@ketecode/loom 0.0.0-stage → 0.2.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/LICENSE +21 -0
- package/README.md +616 -2
- package/agents/accessibility-reviewer/AGENT.md +70 -0
- package/agents/accessibility-reviewer/evals/triggers.json +15 -0
- package/agents/agent-evaluator/AGENT.md +74 -0
- package/agents/agent-evaluator/evals/triggers.json +15 -0
- package/agents/architect/AGENT.md +82 -0
- package/agents/architect/evals/triggers.json +17 -0
- package/agents/billing-reviewer/AGENT.md +68 -0
- package/agents/billing-reviewer/evals/triggers.json +16 -0
- package/agents/code-reviewer/AGENT.md +51 -0
- package/agents/code-reviewer/evals/behavior.json +60 -0
- package/agents/code-reviewer/evals/triggers.json +14 -0
- package/agents/code-simplifier/AGENT.md +74 -0
- package/agents/code-simplifier/evals/triggers.json +15 -0
- package/agents/cpp-build-resolver/AGENT.md +73 -0
- package/agents/cpp-build-resolver/evals/triggers.json +16 -0
- package/agents/cpp-reviewer/AGENT.md +59 -0
- package/agents/cpp-reviewer/evals/triggers.json +16 -0
- package/agents/csharp-build-resolver/AGENT.md +84 -0
- package/agents/csharp-build-resolver/evals/triggers.json +17 -0
- package/agents/csharp-reviewer/AGENT.md +88 -0
- package/agents/csharp-reviewer/evals/triggers.json +17 -0
- package/agents/dart-build-resolver/AGENT.md +80 -0
- package/agents/dart-build-resolver/evals/triggers.json +17 -0
- package/agents/dart-reviewer/AGENT.md +66 -0
- package/agents/dart-reviewer/evals/triggers.json +17 -0
- package/agents/database-reviewer/AGENT.md +72 -0
- package/agents/database-reviewer/evals/triggers.json +16 -0
- package/agents/django-reviewer/AGENT.md +61 -0
- package/agents/django-reviewer/evals/triggers.json +15 -0
- package/agents/doc-updater/AGENT.md +92 -0
- package/agents/doc-updater/evals/triggers.json +14 -0
- package/agents/e2e-runner/AGENT.md +88 -0
- package/agents/e2e-runner/evals/triggers.json +16 -0
- package/agents/fastapi-reviewer/AGENT.md +63 -0
- package/agents/fastapi-reviewer/evals/triggers.json +15 -0
- package/agents/flutter-reviewer/AGENT.md +70 -0
- package/agents/flutter-reviewer/evals/triggers.json +15 -0
- package/agents/fsharp-build-resolver/AGENT.md +81 -0
- package/agents/fsharp-build-resolver/evals/triggers.json +15 -0
- package/agents/fsharp-reviewer/AGENT.md +77 -0
- package/agents/fsharp-reviewer/evals/triggers.json +15 -0
- package/agents/go-build-resolver/AGENT.md +85 -0
- package/agents/go-build-resolver/evals/triggers.json +16 -0
- package/agents/go-reviewer/AGENT.md +66 -0
- package/agents/go-reviewer/evals/triggers.json +16 -0
- package/agents/healthcare-reviewer/AGENT.md +65 -0
- package/agents/healthcare-reviewer/evals/triggers.json +16 -0
- package/agents/i18n-reviewer/AGENT.md +64 -0
- package/agents/i18n-reviewer/evals/triggers.json +16 -0
- package/agents/inbox-triager/AGENT.md +98 -0
- package/agents/inbox-triager/evals/triggers.json +16 -0
- package/agents/infra-reviewer/AGENT.md +93 -0
- package/agents/infra-reviewer/evals/triggers.json +15 -0
- package/agents/java-build-resolver/AGENT.md +82 -0
- package/agents/java-build-resolver/evals/triggers.json +16 -0
- package/agents/java-reviewer/AGENT.md +64 -0
- package/agents/java-reviewer/evals/triggers.json +16 -0
- package/agents/kotlin-build-resolver/AGENT.md +89 -0
- package/agents/kotlin-build-resolver/evals/triggers.json +16 -0
- package/agents/kotlin-reviewer/AGENT.md +75 -0
- package/agents/kotlin-reviewer/evals/triggers.json +16 -0
- package/agents/mle-reviewer/AGENT.md +68 -0
- package/agents/mle-reviewer/evals/triggers.json +16 -0
- package/agents/network-config-reviewer/AGENT.md +68 -0
- package/agents/network-config-reviewer/evals/triggers.json +17 -0
- package/agents/payments-reviewer/AGENT.md +64 -0
- package/agents/payments-reviewer/evals/triggers.json +16 -0
- package/agents/performance-optimizer/AGENT.md +86 -0
- package/agents/performance-optimizer/evals/triggers.json +16 -0
- package/agents/perl-build-resolver/AGENT.md +84 -0
- package/agents/perl-build-resolver/evals/triggers.json +15 -0
- package/agents/perl-reviewer/AGENT.md +77 -0
- package/agents/perl-reviewer/evals/triggers.json +15 -0
- package/agents/php-build-resolver/AGENT.md +88 -0
- package/agents/php-build-resolver/evals/triggers.json +16 -0
- package/agents/php-reviewer/AGENT.md +61 -0
- package/agents/php-reviewer/evals/triggers.json +15 -0
- package/agents/planner/AGENT.md +75 -0
- package/agents/planner/evals/triggers.json +17 -0
- package/agents/pr-test-analyzer/AGENT.md +82 -0
- package/agents/pr-test-analyzer/evals/triggers.json +16 -0
- package/agents/python-build-resolver/AGENT.md +87 -0
- package/agents/python-build-resolver/evals/triggers.json +16 -0
- package/agents/python-reviewer/AGENT.md +63 -0
- package/agents/python-reviewer/evals/triggers.json +15 -0
- package/agents/rag-reviewer/AGENT.md +71 -0
- package/agents/rag-reviewer/evals/triggers.json +16 -0
- package/agents/react-reviewer/AGENT.md +70 -0
- package/agents/react-reviewer/evals/triggers.json +16 -0
- package/agents/refactor-cleaner/AGENT.md +82 -0
- package/agents/refactor-cleaner/evals/triggers.json +16 -0
- package/agents/ruby-build-resolver/AGENT.md +93 -0
- package/agents/ruby-build-resolver/evals/triggers.json +16 -0
- package/agents/ruby-reviewer/AGENT.md +62 -0
- package/agents/ruby-reviewer/evals/triggers.json +16 -0
- package/agents/rust-build-resolver/AGENT.md +98 -0
- package/agents/rust-build-resolver/evals/triggers.json +16 -0
- package/agents/rust-reviewer/AGENT.md +78 -0
- package/agents/rust-reviewer/evals/triggers.json +15 -0
- package/agents/security-reviewer/AGENT.md +84 -0
- package/agents/security-reviewer/evals/triggers.json +16 -0
- package/agents/silent-failure-hunter/AGENT.md +66 -0
- package/agents/silent-failure-hunter/evals/triggers.json +16 -0
- package/agents/solidity-reviewer/AGENT.md +70 -0
- package/agents/solidity-reviewer/evals/triggers.json +16 -0
- package/agents/spec-reviewer/AGENT.md +95 -0
- package/agents/spec-reviewer/evals/behavior.json +57 -0
- package/agents/spec-reviewer/evals/triggers.json +16 -0
- package/agents/swift-build-resolver/AGENT.md +85 -0
- package/agents/swift-build-resolver/evals/triggers.json +15 -0
- package/agents/swift-reviewer/AGENT.md +75 -0
- package/agents/swift-reviewer/evals/triggers.json +15 -0
- package/agents/task-implementer/AGENT.md +89 -0
- package/agents/task-implementer/evals/behavior.json +47 -0
- package/agents/task-implementer/evals/triggers.json +16 -0
- package/agents/typescript-build-resolver/AGENT.md +76 -0
- package/agents/typescript-build-resolver/evals/triggers.json +15 -0
- package/agents/typescript-reviewer/AGENT.md +76 -0
- package/agents/typescript-reviewer/evals/triggers.json +15 -0
- package/agents/vue-reviewer/AGENT.md +75 -0
- package/agents/vue-reviewer/evals/triggers.json +15 -0
- package/bin/kete-loom.js +723 -0
- package/commands/aside.md +19 -0
- package/commands/brainstorm.md +25 -0
- package/commands/build-fix.md +26 -0
- package/commands/campaign.md +19 -0
- package/commands/changelog.md +36 -0
- package/commands/checkpoint.md +26 -0
- package/commands/codemap.md +25 -0
- package/commands/commit.md +26 -0
- package/commands/debug.md +27 -0
- package/commands/deps-audit.md +32 -0
- package/commands/dual-review.md +34 -0
- package/commands/epic-decompose.md +21 -0
- package/commands/explain.md +37 -0
- package/commands/feature-dev.md +23 -0
- package/commands/finish-branch.md +26 -0
- package/commands/fix-bug.md +38 -0
- package/commands/hookify.md +23 -0
- package/commands/i18n-check.md +39 -0
- package/commands/issue-sync.md +22 -0
- package/commands/jira.md +19 -0
- package/commands/learn.md +23 -0
- package/commands/loom.md +21 -0
- package/commands/loop.md +20 -0
- package/commands/model-route.md +27 -0
- package/commands/onboard.md +35 -0
- package/commands/orchestrate.md +21 -0
- package/commands/plan-feature.md +36 -0
- package/commands/postmortem.md +42 -0
- package/commands/pr-describe.md +39 -0
- package/commands/pr.md +22 -0
- package/commands/prd.md +41 -0
- package/commands/production-readiness.md +45 -0
- package/commands/project-init.md +21 -0
- package/commands/refactor-clean.md +24 -0
- package/commands/resume-session.md +22 -0
- package/commands/review.md +35 -0
- package/commands/save-session.md +37 -0
- package/commands/security-scan.md +32 -0
- package/commands/sessions.md +21 -0
- package/commands/skill-create.md +21 -0
- package/commands/tdd.md +36 -0
- package/commands/test-coverage.md +24 -0
- package/commands/threat-model.md +36 -0
- package/commands/update-docs.md +25 -0
- package/commands/usage-report.md +43 -0
- package/commands/verify.md +21 -0
- package/hooks/block-dangerous-commands/HOOK.md +30 -0
- package/hooks/block-dangerous-commands/cases.json +50 -0
- package/hooks/block-dangerous-commands/hook.js +75 -0
- package/hooks/block-foreground-servers/HOOK.md +34 -0
- package/hooks/block-foreground-servers/cases.json +31 -0
- package/hooks/block-foreground-servers/hook.js +41 -0
- package/hooks/block-no-verify/HOOK.md +25 -0
- package/hooks/block-no-verify/cases.json +30 -0
- package/hooks/block-no-verify/hook.js +43 -0
- package/hooks/capture-lessons/HOOK.md +24 -0
- package/hooks/capture-lessons/hook.js +48 -0
- package/hooks/format-on-edit/HOOK.md +24 -0
- package/hooks/format-on-edit/hook.js +89 -0
- package/hooks/guard-secrets/HOOK.md +19 -0
- package/hooks/guard-secrets/cases.json +110 -0
- package/hooks/guard-secrets/hook.js +44 -0
- package/hooks/load-session-context/HOOK.md +20 -0
- package/hooks/load-session-context/hook.js +56 -0
- package/hooks/notify-on-stop/HOOK.md +25 -0
- package/hooks/notify-on-stop/hook.js +27 -0
- package/hooks/protect-files/HOOK.md +24 -0
- package/hooks/protect-files/cases.json +27 -0
- package/hooks/protect-files/hook.js +39 -0
- package/hooks/protect-lint-config/HOOK.md +29 -0
- package/hooks/protect-lint-config/cases.json +18 -0
- package/hooks/protect-lint-config/fixtures/.eslintrc.json +1 -0
- package/hooks/protect-lint-config/fixtures/.golangci.yml +1 -0
- package/hooks/protect-lint-config/fixtures/.prettierrc +1 -0
- package/hooks/protect-lint-config/fixtures/.rubocop.yml +1 -0
- package/hooks/protect-lint-config/fixtures/biome.json +1 -0
- package/hooks/protect-lint-config/fixtures/eslint.config.mjs +1 -0
- package/hooks/protect-lint-config/fixtures/ruff.toml +1 -0
- package/hooks/protect-lint-config/hook.js +25 -0
- package/hooks/read-before-edit/HOOK.md +26 -0
- package/hooks/read-before-edit/cases.json +15 -0
- package/hooks/read-before-edit/hook.js +50 -0
- package/hooks/run.js +148 -0
- package/hooks/verify-before-stop/HOOK.md +32 -0
- package/hooks/verify-before-stop/hook.js +70 -0
- package/mcp/atlassian.json +11 -0
- package/mcp/chrome-devtools.json +18 -0
- package/mcp/clickhouse.json +11 -0
- package/mcp/cloudflare.json +11 -0
- package/mcp/context7.json +11 -0
- package/mcp/exa.json +11 -0
- package/mcp/fetch.json +17 -0
- package/mcp/figma.json +11 -0
- package/mcp/firecrawl.json +11 -0
- package/mcp/git.json +17 -0
- package/mcp/github.json +11 -0
- package/mcp/linear.json +11 -0
- package/mcp/memory.json +18 -0
- package/mcp/notion.json +11 -0
- package/mcp/playwright.json +18 -0
- package/mcp/sentry.json +11 -0
- package/mcp/stripe.json +11 -0
- package/mcp/supabase.json +11 -0
- package/mcp/time.json +17 -0
- package/mcp/vercel.json +11 -0
- package/package.json +61 -4
- package/profiles.json +214 -0
- package/rules/common.md +21 -0
- package/rules/cpp.md +29 -0
- package/rules/csharp.md +25 -0
- package/rules/dart.md +29 -0
- package/rules/fsharp.md +28 -0
- package/rules/git.md +26 -0
- package/rules/go.md +29 -0
- package/rules/java.md +29 -0
- package/rules/kotlin.md +27 -0
- package/rules/perl.md +26 -0
- package/rules/php.md +28 -0
- package/rules/python.md +30 -0
- package/rules/ruby.md +27 -0
- package/rules/rust.md +26 -0
- package/rules/security.md +29 -0
- package/rules/swift.md +28 -0
- package/rules/testing.md +25 -0
- package/rules/typescript.md +29 -0
- package/rules/use-skills.md +23 -0
- package/schemas/skill-frontmatter.schema.json +52 -0
- package/scripts/lib/audit.js +96 -0
- package/scripts/lib/behavior.js +52 -0
- package/scripts/lib/frontmatter.js +65 -0
- package/scripts/lib/hooks-install.js +294 -0
- package/scripts/lib/i18n.js +51 -0
- package/scripts/lib/inventory.js +85 -0
- package/scripts/lib/lint.js +180 -0
- package/scripts/lib/mcp-install.js +288 -0
- package/scripts/lib/profiles.js +128 -0
- package/scripts/lib/render.js +92 -0
- package/scripts/lib/rules-install.js +118 -0
- package/scripts/lib/skills.js +87 -0
- package/scripts/lib/targets.js +123 -0
- package/skills/accounting-api-integration/SKILL.md +81 -0
- package/skills/accounting-api-integration/evals/triggers.json +17 -0
- package/skills/accounting-api-integration/references/quickbooks.md +48 -0
- package/skills/accounting-api-integration/references/xero.md +45 -0
- package/skills/agent-failure-debugging/SKILL.md +92 -0
- package/skills/agent-failure-debugging/evals/triggers.json +16 -0
- package/skills/agent-harness-design/SKILL.md +125 -0
- package/skills/agent-harness-design/evals/triggers.json +21 -0
- package/skills/agent-outbound-messaging/SKILL.md +92 -0
- package/skills/agent-outbound-messaging/evals/triggers.json +16 -0
- package/skills/agent-security/SKILL.md +117 -0
- package/skills/agent-security/evals/triggers.json +16 -0
- package/skills/agent-security/references/host-configs.md +37 -0
- package/skills/ai-media-generation/SKILL.md +89 -0
- package/skills/ai-media-generation/evals/triggers.json +16 -0
- package/skills/ai-media-generation/references/job-pipeline.md +76 -0
- package/skills/angular-patterns/SKILL.md +122 -0
- package/skills/angular-patterns/evals/triggers.json +16 -0
- package/skills/api-client-integration/SKILL.md +86 -0
- package/skills/api-client-integration/evals/triggers.json +16 -0
- package/skills/api-client-integration/references/resilience.md +57 -0
- package/skills/api-design/SKILL.md +96 -0
- package/skills/api-design/evals/triggers.json +18 -0
- package/skills/api-design/references/conventions.md +133 -0
- package/skills/architecture-decision-records/SKILL.md +98 -0
- package/skills/architecture-decision-records/evals/triggers.json +17 -0
- package/skills/article-writing/SKILL.md +108 -0
- package/skills/article-writing/evals/triggers.json +16 -0
- package/skills/aspnet-core-patterns/SKILL.md +149 -0
- package/skills/aspnet-core-patterns/evals/triggers.json +16 -0
- package/skills/auth-patterns/SKILL.md +104 -0
- package/skills/auth-patterns/evals/triggers.json +17 -0
- package/skills/auth-patterns/references/oauth-oidc.md +64 -0
- package/skills/autonomous-loops/SKILL.md +99 -0
- package/skills/autonomous-loops/evals/triggers.json +14 -0
- package/skills/aws-patterns/SKILL.md +91 -0
- package/skills/aws-patterns/evals/triggers.json +16 -0
- package/skills/azure-patterns/SKILL.md +86 -0
- package/skills/azure-patterns/evals/triggers.json +16 -0
- package/skills/benchmark-methodology/SKILL.md +88 -0
- package/skills/benchmark-methodology/evals/triggers.json +16 -0
- package/skills/benchmark-methodology/references/language-harnesses.md +130 -0
- package/skills/bgp-diagnostics/SKILL.md +84 -0
- package/skills/bgp-diagnostics/evals/triggers.json +18 -0
- package/skills/bgp-diagnostics/references/bgp-reference.md +81 -0
- package/skills/bioinformatics-workflows/SKILL.md +108 -0
- package/skills/bioinformatics-workflows/evals/triggers.json +16 -0
- package/skills/bioinformatics-workflows/references/commands.md +71 -0
- package/skills/bioinformatics-workflows/references/formats.md +24 -0
- package/skills/bioinformatics-workflows/references/workflow-managers.md +107 -0
- package/skills/blender-automation/SKILL.md +100 -0
- package/skills/blender-automation/evals/triggers.json +16 -0
- package/skills/blender-automation/references/batch-and-render.md +77 -0
- package/skills/blender-automation/references/bpy-inspection.md +91 -0
- package/skills/blender-automation/references/rig-and-retarget-checks.md +23 -0
- package/skills/brand-strategy/SKILL.md +83 -0
- package/skills/brand-strategy/evals/triggers.json +16 -0
- package/skills/brand-voice/SKILL.md +112 -0
- package/skills/brand-voice/evals/triggers.json +16 -0
- package/skills/browser-qa/SKILL.md +99 -0
- package/skills/browser-qa/evals/triggers.json +16 -0
- package/skills/bun-runtime/SKILL.md +93 -0
- package/skills/bun-runtime/evals/triggers.json +16 -0
- package/skills/change-impact-analysis/SKILL.md +89 -0
- package/skills/change-impact-analysis/evals/triggers.json +16 -0
- package/skills/change-impact-analysis/references/graph-commands.md +28 -0
- package/skills/cisco-ios-config/SKILL.md +101 -0
- package/skills/cisco-ios-config/evals/triggers.json +18 -0
- package/skills/cisco-ios-config/references/verification.md +63 -0
- package/skills/clickhouse-patterns/SKILL.md +101 -0
- package/skills/clickhouse-patterns/evals/triggers.json +18 -0
- package/skills/clickhouse-patterns/references/engines-and-views.md +138 -0
- package/skills/clinical-decision-support/SKILL.md +90 -0
- package/skills/clinical-decision-support/evals/triggers.json +16 -0
- package/skills/clinical-decision-support/references/cds-hooks.md +76 -0
- package/skills/clinical-decision-support/references/regulatory-boundaries.md +37 -0
- package/skills/code-tour/SKILL.md +97 -0
- package/skills/code-tour/evals/triggers.json +14 -0
- package/skills/codebase-onboarding/SKILL.md +112 -0
- package/skills/codebase-onboarding/evals/triggers.json +14 -0
- package/skills/cold-outreach-sequences/SKILL.md +90 -0
- package/skills/cold-outreach-sequences/evals/triggers.json +16 -0
- package/skills/content-repurposing/SKILL.md +82 -0
- package/skills/content-repurposing/evals/triggers.json +16 -0
- package/skills/context-budget/SKILL.md +84 -0
- package/skills/context-budget/evals/triggers.json +14 -0
- package/skills/contract-drafting/SKILL.md +96 -0
- package/skills/contract-drafting/evals/triggers.json +16 -0
- package/skills/contract-drafting/references/term-sheets.md +68 -0
- package/skills/contract-first-development/SKILL.md +86 -0
- package/skills/contract-first-development/evals/triggers.json +16 -0
- package/skills/contract-first-development/references/tooling.md +46 -0
- package/skills/conventional-commits/SKILL.md +144 -0
- package/skills/conventional-commits/evals/triggers.json +16 -0
- package/skills/cpp-patterns/SKILL.md +129 -0
- package/skills/cpp-patterns/evals/triggers.json +16 -0
- package/skills/cpp-patterns/references/cmake-and-tooling.md +88 -0
- package/skills/cpp-patterns/references/undefined-behaviour.md +75 -0
- package/skills/cpp-testing/SKILL.md +131 -0
- package/skills/cpp-testing/evals/triggers.json +16 -0
- package/skills/csharp-patterns/SKILL.md +110 -0
- package/skills/csharp-patterns/evals/triggers.json +17 -0
- package/skills/csharp-patterns/references/analyzers.md +59 -0
- package/skills/csharp-testing/SKILL.md +85 -0
- package/skills/csharp-testing/evals/triggers.json +17 -0
- package/skills/csharp-testing/references/integration-tests.md +77 -0
- package/skills/css-architecture/SKILL.md +143 -0
- package/skills/css-architecture/evals/triggers.json +16 -0
- package/skills/customs-trade-compliance/SKILL.md +95 -0
- package/skills/customs-trade-compliance/evals/triggers.json +16 -0
- package/skills/customs-trade-compliance/references/incoterms-2020.md +42 -0
- package/skills/dart-patterns/SKILL.md +157 -0
- package/skills/dart-patterns/evals/triggers.json +18 -0
- package/skills/dart-testing/SKILL.md +164 -0
- package/skills/dart-testing/evals/triggers.json +18 -0
- package/skills/data-analysis-notebooks/SKILL.md +113 -0
- package/skills/data-analysis-notebooks/evals/triggers.json +16 -0
- package/skills/data-analysis-notebooks/references/dataframe-pitfalls.md +49 -0
- package/skills/data-analysis-notebooks/references/statistics-pitfalls.md +24 -0
- package/skills/data-pipelines/SKILL.md +90 -0
- package/skills/data-pipelines/evals/triggers.json +16 -0
- package/skills/data-pipelines/references/orchestrators.md +64 -0
- package/skills/database-migrations/SKILL.md +102 -0
- package/skills/database-migrations/evals/triggers.json +16 -0
- package/skills/database-migrations/references/recipes.md +98 -0
- package/skills/database-migrations/references/tools.md +21 -0
- package/skills/dbt-patterns/SKILL.md +96 -0
- package/skills/dbt-patterns/evals/triggers.json +16 -0
- package/skills/dbt-patterns/references/yaml-examples.md +114 -0
- package/skills/decision-council/SKILL.md +98 -0
- package/skills/decision-council/evals/triggers.json +16 -0
- package/skills/deep-research/SKILL.md +107 -0
- package/skills/deep-research/evals/triggers.json +14 -0
- package/skills/dependency-audit/SKILL.md +103 -0
- package/skills/dependency-audit/evals/triggers.json +16 -0
- package/skills/dependency-audit/references/tools.md +124 -0
- package/skills/deployment-strategies/SKILL.md +108 -0
- package/skills/deployment-strategies/evals/triggers.json +16 -0
- package/skills/design-brainstorming/SKILL.md +132 -0
- package/skills/design-brainstorming/evals/behavior.json +55 -0
- package/skills/design-brainstorming/evals/triggers.json +16 -0
- package/skills/design-brainstorming/references/visual-mockups.md +34 -0
- package/skills/desktop-app-testing/SKILL.md +104 -0
- package/skills/desktop-app-testing/evals/triggers.json +16 -0
- package/skills/desktop-app-testing/references/drivers.md +81 -0
- package/skills/django-patterns/SKILL.md +123 -0
- package/skills/django-patterns/evals/triggers.json +16 -0
- package/skills/docker-patterns/SKILL.md +132 -0
- package/skills/docker-patterns/evals/triggers.json +16 -0
- package/skills/docker-patterns/references/dockerfiles.md +105 -0
- package/skills/document-processing/SKILL.md +100 -0
- package/skills/document-processing/evals/triggers.json +17 -0
- package/skills/document-processing/references/extraction-and-ocr.md +71 -0
- package/skills/document-processing/references/forms-and-conversion.md +69 -0
- package/skills/document-processing/references/redaction.md +61 -0
- package/skills/e2e-testing-playwright/SKILL.md +94 -0
- package/skills/e2e-testing-playwright/evals/triggers.json +16 -0
- package/skills/e2e-testing-playwright/references/config-and-ci.md +129 -0
- package/skills/ef-core-patterns/SKILL.md +117 -0
- package/skills/ef-core-patterns/evals/triggers.json +16 -0
- package/skills/email-deliverability/SKILL.md +99 -0
- package/skills/email-deliverability/evals/triggers.json +17 -0
- package/skills/email-deliverability/references/dns-records.md +85 -0
- package/skills/energy-procurement/SKILL.md +106 -0
- package/skills/energy-procurement/evals/triggers.json +16 -0
- package/skills/error-handling-patterns/SKILL.md +112 -0
- package/skills/error-handling-patterns/evals/triggers.json +18 -0
- package/skills/error-handling-patterns/references/language-idioms.md +49 -0
- package/skills/estimation-and-scoping/SKILL.md +97 -0
- package/skills/estimation-and-scoping/evals/triggers.json +14 -0
- package/skills/evm-dapp-integration/SKILL.md +73 -0
- package/skills/evm-dapp-integration/evals/triggers.json +16 -0
- package/skills/fastapi-patterns/SKILL.md +127 -0
- package/skills/fastapi-patterns/evals/triggers.json +16 -0
- package/skills/ffmpeg-media-processing/SKILL.md +94 -0
- package/skills/ffmpeg-media-processing/evals/triggers.json +16 -0
- package/skills/ffmpeg-media-processing/references/recipes.md +112 -0
- package/skills/fhir-integration/SKILL.md +81 -0
- package/skills/fhir-integration/evals/triggers.json +16 -0
- package/skills/fhir-integration/references/search-and-bundles.md +73 -0
- package/skills/fhir-integration/references/smart-on-fhir.md +50 -0
- package/skills/finishing-a-branch/SKILL.md +127 -0
- package/skills/finishing-a-branch/evals/behavior.json +49 -0
- package/skills/finishing-a-branch/evals/triggers.json +16 -0
- package/skills/flask-patterns/SKILL.md +132 -0
- package/skills/flask-patterns/evals/triggers.json +16 -0
- package/skills/flutter-patterns/SKILL.md +99 -0
- package/skills/flutter-patterns/evals/triggers.json +16 -0
- package/skills/flutterwave-integration/SKILL.md +75 -0
- package/skills/flutterwave-integration/evals/triggers.json +16 -0
- package/skills/flutterwave-integration/references/api.md +73 -0
- package/skills/flutterwave-integration/references/webhooks.md +49 -0
- package/skills/freight-carrier-management/SKILL.md +107 -0
- package/skills/freight-carrier-management/evals/triggers.json +16 -0
- package/skills/fsharp-patterns/SKILL.md +133 -0
- package/skills/fsharp-patterns/evals/triggers.json +16 -0
- package/skills/fsharp-testing/SKILL.md +136 -0
- package/skills/fsharp-testing/evals/triggers.json +16 -0
- package/skills/gcp-patterns/SKILL.md +86 -0
- package/skills/gcp-patterns/evals/triggers.json +16 -0
- package/skills/git-workflow/SKILL.md +114 -0
- package/skills/git-workflow/evals/triggers.json +16 -0
- package/skills/git-worktrees/SKILL.md +130 -0
- package/skills/git-worktrees/evals/behavior.json +56 -0
- package/skills/git-worktrees/evals/triggers.json +16 -0
- package/skills/github-actions-ci/SKILL.md +117 -0
- package/skills/github-actions-ci/evals/triggers.json +16 -0
- package/skills/github-api-automation/SKILL.md +101 -0
- package/skills/github-api-automation/evals/triggers.json +17 -0
- package/skills/go-patterns/SKILL.md +118 -0
- package/skills/go-patterns/evals/triggers.json +17 -0
- package/skills/go-patterns/references/concurrency.md +162 -0
- package/skills/go-testing/SKILL.md +154 -0
- package/skills/go-testing/evals/triggers.json +17 -0
- package/skills/google-workspace-integration/SKILL.md +65 -0
- package/skills/google-workspace-integration/evals/triggers.json +17 -0
- package/skills/google-workspace-integration/references/api.md +121 -0
- package/skills/harmonyos-arkts/SKILL.md +117 -0
- package/skills/harmonyos-arkts/evals/triggers.json +16 -0
- package/skills/harmonyos-arkts/references/build-errors.md +42 -0
- package/skills/hexagonal-architecture/SKILL.md +89 -0
- package/skills/hexagonal-architecture/evals/triggers.json +17 -0
- package/skills/hipaa-compliance/SKILL.md +91 -0
- package/skills/hipaa-compliance/evals/triggers.json +18 -0
- package/skills/hipaa-compliance/references/safeguards.md +68 -0
- package/skills/hl7v2-integration/SKILL.md +69 -0
- package/skills/hl7v2-integration/evals/triggers.json +16 -0
- package/skills/hl7v2-integration/references/messages-and-ack.md +78 -0
- package/skills/homelab-network-setup/SKILL.md +125 -0
- package/skills/homelab-network-setup/evals/triggers.json +18 -0
- package/skills/homelab-network-setup/references/firewall-and-dns.md +45 -0
- package/skills/homelab-network-setup/references/wireguard.md +72 -0
- package/skills/hubtel-integration/SKILL.md +77 -0
- package/skills/hubtel-integration/evals/triggers.json +16 -0
- package/skills/hubtel-integration/references/api.md +92 -0
- package/skills/i18n-localization/SKILL.md +114 -0
- package/skills/i18n-localization/evals/triggers.json +16 -0
- package/skills/i18n-localization/references/libraries.md +52 -0
- package/skills/implementation-plans/SKILL.md +117 -0
- package/skills/implementation-plans/evals/behavior.json +54 -0
- package/skills/implementation-plans/evals/triggers.json +16 -0
- package/skills/incident-postmortem/SKILL.md +118 -0
- package/skills/incident-postmortem/evals/triggers.json +14 -0
- package/skills/inventory-demand-planning/SKILL.md +89 -0
- package/skills/inventory-demand-planning/evals/triggers.json +16 -0
- package/skills/inventory-demand-planning/references/formulas.md +62 -0
- package/skills/investor-materials/SKILL.md +127 -0
- package/skills/investor-materials/evals/triggers.json +16 -0
- package/skills/investor-materials/references/templates.md +74 -0
- package/skills/invoicing-and-tax/SKILL.md +84 -0
- package/skills/invoicing-and-tax/evals/triggers.json +17 -0
- package/skills/invoicing-and-tax/references/e-invoicing.md +24 -0
- package/skills/invoicing-and-tax/references/invoice-fields.md +38 -0
- package/skills/invoicing-and-tax/references/rounding.md +26 -0
- package/skills/ios-platform-features/SKILL.md +99 -0
- package/skills/ios-platform-features/evals/triggers.json +16 -0
- package/skills/ios-platform-features/references/foundation-models.md +90 -0
- package/skills/java-patterns/SKILL.md +141 -0
- package/skills/java-patterns/evals/triggers.json +17 -0
- package/skills/java-testing/SKILL.md +142 -0
- package/skills/java-testing/evals/triggers.json +16 -0
- package/skills/jetpack-compose-patterns/SKILL.md +88 -0
- package/skills/jetpack-compose-patterns/evals/triggers.json +16 -0
- package/skills/jira-integration/SKILL.md +92 -0
- package/skills/jira-integration/evals/triggers.json +17 -0
- package/skills/jpa-hibernate/SKILL.md +92 -0
- package/skills/jpa-hibernate/evals/triggers.json +18 -0
- package/skills/jpa-hibernate/references/mapping.md +99 -0
- package/skills/jvm-sql-mappers/SKILL.md +98 -0
- package/skills/jvm-sql-mappers/evals/triggers.json +16 -0
- package/skills/jvm-sql-mappers/references/examples.md +129 -0
- package/skills/kotlin-multiplatform/SKILL.md +97 -0
- package/skills/kotlin-multiplatform/evals/triggers.json +16 -0
- package/skills/kotlin-patterns/SKILL.md +128 -0
- package/skills/kotlin-patterns/evals/triggers.json +16 -0
- package/skills/kotlin-testing/SKILL.md +117 -0
- package/skills/kotlin-testing/evals/triggers.json +16 -0
- package/skills/ktor-patterns/SKILL.md +135 -0
- package/skills/ktor-patterns/evals/triggers.json +18 -0
- package/skills/kubernetes-patterns/SKILL.md +106 -0
- package/skills/kubernetes-patterns/evals/triggers.json +16 -0
- package/skills/kubernetes-patterns/references/manifests.md +115 -0
- package/skills/laravel-patterns/SKILL.md +136 -0
- package/skills/laravel-patterns/evals/triggers.json +16 -0
- package/skills/linear-integration/SKILL.md +98 -0
- package/skills/linear-integration/evals/triggers.json +17 -0
- package/skills/literature-review/SKILL.md +109 -0
- package/skills/literature-review/evals/triggers.json +16 -0
- package/skills/literature-review/references/appraisal.md +41 -0
- package/skills/literature-review/references/search-sources.md +39 -0
- package/skills/llm-app-patterns/SKILL.md +97 -0
- package/skills/llm-app-patterns/evals/triggers.json +17 -0
- package/skills/llm-evals/SKILL.md +98 -0
- package/skills/llm-evals/evals/triggers.json +16 -0
- package/skills/llm-evals/references/graders.md +66 -0
- package/skills/logistics-exception-management/SKILL.md +90 -0
- package/skills/logistics-exception-management/evals/triggers.json +16 -0
- package/skills/manim-animations/SKILL.md +106 -0
- package/skills/manim-animations/evals/triggers.json +16 -0
- package/skills/market-research/SKILL.md +117 -0
- package/skills/market-research/evals/triggers.json +16 -0
- package/skills/marketing-campaign/SKILL.md +111 -0
- package/skills/marketing-campaign/evals/triggers.json +16 -0
- package/skills/mcp-server-patterns/SKILL.md +127 -0
- package/skills/mcp-server-patterns/evals/triggers.json +18 -0
- package/skills/mcp-server-patterns/references/protocol-notes.md +68 -0
- package/skills/metrics-dashboards/SKILL.md +113 -0
- package/skills/metrics-dashboards/evals/triggers.json +16 -0
- package/skills/ml-experiment-workflow/SKILL.md +125 -0
- package/skills/ml-experiment-workflow/evals/triggers.json +16 -0
- package/skills/mobile-accessibility/SKILL.md +94 -0
- package/skills/mobile-accessibility/evals/triggers.json +16 -0
- package/skills/mongodb-patterns/SKILL.md +115 -0
- package/skills/mongodb-patterns/evals/triggers.json +18 -0
- package/skills/mongodb-patterns/references/indexes-and-aggregation.md +94 -0
- package/skills/mpesa-daraja-integration/SKILL.md +70 -0
- package/skills/mpesa-daraja-integration/evals/triggers.json +16 -0
- package/skills/mpesa-daraja-integration/references/api.md +103 -0
- package/skills/mpesa-daraja-integration/references/callbacks.md +74 -0
- package/skills/mtn-momo-integration/SKILL.md +66 -0
- package/skills/mtn-momo-integration/evals/triggers.json +16 -0
- package/skills/mtn-momo-integration/references/api.md +153 -0
- package/skills/mtn-momo-integration/references/callbacks.md +92 -0
- package/skills/mtn-momo-integration/references/sandbox-and-go-live.md +51 -0
- package/skills/mtn-momo-integration/scripts/sandbox-setup.js +79 -0
- package/skills/mysql-patterns/SKILL.md +96 -0
- package/skills/mysql-patterns/evals/triggers.json +16 -0
- package/skills/mysql-patterns/references/explain.md +34 -0
- package/skills/mysql-patterns/references/online-ddl.md +41 -0
- package/skills/nestjs-patterns/SKILL.md +114 -0
- package/skills/nestjs-patterns/evals/triggers.json +16 -0
- package/skills/nestjs-patterns/references/testing.md +68 -0
- package/skills/network-automation/SKILL.md +107 -0
- package/skills/network-automation/evals/triggers.json +18 -0
- package/skills/network-automation/references/tool-snippets.md +153 -0
- package/skills/network-design/SKILL.md +98 -0
- package/skills/network-design/evals/triggers.json +16 -0
- package/skills/network-troubleshooting/SKILL.md +152 -0
- package/skills/network-troubleshooting/evals/triggers.json +18 -0
- package/skills/network-troubleshooting/references/commands.md +33 -0
- package/skills/nextjs-patterns/SKILL.md +150 -0
- package/skills/nextjs-patterns/evals/triggers.json +18 -0
- package/skills/nextjs-patterns/references/caching.md +87 -0
- package/skills/node-backend-patterns/SKILL.md +103 -0
- package/skills/node-backend-patterns/evals/triggers.json +16 -0
- package/skills/node-backend-patterns/references/templates.md +122 -0
- package/skills/nuxt-patterns/SKILL.md +103 -0
- package/skills/nuxt-patterns/evals/triggers.json +16 -0
- package/skills/observability/SKILL.md +125 -0
- package/skills/observability/evals/triggers.json +17 -0
- package/skills/observability/references/otel-setup.md +87 -0
- package/skills/observability/references/slo-alerts.md +70 -0
- package/skills/open-source-release/SKILL.md +107 -0
- package/skills/open-source-release/evals/triggers.json +15 -0
- package/skills/open-source-release/references/history-scrub.md +65 -0
- package/skills/parallel-agent-orchestration/SKILL.md +106 -0
- package/skills/parallel-agent-orchestration/evals/triggers.json +14 -0
- package/skills/patent-research/SKILL.md +94 -0
- package/skills/patent-research/evals/triggers.json +16 -0
- package/skills/patent-research/references/databases-and-queries.md +52 -0
- package/skills/paystack-integration/SKILL.md +59 -0
- package/skills/paystack-integration/evals/triggers.json +14 -0
- package/skills/paystack-integration/references/api.md +73 -0
- package/skills/paystack-integration/references/mobile-money.md +50 -0
- package/skills/paystack-integration/references/webhooks.md +80 -0
- package/skills/pci-dss-scope/SKILL.md +103 -0
- package/skills/pci-dss-scope/evals/triggers.json +18 -0
- package/skills/pci-dss-scope/references/saq-and-data.md +36 -0
- package/skills/perl-patterns/SKILL.md +135 -0
- package/skills/perl-patterns/evals/triggers.json +18 -0
- package/skills/perl-testing/SKILL.md +126 -0
- package/skills/perl-testing/evals/triggers.json +17 -0
- package/skills/php-patterns/SKILL.md +116 -0
- package/skills/php-patterns/evals/triggers.json +16 -0
- package/skills/php-testing/SKILL.md +123 -0
- package/skills/php-testing/evals/triggers.json +16 -0
- package/skills/postgres-patterns/SKILL.md +103 -0
- package/skills/postgres-patterns/evals/triggers.json +17 -0
- package/skills/postgres-patterns/references/explain.md +59 -0
- package/skills/postgres-patterns/references/locks.md +53 -0
- package/skills/prd-writing/SKILL.md +124 -0
- package/skills/prd-writing/evals/triggers.json +15 -0
- package/skills/prisma-patterns/SKILL.md +83 -0
- package/skills/prisma-patterns/evals/triggers.json +18 -0
- package/skills/prisma-patterns/references/prisma-8.md +46 -0
- package/skills/prisma-patterns/references/workflow.md +50 -0
- package/skills/privacy-compliance/SKILL.md +121 -0
- package/skills/privacy-compliance/evals/triggers.json +18 -0
- package/skills/privacy-compliance/references/jurisdictions.md +51 -0
- package/skills/production-scheduling/SKILL.md +98 -0
- package/skills/production-scheduling/evals/triggers.json +16 -0
- package/skills/prompt-engineering/SKILL.md +92 -0
- package/skills/prompt-engineering/evals/triggers.json +16 -0
- package/skills/prospect-research/SKILL.md +87 -0
- package/skills/prospect-research/evals/triggers.json +16 -0
- package/skills/python-app-distribution/SKILL.md +107 -0
- package/skills/python-app-distribution/evals/triggers.json +16 -0
- package/skills/python-app-distribution/references/pypi-trusted-publishing.md +55 -0
- package/skills/python-app-distribution/references/windows-macos-signing.md +70 -0
- package/skills/python-patterns/SKILL.md +107 -0
- package/skills/python-patterns/evals/triggers.json +16 -0
- package/skills/python-patterns/references/tooling.md +101 -0
- package/skills/python-testing/SKILL.md +126 -0
- package/skills/python-testing/evals/triggers.json +16 -0
- package/skills/python-testing/references/mocking.md +71 -0
- package/skills/pytorch-patterns/SKILL.md +139 -0
- package/skills/pytorch-patterns/evals/triggers.json +16 -0
- package/skills/pytorch-patterns/references/debugging.md +39 -0
- package/skills/quality-nonconformance/SKILL.md +107 -0
- package/skills/quality-nonconformance/evals/triggers.json +16 -0
- package/skills/quality-nonconformance/references/8d-and-capa.md +46 -0
- package/skills/quarkus-patterns/SKILL.md +93 -0
- package/skills/quarkus-patterns/evals/triggers.json +18 -0
- package/skills/rag-pipeline-patterns/SKILL.md +117 -0
- package/skills/rag-pipeline-patterns/evals/triggers.json +18 -0
- package/skills/rag-pipeline-patterns/references/evaluation.md +37 -0
- package/skills/rag-pipeline-patterns/references/retrieval-recipes.md +78 -0
- package/skills/rails-patterns/SKILL.md +132 -0
- package/skills/rails-patterns/evals/triggers.json +16 -0
- package/skills/react-native-patterns/SKILL.md +101 -0
- package/skills/react-native-patterns/evals/triggers.json +16 -0
- package/skills/react-patterns/SKILL.md +140 -0
- package/skills/react-patterns/evals/triggers.json +18 -0
- package/skills/react-performance/SKILL.md +107 -0
- package/skills/react-performance/evals/triggers.json +18 -0
- package/skills/react-testing/SKILL.md +121 -0
- package/skills/react-testing/evals/triggers.json +18 -0
- package/skills/react-testing/references/msw.md +64 -0
- package/skills/react-testing/references/queries.md +41 -0
- package/skills/react-testing/references/setup.md +74 -0
- package/skills/recommender-systems/SKILL.md +119 -0
- package/skills/recommender-systems/evals/triggers.json +16 -0
- package/skills/recommender-systems/references/evaluation.md +39 -0
- package/skills/redis-patterns/SKILL.md +109 -0
- package/skills/redis-patterns/evals/triggers.json +18 -0
- package/skills/redis-patterns/references/operations.md +61 -0
- package/skills/refactoring-safely/SKILL.md +107 -0
- package/skills/refactoring-safely/evals/behavior.json +57 -0
- package/skills/refactoring-safely/evals/triggers.json +17 -0
- package/skills/release-management/SKILL.md +141 -0
- package/skills/release-management/evals/triggers.json +16 -0
- package/skills/remotion-video/SKILL.md +91 -0
- package/skills/remotion-video/evals/triggers.json +16 -0
- package/skills/remotion-video/references/lambda.md +66 -0
- package/skills/reproducible-dev-environments/SKILL.md +132 -0
- package/skills/reproducible-dev-environments/evals/triggers.json +16 -0
- package/skills/responding-to-code-review/SKILL.md +124 -0
- package/skills/responding-to-code-review/evals/behavior.json +54 -0
- package/skills/responding-to-code-review/evals/triggers.json +16 -0
- package/skills/returns-reverse-logistics/SKILL.md +97 -0
- package/skills/returns-reverse-logistics/evals/triggers.json +16 -0
- package/skills/ruby-patterns/SKILL.md +127 -0
- package/skills/ruby-patterns/evals/triggers.json +18 -0
- package/skills/ruby-testing/SKILL.md +113 -0
- package/skills/ruby-testing/evals/triggers.json +18 -0
- package/skills/runbook-writing/SKILL.md +101 -0
- package/skills/runbook-writing/evals/triggers.json +14 -0
- package/skills/rust-patterns/SKILL.md +118 -0
- package/skills/rust-patterns/evals/triggers.json +16 -0
- package/skills/rust-patterns/references/cargo-and-clippy.md +105 -0
- package/skills/rust-patterns/references/errors-and-traits.md +97 -0
- package/skills/rust-testing/SKILL.md +148 -0
- package/skills/rust-testing/evals/triggers.json +16 -0
- package/skills/rust-testing/references/fakes-proptest-async.md +113 -0
- package/skills/search-first/SKILL.md +73 -0
- package/skills/search-first/evals/triggers.json +14 -0
- package/skills/security-review/SKILL.md +58 -0
- package/skills/security-review/evals/behavior.json +56 -0
- package/skills/security-review/evals/triggers.json +14 -0
- package/skills/security-review/references/checklist.md +54 -0
- package/skills/security-review/scripts/scan-secrets.js +79 -0
- package/skills/seo-audit/SKILL.md +111 -0
- package/skills/seo-audit/evals/triggers.json +16 -0
- package/skills/seo-audit/references/checks.md +65 -0
- package/skills/session-handoff/SKILL.md +101 -0
- package/skills/session-handoff/evals/behavior.json +55 -0
- package/skills/session-handoff/evals/triggers.json +14 -0
- package/skills/skill-authoring/SKILL.md +98 -0
- package/skills/skill-authoring/evals/triggers.json +15 -0
- package/skills/skill-authoring/references/frontmatter.md +40 -0
- package/skills/skill-authoring/references/pressure-testing.md +87 -0
- package/skills/slack-app-integration/SKILL.md +108 -0
- package/skills/slack-app-integration/evals/triggers.json +17 -0
- package/skills/slide-decks/SKILL.md +107 -0
- package/skills/slide-decks/evals/triggers.json +18 -0
- package/skills/slide-decks/references/html-decks.md +86 -0
- package/skills/slide-decks/references/layouts.md +45 -0
- package/skills/slide-decks/references/pptx.md +87 -0
- package/skills/smart-contract-security/SKILL.md +110 -0
- package/skills/smart-contract-security/evals/triggers.json +16 -0
- package/skills/smart-contract-security/references/vulnerability-checklist.md +79 -0
- package/skills/social-media-publishing/SKILL.md +84 -0
- package/skills/social-media-publishing/evals/triggers.json +17 -0
- package/skills/social-media-publishing/references/platform-apis.md +116 -0
- package/skills/solidity-patterns/SKILL.md +95 -0
- package/skills/solidity-patterns/evals/triggers.json +16 -0
- package/skills/spring-boot-patterns/SKILL.md +128 -0
- package/skills/spring-boot-patterns/evals/triggers.json +18 -0
- package/skills/spring-boot-patterns/references/testing.md +72 -0
- package/skills/stripe-integration/SKILL.md +69 -0
- package/skills/stripe-integration/evals/triggers.json +16 -0
- package/skills/stripe-integration/references/api.md +71 -0
- package/skills/stripe-integration/references/billing.md +58 -0
- package/skills/stripe-integration/references/webhooks.md +76 -0
- package/skills/subagent-driven-development/SKILL.md +109 -0
- package/skills/subagent-driven-development/evals/behavior.json +53 -0
- package/skills/subagent-driven-development/evals/triggers.json +15 -0
- package/skills/subagent-driven-development/references/implementer-brief.md +60 -0
- package/skills/subagent-driven-development/references/reviewer-briefs.md +52 -0
- package/skills/subscription-billing-ops/SKILL.md +118 -0
- package/skills/subscription-billing-ops/evals/triggers.json +17 -0
- package/skills/subscription-billing-ops/references/proration.md +47 -0
- package/skills/subscription-billing-ops/references/revenue-metrics.md +38 -0
- package/skills/svelte-patterns/SKILL.md +122 -0
- package/skills/svelte-patterns/evals/triggers.json +16 -0
- package/skills/swift-patterns/SKILL.md +113 -0
- package/skills/swift-patterns/evals/triggers.json +16 -0
- package/skills/swift-patterns/references/concurrency-migration.md +40 -0
- package/skills/swift-testing/SKILL.md +121 -0
- package/skills/swift-testing/evals/triggers.json +16 -0
- package/skills/swift-testing/references/swift-testing-cheatsheet.md +81 -0
- package/skills/swiftui-patterns/SKILL.md +102 -0
- package/skills/swiftui-patterns/evals/triggers.json +16 -0
- package/skills/systematic-debugging/SKILL.md +92 -0
- package/skills/systematic-debugging/evals/behavior.json +59 -0
- package/skills/systematic-debugging/evals/triggers.json +16 -0
- package/skills/systematic-debugging/references/condition-waiting.md +52 -0
- package/skills/systematic-debugging/references/root-cause-tracing.md +49 -0
- package/skills/systematic-debugging/references/test-pollution.md +46 -0
- package/skills/tdd-workflow/SKILL.md +69 -0
- package/skills/tdd-workflow/evals/behavior.json +55 -0
- package/skills/tdd-workflow/evals/triggers.json +15 -0
- package/skills/tdd-workflow/references/testing-anti-patterns.md +87 -0
- package/skills/technical-writing/SKILL.md +95 -0
- package/skills/technical-writing/evals/triggers.json +14 -0
- package/skills/terraform-patterns/SKILL.md +122 -0
- package/skills/terraform-patterns/evals/triggers.json +16 -0
- package/skills/terraform-patterns/references/backends.md +67 -0
- package/skills/test-coverage-improvement/SKILL.md +107 -0
- package/skills/test-coverage-improvement/evals/triggers.json +16 -0
- package/skills/threat-modeling/SKILL.md +113 -0
- package/skills/threat-modeling/evals/triggers.json +16 -0
- package/skills/transactional-email/SKILL.md +68 -0
- package/skills/transactional-email/evals/triggers.json +17 -0
- package/skills/transactional-email/references/providers.md +63 -0
- package/skills/typescript-patterns/SKILL.md +122 -0
- package/skills/typescript-patterns/evals/triggers.json +16 -0
- package/skills/typescript-testing/SKILL.md +101 -0
- package/skills/typescript-testing/evals/triggers.json +16 -0
- package/skills/ui-demo-recording/SKILL.md +93 -0
- package/skills/ui-demo-recording/evals/triggers.json +16 -0
- package/skills/ui-demo-recording/references/cursor-and-captions.md +48 -0
- package/skills/ui-demo-recording/references/playwright-recording.md +63 -0
- package/skills/ui-demo-recording/references/post-processing.md +57 -0
- package/skills/ui-design-polish/SKILL.md +113 -0
- package/skills/ui-design-polish/evals/triggers.json +18 -0
- package/skills/ui-design-polish/references/detail-checklist.md +45 -0
- package/skills/ui-design-polish/references/tokens.md +68 -0
- package/skills/ui-flow-audit/SKILL.md +112 -0
- package/skills/ui-flow-audit/evals/triggers.json +17 -0
- package/skills/ui-motion/SKILL.md +103 -0
- package/skills/ui-motion/evals/triggers.json +18 -0
- package/skills/ui-motion/references/patterns.md +138 -0
- package/skills/ui-motion/references/tokens.md +52 -0
- package/skills/unicode-text-processing/SKILL.md +103 -0
- package/skills/unicode-text-processing/evals/triggers.json +17 -0
- package/skills/unicode-text-processing/references/apis.md +89 -0
- package/skills/unicode-text-processing/references/script-notes.md +50 -0
- package/skills/verification-loop/SKILL.md +70 -0
- package/skills/verification-loop/evals/behavior.json +52 -0
- package/skills/verification-loop/evals/triggers.json +14 -0
- package/skills/verification-loop/scripts/detect-checks.js +102 -0
- package/skills/video-editing/SKILL.md +111 -0
- package/skills/video-editing/evals/triggers.json +16 -0
- package/skills/video-editing/references/edl-and-logging.md +44 -0
- package/skills/video-editing/references/ffmpeg-edit-recipes.md +92 -0
- package/skills/video-editing/references/resolve-scripting.md +53 -0
- package/skills/vite-patterns/SKILL.md +117 -0
- package/skills/vite-patterns/evals/triggers.json +16 -0
- package/skills/vue-patterns/SKILL.md +104 -0
- package/skills/vue-patterns/evals/triggers.json +16 -0
- package/skills/web-accessibility/SKILL.md +119 -0
- package/skills/web-accessibility/evals/triggers.json +16 -0
- package/skills/web-performance/SKILL.md +107 -0
- package/skills/web-performance/evals/triggers.json +16 -0
- package/skills/web-scraping/SKILL.md +80 -0
- package/skills/web-scraping/evals/triggers.json +16 -0
|
@@ -0,0 +1,294 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
// Registers kete-loom hooks with each host (verified against host docs and Kete Code's source,
|
|
4
|
+
// Oct 2026). User scope only. Every host calls `"<node>" "~/.kete-loom/hooks/run.js" <host> <hook>
|
|
5
|
+
// <event>`; that command string is how we recognise our own entries, so we never touch anyone else's.
|
|
6
|
+
//
|
|
7
|
+
// Shared settings files (Claude Code, Gemini CLI, Kete Code) are edited in place: parsed as strict
|
|
8
|
+
// JSON, backed up to `<file>.kete-loom-backup`, written atomically, and refused (with a snippet to
|
|
9
|
+
// paste) when they contain comments, since rewriting would drop them.
|
|
10
|
+
|
|
11
|
+
const fs = require('fs');
|
|
12
|
+
const path = require('path');
|
|
13
|
+
|
|
14
|
+
const RUNNER_RE = /\.kete-loom[\\/]hooks[\\/]run\.js"?\s+([a-z]+)\s+([a-z0-9-]+)(?:\s+([a-z-]+))?\s*$/;
|
|
15
|
+
// Seconds. A formatter run after an edit gets longer than a check before one.
|
|
16
|
+
const TIMEOUT_S = { 'pre-shell': 10, 'pre-edit': 10, 'post-edit': 60, 'session-start': 10, stop: 10, 'stop-gate': 180 };
|
|
17
|
+
|
|
18
|
+
const runtimeDir = (home) => path.join(home, '.kete-loom', 'hooks');
|
|
19
|
+
const command = (home, host, hook, event = 'pre-shell', node = process.execPath) =>
|
|
20
|
+
`"${node}" "${path.join(runtimeDir(home), 'run.js')}" ${host} ${hook} ${event}`;
|
|
21
|
+
|
|
22
|
+
function ours(cmd, hook) {
|
|
23
|
+
const m = typeof cmd === 'string' && RUNNER_RE.exec(cmd);
|
|
24
|
+
return Boolean(m) && (!hook || m[2] === hook);
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
// Host event name and tool matcher for each kete-loom event; a missing entry means the host can't
|
|
28
|
+
// run that event (Cursor has no documented pre-edit hook; OpenCode can't add context at session start).
|
|
29
|
+
// stop-gate needs a stop hook that can make the agent continue: Kete Code's Stop can only notify, and
|
|
30
|
+
// OpenCode's session.idle can't do either from a command.
|
|
31
|
+
const EVENTS = {
|
|
32
|
+
claude: { 'pre-shell': ['PreToolUse', 'Bash'], 'pre-edit': ['PreToolUse', 'Edit|Write|NotebookEdit'], 'post-edit': ['PostToolUse', 'Edit|Write|NotebookEdit'], 'session-start': ['SessionStart'], stop: ['Stop'], 'stop-gate': ['Stop'] },
|
|
33
|
+
codex: { 'pre-shell': ['PreToolUse', 'Bash'], 'pre-edit': ['PreToolUse', 'apply_patch'], 'post-edit': ['PostToolUse', 'apply_patch'], 'session-start': ['SessionStart'], stop: ['Stop'], 'stop-gate': ['Stop'] },
|
|
34
|
+
gemini: { 'pre-shell': ['BeforeTool', 'run_shell_command'], 'pre-edit': ['BeforeTool', 'write_file|replace'], 'post-edit': ['AfterTool', 'write_file|replace'], 'session-start': ['SessionStart'], stop: ['AfterAgent'], 'stop-gate': ['AfterAgent'] },
|
|
35
|
+
kete: { 'pre-shell': ['PreToolUse', 'shell'], 'pre-edit': ['PreToolUse', 'edit|write|patch'], 'post-edit': ['PostToolUse', 'edit|write|patch'], 'session-start': ['SessionStart'], stop: ['Stop'] },
|
|
36
|
+
cursor: { 'pre-shell': ['beforeShellExecution'], 'post-edit': ['afterFileEdit'], 'session-start': ['sessionStart'], stop: ['stop'], 'stop-gate': ['stop'] },
|
|
37
|
+
copilot: { 'pre-shell': ['preToolUse'], 'pre-edit': ['preToolUse'], 'post-edit': ['postToolUse'], 'session-start': ['sessionStart'], stop: ['agentStop'], 'stop-gate': ['agentStop'] },
|
|
38
|
+
opencode: { 'pre-shell': ['tool.execute.before'], 'pre-edit': ['tool.execute.before'], 'post-edit': ['tool.execute.after'] },
|
|
39
|
+
};
|
|
40
|
+
|
|
41
|
+
// Claude-style `{ <event>: [{ matcher, hooks: [entry] }] }` (Claude Code, Codex, Gemini CLI).
|
|
42
|
+
function removeGrouped(map, hook) {
|
|
43
|
+
let removed = 0;
|
|
44
|
+
for (const ev of Object.keys(map || {})) {
|
|
45
|
+
if (!Array.isArray(map[ev])) continue;
|
|
46
|
+
map[ev] = map[ev].filter((group) => {
|
|
47
|
+
if (!group || !Array.isArray(group.hooks)) return true;
|
|
48
|
+
const before = group.hooks.length;
|
|
49
|
+
group.hooks = group.hooks.filter((h) => !ours(h && h.command, hook));
|
|
50
|
+
removed += before - group.hooks.length;
|
|
51
|
+
return group.hooks.length > 0 || before === 0;
|
|
52
|
+
});
|
|
53
|
+
if (!map[ev].length) delete map[ev];
|
|
54
|
+
}
|
|
55
|
+
return removed;
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
// `{ <event>: [entry] }` (Kete Code, Cursor).
|
|
59
|
+
function removeFlat(map, hook) {
|
|
60
|
+
let removed = 0;
|
|
61
|
+
for (const ev of Object.keys(map || {})) {
|
|
62
|
+
if (!Array.isArray(map[ev])) continue;
|
|
63
|
+
const kept = map[ev].filter((h) => !ours(h && h.command, hook));
|
|
64
|
+
removed += map[ev].length - kept.length;
|
|
65
|
+
if (kept.length) map[ev] = kept;
|
|
66
|
+
else delete map[ev];
|
|
67
|
+
}
|
|
68
|
+
return removed;
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
function grouped(host, timeoutUnit = 1) {
|
|
72
|
+
return {
|
|
73
|
+
add: (data, cmd, hook, event) => {
|
|
74
|
+
const [ev, matcher] = EVENTS[host][event];
|
|
75
|
+
const entry = { type: 'command', command: cmd, timeout: TIMEOUT_S[event] * timeoutUnit };
|
|
76
|
+
if (host === 'gemini') entry.name = `kete-loom-${hook}`;
|
|
77
|
+
((data.hooks ||= {})[ev] ||= []).push({ ...(matcher ? { matcher } : {}), hooks: [entry] });
|
|
78
|
+
},
|
|
79
|
+
remove: (data, hook) => removeGrouped(data.hooks, hook),
|
|
80
|
+
};
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
const pascal = (s) => s.replace(/(^|-)(\w)/g, (_, __, c) => c.toUpperCase());
|
|
84
|
+
|
|
85
|
+
const HOSTS = {
|
|
86
|
+
claude: { file: (home) => path.join(home, '.claude', 'settings.json'), ...grouped('claude') },
|
|
87
|
+
codex: {
|
|
88
|
+
standalone: true,
|
|
89
|
+
file: (home) => path.join(home, '.codex', 'hooks.json'),
|
|
90
|
+
...grouped('codex'),
|
|
91
|
+
note: 'Codex runs a new or changed hook only after you trust it: open Codex and run /hooks.',
|
|
92
|
+
},
|
|
93
|
+
// Gemini CLI timeouts are milliseconds.
|
|
94
|
+
gemini: { file: (home) => path.join(home, '.gemini', 'settings.json'), ...grouped('gemini', 1000) },
|
|
95
|
+
kete: {
|
|
96
|
+
// Kete Code reads kete.json and kete.jsonc; edit the one that exists, preferring .jsonc.
|
|
97
|
+
file: (home) => {
|
|
98
|
+
const dir = path.join(home, '.config', 'kete');
|
|
99
|
+
const jsonc = path.join(dir, 'kete.jsonc');
|
|
100
|
+
return fs.existsSync(jsonc) ? jsonc : path.join(dir, 'kete.json');
|
|
101
|
+
},
|
|
102
|
+
add: (data, cmd, hook, event) => {
|
|
103
|
+
const [ev, match] = EVENTS.kete[event];
|
|
104
|
+
(((data.kete ||= {}).hooks ||= {})[ev] ||= []).push({ ...(match ? { match } : {}), command: cmd, timeout: TIMEOUT_S[event] });
|
|
105
|
+
},
|
|
106
|
+
remove: (data, hook) => removeFlat(data.kete && data.kete.hooks, hook),
|
|
107
|
+
},
|
|
108
|
+
cursor: {
|
|
109
|
+
standalone: true,
|
|
110
|
+
file: (home) => path.join(home, '.cursor', 'hooks.json'),
|
|
111
|
+
add: (data, cmd, hook, event) => {
|
|
112
|
+
data.version ||= 1;
|
|
113
|
+
((data.hooks ||= {})[EVENTS.cursor[event][0]] ||= []).push({ command: cmd, timeout: TIMEOUT_S[event] });
|
|
114
|
+
},
|
|
115
|
+
remove: (data, hook) => removeFlat(data.hooks, hook),
|
|
116
|
+
},
|
|
117
|
+
copilot: {
|
|
118
|
+
own: true,
|
|
119
|
+
file: (home, hook) => path.join(process.env.COPILOT_HOME || path.join(home, '.copilot'), 'hooks', `kete-loom-${hook}.json`),
|
|
120
|
+
content: (cmd, hook, event) =>
|
|
121
|
+
JSON.stringify({ version: 1, hooks: { [EVENTS.copilot[event][0]]: [{ type: 'command', bash: cmd, powershell: `& ${cmd}`, timeoutSec: TIMEOUT_S[event] }] } }, null, 2) + '\n',
|
|
122
|
+
isOurs: (text, hook) => {
|
|
123
|
+
try {
|
|
124
|
+
return Object.values(JSON.parse(text).hooks).some((list) => list.some((h) => ours(h.bash, hook)));
|
|
125
|
+
} catch {
|
|
126
|
+
return false;
|
|
127
|
+
}
|
|
128
|
+
},
|
|
129
|
+
},
|
|
130
|
+
opencode: {
|
|
131
|
+
own: true,
|
|
132
|
+
file: (home, hook) => path.join(home, '.config', 'opencode', 'plugins', `kete-loom-${hook}.js`),
|
|
133
|
+
// OpenCode hooks are plugins: hand the raw call to the shared runner, and throw to block.
|
|
134
|
+
content: (cmd, hook, event, home, node = process.execPath) => {
|
|
135
|
+
const key = EVENTS.opencode[event][0];
|
|
136
|
+
const before = key === 'tool.execute.before';
|
|
137
|
+
return `// kete-loom hook ${hook} (${event}): generated by \`npx @ketecode/loom install --hook ${hook}\`; remove with uninstall.
|
|
138
|
+
// runner: ${cmd}
|
|
139
|
+
import { spawnSync } from "node:child_process"
|
|
140
|
+
|
|
141
|
+
export const KeteLoom${pascal(hook)} = async ({ directory }) => ({
|
|
142
|
+
${JSON.stringify(key)}: async (input, output) => {
|
|
143
|
+
const r = spawnSync(${JSON.stringify(node)}, [${JSON.stringify(path.join(runtimeDir(home), 'run.js'))}, "opencode", ${JSON.stringify(hook)}, ${JSON.stringify(event)}], {
|
|
144
|
+
input: JSON.stringify({ tool: input && input.tool, args: (output && output.args) || (input && input.args), cwd: directory }),
|
|
145
|
+
encoding: "utf8",
|
|
146
|
+
timeout: ${TIMEOUT_S[event] * 1000},
|
|
147
|
+
})${before ? '\n if (r.status === 2) throw new Error((r.stderr || "").trim() || "Blocked by kete-loom")' : ''}
|
|
148
|
+
},
|
|
149
|
+
})
|
|
150
|
+
`;
|
|
151
|
+
},
|
|
152
|
+
isOurs: (text, hook) => ours((/^\/\/ runner: (.*)$/m.exec(text) || [])[1], hook),
|
|
153
|
+
},
|
|
154
|
+
};
|
|
155
|
+
|
|
156
|
+
const HOOK_HOSTS = Object.keys(HOSTS);
|
|
157
|
+
const supports = (host, event) => Boolean(EVENTS[host] && EVENTS[host][event]);
|
|
158
|
+
|
|
159
|
+
class CommentedFileError extends Error {}
|
|
160
|
+
|
|
161
|
+
// After removing our entries, drop the containers they leave empty (`hooks: {}`, `kete: {}`).
|
|
162
|
+
function prune(data) {
|
|
163
|
+
const empty = (v) => v && typeof v === 'object' && !Array.isArray(v) && !Object.keys(v).length;
|
|
164
|
+
if (data.kete && empty(data.kete.hooks)) delete data.kete.hooks;
|
|
165
|
+
if (empty(data.kete)) delete data.kete;
|
|
166
|
+
if (empty(data.hooks)) delete data.hooks;
|
|
167
|
+
return data;
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
function readJson(file) {
|
|
171
|
+
if (!fs.existsSync(file)) return {};
|
|
172
|
+
const text = fs.readFileSync(file, 'utf8');
|
|
173
|
+
if (!text.trim()) return {};
|
|
174
|
+
try {
|
|
175
|
+
const data = JSON.parse(text);
|
|
176
|
+
if (!data || typeof data !== 'object' || Array.isArray(data)) throw new Error('top level is not an object');
|
|
177
|
+
return data;
|
|
178
|
+
} catch (e) {
|
|
179
|
+
// shortcut: comment detection is a strip-and-retry, not a JSONC parser; fine for telling the cases apart.
|
|
180
|
+
const stripped = text.replace(/("(?:[^"\\]|\\.)*")|\/\/[^\n]*|\/\*[\s\S]*?\*\//g, (m, str) => str || '');
|
|
181
|
+
try {
|
|
182
|
+
JSON.parse(stripped.replace(/,(\s*[}\]])/g, '$1'));
|
|
183
|
+
} catch {
|
|
184
|
+
throw new Error(`${file} isn't valid JSON (${e.message}); not touching it`);
|
|
185
|
+
}
|
|
186
|
+
throw new CommentedFileError(`${file} has comments, and rewriting it would drop them`);
|
|
187
|
+
}
|
|
188
|
+
}
|
|
189
|
+
|
|
190
|
+
function writeAtomic(file, text) {
|
|
191
|
+
fs.mkdirSync(path.dirname(file), { recursive: true });
|
|
192
|
+
if (fs.existsSync(file)) fs.copyFileSync(file, `${file}.kete-loom-backup`);
|
|
193
|
+
const tmp = `${file}.kete-loom-tmp`;
|
|
194
|
+
fs.writeFileSync(tmp, text);
|
|
195
|
+
fs.renameSync(tmp, file);
|
|
196
|
+
}
|
|
197
|
+
|
|
198
|
+
function snippet(host, cmd, hook, event) {
|
|
199
|
+
const data = {};
|
|
200
|
+
HOSTS[host].add(data, cmd, hook, event);
|
|
201
|
+
return JSON.stringify(data, null, 2);
|
|
202
|
+
}
|
|
203
|
+
|
|
204
|
+
// Registers one hook with one host. Returns { action, dest, reason?, note? }.
|
|
205
|
+
function register(host, hook, event, { home, dryRun = false, node = process.execPath }) {
|
|
206
|
+
const h = HOSTS[host];
|
|
207
|
+
if (!supports(host, event)) return { action: 'skipped', dest: h.file(home, hook), reason: `${host} has no ${event} hook` };
|
|
208
|
+
const cmd = command(home, host, hook, event, node);
|
|
209
|
+
const file = h.file(home, hook);
|
|
210
|
+
if (h.own) {
|
|
211
|
+
const exists = fs.existsSync(file);
|
|
212
|
+
if (exists && !h.isOurs(fs.readFileSync(file, 'utf8'), hook)) return { action: 'skipped', dest: file, reason: 'a file with this name exists and was not written by kete-loom' };
|
|
213
|
+
if (!dryRun) writeAtomic(file, h.content(cmd, hook, event, home, node));
|
|
214
|
+
return { action: exists ? 'updated' : 'installed', dest: file, note: h.note };
|
|
215
|
+
}
|
|
216
|
+
let data;
|
|
217
|
+
try {
|
|
218
|
+
data = readJson(file);
|
|
219
|
+
} catch (e) {
|
|
220
|
+
const reason = e instanceof CommentedFileError ? `${e.message}. Add this yourself:\n${snippet(host, cmd, hook, event)}` : e.message;
|
|
221
|
+
return { action: 'skipped', dest: file, reason };
|
|
222
|
+
}
|
|
223
|
+
const existed = h.remove(data, hook) > 0;
|
|
224
|
+
h.add(data, cmd, hook, event);
|
|
225
|
+
if (!dryRun) writeAtomic(file, JSON.stringify(data, null, 2) + '\n');
|
|
226
|
+
return { action: existed ? 'updated' : 'installed', dest: file, note: h.note };
|
|
227
|
+
}
|
|
228
|
+
|
|
229
|
+
// Removes one hook (or every kete-loom hook when `hook` is null) from one host.
|
|
230
|
+
function unregister(host, hook, { home, dryRun = false, names = [] }) {
|
|
231
|
+
const h = HOSTS[host];
|
|
232
|
+
if (h.own) {
|
|
233
|
+
const removed = [];
|
|
234
|
+
for (const name of hook ? [hook] : names) {
|
|
235
|
+
const file = h.file(home, name);
|
|
236
|
+
if (fs.existsSync(file) && h.isOurs(fs.readFileSync(file, 'utf8'), name)) {
|
|
237
|
+
if (!dryRun) fs.rmSync(file);
|
|
238
|
+
removed.push({ name, dest: file });
|
|
239
|
+
}
|
|
240
|
+
}
|
|
241
|
+
return removed;
|
|
242
|
+
}
|
|
243
|
+
const file = h.file(home, hook);
|
|
244
|
+
if (!fs.existsSync(file)) return [];
|
|
245
|
+
let data;
|
|
246
|
+
try {
|
|
247
|
+
data = readJson(file);
|
|
248
|
+
} catch {
|
|
249
|
+
return []; // not ours to fix
|
|
250
|
+
}
|
|
251
|
+
const before = registered(host, { home });
|
|
252
|
+
if (!h.remove(data, hook)) return [];
|
|
253
|
+
prune(data);
|
|
254
|
+
if (!dryRun) {
|
|
255
|
+
// A standalone hooks file holding nothing but its version is deleted rather than left behind.
|
|
256
|
+
if (h.standalone && !Object.keys(data).filter((k) => k !== 'version').length) fs.rmSync(file);
|
|
257
|
+
else writeAtomic(file, JSON.stringify(data, null, 2) + '\n');
|
|
258
|
+
}
|
|
259
|
+
return before.filter((name) => !hook || name === hook).map((name) => ({ name, dest: file }));
|
|
260
|
+
}
|
|
261
|
+
|
|
262
|
+
// Names of kete-loom hooks registered with a host.
|
|
263
|
+
function registered(host, { home, names = [] }) {
|
|
264
|
+
const h = HOSTS[host];
|
|
265
|
+
if (h.own) return names.filter((n) => fs.existsSync(h.file(home, n)) && h.isOurs(fs.readFileSync(h.file(home, n), 'utf8'), n));
|
|
266
|
+
let data;
|
|
267
|
+
try {
|
|
268
|
+
data = readJson(h.file(home));
|
|
269
|
+
} catch {
|
|
270
|
+
return [];
|
|
271
|
+
}
|
|
272
|
+
const found = new Set();
|
|
273
|
+
(function walk(v) {
|
|
274
|
+
if (typeof v === 'string') {
|
|
275
|
+
const m = RUNNER_RE.exec(v);
|
|
276
|
+
if (m) found.add(m[2]);
|
|
277
|
+
} else if (v && typeof v === 'object') Object.values(v).forEach(walk);
|
|
278
|
+
})(data);
|
|
279
|
+
return [...found];
|
|
280
|
+
}
|
|
281
|
+
|
|
282
|
+
// Copies run.js and each hook's hook.js into ~/.kete-loom/hooks.
|
|
283
|
+
function installRuntime(hooks, { home, dryRun = false, sourceDir }) {
|
|
284
|
+
if (dryRun) return;
|
|
285
|
+
const dir = runtimeDir(home);
|
|
286
|
+
fs.mkdirSync(dir, { recursive: true });
|
|
287
|
+
fs.copyFileSync(path.join(sourceDir, 'run.js'), path.join(dir, 'run.js'));
|
|
288
|
+
for (const hook of hooks) {
|
|
289
|
+
fs.mkdirSync(path.join(dir, hook.dir), { recursive: true });
|
|
290
|
+
fs.copyFileSync(path.join(hook.path, 'hook.js'), path.join(dir, hook.dir, 'hook.js'));
|
|
291
|
+
}
|
|
292
|
+
}
|
|
293
|
+
|
|
294
|
+
module.exports = { HOSTS, HOOK_HOSTS, EVENTS, supports, register, unregister, registered, installRuntime, runtimeDir, command, ours, readJson, writeAtomic, CommentedFileError };
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
// Translated READMEs (docs/i18n/README.<lang>.md) translate the English README's prose. The generated
|
|
4
|
+
// catalog tables stay English-only, so the hash below ignores them: a translation is only out of date
|
|
5
|
+
// when the prose it was made from changes.
|
|
6
|
+
|
|
7
|
+
const crypto = require('crypto');
|
|
8
|
+
const fs = require('fs');
|
|
9
|
+
const path = require('path');
|
|
10
|
+
|
|
11
|
+
const REPO_ROOT = path.join(__dirname, '..', '..');
|
|
12
|
+
const I18N_DIR = path.join(REPO_ROOT, 'docs', 'i18n');
|
|
13
|
+
const LANGUAGES = {
|
|
14
|
+
ar: 'العربية',
|
|
15
|
+
de: 'Deutsch',
|
|
16
|
+
es: 'Español',
|
|
17
|
+
fr: 'Français',
|
|
18
|
+
ja: '日本語',
|
|
19
|
+
'pt-BR': 'Português (Brasil)',
|
|
20
|
+
sw: 'Kiswahili',
|
|
21
|
+
'zh-CN': '简体中文',
|
|
22
|
+
};
|
|
23
|
+
// The searchable catalog site, deployed by .github/workflows/pages.yml.
|
|
24
|
+
const SITE_URL = 'https://kete-org.github.io/kete-loom/';
|
|
25
|
+
const SOURCE_RE = /<!-- translated from README\.md, source ([0-9a-f]{12}) -->/;
|
|
26
|
+
const GENERATED_RE = /(<!-- (\w+):start -->)[\s\S]*?(<!-- \2:end -->)/g;
|
|
27
|
+
const SWITCHER_RE = /<!-- languages:start -->[\s\S]*?<!-- languages:end -->/;
|
|
28
|
+
|
|
29
|
+
// The English prose with generated tables and the language switcher emptied.
|
|
30
|
+
const prose = (text) => text.replace(SWITCHER_RE, '').replace(GENERATED_RE, '$1$3');
|
|
31
|
+
const sourceHash = (text = fs.readFileSync(path.join(REPO_ROOT, 'README.md'), 'utf8')) =>
|
|
32
|
+
crypto.createHash('sha256').update(prose(text)).digest('hex').slice(0, 12);
|
|
33
|
+
|
|
34
|
+
const switcher = (from = '') =>
|
|
35
|
+
`<!-- languages:start -->\n<p align="center">${[['README.md', 'English'], ...Object.entries(LANGUAGES).map(([code, label]) => [`docs/i18n/README.${code}.md`, label])]
|
|
36
|
+
.map(([file, label]) => `<a href="${path.posix.relative(from || '.', file)}">${label}</a>`)
|
|
37
|
+
.join(' · ')} · <a href="${SITE_URL}">Browse the catalog ↗</a></p>\n<!-- languages:end -->`;
|
|
38
|
+
|
|
39
|
+
// Each translation that exists: its language and whether it matches the current English prose.
|
|
40
|
+
function translations() {
|
|
41
|
+
const current = sourceHash();
|
|
42
|
+
return Object.keys(LANGUAGES)
|
|
43
|
+
.map((code) => ({ code, file: path.join(I18N_DIR, `README.${code}.md`) }))
|
|
44
|
+
.filter((t) => fs.existsSync(t.file))
|
|
45
|
+
.map((t) => {
|
|
46
|
+
const m = SOURCE_RE.exec(fs.readFileSync(t.file, 'utf8'));
|
|
47
|
+
return { ...t, source: m && m[1], current: Boolean(m) && m[1] === current };
|
|
48
|
+
});
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
module.exports = { LANGUAGES, I18N_DIR, sourceHash, prose, switcher, translations, SOURCE_RE, SWITCHER_RE };
|
|
@@ -0,0 +1,85 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
// What kete-loom has installed, where, and at which version, read from the markers it writes:
|
|
4
|
+
// `.kete-loom.json` in skill folders, `kete-loom name@version` comments in agents, commands and rules,
|
|
5
|
+
// and the host configs for hooks, linked rules and MCP servers. `update` and `outdated` build on it.
|
|
6
|
+
|
|
7
|
+
const fs = require('fs');
|
|
8
|
+
const path = require('path');
|
|
9
|
+
const { TARGETS, KINDS, resolveTarget } = require('./targets');
|
|
10
|
+
const Hooks = require('./hooks-install');
|
|
11
|
+
const Rules = require('./rules-install');
|
|
12
|
+
const Mcp = require('./mcp-install');
|
|
13
|
+
|
|
14
|
+
const FILE_MARKER = /^(?:# |<!-- )kete-loom ([a-z0-9-]+)@([^\s>]+)/m;
|
|
15
|
+
|
|
16
|
+
function head(file) {
|
|
17
|
+
try {
|
|
18
|
+
const fd = fs.openSync(file, 'r');
|
|
19
|
+
const buf = Buffer.alloc(512);
|
|
20
|
+
const n = fs.readSync(fd, buf, 0, 512, 0);
|
|
21
|
+
fs.closeSync(fd);
|
|
22
|
+
return buf.toString('utf8', 0, n);
|
|
23
|
+
} catch {
|
|
24
|
+
return '';
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
function skillEntry(dir, entry) {
|
|
29
|
+
const p = path.join(dir, entry);
|
|
30
|
+
let stat;
|
|
31
|
+
try {
|
|
32
|
+
stat = fs.lstatSync(p);
|
|
33
|
+
} catch {
|
|
34
|
+
return null;
|
|
35
|
+
}
|
|
36
|
+
if (stat.isSymbolicLink()) return { name: entry, version: null, linked: true, path: p };
|
|
37
|
+
try {
|
|
38
|
+
const marker = JSON.parse(fs.readFileSync(path.join(p, '.kete-loom.json'), 'utf8'));
|
|
39
|
+
return { name: entry, version: marker.version || null, path: p };
|
|
40
|
+
} catch {
|
|
41
|
+
return null; // not installed by kete-loom
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
// Rows of { target, kind, name, version, path, linked? } for one scope.
|
|
46
|
+
function inventory({ scope = 'user', home, cwd = process.cwd(), mcpAll = Mcp.listMcp(), hookNames = [] }) {
|
|
47
|
+
const rows = [];
|
|
48
|
+
for (const target of Object.keys(TARGETS)) {
|
|
49
|
+
for (const kind of KINDS) {
|
|
50
|
+
const dir = resolveTarget(target, { scope, home, cwd, kind });
|
|
51
|
+
if (!dir || !fs.existsSync(dir)) continue;
|
|
52
|
+
for (const entry of fs.readdirSync(dir)) {
|
|
53
|
+
if (kind === 'skills') {
|
|
54
|
+
const s = skillEntry(dir, entry);
|
|
55
|
+
if (s) rows.push({ target, kind, ...s });
|
|
56
|
+
continue;
|
|
57
|
+
}
|
|
58
|
+
const m = FILE_MARKER.exec(head(path.join(dir, entry)));
|
|
59
|
+
if (m) rows.push({ target, kind, name: m[1], version: m[2], path: path.join(dir, entry) });
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
if (scope === 'user') {
|
|
64
|
+
for (const host of Rules.RULE_HOSTS) {
|
|
65
|
+
const dir = Rules.HOSTS[host].dir(home);
|
|
66
|
+
for (const name of Rules.installedNames(dir)) {
|
|
67
|
+
const m = FILE_MARKER.exec(head(path.join(dir, `${name}.md`)));
|
|
68
|
+
rows.push({ target: host, kind: 'rules', name, version: m ? m[2] : null, path: path.join(dir, `${name}.md`) });
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
for (const host of Hooks.HOOK_HOSTS) for (const name of Hooks.registered(host, { home, names: hookNames })) rows.push({ target: host, kind: 'hooks', name, version: null });
|
|
72
|
+
}
|
|
73
|
+
for (const host of Mcp.MCP_HOSTS) for (const name of Mcp.registeredMcp(host, mcpAll, { scope, home, cwd })) rows.push({ target: host, kind: 'mcp', name, version: null });
|
|
74
|
+
return rows;
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
// -1, 0 or 1 for two x.y.z versions.
|
|
78
|
+
function compare(a, b) {
|
|
79
|
+
const pa = String(a).split('.').map(Number);
|
|
80
|
+
const pb = String(b).split('.').map(Number);
|
|
81
|
+
for (let i = 0; i < 3; i++) if ((pa[i] || 0) !== (pb[i] || 0)) return (pa[i] || 0) < (pb[i] || 0) ? -1 : 1;
|
|
82
|
+
return 0;
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
module.exports = { inventory, compare };
|
|
@@ -0,0 +1,180 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
// The spec rules for a single item (docs/SKILL_SPEC.md). Shipped with the CLI so `kete-loom check` can
|
|
4
|
+
// lint skills, agents, commands, rules and hooks you write yourself; scripts/lint-skills.js adds the
|
|
5
|
+
// repository-wide checks on top.
|
|
6
|
+
|
|
7
|
+
const fs = require('fs');
|
|
8
|
+
const os = require('os');
|
|
9
|
+
const path = require('path');
|
|
10
|
+
const { TOOLS } = require('./render');
|
|
11
|
+
const { loadBehavior } = require('./behavior');
|
|
12
|
+
|
|
13
|
+
const NAME_RE = /^[a-z0-9]+(-[a-z0-9]+)*$/;
|
|
14
|
+
const SEMVER_RE = /^\d+\.\d+\.\d+$/;
|
|
15
|
+
const TOP_KEYS = new Set(['name', 'description', 'license', 'compatibility', 'metadata']);
|
|
16
|
+
const CATEGORIES = ['coding', 'testing', 'security', 'integrations', 'devops', 'data', 'ai', 'docs', 'business', 'compliance', 'meta'];
|
|
17
|
+
const RISKS = ['read-only', 'writes-files', 'runs-commands', 'network'];
|
|
18
|
+
const MAX_LINES = 300;
|
|
19
|
+
const MIN_EVALS = 3;
|
|
20
|
+
const HOOK_EVENTS = ['pre-shell', 'pre-edit', 'post-edit', 'session-start', 'stop', 'stop-gate'];
|
|
21
|
+
const MAX_RULE_LINES = 80;
|
|
22
|
+
// Tool names that only exist in one host. Skills should describe the action instead.
|
|
23
|
+
const HOST_SPECIFIC = /\b(Bash tool|Read tool|Edit tool|Write tool|Grep tool|Glob tool|TodoWrite|apply_patch|str_replace_editor)\b/;
|
|
24
|
+
|
|
25
|
+
function words(s) {
|
|
26
|
+
return new Set(String(s).toLowerCase().match(/[a-z]{4,}/g) || []);
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
function jaccard(a, b) {
|
|
30
|
+
const inter = [...a].filter((x) => b.has(x)).length;
|
|
31
|
+
return inter / (a.size + b.size - inter || 1);
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
function lintItem(item) {
|
|
35
|
+
const errors = [...item.parseErrors];
|
|
36
|
+
const warnings = [];
|
|
37
|
+
const d = item.data;
|
|
38
|
+
const meta = d.metadata && typeof d.metadata === 'object' ? d.metadata : null;
|
|
39
|
+
|
|
40
|
+
for (const key of Object.keys(d)) if (!TOP_KEYS.has(key)) errors.push(`unknown top-level key "${key}" (put host-specific keys under metadata)`);
|
|
41
|
+
|
|
42
|
+
if (!d.name) errors.push('missing "name"');
|
|
43
|
+
else {
|
|
44
|
+
if (!NAME_RE.test(d.name)) errors.push(`name "${d.name}" must match ${NAME_RE}`);
|
|
45
|
+
if (d.name.length > 64) errors.push('name longer than 64 characters');
|
|
46
|
+
if (d.name !== item.dir) errors.push(`name "${d.name}" must equal ${item.kind === 'command' ? 'file' : 'folder'} name "${item.dir}"`);
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
if (!d.description) errors.push('missing "description"');
|
|
50
|
+
else if (item.kind === 'command' || item.kind === 'hook' || item.kind === 'rule') {
|
|
51
|
+
// Commands are picked by name and hooks run on events; the description is one line for menus and the catalog.
|
|
52
|
+
const len = d.description.length;
|
|
53
|
+
if (len < 20 || len > 300) errors.push(`description is ${len} chars; must be 20-300`);
|
|
54
|
+
} else {
|
|
55
|
+
const len = d.description.length;
|
|
56
|
+
if (len < 80 || len > 1024) errors.push(`description is ${len} chars; must be 80-1024`);
|
|
57
|
+
if (!/\buse when\b/i.test(d.description)) errors.push(`description must say when to use the ${item.kind} ("Use when ...")`);
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
if (!d.license) errors.push('missing "license"');
|
|
61
|
+
if (d.compatibility && d.compatibility.length > 500) errors.push('compatibility longer than 500 characters');
|
|
62
|
+
|
|
63
|
+
if (!meta) errors.push('missing "metadata" map');
|
|
64
|
+
else {
|
|
65
|
+
const v = meta['kete-loom/version'];
|
|
66
|
+
if (!v) errors.push('missing metadata.kete-loom/version');
|
|
67
|
+
else if (!SEMVER_RE.test(v)) errors.push(`kete-loom/version "${v}" is not semver`);
|
|
68
|
+
const c = meta['kete-loom/category'];
|
|
69
|
+
if (!CATEGORIES.includes(c)) errors.push(`kete-loom/category must be one of ${CATEGORIES.join(', ')}`);
|
|
70
|
+
const r = meta['kete-loom/risk'];
|
|
71
|
+
if (!RISKS.includes(r)) errors.push(`kete-loom/risk must be one of ${RISKS.join(', ')}`);
|
|
72
|
+
if (item.tools) {
|
|
73
|
+
const bad = item.tools.filter((t) => !TOOLS.includes(t));
|
|
74
|
+
if (bad.length || !item.tools.length) errors.push(`kete-loom/tools must be a comma list of ${TOOLS.join(', ')}`);
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
const lines = item.text.replace(/\r?\n$/, '').split('\n').length;
|
|
79
|
+
if (lines > MAX_LINES) errors.push(`${path.basename(item.file)} is ${lines} lines; limit is ${MAX_LINES}. Move detail into references/.`);
|
|
80
|
+
|
|
81
|
+
// Every relative file the body points at must exist.
|
|
82
|
+
const refs = new Set();
|
|
83
|
+
for (const m of item.body.matchAll(/\]\((?!https?:|#|mailto:)([^)\s]+)\)/g)) refs.add(m[1]);
|
|
84
|
+
for (const m of item.body.matchAll(/`((?:references|scripts|assets|templates)\/[^`\s]+)`/g)) refs.add(m[1]);
|
|
85
|
+
for (const ref of refs) {
|
|
86
|
+
if (!fs.existsSync(path.join(item.kind === 'command' ? path.dirname(item.path) : item.path, ref.split('#')[0]))) errors.push(`referenced file not found: ${ref}`);
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
const scriptsDir = path.join(item.path, 'scripts');
|
|
90
|
+
if (fs.existsSync(scriptsDir)) {
|
|
91
|
+
for (const f of fs.readdirSync(scriptsDir)) {
|
|
92
|
+
const p = path.join(scriptsDir, f);
|
|
93
|
+
const head = fs.readFileSync(p, 'utf8').slice(0, 2);
|
|
94
|
+
if (head === '#!' && !(fs.statSync(p).mode & 0o111) && process.platform !== 'win32') errors.push(`scripts/${f} has a shebang but is not executable (chmod +x)`);
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
if (item.kind === 'hook') errors.push(...lintHook(item));
|
|
99
|
+
// Rules load into every matching session, so they stay short: the always-on cost is paid on every turn.
|
|
100
|
+
if (item.kind === 'rule' && lines > MAX_RULE_LINES) errors.push(`rule is ${lines} lines; rules are loaded into context automatically, keep them under ${MAX_RULE_LINES}`);
|
|
101
|
+
if (item.kind === 'rule' && item.paths.some((p) => /\s/.test(p) || p.startsWith('/'))) errors.push('kete-loom/paths must be relative globs without spaces, comma separated (e.g. "**/*.py, **/*.pyi")');
|
|
102
|
+
|
|
103
|
+
// Hosts route to skills and agents by description, so both need trigger evals. Commands and hooks aren't routed.
|
|
104
|
+
const evalFile = ['command', 'hook', 'rule'].includes(item.kind) ? null : path.join(item.path, 'evals', 'triggers.json');
|
|
105
|
+
if (evalFile && !fs.existsSync(evalFile)) errors.push('missing evals/triggers.json');
|
|
106
|
+
else if (evalFile) {
|
|
107
|
+
try {
|
|
108
|
+
const ev = JSON.parse(fs.readFileSync(evalFile, 'utf8'));
|
|
109
|
+
for (const k of ['should_trigger', 'should_not_trigger']) {
|
|
110
|
+
if (!Array.isArray(ev[k]) || ev[k].length < MIN_EVALS) errors.push(`evals/triggers.json needs at least ${MIN_EVALS} "${k}" prompts`);
|
|
111
|
+
}
|
|
112
|
+
} catch (e) {
|
|
113
|
+
errors.push(`evals/triggers.json is not valid JSON: ${e.message}`);
|
|
114
|
+
}
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
// Behaviour evals are optional; when present they must be runnable.
|
|
118
|
+
if (item.kind === 'skill' || item.kind === 'agent') {
|
|
119
|
+
const behavior = loadBehavior(item);
|
|
120
|
+
if (behavior) errors.push(...behavior.problems);
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
const hostHit = HOST_SPECIFIC.exec(item.body);
|
|
124
|
+
if (hostHit) warnings.push(`mentions host-specific tool "${hostHit[1]}"; describe the action instead so every host can follow it`);
|
|
125
|
+
|
|
126
|
+
return { errors, warnings };
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
// A hook ships hook.js (exports check). Blocking (pre-*) hooks also ship cases.json, and every case must
|
|
130
|
+
// give the expected verdict; a case is a command string or an event object such as { files: [...] }.
|
|
131
|
+
function lintHook(hook) {
|
|
132
|
+
const errors = [];
|
|
133
|
+
if (!HOOK_EVENTS.includes(hook.event)) errors.push(`kete-loom/event must be one of ${HOOK_EVENTS.join(', ')}`);
|
|
134
|
+
let check;
|
|
135
|
+
try {
|
|
136
|
+
({ check } = require(path.join(hook.path, 'hook.js')));
|
|
137
|
+
} catch (e) {
|
|
138
|
+
return [...errors, `hook.js failed to load: ${e.message}`];
|
|
139
|
+
}
|
|
140
|
+
if (typeof check !== 'function') return [...errors, 'hook.js must export a check(event) function'];
|
|
141
|
+
if (!String(hook.event).startsWith('pre-')) return errors;
|
|
142
|
+
let cases;
|
|
143
|
+
try {
|
|
144
|
+
// Fake secrets are written as {{repeat:c:n}} so the repository never holds key-shaped strings.
|
|
145
|
+
cases = JSON.parse(fs.readFileSync(path.join(hook.path, 'cases.json'), 'utf8').replace(/\{\{repeat:(.):(\d+)\}\}/g, (_, c, n) => c.repeat(Number(n))));
|
|
146
|
+
} catch (e) {
|
|
147
|
+
return [...errors, `cases.json missing or invalid: ${e.message}`];
|
|
148
|
+
}
|
|
149
|
+
// Hooks that remember what they've seen keep it under KETE_LOOM_STATE_DIR; give each lint run a fresh one.
|
|
150
|
+
const prevState = process.env.KETE_LOOM_STATE_DIR;
|
|
151
|
+
const stateDir = fs.mkdtempSync(path.join(os.tmpdir(), 'kete-loom-lint-'));
|
|
152
|
+
process.env.KETE_LOOM_STATE_DIR = stateDir;
|
|
153
|
+
try {
|
|
154
|
+
lintCases(check, cases, errors);
|
|
155
|
+
} finally {
|
|
156
|
+
if (prevState === undefined) delete process.env.KETE_LOOM_STATE_DIR;
|
|
157
|
+
else process.env.KETE_LOOM_STATE_DIR = prevState;
|
|
158
|
+
fs.rmSync(stateDir, { recursive: true, force: true });
|
|
159
|
+
}
|
|
160
|
+
return errors;
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
function lintCases(check, cases, errors) {
|
|
164
|
+
for (const [key, want] of [['should_block', true], ['should_allow', false]]) {
|
|
165
|
+
if (!Array.isArray(cases[key]) || cases[key].length < MIN_EVALS) errors.push(`cases.json needs at least ${MIN_EVALS} "${key}" cases`);
|
|
166
|
+
for (const c of cases[key] || []) {
|
|
167
|
+
const event = typeof c === 'string' ? { command: c, cwd: process.cwd() } : { cwd: process.cwd(), ...c };
|
|
168
|
+
let got;
|
|
169
|
+
try {
|
|
170
|
+
got = Boolean(check(event).block);
|
|
171
|
+
} catch (e) {
|
|
172
|
+
errors.push(`check() threw on ${JSON.stringify(c)}: ${e.message}`);
|
|
173
|
+
continue;
|
|
174
|
+
}
|
|
175
|
+
if (got !== want) errors.push(`case ${JSON.stringify(c)} should ${want ? 'block' : 'be allowed'}`);
|
|
176
|
+
}
|
|
177
|
+
}
|
|
178
|
+
}
|
|
179
|
+
|
|
180
|
+
module.exports = { lintItem, lintHook, words, jaccard, NAME_RE, SEMVER_RE, CATEGORIES, RISKS, MAX_LINES, HOOK_EVENTS };
|