oh-my-opencode 5.0.0-beta.60 → 5.0.0-beta.63

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 (227) hide show
  1. package/THIRD-PARTY-NOTICES.md +8 -6
  2. package/dist/cli/doctor/checks/browser-provider.d.ts +2 -0
  3. package/dist/cli/index.js +465 -348
  4. package/dist/cli-node/index.js +465 -348
  5. package/dist/config/schema/agent-names.d.ts +0 -1
  6. package/dist/config/schema/browser-automation.d.ts +0 -2
  7. package/dist/config/schema/oh-my-opencode-config.d.ts +0 -1
  8. package/dist/hooks/comment-checker/__fixtures__/download-probe.fixture.d.ts +1 -0
  9. package/dist/index.js +61 -535
  10. package/dist/oh-my-opencode.schema.json +0 -1
  11. package/dist/skills/ast-grep/SKILL.md +12 -0
  12. package/dist/skills/debugging/references/tools/playwright-cli.md +79 -161
  13. package/dist/skills/frontend/SKILL.md +1 -1
  14. package/dist/skills/frontend/references/design/aside.md +1 -1
  15. package/dist/skills/frontend/references/design/clone-from-url.md +1 -1
  16. package/dist/skills/frontend/scripts/perfection/lighthouse-audit.py +2 -2
  17. package/dist/skills/review-work/SKILL.md +1 -1
  18. package/dist/skills/ultimate-browsing/ATTRIBUTION.md +1 -82
  19. package/dist/skills/ultimate-browsing/SKILL.md +17 -29
  20. package/dist/skills/ultimate-browsing/engine/AGENTS.md +2 -1
  21. package/dist/skills/ultimate-browsing/engine/templates/package.json +2 -2
  22. package/dist/skills/ultimate-browsing/engine/templates/playwright_mobile_chrome.js +5 -2
  23. package/dist/skills/ultimate-browsing/engine/templates/playwright_real_chrome.js +8 -6
  24. package/dist/skills/ultimate-browsing/engine/tests/test_playwright_stealth.py +86 -0
  25. package/dist/skills/ultimate-browsing/engine/tests/test_playwright_templates.py +4 -7
  26. package/dist/skills/ultimate-browsing/references/chrome-stealth.md +86 -100
  27. package/dist/skills/ultimate-browsing/references/insane-search/README.md +9 -3
  28. package/dist/skills/ultimate-browsing/references/insane-search/playwright.md +16 -13
  29. package/dist/skills/ultimate-browsing/scripts/extract_cookies.py +3 -3
  30. package/dist/skills/ulw-execute/SKILL.md +1 -1
  31. package/dist/skills/ulw-plan/scripts/scaffold-plan.mjs +1 -1
  32. package/dist/skills/ulw-research/SKILL.md +3 -3
  33. package/dist/skills/visual-qa/AGENTS.md +1 -1
  34. package/dist/skills/visual-qa/SKILL.md +1 -1
  35. package/dist/skills/visual-qa/references/browser-setup.md +75 -0
  36. package/dist/tui.js +12 -5
  37. package/package.json +16 -23
  38. package/packages/omo-codex/plugin/.codex-plugin/plugin.json +1 -1
  39. package/packages/omo-codex/plugin/components/bootstrap/dist/cli.js +6887 -249
  40. package/packages/omo-codex/plugin/components/bootstrap/hooks/hooks.json +1 -1
  41. package/packages/omo-codex/plugin/components/bootstrap/package.json +1 -1
  42. package/packages/omo-codex/plugin/components/bootstrap/src/setup.ts +7 -1
  43. package/packages/omo-codex/plugin/components/comment-checker/hooks/hooks.json +1 -1
  44. package/packages/omo-codex/plugin/components/comment-checker/package.json +1 -1
  45. package/packages/omo-codex/plugin/components/git-bash/hooks/hooks.json +2 -2
  46. package/packages/omo-codex/plugin/components/git-bash/package.json +1 -1
  47. package/packages/omo-codex/plugin/components/lazycodex-executor-verify/hooks/hooks.json +1 -1
  48. package/packages/omo-codex/plugin/components/lazycodex-executor-verify/package.json +1 -1
  49. package/packages/omo-codex/plugin/components/lsp/dist/.omo-runtime-manifest.json +2 -2
  50. package/packages/omo-codex/plugin/components/lsp/hooks/hooks.json +2 -2
  51. package/packages/omo-codex/plugin/components/lsp/package.json +1 -1
  52. package/packages/omo-codex/plugin/components/rules/hooks/hooks.json +4 -4
  53. package/packages/omo-codex/plugin/components/rules/package.json +1 -1
  54. package/packages/omo-codex/plugin/components/teammode/hooks/hooks.json +1 -1
  55. package/packages/omo-codex/plugin/components/teammode/package.json +1 -1
  56. package/packages/omo-codex/plugin/components/telemetry/hooks/hooks.json +1 -1
  57. package/packages/omo-codex/plugin/components/telemetry/package.json +1 -1
  58. package/packages/omo-codex/plugin/components/ultrawork/agents/plan.toml +2 -2
  59. package/packages/omo-codex/plugin/components/ultrawork/dist/cli.js +25 -15
  60. package/packages/omo-codex/plugin/components/ultrawork/hooks/hooks.json +1 -1
  61. package/packages/omo-codex/plugin/components/ultrawork/package.json +1 -1
  62. package/packages/omo-codex/plugin/components/ultrawork/src/directive-content.ts +1 -1
  63. package/packages/omo-codex/plugin/components/ulw-execute-continuation/directive.md +1 -1
  64. package/packages/omo-codex/plugin/components/ulw-execute-continuation/hooks/hooks.json +1 -1
  65. package/packages/omo-codex/plugin/components/ulw-execute-continuation/package.json +1 -1
  66. package/packages/omo-codex/plugin/components/ulw-loop/CHANGELOG.md +15 -0
  67. package/packages/omo-codex/plugin/components/ulw-loop/directive.md +25 -15
  68. package/packages/omo-codex/plugin/components/ulw-loop/dist/checkpoint.js +5 -4
  69. package/packages/omo-codex/plugin/components/ulw-loop/dist/cli.js +640 -327
  70. package/packages/omo-codex/plugin/components/ulw-loop/dist/domain-types.d.ts +5 -0
  71. package/packages/omo-codex/plugin/components/ulw-loop/dist/evidence.js +16 -12
  72. package/packages/omo-codex/plugin/components/ulw-loop/dist/ledger.d.ts +4 -0
  73. package/packages/omo-codex/plugin/components/ulw-loop/dist/ledger.js +34 -0
  74. package/packages/omo-codex/plugin/components/ulw-loop/dist/plan-commit.d.ts +19 -0
  75. package/packages/omo-codex/plugin/components/ulw-loop/dist/plan-commit.js +107 -0
  76. package/packages/omo-codex/plugin/components/ulw-loop/dist/plan-crud.d.ts +2 -1
  77. package/packages/omo-codex/plugin/components/ulw-loop/dist/plan-crud.js +48 -22
  78. package/packages/omo-codex/plugin/components/ulw-loop/dist/plan-io.d.ts +9 -7
  79. package/packages/omo-codex/plugin/components/ulw-loop/dist/plan-io.js +105 -114
  80. package/packages/omo-codex/plugin/components/ulw-loop/dist/plan-log.d.ts +15 -0
  81. package/packages/omo-codex/plugin/components/ulw-loop/dist/plan-log.js +86 -0
  82. package/packages/omo-codex/plugin/components/ulw-loop/dist/plan-missing-recovery.d.ts +5 -1
  83. package/packages/omo-codex/plugin/components/ulw-loop/dist/plan-missing-recovery.js +15 -3
  84. package/packages/omo-codex/plugin/components/ulw-loop/dist/review-blockers.js +3 -4
  85. package/packages/omo-codex/plugin/components/ulw-loop/dist/sdk/factory.js +29 -6
  86. package/packages/omo-codex/plugin/components/ulw-loop/dist/spawn-budget-io.d.ts +5 -0
  87. package/packages/omo-codex/plugin/components/ulw-loop/dist/spawn-budget-io.js +67 -0
  88. package/packages/omo-codex/plugin/components/ulw-loop/dist/spawn-guard.d.ts +1 -0
  89. package/packages/omo-codex/plugin/components/ulw-loop/dist/spawn-guard.js +29 -66
  90. package/packages/omo-codex/plugin/components/ulw-loop/dist/spawn-role-guard.d.ts +2 -0
  91. package/packages/omo-codex/plugin/components/ulw-loop/dist/spawn-role-guard.js +22 -0
  92. package/packages/omo-codex/plugin/components/ulw-loop/dist/state-lock.d.ts +11 -1
  93. package/packages/omo-codex/plugin/components/ulw-loop/dist/state-lock.js +120 -88
  94. package/packages/omo-codex/plugin/components/ulw-loop/dist/status-next-actions.d.ts +3 -2
  95. package/packages/omo-codex/plugin/components/ulw-loop/dist/status-next-actions.js +18 -10
  96. package/packages/omo-codex/plugin/components/ulw-loop/dist/steering-batch.js +4 -4
  97. package/packages/omo-codex/plugin/components/ulw-loop/dist/steering.js +5 -5
  98. package/packages/omo-codex/plugin/components/ulw-loop/dist/stop-resume-hook.js +8 -17
  99. package/packages/omo-codex/plugin/components/ulw-loop/hooks/hooks.json +7 -7
  100. package/packages/omo-codex/plugin/components/ulw-loop/package.json +1 -1
  101. package/packages/omo-codex/plugin/components/ulw-loop/skills/ulw-loop/references/full-workflow.md +2 -2
  102. package/packages/omo-codex/plugin/components/ulw-loop/src/checkpoint.ts +5 -4
  103. package/packages/omo-codex/plugin/components/ulw-loop/src/domain-types.ts +5 -0
  104. package/packages/omo-codex/plugin/components/ulw-loop/src/evidence.ts +16 -16
  105. package/packages/omo-codex/plugin/components/ulw-loop/src/ledger.ts +33 -0
  106. package/packages/omo-codex/plugin/components/ulw-loop/src/plan-commit.ts +124 -0
  107. package/packages/omo-codex/plugin/components/ulw-loop/src/plan-crud.ts +58 -51
  108. package/packages/omo-codex/plugin/components/ulw-loop/src/plan-io.ts +126 -140
  109. package/packages/omo-codex/plugin/components/ulw-loop/src/plan-log.ts +84 -0
  110. package/packages/omo-codex/plugin/components/ulw-loop/src/plan-missing-recovery.ts +26 -3
  111. package/packages/omo-codex/plugin/components/ulw-loop/src/review-blockers.ts +3 -3
  112. package/packages/omo-codex/plugin/components/ulw-loop/src/sdk/factory.ts +55 -6
  113. package/packages/omo-codex/plugin/components/ulw-loop/src/spawn-budget-io.ts +59 -0
  114. package/packages/omo-codex/plugin/components/ulw-loop/src/spawn-guard.ts +29 -62
  115. package/packages/omo-codex/plugin/components/ulw-loop/src/spawn-role-guard.ts +22 -0
  116. package/packages/omo-codex/plugin/components/ulw-loop/src/state-lock.ts +129 -111
  117. package/packages/omo-codex/plugin/components/ulw-loop/src/status-next-actions.ts +19 -10
  118. package/packages/omo-codex/plugin/components/ulw-loop/src/steering-batch.ts +4 -4
  119. package/packages/omo-codex/plugin/components/ulw-loop/src/steering.ts +5 -4
  120. package/packages/omo-codex/plugin/components/ulw-loop/src/stop-resume-hook.ts +8 -16
  121. package/packages/omo-codex/plugin/components/ulw-loop/test/fixtures/barrier.ts +13 -0
  122. package/packages/omo-codex/plugin/components/ulw-loop/test/fixtures/commit-child.ts +65 -0
  123. package/packages/omo-codex/plugin/components/ulw-loop/test/fixtures/commit-cli-qa.mjs +76 -0
  124. package/packages/omo-codex/plugin/components/ulw-loop/test/fixtures/commit-crash.ts +23 -0
  125. package/packages/omo-codex/plugin/components/ulw-loop/test/fixtures/commit-mutations.mjs +58 -0
  126. package/packages/omo-codex/plugin/components/ulw-loop/test/fixtures/commit-writer.ts +65 -0
  127. package/packages/omo-codex/plugin/components/ulw-loop/test/fixtures/lease-clock.ts +23 -0
  128. package/packages/omo-codex/plugin/components/ulw-loop/test/plan-commit-log.test.ts +252 -0
  129. package/packages/omo-codex/plugin/components/ulw-loop/test/plan-commit-recovery.test.ts +190 -0
  130. package/packages/omo-codex/plugin/components/ulw-loop/test/plan-io.test.ts +50 -35
  131. package/packages/omo-codex/plugin/components/ulw-loop/test/plan-log-newest.test.ts +72 -0
  132. package/packages/omo-codex/plugin/components/ulw-loop/test/sdk-completed-plan.test.ts +43 -0
  133. package/packages/omo-codex/plugin/components/ulw-loop/test/sdk-driver-states.test.ts +145 -0
  134. package/packages/omo-codex/plugin/components/ulw-loop/test/sdk-session-context.test.ts +21 -0
  135. package/packages/omo-codex/plugin/components/ulw-loop/test/spawn-guard.test.ts +7 -1
  136. package/packages/omo-codex/plugin/components/ulw-loop/test/spawn-role-matrix.test.ts +113 -0
  137. package/packages/omo-codex/plugin/components/ulw-loop/test/state-lock.test.ts +92 -0
  138. package/packages/omo-codex/plugin/components/ulw-loop/test/status-next-actions-surface.test.ts +133 -0
  139. package/packages/omo-codex/plugin/components/ulw-loop/test/steering-batch.test.ts +12 -12
  140. package/packages/omo-codex/plugin/components/ulw-loop/test/steering.test.ts +4 -1
  141. package/packages/omo-codex/plugin/hooks/post-compact-resetting-git-bash-mcp-reminder.json +1 -1
  142. package/packages/omo-codex/plugin/hooks/post-compact-resetting-lsp-diagnostics-cache.json +1 -1
  143. package/packages/omo-codex/plugin/hooks/post-compact-resetting-project-rule-cache.json +1 -1
  144. package/packages/omo-codex/plugin/hooks/post-tool-use-checking-comments.json +1 -1
  145. package/packages/omo-codex/plugin/hooks/post-tool-use-checking-lsp-diagnostics.json +1 -1
  146. package/packages/omo-codex/plugin/hooks/post-tool-use-checking-thread-title-hygiene.json +1 -1
  147. package/packages/omo-codex/plugin/hooks/post-tool-use-matching-project-rules.json +1 -1
  148. package/packages/omo-codex/plugin/hooks/post-tool-use-recording-spawn-admission.json +1 -1
  149. package/packages/omo-codex/plugin/hooks/pre-tool-use-enforcing-unlimited-goal-budget.json +1 -1
  150. package/packages/omo-codex/plugin/hooks/pre-tool-use-guarding-ulw-loop-spawns.json +1 -1
  151. package/packages/omo-codex/plugin/hooks/pre-tool-use-recommending-git-bash-mcp.json +1 -1
  152. package/packages/omo-codex/plugin/hooks/session-start-checking-auto-update.json +1 -1
  153. package/packages/omo-codex/plugin/hooks/session-start-checking-bootstrap-provisioning.json +1 -1
  154. package/packages/omo-codex/plugin/hooks/session-start-loading-project-rules.json +1 -1
  155. package/packages/omo-codex/plugin/hooks/session-start-recording-session-telemetry.json +1 -1
  156. package/packages/omo-codex/plugin/hooks/stop-checking-ulw-execute-continuation.json +1 -1
  157. package/packages/omo-codex/plugin/hooks/stop-checking-ulw-loop-resume.json +1 -1
  158. package/packages/omo-codex/plugin/hooks/subagent-stop-verifying-lazycodex-executor-evidence.json +1 -1
  159. package/packages/omo-codex/plugin/hooks/user-prompt-submit-checking-ultrawork-trigger.json +1 -1
  160. package/packages/omo-codex/plugin/hooks/user-prompt-submit-checking-ulw-loop-steering.json +1 -1
  161. package/packages/omo-codex/plugin/hooks/user-prompt-submit-loading-project-rules.json +1 -1
  162. package/packages/omo-codex/plugin/package-lock.json +12 -12
  163. package/packages/omo-codex/plugin/package.json +1 -1
  164. package/packages/omo-codex/plugin/scripts/sync-skills.d.mts +4 -0
  165. package/packages/omo-codex/plugin/scripts/sync-skills.mjs +18 -10
  166. package/packages/omo-codex/plugin/skills/ast-grep/SKILL.md +12 -0
  167. package/packages/omo-codex/plugin/skills/debugging/references/tools/playwright-cli.md +79 -161
  168. package/packages/omo-codex/plugin/skills/frontend/SKILL.md +1 -1
  169. package/packages/omo-codex/plugin/skills/frontend/references/design/aside.md +1 -1
  170. package/packages/omo-codex/plugin/skills/frontend/references/design/clone-from-url.md +1 -1
  171. package/packages/omo-codex/plugin/skills/frontend/scripts/perfection/lighthouse-audit.py +2 -2
  172. package/packages/omo-codex/plugin/skills/init-deep/SKILL.md +3 -3
  173. package/packages/omo-codex/plugin/skills/refactor/SKILL.md +3 -3
  174. package/packages/omo-codex/plugin/skills/remove-ai-slops/SKILL.md +3 -3
  175. package/packages/omo-codex/plugin/skills/review-work/SKILL.md +4 -4
  176. package/packages/omo-codex/plugin/skills/ultimate-browsing/ATTRIBUTION.md +1 -82
  177. package/packages/omo-codex/plugin/skills/ultimate-browsing/SKILL.md +17 -29
  178. package/packages/omo-codex/plugin/skills/ultimate-browsing/engine/AGENTS.md +2 -1
  179. package/packages/omo-codex/plugin/skills/ultimate-browsing/engine/templates/package.json +2 -2
  180. package/packages/omo-codex/plugin/skills/ultimate-browsing/engine/templates/playwright_mobile_chrome.js +5 -2
  181. package/packages/omo-codex/plugin/skills/ultimate-browsing/engine/templates/playwright_real_chrome.js +8 -6
  182. package/packages/omo-codex/plugin/skills/ultimate-browsing/engine/tests/test_playwright_stealth.py +86 -0
  183. package/packages/omo-codex/plugin/skills/ultimate-browsing/engine/tests/test_playwright_templates.py +4 -7
  184. package/packages/omo-codex/plugin/skills/ultimate-browsing/references/chrome-stealth.md +86 -100
  185. package/packages/omo-codex/plugin/skills/ultimate-browsing/references/insane-search/README.md +9 -3
  186. package/packages/omo-codex/plugin/skills/ultimate-browsing/references/insane-search/playwright.md +16 -13
  187. package/packages/omo-codex/plugin/skills/ultimate-browsing/scripts/extract_cookies.py +3 -3
  188. package/packages/omo-codex/plugin/skills/ultrawork/SKILL.md +25 -15
  189. package/packages/omo-codex/plugin/skills/ulw-execute/SKILL.md +4 -4
  190. package/packages/omo-codex/plugin/skills/ulw-loop/SKILL.md +3 -3
  191. package/packages/omo-codex/plugin/skills/ulw-loop/references/full-workflow.md +2 -2
  192. package/packages/omo-codex/plugin/skills/ulw-research/SKILL.md +6 -6
  193. package/packages/omo-codex/plugin/skills/visual-qa/AGENTS.md +1 -1
  194. package/packages/omo-codex/plugin/skills/visual-qa/SKILL.md +4 -4
  195. package/packages/omo-codex/plugin/skills/visual-qa/references/browser-setup.md +75 -0
  196. package/packages/omo-codex/plugin/test/bootstrap-default-role.test.mjs +66 -0
  197. package/packages/omo-codex/plugin/test/component-hook-contract-cases.mjs +13 -1
  198. package/packages/omo-codex/scripts/install-dist/install-local.mjs +7060 -417
  199. package/packages/prompts-core/prompts/ultrawork/codex.md +25 -15
  200. package/packages/shared-skills/skills/ast-grep/SKILL.md +12 -0
  201. package/packages/shared-skills/skills/debugging/references/tools/playwright-cli.md +79 -161
  202. package/packages/shared-skills/skills/frontend/SKILL.md +1 -1
  203. package/packages/shared-skills/skills/frontend/references/design/aside.md +1 -1
  204. package/packages/shared-skills/skills/frontend/references/design/clone-from-url.md +1 -1
  205. package/packages/shared-skills/skills/frontend/scripts/perfection/lighthouse-audit.py +2 -2
  206. package/packages/shared-skills/skills/review-work/SKILL.md +1 -1
  207. package/packages/shared-skills/skills/ultimate-browsing/ATTRIBUTION.md +1 -82
  208. package/packages/shared-skills/skills/ultimate-browsing/SKILL.md +17 -29
  209. package/packages/shared-skills/skills/ultimate-browsing/engine/AGENTS.md +2 -1
  210. package/packages/shared-skills/skills/ultimate-browsing/engine/templates/package.json +2 -2
  211. package/packages/shared-skills/skills/ultimate-browsing/engine/templates/playwright_mobile_chrome.js +5 -2
  212. package/packages/shared-skills/skills/ultimate-browsing/engine/templates/playwright_real_chrome.js +8 -6
  213. package/packages/shared-skills/skills/ultimate-browsing/engine/tests/test_playwright_stealth.py +86 -0
  214. package/packages/shared-skills/skills/ultimate-browsing/engine/tests/test_playwright_templates.py +4 -7
  215. package/packages/shared-skills/skills/ultimate-browsing/references/chrome-stealth.md +86 -100
  216. package/packages/shared-skills/skills/ultimate-browsing/references/insane-search/README.md +9 -3
  217. package/packages/shared-skills/skills/ultimate-browsing/references/insane-search/playwright.md +16 -13
  218. package/packages/shared-skills/skills/ultimate-browsing/scripts/extract_cookies.py +3 -3
  219. package/packages/shared-skills/skills/ulw-execute/SKILL.md +1 -1
  220. package/packages/shared-skills/skills/ulw-plan/scripts/scaffold-plan.mjs +1 -1
  221. package/packages/shared-skills/skills/ulw-research/SKILL.md +3 -3
  222. package/packages/shared-skills/skills/visual-qa/AGENTS.md +1 -1
  223. package/packages/shared-skills/skills/visual-qa/SKILL.md +1 -1
  224. package/packages/shared-skills/skills/visual-qa/references/browser-setup.md +75 -0
  225. package/dist/skills/visual-qa/references/agent-browser-setup.md +0 -45
  226. package/packages/omo-codex/plugin/skills/visual-qa/references/agent-browser-setup.md +0 -45
  227. package/packages/shared-skills/skills/visual-qa/references/agent-browser-setup.md +0 -45
