@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
package/bin/kete-loom.js
ADDED
|
@@ -0,0 +1,723 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
'use strict';
|
|
3
|
+
|
|
4
|
+
// kete-loom: install Kete Loom skills, agents and commands into any Agent Skills host.
|
|
5
|
+
// Zero dependencies; Node 18+.
|
|
6
|
+
|
|
7
|
+
const fs = require('fs');
|
|
8
|
+
const os = require('os');
|
|
9
|
+
const path = require('path');
|
|
10
|
+
const { execFileSync } = require('child_process');
|
|
11
|
+
const { SKILLS_DIR, HOOKS_DIR, listSkills, listAgents, listCommands, listHooks, listRules, loadSkill, loadAgent, loadCommand, loadHook, loadRule } = require('../scripts/lib/skills');
|
|
12
|
+
const { lintItem } = require('../scripts/lib/lint');
|
|
13
|
+
const { audit } = require('../scripts/lib/audit');
|
|
14
|
+
const { TARGETS, KINDS, HOST_READS, resolveTarget, detected } = require('../scripts/lib/targets');
|
|
15
|
+
const { MARKER_RE, render } = require('../scripts/lib/render');
|
|
16
|
+
const Hooks = require('../scripts/lib/hooks-install');
|
|
17
|
+
const { loadProfiles, resolveProfiles } = require('../scripts/lib/profiles');
|
|
18
|
+
const Rules = require('../scripts/lib/rules-install');
|
|
19
|
+
const Mcp = require('../scripts/lib/mcp-install');
|
|
20
|
+
const { inventory, compare } = require('../scripts/lib/inventory');
|
|
21
|
+
|
|
22
|
+
const MARKER = '.kete-loom.json';
|
|
23
|
+
const pkg = require('../package.json');
|
|
24
|
+
|
|
25
|
+
const csv = (s) => s.split(',').map((x) => x.trim()).filter(Boolean);
|
|
26
|
+
|
|
27
|
+
function parseArgs(argv) {
|
|
28
|
+
const opts = { _: [], scope: 'user', dryRun: false, force: false, link: false };
|
|
29
|
+
for (let i = 0; i < argv.length; i++) {
|
|
30
|
+
const a = argv[i];
|
|
31
|
+
const next = () => {
|
|
32
|
+
if (i + 1 >= argv.length) throw new Error(`${a} needs a value`);
|
|
33
|
+
return argv[++i];
|
|
34
|
+
};
|
|
35
|
+
if (a === '--target' || a === '-t') opts.targets = csv(next());
|
|
36
|
+
else if (a === '--all-targets') opts.targets = Object.keys(TARGETS);
|
|
37
|
+
else if (a === '--skill' || a === '-s') opts.skills = csv(next());
|
|
38
|
+
else if (a === '--agent' || a === '-a') opts.agents = csv(next());
|
|
39
|
+
else if (a === '--command') opts.commands = csv(next());
|
|
40
|
+
else if (a === '--hook') opts.hookNames = csv(next());
|
|
41
|
+
else if (a === '--rule' || a === '-r') opts.rules = csv(next());
|
|
42
|
+
else if (a === '--mcp') opts.mcp = csv(next());
|
|
43
|
+
else if (a === '--hooks') opts.withHooks = true;
|
|
44
|
+
else if (a === '--profile' || a === '-P') opts.profiles = csv(next());
|
|
45
|
+
else if (a === '--category' || a === '-c') opts.categories = csv(next());
|
|
46
|
+
else if (a === '--scope') opts.scope = next();
|
|
47
|
+
else if (a === '--project' || a === '-p') opts.scope = 'project';
|
|
48
|
+
else if (a === '--dir') opts.dir = path.resolve(next());
|
|
49
|
+
else if (a === '--home') opts.home = path.resolve(next());
|
|
50
|
+
else if (a === '--source') opts.source = path.resolve(next());
|
|
51
|
+
else if (a === '--dry-run' || a === '-n') opts.dryRun = true;
|
|
52
|
+
else if (a === '--force' || a === '-f') opts.force = true;
|
|
53
|
+
else if (a === '--link') opts.link = true;
|
|
54
|
+
else if (a === '--fix') opts.fix = true;
|
|
55
|
+
else if (a === '--json') opts.json = true;
|
|
56
|
+
else if (a === '--help' || a === '-h') opts._.unshift('help');
|
|
57
|
+
else if (a === '--version' || a === '-v') opts._.unshift('version');
|
|
58
|
+
else if (a.startsWith('-')) throw new Error(`unknown option ${a}`);
|
|
59
|
+
else opts._.push(a);
|
|
60
|
+
}
|
|
61
|
+
if (!['user', 'project'].includes(opts.scope)) throw new Error('--scope must be user or project');
|
|
62
|
+
if (opts.targets) for (const t of opts.targets) if (!TARGETS[t]) throw new Error(`unknown target "${t}". Known: ${Object.keys(TARGETS).join(', ')}`);
|
|
63
|
+
return opts;
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
function help() {
|
|
67
|
+
console.log(`kete-loom ${pkg.version} — install Kete Loom skills, agents and commands into any Agent Skills host
|
|
68
|
+
|
|
69
|
+
Usage
|
|
70
|
+
kete-loom install [options] Copy skills, agents and commands into host folders (hooks with --hooks)
|
|
71
|
+
kete-loom update [options] Refresh exactly what kete-loom installed, in the hosts it's in
|
|
72
|
+
kete-loom outdated [--json] Installed items that are older than this version of Kete Loom
|
|
73
|
+
kete-loom audit [--json] Score this project's readiness for coding agents, with fixes
|
|
74
|
+
kete-loom check <path> Lint your own skills, agents, commands, rules or hooks against the spec
|
|
75
|
+
kete-loom uninstall [options] Remove items that kete-loom installed
|
|
76
|
+
kete-loom list [--json] List available skills, agents, commands and hooks
|
|
77
|
+
kete-loom profiles [--json] List install profiles
|
|
78
|
+
kete-loom doctor [options] Show what is installed where, and which hosts can see it
|
|
79
|
+
(--fix repairs the hook runtime and stale registrations)
|
|
80
|
+
|
|
81
|
+
Options
|
|
82
|
+
-t, --target <a,b> Targets: ${Object.keys(TARGETS).join(', ')}
|
|
83
|
+
Default: agents,claude (skills for every host; agents and
|
|
84
|
+
commands for Claude Code, Cursor and VS Code Copilot), plus
|
|
85
|
+
agents and commands for Codex, OpenCode, Gemini CLI and
|
|
86
|
+
Kete Code when they are installed
|
|
87
|
+
--all-targets Install into every host-specific folder as well
|
|
88
|
+
-p, --project Install into the current repo instead of your home folder
|
|
89
|
+
--scope <s> user (default) or project
|
|
90
|
+
--dir <path> Install skills into a custom skills folder (any other agent)
|
|
91
|
+
-s, --skill <a,b> Only these skills
|
|
92
|
+
-a, --agent <a,b> Only these agents
|
|
93
|
+
--command <a,b> Only these commands
|
|
94
|
+
-r, --rule <a,b> Only these rules
|
|
95
|
+
--hook <a,b> Only these hooks
|
|
96
|
+
(--skill, --agent, --command, --rule and --hook combine; with none,
|
|
97
|
+
all skills, agents, commands and rules are installed)
|
|
98
|
+
--mcp <a,b> Also register these MCP servers (see "kete-loom list"). Remote
|
|
99
|
+
servers sign in with OAuth; none need a token in a config file.
|
|
100
|
+
--hooks Also install every hook not marked opt-in (name those with --hook, or
|
|
101
|
+
use --profile strict). Hooks run around the agent's tool calls and are
|
|
102
|
+
registered in each host's config, including Claude Code's and Gemini
|
|
103
|
+
CLI's settings.json (backed up first). User scope only.
|
|
104
|
+
-P, --profile <a,b> Install a preset: minimal, core, developer, security, ai, data,
|
|
105
|
+
business, full (see "kete-loom profiles"). core and the profiles
|
|
106
|
+
built on it add the language and framework packs this project uses.
|
|
107
|
+
Combines with --skill, --agent, --command and --hook.
|
|
108
|
+
-c, --category <a,b> Only these categories
|
|
109
|
+
--link Symlink skills instead of copying (for skill authors)
|
|
110
|
+
-f, --force Overwrite items with the same name not installed by kete-loom
|
|
111
|
+
-n, --dry-run Show what would happen without changing anything
|
|
112
|
+
|
|
113
|
+
Examples
|
|
114
|
+
npx @ketecode/loom install
|
|
115
|
+
npx @ketecode/loom install --project --skill tdd-workflow,verification-loop
|
|
116
|
+
npx @ketecode/loom install --target claude
|
|
117
|
+
npx @ketecode/loom install --target codex --agent code-reviewer
|
|
118
|
+
npx @ketecode/loom install --dir ~/.my-agent/skills
|
|
119
|
+
npx @ketecode/loom install --hook block-dangerous-commands
|
|
120
|
+
npx @ketecode/loom install --profile developer
|
|
121
|
+
`);
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
function catalog(opts) {
|
|
125
|
+
return { skills: listSkills(opts.source || SKILLS_DIR), agents: listAgents(), commands: listCommands(), rules: listRules(), hooks: listHooks(), mcp: Mcp.listMcp() };
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
// Folds --profile into the explicit --skill/--agent/--command/--hook lists (or "everything" for full).
|
|
129
|
+
function applyProfiles(opts, all) {
|
|
130
|
+
if (!opts.profiles || opts.profileApplied) return;
|
|
131
|
+
const r = resolveProfiles(opts.profiles, { catalog: all, cwd: process.cwd() });
|
|
132
|
+
opts.profileApplied = true;
|
|
133
|
+
opts.detected = r.detected;
|
|
134
|
+
if (r.all) {
|
|
135
|
+
opts.withHooks = true;
|
|
136
|
+
opts.mcp = all.mcp.map((m) => m.dir);
|
|
137
|
+
return;
|
|
138
|
+
}
|
|
139
|
+
if (r.mcp.size) opts.mcp = [...new Set([...(opts.mcp || []), ...r.mcp])];
|
|
140
|
+
const merge = (key, set) => (set.size || opts[key] ? (opts[key] = [...new Set([...(opts[key] || []), ...set])]) : undefined);
|
|
141
|
+
merge('skills', r.skills);
|
|
142
|
+
merge('agents', r.agents);
|
|
143
|
+
merge('commands', r.commands);
|
|
144
|
+
merge('rules', r.rules);
|
|
145
|
+
if (r.hooks.size && opts.scope === 'project') opts.droppedHooks = [...r.hooks];
|
|
146
|
+
else merge('hookNames', r.hooks);
|
|
147
|
+
// A profile names its items, so an empty kind means "none of these", not "all of them".
|
|
148
|
+
for (const k of KINDS) opts[k] ||= [];
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
// Returns { skills, agents, commands, hooks } after the profile and --skill/--agent/--command/--hook/--category filters.
|
|
152
|
+
function selectItems(opts) {
|
|
153
|
+
const all = catalog(opts);
|
|
154
|
+
applyProfiles(opts, all);
|
|
155
|
+
const named = KINDS.some((k) => opts[k]) || Boolean(opts.hookNames) || Boolean(opts.mcp);
|
|
156
|
+
const chosen = {};
|
|
157
|
+
for (const kind of KINDS) {
|
|
158
|
+
let items = all[kind];
|
|
159
|
+
if (named) {
|
|
160
|
+
const want = opts[kind] || [];
|
|
161
|
+
const unknown = want.filter((n) => !items.some((i) => i.dir === n));
|
|
162
|
+
if (unknown.length) throw new Error(`unknown ${kind.slice(0, -1)}(s): ${unknown.join(', ')}. Run "kete-loom list".`);
|
|
163
|
+
items = items.filter((i) => want.includes(i.dir));
|
|
164
|
+
}
|
|
165
|
+
if (opts.categories) items = items.filter((i) => opts.categories.includes(i.category));
|
|
166
|
+
chosen[kind] = items;
|
|
167
|
+
}
|
|
168
|
+
// Hooks are opt-in: only with --hooks or when named with --hook. --hooks leaves out the hooks marked
|
|
169
|
+
// kete-loom/opt-in (they change how the agent works, not just what it may do).
|
|
170
|
+
const unknownHooks = (opts.hookNames || []).filter((n) => !all.hooks.some((h) => h.dir === n));
|
|
171
|
+
if (unknownHooks.length) throw new Error(`unknown hook(s): ${unknownHooks.join(', ')}. Run "kete-loom list".`);
|
|
172
|
+
chosen.hooks = opts.hookNames ? all.hooks.filter((h) => opts.hookNames.includes(h.dir)) : opts.withHooks ? all.hooks.filter((h) => !h.optIn) : [];
|
|
173
|
+
if (opts.categories) chosen.hooks = chosen.hooks.filter((h) => opts.categories.includes(h.category));
|
|
174
|
+
// MCP servers are opt-in too: only with --mcp or a profile that names them.
|
|
175
|
+
const unknownMcp = (opts.mcp || []).filter((n) => !all.mcp.some((m) => m.dir === n));
|
|
176
|
+
if (unknownMcp.length) throw new Error(`unknown MCP server(s): ${unknownMcp.join(', ')}. Run "kete-loom list".`);
|
|
177
|
+
chosen.mcp = all.mcp.filter((m) => (opts.mcp || []).includes(m.dir));
|
|
178
|
+
return chosen;
|
|
179
|
+
}
|
|
180
|
+
|
|
181
|
+
function destinations(opts) {
|
|
182
|
+
if (opts.dir) return [{ target: 'custom', kind: 'skills', dir: opts.dir }];
|
|
183
|
+
const where = { scope: opts.scope, home: opts.home || os.homedir(), cwd: process.cwd() };
|
|
184
|
+
const picks = opts.targets
|
|
185
|
+
? opts.targets.map((t) => ({ target: t, kinds: KINDS }))
|
|
186
|
+
: Object.keys(TARGETS)
|
|
187
|
+
.filter((t) => TARGETS[t].default || detected(t, where))
|
|
188
|
+
// Detected hosts read skills from .agents already; they only need their own agents, commands and
|
|
189
|
+
// rules (Cursor and Copilot read agents from .claude too, so they only need rules).
|
|
190
|
+
.map((t) => ({ target: t, kinds: TARGETS[t].default ? KINDS : TARGETS[t].auto ? [...(TARGETS[t].ownSkills ? ['skills'] : []), 'agents', 'commands', 'rules'] : ['rules'] }));
|
|
191
|
+
return picks.flatMap(({ target, kinds }) =>
|
|
192
|
+
kinds.map((kind) => ({ target, kind, dir: resolveTarget(target, { ...where, kind }) })).filter((d) => d.dir)
|
|
193
|
+
);
|
|
194
|
+
}
|
|
195
|
+
|
|
196
|
+
// Hosts to register hooks with: the --target list, or Claude Code plus every other hook host found.
|
|
197
|
+
function hookHosts(opts) {
|
|
198
|
+
const where = { scope: 'user', home: opts.home || os.homedir(), cwd: process.cwd() };
|
|
199
|
+
if (opts.targets) return opts.targets.filter((t) => TARGETS[t].hooks);
|
|
200
|
+
return Hooks.HOOK_HOSTS.filter((t) => TARGETS[t].default || detected(t, where));
|
|
201
|
+
}
|
|
202
|
+
|
|
203
|
+
function installHooks(hooks, opts) {
|
|
204
|
+
if (!hooks.length) return [];
|
|
205
|
+
if (opts.scope === 'project') throw new Error('hooks install at user scope only; drop --project, or pass --skill/--agent/--command to choose what to install in the project');
|
|
206
|
+
const home = opts.home || os.homedir();
|
|
207
|
+
Hooks.installRuntime(hooks, { home, dryRun: opts.dryRun, sourceDir: HOOKS_DIR });
|
|
208
|
+
const results = [];
|
|
209
|
+
for (const target of hookHosts(opts)) {
|
|
210
|
+
for (const hook of hooks) results.push({ target, kind: 'hook', name: hook.dir, ...Hooks.register(target, hook.dir, hook.event, { home, dryRun: opts.dryRun }) });
|
|
211
|
+
}
|
|
212
|
+
return results;
|
|
213
|
+
}
|
|
214
|
+
|
|
215
|
+
function uninstallHooks(opts, named) {
|
|
216
|
+
if (named && !opts.hookNames) return [];
|
|
217
|
+
const home = opts.home || os.homedir();
|
|
218
|
+
const names = listHooks().map((h) => h.dir);
|
|
219
|
+
const hosts = opts.targets ? opts.targets.filter((t) => TARGETS[t].hooks) : Hooks.HOOK_HOSTS;
|
|
220
|
+
const results = [];
|
|
221
|
+
for (const target of hosts) {
|
|
222
|
+
for (const hook of opts.hookNames || [null]) {
|
|
223
|
+
for (const r of Hooks.unregister(target, hook, { home, dryRun: opts.dryRun, names })) results.push({ target, kind: 'hook', action: 'removed', ...r });
|
|
224
|
+
}
|
|
225
|
+
}
|
|
226
|
+
// The shared runtime goes once no host is told to call it any more.
|
|
227
|
+
const left = Hooks.HOOK_HOSTS.flatMap((t) => Hooks.registered(t, { home, names }));
|
|
228
|
+
if (!opts.dryRun) {
|
|
229
|
+
for (const hook of opts.hookNames || names) if (!left.includes(hook)) fs.rmSync(path.join(Hooks.runtimeDir(home), hook), { recursive: true, force: true });
|
|
230
|
+
if (!left.length) {
|
|
231
|
+
fs.rmSync(Hooks.runtimeDir(home), { recursive: true, force: true });
|
|
232
|
+
const parent = path.dirname(Hooks.runtimeDir(home));
|
|
233
|
+
if (fs.existsSync(parent) && !fs.readdirSync(parent).length) fs.rmdirSync(parent);
|
|
234
|
+
}
|
|
235
|
+
}
|
|
236
|
+
return results;
|
|
237
|
+
}
|
|
238
|
+
|
|
239
|
+
// Hosts that can't scope rules to paths get them through their instructions file (rules-install.js).
|
|
240
|
+
function linkedRuleHosts(opts) {
|
|
241
|
+
if (opts.dir || opts.scope === 'project') return [];
|
|
242
|
+
const where = { scope: 'user', home: opts.home || os.homedir(), cwd: process.cwd() };
|
|
243
|
+
return Rules.RULE_HOSTS.filter((t) => (opts.targets ? opts.targets.includes(t) : detected(t, where)));
|
|
244
|
+
}
|
|
245
|
+
|
|
246
|
+
// Hosts to register MCP servers with: the --target list, or Claude Code plus every other host found.
|
|
247
|
+
function mcpHosts(opts) {
|
|
248
|
+
const where = { scope: opts.scope, home: opts.home || os.homedir(), cwd: process.cwd() };
|
|
249
|
+
const hosts = opts.targets ? opts.targets.filter((t) => Mcp.MCP_HOSTS.includes(t)) : Mcp.MCP_HOSTS.filter((t) => TARGETS[t].default || detected(t, where));
|
|
250
|
+
// At project scope Copilot reads the .mcp.json written for Claude Code.
|
|
251
|
+
return opts.scope === 'project' ? hosts.filter((t) => t !== 'copilot') : hosts;
|
|
252
|
+
}
|
|
253
|
+
|
|
254
|
+
function readMarker(dir) {
|
|
255
|
+
try {
|
|
256
|
+
return JSON.parse(fs.readFileSync(path.join(dir, MARKER), 'utf8'));
|
|
257
|
+
} catch {
|
|
258
|
+
return null;
|
|
259
|
+
}
|
|
260
|
+
}
|
|
261
|
+
|
|
262
|
+
function isInside(child, parent) {
|
|
263
|
+
const rel = path.relative(parent, child);
|
|
264
|
+
return rel !== '' && !rel.startsWith('..') && !path.isAbsolute(rel);
|
|
265
|
+
}
|
|
266
|
+
|
|
267
|
+
// A symlink is ours when it points into our skills folder or the --source folder it was linked from.
|
|
268
|
+
function isOurs(dir, opts = {}) {
|
|
269
|
+
try {
|
|
270
|
+
if (fs.lstatSync(dir).isSymbolicLink()) {
|
|
271
|
+
const target = path.resolve(path.dirname(dir), fs.readlinkSync(dir));
|
|
272
|
+
return [SKILLS_DIR, opts.source].some((src) => src && isInside(target, path.resolve(src)));
|
|
273
|
+
}
|
|
274
|
+
} catch {
|
|
275
|
+
return false;
|
|
276
|
+
}
|
|
277
|
+
return readMarker(dir) !== null;
|
|
278
|
+
}
|
|
279
|
+
|
|
280
|
+
// Agent and command files are ours when they carry the `# kete-loom name@version` comment.
|
|
281
|
+
function isOursFile(file) {
|
|
282
|
+
try {
|
|
283
|
+
if (!fs.lstatSync(file).isFile()) return false;
|
|
284
|
+
const fd = fs.openSync(file, 'r');
|
|
285
|
+
const buf = Buffer.alloc(512);
|
|
286
|
+
const n = fs.readSync(fd, buf, 0, 512, 0);
|
|
287
|
+
fs.closeSync(fd);
|
|
288
|
+
return MARKER_RE.test(buf.toString('utf8', 0, n));
|
|
289
|
+
} catch {
|
|
290
|
+
return false;
|
|
291
|
+
}
|
|
292
|
+
}
|
|
293
|
+
|
|
294
|
+
function isSymlink(p) {
|
|
295
|
+
try {
|
|
296
|
+
return fs.lstatSync(p).isSymbolicLink();
|
|
297
|
+
} catch {
|
|
298
|
+
return false;
|
|
299
|
+
}
|
|
300
|
+
}
|
|
301
|
+
|
|
302
|
+
function copyDir(src, dest) {
|
|
303
|
+
fs.mkdirSync(dest, { recursive: true });
|
|
304
|
+
for (const entry of fs.readdirSync(src, { withFileTypes: true })) {
|
|
305
|
+
if (entry.name === 'evals') continue; // evals are for this repo's CI, not for hosts
|
|
306
|
+
const s = path.join(src, entry.name);
|
|
307
|
+
const d = path.join(dest, entry.name);
|
|
308
|
+
if (entry.isDirectory()) copyDir(s, d);
|
|
309
|
+
else {
|
|
310
|
+
fs.copyFileSync(s, d);
|
|
311
|
+
if (fs.statSync(s).mode & 0o111) fs.chmodSync(d, 0o755);
|
|
312
|
+
}
|
|
313
|
+
}
|
|
314
|
+
}
|
|
315
|
+
|
|
316
|
+
const NOT_OURS = 'an item with this name exists and was not installed by kete-loom (use --force)';
|
|
317
|
+
|
|
318
|
+
function installSkill(skill, dir, opts) {
|
|
319
|
+
const dest = path.join(dir, skill.dir);
|
|
320
|
+
const exists = fs.existsSync(dest) || isSymlink(dest);
|
|
321
|
+
if (exists && !isOurs(dest, opts) && !opts.force) return { action: 'skipped', reason: NOT_OURS, dest };
|
|
322
|
+
if (!opts.dryRun) {
|
|
323
|
+
if (exists) fs.rmSync(dest, { recursive: true, force: true });
|
|
324
|
+
fs.mkdirSync(dir, { recursive: true });
|
|
325
|
+
if (opts.link) {
|
|
326
|
+
fs.symlinkSync(skill.path, dest, 'dir');
|
|
327
|
+
} else {
|
|
328
|
+
copyDir(skill.path, dest);
|
|
329
|
+
fs.writeFileSync(
|
|
330
|
+
path.join(dest, MARKER),
|
|
331
|
+
JSON.stringify({ source: 'kete-loom', skill: skill.dir, version: skill.version, installer: pkg.version, installedAt: new Date().toISOString() }, null, 2) + '\n'
|
|
332
|
+
);
|
|
333
|
+
}
|
|
334
|
+
}
|
|
335
|
+
return { action: exists ? 'updated' : 'installed', dest };
|
|
336
|
+
}
|
|
337
|
+
|
|
338
|
+
// Agents and commands are rendered per host, so they are always written, never linked.
|
|
339
|
+
function installFile(item, dir, target, opts) {
|
|
340
|
+
const out = render(item, target);
|
|
341
|
+
if (!out) return null;
|
|
342
|
+
const dest = path.join(dir, out.file);
|
|
343
|
+
const exists = fs.existsSync(dest) || isSymlink(dest);
|
|
344
|
+
if (exists && !isOursFile(dest) && !opts.force) return { action: 'skipped', reason: NOT_OURS, dest };
|
|
345
|
+
if (!opts.dryRun) {
|
|
346
|
+
fs.mkdirSync(dir, { recursive: true });
|
|
347
|
+
if (exists) fs.rmSync(dest, { force: true });
|
|
348
|
+
fs.writeFileSync(dest, out.content);
|
|
349
|
+
}
|
|
350
|
+
return { action: exists ? 'updated' : 'installed', dest };
|
|
351
|
+
}
|
|
352
|
+
|
|
353
|
+
function install(opts) {
|
|
354
|
+
const selected = selectItems(opts);
|
|
355
|
+
if (![...KINDS, 'hooks', 'mcp'].some((k) => selected[k].length)) throw new Error('nothing matched your filters');
|
|
356
|
+
const results = [];
|
|
357
|
+
for (const { target, kind, dir } of destinations(opts)) {
|
|
358
|
+
for (const item of selected[kind]) {
|
|
359
|
+
const r = kind === 'skills' ? installSkill(item, dir, opts) : installFile(item, dir, target, opts);
|
|
360
|
+
if (r) results.push({ target, kind: item.kind, name: item.dir, ...r });
|
|
361
|
+
}
|
|
362
|
+
}
|
|
363
|
+
// Hosts that can't scope by path load every rule they get on every turn, so they only get rules that
|
|
364
|
+
// were chosen (--rule or a profile), never the whole library.
|
|
365
|
+
if (selected.rules.length && opts.rules) for (const host of linkedRuleHosts(opts)) results.push(...Rules.installRules(host, selected.rules, { home: opts.home || os.homedir(), dryRun: opts.dryRun }));
|
|
366
|
+
if (selected.mcp.length && !opts.dir) {
|
|
367
|
+
const all = Mcp.listMcp();
|
|
368
|
+
for (const host of mcpHosts(opts)) results.push(...Mcp.installMcp(host, selected.mcp, all, { scope: opts.scope, home: opts.home || os.homedir(), cwd: process.cwd(), dryRun: opts.dryRun }));
|
|
369
|
+
}
|
|
370
|
+
results.push(...installHooks(selected.hooks, opts));
|
|
371
|
+
report(results, opts);
|
|
372
|
+
if (!opts.json && opts.detected && opts.detected.length) console.log(`\nDetected in this project: ${opts.detected.join(', ')}.`);
|
|
373
|
+
if (!opts.json && opts.droppedHooks) console.log(`\nSkipped the profile's hooks (${opts.droppedHooks.join(', ')}): hooks install for your user only. Run the install without --project to add them.`);
|
|
374
|
+
const notes = [...new Set(results.map((r) => r.note).filter(Boolean))];
|
|
375
|
+
if (notes.length && !opts.json) console.log(`\n${notes.join('\n')}`);
|
|
376
|
+
const missing = missingRequirements(KINDS.flatMap((k) => selected[k]));
|
|
377
|
+
if (missing.length && !opts.json) {
|
|
378
|
+
console.log(`\nNote: some items expect tools that are not on your PATH:`);
|
|
379
|
+
for (const m of missing) console.log(` ${m.name}: ${m.tools.join(', ')}`);
|
|
380
|
+
}
|
|
381
|
+
if (!opts.json && !opts.dryRun) console.log('\nRestart your agent (or start a new session) so it picks up the new items.');
|
|
382
|
+
return results;
|
|
383
|
+
}
|
|
384
|
+
|
|
385
|
+
// `code-reviewer.agent.md` -> `code-reviewer`, `python.instructions.md` -> `python`, `python.mdc` -> `python`
|
|
386
|
+
const itemName = (entry) => entry.replace(/(?:\.agent|\.instructions)?\.(?:md|mdc|toml)$/, '');
|
|
387
|
+
|
|
388
|
+
function uninstall(opts) {
|
|
389
|
+
applyProfiles(opts, catalog(opts)); // `uninstall --profile x` removes only that profile's items
|
|
390
|
+
const named = KINDS.some((k) => opts[k]) || Boolean(opts.hookNames);
|
|
391
|
+
const results = [];
|
|
392
|
+
for (const { target, kind, dir } of destinations(opts)) {
|
|
393
|
+
if (named && !opts[kind]) continue;
|
|
394
|
+
if (!fs.existsSync(dir)) continue;
|
|
395
|
+
for (const entry of fs.readdirSync(dir)) {
|
|
396
|
+
const p = path.join(dir, entry);
|
|
397
|
+
const name = kind === 'skills' ? entry : itemName(entry);
|
|
398
|
+
if (named && !opts[kind].includes(name)) continue;
|
|
399
|
+
if (!(kind === 'skills' ? isOurs(p, opts) : isOursFile(p))) continue;
|
|
400
|
+
if (!opts.dryRun) fs.rmSync(p, { recursive: true, force: true });
|
|
401
|
+
results.push({ target, kind: kind.slice(0, -1), name, action: 'removed', dest: p });
|
|
402
|
+
}
|
|
403
|
+
}
|
|
404
|
+
if (!named || opts.rules) for (const host of linkedRuleHosts(opts)) results.push(...Rules.uninstallRules(host, named ? opts.rules : null, { home: opts.home || os.homedir(), dryRun: opts.dryRun }));
|
|
405
|
+
if (!opts.dir && (!named || opts.mcp)) {
|
|
406
|
+
const all = Mcp.listMcp();
|
|
407
|
+
const servers = opts.mcp ? all.filter((m) => opts.mcp.includes(m.dir)) : all;
|
|
408
|
+
const hosts = opts.targets ? opts.targets.filter((t) => Mcp.MCP_HOSTS.includes(t)) : Mcp.MCP_HOSTS;
|
|
409
|
+
for (const host of hosts) results.push(...Mcp.uninstallMcp(host, servers, all, { scope: opts.scope, home: opts.home || os.homedir(), cwd: process.cwd(), dryRun: opts.dryRun }));
|
|
410
|
+
}
|
|
411
|
+
results.push(...uninstallHooks(opts, named));
|
|
412
|
+
report(results, opts);
|
|
413
|
+
return results;
|
|
414
|
+
}
|
|
415
|
+
|
|
416
|
+
function report(results, opts) {
|
|
417
|
+
if (opts.json) return console.log(JSON.stringify(results, null, 2));
|
|
418
|
+
if (!results.length) return console.log('Nothing to do.');
|
|
419
|
+
const prefix = opts.dryRun ? '[dry-run] ' : '';
|
|
420
|
+
for (const r of results) {
|
|
421
|
+
const where = r.dest.replace(os.homedir(), '~');
|
|
422
|
+
console.log(`${prefix}${r.action.padEnd(9)} ${r.kind.padEnd(7)} ${r.name.padEnd(24)} ${where}${r.reason ? ` (${r.reason})` : ''}`);
|
|
423
|
+
}
|
|
424
|
+
}
|
|
425
|
+
|
|
426
|
+
function onPath(tool) {
|
|
427
|
+
try {
|
|
428
|
+
execFileSync(process.platform === 'win32' ? 'where' : 'which', [tool], { stdio: 'ignore' });
|
|
429
|
+
return true;
|
|
430
|
+
} catch {
|
|
431
|
+
return false;
|
|
432
|
+
}
|
|
433
|
+
}
|
|
434
|
+
|
|
435
|
+
function missingRequirements(items) {
|
|
436
|
+
const cache = {};
|
|
437
|
+
return items
|
|
438
|
+
.map((s) => ({ name: s.dir, tools: s.requires.filter((t) => (cache[t] ??= onPath(t)) === false) }))
|
|
439
|
+
.filter((m) => m.tools.length);
|
|
440
|
+
}
|
|
441
|
+
|
|
442
|
+
function list(opts) {
|
|
443
|
+
const selected = selectItems(opts);
|
|
444
|
+
const items = [...KINDS, 'hooks', 'mcp'].flatMap((k) => (k === 'hooks' || k === 'mcp' ? catalog(opts)[k] : selected[k]));
|
|
445
|
+
if (opts.json) {
|
|
446
|
+
return console.log(JSON.stringify(items.map(({ kind, dir, version, category, risk, description }) => ({ kind, name: dir, version, category, risk, description })), null, 2));
|
|
447
|
+
}
|
|
448
|
+
for (const s of items) {
|
|
449
|
+
console.log(`${s.kind.padEnd(8)} ${s.dir.padEnd(24)} v${(s.version || '?').padEnd(7)} ${String(s.category).padEnd(12)} ${s.risk}`);
|
|
450
|
+
}
|
|
451
|
+
const count = (k) => `${selected[k].length} ${k.slice(0, -1)}(s)`;
|
|
452
|
+
console.log(`\n${KINDS.map(count).join(', ')}, ${catalog(opts).hooks.length} hook(s), ${catalog(opts).mcp.length} MCP server(s). Install with: npx @ketecode/loom install (hooks: --hooks, MCP servers: --mcp <names>)`);
|
|
453
|
+
}
|
|
454
|
+
|
|
455
|
+
// Installed items for this scope, with the library's current version beside each.
|
|
456
|
+
function installed(opts) {
|
|
457
|
+
const all = catalog(opts);
|
|
458
|
+
const version = new Map([...KINDS, 'hooks', 'mcp'].flatMap((k) => (all[k] || []).map((i) => [`${k}:${i.dir}`, i.version])));
|
|
459
|
+
const rows = inventory({ scope: opts.scope, home: opts.home || os.homedir(), cwd: process.cwd(), mcpAll: all.mcp, hookNames: all.hooks.map((h) => h.dir) });
|
|
460
|
+
return rows.map((r) => ({ ...r, latest: version.get(`${r.kind}:${r.name}`) || null }));
|
|
461
|
+
}
|
|
462
|
+
|
|
463
|
+
// update: re-apply exactly what is installed, in the hosts it is installed in.
|
|
464
|
+
function update(opts) {
|
|
465
|
+
const rows = installed(opts);
|
|
466
|
+
if (!rows.length) {
|
|
467
|
+
console.log(`Nothing installed by kete-loom at ${opts.scope} scope. Run: npx @ketecode/loom install`);
|
|
468
|
+
return [];
|
|
469
|
+
}
|
|
470
|
+
const gone = [...new Set(rows.filter((r) => !r.latest && r.kind !== 'hooks' && r.kind !== 'mcp').map((r) => `${r.kind.replace(/s$/, '')} ${r.name}`))];
|
|
471
|
+
const pick = (kind) => [...new Set(rows.filter((r) => r.kind === kind && !r.linked && (r.latest || kind === 'hooks' || kind === 'mcp')).map((r) => r.name))];
|
|
472
|
+
const known = (kind, names) => names.filter((n) => catalog(opts)[kind].some((i) => i.dir === n));
|
|
473
|
+
const next = {
|
|
474
|
+
...opts,
|
|
475
|
+
force: false,
|
|
476
|
+
targets: [...new Set(rows.map((r) => r.target))],
|
|
477
|
+
skills: pick('skills'),
|
|
478
|
+
agents: pick('agents'),
|
|
479
|
+
commands: pick('commands'),
|
|
480
|
+
rules: pick('rules'),
|
|
481
|
+
hookNames: known('hooks', pick('hooks')),
|
|
482
|
+
mcp: known('mcp', pick('mcp')),
|
|
483
|
+
};
|
|
484
|
+
for (const k of ['skills', 'agents', 'commands', 'rules', 'hookNames', 'mcp']) if (!next[k].length) delete next[k];
|
|
485
|
+
const changes = rows.filter((r) => r.version && r.latest && compare(r.version, r.latest) < 0);
|
|
486
|
+
const results = install(next);
|
|
487
|
+
if (!opts.json) {
|
|
488
|
+
const versions = [...new Map(changes.map((r) => [`${r.kind}:${r.name}`, ` ${r.kind.replace(/s$/, '').padEnd(8)} ${r.name.padEnd(28)} ${r.version} -> ${r.latest}`])).values()];
|
|
489
|
+
console.log(versions.length ? `\nNew versions:\n${versions.join('\n')}` : '\nEverything was already at the latest version.');
|
|
490
|
+
const linked = rows.filter((r) => r.linked).map((r) => r.name);
|
|
491
|
+
if (linked.length) console.log(`Linked skills are live already and were left alone: ${[...new Set(linked)].join(', ')}.`);
|
|
492
|
+
if (gone.length) console.log(`No longer in Kete Loom, left in place (remove with uninstall): ${gone.join(', ')}.`);
|
|
493
|
+
}
|
|
494
|
+
return results;
|
|
495
|
+
}
|
|
496
|
+
|
|
497
|
+
function outdated(opts) {
|
|
498
|
+
const rows = installed(opts).filter((r) => r.version && r.latest && compare(r.version, r.latest) < 0);
|
|
499
|
+
if (opts.json) {
|
|
500
|
+
console.log(JSON.stringify(rows.map(({ target, kind, name, version, latest }) => ({ target, kind, name, version, latest })), null, 2));
|
|
501
|
+
return rows.length ? 1 : 0;
|
|
502
|
+
}
|
|
503
|
+
if (!rows.length) {
|
|
504
|
+
console.log('Everything kete-loom installed is up to date.');
|
|
505
|
+
return 0;
|
|
506
|
+
}
|
|
507
|
+
for (const r of rows) console.log(`${r.kind.replace(/s$/, '').padEnd(8)} ${r.name.padEnd(28)} ${r.version.padEnd(8)} -> ${r.latest.padEnd(8)} ${r.target}`);
|
|
508
|
+
console.log('\nRun: npx @ketecode/loom@latest update');
|
|
509
|
+
return 1;
|
|
510
|
+
}
|
|
511
|
+
|
|
512
|
+
// check: lint items you wrote, wherever they live.
|
|
513
|
+
function itemsAt(target) {
|
|
514
|
+
const p = path.resolve(target);
|
|
515
|
+
if (!fs.existsSync(p)) throw new Error(`${target} does not exist`);
|
|
516
|
+
if (fs.statSync(p).isFile()) {
|
|
517
|
+
if (!p.endsWith('.md')) throw new Error(`${target}: expected a .md command or rule, or a folder`);
|
|
518
|
+
return [path.basename(path.dirname(p)) === 'rules' ? loadRule(p) : loadCommand(p)];
|
|
519
|
+
}
|
|
520
|
+
const kinds = [['SKILL.md', loadSkill], ['AGENT.md', loadAgent], ['HOOK.md', loadHook]];
|
|
521
|
+
const own = kinds.find(([f]) => fs.existsSync(path.join(p, f)));
|
|
522
|
+
if (own) return [own[1](p)];
|
|
523
|
+
return fs.readdirSync(p).sort().flatMap((entry) => {
|
|
524
|
+
const child = path.join(p, entry);
|
|
525
|
+
if (fs.statSync(child).isDirectory()) {
|
|
526
|
+
const k = kinds.find(([f]) => fs.existsSync(path.join(child, f)));
|
|
527
|
+
return k ? [k[1](child)] : [];
|
|
528
|
+
}
|
|
529
|
+
return entry.endsWith('.md') && !/^(README|CHANGELOG|AGENTS|CLAUDE)\.md$/i.test(entry) ? [path.basename(p) === 'rules' ? loadRule(child) : loadCommand(child)] : [];
|
|
530
|
+
});
|
|
531
|
+
}
|
|
532
|
+
|
|
533
|
+
function check(opts) {
|
|
534
|
+
const target = opts._[1];
|
|
535
|
+
if (!target) throw new Error('usage: kete-loom check <path to a skill, agent, hook, command or rule, or a folder of them>');
|
|
536
|
+
const items = itemsAt(target);
|
|
537
|
+
if (!items.length) throw new Error(`no skills, agents, commands, rules or hooks found in ${target}`);
|
|
538
|
+
let errors = 0;
|
|
539
|
+
const out = items.map((item) => {
|
|
540
|
+
const r = lintItem(item);
|
|
541
|
+
errors += r.errors.length;
|
|
542
|
+
return { kind: item.kind, name: item.dir, path: item.path, ...r };
|
|
543
|
+
});
|
|
544
|
+
if (opts.json) console.log(JSON.stringify(out, null, 2));
|
|
545
|
+
else {
|
|
546
|
+
for (const r of out) {
|
|
547
|
+
if (!r.errors.length && !r.warnings.length) console.log(`✓ ${r.kind.padEnd(7)} ${r.name}`);
|
|
548
|
+
for (const e of r.errors) console.log(`✗ ${r.kind.padEnd(7)} ${r.name} ${e}`);
|
|
549
|
+
for (const w of r.warnings) console.log(`! ${r.kind.padEnd(7)} ${r.name} ${w}`);
|
|
550
|
+
}
|
|
551
|
+
console.log(`\n${out.length} item(s), ${errors} error(s). The rules are in docs/SKILL_SPEC.md of the Kete Loom repository.`);
|
|
552
|
+
}
|
|
553
|
+
return errors ? 1 : 0;
|
|
554
|
+
}
|
|
555
|
+
|
|
556
|
+
function auditCmd(opts) {
|
|
557
|
+
const all = catalog(opts);
|
|
558
|
+
const r = audit({ cwd: process.cwd(), home: opts.home || os.homedir(), catalog: all });
|
|
559
|
+
if (opts.json) console.log(JSON.stringify(r, null, 2));
|
|
560
|
+
else {
|
|
561
|
+
console.log(`Agent readiness for ${r.root.replace(os.homedir(), '~')}: ${r.score}/100\n`);
|
|
562
|
+
const mark = { pass: '✓', warn: '!', fail: '✗' };
|
|
563
|
+
for (const c of r.checks) {
|
|
564
|
+
console.log(`${mark[c.status]} ${c.title}: ${c.detail}`);
|
|
565
|
+
if (c.fix) console.log(` fix: ${c.fix}`);
|
|
566
|
+
}
|
|
567
|
+
}
|
|
568
|
+
return r.checks.some((c) => c.status === 'fail') ? 1 : 0;
|
|
569
|
+
}
|
|
570
|
+
|
|
571
|
+
function profiles(opts) {
|
|
572
|
+
const all = loadProfiles();
|
|
573
|
+
const items = catalog(opts);
|
|
574
|
+
const rows = Object.entries(all).map(([name, p]) => {
|
|
575
|
+
const r = resolveProfiles([name], { catalog: items, cwd: process.cwd() });
|
|
576
|
+
const count = r.all ? 'everything' : ['skills', 'agents', 'commands', 'hooks'].map((k) => `${r[k].size} ${k}`).join(', ');
|
|
577
|
+
return { name, description: p.description, count, detects: Boolean(p.detect) || (p.extends || []).some((e) => all[e] && all[e].detect) };
|
|
578
|
+
});
|
|
579
|
+
if (opts.json) return console.log(JSON.stringify(rows, null, 2));
|
|
580
|
+
for (const r of rows) console.log(`${r.name.padEnd(10)} ${r.description}\n${' '.repeat(11)}${r.count} in this folder${r.detects ? ' (includes packs detected here)' : ''}\n`);
|
|
581
|
+
console.log('Install one with: npx @ketecode/loom install --profile <name>');
|
|
582
|
+
}
|
|
583
|
+
|
|
584
|
+
// What doctor --fix repairs: the hook runtime (missing or older than this package's copy), hooks
|
|
585
|
+
// registered with a host but no longer in the catalog, and temp files left by an interrupted write.
|
|
586
|
+
function hookProblems(home, hooks, hookRows) {
|
|
587
|
+
const problems = [];
|
|
588
|
+
const dir = Hooks.runtimeDir(home);
|
|
589
|
+
const same = (a, b) => fs.existsSync(a) && fs.existsSync(b) && fs.readFileSync(a).equals(fs.readFileSync(b));
|
|
590
|
+
const used = new Set(hookRows.flatMap((r) => r.hooks));
|
|
591
|
+
const stale = hooks.filter((h) => used.has(h.dir) && !same(path.join(h.path, 'hook.js'), path.join(dir, h.dir, 'hook.js')));
|
|
592
|
+
const runnerStale = used.size && !same(path.join(HOOKS_DIR, 'run.js'), path.join(dir, 'run.js'));
|
|
593
|
+
if (stale.length || runnerStale) {
|
|
594
|
+
const names = [...(runnerStale ? ['run.js'] : []), ...stale.map((h) => h.dir)];
|
|
595
|
+
problems.push({ what: `hook runtime in ${dir.replace(os.homedir(), '~')} is missing or out of date: ${names.join(', ')}`, fix: () => Hooks.installRuntime(stale, { home, sourceDir: HOOKS_DIR }) });
|
|
596
|
+
}
|
|
597
|
+
const known = new Set(hooks.map((h) => h.dir));
|
|
598
|
+
for (const host of Hooks.HOOK_HOSTS) {
|
|
599
|
+
// Shared config files name every hook we registered, so one dropped from the catalog shows up here.
|
|
600
|
+
// shortcut: Copilot and OpenCode keep one file per hook, found only by known names, so they're skipped.
|
|
601
|
+
if (Hooks.HOSTS[host].own) continue;
|
|
602
|
+
for (const name of Hooks.registered(host, { home }).filter((n) => !known.has(n))) {
|
|
603
|
+
problems.push({ what: `${host} runs hook "${name}", which this version of kete-loom no longer has`, fix: () => Hooks.unregister(host, name, { home }) });
|
|
604
|
+
}
|
|
605
|
+
const tmp = `${Hooks.HOSTS[host].file(home, 'x')}.kete-loom-tmp`;
|
|
606
|
+
if (fs.existsSync(tmp)) problems.push({ what: `leftover temp file ${tmp.replace(os.homedir(), '~')}`, fix: () => fs.rmSync(tmp) });
|
|
607
|
+
}
|
|
608
|
+
return problems;
|
|
609
|
+
}
|
|
610
|
+
|
|
611
|
+
function doctor(opts) {
|
|
612
|
+
const home = opts.home || os.homedir();
|
|
613
|
+
const rows = [];
|
|
614
|
+
for (const scope of ['user', 'project']) {
|
|
615
|
+
for (const target of Object.keys(TARGETS)) {
|
|
616
|
+
for (const kind of KINDS) {
|
|
617
|
+
const dir = resolveTarget(target, { scope, home, cwd: process.cwd(), kind });
|
|
618
|
+
if (!dir) continue;
|
|
619
|
+
const entries = fs.existsSync(dir) ? fs.readdirSync(dir) : [];
|
|
620
|
+
const ours = kind === 'skills'
|
|
621
|
+
? entries.filter((e) => isOurs(path.join(dir, e), opts))
|
|
622
|
+
: entries.filter((e) => isOursFile(path.join(dir, e))).map(itemName);
|
|
623
|
+
rows.push({ scope, target, kind, dir, items: ours });
|
|
624
|
+
}
|
|
625
|
+
}
|
|
626
|
+
}
|
|
627
|
+
if (opts.json) return console.log(JSON.stringify(rows, null, 2));
|
|
628
|
+
console.log('Installed kete-loom items:\n');
|
|
629
|
+
for (const r of rows.filter((x) => x.items.length)) {
|
|
630
|
+
console.log(` [${r.scope}] ${r.target.padEnd(9)} ${r.kind.padEnd(9)} ${r.dir.replace(os.homedir(), '~')} (${r.items.length})`);
|
|
631
|
+
}
|
|
632
|
+
if (!rows.some((r) => r.items.length)) console.log(' none yet. Run: npx @ketecode/loom install');
|
|
633
|
+
const linked = Rules.RULE_HOSTS.map((t) => ({ target: t, rules: Rules.installedNames(Rules.HOSTS[t].dir(home)) })).filter((r) => r.rules.length);
|
|
634
|
+
if (linked.length) {
|
|
635
|
+
console.log('\nRules loaded through instructions files:');
|
|
636
|
+
for (const r of linked) console.log(` ${r.target.padEnd(9)} ${r.rules.join(', ')}`);
|
|
637
|
+
}
|
|
638
|
+
const hooks = listHooks();
|
|
639
|
+
const hookNames = hooks.map((h) => h.dir);
|
|
640
|
+
const hookRows = Hooks.HOOK_HOSTS.map((t) => ({ target: t, hooks: Hooks.registered(t, { home, names: hookNames }) })).filter((r) => r.hooks.length);
|
|
641
|
+
if (hookRows.length) {
|
|
642
|
+
console.log('\nHooks:');
|
|
643
|
+
for (const r of hookRows) console.log(` ${r.target.padEnd(9)} ${r.hooks.join(', ')}`);
|
|
644
|
+
}
|
|
645
|
+
const problems = hookProblems(home, hooks, hookRows);
|
|
646
|
+
if (problems.length) {
|
|
647
|
+
console.log(opts.fix ? '\nRepaired:' : '\nProblems:');
|
|
648
|
+
for (const p of problems) {
|
|
649
|
+
if (opts.fix && !opts.dryRun) p.fix();
|
|
650
|
+
console.log(` ${opts.fix ? '✓' : '!'} ${p.what}`);
|
|
651
|
+
}
|
|
652
|
+
if (!opts.fix) console.log(' Run "kete-loom doctor --fix" to repair these.');
|
|
653
|
+
}
|
|
654
|
+
console.log('\nSkills visible to each host:');
|
|
655
|
+
for (const [host, reads] of Object.entries(HOST_READS)) {
|
|
656
|
+
const seen = new Set(rows.filter((r) => r.kind === 'skills' && reads.includes(r.target)).flatMap((r) => r.items));
|
|
657
|
+
console.log(` ${host.padEnd(15)} ${seen.size} skill(s)`);
|
|
658
|
+
}
|
|
659
|
+
const all = catalog(opts);
|
|
660
|
+
const missing = missingRequirements(KINDS.flatMap((k) => all[k]));
|
|
661
|
+
if (missing.length) {
|
|
662
|
+
console.log('\nMissing tools:');
|
|
663
|
+
for (const m of missing) console.log(` ${m.name}: ${m.tools.join(', ')}`);
|
|
664
|
+
}
|
|
665
|
+
}
|
|
666
|
+
|
|
667
|
+
function main(argv) {
|
|
668
|
+
let opts;
|
|
669
|
+
try {
|
|
670
|
+
opts = parseArgs(argv);
|
|
671
|
+
} catch (e) {
|
|
672
|
+
console.error(`error: ${e.message}\nRun "kete-loom help" for usage.`);
|
|
673
|
+
return 2;
|
|
674
|
+
}
|
|
675
|
+
const cmd = opts._[0] || 'help';
|
|
676
|
+
try {
|
|
677
|
+
switch (cmd) {
|
|
678
|
+
case 'install':
|
|
679
|
+
install(opts);
|
|
680
|
+
break;
|
|
681
|
+
case 'update':
|
|
682
|
+
update(opts);
|
|
683
|
+
break;
|
|
684
|
+
case 'outdated':
|
|
685
|
+
return outdated(opts);
|
|
686
|
+
case 'audit':
|
|
687
|
+
return auditCmd(opts);
|
|
688
|
+
case 'check':
|
|
689
|
+
return check(opts);
|
|
690
|
+
case 'uninstall':
|
|
691
|
+
case 'remove':
|
|
692
|
+
uninstall(opts);
|
|
693
|
+
break;
|
|
694
|
+
case 'list':
|
|
695
|
+
case 'ls':
|
|
696
|
+
list(opts);
|
|
697
|
+
break;
|
|
698
|
+
case 'profiles':
|
|
699
|
+
profiles(opts);
|
|
700
|
+
break;
|
|
701
|
+
case 'doctor':
|
|
702
|
+
doctor(opts);
|
|
703
|
+
break;
|
|
704
|
+
case 'version':
|
|
705
|
+
console.log(pkg.version);
|
|
706
|
+
break;
|
|
707
|
+
case 'help':
|
|
708
|
+
help();
|
|
709
|
+
break;
|
|
710
|
+
default:
|
|
711
|
+
console.error(`unknown command "${cmd}". Run "kete-loom help".`);
|
|
712
|
+
return 2;
|
|
713
|
+
}
|
|
714
|
+
} catch (e) {
|
|
715
|
+
console.error(`error: ${e.message}`);
|
|
716
|
+
return 1;
|
|
717
|
+
}
|
|
718
|
+
return 0;
|
|
719
|
+
}
|
|
720
|
+
|
|
721
|
+
if (require.main === module) process.exitCode = main(process.argv.slice(2));
|
|
722
|
+
|
|
723
|
+
module.exports = { main, parseArgs, install, uninstall, MARKER };
|