@qball-inc/the-bulwark 1.0.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/.claude-plugin/plugin.json +43 -0
- package/agents/bulwark-fix-validator.md +633 -0
- package/agents/bulwark-implementer.md +391 -0
- package/agents/bulwark-issue-analyzer.md +308 -0
- package/agents/bulwark-standards-reviewer.md +221 -0
- package/agents/plan-creation-architect.md +323 -0
- package/agents/plan-creation-eng-lead.md +352 -0
- package/agents/plan-creation-po.md +300 -0
- package/agents/plan-creation-qa-critic.md +334 -0
- package/agents/product-ideation-competitive-analyzer.md +298 -0
- package/agents/product-ideation-idea-validator.md +268 -0
- package/agents/product-ideation-market-researcher.md +292 -0
- package/agents/product-ideation-pattern-documenter.md +308 -0
- package/agents/product-ideation-segment-analyzer.md +303 -0
- package/agents/product-ideation-strategist.md +259 -0
- package/agents/statusline-setup.md +97 -0
- package/hooks/hooks.json +59 -0
- package/package.json +45 -0
- package/scripts/hooks/cleanup-stale.sh +13 -0
- package/scripts/hooks/enforce-quality.sh +166 -0
- package/scripts/hooks/implementer-quality.sh +256 -0
- package/scripts/hooks/inject-protocol.sh +52 -0
- package/scripts/hooks/suggest-pipeline.sh +175 -0
- package/scripts/hooks/track-pipeline-start.sh +37 -0
- package/scripts/hooks/track-pipeline-stop.sh +52 -0
- package/scripts/init-rules.sh +35 -0
- package/scripts/init.sh +151 -0
- package/skills/anthropic-validator/SKILL.md +607 -0
- package/skills/anthropic-validator/references/agents-checklist.md +131 -0
- package/skills/anthropic-validator/references/commands-checklist.md +102 -0
- package/skills/anthropic-validator/references/hooks-checklist.md +151 -0
- package/skills/anthropic-validator/references/mcp-checklist.md +136 -0
- package/skills/anthropic-validator/references/plugins-checklist.md +148 -0
- package/skills/anthropic-validator/references/skills-checklist.md +85 -0
- package/skills/assertion-patterns/SKILL.md +296 -0
- package/skills/bug-magnet-data/SKILL.md +284 -0
- package/skills/bug-magnet-data/context/cli-args.md +91 -0
- package/skills/bug-magnet-data/context/db-query.md +104 -0
- package/skills/bug-magnet-data/context/file-contents.md +103 -0
- package/skills/bug-magnet-data/context/http-body.md +91 -0
- package/skills/bug-magnet-data/context/process-spawn.md +123 -0
- package/skills/bug-magnet-data/data/booleans/boundaries.yaml +143 -0
- package/skills/bug-magnet-data/data/collections/arrays.yaml +114 -0
- package/skills/bug-magnet-data/data/collections/objects.yaml +123 -0
- package/skills/bug-magnet-data/data/concurrency/race-conditions.yaml +118 -0
- package/skills/bug-magnet-data/data/concurrency/state-machines.yaml +115 -0
- package/skills/bug-magnet-data/data/dates/boundaries.yaml +137 -0
- package/skills/bug-magnet-data/data/dates/invalid.yaml +132 -0
- package/skills/bug-magnet-data/data/dates/timezone.yaml +118 -0
- package/skills/bug-magnet-data/data/encoding/charset.yaml +79 -0
- package/skills/bug-magnet-data/data/encoding/normalization.yaml +105 -0
- package/skills/bug-magnet-data/data/formats/email.yaml +154 -0
- package/skills/bug-magnet-data/data/formats/json.yaml +187 -0
- package/skills/bug-magnet-data/data/formats/url.yaml +165 -0
- package/skills/bug-magnet-data/data/language-specific/javascript.yaml +182 -0
- package/skills/bug-magnet-data/data/language-specific/python.yaml +174 -0
- package/skills/bug-magnet-data/data/language-specific/rust.yaml +148 -0
- package/skills/bug-magnet-data/data/numbers/boundaries.yaml +161 -0
- package/skills/bug-magnet-data/data/numbers/precision.yaml +89 -0
- package/skills/bug-magnet-data/data/numbers/special.yaml +69 -0
- package/skills/bug-magnet-data/data/strings/boundaries.yaml +109 -0
- package/skills/bug-magnet-data/data/strings/injection.yaml +208 -0
- package/skills/bug-magnet-data/data/strings/special-chars.yaml +190 -0
- package/skills/bug-magnet-data/data/strings/unicode.yaml +139 -0
- package/skills/bug-magnet-data/references/external-lists.md +115 -0
- package/skills/bulwark-brainstorm/SKILL.md +563 -0
- package/skills/bulwark-brainstorm/references/at-teammate-prompts.md +60 -0
- package/skills/bulwark-brainstorm/references/role-critical-analyst.md +78 -0
- package/skills/bulwark-brainstorm/references/role-development-lead.md +66 -0
- package/skills/bulwark-brainstorm/references/role-product-delivery-lead.md +79 -0
- package/skills/bulwark-brainstorm/references/role-product-manager.md +62 -0
- package/skills/bulwark-brainstorm/references/role-project-sme.md +59 -0
- package/skills/bulwark-brainstorm/references/role-technical-architect.md +66 -0
- package/skills/bulwark-research/SKILL.md +298 -0
- package/skills/bulwark-research/references/viewpoint-contrarian.md +63 -0
- package/skills/bulwark-research/references/viewpoint-direct-investigation.md +62 -0
- package/skills/bulwark-research/references/viewpoint-first-principles.md +65 -0
- package/skills/bulwark-research/references/viewpoint-practitioner.md +62 -0
- package/skills/bulwark-research/references/viewpoint-prior-art.md +66 -0
- package/skills/bulwark-scaffold/SKILL.md +330 -0
- package/skills/bulwark-statusline/SKILL.md +161 -0
- package/skills/bulwark-statusline/scripts/statusline.sh +144 -0
- package/skills/bulwark-verify/SKILL.md +519 -0
- package/skills/code-review/SKILL.md +428 -0
- package/skills/code-review/examples/anti-patterns/linting.ts +181 -0
- package/skills/code-review/examples/anti-patterns/security.ts +91 -0
- package/skills/code-review/examples/anti-patterns/standards.ts +195 -0
- package/skills/code-review/examples/anti-patterns/type-safety.ts +108 -0
- package/skills/code-review/examples/recommended/linting.ts +195 -0
- package/skills/code-review/examples/recommended/security.ts +154 -0
- package/skills/code-review/examples/recommended/standards.ts +231 -0
- package/skills/code-review/examples/recommended/type-safety.ts +181 -0
- package/skills/code-review/frameworks/angular.md +218 -0
- package/skills/code-review/frameworks/django.md +235 -0
- package/skills/code-review/frameworks/express.md +207 -0
- package/skills/code-review/frameworks/flask.md +298 -0
- package/skills/code-review/frameworks/generic.md +146 -0
- package/skills/code-review/frameworks/react.md +152 -0
- package/skills/code-review/frameworks/vue.md +244 -0
- package/skills/code-review/references/linting-patterns.md +221 -0
- package/skills/code-review/references/security-patterns.md +125 -0
- package/skills/code-review/references/standards-patterns.md +246 -0
- package/skills/code-review/references/type-safety-patterns.md +130 -0
- package/skills/component-patterns/SKILL.md +131 -0
- package/skills/component-patterns/references/pattern-cli-command.md +118 -0
- package/skills/component-patterns/references/pattern-database.md +166 -0
- package/skills/component-patterns/references/pattern-external-api.md +139 -0
- package/skills/component-patterns/references/pattern-file-parser.md +168 -0
- package/skills/component-patterns/references/pattern-http-server.md +162 -0
- package/skills/component-patterns/references/pattern-process-spawner.md +133 -0
- package/skills/continuous-feedback/SKILL.md +327 -0
- package/skills/continuous-feedback/references/collect-instructions.md +81 -0
- package/skills/continuous-feedback/references/specialize-code-review.md +82 -0
- package/skills/continuous-feedback/references/specialize-general.md +98 -0
- package/skills/continuous-feedback/references/specialize-test-audit.md +81 -0
- package/skills/create-skill/SKILL.md +359 -0
- package/skills/create-skill/references/agent-conventions.md +194 -0
- package/skills/create-skill/references/agent-template.md +195 -0
- package/skills/create-skill/references/content-guidance.md +291 -0
- package/skills/create-skill/references/decision-framework.md +124 -0
- package/skills/create-skill/references/template-pipeline.md +217 -0
- package/skills/create-skill/references/template-reference-heavy.md +111 -0
- package/skills/create-skill/references/template-research.md +210 -0
- package/skills/create-skill/references/template-script-driven.md +172 -0
- package/skills/create-skill/references/template-simple.md +80 -0
- package/skills/create-subagent/SKILL.md +353 -0
- package/skills/create-subagent/references/agent-conventions.md +268 -0
- package/skills/create-subagent/references/content-guidance.md +232 -0
- package/skills/create-subagent/references/decision-framework.md +134 -0
- package/skills/create-subagent/references/template-single-agent.md +192 -0
- package/skills/fix-bug/SKILL.md +241 -0
- package/skills/governance-protocol/SKILL.md +116 -0
- package/skills/init/SKILL.md +341 -0
- package/skills/issue-debugging/SKILL.md +385 -0
- package/skills/issue-debugging/references/anti-patterns.md +245 -0
- package/skills/issue-debugging/references/debug-report-schema.md +227 -0
- package/skills/mock-detection/SKILL.md +511 -0
- package/skills/mock-detection/references/false-positive-prevention.md +402 -0
- package/skills/mock-detection/references/stub-patterns.md +236 -0
- package/skills/pipeline-templates/SKILL.md +215 -0
- package/skills/pipeline-templates/references/code-change-workflow.md +277 -0
- package/skills/pipeline-templates/references/code-review.md +336 -0
- package/skills/pipeline-templates/references/fix-validation.md +421 -0
- package/skills/pipeline-templates/references/new-feature.md +335 -0
- package/skills/pipeline-templates/references/research-brainstorm.md +161 -0
- package/skills/pipeline-templates/references/research-planning.md +257 -0
- package/skills/pipeline-templates/references/test-audit.md +389 -0
- package/skills/pipeline-templates/references/test-execution-fix.md +238 -0
- package/skills/plan-creation/SKILL.md +497 -0
- package/skills/product-ideation/SKILL.md +372 -0
- package/skills/product-ideation/references/analysis-frameworks.md +161 -0
- package/skills/session-handoff/SKILL.md +139 -0
- package/skills/session-handoff/references/examples.md +223 -0
- package/skills/setup-lsp/SKILL.md +312 -0
- package/skills/setup-lsp/references/server-registry.md +85 -0
- package/skills/setup-lsp/references/troubleshooting.md +135 -0
- package/skills/subagent-output-templating/SKILL.md +415 -0
- package/skills/subagent-output-templating/references/examples.md +440 -0
- package/skills/subagent-prompting/SKILL.md +364 -0
- package/skills/subagent-prompting/references/examples.md +342 -0
- package/skills/test-audit/SKILL.md +531 -0
- package/skills/test-audit/references/known-limitations.md +41 -0
- package/skills/test-audit/references/priority-classification.md +30 -0
- package/skills/test-audit/references/prompts/deep-mode-detection.md +83 -0
- package/skills/test-audit/references/prompts/synthesis.md +57 -0
- package/skills/test-audit/references/rewrite-instructions.md +46 -0
- package/skills/test-audit/references/schemas/audit-output.yaml +100 -0
- package/skills/test-audit/references/schemas/diagnostic-output.yaml +49 -0
- package/skills/test-audit/scripts/data-flow-analyzer.ts +509 -0
- package/skills/test-audit/scripts/integration-mock-detector.ts +462 -0
- package/skills/test-audit/scripts/package.json +20 -0
- package/skills/test-audit/scripts/skip-detector.ts +211 -0
- package/skills/test-audit/scripts/verification-counter.ts +295 -0
- package/skills/test-classification/SKILL.md +310 -0
- package/skills/test-fixture-creation/SKILL.md +295 -0
|
@@ -0,0 +1,256 @@
|
|
|
1
|
+
#!/bin/bash
|
|
2
|
+
# implementer-quality.sh - Agent-invoked quality gate + pipeline suggestion
|
|
3
|
+
#
|
|
4
|
+
# Called by bulwark-implementer agent directly via Bash after each Write/Edit.
|
|
5
|
+
# Unlike enforce-quality.sh (which reads stdin JSON from hook system),
|
|
6
|
+
# this script accepts a file path as a CLI argument.
|
|
7
|
+
#
|
|
8
|
+
# Phase 1: Quality checks (code files only)
|
|
9
|
+
# - Runs just typecheck, lint, build
|
|
10
|
+
# - Outputs error details to stdout on failure
|
|
11
|
+
#
|
|
12
|
+
# Phase 2: Pipeline suggestion (all file types)
|
|
13
|
+
# - Classifies file type and estimates change size
|
|
14
|
+
# - Outputs plain text suggestion
|
|
15
|
+
#
|
|
16
|
+
# Exit codes:
|
|
17
|
+
# 0 = All checks passed (or non-code file)
|
|
18
|
+
# 1 = Quality gate failed
|
|
19
|
+
#
|
|
20
|
+
# Usage: implementer-quality.sh <file_path>
|
|
21
|
+
|
|
22
|
+
set -euo pipefail
|
|
23
|
+
|
|
24
|
+
# Configuration
|
|
25
|
+
MAX_OUTPUT_LINES=100
|
|
26
|
+
|
|
27
|
+
# Validate arguments
|
|
28
|
+
if [ $# -lt 1 ]; then
|
|
29
|
+
echo "ERROR: Missing file path argument" >&2
|
|
30
|
+
echo "Usage: implementer-quality.sh <file_path>" >&2
|
|
31
|
+
exit 1
|
|
32
|
+
fi
|
|
33
|
+
|
|
34
|
+
FILE_PATH="$1"
|
|
35
|
+
|
|
36
|
+
# Get directories
|
|
37
|
+
SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)"
|
|
38
|
+
PROJECT_DIR="${CLAUDE_PROJECT_DIR:-.}"
|
|
39
|
+
LOGS_DIR="${PROJECT_DIR}/logs"
|
|
40
|
+
HOOKS_LOG="${LOGS_DIR}/hooks.log"
|
|
41
|
+
|
|
42
|
+
# Ensure logs directory exists
|
|
43
|
+
mkdir -p "$LOGS_DIR"
|
|
44
|
+
|
|
45
|
+
# Log invocation
|
|
46
|
+
TIMESTAMP=$(date -Iseconds)
|
|
47
|
+
echo "[$TIMESTAMP] implementer-quality.sh invoked for ${FILE_PATH}" >> "$HOOKS_LOG"
|
|
48
|
+
|
|
49
|
+
# Skip infrastructure directories
|
|
50
|
+
case "$FILE_PATH" in
|
|
51
|
+
*/logs/*|logs/*|*/tmp/*|tmp/*|*/.claude/*|.claude/*|*/node_modules/*|node_modules/*)
|
|
52
|
+
echo "QUALITY: SKIPPED (infrastructure path)"
|
|
53
|
+
exit 0
|
|
54
|
+
;;
|
|
55
|
+
esac
|
|
56
|
+
|
|
57
|
+
# Function to detect if file is a code file
|
|
58
|
+
is_code_file() {
|
|
59
|
+
local path="$1"
|
|
60
|
+
echo "$path" | grep -qiE '\.(ts|js|tsx|jsx|py|go|rs|java|cpp|c|rb|php|swift|kt)$'
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
# Function to find just command
|
|
64
|
+
find_just() {
|
|
65
|
+
if command -v just &> /dev/null; then
|
|
66
|
+
echo "just"
|
|
67
|
+
elif [ -x "$HOME/.local/bin/just" ]; then
|
|
68
|
+
echo "$HOME/.local/bin/just"
|
|
69
|
+
elif [ -x "/usr/local/bin/just" ]; then
|
|
70
|
+
echo "/usr/local/bin/just"
|
|
71
|
+
else
|
|
72
|
+
echo ""
|
|
73
|
+
fi
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
# Function to check if a Justfile recipe exists
|
|
77
|
+
recipe_exists() {
|
|
78
|
+
local recipe="$1"
|
|
79
|
+
local just_cmd="$2"
|
|
80
|
+
$just_cmd --list 2>/dev/null | grep -qE "^${recipe}[[:space:]]" || \
|
|
81
|
+
$just_cmd --list 2>/dev/null | grep -qE "^${recipe}$"
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
# ============================================================
|
|
85
|
+
# PHASE 1: Quality Checks (code files only)
|
|
86
|
+
# ============================================================
|
|
87
|
+
|
|
88
|
+
QUALITY_PASSED="true"
|
|
89
|
+
|
|
90
|
+
if is_code_file "$FILE_PATH"; then
|
|
91
|
+
if [ ! -f "${PROJECT_DIR}/Justfile" ]; then
|
|
92
|
+
echo "WARNING: No Justfile found. Quality checks skipped."
|
|
93
|
+
else
|
|
94
|
+
JUST_CMD=$(find_just)
|
|
95
|
+
|
|
96
|
+
if [ -z "$JUST_CMD" ]; then
|
|
97
|
+
echo "WARNING: just command not found. Quality checks skipped."
|
|
98
|
+
else
|
|
99
|
+
cd "${PROJECT_DIR}"
|
|
100
|
+
|
|
101
|
+
# Run typecheck if recipe exists
|
|
102
|
+
if recipe_exists "typecheck" "$JUST_CMD"; then
|
|
103
|
+
TYPECHECK_OUTPUT=$($JUST_CMD typecheck 2>&1 | head -n $MAX_OUTPUT_LINES) || {
|
|
104
|
+
QUALITY_PASSED="false"
|
|
105
|
+
echo "QUALITY: FAILED"
|
|
106
|
+
echo "GATE: typecheck"
|
|
107
|
+
echo "---"
|
|
108
|
+
echo "$TYPECHECK_OUTPUT"
|
|
109
|
+
echo "---"
|
|
110
|
+
echo "Fix the type errors above and retry."
|
|
111
|
+
echo "[$TIMESTAMP] implementer-quality.sh: FAILED typecheck for ${FILE_PATH}" >> "$HOOKS_LOG"
|
|
112
|
+
exit 1
|
|
113
|
+
}
|
|
114
|
+
fi
|
|
115
|
+
|
|
116
|
+
# Run lint if recipe exists
|
|
117
|
+
if recipe_exists "lint" "$JUST_CMD"; then
|
|
118
|
+
LINT_OUTPUT=$($JUST_CMD lint 2>&1 | head -n $MAX_OUTPUT_LINES) || {
|
|
119
|
+
QUALITY_PASSED="false"
|
|
120
|
+
echo "QUALITY: FAILED"
|
|
121
|
+
echo "GATE: lint"
|
|
122
|
+
echo "---"
|
|
123
|
+
echo "$LINT_OUTPUT"
|
|
124
|
+
echo "---"
|
|
125
|
+
echo "Fix the lint errors above and retry."
|
|
126
|
+
echo "[$TIMESTAMP] implementer-quality.sh: FAILED lint for ${FILE_PATH}" >> "$HOOKS_LOG"
|
|
127
|
+
exit 1
|
|
128
|
+
}
|
|
129
|
+
fi
|
|
130
|
+
|
|
131
|
+
# Run build if recipe exists
|
|
132
|
+
if recipe_exists "build" "$JUST_CMD"; then
|
|
133
|
+
BUILD_OUTPUT=$($JUST_CMD build 2>&1 | head -n $MAX_OUTPUT_LINES) || {
|
|
134
|
+
QUALITY_PASSED="false"
|
|
135
|
+
echo "QUALITY: FAILED"
|
|
136
|
+
echo "GATE: build"
|
|
137
|
+
echo "---"
|
|
138
|
+
echo "$BUILD_OUTPUT"
|
|
139
|
+
echo "---"
|
|
140
|
+
echo "Fix the build errors above and retry."
|
|
141
|
+
echo "[$TIMESTAMP] implementer-quality.sh: FAILED build for ${FILE_PATH}" >> "$HOOKS_LOG"
|
|
142
|
+
exit 1
|
|
143
|
+
}
|
|
144
|
+
fi
|
|
145
|
+
fi
|
|
146
|
+
fi
|
|
147
|
+
fi
|
|
148
|
+
|
|
149
|
+
# ============================================================
|
|
150
|
+
# PHASE 2: Pipeline Suggestion (all file types)
|
|
151
|
+
# ============================================================
|
|
152
|
+
|
|
153
|
+
# Extract file extension and name
|
|
154
|
+
FILENAME=$(basename "$FILE_PATH")
|
|
155
|
+
EXTENSION="${FILENAME##*.}"
|
|
156
|
+
EXTENSION_LOWER=$(echo "$EXTENSION" | tr '[:upper:]' '[:lower:]')
|
|
157
|
+
|
|
158
|
+
# Determine file type
|
|
159
|
+
IS_CODE="false"
|
|
160
|
+
IS_TEST="false"
|
|
161
|
+
IS_CONFIG="false"
|
|
162
|
+
IS_DOC="false"
|
|
163
|
+
IS_SCRIPT="false"
|
|
164
|
+
IS_DATA="false"
|
|
165
|
+
|
|
166
|
+
# Code files
|
|
167
|
+
if echo "$EXTENSION_LOWER" | grep -qE '^(ts|js|tsx|jsx|py|go|rs|java|cpp|c|rb|php|swift|kt)$'; then
|
|
168
|
+
IS_CODE="true"
|
|
169
|
+
fi
|
|
170
|
+
|
|
171
|
+
# Test files (check filename pattern)
|
|
172
|
+
if echo "$FILENAME" | grep -qiE '(test|spec|_test)\.(ts|js|tsx|jsx|py|go|rs|java|cpp|rb)$'; then
|
|
173
|
+
IS_TEST="true"
|
|
174
|
+
IS_CODE="false"
|
|
175
|
+
fi
|
|
176
|
+
|
|
177
|
+
# Config files
|
|
178
|
+
if echo "$EXTENSION_LOWER" | grep -qE '^(json|yaml|yml|toml|ini|env|config)$'; then
|
|
179
|
+
IS_CONFIG="true"
|
|
180
|
+
fi
|
|
181
|
+
|
|
182
|
+
# Documentation files
|
|
183
|
+
if echo "$EXTENSION_LOWER" | grep -qE '^(md|txt|rst|adoc)$'; then
|
|
184
|
+
IS_DOC="true"
|
|
185
|
+
fi
|
|
186
|
+
|
|
187
|
+
# Script files
|
|
188
|
+
if echo "$EXTENSION_LOWER" | grep -qE '^(sh|bash|zsh|fish|ps1)$'; then
|
|
189
|
+
IS_SCRIPT="true"
|
|
190
|
+
fi
|
|
191
|
+
|
|
192
|
+
# Data files
|
|
193
|
+
if echo "$EXTENSION_LOWER" | grep -qE '^(xlsx|xls|csv|pdf|docx|pptx)$'; then
|
|
194
|
+
IS_DATA="true"
|
|
195
|
+
fi
|
|
196
|
+
|
|
197
|
+
# Count file lines as change size proxy (no hook JSON available)
|
|
198
|
+
if [ -f "$FILE_PATH" ]; then
|
|
199
|
+
CHANGE_SIZE=$(wc -l < "$FILE_PATH" 2>/dev/null || echo "0")
|
|
200
|
+
else
|
|
201
|
+
CHANGE_SIZE=0
|
|
202
|
+
fi
|
|
203
|
+
|
|
204
|
+
# Determine threshold based on file type
|
|
205
|
+
THRESHOLD=5
|
|
206
|
+
if [ "$IS_TEST" = "true" ]; then
|
|
207
|
+
THRESHOLD=10
|
|
208
|
+
elif [ "$IS_CONFIG" = "true" ]; then
|
|
209
|
+
THRESHOLD=3
|
|
210
|
+
elif [ "$IS_DOC" = "true" ]; then
|
|
211
|
+
THRESHOLD=10
|
|
212
|
+
elif [ "$IS_SCRIPT" = "true" ]; then
|
|
213
|
+
THRESHOLD=3
|
|
214
|
+
elif [ "$IS_DATA" = "true" ]; then
|
|
215
|
+
THRESHOLD=1
|
|
216
|
+
fi
|
|
217
|
+
|
|
218
|
+
# Determine recommended pipeline
|
|
219
|
+
RECOMMENDED_PIPELINE="none"
|
|
220
|
+
if [ "$CHANGE_SIZE" -gt "$THRESHOLD" ]; then
|
|
221
|
+
if [ "$IS_CODE" = "true" ]; then
|
|
222
|
+
# Check if file already existed (Edit vs new Write)
|
|
223
|
+
# Since we can't tell from CLI, use line count as heuristic:
|
|
224
|
+
# large files are likely existing code, small files may be new
|
|
225
|
+
RECOMMENDED_PIPELINE="Code Review"
|
|
226
|
+
elif [ "$IS_TEST" = "true" ]; then
|
|
227
|
+
RECOMMENDED_PIPELINE="Test Audit"
|
|
228
|
+
elif [ "$IS_CONFIG" = "true" ]; then
|
|
229
|
+
RECOMMENDED_PIPELINE="Code Review"
|
|
230
|
+
elif [ "$IS_SCRIPT" = "true" ]; then
|
|
231
|
+
RECOMMENDED_PIPELINE="Code Review"
|
|
232
|
+
elif [ "$IS_DOC" = "true" ]; then
|
|
233
|
+
RECOMMENDED_PIPELINE="none"
|
|
234
|
+
elif [ "$IS_DATA" = "true" ]; then
|
|
235
|
+
RECOMMENDED_PIPELINE="none"
|
|
236
|
+
fi
|
|
237
|
+
fi
|
|
238
|
+
|
|
239
|
+
# Log decision
|
|
240
|
+
echo "[$TIMESTAMP] implementer-quality.sh: PASSED for ${FILE_PATH} (pipeline: ${RECOMMENDED_PIPELINE}, lines: ${CHANGE_SIZE})" >> "$HOOKS_LOG"
|
|
241
|
+
|
|
242
|
+
# Output results in plain text format
|
|
243
|
+
echo "QUALITY: PASSED"
|
|
244
|
+
echo "PIPELINE: ${RECOMMENDED_PIPELINE}"
|
|
245
|
+
echo "TARGET: ${FILE_PATH}"
|
|
246
|
+
echo "LINES: ${CHANGE_SIZE}"
|
|
247
|
+
if [ "$RECOMMENDED_PIPELINE" != "none" ]; then
|
|
248
|
+
echo "REASON: File type detected, ${CHANGE_SIZE} lines exceeds threshold ${THRESHOLD}"
|
|
249
|
+
echo "ACTION: Load pipeline-templates skill to execute this pipeline"
|
|
250
|
+
else
|
|
251
|
+
if [ "$CHANGE_SIZE" -le "$THRESHOLD" ]; then
|
|
252
|
+
echo "REASON: Small change (${CHANGE_SIZE} lines, threshold ${THRESHOLD}), no pipeline needed"
|
|
253
|
+
else
|
|
254
|
+
echo "REASON: File type does not require pipeline review"
|
|
255
|
+
fi
|
|
256
|
+
fi
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
#!/bin/bash
|
|
2
|
+
# inject-protocol.sh - Inject governance protocol at session start
|
|
3
|
+
#
|
|
4
|
+
# Hook configuration: once: true (fires once per session)
|
|
5
|
+
# Exit code 0: stdout added to Claude's CONTEXT (not just verbose mode)
|
|
6
|
+
#
|
|
7
|
+
# Architecture: Reads governance content from skill file (not hardcoded)
|
|
8
|
+
# This keeps governance readable and user-extensible.
|
|
9
|
+
#
|
|
10
|
+
# Usage: Called by SessionStart hook, not directly by users
|
|
11
|
+
|
|
12
|
+
set -euo pipefail
|
|
13
|
+
|
|
14
|
+
# Get directories
|
|
15
|
+
SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)"
|
|
16
|
+
PROJECT_DIR="${CLAUDE_PROJECT_DIR:-.}"
|
|
17
|
+
LOGS_DIR="${PROJECT_DIR}/logs"
|
|
18
|
+
HOOKS_LOG="${LOGS_DIR}/hooks.log"
|
|
19
|
+
|
|
20
|
+
# Skill file location (relative to script in plugin structure)
|
|
21
|
+
# Script is at: scripts/hooks/inject-protocol.sh
|
|
22
|
+
# Skill is at: skills/governance-protocol/SKILL.md
|
|
23
|
+
SKILL_FILE="${SCRIPT_DIR}/../../skills/governance-protocol/SKILL.md"
|
|
24
|
+
|
|
25
|
+
# Ensure logs directory exists
|
|
26
|
+
mkdir -p "$LOGS_DIR"
|
|
27
|
+
|
|
28
|
+
# Log the injection event (for verification)
|
|
29
|
+
TIMESTAMP=$(date -Iseconds)
|
|
30
|
+
echo "[${TIMESTAMP}] SessionStart: Governance protocol injected (once:true)" >> "$HOOKS_LOG"
|
|
31
|
+
|
|
32
|
+
# Output activation header (visible in Claude's context)
|
|
33
|
+
echo "═══════════════════════════════════════════════════════════════"
|
|
34
|
+
echo " BULWARK GOVERNANCE PROTOCOL - ACTIVATED"
|
|
35
|
+
echo " Quality enforcement enabled for this session"
|
|
36
|
+
echo "═══════════════════════════════════════════════════════════════"
|
|
37
|
+
echo ""
|
|
38
|
+
|
|
39
|
+
# Extract and output skill content (after frontmatter)
|
|
40
|
+
# Frontmatter is between first --- and second ---
|
|
41
|
+
if [ -f "$SKILL_FILE" ]; then
|
|
42
|
+
# Use awk with state tracking to skip frontmatter
|
|
43
|
+
# Handle both Unix (LF) and Windows (CRLF) line endings
|
|
44
|
+
awk 'BEGIN{s=0} /^---\r?$/{s++;next} s>=2{gsub(/\r$/,"");print}' "$SKILL_FILE"
|
|
45
|
+
else
|
|
46
|
+
echo "Warning: governance-protocol skill not found at ${SKILL_FILE}" >&2
|
|
47
|
+
echo "## Bulwark Governance Protocol"
|
|
48
|
+
echo ""
|
|
49
|
+
echo "Governance skill not found. Please ensure skills/governance-protocol/SKILL.md exists."
|
|
50
|
+
fi
|
|
51
|
+
|
|
52
|
+
exit 0
|
|
@@ -0,0 +1,175 @@
|
|
|
1
|
+
#!/bin/bash
|
|
2
|
+
# suggest-pipeline.sh
|
|
3
|
+
# PostToolUse hook for Write|Edit - suggests pipeline orchestration after code changes
|
|
4
|
+
#
|
|
5
|
+
# Input (stdin): JSON with tool_name, tool_input, tool_response
|
|
6
|
+
# Output (stdout): JSON with hookSpecificOutput.additionalContext
|
|
7
|
+
#
|
|
8
|
+
# Behavior:
|
|
9
|
+
# - Small changes: Skip silently (no suggestion)
|
|
10
|
+
# - Significant changes: Inject additionalContext instructing Claude to load pipeline-templates
|
|
11
|
+
#
|
|
12
|
+
# Small Change Thresholds:
|
|
13
|
+
# - Code files: < 5 lines
|
|
14
|
+
# - Test files: < 10 lines
|
|
15
|
+
# - Config files: < 3 lines
|
|
16
|
+
# - Documentation: <= 10 lines
|
|
17
|
+
# - Scripts: < 3 lines
|
|
18
|
+
#
|
|
19
|
+
# PRODUCTION MODE:
|
|
20
|
+
# - Hook is always enabled (no flag file check)
|
|
21
|
+
# - Configured via /bulwark-scaffold (--no-hooks to opt out)
|
|
22
|
+
# - Called by enforce-quality.sh after quality checks pass
|
|
23
|
+
|
|
24
|
+
# Ensure logs directory exists
|
|
25
|
+
LOGS_DIR="${CLAUDE_PROJECT_DIR:-$(pwd)}/logs"
|
|
26
|
+
mkdir -p "$LOGS_DIR"
|
|
27
|
+
|
|
28
|
+
# Read input from stdin
|
|
29
|
+
INPUT=$(cat)
|
|
30
|
+
|
|
31
|
+
# Parse tool details
|
|
32
|
+
TOOL_NAME=$(echo "$INPUT" | jq -r '.tool_name // "unknown"')
|
|
33
|
+
FILE_PATH=$(echo "$INPUT" | jq -r '.tool_input.file_path // ""')
|
|
34
|
+
TIMESTAMP=$(date -u +"%Y-%m-%dT%H:%M:%SZ")
|
|
35
|
+
|
|
36
|
+
# Skip infrastructure directories (no quality checks or pipeline suggestions)
|
|
37
|
+
# DEF-005: Prevents infinite loops when writing to logs/
|
|
38
|
+
case "$FILE_PATH" in
|
|
39
|
+
*/logs/*|logs/*|*/tmp/*|tmp/*|*/.claude/*|.claude/*|*/node_modules/*|node_modules/*)
|
|
40
|
+
exit 0
|
|
41
|
+
;;
|
|
42
|
+
esac
|
|
43
|
+
|
|
44
|
+
# Log the invocation
|
|
45
|
+
echo "[$TIMESTAMP] PostToolUse: $TOOL_NAME on $FILE_PATH" >> "$LOGS_DIR/hooks.log"
|
|
46
|
+
|
|
47
|
+
# Extract file extension and name
|
|
48
|
+
FILENAME=$(basename "$FILE_PATH")
|
|
49
|
+
EXTENSION="${FILENAME##*.}"
|
|
50
|
+
EXTENSION_LOWER=$(echo "$EXTENSION" | tr '[:upper:]' '[:lower:]')
|
|
51
|
+
|
|
52
|
+
# Determine file type
|
|
53
|
+
IS_CODE="false"
|
|
54
|
+
IS_TEST="false"
|
|
55
|
+
IS_CONFIG="false"
|
|
56
|
+
IS_DOC="false"
|
|
57
|
+
IS_SCRIPT="false"
|
|
58
|
+
IS_DATA="false"
|
|
59
|
+
|
|
60
|
+
# Code files
|
|
61
|
+
if echo "$EXTENSION_LOWER" | grep -qE '^(ts|js|tsx|jsx|py|go|rs|java|cpp|c|rb|php|swift|kt)$'; then
|
|
62
|
+
IS_CODE="true"
|
|
63
|
+
fi
|
|
64
|
+
|
|
65
|
+
# Test files (check filename pattern)
|
|
66
|
+
if echo "$FILENAME" | grep -qiE '(test|spec|_test)\.(ts|js|tsx|jsx|py|go|rs|java|cpp|rb)$'; then
|
|
67
|
+
IS_TEST="true"
|
|
68
|
+
IS_CODE="false" # Treat as test, not code
|
|
69
|
+
fi
|
|
70
|
+
|
|
71
|
+
# Config files
|
|
72
|
+
if echo "$EXTENSION_LOWER" | grep -qE '^(json|yaml|yml|toml|ini|env|config)$'; then
|
|
73
|
+
IS_CONFIG="true"
|
|
74
|
+
fi
|
|
75
|
+
|
|
76
|
+
# Documentation files
|
|
77
|
+
if echo "$EXTENSION_LOWER" | grep -qE '^(md|txt|rst|adoc)$'; then
|
|
78
|
+
IS_DOC="true"
|
|
79
|
+
fi
|
|
80
|
+
|
|
81
|
+
# Script files
|
|
82
|
+
if echo "$EXTENSION_LOWER" | grep -qE '^(sh|bash|zsh|fish|ps1)$'; then
|
|
83
|
+
IS_SCRIPT="true"
|
|
84
|
+
fi
|
|
85
|
+
|
|
86
|
+
# Data files
|
|
87
|
+
if echo "$EXTENSION_LOWER" | grep -qE '^(xlsx|xls|csv|pdf|docx|pptx)$'; then
|
|
88
|
+
IS_DATA="true"
|
|
89
|
+
fi
|
|
90
|
+
|
|
91
|
+
# Calculate change size
|
|
92
|
+
if [ "$TOOL_NAME" = "Edit" ]; then
|
|
93
|
+
# For Edit, measure the old_string and new_string
|
|
94
|
+
OLD_LINES=$(echo "$INPUT" | jq -r '.tool_input.old_string // ""' | wc -l)
|
|
95
|
+
NEW_LINES=$(echo "$INPUT" | jq -r '.tool_input.new_string // ""' | wc -l)
|
|
96
|
+
CHANGE_SIZE=$((NEW_LINES > OLD_LINES ? NEW_LINES : OLD_LINES))
|
|
97
|
+
else
|
|
98
|
+
# For Write, use content length
|
|
99
|
+
CHANGE_SIZE=$(echo "$INPUT" | jq -r '.tool_input.content // ""' | wc -l)
|
|
100
|
+
fi
|
|
101
|
+
|
|
102
|
+
# Determine threshold based on file type
|
|
103
|
+
THRESHOLD=5 # Default for code
|
|
104
|
+
if [ "$IS_TEST" = "true" ]; then
|
|
105
|
+
THRESHOLD=10
|
|
106
|
+
elif [ "$IS_CONFIG" = "true" ]; then
|
|
107
|
+
THRESHOLD=3
|
|
108
|
+
elif [ "$IS_DOC" = "true" ]; then
|
|
109
|
+
THRESHOLD=10
|
|
110
|
+
elif [ "$IS_SCRIPT" = "true" ]; then
|
|
111
|
+
THRESHOLD=3
|
|
112
|
+
elif [ "$IS_DATA" = "true" ]; then
|
|
113
|
+
THRESHOLD=1 # Any data file change is significant
|
|
114
|
+
fi
|
|
115
|
+
|
|
116
|
+
# Log decision factors
|
|
117
|
+
echo "[$TIMESTAMP] File type: code=$IS_CODE test=$IS_TEST config=$IS_CONFIG doc=$IS_DOC script=$IS_SCRIPT data=$IS_DATA" >> "$LOGS_DIR/hooks.log"
|
|
118
|
+
echo "[$TIMESTAMP] Change size: $CHANGE_SIZE lines, threshold: $THRESHOLD" >> "$LOGS_DIR/hooks.log"
|
|
119
|
+
|
|
120
|
+
# Skip small changes
|
|
121
|
+
if [ "$CHANGE_SIZE" -le "$THRESHOLD" ]; then
|
|
122
|
+
echo "[$TIMESTAMP] Pipeline: SKIP (small change: $CHANGE_SIZE <= $THRESHOLD)" >> "$LOGS_DIR/hooks.log"
|
|
123
|
+
exit 0
|
|
124
|
+
fi
|
|
125
|
+
|
|
126
|
+
# Determine recommended pipeline based on file type AND work type
|
|
127
|
+
# DEF-004: Write (new file) vs Edit (existing file) affects pipeline selection
|
|
128
|
+
RECOMMENDED_PIPELINE="Code Review"
|
|
129
|
+
if [ "$IS_CODE" = "true" ]; then
|
|
130
|
+
if [ "$TOOL_NAME" = "Write" ]; then
|
|
131
|
+
# New code file → New Feature Pipeline (includes test generation)
|
|
132
|
+
RECOMMENDED_PIPELINE="New Feature"
|
|
133
|
+
else
|
|
134
|
+
# Editing existing code → Code Review Pipeline
|
|
135
|
+
RECOMMENDED_PIPELINE="Code Review"
|
|
136
|
+
fi
|
|
137
|
+
elif [ "$IS_TEST" = "true" ]; then
|
|
138
|
+
RECOMMENDED_PIPELINE="Test Audit"
|
|
139
|
+
elif [ "$IS_CONFIG" = "true" ]; then
|
|
140
|
+
RECOMMENDED_PIPELINE="Code Review (security focus)"
|
|
141
|
+
elif [ "$IS_SCRIPT" = "true" ]; then
|
|
142
|
+
if [ "$TOOL_NAME" = "Write" ]; then
|
|
143
|
+
RECOMMENDED_PIPELINE="New Feature (security focus)"
|
|
144
|
+
else
|
|
145
|
+
RECOMMENDED_PIPELINE="Code Review (security focus)"
|
|
146
|
+
fi
|
|
147
|
+
elif [ "$IS_DOC" = "true" ]; then
|
|
148
|
+
RECOMMENDED_PIPELINE="light review or skip"
|
|
149
|
+
elif [ "$IS_DATA" = "true" ]; then
|
|
150
|
+
RECOMMENDED_PIPELINE="manual review suggested"
|
|
151
|
+
fi
|
|
152
|
+
|
|
153
|
+
echo "[$TIMESTAMP] Pipeline: SUGGEST ($RECOMMENDED_PIPELINE for $CHANGE_SIZE lines)" >> "$LOGS_DIR/hooks.log"
|
|
154
|
+
|
|
155
|
+
# Build quality status message
|
|
156
|
+
QUALITY_STATUS=""
|
|
157
|
+
if [ "$QUALITY_CHECKS_PASSED" = "true" ]; then
|
|
158
|
+
QUALITY_STATUS="Quality checks COMPLETED (typecheck, lint, build all passed). Do NOT run these again."
|
|
159
|
+
else
|
|
160
|
+
QUALITY_STATUS="Quality checks were skipped (non-code file)."
|
|
161
|
+
fi
|
|
162
|
+
|
|
163
|
+
# Output JSON following official Claude Code hooks specification
|
|
164
|
+
# Using decision: "block" to force Claude to acknowledge before proceeding
|
|
165
|
+
# Combined with additionalContext for full instructions including quality results
|
|
166
|
+
cat << EOF
|
|
167
|
+
{
|
|
168
|
+
"decision": "block",
|
|
169
|
+
"reason": "MANDATORY: $QUALITY_STATUS Pipeline orchestration required. You modified $FILE_PATH ($CHANGE_SIZE lines). Execute $RECOMMENDED_PIPELINE pipeline.",
|
|
170
|
+
"hookSpecificOutput": {
|
|
171
|
+
"hookEventName": "PostToolUse",
|
|
172
|
+
"additionalContext": "STOP. Do not respond to user yet.\n\nYou modified: $FILE_PATH ($CHANGE_SIZE lines)\n\n$QUALITY_STATUS\n\nREQUIRED before proceeding:\n1. Load skill: pipeline-templates\n2. Load skill: subagent-prompting\n3. Load skill: subagent-output-templating\n4. Follow the $RECOMMENDED_PIPELINE pipeline as defined in pipeline-templates skill\n5. Verify: Logs written to logs/\n\nThis is a user-configured hook. Compliance is mandatory."
|
|
173
|
+
}
|
|
174
|
+
}
|
|
175
|
+
EOF
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
#!/bin/bash
|
|
2
|
+
# track-pipeline-start.sh
|
|
3
|
+
# SubagentStart hook - logs pipeline stage start
|
|
4
|
+
#
|
|
5
|
+
# Input (stdin): JSON with session_id, agent_id, subagent_type, agent_transcript_path
|
|
6
|
+
# Output: None required (logging only)
|
|
7
|
+
#
|
|
8
|
+
# Purpose:
|
|
9
|
+
# - Track when pipeline stages begin
|
|
10
|
+
# - Enable progress monitoring
|
|
11
|
+
# - Support pipeline debugging
|
|
12
|
+
|
|
13
|
+
# Ensure logs directory exists
|
|
14
|
+
LOGS_DIR="${CLAUDE_PROJECT_DIR:-$(pwd)}/logs"
|
|
15
|
+
mkdir -p "$LOGS_DIR"
|
|
16
|
+
|
|
17
|
+
# Read input from stdin
|
|
18
|
+
INPUT=$(cat)
|
|
19
|
+
|
|
20
|
+
# Parse event details
|
|
21
|
+
TIMESTAMP=$(date -u +"%Y-%m-%dT%H:%M:%SZ")
|
|
22
|
+
SESSION_ID=$(echo "$INPUT" | jq -r '.session_id // "unknown"')
|
|
23
|
+
AGENT_ID=$(echo "$INPUT" | jq -r '.agent_id // "unknown"')
|
|
24
|
+
SUBAGENT_TYPE=$(echo "$INPUT" | jq -r '.subagent_type // "unknown"')
|
|
25
|
+
TRANSCRIPT_PATH=$(echo "$INPUT" | jq -r '.agent_transcript_path // "none"')
|
|
26
|
+
|
|
27
|
+
# Log to pipeline tracking file
|
|
28
|
+
cat >> "$LOGS_DIR/pipeline-tracking.log" << EOF
|
|
29
|
+
[$TIMESTAMP] SubagentStart
|
|
30
|
+
session: $SESSION_ID
|
|
31
|
+
agent_id: $AGENT_ID
|
|
32
|
+
type: $SUBAGENT_TYPE
|
|
33
|
+
transcript: $TRANSCRIPT_PATH
|
|
34
|
+
EOF
|
|
35
|
+
|
|
36
|
+
# Also log to general hooks log
|
|
37
|
+
echo "[$TIMESTAMP] SubagentStart: $AGENT_ID ($SUBAGENT_TYPE)" >> "$LOGS_DIR/hooks.log"
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
#!/bin/bash
|
|
2
|
+
# track-pipeline-stop.sh
|
|
3
|
+
# SubagentStop hook - logs pipeline stage completion
|
|
4
|
+
#
|
|
5
|
+
# Input (stdin): JSON with session_id, agent_id, subagent_type, agent_transcript_path
|
|
6
|
+
# Output: None required (logging only)
|
|
7
|
+
#
|
|
8
|
+
# Purpose:
|
|
9
|
+
# - Track when pipeline stages complete
|
|
10
|
+
# - Calculate stage duration (when paired with start)
|
|
11
|
+
# - Support pipeline debugging and verification
|
|
12
|
+
|
|
13
|
+
# Ensure logs directory exists
|
|
14
|
+
LOGS_DIR="${CLAUDE_PROJECT_DIR:-$(pwd)}/logs"
|
|
15
|
+
mkdir -p "$LOGS_DIR"
|
|
16
|
+
|
|
17
|
+
# Read input from stdin
|
|
18
|
+
INPUT=$(cat)
|
|
19
|
+
|
|
20
|
+
# Parse event details
|
|
21
|
+
TIMESTAMP=$(date -u +"%Y-%m-%dT%H:%M:%SZ")
|
|
22
|
+
SESSION_ID=$(echo "$INPUT" | jq -r '.session_id // "unknown"')
|
|
23
|
+
AGENT_ID=$(echo "$INPUT" | jq -r '.agent_id // "unknown"')
|
|
24
|
+
SUBAGENT_TYPE=$(echo "$INPUT" | jq -r '.subagent_type // "unknown"')
|
|
25
|
+
TRANSCRIPT_PATH=$(echo "$INPUT" | jq -r '.agent_transcript_path // "none"')
|
|
26
|
+
|
|
27
|
+
# Log to pipeline tracking file
|
|
28
|
+
cat >> "$LOGS_DIR/pipeline-tracking.log" << EOF
|
|
29
|
+
[$TIMESTAMP] SubagentStop
|
|
30
|
+
session: $SESSION_ID
|
|
31
|
+
agent_id: $AGENT_ID
|
|
32
|
+
type: $SUBAGENT_TYPE
|
|
33
|
+
transcript: $TRANSCRIPT_PATH
|
|
34
|
+
EOF
|
|
35
|
+
|
|
36
|
+
# Also log to general hooks log
|
|
37
|
+
echo "[$TIMESTAMP] SubagentStop: $AGENT_ID ($SUBAGENT_TYPE)" >> "$LOGS_DIR/hooks.log"
|
|
38
|
+
|
|
39
|
+
# Verify sub-agent wrote expected log output
|
|
40
|
+
# Custom agents (bulwark-implementer, bulwark-issue-analyzer, etc.) always include
|
|
41
|
+
# their name in log filenames per SA2. Skip for general-purpose agents which are
|
|
42
|
+
# ad-hoc and may not follow the naming convention.
|
|
43
|
+
if [ "$SUBAGENT_TYPE" != "unknown" ] && [ "$SUBAGENT_TYPE" != "general-purpose" ]; then
|
|
44
|
+
# Search for files containing agent type name modified in last 60 seconds
|
|
45
|
+
RECENT_LOG=$(find "$LOGS_DIR" -maxdepth 2 -name "*${SUBAGENT_TYPE}*" -mmin -1 2>/dev/null | head -1)
|
|
46
|
+
if [ -n "$RECENT_LOG" ]; then
|
|
47
|
+
echo "[$TIMESTAMP] SubagentStop: Log verified at $RECENT_LOG" >> "$LOGS_DIR/hooks.log"
|
|
48
|
+
else
|
|
49
|
+
echo "[$TIMESTAMP] SubagentStop: WARNING - No log output found for $SUBAGENT_TYPE" >> "$LOGS_DIR/hooks.log"
|
|
50
|
+
echo "WARNING: Sub-agent $SUBAGENT_TYPE ($AGENT_ID) completed without writing expected log to logs/" >&2
|
|
51
|
+
fi
|
|
52
|
+
fi
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
#!/bin/bash
|
|
2
|
+
# Usage: init-rules.sh <target-dir>
|
|
3
|
+
# Copies universal rules.md to <target-dir>/.claude/rules/rules.md
|
|
4
|
+
# If rules.md already exists at target, creates .bak backup.
|
|
5
|
+
# Source: lib/templates/rules.md (portable copy, NOT project root Rules.md)
|
|
6
|
+
|
|
7
|
+
set -euo pipefail
|
|
8
|
+
|
|
9
|
+
TARGET="${1:?Usage: init-rules.sh <target-dir>}"
|
|
10
|
+
SOURCE_DIR="$(cd "$(dirname "$0")/.." && pwd)"
|
|
11
|
+
SOURCE_FILE="$SOURCE_DIR/lib/templates/rules.md"
|
|
12
|
+
|
|
13
|
+
if [ ! -f "$SOURCE_FILE" ]; then
|
|
14
|
+
echo "ERROR: Source template not found at $SOURCE_FILE"
|
|
15
|
+
exit 1
|
|
16
|
+
fi
|
|
17
|
+
|
|
18
|
+
if [ ! -d "$TARGET" ]; then
|
|
19
|
+
echo "ERROR: Target directory does not exist: $TARGET"
|
|
20
|
+
exit 1
|
|
21
|
+
fi
|
|
22
|
+
|
|
23
|
+
RULES_DIR="$TARGET/.claude/rules"
|
|
24
|
+
RULES_FILE="$RULES_DIR/rules.md"
|
|
25
|
+
|
|
26
|
+
mkdir -p "$RULES_DIR"
|
|
27
|
+
|
|
28
|
+
if [ -f "$RULES_FILE" ]; then
|
|
29
|
+
BACKUP="$RULES_FILE.bak"
|
|
30
|
+
cp "$RULES_FILE" "$BACKUP"
|
|
31
|
+
echo " Backed up existing rules.md to $BACKUP"
|
|
32
|
+
fi
|
|
33
|
+
|
|
34
|
+
cp "$SOURCE_FILE" "$RULES_FILE"
|
|
35
|
+
echo " rules.md installed at $RULES_FILE"
|