oh-my-opencode 4.16.2 → 4.17.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (234) hide show
  1. package/.agents/command/omomomo.md +1 -1
  2. package/.agents/skills/hyperplan/SKILL.md +3 -3
  3. package/.agents/skills/omomomo/SKILL.md +1 -1
  4. package/.agents/skills/pre-publish-review/SKILL.md +3 -0
  5. package/.opencode/command/omomomo.md +1 -1
  6. package/.opencode/skills/hyperplan/SKILL.md +3 -3
  7. package/.opencode/skills/pre-publish-review/SKILL.md +3 -0
  8. package/README.ja.md +4 -4
  9. package/README.ko.md +4 -4
  10. package/README.md +4 -4
  11. package/README.ru.md +4 -4
  12. package/README.zh-cn.md +4 -4
  13. package/dist/agents/hephaestus/agent.d.ts +1 -1
  14. package/dist/agents/hephaestus/gpt-5-6.d.ts +2 -0
  15. package/dist/agents/momus-gpt-5-6.d.ts +1 -0
  16. package/dist/agents/types.d.ts +2 -0
  17. package/dist/cli/index.js +947 -567
  18. package/dist/cli-node/index.js +947 -567
  19. package/dist/features/background-agent/error-classifier.d.ts +5 -0
  20. package/dist/features/builtin-commands/templates/refactor-sections/intro-and-analysis.d.ts +1 -1
  21. package/dist/features/builtin-commands/templates/remove-ai-slops.d.ts +1 -1
  22. package/dist/features/team-mode/test-support/async-test-helpers.d.ts +2 -2
  23. package/dist/index.js +523 -81
  24. package/dist/plugin/chat-message/types.d.ts +4 -0
  25. package/dist/plugin/command-execute-before.d.ts +1 -0
  26. package/dist/plugin/stop-continuation.d.ts +17 -0
  27. package/dist/shared/live-server-route.d.ts +1 -1
  28. package/dist/skills/remove-ai-slops/SKILL.md +2 -2
  29. package/dist/skills/review-work/SKILL.md +1 -1
  30. package/dist/skills/start-work/SKILL.md +5 -2
  31. package/dist/skills/ulw-plan/references/full-workflow.md +1 -1
  32. package/dist/skills/ulw-plan/scripts/scaffold-plan.mjs +2 -2
  33. package/dist/skills/ulw-research/SKILL.md +2 -2
  34. package/dist/skills/visual-qa/SKILL.md +1 -1
  35. package/dist/tui.js +195 -41
  36. package/package.json +15 -14
  37. package/packages/git-bash-mcp/package.json +27 -0
  38. package/packages/omo-codex/plugin/.codex-plugin/plugin.json +3 -1
  39. package/packages/omo-codex/plugin/components/bootstrap/dist/cli.js +465 -248
  40. package/packages/omo-codex/plugin/components/bootstrap/hooks/hooks.json +1 -1
  41. package/packages/omo-codex/plugin/components/bootstrap/package.json +1 -1
  42. package/packages/omo-codex/plugin/components/codegraph/package.json +1 -1
  43. package/packages/omo-codex/plugin/components/comment-checker/hooks/hooks.json +1 -1
  44. package/packages/omo-codex/plugin/components/comment-checker/package.json +1 -1
  45. package/packages/omo-codex/plugin/components/git-bash/hooks/hooks.json +2 -2
  46. package/packages/omo-codex/plugin/components/git-bash/package.json +1 -1
  47. package/packages/omo-codex/plugin/components/lazycodex-executor-verify/AGENTS.md +2 -2
  48. package/packages/omo-codex/plugin/components/lazycodex-executor-verify/dist/cli.js +6 -2
  49. package/packages/omo-codex/plugin/components/lazycodex-executor-verify/dist/codex-hook.js +6 -2
  50. package/packages/omo-codex/plugin/components/lazycodex-executor-verify/hooks/hooks.json +2 -2
  51. package/packages/omo-codex/plugin/components/lazycodex-executor-verify/package.json +1 -1
  52. package/packages/omo-codex/plugin/components/lazycodex-executor-verify/src/codex-hook.ts +6 -2
  53. package/packages/omo-codex/plugin/components/lazycodex-executor-verify/test/cli.test.ts +1 -1
  54. package/packages/omo-codex/plugin/components/lazycodex-executor-verify/test/codex-hook.test.ts +67 -2
  55. package/packages/omo-codex/plugin/components/lsp/hooks/hooks.json +2 -2
  56. package/packages/omo-codex/plugin/components/lsp/package.json +1 -1
  57. package/packages/omo-codex/plugin/components/lsp/test/package-smoke.test.ts +0 -13
  58. package/packages/omo-codex/plugin/components/rules/bundled-rules/hephaestus/gpt-5.6.md +93 -0
  59. package/packages/omo-codex/plugin/components/rules/dist/cli.js +43 -24
  60. package/packages/omo-codex/plugin/components/rules/hooks/hooks.json +4 -4
  61. package/packages/omo-codex/plugin/components/rules/package.json +1 -1
  62. package/packages/omo-codex/plugin/components/rules/src/codex-hook.ts +2 -1
  63. package/packages/omo-codex/plugin/components/rules/src/dynamic-target-fingerprints.ts +15 -6
  64. package/packages/omo-codex/plugin/components/rules/src/rules-engine-factory.ts +7 -2
  65. package/packages/omo-codex/plugin/components/rules/src/static-injection.ts +2 -2
  66. package/packages/omo-codex/plugin/components/rules/test/codex-hook.test.ts +32 -0
  67. package/packages/omo-codex/plugin/components/rules/test/hephaestus-model-variant.test.ts +106 -0
  68. package/packages/omo-codex/plugin/components/start-work-continuation/hooks/hooks.json +2 -2
  69. package/packages/omo-codex/plugin/components/start-work-continuation/package.json +1 -1
  70. package/packages/omo-codex/plugin/components/start-work-continuation/test/codex-hook.test.ts +1 -79
  71. package/packages/omo-codex/plugin/components/teammode/AGENTS.md +12 -9
  72. package/packages/omo-codex/plugin/components/teammode/hooks/hooks.json +1 -1
  73. package/packages/omo-codex/plugin/components/teammode/package.json +1 -1
  74. package/packages/omo-codex/plugin/components/teammode/skills/teammode/SKILL.md +136 -76
  75. package/packages/omo-codex/plugin/components/teammode/skills/teammode/scripts/team-guide.mjs +94 -23
  76. package/packages/omo-codex/plugin/components/teammode/skills/teammode/scripts/team-state.mjs +94 -14
  77. package/packages/omo-codex/plugin/components/teammode/skills/teammode/scripts/team-transport.mjs +55 -0
  78. package/packages/omo-codex/plugin/components/teammode/skills/teammode/scripts/team.mjs +72 -18
  79. package/packages/omo-codex/plugin/components/teammode/test/thread-title-hook.test.ts +23 -0
  80. package/packages/omo-codex/plugin/components/telemetry/hooks/hooks.json +1 -1
  81. package/packages/omo-codex/plugin/components/telemetry/package.json +1 -1
  82. package/packages/omo-codex/plugin/components/ultrawork/agents/explorer.toml +23 -40
  83. package/packages/omo-codex/plugin/components/ultrawork/agents/lazycodex-clone-fidelity-reviewer.toml +1 -1
  84. package/packages/omo-codex/plugin/components/ultrawork/agents/lazycodex-code-reviewer.toml +3 -3
  85. package/packages/omo-codex/plugin/components/ultrawork/agents/lazycodex-gate-reviewer.toml +7 -7
  86. package/packages/omo-codex/plugin/components/ultrawork/agents/lazycodex-qa-executor.toml +5 -5
  87. package/packages/omo-codex/plugin/components/ultrawork/agents/lazycodex-worker-high.toml +26 -0
  88. package/packages/omo-codex/plugin/components/ultrawork/agents/{lazycodex-executor.toml → lazycodex-worker-low.toml} +7 -5
  89. package/packages/omo-codex/plugin/components/ultrawork/agents/lazycodex-worker-medium.toml +26 -0
  90. package/packages/omo-codex/plugin/components/ultrawork/agents/librarian.toml +20 -48
  91. package/packages/omo-codex/plugin/components/ultrawork/agents/metis.toml +17 -29
  92. package/packages/omo-codex/plugin/components/ultrawork/agents/momus.toml +20 -50
  93. package/packages/omo-codex/plugin/components/ultrawork/agents/plan.toml +22 -43
  94. package/packages/omo-codex/plugin/components/ultrawork/directive.md +55 -28
  95. package/packages/omo-codex/plugin/components/ultrawork/hooks/hooks.json +1 -1
  96. package/packages/omo-codex/plugin/components/ultrawork/package.json +1 -1
  97. package/packages/omo-codex/plugin/components/ultrawork/skills/ultrawork/SKILL.md +55 -28
  98. package/packages/omo-codex/plugin/components/ultrawork/skills/ulw-plan/references/full-workflow.md +1 -1
  99. package/packages/omo-codex/plugin/components/ultrawork/skills/ulw-plan/scripts/scaffold-plan.mjs +2 -2
  100. package/packages/omo-codex/plugin/components/ultrawork/test/codex-hook.test.ts +22 -0
  101. package/packages/omo-codex/plugin/components/ultrawork/test/package-smoke.test.ts +0 -68
  102. package/packages/omo-codex/plugin/components/ulw-loop/AGENTS.md +1 -1
  103. package/packages/omo-codex/plugin/components/ulw-loop/CHANGELOG.md +2 -0
  104. package/packages/omo-codex/plugin/components/ulw-loop/README.md +3 -1
  105. package/packages/omo-codex/plugin/components/ulw-loop/directive.md +55 -28
  106. package/packages/omo-codex/plugin/components/ulw-loop/dist/checkpoint.js +6 -1
  107. package/packages/omo-codex/plugin/components/ulw-loop/dist/cli-subcommands.d.ts +1 -1
  108. package/packages/omo-codex/plugin/components/ulw-loop/dist/cli-subcommands.js +13 -2
  109. package/packages/omo-codex/plugin/components/ulw-loop/dist/cli.js +405 -25
  110. package/packages/omo-codex/plugin/components/ulw-loop/dist/codex-goal-instruction.js +12 -1
  111. package/packages/omo-codex/plugin/components/ulw-loop/dist/domain-types.d.ts +4 -2
  112. package/packages/omo-codex/plugin/components/ulw-loop/dist/paths.d.ts +7 -0
  113. package/packages/omo-codex/plugin/components/ulw-loop/dist/paths.js +16 -1
  114. package/packages/omo-codex/plugin/components/ulw-loop/dist/plan-crud.js +1 -0
  115. package/packages/omo-codex/plugin/components/ulw-loop/dist/quality-gate-verdicts.d.ts +6 -0
  116. package/packages/omo-codex/plugin/components/ulw-loop/dist/quality-gate-verdicts.js +20 -0
  117. package/packages/omo-codex/plugin/components/ulw-loop/dist/quality-gate.d.ts +1 -0
  118. package/packages/omo-codex/plugin/components/ulw-loop/dist/quality-gate.js +12 -9
  119. package/packages/omo-codex/plugin/components/ulw-loop/dist/spawn-guard.d.ts +3 -0
  120. package/packages/omo-codex/plugin/components/ulw-loop/dist/spawn-guard.js +148 -0
  121. package/packages/omo-codex/plugin/components/ulw-loop/dist/stop-resume-hook.d.ts +2 -0
  122. package/packages/omo-codex/plugin/components/ulw-loop/dist/stop-resume-hook.js +209 -0
  123. package/packages/omo-codex/plugin/components/ulw-loop/hooks/hooks.json +25 -2
  124. package/packages/omo-codex/plugin/components/ulw-loop/package.json +1 -1
  125. package/packages/omo-codex/plugin/components/ulw-loop/skills/ulw-loop/SKILL.md +14 -15
  126. package/packages/omo-codex/plugin/components/ulw-loop/skills/ulw-loop/references/full-workflow.md +29 -27
  127. package/packages/omo-codex/plugin/components/ulw-loop/src/checkpoint.ts +6 -1
  128. package/packages/omo-codex/plugin/components/ulw-loop/src/cli-subcommands.ts +14 -3
  129. package/packages/omo-codex/plugin/components/ulw-loop/src/cli.ts +10 -0
  130. package/packages/omo-codex/plugin/components/ulw-loop/src/codex-goal-instruction.ts +12 -1
  131. package/packages/omo-codex/plugin/components/ulw-loop/src/domain-types.ts +4 -2
  132. package/packages/omo-codex/plugin/components/ulw-loop/src/paths.ts +27 -1
  133. package/packages/omo-codex/plugin/components/ulw-loop/src/plan-crud.ts +1 -0
  134. package/packages/omo-codex/plugin/components/ulw-loop/src/quality-gate-verdicts.ts +23 -0
  135. package/packages/omo-codex/plugin/components/ulw-loop/src/quality-gate.ts +16 -9
  136. package/packages/omo-codex/plugin/components/ulw-loop/src/spawn-guard.ts +138 -0
  137. package/packages/omo-codex/plugin/components/ulw-loop/src/stop-resume-hook.ts +208 -0
  138. package/packages/omo-codex/plugin/components/ulw-loop/test/cli-create-goals.test.ts +12 -0
  139. package/packages/omo-codex/plugin/components/ulw-loop/test/cli-entrypoint.test.ts +4 -1
  140. package/packages/omo-codex/plugin/components/ulw-loop/test/codex-goal-instruction.test.ts +8 -35
  141. package/packages/omo-codex/plugin/components/ulw-loop/test/fixtures/quality-gate-builder.ts +24 -13
  142. package/packages/omo-codex/plugin/components/ulw-loop/test/package-smoke.test.ts +5 -2
  143. package/packages/omo-codex/plugin/components/ulw-loop/test/paths.test.ts +43 -8
  144. package/packages/omo-codex/plugin/components/ulw-loop/test/quality-gate.test.ts +55 -2
  145. package/packages/omo-codex/plugin/components/ulw-loop/test/spawn-guard.test.ts +228 -0
  146. package/packages/omo-codex/plugin/components/ulw-loop/test/stop-resume-hook.test.ts +193 -0
  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 +18 -0
  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 +17 -0
  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 +2 -2
  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/model-catalog.json +16 -7
  171. package/packages/omo-codex/plugin/package-lock.json +13 -13
  172. package/packages/omo-codex/plugin/package.json +1 -1
  173. package/packages/omo-codex/plugin/scripts/auto-update.mjs +9 -2
  174. package/packages/omo-codex/plugin/scripts/entry-guard.mjs +26 -0
  175. package/packages/omo-codex/plugin/scripts/materialize-shared-upstreams.mjs +3 -1
  176. package/packages/omo-codex/plugin/scripts/migrate-codex-config/catalog.mjs +16 -7
  177. package/packages/omo-codex/plugin/scripts/migrate-codex-config/multi-agent-v2-guard.mjs +39 -4
  178. package/packages/omo-codex/plugin/scripts/migrate-codex-config/subagent-limit-guard.mjs +24 -4
  179. package/packages/omo-codex/plugin/scripts/migrate-codex-config.mjs +3 -3
  180. package/packages/omo-codex/plugin/scripts/migrate-omo-sot.mjs +2 -2
  181. package/packages/omo-codex/plugin/scripts/sync-hook-status-messages.mjs +2 -2
  182. package/packages/omo-codex/plugin/scripts/sync-skills.mjs +14 -6
  183. package/packages/omo-codex/plugin/scripts/sync-version.mjs +4 -2
  184. package/packages/omo-codex/plugin/skills/init-deep/SKILL.md +3 -3
  185. package/packages/omo-codex/plugin/skills/refactor/SKILL.md +3 -3
  186. package/packages/omo-codex/plugin/skills/remove-ai-slops/SKILL.md +5 -5
  187. package/packages/omo-codex/plugin/skills/review-work/SKILL.md +9 -3
  188. package/packages/omo-codex/plugin/skills/start-work/SKILL.md +6 -3
  189. package/packages/omo-codex/plugin/skills/teammode/SKILL.md +136 -76
  190. package/packages/omo-codex/plugin/skills/teammode/scripts/team-guide.mjs +94 -23
  191. package/packages/omo-codex/plugin/skills/teammode/scripts/team-state.mjs +94 -14
  192. package/packages/omo-codex/plugin/skills/teammode/scripts/team-transport.mjs +55 -0
  193. package/packages/omo-codex/plugin/skills/teammode/scripts/team.mjs +72 -18
  194. package/packages/omo-codex/plugin/skills/ultrawork/SKILL.md +55 -28
  195. package/packages/omo-codex/plugin/skills/ulw-loop/SKILL.md +14 -15
  196. package/packages/omo-codex/plugin/skills/ulw-loop/references/full-workflow.md +29 -27
  197. package/packages/omo-codex/plugin/skills/ulw-plan/references/full-workflow.md +1 -1
  198. package/packages/omo-codex/plugin/skills/ulw-plan/scripts/scaffold-plan.mjs +2 -2
  199. package/packages/omo-codex/plugin/skills/ulw-research/SKILL.md +4 -4
  200. package/packages/omo-codex/plugin/skills/visual-qa/SKILL.md +4 -4
  201. package/packages/omo-codex/plugin/test/aggregate-agents.test.mjs +116 -10
  202. package/packages/omo-codex/plugin/test/aggregate-hooks.test.mjs +23 -2
  203. package/packages/omo-codex/plugin/test/aggregate-manifest.test.mjs +1 -1
  204. package/packages/omo-codex/plugin/test/aggregate-model-catalog.test.mjs +4 -4
  205. package/packages/omo-codex/plugin/test/aggregate-skills.test.mjs +4 -2
  206. package/packages/omo-codex/plugin/test/auto-update-restart-notice.test.mjs +33 -0
  207. package/packages/omo-codex/plugin/test/auto-update.test.mjs +4 -4
  208. package/packages/omo-codex/plugin/test/component-hook-contract-cases.mjs +2 -2
  209. package/packages/omo-codex/plugin/test/lcx-bug-skills.test.mjs +4 -101
  210. package/packages/omo-codex/plugin/test/migrate-codex-config.test.mjs +160 -23
  211. package/packages/omo-codex/plugin/test/multi-agent-v2-regression.test.mjs +71 -0
  212. package/packages/omo-codex/plugin/test/subagent-limit-migration.test.mjs +32 -0
  213. package/packages/omo-codex/plugin/test/sync-skills-orchestration.test.mjs +20 -2
  214. package/packages/omo-codex/plugin/test/sync-skills-test-support.mjs +1 -1
  215. package/packages/omo-codex/plugin/test/sync-skills.test.mjs +4 -2
  216. package/packages/omo-codex/plugin/test/teammode-transport.test.mjs +345 -0
  217. package/packages/omo-codex/plugin/test/ulw-plan-skill-contract.test.mjs +9 -40
  218. package/packages/omo-codex/plugin/test/ulw-research-skill-contract.test.mjs +4 -277
  219. package/packages/omo-codex/scripts/install-config-reasoning.test.mjs +5 -5
  220. package/packages/omo-codex/scripts/install-config.test.mjs +22 -3
  221. package/packages/omo-codex/scripts/install-dist/install-local.mjs +508 -286
  222. package/packages/omo-codex/scripts/install-generated-bundle.test.mjs +111 -1
  223. package/packages/shared-skills/skills/remove-ai-slops/SKILL.md +2 -2
  224. package/packages/shared-skills/skills/review-work/SKILL.md +1 -1
  225. package/packages/shared-skills/skills/start-work/SKILL.md +5 -2
  226. package/packages/shared-skills/skills/ulw-plan/references/full-workflow.md +1 -1
  227. package/packages/shared-skills/skills/ulw-plan/scripts/scaffold-plan.mjs +2 -2
  228. package/packages/shared-skills/skills/ulw-research/SKILL.md +2 -2
  229. package/packages/shared-skills/skills/visual-qa/SKILL.md +1 -1
  230. package/dist/skills/visual-qa/scripts/skill-prompt-contract.test.ts +0 -296
  231. package/packages/omo-codex/plugin/components/ulw-loop/test/skill-contract.test.ts +0 -70
  232. package/packages/omo-codex/plugin/test/ulw-research-epistemic-contract.test.mjs +0 -98
  233. package/packages/shared-skills/skills/visual-qa/scripts/skill-prompt-contract.test.ts +0 -296
  234. /package/packages/omo-codex/plugin/components/rules/bundled-rules/{hephaestus.md → hephaestus/gpt-5.5.md} +0 -0
