@thedecipherist/claude-packs 0.0.0-stage → 1.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +754 -0
- package/LICENSE +21 -0
- package/README.md +573 -2
- package/bin/claude-packs.mjs +212 -0
- package/configurations/base/config.json +85 -0
- package/configurations/cpp/config.json +93 -0
- package/configurations/full-stack/config.json +153 -0
- package/configurations/go/config.json +98 -0
- package/configurations/node/config.json +102 -0
- package/configurations/python/config.json +99 -0
- package/configurations/rust/config.json +106 -0
- package/configurations/synth-creator/config.json +148 -0
- package/global/hooks/gnu-shell.mjs +131 -0
- package/global/hooks/lib/shell-writes.mjs +2 -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/build-queue.mjs +22 -0
- package/lib/claude-md.mjs +60 -0
- package/lib/config-cli.mjs +36 -0
- package/lib/configs.mjs +145 -0
- package/lib/coverage.mjs +94 -0
- package/lib/custom-packs.mjs +93 -0
- package/lib/doctor.mjs +126 -0
- package/lib/fix-plan.mjs +72 -0
- package/lib/found-folders.mjs +25 -0
- package/lib/git-tokens.mjs +64 -0
- package/lib/global.mjs +125 -0
- package/lib/hook-proof.mjs +45 -0
- package/lib/hook-timing.mjs +42 -0
- package/lib/hover-gate.mjs +29 -0
- package/lib/kit-command.mjs +14 -0
- package/lib/kit-lock.mjs +149 -0
- package/lib/layout.mjs +99 -0
- package/lib/logs.mjs +109 -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 +109 -0
- package/lib/planner.mjs +59 -0
- package/lib/repeats.mjs +65 -0
- package/lib/repo-weight.mjs +28 -0
- package/lib/rule-tests.mjs +42 -0
- package/lib/rules.mjs +40 -0
- package/lib/scan-detect.mjs +130 -0
- package/lib/scan.mjs +171 -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 +31 -0
- package/lib/switches.mjs +44 -0
- package/lib/symmetry-doctor.mjs +26 -0
- package/lib/sync.mjs +133 -0
- package/lib/workorder.mjs +26 -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 +172 -0
- package/packs/audio-core/hooks/realtime-guard.mjs +67 -0
- package/packs/audio-core/pack.json +192 -0
- package/packs/audio-core/rules/a-control-is-proved-through-its-input.md +26 -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 +28 -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 +23 -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 +35 -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 +25 -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 +99 -0
- package/packs/base/hooks/dispatch-once.mjs +124 -0
- package/packs/base/hooks/file-size-guard.mjs +61 -0
- package/packs/base/hooks/folder-law.mjs +77 -0
- package/packs/base/hooks/git-guard.mjs +202 -0
- package/packs/base/hooks/lesson-checks.mjs +182 -0
- package/packs/base/hooks/lib/apply-edit.mjs +20 -0
- package/packs/base/hooks/lib/code-shapes.mjs +142 -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/crash-policy.mjs +47 -0
- package/packs/base/hooks/lib/dup-index.mjs +204 -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 +68 -0
- package/packs/base/hooks/lib/function-shapes.mjs +90 -0
- package/packs/base/hooks/lib/git-adds.mjs +21 -0
- package/packs/base/hooks/lib/git-auth.mjs +44 -0
- package/packs/base/hooks/lib/git-guard-selftest.mjs +192 -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 +69 -0
- package/packs/base/hooks/lib/layout.mjs +58 -0
- package/packs/base/hooks/lib/making-check-selftest.mjs +112 -0
- package/packs/base/hooks/lib/near-copies.mjs +76 -0
- package/packs/base/hooks/lib/program-read.mjs +199 -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/rust-scan.mjs +139 -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-lists.mjs +31 -0
- package/packs/base/hooks/lib/shape-prose.mjs +78 -0
- package/packs/base/hooks/lib/shape.mjs +273 -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 +86 -0
- package/packs/base/hooks/lib/unread-writes.mjs +24 -0
- package/packs/base/hooks/lib/writes.mjs +71 -0
- package/packs/base/hooks/making-check.mjs +248 -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 +140 -0
- package/packs/base/hooks/secrets-guard.mjs +99 -0
- package/packs/base/hooks/shape-law.mjs +140 -0
- package/packs/base/hooks/suite-once.mjs +96 -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 +19 -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 +23 -0
- package/packs/base/rules/unattended-runs.md +15 -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/new-project/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/skills/write-a-workorder/SKILL.md +41 -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 +26 -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 +29 -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/postgres/checks/pg-bind-values.json +33 -0
- package/packs/postgres/checks/pg-concurrently-in-txn.json +18 -0
- package/packs/postgres/checks/pg-fk-not-valid.json +18 -0
- package/packs/postgres/checks/pg-index-concurrently.json +18 -0
- package/packs/postgres/checks/pg-no-float-money.json +19 -0
- package/packs/postgres/checks/pg-no-money.json +18 -0
- package/packs/postgres/checks/pg-no-required-column.json +18 -0
- package/packs/postgres/checks/pg-no-volatile-default.json +18 -0
- package/packs/postgres/checks/pg-not-exists.json +18 -0
- package/packs/postgres/checks/pg-timestamptz.json +18 -0
- package/packs/postgres/hooks/db-wipe-guard.mjs +95 -0
- package/packs/postgres/pack.json +48 -0
- package/packs/postgres/rules/postgres-migrations-never-stop-traffic.md +28 -0
- package/packs/postgres/rules/postgres-one-pool-per-process.md +21 -0
- package/packs/postgres/rules/postgres-queries-are-null-safe-and-bounded.md +26 -0
- package/packs/postgres/rules/postgres-types-say-what-they-hold.md +22 -0
- package/packs/postgres/rules/postgres-values-are-bound.md +130 -0
- package/packs/postgres/skills/postgres-safe-migration/SKILL.md +45 -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 +22 -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 +22 -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/rust/checks/rust-allow-needs-reason.json +16 -0
- package/packs/rust/checks/rust-blocking-in-async.json +32 -0
- package/packs/rust/checks/rust-if-chain-is-a-match.json +32 -0
- package/packs/rust/checks/rust-static-mut.json +32 -0
- package/packs/rust/checks/rust-string-as-error.json +34 -0
- package/packs/rust/checks/rust-stub-left-in.json +32 -0
- package/packs/rust/checks/rust-unsafe-needs-safety.json +31 -0
- package/packs/rust/checks/rust-unwrap-in-library.json +34 -0
- package/packs/rust/checks/rust-wildcard-dependency.json +16 -0
- package/packs/rust/clippy.toml +5 -0
- package/packs/rust/pack.json +27 -0
- package/packs/rust/rules/rust-async-never-blocks.md +20 -0
- package/packs/rust/rules/rust-borrow-before-you-clone.md +19 -0
- package/packs/rust/rules/rust-errors-are-returned.md +22 -0
- package/packs/rust/rules/rust-lints-are-the-gate.md +23 -0
- package/packs/rust/rules/rust-repeats-become-templates.md +28 -0
- package/packs/rust/rules/rust-unsafe-is-proved.md +21 -0
- package/packs/rust/skills/rust-extract-template/SKILL.md +50 -0
- package/packs/rust/skills/rust-port/SKILL.md +22 -0
- package/packs/rust/skills/rust-review/SKILL.md +24 -0
- package/packs/rust/tools/rust-lints.toml +19 -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/bounce-a-plugin/SKILL.md +40 -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/sound-design/tools/vst3host/build.sh +73 -0
- package/packs/sound-design/tools/vst3host/host_events.h +101 -0
- package/packs/sound-design/tools/vst3host/options.h +172 -0
- package/packs/sound-design/tools/vst3host/render.cpp +245 -0
- package/packs/sound-design/tools/vst3host/session.h +241 -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 +175 -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 +21 -0
- package/packs/synth-creator/tools/buildq.mjs +74 -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
- package/prompts/workorder/PROMPT.md +53 -0
- package/prompts/workorder/run.sh +36 -0
- package/prompts/workorder/workorder.md +59 -0
|
@@ -0,0 +1,241 @@
|
|
|
1
|
+
// One plugin, loaded and running offline: no audio device, no window, no JUCE. A JUCE host cannot load every JUCE plugin (an allocator clash across
|
|
2
|
+
// the boundary aborted one inside its own parameter loader), and every audio path through an operating system can fail differently, one of them by
|
|
3
|
+
// returning silence instead of an error. A renderer that never opens a device has none of those failures, and runs faster than real time.
|
|
4
|
+
#pragma once
|
|
5
|
+
|
|
6
|
+
#include "host_events.h"
|
|
7
|
+
#include "options.h"
|
|
8
|
+
|
|
9
|
+
#include "pluginterfaces/vst/ivstaudioprocessor.h"
|
|
10
|
+
#include "pluginterfaces/vst/ivstcomponent.h"
|
|
11
|
+
#include "pluginterfaces/vst/ivsteditcontroller.h"
|
|
12
|
+
#include "pluginterfaces/vst/ivstprocesscontext.h"
|
|
13
|
+
#include "public.sdk/source/common/memorystream.h"
|
|
14
|
+
#include "public.sdk/source/vst/hosting/hostclasses.h"
|
|
15
|
+
#include "public.sdk/source/vst/hosting/module.h"
|
|
16
|
+
|
|
17
|
+
#include <algorithm>
|
|
18
|
+
#include <array>
|
|
19
|
+
#include <cmath>
|
|
20
|
+
#include <cstdio>
|
|
21
|
+
#include <deque>
|
|
22
|
+
#include <memory>
|
|
23
|
+
#include <string>
|
|
24
|
+
#include <vector>
|
|
25
|
+
|
|
26
|
+
namespace vst3host {
|
|
27
|
+
|
|
28
|
+
inline std::string titleOf (const Vst::ParameterInfo& info) {
|
|
29
|
+
std::string name;
|
|
30
|
+
for (int k = 0; k < 128 && info.title[k]; ++k) name += (char) info.title[k];
|
|
31
|
+
return name;
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
class Session {
|
|
35
|
+
public:
|
|
36
|
+
Session (const Options& options) : sampleRate (options.sampleRate), block (options.block) {}
|
|
37
|
+
|
|
38
|
+
// Loads the module and wires the two halves. An empty return is success; anything else is why it failed.
|
|
39
|
+
std::string open (const std::string& path) {
|
|
40
|
+
std::string error;
|
|
41
|
+
module = VST3::Hosting::Module::create (path, error);
|
|
42
|
+
if (! module) return "load failed: " + error;
|
|
43
|
+
auto factory = module->getFactory();
|
|
44
|
+
for (auto& info : factory.classInfos()) {
|
|
45
|
+
if (info.category() != kVstAudioEffectClass) continue;
|
|
46
|
+
component = factory.createInstance<Vst::IComponent> (info.ID()).take();
|
|
47
|
+
break;
|
|
48
|
+
}
|
|
49
|
+
if (! component) return "no audio class";
|
|
50
|
+
host = new Vst::HostApplication();
|
|
51
|
+
if (component->initialize (host) != kResultOk) return "initialize failed";
|
|
52
|
+
component->queryInterface (Vst::IAudioProcessor::iid, (void**) &processor);
|
|
53
|
+
if (! processor) return "no IAudioProcessor";
|
|
54
|
+
openController (factory);
|
|
55
|
+
return {};
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
void printParameters (bool withValues) {
|
|
59
|
+
if (! controller) return void (std::printf (" no controller, so no parameters to read\n"));
|
|
60
|
+
const int32 count = controller->getParameterCount();
|
|
61
|
+
std::printf (" %d parameters\n", count);
|
|
62
|
+
for (int32 i = 0; i < count; ++i) {
|
|
63
|
+
Vst::ParameterInfo info {};
|
|
64
|
+
if (controller->getParameterInfo (i, info) != kResultOk) continue;
|
|
65
|
+
if (withValues) std::printf (" %-40s %.6f\n", titleOf (info).c_str(), controller->getParamNormalized (info.id));
|
|
66
|
+
else std::printf (" %5d id %-10u %s\n", i, info.id, titleOf (info).c_str());
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
// Every output bus is activated and given a buffer: a plugin handed fewer buses than it declares may write nothing at all.
|
|
71
|
+
std::string start() {
|
|
72
|
+
Vst::ProcessSetup setup {};
|
|
73
|
+
setup.processMode = Vst::kOffline;
|
|
74
|
+
setup.symbolicSampleSize = Vst::kSample32;
|
|
75
|
+
setup.maxSamplesPerBlock = block;
|
|
76
|
+
setup.sampleRate = sampleRate;
|
|
77
|
+
if (processor->setupProcessing (setup) != kResultOk) return "setupProcessing failed";
|
|
78
|
+
activateBuses();
|
|
79
|
+
component->setActive (true);
|
|
80
|
+
processor->setProcessing (true);
|
|
81
|
+
prepareBuffers();
|
|
82
|
+
return {};
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
void stop() {
|
|
86
|
+
processor->setProcessing (false);
|
|
87
|
+
component->setActive (false);
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
// Renders this long. Events and parameter changes go in the first block.
|
|
91
|
+
void run (double seconds, bool keep) {
|
|
92
|
+
const int64 total = (int64) (seconds * sampleRate);
|
|
93
|
+
for (int64 done = 0; done < total; done += block) {
|
|
94
|
+
const auto count = (int32) std::min<int64> (block, total - done);
|
|
95
|
+
processBlock (count);
|
|
96
|
+
if (! keep) continue;
|
|
97
|
+
left.insert (left.end(), buffers[0].begin(), buffers[0].begin() + count);
|
|
98
|
+
right.insert (right.end(), buffers[1].begin(), buffers[1].begin() + count);
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
// Both routes. A firmware emulator's parameters may talk to it only through the controller, and a plain plugin reads inputParameterChanges.
|
|
103
|
+
void setParam (Vst::ParamID id, double value) {
|
|
104
|
+
if (controller) controller->setParamNormalized (id, value);
|
|
105
|
+
int32 index = 0;
|
|
106
|
+
int32 point = 0;
|
|
107
|
+
if (auto* queue = changes.addParameterData (id, index)) queue->addPoint (0, value, point);
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
// VST3 has no event for sysex or a program change: raw MIDI goes in a data event, which a plugin's own MIDI parser reads.
|
|
111
|
+
void sendBytes (std::vector<unsigned char> bytes) {
|
|
112
|
+
kept.push_back (std::move (bytes));
|
|
113
|
+
Vst::Event e {};
|
|
114
|
+
e.type = Vst::Event::kDataEvent;
|
|
115
|
+
e.data.type = Vst::DataEvent::kMidiSysEx;
|
|
116
|
+
e.data.size = (uint32) kept.back().size();
|
|
117
|
+
e.data.bytes = kept.back().data();
|
|
118
|
+
events.addEvent (e);
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
void noteOn (int pitch, int velocity) {
|
|
122
|
+
Vst::Event e {};
|
|
123
|
+
e.type = Vst::Event::kNoteOnEvent;
|
|
124
|
+
e.noteOn.pitch = (int16) pitch;
|
|
125
|
+
e.noteOn.velocity = (float) velocity / 127.0f;
|
|
126
|
+
e.noteOn.noteId = -1;
|
|
127
|
+
events.addEvent (e);
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
void noteOff (int pitch) {
|
|
131
|
+
Vst::Event e {};
|
|
132
|
+
e.type = Vst::Event::kNoteOffEvent;
|
|
133
|
+
e.noteOff.pitch = (int16) pitch;
|
|
134
|
+
e.noteOff.noteId = -1;
|
|
135
|
+
events.addEvent (e);
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
void clearKept() {
|
|
139
|
+
left.clear();
|
|
140
|
+
right.clear();
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
const std::vector<float>& keptLeft() const { return left; }
|
|
144
|
+
const std::vector<float>& keptRight() const { return right; }
|
|
145
|
+
Vst::IEditController* editController() { return controller; }
|
|
146
|
+
ParamChanges& reported() { return outChanges; }
|
|
147
|
+
|
|
148
|
+
private:
|
|
149
|
+
// State first, then the wire: the controller mirrors the component, so it needs the state before its parameters mean anything.
|
|
150
|
+
void openController (VST3::Hosting::PluginFactory& factory) {
|
|
151
|
+
if (component->queryInterface (Vst::IEditController::iid, (void**) &controller) != kResultOk) {
|
|
152
|
+
TUID id;
|
|
153
|
+
if (component->getControllerClassId (id) == kResultOk) controller = factory.createInstance<Vst::IEditController> (VST3::UID (id)).take();
|
|
154
|
+
if (controller) controller->initialize (host);
|
|
155
|
+
}
|
|
156
|
+
if (! controller) return;
|
|
157
|
+
wireHalves();
|
|
158
|
+
MemoryStream state;
|
|
159
|
+
if (component->getState (&state) != kResultOk) return;
|
|
160
|
+
state.seek (0, IBStream::kIBSeekSet, nullptr);
|
|
161
|
+
controller->setComponentState (&state);
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
void wireHalves() {
|
|
165
|
+
Vst::IConnectionPoint* fromComponent = nullptr;
|
|
166
|
+
Vst::IConnectionPoint* fromController = nullptr;
|
|
167
|
+
component->queryInterface (Vst::IConnectionPoint::iid, (void**) &fromComponent);
|
|
168
|
+
controller->queryInterface (Vst::IConnectionPoint::iid, (void**) &fromController);
|
|
169
|
+
if (! fromComponent || ! fromController) return;
|
|
170
|
+
fromComponent->connect (new ConnectionProxy (fromController));
|
|
171
|
+
fromController->connect (new ConnectionProxy (fromComponent));
|
|
172
|
+
}
|
|
173
|
+
|
|
174
|
+
void activateBuses() {
|
|
175
|
+
const int32 outputs = component->getBusCount (Vst::kAudio, Vst::kOutput);
|
|
176
|
+
const int32 eventBuses = component->getBusCount (Vst::kEvent, Vst::kInput);
|
|
177
|
+
std::printf (" buses: %d audio out, %d event in\n", outputs, eventBuses);
|
|
178
|
+
for (int32 bus = 0; bus < outputs; ++bus) component->activateBus (Vst::kAudio, Vst::kOutput, bus, true);
|
|
179
|
+
for (int32 bus = 0; bus < eventBuses; ++bus) component->activateBus (Vst::kEvent, Vst::kInput, bus, true);
|
|
180
|
+
if (component->getBusCount (Vst::kAudio, Vst::kInput) > 0) component->activateBus (Vst::kAudio, Vst::kInput, 0, true);
|
|
181
|
+
}
|
|
182
|
+
|
|
183
|
+
void prepareBuffers() {
|
|
184
|
+
const auto outputs = (size_t) std::max (1, component->getBusCount (Vst::kAudio, Vst::kOutput));
|
|
185
|
+
buffers.assign ((outputs + 1) * 2, std::vector<float> ((size_t) block, 0.0f)); // the last pair is the silent input
|
|
186
|
+
pointers.resize (outputs + 1);
|
|
187
|
+
busBuffers.assign (outputs + 1, Vst::AudioBusBuffers {});
|
|
188
|
+
for (size_t bus = 0; bus <= outputs; ++bus) {
|
|
189
|
+
pointers[bus] = { buffers[bus * 2].data(), buffers[bus * 2 + 1].data() };
|
|
190
|
+
busBuffers[bus].numChannels = 2;
|
|
191
|
+
busBuffers[bus].channelBuffers32 = pointers[bus].data();
|
|
192
|
+
}
|
|
193
|
+
context.state = Vst::ProcessContext::kPlaying | Vst::ProcessContext::kTempoValid;
|
|
194
|
+
context.sampleRate = sampleRate;
|
|
195
|
+
context.tempo = 120.0;
|
|
196
|
+
data.processMode = Vst::kOffline;
|
|
197
|
+
data.symbolicSampleSize = Vst::kSample32;
|
|
198
|
+
data.numInputs = component->getBusCount (Vst::kAudio, Vst::kInput) > 0 ? 1 : 0;
|
|
199
|
+
data.numOutputs = (int32) outputs;
|
|
200
|
+
data.inputs = data.numInputs ? &busBuffers[outputs] : nullptr;
|
|
201
|
+
data.outputs = busBuffers.data();
|
|
202
|
+
data.inputEvents = &events;
|
|
203
|
+
data.inputParameterChanges = &changes;
|
|
204
|
+
data.outputParameterChanges = &outChanges; // left null, a change a plugin's own sysex handler made stays invisible
|
|
205
|
+
data.processContext = &context;
|
|
206
|
+
}
|
|
207
|
+
|
|
208
|
+
void processBlock (int32 count) {
|
|
209
|
+
data.numSamples = count;
|
|
210
|
+
std::fill (buffers[0].begin(), buffers[0].end(), 0.0f);
|
|
211
|
+
std::fill (buffers[1].begin(), buffers[1].end(), 0.0f);
|
|
212
|
+
context.projectTimeSamples = position;
|
|
213
|
+
processor->process (data);
|
|
214
|
+
events.clear();
|
|
215
|
+
changes.clear();
|
|
216
|
+
kept.clear();
|
|
217
|
+
position += count;
|
|
218
|
+
}
|
|
219
|
+
|
|
220
|
+
double sampleRate;
|
|
221
|
+
int block;
|
|
222
|
+
VST3::Hosting::Module::Ptr module;
|
|
223
|
+
Vst::HostApplication* host = nullptr;
|
|
224
|
+
Vst::IComponent* component = nullptr;
|
|
225
|
+
Vst::IAudioProcessor* processor = nullptr;
|
|
226
|
+
Vst::IEditController* controller = nullptr;
|
|
227
|
+
std::vector<std::vector<float>> buffers;
|
|
228
|
+
std::vector<std::array<float*, 2>> pointers;
|
|
229
|
+
std::vector<Vst::AudioBusBuffers> busBuffers;
|
|
230
|
+
Vst::ProcessContext context {};
|
|
231
|
+
Vst::ProcessData data {};
|
|
232
|
+
EventList events;
|
|
233
|
+
ParamChanges changes;
|
|
234
|
+
ParamChanges outChanges;
|
|
235
|
+
std::deque<std::vector<unsigned char>> kept;
|
|
236
|
+
std::vector<float> left;
|
|
237
|
+
std::vector<float> right;
|
|
238
|
+
int64 position = 0;
|
|
239
|
+
};
|
|
240
|
+
|
|
241
|
+
} // namespace vst3host
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
{
|
|
2
|
+
"id": "no-keyboard-focus",
|
|
3
|
+
"why": "Stellix 3a: no dropdown, button or readout ever takes keyboard focus; QWERTY always plays.",
|
|
4
|
+
"rule": ".claude/rules/stellix-deterministic-world.md",
|
|
5
|
+
"concepts": [
|
|
6
|
+
"ui"
|
|
7
|
+
],
|
|
8
|
+
"pattern": "setWantsKeyboardFocus\\s*\\(\\s*true|grabKeyboardFocus\\s*\\(|setMouseClickGrabsKeyboardFocus\\s*\\(\\s*true",
|
|
9
|
+
"code": true,
|
|
10
|
+
"bad": "presetBox.setWantsKeyboardFocus (true);",
|
|
11
|
+
"good": "presetBox.setWantsKeyboardFocus (false);"
|
|
12
|
+
}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
{
|
|
2
|
+
"id": "one-seeded-random",
|
|
3
|
+
"why": "Stellix rule 4: formulas by default; the only randomness is the world's one seeded generator (RANDOM, 6.6). No other random call may exist in the engine, the world or the drawing.",
|
|
4
|
+
"rule": ".claude/rules/stellix-deterministic-world.md",
|
|
5
|
+
"concepts": [
|
|
6
|
+
"cpp"
|
|
7
|
+
],
|
|
8
|
+
"exclude": [
|
|
9
|
+
"@seeded_random",
|
|
10
|
+
"**/tests/**"
|
|
11
|
+
],
|
|
12
|
+
"pattern": "(?<![\\w.])(?:std::)?(?:s?rand|random|drand48|lrand48|arc4random(?:_uniform)?)\\s*\\(|\\b(?:random_device|mt19937(?:_64)?|minstd_rand0?|default_random_engine|ranlux\\w+|knuth_b)\\b|\\b\\w+_distribution\\b|\\bjuce::Random\\b|(?<![\\w:])Random\\s*(?:::|\\w+\\s*[;({=])|\\bgetSystemRandom\\b|\\bSecRandomCopyBytes\\b|\\bRAND_bytes\\b",
|
|
13
|
+
"code": true,
|
|
14
|
+
"bad": "float jitter = juce::Random::getSystemRandom().nextFloat();\nstd::mt19937 g (42);\nstd::uniform_real_distribution<float> d (0, 1);\nuint32_t v = arc4random_uniform (8);",
|
|
15
|
+
"good": "float jitter = world.seeded().next01();\nauto n = randomSource.next(); int operand (int); bool israndom;\ninline float hash (int i) { return std::sin (float (i) * 12.98f) * 43758.5f; }"
|
|
16
|
+
}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
{
|
|
2
|
+
"id": "world-never-includes-painter",
|
|
3
|
+
"why": "Stellix 8: the world is coordinates, not graphics. The audio side includes nothing from the painter or any GPU API; it publishes a plain-data snapshot and nothing else.",
|
|
4
|
+
"rule": ".claude/rules/stellix-world-snapshot.md",
|
|
5
|
+
"concepts": [
|
|
6
|
+
"world",
|
|
7
|
+
"audio"
|
|
8
|
+
],
|
|
9
|
+
"pattern": "#\\s*(include|import)\\s*[<\"][^>\"]*(painter|Painter|gpu/|render/|Renderer|juce_opengl|OpenGL|Metal/|MetalKit|QuartzCore|bgfx|webgpu)[^>\"]*[>\"]",
|
|
10
|
+
"bad": "#include \"../painter/PlanetMesh.h\"",
|
|
11
|
+
"good": "#include \"WorldSnapshot.h\""
|
|
12
|
+
}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
{
|
|
2
|
+
"id": "world-no-libm",
|
|
3
|
+
"why": "libm sin/cos/exp/pow differ in the last bits between Apple, MSVC and glibc; the world must replay bit-identically on Mac and Windows. Use the house world-math functions.",
|
|
4
|
+
"rule": ".claude/rules/world-fp-determinism.md",
|
|
5
|
+
"concepts": [
|
|
6
|
+
"world"
|
|
7
|
+
],
|
|
8
|
+
"exclude": [
|
|
9
|
+
"@world_math"
|
|
10
|
+
],
|
|
11
|
+
"pattern": "\\bstd::(sin|cos|tan|asin|acos|atan2?|exp2?|expm1|log(2|10|1p)?|pow|sinh|cosh|tanh|hypot|cbrt)\\s*\\(|(?<![\\w:.>])(sinf?|cosf?|tanf?|atan2f?|expf?|logf?|powf?)\\s*\\(",
|
|
12
|
+
"code": true,
|
|
13
|
+
"bad": "const double a = std::sin (phase) * radius;",
|
|
14
|
+
"good": "const double a = wm::sin (phase) * radius;"
|
|
15
|
+
}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
{
|
|
2
|
+
"id": "world-no-unordered",
|
|
3
|
+
"why": "Hash-container iteration order differs between libc++ and the MSVC STL; the world must be ordered by stable ID to replay identically on every platform.",
|
|
4
|
+
"rule": ".claude/rules/world-fp-determinism.md",
|
|
5
|
+
"concepts": ["world"],
|
|
6
|
+
"pattern": "\\bstd::unordered_(map|set|multimap|multiset)\\b",
|
|
7
|
+
"code": true,
|
|
8
|
+
"bad": "std::unordered_map<int, Moon> moonsById;",
|
|
9
|
+
"good": "std::array<Moon, kMaxMoons> moons; // ordered by stable id"
|
|
10
|
+
}
|
|
@@ -0,0 +1,88 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
// Nothing is ever pre-rendered (Stellix spec 0.2). No image file may be added to the source or
|
|
3
|
+
// resources (fonts are allowed: data, not pictures). Test output and goldens live outside them.
|
|
4
|
+
// A project sets its own scope in .claude/layout.json "guards": { "images": { "guarded": [globs],
|
|
5
|
+
// "allowed": [globs] } }: "guarded" replaces the code folders (["**"]: anywhere in the repo), "allowed"
|
|
6
|
+
// replaces the default allowed folders (Stellix: design/reference/** and build/pictures/** only).
|
|
7
|
+
// PreToolUse (Write|Edit|MultiEdit|NotebookEdit|Bash): blocks writing, copying or moving an image into a guarded
|
|
8
|
+
// folder by any route (lib/writes.mjs), and a download or conversion that names one (curl, convert, sips ...).
|
|
9
|
+
// --git-staged: run from a git pre-commit hook; fails if a staged added file is an image.
|
|
10
|
+
// --selftest: proves it.
|
|
11
|
+
import { execFileSync } from 'node:child_process';
|
|
12
|
+
import { readFileSync } from 'node:fs';
|
|
13
|
+
import { join, resolve } from 'node:path';
|
|
14
|
+
import { fileURLToPath } from 'node:url';
|
|
15
|
+
import { matchesAny } from './lib/glob.mjs';
|
|
16
|
+
import { codeFolders, readLayout } from './lib/layout.mjs';
|
|
17
|
+
import { claudeRoot, commandLeavesProject, insideProject, relInCheckout } from './lib/project.mjs';
|
|
18
|
+
import { writesOf } from './lib/writes.mjs';
|
|
19
|
+
import { bashOf, runHook, scratchProject, verdicts, writeOf } from './lib/selftest.mjs';
|
|
20
|
+
import { asHook, isMain } from './lib/hook-log.mjs';
|
|
21
|
+
|
|
22
|
+
const ROOT = process.env.CLAUDE_PROJECT_DIR ?? process.cwd();
|
|
23
|
+
const IMAGE = /\.(png|jpe?g|gif|bmp|tiff?|webp|heic|ico|icns|svg|psd|tga|exr|hdr|ktx2?|dds|astc)$/i;
|
|
24
|
+
// Guarded: every code folder in the layout, plus anything that would be bundled as a resource.
|
|
25
|
+
const guarded = (root) => readLayout(root).guards?.images?.guarded ?? [...new Set(['src/**', 'Resources/**', 'resources/**', 'assets/**', ...codeFolders(readLayout(root)).map((f) => `${f}/**`)])];
|
|
26
|
+
const ALLOWED = ['tests/**', '**/tests/**', 'goldens/**', '**/goldens/**', 'docs/**', 'captures/**', 'build/**'];
|
|
27
|
+
const allowed = (root) => readLayout(root).guards?.images?.allowed ?? ALLOWED;
|
|
28
|
+
|
|
29
|
+
// A path is judged in its own checkout, so an image written into an agent worktree is caught too.
|
|
30
|
+
const isBlocked = (p, base = ROOT) => {
|
|
31
|
+
const abs = resolve(base, p);
|
|
32
|
+
if (!IMAGE.test(abs) || !insideProject(abs)) return false;
|
|
33
|
+
const rel = relInCheckout(abs).replace(/^\.claude\/worktrees\/[^/]+\//, '');
|
|
34
|
+
const root = claudeRoot(abs);
|
|
35
|
+
return !rel.startsWith('.claude/') && matchesAny(rel, guarded(root)) && !matchesAny(rel, allowed(root));
|
|
36
|
+
};
|
|
37
|
+
|
|
38
|
+
function fail(files) {
|
|
39
|
+
process.stderr.write(
|
|
40
|
+
`BLOCKED by no-shipped-images: ${files.join(', ')}\n` +
|
|
41
|
+
'Nothing is pre-rendered: draw it in code; a picture check renders off-screen, from the app itself, into an allowed folder (guards.images.allowed in .claude/layout.json).\n',
|
|
42
|
+
);
|
|
43
|
+
return 2;
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
function gitStaged() {
|
|
47
|
+
const out = execFileSync('git', ['diff', '--cached', '--name-only', '--diff-filter=AR'], { cwd: ROOT, encoding: 'utf8' });
|
|
48
|
+
const bad = out.split('\n').filter((f) => f && isBlocked(f));
|
|
49
|
+
return bad.length ? (fail(bad), 1) : 0;
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
function main(text) {
|
|
53
|
+
let payload;
|
|
54
|
+
try {
|
|
55
|
+
payload = JSON.parse(text);
|
|
56
|
+
} catch {
|
|
57
|
+
return 0;
|
|
58
|
+
}
|
|
59
|
+
const input = payload.tool_input ?? {};
|
|
60
|
+
const bad = writesOf(payload, payload.cwd ?? ROOT).filter((w) => w.op !== 'delete' && isBlocked(w.path)).map((w) => w.path);
|
|
61
|
+
if (payload.tool_name === 'Bash' && !commandLeavesProject(input.command)) {
|
|
62
|
+
const tokens = (input.command ?? '').split(/\s+/).map((t) => t.replace(/^['"]|['"]$/g, ''));
|
|
63
|
+
if (/\b(curl|wget|convert|magick|sips|rsvg-convert|ffmpeg)\b/.test(input.command ?? '')) bad.push(...tokens.filter((t) => t && isBlocked(t, payload.cwd ?? ROOT)));
|
|
64
|
+
}
|
|
65
|
+
return bad.length ? fail([...new Set(bad)]) : 0;
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
function selftest() {
|
|
69
|
+
const me = fileURLToPath(import.meta.url);
|
|
70
|
+
const dir = scratchProject({}, { folders: { app: { path: 'lib/app/src', purpose: 'app' }, docs: { path: 'docs', purpose: 'docs' } }, concepts: {} });
|
|
71
|
+
const w = (file) => runHook(me, dir, writeOf(join(dir, file), 'x'));
|
|
72
|
+
return verdicts('no-shipped-images', [
|
|
73
|
+
['an image in a code folder', w('lib/app/src/logo.png'), 2],
|
|
74
|
+
['an image in src/', w('src/icon.svg'), 2],
|
|
75
|
+
['an image in resources/', w('resources/knob.webp'), 2],
|
|
76
|
+
['a font is data, not a picture', w('resources/Inter.ttf'), 0],
|
|
77
|
+
['a golden render under tests/', w('tests/goldens/panel.png'), 0],
|
|
78
|
+
['a picture in docs/', w('docs/shot.png'), 0],
|
|
79
|
+
['cp of an image into a code folder', runHook(me, dir, bashOf('cp /tmp/a.png lib/app/src/a.png', dir)), 2],
|
|
80
|
+
['cp into tests/', runHook(me, dir, bashOf('cp /tmp/a.png tests/goldens/a.png', dir)), 0],
|
|
81
|
+
]);
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
export const hook = main; // run-hooks.mjs calls it with the event's text (KWB-24)
|
|
85
|
+
if (isMain(import.meta.url)) {
|
|
86
|
+
const arg = process.argv.slice(2);
|
|
87
|
+
process.exit(arg.includes('--selftest') ? selftest() : arg.includes('--git-staged') ? gitStaged() : await asHook('no-shipped-images', main));
|
|
88
|
+
}
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "stellix",
|
|
3
|
+
"version": "1.0.0",
|
|
4
|
+
"description": "Stellix spec laws: the world, determinism, generated reset, no shipped images.",
|
|
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/stellix"
|
|
13
|
+
},
|
|
14
|
+
"keywords": [
|
|
15
|
+
"synth"
|
|
16
|
+
],
|
|
17
|
+
"engines": {
|
|
18
|
+
"claude-packs": ">=0.19.0"
|
|
19
|
+
},
|
|
20
|
+
"folders": {
|
|
21
|
+
"world": {
|
|
22
|
+
"path": "src/world",
|
|
23
|
+
"purpose": "the world: coordinates, travellers, hits, pushes, the snapshot writer, the seeded generator, world maths"
|
|
24
|
+
},
|
|
25
|
+
"records": {
|
|
26
|
+
"path": "records",
|
|
27
|
+
"purpose": "layout and state records: every piece of state declared once with its starting value"
|
|
28
|
+
}
|
|
29
|
+
},
|
|
30
|
+
"concepts": {
|
|
31
|
+
"world": [
|
|
32
|
+
"world"
|
|
33
|
+
],
|
|
34
|
+
"records": [
|
|
35
|
+
"records"
|
|
36
|
+
],
|
|
37
|
+
"params": [
|
|
38
|
+
"records"
|
|
39
|
+
]
|
|
40
|
+
},
|
|
41
|
+
"skillsIn": null,
|
|
42
|
+
"hooks": {
|
|
43
|
+
"PreToolUse": [
|
|
44
|
+
{
|
|
45
|
+
"matcher": "Write|Edit|MultiEdit|NotebookEdit|Bash",
|
|
46
|
+
"hooks": [
|
|
47
|
+
{
|
|
48
|
+
"type": "command",
|
|
49
|
+
"command": "node \"$CLAUDE_PROJECT_DIR/.claude/hooks/no-shipped-images.mjs\"",
|
|
50
|
+
"timeout": 10
|
|
51
|
+
}
|
|
52
|
+
]
|
|
53
|
+
}
|
|
54
|
+
]
|
|
55
|
+
},
|
|
56
|
+
"files": {
|
|
57
|
+
"seeded_random": "src/world/seeded_random.h",
|
|
58
|
+
"world_math": "src/world/world_math.h",
|
|
59
|
+
"snapshot": "src/world/snapshot.h"
|
|
60
|
+
}
|
|
61
|
+
}
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
---
|
|
2
|
+
# concepts: world, audio, painter, ui, tests
|
|
3
|
+
paths:
|
|
4
|
+
- "placeholder"
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
# Same playing from the same state gives the same sound and the same picture
|
|
8
|
+
|
|
9
|
+
From spec §0 rule 4, §6.1, §6.3, §7.3.
|
|
10
|
+
|
|
11
|
+
<constraints>
|
|
12
|
+
Always do:
|
|
13
|
+
- Work out every path, bounce, impact and shatter by formula from what was played, where it hits, and the world's settings.
|
|
14
|
+
- Use the world's one seeded generator as the only randomness (RANDOM, opt-in, off in INIT and every factory patch). It may reach modulation and effects only, never pitch, wave, tone, level, filter type or a SOUND choice. Under FOLLOW THE SONG its seed restarts with the song position.
|
|
15
|
+
- Run the world at a fixed 240 Hz tick, independent of buffer size and sample rate. Solve crossings and touches inside the tick and place each event at its exact sample.
|
|
16
|
+
- Keep looking separate from sound: hovering, zooming and moving the camera never change the sound (unless FROM VIEW is on, where the camera becomes patch data).
|
|
17
|
+
|
|
18
|
+
Never do:
|
|
19
|
+
- Call any random source other than the seeded generator. `.claude/checks/one-seeded-random.json` blocks it.
|
|
20
|
+
- Let the frame rate, the window being open, or the host buffer size change what is heard.
|
|
21
|
+
- Let a control take keyboard focus. QWERTY always plays (`no-keyboard-focus.json`).
|
|
22
|
+
</constraints>
|
|
23
|
+
|
|
24
|
+
## Check
|
|
25
|
+
Gates, each proven red by a planted fault:
|
|
26
|
+
- **Bounce repeat:** the same MIDI from INIT renders bit-identical twice, at buffer sizes 64, 512 and 2048 and at 44.1, 48 and 96 kHz.
|
|
27
|
+
- **View:** with FROM VIEW off, a camera move or a hover leaves the render bit-identical.
|
|
28
|
+
- **Four tempos:** HITS and BEATS notes land on their exact samples.
|
|
29
|
+
- **Settle:** after a hard passage the world comes to rest once playing stops.
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
---
|
|
2
|
+
# concepts: records, params, world
|
|
3
|
+
paths:
|
|
4
|
+
- "placeholder"
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
# Reset is generated from the records, never written by hand
|
|
8
|
+
|
|
9
|
+
From spec §0 rule 5.
|
|
10
|
+
|
|
11
|
+
<constraints>
|
|
12
|
+
Always do:
|
|
13
|
+
- Declare every piece of patch state once in the records, with its starting value. The reset is generated from that list, and state without a starting value must not compile.
|
|
14
|
+
- Treat a patch load as a reset followed by an apply, so nothing survives from the previous patch.
|
|
15
|
+
- Make reset clear motion too: every mover, note in flight and shatter piece. Every held note gets its note-off.
|
|
16
|
+
- Keep MAIN volume, octave, the wheel positions, LIMIT and SETTINGS outside the patch, as the patch law says.
|
|
17
|
+
|
|
18
|
+
Never do:
|
|
19
|
+
- Write a reset by hand, or add a field to a hand-made list.
|
|
20
|
+
- Plant state in a member variable that isn't declared in the records.
|
|
21
|
+
</constraints>
|
|
22
|
+
|
|
23
|
+
## Check
|
|
24
|
+
Reset gate: move every control and every piece of patch state away from its start, set the world moving with notes in flight, then reset. The render must be bit-identical to a fresh INIT. Plant the fault (one field outside the list) and the gate must show red.
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
---
|
|
2
|
+
# concepts: world, painter, audio
|
|
3
|
+
paths:
|
|
4
|
+
- "placeholder"
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
# The painter sees the world only through one plain-data snapshot
|
|
8
|
+
|
|
9
|
+
From spec §8 and §7.3.
|
|
10
|
+
|
|
11
|
+
<constraints>
|
|
12
|
+
Always do:
|
|
13
|
+
- Keep the world as coordinates on the audio side: a traveller is a position and a velocity; a moon is a position, a radius and a border; a planet is a position and a radius. Each 240 Hz tick moves travellers, checks distances and turns hits into pushes, as arithmetic only.
|
|
14
|
+
- Publish one plain-data snapshot per tick (positions, pushes, hits) behind a single atomic index. Use double or triple buffering, whichever keeps the reader from ever seeing a half-written one.
|
|
15
|
+
- Let the painter read only the snapshot, at its own frame rate. It may extrapolate between ticks with the same formulas, but when they differ the snapshot wins.
|
|
16
|
+
- Compute predictions (ghost paths, "cutoff +12%") with the engine's own formula code on a copy of the world's state, never with a second version of the formulas.
|
|
17
|
+
|
|
18
|
+
Never do:
|
|
19
|
+
- Include anything from the painter, a GPU API or JUCE OpenGL in world, engine or voice code. `.claude/checks/world-never-includes-painter.json` blocks it.
|
|
20
|
+
- Do camera, perspective, lighting, mesh, bloom or path drawing work inside the world tick. The look-only test's 17 ms demo step is the example of what this forbids.
|
|
21
|
+
- Let the audio thread wait for, lock against or allocate for the painter.
|
|
22
|
+
</constraints>
|
|
23
|
+
|
|
24
|
+
## Check
|
|
25
|
+
- Torn-snapshot gate: a reader hammering the snapshot while the world writes at full rate must never see a mixed one. Plant the fault by writing in place, and the gate goes red.
|
|
26
|
+
- Prediction gate: play a passage; every predicted hit happens, and no unpredicted hit occurs.
|
|
27
|
+
- The realtime-guard hook blocks GPU calls in audio-thread code.
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
---
|
|
2
|
+
# concepts: world, tests
|
|
3
|
+
paths:
|
|
4
|
+
- "placeholder"
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
# Every hit inside a tick is found exactly once and placed at its sample
|
|
8
|
+
|
|
9
|
+
From spec 6.0 and 7.3: the tick never quantises time.
|
|
10
|
+
|
|
11
|
+
<constraints>
|
|
12
|
+
Always do:
|
|
13
|
+
- Sweep each traveller across the tick. A formula curve is split into a fixed number K of substeps (fixed K keeps it deterministic), and each chord is swept against every sphere in reach.
|
|
14
|
+
- Solve segment against sphere with the numerically stable quadratic: `q = −½(b + sign(b)·√disc)`, roots `c'/q` and `q/a` (Ericson, *Real-Time Collision Detection* §5.3). Take the smallest `t` in [0, 1).
|
|
15
|
+
- Keep a contact state per traveller/planet pair. A hit fires on the *entering* transition only; a traveller starting inside counts once, at t = 0.
|
|
16
|
+
- Use a skin tolerance relative to the radius, and settle simultaneous hits by pair ID.
|
|
17
|
+
- Convert `t` to a sample with integer or fixed-point arithmetic: `tickStartSample + floor(t · samplesPerTick)`.
|
|
18
|
+
|
|
19
|
+
Never do:
|
|
20
|
+
- Test only the end position of a tick (fast travellers tunnel through small moons).
|
|
21
|
+
- Let a resting contact fire again every tick.
|
|
22
|
+
</constraints>
|
|
23
|
+
|
|
24
|
+
## Check
|
|
25
|
+
- Test: a traveller at 10x the fastest launch speed crosses a sphere of the smallest radius. Exactly one event, at the analytically expected sample, ±0.
|
|
26
|
+
- Test: grazing paths (tangent, ±1 skin) give the same verdict on both platforms (part of the cross-platform event-log gate).
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
---
|
|
2
|
+
# concepts: world, build
|
|
3
|
+
paths:
|
|
4
|
+
- "placeholder"
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
# The world gives bit-identical results on Mac and Windows
|
|
8
|
+
|
|
9
|
+
The world (travellers, hits, pushes, event samples) must replay identically on ARM64 and x86-64. Audio DSP only needs to be identical per platform.
|
|
10
|
+
|
|
11
|
+
<constraints>
|
|
12
|
+
Always do:
|
|
13
|
+
- Build world sources with `-ffp-contract=off` (clang and clang-cl) and `/fp:precise` without `/fp:contract` (MSVC). Clang fuses multiply-adds by default (`-ffp-contract=on`), and Apple clang on ARM64 emits `fmadd`.
|
|
14
|
+
- Use only `+ − × ÷ sqrt` in the world. IEEE-754 rounds those five exactly, so they match everywhere. Build `sin`, `cos`, `exp` and `pow` from the house polynomial versions (range reduction plus Horner) in one world-math file.
|
|
15
|
+
- Keep world state in fixed arrays ordered by stable ID, and break sort ties by ID.
|
|
16
|
+
- Keep time as integers: sample timestamps as `int64`, and the tick phase as an integer ratio (48 kHz/240 Hz is exactly 200 samples, but 44.1 kHz/240 Hz is 183.75, so accumulate the remainder exactly).
|
|
17
|
+
- Design out denormals in the world: snap magnitudes below 1e-30 to zero explicitly rather than relying on CPU flush modes, which differ between ARM and x86.
|
|
18
|
+
- Consider 64-bit fixed point (e.g. Q32.32) for positions. It removes compiler and flag risk entirely (house option, decided in the world plan).
|
|
19
|
+
|
|
20
|
+
Never do:
|
|
21
|
+
- Call libm (`std::sin`, `std::exp`, `std::pow`…) in world code. Apple libm, the MSVC UCRT and glibc differ in the last bits.
|
|
22
|
+
- Use `std::unordered_*` or iterate anything in hash order in the world.
|
|
23
|
+
- Use fast-math or FMA-contraction flags anywhere (`no-fast-math` check).
|
|
24
|
+
</constraints>
|
|
25
|
+
|
|
26
|
+
## Check
|
|
27
|
+
- `.claude/checks/world-no-libm.json` and `world-no-unordered.json` block libm calls and unordered containers in world code.
|
|
28
|
+
- Cross-platform gate: render N seconds from a saved state on both CI platforms. The world event log (event, sample index, payload hash) must be byte-identical between Mac and Windows; the audio hash must be identical between runs on each platform.
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
{
|
|
2
|
+
"id": "no-raw-html-from-data",
|
|
3
|
+
"why": "HTML put on a page by hand skips the sanitize step: stored markdown can carry a script. The only HTML inserted raw is the renderer's output.",
|
|
4
|
+
"rule": ".claude/rules/stored-text-renders-once.md",
|
|
5
|
+
"globs": [
|
|
6
|
+
"**/*.ts",
|
|
7
|
+
"**/*.tsx",
|
|
8
|
+
"**/*.js",
|
|
9
|
+
"**/*.jsx",
|
|
10
|
+
"**/*.mjs",
|
|
11
|
+
"**/*.vue",
|
|
12
|
+
"**/*.svelte",
|
|
13
|
+
"**/*.html"
|
|
14
|
+
],
|
|
15
|
+
"exclude": [
|
|
16
|
+
"**/node_modules/**",
|
|
17
|
+
"**/dist/**",
|
|
18
|
+
"**/build/**",
|
|
19
|
+
".claude/**",
|
|
20
|
+
"**/.claude/**",
|
|
21
|
+
"**/*.test.*",
|
|
22
|
+
"**/*.spec.*",
|
|
23
|
+
"**/test/**",
|
|
24
|
+
"**/tests/**",
|
|
25
|
+
"**/stored-text.*"
|
|
26
|
+
],
|
|
27
|
+
"strings": true,
|
|
28
|
+
"pattern": "dangerouslySetInnerHTML=\\{\\{\\s*__html:(?!\\s*renderStored\\()|\\.(?:innerHTML|outerHTML)\\s*\\+?=(?!\\s*(?:renderStored\\(|['\"`]{2}))|\\bv-html=\"(?!renderStored\\()",
|
|
29
|
+
"bad": "<div dangerouslySetInnerHTML={{ __html: row.body }} />\n",
|
|
30
|
+
"good": "<StoredText source={row.body} />\n<div dangerouslySetInnerHTML={{ __html: renderStored(row.body) }} />\nel.innerHTML = '';\n"
|
|
31
|
+
}
|