@jairodri/huckleberry-cli 1.0.2 → 1.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (745) hide show
  1. package/README.md +85 -0
  2. package/agents/cos.json +2 -5
  3. package/agents/hermes/AGENTS.md +25 -49
  4. package/agents/hermes/fix-kimaki/SKILL.md +19 -92
  5. package/agents/hermes/hermes-fixer.md +44 -74
  6. package/agents/hermes.json +6 -18
  7. package/kanban/SKILL.md +18 -18
  8. package/kanban/package.json +1 -1
  9. package/kanban/src/dispatcher.mjs +1 -1
  10. package/kanban/templates/blog-social-campaign.yaml +6 -2
  11. package/kanban/templates/social-campaign.yaml +9 -4
  12. package/mcp/jev-calibration.mjs +335 -0
  13. package/mcp/jev-client.mjs +119 -0
  14. package/mcp/jev-thresholds.json +27 -0
  15. package/package.json +13 -9
  16. package/scripts/doctor-watchdog.sh +73 -0
  17. package/scripts/install-services.sh +34 -27
  18. package/scripts/self-improve-weekly.sh +34 -0
  19. package/scripts/sync-skills.mjs +121 -0
  20. package/skills/ab-test-setup/SKILL.md +266 -0
  21. package/skills/ab-test-setup/evals/evals.json +105 -0
  22. package/skills/ab-test-setup/references/sample-size-guide.md +263 -0
  23. package/skills/ab-test-setup/references/test-templates.md +277 -0
  24. package/skills/agent-reach/SKILL.md +132 -0
  25. package/skills/agent-reach/references/career.md +29 -0
  26. package/skills/agent-reach/references/dev.md +62 -0
  27. package/skills/agent-reach/references/search.md +33 -0
  28. package/skills/agent-reach/references/social.md +232 -0
  29. package/skills/agent-reach/references/video.md +130 -0
  30. package/skills/agent-reach/references/web.md +50 -0
  31. package/skills/ai-agent-seo/SKILL.md +450 -0
  32. package/skills/ai-cold-email-intelligence/SKILL.md +54 -0
  33. package/skills/ai-cold-email-intelligence/references/prompts.md +21 -0
  34. package/skills/ai-consensus-builder/SKILL.md +324 -0
  35. package/skills/ai-seo/SKILL.md +399 -0
  36. package/skills/ai-seo/evals/evals.json +90 -0
  37. package/skills/ai-seo/references/content-patterns.md +284 -0
  38. package/skills/ai-seo/references/platform-ranking-factors.md +152 -0
  39. package/skills/ai-visibility-audit/SKILL.md +322 -0
  40. package/skills/analytics-tracking/SKILL.md +309 -0
  41. package/skills/analytics-tracking/evals/evals.json +90 -0
  42. package/skills/analytics-tracking/references/event-library.md +260 -0
  43. package/skills/analytics-tracking/references/ga4-implementation.md +300 -0
  44. package/skills/analytics-tracking/references/gtm-implementation.md +390 -0
  45. package/skills/article-generator/SKILL.md +216 -0
  46. package/skills/auto-indexing/SKILL.md +179 -0
  47. package/skills/auto-indexing/scripts/auto-indexing.js +257 -0
  48. package/skills/auto-skill/SKILL.md +151 -0
  49. package/skills/auto-skill/correction-queue.js +102 -0
  50. package/skills/auto-skill/dedup.js +97 -0
  51. package/skills/auto-skill/skill-router.js +224 -0
  52. package/skills/autoresearch/SKILL.md +334 -0
  53. package/skills/autoresearch/autoresearch-autoresearch/SKILL.md.baseline +329 -0
  54. package/skills/autoresearch/autoresearch-autoresearch/changelog.md +34 -0
  55. package/skills/autoresearch/autoresearch-autoresearch/dashboard.html +116 -0
  56. package/skills/autoresearch/autoresearch-autoresearch/evals.md +39 -0
  57. package/skills/autoresearch/autoresearch-autoresearch/results.json +44 -0
  58. package/skills/autoresearch/autoresearch-autoresearch/results.tsv +3 -0
  59. package/skills/autoresearch/eval-guide.md +121 -0
  60. package/skills/b2b-cold-outreach/SKILL.md +322 -0
  61. package/skills/birdclaw/SKILL.md +82 -0
  62. package/skills/brainstorm/SKILL.md +168 -0
  63. package/skills/brand-kit-playground/SKILL.md +312 -0
  64. package/skills/brand-kit-playground/references/html-architecture.md +316 -0
  65. package/skills/brand-kit-playground/references/steal-patterns.md +88 -0
  66. package/skills/brand-voice/SKILL.md +223 -0
  67. package/skills/brand-voice/references/honesty-as-positioning.md +60 -0
  68. package/skills/brand-voice/references/voice-modes.md +1158 -0
  69. package/skills/business-advisory-council/README.md +136 -0
  70. package/skills/business-advisory-council/SKILL.md +94 -0
  71. package/skills/business-advisory-council/business-advisory-council.py +492 -0
  72. package/skills/business-advisory-council/discord-components-decision.json +8 -0
  73. package/skills/business-advisory-council/examples/steve-conley-partnership.json +6 -0
  74. package/skills/business-advisory-council/steve-conley-call-brief.json +6 -0
  75. package/skills/churn-prevention/SKILL.md +305 -0
  76. package/skills/churn-prevention/evals/evals.json +93 -0
  77. package/skills/churn-prevention/references/cancel-flow-patterns.md +316 -0
  78. package/skills/churn-prevention/references/dunning-playbook.md +408 -0
  79. package/skills/claw-compactor/LICENSE +21 -0
  80. package/skills/claw-compactor/README.md +459 -0
  81. package/skills/claw-compactor/SKILL.md +329 -0
  82. package/skills/claw-compactor/benchmark/RESULTS.md +104 -0
  83. package/skills/claw-compactor/benchmark/__init__.py +1 -0
  84. package/skills/claw-compactor/benchmark/compressors.py +520 -0
  85. package/skills/claw-compactor/benchmark/data/sample_01_devops.json +82 -0
  86. package/skills/claw-compactor/benchmark/data/sample_02_trading.json +54 -0
  87. package/skills/claw-compactor/benchmark/data/sample_03_ml_short.json +38 -0
  88. package/skills/claw-compactor/benchmark/data/sample_04_mixed_long.json +318 -0
  89. package/skills/claw-compactor/benchmark/data/sample_05_sysadmin.json +56 -0
  90. package/skills/claw-compactor/benchmark/evaluate.py +278 -0
  91. package/skills/claw-compactor/benchmark/report.py +241 -0
  92. package/skills/claw-compactor/benchmark/results/benchmark_results.json +405 -0
  93. package/skills/claw-compactor/benchmark/run_benchmark.py +238 -0
  94. package/skills/claw-compactor/engram.yaml +49 -0
  95. package/skills/claw-compactor/proxy/README.md +87 -0
  96. package/skills/claw-compactor/proxy/dashboard.html +804 -0
  97. package/skills/claw-compactor/proxy/event-log.mjs +213 -0
  98. package/skills/claw-compactor/proxy/fair-queue.mjs +288 -0
  99. package/skills/claw-compactor/proxy/metrics-store.mjs +425 -0
  100. package/skills/claw-compactor/proxy/package-lock.json +125 -0
  101. package/skills/claw-compactor/proxy/package.json +15 -0
  102. package/skills/claw-compactor/proxy/portal.html +360 -0
  103. package/skills/claw-compactor/proxy/process-registry.mjs +447 -0
  104. package/skills/claw-compactor/proxy/rate-limiter.mjs +117 -0
  105. package/skills/claw-compactor/proxy/redis-client.mjs +75 -0
  106. package/skills/claw-compactor/proxy/retry.mjs +182 -0
  107. package/skills/claw-compactor/proxy/server.mjs +2100 -0
  108. package/skills/claw-compactor/proxy/session-affinity.mjs +177 -0
  109. package/skills/claw-compactor/proxy/start.sh +23 -0
  110. package/skills/claw-compactor/proxy/test/event-log.test.mjs +237 -0
  111. package/skills/claw-compactor/proxy/test/helpers.mjs +103 -0
  112. package/skills/claw-compactor/proxy/test/integration.test.mjs +297 -0
  113. package/skills/claw-compactor/proxy/test/metrics-store.test.mjs +243 -0
  114. package/skills/claw-compactor/proxy/test/process-registry.test.mjs +390 -0
  115. package/skills/claw-compactor/proxy/test/rate-limiter.test.mjs +121 -0
  116. package/skills/claw-compactor/proxy/test/redis-client.test.mjs +62 -0
  117. package/skills/claw-compactor/proxy/test/token-tracker.test.mjs +200 -0
  118. package/skills/claw-compactor/proxy/token-tracker.mjs +482 -0
  119. package/skills/claw-compactor/pyproject.toml +26 -0
  120. package/skills/claw-compactor/references/README.md +44 -0
  121. package/skills/claw-compactor/references/architecture.md +197 -0
  122. package/skills/claw-compactor/references/benchmarks.md +94 -0
  123. package/skills/claw-compactor/references/compression-prompts.md +39 -0
  124. package/skills/claw-compactor/references/compression-techniques.md +219 -0
  125. package/skills/claw-compactor/references/testing.md +160 -0
  126. package/skills/claw-compactor/scripts/audit_memory.py +216 -0
  127. package/skills/claw-compactor/scripts/compress_memory.py +236 -0
  128. package/skills/claw-compactor/scripts/compressed_context.py +280 -0
  129. package/skills/claw-compactor/scripts/dedup_memory.py +147 -0
  130. package/skills/claw-compactor/scripts/dictionary_compress.py +170 -0
  131. package/skills/claw-compactor/scripts/engram-auto.sh +152 -0
  132. package/skills/claw-compactor/scripts/engram_auto.py +695 -0
  133. package/skills/claw-compactor/scripts/engram_cli.py +474 -0
  134. package/skills/claw-compactor/scripts/estimate_tokens.py +131 -0
  135. package/skills/claw-compactor/scripts/generate_summary_tiers.py +292 -0
  136. package/skills/claw-compactor/scripts/lib/__init__.py +34 -0
  137. package/skills/claw-compactor/scripts/lib/config.py +289 -0
  138. package/skills/claw-compactor/scripts/lib/dedup.py +119 -0
  139. package/skills/claw-compactor/scripts/lib/dictionary.py +281 -0
  140. package/skills/claw-compactor/scripts/lib/engram.py +793 -0
  141. package/skills/claw-compactor/scripts/lib/engram_prompts.py +175 -0
  142. package/skills/claw-compactor/scripts/lib/engram_storage.py +254 -0
  143. package/skills/claw-compactor/scripts/lib/exceptions.py +24 -0
  144. package/skills/claw-compactor/scripts/lib/markdown.py +312 -0
  145. package/skills/claw-compactor/scripts/lib/rle.py +165 -0
  146. package/skills/claw-compactor/scripts/lib/tokenizer_optimizer.py +188 -0
  147. package/skills/claw-compactor/scripts/lib/tokens.py +68 -0
  148. package/skills/claw-compactor/scripts/mem_compress.py +788 -0
  149. package/skills/claw-compactor/scripts/observation_compressor.py +346 -0
  150. package/skills/claw-compactor/tests/__init__.py +0 -0
  151. package/skills/claw-compactor/tests/conftest.py +94 -0
  152. package/skills/claw-compactor/tests/test_audit_comprehensive.py +123 -0
  153. package/skills/claw-compactor/tests/test_audit_memory.py +67 -0
  154. package/skills/claw-compactor/tests/test_benchmark.py +122 -0
  155. package/skills/claw-compactor/tests/test_cli_commands.py +228 -0
  156. package/skills/claw-compactor/tests/test_compress_memory.py +109 -0
  157. package/skills/claw-compactor/tests/test_compress_memory_comprehensive.py +191 -0
  158. package/skills/claw-compactor/tests/test_compressed_context.py +145 -0
  159. package/skills/claw-compactor/tests/test_config.py +54 -0
  160. package/skills/claw-compactor/tests/test_dedup_memory.py +124 -0
  161. package/skills/claw-compactor/tests/test_dictionary.py +327 -0
  162. package/skills/claw-compactor/tests/test_dictionary_comprehensive.py +241 -0
  163. package/skills/claw-compactor/tests/test_engram.py +1091 -0
  164. package/skills/claw-compactor/tests/test_engram_auto.py +529 -0
  165. package/skills/claw-compactor/tests/test_error_handling.py +194 -0
  166. package/skills/claw-compactor/tests/test_estimate_tokens.py +99 -0
  167. package/skills/claw-compactor/tests/test_generate_summary_tiers.py +105 -0
  168. package/skills/claw-compactor/tests/test_integration.py +249 -0
  169. package/skills/claw-compactor/tests/test_lib_dedup.py +135 -0
  170. package/skills/claw-compactor/tests/test_lib_markdown.py +388 -0
  171. package/skills/claw-compactor/tests/test_lib_tokens.py +82 -0
  172. package/skills/claw-compactor/tests/test_main_entry.py +176 -0
  173. package/skills/claw-compactor/tests/test_markdown_advanced.py +284 -0
  174. package/skills/claw-compactor/tests/test_new_features.py +77 -0
  175. package/skills/claw-compactor/tests/test_observation_comprehensive.py +261 -0
  176. package/skills/claw-compactor/tests/test_observation_compressor.py +128 -0
  177. package/skills/claw-compactor/tests/test_performance.py +172 -0
  178. package/skills/claw-compactor/tests/test_pipeline.py +109 -0
  179. package/skills/claw-compactor/tests/test_real_workspace.py +161 -0
  180. package/skills/claw-compactor/tests/test_rle.py +114 -0
  181. package/skills/claw-compactor/tests/test_rle_comprehensive.py +151 -0
  182. package/skills/claw-compactor/tests/test_roundtrip.py +253 -0
  183. package/skills/claw-compactor/tests/test_roundtrip_comprehensive.py +192 -0
  184. package/skills/claw-compactor/tests/test_tiers_comprehensive.py +171 -0
  185. package/skills/claw-compactor/tests/test_token_economics.py +237 -0
  186. package/skills/claw-compactor/tests/test_tokenizer_optimizer.py +175 -0
  187. package/skills/claw-compactor/tests/test_tokenizer_optimizer_comprehensive.py +241 -0
  188. package/skills/claw-compactor/tests/test_tokens.py +27 -0
  189. package/skills/cmo/CHANGELOG.md +61 -0
  190. package/skills/cmo/SKILL.md +500 -0
  191. package/skills/cmo/references/ai-slop-patterns.md +56 -0
  192. package/skills/cmo/references/analytics-guide.md +152 -0
  193. package/skills/cmo/references/ideas-library.md +197 -0
  194. package/skills/cmo/rules/brand-file-map.md +198 -0
  195. package/skills/cmo/rules/brand-memory.md +158 -0
  196. package/skills/cmo/rules/cli-runtime-index.md +95 -0
  197. package/skills/cmo/rules/command-reference.md +167 -0
  198. package/skills/cmo/rules/communication.md +15 -0
  199. package/skills/cmo/rules/context-switch.md +101 -0
  200. package/skills/cmo/rules/ecosystem.md +125 -0
  201. package/skills/cmo/rules/error-recovery.md +98 -0
  202. package/skills/cmo/rules/learning-loop.md +170 -0
  203. package/skills/cmo/rules/monorepo.md +78 -0
  204. package/skills/cmo/rules/output-format.md +124 -0
  205. package/skills/cmo/rules/persona.md +15 -0
  206. package/skills/cmo/rules/playbooks.md +327 -0
  207. package/skills/cmo/rules/progressive-enhancement.md +231 -0
  208. package/skills/cmo/rules/publish-index.md +106 -0
  209. package/skills/cmo/rules/quality-gate.md +90 -0
  210. package/skills/cmo/rules/recency-grounding.md +124 -0
  211. package/skills/cmo/rules/safety.md +80 -0
  212. package/skills/cmo/rules/studio-api-index.md +138 -0
  213. package/skills/cmo/rules/studio-integration.md +147 -0
  214. package/skills/cmo/rules/sub-agents.md +167 -0
  215. package/skills/cold-email/SKILL.md +240 -0
  216. package/skills/cold-email/evals/evals.json +94 -0
  217. package/skills/cold-email/references/benchmarks.md +83 -0
  218. package/skills/cold-email/references/follow-up-sequences.md +81 -0
  219. package/skills/cold-email/references/frameworks.md +90 -0
  220. package/skills/cold-email/references/personalization.md +79 -0
  221. package/skills/cold-email/references/subject-lines.md +53 -0
  222. package/skills/competitive-intel/SKILL.md +433 -0
  223. package/skills/competitive-intel/references/competitive-frameworks.md +145 -0
  224. package/skills/competitor-alternatives/SKILL.md +362 -0
  225. package/skills/competitor-alternatives/evals/evals.json +93 -0
  226. package/skills/competitor-alternatives/references/content-architecture.md +271 -0
  227. package/skills/competitor-alternatives/references/templates.md +223 -0
  228. package/skills/concreteness-fixer/SKILL.md +483 -0
  229. package/skills/concreteness-fixer/scripts/validation/concreteness-validator.js +221 -0
  230. package/skills/concreteness-fixer/utils/execFileNoThrow.js +16 -0
  231. package/skills/content-atomizer/SKILL.md +424 -0
  232. package/skills/content-atomizer/references/hook-strategies.md +56 -0
  233. package/skills/content-atomizer/references/platform-specs.md +118 -0
  234. package/skills/content-atomizer/references/platforms/bluesky.md +64 -0
  235. package/skills/content-atomizer/references/platforms/instagram.md +77 -0
  236. package/skills/content-atomizer/references/platforms/linkedin.md +120 -0
  237. package/skills/content-atomizer/references/platforms/reddit.md +73 -0
  238. package/skills/content-atomizer/references/platforms/threads.md +64 -0
  239. package/skills/content-atomizer/references/platforms/tiktok.md +55 -0
  240. package/skills/content-atomizer/references/platforms/twitter.md +123 -0
  241. package/skills/content-atomizer/references/platforms/youtube.md +56 -0
  242. package/skills/content-atomizer/references/tweet-patterns.md +40 -0
  243. package/skills/content-repost-manager/SKILL.md +245 -0
  244. package/skills/content-repost-manager/scripts/content-repost-scan.py +133 -0
  245. package/skills/context-recovery/.clawdhub/origin.json +7 -0
  246. package/skills/context-recovery/SKILL.md +198 -0
  247. package/skills/context-recovery/_meta.json +6 -0
  248. package/skills/conversion-flow-cro/SKILL.md +248 -0
  249. package/skills/conversion-flow-cro/references/flow-benchmarks.md +158 -0
  250. package/skills/copy-editing/SKILL.md +474 -0
  251. package/skills/copy-editing/evals/evals.json +89 -0
  252. package/skills/copy-editing/references/plain-english-alternatives.md +394 -0
  253. package/skills/copywriting/SKILL.md +349 -0
  254. package/skills/copywriting/evals/evals.json +111 -0
  255. package/skills/copywriting/references/awareness-level-guide.md +227 -0
  256. package/skills/copywriting/references/copy-frameworks.md +389 -0
  257. package/skills/copywriting/references/natural-transitions.md +272 -0
  258. package/skills/creative/SKILL.md +365 -0
  259. package/skills/creative/modes/ad-creative.md +1748 -0
  260. package/skills/creative/modes/product-photo.md +1520 -0
  261. package/skills/creative/modes/product-video.md +1657 -0
  262. package/skills/creative/modes/social-graphics.md +1511 -0
  263. package/skills/creative/modes/talking-head.md +2208 -0
  264. package/skills/creative/references/VISUAL_INTELLIGENCE.md +1233 -0
  265. package/skills/deep-serp-article/SKILL.md +677 -0
  266. package/skills/deep-serp-article/SKILL.md.bak +530 -0
  267. package/skills/earned-media/SKILL.md +260 -0
  268. package/skills/email-sequences/SKILL.md +446 -0
  269. package/skills/email-sequences/references/sequence-templates.md +1217 -0
  270. package/skills/firecrawl/.skill-meta.json +13 -0
  271. package/skills/firecrawl/SKILL.md +154 -0
  272. package/skills/firecrawl/rules/install.md +63 -0
  273. package/skills/firecrawl/rules/security.md +26 -0
  274. package/skills/form-cro/SKILL.md +429 -0
  275. package/skills/form-cro/evals/evals.json +90 -0
  276. package/skills/free-tool-strategy/SKILL.md +325 -0
  277. package/skills/free-tool-strategy/evals/evals.json +90 -0
  278. package/skills/free-tool-strategy/references/tool-types.md +253 -0
  279. package/skills/frontend-slides/SKILL.md +248 -0
  280. package/skills/frontend-slides/STYLE_PRESETS.md +347 -0
  281. package/skills/frontend-slides/animation-patterns.md +110 -0
  282. package/skills/frontend-slides/html-template.md +347 -0
  283. package/skills/frontend-slides/scripts/extract-pptx.py +96 -0
  284. package/skills/frontend-slides/viewport-base.css +153 -0
  285. package/skills/guardrail-framework/SKILL.md +319 -0
  286. package/skills/hook-generator/SKILL.md +438 -0
  287. package/skills/hook-generator/database/2026-PLATFORM-RESEARCH.md +211 -0
  288. package/skills/hook-generator/database/instagram-hooks.json +591 -0
  289. package/skills/hook-generator/database/linkedin-hooks.json +502 -0
  290. package/skills/hook-generator/database/medium-hooks.json +181 -0
  291. package/skills/hook-generator/database/tiktok-hooks.json +337 -0
  292. package/skills/hook-generator/database/twitter-hooks.json +567 -0
  293. package/skills/hook-generator/database/youtube-hooks.json +275 -0
  294. package/skills/hook-generator/package-lock.json +24 -0
  295. package/skills/hook-generator/package.json +5 -0
  296. package/skills/hook-generator/references/hook-generation-system.md +257 -0
  297. package/skills/hook-generator/references/hook-performance-analysis.json +153 -0
  298. package/skills/hook-generator/references/hooks-library.md +128 -0
  299. package/skills/hook-generator/references/platform-hook-frameworks.md +275 -0
  300. package/skills/hook-generator/scripts/generate-hooks-unified.js +722 -0
  301. package/skills/hook-generator/scripts/generate-hooks.js +225 -0
  302. package/skills/hook-generator/scripts/generate.sh +36 -0
  303. package/skills/hook-generator/scripts/ralph-hook-enhancer.js +864 -0
  304. package/skills/hook-generator/scripts/test-gemini-output.js +51 -0
  305. package/skills/humanizer/README.md +120 -0
  306. package/skills/humanizer/SKILL.md +699 -0
  307. package/skills/image-gen/SKILL.md +277 -0
  308. package/skills/image-gen/references/prompt-patterns.md +114 -0
  309. package/skills/image-gen/references/visual-metaphors.md +51 -0
  310. package/skills/impeccable/SKILL.md +86 -0
  311. package/skills/impeccable/reference/adapt.md +312 -0
  312. package/skills/impeccable/reference/adapt.native.md +58 -0
  313. package/skills/impeccable/reference/android.md +40 -0
  314. package/skills/impeccable/reference/animate.md +86 -0
  315. package/skills/impeccable/reference/audit.md +136 -0
  316. package/skills/impeccable/reference/audit.native.md +139 -0
  317. package/skills/impeccable/reference/bolder.md +31 -0
  318. package/skills/impeccable/reference/clarify.md +94 -0
  319. package/skills/impeccable/reference/colorize.md +86 -0
  320. package/skills/impeccable/reference/craft-floor.md +42 -0
  321. package/skills/impeccable/reference/craft.md +5 -0
  322. package/skills/impeccable/reference/critique.md +788 -0
  323. package/skills/impeccable/reference/degraded/asset-producer.md +90 -0
  324. package/skills/impeccable/reference/degraded/documenter.md +24 -0
  325. package/skills/impeccable/reference/degraded/finish-reviewer.md +37 -0
  326. package/skills/impeccable/reference/degraded/manual-edit-applier.md +92 -0
  327. package/skills/impeccable/reference/delight.md +70 -0
  328. package/skills/impeccable/reference/distill.md +111 -0
  329. package/skills/impeccable/reference/doctor.md +53 -0
  330. package/skills/impeccable/reference/document.md +416 -0
  331. package/skills/impeccable/reference/extract.md +69 -0
  332. package/skills/impeccable/reference/harden.md +336 -0
  333. package/skills/impeccable/reference/hooks.md +105 -0
  334. package/skills/impeccable/reference/init.md +125 -0
  335. package/skills/impeccable/reference/ios.md +45 -0
  336. package/skills/impeccable/reference/layout.md +84 -0
  337. package/skills/impeccable/reference/live-setup.md +102 -0
  338. package/skills/impeccable/reference/live.md +323 -0
  339. package/skills/impeccable/reference/new-work.md +110 -0
  340. package/skills/impeccable/reference/onboard.md +234 -0
  341. package/skills/impeccable/reference/operate.md +61 -0
  342. package/skills/impeccable/reference/optimize.md +258 -0
  343. package/skills/impeccable/reference/overdrive.md +127 -0
  344. package/skills/impeccable/reference/polish.md +97 -0
  345. package/skills/impeccable/reference/quieter.md +99 -0
  346. package/skills/impeccable/reference/routing.md +18 -0
  347. package/skills/impeccable/reference/shape.md +59 -0
  348. package/skills/impeccable/reference/typeset.md +80 -0
  349. package/skills/impeccable/reference/visualize.md +49 -0
  350. package/skills/impeccable/scripts/command-metadata.json +94 -0
  351. package/skills/impeccable/scripts/concept-seed.mjs +558 -0
  352. package/skills/impeccable/scripts/context-signals.mjs +334 -0
  353. package/skills/impeccable/scripts/context.mjs +1467 -0
  354. package/skills/impeccable/scripts/critique-storage.mjs +213 -0
  355. package/skills/impeccable/scripts/detect-csp.mjs +198 -0
  356. package/skills/impeccable/scripts/detect.mjs +21 -0
  357. package/skills/impeccable/scripts/detector/browser/injected/index.mjs +2023 -0
  358. package/skills/impeccable/scripts/detector/cli/main.mjs +438 -0
  359. package/skills/impeccable/scripts/detector/design-system.mjs +1046 -0
  360. package/skills/impeccable/scripts/detector/detect-antipatterns-browser.js +8283 -0
  361. package/skills/impeccable/scripts/detector/detect-antipatterns.mjs +50 -0
  362. package/skills/impeccable/scripts/detector/engines/browser/detect-url.mjs +372 -0
  363. package/skills/impeccable/scripts/detector/engines/regex/detect-text.mjs +1168 -0
  364. package/skills/impeccable/scripts/detector/engines/static-html/css-cascade.mjs +1186 -0
  365. package/skills/impeccable/scripts/detector/engines/static-html/detect-html.mjs +264 -0
  366. package/skills/impeccable/scripts/detector/engines/visual/screenshot-contrast.mjs +189 -0
  367. package/skills/impeccable/scripts/detector/findings.mjs +18 -0
  368. package/skills/impeccable/scripts/detector/node/file-system.mjs +203 -0
  369. package/skills/impeccable/scripts/detector/profile/profiler.mjs +166 -0
  370. package/skills/impeccable/scripts/detector/registry/antipatterns.mjs +617 -0
  371. package/skills/impeccable/scripts/detector/rules/checks.mjs +5580 -0
  372. package/skills/impeccable/scripts/detector/shared/color.mjs +124 -0
  373. package/skills/impeccable/scripts/detector/shared/constants.mjs +112 -0
  374. package/skills/impeccable/scripts/detector/shared/fonts.mjs +30 -0
  375. package/skills/impeccable/scripts/detector/shared/inline-ignores.mjs +148 -0
  376. package/skills/impeccable/scripts/detector/shared/page.mjs +7 -0
  377. package/skills/impeccable/scripts/doctor.mjs +336 -0
  378. package/skills/impeccable/scripts/embed-prompt.mjs +133 -0
  379. package/skills/impeccable/scripts/generate-image.mjs +240 -0
  380. package/skills/impeccable/scripts/hook-admin.mjs +801 -0
  381. package/skills/impeccable/scripts/hook-before-edit.mjs +508 -0
  382. package/skills/impeccable/scripts/hook-lib.mjs +2153 -0
  383. package/skills/impeccable/scripts/hook.mjs +78 -0
  384. package/skills/impeccable/scripts/lib/artifact-schema.mjs +93 -0
  385. package/skills/impeccable/scripts/lib/composition-catalog.mjs +200 -0
  386. package/skills/impeccable/scripts/lib/concept-catalog.mjs +384 -0
  387. package/skills/impeccable/scripts/lib/design-parser.mjs +925 -0
  388. package/skills/impeccable/scripts/lib/impeccable-config.mjs +658 -0
  389. package/skills/impeccable/scripts/lib/impeccable-paths.mjs +137 -0
  390. package/skills/impeccable/scripts/lib/is-generated.mjs +69 -0
  391. package/skills/impeccable/scripts/lib/provider.mjs +5 -0
  392. package/skills/impeccable/scripts/lib/roll-selection.mjs +362 -0
  393. package/skills/impeccable/scripts/lib/staleness-deep.mjs +478 -0
  394. package/skills/impeccable/scripts/lib/staleness-notice.mjs +169 -0
  395. package/skills/impeccable/scripts/lib/staleness.mjs +457 -0
  396. package/skills/impeccable/scripts/lib/surface-briefs.mjs +151 -0
  397. package/skills/impeccable/scripts/lib/target-args.mjs +42 -0
  398. package/skills/impeccable/scripts/lib/target-slug.mjs +33 -0
  399. package/skills/impeccable/scripts/lib/template-extensions.mjs +146 -0
  400. package/skills/impeccable/scripts/live/accept-css.mjs +617 -0
  401. package/skills/impeccable/scripts/live/accept-verify.mjs +60 -0
  402. package/skills/impeccable/scripts/live/browser-script-parts.mjs +55 -0
  403. package/skills/impeccable/scripts/live/completion.mjs +28 -0
  404. package/skills/impeccable/scripts/live/event-validation.mjs +199 -0
  405. package/skills/impeccable/scripts/live/frameworks/astro.mjs +47 -0
  406. package/skills/impeccable/scripts/live/frameworks/detect-utils.mjs +73 -0
  407. package/skills/impeccable/scripts/live/frameworks/index.mjs +143 -0
  408. package/skills/impeccable/scripts/live/frameworks/journal.mjs +197 -0
  409. package/skills/impeccable/scripts/live/frameworks/nextjs.mjs +49 -0
  410. package/skills/impeccable/scripts/live/frameworks/nuxt.mjs +161 -0
  411. package/skills/impeccable/scripts/live/frameworks/script-src.mjs +17 -0
  412. package/skills/impeccable/scripts/live/frameworks/static-html.mjs +26 -0
  413. package/skills/impeccable/scripts/live/frameworks/sveltekit.mjs +71 -0
  414. package/skills/impeccable/scripts/live/frameworks/tag-strategy.mjs +247 -0
  415. package/skills/impeccable/scripts/live/frameworks/tanstack-start.mjs +70 -0
  416. package/skills/impeccable/scripts/live/frameworks/vite-generic.mjs +42 -0
  417. package/skills/impeccable/scripts/live/generation-preflight.mjs +149 -0
  418. package/skills/impeccable/scripts/live/insert-ui.mjs +458 -0
  419. package/skills/impeccable/scripts/live/instructions.mjs +142 -0
  420. package/skills/impeccable/scripts/live/manual-apply.mjs +939 -0
  421. package/skills/impeccable/scripts/live/manual-edit-routes.mjs +357 -0
  422. package/skills/impeccable/scripts/live/manual-edits-buffer.mjs +152 -0
  423. package/skills/impeccable/scripts/live/poll-lanes.mjs +14 -0
  424. package/skills/impeccable/scripts/live/roots.mjs +508 -0
  425. package/skills/impeccable/scripts/live/session-store.mjs +563 -0
  426. package/skills/impeccable/scripts/live/source-lock.mjs +105 -0
  427. package/skills/impeccable/scripts/live/source-search.mjs +105 -0
  428. package/skills/impeccable/scripts/live/svelte-ast.mjs +961 -0
  429. package/skills/impeccable/scripts/live/svelte-component.mjs +1342 -0
  430. package/skills/impeccable/scripts/live/sveltekit-adapter.mjs +316 -0
  431. package/skills/impeccable/scripts/live/tanstack-adapter.mjs +280 -0
  432. package/skills/impeccable/scripts/live/ui-core.mjs +180 -0
  433. package/skills/impeccable/scripts/live/vocabulary.mjs +171 -0
  434. package/skills/impeccable/scripts/live-accept.mjs +954 -0
  435. package/skills/impeccable/scripts/live-browser-dom.js +146 -0
  436. package/skills/impeccable/scripts/live-browser-session.js +123 -0
  437. package/skills/impeccable/scripts/live-browser.js +12520 -0
  438. package/skills/impeccable/scripts/live-commit-manual-edits.mjs +1244 -0
  439. package/skills/impeccable/scripts/live-complete.mjs +107 -0
  440. package/skills/impeccable/scripts/live-copy-edit-agent.mjs +683 -0
  441. package/skills/impeccable/scripts/live-discard-manual-edits.mjs +51 -0
  442. package/skills/impeccable/scripts/live-inject.mjs +503 -0
  443. package/skills/impeccable/scripts/live-insert.mjs +292 -0
  444. package/skills/impeccable/scripts/live-manual-edit-evidence.mjs +368 -0
  445. package/skills/impeccable/scripts/live-poll.mjs +429 -0
  446. package/skills/impeccable/scripts/live-resume.mjs +123 -0
  447. package/skills/impeccable/scripts/live-server.mjs +1669 -0
  448. package/skills/impeccable/scripts/live-status.mjs +71 -0
  449. package/skills/impeccable/scripts/live-target.mjs +30 -0
  450. package/skills/impeccable/scripts/live-wrap.mjs +927 -0
  451. package/skills/impeccable/scripts/live.mjs +359 -0
  452. package/skills/impeccable/scripts/modern-screenshot.umd.js +14 -0
  453. package/skills/impeccable/scripts/palette.mjs +628 -0
  454. package/skills/impeccable/scripts/pin.mjs +221 -0
  455. package/skills/impeccable/scripts/serve-question.mjs +932 -0
  456. package/skills/impeccable/scripts/surface-brief.mjs +74 -0
  457. package/skills/inkstone-admin/SKILL.md +66 -0
  458. package/skills/jev-hook-gate/SKILL.md +111 -0
  459. package/skills/keyword-research/SKILL.md +503 -0
  460. package/skills/keyword-research/references/dr-cap-and-confidence.md +62 -0
  461. package/skills/keyword-research/references/keyword-examples.md +769 -0
  462. package/skills/landing-page-architect/SKILL.md +585 -0
  463. package/skills/landing-page-architect/references/architecture-reference.md +32 -0
  464. package/skills/launch-strategy/SKILL.md +384 -0
  465. package/skills/launch-strategy/evals/evals.json +91 -0
  466. package/skills/launch-strategy/references/launch-checklist.md +209 -0
  467. package/skills/launch-strategy/references/launch-timeline.md +159 -0
  468. package/skills/lead-email-craft/SKILL.md +522 -0
  469. package/skills/lead-magnets/SKILL.md +310 -0
  470. package/skills/lead-magnets/references/benchmarks.md +129 -0
  471. package/skills/lead-magnets/references/format-guide.md +196 -0
  472. package/skills/link-building-seo/SKILL.md +210 -0
  473. package/skills/lint-report.txt +1 -0
  474. package/skills/manifest.json +129 -0
  475. package/skills/marketing-demo/SKILL.md +249 -0
  476. package/skills/marketing-demo/references/remotion-examples.md +281 -0
  477. package/skills/marketing-ideas/SKILL.md +167 -0
  478. package/skills/marketing-ideas/evals/evals.json +90 -0
  479. package/skills/marketing-ideas/references/ideas-by-category.md +366 -0
  480. package/skills/marketing-psychology/SKILL.md +374 -0
  481. package/skills/marketing-psychology/evals/evals.json +88 -0
  482. package/skills/marketing-psychology/references/case-studies.md +148 -0
  483. package/skills/narrative-research-article/SKILL.md +469 -0
  484. package/skills/narrative-research-article/references/lanusse-patterns.md +166 -0
  485. package/skills/notebooklm/SKILL.md +674 -0
  486. package/skills/off-page-seo/SKILL.md +219 -0
  487. package/skills/onboarding-cro/SKILL.md +220 -0
  488. package/skills/onboarding-cro/evals/evals.json +92 -0
  489. package/skills/onboarding-cro/references/experiments.md +258 -0
  490. package/skills/original-research/SKILL.md +388 -0
  491. package/skills/page-cro/SKILL.md +269 -0
  492. package/skills/page-cro/references/cro-benchmarks.md +140 -0
  493. package/skills/paper-marketing/SKILL.md +448 -0
  494. package/skills/paper-marketing/references/agent-quality-rubric.md +68 -0
  495. package/skills/paper-marketing/references/brand-system-template.md +120 -0
  496. package/skills/paper-marketing/references/paper-mcp-rules.md +71 -0
  497. package/skills/paper-marketing/references/platform-conventions.md +43 -0
  498. package/skills/paywall-upgrade-cro/SKILL.md +227 -0
  499. package/skills/paywall-upgrade-cro/evals/evals.json +93 -0
  500. package/skills/paywall-upgrade-cro/references/experiments.md +164 -0
  501. package/skills/platform-formatting/SKILL.md +51 -0
  502. package/skills/popup-cro/SKILL.md +454 -0
  503. package/skills/popup-cro/evals/evals.json +94 -0
  504. package/skills/positioning-angles/SKILL.md +524 -0
  505. package/skills/positioning-angles/references/ad-matrix-and-examples.md +176 -0
  506. package/skills/positioning-angles/references/angle-frameworks.md +187 -0
  507. package/skills/positioning-angles/references/dunford-positioning.md +135 -0
  508. package/skills/positioning-angles/references/hormozi-offer.md +247 -0
  509. package/skills/positioning-angles/references/schwartz-sophistication.md +166 -0
  510. package/skills/positioning-angles/references/unique-mechanism.md +162 -0
  511. package/skills/pricing-strategy/SKILL.md +346 -0
  512. package/skills/pricing-strategy/evals/evals.json +90 -0
  513. package/skills/pricing-strategy/references/research-methods.md +152 -0
  514. package/skills/pricing-strategy/references/tier-structure.md +307 -0
  515. package/skills/programmatic-seo/SKILL.md +238 -0
  516. package/skills/programmatic-seo/evals/evals.json +94 -0
  517. package/skills/programmatic-seo/references/playbooks.md +308 -0
  518. package/skills/project-rag/SKILL.md +127 -0
  519. package/skills/quality-gate/SKILL.md +519 -0
  520. package/skills/quality-gate/judge-personas/buyer.md +47 -0
  521. package/skills/quality-gate/judge-personas/expert.md +47 -0
  522. package/skills/quality-gate/judge-personas/outsider.md +47 -0
  523. package/skills/quality-gate/judge-personas/scanner.md +41 -0
  524. package/skills/quality-gate/judge-personas/skeptic.md +40 -0
  525. package/skills/referral-program/SKILL.md +290 -0
  526. package/skills/referral-program/evals/evals.json +89 -0
  527. package/skills/referral-program/references/affiliate-programs.md +163 -0
  528. package/skills/referral-program/references/program-examples.md +143 -0
  529. package/skills/review-sites/SKILL.md +279 -0
  530. package/skills/revops/SKILL.md +343 -0
  531. package/skills/revops/evals/evals.json +91 -0
  532. package/skills/revops/references/automation-playbooks.md +290 -0
  533. package/skills/revops/references/lifecycle-definitions.md +278 -0
  534. package/skills/revops/references/routing-rules.md +203 -0
  535. package/skills/revops/references/scoring-models.md +247 -0
  536. package/skills/saas-product-seo/SKILL.md +324 -0
  537. package/skills/sales-enablement/SKILL.md +349 -0
  538. package/skills/sales-enablement/evals/evals.json +91 -0
  539. package/skills/sales-enablement/references/deck-frameworks.md +263 -0
  540. package/skills/sales-enablement/references/demo-scripts.md +355 -0
  541. package/skills/sales-enablement/references/objection-library.md +270 -0
  542. package/skills/sales-enablement/references/one-pager-templates.md +208 -0
  543. package/skills/schema-markup/SKILL.md +179 -0
  544. package/skills/schema-markup/evals/evals.json +87 -0
  545. package/skills/schema-markup/references/schema-examples.md +398 -0
  546. package/skills/self-improve/SKILL.md +166 -0
  547. package/skills/self-improving-agent/README.md +243 -0
  548. package/skills/self-improving-agent/SKILL.md +437 -0
  549. package/skills/self-improving-agent/scripts/__init__.py +16 -0
  550. package/skills/self-improving-agent/scripts/__pycache__/auto_detect.cpython-314.pyc +0 -0
  551. package/skills/self-improving-agent/scripts/__pycache__/nlm_curation.cpython-314.pyc +0 -0
  552. package/skills/self-improving-agent/scripts/__pycache__/self_improving_agent.cpython-314.pyc +0 -0
  553. package/skills/self-improving-agent/scripts/auto_detect.py +270 -0
  554. package/skills/self-improving-agent/scripts/init_expertise_registry.py +89 -0
  555. package/skills/self-improving-agent/scripts/nlm_curation.py +259 -0
  556. package/skills/self-improving-agent/scripts/self-improving-agent +113 -0
  557. package/skills/self-improving-agent/scripts/self_improving_agent.py +603 -0
  558. package/skills/self-improving-agent/scripts/test_curation_scorer.py +20 -0
  559. package/skills/self-improving-agent/scripts/test_self_improving.py +184 -0
  560. package/skills/send-email/SKILL.md +426 -0
  561. package/skills/send-email/references/batch-email-examples.md +807 -0
  562. package/skills/send-email/references/best-practices.md +453 -0
  563. package/skills/send-email/references/installation.md +123 -0
  564. package/skills/send-email/references/single-email-examples.md +470 -0
  565. package/skills/send-email/references/webhooks.md +221 -0
  566. package/skills/seo-audit/SKILL.md +362 -0
  567. package/skills/seo-audit/references/ai-writing-detection.md +200 -0
  568. package/skills/seo-audit/references/architecture-patterns.md +271 -0
  569. package/skills/seo-audit/references/schema-templates.md +427 -0
  570. package/skills/seo-content/SKILL.md +510 -0
  571. package/skills/seo-content/references/anti-ai-detection.md +184 -0
  572. package/skills/seo-content/references/content-structures.md +148 -0
  573. package/skills/seo-content/references/eeat-examples.md +235 -0
  574. package/skills/seo-content/references/on-page-seo.md +261 -0
  575. package/skills/seo-content/references/pseo-playbooks.md +226 -0
  576. package/skills/seo-content/references/schema-templates.md +104 -0
  577. package/skills/seo-content/references/serp-analysis-format.md +151 -0
  578. package/skills/seo-machine/SKILL.md +331 -0
  579. package/skills/seo-machine/assets/brand-template.md +73 -0
  580. package/skills/seo-machine/assets/link-inventory-template.md +74 -0
  581. package/skills/seo-machine/assets/roadmap-template.md +184 -0
  582. package/skills/seo-machine/references/api-stack-recipes.md +230 -0
  583. package/skills/seo-machine/references/exa-recipes.md +260 -0
  584. package/skills/seo-machine/references/manual-research.md +73 -0
  585. package/skills/seo-machine/references/methodology.md +87 -0
  586. package/skills/seo-machine/references/off-page.md +123 -0
  587. package/skills/seo-machine/references/patterns/alternatives.md +176 -0
  588. package/skills/seo-machine/references/patterns/compare.md +105 -0
  589. package/skills/seo-machine/references/patterns/playbooks.md +106 -0
  590. package/skills/seo-machine/references/patterns/use-case.md +109 -0
  591. package/skills/seo-machine/references/quality-bars.md +99 -0
  592. package/skills/seo-machine/references/stacks/astro.md +156 -0
  593. package/skills/seo-machine/references/stacks/detection.md +61 -0
  594. package/skills/seo-machine/references/stacks/markdown-fallback.md +181 -0
  595. package/skills/seo-machine/references/stacks/nextjs.md +108 -0
  596. package/skills/seo-machine/references/stacks/rails-inertia.md +99 -0
  597. package/skills/seo-machine/references/striking-distance.md +116 -0
  598. package/skills/seo-machine/references/technical-audit.md +153 -0
  599. package/skills/seo-machine/scripts/link_audit.py +265 -0
  600. package/skills/seo-machine/scripts/tech_audit.py +221 -0
  601. package/skills/seo-machine/scripts/word_count.py +154 -0
  602. package/skills/sharp-thesis-validator/SKILL.md +393 -0
  603. package/skills/sharp-thesis-validator/examples.md +186 -0
  604. package/skills/signup-flow-cro/SKILL.md +359 -0
  605. package/skills/signup-flow-cro/evals/evals.json +88 -0
  606. package/skills/site-architecture/SKILL.md +357 -0
  607. package/skills/site-architecture/evals/evals.json +88 -0
  608. package/skills/site-architecture/references/mermaid-templates.md +216 -0
  609. package/skills/site-architecture/references/navigation-patterns.md +305 -0
  610. package/skills/site-architecture/references/site-type-templates.md +293 -0
  611. package/skills/skill-self-improvement/SKILL.md +151 -0
  612. package/skills/slideshow-script/SKILL.md +274 -0
  613. package/skills/slideshow-script/references/content-spec-schema.md +77 -0
  614. package/skills/slideshow-script/references/frameworks.md +84 -0
  615. package/skills/slideshow-script/references/paips-framework.md +37 -0
  616. package/skills/social-campaign/SKILL.md +419 -0
  617. package/skills/social-campaign/references/paper-mcp-workflow.md +48 -0
  618. package/skills/social-content/SKILL.md +359 -0
  619. package/skills/social-content/evals/evals.json +92 -0
  620. package/skills/social-content/references/platforms.md +170 -0
  621. package/skills/social-content/references/post-templates.md +177 -0
  622. package/skills/social-content/references/reverse-engineering.md +195 -0
  623. package/skills/social-worker/SKILL.md +204 -0
  624. package/skills/startup-launcher/SKILL.md +252 -0
  625. package/skills/startup-launcher/references/file-router.md +64 -0
  626. package/skills/startup-launcher/references/platform-matrix.md +65 -0
  627. package/skills/startup-launcher/references/platforms/alternativeto.md +283 -0
  628. package/skills/startup-launcher/references/platforms/appsumo.md +495 -0
  629. package/skills/startup-launcher/references/platforms/auraplusplus.md +736 -0
  630. package/skills/startup-launcher/references/platforms/betalist.md +98 -0
  631. package/skills/startup-launcher/references/platforms/capterra.md +276 -0
  632. package/skills/startup-launcher/references/platforms/crunchbase.md +514 -0
  633. package/skills/startup-launcher/references/platforms/dealify.md +291 -0
  634. package/skills/startup-launcher/references/platforms/dealmirror.md +313 -0
  635. package/skills/startup-launcher/references/platforms/desifounder.md +490 -0
  636. package/skills/startup-launcher/references/platforms/devhunt.md +210 -0
  637. package/skills/startup-launcher/references/platforms/devpost.md +448 -0
  638. package/skills/startup-launcher/references/platforms/fazier.md +56 -0
  639. package/skills/startup-launcher/references/platforms/firsto.md +489 -0
  640. package/skills/startup-launcher/references/platforms/g2.md +226 -0
  641. package/skills/startup-launcher/references/platforms/hackernews.md +99 -0
  642. package/skills/startup-launcher/references/platforms/hackernoon.md +385 -0
  643. package/skills/startup-launcher/references/platforms/indiedeals.md +367 -0
  644. package/skills/startup-launcher/references/platforms/indiehackers.md +80 -0
  645. package/skills/startup-launcher/references/platforms/kenmoo.md +231 -0
  646. package/skills/startup-launcher/references/platforms/labstartups.md +618 -0
  647. package/skills/startup-launcher/references/platforms/launchboard.md +307 -0
  648. package/skills/startup-launcher/references/platforms/launchfast.md +560 -0
  649. package/skills/startup-launcher/references/platforms/launchigniter.md +56 -0
  650. package/skills/startup-launcher/references/platforms/launchingnext.md +674 -0
  651. package/skills/startup-launcher/references/platforms/launchit.md +574 -0
  652. package/skills/startup-launcher/references/platforms/launchyourapp.md +677 -0
  653. package/skills/startup-launcher/references/platforms/libhunt.md +220 -0
  654. package/skills/startup-launcher/references/platforms/ltdhunt.md +221 -0
  655. package/skills/startup-launcher/references/platforms/microlaunch.md +45 -0
  656. package/skills/startup-launcher/references/platforms/openalternative.md +195 -0
  657. package/skills/startup-launcher/references/platforms/peerlist.md +56 -0
  658. package/skills/startup-launcher/references/platforms/peerpush.md +64 -0
  659. package/skills/startup-launcher/references/platforms/primeclub.md +282 -0
  660. package/skills/startup-launcher/references/platforms/productcanyon.md +190 -0
  661. package/skills/startup-launcher/references/platforms/producthunt.md +98 -0
  662. package/skills/startup-launcher/references/platforms/rankinpublic.md +315 -0
  663. package/skills/startup-launcher/references/platforms/rockethub.md +374 -0
  664. package/skills/startup-launcher/references/platforms/saasgenius.md +175 -0
  665. package/skills/startup-launcher/references/platforms/saashub.md +205 -0
  666. package/skills/startup-launcher/references/platforms/saasmantra.md +221 -0
  667. package/skills/startup-launcher/references/platforms/saaspirate.md +287 -0
  668. package/skills/startup-launcher/references/platforms/saaswarrior.md +190 -0
  669. package/skills/startup-launcher/references/platforms/saaszilla.md +194 -0
  670. package/skills/startup-launcher/references/platforms/selected.md +925 -0
  671. package/skills/startup-launcher/references/platforms/sideprojectors.md +86 -0
  672. package/skills/startup-launcher/references/platforms/softonic.md +240 -0
  673. package/skills/startup-launcher/references/platforms/sourceforge.md +251 -0
  674. package/skills/startup-launcher/references/platforms/stacksocial.md +244 -0
  675. package/skills/startup-launcher/references/platforms/startupstash.md +326 -0
  676. package/skills/startup-launcher/references/platforms/theresanaiforthat.md +253 -0
  677. package/skills/startup-launcher/references/platforms/tinylaunch.md +70 -0
  678. package/skills/startup-launcher/references/platforms/tinystartups.md +72 -0
  679. package/skills/startup-launcher/references/platforms/toolfolio.md +291 -0
  680. package/skills/startup-launcher/references/platforms/trustmrr.md +194 -0
  681. package/skills/startup-launcher/references/platforms/trylaunch.md +531 -0
  682. package/skills/startup-launcher/references/platforms/uneed.md +57 -0
  683. package/skills/startup-launcher/references/templates/asset-checklist.md +218 -0
  684. package/skills/startup-launcher/references/templates/launch-tracker.md +195 -0
  685. package/skills/startup-launcher/references/templates/product-brief.md +98 -0
  686. package/skills/summarize/.skill-meta.json +13 -0
  687. package/skills/summarize/SKILL.md +170 -0
  688. package/skills/summarize/rules/install.md +157 -0
  689. package/skills/summarize/rules/usage.md +207 -0
  690. package/skills/topical-authority/SKILL.md +307 -0
  691. package/skills/topical-authority/references/jake-ward-framework.md +201 -0
  692. package/skills/topical-authority/references/serp-clustering-algorithm.md +325 -0
  693. package/skills/topical-authority/scripts/orchestrator.js +367 -0
  694. package/skills/topical-authority/scripts/seo/analyze-competitor-coverage.js +3 -0
  695. package/skills/topical-authority/scripts/seo/audit-internal-links.js +3 -0
  696. package/skills/topical-authority/scripts/seo/build-clusters-from-serp.js +3 -0
  697. package/skills/topical-authority/scripts/seo/extract-keywords-from-forums.js +3 -0
  698. package/skills/topical-authority/scripts/seo/extract-paa-questions.js +3 -0
  699. package/skills/topical-authority/scripts/seo/fetch-serp-urls.js +3 -0
  700. package/skills/topical-authority/scripts/seo/gemini-serp-clustering.js +3 -0
  701. package/skills/topical-authority/scripts/seo/identify-content-gaps.js +3 -0
  702. package/skills/topical-authority/scripts/seo/identify-research-gaps.js +3 -0
  703. package/skills/topical-authority/scripts/seo/scrape-quora-questions.js +3 -0
  704. package/skills/topical-authority/scripts/seo/scrape-reddit-pain-points.js +3 -0
  705. package/skills/topical-authority/scripts/seo/weave-internal-links.js +3 -0
  706. package/skills/visual-style/SKILL.md +199 -0
  707. package/skills/voice-brand-alignment/SKILL.md +70 -0
  708. package/skills/voice-brand-alignment/references/ai-slop-patterns.md +405 -0
  709. package/skills/voice-brand-alignment/scripts/validation/gemini-voice-validator.js +96 -0
  710. package/skills/voice-extraction/SKILL.md +234 -0
  711. package/skills/voice-extraction/references/extraction-prompt.md +155 -0
  712. package/skills/voice-extraction/references/voice-dna-template.md +168 -0
  713. package/skills/voice-extraction/references/voice-elements.md +259 -0
  714. package/skills/voice-extraction/scripts/build-corpus.js +120 -0
  715. package/skills/voice-extraction/scripts/collect-sources.sh +168 -0
  716. package/skills/warm-outbound/SKILL.md +299 -0
  717. package/skills/warm-outbound/templates/warm-message.md +39 -0
  718. package/skills/weekly-newsletter-digest/SKILL.md +78 -0
  719. package/skills/x-playwriter/SKILL.md +428 -0
  720. package/skills/x-playwriter/scripts/x-browser.js +185 -0
  721. package/skills/x-post-generator-openclaw/SKILL.md +138 -0
  722. package/skills/x-post-generator-openclaw/scripts/generate-x-post.js +537 -0
  723. package/skills/x-posting-playwriter/SKILL.md +203 -0
  724. package/skills/x-research/SKILL.md +129 -0
  725. package/skills/x-research/x-research.sh +85 -0
  726. package/skills/youtube-summarize/SKILL.md +90 -0
  727. package/skills/youtube-summarize/scripts/youtube-summarize.sh +143 -0
  728. package/src/cli.js +347 -172
  729. package/src/harness/deepseek-adapter.js +102 -0
  730. package/src/harness/deepseek.js +225 -0
  731. package/src/harness/opencode-adapter.js +174 -0
  732. package/src/harness/pi-adapter.js +172 -0
  733. package/src/harness/registry.js +121 -0
  734. package/src/harness/telemetry.js +102 -0
  735. package/src/harness/types.js +165 -0
  736. package/src/interview.js +36 -4
  737. package/src/postinstall.js +10 -12
  738. package/templates/AGENTS.md +17 -17
  739. package/templates/ORG.md +1 -1
  740. package/templates/TOOLS.md +7 -2
  741. package/templates/opencode.json +26 -29
  742. package/wiki/doctor.md +54 -0
  743. package/wiki/inkstone.md +4 -4
  744. package/wiki/opencode.md +3 -3
  745. package/skills/curated.txt +0 -68
