oh-my-opencode 4.12.0 → 4.13.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +1 -1
- package/THIRD-PARTY-NOTICES.md +1 -1
- package/dist/agents/sisyphus-agent-factory.d.ts +9 -0
- package/dist/agents/sisyphus-runtime-prompt-reconciler.d.ts +31 -0
- package/dist/cli/index.js +916 -670
- package/dist/cli-node/index.js +916 -670
- package/dist/config/schema/codegraph.d.ts +1 -0
- package/dist/config/schema/oh-my-opencode-config.d.ts +2 -0
- package/dist/config/schema/runtime-fallback.d.ts +1 -0
- package/dist/features/background-agent/background-task-marker.d.ts +8 -0
- package/dist/features/background-agent/fallback-retry-handler.d.ts +1 -0
- package/dist/features/background-agent/manager.d.ts +1 -0
- package/dist/features/background-agent/parent-wake-dedupe.d.ts +1 -0
- package/dist/features/background-agent/parent-wake-notifier-types.d.ts +2 -0
- package/dist/features/background-agent/parent-wake-notifier.d.ts +1 -0
- package/dist/features/background-agent/parent-wake-window-recovery.d.ts +2 -0
- package/dist/hooks/runtime-fallback/auto-retry-dispatch.d.ts +2 -2
- package/dist/hooks/runtime-fallback/auto-retry-timeout.d.ts +2 -2
- package/dist/hooks/runtime-fallback/auto-retry.d.ts +1 -1
- package/dist/hooks/runtime-fallback/fallback-state-snapshot.d.ts +13 -0
- package/dist/hooks/runtime-fallback/types.d.ts +8 -0
- package/dist/index.js +1042 -640
- package/dist/oh-my-opencode.schema.json +8 -0
- package/dist/plugin/runtime-skill-resolver.d.ts +35 -0
- package/dist/plugin/skill-context.d.ts +9 -0
- package/dist/skills/frontend/ATTRIBUTION.md +32 -8
- package/dist/skills/frontend/references/design/airbnb.md +3 -0
- package/dist/skills/frontend/references/design/airtable.md +3 -0
- package/dist/skills/frontend/references/design/apple.md +3 -0
- package/dist/skills/frontend/references/design/binance.md +3 -0
- package/dist/skills/frontend/references/design/bmw.md +3 -0
- package/dist/skills/frontend/references/design/bugatti.md +3 -0
- package/dist/skills/frontend/references/design/cal.md +3 -0
- package/dist/skills/frontend/references/design/claude.md +3 -0
- package/dist/skills/frontend/references/design/clay.md +3 -0
- package/dist/skills/frontend/references/design/clickhouse.md +3 -0
- package/dist/skills/frontend/references/design/cohere.md +3 -0
- package/dist/skills/frontend/references/design/coinbase.md +3 -0
- package/dist/skills/frontend/references/design/composio.md +3 -0
- package/dist/skills/frontend/references/design/cursor.md +3 -0
- package/dist/skills/frontend/references/design/elevenlabs.md +3 -0
- package/dist/skills/frontend/references/design/expo.md +3 -0
- package/dist/skills/frontend/references/design/ferrari.md +3 -0
- package/dist/skills/frontend/references/design/figma.md +3 -0
- package/dist/skills/frontend/references/design/framer.md +3 -0
- package/dist/skills/frontend/references/design/hashicorp.md +3 -0
- package/dist/skills/frontend/references/design/ibm.md +3 -0
- package/dist/skills/frontend/references/design/imagegen-frontend-web.md +380 -79
- package/dist/skills/frontend/references/design/intercom.md +3 -0
- package/dist/skills/frontend/references/design/kraken.md +3 -0
- package/dist/skills/frontend/references/design/lamborghini.md +3 -0
- package/dist/skills/frontend/references/design/linear.app.md +3 -0
- package/dist/skills/frontend/references/design/lovable.md +3 -0
- package/dist/skills/frontend/references/design/mastercard.md +3 -0
- package/dist/skills/frontend/references/design/meta.md +3 -0
- package/dist/skills/frontend/references/design/minimax.md +3 -0
- package/dist/skills/frontend/references/design/mintlify.md +3 -0
- package/dist/skills/frontend/references/design/miro.md +3 -0
- package/dist/skills/frontend/references/design/mistral.ai.md +3 -0
- package/dist/skills/frontend/references/design/mongodb.md +3 -0
- package/dist/skills/frontend/references/design/nike.md +3 -0
- package/dist/skills/frontend/references/design/notion.md +3 -0
- package/dist/skills/frontend/references/design/nvidia.md +3 -0
- package/dist/skills/frontend/references/design/ollama.md +3 -0
- package/dist/skills/frontend/references/design/opencode.ai.md +3 -0
- package/dist/skills/frontend/references/design/pinterest.md +3 -0
- package/dist/skills/frontend/references/design/playstation.md +3 -0
- package/dist/skills/frontend/references/design/posthog.md +3 -0
- package/dist/skills/frontend/references/design/raycast.md +3 -0
- package/dist/skills/frontend/references/design/renault.md +3 -0
- package/dist/skills/frontend/references/design/replicate.md +3 -0
- package/dist/skills/frontend/references/design/resend.md +3 -0
- package/dist/skills/frontend/references/design/revolut.md +3 -0
- package/dist/skills/frontend/references/design/runwayml.md +3 -0
- package/dist/skills/frontend/references/design/sanity.md +3 -0
- package/dist/skills/frontend/references/design/sentry.md +3 -0
- package/dist/skills/frontend/references/design/shopify.md +3 -0
- package/dist/skills/frontend/references/design/spacex.md +3 -0
- package/dist/skills/frontend/references/design/spotify.md +3 -0
- package/dist/skills/frontend/references/design/starbucks.md +3 -0
- package/dist/skills/frontend/references/design/stitch-skill.md +1 -1
- package/dist/skills/frontend/references/design/stripe.md +3 -0
- package/dist/skills/frontend/references/design/supabase.md +3 -0
- package/dist/skills/frontend/references/design/superhuman.md +3 -0
- package/dist/skills/frontend/references/design/taste-skill.md +1188 -208
- package/dist/skills/frontend/references/design/tesla.md +3 -0
- package/dist/skills/frontend/references/design/theverge.md +3 -0
- package/dist/skills/frontend/references/design/together.ai.md +3 -0
- package/dist/skills/frontend/references/design/uber.md +3 -0
- package/dist/skills/frontend/references/design/vercel.md +3 -0
- package/dist/skills/frontend/references/design/vodafone.md +3 -0
- package/dist/skills/frontend/references/design/voltagent.md +3 -0
- package/dist/skills/frontend/references/design/warp.md +3 -0
- package/dist/skills/frontend/references/design/webflow.md +3 -0
- package/dist/skills/frontend/references/design/wired.md +3 -0
- package/dist/skills/frontend/references/design/wise.md +3 -0
- package/dist/skills/frontend/references/design/x.ai.md +3 -0
- package/dist/skills/frontend/references/design/zapier.md +3 -0
- package/dist/skills/frontend/references/ui-ux-db/README.md +501 -115
- package/dist/skills/frontend/references/ui-ux-db/data/charts.csv +26 -26
- package/dist/skills/frontend/references/ui-ux-db/data/colors.csv +162 -97
- package/dist/skills/frontend/references/ui-ux-db/data/icons.csv +105 -100
- package/dist/skills/frontend/references/ui-ux-db/data/landing.csv +22 -18
- package/dist/skills/frontend/references/ui-ux-db/data/products.csv +162 -97
- package/dist/skills/frontend/references/ui-ux-db/data/stacks/flutter.csv +53 -53
- package/dist/skills/frontend/references/ui-ux-db/data/stacks/html-tailwind.csv +56 -56
- package/dist/skills/frontend/references/ui-ux-db/data/stacks/nextjs.csv +53 -53
- package/dist/skills/frontend/references/ui-ux-db/data/stacks/react.csv +54 -54
- package/dist/skills/frontend/references/ui-ux-db/data/stacks/svelte.csv +54 -54
- package/dist/skills/frontend/references/ui-ux-db/data/stacks/swiftui.csv +51 -51
- package/dist/skills/frontend/references/ui-ux-db/data/stacks/vue.csv +50 -50
- package/dist/skills/frontend/references/ui-ux-db/data/styles.csv +17 -0
- package/dist/skills/frontend/references/ui-ux-db/data/typography.csv +17 -1
- package/dist/skills/frontend/references/ui-ux-db/data/ui-reasoning.csv +162 -101
- package/dist/skills/frontend/references/ui-ux-db/data/web-interface.csv +30 -30
- package/dist/skills/frontend/references/ui-ux-db/scripts/core.py +31 -22
- package/dist/skills/frontend/references/ui-ux-db/scripts/design_system.py +150 -69
- package/dist/skills/frontend/references/ui-ux-db/scripts/search.py +3 -3
- package/dist/skills/lcx-doctor/SKILL.md +1 -1
- package/dist/skills/ultimate-browsing/ATTRIBUTION.md +105 -0
- package/dist/skills/ultimate-browsing/SKILL.md +140 -0
- package/dist/skills/ultimate-browsing/engine/__init__.py +24 -0
- package/dist/skills/ultimate-browsing/engine/__main__.py +106 -0
- package/dist/skills/ultimate-browsing/engine/bias_check.py +174 -0
- package/dist/skills/ultimate-browsing/engine/curl_probe.py +91 -0
- package/dist/skills/ultimate-browsing/engine/executor.py +192 -0
- package/dist/skills/ultimate-browsing/engine/fetch_chain.py +268 -0
- package/dist/skills/ultimate-browsing/engine/referers.py +15 -0
- package/dist/skills/ultimate-browsing/engine/result_schema.py +45 -0
- package/dist/skills/ultimate-browsing/engine/summary.py +37 -0
- package/dist/skills/ultimate-browsing/engine/templates/package.json +11 -0
- package/dist/skills/ultimate-browsing/engine/templates/playwright_mobile_chrome.js +129 -0
- package/dist/skills/ultimate-browsing/engine/templates/playwright_real_chrome.js +167 -0
- package/dist/skills/ultimate-browsing/engine/tests/test_fetch_chain.py +77 -0
- package/dist/skills/ultimate-browsing/engine/tests/test_playwright_templates.py +282 -0
- package/dist/skills/ultimate-browsing/engine/url_transforms.py +98 -0
- package/dist/skills/ultimate-browsing/engine/validators.py +216 -0
- package/dist/skills/ultimate-browsing/engine/waf_detector.py +214 -0
- package/dist/skills/ultimate-browsing/engine/waf_profiles.yaml +162 -0
- package/dist/skills/ultimate-browsing/references/agent-reach/README.md +79 -0
- package/dist/skills/ultimate-browsing/references/agent-reach/career.md +29 -0
- package/dist/skills/ultimate-browsing/references/agent-reach/dev.md +62 -0
- package/dist/skills/ultimate-browsing/references/agent-reach/search.md +33 -0
- package/dist/skills/ultimate-browsing/references/agent-reach/social.md +207 -0
- package/dist/skills/ultimate-browsing/references/agent-reach/video.md +115 -0
- package/dist/skills/ultimate-browsing/references/agent-reach/web.md +76 -0
- package/dist/skills/ultimate-browsing/references/chrome-stealth.md +120 -0
- package/dist/skills/ultimate-browsing/references/insane-search/README.md +319 -0
- package/dist/skills/ultimate-browsing/references/insane-search/cache-archive.md +83 -0
- package/dist/skills/ultimate-browsing/references/insane-search/fallback.md +159 -0
- package/dist/skills/ultimate-browsing/references/insane-search/jina.md +130 -0
- package/dist/skills/ultimate-browsing/references/insane-search/json-api.md +133 -0
- package/dist/skills/ultimate-browsing/references/insane-search/media.md +123 -0
- package/dist/skills/ultimate-browsing/references/insane-search/metadata.md +116 -0
- package/dist/skills/ultimate-browsing/references/insane-search/naver.md +107 -0
- package/dist/skills/ultimate-browsing/references/insane-search/playwright.md +142 -0
- package/dist/skills/ultimate-browsing/references/insane-search/public-api.md +119 -0
- package/dist/skills/ultimate-browsing/references/insane-search/rss.md +123 -0
- package/dist/skills/ultimate-browsing/references/insane-search/tls-impersonate.md +186 -0
- package/dist/skills/ultimate-browsing/references/insane-search/twitter.md +104 -0
- package/dist/skills/ultimate-browsing/scripts/cookie_crypto.py +75 -0
- package/dist/skills/ultimate-browsing/scripts/cookie_domains.py +38 -0
- package/dist/skills/ultimate-browsing/scripts/cookie_paths.py +112 -0
- package/dist/skills/ultimate-browsing/scripts/extract_cookies.py +280 -0
- package/dist/skills/ultimate-browsing/scripts/tests/test_cookie_domain_filter.py +110 -0
- package/dist/skills/ultimate-browsing/scripts/tests/test_extract_cookies.py +245 -0
- package/dist/skills/ultraresearch/ATTRIBUTION.md +49 -0
- package/dist/skills/ultraresearch/SKILL.md +34 -6
- package/dist/skills/ulw-plan/SKILL.md +4 -1
- package/dist/tools/background-task/constants.d.ts +1 -1
- package/dist/tools/delegate-task/sync-task-deps.d.ts +8 -6
- package/dist/tools/skill-mcp/tools.d.ts +1 -1
- package/dist/tui.js +18 -4
- package/package.json +16 -14
- package/packages/omo-codex/THIRD-PARTY-NOTICES.md +27 -4
- package/packages/omo-codex/plugin/.codex-plugin/plugin.json +3 -1
- package/packages/omo-codex/plugin/README.md +1 -1
- package/packages/omo-codex/plugin/components/bootstrap/dist/cli.js +134 -42
- package/packages/omo-codex/plugin/components/bootstrap/package.json +1 -1
- package/packages/omo-codex/plugin/components/codegraph/LICENSE +21 -0
- package/packages/omo-codex/plugin/components/codegraph/NODE-RUNTIME-LICENSES.md +2951 -0
- package/packages/omo-codex/plugin/components/codegraph/NOTICE +16 -0
- package/packages/omo-codex/plugin/components/codegraph/dist/cli.js +633 -193
- package/packages/omo-codex/plugin/components/codegraph/dist/serve.js +561 -44
- package/packages/omo-codex/plugin/components/codegraph/package.json +9 -3
- package/packages/omo-codex/plugin/components/codegraph/src/cli.ts +11 -0
- package/packages/omo-codex/plugin/components/codegraph/src/hook-types.ts +12 -0
- package/packages/omo-codex/plugin/components/codegraph/src/hook.ts +34 -0
- package/packages/omo-codex/plugin/components/codegraph/src/mcp-unavailable.ts +75 -0
- package/packages/omo-codex/plugin/components/codegraph/src/serve.ts +66 -13
- package/packages/omo-codex/plugin/components/codegraph/src/session-start-worker.ts +26 -12
- package/packages/omo-codex/plugin/components/codegraph/test/hook.test.ts +50 -330
- package/packages/omo-codex/plugin/components/codegraph/test/package-runtime.test.ts +91 -0
- package/packages/omo-codex/plugin/components/codegraph/test/provisioned-node-guard.test.ts +2 -2
- package/packages/omo-codex/plugin/components/codegraph/test/serve-mcp-facade.test.ts +68 -0
- package/packages/omo-codex/plugin/components/codegraph/test/serve-node-support.test.ts +11 -1
- package/packages/omo-codex/plugin/components/codegraph/test/serve-provision.test.ts +48 -0
- package/packages/omo-codex/plugin/components/codegraph/test/serve-unavailable.test.ts +133 -0
- package/packages/omo-codex/plugin/components/codegraph/test/serve.test.ts +1 -112
- package/packages/omo-codex/plugin/components/codegraph/test/session-start-node-support.test.ts +149 -0
- package/packages/omo-codex/plugin/components/codegraph/test/session-start-trust-boundary.test.ts +63 -0
- package/packages/omo-codex/plugin/components/codegraph/test/session-start-worker-availability.test.ts +106 -0
- package/packages/omo-codex/plugin/components/codegraph/test/session-start-worker-flow.test.ts +150 -0
- package/packages/omo-codex/plugin/components/comment-checker/package.json +1 -1
- package/packages/omo-codex/plugin/components/git-bash/package.json +1 -1
- package/packages/omo-codex/plugin/components/lazycodex-executor-verify/package.json +1 -1
- package/packages/omo-codex/plugin/components/lsp/package.json +1 -1
- package/packages/omo-codex/plugin/components/rules/dist/cli.js +3 -3
- package/packages/omo-codex/plugin/components/rules/package.json +1 -1
- package/packages/omo-codex/plugin/components/rules/src/sparkshell-awareness.ts +3 -3
- package/packages/omo-codex/plugin/components/rules/test/sparkshell-awareness.test.ts +33 -9
- package/packages/omo-codex/plugin/components/start-work-continuation/package.json +1 -1
- package/packages/omo-codex/plugin/components/teammode/dist/cli.js +94 -0
- package/packages/omo-codex/plugin/components/teammode/hooks/hooks.json +17 -0
- package/packages/omo-codex/plugin/components/teammode/package.json +26 -0
- package/packages/omo-codex/plugin/components/teammode/skills/teammode/SKILL.md +59 -32
- package/packages/omo-codex/plugin/components/teammode/skills/teammode/scripts/team-guide.mjs +17 -16
- package/packages/omo-codex/plugin/components/teammode/skills/teammode/scripts/team-state.mjs +70 -3
- package/packages/omo-codex/plugin/components/teammode/skills/teammode/scripts/team-worktree.mjs +113 -0
- package/packages/omo-codex/plugin/components/teammode/skills/teammode/scripts/team.mjs +63 -4
- package/packages/omo-codex/plugin/components/teammode/src/cli.ts +12 -0
- package/packages/omo-codex/plugin/components/teammode/src/codex-hook.ts +125 -0
- package/packages/omo-codex/plugin/components/teammode/test/thread-title-hook.test.ts +116 -0
- package/packages/omo-codex/plugin/components/teammode/tsconfig.json +25 -0
- package/packages/omo-codex/plugin/components/telemetry/package.json +1 -1
- package/packages/omo-codex/plugin/components/ultrawork/agents/explorer.toml +1 -1
- package/packages/omo-codex/plugin/components/ultrawork/directive.md +5 -4
- package/packages/omo-codex/plugin/components/ultrawork/package.json +1 -1
- package/packages/omo-codex/plugin/components/ultrawork/test/package-smoke.test.ts +24 -3
- package/packages/omo-codex/plugin/components/ulw-loop/package.json +1 -1
- package/packages/omo-codex/plugin/components/ulw-loop/skills/ulw-loop/references/full-workflow.md +8 -7
- package/packages/omo-codex/plugin/components/ulw-loop/test/skill-contract.test.ts +1 -1
- package/packages/omo-codex/plugin/hooks/post-tool-use-checking-codegraph-init-guidance.json +17 -0
- package/packages/omo-codex/plugin/hooks/post-tool-use-checking-thread-title-hygiene.json +17 -0
- package/packages/omo-codex/plugin/hooks/session-start-checking-codegraph-bootstrap.json +1 -1
- package/packages/omo-codex/plugin/package-lock.json +129 -12
- package/packages/omo-codex/plugin/package.json +3 -2
- package/packages/omo-codex/plugin/scripts/auto-update-plan.mjs +133 -0
- package/packages/omo-codex/plugin/scripts/auto-update-release-notes.mjs +135 -0
- package/packages/omo-codex/plugin/scripts/auto-update.mjs +33 -133
- package/packages/omo-codex/plugin/scripts/hook-status-message.mjs +1 -0
- package/packages/omo-codex/plugin/scripts/materialize-shared-upstreams.mjs +41 -0
- package/packages/omo-codex/plugin/shared/src/config-loader.ts +20 -2
- package/packages/omo-codex/plugin/shared/test/config-loader.test.ts +16 -0
- package/packages/omo-codex/plugin/skills/frontend/ATTRIBUTION.md +32 -8
- package/packages/omo-codex/plugin/skills/frontend/references/design/airbnb.md +3 -0
- package/packages/omo-codex/plugin/skills/frontend/references/design/airtable.md +3 -0
- package/packages/omo-codex/plugin/skills/frontend/references/design/apple.md +3 -0
- package/packages/omo-codex/plugin/skills/frontend/references/design/binance.md +3 -0
- package/packages/omo-codex/plugin/skills/frontend/references/design/bmw.md +3 -0
- package/packages/omo-codex/plugin/skills/frontend/references/design/bugatti.md +3 -0
- package/packages/omo-codex/plugin/skills/frontend/references/design/cal.md +3 -0
- package/packages/omo-codex/plugin/skills/frontend/references/design/claude.md +3 -0
- package/packages/omo-codex/plugin/skills/frontend/references/design/clay.md +3 -0
- package/packages/omo-codex/plugin/skills/frontend/references/design/clickhouse.md +3 -0
- package/packages/omo-codex/plugin/skills/frontend/references/design/cohere.md +3 -0
- package/packages/omo-codex/plugin/skills/frontend/references/design/coinbase.md +3 -0
- package/packages/omo-codex/plugin/skills/frontend/references/design/composio.md +3 -0
- package/packages/omo-codex/plugin/skills/frontend/references/design/cursor.md +3 -0
- package/packages/omo-codex/plugin/skills/frontend/references/design/elevenlabs.md +3 -0
- package/packages/omo-codex/plugin/skills/frontend/references/design/expo.md +3 -0
- package/packages/omo-codex/plugin/skills/frontend/references/design/ferrari.md +3 -0
- package/packages/omo-codex/plugin/skills/frontend/references/design/figma.md +3 -0
- package/packages/omo-codex/plugin/skills/frontend/references/design/framer.md +3 -0
- package/packages/omo-codex/plugin/skills/frontend/references/design/hashicorp.md +3 -0
- package/packages/omo-codex/plugin/skills/frontend/references/design/ibm.md +3 -0
- package/packages/omo-codex/plugin/skills/frontend/references/design/imagegen-frontend-web.md +380 -79
- package/packages/omo-codex/plugin/skills/frontend/references/design/intercom.md +3 -0
- package/packages/omo-codex/plugin/skills/frontend/references/design/kraken.md +3 -0
- package/packages/omo-codex/plugin/skills/frontend/references/design/lamborghini.md +3 -0
- package/packages/omo-codex/plugin/skills/frontend/references/design/linear.app.md +3 -0
- package/packages/omo-codex/plugin/skills/frontend/references/design/lovable.md +3 -0
- package/packages/omo-codex/plugin/skills/frontend/references/design/mastercard.md +3 -0
- package/packages/omo-codex/plugin/skills/frontend/references/design/meta.md +3 -0
- package/packages/omo-codex/plugin/skills/frontend/references/design/minimax.md +3 -0
- package/packages/omo-codex/plugin/skills/frontend/references/design/mintlify.md +3 -0
- package/packages/omo-codex/plugin/skills/frontend/references/design/miro.md +3 -0
- package/packages/omo-codex/plugin/skills/frontend/references/design/mistral.ai.md +3 -0
- package/packages/omo-codex/plugin/skills/frontend/references/design/mongodb.md +3 -0
- package/packages/omo-codex/plugin/skills/frontend/references/design/nike.md +3 -0
- package/packages/omo-codex/plugin/skills/frontend/references/design/notion.md +3 -0
- package/packages/omo-codex/plugin/skills/frontend/references/design/nvidia.md +3 -0
- package/packages/omo-codex/plugin/skills/frontend/references/design/ollama.md +3 -0
- package/packages/omo-codex/plugin/skills/frontend/references/design/opencode.ai.md +3 -0
- package/packages/omo-codex/plugin/skills/frontend/references/design/pinterest.md +3 -0
- package/packages/omo-codex/plugin/skills/frontend/references/design/playstation.md +3 -0
- package/packages/omo-codex/plugin/skills/frontend/references/design/posthog.md +3 -0
- package/packages/omo-codex/plugin/skills/frontend/references/design/raycast.md +3 -0
- package/packages/omo-codex/plugin/skills/frontend/references/design/renault.md +3 -0
- package/packages/omo-codex/plugin/skills/frontend/references/design/replicate.md +3 -0
- package/packages/omo-codex/plugin/skills/frontend/references/design/resend.md +3 -0
- package/packages/omo-codex/plugin/skills/frontend/references/design/revolut.md +3 -0
- package/packages/omo-codex/plugin/skills/frontend/references/design/runwayml.md +3 -0
- package/packages/omo-codex/plugin/skills/frontend/references/design/sanity.md +3 -0
- package/packages/omo-codex/plugin/skills/frontend/references/design/sentry.md +3 -0
- package/packages/omo-codex/plugin/skills/frontend/references/design/shopify.md +3 -0
- package/packages/omo-codex/plugin/skills/frontend/references/design/spacex.md +3 -0
- package/packages/omo-codex/plugin/skills/frontend/references/design/spotify.md +3 -0
- package/packages/omo-codex/plugin/skills/frontend/references/design/starbucks.md +3 -0
- package/packages/omo-codex/plugin/skills/frontend/references/design/stitch-skill.md +1 -1
- package/packages/omo-codex/plugin/skills/frontend/references/design/stripe.md +3 -0
- package/packages/omo-codex/plugin/skills/frontend/references/design/supabase.md +3 -0
- package/packages/omo-codex/plugin/skills/frontend/references/design/superhuman.md +3 -0
- package/packages/omo-codex/plugin/skills/frontend/references/design/taste-skill.md +1188 -208
- package/packages/omo-codex/plugin/skills/frontend/references/design/tesla.md +3 -0
- package/packages/omo-codex/plugin/skills/frontend/references/design/theverge.md +3 -0
- package/packages/omo-codex/plugin/skills/frontend/references/design/together.ai.md +3 -0
- package/packages/omo-codex/plugin/skills/frontend/references/design/uber.md +3 -0
- package/packages/omo-codex/plugin/skills/frontend/references/design/vercel.md +3 -0
- package/packages/omo-codex/plugin/skills/frontend/references/design/vodafone.md +3 -0
- package/packages/omo-codex/plugin/skills/frontend/references/design/voltagent.md +3 -0
- package/packages/omo-codex/plugin/skills/frontend/references/design/warp.md +3 -0
- package/packages/omo-codex/plugin/skills/frontend/references/design/webflow.md +3 -0
- package/packages/omo-codex/plugin/skills/frontend/references/design/wired.md +3 -0
- package/packages/omo-codex/plugin/skills/frontend/references/design/wise.md +3 -0
- package/packages/omo-codex/plugin/skills/frontend/references/design/x.ai.md +3 -0
- package/packages/omo-codex/plugin/skills/frontend/references/design/zapier.md +3 -0
- package/packages/omo-codex/plugin/skills/frontend/references/ui-ux-db/README.md +501 -115
- package/packages/omo-codex/plugin/skills/frontend/references/ui-ux-db/data/charts.csv +26 -26
- package/packages/omo-codex/plugin/skills/frontend/references/ui-ux-db/data/colors.csv +162 -97
- package/packages/omo-codex/plugin/skills/frontend/references/ui-ux-db/data/icons.csv +105 -100
- package/packages/omo-codex/plugin/skills/frontend/references/ui-ux-db/data/landing.csv +22 -18
- package/packages/omo-codex/plugin/skills/frontend/references/ui-ux-db/data/products.csv +162 -97
- package/packages/omo-codex/plugin/skills/frontend/references/ui-ux-db/data/stacks/flutter.csv +53 -53
- package/packages/omo-codex/plugin/skills/frontend/references/ui-ux-db/data/stacks/html-tailwind.csv +56 -56
- package/packages/omo-codex/plugin/skills/frontend/references/ui-ux-db/data/stacks/nextjs.csv +53 -53
- package/packages/omo-codex/plugin/skills/frontend/references/ui-ux-db/data/stacks/react.csv +54 -54
- package/packages/omo-codex/plugin/skills/frontend/references/ui-ux-db/data/stacks/svelte.csv +54 -54
- package/packages/omo-codex/plugin/skills/frontend/references/ui-ux-db/data/stacks/swiftui.csv +51 -51
- package/packages/omo-codex/plugin/skills/frontend/references/ui-ux-db/data/stacks/vue.csv +50 -50
- package/packages/omo-codex/plugin/skills/frontend/references/ui-ux-db/data/styles.csv +17 -0
- package/packages/omo-codex/plugin/skills/frontend/references/ui-ux-db/data/typography.csv +17 -1
- package/packages/omo-codex/plugin/skills/frontend/references/ui-ux-db/data/ui-reasoning.csv +162 -101
- package/packages/omo-codex/plugin/skills/frontend/references/ui-ux-db/data/web-interface.csv +30 -30
- package/packages/omo-codex/plugin/skills/frontend/references/ui-ux-db/scripts/core.py +31 -22
- package/packages/omo-codex/plugin/skills/frontend/references/ui-ux-db/scripts/design_system.py +150 -69
- package/packages/omo-codex/plugin/skills/frontend/references/ui-ux-db/scripts/search.py +3 -3
- package/packages/omo-codex/plugin/skills/lcx-doctor/SKILL.md +1 -1
- package/packages/omo-codex/plugin/skills/teammode/SKILL.md +59 -32
- package/packages/omo-codex/plugin/skills/teammode/scripts/team-guide.mjs +17 -16
- package/packages/omo-codex/plugin/skills/teammode/scripts/team-state.mjs +70 -3
- package/packages/omo-codex/plugin/skills/teammode/scripts/team-worktree.mjs +113 -0
- package/packages/omo-codex/plugin/skills/teammode/scripts/team.mjs +63 -4
- package/packages/omo-codex/plugin/skills/ultimate-browsing/ATTRIBUTION.md +105 -0
- package/packages/omo-codex/plugin/skills/ultimate-browsing/SKILL.md +140 -0
- package/packages/omo-codex/plugin/skills/ultimate-browsing/agents/openai.yaml +2 -0
- package/packages/omo-codex/plugin/skills/ultimate-browsing/engine/__init__.py +24 -0
- package/packages/omo-codex/plugin/skills/ultimate-browsing/engine/__main__.py +106 -0
- package/packages/omo-codex/plugin/skills/ultimate-browsing/engine/bias_check.py +174 -0
- package/packages/omo-codex/plugin/skills/ultimate-browsing/engine/curl_probe.py +91 -0
- package/packages/omo-codex/plugin/skills/ultimate-browsing/engine/executor.py +192 -0
- package/packages/omo-codex/plugin/skills/ultimate-browsing/engine/fetch_chain.py +268 -0
- package/packages/omo-codex/plugin/skills/ultimate-browsing/engine/referers.py +15 -0
- package/packages/omo-codex/plugin/skills/ultimate-browsing/engine/result_schema.py +45 -0
- package/packages/omo-codex/plugin/skills/ultimate-browsing/engine/summary.py +37 -0
- package/packages/omo-codex/plugin/skills/ultimate-browsing/engine/templates/package.json +11 -0
- package/packages/omo-codex/plugin/skills/ultimate-browsing/engine/templates/playwright_mobile_chrome.js +129 -0
- package/packages/omo-codex/plugin/skills/ultimate-browsing/engine/templates/playwright_real_chrome.js +167 -0
- package/packages/omo-codex/plugin/skills/ultimate-browsing/engine/tests/test_fetch_chain.py +77 -0
- package/packages/omo-codex/plugin/skills/ultimate-browsing/engine/tests/test_playwright_templates.py +282 -0
- package/packages/omo-codex/plugin/skills/ultimate-browsing/engine/url_transforms.py +98 -0
- package/packages/omo-codex/plugin/skills/ultimate-browsing/engine/validators.py +216 -0
- package/packages/omo-codex/plugin/skills/ultimate-browsing/engine/waf_detector.py +214 -0
- package/packages/omo-codex/plugin/skills/ultimate-browsing/engine/waf_profiles.yaml +162 -0
- package/packages/omo-codex/plugin/skills/ultimate-browsing/references/agent-reach/README.md +79 -0
- package/packages/omo-codex/plugin/skills/ultimate-browsing/references/agent-reach/career.md +29 -0
- package/packages/omo-codex/plugin/skills/ultimate-browsing/references/agent-reach/dev.md +62 -0
- package/packages/omo-codex/plugin/skills/ultimate-browsing/references/agent-reach/search.md +33 -0
- package/packages/omo-codex/plugin/skills/ultimate-browsing/references/agent-reach/social.md +207 -0
- package/packages/omo-codex/plugin/skills/ultimate-browsing/references/agent-reach/video.md +115 -0
- package/packages/omo-codex/plugin/skills/ultimate-browsing/references/agent-reach/web.md +76 -0
- package/packages/omo-codex/plugin/skills/ultimate-browsing/references/chrome-stealth.md +120 -0
- package/packages/omo-codex/plugin/skills/ultimate-browsing/references/insane-search/README.md +319 -0
- package/packages/omo-codex/plugin/skills/ultimate-browsing/references/insane-search/cache-archive.md +83 -0
- package/packages/omo-codex/plugin/skills/ultimate-browsing/references/insane-search/fallback.md +159 -0
- package/packages/omo-codex/plugin/skills/ultimate-browsing/references/insane-search/jina.md +130 -0
- package/packages/omo-codex/plugin/skills/ultimate-browsing/references/insane-search/json-api.md +133 -0
- package/packages/omo-codex/plugin/skills/ultimate-browsing/references/insane-search/media.md +123 -0
- package/packages/omo-codex/plugin/skills/ultimate-browsing/references/insane-search/metadata.md +116 -0
- package/packages/omo-codex/plugin/skills/ultimate-browsing/references/insane-search/naver.md +107 -0
- package/packages/omo-codex/plugin/skills/ultimate-browsing/references/insane-search/playwright.md +142 -0
- package/packages/omo-codex/plugin/skills/ultimate-browsing/references/insane-search/public-api.md +119 -0
- package/packages/omo-codex/plugin/skills/ultimate-browsing/references/insane-search/rss.md +123 -0
- package/packages/omo-codex/plugin/skills/ultimate-browsing/references/insane-search/tls-impersonate.md +186 -0
- package/packages/omo-codex/plugin/skills/ultimate-browsing/references/insane-search/twitter.md +104 -0
- package/packages/omo-codex/plugin/skills/ultimate-browsing/scripts/cookie_crypto.py +75 -0
- package/packages/omo-codex/plugin/skills/ultimate-browsing/scripts/cookie_domains.py +38 -0
- package/packages/omo-codex/plugin/skills/ultimate-browsing/scripts/cookie_paths.py +112 -0
- package/packages/omo-codex/plugin/skills/ultimate-browsing/scripts/extract_cookies.py +280 -0
- package/packages/omo-codex/plugin/skills/ultimate-browsing/scripts/tests/test_cookie_domain_filter.py +110 -0
- package/packages/omo-codex/plugin/skills/ultimate-browsing/scripts/tests/test_extract_cookies.py +245 -0
- package/packages/omo-codex/plugin/skills/ultraresearch/ATTRIBUTION.md +49 -0
- package/packages/omo-codex/plugin/skills/ultraresearch/SKILL.md +34 -6
- package/packages/omo-codex/plugin/skills/ulw-loop/references/full-workflow.md +8 -7
- package/packages/omo-codex/plugin/test/aggregate-build.test.mjs +2 -1
- package/packages/omo-codex/plugin/test/aggregate-hooks.test.mjs +36 -0
- package/packages/omo-codex/plugin/test/aggregate-manifest.test.mjs +2 -1
- package/packages/omo-codex/plugin/test/aggregate-plugin-fixture.mjs +1 -1
- package/packages/omo-codex/plugin/test/auto-update-release-notes.test.mjs +95 -0
- package/packages/omo-codex/plugin/test/auto-update-restart-notice.test.mjs +12 -3
- package/packages/omo-codex/plugin/test/component-bundled-cli.test.mjs +1 -0
- package/packages/omo-codex/plugin/test/component-codegraph-mcp-smoke.test.mjs +76 -0
- package/packages/omo-codex/plugin/test/component-hook-contract-cases.mjs +24 -0
- package/packages/omo-codex/plugin/test/hook-status-message.test.mjs +1 -0
- package/packages/omo-codex/plugin/test/sync-skills-test-support.mjs +1 -0
- package/packages/omo-codex/plugin/test/teammode-communication.test.mjs +87 -0
- package/packages/omo-codex/plugin/test/teammode-thread-title.test.mjs +169 -0
- package/packages/omo-codex/plugin/test/teammode-worktree.test.mjs +246 -0
- package/packages/omo-codex/plugin/test/ultraresearch-skill-contract.test.mjs +78 -0
- package/packages/omo-codex/scripts/install-cli-args.test.mjs +1 -1
- package/packages/omo-codex/scripts/install-config-git-bash.test.mjs +23 -0
- package/packages/omo-codex/scripts/install-delegated-command.test.mjs +76 -4
- package/packages/omo-codex/scripts/install-dist/install-local.mjs +531 -214
- package/packages/omo-codex/scripts/install-local-entrypoint.test.mjs +40 -3
- package/packages/shared-skills/skills/frontend/ATTRIBUTION.md +32 -8
- package/packages/shared-skills/skills/frontend/references/design/airbnb.md +3 -0
- package/packages/shared-skills/skills/frontend/references/design/airtable.md +3 -0
- package/packages/shared-skills/skills/frontend/references/design/apple.md +3 -0
- package/packages/shared-skills/skills/frontend/references/design/binance.md +3 -0
- package/packages/shared-skills/skills/frontend/references/design/bmw.md +3 -0
- package/packages/shared-skills/skills/frontend/references/design/bugatti.md +3 -0
- package/packages/shared-skills/skills/frontend/references/design/cal.md +3 -0
- package/packages/shared-skills/skills/frontend/references/design/claude.md +3 -0
- package/packages/shared-skills/skills/frontend/references/design/clay.md +3 -0
- package/packages/shared-skills/skills/frontend/references/design/clickhouse.md +3 -0
- package/packages/shared-skills/skills/frontend/references/design/cohere.md +3 -0
- package/packages/shared-skills/skills/frontend/references/design/coinbase.md +3 -0
- package/packages/shared-skills/skills/frontend/references/design/composio.md +3 -0
- package/packages/shared-skills/skills/frontend/references/design/cursor.md +3 -0
- package/packages/shared-skills/skills/frontend/references/design/elevenlabs.md +3 -0
- package/packages/shared-skills/skills/frontend/references/design/expo.md +3 -0
- package/packages/shared-skills/skills/frontend/references/design/ferrari.md +3 -0
- package/packages/shared-skills/skills/frontend/references/design/figma.md +3 -0
- package/packages/shared-skills/skills/frontend/references/design/framer.md +3 -0
- package/packages/shared-skills/skills/frontend/references/design/hashicorp.md +3 -0
- package/packages/shared-skills/skills/frontend/references/design/ibm.md +3 -0
- package/packages/shared-skills/skills/frontend/references/design/imagegen-frontend-web.md +380 -79
- package/packages/shared-skills/skills/frontend/references/design/intercom.md +3 -0
- package/packages/shared-skills/skills/frontend/references/design/kraken.md +3 -0
- package/packages/shared-skills/skills/frontend/references/design/lamborghini.md +3 -0
- package/packages/shared-skills/skills/frontend/references/design/linear.app.md +3 -0
- package/packages/shared-skills/skills/frontend/references/design/lovable.md +3 -0
- package/packages/shared-skills/skills/frontend/references/design/mastercard.md +3 -0
- package/packages/shared-skills/skills/frontend/references/design/meta.md +3 -0
- package/packages/shared-skills/skills/frontend/references/design/minimax.md +3 -0
- package/packages/shared-skills/skills/frontend/references/design/mintlify.md +3 -0
- package/packages/shared-skills/skills/frontend/references/design/miro.md +3 -0
- package/packages/shared-skills/skills/frontend/references/design/mistral.ai.md +3 -0
- package/packages/shared-skills/skills/frontend/references/design/mongodb.md +3 -0
- package/packages/shared-skills/skills/frontend/references/design/nike.md +3 -0
- package/packages/shared-skills/skills/frontend/references/design/notion.md +3 -0
- package/packages/shared-skills/skills/frontend/references/design/nvidia.md +3 -0
- package/packages/shared-skills/skills/frontend/references/design/ollama.md +3 -0
- package/packages/shared-skills/skills/frontend/references/design/opencode.ai.md +3 -0
- package/packages/shared-skills/skills/frontend/references/design/pinterest.md +3 -0
- package/packages/shared-skills/skills/frontend/references/design/playstation.md +3 -0
- package/packages/shared-skills/skills/frontend/references/design/posthog.md +3 -0
- package/packages/shared-skills/skills/frontend/references/design/raycast.md +3 -0
- package/packages/shared-skills/skills/frontend/references/design/renault.md +3 -0
- package/packages/shared-skills/skills/frontend/references/design/replicate.md +3 -0
- package/packages/shared-skills/skills/frontend/references/design/resend.md +3 -0
- package/packages/shared-skills/skills/frontend/references/design/revolut.md +3 -0
- package/packages/shared-skills/skills/frontend/references/design/runwayml.md +3 -0
- package/packages/shared-skills/skills/frontend/references/design/sanity.md +3 -0
- package/packages/shared-skills/skills/frontend/references/design/sentry.md +3 -0
- package/packages/shared-skills/skills/frontend/references/design/shopify.md +3 -0
- package/packages/shared-skills/skills/frontend/references/design/spacex.md +3 -0
- package/packages/shared-skills/skills/frontend/references/design/spotify.md +3 -0
- package/packages/shared-skills/skills/frontend/references/design/starbucks.md +3 -0
- package/packages/shared-skills/skills/frontend/references/design/stitch-skill.md +1 -1
- package/packages/shared-skills/skills/frontend/references/design/stripe.md +3 -0
- package/packages/shared-skills/skills/frontend/references/design/supabase.md +3 -0
- package/packages/shared-skills/skills/frontend/references/design/superhuman.md +3 -0
- package/packages/shared-skills/skills/frontend/references/design/taste-skill.md +1188 -208
- package/packages/shared-skills/skills/frontend/references/design/tesla.md +3 -0
- package/packages/shared-skills/skills/frontend/references/design/theverge.md +3 -0
- package/packages/shared-skills/skills/frontend/references/design/together.ai.md +3 -0
- package/packages/shared-skills/skills/frontend/references/design/uber.md +3 -0
- package/packages/shared-skills/skills/frontend/references/design/vercel.md +3 -0
- package/packages/shared-skills/skills/frontend/references/design/vodafone.md +3 -0
- package/packages/shared-skills/skills/frontend/references/design/voltagent.md +3 -0
- package/packages/shared-skills/skills/frontend/references/design/warp.md +3 -0
- package/packages/shared-skills/skills/frontend/references/design/webflow.md +3 -0
- package/packages/shared-skills/skills/frontend/references/design/wired.md +3 -0
- package/packages/shared-skills/skills/frontend/references/design/wise.md +3 -0
- package/packages/shared-skills/skills/frontend/references/design/x.ai.md +3 -0
- package/packages/shared-skills/skills/frontend/references/design/zapier.md +3 -0
- package/packages/shared-skills/skills/frontend/references/ui-ux-db/README.md +501 -115
- package/packages/shared-skills/skills/frontend/references/ui-ux-db/data/charts.csv +26 -26
- package/packages/shared-skills/skills/frontend/references/ui-ux-db/data/colors.csv +162 -97
- package/packages/shared-skills/skills/frontend/references/ui-ux-db/data/icons.csv +105 -100
- package/packages/shared-skills/skills/frontend/references/ui-ux-db/data/landing.csv +22 -18
- package/packages/shared-skills/skills/frontend/references/ui-ux-db/data/products.csv +162 -97
- package/packages/shared-skills/skills/frontend/references/ui-ux-db/data/stacks/flutter.csv +53 -53
- package/packages/shared-skills/skills/frontend/references/ui-ux-db/data/stacks/html-tailwind.csv +56 -56
- package/packages/shared-skills/skills/frontend/references/ui-ux-db/data/stacks/nextjs.csv +53 -53
- package/packages/shared-skills/skills/frontend/references/ui-ux-db/data/stacks/react.csv +54 -54
- package/packages/shared-skills/skills/frontend/references/ui-ux-db/data/stacks/svelte.csv +54 -54
- package/packages/shared-skills/skills/frontend/references/ui-ux-db/data/stacks/swiftui.csv +51 -51
- package/packages/shared-skills/skills/frontend/references/ui-ux-db/data/stacks/vue.csv +50 -50
- package/packages/shared-skills/skills/frontend/references/ui-ux-db/data/styles.csv +17 -0
- package/packages/shared-skills/skills/frontend/references/ui-ux-db/data/typography.csv +17 -1
- package/packages/shared-skills/skills/frontend/references/ui-ux-db/data/ui-reasoning.csv +162 -101
- package/packages/shared-skills/skills/frontend/references/ui-ux-db/data/web-interface.csv +30 -30
- package/packages/shared-skills/skills/frontend/references/ui-ux-db/scripts/core.py +31 -22
- package/packages/shared-skills/skills/frontend/references/ui-ux-db/scripts/design_system.py +150 -69
- package/packages/shared-skills/skills/frontend/references/ui-ux-db/scripts/search.py +3 -3
- package/packages/shared-skills/skills/lcx-doctor/SKILL.md +1 -1
- package/packages/shared-skills/skills/ultimate-browsing/ATTRIBUTION.md +105 -0
- package/packages/shared-skills/skills/ultimate-browsing/SKILL.md +140 -0
- package/packages/shared-skills/skills/ultimate-browsing/engine/__init__.py +24 -0
- package/packages/shared-skills/skills/ultimate-browsing/engine/__main__.py +106 -0
- package/packages/shared-skills/skills/ultimate-browsing/engine/bias_check.py +174 -0
- package/packages/shared-skills/skills/ultimate-browsing/engine/curl_probe.py +91 -0
- package/packages/shared-skills/skills/ultimate-browsing/engine/executor.py +192 -0
- package/packages/shared-skills/skills/ultimate-browsing/engine/fetch_chain.py +268 -0
- package/packages/shared-skills/skills/ultimate-browsing/engine/referers.py +15 -0
- package/packages/shared-skills/skills/ultimate-browsing/engine/result_schema.py +45 -0
- package/packages/shared-skills/skills/ultimate-browsing/engine/summary.py +37 -0
- package/packages/shared-skills/skills/ultimate-browsing/engine/templates/package.json +11 -0
- package/packages/shared-skills/skills/ultimate-browsing/engine/templates/playwright_mobile_chrome.js +129 -0
- package/packages/shared-skills/skills/ultimate-browsing/engine/templates/playwright_real_chrome.js +167 -0
- package/packages/shared-skills/skills/ultimate-browsing/engine/tests/test_fetch_chain.py +77 -0
- package/packages/shared-skills/skills/ultimate-browsing/engine/tests/test_playwright_templates.py +282 -0
- package/packages/shared-skills/skills/ultimate-browsing/engine/url_transforms.py +98 -0
- package/packages/shared-skills/skills/ultimate-browsing/engine/validators.py +216 -0
- package/packages/shared-skills/skills/ultimate-browsing/engine/waf_detector.py +214 -0
- package/packages/shared-skills/skills/ultimate-browsing/engine/waf_profiles.yaml +162 -0
- package/packages/shared-skills/skills/ultimate-browsing/references/agent-reach/README.md +79 -0
- package/packages/shared-skills/skills/ultimate-browsing/references/agent-reach/career.md +29 -0
- package/packages/shared-skills/skills/ultimate-browsing/references/agent-reach/dev.md +62 -0
- package/packages/shared-skills/skills/ultimate-browsing/references/agent-reach/search.md +33 -0
- package/packages/shared-skills/skills/ultimate-browsing/references/agent-reach/social.md +207 -0
- package/packages/shared-skills/skills/ultimate-browsing/references/agent-reach/video.md +115 -0
- package/packages/shared-skills/skills/ultimate-browsing/references/agent-reach/web.md +76 -0
- package/packages/shared-skills/skills/ultimate-browsing/references/chrome-stealth.md +120 -0
- package/packages/shared-skills/skills/ultimate-browsing/references/insane-search/README.md +319 -0
- package/packages/shared-skills/skills/ultimate-browsing/references/insane-search/cache-archive.md +83 -0
- package/packages/shared-skills/skills/ultimate-browsing/references/insane-search/fallback.md +159 -0
- package/packages/shared-skills/skills/ultimate-browsing/references/insane-search/jina.md +130 -0
- package/packages/shared-skills/skills/ultimate-browsing/references/insane-search/json-api.md +133 -0
- package/packages/shared-skills/skills/ultimate-browsing/references/insane-search/media.md +123 -0
- package/packages/shared-skills/skills/ultimate-browsing/references/insane-search/metadata.md +116 -0
- package/packages/shared-skills/skills/ultimate-browsing/references/insane-search/naver.md +107 -0
- package/packages/shared-skills/skills/ultimate-browsing/references/insane-search/playwright.md +142 -0
- package/packages/shared-skills/skills/ultimate-browsing/references/insane-search/public-api.md +119 -0
- package/packages/shared-skills/skills/ultimate-browsing/references/insane-search/rss.md +123 -0
- package/packages/shared-skills/skills/ultimate-browsing/references/insane-search/tls-impersonate.md +186 -0
- package/packages/shared-skills/skills/ultimate-browsing/references/insane-search/twitter.md +104 -0
- package/packages/shared-skills/skills/ultimate-browsing/scripts/cookie_crypto.py +75 -0
- package/packages/shared-skills/skills/ultimate-browsing/scripts/cookie_domains.py +38 -0
- package/packages/shared-skills/skills/ultimate-browsing/scripts/cookie_paths.py +112 -0
- package/packages/shared-skills/skills/ultimate-browsing/scripts/extract_cookies.py +280 -0
- package/packages/shared-skills/skills/ultimate-browsing/scripts/tests/test_cookie_domain_filter.py +110 -0
- package/packages/shared-skills/skills/ultimate-browsing/scripts/tests/test_extract_cookies.py +245 -0
- package/packages/shared-skills/skills/ultraresearch/ATTRIBUTION.md +49 -0
- package/packages/shared-skills/skills/ultraresearch/SKILL.md +34 -6
- package/packages/shared-skills/skills/ulw-plan/SKILL.md +4 -1
- package/packages/omo-codex/plugin/components/codegraph/dist/cli.d.ts +0 -2
- package/packages/omo-codex/plugin/components/codegraph/dist/serve.d.ts +0 -32
|
@@ -0,0 +1,98 @@
|
|
|
1
|
+
"""Generic URL transforms for the fetch grid.
|
|
2
|
+
|
|
3
|
+
Transforms are domain-agnostic *rules*. They never reference a specific
|
|
4
|
+
site by name. A transform either applies (returns a new URL) or is skipped
|
|
5
|
+
(returns None). Callers iterate transforms in order.
|
|
6
|
+
|
|
7
|
+
Empirically useful transforms (see observations/):
|
|
8
|
+
* mobile_subdomain — `www.example.com` → `m.example.com`
|
|
9
|
+
Strong win on SSR sites with mobile-first serving. Loss on SPA shells
|
|
10
|
+
(some mobile sites return tiny bootstrap HTML).
|
|
11
|
+
* am_prefix — `example.com` (no www) → `m.example.com`
|
|
12
|
+
* drop_www — occasionally unblocks hosts that gate www but not apex.
|
|
13
|
+
|
|
14
|
+
Adding new transforms: prove they help on ≥2 unrelated sites first
|
|
15
|
+
(cross-site validation — bias check).
|
|
16
|
+
"""
|
|
17
|
+
from __future__ import annotations
|
|
18
|
+
|
|
19
|
+
from typing import Callable, Optional
|
|
20
|
+
from urllib.parse import urlsplit, urlunsplit
|
|
21
|
+
|
|
22
|
+
|
|
23
|
+
def _replace_host(url: str, new_host: str) -> str:
|
|
24
|
+
parts = urlsplit(url)
|
|
25
|
+
return urlunsplit(parts._replace(netloc=new_host))
|
|
26
|
+
|
|
27
|
+
|
|
28
|
+
def _original(url: str) -> Optional[str]:
|
|
29
|
+
return url
|
|
30
|
+
|
|
31
|
+
|
|
32
|
+
def _mobile_subdomain(url: str) -> Optional[str]:
|
|
33
|
+
"""`https://www.example.com/a` → `https://m.example.com/a` (only if host starts with www.)."""
|
|
34
|
+
parts = urlsplit(url)
|
|
35
|
+
host = parts.hostname or ""
|
|
36
|
+
if not host.startswith("www."):
|
|
37
|
+
return None
|
|
38
|
+
new_host = "m." + host[4:]
|
|
39
|
+
if parts.port:
|
|
40
|
+
new_host = f"{new_host}:{parts.port}"
|
|
41
|
+
return _replace_host(url, new_host)
|
|
42
|
+
|
|
43
|
+
|
|
44
|
+
def _am_prefix(url: str) -> Optional[str]:
|
|
45
|
+
"""`https://example.com/a` → `https://m.example.com/a` (only if host has no subdomain)."""
|
|
46
|
+
parts = urlsplit(url)
|
|
47
|
+
host = parts.hostname or ""
|
|
48
|
+
if not host or host.startswith("m."):
|
|
49
|
+
return None
|
|
50
|
+
# Only apply to apex-like hosts (≤2 dot-separated labels).
|
|
51
|
+
if host.count(".") >= 2 and not host.startswith("www."):
|
|
52
|
+
return None
|
|
53
|
+
if host.startswith("www."):
|
|
54
|
+
return None # handled by mobile_subdomain
|
|
55
|
+
return _replace_host(url, "m." + host)
|
|
56
|
+
|
|
57
|
+
|
|
58
|
+
def _drop_www(url: str) -> Optional[str]:
|
|
59
|
+
parts = urlsplit(url)
|
|
60
|
+
host = parts.hostname or ""
|
|
61
|
+
if not host.startswith("www."):
|
|
62
|
+
return None
|
|
63
|
+
return _replace_host(url, host[4:])
|
|
64
|
+
|
|
65
|
+
|
|
66
|
+
TRANSFORMS: dict[str, Callable[[str], Optional[str]]] = {
|
|
67
|
+
"original": _original,
|
|
68
|
+
"mobile_subdomain": _mobile_subdomain,
|
|
69
|
+
"am_prefix": _am_prefix,
|
|
70
|
+
"drop_www": _drop_www,
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
|
|
74
|
+
def apply_transform(name: str, url: str) -> Optional[str]:
|
|
75
|
+
"""Apply one transform by name. Returns transformed URL or None if skipped."""
|
|
76
|
+
fn = TRANSFORMS.get(name)
|
|
77
|
+
if fn is None:
|
|
78
|
+
raise ValueError(f"Unknown transform: {name!r}. Known: {list(TRANSFORMS)}")
|
|
79
|
+
return fn(url)
|
|
80
|
+
|
|
81
|
+
|
|
82
|
+
def iter_transformed(url: str, order: list[str]) -> list[tuple[str, str]]:
|
|
83
|
+
"""Yield (transform_name, transformed_url) pairs for a given order.
|
|
84
|
+
|
|
85
|
+
Skips transforms that return None (not applicable) and deduplicates
|
|
86
|
+
URLs (so `original` and `drop_www` of `https://example.com` don't double-run).
|
|
87
|
+
"""
|
|
88
|
+
seen: set[str] = set()
|
|
89
|
+
out: list[tuple[str, str]] = []
|
|
90
|
+
for name in order:
|
|
91
|
+
new_url = apply_transform(name, url)
|
|
92
|
+
if new_url is None:
|
|
93
|
+
continue
|
|
94
|
+
if new_url in seen:
|
|
95
|
+
continue
|
|
96
|
+
seen.add(new_url)
|
|
97
|
+
out.append((name, new_url))
|
|
98
|
+
return out
|
|
@@ -0,0 +1,216 @@
|
|
|
1
|
+
"""Generic challenge / success validator.
|
|
2
|
+
|
|
3
|
+
Four layers (all generic, never site-specific):
|
|
4
|
+
1. Challenge markers (WAF product strings — not site brand names)
|
|
5
|
+
2. Size fingerprints (known bad byte sizes hinted by caller)
|
|
6
|
+
3. Cookie sensor state (e.g. Akamai `_abck=~-1~`)
|
|
7
|
+
4. Caller-supplied success_selectors (strongest positive proof)
|
|
8
|
+
|
|
9
|
+
Layers 1-3 are "negative proof" (fail fast).
|
|
10
|
+
Layer 4 is "positive proof" — without it, HTTP 200 is only a weak success.
|
|
11
|
+
"""
|
|
12
|
+
from __future__ import annotations
|
|
13
|
+
|
|
14
|
+
from dataclasses import dataclass, field
|
|
15
|
+
from enum import Enum
|
|
16
|
+
from typing import Optional
|
|
17
|
+
|
|
18
|
+
try:
|
|
19
|
+
from bs4 import BeautifulSoup
|
|
20
|
+
except ImportError: # bs4 is a soft dep: only used when selectors given
|
|
21
|
+
BeautifulSoup = None
|
|
22
|
+
|
|
23
|
+
|
|
24
|
+
# Markers are WAF-product strings only. Never include site brand / domain.
|
|
25
|
+
CHALLENGE_MARKERS: list[str] = [
|
|
26
|
+
"Access Denied",
|
|
27
|
+
"sec-if-cpt-container",
|
|
28
|
+
"Powered and protected by Akamai",
|
|
29
|
+
"Just a moment...",
|
|
30
|
+
"Checking your browser",
|
|
31
|
+
"cf-chl-bypass",
|
|
32
|
+
"Attention Required! | Cloudflare",
|
|
33
|
+
"<title>Bot Challenge</title>",
|
|
34
|
+
"DataDome",
|
|
35
|
+
"captcha",
|
|
36
|
+
"Please enable JS and disable any ad blocker",
|
|
37
|
+
"The requested URL was rejected",
|
|
38
|
+
"Request unsuccessful. Incapsula",
|
|
39
|
+
]
|
|
40
|
+
|
|
41
|
+
# Minimum body size below which we suspect a stub / challenge page.
|
|
42
|
+
# Tunable: some legitimate short JSON responses may be smaller, but callers
|
|
43
|
+
# that know their response type should pass success_selectors instead.
|
|
44
|
+
SMALL_BODY_THRESHOLD = 3000
|
|
45
|
+
|
|
46
|
+
|
|
47
|
+
class Verdict(Enum):
|
|
48
|
+
"""Three-level classification (Codex suggestion — avoid binary)."""
|
|
49
|
+
|
|
50
|
+
STRONG_OK = "strong_ok" # passes all layers incl. success_selectors
|
|
51
|
+
WEAK_OK = "weak_ok" # passes 1-3 but no positive proof available
|
|
52
|
+
CHALLENGE = "challenge" # fails 1-3 (negative proof triggered)
|
|
53
|
+
BLOCKED = "blocked" # non-200 status
|
|
54
|
+
UNKNOWN = "unknown" # exception / malformed response
|
|
55
|
+
|
|
56
|
+
|
|
57
|
+
@dataclass
|
|
58
|
+
class ValidationResult:
|
|
59
|
+
verdict: Verdict
|
|
60
|
+
reasons: list[str] = field(default_factory=list)
|
|
61
|
+
matched_selectors: list[str] = field(default_factory=list)
|
|
62
|
+
body_size: int = 0
|
|
63
|
+
status: int = 0
|
|
64
|
+
|
|
65
|
+
@property
|
|
66
|
+
def ok(self) -> bool:
|
|
67
|
+
"""Kept for ergonomic `if vr.ok:` use — weak_ok counts as ok."""
|
|
68
|
+
return self.verdict in (Verdict.STRONG_OK, Verdict.WEAK_OK)
|
|
69
|
+
|
|
70
|
+
def to_dict(self) -> dict:
|
|
71
|
+
return {
|
|
72
|
+
"verdict": self.verdict.value,
|
|
73
|
+
"reasons": self.reasons,
|
|
74
|
+
"matched_selectors": self.matched_selectors,
|
|
75
|
+
"body_size": self.body_size,
|
|
76
|
+
"status": self.status,
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
|
|
80
|
+
def _marker_hits(body_lower: str) -> list[str]:
|
|
81
|
+
return [m for m in CHALLENGE_MARKERS if m.lower() in body_lower]
|
|
82
|
+
|
|
83
|
+
|
|
84
|
+
def _abck_unresolved(cookies: dict) -> bool:
|
|
85
|
+
abck = cookies.get("_abck", "")
|
|
86
|
+
return bool(abck) and "~-1~" in abck
|
|
87
|
+
|
|
88
|
+
|
|
89
|
+
def _selector_hits(body: str, selectors: list[str]) -> Optional[list[str]]:
|
|
90
|
+
"""Return matched-selector list, or None if BS4 is unavailable.
|
|
91
|
+
|
|
92
|
+
Distinguishing None (dependency missing) from [] (nothing matched) lets
|
|
93
|
+
the caller classify as UNKNOWN vs CHALLENGE correctly (Codex review: do
|
|
94
|
+
not let dependency failure masquerade as a WAF outcome).
|
|
95
|
+
"""
|
|
96
|
+
if BeautifulSoup is None:
|
|
97
|
+
return None
|
|
98
|
+
try:
|
|
99
|
+
soup = BeautifulSoup(body, "html.parser")
|
|
100
|
+
except Exception:
|
|
101
|
+
return []
|
|
102
|
+
hits: list[str] = []
|
|
103
|
+
for sel in selectors:
|
|
104
|
+
try:
|
|
105
|
+
if soup.select(sel):
|
|
106
|
+
hits.append(sel)
|
|
107
|
+
except Exception:
|
|
108
|
+
continue
|
|
109
|
+
return hits
|
|
110
|
+
|
|
111
|
+
|
|
112
|
+
def validate(
|
|
113
|
+
resp,
|
|
114
|
+
*,
|
|
115
|
+
success_selectors: Optional[list[str]] = None,
|
|
116
|
+
known_bad_sizes: Optional[list[int]] = None,
|
|
117
|
+
size_tolerance: int = 20,
|
|
118
|
+
) -> ValidationResult:
|
|
119
|
+
"""Validate a `curl_cffi` / `requests` response.
|
|
120
|
+
|
|
121
|
+
Parameters
|
|
122
|
+
----------
|
|
123
|
+
resp
|
|
124
|
+
Response object with `.status_code`, `.text`, and cookie-like access.
|
|
125
|
+
success_selectors
|
|
126
|
+
Caller-supplied CSS selectors. Any match promotes `weak_ok` → `strong_ok`.
|
|
127
|
+
Absence of selectors still allows `weak_ok` (no positive proof, but
|
|
128
|
+
no negative proof either).
|
|
129
|
+
known_bad_sizes
|
|
130
|
+
Byte sizes that have been empirically observed as challenge-page
|
|
131
|
+
fingerprints (caller / profile hint). NOTE: these values decay over
|
|
132
|
+
time — profiles should timestamp or refresh them.
|
|
133
|
+
"""
|
|
134
|
+
try:
|
|
135
|
+
status = int(getattr(resp, "status_code", 0) or 0)
|
|
136
|
+
text = getattr(resp, "text", "") or ""
|
|
137
|
+
size = len(text)
|
|
138
|
+
except Exception as e:
|
|
139
|
+
return ValidationResult(verdict=Verdict.UNKNOWN, reasons=[f"parse_error:{e}"])
|
|
140
|
+
|
|
141
|
+
r = ValidationResult(verdict=Verdict.UNKNOWN, body_size=size, status=status)
|
|
142
|
+
|
|
143
|
+
if status == 0 or status >= 400:
|
|
144
|
+
r.verdict = Verdict.BLOCKED
|
|
145
|
+
r.reasons.append(f"status={status}")
|
|
146
|
+
return r
|
|
147
|
+
|
|
148
|
+
# --- Layer 1: challenge markers (product strings, never site brand) ---
|
|
149
|
+
lowered = text.lower()
|
|
150
|
+
markers = _marker_hits(lowered)
|
|
151
|
+
if markers:
|
|
152
|
+
r.verdict = Verdict.CHALLENGE
|
|
153
|
+
r.reasons.extend(f"marker:{m}" for m in markers[:3])
|
|
154
|
+
return r
|
|
155
|
+
|
|
156
|
+
# --- Layer 2: size fingerprints (caller hint, tolerant match) ---
|
|
157
|
+
# Fingerprint match is a strong negative signal — override even selectors.
|
|
158
|
+
if known_bad_sizes:
|
|
159
|
+
for bad in known_bad_sizes:
|
|
160
|
+
if abs(size - bad) <= size_tolerance:
|
|
161
|
+
r.verdict = Verdict.CHALLENGE
|
|
162
|
+
r.reasons.append(f"size_fp:{size}~{bad}")
|
|
163
|
+
return r
|
|
164
|
+
|
|
165
|
+
# --- Layer 4 (early): caller's positive proof overrides size heuristic ---
|
|
166
|
+
# If caller provided selectors, trust their definition of "content exists".
|
|
167
|
+
# A small page with the required selector is still success.
|
|
168
|
+
if success_selectors:
|
|
169
|
+
hits = _selector_hits(text, success_selectors)
|
|
170
|
+
if hits is None:
|
|
171
|
+
# BS4 dependency missing — can't evaluate caller's proof.
|
|
172
|
+
# Classify as UNKNOWN (not CHALLENGE) so a WAF outcome isn't faked.
|
|
173
|
+
r.verdict = Verdict.UNKNOWN
|
|
174
|
+
r.reasons.append("bs4_missing")
|
|
175
|
+
return r
|
|
176
|
+
if hits:
|
|
177
|
+
# Cookie sensor state acts as a true gate when selectors passed:
|
|
178
|
+
# unresolved `_abck` means Akamai did not accept our session even
|
|
179
|
+
# though the body has our expected selector — trust is weak.
|
|
180
|
+
cookies = _extract_cookies(resp)
|
|
181
|
+
r.matched_selectors = hits
|
|
182
|
+
if _abck_unresolved(cookies):
|
|
183
|
+
r.reasons.append("abck_unresolved")
|
|
184
|
+
r.verdict = Verdict.WEAK_OK # demoted from STRONG_OK
|
|
185
|
+
return r
|
|
186
|
+
r.verdict = Verdict.STRONG_OK
|
|
187
|
+
return r
|
|
188
|
+
# Selectors requested but none matched → challenge regardless of size.
|
|
189
|
+
r.verdict = Verdict.CHALLENGE
|
|
190
|
+
r.reasons.append("no_success_selector")
|
|
191
|
+
return r
|
|
192
|
+
|
|
193
|
+
# No selectors: fall back to size heuristic.
|
|
194
|
+
if size < SMALL_BODY_THRESHOLD:
|
|
195
|
+
r.verdict = Verdict.CHALLENGE
|
|
196
|
+
r.reasons.append(f"tiny_body:{size}")
|
|
197
|
+
return r
|
|
198
|
+
|
|
199
|
+
# --- Layer 3: cookie sensor state (only when no selectors to decide on) ---
|
|
200
|
+
cookies = _extract_cookies(resp)
|
|
201
|
+
if _abck_unresolved(cookies):
|
|
202
|
+
r.reasons.append("abck_unresolved")
|
|
203
|
+
|
|
204
|
+
# No positive proof available — weak OK.
|
|
205
|
+
r.verdict = Verdict.WEAK_OK
|
|
206
|
+
return r
|
|
207
|
+
|
|
208
|
+
|
|
209
|
+
def _extract_cookies(resp) -> dict:
|
|
210
|
+
try:
|
|
211
|
+
return {c.name: c.value for c in resp.cookies.jar}
|
|
212
|
+
except Exception:
|
|
213
|
+
try:
|
|
214
|
+
return dict(resp.cookies) if hasattr(resp, "cookies") else {}
|
|
215
|
+
except Exception:
|
|
216
|
+
return {}
|
|
@@ -0,0 +1,214 @@
|
|
|
1
|
+
"""WAF-product detection from a live response.
|
|
2
|
+
|
|
3
|
+
Returns a *ranking* of (profile_id, confidence) pairs — never a single verdict.
|
|
4
|
+
Single-answer detectors cause cascading wrong plans when misfiring (Codex's
|
|
5
|
+
critique). Planner consumes the ranking and tries top candidates in order.
|
|
6
|
+
|
|
7
|
+
All detectors operate on WAF-vendor artifacts (cookies / headers / body
|
|
8
|
+
strings) — never site hostnames. See engine/waf_profiles.yaml for the
|
|
9
|
+
profile definitions.
|
|
10
|
+
"""
|
|
11
|
+
from __future__ import annotations
|
|
12
|
+
|
|
13
|
+
import fnmatch
|
|
14
|
+
import os
|
|
15
|
+
import re
|
|
16
|
+
from dataclasses import dataclass
|
|
17
|
+
from typing import Optional
|
|
18
|
+
|
|
19
|
+
try:
|
|
20
|
+
import yaml # PyYAML
|
|
21
|
+
except ImportError:
|
|
22
|
+
yaml = None
|
|
23
|
+
|
|
24
|
+
|
|
25
|
+
PROFILES_PATH = os.path.join(os.path.dirname(__file__), "waf_profiles.yaml")
|
|
26
|
+
|
|
27
|
+
|
|
28
|
+
# In-code safety net — used when waf_profiles.yaml is missing / invalid
|
|
29
|
+
# or PyYAML isn't installed. Keeps fetch() working in a degraded-but-sane
|
|
30
|
+
# mode. Must stay site-agnostic (No-Site-Name Rule).
|
|
31
|
+
_DEFAULT_PROFILES: dict = {
|
|
32
|
+
"unknown_challenge": {
|
|
33
|
+
"detectors": {},
|
|
34
|
+
"confidence_rules": {"strong": 0, "weak": 0},
|
|
35
|
+
"capabilities_needed": ["needs_js_exec"],
|
|
36
|
+
"tls_impersonate_candidates": [
|
|
37
|
+
["safari", "chrome", "firefox"],
|
|
38
|
+
["safari_ios", "chrome_android"],
|
|
39
|
+
],
|
|
40
|
+
"referer_strategies": ["self_root", "google_search", "none"],
|
|
41
|
+
"url_transform_order": ["original", "mobile_subdomain"],
|
|
42
|
+
"fallback_when_challenge": ["playwright_mcp", "playwright_real_chrome"],
|
|
43
|
+
"notes": "in-code default — waf_profiles.yaml unavailable",
|
|
44
|
+
},
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
|
|
48
|
+
# Module-level sticky error. Readers call `last_load_error()` after each
|
|
49
|
+
# `_load_profiles()` call to surface YAML problems in FetchResult.trace.
|
|
50
|
+
_LAST_LOAD_ERROR: Optional[str] = None
|
|
51
|
+
|
|
52
|
+
|
|
53
|
+
@dataclass
|
|
54
|
+
class DetectionHit:
|
|
55
|
+
profile_id: str
|
|
56
|
+
confidence: float
|
|
57
|
+
signals: list[str]
|
|
58
|
+
|
|
59
|
+
|
|
60
|
+
def last_load_error() -> Optional[str]:
|
|
61
|
+
"""Return the most recent profile-loader error (or None if clean)."""
|
|
62
|
+
return _LAST_LOAD_ERROR
|
|
63
|
+
|
|
64
|
+
|
|
65
|
+
def _load_profiles(path: str = PROFILES_PATH) -> dict:
|
|
66
|
+
"""Load profiles with graceful fallback.
|
|
67
|
+
|
|
68
|
+
Never raises. On any failure (PyYAML missing, file missing, parse error,
|
|
69
|
+
unexpected shape) it returns a copy of `_DEFAULT_PROFILES` and stores
|
|
70
|
+
the reason in `_LAST_LOAD_ERROR` for the caller to surface.
|
|
71
|
+
"""
|
|
72
|
+
global _LAST_LOAD_ERROR
|
|
73
|
+
_LAST_LOAD_ERROR = None
|
|
74
|
+
|
|
75
|
+
if yaml is None:
|
|
76
|
+
_LAST_LOAD_ERROR = "PyYAML not installed — using in-code default profile"
|
|
77
|
+
return dict(_DEFAULT_PROFILES)
|
|
78
|
+
try:
|
|
79
|
+
with open(path, "r", encoding="utf-8") as f:
|
|
80
|
+
loaded = yaml.safe_load(f) or {}
|
|
81
|
+
except FileNotFoundError:
|
|
82
|
+
_LAST_LOAD_ERROR = f"waf_profiles.yaml not found at {path}"
|
|
83
|
+
return dict(_DEFAULT_PROFILES)
|
|
84
|
+
except yaml.YAMLError as e:
|
|
85
|
+
_LAST_LOAD_ERROR = f"YAML parse error: {type(e).__name__}: {str(e)[:200]}"
|
|
86
|
+
return dict(_DEFAULT_PROFILES)
|
|
87
|
+
except Exception as e:
|
|
88
|
+
_LAST_LOAD_ERROR = f"profile loader: {type(e).__name__}: {str(e)[:200]}"
|
|
89
|
+
return dict(_DEFAULT_PROFILES)
|
|
90
|
+
|
|
91
|
+
if not isinstance(loaded, dict) or not any(k for k in loaded if not k.startswith("_")):
|
|
92
|
+
_LAST_LOAD_ERROR = f"waf_profiles.yaml has no usable profiles"
|
|
93
|
+
return dict(_DEFAULT_PROFILES)
|
|
94
|
+
|
|
95
|
+
return loaded
|
|
96
|
+
|
|
97
|
+
|
|
98
|
+
def _cookies_dict(resp) -> dict:
|
|
99
|
+
try:
|
|
100
|
+
return {c.name: c.value for c in resp.cookies.jar}
|
|
101
|
+
except Exception:
|
|
102
|
+
try:
|
|
103
|
+
return dict(resp.cookies) if hasattr(resp, "cookies") else {}
|
|
104
|
+
except Exception:
|
|
105
|
+
return {}
|
|
106
|
+
|
|
107
|
+
|
|
108
|
+
def _headers_dict(resp) -> dict:
|
|
109
|
+
try:
|
|
110
|
+
return {k.lower(): v for k, v in dict(resp.headers).items()}
|
|
111
|
+
except Exception:
|
|
112
|
+
return {}
|
|
113
|
+
|
|
114
|
+
|
|
115
|
+
def _match_patterns(haystack_keys: list[str], patterns: list[str]) -> list[str]:
|
|
116
|
+
"""Match literal names or fnmatch patterns (for wildcards like `X-Akamai-*`)."""
|
|
117
|
+
hits: list[str] = []
|
|
118
|
+
lowered_keys = [k.lower() for k in haystack_keys]
|
|
119
|
+
for pat in patterns or []:
|
|
120
|
+
pat_l = pat.lower()
|
|
121
|
+
if any(c in pat for c in "*?["):
|
|
122
|
+
for key in lowered_keys:
|
|
123
|
+
if fnmatch.fnmatchcase(key, pat_l):
|
|
124
|
+
hits.append(pat)
|
|
125
|
+
break
|
|
126
|
+
else:
|
|
127
|
+
if pat_l in lowered_keys:
|
|
128
|
+
hits.append(pat)
|
|
129
|
+
return hits
|
|
130
|
+
|
|
131
|
+
|
|
132
|
+
def _score_profile(profile_id: str, profile: dict, resp) -> Optional[DetectionHit]:
|
|
133
|
+
"""Apply profile detectors to resp. Returns hit or None."""
|
|
134
|
+
if profile_id.startswith("_"):
|
|
135
|
+
return None
|
|
136
|
+
detectors = profile.get("detectors") or {}
|
|
137
|
+
if not detectors and profile_id != "unknown_challenge":
|
|
138
|
+
return None
|
|
139
|
+
|
|
140
|
+
cookies = _cookies_dict(resp)
|
|
141
|
+
headers = _headers_dict(resp)
|
|
142
|
+
body = (getattr(resp, "text", "") or "").lower()
|
|
143
|
+
server = headers.get("server", "")
|
|
144
|
+
|
|
145
|
+
signals: list[str] = []
|
|
146
|
+
|
|
147
|
+
# Cookie detectors
|
|
148
|
+
cookie_pats = detectors.get("cookie") or []
|
|
149
|
+
for hit in _match_patterns(list(cookies.keys()), cookie_pats):
|
|
150
|
+
signals.append(f"cookie:{hit}")
|
|
151
|
+
|
|
152
|
+
# Header detectors
|
|
153
|
+
header_pats = detectors.get("header") or []
|
|
154
|
+
for hit in _match_patterns(list(headers.keys()), header_pats):
|
|
155
|
+
signals.append(f"header:{hit}")
|
|
156
|
+
|
|
157
|
+
# Server substring
|
|
158
|
+
for needle in detectors.get("server_contains") or []:
|
|
159
|
+
if needle.lower() in server:
|
|
160
|
+
signals.append(f"server:{needle}")
|
|
161
|
+
|
|
162
|
+
# Body markers
|
|
163
|
+
for needle in detectors.get("body") or []:
|
|
164
|
+
if needle.lower() in body:
|
|
165
|
+
signals.append(f"body:{needle}")
|
|
166
|
+
|
|
167
|
+
if not signals:
|
|
168
|
+
return None
|
|
169
|
+
|
|
170
|
+
rules = profile.get("confidence_rules") or {"strong": 2, "weak": 1}
|
|
171
|
+
n = len(signals)
|
|
172
|
+
if n >= rules.get("strong", 2):
|
|
173
|
+
conf = 0.9
|
|
174
|
+
elif n >= rules.get("weak", 1):
|
|
175
|
+
conf = 0.6
|
|
176
|
+
else:
|
|
177
|
+
conf = 0.3
|
|
178
|
+
|
|
179
|
+
return DetectionHit(profile_id=profile_id, confidence=conf, signals=signals)
|
|
180
|
+
|
|
181
|
+
|
|
182
|
+
def detect(resp, *, profiles: Optional[dict] = None, min_confidence: float = 0.0) -> list[DetectionHit]:
|
|
183
|
+
"""Return ranked list of detection hits (best first).
|
|
184
|
+
|
|
185
|
+
When nothing fires, the returned list contains a single `unknown_challenge`
|
|
186
|
+
hit with confidence 0.1 — caller can use its conservative settings.
|
|
187
|
+
"""
|
|
188
|
+
if profiles is None:
|
|
189
|
+
profiles = _load_profiles()
|
|
190
|
+
|
|
191
|
+
hits: list[DetectionHit] = []
|
|
192
|
+
for profile_id, profile in profiles.items():
|
|
193
|
+
if profile_id.startswith("_"):
|
|
194
|
+
continue
|
|
195
|
+
h = _score_profile(profile_id, profile, resp)
|
|
196
|
+
if h and h.confidence >= min_confidence:
|
|
197
|
+
hits.append(h)
|
|
198
|
+
|
|
199
|
+
hits.sort(key=lambda x: x.confidence, reverse=True)
|
|
200
|
+
|
|
201
|
+
if not hits:
|
|
202
|
+
hits.append(DetectionHit(
|
|
203
|
+
profile_id="unknown_challenge",
|
|
204
|
+
confidence=0.1,
|
|
205
|
+
signals=["fallback"],
|
|
206
|
+
))
|
|
207
|
+
return hits
|
|
208
|
+
|
|
209
|
+
|
|
210
|
+
def load_profile(profile_id: str, *, profiles: Optional[dict] = None) -> dict:
|
|
211
|
+
"""Get one profile by id, resolving `unknown_challenge` if missing."""
|
|
212
|
+
if profiles is None:
|
|
213
|
+
profiles = _load_profiles()
|
|
214
|
+
return profiles.get(profile_id) or profiles.get("unknown_challenge") or {}
|
|
@@ -0,0 +1,162 @@
|
|
|
1
|
+
# WAF Product Profiles — never site-specific.
|
|
2
|
+
#
|
|
3
|
+
# NO-SITE-NAME RULE:
|
|
4
|
+
# * Key names are WAF products (akamai_bot_manager), not sites.
|
|
5
|
+
# * Detectors use product artifacts (cookies / headers / vendor strings).
|
|
6
|
+
# * Field values (markers, cookie names) must appear in any site running
|
|
7
|
+
# that WAF, not just one. If a value only fits one site, it belongs
|
|
8
|
+
# to runtime hints / observations, not this file.
|
|
9
|
+
#
|
|
10
|
+
# Profiles are *recommendations*, not deterministic recipes. The planner
|
|
11
|
+
# treats them as priors; attempts always evaluate real responses.
|
|
12
|
+
#
|
|
13
|
+
# Timestamp each profile entry. If stale (> 6 months), cross-validate.
|
|
14
|
+
|
|
15
|
+
_meta:
|
|
16
|
+
schema_version: 1
|
|
17
|
+
last_reviewed: "2026-04-21"
|
|
18
|
+
|
|
19
|
+
akamai_bot_manager:
|
|
20
|
+
detectors:
|
|
21
|
+
cookie: ["_abck", "bm_sz", "ak_bmsc", "bm_sv", "bm_so"]
|
|
22
|
+
header: ["X-Akamai-*"]
|
|
23
|
+
server_contains: ["AkamaiGHost"]
|
|
24
|
+
body: ["sec-if-cpt-container", "Powered and protected by Akamai"]
|
|
25
|
+
confidence_rules:
|
|
26
|
+
# Multi-signal gating — single marker insufficient.
|
|
27
|
+
strong: 2 # any 2 signals from above → confidence 0.9
|
|
28
|
+
weak: 1 # 1 signal → confidence 0.6
|
|
29
|
+
capabilities_needed:
|
|
30
|
+
- needs_real_tls_stack # Playwright Chromium (BoringSSL) is detected
|
|
31
|
+
- needs_js_exec # 2.6KB challenge requires JS sensor
|
|
32
|
+
tls_impersonate_candidates:
|
|
33
|
+
# Every impersonate target curl_cffi supports that historically yielded
|
|
34
|
+
# at least a challenge page (i.e. IP still alive) rather than an outright
|
|
35
|
+
# TLS reject. Grouped by family; planner tries top groups first.
|
|
36
|
+
# Refresh quarterly — vendor WAFs shift which TLS fingerprints they trust.
|
|
37
|
+
- [safari, safari15_3, safari15_5, safari17_0, safari260]
|
|
38
|
+
- [safari_ios, safari17_2_ios, safari260_ios]
|
|
39
|
+
- [chrome99, chrome100, chrome101, chrome104, chrome110, chrome116, chrome119, chrome124, chrome131, chrome133a, chrome136, chrome145, chrome146]
|
|
40
|
+
- [chrome_android, chrome131_android]
|
|
41
|
+
- [edge99, edge101]
|
|
42
|
+
tls_impersonate_avoid:
|
|
43
|
+
# Empirically observed to 403 immediately (TLS fingerprint blacklisted).
|
|
44
|
+
# DO NOT hard-block — planner deprioritizes only. Refresh quarterly.
|
|
45
|
+
- safari18_0
|
|
46
|
+
- chrome107
|
|
47
|
+
- chrome120
|
|
48
|
+
- chrome123
|
|
49
|
+
- chrome145 # curl_cffi 0.11+ needed — mark avoid for older installs
|
|
50
|
+
- chrome146
|
|
51
|
+
- firefox
|
|
52
|
+
- firefox133
|
|
53
|
+
- firefox135
|
|
54
|
+
referer_strategies:
|
|
55
|
+
- self_root # scheme://host/
|
|
56
|
+
url_transform_order:
|
|
57
|
+
- original
|
|
58
|
+
- mobile_subdomain # www.* → m.* — strong observational win in SSR sites
|
|
59
|
+
fallback_when_challenge:
|
|
60
|
+
- curl_grid_exhaust # try more impersonate × referer × url combos
|
|
61
|
+
- playwright_real_chrome
|
|
62
|
+
notes: |
|
|
63
|
+
DO NOT encode site-specific selectors or byte-size fingerprints here.
|
|
64
|
+
Those belong to caller's success_selectors param or observations log.
|
|
65
|
+
|
|
66
|
+
cloudflare_turnstile:
|
|
67
|
+
detectors:
|
|
68
|
+
cookie: ["cf_clearance", "__cf_bm", "__cfduid"]
|
|
69
|
+
header: ["cf-ray", "cf-cache-status"]
|
|
70
|
+
server_contains: ["cloudflare"]
|
|
71
|
+
body: ["Just a moment...", "Checking your browser", "cf-chl-bypass", "Attention Required! | Cloudflare"]
|
|
72
|
+
capabilities_needed:
|
|
73
|
+
- needs_js_exec # MCP Playwright Chromium OK — no real-TLS required
|
|
74
|
+
tls_impersonate_candidates:
|
|
75
|
+
- [chrome, chrome_android]
|
|
76
|
+
referer_strategies:
|
|
77
|
+
- google_search
|
|
78
|
+
- self_root
|
|
79
|
+
fallback_when_challenge:
|
|
80
|
+
- playwright_mcp # MCP sufficient; Chromium TLS passes CF baseline
|
|
81
|
+
- playwright_real_chrome
|
|
82
|
+
|
|
83
|
+
f5_big_ip:
|
|
84
|
+
detectors:
|
|
85
|
+
cookie: ["BigIPServer", "TS01*", "F5_*"]
|
|
86
|
+
body: ["The requested URL was rejected", "support ID is:"]
|
|
87
|
+
capabilities_needed:
|
|
88
|
+
- needs_real_tls_stack
|
|
89
|
+
tls_impersonate_candidates:
|
|
90
|
+
- [safari, chrome]
|
|
91
|
+
referer_strategies:
|
|
92
|
+
- self_root
|
|
93
|
+
|
|
94
|
+
aws_waf:
|
|
95
|
+
detectors:
|
|
96
|
+
cookie: ["aws-waf-token"]
|
|
97
|
+
header: ["x-amzn-requestid", "x-amzn-errortype", "x-amzn-waf-*"]
|
|
98
|
+
capabilities_needed:
|
|
99
|
+
- needs_real_tls_stack
|
|
100
|
+
tls_impersonate_candidates:
|
|
101
|
+
- [chrome]
|
|
102
|
+
referer_strategies:
|
|
103
|
+
- self_root
|
|
104
|
+
|
|
105
|
+
datadome_probable:
|
|
106
|
+
detectors:
|
|
107
|
+
cookie: ["datadome"]
|
|
108
|
+
body: ["DataDome"]
|
|
109
|
+
capabilities_needed:
|
|
110
|
+
- needs_real_tls_stack
|
|
111
|
+
- needs_js_exec
|
|
112
|
+
tls_impersonate_candidates:
|
|
113
|
+
- [safari, chrome]
|
|
114
|
+
fallback_when_challenge:
|
|
115
|
+
- playwright_real_chrome
|
|
116
|
+
notes: |
|
|
117
|
+
"_probable" suffix reminds us this is a growing attack surface — mark
|
|
118
|
+
as tentative until cross-site evidence accumulates in observations/.
|
|
119
|
+
|
|
120
|
+
perimeterx_human:
|
|
121
|
+
detectors:
|
|
122
|
+
cookie: ["_px3", "_pxhd", "_px2", "pxcts"]
|
|
123
|
+
body: ["px-captcha", "Press & Hold to confirm you are a human"]
|
|
124
|
+
capabilities_needed:
|
|
125
|
+
- needs_real_tls_stack
|
|
126
|
+
- needs_js_exec
|
|
127
|
+
tls_impersonate_candidates:
|
|
128
|
+
- [safari, chrome]
|
|
129
|
+
fallback_when_challenge:
|
|
130
|
+
- playwright_real_chrome
|
|
131
|
+
notes: |
|
|
132
|
+
PerimeterX (now HUMAN Bot Defender). Distinct cookie family from
|
|
133
|
+
DataDome. Keep profiles separate so planner does not pick wrong
|
|
134
|
+
fallback strategy.
|
|
135
|
+
|
|
136
|
+
# ---------------------------------------------------------------------------
|
|
137
|
+
# Safety net: always-valid fallback profile.
|
|
138
|
+
# ---------------------------------------------------------------------------
|
|
139
|
+
unknown_challenge:
|
|
140
|
+
detectors: {} # never matches actively — used only when no other profile fires
|
|
141
|
+
confidence_rules:
|
|
142
|
+
strong: 0
|
|
143
|
+
weak: 0
|
|
144
|
+
capabilities_needed:
|
|
145
|
+
- needs_js_exec # conservative default
|
|
146
|
+
tls_impersonate_candidates:
|
|
147
|
+
- [safari, chrome, firefox]
|
|
148
|
+
- [safari_ios, chrome_android]
|
|
149
|
+
referer_strategies:
|
|
150
|
+
- self_root
|
|
151
|
+
- google_search
|
|
152
|
+
- none
|
|
153
|
+
url_transform_order:
|
|
154
|
+
- original
|
|
155
|
+
- mobile_subdomain
|
|
156
|
+
fallback_when_challenge:
|
|
157
|
+
- playwright_mcp
|
|
158
|
+
- playwright_real_chrome
|
|
159
|
+
notes: |
|
|
160
|
+
When detector returns low-confidence results we land here. Broad,
|
|
161
|
+
conservative grid. Evidence from these runs should feed observations/
|
|
162
|
+
for eventual profile promotion.
|