oh-my-opencode 4.19.4 → 5.0.0-beta.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (268) hide show
  1. package/README.ja.md +1 -1
  2. package/README.ko.md +1 -1
  3. package/README.md +6 -5
  4. package/README.ru.md +1 -1
  5. package/README.zh-cn.md +1 -1
  6. package/bin/oh-my-opencode.js +14 -1
  7. package/bin/oh-my-opencode.test.ts +21 -0
  8. package/dist/cli/index.js +1452 -703
  9. package/dist/cli-node/index.js +1452 -703
  10. package/dist/config/schema/agent-overrides.d.ts +528 -0
  11. package/dist/config/schema/oh-my-opencode-config.d.ts +495 -0
  12. package/dist/features/monitor/batcher.d.ts +3 -1
  13. package/dist/features/monitor/manager-internals.d.ts +1 -0
  14. package/dist/features/monitor/output-injector-types.d.ts +2 -0
  15. package/dist/features/monitor/output-injector.d.ts +6 -0
  16. package/dist/hooks/todo-continuation-enforcer/types.d.ts +1 -0
  17. package/dist/hooks/todo-continuation-enforcer/unrecoverable-request-error.d.ts +9 -0
  18. package/dist/hooks/tool-pair-validator/hook.test-support.d.ts +29 -0
  19. package/dist/hooks/tool-pair-validator/tool-part-ids.d.ts +14 -5
  20. package/dist/hooks/tool-pair-validator/tool-result-repair.d.ts +4 -3
  21. package/dist/hooks/tool-pair-validator/types.d.ts +5 -22
  22. package/dist/index.js +2776 -2240
  23. package/dist/mcp/lsp.d.ts +1 -0
  24. package/dist/oh-my-opencode.schema.json +1466 -131
  25. package/dist/shared/tmux/constants.d.ts +1 -1
  26. package/dist/skills/ast-grep/SOURCE +1 -1
  27. package/dist/skills/ast-grep/install.ps1 +2 -2
  28. package/dist/skills/ast-grep/install.sh +1 -1
  29. package/dist/skills/ast-grep/references/install.md +2 -2
  30. package/dist/skills/ast-grep/tests/smoke.sh +1 -1
  31. package/dist/skills/start-work/SKILL.md +54 -9
  32. package/dist/skills/ultimate-browsing/SKILL.md +2 -2
  33. package/dist/skills/ultimate-browsing/engine/__main__.py +8 -1
  34. package/dist/skills/ultimate-browsing/engine/bias_check.py +11 -0
  35. package/dist/skills/ultimate-browsing/engine/fetch_chain.py +90 -52
  36. package/dist/skills/ultimate-browsing/engine/result_schema.py +10 -1
  37. package/dist/skills/ultimate-browsing/engine/surrogate.py +214 -0
  38. package/dist/skills/ultimate-browsing/engine/surrogates.yaml +60 -0
  39. package/dist/skills/ultimate-browsing/engine/tests/fixtures/amp_redirect_stub.html +7 -0
  40. package/dist/skills/ultimate-browsing/engine/tests/fixtures/search_interstitial.html +19 -0
  41. package/dist/skills/ultimate-browsing/engine/tests/fixtures/wayback_available.json +1 -0
  42. package/dist/skills/ultimate-browsing/engine/tests/fixtures/wayback_snapshot.html +1128 -0
  43. package/dist/skills/ultimate-browsing/engine/tests/test_surrogate.py +252 -0
  44. package/dist/skills/ultimate-browsing/engine/tests/test_surrogate_validators.py +78 -0
  45. package/dist/skills/ultimate-browsing/engine/validators.py +46 -0
  46. package/dist/skills/ultimate-browsing/engine/waf_detector.py +1 -1
  47. package/dist/skills/ultimate-browsing/engine/waf_profiles.yaml +10 -5
  48. package/dist/skills/ultimate-browsing/references/agent-reach/social.md +1 -1
  49. package/dist/skills/ultimate-browsing/references/chrome-stealth.md +13 -11
  50. package/dist/skills/ultimate-browsing/references/insane-search/README.md +4 -4
  51. package/dist/skills/ultimate-browsing/references/insane-search/cache-archive.md +51 -50
  52. package/dist/skills/ultimate-browsing/references/insane-search/fallback.md +1 -1
  53. package/dist/skills/ultimate-browsing/references/insane-search/jina.md +8 -2
  54. package/dist/skills/ultimate-browsing/references/insane-search/naver.md +1 -1
  55. package/dist/skills/ultimate-browsing/references/insane-search/twitter.md +3 -3
  56. package/dist/skills/ulw-plan/SKILL.md +1 -1
  57. package/dist/skills/ulw-plan/references/full-workflow.md +3 -3
  58. package/dist/skills/ulw-plan/scripts/scaffold-plan.mjs +1 -1
  59. package/dist/skills/ulw-research/SKILL.md +15 -10
  60. package/dist/tui.js +307 -28
  61. package/docs/reference/web-terminal-visual-qa.md +1 -1
  62. package/package.json +27 -19
  63. package/packages/lsp-core/src/lsp/connection.ts +1 -1
  64. package/packages/lsp-daemon/dist/cli.js +27 -13
  65. package/packages/lsp-daemon/dist/client.js +49 -35
  66. package/packages/lsp-daemon/dist/ensure-daemon.d.ts +1 -0
  67. package/packages/lsp-daemon/dist/ensure-daemon.js +18 -5
  68. package/packages/lsp-daemon/dist/index.js +34 -20
  69. package/packages/lsp-tools-mcp/dist/cli.js +1 -1
  70. package/packages/lsp-tools-mcp/dist/lsp/manager.js +1 -1
  71. package/packages/lsp-tools-mcp/dist/mcp.js +1 -1
  72. package/packages/lsp-tools-mcp/dist/tools.js +1 -1
  73. package/packages/omo-codex/plugin/.codex-plugin/plugin.json +1 -1
  74. package/packages/omo-codex/plugin/components/bootstrap/dist/cli.js +268 -92
  75. package/packages/omo-codex/plugin/components/bootstrap/hooks/hooks.json +1 -1
  76. package/packages/omo-codex/plugin/components/bootstrap/package.json +1 -1
  77. package/packages/omo-codex/plugin/components/bootstrap/src/setup.ts +7 -7
  78. package/packages/omo-codex/plugin/components/bootstrap/src/worker.ts +3 -0
  79. package/packages/omo-codex/plugin/components/codegraph/dist/cli.js +106 -6
  80. package/packages/omo-codex/plugin/components/codegraph/dist/serve.js +106 -6
  81. package/packages/omo-codex/plugin/components/codegraph/package.json +1 -1
  82. package/packages/omo-codex/plugin/components/comment-checker/hooks/hooks.json +1 -1
  83. package/packages/omo-codex/plugin/components/comment-checker/package.json +1 -1
  84. package/packages/omo-codex/plugin/components/git-bash/hooks/hooks.json +2 -2
  85. package/packages/omo-codex/plugin/components/git-bash/package.json +1 -1
  86. package/packages/omo-codex/plugin/components/lazycodex-executor-verify/hooks/hooks.json +1 -1
  87. package/packages/omo-codex/plugin/components/lazycodex-executor-verify/package.json +1 -1
  88. package/packages/omo-codex/plugin/components/lsp/dist/.omo-runtime-manifest.json +3 -3
  89. package/packages/omo-codex/plugin/components/lsp/dist/cli.js +56 -42
  90. package/packages/omo-codex/plugin/components/lsp/hooks/hooks.json +2 -2
  91. package/packages/omo-codex/plugin/components/lsp/package.json +1 -1
  92. package/packages/omo-codex/plugin/components/rules/hooks/hooks.json +4 -4
  93. package/packages/omo-codex/plugin/components/rules/package.json +1 -1
  94. package/packages/omo-codex/plugin/components/start-work-continuation/AGENTS.md +1 -0
  95. package/packages/omo-codex/plugin/components/start-work-continuation/README.md +5 -1
  96. package/packages/omo-codex/plugin/components/start-work-continuation/directive.md +2 -1
  97. package/packages/omo-codex/plugin/components/start-work-continuation/dist/cli.js +18 -0
  98. package/packages/omo-codex/plugin/components/start-work-continuation/hooks/hooks.json +2 -2
  99. package/packages/omo-codex/plugin/components/start-work-continuation/package.json +1 -1
  100. package/packages/omo-codex/plugin/components/start-work-continuation/src/codex-hook.ts +21 -0
  101. package/packages/omo-codex/plugin/components/start-work-continuation/test/codex-hook.test.ts +105 -0
  102. package/packages/omo-codex/plugin/components/teammode/hooks/hooks.json +1 -1
  103. package/packages/omo-codex/plugin/components/teammode/package.json +1 -1
  104. package/packages/omo-codex/plugin/components/telemetry/hooks/hooks.json +1 -1
  105. package/packages/omo-codex/plugin/components/telemetry/package.json +1 -1
  106. package/packages/omo-codex/plugin/components/ultrawork/CHANGELOG.md +2 -0
  107. package/packages/omo-codex/plugin/components/ultrawork/agents/lazycodex-code-reviewer.toml +1 -1
  108. package/packages/omo-codex/plugin/components/ultrawork/agents/lazycodex-gate-reviewer.toml +1 -1
  109. package/packages/omo-codex/plugin/components/ultrawork/agents/lazycodex-qa-executor.toml +1 -1
  110. package/packages/omo-codex/plugin/components/ultrawork/agents/lazycodex-worker-high.toml +1 -1
  111. package/packages/omo-codex/plugin/components/ultrawork/agents/lazycodex-worker-low.toml +1 -1
  112. package/packages/omo-codex/plugin/components/ultrawork/agents/lazycodex-worker-medium.toml +1 -1
  113. package/packages/omo-codex/plugin/components/ultrawork/agents/plan.toml +2 -2
  114. package/packages/omo-codex/plugin/components/ultrawork/directive.md +3 -2
  115. package/packages/omo-codex/plugin/components/ultrawork/hooks/hooks.json +1 -1
  116. package/packages/omo-codex/plugin/components/ultrawork/package.json +1 -1
  117. package/packages/omo-codex/plugin/components/ultrawork/skills/ultrawork/SKILL.md +3 -2
  118. package/packages/omo-codex/plugin/components/ultrawork/skills/ulw-plan/SKILL.md +1 -1
  119. package/packages/omo-codex/plugin/components/ultrawork/skills/ulw-plan/references/full-workflow.md +3 -3
  120. package/packages/omo-codex/plugin/components/ultrawork/skills/ulw-plan/scripts/scaffold-plan.mjs +1 -1
  121. package/packages/omo-codex/plugin/components/ulw-loop/AGENTS.md +1 -1
  122. package/packages/omo-codex/plugin/components/ulw-loop/CHANGELOG.md +2 -0
  123. package/packages/omo-codex/plugin/components/ulw-loop/README.md +11 -11
  124. package/packages/omo-codex/plugin/components/ulw-loop/directive.md +3 -2
  125. package/packages/omo-codex/plugin/components/ulw-loop/dist/checkpoint-reconciliation.js +1 -1
  126. package/packages/omo-codex/plugin/components/ulw-loop/dist/cli-output.d.ts +1 -1
  127. package/packages/omo-codex/plugin/components/ulw-loop/dist/cli-output.js +9 -9
  128. package/packages/omo-codex/plugin/components/ulw-loop/dist/cli-steering.js +1 -1
  129. package/packages/omo-codex/plugin/components/ulw-loop/dist/cli.js +66 -66
  130. package/packages/omo-codex/plugin/components/ulw-loop/dist/codex-goal-instruction.js +4 -4
  131. package/packages/omo-codex/plugin/components/ulw-loop/dist/codex-hook.js +1 -1
  132. package/packages/omo-codex/plugin/components/ulw-loop/dist/plan-crud.js +1 -1
  133. package/packages/omo-codex/plugin/components/ulw-loop/dist/plan-io.js +1 -1
  134. package/packages/omo-codex/plugin/components/ulw-loop/dist/steering.js +1 -1
  135. package/packages/omo-codex/plugin/components/ulw-loop/dist/stop-resume-hook.js +2 -2
  136. package/packages/omo-codex/plugin/components/ulw-loop/hooks/hooks.json +4 -4
  137. package/packages/omo-codex/plugin/components/ulw-loop/package.json +1 -1
  138. package/packages/omo-codex/plugin/components/ulw-loop/skills/ulw-loop/SKILL.md +3 -3
  139. package/packages/omo-codex/plugin/components/ulw-loop/skills/ulw-loop/references/full-workflow.md +22 -25
  140. package/packages/omo-codex/plugin/components/ulw-loop/src/checkpoint-reconciliation.ts +1 -1
  141. package/packages/omo-codex/plugin/components/ulw-loop/src/cli-output.ts +9 -9
  142. package/packages/omo-codex/plugin/components/ulw-loop/src/cli-steering.ts +1 -1
  143. package/packages/omo-codex/plugin/components/ulw-loop/src/cli.ts +1 -1
  144. package/packages/omo-codex/plugin/components/ulw-loop/src/codex-goal-instruction.ts +4 -4
  145. package/packages/omo-codex/plugin/components/ulw-loop/src/codex-hook.ts +1 -1
  146. package/packages/omo-codex/plugin/components/ulw-loop/src/plan-crud.ts +1 -1
  147. package/packages/omo-codex/plugin/components/ulw-loop/src/plan-io.ts +1 -1
  148. package/packages/omo-codex/plugin/components/ulw-loop/src/steering.ts +1 -1
  149. package/packages/omo-codex/plugin/components/ulw-loop/src/stop-resume-hook.ts +2 -2
  150. package/packages/omo-codex/plugin/components/ulw-loop/test/cli-commands.test.ts +2 -2
  151. package/packages/omo-codex/plugin/components/ulw-loop/test/cli-entrypoint.test.ts +1 -1
  152. package/packages/omo-codex/plugin/components/ulw-loop/test/cli-helpers.test.ts +2 -2
  153. package/packages/omo-codex/plugin/components/ulw-loop/test/cli-steering-kind-guidance.test.ts +1 -1
  154. package/packages/omo-codex/plugin/components/ulw-loop/test/codex-hook.test.ts +2 -2
  155. package/packages/omo-codex/plugin/components/ulw-loop/test/fixtures/quality-gate-builder.ts +1 -1
  156. package/packages/omo-codex/plugin/components/ulw-loop/test/package-smoke.test.ts +5 -5
  157. package/packages/omo-codex/plugin/components/ulw-loop/test/plan-io.test.ts +1 -1
  158. package/packages/omo-codex/plugin/components/ulw-loop/test/quality-gate-roles.test.ts +1 -1
  159. package/packages/omo-codex/plugin/components/ulw-loop/test/steering.test.ts +1 -1
  160. package/packages/omo-codex/plugin/components/ulw-loop/test/stop-resume-hook.test.ts +1 -1
  161. package/packages/omo-codex/plugin/hooks/post-compact-resetting-git-bash-mcp-reminder.json +1 -1
  162. package/packages/omo-codex/plugin/hooks/post-compact-resetting-lsp-diagnostics-cache.json +1 -1
  163. package/packages/omo-codex/plugin/hooks/post-compact-resetting-project-rule-cache.json +1 -1
  164. package/packages/omo-codex/plugin/hooks/post-tool-use-checking-codegraph-init-guidance.json +1 -1
  165. package/packages/omo-codex/plugin/hooks/post-tool-use-checking-comments.json +1 -1
  166. package/packages/omo-codex/plugin/hooks/post-tool-use-checking-lsp-diagnostics.json +1 -1
  167. package/packages/omo-codex/plugin/hooks/post-tool-use-checking-thread-title-hygiene.json +1 -1
  168. package/packages/omo-codex/plugin/hooks/post-tool-use-matching-project-rules.json +1 -1
  169. package/packages/omo-codex/plugin/hooks/pre-tool-use-enforcing-unlimited-goal-budget.json +1 -1
  170. package/packages/omo-codex/plugin/hooks/pre-tool-use-guarding-ulw-loop-spawns.json +1 -1
  171. package/packages/omo-codex/plugin/hooks/pre-tool-use-recommending-git-bash-mcp.json +1 -1
  172. package/packages/omo-codex/plugin/hooks/session-start-checking-auto-update.json +1 -1
  173. package/packages/omo-codex/plugin/hooks/session-start-checking-bootstrap-provisioning.json +1 -1
  174. package/packages/omo-codex/plugin/hooks/session-start-checking-codegraph-bootstrap.json +1 -1
  175. package/packages/omo-codex/plugin/hooks/session-start-loading-project-rules.json +1 -1
  176. package/packages/omo-codex/plugin/hooks/session-start-recording-session-telemetry.json +1 -1
  177. package/packages/omo-codex/plugin/hooks/stop-checking-start-work-continuation.json +1 -1
  178. package/packages/omo-codex/plugin/hooks/stop-checking-ulw-loop-resume.json +1 -1
  179. package/packages/omo-codex/plugin/hooks/subagent-stop-checking-start-work-continuation.json +1 -1
  180. package/packages/omo-codex/plugin/hooks/subagent-stop-verifying-lazycodex-executor-evidence.json +1 -1
  181. package/packages/omo-codex/plugin/hooks/user-prompt-submit-checking-ultrawork-trigger.json +1 -1
  182. package/packages/omo-codex/plugin/hooks/user-prompt-submit-checking-ulw-loop-steering.json +1 -1
  183. package/packages/omo-codex/plugin/hooks/user-prompt-submit-loading-project-rules.json +1 -1
  184. package/packages/omo-codex/plugin/package-lock.json +13 -13
  185. package/packages/omo-codex/plugin/package.json +1 -1
  186. package/packages/omo-codex/plugin/scripts/sync-skills.mjs +4 -4
  187. package/packages/omo-codex/plugin/skills/ast-grep/SOURCE +1 -1
  188. package/packages/omo-codex/plugin/skills/ast-grep/install.ps1 +2 -2
  189. package/packages/omo-codex/plugin/skills/ast-grep/install.sh +1 -1
  190. package/packages/omo-codex/plugin/skills/ast-grep/references/install.md +2 -2
  191. package/packages/omo-codex/plugin/skills/ast-grep/tests/smoke.sh +1 -1
  192. package/packages/omo-codex/plugin/skills/start-work/SKILL.md +54 -9
  193. package/packages/omo-codex/plugin/skills/ultimate-browsing/SKILL.md +2 -2
  194. package/packages/omo-codex/plugin/skills/ultimate-browsing/engine/__main__.py +8 -1
  195. package/packages/omo-codex/plugin/skills/ultimate-browsing/engine/bias_check.py +11 -0
  196. package/packages/omo-codex/plugin/skills/ultimate-browsing/engine/fetch_chain.py +90 -52
  197. package/packages/omo-codex/plugin/skills/ultimate-browsing/engine/result_schema.py +10 -1
  198. package/packages/omo-codex/plugin/skills/ultimate-browsing/engine/surrogate.py +214 -0
  199. package/packages/omo-codex/plugin/skills/ultimate-browsing/engine/surrogates.yaml +60 -0
  200. package/packages/omo-codex/plugin/skills/ultimate-browsing/engine/tests/fixtures/amp_redirect_stub.html +7 -0
  201. package/packages/omo-codex/plugin/skills/ultimate-browsing/engine/tests/fixtures/search_interstitial.html +19 -0
  202. package/packages/omo-codex/plugin/skills/ultimate-browsing/engine/tests/fixtures/wayback_available.json +1 -0
  203. package/packages/omo-codex/plugin/skills/ultimate-browsing/engine/tests/fixtures/wayback_snapshot.html +1128 -0
  204. package/packages/omo-codex/plugin/skills/ultimate-browsing/engine/tests/test_surrogate.py +252 -0
  205. package/packages/omo-codex/plugin/skills/ultimate-browsing/engine/tests/test_surrogate_validators.py +78 -0
  206. package/packages/omo-codex/plugin/skills/ultimate-browsing/engine/validators.py +46 -0
  207. package/packages/omo-codex/plugin/skills/ultimate-browsing/engine/waf_detector.py +1 -1
  208. package/packages/omo-codex/plugin/skills/ultimate-browsing/engine/waf_profiles.yaml +10 -5
  209. package/packages/omo-codex/plugin/skills/ultimate-browsing/references/agent-reach/social.md +1 -1
  210. package/packages/omo-codex/plugin/skills/ultimate-browsing/references/chrome-stealth.md +13 -11
  211. package/packages/omo-codex/plugin/skills/ultimate-browsing/references/insane-search/README.md +4 -4
  212. package/packages/omo-codex/plugin/skills/ultimate-browsing/references/insane-search/cache-archive.md +51 -50
  213. package/packages/omo-codex/plugin/skills/ultimate-browsing/references/insane-search/fallback.md +1 -1
  214. package/packages/omo-codex/plugin/skills/ultimate-browsing/references/insane-search/jina.md +8 -2
  215. package/packages/omo-codex/plugin/skills/ultimate-browsing/references/insane-search/naver.md +1 -1
  216. package/packages/omo-codex/plugin/skills/ultimate-browsing/references/insane-search/twitter.md +3 -3
  217. package/packages/omo-codex/plugin/skills/ultrawork/SKILL.md +3 -2
  218. package/packages/omo-codex/plugin/skills/ulw-loop/SKILL.md +3 -3
  219. package/packages/omo-codex/plugin/skills/ulw-loop/references/full-workflow.md +22 -25
  220. package/packages/omo-codex/plugin/skills/ulw-plan/SKILL.md +1 -1
  221. package/packages/omo-codex/plugin/skills/ulw-plan/references/full-workflow.md +3 -3
  222. package/packages/omo-codex/plugin/skills/ulw-plan/scripts/scaffold-plan.mjs +1 -1
  223. package/packages/omo-codex/plugin/skills/ulw-research/SKILL.md +15 -10
  224. package/packages/omo-codex/plugin/test/bootstrap-binlinks.test.mjs +12 -12
  225. package/packages/omo-codex/plugin/test/bootstrap-orchestration.test.mjs +36 -4
  226. package/packages/omo-codex/plugin/test/sync-skills-orchestration.test.mjs +1 -1
  227. package/packages/omo-codex/plugin/test/sync-skills-test-support.mjs +4 -4
  228. package/packages/omo-codex/scripts/install-bin-links.test.mjs +56 -2
  229. package/packages/omo-codex/scripts/install-delegated-command.test.mjs +6 -6
  230. package/packages/omo-codex/scripts/install-dist/install-local.mjs +115 -61
  231. package/packages/omo-codex/scripts/install-local-entrypoint.test.mjs +4 -4
  232. package/packages/omo-codex/scripts/install-local.test.mjs +5 -2
  233. package/packages/shared-skills/index.mjs +19 -1
  234. package/packages/shared-skills/skills/ast-grep/SOURCE +1 -1
  235. package/packages/shared-skills/skills/ast-grep/install.ps1 +2 -2
  236. package/packages/shared-skills/skills/ast-grep/install.sh +1 -1
  237. package/packages/shared-skills/skills/ast-grep/references/install.md +2 -2
  238. package/packages/shared-skills/skills/ast-grep/tests/smoke.sh +1 -1
  239. package/packages/shared-skills/skills/start-work/SKILL.md +54 -9
  240. package/packages/shared-skills/skills/ultimate-browsing/SKILL.md +2 -2
  241. package/packages/shared-skills/skills/ultimate-browsing/engine/__main__.py +8 -1
  242. package/packages/shared-skills/skills/ultimate-browsing/engine/bias_check.py +11 -0
  243. package/packages/shared-skills/skills/ultimate-browsing/engine/fetch_chain.py +90 -52
  244. package/packages/shared-skills/skills/ultimate-browsing/engine/result_schema.py +10 -1
  245. package/packages/shared-skills/skills/ultimate-browsing/engine/surrogate.py +214 -0
  246. package/packages/shared-skills/skills/ultimate-browsing/engine/surrogates.yaml +60 -0
  247. package/packages/shared-skills/skills/ultimate-browsing/engine/tests/fixtures/amp_redirect_stub.html +7 -0
  248. package/packages/shared-skills/skills/ultimate-browsing/engine/tests/fixtures/search_interstitial.html +19 -0
  249. package/packages/shared-skills/skills/ultimate-browsing/engine/tests/fixtures/wayback_available.json +1 -0
  250. package/packages/shared-skills/skills/ultimate-browsing/engine/tests/fixtures/wayback_snapshot.html +1128 -0
  251. package/packages/shared-skills/skills/ultimate-browsing/engine/tests/test_surrogate.py +252 -0
  252. package/packages/shared-skills/skills/ultimate-browsing/engine/tests/test_surrogate_validators.py +78 -0
  253. package/packages/shared-skills/skills/ultimate-browsing/engine/validators.py +46 -0
  254. package/packages/shared-skills/skills/ultimate-browsing/engine/waf_detector.py +1 -1
  255. package/packages/shared-skills/skills/ultimate-browsing/engine/waf_profiles.yaml +10 -5
  256. package/packages/shared-skills/skills/ultimate-browsing/references/agent-reach/social.md +1 -1
  257. package/packages/shared-skills/skills/ultimate-browsing/references/chrome-stealth.md +13 -11
  258. package/packages/shared-skills/skills/ultimate-browsing/references/insane-search/README.md +4 -4
  259. package/packages/shared-skills/skills/ultimate-browsing/references/insane-search/cache-archive.md +51 -50
  260. package/packages/shared-skills/skills/ultimate-browsing/references/insane-search/fallback.md +1 -1
  261. package/packages/shared-skills/skills/ultimate-browsing/references/insane-search/jina.md +8 -2
  262. package/packages/shared-skills/skills/ultimate-browsing/references/insane-search/naver.md +1 -1
  263. package/packages/shared-skills/skills/ultimate-browsing/references/insane-search/twitter.md +3 -3
  264. package/packages/shared-skills/skills/ulw-plan/SKILL.md +1 -1
  265. package/packages/shared-skills/skills/ulw-plan/references/full-workflow.md +3 -3
  266. package/packages/shared-skills/skills/ulw-plan/scripts/scaffold-plan.mjs +1 -1
  267. package/packages/shared-skills/skills/ulw-research/SKILL.md +15 -10
  268. package/postinstall.mjs +6 -0