@@ -12,13 +12,13 @@ This skill may include examples copied from the OpenCode harness. In Codex, do n
12
12
  | `call_omo_agent(subagent_type="librarian", ...)` | `multi_agent_v1.spawn_agent({"message":"TASK: act as a librarian. ...","agent_type":"librarian","fork_context":false})` |
13
13
  | `task(subagent_type="plan", ...)` | `multi_agent_v1.spawn_agent({"message":"TASK: act as a planning agent. ...","agent_type":"plan","fork_context":false})` |
14
14
  | `task(subagent_type="oracle", ...)` for final verification | By default, record a self-review in the notepad: re-read the diff, run diagnostics, and capture evidence for every acceptance criterion. Only when the user demanded strict, rigorous, or high-accuracy review, use `multi_agent_v1.spawn_agent({"message":"TASK: act as a rigorous reviewer. ...","agent_type":"lazycodex-gate-reviewer","fork_context":false})`; include `fork_context: false`. |
15
- | `task(category="...", ...)` for implementation or QA | `multi_agent_v1.spawn_agent({"message":"TASK: act as an implementation or QA worker. ...","fork_context":false})` |
15
+ | `task(category="...", ...)` for implementation or QA | `multi_agent_v1.spawn_agent({"message":"TASK: act as an implementation or QA worker. ...","agent_type":"lazycodex-worker-medium","fork_context":false})` |
16
16
  | `background_output(task_id="...")` | `multi_agent_v1.wait_agent(...)` for mailbox signals |
