@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.
Files changed (175) hide show
  1. package/.claude-plugin/plugin.json +43 -0
  2. package/agents/bulwark-fix-validator.md +633 -0
  3. package/agents/bulwark-implementer.md +391 -0
  4. package/agents/bulwark-issue-analyzer.md +308 -0
  5. package/agents/bulwark-standards-reviewer.md +221 -0
  6. package/agents/plan-creation-architect.md +323 -0
  7. package/agents/plan-creation-eng-lead.md +352 -0
  8. package/agents/plan-creation-po.md +300 -0
  9. package/agents/plan-creation-qa-critic.md +334 -0
  10. package/agents/product-ideation-competitive-analyzer.md +298 -0
  11. package/agents/product-ideation-idea-validator.md +268 -0
  12. package/agents/product-ideation-market-researcher.md +292 -0
  13. package/agents/product-ideation-pattern-documenter.md +308 -0
  14. package/agents/product-ideation-segment-analyzer.md +303 -0
  15. package/agents/product-ideation-strategist.md +259 -0
  16. package/agents/statusline-setup.md +97 -0
  17. package/hooks/hooks.json +59 -0
  18. package/package.json +45 -0
  19. package/scripts/hooks/cleanup-stale.sh +13 -0
  20. package/scripts/hooks/enforce-quality.sh +166 -0
  21. package/scripts/hooks/implementer-quality.sh +256 -0
  22. package/scripts/hooks/inject-protocol.sh +52 -0
  23. package/scripts/hooks/suggest-pipeline.sh +175 -0
  24. package/scripts/hooks/track-pipeline-start.sh +37 -0
  25. package/scripts/hooks/track-pipeline-stop.sh +52 -0
  26. package/scripts/init-rules.sh +35 -0
  27. package/scripts/init.sh +151 -0
  28. package/skills/anthropic-validator/SKILL.md +607 -0
  29. package/skills/anthropic-validator/references/agents-checklist.md +131 -0
  30. package/skills/anthropic-validator/references/commands-checklist.md +102 -0
  31. package/skills/anthropic-validator/references/hooks-checklist.md +151 -0
  32. package/skills/anthropic-validator/references/mcp-checklist.md +136 -0
  33. package/skills/anthropic-validator/references/plugins-checklist.md +148 -0
  34. package/skills/anthropic-validator/references/skills-checklist.md +85 -0
  35. package/skills/assertion-patterns/SKILL.md +296 -0
  36. package/skills/bug-magnet-data/SKILL.md +284 -0
  37. package/skills/bug-magnet-data/context/cli-args.md +91 -0
  38. package/skills/bug-magnet-data/context/db-query.md +104 -0
  39. package/skills/bug-magnet-data/context/file-contents.md +103 -0
  40. package/skills/bug-magnet-data/context/http-body.md +91 -0
  41. package/skills/bug-magnet-data/context/process-spawn.md +123 -0
  42. package/skills/bug-magnet-data/data/booleans/boundaries.yaml +143 -0
  43. package/skills/bug-magnet-data/data/collections/arrays.yaml +114 -0
  44. package/skills/bug-magnet-data/data/collections/objects.yaml +123 -0
  45. package/skills/bug-magnet-data/data/concurrency/race-conditions.yaml +118 -0
  46. package/skills/bug-magnet-data/data/concurrency/state-machines.yaml +115 -0
  47. package/skills/bug-magnet-data/data/dates/boundaries.yaml +137 -0
  48. package/skills/bug-magnet-data/data/dates/invalid.yaml +132 -0
  49. package/skills/bug-magnet-data/data/dates/timezone.yaml +118 -0
  50. package/skills/bug-magnet-data/data/encoding/charset.yaml +79 -0
  51. package/skills/bug-magnet-data/data/encoding/normalization.yaml +105 -0
  52. package/skills/bug-magnet-data/data/formats/email.yaml +154 -0
  53. package/skills/bug-magnet-data/data/formats/json.yaml +187 -0
  54. package/skills/bug-magnet-data/data/formats/url.yaml +165 -0
  55. package/skills/bug-magnet-data/data/language-specific/javascript.yaml +182 -0
  56. package/skills/bug-magnet-data/data/language-specific/python.yaml +174 -0
  57. package/skills/bug-magnet-data/data/language-specific/rust.yaml +148 -0
  58. package/skills/bug-magnet-data/data/numbers/boundaries.yaml +161 -0
  59. package/skills/bug-magnet-data/data/numbers/precision.yaml +89 -0
  60. package/skills/bug-magnet-data/data/numbers/special.yaml +69 -0
  61. package/skills/bug-magnet-data/data/strings/boundaries.yaml +109 -0
  62. package/skills/bug-magnet-data/data/strings/injection.yaml +208 -0
  63. package/skills/bug-magnet-data/data/strings/special-chars.yaml +190 -0
  64. package/skills/bug-magnet-data/data/strings/unicode.yaml +139 -0
  65. package/skills/bug-magnet-data/references/external-lists.md +115 -0
  66. package/skills/bulwark-brainstorm/SKILL.md +563 -0
  67. package/skills/bulwark-brainstorm/references/at-teammate-prompts.md +60 -0
  68. package/skills/bulwark-brainstorm/references/role-critical-analyst.md +78 -0
  69. package/skills/bulwark-brainstorm/references/role-development-lead.md +66 -0
  70. package/skills/bulwark-brainstorm/references/role-product-delivery-lead.md +79 -0
  71. package/skills/bulwark-brainstorm/references/role-product-manager.md +62 -0
  72. package/skills/bulwark-brainstorm/references/role-project-sme.md +59 -0
  73. package/skills/bulwark-brainstorm/references/role-technical-architect.md +66 -0
  74. package/skills/bulwark-research/SKILL.md +298 -0
  75. package/skills/bulwark-research/references/viewpoint-contrarian.md +63 -0
  76. package/skills/bulwark-research/references/viewpoint-direct-investigation.md +62 -0
  77. package/skills/bulwark-research/references/viewpoint-first-principles.md +65 -0
  78. package/skills/bulwark-research/references/viewpoint-practitioner.md +62 -0
  79. package/skills/bulwark-research/references/viewpoint-prior-art.md +66 -0
  80. package/skills/bulwark-scaffold/SKILL.md +330 -0
  81. package/skills/bulwark-statusline/SKILL.md +161 -0
  82. package/skills/bulwark-statusline/scripts/statusline.sh +144 -0
  83. package/skills/bulwark-verify/SKILL.md +519 -0
  84. package/skills/code-review/SKILL.md +428 -0
  85. package/skills/code-review/examples/anti-patterns/linting.ts +181 -0
  86. package/skills/code-review/examples/anti-patterns/security.ts +91 -0
  87. package/skills/code-review/examples/anti-patterns/standards.ts +195 -0
  88. package/skills/code-review/examples/anti-patterns/type-safety.ts +108 -0
  89. package/skills/code-review/examples/recommended/linting.ts +195 -0
  90. package/skills/code-review/examples/recommended/security.ts +154 -0
  91. package/skills/code-review/examples/recommended/standards.ts +231 -0
  92. package/skills/code-review/examples/recommended/type-safety.ts +181 -0
  93. package/skills/code-review/frameworks/angular.md +218 -0
  94. package/skills/code-review/frameworks/django.md +235 -0
  95. package/skills/code-review/frameworks/express.md +207 -0
  96. package/skills/code-review/frameworks/flask.md +298 -0
  97. package/skills/code-review/frameworks/generic.md +146 -0
  98. package/skills/code-review/frameworks/react.md +152 -0
  99. package/skills/code-review/frameworks/vue.md +244 -0
  100. package/skills/code-review/references/linting-patterns.md +221 -0
  101. package/skills/code-review/references/security-patterns.md +125 -0
  102. package/skills/code-review/references/standards-patterns.md +246 -0
  103. package/skills/code-review/references/type-safety-patterns.md +130 -0
  104. package/skills/component-patterns/SKILL.md +131 -0
  105. package/skills/component-patterns/references/pattern-cli-command.md +118 -0
  106. package/skills/component-patterns/references/pattern-database.md +166 -0
  107. package/skills/component-patterns/references/pattern-external-api.md +139 -0
  108. package/skills/component-patterns/references/pattern-file-parser.md +168 -0
  109. package/skills/component-patterns/references/pattern-http-server.md +162 -0
  110. package/skills/component-patterns/references/pattern-process-spawner.md +133 -0
  111. package/skills/continuous-feedback/SKILL.md +327 -0
  112. package/skills/continuous-feedback/references/collect-instructions.md +81 -0
  113. package/skills/continuous-feedback/references/specialize-code-review.md +82 -0
  114. package/skills/continuous-feedback/references/specialize-general.md +98 -0
  115. package/skills/continuous-feedback/references/specialize-test-audit.md +81 -0
  116. package/skills/create-skill/SKILL.md +359 -0
  117. package/skills/create-skill/references/agent-conventions.md +194 -0
  118. package/skills/create-skill/references/agent-template.md +195 -0
  119. package/skills/create-skill/references/content-guidance.md +291 -0
  120. package/skills/create-skill/references/decision-framework.md +124 -0
  121. package/skills/create-skill/references/template-pipeline.md +217 -0
  122. package/skills/create-skill/references/template-reference-heavy.md +111 -0
  123. package/skills/create-skill/references/template-research.md +210 -0
  124. package/skills/create-skill/references/template-script-driven.md +172 -0
  125. package/skills/create-skill/references/template-simple.md +80 -0
  126. package/skills/create-subagent/SKILL.md +353 -0
  127. package/skills/create-subagent/references/agent-conventions.md +268 -0
  128. package/skills/create-subagent/references/content-guidance.md +232 -0
  129. package/skills/create-subagent/references/decision-framework.md +134 -0
  130. package/skills/create-subagent/references/template-single-agent.md +192 -0
  131. package/skills/fix-bug/SKILL.md +241 -0
  132. package/skills/governance-protocol/SKILL.md +116 -0
  133. package/skills/init/SKILL.md +341 -0
  134. package/skills/issue-debugging/SKILL.md +385 -0
  135. package/skills/issue-debugging/references/anti-patterns.md +245 -0
  136. package/skills/issue-debugging/references/debug-report-schema.md +227 -0
  137. package/skills/mock-detection/SKILL.md +511 -0
  138. package/skills/mock-detection/references/false-positive-prevention.md +402 -0
  139. package/skills/mock-detection/references/stub-patterns.md +236 -0
  140. package/skills/pipeline-templates/SKILL.md +215 -0
  141. package/skills/pipeline-templates/references/code-change-workflow.md +277 -0
  142. package/skills/pipeline-templates/references/code-review.md +336 -0
  143. package/skills/pipeline-templates/references/fix-validation.md +421 -0
  144. package/skills/pipeline-templates/references/new-feature.md +335 -0
  145. package/skills/pipeline-templates/references/research-brainstorm.md +161 -0
  146. package/skills/pipeline-templates/references/research-planning.md +257 -0
  147. package/skills/pipeline-templates/references/test-audit.md +389 -0
  148. package/skills/pipeline-templates/references/test-execution-fix.md +238 -0
  149. package/skills/plan-creation/SKILL.md +497 -0
  150. package/skills/product-ideation/SKILL.md +372 -0
  151. package/skills/product-ideation/references/analysis-frameworks.md +161 -0
  152. package/skills/session-handoff/SKILL.md +139 -0
  153. package/skills/session-handoff/references/examples.md +223 -0
  154. package/skills/setup-lsp/SKILL.md +312 -0
  155. package/skills/setup-lsp/references/server-registry.md +85 -0
  156. package/skills/setup-lsp/references/troubleshooting.md +135 -0
  157. package/skills/subagent-output-templating/SKILL.md +415 -0
  158. package/skills/subagent-output-templating/references/examples.md +440 -0
  159. package/skills/subagent-prompting/SKILL.md +364 -0
  160. package/skills/subagent-prompting/references/examples.md +342 -0
  161. package/skills/test-audit/SKILL.md +531 -0
  162. package/skills/test-audit/references/known-limitations.md +41 -0
  163. package/skills/test-audit/references/priority-classification.md +30 -0
  164. package/skills/test-audit/references/prompts/deep-mode-detection.md +83 -0
  165. package/skills/test-audit/references/prompts/synthesis.md +57 -0
  166. package/skills/test-audit/references/rewrite-instructions.md +46 -0
  167. package/skills/test-audit/references/schemas/audit-output.yaml +100 -0
  168. package/skills/test-audit/references/schemas/diagnostic-output.yaml +49 -0
  169. package/skills/test-audit/scripts/data-flow-analyzer.ts +509 -0
  170. package/skills/test-audit/scripts/integration-mock-detector.ts +462 -0
  171. package/skills/test-audit/scripts/package.json +20 -0
  172. package/skills/test-audit/scripts/skip-detector.ts +211 -0
  173. package/skills/test-audit/scripts/verification-counter.ts +295 -0
  174. package/skills/test-classification/SKILL.md +310 -0
  175. 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"