@dsalazardev/ai-hub-cli 0.0.0-stage → 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -0
- package/NOTICE.md +34 -0
- package/README.md +64 -2
- package/agents/cpp-build-resolver.md +25 -0
- package/agents/cpp-reviewer.md +28 -0
- package/agents/csharp-reviewer.md +28 -0
- package/agents/django-build-resolver.md +25 -0
- package/agents/django-reviewer.md +28 -0
- package/agents/explorer-domain.md +28 -0
- package/agents/fastapi-reviewer.md +28 -0
- package/agents/flutter-build-resolver.md +25 -0
- package/agents/flutter-reviewer.md +28 -0
- package/agents/go-build-resolver.md +25 -0
- package/agents/go-reviewer.md +28 -0
- package/agents/implementer-backend.md +30 -0
- package/agents/implementer-frontend.md +30 -0
- package/agents/java-build-resolver.md +26 -0
- package/agents/java-reviewer.md +29 -0
- package/agents/kotlin-build-resolver.md +25 -0
- package/agents/kotlin-reviewer.md +28 -0
- package/agents/mle-reviewer.md +28 -0
- package/agents/php-reviewer.md +29 -0
- package/agents/postgres-reviewer.md +28 -0
- package/agents/python-reviewer.md +28 -0
- package/agents/pytorch-build-resolver.md +25 -0
- package/agents/rag-reviewer.md +28 -0
- package/agents/react-build-resolver.md +26 -0
- package/agents/react-reviewer.md +29 -0
- package/agents/reviewer-architecture.md +32 -0
- package/agents/reviewer-tests.md +31 -0
- package/agents/rust-build-resolver.md +25 -0
- package/agents/rust-reviewer.md +28 -0
- package/agents/spec-author.md +36 -0
- package/agents/spec-miner.md +14 -0
- package/agents/swift-build-resolver.md +25 -0
- package/agents/swift-reviewer.md +28 -0
- package/agents/typescript-reviewer.md +28 -0
- package/agents/vue-reviewer.md +28 -0
- package/dist/backup/snapshots.d.ts +24 -0
- package/dist/backup/snapshots.js +171 -0
- package/dist/bin/ai-hub.d.ts +2 -0
- package/dist/bin/ai-hub.js +11 -0
- package/dist/cli/args.d.ts +4 -0
- package/dist/cli/args.js +63 -0
- package/dist/cli/context.d.ts +7 -0
- package/dist/cli/context.js +74 -0
- package/dist/cli/doctor.d.ts +14 -0
- package/dist/cli/doctor.js +200 -0
- package/dist/cli/drift.d.ts +2 -0
- package/dist/cli/drift.js +34 -0
- package/dist/cli/items.d.ts +5 -0
- package/dist/cli/items.js +10 -0
- package/dist/cli/legacy.d.ts +3 -0
- package/dist/cli/legacy.js +18 -0
- package/dist/cli/maintenance.d.ts +8 -0
- package/dist/cli/maintenance.js +262 -0
- package/dist/cli/memory.d.ts +2 -0
- package/dist/cli/memory.js +84 -0
- package/dist/cli/onboarding.d.ts +17 -0
- package/dist/cli/onboarding.js +234 -0
- package/dist/cli/run.d.ts +15 -0
- package/dist/cli/run.js +183 -0
- package/dist/cli/source.d.ts +5 -0
- package/dist/cli/source.js +22 -0
- package/dist/cli/trunk.d.ts +8 -0
- package/dist/cli/trunk.js +54 -0
- package/dist/cli/types.d.ts +17 -0
- package/dist/cli/types.js +4 -0
- package/dist/cli/worktrees.d.ts +11 -0
- package/dist/cli/worktrees.js +141 -0
- package/dist/engine/engine.d.ts +48 -0
- package/dist/engine/engine.js +114 -0
- package/dist/engine/gates.d.ts +2 -0
- package/dist/engine/gates.js +93 -0
- package/dist/frontmatter.d.ts +11 -0
- package/dist/frontmatter.js +30 -0
- package/dist/harness/guards/adapters/context.d.ts +19 -0
- package/dist/harness/guards/adapters/context.js +153 -0
- package/dist/harness/guards/adapters/hermes.d.ts +13 -0
- package/dist/harness/guards/adapters/hermes.js +18 -0
- package/dist/harness/guards/adapters/hooks.d.ts +25 -0
- package/dist/harness/guards/adapters/hooks.js +52 -0
- package/dist/harness/guards/branch.d.ts +5 -0
- package/dist/harness/guards/branch.js +43 -0
- package/dist/harness/guards/danger.d.ts +13 -0
- package/dist/harness/guards/danger.js +157 -0
- package/dist/harness/guards/index.d.ts +6 -0
- package/dist/harness/guards/index.js +6 -0
- package/dist/harness/guards/preflight.d.ts +14 -0
- package/dist/harness/guards/preflight.js +37 -0
- package/dist/harness/guards/ship.d.ts +2 -0
- package/dist/harness/guards/ship.js +35 -0
- package/dist/harness/guards/trunk.d.ts +5 -0
- package/dist/harness/guards/trunk.js +41 -0
- package/dist/harness/guards/types.d.ts +50 -0
- package/dist/harness/guards/types.js +1 -0
- package/dist/harness/memory/ledger.d.ts +53 -0
- package/dist/harness/memory/ledger.js +136 -0
- package/dist/harness/memory/state.d.ts +35 -0
- package/dist/harness/memory/state.js +121 -0
- package/dist/harness/worktree/reaper.d.ts +32 -0
- package/dist/harness/worktree/reaper.js +54 -0
- package/dist/manifest/build.d.ts +1 -0
- package/dist/manifest/build.js +1 -0
- package/dist/manifest/cli.d.ts +2 -0
- package/dist/manifest/cli.js +44 -0
- package/dist/manifest/dispatch.d.ts +13 -0
- package/dist/manifest/dispatch.js +36 -0
- package/dist/manifest/labels.d.ts +15 -0
- package/dist/manifest/labels.js +70 -0
- package/dist/manifest/manifest.d.ts +113 -0
- package/dist/manifest/manifest.js +202 -0
- package/dist/package-info.d.ts +4 -0
- package/dist/package-info.js +7 -0
- package/dist/paths.d.ts +33 -0
- package/dist/paths.js +123 -0
- package/dist/presets/detect.d.ts +24 -0
- package/dist/presets/detect.js +116 -0
- package/dist/presets/materialize.d.ts +18 -0
- package/dist/presets/materialize.js +101 -0
- package/dist/presets/resolve.d.ts +37 -0
- package/dist/presets/resolve.js +83 -0
- package/dist/presets/schema.d.ts +57 -0
- package/dist/presets/schema.js +68 -0
- package/dist/source-checkout.d.ts +8 -0
- package/dist/source-checkout.js +19 -0
- package/dist/sync/config.d.ts +47 -0
- package/dist/sync/config.js +85 -0
- package/dist/sync/lock.d.ts +16 -0
- package/dist/sync/lock.js +43 -0
- package/dist/sync/render.d.ts +18 -0
- package/dist/sync/render.js +255 -0
- package/dist/sync/sync.d.ts +38 -0
- package/dist/sync/sync.js +288 -0
- package/dist/sync/targets.d.ts +24 -0
- package/dist/sync/targets.js +78 -0
- package/engine/coupling.json +4 -0
- package/engine/engine.yaml +250 -0
- package/engine/legacy-paths.json +4 -0
- package/engine/preflight.md +11 -0
- package/manifest.json +393 -0
- package/package.json +61 -4
- package/presets/angular-express/harness/rules/01-zero-any.sh +25 -0
- package/presets/angular-express/harness/rules/02-no-ng-module.sh +21 -0
- package/presets/angular-express/harness/rules/03-no-constructor-injection.sh +21 -0
- package/presets/angular-express/harness/rules/04-no-legacy-directives.sh +21 -0
- package/presets/angular-express/harness/rules/05-no-dolibarrdal-inheritance.sh +25 -0
- package/presets/angular-express/harness/rules/06-no-todos.sh +22 -0
- package/presets/angular-express/harness/run-all.sh +13 -0
- package/presets/angular-express/preset.yaml +55 -0
- package/presets/angular-express/references/common-imports-catalog.md +146 -0
- package/presets/angular-express/references/fichajes-migration-notes.md +57 -0
- package/presets/angular-express/references/module-implementation-flow.md +260 -0
- package/presets/angular-express/references/products-coding-standard.md +143 -0
- package/presets/angular-express/references/products-module-blueprint.md +860 -0
- package/presets/angular-express/references/replicate-module-checklist.md +72 -0
- package/presets/angular-express/references/users-migration-notes.md +172 -0
- package/presets/angular-express/rules/architecture.md +8 -0
- package/presets/angular-express/rules/backend.md +4 -0
- package/presets/angular-express/rules/frontend.md +53 -0
- package/presets/angular-express/skills/angular-developer/SKILL.md +130 -0
- package/presets/angular-express/skills/angular-developer/references/angular-animations.md +160 -0
- package/presets/angular-express/skills/angular-developer/references/angular-aria.md +410 -0
- package/presets/angular-express/skills/angular-developer/references/cli.md +86 -0
- package/presets/angular-express/skills/angular-developer/references/component-harnesses.md +59 -0
- package/presets/angular-express/skills/angular-developer/references/component-styling.md +91 -0
- package/presets/angular-express/skills/angular-developer/references/components.md +117 -0
- package/presets/angular-express/skills/angular-developer/references/creating-services.md +97 -0
- package/presets/angular-express/skills/angular-developer/references/data-resolvers.md +69 -0
- package/presets/angular-express/skills/angular-developer/references/define-routes.md +67 -0
- package/presets/angular-express/skills/angular-developer/references/defining-providers.md +72 -0
- package/presets/angular-express/skills/angular-developer/references/di-fundamentals.md +120 -0
- package/presets/angular-express/skills/angular-developer/references/e2e-testing.md +66 -0
- package/presets/angular-express/skills/angular-developer/references/effects.md +83 -0
- package/presets/angular-express/skills/angular-developer/references/hierarchical-injectors.md +43 -0
- package/presets/angular-express/skills/angular-developer/references/host-elements.md +80 -0
- package/presets/angular-express/skills/angular-developer/references/injection-context.md +63 -0
- package/presets/angular-express/skills/angular-developer/references/inputs.md +101 -0
- package/presets/angular-express/skills/angular-developer/references/linked-signal.md +59 -0
- package/presets/angular-express/skills/angular-developer/references/loading-strategies.md +61 -0
- package/presets/angular-express/skills/angular-developer/references/mcp.md +106 -0
- package/presets/angular-express/skills/angular-developer/references/migrations.md +30 -0
- package/presets/angular-express/skills/angular-developer/references/navigate-to-routes.md +69 -0
- package/presets/angular-express/skills/angular-developer/references/outputs.md +86 -0
- package/presets/angular-express/skills/angular-developer/references/reactive-forms.md +122 -0
- package/presets/angular-express/skills/angular-developer/references/rendering-strategies.md +44 -0
- package/presets/angular-express/skills/angular-developer/references/resource.md +74 -0
- package/presets/angular-express/skills/angular-developer/references/route-animations.md +56 -0
- package/presets/angular-express/skills/angular-developer/references/route-guards.md +52 -0
- package/presets/angular-express/skills/angular-developer/references/router-lifecycle.md +45 -0
- package/presets/angular-express/skills/angular-developer/references/router-testing.md +87 -0
- package/presets/angular-express/skills/angular-developer/references/show-routes-with-outlets.md +68 -0
- package/presets/angular-express/skills/angular-developer/references/signal-forms.md +897 -0
- package/presets/angular-express/skills/angular-developer/references/signals-overview.md +94 -0
- package/presets/angular-express/skills/angular-developer/references/tailwind-css.md +69 -0
- package/presets/angular-express/skills/angular-developer/references/template-driven-forms.md +114 -0
- package/presets/angular-express/skills/angular-developer/references/testing-fundamentals.md +66 -0
- package/presets/angular-express/skills/angular-new-app/SKILL.md +62 -0
- package/presets/angular-express/skills/frontend-design/LICENSE.txt +177 -0
- package/presets/angular-express/skills/frontend-design/SKILL.md +55 -0
- package/presets/angular-express/skills/onna-architecture-angular/SKILL.md +229 -0
- package/presets/angular-express/skills/onna-architecture-bff/SKILL.md +446 -0
- package/presets/angular-express/skills/onna-architecture-common/SKILL.md +313 -0
- package/presets/angular-express/skills/onna-design-system/SKILL.md +615 -0
- package/presets/base/preset.yaml +27 -0
- package/presets/base/rules/core.md +35 -0
- package/presets/generic-ts/preset.yaml +46 -0
- package/presets/python/preset.yaml +47 -0
- package/presets/python/rules/python.md +10 -0
- package/schema/engine.schema.json +73 -0
- package/schema/manifest.schema.json +140 -0
- package/schema/preset.schema.json +98 -0
- package/schema/state.schema.json +27 -0
- package/skills/shared/ab-testing/SKILL.md +159 -0
- package/skills/shared/ab-testing/evals/README.md +8 -0
- package/skills/shared/ab-testing/evals/cases.yaml +49 -0
- package/skills/shared/ab-testing/references/pitfalls.md +74 -0
- package/skills/shared/ab-testing/references/sample-size-and-cuped.md +128 -0
- package/skills/shared/ab-testing/scripts/verify.sh +89 -0
- package/skills/shared/accessibility/SKILL.md +216 -0
- package/skills/shared/accessibility/evals/README.md +3 -0
- package/skills/shared/accessibility/evals/cases.yaml +47 -0
- package/skills/shared/accessibility/references/aria-patterns.md +113 -0
- package/skills/shared/accessibility/references/wcag22-checklist.md +83 -0
- package/skills/shared/accessibility/scripts/verify.sh +103 -0
- package/skills/shared/agent-eval/SKILL.md +187 -0
- package/skills/shared/agent-eval/evals/README.md +12 -0
- package/skills/shared/agent-eval/evals/cases.yaml +45 -0
- package/skills/shared/agent-eval/references/judge-design.md +118 -0
- package/skills/shared/agent-eval/references/runner-and-gate.md +183 -0
- package/skills/shared/agent-eval/scripts/verify.sh +161 -0
- package/skills/shared/agent-safety/SKILL.md +169 -0
- package/skills/shared/agent-safety/evals/README.md +12 -0
- package/skills/shared/agent-safety/evals/cases.yaml +46 -0
- package/skills/shared/agent-safety/references/threat-model.md +51 -0
- package/skills/shared/analyze/SKILL.md +123 -0
- package/skills/shared/analyze/evals/README.md +72 -0
- package/skills/shared/analyze/evals/cases.yaml +74 -0
- package/skills/shared/angular/SKILL.md +275 -0
- package/skills/shared/angular/evals/README.md +3 -0
- package/skills/shared/angular/evals/cases.yaml +38 -0
- package/skills/shared/angular/references/migration.md +81 -0
- package/skills/shared/angular/references/signals-rxjs.md +92 -0
- package/skills/shared/angular/scripts/verify.sh +122 -0
- package/skills/shared/api-connector-builder/SKILL.md +268 -0
- package/skills/shared/api-connector-builder/evals/README.md +11 -0
- package/skills/shared/api-connector-builder/evals/cases.yaml +47 -0
- package/skills/shared/api-connector-builder/references/auth-flows.md +132 -0
- package/skills/shared/api-connector-builder/references/pagination.md +144 -0
- package/skills/shared/api-connector-builder/scripts/verify.sh +172 -0
- package/skills/shared/api-design/SKILL.md +182 -0
- package/skills/shared/api-design/evals/README.md +3 -0
- package/skills/shared/api-design/evals/cases.yaml +45 -0
- package/skills/shared/api-design/references/graphql-design.md +70 -0
- package/skills/shared/api-design/references/openapi-contract.md +86 -0
- package/skills/shared/api-design/references/rest-conventions.md +63 -0
- package/skills/shared/api-design/references/versioning-and-evolution.md +49 -0
- package/skills/shared/api-design/scripts/verify.sh +138 -0
- package/skills/shared/astro/SKILL.md +257 -0
- package/skills/shared/astro/evals/README.md +3 -0
- package/skills/shared/astro/evals/cases.yaml +41 -0
- package/skills/shared/astro/references/content-layer.md +118 -0
- package/skills/shared/astro/references/deploy-and-integrations.md +163 -0
- package/skills/shared/astro/scripts/verify.sh +137 -0
- package/skills/shared/author-skill/SKILL.md +194 -0
- package/skills/shared/author-skill/evals/README.md +66 -0
- package/skills/shared/author-skill/evals/cases.yaml +75 -0
- package/skills/shared/author-skill/references/description-recipe.md +85 -0
- package/skills/shared/author-skill/references/eval-authoring.md +108 -0
- package/skills/shared/author-skill/references/skill-conventions.md +95 -0
- package/skills/shared/automation-flows/SKILL.md +122 -0
- package/skills/shared/automation-flows/evals/README.md +5 -0
- package/skills/shared/automation-flows/evals/cases.yaml +44 -0
- package/skills/shared/automation-flows/references/error-handling.md +58 -0
- package/skills/shared/automation-flows/references/n8n-workflow-json.md +63 -0
- package/skills/shared/automation-flows/scripts/verify.sh +78 -0
- package/skills/shared/aws-essentials/SKILL.md +206 -0
- package/skills/shared/aws-essentials/evals/README.md +10 -0
- package/skills/shared/aws-essentials/evals/cases.yaml +44 -0
- package/skills/shared/aws-essentials/references/iam-least-privilege.md +134 -0
- package/skills/shared/aws-essentials/references/rds-cloudfront-recipes.md +127 -0
- package/skills/shared/aws-essentials/scripts/verify.sh +99 -0
- package/skills/shared/backups/SKILL.md +131 -0
- package/skills/shared/backups/evals/README.md +3 -0
- package/skills/shared/backups/evals/cases.yaml +42 -0
- package/skills/shared/backups/references/engine-recipes.md +121 -0
- package/skills/shared/backups/references/restore-runbook.md +65 -0
- package/skills/shared/backups/scripts/verify.sh +80 -0
- package/skills/shared/bash-scripting/SKILL.md +227 -0
- package/skills/shared/bash-scripting/evals/README.md +3 -0
- package/skills/shared/bash-scripting/evals/cases.yaml +45 -0
- package/skills/shared/bash-scripting/references/portability.md +97 -0
- package/skills/shared/bash-scripting/scripts/verify.sh +140 -0
- package/skills/shared/building-agents/SKILL.md +386 -0
- package/skills/shared/building-agents/evals/README.md +68 -0
- package/skills/shared/building-agents/evals/cases.yaml +60 -0
- package/skills/shared/building-agents/references/agent-loops-and-harness.md +371 -0
- package/skills/shared/building-agents/references/evals-and-observability.md +420 -0
- package/skills/shared/building-agents/references/mcp-servers.md +294 -0
- package/skills/shared/building-agents/references/provider-abstraction.md +489 -0
- package/skills/shared/building-agents/references/tools-and-rag.md +417 -0
- package/skills/shared/building-agents/scripts/verify.sh +121 -0
- package/skills/shared/chatbot/SKILL.md +151 -0
- package/skills/shared/chatbot/evals/README.md +13 -0
- package/skills/shared/chatbot/evals/cases.yaml +43 -0
- package/skills/shared/chatbot/references/handoff-and-sales.md +71 -0
- package/skills/shared/chatbot/references/system-prompt-and-guardrails.md +78 -0
- package/skills/shared/chatbot/scripts/verify.sh +162 -0
- package/skills/shared/chrome-extension/SKILL.md +169 -0
- package/skills/shared/chrome-extension/evals/README.md +12 -0
- package/skills/shared/chrome-extension/evals/cases.yaml +40 -0
- package/skills/shared/chrome-extension/references/store-and-migration.md +84 -0
- package/skills/shared/chrome-extension/scripts/verify.sh +62 -0
- package/skills/shared/clarify/SKILL.md +161 -0
- package/skills/shared/clarify/evals/README.md +70 -0
- package/skills/shared/clarify/evals/cases.yaml +71 -0
- package/skills/shared/clickhouse-analytics/SKILL.md +159 -0
- package/skills/shared/clickhouse-analytics/evals/README.md +3 -0
- package/skills/shared/clickhouse-analytics/evals/cases.yaml +45 -0
- package/skills/shared/clickhouse-analytics/references/ingestion-and-mvs.md +109 -0
- package/skills/shared/clickhouse-analytics/references/query-optimization.md +76 -0
- package/skills/shared/clickhouse-analytics/references/schema-and-engines.md +63 -0
- package/skills/shared/clickhouse-analytics/scripts/verify.sh +109 -0
- package/skills/shared/cloudflare/SKILL.md +186 -0
- package/skills/shared/cloudflare/evals/README.md +15 -0
- package/skills/shared/cloudflare/evals/cases.yaml +46 -0
- package/skills/shared/cloudflare/references/storage-primitives.md +104 -0
- package/skills/shared/cloudflare/references/wrangler-config.md +91 -0
- package/skills/shared/cloudflare/scripts/verify.sh +133 -0
- package/skills/shared/code-review/SKILL.md +132 -0
- package/skills/shared/code-review/evals/README.md +3 -0
- package/skills/shared/code-review/evals/cases.yaml +55 -0
- package/skills/shared/code-review/references/pr-workflow.md +67 -0
- package/skills/shared/codebase-onboarding/SKILL.md +128 -0
- package/skills/shared/codebase-onboarding/evals/README.md +3 -0
- package/skills/shared/codebase-onboarding/evals/cases.yaml +69 -0
- package/skills/shared/codebase-onboarding/references/recon-playbook.md +57 -0
- package/skills/shared/codebase-onboarding/scripts/verify.sh +54 -0
- package/skills/shared/compose-multiplatform/SKILL.md +198 -0
- package/skills/shared/compose-multiplatform/evals/README.md +3 -0
- package/skills/shared/compose-multiplatform/evals/cases.yaml +40 -0
- package/skills/shared/compose-multiplatform/references/ios-interop.md +91 -0
- package/skills/shared/compose-multiplatform/references/project-setup.md +96 -0
- package/skills/shared/compose-multiplatform/scripts/verify.sh +123 -0
- package/skills/shared/connect-tool/SKILL.md +163 -0
- package/skills/shared/connect-tool/evals/cases.yaml +58 -0
- package/skills/shared/constitution/SKILL.md +158 -0
- package/skills/shared/constitution/evals/README.md +68 -0
- package/skills/shared/constitution/evals/cases.yaml +72 -0
- package/skills/shared/constitution/references/constitution-template.md +100 -0
- package/skills/shared/context-budget/SKILL.md +114 -0
- package/skills/shared/context-budget/evals/README.md +11 -0
- package/skills/shared/context-budget/evals/cases.yaml +40 -0
- package/skills/shared/context-budget/references/handoff-and-compaction.md +96 -0
- package/skills/shared/continuous-learning/SKILL.md +106 -0
- package/skills/shared/continuous-learning/evals/README.md +16 -0
- package/skills/shared/continuous-learning/evals/cases.yaml +39 -0
- package/skills/shared/continuous-learning/references/lesson-routing.md +106 -0
- package/skills/shared/coolify/SKILL.md +194 -0
- package/skills/shared/coolify/evals/README.md +21 -0
- package/skills/shared/coolify/evals/cases.yaml +46 -0
- package/skills/shared/coolify/references/databases-and-backups.md +99 -0
- package/skills/shared/coolify/references/deploy-recipes.md +105 -0
- package/skills/shared/coolify/references/install-and-proxy.md +80 -0
- package/skills/shared/coolify/scripts/verify.sh +123 -0
- package/skills/shared/cost-tracking/SKILL.md +176 -0
- package/skills/shared/cost-tracking/evals/README.md +3 -0
- package/skills/shared/cost-tracking/evals/cases.yaml +45 -0
- package/skills/shared/cost-tracking/references/cloud-caps.md +52 -0
- package/skills/shared/cost-tracking/references/pricing-tables.md +51 -0
- package/skills/shared/cost-tracking/scripts/verify.sh +135 -0
- package/skills/shared/cpp/SKILL.md +302 -0
- package/skills/shared/cpp/evals/README.md +14 -0
- package/skills/shared/cpp/evals/cases.yaml +44 -0
- package/skills/shared/cpp/references/cmake.md +167 -0
- package/skills/shared/cpp/references/move-and-templates.md +130 -0
- package/skills/shared/cpp/references/undefined-behavior.md +86 -0
- package/skills/shared/cpp/scripts/verify.sh +165 -0
- package/skills/shared/csharp-dotnet/SKILL.md +272 -0
- package/skills/shared/csharp-dotnet/evals/README.md +3 -0
- package/skills/shared/csharp-dotnet/evals/cases.yaml +48 -0
- package/skills/shared/csharp-dotnet/references/aspnetcore.md +99 -0
- package/skills/shared/csharp-dotnet/references/async.md +82 -0
- package/skills/shared/csharp-dotnet/references/efcore.md +96 -0
- package/skills/shared/csharp-dotnet/scripts/verify.sh +90 -0
- package/skills/shared/data-cleaning/SKILL.md +259 -0
- package/skills/shared/data-cleaning/evals/README.md +16 -0
- package/skills/shared/data-cleaning/evals/cases.yaml +57 -0
- package/skills/shared/data-cleaning/references/normalization-recipes.md +136 -0
- package/skills/shared/data-cleaning/references/validation-patterns.md +134 -0
- package/skills/shared/data-cleaning/scripts/verify.sh +115 -0
- package/skills/shared/data-scraper/SKILL.md +130 -0
- package/skills/shared/data-scraper/evals/README.md +3 -0
- package/skills/shared/data-scraper/evals/cases.yaml +46 -0
- package/skills/shared/data-scraper/references/anti-bot.md +85 -0
- package/skills/shared/data-scraper/references/frameworks.md +116 -0
- package/skills/shared/data-scraper/references/legal-compliance.md +64 -0
- package/skills/shared/data-scraper/scripts/verify.sh +166 -0
- package/skills/shared/db-migrations/SKILL.md +237 -0
- package/skills/shared/db-migrations/evals/README.md +10 -0
- package/skills/shared/db-migrations/evals/cases.yaml +46 -0
- package/skills/shared/db-migrations/references/backfill-and-batching.md +105 -0
- package/skills/shared/db-migrations/references/expand-contract-playbook.md +152 -0
- package/skills/shared/db-migrations/references/tools-and-runners.md +88 -0
- package/skills/shared/db-migrations/scripts/verify.sh +112 -0
- package/skills/shared/debug/SKILL.md +188 -0
- package/skills/shared/debug/evals/README.md +88 -0
- package/skills/shared/debug/evals/cases.yaml +74 -0
- package/skills/shared/decision-challenge/SKILL.md +113 -0
- package/skills/shared/decision-challenge/evals/README.md +3 -0
- package/skills/shared/decision-challenge/evals/cases.yaml +42 -0
- package/skills/shared/decision-records/SKILL.md +202 -0
- package/skills/shared/decision-records/evals/README.md +3 -0
- package/skills/shared/decision-records/evals/cases.yaml +43 -0
- package/skills/shared/decision-records/references/templates.md +252 -0
- package/skills/shared/decision-records/scripts/verify.sh +105 -0
- package/skills/shared/deep-learning/SKILL.md +226 -0
- package/skills/shared/deep-learning/evals/README.md +11 -0
- package/skills/shared/deep-learning/evals/cases.yaml +48 -0
- package/skills/shared/deep-learning/references/distributed.md +105 -0
- package/skills/shared/deep-learning/references/training-recipes.md +135 -0
- package/skills/shared/deployment/SKILL.md +374 -0
- package/skills/shared/deployment/evals/README.md +50 -0
- package/skills/shared/deployment/evals/cases.yaml +53 -0
- package/skills/shared/deployment/references/coolify.md +216 -0
- package/skills/shared/deployment/references/dockerfiles-by-stack.md +319 -0
- package/skills/shared/deployment/references/github-actions.md +295 -0
- package/skills/shared/deployment/references/hosting-targets.md +272 -0
- package/skills/shared/deployment/scripts/verify.sh +134 -0
- package/skills/shared/deprecation/SKILL.md +123 -0
- package/skills/shared/deprecation/evals/README.md +3 -0
- package/skills/shared/deprecation/evals/cases.yaml +42 -0
- package/skills/shared/design/IMPECCABLE-LICENSE.txt +191 -0
- package/skills/shared/design/SKILL.md +111 -0
- package/skills/shared/design/THIRD_PARTY.md +26 -0
- package/skills/shared/design/engine/LICENSE +21 -0
- package/skills/shared/design/engine/RUN.md +515 -0
- package/skills/shared/design/engine/UPSTREAM.json +4 -0
- package/skills/shared/design/engine/assets/app.css +216 -0
- package/skills/shared/design/engine/assets/base.css +105 -0
- package/skills/shared/design/engine/assets/base.js +37 -0
- package/skills/shared/design/engine/assets/charts.js +617 -0
- package/skills/shared/design/engine/assets/scenes/stage.css +28 -0
- package/skills/shared/design/engine/assets/scenes/stage.js +133 -0
- package/skills/shared/design/engine/library/app.json +1327 -0
- package/skills/shared/design/engine/library/directions.json +1078 -0
- package/skills/shared/design/engine/library/heroes.json +1086 -0
- package/skills/shared/design/engine/library/motions.json +92 -0
- package/skills/shared/design/engine/library/palettes.json +1485 -0
- package/skills/shared/design/engine/library/photos.json +7240 -0
- package/skills/shared/design/engine/library/sections.json +4429 -0
- package/skills/shared/design/engine/library/sites.json +8350 -0
- package/skills/shared/design/engine/library/type.json +2024 -0
- package/skills/shared/design/engine/references/app-screens.md +1199 -0
- package/skills/shared/design/engine/references/colour.md +141 -0
- package/skills/shared/design/engine/references/copy.md +177 -0
- package/skills/shared/design/engine/references/critique.md +182 -0
- package/skills/shared/design/engine/references/imagery.md +791 -0
- package/skills/shared/design/engine/references/layout.md +292 -0
- package/skills/shared/design/engine/references/motion.md +980 -0
- package/skills/shared/design/engine/references/research.md +356 -0
- package/skills/shared/design/engine/references/scenes.md +174 -0
- package/skills/shared/design/engine/references/tells.md +115 -0
- package/skills/shared/design/engine/references/type.md +170 -0
- package/skills/shared/design/engine/scripts/assets.mjs +865 -0
- package/skills/shared/design/engine/scripts/draw.mjs +584 -0
- package/skills/shared/design/engine/scripts/inspect.mjs +303 -0
- package/skills/shared/design/engine/scripts/lib/app-draw.mjs +203 -0
- package/skills/shared/design/engine/scripts/lib/cdp.mjs +248 -0
- package/skills/shared/design/engine/scripts/lib/probe.mjs +909 -0
- package/skills/shared/design/engine/scripts/lib/rules.mjs +243 -0
- package/skills/shared/design/engine/scripts/lint.mjs +119 -0
- package/skills/shared/design/engine/scripts/scenes.mjs +124 -0
- package/skills/shared/design/evals/cases.yaml +45 -0
- package/skills/shared/design/references/design-md.md +49 -0
- package/skills/shared/design/references/finish-review.md +46 -0
- package/skills/shared/design/references/modes.md +51 -0
- package/skills/shared/digitalocean/SKILL.md +227 -0
- package/skills/shared/digitalocean/evals/README.md +10 -0
- package/skills/shared/digitalocean/evals/cases.yaml +37 -0
- package/skills/shared/digitalocean/references/app-spec.md +126 -0
- package/skills/shared/digitalocean/references/droplet-ops.md +95 -0
- package/skills/shared/digitalocean/scripts/verify.sh +102 -0
- package/skills/shared/django/SKILL.md +263 -0
- package/skills/shared/django/evals/README.md +11 -0
- package/skills/shared/django/evals/cases.yaml +47 -0
- package/skills/shared/django/references/drf.md +109 -0
- package/skills/shared/django/references/orm-performance.md +91 -0
- package/skills/shared/django/references/security.md +81 -0
- package/skills/shared/django/references/testing.md +86 -0
- package/skills/shared/django/scripts/verify.sh +115 -0
- package/skills/shared/docker/SKILL.md +251 -0
- package/skills/shared/docker/evals/README.md +10 -0
- package/skills/shared/docker/evals/cases.yaml +44 -0
- package/skills/shared/docker/references/base-images-and-stages.md +104 -0
- package/skills/shared/docker/references/compose-recipes.md +109 -0
- package/skills/shared/docker/scripts/verify.sh +149 -0
- package/skills/shared/domains-dns/SKILL.md +131 -0
- package/skills/shared/domains-dns/evals/README.md +16 -0
- package/skills/shared/domains-dns/evals/cases.yaml +47 -0
- package/skills/shared/domains-dns/references/record-cookbook.md +94 -0
- package/skills/shared/domains-dns/references/tls-and-acme.md +90 -0
- package/skills/shared/domains-dns/references/verify-and-debug.md +64 -0
- package/skills/shared/domains-dns/scripts/verify.sh +163 -0
- package/skills/shared/drizzle-orm/SKILL.md +231 -0
- package/skills/shared/drizzle-orm/evals/README.md +12 -0
- package/skills/shared/drizzle-orm/evals/cases.yaml +47 -0
- package/skills/shared/drizzle-orm/references/relations-and-drivers.md +118 -0
- package/skills/shared/drizzle-orm/scripts/verify.sh +155 -0
- package/skills/shared/duckdb/SKILL.md +202 -0
- package/skills/shared/duckdb/evals/README.md +31 -0
- package/skills/shared/duckdb/evals/cases.yaml +41 -0
- package/skills/shared/duckdb/references/python-and-interop.md +105 -0
- package/skills/shared/duckdb/references/remote-and-lakehouse.md +101 -0
- package/skills/shared/duckdb/scripts/verify.sh +71 -0
- package/skills/shared/dynamodb/SKILL.md +204 -0
- package/skills/shared/dynamodb/evals/README.md +8 -0
- package/skills/shared/dynamodb/evals/cases.yaml +46 -0
- package/skills/shared/dynamodb/references/access-patterns.md +127 -0
- package/skills/shared/dynamodb/references/capacity-and-limits.md +78 -0
- package/skills/shared/dynamodb/scripts/verify.sh +108 -0
- package/skills/shared/e2e-testing/SKILL.md +233 -0
- package/skills/shared/e2e-testing/evals/README.md +10 -0
- package/skills/shared/e2e-testing/evals/cases.yaml +64 -0
- package/skills/shared/e2e-testing/references/config-and-ci.md +156 -0
- package/skills/shared/e2e-testing/references/flakiness-playbook.md +124 -0
- package/skills/shared/e2e-testing/scripts/verify.sh +117 -0
- package/skills/shared/electron/SKILL.md +209 -0
- package/skills/shared/electron/evals/README.md +13 -0
- package/skills/shared/electron/evals/cases.yaml +38 -0
- package/skills/shared/electron/references/packaging-and-updates.md +122 -0
- package/skills/shared/electron/references/security-and-ipc.md +158 -0
- package/skills/shared/electron/scripts/verify.sh +143 -0
- package/skills/shared/elixir/SKILL.md +209 -0
- package/skills/shared/elixir/evals/README.md +3 -0
- package/skills/shared/elixir/evals/cases.yaml +41 -0
- package/skills/shared/elixir/references/mix-and-releases.md +91 -0
- package/skills/shared/elixir/references/otp-patterns.md +96 -0
- package/skills/shared/elixir/scripts/verify.sh +76 -0
- package/skills/shared/email-deliverability/SKILL.md +148 -0
- package/skills/shared/email-deliverability/evals/README.md +21 -0
- package/skills/shared/email-deliverability/evals/cases.yaml +45 -0
- package/skills/shared/email-deliverability/scripts/verify.sh +98 -0
- package/skills/shared/embeddings-search/SKILL.md +184 -0
- package/skills/shared/embeddings-search/evals/README.md +10 -0
- package/skills/shared/embeddings-search/evals/cases.yaml +44 -0
- package/skills/shared/embeddings-search/references/evaluation.md +86 -0
- package/skills/shared/embeddings-search/references/models.md +73 -0
- package/skills/shared/embeddings-search/scripts/verify.sh +103 -0
- package/skills/shared/error-handling/SKILL.md +273 -0
- package/skills/shared/error-handling/evals/README.md +12 -0
- package/skills/shared/error-handling/evals/cases.yaml +46 -0
- package/skills/shared/error-handling/references/boundaries-and-messaging.md +120 -0
- package/skills/shared/error-handling/references/retry-and-resilience.md +154 -0
- package/skills/shared/error-handling/scripts/verify.sh +110 -0
- package/skills/shared/expo/SKILL.md +243 -0
- package/skills/shared/expo/evals/README.md +13 -0
- package/skills/shared/expo/evals/cases.yaml +44 -0
- package/skills/shared/expo/references/config-plugins.md +117 -0
- package/skills/shared/expo/references/eas-update.md +118 -0
- package/skills/shared/expo/scripts/verify.sh +132 -0
- package/skills/shared/fal/SKILL.md +196 -0
- package/skills/shared/fal/evals/README.md +3 -0
- package/skills/shared/fal/evals/cases.yaml +42 -0
- package/skills/shared/fal/references/models-and-cost.md +53 -0
- package/skills/shared/fal/references/queue-and-webhooks.md +153 -0
- package/skills/shared/fal/scripts/verify.sh +72 -0
- package/skills/shared/fastapi/SKILL.md +469 -0
- package/skills/shared/fastapi/evals/README.md +50 -0
- package/skills/shared/fastapi/evals/cases.yaml +55 -0
- package/skills/shared/fastapi/references/database.md +347 -0
- package/skills/shared/fastapi/references/production.md +338 -0
- package/skills/shared/fastapi/references/security.md +330 -0
- package/skills/shared/fastapi/references/testing.md +349 -0
- package/skills/shared/fastapi/scripts/verify.sh +157 -0
- package/skills/shared/finetuning/SKILL.md +232 -0
- package/skills/shared/finetuning/evals/README.md +13 -0
- package/skills/shared/finetuning/evals/cases.yaml +50 -0
- package/skills/shared/finetuning/references/hyperparameters-and-eval.md +74 -0
- package/skills/shared/finetuning/references/methods.md +189 -0
- package/skills/shared/firebase/SKILL.md +237 -0
- package/skills/shared/firebase/evals/README.md +12 -0
- package/skills/shared/firebase/evals/cases.yaml +45 -0
- package/skills/shared/firebase/references/cloud-functions.md +102 -0
- package/skills/shared/firebase/references/data-modeling.md +108 -0
- package/skills/shared/firebase/references/security-rules.md +137 -0
- package/skills/shared/firebase/scripts/verify.sh +98 -0
- package/skills/shared/flutter/SKILL.md +400 -0
- package/skills/shared/flutter/evals/README.md +54 -0
- package/skills/shared/flutter/evals/cases.yaml +69 -0
- package/skills/shared/flutter/references/architecture-and-state.md +499 -0
- package/skills/shared/flutter/references/i18n-and-dependencies.md +197 -0
- package/skills/shared/flutter/references/performance.md +299 -0
- package/skills/shared/flutter/references/testing.md +385 -0
- package/skills/shared/flutter/references/ui-and-navigation.md +378 -0
- package/skills/shared/flutter/scripts/verify.sh +104 -0
- package/skills/shared/fly-io/SKILL.md +197 -0
- package/skills/shared/fly-io/evals/README.md +3 -0
- package/skills/shared/fly-io/evals/cases.yaml +42 -0
- package/skills/shared/fly-io/references/fly-toml.md +155 -0
- package/skills/shared/fly-io/references/multi-region.md +66 -0
- package/skills/shared/fly-io/scripts/verify.sh +90 -0
- package/skills/shared/ftd/SKILL.md +111 -0
- package/skills/shared/ftd/evals/cases.yaml +66 -0
- package/skills/shared/ftd/evals/routing.json +24 -0
- package/skills/shared/game-design/SKILL.md +146 -0
- package/skills/shared/game-design/evals/README.md +13 -0
- package/skills/shared/game-design/evals/cases.yaml +47 -0
- package/skills/shared/game-design/references/mechanics-and-loops.md +78 -0
- package/skills/shared/game-design/references/playtesting-and-scope.md +58 -0
- package/skills/shared/game-design/references/progression-and-economy.md +70 -0
- package/skills/shared/game-storytelling/SKILL.md +134 -0
- package/skills/shared/game-storytelling/evals/README.md +28 -0
- package/skills/shared/game-storytelling/evals/cases.yaml +51 -0
- package/skills/shared/game-storytelling/references/branching-and-state.md +134 -0
- package/skills/shared/game-storytelling/references/dialogue-tools.md +117 -0
- package/skills/shared/game-storytelling/references/environmental-storytelling.md +71 -0
- package/skills/shared/gamedev-multiplayer/SKILL.md +237 -0
- package/skills/shared/gamedev-multiplayer/evals/README.md +12 -0
- package/skills/shared/gamedev-multiplayer/evals/cases.yaml +44 -0
- package/skills/shared/gamedev-multiplayer/references/godot-high-level-multiplayer.md +133 -0
- package/skills/shared/gamedev-multiplayer/references/prediction-and-latency.md +104 -0
- package/skills/shared/gamedev-multiplayer/references/unity-and-unreal-netcode.md +166 -0
- package/skills/shared/gamedev-pathing/SKILL.md +233 -0
- package/skills/shared/gamedev-pathing/evals/README.md +14 -0
- package/skills/shared/gamedev-pathing/evals/cases.yaml +49 -0
- package/skills/shared/gamedev-pathing/references/navmesh-workflow.md +110 -0
- package/skills/shared/gamedev-pathing/references/search-algorithms.md +135 -0
- package/skills/shared/gamedev-pathing/references/steering-and-avoidance.md +120 -0
- package/skills/shared/gamedev-physics/SKILL.md +225 -0
- package/skills/shared/gamedev-physics/evals/README.md +12 -0
- package/skills/shared/gamedev-physics/evals/cases.yaml +54 -0
- package/skills/shared/gamedev-physics/references/character-controllers.md +120 -0
- package/skills/shared/gamedev-physics/references/determinism-and-queries.md +124 -0
- package/skills/shared/gamedev-physics/references/layers-and-masks.md +115 -0
- package/skills/shared/gamedev-shaders/SKILL.md +232 -0
- package/skills/shared/gamedev-shaders/evals/README.md +14 -0
- package/skills/shared/gamedev-shaders/evals/cases.yaml +45 -0
- package/skills/shared/gamedev-shaders/references/effect-recipes.md +205 -0
- package/skills/shared/gamedev-shaders/references/godot-shading-language.md +133 -0
- package/skills/shared/gamedev-shaders/references/unity-and-unreal-shaders.md +169 -0
- package/skills/shared/gamedev-shipping/SKILL.md +220 -0
- package/skills/shared/gamedev-shipping/evals/README.md +9 -0
- package/skills/shared/gamedev-shipping/evals/cases.yaml +55 -0
- package/skills/shared/gamedev-shipping/references/mobile-and-desktop.md +127 -0
- package/skills/shared/gamedev-shipping/references/stores-and-ci.md +162 -0
- package/skills/shared/gamedev-shipping/references/web-export-headers.md +140 -0
- package/skills/shared/gcp-essentials/SKILL.md +324 -0
- package/skills/shared/gcp-essentials/evals/README.md +12 -0
- package/skills/shared/gcp-essentials/evals/cases.yaml +38 -0
- package/skills/shared/gcp-essentials/references/deploy-recipes.md +81 -0
- package/skills/shared/gcp-essentials/references/iam-and-auth.md +94 -0
- package/skills/shared/gcp-essentials/references/networking-and-sql.md +74 -0
- package/skills/shared/gcp-essentials/scripts/verify.sh +158 -0
- package/skills/shared/git-workflow/SKILL.md +214 -0
- package/skills/shared/git-workflow/evals/README.md +10 -0
- package/skills/shared/git-workflow/evals/cases.yaml +52 -0
- package/skills/shared/git-workflow/references/gitmoji.md +157 -0
- package/skills/shared/git-workflow/references/interactive-rebase.md +89 -0
- package/skills/shared/github-actions/SKILL.md +244 -0
- package/skills/shared/github-actions/evals/README.md +3 -0
- package/skills/shared/github-actions/evals/cases.yaml +45 -0
- package/skills/shared/github-actions/references/caching-and-matrix.md +92 -0
- package/skills/shared/github-actions/references/oidc-deploys.md +130 -0
- package/skills/shared/github-actions/scripts/verify.sh +105 -0
- package/skills/shared/gitlab-auth/SKILL.md +99 -0
- package/skills/shared/gitlab-workflow/SKILL.md +138 -0
- package/skills/shared/go/SKILL.md +390 -0
- package/skills/shared/go/evals/README.md +56 -0
- package/skills/shared/go/evals/cases.yaml +55 -0
- package/skills/shared/go/references/concurrency.md +557 -0
- package/skills/shared/go/references/http-services.md +529 -0
- package/skills/shared/go/references/testing.md +338 -0
- package/skills/shared/go/scripts/verify.sh +134 -0
- package/skills/shared/godot/SKILL.md +300 -0
- package/skills/shared/godot/evals/README.md +13 -0
- package/skills/shared/godot/evals/cases.yaml +50 -0
- package/skills/shared/godot/references/export-and-testing.md +102 -0
- package/skills/shared/godot/references/gdscript-style.md +84 -0
- package/skills/shared/godot/references/godot3-to-4-traps.md +89 -0
- package/skills/shared/godot/references/nodes-scenes-resources.md +109 -0
- package/skills/shared/harness/SKILL.md +316 -0
- package/skills/shared/harness/assets/_TEMPLATE/.env.example +8 -0
- package/skills/shared/harness/assets/_TEMPLATE/CREDENTIALS.md +25 -0
- package/skills/shared/harness/assets/_TEMPLATE/README.md +25 -0
- package/skills/shared/harness/assets/_TEMPLATE/gitignore +10 -0
- package/skills/shared/harness/assets/_TEMPLATE/test_connection.sh +30 -0
- package/skills/shared/harness/evals/README.md +54 -0
- package/skills/shared/harness/evals/cases.yaml +72 -0
- package/skills/shared/harness/examples/audit-example.md +120 -0
- package/skills/shared/harness/references/agents-md-template.md +41 -0
- package/skills/shared/harness/references/audit-report-template.html +140 -0
- package/skills/shared/harness/references/audit-report-template.md +116 -0
- package/skills/shared/harness/references/claude-md-template.md +85 -0
- package/skills/shared/harness/references/daily-curation-automation.md +68 -0
- package/skills/shared/harness/references/inbox-readme-template.md +51 -0
- package/skills/shared/harness/references/ingest-formats.md +185 -0
- package/skills/shared/harness/references/ingest-ignore-defaults.md +48 -0
- package/skills/shared/harness/references/obsidian-scaffolding.md +103 -0
- package/skills/shared/harness/references/providers.yaml +3546 -0
- package/skills/shared/harness/references/tools-readme-template.md +88 -0
- package/skills/shared/harness/references/wiki-archive-template.html +81 -0
- package/skills/shared/harness/references/wiki-article-template.md +60 -0
- package/skills/shared/harness/references/wiki-dashboard-template.html +136 -0
- package/skills/shared/harness/references/wiki-deep-improve-report-template.html +126 -0
- package/skills/shared/harness/references/wiki-gaps-template.md +22 -0
- package/skills/shared/harness/references/wiki-index-template.md +32 -0
- package/skills/shared/harness/references/wiki-protocol.md +926 -0
- package/skills/shared/harness/references/wiki-raw-template.md +7 -0
- package/skills/shared/harness/references/wiki-worklog-template.md +60 -0
- package/skills/shared/hetzner/SKILL.md +203 -0
- package/skills/shared/hetzner/evals/README.md +35 -0
- package/skills/shared/hetzner/evals/cases.yaml +46 -0
- package/skills/shared/hetzner/references/cloud-init.md +120 -0
- package/skills/shared/hetzner/references/plans-and-locations.md +56 -0
- package/skills/shared/hetzner/scripts/verify.sh +122 -0
- package/skills/shared/htmx/SKILL.md +261 -0
- package/skills/shared/htmx/evals/README.md +3 -0
- package/skills/shared/htmx/evals/cases.yaml +38 -0
- package/skills/shared/htmx/references/patterns.md +113 -0
- package/skills/shared/htmx/references/server-contract.md +91 -0
- package/skills/shared/htmx/scripts/verify.sh +93 -0
- package/skills/shared/huggingface/SKILL.md +191 -0
- package/skills/shared/huggingface/evals/README.md +11 -0
- package/skills/shared/huggingface/evals/cases.yaml +41 -0
- package/skills/shared/huggingface/references/endpoints-and-spaces.md +99 -0
- package/skills/shared/huggingface/references/hub-and-cli.md +85 -0
- package/skills/shared/huggingface/references/inference-providers.md +115 -0
- package/skills/shared/huggingface/scripts/verify.sh +123 -0
- package/skills/shared/idea-refinement/SKILL.md +121 -0
- package/skills/shared/idea-refinement/evals/README.md +3 -0
- package/skills/shared/idea-refinement/evals/cases.yaml +42 -0
- package/skills/shared/implement/SKILL.md +383 -0
- package/skills/shared/implement/evals/README.md +56 -0
- package/skills/shared/implement/evals/cases.yaml +43 -0
- package/skills/shared/implement/references/per-task-review.md +46 -0
- package/skills/shared/implement/scripts/review-package +59 -0
- package/skills/shared/implement/scripts/sdd-workspace +47 -0
- package/skills/shared/implement/scripts/task-brief +77 -0
- package/skills/shared/init/SKILL.md +209 -0
- package/skills/shared/init/evals/README.md +49 -0
- package/skills/shared/init/evals/cases.yaml +74 -0
- package/skills/shared/init/references/accompaniment-and-profile.md +122 -0
- package/skills/shared/init/references/discovery.md +90 -0
- package/skills/shared/init/references/recommend-skills.md +115 -0
- package/skills/shared/init/scripts/verify.sh +118 -0
- package/skills/shared/java/SKILL.md +341 -0
- package/skills/shared/java/evals/README.md +23 -0
- package/skills/shared/java/evals/cases.yaml +43 -0
- package/skills/shared/java/references/builds.md +133 -0
- package/skills/shared/java/references/concurrency.md +108 -0
- package/skills/shared/java/references/streams.md +102 -0
- package/skills/shared/java/scripts/verify.sh +107 -0
- package/skills/shared/knowledge-ops/SKILL.md +122 -0
- package/skills/shared/knowledge-ops/evals/README.md +16 -0
- package/skills/shared/knowledge-ops/evals/cases.yaml +50 -0
- package/skills/shared/knowledge-ops/references/gardening-playbook.md +126 -0
- package/skills/shared/kotlin-android/SKILL.md +245 -0
- package/skills/shared/kotlin-android/evals/README.md +13 -0
- package/skills/shared/kotlin-android/evals/cases.yaml +56 -0
- package/skills/shared/kotlin-android/references/architecture.md +200 -0
- package/skills/shared/kotlin-android/references/gradle-setup.md +125 -0
- package/skills/shared/kotlin-android/scripts/verify.sh +109 -0
- package/skills/shared/laravel/SKILL.md +301 -0
- package/skills/shared/laravel/evals/README.md +10 -0
- package/skills/shared/laravel/evals/cases.yaml +45 -0
- package/skills/shared/laravel/references/eloquent-patterns.md +126 -0
- package/skills/shared/laravel/references/queues-and-scheduling.md +153 -0
- package/skills/shared/laravel/scripts/verify.sh +128 -0
- package/skills/shared/level-design/SKILL.md +143 -0
- package/skills/shared/level-design/evals/README.md +35 -0
- package/skills/shared/level-design/evals/cases.yaml +58 -0
- package/skills/shared/level-design/references/blockout-to-art.md +118 -0
- package/skills/shared/level-design/references/guidance-and-readability.md +152 -0
- package/skills/shared/level-design/references/pacing-and-encounters.md +142 -0
- package/skills/shared/llm-pipeline/SKILL.md +150 -0
- package/skills/shared/llm-pipeline/evals/README.md +3 -0
- package/skills/shared/llm-pipeline/evals/cases.yaml +44 -0
- package/skills/shared/llm-pipeline/references/caching-layers.md +60 -0
- package/skills/shared/llm-pipeline/references/litellm-router.md +101 -0
- package/skills/shared/llm-pipeline/scripts/verify.sh +169 -0
- package/skills/shared/machine-learning/SKILL.md +228 -0
- package/skills/shared/machine-learning/evals/README.md +15 -0
- package/skills/shared/machine-learning/evals/cases.yaml +54 -0
- package/skills/shared/machine-learning/references/gbdt-and-tuning.md +83 -0
- package/skills/shared/machine-learning/references/metrics-and-imbalance.md +82 -0
- package/skills/shared/machine-learning/references/pipelines-and-cv.md +135 -0
- package/skills/shared/modal/SKILL.md +290 -0
- package/skills/shared/modal/evals/README.md +29 -0
- package/skills/shared/modal/evals/cases.yaml +50 -0
- package/skills/shared/modal/references/images-gpu-cookbook.md +160 -0
- package/skills/shared/modal/references/web-and-scaling.md +138 -0
- package/skills/shared/modal/scripts/verify.sh +127 -0
- package/skills/shared/mongodb/SKILL.md +342 -0
- package/skills/shared/mongodb/evals/README.md +29 -0
- package/skills/shared/mongodb/evals/cases.yaml +41 -0
- package/skills/shared/mongodb/references/aggregation.md +115 -0
- package/skills/shared/mongodb/references/data-modeling.md +135 -0
- package/skills/shared/mongodb/references/transactions-and-ops.md +128 -0
- package/skills/shared/mongodb/scripts/verify.sh +151 -0
- package/skills/shared/monitoring/SKILL.md +155 -0
- package/skills/shared/monitoring/evals/README.md +3 -0
- package/skills/shared/monitoring/evals/cases.yaml +47 -0
- package/skills/shared/monitoring/references/burn-rate-and-oncall.md +128 -0
- package/skills/shared/monitoring/references/tool-setup.md +154 -0
- package/skills/shared/monitoring/scripts/verify.sh +145 -0
- package/skills/shared/mysql/SKILL.md +249 -0
- package/skills/shared/mysql/evals/README.md +12 -0
- package/skills/shared/mysql/evals/cases.yaml +49 -0
- package/skills/shared/mysql/references/indexing-and-explain.md +161 -0
- package/skills/shared/mysql/references/mysql-vs-mariadb.md +78 -0
- package/skills/shared/mysql/references/online-ddl-and-migrations.md +120 -0
- package/skills/shared/mysql/references/replication-and-ha.md +115 -0
- package/skills/shared/mysql/scripts/verify.sh +141 -0
- package/skills/shared/neon/SKILL.md +218 -0
- package/skills/shared/neon/evals/README.md +11 -0
- package/skills/shared/neon/evals/cases.yaml +45 -0
- package/skills/shared/neon/references/branching-ci.md +86 -0
- package/skills/shared/neon/scripts/verify.sh +78 -0
- package/skills/shared/nestjs/SKILL.md +217 -0
- package/skills/shared/nestjs/evals/README.md +3 -0
- package/skills/shared/nestjs/evals/cases.yaml +38 -0
- package/skills/shared/nestjs/references/cross-cutting.md +135 -0
- package/skills/shared/nestjs/references/testing-recipes.md +105 -0
- package/skills/shared/nestjs/scripts/verify.sh +98 -0
- package/skills/shared/netlify/SKILL.md +208 -0
- package/skills/shared/netlify/evals/README.md +13 -0
- package/skills/shared/netlify/evals/cases.yaml +43 -0
- package/skills/shared/netlify/references/functions.md +97 -0
- package/skills/shared/netlify/references/netlify-toml.md +115 -0
- package/skills/shared/netlify/scripts/verify.sh +95 -0
- package/skills/shared/nextjs/SKILL.md +400 -0
- package/skills/shared/nextjs/evals/README.md +59 -0
- package/skills/shared/nextjs/evals/cases.yaml +56 -0
- package/skills/shared/nextjs/references/data-and-caching.md +309 -0
- package/skills/shared/nextjs/references/metadata.md +208 -0
- package/skills/shared/nextjs/references/performance.md +325 -0
- package/skills/shared/nextjs/references/react.md +383 -0
- package/skills/shared/nextjs/references/security.md +239 -0
- package/skills/shared/nextjs/references/testing.md +290 -0
- package/skills/shared/nextjs/scripts/verify.sh +141 -0
- package/skills/shared/nlp/SKILL.md +225 -0
- package/skills/shared/nlp/evals/README.md +10 -0
- package/skills/shared/nlp/evals/cases.yaml +45 -0
- package/skills/shared/nlp/references/evaluation.md +107 -0
- package/skills/shared/nlp/references/tokenization.md +95 -0
- package/skills/shared/no-code-app/SKILL.md +145 -0
- package/skills/shared/no-code-app/evals/README.md +3 -0
- package/skills/shared/no-code-app/evals/cases.yaml +43 -0
- package/skills/shared/no-code-app/references/platform-limits.md +100 -0
- package/skills/shared/nodejs/SKILL.md +229 -0
- package/skills/shared/nodejs/evals/README.md +3 -0
- package/skills/shared/nodejs/evals/cases.yaml +39 -0
- package/skills/shared/nodejs/references/express5-migration.md +53 -0
- package/skills/shared/nodejs/references/graceful-shutdown.md +73 -0
- package/skills/shared/nodejs/scripts/verify.sh +122 -0
- package/skills/shared/observability/SKILL.md +235 -0
- package/skills/shared/observability/evals/README.md +3 -0
- package/skills/shared/observability/evals/cases.yaml +51 -0
- package/skills/shared/observability/references/collector-config.md +98 -0
- package/skills/shared/observability/references/instrumentation-recipes.md +115 -0
- package/skills/shared/observability/scripts/verify.sh +156 -0
- package/skills/shared/ollama/SKILL.md +213 -0
- package/skills/shared/ollama/evals/README.md +9 -0
- package/skills/shared/ollama/evals/cases.yaml +43 -0
- package/skills/shared/ollama/references/api.md +148 -0
- package/skills/shared/ollama/references/hardware-sizing.md +87 -0
- package/skills/shared/ollama/scripts/verify.sh +116 -0
- package/skills/shared/open-weights/SKILL.md +239 -0
- package/skills/shared/open-weights/evals/README.md +14 -0
- package/skills/shared/open-weights/evals/cases.yaml +42 -0
- package/skills/shared/open-weights/references/licenses.md +123 -0
- package/skills/shared/open-weights/references/model-families.md +83 -0
- package/skills/shared/open-weights/references/sizing-and-quant.md +89 -0
- package/skills/shared/orient/SKILL.md +92 -0
- package/skills/shared/orient/evals/README.md +18 -0
- package/skills/shared/orient/evals/cases.yaml +67 -0
- package/skills/shared/orient/references/explain-ladder.md +93 -0
- package/skills/shared/orient/references/orientation-contract.md +86 -0
- package/skills/shared/parallel/SKILL.md +168 -0
- package/skills/shared/parallel/evals/README.md +62 -0
- package/skills/shared/parallel/evals/cases.yaml +44 -0
- package/skills/shared/performance/SKILL.md +229 -0
- package/skills/shared/performance/evals/README.md +3 -0
- package/skills/shared/performance/evals/cases.yaml +49 -0
- package/skills/shared/performance/references/profiling-playbook.md +54 -0
- package/skills/shared/performance/scripts/verify.sh +94 -0
- package/skills/shared/phoenix/SKILL.md +169 -0
- package/skills/shared/phoenix/evals/README.md +3 -0
- package/skills/shared/phoenix/evals/cases.yaml +40 -0
- package/skills/shared/phoenix/references/auth-and-scopes.md +82 -0
- package/skills/shared/phoenix/references/ecto-patterns.md +93 -0
- package/skills/shared/phoenix/references/liveview.md +134 -0
- package/skills/shared/phoenix/scripts/verify.sh +73 -0
- package/skills/shared/php/SKILL.md +397 -0
- package/skills/shared/php/evals/README.md +12 -0
- package/skills/shared/php/evals/cases.yaml +45 -0
- package/skills/shared/php/references/tooling.md +170 -0
- package/skills/shared/php/references/type-system.md +220 -0
- package/skills/shared/php/scripts/verify.sh +155 -0
- package/skills/shared/plan/SKILL.md +166 -0
- package/skills/shared/plan/evals/README.md +62 -0
- package/skills/shared/plan/evals/cases.yaml +49 -0
- package/skills/shared/plan/references/plan-template.md +153 -0
- package/skills/shared/planetscale/SKILL.md +198 -0
- package/skills/shared/planetscale/evals/README.md +11 -0
- package/skills/shared/planetscale/evals/cases.yaml +46 -0
- package/skills/shared/planetscale/references/deploy-requests.md +75 -0
- package/skills/shared/planetscale/references/no-foreign-keys.md +88 -0
- package/skills/shared/planetscale/scripts/verify.sh +115 -0
- package/skills/shared/planning-with-files/SKILL.md +278 -0
- package/skills/shared/planning-with-files/examples.md +202 -0
- package/skills/shared/planning-with-files/reference.md +218 -0
- package/skills/shared/planning-with-files/scripts/attest-plan.ps1 +118 -0
- package/skills/shared/planning-with-files/scripts/attest-plan.sh +110 -0
- package/skills/shared/planning-with-files/scripts/check-complete.ps1 +44 -0
- package/skills/shared/planning-with-files/scripts/check-complete.sh +46 -0
- package/skills/shared/planning-with-files/scripts/init-session.ps1 +166 -0
- package/skills/shared/planning-with-files/scripts/init-session.sh +284 -0
- package/skills/shared/planning-with-files/scripts/resolve-plan-dir.ps1 +44 -0
- package/skills/shared/planning-with-files/scripts/resolve-plan-dir.sh +76 -0
- package/skills/shared/planning-with-files/scripts/session-catchup.py +438 -0
- package/skills/shared/planning-with-files/scripts/set-active-plan.ps1 +50 -0
- package/skills/shared/planning-with-files/scripts/set-active-plan.sh +50 -0
- package/skills/shared/planning-with-files/templates/findings.md +95 -0
- package/skills/shared/planning-with-files/templates/progress.md +114 -0
- package/skills/shared/planning-with-files/templates/task_plan.md +132 -0
- package/skills/shared/postgresdb/SKILL.md +354 -0
- package/skills/shared/postgresdb/evals/README.md +55 -0
- package/skills/shared/postgresdb/evals/cases.yaml +57 -0
- package/skills/shared/postgresdb/references/migrations.md +279 -0
- package/skills/shared/postgresdb/references/operations-and-security.md +267 -0
- package/skills/shared/postgresdb/references/query-optimization.md +374 -0
- package/skills/shared/postgresdb/references/schema-and-indexing.md +379 -0
- package/skills/shared/postgresdb/scripts/verify.sh +191 -0
- package/skills/shared/prisma-orm/SKILL.md +313 -0
- package/skills/shared/prisma-orm/evals/README.md +12 -0
- package/skills/shared/prisma-orm/evals/cases.yaml +56 -0
- package/skills/shared/prisma-orm/references/migrations-and-v7-upgrade.md +197 -0
- package/skills/shared/prisma-orm/references/queries-and-performance.md +169 -0
- package/skills/shared/prisma-orm/scripts/verify.sh +137 -0
- package/skills/shared/prompt-engineering/SKILL.md +127 -0
- package/skills/shared/prompt-engineering/evals/README.md +11 -0
- package/skills/shared/prompt-engineering/evals/cases.yaml +46 -0
- package/skills/shared/prompt-engineering/references/eval-templates.md +94 -0
- package/skills/shared/prompt-engineering/references/output-contracts.md +120 -0
- package/skills/shared/prompt-engineering/scripts/verify.sh +84 -0
- package/skills/shared/python/SKILL.md +320 -0
- package/skills/shared/python/evals/README.md +19 -0
- package/skills/shared/python/evals/cases.yaml +46 -0
- package/skills/shared/python/references/async.md +136 -0
- package/skills/shared/python/references/stdlib.md +162 -0
- package/skills/shared/python/references/typing.md +160 -0
- package/skills/shared/python/scripts/verify.sh +125 -0
- package/skills/shared/rag/SKILL.md +209 -0
- package/skills/shared/rag/evals/README.md +13 -0
- package/skills/shared/rag/evals/cases.yaml +45 -0
- package/skills/shared/rag/references/evaluation.md +99 -0
- package/skills/shared/rag/references/pipeline.md +151 -0
- package/skills/shared/rag/scripts/verify.sh +99 -0
- package/skills/shared/rails/SKILL.md +264 -0
- package/skills/shared/rails/evals/README.md +12 -0
- package/skills/shared/rails/evals/cases.yaml +47 -0
- package/skills/shared/rails/references/activerecord.md +148 -0
- package/skills/shared/rails/references/hotwire.md +139 -0
- package/skills/shared/rails/references/testing.md +110 -0
- package/skills/shared/rails/scripts/verify.sh +128 -0
- package/skills/shared/railway/SKILL.md +245 -0
- package/skills/shared/railway/evals/README.md +14 -0
- package/skills/shared/railway/evals/cases.yaml +44 -0
- package/skills/shared/railway/references/cli-cookbook.md +137 -0
- package/skills/shared/railway/references/config-as-code.md +120 -0
- package/skills/shared/railway/scripts/verify.sh +162 -0
- package/skills/shared/react/SKILL.md +182 -0
- package/skills/shared/react/evals/README.md +3 -0
- package/skills/shared/react/evals/cases.yaml +43 -0
- package/skills/shared/react/references/data-and-state.md +152 -0
- package/skills/shared/react/references/performance.md +75 -0
- package/skills/shared/react/references/routing.md +99 -0
- package/skills/shared/react/scripts/verify.sh +123 -0
- package/skills/shared/react-native/SKILL.md +215 -0
- package/skills/shared/react-native/evals/README.md +3 -0
- package/skills/shared/react-native/evals/cases.yaml +42 -0
- package/skills/shared/react-native/references/native-modules.md +123 -0
- package/skills/shared/react-native/references/performance-debugging.md +46 -0
- package/skills/shared/react-native/scripts/verify.sh +120 -0
- package/skills/shared/redis/SKILL.md +298 -0
- package/skills/shared/redis/evals/README.md +10 -0
- package/skills/shared/redis/evals/cases.yaml +43 -0
- package/skills/shared/redis/references/caching.md +116 -0
- package/skills/shared/redis/references/locks-and-rate-limiting.md +140 -0
- package/skills/shared/redis/references/queues.md +102 -0
- package/skills/shared/redis/scripts/verify.sh +164 -0
- package/skills/shared/render/SKILL.md +256 -0
- package/skills/shared/render/evals/README.md +12 -0
- package/skills/shared/render/evals/cases.yaml +45 -0
- package/skills/shared/render/references/blueprint-reference.md +203 -0
- package/skills/shared/render/scripts/verify.sh +167 -0
- package/skills/shared/replicate/SKILL.md +210 -0
- package/skills/shared/replicate/evals/README.md +9 -0
- package/skills/shared/replicate/evals/cases.yaml +45 -0
- package/skills/shared/replicate/references/cog-packaging.md +89 -0
- package/skills/shared/replicate/references/deployments-api.md +87 -0
- package/skills/shared/replicate/references/webhooks-and-async.md +110 -0
- package/skills/shared/replicate/scripts/verify.sh +162 -0
- package/skills/shared/research-ops/SKILL.md +200 -0
- package/skills/shared/research-ops/evals/README.md +13 -0
- package/skills/shared/research-ops/evals/cases.yaml +38 -0
- package/skills/shared/research-ops/references/credibility-rubric.md +78 -0
- package/skills/shared/research-ops/references/memo-template.md +63 -0
- package/skills/shared/research-ops/scripts/verify.sh +181 -0
- package/skills/shared/review/SKILL.md +314 -0
- package/skills/shared/review/evals/README.md +84 -0
- package/skills/shared/review/evals/cases.yaml +55 -0
- package/skills/shared/ruby/SKILL.md +295 -0
- package/skills/shared/ruby/evals/README.md +12 -0
- package/skills/shared/ruby/evals/cases.yaml +41 -0
- package/skills/shared/ruby/references/gems-and-testing.md +208 -0
- package/skills/shared/ruby/references/metaprogramming.md +161 -0
- package/skills/shared/ruby/scripts/verify.sh +83 -0
- package/skills/shared/runpod/SKILL.md +238 -0
- package/skills/shared/runpod/evals/README.md +11 -0
- package/skills/shared/runpod/evals/cases.yaml +47 -0
- package/skills/shared/runpod/references/cost-and-scaling.md +85 -0
- package/skills/shared/runpod/references/serverless-workers.md +101 -0
- package/skills/shared/runpod/scripts/verify.sh +126 -0
- package/skills/shared/rust/SKILL.md +320 -0
- package/skills/shared/rust/evals/README.md +12 -0
- package/skills/shared/rust/evals/cases.yaml +42 -0
- package/skills/shared/rust/references/async-tokio.md +141 -0
- package/skills/shared/rust/references/axum-service.md +132 -0
- package/skills/shared/rust/references/ownership.md +86 -0
- package/skills/shared/rust/references/testing.md +108 -0
- package/skills/shared/rust/scripts/verify.sh +91 -0
- package/skills/shared/scaling/SKILL.md +137 -0
- package/skills/shared/scaling/evals/README.md +3 -0
- package/skills/shared/scaling/evals/cases.yaml +42 -0
- package/skills/shared/scaling/references/load-testing-k6.md +127 -0
- package/skills/shared/scaling/scripts/example.load.js +24 -0
- package/skills/shared/scaling/scripts/verify.sh +70 -0
- package/skills/shared/sdd/SKILL.md +250 -0
- package/skills/shared/sdd/evals/README.md +60 -0
- package/skills/shared/sdd/evals/cases.yaml +90 -0
- package/skills/shared/sdd/references/model-routing.md +194 -0
- package/skills/shared/sdd-init/SKILL.md +189 -0
- package/skills/shared/sdd-init/evals/README.md +3 -0
- package/skills/shared/sdd-init/evals/cases.yaml +43 -0
- package/skills/shared/secure-coding/SKILL.md +336 -0
- package/skills/shared/secure-coding/evals/README.md +68 -0
- package/skills/shared/secure-coding/evals/cases.yaml +55 -0
- package/skills/shared/secure-coding/references/authn-authz.md +249 -0
- package/skills/shared/secure-coding/references/owasp-by-stack.md +574 -0
- package/skills/shared/secure-coding/references/secrets-and-supply-chain.md +205 -0
- package/skills/shared/secure-coding/references/threat-modeling.md +213 -0
- package/skills/shared/secure-coding/scripts/verify.sh +208 -0
- package/skills/shared/security-scan/SKILL.md +219 -0
- package/skills/shared/security-scan/evals/README.md +14 -0
- package/skills/shared/security-scan/evals/cases.yaml +50 -0
- package/skills/shared/security-scan/references/tools.md +97 -0
- package/skills/shared/security-scan/references/triage.md +92 -0
- package/skills/shared/security-scan/scripts/verify.sh +108 -0
- package/skills/shared/ship/SKILL.md +272 -0
- package/skills/shared/ship/evals/README.md +89 -0
- package/skills/shared/ship/evals/cases.yaml +44 -0
- package/skills/shared/shopify/SKILL.md +229 -0
- package/skills/shared/shopify/evals/README.md +14 -0
- package/skills/shared/shopify/evals/cases.yaml +41 -0
- package/skills/shared/shopify/references/apps-graphql.md +103 -0
- package/skills/shared/shopify/references/checkout-extensibility.md +71 -0
- package/skills/shared/shopify/references/liquid-themes.md +89 -0
- package/skills/shared/shopify/scripts/verify.sh +120 -0
- package/skills/shared/simplify-code/SKILL.md +101 -0
- package/skills/shared/simplify-code/evals/README.md +3 -0
- package/skills/shared/simplify-code/evals/cases.yaml +42 -0
- package/skills/shared/skill-scout/SKILL.md +169 -0
- package/skills/shared/skill-scout/evals/README.md +12 -0
- package/skills/shared/skill-scout/evals/cases.yaml +56 -0
- package/skills/shared/skill-scout/references/install-commands.md +76 -0
- package/skills/shared/skill-scout/scripts/verify.sh +154 -0
- package/skills/shared/solid-js/SKILL.md +260 -0
- package/skills/shared/solid-js/evals/README.md +3 -0
- package/skills/shared/solid-js/evals/cases.yaml +38 -0
- package/skills/shared/solid-js/references/reactivity-deep-dive.md +89 -0
- package/skills/shared/solid-js/references/router-and-start.md +93 -0
- package/skills/shared/solid-js/scripts/verify.sh +130 -0
- package/skills/shared/source-grounded-development/SKILL.md +108 -0
- package/skills/shared/source-grounded-development/evals/README.md +3 -0
- package/skills/shared/source-grounded-development/evals/cases.yaml +42 -0
- package/skills/shared/specify/SKILL.md +391 -0
- package/skills/shared/specify/evals/README.md +73 -0
- package/skills/shared/specify/evals/cases.yaml +93 -0
- package/skills/shared/specify/references/eliciting-requirements.md +117 -0
- package/skills/shared/specify/references/spec-template.md +101 -0
- package/skills/shared/speckit-analyze/SKILL.md +35 -0
- package/skills/shared/speckit-assess-decide/SKILL.md +36 -0
- package/skills/shared/speckit-assess-define/SKILL.md +36 -0
- package/skills/shared/speckit-assess-intake/SKILL.md +38 -0
- package/skills/shared/speckit-assess-research/SKILL.md +36 -0
- package/skills/shared/speckit-assess-shape/SKILL.md +36 -0
- package/skills/shared/speckit-bug-assess/SKILL.md +38 -0
- package/skills/shared/speckit-bug-fix/SKILL.md +37 -0
- package/skills/shared/speckit-bug-test/SKILL.md +37 -0
- package/skills/shared/speckit-checklist/SKILL.md +35 -0
- package/skills/shared/speckit-clarify/SKILL.md +32 -0
- package/skills/shared/speckit-constitution/SKILL.md +35 -0
- package/skills/shared/speckit-converge/SKILL.md +36 -0
- package/skills/shared/speckit-implement/SKILL.md +32 -0
- package/skills/shared/speckit-plan/SKILL.md +37 -0
- package/skills/shared/speckit-specify/SKILL.md +36 -0
- package/skills/shared/speckit-tasks/SKILL.md +34 -0
- package/skills/shared/spreadsheet-ops/SKILL.md +180 -0
- package/skills/shared/spreadsheet-ops/evals/README.md +33 -0
- package/skills/shared/spreadsheet-ops/evals/cases.yaml +42 -0
- package/skills/shared/spreadsheet-ops/references/formula-cookbook.md +70 -0
- package/skills/shared/spreadsheet-ops/references/python-excel.md +87 -0
- package/skills/shared/spreadsheet-ops/references/sheets-api-appsscript.md +118 -0
- package/skills/shared/spreadsheet-ops/scripts/verify.sh +152 -0
- package/skills/shared/spring-boot/SKILL.md +350 -0
- package/skills/shared/spring-boot/evals/README.md +11 -0
- package/skills/shared/spring-boot/evals/cases.yaml +49 -0
- package/skills/shared/spring-boot/references/jpa.md +94 -0
- package/skills/shared/spring-boot/references/security.md +92 -0
- package/skills/shared/spring-boot/references/testing.md +95 -0
- package/skills/shared/spring-boot/scripts/verify.sh +115 -0
- package/skills/shared/sql/SKILL.md +286 -0
- package/skills/shared/sql/evals/README.md +9 -0
- package/skills/shared/sql/evals/cases.yaml +49 -0
- package/skills/shared/sql/references/ctes-and-recursion.md +63 -0
- package/skills/shared/sql/references/joins-and-sets.md +71 -0
- package/skills/shared/sql/references/portability.md +38 -0
- package/skills/shared/sql/references/window-functions.md +72 -0
- package/skills/shared/sql/scripts/verify.sh +139 -0
- package/skills/shared/sqlite-turso/SKILL.md +214 -0
- package/skills/shared/sqlite-turso/evals/README.md +24 -0
- package/skills/shared/sqlite-turso/evals/cases.yaml +45 -0
- package/skills/shared/sqlite-turso/references/embedded-replicas.md +96 -0
- package/skills/shared/sqlite-turso/scripts/verify.sh +95 -0
- package/skills/shared/structured-extraction/SKILL.md +230 -0
- package/skills/shared/structured-extraction/evals/README.md +13 -0
- package/skills/shared/structured-extraction/evals/cases.yaml +70 -0
- package/skills/shared/structured-extraction/references/providers.md +152 -0
- package/skills/shared/structured-extraction/scripts/verify.sh +160 -0
- package/skills/shared/suggest/SKILL.md +123 -0
- package/skills/shared/suggest/evals/README.md +17 -0
- package/skills/shared/suggest/evals/cases.yaml +78 -0
- package/skills/shared/supabase/SKILL.md +268 -0
- package/skills/shared/supabase/evals/README.md +12 -0
- package/skills/shared/supabase/evals/cases.yaml +42 -0
- package/skills/shared/supabase/references/auth-ssr.md +173 -0
- package/skills/shared/supabase/references/rls-cookbook.md +122 -0
- package/skills/shared/supabase/scripts/verify.sh +149 -0
- package/skills/shared/svelte/SKILL.md +238 -0
- package/skills/shared/svelte/evals/README.md +3 -0
- package/skills/shared/svelte/evals/cases.yaml +41 -0
- package/skills/shared/svelte/references/runes.md +97 -0
- package/skills/shared/svelte/references/sveltekit-data.md +156 -0
- package/skills/shared/svelte/scripts/verify.sh +128 -0
- package/skills/shared/swift-ios/SKILL.md +224 -0
- package/skills/shared/swift-ios/evals/README.md +3 -0
- package/skills/shared/swift-ios/evals/cases.yaml +46 -0
- package/skills/shared/swift-ios/references/concurrency.md +132 -0
- package/skills/shared/swift-ios/references/testing.md +112 -0
- package/skills/shared/swift-ios/scripts/verify.sh +98 -0
- package/skills/shared/tasks/SKILL.md +265 -0
- package/skills/shared/tasks/evals/README.md +70 -0
- package/skills/shared/tasks/evals/cases.yaml +75 -0
- package/skills/shared/tauri/SKILL.md +219 -0
- package/skills/shared/tauri/evals/README.md +12 -0
- package/skills/shared/tauri/evals/cases.yaml +46 -0
- package/skills/shared/tauri/references/bundling-distribution.md +129 -0
- package/skills/shared/tauri/references/security.md +143 -0
- package/skills/shared/tauri/scripts/verify.sh +178 -0
- package/skills/shared/technical-writing/SKILL.md +230 -0
- package/skills/shared/technical-writing/evals/README.md +12 -0
- package/skills/shared/technical-writing/evals/cases.yaml +53 -0
- package/skills/shared/technical-writing/references/diataxis-modes.md +131 -0
- package/skills/shared/technical-writing/references/vale-starter.md +90 -0
- package/skills/shared/technical-writing/scripts/verify.sh +83 -0
- package/skills/shared/testing-go/SKILL.md +263 -0
- package/skills/shared/testing-go/evals/README.md +3 -0
- package/skills/shared/testing-go/evals/cases.yaml +46 -0
- package/skills/shared/testing-go/references/coverage-and-benchmarks.md +85 -0
- package/skills/shared/testing-go/references/mocks-and-fakes.md +140 -0
- package/skills/shared/testing-go/references/synctest-and-concurrency.md +82 -0
- package/skills/shared/testing-go/scripts/verify.sh +72 -0
- package/skills/shared/testing-py/SKILL.md +197 -0
- package/skills/shared/testing-py/evals/README.md +5 -0
- package/skills/shared/testing-py/evals/cases.yaml +44 -0
- package/skills/shared/testing-py/references/mocking.md +141 -0
- package/skills/shared/testing-py/references/property-testing.md +99 -0
- package/skills/shared/testing-py/scripts/verify.sh +117 -0
- package/skills/shared/testing-web/SKILL.md +244 -0
- package/skills/shared/testing-web/evals/README.md +11 -0
- package/skills/shared/testing-web/evals/cases.yaml +52 -0
- package/skills/shared/testing-web/references/jest-setup.md +88 -0
- package/skills/shared/testing-web/references/recipes.md +116 -0
- package/skills/shared/testing-web/scripts/verify.sh +111 -0
- package/skills/shared/together-fireworks/SKILL.md +176 -0
- package/skills/shared/together-fireworks/evals/README.md +3 -0
- package/skills/shared/together-fireworks/evals/cases.yaml +50 -0
- package/skills/shared/together-fireworks/references/batch-and-tuning.md +59 -0
- package/skills/shared/together-fireworks/references/models-and-pricing.md +79 -0
- package/skills/shared/together-fireworks/scripts/verify.sh +165 -0
- package/skills/shared/training-data/SKILL.md +226 -0
- package/skills/shared/training-data/evals/README.md +13 -0
- package/skills/shared/training-data/evals/cases.yaml +41 -0
- package/skills/shared/training-data/references/formats.md +118 -0
- package/skills/shared/training-data/references/synthesis-dedup-quality.md +134 -0
- package/skills/shared/translation-l10n/SKILL.md +229 -0
- package/skills/shared/translation-l10n/evals/README.md +3 -0
- package/skills/shared/translation-l10n/evals/cases.yaml +39 -0
- package/skills/shared/translation-l10n/references/icu-cookbook.md +82 -0
- package/skills/shared/translation-l10n/references/rtl-and-bidi.md +60 -0
- package/skills/shared/typescript/SKILL.md +225 -0
- package/skills/shared/typescript/evals/README.md +15 -0
- package/skills/shared/typescript/evals/cases.yaml +46 -0
- package/skills/shared/typescript/references/build-and-monorepo.md +141 -0
- package/skills/shared/typescript/references/type-system.md +162 -0
- package/skills/shared/typescript/scripts/verify.sh +52 -0
- package/skills/shared/ui-engineering/SKILL.md +113 -0
- package/skills/shared/ui-engineering/evals/cases.yaml +38 -0
- package/skills/shared/unity/SKILL.md +282 -0
- package/skills/shared/unity/evals/README.md +8 -0
- package/skills/shared/unity/evals/cases.yaml +43 -0
- package/skills/shared/unity/references/build-and-platforms.md +65 -0
- package/skills/shared/unity/references/input-system.md +102 -0
- package/skills/shared/unity/references/lifecycle-deep-dive.md +75 -0
- package/skills/shared/unreal/SKILL.md +270 -0
- package/skills/shared/unreal/evals/README.md +12 -0
- package/skills/shared/unreal/evals/cases.yaml +45 -0
- package/skills/shared/unreal/references/blueprint-cpp-parity.md +109 -0
- package/skills/shared/unreal/references/gameplay-framework.md +95 -0
- package/skills/shared/unreal/references/packaging.md +83 -0
- package/skills/shared/unslop/SKILL.md +143 -0
- package/skills/shared/unslop/evals/README.md +25 -0
- package/skills/shared/unslop/evals/cases.yaml +61 -0
- package/skills/shared/unsloth/SKILL.md +254 -0
- package/skills/shared/unsloth/evals/README.md +10 -0
- package/skills/shared/unsloth/evals/cases.yaml +42 -0
- package/skills/shared/unsloth/references/export.md +75 -0
- package/skills/shared/unsloth/references/grpo.md +91 -0
- package/skills/shared/unsloth/references/masking-and-templates.md +91 -0
- package/skills/shared/variant-explorer/SKILL.md +93 -0
- package/skills/shared/variant-explorer/evals/cases.yaml +38 -0
- package/skills/shared/vector-db/SKILL.md +189 -0
- package/skills/shared/vector-db/evals/README.md +10 -0
- package/skills/shared/vector-db/evals/cases.yaml +45 -0
- package/skills/shared/vector-db/references/engines.md +175 -0
- package/skills/shared/vector-db/references/tuning.md +62 -0
- package/skills/shared/vector-db/scripts/verify.sh +110 -0
- package/skills/shared/vercel/SKILL.md +242 -0
- package/skills/shared/vercel/evals/README.md +23 -0
- package/skills/shared/vercel/evals/cases.yaml +45 -0
- package/skills/shared/vercel/references/cli-cookbook.md +98 -0
- package/skills/shared/vercel/references/vercel-json.md +120 -0
- package/skills/shared/vercel/scripts/verify.sh +168 -0
- package/skills/shared/verify/SKILL.md +230 -0
- package/skills/shared/verify/evals/README.md +78 -0
- package/skills/shared/verify/evals/cases.yaml +104 -0
- package/skills/shared/vllm/SKILL.md +235 -0
- package/skills/shared/vllm/evals/README.md +9 -0
- package/skills/shared/vllm/evals/cases.yaml +47 -0
- package/skills/shared/vllm/references/flags-and-endpoints.md +105 -0
- package/skills/shared/vllm/references/memory-and-throughput.md +78 -0
- package/skills/shared/vue-nuxt/SKILL.md +323 -0
- package/skills/shared/vue-nuxt/evals/README.md +11 -0
- package/skills/shared/vue-nuxt/evals/cases.yaml +49 -0
- package/skills/shared/vue-nuxt/references/data-and-state.md +127 -0
- package/skills/shared/vue-nuxt/references/migration-nuxt4.md +79 -0
- package/skills/shared/vue-nuxt/references/nitro-and-rendering.md +117 -0
- package/skills/shared/vue-nuxt/references/reactivity.md +135 -0
- package/skills/shared/vue-nuxt/scripts/verify.sh +148 -0
- package/skills/shared/webhooks/SKILL.md +229 -0
- package/skills/shared/webhooks/evals/README.md +15 -0
- package/skills/shared/webhooks/evals/cases.yaml +46 -0
- package/skills/shared/webhooks/references/framework-raw-body.md +97 -0
- package/skills/shared/webhooks/references/signature-schemes.md +66 -0
- package/skills/shared/webhooks/scripts/verify.sh +142 -0
- package/skills/shared/wordpress/SKILL.md +224 -0
- package/skills/shared/wordpress/evals/README.md +3 -0
- package/skills/shared/wordpress/evals/cases.yaml +50 -0
- package/skills/shared/wordpress/references/hardening.md +108 -0
- package/skills/shared/wordpress/references/performance.md +80 -0
- package/skills/shared/wordpress/references/woocommerce.md +65 -0
- package/skills/shared/wordpress/scripts/verify.sh +96 -0
- package/skills/shared/worktrees/SKILL.md +204 -0
- package/skills/shared/worktrees/evals/README.md +78 -0
- package/skills/shared/worktrees/evals/cases.yaml +47 -0
|
@@ -0,0 +1,229 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: webhooks
|
|
3
|
+
description: "Use when building the receiving end of a webhook — a provider-agnostic endpoint that proves pushed events are authentic and never processes one twice: raw-body HMAC, ~5-min replay window, idempotency on the event id, fast-ack-then-queue. NOT the Stripe-Signature scheme (that is stripe), NOT outbound clients you call (that is api-connector-builder)."
|
|
4
|
+
tags: [webhooks, inbound-webhooks, hmac-verification, idempotency, signature-verification, queue, connectors]
|
|
5
|
+
recommends: [stripe, email-connector, api-connector-builder, automation-flows, redis, secure-coding]
|
|
6
|
+
profiles: []
|
|
7
|
+
origin: ai-hub
|
|
8
|
+
---
|
|
9
|
+
|
|
10
|
+
# Webhooks — the inbound front door that survives retries and forgeries
|
|
11
|
+
|
|
12
|
+
You are building the side of a webhook that *receives*. Some external system
|
|
13
|
+
pushes an HTTP POST at your endpoint; your job is to prove it is real, refuse to
|
|
14
|
+
act on it twice, and answer fast. That is the whole mandate.
|
|
15
|
+
|
|
16
|
+
This skill is provider-agnostic — it teaches the mechanics every webhook source
|
|
17
|
+
shares, not any one vendor's event catalog — and it ends at "enqueued." What
|
|
18
|
+
happens to the event afterward is a different job:
|
|
19
|
+
|
|
20
|
+
- The Stripe-specific scheme (`Stripe-Signature`, `t=,v1=`, `stripe listen`,
|
|
21
|
+
the event model) → `../stripe/SKILL.md`.
|
|
22
|
+
- Email bounce/complaint webhooks where the point is suppression state →
|
|
23
|
+
`../email-connector/SKILL.md`.
|
|
24
|
+
- The *outbound* client that calls someone else's API → `api-connector-builder`.
|
|
25
|
+
- Multi-step orchestration after the event lands → `automation-flows`.
|
|
26
|
+
- Broker/queue tuning (BullMQ concurrency, DLQ ops) → `redis`.
|
|
27
|
+
- Constant-time compare, secret handling, supply-chain hygiene →
|
|
28
|
+
`../secure-coding/SKILL.md`.
|
|
29
|
+
|
|
30
|
+
## The pipeline
|
|
31
|
+
|
|
32
|
+
These five stages run in exactly this order. Each one exists to protect the one
|
|
33
|
+
after it; reorder them and you either trust forged data or waste work.
|
|
34
|
+
|
|
35
|
+
| # | Stage | Why it precedes the next |
|
|
36
|
+
|---|-------|--------------------------|
|
|
37
|
+
| 1 | Read the **raw body** | Parsing first destroys the bytes the signature was computed over. Capture the raw buffer before any JSON parse. |
|
|
38
|
+
| 2 | **Verify the signature** | Until this passes, every field in the body is attacker-controlled. Verify before you read anything. |
|
|
39
|
+
| 3 | Check the **timestamp window** | A cheap reject of replayed-but-valid payloads, before you touch a datastore. |
|
|
40
|
+
| 4 | **Dedupe** on the event id | At-least-once delivery means duplicates are normal. Mark it seen before doing work, not after. |
|
|
41
|
+
| 5 | **Persist/enqueue → `2xx`** | Hand the event to durable storage, then ack. The ack means "I own this now." |
|
|
42
|
+
|
|
43
|
+
**Delivery is at-least-once, never exactly-once.** Every major provider retries
|
|
44
|
+
on non-2xx or timeout, so duplicate deliveries are normal traffic and idempotency
|
|
45
|
+
is required, not a nice-to-have.
|
|
46
|
+
|
|
47
|
+
## Verify the signature
|
|
48
|
+
|
|
49
|
+
**Verify over the raw bytes, never over re-serialized JSON.** Re-serializing a
|
|
50
|
+
parsed object reorders keys and normalizes whitespace, so the HMAC you compute
|
|
51
|
+
no longer matches the one the sender computed. This is the single most common
|
|
52
|
+
cause of "signature fails even though the secret is right."
|
|
53
|
+
|
|
54
|
+
```js
|
|
55
|
+
// Bad — body was parsed, so the bytes are gone. HMAC will never match.
|
|
56
|
+
app.post("/webhooks", express.json(), (req, res) => {
|
|
57
|
+
const expected = sign(JSON.stringify(req.body)); // reordered, re-spaced
|
|
58
|
+
});
|
|
59
|
+
|
|
60
|
+
// Good — keep the raw buffer for the HMAC; parse only after verifying.
|
|
61
|
+
app.post("/webhooks", express.raw({ type: "*/*" }), (req, res) => {
|
|
62
|
+
const raw = req.body; // a Buffer, the exact bytes received
|
|
63
|
+
if (!verify(raw, req.headers)) return res.sendStatus(400);
|
|
64
|
+
const event = JSON.parse(raw.toString("utf8"));
|
|
65
|
+
});
|
|
66
|
+
```
|
|
67
|
+
|
|
68
|
+
**Compare signatures in constant time.** A normal `===`/`==` short-circuits on
|
|
69
|
+
the first differing byte, which leaks how much of the signature an attacker
|
|
70
|
+
guessed correctly. Use `crypto.timingSafeEqual` (Node) or `hmac.compare_digest`
|
|
71
|
+
(Python). The buffers must be equal length, so guard that first.
|
|
72
|
+
|
|
73
|
+
The cross-vendor **Standard Webhooks** spec (adopted by Svix, Clerk, Resend,
|
|
74
|
+
Brex and others) defines the scheme this skill defaults to: headers
|
|
75
|
+
`webhook-id`, `webhook-timestamp`, `webhook-signature`; the signature is
|
|
76
|
+
`base64(HMAC-SHA256(secret, "{id}.{timestamp}.{body}"))`, version-prefixed as
|
|
77
|
+
`v1,<sig>`, and the header may carry **space-separated** signatures so a secret
|
|
78
|
+
can be rotated without dropped deliveries — accept the request if **any** match.
|
|
79
|
+
|
|
80
|
+
```js
|
|
81
|
+
import crypto from "node:crypto";
|
|
82
|
+
|
|
83
|
+
function verify(raw, headers) {
|
|
84
|
+
const id = headers["webhook-id"];
|
|
85
|
+
const ts = headers["webhook-timestamp"];
|
|
86
|
+
const secret = process.env.WEBHOOK_SECRET; // never a literal
|
|
87
|
+
const signed = `${id}.${ts}.${raw.toString("utf8")}`;
|
|
88
|
+
const expected = crypto
|
|
89
|
+
.createHmac("sha256", Buffer.from(secret, "base64"))
|
|
90
|
+
.update(signed)
|
|
91
|
+
.digest("base64");
|
|
92
|
+
// header is "v1,<sig> v1,<sig2>"; accept if any matches (secret rotation)
|
|
93
|
+
return String(headers["webhook-signature"] || "")
|
|
94
|
+
.split(" ")
|
|
95
|
+
.map((part) => part.split(",")[1])
|
|
96
|
+
.some((sig) => sameLength(sig, expected) &&
|
|
97
|
+
crypto.timingSafeEqual(Buffer.from(sig), Buffer.from(expected)));
|
|
98
|
+
}
|
|
99
|
+
const sameLength = (a = "", b = "") => a.length === b.length;
|
|
100
|
+
```
|
|
101
|
+
|
|
102
|
+
```python
|
|
103
|
+
import hmac, hashlib, base64, os
|
|
104
|
+
|
|
105
|
+
def verify(raw: bytes, headers) -> bool:
|
|
106
|
+
secret = base64.b64decode(os.environ["WEBHOOK_SECRET"]) # never a literal
|
|
107
|
+
signed = f'{headers["webhook-id"]}.{headers["webhook-timestamp"]}.'.encode() + raw
|
|
108
|
+
expected = base64.b64encode(hmac.new(secret, signed, hashlib.sha256).digest()).decode()
|
|
109
|
+
sent = headers.get("webhook-signature", "")
|
|
110
|
+
for part in sent.split(" "): # space-separated for rotation
|
|
111
|
+
sig = part.split(",", 1)[-1]
|
|
112
|
+
if hmac.compare_digest(sig, expected): # constant time
|
|
113
|
+
return True
|
|
114
|
+
return False
|
|
115
|
+
```
|
|
116
|
+
|
|
117
|
+
Per-provider header formats (Stripe `t=,v1=`, GitHub `X-Hub-Signature-256`,
|
|
118
|
+
Shopify base64 HMAC, Slack `v0=`, Svix) all map onto the same primitive —
|
|
119
|
+
mapping table and per-language verify primitives in
|
|
120
|
+
`references/signature-schemes.md`.
|
|
121
|
+
|
|
122
|
+
## Timestamp & replay
|
|
123
|
+
|
|
124
|
+
A valid signature does not stop a replay: an attacker who captures one delivery
|
|
125
|
+
can re-send the exact bytes, signature intact. Bound it with a timestamp.
|
|
126
|
+
|
|
127
|
+
**Reject any event whose `webhook-timestamp` is more than ~5 minutes from now.**
|
|
128
|
+
That five-minute window is the de-facto industry value (Benchling and others
|
|
129
|
+
recommend it). The Standard Webhooks spec mandates that you perform *a*
|
|
130
|
+
tolerance check but does not fix the number — pick a small one.
|
|
131
|
+
|
|
132
|
+
```js
|
|
133
|
+
const skewSeconds = Math.abs(Date.now() / 1000 - Number(ts));
|
|
134
|
+
if (skewSeconds > 300) return res.sendStatus(400); // outside the 5-min window
|
|
135
|
+
```
|
|
136
|
+
|
|
137
|
+
The timestamp window bounds *how long* a captured payload is replayable; the
|
|
138
|
+
idempotency check (next section) stops *exact* replays that arrive inside the
|
|
139
|
+
window. You need both — neither alone is enough.
|
|
140
|
+
|
|
141
|
+
## Idempotency
|
|
142
|
+
|
|
143
|
+
**The idempotency key is the provider's stable event id** (`webhook-id`, or for
|
|
144
|
+
Stripe `event.id`) — never a hash of the body or your own generated id. Mark it
|
|
145
|
+
seen *before* doing the work, so a retry that arrives mid-processing is caught.
|
|
146
|
+
|
|
147
|
+
Two stores, same idea:
|
|
148
|
+
|
|
149
|
+
| Store | Mechanism | TTL / lifetime |
|
|
150
|
+
|-------|-----------|----------------|
|
|
151
|
+
| Relational DB | `INSERT` the event id into a table with a **UNIQUE** constraint; a duplicate insert throws → skip | Keep the row at least as long as the retry window |
|
|
152
|
+
| Redis | `SET key val NX EX <ttl>` — `SETNX` returns false if already present → skip | TTL **≥ the provider's retry window** (hours to days) |
|
|
153
|
+
|
|
154
|
+
**The dedupe TTL must outlive the provider's entire retry schedule.** Retries
|
|
155
|
+
are exponential and capped — a provider may redeliver hours or days later. If
|
|
156
|
+
your key expires first, that late retry looks brand-new and you process twice.
|
|
157
|
+
|
|
158
|
+
```js
|
|
159
|
+
// Insert-then-process: the UNIQUE insert is the gate. Do work only if we won it.
|
|
160
|
+
try {
|
|
161
|
+
await db.query("INSERT INTO seen_events (id) VALUES ($1)", [id]);
|
|
162
|
+
} catch (e) {
|
|
163
|
+
if (e.code === "23505") return res.sendStatus(200); // already seen → ack, skip
|
|
164
|
+
throw e;
|
|
165
|
+
}
|
|
166
|
+
await queue.add("process", { id, event });
|
|
167
|
+
res.sendStatus(200);
|
|
168
|
+
```
|
|
169
|
+
|
|
170
|
+
Prefer **insert-then-process** over **process-then-mark**. Marking after the
|
|
171
|
+
work leaves a window where two concurrent deliveries both pass the "have I seen
|
|
172
|
+
it?" check and both run. Let the UNIQUE constraint (or `NX`) be the lock.
|
|
173
|
+
|
|
174
|
+
## Fast-ack & queue
|
|
175
|
+
|
|
176
|
+
Heavy synchronous work inside the handler causes provider timeouts and a storm
|
|
177
|
+
of retries. Return `2xx` as soon as the event is durably stored or enqueued,
|
|
178
|
+
then do the real work in a background worker. The status code is a contract with
|
|
179
|
+
the sender:
|
|
180
|
+
|
|
181
|
+
| You return | Meaning to the provider | Use it when |
|
|
182
|
+
|------------|-------------------------|-------------|
|
|
183
|
+
| `2xx` | "I own this now" | After enqueue/persist — **even if** downstream processing later fails. Recover failures from your own queue, not by asking for a redelivery. |
|
|
184
|
+
| `4xx` | Permanent reject, do not retry | Bad/forged signature (`400`/`401`), or a payload you will never accept. A retry of a forged request is still forged. |
|
|
185
|
+
| `5xx` / timeout | "Try again" | A genuine transient failure *before* you took ownership (e.g. the queue itself is down). |
|
|
186
|
+
|
|
187
|
+
Once work is in the queue, handle failures there: bounded retries with backoff,
|
|
188
|
+
then route exhausted jobs to a **dead-letter queue / poison shelf** for manual
|
|
189
|
+
inspection. Do not let a poison event loop forever or block the queue head.
|
|
190
|
+
Queue/broker tuning itself (concurrency, DLQ wiring) is `redis`'s job.
|
|
191
|
+
|
|
192
|
+
## Framework raw-body recipes
|
|
193
|
+
|
|
194
|
+
Capturing the raw body is framework-specific and is the usual culprit behind
|
|
195
|
+
"mismatch though the secret is correct." One line each; full recipes in
|
|
196
|
+
`references/framework-raw-body.md`:
|
|
197
|
+
|
|
198
|
+
- **Express** — mount `express.raw({ type: "*/*" })` on the webhook route only;
|
|
199
|
+
do not let a global `express.json()` consume it first.
|
|
200
|
+
- **Next.js App Router** — read `await req.text()` (or `req.arrayBuffer()`) in
|
|
201
|
+
the route handler; the App Router does not auto-parse, but `await req.json()`
|
|
202
|
+
discards the raw bytes, so verify off the text.
|
|
203
|
+
- **FastAPI / Starlette** — `await request.body()` for the raw `bytes`; do not
|
|
204
|
+
type the handler param as a Pydantic model (that parses for you).
|
|
205
|
+
- **Hono** — `await c.req.text()` before any `c.req.json()`.
|
|
206
|
+
- **Serverless (Lambda/Vercel/Cloudflare)** — disable body parsing / read the
|
|
207
|
+
raw stream; base64-decode if the platform wraps the body.
|
|
208
|
+
|
|
209
|
+
## Anti-patterns
|
|
210
|
+
|
|
211
|
+
| Anti-pattern | Why it bites | Do instead |
|
|
212
|
+
|--------------|--------------|------------|
|
|
213
|
+
| HMAC over parsed/re-serialized JSON | Key reorder + whitespace break the signature ("works with the right secret but still fails") | Verify over the raw bytes captured before parsing |
|
|
214
|
+
| `===` / `==` on the signature | Timing side-channel leaks the secret byte by byte | `crypto.timingSafeEqual` / `hmac.compare_digest` |
|
|
215
|
+
| Heavy synchronous work in the handler | Provider times out → retry storm → duplicate processing | Fast-ack: verify → dedupe → enqueue → `2xx`, work in a worker |
|
|
216
|
+
| Ack before persisting/enqueueing | `2xx` means "I own it"; if you crash now the event is lost forever (provider won't retry a 2xx) | Persist or enqueue *first*, then return `2xx` |
|
|
217
|
+
| No dedupe / dedupe on a body hash | At-least-once delivery double-processes; body hashes drift across redeliveries | UNIQUE-constraint or `SETNX` on the provider's stable event id |
|
|
218
|
+
| Dedupe TTL shorter than the retry window | A late retry looks new and runs again | TTL ≥ the provider's full retry schedule (hours–days) |
|
|
219
|
+
| Signing secret hard-coded in source | Leaks in git history; can't rotate | Read from env; accept space-separated sigs for rotation |
|
|
220
|
+
| Returning `200` on a bad signature | Silently swallows forged traffic and masks misconfig | `400`/`401` on signature failure |
|
|
221
|
+
| Skipping the timestamp check | Valid-but-replayed payloads sail through | Reject outside the ~5-min window |
|
|
222
|
+
|
|
223
|
+
## Verify your handler
|
|
224
|
+
|
|
225
|
+
`scripts/verify.sh` is a read-only heuristic linter. Run it from the root of the
|
|
226
|
+
project that contains your handler; it scans candidate files and prints
|
|
227
|
+
PASS/WARN/FAIL per invariant (raw-body verify, constant-time compare, timestamp
|
|
228
|
+
check, secret-from-env, dedupe-on-event-id). A WARN means "I could not find
|
|
229
|
+
evidence," which on a clean tree is expected and exits `0`.
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
# Evals — webhooks
|
|
2
|
+
|
|
3
|
+
These cases are descriptive routing/capability checks, not an automated test
|
|
4
|
+
suite. To run them, feed each `should_trigger` prompt to the skill router and
|
|
5
|
+
confirm `webhooks` is selected (the `why` explains the intent, including the
|
|
6
|
+
non-obvious raw-body and fast-ack symptoms); feed each `should_not_trigger`
|
|
7
|
+
prompt and confirm the router picks the named sibling in `route_to` instead
|
|
8
|
+
(these guard the boundaries against `stripe`, `email-connector`,
|
|
9
|
+
`api-connector-builder`, `automation-flows` and `redis`). The `capability` case
|
|
10
|
+
is graded by generation: have the skill produce the Express handler and check
|
|
11
|
+
the output against the `must_include` rubric — every line should be present
|
|
12
|
+
(raw-body HMAC, constant-time compare, 5-min window, dedupe-on-event-id with a
|
|
13
|
+
TTL that outlives retries, 2xx-after-enqueue, secret-from-env, 400/401 on a bad
|
|
14
|
+
signature). `scripts/verify.sh` is a complementary static linter for those same
|
|
15
|
+
invariants against real handler files; it is advisory, not part of this eval.
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
skill: webhooks
|
|
2
|
+
|
|
3
|
+
should_trigger:
|
|
4
|
+
- prompt: "We need to receive webhooks from a provider and process them without dropping events or double-processing. Where do I start?"
|
|
5
|
+
why: "Core inbound flow: receive + dedupe + safe processing is the skill's whole mandate (verify → timestamp → dedupe → fast-ack)."
|
|
6
|
+
- prompt: "My webhook signature verification keeps failing even though the signing secret is definitely correct. What am I missing?"
|
|
7
|
+
why: "Non-obvious. The classic raw-body trap — verifying over re-serialized JSON instead of the raw bytes. The skill names this exact symptom."
|
|
8
|
+
- prompt: "The provider keeps retrying and our handler ends up running the same event twice. How do we make it idempotent?"
|
|
9
|
+
why: "At-least-once delivery + idempotency on the stable event id is a flagship section; phrased as a symptom, not jargon."
|
|
10
|
+
- prompt: "How do I do a constant-time signature compare and a timestamp/replay check on an incoming webhook?"
|
|
11
|
+
why: "Verify mechanics: timingSafeEqual / compare_digest plus the ~5-min tolerance window are core content."
|
|
12
|
+
- prompt: "Verificar la firma del webhook entrante y evitar procesar el mismo evento dos veces — ¿cómo lo monto en Express?"
|
|
13
|
+
why: "Spanish trigger covering signature verification + idempotency, the two central invariants."
|
|
14
|
+
- prompt: "Our webhook endpoint times out under load and the sender hammers it with retries. How do we ack fast and move the work off the request?"
|
|
15
|
+
why: "Non-obvious framing of the fast-ack-then-queue pattern; the timeout→retry-storm chain is the reason the pattern exists."
|
|
16
|
+
- prompt: "What status code should I return from a webhook handler when the signature is bad versus when my downstream save fails?"
|
|
17
|
+
why: "Status-code semantics (2xx = I own it, 4xx = forged/no-retry, 5xx = genuine retry) is a dedicated decision table."
|
|
18
|
+
|
|
19
|
+
should_not_trigger:
|
|
20
|
+
- prompt: "Verify a Stripe webhook with the Stripe-Signature header and handle checkout.session.completed in my SaaS."
|
|
21
|
+
route_to: stripe
|
|
22
|
+
why: "Stripe's specific t=,v1= scheme, event model and stripe listen CLI belong to the specialized skill; webhooks covers only the generic case."
|
|
23
|
+
- prompt: "Handle Resend and SendGrid bounce and complaint webhooks so our suppression list stays clean."
|
|
24
|
+
route_to: email-connector
|
|
25
|
+
why: "The point is deliverability suppression state, not generic receive-and-verify mechanics."
|
|
26
|
+
- prompt: "Build a client that calls the GitHub REST API with auth, pagination and retries on the requests we initiate."
|
|
27
|
+
route_to: api-connector-builder
|
|
28
|
+
why: "That is the outbound client (we call them), the opposite direction from an inbound receiver."
|
|
29
|
+
- prompt: "After an order webhook lands, branch across Slack, the database and an email in a multi-step flow with conditions."
|
|
30
|
+
route_to: automation-flows
|
|
31
|
+
why: "Post-landing orchestration; webhooks ends at 'enqueued' and the flow engine takes over from there."
|
|
32
|
+
- prompt: "Tune our BullMQ worker concurrency and set up a dead-letter queue in Redis."
|
|
33
|
+
route_to: redis
|
|
34
|
+
why: "Broker/queue operations, not the front-door receiver; webhooks enqueues but does not own broker tuning."
|
|
35
|
+
|
|
36
|
+
capability:
|
|
37
|
+
- scenario: "Implement an inbound webhook endpoint for a generic Standard-Webhooks provider in Node/Express that receives an event, proves it is authentic, refuses to process it twice, and acks fast — then describe where the real work runs."
|
|
38
|
+
must_include:
|
|
39
|
+
- "HMAC is computed over the RAW request body (raw buffer/text), not over JSON.parse(req.body) or a re-serialized object"
|
|
40
|
+
- "constant-time comparison via crypto.timingSafeEqual (not === / ==), with an equal-length guard"
|
|
41
|
+
- "timestamp tolerance check (~5 minutes) rejecting stale/replayed deliveries"
|
|
42
|
+
- "dedupe on the provider's stable event id (webhook-id) via a UNIQUE constraint or Redis SETNX, marked before processing"
|
|
43
|
+
- "dedupe TTL must outlive the provider's retry window (hours to days)"
|
|
44
|
+
- "returns 2xx only after the event is persisted/enqueued, then does the work in a background worker"
|
|
45
|
+
- "signing secret read from an environment variable, never a hard-coded literal"
|
|
46
|
+
- "bad/forged signature returns 400 or 401, not 200"
|
|
@@ -0,0 +1,97 @@
|
|
|
1
|
+
# Getting the raw body, per framework
|
|
2
|
+
|
|
3
|
+
If your signature check fails but the secret is correct, you are almost always
|
|
4
|
+
verifying over a **re-serialized** body instead of the raw bytes the sender
|
|
5
|
+
signed. Each framework hides the raw body somewhere different. The rule is the
|
|
6
|
+
same everywhere: **capture the raw bytes, verify, and only then parse.**
|
|
7
|
+
|
|
8
|
+
## Express
|
|
9
|
+
|
|
10
|
+
A global `express.json()` consumes the stream, so by the time your handler runs
|
|
11
|
+
the original bytes are gone. Mount `express.raw()` on the webhook route only.
|
|
12
|
+
|
|
13
|
+
```js
|
|
14
|
+
import express from "express";
|
|
15
|
+
const app = express();
|
|
16
|
+
app.use(express.json()); // fine for the rest of the app
|
|
17
|
+
|
|
18
|
+
// Webhook route gets RAW, mounted before/instead of the global parser for this path.
|
|
19
|
+
app.post("/webhooks", express.raw({ type: "*/*" }), (req, res) => {
|
|
20
|
+
const raw = req.body; // Buffer — exact bytes
|
|
21
|
+
if (!verify(raw, req.headers)) return res.sendStatus(400);
|
|
22
|
+
const event = JSON.parse(raw.toString("utf8"));
|
|
23
|
+
// dedupe + enqueue + res.sendStatus(200)
|
|
24
|
+
});
|
|
25
|
+
```
|
|
26
|
+
|
|
27
|
+
If a global parser already ran, recover the bytes with a `verify` callback:
|
|
28
|
+
`express.json({ verify: (req, _res, buf) => { req.rawBody = buf; } })`.
|
|
29
|
+
|
|
30
|
+
## Next.js (App Router)
|
|
31
|
+
|
|
32
|
+
Route handlers do **not** auto-parse, but `await req.json()` reads the stream and
|
|
33
|
+
discards the raw bytes. Read the text instead and parse it yourself after
|
|
34
|
+
verifying.
|
|
35
|
+
|
|
36
|
+
```ts
|
|
37
|
+
// app/api/webhooks/route.ts
|
|
38
|
+
export async function POST(req: Request) {
|
|
39
|
+
const raw = await req.text(); // raw string; do NOT call req.json() first
|
|
40
|
+
const headers = Object.fromEntries(req.headers);
|
|
41
|
+
if (!verify(raw, headers)) return new Response("bad sig", { status: 400 });
|
|
42
|
+
const event = JSON.parse(raw);
|
|
43
|
+
// dedupe + enqueue
|
|
44
|
+
return new Response("ok", { status: 200 });
|
|
45
|
+
}
|
|
46
|
+
```
|
|
47
|
+
|
|
48
|
+
(Pages Router differs: set `export const config = { api: { bodyParser: false } }`
|
|
49
|
+
and read the stream — prefer the App Router handler above.)
|
|
50
|
+
|
|
51
|
+
## FastAPI / Starlette
|
|
52
|
+
|
|
53
|
+
Typing the parameter as a Pydantic model parses the body for you and throws away
|
|
54
|
+
the bytes. Take the raw `bytes` from the `Request`.
|
|
55
|
+
|
|
56
|
+
```python
|
|
57
|
+
from fastapi import FastAPI, Request, Response
|
|
58
|
+
app = FastAPI()
|
|
59
|
+
|
|
60
|
+
@app.post("/webhooks")
|
|
61
|
+
async def webhooks(request: Request):
|
|
62
|
+
raw = await request.body() # bytes — do not declare a model param
|
|
63
|
+
if not verify(raw, request.headers):
|
|
64
|
+
return Response(status_code=400)
|
|
65
|
+
event = json.loads(raw)
|
|
66
|
+
# dedupe + enqueue
|
|
67
|
+
return Response(status_code=200)
|
|
68
|
+
```
|
|
69
|
+
|
|
70
|
+
## Hono
|
|
71
|
+
|
|
72
|
+
```ts
|
|
73
|
+
app.post("/webhooks", async (c) => {
|
|
74
|
+
const raw = await c.req.text(); // before any c.req.json()
|
|
75
|
+
if (!verify(raw, c.req.header())) return c.text("bad sig", 400);
|
|
76
|
+
const event = JSON.parse(raw);
|
|
77
|
+
return c.text("ok", 200);
|
|
78
|
+
});
|
|
79
|
+
```
|
|
80
|
+
|
|
81
|
+
## Serverless (Lambda / Vercel / Cloudflare Workers)
|
|
82
|
+
|
|
83
|
+
- **AWS Lambda (API Gateway / function URL):** the body arrives as a string in
|
|
84
|
+
`event.body`; if `event.isBase64Encoded` is true, `Buffer.from(event.body,
|
|
85
|
+
"base64")` first. Verify over that, never over a parsed object.
|
|
86
|
+
- **Vercel Functions:** disable the body parser for the route and read the raw
|
|
87
|
+
stream (Edge runtime: `await req.text()`).
|
|
88
|
+
- **Cloudflare Workers:** `await request.text()` / `await request.arrayBuffer()`
|
|
89
|
+
in the `fetch` handler; the body is unbuffered, so read it once.
|
|
90
|
+
|
|
91
|
+
## Common traps
|
|
92
|
+
|
|
93
|
+
- A reverse proxy or middleware that re-encodes the body (gzip, charset
|
|
94
|
+
normalization) changes the bytes after the sender signed them — verify before
|
|
95
|
+
any transform, and disable response/transit re-encoding on the webhook path.
|
|
96
|
+
- Reading the body stream twice: many runtimes let you read it once. Capture the
|
|
97
|
+
raw bytes into a variable and reuse that variable for both verify and parse.
|
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
# Per-provider signature schemes
|
|
2
|
+
|
|
3
|
+
Every webhook signature is the same primitive — `HMAC-SHA256(secret, message)`
|
|
4
|
+
compared in constant time — wrapped in a different header layout. Map the
|
|
5
|
+
provider onto the generic verify routine in `SKILL.md` by answering three
|
|
6
|
+
questions: **which headers carry the id/timestamp/signature**, **what string is
|
|
7
|
+
signed**, and **how is the signature encoded**.
|
|
8
|
+
|
|
9
|
+
## Comparison table
|
|
10
|
+
|
|
11
|
+
| Provider | Signature header | Signed message | Encoding | Timestamp source |
|
|
12
|
+
|----------|------------------|----------------|----------|------------------|
|
|
13
|
+
| Standard Webhooks | `webhook-signature` (`v1,<sig> …` space-separated) | `{webhook-id}.{webhook-timestamp}.{raw-body}` | base64 | `webhook-timestamp` header (Unix seconds) |
|
|
14
|
+
| Stripe | `Stripe-Signature` (`t=<ts>,v1=<sig>`) | `{t}.{raw-body}` | hex | `t` field inside the header |
|
|
15
|
+
| GitHub | `X-Hub-Signature-256` (`sha256=<sig>`) | raw body only | hex | none — rely on TLS + secret; no replay window |
|
|
16
|
+
| Shopify | `X-Shopify-Hmac-SHA256` | raw body only | base64 | none |
|
|
17
|
+
| Slack | `X-Slack-Signature` (`v0=<sig>`) + `X-Slack-Request-Timestamp` | `v0:{timestamp}:{raw-body}` | hex | `X-Slack-Request-Timestamp` header |
|
|
18
|
+
| Svix | same as Standard Webhooks (`svix-id/timestamp/signature` or `webhook-*`) | `{id}.{timestamp}.{raw-body}` | base64 | timestamp header |
|
|
19
|
+
|
|
20
|
+
Notes that bite:
|
|
21
|
+
|
|
22
|
+
- **Stripe and Standard Webhooks both prefix versions and both allow multiple
|
|
23
|
+
comma/space-separated signatures** for secret rotation — accept the request if
|
|
24
|
+
*any* candidate matches. Never `break` on the first mismatch.
|
|
25
|
+
- **GitHub and Shopify sign the body alone** (no id/timestamp), so they have no
|
|
26
|
+
built-in replay window. Lean on HTTPS and the secret; if you need replay
|
|
27
|
+
protection, dedupe on a delivery id (`X-GitHub-Delivery`).
|
|
28
|
+
- **Slack signs `v0:{ts}:{body}`** with a colon separator and a literal `v0:`
|
|
29
|
+
prefix — different layout from the dot-joined Standard Webhooks string.
|
|
30
|
+
- For the **Stripe** scheme specifically (event model, `stripe listen`, the
|
|
31
|
+
billing flows) use `../../stripe/SKILL.md`; this table only covers verifying
|
|
32
|
+
the signature.
|
|
33
|
+
|
|
34
|
+
## Verify primitives by language
|
|
35
|
+
|
|
36
|
+
The two things that must be language-correct: feed the **raw bytes** to the HMAC,
|
|
37
|
+
and use the **constant-time** comparator.
|
|
38
|
+
|
|
39
|
+
| Language | HMAC-SHA256 | Constant-time compare |
|
|
40
|
+
|----------|-------------|------------------------|
|
|
41
|
+
| Node.js | `crypto.createHmac("sha256", key).update(raw).digest()` | `crypto.timingSafeEqual(a, b)` (equal-length Buffers) |
|
|
42
|
+
| Python | `hmac.new(key, raw, hashlib.sha256).digest()` | `hmac.compare_digest(a, b)` |
|
|
43
|
+
| Go | `hmac.New(sha256.New, key); mac.Write(raw)` | `hmac.Equal(expected, got)` |
|
|
44
|
+
| Ruby | `OpenSSL::HMAC.digest("SHA256", key, raw)` | `Rack::Utils.secure_compare(a, b)` |
|
|
45
|
+
| PHP | `hash_hmac("sha256", $raw, $key, true)` | `hash_equals($a, $b)` |
|
|
46
|
+
|
|
47
|
+
```go
|
|
48
|
+
// Go — Standard Webhooks verify, constant time, raw body in.
|
|
49
|
+
func verify(raw []byte, id, ts, header, secretB64 string) bool {
|
|
50
|
+
key, _ := base64.StdEncoding.DecodeString(secretB64)
|
|
51
|
+
mac := hmac.New(sha256.New, key)
|
|
52
|
+
mac.Write([]byte(id + "." + ts + "."))
|
|
53
|
+
mac.Write(raw)
|
|
54
|
+
expected := base64.StdEncoding.EncodeToString(mac.Sum(nil))
|
|
55
|
+
for _, part := range strings.Fields(header) { // space-separated for rotation
|
|
56
|
+
sig := strings.TrimPrefix(part, "v1,")
|
|
57
|
+
if hmac.Equal([]byte(sig), []byte(expected)) {
|
|
58
|
+
return true
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
return false
|
|
62
|
+
}
|
|
63
|
+
```
|
|
64
|
+
|
|
65
|
+
Whatever the layout, the order from `SKILL.md` does not change: raw body →
|
|
66
|
+
verify → timestamp window → dedupe → enqueue → `2xx`.
|
|
@@ -0,0 +1,142 @@
|
|
|
1
|
+
#!/usr/bin/env bash
|
|
2
|
+
set -euo pipefail
|
|
3
|
+
|
|
4
|
+
# ============================================================================
|
|
5
|
+
# NAME
|
|
6
|
+
# verify.sh — webhooks inbound-handler invariant linter
|
|
7
|
+
#
|
|
8
|
+
# USAGE
|
|
9
|
+
# ./verify.sh [PATH]
|
|
10
|
+
# Run from the ROOT of YOUR project (the repo containing your webhook
|
|
11
|
+
# handler), NOT from the skills repository. PATH defaults to the current
|
|
12
|
+
# directory. Read-only: it never writes, never fixes, never installs.
|
|
13
|
+
#
|
|
14
|
+
# WHAT IT DOES
|
|
15
|
+
# Heuristically scans candidate webhook-handler files for the five inbound
|
|
16
|
+
# invariants and prints PASS / WARN / FAIL per file:
|
|
17
|
+
# 1. raw body is used for HMAC verification (flags parsed-body verify)
|
|
18
|
+
# 2. a constant-time signature compare is present (flags ==/=== on a sig)
|
|
19
|
+
# 3. a timestamp / tolerance check exists
|
|
20
|
+
# 4. the signing secret comes from env, not a string literal
|
|
21
|
+
# 5. a dedupe step references a stable event id
|
|
22
|
+
#
|
|
23
|
+
# It is a HEURISTIC (grep-based), advisory not a compiler. A WARN means
|
|
24
|
+
# "no evidence found", which is not necessarily a bug.
|
|
25
|
+
#
|
|
26
|
+
# EXIT CODES
|
|
27
|
+
# 0 no candidate files found (clean/empty tree), OR all candidates PASS
|
|
28
|
+
# every hard check. WARN never fails the run.
|
|
29
|
+
# 1 a candidate file FAILS a hard check (parsed-body verify, ==/=== on a
|
|
30
|
+
# signature, or a hard-coded secret).
|
|
31
|
+
# ============================================================================
|
|
32
|
+
|
|
33
|
+
TARGET="${1:-.}"
|
|
34
|
+
|
|
35
|
+
if [ ! -e "$TARGET" ]; then
|
|
36
|
+
echo "verify.sh: target not found: $TARGET" >&2
|
|
37
|
+
exit 0
|
|
38
|
+
fi
|
|
39
|
+
|
|
40
|
+
# ----------------------------------------------------------------------------
|
|
41
|
+
# Find candidate handler files: source files that look like they touch
|
|
42
|
+
# webhooks / HMAC signatures. Prune dependency + VCS dirs. NUL-delimited so
|
|
43
|
+
# paths with spaces survive.
|
|
44
|
+
# ----------------------------------------------------------------------------
|
|
45
|
+
# Portable (bash 3.2 / macOS + GNU) NUL-safe array build — no mapfile, no
|
|
46
|
+
# process substitution, and -name globs instead of -iregex (BSD/GNU agree on
|
|
47
|
+
# globs). We stage the NUL-delimited find output in a temp file, then read it.
|
|
48
|
+
LISTFILE="$(mktemp -t webhooks-verify.XXXXXX 2>/dev/null || mktemp)"
|
|
49
|
+
trap 'rm -f "$LISTFILE"' EXIT
|
|
50
|
+
|
|
51
|
+
find "$TARGET" \
|
|
52
|
+
\( -name node_modules -o -name .git -o -name dist -o -name build \
|
|
53
|
+
-o -name vendor -o -name .venv -o -name venv -o -name __pycache__ \) -prune \
|
|
54
|
+
-o -type f \( -name '*.js' -o -name '*.cjs' -o -name '*.mjs' \
|
|
55
|
+
-o -name '*.ts' -o -name '*.tsx' -o -name '*.py' \
|
|
56
|
+
-o -name '*.go' -o -name '*.rb' -o -name '*.php' \) \
|
|
57
|
+
-print0 > "$LISTFILE" 2>/dev/null || true
|
|
58
|
+
|
|
59
|
+
CANDIDATES=()
|
|
60
|
+
while IFS= read -r -d '' f; do
|
|
61
|
+
if grep -Eilq 'webhook|x-hub-signature|stripe-signature|x-slack-signature|hmac' "$f" 2>/dev/null; then
|
|
62
|
+
CANDIDATES+=("$f")
|
|
63
|
+
fi
|
|
64
|
+
done < "$LISTFILE"
|
|
65
|
+
|
|
66
|
+
if [ "${#CANDIDATES[@]}" -eq 0 ]; then
|
|
67
|
+
echo "PASS no webhook-handler files found under '$TARGET' — nothing to lint."
|
|
68
|
+
exit 0
|
|
69
|
+
fi
|
|
70
|
+
|
|
71
|
+
C_RESET=$'\033[0m'; C_RED=$'\033[31m'; C_GRN=$'\033[32m'; C_YEL=$'\033[33m'
|
|
72
|
+
say_pass() { printf '%sPASS%s %s\n' "$C_GRN" "$C_RESET" "$1"; }
|
|
73
|
+
say_warn() { printf '%sWARN%s %s\n' "$C_YEL" "$C_RESET" "$1"; }
|
|
74
|
+
say_fail() { printf '%sFAIL%s %s\n' "$C_RED" "$C_RESET" "$1"; }
|
|
75
|
+
|
|
76
|
+
# matches lines, case-insensitive, fixed cost
|
|
77
|
+
has() { grep -Eiq "$1" "$2" 2>/dev/null; }
|
|
78
|
+
|
|
79
|
+
exit_code=0
|
|
80
|
+
|
|
81
|
+
for f in "${CANDIDATES[@]}"; do
|
|
82
|
+
echo "── $f"
|
|
83
|
+
|
|
84
|
+
# 1. raw body used / parsed-body verify NOT used --------------------------
|
|
85
|
+
# Hard fail if we see a signature/HMAC built from an obviously parsed
|
|
86
|
+
# body (JSON.stringify(req.body), JSON.parse(...) fed to the digest).
|
|
87
|
+
if has 'createHmac|hmac\.new|OpenSSL::HMAC|hash_hmac|hmac\.New' "$f"; then
|
|
88
|
+
if has 'JSON\.stringify\s*\(\s*req\.body|JSON\.stringify\s*\(\s*request\.body' "$f"; then
|
|
89
|
+
say_fail "(1) HMAC appears to run over re-serialized parsed body (JSON.stringify(req.body)) — verify over the raw bytes"
|
|
90
|
+
exit_code=1
|
|
91
|
+
elif has 'rawbody|raw_body|req\.text\(\)|request\.body\(\)|c\.req\.text\(\)|arraybuffer|express\.raw|isbase64encoded' "$f"; then
|
|
92
|
+
say_pass "(1) raw body captured for HMAC verification"
|
|
93
|
+
else
|
|
94
|
+
say_warn "(1) HMAC found but no clear raw-body capture — confirm you verify over the raw bytes, not parsed JSON"
|
|
95
|
+
fi
|
|
96
|
+
else
|
|
97
|
+
say_warn "(1) no HMAC call detected in this file"
|
|
98
|
+
fi
|
|
99
|
+
|
|
100
|
+
# 2. constant-time compare -----------------------------------------------
|
|
101
|
+
if has 'timingsafeequal|compare_digest|hmac\.equal|secure_compare|hash_equals' "$f"; then
|
|
102
|
+
say_pass "(2) constant-time signature compare present"
|
|
103
|
+
elif has 'signature\s*===|signature\s*==|sig\s*===|sig\s*==|=== *expectedsig|== *expectedsig' "$f"; then
|
|
104
|
+
say_fail "(2) signature compared with ==/=== — timing leak; use a constant-time comparator"
|
|
105
|
+
exit_code=1
|
|
106
|
+
else
|
|
107
|
+
say_warn "(2) no constant-time compare detected — confirm timingSafeEqual / compare_digest is used"
|
|
108
|
+
fi
|
|
109
|
+
|
|
110
|
+
# 3. timestamp / tolerance check -----------------------------------------
|
|
111
|
+
if has 'webhook-timestamp|x-slack-request-timestamp|timestamp' "$f" \
|
|
112
|
+
&& has '300|5 *\* *60|tolerance|skew|maxage|max_age|window' "$f"; then
|
|
113
|
+
say_pass "(3) timestamp tolerance / replay window check present"
|
|
114
|
+
else
|
|
115
|
+
say_warn "(3) no timestamp tolerance check detected — reject events outside ~5 minutes"
|
|
116
|
+
fi
|
|
117
|
+
|
|
118
|
+
# 4. secret from env, not a literal --------------------------------------
|
|
119
|
+
if has 'webhook_secret\s*=\s*["'\''][a-z0-9_]{12,}|signing_secret\s*=\s*["'\''][a-z0-9_]{12,}|whsec_[a-z0-9]' "$f"; then
|
|
120
|
+
say_fail "(4) signing secret looks hard-coded — read it from an environment variable"
|
|
121
|
+
exit_code=1
|
|
122
|
+
elif has 'process\.env|os\.environ|os\.getenv|env\(|ENV\[' "$f"; then
|
|
123
|
+
say_pass "(4) signing secret sourced from environment"
|
|
124
|
+
else
|
|
125
|
+
say_warn "(4) no env lookup detected — confirm the signing secret comes from env"
|
|
126
|
+
fi
|
|
127
|
+
|
|
128
|
+
# 5. dedupe on event id ---------------------------------------------------
|
|
129
|
+
if has 'unique|setnx|set .* nx|already.processed|already.seen|seen_event|idempoten|webhook-id|event\.id|delivery.id' "$f"; then
|
|
130
|
+
say_pass "(5) dedupe / idempotency on an event id present"
|
|
131
|
+
else
|
|
132
|
+
say_warn "(5) no dedupe step detected — dedupe on the provider's stable event id (UNIQUE / SETNX)"
|
|
133
|
+
fi
|
|
134
|
+
done
|
|
135
|
+
|
|
136
|
+
echo
|
|
137
|
+
if [ "$exit_code" -eq 0 ]; then
|
|
138
|
+
echo "${C_GRN}verify.sh: no hard failures.${C_RESET} WARN lines are advisory — review them."
|
|
139
|
+
else
|
|
140
|
+
echo "${C_RED}verify.sh: hard failures found.${C_RESET} Fix the FAIL lines above."
|
|
141
|
+
fi
|
|
142
|
+
exit "$exit_code"
|