@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,18 @@
|
|
|
1
|
+
---
|
|
2
|
+
# concepts: tests, build
|
|
3
|
+
paths:
|
|
4
|
+
- "placeholder"
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
# "Done" means evidence from this turn
|
|
8
|
+
|
|
9
|
+
<constraints>
|
|
10
|
+
Always do:
|
|
11
|
+
- Before saying done, fixed, passing, faster or "sounds the same", run the command that proves it in this turn and quote its verdict: test-verdict JSON, null-test result in dBFS, benchmark p99, golden-image score.
|
|
12
|
+
- Say exactly what was not verified, and why ("not run on Windows", "listened only, not measured").
|
|
13
|
+
- Treat a subagent's report as a claim. Check its diff and re-run its verdict before passing it on.
|
|
14
|
+
|
|
15
|
+
Never do:
|
|
16
|
+
- Report success from memory of an earlier run, from a build that only compiled, or from "should work".
|
|
17
|
+
- Report a partial pass as a pass.
|
|
18
|
+
</constraints>
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
---
|
|
2
|
+
# concepts: tooling
|
|
3
|
+
paths:
|
|
4
|
+
- "placeholder"
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
# Hooks, gates and tools: each seen red, each fault logged
|
|
8
|
+
|
|
9
|
+
<constraints>
|
|
10
|
+
Always do:
|
|
11
|
+
- Give every hook and gate a `--selftest` that plants its fault, and run it from the project's plants script (the `plants` command in `.claude/layout.json`). A new gate goes in there in the same commit. A gate that has never been seen red proves nothing.
|
|
12
|
+
- Log a workflow fault (a hook, a tool, the build queue, a test run) in `workflow-bugs.md` before fixing it (the `workflow-bugs` skill), and close it with cause, fix and what now catches it.
|
|
13
|
+
- Run Python on files that come from outside with `-I`. Measure files with Python, not with BSD or GNU tool flags.
|
|
14
|
+
- Keep a planted fault in the test build only: one macro or `constexpr` flag that is false in the shipped binary, and a release gate that searches the binary for it (`cpp-faults-only-in-the-test-build`).
|
|
15
|
+
- Treat a hook that blocks correct work as a red check: stop, report its exact message, and log it. The hook is fixed first, with a selftest that plants the right case and the wrong one; the work resumes after.
|
|
16
|
+
- Make a fix to a hook, rule, check or skill that every synth uses in claude-packs, with its test, then take it in with `npx --no-install @thedecipherist/claude-packs update`. Only a law that is about this project alone stays in this project's `.claude/`.
|
|
17
|
+
|
|
18
|
+
Never do:
|
|
19
|
+
- Route around a block: no code put into an unrelated existing file, no file pushed past the line limit, no write through the shell after a refusal, no override variable.
|
|
20
|
+
- Change a hook so that its own selftest passes while the fault it exists for gets through.
|
|
21
|
+
</constraints>
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
---
|
|
2
|
+
# hook: time-guard.mjs
|
|
3
|
+
---
|
|
4
|
+
# Long work runs in the background, and a warning about time is acted on
|
|
5
|
+
|
|
6
|
+
<constraints>
|
|
7
|
+
Always do:
|
|
8
|
+
- Start anything over about two minutes as a background job with its output in a file; you are told when it ends. Do other work meanwhile.
|
|
9
|
+
- When `time-guard` says something is slow, look at it now: find what is running, say so, and stop it if it is not needed.
|
|
10
|
+
- Commit an agent's work when `time-guard` says it has gone unsaved.
|
|
11
|
+
|
|
12
|
+
Never do:
|
|
13
|
+
- Wait in a `sleep`, `until` or `pgrep` loop, or poll a job's output file.
|
|
14
|
+
- Start a second copy of a job that is still running, or start it again without reading why the first one ended.
|
|
15
|
+
- Treat a slow job as normal because the last one was slow too.
|
|
16
|
+
</constraints>
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
---
|
|
2
|
+
# concepts: cpp
|
|
3
|
+
---
|
|
4
|
+
|
|
5
|
+
# Time and keys come from synthcore: one clock, written once
|
|
6
|
+
|
|
7
|
+
<constraints>
|
|
8
|
+
Always do:
|
|
9
|
+
- Link `synthcore` for tempo, MIDI clock, transport, sync modes, QWERTY and the focus rule. Subclass `core::CoreHost`, and make `host.readTransport (getPlayHead(), midi, n);` the second line of `processBlock`, after `ScopedNoDenormals`.
|
|
10
|
+
- Have every tempo-synced thing read the one master clock. Tap tempo sets the same `bpm` parameter the clock reads.
|
|
11
|
+
- Fix a fault in the clock in `synthcore`, once, with its test, and take it in everywhere.
|
|
12
|
+
|
|
13
|
+
Never do:
|
|
14
|
+
- Read the play head, count MIDI clock bytes or work out a tempo in a unit. `timing-from-synthcore` refuses it.
|
|
15
|
+
- Copy `synthcore`'s code into a unit, or write a second clock because one thing needs it.
|
|
16
|
+
</constraints>
|
|
@@ -0,0 +1,125 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: build-step
|
|
3
|
+
description: Use when work begins on a step of a synth's build.md, when a step's "done when" may be met, when a session starts or ends in a repo with a build.md, or when someone asks where the build is. Also /build-step.
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# One build step: its own branch, from start to merge
|
|
7
|
+
|
|
8
|
+
The canonical text is the repo's own `build.md` ("Rules for this file") and its `CLAUDE.md`. This file is the operating
|
|
9
|
+
summary. Where they disagree, the repo wins. The step tool is the project's (the `step` command in `.claude/layout.json`,
|
|
10
|
+
usually `python3 tools/step.py`); if the repo has none, copy `tools/step.py` and `tools/hooks/` from a sibling synth that
|
|
11
|
+
has them before doing any of this by hand.
|
|
12
|
+
|
|
13
|
+
The house rule: **every build task is built in a new branch. Once completed it is merged into the
|
|
14
|
+
trunk. We must not be able to lose any work.** MegaSynth lost two days of panel work to one checkout, more to work nobody
|
|
15
|
+
had written down as started, and more to steps called done because the code compiled. A step is a promise with a
|
|
16
|
+
measurement on the end, and a pushed branch is what a dead session leaves behind.
|
|
17
|
+
|
|
18
|
+
## 0. Before acting on a paste from the user
|
|
19
|
+
|
|
20
|
+
- If the project's spec carries an edition line ("Spec edition: ..." at the top of `docs/*-spec.md`) and the paste names an
|
|
21
|
+
edition, check the file shows it. Older, or no line: **stop and say so**, naming both editions.
|
|
22
|
+
- Every file a paste names must be there. One missing or older: **stop and tell the user**, naming the file and what was found;
|
|
23
|
+
do not carry on with the parts that do not depend on it.
|
|
24
|
+
|
|
25
|
+
## 1. At the start of a session
|
|
26
|
+
|
|
27
|
+
```
|
|
28
|
+
python3 tools/step.py status
|
|
29
|
+
```
|
|
30
|
+
|
|
31
|
+
It prints the count, the current step, the branch you are on, uncommitted changes and every branch not yet merged, with
|
|
32
|
+
its last commit. An unmerged branch is unfinished work: read its last commit message and its In-progress row before
|
|
33
|
+
starting anything else. Read `bugs.md`'s Open table too.
|
|
34
|
+
|
|
35
|
+
**If the work in front of you is not a step in build.md, stop and ask the user whether the plan has changed.** A bug fix or a
|
|
36
|
+
change of plan the user has agreed goes on `start --work <name> "task"` and is merged with `land`.
|
|
37
|
+
|
|
38
|
+
## 2. Start: the branch comes first
|
|
39
|
+
|
|
40
|
+
```
|
|
41
|
+
python3 tools/step.py start <STEP> "<the task, smaller than the step>"
|
|
42
|
+
```
|
|
43
|
+
|
|
44
|
+
This makes the step's branch from the trunk, writes the task under "In progress" with its start time (date, time, zone),
|
|
45
|
+
commits and pushes the branch. Nothing is committed straight onto the trunk; `git-guard` refuses it.
|
|
46
|
+
|
|
47
|
+
Read the step's "done when" now and decide how it will be measured. If it cannot be measured or seen in the opened app,
|
|
48
|
+
say so before building.
|
|
49
|
+
|
|
50
|
+
### The shape comes first (KWB-1)
|
|
51
|
+
|
|
52
|
+
Before any code, name every concept the step touches and find its row in `design/shape.json` (ONE with its frozen id, or
|
|
53
|
+
MANY with its count, generator, selectors and declared constants).
|
|
54
|
+
|
|
55
|
+
- **A concept the step introduces gets its row first, as the step's first commit** (`step.py save "shape: <concept> row"`
|
|
56
|
+
with only `design/shape.json` in it), before any code that uses it. `shape-law` refuses an instance type with no row.
|
|
57
|
+
- Build for the shape: one loop over every instance, or the generator. Test the behaviour once, on the template (`test-the-template-once`). An instance a bug was seen in goes on a `seen in:`
|
|
58
|
+
line; a rule that picks one is a selector listed in the row; a fixed one is a named constant there. Anything else is
|
|
59
|
+
refused with "example, rule, or constant?".
|
|
60
|
+
- **Every subagent brief quotes the manifest row of every concept it touches, word for word**, and names the shape and
|
|
61
|
+
the generator, never an instance (`brief-guard` refuses "drive slot 2"; "seen in: slot 2, build for all slots" passes).
|
|
62
|
+
- `npx --no-install @thedecipherist/claude-packs shape scan` lists what the repo already names by instance; a step that touches such a file fixes its
|
|
63
|
+
lines or leaves them as they were, never adds to them.
|
|
64
|
+
|
|
65
|
+
## 3. While working: save often
|
|
66
|
+
|
|
67
|
+
```
|
|
68
|
+
python3 tools/step.py save "<what state it is in>" [--paths <new files>]
|
|
69
|
+
```
|
|
70
|
+
|
|
71
|
+
Commits everything changed and pushes the branch. Run it after every unit of work, before any risky command, and
|
|
72
|
+
**always before a session ends**, saying if the work was interrupted and what is half done. It lists new files it was not
|
|
73
|
+
told about; name them or ignore them, never leave them floating.
|
|
74
|
+
|
|
75
|
+
- A bug goes into `bugs.md` the moment it is found, before it is fixed.
|
|
76
|
+
- A red tripwire gate stops all other work.
|
|
77
|
+
- Steps that run side by side each have their own branch. Switch with `start`; it refuses to switch over uncommitted work.
|
|
78
|
+
|
|
79
|
+
## 4. Is it done?
|
|
80
|
+
|
|
81
|
+
```
|
|
82
|
+
python3 tools/step.py check
|
|
83
|
+
```
|
|
84
|
+
|
|
85
|
+
It runs the mechanical checks and prints the repo's "Runs through every step" list to walk by eye. Run the project's
|
|
86
|
+
plants script (the `plants` command) before ticking: every planted fault red. Then the step's own "done when":
|
|
87
|
+
|
|
88
|
+
- **Measured or seen in the opened app.** Rebuilt, opened, pressed. Not "wired", not "compiles", not "the test I just
|
|
89
|
+
wrote passes".
|
|
90
|
+
- A gate that passed first time is suspect. Plant the fault it exists to catch and watch it fail.
|
|
91
|
+
- Say which artefact was checked: the standalone, a probe, a picture the app rendered itself.
|
|
92
|
+
|
|
93
|
+
If any part is not met, the step is not done. Say which part, `save`, and keep working or ask. The branch stays open;
|
|
94
|
+
that is what it is for.
|
|
95
|
+
|
|
96
|
+
## 5. Finish: merge into the trunk
|
|
97
|
+
|
|
98
|
+
```
|
|
99
|
+
python3 tools/step.py finish <STEP> --proof "<what was measured, with numbers>" [--paths <new files>]
|
|
100
|
+
```
|
|
101
|
+
|
|
102
|
+
On the step's branch. It brings the trunk into the branch first, ticks and dates the step, moves its In-progress row to
|
|
103
|
+
the log with the finish time and what the step took, updates "Where we are" and the count, commits, merges into the trunk
|
|
104
|
+
with a merge commit, writes that commit's short hash into the log line in a second commit, and pushes the trunk and the
|
|
105
|
+
branch.
|
|
106
|
+
|
|
107
|
+
It refuses an empty proof, a step that is not the current one (side-by-side steps take `--out-of-order`), and unnamed new
|
|
108
|
+
files. If a merge conflicts it stops with both sides intact: resolve by hand, never by throwing a side away, and ask the user
|
|
109
|
+
if it is not obvious which line is right. If it prints NOT PUSHED, push with the command it shows. A step is not finished
|
|
110
|
+
until the trunk is pushed.
|
|
111
|
+
|
|
112
|
+
## 6. Tell the user
|
|
113
|
+
|
|
114
|
+
Conclusion first, in plain language: the step, what proved it, the new count, the next step. Show the changed `build.md`.
|
|
115
|
+
Never claim a step works that has not been built, opened and measured.
|
|
116
|
+
|
|
117
|
+
## Never
|
|
118
|
+
|
|
119
|
+
- Delete a branch, here or on GitHub. Rebase, amend, squash or force-push. `git add -A`.
|
|
120
|
+
- `checkout`, `restore`, `stash` or `reset --hard` over uncommitted work. `save` first.
|
|
121
|
+
- Commit straight onto the trunk. Pass `--no-verify`.
|
|
122
|
+
- Delete a step from build.md: strike it through with the reason and the date. A reopened step keeps its line, marked
|
|
123
|
+
REOPENED.
|
|
124
|
+
- Tick from memory of an earlier session. Measure again.
|
|
125
|
+
- Soften a red test in a commit message.
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: build-through-the-queue
|
|
3
|
+
description: Use when about to compile, run ctest, or run a program from a build folder, or when build-guard refused a command.
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# Build through the queue (one job: no build takes the whole machine)
|
|
7
|
+
|
|
8
|
+
<constraints>
|
|
9
|
+
Always do:
|
|
10
|
+
1. Use the project's wrapper first: the `build` and `test` commands in `.claude/layout.json`. Otherwise run `node .claude/tools/buildq.mjs <command>`.
|
|
11
|
+
2. The queue runs two at a time and waits for a slot by itself; `--status` shows the slots. Run it in the foreground, or as a background job.
|
|
12
|
+
3. As an agent, build only the targets the change needs (`--target X --target Y`) and run only its tests (`-R 'pattern'`, at most 30).
|
|
13
|
+
4. An agent started as `KIND: light` does not build or run tests: do the light part, and say in the report what needs building.
|
|
14
|
+
|
|
15
|
+
5. End a build's command with the build's own status. A background job reports its last command's status: a build followed by `echo` or `tail` reports theirs, and a stale binary reads as a pass. Keep the output in a file and read the build's exit.
|
|
16
|
+
|
|
17
|
+
Never do:
|
|
18
|
+
- Run `cmake --build`, `ctest`, `make`, `ninja`, `xcodebuild`, or a program from a build folder straight from the shell.
|
|
19
|
+
- Wrap a build in a wait loop.
|
|
20
|
+
- Build every target from an agent: the whole build runs once, before landing.
|
|
21
|
+
</constraints>
|
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
// buildq: the machine-wide build queue that build-guard sends every heavy job to (KF-1: the hook named a tool no pack shipped). Two jobs at a time, across every
|
|
3
|
+
// project on the machine; a job waits for a slot by itself. A slot is a folder made atomically, holding its owner's pid; a dead owner's slot is taken back.
|
|
4
|
+
// The exit status is the command's own, so `node .claude/tools/buildq.mjs ninja && next` means what it says. A status read after a pipe or an echo is theirs, not the build's (KF-37).
|
|
5
|
+
// node .claude/tools/buildq.mjs <command> [args...] run it in the next free slot
|
|
6
|
+
// node .claude/tools/buildq.mjs --status how many slots are taken
|
|
7
|
+
// BUILDQ_DIR: where the slots live (default: the machine's temp folder). BUILDQ_SLOTS: how many (default 2).
|
|
8
|
+
import { spawnSync } from 'node:child_process';
|
|
9
|
+
import { mkdirSync, readFileSync, rmSync, writeFileSync } from 'node:fs';
|
|
10
|
+
import { tmpdir } from 'node:os';
|
|
11
|
+
import { join } from 'node:path';
|
|
12
|
+
|
|
13
|
+
const DIR = process.env.BUILDQ_DIR ?? join(tmpdir(), 'claude-packs-buildq');
|
|
14
|
+
const SLOTS = Number(process.env.BUILDQ_SLOTS ?? 2);
|
|
15
|
+
const WAIT_MS = 500;
|
|
16
|
+
const slotAt = (n) => join(DIR, `slot-${n}`);
|
|
17
|
+
const nap = (ms) => Atomics.wait(new Int32Array(new SharedArrayBuffer(4)), 0, 0, ms);
|
|
18
|
+
|
|
19
|
+
function ownerOf(slot) {
|
|
20
|
+
try { return Number(readFileSync(join(slot, 'pid'), 'utf8')); } catch { return null; }
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
function isLive(slot) {
|
|
24
|
+
const pid = ownerOf(slot);
|
|
25
|
+
if (pid === null) return false;
|
|
26
|
+
try {
|
|
27
|
+
process.kill(pid, 0);
|
|
28
|
+
return true;
|
|
29
|
+
} catch (e) {
|
|
30
|
+
return e.code === 'EPERM'; // another user's job holds it
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
function claim() {
|
|
35
|
+
mkdirSync(DIR, { recursive: true });
|
|
36
|
+
for (let n = 0; n < SLOTS; n += 1) {
|
|
37
|
+
const slot = slotAt(n);
|
|
38
|
+
try {
|
|
39
|
+
mkdirSync(slot);
|
|
40
|
+
writeFileSync(join(slot, 'pid'), `${process.pid}\n`);
|
|
41
|
+
return slot;
|
|
42
|
+
} catch (e) {
|
|
43
|
+
if (e.code !== 'EEXIST') throw e;
|
|
44
|
+
if (ownerOf(slot) !== null && !isLive(slot)) rmSync(slot, { recursive: true, force: true });
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
return null;
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
function status() {
|
|
51
|
+
const taken = Array.from({ length: SLOTS }, (_, n) => slotAt(n)).filter(isLive).length;
|
|
52
|
+
console.log(`${taken} of ${SLOTS} slots taken`);
|
|
53
|
+
return 0;
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
function run(command) {
|
|
57
|
+
let slot = claim();
|
|
58
|
+
for (; slot === null; slot = claim()) nap(WAIT_MS);
|
|
59
|
+
try {
|
|
60
|
+
const r = spawnSync(command[0], command.slice(1), { stdio: 'inherit' });
|
|
61
|
+
if (r.error) console.error(`buildq: ${command[0]}: ${r.error.message}`);
|
|
62
|
+
return r.status ?? 1;
|
|
63
|
+
} finally {
|
|
64
|
+
rmSync(slot, { recursive: true, force: true });
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
const args = process.argv.slice(2);
|
|
69
|
+
if (args[0] === '--status') process.exit(status());
|
|
70
|
+
if (!args.length) {
|
|
71
|
+
console.error('usage: node .claude/tools/buildq.mjs <command> [args...] | --status');
|
|
72
|
+
process.exit(2);
|
|
73
|
+
}
|
|
74
|
+
process.exit(run(args));
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
// Freeze the files that define "fixed" before changing the code that must satisfy them.
|
|
3
|
+
// node .claude/tools/freeze.mjs on "<reason>" <file-or-glob>...
|
|
4
|
+
// node .claude/tools/freeze.mjs off
|
|
5
|
+
// node .claude/tools/freeze.mjs status
|
|
6
|
+
// The frozen-files hook refuses edits to anything on the list until it is turned off.
|
|
7
|
+
import { existsSync, mkdirSync, readFileSync, rmSync, writeFileSync } from 'node:fs';
|
|
8
|
+
import { join } from 'node:path';
|
|
9
|
+
|
|
10
|
+
const ROOT = process.env.CLAUDE_PROJECT_DIR ?? process.cwd();
|
|
11
|
+
const STATE = join(ROOT, '.claude', 'state', 'frozen.json');
|
|
12
|
+
const [cmd, reason, ...files] = process.argv.slice(2);
|
|
13
|
+
|
|
14
|
+
const USAGE = 'usage: freeze.mjs on "<reason>" <files...> | off | status';
|
|
15
|
+
|
|
16
|
+
function on() {
|
|
17
|
+
if (!reason || files.length === 0) {
|
|
18
|
+
console.error('usage: freeze.mjs on "<reason>" <file-or-glob>...');
|
|
19
|
+
return 2;
|
|
20
|
+
}
|
|
21
|
+
mkdirSync(join(ROOT, '.claude', 'state'), { recursive: true });
|
|
22
|
+
const prev = existsSync(STATE) ? JSON.parse(readFileSync(STATE, 'utf8')).files ?? [] : [];
|
|
23
|
+
const all = [...new Set([...prev, ...files])];
|
|
24
|
+
writeFileSync(STATE, `${JSON.stringify({ reason, files: all, since: new Date().toISOString() }, null, 2)}\n`);
|
|
25
|
+
console.log(`frozen (${reason}):\n${all.map((f) => ` ${f}`).join('\n')}`);
|
|
26
|
+
return 0;
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
const COMMANDS = {
|
|
30
|
+
on,
|
|
31
|
+
off: () => (rmSync(STATE, { force: true }), console.log('nothing frozen'), 0),
|
|
32
|
+
status: () => (console.log(existsSync(STATE) ? readFileSync(STATE, 'utf8') : 'nothing frozen'), 0),
|
|
33
|
+
};
|
|
34
|
+
|
|
35
|
+
const run = Object.hasOwn(COMMANDS, cmd) ? COMMANDS[cmd] : () => (console.error(USAGE), 2);
|
|
36
|
+
process.exit(run());
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
{
|
|
2
|
+
"id": "tui-entry-restores-terminal",
|
|
3
|
+
"why": "Entering the alternate screen or raw mode without an exit handler that restores them strands the user in a broken terminal after a crash. process.once('exit', restore), registered before the first render.",
|
|
4
|
+
"rule": ".claude/rules/tui-resize-and-screen.md",
|
|
5
|
+
"concepts": [
|
|
6
|
+
"tui",
|
|
7
|
+
"tui-entry"
|
|
8
|
+
],
|
|
9
|
+
"exclude": [
|
|
10
|
+
"**/node_modules/**",
|
|
11
|
+
"**/dist/**",
|
|
12
|
+
"**/build/**",
|
|
13
|
+
".claude/**",
|
|
14
|
+
"**/.claude/**",
|
|
15
|
+
"**/*.test.*",
|
|
16
|
+
"**/test/**"
|
|
17
|
+
],
|
|
18
|
+
"code": false,
|
|
19
|
+
"mode": "needs",
|
|
20
|
+
"pattern": "\\?1049h|setRawMode\\s*\\(\\s*true\\s*\\)",
|
|
21
|
+
"needs": [
|
|
22
|
+
"\\?1049l|setRawMode\\s*\\(\\s*(?:false|wasRaw|prev\\w*|was\\w*)\\s*\\)",
|
|
23
|
+
"process\\.(?:once|on)\\s*\\(\\s*['\\\"](?:exit|SIGINT)['\\\"]"
|
|
24
|
+
],
|
|
25
|
+
"bad": "process.stdout.write('\\x1B[?1049h\\x1B[?25l');\nconst { waitUntilExit } = render(<App />);",
|
|
26
|
+
"good": "process.stdout.write('\\x1B[?1049h\\x1B[?25l');\nconst restore = () => process.stdout.write('\\x1B[?25h\\x1B[?1049l');\nprocess.once('exit', restore);\nconst { waitUntilExit } = render(<App />);"
|
|
27
|
+
}
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
{
|
|
2
|
+
"id": "tui-gates-on-tty",
|
|
3
|
+
"why": "A TUI started on a non-TTY stdout (CI, a pipe, a log) writes escape codes into the log and reads stdin that never answers. Gate on isTTY and a minimum size, fall back to plain output.",
|
|
4
|
+
"rule": ".claude/rules/tui-resize-and-screen.md",
|
|
5
|
+
"concepts": [
|
|
6
|
+
"tui-entry"
|
|
7
|
+
],
|
|
8
|
+
"exclude": [
|
|
9
|
+
"**/node_modules/**",
|
|
10
|
+
"**/dist/**",
|
|
11
|
+
"**/build/**",
|
|
12
|
+
".claude/**",
|
|
13
|
+
"**/.claude/**",
|
|
14
|
+
"**/*.test.*",
|
|
15
|
+
"**/test/**"
|
|
16
|
+
],
|
|
17
|
+
"code": false,
|
|
18
|
+
"mode": "needs",
|
|
19
|
+
"pattern": "\\?1049h|setRawMode\\s*\\(\\s*true\\s*\\)|\\brender\\s*\\(\\s*<",
|
|
20
|
+
"needs": [
|
|
21
|
+
"\\bisTTY\\b"
|
|
22
|
+
],
|
|
23
|
+
"bad": "process.stdout.write('\\x1B[?1049h');\nrender(<App />);",
|
|
24
|
+
"good": "if (!process.stdin.isTTY || !process.stdout.isTTY) return printPlain(report);\nprocess.stdout.write('\\x1B[?1049h');\nrender(<App />);"
|
|
25
|
+
}
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
{
|
|
2
|
+
"id": "tui-no-ris-reset",
|
|
3
|
+
"why": "\\x1Bc (RIS) resets the whole terminal: colours, font, cursor settings, and behaves differently per emulator. Clear with \\x1B[2J\\x1B[H.",
|
|
4
|
+
"rule": ".claude/rules/tui-resize-and-screen.md",
|
|
5
|
+
"concepts": [
|
|
6
|
+
"tui",
|
|
7
|
+
"tui-entry"
|
|
8
|
+
],
|
|
9
|
+
"exclude": [
|
|
10
|
+
"**/node_modules/**",
|
|
11
|
+
"**/dist/**",
|
|
12
|
+
"**/build/**",
|
|
13
|
+
".claude/**",
|
|
14
|
+
"**/.claude/**",
|
|
15
|
+
"**/*.test.*",
|
|
16
|
+
"**/test/**"
|
|
17
|
+
],
|
|
18
|
+
"code": false,
|
|
19
|
+
"pattern": "\\\\x1[bB]c(?![0-9A-Za-z])|\\\\u001[bB]c(?![0-9A-Za-z])|\\\\033c(?![0-9A-Za-z])",
|
|
20
|
+
"bad": "process.stdout.write('\\x1Bc');",
|
|
21
|
+
"good": "process.stdout.write('\\x1B[2J\\x1B[H');"
|
|
22
|
+
}
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
{
|
|
2
|
+
"id": "tui-resize-listener-removed",
|
|
3
|
+
"why": "A resize listener that is never removed keeps rendering into a terminal the TUI has left, over the shell prompt. Every process.stdout.on('resize') has its off() on exit.",
|
|
4
|
+
"rule": ".claude/rules/tui-resize-and-screen.md",
|
|
5
|
+
"concepts": [
|
|
6
|
+
"tui",
|
|
7
|
+
"tui-entry"
|
|
8
|
+
],
|
|
9
|
+
"exclude": [
|
|
10
|
+
"**/node_modules/**",
|
|
11
|
+
"**/dist/**",
|
|
12
|
+
"**/build/**",
|
|
13
|
+
".claude/**",
|
|
14
|
+
"**/.claude/**",
|
|
15
|
+
"**/*.test.*",
|
|
16
|
+
"**/test/**"
|
|
17
|
+
],
|
|
18
|
+
"code": false,
|
|
19
|
+
"mode": "needs",
|
|
20
|
+
"pattern": "process\\.stdout\\.on\\s*\\(\\s*['\\\"]resize['\\\"]",
|
|
21
|
+
"needs": [
|
|
22
|
+
"process\\.stdout\\.(?:off|removeListener)\\s*\\(\\s*['\\\"]resize['\\\"]"
|
|
23
|
+
],
|
|
24
|
+
"bad": "process.stdout.on('resize', onResize);",
|
|
25
|
+
"good": "process.stdout.on('resize', onResize);\nconst exit = () => { process.stdout.off('resize', onResize); };"
|
|
26
|
+
}
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
{
|
|
2
|
+
"id": "tui-width-is-state",
|
|
3
|
+
"why": "A value computed from process.stdout.columns at render time keeps its old width after a resize until the next keypress. In a React/Ink component the width is state updated by the resize handler.",
|
|
4
|
+
"rule": ".claude/rules/tui-resize-and-screen.md",
|
|
5
|
+
"globs": [
|
|
6
|
+
"**/*.tsx"
|
|
7
|
+
],
|
|
8
|
+
"concepts": [
|
|
9
|
+
"tui"
|
|
10
|
+
],
|
|
11
|
+
"exclude": [
|
|
12
|
+
"**/node_modules/**",
|
|
13
|
+
"**/dist/**",
|
|
14
|
+
"**/build/**",
|
|
15
|
+
".claude/**",
|
|
16
|
+
"**/.claude/**",
|
|
17
|
+
"**/*.test.*",
|
|
18
|
+
"**/test/**",
|
|
19
|
+
"**/bin/**",
|
|
20
|
+
"**/cli.tsx",
|
|
21
|
+
"**/index.tsx",
|
|
22
|
+
"**/main.tsx"
|
|
23
|
+
],
|
|
24
|
+
"code": false,
|
|
25
|
+
"mode": "needs",
|
|
26
|
+
"pattern": "process\\.stdout\\.columns",
|
|
27
|
+
"needs": [
|
|
28
|
+
"\\buseState\\s*\\(",
|
|
29
|
+
"['\\\"]resize['\\\"]"
|
|
30
|
+
],
|
|
31
|
+
"bad": "const divider = '\\u2500'.repeat(process.stdout.columns ?? 80);",
|
|
32
|
+
"good": "const [termWidth, setTermWidth] = useState(process.stdout.columns ?? 80);\nuseEffect(() => { const on = () => setTermWidth(process.stdout.columns ?? 80); process.stdout.on('resize', on); return () => { process.stdout.off('resize', on); }; }, []);"
|
|
33
|
+
}
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "tui",
|
|
3
|
+
"version": "1.0.0",
|
|
4
|
+
"description": "Terminal UIs (Ink + React or raw-mode Node): alternate screen, resize ordering, width as state, raw mode restored on every exit.",
|
|
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/tui"
|
|
13
|
+
},
|
|
14
|
+
"keywords": [
|
|
15
|
+
"terminal",
|
|
16
|
+
"tui"
|
|
17
|
+
],
|
|
18
|
+
"engines": {
|
|
19
|
+
"claude-packs": ">=0.19.0"
|
|
20
|
+
},
|
|
21
|
+
"folders": {},
|
|
22
|
+
"concepts": {
|
|
23
|
+
"tui": [
|
|
24
|
+
"**/tui/**",
|
|
25
|
+
"**/*tui*",
|
|
26
|
+
"**/*.tui.*",
|
|
27
|
+
"**/ui/**/*.tsx",
|
|
28
|
+
"**/cli/**/*.tsx",
|
|
29
|
+
"**/ui/browse*",
|
|
30
|
+
"**/ui/screen*",
|
|
31
|
+
"**/screens/**"
|
|
32
|
+
],
|
|
33
|
+
"tui-entry": [
|
|
34
|
+
"**/bin/**",
|
|
35
|
+
"**/cli.ts",
|
|
36
|
+
"**/cli.tsx",
|
|
37
|
+
"**/index.tsx",
|
|
38
|
+
"**/main.tsx",
|
|
39
|
+
"**/tui/index.*"
|
|
40
|
+
]
|
|
41
|
+
},
|
|
42
|
+
"skillsIn": null,
|
|
43
|
+
"hooks": {}
|
|
44
|
+
}
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
---
|
|
2
|
+
# concepts: tui, tui-entry
|
|
3
|
+
paths:
|
|
4
|
+
- "placeholder"
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
# A TUI owns the alternate screen, clears before the framework draws, and treats size as state
|
|
8
|
+
|
|
9
|
+
Every resize bug is one root cause: the renderer diffs its previous output and repositions the cursor, it does not clear and redraw. On resize, content it no longer owns stays visible, the cursor lands somewhere unknown, and a taller terminal re-reveals old scrollback lines.
|
|
10
|
+
|
|
11
|
+
<constraints>
|
|
12
|
+
Always do:
|
|
13
|
+
- **Alternate screen from the entry point**: `process.stdout.write('\x1B[?1049h\x1B[?25l')` before the first render; restore with `'\x1B[?25h\x1B[?1049l'` in a `process.once('exit', …)` handler registered **before** rendering, so the terminal comes back even on a crash (`tui-entry-restores-terminal`).
|
|
14
|
+
- **Clear handler registered in the entry point before `render()`**: `process.stdout.on('resize', () => process.stdout.write('\x1B[2J\x1B[H'))`. Node fires resize listeners in registration order; Ink registers its own inside `render()`, so a clear registered in a `useEffect` runs after Ink has drawn and blanks the screen until the next keypress.
|
|
15
|
+
- **Width is state**: `const [cols, setCols] = useState(process.stdout.columns ?? 80)` in the root component, updated by a resize handler that does nothing else. A divider computed once from `process.stdout.columns` keeps its old width until the next keypress (`tui-width-is-state`).
|
|
16
|
+
- Correct resize order, one job each: 1 entry-point clear, 2 the framework's layout, 3 the state update that re-renders width-dependent lines.
|
|
17
|
+
- Raw-mode TUIs (no framework): gate on `process.stdin.isTTY && process.stdout.isTTY` and a minimum size, fall back to plain output otherwise; `setRawMode(true)` is paired with a restore of the previous raw state; one idempotent `exit()` (an `exited` flag) that removes the resize and data listeners, restores raw mode, shows the cursor and leaves the alternate screen; SIGINT routes through the same `exit()`.
|
|
18
|
+
- Remove every `resize`/`data` listener on exit (`process.stdout.off`, `process.stdin.off`).
|
|
19
|
+
|
|
20
|
+
Never do:
|
|
21
|
+
- `\x1Bc` (RIS, reset to initial state): it resets colours, font and cursor settings and differs per emulator (`tui-no-ris-reset`). `\x1B[2J\x1B[H` only.
|
|
22
|
+
- Escape codes written from a component's render path; they fight the framework's output buffer. Effects and the entry point only.
|
|
23
|
+
- Resize logic split across several handlers that each clear, draw or set state.
|
|
24
|
+
- A TUI on a non-TTY stdout (CI, a pipe): the escape codes become garbage in the log.
|
|
25
|
+
</constraints>
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: build-tui
|
|
3
|
+
description: Use when building or changing an interactive terminal UI (Ink + React, or raw-mode Node with @clack/prompts), or when a TUI shows ghost or repeated content, a blank screen after resize, a divider stuck at the old width, or a terminal left in a broken state after exit.
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# build-tui
|
|
7
|
+
|
|
8
|
+
One thing: scaffold or repair a TUI's entry point and root so the `tui-resize-and-screen` rule holds, then prove it with a resize.
|
|
9
|
+
|
|
10
|
+
<constraints>
|
|
11
|
+
Always do:
|
|
12
|
+
1. Entry point, in this order: TTY and size gate (fallback to plain output when `!isTTY` or under 60×12) → enter alternate screen and hide the cursor → `process.once('exit', restore)` → `process.stdout.on('resize', clear)` → `render()` (Ink) or the raw-mode loop → on exit: `off` every listener, restore raw mode, show cursor, leave the alternate screen. One idempotent `exit()` used by the normal path and SIGINT.
|
|
13
|
+
2. Root component (Ink): `termWidth` as state from `process.stdout.columns`, updated by a resize handler that only sets state; every width-dependent string derives from it.
|
|
14
|
+
3. Raw mode (no framework): `setRawMode(true)` after saving `stdin.isRaw`; a single `data` handler mapping keys through a lookup table (`{ q: quit, j: down, k: up, … }`), never an if-chain; `render(state)` is the only function that writes to stdout.
|
|
15
|
+
4. Prove it: run the TUI in a pty (`node-pty` or `script -q`), send a resize (`SIGWINCH` after changing `columns`/`rows`), and assert the frame has no repeated banner, no stale divider width, and that after quit the terminal is out of the alternate screen (`\x1B[?1049l` was written).
|
|
16
|
+
5. Check versions with `latest-versions` (`ink`, `react`, `@clack/prompts`) before adding them.
|
|
17
|
+
|
|
18
|
+
Never do:
|
|
19
|
+
- Fix a resize bug by adding another clear somewhere; find which of the three handlers is out of order.
|
|
20
|
+
- Ship without the `process.once('exit', …)` restore.
|
|
21
|
+
</constraints>
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
{
|
|
2
|
+
"id": "ui-input-needs-autocomplete",
|
|
3
|
+
"why": "An email, password or phone field with no autocomplete makes everyone type it by hand.",
|
|
4
|
+
"rule": ".claude/rules/forms-never-fight.md",
|
|
5
|
+
"concepts": [
|
|
6
|
+
"ui-markup"
|
|
7
|
+
],
|
|
8
|
+
"globs": [],
|
|
9
|
+
"exclude": [
|
|
10
|
+
"**/node_modules/**",
|
|
11
|
+
"**/dist/**",
|
|
12
|
+
"**/build/**",
|
|
13
|
+
".claude/**",
|
|
14
|
+
"**/.claude/**",
|
|
15
|
+
"**/*.test.*",
|
|
16
|
+
"**/*.spec.*"
|
|
17
|
+
],
|
|
18
|
+
"pattern": "<input\\b(?![^>]*\\bautocomplete)[^>]*\\btype=[\"'{]*(?:email|password|tel)\\b",
|
|
19
|
+
"bad": "<input type=\"email\" name=\"email\" />\n",
|
|
20
|
+
"good": "<input type=\"email\" name=\"email\" autoComplete=\"email\" />\n",
|
|
21
|
+
"flags": "i",
|
|
22
|
+
"kind": "quality"
|
|
23
|
+
}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
{
|
|
2
|
+
"id": "ui-intl-for-dates",
|
|
3
|
+
"why": "A date built from its parts is wrong for most of the world. Use Intl.DateTimeFormat.",
|
|
4
|
+
"rule": ".claude/rules/dates-and-numbers.md",
|
|
5
|
+
"concepts": [
|
|
6
|
+
"ui-markup"
|
|
7
|
+
],
|
|
8
|
+
"globs": [],
|
|
9
|
+
"exclude": [
|
|
10
|
+
"**/node_modules/**",
|
|
11
|
+
"**/dist/**",
|
|
12
|
+
"**/build/**",
|
|
13
|
+
".claude/**",
|
|
14
|
+
"**/.claude/**",
|
|
15
|
+
"**/*.test.*",
|
|
16
|
+
"**/*.spec.*"
|
|
17
|
+
],
|
|
18
|
+
"pattern": "\\.getMonth\\(\\)\\s*\\+\\s*1\\b",
|
|
19
|
+
"bad": "const d = `${t.getMonth() + 1}/${t.getDate()}`;\n",
|
|
20
|
+
"good": "const d = new Intl.DateTimeFormat(locale).format(t);\n"
|
|
21
|
+
}
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
{
|
|
2
|
+
"id": "ui-no-ai-palette",
|
|
3
|
+
"why": "Purple and violet gradients are the most recognizable tell of generated UI. Use the project's palette.",
|
|
4
|
+
"rule": ".claude/rules/no-generated-look.md",
|
|
5
|
+
"concepts": [
|
|
6
|
+
"ui-markup",
|
|
7
|
+
"ui-styles"
|
|
8
|
+
],
|
|
9
|
+
"globs": [],
|
|
10
|
+
"exclude": [
|
|
11
|
+
"**/node_modules/**",
|
|
12
|
+
"**/dist/**",
|
|
13
|
+
"**/build/**",
|
|
14
|
+
".claude/**",
|
|
15
|
+
"**/.claude/**",
|
|
16
|
+
"**/*.test.*",
|
|
17
|
+
"**/*.spec.*"
|
|
18
|
+
],
|
|
19
|
+
"pattern": "\\bfrom-(?:purple|violet|indigo|fuchsia)-\\d+\\b|linear-gradient\\([^)\\n]*\\b(?:purple|violet|indigo)\\b",
|
|
20
|
+
"bad": "<div className=\"bg-gradient-to-r from-purple-500 to-pink-500\" />\n",
|
|
21
|
+
"good": "<div className=\"bg-surface text-ink\" />\n"
|
|
22
|
+
}
|