oh-my-opencode 4.13.0 → 4.14.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 (445) hide show
  1. package/.agents/skills/codex-qa/SKILL.md +15 -0
  2. package/.agents/skills/codex-qa/references/logging-debug.md +12 -0
  3. package/.agents/skills/opencode-qa/SKILL.md +17 -0
  4. package/.agents/skills/opencode-qa/references/tui-tmux.md +17 -0
  5. package/.agents/skills/work-with-pr/SKILL.md +18 -10
  6. package/.opencode/skills/work-with-pr/SKILL.md +18 -10
  7. package/README.md +2 -2
  8. package/dist/cli/doctor/checks/telemetry.d.ts +2 -0
  9. package/dist/cli/doctor/framework/constants.d.ts +1 -0
  10. package/dist/cli/doctor/framework/doctor-target.d.ts +1 -1
  11. package/dist/cli/index.js +24651 -16452
  12. package/dist/cli-node/index.js +24651 -16452
  13. package/dist/config/schema/oh-my-opencode-config.d.ts +1 -0
  14. package/dist/features/team-mode/test-support/async-test-helpers.d.ts +19 -0
  15. package/dist/hooks/atlas/final-wave-approval-gate.d.ts +1 -0
  16. package/dist/hooks/atlas/subagent-completion-reminder.d.ts +30 -0
  17. package/dist/hooks/atlas/types.d.ts +2 -0
  18. package/dist/hooks/atlas/verification-reminders.d.ts +3 -0
  19. package/dist/hooks/team-session-events/team-idle-wake-hint.d.ts +1 -0
  20. package/dist/index.d.ts +1 -0
  21. package/dist/index.js +33232 -19559
  22. package/dist/mcp/context7.d.ts +9 -8
  23. package/dist/oh-my-opencode.schema.json +4 -0
  24. package/dist/shared/posthog.d.ts +17 -10
  25. package/dist/shared/telemetry-product-identity.d.ts +2 -0
  26. package/dist/skills/coding-agent-sessions/SKILL.md +128 -0
  27. package/dist/skills/coding-agent-sessions/agents/openai.yaml +4 -0
  28. package/dist/skills/coding-agent-sessions/references/all-platforms.md +71 -0
  29. package/dist/skills/coding-agent-sessions/references/claude.md +32 -0
  30. package/dist/skills/coding-agent-sessions/references/codex.md +30 -0
  31. package/dist/skills/coding-agent-sessions/references/opencode.md +43 -0
  32. package/dist/skills/coding-agent-sessions/references/senpi.md +17 -0
  33. package/dist/skills/coding-agent-sessions/scripts/agent_sessions/__init__.py +1 -0
  34. package/dist/skills/coding-agent-sessions/scripts/agent_sessions/claude.py +66 -0
  35. package/dist/skills/coding-agent-sessions/scripts/agent_sessions/cli.py +283 -0
  36. package/dist/skills/coding-agent-sessions/scripts/agent_sessions/codex.py +105 -0
  37. package/dist/skills/coding-agent-sessions/scripts/agent_sessions/file_scanners.py +275 -0
  38. package/dist/skills/coding-agent-sessions/scripts/agent_sessions/jsonio.py +55 -0
  39. package/dist/skills/coding-agent-sessions/scripts/agent_sessions/kiro_scanner.py +91 -0
  40. package/dist/skills/coding-agent-sessions/scripts/agent_sessions/opencode.py +289 -0
  41. package/dist/skills/coding-agent-sessions/scripts/agent_sessions/scanners.py +92 -0
  42. package/dist/skills/coding-agent-sessions/scripts/agent_sessions/sqlite_optional_scanners.py +203 -0
  43. package/dist/skills/coding-agent-sessions/scripts/agent_sessions/sqlite_scanners.py +177 -0
  44. package/dist/skills/coding-agent-sessions/scripts/agent_sessions/timeparse.py +51 -0
  45. package/dist/skills/coding-agent-sessions/scripts/agent_sessions/transcript.py +149 -0
  46. package/dist/skills/coding-agent-sessions/scripts/agent_sessions/types.py +57 -0
  47. package/dist/skills/coding-agent-sessions/scripts/find-agent-sessions.py +19 -0
  48. package/dist/skills/frontend/ATTRIBUTION.md +52 -8
  49. package/dist/skills/frontend/SKILL.md +29 -8
  50. package/dist/skills/frontend/references/design/README.md +29 -12
  51. package/dist/skills/frontend/references/design/_INDEX.md +3 -3
  52. package/dist/skills/frontend/references/design/design-system-architecture.md +22 -19
  53. package/dist/skills/frontend/references/designpowers/EVIDENCE.md +89 -0
  54. package/dist/skills/frontend/references/designpowers/README.md +48 -0
  55. package/dist/skills/frontend/references/designpowers/UPSTREAM.md +80 -0
  56. package/dist/skills/frontend/references/designpowers/lane-a-direction.md +64 -0
  57. package/dist/skills/frontend/references/designpowers/lane-b-execution.md +65 -0
  58. package/dist/skills/frontend/references/designpowers/lane-c-review.md +65 -0
  59. package/dist/skills/frontend/references/designpowers/lane-d-memory.md +83 -0
  60. package/dist/skills/frontend/references/designpowers/orchestration.md +80 -0
  61. package/dist/skills/frontend/references/designpowers/routing.md +79 -0
  62. package/dist/skills/frontend/references/designpowers/vendor/LICENSE +21 -0
  63. package/dist/skills/frontend/references/designpowers/vendor/agents/accessibility-reviewer.md +83 -0
  64. package/dist/skills/frontend/references/designpowers/vendor/agents/content-writer.md +132 -0
  65. package/dist/skills/frontend/references/designpowers/vendor/agents/design-builder.md +109 -0
  66. package/dist/skills/frontend/references/designpowers/vendor/agents/design-critic.md +89 -0
  67. package/dist/skills/frontend/references/designpowers/vendor/agents/design-lead.md +113 -0
  68. package/dist/skills/frontend/references/designpowers/vendor/agents/design-scout.md +78 -0
  69. package/dist/skills/frontend/references/designpowers/vendor/agents/design-strategist.md +121 -0
  70. package/dist/skills/frontend/references/designpowers/vendor/agents/heuristic-evaluator.md +268 -0
  71. package/dist/skills/frontend/references/designpowers/vendor/agents/inspiration-scout.md +107 -0
  72. package/dist/skills/frontend/references/designpowers/vendor/agents/motion-designer.md +120 -0
  73. package/dist/skills/frontend/references/designpowers/vendor/skills/accessible-content/SKILL.md +101 -0
  74. package/dist/skills/frontend/references/designpowers/vendor/skills/adaptive-interfaces/SKILL.md +109 -0
  75. package/dist/skills/frontend/references/designpowers/vendor/skills/cognitive-accessibility/SKILL.md +107 -0
  76. package/dist/skills/frontend/references/designpowers/vendor/skills/design-debate/SKILL.md +199 -0
  77. package/dist/skills/frontend/references/designpowers/vendor/skills/design-debt-tracker/SKILL.md +174 -0
  78. package/dist/skills/frontend/references/designpowers/vendor/skills/design-handoff/SKILL.md +125 -0
  79. package/dist/skills/frontend/references/designpowers/vendor/skills/design-md/SKILL.md +106 -0
  80. package/dist/skills/frontend/references/designpowers/vendor/skills/design-retrospective/SKILL.md +266 -0
  81. package/dist/skills/frontend/references/designpowers/vendor/skills/design-review/SKILL.md +123 -0
  82. package/dist/skills/frontend/references/designpowers/vendor/skills/design-system-alignment/SKILL.md +120 -0
  83. package/dist/skills/frontend/references/designpowers/vendor/skills/designpowers-critique/SKILL.md +164 -0
  84. package/dist/skills/frontend/references/designpowers/vendor/skills/heuristic-evaluation/SKILL.md +85 -0
  85. package/dist/skills/frontend/references/designpowers/vendor/skills/inclusive-personas/SKILL.md +98 -0
  86. package/dist/skills/frontend/references/designpowers/vendor/skills/inspiration-scouting/SKILL.md +165 -0
  87. package/dist/skills/frontend/references/designpowers/vendor/skills/interaction-design/SKILL.md +122 -0
  88. package/dist/skills/frontend/references/designpowers/vendor/skills/motion-choreography/SKILL.md +81 -0
  89. package/dist/skills/frontend/references/designpowers/vendor/skills/research-planning/SKILL.md +96 -0
  90. package/dist/skills/frontend/references/designpowers/vendor/skills/responsive-patterns/SKILL.md +77 -0
  91. package/dist/skills/frontend/references/designpowers/vendor/skills/synthetic-user-testing/SKILL.md +192 -0
  92. package/dist/skills/frontend/references/designpowers/vendor/skills/taste-feedback/SKILL.md +165 -0
  93. package/dist/skills/frontend/references/designpowers/vendor/skills/taste-report/SKILL.md +78 -0
  94. package/dist/skills/frontend/references/designpowers/vendor/skills/token-architecture/SKILL.md +75 -0
  95. package/dist/skills/frontend/references/designpowers/vendor/skills/ui-composition/SKILL.md +117 -0
  96. package/dist/skills/frontend/references/designpowers/vendor/skills/usability-testing/SKILL.md +78 -0
  97. package/dist/skills/frontend/references/designpowers/vendor/skills/verification-before-shipping/SKILL.md +125 -0
  98. package/dist/skills/frontend/references/designpowers/vendor/skills/voice-and-tone/SKILL.md +79 -0
  99. package/dist/skills/frontend/references/designpowers/vendor/skills/writing-design-plans/SKILL.md +119 -0
  100. package/dist/skills/frontend/references/ui-ux-db/scripts/core.py +0 -0
  101. package/dist/skills/git-master/SKILL.md +4 -0
  102. package/dist/skills/review-work/SKILL.md +3 -3
  103. package/dist/skills/start-work/SKILL.md +7 -5
  104. package/dist/skills/ultraresearch/SKILL.md +4 -252
  105. package/dist/skills/ulw-plan/SKILL.md +8 -6
  106. package/dist/skills/ulw-plan/references/full-workflow.md +11 -6
  107. package/dist/skills/ulw-plan/references/intent-clear.md +3 -3
  108. package/dist/skills/ulw-plan/references/intent-unclear.md +1 -1
  109. package/dist/skills/{ultraresearch → ulw-research}/ATTRIBUTION.md +1 -1
  110. package/dist/skills/ulw-research/SKILL.md +260 -0
  111. package/dist/skills/visual-qa/SKILL.md +105 -14
  112. package/dist/skills/visual-qa/scripts/skill-prompt-contract.test.ts +120 -1
  113. package/dist/testing/create-plugin-module.d.ts +2 -0
  114. package/dist/tui.js +23917 -16117
  115. package/docs/reference/github-attachment-upload.md +51 -0
  116. package/docs/reference/web-terminal-visual-qa.md +81 -0
  117. package/package.json +20 -14
  118. package/packages/lsp-core/src/lsp/process.ts +4 -1
  119. package/packages/lsp-core/src/mcp.ts +1 -0
  120. package/packages/lsp-daemon/dist/cli.js +5 -1
  121. package/packages/lsp-daemon/dist/index.js +5 -1
  122. package/packages/lsp-daemon/dist/proxy.js +1 -0
  123. package/packages/lsp-tools-mcp/dist/cli.js +5 -1
  124. package/packages/lsp-tools-mcp/dist/lsp/manager.js +4 -1
  125. package/packages/lsp-tools-mcp/dist/mcp.js +5 -1
  126. package/packages/lsp-tools-mcp/dist/tools.js +4 -1
  127. package/packages/omo-codex/plugin/.codex-plugin/plugin.json +1 -1
  128. package/packages/omo-codex/plugin/components/bootstrap/dist/cli.js +323 -62
  129. package/packages/omo-codex/plugin/components/bootstrap/package.json +1 -1
  130. package/packages/omo-codex/plugin/components/bootstrap/scripts/bootstrap.ps1 +37 -68
  131. package/packages/omo-codex/plugin/components/bootstrap/scripts/node-dispatch.ps1 +75 -0
  132. package/packages/omo-codex/plugin/components/bootstrap/src/cli.ts +1 -1
  133. package/packages/omo-codex/plugin/components/bootstrap/src/setup.ts +2 -18
  134. package/packages/omo-codex/plugin/components/codegraph/dist/cli.js +575 -334
  135. package/packages/omo-codex/plugin/components/codegraph/dist/serve.js +204 -39
  136. package/packages/omo-codex/plugin/components/codegraph/package.json +2 -2
  137. package/packages/omo-codex/plugin/components/codegraph/src/hook-types.ts +7 -1
  138. package/packages/omo-codex/plugin/components/codegraph/src/hook.ts +103 -3
  139. package/packages/omo-codex/plugin/components/codegraph/src/mcp-bridge.ts +114 -0
  140. package/packages/omo-codex/plugin/components/codegraph/src/serve-invocation.ts +29 -0
  141. package/packages/omo-codex/plugin/components/codegraph/src/serve.ts +31 -57
  142. package/packages/omo-codex/plugin/components/codegraph/src/session-start-worker.ts +7 -4
  143. package/packages/omo-codex/plugin/components/codegraph/test/hook.test.ts +43 -9
  144. package/packages/omo-codex/plugin/components/codegraph/test/serve-mcp-bridge.test.ts +146 -0
  145. package/packages/omo-codex/plugin/components/codegraph/test/serve.test.ts +12 -7
  146. package/packages/omo-codex/plugin/components/codegraph/test/session-start-worker-flow.test.ts +71 -1
  147. package/packages/omo-codex/plugin/components/comment-checker/package.json +1 -1
  148. package/packages/omo-codex/plugin/components/git-bash/package.json +1 -1
  149. package/packages/omo-codex/plugin/components/lazycodex-executor-verify/package.json +1 -1
  150. package/packages/omo-codex/plugin/components/lsp/dist/cli.js +4 -1
  151. package/packages/omo-codex/plugin/components/lsp/package.json +1 -1
  152. package/packages/omo-codex/plugin/components/rules/dist/cli.js +2 -2
  153. package/packages/omo-codex/plugin/components/rules/package.json +1 -1
  154. package/packages/omo-codex/plugin/components/rules/src/sparkshell-awareness.ts +2 -2
  155. package/packages/omo-codex/plugin/components/rules/test/sparkshell-awareness.test.ts +11 -2
  156. package/packages/omo-codex/plugin/components/start-work-continuation/directive.md +6 -6
  157. package/packages/omo-codex/plugin/components/start-work-continuation/package.json +1 -1
  158. package/packages/omo-codex/plugin/components/start-work-continuation/test/codex-hook.test.ts +23 -0
  159. package/packages/omo-codex/plugin/components/teammode/dist/cli.js +22 -4
  160. package/packages/omo-codex/plugin/components/teammode/package.json +1 -1
  161. package/packages/omo-codex/plugin/components/teammode/skills/teammode/SKILL.md +40 -2
  162. package/packages/omo-codex/plugin/components/teammode/skills/teammode/scripts/team-guide.mjs +32 -5
  163. package/packages/omo-codex/plugin/components/teammode/skills/teammode/scripts/team.mjs +7 -3
  164. package/packages/omo-codex/plugin/components/teammode/src/codex-hook.ts +19 -4
  165. package/packages/omo-codex/plugin/components/teammode/test/thread-title-hook.test.ts +32 -2
  166. package/packages/omo-codex/plugin/components/telemetry/package.json +1 -1
  167. package/packages/omo-codex/plugin/components/ultrawork/README.md +1 -1
  168. package/packages/omo-codex/plugin/components/ultrawork/agents/explorer.toml +1 -1
  169. package/packages/omo-codex/plugin/components/ultrawork/agents/plan.toml +2 -2
  170. package/packages/omo-codex/plugin/components/ultrawork/directive.md +23 -7
  171. package/packages/omo-codex/plugin/components/ultrawork/dist/cli.js +1 -1
  172. package/packages/omo-codex/plugin/components/ultrawork/package.json +1 -1
  173. package/packages/omo-codex/plugin/components/ultrawork/skills/ulw-plan/SKILL.md +6 -4
  174. package/packages/omo-codex/plugin/components/ultrawork/skills/ulw-plan/references/full-workflow.md +11 -6
  175. package/packages/omo-codex/plugin/components/ultrawork/skills/ulw-plan/references/intent-clear.md +3 -3
  176. package/packages/omo-codex/plugin/components/ultrawork/skills/ulw-plan/references/intent-unclear.md +1 -1
  177. package/packages/omo-codex/plugin/components/ultrawork/src/codex-hook.ts +1 -1
  178. package/packages/omo-codex/plugin/components/ultrawork/test/codex-hook-trigger-policy.test.ts +24 -0
  179. package/packages/omo-codex/plugin/components/ultrawork/test/package-smoke.test.ts +6 -1
  180. package/packages/omo-codex/plugin/components/ulw-loop/AGENTS.md +1 -1
  181. package/packages/omo-codex/plugin/components/ulw-loop/README.md +25 -21
  182. package/packages/omo-codex/plugin/components/ulw-loop/biome.json +1 -1
  183. package/packages/omo-codex/plugin/components/ulw-loop/directive.md +381 -0
  184. package/packages/omo-codex/plugin/components/ulw-loop/dist/cli-steering.js +14 -1
  185. package/packages/omo-codex/plugin/components/ulw-loop/dist/cli.js +145 -14
  186. package/packages/omo-codex/plugin/components/ulw-loop/dist/codex-hook.d.ts +6 -3
  187. package/packages/omo-codex/plugin/components/ulw-loop/dist/codex-hook.js +16 -6
  188. package/packages/omo-codex/plugin/components/ulw-loop/dist/ultrawork-directive.d.ts +5 -0
  189. package/packages/omo-codex/plugin/components/ulw-loop/dist/ultrawork-directive.js +104 -0
  190. package/packages/omo-codex/plugin/components/ulw-loop/hooks/hooks.json +1 -1
  191. package/packages/omo-codex/plugin/components/ulw-loop/package.json +2 -1
  192. package/packages/omo-codex/plugin/components/ulw-loop/skills/ulw-loop/references/full-workflow.md +19 -11
  193. package/packages/omo-codex/plugin/components/ulw-loop/src/cli-steering.ts +14 -1
  194. package/packages/omo-codex/plugin/components/ulw-loop/src/cli.ts +4 -2
  195. package/packages/omo-codex/plugin/components/ulw-loop/src/codex-hook.ts +28 -6
  196. package/packages/omo-codex/plugin/components/ulw-loop/src/ultrawork-directive.ts +113 -0
  197. package/packages/omo-codex/plugin/components/ulw-loop/test/cli-entrypoint.test.ts +33 -2
  198. package/packages/omo-codex/plugin/components/ulw-loop/test/cli-steering-kind-guidance.test.ts +31 -0
  199. package/packages/omo-codex/plugin/components/ulw-loop/test/codex-hook.test.ts +13 -0
  200. package/packages/omo-codex/plugin/components/ulw-loop/test/package-smoke.test.ts +36 -0
  201. package/packages/omo-codex/plugin/components/ulw-loop/test/skill-contract.test.ts +12 -0
  202. package/packages/omo-codex/plugin/components/ulw-loop/test/ultrawork-directive.test.ts +64 -0
  203. package/packages/omo-codex/plugin/hooks/post-compact-resetting-git-bash-mcp-reminder.json +2 -1
  204. package/packages/omo-codex/plugin/hooks/post-compact-resetting-lsp-diagnostics-cache.json +2 -1
  205. package/packages/omo-codex/plugin/hooks/post-compact-resetting-project-rule-cache.json +2 -1
  206. package/packages/omo-codex/plugin/hooks/post-tool-use-checking-codegraph-init-guidance.json +2 -1
  207. package/packages/omo-codex/plugin/hooks/post-tool-use-checking-comments.json +2 -1
  208. package/packages/omo-codex/plugin/hooks/post-tool-use-checking-lsp-diagnostics.json +2 -1
  209. package/packages/omo-codex/plugin/hooks/post-tool-use-checking-thread-title-hygiene.json +2 -1
  210. package/packages/omo-codex/plugin/hooks/post-tool-use-matching-project-rules.json +2 -1
  211. package/packages/omo-codex/plugin/hooks/pre-tool-use-enforcing-unlimited-goal-budget.json +2 -1
  212. package/packages/omo-codex/plugin/hooks/pre-tool-use-recommending-git-bash-mcp.json +2 -1
  213. package/packages/omo-codex/plugin/hooks/session-start-checking-auto-update.json +2 -1
  214. package/packages/omo-codex/plugin/hooks/session-start-checking-codegraph-bootstrap.json +2 -1
  215. package/packages/omo-codex/plugin/hooks/session-start-loading-project-rules.json +2 -1
  216. package/packages/omo-codex/plugin/hooks/session-start-recording-session-telemetry.json +2 -1
  217. package/packages/omo-codex/plugin/hooks/stop-checking-start-work-continuation.json +2 -1
  218. package/packages/omo-codex/plugin/hooks/subagent-stop-checking-start-work-continuation.json +2 -1
  219. package/packages/omo-codex/plugin/hooks/subagent-stop-verifying-lazycodex-executor-evidence.json +2 -1
  220. package/packages/omo-codex/plugin/hooks/user-prompt-submit-checking-ultrawork-trigger.json +2 -1
  221. package/packages/omo-codex/plugin/hooks/user-prompt-submit-checking-ulw-loop-steering.json +2 -1
  222. package/packages/omo-codex/plugin/hooks/user-prompt-submit-loading-project-rules.json +2 -1
  223. package/packages/omo-codex/plugin/package-lock.json +13 -13
  224. package/packages/omo-codex/plugin/package.json +1 -1
  225. package/packages/omo-codex/plugin/scripts/auto-update.mjs +9 -5
  226. package/packages/omo-codex/plugin/scripts/materialize-shared-upstreams.mjs +1 -0
  227. package/packages/omo-codex/plugin/scripts/migrate-codex-config/context7-placeholder-guard.mjs +131 -0
  228. package/packages/omo-codex/plugin/scripts/migrate-codex-config/multi-agent-mode-guard.mjs +60 -0
  229. package/packages/omo-codex/plugin/scripts/migrate-codex-config/multi-agent-v2-guard.mjs +3 -10
  230. package/packages/omo-codex/plugin/scripts/migrate-codex-config/root-settings.mjs +31 -1
  231. package/packages/omo-codex/plugin/scripts/migrate-codex-config/subagent-limit-guard.mjs +73 -0
  232. package/packages/omo-codex/plugin/scripts/migrate-codex-config.mjs +20 -3
  233. package/packages/omo-codex/plugin/scripts/sync-skills.mjs +30 -8
  234. package/packages/omo-codex/plugin/skills/coding-agent-sessions/SKILL.md +128 -0
  235. package/packages/omo-codex/plugin/skills/coding-agent-sessions/agents/openai.yaml +4 -0
  236. package/packages/omo-codex/plugin/skills/coding-agent-sessions/references/all-platforms.md +71 -0
  237. package/packages/omo-codex/plugin/skills/coding-agent-sessions/references/claude.md +32 -0
  238. package/packages/omo-codex/plugin/skills/coding-agent-sessions/references/codex.md +30 -0
  239. package/packages/omo-codex/plugin/skills/coding-agent-sessions/references/opencode.md +43 -0
  240. package/packages/omo-codex/plugin/skills/coding-agent-sessions/references/senpi.md +17 -0
  241. package/packages/omo-codex/plugin/skills/coding-agent-sessions/scripts/agent_sessions/__init__.py +1 -0
  242. package/packages/omo-codex/plugin/skills/coding-agent-sessions/scripts/agent_sessions/claude.py +66 -0
  243. package/packages/omo-codex/plugin/skills/coding-agent-sessions/scripts/agent_sessions/cli.py +283 -0
  244. package/packages/omo-codex/plugin/skills/coding-agent-sessions/scripts/agent_sessions/codex.py +105 -0
  245. package/packages/omo-codex/plugin/skills/coding-agent-sessions/scripts/agent_sessions/file_scanners.py +275 -0
  246. package/packages/omo-codex/plugin/skills/coding-agent-sessions/scripts/agent_sessions/jsonio.py +55 -0
  247. package/packages/omo-codex/plugin/skills/coding-agent-sessions/scripts/agent_sessions/kiro_scanner.py +91 -0
  248. package/packages/omo-codex/plugin/skills/coding-agent-sessions/scripts/agent_sessions/opencode.py +289 -0
  249. package/packages/omo-codex/plugin/skills/coding-agent-sessions/scripts/agent_sessions/scanners.py +92 -0
  250. package/packages/omo-codex/plugin/skills/coding-agent-sessions/scripts/agent_sessions/sqlite_optional_scanners.py +203 -0
  251. package/packages/omo-codex/plugin/skills/coding-agent-sessions/scripts/agent_sessions/sqlite_scanners.py +177 -0
  252. package/packages/omo-codex/plugin/skills/coding-agent-sessions/scripts/agent_sessions/timeparse.py +51 -0
  253. package/packages/omo-codex/plugin/skills/coding-agent-sessions/scripts/agent_sessions/transcript.py +149 -0
  254. package/packages/omo-codex/plugin/skills/coding-agent-sessions/scripts/agent_sessions/types.py +57 -0
  255. package/packages/omo-codex/plugin/skills/coding-agent-sessions/scripts/find-agent-sessions.py +19 -0
  256. package/packages/omo-codex/plugin/skills/frontend/ATTRIBUTION.md +52 -8
  257. package/packages/omo-codex/plugin/skills/frontend/SKILL.md +29 -8
  258. package/packages/omo-codex/plugin/skills/frontend/references/design/README.md +29 -12
  259. package/packages/omo-codex/plugin/skills/frontend/references/design/_INDEX.md +3 -3
  260. package/packages/omo-codex/plugin/skills/frontend/references/design/design-system-architecture.md +22 -19
  261. package/packages/omo-codex/plugin/skills/frontend/references/designpowers/EVIDENCE.md +89 -0
  262. package/packages/omo-codex/plugin/skills/frontend/references/designpowers/README.md +48 -0
  263. package/packages/omo-codex/plugin/skills/frontend/references/designpowers/UPSTREAM.md +80 -0
  264. package/packages/omo-codex/plugin/skills/frontend/references/designpowers/lane-a-direction.md +64 -0
  265. package/packages/omo-codex/plugin/skills/frontend/references/designpowers/lane-b-execution.md +65 -0
  266. package/packages/omo-codex/plugin/skills/frontend/references/designpowers/lane-c-review.md +65 -0
  267. package/packages/omo-codex/plugin/skills/frontend/references/designpowers/lane-d-memory.md +83 -0
  268. package/packages/omo-codex/plugin/skills/frontend/references/designpowers/orchestration.md +80 -0
  269. package/packages/omo-codex/plugin/skills/frontend/references/designpowers/routing.md +79 -0
  270. package/packages/omo-codex/plugin/skills/frontend/references/designpowers/vendor/LICENSE +21 -0
  271. package/packages/omo-codex/plugin/skills/frontend/references/designpowers/vendor/agents/accessibility-reviewer.md +83 -0
  272. package/packages/omo-codex/plugin/skills/frontend/references/designpowers/vendor/agents/content-writer.md +132 -0
  273. package/packages/omo-codex/plugin/skills/frontend/references/designpowers/vendor/agents/design-builder.md +109 -0
  274. package/packages/omo-codex/plugin/skills/frontend/references/designpowers/vendor/agents/design-critic.md +89 -0
  275. package/packages/omo-codex/plugin/skills/frontend/references/designpowers/vendor/agents/design-lead.md +113 -0
  276. package/packages/omo-codex/plugin/skills/frontend/references/designpowers/vendor/agents/design-scout.md +78 -0
  277. package/packages/omo-codex/plugin/skills/frontend/references/designpowers/vendor/agents/design-strategist.md +121 -0
  278. package/packages/omo-codex/plugin/skills/frontend/references/designpowers/vendor/agents/heuristic-evaluator.md +268 -0
  279. package/packages/omo-codex/plugin/skills/frontend/references/designpowers/vendor/agents/inspiration-scout.md +107 -0
  280. package/packages/omo-codex/plugin/skills/frontend/references/designpowers/vendor/agents/motion-designer.md +120 -0
  281. package/packages/omo-codex/plugin/skills/frontend/references/designpowers/vendor/skills/accessible-content/SKILL.md +101 -0
  282. package/packages/omo-codex/plugin/skills/frontend/references/designpowers/vendor/skills/adaptive-interfaces/SKILL.md +109 -0
  283. package/packages/omo-codex/plugin/skills/frontend/references/designpowers/vendor/skills/cognitive-accessibility/SKILL.md +107 -0
  284. package/packages/omo-codex/plugin/skills/frontend/references/designpowers/vendor/skills/design-debate/SKILL.md +199 -0
  285. package/packages/omo-codex/plugin/skills/frontend/references/designpowers/vendor/skills/design-debt-tracker/SKILL.md +174 -0
  286. package/packages/omo-codex/plugin/skills/frontend/references/designpowers/vendor/skills/design-handoff/SKILL.md +125 -0
  287. package/packages/omo-codex/plugin/skills/frontend/references/designpowers/vendor/skills/design-md/SKILL.md +106 -0
  288. package/packages/omo-codex/plugin/skills/frontend/references/designpowers/vendor/skills/design-retrospective/SKILL.md +266 -0
  289. package/packages/omo-codex/plugin/skills/frontend/references/designpowers/vendor/skills/design-review/SKILL.md +123 -0
  290. package/packages/omo-codex/plugin/skills/frontend/references/designpowers/vendor/skills/design-system-alignment/SKILL.md +120 -0
  291. package/packages/omo-codex/plugin/skills/frontend/references/designpowers/vendor/skills/designpowers-critique/SKILL.md +164 -0
  292. package/packages/omo-codex/plugin/skills/frontend/references/designpowers/vendor/skills/heuristic-evaluation/SKILL.md +85 -0
  293. package/packages/omo-codex/plugin/skills/frontend/references/designpowers/vendor/skills/inclusive-personas/SKILL.md +98 -0
  294. package/packages/omo-codex/plugin/skills/frontend/references/designpowers/vendor/skills/inspiration-scouting/SKILL.md +165 -0
  295. package/packages/omo-codex/plugin/skills/frontend/references/designpowers/vendor/skills/interaction-design/SKILL.md +122 -0
  296. package/packages/omo-codex/plugin/skills/frontend/references/designpowers/vendor/skills/motion-choreography/SKILL.md +81 -0
  297. package/packages/omo-codex/plugin/skills/frontend/references/designpowers/vendor/skills/research-planning/SKILL.md +96 -0
  298. package/packages/omo-codex/plugin/skills/frontend/references/designpowers/vendor/skills/responsive-patterns/SKILL.md +77 -0
  299. package/packages/omo-codex/plugin/skills/frontend/references/designpowers/vendor/skills/synthetic-user-testing/SKILL.md +192 -0
  300. package/packages/omo-codex/plugin/skills/frontend/references/designpowers/vendor/skills/taste-feedback/SKILL.md +165 -0
  301. package/packages/omo-codex/plugin/skills/frontend/references/designpowers/vendor/skills/taste-report/SKILL.md +78 -0
  302. package/packages/omo-codex/plugin/skills/frontend/references/designpowers/vendor/skills/token-architecture/SKILL.md +75 -0
  303. package/packages/omo-codex/plugin/skills/frontend/references/designpowers/vendor/skills/ui-composition/SKILL.md +117 -0
  304. package/packages/omo-codex/plugin/skills/frontend/references/designpowers/vendor/skills/usability-testing/SKILL.md +78 -0
  305. package/packages/omo-codex/plugin/skills/frontend/references/designpowers/vendor/skills/verification-before-shipping/SKILL.md +125 -0
  306. package/packages/omo-codex/plugin/skills/frontend/references/designpowers/vendor/skills/voice-and-tone/SKILL.md +79 -0
  307. package/packages/omo-codex/plugin/skills/frontend/references/designpowers/vendor/skills/writing-design-plans/SKILL.md +119 -0
  308. package/packages/omo-codex/plugin/skills/frontend/references/ui-ux-db/scripts/core.py +0 -0
  309. package/packages/omo-codex/plugin/skills/git-master/SKILL.md +4 -0
  310. package/packages/omo-codex/plugin/skills/init-deep/SKILL.md +4 -0
  311. package/packages/omo-codex/plugin/skills/refactor/SKILL.md +4 -0
  312. package/packages/omo-codex/plugin/skills/remove-ai-slops/SKILL.md +4 -0
  313. package/packages/omo-codex/plugin/skills/review-work/SKILL.md +12 -4
  314. package/packages/omo-codex/plugin/skills/start-work/SKILL.md +14 -8
  315. package/packages/omo-codex/plugin/skills/teammode/SKILL.md +40 -2
  316. package/packages/omo-codex/plugin/skills/teammode/scripts/team-guide.mjs +32 -5
  317. package/packages/omo-codex/plugin/skills/teammode/scripts/team.mjs +7 -3
  318. package/packages/omo-codex/plugin/skills/ultraresearch/SKILL.md +4 -250
  319. package/packages/omo-codex/plugin/skills/ulw-loop/references/full-workflow.md +19 -11
  320. package/packages/omo-codex/plugin/skills/ulw-plan/SKILL.md +6 -4
  321. package/packages/omo-codex/plugin/skills/ulw-plan/references/full-workflow.md +11 -6
  322. package/packages/omo-codex/plugin/skills/ulw-plan/references/intent-clear.md +3 -3
  323. package/packages/omo-codex/plugin/skills/ulw-plan/references/intent-unclear.md +1 -1
  324. package/packages/{shared-skills/skills/ultraresearch → omo-codex/plugin/skills/ulw-research}/ATTRIBUTION.md +1 -1
  325. package/packages/omo-codex/plugin/skills/ulw-research/SKILL.md +262 -0
  326. package/packages/omo-codex/plugin/skills/ulw-research/agents/openai.yaml +2 -0
  327. package/packages/omo-codex/plugin/skills/visual-qa/SKILL.md +109 -14
  328. package/packages/omo-codex/plugin/test/aggregate-hooks.test.mjs +23 -0
  329. package/packages/omo-codex/plugin/test/aggregate-manifest.test.mjs +1 -0
  330. package/packages/omo-codex/plugin/test/auto-update-release-notes.test.mjs +1 -0
  331. package/packages/omo-codex/plugin/test/auto-update-restart-notice.test.mjs +24 -1
  332. package/packages/omo-codex/plugin/test/bootstrap-binlinks.test.mjs +23 -5
  333. package/packages/omo-codex/plugin/test/bootstrap-hooks.test.mjs +38 -0
  334. package/packages/omo-codex/plugin/test/bootstrap-ps-guard.test.mjs +25 -0
  335. package/packages/omo-codex/plugin/test/bootstrap-setup.test.mjs +1 -7
  336. package/packages/omo-codex/plugin/test/migrate-codex-config.test.mjs +206 -6
  337. package/packages/omo-codex/plugin/test/subagent-limit-migration.test.mjs +44 -0
  338. package/packages/omo-codex/plugin/test/sync-skills-orchestration.test.mjs +50 -1
  339. package/packages/omo-codex/plugin/test/sync-skills-test-support.mjs +10 -7
  340. package/packages/omo-codex/plugin/test/sync-skills.test.mjs +28 -2
  341. package/packages/omo-codex/plugin/test/teammode-communication.test.mjs +20 -0
  342. package/packages/omo-codex/plugin/test/teammode-thread-links.test.mjs +117 -0
  343. package/packages/omo-codex/plugin/test/teammode-worktree.test.mjs +5 -2
  344. package/packages/omo-codex/plugin/test/ulw-research-skill-contract.test.mjs +285 -0
  345. package/packages/omo-codex/scripts/install-bin-links.test.mjs +6 -1
  346. package/packages/omo-codex/scripts/install-cache-copy.test.mjs +51 -0
  347. package/packages/omo-codex/scripts/install-config.test.mjs +198 -17
  348. package/packages/omo-codex/scripts/install-dist/install-local.mjs +701 -282
  349. package/packages/omo-codex/scripts/install-local-git-bash-preflight.test.mjs +24 -15
  350. package/packages/omo-codex/scripts/install-local.test.mjs +5 -1
  351. package/packages/omo-codex/scripts/install-mcp-context7-runtime.test.mjs +84 -0
  352. package/packages/shared-skills/skills/coding-agent-sessions/SKILL.md +128 -0
  353. package/packages/shared-skills/skills/coding-agent-sessions/agents/openai.yaml +4 -0
  354. package/packages/shared-skills/skills/coding-agent-sessions/references/all-platforms.md +71 -0
  355. package/packages/shared-skills/skills/coding-agent-sessions/references/claude.md +32 -0
  356. package/packages/shared-skills/skills/coding-agent-sessions/references/codex.md +30 -0
  357. package/packages/shared-skills/skills/coding-agent-sessions/references/opencode.md +43 -0
  358. package/packages/shared-skills/skills/coding-agent-sessions/references/senpi.md +17 -0
  359. package/packages/shared-skills/skills/coding-agent-sessions/scripts/agent_sessions/__init__.py +1 -0
  360. package/packages/shared-skills/skills/coding-agent-sessions/scripts/agent_sessions/claude.py +66 -0
  361. package/packages/shared-skills/skills/coding-agent-sessions/scripts/agent_sessions/cli.py +283 -0
  362. package/packages/shared-skills/skills/coding-agent-sessions/scripts/agent_sessions/codex.py +105 -0
  363. package/packages/shared-skills/skills/coding-agent-sessions/scripts/agent_sessions/file_scanners.py +275 -0
  364. package/packages/shared-skills/skills/coding-agent-sessions/scripts/agent_sessions/jsonio.py +55 -0
  365. package/packages/shared-skills/skills/coding-agent-sessions/scripts/agent_sessions/kiro_scanner.py +91 -0
  366. package/packages/shared-skills/skills/coding-agent-sessions/scripts/agent_sessions/opencode.py +289 -0
  367. package/packages/shared-skills/skills/coding-agent-sessions/scripts/agent_sessions/scanners.py +92 -0
  368. package/packages/shared-skills/skills/coding-agent-sessions/scripts/agent_sessions/sqlite_optional_scanners.py +203 -0
  369. package/packages/shared-skills/skills/coding-agent-sessions/scripts/agent_sessions/sqlite_scanners.py +177 -0
  370. package/packages/shared-skills/skills/coding-agent-sessions/scripts/agent_sessions/timeparse.py +51 -0
  371. package/packages/shared-skills/skills/coding-agent-sessions/scripts/agent_sessions/transcript.py +149 -0
  372. package/packages/shared-skills/skills/coding-agent-sessions/scripts/agent_sessions/types.py +57 -0
  373. package/packages/shared-skills/skills/coding-agent-sessions/scripts/find-agent-sessions.py +19 -0
  374. package/packages/shared-skills/skills/frontend/ATTRIBUTION.md +52 -8
  375. package/packages/shared-skills/skills/frontend/SKILL.md +29 -8
  376. package/packages/shared-skills/skills/frontend/references/design/README.md +29 -12
  377. package/packages/shared-skills/skills/frontend/references/design/_INDEX.md +3 -3
  378. package/packages/shared-skills/skills/frontend/references/design/design-system-architecture.md +22 -19
  379. package/packages/shared-skills/skills/frontend/references/designpowers/EVIDENCE.md +89 -0
  380. package/packages/shared-skills/skills/frontend/references/designpowers/README.md +48 -0
  381. package/packages/shared-skills/skills/frontend/references/designpowers/UPSTREAM.md +80 -0
  382. package/packages/shared-skills/skills/frontend/references/designpowers/lane-a-direction.md +64 -0
  383. package/packages/shared-skills/skills/frontend/references/designpowers/lane-b-execution.md +65 -0
  384. package/packages/shared-skills/skills/frontend/references/designpowers/lane-c-review.md +65 -0
  385. package/packages/shared-skills/skills/frontend/references/designpowers/lane-d-memory.md +83 -0
  386. package/packages/shared-skills/skills/frontend/references/designpowers/orchestration.md +80 -0
  387. package/packages/shared-skills/skills/frontend/references/designpowers/routing.md +79 -0
  388. package/packages/shared-skills/skills/frontend/references/designpowers/vendor/LICENSE +21 -0
  389. package/packages/shared-skills/skills/frontend/references/designpowers/vendor/agents/accessibility-reviewer.md +83 -0
  390. package/packages/shared-skills/skills/frontend/references/designpowers/vendor/agents/content-writer.md +132 -0
  391. package/packages/shared-skills/skills/frontend/references/designpowers/vendor/agents/design-builder.md +109 -0
  392. package/packages/shared-skills/skills/frontend/references/designpowers/vendor/agents/design-critic.md +89 -0
  393. package/packages/shared-skills/skills/frontend/references/designpowers/vendor/agents/design-lead.md +113 -0
  394. package/packages/shared-skills/skills/frontend/references/designpowers/vendor/agents/design-scout.md +78 -0
  395. package/packages/shared-skills/skills/frontend/references/designpowers/vendor/agents/design-strategist.md +121 -0
  396. package/packages/shared-skills/skills/frontend/references/designpowers/vendor/agents/heuristic-evaluator.md +268 -0
  397. package/packages/shared-skills/skills/frontend/references/designpowers/vendor/agents/inspiration-scout.md +107 -0
  398. package/packages/shared-skills/skills/frontend/references/designpowers/vendor/agents/motion-designer.md +120 -0
  399. package/packages/shared-skills/skills/frontend/references/designpowers/vendor/skills/accessible-content/SKILL.md +101 -0
  400. package/packages/shared-skills/skills/frontend/references/designpowers/vendor/skills/adaptive-interfaces/SKILL.md +109 -0
  401. package/packages/shared-skills/skills/frontend/references/designpowers/vendor/skills/cognitive-accessibility/SKILL.md +107 -0
  402. package/packages/shared-skills/skills/frontend/references/designpowers/vendor/skills/design-debate/SKILL.md +199 -0
  403. package/packages/shared-skills/skills/frontend/references/designpowers/vendor/skills/design-debt-tracker/SKILL.md +174 -0
  404. package/packages/shared-skills/skills/frontend/references/designpowers/vendor/skills/design-handoff/SKILL.md +125 -0
  405. package/packages/shared-skills/skills/frontend/references/designpowers/vendor/skills/design-md/SKILL.md +106 -0
  406. package/packages/shared-skills/skills/frontend/references/designpowers/vendor/skills/design-retrospective/SKILL.md +266 -0
  407. package/packages/shared-skills/skills/frontend/references/designpowers/vendor/skills/design-review/SKILL.md +123 -0
  408. package/packages/shared-skills/skills/frontend/references/designpowers/vendor/skills/design-system-alignment/SKILL.md +120 -0
  409. package/packages/shared-skills/skills/frontend/references/designpowers/vendor/skills/designpowers-critique/SKILL.md +164 -0
  410. package/packages/shared-skills/skills/frontend/references/designpowers/vendor/skills/heuristic-evaluation/SKILL.md +85 -0
  411. package/packages/shared-skills/skills/frontend/references/designpowers/vendor/skills/inclusive-personas/SKILL.md +98 -0
  412. package/packages/shared-skills/skills/frontend/references/designpowers/vendor/skills/inspiration-scouting/SKILL.md +165 -0
  413. package/packages/shared-skills/skills/frontend/references/designpowers/vendor/skills/interaction-design/SKILL.md +122 -0
  414. package/packages/shared-skills/skills/frontend/references/designpowers/vendor/skills/motion-choreography/SKILL.md +81 -0
  415. package/packages/shared-skills/skills/frontend/references/designpowers/vendor/skills/research-planning/SKILL.md +96 -0
  416. package/packages/shared-skills/skills/frontend/references/designpowers/vendor/skills/responsive-patterns/SKILL.md +77 -0
  417. package/packages/shared-skills/skills/frontend/references/designpowers/vendor/skills/synthetic-user-testing/SKILL.md +192 -0
  418. package/packages/shared-skills/skills/frontend/references/designpowers/vendor/skills/taste-feedback/SKILL.md +165 -0
  419. package/packages/shared-skills/skills/frontend/references/designpowers/vendor/skills/taste-report/SKILL.md +78 -0
  420. package/packages/shared-skills/skills/frontend/references/designpowers/vendor/skills/token-architecture/SKILL.md +75 -0
  421. package/packages/shared-skills/skills/frontend/references/designpowers/vendor/skills/ui-composition/SKILL.md +117 -0
  422. package/packages/shared-skills/skills/frontend/references/designpowers/vendor/skills/usability-testing/SKILL.md +78 -0
  423. package/packages/shared-skills/skills/frontend/references/designpowers/vendor/skills/verification-before-shipping/SKILL.md +125 -0
  424. package/packages/shared-skills/skills/frontend/references/designpowers/vendor/skills/voice-and-tone/SKILL.md +79 -0
  425. package/packages/shared-skills/skills/frontend/references/designpowers/vendor/skills/writing-design-plans/SKILL.md +119 -0
  426. package/packages/shared-skills/skills/frontend/references/ui-ux-db/scripts/core.py +0 -0
  427. package/packages/shared-skills/skills/git-master/SKILL.md +4 -0
  428. package/packages/shared-skills/skills/review-work/SKILL.md +3 -3
  429. package/packages/shared-skills/skills/start-work/SKILL.md +7 -5
  430. package/packages/shared-skills/skills/ultraresearch/SKILL.md +4 -252
  431. package/packages/shared-skills/skills/ulw-plan/SKILL.md +8 -6
  432. package/packages/shared-skills/skills/ulw-plan/references/full-workflow.md +11 -6
  433. package/packages/shared-skills/skills/ulw-plan/references/intent-clear.md +3 -3
  434. package/packages/shared-skills/skills/ulw-plan/references/intent-unclear.md +1 -1
  435. package/packages/{omo-codex/plugin/skills/ultraresearch → shared-skills/skills/ulw-research}/ATTRIBUTION.md +1 -1
  436. package/packages/shared-skills/skills/ulw-research/SKILL.md +260 -0
  437. package/packages/shared-skills/skills/visual-qa/SKILL.md +105 -14
  438. package/packages/shared-skills/skills/visual-qa/scripts/skill-prompt-contract.test.ts +120 -1
  439. package/script/qa/web-terminal-redaction.d.mts +13 -0
  440. package/script/qa/web-terminal-redaction.mjs +43 -0
  441. package/script/qa/web-terminal-renderer.mjs +218 -0
  442. package/script/qa/web-terminal-visual-qa.mjs +264 -0
  443. package/packages/omo-codex/plugin/skills/ultimate-browsing/scripts/tests/test_cookie_domain_filter.py +0 -110
  444. package/packages/omo-codex/plugin/skills/ultimate-browsing/scripts/tests/test_extract_cookies.py +0 -245
  445. package/packages/omo-codex/plugin/test/ultraresearch-skill-contract.test.mjs +0 -204
