@thedecipherist/claude-packs 0.0.0-stage → 1.0.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/CHANGELOG.md +680 -0
- package/LICENSE +21 -0
- package/README.md +316 -2
- package/bin/claude-packs.mjs +204 -0
- package/configurations/base/config.json +85 -0
- package/configurations/cpp/config.json +92 -0
- package/configurations/full-stack/config.json +152 -0
- package/configurations/go/config.json +96 -0
- package/configurations/node/config.json +100 -0
- package/configurations/python/config.json +97 -0
- package/configurations/synth-creator/config.json +148 -0
- package/global/hooks/gnu-shell.mjs +131 -0
- package/global/hooks/lib/program-read.mjs +196 -0
- package/global/hooks/lib/program-writes.mjs +177 -0
- package/global/hooks/lib/shell-writes.mjs +293 -0
- package/global/hooks/shell-traps.mjs +79 -0
- package/global/hooks/version-pin-guard.mjs +280 -0
- package/global/skills/latest-versions/SKILL.md +49 -0
- package/lib/backup.mjs +34 -0
- package/lib/claude-md.mjs +58 -0
- package/lib/config-cli.mjs +36 -0
- package/lib/configs.mjs +145 -0
- package/lib/coverage.mjs +86 -0
- package/lib/custom-packs.mjs +93 -0
- package/lib/doctor.mjs +115 -0
- package/lib/fix-plan.mjs +71 -0
- package/lib/git-tokens.mjs +64 -0
- package/lib/global.mjs +125 -0
- package/lib/hook-proof.mjs +28 -0
- package/lib/hook-timing.mjs +42 -0
- package/lib/hover-gate.mjs +29 -0
- package/lib/kit-lock.mjs +149 -0
- package/lib/layout.mjs +75 -0
- package/lib/logs.mjs +69 -0
- package/lib/manifest.mjs +24 -0
- package/lib/new.mjs +49 -0
- package/lib/once-only-report.mjs +54 -0
- package/lib/pack-manifest.mjs +20 -0
- package/lib/packs.mjs +107 -0
- package/lib/planner.mjs +59 -0
- package/lib/repeats.mjs +65 -0
- package/lib/repo-weight.mjs +28 -0
- package/lib/rules.mjs +40 -0
- package/lib/scan-detect.mjs +94 -0
- package/lib/scan.mjs +168 -0
- package/lib/selftest-cache.mjs +39 -0
- package/lib/settings.mjs +138 -0
- package/lib/shape-cli.mjs +76 -0
- package/lib/shape.mjs +4 -0
- package/lib/suggest.mjs +18 -0
- package/lib/switches.mjs +44 -0
- package/lib/symmetry-doctor.mjs +26 -0
- package/lib/sync.mjs +130 -0
- package/package.json +34 -4
- package/packs/ai/checks/boundary-computes-its-own-hash.json +30 -0
- package/packs/ai/checks/model-call-needs-boundary.json +29 -0
- package/packs/ai/checks/model-id-from-config.json +28 -0
- package/packs/ai/checks/model-output-validated.json +26 -0
- package/packs/ai/pack.json +38 -0
- package/packs/ai/rules/ai-input-sha-boundary.md +31 -0
- package/packs/ai/rules/llm-pipeline-security.md +26 -0
- package/packs/audio-core/checks/denormals-not-in-prepare.json +12 -0
- package/packs/audio-core/checks/dsp-without-apvts.json +12 -0
- package/packs/audio-core/checks/float-phase-or-rate.json +12 -0
- package/packs/audio-core/checks/juce-snap-to-zero-off.json +12 -0
- package/packs/audio-core/checks/keep-werror.json +12 -0
- package/packs/audio-core/checks/no-fast-math.json +14 -0
- package/packs/audio-core/checks/no-locale-change.json +12 -0
- package/packs/audio-core/checks/no-march-native.json +14 -0
- package/packs/audio-core/clang-tidy +28 -0
- package/packs/audio-core/hooks/lib/realtime-checks.mjs +56 -0
- package/packs/audio-core/hooks/param-id-lock.mjs +129 -0
- package/packs/audio-core/hooks/realtime-guard.mjs +67 -0
- package/packs/audio-core/pack.json +187 -0
- package/packs/audio-core/rules/audio-thread-realtime-safe.md +27 -0
- package/packs/audio-core/rules/audio-ui-thread-handoff.md +21 -0
- package/packs/audio-core/rules/boundary-tests-cross-the-boundary.md +16 -0
- package/packs/audio-core/rules/build-flags-safe.md +20 -0
- package/packs/audio-core/rules/cached-parameter-pointers.md +28 -0
- package/packs/audio-core/rules/clang-tidy-core-guidelines.md +21 -0
- package/packs/audio-core/rules/control-reaches-every-surface.md +23 -0
- package/packs/audio-core/rules/cpu-worst-case-per-block.md +26 -0
- package/packs/audio-core/rules/dc-block-after-asymmetry.md +22 -0
- package/packs/audio-core/rules/discrete-params-snap.md +19 -0
- package/packs/audio-core/rules/double-where-precision-matters.md +20 -0
- package/packs/audio-core/rules/filters-stable-under-modulation.md +29 -0
- package/packs/audio-core/rules/host-parameters-at-scale.md +24 -0
- package/packs/audio-core/rules/house-control-behaviours.md +34 -0
- package/packs/audio-core/rules/math-domain-guards.md +19 -0
- package/packs/audio-core/rules/modulated-delay-interpolation.md +22 -0
- package/packs/audio-core/rules/multiband-phase-coherent.md +22 -0
- package/packs/audio-core/rules/nonlinear-stages-antialiased.md +28 -0
- package/packs/audio-core/rules/note-ledger-and-pedals.md +22 -0
- package/packs/audio-core/rules/one-formula-per-value.md +20 -0
- package/packs/audio-core/rules/optimisations-are-null-tested.md +23 -0
- package/packs/audio-core/rules/oscillators-bandlimited.md +23 -0
- package/packs/audio-core/rules/output-limiter.md +23 -0
- package/packs/audio-core/rules/parameter-ids-never-change.md +20 -0
- package/packs/audio-core/rules/params-and-state-thread-safe.md +19 -0
- package/packs/audio-core/rules/params-snapshot-per-block.md +21 -0
- package/packs/audio-core/rules/patch-excludes-performance-controls.md +18 -0
- package/packs/audio-core/rules/per-sample-code-inlinable.md +22 -0
- package/packs/audio-core/rules/prepare-is-repeatable.md +23 -0
- package/packs/audio-core/rules/recursive-state-nan-guard.md +20 -0
- package/packs/audio-core/rules/reverb-loop-gain-bounded.md +24 -0
- package/packs/audio-core/rules/sample-accurate-midi.md +22 -0
- package/packs/audio-core/rules/sample-rate-and-block-size-from-host.md +23 -0
- package/packs/audio-core/rules/scoped-no-denormals.md +26 -0
- package/packs/audio-core/rules/smooth-continuous-parameters.md +22 -0
- package/packs/audio-core/rules/state-load-versioned-and-safe.md +22 -0
- package/packs/audio-core/rules/straight-on-and-aligned.md +21 -0
- package/packs/audio-core/rules/ui-matches-reference-look.md +21 -0
- package/packs/audio-core/rules/undo-one-gesture-one-step.md +21 -0
- package/packs/audio-core/rules/voice-steal-fades.md +21 -0
- package/packs/audio-core/rules/voice-sum-headroom.md +20 -0
- package/packs/audio-core/skills/analyse-reference-look/SKILL.md +21 -0
- package/packs/audio-core/skills/copy-and-prove/SKILL.md +98 -0
- package/packs/audio-core/skills/juce-realtime-audit/SKILL.md +22 -0
- package/packs/audio-core/skills/measure-tone/SKILL.md +20 -0
- package/packs/audio-core/skills/new-panel-control/SKILL.md +15 -0
- package/packs/audio-core/skills/prove-control/SKILL.md +23 -0
- package/packs/audio-core/skills/trace-parameter/SKILL.md +29 -0
- package/packs/audio-core/tools/lib/spectrum.mjs +112 -0
- package/packs/audio-core/tools/lib/wav.mjs +41 -0
- package/packs/audio-core/tools/tone-report.mjs +47 -0
- package/packs/base/checks/field-map-over-if-runs.json +25 -0
- package/packs/base/checks/lookup-over-if-chains.json +25 -0
- package/packs/base/checks/lookup-over-ternary-chains.json +20 -0
- package/packs/base/checks/no-code-after-midline-comment.json +12 -0
- package/packs/base/checks/one-walk-per-template.json +23 -0
- package/packs/base/checks/stub-reports-success.json +31 -0
- package/packs/base/checks/test-skip-on-failed-setup.json +17 -0
- package/packs/base/hooks/brief-guard.mjs +96 -0
- package/packs/base/hooks/code-shape.mjs +95 -0
- package/packs/base/hooks/dispatch-once.mjs +87 -0
- package/packs/base/hooks/file-size-guard.mjs +61 -0
- package/packs/base/hooks/folder-law.mjs +74 -0
- package/packs/base/hooks/git-guard.mjs +289 -0
- package/packs/base/hooks/lesson-checks.mjs +174 -0
- package/packs/base/hooks/lib/apply-edit.mjs +20 -0
- package/packs/base/hooks/lib/code-shapes.mjs +137 -0
- package/packs/base/hooks/lib/content.mjs +14 -0
- package/packs/base/hooks/lib/cpp-scan.mjs +94 -0
- package/packs/base/hooks/lib/dup-index.mjs +199 -0
- package/packs/base/hooks/lib/dup.mjs +127 -0
- package/packs/base/hooks/lib/elements.mjs +87 -0
- package/packs/base/hooks/lib/event-log.mjs +67 -0
- package/packs/base/hooks/lib/function-shapes.mjs +90 -0
- package/packs/base/hooks/lib/git-adds.mjs +20 -0
- package/packs/base/hooks/lib/git-guard-selftest.mjs +99 -0
- package/packs/base/hooks/lib/glob.mjs +33 -0
- package/packs/base/hooks/lib/hook-log.mjs +100 -0
- package/packs/base/hooks/lib/house.py +77 -0
- package/packs/base/hooks/lib/languages.mjs +66 -0
- package/packs/base/hooks/lib/layout.mjs +54 -0
- package/packs/base/hooks/lib/making-check-selftest.mjs +109 -0
- package/packs/base/hooks/lib/near-copies.mjs +76 -0
- package/packs/base/hooks/lib/program-read.mjs +196 -0
- package/packs/base/hooks/lib/program-writes.mjs +177 -0
- package/packs/base/hooks/lib/project.mjs +81 -0
- package/packs/base/hooks/lib/prose.mjs +11 -0
- package/packs/base/hooks/lib/pushed.mjs +201 -0
- package/packs/base/hooks/lib/repo-index.mjs +52 -0
- package/packs/base/hooks/lib/secret-patterns.mjs +18 -0
- package/packs/base/hooks/lib/selftest.mjs +45 -0
- package/packs/base/hooks/lib/shape-code.mjs +126 -0
- package/packs/base/hooks/lib/shape.mjs +294 -0
- package/packs/base/hooks/lib/shell-writes-selftest.mjs +65 -0
- package/packs/base/hooks/lib/shell-writes.mjs +293 -0
- package/packs/base/hooks/lib/turn.mjs +81 -0
- package/packs/base/hooks/lib/writes.mjs +71 -0
- package/packs/base/hooks/making-check.mjs +243 -0
- package/packs/base/hooks/making.mjs +106 -0
- package/packs/base/hooks/once-only.mjs +150 -0
- package/packs/base/hooks/placement-law.mjs +84 -0
- package/packs/base/hooks/repo-litter.mjs +75 -0
- package/packs/base/hooks/reuse-hint.mjs +75 -0
- package/packs/base/hooks/run-hooks.mjs +132 -0
- package/packs/base/hooks/secrets-guard.mjs +99 -0
- package/packs/base/hooks/shape-law.mjs +133 -0
- package/packs/base/hooks/suite-once.mjs +80 -0
- package/packs/base/hooks/template-law.mjs +148 -0
- package/packs/base/hooks/untrusted-boundary.mjs +53 -0
- package/packs/base/pack.json +214 -0
- package/packs/base/rules/a-control-is-seen-to-fire.md +27 -0
- package/packs/base/rules/behaviour-lives-with-its-kind.md +51 -0
- package/packs/base/rules/bug-fix-starts-red.md +25 -0
- package/packs/base/rules/field-map-over-if-runs.md +47 -0
- package/packs/base/rules/finished-work-lands.md +17 -0
- package/packs/base/rules/git-right-first-time.md +19 -0
- package/packs/base/rules/instances-by-index-identities-by-id.md +54 -0
- package/packs/base/rules/lookup-over-if-chains.md +49 -0
- package/packs/base/rules/making-line-first.md +14 -0
- package/packs/base/rules/open-items-tagged.md +17 -0
- package/packs/base/rules/plan-and-logs.md +22 -0
- package/packs/base/rules/references-use-anchors.md +19 -0
- package/packs/base/rules/refusals-are-judged.md +18 -0
- package/packs/base/rules/reuse-before-writing.md +15 -0
- package/packs/base/rules/secrets-never-committed.md +16 -0
- package/packs/base/rules/skill-writing.md +23 -0
- package/packs/base/rules/split-before-the-limit.md +14 -0
- package/packs/base/rules/subagent-dispatch.md +26 -0
- package/packs/base/rules/test-only-what-changed.md +17 -0
- package/packs/base/rules/test-the-template-once.md +22 -0
- package/packs/base/rules/untrusted-content-boundary.md +15 -0
- package/packs/base/skills/add-lesson-check/SKILL.md +26 -0
- package/packs/base/skills/fix-from-scan/SKILL.md +25 -0
- package/packs/base/skills/land-branch/SKILL.md +24 -0
- package/packs/base/skills/make-it-a-template/SKILL.md +23 -0
- package/packs/base/skills/pdf-to-md/SKILL.md +25 -0
- package/packs/base/skills/pick-tests/SKILL.md +20 -0
- package/packs/base/skills/pressure-test-skill/SKILL.md +23 -0
- package/packs/base/skills/prove-instances-identical/SKILL.md +37 -0
- package/packs/base/tools/shape-symmetry-selftest.mjs +66 -0
- package/packs/base/tools/shape-symmetry.mjs +178 -0
- package/packs/base/tools/test-verdict.mjs +75 -0
- package/packs/ci/checks/ci-permissions-stated.json +18 -0
- package/packs/ci/checks/ci-tools-pinned.json +14 -0
- package/packs/ci/pack.json +21 -0
- package/packs/ci/rules/ci-covers-what-ships.md +20 -0
- package/packs/ci/rules/generated-files-have-no-diff.md +15 -0
- package/packs/content-site/checks/captcha-is-not-constant.json +27 -0
- package/packs/content-site/checks/img-has-size.json +20 -0
- package/packs/content-site/checks/page-head-complete.json +26 -0
- package/packs/content-site/pack.json +22 -0
- package/packs/content-site/rules/content-has-one-source.md +23 -0
- package/packs/content-site/rules/media-is-sized.md +24 -0
- package/packs/content-site/rules/page-head-is-complete.md +26 -0
- package/packs/content-site/rules/public-forms-are-defended.md +27 -0
- package/packs/content-site/skills/publish-a-page/SKILL.md +21 -0
- package/packs/cpp/checks/cpp-clamp-before-cast.json +16 -0
- package/packs/cpp/checks/cpp-find-with-the-library.json +12 -0
- package/packs/cpp/checks/cpp-hardened-test-build.json +18 -0
- package/packs/cpp/checks/cpp-m-pi-not-standard.json +23 -0
- package/packs/cpp/checks/cpp-no-atoi.json +16 -0
- package/packs/cpp/checks/cpp-no-const-cast.json +16 -0
- package/packs/cpp/checks/cpp-no-float-loop-counter.json +16 -0
- package/packs/cpp/checks/cpp-no-getenv-in-product.json +22 -0
- package/packs/cpp/checks/cpp-no-mutable-global.json +20 -0
- package/packs/cpp/checks/cpp-no-mutable-local-static.json +23 -0
- package/packs/cpp/checks/cpp-no-unchecked-fwrite.json +17 -0
- package/packs/cpp/checks/cpp-no-using-namespace-in-header.json +19 -0
- package/packs/cpp/checks/cpp-no-zero-size-array.json +23 -0
- package/packs/cpp/checks/cpp-numbers-pi.json +16 -0
- package/packs/cpp/pack.json +22 -0
- package/packs/cpp/rules/cpp-absent-and-failed-are-types.md +24 -0
- package/packs/cpp/rules/cpp-builds-everywhere.md +26 -0
- package/packs/cpp/rules/cpp-faults-only-in-the-test-build.md +21 -0
- package/packs/cpp/rules/cpp-find-with-the-library.md +19 -0
- package/packs/cpp/rules/cpp-gates-share-one-reader.md +22 -0
- package/packs/cpp/rules/cpp-headers-declare.md +22 -0
- package/packs/cpp/rules/cpp-numbers-and-casts.md +22 -0
- package/packs/cpp/rules/cpp-repeats-become-templates.md +33 -0
- package/packs/cpp/rules/cpp-static-analysis-runs.md +22 -0
- package/packs/cpp/rules/cpp-thread-contracts-are-code.md +23 -0
- package/packs/cpp/skills/cpp-extract-template/SKILL.md +38 -0
- package/packs/docker/checks/alpine-with-native-build.json +13 -0
- package/packs/docker/checks/compose-db-needs-auth.json +14 -0
- package/packs/docker/checks/compose-image-pinned.json +14 -0
- package/packs/docker/checks/compose-no-hardcoded-ip.json +12 -0
- package/packs/docker/checks/compose-no-host-bind-for-data.json +18 -0
- package/packs/docker/checks/compose-no-plaintext-secret.json +13 -0
- package/packs/docker/checks/compose-no-swarm-ignored-keys.json +13 -0
- package/packs/docker/checks/compose-overlay-not-bridge.json +13 -0
- package/packs/docker/checks/compose-service-needs-healthcheck.json +11 -0
- package/packs/docker/checks/compose-service-needs-init.json +11 -0
- package/packs/docker/checks/copy-needs-chown-with-user.json +17 -0
- package/packs/docker/checks/copy-source-before-deps.json +13 -0
- package/packs/docker/checks/docker-exec-form.json +16 -0
- package/packs/docker/checks/dockerfile-needs-healthcheck.json +17 -0
- package/packs/docker/checks/dockerfile-needs-user.json +21 -0
- package/packs/docker/checks/dockerignore-has-the-basics.json +21 -0
- package/packs/docker/checks/gitattributes-forces-lf.json +17 -0
- package/packs/docker/checks/health-checks-nothing.json +25 -0
- package/packs/docker/checks/no-crlf-in-scripts.json +15 -0
- package/packs/docker/checks/no-latest-base.json +13 -0
- package/packs/docker/checks/no-secret-in-image.json +13 -0
- package/packs/docker/checks/no-sensitive-file-copy.json +13 -0
- package/packs/docker/checks/node-env-before-install.json +13 -0
- package/packs/docker/checks/npm-ci-not-install.json +13 -0
- package/packs/docker/pack.json +46 -0
- package/packs/docker/rules/compose-pinned-and-closed.md +21 -0
- package/packs/docker/rules/compose-swarm-safe.md +26 -0
- package/packs/docker/rules/docker-exec-form.md +19 -0
- package/packs/docker/rules/dockerfile-multistage.md +13 -0
- package/packs/docker/rules/dockerfile-production.md +25 -0
- package/packs/docker/skills/docker-diagnose/SKILL.md +23 -0
- package/packs/dynamic-data/checks/draft-on-the-server.json +27 -0
- package/packs/dynamic-data/checks/guard-does-its-job.json +28 -0
- package/packs/dynamic-data/checks/key-is-not-a-display-name.json +28 -0
- package/packs/dynamic-data/checks/no-code-from-data.json +29 -0
- package/packs/dynamic-data/checks/no-collection-from-request.json +27 -0
- package/packs/dynamic-data/checks/no-pipeline-from-stored-text.json +27 -0
- package/packs/dynamic-data/checks/no-regexp-from-stored-config.json +27 -0
- package/packs/dynamic-data/checks/no-template-from-stored-text.json +27 -0
- package/packs/dynamic-data/checks/save-takes-named-paths.json +27 -0
- package/packs/dynamic-data/pack.json +23 -0
- package/packs/dynamic-data/rules/a-list-is-a-saved-query.md +23 -0
- package/packs/dynamic-data/rules/definitions-are-validated-data.md +24 -0
- package/packs/dynamic-data/rules/every-dynamic-surface-has-a-boundary.md +29 -0
- package/packs/dynamic-data/rules/fields-have-owners.md +22 -0
- package/packs/dynamic-data/rules/imports-drop-nothing.md +26 -0
- package/packs/dynamic-data/rules/one-definition-many-surfaces.md +24 -0
- package/packs/dynamic-data/rules/one-fact-one-place.md +28 -0
- package/packs/dynamic-data/rules/rules-live-in-the-engine.md +29 -0
- package/packs/dynamic-data/rules/saves-are-patches.md +28 -0
- package/packs/dynamic-data/rules/tenant-costs-one-document.md +22 -0
- package/packs/dynamic-data/skills/design-a-definition/SKILL.md +24 -0
- package/packs/fastify/checks/api-routes-versioned.json +28 -0
- package/packs/fastify/checks/cookie-host-prefix.json +24 -0
- package/packs/fastify/checks/hijack-needs-try.json +28 -0
- package/packs/fastify/checks/no-cast-at-route-boundary.json +24 -0
- package/packs/fastify/checks/no-db-in-route-file.json +28 -0
- package/packs/fastify/checks/no-err-message-to-client.json +24 -0
- package/packs/fastify/checks/no-regexp-from-input.json +24 -0
- package/packs/fastify/checks/no-trust-proxy-true.json +25 -0
- package/packs/fastify/checks/one-error-body.json +26 -0
- package/packs/fastify/checks/origin-from-config-not-host.json +31 -0
- package/packs/fastify/checks/password-needs-slow-hash.json +30 -0
- package/packs/fastify/checks/sec-headers-present.json +28 -0
- package/packs/fastify/checks/secrets-compared-constant-time.json +24 -0
- package/packs/fastify/checks/sse-needs-error-listener.json +28 -0
- package/packs/fastify/checks/user-bytes-need-disposition.json +29 -0
- package/packs/fastify/pack.json +41 -0
- package/packs/fastify/rules/credentials-and-input.md +23 -0
- package/packs/fastify/rules/security-one-switch.md +28 -0
- package/packs/fastify/rules/streams-and-hijacks.md +22 -0
- package/packs/fastify/rules/tests-use-inject.md +13 -0
- package/packs/fastify/rules/three-layers.md +20 -0
- package/packs/fastify/rules/trust-config-not-headers.md +24 -0
- package/packs/full-stack/checks/no-express-no-vite.json +23 -0
- package/packs/full-stack/hooks/stack-guard.mjs +90 -0
- package/packs/full-stack/pack.json +76 -0
- package/packs/full-stack/rules/stack-is-fastify-and-nextjs.md +20 -0
- package/packs/go/checks/go-exec-result-ignored.json +15 -0
- package/packs/go/checks/go-unmarshal-error-ignored.json +15 -0
- package/packs/go/pack.json +21 -0
- package/packs/go/rules/go-errors-are-handled.md +22 -0
- package/packs/gpu-painter/checks/dawn-backends-and-validation.json +9 -0
- package/packs/gpu-painter/checks/dawn-no-spontaneous.json +10 -0
- package/packs/gpu-painter/checks/dawn-present-on-render-thread.json +17 -0
- package/packs/gpu-painter/checks/gpu-no-frame-stalls.json +12 -0
- package/packs/gpu-painter/checks/no-opengl-link.json +11 -0
- package/packs/gpu-painter/checks/no-opengl.json +13 -0
- package/packs/gpu-painter/hooks/browser-guard.py +196 -0
- package/packs/gpu-painter/pack.json +91 -0
- package/packs/gpu-painter/rules/dawn-build-and-shaders.md +27 -0
- package/packs/gpu-painter/rules/dawn-device-and-render-thread.md +26 -0
- package/packs/gpu-painter/rules/gpu-antialiasing.md +20 -0
- package/packs/gpu-painter/rules/gpu-blend-order.md +22 -0
- package/packs/gpu-painter/rules/gpu-bloom.md +20 -0
- package/packs/gpu-painter/rules/gpu-frame-budget.md +25 -0
- package/packs/gpu-painter/rules/gpu-frame-pacing-and-power.md +27 -0
- package/packs/gpu-painter/rules/gpu-frame-work.md +30 -0
- package/packs/gpu-painter/rules/gpu-golden-images.md +21 -0
- package/packs/gpu-painter/rules/gpu-hdr-and-tonemap.md +23 -0
- package/packs/gpu-painter/rules/gpu-picking-on-cpu.md +19 -0
- package/packs/gpu-painter/rules/gpu-render-lifecycle.md +25 -0
- package/packs/gpu-painter/rules/gpu-text-atlas.md +24 -0
- package/packs/gpu-painter/rules/gpu-travellers-from-snapshot.md +24 -0
- package/packs/gpu-painter/rules/hover-every-pressable.md +25 -0
- package/packs/gpu-painter/skills/gpu-capture/SKILL.md +15 -0
- package/packs/gpu-painter/skills/gpu-frame-bench/SKILL.md +14 -0
- package/packs/gpu-painter/skills/gpu-golden-check/SKILL.md +13 -0
- package/packs/gpu-painter/skills/gpu-golden-update/SKILL.md +16 -0
- package/packs/gpu-painter/skills/gpu-lifecycle-stress/SKILL.md +15 -0
- package/packs/gpu-painter/skills/hover-state/SKILL.md +33 -0
- package/packs/hook-proof/checks/hook-catch-must-not-allow.json +16 -0
- package/packs/hook-proof/checks/hook-command-no-pipe.json +16 -0
- package/packs/hook-proof/checks/hook-exit-1-does-not-block.json +17 -0
- package/packs/hook-proof/checks/hook-no-or-true.json +18 -0
- package/packs/hook-proof/checks/hook-refusal-on-stderr.json +17 -0
- package/packs/hook-proof/pack.json +38 -0
- package/packs/hook-proof/rules/a-refusal-is-exit-2.md +28 -0
- package/packs/hook-proof/skills/prove-a-hook/SKILL.md +21 -0
- package/packs/host-agent/checks/file-path-from-param.json +27 -0
- package/packs/host-agent/checks/integrity-check-optional.json +27 -0
- package/packs/host-agent/checks/quoted-value-into-config.json +24 -0
- package/packs/host-agent/checks/secret-on-argv.json +28 -0
- package/packs/host-agent/checks/ssh-verifies-host-key.json +27 -0
- package/packs/host-agent/checks/system-file-written-in-place.json +26 -0
- package/packs/host-agent/checks/tmp-path-predictable.json +27 -0
- package/packs/host-agent/pack.json +22 -0
- package/packs/host-agent/rules/root-on-other-machines.md +27 -0
- package/packs/html-ui/checks/email-html-escapes.json +25 -0
- package/packs/html-ui/checks/external-link-rel.json +21 -0
- package/packs/html-ui/checks/no-duplicate-escape.json +26 -0
- package/packs/html-ui/checks/no-inline-client-script.json +21 -0
- package/packs/html-ui/checks/no-inline-style.json +23 -0
- package/packs/html-ui/pack.json +33 -0
- package/packs/html-ui/rules/email-html-escapes.md +19 -0
- package/packs/html-ui/rules/server-html-escapes-everything.md +22 -0
- package/packs/http-api/checks/api-path-versioned.json +31 -0
- package/packs/http-api/checks/authz-from-request-body.json +26 -0
- package/packs/http-api/checks/client-calls-a-version.json +28 -0
- package/packs/http-api/checks/client-ip-not-leftmost-xff.json +28 -0
- package/packs/http-api/checks/cors-needs-origin.json +26 -0
- package/packs/http-api/checks/csp-not-switched-off.json +28 -0
- package/packs/http-api/checks/debug-route-not-shipped.json +26 -0
- package/packs/http-api/checks/encrypted-name-plaintext-value.json +26 -0
- package/packs/http-api/checks/err-text-stays-server-side.json +27 -0
- package/packs/http-api/checks/failure-is-not-empty.json +28 -0
- package/packs/http-api/checks/gate-is-not-a-todo.json +27 -0
- package/packs/http-api/checks/guard-fails-open.json +28 -0
- package/packs/http-api/checks/hmac-over-reserialised-body.json +26 -0
- package/packs/http-api/checks/jwt-verify-pins-algorithm.json +26 -0
- package/packs/http-api/checks/middleware-skips-without-user.json +26 -0
- package/packs/http-api/checks/next-api-route-versioned.json +47 -0
- package/packs/http-api/checks/no-security-off-switch.json +28 -0
- package/packs/http-api/checks/oauth-state-signed.json +26 -0
- package/packs/http-api/checks/one-time-code-compared-raw.json +26 -0
- package/packs/http-api/checks/query-cast-is-not-validation.json +28 -0
- package/packs/http-api/checks/queue-action-from-client.json +26 -0
- package/packs/http-api/checks/rate-limit-one-module.json +28 -0
- package/packs/http-api/checks/role-checked-in-one-guard.json +27 -0
- package/packs/http-api/checks/route-body-needs-schema.json +31 -0
- package/packs/http-api/checks/route-scopes-to-the-caller.json +31 -0
- package/packs/http-api/checks/secret-compared-constant-time-any.json +28 -0
- package/packs/http-api/checks/secret-in-job-record.json +27 -0
- package/packs/http-api/checks/server-fetches-tenant-url.json +30 -0
- package/packs/http-api/checks/short-code-needs-limit.json +26 -0
- package/packs/http-api/checks/user-url-through-safe-fetch.json +28 -0
- package/packs/http-api/checks/webhook-dedupes-event-id.json +30 -0
- package/packs/http-api/pack.json +45 -0
- package/packs/http-api/rules/adapters-one-db-gateway.md +18 -0
- package/packs/http-api/rules/apis-are-versioned.md +27 -0
- package/packs/http-api/rules/credentials-handled-safely.md +22 -0
- package/packs/http-api/rules/handlers-own-the-work.md +17 -0
- package/packs/http-api/rules/health-and-correlation.md +17 -0
- package/packs/http-api/rules/one-error-contract.md +17 -0
- package/packs/http-api/rules/routes-are-thin.md +17 -0
- package/packs/http-api/rules/routes-scope-to-the-caller.md +26 -0
- package/packs/http-api/rules/routes-validate-and-answer.md +25 -0
- package/packs/http-api/skills/change-an-api/SKILL.md +20 -0
- package/packs/http-api/skills/secure-a-route/SKILL.md +21 -0
- package/packs/instrument-shell/checks/no-raw-struct-blob.json +23 -0
- package/packs/instrument-shell/pack.json +22 -0
- package/packs/instrument-shell/rules/fold-keeps-every-route.md +24 -0
- package/packs/instrument-shell/rules/quiet-announces-itself.md +22 -0
- package/packs/instrument-shell/rules/render-the-extremes.md +25 -0
- package/packs/instrument-shell/rules/seams-are-declared.md +27 -0
- package/packs/instrument-shell/rules/session-blob-append-only.md +25 -0
- package/packs/instrument-shell/skills/gates-from-commit-one/SKILL.md +20 -0
- package/packs/instrument-shell/skills/hit-the-painted-control/SKILL.md +18 -0
- package/packs/js-ts/checks/async-callback-unguarded.json +26 -0
- package/packs/js-ts/checks/background-loop-needs-stop.json +28 -0
- package/packs/js-ts/checks/child-process-error-handler.json +28 -0
- package/packs/js-ts/checks/entry-registers-shutdown.json +31 -0
- package/packs/js-ts/checks/fetch-needs-timeout.json +30 -0
- package/packs/js-ts/checks/job-only-in-memory.json +28 -0
- package/packs/js-ts/checks/json-only-through-helper.json +29 -0
- package/packs/js-ts/checks/line-under-200-chars.json +34 -0
- package/packs/js-ts/checks/localhost-default-in-server.json +29 -0
- package/packs/js-ts/checks/no-any.json +27 -0
- package/packs/js-ts/checks/no-cast-escape-hatches.json +24 -0
- package/packs/js-ts/checks/no-console-in-app.json +31 -0
- package/packs/js-ts/checks/no-dynamic-import-node-builtin.json +25 -0
- package/packs/js-ts/checks/no-inline-binary.json +20 -0
- package/packs/js-ts/checks/no-inline-zod-outside-schemas.json +27 -0
- package/packs/js-ts/checks/no-local-sleep.json +25 -0
- package/packs/js-ts/checks/no-nested-ternary.json +20 -0
- package/packs/js-ts/checks/no-secret-in-log.json +24 -0
- package/packs/js-ts/checks/no-shell-string-interpolation.json +24 -0
- package/packs/js-ts/checks/no-swallowed-errors.json +25 -0
- package/packs/js-ts/checks/no-ts-enum.json +20 -0
- package/packs/js-ts/checks/process-env-only-in-config.json +31 -0
- package/packs/js-ts/checks/race-leaves-work-running.json +23 -0
- package/packs/js-ts/checks/reject-as-catch-all-exists.json +24 -0
- package/packs/js-ts/checks/secret-has-no-fallback.json +24 -0
- package/packs/js-ts/checks/secret-needs-crypto-random.json +24 -0
- package/packs/js-ts/checks/server-close-awaited.json +27 -0
- package/packs/js-ts/checks/session-user-typed-once.json +24 -0
- package/packs/js-ts/checks/switch-is-a-table.json +24 -0
- package/packs/js-ts/checks/test-imports-the-source.json +19 -0
- package/packs/js-ts/checks/test-name-says-behaviour.json +16 -0
- package/packs/js-ts/checks/tsconfig-flags.json +21 -0
- package/packs/js-ts/checks/void-needs-catch.json +24 -0
- package/packs/js-ts/checks/zod-string-needs-max.json +25 -0
- package/packs/js-ts/checks/zod-v4-formats.json +23 -0
- package/packs/js-ts/pack.json +84 -0
- package/packs/js-ts/rules/await-handled-at-a-boundary.md +66 -0
- package/packs/js-ts/rules/env-through-config.md +36 -0
- package/packs/js-ts/rules/errors-never-swallowed.md +33 -0
- package/packs/js-ts/rules/files-under-300-lines.md +18 -0
- package/packs/js-ts/rules/guard-clauses-over-nesting.md +34 -0
- package/packs/js-ts/rules/js-repeats-become-templates.md +26 -0
- package/packs/js-ts/rules/json-only-through-one-helper.md +62 -0
- package/packs/js-ts/rules/named-constants-not-magic-numbers.md +34 -0
- package/packs/js-ts/rules/no-any.md +34 -0
- package/packs/js-ts/rules/no-console.md +30 -0
- package/packs/js-ts/rules/no-floating-promises.md +31 -0
- package/packs/js-ts/rules/no-param-mutation.md +28 -0
- package/packs/js-ts/rules/no-unsafe-assertions.md +30 -0
- package/packs/js-ts/rules/one-logger.md +24 -0
- package/packs/js-ts/rules/outbound-calls-have-a-limit.md +20 -0
- package/packs/js-ts/rules/parallel-independent-awaits.md +29 -0
- package/packs/js-ts/rules/process-lifecycle.md +47 -0
- package/packs/js-ts/rules/schema-single-source-of-truth.md +36 -0
- package/packs/js-ts/rules/secrets-stay-secret.md +22 -0
- package/packs/js-ts/rules/small-functions.md +20 -0
- package/packs/js-ts/rules/test-names-describe-behavior.md +28 -0
- package/packs/js-ts/rules/tests-can-fail.md +19 -0
- package/packs/js-ts/rules/tsconfig-strict.md +32 -0
- package/packs/js-ts/rules/typed-exports.md +27 -0
- package/packs/js-ts/rules/types-once-at-the-edge.md +18 -0
- package/packs/js-ts/rules/unions-over-enums.md +29 -0
- package/packs/js-ts/rules/zod-at-route-boundaries.md +40 -0
- package/packs/midi/checks/active-sensing-no-pulse.json +24 -0
- package/packs/midi/checks/clock-not-at-sample-zero.json +23 -0
- package/packs/midi/checks/midi-realtime-first.json +27 -0
- package/packs/midi/checks/no-tempo-writeback.json +23 -0
- package/packs/midi/checks/position-not-integrated.json +25 -0
- package/packs/midi/checks/stub-playhead-advances.json +27 -0
- package/packs/midi/checks/sysex-length-literal.json +23 -0
- package/packs/midi/checks/sysex-not-on-audio.json +24 -0
- package/packs/midi/checks/sysex-survives-realtime.json +27 -0
- package/packs/midi/pack.json +22 -0
- package/packs/midi/rules/clock-is-a-pulse-stream.md +30 -0
- package/packs/midi/rules/imports-count-every-loss.md +25 -0
- package/packs/midi/rules/measure-the-clock-in-audio.md +30 -0
- package/packs/midi/rules/sync-is-a-mode.md +29 -0
- package/packs/midi/rules/sysex-is-a-record.md +29 -0
- package/packs/midi/skills/clock-probe/SKILL.md +23 -0
- package/packs/midi/skills/clock-probe/clock-law.md +417 -0
- package/packs/midi/skills/does-it-sync/SKILL.md +19 -0
- package/packs/mongo/checks/bulk-over-many.json +28 -0
- package/packs/mongo/checks/created-at-immutable.json +25 -0
- package/packs/mongo/checks/driver-outside-gateway.json +24 -0
- package/packs/mongo/checks/key-lookup-is-hashed.json +24 -0
- package/packs/mongo/checks/mongoclient-cached-and-named.json +34 -0
- package/packs/mongo/checks/mongoclient-outside-gateway.json +24 -0
- package/packs/mongo/checks/no-count-plus-one-ids.json +25 -0
- package/packs/mongo/checks/no-db-write-in-loop.json +25 -0
- package/packs/mongo/checks/no-drop-in-code.json +27 -0
- package/packs/mongo/checks/no-empty-deletemany.json +26 -0
- package/packs/mongo/checks/no-find-reads.json +26 -0
- package/packs/mongo/checks/no-input-spread-into-write.json +24 -0
- package/packs/mongo/checks/no-mongoose.json +23 -0
- package/packs/mongo/checks/no-negation-delete.json +26 -0
- package/packs/mongo/checks/no-non-null-after-findone.json +25 -0
- package/packs/mongo/checks/objectid-equals.json +26 -0
- package/packs/mongo/checks/update-then-reread.json +24 -0
- package/packs/mongo/checks/watch-not-poll.json +25 -0
- package/packs/mongo/pack.json +52 -0
- package/packs/mongo/rules/deletes-name-what-dies.md +21 -0
- package/packs/mongo/rules/driver-only-in-gateway.md +26 -0
- package/packs/mongo/rules/keys-hashed-input-picked.md +21 -0
- package/packs/mongo/rules/one-client-one-pool.md +32 -0
- package/packs/mongo/rules/reads-aggregate-writes-bulk.md +25 -0
- package/packs/mongo/rules/writes-are-atomic.md +27 -0
- package/packs/multi-tenant/checks/role-sees-all-tenants.json +26 -0
- package/packs/multi-tenant/checks/tenant-filter-from-url.json +25 -0
- package/packs/multi-tenant/pack.json +22 -0
- package/packs/multi-tenant/rules/no-role-crosses-a-tenant.md +21 -0
- package/packs/multi-tenant/skills/prove-tenant-isolation/SKILL.md +19 -0
- package/packs/nginx/checks/modsec-no-blanket-off.json +16 -0
- package/packs/nginx/checks/nginx-csp-no-unsafe.json +15 -0
- package/packs/nginx/checks/nginx-headers-always.json +15 -0
- package/packs/nginx/checks/nginx-keepalive-http11.json +20 -0
- package/packs/nginx/checks/nginx-logs-to-stdout.json +15 -0
- package/packs/nginx/checks/nginx-no-crlf.json +17 -0
- package/packs/nginx/checks/nginx-resolver-ttl.json +19 -0
- package/packs/nginx/pack.json +43 -0
- package/packs/nginx/rules/modsecurity-tuning.md +22 -0
- package/packs/nginx/rules/nginx-production.md +26 -0
- package/packs/nginx/skills/waf-rollout/SKILL.md +20 -0
- package/packs/python/checks/py-no-bare-except.json +18 -0
- package/packs/python/checks/py-no-eval.json +18 -0
- package/packs/python/checks/py-no-mutable-default.json +18 -0
- package/packs/python/checks/py-no-shell-true.json +18 -0
- package/packs/python/checks/py-no-star-import.json +18 -0
- package/packs/python/checks/py-no-swallowed-exception.json +18 -0
- package/packs/python/checks/py-none-by-is.json +18 -0
- package/packs/python/checks/py-open-with-with.json +18 -0
- package/packs/python/checks/py-requests-timeout.json +18 -0
- package/packs/python/checks/py-subprocess-output-checked.json +18 -0
- package/packs/python/checks/py-yaml-safe-load.json +18 -0
- package/packs/python/pack.json +26 -0
- package/packs/python/rules/python-errors-and-resources.md +26 -0
- package/packs/python/rules/python-repeats-become-templates.md +27 -0
- package/packs/python/skills/python-extract-template/SKILL.md +35 -0
- package/packs/react/checks/dialog-needs-role.json +28 -0
- package/packs/react/checks/effect-not-for-derived-state.json +24 -0
- package/packs/react/checks/icon-button-needs-name.json +24 -0
- package/packs/react/checks/label-needs-a-field.json +24 -0
- package/packs/react/checks/ui-failed-fetch-says-so.json +23 -0
- package/packs/react/checks/ui-ok-branch-has-an-else.json +23 -0
- package/packs/react/pack.json +20 -0
- package/packs/react/rules/react-accessible-controls.md +20 -0
- package/packs/react/rules/react-state-and-effects.md +23 -0
- package/packs/reverse-engineering/checks/ear-constant-tagged.json +23 -0
- package/packs/reverse-engineering/checks/no-default-on-distrust.json +24 -0
- package/packs/reverse-engineering/checks/no-rom-table-literal.json +29 -0
- package/packs/reverse-engineering/checks/prose-never-decides.json +22 -0
- package/packs/reverse-engineering/hooks/firmware-out-of-git.mjs +49 -0
- package/packs/reverse-engineering/pack.json +35 -0
- package/packs/reverse-engineering/rules/a-negative-names-what-was-scanned.md +19 -0
- package/packs/reverse-engineering/rules/account-every-term.md +20 -0
- package/packs/reverse-engineering/rules/addresses-name-their-space.md +21 -0
- package/packs/reverse-engineering/rules/every-law-has-a-source.md +18 -0
- package/packs/reverse-engineering/rules/findings-are-withdrawn-in-place.md +17 -0
- package/packs/reverse-engineering/rules/firmware-stays-out.md +18 -0
- package/packs/reverse-engineering/rules/names-before-code.md +19 -0
- package/packs/reverse-engineering/rules/reproduction-or-original.md +18 -0
- package/packs/reverse-engineering/rules/two-sources-before-naming.md +21 -0
- package/packs/reverse-engineering/skills/bank-census/SKILL.md +18 -0
- package/packs/reverse-engineering/skills/gather-sources/SKILL.md +21 -0
- package/packs/reverse-engineering/skills/menu-map/SKILL.md +28 -0
- package/packs/reverse-engineering/skills/names-first/SKILL.md +41 -0
- package/packs/reverse-engineering/skills/re-deliverables/SKILL.md +21 -0
- package/packs/reverse-engineering/skills/tripwire-the-law/SKILL.md +19 -0
- package/packs/reverse-engineering/tools/lib/unwrap.mjs +115 -0
- package/packs/reverse-engineering/tools/names-sweep.mjs +264 -0
- package/packs/shell/checks/sh-mktemp.json +18 -0
- package/packs/shell/checks/sh-no-backticks.json +18 -0
- package/packs/shell/checks/sh-no-eval.json +18 -0
- package/packs/shell/checks/sh-no-parse-ls.json +18 -0
- package/packs/shell/checks/sh-no-pipe-to-shell.json +18 -0
- package/packs/shell/checks/sh-no-program-in-heredoc.json +18 -0
- package/packs/shell/checks/sh-quote-arguments.json +18 -0
- package/packs/shell/checks/sh-rm-guarded.json +18 -0
- package/packs/shell/checks/sh-strict-mode.json +20 -0
- package/packs/shell/pack.json +28 -0
- package/packs/shell/rules/shell-repeats-become-templates.md +23 -0
- package/packs/shell/rules/shell-strict-and-quoted.md +27 -0
- package/packs/shell/skills/shell-extract-template/SKILL.md +32 -0
- package/packs/shell-hooks/checks/gnu-only-in-shell.json +18 -0
- package/packs/shell-hooks/checks/hook-command-anchored.json +12 -0
- package/packs/shell-hooks/checks/hook-json-by-tool.json +18 -0
- package/packs/shell-hooks/checks/no-bash-c-with-variable.json +20 -0
- package/packs/shell-hooks/pack.json +36 -0
- package/packs/shell-hooks/rules/hooks-portable-anchored-quoted.md +26 -0
- package/packs/sound-design/checks/audio-seed-fixed.json +23 -0
- package/packs/sound-design/checks/mix-is-a-crossfade.json +30 -0
- package/packs/sound-design/checks/no-hash-in-the-signal.json +30 -0
- package/packs/sound-design/checks/no-literal-key-anchor.json +30 -0
- package/packs/sound-design/checks/test-compares-a-function-with-itself.json +22 -0
- package/packs/sound-design/pack.json +22 -0
- package/packs/sound-design/rules/algorithms-are-data.md +26 -0
- package/packs/sound-design/rules/meter-before-engine.md +27 -0
- package/packs/sound-design/rules/neutral-is-exact.md +26 -0
- package/packs/sound-design/rules/test-off-the-easy-point.md +28 -0
- package/packs/sound-design/rules/unreachable-is-said.md +25 -0
- package/packs/sound-design/rules/waveforms-and-octaves.md +24 -0
- package/packs/sound-design/skills/choose-observable/SKILL.md +18 -0
- package/packs/sound-design/skills/measure-a-law/SKILL.md +18 -0
- package/packs/sound-design/skills/measure-reverb/SKILL.md +19 -0
- package/packs/sound-design/skills/spread-probe/SKILL.md +18 -0
- package/packs/stellix/checks/no-keyboard-focus.json +12 -0
- package/packs/stellix/checks/one-seeded-random.json +16 -0
- package/packs/stellix/checks/world-never-includes-painter.json +12 -0
- package/packs/stellix/checks/world-no-libm.json +15 -0
- package/packs/stellix/checks/world-no-unordered.json +10 -0
- package/packs/stellix/hooks/no-shipped-images.mjs +88 -0
- package/packs/stellix/pack.json +61 -0
- package/packs/stellix/rules/stellix-deterministic-world.md +29 -0
- package/packs/stellix/rules/stellix-reset-generated.md +24 -0
- package/packs/stellix/rules/stellix-world-snapshot.md +27 -0
- package/packs/stellix/rules/world-continuous-collision.md +26 -0
- package/packs/stellix/rules/world-fp-determinism.md +28 -0
- package/packs/stored-text/checks/no-raw-html-from-data.json +31 -0
- package/packs/stored-text/checks/stored-text-libs-only-in-renderer.json +31 -0
- package/packs/stored-text/checks/stored-text-renderer-complete.json +24 -0
- package/packs/stored-text/checks/stored-text-through-renderer.json +25 -0
- package/packs/stored-text/pack.json +41 -0
- package/packs/stored-text/rules/stored-text-renders-once.md +26 -0
- package/packs/stored-text/skills/render-stored-text/SKILL.md +24 -0
- package/packs/synth-creator/checks/timing-from-synthcore.json +24 -0
- package/packs/synth-creator/checks/ui-drawn-in-code.json +23 -0
- package/packs/synth-creator/hooks/build-guard.mjs +232 -0
- package/packs/synth-creator/hooks/build-sweep.mjs +166 -0
- package/packs/synth-creator/hooks/frozen-files.mjs +63 -0
- package/packs/synth-creator/hooks/idle-wake.mjs +90 -0
- package/packs/synth-creator/hooks/protect-vendor.mjs +174 -0
- package/packs/synth-creator/hooks/spec-lock.mjs +117 -0
- package/packs/synth-creator/hooks/stage-guard.mjs +50 -0
- package/packs/synth-creator/hooks/time-guard.mjs +292 -0
- package/packs/synth-creator/hooks/user-asks.mjs +165 -0
- package/packs/synth-creator/pack.json +136 -0
- package/packs/synth-creator/rules/copy-trees-read-only.md +25 -0
- package/packs/synth-creator/rules/debug-by-measurement.md +20 -0
- package/packs/synth-creator/rules/done-means-fresh-evidence.md +18 -0
- package/packs/synth-creator/rules/hooks-and-gates.md +21 -0
- package/packs/synth-creator/rules/long-work-in-the-background.md +16 -0
- package/packs/synth-creator/rules/timing-from-synthcore.md +16 -0
- package/packs/synth-creator/skills/build-step/SKILL.md +125 -0
- package/packs/synth-creator/skills/build-through-the-queue/SKILL.md +19 -0
- package/packs/synth-creator/tools/freeze.mjs +36 -0
- package/packs/tui/checks/tui-entry-restores-terminal.json +27 -0
- package/packs/tui/checks/tui-gates-on-tty.json +25 -0
- package/packs/tui/checks/tui-no-ris-reset.json +22 -0
- package/packs/tui/checks/tui-resize-listener-removed.json +26 -0
- package/packs/tui/checks/tui-width-is-state.json +33 -0
- package/packs/tui/pack.json +44 -0
- package/packs/tui/rules/tui-resize-and-screen.md +25 -0
- package/packs/tui/skills/build-tui/SKILL.md +21 -0
- package/packs/ui-craft/checks/ui-input-needs-autocomplete.json +23 -0
- package/packs/ui-craft/checks/ui-intl-for-dates.json +21 -0
- package/packs/ui-craft/checks/ui-no-ai-palette.json +22 -0
- package/packs/ui-craft/checks/ui-no-animate-layout.json +22 -0
- package/packs/ui-craft/checks/ui-no-assistant-palette.json +23 -0
- package/packs/ui-craft/checks/ui-no-bounce-easing.json +22 -0
- package/packs/ui-craft/checks/ui-no-custom-cursor.json +22 -0
- package/packs/ui-craft/checks/ui-no-emoji-as-ui.json +22 -0
- package/packs/ui-craft/checks/ui-no-empty-image.json +21 -0
- package/packs/ui-craft/checks/ui-no-eyebrow.json +21 -0
- package/packs/ui-craft/checks/ui-no-furniture-text.json +22 -0
- package/packs/ui-craft/checks/ui-no-gradient-text.json +22 -0
- package/packs/ui-craft/checks/ui-no-index-numbering.json +21 -0
- package/packs/ui-craft/checks/ui-no-lorem.json +22 -0
- package/packs/ui-craft/checks/ui-no-marketing-buzzword.json +22 -0
- package/packs/ui-craft/checks/ui-no-paste-block.json +21 -0
- package/packs/ui-craft/checks/ui-no-placeholder-names.json +21 -0
- package/packs/ui-craft/checks/ui-no-scroll-hijack.json +21 -0
- package/packs/ui-craft/checks/ui-no-side-tab.json +21 -0
- package/packs/ui-craft/checks/ui-no-stock-labels.json +22 -0
- package/packs/ui-craft/checks/ui-no-transition-all.json +22 -0
- package/packs/ui-craft/checks/ui-no-uppercase-table-header.json +21 -0
- package/packs/ui-craft/checks/ui-no-zebra-rows.json +22 -0
- package/packs/ui-craft/checks/ui-no-zoom-lock.json +21 -0
- package/packs/ui-craft/pack.json +43 -0
- package/packs/ui-craft/rules/apps-are-not-pages.md +26 -0
- package/packs/ui-craft/rules/data-tells-the-truth.md +26 -0
- package/packs/ui-craft/rules/dates-and-numbers.md +18 -0
- package/packs/ui-craft/rules/forms-never-fight.md +22 -0
- package/packs/ui-craft/rules/interface-copy.md +26 -0
- package/packs/ui-craft/rules/motion-is-rare.md +31 -0
- package/packs/ui-craft/rules/no-generated-look.md +37 -0
- package/packs/ui-craft/rules/page-holds-its-frame.md +28 -0
- package/packs/ui-craft/rules/page-proved-rendered.md +19 -0
- package/packs/ui-craft/rules/pictures-do-a-job.md +25 -0
- package/packs/ui-craft/rules/pointer-feedback.md +28 -0
- package/packs/ui-craft/rules/screen-answers-one-question.md +24 -0
- package/packs/ui-craft/rules/survives-real-data.md +23 -0
- package/packs/ui-craft/rules/touch-and-small-screens.md +19 -0
- package/packs/ui-craft/rules/type-space-colour.md +26 -0
- package/packs/ui-craft/rules/url-holds-the-state.md +19 -0
- package/packs/ui-craft/skills/app-screen/SKILL.md +33 -0
- package/packs/ui-craft/skills/build-from-reference/SKILL.md +28 -0
- package/packs/ui-craft/skills/chart-choice/SKILL.md +34 -0
- package/packs/ui-craft/skills/hover-state/SKILL.md +28 -0
- package/packs/ui-craft/skills/page-critique/SKILL.md +33 -0
- package/packs/ui-craft/skills/prove-page/SKILL.md +23 -0
- package/packs/ui-craft/skills/redesign-page/SKILL.md +19 -0
- package/packs/ui-craft/skills/ui-code-review/SKILL.md +22 -0
- package/packs/ui-craft/skills/write-the-page/SKILL.md +21 -0
- package/packs/ui-craft/tools/page-measure.mjs +41 -0
- package/packs/web/checks/a11y-img-needs-alt.json +26 -0
- package/packs/web/checks/a11y-no-bare-outline-none.json +21 -0
- package/packs/web/checks/a11y-no-clickable-div.json +26 -0
- package/packs/web/checks/a11y-no-positive-tabindex.json +26 -0
- package/packs/web/checks/client-no-api-key.json +29 -0
- package/packs/web/checks/client-no-browser-global-at-module-scope.json +28 -0
- package/packs/web/checks/client-no-server-import.json +31 -0
- package/packs/web/checks/client-no-window-location-nav.json +28 -0
- package/packs/web/checks/css-no-inline-style.json +30 -0
- package/packs/web/checks/ds-pages-compose-primitives.json +28 -0
- package/packs/web/checks/key-from-index.json +23 -0
- package/packs/web/checks/prodbuild-no-cdn-runtime-deps.json +21 -0
- package/packs/web/checks/prodbuild-no-dev-flags.json +21 -0
- package/packs/web/checks/prodbuild-no-remote-fonts.json +22 -0
- package/packs/web/checks/rcss-button-cursor.json +30 -0
- package/packs/web/checks/rcss-no-100vw.json +21 -0
- package/packs/web/checks/rcss-no-fixed-wide-width.json +21 -0
- package/packs/web/checks/rcss-viewport-meta.json +28 -0
- package/packs/web/checks/secret-not-in-web-storage.json +25 -0
- package/packs/web/checks/tw-no-raw-hex-in-markup.json +34 -0
- package/packs/web/checks/wp-hero-not-lazy.json +27 -0
- package/packs/web/checks/wp-img-needs-dimensions.json +26 -0
- package/packs/web/pack.json +73 -0
- package/packs/web/rules/accessibility.md +26 -0
- package/packs/web/rules/client-boundaries.md +23 -0
- package/packs/web/rules/production-build.md +22 -0
- package/packs/web/rules/secrets-not-in-the-browser.md +18 -0
- package/packs/web/rules/styles-live-in-stylesheets.md +23 -0
- package/packs/web/rules/tailwind-v4.md +23 -0
- package/packs/web/rules/ui-primitives-one-module.md +30 -0
- package/packs/web/rules/web-performance.md +21 -0
- package/packs/web/skills/design-direction/SKILL.md +30 -0
- package/packs/web/skills/design-review/SKILL.md +28 -0
- package/packs/web/skills/pick-rendering-mode/SKILL.md +21 -0
- package/packs/web/skills/preflight-build/SKILL.md +23 -0
- package/packs/web/skills/seo-audit/SKILL.md +22 -0
- package/packs/websocket/checks/no-token-in-query.json +26 -0
- package/packs/websocket/checks/stale-socket-deletes-new-entry.json +25 -0
- package/packs/websocket/checks/ws-identity-from-message.json +26 -0
- package/packs/websocket/pack.json +21 -0
- package/packs/websocket/rules/identity-comes-from-the-connection.md +24 -0
- package/packs/writing/checks/ascii-no-em-dash.json +17 -0
- package/packs/writing/checks/no-copula-dodging.json +18 -0
- package/packs/writing/checks/no-dramatic-colon.json +18 -0
- package/packs/writing/checks/no-not-x-but-y.json +18 -0
- package/packs/writing/checks/no-participial-opener.json +18 -0
- package/packs/writing/checks/no-pseudo-wisdom.json +18 -0
- package/packs/writing/checks/no-slop-words.json +18 -0
- package/packs/writing/checks/no-stock-connectors.json +18 -0
- package/packs/writing/checks/no-time-or-date.json +27 -0
- package/packs/writing/checks/no-trailing-ing.json +18 -0
- package/packs/writing/checks/no-vague-attribution.json +18 -0
- package/packs/writing/pack.json +43 -0
- package/packs/writing/rules/ascii-no-em-dash.md +21 -0
- package/packs/writing/rules/cut-the-padding.md +20 -0
- package/packs/writing/rules/direct-voice.md +22 -0
- package/packs/writing/rules/no-cargo-cult.md +16 -0
- package/packs/writing/rules/no-scaffolding.md +19 -0
- package/packs/writing/rules/no-stock-language.md +27 -0
- package/packs/writing/rules/no-time-or-date.md +18 -0
- package/packs/writing/rules/rhythm-like-talk.md +20 -0
- package/packs/writing/rules/write-from-your-own-corner.md +20 -0
- package/packs/writing/skills/argument-post/SKILL.md +28 -0
- package/packs/writing/skills/humanize/SKILL.md +28 -0
- package/packs/writing/skills/launch-post/SKILL.md +38 -0
- package/packs/writing/skills/pick-subreddit/SKILL.md +69 -0
- package/packs/writing/skills/post-voice/SKILL.md +22 -0
- package/packs/writing/skills/reddit-post/SKILL.md +63 -0
- package/packs/writing/skills/reddit-title/SKILL.md +23 -0
- package/packs/writing/skills/reply-moves/SKILL.md +40 -0
- package/packs/writing/skills/reply-stance/SKILL.md +23 -0
- package/packs/writing/skills/should-i-reply/SKILL.md +21 -0
- package/packs/zod/hooks/schemas-only.mjs +53 -0
- package/packs/zod/pack.json +44 -0
- package/packs/zod/rules/env-shapes-only.md +14 -0
- package/packs/zod/rules/zod-4-schemas.md +14 -0
- package/profiles/stellix.layout.json +315 -0
- package/profiles/sub37.layout.json +247 -0
- package/prompts/scan-review.md +40 -0
- package/prompts/survey.md +82 -0
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
{
|
|
2
|
+
"id": "no-trust-proxy-true",
|
|
3
|
+
"why": "trustProxy: true makes req.ip the leftmost X-Forwarded-For value, so every spoofed header is a fresh rate-limit bucket. Use the ingress hop count or an address list.",
|
|
4
|
+
"rule": ".claude/rules/security-one-switch.md",
|
|
5
|
+
"concepts": [
|
|
6
|
+
"fastify-app",
|
|
7
|
+
"routes"
|
|
8
|
+
],
|
|
9
|
+
"exclude": [
|
|
10
|
+
"**/node_modules/**",
|
|
11
|
+
"**/dist/**",
|
|
12
|
+
"**/build/**",
|
|
13
|
+
"**/.next/**",
|
|
14
|
+
".claude/**",
|
|
15
|
+
"**/.claude/**",
|
|
16
|
+
"**/*.test.*",
|
|
17
|
+
"**/*.spec.*",
|
|
18
|
+
"**/test/**",
|
|
19
|
+
"**/tests/**"
|
|
20
|
+
],
|
|
21
|
+
"code": true,
|
|
22
|
+
"pattern": "\\btrustProxy\\s*:\\s*true\\b|trust proxy['\\\"]?\\s*,\\s*true",
|
|
23
|
+
"bad": "const app = Fastify({ trustProxy: true });",
|
|
24
|
+
"good": "const app = Fastify({ trustProxy: 1 });"
|
|
25
|
+
}
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
{
|
|
2
|
+
"id": "one-error-body",
|
|
3
|
+
"why": "A route that builds its own 404/400 body diverges from the error handler's contract (here: an empty correlation_id). One notFound()/badRequest() builder, used everywhere.",
|
|
4
|
+
"rule": ".claude/rules/security-one-switch.md",
|
|
5
|
+
"concepts": [
|
|
6
|
+
"routes"
|
|
7
|
+
],
|
|
8
|
+
"exclude": [
|
|
9
|
+
"**/node_modules/**",
|
|
10
|
+
"**/dist/**",
|
|
11
|
+
"**/build/**",
|
|
12
|
+
"**/.next/**",
|
|
13
|
+
".claude/**",
|
|
14
|
+
"**/.claude/**",
|
|
15
|
+
"**/*.test.*",
|
|
16
|
+
"**/*.spec.*",
|
|
17
|
+
"**/test/**",
|
|
18
|
+
"**/tests/**",
|
|
19
|
+
"**/app.ts",
|
|
20
|
+
"**/errors.*"
|
|
21
|
+
],
|
|
22
|
+
"code": false,
|
|
23
|
+
"pattern": "code\\s*:\\s*['\\\"](?:NOT_FOUND|BAD_REQUEST|INTERNAL|UNAUTHORIZED|FORBIDDEN)['\\\"]",
|
|
24
|
+
"bad": "return reply.code(404).send({ error: { code: 'NOT_FOUND', message: 'not found', correlation_id: '' } });",
|
|
25
|
+
"good": "return notFound(reply);"
|
|
26
|
+
}
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
{
|
|
2
|
+
"id": "origin-from-config-not-host",
|
|
3
|
+
"why": "Host and x-forwarded-* headers are client-controlled unless the proxy sets them. Origin, issuer, redirects and cookie flags come from PUBLIC_URL in the env schema.",
|
|
4
|
+
"rule": ".claude/rules/trust-config-not-headers.md",
|
|
5
|
+
"concepts": [
|
|
6
|
+
"routes"
|
|
7
|
+
],
|
|
8
|
+
"exclude": [
|
|
9
|
+
"**/node_modules/**",
|
|
10
|
+
"**/dist/**",
|
|
11
|
+
"**/build/**",
|
|
12
|
+
"**/.next/**",
|
|
13
|
+
".claude/**",
|
|
14
|
+
"**/.claude/**",
|
|
15
|
+
"**/*.test.*",
|
|
16
|
+
"**/*.spec.*",
|
|
17
|
+
"**/test/**",
|
|
18
|
+
"**/tests/**",
|
|
19
|
+
"**/env.*",
|
|
20
|
+
"**/config.*",
|
|
21
|
+
"**/config/**",
|
|
22
|
+
"**/proxy.*"
|
|
23
|
+
],
|
|
24
|
+
"code": false,
|
|
25
|
+
"pattern": "\\bheaders\\s*(?:\\.host\\b|\\[\\s*['\\\"](?:host|x-forwarded-proto|x-forwarded-host|x-forwarded-for)['\\\"]\\s*\\])",
|
|
26
|
+
"bad": "const proto = req.headers['x-forwarded-proto'] ?? 'http';\nconst origin = `${proto}://${req.headers.host}`;",
|
|
27
|
+
"good": "const origin = env.PUBLIC_URL;",
|
|
28
|
+
"globs": [
|
|
29
|
+
"**/ui/**/*.ts"
|
|
30
|
+
]
|
|
31
|
+
}
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
{
|
|
2
|
+
"id": "password-needs-slow-hash",
|
|
3
|
+
"why": "A fast digest (md5, sha1, sha256) of a password falls to offline brute force at billions of guesses per second. argon2id or bcrypt (cost >= 12) with the library's own salt.",
|
|
4
|
+
"rule": ".claude/rules/credentials-and-input.md",
|
|
5
|
+
"concepts": [
|
|
6
|
+
"routes"
|
|
7
|
+
],
|
|
8
|
+
"globs": [
|
|
9
|
+
"**/auth/**",
|
|
10
|
+
"**/handlers/**",
|
|
11
|
+
"**/users*"
|
|
12
|
+
],
|
|
13
|
+
"exclude": [
|
|
14
|
+
"**/node_modules/**",
|
|
15
|
+
"**/dist/**",
|
|
16
|
+
"**/build/**",
|
|
17
|
+
"**/.next/**",
|
|
18
|
+
".claude/**",
|
|
19
|
+
"**/.claude/**",
|
|
20
|
+
"**/*.test.*",
|
|
21
|
+
"**/*.spec.*",
|
|
22
|
+
"**/test/**",
|
|
23
|
+
"**/tests/**"
|
|
24
|
+
],
|
|
25
|
+
"code": false,
|
|
26
|
+
"flags": "i",
|
|
27
|
+
"pattern": "createHash\\s*\\(\\s*['\\\"](?:md5|sha1|sha256|sha512)['\\\"]\\s*\\)[^;\\n]*(?:password|passwd|pwd)|(?:password|passwd)[^;\\n]*createHash\\s*\\(\\s*['\\\"](?:md5|sha1|sha256|sha512)['\\\"]",
|
|
28
|
+
"bad": "const hash = createHash('sha256').update(password + salt).digest('hex');",
|
|
29
|
+
"good": "const hash = await argon2.hash(password, { type: argon2.argon2id });"
|
|
30
|
+
}
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
{
|
|
2
|
+
"id": "sec-headers-present",
|
|
3
|
+
"why": "An app file that creates the Fastify instance must register helmet (inside the single isProd switch). Its absence is invisible in a diff; this check sees the whole file.",
|
|
4
|
+
"rule": ".claude/rules/security-one-switch.md",
|
|
5
|
+
"concepts": [
|
|
6
|
+
"fastify-app"
|
|
7
|
+
],
|
|
8
|
+
"exclude": [
|
|
9
|
+
"**/node_modules/**",
|
|
10
|
+
"**/dist/**",
|
|
11
|
+
"**/build/**",
|
|
12
|
+
"**/.next/**",
|
|
13
|
+
".claude/**",
|
|
14
|
+
"**/.claude/**",
|
|
15
|
+
"**/*.test.*",
|
|
16
|
+
"**/*.spec.*",
|
|
17
|
+
"**/test/**",
|
|
18
|
+
"**/tests/**"
|
|
19
|
+
],
|
|
20
|
+
"code": false,
|
|
21
|
+
"mode": "needs",
|
|
22
|
+
"pattern": "\\bFastify\\s*\\(|\\bfastify\\s*\\(\\s*\\{",
|
|
23
|
+
"needs": [
|
|
24
|
+
"\\bhelmet\\b"
|
|
25
|
+
],
|
|
26
|
+
"bad": "const app = Fastify({ logger });\nawait app.register(rateLimit, {});",
|
|
27
|
+
"good": "const app = Fastify({ logger });\nif (isProd) { await app.register(helmet, { contentSecurityPolicy: csp }); await app.register(rateLimit, {}); }"
|
|
28
|
+
}
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
{
|
|
2
|
+
"id": "secrets-compared-constant-time",
|
|
3
|
+
"why": "=== on a token or secret leaks its length and prefix through timing. crypto.timingSafeEqual (or the hash library's verify for passwords).",
|
|
4
|
+
"rule": ".claude/rules/credentials-and-input.md",
|
|
5
|
+
"concepts": [
|
|
6
|
+
"routes"
|
|
7
|
+
],
|
|
8
|
+
"exclude": [
|
|
9
|
+
"**/node_modules/**",
|
|
10
|
+
"**/dist/**",
|
|
11
|
+
"**/build/**",
|
|
12
|
+
"**/.next/**",
|
|
13
|
+
".claude/**",
|
|
14
|
+
"**/.claude/**",
|
|
15
|
+
"**/*.test.*",
|
|
16
|
+
"**/*.spec.*",
|
|
17
|
+
"**/test/**",
|
|
18
|
+
"**/tests/**"
|
|
19
|
+
],
|
|
20
|
+
"code": true,
|
|
21
|
+
"pattern": "\\b(?:token|secret|signature|apiKey|api_key|bearer|otp)\\b\\s*[!=]==?\\s*(?!\\s*(?:undefined|null|''|\\\"\\\"|``))[\\w'\\\"`]",
|
|
22
|
+
"bad": "if (token === expected) return next();",
|
|
23
|
+
"good": "if (timingSafeEqual(Buffer.from(token), Buffer.from(expected))) return next();\nif (token === undefined) return reply.code(401).send(unauthorized);"
|
|
24
|
+
}
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
{
|
|
2
|
+
"id": "sse-needs-error-listener",
|
|
3
|
+
"why": "A keepalive write on an errored socket emits 'error' on the ServerResponse; with no listener that is an uncaught exception. Register raw.on('error', stop) before the first write.",
|
|
4
|
+
"rule": ".claude/rules/streams-and-hijacks.md",
|
|
5
|
+
"concepts": [
|
|
6
|
+
"routes"
|
|
7
|
+
],
|
|
8
|
+
"exclude": [
|
|
9
|
+
"**/node_modules/**",
|
|
10
|
+
"**/dist/**",
|
|
11
|
+
"**/build/**",
|
|
12
|
+
"**/.next/**",
|
|
13
|
+
".claude/**",
|
|
14
|
+
"**/.claude/**",
|
|
15
|
+
"**/*.test.*",
|
|
16
|
+
"**/*.spec.*",
|
|
17
|
+
"**/test/**",
|
|
18
|
+
"**/tests/**"
|
|
19
|
+
],
|
|
20
|
+
"code": false,
|
|
21
|
+
"mode": "needs",
|
|
22
|
+
"pattern": "text/event-stream",
|
|
23
|
+
"needs": [
|
|
24
|
+
"\\.on\\s*\\(\\s*['\\\"]error['\\\"]"
|
|
25
|
+
],
|
|
26
|
+
"bad": "raw.writeHead(200, { 'content-type': 'text/event-stream' });\nraw.on('close', stop);",
|
|
27
|
+
"good": "raw.writeHead(200, { 'content-type': 'text/event-stream' });\nraw.on('error', stop);\nraw.on('close', stop);"
|
|
28
|
+
}
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
{
|
|
2
|
+
"id": "user-bytes-need-disposition",
|
|
3
|
+
"why": "Serving uploaded bytes inline with their stored mime on the app origin is stored XSS: a text/html or image/svg+xml upload runs with the session cookie. Content-Disposition: attachment, or an allow-listed type.",
|
|
4
|
+
"rule": ".claude/rules/trust-config-not-headers.md",
|
|
5
|
+
"concepts": [
|
|
6
|
+
"routes"
|
|
7
|
+
],
|
|
8
|
+
"exclude": [
|
|
9
|
+
"**/node_modules/**",
|
|
10
|
+
"**/dist/**",
|
|
11
|
+
"**/build/**",
|
|
12
|
+
"**/.next/**",
|
|
13
|
+
".claude/**",
|
|
14
|
+
"**/.claude/**",
|
|
15
|
+
"**/*.test.*",
|
|
16
|
+
"**/*.spec.*",
|
|
17
|
+
"**/test/**",
|
|
18
|
+
"**/tests/**"
|
|
19
|
+
],
|
|
20
|
+
"code": false,
|
|
21
|
+
"mode": "needs",
|
|
22
|
+
"pattern": "\\.type\\(\\s*[\\w.]+\\.(?:mime|mimeType|contentType|content_type)\\b",
|
|
23
|
+
"needs": [
|
|
24
|
+
"Content-Disposition"
|
|
25
|
+
],
|
|
26
|
+
"bad": "return reply.type(got.meta.mime).send(got.bytes);",
|
|
27
|
+
"good": "return reply.header('Content-Disposition', `attachment; filename=\"${safeName}\"`).type(got.meta.mime).send(got.bytes);",
|
|
28
|
+
"flags": "i"
|
|
29
|
+
}
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "fastify",
|
|
3
|
+
"version": "1.0.0",
|
|
4
|
+
"description": "Fastify servers: security always on, trust config not headers, Zod at every route, streams and hijacks handled.",
|
|
5
|
+
"type": "stock",
|
|
6
|
+
"author": "claude-packs",
|
|
7
|
+
"license": "MIT",
|
|
8
|
+
"homepage": "https://github.com/TheDecipherist/claude-packs",
|
|
9
|
+
"repository": {
|
|
10
|
+
"type": "git",
|
|
11
|
+
"url": "https://github.com/TheDecipherist/claude-packs.git",
|
|
12
|
+
"directory": "packs/fastify"
|
|
13
|
+
},
|
|
14
|
+
"keywords": [
|
|
15
|
+
"fastify",
|
|
16
|
+
"api"
|
|
17
|
+
],
|
|
18
|
+
"engines": {
|
|
19
|
+
"claude-packs": ">=0.19.0"
|
|
20
|
+
},
|
|
21
|
+
"folders": {},
|
|
22
|
+
"concepts": {
|
|
23
|
+
"fastify-app": [
|
|
24
|
+
"**/app.ts",
|
|
25
|
+
"**/server.ts",
|
|
26
|
+
"**/src/index.ts",
|
|
27
|
+
"**/plugins/**/*.ts"
|
|
28
|
+
],
|
|
29
|
+
"routes": [
|
|
30
|
+
"**/routes/**/*.ts",
|
|
31
|
+
"**/handlers/**/*.ts",
|
|
32
|
+
"**/controllers/**/*.ts",
|
|
33
|
+
"**/app.ts",
|
|
34
|
+
"**/server.ts",
|
|
35
|
+
"**/ui/router*.ts",
|
|
36
|
+
"**/auth/**/*.ts"
|
|
37
|
+
]
|
|
38
|
+
},
|
|
39
|
+
"skillsIn": null,
|
|
40
|
+
"hooks": {}
|
|
41
|
+
}
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
---
|
|
2
|
+
# concepts: routes
|
|
3
|
+
paths:
|
|
4
|
+
- "placeholder"
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
# Passwords are slow-hashed, secrets compared constant-time, regexes never built from input
|
|
8
|
+
|
|
9
|
+
<constraints>
|
|
10
|
+
Always do:
|
|
11
|
+
- Passwords at rest: argon2id (preferred) or bcrypt cost ≥ 12; the library manages the salt. The plaintext exists only in the request that carries it: never persisted, logged, returned or put in an error message; response schemas omit the hash field entirely.
|
|
12
|
+
- Secrets compared constant-time: the hash library's verify for passwords, `crypto.timingSafeEqual` for tokens (`secrets-compared-constant-time`).
|
|
13
|
+
- Login failures say "Invalid email or password", never which field.
|
|
14
|
+
- Every public, unauthenticated endpoint that accepts user-submitted data (login, signup, contact, reviews, newsletter) carries a human gate (a CAPTCHA verified **server-side**) plus a rate limit, and its rejections are observable.
|
|
15
|
+
- Unauthenticated input that becomes durable state later rendered to another user is a decision recorded in the feature doc, not a default.
|
|
16
|
+
- A `RegExp` built from input goes through an escape helper (`no-regexp-from-input`), with a test that goes red when the sanitiser is bypassed.
|
|
17
|
+
- Test passwords are generated per run and test emails assembled at runtime; no password, secret or email literal is ever committed, tests included.
|
|
18
|
+
|
|
19
|
+
Never do:
|
|
20
|
+
- md5/sha-family digests for passwords, salted or not (`password-needs-slow-hash`): fast hashes fall to offline brute force at billions of guesses per second.
|
|
21
|
+
- `===` on a token or secret.
|
|
22
|
+
- `err.message` in a client-facing body.
|
|
23
|
+
</constraints>
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
---
|
|
2
|
+
# concepts: fastify-app
|
|
3
|
+
paths:
|
|
4
|
+
- "placeholder"
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
# Security hardening is production machinery: one `isProd` switch, off in dev, proven by the prod gate
|
|
8
|
+
|
|
9
|
+
The owner's iron rule, from scars: helmet's CSP blocked the inline hydration script, Secure-only cookies forced a fake reverse proxy mid-development just to log in, and a login rate limiter in a hot-reload loop is self-inflicted lockout. Dev runs bare; prod runs everything; the prod-build gate is where it is verified.
|
|
10
|
+
|
|
11
|
+
<constraints>
|
|
12
|
+
Always do:
|
|
13
|
+
- **One** `if (isProd) { … }` branch at app setup mounts all of it: `@fastify/helmet` with a real CSP (nonce per request for the one inline script), HSTS when TLS terminates upstream, `nosniff`, frame protection, Secure cookies, every rate limiter. Never per-middleware sprinkles that half-apply.
|
|
14
|
+
- `isProd` comes from the env module (`NODE_ENV === 'production'`), and **every network-reachable deploy, staging included, runs with it on**. A staging box in dev mode has unlimited login brute force and no CSP.
|
|
15
|
+
- Dev keeps functional auth (login and sessions work; `cookie.secure = isProd`) and nothing else.
|
|
16
|
+
- Because dev never exercises the hardening, the prod-build gate (`preflight-build`, then the browser pass against the built app with zero console errors, CSP violations are console errors) is the **only** place it is verified. It is never skipped.
|
|
17
|
+
- `helmet` is present in the app file (`sec-headers-present`); `trustProxy` is the ingress hop count or a list, never `true` (`no-trust-proxy-true`): with `true`, `req.ip` is the leftmost `X-Forwarded-For` value and one header per request is one fresh rate-limit bucket per request.
|
|
18
|
+
- The rate limiter is correct on all four counts: keyed so a spoofed header cannot mint buckets; a store that survives N replicas (or a stated "one replica" decision); bounded map growth plus a global ceiling; rejections observable (a 429 logs or counts, so an attack is not a quiet week).
|
|
19
|
+
- Every request-path query carries a timeout (`maxTimeMS`, an `AbortSignal`) and the request has a deadline.
|
|
20
|
+
- `/health` does not hit the database per request; cache the last ping for a few seconds.
|
|
21
|
+
- A cap on concurrent streams per client (SSE connections, change streams opened by `wait_*` tools).
|
|
22
|
+
- One `setErrorHandler`, one `setNotFoundHandler`, one body shape `{ error: { code, message, correlation_id } }`; a 500 carries the correlation id, never `err.message` (`no-err-message-to-client`).
|
|
23
|
+
|
|
24
|
+
Never do:
|
|
25
|
+
- Security plugins outside the single switch, or logic that differs between prod and dev beyond the switch, the log level and the listen address.
|
|
26
|
+
- A source-IP check as authorization behind a proxy: `req.ip` is attacker-controlled when proxies are trusted. A real credential, or an unpublished port.
|
|
27
|
+
- A route that builds its own 404/400 body (`one-error-body`).
|
|
28
|
+
</constraints>
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
---
|
|
2
|
+
# concepts: routes
|
|
3
|
+
paths:
|
|
4
|
+
- "placeholder"
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
# A hijacked reply handles its own errors; a stream has an error listener and a stop
|
|
8
|
+
|
|
9
|
+
Once `reply.hijack()` runs, Fastify's error handler can no longer answer: a throw afterwards leaves the socket open forever. A `ServerResponse` that errors with no `'error'` listener crashes the process.
|
|
10
|
+
|
|
11
|
+
<constraints>
|
|
12
|
+
Always do:
|
|
13
|
+
- `reply.hijack()` is immediately followed by `try { … } catch { raw.end() }` (`hijack-needs-try`).
|
|
14
|
+
- An SSE response registers `raw.on('error', stop)` and `raw.on('close', stop)` before the first write, and `stop` closes every change stream and timer it opened (`sse-needs-error-listener`).
|
|
15
|
+
- Every `watch()` opened for a request is closed by that request's `stop`; cap them per client.
|
|
16
|
+
- Long-running loops take an `AbortSignal` and return a stop function (`background-loop-needs-stop`); `startWatchers()`'s stop handle is kept and called from `shutdown`.
|
|
17
|
+
- Poll with a change stream or `findOneAndUpdate` wake-ups, not `while (Date.now() < deadline) await sleep(150)` against the database (`watch-not-poll`, mongo pack).
|
|
18
|
+
|
|
19
|
+
Never do:
|
|
20
|
+
- `Promise.race` with a bare `setTimeout` (the loser leaks); use `AbortSignal.timeout(ms)` or `setTimeout` from `node:timers/promises` with a signal.
|
|
21
|
+
- An in-memory `Map` used as a session/transport store without a TTL sweep and a max size.
|
|
22
|
+
</constraints>
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
---
|
|
2
|
+
# concepts: tests
|
|
3
|
+
---
|
|
4
|
+
# API tests go through Fastify's inject(), never a bound port
|
|
5
|
+
|
|
6
|
+
<constraints>
|
|
7
|
+
Always do:
|
|
8
|
+
- Build the server with `buildServer()` and call `app.inject({ method, url, payload })` in every API test, then `app.close()`.
|
|
9
|
+
- Cover each route's success, its validation failure and its error contract reply.
|
|
10
|
+
|
|
11
|
+
Never do:
|
|
12
|
+
- Call `listen()` in a test, or reach a real network service; fake the adapters.
|
|
13
|
+
</constraints>
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
---
|
|
2
|
+
# concepts: routes, fastify-app
|
|
3
|
+
paths:
|
|
4
|
+
- "placeholder"
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
# Three layers, one direction: routes → handlers → adapters
|
|
8
|
+
|
|
9
|
+
<constraints>
|
|
10
|
+
Always do:
|
|
11
|
+
- Routes (`app.ts`, `routes/**`, Next's `app/api/**/route.ts`) are thin: parse and validate the request with the entity schema, call one handler, return its result. Request-in, handler-call, response-out, nothing else.
|
|
12
|
+
- Handlers (`handlers/**`, one file per domain) hold the business logic and orchestration; they call adapters for anything external and never reach outside the process themselves.
|
|
13
|
+
- Adapters (`adapters/**`, the database gateway, external API clients, queues) wrap everything external; the Mongo gateway is the one place driver code lives (`mongo` pack).
|
|
14
|
+
- All API routes live under `/api/v1/` from the first line; no unversioned route "for now" (`api-routes-versioned`).
|
|
15
|
+
- A service owns its domain and is reached through its interface; shared code is hoisted to a shared package, never imported sideways from a sibling's internals.
|
|
16
|
+
|
|
17
|
+
Never do:
|
|
18
|
+
- A database call, `fetch` to an external API, or business logic inline in a route file (`no-db-in-route-file`).
|
|
19
|
+
- A handler that imports the driver or an HTTP client directly.
|
|
20
|
+
</constraints>
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
---
|
|
2
|
+
# concepts: routes
|
|
3
|
+
paths:
|
|
4
|
+
- "placeholder"
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
# Origin, protocol and cookie flags come from config, never from request headers
|
|
8
|
+
|
|
9
|
+
`Host`, `x-forwarded-proto` and `x-forwarded-host` are client-controlled unless the proxy strips and sets them. Building an OAuth issuer, a redirect or a cookie flag from them hands the attacker the discovery document.
|
|
10
|
+
|
|
11
|
+
<constraints>
|
|
12
|
+
Always do:
|
|
13
|
+
- `PUBLIC_URL` in the env schema is the only source for issuer, endpoints, absolute redirects and the `resource` claim.
|
|
14
|
+
- `secure: env.PUBLIC_URL.startsWith('https')`, not a header. Session cookies use the `__Host-` prefix (`path: '/'`, `secure`, no `domain`), `httpOnly`, `sameSite: 'lax'` or `'strict'`.
|
|
15
|
+
- Proxy awareness through Fastify's `trustProxy` option configured from env, then `request.protocol`/`request.hostname`; never raw `headers['x-forwarded-*']` in route code.
|
|
16
|
+
- Parse `body`, `query`, `params` with the entity's Zod schema (`safeParse` → 400); the same schema the schemas module exports. A cast or `String(body.x)` is not validation (`no-cast-at-route-boundary`).
|
|
17
|
+
- User-uploaded bytes are served with `Content-Disposition: attachment` or an allow-listed `Content-Type`; a stored `text/html`/`image/svg+xml` served inline on the app origin is stored XSS (`user-bytes-need-disposition`).
|
|
18
|
+
- One `preHandler` loads the session/auth context onto `request`; routes never repeat the load-and-redirect block.
|
|
19
|
+
|
|
20
|
+
Never do:
|
|
21
|
+
- `headers.host`, `headers['x-forwarded-proto']`, `headers['x-forwarded-host']` outside the config/proxy module (`origin-from-config-not-host`).
|
|
22
|
+
- `setCookie('session', …)` without the `__Host-` prefix (`cookie-host-prefix`).
|
|
23
|
+
- `req.body as { … }`, `req.query as …`, `Number(query.page)`.
|
|
24
|
+
</constraints>
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
{
|
|
2
|
+
"id": "no-express-no-vite",
|
|
3
|
+
"why": "The stack is Fastify and Next.js. Express and Vite are never imported, depended on or mentioned; a 'ported from Express' comment is how the next Express import gets in.",
|
|
4
|
+
"rule": ".claude/rules/stack-is-fastify-and-nextjs.md",
|
|
5
|
+
"concepts": [
|
|
6
|
+
"js"
|
|
7
|
+
],
|
|
8
|
+
"globs": [
|
|
9
|
+
"**/package.json"
|
|
10
|
+
],
|
|
11
|
+
"exclude": [
|
|
12
|
+
"**/node_modules/**",
|
|
13
|
+
"**/dist/**",
|
|
14
|
+
".claude/**",
|
|
15
|
+
"**/.claude/**",
|
|
16
|
+
"**/*.md"
|
|
17
|
+
],
|
|
18
|
+
"code": false,
|
|
19
|
+
"flags": "i",
|
|
20
|
+
"pattern": "['\"](express|vite)['\"]\\s*:|from\\s*['\"](express|vite)['\"]|require\\(\\s*['\"](express|vite)['\"]\\s*\\)",
|
|
21
|
+
"bad": "import express from 'express';\n// same as express trust proxy 1",
|
|
22
|
+
"good": "import Fastify from 'fastify';\napp.register(helmet);\n\"vitest\": \"3.0.0\"\nThe express lane is closed.\n"
|
|
23
|
+
}
|
|
@@ -0,0 +1,90 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
// stack-guard (PreToolUse, Write|Edit|MultiEdit|NotebookEdit|Bash): the full-stack configuration's stack is Fastify and
|
|
3
|
+
// Next.js, and Zod 4 (STEP 3 item 4). Refused, by every write route (lib/writes.mjs) and on an install command:
|
|
4
|
+
// - express or vite added to a package.json (dependencies of any kind) or installed (`npm i`, `pnpm add`, `yarn add`, `bun add`);
|
|
5
|
+
// - an import or require of express or vite (or one of their subpaths, @vitejs/*) added to a JS or TS file;
|
|
6
|
+
// - zod pinned below 4 in a package.json, or installed as zod@3.
|
|
7
|
+
// The API is Fastify (routes, inject() tests, its own plugins: @fastify/helmet, @fastify/rate-limit); the web app is Next.js,
|
|
8
|
+
// which builds itself. Another project's files are not judged.
|
|
9
|
+
// node stack-guard.mjs --selftest
|
|
10
|
+
import { basename, extname, join } from 'node:path';
|
|
11
|
+
import { judgeEvent } from './lib/writes.mjs';
|
|
12
|
+
import { bashOf, runHook, scratchProject, verdicts, writeOf } from './lib/selftest.mjs';
|
|
13
|
+
import { asHook, isMain } from './lib/hook-log.mjs';
|
|
14
|
+
|
|
15
|
+
const BANNED = /^(express|vite|@vitejs\/.+)$/;
|
|
16
|
+
const CODE = new Set(['.js', '.mjs', '.cjs', '.ts', '.mts', '.cts', '.tsx', '.jsx']);
|
|
17
|
+
const IMPORT = /(?:\bfrom\s*|\bimport\s*\(\s*|\brequire\s*\(\s*|^\s*import\s+)['"]((?:@vitejs\/[\w.-]+|express|vite)(?:\/[\w./-]*)?)['"]/gm;
|
|
18
|
+
const WHY = 'The full-stack configuration builds on Fastify (the API: routes, handlers, inject() tests, @fastify/helmet and @fastify/rate-limit) and Next.js (the web app, which builds itself). Use those; express and vite are not part of this stack.';
|
|
19
|
+
|
|
20
|
+
function depsOf(text) {
|
|
21
|
+
try {
|
|
22
|
+
const j = JSON.parse(text || '{}');
|
|
23
|
+
return Object.assign({}, j.dependencies, j.devDependencies, j.peerDependencies, j.optionalDependencies);
|
|
24
|
+
} catch { return null; }
|
|
25
|
+
}
|
|
26
|
+
const zodBelow4 = (spec) => typeof spec === 'string' && /^[\^~>=<\s]*[0-3](\.|$)/.test(spec.trim());
|
|
27
|
+
|
|
28
|
+
export function judgeManifest(before, after) {
|
|
29
|
+
const was = depsOf(before) ?? {}, now = depsOf(after);
|
|
30
|
+
if (!now) return null;
|
|
31
|
+
const added = Object.keys(now).filter((d) => BANNED.test(d) && !(d in was));
|
|
32
|
+
if (added.length) return `package.json gains ${added.join(', ')}. ${WHY}`;
|
|
33
|
+
if (zodBelow4(now.zod) && now.zod !== was.zod) return `package.json pins zod ${now.zod}. Schemas are Zod 4 (import { z } from 'zod', version 4 or later); take the latest 4.x.`;
|
|
34
|
+
return null;
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
export function judgeCode(before, after) {
|
|
38
|
+
const names = (t) => [...(t ?? '').matchAll(IMPORT)].map((m) => m[1]);
|
|
39
|
+
const had = names(before);
|
|
40
|
+
const added = names(after).filter((n) => !had.includes(n));
|
|
41
|
+
return added.length ? `this file gains an import of ${added[0]}. ${WHY}` : null;
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
export function judgeInstall(command) {
|
|
45
|
+
for (const part of command.replace(/<<-?\s*['"]?(\w+)['"]?[\s\S]*?\n\1\b/g, '').split(/&&|\|\||;|\|/)) {
|
|
46
|
+
const w = part.trim().split(/\s+/);
|
|
47
|
+
const at = w.findIndex((x, i) => ['npm', 'pnpm', 'yarn', 'bun'].includes(w[i - 1]) && ['i', 'install', 'add'].includes(x));
|
|
48
|
+
if (at < 0) continue;
|
|
49
|
+
for (const a of w.slice(at + 1).filter((x) => !x.startsWith('-'))) {
|
|
50
|
+
const name = a.replace(/(?!^)@[^/]*$/, '');
|
|
51
|
+
if (BANNED.test(name)) return `\`${part.trim()}\` installs ${name}. ${WHY}`;
|
|
52
|
+
if (name === 'zod' && /@[\^~]?[0-3](\.|$)/.test(a.slice(name.length))) return `\`${part.trim()}\` installs ${a}. Schemas are Zod 4: install zod@4 (the latest).`;
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
return null;
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
const main = (text) => judgeEvent(text, {
|
|
59
|
+
name: 'stack-guard',
|
|
60
|
+
command: judgeInstall,
|
|
61
|
+
write: (w) => (w.after === null ? null : basename(w.path) === 'package.json' ? judgeManifest(w.before, w.after) : CODE.has(extname(w.path)) ? judgeCode(w.before, w.after) : null),
|
|
62
|
+
});
|
|
63
|
+
|
|
64
|
+
function selftest() {
|
|
65
|
+
const hook = new URL(import.meta.url).pathname;
|
|
66
|
+
const pkg = (deps) => JSON.stringify({ name: 'x', dependencies: deps }, null, 2);
|
|
67
|
+
const dir = scratchProject({ 'api/package.json': pkg({ fastify: '5.6.1' }), 'api/src/old.ts': "import express from 'express';\n" });
|
|
68
|
+
const w = (rel, text) => runHook(hook, dir, writeOf(join(dir, rel), text));
|
|
69
|
+
const sh = (cmd) => runHook(hook, dir, bashOf(cmd, dir));
|
|
70
|
+
const cases = [
|
|
71
|
+
['express added to package.json', w('api/package.json', pkg({ fastify: '5.6.1', express: '5.1.0' })), 2],
|
|
72
|
+
['vite added as a dev dependency', w('api/package.json', JSON.stringify({ devDependencies: { vite: '7.1.0' } })), 2],
|
|
73
|
+
['zod 3 pinned', w('api/package.json', pkg({ fastify: '5.6.1', zod: '^3.23.8' })), 2],
|
|
74
|
+
['zod 4 and fastify plugins', w('api/package.json', pkg({ fastify: '5.6.1', zod: '4.1.12', '@fastify/helmet': '13.0.2' })), 0],
|
|
75
|
+
['an import of express added', w('api/src/server.ts', "import express from 'express';\n"), 2],
|
|
76
|
+
['a require of vite', w('tools/build.cjs', "const { build } = require('vite');\n"), 2],
|
|
77
|
+
['an import of @vitejs/plugin-react', w('channel/vite.config.ts', "import react from '@vitejs/plugin-react';\n"), 2],
|
|
78
|
+
['a file that already had the import keeps it', w('api/src/old.ts', "import express from 'express';\nexport const x = 1;\n"), 0],
|
|
79
|
+
['fastify imported', w('api/src/server.ts', "import Fastify from 'fastify';\n"), 0],
|
|
80
|
+
['a doc that names express', w('docs/why.md', "We never use express.\n"), 0],
|
|
81
|
+
['npm install express', sh('npm install express'), 2],
|
|
82
|
+
['pnpm add -D vite@7', sh('pnpm add -D vite@7'), 2],
|
|
83
|
+
['npm i zod@3', sh('npm i zod@3.23.8'), 2],
|
|
84
|
+
['npm i zod@4 fastify', sh('npm i zod@4.1.12 fastify'), 0],
|
|
85
|
+
];
|
|
86
|
+
return verdicts('stack-guard', cases);
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
export const hook = main; // run-hooks.mjs calls it with the event's text (KWB-24)
|
|
90
|
+
if (isMain(import.meta.url)) process.exit(process.argv.includes('--selftest') ? selftest() : await asHook('stack-guard', main));
|
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "full-stack",
|
|
3
|
+
"version": "1.0.0",
|
|
4
|
+
"description": "The full-stack configuration's stack choice: Fastify and Next.js only (stack-guard). The rest of the configuration is other packs: http-api, fastify, zod, docker.",
|
|
5
|
+
"type": "stock",
|
|
6
|
+
"author": "claude-packs",
|
|
7
|
+
"license": "MIT",
|
|
8
|
+
"homepage": "https://github.com/TheDecipherist/claude-packs",
|
|
9
|
+
"repository": {
|
|
10
|
+
"type": "git",
|
|
11
|
+
"url": "https://github.com/TheDecipherist/claude-packs.git",
|
|
12
|
+
"directory": "packs/full-stack"
|
|
13
|
+
},
|
|
14
|
+
"keywords": [
|
|
15
|
+
"fastify",
|
|
16
|
+
"nextjs",
|
|
17
|
+
"zod"
|
|
18
|
+
],
|
|
19
|
+
"engines": {
|
|
20
|
+
"claude-packs": ">=0.19.0"
|
|
21
|
+
},
|
|
22
|
+
"configurationPack": true,
|
|
23
|
+
"folders": {},
|
|
24
|
+
"concepts": {
|
|
25
|
+
"api": [
|
|
26
|
+
"api"
|
|
27
|
+
],
|
|
28
|
+
"core": [
|
|
29
|
+
"core"
|
|
30
|
+
],
|
|
31
|
+
"routes": [
|
|
32
|
+
"routes"
|
|
33
|
+
],
|
|
34
|
+
"handlers": [
|
|
35
|
+
"handlers"
|
|
36
|
+
],
|
|
37
|
+
"adapters": [
|
|
38
|
+
"adapters"
|
|
39
|
+
],
|
|
40
|
+
"schemas": [
|
|
41
|
+
"schemas"
|
|
42
|
+
],
|
|
43
|
+
"channel": [
|
|
44
|
+
"channel"
|
|
45
|
+
],
|
|
46
|
+
"manifests": [
|
|
47
|
+
"**/package.json"
|
|
48
|
+
],
|
|
49
|
+
"api-tests": [
|
|
50
|
+
"api-tests"
|
|
51
|
+
],
|
|
52
|
+
"tests": [
|
|
53
|
+
"api-tests",
|
|
54
|
+
"**/*.test.ts",
|
|
55
|
+
"**/*.test.tsx"
|
|
56
|
+
],
|
|
57
|
+
"ui": [
|
|
58
|
+
"channel"
|
|
59
|
+
]
|
|
60
|
+
},
|
|
61
|
+
"skillsIn": null,
|
|
62
|
+
"hooks": {
|
|
63
|
+
"PreToolUse": [
|
|
64
|
+
{
|
|
65
|
+
"matcher": "Write|Edit|MultiEdit|NotebookEdit|Bash",
|
|
66
|
+
"hooks": [
|
|
67
|
+
{
|
|
68
|
+
"type": "command",
|
|
69
|
+
"command": "node \"$CLAUDE_PROJECT_DIR/.claude/hooks/stack-guard.mjs\"",
|
|
70
|
+
"timeout": 10
|
|
71
|
+
}
|
|
72
|
+
]
|
|
73
|
+
}
|
|
74
|
+
]
|
|
75
|
+
}
|
|
76
|
+
}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
---
|
|
2
|
+
# concepts: api, core, channel, manifests
|
|
3
|
+
paths:
|
|
4
|
+
- "placeholder"
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
# The stack is Fastify and Next.js. Never Express, never Vite.
|
|
8
|
+
|
|
9
|
+
<constraints>
|
|
10
|
+
Always do:
|
|
11
|
+
- HTTP servers and APIs: **Fastify** (current major, `latest-versions`). Web apps: **Next.js**. Bundling is Next's; tests run on `node:test` or the project's existing runner.
|
|
12
|
+
- Check the current versions of every dependency with `latest-versions` before adding one, with its row in `docs/versions.md`.
|
|
13
|
+
- Export a `buildServer()` that returns the Fastify instance without listening; only the entry file listens.
|
|
14
|
+
|
|
15
|
+
Never do:
|
|
16
|
+
- Import, depend on or mention `express` or `vite` in code or comments (`stack-guard`, `no-express-no-vite`). A stale "ported from Express" comment is how the next Express import gets in.
|
|
17
|
+
- `await import('node:…')` of a built-in in a hot path: built-ins are static imports.
|
|
18
|
+
- A `.ts` source line over 200 characters (`line-under-200-chars`): a 1,100-character tool description belongs in a `descriptions.ts` table.
|
|
19
|
+
- Base64 blobs in source (`no-inline-binary`): assets are files served as files.
|
|
20
|
+
</constraints>
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
{
|
|
2
|
+
"id": "go-exec-result-ignored",
|
|
3
|
+
"why": "A discarded error on a state change reports success for work that failed.",
|
|
4
|
+
"rule": ".claude/rules/go-errors-are-handled.md",
|
|
5
|
+
"globs": [
|
|
6
|
+
"**/*.go"
|
|
7
|
+
],
|
|
8
|
+
"exclude": [
|
|
9
|
+
"**/*_test.go",
|
|
10
|
+
"**/vendor/**"
|
|
11
|
+
],
|
|
12
|
+
"pattern": "_,\\s*_(?:,\\s*_)?\\s*=\\s*[\\w.]*(?:Exec\\w*|Run|Shell|\\w*Run|\\w*Shell)\\(",
|
|
13
|
+
"bad": "_, _, _ = docker.ExecAndCapture(ctx, id, cmd)",
|
|
14
|
+
"good": "if _, _, err := docker.ExecAndCapture(ctx, id, cmd); err != nil { return Fail(err.Error()) }"
|
|
15
|
+
}
|