17
17
  | `team_*(...)` | Use Codex native subagents via `multi_agent_v1.spawn_agent` and `multi_agent_v1.wait_agent`; use `multi_agent_v1.send_input` and `multi_agent_v1.close_agent` only when exposed in the active tools list |
18
18
 
19
- 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`. OMO installs these selectable agent roles into `~/.codex/agents/`: `explorer`, `librarian`, `plan`, `momus`, `metis`, `lazycodex-code-reviewer`, `lazycodex-qa-executor`, and `lazycodex-gate-reviewer` - pass the matching name as `agent_type` so the child gets that role's model and instructions. If the spawn tool exposes no `agent_type` parameter, omit it and describe the role inside `message`. If a code block below conflicts with this section, this section wins.
19
+ 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`. OMO installs these selectable agent roles into `~/.codex/agents/`: `explorer`, `librarian`, `plan`, `momus`, `metis`, `lazycodex-code-reviewer`, `lazycodex-qa-executor`, and `lazycodex-gate-reviewer` - pass the matching name as `agent_type` so the child gets that role's model and instructions. Inspect the actual spawn schema: whenever `agent_type` is exposed, EVERY spawn MUST select an exact LazyCodex role, on V1 or V2. Implementation difficulty selects `lazycodex-worker-low`, `lazycodex-worker-medium`, or `lazycodex-worker-high`; clone QA can select `lazycodex-clone-fidelity-reviewer`. Never select generic `worker` or `default`. If a code block below conflicts with this section, this section wins.
20
20
 