@@ -1 +1 @@
1
- export { POLL_INTERVAL_BACKGROUND_MS, SESSION_MISSING_GRACE_MS, SESSION_READY_POLL_INTERVAL_MS, SESSION_READY_TIMEOUT_MS, SESSION_TIMEOUT_MS, } from "@oh-my-opencode/tmux-core";
1
+ export { AUTO_ACTIVATE_GRACE_MS, POLL_INTERVAL_BACKGROUND_MS, SESSION_MISSING_GRACE_MS, SESSION_READY_POLL_INTERVAL_MS, SESSION_READY_TIMEOUT_MS, SESSION_TIMEOUT_MS, } from "@oh-my-opencode/tmux-core";
@@ -1 +1 @@
1
- upstream: https://github.com/code-yeongyu/ast-grep-skill @ 3148c69 (ast-grep 0.43.0). Vendored as a sync; do not fork-drift.
1
+ upstream: https://github.com/code-yeongyu/ast-grep-skill @ 3148c69 (ast-grep 0.45.0). Vendored as a sync; do not fork-drift.
@@ -21,7 +21,7 @@
21
21
  Force one method: scoop | winget | choco | npm | cargo | pip | github
22
22
 
23
23
  .PARAMETER Version
24
- Pin a specific version when downloading from GitHub. Default: 0.43.0
24
+ Pin a specific version when downloading from GitHub. Default: 0.45.0
25
25
 
