luckiest-co 1.0.0 → 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.
Files changed (618) hide show
  1. package/.claude-plugin/marketplace.json +16 -0
  2. package/.claude-plugin/plugin.json +1 -1
  3. package/LICENSE +24 -0
  4. package/bin/install.js +7 -5
  5. package/commands/{luckiest/finish.md → finish.md} +2 -0
  6. package/commands/go.md +53 -0
  7. package/commands/plan.md +66 -0
  8. package/package.json +16 -5
  9. package/skills/brainstorm/ATTRIBUTION.md +27 -0
  10. package/skills/brainstorm/SKILL.md +139 -0
  11. package/skills/luckiest-ab-testing/ATTRIBUTION.md +35 -0
  12. package/skills/luckiest-ab-testing/CHANGELOG.md +27 -0
  13. package/skills/luckiest-ab-testing/SKILL.md +379 -0
  14. package/skills/luckiest-ab-testing/evals/evals.json +118 -0
  15. package/skills/luckiest-ab-testing/references/sample-size-guide.md +290 -0
  16. package/skills/luckiest-ab-testing/references/test-templates.md +284 -0
  17. package/skills/luckiest-ad-creative/ATTRIBUTION.md +35 -0
  18. package/skills/luckiest-ad-creative/CHANGELOG.md +23 -0
  19. package/skills/luckiest-ad-creative/SKILL.md +393 -0
  20. package/skills/luckiest-ad-creative/evals/evals.json +90 -0
  21. package/skills/luckiest-ad-creative/references/generative-tools.md +637 -0
  22. package/skills/luckiest-ad-creative/references/platform-specs.md +213 -0
  23. package/skills/luckiest-ads/ATTRIBUTION.md +36 -0
  24. package/skills/luckiest-ads/CHANGELOG.md +24 -0
  25. package/skills/luckiest-ads/LICENSE +21 -0
  26. package/skills/luckiest-ads/SKILL.md +434 -0
  27. package/skills/luckiest-ads/evals/evals.json +90 -0
  28. package/skills/luckiest-ads/references/ad-copy-templates.md +207 -0
  29. package/skills/luckiest-ads/references/audience-targeting.md +243 -0
  30. package/skills/luckiest-ads/references/conversion-tracking.md +361 -0
  31. package/skills/luckiest-ads/references/platform-setup-checklists.md +277 -0
  32. package/skills/luckiest-advisors/ATTRIBUTION.md +16 -0
  33. package/skills/luckiest-advisors/CHANGELOG.md +99 -0
  34. package/skills/luckiest-advisors/SKILL.md +151 -0
  35. package/skills/luckiest-aeo-grader/ATTRIBUTION.md +19 -0
  36. package/skills/luckiest-aeo-grader/CHANGELOG.md +52 -0
  37. package/skills/luckiest-aeo-grader/SKILL.md +200 -0
  38. package/skills/luckiest-aeo-grader/evals/evals.json +19 -0
  39. package/skills/luckiest-aeo-grader/references/rubric.md +72 -0
  40. package/skills/luckiest-aeo-grader/scripts/scan.py +265 -0
  41. package/skills/luckiest-ai-seo/ATTRIBUTION.md +38 -0
  42. package/skills/luckiest-ai-seo/CHANGELOG.md +23 -0
  43. package/skills/luckiest-ai-seo/SKILL.md +510 -0
  44. package/skills/luckiest-ai-seo/evals/evals.json +90 -0
  45. package/skills/luckiest-ai-seo/references/content-patterns.md +285 -0
  46. package/skills/luckiest-ai-seo/references/content-types.md +71 -0
  47. package/skills/luckiest-ai-seo/references/okf.md +104 -0
  48. package/skills/luckiest-ai-seo/references/platform-ranking-factors.md +154 -0
  49. package/skills/luckiest-analytics/ATTRIBUTION.md +42 -0
  50. package/skills/luckiest-analytics/CHANGELOG.md +36 -0
  51. package/skills/luckiest-analytics/SKILL.md +380 -0
  52. package/skills/luckiest-analytics/evals/evals.json +90 -0
  53. package/skills/luckiest-analytics/references/event-library.md +260 -0
  54. package/skills/luckiest-analytics/references/ga4-implementation.md +300 -0
  55. package/skills/luckiest-analytics/references/gtm-implementation.md +390 -0
  56. package/skills/luckiest-aso/ATTRIBUTION.md +40 -0
  57. package/skills/luckiest-aso/CHANGELOG.md +33 -0
  58. package/skills/luckiest-aso/SKILL.md +327 -0
  59. package/skills/luckiest-aso/evals/evals.json +91 -0
  60. package/skills/luckiest-aso/references/apple-specs.md +107 -0
  61. package/skills/luckiest-aso/references/benchmarks.md +129 -0
  62. package/skills/luckiest-aso/references/google-play-specs.md +131 -0
  63. package/skills/luckiest-aso/references/report-template.md +213 -0
  64. package/skills/luckiest-aso/references/scoring-criteria.md +213 -0
  65. package/skills/luckiest-churn-prevention/ATTRIBUTION.md +41 -0
  66. package/skills/luckiest-churn-prevention/CHANGELOG.md +24 -0
  67. package/skills/luckiest-churn-prevention/SKILL.md +445 -0
  68. package/skills/luckiest-churn-prevention/evals/evals.json +93 -0
  69. package/skills/luckiest-churn-prevention/references/cancel-flow-patterns.md +316 -0
  70. package/skills/luckiest-churn-prevention/references/dunning-playbook.md +408 -0
  71. package/skills/luckiest-co-marketing/ATTRIBUTION.md +38 -0
  72. package/skills/luckiest-co-marketing/CHANGELOG.md +25 -0
  73. package/skills/luckiest-co-marketing/SKILL.md +331 -0
  74. package/skills/luckiest-co-marketing/evals/evals.json +84 -0
  75. package/skills/luckiest-coder/ATTRIBUTION.md +26 -0
  76. package/skills/luckiest-coder/CHANGELOG.md +30 -0
  77. package/skills/luckiest-coder/SKILL.md +77 -0
  78. package/skills/luckiest-coder/references/antigravity-tools.md +23 -0
  79. package/skills/luckiest-coder/references/codex-tools.md +39 -0
  80. package/skills/luckiest-coder/references/pi-tools.md +16 -0
  81. package/skills/luckiest-coder-brainstorming/ATTRIBUTION.md +26 -0
  82. package/skills/luckiest-coder-brainstorming/CHANGELOG.md +31 -0
  83. package/skills/luckiest-coder-brainstorming/SKILL.md +173 -0
  84. package/skills/luckiest-coder-brainstorming/scripts/frame-template.html +213 -0
  85. package/skills/luckiest-coder-brainstorming/scripts/helper.js +168 -0
  86. package/skills/luckiest-coder-brainstorming/scripts/server.cjs +721 -0
  87. package/skills/luckiest-coder-brainstorming/scripts/start-server.sh +209 -0
  88. package/skills/luckiest-coder-brainstorming/scripts/stop-server.sh +120 -0
  89. package/skills/luckiest-coder-brainstorming/spec-document-reviewer-prompt.md +49 -0
  90. package/skills/luckiest-coder-brainstorming/visual-companion.md +291 -0
  91. package/skills/luckiest-coder-consistency/ATTRIBUTION.md +30 -0
  92. package/skills/luckiest-coder-consistency/CHANGELOG.md +26 -0
  93. package/skills/luckiest-coder-consistency/SKILL.md +98 -0
  94. package/skills/luckiest-coder-constitution/ATTRIBUTION.md +28 -0
  95. package/skills/luckiest-coder-constitution/CHANGELOG.md +25 -0
  96. package/skills/luckiest-coder-constitution/SKILL.md +115 -0
  97. package/skills/luckiest-coder-debugging/ATTRIBUTION.md +26 -0
  98. package/skills/luckiest-coder-debugging/CHANGELOG.md +22 -0
  99. package/skills/luckiest-coder-debugging/CREATION-LOG.md +119 -0
  100. package/skills/luckiest-coder-debugging/SKILL.md +309 -0
  101. package/skills/luckiest-coder-debugging/condition-based-waiting-example.ts +158 -0
  102. package/skills/luckiest-coder-debugging/condition-based-waiting.md +115 -0
  103. package/skills/luckiest-coder-debugging/defense-in-depth.md +122 -0
  104. package/skills/luckiest-coder-debugging/find-polluter.sh +63 -0
  105. package/skills/luckiest-coder-debugging/root-cause-tracing.md +169 -0
  106. package/skills/luckiest-coder-debugging/test-academic.md +14 -0
  107. package/skills/luckiest-coder-debugging/test-pressure-1.md +58 -0
  108. package/skills/luckiest-coder-debugging/test-pressure-2.md +68 -0
  109. package/skills/luckiest-coder-debugging/test-pressure-3.md +69 -0
  110. package/skills/luckiest-coder-dispatching-parallel-agents/ATTRIBUTION.md +26 -0
  111. package/skills/luckiest-coder-dispatching-parallel-agents/CHANGELOG.md +23 -0
  112. package/skills/luckiest-coder-dispatching-parallel-agents/SKILL.md +198 -0
  113. package/skills/luckiest-coder-executing-plans/ATTRIBUTION.md +26 -0
  114. package/skills/luckiest-coder-executing-plans/CHANGELOG.md +22 -0
  115. package/skills/luckiest-coder-executing-plans/SKILL.md +83 -0
  116. package/skills/luckiest-coder-finishing-a-branch/ATTRIBUTION.md +26 -0
  117. package/skills/luckiest-coder-finishing-a-branch/CHANGELOG.md +22 -0
  118. package/skills/luckiest-coder-finishing-a-branch/SKILL.md +258 -0
  119. package/skills/luckiest-coder-git-worktrees/ATTRIBUTION.md +26 -0
  120. package/skills/luckiest-coder-git-worktrees/CHANGELOG.md +22 -0
  121. package/skills/luckiest-coder-git-worktrees/SKILL.md +215 -0
  122. package/skills/luckiest-coder-guard/ATTRIBUTION.md +29 -0
  123. package/skills/luckiest-coder-guard/CHANGELOG.md +48 -0
  124. package/skills/luckiest-coder-guard/LICENSE +21 -0
  125. package/skills/luckiest-coder-guard/SKILL.md +126 -0
  126. package/skills/luckiest-coder-guard/bin/check-careful.sh +65 -0
  127. package/skills/luckiest-coder-guard/bin/check-freeze.sh +48 -0
  128. package/skills/luckiest-coder-qa/ATTRIBUTION.md +28 -0
  129. package/skills/luckiest-coder-qa/CHANGELOG.md +49 -0
  130. package/skills/luckiest-coder-qa/LICENSE +21 -0
  131. package/skills/luckiest-coder-qa/SKILL.md +160 -0
  132. package/skills/luckiest-coder-qa/references/issue-taxonomy.md +85 -0
  133. package/skills/luckiest-coder-qa/references/qa-report-template.md +126 -0
  134. package/skills/luckiest-coder-receiving-code-review/ATTRIBUTION.md +26 -0
  135. package/skills/luckiest-coder-receiving-code-review/CHANGELOG.md +28 -0
  136. package/skills/luckiest-coder-receiving-code-review/SKILL.md +226 -0
  137. package/skills/luckiest-coder-requesting-code-review/ATTRIBUTION.md +26 -0
  138. package/skills/luckiest-coder-requesting-code-review/CHANGELOG.md +31 -0
  139. package/skills/luckiest-coder-requesting-code-review/SKILL.md +118 -0
  140. package/skills/luckiest-coder-requesting-code-review/code-reviewer.md +172 -0
  141. package/skills/luckiest-coder-shipping/ATTRIBUTION.md +26 -0
  142. package/skills/luckiest-coder-shipping/CHANGELOG.md +48 -0
  143. package/skills/luckiest-coder-shipping/LICENSE +21 -0
  144. package/skills/luckiest-coder-shipping/SKILL.md +148 -0
  145. package/skills/luckiest-coder-shipping/references/canary.md +44 -0
  146. package/skills/luckiest-coder-shipping/references/test-and-coverage.md +91 -0
  147. package/skills/luckiest-coder-subagent-driven-development/ATTRIBUTION.md +26 -0
  148. package/skills/luckiest-coder-subagent-driven-development/CHANGELOG.md +28 -0
  149. package/skills/luckiest-coder-subagent-driven-development/SKILL.md +439 -0
  150. package/skills/luckiest-coder-subagent-driven-development/implementer-prompt.md +139 -0
  151. package/skills/luckiest-coder-subagent-driven-development/scripts/review-package +44 -0
  152. package/skills/luckiest-coder-subagent-driven-development/scripts/sdd-workspace +22 -0
  153. package/skills/luckiest-coder-subagent-driven-development/scripts/task-brief +40 -0
  154. package/skills/luckiest-coder-subagent-driven-development/task-reviewer-prompt.md +188 -0
  155. package/skills/luckiest-coder-tdd/ATTRIBUTION.md +26 -0
  156. package/skills/luckiest-coder-tdd/CHANGELOG.md +26 -0
  157. package/skills/luckiest-coder-tdd/SKILL.md +384 -0
  158. package/skills/luckiest-coder-tdd/testing-anti-patterns.md +299 -0
  159. package/skills/luckiest-coder-verification/ATTRIBUTION.md +26 -0
  160. package/skills/luckiest-coder-verification/CHANGELOG.md +22 -0
  161. package/skills/luckiest-coder-verification/SKILL.md +152 -0
  162. package/skills/luckiest-coder-writing-plans/ATTRIBUTION.md +26 -0
  163. package/skills/luckiest-coder-writing-plans/CHANGELOG.md +22 -0
  164. package/skills/luckiest-coder-writing-plans/SKILL.md +191 -0
  165. package/skills/luckiest-coder-writing-plans/plan-document-reviewer-prompt.md +49 -0
  166. package/skills/luckiest-coder-writing-skills/ATTRIBUTION.md +26 -0
  167. package/skills/luckiest-coder-writing-skills/CHANGELOG.md +31 -0
  168. package/skills/luckiest-coder-writing-skills/SKILL.md +702 -0
  169. package/skills/luckiest-coder-writing-skills/anthropic-best-practices.md +1150 -0
  170. package/skills/luckiest-coder-writing-skills/examples/CLAUDE_MD_TESTING.md +189 -0
  171. package/skills/luckiest-coder-writing-skills/graphviz-conventions.dot +172 -0
  172. package/skills/luckiest-coder-writing-skills/persuasion-principles.md +187 -0
  173. package/skills/luckiest-coder-writing-skills/render-graphs.js +168 -0
  174. package/skills/luckiest-coder-writing-skills/testing-skills-with-subagents.md +384 -0
  175. package/skills/luckiest-cold-email/ATTRIBUTION.md +36 -0
  176. package/skills/luckiest-cold-email/CHANGELOG.md +24 -0
  177. package/skills/luckiest-cold-email/SKILL.md +213 -0
  178. package/skills/luckiest-cold-email/evals/evals.json +94 -0
  179. package/skills/luckiest-cold-email/references/benchmarks.md +83 -0
  180. package/skills/luckiest-cold-email/references/follow-up-sequences.md +81 -0
  181. package/skills/luckiest-cold-email/references/frameworks.md +90 -0
  182. package/skills/luckiest-cold-email/references/personalization.md +79 -0
  183. package/skills/luckiest-cold-email/references/subject-lines.md +53 -0
  184. package/skills/luckiest-community-marketing/ATTRIBUTION.md +41 -0
  185. package/skills/luckiest-community-marketing/CHANGELOG.md +35 -0
  186. package/skills/luckiest-community-marketing/SKILL.md +200 -0
  187. package/skills/luckiest-community-marketing/evals/evals.json +89 -0
  188. package/skills/luckiest-competitor-profiling/ATTRIBUTION.md +36 -0
  189. package/skills/luckiest-competitor-profiling/CHANGELOG.md +24 -0
  190. package/skills/luckiest-competitor-profiling/SKILL.md +443 -0
  191. package/skills/luckiest-competitor-profiling/evals/evals.json +85 -0
  192. package/skills/luckiest-competitor-profiling/references/templates.md +167 -0
  193. package/skills/luckiest-competitor-profiling/references/tool-reference.md +179 -0
  194. package/skills/luckiest-competitors/ATTRIBUTION.md +36 -0
  195. package/skills/luckiest-competitors/CHANGELOG.md +25 -0
  196. package/skills/luckiest-competitors/SKILL.md +171 -0
  197. package/skills/luckiest-competitors/evals/evals.json +93 -0
  198. package/skills/luckiest-competitors/references/content-architecture.md +271 -0
  199. package/skills/luckiest-competitors/references/templates.md +223 -0
  200. package/skills/luckiest-content-strategy/ATTRIBUTION.md +39 -0
  201. package/skills/luckiest-content-strategy/CHANGELOG.md +23 -0
  202. package/skills/luckiest-content-strategy/SKILL.md +395 -0
  203. package/skills/luckiest-content-strategy/evals/evals.json +90 -0
  204. package/skills/luckiest-content-strategy/references/headless-cms.md +194 -0
  205. package/skills/luckiest-copy-editing/ATTRIBUTION.md +41 -0
  206. package/skills/luckiest-copy-editing/CHANGELOG.md +31 -0
  207. package/skills/luckiest-copy-editing/SKILL.md +491 -0
  208. package/skills/luckiest-copy-editing/evals/evals.json +89 -0
  209. package/skills/luckiest-copy-editing/references/checklist.md +66 -0
  210. package/skills/luckiest-copy-editing/references/content-refresh.md +38 -0
  211. package/skills/luckiest-copy-editing/references/plain-english-alternatives.md +394 -0
  212. package/skills/luckiest-copywriting/ATTRIBUTION.md +35 -0
  213. package/skills/luckiest-copywriting/CHANGELOG.md +23 -0
  214. package/skills/luckiest-copywriting/SKILL.md +296 -0
  215. package/skills/luckiest-copywriting/evals/evals.json +111 -0
  216. package/skills/luckiest-copywriting/references/copy-frameworks.md +344 -0
  217. package/skills/luckiest-copywriting/references/natural-transitions.md +272 -0
  218. package/skills/luckiest-cro/ATTRIBUTION.md +34 -0
  219. package/skills/luckiest-cro/CHANGELOG.md +23 -0
  220. package/skills/luckiest-cro/SKILL.md +215 -0
  221. package/skills/luckiest-cro/evals/evals.json +111 -0
  222. package/skills/luckiest-cro/references/experiments.md +248 -0
  223. package/skills/luckiest-cro/references/form.md +422 -0
  224. package/skills/luckiest-customer-research/ATTRIBUTION.md +40 -0
  225. package/skills/luckiest-customer-research/CHANGELOG.md +26 -0
  226. package/skills/luckiest-customer-research/SKILL.md +293 -0
  227. package/skills/luckiest-customer-research/evals/evals.json +162 -0
  228. package/skills/luckiest-customer-research/references/source-guides.md +401 -0
  229. package/skills/luckiest-directory-submissions/ATTRIBUTION.md +40 -0
  230. package/skills/luckiest-directory-submissions/CHANGELOG.md +33 -0
  231. package/skills/luckiest-directory-submissions/SKILL.md +419 -0
  232. package/skills/luckiest-directory-submissions/evals/evals.json +94 -0
  233. package/skills/luckiest-directory-submissions/references/directory-list.md +477 -0
  234. package/skills/luckiest-directory-submissions/references/positioning-variations.md +232 -0
  235. package/skills/luckiest-directory-submissions/references/submission-tracker-template.csv +266 -0
  236. package/skills/luckiest-emails/ATTRIBUTION.md +42 -0
  237. package/skills/luckiest-emails/CHANGELOG.md +33 -0
  238. package/skills/luckiest-emails/SKILL.md +220 -0
  239. package/skills/luckiest-emails/evals/evals.json +93 -0
  240. package/skills/luckiest-emails/references/copy-guidelines.md +120 -0
  241. package/skills/luckiest-emails/references/email-types.md +515 -0
  242. package/skills/luckiest-emails/references/sequence-templates.md +168 -0
  243. package/skills/luckiest-extract-design-system/ATTRIBUTION.md +8 -0
  244. package/skills/luckiest-extract-design-system/CHANGELOG.md +37 -0
  245. package/skills/luckiest-extract-design-system/SKILL.md +83 -0
  246. package/skills/luckiest-free-tools/ATTRIBUTION.md +43 -0
  247. package/skills/luckiest-free-tools/CHANGELOG.md +25 -0
  248. package/skills/luckiest-free-tools/SKILL.md +220 -0
  249. package/skills/luckiest-free-tools/evals/evals.json +90 -0
  250. package/skills/luckiest-free-tools/references/tool-types.md +217 -0
  251. package/skills/luckiest-image/ATTRIBUTION.md +43 -0
  252. package/skills/luckiest-image/CHANGELOG.md +23 -0
  253. package/skills/luckiest-image/SKILL.md +376 -0
  254. package/skills/luckiest-image/evals/evals.json +89 -0
  255. package/skills/luckiest-image/references/ai-image-prompting.md +229 -0
  256. package/skills/luckiest-launch/ATTRIBUTION.md +40 -0
  257. package/skills/luckiest-launch/CHANGELOG.md +43 -0
  258. package/skills/luckiest-launch/SKILL.md +385 -0
  259. package/skills/luckiest-launch/evals/evals.json +91 -0
  260. package/skills/luckiest-lead-magnets/ATTRIBUTION.md +35 -0
  261. package/skills/luckiest-lead-magnets/CHANGELOG.md +23 -0
  262. package/skills/luckiest-lead-magnets/SKILL.md +331 -0
  263. package/skills/luckiest-lead-magnets/evals/evals.json +87 -0
  264. package/skills/luckiest-lead-magnets/references/benchmarks.md +129 -0
  265. package/skills/luckiest-lead-magnets/references/format-guide.md +196 -0
  266. package/skills/luckiest-marketing-ideas/ATTRIBUTION.md +39 -0
  267. package/skills/luckiest-marketing-ideas/CHANGELOG.md +33 -0
  268. package/skills/luckiest-marketing-ideas/SKILL.md +191 -0
  269. package/skills/luckiest-marketing-ideas/evals/evals.json +90 -0
  270. package/skills/luckiest-marketing-ideas/references/ideas-by-category.md +366 -0
  271. package/skills/luckiest-marketing-plan/ATTRIBUTION.md +40 -0
  272. package/skills/luckiest-marketing-plan/CHANGELOG.md +23 -0
  273. package/skills/luckiest-marketing-plan/SKILL.md +285 -0
  274. package/skills/luckiest-marketing-plan/evals/evals.json +96 -0
  275. package/skills/luckiest-marketing-plan/references/aarrr-framework.md +180 -0
  276. package/skills/luckiest-marketing-plan/references/budget-planning.md +168 -0
  277. package/skills/luckiest-marketing-plan/references/client-types.md +373 -0
  278. package/skills/luckiest-marketing-plan/references/current-state-rubric.md +255 -0
  279. package/skills/luckiest-marketing-plan/references/example-quietude.md +972 -0
  280. package/skills/luckiest-marketing-plan/references/funding-stage-unlocks.md +230 -0
  281. package/skills/luckiest-marketing-plan/references/growth-patterns.md +148 -0
  282. package/skills/luckiest-marketing-plan/references/idea-cross-reference.md +265 -0
  283. package/skills/luckiest-marketing-plan/references/measurement-framework.md +213 -0
  284. package/skills/luckiest-marketing-plan/references/methodology.md +363 -0
  285. package/skills/luckiest-marketing-plan/references/ops-stack-mapping.md +197 -0
  286. package/skills/luckiest-marketing-plan/references/plan-template.md +494 -0
  287. package/skills/luckiest-marketing-plan/references/team-and-agency-model.md +278 -0
  288. package/skills/luckiest-marketing-psychology/ATTRIBUTION.md +31 -0
  289. package/skills/luckiest-marketing-psychology/CHANGELOG.md +32 -0
  290. package/skills/luckiest-marketing-psychology/SKILL.md +202 -0
  291. package/skills/luckiest-marketing-psychology/evals.json +88 -0
  292. package/skills/luckiest-model-router/ATTRIBUTION.md +11 -0
  293. package/skills/luckiest-model-router/CHANGELOG.md +45 -0
  294. package/skills/luckiest-model-router/SKILL.md +74 -0
  295. package/skills/luckiest-model-router/scripts/route.py +145 -0
  296. package/skills/luckiest-offers/ATTRIBUTION.md +39 -0
  297. package/skills/luckiest-offers/CHANGELOG.md +23 -0
  298. package/skills/luckiest-offers/SKILL.md +167 -0
  299. package/skills/luckiest-offers/references/bonus-stacking.md +150 -0
  300. package/skills/luckiest-offers/references/examples.md +215 -0
  301. package/skills/luckiest-offers/references/guarantee-design.md +172 -0
  302. package/skills/luckiest-offers/references/offer-anatomy.md +203 -0
  303. package/skills/luckiest-offers/references/offer-formats.md +240 -0
  304. package/skills/luckiest-offers/references/scarcity-urgency.md +175 -0
  305. package/skills/luckiest-offers/references/value-equation.md +134 -0
  306. package/skills/luckiest-onboarding/ATTRIBUTION.md +43 -0
  307. package/skills/luckiest-onboarding/CHANGELOG.md +31 -0
  308. package/skills/luckiest-onboarding/SKILL.md +243 -0
  309. package/skills/luckiest-onboarding/references/experiments.md +258 -0
  310. package/skills/luckiest-paywalls/ATTRIBUTION.md +39 -0
  311. package/skills/luckiest-paywalls/CHANGELOG.md +25 -0
  312. package/skills/luckiest-paywalls/SKILL.md +256 -0
  313. package/skills/luckiest-paywalls/evals/evals.json +93 -0
  314. package/skills/luckiest-paywalls/references/experiments.md +164 -0
  315. package/skills/luckiest-popups/ATTRIBUTION.md +35 -0
  316. package/skills/luckiest-popups/CHANGELOG.md +27 -0
  317. package/skills/luckiest-popups/SKILL.md +477 -0
  318. package/skills/luckiest-popups/evals/evals.json +107 -0
  319. package/skills/luckiest-pricing/ATTRIBUTION.md +35 -0
  320. package/skills/luckiest-pricing/CHANGELOG.md +31 -0
  321. package/skills/luckiest-pricing/SKILL.md +283 -0
  322. package/skills/luckiest-pricing/evals/evals.json +90 -0
  323. package/skills/luckiest-pricing/references/research-methods.md +152 -0
  324. package/skills/luckiest-pricing/references/tier-structure.md +232 -0
  325. package/skills/luckiest-product-marketing/ATTRIBUTION.md +38 -0
  326. package/skills/luckiest-product-marketing/CHANGELOG.md +23 -0
  327. package/skills/luckiest-product-marketing/SKILL.md +256 -0
  328. package/skills/luckiest-product-marketing/evals/evals.json +85 -0
  329. package/skills/luckiest-programmatic-seo/ATTRIBUTION.md +35 -0
  330. package/skills/luckiest-programmatic-seo/CHANGELOG.md +24 -0
  331. package/skills/luckiest-programmatic-seo/SKILL.md +286 -0
  332. package/skills/luckiest-programmatic-seo/evals/evals.json +95 -0
  333. package/skills/luckiest-programmatic-seo/references/playbooks.md +308 -0
  334. package/skills/luckiest-prompt-rewrite/ATTRIBUTION.md +39 -0
  335. package/skills/luckiest-prompt-rewrite/CHANGELOG.md +70 -0
  336. package/skills/luckiest-prompt-rewrite/LICENSE +21 -0
  337. package/skills/luckiest-prompt-rewrite/SKILL.md +494 -0
  338. package/skills/luckiest-prompt-rewrite/references/patterns.md +82 -0
  339. package/skills/luckiest-prompt-rewrite/references/templates.md +454 -0
  340. package/skills/luckiest-prospecting/ATTRIBUTION.md +29 -0
  341. package/skills/luckiest-prospecting/CHANGELOG.md +24 -0
  342. package/skills/luckiest-prospecting/SKILL.md +275 -0
  343. package/skills/luckiest-prospecting/evals/evals.json +107 -0
  344. package/skills/luckiest-prospecting/references/b2b-prospecting.md +106 -0
  345. package/skills/luckiest-prospecting/references/compliance.md +123 -0
  346. package/skills/luckiest-prospecting/references/data-sources.md +287 -0
  347. package/skills/luckiest-prospecting/references/local-prospecting.md +165 -0
  348. package/skills/luckiest-prospecting/references/saas-prospecting.md +123 -0
  349. package/skills/luckiest-public-relations/ATTRIBUTION.md +34 -0
  350. package/skills/luckiest-public-relations/CHANGELOG.md +23 -0
  351. package/skills/luckiest-public-relations/SKILL.md +154 -0
  352. package/skills/luckiest-public-relations/references/journalist-pitching.md +368 -0
  353. package/skills/luckiest-public-relations/references/media-outlets.md +207 -0
  354. package/skills/luckiest-public-relations/references/newsjacking.md +218 -0
  355. package/skills/luckiest-public-relations/references/press-platforms.md +188 -0
  356. package/skills/luckiest-referrals/ATTRIBUTION.md +41 -0
  357. package/skills/luckiest-referrals/CHANGELOG.md +23 -0
  358. package/skills/luckiest-referrals/SKILL.md +292 -0
  359. package/skills/luckiest-referrals/evals/evals.json +90 -0
  360. package/skills/luckiest-referrals/references/affiliate-programs.md +167 -0
  361. package/skills/luckiest-referrals/references/program-examples.md +143 -0
  362. package/skills/luckiest-revops/ATTRIBUTION.md +40 -0
  363. package/skills/luckiest-revops/CHANGELOG.md +24 -0
  364. package/skills/luckiest-revops/SKILL.md +362 -0
  365. package/skills/luckiest-revops/evals/evals.json +91 -0
  366. package/skills/luckiest-revops/references/automation-playbooks.md +290 -0
  367. package/skills/luckiest-revops/references/lifecycle-definitions.md +278 -0
  368. package/skills/luckiest-revops/references/routing-rules.md +203 -0
  369. package/skills/luckiest-revops/references/scoring-models.md +247 -0
  370. package/skills/luckiest-sales-enablement/ATTRIBUTION.md +39 -0
  371. package/skills/luckiest-sales-enablement/CHANGELOG.md +23 -0
  372. package/skills/luckiest-sales-enablement/SKILL.md +379 -0
  373. package/skills/luckiest-sales-enablement/evals/evals.json +91 -0
  374. package/skills/luckiest-sales-enablement/references/deck-frameworks.md +263 -0
  375. package/skills/luckiest-sales-enablement/references/demo-scripts.md +355 -0
  376. package/skills/luckiest-sales-enablement/references/objection-library.md +270 -0
  377. package/skills/luckiest-sales-enablement/references/one-pager-templates.md +208 -0
  378. package/skills/luckiest-schema/ATTRIBUTION.md +39 -0
  379. package/skills/luckiest-schema/CHANGELOG.md +25 -0
  380. package/skills/luckiest-schema/SKILL.md +209 -0
  381. package/skills/luckiest-schema/evals/evals.json +88 -0
  382. package/skills/luckiest-schema/references/schema-examples.md +398 -0
  383. package/skills/luckiest-seo-audit/ATTRIBUTION.md +39 -0
  384. package/skills/luckiest-seo-audit/CHANGELOG.md +23 -0
  385. package/skills/luckiest-seo-audit/SKILL.md +529 -0
  386. package/skills/luckiest-seo-audit/evals/evals.json +136 -0
  387. package/skills/luckiest-seo-audit/references/ai-writing-detection.md +200 -0
  388. package/skills/luckiest-seo-audit/references/international-seo.md +230 -0
  389. package/skills/luckiest-session-handoff/ATTRIBUTION.md +14 -0
  390. package/skills/luckiest-session-handoff/CHANGELOG.md +30 -0
  391. package/skills/luckiest-session-handoff/SKILL.md +96 -0
  392. package/skills/luckiest-signup/ATTRIBUTION.md +48 -0
  393. package/skills/luckiest-signup/CHANGELOG.md +24 -0
  394. package/skills/luckiest-signup/SKILL.md +382 -0
  395. package/skills/luckiest-signup/evals/evals.json +88 -0
  396. package/skills/luckiest-site-architecture/ATTRIBUTION.md +38 -0
  397. package/skills/luckiest-site-architecture/CHANGELOG.md +23 -0
  398. package/skills/luckiest-site-architecture/SKILL.md +383 -0
  399. package/skills/luckiest-site-architecture/evals/evals.json +88 -0
  400. package/skills/luckiest-site-architecture/references/mermaid-templates.md +216 -0
  401. package/skills/luckiest-site-architecture/references/navigation-patterns.md +305 -0
  402. package/skills/luckiest-site-architecture/references/site-type-templates.md +293 -0
  403. package/skills/luckiest-sms/ATTRIBUTION.md +27 -0
  404. package/skills/luckiest-sms/CHANGELOG.md +24 -0
  405. package/skills/luckiest-sms/SKILL.md +400 -0
  406. package/skills/luckiest-sms/evals/evals.json +100 -0
  407. package/skills/luckiest-sms/references/compliance.md +202 -0
  408. package/skills/luckiest-sms/references/platforms.md +318 -0
  409. package/skills/luckiest-sms/references/sequence-templates.md +282 -0
  410. package/skills/luckiest-social/ATTRIBUTION.md +27 -0
  411. package/skills/luckiest-social/CHANGELOG.md +24 -0
  412. package/skills/luckiest-social/SKILL.md +430 -0
  413. package/skills/luckiest-social/evals/evals.json +92 -0
  414. package/skills/luckiest-social/references/listening-sources-template.md +123 -0
  415. package/skills/luckiest-social/references/listening.md +283 -0
  416. package/skills/luckiest-social/references/platform-limits.md +110 -0
  417. package/skills/luckiest-social/references/platforms.md +170 -0
  418. package/skills/luckiest-social/references/post-templates.md +177 -0
  419. package/skills/luckiest-social/references/reverse-engineering.md +195 -0
  420. package/skills/luckiest-social/references/short-form-video.md +237 -0
  421. package/skills/luckiest-thinker/ATTRIBUTION.md +16 -0
  422. package/skills/luckiest-thinker/CHANGELOG.md +20 -0
  423. package/skills/luckiest-thinker/LICENSE +21 -0
  424. package/skills/luckiest-thinker/SKILL.md +92 -0
  425. package/skills/luckiest-thinker/references/distribution-calibration.md +106 -0
  426. package/skills/luckiest-thinker/references/research-foundations.md +214 -0
  427. package/skills/luckiest-thinker/references/thinking-patterns.md +138 -0
  428. package/skills/luckiest-trends/.skillignore +10 -0
  429. package/skills/luckiest-trends/ATTRIBUTION.md +43 -0
  430. package/skills/luckiest-trends/CHANGELOG.md +86 -0
  431. package/skills/luckiest-trends/LICENSE +21 -0
  432. package/skills/luckiest-trends/SKILL.md +194 -0
  433. package/skills/luckiest-trends/agents/openai.yaml +8 -0
  434. package/skills/luckiest-trends/references/engine-contract.md +2041 -0
  435. package/skills/luckiest-trends/references/save-html-brief.md +206 -0
  436. package/skills/luckiest-trends/scripts/briefing.py +272 -0
  437. package/skills/luckiest-trends/scripts/build-skill.sh +39 -0
  438. package/skills/luckiest-trends/scripts/compare.sh +61 -0
  439. package/skills/luckiest-trends/scripts/evaluate_search_quality.py +573 -0
  440. package/skills/luckiest-trends/scripts/last30days.py +1467 -0
  441. package/skills/luckiest-trends/scripts/lib/__init__.py +1 -0
  442. package/skills/luckiest-trends/scripts/lib/__pycache__/__init__.cpython-313.pyc +0 -0
  443. package/skills/luckiest-trends/scripts/lib/__pycache__/arxiv.cpython-313.pyc +0 -0
  444. package/skills/luckiest-trends/scripts/lib/__pycache__/bird_x.cpython-313.pyc +0 -0
  445. package/skills/luckiest-trends/scripts/lib/__pycache__/bluesky.cpython-313.pyc +0 -0
  446. package/skills/luckiest-trends/scripts/lib/__pycache__/categories.cpython-313.pyc +0 -0
  447. package/skills/luckiest-trends/scripts/lib/__pycache__/cjk.cpython-313.pyc +0 -0
  448. package/skills/luckiest-trends/scripts/lib/__pycache__/cluster.cpython-313.pyc +0 -0
  449. package/skills/luckiest-trends/scripts/lib/__pycache__/dates.cpython-313.pyc +0 -0
  450. package/skills/luckiest-trends/scripts/lib/__pycache__/dedupe.cpython-313.pyc +0 -0
  451. package/skills/luckiest-trends/scripts/lib/__pycache__/digg.cpython-313.pyc +0 -0
  452. package/skills/luckiest-trends/scripts/lib/__pycache__/entity_extract.cpython-313.pyc +0 -0
  453. package/skills/luckiest-trends/scripts/lib/__pycache__/env.cpython-313.pyc +0 -0
  454. package/skills/luckiest-trends/scripts/lib/__pycache__/fusion.cpython-313.pyc +0 -0
  455. package/skills/luckiest-trends/scripts/lib/__pycache__/github.cpython-313.pyc +0 -0
  456. package/skills/luckiest-trends/scripts/lib/__pycache__/grounding.cpython-313.pyc +0 -0
  457. package/skills/luckiest-trends/scripts/lib/__pycache__/hackernews.cpython-313.pyc +0 -0
  458. package/skills/luckiest-trends/scripts/lib/__pycache__/hiring_signals.cpython-313.pyc +0 -0
  459. package/skills/luckiest-trends/scripts/lib/__pycache__/html_render.cpython-313.pyc +0 -0
  460. package/skills/luckiest-trends/scripts/lib/__pycache__/http.cpython-313.pyc +0 -0
  461. package/skills/luckiest-trends/scripts/lib/__pycache__/instagram.cpython-313.pyc +0 -0
  462. package/skills/luckiest-trends/scripts/lib/__pycache__/jobs.cpython-313.pyc +0 -0
  463. package/skills/luckiest-trends/scripts/lib/__pycache__/linkedin.cpython-313.pyc +0 -0
  464. package/skills/luckiest-trends/scripts/lib/__pycache__/log.cpython-313.pyc +0 -0
  465. package/skills/luckiest-trends/scripts/lib/__pycache__/normalize.cpython-313.pyc +0 -0
  466. package/skills/luckiest-trends/scripts/lib/__pycache__/permission_preflight.cpython-313.pyc +0 -0
  467. package/skills/luckiest-trends/scripts/lib/__pycache__/perplexity.cpython-313.pyc +0 -0
  468. package/skills/luckiest-trends/scripts/lib/__pycache__/pinterest.cpython-313.pyc +0 -0
  469. package/skills/luckiest-trends/scripts/lib/__pycache__/pipeline.cpython-313.pyc +0 -0
  470. package/skills/luckiest-trends/scripts/lib/__pycache__/planner.cpython-313.pyc +0 -0
  471. package/skills/luckiest-trends/scripts/lib/__pycache__/polymarket.cpython-313.pyc +0 -0
  472. package/skills/luckiest-trends/scripts/lib/__pycache__/preflight.cpython-313.pyc +0 -0
  473. package/skills/luckiest-trends/scripts/lib/__pycache__/providers.cpython-313.pyc +0 -0
  474. package/skills/luckiest-trends/scripts/lib/__pycache__/quality_nudge.cpython-313.pyc +0 -0
  475. package/skills/luckiest-trends/scripts/lib/__pycache__/query.cpython-313.pyc +0 -0
  476. package/skills/luckiest-trends/scripts/lib/__pycache__/reddit.cpython-313.pyc +0 -0
  477. package/skills/luckiest-trends/scripts/lib/__pycache__/reddit_arctic.cpython-313.pyc +0 -0
  478. package/skills/luckiest-trends/scripts/lib/__pycache__/reddit_enrich.cpython-313.pyc +0 -0
  479. package/skills/luckiest-trends/scripts/lib/__pycache__/reddit_keyless.cpython-313.pyc +0 -0
  480. package/skills/luckiest-trends/scripts/lib/__pycache__/reddit_listing.cpython-313.pyc +0 -0
  481. package/skills/luckiest-trends/scripts/lib/__pycache__/reddit_public.cpython-313.pyc +0 -0
  482. package/skills/luckiest-trends/scripts/lib/__pycache__/reddit_rss.cpython-313.pyc +0 -0
  483. package/skills/luckiest-trends/scripts/lib/__pycache__/reddit_shreddit.cpython-313.pyc +0 -0
  484. package/skills/luckiest-trends/scripts/lib/__pycache__/relevance.cpython-313.pyc +0 -0
  485. package/skills/luckiest-trends/scripts/lib/__pycache__/render.cpython-313.pyc +0 -0
  486. package/skills/luckiest-trends/scripts/lib/__pycache__/rerank.cpython-313.pyc +0 -0
  487. package/skills/luckiest-trends/scripts/lib/__pycache__/resolve.cpython-313.pyc +0 -0
  488. package/skills/luckiest-trends/scripts/lib/__pycache__/schema.cpython-313.pyc +0 -0
  489. package/skills/luckiest-trends/scripts/lib/__pycache__/signals.cpython-313.pyc +0 -0
  490. package/skills/luckiest-trends/scripts/lib/__pycache__/skill_meta.cpython-313.pyc +0 -0
  491. package/skills/luckiest-trends/scripts/lib/__pycache__/snippet.cpython-313.pyc +0 -0
  492. package/skills/luckiest-trends/scripts/lib/__pycache__/subproc.cpython-313.pyc +0 -0
  493. package/skills/luckiest-trends/scripts/lib/__pycache__/techmeme.cpython-313.pyc +0 -0
  494. package/skills/luckiest-trends/scripts/lib/__pycache__/threads.cpython-313.pyc +0 -0
  495. package/skills/luckiest-trends/scripts/lib/__pycache__/tiktok.cpython-313.pyc +0 -0
  496. package/skills/luckiest-trends/scripts/lib/__pycache__/trustpilot.cpython-313.pyc +0 -0
  497. package/skills/luckiest-trends/scripts/lib/__pycache__/truthsocial.cpython-313.pyc +0 -0
  498. package/skills/luckiest-trends/scripts/lib/__pycache__/ui.cpython-313.pyc +0 -0
  499. package/skills/luckiest-trends/scripts/lib/__pycache__/web_search_keyless.cpython-313.pyc +0 -0
  500. package/skills/luckiest-trends/scripts/lib/__pycache__/xai_x.cpython-313.pyc +0 -0
  501. package/skills/luckiest-trends/scripts/lib/__pycache__/xiaohongshu_api.cpython-313.pyc +0 -0
  502. package/skills/luckiest-trends/scripts/lib/__pycache__/xquik.cpython-313.pyc +0 -0
  503. package/skills/luckiest-trends/scripts/lib/__pycache__/xurl_x.cpython-313.pyc +0 -0
  504. package/skills/luckiest-trends/scripts/lib/__pycache__/youtube_yt.cpython-313.pyc +0 -0
  505. package/skills/luckiest-trends/scripts/lib/arxiv.py +290 -0
  506. package/skills/luckiest-trends/scripts/lib/bird_x.py +639 -0
  507. package/skills/luckiest-trends/scripts/lib/bluesky.py +323 -0
  508. package/skills/luckiest-trends/scripts/lib/categories.py +283 -0
  509. package/skills/luckiest-trends/scripts/lib/chrome_cookies.py +414 -0
  510. package/skills/luckiest-trends/scripts/lib/cjk.py +107 -0
  511. package/skills/luckiest-trends/scripts/lib/cluster.py +271 -0
  512. package/skills/luckiest-trends/scripts/lib/competitors.py +198 -0
  513. package/skills/luckiest-trends/scripts/lib/cookie_extract.py +508 -0
  514. package/skills/luckiest-trends/scripts/lib/dates.py +169 -0
  515. package/skills/luckiest-trends/scripts/lib/dedupe.py +145 -0
  516. package/skills/luckiest-trends/scripts/lib/digg.py +440 -0
  517. package/skills/luckiest-trends/scripts/lib/entity_extract.py +127 -0
  518. package/skills/luckiest-trends/scripts/lib/env.py +1073 -0
  519. package/skills/luckiest-trends/scripts/lib/fanout.py +84 -0
  520. package/skills/luckiest-trends/scripts/lib/fusion.py +207 -0
  521. package/skills/luckiest-trends/scripts/lib/github.py +996 -0
  522. package/skills/luckiest-trends/scripts/lib/grounding.py +331 -0
  523. package/skills/luckiest-trends/scripts/lib/hackernews.py +357 -0
  524. package/skills/luckiest-trends/scripts/lib/health.py +92 -0
  525. package/skills/luckiest-trends/scripts/lib/hiring_signals.py +326 -0
  526. package/skills/luckiest-trends/scripts/lib/html_publish.py +73 -0
  527. package/skills/luckiest-trends/scripts/lib/html_render.py +738 -0
  528. package/skills/luckiest-trends/scripts/lib/http.py +372 -0
  529. package/skills/luckiest-trends/scripts/lib/instagram.py +521 -0
  530. package/skills/luckiest-trends/scripts/lib/jobs.py +708 -0
  531. package/skills/luckiest-trends/scripts/lib/linkedin.py +363 -0
  532. package/skills/luckiest-trends/scripts/lib/log.py +35 -0
  533. package/skills/luckiest-trends/scripts/lib/normalize.py +759 -0
  534. package/skills/luckiest-trends/scripts/lib/permission_preflight.py +242 -0
  535. package/skills/luckiest-trends/scripts/lib/perplexity.py +745 -0
  536. package/skills/luckiest-trends/scripts/lib/pinterest.py +154 -0
  537. package/skills/luckiest-trends/scripts/lib/pipeline.py +1720 -0
  538. package/skills/luckiest-trends/scripts/lib/planner.py +763 -0
  539. package/skills/luckiest-trends/scripts/lib/polymarket.py +794 -0
  540. package/skills/luckiest-trends/scripts/lib/preflight.py +119 -0
  541. package/skills/luckiest-trends/scripts/lib/providers.py +380 -0
  542. package/skills/luckiest-trends/scripts/lib/quality_nudge.py +383 -0
  543. package/skills/luckiest-trends/scripts/lib/query.py +202 -0
  544. package/skills/luckiest-trends/scripts/lib/reddit.py +731 -0
  545. package/skills/luckiest-trends/scripts/lib/reddit_arctic.py +92 -0
  546. package/skills/luckiest-trends/scripts/lib/reddit_enrich.py +322 -0
  547. package/skills/luckiest-trends/scripts/lib/reddit_keyless.py +329 -0
  548. package/skills/luckiest-trends/scripts/lib/reddit_listing.py +188 -0
  549. package/skills/luckiest-trends/scripts/lib/reddit_public.py +275 -0
  550. package/skills/luckiest-trends/scripts/lib/reddit_rss.py +224 -0
  551. package/skills/luckiest-trends/scripts/lib/reddit_shreddit.py +184 -0
  552. package/skills/luckiest-trends/scripts/lib/relevance.py +200 -0
  553. package/skills/luckiest-trends/scripts/lib/render.py +2130 -0
  554. package/skills/luckiest-trends/scripts/lib/rerank.py +708 -0
  555. package/skills/luckiest-trends/scripts/lib/resolve.py +345 -0
  556. package/skills/luckiest-trends/scripts/lib/safari_cookies.py +193 -0
  557. package/skills/luckiest-trends/scripts/lib/schema.py +319 -0
  558. package/skills/luckiest-trends/scripts/lib/setup_wizard.py +843 -0
  559. package/skills/luckiest-trends/scripts/lib/signals.py +334 -0
  560. package/skills/luckiest-trends/scripts/lib/skill_meta.py +33 -0
  561. package/skills/luckiest-trends/scripts/lib/snippet.py +51 -0
  562. package/skills/luckiest-trends/scripts/lib/subproc.py +116 -0
  563. package/skills/luckiest-trends/scripts/lib/techmeme.py +239 -0
  564. package/skills/luckiest-trends/scripts/lib/threads.py +207 -0
  565. package/skills/luckiest-trends/scripts/lib/tiktok.py +596 -0
  566. package/skills/luckiest-trends/scripts/lib/transcribe.py +235 -0
  567. package/skills/luckiest-trends/scripts/lib/trustpilot.py +277 -0
  568. package/skills/luckiest-trends/scripts/lib/truthsocial.py +162 -0
  569. package/skills/luckiest-trends/scripts/lib/ui.py +626 -0
  570. package/skills/luckiest-trends/scripts/lib/vendor/bird-search/LICENSE +21 -0
  571. package/skills/luckiest-trends/scripts/lib/vendor/bird-search/bird-search.mjs +147 -0
  572. package/skills/luckiest-trends/scripts/lib/vendor/bird-search/lib/cookies.js +220 -0
  573. package/skills/luckiest-trends/scripts/lib/vendor/bird-search/lib/features.json +17 -0
  574. package/skills/luckiest-trends/scripts/lib/vendor/bird-search/lib/paginate-cursor.js +37 -0
  575. package/skills/luckiest-trends/scripts/lib/vendor/bird-search/lib/query-ids.json +20 -0
  576. package/skills/luckiest-trends/scripts/lib/vendor/bird-search/lib/runtime-features.js +151 -0
  577. package/skills/luckiest-trends/scripts/lib/vendor/bird-search/lib/runtime-query-ids.js +264 -0
  578. package/skills/luckiest-trends/scripts/lib/vendor/bird-search/lib/twitter-client-base.js +129 -0
  579. package/skills/luckiest-trends/scripts/lib/vendor/bird-search/lib/twitter-client-constants.js +50 -0
  580. package/skills/luckiest-trends/scripts/lib/vendor/bird-search/lib/twitter-client-features.js +347 -0
  581. package/skills/luckiest-trends/scripts/lib/vendor/bird-search/lib/twitter-client-search.js +157 -0
  582. package/skills/luckiest-trends/scripts/lib/vendor/bird-search/lib/twitter-client-types.js +2 -0
  583. package/skills/luckiest-trends/scripts/lib/vendor/bird-search/lib/twitter-client-utils.js +511 -0
  584. package/skills/luckiest-trends/scripts/lib/vendor/bird-search/package.json +13 -0
  585. package/skills/luckiest-trends/scripts/lib/web_fetch_keyless.py +105 -0
  586. package/skills/luckiest-trends/scripts/lib/web_search_keyless.py +158 -0
  587. package/skills/luckiest-trends/scripts/lib/xai_x.py +236 -0
  588. package/skills/luckiest-trends/scripts/lib/xiaohongshu_api.py +162 -0
  589. package/skills/luckiest-trends/scripts/lib/xquik.py +404 -0
  590. package/skills/luckiest-trends/scripts/lib/xurl_x.py +171 -0
  591. package/skills/luckiest-trends/scripts/lib/youtube_yt.py +1365 -0
  592. package/skills/luckiest-trends/scripts/setup-keychain.sh +123 -0
  593. package/skills/luckiest-trends/scripts/setup-pass.sh +132 -0
  594. package/skills/luckiest-trends/scripts/store.py +1020 -0
  595. package/skills/luckiest-trends/scripts/test-v1-vs-v2.sh +220 -0
  596. package/skills/luckiest-trends/scripts/test_device_auth.py +128 -0
  597. package/skills/luckiest-trends/scripts/verify_v3.py +195 -0
  598. package/skills/luckiest-trends/scripts/watchlist.py +318 -0
  599. package/skills/luckiest-video/ATTRIBUTION.md +27 -0
  600. package/skills/luckiest-video/CHANGELOG.md +23 -0
  601. package/skills/luckiest-video/SKILL.md +371 -0
  602. package/skills/luckiest-video/evals/evals.json +88 -0
  603. package/skills/luckiest-video/references/ai-video-prompting.md +175 -0
  604. package/skills/remix/SKILL.md +32 -0
  605. package/commands/luckiest/go.md +0 -45
  606. package/commands/luckiest/plan.md +0 -55
  607. /package/commands/{luckiest/charms.md → charms.md} +0 -0
  608. /package/commands/{luckiest/helpers.md → helpers.md} +0 -0
  609. /package/commands/{luckiest/home.md → home.md} +0 -0
  610. /package/commands/{luckiest/leaderboard.md → leaderboard.md} +0 -0
  611. /package/commands/{luckiest/merge.md → merge.md} +0 -0
  612. /package/commands/{luckiest/overlaps.md → overlaps.md} +0 -0
  613. /package/commands/{luckiest/skills.md → skills.md} +0 -0
  614. /package/commands/{luckiest/start.md → start.md} +0 -0
  615. /package/commands/{luckiest/status.md → status.md} +0 -0
  616. /package/commands/{luckiest/updates.md → updates.md} +0 -0
  617. /package/commands/{luckiest/vouch.md → vouch.md} +0 -0
  618. /package/commands/{luckiest/wishes.md → wishes.md} +0 -0
