claude-code-superkit 0.0.0-stage → 1.5.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -0
- package/README.md +374 -2
- package/bin/cli.js +153 -0
- package/bin/inject-tokens.js +224 -0
- package/bin/measure-tokens.js +17 -0
- package/bin/superkit-counts-verify.sh +30 -0
- package/lib/codex.js +246 -0
- package/lib/docs-scaffold.js +147 -0
- package/lib/installer.js +499 -0
- package/lib/prompts.js +51 -0
- package/lib/settings-builder.js +51 -0
- package/lib/superpowers.js +99 -0
- package/lib/utils.js +117 -0
- package/lib/validator.js +84 -0
- package/package.json +49 -4
- package/packages/codex/AGENTS.md +396 -0
- package/packages/codex/INSTALL.md +342 -0
- package/packages/codex/config.toml +22 -0
- package/packages/codex/hooks/superkit.mjs +203 -0
- package/packages/codex/hooks.json +30 -0
- package/packages/codex/legacy-baseline.json +88 -0
- package/packages/codex/native-skills.txt +65 -0
- package/packages/codex/rules/default.rules +565 -0
- package/packages/codex/skills/ai-slop-cleaner/SKILL.md +44 -0
- package/packages/codex/skills/api-contract-sync/SKILL.md +96 -0
- package/packages/codex/skills/architect/SKILL.md +49 -0
- package/packages/codex/skills/audit-backend/SKILL.md +80 -0
- package/packages/codex/skills/audit-frontend/SKILL.md +82 -0
- package/packages/codex/skills/audit-infra/SKILL.md +87 -0
- package/packages/codex/skills/audit-orchestrator/SKILL.md +114 -0
- package/packages/codex/skills/behavioral-nudge-engine/SKILL.md +110 -0
- package/packages/codex/skills/benchmark/SKILL.md +49 -0
- package/packages/codex/skills/bot-reviewer/SKILL.md +94 -0
- package/packages/codex/skills/code-reviewer/SKILL.md +67 -0
- package/packages/codex/skills/codebase-onboarding-engineer/SKILL.md +46 -0
- package/packages/codex/skills/comment-rot-analyzer/SKILL.md +75 -0
- package/packages/codex/skills/commit-helper/SKILL.md +101 -0
- package/packages/codex/skills/critic/SKILL.md +56 -0
- package/packages/codex/skills/database-reviewer/SKILL.md +79 -0
- package/packages/codex/skills/debug-observer/SKILL.md +107 -0
- package/packages/codex/skills/dependency-checker/SKILL.md +69 -0
- package/packages/codex/skills/design-system-reviewer/SKILL.md +121 -0
- package/packages/codex/skills/dev-orchestrator/SKILL.md +304 -0
- package/packages/codex/skills/docs-reviewer/SKILL.md +86 -0
- package/packages/codex/skills/drizzle-orm-expert/SKILL.md +246 -0
- package/packages/codex/skills/e2e-test-generator/SKILL.md +95 -0
- package/packages/codex/skills/evaluator/SKILL.md +63 -0
- package/packages/codex/skills/frontend-perf-reviewer/SKILL.md +95 -0
- package/packages/codex/skills/frontend-ui-color-reviewer/SKILL.md +68 -0
- package/packages/codex/skills/frontend-ui-design-critic/SKILL.md +99 -0
- package/packages/codex/skills/frontend-ui-interaction-reviewer/SKILL.md +102 -0
- package/packages/codex/skills/frontend-ui-motion-reviewer/SKILL.md +85 -0
- package/packages/codex/skills/frontend-ui-reviewer/SKILL.md +81 -0
- package/packages/codex/skills/frontend-ui-typography-reviewer/SKILL.md +62 -0
- package/packages/codex/skills/gltf-debugging/SKILL.md +128 -0
- package/packages/codex/skills/go-benchmark/SKILL.md +217 -0
- package/packages/codex/skills/go-concurrency-reviewer/SKILL.md +113 -0
- package/packages/codex/skills/go-error-reviewer/SKILL.md +107 -0
- package/packages/codex/skills/go-grpc-patterns/SKILL.md +285 -0
- package/packages/codex/skills/go-modernizer/SKILL.md +111 -0
- package/packages/codex/skills/go-observability-reviewer/SKILL.md +121 -0
- package/packages/codex/skills/go-performance-reviewer/SKILL.md +112 -0
- package/packages/codex/skills/go-reviewer/SKILL.md +109 -0
- package/packages/codex/skills/go-samber-do/SKILL.md +158 -0
- package/packages/codex/skills/go-samber-lo/SKILL.md +178 -0
- package/packages/codex/skills/go-samber-oops/SKILL.md +174 -0
- package/packages/codex/skills/goal-verifier/SKILL.md +53 -0
- package/packages/codex/skills/health-checker/SKILL.md +109 -0
- package/packages/codex/skills/html-to-3d-texture/SKILL.md +153 -0
- package/packages/codex/skills/impeccable-craft/SKILL.md +101 -0
- package/packages/codex/skills/lint-runner/SKILL.md +85 -0
- package/packages/codex/skills/migrate/SKILL.md +60 -0
- package/packages/codex/skills/migration-reviewer/SKILL.md +88 -0
- package/packages/codex/skills/minimal-change-engineer/SKILL.md +44 -0
- package/packages/codex/skills/new-migration/SKILL.md +59 -0
- package/packages/codex/skills/nextjs-supabase-auth/SKILL.md +227 -0
- package/packages/codex/skills/output-enforcement/SKILL.md +71 -0
- package/packages/codex/skills/plan-checker/SKILL.md +53 -0
- package/packages/codex/skills/postgresql-optimization/SKILL.md +159 -0
- package/packages/codex/skills/pre-deploy-validator/SKILL.md +111 -0
- package/packages/codex/skills/presentation-reviewer/SKILL.md +88 -0
- package/packages/codex/skills/product-3d-lighting/SKILL.md +137 -0
- package/packages/codex/skills/project-architecture/SKILL.md +52 -0
- package/packages/codex/skills/py-reviewer/SKILL.md +100 -0
- package/packages/codex/skills/r3f-scene-reviewer/SKILL.md +88 -0
- package/packages/codex/skills/r3f-scroll-driven-3d/SKILL.md +162 -0
- package/packages/codex/skills/reality-checker/SKILL.md +61 -0
- package/packages/codex/skills/redis-patterns/SKILL.md +260 -0
- package/packages/codex/skills/review-orchestrator/SKILL.md +151 -0
- package/packages/codex/skills/rs-reviewer/SKILL.md +98 -0
- package/packages/codex/skills/ru-text/SKILL.md +132 -0
- package/packages/codex/skills/scaffold-endpoint/SKILL.md +44 -0
- package/packages/codex/skills/security-scanner/SKILL.md +94 -0
- package/packages/codex/skills/silent-failure-hunter/SKILL.md +176 -0
- package/packages/codex/skills/telegram-bot-builder/SKILL.md +120 -0
- package/packages/codex/skills/test-generator/SKILL.md +79 -0
- package/packages/codex/skills/test-runner/SKILL.md +101 -0
- package/packages/codex/skills/threejs-color-management/SKILL.md +97 -0
- package/packages/codex/skills/tree-generator/SKILL.md +63 -0
- package/packages/codex/skills/ts-reviewer/SKILL.md +90 -0
- package/packages/codex/skills/ui-design-reviewer/SKILL.md +89 -0
- package/packages/codex/skills/ui-reviewer/SKILL.md +103 -0
- package/packages/codex/skills/visual-reviewer/SKILL.md +85 -0
- package/packages/codex/skills/writing-agents/SKILL.md +165 -0
- package/packages/codex/skills/writing-commands/SKILL.md +173 -0
- package/packages/core/CLAUDE.md +118 -0
- package/packages/core/INTERNAL-FILES +16 -0
- package/packages/core/agents/ai-slop-cleaner.md +187 -0
- package/packages/core/agents/api-contract-sync.md +127 -0
- package/packages/core/agents/architect.md +205 -0
- package/packages/core/agents/audit-backend.md +137 -0
- package/packages/core/agents/audit-frontend.md +129 -0
- package/packages/core/agents/audit-infra.md +182 -0
- package/packages/core/agents/behavioral-nudge-engine.md +170 -0
- package/packages/core/agents/code-reviewer.md +195 -0
- package/packages/core/agents/codebase-onboarding-engineer.md +172 -0
- package/packages/core/agents/comment-rot-analyzer.md +115 -0
- package/packages/core/agents/critic.md +172 -0
- package/packages/core/agents/database-reviewer.md +201 -0
- package/packages/core/agents/debug-observer.md +261 -0
- package/packages/core/agents/dependency-checker.md +199 -0
- package/packages/core/agents/docs-reviewer.md +206 -0
- package/packages/core/agents/e2e-test-generator.md +261 -0
- package/packages/core/agents/evaluator.md +141 -0
- package/packages/core/agents/goal-verifier.md +130 -0
- package/packages/core/agents/health-checker.md +194 -0
- package/packages/core/agents/migration-reviewer.md +161 -0
- package/packages/core/agents/minimal-change-engineer.md +219 -0
- package/packages/core/agents/plan-checker.md +139 -0
- package/packages/core/agents/pre-deploy-validator.md +189 -0
- package/packages/core/agents/reality-checker.md +175 -0
- package/packages/core/agents/scaffold-endpoint.md +162 -0
- package/packages/core/agents/security-scanner.md +236 -0
- package/packages/core/agents/silent-failure-hunter.md +276 -0
- package/packages/core/agents/test-generator.md +146 -0
- package/packages/core/agents/tree-generator.md +141 -0
- package/packages/core/agents/ui-reviewer.md +172 -0
- package/packages/core/agents/visual-reviewer.md +211 -0
- package/packages/core/commands/audit.md +166 -0
- package/packages/core/commands/benchmark.md +130 -0
- package/packages/core/commands/commit.md +148 -0
- package/packages/core/commands/dev.md +302 -0
- package/packages/core/commands/docs-init.md +75 -0
- package/packages/core/commands/lint.md +137 -0
- package/packages/core/commands/migrate.md +146 -0
- package/packages/core/commands/new-migration.md +182 -0
- package/packages/core/commands/pair.md +209 -0
- package/packages/core/commands/review.md +195 -0
- package/packages/core/commands/security-scan.md +142 -0
- package/packages/core/commands/superkit-evolve.md +231 -0
- package/packages/core/commands/superkit-init.md +274 -0
- package/packages/core/commands/test.md +108 -0
- package/packages/core/commands/workflow.md +150 -0
- package/packages/core/docs/guide/01-getting-started.md +41 -0
- package/packages/core/docs-templates/README.md +33 -0
- package/packages/core/docs-templates/adr-template.md +62 -0
- package/packages/core/docs-templates/architecture/api-contracts.md +26 -0
- package/packages/core/docs-templates/architecture/api-reference.md +48 -0
- package/packages/core/docs-templates/architecture/auth-and-sessions.md +38 -0
- package/packages/core/docs-templates/architecture/backend-layers.md +42 -0
- package/packages/core/docs-templates/architecture/data-flow.md +26 -0
- package/packages/core/docs-templates/architecture/database-schema.md +51 -0
- package/packages/core/docs-templates/architecture/deployment.md +41 -0
- package/packages/core/docs-templates/architecture/frontend-state.md +46 -0
- package/packages/core/helpers/statusline.cjs +370 -0
- package/packages/core/hooks/CHAIN-SEMANTICS.md +84 -0
- package/packages/core/hooks/audit-settings-source.sh +98 -0
- package/packages/core/hooks/audit-trail.sh +120 -0
- package/packages/core/hooks/block-dangerous-git.sh +189 -0
- package/packages/core/hooks/bundle-import-check.sh +64 -0
- package/packages/core/hooks/compact-state-inject.sh +84 -0
- package/packages/core/hooks/config-protection.sh +68 -0
- package/packages/core/hooks/console-log-warning.sh +28 -0
- package/packages/core/hooks/context-monitor.sh +35 -0
- package/packages/core/hooks/dev-edit-counter.sh +59 -0
- package/packages/core/hooks/dev-marker-set.sh +55 -0
- package/packages/core/hooks/dev-required-on-commit.sh +426 -0
- package/packages/core/hooks/doc-check-on-commit.sh +396 -0
- package/packages/core/hooks/edit-streak-check.sh +63 -0
- package/packages/core/hooks/evolve-check.sh +78 -0
- package/packages/core/hooks/gateguard-pre-edit.sh +154 -0
- package/packages/core/hooks/gateguard-record-facts.sh +37 -0
- package/packages/core/hooks/intake-classifier.py +449 -0
- package/packages/core/hooks/lib/profile.sh +141 -0
- package/packages/core/hooks/loop-guard.sh +75 -0
- package/packages/core/hooks/migration-safety.sh +56 -0
- package/packages/core/hooks/plan-completion-gate.sh +61 -0
- package/packages/core/hooks/pre-compact-save.sh +89 -0
- package/packages/core/hooks/security-patterns.sh +119 -0
- package/packages/core/hooks/session-context-restore.sh +76 -0
- package/packages/core/hooks/subagent-stop-validate.sh +73 -0
- package/packages/core/hooks/superkit-counts-verify.sh +346 -0
- package/packages/core/hooks/superkit-update.sh +367 -0
- package/packages/core/hooks/tests/README.md +42 -0
- package/packages/core/hooks/tests/audit-trail-chain_test.sh +62 -0
- package/packages/core/hooks/tests/block-dangerous-git_test.sh +144 -0
- package/packages/core/hooks/tests/chain-semantics/h1.sh +11 -0
- package/packages/core/hooks/tests/chain-semantics/h2.sh +9 -0
- package/packages/core/hooks/tests/chain-semantics/h3.sh +11 -0
- package/packages/core/hooks/tests/chain-semantics/run-experiment.sh +65 -0
- package/packages/core/hooks/tests/chain-semantics/settings-experiment.json +15 -0
- package/packages/core/hooks/tests/counts-verify_test.sh +118 -0
- package/packages/core/hooks/tests/dev-required-on-commit_test.sh +207 -0
- package/packages/core/hooks/tests/dev-required-wip-on-main_test.sh +20 -0
- package/packages/core/hooks/tests/doc-check-on-commit_test.sh +122 -0
- package/packages/core/hooks/tests/edit-streak-check_test.sh +106 -0
- package/packages/core/hooks/tests/internal-manifest_test.sh +130 -0
- package/packages/core/hooks/tests/json-path_test.sh +108 -0
- package/packages/core/hooks/tests/mirror-invariants_test.sh +139 -0
- package/packages/core/hooks/tests/nudge-throttle_test.sh +95 -0
- package/packages/core/hooks/tests/profile-helper_test.sh +21 -0
- package/packages/core/hooks/tests/run-all.sh +47 -0
- package/packages/core/hooks/tests/session-key-helper_test.sh +17 -0
- package/packages/core/hooks/tests/superkit-update_test.sh +311 -0
- package/packages/core/hooks/tests/warn-visibility_test.sh +59 -0
- package/packages/core/hooks/user-intent-detect.sh +44 -0
- package/packages/core/hooks/verify-hooks.sh +69 -0
- package/packages/core/rules/auto-commands.md +124 -0
- package/packages/core/rules/coding-style.md +68 -0
- package/packages/core/rules/dev-workflow.md +77 -0
- package/packages/core/rules/documentation.md +106 -0
- package/packages/core/rules/frontend-aesthetics.md +53 -0
- package/packages/core/rules/git-workflow.md +14 -0
- package/packages/core/rules/security.md +29 -0
- package/packages/core/rules/superkit-integrity.md +114 -0
- package/packages/core/settings.json +229 -0
- package/packages/core/skills/drizzle-orm-expert/SKILL.md +260 -0
- package/packages/core/skills/nextjs-supabase-auth/SKILL.md +259 -0
- package/packages/core/skills/postgresql-optimization/SKILL.md +150 -0
- package/packages/core/skills/project-architecture/SKILL.md +31 -0
- package/packages/core/skills/project-scanner/SKILL.md +132 -0
- package/packages/core/skills/redis-patterns/SKILL.md +261 -0
- package/packages/core/skills/ru-text/SKILL.md +156 -0
- package/packages/core/skills/telegram-bot-builder/SKILL.md +145 -0
- package/packages/core/skills/writing-agents/SKILL.md +220 -0
- package/packages/core/skills/writing-commands/SKILL.md +176 -0
- package/packages/core/skills/writing-hooks/SKILL.md +335 -0
- package/packages/extras/bot-reviewer.md +279 -0
- package/packages/extras/design-system-reviewer.md +234 -0
- package/packages/extras/red-blue-auditor/README.md +117 -0
- package/packages/extras/red-blue-auditor/agent.md +128 -0
- package/packages/extras/red-blue-auditor/patterns/agent-config.txt +4 -0
- package/packages/extras/red-blue-auditor/patterns/hook-injection.txt +8 -0
- package/packages/extras/red-blue-auditor/patterns/mcp-risk.txt +5 -0
- package/packages/extras/red-blue-auditor/patterns/permission-abuse.txt +6 -0
- package/packages/extras/red-blue-auditor/patterns/secrets.txt +17 -0
- package/packages/extras/red-blue-auditor/scan.sh +88 -0
- package/packages/extras/skillsmp-search/SKILL.md +134 -0
- package/packages/frontend-3d/README.md +62 -0
- package/packages/frontend-3d/agents/frontend-perf-reviewer.md +164 -0
- package/packages/frontend-3d/agents/presentation-reviewer.md +146 -0
- package/packages/frontend-3d/agents/r3f-scene-reviewer.md +128 -0
- package/packages/frontend-3d/agents/ui-design-reviewer.md +169 -0
- package/packages/frontend-3d/commands/capture-screen.md +166 -0
- package/packages/frontend-3d/hooks/bundle-size-warn.sh +93 -0
- package/packages/frontend-3d/hooks/gsap-pattern-check.sh +74 -0
- package/packages/frontend-3d/hooks/r3f-color-check.sh +76 -0
- package/packages/frontend-3d/hooks/tailwind-version-guard.sh +98 -0
- package/packages/frontend-3d/rules/frontend-aesthetics-3d.md +81 -0
- package/packages/frontend-3d/rules/gsap-conventions.md +129 -0
- package/packages/frontend-3d/rules/threejs-conventions.md +116 -0
- package/packages/frontend-3d/skills/gltf-debugging/SKILL.md +145 -0
- package/packages/frontend-3d/skills/html-to-3d-texture/SKILL.md +183 -0
- package/packages/frontend-3d/skills/output-enforcement/SKILL.md +79 -0
- package/packages/frontend-3d/skills/product-3d-lighting/SKILL.md +166 -0
- package/packages/frontend-3d/skills/r3f-scroll-driven-3d/SKILL.md +209 -0
- package/packages/frontend-3d/skills/threejs-color-management/SKILL.md +111 -0
- package/packages/frontend-ui/NOTICE.md +99 -0
- package/packages/frontend-ui/README.md +59 -0
- package/packages/frontend-ui/agents/ui-color-reviewer.md +174 -0
- package/packages/frontend-ui/agents/ui-design-critic.md +198 -0
- package/packages/frontend-ui/agents/ui-interaction-reviewer.md +259 -0
- package/packages/frontend-ui/agents/ui-motion-reviewer.md +266 -0
- package/packages/frontend-ui/agents/ui-reviewer.md +251 -0
- package/packages/frontend-ui/agents/ui-typography-reviewer.md +222 -0
- package/packages/frontend-ui/hooks/tests/ui-animation-easing-check_test.sh +78 -0
- package/packages/frontend-ui/hooks/tests/ui-banned-fonts-check_test.sh +77 -0
- package/packages/frontend-ui/hooks/tests/ui-color-check_test.sh +75 -0
- package/packages/frontend-ui/hooks/ui-animation-easing-check.sh +86 -0
- package/packages/frontend-ui/hooks/ui-banned-fonts-check.sh +90 -0
- package/packages/frontend-ui/hooks/ui-color-check.sh +102 -0
- package/packages/frontend-ui/rules/color-and-contrast.md +230 -0
- package/packages/frontend-ui/rules/frontend-design-aesthetics.md +124 -0
- package/packages/frontend-ui/rules/interaction-polish.md +335 -0
- package/packages/frontend-ui/rules/motion-and-animation.md +283 -0
- package/packages/frontend-ui/rules/spatial-and-layout.md +212 -0
- package/packages/frontend-ui/rules/typography-guidelines.md +185 -0
- package/packages/frontend-ui/rules/ui-anti-patterns.md +309 -0
- package/packages/frontend-ui/settings.json +24 -0
- package/packages/frontend-ui/skills/impeccable-craft/SKILL.md +187 -0
- package/packages/gan/README.md +232 -0
- package/packages/gan/agents/gan-evaluator.md +214 -0
- package/packages/gan/agents/gan-generator.md +171 -0
- package/packages/gan/agents/gan-planner.md +206 -0
- package/packages/gan/rubrics/functionality.md +66 -0
- package/packages/gan/rubrics/ui-quality.md +77 -0
- package/packages/gan/skills/gan-evaluator/SKILL.md +91 -0
- package/packages/gan/skills/gan-generator/SKILL.md +72 -0
- package/packages/gan/skills/gan-planner/SKILL.md +93 -0
- package/packages/stack-agents/go/go-concurrency-reviewer.md +210 -0
- package/packages/stack-agents/go/go-error-reviewer.md +187 -0
- package/packages/stack-agents/go/go-modernizer.md +160 -0
- package/packages/stack-agents/go/go-observability-reviewer.md +185 -0
- package/packages/stack-agents/go/go-performance-reviewer.md +160 -0
- package/packages/stack-agents/go/go-reviewer.md +277 -0
- package/packages/stack-agents/go/references/benchmark-methodology.md +280 -0
- package/packages/stack-agents/go/references/channel-patterns.md +384 -0
- package/packages/stack-agents/go/references/cli-cobra-viper.md +190 -0
- package/packages/stack-agents/go/references/code-style.md +262 -0
- package/packages/stack-agents/go/references/context-propagation.md +317 -0
- package/packages/stack-agents/go/references/data-structures.md +315 -0
- package/packages/stack-agents/go/references/database-patterns.md +334 -0
- package/packages/stack-agents/go/references/design-patterns.md +411 -0
- package/packages/stack-agents/go/references/di-frameworks.md +146 -0
- package/packages/stack-agents/go/references/error-creation.md +251 -0
- package/packages/stack-agents/go/references/error-inspection.md +348 -0
- package/packages/stack-agents/go/references/error-wrapping.md +230 -0
- package/packages/stack-agents/go/references/gopls-driving.md +62 -0
- package/packages/stack-agents/go/references/goroutine-lifecycle.md +351 -0
- package/packages/stack-agents/go/references/graphql-patterns.md +221 -0
- package/packages/stack-agents/go/references/grpc-patterns.md +373 -0
- package/packages/stack-agents/go/references/modernize-guide.md +522 -0
- package/packages/stack-agents/go/references/module-management.md +191 -0
- package/packages/stack-agents/go/references/naming-conventions.md +176 -0
- package/packages/stack-agents/go/references/observability-pipeline.md +352 -0
- package/packages/stack-agents/go/references/performance-profiling.md +250 -0
- package/packages/stack-agents/go/references/refactoring-mechanics.md +127 -0
- package/packages/stack-agents/go/references/rest-openapi-patterns.md +160 -0
- package/packages/stack-agents/go/references/samber-do.md +201 -0
- package/packages/stack-agents/go/references/samber-libraries.md +363 -0
- package/packages/stack-agents/go/references/samber-lo.md +260 -0
- package/packages/stack-agents/go/references/samber-oops.md +200 -0
- package/packages/stack-agents/go/references/security-checklist.md +441 -0
- package/packages/stack-agents/go/references/standard-stdlib-now.md +181 -0
- package/packages/stack-agents/go/references/stay-updated.md +147 -0
- package/packages/stack-agents/go/references/structs-interfaces.md +312 -0
- package/packages/stack-agents/go/references/sync-primitives.md +395 -0
- package/packages/stack-agents/go/references/testing-patterns.md +483 -0
- package/packages/stack-agents/go/references/troubleshooting.md +98 -0
- package/packages/stack-agents/python/py-reviewer.md +194 -0
- package/packages/stack-agents/rust/rs-reviewer.md +188 -0
- package/packages/stack-agents/typescript/ts-reviewer.md +135 -0
- package/packages/stack-hooks/go/go-context-check-on-edit.sh +56 -0
- package/packages/stack-hooks/go/go-error-check-on-edit.sh +54 -0
- package/packages/stack-hooks/go/go-format-on-edit.sh +32 -0
- package/packages/stack-hooks/go/go-safety-check-on-edit.sh +54 -0
- package/packages/stack-hooks/go/go-vet-on-edit.sh +61 -0
- package/packages/stack-hooks/go/golangci-lint-on-edit.sh +54 -0
- package/packages/stack-hooks/python/ruff-on-edit.sh +67 -0
- package/packages/stack-hooks/rust/cargo-check-on-edit.sh +64 -0
- package/packages/stack-hooks/typescript/typecheck-on-edit.sh +76 -0
- package/packages/stack-rules/go/go-conventions.md +44 -0
- package/packages/stack-rules/go/go-safety.md +35 -0
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
#!/bin/bash
|
|
2
|
+
# config-protection.sh — warn when modifying linter/formatter/standard config files
|
|
3
|
+
# Triggers on: PostToolUse(Edit|Write)
|
|
4
|
+
# Profile: standard, strict
|
|
5
|
+
|
|
6
|
+
# Unified profile + disable check
|
|
7
|
+
SUPERKIT_PROFILE_LIB="$(dirname "$0")/lib/profile.sh"
|
|
8
|
+
[ -f "$SUPERKIT_PROFILE_LIB" ] || SUPERKIT_PROFILE_LIB="$(dirname "$0")/../lib/profile.sh"
|
|
9
|
+
# shellcheck source=/dev/null
|
|
10
|
+
[ -f "$SUPERKIT_PROFILE_LIB" ] && source "$SUPERKIT_PROFILE_LIB" && should_skip_hook "$(basename "$0" .sh)" && exit 0
|
|
11
|
+
|
|
12
|
+
PROFILE="${CLAUDE_HOOK_PROFILE:-standard}"
|
|
13
|
+
if [ "$PROFILE" = "fast" ]; then
|
|
14
|
+
exit 0
|
|
15
|
+
fi
|
|
16
|
+
|
|
17
|
+
# Read tool input — PostToolUse payload: .tool_input.file_path.
|
|
18
|
+
# See doc-check-on-commit.sh for the historical-bug context — same JSON shape.
|
|
19
|
+
INPUT=$(cat)
|
|
20
|
+
FILE_PATH=$(echo "$INPUT" | jq -r '.tool_input.file_path // .tool_input.filePath // .file_path // .filePath // empty' 2>/dev/null)
|
|
21
|
+
|
|
22
|
+
if [ -z "$FILE_PATH" ]; then
|
|
23
|
+
exit 0
|
|
24
|
+
fi
|
|
25
|
+
|
|
26
|
+
BASENAME=$(basename "$FILE_PATH")
|
|
27
|
+
WARN=false
|
|
28
|
+
|
|
29
|
+
case "$BASENAME" in
|
|
30
|
+
.eslintrc*|eslint.config*|.prettierrc*|prettier.config*|biome.json)
|
|
31
|
+
WARN=true ;;
|
|
32
|
+
tsconfig*.json)
|
|
33
|
+
WARN=true ;;
|
|
34
|
+
.golangci.yml|.golangci.yaml|golangci-lint.yml)
|
|
35
|
+
WARN=true ;;
|
|
36
|
+
.stylelintrc*|stylelint.config*)
|
|
37
|
+
WARN=true ;;
|
|
38
|
+
Cargo.toml)
|
|
39
|
+
# Only warn if [lints] or clippy section changed
|
|
40
|
+
WARN=false ;;
|
|
41
|
+
settings.json)
|
|
42
|
+
# .claude/settings.json — meta-protection
|
|
43
|
+
if echo "$FILE_PATH" | grep -q ".claude/settings.json"; then
|
|
44
|
+
WARN=true
|
|
45
|
+
fi
|
|
46
|
+
;;
|
|
47
|
+
.env|.env.*|.env.local|.env.production|.env.staging)
|
|
48
|
+
WARN=true
|
|
49
|
+
;;
|
|
50
|
+
DECISIONS.md)
|
|
51
|
+
echo ""
|
|
52
|
+
echo "WARNING: DECISIONS.md is append-only"
|
|
53
|
+
echo " Do NOT delete or modify existing entries — only add new ones."
|
|
54
|
+
echo " To reverse a decision, add a new entry that supersedes the old one."
|
|
55
|
+
echo ""
|
|
56
|
+
exit 0
|
|
57
|
+
;;
|
|
58
|
+
esac
|
|
59
|
+
|
|
60
|
+
if [ "$WARN" = true ]; then
|
|
61
|
+
echo ""
|
|
62
|
+
echo "WARNING: Config file modified: $BASENAME"
|
|
63
|
+
echo " Ensure coding standards are not weakened."
|
|
64
|
+
echo " Changes to linter/formatter configs affect the entire project."
|
|
65
|
+
echo ""
|
|
66
|
+
fi
|
|
67
|
+
|
|
68
|
+
exit 0
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
#!/bin/bash
|
|
2
|
+
# console-log-warning.sh — PostToolUse hook for Edit/Write
|
|
3
|
+
# Warns if console.log is added to .ts/.tsx files
|
|
4
|
+
# Profile: fast, standard, strict (always on)
|
|
5
|
+
|
|
6
|
+
# Unified profile + disable check
|
|
7
|
+
SUPERKIT_PROFILE_LIB="$(dirname "$0")/lib/profile.sh"
|
|
8
|
+
[ -f "$SUPERKIT_PROFILE_LIB" ] || SUPERKIT_PROFILE_LIB="$(dirname "$0")/../lib/profile.sh"
|
|
9
|
+
# shellcheck source=/dev/null
|
|
10
|
+
[ -f "$SUPERKIT_PROFILE_LIB" ] && source "$SUPERKIT_PROFILE_LIB" && should_skip_hook "$(basename "$0" .sh)" && exit 0
|
|
11
|
+
|
|
12
|
+
INPUT=$(cat)
|
|
13
|
+
FILE_PATH=$(echo "$INPUT" | jq -r '.tool_input.file_path // empty')
|
|
14
|
+
NEW_STRING=$(echo "$INPUT" | jq -r '.tool_input.new_string // .tool_input.content // empty')
|
|
15
|
+
|
|
16
|
+
if [ -z "$FILE_PATH" ]; then
|
|
17
|
+
exit 0
|
|
18
|
+
fi
|
|
19
|
+
|
|
20
|
+
if [[ ! "$FILE_PATH" =~ \.(ts|tsx)$ ]]; then
|
|
21
|
+
exit 0
|
|
22
|
+
fi
|
|
23
|
+
|
|
24
|
+
if echo "$NEW_STRING" | grep -qE 'console\.(log|debug|info)'; then
|
|
25
|
+
echo "WARNING: console.log detected in $FILE_PATH — remember to remove before commit" >&2
|
|
26
|
+
fi
|
|
27
|
+
|
|
28
|
+
exit 0
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
#!/bin/bash
|
|
2
|
+
# context-monitor.sh — monitors context window usage, warns at 75% and 90%
|
|
3
|
+
# Triggers on: PostToolUse (every tool call)
|
|
4
|
+
# Profile: all (context awareness is always useful)
|
|
5
|
+
|
|
6
|
+
# Unified profile + disable check
|
|
7
|
+
SUPERKIT_PROFILE_LIB="$(dirname "$0")/lib/profile.sh"
|
|
8
|
+
[ -f "$SUPERKIT_PROFILE_LIB" ] || SUPERKIT_PROFILE_LIB="$(dirname "$0")/../lib/profile.sh"
|
|
9
|
+
# shellcheck source=/dev/null
|
|
10
|
+
[ -f "$SUPERKIT_PROFILE_LIB" ] && source "$SUPERKIT_PROFILE_LIB" && should_skip_hook "$(basename "$0" .sh)" && exit 0
|
|
11
|
+
|
|
12
|
+
TOKENS_USED="${CLAUDE_CONTEXT_TOKENS_USED:-0}"
|
|
13
|
+
TOKENS_MAX="${CLAUDE_CONTEXT_TOKENS_MAX:-1000000}"
|
|
14
|
+
|
|
15
|
+
if [ "$TOKENS_USED" -eq 0 ]; then
|
|
16
|
+
exit 0
|
|
17
|
+
fi
|
|
18
|
+
|
|
19
|
+
PERCENT=$(( TOKENS_USED * 100 / TOKENS_MAX ))
|
|
20
|
+
|
|
21
|
+
if [ "$PERCENT" -ge 90 ]; then
|
|
22
|
+
echo ""
|
|
23
|
+
echo "CONTEXT 90% — recommend /compact or new session"
|
|
24
|
+
echo " Used: ~${TOKENS_USED} / ${TOKENS_MAX} tokens"
|
|
25
|
+
echo " Response quality may degrade. Save important context."
|
|
26
|
+
echo ""
|
|
27
|
+
elif [ "$PERCENT" -ge 75 ]; then
|
|
28
|
+
echo ""
|
|
29
|
+
echo "CONTEXT 75% — context window filling up"
|
|
30
|
+
echo " Used: ~${TOKENS_USED} / ${TOKENS_MAX} tokens"
|
|
31
|
+
echo " Plan to wrap up current task or /compact."
|
|
32
|
+
echo ""
|
|
33
|
+
fi
|
|
34
|
+
|
|
35
|
+
exit 0
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
#!/bin/bash
|
|
2
|
+
# dev-edit-counter.sh — counts code-file edits in current session
|
|
3
|
+
# Triggers on: PostToolUse(Edit|Write|MultiEdit)
|
|
4
|
+
# Profile: standard, strict
|
|
5
|
+
#
|
|
6
|
+
# Purpose: feeds the `dev-required-on-commit.sh` gate. When Claude accumulates
|
|
7
|
+
# 3+ edits to real code files without invoking /dev, the next git commit
|
|
8
|
+
# must either have a /dev marker or a [quick]/[no-dev]/[trivial]/[hotfix]
|
|
9
|
+
# override in the commit message.
|
|
10
|
+
#
|
|
11
|
+
# State file: /tmp/claude-edit-count-${SESSION_KEY}
|
|
12
|
+
# Reset: on successful commit or fresh session (new session_id).
|
|
13
|
+
|
|
14
|
+
# Unified profile + disable check
|
|
15
|
+
SUPERKIT_PROFILE_LIB="$(dirname "$0")/lib/profile.sh"
|
|
16
|
+
[ -f "$SUPERKIT_PROFILE_LIB" ] || SUPERKIT_PROFILE_LIB="$(dirname "$0")/../lib/profile.sh"
|
|
17
|
+
# shellcheck source=/dev/null
|
|
18
|
+
[ -f "$SUPERKIT_PROFILE_LIB" ] && source "$SUPERKIT_PROFILE_LIB" && should_skip_hook "$(basename "$0" .sh)" && exit 0
|
|
19
|
+
|
|
20
|
+
PROFILE="${CLAUDE_HOOK_PROFILE:-standard}"
|
|
21
|
+
if [ "$PROFILE" = "fast" ]; then
|
|
22
|
+
exit 0
|
|
23
|
+
fi
|
|
24
|
+
|
|
25
|
+
# Read tool input — PostToolUse payload: .tool_input.file_path + .session_id
|
|
26
|
+
INPUT=$(cat)
|
|
27
|
+
FILE_PATH=$(echo "$INPUT" | jq -r '.tool_input.file_path // .tool_input.filePath // .file_path // empty' 2>/dev/null)
|
|
28
|
+
SESSION_ID=$(echo "$INPUT" | jq -r '.session_id // empty' 2>/dev/null)
|
|
29
|
+
|
|
30
|
+
if [ -z "$FILE_PATH" ]; then
|
|
31
|
+
exit 0
|
|
32
|
+
fi
|
|
33
|
+
|
|
34
|
+
# ── Skip tests, docs, config, and non-production paths ──
|
|
35
|
+
case "$FILE_PATH" in
|
|
36
|
+
*_test.go|*test_*.go|*.test.ts|*.test.tsx|*.spec.ts|*.spec.tsx)
|
|
37
|
+
exit 0 ;;
|
|
38
|
+
*.md|*.mdx|*.txt|*.json|*.yaml|*.yml|*.toml|*.ini|*.cfg|*.env*)
|
|
39
|
+
exit 0 ;;
|
|
40
|
+
*/.claude/*|*/memory/*|*/docs/*|*/node_modules/*|*/vendor/*|*/dist/*|*/build/*)
|
|
41
|
+
exit 0 ;;
|
|
42
|
+
*/.git/*|*/.obsidian/*)
|
|
43
|
+
exit 0 ;;
|
|
44
|
+
esac
|
|
45
|
+
|
|
46
|
+
# ── Count only real code files ──
|
|
47
|
+
case "$FILE_PATH" in
|
|
48
|
+
*.go|*.ts|*.tsx|*.js|*.jsx|*.py|*.rs|*.sql|*.rb|*.java|*.kt|*.cs|*.swift|*.c|*.cpp|*.h|*.hpp) ;;
|
|
49
|
+
*) exit 0 ;;
|
|
50
|
+
esac
|
|
51
|
+
|
|
52
|
+
# Use Claude Code session_id (stable across all hooks in one session).
|
|
53
|
+
# Fallback to PPID for tests + old Claude Code versions that don't send it.
|
|
54
|
+
SESSION_KEY="${SESSION_ID:-${CLAUDE_HOOK_PID:-$PPID}}"
|
|
55
|
+
COUNTER="${TMPDIR:-/tmp}/claude-edit-count-${SESSION_KEY}"
|
|
56
|
+
CURRENT=$(cat "$COUNTER" 2>/dev/null || echo 0)
|
|
57
|
+
echo $((CURRENT + 1)) > "$COUNTER"
|
|
58
|
+
|
|
59
|
+
exit 0
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
#!/bin/bash
|
|
2
|
+
# dev-marker-set.sh — sets a marker file when /dev is invoked
|
|
3
|
+
# Triggers on: UserPromptSubmit AND PreToolUse(Skill)
|
|
4
|
+
# Profile: standard, strict
|
|
5
|
+
#
|
|
6
|
+
# Purpose: lets `dev-required-on-commit.sh` know that /dev was run in
|
|
7
|
+
# the current session. Two paths:
|
|
8
|
+
# (1) user types `/dev …` — detected via UserPromptSubmit payload.prompt
|
|
9
|
+
# (2) Claude invokes Skill({skill: "dev"}) — detected via
|
|
10
|
+
# PreToolUse payload.tool_input.skill
|
|
11
|
+
#
|
|
12
|
+
# Marker: /tmp/claude-dev-marker-${SESSION_KEY}
|
|
13
|
+
# The marker is cleared by `dev-required-on-commit.sh` on successful commit
|
|
14
|
+
# so the 3-edit budget restarts for the next work-cycle.
|
|
15
|
+
|
|
16
|
+
# Unified profile + disable check
|
|
17
|
+
SUPERKIT_PROFILE_LIB="$(dirname "$0")/lib/profile.sh"
|
|
18
|
+
[ -f "$SUPERKIT_PROFILE_LIB" ] || SUPERKIT_PROFILE_LIB="$(dirname "$0")/../lib/profile.sh"
|
|
19
|
+
# shellcheck source=/dev/null
|
|
20
|
+
[ -f "$SUPERKIT_PROFILE_LIB" ] && source "$SUPERKIT_PROFILE_LIB" && should_skip_hook "$(basename "$0" .sh)" && exit 0
|
|
21
|
+
|
|
22
|
+
PROFILE="${CLAUDE_HOOK_PROFILE:-standard}"
|
|
23
|
+
if [ "$PROFILE" = "fast" ]; then
|
|
24
|
+
exit 0
|
|
25
|
+
fi
|
|
26
|
+
|
|
27
|
+
INPUT=$(cat)
|
|
28
|
+
EVENT=$(echo "$INPUT" | jq -r '.hook_event_name // empty' 2>/dev/null)
|
|
29
|
+
SESSION_ID=$(echo "$INPUT" | jq -r '.session_id // empty' 2>/dev/null)
|
|
30
|
+
# Use Claude Code session_id for stable cross-hook state.
|
|
31
|
+
SESSION_KEY="${SESSION_ID:-${CLAUDE_HOOK_PID:-$PPID}}"
|
|
32
|
+
MARKER="${TMPDIR:-/tmp}/claude-dev-marker-${SESSION_KEY}"
|
|
33
|
+
|
|
34
|
+
case "$EVENT" in
|
|
35
|
+
UserPromptSubmit)
|
|
36
|
+
PROMPT=$(echo "$INPUT" | jq -r '.prompt // empty' 2>/dev/null)
|
|
37
|
+
# Match /dev at start of prompt (or after whitespace), followed by
|
|
38
|
+
# word boundary — avoid matching /develop, /device, /devops, etc.
|
|
39
|
+
if echo "$PROMPT" | grep -qE '(^|[[:space:]])/dev([[:space:]]|$)'; then
|
|
40
|
+
touch "$MARKER"
|
|
41
|
+
fi
|
|
42
|
+
;;
|
|
43
|
+
PreToolUse)
|
|
44
|
+
TOOL=$(echo "$INPUT" | jq -r '.tool_name // empty' 2>/dev/null)
|
|
45
|
+
if [ "$TOOL" = "Skill" ]; then
|
|
46
|
+
SKILL=$(echo "$INPUT" | jq -r '.tool_input.skill // empty' 2>/dev/null)
|
|
47
|
+
# Match exact "dev" or namespaced variant like "superpowers:dev"
|
|
48
|
+
if [ "$SKILL" = "dev" ] || echo "$SKILL" | grep -qE ':dev$'; then
|
|
49
|
+
touch "$MARKER"
|
|
50
|
+
fi
|
|
51
|
+
fi
|
|
52
|
+
;;
|
|
53
|
+
esac
|
|
54
|
+
|
|
55
|
+
exit 0
|
|
@@ -0,0 +1,426 @@
|
|
|
1
|
+
#!/bin/bash
|
|
2
|
+
# dev-required-on-commit.sh — BLOCK commits when ≥N code edits happened
|
|
3
|
+
# without /dev orchestration
|
|
4
|
+
# Triggers on: PreToolUse(Bash) when command contains "git commit"
|
|
5
|
+
# Profile: standard, strict
|
|
6
|
+
#
|
|
7
|
+
# Layer 3 enforcement of .claude/rules/dev-workflow.md:
|
|
8
|
+
#
|
|
9
|
+
# Claude MUST follow the /dev orchestration for ALL tasks that involve
|
|
10
|
+
# code changes — without the user explicitly calling /dev.
|
|
11
|
+
#
|
|
12
|
+
# Session-local state:
|
|
13
|
+
# ${TMPDIR}/claude-edit-count-${SESSION_KEY} — counter (dev-edit-counter.sh)
|
|
14
|
+
# ${TMPDIR}/claude-dev-marker-${SESSION_KEY} — /dev marker (dev-marker-set.sh)
|
|
15
|
+
#
|
|
16
|
+
# Long-lived state (Task 11 anti-reset cycle detection):
|
|
17
|
+
# ~/.claude/state/dev-cycles-${SESSION_KEY}.jsonl — one line per reset
|
|
18
|
+
# { ts, outcome: "allow-under-threshold" | "allow-with-dev" |
|
|
19
|
+
# "allow-override", tag?, counter }
|
|
20
|
+
# If the last hour contains ≥2 override-ended cycles, strictness rises
|
|
21
|
+
# (threshold 3 → 2). ≥3 consecutive override-ended cycles → override
|
|
22
|
+
# DISABLED for 60 minutes; /dev is required unconditionally.
|
|
23
|
+
#
|
|
24
|
+
# Logic:
|
|
25
|
+
# - count < THRESHOLD → allow + reset + cycle log
|
|
26
|
+
# - count ≥ THRESHOLD + marker exists → allow + reset + cycle log
|
|
27
|
+
# - override tag present (+ passes → allow + reset + cycle log
|
|
28
|
+
# Task 12 rationale checks)
|
|
29
|
+
# - otherwise → block (exit 2)
|
|
30
|
+
#
|
|
31
|
+
# THRESHOLD:
|
|
32
|
+
# Default 3. If anti-reset detected 2+ override cycles in the last 60
|
|
33
|
+
# min, THRESHOLD drops to 2. If 3+ consecutive override cycles, the
|
|
34
|
+
# override path is DISABLED (forced recovery).
|
|
35
|
+
#
|
|
36
|
+
# EXIT CODES:
|
|
37
|
+
# 0 = allow
|
|
38
|
+
# 2 = BLOCK (no /dev + no valid override)
|
|
39
|
+
|
|
40
|
+
# Unified profile + disable check
|
|
41
|
+
SUPERKIT_PROFILE_LIB="$(dirname "$0")/lib/profile.sh"
|
|
42
|
+
[ -f "$SUPERKIT_PROFILE_LIB" ] || SUPERKIT_PROFILE_LIB="$(dirname "$0")/../lib/profile.sh"
|
|
43
|
+
# shellcheck source=/dev/null
|
|
44
|
+
[ -f "$SUPERKIT_PROFILE_LIB" ] && source "$SUPERKIT_PROFILE_LIB" && should_skip_hook "$(basename "$0" .sh)" && exit 0
|
|
45
|
+
|
|
46
|
+
PROFILE="${CLAUDE_HOOK_PROFILE:-standard}"
|
|
47
|
+
if [ "$PROFILE" = "fast" ]; then
|
|
48
|
+
exit 0
|
|
49
|
+
fi
|
|
50
|
+
|
|
51
|
+
INPUT=$(cat)
|
|
52
|
+
COMMAND=$(echo "$INPUT" | jq -r '.tool_input.command // .command // empty' 2>/dev/null)
|
|
53
|
+
SESSION_ID=$(echo "$INPUT" | jq -r '.session_id // empty' 2>/dev/null)
|
|
54
|
+
|
|
55
|
+
# Match `git commit` including `git -C <path> commit`
|
|
56
|
+
if ! echo "$COMMAND" | grep -qE 'git(\s+-[cC]\s+\S+)*\s+commit'; then
|
|
57
|
+
exit 0
|
|
58
|
+
fi
|
|
59
|
+
|
|
60
|
+
SESSION_KEY="${SESSION_ID:-${CLAUDE_HOOK_PID:-$PPID}}"
|
|
61
|
+
COUNTER="${TMPDIR:-/tmp}/claude-edit-count-${SESSION_KEY}"
|
|
62
|
+
MARKER="${TMPDIR:-/tmp}/claude-dev-marker-${SESSION_KEY}"
|
|
63
|
+
CYCLES_DIR="$HOME/.claude/state"
|
|
64
|
+
CYCLES_FILE="$CYCLES_DIR/dev-cycles-${SESSION_KEY}.jsonl"
|
|
65
|
+
mkdir -p "$CYCLES_DIR" 2>/dev/null
|
|
66
|
+
|
|
67
|
+
log_cycle() {
|
|
68
|
+
# $1 = outcome, $2 = optional tag, $3 = counter value
|
|
69
|
+
local ts
|
|
70
|
+
ts=$(date -u +%Y-%m-%dT%H:%M:%SZ)
|
|
71
|
+
printf '{"ts":"%s","outcome":"%s","tag":"%s","counter":%s}\n' \
|
|
72
|
+
"$ts" "$1" "${2:-}" "${3:-0}" >> "$CYCLES_FILE" 2>/dev/null
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
reset_state() {
|
|
76
|
+
rm -f "$COUNTER" "$MARKER"
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
# ── Analyse last hour of cycles (anti-reset detection) ──
|
|
80
|
+
cycles_last_hour() {
|
|
81
|
+
# Output: count of override-ended cycles in the last 60 minutes
|
|
82
|
+
[ -f "$CYCLES_FILE" ] || { echo 0; return; }
|
|
83
|
+
local cutoff
|
|
84
|
+
cutoff=$(date -u -v-60M +%s 2>/dev/null || date -u -d '60 minutes ago' +%s 2>/dev/null || echo 0)
|
|
85
|
+
awk -v cutoff="$cutoff" '
|
|
86
|
+
/"outcome":"allow-override"/ {
|
|
87
|
+
# POSIX 2-arg match (works in both gawk and BWK) — pull substring via RSTART/RLENGTH
|
|
88
|
+
if (!match($0, /"ts":"[^"]+"/)) next
|
|
89
|
+
ts_str = substr($0, RSTART+6, RLENGTH-7)
|
|
90
|
+
"date -u -j -f %Y-%m-%dT%H:%M:%SZ " ts_str " +%s 2>/dev/null || date -u -d " ts_str " +%s 2>/dev/null" | getline ts
|
|
91
|
+
if (ts+0 >= cutoff+0) n++
|
|
92
|
+
}
|
|
93
|
+
END { print n+0 }
|
|
94
|
+
' "$CYCLES_FILE"
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
consecutive_override_tail() {
|
|
98
|
+
# Output: number of override cycles at the END of the log (consecutive)
|
|
99
|
+
[ -f "$CYCLES_FILE" ] || { echo 0; return; }
|
|
100
|
+
tac "$CYCLES_FILE" 2>/dev/null | awk '
|
|
101
|
+
/"outcome":"allow-override"/ { n++; next }
|
|
102
|
+
{ exit }
|
|
103
|
+
END { print n+0 }
|
|
104
|
+
'
|
|
105
|
+
}
|
|
106
|
+
# macOS ships with `tail -r` but not `tac` — provide a fallback
|
|
107
|
+
if ! command -v tac >/dev/null 2>&1; then
|
|
108
|
+
consecutive_override_tail() {
|
|
109
|
+
[ -f "$CYCLES_FILE" ] || { echo 0; return; }
|
|
110
|
+
tail -r "$CYCLES_FILE" 2>/dev/null | awk '
|
|
111
|
+
/"outcome":"allow-override"/ { n++; next }
|
|
112
|
+
{ exit }
|
|
113
|
+
END { print n+0 }
|
|
114
|
+
'
|
|
115
|
+
}
|
|
116
|
+
fi
|
|
117
|
+
|
|
118
|
+
OVERRIDE_CYCLES_RECENT=$(cycles_last_hour)
|
|
119
|
+
OVERRIDE_CYCLES_CONSEC=$(consecutive_override_tail)
|
|
120
|
+
|
|
121
|
+
THRESHOLD=3
|
|
122
|
+
OVERRIDE_DISABLED=false
|
|
123
|
+
if [ "$OVERRIDE_CYCLES_CONSEC" -ge 3 ]; then
|
|
124
|
+
OVERRIDE_DISABLED=true
|
|
125
|
+
fi
|
|
126
|
+
if [ "$OVERRIDE_CYCLES_RECENT" -ge 2 ]; then
|
|
127
|
+
THRESHOLD=2
|
|
128
|
+
fi
|
|
129
|
+
|
|
130
|
+
# ── Rolling-budget query (Task 12): count overrides in audit log ──
|
|
131
|
+
budget_last_30min() {
|
|
132
|
+
# Count override-tagged entries in ~/.claude/audit/*.jsonl within 30 min.
|
|
133
|
+
# Audit log lives under $HOME/.claude/audit/YYYY-MM-DD.jsonl.
|
|
134
|
+
local cutoff
|
|
135
|
+
cutoff=$(date -u -v-30M +%s 2>/dev/null || date -u -d '30 minutes ago' +%s 2>/dev/null || echo 0)
|
|
136
|
+
local cnt=0
|
|
137
|
+
for f in "$HOME/.claude/audit/"*.jsonl; do
|
|
138
|
+
[ -f "$f" ] || continue
|
|
139
|
+
while IFS= read -r line; do
|
|
140
|
+
local tag ts_iso ts_epoch
|
|
141
|
+
tag=$(printf '%s' "$line" | jq -r '.tag // empty' 2>/dev/null)
|
|
142
|
+
[ -z "$tag" ] && continue
|
|
143
|
+
ts_iso=$(printf '%s' "$line" | jq -r '.ts // empty' 2>/dev/null)
|
|
144
|
+
[ -z "$ts_iso" ] && continue
|
|
145
|
+
ts_epoch=$(date -u -j -f '%Y-%m-%dT%H:%M:%SZ' "$ts_iso" +%s 2>/dev/null || \
|
|
146
|
+
date -u -d "$ts_iso" +%s 2>/dev/null || echo 0)
|
|
147
|
+
[ "$ts_epoch" -ge "$cutoff" ] && cnt=$((cnt + 1))
|
|
148
|
+
done < "$f"
|
|
149
|
+
done
|
|
150
|
+
echo "$cnt"
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
# ── Resolve the real target repo if `-C <path>` is present ──
|
|
154
|
+
# Must be defined before the override-tag block so Rule 3 ([wip]-on-main)
|
|
155
|
+
# can call `$GIT_CMD_PREFIX rev-parse` to detect the current branch.
|
|
156
|
+
GIT_TARGET_DIR=$(echo "$COMMAND" | sed -nE 's/.*git[[:space:]]+(-[cC][[:space:]]+([^[:space:]]+)).*/\2/p' | head -n1)
|
|
157
|
+
if [ -n "$GIT_TARGET_DIR" ] && [ -d "$GIT_TARGET_DIR" ]; then
|
|
158
|
+
GIT_CMD_PREFIX="git -C $GIT_TARGET_DIR"
|
|
159
|
+
else
|
|
160
|
+
GIT_CMD_PREFIX="git"
|
|
161
|
+
fi
|
|
162
|
+
|
|
163
|
+
# ── Exempt-only short-circuit (D3 fix) ──
|
|
164
|
+
# Determine whether the commit stages a non-exempt CODE file. This MUST run
|
|
165
|
+
# before the override branch: an exempt-only commit (docs / .claude/ /
|
|
166
|
+
# memory/ / tests / presentation/) needs neither /dev nor an override tag,
|
|
167
|
+
# so we exit 0 here and a tag merely *mentioned* in such a commit's message
|
|
168
|
+
# can never trigger a block. Depends only on $GIT_CMD_PREFIX and $COMMAND.
|
|
169
|
+
# Preserves the counter — no reset_state, no log_cycle — exactly as the old
|
|
170
|
+
# exempt exit did.
|
|
171
|
+
STAGED=$($GIT_CMD_PREFIX diff --cached --name-only 2>/dev/null)
|
|
172
|
+
if [ -z "$STAGED" ] && echo "$COMMAND" | grep -qE '(^|[[:space:]])(-a|--all)([[:space:]]|$)'; then
|
|
173
|
+
STAGED=$($GIT_CMD_PREFIX diff --name-only 2>/dev/null)
|
|
174
|
+
fi
|
|
175
|
+
|
|
176
|
+
HAS_CODE=false
|
|
177
|
+
while IFS= read -r f; do
|
|
178
|
+
[ -z "$f" ] && continue
|
|
179
|
+
case "$f" in
|
|
180
|
+
*.go|*.ts|*.tsx|*.js|*.jsx|*.py|*.rs|*.sql|*.rb|*.java|*.kt|*.cs|*.swift|*.c|*.cpp|*.h|*.hpp)
|
|
181
|
+
# Skip test / presentation / .claude / memory / docs
|
|
182
|
+
case "$f" in
|
|
183
|
+
*_test.go|*test_*.go|*.test.ts|*.test.tsx|*.spec.ts|*.spec.tsx) continue ;;
|
|
184
|
+
presentation/*|*/presentation/*) continue ;;
|
|
185
|
+
.claude/*|*/.claude/*|memory/*|*/memory/*) continue ;;
|
|
186
|
+
esac
|
|
187
|
+
HAS_CODE=true
|
|
188
|
+
break
|
|
189
|
+
;;
|
|
190
|
+
esac
|
|
191
|
+
done <<< "$STAGED"
|
|
192
|
+
|
|
193
|
+
if [ "$HAS_CODE" = false ]; then
|
|
194
|
+
# Docs-only or exempt-only commit — no /dev required. Preserve counter.
|
|
195
|
+
exit 0
|
|
196
|
+
fi
|
|
197
|
+
|
|
198
|
+
# ── Override: explicit bypass tag in commit message (Task 12 validation) ──
|
|
199
|
+
# Recognised tags: [quick] [no-dev] [trivial] [hotfix] [wip]
|
|
200
|
+
#
|
|
201
|
+
# INTENTIONAL match (D3 fix): only the commit-message payload is inspected,
|
|
202
|
+
# and the tag must OPEN a line — the subject line or its own trailer line.
|
|
203
|
+
# A tag mentioned mid-sentence (or anywhere OUTSIDE -m/--message, e.g. a
|
|
204
|
+
# filename) does NOT count as an override. We isolate the message with '#'
|
|
205
|
+
# parameter expansion (shortest match → first -m/--message flag), strip one
|
|
206
|
+
# enclosing quote to expose the subject's first char, then require the tag
|
|
207
|
+
# at a line start (^\s*[tag]). Rare no-space forms (-m"x") fall back to no
|
|
208
|
+
# override — an intentional tag is cheap to re-add correctly.
|
|
209
|
+
MSG_REGION="$COMMAND"
|
|
210
|
+
case "$COMMAND" in
|
|
211
|
+
*--message=*) MSG_REGION="${COMMAND#*--message=}" ;;
|
|
212
|
+
*--message\ *) MSG_REGION="${COMMAND#*--message }" ;;
|
|
213
|
+
*-m\ *) MSG_REGION="${COMMAND#*-m }" ;;
|
|
214
|
+
esac
|
|
215
|
+
MSG_REGION="${MSG_REGION#\"}"
|
|
216
|
+
MSG_REGION="${MSG_REGION#\'}"
|
|
217
|
+
MATCHED_TAG=$(printf '%s\n' "$MSG_REGION" \
|
|
218
|
+
| sed -E 's/^[[:space:]]+//' \
|
|
219
|
+
| grep -oiE '^\[(quick|no-dev|trivial|hotfix|wip)(:[^]]*)?\]' \
|
|
220
|
+
| head -1)
|
|
221
|
+
if [ -n "$MATCHED_TAG" ]; then
|
|
222
|
+
if [ "$OVERRIDE_DISABLED" = true ]; then
|
|
223
|
+
cat >&2 <<EOF
|
|
224
|
+
|
|
225
|
+
BLOCKED: Override path disabled (anti-reset penalty)
|
|
226
|
+
|
|
227
|
+
You've used ${OVERRIDE_CYCLES_CONSEC} consecutive override cycles in this
|
|
228
|
+
session. The escape hatch is temporarily locked — /dev is required for
|
|
229
|
+
the next code-changing commit regardless of the [quick] / [no-dev] /
|
|
230
|
+
[trivial] / [hotfix] / [wip] tag.
|
|
231
|
+
|
|
232
|
+
Options:
|
|
233
|
+
1) Run /dev — orchestrate through the phased workflow.
|
|
234
|
+
2) Commit only non-code files (docs, .claude/, memory/) — those are
|
|
235
|
+
exempt and will clear the penalty on the next commit.
|
|
236
|
+
3) End the session and start a fresh one — the penalty state is
|
|
237
|
+
session-keyed so it does not bleed across sessions.
|
|
238
|
+
|
|
239
|
+
To manually clear the penalty: rm ${CYCLES_FILE}
|
|
240
|
+
|
|
241
|
+
EOF
|
|
242
|
+
exit 2
|
|
243
|
+
fi
|
|
244
|
+
|
|
245
|
+
# Extract tag name + optional `: <reason>`
|
|
246
|
+
TAG_NAME=$(printf '%s' "$MATCHED_TAG" | tr '[:upper:]' '[:lower:]' | sed -E 's/^\[([a-z-]+).*/\1/')
|
|
247
|
+
TAG_REASON=$(printf '%s' "$MATCHED_TAG" | sed -nE 's/^\[[a-z-]+:[[:space:]]*([^]]*)\]$/\1/ip')
|
|
248
|
+
|
|
249
|
+
# Rule 1: quick / trivial / no-dev require a rationale of ≥15 chars
|
|
250
|
+
# Exception (Task 15): if the user explicitly asked for a "quick fix" /
|
|
251
|
+
# "small tweak" / etc. in this session, user-intent-detect.sh leaves a
|
|
252
|
+
# marker. Bare [quick] is then allowed (the user took responsibility).
|
|
253
|
+
# The marker is consumed so subsequent commits still need rationale.
|
|
254
|
+
USER_INTENT_MARKER="${TMPDIR:-/tmp}/claude-user-said-quick-${SESSION_KEY}"
|
|
255
|
+
USER_SAID_QUICK=false
|
|
256
|
+
[ -f "$USER_INTENT_MARKER" ] && USER_SAID_QUICK=true
|
|
257
|
+
case "$TAG_NAME" in
|
|
258
|
+
quick|trivial|no-dev)
|
|
259
|
+
if [ -z "$TAG_REASON" ] || [ "${#TAG_REASON}" -lt 15 ]; then
|
|
260
|
+
if [ "$USER_SAID_QUICK" = true ] && [ "$TAG_NAME" = "quick" ]; then
|
|
261
|
+
# User explicitly authorised a quick fix — consume the marker
|
|
262
|
+
rm -f "$USER_INTENT_MARKER"
|
|
263
|
+
else
|
|
264
|
+
cat >&2 <<EOF
|
|
265
|
+
|
|
266
|
+
BLOCKED: [${TAG_NAME}] override requires a rationale of at least 15 characters.
|
|
267
|
+
|
|
268
|
+
Format: [${TAG_NAME}: <explain why /dev is not needed here>]
|
|
269
|
+
|
|
270
|
+
Example:
|
|
271
|
+
[${TAG_NAME}: config-only tweak, no logic change, follow-up in plan #42]
|
|
272
|
+
|
|
273
|
+
Current tag: ${MATCHED_TAG}
|
|
274
|
+
(If the user explicitly asked for a "quick fix" in chat, the bare
|
|
275
|
+
[quick] tag is allowed once per such request.)
|
|
276
|
+
|
|
277
|
+
EOF
|
|
278
|
+
exit 2
|
|
279
|
+
fi
|
|
280
|
+
fi
|
|
281
|
+
;;
|
|
282
|
+
esac
|
|
283
|
+
|
|
284
|
+
# Rule 2: [hotfix] requires a ticket ID OR `no-ticket: <reason>`
|
|
285
|
+
if [ "$TAG_NAME" = "hotfix" ]; then
|
|
286
|
+
if [ -z "$TAG_REASON" ]; then
|
|
287
|
+
cat >&2 <<EOF
|
|
288
|
+
|
|
289
|
+
BLOCKED: [hotfix] requires a ticket reference OR an explicit no-ticket justification.
|
|
290
|
+
|
|
291
|
+
Formats accepted:
|
|
292
|
+
[hotfix: #1234 …] — GitHub/Linear-style numeric ticket
|
|
293
|
+
[hotfix: ABC-123 …] — Jira-style key-number ticket
|
|
294
|
+
[hotfix: no-ticket: <reason>] — explain why there is no ticket (≥15 chars)
|
|
295
|
+
|
|
296
|
+
Current tag: ${MATCHED_TAG}
|
|
297
|
+
|
|
298
|
+
EOF
|
|
299
|
+
exit 2
|
|
300
|
+
fi
|
|
301
|
+
# Accept if reason contains ticket-id OR starts with `no-ticket:<reason ≥15 chars>`
|
|
302
|
+
if ! printf '%s' "$TAG_REASON" | grep -qE '(#[0-9]+|[A-Z]+-[0-9]+)'; then
|
|
303
|
+
if ! printf '%s' "$TAG_REASON" | grep -qiE '^no-ticket:[[:space:]]*.{15,}$'; then
|
|
304
|
+
cat >&2 <<EOF
|
|
305
|
+
|
|
306
|
+
BLOCKED: [hotfix] rationale must contain a ticket ID (#123 or ABC-123) or
|
|
307
|
+
start with "no-ticket: <reason of at least 15 chars>".
|
|
308
|
+
|
|
309
|
+
Current reason: "${TAG_REASON}"
|
|
310
|
+
|
|
311
|
+
EOF
|
|
312
|
+
exit 2
|
|
313
|
+
fi
|
|
314
|
+
fi
|
|
315
|
+
fi
|
|
316
|
+
|
|
317
|
+
# Rule 3: [wip] is forbidden on main / prod branches
|
|
318
|
+
if [ "$TAG_NAME" = "wip" ]; then
|
|
319
|
+
CURRENT_BRANCH=$($GIT_CMD_PREFIX rev-parse --abbrev-ref HEAD 2>/dev/null || echo "")
|
|
320
|
+
case "$CURRENT_BRANCH" in
|
|
321
|
+
main|master|prod|prod/*|production|production/*)
|
|
322
|
+
cat >&2 <<EOF
|
|
323
|
+
|
|
324
|
+
BLOCKED: [wip] is not allowed on ${CURRENT_BRANCH}.
|
|
325
|
+
|
|
326
|
+
WIP commits belong on feature branches, not the mainline. Options:
|
|
327
|
+
1) Checkout a feature branch and try again.
|
|
328
|
+
2) Finish the work and drop the [wip] tag.
|
|
329
|
+
3) Use [quick: <reason>] if this is genuinely a small standalone fix.
|
|
330
|
+
|
|
331
|
+
EOF
|
|
332
|
+
exit 2
|
|
333
|
+
;;
|
|
334
|
+
esac
|
|
335
|
+
fi
|
|
336
|
+
|
|
337
|
+
# Rule 4: rolling budget — max 2 overrides per 30 min across audit log
|
|
338
|
+
RECENT_OVERRIDES_30M=$(budget_last_30min 2>/dev/null || echo 0)
|
|
339
|
+
if [ "$RECENT_OVERRIDES_30M" -ge 2 ]; then
|
|
340
|
+
cat >&2 <<EOF
|
|
341
|
+
|
|
342
|
+
BLOCKED: Override budget exhausted (${RECENT_OVERRIDES_30M} in the last 30 min, cap = 2).
|
|
343
|
+
|
|
344
|
+
You've used 2+ override tags in the last 30 minutes. The next commit
|
|
345
|
+
must go through /dev instead of adding another [quick] / [no-dev] /
|
|
346
|
+
[trivial] / [hotfix] / [wip] tag.
|
|
347
|
+
|
|
348
|
+
Options:
|
|
349
|
+
1) Run /dev — orchestrate through the phased workflow (recommended).
|
|
350
|
+
2) Wait until the oldest override drops out of the 30-min window,
|
|
351
|
+
then retry.
|
|
352
|
+
3) Split the staged files — commit docs/config first (those don't
|
|
353
|
+
count against the budget), then handle code via /dev.
|
|
354
|
+
|
|
355
|
+
Audit log: ~/.claude/audit/$(date -u +%Y-%m-%d).jsonl
|
|
356
|
+
|
|
357
|
+
EOF
|
|
358
|
+
exit 2
|
|
359
|
+
fi
|
|
360
|
+
|
|
361
|
+
log_cycle "allow-override" "$MATCHED_TAG" "$(cat "$COUNTER" 2>/dev/null || echo 0)"
|
|
362
|
+
if [ "$OVERRIDE_CYCLES_RECENT" -ge 1 ]; then
|
|
363
|
+
cat >&2 <<EOF
|
|
364
|
+
|
|
365
|
+
⚠ override-cycle warning: you've used an override tag ${OVERRIDE_CYCLES_RECENT}× in the
|
|
366
|
+
last 60 min. Consider running /dev for the next code-changing commit —
|
|
367
|
+
one more override in this window will raise strictness (threshold 3 → 2).
|
|
368
|
+
|
|
369
|
+
EOF
|
|
370
|
+
fi
|
|
371
|
+
reset_state
|
|
372
|
+
exit 0
|
|
373
|
+
fi
|
|
374
|
+
|
|
375
|
+
# ── Check edit budget ──
|
|
376
|
+
# (Reached only for a genuine CODE commit with no valid override tag —
|
|
377
|
+
# the exempt-only short-circuit above already returned 0 for exempt files.)
|
|
378
|
+
COUNT=$(cat "$COUNTER" 2>/dev/null || echo 0)
|
|
379
|
+
|
|
380
|
+
if [ "$COUNT" -lt "$THRESHOLD" ]; then
|
|
381
|
+
log_cycle "allow-under-threshold" "" "$COUNT"
|
|
382
|
+
reset_state
|
|
383
|
+
exit 0
|
|
384
|
+
fi
|
|
385
|
+
|
|
386
|
+
if [ -f "$MARKER" ]; then
|
|
387
|
+
log_cycle "allow-with-dev" "" "$COUNT"
|
|
388
|
+
reset_state
|
|
389
|
+
exit 0
|
|
390
|
+
fi
|
|
391
|
+
|
|
392
|
+
# ── Block ──
|
|
393
|
+
EXTRA_NOTE=""
|
|
394
|
+
if [ "$THRESHOLD" = "2" ]; then
|
|
395
|
+
EXTRA_NOTE=" Note: threshold was raised from 3 to 2 because ${OVERRIDE_CYCLES_RECENT}+ override
|
|
396
|
+
cycles were recorded in the last 60 min (anti-reset strictness).
|
|
397
|
+
|
|
398
|
+
"
|
|
399
|
+
fi
|
|
400
|
+
cat >&2 <<EOF
|
|
401
|
+
|
|
402
|
+
BLOCKED: $COUNT code-file edits without /dev orchestration
|
|
403
|
+
|
|
404
|
+
Rule (.claude/rules/dev-workflow.md):
|
|
405
|
+
Claude MUST follow /dev for ALL tasks that involve code changes.
|
|
406
|
+
|
|
407
|
+
${EXTRA_NOTE} Options:
|
|
408
|
+
1) Run /dev — orchestrate through the phased workflow (recommended).
|
|
409
|
+
2) Add one of these tags to your commit message to override:
|
|
410
|
+
[quick] — small fix, skip /dev intentionally
|
|
411
|
+
[no-dev] — non-trivial but /dev not applicable (explain why)
|
|
412
|
+
[trivial] — cosmetic change (naming, formatting)
|
|
413
|
+
[hotfix] — emergency fix
|
|
414
|
+
[wip] — work-in-progress checkpoint
|
|
415
|
+
|
|
416
|
+
Current state:
|
|
417
|
+
edits = $COUNT (threshold: $THRESHOLD)
|
|
418
|
+
marker = missing → /dev was NOT invoked this work-cycle
|
|
419
|
+
recent-override-cycles (60 min) = $OVERRIDE_CYCLES_RECENT
|
|
420
|
+
consecutive-override-cycles = $OVERRIDE_CYCLES_CONSEC
|
|
421
|
+
|
|
422
|
+
To reset manually: rm $COUNTER
|
|
423
|
+
To clear anti-reset penalty: rm $CYCLES_FILE
|
|
424
|
+
|
|
425
|
+
EOF
|
|
426
|
+
exit 2
|