@@ -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
  });
@@ -22,8 +22,8 @@ test("#given empty Codex config #when script installer updates config #then sets
22
22
 
23
23
  // then
24
24
  const content = await readFile(configPath, "utf8");
25
- assert.match(content, /model = "gpt-5\.5"/);
26
- assert.match(content, /model_context_window = 400000/);
25
+ assert.match(content, /model = "gpt-5\.6-sol"/);
26
+ assert.match(content, /model_context_window = 372000/);
27
27
  assert.match(content, /model_reasoning_effort = "high"/);
28
28
  assert.match(content, /plan_mode_reasoning_effort = "xhigh"/);
29
29
  });
@@ -61,8 +61,8 @@ test("#given existing model and reasoning config #when script installer updates
61
61
  assert.equal(content.match(/^model_context_window\s*=/gm)?.length, 1);
62
62
  assert.equal(content.match(/^model_reasoning_effort\s*=/gm)?.length, 1);
63
63
  assert.equal(content.match(/^plan_mode_reasoning_effort\s*=/gm)?.length, 1);
64
- assert.match(content, /model = "gpt-5\.5"/);
65
- assert.match(content, /model_context_window = 400000/);
64
+ assert.match(content, /model = "gpt-5\.6-sol"/);
65
+ assert.match(content, /model_context_window = 372000/);
66
66
  assert.match(content, /model_reasoning_effort = "high"/);
67
67
  assert.match(content, /plan_mode_reasoning_effort = "xhigh"/);
68
68
  assert.doesNotMatch(content, /model = "gpt-5\.2"/);
@@ -148,6 +148,6 @@ test("#given fallback model catalog #when catalog file is unavailable #then no m
148
148
  const catalog = await readCodexModelCatalog(root);
149
149
 
150
150
  // then
151
- assert.equal(catalog.current.model, "gpt-5.5");
151
+ assert.equal(catalog.current.model, "gpt-5.6-sol");
152
152
  assert.equal(catalog.managedProfiles.some((profile) => profile.model === "gpt-5.4"), false);
153
153
  });