26
26
  .PARAMETER NoFallback
27
27
  Don't fall back to GitHub zip; fail if all package managers miss
@@ -37,7 +37,7 @@
37
37
 
38
38
  param(
39
39
  [string]$Method = "",
40
- [string]$Version = "0.43.0",
40
+ [string]$Version = "0.45.0",
41
41
  [switch]$NoFallback,
42
42
  [switch]$Quiet
43
43
  )
@@ -33,7 +33,7 @@ SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
33
33
  SKILL_ROOT="$SCRIPT_DIR"
34
34
  CACHE_BIN_DIR="${OMO_AST_GREP_BIN_DIR:-$SKILL_ROOT/bin}"
35
35
 
36
- PINNED_VERSION="0.43.0"
36
+ PINNED_VERSION="0.45.0"
37
37
  FORCED_METHOD=""
38
38
  USE_FALLBACK=1
39
39
  QUIET=0
@@ -94,7 +94,7 @@ If every package manager fails:
94
94
  # app-aarch64-pc-windows-msvc.zip Windows ARM64
95
95
 
96
96
  # 2. Download and extract:
97
- VERSION=0.43.0
97
+ VERSION=0.45.0
98
98
  TRIPLE=aarch64-apple-darwin
99
99
  curl -fsSL "https://github.com/ast-grep/ast-grep/releases/download/${VERSION}/app-${TRIPLE}.zip" -o /tmp/ast-grep.zip