@@ -0,0 +1,626 @@
1
+ """Terminal UI utilities for last30days skill."""
2
+
3
+ import sys
4
+ import time
5
+ import threading
6
+ import random
7
+ from typing import Optional
8
+
9
+ from .render import _skill_version
10
+
11
+ # Check if we're in a real terminal (not captured by Claude Code)
12
+ IS_TTY = sys.stderr.isatty()
13
+
14
+ # ANSI color codes
15
+ class Colors:
16
+ PURPLE = '\033[95m'
17
+ BLUE = '\033[94m'
18
+ CYAN = '\033[96m'
19
+ GREEN = '\033[92m'
20
+ YELLOW = '\033[93m'
21
+ RED = '\033[91m'
22
+ BOLD = '\033[1m'
23
+ DIM = '\033[2m'
24
+ RESET = '\033[0m'
25
+
26
+
27
+ BANNER = f"""{Colors.PURPLE}{Colors.BOLD}
28
+ ██╗ █████╗ ███████╗████████╗██████╗ ██████╗ ██████╗ █████╗ ██╗ ██╗███████╗
29
+ ██║ ██╔══██╗██╔════╝╚══██╔══╝╚════██╗██╔═████╗██╔══██╗██╔══██╗╚██╗ ██╔╝██╔════╝
30
+ ██║ ███████║███████╗ ██║ █████╔╝██║██╔██║██║ ██║███████║ ╚████╔╝ ███████╗
31
+ ██║ ██╔══██║╚════██║ ██║ ╚═══██╗████╔╝██║██║ ██║██╔══██║ ╚██╔╝ ╚════██║
32
+ ███████╗██║ ██║███████║ ██║ ██████╔╝╚██████╔╝██████╔╝██║ ██║ ██║ ███████║
33
+ ╚══════╝╚═╝ ╚═╝╚══════╝ ╚═╝ ╚═════╝ ╚═════╝ ╚═════╝ ╚═╝ ╚═╝ ╚═╝ ╚══════╝
34
+ {Colors.RESET}{Colors.DIM} 30 days of research. 30 seconds of work.{Colors.RESET}
35
+ """
36
+
37
+ MINI_BANNER = f"""{Colors.PURPLE}{Colors.BOLD}/last30days{Colors.RESET} {Colors.DIM}· researching...{Colors.RESET}"""
38
+
39
+ # Fun status messages for each phase
40
+ REDDIT_MESSAGES = [
41
+ "Diving into Reddit threads...",
42
+ "Scanning subreddits for gold...",
43
+ "Reading what Redditors are saying...",
44
+ "Exploring the front page of the internet...",
45
+ "Finding the good discussions...",
46
+ "Upvoting mentally...",
47
+ "Scrolling through comments...",
48
+ ]
49
+
50
+ X_MESSAGES = [
51
+ "Checking what X is buzzing about...",
52
+ "Reading the timeline...",
53
+ "Finding the hot takes...",
54
+ "Scanning tweets and threads...",
55
+ "Discovering trending insights...",
56
+ "Following the conversation...",
57
+ "Reading between the posts...",
58
+ ]
59
+
60
+ ENRICHING_MESSAGES = [
61
+ "Getting the juicy details...",
62
+ "Fetching engagement metrics...",
63
+ "Reading top comments...",
64
+ "Extracting insights...",
65
+ "Analyzing discussions...",
66
+ ]
67
+
68
+ YOUTUBE_MESSAGES = [
69
+ "Searching YouTube for videos...",
70
+ "Finding relevant video content...",
71
+ "Scanning YouTube channels...",
72
+ "Discovering video discussions...",
73
+ "Fetching transcripts...",
74
+ ]
75
+
76
+ TIKTOK_MESSAGES = [
77
+ "Searching TikTok for trending videos...",
78
+ "Finding what's viral on TikTok...",
79
+ "Scanning TikTok for relevant content...",
80
+ ]
81
+
82
+ INSTAGRAM_MESSAGES = [
83
+ "Searching Instagram Reels...",
84
+ "Finding what's trending on Instagram...",
85
+ "Scanning Instagram for relevant reels...",
86
+ ]
87
+
88
+ HN_MESSAGES = [
89
+ "Searching Hacker News...",
90
+ "Scanning HN front page stories...",
91
+ "Finding technical discussions...",
92
+ "Discovering developer conversations...",
93
+ ]
94
+
95
+ POLYMARKET_MESSAGES = [
96
+ "Checking prediction markets...",
97
+ "Finding what people are betting on...",
98
+ "Scanning Polymarket for odds...",
99
+ "Discovering prediction markets...",
100
+ ]
101
+
102
+ PROCESSING_MESSAGES = [
103
+ "Crunching the data...",
104
+ "Scoring and ranking...",
105
+ "Finding patterns...",
106
+ "Removing duplicates...",
107
+ "Organizing findings...",
108
+ ]
109
+
110
+ WEB_ONLY_MESSAGES = [
111
+ "Searching the web...",
112
+ "Finding blogs and docs...",
113
+ "Crawling news sites...",
114
+ "Discovering tutorials...",
115
+ ]
116
+
117
+ SOURCE_COMPLETION_ORDER = [
118
+ "reddit",
119
+ "x",
120
+ "youtube",
121
+ "tiktok",
122
+ "instagram",
123
+ "hackernews",
124
+ "bluesky",
125
+ "truthsocial",
126
+ "polymarket",
127
+ "grounding",
128
+ "xiaohongshu",
129
+ "digg",
130
+ "arxiv",
131
+ "techmeme",
132
+ "trustpilot",
133
+ ]
134
+
135
+ SOURCE_COMPLETION_META = {
136
+ "reddit": ("Reddit", "thread", "threads", Colors.YELLOW),
137
+ "x": ("X", "post", "posts", Colors.CYAN),
138
+ "youtube": ("YouTube", "video", "videos", Colors.RED),
139
+ "tiktok": ("TikTok", "video", "videos", Colors.PURPLE),
140
+ "instagram": ("Instagram", "reel", "reels", Colors.PURPLE),
141
+ "hackernews": ("HN", "story", "stories", Colors.YELLOW),
142
+ "bluesky": ("Bluesky", "post", "posts", Colors.BLUE),
143
+ "truthsocial": ("Truth Social", "post", "posts", Colors.CYAN),
144
+ "polymarket": ("Polymarket", "market", "markets", Colors.GREEN),
145
+ "grounding": ("Web", "result", "results", Colors.GREEN),
146
+ "xiaohongshu": ("Xiaohongshu", "post", "posts", Colors.RED),
147
+ "digg": ("Digg", "cluster", "clusters", Colors.YELLOW),
148
+ "arxiv": ("arXiv", "paper", "papers", Colors.RED),
149
+ "techmeme": ("Techmeme", "headline", "headlines", Colors.CYAN),
150
+ "trustpilot": ("Trustpilot", "review", "reviews", Colors.GREEN),
151
+ }
152
+
153
+
154
+ def _completion_sources(source_counts: dict[str, int], display_sources: list[str] | None) -> list[str]:
155
+ requested = list(dict.fromkeys(display_sources or []))
156
+ if not requested:
157
+ requested = [source for source, count in source_counts.items() if count]
158
+ if not requested and source_counts:
159
+ requested = list(source_counts)
160
+
161
+ candidate_set = set(requested) | set(source_counts)
162
+ ordered = [source for source in SOURCE_COMPLETION_ORDER if source in candidate_set]
163
+ for source in requested + list(source_counts):
164
+ if source in candidate_set and source not in ordered:
165
+ ordered.append(source)
166
+ return ordered
167
+
168
+
169
+ def _format_completion_part(source: str, count: int, tty: bool) -> str:
170
+ label, singular, plural, color = SOURCE_COMPLETION_META.get(
171
+ source,
172
+ (source.replace("_", " ").title(), "result", "results", Colors.RESET),
173
+ )
174
+ unit = singular if count == 1 else plural
175
+ if tty:
176
+ return f"{color}{label}:{Colors.RESET} {count} {unit}"
177
+ return f"{label}: {count} {unit}"
178
+
179
+ def _build_nux_message(diag: dict = None) -> str:
180
+ """Build conversational NUX message with dynamic source status."""
181
+ available = set((diag or {}).get("available_sources", []))
182
+ if diag:
183
+ reddit = "✓" if "reddit" in available else "✗"
184
+ x = "✓" if "x" in available else "✗"
185
+ youtube = "✓" if "youtube" in available else "✗"
186
+ web = "✓" if "grounding" in available else "✗"
187
+ status_line = f"Reddit {reddit}, X {x}, YouTube {youtube}, Web {web}"
188
+ else:
189
+ status_line = "YouTube ✓, Web ✓, Reddit ✗, X ✗"
190
+
191
+ return f"""
192
+ I just researched that for you. Here's what I've got right now:
193
+
194
+ {status_line}
195
+
196
+ More sources means better research, but it works fine as-is. You can unlock more for free - log into x.com in your browser for X, and run `brew install yt-dlp` for YouTube transcripts. That gives you Reddit (with comments), X, YouTube, HN, and Polymarket - all free.
197
+
198
+ Some examples of what you can do:
199
+ - "last30 what are people saying about Figma"
200
+ - "last30 watch my biggest competitor every week"
201
+ - "last30 watch AI video tools monthly"
202
+ - "last30 what have you found about AI video?"
203
+
204
+ Just start with "last30" and talk to me like normal.
205
+ """
206
+
207
+ # Shorter promo for single missing key
208
+ PROMO_SINGLE_KEY = {
209
+ "reddit": "\n💡 Unlock TikTok and Instagram with SCRAPECREATORS_API_KEY - 10,000 free calls, no CC - scrapecreators.com\n",
210
+ "x": "\n💡 Unlock X: log into x.com in your browser, then re-run. "
211
+ "Firefox works on all platforms. Safari works on macOS (detected automatically). "
212
+ "Chrome, Brave, Edge, Arc, Vivaldi, Opera, or Chromium on macOS require "
213
+ "FROM_BROWSER=auto in .env (Keychain dialog). On Windows only Firefox is supported. "
214
+ "Or add AUTH_TOKEN/CT0 or XAI_API_KEY.\n",
215
+ "web": "\n💡 You can unlock native grounded web search with BRAVE_API_KEY or SERPER_API_KEY.\n",
216
+ }
217
+
218
+ # Bird auth help (for local users with vendored Bird CLI)
219
+ BIRD_AUTH_HELP = f"""
220
+ {Colors.YELLOW}Bird authentication failed.{Colors.RESET}
221
+
222
+ To fix this:
223
+ 1. Add AUTH_TOKEN and CT0 to ~/.config/last30days/.env, or to trusted .claude/last30days.env with LAST30DAYS_TRUST_PROJECT_CONFIG=1
224
+ 2. Or set XAI_API_KEY for the xAI fallback backend
225
+ """
226
+
227
+ BIRD_AUTH_HELP_PLAIN = """
228
+ Bird authentication failed.
229
+
230
+ To fix this:
231
+ 1. Add AUTH_TOKEN and CT0 to ~/.config/last30days/.env, or to trusted .claude/last30days.env with LAST30DAYS_TRUST_PROJECT_CONFIG=1
232
+ 2. Or set XAI_API_KEY for the xAI fallback backend
233
+ """
234
+
235
+ # Spinner frames
236
+ SPINNER_FRAMES = ['⠋', '⠙', '⠹', '⠸', '⠼', '⠴', '⠦', '⠧', '⠇', '⠏']
237
+ DOTS_FRAMES = [' ', '. ', '.. ', '...']
238
+
239
+
240
+ class Spinner:
241
+ """Animated spinner for long-running operations."""
242
+
243
+ def __init__(self, message: str = "Working", color: str = Colors.CYAN, quiet: bool = False):
244
+ self.message = message
245
+ self.color = color
246
+ self.running = False
247
+ self.thread: Optional[threading.Thread] = None
248
+ self.frame_idx = 0
249
+ self.shown_static = False
250
+ self.quiet = quiet # Suppress non-TTY start message (still shows ✓ completion)
251
+
252
+ def _spin(self):
253
+ while self.running:
254
+ frame = SPINNER_FRAMES[self.frame_idx % len(SPINNER_FRAMES)]
255
+ sys.stderr.write(f"\r{self.color}{frame}{Colors.RESET} {self.message} ")
256
+ sys.stderr.flush()
257
+ self.frame_idx += 1
258
+ time.sleep(0.08)
259
+
260
+ def start(self):
261
+ self.running = True
262
+ if IS_TTY:
263
+ # Real terminal - animate
264
+ self.thread = threading.Thread(target=self._spin, daemon=True)
265
+ self.thread.start()
266
+ else:
267
+ # Not a TTY (Claude Code) - just print once
268
+ if not self.shown_static and not self.quiet:
269
+ sys.stderr.write(f"⏳ {self.message}\n")
270
+ sys.stderr.flush()
271
+ self.shown_static = True
272
+
273
+ def update(self, message: str):
274
+ self.message = message
275
+ if not IS_TTY and not self.shown_static:
276
+ # Print update in non-TTY mode
277
+ sys.stderr.write(f"⏳ {message}\n")
278
+ sys.stderr.flush()
279
+
280
+ def stop(self, final_message: str = ""):
281
+ self.running = False
282
+ if self.thread:
283
+ self.thread.join(timeout=0.2)
284
+ if IS_TTY:
285
+ # Clear the line in real terminal
286
+ sys.stderr.write("\r" + " " * 80 + "\r")
287
+ if final_message:
288
+ sys.stderr.write(f"✓ {final_message}\n")
289
+ sys.stderr.flush()
290
+
291
+
292
+ class ProgressDisplay:
293
+ """Progress display for research phases."""
294
+
295
+ def __init__(self, topic: str, show_banner: bool = True):
296
+ self.topic = topic
297
+ self.spinner: Optional[Spinner] = None
298
+ self.start_time = time.time()
299
+
300
+ if show_banner:
301
+ self._show_banner()
302
+
303
+ def _show_banner(self):
304
+ if IS_TTY:
305
+ sys.stderr.write(MINI_BANNER + "\n")
306
+ sys.stderr.write(f"{Colors.DIM}Topic: {Colors.RESET}{Colors.BOLD}{self.topic}{Colors.RESET}\n\n")
307
+ else:
308
+ # Simple text for non-TTY
309
+ sys.stderr.write(f"/last30days · researching: {self.topic}\n")
310
+ sys.stderr.flush()
311
+
312
+ def start_reddit(self):
313
+ msg = random.choice(REDDIT_MESSAGES)
314
+ self.spinner = Spinner(f"{Colors.YELLOW}Reddit{Colors.RESET} {msg}", Colors.YELLOW)
315
+ self.spinner.start()
316
+
317
+ def end_reddit(self, count: int):
318
+ if self.spinner:
319
+ self.spinner.stop(f"{Colors.YELLOW}Reddit{Colors.RESET} Found {count} threads")
320
+
321
+ def start_reddit_enrich(self, current: int, total: int):
322
+ if self.spinner:
323
+ self.spinner.stop()
324
+ msg = random.choice(ENRICHING_MESSAGES)
325
+ self.spinner = Spinner(f"{Colors.YELLOW}Reddit{Colors.RESET} [{current}/{total}] {msg}", Colors.YELLOW)
326
+ self.spinner.start()
327
+
328
+ def update_reddit_enrich(self, current: int, total: int):
329
+ if self.spinner:
330
+ msg = random.choice(ENRICHING_MESSAGES)
331
+ self.spinner.update(f"{Colors.YELLOW}Reddit{Colors.RESET} [{current}/{total}] {msg}")
332
+
333
+ def end_reddit_enrich(self):
334
+ if self.spinner:
335
+ self.spinner.stop(f"{Colors.YELLOW}Reddit{Colors.RESET} Enriched with engagement data")
336
+
337
+ def start_x(self):
338
+ msg = random.choice(X_MESSAGES)
339
+ self.spinner = Spinner(f"{Colors.CYAN}X{Colors.RESET} {msg}", Colors.CYAN)
340
+ self.spinner.start()
341
+
342
+ def end_x(self, count: int):
343
+ if self.spinner:
344
+ self.spinner.stop(f"{Colors.CYAN}X{Colors.RESET} Found {count} posts")
345
+
346
+ def start_youtube(self):
347
+ msg = random.choice(YOUTUBE_MESSAGES)
348
+ self.spinner = Spinner(f"{Colors.RED}YouTube{Colors.RESET} {msg}", Colors.RED)
349
+ self.spinner.start()
350
+
351
+ def end_youtube(self, count: int):
352
+ if self.spinner:
353
+ self.spinner.stop(f"{Colors.RED}YouTube{Colors.RESET} Found {count} videos")
354
+
355
+ def start_tiktok(self):
356
+ msg = random.choice(TIKTOK_MESSAGES)
357
+ self.spinner = Spinner(f"{Colors.PURPLE}TikTok{Colors.RESET} {msg}", Colors.PURPLE)
358
+ self.spinner.start()
359
+
360
+ def end_tiktok(self, count: int):
361
+ if self.spinner:
362
+ self.spinner.stop(f"{Colors.PURPLE}TikTok{Colors.RESET} Found {count} videos")
363
+
364
+ def start_instagram(self):
365
+ msg = random.choice(INSTAGRAM_MESSAGES)
366
+ self.spinner = Spinner(f"{Colors.PURPLE}Instagram{Colors.RESET} {msg}", Colors.PURPLE)
367
+ self.spinner.start()
368
+
369
+ def end_instagram(self, count: int):
370
+ if self.spinner:
371
+ self.spinner.stop(f"{Colors.PURPLE}Instagram{Colors.RESET} Found {count} reels")
372
+
373
+ def start_hackernews(self):
374
+ msg = random.choice(HN_MESSAGES)
375
+ self.spinner = Spinner(f"{Colors.YELLOW}HN{Colors.RESET} {msg}", Colors.YELLOW, quiet=True)
376
+ self.spinner.start()
377
+
378
+ def end_hackernews(self, count: int):
379
+ if self.spinner:
380
+ self.spinner.stop(f"{Colors.YELLOW}HN{Colors.RESET} Found {count} stories")
381
+
382
+ def start_polymarket(self):
383
+ msg = random.choice(POLYMARKET_MESSAGES)
384
+ self.spinner = Spinner(f"{Colors.GREEN}Polymarket{Colors.RESET} {msg}", Colors.GREEN, quiet=True)
385
+ self.spinner.start()
386
+
387
+ def end_polymarket(self, count: int):
388
+ if self.spinner:
389
+ self.spinner.stop(f"{Colors.GREEN}Polymarket{Colors.RESET} Found {count} markets")
390
+
391
+ def start_processing(self):
392
+ msg = random.choice(PROCESSING_MESSAGES)
393
+ self.spinner = Spinner(f"{Colors.PURPLE}Processing{Colors.RESET} {msg}", Colors.PURPLE)
394
+ self.spinner.start()
395
+
396
+ def end_processing(self):
397
+ if self.spinner:
398
+ self.spinner.stop()
399
+
400
+ def show_complete(
401
+ self,
402
+ reddit_count: int = 0,
403
+ x_count: int = 0,
404
+ youtube_count: int = 0,
405
+ hn_count: int = 0,
406
+ pm_count: int = 0,
407
+ tiktok_count: int = 0,
408
+ ig_count: int = 0,
409
+ *,
410
+ source_counts: dict[str, int] | None = None,
411
+ display_sources: list[str] | None = None,
412
+ ):
413
+ elapsed = time.time() - self.start_time
414
+ if source_counts is None:
415
+ source_counts = {
416
+ "reddit": reddit_count,
417
+ "x": x_count,
418
+ "youtube": youtube_count,
419
+ "tiktok": tiktok_count,
420
+ "instagram": ig_count,
421
+ "hackernews": hn_count,
422
+ "polymarket": pm_count,
423
+ }
424
+ if display_sources is None:
425
+ display_sources = [source for source, count in source_counts.items() if count]
426
+ if not display_sources:
427
+ display_sources = ["reddit", "x"]
428
+
429
+ ordered_sources = _completion_sources(source_counts, display_sources)
430
+ parts = [
431
+ _format_completion_part(source, source_counts.get(source, 0), tty=IS_TTY)
432
+ for source in ordered_sources
433
+ ]
434
+ if IS_TTY:
435
+ sys.stderr.write(f"\n{Colors.GREEN}{Colors.BOLD}✓ Research complete{Colors.RESET} ")
436
+ sys.stderr.write(f"{Colors.DIM}({elapsed:.1f}s){Colors.RESET}\n")
437
+ sys.stderr.write(" " + " ".join(parts))
438
+ sys.stderr.write("\n\n")
439
+ else:
440
+ sys.stderr.write(f"✓ Research complete ({elapsed:.1f}s) - {', '.join(parts)}\n")
441
+ sys.stderr.flush()
442
+
443
+ def show_cached(self, age_hours: float = None):
444
+ if age_hours is not None:
445
+ age_str = f" ({age_hours:.1f}h old)"
446
+ else:
447
+ age_str = ""
448
+ sys.stderr.write(f"{Colors.GREEN}⚡{Colors.RESET} {Colors.DIM}Using cached results{age_str} - use --refresh for fresh data{Colors.RESET}\n\n")
449
+ sys.stderr.flush()
450
+
451
+ def show_error(self, message: str):
452
+ sys.stderr.write(f"{Colors.RED}✗ Error:{Colors.RESET} {message}\n")
453
+ sys.stderr.flush()
454
+
455
+ def start_web_only(self):
456
+ """Show web-only mode indicator."""
457
+ msg = random.choice(WEB_ONLY_MESSAGES)
458
+ self.spinner = Spinner(f"{Colors.GREEN}Web{Colors.RESET} {msg}", Colors.GREEN)
459
+ self.spinner.start()
460
+
461
+ def end_web_only(self):
462
+ """End web-only spinner."""
463
+ if self.spinner:
464
+ self.spinner.stop(f"{Colors.GREEN}Web{Colors.RESET} assistant will search the web")
465
+
466
+ def show_web_only_complete(self):
467
+ """Show completion for web-only mode."""
468
+ elapsed = time.time() - self.start_time
469
+ if IS_TTY:
470
+ sys.stderr.write(f"\n{Colors.GREEN}{Colors.BOLD}✓ Ready for web search{Colors.RESET} ")
471
+ sys.stderr.write(f"{Colors.DIM}({elapsed:.1f}s){Colors.RESET}\n")
472
+ sys.stderr.write(f" {Colors.GREEN}Web:{Colors.RESET} assistant will search blogs, docs & news\n\n")
473
+ else:
474
+ sys.stderr.write(f"✓ Ready for web search ({elapsed:.1f}s)\n")
475
+ sys.stderr.flush()
476
+
477
+ def show_promo(self, missing: str = "both", diag: dict = None):
478
+ """Show NUX / promotional message for missing API keys.
479
+
480
+ Args:
481
+ missing: 'both', 'all', 'reddit', or 'x' - which keys are missing
482
+ diag: Optional diagnostics dict for dynamic source status
483
+ """
484
+ if missing in ("both", "all"):
485
+ sys.stderr.write(_build_nux_message(diag))
486
+ elif missing in PROMO_SINGLE_KEY:
487
+ sys.stderr.write(PROMO_SINGLE_KEY[missing])
488
+ sys.stderr.flush()
489
+
490
+ def show_bird_auth_help(self):
491
+ """Show Bird authentication help."""
492
+ if IS_TTY:
493
+ sys.stderr.write(BIRD_AUTH_HELP)
494
+ else:
495
+ sys.stderr.write(BIRD_AUTH_HELP_PLAIN)
496
+ sys.stderr.flush()
497
+
498
+
499
+ def show_diagnostic_banner(diag: dict):
500
+ """Show pre-flight source status banner when sources are missing.
501
+
502
+ Args:
503
+ diag: Dict from pipeline.diagnose() with available_sources, x_backend,
504
+ bird status, provider availability, and native web backend info.
505
+ """
506
+ available_sources = set(diag.get("available_sources") or [])
507
+ has_reddit = "reddit" in available_sources
508
+ has_scrapecreators = diag.get("has_scrapecreators", False)
509
+ has_x = "x" in available_sources
510
+ has_youtube = "youtube" in available_sources
511
+ has_web = "grounding" in available_sources
512
+ has_xiaohongshu = "xiaohongshu" in available_sources
513
+ x_backend = diag.get("x_backend")
514
+ native_web_backend = diag.get("native_web_backend")
515
+
516
+ # If everything is available, no banner needed
517
+ if has_reddit and has_x and has_youtube and has_web:
518
+ return
519
+
520
+ lines = []
521
+
522
+ if IS_TTY:
523
+ lines.append(f"{Colors.DIM}┌─────────────────────────────────────────────────────┐{Colors.RESET}")
524
+ _header = f"/last30days v{_skill_version()} - Source Status"
525
+ lines.append(f"{Colors.DIM}│{Colors.RESET} {Colors.BOLD}{_header}{Colors.RESET}{' ' * (52 - len(_header))}{Colors.DIM}│{Colors.RESET}")
526
+ lines.append(f"{Colors.DIM}│{Colors.RESET} {Colors.DIM}│{Colors.RESET}")
527
+
528
+ # Reddit
529
+ if has_reddit and has_scrapecreators:
530
+ lines.append(f"{Colors.DIM}│{Colors.RESET} {Colors.GREEN}✅ Reddit{Colors.RESET} — full threads with comments {Colors.DIM}│{Colors.RESET}")
531
+ elif has_reddit:
532
+ lines.append(f"{Colors.DIM}│{Colors.RESET} {Colors.GREEN}✅ Reddit{Colors.RESET} — public threads (titles + scores) {Colors.DIM}│{Colors.RESET}")
533
+ else:
534
+ lines.append(f"{Colors.DIM}│{Colors.RESET} {Colors.RED}❌ Reddit{Colors.RESET} — unavailable {Colors.DIM}│{Colors.RESET}")
535
+
536
+ # X/Twitter
537
+ if has_x:
538
+ username = diag.get("bird_username", "")
539
+ label = f"Bird ({username})" if x_backend == "bird" and username else str(x_backend or "xai").upper()
540
+ lines.append(f"{Colors.DIM}│{Colors.RESET} {Colors.GREEN}✅ X/Twitter{Colors.RESET} — {label} {Colors.DIM}│{Colors.RESET}")
541
+ else:
542
+ lines.append(f"{Colors.DIM}│{Colors.RESET} {Colors.RED}❌ X/Twitter{Colors.RESET} — No X auth or fallback key {Colors.DIM}│{Colors.RESET}")
543
+ if diag.get("bird_installed"):
544
+ lines.append(f"{Colors.DIM}│{Colors.RESET} └─ Add AUTH_TOKEN/CT0 or XAI_API_KEY {Colors.DIM}│{Colors.RESET}")
545
+ else:
546
+ lines.append(f"{Colors.DIM}│{Colors.RESET} └─ Needs Node.js 22+ (Bird is bundled) {Colors.DIM}│{Colors.RESET}")
547
+
548
+ # YouTube
549
+ if has_youtube:
550
+ lines.append(f"{Colors.DIM}│{Colors.RESET} {Colors.GREEN}✅ YouTube{Colors.RESET} — yt-dlp found {Colors.DIM}│{Colors.RESET}")
551
+ else:
552
+ lines.append(f"{Colors.DIM}│{Colors.RESET} {Colors.RED}❌ YouTube{Colors.RESET} — yt-dlp not installed {Colors.DIM}│{Colors.RESET}")
553
+ lines.append(f"{Colors.DIM}│{Colors.RESET} └─ Fix: brew install yt-dlp (free) {Colors.DIM}│{Colors.RESET}")
554
+
555
+ # Xiaohongshu (only show when configured)
556
+ if has_xiaohongshu:
557
+ lines.append(f"{Colors.DIM}│{Colors.RESET} {Colors.GREEN}✅ Xiaohongshu{Colors.RESET} — API connected + logged in {Colors.DIM}│{Colors.RESET}")
558
+
559
+ # Web
560
+ if has_web:
561
+ backend = native_web_backend or "native"
562
+ lines.append(f"{Colors.DIM}│{Colors.RESET} {Colors.GREEN}✅ Web{Colors.RESET} — {backend} API {Colors.DIM}│{Colors.RESET}")
563
+ else:
564
+ lines.append(f"{Colors.DIM}│{Colors.RESET} {Colors.YELLOW}⚡ Web{Colors.RESET} — Add BRAVE_API_KEY or SERPER_API_KEY {Colors.DIM}│{Colors.RESET}")
565
+
566
+ lines.append(f"{Colors.DIM}│{Colors.RESET} {Colors.DIM}│{Colors.RESET}")
567
+ lines.append(f"{Colors.DIM}│{Colors.RESET} Config: {Colors.BOLD}~/.config/last30days/.env{Colors.RESET} {Colors.DIM}│{Colors.RESET}")
568
+ lines.append(f"{Colors.DIM}└─────────────────────────────────────────────────────┘{Colors.RESET}")
569
+ else:
570
+ # Plain text for non-TTY (Claude Code / Codex)
571
+ lines.append("┌─────────────────────────────────────────────────────┐")
572
+ _header_plain = f"/last30days v{_skill_version()} - Source Status"
573
+ lines.append(f"│ {_header_plain}{' ' * (52 - len(_header_plain))}│")
574
+ lines.append("│ │")
575
+
576
+ if has_reddit and has_scrapecreators:
577
+ lines.append("│ ✅ Reddit — full threads with comments │")
578
+ elif has_reddit:
579
+ lines.append("│ ✅ Reddit — public threads (titles + scores) │")
580
+ else:
581
+ lines.append("│ ❌ Reddit — unavailable │")
582
+
583
+ if has_x:
584
+ lines.append("│ ✅ X/Twitter — available │")
585
+ else:
586
+ lines.append("│ ❌ X/Twitter — No X auth or fallback key │")
587
+ if diag.get("bird_installed"):
588
+ lines.append("│ └─ Add AUTH_TOKEN/CT0 or XAI_API_KEY │")
589
+ else:
590
+ lines.append("│ └─ Needs Node.js 22+ (Bird is bundled) │")
591
+
592
+ if has_youtube:
593
+ lines.append("│ ✅ YouTube — yt-dlp found │")
594
+ else:
595
+ lines.append("│ ❌ YouTube — yt-dlp not installed │")
596
+ lines.append("│ └─ Fix: brew install yt-dlp (free) │")
597
+
598
+ if has_xiaohongshu:
599
+ lines.append("│ ✅ Xiaohongshu — API connected + logged in │")
600
+
601
+ if has_web:
602
+ backend = native_web_backend or "native"
603
+ lines.append(f"│ ✅ Web — {backend} API available{' ' * max(0, 13 - len(backend))}│")
604
+ else:
605
+ lines.append("│ ⚡ Web — Add BRAVE_API_KEY or SERPER_API_KEY │")
606
+
607
+ lines.append("│ │")
608
+ lines.append("│ Config: ~/.config/last30days/.env │")
609
+ lines.append("└─────────────────────────────────────────────────────┘")
610
+
611
+ sys.stderr.write("\n".join(lines) + "\n\n")
612
+ sys.stderr.flush()
613
+
614
+
615
+ def print_phase(phase: str, message: str):
616
+ """Print a phase message."""
617
+ colors = {
618
+ "reddit": Colors.YELLOW,
619
+ "x": Colors.CYAN,
620
+ "process": Colors.PURPLE,
621
+ "done": Colors.GREEN,
622
+ "error": Colors.RED,
623
+ }
624
+ color = colors.get(phase, Colors.RESET)
625
+ sys.stderr.write(f"{color}▸{Colors.RESET} {message}\n")
626
+ sys.stderr.flush()
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2025 Peter Steinberger
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.