@paulduvall/claude-dev-toolkit 0.0.1-alpha.2 → 0.0.1-alpha.21
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -0
- package/README.md +88 -37
- package/bin/claude-commands +307 -65
- package/commands/active/xarchitecture.md +393 -0
- package/commands/active/xconfig.md +127 -0
- package/commands/active/xcontinue.md +92 -0
- package/commands/active/xdebug.md +130 -0
- package/commands/active/xdocs.md +178 -0
- package/commands/active/xexplore.md +94 -0
- package/commands/active/xgit.md +149 -0
- package/commands/active/xpipeline.md +152 -0
- package/commands/active/xquality.md +96 -0
- package/commands/active/xrefactor.md +198 -0
- package/commands/active/xrelease.md +142 -0
- package/commands/active/xsecurity.md +92 -0
- package/commands/active/xspec.md +174 -0
- package/commands/active/xtdd.md +151 -0
- package/commands/active/xtest.md +89 -0
- package/commands/active/xverify.md +80 -0
- package/commands/experiments/xact.md +742 -0
- package/commands/experiments/xanalytics.md +113 -0
- package/commands/experiments/xanalyze.md +70 -0
- package/commands/experiments/xapi.md +161 -0
- package/commands/experiments/xatomic.md +112 -0
- package/commands/experiments/xaws.md +85 -0
- package/commands/experiments/xcicd.md +337 -0
- package/commands/experiments/xcommit.md +122 -0
- package/commands/experiments/xcompliance.md +182 -0
- package/commands/experiments/xconstraints.md +89 -0
- package/commands/experiments/xcoverage.md +90 -0
- package/commands/experiments/xdb.md +102 -0
- package/commands/experiments/xdesign.md +121 -0
- package/commands/experiments/xdevcontainer.md +238 -0
- package/commands/experiments/xevaluate.md +111 -0
- package/commands/experiments/xfootnote.md +12 -0
- package/commands/experiments/xgenerate.md +117 -0
- package/commands/experiments/xgovernance.md +149 -0
- package/commands/experiments/xgreen.md +66 -0
- package/commands/experiments/xiac.md +118 -0
- package/commands/experiments/xincident.md +137 -0
- package/commands/experiments/xinfra.md +115 -0
- package/commands/experiments/xknowledge.md +115 -0
- package/commands/experiments/xmaturity.md +120 -0
- package/commands/experiments/xmetrics.md +118 -0
- package/commands/experiments/xmonitoring.md +128 -0
- package/commands/experiments/xnew.md +903 -0
- package/commands/experiments/xobservable.md +114 -0
- package/commands/experiments/xoidc.md +165 -0
- package/commands/experiments/xoptimize.md +115 -0
- package/commands/experiments/xperformance.md +112 -0
- package/commands/experiments/xplanning.md +131 -0
- package/commands/experiments/xpolicy.md +115 -0
- package/commands/experiments/xproduct.md +98 -0
- package/commands/experiments/xreadiness.md +75 -0
- package/commands/experiments/xred.md +55 -0
- package/commands/experiments/xrisk.md +128 -0
- package/commands/experiments/xrules.md +124 -0
- package/commands/experiments/xsandbox.md +120 -0
- package/commands/experiments/xscan.md +102 -0
- package/commands/experiments/xsetup.md +123 -0
- package/commands/experiments/xtemplate.md +116 -0
- package/commands/experiments/xtrace.md +212 -0
- package/commands/experiments/xux.md +171 -0
- package/commands/experiments/xvalidate.md +104 -0
- package/commands/experiments/xworkflow.md +113 -0
- package/hooks/.smellrc.example.json +19 -0
- package/hooks/README.md +263 -0
- package/hooks/check-commit-signing.py +127 -0
- package/hooks/check-complexity.py +38 -0
- package/hooks/check-security.py +37 -0
- package/hooks/claude-wrapper.sh +29 -0
- package/hooks/config.py +110 -0
- package/hooks/file-logger.sh +100 -0
- package/hooks/lib/argument-parser.sh +427 -0
- package/hooks/lib/config-constants.sh +230 -0
- package/hooks/lib/context-manager.sh +560 -0
- package/hooks/lib/error-handler.sh +423 -0
- package/hooks/lib/execution-engine.sh +444 -0
- package/hooks/lib/execution-results.sh +113 -0
- package/hooks/lib/execution-simulation.sh +114 -0
- package/hooks/lib/field-validators.sh +104 -0
- package/hooks/lib/file-utils.sh +398 -0
- package/hooks/lib/subagent-discovery.sh +468 -0
- package/hooks/lib/subagent-validator.sh +407 -0
- package/hooks/lib/validation-reporter.sh +134 -0
- package/hooks/on-error-debug.sh +226 -0
- package/hooks/pre-commit-quality.sh +204 -0
- package/hooks/pre-commit-test-runner.sh +132 -0
- package/hooks/pre-write-security.sh +115 -0
- package/hooks/prevent-credential-exposure.sh +279 -0
- package/hooks/security_bandit.py +177 -0
- package/hooks/security_checks.py +97 -0
- package/hooks/security_secrets.py +81 -0
- package/hooks/security_trojan.py +61 -0
- package/hooks/settings.example.json +52 -0
- package/hooks/smell_checks.py +238 -0
- package/hooks/smell_javascript.py +231 -0
- package/hooks/smell_python.py +110 -0
- package/hooks/smell_ruff.py +70 -0
- package/hooks/smell_types.py +72 -0
- package/hooks/subagent-trigger-simple.sh +202 -0
- package/hooks/subagent-trigger.sh +253 -0
- package/hooks/suppression.py +82 -0
- package/hooks/tab-color.sh +70 -0
- package/hooks/verify-before-edit.sh +135 -0
- package/lib/backup-restore-command.js +140 -0
- package/lib/base/base-command.js +252 -0
- package/lib/base/command-result.js +184 -0
- package/lib/config/constants.js +255 -0
- package/lib/config.js +48 -6
- package/lib/configure-command.js +428 -0
- package/lib/dependency-validator.js +64 -5
- package/lib/hook-installer-core.js +2 -2
- package/lib/installation-instruction-generator.js +213 -495
- package/lib/installer.js +134 -56
- package/lib/oidc-command.js +740 -0
- package/lib/services/backup-list-service.js +226 -0
- package/lib/services/backup-service.js +230 -0
- package/lib/services/command-installer-service.js +217 -0
- package/lib/services/logger-service.js +201 -0
- package/lib/services/package-manager-service.js +319 -0
- package/lib/services/platform-instruction-service.js +294 -0
- package/lib/services/recovery-instruction-service.js +348 -0
- package/lib/services/restore-service.js +221 -0
- package/lib/setup-command.js +359 -0
- package/lib/setup-wizard.js +155 -262
- package/lib/uninstall-command.js +100 -0
- package/lib/utils/claude-path-config.js +184 -0
- package/lib/utils/file-system-utils.js +152 -0
- package/lib/utils.js +8 -4
- package/lib/verify-command.js +430 -0
- package/package.json +7 -3
- package/scripts/postinstall.js +172 -157
- package/subagents/debug-specialist.md +7 -0
- package/templates/README.md +115 -0
- package/templates/basic-settings.json +30 -0
- package/templates/comprehensive-settings.json +57 -0
- package/templates/global-claude.md +344 -0
- package/templates/hybrid-hook-config.yaml +132 -0
- package/templates/security-focused-settings.json +62 -0
- package/templates/subagent-hooks.yaml +188 -0
- package/lib/package-manager-service.js +0 -270
- package/subagents/debug-context.md +0 -197
|
@@ -0,0 +1,226 @@
|
|
|
1
|
+
#!/usr/bin/env bash
|
|
2
|
+
set -euo pipefail
|
|
3
|
+
|
|
4
|
+
# Claude Code Hook: Error Handling Trigger
|
|
5
|
+
#
|
|
6
|
+
# Purpose: Lightweight trigger for automatic debugging assistance on errors
|
|
7
|
+
# Trigger: Manual invocation or PostToolUse (no OnError hook event exists in Claude Code)
|
|
8
|
+
# Approach: Capture error context and delegate to debug-specialist subagent
|
|
9
|
+
#
|
|
10
|
+
# This hook provides immediate debugging help by gathering error context
|
|
11
|
+
# and connecting users with the debug-specialist subagent.
|
|
12
|
+
|
|
13
|
+
##################################
|
|
14
|
+
# Load Shared Libraries
|
|
15
|
+
##################################
|
|
16
|
+
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
|
17
|
+
LIB_DIR="$SCRIPT_DIR/lib"
|
|
18
|
+
|
|
19
|
+
# Load essential modules for error context gathering
|
|
20
|
+
source "$LIB_DIR/config-constants.sh"
|
|
21
|
+
source "$LIB_DIR/context-manager.sh"
|
|
22
|
+
source "$LIB_DIR/error-handler.sh"
|
|
23
|
+
source "$LIB_DIR/file-utils.sh"
|
|
24
|
+
|
|
25
|
+
##################################
|
|
26
|
+
# Error Context Gathering
|
|
27
|
+
##################################
|
|
28
|
+
gather_error_context() {
|
|
29
|
+
local error_type="${1:-unknown}"
|
|
30
|
+
local error_message="${2:-No error message provided}"
|
|
31
|
+
local failed_command="${3:-unknown}"
|
|
32
|
+
|
|
33
|
+
log_info "Gathering error context for debugging assistance"
|
|
34
|
+
|
|
35
|
+
# Capture comprehensive error context
|
|
36
|
+
local safe_type safe_msg safe_cmd safe_user safe_wd safe_branch
|
|
37
|
+
safe_type=$(json_escape "$error_type")
|
|
38
|
+
safe_msg=$(json_escape "$error_message")
|
|
39
|
+
safe_cmd=$(json_escape "$failed_command")
|
|
40
|
+
safe_user=$(json_escape "$USER")
|
|
41
|
+
safe_wd=$(json_escape "$(pwd)")
|
|
42
|
+
safe_branch=$(json_escape "$(git branch --show-current 2>/dev/null || echo 'not-in-git')")
|
|
43
|
+
|
|
44
|
+
local context_data
|
|
45
|
+
context_data=$(cat <<EOF
|
|
46
|
+
{
|
|
47
|
+
"trigger": "on_error_debug",
|
|
48
|
+
"error_info": {
|
|
49
|
+
"type": "$safe_type",
|
|
50
|
+
"message": "$safe_msg",
|
|
51
|
+
"failed_command": "$safe_cmd",
|
|
52
|
+
"timestamp": "$(date -u +"%Y-%m-%dT%H:%M:%SZ")"
|
|
53
|
+
},
|
|
54
|
+
"environment": {
|
|
55
|
+
"tool": "${CLAUDE_TOOL:-unknown}",
|
|
56
|
+
"file": "${CLAUDE_FILE:-none}",
|
|
57
|
+
"working_directory": "$safe_wd",
|
|
58
|
+
"user": "$safe_user",
|
|
59
|
+
"shell": "${SHELL##*/}",
|
|
60
|
+
"session_id": "${CLAUDE_SESSION_ID:-$$}"
|
|
61
|
+
},
|
|
62
|
+
"project_context": {
|
|
63
|
+
"git_branch": "$safe_branch",
|
|
64
|
+
"git_status": "$(git status --porcelain 2>/dev/null | wc -l | tr -d ' ') modified files"
|
|
65
|
+
},
|
|
66
|
+
"system_context": {
|
|
67
|
+
"os": "$(uname -s)"
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
EOF
|
|
71
|
+
)
|
|
72
|
+
|
|
73
|
+
echo "$context_data"
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
##################################
|
|
77
|
+
# System Diagnostics
|
|
78
|
+
##################################
|
|
79
|
+
gather_diagnostic_info() {
|
|
80
|
+
local diagnostic_info=""
|
|
81
|
+
|
|
82
|
+
# Check recent error logs if available
|
|
83
|
+
if [[ -f "$LOG_FILE" ]]; then
|
|
84
|
+
local recent_errors
|
|
85
|
+
recent_errors=$(tail -20 "$LOG_FILE" 2>/dev/null | grep -i error || echo "No recent errors in log")
|
|
86
|
+
diagnostic_info+="\nRecent log errors:\n$recent_errors"
|
|
87
|
+
fi
|
|
88
|
+
|
|
89
|
+
# Check system resources
|
|
90
|
+
if command -v df >/dev/null; then
|
|
91
|
+
local disk_usage
|
|
92
|
+
disk_usage=$(df -h . | tail -1 | awk '{print "Disk: " $4 " available"}')
|
|
93
|
+
diagnostic_info+="\n\nSystem resources:\n$disk_usage"
|
|
94
|
+
fi
|
|
95
|
+
|
|
96
|
+
# Check for common environment issues
|
|
97
|
+
if [[ -f "package.json" ]] && command -v npm >/dev/null; then
|
|
98
|
+
diagnostic_info+="\nNode.js project detected"
|
|
99
|
+
diagnostic_info+="\nNPM version: $(npm --version 2>/dev/null || echo 'npm not available')"
|
|
100
|
+
fi
|
|
101
|
+
|
|
102
|
+
if [[ -f "requirements.txt" ]] && command -v python >/dev/null; then
|
|
103
|
+
diagnostic_info+="\nPython project detected"
|
|
104
|
+
diagnostic_info+="\nPython version: $(python --version 2>/dev/null || echo 'python not available')"
|
|
105
|
+
fi
|
|
106
|
+
|
|
107
|
+
echo "$diagnostic_info"
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
##################################
|
|
111
|
+
# Subagent Delegation
|
|
112
|
+
##################################
|
|
113
|
+
delegate_to_debug_subagent() {
|
|
114
|
+
local context="$1"
|
|
115
|
+
local diagnostics="$2"
|
|
116
|
+
local error_message="$3"
|
|
117
|
+
|
|
118
|
+
log_info "Delegating error analysis to debug-specialist subagent"
|
|
119
|
+
|
|
120
|
+
echo "🐛 ERROR DETECTED: Automatic debugging assistance activated"
|
|
121
|
+
echo ""
|
|
122
|
+
echo "Error Details:"
|
|
123
|
+
echo " Message: $error_message"
|
|
124
|
+
echo " Tool: ${CLAUDE_TOOL:-unknown}"
|
|
125
|
+
echo " File: ${CLAUDE_FILE:-none}"
|
|
126
|
+
echo " Time: $(date)"
|
|
127
|
+
echo ""
|
|
128
|
+
|
|
129
|
+
if [[ -n "$diagnostics" ]]; then
|
|
130
|
+
echo "System Diagnostics:"
|
|
131
|
+
echo "$diagnostics"
|
|
132
|
+
echo ""
|
|
133
|
+
fi
|
|
134
|
+
|
|
135
|
+
echo "Context for debug-specialist subagent:"
|
|
136
|
+
echo "$context" | jq . 2>/dev/null || echo "$context"
|
|
137
|
+
echo ""
|
|
138
|
+
echo "🔍 DEBUG REQUEST:"
|
|
139
|
+
echo "Please analyze the error above and provide:"
|
|
140
|
+
echo "- Root cause analysis"
|
|
141
|
+
echo "- Step-by-step troubleshooting approach"
|
|
142
|
+
echo "- Specific commands or fixes to try"
|
|
143
|
+
echo "- Prevention strategies for similar issues"
|
|
144
|
+
echo ""
|
|
145
|
+
echo "Type your analysis or questions about this error."
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
##################################
|
|
149
|
+
# Quick Error Classification
|
|
150
|
+
##################################
|
|
151
|
+
classify_error() {
|
|
152
|
+
local error_message="$1"
|
|
153
|
+
local error_type="general"
|
|
154
|
+
|
|
155
|
+
# Basic error pattern matching for better context
|
|
156
|
+
case "$error_message" in
|
|
157
|
+
*"permission denied"*|*"Permission denied"*)
|
|
158
|
+
error_type="permission_error"
|
|
159
|
+
;;
|
|
160
|
+
*"command not found"*|*"Command not found"*)
|
|
161
|
+
error_type="command_not_found"
|
|
162
|
+
;;
|
|
163
|
+
*"No such file"*|*"cannot find"*)
|
|
164
|
+
error_type="file_not_found"
|
|
165
|
+
;;
|
|
166
|
+
*"syntax error"*|*"Syntax error"*)
|
|
167
|
+
error_type="syntax_error"
|
|
168
|
+
;;
|
|
169
|
+
*"connection"*|*"network"*|*"timeout"*)
|
|
170
|
+
error_type="network_error"
|
|
171
|
+
;;
|
|
172
|
+
*"import"*|*"module"*|*"package"*)
|
|
173
|
+
error_type="dependency_error"
|
|
174
|
+
;;
|
|
175
|
+
*)
|
|
176
|
+
error_type="general_error"
|
|
177
|
+
;;
|
|
178
|
+
esac
|
|
179
|
+
|
|
180
|
+
echo "$error_type"
|
|
181
|
+
}
|
|
182
|
+
|
|
183
|
+
##################################
|
|
184
|
+
# Main Hook Logic
|
|
185
|
+
##################################
|
|
186
|
+
main() {
|
|
187
|
+
# Initialize error handling (ironic for an error hook, but important!)
|
|
188
|
+
initialize_error_handling || {
|
|
189
|
+
echo "ERROR: Failed to initialize error handling in error hook" >&2
|
|
190
|
+
exit 1
|
|
191
|
+
}
|
|
192
|
+
|
|
193
|
+
local error_message="${1:-Unknown error occurred}"
|
|
194
|
+
local failed_command="${2:-unknown}"
|
|
195
|
+
|
|
196
|
+
log_info "Error hook triggered: $error_message"
|
|
197
|
+
|
|
198
|
+
# Classify the error type
|
|
199
|
+
local error_type
|
|
200
|
+
error_type=$(classify_error "$error_message")
|
|
201
|
+
|
|
202
|
+
# Gather comprehensive error context
|
|
203
|
+
local context
|
|
204
|
+
context=$(gather_error_context "$error_type" "$error_message" "$failed_command")
|
|
205
|
+
|
|
206
|
+
# Gather additional diagnostic information
|
|
207
|
+
local diagnostics
|
|
208
|
+
diagnostics=$(gather_diagnostic_info)
|
|
209
|
+
|
|
210
|
+
# Delegate to debug-specialist subagent
|
|
211
|
+
delegate_to_debug_subagent "$context" "$diagnostics" "$error_message"
|
|
212
|
+
|
|
213
|
+
log_info "Debug delegation completed for error: $error_type"
|
|
214
|
+
}
|
|
215
|
+
|
|
216
|
+
##################################
|
|
217
|
+
# Execute Hook
|
|
218
|
+
##################################
|
|
219
|
+
# Handle both direct invocation and error trap scenarios
|
|
220
|
+
if [[ "${1:-}" == "--trap" ]]; then
|
|
221
|
+
# Called from an error trap
|
|
222
|
+
main "Script error at line ${2:-unknown}" "${3:-unknown command}"
|
|
223
|
+
else
|
|
224
|
+
# Called directly with error information
|
|
225
|
+
main "$@"
|
|
226
|
+
fi
|
|
@@ -0,0 +1,204 @@
|
|
|
1
|
+
#!/usr/bin/env bash
|
|
2
|
+
set -euo pipefail
|
|
3
|
+
|
|
4
|
+
# Claude Code Hook: Pre-Commit Quality Check
|
|
5
|
+
#
|
|
6
|
+
# Purpose: Lightweight trigger for code quality validation before git commits
|
|
7
|
+
# Trigger: Custom hook for pre-commit operations
|
|
8
|
+
# Approach: Quick validation with style-enforcer subagent delegation
|
|
9
|
+
#
|
|
10
|
+
# This hook ensures code quality by leveraging AI analysis rather than
|
|
11
|
+
# running multiple linting tools manually.
|
|
12
|
+
|
|
13
|
+
##################################
|
|
14
|
+
# Load Shared Libraries
|
|
15
|
+
##################################
|
|
16
|
+
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
|
17
|
+
LIB_DIR="$SCRIPT_DIR/lib"
|
|
18
|
+
|
|
19
|
+
# Load essential modules for lightweight operation
|
|
20
|
+
source "$LIB_DIR/config-constants.sh"
|
|
21
|
+
source "$LIB_DIR/context-manager.sh"
|
|
22
|
+
source "$LIB_DIR/error-handler.sh"
|
|
23
|
+
source "$LIB_DIR/file-utils.sh"
|
|
24
|
+
|
|
25
|
+
##################################
|
|
26
|
+
# Git Context Analysis
|
|
27
|
+
##################################
|
|
28
|
+
analyze_staged_changes() {
|
|
29
|
+
log_info "Analyzing staged changes for quality check"
|
|
30
|
+
|
|
31
|
+
# Check if we're in a git repository
|
|
32
|
+
if ! git rev-parse --git-dir >/dev/null 2>&1; then
|
|
33
|
+
log_debug "Not in a git repository, skipping pre-commit quality check"
|
|
34
|
+
return 0
|
|
35
|
+
fi
|
|
36
|
+
|
|
37
|
+
# Get staged files
|
|
38
|
+
local staged_files
|
|
39
|
+
staged_files=$(git diff --cached --name-only 2>/dev/null || echo "")
|
|
40
|
+
|
|
41
|
+
if [[ -z "$staged_files" ]]; then
|
|
42
|
+
log_info "No staged changes found, skipping quality check"
|
|
43
|
+
return 0
|
|
44
|
+
fi
|
|
45
|
+
|
|
46
|
+
echo "$staged_files"
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
##################################
|
|
50
|
+
# Quality Context Gathering
|
|
51
|
+
##################################
|
|
52
|
+
gather_quality_context() {
|
|
53
|
+
local staged_files="$1"
|
|
54
|
+
|
|
55
|
+
# Create context for quality analysis
|
|
56
|
+
local context_data
|
|
57
|
+
context_data=$(cat <<EOF
|
|
58
|
+
{
|
|
59
|
+
"trigger": "pre_commit_quality",
|
|
60
|
+
"staged_files": [$(echo "$staged_files" | sed 's/.*/"&"/' | paste -sd ',' -)],
|
|
61
|
+
"git_info": {
|
|
62
|
+
"branch": "$(git branch --show-current 2>/dev/null || echo 'unknown')",
|
|
63
|
+
"commit_hash": "$(git rev-parse HEAD 2>/dev/null || echo 'initial')",
|
|
64
|
+
"status": "$(git status --porcelain --cached | wc -l | tr -d ' ') files staged"
|
|
65
|
+
},
|
|
66
|
+
"project_info": {
|
|
67
|
+
"working_directory": "$(pwd)",
|
|
68
|
+
"user": "$USER",
|
|
69
|
+
"timestamp": "$(date -u +"%Y-%m-%dT%H:%M:%SZ")"
|
|
70
|
+
},
|
|
71
|
+
"file_analysis": {
|
|
72
|
+
"total_files": $(echo "$staged_files" | wc -l | tr -d ' '),
|
|
73
|
+
"file_types": $(echo "$staged_files" | sed 's/.*\.//' | sort | uniq -c | jq -R -s 'split("\n")[:-1] | map(split(" ")[-1]) | unique')
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
EOF
|
|
77
|
+
)
|
|
78
|
+
|
|
79
|
+
echo "$context_data"
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
##################################
|
|
83
|
+
# Subagent Delegation
|
|
84
|
+
##################################
|
|
85
|
+
delegate_to_quality_subagent() {
|
|
86
|
+
local context="$1"
|
|
87
|
+
local staged_files="$2"
|
|
88
|
+
|
|
89
|
+
log_info "Delegating quality analysis to style-enforcer subagent"
|
|
90
|
+
|
|
91
|
+
echo "📊 QUALITY CHECK: Analyzing staged changes before commit"
|
|
92
|
+
echo ""
|
|
93
|
+
echo "Staged files for analysis:"
|
|
94
|
+
echo "$staged_files" | sed 's/^/ - /'
|
|
95
|
+
echo ""
|
|
96
|
+
echo "Context for style-enforcer subagent:"
|
|
97
|
+
echo "$context" | jq . 2>/dev/null || echo "$context"
|
|
98
|
+
echo ""
|
|
99
|
+
echo "Please analyze the staged changes for:"
|
|
100
|
+
echo "- Code formatting and style consistency"
|
|
101
|
+
echo "- Import organization and unused imports"
|
|
102
|
+
echo "- Type annotations and documentation"
|
|
103
|
+
echo "- Best practices and code patterns"
|
|
104
|
+
echo "- Performance considerations"
|
|
105
|
+
echo ""
|
|
106
|
+
echo "Provide specific feedback or type 'approved' if quality standards are met."
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
##################################
|
|
110
|
+
# Quick File Validation
|
|
111
|
+
##################################
|
|
112
|
+
validate_basic_file_integrity() {
|
|
113
|
+
local staged_files="$1"
|
|
114
|
+
|
|
115
|
+
log_debug "Performing basic file integrity checks"
|
|
116
|
+
|
|
117
|
+
# Check for common issues that can be caught quickly
|
|
118
|
+
local issues=()
|
|
119
|
+
|
|
120
|
+
while IFS= read -r file; do
|
|
121
|
+
[[ -z "$file" ]] && continue
|
|
122
|
+
|
|
123
|
+
# Skip non-existent files (deletions)
|
|
124
|
+
[[ ! -f "$file" ]] && continue
|
|
125
|
+
|
|
126
|
+
# Check for basic syntax issues in common file types
|
|
127
|
+
case "$file" in
|
|
128
|
+
*.json)
|
|
129
|
+
if ! jq . "$file" >/dev/null 2>&1; then
|
|
130
|
+
issues+=("Invalid JSON syntax: $file")
|
|
131
|
+
fi
|
|
132
|
+
;;
|
|
133
|
+
*.yml|*.yaml)
|
|
134
|
+
if command -v yq >/dev/null && ! yq . "$file" >/dev/null 2>&1; then
|
|
135
|
+
issues+=("Invalid YAML syntax: $file")
|
|
136
|
+
fi
|
|
137
|
+
;;
|
|
138
|
+
*.sh)
|
|
139
|
+
if ! bash -n "$file" 2>/dev/null; then
|
|
140
|
+
issues+=("Invalid shell syntax: $file")
|
|
141
|
+
fi
|
|
142
|
+
;;
|
|
143
|
+
esac
|
|
144
|
+
|
|
145
|
+
# Check for potential credential patterns (quick scan)
|
|
146
|
+
if grep -qE "(password|api_key|secret|token)\s*[:=]\s*['\"][^'\"]+['\"]" "$file" 2>/dev/null; then
|
|
147
|
+
issues+=("Potential credential exposure: $file")
|
|
148
|
+
fi
|
|
149
|
+
|
|
150
|
+
done <<< "$staged_files"
|
|
151
|
+
|
|
152
|
+
# Report immediate issues
|
|
153
|
+
if [[ ${#issues[@]} -gt 0 ]]; then
|
|
154
|
+
echo "⚠️ IMMEDIATE ISSUES FOUND:"
|
|
155
|
+
printf '%s\n' "${issues[@]}" | sed 's/^/ - /'
|
|
156
|
+
echo ""
|
|
157
|
+
echo "Please fix these issues before committing."
|
|
158
|
+
return 1
|
|
159
|
+
fi
|
|
160
|
+
|
|
161
|
+
return 0
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
##################################
|
|
165
|
+
# Main Hook Logic
|
|
166
|
+
##################################
|
|
167
|
+
main() {
|
|
168
|
+
# Initialize error handling
|
|
169
|
+
initialize_error_handling || {
|
|
170
|
+
echo "ERROR: Failed to initialize error handling" >&2
|
|
171
|
+
exit 1
|
|
172
|
+
}
|
|
173
|
+
|
|
174
|
+
log_info "Pre-commit quality check initiated"
|
|
175
|
+
|
|
176
|
+
# Analyze what's being committed
|
|
177
|
+
local staged_files
|
|
178
|
+
staged_files=$(analyze_staged_changes)
|
|
179
|
+
|
|
180
|
+
# Exit early if no staged changes
|
|
181
|
+
if [[ -z "$staged_files" ]]; then
|
|
182
|
+
exit 0
|
|
183
|
+
fi
|
|
184
|
+
|
|
185
|
+
# Perform quick validation checks
|
|
186
|
+
if ! validate_basic_file_integrity "$staged_files"; then
|
|
187
|
+
log_error "Basic file integrity checks failed"
|
|
188
|
+
exit 1
|
|
189
|
+
fi
|
|
190
|
+
|
|
191
|
+
# Gather context for subagent analysis
|
|
192
|
+
local context
|
|
193
|
+
context=$(gather_quality_context "$staged_files")
|
|
194
|
+
|
|
195
|
+
# Delegate to quality subagent for comprehensive analysis
|
|
196
|
+
delegate_to_quality_subagent "$context" "$staged_files"
|
|
197
|
+
|
|
198
|
+
log_info "Quality check delegation completed"
|
|
199
|
+
}
|
|
200
|
+
|
|
201
|
+
##################################
|
|
202
|
+
# Execute Hook
|
|
203
|
+
##################################
|
|
204
|
+
main "$@"
|
|
@@ -0,0 +1,132 @@
|
|
|
1
|
+
#!/usr/bin/env bash
|
|
2
|
+
set -euo pipefail
|
|
3
|
+
|
|
4
|
+
# Claude Code Hook: Pre-Commit Test Runner
|
|
5
|
+
#
|
|
6
|
+
# Description: Auto-detects test framework and runs tests before commits
|
|
7
|
+
# Purpose: Prevent commits with failing tests by validating the full test suite
|
|
8
|
+
# Trigger: PreToolUse
|
|
9
|
+
# Blocking: Yes
|
|
10
|
+
# Tools: Bash
|
|
11
|
+
# Author: Claude Dev Toolkit
|
|
12
|
+
# Version: 1.0.0
|
|
13
|
+
# Category: security
|
|
14
|
+
#
|
|
15
|
+
# This hook validates code quality by running the project's test suite
|
|
16
|
+
# before allowing commit operations to proceed.
|
|
17
|
+
|
|
18
|
+
##################################
|
|
19
|
+
# Configuration
|
|
20
|
+
##################################
|
|
21
|
+
HOOK_NAME="pre-commit-test-runner"
|
|
22
|
+
LOG_FILE="$HOME/.claude/logs/pre-commit-test-runner.log"
|
|
23
|
+
|
|
24
|
+
mkdir -p "$(dirname "$LOG_FILE")"
|
|
25
|
+
chmod 700 "$(dirname "$LOG_FILE")"
|
|
26
|
+
touch "$LOG_FILE"
|
|
27
|
+
chmod 600 "$LOG_FILE"
|
|
28
|
+
|
|
29
|
+
##################################
|
|
30
|
+
# Logging
|
|
31
|
+
##################################
|
|
32
|
+
log() {
|
|
33
|
+
echo "[$(date +'%Y-%m-%d %H:%M:%S')] [$HOOK_NAME] $*" >> "$LOG_FILE"
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
##################################
|
|
37
|
+
# Commit Detection
|
|
38
|
+
##################################
|
|
39
|
+
is_commit_command() {
|
|
40
|
+
local tool="${CLAUDE_TOOL:-}"
|
|
41
|
+
local content="${CLAUDE_CONTENT:-}"
|
|
42
|
+
|
|
43
|
+
if [[ "$tool" != "Bash" ]]; then
|
|
44
|
+
return 1
|
|
45
|
+
fi
|
|
46
|
+
|
|
47
|
+
echo "$content" | grep -qE 'git\s+commit' || return 1
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
##################################
|
|
51
|
+
# Framework Detection
|
|
52
|
+
##################################
|
|
53
|
+
detect_framework() {
|
|
54
|
+
if [[ -f "pytest.ini" ]] || { [[ -f "pyproject.toml" ]] && grep -q '\[tool.pytest' pyproject.toml 2>/dev/null; }; then
|
|
55
|
+
echo "pytest"
|
|
56
|
+
elif [[ -f "package.json" ]] && grep -q '"test"' package.json 2>/dev/null; then
|
|
57
|
+
if grep -qE '"(jest|vitest)' package.json 2>/dev/null; then
|
|
58
|
+
echo "jest"
|
|
59
|
+
else
|
|
60
|
+
echo "npm-test"
|
|
61
|
+
fi
|
|
62
|
+
elif [[ -f "go.mod" ]]; then
|
|
63
|
+
echo "go-test"
|
|
64
|
+
elif [[ -f "Cargo.toml" ]]; then
|
|
65
|
+
echo "cargo-test"
|
|
66
|
+
elif [[ -f "mix.exs" ]]; then
|
|
67
|
+
echo "mix-test"
|
|
68
|
+
else
|
|
69
|
+
echo "none"
|
|
70
|
+
fi
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
##################################
|
|
74
|
+
# Test Execution
|
|
75
|
+
##################################
|
|
76
|
+
run_tests() {
|
|
77
|
+
local framework="$1"
|
|
78
|
+
log "Running tests with framework: $framework"
|
|
79
|
+
|
|
80
|
+
case "$framework" in
|
|
81
|
+
pytest) python -m pytest --tb=short 2>&1 ;;
|
|
82
|
+
jest) npx jest --ci 2>&1 ;;
|
|
83
|
+
npm-test) npm test 2>&1 ;;
|
|
84
|
+
go-test) go test ./... 2>&1 ;;
|
|
85
|
+
cargo-test) cargo test 2>&1 ;;
|
|
86
|
+
mix-test) mix test 2>&1 ;;
|
|
87
|
+
*) echo "No test framework detected" ;;
|
|
88
|
+
esac
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
##################################
|
|
92
|
+
# Main Hook Logic
|
|
93
|
+
##################################
|
|
94
|
+
main() {
|
|
95
|
+
if ! is_commit_command; then
|
|
96
|
+
log "Not a commit command, skipping"
|
|
97
|
+
exit 0
|
|
98
|
+
fi
|
|
99
|
+
|
|
100
|
+
log "Commit detected, checking for test framework"
|
|
101
|
+
local framework
|
|
102
|
+
framework=$(detect_framework)
|
|
103
|
+
|
|
104
|
+
if [[ "$framework" == "none" ]]; then
|
|
105
|
+
log "No test framework detected, allowing commit"
|
|
106
|
+
exit 0
|
|
107
|
+
fi
|
|
108
|
+
|
|
109
|
+
log "Detected framework: $framework"
|
|
110
|
+
local output
|
|
111
|
+
output=$(run_tests "$framework") || {
|
|
112
|
+
local exit_code=$?
|
|
113
|
+
echo "Test validation failed — commit blocked"
|
|
114
|
+
echo "Framework: $framework"
|
|
115
|
+
echo "$output" | tail -10
|
|
116
|
+
log "Tests FAILED (exit $exit_code)"
|
|
117
|
+
exit 1
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
log "Security check passed — all tests green"
|
|
121
|
+
exit 0
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
##################################
|
|
125
|
+
# Error Handling
|
|
126
|
+
##################################
|
|
127
|
+
trap 'log "Hook failed with error on line $LINENO"' ERR
|
|
128
|
+
|
|
129
|
+
##################################
|
|
130
|
+
# Execute
|
|
131
|
+
##################################
|
|
132
|
+
main "$@"
|
|
@@ -0,0 +1,115 @@
|
|
|
1
|
+
#!/usr/bin/env bash
|
|
2
|
+
set -euo pipefail
|
|
3
|
+
|
|
4
|
+
# Claude Code Hook: Pre-Write Security Check
|
|
5
|
+
#
|
|
6
|
+
# Purpose: Lightweight trigger for security scanning before file modifications
|
|
7
|
+
# Trigger: PreToolUse for Edit, Write, MultiEdit tools
|
|
8
|
+
# Approach: Gather context and delegate complex logic to security-auditor subagent
|
|
9
|
+
#
|
|
10
|
+
# This hook provides immediate security feedback by leveraging AI reasoning
|
|
11
|
+
# rather than complex bash pattern matching.
|
|
12
|
+
|
|
13
|
+
##################################
|
|
14
|
+
# Load Shared Libraries
|
|
15
|
+
##################################
|
|
16
|
+
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
|
17
|
+
LIB_DIR="$SCRIPT_DIR/lib"
|
|
18
|
+
|
|
19
|
+
# Load only essential modules for lightweight operation
|
|
20
|
+
source "$LIB_DIR/config-constants.sh"
|
|
21
|
+
source "$LIB_DIR/file-utils.sh"
|
|
22
|
+
source "$LIB_DIR/context-manager.sh"
|
|
23
|
+
source "$LIB_DIR/error-handler.sh"
|
|
24
|
+
|
|
25
|
+
##################################
|
|
26
|
+
# Simple Context Gathering
|
|
27
|
+
##################################
|
|
28
|
+
gather_security_context() {
|
|
29
|
+
local tool="${CLAUDE_TOOL:-unknown}"
|
|
30
|
+
local file="${CLAUDE_FILE:-none}"
|
|
31
|
+
|
|
32
|
+
log_info "Pre-write security check triggered for: $tool on $file"
|
|
33
|
+
|
|
34
|
+
# Create lightweight context for subagent
|
|
35
|
+
local safe_tool safe_file safe_user safe_wd safe_branch
|
|
36
|
+
safe_tool=$(json_escape "$tool")
|
|
37
|
+
safe_file=$(json_escape "$file")
|
|
38
|
+
safe_user=$(json_escape "$USER")
|
|
39
|
+
safe_wd=$(json_escape "$(pwd)")
|
|
40
|
+
safe_branch=$(json_escape "$(git branch --show-current 2>/dev/null || echo 'not-in-git')")
|
|
41
|
+
|
|
42
|
+
local context_data
|
|
43
|
+
context_data=$(cat <<EOF
|
|
44
|
+
{
|
|
45
|
+
"trigger": "pre_write_security",
|
|
46
|
+
"tool": "$safe_tool",
|
|
47
|
+
"file": "$safe_file",
|
|
48
|
+
"timestamp": "$(date -u +"%Y-%m-%dT%H:%M:%SZ")",
|
|
49
|
+
"user": "$safe_user",
|
|
50
|
+
"working_directory": "$safe_wd",
|
|
51
|
+
"git_branch": "$safe_branch",
|
|
52
|
+
"session_id": "${CLAUDE_SESSION_ID:-$$}"
|
|
53
|
+
}
|
|
54
|
+
EOF
|
|
55
|
+
)
|
|
56
|
+
|
|
57
|
+
echo "$context_data"
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
##################################
|
|
61
|
+
# Subagent Delegation
|
|
62
|
+
##################################
|
|
63
|
+
delegate_to_security_subagent() {
|
|
64
|
+
local context="$1"
|
|
65
|
+
|
|
66
|
+
# Log the delegation
|
|
67
|
+
log_info "Delegating security analysis to security-auditor subagent"
|
|
68
|
+
|
|
69
|
+
# In the hybrid approach, we provide context and let Claude Code
|
|
70
|
+
# handle the subagent execution through its native mechanisms
|
|
71
|
+
echo "🔒 SECURITY CHECK: Analyzing $CLAUDE_TOOL operation on $CLAUDE_FILE"
|
|
72
|
+
echo ""
|
|
73
|
+
echo "Context for security-auditor subagent:"
|
|
74
|
+
echo "$context" | jq . 2>/dev/null || echo "$context"
|
|
75
|
+
echo ""
|
|
76
|
+
echo "Please review the operation above for:"
|
|
77
|
+
echo "- Credential exposure (API keys, passwords, tokens)"
|
|
78
|
+
echo "- Security vulnerabilities (SQL injection, XSS, etc.)"
|
|
79
|
+
echo "- Sensitive data handling"
|
|
80
|
+
echo "- Access control issues"
|
|
81
|
+
echo ""
|
|
82
|
+
echo "Type 'continue' if the operation is secure, or provide specific security concerns."
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
##################################
|
|
86
|
+
# Main Hook Logic
|
|
87
|
+
##################################
|
|
88
|
+
main() {
|
|
89
|
+
# Initialize error handling
|
|
90
|
+
initialize_error_handling || {
|
|
91
|
+
echo "ERROR: Failed to initialize error handling" >&2
|
|
92
|
+
exit 1
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
# Gather context for security analysis
|
|
96
|
+
local context
|
|
97
|
+
context=$(gather_security_context)
|
|
98
|
+
|
|
99
|
+
# Check if this is a security-relevant operation
|
|
100
|
+
case "${CLAUDE_TOOL:-}" in
|
|
101
|
+
Edit|Write|MultiEdit)
|
|
102
|
+
log_debug "Security-relevant tool detected: $CLAUDE_TOOL"
|
|
103
|
+
delegate_to_security_subagent "$context"
|
|
104
|
+
;;
|
|
105
|
+
*)
|
|
106
|
+
log_debug "Non-security-relevant tool: ${CLAUDE_TOOL:-unknown}"
|
|
107
|
+
exit 0
|
|
108
|
+
;;
|
|
109
|
+
esac
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
##################################
|
|
113
|
+
# Execute Hook
|
|
114
|
+
##################################
|
|
115
|
+
main "$@"
|