21
- Codex exposes ONE of two subagent tool surfaces per session; check your own tool list and route accordingly. If `multi_agent_v1.*` tools exist, use the table above as written. If instead a flat `spawn_agent` with a required `task_name` exists (`multi_agent_v2`), rewrite every `multi_agent_v1.*` example: `multi_agent_v1.spawn_agent({...,"fork_context":false})` becomes `spawn_agent({"task_name":"<lowercase_digits_underscores>","message":...,"agent_type":...,"fork_turns":"none"})` (`"all"` only when full parent history is truly required); `send_input` becomes `send_message`; do not call `close_agent`/`resume_agent` (finished agents end on their own; `followup_task` re-tasks one, `interrupt_agent` stops one); `wait_agent` takes only `timeout_ms` and returns on any child mailbox activity. On the v2 surface `agent_type` may be ABSENT from the spawn schema (verified 2026-07-11: only `fork_turns`/`message`/`task_name`) — when absent, omit it and describe the role inside `message`; installed role TOMLs cannot be selected on that surface. If a code block below conflicts with this section, this section wins. `fork_context` is rejected on `multi_agent_v2` (`fork_context is not supported in MultiAgentV2; use fork_turns instead`).
21
+ Codex exposes ONE of two subagent tool surfaces per session; check your own tool list and route accordingly. If `multi_agent_v1.*` tools exist, use the table above as written. If instead a flat `spawn_agent` with a required `task_name` exists (`multi_agent_v2`), rewrite every `multi_agent_v1.*` example: `multi_agent_v1.spawn_agent({...,"fork_context":false})` becomes `spawn_agent({"task_name":"<lowercase_digits_underscores>","message":...,"agent_type":...,"fork_turns":"none"})` (`"all"` only when full parent history is truly required); `send_input` becomes `send_message`; do not call `close_agent`/`resume_agent` (finished agents end on their own; `followup_task` re-tasks one, `interrupt_agent` stops one); `wait_agent` takes only `timeout_ms` and returns on any child mailbox activity. Do not infer role support from V1/V2 or a model version. Legacy-schema exception: only if the actual schema lacks `agent_type`, omit that unsupported field and carry the complete role instructions in `message`, with history explicitly disabled. This cannot select a specialized TOML; an installed managed default supplies the medium worker for unnamed non-forks. The guard has no schema metadata and rejects unnamed calls, so report incompatible routing instead of retrying generically. Every deliberate full-history fork must still name its role: Codex skips role application on unnamed full-history forks, an upstream gap no LazyCodex default can repair. If a code block below conflicts with this section, this section wins. `fork_context` is rejected on `multi_agent_v2` (`fork_context is not supported in MultiAgentV2; use fork_turns instead`).
22
22
 
