@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.
- package/README.md +85 -0
- package/agents/cos.json +2 -5
- package/agents/hermes/AGENTS.md +25 -49
- package/agents/hermes/fix-kimaki/SKILL.md +19 -92
- package/agents/hermes/hermes-fixer.md +44 -74
- package/agents/hermes.json +6 -18
- package/kanban/SKILL.md +18 -18
- package/kanban/package.json +1 -1
- package/kanban/src/dispatcher.mjs +1 -1
- package/kanban/templates/blog-social-campaign.yaml +6 -2
- package/kanban/templates/social-campaign.yaml +9 -4
- package/mcp/jev-calibration.mjs +335 -0
- package/mcp/jev-client.mjs +119 -0
- package/mcp/jev-thresholds.json +27 -0
- package/package.json +13 -9
- package/scripts/doctor-watchdog.sh +73 -0
- package/scripts/install-services.sh +34 -27
- package/scripts/self-improve-weekly.sh +34 -0
- package/scripts/sync-skills.mjs +121 -0
- package/skills/ab-test-setup/SKILL.md +266 -0
- package/skills/ab-test-setup/evals/evals.json +105 -0
- package/skills/ab-test-setup/references/sample-size-guide.md +263 -0
- package/skills/ab-test-setup/references/test-templates.md +277 -0
- package/skills/agent-reach/SKILL.md +132 -0
- package/skills/agent-reach/references/career.md +29 -0
- package/skills/agent-reach/references/dev.md +62 -0
- package/skills/agent-reach/references/search.md +33 -0
- package/skills/agent-reach/references/social.md +232 -0
- package/skills/agent-reach/references/video.md +130 -0
- package/skills/agent-reach/references/web.md +50 -0
- package/skills/ai-agent-seo/SKILL.md +450 -0
- package/skills/ai-cold-email-intelligence/SKILL.md +54 -0
- package/skills/ai-cold-email-intelligence/references/prompts.md +21 -0
- package/skills/ai-consensus-builder/SKILL.md +324 -0
- package/skills/ai-seo/SKILL.md +399 -0
- package/skills/ai-seo/evals/evals.json +90 -0
- package/skills/ai-seo/references/content-patterns.md +284 -0
- package/skills/ai-seo/references/platform-ranking-factors.md +152 -0
- package/skills/ai-visibility-audit/SKILL.md +322 -0
- package/skills/analytics-tracking/SKILL.md +309 -0
- package/skills/analytics-tracking/evals/evals.json +90 -0
- package/skills/analytics-tracking/references/event-library.md +260 -0
- package/skills/analytics-tracking/references/ga4-implementation.md +300 -0
- package/skills/analytics-tracking/references/gtm-implementation.md +390 -0
- package/skills/article-generator/SKILL.md +216 -0
- package/skills/auto-indexing/SKILL.md +179 -0
- package/skills/auto-indexing/scripts/auto-indexing.js +257 -0
- package/skills/auto-skill/SKILL.md +151 -0
- package/skills/auto-skill/correction-queue.js +102 -0
- package/skills/auto-skill/dedup.js +97 -0
- package/skills/auto-skill/skill-router.js +224 -0
- package/skills/autoresearch/SKILL.md +334 -0
- package/skills/autoresearch/autoresearch-autoresearch/SKILL.md.baseline +329 -0
- package/skills/autoresearch/autoresearch-autoresearch/changelog.md +34 -0
- package/skills/autoresearch/autoresearch-autoresearch/dashboard.html +116 -0
- package/skills/autoresearch/autoresearch-autoresearch/evals.md +39 -0
- package/skills/autoresearch/autoresearch-autoresearch/results.json +44 -0
- package/skills/autoresearch/autoresearch-autoresearch/results.tsv +3 -0
- package/skills/autoresearch/eval-guide.md +121 -0
- package/skills/b2b-cold-outreach/SKILL.md +322 -0
- package/skills/birdclaw/SKILL.md +82 -0
- package/skills/brainstorm/SKILL.md +168 -0
- package/skills/brand-kit-playground/SKILL.md +312 -0
- package/skills/brand-kit-playground/references/html-architecture.md +316 -0
- package/skills/brand-kit-playground/references/steal-patterns.md +88 -0
- package/skills/brand-voice/SKILL.md +223 -0
- package/skills/brand-voice/references/honesty-as-positioning.md +60 -0
- package/skills/brand-voice/references/voice-modes.md +1158 -0
- package/skills/business-advisory-council/README.md +136 -0
- package/skills/business-advisory-council/SKILL.md +94 -0
- package/skills/business-advisory-council/business-advisory-council.py +492 -0
- package/skills/business-advisory-council/discord-components-decision.json +8 -0
- package/skills/business-advisory-council/examples/steve-conley-partnership.json +6 -0
- package/skills/business-advisory-council/steve-conley-call-brief.json +6 -0
- package/skills/churn-prevention/SKILL.md +305 -0
- package/skills/churn-prevention/evals/evals.json +93 -0
- package/skills/churn-prevention/references/cancel-flow-patterns.md +316 -0
- package/skills/churn-prevention/references/dunning-playbook.md +408 -0
- package/skills/claw-compactor/LICENSE +21 -0
- package/skills/claw-compactor/README.md +459 -0
- package/skills/claw-compactor/SKILL.md +329 -0
- package/skills/claw-compactor/benchmark/RESULTS.md +104 -0
- package/skills/claw-compactor/benchmark/__init__.py +1 -0
- package/skills/claw-compactor/benchmark/compressors.py +520 -0
- package/skills/claw-compactor/benchmark/data/sample_01_devops.json +82 -0
- package/skills/claw-compactor/benchmark/data/sample_02_trading.json +54 -0
- package/skills/claw-compactor/benchmark/data/sample_03_ml_short.json +38 -0
- package/skills/claw-compactor/benchmark/data/sample_04_mixed_long.json +318 -0
- package/skills/claw-compactor/benchmark/data/sample_05_sysadmin.json +56 -0
- package/skills/claw-compactor/benchmark/evaluate.py +278 -0
- package/skills/claw-compactor/benchmark/report.py +241 -0
- package/skills/claw-compactor/benchmark/results/benchmark_results.json +405 -0
- package/skills/claw-compactor/benchmark/run_benchmark.py +238 -0
- package/skills/claw-compactor/engram.yaml +49 -0
- package/skills/claw-compactor/proxy/README.md +87 -0
- package/skills/claw-compactor/proxy/dashboard.html +804 -0
- package/skills/claw-compactor/proxy/event-log.mjs +213 -0
- package/skills/claw-compactor/proxy/fair-queue.mjs +288 -0
- package/skills/claw-compactor/proxy/metrics-store.mjs +425 -0
- package/skills/claw-compactor/proxy/package-lock.json +125 -0
- package/skills/claw-compactor/proxy/package.json +15 -0
- package/skills/claw-compactor/proxy/portal.html +360 -0
- package/skills/claw-compactor/proxy/process-registry.mjs +447 -0
- package/skills/claw-compactor/proxy/rate-limiter.mjs +117 -0
- package/skills/claw-compactor/proxy/redis-client.mjs +75 -0
- package/skills/claw-compactor/proxy/retry.mjs +182 -0
- package/skills/claw-compactor/proxy/server.mjs +2100 -0
- package/skills/claw-compactor/proxy/session-affinity.mjs +177 -0
- package/skills/claw-compactor/proxy/start.sh +23 -0
- package/skills/claw-compactor/proxy/test/event-log.test.mjs +237 -0
- package/skills/claw-compactor/proxy/test/helpers.mjs +103 -0
- package/skills/claw-compactor/proxy/test/integration.test.mjs +297 -0
- package/skills/claw-compactor/proxy/test/metrics-store.test.mjs +243 -0
- package/skills/claw-compactor/proxy/test/process-registry.test.mjs +390 -0
- package/skills/claw-compactor/proxy/test/rate-limiter.test.mjs +121 -0
- package/skills/claw-compactor/proxy/test/redis-client.test.mjs +62 -0
- package/skills/claw-compactor/proxy/test/token-tracker.test.mjs +200 -0
- package/skills/claw-compactor/proxy/token-tracker.mjs +482 -0
- package/skills/claw-compactor/pyproject.toml +26 -0
- package/skills/claw-compactor/references/README.md +44 -0
- package/skills/claw-compactor/references/architecture.md +197 -0
- package/skills/claw-compactor/references/benchmarks.md +94 -0
- package/skills/claw-compactor/references/compression-prompts.md +39 -0
- package/skills/claw-compactor/references/compression-techniques.md +219 -0
- package/skills/claw-compactor/references/testing.md +160 -0
- package/skills/claw-compactor/scripts/audit_memory.py +216 -0
- package/skills/claw-compactor/scripts/compress_memory.py +236 -0
- package/skills/claw-compactor/scripts/compressed_context.py +280 -0
- package/skills/claw-compactor/scripts/dedup_memory.py +147 -0
- package/skills/claw-compactor/scripts/dictionary_compress.py +170 -0
- package/skills/claw-compactor/scripts/engram-auto.sh +152 -0
- package/skills/claw-compactor/scripts/engram_auto.py +695 -0
- package/skills/claw-compactor/scripts/engram_cli.py +474 -0
- package/skills/claw-compactor/scripts/estimate_tokens.py +131 -0
- package/skills/claw-compactor/scripts/generate_summary_tiers.py +292 -0
- package/skills/claw-compactor/scripts/lib/__init__.py +34 -0
- package/skills/claw-compactor/scripts/lib/config.py +289 -0
- package/skills/claw-compactor/scripts/lib/dedup.py +119 -0
- package/skills/claw-compactor/scripts/lib/dictionary.py +281 -0
- package/skills/claw-compactor/scripts/lib/engram.py +793 -0
- package/skills/claw-compactor/scripts/lib/engram_prompts.py +175 -0
- package/skills/claw-compactor/scripts/lib/engram_storage.py +254 -0
- package/skills/claw-compactor/scripts/lib/exceptions.py +24 -0
- package/skills/claw-compactor/scripts/lib/markdown.py +312 -0
- package/skills/claw-compactor/scripts/lib/rle.py +165 -0
- package/skills/claw-compactor/scripts/lib/tokenizer_optimizer.py +188 -0
- package/skills/claw-compactor/scripts/lib/tokens.py +68 -0
- package/skills/claw-compactor/scripts/mem_compress.py +788 -0
- package/skills/claw-compactor/scripts/observation_compressor.py +346 -0
- package/skills/claw-compactor/tests/__init__.py +0 -0
- package/skills/claw-compactor/tests/conftest.py +94 -0
- package/skills/claw-compactor/tests/test_audit_comprehensive.py +123 -0
- package/skills/claw-compactor/tests/test_audit_memory.py +67 -0
- package/skills/claw-compactor/tests/test_benchmark.py +122 -0
- package/skills/claw-compactor/tests/test_cli_commands.py +228 -0
- package/skills/claw-compactor/tests/test_compress_memory.py +109 -0
- package/skills/claw-compactor/tests/test_compress_memory_comprehensive.py +191 -0
- package/skills/claw-compactor/tests/test_compressed_context.py +145 -0
- package/skills/claw-compactor/tests/test_config.py +54 -0
- package/skills/claw-compactor/tests/test_dedup_memory.py +124 -0
- package/skills/claw-compactor/tests/test_dictionary.py +327 -0
- package/skills/claw-compactor/tests/test_dictionary_comprehensive.py +241 -0
- package/skills/claw-compactor/tests/test_engram.py +1091 -0
- package/skills/claw-compactor/tests/test_engram_auto.py +529 -0
- package/skills/claw-compactor/tests/test_error_handling.py +194 -0
- package/skills/claw-compactor/tests/test_estimate_tokens.py +99 -0
- package/skills/claw-compactor/tests/test_generate_summary_tiers.py +105 -0
- package/skills/claw-compactor/tests/test_integration.py +249 -0
- package/skills/claw-compactor/tests/test_lib_dedup.py +135 -0
- package/skills/claw-compactor/tests/test_lib_markdown.py +388 -0
- package/skills/claw-compactor/tests/test_lib_tokens.py +82 -0
- package/skills/claw-compactor/tests/test_main_entry.py +176 -0
- package/skills/claw-compactor/tests/test_markdown_advanced.py +284 -0
- package/skills/claw-compactor/tests/test_new_features.py +77 -0
- package/skills/claw-compactor/tests/test_observation_comprehensive.py +261 -0
- package/skills/claw-compactor/tests/test_observation_compressor.py +128 -0
- package/skills/claw-compactor/tests/test_performance.py +172 -0
- package/skills/claw-compactor/tests/test_pipeline.py +109 -0
- package/skills/claw-compactor/tests/test_real_workspace.py +161 -0
- package/skills/claw-compactor/tests/test_rle.py +114 -0
- package/skills/claw-compactor/tests/test_rle_comprehensive.py +151 -0
- package/skills/claw-compactor/tests/test_roundtrip.py +253 -0
- package/skills/claw-compactor/tests/test_roundtrip_comprehensive.py +192 -0
- package/skills/claw-compactor/tests/test_tiers_comprehensive.py +171 -0
- package/skills/claw-compactor/tests/test_token_economics.py +237 -0
- package/skills/claw-compactor/tests/test_tokenizer_optimizer.py +175 -0
- package/skills/claw-compactor/tests/test_tokenizer_optimizer_comprehensive.py +241 -0
- package/skills/claw-compactor/tests/test_tokens.py +27 -0
- package/skills/cmo/CHANGELOG.md +61 -0
- package/skills/cmo/SKILL.md +500 -0
- package/skills/cmo/references/ai-slop-patterns.md +56 -0
- package/skills/cmo/references/analytics-guide.md +152 -0
- package/skills/cmo/references/ideas-library.md +197 -0
- package/skills/cmo/rules/brand-file-map.md +198 -0
- package/skills/cmo/rules/brand-memory.md +158 -0
- package/skills/cmo/rules/cli-runtime-index.md +95 -0
- package/skills/cmo/rules/command-reference.md +167 -0
- package/skills/cmo/rules/communication.md +15 -0
- package/skills/cmo/rules/context-switch.md +101 -0
- package/skills/cmo/rules/ecosystem.md +125 -0
- package/skills/cmo/rules/error-recovery.md +98 -0
- package/skills/cmo/rules/learning-loop.md +170 -0
- package/skills/cmo/rules/monorepo.md +78 -0
- package/skills/cmo/rules/output-format.md +124 -0
- package/skills/cmo/rules/persona.md +15 -0
- package/skills/cmo/rules/playbooks.md +327 -0
- package/skills/cmo/rules/progressive-enhancement.md +231 -0
- package/skills/cmo/rules/publish-index.md +106 -0
- package/skills/cmo/rules/quality-gate.md +90 -0
- package/skills/cmo/rules/recency-grounding.md +124 -0
- package/skills/cmo/rules/safety.md +80 -0
- package/skills/cmo/rules/studio-api-index.md +138 -0
- package/skills/cmo/rules/studio-integration.md +147 -0
- package/skills/cmo/rules/sub-agents.md +167 -0
- package/skills/cold-email/SKILL.md +240 -0
- package/skills/cold-email/evals/evals.json +94 -0
- package/skills/cold-email/references/benchmarks.md +83 -0
- package/skills/cold-email/references/follow-up-sequences.md +81 -0
- package/skills/cold-email/references/frameworks.md +90 -0
- package/skills/cold-email/references/personalization.md +79 -0
- package/skills/cold-email/references/subject-lines.md +53 -0
- package/skills/competitive-intel/SKILL.md +433 -0
- package/skills/competitive-intel/references/competitive-frameworks.md +145 -0
- package/skills/competitor-alternatives/SKILL.md +362 -0
- package/skills/competitor-alternatives/evals/evals.json +93 -0
- package/skills/competitor-alternatives/references/content-architecture.md +271 -0
- package/skills/competitor-alternatives/references/templates.md +223 -0
- package/skills/concreteness-fixer/SKILL.md +483 -0
- package/skills/concreteness-fixer/scripts/validation/concreteness-validator.js +221 -0
- package/skills/concreteness-fixer/utils/execFileNoThrow.js +16 -0
- package/skills/content-atomizer/SKILL.md +424 -0
- package/skills/content-atomizer/references/hook-strategies.md +56 -0
- package/skills/content-atomizer/references/platform-specs.md +118 -0
- package/skills/content-atomizer/references/platforms/bluesky.md +64 -0
- package/skills/content-atomizer/references/platforms/instagram.md +77 -0
- package/skills/content-atomizer/references/platforms/linkedin.md +120 -0
- package/skills/content-atomizer/references/platforms/reddit.md +73 -0
- package/skills/content-atomizer/references/platforms/threads.md +64 -0
- package/skills/content-atomizer/references/platforms/tiktok.md +55 -0
- package/skills/content-atomizer/references/platforms/twitter.md +123 -0
- package/skills/content-atomizer/references/platforms/youtube.md +56 -0
- package/skills/content-atomizer/references/tweet-patterns.md +40 -0
- package/skills/content-repost-manager/SKILL.md +245 -0
- package/skills/content-repost-manager/scripts/content-repost-scan.py +133 -0
- package/skills/context-recovery/.clawdhub/origin.json +7 -0
- package/skills/context-recovery/SKILL.md +198 -0
- package/skills/context-recovery/_meta.json +6 -0
- package/skills/conversion-flow-cro/SKILL.md +248 -0
- package/skills/conversion-flow-cro/references/flow-benchmarks.md +158 -0
- package/skills/copy-editing/SKILL.md +474 -0
- package/skills/copy-editing/evals/evals.json +89 -0
- package/skills/copy-editing/references/plain-english-alternatives.md +394 -0
- package/skills/copywriting/SKILL.md +349 -0
- package/skills/copywriting/evals/evals.json +111 -0
- package/skills/copywriting/references/awareness-level-guide.md +227 -0
- package/skills/copywriting/references/copy-frameworks.md +389 -0
- package/skills/copywriting/references/natural-transitions.md +272 -0
- package/skills/creative/SKILL.md +365 -0
- package/skills/creative/modes/ad-creative.md +1748 -0
- package/skills/creative/modes/product-photo.md +1520 -0
- package/skills/creative/modes/product-video.md +1657 -0
- package/skills/creative/modes/social-graphics.md +1511 -0
- package/skills/creative/modes/talking-head.md +2208 -0
- package/skills/creative/references/VISUAL_INTELLIGENCE.md +1233 -0
- package/skills/deep-serp-article/SKILL.md +677 -0
- package/skills/deep-serp-article/SKILL.md.bak +530 -0
- package/skills/earned-media/SKILL.md +260 -0
- package/skills/email-sequences/SKILL.md +446 -0
- package/skills/email-sequences/references/sequence-templates.md +1217 -0
- package/skills/firecrawl/.skill-meta.json +13 -0
- package/skills/firecrawl/SKILL.md +154 -0
- package/skills/firecrawl/rules/install.md +63 -0
- package/skills/firecrawl/rules/security.md +26 -0
- package/skills/form-cro/SKILL.md +429 -0
- package/skills/form-cro/evals/evals.json +90 -0
- package/skills/free-tool-strategy/SKILL.md +325 -0
- package/skills/free-tool-strategy/evals/evals.json +90 -0
- package/skills/free-tool-strategy/references/tool-types.md +253 -0
- package/skills/frontend-slides/SKILL.md +248 -0
- package/skills/frontend-slides/STYLE_PRESETS.md +347 -0
- package/skills/frontend-slides/animation-patterns.md +110 -0
- package/skills/frontend-slides/html-template.md +347 -0
- package/skills/frontend-slides/scripts/extract-pptx.py +96 -0
- package/skills/frontend-slides/viewport-base.css +153 -0
- package/skills/guardrail-framework/SKILL.md +319 -0
- package/skills/hook-generator/SKILL.md +438 -0
- package/skills/hook-generator/database/2026-PLATFORM-RESEARCH.md +211 -0
- package/skills/hook-generator/database/instagram-hooks.json +591 -0
- package/skills/hook-generator/database/linkedin-hooks.json +502 -0
- package/skills/hook-generator/database/medium-hooks.json +181 -0
- package/skills/hook-generator/database/tiktok-hooks.json +337 -0
- package/skills/hook-generator/database/twitter-hooks.json +567 -0
- package/skills/hook-generator/database/youtube-hooks.json +275 -0
- package/skills/hook-generator/package-lock.json +24 -0
- package/skills/hook-generator/package.json +5 -0
- package/skills/hook-generator/references/hook-generation-system.md +257 -0
- package/skills/hook-generator/references/hook-performance-analysis.json +153 -0
- package/skills/hook-generator/references/hooks-library.md +128 -0
- package/skills/hook-generator/references/platform-hook-frameworks.md +275 -0
- package/skills/hook-generator/scripts/generate-hooks-unified.js +722 -0
- package/skills/hook-generator/scripts/generate-hooks.js +225 -0
- package/skills/hook-generator/scripts/generate.sh +36 -0
- package/skills/hook-generator/scripts/ralph-hook-enhancer.js +864 -0
- package/skills/hook-generator/scripts/test-gemini-output.js +51 -0
- package/skills/humanizer/README.md +120 -0
- package/skills/humanizer/SKILL.md +699 -0
- package/skills/image-gen/SKILL.md +277 -0
- package/skills/image-gen/references/prompt-patterns.md +114 -0
- package/skills/image-gen/references/visual-metaphors.md +51 -0
- package/skills/impeccable/SKILL.md +86 -0
- package/skills/impeccable/reference/adapt.md +312 -0
- package/skills/impeccable/reference/adapt.native.md +58 -0
- package/skills/impeccable/reference/android.md +40 -0
- package/skills/impeccable/reference/animate.md +86 -0
- package/skills/impeccable/reference/audit.md +136 -0
- package/skills/impeccable/reference/audit.native.md +139 -0
- package/skills/impeccable/reference/bolder.md +31 -0
- package/skills/impeccable/reference/clarify.md +94 -0
- package/skills/impeccable/reference/colorize.md +86 -0
- package/skills/impeccable/reference/craft-floor.md +42 -0
- package/skills/impeccable/reference/craft.md +5 -0
- package/skills/impeccable/reference/critique.md +788 -0
- package/skills/impeccable/reference/degraded/asset-producer.md +90 -0
- package/skills/impeccable/reference/degraded/documenter.md +24 -0
- package/skills/impeccable/reference/degraded/finish-reviewer.md +37 -0
- package/skills/impeccable/reference/degraded/manual-edit-applier.md +92 -0
- package/skills/impeccable/reference/delight.md +70 -0
- package/skills/impeccable/reference/distill.md +111 -0
- package/skills/impeccable/reference/doctor.md +53 -0
- package/skills/impeccable/reference/document.md +416 -0
- package/skills/impeccable/reference/extract.md +69 -0
- package/skills/impeccable/reference/harden.md +336 -0
- package/skills/impeccable/reference/hooks.md +105 -0
- package/skills/impeccable/reference/init.md +125 -0
- package/skills/impeccable/reference/ios.md +45 -0
- package/skills/impeccable/reference/layout.md +84 -0
- package/skills/impeccable/reference/live-setup.md +102 -0
- package/skills/impeccable/reference/live.md +323 -0
- package/skills/impeccable/reference/new-work.md +110 -0
- package/skills/impeccable/reference/onboard.md +234 -0
- package/skills/impeccable/reference/operate.md +61 -0
- package/skills/impeccable/reference/optimize.md +258 -0
- package/skills/impeccable/reference/overdrive.md +127 -0
- package/skills/impeccable/reference/polish.md +97 -0
- package/skills/impeccable/reference/quieter.md +99 -0
- package/skills/impeccable/reference/routing.md +18 -0
- package/skills/impeccable/reference/shape.md +59 -0
- package/skills/impeccable/reference/typeset.md +80 -0
- package/skills/impeccable/reference/visualize.md +49 -0
- package/skills/impeccable/scripts/command-metadata.json +94 -0
- package/skills/impeccable/scripts/concept-seed.mjs +558 -0
- package/skills/impeccable/scripts/context-signals.mjs +334 -0
- package/skills/impeccable/scripts/context.mjs +1467 -0
- package/skills/impeccable/scripts/critique-storage.mjs +213 -0
- package/skills/impeccable/scripts/detect-csp.mjs +198 -0
- package/skills/impeccable/scripts/detect.mjs +21 -0
- package/skills/impeccable/scripts/detector/browser/injected/index.mjs +2023 -0
- package/skills/impeccable/scripts/detector/cli/main.mjs +438 -0
- package/skills/impeccable/scripts/detector/design-system.mjs +1046 -0
- package/skills/impeccable/scripts/detector/detect-antipatterns-browser.js +8283 -0
- package/skills/impeccable/scripts/detector/detect-antipatterns.mjs +50 -0
- package/skills/impeccable/scripts/detector/engines/browser/detect-url.mjs +372 -0
- package/skills/impeccable/scripts/detector/engines/regex/detect-text.mjs +1168 -0
- package/skills/impeccable/scripts/detector/engines/static-html/css-cascade.mjs +1186 -0
- package/skills/impeccable/scripts/detector/engines/static-html/detect-html.mjs +264 -0
- package/skills/impeccable/scripts/detector/engines/visual/screenshot-contrast.mjs +189 -0
- package/skills/impeccable/scripts/detector/findings.mjs +18 -0
- package/skills/impeccable/scripts/detector/node/file-system.mjs +203 -0
- package/skills/impeccable/scripts/detector/profile/profiler.mjs +166 -0
- package/skills/impeccable/scripts/detector/registry/antipatterns.mjs +617 -0
- package/skills/impeccable/scripts/detector/rules/checks.mjs +5580 -0
- package/skills/impeccable/scripts/detector/shared/color.mjs +124 -0
- package/skills/impeccable/scripts/detector/shared/constants.mjs +112 -0
- package/skills/impeccable/scripts/detector/shared/fonts.mjs +30 -0
- package/skills/impeccable/scripts/detector/shared/inline-ignores.mjs +148 -0
- package/skills/impeccable/scripts/detector/shared/page.mjs +7 -0
- package/skills/impeccable/scripts/doctor.mjs +336 -0
- package/skills/impeccable/scripts/embed-prompt.mjs +133 -0
- package/skills/impeccable/scripts/generate-image.mjs +240 -0
- package/skills/impeccable/scripts/hook-admin.mjs +801 -0
- package/skills/impeccable/scripts/hook-before-edit.mjs +508 -0
- package/skills/impeccable/scripts/hook-lib.mjs +2153 -0
- package/skills/impeccable/scripts/hook.mjs +78 -0
- package/skills/impeccable/scripts/lib/artifact-schema.mjs +93 -0
- package/skills/impeccable/scripts/lib/composition-catalog.mjs +200 -0
- package/skills/impeccable/scripts/lib/concept-catalog.mjs +384 -0
- package/skills/impeccable/scripts/lib/design-parser.mjs +925 -0
- package/skills/impeccable/scripts/lib/impeccable-config.mjs +658 -0
- package/skills/impeccable/scripts/lib/impeccable-paths.mjs +137 -0
- package/skills/impeccable/scripts/lib/is-generated.mjs +69 -0
- package/skills/impeccable/scripts/lib/provider.mjs +5 -0
- package/skills/impeccable/scripts/lib/roll-selection.mjs +362 -0
- package/skills/impeccable/scripts/lib/staleness-deep.mjs +478 -0
- package/skills/impeccable/scripts/lib/staleness-notice.mjs +169 -0
- package/skills/impeccable/scripts/lib/staleness.mjs +457 -0
- package/skills/impeccable/scripts/lib/surface-briefs.mjs +151 -0
- package/skills/impeccable/scripts/lib/target-args.mjs +42 -0
- package/skills/impeccable/scripts/lib/target-slug.mjs +33 -0
- package/skills/impeccable/scripts/lib/template-extensions.mjs +146 -0
- package/skills/impeccable/scripts/live/accept-css.mjs +617 -0
- package/skills/impeccable/scripts/live/accept-verify.mjs +60 -0
- package/skills/impeccable/scripts/live/browser-script-parts.mjs +55 -0
- package/skills/impeccable/scripts/live/completion.mjs +28 -0
- package/skills/impeccable/scripts/live/event-validation.mjs +199 -0
- package/skills/impeccable/scripts/live/frameworks/astro.mjs +47 -0
- package/skills/impeccable/scripts/live/frameworks/detect-utils.mjs +73 -0
- package/skills/impeccable/scripts/live/frameworks/index.mjs +143 -0
- package/skills/impeccable/scripts/live/frameworks/journal.mjs +197 -0
- package/skills/impeccable/scripts/live/frameworks/nextjs.mjs +49 -0
- package/skills/impeccable/scripts/live/frameworks/nuxt.mjs +161 -0
- package/skills/impeccable/scripts/live/frameworks/script-src.mjs +17 -0
- package/skills/impeccable/scripts/live/frameworks/static-html.mjs +26 -0
- package/skills/impeccable/scripts/live/frameworks/sveltekit.mjs +71 -0
- package/skills/impeccable/scripts/live/frameworks/tag-strategy.mjs +247 -0
- package/skills/impeccable/scripts/live/frameworks/tanstack-start.mjs +70 -0
- package/skills/impeccable/scripts/live/frameworks/vite-generic.mjs +42 -0
- package/skills/impeccable/scripts/live/generation-preflight.mjs +149 -0
- package/skills/impeccable/scripts/live/insert-ui.mjs +458 -0
- package/skills/impeccable/scripts/live/instructions.mjs +142 -0
- package/skills/impeccable/scripts/live/manual-apply.mjs +939 -0
- package/skills/impeccable/scripts/live/manual-edit-routes.mjs +357 -0
- package/skills/impeccable/scripts/live/manual-edits-buffer.mjs +152 -0
- package/skills/impeccable/scripts/live/poll-lanes.mjs +14 -0
- package/skills/impeccable/scripts/live/roots.mjs +508 -0
- package/skills/impeccable/scripts/live/session-store.mjs +563 -0
- package/skills/impeccable/scripts/live/source-lock.mjs +105 -0
- package/skills/impeccable/scripts/live/source-search.mjs +105 -0
- package/skills/impeccable/scripts/live/svelte-ast.mjs +961 -0
- package/skills/impeccable/scripts/live/svelte-component.mjs +1342 -0
- package/skills/impeccable/scripts/live/sveltekit-adapter.mjs +316 -0
- package/skills/impeccable/scripts/live/tanstack-adapter.mjs +280 -0
- package/skills/impeccable/scripts/live/ui-core.mjs +180 -0
- package/skills/impeccable/scripts/live/vocabulary.mjs +171 -0
- package/skills/impeccable/scripts/live-accept.mjs +954 -0
- package/skills/impeccable/scripts/live-browser-dom.js +146 -0
- package/skills/impeccable/scripts/live-browser-session.js +123 -0
- package/skills/impeccable/scripts/live-browser.js +12520 -0
- package/skills/impeccable/scripts/live-commit-manual-edits.mjs +1244 -0
- package/skills/impeccable/scripts/live-complete.mjs +107 -0
- package/skills/impeccable/scripts/live-copy-edit-agent.mjs +683 -0
- package/skills/impeccable/scripts/live-discard-manual-edits.mjs +51 -0
- package/skills/impeccable/scripts/live-inject.mjs +503 -0
- package/skills/impeccable/scripts/live-insert.mjs +292 -0
- package/skills/impeccable/scripts/live-manual-edit-evidence.mjs +368 -0
- package/skills/impeccable/scripts/live-poll.mjs +429 -0
- package/skills/impeccable/scripts/live-resume.mjs +123 -0
- package/skills/impeccable/scripts/live-server.mjs +1669 -0
- package/skills/impeccable/scripts/live-status.mjs +71 -0
- package/skills/impeccable/scripts/live-target.mjs +30 -0
- package/skills/impeccable/scripts/live-wrap.mjs +927 -0
- package/skills/impeccable/scripts/live.mjs +359 -0
- package/skills/impeccable/scripts/modern-screenshot.umd.js +14 -0
- package/skills/impeccable/scripts/palette.mjs +628 -0
- package/skills/impeccable/scripts/pin.mjs +221 -0
- package/skills/impeccable/scripts/serve-question.mjs +932 -0
- package/skills/impeccable/scripts/surface-brief.mjs +74 -0
- package/skills/inkstone-admin/SKILL.md +66 -0
- package/skills/jev-hook-gate/SKILL.md +111 -0
- package/skills/keyword-research/SKILL.md +503 -0
- package/skills/keyword-research/references/dr-cap-and-confidence.md +62 -0
- package/skills/keyword-research/references/keyword-examples.md +769 -0
- package/skills/landing-page-architect/SKILL.md +585 -0
- package/skills/landing-page-architect/references/architecture-reference.md +32 -0
- package/skills/launch-strategy/SKILL.md +384 -0
- package/skills/launch-strategy/evals/evals.json +91 -0
- package/skills/launch-strategy/references/launch-checklist.md +209 -0
- package/skills/launch-strategy/references/launch-timeline.md +159 -0
- package/skills/lead-email-craft/SKILL.md +522 -0
- package/skills/lead-magnets/SKILL.md +310 -0
- package/skills/lead-magnets/references/benchmarks.md +129 -0
- package/skills/lead-magnets/references/format-guide.md +196 -0
- package/skills/link-building-seo/SKILL.md +210 -0
- package/skills/lint-report.txt +1 -0
- package/skills/manifest.json +129 -0
- package/skills/marketing-demo/SKILL.md +249 -0
- package/skills/marketing-demo/references/remotion-examples.md +281 -0
- package/skills/marketing-ideas/SKILL.md +167 -0
- package/skills/marketing-ideas/evals/evals.json +90 -0
- package/skills/marketing-ideas/references/ideas-by-category.md +366 -0
- package/skills/marketing-psychology/SKILL.md +374 -0
- package/skills/marketing-psychology/evals/evals.json +88 -0
- package/skills/marketing-psychology/references/case-studies.md +148 -0
- package/skills/narrative-research-article/SKILL.md +469 -0
- package/skills/narrative-research-article/references/lanusse-patterns.md +166 -0
- package/skills/notebooklm/SKILL.md +674 -0
- package/skills/off-page-seo/SKILL.md +219 -0
- package/skills/onboarding-cro/SKILL.md +220 -0
- package/skills/onboarding-cro/evals/evals.json +92 -0
- package/skills/onboarding-cro/references/experiments.md +258 -0
- package/skills/original-research/SKILL.md +388 -0
- package/skills/page-cro/SKILL.md +269 -0
- package/skills/page-cro/references/cro-benchmarks.md +140 -0
- package/skills/paper-marketing/SKILL.md +448 -0
- package/skills/paper-marketing/references/agent-quality-rubric.md +68 -0
- package/skills/paper-marketing/references/brand-system-template.md +120 -0
- package/skills/paper-marketing/references/paper-mcp-rules.md +71 -0
- package/skills/paper-marketing/references/platform-conventions.md +43 -0
- package/skills/paywall-upgrade-cro/SKILL.md +227 -0
- package/skills/paywall-upgrade-cro/evals/evals.json +93 -0
- package/skills/paywall-upgrade-cro/references/experiments.md +164 -0
- package/skills/platform-formatting/SKILL.md +51 -0
- package/skills/popup-cro/SKILL.md +454 -0
- package/skills/popup-cro/evals/evals.json +94 -0
- package/skills/positioning-angles/SKILL.md +524 -0
- package/skills/positioning-angles/references/ad-matrix-and-examples.md +176 -0
- package/skills/positioning-angles/references/angle-frameworks.md +187 -0
- package/skills/positioning-angles/references/dunford-positioning.md +135 -0
- package/skills/positioning-angles/references/hormozi-offer.md +247 -0
- package/skills/positioning-angles/references/schwartz-sophistication.md +166 -0
- package/skills/positioning-angles/references/unique-mechanism.md +162 -0
- package/skills/pricing-strategy/SKILL.md +346 -0
- package/skills/pricing-strategy/evals/evals.json +90 -0
- package/skills/pricing-strategy/references/research-methods.md +152 -0
- package/skills/pricing-strategy/references/tier-structure.md +307 -0
- package/skills/programmatic-seo/SKILL.md +238 -0
- package/skills/programmatic-seo/evals/evals.json +94 -0
- package/skills/programmatic-seo/references/playbooks.md +308 -0
- package/skills/project-rag/SKILL.md +127 -0
- package/skills/quality-gate/SKILL.md +519 -0
- package/skills/quality-gate/judge-personas/buyer.md +47 -0
- package/skills/quality-gate/judge-personas/expert.md +47 -0
- package/skills/quality-gate/judge-personas/outsider.md +47 -0
- package/skills/quality-gate/judge-personas/scanner.md +41 -0
- package/skills/quality-gate/judge-personas/skeptic.md +40 -0
- package/skills/referral-program/SKILL.md +290 -0
- package/skills/referral-program/evals/evals.json +89 -0
- package/skills/referral-program/references/affiliate-programs.md +163 -0
- package/skills/referral-program/references/program-examples.md +143 -0
- package/skills/review-sites/SKILL.md +279 -0
- package/skills/revops/SKILL.md +343 -0
- package/skills/revops/evals/evals.json +91 -0
- package/skills/revops/references/automation-playbooks.md +290 -0
- package/skills/revops/references/lifecycle-definitions.md +278 -0
- package/skills/revops/references/routing-rules.md +203 -0
- package/skills/revops/references/scoring-models.md +247 -0
- package/skills/saas-product-seo/SKILL.md +324 -0
- package/skills/sales-enablement/SKILL.md +349 -0
- package/skills/sales-enablement/evals/evals.json +91 -0
- package/skills/sales-enablement/references/deck-frameworks.md +263 -0
- package/skills/sales-enablement/references/demo-scripts.md +355 -0
- package/skills/sales-enablement/references/objection-library.md +270 -0
- package/skills/sales-enablement/references/one-pager-templates.md +208 -0
- package/skills/schema-markup/SKILL.md +179 -0
- package/skills/schema-markup/evals/evals.json +87 -0
- package/skills/schema-markup/references/schema-examples.md +398 -0
- package/skills/self-improve/SKILL.md +166 -0
- package/skills/self-improving-agent/README.md +243 -0
- package/skills/self-improving-agent/SKILL.md +437 -0
- package/skills/self-improving-agent/scripts/__init__.py +16 -0
- package/skills/self-improving-agent/scripts/__pycache__/auto_detect.cpython-314.pyc +0 -0
- package/skills/self-improving-agent/scripts/__pycache__/nlm_curation.cpython-314.pyc +0 -0
- package/skills/self-improving-agent/scripts/__pycache__/self_improving_agent.cpython-314.pyc +0 -0
- package/skills/self-improving-agent/scripts/auto_detect.py +270 -0
- package/skills/self-improving-agent/scripts/init_expertise_registry.py +89 -0
- package/skills/self-improving-agent/scripts/nlm_curation.py +259 -0
- package/skills/self-improving-agent/scripts/self-improving-agent +113 -0
- package/skills/self-improving-agent/scripts/self_improving_agent.py +603 -0
- package/skills/self-improving-agent/scripts/test_curation_scorer.py +20 -0
- package/skills/self-improving-agent/scripts/test_self_improving.py +184 -0
- package/skills/send-email/SKILL.md +426 -0
- package/skills/send-email/references/batch-email-examples.md +807 -0
- package/skills/send-email/references/best-practices.md +453 -0
- package/skills/send-email/references/installation.md +123 -0
- package/skills/send-email/references/single-email-examples.md +470 -0
- package/skills/send-email/references/webhooks.md +221 -0
- package/skills/seo-audit/SKILL.md +362 -0
- package/skills/seo-audit/references/ai-writing-detection.md +200 -0
- package/skills/seo-audit/references/architecture-patterns.md +271 -0
- package/skills/seo-audit/references/schema-templates.md +427 -0
- package/skills/seo-content/SKILL.md +510 -0
- package/skills/seo-content/references/anti-ai-detection.md +184 -0
- package/skills/seo-content/references/content-structures.md +148 -0
- package/skills/seo-content/references/eeat-examples.md +235 -0
- package/skills/seo-content/references/on-page-seo.md +261 -0
- package/skills/seo-content/references/pseo-playbooks.md +226 -0
- package/skills/seo-content/references/schema-templates.md +104 -0
- package/skills/seo-content/references/serp-analysis-format.md +151 -0
- package/skills/seo-machine/SKILL.md +331 -0
- package/skills/seo-machine/assets/brand-template.md +73 -0
- package/skills/seo-machine/assets/link-inventory-template.md +74 -0
- package/skills/seo-machine/assets/roadmap-template.md +184 -0
- package/skills/seo-machine/references/api-stack-recipes.md +230 -0
- package/skills/seo-machine/references/exa-recipes.md +260 -0
- package/skills/seo-machine/references/manual-research.md +73 -0
- package/skills/seo-machine/references/methodology.md +87 -0
- package/skills/seo-machine/references/off-page.md +123 -0
- package/skills/seo-machine/references/patterns/alternatives.md +176 -0
- package/skills/seo-machine/references/patterns/compare.md +105 -0
- package/skills/seo-machine/references/patterns/playbooks.md +106 -0
- package/skills/seo-machine/references/patterns/use-case.md +109 -0
- package/skills/seo-machine/references/quality-bars.md +99 -0
- package/skills/seo-machine/references/stacks/astro.md +156 -0
- package/skills/seo-machine/references/stacks/detection.md +61 -0
- package/skills/seo-machine/references/stacks/markdown-fallback.md +181 -0
- package/skills/seo-machine/references/stacks/nextjs.md +108 -0
- package/skills/seo-machine/references/stacks/rails-inertia.md +99 -0
- package/skills/seo-machine/references/striking-distance.md +116 -0
- package/skills/seo-machine/references/technical-audit.md +153 -0
- package/skills/seo-machine/scripts/link_audit.py +265 -0
- package/skills/seo-machine/scripts/tech_audit.py +221 -0
- package/skills/seo-machine/scripts/word_count.py +154 -0
- package/skills/sharp-thesis-validator/SKILL.md +393 -0
- package/skills/sharp-thesis-validator/examples.md +186 -0
- package/skills/signup-flow-cro/SKILL.md +359 -0
- package/skills/signup-flow-cro/evals/evals.json +88 -0
- package/skills/site-architecture/SKILL.md +357 -0
- package/skills/site-architecture/evals/evals.json +88 -0
- package/skills/site-architecture/references/mermaid-templates.md +216 -0
- package/skills/site-architecture/references/navigation-patterns.md +305 -0
- package/skills/site-architecture/references/site-type-templates.md +293 -0
- package/skills/skill-self-improvement/SKILL.md +151 -0
- package/skills/slideshow-script/SKILL.md +274 -0
- package/skills/slideshow-script/references/content-spec-schema.md +77 -0
- package/skills/slideshow-script/references/frameworks.md +84 -0
- package/skills/slideshow-script/references/paips-framework.md +37 -0
- package/skills/social-campaign/SKILL.md +419 -0
- package/skills/social-campaign/references/paper-mcp-workflow.md +48 -0
- package/skills/social-content/SKILL.md +359 -0
- package/skills/social-content/evals/evals.json +92 -0
- package/skills/social-content/references/platforms.md +170 -0
- package/skills/social-content/references/post-templates.md +177 -0
- package/skills/social-content/references/reverse-engineering.md +195 -0
- package/skills/social-worker/SKILL.md +204 -0
- package/skills/startup-launcher/SKILL.md +252 -0
- package/skills/startup-launcher/references/file-router.md +64 -0
- package/skills/startup-launcher/references/platform-matrix.md +65 -0
- package/skills/startup-launcher/references/platforms/alternativeto.md +283 -0
- package/skills/startup-launcher/references/platforms/appsumo.md +495 -0
- package/skills/startup-launcher/references/platforms/auraplusplus.md +736 -0
- package/skills/startup-launcher/references/platforms/betalist.md +98 -0
- package/skills/startup-launcher/references/platforms/capterra.md +276 -0
- package/skills/startup-launcher/references/platforms/crunchbase.md +514 -0
- package/skills/startup-launcher/references/platforms/dealify.md +291 -0
- package/skills/startup-launcher/references/platforms/dealmirror.md +313 -0
- package/skills/startup-launcher/references/platforms/desifounder.md +490 -0
- package/skills/startup-launcher/references/platforms/devhunt.md +210 -0
- package/skills/startup-launcher/references/platforms/devpost.md +448 -0
- package/skills/startup-launcher/references/platforms/fazier.md +56 -0
- package/skills/startup-launcher/references/platforms/firsto.md +489 -0
- package/skills/startup-launcher/references/platforms/g2.md +226 -0
- package/skills/startup-launcher/references/platforms/hackernews.md +99 -0
- package/skills/startup-launcher/references/platforms/hackernoon.md +385 -0
- package/skills/startup-launcher/references/platforms/indiedeals.md +367 -0
- package/skills/startup-launcher/references/platforms/indiehackers.md +80 -0
- package/skills/startup-launcher/references/platforms/kenmoo.md +231 -0
- package/skills/startup-launcher/references/platforms/labstartups.md +618 -0
- package/skills/startup-launcher/references/platforms/launchboard.md +307 -0
- package/skills/startup-launcher/references/platforms/launchfast.md +560 -0
- package/skills/startup-launcher/references/platforms/launchigniter.md +56 -0
- package/skills/startup-launcher/references/platforms/launchingnext.md +674 -0
- package/skills/startup-launcher/references/platforms/launchit.md +574 -0
- package/skills/startup-launcher/references/platforms/launchyourapp.md +677 -0
- package/skills/startup-launcher/references/platforms/libhunt.md +220 -0
- package/skills/startup-launcher/references/platforms/ltdhunt.md +221 -0
- package/skills/startup-launcher/references/platforms/microlaunch.md +45 -0
- package/skills/startup-launcher/references/platforms/openalternative.md +195 -0
- package/skills/startup-launcher/references/platforms/peerlist.md +56 -0
- package/skills/startup-launcher/references/platforms/peerpush.md +64 -0
- package/skills/startup-launcher/references/platforms/primeclub.md +282 -0
- package/skills/startup-launcher/references/platforms/productcanyon.md +190 -0
- package/skills/startup-launcher/references/platforms/producthunt.md +98 -0
- package/skills/startup-launcher/references/platforms/rankinpublic.md +315 -0
- package/skills/startup-launcher/references/platforms/rockethub.md +374 -0
- package/skills/startup-launcher/references/platforms/saasgenius.md +175 -0
- package/skills/startup-launcher/references/platforms/saashub.md +205 -0
- package/skills/startup-launcher/references/platforms/saasmantra.md +221 -0
- package/skills/startup-launcher/references/platforms/saaspirate.md +287 -0
- package/skills/startup-launcher/references/platforms/saaswarrior.md +190 -0
- package/skills/startup-launcher/references/platforms/saaszilla.md +194 -0
- package/skills/startup-launcher/references/platforms/selected.md +925 -0
- package/skills/startup-launcher/references/platforms/sideprojectors.md +86 -0
- package/skills/startup-launcher/references/platforms/softonic.md +240 -0
- package/skills/startup-launcher/references/platforms/sourceforge.md +251 -0
- package/skills/startup-launcher/references/platforms/stacksocial.md +244 -0
- package/skills/startup-launcher/references/platforms/startupstash.md +326 -0
- package/skills/startup-launcher/references/platforms/theresanaiforthat.md +253 -0
- package/skills/startup-launcher/references/platforms/tinylaunch.md +70 -0
- package/skills/startup-launcher/references/platforms/tinystartups.md +72 -0
- package/skills/startup-launcher/references/platforms/toolfolio.md +291 -0
- package/skills/startup-launcher/references/platforms/trustmrr.md +194 -0
- package/skills/startup-launcher/references/platforms/trylaunch.md +531 -0
- package/skills/startup-launcher/references/platforms/uneed.md +57 -0
- package/skills/startup-launcher/references/templates/asset-checklist.md +218 -0
- package/skills/startup-launcher/references/templates/launch-tracker.md +195 -0
- package/skills/startup-launcher/references/templates/product-brief.md +98 -0
- package/skills/summarize/.skill-meta.json +13 -0
- package/skills/summarize/SKILL.md +170 -0
- package/skills/summarize/rules/install.md +157 -0
- package/skills/summarize/rules/usage.md +207 -0
- package/skills/topical-authority/SKILL.md +307 -0
- package/skills/topical-authority/references/jake-ward-framework.md +201 -0
- package/skills/topical-authority/references/serp-clustering-algorithm.md +325 -0
- package/skills/topical-authority/scripts/orchestrator.js +367 -0
- package/skills/topical-authority/scripts/seo/analyze-competitor-coverage.js +3 -0
- package/skills/topical-authority/scripts/seo/audit-internal-links.js +3 -0
- package/skills/topical-authority/scripts/seo/build-clusters-from-serp.js +3 -0
- package/skills/topical-authority/scripts/seo/extract-keywords-from-forums.js +3 -0
- package/skills/topical-authority/scripts/seo/extract-paa-questions.js +3 -0
- package/skills/topical-authority/scripts/seo/fetch-serp-urls.js +3 -0
- package/skills/topical-authority/scripts/seo/gemini-serp-clustering.js +3 -0
- package/skills/topical-authority/scripts/seo/identify-content-gaps.js +3 -0
- package/skills/topical-authority/scripts/seo/identify-research-gaps.js +3 -0
- package/skills/topical-authority/scripts/seo/scrape-quora-questions.js +3 -0
- package/skills/topical-authority/scripts/seo/scrape-reddit-pain-points.js +3 -0
- package/skills/topical-authority/scripts/seo/weave-internal-links.js +3 -0
- package/skills/visual-style/SKILL.md +199 -0
- package/skills/voice-brand-alignment/SKILL.md +70 -0
- package/skills/voice-brand-alignment/references/ai-slop-patterns.md +405 -0
- package/skills/voice-brand-alignment/scripts/validation/gemini-voice-validator.js +96 -0
- package/skills/voice-extraction/SKILL.md +234 -0
- package/skills/voice-extraction/references/extraction-prompt.md +155 -0
- package/skills/voice-extraction/references/voice-dna-template.md +168 -0
- package/skills/voice-extraction/references/voice-elements.md +259 -0
- package/skills/voice-extraction/scripts/build-corpus.js +120 -0
- package/skills/voice-extraction/scripts/collect-sources.sh +168 -0
- package/skills/warm-outbound/SKILL.md +299 -0
- package/skills/warm-outbound/templates/warm-message.md +39 -0
- package/skills/weekly-newsletter-digest/SKILL.md +78 -0
- package/skills/x-playwriter/SKILL.md +428 -0
- package/skills/x-playwriter/scripts/x-browser.js +185 -0
- package/skills/x-post-generator-openclaw/SKILL.md +138 -0
- package/skills/x-post-generator-openclaw/scripts/generate-x-post.js +537 -0
- package/skills/x-posting-playwriter/SKILL.md +203 -0
- package/skills/x-research/SKILL.md +129 -0
- package/skills/x-research/x-research.sh +85 -0
- package/skills/youtube-summarize/SKILL.md +90 -0
- package/skills/youtube-summarize/scripts/youtube-summarize.sh +143 -0
- package/src/cli.js +347 -172
- package/src/harness/deepseek-adapter.js +102 -0
- package/src/harness/deepseek.js +225 -0
- package/src/harness/opencode-adapter.js +174 -0
- package/src/harness/pi-adapter.js +172 -0
- package/src/harness/registry.js +121 -0
- package/src/harness/telemetry.js +102 -0
- package/src/harness/types.js +165 -0
- package/src/interview.js +36 -4
- package/src/postinstall.js +10 -12
- package/templates/AGENTS.md +17 -17
- package/templates/ORG.md +1 -1
- package/templates/TOOLS.md +7 -2
- package/templates/opencode.json +26 -29
- package/wiki/doctor.md +54 -0
- package/wiki/inkstone.md +4 -4
- package/wiki/opencode.md +3 -3
- package/skills/curated.txt +0 -68
|
@@ -0,0 +1,194 @@
|
|
|
1
|
+
"""Error handling tests — file not found, corrupt data, edge cases."""
|
|
2
|
+
import json
|
|
3
|
+
import sys
|
|
4
|
+
import pytest
|
|
5
|
+
from pathlib import Path
|
|
6
|
+
|
|
7
|
+
sys.path.insert(0, str(Path(__file__).resolve().parent.parent / "scripts"))
|
|
8
|
+
|
|
9
|
+
from lib.exceptions import FileNotFoundError_, MemCompressError, ParseError, TokenEstimationError
|
|
10
|
+
from lib.dictionary import load_codebook, save_codebook, compress_text, decompress_text, build_codebook
|
|
11
|
+
from lib.tokens import estimate_tokens
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
class TestExceptions:
|
|
15
|
+
def test_file_not_found_is_mem_compress_error(self):
|
|
16
|
+
assert issubclass(FileNotFoundError_, MemCompressError)
|
|
17
|
+
|
|
18
|
+
def test_parse_error_is_mem_compress_error(self):
|
|
19
|
+
assert issubclass(ParseError, MemCompressError)
|
|
20
|
+
|
|
21
|
+
def test_token_estimation_error(self):
|
|
22
|
+
assert issubclass(TokenEstimationError, MemCompressError)
|
|
23
|
+
|
|
24
|
+
def test_raise_file_not_found(self):
|
|
25
|
+
with pytest.raises(FileNotFoundError_):
|
|
26
|
+
raise FileNotFoundError_("test.md")
|
|
27
|
+
|
|
28
|
+
def test_raise_parse_error(self):
|
|
29
|
+
with pytest.raises(ParseError):
|
|
30
|
+
raise ParseError("bad markdown")
|
|
31
|
+
|
|
32
|
+
def test_exception_message(self):
|
|
33
|
+
e = FileNotFoundError_("missing.md")
|
|
34
|
+
assert "missing.md" in str(e)
|
|
35
|
+
|
|
36
|
+
|
|
37
|
+
class TestDictionaryErrors:
|
|
38
|
+
def test_load_nonexistent_codebook(self, tmp_path):
|
|
39
|
+
with pytest.raises(Exception):
|
|
40
|
+
load_codebook(tmp_path / "nonexistent.json")
|
|
41
|
+
|
|
42
|
+
def test_load_corrupt_codebook(self, tmp_path):
|
|
43
|
+
bad = tmp_path / "bad.json"
|
|
44
|
+
bad.write_text("this is not json{{{")
|
|
45
|
+
with pytest.raises(Exception):
|
|
46
|
+
load_codebook(bad)
|
|
47
|
+
|
|
48
|
+
def test_load_empty_file(self, tmp_path):
|
|
49
|
+
empty = tmp_path / "empty.json"
|
|
50
|
+
empty.write_text("")
|
|
51
|
+
with pytest.raises(Exception):
|
|
52
|
+
load_codebook(empty)
|
|
53
|
+
|
|
54
|
+
def test_compress_empty_codebook(self):
|
|
55
|
+
result = compress_text("hello world", {})
|
|
56
|
+
assert result == "hello world"
|
|
57
|
+
|
|
58
|
+
def test_decompress_empty_codebook(self):
|
|
59
|
+
result = decompress_text("hello world", {})
|
|
60
|
+
assert result == "hello world"
|
|
61
|
+
|
|
62
|
+
def test_compress_empty_text(self):
|
|
63
|
+
result = compress_text("", {"hello": "$AA"})
|
|
64
|
+
assert result == ""
|
|
65
|
+
|
|
66
|
+
def test_build_codebook_empty_input(self):
|
|
67
|
+
result = build_codebook([])
|
|
68
|
+
assert isinstance(result, dict)
|
|
69
|
+
|
|
70
|
+
def test_build_codebook_whitespace_only(self):
|
|
71
|
+
result = build_codebook([" \n\n "])
|
|
72
|
+
assert isinstance(result, dict)
|
|
73
|
+
|
|
74
|
+
def test_save_load_roundtrip(self, tmp_path):
|
|
75
|
+
codebook = {"hello": "$AA", "world": "$AB"}
|
|
76
|
+
path = tmp_path / "cb.json"
|
|
77
|
+
save_codebook(codebook, path)
|
|
78
|
+
loaded = load_codebook(path)
|
|
79
|
+
assert loaded == codebook
|
|
80
|
+
|
|
81
|
+
|
|
82
|
+
class TestEstimateTokenErrors:
|
|
83
|
+
def test_none_input(self):
|
|
84
|
+
"""Estimate tokens with None should raise or handle gracefully."""
|
|
85
|
+
with pytest.raises((TypeError, AttributeError)):
|
|
86
|
+
estimate_tokens(None)
|
|
87
|
+
|
|
88
|
+
def test_numeric_input(self):
|
|
89
|
+
with pytest.raises((TypeError, AttributeError)):
|
|
90
|
+
estimate_tokens(42)
|
|
91
|
+
|
|
92
|
+
def test_bytes_input(self):
|
|
93
|
+
with pytest.raises((TypeError, AttributeError)):
|
|
94
|
+
estimate_tokens(b"hello")
|
|
95
|
+
|
|
96
|
+
|
|
97
|
+
class TestCompressMemoryErrors:
|
|
98
|
+
def test_nonexistent_path(self):
|
|
99
|
+
from compress_memory import _collect_files
|
|
100
|
+
with pytest.raises(FileNotFoundError_):
|
|
101
|
+
_collect_files("/nonexistent/path/xyz123")
|
|
102
|
+
|
|
103
|
+
def test_empty_file(self, tmp_path):
|
|
104
|
+
from compress_memory import compress_file
|
|
105
|
+
f = tmp_path / "empty.md"
|
|
106
|
+
f.write_text("")
|
|
107
|
+
result = compress_file(f, dry_run=True, no_llm=True)
|
|
108
|
+
assert isinstance(result, dict)
|
|
109
|
+
|
|
110
|
+
def test_binary_content(self, tmp_path):
|
|
111
|
+
"""Binary-ish content shouldn't crash."""
|
|
112
|
+
from compress_memory import rule_compress
|
|
113
|
+
text = "Normal text\x00\x01\x02 more text"
|
|
114
|
+
result = rule_compress(text)
|
|
115
|
+
assert isinstance(result, str)
|
|
116
|
+
|
|
117
|
+
|
|
118
|
+
class TestDedupErrors:
|
|
119
|
+
def test_nonexistent_path(self):
|
|
120
|
+
from dedup_memory import _collect_entries
|
|
121
|
+
with pytest.raises(FileNotFoundError_):
|
|
122
|
+
_collect_entries("/nonexistent/xyz")
|
|
123
|
+
|
|
124
|
+
def test_empty_directory(self, tmp_path):
|
|
125
|
+
from dedup_memory import _collect_entries
|
|
126
|
+
result = _collect_entries(str(tmp_path))
|
|
127
|
+
assert result == []
|
|
128
|
+
|
|
129
|
+
|
|
130
|
+
class TestEstimateTokensScript:
|
|
131
|
+
def test_nonexistent_path(self):
|
|
132
|
+
from estimate_tokens import scan_path
|
|
133
|
+
with pytest.raises(FileNotFoundError_):
|
|
134
|
+
scan_path("/nonexistent/xyz")
|
|
135
|
+
|
|
136
|
+
|
|
137
|
+
class TestAuditErrors:
|
|
138
|
+
def test_nonexistent_workspace(self):
|
|
139
|
+
from audit_memory import audit_workspace
|
|
140
|
+
with pytest.raises(FileNotFoundError_):
|
|
141
|
+
audit_workspace("/nonexistent/xyz")
|
|
142
|
+
|
|
143
|
+
|
|
144
|
+
class TestTiersErrors:
|
|
145
|
+
def test_nonexistent_path(self):
|
|
146
|
+
from generate_summary_tiers import _find_memory_files
|
|
147
|
+
with pytest.raises(FileNotFoundError_):
|
|
148
|
+
_find_memory_files("/nonexistent/xyz")
|
|
149
|
+
|
|
150
|
+
|
|
151
|
+
class TestObservationErrors:
|
|
152
|
+
def test_nonexistent_file(self):
|
|
153
|
+
from observation_compressor import parse_session_jsonl
|
|
154
|
+
with pytest.raises(Exception):
|
|
155
|
+
parse_session_jsonl(Path("/nonexistent/session.jsonl"))
|
|
156
|
+
|
|
157
|
+
def test_corrupt_jsonl(self, tmp_path):
|
|
158
|
+
from observation_compressor import parse_session_jsonl
|
|
159
|
+
f = tmp_path / "bad.jsonl"
|
|
160
|
+
f.write_text("not json\n{bad json}\n")
|
|
161
|
+
# Should handle gracefully (skip bad lines or raise)
|
|
162
|
+
try:
|
|
163
|
+
result = parse_session_jsonl(f)
|
|
164
|
+
assert isinstance(result, list)
|
|
165
|
+
except Exception:
|
|
166
|
+
pass # Either handling is acceptable
|
|
167
|
+
|
|
168
|
+
def test_empty_jsonl(self, tmp_path):
|
|
169
|
+
from observation_compressor import parse_session_jsonl
|
|
170
|
+
f = tmp_path / "empty.jsonl"
|
|
171
|
+
f.write_text("")
|
|
172
|
+
result = parse_session_jsonl(f)
|
|
173
|
+
assert result == []
|
|
174
|
+
|
|
175
|
+
def test_compress_empty_session(self, tmp_path):
|
|
176
|
+
from observation_compressor import compress_session
|
|
177
|
+
f = tmp_path / "empty.jsonl"
|
|
178
|
+
f.write_text("")
|
|
179
|
+
result = compress_session(f)
|
|
180
|
+
assert isinstance(result, dict)
|
|
181
|
+
|
|
182
|
+
|
|
183
|
+
class TestMainEntryErrors:
|
|
184
|
+
def test_nonexistent_workspace(self):
|
|
185
|
+
from mem_compress import _workspace_path
|
|
186
|
+
with pytest.raises(SystemExit):
|
|
187
|
+
_workspace_path("/nonexistent/xyz")
|
|
188
|
+
|
|
189
|
+
def test_file_as_workspace(self, tmp_path):
|
|
190
|
+
f = tmp_path / "file.txt"
|
|
191
|
+
f.write_text("hello")
|
|
192
|
+
from mem_compress import _workspace_path
|
|
193
|
+
with pytest.raises(SystemExit):
|
|
194
|
+
_workspace_path(str(f))
|
|
@@ -0,0 +1,99 @@
|
|
|
1
|
+
"""Tests for estimate_tokens.py."""
|
|
2
|
+
|
|
3
|
+
import json
|
|
4
|
+
import sys
|
|
5
|
+
from pathlib import Path
|
|
6
|
+
|
|
7
|
+
import pytest
|
|
8
|
+
|
|
9
|
+
sys.path.insert(0, str(Path(__file__).resolve().parent.parent / "scripts"))
|
|
10
|
+
from estimate_tokens import scan_path, format_human, _score_potential
|
|
11
|
+
from lib.tokens import estimate_tokens, using_tiktoken
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
class TestEstimateTokens:
|
|
15
|
+
def test_empty_string(self):
|
|
16
|
+
assert estimate_tokens("") == 0
|
|
17
|
+
|
|
18
|
+
def test_simple_english(self):
|
|
19
|
+
tokens = estimate_tokens("Hello world, this is a test.")
|
|
20
|
+
assert 0 < tokens < 50
|
|
21
|
+
|
|
22
|
+
def test_unicode_chinese(self):
|
|
23
|
+
assert estimate_tokens("你好世界") > 0
|
|
24
|
+
|
|
25
|
+
def test_large_input(self):
|
|
26
|
+
assert estimate_tokens("word " * 25000) > 1000
|
|
27
|
+
|
|
28
|
+
|
|
29
|
+
class TestScorePotential:
|
|
30
|
+
def test_high_tokens(self):
|
|
31
|
+
assert _score_potential(3000, 2500) == "high"
|
|
32
|
+
|
|
33
|
+
def test_high_reduction(self):
|
|
34
|
+
assert _score_potential(1000, 800) == "high"
|
|
35
|
+
|
|
36
|
+
def test_medium(self):
|
|
37
|
+
assert _score_potential(600, 560) == "medium"
|
|
38
|
+
|
|
39
|
+
def test_low(self):
|
|
40
|
+
assert _score_potential(100, 98) == "low"
|
|
41
|
+
|
|
42
|
+
def test_zero(self):
|
|
43
|
+
assert _score_potential(0, 0) == "low"
|
|
44
|
+
|
|
45
|
+
|
|
46
|
+
class TestScanPath:
|
|
47
|
+
def test_workspace(self, tmp_workspace):
|
|
48
|
+
results = scan_path(str(tmp_workspace))
|
|
49
|
+
assert len(results) > 0
|
|
50
|
+
assert all("tokens" in r for r in results)
|
|
51
|
+
|
|
52
|
+
def test_single_file(self, tmp_workspace):
|
|
53
|
+
assert len(scan_path(str(tmp_workspace / "MEMORY.md"))) == 1
|
|
54
|
+
|
|
55
|
+
def test_empty_file(self, empty_file):
|
|
56
|
+
results = scan_path(str(empty_file))
|
|
57
|
+
assert len(results) == 1
|
|
58
|
+
assert results[0]["tokens"] == 0
|
|
59
|
+
|
|
60
|
+
def test_nonexistent(self):
|
|
61
|
+
with pytest.raises(Exception):
|
|
62
|
+
scan_path("/nonexistent/xyz")
|
|
63
|
+
|
|
64
|
+
def test_large_file(self, large_file):
|
|
65
|
+
results = scan_path(str(large_file))
|
|
66
|
+
assert results[0]["tokens"] > 1000
|
|
67
|
+
|
|
68
|
+
def test_unicode(self, unicode_file):
|
|
69
|
+
assert scan_path(str(unicode_file))[0]["tokens"] > 0
|
|
70
|
+
|
|
71
|
+
def test_broken_markdown(self, broken_markdown):
|
|
72
|
+
assert len(scan_path(str(broken_markdown))) == 1
|
|
73
|
+
|
|
74
|
+
def test_threshold(self, tmp_workspace):
|
|
75
|
+
assert len(scan_path(str(tmp_workspace), threshold=999999)) == 0
|
|
76
|
+
|
|
77
|
+
def test_headers_only(self, headers_only):
|
|
78
|
+
assert len(scan_path(str(headers_only))) == 1
|
|
79
|
+
|
|
80
|
+
def test_single_line(self, single_line):
|
|
81
|
+
assert scan_path(str(single_line))[0]["tokens"] > 0
|
|
82
|
+
|
|
83
|
+
def test_sorted_desc(self, tmp_workspace):
|
|
84
|
+
tokens = [r["tokens"] for r in scan_path(str(tmp_workspace))]
|
|
85
|
+
assert tokens == sorted(tokens, reverse=True)
|
|
86
|
+
|
|
87
|
+
|
|
88
|
+
class TestFormatHuman:
|
|
89
|
+
def test_empty(self):
|
|
90
|
+
assert "No files" in format_human([])
|
|
91
|
+
|
|
92
|
+
def test_normal(self, tmp_workspace):
|
|
93
|
+
output = format_human(scan_path(str(tmp_workspace)))
|
|
94
|
+
assert "Token Estimation Report" in output
|
|
95
|
+
|
|
96
|
+
def test_json_roundtrip(self, tmp_workspace):
|
|
97
|
+
results = scan_path(str(tmp_workspace))
|
|
98
|
+
j = json.dumps({"files": results})
|
|
99
|
+
assert "files" in json.loads(j)
|
|
@@ -0,0 +1,105 @@
|
|
|
1
|
+
"""Tests for generate_summary_tiers.py."""
|
|
2
|
+
|
|
3
|
+
import json
|
|
4
|
+
import sys
|
|
5
|
+
from pathlib import Path
|
|
6
|
+
|
|
7
|
+
import pytest
|
|
8
|
+
|
|
9
|
+
sys.path.insert(0, str(Path(__file__).resolve().parent.parent / "scripts"))
|
|
10
|
+
from generate_summary_tiers import generate_tiers, format_human, format_tier_template, _find_memory_files, _classify_section
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
class TestClassifySection:
|
|
14
|
+
def test_decision(self):
|
|
15
|
+
assert _classify_section("Important Decisions") >= 9
|
|
16
|
+
|
|
17
|
+
def test_archive(self):
|
|
18
|
+
assert _classify_section("Archive") <= 2
|
|
19
|
+
|
|
20
|
+
def test_action(self):
|
|
21
|
+
assert _classify_section("Action Items") >= 8
|
|
22
|
+
|
|
23
|
+
def test_unknown(self):
|
|
24
|
+
assert _classify_section("Random Header") == 5
|
|
25
|
+
|
|
26
|
+
def test_case_insensitive(self):
|
|
27
|
+
assert _classify_section("CRITICAL BUGS") >= 9
|
|
28
|
+
|
|
29
|
+
|
|
30
|
+
class TestFindMemoryFiles:
|
|
31
|
+
def test_workspace(self, tmp_workspace):
|
|
32
|
+
files = _find_memory_files(str(tmp_workspace))
|
|
33
|
+
assert len(files) > 0
|
|
34
|
+
assert "MEMORY.md" in str(files[0])
|
|
35
|
+
|
|
36
|
+
def test_single_file(self, tmp_workspace):
|
|
37
|
+
assert len(_find_memory_files(str(tmp_workspace / "MEMORY.md"))) == 1
|
|
38
|
+
|
|
39
|
+
def test_nonexistent(self):
|
|
40
|
+
with pytest.raises(Exception):
|
|
41
|
+
_find_memory_files("/nonexistent/xyz")
|
|
42
|
+
|
|
43
|
+
def test_empty_dir(self, tmp_path):
|
|
44
|
+
assert len(_find_memory_files(str(tmp_path))) == 0
|
|
45
|
+
|
|
46
|
+
|
|
47
|
+
class TestGenerateTiers:
|
|
48
|
+
def test_basic(self, tmp_workspace):
|
|
49
|
+
result = generate_tiers(_find_memory_files(str(tmp_workspace)))
|
|
50
|
+
assert "total_tokens" in result
|
|
51
|
+
assert len(result["tiers"]) == 3
|
|
52
|
+
|
|
53
|
+
def test_budgets_respected(self, tmp_workspace):
|
|
54
|
+
result = generate_tiers(_find_memory_files(str(tmp_workspace)))
|
|
55
|
+
for tier in result["tiers"].values():
|
|
56
|
+
assert tier["tokens_used"] <= tier["budget"]
|
|
57
|
+
|
|
58
|
+
def test_tier_ordering(self, tmp_workspace):
|
|
59
|
+
result = generate_tiers(_find_memory_files(str(tmp_workspace)))
|
|
60
|
+
counts = [result["tiers"][i]["sections_included"] for i in range(3)]
|
|
61
|
+
assert counts[0] <= counts[1] <= counts[2]
|
|
62
|
+
|
|
63
|
+
def test_empty_file(self, empty_file):
|
|
64
|
+
assert generate_tiers([empty_file])["total_tokens"] == 0
|
|
65
|
+
|
|
66
|
+
def test_unicode(self, unicode_file):
|
|
67
|
+
assert generate_tiers([unicode_file])["total_tokens"] > 0
|
|
68
|
+
|
|
69
|
+
def test_large_file(self, large_file):
|
|
70
|
+
assert generate_tiers([large_file])["total_sections"] > 100
|
|
71
|
+
|
|
72
|
+
def test_headers_only(self, headers_only):
|
|
73
|
+
assert isinstance(generate_tiers([headers_only]), dict)
|
|
74
|
+
|
|
75
|
+
def test_single_line(self, single_line):
|
|
76
|
+
assert generate_tiers([single_line])["total_sections"] >= 1
|
|
77
|
+
|
|
78
|
+
def test_broken_markdown(self, broken_markdown):
|
|
79
|
+
assert isinstance(generate_tiers([broken_markdown]), dict)
|
|
80
|
+
|
|
81
|
+
|
|
82
|
+
class TestFormatHuman:
|
|
83
|
+
def test_output(self, tmp_workspace):
|
|
84
|
+
output = format_human(generate_tiers(_find_memory_files(str(tmp_workspace))))
|
|
85
|
+
assert "Summary Tier Analysis" in output
|
|
86
|
+
for level in range(3):
|
|
87
|
+
assert "Level {}".format(level) in output
|
|
88
|
+
|
|
89
|
+
|
|
90
|
+
class TestFormatTierTemplate:
|
|
91
|
+
def test_markdown(self, tmp_workspace):
|
|
92
|
+
result = generate_tiers(_find_memory_files(str(tmp_workspace)))
|
|
93
|
+
for level in range(3):
|
|
94
|
+
t = format_tier_template(result, level)
|
|
95
|
+
assert "Level {}".format(level) in t
|
|
96
|
+
assert "Budget:" in t
|
|
97
|
+
|
|
98
|
+
def test_empty(self, empty_file):
|
|
99
|
+
assert isinstance(format_tier_template(generate_tiers([empty_file]), 0), str)
|
|
100
|
+
|
|
101
|
+
|
|
102
|
+
class TestJsonOutput:
|
|
103
|
+
def test_serializable(self, tmp_workspace):
|
|
104
|
+
result = generate_tiers(_find_memory_files(str(tmp_workspace)))
|
|
105
|
+
assert "tiers" in json.loads(json.dumps(result))
|
|
@@ -0,0 +1,249 @@
|
|
|
1
|
+
"""Integration tests: full pipeline and cross-module scenarios."""
|
|
2
|
+
|
|
3
|
+
import json
|
|
4
|
+
import subprocess
|
|
5
|
+
import sys
|
|
6
|
+
from pathlib import Path
|
|
7
|
+
|
|
8
|
+
import pytest
|
|
9
|
+
|
|
10
|
+
from estimate_tokens import scan_path, format_human as est_format
|
|
11
|
+
from compress_memory import rule_compress, compress_file, generate_llm_prompt
|
|
12
|
+
from generate_summary_tiers import generate_tiers
|
|
13
|
+
from dedup_memory import run_dedup
|
|
14
|
+
from lib.tokens import estimate_tokens
|
|
15
|
+
from lib.markdown import parse_sections, strip_markdown_redundancy
|
|
16
|
+
from lib.dedup import find_duplicates
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
class TestFullPipeline:
|
|
20
|
+
"""End-to-end: estimate → compress → tiers → dedup."""
|
|
21
|
+
|
|
22
|
+
def test_estimate_compress_tiers_dedup(self, tmp_workspace: Path) -> None:
|
|
23
|
+
"""Full pipeline on a populated workspace."""
|
|
24
|
+
ws = str(tmp_workspace)
|
|
25
|
+
|
|
26
|
+
# 1. Estimate
|
|
27
|
+
results = scan_path(ws)
|
|
28
|
+
assert len(results) > 0
|
|
29
|
+
total_before = sum(r["tokens"] for r in results)
|
|
30
|
+
assert total_before > 0
|
|
31
|
+
|
|
32
|
+
# 2. Compress each daily file
|
|
33
|
+
memory_dir = tmp_workspace / "memory"
|
|
34
|
+
for f in sorted(memory_dir.glob("*.md")):
|
|
35
|
+
stats = compress_file(f, dry_run=True, no_llm=True)
|
|
36
|
+
assert stats["original_tokens"] >= stats["rule_compressed_tokens"]
|
|
37
|
+
assert stats["rule_reduction_pct"] >= 0
|
|
38
|
+
|
|
39
|
+
# 3. Generate tiers
|
|
40
|
+
files = [tmp_workspace / "MEMORY.md"] + sorted(memory_dir.glob("*.md"))
|
|
41
|
+
tier_result = generate_tiers(files)
|
|
42
|
+
assert tier_result["total_tokens"] > 0
|
|
43
|
+
assert 0 in tier_result["tiers"]
|
|
44
|
+
assert 1 in tier_result["tiers"]
|
|
45
|
+
assert 2 in tier_result["tiers"]
|
|
46
|
+
# Level 0 should use fewer tokens than Level 2
|
|
47
|
+
assert tier_result["tiers"][0]["tokens_used"] <= tier_result["tiers"][2]["tokens_used"]
|
|
48
|
+
|
|
49
|
+
# 4. Dedup
|
|
50
|
+
dedup_result = run_dedup(ws)
|
|
51
|
+
assert "duplicate_groups" in dedup_result
|
|
52
|
+
assert dedup_result["total_entries"] >= 0
|
|
53
|
+
|
|
54
|
+
def test_unicode_pipeline(self, unicode_file: Path) -> None:
|
|
55
|
+
"""Pipeline with Chinese/mixed content."""
|
|
56
|
+
# Estimate
|
|
57
|
+
results = scan_path(str(unicode_file))
|
|
58
|
+
assert len(results) == 1
|
|
59
|
+
assert results[0]["tokens"] > 0
|
|
60
|
+
|
|
61
|
+
# Compress
|
|
62
|
+
stats = compress_file(unicode_file, dry_run=True, no_llm=True)
|
|
63
|
+
assert stats["original_tokens"] > 0
|
|
64
|
+
|
|
65
|
+
# Parse sections
|
|
66
|
+
text = unicode_file.read_text(encoding="utf-8")
|
|
67
|
+
sections = parse_sections(text)
|
|
68
|
+
assert len(sections) >= 1
|
|
69
|
+
|
|
70
|
+
def test_large_file_pipeline(self, large_file: Path) -> None:
|
|
71
|
+
"""Pipeline with ~100k+ char file."""
|
|
72
|
+
results = scan_path(str(large_file))
|
|
73
|
+
assert results[0]["tokens"] > 10000
|
|
74
|
+
|
|
75
|
+
stats = compress_file(large_file, dry_run=True, no_llm=True)
|
|
76
|
+
assert stats["original_tokens"] > 10000
|
|
77
|
+
# Rule compression should remove at least something
|
|
78
|
+
assert stats["rule_compressed_tokens"] <= stats["original_tokens"]
|
|
79
|
+
|
|
80
|
+
def test_empty_file_resilience(self, empty_file: Path) -> None:
|
|
81
|
+
"""All tools handle empty file gracefully."""
|
|
82
|
+
results = scan_path(str(empty_file))
|
|
83
|
+
assert len(results) >= 1 # the file exists, just empty
|
|
84
|
+
|
|
85
|
+
stats = compress_file(empty_file, dry_run=True, no_llm=True)
|
|
86
|
+
assert stats["original_tokens"] == 0
|
|
87
|
+
|
|
88
|
+
def test_broken_markdown_resilience(self, broken_markdown: Path) -> None:
|
|
89
|
+
"""Broken markdown doesn't crash anything."""
|
|
90
|
+
results = scan_path(str(broken_markdown))
|
|
91
|
+
assert len(results) == 1
|
|
92
|
+
|
|
93
|
+
stats = compress_file(broken_markdown, dry_run=True, no_llm=True)
|
|
94
|
+
assert stats["original_tokens"] > 0
|
|
95
|
+
|
|
96
|
+
sections = parse_sections(broken_markdown.read_text(encoding="utf-8"))
|
|
97
|
+
assert len(sections) >= 1
|
|
98
|
+
|
|
99
|
+
def test_dedup_finds_known_duplicates(self, duplicate_content: Path) -> None:
|
|
100
|
+
"""Dedup correctly identifies known duplicate content."""
|
|
101
|
+
result = run_dedup(str(duplicate_content), threshold=0.5)
|
|
102
|
+
assert result["total_entries"] >= 2
|
|
103
|
+
# The two files have nearly identical "Setup" sections
|
|
104
|
+
assert len(result["duplicate_groups"]) >= 1
|
|
105
|
+
|
|
106
|
+
def test_dedup_auto_merge(self, duplicate_content: Path) -> None:
|
|
107
|
+
"""Auto-merge removes duplicates and preserves unique content."""
|
|
108
|
+
result = run_dedup(str(duplicate_content), threshold=0.5, auto_merge=True)
|
|
109
|
+
if result["duplicate_groups"]:
|
|
110
|
+
assert result.get("tokens_saved", 0) >= 0
|
|
111
|
+
if "files_modified" in result:
|
|
112
|
+
# Verify unique content survived
|
|
113
|
+
b_text = (duplicate_content / "b.md").read_text(encoding="utf-8")
|
|
114
|
+
assert "Unique content" in b_text
|
|
115
|
+
|
|
116
|
+
|
|
117
|
+
class TestCompressionQuality:
|
|
118
|
+
"""Verify compression preserves information."""
|
|
119
|
+
|
|
120
|
+
def test_rule_compress_preserves_facts(self) -> None:
|
|
121
|
+
"""Rule compression keeps key facts."""
|
|
122
|
+
text = (
|
|
123
|
+
"# 2025-01-15 Session Notes\n\n"
|
|
124
|
+
"- Fixed critical bug in API endpoint /v2/orders\n"
|
|
125
|
+
"- Server IP: 10.0.2.1\n"
|
|
126
|
+
"- Deployed version 2.1.3 to production\n"
|
|
127
|
+
"- Met with Alice about Q2 roadmap\n"
|
|
128
|
+
"- Decision: migrate to PostgreSQL 16\n"
|
|
129
|
+
)
|
|
130
|
+
compressed = rule_compress(text)
|
|
131
|
+
# All critical facts should survive rule compression
|
|
132
|
+
assert "10.0.2.1" in compressed
|
|
133
|
+
assert "2.1.3" in compressed
|
|
134
|
+
assert "PostgreSQL" in compressed
|
|
135
|
+
|
|
136
|
+
def test_rule_compress_removes_dupes(self) -> None:
|
|
137
|
+
"""Rule compression removes exact duplicate lines."""
|
|
138
|
+
text = (
|
|
139
|
+
"# Notes\n"
|
|
140
|
+
"- Deploy on AWS\n"
|
|
141
|
+
"- Deploy on AWS\n"
|
|
142
|
+
"- Different thing\n"
|
|
143
|
+
"- Deploy on AWS\n"
|
|
144
|
+
)
|
|
145
|
+
compressed = rule_compress(text)
|
|
146
|
+
assert compressed.count("Deploy on AWS") == 1
|
|
147
|
+
assert "Different thing" in compressed
|
|
148
|
+
|
|
149
|
+
def test_llm_prompt_contains_content(self) -> None:
|
|
150
|
+
"""LLM prompt includes the content to compress."""
|
|
151
|
+
prompt = generate_llm_prompt("My test content here", target_pct=40)
|
|
152
|
+
assert "My test content here" in prompt
|
|
153
|
+
assert "40%" in prompt
|
|
154
|
+
|
|
155
|
+
def test_compression_ratio_reasonable(self, tmp_workspace: Path) -> None:
|
|
156
|
+
"""Rule compression achieves reasonable ratio on real-ish content."""
|
|
157
|
+
mem_file = tmp_workspace / "MEMORY.md"
|
|
158
|
+
text = mem_file.read_text(encoding="utf-8")
|
|
159
|
+
original_tokens = estimate_tokens(text)
|
|
160
|
+
compressed = rule_compress(text)
|
|
161
|
+
compressed_tokens = estimate_tokens(compressed)
|
|
162
|
+
# Rule compression alone shouldn't inflate
|
|
163
|
+
assert compressed_tokens <= original_tokens
|
|
164
|
+
|
|
165
|
+
|
|
166
|
+
class TestTierQuality:
|
|
167
|
+
"""Verify tier generation correctness."""
|
|
168
|
+
|
|
169
|
+
def test_tier_budget_respected(self, tmp_workspace: Path) -> None:
|
|
170
|
+
"""Each tier stays within its token budget."""
|
|
171
|
+
files = [tmp_workspace / "MEMORY.md"]
|
|
172
|
+
result = generate_tiers(files)
|
|
173
|
+
for tier_level, tier in result["tiers"].items():
|
|
174
|
+
assert tier["tokens_used"] <= tier["budget"], (
|
|
175
|
+
f"Tier {tier_level} exceeded budget: "
|
|
176
|
+
f"{tier['tokens_used']} > {tier['budget']}"
|
|
177
|
+
)
|
|
178
|
+
|
|
179
|
+
def test_tier_ordering(self, tmp_workspace: Path) -> None:
|
|
180
|
+
"""Higher tiers include more content."""
|
|
181
|
+
files = [tmp_workspace / "MEMORY.md"]
|
|
182
|
+
result = generate_tiers(files)
|
|
183
|
+
tiers = result["tiers"]
|
|
184
|
+
assert tiers[0]["tokens_used"] <= tiers[1]["tokens_used"]
|
|
185
|
+
assert tiers[1]["tokens_used"] <= tiers[2]["tokens_used"]
|
|
186
|
+
|
|
187
|
+
def test_tier_priority_ordering(self, tmp_workspace: Path) -> None:
|
|
188
|
+
"""Higher-priority sections are included first."""
|
|
189
|
+
files = [tmp_workspace / "MEMORY.md"]
|
|
190
|
+
result = generate_tiers(files)
|
|
191
|
+
for tier in result["tiers"].values():
|
|
192
|
+
if len(tier["sections"]) >= 2:
|
|
193
|
+
priorities = [s["priority"] for s in tier["sections"]]
|
|
194
|
+
# Should be roughly descending (it IS sorted descending)
|
|
195
|
+
assert priorities == sorted(priorities, reverse=True)
|
|
196
|
+
|
|
197
|
+
|
|
198
|
+
class TestCLIScripts:
|
|
199
|
+
"""Test scripts work as standalone CLI tools."""
|
|
200
|
+
|
|
201
|
+
def _run_script(self, script: str, args: list, cwd: str = None) -> subprocess.CompletedProcess:
|
|
202
|
+
script_path = Path(__file__).parent.parent / "scripts" / script
|
|
203
|
+
return subprocess.run(
|
|
204
|
+
[sys.executable, str(script_path)] + args,
|
|
205
|
+
capture_output=True, text=True, timeout=30,
|
|
206
|
+
cwd=cwd,
|
|
207
|
+
)
|
|
208
|
+
|
|
209
|
+
def test_estimate_tokens_cli(self, tmp_workspace: Path) -> None:
|
|
210
|
+
r = self._run_script("estimate_tokens.py", [str(tmp_workspace)])
|
|
211
|
+
assert r.returncode == 0
|
|
212
|
+
assert "tokens" in r.stdout.lower()
|
|
213
|
+
|
|
214
|
+
def test_estimate_tokens_json(self, tmp_workspace: Path) -> None:
|
|
215
|
+
r = self._run_script("estimate_tokens.py", [str(tmp_workspace), "--json"])
|
|
216
|
+
assert r.returncode == 0
|
|
217
|
+
data = json.loads(r.stdout)
|
|
218
|
+
assert "files" in data
|
|
219
|
+
|
|
220
|
+
def test_compress_dry_run(self, tmp_workspace: Path) -> None:
|
|
221
|
+
r = self._run_script("compress_memory.py", [
|
|
222
|
+
str(tmp_workspace / "MEMORY.md"), "--dry-run", "--json"
|
|
223
|
+
])
|
|
224
|
+
assert r.returncode == 0
|
|
225
|
+
|
|
226
|
+
def test_tiers_cli(self, tmp_workspace: Path) -> None:
|
|
227
|
+
r = self._run_script("generate_summary_tiers.py", [str(tmp_workspace)])
|
|
228
|
+
assert r.returncode == 0
|
|
229
|
+
assert "Level" in r.stdout
|
|
230
|
+
|
|
231
|
+
def test_tiers_json(self, tmp_workspace: Path) -> None:
|
|
232
|
+
r = self._run_script("generate_summary_tiers.py", [str(tmp_workspace), "--json"])
|
|
233
|
+
assert r.returncode == 0
|
|
234
|
+
data = json.loads(r.stdout)
|
|
235
|
+
assert "tiers" in data
|
|
236
|
+
|
|
237
|
+
def test_dedup_cli(self, tmp_workspace: Path) -> None:
|
|
238
|
+
r = self._run_script("dedup_memory.py", [str(tmp_workspace)])
|
|
239
|
+
assert r.returncode == 0
|
|
240
|
+
|
|
241
|
+
def test_dedup_json(self, tmp_workspace: Path) -> None:
|
|
242
|
+
r = self._run_script("dedup_memory.py", [str(tmp_workspace), "--json"])
|
|
243
|
+
assert r.returncode == 0
|
|
244
|
+
data = json.loads(r.stdout)
|
|
245
|
+
assert "duplicate_groups" in data
|
|
246
|
+
|
|
247
|
+
def test_nonexistent_path(self) -> None:
|
|
248
|
+
r = self._run_script("estimate_tokens.py", ["/nonexistent/xyz123"])
|
|
249
|
+
assert r.returncode != 0
|