@toolu/opencode 6.8.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/generated/GENERATED-NOTES.md +16 -0
- package/generated/agents/toolu--architect.md +52 -0
- package/generated/agents/toolu--deep-explore.md +65 -0
- package/generated/agents/toolu--implementer.md +50 -0
- package/generated/agents/toolu--quick-task.md +54 -0
- package/generated/agents/toolu--research-agent.md +101 -0
- package/generated/commands/toolu--commit.md +8 -0
- package/generated/commands/toolu--review-and-commit.md +8 -0
- package/generated/opencode.toolu.json +116 -0
- package/generated/skills/toolu--brainstorm/SKILL.md +57 -0
- package/generated/skills/toolu--brainstorm/references/design-questions.md +36 -0
- package/generated/skills/toolu--commit--skill/SKILL.md +11 -0
- package/generated/skills/toolu--debug/SKILL.md +54 -0
- package/generated/skills/toolu--deep-research/SKILL.md +51 -0
- package/generated/skills/toolu--execution/SKILL.md +77 -0
- package/generated/skills/toolu--orchestrator/SKILL.md +145 -0
- package/generated/skills/toolu--orchestrator/references/delegation-cost.md +104 -0
- package/generated/skills/toolu--orchestrator/references/model-routing.md +112 -0
- package/generated/skills/toolu--plan/SKILL.md +56 -0
- package/generated/skills/toolu--plan/references/ledger.md +18 -0
- package/generated/skills/toolu--plan-review/SKILL.md +48 -0
- package/generated/skills/toolu--review-and-commit--skill/SKILL.md +10 -0
- package/generated/skills/toolu--setup/SKILL.md +24 -0
- package/generated/skills/toolu--setup/scripts/setup.sh +206 -0
- package/generated/skills/toolu--spec/SKILL.md +67 -0
- package/generated/skills/toolu--spec-review/SKILL.md +50 -0
- package/generated/skills/toolu--test/SKILL.md +49 -0
- package/package.json +51 -0
- package/plugins/agent-browser/.claude-plugin/plugin.json +18 -0
- package/plugins/agent-browser/.codex-plugin/plugin.json +7 -0
- package/plugins/agent-browser/README.md +18 -0
- package/plugins/agent-browser/hooks/hooks.json +15 -0
- package/plugins/agent-browser/hooks/session-start.sh +42 -0
- package/plugins/agent-browser/skills/agent-browser/SKILL.md +77 -0
- package/plugins/agent-browser/skills/agent-browser/scripts/agent-browser.sh +80 -0
- package/plugins/ast-grep/.claude-plugin/plugin.json +18 -0
- package/plugins/ast-grep/.codex-plugin/plugin.json +7 -0
- package/plugins/ast-grep/README.md +21 -0
- package/plugins/ast-grep/hooks/hooks.json +15 -0
- package/plugins/ast-grep/hooks/post-tools.d/byte-savings.sh +67 -0
- package/plugins/ast-grep/hooks/pre-tools.d/search-nudge.sh +170 -0
- package/plugins/ast-grep/hooks/register.sh +68 -0
- package/plugins/ast-grep/scripts/byte-savings-report.sh +28 -0
- package/plugins/ast-grep/skills/ast-grep/SKILL.md +127 -0
- package/plugins/ast-grep/skills/ast-grep/references/ast-grep-advanced.md +44 -0
- package/plugins/ast-grep/skills/ast-grep/scripts/ast-grep.sh +103 -0
- package/plugins/context7/.claude-plugin/plugin.json +18 -0
- package/plugins/context7/.codex-plugin/plugin.json +7 -0
- package/plugins/context7/README.md +19 -0
- package/plugins/context7/hooks/hooks.json +15 -0
- package/plugins/context7/hooks/session-start.sh +42 -0
- package/plugins/context7/skills/context7/SKILL.md +64 -0
- package/plugins/context7/skills/context7/scripts/search.sh +151 -0
- package/plugins/exa-search/.claude-plugin/plugin.json +18 -0
- package/plugins/exa-search/.codex-plugin/plugin.json +7 -0
- package/plugins/exa-search/README.md +19 -0
- package/plugins/exa-search/hooks/hooks.json +15 -0
- package/plugins/exa-search/hooks/session-start.sh +34 -0
- package/plugins/exa-search/skills/exa-search/SKILL.md +91 -0
- package/plugins/exa-search/skills/exa-search/scripts/search.sh +221 -0
- package/plugins/jev/.claude-plugin/plugin.json +19 -0
- package/plugins/jev/.codex-plugin/plugin.json +7 -0
- package/plugins/jev/README.md +61 -0
- package/plugins/jev/hooks/hooks.json +25 -0
- package/plugins/jev/hooks/lib/common.sh +49 -0
- package/plugins/jev/hooks/session-start.sh +45 -0
- package/plugins/jev/hooks/user-prompt-submit.sh +41 -0
- package/plugins/jev/skills/jev/SKILL.md +81 -0
- package/plugins/jev/skills/jev/evals/README.md +98 -0
- package/plugins/jev/skills/jev/references/problem-solving.md +198 -0
- package/plugins/jev/skills/jev/scripts/jev.sh +405 -0
- package/plugins/jira/.claude-plugin/plugin.json +18 -0
- package/plugins/jira/.codex-plugin/plugin.json +7 -0
- package/plugins/jira/README.md +42 -0
- package/plugins/jira/hooks/hooks.json +15 -0
- package/plugins/jira/hooks/session-start.sh +34 -0
- package/plugins/jira/skills/jira/SKILL.md +123 -0
- package/plugins/jira/skills/jira/scripts/jira.sh +70 -0
- package/plugins/jira/skills/jira/scripts/lib/adf.sh +17 -0
- package/plugins/jira/skills/jira/scripts/lib/attachment.sh +94 -0
- package/plugins/jira/skills/jira/scripts/lib/board.sh +58 -0
- package/plugins/jira/skills/jira/scripts/lib/http.sh +184 -0
- package/plugins/jira/skills/jira/scripts/lib/issue.sh +159 -0
- package/plugins/jira/skills/jira/scripts/lib/paginate.sh +45 -0
- package/plugins/jira/skills/jira/scripts/lib/plan-parse.sh +70 -0
- package/plugins/jira/skills/jira/scripts/lib/plan-run.sh +115 -0
- package/plugins/jira/skills/jira/scripts/lib/plan-store.sh +168 -0
- package/plugins/jira/skills/jira/scripts/lib/plan.sh +108 -0
- package/plugins/jira/skills/jira/scripts/lib/project.sh +42 -0
- package/plugins/jira/skills/jira/scripts/lib/raw.sh +15 -0
- package/plugins/jira/skills/jira/scripts/lib/search.sh +41 -0
- package/plugins/jira/skills/jira/scripts/lib/sprint.sh +88 -0
- package/plugins/jira/skills/jira/scripts/lib/user.sh +45 -0
- package/plugins/jira/skills/jira/scripts/lib/worklog.sh +56 -0
- package/plugins/pr-babysit/.claude-plugin/plugin.json +25 -0
- package/plugins/pr-babysit/.codex-plugin/plugin.json +7 -0
- package/plugins/pr-babysit/README.md +38 -0
- package/plugins/pr-babysit/commands/babysit.md +13 -0
- package/plugins/pr-babysit/hooks/check-toolu.sh +20 -0
- package/plugins/pr-babysit/hooks/hooks.json +15 -0
- package/plugins/pr-babysit/scripts/babysit-tick.sh +133 -0
- package/plugins/pr-babysit/scripts/collect-pr.sh +224 -0
- package/plugins/pr-babysit/scripts/lib/common.sh +146 -0
- package/plugins/pr-babysit/scripts/lib/gh.sh +150 -0
- package/plugins/pr-babysit/scripts/lib/lock.sh +84 -0
- package/plugins/pr-babysit/scripts/lib/normalize.sh +98 -0
- package/plugins/pr-babysit/scripts/lib/state.sh +37 -0
- package/plugins/pr-babysit/scripts/parse-verdict.sh +171 -0
- package/plugins/pr-babysit/scripts/record.sh +69 -0
- package/plugins/pr-babysit/scripts/reduce-state.sh +245 -0
- package/plugins/pr-babysit/scripts/reply-thread.sh +90 -0
- package/plugins/pr-babysit/scripts/resolve-thread.sh +71 -0
- package/plugins/pr-babysit/skills/babysit/SKILL.md +31 -0
- package/plugins/pr-babysit/skills/babysit/references/helper.md +209 -0
- package/plugins/pr-babysit/workflows/babysit.md +722 -0
- package/plugins/python-quality/.claude-plugin/plugin.json +24 -0
- package/plugins/python-quality/.codex-plugin/plugin.json +6 -0
- package/plugins/python-quality/README.md +23 -0
- package/plugins/python-quality/hooks/check-toolu.sh +20 -0
- package/plugins/python-quality/hooks/concerns/00-preamble.sh +85 -0
- package/plugins/python-quality/hooks/concerns/10-size-file.sh +6 -0
- package/plugins/python-quality/hooks/concerns/20-tests.sh +37 -0
- package/plugins/python-quality/hooks/concerns/30-suppression.sh +33 -0
- package/plugins/python-quality/hooks/concerns/50-size-fn.sh +49 -0
- package/plugins/python-quality/hooks/concerns/70-no-mocks.sh +76 -0
- package/plugins/python-quality/hooks/concerns/90-docs.sh +52 -0
- package/plugins/python-quality/hooks/concerns/99-finalize.sh +36 -0
- package/plugins/python-quality/hooks/hooks.json +19 -0
- package/plugins/python-quality/hooks/register.sh +65 -0
- package/plugins/rust-quality/.claude-plugin/plugin.json +24 -0
- package/plugins/rust-quality/.codex-plugin/plugin.json +6 -0
- package/plugins/rust-quality/README.md +24 -0
- package/plugins/rust-quality/hooks/check-toolu.sh +20 -0
- package/plugins/rust-quality/hooks/concerns/00-preamble.sh +93 -0
- package/plugins/rust-quality/hooks/concerns/10-size-file.sh +10 -0
- package/plugins/rust-quality/hooks/concerns/20-tests.sh +84 -0
- package/plugins/rust-quality/hooks/concerns/30-suppression.sh +26 -0
- package/plugins/rust-quality/hooks/concerns/40-unsafe.sh +39 -0
- package/plugins/rust-quality/hooks/concerns/50-size-fn.sh +38 -0
- package/plugins/rust-quality/hooks/concerns/55-size-impl.sh +28 -0
- package/plugins/rust-quality/hooks/concerns/60-error-handling.sh +149 -0
- package/plugins/rust-quality/hooks/concerns/70-no-mocks.sh +139 -0
- package/plugins/rust-quality/hooks/concerns/90-docs.sh +32 -0
- package/plugins/rust-quality/hooks/concerns/99-finalize.sh +36 -0
- package/plugins/rust-quality/hooks/hooks.json +19 -0
- package/plugins/rust-quality/hooks/register.sh +65 -0
- package/plugins/statusline/.claude-plugin/plugin.json +19 -0
- package/plugins/statusline/.codex-plugin/plugin.json +7 -0
- package/plugins/statusline/README.md +108 -0
- package/plugins/statusline/commands/setup.md +30 -0
- package/plugins/statusline/hooks/hooks.json +15 -0
- package/plugins/statusline/hooks/session-start.sh +45 -0
- package/plugins/statusline/scripts/collect-status.sh +147 -0
- package/plugins/statusline/scripts/setup.sh +93 -0
- package/plugins/statusline/scripts/status.sh +55 -0
- package/plugins/statusline/skills/status/SKILL.md +13 -0
- package/plugins/statusline/statusline.sh +177 -0
- package/plugins/toolu/.claude-plugin/plugin.json +19 -0
- package/plugins/toolu/.codex-plugin/plugin.json +7 -0
- package/plugins/toolu/README.md +35 -0
- package/plugins/toolu/agents/.gitkeep +0 -0
- package/plugins/toolu/agents/architect.md +52 -0
- package/plugins/toolu/agents/deep-explore.md +65 -0
- package/plugins/toolu/agents/implementer.md +50 -0
- package/plugins/toolu/agents/quick-task.md +54 -0
- package/plugins/toolu/agents/research-agent.md +107 -0
- package/plugins/toolu/assets/agents/architect.toml +9 -0
- package/plugins/toolu/assets/agents/deep-explore.toml +9 -0
- package/plugins/toolu/assets/agents/implementer.toml +9 -0
- package/plugins/toolu/assets/agents/quick-task.toml +9 -0
- package/plugins/toolu/assets/agents/research-agent.toml +9 -0
- package/plugins/toolu/commands/.gitkeep +0 -0
- package/plugins/toolu/commands/commit.md +5 -0
- package/plugins/toolu/commands/review-and-commit.md +5 -0
- package/plugins/toolu/hooks/docs/gates.md +157 -0
- package/plugins/toolu/hooks/docs/model-routing.md +14 -0
- package/plugins/toolu/hooks/docs/post-compaction.md +3 -0
- package/plugins/toolu/hooks/docs/push-review.md +123 -0
- package/plugins/toolu/hooks/docs/session-start-python.md +3 -0
- package/plugins/toolu/hooks/docs/session-start-rust.md +4 -0
- package/plugins/toolu/hooks/docs/session-start-ts.md +3 -0
- package/plugins/toolu/hooks/docs/session-start.md +16 -0
- package/plugins/toolu/hooks/hooks.json +76 -0
- package/plugins/toolu/hooks/lib/config.sh +355 -0
- package/plugins/toolu/hooks/lib/detect.sh +929 -0
- package/plugins/toolu/hooks/lib/diff-sha.sh +32 -0
- package/plugins/toolu/hooks/lib/dispatch.sh +365 -0
- package/plugins/toolu/hooks/lib/docs-sync-config.sh +81 -0
- package/plugins/toolu/hooks/lib/edit-records.sh +157 -0
- package/plugins/toolu/hooks/lib/gate-file.sh +201 -0
- package/plugins/toolu/hooks/lib/gate-mode.sh +244 -0
- package/plugins/toolu/hooks/lib/host.sh +205 -0
- package/plugins/toolu/hooks/lib/permissions.sh +125 -0
- package/plugins/toolu/hooks/lib/plan-ledger-parse.sh +219 -0
- package/plugins/toolu/hooks/lib/plan-ledger-preflight.sh +137 -0
- package/plugins/toolu/hooks/lib/plan-ledger.sh +749 -0
- package/plugins/toolu/hooks/lib/push-waiver.sh +116 -0
- package/plugins/toolu/hooks/lib/quality-config.sh +184 -0
- package/plugins/toolu/hooks/lib/registry.sh +72 -0
- package/plugins/toolu/hooks/lib/state-sweeper.sh +194 -0
- package/plugins/toolu/hooks/lib/telemetry.sh +94 -0
- package/plugins/toolu/hooks/lib/verdict.sh +477 -0
- package/plugins/toolu/hooks/post-tools/mod.sh +42 -0
- package/plugins/toolu/hooks/post-tools/modules/gate-status.sh +140 -0
- package/plugins/toolu/hooks/post-tools/modules/push-waiver.sh +97 -0
- package/plugins/toolu/hooks/pre-compact.sh +18 -0
- package/plugins/toolu/hooks/pre-tools/agent-tier.sh +111 -0
- package/plugins/toolu/hooks/pre-tools/mod.sh +37 -0
- package/plugins/toolu/hooks/pre-tools/modules/bash-commands.sh +187 -0
- package/plugins/toolu/hooks/pre-tools/modules/code-edit-rules.sh +78 -0
- package/plugins/toolu/hooks/pre-tools/modules/commit-gate.sh +70 -0
- package/plugins/toolu/hooks/pre-tools/modules/docs-sync.sh +137 -0
- package/plugins/toolu/hooks/pre-tools/modules/mcp-blocker.sh +151 -0
- package/plugins/toolu/hooks/pre-tools/modules/plan-ledger.sh +201 -0
- package/plugins/toolu/hooks/pre-tools/modules/protected-files.sh +177 -0
- package/plugins/toolu/hooks/pre-tools/modules/push-review.sh +273 -0
- package/plugins/toolu/hooks/pre-tools/modules/quality-gate.sh +87 -0
- package/plugins/toolu/hooks/session-start.sh +379 -0
- package/plugins/toolu/hooks/user-prompt-submit.sh +197 -0
- package/plugins/toolu/scripts/context-budget.sh +111 -0
- package/plugins/toolu/scripts/debug-log.sh +98 -0
- package/plugins/toolu/scripts/debug-stack.sh +108 -0
- package/plugins/toolu/scripts/debug-testfail.sh +97 -0
- package/plugins/toolu/settings/.gitkeep +0 -0
- package/plugins/toolu/settings/README.md +127 -0
- package/plugins/toolu/settings/bash-allowlist.txt +12 -0
- package/plugins/toolu/settings/bash-denylist.txt +25 -0
- package/plugins/toolu/settings/code-edit-rules.json +67 -0
- package/plugins/toolu/settings/commit-prefixes.txt +12 -0
- package/plugins/toolu/settings/mcp-blocklist.txt +8 -0
- package/plugins/toolu/settings/permissions.fragment.json +36 -0
- package/plugins/toolu/settings/protected-files.txt +30 -0
- package/plugins/toolu/settings/rust-unsafe-exemptions.txt +5 -0
- package/plugins/toolu/settings/toolu.config.example.json +130 -0
- package/plugins/toolu/skills/.gitkeep +0 -0
- package/plugins/toolu/skills/brainstorm/SKILL.md +57 -0
- package/plugins/toolu/skills/brainstorm/references/design-questions.md +36 -0
- package/plugins/toolu/skills/commit/SKILL.md +11 -0
- package/plugins/toolu/skills/debug/SKILL.md +54 -0
- package/plugins/toolu/skills/debug/evals/README.md +17 -0
- package/plugins/toolu/skills/debug/evals/cases.json +24 -0
- package/plugins/toolu/skills/debug/evals/results.json +34 -0
- package/plugins/toolu/skills/deep-research/SKILL.md +51 -0
- package/plugins/toolu/skills/execution/SKILL.md +77 -0
- package/plugins/toolu/skills/orchestrator/SKILL.md +145 -0
- package/plugins/toolu/skills/orchestrator/references/delegation-cost.md +104 -0
- package/plugins/toolu/skills/orchestrator/references/model-routing.md +112 -0
- package/plugins/toolu/skills/plan/SKILL.md +56 -0
- package/plugins/toolu/skills/plan/references/ledger.md +18 -0
- package/plugins/toolu/skills/plan-review/SKILL.md +48 -0
- package/plugins/toolu/skills/review-and-commit/SKILL.md +10 -0
- package/plugins/toolu/skills/setup/SKILL.md +24 -0
- package/plugins/toolu/skills/setup/scripts/setup.sh +206 -0
- package/plugins/toolu/skills/spec/SKILL.md +67 -0
- package/plugins/toolu/skills/spec-review/SKILL.md +50 -0
- package/plugins/toolu/skills/test/SKILL.md +49 -0
- package/plugins/toolu/workflows/commit.md +21 -0
- package/plugins/toolu/workflows/host-mapping.md +22 -0
- package/plugins/toolu/workflows/review-and-commit.md +54 -0
- package/plugins/toolu/workflows/semantic-judgments.md +35 -0
- package/plugins/toolu-review/.claude-plugin/plugin.json +18 -0
- package/plugins/toolu-review/.codex-plugin/plugin.json +7 -0
- package/plugins/toolu-review/README.md +17 -0
- package/plugins/toolu-review/hooks/hooks.json +15 -0
- package/plugins/toolu-review/hooks/session-start.sh +34 -0
- package/plugins/toolu-review/skills/review/SKILL.md +90 -0
- package/plugins/toolu-review/skills/review/scripts/write-state.sh +189 -0
- package/plugins/ts-quality/.claude-plugin/plugin.json +24 -0
- package/plugins/ts-quality/.codex-plugin/plugin.json +6 -0
- package/plugins/ts-quality/README.md +24 -0
- package/plugins/ts-quality/hooks/check-toolu.sh +20 -0
- package/plugins/ts-quality/hooks/concerns/00-preamble.sh +123 -0
- package/plugins/ts-quality/hooks/concerns/10-imports.sh +33 -0
- package/plugins/ts-quality/hooks/concerns/15-type-as.sh +9 -0
- package/plugins/ts-quality/hooks/concerns/20-tests.sh +26 -0
- package/plugins/ts-quality/hooks/concerns/25-size-file.sh +40 -0
- package/plugins/ts-quality/hooks/concerns/30-size-fn.sh +53 -0
- package/plugins/ts-quality/hooks/concerns/35-react-hooks.sh +7 -0
- package/plugins/ts-quality/hooks/concerns/40-factory.sh +5 -0
- package/plugins/ts-quality/hooks/concerns/45-typeguard.sh +6 -0
- package/plugins/ts-quality/hooks/concerns/50-type-dup.sh +16 -0
- package/plugins/ts-quality/hooks/concerns/55-naming.sh +11 -0
- package/plugins/ts-quality/hooks/concerns/60-console.sh +6 -0
- package/plugins/ts-quality/hooks/concerns/65-suppression.sh +12 -0
- package/plugins/ts-quality/hooks/concerns/70-ui-confirm.sh +8 -0
- package/plugins/ts-quality/hooks/concerns/72-ui-radix.sh +12 -0
- package/plugins/ts-quality/hooks/concerns/74-react-props.sh +6 -0
- package/plugins/ts-quality/hooks/concerns/76-toast.sh +10 -0
- package/plugins/ts-quality/hooks/concerns/78-error-ast.sh +242 -0
- package/plugins/ts-quality/hooks/concerns/80-throw-literal.sh +23 -0
- package/plugins/ts-quality/hooks/concerns/85-no-mocks.sh +109 -0
- package/plugins/ts-quality/hooks/concerns/90-duplication.sh +30 -0
- package/plugins/ts-quality/hooks/concerns/92-docs.sh +36 -0
- package/plugins/ts-quality/hooks/concerns/94-handler.sh +15 -0
- package/plugins/ts-quality/hooks/concerns/99-finalize.sh +46 -0
- package/plugins/ts-quality/hooks/hooks.json +19 -0
- package/plugins/ts-quality/hooks/register.sh +65 -0
- package/src/adapter/__tests__/evaluate.test.ts +82 -0
- package/src/adapter/__tests__/permission-map.test.ts +91 -0
- package/src/adapter/evaluate.ts +54 -0
- package/src/adapter/permission-map.ts +177 -0
- package/src/bootstrap/__tests__/bootstrap.test.ts +148 -0
- package/src/bootstrap/entrypoint.ts +18 -0
- package/src/bootstrap/index.ts +5 -0
- package/src/bootstrap/readiness.ts +59 -0
- package/src/bootstrap/result.ts +21 -0
- package/src/bootstrap/runtime.ts +99 -0
- package/src/bootstrap/test-helpers.ts +25 -0
- package/src/host/__tests__/host.test.ts +37 -0
- package/src/host/detect.ts +46 -0
- package/src/host/index.ts +10 -0
- package/src/host/roots.ts +59 -0
- package/src/host/types.ts +14 -0
- package/src/inventory/__tests__/inventory.test.ts +69 -0
- package/src/inventory/index.ts +9 -0
- package/src/inventory/manifest.ts +46 -0
- package/src/inventory/scan.ts +66 -0
- package/src/inventory/selection.ts +92 -0
- package/src/inventory/types.ts +22 -0
- package/src/lifecycle/__tests__/lifecycle.test.ts +7 -0
- package/src/lifecycle/index.ts +2 -0
- package/src/lifecycle/table.ts +42 -0
- package/src/plugin/__tests__/plugin-stub.test.ts +6 -0
- package/src/plugin/plugin-stub.ts +7 -0
- package/src/plugin/toolu.ts +142 -0
- package/src/preflight/__tests__/preflight.test.ts +20 -0
- package/src/preflight/check.ts +75 -0
- package/src/preflight/index.ts +2 -0
- package/src/select/__tests__/select.test.ts +52 -0
- package/src/select/index.ts +2 -0
- package/src/select/resolve.ts +87 -0
|
@@ -0,0 +1,273 @@
|
|
|
1
|
+
#!/usr/bin/env bash
|
|
2
|
+
# Pre-tool check: gate `git push` on a recorded code review.
|
|
3
|
+
#
|
|
4
|
+
# How firmly it gates is a mode, not a constant — see lib/gate-mode.sh. At the
|
|
5
|
+
# shipped default (balanced) this ADVISES: the agent is told, the push is not
|
|
6
|
+
# stopped. `gates.pushReview.mode: ask` prompts and remembers a yes as a
|
|
7
|
+
# waiver for that exact diff (lib/push-waiver.sh). `block` restores the
|
|
8
|
+
# original hard deny.
|
|
9
|
+
# Project-agnostic: base branch is detected via detect_base_branch
|
|
10
|
+
# (or env-overridden with $PUSH_REVIEW_BASE for tests).
|
|
11
|
+
#
|
|
12
|
+
# Inputs (from parent dispatcher pre-tools/mod.sh, via `export`):
|
|
13
|
+
# $tool_name - name of the tool being invoked
|
|
14
|
+
# $input - raw JSON payload (also piped to stdin; this module reads the env var)
|
|
15
|
+
#
|
|
16
|
+
# State file: <host-state>/tmp/push-review/<branch-slug>.json
|
|
17
|
+
# Override via $STATE_DIR for testing.
|
|
18
|
+
|
|
19
|
+
# pipefail so a `git diff | git hash-object` failure surfaces; without it,
|
|
20
|
+
# an empty diff stream succeeds and yields the well-known empty-blob SHA,
|
|
21
|
+
# which a stale state file can cache and reuse across any future empty-diff
|
|
22
|
+
# state on the same branch (including post-force-reset).
|
|
23
|
+
set -o pipefail
|
|
24
|
+
|
|
25
|
+
: "${tool_name:=}"
|
|
26
|
+
: "${input:=}"
|
|
27
|
+
|
|
28
|
+
_toolu_lib="${TOOLU_LIB_DIR:-${BASH_SOURCE%/*}/../../lib}"
|
|
29
|
+
# shellcheck source=../../lib/detect.sh
|
|
30
|
+
. "$_toolu_lib/detect.sh"
|
|
31
|
+
# shellcheck source=../../lib/diff-sha.sh
|
|
32
|
+
. "$_toolu_lib/diff-sha.sh"
|
|
33
|
+
# shellcheck source=../../lib/telemetry.sh
|
|
34
|
+
. "$_toolu_lib/telemetry.sh"
|
|
35
|
+
# shellcheck source=../../lib/gate-mode.sh
|
|
36
|
+
. "$_toolu_lib/gate-mode.sh"
|
|
37
|
+
# shellcheck source=../../lib/push-waiver.sh
|
|
38
|
+
. "$_toolu_lib/push-waiver.sh"
|
|
39
|
+
|
|
40
|
+
[[ "$tool_name" != "Bash" ]] && exit 0
|
|
41
|
+
|
|
42
|
+
command -v jq >/dev/null 2>&1 || exit 0
|
|
43
|
+
command -v git >/dev/null 2>&1 || exit 0
|
|
44
|
+
|
|
45
|
+
command=$(echo "$input" | jq -r '.tool_input.command // ""')
|
|
46
|
+
|
|
47
|
+
# Push detection (strip_heredocs + boundary-anchored regex) is shared via
|
|
48
|
+
# detect.sh's is_git_push. The trailing boundary also catches statement
|
|
49
|
+
# terminators (`git push;`, `git push&`, `git push|tee`) — without them an agent
|
|
50
|
+
# could append `;` and slip the push past the gate, which is now the only
|
|
51
|
+
# push-time check.
|
|
52
|
+
is_git_push "$command" || exit 0
|
|
53
|
+
|
|
54
|
+
# Resolve the delivery mode before doing any work: `off` means this gate has
|
|
55
|
+
# nothing to say, and the git plumbing below is not free.
|
|
56
|
+
mode=$(toolu_gate_mode pushReview)
|
|
57
|
+
[ "$mode" = "off" ] && exit 0
|
|
58
|
+
|
|
59
|
+
# Every check below reads the repo the push TARGETS, not the hook's cwd — a
|
|
60
|
+
# `git -C <worktree> push` must be judged on the worktree's branch, diff and
|
|
61
|
+
# state file. Keying off $CLAUDE_PROJECT_DIR (a main-checkout path) split the
|
|
62
|
+
# state file in two: the reviewer wrote the worktree's copy while the gate read
|
|
63
|
+
# the main checkout's, so no amount of re-reviewing could satisfy it.
|
|
64
|
+
repo_root=$(push_target_root "$command")
|
|
65
|
+
|
|
66
|
+
# The checked-out branch, or — on a detached checkout such as pr-babysit's
|
|
67
|
+
# `git worktree add --detach` + `push origin HEAD:<branch>` — the refspec
|
|
68
|
+
# destination (push_target_branch in lib/detect.sh). Empty means neither
|
|
69
|
+
# names a branch and the detached-head deny below stands.
|
|
70
|
+
current_branch=$(push_target_branch "$command" "$repo_root")
|
|
71
|
+
slug=$(branch_slug "$current_branch")
|
|
72
|
+
|
|
73
|
+
# Resolve state dir: env override takes precedence; else target-repo default.
|
|
74
|
+
state_dir=${STATE_DIR:-$(toolu_project_state_dir push-review "$repo_root")}
|
|
75
|
+
state_file="$state_dir/${slug}.json"
|
|
76
|
+
|
|
77
|
+
# Base branch: env override > detect_base_branch, resolved in the target repo.
|
|
78
|
+
base_branch="${PUSH_REVIEW_BASE:-$(detect_base_branch "$repo_root")}"
|
|
79
|
+
|
|
80
|
+
# push_check telemetry: one closed set of reason codes across every decision
|
|
81
|
+
# exit below (base-missing, detached-head, diff-failed, no-state, stale-diff,
|
|
82
|
+
# schema-v1, schema, file-coverage, findings, reviewer, round-cap, empty-diff,
|
|
83
|
+
# pass). detached-head is unreachable-by-contract in the stream: telemetry_append
|
|
84
|
+
# refuses branch=="HEAD", so that deny never produces a line — the call stays for
|
|
85
|
+
# consistency should the contract change. ROUND is the state file's review_round
|
|
86
|
+
# when it's already known at the call site; the exits that precede reading the
|
|
87
|
+
# state file (or that fail its schema) pass "" -> JSON null.
|
|
88
|
+
_pr_telemetry() {
|
|
89
|
+
local result="$1" code="$2" round="${3:-}"
|
|
90
|
+
local round_json="null"
|
|
91
|
+
[[ "$round" =~ ^[0-9]+$ ]] && round_json="$round"
|
|
92
|
+
telemetry_append "$repo_root" "push_check" \
|
|
93
|
+
"$(jq -cn --arg result "$result" --arg code "$code" --argjson round "$round_json" \
|
|
94
|
+
'{result: $result, reason_code: $code, round: $round}')"
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
# _pr_decide CODE REASON [ROUND]
|
|
98
|
+
# Deliver one failed check in the configured mode, record it, and stop.
|
|
99
|
+
#
|
|
100
|
+
# In `ask` mode the question is also written down as a pending waiver keyed to
|
|
101
|
+
# the diff being asked about, so post-tools/modules/push-waiver.sh can promote
|
|
102
|
+
# it if the push actually happens. Checks that fail before a diff SHA exists
|
|
103
|
+
# (missing base, detached HEAD) have nothing to key a waiver to and simply skip
|
|
104
|
+
# that step — they are operational errors, not review decisions.
|
|
105
|
+
_pr_decide() {
|
|
106
|
+
local code="$1" reason="$2" round="${3:-}"
|
|
107
|
+
local result="$mode"
|
|
108
|
+
case "$mode" in
|
|
109
|
+
block) result=deny ;;
|
|
110
|
+
ask)
|
|
111
|
+
result=ask
|
|
112
|
+
reason="No clean review is recorded for this diff. Approving pushes anyway, and the approval is remembered until the diff changes.
|
|
113
|
+
|
|
114
|
+
$reason"
|
|
115
|
+
if [ -n "${current_diff_sha:-}" ]; then
|
|
116
|
+
push_waiver_pend "$repo_root" "$slug" "$current_diff_sha" "$base_branch" "$code" \
|
|
117
|
+
|| echo "push-review: could not record the pending waiver; a yes will be asked again" >&2
|
|
118
|
+
fi
|
|
119
|
+
;;
|
|
120
|
+
advise) result=advise ;;
|
|
121
|
+
esac
|
|
122
|
+
toolu_gate_emit "$mode" "$reason"
|
|
123
|
+
_pr_telemetry "$result" "$code" "$round"
|
|
124
|
+
exit 0
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
# Verify base branch exists locally.
|
|
128
|
+
if ! git -C "$repo_root" rev-parse --verify --quiet "$base_branch" >/dev/null; then
|
|
129
|
+
_pr_decide base-missing "base branch '$base_branch' not found locally; run \`git fetch origin $base_branch:$base_branch\`"
|
|
130
|
+
fi
|
|
131
|
+
|
|
132
|
+
# Detached HEAD with no refspec destination to judge instead.
|
|
133
|
+
if [[ "$current_branch" == "HEAD" || -z "$current_branch" ]]; then
|
|
134
|
+
_pr_decide detached-head "detached HEAD — checkout a branch, or push an explicit \`HEAD:<branch>\` refspec so the review state can be keyed to that branch"
|
|
135
|
+
fi
|
|
136
|
+
|
|
137
|
+
# Pushing the base branch itself (e.g. fast-forwarded main after a local merge)
|
|
138
|
+
# is not a feature-review scenario — `<base>...<base>` has empty diff by
|
|
139
|
+
# definition. Allow without state-file gate.
|
|
140
|
+
if [[ "$current_branch" == "$base_branch" ]]; then
|
|
141
|
+
exit 0
|
|
142
|
+
fi
|
|
143
|
+
|
|
144
|
+
# Compute branch diff SHA (content-addressed, survives amend/rebase).
|
|
145
|
+
# Well-known git empty-blob SHA — the value `git hash-object --stdin` produces
|
|
146
|
+
# for an empty stream. We refuse to cache or trust this value: a state file
|
|
147
|
+
# bearing it would be reusable across any future empty-diff state on the same
|
|
148
|
+
# branch (e.g. after a force reset wipes commits).
|
|
149
|
+
EMPTY_BLOB_SHA="e69de29bb2d1d6434b8b29ae775ad8c2e48c5391"
|
|
150
|
+
|
|
151
|
+
current_diff_sha=$(toolu_diff_sha "$repo_root" "$base_branch")
|
|
152
|
+
if [[ -z "$current_diff_sha" ]]; then
|
|
153
|
+
# git diff failed (disk full, etc). Allow push; underlying push will surface real failure.
|
|
154
|
+
echo "push-review: git diff ${base_branch}...HEAD failed; allowing push to surface real error" >&2
|
|
155
|
+
_pr_telemetry allow diff-failed
|
|
156
|
+
exit 0
|
|
157
|
+
fi
|
|
158
|
+
|
|
159
|
+
if [[ "$current_diff_sha" == "$EMPTY_BLOB_SHA" ]]; then
|
|
160
|
+
# Empty diff against base: nothing to review and nothing to push. Treat as
|
|
161
|
+
# a sentinel that NEVER satisfies the cache check, then deny the push so
|
|
162
|
+
# the user is forced to confirm intent rather than push a no-op.
|
|
163
|
+
current_diff_sha="empty-diff"
|
|
164
|
+
_pr_decide empty-diff "Refusing to push: diff against $base_branch is empty. Either no commits diverged from base, or the branch was force-reset. Verify intent before pushing."
|
|
165
|
+
fi
|
|
166
|
+
|
|
167
|
+
# A waiver for THIS diff means the user already answered "push anyway" for
|
|
168
|
+
# exactly this code. Honor it silently — asking again about an answered
|
|
169
|
+
# question is the nag this gate is trying not to be.
|
|
170
|
+
if push_waiver_matches "$repo_root" "$slug" "$current_diff_sha"; then
|
|
171
|
+
_pr_telemetry allow waived
|
|
172
|
+
exit 0
|
|
173
|
+
fi
|
|
174
|
+
|
|
175
|
+
# Reviewer guidance is agnostic: any one accepted reviewer satisfies the gate.
|
|
176
|
+
# The built-in /code-review skill is the always-available baseline.
|
|
177
|
+
reviewer_hint="the built-in \`/code-review xhigh --fix\` skill, recorded as \"code-review\" (or the \`toolu-review:review\` skill)"
|
|
178
|
+
|
|
179
|
+
# State file gate.
|
|
180
|
+
if [[ ! -f "$state_file" ]]; then
|
|
181
|
+
_pr_decide no-state "Code review required before push (diff SHA $current_diff_sha, base $base_branch).
|
|
182
|
+
Run a code reviewer on \`git diff $base_branch...HEAD\` and apply its findings — use $reviewer_hint. Then atomically write $state_file (tmp+mv) with schema { version: 2, branch, diff_sha, base_branch, reviewed_at, reviewers, findings_count, findings, review_round, reviewed_files }. \`reviewers\` must include at least one accepted reviewer (code-review, toolu-review:review, code-review:xhigh, review, or security-review), \`findings_count\` must be 0, \`review_round\` starts at 1 for a new \`diff_sha\` and bumps by 1 only when rewriting at the same \`diff_sha\`. \`reviewed_files\` must list every path from \`git diff $base_branch...HEAD --name-only\` (sorted, unique) — the actual reviewer file coverage. Retry push."
|
|
183
|
+
fi
|
|
184
|
+
|
|
185
|
+
# Validate state file: version, diff_sha, findings_count, reviewers.
|
|
186
|
+
state_version=$(jq -r '.version // ""' "$state_file" 2>/dev/null || echo "")
|
|
187
|
+
state_sha=$(jq -r '.diff_sha // ""' "$state_file" 2>/dev/null || echo "")
|
|
188
|
+
state_findings=$(jq -r '.findings_count // ""' "$state_file" 2>/dev/null || echo "")
|
|
189
|
+
|
|
190
|
+
# A schema v1 state (no reviewed_files contract) gets a dedicated one-time
|
|
191
|
+
# upgrade deny rather than the generic "corrupted" deny — the state is valid,
|
|
192
|
+
# just stale-schema, and the fix is a re-review, not a delete-and-retry.
|
|
193
|
+
if [[ "$state_version" == "1" ]]; then
|
|
194
|
+
_pr_decide schema-v1 "push-review state is schema v1; harness v2 requires reviewed_files — re-run the review to regenerate the state file"
|
|
195
|
+
fi
|
|
196
|
+
|
|
197
|
+
if [[ "$state_version" != "2" || -z "$state_sha" || -z "$state_findings" ]]; then
|
|
198
|
+
_pr_decide schema "state file corrupted at $state_file; delete and re-review"
|
|
199
|
+
fi
|
|
200
|
+
|
|
201
|
+
# review_round: read here (once) rather than only at the round-cap check below,
|
|
202
|
+
# so it's already known for the reviewer-acceptance telemetry exit too. Missing
|
|
203
|
+
# field defaults to round 1 for backward compat (same default the round-cap
|
|
204
|
+
# check uses).
|
|
205
|
+
state_round=$(jq -r '.review_round // 1' "$state_file" 2>/dev/null || echo "1")
|
|
206
|
+
|
|
207
|
+
# Reviewer-agnostic gate: at least ONE accepted reviewer must appear in the
|
|
208
|
+
# state file. The built-in /code-review skill is the always-available baseline;
|
|
209
|
+
# other known reviewers are accepted too. The check is "intersection non-empty",
|
|
210
|
+
# not equality, so running extra reviewers first is always
|
|
211
|
+
# fine. Requiring at least one known name still prevents an agent from writing a
|
|
212
|
+
# junk reviewer entry to bypass the gate.
|
|
213
|
+
accepted_reviewers='["code-review","toolu-review:review","code-review:xhigh","review","security-review"]'
|
|
214
|
+
if ! jq -e --argjson acc "$accepted_reviewers" \
|
|
215
|
+
'(.reviewers // []) as $r | any($acc[]; . as $x | $r | index($x) != null)' \
|
|
216
|
+
"$state_file" >/dev/null 2>&1; then
|
|
217
|
+
_pr_decide reviewer "state file lists no accepted reviewer at $state_file
|
|
218
|
+
\`reviewers\` must include at least one of: $accepted_reviewers
|
|
219
|
+
Run a reviewer — use $reviewer_hint — then rewrite the state file." "$state_round"
|
|
220
|
+
fi
|
|
221
|
+
|
|
222
|
+
# Max review rounds — bound the fix→re-review loop. `review_round` counts
|
|
223
|
+
# rewrites AT THE SAME diff_sha: a changed diff resets it to 1, so the counter
|
|
224
|
+
# measures "reviewers keep finding issues in code that never changed", not
|
|
225
|
+
# "this branch has been worked on for a while". Counting every rewrite instead
|
|
226
|
+
# made the cap terminal — nothing resets it after a push, so a long-lived
|
|
227
|
+
# branch eventually denied every push forever.
|
|
228
|
+
# Missing field is treated as round 1 for backward compat.
|
|
229
|
+
# After MAX_ROUNDS, deny with an escalation message so the babysit triggers
|
|
230
|
+
# its Step 6 escalation stop instead of looping indefinitely.
|
|
231
|
+
MAX_ROUNDS=5
|
|
232
|
+
if [[ "$state_round" =~ ^[0-9]+$ ]] && (( state_round > MAX_ROUNDS )); then
|
|
233
|
+
_pr_decide round-cap "ESCALATE: review loop hit $state_round rounds (max $MAX_ROUNDS) on an unchanged diff at $state_file. Reviewers keep finding new issues after each fix — stop auto-looping and surface the current findings to the human. Babysit: treat as Escalation stop (Step 6)." "$state_round"
|
|
234
|
+
fi
|
|
235
|
+
|
|
236
|
+
if [[ "$state_sha" != "$current_diff_sha" ]]; then
|
|
237
|
+
_pr_decide stale-diff "Code review required: diff changed since review.
|
|
238
|
+
Current diff SHA: $current_diff_sha
|
|
239
|
+
State file: $state_file (stale)
|
|
240
|
+
Re-run reviewers on the new diff and rewrite the state file." "$state_round"
|
|
241
|
+
fi
|
|
242
|
+
|
|
243
|
+
if [[ "$state_findings" != "0" ]]; then
|
|
244
|
+
_pr_decide findings "Code review has open findings ($state_findings).
|
|
245
|
+
State file: $state_file
|
|
246
|
+
Address every finding (any finding blocks). Re-commit. Re-run reviewers. Rewrite state file with findings_count=0." "$state_round"
|
|
247
|
+
fi
|
|
248
|
+
|
|
249
|
+
# Reviewer file coverage (v2): reviewed_files must equal the diff's changed
|
|
250
|
+
# paths (sorted, unique) — catches honestly-reported partial review scope.
|
|
251
|
+
# Not adversary-proof against a writer that lies about what it reviewed
|
|
252
|
+
# (Non-Goal 3, spec). A missing/malformed reviewed_files reads as empty here
|
|
253
|
+
# (jq errors are silenced), which correctly denies naming every changed path
|
|
254
|
+
# as missing rather than passing vacuously.
|
|
255
|
+
changed_sorted=$(git -C "$repo_root" diff --no-color "${base_branch}...HEAD" --name-only 2>/dev/null | sort -u)
|
|
256
|
+
reviewed_sorted=$(jq -r '.reviewed_files[]' "$state_file" 2>/dev/null | sort -u)
|
|
257
|
+
|
|
258
|
+
if [[ "$changed_sorted" != "$reviewed_sorted" ]]; then
|
|
259
|
+
missing=$(comm -23 <(printf '%s\n' "$changed_sorted") <(printf '%s\n' "$reviewed_sorted"))
|
|
260
|
+
extra=$(comm -13 <(printf '%s\n' "$changed_sorted") <(printf '%s\n' "$reviewed_sorted"))
|
|
261
|
+
reason="reviewed_files does not match the current diff at $state_file."
|
|
262
|
+
[ -n "$missing" ] && reason="$reason
|
|
263
|
+
Missing from reviewed_files (changed but not reviewed): $missing"
|
|
264
|
+
[ -n "$extra" ] && reason="$reason
|
|
265
|
+
In reviewed_files but not in the current diff: $extra"
|
|
266
|
+
reason="$reason
|
|
267
|
+
Re-review the full diff and rewrite reviewed_files to match \`git diff $base_branch...HEAD --name-only\` exactly."
|
|
268
|
+
_pr_decide file-coverage "$reason" "$state_round"
|
|
269
|
+
fi
|
|
270
|
+
|
|
271
|
+
# All gates pass: allow push.
|
|
272
|
+
_pr_telemetry allow pass "$state_round"
|
|
273
|
+
exit 0
|
|
@@ -0,0 +1,87 @@
|
|
|
1
|
+
#!/usr/bin/env bash
|
|
2
|
+
# Pre-tool check: quality gate enforcement.
|
|
3
|
+
#
|
|
4
|
+
# When the gate state file says "failing", this stops the two actions that
|
|
5
|
+
# would let a red build escape the working tree: `git commit` and `git push`.
|
|
6
|
+
# Nothing else. Reading, searching, editing, and running commands stay open —
|
|
7
|
+
# a failing gate is a reason not to SHIP, not a reason to be unable to work.
|
|
8
|
+
# (It used to deny every tool call except a whitelist, which meant a stale red
|
|
9
|
+
# gate could block `ls`.)
|
|
10
|
+
#
|
|
11
|
+
# How firmly it stops them is a mode — see lib/gate-mode.sh. Default: block.
|
|
12
|
+
# `MY_CLAUDE_QUALITY=off` remains an env-level kill switch for the whole gate.
|
|
13
|
+
#
|
|
14
|
+
# Project-agnostic: tooling is auto-detected; missing tooling → silent skip.
|
|
15
|
+
#
|
|
16
|
+
# Inputs (from parent dispatcher pre-tools/mod.sh, via `export`):
|
|
17
|
+
# $tool_name - name of the tool being invoked
|
|
18
|
+
# $input - raw JSON payload on stdin
|
|
19
|
+
|
|
20
|
+
: "${tool_name:=}"
|
|
21
|
+
: "${input:=}"
|
|
22
|
+
|
|
23
|
+
_toolu_lib="${TOOLU_LIB_DIR:-${BASH_SOURCE%/*}/../../lib}"
|
|
24
|
+
# shellcheck source=../../lib/detect.sh
|
|
25
|
+
. "$_toolu_lib/detect.sh"
|
|
26
|
+
# shellcheck source=../../lib/gate-mode.sh
|
|
27
|
+
. "$_toolu_lib/gate-mode.sh"
|
|
28
|
+
|
|
29
|
+
# Owner kill-switch.
|
|
30
|
+
[ "${MY_CLAUDE_QUALITY:-}" = "off" ] && exit 0
|
|
31
|
+
|
|
32
|
+
# Guard tooling.
|
|
33
|
+
command -v jq >/dev/null 2>&1 || exit 0
|
|
34
|
+
command -v git >/dev/null 2>&1 || exit 0
|
|
35
|
+
|
|
36
|
+
# Only Bash/Shell can commit or push, so every other tool is out of scope
|
|
37
|
+
# before any file is read.
|
|
38
|
+
[[ "$tool_name" != "Bash" && "$tool_name" != "Shell" ]] && exit 0
|
|
39
|
+
|
|
40
|
+
command=$(echo "$input" | jq -r '.tool_input.command // ""')
|
|
41
|
+
cmd_only=$(printf '%s\n' "$command" | strip_heredocs)
|
|
42
|
+
|
|
43
|
+
# Heredoc-stripped, boundary-anchored detection shared with push-review, so
|
|
44
|
+
# `git -C <path> commit` and `foo && git push` are seen and a commit message
|
|
45
|
+
# that merely mentions pushing is not.
|
|
46
|
+
if ! is_git_commit "$cmd_only" && ! is_git_push "$cmd_only"; then
|
|
47
|
+
exit 0
|
|
48
|
+
fi
|
|
49
|
+
|
|
50
|
+
# Only now is the config worth loading. This module runs on every Bash call and
|
|
51
|
+
# almost none of them are a commit or a push; resolving the mode first would
|
|
52
|
+
# have paid a config read + jq parse for every `ls`.
|
|
53
|
+
mode=$(toolu_gate_mode qualityGate)
|
|
54
|
+
[ "$mode" = "off" ] && exit 0
|
|
55
|
+
|
|
56
|
+
project_root="$(detect_project_root)"
|
|
57
|
+
[ -z "$project_root" ] && project_root="$(pwd)"
|
|
58
|
+
|
|
59
|
+
gate_file="$(toolu_project_state_root "$project_root")/quality-gate-status.json"
|
|
60
|
+
|
|
61
|
+
[[ ! -f "$gate_file" ]] && exit 0
|
|
62
|
+
[[ "$(jq -r '.status // ""' "$gate_file" 2>/dev/null)" != "failing" ]] && exit 0
|
|
63
|
+
|
|
64
|
+
# Skip enforcement in git linked worktrees — quality state lives on the main checkout.
|
|
65
|
+
git_dir="$(git -C "$project_root" rev-parse --path-format=absolute --git-dir 2>/dev/null || true)"
|
|
66
|
+
common_dir="$(git -C "$project_root" rev-parse --path-format=absolute --git-common-dir 2>/dev/null || true)"
|
|
67
|
+
git_dir="${git_dir%/}"
|
|
68
|
+
common_dir="${common_dir%/}"
|
|
69
|
+
if [[ -n "$git_dir" && -n "$common_dir" && "$git_dir" != "$common_dir" ]]; then
|
|
70
|
+
exit 0
|
|
71
|
+
fi
|
|
72
|
+
|
|
73
|
+
reason=$(jq -r '.reason // "Quality gate failing"' "$gate_file" 2>/dev/null || echo "Quality gate failing")
|
|
74
|
+
violations=$(jq -r '.violations // ""' "$gate_file" 2>/dev/null || echo "")
|
|
75
|
+
|
|
76
|
+
# The lead sentence follows the mode: claiming something was BLOCKED while
|
|
77
|
+
# merely advising would be a lie in the one place the user is reading closely.
|
|
78
|
+
case "$mode" in
|
|
79
|
+
block) lead="BLOCKED: quality gate failing — fix the violations before committing or pushing." ;;
|
|
80
|
+
ask) lead="The quality gate is failing. Commit/push anyway?" ;;
|
|
81
|
+
*) lead="Heads up: the quality gate is failing (commit and push are not blocked at this setting)." ;;
|
|
82
|
+
esac
|
|
83
|
+
|
|
84
|
+
toolu_gate_emit "$mode" "$lead
|
|
85
|
+
$reason
|
|
86
|
+
$violations"
|
|
87
|
+
exit 0
|