23
23
  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.
24
24
 
@@ -169,7 +169,7 @@ You are the QA lane. Do not delegate hands-on QA to a sub-agent: the orchestrato
169
169
  2. **Pick the channel that faithfully exercises the surface** and capture the artifact:
170
170
  - HTTP: `curl -i` (or an API request context) - status line, headers, body.
171
171
  - CLI / TUI: a real pty - drive the command and keep the transcript; for color or layout evidence render through a browser-based terminal, never a `tmux capture-pane` dump.
172
- - Web: the real page in a real browser - the harness's in-process surface (a `Bun.WebView` / `playwright-core` code cell, or Codex's Browser plugin) or the agent-browser CLI - action log plus screenshot.
172
+ - Web: from js eval, use `new Bun.WebView()` on Bun >= 1.4 (macOS default; Linux/Windows need Chrome/Chromium/Edge). Otherwise, or for Chrome semantics, stealth, trace, or auth, write and run a `playwright-core` script against local Chrome (`channel: "chrome"`; persistent context on a CLONED profile). Codex: `browser:control-in-app-browser`. Capture action log plus screenshot.
173
173
  - Desktop / GUI: OS-level automation against the running app - action log plus screenshot.
174
174
  - Library / SDK: a script that imports and exercises the public API - transcript.
175
175
  - Data-shaped work (migrations, configs, generated files): the resulting artifact itself, diffed or dumped.
@@ -1,8 +1,7 @@
1
1
  # ATTRIBUTION / NOTICE
2
2
 
3
3
  This skill (`ultimate-browsing`, part of `@oh-my-opencode/shared-skills`) ships
4
- project-original content, one vendored-and-modified upstream engine, plus two
5
- third-party tools that it installs at runtime (it does NOT vendor their source).
4
+ project-original content and one vendored-and-modified upstream engine.
6
5
  Each component's provenance, license, and required notices are reproduced below.
7
6
 
8
7
  ---
@@ -50,83 +49,3 @@ license obligation:
50
49
  These reference platform-native CLIs and public APIs by name (e.g. `xhs`, `yt-dlp`,
51
50
  `agent-reach`, `mcporter`, Jina Reader, V2EX public API). Those are external tools the
52
51
  user installs separately; this skill includes none of their source.
53
-
54
- ---
55
-
56
- ## 3. CloakBrowser (CloakHQ) — Tier-2 stealth Chromium (runtime dependency)
57
-
58
- The Tier-2 stealth browser is **CloakBrowser**, installed at runtime via `pip`
59
- (`pip install cloakbrowser`). No CloakBrowser source is vendored in this repository.
60
-
61
- - Source: https://github.com/CloakHQ/CloakBrowser
62
- - Pinned runtime version: **0.5.7** (documented in `references/chrome-stealth.md`;
63
- this is a documented version string, not an automated drift check).
64
- - Wrapper source license: MIT License.
65
- - Binary license: the compiled CloakBrowser Chromium binary downloaded by
66
- `cloakbrowser.ensure_binary()` is governed by the separate CloakBrowser
67
- Binary License:
68
- https://github.com/CloakHQ/CloakBrowser/blob/main/BINARY-LICENSE.md
69
- - Redistribution note: this npm package does not redistribute the CloakBrowser
70
- binary, does not repackage it, and does not include it in `skills/` or
71
- `dist/skills`. Users who run the Tier-2 setup download the binary directly
72
- from CloakHQ's official distribution channels and must comply with that
73
- binary license.
74
-
75
- MIT wrapper source license:
76
-
77
- ```
78
- MIT License
79
-
80
- Copyright (c) 2026 CloakHQ
81
-
82
- Permission is hereby granted, free of charge, to any person obtaining a copy
83
- of this software and associated documentation files (the "Software"), to deal
84
- in the Software without restriction, including without limitation the rights
85
- to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
86
- copies of the Software, and to permit persons to whom the Software is
87
- furnished to do so, subject to the following conditions:
88
-
89
- The above copyright notice and this permission notice shall be included in all
90
- copies or substantial portions of the Software.
91
-
92
- THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
93
- IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
94
- FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
95
- AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
96
- LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
97
- OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
98
- SOFTWARE.
99
- ```
100
-
101
- ---
102
-
103
- ## 4. agent-browser (vercel-labs) — Tier-2 CDP automation CLI (runtime dependency)
104
-
105
- The Tier-2 automation CLI is **agent-browser**, installed at runtime via `npm`
106
- (`bun add -g agent-browser`). No agent-browser source is vendored in this repository.
107
-
108
- - Source: https://github.com/vercel-labs/agent-browser
109
- - Pinned runtime version: **0.34.0** (documented in `references/chrome-stealth.md`;
110
- documented version string, no automated drift check).
111
- - Licensed under the Apache License, Version 2.0 (the "License"); you may not use
112
- these files except in compliance with the License. You may obtain a copy of the
113
- License at:
114
-
115
- http://www.apache.org/licenses/LICENSE-2.0
116
-
117
- Unless required by applicable law or agreed to in writing, software distributed under
118
- the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
119
- KIND, either express or implied. See the License for the specific language governing
120
- permissions and limitations under the License.
121
-
122
- - **Changes (Apache-2.0 §4(b)):** none. agent-browser is installed unmodified at
123
- runtime; no agent-browser source file is copied, modified, or redistributed by this
124
- skill. This skill only documents how to invoke the upstream CLI.
125
-
126
- - **NOTICE:** the upstream agent-browser distribution may include a `NOTICE` file. As
127
- this skill redistributes no agent-browser source, no upstream NOTICE content is
128
- bundled here; consult the upstream repository for its `NOTICE` file when present.
129
-
130
- - **Trademark notice:** "agent-browser" and "Vercel" are referenced by name for
131
- identification only. No trademark license is granted under the Apache License 2.0
132
- (Section 6).
@@ -1,13 +1,13 @@
1
1
  ---
