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
@@ -1,20 +1,27 @@
1
1
  import assert from "node:assert/strict";
2
+ import { execFile } from "node:child_process";
2
3
  import { lstat, mkdir, mkdtemp, readdir, readFile, readlink, rm, stat, writeFile } from "node:fs/promises";
3
4
  import { tmpdir } from "node:os";
4
- import { join, sep } from "node:path";
5
+ import { dirname, join, sep } from "node:path";
5
6
  import test from "node:test";
7
+ import { promisify } from "node:util";
6
8
 
7
9
  const CLI_URL = new URL("../components/bootstrap/dist/cli.js", import.meta.url);
8
10
  const { runBootstrapWorker, runWorkerSetup } = await import(CLI_URL.href);
9
11
 
10
12
  const MARKETPLACE_SOURCE_LINE = 'source = "https://github.com/code-yeongyu/lazycodex.git"';
11
13
  const COMPONENT_BIN_NAME = "omo-toolbox";
14
+ const execFileAsync = promisify(execFile);
12
15
  const OMO_CLI_DEGRADED_ENTRY = {
13
16
  component: "omo-cli",
14
17
  hint: "use npx lazycodex-ai for the omo CLI",
15
18
  reason: "marketplace payload has no dist/cli",
16
19
  };
17
20
 
21
+ function escapeRegExp(value) {
22
+ return value.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
23
+ }
24
+
18
25
  async function withBinLinkFixture(run) {
19
26
  const root = await mkdtemp(join(tmpdir(), "omo-bootstrap-binlinks-"));
20
27
  try {
@@ -79,6 +86,8 @@ async function writeVersionedRoot(root, version, { withRuntimeCli = false } = {}
79
86
  if (withRuntimeCli) {
80
87
  await mkdir(join(pluginRoot, "dist", "cli"), { recursive: true });
81
88
  await writeFile(join(pluginRoot, "dist", "cli", "index.js"), "console.log('omo');\n");
89
+ await mkdir(join(pluginRoot, "dist", "cli-node"), { recursive: true });
90
+ await writeFile(join(pluginRoot, "dist", "cli-node", "index.js"), "console.log('omo node runtime');\n");
82
91
  }
83
92
  return pluginRoot;
84
93
  }
@@ -196,14 +205,18 @@ test("#given platform win32 #when the worker setup links bins #then component bi
196
205
  assert.deepEqual(outcome.degraded, []);
197
206
  const shim = await readFile(join(fixture.binDir, `${COMPONENT_BIN_NAME}.cmd`), "utf8");
198
207
  assert.match(shim, /@echo off/);
199
- assert.ok(shim.includes(`node "${join(pluginRoot, "components", "toolbox", "dist", "cli.js")}"`));
208
+ const componentEntrypoint = join(pluginRoot, "components", "toolbox", "dist", "cli.js");
209
+ assert.match(shim, /NODE_REPL_NODE_PATH/);
210
+ assert.match(shim, /"%OMO_NODE_BINARY%"/);
211
+ assert.match(shim, new RegExp(`"${escapeRegExp(componentEntrypoint)}" %\\*`));
212
+ assert.doesNotMatch(shim, new RegExp(`node "${escapeRegExp(componentEntrypoint)}" %\\*`));
200
213
  const wrapper = await readFile(join(fixture.binDir, "omo.cmd"), "utf8");
201
214
  assert.ok(wrapper.includes(join(pluginRoot, "dist", "cli", "index.js")));
202
215
  await assert.rejects(() => lstat(join(fixture.binDir, COMPONENT_BIN_NAME)), "win32 must not leave posix symlinks behind");
203
216
  });
204
217
  });
205
218
 