@@ -6,6 +6,7 @@ export const CONTEXT_PRESSURE_SKILL_BUDGET_BYTES = 25_000;
6
6
 
7
7
  export const expectedSkills = [
8
8
  "ast-grep",
9
+ "coding-agent-sessions",
9
10
  "comment-checker",
10
11
  "debugging",
11
12
  "frontend",
@@ -27,6 +28,7 @@ export const expectedSkills = [
27
28
  "ultraresearch",
28
29
  "ulw-loop",
29
30
  "ulw-plan",
31
+ "ulw-research",
30
32
  "visual-qa",
31
33
  ];
32
34
 
@@ -41,6 +43,7 @@ export const componentSkillSources = [
41
43
 
42
44
  const codexCompatibilityEndMarkers = [
43
45
  "For work likely to exceed one wait cycle, require the child to send `WORKING: <task> - <current phase>` before long passes and `BLOCKED: <reason>` only when progress stops. A `multi_agent_v1.wait_agent` timeout only means no new mailbox update arrived. Treat a running child as alive. Fallback only when the child is completed without the deliverable, ack-only after followup, explicitly `BLOCKED:`, or no longer running.\n\n",
46
+ "On `multi_agent_v2` sessions the same `agent_type` applies (the OMO installer exposes it) with `fork_turns` instead of `fork_context`. If a code block below conflicts with this section, this section wins.\n\n",
44
47
  "Role-specific behavior must be described in a self-contained `message`. Use `fork_context: false` to start the child with only the initial prompt (no parent history); use `fork_context: true` only when full parent history is truly required. Include any required conversation context, files, diffs, constraints, and requested skill names directly in the spawned agent's `message`. If a code block below conflicts with this section, this section wins.\n\n",
45
48
  "When translating `load_skills=[...]`, include the requested skill names in the spawned agent's `message`. If a code block below conflicts with this section, this section wins.\n\n",
46
49
  "When translating `load_skills=[...]`, name the skills inside the spawned agent's `message`. If a code block below conflicts with this section, this section wins.\n\n",
@@ -64,29 +67,29 @@ export function removeCodexCompatibilityGuidance(content) {
64
67
  const startWorkOriginalCompletion = `When all top-level checkboxes in \`## TODOs\` and \`## Final Verification Wave\` are complete:
65
68
 
66
69
  1. Run the plan's final verification commands.
67
- 2. If worktree mode was used, sync \`.omo/\` state back to the main repo, merge or hand off exactly as requested, and remove the worktree only after successful merge or explicit handoff.
70
+ 2. For PR/branch work, finish the lifecycle from the task-owned worktree: sync \`.omo/\` state back to the main repo, create or update the PR, wait for review/verification gates, merge by default unless explicitly opted out, and remove the worktree only after successful merge or explicit handoff.
68
71
  3. Remove or mark the Boulder work as completed.
69
72
  4. Print an \`ORCHESTRATION COMPLETE\` block with the plan path, verification commands, artifacts, and cleanup receipts.`;
70
73
 
71
74
  const startWorkCodexCompletion = `When all top-level checkboxes in \`## TODOs\` and \`## Final Verification Wave\` are complete:
72
75
 
73
76
  1. Run the plan's final verification commands.
74
- 2. Complete the **Global Review and Debugging Gate** before any completion claim, PR handoff, or branch handoff:
77
+ 2. Complete the **Global Review and Debugging Gate** before any completion claim, PR creation, PR handoff, branch handoff, or merge:
75
78
  - Invoke the \`review-work\` skill with the final diff, changed files, user goal, constraints, run command, and verification evidence. All five review lanes must return PASS. A timeout, missing deliverable, ack-only child, \`BLOCKED:\`, or inconclusive lane is a gate failure, not approval.
76
79
  - Run a debugging-oriented runtime audit even when the review passes: name at least three plausible failure hypotheses for the changed surface, run the distinguishing checks against the actual artifact, and append the ruled-out or confirmed result to \`.omo/start-work/ledger.jsonl\`.
77
80
  - If any review lane or debugging hypothesis fails, invoke the \`debugging\` skill, confirm root cause with runtime evidence, add the minimal failing test or reproduction, fix it, rerun the affected verification, then rerun the Global Review and Debugging Gate.
78
81
  - Evidence hygiene is mandatory: redact or mask secrets and sensitive user data before writing \`.omo/start-work/ledger.jsonl\`, a PR body, or a handoff. Never include raw tokens, credentials, auth headers, cookies, API keys, env dumps, private logs, or PII; use concise summaries, lengths, hashes, or short non-sensitive prefixes instead.
79
- - If the work includes creating, updating, or handing off a PR, refresh \`git status\` and the PR/branch state after the gate, and include only redacted review/debugging evidence in the PR body or handoff.
80
- 3. If worktree mode was used, sync \`.omo/\` state back to the main repo, merge or hand off exactly as requested, and remove the worktree only after successful merge or explicit handoff.
82
+ - If the work includes creating, updating, or handing off a PR, refresh \`git status\` and the PR/branch state from the task-owned worktree after the gate, and include only redacted review/debugging evidence in the PR body or handoff.
83
+ 3. Finish the PR/branch lifecycle from its task-owned worktree: sync \`.omo/\` state back to the main repo, create or update the PR when requested, wait for CI/review/Cubic gates, merge by default unless explicitly opted out, and remove the worktree only after successful merge or explicit handoff.
81
84
  4. Remove or mark the Boulder work as completed.
82
85
  5. Print an \`ORCHESTRATION COMPLETE\` block with the plan path, verification commands, Global Review and Debugging Gate verdict, artifacts, and cleanup receipts.`;
83
86
 
84
- const startWorkOriginalHardRule = "- No completion claim while an applicable ultraqa adversarial class was never probed. Each applicable class needs a captured observable result; each skipped class needs a one-line not-applicable reason in the ledger.\n- No unprefixed session ids in Boulder state. Codex sessions are always `codex:<session_id>`.";
87
+ const startWorkOriginalHardRule = "- No completion claim while an applicable ultraqa adversarial class was never probed. Each applicable class needs a captured observable result; each skipped class needs a one-line not-applicable reason in the ledger.\n- No PR/branch implementation, review, or merge in the main worktree; use the task-owned git worktree.\n- No unprefixed session ids in Boulder state. Codex sessions are always `codex:<session_id>`.";
85
88
 
86
- const startWorkCodexHardRule = "- No completion claim while an applicable ultraqa adversarial class was never probed. Each applicable class needs a captured observable result; each skipped class needs a one-line not-applicable reason in the ledger.\n- No `ORCHESTRATION COMPLETE`, final response, PR creation, or PR handoff before the Global Review and Debugging Gate passes with recorded evidence.\n- No unprefixed session ids in Boulder state. Codex sessions are always `codex:<session_id>`.";
89
+ const startWorkCodexHardRule = "- No completion claim while an applicable ultraqa adversarial class was never probed. Each applicable class needs a captured observable result; each skipped class needs a one-line not-applicable reason in the ledger.\n- No `ORCHESTRATION COMPLETE`, final response, PR creation, PR handoff, or merge before the Global Review and Debugging Gate passes with recorded evidence.\n- No PR/branch implementation or review in the main worktree; create or use a task-owned git worktree first.\n- No unprefixed session ids in Boulder state. Codex sessions are always `codex:<session_id>`.";
87
90
 
88
91
  const reviewWorkCodexGatePattern =
89
- /\nWhen `review-work` is used as a final implementation, PR, or `\$start-work`\ngate, it is blocking\. A timeout, missing deliverable, ack-only response,\nexplicit `BLOCKED:`, or inconclusive lane is not a pass\. Treat that lane as\nfailed, investigate the underlying uncertainty with the `debugging` skill when\nruntime behavior may be wrong, fix with evidence, and rerun the affected lane\nbefore claiming completion or handing off a PR\.\n\nReview evidence must be safe to share\. Redact or mask secrets and sensitive\nuser data before including evidence in logs, PR bodies, or handoffs\. Never\ninclude raw tokens, credentials, auth headers, cookies, API keys, env dumps,\nprivate logs, or PII; summarize with lengths, hashes, and short non-sensitive\nprefixes when identity is needed\.\n/;
92
+ /\nWhen `review-work` is used as a final implementation, PR, or `\$start-work`\ngate, it is blocking\. A timeout, missing deliverable, ack-only response,\nexplicit `BLOCKED:`, or inconclusive lane is not a pass\. Treat that lane as\nfailed, investigate the underlying uncertainty with the `debugging` skill when\nruntime behavior may be wrong, fix with evidence, and rerun the affected lane\nbefore claiming completion, creating or handing off a PR, or merging\.\n\nWhen reviewing a PR or branch, collect diff, file contents, and verification\nresults from a dedicated review worktree attached to that branch\. Never\ncheckout, test, or edit the review branch in the main worktree\.\n\nReview evidence must be safe to share\. Redact or mask secrets and sensitive\nuser data before including evidence in logs, PR bodies, or handoffs\. Never\ninclude raw tokens, credentials, auth headers, cookies, API keys, env dumps,\nprivate logs, or PII; summarize with lengths, hashes, and short non-sensitive\nprefixes when identity is needed\.\n/;
90
93
 
91
94
  export function removeCodexSkillOverlays(skillName, content) {
92
95
  if (skillName === "start-work") {
@@ -112,10 +112,22 @@ test("#given shared skill source tests #when aggregate Codex skills are synced #
112
112
  const aggregateSkillsRoot = join(root, "skills");
113
113
 
114
114
  // when
115
- const visualQaFiles = await listSkillFiles(join(aggregateSkillsRoot, "visual-qa"));
115
+ const forbiddenFiles = [];
116
+ for (const skillName of expectedSkills) {
117
+ for (const file of await listSkillFiles(join(aggregateSkillsRoot, skillName))) {
118
+ const normalized = file.replaceAll("\\", "/");
119
+ const segments = normalized.split("/");
120
+ const scriptsIndex = segments.lastIndexOf("scripts");
121
+ const hasPythonTestDir = scriptsIndex !== -1 && segments[scriptsIndex + 1] === "tests";
122
+ const isSourceMetadata = normalized === ".gitignore" || normalized === ".npmignore" || normalized === "pyrightconfig.json";
123
+ if (normalized.endsWith(".test.ts") || hasPythonTestDir || segments.includes("__pycache__") || normalized.endsWith(".pyc") || isSourceMetadata) {
124
+ forbiddenFiles.push(`${skillName}/${normalized}`);
125
+ }
126
+ }
127
+ }
116
128
 
117
129
  // then
118
- assert.equal(visualQaFiles.some((file) => file.endsWith(".test.ts")), false);
130
+ assert.deepEqual(forbiddenFiles, []);
119
131
  });
120
132
 
121
133
  test("#given component skill sources #when aggregate Codex component skills are inspected #then generated copies have no hand-authored drift", async () => {
@@ -169,6 +181,20 @@ test("#given synced ulw-loop skill #when Codex hint metadata is inspected #then
169
181
  assert.match(interfaceMetadata, /- "ulw-loop"/);
170
182
  });
171
183
 
184
+ test("#given synced legacy ultraresearch alias #when inspected #then it points users at ulw-research", async () => {
185
+ // given
186
+ const skillRoot = join(root, "skills", "ultraresearch");
187
+
188
+ // when
189
+ const skill = await readFile(join(skillRoot, "SKILL.md"), "utf8");
190
+ const interfaceMetadata = await readFile(join(skillRoot, "agents", "openai.yaml"), "utf8");
191
+
192
+ // then
193
+ assert.match(skill, /^---\r?\nname: ultraresearch\r?\n/m);
194
+ assert.match(skill, /legacy name for `ulw-research`/);
195
+ assert.match(interfaceMetadata, /display_name: "\(OmO\) ultraresearch"/);
196
+ });
197
+
172
198
  test("#given synced git-master skill #when inspected #then commits and git history route through it", async () => {
173
199
  // given
174
200
  const skillRoot = join(root, "skills", "git-master");
@@ -53,6 +53,9 @@ test("#given a bound team #when the member field manual renders #then it gives c
53
53
  // then - an explicit peer-notify rule so cross-cutting findings are pushed, not siloed
54
54
  assert.match(guide, /to a \*\*peer\*\*/, "guide must have an explicit peer-notify rule");
55
55
  assert.match(guide, /touches their slice/, "guide must trigger peer messages on slice-touching findings");
56
+ // then - the reassurance WHY that ties the two halves together: frequent reporting is what earns
57
+ // uninterrupted focus, so the leader has no reason to interrupt a member who keeps it informed
58
+ assert.match(guide, /uninterrupted focus/i, "guide must tell members frequent updates buy uninterrupted focus from the leader");
56
59
  // then - the end-only directive that previously won is gone (it licensed batch-at-the-end reporting)
57
60
  assert.doesNotMatch(guide, /the moment your work is complete/, "the standalone end-only report directive must be removed");
58
61
  } finally {
@@ -85,3 +88,20 @@ test("#given the leader-facing SKILL.md #when it describes communication #then i
85
88
  assert.match(skill, /--session <your own thread id>/, "SKILL.md must require init --session <your own thread id>");
86
89
  assert.match(skill, /stuck polling|cannot report to you/i, "SKILL.md must explain why --session matters");
87
90
  });
91
+
92
+ // The leader (a GPT-5.5 main session) over-polls when nothing reframes silence as work: real jobdori
93
+ // run 019f07a6- fired 6 leader->child pings, 4 pure "WORKING CHECK"/"NUDGE" nags that interrupted the
94
+ // child mid-slice. The member guide already mandates frequent reporting; the missing half is telling the
95
+ // leader to WAIT. These tests pin that the leader-facing skill reframes quiet-as-working and gates any
96
+ // outbound ping behind concrete decision rules instead of letting anxiety drive a barrage.
97
+ test("#given the leader-facing SKILL.md #when it covers waiting on members #then it reframes a quiet member as working and gates leader pings behind decision rules", () => {
98
+ const skill = readFileSync(join(root, "components", "teammode", "skills", "teammode", "SKILL.md"), "utf8");
99
+
100
+ // then - a quiet member between heartbeats is reframed as working, not a stall to chase
101
+ // (\s+ tolerates markdown line-wrapping between the two words)
102
+ assert.match(skill, /working,\s+not stalled/i, "SKILL.md must reframe a quiet member as working, not stalled");
103
+ // then - outbound leader messages are gated behind explicit decision rules, not anxiety
104
+ assert.match(skill, /Message a member only when/i, "SKILL.md must gate leader pings behind a concrete decision rule");
105
+ // then - the anti-pattern nag pings the real run produced are named as what NOT to send
106
+ assert.match(skill, /are you\s+done\?/i, "SKILL.md must name the 'are you done?' style nag as forbidden");
107
+ });
@@ -0,0 +1,117 @@
1
+ import assert from "node:assert/strict";
2
+ import { readFileSync } from "node:fs";
3
+ import test from "node:test";
4
+
5
+ import { cleanupTeamRoot, createTeamRoot, runTeam, teamDir } from "./teammode-safety-fixture.mjs";
6
+
7
+ function addMember(tempRoot, sessionId, { id, name, focus, lens, deliverable }) {
8
+ runTeam(
9
+ tempRoot,
10
+ "add-member",
11
+ "--team",
12
+ sessionId,
13
+ "--id",
14
+ id,
15
+ "--name",
16
+ name,
17
+ "--focus",
18
+ focus,
19
+ "--lens",
20
+ lens,
21
+ "--deliverable",
22
+ deliverable,
23
+ );
24
+ }
25
+
26
+ test("#given a worktree-backed team has bound member threads #when guide and status render #then they include codex thread links", () => {
27
+ const tempRoot = createTeamRoot("omo-codex-teammode-thread-links-");
28
+ try {
29
+ const sessionId = "thread-links";
30
+ runTeam(tempRoot, "init", "--name", "Review", "--session-name", "worktrees", "--session", sessionId, "--worktree");
31
+ addMember(tempRoot, sessionId, {
32
+ id: "A",
33
+ name: "qa-review-r2",
34
+ focus: "review PR 545 QA audit",
35
+ lens: "perspective",
36
+ deliverable: "write qa-review artifact",
37
+ });
38
+ addMember(tempRoot, sessionId, {
39
+ id: "B",
40
+ name: "pr-driver",
41
+ focus: "drive PR readiness",
42
+ lens: "ownership",
43
+ deliverable: "prepare review handoff",
44
+ });
45
+ runTeam(
46
+ tempRoot,
47
+ "bind-thread",
48
+ "--team",
49
+ sessionId,
50
+ "--id",
51
+ "A",
52
+ "--thread",
53
+ "019ef350-ee78-72a3-bd5e-e40cebc3d814",
54
+ "--cwd",
55
+ "/tmp/review-worktree",
56
+ );
57
+ runTeam(
58
+ tempRoot,
59
+ "bind-thread",
60
+ "--team",
61
+ sessionId,
62
+ "--id",
63
+ "B",
64
+ "--thread",
65
+ "019ef2dd-5b99-7ae2-8461-ffa6ca309d23",
66
+ "--cwd",
67
+ "/tmp/pr-driver-worktree",
68
+ );
69
+
70
+ const guide = readFileSync(`${teamDir(tempRoot, sessionId)}/guide.md`, "utf8");
71
+ const status = runTeam(tempRoot, "status", "--team", sessionId).stdout;
72
+ const prompt = runTeam(tempRoot, "member-prompt", "--team", sessionId, "--id", "A").stdout;
73
+
74
+ assert.match(guide, /codex:\/\/threads\/019ef350-ee78-72a3-bd5e-e40cebc3d814/);
75
+ assert.match(guide, /codex:\/\/threads\/019ef2dd-5b99-7ae2-8461-ffa6ca309d23/);
76
+ assert.match(guide, /worktree `\/tmp\/review-worktree`/);
77
+ assert.match(status, /link=codex:\/\/threads\/019ef350-ee78-72a3-bd5e-e40cebc3d814/);
78
+ assert.match(prompt, /Your Codex thread link is codex:\/\/threads\/019ef350-ee78-72a3-bd5e-e40cebc3d814/);
79
+ assert.match(prompt, /Work inside `\/tmp\/review-worktree`/);
80
+ assert.match(prompt, /Before editing, verify that your assigned worktree exists and contains repo files/);
81
+ assert.match(prompt, /BLOCKED: worktree not ready/);
82
+ } finally {
83
+ cleanupTeamRoot(tempRoot);
84
+ }
85
+ });
86
+
87
+ test("#given a worktree member has no cwd bound yet #when guide and prompt render #then they tell Codex to wait for readiness", () => {
88
+ const tempRoot = createTeamRoot("omo-codex-teammode-worktree-wait-");
89
+ try {
90
+ const sessionId = "worktree-wait";
91
+ runTeam(tempRoot, "init", "--name", "Wait", "--session-name", "worktrees", "--session", sessionId, "--worktree", "--base-branch", "main");
92
+ addMember(tempRoot, sessionId, {
93
+ id: "A",
94
+ name: "worktree-driver",
95
+ focus: "drive a pending Codex worktree thread",
96
+ lens: "ownership",
97
+ deliverable: "ready worktree report",
98
+ });
99
+ addMember(tempRoot, sessionId, {
100
+ id: "B",
101
+ name: "integration-watch",
102
+ focus: "watch integration boundaries",
103
+ lens: "perspective",
104
+ deliverable: "integration notes",
105
+ });
106
+ runTeam(tempRoot, "bind-thread", "--team", sessionId, "--id", "A", "--thread", "019ef350-ee78-72a3-bd5e-e40cebc3d814");
107
+
108
+ const guide = readFileSync(`${teamDir(tempRoot, sessionId)}/guide.md`, "utf8");
109
+ const prompt = runTeam(tempRoot, "member-prompt", "--team", sessionId, "--id", "A").stdout;
110
+
111
+ assert.match(guide, /If Codex returns only `pendingWorktreeId`/);
112
+ assert.match(guide, /wait until Codex surfaces a real thread id/);
113
+ assert.match(prompt, /If this prompt arrived before your Codex worktree checkout is ready/);
114
+ } finally {
115
+ cleanupTeamRoot(tempRoot);
116
+ }
117
+ });
@@ -78,9 +78,12 @@ test("#given a worktree team #when worktree-add A #then a real git worktree on a
78
78
  assert.equal(member.worktree.branch, expectedBranch);
79
79
  assert.ok(samePath(member.cwd, expectedPath), "cwd must be the member worktree dir");
80
80
 
81
- // then - the leader is told the exact cd target
82
- assert.match(result.stdout, /cd /);
81
+ // then - the leader is told the exact worktree target without prompting an unbound member
82
+ assert.match(result.stdout, new RegExp(expectedPath.replace(/[.*+?^${}()|[\]\\]/g, "\\$&")));
83
83
  assert.match(result.stdout, /A/);
84
+ assert.match(result.stdout, /wait for the real Codex thread id/);
85
+ assert.match(result.stdout, /bind-thread before sending bootstrap/);
86
+ assert.doesNotMatch(result.stdout, /Tell that member to:/);
84
87
  } finally {
85
88
  cleanupTeamRoot(tempRoot);
86
89
  }
@@ -0,0 +1,285 @@
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
+ import assert from "node:assert/strict";
4
+ import { readFile } from "node:fs/promises";
5
+ import { dirname, join } from "node:path";
6
+ import test from "node:test";
7
+ import { fileURLToPath } from "node:url";
8
+ import { sharedSkillsRootPath } from "@oh-my-opencode/shared-skills";
9
+
10
+ const root = dirname(dirname(fileURLToPath(import.meta.url)));
11
+
12
+ async function readUlwResearchCopies() {
13
+ const sharedPath = join(sharedSkillsRootPath(), "ulw-research", "SKILL.md");
14
+ const packagedPath = join(root, "skills", "ulw-research", "SKILL.md");
15
+ return [
16
+ { label: "shared", path: sharedPath, content: await readFile(sharedPath, "utf8") },
17
+ { label: "packaged", path: packagedPath, content: await readFile(packagedPath, "utf8") },
18
+ ];
19
+ }
20
+
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 () => {
46
+ for (const copy of await readUlwResearchCopies()) {
47
+ assert.match(copy.content, /^name: ulw-research$/m, `${copy.label}: frontmatter must expose ulw-research`);
48
+ }
49
+ });
50
+
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
+ assert.match(description, /ultraresearch/i, `${copy.label}: description must preserve ultraresearch discoverability`);
81
+ assert.match(description, /\bulw\b/i, `${copy.label}: description must preserve ulw discoverability`);
82
+ assert.match(description, /explicit/i, `${copy.label}: description must gate activation on explicit demand`);
83
+ assert.match(
84
+ description,
85
+ /ultra-precise investigation/i,
86
+ `${copy.label}: description must name the ultra-precise investigation trigger`,
87
+ );
88
+ assert.match(description, /\bresearch\b/i, `${copy.label}: description must name the research trigger`);
89
+ }
90
+ });
91
+
92
+ test("#given ulw-research body #when authority is inspected #then it takes precedence over exploration-bounding instructions", async () => {
93
+ for (const copy of await readUlwResearchCopies()) {
94
+ assert.match(
95
+ copy.content,
96
+ /exploration-bounding|exploration (?:caps|budgets|limits)/i,
97
+ `${copy.label}: body must name the exploration-bounding instructions it overrides`,
98
+ );
99
+ assert.match(
100
+ copy.content,
101
+ /supersede|override|do(?:es)? not (?:bind|apply)/i,
102
+ `${copy.label}: body must state precedence while the mode is active`,
103
+ );
104
+ }
105
+ });
106
+
107
+ test("#given ulw-research worker protocol #when EXPAND flow is inspected #then markers travel as message text and workers never write files", async () => {
108
+ for (const copy of await readUlwResearchCopies()) {
109
+ assert.match(copy.content, /EXPAND/, `${copy.label}: body must keep the EXPAND marker protocol`);
110
+ assert.match(
111
+ copy.content,
112
+ /(?:reply|message|response) text|end (?:its|the|your) (?:reply|response|final message)/i,
113
+ `${copy.label}: EXPAND markers must be returned as message text`,
114
+ );
115
+ assert.match(
116
+ copy.content,
117
+ /read-only|cannot write files|never ask (?:a )?worker(?:s)? to write/i,
118
+ `${copy.label}: body must state the read-only worker constraint`,
119
+ );
120
+ assert.doesNotMatch(
121
+ copy.content,
122
+ /APPEND (?:your )?findings to \$SESSION_DIR/i,
123
+ `${copy.label}: workers must not be instructed to append session-dir files`,
124
+ );
125
+ }
126
+ });
127
+
128
+ test("#given ulw-research journaling #when ownership is inspected #then the orchestrator owns the session journal", async () => {
129
+ for (const copy of await readUlwResearchCopies()) {
130
+ assert.match(
131
+ copy.content,
132
+ /orchestrator[\s\S]{0,200}journal|journal[\s\S]{0,200}orchestrator/i,
133
+ `${copy.label}: body must assign session-journal writes to the orchestrator`,
134
+ );
135
+ assert.match(copy.content, /SESSION_DIR/, `${copy.label}: body must keep the session directory protocol`);
136
+ }
137
+ });
138
+
139
+ test("#given ulw-research expansion loop #when stop rules are inspected #then convergence rules and a depth cap are stated", async () => {
140
+ for (const copy of await readUlwResearchCopies()) {
141
+ assert.match(copy.content, /converg/i, `${copy.label}: body must define convergence`);
142
+ assert.match(copy.content, /depth/i, `${copy.label}: body must define an expansion depth cap`);
143
+ assert.match(
144
+ copy.content,
145
+ /minimum (?:of )?(?:2|two) expansion waves|at least (?:2|two) expansion waves/i,
146
+ `${copy.label}: body must require a minimum of two expansion waves before convergence`,
147
+ );
148
+ }
149
+ });
150
+
151
+ test("#given ulw-research under ultrawork #when coexistence is inspected #then marker and done-definition conflicts are resolved", async () => {
152
+ for (const copy of await readUlwResearchCopies()) {
153
+ assert.match(copy.content, /ultrawork|\bulw\b/i, `${copy.label}: body must address ultrawork coexistence`);
154
+ assert.match(
155
+ copy.content,
156
+ /first(?:-| )line/i,
157
+ `${copy.label}: body must resolve the first-line activation marker conflict`,
158
+ );
159
+ }
160
+ });
161
+
162
+ test("#given ulw-research worker sizing #when spawn guidance is inspected #then capable-model and high-effort routing is stated", async () => {
163
+ for (const copy of await readUlwResearchCopies()) {
164
+ assert.match(
165
+ copy.content,
166
+ /capable model|high(?:est)? (?:reasoning )?effort/i,
167
+ `${copy.label}: body must route research workers to a capable model or high effort`,
168
+ );
169
+ }
170
+ });
171
+
172
+ test("#given ulw-research execution substrate #when team usage is inspected #then it prefers a cooperating team with harness-native team tools", async () => {
173
+ for (const copy of await readUlwResearchCopies()) {
174
+ assert.match(
175
+ copy.content,
176
+ /cooperating team/i,
177
+ `${copy.label}: body must encourage running the swarm as a cooperating team`,
178
+ );
179
+ assert.match(copy.content, /\bteammode\b/i, `${copy.label}: body must name the Codex teammode skill`);
180
+ assert.match(copy.content, /team_mode/i, `${copy.label}: body must name the OpenCode team_mode path`);
181
+ }
182
+ });
183
+
184
+ test("#given ulw-research team composition #when member slicing is inspected #then members map to part/ownership/perspective, never job titles", async () => {
185
+ for (const copy of await readUlwResearchCopies()) {
186
+ assert.match(
187
+ copy.content,
188
+ /by part, ownership, or perspective/i,
189
+ `${copy.label}: body must compose members by part, ownership, or perspective`,
190
+ );
191
+ assert.match(
192
+ copy.content,
193
+ /never a job title|not (?:a |by )?job title/i,
194
+ `${copy.label}: body must forbid vague job-title members`,
195
+ );
196
+ }
197
+ });
198
+
199
+ test("#given ulw-research team communication #when the raise law is inspected #then members broadcast every lead immediately rather than hoarding", async () => {
200
+ for (const copy of await readUlwResearchCopies()) {
201
+ assert.match(
202
+ copy.content,
203
+ /raise law|broadcast every lead/i,
204
+ `${copy.label}: body must state the raise/broadcast law`,
205
+ );
206
+ assert.match(copy.content, /over-communicate/i, `${copy.label}: body must demand over-communication`);
207
+ assert.match(
208
+ copy.content,
209
+ /the (?:moment|instant) it (?:surfaces|appears|lands)/i,
210
+ `${copy.label}: body must require raising leads the moment they surface`,
211
+ );
212
+ assert.match(
213
+ copy.content,
214
+ /hoard/i,
215
+ `${copy.label}: body must reject hoarding leads for a final dump`,
216
+ );
217
+ }
218
+ });
219
+
220
+ test("#given ulw-research default swarm #when team guidance is inspected #then teammode, many teammates, and hyperdebate are defaulted", async () => {
221
+ for (const copy of await readUlwResearchCopies()) {
222
+ const teamSection = markdownSection(copy.content, "## Run the swarm as a cooperating team", "## Worker ground rules");
223
+ assert.match(teamSection, /default(?:s)? to teammode|teammode by default/i, `${copy.label}: teammode must be the default`);
224
+ assert.match(teamSection, /many teammates|larger roster|5-8 teammates|5\+ teammates/i, `${copy.label}: body must prefer many teammates`);
225
+ assert.match(teamSection, /hyperdebate|ultradebate/i, `${copy.label}: body must require adversarial debate`);
226
+ assert.match(teamSection, /skeptic|red-team|cross-critique/i, `${copy.label}: body must include a critique perspective`);
227
+ }
228
+ });
229
+
230
+ test("#given ulw-research non-code verification #when the gate is inspected #then a claim ledger / verified-claims data-flow-lock exists", async () => {
231
+ for (const copy of await readUlwResearchCopies()) {
232
+ assert.match(
233
+ copy.content,
234
+ /claim ledger|verified-claims/i,
235
+ `${copy.label}: body must define the non-code claim-ledger verification gate`,
236
+ );
237
+ }
238
+ });
239
+
240
+ test("#given ulw-research claim ledger #when ownership is inspected #then workers never write the ledger / verified-claims artifact", async () => {
241
+ for (const copy of await readUlwResearchCopies()) {
242
+ assert.doesNotMatch(
243
+ copy.content,
244
+ /worker[^.]*\b(?:write|append|create)s?\b[^.]*(?:ledger|verified-claims)/i,
245
+ `${copy.label}: workers must not be instructed to write/append/create the ledger or verified-claims`,
246
+ );
247
+ }
248
+ });
249
+
250
+ test("#given ulw-research report output #when defaults are inspected #then HTML/PDF reports go through frontend, visual QA, and reviewer approval", async () => {
251
+ for (const copy of await readUlwResearchCopies()) {
252
+ const phase0 = markdownSection(copy.content, "## Phase 0 — Decompose and open the journal", "## Phase 1 — Saturation wave");
253
+ const phase4 = markdownSection(copy.content, "## Phase 4 — Synthesize", "## Phase 5 — Final materials");
254
+ const phase5 = markdownSection(copy.content, "## Phase 5 — Final materials", "## Search craft");
255
+ 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`);
256
+ assert.match(phase4, /citation source of truth/i, `${copy.label}: Phase 4 synthesis must be a source of truth, not the default final artifact`);
257
+ 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`);
258
+ 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`);
259
+ assert.match(phase5, /HTML first[\s\S]{0,120}PDF default/i, `${copy.label}: report output must default to HTML with PDF availability`);
260
+ assert.match(phase5, /\bfrontend\b/i, `${copy.label}: report assembly must load the frontend skill`);
261
+ assert.match(phase5, /visual-qa/i, `${copy.label}: report assembly must require visual-qa`);
262
+ assert.match(phase5, /ulw-loop|ULW loop/i, `${copy.label}: report QA must run under the ULW loop`);
263
+ 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`);
264
+ }
265
+ });
266
+
267
+ test("#given ulw-research final materials #when visual artifact guidance is inspected #then charts Mermaid graphs and imagegen are strongly required", async () => {
268
+ for (const copy of await readUlwResearchCopies()) {
269
+ const phase5 = markdownSection(copy.content, "## Phase 5 — Final materials", "## Search craft");
270
+ assert.match(phase5, /actively use charts/i, `${copy.label}: reports must strongly require charts`);
271
+ assert.match(phase5, /Mermaid graphs/i, `${copy.label}: reports must require Mermaid graphs`);
272
+ assert.match(phase5, /imagegen skill/i, `${copy.label}: reports must require imagegen visuals`);
273
+ assert.match(phase5, /generated (?:diagrams|visuals)|generated diagrams or editorial visuals/i, `${copy.label}: report assets must include generated visual guidance`);
274
+ }
275
+ });
276
+
277
+ test("#given ulw-research blocked sources #when escalation is inspected #then it routes through the ultimate-browsing skill", async () => {
278
+ for (const copy of await readUlwResearchCopies()) {
279
+ assert.match(
280
+ copy.content,
281
+ /ultimate-browsing/,
282
+ `${copy.label}: body must escalate blocked sources via the ultimate-browsing skill`,
283
+ );
284
+ }
285
+ });
@@ -1,3 +1,5 @@
1
+ // allow: SIZE_OK - bin link installer tests share one cross-platform link fixture; this release adds narrow link cases and future additions should split by platform family.
2
+
1
3
  import assert from "node:assert/strict";
2
4
  import { spawnSync } from "node:child_process";
3
5
  import { chmod, lstat, mkdir, readFile, readlink, symlink, writeFile } from "node:fs/promises";
@@ -154,7 +156,10 @@ test("#given Windows platform #when linking cached plugin bins #then writes comm
154
156
  assert.deepEqual(linked, [{ name: "alpha", path: join(binDir, "alpha.cmd"), target: join(pluginRoot, "dist", "cli.js") }]);
155
157
  const shim = await readFile(join(binDir, "alpha.cmd"), "utf8");
156
158
  assert.match(shim, /@echo off/);
157
- assert.match(shim, new RegExp(`node "${join(pluginRoot, "dist", "cli.js").replace(/[.*+?^${}()|[\]\\]/g, "\\$&")}" %\\*`));
159
+ assert.match(shim, /NODE_REPL_NODE_PATH/);
160
+ assert.match(shim, /"%OMO_NODE_BINARY%"/);
161
+ assert.match(shim, new RegExp(`"${join(pluginRoot, "dist", "cli.js").replace(/[.*+?^${}()|[\]\\]/g, "\\$&")}" %\\*`));
162
+ assert.doesNotMatch(shim, new RegExp(`node "${join(pluginRoot, "dist", "cli.js").replace(/[.*+?^${}()|[\]\\]/g, "\\$&")}" %\\*`));
158
163
  });
159
164
 
160
165
  test("#given existing custom Windows command shim #when linking bins #then rejects without overwriting", async () => {
@@ -87,6 +87,57 @@ test("#given cached file dependency is rewritten #when lockfile exists #then pac
87
87
  assert.equal(cachedPackageLock.packages["node_modules/@scope/lsp-tools"].resolved, packageLockDependencyPath);
88
88
  });
89
89
 
90
+ test("#given npm creates workspace bin shims in the cache #when caching plugin #then plugin-owned shims are removed", async () => {
91
+ // given
92
+ const root = await makeTempDir();
93
+ const codexHome = join(root, "codex-home");
94
+ const sourceRoot = join(root, "plugin");
95
+ const componentRoot = join(sourceRoot, "components", "ulw-loop");
96
+ await mkdir(join(componentRoot, "dist"), { recursive: true });
97
+ await writeFile(
98
+ join(sourceRoot, "package.json"),
99
+ JSON.stringify({
100
+ name: "@scope/omo",
101
+ version: "0.1.0",
102
+ workspaces: ["components/ulw-loop"],
103
+ }),
104
+ );
105
+ await writeFile(
106
+ join(componentRoot, "package.json"),
107
+ JSON.stringify({
108
+ name: "@code-yeongyu/codex-ulw-loop",
109
+ version: "0.1.0",
110
+ bin: { "omo-ulw-loop": "dist/cli.js" },
111
+ }),
112
+ );
113
+ await writeFile(join(componentRoot, "dist", "cli.js"), "#!/usr/bin/env node\n");
114
+
115
+ // when
116
+ const installed = await installCachedPlugin({
117
+ codexHome,
118
+ marketplaceName: "debug",
119
+ name: "omo",
120
+ sourcePath: sourceRoot,
121
+ version: "0.1.0",
122
+ runCommand: async (_command, args, options) => {
123
+ if (args.join(" ") !== "ci --omit=dev") return;
124
+ const npmBinDir = join(options.cwd, "node_modules", ".bin");
125
+ await mkdir(npmBinDir, { recursive: true });
126
+ await writeFile(join(npmBinDir, "omo-ulw-loop"), "#!/bin/sh\nnode ../@code-yeongyu/codex-ulw-loop/dist/cli.js \"$@\"\n");
127
+ await writeFile(
128
+ join(npmBinDir, "omo-ulw-loop.cmd"),
129
+ '@echo off\r\nnode "%~dp0\\..\\@code-yeongyu\\codex-ulw-loop\\dist\\cli.js" %*\r\n',
130
+ );
131
+ await writeFile(join(npmBinDir, "other-tool.cmd"), "@echo off\r\necho preserved\r\n");
132
+ },
133
+ });
134
+
135
+ // then
136
+ await assert.rejects(stat(join(installed.path, "node_modules", ".bin", "omo-ulw-loop")));
137
+ await assert.rejects(stat(join(installed.path, "node_modules", ".bin", "omo-ulw-loop.cmd")));
138
+ assert.equal(await readFile(join(installed.path, "node_modules", ".bin", "other-tool.cmd"), "utf8"), "@echo off\r\necho preserved\r\n");
139
+ });
140
+
90
141
  test("#given existing cache #when npm install fails #then previous active cache is preserved", async () => {
91
142
  // given
92
143
  const root = await makeTempDir();