@@ -23,10 +23,11 @@ test("#given empty Codex config #when script installer updates config #then sets
23
23
  });
24
24
 
25
25
  // then
26
+ // The stamped default model is v2-preferred, so the installer must not
27
+ // introduce agents.max_threads (Codex rejects it under MultiAgentV2).
26
28
  const config = await readFile(configPath, "utf8");
27
29
  assert.doesNotMatch(config, /^\s*multi_agent_mode\s*=/m);
28
- assert.match(config, /\[agents\]/);
29
- assert.match(config, /max_threads = 1000/);
30
+ assert.doesNotMatch(config, /^\s*max_threads\s*=/m);
30
31
  assert.match(config, /\[features\.multi_agent_v2\]/);
31
32
  const v2Section = multiAgentV2Section(config);
32
33
  assert.doesNotMatch(v2Section, /^enabled\s*=/m);
@@ -281,11 +282,15 @@ test("#given sisyphuslabs config without explicit source #when script installer
281
282
 
282
283
  test("#given existing MultiAgentV2 table #when script installer updates config #then preserves unrelated tuning while setting subagent thread limits", async () => {
283
284
  // given
285
+ // A pinned v1 model keeps this on the preserve-user-disable path; the
286
+ // stamped v2-preferred default would clear the disable instead.
284
287
  const root = await mkdtemp(join(tmpdir(), "omo-codex-script-config-multi-agent-existing-"));
285
288
  const configPath = join(root, "config.toml");
286
289
  await writeFile(
287
290
  configPath,
288
291
  [
292
+ 'model = "gpt-5.5"',
293
+ "",
289
294
  "[features.multi_agent_v2]",
290
295
  "enabled = false",
291
296
  "usage_hint_enabled = false",
@@ -327,9 +332,11 @@ test("#given empty Codex config #when script installer updates config #then sets
327
332
  });
328
333
 
329
334
  // then
335
+ // The stamped default model is v2-preferred, so agents.max_threads is not
336
+ // introduced (Codex rejects it under MultiAgentV2).
330
337
  const config = await readFile(configPath, "utf8");
331
338
  const v2Section = config.slice(config.indexOf("[features.multi_agent_v2]"));
332
- assert.match(config, /\[agents\][\s\S]*?max_threads = 1000/);
339
+ assert.doesNotMatch(config, /^\s*max_threads\s*=/m);
333
340
  assert.match(v2Section, /max_concurrent_threads_per_session = 1000/);
334
341
  assert.doesNotMatch(v2Section, /hide_spawn_agent_metadata/);
335
342
  });
@@ -402,11 +409,15 @@ const v2Section = multiAgentV2Section(config);
402
409
 
403
410
  test("#given legacy boolean MultiAgentV2 flag false #when script installer updates config #then normalizes to a disabled table config", async () => {
404
411
  // given
412
+ // A pinned v1 model keeps the legacy boolean materializing as a disabled
413
+ // table; the stamped v2-preferred default would drop the disable instead.
405
414
  const root = await mkdtemp(join(tmpdir(), "omo-codex-script-config-multi-agent-legacy-false-"));
406
415
  const configPath = join(root, "config.toml");
407
416
  await writeFile(
408
417
  configPath,
409
418
  [
419
+ 'model = "gpt-5.5"',
420
+ "",
410
421
  "[features]",
411
422
  "multi_agent_v2 = false",
412
423
  "plugins = false",
@@ -434,11 +445,15 @@ test("#given legacy boolean MultiAgentV2 flag false #when script installer updat
434
445
 
435
446
  test("#given legacy agents max_threads #when script installer updates config #then raises the root subagent thread cap", async () => {
436
447
  // given
448
+ // A pinned v1 model keeps the legacy low-cap raise path exercised; the
449
+ // stamped v2-preferred default would remove agents.max_threads instead.
437
450
  const root = await mkdtemp(join(tmpdir(), "omo-codex-script-config-multi-agent-legacy-threads-"));
438
451
  const configPath = join(root, "config.toml");
439
452
  await writeFile(
440
453
  configPath,
441
454
  [
455
+ 'model = "gpt-5.5"',
456
+ "",
442
457
  "[agents]",
443
458
  "max_threads = 16",
444
459
  "max_depth = 4",
@@ -471,11 +486,15 @@ const v2Section = multiAgentV2Section(config);
471
486
 
472
487
  test("#given managed agent role sections #when script installer updates config #then preserves role config while raising only root agents max_threads", async () => {
473
488
  // given
489
+ // A pinned v1 model keeps the legacy low-cap raise path exercised; the
490
+ // stamped v2-preferred default would remove agents.max_threads instead.
474
491
  const root = await mkdtemp(join(tmpdir(), "omo-codex-script-config-multi-agent-role-section-"));
475
492
  const configPath = join(root, "config.toml");
476
493
  await writeFile(
477
494
  configPath,
478
495
  [
496
+ 'model = "gpt-5.5"',
497
+ "",
479
498
  "[agents]",
480
499
  "max_threads = 16",
481
500
  "",