206
- test("#given a marketplace payload without dist/cli #when the worker setup runs #then it records the degraded omo-cli entry, logs the skip warning, and leaves no broken or omo link", async () => {
219
+ test("#given a legacy payload without root CLI dist #when the worker setup runs #then it records degraded omo-cli and leaves no broken link", async () => {
207
220
  await withBinLinkFixture(async (fixture) => {
208
221
  const pluginRoot = await writeVersionedRoot(fixture.root, "1.0.0");
209
222
 
@@ -234,14 +247,19 @@ test("#given a payload shipping dist/cli #when the worker setup runs with no bin
234
247
  assert.deepEqual(outcome.degraded, []);
235
248
  const defaultBinDir = join(fixture.codexHome, "bin");
236
249
  const wrapperName = process.platform === "win32" ? "omo.cmd" : "omo";
237
- const wrapper = await readFile(join(defaultBinDir, wrapperName), "utf8");
250
+ const wrapperPath = join(defaultBinDir, wrapperName);
251
+ const wrapper = await readFile(wrapperPath, "utf8");
238
252
  assert.ok(wrapper.includes(join(pluginRoot, "dist", "cli", "index.js")));
239
253
  if (process.platform !== "win32") {
240
- assert.ok((await stat(join(defaultBinDir, "omo"))).mode & 0o111, "the posix omo wrapper must be executable");
254
+ assert.ok((await stat(wrapperPath)).mode & 0o111, "the posix omo wrapper must be executable");
241
255
  assert.equal(
242
256
  await readlink(join(defaultBinDir, COMPONENT_BIN_NAME)),
243
257
  join(pluginRoot, "components", "toolbox", "dist", "cli.js"),
244
258
  );
259
+ const result = await execFileAsync(wrapperPath, ["--version"], {
260
+ env: { ...process.env, OMO_RUNTIME: "node", PATH: `${dirname(process.execPath)}:/usr/bin:/bin` },
261
+ });
262
+ assert.match(result.stdout, /omo node runtime/);
245
263
  } else {
246
264
  const shim = await readFile(join(defaultBinDir, `${COMPONENT_BIN_NAME}.cmd`), "utf8");
247
265
  assert.ok(shim.includes(join(pluginRoot, "components", "toolbox", "dist", "cli.js")));
@@ -16,6 +16,8 @@ const SKIPPED_DIRECTORY_NAMES = new Set([".git", "node_modules"]);
16
16
  const EXPECTED_BOOTSTRAP_COMMAND = 'node "${PLUGIN_ROOT}/components/bootstrap/dist/cli.js" hook session-start';
17
17
  const EXPECTED_BOOTSTRAP_COMMAND_WINDOWS =
18
18
  'powershell -NoProfile -ExecutionPolicy Bypass -File "${PLUGIN_ROOT}\\components\\bootstrap\\scripts\\bootstrap.ps1"';
19
+ const EXPECTED_NODE_DISPATCH_PREFIX =
20
+ 'powershell -NoProfile -ExecutionPolicy Bypass -File "${PLUGIN_ROOT}\\components\\bootstrap\\scripts\\node-dispatch.ps1"';
19
21
 
20
22
  async function pathExists(absolutePath) {
21
23
  try {
@@ -127,6 +129,23 @@ test("#given aggregate and component hook manifests #when command targets are re
127
129
  assert.deepEqual(missing, []);
128
130
  });
129
131
 
132
+ test("#given aggregate hook manifests #when command handlers are inspected #then each has a Windows dispatcher", async () => {
133
+ // given
134
+ const aggregateHooks = await readAggregateHookManifests();
135
+
136
+ // when
137
+ const missing = [];
138
+ for (const manifest of aggregateHooks) {
139
+ for (const { handler } of collectCommandHooks(manifest.hooks, manifest.source)) {
140
+ if (typeof handler.commandWindows === "string" && handler.commandWindows.length > 0) continue;
141
+ missing.push(`${manifest.source}: ${handler.command}`);
142
+ }
143
+ }
144
+
145
+ // then
146
+ assert.deepEqual(missing, [], `Aggregate hook commands need commandWindows dispatchers:\n${missing.join("\n")}`);
147
+ });
148
+
130
149
  test("#given the bootstrap component #when its SessionStart registration is inspected #then aggregate and component entries declare both platform commands", async () => {
131
150
  // given
132
151
  const aggregateHooks = (await readAggregateHookManifests()).find(({ source }) =>
@@ -156,6 +175,25 @@ test("#given the bootstrap component #when its SessionStart registration is insp
156
175
  }
157
176
  });
158
177
 
178
+ test("#given non-bootstrap aggregate hook manifests #when commandWindows entries are read #then they launch the managed Node dispatcher", async () => {
179
+ // given
180
+ const aggregateHooks = await readAggregateHookManifests();
181
+
182
+ // when
183
+ const offenders = [];
184
+ for (const manifest of aggregateHooks) {
185
+ for (const { handler } of collectCommandHooks(manifest.hooks, manifest.source)) {
186
+ if (handler.command === EXPECTED_BOOTSTRAP_COMMAND) continue;
187
+ if (typeof handler.commandWindows !== "string" || !handler.commandWindows.startsWith(EXPECTED_NODE_DISPATCH_PREFIX)) {
188
+ offenders.push(`${manifest.source}: ${handler.commandWindows ?? "<missing>"}`);
189
+ }
190
+ }
191
+ }
192
+
193
+ // then
194
+ assert.deepEqual(offenders, [], `Non-bootstrap aggregate hooks must use node-dispatch.ps1 on Windows:\n${offenders.join("\n")}`);
195
+ });
196
+
159
197
  test("#given the built bootstrap bundle #when its module references are inspected #then it depends on Node built-ins only", async () => {
160
198
  // given
161
199
  const bundlePath = join(root, "components", "bootstrap", "dist", "cli.js");
@@ -68,6 +68,31 @@ test("#given bootstrap.ps1 #when environment writes are scanned #then no Machine
68
68
  assert.deepEqual(offenders, [], "bootstrap.ps1 must only touch User-scope environment values (Machine scope needs elevation)");
69
69
  });
70
70
 
71
+ test("#given bootstrap.ps1 #when dependency discovery misses #then it never invokes winget or mutates user PATH", async () => {
72
+ // given
73
+ const content = await readBootstrapScript();
74
+
75
+ // then
76
+ assert.doesNotMatch(content, /&\s*winget\s+install/i, "bootstrap.ps1 must not install system dependencies with winget");
77
+ assert.doesNotMatch(
78
+ content,
79
+ /SetEnvironmentVariable\("Path"/,
80
+ "bootstrap.ps1 must not mutate the user PATH when Codex Desktop misses PATH entries",
81
+ );
82
+ });
83
+
84
+ test("#given bootstrap.ps1 #when resolving Node #then Codex NODE_REPL_NODE_PATH is checked before PATH", async () => {
85
+ // given
86
+ const content = await readBootstrapScript();
87
+
88
+ // then
89
+ assert.match(content, /NODE_REPL_NODE_PATH/, "bootstrap.ps1 must know how to read the Codex bundled Node setting");
90
+ assert(
91
+ content.indexOf("NODE_REPL_NODE_PATH") < content.indexOf("Get-Command node"),
92
+ "bootstrap.ps1 must prefer Codex bundled Node config before probing PATH",
93
+ );
94
+ });
95
+
71
96
  test("#given bootstrap.ps1 #when execution policy mutations are scanned #then Set-ExecutionPolicy is never invoked", async () => {
72
97
  // given
73
98
  const content = await readBootstrapScript();
@@ -205,21 +205,15 @@ test("#given an unwritable config.toml #when the worker setup runs #then it degr
205
205
  });
206
206
  });
207
207
 
208
- test("#given win32 without Git Bash and auto-install skipped #when the worker setup runs #then it degrades instead of throwing and disables the git_bash MCP", async () => {
208
+ test("#given win32 without Git Bash #when the worker setup runs #then it degrades instead of throwing and disables the git_bash MCP", async () => {
209
209
  await withSetupFixture(async (fixture) => {
210
- const commands = [];
211
210
  const outcome = await runWorkerSetup(
212
211
  setupOptions(fixture, {
213
- env: { OMO_CODEX_SKIP_GIT_BASH_AUTO_INSTALL: "1" },
214
212
  platform: "win32",
215
213
  resolveGitBash: () => ({ checkedPaths: [], found: false, installHint: "install git bash" }),
216
- runCommand: async (command, args) => {
217
- commands.push([command, ...args]);
218
- },
219
214
  }),
220
215
  );
221
216
 
222
- assert.deepEqual(commands, []);
223
217
  const gitBashEntries = outcome.degraded.filter((entry) => entry.component === "git-bash");
224
218
  assert.equal(gitBashEntries.length, 1);
225
219
  const config = await readConfig(fixture);
@@ -1,12 +1,41 @@
1
+ // allow: SIZE_OK - migration scenarios share one temp Codex-home harness across legacy TOML shapes; this release only adds config cases and future additions should split by migration family.
2
+
1
3
  import assert from "node:assert/strict";
4
+ import { spawnSync } from "node:child_process";
2
5
  import { mkdir, mkdtemp, readFile, rm, symlink, writeFile } from "node:fs/promises";
3
6
  import { tmpdir } from "node:os";
4
7
  import { dirname, join } from "node:path";
5
8
  import test from "node:test";
6
9
 
10
+ import { removeUnsupportedRootMultiAgentMode } from "../scripts/migrate-codex-config/multi-agent-mode-guard.mjs";
7
11
  import { forceDisableMultiAgentV2 } from "../scripts/migrate-codex-config/multi-agent-v2-guard.mjs";
8
12
  import { ensureCodexReasoningConfig, migrateCodexConfig } from "../scripts/migrate-codex-config.mjs";
9
13
 
14
+ function parseTomlWithPython(config) {
15
+ const python = resolvePython();
16
+ const result = spawnSync(
17
+ python,
18
+ [
19
+ "-c",
20
+ [
21
+ "import json, sys, tomllib",
22
+ "print(json.dumps(tomllib.loads(sys.stdin.read())))",
23
+ ].join("; "),
24
+ ],
25
+ { encoding: "utf8", input: config },
26
+ );
27
+ assert.equal(result.status, 0, result.stderr);
28
+ return JSON.parse(result.stdout);
29
+ }
30
+
31
+ function resolvePython() {
32
+ for (const command of ["python3", "python"]) {
33
+ const result = spawnSync(command, ["-c", "import tomllib"], { encoding: "utf8" });
34
+ if (result.status === 0) return command;
35
+ }
36
+ assert.fail("Python with tomllib is required for TOML parse assertions");
37
+ }
38
+
10
39
  test("#given stale root reasoning config #when ensuring config #then replaces stale values without duplicate keys", () => {
11
40
  const result = ensureCodexReasoningConfig(
12
41
  [
@@ -181,7 +210,7 @@ test("#given model catalog is malformed and stale config #when migrating #then f
181
210
  assert.match(content, /model_context_window = 400000/);
182
211
  });
183
212
 
184
- test("#given user-customized Codex model config #when migrating #then user values are preserved", async () => {
213
+ test("#given user-customized Codex model config #when migrating #then user values are preserved without root multi-agent mode", async () => {
185
214
  const root = await mkdtemp(join(tmpdir(), "lazycodex-config-custom-"));
186
215
  const codexHome = join(root, "codex-home");
187
216
  await mkdir(codexHome, { recursive: true });
@@ -205,11 +234,16 @@ test("#given user-customized Codex model config #when migrating #then user value
205
234
  });
206
235
 
207
236
  const content = await readFile(join(codexHome, "config.toml"), "utf8");
208
- assert.deepEqual(result.changed, []);
237
+ assert.deepEqual(result.changed, [join(codexHome, "config.toml")]);
238
+ assert.deepEqual(result.modeChanged, []);
209
239
  assert.match(content, /model = "gpt-5\.4"/);
210
240
  assert.match(content, /model_context_window = 123456/);
211
241
  assert.match(content, /model_reasoning_effort = "medium"/);
212
242
  assert.match(content, /plan_mode_reasoning_effort = "medium"/);
243
+ assert.doesNotMatch(content, /^\s*multi_agent_mode\s*=/m);
244
+ assert.match(content, /\[agents\][\s\S]*?max_threads = 1000/);
245
+ assert.match(content, /\[features\.multi_agent_v2\][\s\S]*?enabled = false/);
246
+ assert.match(content, /max_concurrent_threads_per_session = 1000/);
213
247
  });
214
248
 
215
249
  test("#given managed config state is malformed #when migrating #then migration ignores stale state safely", async () => {
@@ -328,6 +362,7 @@ test("#given config already matches current catalog #when catalog version advanc
328
362
  "model_context_window = 400000",
329
363
  'model_reasoning_effort = "high"',
330
364
  'plan_mode_reasoning_effort = "xhigh"',
365
+ 'multi_agent_mode = "proactive"',
331
366
  "",
332
367
  "[features.multi_agent_v2]",
333
368
  "enabled = false",
@@ -363,9 +398,88 @@ test("#given config already matches current catalog #when catalog version advanc
363
398
  });
364
399
 
365
400
  const state = JSON.parse(await readFile(statePath, "utf8"));
366
- assert.deepEqual(result.changed, []);
401
+ assert.deepEqual(result.changed, [configPath]);
402
+ assert.deepEqual(result.modeChanged, [configPath]);
367
403
  assert.equal(state.files[configPath].managed, true);
368
404
  assert.equal(state.files[configPath].catalogVersion, "test.role-only");
405
+ const content = await readFile(configPath, "utf8");
406
+ assert.doesNotMatch(content, /^\s*multi_agent_mode\s*=/m);
407
+ assert.match(content, /\[agents\][\s\S]*?max_threads = 1000/);
408
+ assert.match(content, /max_concurrent_threads_per_session = 1000/);
409
+ });
410
+
411
+ test("#given stale Context7 placeholder MCP config #when migrating #then removes it and keeps plugin policy", async () => {
412
+ const root = await mkdtemp(join(tmpdir(), "lazycodex-context7-placeholder-cleanup-"));
413
+ const codexHome = join(root, "codex-home");
414
+ const configPath = join(codexHome, "config.toml");
415
+ await mkdir(codexHome, { recursive: true });
416
+ await writeFile(
417
+ configPath,
418
+ [
419
+ 'model = "gpt-5.5"',
420
+ "model_context_window = 400000",
421
+ 'model_reasoning_effort = "high"',
422
+ 'plan_mode_reasoning_effort = "xhigh"',
423
+ "",
424
+ "[mcp_servers.context7] # stale npx package from old docs",
425
+ 'command = "npx"',
426
+ 'args = ["-y", "@upstash/context7-mcp", "--api-key", "YOUR_API_KEY"]',
427
+ "startup_timeout_sec = 20",
428
+ "",
429
+ '[plugins."omo@sisyphuslabs".mcp_servers.context7]',
430
+ "enabled = true",
431
+ "",
432
+ ].join("\n"),
433
+ );
434
+
435
+ const result = await migrateCodexConfig({
436
+ env: { CODEX_HOME: codexHome, LAZYCODEX_MODEL_CATALOG_STATE_PATH: join(root, "model-state.json") },
437
+ cwd: root,
438
+ });
439
+
440
+ const content = await readFile(configPath, "utf8");
441
+ assert.deepEqual(result.changed, [configPath]);
442
+ assert.doesNotMatch(content, /\[mcp_servers\.context7\]/);
443
+ assert.doesNotMatch(content, /@upstash\/context7-mcp/);
444
+ assert.doesNotMatch(content, /YOUR_API_KEY/);
445
+ assert.match(content, /\[plugins\."omo@sisyphuslabs"\.mcp_servers\.context7\][\s\S]*?enabled = true/);
446
+ });
447
+
448
+ test("#given real Context7 API key and placeholder comment #when migrating #then preserves user server settings", async () => {
449
+ const root = await mkdtemp(join(tmpdir(), "lazycodex-context7-real-key-"));
450
+ const codexHome = join(root, "codex-home");
451
+ const configPath = join(codexHome, "config.toml");
452
+ await mkdir(codexHome, { recursive: true });
453
+ await writeFile(
454
+ configPath,
455
+ [
456
+ 'model = "gpt-5.5"',
457
+ "model_context_window = 400000",
458
+ 'model_reasoning_effort = "high"',
459
+ 'plan_mode_reasoning_effort = "xhigh"',
460
+ "",
461
+ "[mcp_servers.context7]",
462
+ 'command = "npx"',
463
+ 'args = ["-y", "@upstash/context7-mcp", "--api-key", "ctx7sk_live_example"] # replace YOUR_API_KEY in docs only',
464
+ "startup_timeout_sec = 20",
465
+ "",
466
+ '[plugins."omo@sisyphuslabs".mcp_servers.context7]',
467
+ "enabled = true",
468
+ "",
469
+ ].join("\n"),
470
+ );
471
+
472
+ const result = await migrateCodexConfig({
473
+ env: { CODEX_HOME: codexHome, LAZYCODEX_MODEL_CATALOG_STATE_PATH: join(root, "model-state.json") },
474
+ cwd: root,
475
+ });
476
+
477
+ const content = await readFile(configPath, "utf8");
478
+ assert.deepEqual(result.changed, [configPath]);
479
+ assert.match(content, /\[mcp_servers\.context7\]/);
480
+ assert.match(content, /ctx7sk_live_example/);
481
+ assert.match(content, /replace YOUR_API_KEY in docs only/);
482
+ assert.match(content, /\[plugins\."omo@sisyphuslabs"\.mcp_servers\.context7\][\s\S]*?enabled = true/);
369
483
  });
370
484
 
371
485
  test("#given multi_agent_v2 enabled #when forcing disable #then flips the flag to false", () => {
@@ -470,18 +584,23 @@ test("#given an annotated managed section #when forcing disable runs again #then
470
584
  assert.match(rerun, /enabled = false/);
471
585
  });
472
586
 
473
- test("#given [features] boolean shorthand multi_agent_v2 = false #when forcing disable #then returns config unchanged", () => {
587
+ test("#given [features] boolean shorthand multi_agent_v2 = false #when forcing disable #then rewrites to the non-conflicting disabled table", () => {
474
588
  const config = [
475
589
  'model = "gpt-5.5"',
476
590
  "",
477
591
  "[features]",
478
592
  "multi_agent_v2 = false",
593
+ "plugins = true",
479
594
  "",
480
595
  ].join("\n");
481
596
 
482
597
  const result = forceDisableMultiAgentV2(config);
598
+ const parsed = parseTomlWithPython(result);
483
599
 
484
- assert.equal(result, config);
600
+ assert.doesNotMatch(result, /^\s*multi_agent_v2\s*=/m);
601
+ assert.equal((result.match(/\[features\.multi_agent_v2\]/g) ?? []).length, 1);
602
+ assert.equal(parsed.features.plugins, true);
603
+ assert.equal(parsed.features.multi_agent_v2.enabled, false);
485
604
  });
486
605
 
487
606
  test("#given multi_agent_v2 already disabled #when forcing disable #then returns config unchanged", () => {
@@ -520,8 +639,87 @@ test("#given global config without multi_agent_v2 section #when full migration r
520
639
  });
521
640
 
522
641
  assert.deepEqual(result.changed, [configPath]);
642
+ assert.deepEqual(result.modeChanged, []);
523
643
  const content = await readFile(configPath, "utf8");
524
- assert.match(content, /\[features\.multi_agent_v2\]\nenabled = false\n/);
644
+ assert.match(content, /\[features\.multi_agent_v2\][\s\S]*?enabled = false/);
645
+ assert.match(content, /max_concurrent_threads_per_session = 1000/);
646
+ assert.match(content, /\[agents\][\s\S]*?max_threads = 1000/);
647
+ assert.doesNotMatch(content, /^\s*multi_agent_mode\s*=/m);
648
+ });
649
+
650
+ test("#given global config starts with inline-comment features table #when full migration runs #then managed root settings stay at TOML root", async () => {
651
+ const root = await mkdtemp(join(tmpdir(), "lazycodex-root-settings-inline-features-"));
652
+ const codexHome = join(root, "codex-home");
653
+ await mkdir(codexHome, { recursive: true });
654
+ const configPath = join(codexHome, "config.toml");
655
+ await writeFile(
656
+ configPath,
657
+ [
658
+ "[features] # keep comment",
659
+ "plugins = true",
660
+ "",
661
+ ].join("\n"),
662
+ );
663
+
664
+ const result = await migrateCodexConfig({
665
+ env: { CODEX_HOME: codexHome, LAZYCODEX_MODEL_CATALOG_STATE_PATH: join(root, "model-state.json") },
666
+ cwd: root,
667
+ });
668
+
669
+ assert.deepEqual(result.changed, [configPath]);
670
+ const content = await readFile(configPath, "utf8");
671
+ const parsed = parseTomlWithPython(content);
672
+ assert.equal("multi_agent_mode" in parsed, false);
673
+ assert.equal(parsed.model, "gpt-5.5");
674
+ assert.equal(parsed.model_context_window, 400000);
675
+ assert.equal(parsed.model_reasoning_effort, "high");
676
+ assert.equal(parsed.plan_mode_reasoning_effort, "xhigh");
677
+ assert.equal(parsed.features.plugins, true);
678
+ assert.equal("multi_agent_mode" in parsed.features, false);
679
+ assert.equal("model" in parsed.features, false);
680
+ assert.equal("model_context_window" in parsed.features, false);
681
+ assert.match(content, /^model = "gpt-5\.5"\nmodel_context_window = 400000/m);
682
+ assert.doesNotMatch(content, /^\s*multi_agent_mode\s*=/m);
683
+ assert.match(content, /\[features\] # keep comment\nplugins = true/);
684
+ });
685
+
686
+ test("#given queue multi-agent mode #when removing unsupported root key #then deletes root setting", () => {
687
+ const config = ['multi_agent_mode = "queue"', "", "[features]", "multi_agent = true", ""].join("\n");
688
+
689
+ const result = removeUnsupportedRootMultiAgentMode(config);
690
+
691
+ assert.doesNotMatch(result, /^\s*multi_agent_mode\s*=/m);
692
+ assert.doesNotMatch(result, /multi_agent_mode = "queue"/);
693
+ assert.match(result, /\[features\]/);
694
+ });
695
+
696
+ test("#given proactive multi-agent mode #when removing unsupported root key #then deletes root setting", () => {
697
+ const config = ['multi_agent_mode = "proactive" # user already opted in', "", "[features]", "multi_agent = true", ""].join("\n");
698
+
699
+ const result = removeUnsupportedRootMultiAgentMode(config);
700
+
701
+ assert.doesNotMatch(result, /^\s*multi_agent_mode\s*=/m);
702
+ assert.match(result, /\[features\]/);
703
+ });
704
+
705
+ test("#given inline-comment features table #when removing unsupported root key #then config stays unchanged", () => {
706
+ const config = ["[features] # keep comment", "multi_agent = true", ""].join("\n");
707
+
708
+ const result = removeUnsupportedRootMultiAgentMode(config);
709
+ const parsed = parseTomlWithPython(result);
710
+
711
+ assert.equal(result, config);
712
+ assert.equal("multi_agent_mode" in parsed, false);
713
+ assert.equal(parsed.features.multi_agent, true);
714
+ });
715
+
716
+ test("#given indented root proactive mode #when removing unsupported root key #then no root setting remains", () => {
717
+ const config = [' multi_agent_mode = "proactive" # user already opted in', "", "[features] # keep comment", "multi_agent = true", ""].join("\n");
718
+
719
+ const result = removeUnsupportedRootMultiAgentMode(config);
720
+
721
+ assert.equal(result.match(/multi_agent_mode\s*=/g)?.length ?? 0, 0);
722
+ assert.match(result, /^\[features\] # keep comment$/m);
525
723
  });
526
724
 
527
725
  test("#given global config with forced multi_agent_v2 #when full migration runs #then disables it on disk", async () => {
@@ -551,6 +749,8 @@ test("#given global config with forced multi_agent_v2 #when full migration runs
551
749
  const content = await readFile(configPath, "utf8");
552
750
  assert.match(content, /enabled = false/);
553
751
  assert.doesNotMatch(content, /enabled = true/);
752
+ assert.match(content, /max_concurrent_threads_per_session = 1000/);
753
+ assert.match(content, /\[agents\][\s\S]*?max_threads = 1000/);
554
754
  });
555
755
 
556
756
  test("#given enabled = true with an inline comment #when forcing disable #then flips to false and preserves the comment", () => {
@@ -0,0 +1,44 @@
1
+ import assert from "node:assert/strict";
2
+ import { mkdtemp, readFile, writeFile } from "node:fs/promises";
3
+ import { tmpdir } from "node:os";
4
+ import { join } from "node:path";
5
+ import test from "node:test";
6
+
7
+ import { migrateConfigFile } from "../scripts/migrate-codex-config.mjs";
8
+
9
+ test("#given SessionStart config migration sees a low subagent cap #when migrating #then raises it to 1000", async () => {
10
+ const root = await mkdtemp(join(tmpdir(), "lazycodex-subagent-limit-migration-"));
11
+ const configPath = join(root, "config.toml");
12
+ await writeFile(
13
+ configPath,
14
+ [
15
+ 'model = "gpt-5.4"',
16
+ "model_context_window = 123456",
17
+ 'model_reasoning_effort = "medium"',
18
+ 'plan_mode_reasoning_effort = "medium"',
19
+ "",
20
+ "[agents]",
21
+ "max_threads = 6",
22
+ "max_depth = 4",
23
+ "",
24
+ "[agents.explorer]",
25
+ 'config_file = "./agents/explorer.toml"',
26
+ "",
27
+ "[features.multi_agent_v2]",
28
+ "enabled = false",
29
+ "max_concurrent_threads_per_session = 6",
30
+ "",
31
+ ].join("\n"),
32
+ );
33
+
34
+ const result = await migrateConfigFile(configPath);
35
+
36
+ const content = await readFile(configPath, "utf8");
37
+ assert.equal(result.changed, true);
38
+ assert.match(content, /\[agents\][\s\S]*?max_threads = 1000/);
39
+ assert.match(content, /max_depth = 4/);
40
+ assert.match(content, /\[agents\.explorer\]\nconfig_file = "\.\/agents\/explorer\.toml"/);
41
+ assert.match(content, /\[features\.multi_agent_v2\][\s\S]*?enabled = false/);
42
+ assert.match(content, /max_concurrent_threads_per_session = 1000/);
43
+ assert.doesNotMatch(content, /^max_threads\s*=\s*6$/m);
44
+ });
@@ -20,10 +20,19 @@ async function readSkill(skillName) {
20
20
  return readFile(join(root, "skills", skillName, "SKILL.md"), "utf8");
21
21
  }
22
22
 
23
+ async function readSharedSkill(skillName) {
24
+ return readFile(join(root, "../../shared-skills/skills", skillName, "SKILL.md"), "utf8");
25
+ }
26
+
23
27
  function patternFromParts(parts, flags) {
24
28
  return new RegExp(parts.join(""), flags);
25
29
  }
26
30
 
31
+ const multiAgentV2RoleGuidance =
32
+ "On `multi_agent_v2` sessions the same `agent_type` applies (the OMO installer exposes it) with `fork_turns` instead of `fork_context`.";
33
+ const loadSkillsGuidance =
34
+ "When translating `load_skills=[...]`, include the requested skill names in the spawned agent's `message`.";
35
+
27
36
  test("#given synced aggregate Codex skills #when they contain OpenCode orchestration examples #then Codex tool compatibility guidance is injected", async () => {
28
37
  // given
29
38
  const opencodeOnlyToolPattern = /\b(?:call_omo_agent|background_output|team_[a-z_]+|task)\s*\(/;
@@ -41,6 +50,8 @@ test("#given synced aggregate Codex skills #when they contain OpenCode orchestra
41
50
  compatibilityIndex < content.search(opencodeOnlyToolPattern),
42
51
  `${skillName} must explain Codex tool translation before OpenCode-only examples`,
43
52
  );
53
+ assert.ok(content.includes(multiAgentV2RoleGuidance), `${skillName} missing multi_agent_v2 role guidance`);
54
+ assert.ok(content.includes(loadSkillsGuidance), `${skillName} missing load_skills guidance`);
44
55
  }
45
56
  });
46
57
 
@@ -77,7 +88,7 @@ task(category="quick", prompt="verify")
77
88
  assert.ok(compatibilityIndex < firstToolIndex);
78
89
  assert.equal(adapted.match(/## Codex Harness Tool Compatibility/g)?.length, 1);
79
90
  assert.doesNotMatch(adapted, /Older variant guidance/);
80
- assert.doesNotMatch(adapted, /When translating `load_skills=\[\.\.\.\]`/);
91
+ assert.doesNotMatch(adapted, /name the skills inside the spawned agent's `message`/);
81
92
  assert.match(adapted, /\n---\n\n## Next Section/);
82
93
  });
83
94
 
@@ -141,6 +152,25 @@ call_omo_agent(subagent_type="explore", prompt="inspect")
141
152
  assert.doesNotMatch(adapted, /Obsolete generated compatibility prose/);
142
153
  });
143
154
 
155
+ test("#given generated Codex compatibility guidance #when adapting a skill #then multi-agent role and load_skills guidance are both present", () => {
156
+ // given
157
+ const content = `---
158
+ name: example
159
+ ---
160
+
161
+ # Example Skill
162
+
163
+ task(subagent_type="oracle", load_skills=["debugging"], prompt="verify")
164
+ `;
165
+
166
+ // when
167
+ const adapted = insertCodexCompatibilityGuidance(content);
168
+
169
+ // then
170
+ assert.ok(adapted.includes(multiAgentV2RoleGuidance));
171
+ assert.ok(adapted.includes(loadSkillsGuidance));
172
+ });
173
+
144
174
  test("#given generated guidance before a template export #when adapting a skill #then the export wrapper is preserved", () => {
145
175
  // given
146
176
  const content = `---
@@ -214,3 +244,22 @@ test("#given review-work skill #when some lanes do not finish #then aggregate re
214
244
  assert.match(content, /Do not spin in repeated/);
215
245
  assert.match(content, /Do not use `multi_agent_v1\.send_input` as an interrupt/);
216
246
  });
247
+
248
+ test("#given PR and review skills #when synced for Codex #then worktree lifecycle is mandatory", async () => {
249
+ const startWork = await readSkill("start-work");
250
+ const reviewWork = await readSkill("review-work");
251
+ const sharedStartWork = await readSharedSkill("start-work");
252
+
253
+ assert.match(startWork, /PR creation, PR handoff, branch handoff, or merge/);
254
+ assert.match(startWork, /Finish the PR\/branch lifecycle from its task-owned worktree/);
255
+ assert.match(startWork, /merge by default unless explicitly opted out/);
256
+ assert.match(startWork, /No PR\/branch implementation or review in the main worktree/);
257
+
258
+ assert.match(sharedStartWork, /required for PR\/branch work/);
259
+ assert.match(sharedStartWork, /No PR\/branch implementation, review, or merge in the main worktree/);
260
+ assert.doesNotMatch(sharedStartWork, /If worktree mode was used/);
261
+ assert.doesNotMatch(sharedStartWork, /merge or hand off exactly as requested/);
262
+
263
+ assert.match(reviewWork, /dedicated review worktree attached to that branch/);
264
+ assert.match(reviewWork, /Never\s+checkout, test, or edit the review branch in the main worktree/);
265
+ });