@getarbiter/cli 0.5.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 +713 -0
- package/LICENSE +202 -0
- package/NOTICE +31 -0
- package/PRIVACY.md +111 -0
- package/README.md +237 -0
- package/THIRD_PARTY_LICENSES.md +472 -0
- package/dist/.src-manifest.json +1 -0
- package/dist/capabilities/host-probe.js +3 -0
- package/dist/cli.d.ts +2 -0
- package/dist/cli.js +87 -0
- package/dist/commands/adopt-policy.js +3 -0
- package/dist/commands/configure-interactive.js +3 -0
- package/dist/commands/configure.js +5 -0
- package/dist/commands/cross-model-review.js +3 -0
- package/dist/commands/diff.js +20 -0
- package/dist/commands/doc-set.js +3 -0
- package/dist/commands/doctor/clean.js +2 -0
- package/dist/commands/doctor/fail-open-census.js +12 -0
- package/dist/commands/doctor/health.js +11 -0
- package/dist/commands/doctor/prove-gates.js +13 -0
- package/dist/commands/doctor/recover-lock.js +12 -0
- package/dist/commands/doctor/repair-state.js +6 -0
- package/dist/commands/doctor/tool-pin-extract.js +4 -0
- package/dist/commands/doctor/tool-pins.js +9 -0
- package/dist/commands/doctor-interactive.js +2 -0
- package/dist/commands/doctor.js +2 -0
- package/dist/commands/explain.js +19 -0
- package/dist/commands/gate-exec.js +4 -0
- package/dist/commands/gold-audit.js +14 -0
- package/dist/commands/graph.js +5 -0
- package/dist/commands/init/build-arbiter-config.js +1 -0
- package/dist/commands/init/generate.js +42 -0
- package/dist/commands/init/github-setup.js +5 -0
- package/dist/commands/init/maturity-gates.js +10 -0
- package/dist/commands/init/resolve-config.js +3 -0
- package/dist/commands/init/toolchain.js +10 -0
- package/dist/commands/init/types.js +1 -0
- package/dist/commands/init.js +17 -0
- package/dist/commands/method-interactive.js +4 -0
- package/dist/commands/method.js +11 -0
- package/dist/commands/obsidian.js +2 -0
- package/dist/commands/plugin.js +8 -0
- package/dist/commands/pr-merged.js +2 -0
- package/dist/commands/retire-policy.js +3 -0
- package/dist/commands/review-diff.js +3 -0
- package/dist/commands/settings.js +7 -0
- package/dist/commands/ship-config.js +2 -0
- package/dist/commands/ship-profile.js +2 -0
- package/dist/commands/ship-review.js +1 -0
- package/dist/commands/ship-tier.js +2 -0
- package/dist/commands/ship-train.js +2 -0
- package/dist/commands/task-mark.js +2 -0
- package/dist/commands/task-note.js +3 -0
- package/dist/commands/task-record-red.js +2 -0
- package/dist/commands/task-record-tech-debt.js +4 -0
- package/dist/commands/task-ship.js +3 -0
- package/dist/commands/task-state.js +6 -0
- package/dist/commands/task.js +59 -0
- package/dist/commands/update.js +60 -0
- package/dist/commands/upgrade-level-interactive.js +2 -0
- package/dist/commands/upgrade-level.js +7 -0
- package/dist/commands/verify-plan.js +8 -0
- package/dist/commands/verify-tdd.js +2 -0
- package/dist/commands/verify.js +7 -0
- package/dist/commands/wizard/coherence.js +1 -0
- package/dist/commands/worktree-prune.js +4 -0
- package/dist/commands/worktree.js +39 -0
- package/dist/compatibility/cross-language-matrix.json +540 -0
- package/dist/compatibility/index.d.ts +4 -0
- package/dist/compatibility/index.js +2 -0
- package/dist/compatibility/matcher.js +1 -0
- package/dist/compatibility/matrix.json +27 -0
- package/dist/compatibility/parsers.d.ts +38 -0
- package/dist/compatibility/parsers.js +1 -0
- package/dist/compatibility/probe.d.ts +41 -0
- package/dist/compatibility/probe.js +4 -0
- package/dist/compatibility/report.js +2 -0
- package/dist/compatibility/schema.d.ts +80 -0
- package/dist/compatibility/schema.js +1 -0
- package/dist/compatibility/skills-matrix.json +98 -0
- package/dist/compatibility/skills-validator.d.ts +30 -0
- package/dist/compatibility/skills-validator.js +4 -0
- package/dist/compatibility/tooling-proposals.json +5 -0
- package/dist/config/arbiter-ignore.js +3 -0
- package/dist/config/collaboration-mode-defaults.js +1 -0
- package/dist/config/diff.js +1 -0
- package/dist/config/env-overrides.js +3 -0
- package/dist/config/env-registry.js +2 -0
- package/dist/config/levels.js +1 -0
- package/dist/config/migrations/index.js +2 -0
- package/dist/config/migrations/v0-to-v1.js +2 -0
- package/dist/config/migrations/v1-to-v2.js +2 -0
- package/dist/config/migrations/v2-to-v3.js +2 -0
- package/dist/config/migrations/v3-to-v4.js +2 -0
- package/dist/config/override-resolver.js +2 -0
- package/dist/config/resolve-project-config.js +2 -0
- package/dist/config/resolve-project-name.js +2 -0
- package/dist/config/schema.d.ts +480 -0
- package/dist/config/schema.js +1 -0
- package/dist/config/test-pyramid-profiles.js +1 -0
- package/dist/config/thresholds.js +2 -0
- package/dist/conformance/dimensions.js +3 -0
- package/dist/conformance/engine.js +7 -0
- package/dist/conformance/gate-proofs.js +4 -0
- package/dist/conformance/shared.js +2 -0
- package/dist/detectors/axis.js +1 -0
- package/dist/detectors/build.js +2 -0
- package/dist/detectors/existing.js +2 -0
- package/dist/detectors/external-model.js +2 -0
- package/dist/detectors/framework.js +2 -0
- package/dist/detectors/git.js +11 -0
- package/dist/detectors/github.js +2 -0
- package/dist/detectors/lanes.js +5 -0
- package/dist/detectors/language-hooks.js +117 -0
- package/dist/detectors/language.js +2 -0
- package/dist/detectors/package-manager.js +2 -0
- package/dist/detectors/package.js +2 -0
- package/dist/detectors/scaffold-wiring.js +2 -0
- package/dist/detectors/workflow-collision.js +4 -0
- package/dist/evidence/gate-binding.js +4 -0
- package/dist/evidence/git-checks.js +3 -0
- package/dist/evidence/load.js +2 -0
- package/dist/evidence/provenance.js +2 -0
- package/dist/evidence/summary.js +2 -0
- package/dist/evidence/tdd-reexecute.js +2 -0
- package/dist/evidence/tdd.js +4 -0
- package/dist/experimental/index.js +2 -0
- package/dist/experimental/parse-argv.js +2 -0
- package/dist/experimental/registry.js +2 -0
- package/dist/generators/agents-claude.js +2 -0
- package/dist/generators/agents-md.js +2 -0
- package/dist/generators/anti-drift-validators.js +3 -0
- package/dist/generators/anti-proforma.js +2 -0
- package/dist/generators/api-e2e.js +2 -0
- package/dist/generators/api-middleware.js +2 -0
- package/dist/generators/archunit.js +2 -0
- package/dist/generators/audit-toolchain.js +2 -0
- package/dist/generators/auth.js +2 -0
- package/dist/generators/behavioral-tests.js +2 -0
- package/dist/generators/boundaries.js +2 -0
- package/dist/generators/check-all.js +2 -0
- package/dist/generators/check-stack-conformity.js +2 -0
- package/dist/generators/ci-five-lane.js +2 -0
- package/dist/generators/ci-tier.js +2 -0
- package/dist/generators/claude.js +3 -0
- package/dist/generators/codex-hooks.js +2 -0
- package/dist/generators/codex-known-limitations.js +2 -0
- package/dist/generators/codex.js +15 -0
- package/dist/generators/commit-footer.js +2 -0
- package/dist/generators/compliance-menu.js +2 -0
- package/dist/generators/compliance.js +2 -0
- package/dist/generators/conformance.js +2 -0
- package/dist/generators/contract-testing.js +2 -0
- package/dist/generators/coverage.js +2 -0
- package/dist/generators/debt-gates.js +24 -0
- package/dist/generators/debt-ratchet.js +2 -0
- package/dist/generators/derived-class.js +2 -0
- package/dist/generators/doc-set.js +4 -0
- package/dist/generators/docs.js +2 -0
- package/dist/generators/duplication.js +2 -0
- package/dist/generators/e2e-constitution.js +2 -0
- package/dist/generators/env-template.js +2 -0
- package/dist/generators/evidence-retention.js +2 -0
- package/dist/generators/feature-matrix.js +2 -0
- package/dist/generators/frontend-governance.js +2 -0
- package/dist/generators/frontend-quality.js +2 -0
- package/dist/generators/gap.js +2 -0
- package/dist/generators/gdpr.js +2 -0
- package/dist/generators/githooks.js +2 -0
- package/dist/generators/github-setup.js +2 -0
- package/dist/generators/github.js +2 -0
- package/dist/generators/gitignore.js +2 -0
- package/dist/generators/global-invariants.js +3 -0
- package/dist/generators/go-boundaries.js +2 -0
- package/dist/generators/gold-kit.js +2 -0
- package/dist/generators/infra.js +2 -0
- package/dist/generators/integration-testing.js +7 -0
- package/dist/generators/iso27001.js +2 -0
- package/dist/generators/iso9001.js +2 -0
- package/dist/generators/labels.js +2 -0
- package/dist/generators/local-wrapper.js +2 -0
- package/dist/generators/modulith.js +2 -0
- package/dist/generators/mutation.js +2 -0
- package/dist/generators/observability.js +2 -0
- package/dist/generators/operations.js +2 -0
- package/dist/generators/perf-k6.js +2 -0
- package/dist/generators/pharma.js +2 -0
- package/dist/generators/playwright-python.js +2 -0
- package/dist/generators/playwright-ts.js +2 -0
- package/dist/generators/pr-tooling.js +2 -0
- package/dist/generators/python-boundaries.js +2 -0
- package/dist/generators/quality.js +2 -0
- package/dist/generators/registry.js +2 -0
- package/dist/generators/regulated.js +2 -0
- package/dist/generators/resilience.js +2 -0
- package/dist/generators/risk-register.js +2 -0
- package/dist/generators/root.js +2 -0
- package/dist/generators/rust-boundaries.js +2 -0
- package/dist/generators/safety-class.js +2 -0
- package/dist/generators/security.js +2 -0
- package/dist/generators/seed.js +2 -0
- package/dist/generators/self-validation.js +2 -0
- package/dist/generators/ship-driver.js +2 -0
- package/dist/generators/skill-names.json +17 -0
- package/dist/generators/skills.js +2 -0
- package/dist/generators/smoke-journeys.js +2 -0
- package/dist/generators/solo-exception.js +2 -0
- package/dist/generators/ssot.js +2 -0
- package/dist/generators/stride-enforcement.js +2 -0
- package/dist/generators/suppressions.js +2 -0
- package/dist/generators/test-pyramid-manifest.js +3 -0
- package/dist/generators/test-taxonomy.js +2 -0
- package/dist/generators/wiki.js +2 -0
- package/dist/github/branch-protection.js +2 -0
- package/dist/github/classify-gh-error.js +2 -0
- package/dist/github/labels.js +2 -0
- package/dist/github/project-board.js +2 -0
- package/dist/graph/builders/adr.js +4 -0
- package/dist/graph/builders/ast.js +3 -0
- package/dist/graph/builders/canon.js +2 -0
- package/dist/graph/builders/evidence.js +2 -0
- package/dist/graph/builders/inv.js +1 -0
- package/dist/graph/builders/req.js +3 -0
- package/dist/graph/builders/test-nodes.js +3 -0
- package/dist/graph/builders/utils.js +2 -0
- package/dist/graph/load.js +2 -0
- package/dist/graph/model.js +2 -0
- package/dist/graph/query.js +3 -0
- package/dist/graph/store.js +1 -0
- package/dist/i18n/en.json +293 -0
- package/dist/i18n/index.js +4 -0
- package/dist/i18n/types.js +2 -0
- package/dist/integrations/companions.js +2 -0
- package/dist/integrations/external-review.js +10 -0
- package/dist/integrations/plugin-schema.js +2 -0
- package/dist/integrations/skill-detector.js +7 -0
- package/dist/integrations/skills-matrix.js +2 -0
- package/dist/integrations/types.d.ts +23 -0
- package/dist/integrations/types.js +2 -0
- package/dist/internal/cli-deprecation-registry.js +2 -0
- package/dist/internal/deprecate.js +3 -0
- package/dist/internal/experimental-warn.js +3 -0
- package/dist/invariants/catalog.d.ts +2 -0
- package/dist/invariants/catalog.js +1 -0
- package/dist/invariants/filter.d.ts +28 -0
- package/dist/invariants/filter.js +1 -0
- package/dist/invariants/index.d.ts +4 -0
- package/dist/invariants/index.js +2 -0
- package/dist/invariants/tiers.js +1 -0
- package/dist/invariants/types.d.ts +1 -0
- package/dist/invariants/types.js +1 -0
- package/dist/kit/applicability.js +3 -0
- package/dist/kit/audit-report.js +3 -0
- package/dist/kit/brownfield-detect.js +4 -0
- package/dist/kit/canonical-mapping.json +1 -0
- package/dist/kit/catalog.js +2 -0
- package/dist/kit/catalog.json +1 -0
- package/dist/kit/derived.json +1 -0
- package/dist/kit/emit-issues.js +8 -0
- package/dist/kit/measure.js +5 -0
- package/dist/kit/redaction.js +3 -0
- package/dist/kit/schema.js +2 -0
- package/dist/kit/taxonomy.js +2 -0
- package/dist/kit/thresholds.d.ts +12 -0
- package/dist/kit/thresholds.js +2 -0
- package/dist/kit/wave-engine.js +1 -0
- package/dist/recipes/loader.js +6 -0
- package/dist/recipes/schema.js +2 -0
- package/dist/risk/classifier.js +2 -0
- package/dist/risk/sha-check.js +2 -0
- package/dist/state/backups.js +2 -0
- package/dist/state/envelope.js +2 -0
- package/dist/state/generated-manifest.js +3 -0
- package/dist/state/manifest-key.js +2 -0
- package/dist/state/migrations/index.js +1 -0
- package/dist/state/migrations/v0-to-v1.js +2 -0
- package/dist/state/retired-renders.js +2 -0
- package/dist/templates/.nvmrc.ejs +1 -0
- package/dist/templates/HANDOFF.template.md +45 -0
- package/dist/templates/__tests__/contract/error-shape.contract.test.ts.ejs +47 -0
- package/dist/templates/agents-md/AGENTS.md.ejs +517 -0
- package/dist/templates/api-e2e/README.md.ejs +33 -0
- package/dist/templates/api-e2e/go-httptest.go.ejs +43 -0
- package/dist/templates/api-e2e/java-restassured.java.ejs +28 -0
- package/dist/templates/api-e2e/kotlin-restassured.kt.ejs +30 -0
- package/dist/templates/api-e2e/manifest.json.ejs +8 -0
- package/dist/templates/api-e2e/postman.collection.json.ejs +30 -0
- package/dist/templates/api-e2e/python-httpx.py.ejs +17 -0
- package/dist/templates/api-e2e/run.sh.ejs +61 -0
- package/dist/templates/api-e2e/ts-supertest.test.ts.ejs +18 -0
- package/dist/templates/archunit/AntiCyclicTest.java.ejs +29 -0
- package/dist/templates/archunit/AntiProformaExempt.java.ejs +35 -0
- package/dist/templates/archunit/AntiProformaTest.java.ejs +104 -0
- package/dist/templates/archunit/ArchitectureTest.java.ejs +87 -0
- package/dist/templates/archunit/DependencyFlowTest.java.ejs +55 -0
- package/dist/templates/archunit/DomainPurityTest.java.ejs +47 -0
- package/dist/templates/archunit/NamingConventionsTest.java.ejs +54 -0
- package/dist/templates/archunit/NoH2ArchTest.java.ejs +30 -0
- package/dist/templates/archunit/NoMockMvcTest.java.ejs +71 -0
- package/dist/templates/archunit/PortsIndependenceTest.java.ejs +55 -0
- package/dist/templates/archunit/RestAssuredArchTest.java.ejs +32 -0
- package/dist/templates/archunit/RestAssuredBaseIT.java.ejs +66 -0
- package/dist/templates/archunit/TestCoverageArchTest.java.ejs +29 -0
- package/dist/templates/archunit/arch-test-deps-maven.md.ejs +42 -0
- package/dist/templates/archunit/arch-test-deps.gradle.ejs +14 -0
- package/dist/templates/audit/gdpr/check-gdpr-controls.mjs.ejs +102 -0
- package/dist/templates/audit/gdpr/controls-to-gates.md.ejs +42 -0
- package/dist/templates/audit/gdpr/data-flow-map.md.ejs +30 -0
- package/dist/templates/audit/gdpr/dpia.md.ejs +45 -0
- package/dist/templates/audit/generic/audit-gate-rules.md.ejs +24 -0
- package/dist/templates/audit/generic/audit-trail-policy.md.ejs +38 -0
- package/dist/templates/audit/iso27001/iso27001-controls-gate-map.md.ejs +60 -0
- package/dist/templates/auth/setup.md.ejs +661 -0
- package/dist/templates/behavioral-tests/ExampleBehavioralTest.java.ejs +67 -0
- package/dist/templates/behavioral-tests/TESTING_POLICY.md.ejs +116 -0
- package/dist/templates/behavioral-tests/bdd/ExampleBddIT.java.ejs +19 -0
- package/dist/templates/behavioral-tests/bdd/ExampleSteps.java.ejs +61 -0
- package/dist/templates/behavioral-tests/bdd/example.feature.ejs +14 -0
- package/dist/templates/behavioral-tests/bdd/example.steps.ts.ejs +37 -0
- package/dist/templates/behavioral-tests/bdd/example_bdd_test.rs.ejs +64 -0
- package/dist/templates/behavioral-tests/bdd/example_test.go.ejs +80 -0
- package/dist/templates/behavioral-tests/bdd/test_example_bdd.py.ejs +47 -0
- package/dist/templates/behavioral-tests/eslint-playwright.json.ejs +10 -0
- package/dist/templates/behavioral-tests/eslint.config.playwright.mjs.ejs +29 -0
- package/dist/templates/behavioral-tests/example.behavioral.test.ts.ejs +47 -0
- package/dist/templates/behavioral-tests/example_behavioral_test.go.ejs +51 -0
- package/dist/templates/behavioral-tests/example_behavioral_test.rs.ejs +47 -0
- package/dist/templates/behavioral-tests/test_example_behavioral.py.ejs +40 -0
- package/dist/templates/boundaries/.eslintrc-boundaries.cjs.ejs +81 -0
- package/dist/templates/boundaries/.eslintrc-frontend-spa.cjs.ejs +79 -0
- package/dist/templates/boundaries/.importlinter.ejs +48 -0
- package/dist/templates/boundaries/check-boundaries-go.mjs.ejs +94 -0
- package/dist/templates/boundaries/check-boundaries-python.mjs.ejs +118 -0
- package/dist/templates/boundaries/check-boundaries-rust.mjs.ejs +111 -0
- package/dist/templates/boundaries/check-boundaries.mjs.ejs +34 -0
- package/dist/templates/boundaries/clippy.toml.ejs +50 -0
- package/dist/templates/boundaries/deny.toml.ejs +56 -0
- package/dist/templates/boundaries/eslint.config.boundaries.mjs.ejs +112 -0
- package/dist/templates/boundaries/eslint.config.frontend-spa.mjs.ejs +93 -0
- package/dist/templates/boundaries/golangci-boundaries.yml.ejs +70 -0
- package/dist/templates/boundaries/ruff-boundaries.toml.ejs +32 -0
- package/dist/templates/claude/CLAUDE.md.ejs +78 -0
- package/dist/templates/claude/agents/agent-write-classes.json +30 -0
- package/dist/templates/claude/agents/bridge-reviewer.md.ejs +68 -0
- package/dist/templates/claude/agents/codebase-scanner.md.ejs +69 -0
- package/dist/templates/claude/agents/context-checker.md.ejs +73 -0
- package/dist/templates/claude/agents/red-team.md.ejs +134 -0
- package/dist/templates/claude/commands/close-gold-gap.md.ejs +43 -0
- package/dist/templates/claude/commands/drain.md.ejs +81 -0
- package/dist/templates/claude/commands/gold-audit.md.ejs +43 -0
- package/dist/templates/claude/commands/impact.md.ejs +39 -0
- package/dist/templates/claude/commands/levelup.md.ejs +61 -0
- package/dist/templates/claude/commands/ship.md.ejs +902 -0
- package/dist/templates/claude/commands/tabletop.md.ejs +46 -0
- package/dist/templates/claude/commands/task.md.ejs +87 -0
- package/dist/templates/claude/commands/wt-close.md.ejs +58 -0
- package/dist/templates/claude/commands/wt-list.md.ejs +48 -0
- package/dist/templates/claude/commands/wt-open.md.ejs +61 -0
- package/dist/templates/claude/commands/wt-prune.md.ejs +38 -0
- package/dist/templates/claude/hooks/check-circular-deps.mjs.ejs +56 -0
- package/dist/templates/claude/hooks/check-no-orphan-todo.mjs.ejs +45 -0
- package/dist/templates/claude/hooks/check-no-pii.mjs.ejs +121 -0
- package/dist/templates/claude/hooks/check-no-placeholders.mjs.ejs +71 -0
- package/dist/templates/claude/hooks/check-no-skipped-tests.mjs +80 -0
- package/dist/templates/claude/hooks/check-no-unused-exports.mjs +62 -0
- package/dist/templates/claude/hooks/closer-mode-guard.mjs.ejs +102 -0
- package/dist/templates/claude/hooks/debug-state-on-failure.mjs.ejs +98 -0
- package/dist/templates/claude/hooks/enforce-gate-before-pr.mjs +142 -0
- package/dist/templates/claude/hooks/enforce-read-only.mjs +28 -0
- package/dist/templates/claude/hooks/exitplanmode-banner.mjs.ejs +43 -0
- package/dist/templates/claude/hooks/guard-done-evidence.mjs.ejs +85 -0
- package/dist/templates/claude/hooks/guard-task-completion.mjs.ejs +56 -0
- package/dist/templates/claude/hooks/hooks.mjs.ejs +127 -0
- package/dist/templates/claude/hooks/lib.mjs.ejs +523 -0
- package/dist/templates/claude/hooks/post-brainstorm-stop.mjs +48 -0
- package/dist/templates/claude/hooks/post-commit-check.mjs.ejs +65 -0
- package/dist/templates/claude/hooks/post-commit-checklists/go/backend.ejs +4 -0
- package/dist/templates/claude/hooks/post-commit-checklists/go/docs.ejs +4 -0
- package/dist/templates/claude/hooks/post-commit-checklists/go/frontend.ejs +4 -0
- package/dist/templates/claude/hooks/post-commit-checklists/java/backend.ejs +4 -0
- package/dist/templates/claude/hooks/post-commit-checklists/java/docs.ejs +4 -0
- package/dist/templates/claude/hooks/post-commit-checklists/java/frontend.ejs +4 -0
- package/dist/templates/claude/hooks/post-commit-checklists/python/backend.ejs +4 -0
- package/dist/templates/claude/hooks/post-commit-checklists/python/docs.ejs +4 -0
- package/dist/templates/claude/hooks/post-commit-checklists/python/frontend.ejs +4 -0
- package/dist/templates/claude/hooks/post-commit-checklists/rust/backend.ejs +5 -0
- package/dist/templates/claude/hooks/post-commit-checklists/rust/docs.ejs +4 -0
- package/dist/templates/claude/hooks/post-commit-checklists/rust/frontend.ejs +4 -0
- package/dist/templates/claude/hooks/post-commit-checklists/ts/backend.ejs +4 -0
- package/dist/templates/claude/hooks/post-commit-checklists/ts/docs.ejs +4 -0
- package/dist/templates/claude/hooks/post-commit-checklists/ts/frontend.ejs +5 -0
- package/dist/templates/claude/hooks/post-edit-dispatch.mjs.ejs +73 -0
- package/dist/templates/claude/hooks/post-subagent-release.mjs +80 -0
- package/dist/templates/claude/hooks/pre-compact.mjs.ejs +79 -0
- package/dist/templates/claude/hooks/pre-edit-plan-anchor.mjs.ejs +225 -0
- package/dist/templates/claude/hooks/pre-edit-ssot-guard.mjs +204 -0
- package/dist/templates/claude/hooks/pre-spawn-worktree-guard.mjs +129 -0
- package/dist/templates/claude/hooks/skill-forced-eval.mjs.ejs +281 -0
- package/dist/templates/claude/hooks/stop-dangerous.mjs +86 -0
- package/dist/templates/claude/hooks/stop-evidence-guard.mjs.ejs +245 -0
- package/dist/templates/claude/hooks/stop-finding-loss.mjs.ejs +168 -0
- package/dist/templates/claude/hooks/wiki-on-commit.mjs.ejs +38 -0
- package/dist/templates/claude/knowledge-map.json.ejs +26 -0
- package/dist/templates/claude/rules/05-agent-lifecycle.md +7 -0
- package/dist/templates/claude/rules/25-todo-folder-policy.md +5 -0
- package/dist/templates/claude/rules/40-context-economy.md +32 -0
- package/dist/templates/claude/rules/45-mcp-fallback.md +25 -0
- package/dist/templates/claude/rules/50-batch-execution.md +75 -0
- package/dist/templates/claude/rules/55-brainstorm-terminal-state.md +44 -0
- package/dist/templates/claude/rules/60-incidental-capture.md +43 -0
- package/dist/templates/claude/rules/75-impact-vault-reading.md +43 -0
- package/dist/templates/claude/rules/90-exec-protocol.md.ejs +40 -0
- package/dist/templates/claude/rules/95-closer-mode.md +45 -0
- package/dist/templates/claude/settings.json.ejs +165 -0
- package/dist/templates/claude/skills/architect-review/SKILL.md.ejs +82 -0
- package/dist/templates/claude/skills/brainstorming/SKILL.md.ejs +86 -0
- package/dist/templates/claude/skills/clean-code/SKILL.md.ejs +39 -0
- package/dist/templates/claude/skills/close-gold-gap/SKILL.md.ejs +58 -0
- package/dist/templates/claude/skills/codebase-audit/SKILL.md.ejs +88 -0
- package/dist/templates/claude/skills/configure/SKILL.md.ejs +72 -0
- package/dist/templates/claude/skills/epic-decompose/SKILL.md.ejs +86 -0
- package/dist/templates/claude/skills/gold-audit/SKILL.md.ejs +91 -0
- package/dist/templates/claude/skills/impact/SKILL.md.ejs +104 -0
- package/dist/templates/claude/skills/levelup/SKILL.md.ejs +146 -0
- package/dist/templates/claude/skills/tabletop/SKILL.md.ejs +118 -0
- package/dist/templates/claude/skills/tdd/SKILL.md.ejs +157 -0
- package/dist/templates/claude/skills/understand-code/SKILL.md.ejs +93 -0
- package/dist/templates/claude/skills/verification/SKILL.md.ejs +68 -0
- package/dist/templates/claude/skills/wave-drain/SKILL.md.ejs +491 -0
- package/dist/templates/codex/CODEX.md.ejs +140 -0
- package/dist/templates/codex/codex-adapter.mjs +132 -0
- package/dist/templates/codex/config.toml.ejs +189 -0
- package/dist/templates/compliance/compliance-mapping.md.ejs +124 -0
- package/dist/templates/compliance/compliance-menu.md.ejs +89 -0
- package/dist/templates/contract-testing/CONTRACTS_POLICY.md.ejs +30 -0
- package/dist/templates/contract-testing/api-snapshots/config-keys-baseline.json.ejs +1 -0
- package/dist/templates/contract-testing/api-snapshots/config-response-baseline.json.ejs +1 -0
- package/dist/templates/contract-testing/api-snapshots/enum-values-baseline.json.ejs +1 -0
- package/dist/templates/contract-testing/api-snapshots/error-shape-baseline.json.ejs +6 -0
- package/dist/templates/contract-testing/api-snapshots/openapi-baseline.json.ejs +12 -0
- package/dist/templates/contract-testing/api-snapshots/openapi-content-types-baseline.json.ejs +3 -0
- package/dist/templates/contract-testing/api-snapshots/openapi-paths-baseline.json.ejs +1 -0
- package/dist/templates/contract-testing/api-snapshots/openapi-required-fields-baseline.json.ejs +1 -0
- package/dist/templates/contract-testing/api-snapshots/openapi-response-status-baseline.json.ejs +3 -0
- package/dist/templates/contract-testing/api-snapshots/test-snapshot.json.ejs +4 -0
- package/dist/templates/contract-testing/env/.env.pact.ejs +4 -0
- package/dist/templates/contract-testing/graphql/GraphqlSchemaTest.java.ejs +29 -0
- package/dist/templates/contract-testing/graphql/graphql-inspector.test.ts.ejs +20 -0
- package/dist/templates/contract-testing/graphql/graphql_schema_test.go.ejs +27 -0
- package/dist/templates/contract-testing/graphql/graphql_schema_test.rs.ejs +27 -0
- package/dist/templates/contract-testing/graphql/test_graphql_schema.py.ejs +21 -0
- package/dist/templates/contract-testing/grpc/GrpcContractTest.java.ejs +23 -0
- package/dist/templates/contract-testing/grpc/buf-breaking.yml.ejs +6 -0
- package/dist/templates/contract-testing/grpc/buf.yaml.ejs +11 -0
- package/dist/templates/contract-testing/grpc/grpc-contract.test.ts.ejs +16 -0
- package/dist/templates/contract-testing/grpc/grpc_contract_test.go.ejs +22 -0
- package/dist/templates/contract-testing/grpc/grpc_contract_test.rs.ejs +22 -0
- package/dist/templates/contract-testing/grpc/test_grpc_contract.py.ejs +18 -0
- package/dist/templates/contract-testing/message-queue/SchemaRegistryCheckIT.java.ejs +44 -0
- package/dist/templates/contract-testing/message-queue/schema-registry-check.ts.ejs +42 -0
- package/dist/templates/contract-testing/message-queue/schema_registry_test.go.ejs +71 -0
- package/dist/templates/contract-testing/message-queue/schema_registry_test.rs.ejs +61 -0
- package/dist/templates/contract-testing/message-queue/test_schema_registry.py.ejs +31 -0
- package/dist/templates/contract-testing/pact-samples/assignment-response.json.ejs +7 -0
- package/dist/templates/contract-testing/pact-samples/availability-response.json.ejs +13 -0
- package/dist/templates/contract-testing/pact-samples/availability-rule-response.json.ejs +8 -0
- package/dist/templates/contract-testing/pact-samples/capacity-response.json.ejs +11 -0
- package/dist/templates/contract-testing/pact-samples/fully-booked-response.json.ejs +6 -0
- package/dist/templates/contract-testing/pact-samples/schedule-override-response.json.ejs +7 -0
- package/dist/templates/contract-testing/rest-owned/PactVerificationIT.java.ejs +31 -0
- package/dist/templates/contract-testing/rest-owned/pact-consumer.test.ts.ejs +36 -0
- package/dist/templates/contract-testing/rest-owned/pact-deps.gradle.ejs +15 -0
- package/dist/templates/contract-testing/rest-owned/pact_consumer_test.go.ejs +48 -0
- package/dist/templates/contract-testing/rest-owned/pact_consumer_test.rs.ejs +23 -0
- package/dist/templates/contract-testing/rest-owned/test_pact_consumer.py.ejs +35 -0
- package/dist/templates/contract-testing/rest-public/OpenApiDiffIT.java.ejs +44 -0
- package/dist/templates/contract-testing/rest-public/export-openapi-java.gradle.ejs +13 -0
- package/dist/templates/contract-testing/rest-public/export-openapi.mjs.ejs +21 -0
- package/dist/templates/contract-testing/rest-public/export_openapi.go.ejs +30 -0
- package/dist/templates/contract-testing/rest-public/export_openapi.py.ejs +27 -0
- package/dist/templates/contract-testing/rest-public/export_openapi.rs.ejs +32 -0
- package/dist/templates/contract-testing/rest-public/openapi-diff.ts.ejs +42 -0
- package/dist/templates/contract-testing/rest-public/openapi_diff_test.go.ejs +35 -0
- package/dist/templates/contract-testing/rest-public/openapi_diff_test.rs.ejs +36 -0
- package/dist/templates/contract-testing/rest-public/test_openapi_diff.py.ejs +32 -0
- package/dist/templates/coverage/.coveragerc.ejs +26 -0
- package/dist/templates/coverage/.tarpaulin.toml.ejs +30 -0
- package/dist/templates/coverage/Cargo.toml.profile.release.ejs +24 -0
- package/dist/templates/coverage/jacoco-maven-setup.md.ejs +72 -0
- package/dist/templates/coverage/jacoco.gradle.ejs +49 -0
- package/dist/templates/coverage/kover.gradle.ejs +35 -0
- package/dist/templates/coverage/vitest.browser.config.ts.ejs +47 -0
- package/dist/templates/coverage/vitest.config.ts.ejs +47 -0
- package/dist/templates/docs/CODING_STANDARDS.md.ejs +81 -0
- package/dist/templates/docs/FEATURE_MATRIX.md.ejs +84 -0
- package/dist/templates/docs/GAP.md.ejs +58 -0
- package/dist/templates/docs/ISO27001_ANNEX_A.md.ejs +144 -0
- package/dist/templates/docs/MASTER_TEST_PLAN.md.ejs +52 -0
- package/dist/templates/docs/POST_MERGE_REVIEW_TEMPLATE.md.ejs +63 -0
- package/dist/templates/docs/SECURE_CODING_CHECKLIST.md.ejs +61 -0
- package/dist/templates/docs/adr/ADR-000_template.md.ejs +28 -0
- package/dist/templates/docs/bugs/bug-analysis.md.ejs +47 -0
- package/dist/templates/docs/bugs/bug-report.md.ejs +51 -0
- package/dist/templates/docs/bugs/bug-verification.md.ejs +42 -0
- package/dist/templates/docs/runbooks/deployment.md.ejs +119 -0
- package/dist/templates/docs/runbooks/prod-checklist.md.ejs +90 -0
- package/dist/templates/docs/runbooks/rollback.md.ejs +124 -0
- package/dist/templates/docs/runbooks/troubleshooting.md.ejs +130 -0
- package/dist/templates/docs/skeletons/arc42-canvas.md.ejs +46 -0
- package/dist/templates/docs/skeletons/arc42-full.md.ejs +59 -0
- package/dist/templates/docs/skeletons/decision-registry.md.ejs +38 -0
- package/dist/templates/docs/skeletons/er-model.md.ejs +19 -0
- package/dist/templates/docs/skeletons/glossary.md.ejs +8 -0
- package/dist/templates/docs/skeletons/governance.md.ejs +13 -0
- package/dist/templates/docs/skeletons/slo.md.ejs +21 -0
- package/dist/templates/docs/skeletons/technical-debt.md.ejs +8 -0
- package/dist/templates/docs/skeletons/test-strategy.md.ejs +14 -0
- package/dist/templates/docs/skeletons/threat-model-4q.md.ejs +20 -0
- package/dist/templates/docs/skeletons/threat-model-stride.md.ejs +22 -0
- package/dist/templates/docs/specs/atomic-task-list.md.ejs +57 -0
- package/dist/templates/docs/steering/product.md.ejs +44 -0
- package/dist/templates/docs/steering/structure.md.ejs +49 -0
- package/dist/templates/docs/steering/tech.md.ejs +53 -0
- package/dist/templates/documentation/cli-catalog.md.ejs +21 -0
- package/dist/templates/e2e/E2E_CONSTITUTION.md.ejs +77 -0
- package/dist/templates/e2e/playwright-python/conftest.py.ejs +22 -0
- package/dist/templates/e2e/playwright-python/run_axe.py.ejs +99 -0
- package/dist/templates/e2e/playwright-python/test_a11y.py.ejs +38 -0
- package/dist/templates/e2e/playwright-python/test_smoke.py.ejs +28 -0
- package/dist/templates/e2e/playwright-ts/a11y.spec.ts.ejs +20 -0
- package/dist/templates/e2e/playwright-ts/render-smoke.spec.ts.ejs +90 -0
- package/dist/templates/e2e/playwright-ts/run-axe.ts.ejs +74 -0
- package/dist/templates/e2e/smoke-journeys/journeys.spec.ts.ejs +53 -0
- package/dist/templates/evidence-files.json.ejs +13 -0
- package/dist/templates/frontend/FE_DESIGN_PRINCIPLES.md.ejs +115 -0
- package/dist/templates/frontend/FRONTEND_CONSTITUTION.md.ejs +170 -0
- package/dist/templates/frontend/design-tokens.json.ejs +107 -0
- package/dist/templates/frontend/vrt-setup.md.ejs +83 -0
- package/dist/templates/githooks/commit-msg.ejs +60 -0
- package/dist/templates/githooks/pre-commit.ejs +95 -0
- package/dist/templates/githooks/pre-push.ejs +251 -0
- package/dist/templates/githooks/setup-hooks.sh.ejs +8 -0
- package/dist/templates/github/PULL_REQUEST_TEMPLATE.md +37 -0
- package/dist/templates/github/PULL_REQUEST_TEMPLATE.md.ejs +52 -0
- package/dist/templates/github/actions/build-cache/action.yml.ejs +84 -0
- package/dist/templates/github/actions/nas-ssh/action.yml.ejs +53 -0
- package/dist/templates/github/actions/setup-java-maven/action.yml.ejs +53 -0
- package/dist/templates/github/actions/setup-node-pnpm/action.yml.ejs +39 -0
- package/dist/templates/github/actions/sign-and-attest/action.yml.ejs +53 -0
- package/dist/templates/github/dependabot.yml.ejs +66 -0
- package/dist/templates/github/extended-ci-paths.txt.ejs +38 -0
- package/dist/templates/github/issue-templates/bug-report.yml +72 -0
- package/dist/templates/github/issue-templates/compliance-item.yml.ejs +75 -0
- package/dist/templates/github/issue-templates/config.yml +2 -0
- package/dist/templates/github/issue-templates/epic.yml +66 -0
- package/dist/templates/github/issue-templates/feature-request.yml +24 -0
- package/dist/templates/github/issue-templates/task-brief.yml.ejs +125 -0
- package/dist/templates/github/labels.yml.ejs +161 -0
- package/dist/templates/github/scripts/sticky-failure-issue.sh.ejs +61 -0
- package/dist/templates/github/workflows/01-pr-fast.yml.ejs +1089 -0
- package/dist/templates/github/workflows/02-pr-extended.yml.ejs +512 -0
- package/dist/templates/github/workflows/03-human-approval.yml.ejs +76 -0
- package/dist/templates/github/workflows/04-deploy-test.yml.ejs +425 -0
- package/dist/templates/github/workflows/05-release.yml.ejs +813 -0
- package/dist/templates/github/workflows/06-nightly-lite.yml.ejs +125 -0
- package/dist/templates/github/workflows/06-nightly.yml.ejs +25 -0
- package/dist/templates/github/workflows/07-weekly-lite.yml.ejs +221 -0
- package/dist/templates/github/workflows/07-weekly.yml.ejs +23 -0
- package/dist/templates/github/workflows/08-monthly.yml.ejs +23 -0
- package/dist/templates/github/workflows/09-heartbeat.yml.ejs +268 -0
- package/dist/templates/github/workflows/10-deploy-prod.yml.ejs +144 -0
- package/dist/templates/github/workflows/11-k6-on-demand.yml.ejs +43 -0
- package/dist/templates/github/workflows/12-mutation-scheduled.yml.ejs +100 -0
- package/dist/templates/github/workflows/13-archunit-extended.yml.ejs +33 -0
- package/dist/templates/github/workflows/14-license-scan.yml.ejs +45 -0
- package/dist/templates/github/workflows/15-codeql.yml.ejs +117 -0
- package/dist/templates/github/workflows/16-frontend-quality.yml.ejs +154 -0
- package/dist/templates/github/workflows/17-ossf-scorecard.yml.ejs +46 -0
- package/dist/templates/github/workflows/18-frontend-lane.yml.ejs +50 -0
- package/dist/templates/github/workflows/_ai-draft-check.yml.ejs +44 -0
- package/dist/templates/github/workflows/_contract-postman.yml.ejs +93 -0
- package/dist/templates/github/workflows/_cosign-copy/aws-ecs.ejs +90 -0
- package/dist/templates/github/workflows/_cosign-copy/azure-container-app.ejs +97 -0
- package/dist/templates/github/workflows/_cosign-copy/gcp-cloud-run.ejs +102 -0
- package/dist/templates/github/workflows/_cosign-copy/ghcr.ejs +76 -0
- package/dist/templates/github/workflows/_cosign-copy/nas-compose.ejs +69 -0
- package/dist/templates/github/workflows/_deploy/aws-ecs.ejs +78 -0
- package/dist/templates/github/workflows/_deploy/azure-container-app.ejs +59 -0
- package/dist/templates/github/workflows/_deploy/gcp-cloud-run.ejs +71 -0
- package/dist/templates/github/workflows/_deploy/ghcr.ejs +19 -0
- package/dist/templates/github/workflows/_deploy/nas-compose.ejs +45 -0
- package/dist/templates/github/workflows/_k6-runner.yml.ejs +107 -0
- package/dist/templates/github/workflows/_label-on-approve.yml.ejs +44 -0
- package/dist/templates/github/workflows/_label-sync.yml.ejs +58 -0
- package/dist/templates/github/workflows/_monthly.yml.ejs +343 -0
- package/dist/templates/github/workflows/_nightly.yml.ejs +826 -0
- package/dist/templates/github/workflows/_notify.yml.ejs +96 -0
- package/dist/templates/github/workflows/_partials/macos-keychain-bypass.ejs +6 -0
- package/dist/templates/github/workflows/_partials/macos-keychain-restore.ejs +6 -0
- package/dist/templates/github/workflows/_partials/scheduled-heavy-jobs.ejs +117 -0
- package/dist/templates/github/workflows/_partials/sigstore-preflight.ejs +8 -0
- package/dist/templates/github/workflows/_partials/trivy-fs-java.ejs +27 -0
- package/dist/templates/github/workflows/_post-merge-notify.yml.ejs +228 -0
- package/dist/templates/github/workflows/_pr-staleness.yml.ejs +85 -0
- package/dist/templates/github/workflows/_shared-security.yml.ejs +132 -0
- package/dist/templates/github/workflows/_sigstore-retry-sign.yml.ejs +102 -0
- package/dist/templates/github/workflows/_weekly.yml.ejs +313 -0
- package/dist/templates/github/workflows/drift-shadow.yml.ejs +51 -0
- package/dist/templates/github/workflows/five-lane/ci.yml.ejs +54 -0
- package/dist/templates/github/workflows/five-lane/nightly.yml.ejs +70 -0
- package/dist/templates/github/workflows/five-lane/release.yml.ejs +53 -0
- package/dist/templates/github/workflows/five-lane/weekly.yml.ejs +72 -0
- package/dist/templates/github/workflows/issue-state.yml.ejs +93 -0
- package/dist/templates/global-invariants/GLOBAL_INVARIANTS.md.ejs +34 -0
- package/dist/templates/governance/RACI.md.ejs +21 -0
- package/dist/templates/governance/ci-mental-model.md.ejs +268 -0
- package/dist/templates/governance/contract-integrity-policy.md.ejs +116 -0
- package/dist/templates/governance/enterprise-compliance-baseline.md.ejs +111 -0
- package/dist/templates/governance/evidence-retention.md.ejs +43 -0
- package/dist/templates/governance/gdpr-erasure-runbook.md.ejs +165 -0
- package/dist/templates/governance/qa-audit-phases.md.ejs +129 -0
- package/dist/templates/governance/risk-assessment-template.md.ejs +105 -0
- package/dist/templates/governance/risk-register.md.ejs +76 -0
- package/dist/templates/governance/solo-dev-exception.md.ejs +96 -0
- package/dist/templates/governance/validation-evidence.md.ejs +131 -0
- package/dist/templates/infra/azure/containerapp.tpl.yaml.ejs +74 -0
- package/dist/templates/infra/nas-compose/deploy.sh.ejs +114 -0
- package/dist/templates/integration-testing/AbstractIntegrationTest.java.ejs +36 -0
- package/dist/templates/integration-testing/NoH2ArchTest.java.ejs +24 -0
- package/dist/templates/integration-testing/conftest.py.ejs +20 -0
- package/dist/templates/integration-testing/db_fixture.rs.ejs +48 -0
- package/dist/templates/integration-testing/eslint-no-fake-db.json.ejs +19 -0
- package/dist/templates/integration-testing/eslint.config.no-fake-db.mjs.ejs +46 -0
- package/dist/templates/integration-testing/main_test.go.ejs +53 -0
- package/dist/templates/integration-testing/main_test_sqlite.go.ejs +37 -0
- package/dist/templates/integration-testing/test-setup.ts.ejs +26 -0
- package/dist/templates/integration-testing/testcontainers-deps.gradle.ejs +9 -0
- package/dist/templates/java/DeprecationInterceptor.java.ejs +50 -0
- package/dist/templates/java/archunit-hexagonal.ejs +69 -0
- package/dist/templates/java/modulith/ApplicationModulesTest.java.ejs +21 -0
- package/dist/templates/java/modulith/modulith-deps.gradle.ejs +13 -0
- package/dist/templates/java/modulith/modulith-maven-setup.md.ejs +21 -0
- package/dist/templates/java/pharma/AuditEvent.java.ejs +138 -0
- package/dist/templates/java/pharma/AuditMapper.java.ejs +60 -0
- package/dist/templates/java/pharma/archunit-pharma.ejs +128 -0
- package/dist/templates/kit/GLOBAL_KIT.md.ejs +11 -0
- package/dist/templates/kit/dim.md.ejs +33 -0
- package/dist/templates/llms-txt.config.json.ejs +22 -0
- package/dist/templates/local-wrapper/.env.example.ejs +15 -0
- package/dist/templates/local-wrapper/Makefile.ejs +44 -0
- package/dist/templates/local-wrapper/run.sh.ejs +5 -0
- package/dist/templates/middleware/410-gone-handler.ts.ejs +41 -0
- package/dist/templates/middleware/correlation-id.ts.ejs +32 -0
- package/dist/templates/middleware/deprecation.ts.ejs +45 -0
- package/dist/templates/middleware/error-handler.ts.ejs +73 -0
- package/dist/templates/middleware/payload-size-limit.ts.ejs +51 -0
- package/dist/templates/mutation/README.md.ejs +67 -0
- package/dist/templates/mutation/cargo-mutants.toml.ejs +9 -0
- package/dist/templates/mutation/mutmut-config.toml.ejs +7 -0
- package/dist/templates/mutation/parse-mutants.mjs.ejs +44 -0
- package/dist/templates/mutation/parse-mutmut.py.ejs +44 -0
- package/dist/templates/mutation/pitest-l2-setup.md.ejs +66 -0
- package/dist/templates/mutation/pitest-maven-setup.md.ejs +64 -0
- package/dist/templates/mutation/pitest.gradle.ejs +23 -0
- package/dist/templates/mutation/stryker.conf.json.ejs +17 -0
- package/dist/templates/observability/setup.md.ejs +495 -0
- package/dist/templates/operations/handbook.md.ejs +217 -0
- package/dist/templates/perf/bundle-budget.json.ejs +29 -0
- package/dist/templates/perf/k6/reports/csv-report.py.ejs +91 -0
- package/dist/templates/perf/k6/reports/html-report.py.ejs +114 -0
- package/dist/templates/perf/k6/reports/json-report.py.ejs +74 -0
- package/dist/templates/perf/k6/scenarios/breakpoint.js.ejs +26 -0
- package/dist/templates/perf/k6/scenarios/burst.js.ejs +43 -0
- package/dist/templates/perf/k6/scenarios/endurance.js.ejs +36 -0
- package/dist/templates/perf/k6/scenarios/load.js.ejs +26 -0
- package/dist/templates/perf/k6/scenarios/ramp-down.js.ejs +29 -0
- package/dist/templates/perf/k6/scenarios/ramp-up.js.ejs +32 -0
- package/dist/templates/perf/k6/scenarios/smoke.js.ejs +23 -0
- package/dist/templates/perf/k6/scenarios/soak.js.ejs +26 -0
- package/dist/templates/perf/k6/scenarios/spike.js.ejs +29 -0
- package/dist/templates/perf/k6/scenarios/steady-state.js.ejs +31 -0
- package/dist/templates/perf/k6/scenarios/stress.js.ejs +29 -0
- package/dist/templates/perf/k6/scenarios/volume.js.ejs +36 -0
- package/dist/templates/perf/k6/seed/test-data.sql.ejs +59 -0
- package/dist/templates/perf/lighthouserc.json.ejs +41 -0
- package/dist/templates/quality/iso9001/CAPA_LOG.md.ejs +36 -0
- package/dist/templates/quality/iso9001/DOCUMENT_CONTROL.md.ejs +36 -0
- package/dist/templates/quality/iso9001/REQUIREMENTS_TRACEABILITY.md.ejs +61 -0
- package/dist/templates/regulated/overlay.json.ejs +26 -0
- package/dist/templates/regulated/regulated-overlay.md.ejs +40 -0
- package/dist/templates/resilience/RESILIENCE.md.ejs +310 -0
- package/dist/templates/root/.gitignore.ejs +85 -0
- package/dist/templates/root/CODEOWNERS.ejs +18 -0
- package/dist/templates/root/CONTRIBUTING.md.ejs +62 -0
- package/dist/templates/root/SECURITY.md.ejs +19 -0
- package/dist/templates/root/TEST_TAXONOMY.md.ejs +100 -0
- package/dist/templates/root/commitlint.config.js.ejs +4 -0
- package/dist/templates/root/docs/METHOD/CANONICAL_PATHS.md.ejs +24 -0
- package/dist/templates/root/docs/METHOD/ENGINEERING_DEFAULTS.md.ejs +136 -0
- package/dist/templates/root/docs/METHOD/KNOWLEDGE_MAP.md.ejs +90 -0
- package/dist/templates/root/docs/METHOD/PATTERNS_CATALOG.md.ejs +51 -0
- package/dist/templates/root/docs/METHOD/REUSE_REGISTRY.md.ejs +26 -0
- package/dist/templates/root/docs/METHOD/REUSE_REGISTRY_SPEC.md.ejs +80 -0
- package/dist/templates/root/docs/METHOD/SSOT_CORE_SET.md.ejs +62 -0
- package/dist/templates/root/docs/METHOD/TRACK_ROUTER.md.ejs +39 -0
- package/dist/templates/root/docs/SYSTEM/CANON.md.ejs +359 -0
- package/dist/templates/root/docs/SYSTEM/FAIL_CLOSED.md.ejs +171 -0
- package/dist/templates/root/editorconfig.ejs +39 -0
- package/dist/templates/root/tsconfig.json.ejs +21 -0
- package/dist/templates/rust/clippy.toml.ejs +14 -0
- package/dist/templates/schemas/milestone.schema.json.ejs +164 -0
- package/dist/templates/schemas/rtm-verdict.schema.json.ejs +52 -0
- package/dist/templates/schemas/source-record.schema.json.ejs +91 -0
- package/dist/templates/schemas/tabletop-evidence.schema.json.ejs +53 -0
- package/dist/templates/schemas/use-case.schema.json.ejs +59 -0
- package/dist/templates/scripts/apply-branch-protection.mjs.ejs +70 -0
- package/dist/templates/scripts/audit-toolchain.mjs.ejs +112 -0
- package/dist/templates/scripts/bg-run.sh.ejs +59 -0
- package/dist/templates/scripts/capacity-probe.mjs.ejs +147 -0
- package/dist/templates/scripts/capture-debt-baseline.mjs.ejs +99 -0
- package/dist/templates/scripts/check-acceptance.mjs.ejs +298 -0
- package/dist/templates/scripts/check-action-pins.mjs.ejs +215 -0
- package/dist/templates/scripts/check-agent-return.mjs.ejs +177 -0
- package/dist/templates/scripts/check-all.mjs.ejs +1746 -0
- package/dist/templates/scripts/check-anti-fake-green.mjs.ejs +80 -0
- package/dist/templates/scripts/check-anti-proforma.mjs.ejs +547 -0
- package/dist/templates/scripts/check-api-e2e.mjs.ejs +106 -0
- package/dist/templates/scripts/check-arc42-slots.mjs.ejs +25 -0
- package/dist/templates/scripts/check-assertion-delta.mjs.ejs +287 -0
- package/dist/templates/scripts/check-audit-dry-pass.mjs.ejs +176 -0
- package/dist/templates/scripts/check-bundle-size.mjs.ejs +151 -0
- package/dist/templates/scripts/check-canonical-paths.mjs.ejs +39 -0
- package/dist/templates/scripts/check-ci-tiers.mjs.ejs +111 -0
- package/dist/templates/scripts/check-claude-md-lint.mjs.ejs +142 -0
- package/dist/templates/scripts/check-collab-mode-wired.mjs.ejs +60 -0
- package/dist/templates/scripts/check-commit-footer-rationale.mjs.ejs +170 -0
- package/dist/templates/scripts/check-constraint-scan.mjs.ejs +681 -0
- package/dist/templates/scripts/check-consumer-audit.mjs.ejs +414 -0
- package/dist/templates/scripts/check-continue-on-error.mjs.ejs +227 -0
- package/dist/templates/scripts/check-cross-model-review.mjs.ejs +458 -0
- package/dist/templates/scripts/check-decision-registry.mjs.ejs +101 -0
- package/dist/templates/scripts/check-doc-freshness.mjs.ejs +17 -0
- package/dist/templates/scripts/check-doc-links.mjs.ejs +98 -0
- package/dist/templates/scripts/check-doc-set.mjs.ejs +18 -0
- package/dist/templates/scripts/check-docs.mjs.ejs +71 -0
- package/dist/templates/scripts/check-domain-api-surface.mjs.ejs +80 -0
- package/dist/templates/scripts/check-drift.mjs.ejs +167 -0
- package/dist/templates/scripts/check-duplication.mjs.ejs +45 -0
- package/dist/templates/scripts/check-e2e-escalation.mjs.ejs +199 -0
- package/dist/templates/scripts/check-e2e-quarantine.mjs.ejs +68 -0
- package/dist/templates/scripts/check-emission-parity.mjs.ejs +91 -0
- package/dist/templates/scripts/check-exit-code-contract.mjs.ejs +138 -0
- package/dist/templates/scripts/check-fail-closed-audit.mjs.ejs +389 -0
- package/dist/templates/scripts/check-fe-boundaries.mjs.ejs +184 -0
- package/dist/templates/scripts/check-feature-matrix.mjs.ejs +835 -0
- package/dist/templates/scripts/check-frontend-lane.mjs.ejs +73 -0
- package/dist/templates/scripts/check-grace-window.mjs.ejs +102 -0
- package/dist/templates/scripts/check-handoff-doc.mjs.ejs +192 -0
- package/dist/templates/scripts/check-hook-routing.mjs.ejs +224 -0
- package/dist/templates/scripts/check-image-pins.mjs.ejs +90 -0
- package/dist/templates/scripts/check-inline-suppressions.mjs.ejs +153 -0
- package/dist/templates/scripts/check-iso9001.mjs.ejs +146 -0
- package/dist/templates/scripts/check-knowledge-map.mjs.ejs +49 -0
- package/dist/templates/scripts/check-local-ci-parity.mjs.ejs +382 -0
- package/dist/templates/scripts/check-m16-handoff.mjs.ejs +112 -0
- package/dist/templates/scripts/check-merge-method.mjs.ejs +92 -0
- package/dist/templates/scripts/check-milestones.mjs.ejs +678 -0
- package/dist/templates/scripts/check-min-test-execution.mjs.ejs +225 -0
- package/dist/templates/scripts/check-muted-test.mjs.ejs +270 -0
- package/dist/templates/scripts/check-no-stub-redirects.mjs.ejs +154 -0
- package/dist/templates/scripts/check-no-tracked-artifacts.mjs.ejs +134 -0
- package/dist/templates/scripts/check-oracle-discrimination.mjs.ejs +244 -0
- package/dist/templates/scripts/check-pii-scan.mjs.ejs +67 -0
- package/dist/templates/scripts/check-pipe-tee-hazard.mjs.ejs +85 -0
- package/dist/templates/scripts/check-pr-size-gate.mjs.ejs +85 -0
- package/dist/templates/scripts/check-refutation-verdicts.mjs.ejs +256 -0
- package/dist/templates/scripts/check-regulated-overlay.mjs.ejs +158 -0
- package/dist/templates/scripts/check-render-smoke.mjs.ejs +100 -0
- package/dist/templates/scripts/check-reuse-registry.mjs.ejs +44 -0
- package/dist/templates/scripts/check-review-completion.mjs.ejs +708 -0
- package/dist/templates/scripts/check-safety-adopt-ratchet.mjs.ejs +142 -0
- package/dist/templates/scripts/check-secret-presence.mjs.ejs +191 -0
- package/dist/templates/scripts/check-secret-scan.mjs.ejs +82 -0
- package/dist/templates/scripts/check-skip-critical-e2e.mjs.ejs +142 -0
- package/dist/templates/scripts/check-smoke-journeys.mjs.ejs +272 -0
- package/dist/templates/scripts/check-solo-reactivation.mjs.ejs +102 -0
- package/dist/templates/scripts/check-sources.mjs.ejs +245 -0
- package/dist/templates/scripts/check-ssot-core.mjs.ejs +45 -0
- package/dist/templates/scripts/check-stack-conformity.mjs.ejs +160 -0
- package/dist/templates/scripts/check-stride-traceability.mjs.ejs +101 -0
- package/dist/templates/scripts/check-suppression-expiry.mjs.ejs +79 -0
- package/dist/templates/scripts/check-suppression-rationale.mjs.ejs +76 -0
- package/dist/templates/scripts/check-suppressions.mjs.ejs +150 -0
- package/dist/templates/scripts/check-tabletop-evidence.mjs.ejs +499 -0
- package/dist/templates/scripts/check-tdd-evidence.mjs.ejs +381 -0
- package/dist/templates/scripts/check-test-naming.mjs.ejs +151 -0
- package/dist/templates/scripts/check-test-pyramid.mjs.ejs +170 -0
- package/dist/templates/scripts/check-test-scope-tier.mjs.ejs +208 -0
- package/dist/templates/scripts/check-tier-coverage.mjs.ejs +71 -0
- package/dist/templates/scripts/check-todo-max-age.mjs.ejs +205 -0
- package/dist/templates/scripts/check-touched-vs-manifest.mjs.ejs +179 -0
- package/dist/templates/scripts/check-unwired-guards.mjs.ejs +367 -0
- package/dist/templates/scripts/check-use-cases.mjs.ejs +345 -0
- package/dist/templates/scripts/check-validator-helptext.mjs.ejs +80 -0
- package/dist/templates/scripts/check-wiki-lint.mjs.ejs +162 -0
- package/dist/templates/scripts/check-workflow-docs-sync.mjs.ejs +91 -0
- package/dist/templates/scripts/check-workflow-job-naming.mjs.ejs +102 -0
- package/dist/templates/scripts/check-workflow-perms.mjs.ejs +54 -0
- package/dist/templates/scripts/check-workflow-runners.mjs.ejs +87 -0
- package/dist/templates/scripts/check-workflow-sha-pinning.mjs.ejs +89 -0
- package/dist/templates/scripts/check-workflow-test-integrity.mjs.ejs +235 -0
- package/dist/templates/scripts/checks/check-rust-no-unsafe.mjs.ejs +58 -0
- package/dist/templates/scripts/checks/check-rust-no-unwrap.mjs.ejs +61 -0
- package/dist/templates/scripts/ci-classify-changes.mjs.ejs +119 -0
- package/dist/templates/scripts/conformance.mjs.ejs +37 -0
- package/dist/templates/scripts/constraint-map.json.ejs +25 -0
- package/dist/templates/scripts/debt-lib.mjs.ejs +1015 -0
- package/dist/templates/scripts/debt-report.mjs.ejs +199 -0
- package/dist/templates/scripts/domain-api-surface.json.ejs +23 -0
- package/dist/templates/scripts/done-evidence.mjs.ejs +359 -0
- package/dist/templates/scripts/evidence-collect.mjs.ejs +264 -0
- package/dist/templates/scripts/evidence-prune.mjs.ejs +96 -0
- package/dist/templates/scripts/evidence-rotate.mjs.ejs +53 -0
- package/dist/templates/scripts/evidence-writer.sh.ejs +220 -0
- package/dist/templates/scripts/gate-registry.yml.ejs +286 -0
- package/dist/templates/scripts/gen-doc-index.mjs.ejs +19 -0
- package/dist/templates/scripts/gen-gap.mjs.ejs +153 -0
- package/dist/templates/scripts/gen-llms-txt.mjs.ejs +18 -0
- package/dist/templates/scripts/gen-wiki.mjs.ejs +196 -0
- package/dist/templates/scripts/gh-cleanup-expired-artifacts.mjs.ejs +134 -0
- package/dist/templates/scripts/gold-audit.mjs.ejs +19 -0
- package/dist/templates/scripts/i18n-literal-scanner.mjs.ejs +175 -0
- package/dist/templates/scripts/ingest-zap-report.mjs.ejs +107 -0
- package/dist/templates/scripts/inject-pact-samples.sh.ejs +96 -0
- package/dist/templates/scripts/issue-readiness.mjs.ejs +84 -0
- package/dist/templates/scripts/knowledge-map-update.mjs.ejs +32 -0
- package/dist/templates/scripts/lib/acceptance-criteria.mjs.ejs +213 -0
- package/dist/templates/scripts/lib/agent-return-validate.mjs.ejs +481 -0
- package/dist/templates/scripts/lib/coverage-gate.mjs.ejs +54 -0
- package/dist/templates/scripts/lib/e2e-reliability.mjs.ejs +207 -0
- package/dist/templates/scripts/lib/ephemeral-server.mjs.ejs +148 -0
- package/dist/templates/scripts/lib/evidence-binding.mjs.ejs +140 -0
- package/dist/templates/scripts/lib/exact-sha-policy.mjs.ejs +233 -0
- package/dist/templates/scripts/lib/gate-args.mjs.ejs +20 -0
- package/dist/templates/scripts/lib/gate-evidence.mjs.ejs +622 -0
- package/dist/templates/scripts/lib/gate-mutex.mjs.ejs +340 -0
- package/dist/templates/scripts/lib/glob-walk.mjs.ejs +148 -0
- package/dist/templates/scripts/lib/run-helpers.mjs.ejs +416 -0
- package/dist/templates/scripts/lib/seed-common.sh.ejs +105 -0
- package/dist/templates/scripts/lib/waiter-count.mjs.ejs +62 -0
- package/dist/templates/scripts/muted-tests-baseline.json.ejs +4 -0
- package/dist/templates/scripts/optional-emissions.json.ejs +117 -0
- package/dist/templates/scripts/oracle-discrimination-baseline.json.ejs +6 -0
- package/dist/templates/scripts/pid-watch.sh.ejs +78 -0
- package/dist/templates/scripts/pii-scan.mjs.ejs +125 -0
- package/dist/templates/scripts/pr-merge-watch.mjs.ejs +445 -0
- package/dist/templates/scripts/record-agent-return.mjs.ejs +279 -0
- package/dist/templates/scripts/record-journey-evidence.mjs.ejs +69 -0
- package/dist/templates/scripts/rework-log.mjs.ejs +172 -0
- package/dist/templates/scripts/run-postman-tests.sh.ejs +112 -0
- package/dist/templates/scripts/schemas/agent-return-external.schema.json +74 -0
- package/dist/templates/scripts/schemas/agent-return.schema.json.ejs +181 -0
- package/dist/templates/scripts/schemas/cross-model-dispatch.schema.json +95 -0
- package/dist/templates/scripts/seed-test-data.sh.ejs +99 -0
- package/dist/templates/scripts/self-validation.mjs.ejs +126 -0
- package/dist/templates/scripts/setup-repo.sh.ejs +78 -0
- package/dist/templates/scripts/spotbugs-baseline.json.ejs +4 -0
- package/dist/templates/scripts/test-gate-layering.mjs.ejs +92 -0
- package/dist/templates/scripts/validate-api-snapshots.mjs.ejs +86 -0
- package/dist/templates/scripts/validate-k6-scenarios.mjs.ejs +96 -0
- package/dist/templates/scripts/validate-openapi-field-types.mjs.ejs +124 -0
- package/dist/templates/scripts/validate-postman-collection.mjs.ejs +159 -0
- package/dist/templates/scripts/verify-fe-coverage.mjs.ejs +138 -0
- package/dist/templates/scripts/verify-i18n-parity.mjs.ejs +114 -0
- package/dist/templates/scripts/verify-module-coverage.mjs.ejs +207 -0
- package/dist/templates/scripts/verify-mutation-baseline.mjs.ejs +209 -0
- package/dist/templates/scripts/verify-spotbugs.mjs.ejs +216 -0
- package/dist/templates/scripts/verify-tokens.mjs.ejs +177 -0
- package/dist/templates/security/RISK_ASSESSMENT.md.ejs +35 -0
- package/dist/templates/security/STRIDE.md.ejs +24 -0
- package/dist/templates/security/gitleaks.toml.ejs +21 -0
- package/dist/templates/security/zap/baseline-auth.context.ejs +58 -0
- package/dist/templates/security/zap/rules.tsv.ejs +100 -0
- package/dist/templates/ship/TICK_PROMPT.md.ejs +55 -0
- package/dist/templates/ship/supervisor.sh.ejs +46 -0
- package/dist/templates/smoke-journeys/manifest.json.ejs +1 -0
- package/dist/templates/sonar-project.properties.ejs +25 -0
- package/dist/templates/standards/doc-profile.ejs +27 -0
- package/dist/templates/standards/gold-doc-set.yml.ejs +528 -0
- package/dist/templates/standards/gold-registry.java.yml.ejs +266 -0
- package/dist/templates/standards/gold-registry.typescript.yml.ejs +104 -0
- package/dist/templates/standards/gold-registry.yml.ejs +119 -0
- package/dist/templates/standards/thresholds.yml.ejs +86 -0
- package/dist/templates/static-analysis/.dependency-cruiser.cjs.ejs +78 -0
- package/dist/templates/static-analysis/.golangci.yml.ejs +70 -0
- package/dist/templates/static-analysis/.shellcheckrc.ejs +13 -0
- package/dist/templates/static-analysis/.yamllint.yml.ejs +41 -0
- package/dist/templates/static-analysis/checkstyle.xml.ejs +83 -0
- package/dist/templates/static-analysis/detekt.yml.ejs +26 -0
- package/dist/templates/static-analysis/eslint.config.mjs.ejs +54 -0
- package/dist/templates/static-analysis/eslint.config.static.mjs.ejs +38 -0
- package/dist/templates/static-analysis/eslintrc-static.json.ejs +30 -0
- package/dist/templates/static-analysis/jscpd.json.ejs +25 -0
- package/dist/templates/static-analysis/knip.json.ejs +26 -0
- package/dist/templates/static-analysis/pmd-ruleset.xml.ejs +92 -0
- package/dist/templates/static-analysis/prettierignore.ejs +59 -0
- package/dist/templates/static-analysis/prettierrc.json.ejs +10 -0
- package/dist/templates/static-analysis/requirements-dev.txt.ejs +11 -0
- package/dist/templates/static-analysis/ruff.toml.ejs +40 -0
- package/dist/templates/static-analysis/rustfmt.toml.ejs +3 -0
- package/dist/templates/static-analysis/spotbugs-exclude.xml.ejs +120 -0
- package/dist/templates/static-analysis/spotbugs.gradle.ejs +18 -0
- package/dist/templates/static-analysis/spotless.gradle.ejs +38 -0
- package/dist/templates/static-analysis/stylelintrc.json.ejs +16 -0
- package/dist/templates/suppressions/archunit-baseline.json.ejs +1 -0
- package/dist/templates/suppressions/consumer-audit-allowlist.json.ejs +1 -0
- package/dist/templates/suppressions/gitleaksignore.ejs +20 -0
- package/dist/templates/suppressions/pii-allowlist.json.ejs +1 -0
- package/dist/templates/suppressions/suppressions-schema.json.ejs +39 -0
- package/dist/templates/suppressions/trivyignore.ejs +17 -0
- package/dist/templates/testing/test-taxonomy.md.ejs +120 -0
- package/dist/test/example.behavioral.test.js +2 -0
- package/dist/types/memory.d.ts +19 -0
- package/dist/types/memory.js +1 -0
- package/dist/types/plan.d.ts +102 -0
- package/dist/types/plan.js +2 -0
- package/dist/types/plugin.d.ts +45 -0
- package/dist/types/plugin.js +1 -0
- package/dist/utils/canon-loader.js +2 -0
- package/dist/utils/channel.js +1 -0
- package/dist/utils/config.d.ts +79 -0
- package/dist/utils/config.js +5 -0
- package/dist/utils/confirm-downgrade.js +5 -0
- package/dist/utils/env.js +2 -0
- package/dist/utils/error-catalog.js +2 -0
- package/dist/utils/errors.js +2 -0
- package/dist/utils/evidence-log.js +3 -0
- package/dist/utils/file-lock.js +2 -0
- package/dist/utils/first-run.js +8 -0
- package/dist/utils/fs.js +3 -0
- package/dist/utils/github-issue-helper.js +4 -0
- package/dist/utils/gradle.js +21 -0
- package/dist/utils/json-output.js +2 -0
- package/dist/utils/logger-config.js +4 -0
- package/dist/utils/logger.js +3 -0
- package/dist/utils/maturity-check.js +2 -0
- package/dist/utils/pkg.js +3 -0
- package/dist/utils/platform.js +2 -0
- package/dist/utils/plugin-loader.js +2 -0
- package/dist/utils/plugin-worker.js +2 -0
- package/dist/utils/prettier-format.js +2 -0
- package/dist/utils/profiler.js +2 -0
- package/dist/utils/render.js +2 -0
- package/dist/utils/replay.js +3 -0
- package/dist/utils/run-cli.js +6 -0
- package/dist/utils/run-id.js +3 -0
- package/dist/utils/safe-read.js +2 -0
- package/dist/utils/task-id.js +2 -0
- package/dist/utils/today.js +2 -0
- package/dist/utils/tty.js +2 -0
- package/dist/utils/walk-dir.js +2 -0
- package/dist/verify/rules/drive-by-scope.js +1 -0
- package/dist/verify/rules/orphan-todos.js +1 -0
- package/dist/verify/rules/registry.js +1 -0
- package/dist/verify/rules/skip-patterns.js +1 -0
- package/dist/verify/rules/types.d.ts +15 -0
- package/dist/verify/rules/types.js +1 -0
- package/dist/verify/rules/ui-language.js +1 -0
- package/dist/verify/run.js +3 -0
- package/dist/wizard/archetype-defaults.js +1 -0
- package/dist/wizard/presets.js +1 -0
- package/dist/wizard/prompts.js +44 -0
- package/dist/wizard/types.d.ts +637 -0
- package/dist/wizard/types.js +1 -0
- package/dist/worktree/harvest.js +2 -0
- package/dist/worktree/links.js +2 -0
- package/dist/worktree/paths.js +2 -0
- package/dist/worktree/validate.js +3 -0
- package/package.json +124 -0
- package/scripts/check-arc42-slots.mjs +738 -0
- package/scripts/check-doc-freshness.mjs +236 -0
- package/scripts/check-doc-set.mjs +243 -0
- package/scripts/check-doc-style.mjs +228 -0
- package/scripts/gold-audit.mjs +319 -0
- package/scripts/lib/doc-gate-allowlist.mjs +123 -0
- package/scripts/lib/doc-set-resolve.mjs +274 -0
- package/scripts/lib/glob-walk.mjs +148 -0
- package/scripts/lib/gold-audit-lib.mjs +1260 -0
- package/scripts/lib/run-helpers.mjs +413 -0
|
@@ -0,0 +1,523 @@
|
|
|
1
|
+
// Arbiter hook library — shared utilities for all hooks
|
|
2
|
+
// Project: <%= projectName %>
|
|
3
|
+
import { mkdirSync, appendFileSync, readFileSync, existsSync, statSync, writeFileSync } from 'node:fs';
|
|
4
|
+
import { join, extname, dirname, resolve, sep } from 'node:path';
|
|
5
|
+
import { fileURLToPath } from 'node:url';
|
|
6
|
+
import { tmpdir } from 'node:os';
|
|
7
|
+
import { createHash } from 'node:crypto';
|
|
8
|
+
import { spawnSync } from 'node:child_process';
|
|
9
|
+
|
|
10
|
+
const PROJECT = '<%= projectName %>';
|
|
11
|
+
const LOG_DIR = '.claude/hooks/logs';
|
|
12
|
+
const LOG_FILE = `${LOG_DIR}/hook-events.log`;
|
|
13
|
+
|
|
14
|
+
mkdirSync(LOG_DIR, { recursive: true });
|
|
15
|
+
|
|
16
|
+
function logEvent(level, message) {
|
|
17
|
+
const ts = new Date().toISOString();
|
|
18
|
+
appendFileSync(LOG_FILE, `[${ts}] [${PROJECT}] [${level}] ${message}\n`);
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
export const logInfo = (msg) => logEvent('INFO', msg);
|
|
22
|
+
export const logWarn = (msg) => logEvent('WARN', msg);
|
|
23
|
+
export const logError = (msg) => logEvent('ERROR', msg);
|
|
24
|
+
|
|
25
|
+
/**
|
|
26
|
+
* Per-edit debounce for whole-graph hooks (#1515). knip / madge analyse the
|
|
27
|
+
* entire project graph and cannot be scoped to one file, so running them on
|
|
28
|
+
* every save is O(repo)/edit. This caps them to at most once per `windowMs`
|
|
29
|
+
* across a burst of edits (the L1 gate re-runs them authoritatively before
|
|
30
|
+
* commit/push, so a skipped per-edit run never weakens enforcement). Keyed by
|
|
31
|
+
* cwd so sibling repos do not share a marker. Fail-open: any FS error runs the
|
|
32
|
+
* check rather than silently disabling it. Set ARBITER_HOOK_DEBOUNCE_MS=0 to
|
|
33
|
+
* disable. Returns true when the caller should skip (still within the window).
|
|
34
|
+
*/
|
|
35
|
+
export function debounceHook(key, windowMs = Number(process.env.ARBITER_HOOK_DEBOUNCE_MS ?? 20000)) {
|
|
36
|
+
if (!(windowMs > 0)) return false;
|
|
37
|
+
try {
|
|
38
|
+
const dir = join(tmpdir(), 'arbiter-hook-debounce');
|
|
39
|
+
const id = createHash('sha1').update(process.cwd()).digest('hex').slice(0, 16);
|
|
40
|
+
const marker = join(dir, `${key}-${id}`);
|
|
41
|
+
if (existsSync(marker) && Date.now() - statSync(marker).mtimeMs < windowMs) return true;
|
|
42
|
+
mkdirSync(dir, { recursive: true });
|
|
43
|
+
writeFileSync(marker, String(Date.now()));
|
|
44
|
+
} catch {
|
|
45
|
+
// fail-open: never silently disable enforcement on a transient FS error.
|
|
46
|
+
}
|
|
47
|
+
return false;
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
/**
|
|
51
|
+
* Scope a whole-repo format/lint command to the single edited file (#1515).
|
|
52
|
+
* Per-edit hooks must not re-scan the entire repo. Rewrites a configured
|
|
53
|
+
* command into an argv targeting one file when the tool supports it:
|
|
54
|
+
* - npm/yarn/pnpm "lint" script indirection → direct `npx eslint <file>`
|
|
55
|
+
* - known per-file tools (prettier/eslint/ruff/black/gofmt/rustfmt/biome):
|
|
56
|
+
* strip trailing whole-repo path tokens, append the file
|
|
57
|
+
* - whole-graph tools (cargo/mvn/gradle/golangci-lint/go): returned unchanged
|
|
58
|
+
* (not meaningfully scopeable to one file — left to the gate).
|
|
59
|
+
* Returns an argv array ready for spawnSync.
|
|
60
|
+
*/
|
|
61
|
+
export function scopeCommandToFile(command, file) {
|
|
62
|
+
const toks = String(command || '').split(' ').filter(Boolean);
|
|
63
|
+
if (toks.length === 0) return toks;
|
|
64
|
+
if (/^(npm|yarn|pnpm)$/.test(toks[0]) && toks.includes('lint')) return ['npx', 'eslint', file];
|
|
65
|
+
const tool = toks[0] === 'npx' ? toks[1] : toks[0];
|
|
66
|
+
const SCOPEABLE = new Set(['prettier', 'eslint', 'ruff', 'black', 'gofmt', 'rustfmt', 'biome']);
|
|
67
|
+
if (!SCOPEABLE.has(tool)) return toks;
|
|
68
|
+
const REPO_TARGETS = new Set(['.', './', 'src', '__tests__', 'tests']);
|
|
69
|
+
while (toks.length > 1 && REPO_TARGETS.has(toks[toks.length - 1])) toks.pop();
|
|
70
|
+
toks.push(file);
|
|
71
|
+
return toks;
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
/**
|
|
75
|
+
* Path-eligibility for post-edit-dispatch.mjs's Go format/lint dispatch (#486).
|
|
76
|
+
* The hook is Go-only, so the `.go` extension is the real filter and there is no
|
|
77
|
+
* lane-scoping: the previous LANES=["frontend","backend","docs"] gate silently
|
|
78
|
+
* excluded cmd/ and internal/ — 99% of the repo's Go code — so gofmt/golangci-lint
|
|
79
|
+
* never ran there. Returns true when the edited file should reach the dispatch.
|
|
80
|
+
*/
|
|
81
|
+
export function reachesDispatch(filePath) {
|
|
82
|
+
if (!filePath) return false;
|
|
83
|
+
const SKIP_PATTERNS = /\.(md|json|yaml|yml|txt|log|lock|toml|xml|html|css|svg|png|jpg|gif)$/i;
|
|
84
|
+
const SKIP_DIRS = /\/(node_modules|build|dist|target|\.git|\.cache|__pycache__|\.venv)\//;
|
|
85
|
+
if (SKIP_PATTERNS.test(filePath) || SKIP_DIRS.test(filePath)) return false;
|
|
86
|
+
return extname(filePath).toLowerCase() === '.go';
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
/**
|
|
90
|
+
* Environment for the hook's `golangci-lint run` (#487). Isolates golangci's cache
|
|
91
|
+
* per worktree, mirroring check-all.mjs (#176, resolveGolangciCacheDir): the shared
|
|
92
|
+
* default cache (~/.cache/golangci-lint) references deleted sibling-worktree paths
|
|
93
|
+
* after a worktree is removed, leaking phantom-file findings across worktrees. The
|
|
94
|
+
* cache dir is inlined (not imported from scripts/lib) to keep this hook library
|
|
95
|
+
* dependency-free.
|
|
96
|
+
*/
|
|
97
|
+
export function lintEnv(root) {
|
|
98
|
+
return { ...process.env, GOLANGCI_LINT_CACHE: join(root, '.golangci-cache') };
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
/**
|
|
102
|
+
* Splits the argument list of an `arbiter-suppress(...)` directive on top-level
|
|
103
|
+
* commas, honoring single/double quoted values so a `reason="a, b"` stays intact.
|
|
104
|
+
* Kept inline (no shared import) so the emitted hook library is dependency-free.
|
|
105
|
+
*/
|
|
106
|
+
function parseSuppressArgs(argsStr) {
|
|
107
|
+
const parts = [];
|
|
108
|
+
let current = '';
|
|
109
|
+
let inQuote = false;
|
|
110
|
+
let quoteChar = '';
|
|
111
|
+
for (const ch of argsStr) {
|
|
112
|
+
if (!inQuote && (ch === '"' || ch === "'")) {
|
|
113
|
+
inQuote = true;
|
|
114
|
+
quoteChar = ch;
|
|
115
|
+
current += ch;
|
|
116
|
+
} else if (inQuote && ch === quoteChar) {
|
|
117
|
+
inQuote = false;
|
|
118
|
+
quoteChar = '';
|
|
119
|
+
current += ch;
|
|
120
|
+
} else if (!inQuote && ch === ',') {
|
|
121
|
+
parts.push(current.trim());
|
|
122
|
+
current = '';
|
|
123
|
+
} else {
|
|
124
|
+
current += ch;
|
|
125
|
+
}
|
|
126
|
+
}
|
|
127
|
+
if (current.trim()) parts.push(current.trim());
|
|
128
|
+
return parts;
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
/**
|
|
132
|
+
* Checks whether an inline suppression directive on the same or previous line covers
|
|
133
|
+
* the given invariant ID. The directive is a line comment of the form
|
|
134
|
+
* `arbiter-suppress(INV-NN, until=YYYY-MM-DD, reason="...", owner=...)` (two leading
|
|
135
|
+
* slashes mark it as a comment — kept out of this doc string so this file's own
|
|
136
|
+
* suppression scanner does not mistake the example for a real directive, #1772).
|
|
137
|
+
* Returns true only for a complete, non-expired directive (valid `until` date in the
|
|
138
|
+
* future, `reason` >= 10 chars, `owner` present). Mirrors arbiter's own
|
|
139
|
+
* `.claude/hooks/lib.mjs::findInlineSuppression` so generated projects get the
|
|
140
|
+
* SAME honored escape hatch the hook messages advertise (#1553).
|
|
141
|
+
* @param {string} fileContent full file content
|
|
142
|
+
* @param {number} lineIndex 0-based line index of the violation
|
|
143
|
+
* @param {string|null} invId e.g. "INV-12", or null to match any valid directive
|
|
144
|
+
*/
|
|
145
|
+
export function findInlineSuppression(fileContent, lineIndex, invId) {
|
|
146
|
+
const lines = fileContent.split('\n');
|
|
147
|
+
const candidateLines = [lines[lineIndex]];
|
|
148
|
+
if (lineIndex > 0) candidateLines.unshift(lines[lineIndex - 1]);
|
|
149
|
+
|
|
150
|
+
const SUPPRESS_RE = /\/\/\s*arbiter-suppress\(([^)]+)\)/;
|
|
151
|
+
|
|
152
|
+
for (const line of candidateLines) {
|
|
153
|
+
const m = SUPPRESS_RE.test(line) ? line.match(SUPPRESS_RE) : null;
|
|
154
|
+
if (!m) continue;
|
|
155
|
+
|
|
156
|
+
const parts = parseSuppressArgs(m[1]);
|
|
157
|
+
if (parts.length === 0) continue;
|
|
158
|
+
|
|
159
|
+
const firstPart = parts[0];
|
|
160
|
+
if (invId !== null && firstPart !== invId) continue;
|
|
161
|
+
|
|
162
|
+
const kvPairs = {};
|
|
163
|
+
for (let i = 1; i < parts.length; i++) {
|
|
164
|
+
const eqIdx = parts[i].indexOf('=');
|
|
165
|
+
if (eqIdx === -1) continue;
|
|
166
|
+
const key = parts[i].slice(0, eqIdx).trim();
|
|
167
|
+
let val = parts[i].slice(eqIdx + 1).trim();
|
|
168
|
+
if (
|
|
169
|
+
(val.startsWith('"') && val.endsWith('"')) ||
|
|
170
|
+
(val.startsWith("'") && val.endsWith("'"))
|
|
171
|
+
) {
|
|
172
|
+
val = val.slice(1, -1);
|
|
173
|
+
}
|
|
174
|
+
kvPairs[key] = val;
|
|
175
|
+
}
|
|
176
|
+
|
|
177
|
+
if (!kvPairs.until || !kvPairs.reason || !kvPairs.owner) continue;
|
|
178
|
+
|
|
179
|
+
const expiry = new Date(kvPairs.until);
|
|
180
|
+
if (isNaN(expiry.getTime())) continue;
|
|
181
|
+
if (expiry.getTime() < Date.now()) continue;
|
|
182
|
+
if (kvPairs.reason.length < 10) continue;
|
|
183
|
+
|
|
184
|
+
return true;
|
|
185
|
+
}
|
|
186
|
+
return false;
|
|
187
|
+
}
|
|
188
|
+
|
|
189
|
+
/**
|
|
190
|
+
* Sanitize a task id into a safe filesystem segment AND safe regex literal.
|
|
191
|
+
* MUST stay in lockstep with `src/utils/task-id.ts::sanitizeTaskId`.
|
|
192
|
+
* Parity enforced by `__tests__/lib/sanitize-task-id-parity.test.ts`.
|
|
193
|
+
*/
|
|
194
|
+
export function sanitizeTaskId(raw) {
|
|
195
|
+
const cleaned = String(raw ?? '').replace(/[^a-zA-Z0-9_-]/g, '_').slice(0, 64);
|
|
196
|
+
return cleaned.length > 0 ? cleaned : 'unknown';
|
|
197
|
+
}
|
|
198
|
+
|
|
199
|
+
/**
|
|
200
|
+
* Resolve the path of the file a tool is about to edit / has just edited.
|
|
201
|
+
*
|
|
202
|
+
* The Claude Code hook protocol delivers tool input as a JSON object on stdin
|
|
203
|
+
* (`{ tool_name, tool_input: { file_path, ... } }`). The Codex adapter, by
|
|
204
|
+
* contrast, translates that payload into the `CLAUDE_TOOL_INPUT_PATH`
|
|
205
|
+
* environment variable before delegating to the hook. A hook that reads only
|
|
206
|
+
* the env var silently no-ops under the stdin-JSON protocol (it sees an empty
|
|
207
|
+
* path and exits 0 without inspecting the file). This resolver accepts BOTH:
|
|
208
|
+
* it prefers the stdin-JSON `tool_input.file_path`, then falls back to the env
|
|
209
|
+
* var (Codex path). Returns '' when neither is present.
|
|
210
|
+
*
|
|
211
|
+
* stdin (fd 0) is consumed at most once and only when it is a pipe/file; on a
|
|
212
|
+
* TTY or when no payload is available it returns '' without blocking.
|
|
213
|
+
*
|
|
214
|
+
* @param {string} [rawStdin] Optional pre-read stdin payload (tests / callers
|
|
215
|
+
* that already buffered fd 0). When omitted, fd 0 is read directly.
|
|
216
|
+
* @returns {string} The resolved file path, or '' if none could be determined.
|
|
217
|
+
*/
|
|
218
|
+
export function resolveToolInputPath(rawStdin) {
|
|
219
|
+
let raw = rawStdin;
|
|
220
|
+
if (typeof raw !== 'string') {
|
|
221
|
+
raw = '';
|
|
222
|
+
try {
|
|
223
|
+
// Reading fd 0 throws EAGAIN on an interactive TTY with no piped input;
|
|
224
|
+
// treat any read failure as "no stdin payload" and fall through to env.
|
|
225
|
+
raw = readFileSync(0, 'utf-8');
|
|
226
|
+
} catch {
|
|
227
|
+
raw = '';
|
|
228
|
+
}
|
|
229
|
+
}
|
|
230
|
+
const trimmed = raw.trim();
|
|
231
|
+
if (trimmed) {
|
|
232
|
+
try {
|
|
233
|
+
const payload = JSON.parse(trimmed);
|
|
234
|
+
const fromStdin = payload?.tool_input?.file_path;
|
|
235
|
+
if (typeof fromStdin === 'string' && fromStdin.length > 0) {
|
|
236
|
+
return fromStdin;
|
|
237
|
+
}
|
|
238
|
+
} catch {
|
|
239
|
+
// Not JSON (or not the expected shape) — fall through to the env fallback.
|
|
240
|
+
}
|
|
241
|
+
}
|
|
242
|
+
const fromEnv = process.env.CLAUDE_TOOL_INPUT_PATH;
|
|
243
|
+
return typeof fromEnv === 'string' ? fromEnv : '';
|
|
244
|
+
}
|
|
245
|
+
|
|
246
|
+
// Directory these hooks were loaded from, and the checkout root above it
|
|
247
|
+
// (`<root>/.claude/hooks/lib.mjs`). This is the repo that OWNS the rules, which is
|
|
248
|
+
// what membership has to be measured against — see isPathInThisRepo (#565).
|
|
249
|
+
const HOOKS_DIR = dirname(fileURLToPath(import.meta.url));
|
|
250
|
+
const HOOK_OWNER_ROOT = resolve(HOOKS_DIR, '..', '..');
|
|
251
|
+
|
|
252
|
+
/** Absolute path of the shared .git dir every worktree of `dir`'s repo points at, or null. */
|
|
253
|
+
function gitCommonDir(dir) {
|
|
254
|
+
const r = spawnSync('git', ['-C', dir, 'rev-parse', '--git-common-dir'], { encoding: 'utf-8' });
|
|
255
|
+
if (r.status !== 0 || !r.stdout.trim()) return null;
|
|
256
|
+
// Relative inside a main working tree ('.git', '../../.git'), absolute inside a
|
|
257
|
+
// linked worktree — resolve against `dir` so both forms compare equal.
|
|
258
|
+
return resolve(dir, r.stdout.trim());
|
|
259
|
+
}
|
|
260
|
+
|
|
261
|
+
/**
|
|
262
|
+
* True when `file` belongs to the repo that owns these hooks (#565).
|
|
263
|
+
*
|
|
264
|
+
* A subagent inherits the SESSION's CLAUDE_PROJECT_DIR, not the one of the repo it is
|
|
265
|
+
* working in, so these Edit|Write hooks stay registered and fire on files belonging to
|
|
266
|
+
* a different repository — an agent editing a sibling repo's AGENTS.md was blocked by
|
|
267
|
+
* enforce-read-only here, which matches the substring and nothing else. This repo has no
|
|
268
|
+
* governance over a foreign repo; that repo's own hooks decide.
|
|
269
|
+
*
|
|
270
|
+
* Membership is git identity, NOT a path prefix: a repo's linked worktrees live
|
|
271
|
+
* outside the repo root (<repo>.worktrees/) and are legitimately covered, so
|
|
272
|
+
* `startsWith(repoRoot)` would silently un-govern all of them.
|
|
273
|
+
* `rev-parse --git-common-dir` is identical across the main checkout and every linked
|
|
274
|
+
* worktree and distinct for any other repo — the same idea #549 used for the Bash side.
|
|
275
|
+
*
|
|
276
|
+
* The anchor is HOOK_OWNER_ROOT rather than `process.cwd()`, which is where this differs
|
|
277
|
+
* from enforce-gate-before-pr.mjs: the reported session had its cwd inside the foreign
|
|
278
|
+
* repo, so a cwd-anchored identity would call that repo "home" and keep blocking.
|
|
279
|
+
*
|
|
280
|
+
* Fail-closed on uncertainty (INV-96): an unresolvable path, or an own-identity that git
|
|
281
|
+
* cannot report, keeps the guard armed. Not-foreign is the safe answer — a guard must not
|
|
282
|
+
* disarm itself on doubt.
|
|
283
|
+
*
|
|
284
|
+
* Takes the ALREADY-RESOLVED path: fd 0 is consumed at most once, so a second
|
|
285
|
+
* resolveToolInputPath() call inside here would read '' and wave everything through.
|
|
286
|
+
*
|
|
287
|
+
* @param {string} file Absolute or cwd-relative path from resolveToolInputPath().
|
|
288
|
+
* @returns {boolean}
|
|
289
|
+
*/
|
|
290
|
+
export function isPathInThisRepo(file) {
|
|
291
|
+
if (!file) return true;
|
|
292
|
+
const abs = resolve(file);
|
|
293
|
+
// Ordinary edit inside the checkout these hooks came from: true by construction,
|
|
294
|
+
// and worth short-circuiting — the alternative is two git spawns on every edit.
|
|
295
|
+
if (abs === HOOK_OWNER_ROOT || abs.startsWith(HOOK_OWNER_ROOT + sep)) return true;
|
|
296
|
+
|
|
297
|
+
const home = gitCommonDir(HOOKS_DIR);
|
|
298
|
+
if (!home) return true;
|
|
299
|
+
|
|
300
|
+
// A Write can target a file — or a whole directory tree — that does not exist yet;
|
|
301
|
+
// `git -C` needs a real directory, so climb to the nearest existing ancestor.
|
|
302
|
+
let dir = dirname(abs);
|
|
303
|
+
while (!existsSync(dir)) {
|
|
304
|
+
const parent = dirname(dir);
|
|
305
|
+
if (parent === dir) return false;
|
|
306
|
+
dir = parent;
|
|
307
|
+
}
|
|
308
|
+
return gitCommonDir(dir) === home;
|
|
309
|
+
}
|
|
310
|
+
|
|
311
|
+
/**
|
|
312
|
+
* Added lines of a file vs HEAD, for diff-scoped PostToolUse scans (#609).
|
|
313
|
+
*
|
|
314
|
+
* PostToolUse Edit|Write hooks used to scan the WHOLE edited file, so a
|
|
315
|
+
* pre-existing forbidden pattern on an UNCHANGED line (e.g. an HTML form-field
|
|
316
|
+
* hint attribute, matched case-insensitively by the marker regex) blocked any
|
|
317
|
+
* unrelated edit in the same file — a false positive on every touch. Scoping
|
|
318
|
+
* the scan to the lines the edit actually added fixes it without weakening
|
|
319
|
+
* detection of NEW offenses.
|
|
320
|
+
*
|
|
321
|
+
* `git ls-files --error-unmatch <file>` distinguishes untracked (new) files —
|
|
322
|
+
* which `git diff HEAD` would show nothing for — from tracked-but-unchanged
|
|
323
|
+
* (which legitimately has no added lines). Untracked files return
|
|
324
|
+
* `{ tracked: false, added: null }` so the caller falls back to a whole-file
|
|
325
|
+
* scan (every line is new). Tracked files return the added-line contents with
|
|
326
|
+
* their 1-based line number in the new file, parsed from the `@@ +c,d @@`
|
|
327
|
+
* hunk headers. The gate's `--all` walk is NOT affected — it stays whole-file
|
|
328
|
+
* (that is the anti-drift gate; this helper is the PostToolUse path only).
|
|
329
|
+
*
|
|
330
|
+
* Runs git in `process.cwd()` (the worktree the hook fires in). Fail-open:
|
|
331
|
+
* any git error degrades to `tracked: false` so the caller scans the whole
|
|
332
|
+
* file rather than silently skipping an offense.
|
|
333
|
+
*
|
|
334
|
+
* @param {string} file Absolute or cwd-relative path.
|
|
335
|
+
* @returns {{tracked: boolean, added: Array<{line: number, content: string}>|null}}
|
|
336
|
+
*/
|
|
337
|
+
export function addedLinesVsHEAD(file) {
|
|
338
|
+
const tracked = spawnSync('git', ['ls-files', '--error-unmatch', file], { encoding: 'utf-8' });
|
|
339
|
+
if (tracked.status !== 0) return { tracked: false, added: null };
|
|
340
|
+
const diff = spawnSync('git', ['diff', 'HEAD', '--', file], { encoding: 'utf-8' });
|
|
341
|
+
if (diff.status !== 0) return { tracked: false, added: null };
|
|
342
|
+
const added = [];
|
|
343
|
+
let newLine = 0;
|
|
344
|
+
let inHunk = false;
|
|
345
|
+
for (const line of diff.stdout.split('\n')) {
|
|
346
|
+
const hunk = /^@@\s+-\d+(?:,\d+)?\s+\+(\d+)(?:,\d+)?\s+@@/.exec(line);
|
|
347
|
+
if (hunk) { inHunk = true; newLine = parseInt(hunk[1], 10); continue; }
|
|
348
|
+
if (!inHunk) continue;
|
|
349
|
+
if (line.startsWith('+')) {
|
|
350
|
+
added.push({ line: newLine, content: line.slice(1) });
|
|
351
|
+
newLine++;
|
|
352
|
+
} else if (line.startsWith(' ')) {
|
|
353
|
+
newLine++;
|
|
354
|
+
}
|
|
355
|
+
// '-' lines and '\ No newline...' do not advance the new-file line counter.
|
|
356
|
+
}
|
|
357
|
+
return { tracked: true, added };
|
|
358
|
+
}
|
|
359
|
+
|
|
360
|
+
/**
|
|
361
|
+
* Resolve the shell command a Bash tool is about to run / has just run.
|
|
362
|
+
*
|
|
363
|
+
* The command-hook counterpart of resolveToolInputPath. The Claude Code hook
|
|
364
|
+
* protocol delivers the Bash payload as a JSON object on stdin
|
|
365
|
+
* (`{ tool_name, tool_input: { command, ... } }`); the Codex adapter instead
|
|
366
|
+
* sets the `CLAUDE_TOOL_INPUT_COMMAND` environment variable. A hook that reads
|
|
367
|
+
* only the env var silently no-ops under the stdin-JSON protocol (it sees an
|
|
368
|
+
* empty command and exits 0 without inspecting it). This resolver accepts BOTH:
|
|
369
|
+
* it prefers the stdin-JSON `tool_input.command`, then falls back to the env var
|
|
370
|
+
* (Codex path). Returns '' when neither is present.
|
|
371
|
+
*
|
|
372
|
+
* stdin (fd 0) is consumed at most once and only when it is a pipe/file; on a
|
|
373
|
+
* TTY or when no payload is available it returns '' without blocking.
|
|
374
|
+
*
|
|
375
|
+
* @param {string} [rawStdin] Optional pre-read stdin payload (tests / callers
|
|
376
|
+
* that already buffered fd 0). When omitted, fd 0 is read directly.
|
|
377
|
+
* @returns {string} The resolved command, or '' if none could be determined.
|
|
378
|
+
*/
|
|
379
|
+
export function resolveToolInputCommand(rawStdin) {
|
|
380
|
+
let raw = rawStdin;
|
|
381
|
+
if (typeof raw !== 'string') {
|
|
382
|
+
raw = '';
|
|
383
|
+
try {
|
|
384
|
+
// Reading fd 0 throws EAGAIN on an interactive TTY with no piped input;
|
|
385
|
+
// treat any read failure as "no stdin payload" and fall through to env.
|
|
386
|
+
raw = readFileSync(0, 'utf-8');
|
|
387
|
+
} catch {
|
|
388
|
+
raw = '';
|
|
389
|
+
}
|
|
390
|
+
}
|
|
391
|
+
const trimmed = raw.trim();
|
|
392
|
+
if (trimmed) {
|
|
393
|
+
try {
|
|
394
|
+
const payload = JSON.parse(trimmed);
|
|
395
|
+
const fromStdin = payload?.tool_input?.command;
|
|
396
|
+
if (typeof fromStdin === 'string' && fromStdin.length > 0) {
|
|
397
|
+
return fromStdin;
|
|
398
|
+
}
|
|
399
|
+
} catch {
|
|
400
|
+
// Not JSON (or not the expected shape) — fall through to the env fallback.
|
|
401
|
+
}
|
|
402
|
+
}
|
|
403
|
+
const fromEnv = process.env.CLAUDE_TOOL_INPUT_COMMAND;
|
|
404
|
+
return typeof fromEnv === 'string' ? fromEnv : '';
|
|
405
|
+
}
|
|
406
|
+
|
|
407
|
+
// Dangerous-command detection for stop-dangerous.mjs (#552). Kept here, beside
|
|
408
|
+
// resolveToolInputCommand, so the guard stays dependency-free.
|
|
409
|
+
const DANGEROUS_LITERALS = [
|
|
410
|
+
'rm -rf /',
|
|
411
|
+
'rm -rf ~',
|
|
412
|
+
'git reset --hard',
|
|
413
|
+
'DROP TABLE',
|
|
414
|
+
'DROP DATABASE',
|
|
415
|
+
'sudo rm',
|
|
416
|
+
'> /dev/sda',
|
|
417
|
+
];
|
|
418
|
+
|
|
419
|
+
/**
|
|
420
|
+
* True when `command` actually runs something destructive.
|
|
421
|
+
*
|
|
422
|
+
* The previous form was a bare substring scan with two failure modes in opposite
|
|
423
|
+
* directions: it blocked `--force-with-lease` (the safe variant, needed after every
|
|
424
|
+
* rebase) and it fired on a command merely *named* inside a quoted string or heredoc
|
|
425
|
+
* body — a guard that cannot tell doing from mentioning gets routed around by habit.
|
|
426
|
+
*
|
|
427
|
+
* @param {string} command
|
|
428
|
+
* @returns {boolean}
|
|
429
|
+
*/
|
|
430
|
+
/**
|
|
431
|
+
* Strips heredoc bodies and quoted-string spans so pattern matching sees only the
|
|
432
|
+
* executed/literal command shape, never text a quoted argument or heredoc payload
|
|
433
|
+
* merely *mentions* (#2403). Shared by isDangerousCommand below and by
|
|
434
|
+
* stop-dangerous.mjs's protected-Arbiter-state-write guard.
|
|
435
|
+
*
|
|
436
|
+
* @param {string} command
|
|
437
|
+
* @returns {string}
|
|
438
|
+
*/
|
|
439
|
+
export function stripQuotedAndHeredocs(command) {
|
|
440
|
+
return String(command ?? '')
|
|
441
|
+
.replace(/<<-?\s*(['"]?)([A-Za-z_][A-Za-z0-9_]*)\1[\s\S]*?^\s*\2\s*$/gm, ' ')
|
|
442
|
+
.replace(/'[^']*'/g, ' ')
|
|
443
|
+
.replace(/"[^"]*"/g, ' ');
|
|
444
|
+
}
|
|
445
|
+
|
|
446
|
+
export function isDangerousCommand(command) {
|
|
447
|
+
const raw = String(command ?? '');
|
|
448
|
+
// Literals stay on the raw text: a destructive argument is normally quoted
|
|
449
|
+
// (`psql -c "DROP TABLE users"`), so stripping quotes would disarm them.
|
|
450
|
+
if (DANGEROUS_LITERALS.some((p) => raw.includes(p))) return true;
|
|
451
|
+
|
|
452
|
+
// The forced push is the opposite case — it is the one that kept firing on prose
|
|
453
|
+
// (an issue body describing this very guard), so it is matched on the text with
|
|
454
|
+
// heredoc bodies and quoted spans removed.
|
|
455
|
+
const executed = stripQuotedAndHeredocs(raw);
|
|
456
|
+
|
|
457
|
+
// --force-with-lease refuses to overwrite refs the local side has not seen, so it is
|
|
458
|
+
// the form a rebase is supposed to use; only the unguarded variants are blocked.
|
|
459
|
+
return /(?:^|[;&|]|\s)git\s+push\b(?![^;&|]*--force-with-lease)[^;&|]*(?:--force\b|\s-f\b)/.test(
|
|
460
|
+
executed,
|
|
461
|
+
);
|
|
462
|
+
}
|
|
463
|
+
|
|
464
|
+
/** Returns the git repository root, falling back to process.cwd(). */
|
|
465
|
+
export function getRepoRoot() {
|
|
466
|
+
const result = spawnSync('git', ['rev-parse', '--show-toplevel'], {
|
|
467
|
+
encoding: 'utf-8',
|
|
468
|
+
});
|
|
469
|
+
if (result.status === 0 && result.stdout) {
|
|
470
|
+
return result.stdout.trim();
|
|
471
|
+
}
|
|
472
|
+
logWarn('getRepoRoot: git rev-parse failed, falling back to cwd');
|
|
473
|
+
return process.cwd();
|
|
474
|
+
}
|
|
475
|
+
|
|
476
|
+
// E5 (#1947): shared write-intent-agent sidecar contract — pre-spawn-worktree-guard.mjs
|
|
477
|
+
// registers entries, post-subagent-release.mjs (SubagentStop) removes them on cleanup.
|
|
478
|
+
// Both files import from here rather than duplicating the path/TTL/prune logic.
|
|
479
|
+
export const SIDECAR_PATH = join('.arbiter', 'agents-active.json');
|
|
480
|
+
export const SIDECAR_TTL_MS = 2 * 60 * 60 * 1000; // 2h — mirrors `arbiter worktree prune --stale`
|
|
481
|
+
|
|
482
|
+
/** Generic best-effort JSON read; missing/malformed file => null (caller decides fallback). */
|
|
483
|
+
export function readJsonOrNull(path) {
|
|
484
|
+
try {
|
|
485
|
+
return JSON.parse(readFileSync(path, 'utf-8'));
|
|
486
|
+
// FAIL-OPEN-INTENT: a caller reading optional bookkeeping/config JSON must not crash
|
|
487
|
+
// on a missing or malformed file — null lets it fall back to a safe default.
|
|
488
|
+
} catch {
|
|
489
|
+
return null;
|
|
490
|
+
}
|
|
491
|
+
}
|
|
492
|
+
|
|
493
|
+
/** Drops sidecar entries older than SIDECAR_TTL_MS so a killed agent cannot wedge future spawns. */
|
|
494
|
+
export function pruneStaleSidecarEntries(entries, now) {
|
|
495
|
+
return entries.filter((e) => now - Number(e.ts ?? 0) < SIDECAR_TTL_MS);
|
|
496
|
+
}
|
|
497
|
+
|
|
498
|
+
/**
|
|
499
|
+
* Reads task state from the unified document `.claude/.task/status.json` in the given root.
|
|
500
|
+
* Returns defaults ('unknown') when the document is absent or unreadable.
|
|
501
|
+
*/
|
|
502
|
+
export function readTaskState(root) {
|
|
503
|
+
const statusPath = join(root, '.claude', '.task', 'status.json');
|
|
504
|
+
let state = {};
|
|
505
|
+
if (existsSync(statusPath)) {
|
|
506
|
+
try {
|
|
507
|
+
state = JSON.parse(readFileSync(statusPath, 'utf-8'));
|
|
508
|
+
} catch (err) {
|
|
509
|
+
// Fail visibly: a corrupt document silently disarms phase-gated guards, so warn rather
|
|
510
|
+
// than treat corruption as a fresh tree.
|
|
511
|
+
process.stderr.write(`[arbiter] warn: ${statusPath} is unreadable (${err.message}); treating task state as unknown.\n`);
|
|
512
|
+
state = {};
|
|
513
|
+
}
|
|
514
|
+
}
|
|
515
|
+
const pick = (v) => (typeof v === 'string' && v.length > 0 ? v : 'unknown');
|
|
516
|
+
return {
|
|
517
|
+
taskId: pick(state.taskId),
|
|
518
|
+
phase: pick(state.phase),
|
|
519
|
+
plan: pick(state.plan),
|
|
520
|
+
tier: pick(state.tier),
|
|
521
|
+
branch: pick(state.branch),
|
|
522
|
+
};
|
|
523
|
+
}
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
// SPDX-License-Identifier: Apache-2.0
|
|
3
|
+
// UserPromptSubmit: block /task commands while brainstorm-active marker exists.
|
|
4
|
+
// Purpose: enforce terminal-state of brainstorming skill (#699) — user must
|
|
5
|
+
// explicitly clear the marker before implementation can begin.
|
|
6
|
+
// Marker: .arbiter/brainstorm-active (auto-expires after 24h via mtime).
|
|
7
|
+
// Never blocks non-/task prompts. Always exits 0 on read errors.
|
|
8
|
+
import { readFileSync, statSync, unlinkSync, existsSync } from 'node:fs'
|
|
9
|
+
import { join } from 'node:path'
|
|
10
|
+
|
|
11
|
+
const TWENTY_FOUR_HOURS_MS = 24 * 60 * 60 * 1000
|
|
12
|
+
|
|
13
|
+
let prompt = ''
|
|
14
|
+
try {
|
|
15
|
+
const raw = readFileSync(0, 'utf-8')
|
|
16
|
+
prompt = JSON.parse(raw)?.prompt ?? ''
|
|
17
|
+
} catch {
|
|
18
|
+
process.exit(0)
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
// Only gate /task commands
|
|
22
|
+
if (!prompt.trimStart().startsWith('/task')) process.exit(0)
|
|
23
|
+
|
|
24
|
+
const markerPath = join(process.cwd(), '.arbiter', 'brainstorm-active')
|
|
25
|
+
if (!existsSync(markerPath)) process.exit(0)
|
|
26
|
+
|
|
27
|
+
// Auto-expire after 24h (clock-skew tolerant: use absolute diff)
|
|
28
|
+
try {
|
|
29
|
+
const mtime = statSync(markerPath).mtime.getTime()
|
|
30
|
+
if (Math.abs(Date.now() - mtime) > TWENTY_FOUR_HOURS_MS) {
|
|
31
|
+
unlinkSync(markerPath)
|
|
32
|
+
process.exit(0)
|
|
33
|
+
}
|
|
34
|
+
} catch (e) {
|
|
35
|
+
if (e.code === 'ENOENT') process.exit(0) // Marker vanished between check and stat — allow
|
|
36
|
+
process.stderr.write(
|
|
37
|
+
`[brainstorm-gate] ERROR: could not stat marker (${e.code ?? e.message}) — blocking\n`,
|
|
38
|
+
)
|
|
39
|
+
process.exit(2)
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
process.stderr.write(
|
|
43
|
+
`[brainstorm-gate] BLOCKED: brainstorm session still active.\n` +
|
|
44
|
+
` Marker: ${markerPath}\n` +
|
|
45
|
+
` Clear it first: rm "${markerPath}"\n` +
|
|
46
|
+
` Then retry your /task command.\n`,
|
|
47
|
+
)
|
|
48
|
+
process.exit(2)
|
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
// Arbiter hook: block non-conventional commit messages after git commit (INV-22)
|
|
3
|
+
// Fires on: PostToolUse → Bash
|
|
4
|
+
import { spawnSync } from 'node:child_process';
|
|
5
|
+
import { resolveToolInputCommand } from './lib.mjs';
|
|
6
|
+
|
|
7
|
+
// Resolve the command from stdin-JSON (real Claude Code) or the env var (Codex).
|
|
8
|
+
// Reading only the env var made this guard silently inert under Claude Code (#1565).
|
|
9
|
+
const command = resolveToolInputCommand();
|
|
10
|
+
|
|
11
|
+
// Only act on git commit commands
|
|
12
|
+
if (!/^git commit/.test(command)) process.exit(0);
|
|
13
|
+
|
|
14
|
+
// Get last commit message
|
|
15
|
+
const result = spawnSync('git', ['log', '-1', '--format=%s'], {
|
|
16
|
+
encoding: 'utf-8',
|
|
17
|
+
});
|
|
18
|
+
const msg = (result.stdout ?? '').trim();
|
|
19
|
+
|
|
20
|
+
// git log failed or no commits yet — skip check
|
|
21
|
+
if (result.status !== 0 || !msg) process.exit(0);
|
|
22
|
+
|
|
23
|
+
// Check conventional commit format: type(scope): summary
|
|
24
|
+
const CONVENTIONAL =
|
|
25
|
+
/^(feat|fix|refactor|test|docs|ci|chore|perf|style|build|revert)(\([^)]+\))?: .{1,72}$/;
|
|
26
|
+
if (!CONVENTIONAL.test(msg)) {
|
|
27
|
+
process.stderr.write(
|
|
28
|
+
`[arbiter] INV-22: Commit message does not follow convention: ${msg}\n`,
|
|
29
|
+
);
|
|
30
|
+
process.stderr.write(
|
|
31
|
+
`[arbiter] Expected: type(scope): summary (e.g., feat(auth): add login)\n`,
|
|
32
|
+
);
|
|
33
|
+
process.stderr.write(`[arbiter] Run \`arbiter explain INV-22\` for details.\n`);
|
|
34
|
+
process.exit(2);
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
// Track-aware post-commit checklist (#724)
|
|
38
|
+
// CRLF stripped: git diff --name-only can emit CRLF on Windows
|
|
39
|
+
const trackDiff = spawnSync('git', ['diff', '--name-only', 'HEAD~1', 'HEAD'], { encoding: 'utf-8' });
|
|
40
|
+
const commitFiles = trackDiff.status === 0
|
|
41
|
+
? (trackDiff.stdout ?? '').split('\n').map((f) => f.replace(/\r/g, '')).filter(Boolean)
|
|
42
|
+
: [];
|
|
43
|
+
|
|
44
|
+
const FE_RE = /\.(tsx?|jsx?|vue|svelte|css|scss)$|^(web|frontend)\//;
|
|
45
|
+
const BE_RE = /\.(go|py|java|rs|rb)$|^(api|backend|server|cmd)\//;
|
|
46
|
+
const DOCS_RE = /\.md$|^docs\//;
|
|
47
|
+
|
|
48
|
+
const hasFE = commitFiles.some((f) => FE_RE.test(f));
|
|
49
|
+
const hasBE = commitFiles.some((f) => BE_RE.test(f));
|
|
50
|
+
const hasDocs = commitFiles.some((f) => DOCS_RE.test(f));
|
|
51
|
+
|
|
52
|
+
const tracks = [];
|
|
53
|
+
if (hasFE) tracks.push('frontend');
|
|
54
|
+
if (hasBE) tracks.push('backend');
|
|
55
|
+
if (hasDocs) tracks.push('docs');
|
|
56
|
+
|
|
57
|
+
if (tracks.length > 0) {
|
|
58
|
+
const label = tracks.length > 1 ? 'Tracks' : 'Track';
|
|
59
|
+
process.stdout.write(`[arbiter] ${label}: ${tracks.join(' + ')}\n`);
|
|
60
|
+
<% const _stackMap = { typescript: 'ts', java: 'java', go: 'go', python: 'python', rust: 'rust', multi: 'ts' }; %>
|
|
61
|
+
<% const _stack = _stackMap[language] || 'ts'; %>
|
|
62
|
+
<%- include(`./post-commit-checklists/${_stack}/frontend.ejs`) %>
|
|
63
|
+
<%- include(`./post-commit-checklists/${_stack}/backend.ejs`) %>
|
|
64
|
+
<%- include(`./post-commit-checklists/${_stack}/docs.ejs`) %>
|
|
65
|
+
}
|