luckiest-co 1.0.1 → 1.0.3
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/.claude-plugin/marketplace.json +16 -0
- package/.claude-plugin/plugin.json +1 -1
- package/LICENSE +24 -0
- package/bin/install.js +6 -4
- package/commands/{luckiest/finish.md → finish.md} +2 -0
- package/commands/go.md +53 -0
- package/commands/plan.md +66 -0
- package/package.json +3 -2
- package/skills/brainstorm/ATTRIBUTION.md +27 -0
- package/skills/brainstorm/SKILL.md +139 -0
- package/skills/luckiest-ab-testing/ATTRIBUTION.md +35 -0
- package/skills/luckiest-ab-testing/CHANGELOG.md +27 -0
- package/skills/luckiest-ab-testing/SKILL.md +379 -0
- package/skills/luckiest-ab-testing/evals/evals.json +118 -0
- package/skills/luckiest-ab-testing/references/sample-size-guide.md +290 -0
- package/skills/luckiest-ab-testing/references/test-templates.md +284 -0
- package/skills/luckiest-ad-creative/ATTRIBUTION.md +35 -0
- package/skills/luckiest-ad-creative/CHANGELOG.md +23 -0
- package/skills/luckiest-ad-creative/SKILL.md +393 -0
- package/skills/luckiest-ad-creative/evals/evals.json +90 -0
- package/skills/luckiest-ad-creative/references/generative-tools.md +637 -0
- package/skills/luckiest-ad-creative/references/platform-specs.md +213 -0
- package/skills/luckiest-ads/ATTRIBUTION.md +36 -0
- package/skills/luckiest-ads/CHANGELOG.md +24 -0
- package/skills/luckiest-ads/LICENSE +21 -0
- package/skills/luckiest-ads/SKILL.md +434 -0
- package/skills/luckiest-ads/evals/evals.json +90 -0
- package/skills/luckiest-ads/references/ad-copy-templates.md +207 -0
- package/skills/luckiest-ads/references/audience-targeting.md +243 -0
- package/skills/luckiest-ads/references/conversion-tracking.md +361 -0
- package/skills/luckiest-ads/references/platform-setup-checklists.md +277 -0
- package/skills/luckiest-advisors/ATTRIBUTION.md +16 -0
- package/skills/luckiest-advisors/CHANGELOG.md +99 -0
- package/skills/luckiest-advisors/SKILL.md +151 -0
- package/skills/luckiest-aeo-grader/ATTRIBUTION.md +19 -0
- package/skills/luckiest-aeo-grader/CHANGELOG.md +52 -0
- package/skills/luckiest-aeo-grader/SKILL.md +200 -0
- package/skills/luckiest-aeo-grader/evals/evals.json +19 -0
- package/skills/luckiest-aeo-grader/references/rubric.md +72 -0
- package/skills/luckiest-aeo-grader/scripts/scan.py +265 -0
- package/skills/luckiest-ai-seo/ATTRIBUTION.md +38 -0
- package/skills/luckiest-ai-seo/CHANGELOG.md +23 -0
- package/skills/luckiest-ai-seo/SKILL.md +510 -0
- package/skills/luckiest-ai-seo/evals/evals.json +90 -0
- package/skills/luckiest-ai-seo/references/content-patterns.md +285 -0
- package/skills/luckiest-ai-seo/references/content-types.md +71 -0
- package/skills/luckiest-ai-seo/references/okf.md +104 -0
- package/skills/luckiest-ai-seo/references/platform-ranking-factors.md +154 -0
- package/skills/luckiest-analytics/ATTRIBUTION.md +42 -0
- package/skills/luckiest-analytics/CHANGELOG.md +36 -0
- package/skills/luckiest-analytics/SKILL.md +380 -0
- package/skills/luckiest-analytics/evals/evals.json +90 -0
- package/skills/luckiest-analytics/references/event-library.md +260 -0
- package/skills/luckiest-analytics/references/ga4-implementation.md +300 -0
- package/skills/luckiest-analytics/references/gtm-implementation.md +390 -0
- package/skills/luckiest-aso/ATTRIBUTION.md +40 -0
- package/skills/luckiest-aso/CHANGELOG.md +33 -0
- package/skills/luckiest-aso/SKILL.md +327 -0
- package/skills/luckiest-aso/evals/evals.json +91 -0
- package/skills/luckiest-aso/references/apple-specs.md +107 -0
- package/skills/luckiest-aso/references/benchmarks.md +129 -0
- package/skills/luckiest-aso/references/google-play-specs.md +131 -0
- package/skills/luckiest-aso/references/report-template.md +213 -0
- package/skills/luckiest-aso/references/scoring-criteria.md +213 -0
- package/skills/luckiest-churn-prevention/ATTRIBUTION.md +41 -0
- package/skills/luckiest-churn-prevention/CHANGELOG.md +24 -0
- package/skills/luckiest-churn-prevention/SKILL.md +445 -0
- package/skills/luckiest-churn-prevention/evals/evals.json +93 -0
- package/skills/luckiest-churn-prevention/references/cancel-flow-patterns.md +316 -0
- package/skills/luckiest-churn-prevention/references/dunning-playbook.md +408 -0
- package/skills/luckiest-co-marketing/ATTRIBUTION.md +38 -0
- package/skills/luckiest-co-marketing/CHANGELOG.md +25 -0
- package/skills/luckiest-co-marketing/SKILL.md +331 -0
- package/skills/luckiest-co-marketing/evals/evals.json +84 -0
- package/skills/luckiest-coder/ATTRIBUTION.md +26 -0
- package/skills/luckiest-coder/CHANGELOG.md +30 -0
- package/skills/luckiest-coder/SKILL.md +77 -0
- package/skills/luckiest-coder/references/antigravity-tools.md +23 -0
- package/skills/luckiest-coder/references/codex-tools.md +39 -0
- package/skills/luckiest-coder/references/pi-tools.md +16 -0
- package/skills/luckiest-coder-brainstorming/ATTRIBUTION.md +26 -0
- package/skills/luckiest-coder-brainstorming/CHANGELOG.md +31 -0
- package/skills/luckiest-coder-brainstorming/SKILL.md +173 -0
- package/skills/luckiest-coder-brainstorming/scripts/frame-template.html +213 -0
- package/skills/luckiest-coder-brainstorming/scripts/helper.js +168 -0
- package/skills/luckiest-coder-brainstorming/scripts/server.cjs +721 -0
- package/skills/luckiest-coder-brainstorming/scripts/start-server.sh +209 -0
- package/skills/luckiest-coder-brainstorming/scripts/stop-server.sh +120 -0
- package/skills/luckiest-coder-brainstorming/spec-document-reviewer-prompt.md +49 -0
- package/skills/luckiest-coder-brainstorming/visual-companion.md +291 -0
- package/skills/luckiest-coder-consistency/ATTRIBUTION.md +30 -0
- package/skills/luckiest-coder-consistency/CHANGELOG.md +26 -0
- package/skills/luckiest-coder-consistency/SKILL.md +98 -0
- package/skills/luckiest-coder-constitution/ATTRIBUTION.md +28 -0
- package/skills/luckiest-coder-constitution/CHANGELOG.md +25 -0
- package/skills/luckiest-coder-constitution/SKILL.md +115 -0
- package/skills/luckiest-coder-debugging/ATTRIBUTION.md +26 -0
- package/skills/luckiest-coder-debugging/CHANGELOG.md +22 -0
- package/skills/luckiest-coder-debugging/CREATION-LOG.md +119 -0
- package/skills/luckiest-coder-debugging/SKILL.md +309 -0
- package/skills/luckiest-coder-debugging/condition-based-waiting-example.ts +158 -0
- package/skills/luckiest-coder-debugging/condition-based-waiting.md +115 -0
- package/skills/luckiest-coder-debugging/defense-in-depth.md +122 -0
- package/skills/luckiest-coder-debugging/find-polluter.sh +63 -0
- package/skills/luckiest-coder-debugging/root-cause-tracing.md +169 -0
- package/skills/luckiest-coder-debugging/test-academic.md +14 -0
- package/skills/luckiest-coder-debugging/test-pressure-1.md +58 -0
- package/skills/luckiest-coder-debugging/test-pressure-2.md +68 -0
- package/skills/luckiest-coder-debugging/test-pressure-3.md +69 -0
- package/skills/luckiest-coder-dispatching-parallel-agents/ATTRIBUTION.md +26 -0
- package/skills/luckiest-coder-dispatching-parallel-agents/CHANGELOG.md +23 -0
- package/skills/luckiest-coder-dispatching-parallel-agents/SKILL.md +198 -0
- package/skills/luckiest-coder-executing-plans/ATTRIBUTION.md +26 -0
- package/skills/luckiest-coder-executing-plans/CHANGELOG.md +22 -0
- package/skills/luckiest-coder-executing-plans/SKILL.md +83 -0
- package/skills/luckiest-coder-finishing-a-branch/ATTRIBUTION.md +26 -0
- package/skills/luckiest-coder-finishing-a-branch/CHANGELOG.md +22 -0
- package/skills/luckiest-coder-finishing-a-branch/SKILL.md +258 -0
- package/skills/luckiest-coder-git-worktrees/ATTRIBUTION.md +26 -0
- package/skills/luckiest-coder-git-worktrees/CHANGELOG.md +22 -0
- package/skills/luckiest-coder-git-worktrees/SKILL.md +215 -0
- package/skills/luckiest-coder-guard/ATTRIBUTION.md +29 -0
- package/skills/luckiest-coder-guard/CHANGELOG.md +48 -0
- package/skills/luckiest-coder-guard/LICENSE +21 -0
- package/skills/luckiest-coder-guard/SKILL.md +126 -0
- package/skills/luckiest-coder-guard/bin/check-careful.sh +65 -0
- package/skills/luckiest-coder-guard/bin/check-freeze.sh +48 -0
- package/skills/luckiest-coder-qa/ATTRIBUTION.md +28 -0
- package/skills/luckiest-coder-qa/CHANGELOG.md +49 -0
- package/skills/luckiest-coder-qa/LICENSE +21 -0
- package/skills/luckiest-coder-qa/SKILL.md +160 -0
- package/skills/luckiest-coder-qa/references/issue-taxonomy.md +85 -0
- package/skills/luckiest-coder-qa/references/qa-report-template.md +126 -0
- package/skills/luckiest-coder-receiving-code-review/ATTRIBUTION.md +26 -0
- package/skills/luckiest-coder-receiving-code-review/CHANGELOG.md +28 -0
- package/skills/luckiest-coder-receiving-code-review/SKILL.md +226 -0
- package/skills/luckiest-coder-requesting-code-review/ATTRIBUTION.md +26 -0
- package/skills/luckiest-coder-requesting-code-review/CHANGELOG.md +31 -0
- package/skills/luckiest-coder-requesting-code-review/SKILL.md +118 -0
- package/skills/luckiest-coder-requesting-code-review/code-reviewer.md +172 -0
- package/skills/luckiest-coder-shipping/ATTRIBUTION.md +26 -0
- package/skills/luckiest-coder-shipping/CHANGELOG.md +48 -0
- package/skills/luckiest-coder-shipping/LICENSE +21 -0
- package/skills/luckiest-coder-shipping/SKILL.md +148 -0
- package/skills/luckiest-coder-shipping/references/canary.md +44 -0
- package/skills/luckiest-coder-shipping/references/test-and-coverage.md +91 -0
- package/skills/luckiest-coder-subagent-driven-development/ATTRIBUTION.md +26 -0
- package/skills/luckiest-coder-subagent-driven-development/CHANGELOG.md +28 -0
- package/skills/luckiest-coder-subagent-driven-development/SKILL.md +439 -0
- package/skills/luckiest-coder-subagent-driven-development/implementer-prompt.md +139 -0
- package/skills/luckiest-coder-subagent-driven-development/scripts/review-package +44 -0
- package/skills/luckiest-coder-subagent-driven-development/scripts/sdd-workspace +22 -0
- package/skills/luckiest-coder-subagent-driven-development/scripts/task-brief +40 -0
- package/skills/luckiest-coder-subagent-driven-development/task-reviewer-prompt.md +188 -0
- package/skills/luckiest-coder-tdd/ATTRIBUTION.md +26 -0
- package/skills/luckiest-coder-tdd/CHANGELOG.md +26 -0
- package/skills/luckiest-coder-tdd/SKILL.md +384 -0
- package/skills/luckiest-coder-tdd/testing-anti-patterns.md +299 -0
- package/skills/luckiest-coder-verification/ATTRIBUTION.md +26 -0
- package/skills/luckiest-coder-verification/CHANGELOG.md +22 -0
- package/skills/luckiest-coder-verification/SKILL.md +152 -0
- package/skills/luckiest-coder-writing-plans/ATTRIBUTION.md +26 -0
- package/skills/luckiest-coder-writing-plans/CHANGELOG.md +22 -0
- package/skills/luckiest-coder-writing-plans/SKILL.md +191 -0
- package/skills/luckiest-coder-writing-plans/plan-document-reviewer-prompt.md +49 -0
- package/skills/luckiest-coder-writing-skills/ATTRIBUTION.md +26 -0
- package/skills/luckiest-coder-writing-skills/CHANGELOG.md +31 -0
- package/skills/luckiest-coder-writing-skills/SKILL.md +702 -0
- package/skills/luckiest-coder-writing-skills/anthropic-best-practices.md +1150 -0
- package/skills/luckiest-coder-writing-skills/examples/CLAUDE_MD_TESTING.md +189 -0
- package/skills/luckiest-coder-writing-skills/graphviz-conventions.dot +172 -0
- package/skills/luckiest-coder-writing-skills/persuasion-principles.md +187 -0
- package/skills/luckiest-coder-writing-skills/render-graphs.js +168 -0
- package/skills/luckiest-coder-writing-skills/testing-skills-with-subagents.md +384 -0
- package/skills/luckiest-cold-email/ATTRIBUTION.md +36 -0
- package/skills/luckiest-cold-email/CHANGELOG.md +24 -0
- package/skills/luckiest-cold-email/SKILL.md +213 -0
- package/skills/luckiest-cold-email/evals/evals.json +94 -0
- package/skills/luckiest-cold-email/references/benchmarks.md +83 -0
- package/skills/luckiest-cold-email/references/follow-up-sequences.md +81 -0
- package/skills/luckiest-cold-email/references/frameworks.md +90 -0
- package/skills/luckiest-cold-email/references/personalization.md +79 -0
- package/skills/luckiest-cold-email/references/subject-lines.md +53 -0
- package/skills/luckiest-community-marketing/ATTRIBUTION.md +41 -0
- package/skills/luckiest-community-marketing/CHANGELOG.md +35 -0
- package/skills/luckiest-community-marketing/SKILL.md +200 -0
- package/skills/luckiest-community-marketing/evals/evals.json +89 -0
- package/skills/luckiest-competitor-profiling/ATTRIBUTION.md +36 -0
- package/skills/luckiest-competitor-profiling/CHANGELOG.md +24 -0
- package/skills/luckiest-competitor-profiling/SKILL.md +443 -0
- package/skills/luckiest-competitor-profiling/evals/evals.json +85 -0
- package/skills/luckiest-competitor-profiling/references/templates.md +167 -0
- package/skills/luckiest-competitor-profiling/references/tool-reference.md +179 -0
- package/skills/luckiest-competitors/ATTRIBUTION.md +36 -0
- package/skills/luckiest-competitors/CHANGELOG.md +25 -0
- package/skills/luckiest-competitors/SKILL.md +171 -0
- package/skills/luckiest-competitors/evals/evals.json +93 -0
- package/skills/luckiest-competitors/references/content-architecture.md +271 -0
- package/skills/luckiest-competitors/references/templates.md +223 -0
- package/skills/luckiest-content-strategy/ATTRIBUTION.md +39 -0
- package/skills/luckiest-content-strategy/CHANGELOG.md +23 -0
- package/skills/luckiest-content-strategy/SKILL.md +395 -0
- package/skills/luckiest-content-strategy/evals/evals.json +90 -0
- package/skills/luckiest-content-strategy/references/headless-cms.md +194 -0
- package/skills/luckiest-copy-editing/ATTRIBUTION.md +41 -0
- package/skills/luckiest-copy-editing/CHANGELOG.md +31 -0
- package/skills/luckiest-copy-editing/SKILL.md +491 -0
- package/skills/luckiest-copy-editing/evals/evals.json +89 -0
- package/skills/luckiest-copy-editing/references/checklist.md +66 -0
- package/skills/luckiest-copy-editing/references/content-refresh.md +38 -0
- package/skills/luckiest-copy-editing/references/plain-english-alternatives.md +394 -0
- package/skills/luckiest-copywriting/ATTRIBUTION.md +35 -0
- package/skills/luckiest-copywriting/CHANGELOG.md +23 -0
- package/skills/luckiest-copywriting/SKILL.md +296 -0
- package/skills/luckiest-copywriting/evals/evals.json +111 -0
- package/skills/luckiest-copywriting/references/copy-frameworks.md +344 -0
- package/skills/luckiest-copywriting/references/natural-transitions.md +272 -0
- package/skills/luckiest-cro/ATTRIBUTION.md +34 -0
- package/skills/luckiest-cro/CHANGELOG.md +23 -0
- package/skills/luckiest-cro/SKILL.md +215 -0
- package/skills/luckiest-cro/evals/evals.json +111 -0
- package/skills/luckiest-cro/references/experiments.md +248 -0
- package/skills/luckiest-cro/references/form.md +422 -0
- package/skills/luckiest-customer-research/ATTRIBUTION.md +40 -0
- package/skills/luckiest-customer-research/CHANGELOG.md +26 -0
- package/skills/luckiest-customer-research/SKILL.md +293 -0
- package/skills/luckiest-customer-research/evals/evals.json +162 -0
- package/skills/luckiest-customer-research/references/source-guides.md +401 -0
- package/skills/luckiest-directory-submissions/ATTRIBUTION.md +40 -0
- package/skills/luckiest-directory-submissions/CHANGELOG.md +33 -0
- package/skills/luckiest-directory-submissions/SKILL.md +419 -0
- package/skills/luckiest-directory-submissions/evals/evals.json +94 -0
- package/skills/luckiest-directory-submissions/references/directory-list.md +477 -0
- package/skills/luckiest-directory-submissions/references/positioning-variations.md +232 -0
- package/skills/luckiest-directory-submissions/references/submission-tracker-template.csv +266 -0
- package/skills/luckiest-emails/ATTRIBUTION.md +42 -0
- package/skills/luckiest-emails/CHANGELOG.md +33 -0
- package/skills/luckiest-emails/SKILL.md +220 -0
- package/skills/luckiest-emails/evals/evals.json +93 -0
- package/skills/luckiest-emails/references/copy-guidelines.md +120 -0
- package/skills/luckiest-emails/references/email-types.md +515 -0
- package/skills/luckiest-emails/references/sequence-templates.md +168 -0
- package/skills/luckiest-extract-design-system/ATTRIBUTION.md +8 -0
- package/skills/luckiest-extract-design-system/CHANGELOG.md +37 -0
- package/skills/luckiest-extract-design-system/SKILL.md +83 -0
- package/skills/luckiest-free-tools/ATTRIBUTION.md +43 -0
- package/skills/luckiest-free-tools/CHANGELOG.md +25 -0
- package/skills/luckiest-free-tools/SKILL.md +220 -0
- package/skills/luckiest-free-tools/evals/evals.json +90 -0
- package/skills/luckiest-free-tools/references/tool-types.md +217 -0
- package/skills/luckiest-image/ATTRIBUTION.md +43 -0
- package/skills/luckiest-image/CHANGELOG.md +23 -0
- package/skills/luckiest-image/SKILL.md +376 -0
- package/skills/luckiest-image/evals/evals.json +89 -0
- package/skills/luckiest-image/references/ai-image-prompting.md +229 -0
- package/skills/luckiest-launch/ATTRIBUTION.md +40 -0
- package/skills/luckiest-launch/CHANGELOG.md +43 -0
- package/skills/luckiest-launch/SKILL.md +385 -0
- package/skills/luckiest-launch/evals/evals.json +91 -0
- package/skills/luckiest-lead-magnets/ATTRIBUTION.md +35 -0
- package/skills/luckiest-lead-magnets/CHANGELOG.md +23 -0
- package/skills/luckiest-lead-magnets/SKILL.md +331 -0
- package/skills/luckiest-lead-magnets/evals/evals.json +87 -0
- package/skills/luckiest-lead-magnets/references/benchmarks.md +129 -0
- package/skills/luckiest-lead-magnets/references/format-guide.md +196 -0
- package/skills/luckiest-marketing-ideas/ATTRIBUTION.md +39 -0
- package/skills/luckiest-marketing-ideas/CHANGELOG.md +33 -0
- package/skills/luckiest-marketing-ideas/SKILL.md +191 -0
- package/skills/luckiest-marketing-ideas/evals/evals.json +90 -0
- package/skills/luckiest-marketing-ideas/references/ideas-by-category.md +366 -0
- package/skills/luckiest-marketing-plan/ATTRIBUTION.md +40 -0
- package/skills/luckiest-marketing-plan/CHANGELOG.md +23 -0
- package/skills/luckiest-marketing-plan/SKILL.md +285 -0
- package/skills/luckiest-marketing-plan/evals/evals.json +96 -0
- package/skills/luckiest-marketing-plan/references/aarrr-framework.md +180 -0
- package/skills/luckiest-marketing-plan/references/budget-planning.md +168 -0
- package/skills/luckiest-marketing-plan/references/client-types.md +373 -0
- package/skills/luckiest-marketing-plan/references/current-state-rubric.md +255 -0
- package/skills/luckiest-marketing-plan/references/example-quietude.md +972 -0
- package/skills/luckiest-marketing-plan/references/funding-stage-unlocks.md +230 -0
- package/skills/luckiest-marketing-plan/references/growth-patterns.md +148 -0
- package/skills/luckiest-marketing-plan/references/idea-cross-reference.md +265 -0
- package/skills/luckiest-marketing-plan/references/measurement-framework.md +213 -0
- package/skills/luckiest-marketing-plan/references/methodology.md +363 -0
- package/skills/luckiest-marketing-plan/references/ops-stack-mapping.md +197 -0
- package/skills/luckiest-marketing-plan/references/plan-template.md +494 -0
- package/skills/luckiest-marketing-plan/references/team-and-agency-model.md +278 -0
- package/skills/luckiest-marketing-psychology/ATTRIBUTION.md +31 -0
- package/skills/luckiest-marketing-psychology/CHANGELOG.md +32 -0
- package/skills/luckiest-marketing-psychology/SKILL.md +202 -0
- package/skills/luckiest-marketing-psychology/evals.json +88 -0
- package/skills/luckiest-model-router/ATTRIBUTION.md +11 -0
- package/skills/luckiest-model-router/CHANGELOG.md +45 -0
- package/skills/luckiest-model-router/SKILL.md +74 -0
- package/skills/luckiest-model-router/scripts/route.py +145 -0
- package/skills/luckiest-offers/ATTRIBUTION.md +39 -0
- package/skills/luckiest-offers/CHANGELOG.md +23 -0
- package/skills/luckiest-offers/SKILL.md +167 -0
- package/skills/luckiest-offers/references/bonus-stacking.md +150 -0
- package/skills/luckiest-offers/references/examples.md +215 -0
- package/skills/luckiest-offers/references/guarantee-design.md +172 -0
- package/skills/luckiest-offers/references/offer-anatomy.md +203 -0
- package/skills/luckiest-offers/references/offer-formats.md +240 -0
- package/skills/luckiest-offers/references/scarcity-urgency.md +175 -0
- package/skills/luckiest-offers/references/value-equation.md +134 -0
- package/skills/luckiest-onboarding/ATTRIBUTION.md +43 -0
- package/skills/luckiest-onboarding/CHANGELOG.md +31 -0
- package/skills/luckiest-onboarding/SKILL.md +243 -0
- package/skills/luckiest-onboarding/references/experiments.md +258 -0
- package/skills/luckiest-paywalls/ATTRIBUTION.md +39 -0
- package/skills/luckiest-paywalls/CHANGELOG.md +25 -0
- package/skills/luckiest-paywalls/SKILL.md +256 -0
- package/skills/luckiest-paywalls/evals/evals.json +93 -0
- package/skills/luckiest-paywalls/references/experiments.md +164 -0
- package/skills/luckiest-popups/ATTRIBUTION.md +35 -0
- package/skills/luckiest-popups/CHANGELOG.md +27 -0
- package/skills/luckiest-popups/SKILL.md +477 -0
- package/skills/luckiest-popups/evals/evals.json +107 -0
- package/skills/luckiest-pricing/ATTRIBUTION.md +35 -0
- package/skills/luckiest-pricing/CHANGELOG.md +31 -0
- package/skills/luckiest-pricing/SKILL.md +283 -0
- package/skills/luckiest-pricing/evals/evals.json +90 -0
- package/skills/luckiest-pricing/references/research-methods.md +152 -0
- package/skills/luckiest-pricing/references/tier-structure.md +232 -0
- package/skills/luckiest-product-marketing/ATTRIBUTION.md +38 -0
- package/skills/luckiest-product-marketing/CHANGELOG.md +23 -0
- package/skills/luckiest-product-marketing/SKILL.md +256 -0
- package/skills/luckiest-product-marketing/evals/evals.json +85 -0
- package/skills/luckiest-programmatic-seo/ATTRIBUTION.md +35 -0
- package/skills/luckiest-programmatic-seo/CHANGELOG.md +24 -0
- package/skills/luckiest-programmatic-seo/SKILL.md +286 -0
- package/skills/luckiest-programmatic-seo/evals/evals.json +95 -0
- package/skills/luckiest-programmatic-seo/references/playbooks.md +308 -0
- package/skills/luckiest-prompt-rewrite/ATTRIBUTION.md +39 -0
- package/skills/luckiest-prompt-rewrite/CHANGELOG.md +70 -0
- package/skills/luckiest-prompt-rewrite/LICENSE +21 -0
- package/skills/luckiest-prompt-rewrite/SKILL.md +494 -0
- package/skills/luckiest-prompt-rewrite/references/patterns.md +82 -0
- package/skills/luckiest-prompt-rewrite/references/templates.md +454 -0
- package/skills/luckiest-prospecting/ATTRIBUTION.md +29 -0
- package/skills/luckiest-prospecting/CHANGELOG.md +24 -0
- package/skills/luckiest-prospecting/SKILL.md +275 -0
- package/skills/luckiest-prospecting/evals/evals.json +107 -0
- package/skills/luckiest-prospecting/references/b2b-prospecting.md +106 -0
- package/skills/luckiest-prospecting/references/compliance.md +123 -0
- package/skills/luckiest-prospecting/references/data-sources.md +287 -0
- package/skills/luckiest-prospecting/references/local-prospecting.md +165 -0
- package/skills/luckiest-prospecting/references/saas-prospecting.md +123 -0
- package/skills/luckiest-public-relations/ATTRIBUTION.md +34 -0
- package/skills/luckiest-public-relations/CHANGELOG.md +23 -0
- package/skills/luckiest-public-relations/SKILL.md +154 -0
- package/skills/luckiest-public-relations/references/journalist-pitching.md +368 -0
- package/skills/luckiest-public-relations/references/media-outlets.md +207 -0
- package/skills/luckiest-public-relations/references/newsjacking.md +218 -0
- package/skills/luckiest-public-relations/references/press-platforms.md +188 -0
- package/skills/luckiest-referrals/ATTRIBUTION.md +41 -0
- package/skills/luckiest-referrals/CHANGELOG.md +23 -0
- package/skills/luckiest-referrals/SKILL.md +292 -0
- package/skills/luckiest-referrals/evals/evals.json +90 -0
- package/skills/luckiest-referrals/references/affiliate-programs.md +167 -0
- package/skills/luckiest-referrals/references/program-examples.md +143 -0
- package/skills/luckiest-revops/ATTRIBUTION.md +40 -0
- package/skills/luckiest-revops/CHANGELOG.md +24 -0
- package/skills/luckiest-revops/SKILL.md +362 -0
- package/skills/luckiest-revops/evals/evals.json +91 -0
- package/skills/luckiest-revops/references/automation-playbooks.md +290 -0
- package/skills/luckiest-revops/references/lifecycle-definitions.md +278 -0
- package/skills/luckiest-revops/references/routing-rules.md +203 -0
- package/skills/luckiest-revops/references/scoring-models.md +247 -0
- package/skills/luckiest-sales-enablement/ATTRIBUTION.md +39 -0
- package/skills/luckiest-sales-enablement/CHANGELOG.md +23 -0
- package/skills/luckiest-sales-enablement/SKILL.md +379 -0
- package/skills/luckiest-sales-enablement/evals/evals.json +91 -0
- package/skills/luckiest-sales-enablement/references/deck-frameworks.md +263 -0
- package/skills/luckiest-sales-enablement/references/demo-scripts.md +355 -0
- package/skills/luckiest-sales-enablement/references/objection-library.md +270 -0
- package/skills/luckiest-sales-enablement/references/one-pager-templates.md +208 -0
- package/skills/luckiest-schema/ATTRIBUTION.md +39 -0
- package/skills/luckiest-schema/CHANGELOG.md +25 -0
- package/skills/luckiest-schema/SKILL.md +209 -0
- package/skills/luckiest-schema/evals/evals.json +88 -0
- package/skills/luckiest-schema/references/schema-examples.md +398 -0
- package/skills/luckiest-seo-audit/ATTRIBUTION.md +39 -0
- package/skills/luckiest-seo-audit/CHANGELOG.md +23 -0
- package/skills/luckiest-seo-audit/SKILL.md +529 -0
- package/skills/luckiest-seo-audit/evals/evals.json +136 -0
- package/skills/luckiest-seo-audit/references/ai-writing-detection.md +200 -0
- package/skills/luckiest-seo-audit/references/international-seo.md +230 -0
- package/skills/luckiest-session-handoff/ATTRIBUTION.md +14 -0
- package/skills/luckiest-session-handoff/CHANGELOG.md +30 -0
- package/skills/luckiest-session-handoff/SKILL.md +96 -0
- package/skills/luckiest-signup/ATTRIBUTION.md +48 -0
- package/skills/luckiest-signup/CHANGELOG.md +24 -0
- package/skills/luckiest-signup/SKILL.md +382 -0
- package/skills/luckiest-signup/evals/evals.json +88 -0
- package/skills/luckiest-site-architecture/ATTRIBUTION.md +38 -0
- package/skills/luckiest-site-architecture/CHANGELOG.md +23 -0
- package/skills/luckiest-site-architecture/SKILL.md +383 -0
- package/skills/luckiest-site-architecture/evals/evals.json +88 -0
- package/skills/luckiest-site-architecture/references/mermaid-templates.md +216 -0
- package/skills/luckiest-site-architecture/references/navigation-patterns.md +305 -0
- package/skills/luckiest-site-architecture/references/site-type-templates.md +293 -0
- package/skills/luckiest-sms/ATTRIBUTION.md +27 -0
- package/skills/luckiest-sms/CHANGELOG.md +24 -0
- package/skills/luckiest-sms/SKILL.md +400 -0
- package/skills/luckiest-sms/evals/evals.json +100 -0
- package/skills/luckiest-sms/references/compliance.md +202 -0
- package/skills/luckiest-sms/references/platforms.md +318 -0
- package/skills/luckiest-sms/references/sequence-templates.md +282 -0
- package/skills/luckiest-social/ATTRIBUTION.md +27 -0
- package/skills/luckiest-social/CHANGELOG.md +24 -0
- package/skills/luckiest-social/SKILL.md +430 -0
- package/skills/luckiest-social/evals/evals.json +92 -0
- package/skills/luckiest-social/references/listening-sources-template.md +123 -0
- package/skills/luckiest-social/references/listening.md +283 -0
- package/skills/luckiest-social/references/platform-limits.md +110 -0
- package/skills/luckiest-social/references/platforms.md +170 -0
- package/skills/luckiest-social/references/post-templates.md +177 -0
- package/skills/luckiest-social/references/reverse-engineering.md +195 -0
- package/skills/luckiest-social/references/short-form-video.md +237 -0
- package/skills/luckiest-thinker/ATTRIBUTION.md +16 -0
- package/skills/luckiest-thinker/CHANGELOG.md +20 -0
- package/skills/luckiest-thinker/LICENSE +21 -0
- package/skills/luckiest-thinker/SKILL.md +92 -0
- package/skills/luckiest-thinker/references/distribution-calibration.md +106 -0
- package/skills/luckiest-thinker/references/research-foundations.md +214 -0
- package/skills/luckiest-thinker/references/thinking-patterns.md +138 -0
- package/skills/luckiest-trends/.skillignore +10 -0
- package/skills/luckiest-trends/ATTRIBUTION.md +43 -0
- package/skills/luckiest-trends/CHANGELOG.md +86 -0
- package/skills/luckiest-trends/LICENSE +21 -0
- package/skills/luckiest-trends/SKILL.md +194 -0
- package/skills/luckiest-trends/agents/openai.yaml +8 -0
- package/skills/luckiest-trends/references/engine-contract.md +2041 -0
- package/skills/luckiest-trends/references/save-html-brief.md +206 -0
- package/skills/luckiest-trends/scripts/briefing.py +272 -0
- package/skills/luckiest-trends/scripts/build-skill.sh +39 -0
- package/skills/luckiest-trends/scripts/compare.sh +61 -0
- package/skills/luckiest-trends/scripts/evaluate_search_quality.py +573 -0
- package/skills/luckiest-trends/scripts/last30days.py +1467 -0
- package/skills/luckiest-trends/scripts/lib/__init__.py +1 -0
- package/skills/luckiest-trends/scripts/lib/__pycache__/__init__.cpython-313.pyc +0 -0
- package/skills/luckiest-trends/scripts/lib/__pycache__/arxiv.cpython-313.pyc +0 -0
- package/skills/luckiest-trends/scripts/lib/__pycache__/bird_x.cpython-313.pyc +0 -0
- package/skills/luckiest-trends/scripts/lib/__pycache__/bluesky.cpython-313.pyc +0 -0
- package/skills/luckiest-trends/scripts/lib/__pycache__/categories.cpython-313.pyc +0 -0
- package/skills/luckiest-trends/scripts/lib/__pycache__/cjk.cpython-313.pyc +0 -0
- package/skills/luckiest-trends/scripts/lib/__pycache__/cluster.cpython-313.pyc +0 -0
- package/skills/luckiest-trends/scripts/lib/__pycache__/dates.cpython-313.pyc +0 -0
- package/skills/luckiest-trends/scripts/lib/__pycache__/dedupe.cpython-313.pyc +0 -0
- package/skills/luckiest-trends/scripts/lib/__pycache__/digg.cpython-313.pyc +0 -0
- package/skills/luckiest-trends/scripts/lib/__pycache__/entity_extract.cpython-313.pyc +0 -0
- package/skills/luckiest-trends/scripts/lib/__pycache__/env.cpython-313.pyc +0 -0
- package/skills/luckiest-trends/scripts/lib/__pycache__/fusion.cpython-313.pyc +0 -0
- package/skills/luckiest-trends/scripts/lib/__pycache__/github.cpython-313.pyc +0 -0
- package/skills/luckiest-trends/scripts/lib/__pycache__/grounding.cpython-313.pyc +0 -0
- package/skills/luckiest-trends/scripts/lib/__pycache__/hackernews.cpython-313.pyc +0 -0
- package/skills/luckiest-trends/scripts/lib/__pycache__/hiring_signals.cpython-313.pyc +0 -0
- package/skills/luckiest-trends/scripts/lib/__pycache__/html_render.cpython-313.pyc +0 -0
- package/skills/luckiest-trends/scripts/lib/__pycache__/http.cpython-313.pyc +0 -0
- package/skills/luckiest-trends/scripts/lib/__pycache__/instagram.cpython-313.pyc +0 -0
- package/skills/luckiest-trends/scripts/lib/__pycache__/jobs.cpython-313.pyc +0 -0
- package/skills/luckiest-trends/scripts/lib/__pycache__/linkedin.cpython-313.pyc +0 -0
- package/skills/luckiest-trends/scripts/lib/__pycache__/log.cpython-313.pyc +0 -0
- package/skills/luckiest-trends/scripts/lib/__pycache__/normalize.cpython-313.pyc +0 -0
- package/skills/luckiest-trends/scripts/lib/__pycache__/permission_preflight.cpython-313.pyc +0 -0
- package/skills/luckiest-trends/scripts/lib/__pycache__/perplexity.cpython-313.pyc +0 -0
- package/skills/luckiest-trends/scripts/lib/__pycache__/pinterest.cpython-313.pyc +0 -0
- package/skills/luckiest-trends/scripts/lib/__pycache__/pipeline.cpython-313.pyc +0 -0
- package/skills/luckiest-trends/scripts/lib/__pycache__/planner.cpython-313.pyc +0 -0
- package/skills/luckiest-trends/scripts/lib/__pycache__/polymarket.cpython-313.pyc +0 -0
- package/skills/luckiest-trends/scripts/lib/__pycache__/preflight.cpython-313.pyc +0 -0
- package/skills/luckiest-trends/scripts/lib/__pycache__/providers.cpython-313.pyc +0 -0
- package/skills/luckiest-trends/scripts/lib/__pycache__/quality_nudge.cpython-313.pyc +0 -0
- package/skills/luckiest-trends/scripts/lib/__pycache__/query.cpython-313.pyc +0 -0
- package/skills/luckiest-trends/scripts/lib/__pycache__/reddit.cpython-313.pyc +0 -0
- package/skills/luckiest-trends/scripts/lib/__pycache__/reddit_arctic.cpython-313.pyc +0 -0
- package/skills/luckiest-trends/scripts/lib/__pycache__/reddit_enrich.cpython-313.pyc +0 -0
- package/skills/luckiest-trends/scripts/lib/__pycache__/reddit_keyless.cpython-313.pyc +0 -0
- package/skills/luckiest-trends/scripts/lib/__pycache__/reddit_listing.cpython-313.pyc +0 -0
- package/skills/luckiest-trends/scripts/lib/__pycache__/reddit_public.cpython-313.pyc +0 -0
- package/skills/luckiest-trends/scripts/lib/__pycache__/reddit_rss.cpython-313.pyc +0 -0
- package/skills/luckiest-trends/scripts/lib/__pycache__/reddit_shreddit.cpython-313.pyc +0 -0
- package/skills/luckiest-trends/scripts/lib/__pycache__/relevance.cpython-313.pyc +0 -0
- package/skills/luckiest-trends/scripts/lib/__pycache__/render.cpython-313.pyc +0 -0
- package/skills/luckiest-trends/scripts/lib/__pycache__/rerank.cpython-313.pyc +0 -0
- package/skills/luckiest-trends/scripts/lib/__pycache__/resolve.cpython-313.pyc +0 -0
- package/skills/luckiest-trends/scripts/lib/__pycache__/schema.cpython-313.pyc +0 -0
- package/skills/luckiest-trends/scripts/lib/__pycache__/signals.cpython-313.pyc +0 -0
- package/skills/luckiest-trends/scripts/lib/__pycache__/skill_meta.cpython-313.pyc +0 -0
- package/skills/luckiest-trends/scripts/lib/__pycache__/snippet.cpython-313.pyc +0 -0
- package/skills/luckiest-trends/scripts/lib/__pycache__/subproc.cpython-313.pyc +0 -0
- package/skills/luckiest-trends/scripts/lib/__pycache__/techmeme.cpython-313.pyc +0 -0
- package/skills/luckiest-trends/scripts/lib/__pycache__/threads.cpython-313.pyc +0 -0
- package/skills/luckiest-trends/scripts/lib/__pycache__/tiktok.cpython-313.pyc +0 -0
- package/skills/luckiest-trends/scripts/lib/__pycache__/trustpilot.cpython-313.pyc +0 -0
- package/skills/luckiest-trends/scripts/lib/__pycache__/truthsocial.cpython-313.pyc +0 -0
- package/skills/luckiest-trends/scripts/lib/__pycache__/ui.cpython-313.pyc +0 -0
- package/skills/luckiest-trends/scripts/lib/__pycache__/web_search_keyless.cpython-313.pyc +0 -0
- package/skills/luckiest-trends/scripts/lib/__pycache__/xai_x.cpython-313.pyc +0 -0
- package/skills/luckiest-trends/scripts/lib/__pycache__/xiaohongshu_api.cpython-313.pyc +0 -0
- package/skills/luckiest-trends/scripts/lib/__pycache__/xquik.cpython-313.pyc +0 -0
- package/skills/luckiest-trends/scripts/lib/__pycache__/xurl_x.cpython-313.pyc +0 -0
- package/skills/luckiest-trends/scripts/lib/__pycache__/youtube_yt.cpython-313.pyc +0 -0
- package/skills/luckiest-trends/scripts/lib/arxiv.py +290 -0
- package/skills/luckiest-trends/scripts/lib/bird_x.py +639 -0
- package/skills/luckiest-trends/scripts/lib/bluesky.py +323 -0
- package/skills/luckiest-trends/scripts/lib/categories.py +283 -0
- package/skills/luckiest-trends/scripts/lib/chrome_cookies.py +414 -0
- package/skills/luckiest-trends/scripts/lib/cjk.py +107 -0
- package/skills/luckiest-trends/scripts/lib/cluster.py +271 -0
- package/skills/luckiest-trends/scripts/lib/competitors.py +198 -0
- package/skills/luckiest-trends/scripts/lib/cookie_extract.py +508 -0
- package/skills/luckiest-trends/scripts/lib/dates.py +169 -0
- package/skills/luckiest-trends/scripts/lib/dedupe.py +145 -0
- package/skills/luckiest-trends/scripts/lib/digg.py +440 -0
- package/skills/luckiest-trends/scripts/lib/entity_extract.py +127 -0
- package/skills/luckiest-trends/scripts/lib/env.py +1073 -0
- package/skills/luckiest-trends/scripts/lib/fanout.py +84 -0
- package/skills/luckiest-trends/scripts/lib/fusion.py +207 -0
- package/skills/luckiest-trends/scripts/lib/github.py +996 -0
- package/skills/luckiest-trends/scripts/lib/grounding.py +331 -0
- package/skills/luckiest-trends/scripts/lib/hackernews.py +357 -0
- package/skills/luckiest-trends/scripts/lib/health.py +92 -0
- package/skills/luckiest-trends/scripts/lib/hiring_signals.py +326 -0
- package/skills/luckiest-trends/scripts/lib/html_publish.py +73 -0
- package/skills/luckiest-trends/scripts/lib/html_render.py +738 -0
- package/skills/luckiest-trends/scripts/lib/http.py +372 -0
- package/skills/luckiest-trends/scripts/lib/instagram.py +521 -0
- package/skills/luckiest-trends/scripts/lib/jobs.py +708 -0
- package/skills/luckiest-trends/scripts/lib/linkedin.py +363 -0
- package/skills/luckiest-trends/scripts/lib/log.py +35 -0
- package/skills/luckiest-trends/scripts/lib/normalize.py +759 -0
- package/skills/luckiest-trends/scripts/lib/permission_preflight.py +242 -0
- package/skills/luckiest-trends/scripts/lib/perplexity.py +745 -0
- package/skills/luckiest-trends/scripts/lib/pinterest.py +154 -0
- package/skills/luckiest-trends/scripts/lib/pipeline.py +1720 -0
- package/skills/luckiest-trends/scripts/lib/planner.py +763 -0
- package/skills/luckiest-trends/scripts/lib/polymarket.py +794 -0
- package/skills/luckiest-trends/scripts/lib/preflight.py +119 -0
- package/skills/luckiest-trends/scripts/lib/providers.py +380 -0
- package/skills/luckiest-trends/scripts/lib/quality_nudge.py +383 -0
- package/skills/luckiest-trends/scripts/lib/query.py +202 -0
- package/skills/luckiest-trends/scripts/lib/reddit.py +731 -0
- package/skills/luckiest-trends/scripts/lib/reddit_arctic.py +92 -0
- package/skills/luckiest-trends/scripts/lib/reddit_enrich.py +322 -0
- package/skills/luckiest-trends/scripts/lib/reddit_keyless.py +329 -0
- package/skills/luckiest-trends/scripts/lib/reddit_listing.py +188 -0
- package/skills/luckiest-trends/scripts/lib/reddit_public.py +275 -0
- package/skills/luckiest-trends/scripts/lib/reddit_rss.py +224 -0
- package/skills/luckiest-trends/scripts/lib/reddit_shreddit.py +184 -0
- package/skills/luckiest-trends/scripts/lib/relevance.py +200 -0
- package/skills/luckiest-trends/scripts/lib/render.py +2130 -0
- package/skills/luckiest-trends/scripts/lib/rerank.py +708 -0
- package/skills/luckiest-trends/scripts/lib/resolve.py +345 -0
- package/skills/luckiest-trends/scripts/lib/safari_cookies.py +193 -0
- package/skills/luckiest-trends/scripts/lib/schema.py +319 -0
- package/skills/luckiest-trends/scripts/lib/setup_wizard.py +843 -0
- package/skills/luckiest-trends/scripts/lib/signals.py +334 -0
- package/skills/luckiest-trends/scripts/lib/skill_meta.py +33 -0
- package/skills/luckiest-trends/scripts/lib/snippet.py +51 -0
- package/skills/luckiest-trends/scripts/lib/subproc.py +116 -0
- package/skills/luckiest-trends/scripts/lib/techmeme.py +239 -0
- package/skills/luckiest-trends/scripts/lib/threads.py +207 -0
- package/skills/luckiest-trends/scripts/lib/tiktok.py +596 -0
- package/skills/luckiest-trends/scripts/lib/transcribe.py +235 -0
- package/skills/luckiest-trends/scripts/lib/trustpilot.py +277 -0
- package/skills/luckiest-trends/scripts/lib/truthsocial.py +162 -0
- package/skills/luckiest-trends/scripts/lib/ui.py +626 -0
- package/skills/luckiest-trends/scripts/lib/vendor/bird-search/LICENSE +21 -0
- package/skills/luckiest-trends/scripts/lib/vendor/bird-search/bird-search.mjs +147 -0
- package/skills/luckiest-trends/scripts/lib/vendor/bird-search/lib/cookies.js +220 -0
- package/skills/luckiest-trends/scripts/lib/vendor/bird-search/lib/features.json +17 -0
- package/skills/luckiest-trends/scripts/lib/vendor/bird-search/lib/paginate-cursor.js +37 -0
- package/skills/luckiest-trends/scripts/lib/vendor/bird-search/lib/query-ids.json +20 -0
- package/skills/luckiest-trends/scripts/lib/vendor/bird-search/lib/runtime-features.js +151 -0
- package/skills/luckiest-trends/scripts/lib/vendor/bird-search/lib/runtime-query-ids.js +264 -0
- package/skills/luckiest-trends/scripts/lib/vendor/bird-search/lib/twitter-client-base.js +129 -0
- package/skills/luckiest-trends/scripts/lib/vendor/bird-search/lib/twitter-client-constants.js +50 -0
- package/skills/luckiest-trends/scripts/lib/vendor/bird-search/lib/twitter-client-features.js +347 -0
- package/skills/luckiest-trends/scripts/lib/vendor/bird-search/lib/twitter-client-search.js +157 -0
- package/skills/luckiest-trends/scripts/lib/vendor/bird-search/lib/twitter-client-types.js +2 -0
- package/skills/luckiest-trends/scripts/lib/vendor/bird-search/lib/twitter-client-utils.js +511 -0
- package/skills/luckiest-trends/scripts/lib/vendor/bird-search/package.json +13 -0
- package/skills/luckiest-trends/scripts/lib/web_fetch_keyless.py +105 -0
- package/skills/luckiest-trends/scripts/lib/web_search_keyless.py +158 -0
- package/skills/luckiest-trends/scripts/lib/xai_x.py +236 -0
- package/skills/luckiest-trends/scripts/lib/xiaohongshu_api.py +162 -0
- package/skills/luckiest-trends/scripts/lib/xquik.py +404 -0
- package/skills/luckiest-trends/scripts/lib/xurl_x.py +171 -0
- package/skills/luckiest-trends/scripts/lib/youtube_yt.py +1365 -0
- package/skills/luckiest-trends/scripts/setup-keychain.sh +123 -0
- package/skills/luckiest-trends/scripts/setup-pass.sh +132 -0
- package/skills/luckiest-trends/scripts/store.py +1020 -0
- package/skills/luckiest-trends/scripts/test-v1-vs-v2.sh +220 -0
- package/skills/luckiest-trends/scripts/test_device_auth.py +128 -0
- package/skills/luckiest-trends/scripts/verify_v3.py +195 -0
- package/skills/luckiest-trends/scripts/watchlist.py +318 -0
- package/skills/luckiest-video/ATTRIBUTION.md +27 -0
- package/skills/luckiest-video/CHANGELOG.md +23 -0
- package/skills/luckiest-video/SKILL.md +371 -0
- package/skills/luckiest-video/evals/evals.json +88 -0
- package/skills/luckiest-video/references/ai-video-prompting.md +175 -0
- package/skills/remix/SKILL.md +32 -0
- package/commands/luckiest/go.md +0 -45
- package/commands/luckiest/plan.md +0 -55
- /package/commands/{luckiest/charms.md → charms.md} +0 -0
- /package/commands/{luckiest/helpers.md → helpers.md} +0 -0
- /package/commands/{luckiest/home.md → home.md} +0 -0
- /package/commands/{luckiest/leaderboard.md → leaderboard.md} +0 -0
- /package/commands/{luckiest/merge.md → merge.md} +0 -0
- /package/commands/{luckiest/overlaps.md → overlaps.md} +0 -0
- /package/commands/{luckiest/skills.md → skills.md} +0 -0
- /package/commands/{luckiest/start.md → start.md} +0 -0
- /package/commands/{luckiest/status.md → status.md} +0 -0
- /package/commands/{luckiest/updates.md → updates.md} +0 -0
- /package/commands/{luckiest/vouch.md → vouch.md} +0 -0
- /package/commands/{luckiest/wishes.md → wishes.md} +0 -0
|
@@ -0,0 +1,383 @@
|
|
|
1
|
+
"""Post-research quality score and upgrade nudge.
|
|
2
|
+
|
|
3
|
+
Computes a quality score based on 5 core sources and builds
|
|
4
|
+
a nudge message describing what the user missed and how to fix it.
|
|
5
|
+
"""
|
|
6
|
+
|
|
7
|
+
from typing import List
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
# The 5 core sources
|
|
11
|
+
CORE_SOURCES = ["hn", "polymarket", "x", "youtube", "reddit"]
|
|
12
|
+
|
|
13
|
+
# Labels for display
|
|
14
|
+
SOURCE_LABELS = {
|
|
15
|
+
"hn": "Hacker News",
|
|
16
|
+
"polymarket": "Polymarket",
|
|
17
|
+
"x": "X/Twitter",
|
|
18
|
+
"youtube": "YouTube",
|
|
19
|
+
"reddit": "Reddit",
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
|
|
23
|
+
def _is_x_active(config: dict, research_results: dict) -> bool:
|
|
24
|
+
"""Check if X source is active (has credentials AND didn't error)."""
|
|
25
|
+
has_creds = _has_x_credentials(config)
|
|
26
|
+
if not has_creds:
|
|
27
|
+
return False
|
|
28
|
+
# If X errored this run, it's configured but broken
|
|
29
|
+
if research_results.get("x_error"):
|
|
30
|
+
return False
|
|
31
|
+
return True
|
|
32
|
+
|
|
33
|
+
|
|
34
|
+
def _has_x_credentials(config: dict) -> bool:
|
|
35
|
+
"""Return True when any X/Twitter source credential is configured."""
|
|
36
|
+
return bool(
|
|
37
|
+
config.get("AUTH_TOKEN")
|
|
38
|
+
or config.get("XAI_API_KEY")
|
|
39
|
+
or config.get("XQUIK_API_KEY")
|
|
40
|
+
)
|
|
41
|
+
|
|
42
|
+
|
|
43
|
+
def _has_ytdlp() -> bool:
|
|
44
|
+
"""Return True when the local/free YouTube lane is available."""
|
|
45
|
+
try:
|
|
46
|
+
from . import youtube_yt
|
|
47
|
+
return bool(youtube_yt.is_ytdlp_installed())
|
|
48
|
+
except Exception:
|
|
49
|
+
return False
|
|
50
|
+
|
|
51
|
+
|
|
52
|
+
def _youtube_returned_data(research_results: dict) -> bool:
|
|
53
|
+
"""Return True when YouTube produced usable items through any provider."""
|
|
54
|
+
videos = int(research_results.get("youtube_videos_count") or 0)
|
|
55
|
+
transcripts = int(research_results.get("youtube_transcripts_count") or 0)
|
|
56
|
+
return videos > 0 or transcripts > 0
|
|
57
|
+
|
|
58
|
+
|
|
59
|
+
def _is_youtube_active(config: dict, research_results: dict, *, has_ytdlp: bool) -> bool:
|
|
60
|
+
"""Check if YouTube source is active (yt-dlp installed)."""
|
|
61
|
+
if not has_ytdlp:
|
|
62
|
+
return False
|
|
63
|
+
if research_results.get("youtube_error"):
|
|
64
|
+
return False
|
|
65
|
+
return True
|
|
66
|
+
|
|
67
|
+
|
|
68
|
+
# Below this transcript-fetch ratio, YouTube is considered "degraded" rather
|
|
69
|
+
# than active. Picked at 50% so a single legitimate caption-disabled video in a
|
|
70
|
+
# multi-video result does not trip the nudge, but a stale-yt-dlp run that fails
|
|
71
|
+
# every transcript does. Tunable via DEGRADED_TRANSCRIPT_THRESHOLD env var if
|
|
72
|
+
# operators need to adjust without code changes.
|
|
73
|
+
DEFAULT_DEGRADED_TRANSCRIPT_THRESHOLD = 0.5
|
|
74
|
+
|
|
75
|
+
|
|
76
|
+
def _is_youtube_degraded(research_results: dict, threshold: float) -> bool:
|
|
77
|
+
"""YouTube is degraded when videos were returned but the transcript-fetch
|
|
78
|
+
ratio is below threshold. The canonical cause is a stale yt-dlp binary -
|
|
79
|
+
YouTube's caption format changes frequently and old binaries silently fail
|
|
80
|
+
every transcript while the search itself still succeeds.
|
|
81
|
+
|
|
82
|
+
Captions-disabled videos are subtracted from the denominator: an uploader
|
|
83
|
+
who turned off captions can never produce a transcript, so counting that
|
|
84
|
+
video toward "fetch failures" produces false positives. A single
|
|
85
|
+
captions-disabled video in a small result set was tripping the nudge.
|
|
86
|
+
|
|
87
|
+
When actual fetch outcomes are available, they take precedence over the
|
|
88
|
+
post-pruning ratio: the report counts only see items that survived
|
|
89
|
+
freshness/relevance pruning, so a run where every transcript fetch
|
|
90
|
+
succeeded but the fetched videos were later pruned looks identical to a
|
|
91
|
+
stale-binary run (#531). Zero failures across attempted fetches proves
|
|
92
|
+
the binary works - don't flag.
|
|
93
|
+
"""
|
|
94
|
+
videos = int(research_results.get("youtube_videos_count") or 0)
|
|
95
|
+
transcripts = int(research_results.get("youtube_transcripts_count") or 0)
|
|
96
|
+
captions_disabled = int(research_results.get("youtube_captions_disabled_count") or 0)
|
|
97
|
+
if videos <= 0:
|
|
98
|
+
return False
|
|
99
|
+
fetch_attempts = int(research_results.get("youtube_transcript_fetch_attempts") or 0)
|
|
100
|
+
fetch_failures = int(research_results.get("youtube_transcript_fetch_failures") or 0)
|
|
101
|
+
if fetch_attempts > 0 and fetch_failures == 0:
|
|
102
|
+
return False
|
|
103
|
+
eligible = videos - captions_disabled
|
|
104
|
+
if eligible <= 0:
|
|
105
|
+
# Every returned video had captions disabled - upstream content fact,
|
|
106
|
+
# not a yt-dlp problem. Don't flag.
|
|
107
|
+
return False
|
|
108
|
+
return (transcripts / eligible) < threshold
|
|
109
|
+
|
|
110
|
+
|
|
111
|
+
def _is_instagram_silent_failure(config: dict, research_results: dict) -> bool:
|
|
112
|
+
"""Instagram is silently failing when SC is configured but the source
|
|
113
|
+
returned zero items. The canonical cause is SC's v2 reels endpoint
|
|
114
|
+
500'ing on multi-token queries (it wraps Google Search and is documented
|
|
115
|
+
to be flaky there). Pre-fix the user got no signal at all - no Instagram
|
|
116
|
+
section in the brief, no error in the footer, just unexplained absence.
|
|
117
|
+
"""
|
|
118
|
+
if not config.get("SCRAPECREATORS_API_KEY"):
|
|
119
|
+
return False # not configured — not a silent failure
|
|
120
|
+
# Honor EXCLUDE_SOURCES: a user who set EXCLUDE_SOURCES=instagram
|
|
121
|
+
# intentionally turned the source off, so a zero-item count is
|
|
122
|
+
# expected, not a silent failure. Mirror the canonical parsing
|
|
123
|
+
# pattern from pipeline.available_sources().
|
|
124
|
+
excluded = {
|
|
125
|
+
s.strip().lower()
|
|
126
|
+
for s in (config.get("EXCLUDE_SOURCES") or "").split(",")
|
|
127
|
+
if s.strip()
|
|
128
|
+
}
|
|
129
|
+
# Symmetric case: INCLUDE_SOURCES is an opt-in allowlist. If it is
|
|
130
|
+
# non-empty and does not name instagram, the source was intentionally
|
|
131
|
+
# filtered out, so a zero-item count is expected — not a silent failure.
|
|
132
|
+
included = {
|
|
133
|
+
s.strip().lower()
|
|
134
|
+
for s in (config.get("INCLUDE_SOURCES") or "").split(",")
|
|
135
|
+
if s.strip()
|
|
136
|
+
}
|
|
137
|
+
if "instagram" in excluded or (included and "instagram" not in included):
|
|
138
|
+
return False
|
|
139
|
+
count = research_results.get("instagram_items_count")
|
|
140
|
+
if count is None:
|
|
141
|
+
return False # source not run this invocation
|
|
142
|
+
return int(count) == 0
|
|
143
|
+
|
|
144
|
+
|
|
145
|
+
def compute_quality_score(config: dict, research_results: dict) -> dict:
|
|
146
|
+
"""Compute research quality score based on 5 core sources.
|
|
147
|
+
|
|
148
|
+
Args:
|
|
149
|
+
config: Configuration dict from env.get_config()
|
|
150
|
+
research_results: Dict with keys like x_error, youtube_error,
|
|
151
|
+
reddit_error reflecting what happened this run. Optional keys
|
|
152
|
+
``youtube_videos_count`` and ``youtube_transcripts_count`` enable
|
|
153
|
+
degraded-YouTube detection (transcript-fetch ratio below threshold,
|
|
154
|
+
or fallback/provider data returned without local yt-dlp).
|
|
155
|
+
Optional key ``instagram_items_count`` enables silent-failure
|
|
156
|
+
detection for the bonus Instagram source.
|
|
157
|
+
|
|
158
|
+
Returns:
|
|
159
|
+
{
|
|
160
|
+
"score_pct": 40-100,
|
|
161
|
+
"core_active": ["hn", "polymarket", ...],
|
|
162
|
+
"core_missing": ["x", "youtube"],
|
|
163
|
+
"core_errored": [], # configured but errored at top level
|
|
164
|
+
"core_degraded": [], # configured and returned items but quality below threshold
|
|
165
|
+
"bonus_errored": [], # bonus sources (Instagram, etc.) configured but silent
|
|
166
|
+
"nudge_text": "..." or None if all sources healthy
|
|
167
|
+
}
|
|
168
|
+
"""
|
|
169
|
+
core_active: List[str] = []
|
|
170
|
+
core_missing: List[str] = []
|
|
171
|
+
core_errored: List[str] = []
|
|
172
|
+
core_degraded: List[str] = []
|
|
173
|
+
bonus_errored: List[str] = []
|
|
174
|
+
|
|
175
|
+
# HN, Polymarket, and Reddit are always active
|
|
176
|
+
core_active.append("hn")
|
|
177
|
+
core_active.append("polymarket")
|
|
178
|
+
core_active.append("reddit")
|
|
179
|
+
|
|
180
|
+
# X
|
|
181
|
+
has_x_creds = _has_x_credentials(config)
|
|
182
|
+
if _is_x_active(config, research_results):
|
|
183
|
+
core_active.append("x")
|
|
184
|
+
else:
|
|
185
|
+
core_missing.append("x")
|
|
186
|
+
if has_x_creds and research_results.get("x_error"):
|
|
187
|
+
core_errored.append("x")
|
|
188
|
+
|
|
189
|
+
# YouTube
|
|
190
|
+
has_ytdlp = _has_ytdlp()
|
|
191
|
+
yt_active = _is_youtube_active(config, research_results, has_ytdlp=has_ytdlp)
|
|
192
|
+
youtube_returned_data = _youtube_returned_data(research_results)
|
|
193
|
+
if yt_active:
|
|
194
|
+
core_active.append("youtube")
|
|
195
|
+
# Active means yt-dlp is installed and search did not error at the top
|
|
196
|
+
# level. But search-success + transcript-failure is the canonical
|
|
197
|
+
# stale-binary failure mode that the footer used to hide. Flag as
|
|
198
|
+
# degraded so the user gets an actionable nudge to update the binary.
|
|
199
|
+
threshold = float(config.get("DEGRADED_TRANSCRIPT_THRESHOLD") or DEFAULT_DEGRADED_TRANSCRIPT_THRESHOLD)
|
|
200
|
+
if _is_youtube_degraded(research_results, threshold):
|
|
201
|
+
core_degraded.append("youtube")
|
|
202
|
+
elif youtube_returned_data and not research_results.get("youtube_error"):
|
|
203
|
+
# YouTube produced data through a fallback/provider lane even though the
|
|
204
|
+
# local free yt-dlp lane is unavailable. Count the source as present,
|
|
205
|
+
# but surface it as degraded so users do not see the contradictory
|
|
206
|
+
# "Missing: YouTube" ending after a report with YouTube evidence.
|
|
207
|
+
# has_ytdlp is provably False here: yt_active is False and youtube_error
|
|
208
|
+
# is excluded by this guard, leaving unavailable yt-dlp as the cause.
|
|
209
|
+
core_active.append("youtube")
|
|
210
|
+
core_degraded.append("youtube")
|
|
211
|
+
else:
|
|
212
|
+
core_missing.append("youtube")
|
|
213
|
+
# Check if configured but errored (yt-dlp installed but failed this run)
|
|
214
|
+
if has_ytdlp and research_results.get("youtube_error"):
|
|
215
|
+
core_errored.append("youtube")
|
|
216
|
+
|
|
217
|
+
# Bonus sources (Instagram, etc.): SC-key holders expect content from
|
|
218
|
+
# these but until now the pipeline fell silent on configured-but-zero.
|
|
219
|
+
if _is_instagram_silent_failure(config, research_results):
|
|
220
|
+
bonus_errored.append("instagram")
|
|
221
|
+
|
|
222
|
+
score_pct = int(len(core_active) / 5 * 100)
|
|
223
|
+
|
|
224
|
+
has_sc = bool(config.get("SCRAPECREATORS_API_KEY"))
|
|
225
|
+
active_sources = research_results.get("active_sources") or []
|
|
226
|
+
nudge_text = _build_nudge_text(
|
|
227
|
+
core_missing,
|
|
228
|
+
core_errored,
|
|
229
|
+
core_degraded,
|
|
230
|
+
research_results,
|
|
231
|
+
has_sc=has_sc,
|
|
232
|
+
active_sources=active_sources,
|
|
233
|
+
bonus_errored=bonus_errored,
|
|
234
|
+
has_ytdlp=has_ytdlp,
|
|
235
|
+
) if (core_missing or core_degraded or bonus_errored) else None
|
|
236
|
+
|
|
237
|
+
return {
|
|
238
|
+
"score_pct": score_pct,
|
|
239
|
+
"core_active": core_active,
|
|
240
|
+
"core_missing": core_missing,
|
|
241
|
+
"core_errored": core_errored,
|
|
242
|
+
"core_degraded": core_degraded,
|
|
243
|
+
"bonus_errored": bonus_errored,
|
|
244
|
+
"nudge_text": nudge_text,
|
|
245
|
+
}
|
|
246
|
+
|
|
247
|
+
|
|
248
|
+
def _build_nudge_text(
|
|
249
|
+
core_missing: List[str],
|
|
250
|
+
core_errored: List[str],
|
|
251
|
+
core_degraded: List[str] = None,
|
|
252
|
+
research_results: dict = None,
|
|
253
|
+
has_sc: bool = False,
|
|
254
|
+
active_sources: list = None,
|
|
255
|
+
bonus_errored: List[str] = None,
|
|
256
|
+
has_ytdlp: bool = False,
|
|
257
|
+
) -> str:
|
|
258
|
+
"""Build human-readable nudge text describing what was missed or degraded.
|
|
259
|
+
|
|
260
|
+
Prioritizes free suggestions. Optionally mentions bonus sources
|
|
261
|
+
(TikTok, Instagram, Threads, Pinterest) if ScrapeCreators key is configured.
|
|
262
|
+
"""
|
|
263
|
+
lines: List[str] = []
|
|
264
|
+
core_degraded = core_degraded or []
|
|
265
|
+
bonus_errored = bonus_errored or []
|
|
266
|
+
research_results = research_results or {}
|
|
267
|
+
|
|
268
|
+
# Describe what was missed
|
|
269
|
+
missed_parts: List[str] = []
|
|
270
|
+
for src in core_missing:
|
|
271
|
+
label = SOURCE_LABELS[src]
|
|
272
|
+
if src in core_errored:
|
|
273
|
+
missed_parts.append(f"{label} (errored this run)")
|
|
274
|
+
else:
|
|
275
|
+
missed_parts.append(label)
|
|
276
|
+
|
|
277
|
+
active_count = 5 - len(core_missing)
|
|
278
|
+
lines.append(f"Research quality: {active_count}/5 core sources.")
|
|
279
|
+
if missed_parts:
|
|
280
|
+
lines.append(f"Missing: {', '.join(missed_parts)}.")
|
|
281
|
+
if core_degraded:
|
|
282
|
+
degraded_labels = ", ".join(SOURCE_LABELS[s] for s in core_degraded)
|
|
283
|
+
lines.append(f"Degraded: {degraded_labels}.")
|
|
284
|
+
if bonus_errored:
|
|
285
|
+
bonus_labels = ", ".join(s.capitalize() for s in bonus_errored)
|
|
286
|
+
lines.append(f"Bonus source silent: {bonus_labels}.")
|
|
287
|
+
lines.append("")
|
|
288
|
+
|
|
289
|
+
# Free suggestions
|
|
290
|
+
free_suggestions: List[str] = []
|
|
291
|
+
|
|
292
|
+
if "x" in core_missing:
|
|
293
|
+
if "x" in core_errored:
|
|
294
|
+
free_suggestions.append(
|
|
295
|
+
"X/Twitter errored - log into x.com in your browser, then re-run."
|
|
296
|
+
)
|
|
297
|
+
else:
|
|
298
|
+
free_suggestions.append(
|
|
299
|
+
"X/Twitter: real-time posts with likes and reposts - the fastest "
|
|
300
|
+
"signal for breaking topics. Three options: log into x.com in your "
|
|
301
|
+
"browser and re-run (cookies detected automatically), or add "
|
|
302
|
+
"XAI_API_KEY to your .env (get key at api.x.ai), or add "
|
|
303
|
+
"XQUIK_API_KEY to your .env (get key at xquik.com)."
|
|
304
|
+
)
|
|
305
|
+
|
|
306
|
+
if "youtube" in core_missing:
|
|
307
|
+
if "youtube" in core_errored:
|
|
308
|
+
free_suggestions.append(
|
|
309
|
+
"YouTube errored - update yt-dlp: brew upgrade yt-dlp"
|
|
310
|
+
)
|
|
311
|
+
else:
|
|
312
|
+
free_suggestions.append(
|
|
313
|
+
"YouTube: video transcripts with key moments - often the deepest "
|
|
314
|
+
"explanations on any topic. Install yt-dlp: brew install yt-dlp (free)"
|
|
315
|
+
)
|
|
316
|
+
|
|
317
|
+
if "youtube" in core_degraded:
|
|
318
|
+
videos = int(research_results.get("youtube_videos_count") or 0)
|
|
319
|
+
transcripts = int(research_results.get("youtube_transcripts_count") or 0)
|
|
320
|
+
captions_disabled = int(research_results.get("youtube_captions_disabled_count") or 0)
|
|
321
|
+
if not has_ytdlp and _youtube_returned_data(research_results):
|
|
322
|
+
free_suggestions.append(
|
|
323
|
+
f"YouTube returned {videos} videos and {transcripts} transcripts "
|
|
324
|
+
"through a fallback/provider path, but local yt-dlp is not "
|
|
325
|
+
"installed. Install yt-dlp to enable the free local YouTube lane "
|
|
326
|
+
"and reduce reliance on fallback providers: brew install yt-dlp "
|
|
327
|
+
"(macOS), scoop install yt-dlp (Windows), or pip install -U yt-dlp."
|
|
328
|
+
)
|
|
329
|
+
else:
|
|
330
|
+
captions_note = ""
|
|
331
|
+
if captions_disabled > 0:
|
|
332
|
+
captions_note = (
|
|
333
|
+
f" ({captions_disabled} of those had captions disabled by the "
|
|
334
|
+
"uploader, which is a separate cause and not fixable on your end)"
|
|
335
|
+
)
|
|
336
|
+
free_suggestions.append(
|
|
337
|
+
f"YouTube returned {videos} videos but only {transcripts} transcripts "
|
|
338
|
+
f"captured{captions_note}. The most common remaining cause is a stale "
|
|
339
|
+
"yt-dlp binary - YouTube's caption format changes frequently and old "
|
|
340
|
+
"binaries silently fail every transcript. Update via your package "
|
|
341
|
+
"manager: scoop update yt-dlp (Windows), brew upgrade yt-dlp (macOS), "
|
|
342
|
+
"or pip install -U yt-dlp."
|
|
343
|
+
)
|
|
344
|
+
|
|
345
|
+
if "instagram" in bonus_errored:
|
|
346
|
+
free_suggestions.append(
|
|
347
|
+
"Instagram returned 0 reels despite SC being configured. SC's "
|
|
348
|
+
"v2 reels endpoint wraps Google Search and 500's frequently on "
|
|
349
|
+
"multi-token queries. The skill now retries with hashtag-form "
|
|
350
|
+
"automatically; if zero items still appear, the topic may have "
|
|
351
|
+
"no reel coverage on Instagram. Try a single-word topic like "
|
|
352
|
+
"the most distinctive noun in your query."
|
|
353
|
+
)
|
|
354
|
+
|
|
355
|
+
# Mention bonus opt-in sources when SC key is present
|
|
356
|
+
if has_sc:
|
|
357
|
+
bonus_hints = []
|
|
358
|
+
if "threads" not in (active_sources or []):
|
|
359
|
+
bonus_hints.append("Threads")
|
|
360
|
+
if "pinterest" not in (active_sources or []):
|
|
361
|
+
bonus_hints.append("Pinterest")
|
|
362
|
+
if bonus_hints:
|
|
363
|
+
free_suggestions.append(
|
|
364
|
+
f"Your SC key also powers {', '.join(bonus_hints)} and YouTube comments. "
|
|
365
|
+
"Add them to INCLUDE_SOURCES in your .env to enable."
|
|
366
|
+
)
|
|
367
|
+
|
|
368
|
+
if free_suggestions:
|
|
369
|
+
lines.append("Free fixes:")
|
|
370
|
+
for s in free_suggestions:
|
|
371
|
+
lines.append(f" - {s}")
|
|
372
|
+
lines.append("")
|
|
373
|
+
|
|
374
|
+
# Bonus sources mention (non-blocking)
|
|
375
|
+
if not has_sc:
|
|
376
|
+
lines.append(
|
|
377
|
+
"Bonus: TikTok and Instagram are available with a free "
|
|
378
|
+
"ScrapeCreators key at scrapecreators.com (no affiliation)."
|
|
379
|
+
)
|
|
380
|
+
else:
|
|
381
|
+
lines.append("last30days has no affiliation with any API provider.")
|
|
382
|
+
|
|
383
|
+
return "\n".join(lines)
|
|
@@ -0,0 +1,202 @@
|
|
|
1
|
+
"""Shared query preprocessing utilities: noise-word stripping, core subject
|
|
2
|
+
extraction, and compound term detection. Used by all search modules."""
|
|
3
|
+
|
|
4
|
+
import re
|
|
5
|
+
from typing import FrozenSet, List, Optional, Set
|
|
6
|
+
|
|
7
|
+
# Common multi-word prefixes stripped from all queries (identical across modules)
|
|
8
|
+
PREFIXES = [
|
|
9
|
+
'what are the best', 'what is the best', 'what are the latest',
|
|
10
|
+
'what are people saying about', 'what do people think about',
|
|
11
|
+
'how do i use', 'how to use', 'how to',
|
|
12
|
+
'what are', 'what is', 'tips for', 'best practices for',
|
|
13
|
+
# Hebrew question/meta prefixes
|
|
14
|
+
'מה יש חדש ב', 'מה יש חדש על', 'מה אנשים אומרים על',
|
|
15
|
+
'מה חדש ב', 'מה חדש על', 'איך להשתמש ב',
|
|
16
|
+
'מהם המוצרים של', 'מה הם', 'מהם',
|
|
17
|
+
]
|
|
18
|
+
|
|
19
|
+
# Multi-word suffixes (used by bird_x)
|
|
20
|
+
SUFFIXES = [
|
|
21
|
+
'best practices', 'use cases', 'prompt techniques',
|
|
22
|
+
'prompting techniques', 'prompting tips',
|
|
23
|
+
]
|
|
24
|
+
|
|
25
|
+
# Base noise words shared across most modules
|
|
26
|
+
NOISE_WORDS = frozenset({
|
|
27
|
+
# Articles/prepositions/conjunctions
|
|
28
|
+
'a', 'an', 'the', 'is', 'are', 'was', 'were', 'and', 'or',
|
|
29
|
+
'of', 'in', 'on', 'for', 'with', 'about', 'to',
|
|
30
|
+
# Question words
|
|
31
|
+
'how', 'what', 'which', 'who', 'why', 'when', 'where',
|
|
32
|
+
'does', 'should', 'could', 'would',
|
|
33
|
+
# Research/meta descriptors
|
|
34
|
+
'best', 'top', 'good', 'great', 'awesome', 'killer',
|
|
35
|
+
'latest', 'new', 'news', 'update', 'updates',
|
|
36
|
+
'trendiest', 'trending', 'hottest', 'hot', 'popular', 'viral',
|
|
37
|
+
'practices', 'features', 'guide', 'tutorial',
|
|
38
|
+
'recommendations', 'advice', 'review', 'reviews',
|
|
39
|
+
'usecases', 'examples', 'comparison', 'versus', 'vs',
|
|
40
|
+
'plugin', 'plugins', 'skill', 'skills', 'tool', 'tools',
|
|
41
|
+
# Prompting meta words
|
|
42
|
+
'prompt', 'prompts', 'prompting', 'techniques', 'tips',
|
|
43
|
+
'tricks', 'methods', 'strategies', 'approaches',
|
|
44
|
+
# Action words
|
|
45
|
+
'using', 'uses', 'use',
|
|
46
|
+
# Misc filler
|
|
47
|
+
'people', 'saying', 'think', 'said', 'lately',
|
|
48
|
+
# Hebrew function words / prepositions / filler
|
|
49
|
+
'מה', 'מי', 'איך', 'למה', 'איפה', 'מתי', 'כמה', 'האם',
|
|
50
|
+
'של', 'על', 'עם', 'אל', 'את', 'בין', 'כי', 'כן', 'לא',
|
|
51
|
+
'יש', 'אין', 'כבר', 'רק', 'גם', 'אבל', 'כך', 'זה', 'זו',
|
|
52
|
+
'חדש', 'חדשים', 'טוב', 'טובים', 'הכי', 'ביותר',
|
|
53
|
+
'מוצרים', 'מבצע', 'מבצעים', 'חדשות', 'עדכונים',
|
|
54
|
+
})
|
|
55
|
+
|
|
56
|
+
|
|
57
|
+
# Shared noise sets for adapter `_extract_core_subject` wrappers.
|
|
58
|
+
#
|
|
59
|
+
# SOCIAL_NOISE: short-form micro-social platforms (Bluesky, Threads, Truth Social)
|
|
60
|
+
# where research/meta words rarely appear in the body of a post.
|
|
61
|
+
SOCIAL_NOISE = frozenset({
|
|
62
|
+
'best', 'top', 'good', 'great', 'awesome',
|
|
63
|
+
'latest', 'new', 'news', 'update', 'updates',
|
|
64
|
+
'trending', 'hottest', 'popular', 'viral',
|
|
65
|
+
'practices', 'features', 'recommendations', 'advice',
|
|
66
|
+
'or', 'and',
|
|
67
|
+
})
|
|
68
|
+
|
|
69
|
+
# VIRAL_NOISE: viral / discovery platforms (TikTok, Instagram, Pinterest) and
|
|
70
|
+
# the base for YouTube. Adds 'killer', the prompt-meta cluster, and the
|
|
71
|
+
# methodology cluster on top of SOCIAL_NOISE.
|
|
72
|
+
VIRAL_NOISE = SOCIAL_NOISE | frozenset({
|
|
73
|
+
'killer',
|
|
74
|
+
'prompt', 'prompts', 'prompting',
|
|
75
|
+
'methods', 'strategies', 'approaches',
|
|
76
|
+
})
|
|
77
|
+
|
|
78
|
+
|
|
79
|
+
def extract_core_subject(
|
|
80
|
+
topic: str,
|
|
81
|
+
*,
|
|
82
|
+
noise: Optional[FrozenSet[str]] = None,
|
|
83
|
+
max_words: Optional[int] = None,
|
|
84
|
+
strip_suffixes: bool = False,
|
|
85
|
+
) -> str:
|
|
86
|
+
"""Extract core subject from a verbose search query.
|
|
87
|
+
|
|
88
|
+
Strips common question/meta prefixes and noise words to produce a
|
|
89
|
+
compact search-friendly query. Platforms customize via parameters.
|
|
90
|
+
|
|
91
|
+
Args:
|
|
92
|
+
topic: Raw user query
|
|
93
|
+
noise: Override noise word set (default: NOISE_WORDS)
|
|
94
|
+
max_words: Cap result to N words (default: no cap)
|
|
95
|
+
strip_suffixes: Also strip trailing multi-word suffixes (bird_x uses this)
|
|
96
|
+
|
|
97
|
+
Returns:
|
|
98
|
+
Cleaned query string
|
|
99
|
+
"""
|
|
100
|
+
text = topic.lower().strip()
|
|
101
|
+
if not text:
|
|
102
|
+
return text
|
|
103
|
+
|
|
104
|
+
# Phase 1: Strip multi-word prefixes (longest first, stop after first match)
|
|
105
|
+
for p in PREFIXES:
|
|
106
|
+
if text.startswith(p + ' '):
|
|
107
|
+
text = text[len(p):].strip()
|
|
108
|
+
break
|
|
109
|
+
|
|
110
|
+
# Phase 2: Strip multi-word suffixes (opt-in)
|
|
111
|
+
if strip_suffixes:
|
|
112
|
+
for s in SUFFIXES:
|
|
113
|
+
if text.endswith(' ' + s):
|
|
114
|
+
text = text[:-len(s)].strip()
|
|
115
|
+
break
|
|
116
|
+
|
|
117
|
+
# Phase 3: Filter individual noise words
|
|
118
|
+
noise_set = noise if noise is not None else NOISE_WORDS
|
|
119
|
+
words = text.split()
|
|
120
|
+
filtered = [w for w in words if w not in noise_set]
|
|
121
|
+
|
|
122
|
+
# Apply word cap if requested
|
|
123
|
+
if max_words is not None and filtered:
|
|
124
|
+
filtered = filtered[:max_words]
|
|
125
|
+
|
|
126
|
+
result = ' '.join(filtered) if filtered else text
|
|
127
|
+
return result.rstrip('?!.') if not max_words else (result or topic.lower().strip())
|
|
128
|
+
|
|
129
|
+
|
|
130
|
+
def infer_query_intent(topic: str) -> str:
|
|
131
|
+
"""Classify a topic into a coarse intent for adapter query expansion.
|
|
132
|
+
|
|
133
|
+
Returns one of: ``comparison``, ``how_to``, ``opinion``, ``product``,
|
|
134
|
+
``prediction``, ``breaking_news`` (default).
|
|
135
|
+
|
|
136
|
+
The ``how_to`` regex covers both prefixed forms (``how to install``)
|
|
137
|
+
and bare imperatives (``configure``, ``troubleshoot``, ``debug``,
|
|
138
|
+
``fix``). Adapters that previously kept their own copy of this
|
|
139
|
+
classifier had drifted to subtly different word lists; this is the
|
|
140
|
+
superset.
|
|
141
|
+
|
|
142
|
+
Polymarket keeps a custom narrower classifier (prediction-only) and
|
|
143
|
+
does NOT delegate here; its expansion only needs that signal.
|
|
144
|
+
"""
|
|
145
|
+
text = topic.lower().strip()
|
|
146
|
+
if re.search(r"\b(vs|versus|compare|difference between)\b", text):
|
|
147
|
+
return "comparison"
|
|
148
|
+
if re.search(
|
|
149
|
+
r"\b(how to|tutorial|guide|setup|step by step|deploy|install|"
|
|
150
|
+
r"configuration|configure|troubleshoot|troubleshooting|error|errors|"
|
|
151
|
+
r"fix|debug)\b",
|
|
152
|
+
text,
|
|
153
|
+
):
|
|
154
|
+
return "how_to"
|
|
155
|
+
if re.search(r"\b(thoughts on|worth it|should i|opinion|review)\b", text):
|
|
156
|
+
return "opinion"
|
|
157
|
+
if re.search(r"\b(pricing|feature|features|best .* for)\b", text):
|
|
158
|
+
return "product"
|
|
159
|
+
if re.search(r"\b(predict|prediction|odds|forecast|chance)\b", text):
|
|
160
|
+
return "prediction"
|
|
161
|
+
return "breaking_news"
|
|
162
|
+
|
|
163
|
+
|
|
164
|
+
def extract_compound_terms(topic: str) -> List[str]:
|
|
165
|
+
"""Detect multi-word terms that should be quoted in search queries.
|
|
166
|
+
|
|
167
|
+
Identifies:
|
|
168
|
+
- Hyphenated terms: "multi-agent", "vc-backed"
|
|
169
|
+
- Title-cased multi-word names: "Claude Code", "React Native"
|
|
170
|
+
|
|
171
|
+
Returns list of terms suitable for quoting (e.g., '"multi-agent"').
|
|
172
|
+
"""
|
|
173
|
+
terms: List[str] = []
|
|
174
|
+
|
|
175
|
+
# Hyphenated terms
|
|
176
|
+
for match in re.finditer(r'\b\w+-\w+(?:-\w+)*\b', topic):
|
|
177
|
+
terms.append(match.group())
|
|
178
|
+
|
|
179
|
+
# Title-cased sequences (2+ capitalized words in a row)
|
|
180
|
+
for match in re.finditer(r'(?:[A-Z][a-z]+\s+){1,}[A-Z][a-z]+', topic):
|
|
181
|
+
terms.append(match.group())
|
|
182
|
+
|
|
183
|
+
return terms
|
|
184
|
+
|
|
185
|
+
|
|
186
|
+
def leading_mentions(text: Optional[str]) -> List[str]:
|
|
187
|
+
"""Return the handles a post is directed at: the leading run of @mentions in the text.
|
|
188
|
+
|
|
189
|
+
X replies open with the target handle(s) (e.g. "@someone thanks!"), so the
|
|
190
|
+
leading run identifies who the post is addressed to. A mention later in the
|
|
191
|
+
body is not a reply target and is intentionally ignored. Returns normalized
|
|
192
|
+
(``@``-stripped, lowercased) handles, in order. Shared by every X-shaped
|
|
193
|
+
source adapter (bird, xquik) so leading-mention parsing has one definition.
|
|
194
|
+
"""
|
|
195
|
+
out: List[str] = []
|
|
196
|
+
for token in (text or "").split():
|
|
197
|
+
tok = token.strip(",.:;!?")
|
|
198
|
+
if tok.startswith("@") and len(tok) > 1:
|
|
199
|
+
out.append(tok[1:].lower())
|
|
200
|
+
else:
|
|
201
|
+
break
|
|
202
|
+
return out
|