@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,145 @@
|
|
|
1
|
+
"""Tests for Compressed Context Protocol."""
|
|
2
|
+
|
|
3
|
+
import sys
|
|
4
|
+
from pathlib import Path
|
|
5
|
+
|
|
6
|
+
import pytest
|
|
7
|
+
|
|
8
|
+
sys.path.insert(0, str(Path(__file__).resolve().parent.parent / "scripts"))
|
|
9
|
+
from compressed_context import (
|
|
10
|
+
compress_ultra, compress_medium, compress_light,
|
|
11
|
+
compress, compress_with_stats,
|
|
12
|
+
DECOMPRESS_INSTRUCTIONS,
|
|
13
|
+
)
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
SAMPLE_BIO = (
|
|
17
|
+
"Alex is the CTO of ExampleCorp and founder of DataPlatform. "
|
|
18
|
+
"He has 13+ years of crypto quantitative trading experience. "
|
|
19
|
+
"He is based in Los Gatos, CA with offices in Shanghai and Taipei."
|
|
20
|
+
)
|
|
21
|
+
|
|
22
|
+
SAMPLE_TECH = (
|
|
23
|
+
"The infrastructure uses Kubernetes for container orchestration "
|
|
24
|
+
"with continuous integration and deployment pipelines. "
|
|
25
|
+
"The application architecture includes distributed database "
|
|
26
|
+
"systems and monitoring dashboards for production environments."
|
|
27
|
+
)
|
|
28
|
+
|
|
29
|
+
|
|
30
|
+
class TestCompressUltra:
|
|
31
|
+
def test_reduces_length(self):
|
|
32
|
+
result = compress_ultra(SAMPLE_BIO)
|
|
33
|
+
assert len(result) < len(SAMPLE_BIO)
|
|
34
|
+
|
|
35
|
+
def test_preserves_names(self):
|
|
36
|
+
result = compress_ultra(SAMPLE_BIO)
|
|
37
|
+
assert "Alex" in result
|
|
38
|
+
assert "Alex" in result
|
|
39
|
+
assert "ExampleCorp" in result
|
|
40
|
+
|
|
41
|
+
def test_abbreviates(self):
|
|
42
|
+
result = compress_ultra(SAMPLE_TECH)
|
|
43
|
+
# Should use abbreviations
|
|
44
|
+
assert "k8s" in result or "infra" in result or len(result) < len(SAMPLE_TECH) * 0.8
|
|
45
|
+
|
|
46
|
+
def test_empty(self):
|
|
47
|
+
assert compress_ultra("") == ""
|
|
48
|
+
|
|
49
|
+
def test_removes_fillers(self):
|
|
50
|
+
text = "He has extensive experience. In addition, he is skilled."
|
|
51
|
+
result = compress_ultra(text)
|
|
52
|
+
assert "In addition" not in result
|
|
53
|
+
|
|
54
|
+
|
|
55
|
+
class TestCompressMedium:
|
|
56
|
+
def test_less_aggressive(self):
|
|
57
|
+
ultra = compress_ultra(SAMPLE_BIO)
|
|
58
|
+
medium = compress_medium(SAMPLE_BIO)
|
|
59
|
+
# Medium should be longer than ultra (less aggressive)
|
|
60
|
+
assert len(medium) >= len(ultra)
|
|
61
|
+
|
|
62
|
+
def test_reduces_length(self):
|
|
63
|
+
result = compress_medium(SAMPLE_TECH)
|
|
64
|
+
assert len(result) < len(SAMPLE_TECH)
|
|
65
|
+
|
|
66
|
+
|
|
67
|
+
class TestCompressLight:
|
|
68
|
+
def test_minimal_changes(self):
|
|
69
|
+
text = "Simple text with no issues"
|
|
70
|
+
assert compress_light(text) == text
|
|
71
|
+
|
|
72
|
+
def test_cleanup(self):
|
|
73
|
+
text = "Extra spaces here\n\n\n\nToo many lines"
|
|
74
|
+
result = compress_light(text)
|
|
75
|
+
assert " " not in result.replace(" ", " ") # might still have some
|
|
76
|
+
assert "\n\n\n" not in result
|
|
77
|
+
|
|
78
|
+
|
|
79
|
+
class TestCompress:
|
|
80
|
+
def test_returns_dict(self):
|
|
81
|
+
result = compress(SAMPLE_BIO, "ultra")
|
|
82
|
+
assert "compressed" in result
|
|
83
|
+
assert "instructions" in result
|
|
84
|
+
assert result["level"] == "ultra"
|
|
85
|
+
|
|
86
|
+
def test_all_levels(self):
|
|
87
|
+
for level in ["ultra", "medium", "light"]:
|
|
88
|
+
result = compress(SAMPLE_BIO, level)
|
|
89
|
+
assert result["level"] == level
|
|
90
|
+
assert len(result["compressed"]) > 0
|
|
91
|
+
assert len(result["instructions"]) > 0
|
|
92
|
+
|
|
93
|
+
def test_invalid_level(self):
|
|
94
|
+
with pytest.raises(ValueError):
|
|
95
|
+
compress(SAMPLE_BIO, "extreme")
|
|
96
|
+
|
|
97
|
+
def test_instructions_exist(self):
|
|
98
|
+
for level in ["ultra", "medium", "light"]:
|
|
99
|
+
assert level in DECOMPRESS_INSTRUCTIONS
|
|
100
|
+
|
|
101
|
+
|
|
102
|
+
class TestCompressWithStats:
|
|
103
|
+
def test_basic(self):
|
|
104
|
+
stats = compress_with_stats(SAMPLE_BIO, "ultra")
|
|
105
|
+
assert stats["original_tokens"] > 0
|
|
106
|
+
assert stats["compressed_tokens"] > 0
|
|
107
|
+
assert stats["compressed_tokens"] < stats["original_tokens"]
|
|
108
|
+
# Note: reduction_pct includes instruction overhead so may be negative for short texts
|
|
109
|
+
assert "instructions" in stats
|
|
110
|
+
|
|
111
|
+
def test_all_levels(self):
|
|
112
|
+
for level in ["ultra", "medium", "light"]:
|
|
113
|
+
stats = compress_with_stats(SAMPLE_BIO, level)
|
|
114
|
+
assert stats["original_tokens"] > 0
|
|
115
|
+
assert isinstance(stats["reduction_pct"], float)
|
|
116
|
+
|
|
117
|
+
def test_empty(self):
|
|
118
|
+
stats = compress_with_stats("", "ultra")
|
|
119
|
+
assert stats["original_tokens"] == 0
|
|
120
|
+
|
|
121
|
+
def test_unicode(self):
|
|
122
|
+
text = "中文内容测试:这是一个很长的中文段落,包含了很多信息。"
|
|
123
|
+
stats = compress_with_stats(text, "ultra")
|
|
124
|
+
assert stats["compressed_tokens"] > 0
|
|
125
|
+
assert "中文" in stats["compressed"]
|
|
126
|
+
|
|
127
|
+
def test_real_bio_compression(self):
|
|
128
|
+
"""The sample bio should compress the text itself significantly."""
|
|
129
|
+
stats = compress_with_stats(SAMPLE_BIO, "ultra")
|
|
130
|
+
# Compressed text alone should be smaller than original
|
|
131
|
+
assert stats["compressed_tokens"] < stats["original_tokens"]
|
|
132
|
+
# For longer texts, net reduction (including instructions) should be positive
|
|
133
|
+
# For short texts like this, just verify text compression works
|
|
134
|
+
text_reduction = (stats["original_tokens"] - stats["compressed_tokens"]) / stats["original_tokens"] * 100
|
|
135
|
+
assert text_reduction > 5, f"Only {text_reduction:.1f}% text reduction"
|
|
136
|
+
|
|
137
|
+
|
|
138
|
+
class TestCLI:
|
|
139
|
+
def test_file_compress(self, tmp_path):
|
|
140
|
+
"""Test that compress works on a file's content."""
|
|
141
|
+
f = tmp_path / "test.md"
|
|
142
|
+
f.write_text(SAMPLE_BIO)
|
|
143
|
+
text = f.read_text()
|
|
144
|
+
stats = compress_with_stats(text, "ultra")
|
|
145
|
+
assert stats["compressed_tokens"] < stats["original_tokens"]
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
"""Tests for lib.config module."""
|
|
2
|
+
|
|
3
|
+
import json
|
|
4
|
+
from pathlib import Path
|
|
5
|
+
|
|
6
|
+
import pytest
|
|
7
|
+
|
|
8
|
+
from lib.config import MemCompressConfig, load_config, DEFAULT_CONFIG
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
class TestMemCompressConfig:
|
|
12
|
+
def test_defaults(self) -> None:
|
|
13
|
+
cfg = MemCompressConfig()
|
|
14
|
+
assert cfg.chars_per_token == 4
|
|
15
|
+
assert cfg.level0_max_tokens == 200
|
|
16
|
+
|
|
17
|
+
def test_custom_values(self) -> None:
|
|
18
|
+
cfg = MemCompressConfig(chars_per_token=3)
|
|
19
|
+
assert cfg.chars_per_token == 3
|
|
20
|
+
|
|
21
|
+
|
|
22
|
+
class TestLoadConfig:
|
|
23
|
+
def test_no_config_file(self, tmp_path: Path) -> None:
|
|
24
|
+
cfg = load_config(tmp_path)
|
|
25
|
+
assert cfg.chars_per_token == DEFAULT_CONFIG["chars_per_token"]
|
|
26
|
+
|
|
27
|
+
def test_valid_config(self, tmp_path: Path) -> None:
|
|
28
|
+
(tmp_path / "claw-compactor-config.json").write_text(
|
|
29
|
+
json.dumps({"chars_per_token": 3}), encoding="utf-8"
|
|
30
|
+
)
|
|
31
|
+
cfg = load_config(tmp_path)
|
|
32
|
+
assert cfg.chars_per_token == 3
|
|
33
|
+
|
|
34
|
+
def test_invalid_json(self, tmp_path: Path) -> None:
|
|
35
|
+
(tmp_path / "claw-compactor-config.json").write_text("{{bad", encoding="utf-8")
|
|
36
|
+
cfg = load_config(tmp_path)
|
|
37
|
+
assert cfg.chars_per_token == 4
|
|
38
|
+
|
|
39
|
+
def test_non_dict(self, tmp_path: Path) -> None:
|
|
40
|
+
(tmp_path / "claw-compactor-config.json").write_text('["arr"]', encoding="utf-8")
|
|
41
|
+
cfg = load_config(tmp_path)
|
|
42
|
+
assert cfg.chars_per_token == 4
|
|
43
|
+
|
|
44
|
+
def test_unknown_keys_ignored(self, tmp_path: Path) -> None:
|
|
45
|
+
(tmp_path / "claw-compactor-config.json").write_text(
|
|
46
|
+
json.dumps({"chars_per_token": 5, "bogus": 99}), encoding="utf-8"
|
|
47
|
+
)
|
|
48
|
+
cfg = load_config(tmp_path)
|
|
49
|
+
assert cfg.chars_per_token == 5
|
|
50
|
+
|
|
51
|
+
def test_empty_file(self, tmp_path: Path) -> None:
|
|
52
|
+
(tmp_path / "claw-compactor-config.json").write_text("", encoding="utf-8")
|
|
53
|
+
cfg = load_config(tmp_path)
|
|
54
|
+
assert cfg.chars_per_token == 4
|
|
@@ -0,0 +1,124 @@
|
|
|
1
|
+
"""Tests for dedup_memory.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 dedup_memory import run_dedup, format_human, _collect_entries
|
|
11
|
+
from lib.dedup import find_duplicates, merge_duplicates, jaccard, _shingles
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
class TestShingles:
|
|
15
|
+
def test_basic(self):
|
|
16
|
+
assert len(_shingles("the quick brown fox jumps over")) > 0
|
|
17
|
+
|
|
18
|
+
def test_short(self):
|
|
19
|
+
assert len(_shingles("hi")) == 1
|
|
20
|
+
|
|
21
|
+
def test_empty(self):
|
|
22
|
+
assert len(_shingles("")) == 1
|
|
23
|
+
|
|
24
|
+
|
|
25
|
+
class TestJaccard:
|
|
26
|
+
def test_identical(self):
|
|
27
|
+
assert jaccard({1, 2, 3}, {1, 2, 3}) == 1.0
|
|
28
|
+
|
|
29
|
+
def test_disjoint(self):
|
|
30
|
+
assert jaccard({1, 2}, {3, 4}) == 0.0
|
|
31
|
+
|
|
32
|
+
def test_partial(self):
|
|
33
|
+
assert 0 < jaccard({1, 2, 3}, {2, 3, 4}) < 1
|
|
34
|
+
|
|
35
|
+
def test_empty(self):
|
|
36
|
+
assert jaccard(set(), set()) == 1.0
|
|
37
|
+
|
|
38
|
+
def test_one_empty(self):
|
|
39
|
+
assert jaccard({1}, set()) == 0.0
|
|
40
|
+
|
|
41
|
+
|
|
42
|
+
class TestFindDuplicates:
|
|
43
|
+
def test_exact(self):
|
|
44
|
+
entries = ["Install Python 3.10 and configure environment", "Install Python 3.10 and configure environment", "Something different about database"]
|
|
45
|
+
groups = find_duplicates(entries, threshold=0.5)
|
|
46
|
+
assert len(groups) >= 1
|
|
47
|
+
|
|
48
|
+
def test_near(self):
|
|
49
|
+
entries = ["Install Python 3.10 and set up virtual env for dev", "Install Python 3.10 and set up virtual env for prod", "Configure nginx reverse proxy"]
|
|
50
|
+
assert len(find_duplicates(entries, threshold=0.5)) >= 1
|
|
51
|
+
|
|
52
|
+
def test_no_duplicates(self):
|
|
53
|
+
assert len(find_duplicates(["Alpha beta gamma", "One two three four", "日本語テスト"], threshold=0.8)) == 0
|
|
54
|
+
|
|
55
|
+
def test_single(self):
|
|
56
|
+
assert find_duplicates(["one"]) == []
|
|
57
|
+
|
|
58
|
+
def test_empty(self):
|
|
59
|
+
assert find_duplicates([]) == []
|
|
60
|
+
|
|
61
|
+
def test_large(self):
|
|
62
|
+
entries = ["Entry {} with filler content for testing".format(i) for i in range(500)]
|
|
63
|
+
entries += [entries[0], entries[1]]
|
|
64
|
+
assert len(find_duplicates(entries, threshold=0.8)) >= 2
|
|
65
|
+
|
|
66
|
+
def test_unicode(self):
|
|
67
|
+
entries = ["配置数据库连接字符串和环境变量", "配置数据库连接字符串和环境变量", "不同的内容关于部署"]
|
|
68
|
+
assert len(find_duplicates(entries, threshold=0.5)) >= 1
|
|
69
|
+
|
|
70
|
+
|
|
71
|
+
class TestMergeDuplicates:
|
|
72
|
+
def test_no_groups(self):
|
|
73
|
+
assert merge_duplicates(["a", "b"], []) == ["a", "b"]
|
|
74
|
+
|
|
75
|
+
|
|
76
|
+
class TestCollectEntries:
|
|
77
|
+
def test_workspace(self, tmp_workspace):
|
|
78
|
+
entries = _collect_entries(str(tmp_workspace))
|
|
79
|
+
assert len(entries) > 0
|
|
80
|
+
|
|
81
|
+
def test_nonexistent(self):
|
|
82
|
+
with pytest.raises(Exception):
|
|
83
|
+
_collect_entries("/nonexistent/xyz")
|
|
84
|
+
|
|
85
|
+
def test_empty(self, empty_file):
|
|
86
|
+
assert len(_collect_entries(str(empty_file))) == 0
|
|
87
|
+
|
|
88
|
+
def test_unicode(self, unicode_file):
|
|
89
|
+
assert len(_collect_entries(str(unicode_file))) > 0
|
|
90
|
+
|
|
91
|
+
|
|
92
|
+
class TestRunDedup:
|
|
93
|
+
def test_basic(self, tmp_workspace):
|
|
94
|
+
result = run_dedup(str(tmp_workspace))
|
|
95
|
+
assert "total_entries" in result
|
|
96
|
+
assert "duplicate_groups" in result
|
|
97
|
+
|
|
98
|
+
def test_with_dupes(self, duplicate_content):
|
|
99
|
+
result = run_dedup(str(duplicate_content), threshold=0.5)
|
|
100
|
+
assert result["total_entries"] > 0
|
|
101
|
+
|
|
102
|
+
def test_auto_merge(self, duplicate_content):
|
|
103
|
+
result = run_dedup(str(duplicate_content), threshold=0.5, auto_merge=True)
|
|
104
|
+
assert "tokens_before" in result
|
|
105
|
+
|
|
106
|
+
def test_empty(self, tmp_path):
|
|
107
|
+
(tmp_path / "e.md").write_text("", encoding="utf-8")
|
|
108
|
+
assert run_dedup(str(tmp_path))["total_entries"] == 0
|
|
109
|
+
|
|
110
|
+
def test_nonexistent(self):
|
|
111
|
+
with pytest.raises(Exception):
|
|
112
|
+
run_dedup("/nonexistent/xyz")
|
|
113
|
+
|
|
114
|
+
def test_json(self, tmp_workspace):
|
|
115
|
+
assert json.loads(json.dumps(run_dedup(str(tmp_workspace))))
|
|
116
|
+
|
|
117
|
+
|
|
118
|
+
class TestFormatHuman:
|
|
119
|
+
def test_no_dupes(self):
|
|
120
|
+
assert "No duplicates" in format_human({"total_entries": 5, "duplicate_groups": [], "entries_removed": 0})
|
|
121
|
+
|
|
122
|
+
def test_with_dupes(self, duplicate_content):
|
|
123
|
+
output = format_human(run_dedup(str(duplicate_content), threshold=0.3))
|
|
124
|
+
assert "Deduplication Report" in output
|
|
@@ -0,0 +1,327 @@
|
|
|
1
|
+
"""Tests for dictionary-based compression."""
|
|
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 lib.dictionary import (
|
|
11
|
+
build_codebook, compress_text, decompress_text,
|
|
12
|
+
save_codebook, load_codebook, compression_stats,
|
|
13
|
+
_generate_codes, _tokenize_ngrams, _extract_ip_prefixes,
|
|
14
|
+
_extract_path_prefixes,
|
|
15
|
+
)
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
# --- Fixtures ---
|
|
19
|
+
|
|
20
|
+
@pytest.fixture
|
|
21
|
+
def sample_texts():
|
|
22
|
+
"""Realistic memory-style texts with repetition."""
|
|
23
|
+
return [
|
|
24
|
+
"# Server Config\n\n- Gateway IP: 10.0.1.1\n- Node: remote-node at 10.0.1.2\n"
|
|
25
|
+
"- User: example_user\n- Path: /home/user/workspace\n"
|
|
26
|
+
"- NetworkID: abc123network456\n- Token: my-secret-token-2024\n",
|
|
27
|
+
|
|
28
|
+
"# Daily Notes\n\n- Connected to 10.0.1.1 gateway\n"
|
|
29
|
+
"- Deployed on remote-node (10.0.1.2)\n"
|
|
30
|
+
"- User example_user ran backup\n"
|
|
31
|
+
"- Workspace: /home/user/workspace\n"
|
|
32
|
+
"- Using token my-secret-token-2024\n",
|
|
33
|
+
|
|
34
|
+
"# More Notes\n\n- Gateway 10.0.1.1 is stable\n"
|
|
35
|
+
"- remote-node running fine at 10.0.1.2\n"
|
|
36
|
+
"- example_user home: /home/user/workspace\n"
|
|
37
|
+
"- Auth: my-secret-token-2024\n",
|
|
38
|
+
]
|
|
39
|
+
|
|
40
|
+
|
|
41
|
+
@pytest.fixture
|
|
42
|
+
def codebook():
|
|
43
|
+
return {
|
|
44
|
+
"$GW": "10.0.1.1",
|
|
45
|
+
"$JP": "10.0.1.2",
|
|
46
|
+
"$U": "example_user",
|
|
47
|
+
"$WS": "/home/user/workspace",
|
|
48
|
+
"$TK": "my-secret-token-2024",
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
|
|
52
|
+
# --- Code generation ---
|
|
53
|
+
|
|
54
|
+
class TestGenerateCodes:
|
|
55
|
+
def test_count(self):
|
|
56
|
+
codes = _generate_codes(10)
|
|
57
|
+
assert len(codes) == 10
|
|
58
|
+
|
|
59
|
+
def test_uniqueness(self):
|
|
60
|
+
codes = _generate_codes(676)
|
|
61
|
+
assert len(set(codes)) == 676
|
|
62
|
+
|
|
63
|
+
def test_format(self):
|
|
64
|
+
codes = _generate_codes(5)
|
|
65
|
+
for c in codes:
|
|
66
|
+
assert c.startswith('$')
|
|
67
|
+
assert len(c) == 3
|
|
68
|
+
assert c[1:].isalpha() and c[1:].isupper()
|
|
69
|
+
|
|
70
|
+
def test_overflow_to_3char(self):
|
|
71
|
+
codes = _generate_codes(677)
|
|
72
|
+
assert len(codes) == 677
|
|
73
|
+
assert len(codes[-1]) == 4 # $AAA
|
|
74
|
+
|
|
75
|
+
|
|
76
|
+
# --- N-gram extraction ---
|
|
77
|
+
|
|
78
|
+
class TestTokenizeNgrams:
|
|
79
|
+
def test_basic(self):
|
|
80
|
+
ngrams = _tokenize_ngrams("the quick brown fox jumps over the lazy dog")
|
|
81
|
+
assert any("quick brown" in k for k in ngrams)
|
|
82
|
+
|
|
83
|
+
def test_min_length_filter(self):
|
|
84
|
+
ngrams = _tokenize_ngrams("a b c d e f")
|
|
85
|
+
# All ngrams shorter than MIN_PHRASE_LEN should be filtered
|
|
86
|
+
for gram in ngrams:
|
|
87
|
+
assert len(gram) >= 6
|
|
88
|
+
|
|
89
|
+
def test_empty(self):
|
|
90
|
+
assert len(_tokenize_ngrams("")) == 0
|
|
91
|
+
|
|
92
|
+
|
|
93
|
+
# --- IP prefix extraction ---
|
|
94
|
+
|
|
95
|
+
class TestExtractIpPrefixes:
|
|
96
|
+
def test_finds_common_prefix(self):
|
|
97
|
+
texts = [
|
|
98
|
+
"Server at 192.168.1.10 and 192.168.1.20",
|
|
99
|
+
"Also 192.168.1.30 and 10.0.0.1",
|
|
100
|
+
"More at 192.168.1.40",
|
|
101
|
+
]
|
|
102
|
+
prefixes = _extract_ip_prefixes(texts)
|
|
103
|
+
assert any("192.168.1." in p for p in prefixes)
|
|
104
|
+
|
|
105
|
+
def test_no_ips(self):
|
|
106
|
+
assert _extract_ip_prefixes(["no ips here"]) == {}
|
|
107
|
+
|
|
108
|
+
|
|
109
|
+
# --- Path prefix extraction ---
|
|
110
|
+
|
|
111
|
+
class TestExtractPathPrefixes:
|
|
112
|
+
def test_finds_common_path(self):
|
|
113
|
+
texts = [
|
|
114
|
+
"File at /Users/duke/.openclaw/workspace/MEMORY.md",
|
|
115
|
+
"Also /Users/duke/.openclaw/workspace/TOOLS.md",
|
|
116
|
+
"And /Users/duke/.openclaw/workspace/memory/2026-01.md",
|
|
117
|
+
]
|
|
118
|
+
prefixes = _extract_path_prefixes(texts)
|
|
119
|
+
assert any("/Users/duke/.openclaw" in p for p in prefixes)
|
|
120
|
+
|
|
121
|
+
def test_no_paths(self):
|
|
122
|
+
assert _extract_path_prefixes(["no paths"]) == {}
|
|
123
|
+
|
|
124
|
+
|
|
125
|
+
# --- Codebook building ---
|
|
126
|
+
|
|
127
|
+
class TestBuildCodebook:
|
|
128
|
+
def test_builds_from_texts(self, sample_texts):
|
|
129
|
+
cb = build_codebook(sample_texts, min_freq=2)
|
|
130
|
+
assert len(cb) > 0
|
|
131
|
+
# All values should be real phrases
|
|
132
|
+
for code, phrase in cb.items():
|
|
133
|
+
assert code.startswith('$')
|
|
134
|
+
assert len(phrase) >= 6
|
|
135
|
+
|
|
136
|
+
def test_empty_texts(self):
|
|
137
|
+
cb = build_codebook([], min_freq=2)
|
|
138
|
+
assert cb == {}
|
|
139
|
+
|
|
140
|
+
def test_no_frequent_phrases(self):
|
|
141
|
+
cb = build_codebook(["unique text one", "different text two"], min_freq=5)
|
|
142
|
+
assert cb == {}
|
|
143
|
+
|
|
144
|
+
def test_max_entries(self, sample_texts):
|
|
145
|
+
cb = build_codebook(sample_texts, max_entries=3, min_freq=2)
|
|
146
|
+
assert len(cb) <= 3
|
|
147
|
+
|
|
148
|
+
def test_no_overlapping_codes(self, sample_texts):
|
|
149
|
+
cb = build_codebook(sample_texts, min_freq=2)
|
|
150
|
+
codes = list(cb.keys())
|
|
151
|
+
for i, c1 in enumerate(codes):
|
|
152
|
+
for c2 in codes[i+1:]:
|
|
153
|
+
assert c1 != c2
|
|
154
|
+
|
|
155
|
+
|
|
156
|
+
# --- Compression / Decompression ---
|
|
157
|
+
|
|
158
|
+
class TestCompressDecompress:
|
|
159
|
+
def test_basic_compress(self, codebook):
|
|
160
|
+
text = "Gateway at 10.0.1.1 running"
|
|
161
|
+
r = compress_text(text, codebook)
|
|
162
|
+
assert "$GW" in r
|
|
163
|
+
assert "10.0.1.1" not in r
|
|
164
|
+
|
|
165
|
+
def test_basic_decompress(self, codebook):
|
|
166
|
+
compressed = "Gateway at $GW running"
|
|
167
|
+
r = decompress_text(compressed, codebook)
|
|
168
|
+
assert "10.0.1.1" in r
|
|
169
|
+
assert "$GW" not in r
|
|
170
|
+
|
|
171
|
+
def test_roundtrip(self, codebook):
|
|
172
|
+
"""Compression then decompression must be lossless."""
|
|
173
|
+
text = (
|
|
174
|
+
"Connect to 10.0.1.1 as example_user\n"
|
|
175
|
+
"Node 10.0.1.2 is remote-node\n"
|
|
176
|
+
"Workspace: /home/user/workspace\n"
|
|
177
|
+
"Token: my-secret-token-2024\n"
|
|
178
|
+
)
|
|
179
|
+
compressed = compress_text(text, codebook)
|
|
180
|
+
decompressed = decompress_text(compressed, codebook)
|
|
181
|
+
assert decompressed == text
|
|
182
|
+
|
|
183
|
+
def test_roundtrip_no_matches(self, codebook):
|
|
184
|
+
text = "Nothing to compress here."
|
|
185
|
+
assert decompress_text(compress_text(text, codebook), codebook) == text
|
|
186
|
+
|
|
187
|
+
def test_roundtrip_all_matches(self, codebook):
|
|
188
|
+
text = "10.0.1.1 10.0.1.2 example_user"
|
|
189
|
+
assert decompress_text(compress_text(text, codebook), codebook) == text
|
|
190
|
+
|
|
191
|
+
def test_empty_codebook(self):
|
|
192
|
+
assert compress_text("hello", {}) == "hello"
|
|
193
|
+
assert decompress_text("hello", {}) == "hello"
|
|
194
|
+
|
|
195
|
+
def test_empty_text(self, codebook):
|
|
196
|
+
assert compress_text("", codebook) == ""
|
|
197
|
+
assert decompress_text("", codebook) == ""
|
|
198
|
+
|
|
199
|
+
def test_multiple_occurrences(self, codebook):
|
|
200
|
+
text = "IP 10.0.1.1 and again 10.0.1.1"
|
|
201
|
+
compressed = compress_text(text, codebook)
|
|
202
|
+
assert compressed.count("$GW") == 2
|
|
203
|
+
assert decompress_text(compressed, codebook) == text
|
|
204
|
+
|
|
205
|
+
def test_adjacent_codes(self, codebook):
|
|
206
|
+
text = "10.0.1.1example_user"
|
|
207
|
+
compressed = compress_text(text, codebook)
|
|
208
|
+
decompressed = decompress_text(compressed, codebook)
|
|
209
|
+
assert decompressed == text
|
|
210
|
+
|
|
211
|
+
|
|
212
|
+
class TestRoundtripWithBuiltCodebook:
|
|
213
|
+
"""Test that build → compress → decompress is lossless."""
|
|
214
|
+
|
|
215
|
+
def test_full_pipeline(self, sample_texts):
|
|
216
|
+
cb = build_codebook(sample_texts, min_freq=2)
|
|
217
|
+
for text in sample_texts:
|
|
218
|
+
compressed = compress_text(text, cb)
|
|
219
|
+
decompressed = decompress_text(compressed, cb)
|
|
220
|
+
assert decompressed == text, f"Roundtrip failed for text starting with: {text[:50]}"
|
|
221
|
+
|
|
222
|
+
def test_large_corpus(self):
|
|
223
|
+
"""Test with a larger synthetic corpus."""
|
|
224
|
+
base = "Server 192.168.1.{i} is running service-{i} on /opt/app/service-{i}/config"
|
|
225
|
+
texts = [base.format(i=i) for i in range(50)]
|
|
226
|
+
cb = build_codebook(texts, min_freq=3)
|
|
227
|
+
combined = '\n'.join(texts)
|
|
228
|
+
compressed = compress_text(combined, cb)
|
|
229
|
+
decompressed = decompress_text(compressed, cb)
|
|
230
|
+
assert decompressed == combined
|
|
231
|
+
|
|
232
|
+
|
|
233
|
+
# --- Save / Load ---
|
|
234
|
+
|
|
235
|
+
class TestSaveLoadCodebook:
|
|
236
|
+
def test_save_load_roundtrip(self, tmp_path, codebook):
|
|
237
|
+
path = tmp_path / "cb.json"
|
|
238
|
+
save_codebook(codebook, path)
|
|
239
|
+
loaded = load_codebook(path)
|
|
240
|
+
assert loaded == codebook
|
|
241
|
+
|
|
242
|
+
def test_load_nonexistent(self, tmp_path):
|
|
243
|
+
with pytest.raises(FileNotFoundError):
|
|
244
|
+
load_codebook(tmp_path / "nope.json")
|
|
245
|
+
|
|
246
|
+
def test_load_invalid(self, tmp_path):
|
|
247
|
+
path = tmp_path / "bad.json"
|
|
248
|
+
path.write_text('{"not_entries": true}')
|
|
249
|
+
with pytest.raises(ValueError):
|
|
250
|
+
load_codebook(path)
|
|
251
|
+
|
|
252
|
+
def test_save_creates_dirs(self, tmp_path, codebook):
|
|
253
|
+
path = tmp_path / "deep" / "nested" / "cb.json"
|
|
254
|
+
save_codebook(codebook, path)
|
|
255
|
+
assert path.exists()
|
|
256
|
+
|
|
257
|
+
|
|
258
|
+
# --- Stats ---
|
|
259
|
+
|
|
260
|
+
class TestCompressionStats:
|
|
261
|
+
def test_basic(self, codebook):
|
|
262
|
+
original = "10.0.1.1 is the gateway for example_user"
|
|
263
|
+
compressed = compress_text(original, codebook)
|
|
264
|
+
stats = compression_stats(original, compressed, codebook)
|
|
265
|
+
assert stats["gross_reduction_pct"] > 0
|
|
266
|
+
assert stats["codebook_entries"] == len(codebook)
|
|
267
|
+
assert stats["codes_used"] > 0
|
|
268
|
+
|
|
269
|
+
def test_empty(self):
|
|
270
|
+
stats = compression_stats("", "", {})
|
|
271
|
+
assert stats["gross_reduction_pct"] == 0.0
|
|
272
|
+
|
|
273
|
+
|
|
274
|
+
# --- Integration with dictionary_compress.py CLI ---
|
|
275
|
+
|
|
276
|
+
class TestCLICommands:
|
|
277
|
+
def test_build_and_stats(self, tmp_path):
|
|
278
|
+
from dictionary_compress import cmd_build, cmd_stats
|
|
279
|
+
# Create workspace
|
|
280
|
+
(tmp_path / "MEMORY.md").write_text(
|
|
281
|
+
"# Mem\n\n- Server: 192.168.1.100\n- Server: 192.168.1.100\n"
|
|
282
|
+
"- Path: /long/repeated/path/here\n- Path: /long/repeated/path/here\n"
|
|
283
|
+
"- Token: my-long-token-value-2024\n- Token: my-long-token-value-2024\n"
|
|
284
|
+
"- Again server 192.168.1.100 and /long/repeated/path/here\n"
|
|
285
|
+
)
|
|
286
|
+
mem = tmp_path / "memory"
|
|
287
|
+
mem.mkdir()
|
|
288
|
+
(mem / "day1.md").write_text(
|
|
289
|
+
"# Day\n- Used 192.168.1.100\n- At /long/repeated/path/here\n"
|
|
290
|
+
"- Auth: my-long-token-value-2024\n"
|
|
291
|
+
)
|
|
292
|
+
|
|
293
|
+
cb_path = tmp_path / "memory" / ".codebook.json"
|
|
294
|
+
result = cmd_build(tmp_path, cb_path, min_freq=2)
|
|
295
|
+
assert result["codebook_entries"] > 0
|
|
296
|
+
assert cb_path.exists()
|
|
297
|
+
|
|
298
|
+
stats = cmd_stats(tmp_path, cb_path)
|
|
299
|
+
assert stats["codebook_entries"] > 0
|
|
300
|
+
|
|
301
|
+
def test_compress_decompress_roundtrip(self, tmp_path):
|
|
302
|
+
from dictionary_compress import cmd_build, cmd_compress, cmd_decompress
|
|
303
|
+
|
|
304
|
+
original_text = (
|
|
305
|
+
"# Notes\n- IP: 10.20.30.40 is primary\n- IP: 10.20.30.40 backup too\n"
|
|
306
|
+
"- Workspace /home/user/.openclaw/workspace is main\n"
|
|
307
|
+
"- Also /home/user/.openclaw/workspace for backup\n"
|
|
308
|
+
"- Token super-secret-token-2024 used\n"
|
|
309
|
+
"- Again super-secret-token-2024 here\n"
|
|
310
|
+
"- And 10.20.30.40 again\n"
|
|
311
|
+
)
|
|
312
|
+
(tmp_path / "MEMORY.md").write_text(original_text)
|
|
313
|
+
mem = tmp_path / "memory"
|
|
314
|
+
mem.mkdir()
|
|
315
|
+
|
|
316
|
+
cb_path = mem / ".codebook.json"
|
|
317
|
+
cmd_build(tmp_path, cb_path, min_freq=2)
|
|
318
|
+
|
|
319
|
+
# Compress
|
|
320
|
+
cmd_compress(tmp_path, cb_path, dry_run=False)
|
|
321
|
+
compressed = (tmp_path / "MEMORY.md").read_text()
|
|
322
|
+
assert len(compressed) <= len(original_text)
|
|
323
|
+
|
|
324
|
+
# Decompress
|
|
325
|
+
cmd_decompress(tmp_path, cb_path, dry_run=False)
|
|
326
|
+
restored = (tmp_path / "MEMORY.md").read_text()
|
|
327
|
+
assert restored == original_text
|