2
2
  name: ultimate-browsing
3
- description: "Reaches web pages a plain fetch cannot: renders JS, drives clicks and forms, captures screenshots, holds a login, and gets past WAF blocks through platform-native readers and stealth Chrome. Use for any page work beyond retrieving static text."
3
+ description: "Renders, drives, and screenshots web pages: JS-rendered sources, clicks and forms, persistent logins, WAF-blocked hosts (platform-native readers, stealth Chrome), and the browsing lane of a research run, with screenshots as provenance. Not for plain search or unblocked static fetch."
4
4
  ---
5
5
 
6
6
  # Ultimate Browsing
7
7
 
8
8
  Web access for everything a plain fetch cannot finish: a page that renders in JS, a click or a form, a screenshot, a login that must persist across pages, or a host that blocks generic fetchers (WAF / 403 / Cloudflare). Start at the cheapest tier that can do the job and climb only when it cannot:
9
9
 
10
- **Tier 1 — insane-search** (headless extraction + WAF bypass) -> **Tier 1.5 — agent-reach** (platform-native APIs, esp. Chinese platforms) -> **Tier 2 — a real browser**: 2a a code-driven kernel browser, 2b Chrome stealth (CloakBrowser + agent-browser) when the page fights back.
10
+ **Tier 1 — insane-search** (headless extraction + WAF bypass) -> **Tier 1.5 — agent-reach** (platform-native APIs, esp. Chinese platforms) -> **Tier 2 — a real browser**: 2a Bun.WebView, 2b a local-Chrome `playwright-core` script from js eval for Chrome semantics, stealth, trace, or auth.
11
11
 
12
12
  ## PHASE 0 — ROUTE FIRST (MANDATORY)
13
13
 