100
100
  unzip /tmp/ast-grep.zip -d /tmp/ast-grep
@@ -125,7 +125,7 @@ Requires Rust 1.74+. Slowest path; only useful when you need a specific commit o
125
125
 
126
126
  ```bash
127
127
  ast-grep --version # or `sg --version`
128
- # ast-grep 0.43.0
128
+ # ast-grep 0.45.0
129
129
  ```
130
130
 
131
131
  Then sanity-check a real query:
@@ -49,7 +49,7 @@ fake_sg() {
49
49
  cat > "$target" <<'SH'
50
50
  #!/usr/bin/env bash
51
51
  if [ "${1:-}" = "--version" ]; then
52
- printf 'ast-grep 0.43.0 fake\n'
52
+ printf 'ast-grep 0.45.0 fake\n'
53
53
  else
54
54
  printf 'fake ast-grep\n'
55
55
  fi
@@ -1,6 +1,6 @@
1
1
  ---
2
2
  name: start-work
3
- description: "Execute a Prometheus work plan in Codex with Boulder state, evidence ledger updates, worktree discipline, parallel subagents, and Stop-hook continuation. Use after planning when the user says start work, execute plan, continue plan, resume plan, or asks to run a .omo/plans plan."
3
+ description: "Execute a Prometheus work plan with Boulder state, evidence ledger updates, worktree discipline, parallel subagents, and Stop-hook continuation. Use after planning when the user says start work, execute plan, continue plan, resume plan, or asks to run a .omo/plans plan."
4
4
  ---
5
5
 
6
6
  ## ABSOLUTE RULE: YOU ARE AN ORCHESTRATOR — NEVER THE IMPLEMENTER
@@ -22,8 +22,8 @@ When translating `load_skills=[...]`, name the skills inside the spawned agent's
22
22
 
23
23
  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 — when absent, omit it and describe the role inside `message`. If a code block below conflicts with this section, this section wins.
24
24
 
25
- ### Delegation by difficulty (Codex tier workers)
26
- When tier worker agents are installed (Codex), size each implementation lane by difficulty and pass the matching `agent_type` where the spawn schema exposes it: LOW (one-file fix, boilerplate, config/copy) -> `lazycodex-worker-low`; MEDIUM (standard feature, few files, known patterns) -> `lazycodex-worker-medium`; HIGH (new module, cross-module refactor, concurrency/security/migration) -> `lazycodex-worker-high`. Explorer/librarian research lanes keep their own roles. Difficulty (model power) is orthogonal to the LIGHT/HEAVY rigor tier in step 4 — judge each on its own facts. On spawn surfaces without `agent_type` (deployed v2), state the tier inside `message`.
25
+ ### Codex tier mapping for the delegation router
26
+ When tier worker agents are installed, map the delegation router's parenthesized difficulty to `agent_type`: (low) -> `lazycodex-worker-low`; (medium) -> `lazycodex-worker-medium`; (high) -> `lazycodex-worker-high`. Explorer/librarian research lanes keep their own roles. On spawn surfaces without `agent_type`, state the tier inside `message`. Difficulty (model power) is orthogonal to the LIGHT/HEAVY rigor tier in step 4 — judge each on its own facts.
27
27
 
28
28
  ## Codex Subagent Reliability
29
29
 
@@ -33,7 +33,7 @@ Plan and reviewer agents may run for a long time: spawn them in the background a
33
33
 
34
34
  # start-work
35
35
 
36
- Execute a Prometheus work plan until every top-level checkbox is complete. This skill pairs with the Codex `Stop` / `SubagentStop` continuation hook (`components/start-work-continuation`), which re-injects the next turn while `.omo/boulder.json` says this `codex:<session_id>` still has unchecked plan work.
36
+ Execute a Prometheus work plan until every top-level checkbox is complete. This skill pairs with the harness's start-work continuation hook, which re-injects the next turn while `.omo/boulder.json` says this `codex:<session_id>` still has unchecked plan work.
37
37
 
38
38
  ## Usage
39
39
 
@@ -97,14 +97,58 @@ Write `.omo/boulder.json` before implementation starts. Prefix session ids with
97
97
 
98
98
  For PR/branch work, a task-owned worktree is mandatory before implementation starts: pass `--worktree`, or use `--make-pr`/`--ship`, which auto-create one. Verify the path with `git worktree list --porcelain` or create it with `git worktree add <path> <branch-or-HEAD>`, then store the absolute path as `worktree_path`. All edits, commands, tests, and evidence capture must run inside that worktree.
99
99
 
100
+ ## Parallel delivery lanes (teams and worktrees)
101
+
102
+ Solo orchestration with parallel background workers is the default topology. Decide once, when the wave's lanes are known, and record the verdict in the ledger:
103
+
104
+ - **Independent lanes -> parallel workers.** Separate files, no shared contract: one parallel spawn burst; no team.
105
+ - **Overlapping lanes -> a team.** The lanes touch the same module or contract AND running them concurrently actually finishes sooner: stand up a team (where the harness has one) so one lane's discoveries relay through you mid-flight.
106
+ - **PR-mode independent lanes -> a worktree per lane.** Under `--make-pr`/`--ship`, when a wave holds independent checkboxes, give each lane its own branch and task-owned worktree, delivered as its own PR.
107
+
108
+ Landing rules, regardless of topology:
109
+
110
+ - **Merge per verified unit.** A lane lands the moment its own gates pass — it never waits for the slowest sibling. Integrate landed work back into the base the remaining lanes branch from.
111
+ - **Only the orchestrator merges.** Workers and team members never merge and never push the base branch.
112
+ - **Conflicts are the orchestrator's job.** Decide the landing order and tell the later lane what changed; a worker never resolves a sibling's conflict blind.
113
+
100
114
  ## Phase 3: Execute the next checkbox
101
115
 
102
116
  1. Read the full selected plan.
103
117
  2. Find the first unchecked column-0 checkbox in `## TODOs` or `## Final Verification Wave`.
104
118
  3. Ignore nested checkboxes under acceptance criteria, evidence, and definition-of-done sections.
105
119
  4. Classify the checkbox tier and record it in its ledger entry. Default is LIGHT — a narrow change inside existing layers. Take HEAVY only on a fact you can point to: a new module / abstraction / domain model; auth, security, or session; an external integration; a DB schema or migration; concurrency or transaction boundaries; a cross-domain refactor; or the plan or user signals care. When unsure, take HEAVY; upgrade and redo skipped gates the moment a HEAVY fact surfaces; never downgrade.
106
- 5. Decompose that checkbox into atomic sub-tasks. Collect every other unchecked checkbox in the same plan wave whose dependencies are met — their lanes execute concurrently.
107
- 6. **DELEGATE EVERYTHING. YOU NEVER IMPLEMENT.** Dispatch ALL independent sub-tasks across those checkboxes in one parallel `multi_agent_v1.spawn_agent` burst; serialize only named dependencies. Verification and checkbox marking stay per-checkbox.
120
+ 5. Decompose that checkbox into atomic sub-tasks sized for ONE worker in ONE run — a sub-task that would need mid-flight steering is two sub-tasks. Collect every other unchecked checkbox in the same plan wave whose dependencies are met — their lanes execute concurrently. A wave that could split further but holds fewer than 3 independent sub-tasks is under-split.
121
+ 6. **DELEGATE EVERYTHING. YOU NEVER IMPLEMENT.** Route every sub-task through the delegation router below, then dispatch ALL independent sub-tasks across those checkboxes in one parallel worker-spawn burst (a single batched spawn call where the harness supports it); serialize only named dependencies. Verification and checkbox marking stay per-checkbox.
122
+ 7. Give every dispatched sub-task its completion condition and watch for it per the section below. A dispatch whose completion nobody watches is an unfinished dispatch.
123
+
124
+ ### Monitor every dispatched subagent to its completion condition
125
+
126
+ A spawned worker is not fire-and-forget. For EACH subagent in the burst, name the observable state that ends its lane — the file written, the PR opened, the checkbox's gates green — and put a watcher on THAT state, never on a clock.
127
+
128
+ - **Arm one watcher per lane, at spawn time.** The worker's own completion arrives on its own as an injected notification; arm an explicit `monitor` on top of it only when the lane's completion condition lives OUTSIDE the child's final message — CI turning green, a log line, a build artifact appearing, a branch landing. Watch the state itself (`monitor` with a command that exits or emits on that condition), and keep the burst's watchers distinct so one lane firing never reads as another's.
129
+ - **NEVER poll and NEVER sleep.** No `sleep`, no timed retry loop, no re-reading the same status hoping it changed. Between waves, do independent root work or end the turn; an idle session is always woken. A single `task_output({ mode: "tail" })` peek is allowed only when a midpoint decision genuinely depends on it.
130
+ - **Tear the watcher down the instant it resolves.** The moment a monitor fires, or you discover it was armed on the WRONG condition (it watches a path the lane never touches, a pattern that can never match, a lane you already cancelled), stop it with `kill_bash` and say so in the ledger. A stale watcher re-fires on unrelated output and corrupts the next wave's verdict.
131
+ - **Then advance.** Fired watcher plus verified evidence means that lane's gates run and its checkbox closes; a mis-set watcher means re-arm it on the right condition or drop it, and continue. Never let a dead watcher hold the run open, and never treat watcher silence as a pass.
132
+
133
+ ### Delegation router — recommended task executor category
134
+
135
+ When the plan annotates a todo with `Recommended task executor category:`, follow that annotation; deviate only for a reason recorded in the ledger entry. Otherwise route by shape, in the omo category vocabulary (category-capable harnesses pass it directly on the worker-spawn tool, e.g. `task(category="quick", ...)`; others map the parenthesized difficulty):
136
+
137
+ | Category | Route here |
138
+ | --- | --- |
139
+ | `quick` (low) | mechanical, single-file, boilerplate, config/copy — the default for every splittable piece |
140
+ | `unspecified-low` (low) | small tasks that fit no other category |
141
+ | `unspecified-high` (medium) | standard features across a few files with known patterns |
142
+ | `visual-engineering` (medium) | frontend, UI/UX, styling, animation |
143
+ | `writing` (low) | documentation and prose |
144
+ | `git` (low) | git operations |
145
+ | `deep` (high) | hairy debugging, research-heavy or subtle cross-module work |
146
+ | `ultrabrain` (high) | ONE genuinely hard, logic-heavy problem — hand it the goal, not step-by-step instructions |
147
+
148
+ Sizing is a two-branch decision made per checkbox, before dispatch:
149
+
150
+ - **Splittable work splits.** When the checkbox decomposes into independent pieces, dispatch them as a swarm of `quick`/`unspecified-low` workers in ONE parallel burst — many small cheap workers in parallel beat one large delegation.
151
+ - **Cohesive hard work stays whole.** When splitting would sever shared reasoning (one algorithm, one migration, one subtle bug), send the WHOLE problem to `deep` or `ultrabrain` as ONE delegation. Never force-split work whose parts share one insight.
108
152
 
109
153
  Each sub-task message must include:
110
154
 
@@ -115,11 +159,12 @@ Each sub-task message must include:
115
159
  5. One Manual-QA channel, named with the exact tool and exact invocation (the literal `curl`, `send-keys`, `browser:control-in-app-browser` action, `page.click`, payload, selectors, and the binary observable that decides PASS/FAIL), not "verify it works". A LIGHT checkbox needs one real-surface proof of its deliverable, and auxiliary surfaces (CLI stdout, DB state diff, parsed config dump) are first-class when the surface is CLI- or data-shaped:
116
160
  - HTTP call: `curl -i` against the live endpoint.
117
161
  - Terminal / TUI: drive a real pty; `tmux send-keys` is fine for a boot/behavior smoke, but color/layout/CJK evidence goes through the xterm.js web terminal below, NEVER `tmux capture-pane`.
118
- - Browser use: in Codex, use `browser:control-in-app-browser` first when available and the scenario does not need an authenticated or persistent user browser profile; otherwise drive the real page with Chrome, or agent-browser (https://github.com/vercel-labs/agent-browser) when Chrome is unavailable.
162
+ - Browser use: prefer the harness's in-app browser control when available and the scenario does not need an authenticated or persistent user browser profile; otherwise drive the real page with Chrome, or agent-browser (https://github.com/vercel-labs/agent-browser) when Chrome is unavailable.
119
163
  - Computer use: OS-level GUI automation against the running desktop app when the surface is not a page.
120
164
  - TUI visual evidence: when a TUI claim needs visual QA or PR proof, run `node script/qa/web-terminal-visual-qa.mjs --command "<cmd>" --input "{Enter}" --evidence-dir <dir>` (real pty rendered through xterm.js in Chrome) and attach `terminal.png` plus `metadata.json`.
121
165
  6. The adversarial classes that apply to this sub-task (from the 9 ultraqa classes) and how each is probed.
122
166
  7. Required artifact path and cleanup receipt.
167
+ 8. Tool-use expectations: batch independent tool calls in parallel; when the harness exposes a code-execution surface (eval), use it for multi-call steps instead of one-by-one calls.
123
168
 
124
169
  The 9 ultraqa classes are trigger-mapped: new input parsing → malformed input; untrusted external text → prompt injection; resumable or long-running flows → cancel/resume; generated or cached artifacts → stale state; uncommitted user files in scope → dirty worktree; long external commands → hung or long commands; new or timing-sensitive tests → flaky tests; log-based success claims → misleading success output; mid-operation interrupts → repeated interruptions. A class applies when its trigger fact holds. Probe each applicable class; record the rest as not-applicable with a one-line reason.
125
170
 
@@ -160,7 +205,7 @@ A worker done claim is never final: each implementation sub-task returns a `Done
160
205
 
161
206
  Rules:
162
207
  - `confirmed` is the only pass verdict. `false-positive`, `needs-fix`, and `needs-human-review` all block checkbox completion.
163
- - The verifier must be independent from the executor: use `lazycodex-gate-reviewer`, a scoped `worker` reviewer, or root only when root did not implement or materially rewrite that task.
208
+ - The verifier must be independent from the executor: use the harness's gate reviewer (see the harness compatibility section) or a fresh reviewer worker on a strong model, or root only when root did not implement or materially rewrite that task.
164
209
  - A worker done claim must be independently verified before it becomes checkbox completion.
165
210
  - On any non-confirmed verdict, append the feedback to the ledger, reset the checkbox work to in-progress, and re-dispatch the executor with the exact failure.
166
211
  - The verifier must probe the applicable adversarial keys, including `stale_state`, `dirty_worktree`, and `misleading_success_output`, before allowing `FullyDone`.
@@ -191,5 +236,5 @@ When all top-level checkboxes in `## TODOs` and `## Final Verification Wave` are
191
236
  - **NO DIRECT IMPLEMENTATION BY THE ORCHESTRATOR.** Root NEVER edits product files, writes tests, or runs QA itself — a spawned worker does.
192
237
  - No completion claim while an applicable ultraqa adversarial class was never probed. Each applicable class needs a captured observable result; each skipped class needs a one-line not-applicable reason in the ledger.
193
238
  - No PR/branch implementation, review, or merge in the main worktree; use the task-owned git worktree.
194
- - No unprefixed session ids in Boulder state. Codex sessions are always `codex:<session_id>`.
239
+ - No unprefixed session ids in Boulder state. Sessions are always recorded as `codex:<session_id>`.
195
240
  - No stale-memory execution. The plan and ledger are the durable source of truth.
@@ -37,7 +37,7 @@ Read the matching reference before acting: [`references/insane-search/README.md`
37
37
  ## Tier 1 — insane-search (headless extraction)
38
38
 
39
39
  **When**: content extraction, blocked-URL bypass, media metadata — no browser UI needed.
40
- **Why first**: ~10x faster than a browser, no process spin-up; handles most "fetch this blocked page" requests via curl_cffi TLS impersonation, yt-dlp (1858 sites), Jina Reader, official public APIs, mobile URL transforms, and a Playwright real-Chrome fallback. The engine lives **inside this skill** at `engine/` and is invoked as a module.
40
+ **Why first**: ~10x faster than a browser, no process spin-up; handles most "fetch this blocked page" requests via curl_cffi TLS impersonation, yt-dlp (1858 sites), official public APIs, mobile URL transforms, **Phase-2.5 surrogate archives** (Wayback / archive.today snapshots, provenance-tagged — see [`references/insane-search/cache-archive.md`](references/insane-search/cache-archive.md)), a key-gated Jina Reader (`JINA_API_KEY`), and a Playwright real-Chrome fallback. The engine lives **inside this skill** at `engine/` and is invoked as a module. Surrogate results are dated COPIES: a result whose `provenance` is `snapshot` must be reported with its `snapshot_timestamp`, never presented as the live page.
41
41
 
42
42
  ```bash
43
43
  # Core command — auto-detects WAF, runs the full fetch grid (run from the skill dir):
@@ -60,7 +60,7 @@ The full engine harness (rules R1-R7, the Phase 0 official-API index, the no-sit
60
60
 
61
61
  ## Tier 1.5 — agent-reach (platform-native readers)
62
62
 
63
- **When**: the target is a platform with a first-class API/CLI that beats generic fetching — especially Chinese platforms that stealth browsers still cannot reach cleanly. Several channels are zero-config (Douyin, Weibo via Jina, V2EX, Reddit, Jina Reader, RSS, YouTube); others need a one-time auth you supply via environment variables if you have access.
63
+ **When**: the target is a platform with a first-class API/CLI that beats generic fetching — especially Chinese platforms that stealth browsers still cannot reach cleanly. Several channels are zero-config (Douyin, V2EX, Reddit, RSS, YouTube); others need a one-time auth you supply via environment variables if you have access (`JINA_API_KEY` for Jina Reader — anonymous access is dead, see `references/insane-search/jina.md`; `TWITTER_*` for X; a transcription key for podcasts).
64
64
 
65
65
  | Category | Platforms | Entry |
66
66
  |---|---|---|
@@ -39,6 +39,10 @@ def build_parser() -> argparse.ArgumentParser:
39
39
  help="Upper bound across all phases (default 12).")
40
40
  p.add_argument("--no-playwright", action="store_true",
41
41
  help="Skip Playwright fallback (curl-only).")
42
+ p.add_argument("--allow-proxy", action="store_true",
43
+ help=("Enable kind=proxy surrogate entries (raw relay routes; "
44
+ "MITM by construction — never citable alone, never "
45
+ "receives cookies/auth headers). Off by default."))
42
46
  p.add_argument("--json", action="store_true",
43
47
  help="Emit FetchResult as JSON to stdout (content omitted).")
44
48
  p.add_argument("--trace", action="store_true",
@@ -56,6 +60,7 @@ def main(argv: list[str] | None = None) -> int:
56
60
  timeout=args.timeout,
57
61
  max_attempts=args.max_attempts,
58
62
  enable_playwright=not args.no_playwright,
63
+ allow_surrogate_proxy=args.allow_proxy,
59
64
  )
60
65
  except Exception as e:
61
66
  print(f"engine fatal: {type(e).__name__}: {e}", file=sys.stderr)
@@ -96,7 +101,9 @@ def main(argv: list[str] | None = None) -> int:
96
101
  # Default: HTML to stdout, status to stderr.
97
102
  print(result.content, end="")
98
103
  print(f"\n[engine] ok={result.ok} verdict={result.verdict} "
99
- f"profile={result.profile_used} attempts={len(result.trace)}",
104
+ f"profile={result.profile_used} attempts={len(result.trace)} "
105
+ f"provenance={result.provenance}"
106
+ + (f" snapshot_ts={result.snapshot_timestamp}" if result.snapshot_timestamp else ""),
100
107
  file=sys.stderr)
101
108
 
102
109
  return 0 if result.ok else 1
@@ -54,6 +54,14 @@ URL_ALLOWLIST = {
54
54
  "www.google.com", "google.com",
55
55
  # Generic HTTP test endpoint for infrastructure / transport tests.
56
56
  "httpbin.org",
57
+ # Surrogate-tier infrastructure (engine/surrogates.yaml): archives/relays
58
+ # that serve a copy of ANY target URL. Same no-site-preference category as
59
+ # the google.com Referer — they are not target sites.
60
+ "archive.org", "web.archive.org",
61
+ "r.jina.ai",
62
+ # Placeholder host in the proxy-entry shape example; "canonical non-routable
63
+ # doc domain" (.invalid TLD), can never be a real target.
64
+ "relay.invalid",
57
65
  }
58
66
 
59
67
  # Files / dirs that must be clean.
@@ -80,6 +88,9 @@ EXPLICIT_ALLOW_FILES = {
80
88
  # None right now — add if needed with justification.
81
89
  }
82
90
 
91
+ # NOTE-BIAS-OK convention for surrogate tests: fixture URLs (stub/interstitial
92
+ # captures from third-party services) carry the marker on the flagged line.
93
+
83
94
 
84
95
  def _line_is_exempt(line: str, ext: str) -> bool:
85
96
  markers = COMMENT_OK_MARKERS.get(ext, ())
@@ -40,6 +40,7 @@ def fetch(
40
40
  timeout: int = 25,
41
41
  max_attempts: int = 12,
42
42
  enable_playwright: bool = True, # hook left for executor module
43
+ allow_surrogate_proxy: bool = False, # opt-in: kind=proxy registry entries
43
44
  ) -> FetchResult:
44
45
  """Fetch `url` using the generic grid.
45
46
 
@@ -175,73 +176,110 @@ def fetch(
175
176
  if att.verdict in (Verdict.STRONG_OK.value, Verdict.WEAK_OK.value):
176
177
  return _build_result(resp, att, trace, profile_used=profile_id)
177
178
 
178
- # -------- Phase 3: Playwright fallback (profile-driven order) -----------
179
- if enable_playwright:
180
- try:
181
- from .executor import run_playwright_fallback # lazy import
182
- # Honour profile's `fallback_when_challenge` list — iterate the
183
- # caller-declared order instead of capability-inferred single pick.
184
- fb_profile = load_profile(profile_used or "unknown_challenge", profiles=profiles)
185
- fb_order = fb_profile.get("fallback_when_challenge") or ["playwright_real_chrome"]
186
- pw_attempt = None
187
- pw_content = ""
188
- for fb_name in fb_order:
189
- if fb_name == "curl_grid_exhaust":
190
- # Already performed in Phase 2; nothing more to do here.
191
- continue
192
- pw_attempt, pw_content = run_playwright_fallback(
179
+ # -------- Phase 2.5 + 3: fallback ladder (profile-driven order) ---------
180
+ # Surrogate routes are NOT browser work, so they run even when the caller
181
+ # disabled Playwright; only browser executors honour `enable_playwright`.
182
+ try:
183
+ # Honour profile's `fallback_when_challenge` list — iterate the
184
+ # caller-declared order instead of capability-inferred single pick.
185
+ fb_profile = load_profile(profile_used or "unknown_challenge", profiles=profiles)
186
+ fb_order = fb_profile.get("fallback_when_challenge") or ["playwright_real_chrome"]
187
+ pw_attempt = None
188
+ pw_content = ""
189
+ for fb_name in fb_order:
190
+ if fb_name == "curl_grid_exhaust":
191
+ # Already performed in Phase 2; nothing more to do here.
192
+ continue
193
+ if fb_name.startswith("surrogate_"):
194
+ # Phase 2.5: archive/reader/proxy routes serving a copy of
195
+ # the target. Cheaper than a browser; provenance-labeled.
196
+ from . import surrogate as surrogate_mod
197
+ s_atts, s_meta, s_content = surrogate_mod.run_surrogate(
193
198
  url,
194
- profile_id=profile_used or "unknown_challenge",
199
+ registry=surrogate_mod.load_surrogates(),
200
+ allow_proxy=allow_surrogate_proxy,
201
+ timeout=timeout,
195
202
  success_selectors=success_selectors,
196
- device_class=device_class,
197
- force_executor=fb_name,
198
203
  )
199
- trace.append(pw_attempt)
200
- if pw_attempt.verdict in (Verdict.STRONG_OK.value, Verdict.WEAK_OK.value):
204
+ trace.extend(s_atts)
205
+ s_att = s_atts[-1]
206
+ if s_att.verdict in (Verdict.STRONG_OK.value, Verdict.WEAK_OK.value):
201
207
  return FetchResult(
202
208
  ok=True,
203
- content=pw_content,
204
- final_url=pw_attempt.url,
205
- verdict=pw_attempt.verdict,
209
+ content=s_content,
210
+ final_url=s_att.url,
211
+ verdict=s_att.verdict,
206
212
  profile_used=profile_used,
207
213
  trace=trace,
208
- summary=f"Playwright fallback succeeded via {fb_name}",
214
+ summary=(
215
+ f"surrogate {s_meta.get('surrogate')} succeeded"
216
+ f" (provenance={s_meta.get('provenance')}"
217
+ + (f" snapshot_ts={s_meta.get('snapshot_timestamp')})" if s_meta.get('snapshot_timestamp') else ")")
218
+ ),
219
+ provenance=str(s_meta.get("provenance", "live")),
220
+ snapshot_timestamp=s_meta.get("snapshot_timestamp"),
221
+ trust=str(s_meta.get("trust", "origin")),
209
222
  )
210
- # Synthesize a placeholder if no iteration ran (empty list).
211
- if pw_attempt is None:
212
- pw_attempt = Attempt(
213
- phase="fallback",
214
- executor="none",
215
- url=url,
216
- url_transform="original",
217
- impersonate=None,
218
- referer="",
219
- verdict=Verdict.UNKNOWN.value,
220
- error="profile has empty fallback_when_challenge",
223
+ continue
224
+ if not enable_playwright:
225
+ continue
226
+ from .executor import run_playwright_fallback # lazy import
227
+ pw_attempt, pw_content = run_playwright_fallback(
228
+ url,
229
+ profile_id=profile_used or "unknown_challenge",
230
+ success_selectors=success_selectors,
231
+ device_class=device_class,
232
+ force_executor=fb_name,
233
+ )
234
+ trace.append(pw_attempt)
235
+ if pw_attempt.verdict in (Verdict.STRONG_OK.value, Verdict.WEAK_OK.value):
236
+ return FetchResult(
237
+ ok=True,
238
+ content=pw_content,
239
+ final_url=pw_attempt.url,
240
+ verdict=pw_attempt.verdict,
241
+ profile_used=profile_used,
242
+ trace=trace,
243
+ summary=f"Playwright fallback succeeded via {fb_name}",
221
244
  )
222
- trace.append(pw_attempt)
223
- except ImportError:
224
- trace.append(Attempt(
245
+ # Synthesize a placeholder only when the profile genuinely offers no
246
+ # fallback route. Entries skipped because the caller disabled the
247
+ # browser are a caller choice, not a profile defect — no trace noise.
248
+ actionable = [n for n in fb_order if n != "curl_grid_exhaust"]
249
+ if pw_attempt is None and not actionable:
250
+ pw_attempt = Attempt(
225
251
  phase="fallback",
226
- executor="playwright",
252
+ executor="none",
227
253
  url=url,
228
254
  url_transform="original",
229
255
  impersonate=None,
230
256
  referer="",
231
257
  verdict=Verdict.UNKNOWN.value,
232
- error="executor module not available",
233
- ))
234
- except (RuntimeError, OSError) as e:
235
- trace.append(Attempt(
236
- phase="fallback",
237
- executor="playwright",
238
- url=url,
239
- url_transform="original",
240
- impersonate=None,
241
- referer="",
242
- verdict=Verdict.UNKNOWN.value,
243
- error=f"{type(e).__name__}:{str(e)[:200]}",
244
- ))
258
+ error="profile has empty fallback_when_challenge",
259
+ )
260
+ trace.append(pw_attempt)
261
+ except ImportError:
262
+ trace.append(Attempt(
263
+ phase="fallback",
264
+ executor="playwright",
265
+ url=url,
266
+ url_transform="original",
267
+ impersonate=None,
268
+ referer="",
269
+ verdict=Verdict.UNKNOWN.value,
270
+ error="executor module not available",
271
+ ))
272
+ except (RuntimeError, OSError) as e:
273
+ trace.append(Attempt(
274
+ phase="fallback",
275
+ executor="playwright",
276
+ url=url,
277
+ url_transform="original",
278
+ impersonate=None,
279
+ referer="",
280
+ verdict=Verdict.UNKNOWN.value,
281
+ error=f"{type(e).__name__}:{str(e)[:200]}",
282
+ ))
245
283
 
246
284
  # -------- Give up, return best we have ----------------------------------
247
285
  summary = format_summary(trace, profile_used)
@@ -1,7 +1,10 @@
1
1
  from __future__ import annotations
2
2
 
3
3
  from dataclasses import asdict, dataclass, field
4
- from typing import Optional
4
+ from typing import Literal, Optional
5
+
6
+ Provenance = Literal["live", "snapshot", "proxy"]
7
+ Trust = Literal["origin", "archive", "untrusted"]
5
8
 
6
9
 
7
10
  @dataclass
@@ -32,6 +35,9 @@ class FetchResult:
32
35
  profile_used: Optional[str] = None
33
36
  trace: list[Attempt] = field(default_factory=list)
34
37
  summary: str = ""
38
+ provenance: str = "live" # live | snapshot | proxy
39
+ snapshot_timestamp: Optional[str] = None # archive's own timestamp, when snapshot
40
+ trust: str = "origin" # origin | archive | untrusted
35
41
 
36
42
  def to_dict(self) -> dict:
37
43
  return {
@@ -41,5 +47,8 @@ class FetchResult:
41
47
  "profile_used": self.profile_used,
42
48
  "trace": [a.to_dict() for a in self.trace],
43
49
  "summary": self.summary,
50
+ "provenance": self.provenance,
51
+ "snapshot_timestamp": self.snapshot_timestamp,
52
+ "trust": self.trust,
44
53
  "content_length": len(self.content),
45
54
  }