oh-my-opencode 4.12.1 → 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 +896 -669
- package/dist/cli-node/index.js +896 -669
- 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 +708 -413
- 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 +23 -4
- package/dist/skills/ulw-plan/SKILL.md +4 -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 +9 -1
- package/package.json +16 -14
- package/packages/omo-codex/THIRD-PARTY-NOTICES.md +27 -4
- package/packages/omo-codex/plugin/.codex-plugin/plugin.json +1 -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 +323 -39
- package/packages/omo-codex/plugin/components/codegraph/dist/serve.js +292 -19
- package/packages/omo-codex/plugin/components/codegraph/package.json +9 -3
- package/packages/omo-codex/plugin/components/codegraph/src/mcp-unavailable.ts +75 -0
- package/packages/omo-codex/plugin/components/codegraph/src/serve.ts +29 -13
- package/packages/omo-codex/plugin/components/codegraph/src/session-start-worker.ts +20 -7
- package/packages/omo-codex/plugin/components/codegraph/test/hook.test.ts +1 -243
- 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 +1 -1
- 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-unavailable.test.ts +133 -0
- package/packages/omo-codex/plugin/components/codegraph/test/serve.test.ts +1 -113
- package/packages/omo-codex/plugin/components/codegraph/test/session-start-node-support.test.ts +8 -1
- 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/package.json +1 -1
- 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/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/package-lock.json +112 -13
- package/packages/omo-codex/plugin/package.json +2 -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/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 +23 -4
- 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/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-codegraph-mcp-smoke.test.mjs +76 -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 +30 -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 +520 -216
- 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 +23 -4
- 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
package/packages/omo-codex/plugin/skills/ultimate-browsing/references/insane-search/twitter.md
ADDED
|
@@ -0,0 +1,104 @@
|
|
|
1
|
+
# X/Twitter 접근 전략
|
|
2
|
+
|
|
3
|
+
> WebFetch는 402로 차단됨. 아래 방법으로 우회한다. 모두 API 키/인증 불필요.
|
|
4
|
+
|
|
5
|
+
## 검색 (트윗 발견)
|
|
6
|
+
|
|
7
|
+
```python
|
|
8
|
+
WebSearch(query="site:x.com {검색어}")
|
|
9
|
+
```
|
|
10
|
+
|
|
11
|
+
WebSearch는 X 포스트를 검색 결과로 반환한다. 제목, snippet, URL을 획득할 수 있지만 트윗 전문이나 engagement 수치는 없다.
|
|
12
|
+
|
|
13
|
+
## 타임라인 조회 — Syndication API
|
|
14
|
+
|
|
15
|
+
특정 핸들의 최근 ~100개 트윗 + engagement 수치(likes, RTs) 제공.
|
|
16
|
+
|
|
17
|
+
### 엔드포인트
|
|
18
|
+
|
|
19
|
+
```
|
|
20
|
+
https://syndication.twitter.com/srv/timeline-profile/screen-name/{handle}
|
|
21
|
+
```
|
|
22
|
+
|
|
23
|
+
### 원샷 스크립트
|
|
24
|
+
|
|
25
|
+
```bash
|
|
26
|
+
curl -sL "https://syndication.twitter.com/srv/timeline-profile/screen-name/{handle}" | \
|
|
27
|
+
python3 -c "
|
|
28
|
+
import sys, json, re, html
|
|
29
|
+
content = sys.stdin.read()
|
|
30
|
+
match = re.search(r'__NEXT_DATA__.*?>(.*?)</script>', content)
|
|
31
|
+
if match:
|
|
32
|
+
data = json.loads(match.group(1))
|
|
33
|
+
for e in data['props']['pageProps']['timeline']['entries']:
|
|
34
|
+
if e['type'] == 'tweet':
|
|
35
|
+
t = e['content']['tweet']
|
|
36
|
+
print(f\"@{t['user']['screen_name']} ({t.get('created_at','?')})\")
|
|
37
|
+
print(f\" {html.unescape(t.get('full_text',''))[:300]}\")
|
|
38
|
+
print(f\" Likes: {t.get('favorite_count',0)} | RTs: {t.get('retweet_count',0)}\")
|
|
39
|
+
print('---')
|
|
40
|
+
"
|
|
41
|
+
```
|
|
42
|
+
|
|
43
|
+
### 가져올 수 있는 데이터
|
|
44
|
+
|
|
45
|
+
| 필드 | 경로 | 예시 |
|
|
46
|
+
|------|------|------|
|
|
47
|
+
| 트윗 전문 | `tweet.full_text` | "Give your agent the..." |
|
|
48
|
+
| 작성자 핸들 | `tweet.user.screen_name` | "openclaw" |
|
|
49
|
+
| 작성자 이름 | `tweet.user.name` | "OpenClaw" |
|
|
50
|
+
| 좋아요 수 | `tweet.favorite_count` | 1929 |
|
|
51
|
+
| RT 수 | `tweet.retweet_count` | 169 |
|
|
52
|
+
| 작성 시각 | `tweet.created_at` | "Mon Apr 06 04:04:08 +0000 2026" |
|
|
53
|
+
| 트윗 ID | `tweet.id_str` | "2041003999856406714" |
|
|
54
|
+
| 미디어 URL | `tweet.entities.media[].media_url_https` | 이미지/동영상 URL |
|
|
55
|
+
|
|
56
|
+
### 제한
|
|
57
|
+
|
|
58
|
+
- 최근 ~100개 반환 (페이지네이션 불가)
|
|
59
|
+
- 비공개 계정 접근 불가
|
|
60
|
+
- 검색 기능 없음 (타임라인만)
|
|
61
|
+
- **저팔로워/신규 계정**: `hasResults: false` 반환 가능. 이 경우 oEmbed 개별 트윗 접근은 정상 동작하므로 "조합 패턴"으로 폴백.
|
|
62
|
+
- 비공식 엔드포인트 — X가 변경/차단 가능
|
|
63
|
+
|
|
64
|
+
## 개별 트윗 조회 — oEmbed API
|
|
65
|
+
|
|
66
|
+
특정 트윗 URL을 알 때 전문 가져오기.
|
|
67
|
+
|
|
68
|
+
### 엔드포인트
|
|
69
|
+
|
|
70
|
+
```
|
|
71
|
+
https://publish.twitter.com/oembed?url=https://x.com/{user}/status/{tweet_id}
|
|
72
|
+
```
|
|
73
|
+
|
|
74
|
+
### 사용법
|
|
75
|
+
|
|
76
|
+
```bash
|
|
77
|
+
curl -sL "https://publish.twitter.com/oembed?url=https://x.com/{user}/status/{tweet_id}"
|
|
78
|
+
```
|
|
79
|
+
|
|
80
|
+
### 응답 (JSON)
|
|
81
|
+
|
|
82
|
+
| 필드 | 설명 |
|
|
83
|
+
|------|------|
|
|
84
|
+
| `author_name` | 작성자 표시 이름 |
|
|
85
|
+
| `author_url` | 작성자 프로필 URL |
|
|
86
|
+
| `html` | 트윗 전문이 포함된 HTML blockquote |
|
|
87
|
+
| `url` | 트윗 원본 URL |
|
|
88
|
+
|
|
89
|
+
## 조합 패턴 (검색 → 상세)
|
|
90
|
+
|
|
91
|
+
```
|
|
92
|
+
1단계: WebSearch(query="site:x.com {키워드}") → 트윗 URL 획득
|
|
93
|
+
2단계: curl oEmbed API → 트윗 전문 획득
|
|
94
|
+
```
|
|
95
|
+
|
|
96
|
+
## 실패하는 방법 (사용하지 말 것)
|
|
97
|
+
|
|
98
|
+
| 방법 | 결과 | 원인 |
|
|
99
|
+
|------|------|------|
|
|
100
|
+
| WebFetch | 402 Payment Required | Claude Code의 WebFetch 제한 |
|
|
101
|
+
| Nitter | 빈 응답 | Nitter 인스턴스 대부분 종료됨 |
|
|
102
|
+
| Wayback Machine | OG 메타태그만 | SPA 렌더링 안 됨 |
|
|
103
|
+
| Mobile UA curl | OG 메타태그만 | SPA 렌더링 안 됨 |
|
|
104
|
+
| RSS | 엔드포인트 없음 | X는 RSS 지원 중단 |
|
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
"""Pure key derivation + value decryption, with the OS-keyring read injected."""
|
|
2
|
+
from __future__ import annotations
|
|
3
|
+
|
|
4
|
+
import base64
|
|
5
|
+
import json
|
|
6
|
+
import subprocess
|
|
7
|
+
from pathlib import Path
|
|
8
|
+
|
|
9
|
+
from cookie_paths import UnsupportedPlatform
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
def derive_key(platform: str, secret: bytes) -> bytes:
|
|
13
|
+
if platform == "win32":
|
|
14
|
+
if len(secret) != 32:
|
|
15
|
+
raise ValueError(f"win32 os_crypt key must be 32 bytes, got {len(secret)}")
|
|
16
|
+
return secret
|
|
17
|
+
if platform in ("darwin", "linux"):
|
|
18
|
+
from cryptography.hazmat.primitives import hashes
|
|
19
|
+
from cryptography.hazmat.primitives.kdf.pbkdf2 import PBKDF2HMAC
|
|
20
|
+
|
|
21
|
+
iterations = 1003 if platform == "darwin" else 1
|
|
22
|
+
return PBKDF2HMAC(algorithm=hashes.SHA1(), length=16, salt=b"saltysalt", iterations=iterations).derive(secret)
|
|
23
|
+
raise UnsupportedPlatform(f"unsupported platform for key derivation: {platform!r}")
|
|
24
|
+
|
|
25
|
+
|
|
26
|
+
def decrypt_chromium_value(platform: str, key: bytes, encrypted: bytes) -> str:
|
|
27
|
+
if not encrypted:
|
|
28
|
+
return ""
|
|
29
|
+
prefix = encrypted[:3]
|
|
30
|
+
if prefix in (b"v10", b"v11") and platform == "win32":
|
|
31
|
+
from cryptography.hazmat.primitives.ciphers import Cipher, algorithms, modes
|
|
32
|
+
|
|
33
|
+
nonce, ciphertext, tag = encrypted[3:15], encrypted[15:-16], encrypted[-16:]
|
|
34
|
+
decryptor = Cipher(algorithms.AES(key), modes.GCM(nonce, tag)).decryptor()
|
|
35
|
+
return (decryptor.update(ciphertext) + decryptor.finalize()).decode("utf-8", errors="replace")
|
|
36
|
+
if prefix in (b"v10", b"v11"):
|
|
37
|
+
from cryptography.hazmat.primitives.ciphers import Cipher, algorithms, modes
|
|
38
|
+
|
|
39
|
+
decryptor = Cipher(algorithms.AES128(key), modes.CBC(b" " * 16)).decryptor()
|
|
40
|
+
decrypted = decryptor.update(encrypted[3:]) + decryptor.finalize()
|
|
41
|
+
pad = decrypted[-1]
|
|
42
|
+
if isinstance(pad, int) and 1 <= pad <= 16:
|
|
43
|
+
decrypted = decrypted[:-pad]
|
|
44
|
+
return decrypted.decode("utf-8", errors="replace")
|
|
45
|
+
return encrypted.decode("utf-8", errors="replace")
|
|
46
|
+
|
|
47
|
+
|
|
48
|
+
def macos_keyring_secret(safe_storage: str) -> bytes:
|
|
49
|
+
result = subprocess.run(
|
|
50
|
+
["security", "find-generic-password", "-s", safe_storage, "-w"],
|
|
51
|
+
capture_output=True, text=True, timeout=30,
|
|
52
|
+
)
|
|
53
|
+
if result.returncode != 0:
|
|
54
|
+
raise RuntimeError(f"cannot read {safe_storage} from Keychain: {result.stderr.strip()}")
|
|
55
|
+
return result.stdout.strip().encode()
|
|
56
|
+
|
|
57
|
+
|
|
58
|
+
def linux_keyring_secret(safe_storage: str) -> bytes:
|
|
59
|
+
try:
|
|
60
|
+
import secretstorage
|
|
61
|
+
except ImportError:
|
|
62
|
+
return b"peanuts"
|
|
63
|
+
conn = secretstorage.dbus_init()
|
|
64
|
+
for item in secretstorage.get_default_collection(conn).get_all_items():
|
|
65
|
+
if item.get_label() == safe_storage:
|
|
66
|
+
return item.get_secret()
|
|
67
|
+
return b"peanuts"
|
|
68
|
+
|
|
69
|
+
|
|
70
|
+
def windows_oscrypt_key(local_state_path: Path) -> bytes:
|
|
71
|
+
state = json.loads(local_state_path.read_text())
|
|
72
|
+
blob = base64.b64decode(state["os_crypt"]["encrypted_key"])[5:]
|
|
73
|
+
import win32crypt
|
|
74
|
+
|
|
75
|
+
return win32crypt.CryptUnprotectData(blob, None, None, None, 0)[1]
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
SQL_LIKE_ESCAPE = "\\"
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
class CookieDomainError(ValueError):
|
|
7
|
+
pass
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
def normalize_cookie_domain(domain: str) -> str:
|
|
11
|
+
normalized = domain.strip().lower().lstrip(".")
|
|
12
|
+
if not normalized:
|
|
13
|
+
raise CookieDomainError("cookie domain must not be empty")
|
|
14
|
+
return normalized
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
def escape_sql_like(value: str) -> str:
|
|
18
|
+
return (
|
|
19
|
+
value
|
|
20
|
+
.replace(SQL_LIKE_ESCAPE, SQL_LIKE_ESCAPE * 2)
|
|
21
|
+
.replace("%", f"{SQL_LIKE_ESCAPE}%")
|
|
22
|
+
.replace("_", f"{SQL_LIKE_ESCAPE}_")
|
|
23
|
+
)
|
|
24
|
+
|
|
25
|
+
|
|
26
|
+
def domain_where_clause(column: str, domains: list[str]) -> tuple[str, list[str]]:
|
|
27
|
+
normalized_domains = sorted({normalize_cookie_domain(domain) for domain in domains})
|
|
28
|
+
if not normalized_domains:
|
|
29
|
+
raise CookieDomainError("at least one cookie domain is required")
|
|
30
|
+
|
|
31
|
+
clauses: list[str] = []
|
|
32
|
+
params: list[str] = []
|
|
33
|
+
for domain in normalized_domains:
|
|
34
|
+
clauses.append(
|
|
35
|
+
f"({column} = ? OR {column} = ? OR {column} LIKE ? ESCAPE '{SQL_LIKE_ESCAPE}')"
|
|
36
|
+
)
|
|
37
|
+
params.extend([domain, f".{domain}", f"%.{escape_sql_like(domain)}"])
|
|
38
|
+
return " OR ".join(clauses), params
|
|
@@ -0,0 +1,112 @@
|
|
|
1
|
+
"""Pure profile-path resolution for cross-platform cookie extraction."""
|
|
2
|
+
from __future__ import annotations
|
|
3
|
+
|
|
4
|
+
import os
|
|
5
|
+
from pathlib import Path
|
|
6
|
+
from typing import Final, Literal, TypedDict, assert_never
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
class UnsupportedPlatform(ValueError):
|
|
10
|
+
"""Raised when a browser/platform combination is not supported."""
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
BrowserKind = Literal["chromium", "firefox"]
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
class BrowserDirs(TypedDict):
|
|
17
|
+
darwin: str
|
|
18
|
+
linux: str
|
|
19
|
+
win32: str
|
|
20
|
+
|
|
21
|
+
|
|
22
|
+
class BrowserSpec(TypedDict):
|
|
23
|
+
kind: BrowserKind
|
|
24
|
+
safe_storage: str | None
|
|
25
|
+
dirs: BrowserDirs
|
|
26
|
+
|
|
27
|
+
|
|
28
|
+
BROWSERS: Final[dict[str, BrowserSpec]] = {
|
|
29
|
+
"chrome": {
|
|
30
|
+
"kind": "chromium",
|
|
31
|
+
"safe_storage": "Chrome Safe Storage",
|
|
32
|
+
"dirs": {"darwin": "Google/Chrome", "linux": "google-chrome", "win32": "Google/Chrome/User Data"},
|
|
33
|
+
},
|
|
34
|
+
"brave": {
|
|
35
|
+
"kind": "chromium",
|
|
36
|
+
"safe_storage": "Brave Safe Storage",
|
|
37
|
+
"dirs": {
|
|
38
|
+
"darwin": "BraveSoftware/Brave-Browser",
|
|
39
|
+
"linux": "BraveSoftware/Brave-Browser",
|
|
40
|
+
"win32": "BraveSoftware/Brave-Browser/User Data",
|
|
41
|
+
},
|
|
42
|
+
},
|
|
43
|
+
"chromium": {
|
|
44
|
+
"kind": "chromium",
|
|
45
|
+
"safe_storage": "Chromium Safe Storage",
|
|
46
|
+
"dirs": {"darwin": "Chromium", "linux": "chromium", "win32": "Chromium/User Data"},
|
|
47
|
+
},
|
|
48
|
+
"firefox": {
|
|
49
|
+
"kind": "firefox",
|
|
50
|
+
"safe_storage": None,
|
|
51
|
+
"dirs": {"darwin": "Firefox/Profiles", "linux": ".mozilla/firefox", "win32": "Mozilla/Firefox/Profiles"},
|
|
52
|
+
},
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
CHROMIUM_PROFILE_DIRS: Final = ["Default", "Profile 1", "Profile 2"]
|
|
56
|
+
|
|
57
|
+
|
|
58
|
+
def platform_base(platform: str, kind: BrowserKind) -> Path:
|
|
59
|
+
home = Path.home()
|
|
60
|
+
match platform:
|
|
61
|
+
case "darwin":
|
|
62
|
+
return home / "Library" / "Application Support"
|
|
63
|
+
case "linux":
|
|
64
|
+
match kind:
|
|
65
|
+
case "firefox":
|
|
66
|
+
return home
|
|
67
|
+
case "chromium":
|
|
68
|
+
return Path(os.environ.get("XDG_CONFIG_HOME", str(home / ".config")))
|
|
69
|
+
case unreachable:
|
|
70
|
+
assert_never(unreachable)
|
|
71
|
+
case "win32":
|
|
72
|
+
return Path(os.environ.get("LOCALAPPDATA", str(home / "AppData" / "Local")))
|
|
73
|
+
case _:
|
|
74
|
+
raise UnsupportedPlatform(f"unsupported platform: {platform!r}")
|
|
75
|
+
|
|
76
|
+
|
|
77
|
+
def browser_dir(spec: BrowserSpec, platform: str) -> str:
|
|
78
|
+
match platform:
|
|
79
|
+
case "darwin":
|
|
80
|
+
return spec["dirs"]["darwin"]
|
|
81
|
+
case "linux":
|
|
82
|
+
return spec["dirs"]["linux"]
|
|
83
|
+
case "win32":
|
|
84
|
+
return spec["dirs"]["win32"]
|
|
85
|
+
case _:
|
|
86
|
+
raise UnsupportedPlatform(f"browser not mapped for platform {platform!r}")
|
|
87
|
+
|
|
88
|
+
|
|
89
|
+
def resolve_cookie_db(browser: str, platform: str, base_override: Path | None = None) -> Path:
|
|
90
|
+
spec = BROWSERS.get(browser)
|
|
91
|
+
if spec is None:
|
|
92
|
+
raise UnsupportedPlatform(f"unsupported browser: {browser!r}")
|
|
93
|
+
base = base_override if base_override is not None else platform_base(platform, spec["kind"])
|
|
94
|
+
profile_root = base / browser_dir(spec, platform)
|
|
95
|
+
|
|
96
|
+
match spec["kind"]:
|
|
97
|
+
case "firefox":
|
|
98
|
+
if not profile_root.exists():
|
|
99
|
+
raise FileNotFoundError(f"no Firefox profile root at {profile_root}")
|
|
100
|
+
for entry in sorted(profile_root.iterdir()):
|
|
101
|
+
db = entry / "cookies.sqlite"
|
|
102
|
+
if db.exists():
|
|
103
|
+
return db
|
|
104
|
+
raise FileNotFoundError(f"no cookies.sqlite under {profile_root}")
|
|
105
|
+
case "chromium":
|
|
106
|
+
for profile in CHROMIUM_PROFILE_DIRS:
|
|
107
|
+
for candidate in (profile_root / profile / "Cookies", profile_root / profile / "Network" / "Cookies"):
|
|
108
|
+
if candidate.exists():
|
|
109
|
+
return candidate
|
|
110
|
+
raise FileNotFoundError(f"no Cookies DB under {profile_root}")
|
|
111
|
+
case unreachable:
|
|
112
|
+
assert_never(unreachable)
|
|
@@ -0,0 +1,280 @@
|
|
|
1
|
+
#!/usr/bin/env python3
|
|
2
|
+
"""Cross-platform browser cookie extraction for Tier-2 Chrome stealth.
|
|
3
|
+
|
|
4
|
+
The OS-keyring lookup is an injected boundary: cookie_paths resolves profile
|
|
5
|
+
paths and cookie_crypto derives keys + decrypts values, both pure and testable
|
|
6
|
+
with synthetic fixtures on any OS. This module wires them to a real browser DB
|
|
7
|
+
and the agent-browser CDP session.
|
|
8
|
+
|
|
9
|
+
Usage:
|
|
10
|
+
python extract_cookies.py --browser chrome --domain youtube.com --output /tmp/cookies.json
|
|
11
|
+
python extract_cookies.py --browser chrome --domain youtube.com --inject --cdp 9242
|
|
12
|
+
"""
|
|
13
|
+
from __future__ import annotations
|
|
14
|
+
|
|
15
|
+
import argparse
|
|
16
|
+
import json
|
|
17
|
+
import os
|
|
18
|
+
import shutil
|
|
19
|
+
import sqlite3
|
|
20
|
+
import subprocess
|
|
21
|
+
import sys
|
|
22
|
+
import tempfile
|
|
23
|
+
from pathlib import Path
|
|
24
|
+
from typing import Callable, NotRequired, TypedDict
|
|
25
|
+
|
|
26
|
+
from cookie_crypto import (
|
|
27
|
+
decrypt_chromium_value,
|
|
28
|
+
derive_key,
|
|
29
|
+
linux_keyring_secret,
|
|
30
|
+
macos_keyring_secret,
|
|
31
|
+
windows_oscrypt_key,
|
|
32
|
+
)
|
|
33
|
+
from cookie_domains import domain_where_clause
|
|
34
|
+
from cookie_paths import BROWSERS, BrowserSpec, UnsupportedPlatform, platform_base, resolve_cookie_db
|
|
35
|
+
|
|
36
|
+
_SAMESITE = {-1: "None", 0: "None", 1: "Lax", 2: "Strict"}
|
|
37
|
+
|
|
38
|
+
IMPORTANT_COOKIES = {
|
|
39
|
+
"SID", "SSID", "HSID", "APISID", "SAPISID",
|
|
40
|
+
"__Secure-1PSID", "__Secure-3PSID", "__Secure-1PSIDTS", "__Secure-3PSIDTS",
|
|
41
|
+
"LOGIN_INFO", "PREF", "VISITOR_INFO1_LIVE", "YSC", "NID", "CONSENT",
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
|
|
45
|
+
class CookieRecord(TypedDict):
|
|
46
|
+
name: str
|
|
47
|
+
value: str
|
|
48
|
+
domain: str
|
|
49
|
+
path: str
|
|
50
|
+
expires: int
|
|
51
|
+
secure: bool
|
|
52
|
+
httpOnly: bool
|
|
53
|
+
sameSite: str
|
|
54
|
+
|
|
55
|
+
|
|
56
|
+
class CdpCookie(TypedDict):
|
|
57
|
+
name: str
|
|
58
|
+
value: str
|
|
59
|
+
domain: str
|
|
60
|
+
path: str
|
|
61
|
+
secure: bool
|
|
62
|
+
httpOnly: bool
|
|
63
|
+
sameSite: str
|
|
64
|
+
expires: NotRequired[int]
|
|
65
|
+
|
|
66
|
+
|
|
67
|
+
_CDP_SET_COOKIES_SCRIPT = r"""
|
|
68
|
+
const port = Number(process.argv[1] || 0);
|
|
69
|
+
if (!Number.isInteger(port) || port <= 0) {
|
|
70
|
+
process.stderr.write("invalid CDP port\n");
|
|
71
|
+
process.exit(2);
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
let input = "";
|
|
75
|
+
process.stdin.setEncoding("utf8");
|
|
76
|
+
process.stdin.on("data", (chunk) => { input += chunk; });
|
|
77
|
+
process.stdin.on("end", () => {
|
|
78
|
+
(async () => {
|
|
79
|
+
const cookies = JSON.parse(input || "[]");
|
|
80
|
+
const version = await fetch(`http://127.0.0.1:${port}/json/version`).then((r) => r.json());
|
|
81
|
+
const ws = new WebSocket(version.webSocketDebuggerUrl);
|
|
82
|
+
let nextId = 1;
|
|
83
|
+
const pending = new Map();
|
|
84
|
+
|
|
85
|
+
ws.onmessage = (event) => {
|
|
86
|
+
const msg = JSON.parse(event.data);
|
|
87
|
+
const waiter = pending.get(msg.id);
|
|
88
|
+
if (!waiter) return;
|
|
89
|
+
pending.delete(msg.id);
|
|
90
|
+
if (msg.error) waiter.reject(new Error(msg.error.message || "CDP error"));
|
|
91
|
+
else waiter.resolve(msg.result);
|
|
92
|
+
};
|
|
93
|
+
|
|
94
|
+
await new Promise((resolve, reject) => {
|
|
95
|
+
ws.onopen = resolve;
|
|
96
|
+
ws.onerror = reject;
|
|
97
|
+
});
|
|
98
|
+
|
|
99
|
+
const send = (method, params) => new Promise((resolve, reject) => {
|
|
100
|
+
const id = nextId++;
|
|
101
|
+
pending.set(id, { resolve, reject });
|
|
102
|
+
ws.send(JSON.stringify({ id, method, params }));
|
|
103
|
+
});
|
|
104
|
+
|
|
105
|
+
let ok = 0;
|
|
106
|
+
for (const cookie of cookies) {
|
|
107
|
+
const result = await send("Network.setCookie", cookie);
|
|
108
|
+
if (result && result.success) ok += 1;
|
|
109
|
+
}
|
|
110
|
+
ws.close();
|
|
111
|
+
process.stdout.write(String(ok));
|
|
112
|
+
})().catch((error) => {
|
|
113
|
+
process.stderr.write(`${error.name || "Error"}: ${error.message || error}\n`);
|
|
114
|
+
process.exit(1);
|
|
115
|
+
});
|
|
116
|
+
});
|
|
117
|
+
"""
|
|
118
|
+
|
|
119
|
+
|
|
120
|
+
def _secure_cookie_db_copy(db_path: Path) -> Path:
|
|
121
|
+
handle = tempfile.NamedTemporaryFile(prefix="omo-cookies-", suffix=".sqlite", delete=False)
|
|
122
|
+
tmp = Path(handle.name)
|
|
123
|
+
handle.close()
|
|
124
|
+
try:
|
|
125
|
+
shutil.copyfile(db_path, tmp)
|
|
126
|
+
tmp.chmod(0o600)
|
|
127
|
+
return tmp
|
|
128
|
+
except (OSError, shutil.Error):
|
|
129
|
+
tmp.unlink(missing_ok=True)
|
|
130
|
+
raise
|
|
131
|
+
|
|
132
|
+
|
|
133
|
+
def write_cookie_file(path: Path, cookies: list[CookieRecord]) -> None:
|
|
134
|
+
if path.is_symlink():
|
|
135
|
+
raise ValueError(f"refusing to write cookies through symlink: {path}")
|
|
136
|
+
path.parent.mkdir(parents=True, exist_ok=True)
|
|
137
|
+
fd, tmp_name = tempfile.mkstemp(prefix=f".{path.name}.", suffix=".tmp", dir=str(path.parent))
|
|
138
|
+
tmp_path = Path(tmp_name)
|
|
139
|
+
try:
|
|
140
|
+
with os.fdopen(fd, "w", encoding="utf-8") as f:
|
|
141
|
+
os.fchmod(f.fileno(), 0o600)
|
|
142
|
+
json.dump(cookies, f, indent=2)
|
|
143
|
+
f.write("\n")
|
|
144
|
+
os.replace(tmp_path, path)
|
|
145
|
+
finally:
|
|
146
|
+
tmp_path.unlink(missing_ok=True)
|
|
147
|
+
|
|
148
|
+
|
|
149
|
+
def extract_firefox(db_path: Path, domains: list[str]) -> list[CookieRecord]:
|
|
150
|
+
tmp = _secure_cookie_db_copy(db_path)
|
|
151
|
+
try:
|
|
152
|
+
where, params = domain_where_clause("host", domains)
|
|
153
|
+
conn = sqlite3.connect(str(tmp))
|
|
154
|
+
rows = conn.execute(
|
|
155
|
+
f"SELECT name, value, host, path, expiry, isSecure, isHttpOnly, sameSite "
|
|
156
|
+
f"FROM moz_cookies WHERE ({where}) ORDER BY host, name",
|
|
157
|
+
params,
|
|
158
|
+
).fetchall()
|
|
159
|
+
conn.close()
|
|
160
|
+
finally:
|
|
161
|
+
tmp.unlink(missing_ok=True)
|
|
162
|
+
return [
|
|
163
|
+
{
|
|
164
|
+
"name": n, "value": v, "domain": h, "path": p, "expires": e,
|
|
165
|
+
"secure": bool(sec), "httpOnly": bool(ho), "sameSite": _SAMESITE.get(ss, "Lax"),
|
|
166
|
+
}
|
|
167
|
+
for n, v, h, p, e, sec, ho, ss in rows
|
|
168
|
+
]
|
|
169
|
+
|
|
170
|
+
|
|
171
|
+
def extract_chromium(db_path: Path, domains: list[str], platform: str, key: bytes) -> list[CookieRecord]:
|
|
172
|
+
tmp = _secure_cookie_db_copy(db_path)
|
|
173
|
+
try:
|
|
174
|
+
where, params = domain_where_clause("host_key", domains)
|
|
175
|
+
conn = sqlite3.connect(str(tmp))
|
|
176
|
+
rows = conn.execute(
|
|
177
|
+
f"SELECT name, encrypted_value, host_key, path, expires_utc, is_secure, is_httponly, samesite "
|
|
178
|
+
f"FROM cookies WHERE ({where}) ORDER BY host_key, name",
|
|
179
|
+
params,
|
|
180
|
+
).fetchall()
|
|
181
|
+
conn.close()
|
|
182
|
+
finally:
|
|
183
|
+
tmp.unlink(missing_ok=True)
|
|
184
|
+
out = []
|
|
185
|
+
for n, enc, h, p, exp, sec, ho, ss in rows:
|
|
186
|
+
unix_expires = int((exp / 1_000_000) - 11644473600) if exp and exp > 0 else 0
|
|
187
|
+
out.append({
|
|
188
|
+
"name": n, "value": decrypt_chromium_value(platform, key, enc), "domain": h, "path": p,
|
|
189
|
+
"expires": unix_expires, "secure": bool(sec), "httpOnly": bool(ho), "sameSite": _SAMESITE.get(ss, "Lax"),
|
|
190
|
+
})
|
|
191
|
+
return out
|
|
192
|
+
|
|
193
|
+
|
|
194
|
+
def _browser_spec(browser: str) -> BrowserSpec:
|
|
195
|
+
spec = BROWSERS.get(browser)
|
|
196
|
+
if spec is None:
|
|
197
|
+
raise UnsupportedPlatform(f"unsupported browser: {browser!r}")
|
|
198
|
+
return spec
|
|
199
|
+
|
|
200
|
+
|
|
201
|
+
def default_keyring_reader(platform: str, spec: BrowserSpec) -> Callable[[str], bytes]:
|
|
202
|
+
if platform == "darwin":
|
|
203
|
+
return macos_keyring_secret
|
|
204
|
+
if platform == "linux":
|
|
205
|
+
return linux_keyring_secret
|
|
206
|
+
if platform == "win32":
|
|
207
|
+
def _win(_safe_storage: str) -> bytes:
|
|
208
|
+
base = platform_base("win32", "chromium")
|
|
209
|
+
return windows_oscrypt_key(base / spec["dirs"]["win32"] / "Local State")
|
|
210
|
+
return _win
|
|
211
|
+
raise UnsupportedPlatform(f"no keyring reader for platform {platform!r}")
|
|
212
|
+
|
|
213
|
+
|
|
214
|
+
def extract_cookies(
|
|
215
|
+
browser: str,
|
|
216
|
+
domains: list[str],
|
|
217
|
+
platform: str = sys.platform,
|
|
218
|
+
keyring_reader: Callable[[str], bytes] | None = None,
|
|
219
|
+
base_override: Path | None = None,
|
|
220
|
+
) -> list[CookieRecord]:
|
|
221
|
+
spec = _browser_spec(browser)
|
|
222
|
+
db = resolve_cookie_db(browser, platform, base_override=base_override)
|
|
223
|
+
if spec["kind"] == "firefox":
|
|
224
|
+
return extract_firefox(db, domains)
|
|
225
|
+
reader = keyring_reader or default_keyring_reader(platform, spec)
|
|
226
|
+
safe_storage = spec["safe_storage"]
|
|
227
|
+
if safe_storage is None:
|
|
228
|
+
raise UnsupportedPlatform(f"browser {browser!r} has no keyring storage name")
|
|
229
|
+
key = derive_key(platform, reader(safe_storage))
|
|
230
|
+
return extract_chromium(db, domains, platform, key)
|
|
231
|
+
|
|
232
|
+
|
|
233
|
+
def inject_cookies(cookies: list[CookieRecord], cdp_port: int) -> None:
|
|
234
|
+
filtered = [c for c in cookies if c["name"] in IMPORTANT_COOKIES] or cookies
|
|
235
|
+
payload: list[CdpCookie] = [
|
|
236
|
+
{
|
|
237
|
+
"name": c["name"],
|
|
238
|
+
"value": c["value"],
|
|
239
|
+
"domain": c["domain"],
|
|
240
|
+
"path": c.get("path") or "/",
|
|
241
|
+
"secure": bool(c.get("secure")),
|
|
242
|
+
"httpOnly": bool(c.get("httpOnly")),
|
|
243
|
+
"sameSite": c.get("sameSite", "Lax"),
|
|
244
|
+
**({"expires": int(c["expires"])} if c.get("expires") and int(c["expires"]) > 0 else {}),
|
|
245
|
+
}
|
|
246
|
+
for c in filtered
|
|
247
|
+
]
|
|
248
|
+
proc = subprocess.run(
|
|
249
|
+
["node", "-e", _CDP_SET_COOKIES_SCRIPT, str(cdp_port)],
|
|
250
|
+
input=json.dumps(payload),
|
|
251
|
+
capture_output=True,
|
|
252
|
+
text=True,
|
|
253
|
+
timeout=15,
|
|
254
|
+
)
|
|
255
|
+
if proc.returncode != 0:
|
|
256
|
+
raise RuntimeError((proc.stderr or "CDP cookie injection failed").strip())
|
|
257
|
+
ok = int((proc.stdout or "0").strip() or "0")
|
|
258
|
+
print(f"Injected {ok}/{len(filtered)} cookies into agent-browser (CDP {cdp_port})")
|
|
259
|
+
|
|
260
|
+
|
|
261
|
+
def main() -> None:
|
|
262
|
+
parser = argparse.ArgumentParser(description="Extract browser cookies (cross-platform)")
|
|
263
|
+
parser.add_argument("--browser", required=True, choices=sorted(BROWSERS.keys()))
|
|
264
|
+
parser.add_argument("--domain", required=True, action="append", dest="domains")
|
|
265
|
+
parser.add_argument("--output", help="Write cookies JSON to file")
|
|
266
|
+
parser.add_argument("--inject", action="store_true", help="Inject into agent-browser")
|
|
267
|
+
parser.add_argument("--cdp", type=int, default=9242, help="CDP port (default 9242)")
|
|
268
|
+
args = parser.parse_args()
|
|
269
|
+
|
|
270
|
+
cookies = extract_cookies(args.browser, args.domains)
|
|
271
|
+
print(f"Extracted {len(cookies)} cookies from {args.browser}")
|
|
272
|
+
if args.output:
|
|
273
|
+
write_cookie_file(Path(args.output), cookies)
|
|
274
|
+
print(f"Saved to {args.output}")
|
|
275
|
+
if args.inject:
|
|
276
|
+
inject_cookies(cookies, args.cdp)
|
|
277
|
+
|
|
278
|
+
|
|
279
|
+
if __name__ == "__main__":
|
|
280
|
+
main()
|