@@ -86,33 +86,26 @@ Routing table, per-platform auth (set `TWITTER_*` env vars, `gh auth login`, a t
86
86
 
87
87
  ### Tier 2a — kernel browser (default)
88
88
 
89
- Drive the page from the code cell you are already in, with no CLI process and no open CDP port. On a Bun >= 1.4 runtime that is `new Bun.WebView()` (`navigate`, `click`, `type`, `evaluate`, `screenshot`, raw `cdp`); elsewhere it is `playwright-core`/`puppeteer-core` against the local Chrome. Snapshots and screenshots come back in-process, so this is the cheapest way to answer "what does the page actually render".
89
+ Use `new Bun.WebView()` from the js-eval kernel on Bun >= 1.4: macOS defaults to system WebKit; Linux/Windows need installed Chrome/Chromium/Edge. WebView is headless, WebKit has no CDP, and `type()` emits no keyboard events. For other kernels or when those differences matter, use 2b.
90
90
 
91
91
  ```js
92
- await using view = new Bun.WebView({ width: 1280, height: 800 })
93
- await view.navigate(url)
94
- const title = await view.evaluate("document.title")
95
- await view.screenshot({ path: "/tmp/page.png" })
92
+ const view = new Bun.WebView({ width: 1280, height: 800 })
93
+ try {
94
+ await view.navigate(url)
95
+ const title = await view.evaluate("document.title")
96
+ await Bun.write(pngPath, await view.screenshot())
97
+ } finally {
98
+ view[Symbol.dispose]()
99
+ }
96
100
  ```
97
101
 
98
- Climb to 2b when the site detects automation (Turnstile, FingerprintJS, "unusual traffic"), when the flow needs a persistent logged-in profile or injected cookies, or when the kernel browser cannot reach the page at all.
102
+ Use 2b for real-Chrome semantics, stealth, trace, authenticated profiles, or a page the kernel browser cannot reach.
99
103
 
100
104
  ### Tier 2b — Chrome stealth (blocked or logged-in pages)
101
105
 
102
- CloakBrowser is a stealth Chromium with source-level fingerprint patches that passes Cloudflare Turnstile, FingerprintJS, BrowserScan, and 30+ detectors; agent-browser is the CDP automation CLI that drives it. Both are runtime-installed tools (not vendored here). Full setup, version pins, launch flow, cookie login, and cross-platform notes are in [references/chrome-stealth.md](references/chrome-stealth.md).
106
+ WRITE a `playwright-core` script and run it from js eval against installed local Chrome: `chromium.launch({ channel: "chrome" })`, or `launchPersistentContext` on a task-owned profile. For authenticated state, CLONE the user's profile first (`rsync -a <profile>/ <tmp-clone>/`); NEVER launch against or clear cookies/cache/site data from the live profile. Codex: prefer `browser:control-in-app-browser` for ordinary page control.
103
107
 
104
- NEVER clear cookies, cache, or site data (`Network.clearBrowserCookies`, `Storage.clearCookies`, `chrome.browsingData.remove`, "clear browsing data") on the user's real/main browser profile — it wipes their logged-in state everywhere. If the task needs that profile's login state, clone the profile directory first (`rsync -a <profile>/ <tmp-clone>/`) and launch CloakBrowser / agent-browser with the clone as the user-data-dir; run any clearing on the clone only.
105
-
106
- ```bash
107
- # 1. Launch CloakBrowser with CDP on :9242 (see chrome-stealth.md for install + venv).
108
- # 2. CloakBrowser launches tabless — open the first tab via CDP before any agent-browser command:
109
- curl -s -X PUT "http://127.0.0.1:9242/json/new?https://example.com"
110
- # 3. Drive it with agent-browser over CDP:
111
- agent-browser --cdp 9242 snapshot -i # interactive elements (@eN refs)
112
- agent-browser --cdp 9242 click @e3
113
- agent-browser --cdp 9242 screenshot out.png
114
- agent-browser --cdp 9242 close
115
- ```
108
+ Keep the engine's Playwright templates for script-based extraction. Stealth is optional: the user installs `playwright-extra` + `puppeteer-extra-plugin-stealth` once in the engine directory and the script wraps the `playwright-core` browser type. Setup, persistent-context arguments, screenshots, and cleanup are in [references/chrome-stealth.md](references/chrome-stealth.md). A stealth flag is not proof of access: inspect the rendered result and report challenges that remain.
116
109
 
117
110
  ### Cookie login (cross-platform)
118
111
 
@@ -134,14 +127,11 @@ Cookie export files are written with owner-only `0600` permissions. Do not place
134
127
  |------|-------------|
135
128
  | [references/insane-search/README.md](references/insane-search/README.md) | Tier-1 engine harness (R1-R7, Phase 0 API index, no-site-name rule) + its `*.md` deep-dives |
136
129
  | [references/agent-reach/README.md](references/agent-reach/README.md) | Tier-1.5 routing table, platform auth, per-category `*.md` |
137
- | [references/chrome-stealth.md](references/chrome-stealth.md) | Tier-2 CloakBrowser + agent-browser install, CDP flow, version pins, cookie login |
130
+ | [references/chrome-stealth.md](references/chrome-stealth.md) | Tier-2 playwright-core scripts, optional stealth setup, cloned profiles, cookie login |
138
131
 
139
132
  ## Environment variables
140
133
 
141
134
  ```bash
142
- CLOAK_CDP_PORT=9242 # CloakBrowser CDP port (default 9242)
143
- AGENT_BROWSER_USER_AGENT="..." # override UA to hide HeadlessChrome
144
- AGENT_BROWSER_HEADED=1 # show the browser window
145
135
  # agent-reach auth: set the channel-specific env vars from each tool's docs only if you have access
146
136
  # insane-search needs no env vars — it auto-installs deps on first run
147
137
  ```
@@ -149,9 +139,7 @@ AGENT_BROWSER_HEADED=1 # show the browser window
149
139
  ## Anti-patterns
150
140
 
151
141
  - Do NOT launch Chrome stealth for plain text extraction — use Tier 1.
152
- - Do NOT pass an `--init-script` for the webdriver flag — CloakBrowser already patches it at source; the only required override is `--user-agent`.
153
- - Do NOT run agent-browser before creating the first tab via `curl -X PUT .../json/new` — CloakBrowser launches tabless.
154
- - Do NOT use vanilla Chrome when stealth is needed — always CloakBrowser.
155
- - Do NOT forget to `close` the session when done.
142
+ - Use stealth plugins only in an explicitly installed script environment, not injected into WebView.
143
+ - Close every WebView/browser context when done and remove only task-owned profile clones.
156
144
  - Do NOT inject cookies without reloading the page.
157
145
  - Do NOT hardcode site domains/selectors into `engine/**` or `waf_profiles.yaml` — runtime hints only (see the no-site-name rule in the insane-search reference).
@@ -65,7 +65,8 @@ is a regression, not an upgrade:
65
65
  - **De-personalization** — no personal absolute paths, no personal auth token literals,
66
66
  no personal browser choice; enforced by `depersonalization-gate.test.ts`.
67
67
  - **Skill-level layering** — the engine is Tier 1 under a router that also owns Tier 1.5
68
- (agent-reach) and Tier 2 (CloakBrowser + agent-browser). Upstream has no such tiering.
68
+ (agent-reach) and Tier 2 (Bun.WebView / local-Chrome playwright-core scripts from js eval).
69
+ Upstream has no such tiering.
69
70
 
70
71
  ### WANT — upstream improvements worth porting forward
71
72
 
@@ -2,9 +2,9 @@
2
2
  "name": "insane-search-templates",
3
3
  "version": "0.1.0",
4
4
  "private": true,
5
- "description": "Local deps for Playwright real-Chrome templates. npm install && npx playwright install chrome",
5
+ "description": "Script-only dependencies for local Chrome templates driven from js eval; Chrome must already be installed.",
6
6
  "dependencies": {
7
- "playwright": "^1.62.1",
7
+ "playwright-core": "^1.62.1",
8
8
  "playwright-extra": "^4.3.6",
9
9
  "puppeteer-extra-plugin-stealth": "^2.11.2"
10
10
  }
@@ -76,11 +76,12 @@ async function main() {
76
76
  const playwrightExtra = requireOptionalModule('playwright-extra');
77
77
  const stealthPlugin = playwrightExtra ? requireOptionalModule('puppeteer-extra-plugin-stealth') : null;
78
78
  if (playwrightExtra && stealthPlugin) {
79
- ({ chromium, devices } = playwrightExtra);
79
+ ({ devices } = require('playwright-core'));
80
+ chromium = playwrightExtra.addExtra(require('playwright-core').chromium);
80
81
  const stealth = stealthPlugin();
81
82
  chromium.use(stealth);
82
83
  } else {
83
- ({ chromium, devices } = require('playwright'));
84
+ ({ chromium, devices } = require('playwright-core'));
84
85
  }
85
86
 
86
87
  const dev = devices[deviceName];
@@ -94,6 +95,8 @@ async function main() {
94
95
  try {
95
96
  ctx = await chromium.launchPersistentContext(profileDir, {
96
97
  channel: 'chrome',
98
+ args: ['--disable-blink-features=AutomationControlled'],
99
+ ignoreDefaultArgs: ['--enable-automation'],
97
100
  headless,
98
101
  ...dev,
99
102
  });
@@ -10,9 +10,9 @@
10
10
  * NO-SITE-NAME RULE: this file must never branch on specific hostnames.
11
11
  * All site specifics come from the JSON input (url, waitSelector).
12
12
  *
13
- * Dependencies (install once on target machine):
14
- * npm i -g playwright playwright-extra puppeteer-extra-plugin-stealth
15
- * npx playwright install chrome # system Chrome binary
13
+ * User setup: ../../references/chrome-stealth.md (engine-local dependencies).
14
+ * Chrome must already be installed; optional stealth plugins run only in this script.
15
+ * Execute this script from js eval; profileDir must be task-owned or a CLONED profile.
16
16
  */
17
17
 
18
18
  const fs = require('fs');
@@ -82,18 +82,20 @@ async function main() {
82
82
  const playwrightExtra = requireOptionalModule('playwright-extra');
83
83
  const stealthPlugin = playwrightExtra ? requireOptionalModule('puppeteer-extra-plugin-stealth') : null;
84
84
  if (playwrightExtra && stealthPlugin) {
85
- ({ chromium } = playwrightExtra);
85
+ chromium = playwrightExtra.addExtra(require('playwright-core').chromium);
86
86
  const stealth = stealthPlugin();
87
87
  chromium.use(stealth);
88
88
  } else {
89
- // Fallback to plain playwright (no stealth). Still uses channel:chrome.
90
- ({ chromium } = require('playwright'));
89
+ // Core controls installed Chrome without downloading a managed browser.
90
+ ({ chromium } = require('playwright-core'));
91
91
  }
92
92
 
93
93
  let ctx;
94
94
  try {
95
95
  ctx = await chromium.launchPersistentContext(profileDir, {
96
96
  channel: 'chrome', // real Chrome, not bundled Chromium
97
+ args: ['--disable-blink-features=AutomationControlled'],
98
+ ignoreDefaultArgs: ['--enable-automation'],
97
99
  headless,
98
100
  viewport,
99
101
  });
@@ -0,0 +1,86 @@
1
+ from __future__ import annotations
2
+
3
+ import json
4
+ import os
5
+ import subprocess
6
+ import tempfile
7
+ import unittest
8
+ from pathlib import Path
9
+
10
+ from test_playwright_templates import (
11
+ TEMPLATE_NAMES,
12
+ TEMPLATES_DIR,
13
+ _install_fake_playwright,
14
+ _write_file,
15
+ )
16
+
17
+
18
+ class PlaywrightTemplateStealth(unittest.TestCase):
19
+ def test_extracts_html_and_closes_wrapped_chrome_when_stealth_is_installed(self) -> None:
20
+ for template_name in TEMPLATE_NAMES:
21
+ with self.subTest(template_name=template_name), tempfile.TemporaryDirectory() as tmp:
22
+ # Given: core has no plugin API; only addExtra supplies a registered wrapper.
23
+ root = Path(tmp)
24
+ modules = root / "node_modules"
25
+ profile = root / "profile"
26
+ receipt = root / "launch.json"
27
+ _install_fake_playwright(modules)
28
+ _write_file(modules / "puppeteer-extra-plugin-stealth/index.js", """
29
+ module.exports = () => ({ name: 'stealth' });
30
+ """)
31
+ _write_file(modules / "playwright-extra/index.js", """
32
+ const assert = require('node:assert/strict');
33
+ const fs = require('node:fs');
34
+ exports.addExtra = (core) => {
35
+ assert.equal(core, require('playwright-core').chromium);
36
+ assert.equal(Object.hasOwn(core, 'use'), false);
37
+ const events = ['wrap'];
38
+ let registered = false;
39
+ return {
40
+ use(plugin) {
41
+ assert.equal(plugin.name, 'stealth');
42
+ registered = true;
43
+ events.push(plugin.name);
44
+ },
45
+ async launchPersistentContext(profileDir, options) {
46
+ assert.equal(registered, true);
47
+ events.push({ profileDir, channel: options.channel, viewport: options.viewport });
48
+ const context = await core.launchPersistentContext(profileDir, options);
49
+ return {
50
+ ...context,
51
+ async close() {
52
+ await context.close();
53
+ events.push('close');
54
+ fs.writeFileSync(process.env.STEALTH_RECEIPT, JSON.stringify(events));
55
+ },
56
+ };
57
+ },
58
+ };
59
+ };
60
+ """)
61
+ script = root / template_name
62
+ script.write_bytes((TEMPLATES_DIR / template_name).read_bytes())
63
+ env = {key: value for key, value in os.environ.items() if key != "NODE_PATH"}
64
+ env["STEALTH_RECEIPT"] = str(receipt)
65
+
66
+ # When: the actual bundled entry point consumes its normal stdin protocol.
67
+ result = subprocess.run(
68
+ ["node", str(script)],
69
+ input=json.dumps({"url": "https://example.com/", "profileDir": str(profile), "headless": True}),
70
+ text=True, capture_output=True, timeout=5, env=env, check=False,
71
+ )
72
+
73
+ # Then: HTML arrives through the registered wrapper and the context is closed.
74
+ self.assertEqual(result.returncode, 0, result.stderr)
75
+ self.assertEqual(result.stdout, "<html><article>ok</article></html>")
76
+ self.assertEqual(result.stderr, "")
77
+ viewport = {"width": 390, "height": 844} if "mobile" in template_name else {"width": 1366, "height": 900}
78
+ self.assertEqual(json.loads(receipt.read_text(encoding="utf-8")), [
79
+ "wrap", "stealth",
80
+ {"profileDir": str(profile), "channel": "chrome", "viewport": viewport},
81
+ "close",
82
+ ])
83
+
84
+
85
+ if __name__ == "__main__":
86
+ unittest.main()
@@ -21,7 +21,7 @@ def _write_file(path: Path, content: str) -> None:
21
21
 
22
22
  def _install_fake_playwright(node_modules: Path) -> None:
23
23
  _write_file(
24
- node_modules / "playwright" / "index.js",
24
+ node_modules / "playwright-core" / "index.js",
25
25
  """
26
26
  const page = {
27
27
  async goto() {},
@@ -47,7 +47,6 @@ def _install_fake_playwright(node_modules: Path) -> None:
47
47
  };
48
48
 
49
49
  exports.chromium = {
50
- use() {},
51
50
  async launchPersistentContext() { return context; },
52
51
  };
53
52
  exports.devices = {
@@ -78,9 +77,7 @@ def _install_working_playwright_extra(node_modules: Path) -> None:
78
77
  _write_file(
79
78
  node_modules / "playwright-extra" / "index.js",
80
79
  """
81
- const playwright = require('playwright');
82
- exports.chromium = playwright.chromium;
83
- exports.devices = playwright.devices;
80
+ exports.addExtra = (browserType) => browserType;
84
81
  """,
85
82
  )
86
83
 
@@ -149,7 +146,7 @@ def _run_template(
149
146
 
150
147
  @unittest.skipUnless(shutil.which("node"), "node is required for Playwright template tests")
151
148
  class PlaywrightTemplateErrorHandling(unittest.TestCase):
152
- def test_missing_playwright_extra_warns_and_falls_back_to_plain_playwright(self) -> None:
149
+ def test_missing_playwright_extra_warns_and_falls_back_to_playwright_core(self) -> None:
153
150
  for template_name in TEMPLATE_NAMES:
154
151
  with self.subTest(template_name=template_name):
155
152
  result = _run_template(
@@ -166,7 +163,7 @@ class PlaywrightTemplateErrorHandling(unittest.TestCase):
166
163
  self.assertIn("best-effort optional module playwright-extra failed:", result.stderr)
167
164
  self.assertIn("Cannot find module 'playwright-extra'", result.stderr)
168
165
 
169
- def test_missing_stealth_plugin_warns_and_falls_back_to_plain_playwright(self) -> None:
166
+ def test_missing_stealth_plugin_warns_and_falls_back_to_playwright_core(self) -> None:
170
167
  for template_name in TEMPLATE_NAMES:
171
168
  with self.subTest(template_name=template_name):
172
169
  result = _run_template(