@@ -0,0 +1,102 @@
1
+ /**
2
+ * deepseek-adapter — routes a task to a DeepSeek model, either:
3
+ * - direct DeepSeek API (DEEPSEEK_API_KEY), or
4
+ * - OpenRouter (OPENROUTER_API_KEY) using a deepseek/* route
5
+ *
6
+ * Cost-optimized alternative to the local opencode harness: one stateless chat
7
+ * completion per task with per-task token + cost tracking. No tool use /
8
+ * filesystem access, so registry policy routes tool-dependent tasks to opencode.
9
+ */
10
+ import { HarnessAdapter, baseResult, nowIso } from "./types.js";
11
+ import {
12
+ chatCompletion, computeCost, isPeakNow, defaultModel, probe,
13
+ resolveProvider, providerKey, DEEPSEEK_MODELS, OPENROUTER_MODELS,
14
+ } from "./deepseek.js";
15
+
16
+ export class DeepSeekAdapter extends HarnessAdapter {
17
+ constructor(opts = {}) {
18
+ super({ id: "deepseek", label: "DeepSeek (cost-optimized)", ...opts });
19
+ this.provider = opts.provider || resolveProvider();
20
+ this.apiKey = opts.apiKey || providerKey(this.provider);
21
+ }
22
+
23
+ capabilities() {
24
+ const table = this.provider === "openrouter" ? OPENROUTER_MODELS : DEEPSEEK_MODELS;
25
+ const m = table[defaultModel(this.provider)];
26
+ const costIn = this.provider === "openrouter" ? (m?.input ?? 0.051) : (m?.inPeak ?? 0.30);
27
+ const costOut = this.provider === "openrouter" ? (m?.output ?? 0.567) : (m?.outPeak ?? 1.20);
28
+ return {
29
+ streaming: false,
30
+ checkpoint: false, // stateless API — nothing to resume
31
+ cancel: true, // AbortSignal per request
32
+ files: false, // no filesystem access
33
+ tools: false, // pure completion, no tool calls in v1
34
+ modelChoice: true,
35
+ provider: this.provider,
36
+ costPerMTokIn: costIn,
37
+ costPerMTokOut: costOut,
38
+ };
39
+ }
40
+
41
+ async status() {
42
+ if (!this.apiKey) {
43
+ const envName = this.provider === "openrouter" ? "OPENROUTER_API_KEY" : "DEEPSEEK_API_KEY";
44
+ return { ready: false, reason: `missing ${envName}`, detail: `add ${envName} to ~/.huckleberry/.env` };
45
+ }
46
+ const p = await probe(this.apiKey, this.provider);
47
+ if (!p.ok) return { ready: false, reason: `${this.provider} probe failed: ${p.error}`, detail: "check key/network/credits" };
48
+ return { ready: true, detail: `${this.provider} · ${p.models.length} models · ${defaultModel(this.provider)}` };
49
+ }
50
+
51
+ /**
52
+ * @param {import("./types.js").TaskRequest} task
53
+ * @returns {Promise<import("./types.js").TaskResult>}
54
+ */
55
+ async submit(task) {
56
+ const started = Date.now();
57
+ const out = baseResult({ ...task, adapterId: this.id });
58
+ const model = task.model || defaultModel(this.provider);
59
+ if (!this.apiKey) {
60
+ out.status = "error";
61
+ out.error = `${this.provider === "openrouter" ? "OPENROUTER_API_KEY" : "DEEPSEEK_API_KEY"} not set — cannot run deepseek adapter`;
62
+ out.durationMs = Date.now() - started;
63
+ return out;
64
+ }
65
+ try {
66
+ const messages = [];
67
+ if (task.system) messages.push({ role: "system", content: task.system });
68
+ messages.push({ role: "user", content: task.prompt });
69
+ const r = await chatCompletion({
70
+ provider: this.provider,
71
+ apiKey: this.apiKey,
72
+ model,
73
+ messages,
74
+ maxTokens: task.maxTokens || 4096,
75
+ timeoutMs: task.timeoutMs || 180000,
76
+ });
77
+ out.output = r.content;
78
+ out.model = r.model;
79
+ const cacheHit = r.usage.prompt_cache_hit_tokens ?? r.usage.cache_read_input_tokens ?? 0;
80
+ out.usage = {
81
+ input: r.usage.prompt_tokens || 0,
82
+ output: r.usage.completion_tokens || 0,
83
+ cacheHit,
84
+ cacheMiss: r.usage.prompt_cache_miss_tokens ?? Math.max(0, (r.usage.prompt_tokens || 0) - cacheHit),
85
+ };
86
+ out.costUsd = computeCost({ model: r.model, usage: r.usage }, !isPeakNow(), this.provider);
87
+ out.status = out.output ? "ok" : "error";
88
+ if (!out.output) out.error = "empty completion (model returned no content)";
89
+ } catch (e) {
90
+ out.status = "error";
91
+ out.error = e.message;
92
+ }
93
+ out.durationMs = Date.now() - started;
94
+ out.startedAt = nowIso();
95
+ return out;
96
+ }
97
+
98
+ async cancel(_taskId) {
99
+ // stateless: each call uses its own AbortSignal; nothing to cancel post-hoc
100
+ return false;
101
+ }
102
+ }
@@ -0,0 +1,225 @@
1
+ /**
2
+ * DeepSeek client — OpenAI-compatible, two providers:
3
+ * - direct: https://api.deepseek.com (needs DEEPSEEK_API_KEY)
4
+ * - openrouter: https://openrouter.ai/api/v1 (needs OPENROUTER_API_KEY)
5
+ *
6
+ * Direct DeepSeek pricing (per 1M tokens, verified api-docs.deepseek.com 2026-11-04):
7
+ * deepseek-flash: in $0.15 off-peak / $0.30 peak (cache hit: $0.003/$0.006) · out $0.60/$1.20
8
+ * deepseek-v4-pro: in $0.66 off-peak / $1.32 peak (cache hit: $0.022/$0.044) · out $1.98/$3.96
9
+ * Off-peak = all hours except 01:00-04:00 & 06:00-10:00 UTC Mon-Fri (excluding CN holidays).
10
+ *
11
+ * OpenRouter pricing differs per model route and is fetched live where possible;
12
+ * the table below is a fallback snapshot (verified via /models 2026-11-06, $/1M tok).
13
+ */
14
+ import { writeFileSync, mkdirSync, readFileSync, existsSync } from "node:fs";
15
+ import { join, dirname } from "node:path";
16
+ import { homedir } from "node:os";
17
+
18
+ /**
19
+ * Load key=value pairs from ~/.huckleberry/.env into a flat object. The harness
20
+ * runs as a subprocess that does not inherit a user's shell env, so credentials
21
+ * written by `huckleberry install` must be read from the state file.
22
+ * @returns {Record<string,string>}
23
+ */
24
+ export function loadHarnessEnv() {
25
+ const out = {};
26
+ const root = process.env.HUCKLEBERRY_HOME || homedir();
27
+ const envPath = join(root, ".huckleberry", ".env");
28
+ if (!existsSync(envPath)) return out;
29
+ try {
30
+ for (const line of readFileSync(envPath, "utf8").split("\n")) {
31
+ const m = line.match(/^\s*([A-Z0-9_]+)\s*=\s*(.*)\s*$/);
32
+ if (m && m[2]) out[m[1]] = m[2].replace(/^["']|["']$/g, "").trim();
33
+ }
34
+ } catch { /* unreadable — treat as empty */ }
35
+ return out;
36
+ }
37
+
38
+ /**
39
+ * Merged env for credential resolution. Precedence: ~/.huckleberry/.env WINS over
40
+ * ambient process env for credential keys. Rationale: the install's own .env is the
41
+ * documented place keys are set, and an unrelated ambient OPENROUTER_API_KEY (e.g.
42
+ * from a workspace .env with an expired key) must not silently break the harness.
43
+ * Per-task overrides are passed explicitly via TaskRequest.env.
44
+ */
45
+ function envWithFile() {
46
+ return { ...process.env, ...loadHarnessEnv() };
47
+ }
48
+
49
+ export const DEEPSEEK_BASE_URL = process.env.DEEPSEEK_BASE_URL || "https://api.deepseek.com";
50
+ export const OPENROUTER_BASE_URL = process.env.OPENROUTER_BASE_URL || "https://openrouter.ai/api/v1";
51
+
52
+ export const DEEPSEEK_MODELS = {
53
+ "deepseek-flash": {
54
+ inPeak: 0.30, inOffPeak: 0.15, inCacheHitPeak: 0.006, inCacheHitOffPeak: 0.003,
55
+ outPeak: 1.20, outOffPeak: 0.60,
56
+ },
57
+ "deepseek-v4-pro": {
58
+ inPeak: 1.32, inOffPeak: 0.66, inCacheHitPeak: 0.044, inCacheHitOffPeak: 0.022,
59
+ outPeak: 3.96, outOffPeak: 1.98,
60
+ },
61
+ };
62
+
63
+ /**
64
+ * OpenRouter route pricing ($/1M tok). Snapshot 2026-11-06; used when the live
65
+ * /models lookup has not run. `input`/`output` are list prices, cache reads billed lower.
66
+ */
67
+ export const OPENROUTER_MODELS = {
68
+ "deepseek/deepseek-v4.1-flash": { input: 0.051, output: 0.567, cacheRead: 0.0102 },
69
+ "deepseek/deepseek-v4.1-flash-1017": { input: 0.15, output: 0.60, cacheRead: 0.03 },
70
+ "deepseek/deepseek-v4-pro": { input: 0.88, output: 1.76, cacheRead: 0.176 },
71
+ "deepseek/deepseek-v4-pro-0813": { input: 0.1165, output: 4.66, cacheRead: 0.0233 },
72
+ "deepseek/deepseek-v3.2": { input: 0.26, output: 0.38, cacheRead: 0.052 },
73
+ };
74
+
75
+ /** Resolve the active provider from env (process env + ~/.huckleberry/.env). Defaults to direct DeepSeek. */
76
+ export function resolveProvider(env = envWithFile()) {
77
+ const explicit = (env.HUCKLEBERRY_DEEPSEEK_PROVIDER || "").toLowerCase();
78
+ if (explicit === "openrouter" || explicit === "deepseek") return explicit;
79
+ if (env.DEEPSEEK_API_KEY) return "deepseek";
80
+ if (env.OPENROUTER_API_KEY) return "openrouter";
81
+ return "deepseek";
82
+ }
83
+
84
+ export function providerKey(provider = resolveProvider()) {
85
+ const env = envWithFile();
86
+ return provider === "openrouter"
87
+ ? (env.OPENROUTER_API_KEY || "")
88
+ : (env.DEEPSEEK_API_KEY || "");
89
+ }
90
+
91
+ export function providerBaseUrl(provider = resolveProvider()) {
92
+ return provider === "openrouter" ? OPENROUTER_BASE_URL : DEEPSEEK_BASE_URL;
93
+ }
94
+
95
+ export function defaultModel(provider = resolveProvider()) {
96
+ const env = envWithFile();
97
+ if (provider === "openrouter") return env.DEEPSEEK_MODEL || "deepseek/deepseek-v4.1-flash";
98
+ return env.DEEPSEEK_MODEL || "deepseek-flash";
99
+ }
100
+
101
+ /** Peak windows: 01:00-04:00 and 06:00-10:00 UTC, Mon-Fri. */
102
+ export function isPeakNow(date = new Date()) {
103
+ const d = date.getUTCDay();
104
+ const h = date.getUTCHours();
105
+ if (d === 0 || d === 6) return false; // weekends always off-peak
106
+ return (h >= 1 && h < 4) || (h >= 6 && h < 10);
107
+ }
108
+
109
+ /**
110
+ * Compute USD cost from token usage.
111
+ * - direct provider: peak rates unless offPeak=true
112
+ * - openrouter provider: list prices from OPENROUTER_MODELS (input/output + cache read)
113
+ * @param {{model:string, usage:Object}} r
114
+ * @param {boolean} [offPeak]
115
+ * @param {string} [provider]
116
+ * @returns {number} cost in USD (6dp)
117
+ */
118
+ export function computeCost(r, offPeak = !isPeakNow(), provider = resolveProvider()) {
119
+ if (provider === "openrouter") {
120
+ const p = OPENROUTER_MODELS[r.model] || OPENROUTER_MODELS[defaultModel("openrouter")] || { input: 0.051, output: 0.567, cacheRead: 0.01 };
121
+ const hit = r.usage.prompt_cache_hit_tokens || r.usage.cache_read_input_tokens || 0;
122
+ const miss = r.usage.prompt_cache_miss_tokens ?? Math.max(0, (r.usage.prompt_tokens || 0) - hit);
123
+ const cost = (hit / 1e6) * p.cacheRead + (miss / 1e6) * p.input + ((r.usage.completion_tokens || 0) / 1e6) * p.output;
124
+ return Math.round(cost * 1e6) / 1e6;
125
+ }
126
+ const p = DEEPSEEK_MODELS[r.model] || DEEPSEEK_MODELS[defaultModel("deepseek")];
127
+ const hit = r.usage.prompt_cache_hit_tokens || 0;
128
+ const miss = r.usage.prompt_cache_miss_tokens ?? Math.max(0, (r.usage.prompt_tokens || 0) - hit);
129
+ const inRate = offPeak ? p.inOffPeak : p.inPeak;
130
+ const hitRate = offPeak ? p.inCacheHitOffPeak : p.inCacheHitPeak;
131
+ const outRate = offPeak ? p.outOffPeak : p.outPeak;
132
+ const cost = (hit / 1e6) * hitRate + (miss / 1e6) * inRate + ((r.usage.completion_tokens || 0) / 1e6) * outRate;
133
+ return Math.round(cost * 1e6) / 1e6;
134
+ }
135
+
136
+ /**
137
+ * Minimal OpenAI-compatible chat completions call. Works against DeepSeek direct
138
+ * and OpenRouter (same wire shape). OpenRouter additionally accepts attribution headers.
139
+ * @param {Object} opts
140
+ * @param {string} [opts.apiKey] defaults to provider key from env
141
+ * @param {string} [opts.provider] "deepseek" | "openrouter"
142
+ * @param {Array<{role:string, content:string}>} opts.messages
143
+ * @param {string} [opts.model]
144
+ * @param {number} [opts.maxTokens]
145
+ * @param {number} [opts.temperature]
146
+ * @param {number} [opts.timeoutMs] default 120000
147
+ * @param {string} [opts.baseUrl]
148
+ * @returns {Promise<{content:string, usage:Object, model:string, raw:Object}>}
149
+ */
150
+ export async function chatCompletion(opts) {
151
+ const provider = opts.provider || resolveProvider();
152
+ const model = opts.model || defaultModel(provider);
153
+ const apiKey = opts.apiKey || providerKey(provider);
154
+ const baseUrl = opts.baseUrl || providerBaseUrl(provider);
155
+ const headers = { "Content-Type": "application/json", Authorization: `Bearer ${apiKey}` };
156
+ if (provider === "openrouter") {
157
+ headers["HTTP-Referer"] = "https://huckleberry.ai";
158
+ headers["X-Title"] = "Huckleberry Harness";
159
+ }
160
+ const res = await fetch(`${baseUrl}/chat/completions`, {
161
+ method: "POST",
162
+ headers,
163
+ body: JSON.stringify({
164
+ model,
165
+ messages: opts.messages,
166
+ // Some routes require an explicit cap; default keeps replies bounded.
167
+ max_tokens: opts.maxTokens || 4096,
168
+ ...(opts.temperature !== undefined ? { temperature: opts.temperature } : {}),
169
+ stream: false,
170
+ }),
171
+ signal: AbortSignal.timeout(opts.timeoutMs || 120000),
172
+ });
173
+ if (!res.ok) {
174
+ const body = await res.text().catch(() => "");
175
+ const err = new Error(`${provider} API ${res.status}: ${body.slice(0, 400)}`);
176
+ err.status = res.status;
177
+ throw err;
178
+ }
179
+ const json = await res.json();
180
+ const msg = json.choices?.[0]?.message || {};
181
+ // Some reasoning models put the answer in `content`, others only in `reasoning`.
182
+ const content = msg.content || msg.reasoning || "";
183
+ return {
184
+ content,
185
+ usage: json.usage || {},
186
+ model: json.model || model,
187
+ raw: json,
188
+ };
189
+ }
190
+
191
+ /**
192
+ * Wire-format smoke test: cheap GET /models probe against the active provider.
193
+ * @param {string} [apiKey]
194
+ * @param {string} [provider]
195
+ * @returns {Promise<{ok:boolean, models?:string[], error?:string, provider?:string}>}
196
+ */
197
+ export async function probe(apiKey, provider = resolveProvider()) {
198
+ const key = apiKey || providerKey(provider);
199
+ const baseUrl = providerBaseUrl(provider);
200
+ try {
201
+ const res = await fetch(`${baseUrl}/models`, {
202
+ headers: { Authorization: `Bearer ${key}` },
203
+ signal: AbortSignal.timeout(15000),
204
+ });
205
+ if (!res.ok) {
206
+ const body = await res.text().catch(() => "");
207
+ return { ok: false, error: `HTTP ${res.status}${body ? `: ${body.slice(0, 120)}` : ""}`, provider };
208
+ }
209
+ const json = await res.json();
210
+ return { ok: true, models: (json.data || []).map(m => m.id), provider };
211
+ } catch (e) {
212
+ return { ok: false, error: e.message, provider };
213
+ }
214
+ }
215
+
216
+ /**
217
+ * Save a captured API exchange as a fixture (for wire-format tests without API calls).
218
+ * @param {string} dir output dir
219
+ * @param {string} name fixture name
220
+ * @param {Object} obj the response JSON (never includes the key)
221
+ */
222
+ export function saveFixture(dir, name, obj) {
223
+ mkdirSync(dir, { recursive: true });
224
+ writeFileSync(join(dir, `${name}.json`), JSON.stringify(obj, null, 2));
225
+ }
@@ -0,0 +1,174 @@
1
+ /**
2
+ * opencode-adapter — DEFAULT harness. Wraps the existing `opencode run` behavior.
3
+ *
4
+ * CRITICAL: this adapter must be a NO-OP for existing installs. It invokes the
5
+ * same `opencode run "<prompt>"` command the CLI already used for `cro`/`review`,
6
+ * with the same default (no explicit model/agent unless the task sets one). No new
7
+ * env vars are required; if opencode is absent the adapter reports not-ready and
8
+ * the CLI falls back exactly as before.
9
+ */
10
+ import { spawn, execFile } from "node:child_process";
11
+ import { promisify } from "node:util";
12
+ import { tmpdir, homedir } from "node:os";
13
+ import { mkdirSync, existsSync } from "node:fs";
14
+ import { join } from "node:path";
15
+ import { HarnessAdapter, baseResult, nowIso } from "./types.js";
16
+
17
+ const execFileAsync = promisify(execFile);
18
+
19
+ /** Neutral working directory so opencode does not load a host repo's context. */
20
+ const NEUTRAL_CWD = join(tmpdir(), "huckleberry-harness");
21
+ function neutralCwd() {
22
+ try { mkdirSync(NEUTRAL_CWD, { recursive: true }); } catch { /* exists */ }
23
+ return NEUTRAL_CWD;
24
+ }
25
+
26
+ /**
27
+ * Resolve the opencode binary against PATH plus common install dirs, so the
28
+ * adapter works from processes (cron, sandbox runners) that lack the shell PATH.
29
+ */
30
+ function opencodeBin() {
31
+ const extra = [
32
+ join(homedir(), ".opencode", "bin"),
33
+ "/usr/local/bin",
34
+ "/opt/homebrew/bin",
35
+ join(homedir(), ".bun", "bin"),
36
+ ];
37
+ for (const d of extra) {
38
+ const p = join(d, "opencode");
39
+ if (existsSync(p)) return p;
40
+ }
41
+ return "opencode"; // fall back to PATH lookup
42
+ }
43
+
44
+ const DEFAULT_TIMEOUT_MS = 900000; // 15 min — opencode cold boot + agent work
45
+
46
+ function runOpenCode(args, cwd, timeoutMs) {
47
+ return new Promise((resolve, reject) => {
48
+ const child = spawn(opencodeBin(), args, {
49
+ cwd,
50
+ env: { ...process.env, PATH: process.env.PATH + ":" + join(homedir(), ".opencode", "bin") },
51
+ stdio: ["ignore", "pipe", "pipe"],
52
+ });
53
+ let stdout = "", stderr = "";
54
+ child.stdout.on("data", d => { stdout += d; });
55
+ child.stderr.on("data", d => { stderr += d; });
56
+ const timer = setTimeout(() => {
57
+ child.kill("SIGKILL");
58
+ reject(Object.assign(new Error("timeout"), { stdout, stderr, code: "ETIMEDOUT" }));
59
+ }, timeoutMs);
60
+ child.on("close", (code, signal) => {
61
+ clearTimeout(timer);
62
+ if (code === 0) resolve({ stdout, stderr });
63
+ else reject(Object.assign(new Error(`exit ${code}${signal ? ` (${signal})` : ""}`), { stdout, stderr, code, signal }));
64
+ });
65
+ child.on("error", (e) => {
66
+ clearTimeout(timer);
67
+ reject(e);
68
+ });
69
+ });
70
+ }
71
+
72
+ export class OpenCodeAdapter extends HarnessAdapter {
73
+ constructor(opts = {}) {
74
+ super({ id: "opencode", label: "opencode CLI (local, default)", ...opts });
75
+ /** @type {Map<string, {task:Object, output:string, startedAt:string}>} */
76
+ this.checkpoints = new Map();
77
+ }
78
+
79
+ capabilities() {
80
+ return {
81
+ streaming: false, // opencode run prints at the end; we capture stdout
82
+ checkpoint: true, // we snapshot the task for re-run
83
+ cancel: true,
84
+ files: true,
85
+ tools: true, // full agent with tool/filesystem access
86
+ modelChoice: true, // via --model / named agent
87
+ costPerMTokIn: 0, // local engine — no per-token charge (uses the user's provider)
88
+ costPerMTokOut: 0,
89
+ };
90
+ }
91
+
92
+ async status() {
93
+ try {
94
+ const { stdout } = await execFileAsync(opencodeBin(), ["--version"], { timeout: 20000 });
95
+ return { ready: true, detail: `opencode ${stdout.trim()}` };
96
+ } catch (e) {
97
+ return { ready: false, reason: "opencode not on PATH", detail: "npm install -g opencode" };
98
+ }
99
+ }
100
+
101
+ /**
102
+ * @param {import("./types.js").TaskRequest} task
103
+ * @returns {Promise<import("./types.js").TaskResult>}
104
+ */
105
+ async submit(task) {
106
+ const started = Date.now();
107
+ const out = baseResult({ ...task, adapterId: this.id });
108
+ // Run from a NEUTRAL cwd by default: running opencode inside the clawd workspace
109
+ // loads its full AGENTS.md + 200+ skills and can exceed any sane timeout. The
110
+ // harness task carries its own prompt; it doesn't need the caller's repo context.
111
+ const runCwd = task.cwd || neutralCwd();
112
+ const args = ["run"];
113
+ // Harness tasks are execution tasks — use build agent (not plan) to get output.
114
+ if (!task.agent) args.push("--agent", "build");
115
+ if (task.agent) args.push("--agent", task.agent);
116
+ if (task.model) args.push("--model", task.model);
117
+ args.push(task.prompt);
118
+
119
+ try {
120
+ const { stdout, stderr } = await runOpenCode(args, runCwd, task.timeoutMs || DEFAULT_TIMEOUT_MS);
121
+ out.output = stdout.trim();
122
+ out.status = "ok";
123
+ // opencode prints MCP boot noise to stderr; keep it as a diagnostic, not an error
124
+ if (stderr?.trim()) out.stderr = stderr.trim();
125
+ // opencode merges usage into stderr on some versions; parse if present
126
+ const usage = parseOpenCodeUsage(stdout + "\n" + stderr);
127
+ if (usage) out.usage = usage;
128
+ } catch (e) {
129
+ out.status = "error";
130
+ out.error = e.message;
131
+ out.output = (e.stdout || "").trim();
132
+ }
133
+ out.durationMs = Date.now() - started;
134
+ out.startedAt = nowIso();
135
+ // checkpoint snapshot (enables resume = re-run)
136
+ this.checkpoints.set(task.id, { task, output: out.output, startedAt: out.startedAt });
137
+ out.checkpointId = task.id;
138
+ return out;
139
+ }
140
+
141
+ async cancel(_taskId) {
142
+ // spawn() children can't be signalled from here without keeping handles;
143
+ // the runOpenCode timeout already caps run time.
144
+ return false;
145
+ }
146
+
147
+ async checkpoint(taskId) {
148
+ return this.checkpoints.has(taskId) ? taskId : null;
149
+ }
150
+
151
+ async resume(checkpointId) {
152
+ const cp = this.checkpoints.get(checkpointId);
153
+ if (!cp) throw new Error(`opencode: no checkpoint ${checkpointId}`);
154
+ return this.submit(cp.task); // local engine: resume == re-run
155
+ }
156
+
157
+ async downloadFiles(taskId) {
158
+ const cp = this.checkpoints.get(taskId);
159
+ if (!cp) return [];
160
+ // opencode writes files itself; we report the cwd the task ran in as the search root
161
+ return [];
162
+ }
163
+ }
164
+
165
+ /**
166
+ * Best-effort parse of token usage from opencode output. Returns null when absent
167
+ * (older versions print nothing) — callers treat 0 usage as "unavailable".
168
+ * @param {string} text
169
+ */
170
+ function parseOpenCodeUsage(text) {
171
+ const m = text.match(/tokens?:?\s*(\d+)\s*(?:in|input)[^\d]*(\d+)\s*(?:out|output)/i);
172
+ if (m) return { input: Number(m[1]), output: Number(m[2]) };
173
+ return null;
174
+ }
@@ -0,0 +1,172 @@
1
+ /**
2
+ * pi-adapter — routes a task to the Pi coding-agent CLI (earendil-works/pi).
3
+ *
4
+ * WHY: Pi ships a markedly smaller cold-start prompt than opencode (benchmark
5
+ * discussion #6646: Pi ~2.8k first-turn input tokens vs opencode ~12.4k, ~5 tools
6
+ * vs ~12). For many short cold sessions that 4x overhead gap dominates cost. For
7
+ * long cached sessions opencode can be cheaper per turn, so harness selection is
8
+ * workload-dependent — this adapter makes that choice available.
9
+ *
10
+ * Install: npm install -g @earendil-works/pi-coding-agent (binary: `pi`)
11
+ * Model selection: pass task.model as `provider/id` (e.g. deepseek/deepseek-v4.1-flash).
12
+ * Auth: Pi reads provider creds from its own config/`pi auth`; OPENROUTER_API_KEY is
13
+ * honoured via `--api-key` override when provided through task.env.
14
+ */
15
+ import { spawn, execFile } from "node:child_process";
16
+ import { promisify } from "node:util";
17
+ import { tmpdir, homedir } from "node:os";
18
+ import { mkdirSync, existsSync } from "node:fs";
19
+ import { join } from "node:path";
20
+ import { HarnessAdapter, baseResult, nowIso } from "./types.js";
21
+ import { loadHarnessEnv } from "./deepseek.js";
22
+
23
+ const execFileAsync = promisify(execFile);
24
+
25
+ /** Resolve the OpenRouter key: huckleberry .env wins over ambient env. */
26
+ function openRouterKey() {
27
+ const env = { ...process.env, ...loadHarnessEnv() };
28
+ return env.OPENROUTER_API_KEY || "";
29
+ }
30
+
31
+ const NEUTRAL_CWD = join(tmpdir(), "huckleberry-harness-pi");
32
+ function neutralCwd() {
33
+ try { mkdirSync(NEUTRAL_CWD, { recursive: true }); } catch { /* exists */ }
34
+ return NEUTRAL_CWD;
35
+ }
36
+
37
+ function piBin() {
38
+ const extra = [
39
+ join(homedir(), ".npm-global", "bin"),
40
+ join(homedir(), ".local", "bin"),
41
+ "/usr/local/bin",
42
+ "/opt/homebrew/bin",
43
+ join(homedir(), ".bun", "bin"),
44
+ ];
45
+ for (const d of extra) {
46
+ const p = join(d, "pi");
47
+ if (existsSync(p)) return p;
48
+ }
49
+ return "pi";
50
+ }
51
+
52
+ const DEFAULT_TIMEOUT_MS = 900000;
53
+
54
+ /**
55
+ * Model id default. pi requires a provider-qualified id; we default to the
56
+ * OpenRouter route so a single OpenRouter key drives all adapters consistently.
57
+ */
58
+ function piDefaultModel() {
59
+ const env = process.env;
60
+ if (env.PI_MODEL) return env.PI_MODEL;
61
+ if (env.DEEPSEEK_MODEL && env.DEEPSEEK_MODEL.includes("/")) return env.DEEPSEEK_MODEL;
62
+ return "openrouter/deepseek/deepseek-v4.1-flash";
63
+ }
64
+
65
+ function runPi(args, cwd, timeoutMs, env) {
66
+ return new Promise((resolve, reject) => {
67
+ const child = spawn(piBin(), args, {
68
+ cwd,
69
+ env: { ...process.env, ...(env || {}) },
70
+ stdio: ["ignore", "pipe", "pipe"],
71
+ });
72
+ let stdout = "", stderr = "";
73
+ child.stdout.on("data", d => { stdout += d; });
74
+ child.stderr.on("data", d => { stderr += d; });
75
+ const timer = setTimeout(() => {
76
+ child.kill("SIGKILL");
77
+ reject(Object.assign(new Error("timeout"), { stdout, stderr, code: "ETIMEDOUT" }));
78
+ }, timeoutMs);
79
+ child.on("close", (code, signal) => {
80
+ clearTimeout(timer);
81
+ if (code === 0) resolve({ stdout, stderr });
82
+ else reject(Object.assign(new Error(`exit ${code}${signal ? ` (${signal})` : ""}`), { stdout, stderr, code, signal }));
83
+ });
84
+ child.on("error", (e) => { clearTimeout(timer); reject(e); });
85
+ });
86
+ }
87
+
88
+ export class PiAdapter extends HarnessAdapter {
89
+ constructor(opts = {}) {
90
+ super({ id: "pi", label: "Pi coding agent (lean cold-start)", ...opts });
91
+ this.checkpoints = new Map();
92
+ }
93
+
94
+ capabilities() {
95
+ return {
96
+ streaming: false,
97
+ checkpoint: true, // snapshot for re-run
98
+ cancel: true,
99
+ files: true, // Pi is a coding agent with filesystem tools
100
+ tools: true,
101
+ modelChoice: true, // --model provider/id
102
+ costPerMTokIn: 0, // local engine — cost is the routed model's, not Pi's
103
+ costPerMTokOut: 0,
104
+ };
105
+ }
106
+
107
+ async status() {
108
+ try {
109
+ const { stdout } = await execFileAsync(piBin(), ["--version"], { timeout: 20000 });
110
+ return { ready: true, detail: `pi ${stdout.trim()}` };
111
+ } catch (e) {
112
+ return { ready: false, reason: "pi not installed", detail: "npm install -g @earendil-works/pi-coding-agent" };
113
+ }
114
+ }
115
+
116
+ /**
117
+ * @param {import("./types.js").TaskRequest} task
118
+ * @returns {Promise<import("./types.js").TaskResult>}
119
+ */
120
+ async submit(task) {
121
+ const started = Date.now();
122
+ const out = baseResult({ ...task, adapterId: this.id });
123
+ // Print mode: non-interactive, single-shot. --print emits only the answer.
124
+ // Pi resolves models as `provider/id`; our default pins the OpenRouter route.
125
+ const args = ["--print"];
126
+ const model = task.model || piDefaultModel();
127
+ args.push("--model", model);
128
+ const key = task.env?.OPENROUTER_API_KEY || openRouterKey();
129
+ if (key) args.push("--api-key", key);
130
+ args.push(task.prompt);
131
+
132
+ try {
133
+ const { stdout, stderr } = await runPi(args, task.cwd || neutralCwd(), task.timeoutMs || DEFAULT_TIMEOUT_MS, task.env);
134
+ out.output = stdout.trim();
135
+ out.status = "ok";
136
+ if (stderr?.trim()) out.stderr = stderr.trim();
137
+ const usage = parsePiUsage(stderr + "\n" + stdout);
138
+ if (usage) out.usage = usage;
139
+ } catch (e) {
140
+ out.status = "error";
141
+ out.error = e.message;
142
+ out.output = (e.stdout || "").trim();
143
+ }
144
+ out.durationMs = Date.now() - started;
145
+ out.startedAt = nowIso();
146
+ this.checkpoints.set(task.id, { task, output: out.output, startedAt: out.startedAt });
147
+ out.checkpointId = task.id;
148
+ return out;
149
+ }
150
+
151
+ async cancel(_taskId) { return false; }
152
+
153
+ async checkpoint(taskId) { return this.checkpoints.has(taskId) ? taskId : null; }
154
+
155
+ async resume(checkpointId) {
156
+ const cp = this.checkpoints.get(checkpointId);
157
+ if (!cp) throw new Error(`pi: no checkpoint ${checkpointId}`);
158
+ return this.submit(cp.task);
159
+ }
160
+
161
+ async downloadFiles(_taskId) { return []; }
162
+ }
163
+
164
+ /**
165
+ * Best-effort token parse from pi output (varies by version). Null when absent.
166
+ * @param {string} text
167
+ */
168
+ function parsePiUsage(text) {
169
+ const m = text.match(/input[^\d]*(\d+)[^\d]*output[^\d]*(\d+)/i) || text.match(/(\d+)\s*(?:in|input)[^\d]*(\d+)\s*(?:out|output)/i);
170
+ if (m) return { input: Number(m[1]), output: Number(m[2]) };
171
+ return null;
172
+ }