@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,427 @@
|
|
|
1
|
+
#!/usr/bin/env bash
|
|
2
|
+
set -uo pipefail
|
|
3
|
+
|
|
4
|
+
# Argument Parser Module for Subagent-Hook Integration
|
|
5
|
+
#
|
|
6
|
+
# This module provides command-line argument parsing and validation
|
|
7
|
+
# for the subagent-hook integration system.
|
|
8
|
+
|
|
9
|
+
# Include guard
|
|
10
|
+
[[ -n "${_ARGUMENT_PARSER_LOADED:-}" ]] && return 0
|
|
11
|
+
_ARGUMENT_PARSER_LOADED=1
|
|
12
|
+
|
|
13
|
+
# Source required modules
|
|
14
|
+
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
|
15
|
+
source "$SCRIPT_DIR/config-constants.sh"
|
|
16
|
+
source "$SCRIPT_DIR/error-handler.sh"
|
|
17
|
+
|
|
18
|
+
##################################
|
|
19
|
+
# Argument Structure
|
|
20
|
+
##################################
|
|
21
|
+
|
|
22
|
+
# Global variables to store parsed arguments (compatible with older bash versions)
|
|
23
|
+
PARSED_SUBAGENT_NAME=""
|
|
24
|
+
PARSED_EVENT_TYPE=""
|
|
25
|
+
PARSED_ADDITIONAL_CONTEXT=""
|
|
26
|
+
PARSED_EXECUTION_MODE=""
|
|
27
|
+
PARSED_DEBUG_MODE=false
|
|
28
|
+
PARSED_DRY_RUN=false
|
|
29
|
+
PARSED_HELP_REQUESTED=false
|
|
30
|
+
|
|
31
|
+
##################################
|
|
32
|
+
# Usage Functions
|
|
33
|
+
##################################
|
|
34
|
+
|
|
35
|
+
show_usage() {
|
|
36
|
+
cat <<EOF
|
|
37
|
+
Usage: subagent-trigger.sh [OPTIONS] <subagent-name> [event-type] [additional-context]
|
|
38
|
+
OR: subagent-trigger.sh [OPTIONS] --event <event-type>
|
|
39
|
+
|
|
40
|
+
Trigger subagents based on Claude Code events for automated assistance.
|
|
41
|
+
|
|
42
|
+
ARGUMENTS:
|
|
43
|
+
subagent-name Name of the subagent to execute
|
|
44
|
+
event-type Type of event triggering the subagent (default: manual)
|
|
45
|
+
additional-context Additional context to pass to the subagent
|
|
46
|
+
|
|
47
|
+
SPECIAL MODES:
|
|
48
|
+
--event <event-type> Run all subagents configured for the specified event
|
|
49
|
+
|
|
50
|
+
OPTIONS:
|
|
51
|
+
--debug Enable debug logging and verbose output
|
|
52
|
+
--dry-run Show what would be executed without running
|
|
53
|
+
--help, -h Show this help message and exit
|
|
54
|
+
--timeout <ms> Override default timeout (max: $MAX_SUBAGENT_TIMEOUT ms)
|
|
55
|
+
--non-blocking Force non-blocking execution mode
|
|
56
|
+
--blocking Force blocking execution mode
|
|
57
|
+
--config <file> Use custom configuration file
|
|
58
|
+
|
|
59
|
+
SUPPORTED EVENTS:
|
|
60
|
+
EOF
|
|
61
|
+
|
|
62
|
+
local event
|
|
63
|
+
for event in "${SUPPORTED_EVENTS[@]}"; do
|
|
64
|
+
echo " - $event"
|
|
65
|
+
done
|
|
66
|
+
|
|
67
|
+
cat <<EOF
|
|
68
|
+
|
|
69
|
+
EXAMPLES:
|
|
70
|
+
# Run security-auditor for pre-write event
|
|
71
|
+
subagent-trigger.sh security-auditor pre_write
|
|
72
|
+
|
|
73
|
+
# Run all subagents configured for pre_commit event
|
|
74
|
+
subagent-trigger.sh --event pre_commit
|
|
75
|
+
|
|
76
|
+
# Debug mode with custom timeout
|
|
77
|
+
subagent-trigger.sh --debug --timeout 10000 style-enforcer pre_write
|
|
78
|
+
|
|
79
|
+
# Dry run to see what would be executed
|
|
80
|
+
subagent-trigger.sh --dry-run --event security_check
|
|
81
|
+
|
|
82
|
+
EXIT CODES:
|
|
83
|
+
$EXIT_SUCCESS - Success
|
|
84
|
+
$EXIT_GENERAL_ERROR - General error
|
|
85
|
+
$EXIT_VALIDATION_FAILED - Validation failed
|
|
86
|
+
$EXIT_SUBAGENT_NOT_FOUND - Subagent not found
|
|
87
|
+
$EXIT_EXECUTION_FAILED - Execution failed
|
|
88
|
+
$EXIT_TIMEOUT - Operation timed out
|
|
89
|
+
$EXIT_SECURITY_VIOLATION - Security violation detected
|
|
90
|
+
|
|
91
|
+
For more information, see: ~/.claude/logs/subagent-hooks.log
|
|
92
|
+
EOF
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
show_version() {
|
|
96
|
+
cat <<EOF
|
|
97
|
+
Subagent Hook Trigger v$SUBAGENT_HOOK_VERSION
|
|
98
|
+
API Version: $API_VERSION
|
|
99
|
+
Compatible with Claude Code: $COMPATIBLE_CLAUDE_VERSION
|
|
100
|
+
|
|
101
|
+
Configuration:
|
|
102
|
+
Subagents Directory: $SUBAGENTS_DIR
|
|
103
|
+
Configuration File: $CONFIG_FILE
|
|
104
|
+
Log File: $LOG_FILE
|
|
105
|
+
|
|
106
|
+
System Information:
|
|
107
|
+
User: $USER
|
|
108
|
+
Working Directory: $(pwd)
|
|
109
|
+
Git Branch: $(git branch --show-current 2>/dev/null || echo 'not-in-git')
|
|
110
|
+
Timestamp: $(date -u +"%Y-%m-%dT%H:%M:%SZ")
|
|
111
|
+
EOF
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
##################################
|
|
115
|
+
# Argument Validation Functions
|
|
116
|
+
##################################
|
|
117
|
+
|
|
118
|
+
validate_subagent_name() {
|
|
119
|
+
local name="$1"
|
|
120
|
+
|
|
121
|
+
if [[ -z "$name" ]]; then
|
|
122
|
+
log_error "Subagent name cannot be empty"
|
|
123
|
+
return $EXIT_VALIDATION_FAILED
|
|
124
|
+
fi
|
|
125
|
+
|
|
126
|
+
if [[ ${#name} -gt $MAX_SUBAGENT_NAME_LENGTH ]]; then
|
|
127
|
+
log_error "Subagent name too long: ${#name} chars (max: $MAX_SUBAGENT_NAME_LENGTH)"
|
|
128
|
+
return $EXIT_VALIDATION_FAILED
|
|
129
|
+
fi
|
|
130
|
+
|
|
131
|
+
if [[ ! "$name" =~ $SUBAGENT_NAME_PATTERN ]]; then
|
|
132
|
+
log_error "Invalid subagent name format: $name"
|
|
133
|
+
log_error "Name must match pattern: $SUBAGENT_NAME_PATTERN"
|
|
134
|
+
return $EXIT_VALIDATION_FAILED
|
|
135
|
+
fi
|
|
136
|
+
|
|
137
|
+
return $EXIT_SUCCESS
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
validate_event_type() {
|
|
141
|
+
local event="$1"
|
|
142
|
+
|
|
143
|
+
if [[ -z "$event" ]]; then
|
|
144
|
+
log_error "Event type cannot be empty"
|
|
145
|
+
return $EXIT_VALIDATION_FAILED
|
|
146
|
+
fi
|
|
147
|
+
|
|
148
|
+
if [[ ! "$event" =~ $EVENT_NAME_PATTERN ]]; then
|
|
149
|
+
log_error "Invalid event name format: $event"
|
|
150
|
+
log_error "Event must match pattern: $EVENT_NAME_PATTERN"
|
|
151
|
+
return $EXIT_VALIDATION_FAILED
|
|
152
|
+
fi
|
|
153
|
+
|
|
154
|
+
if ! is_supported_event "$event"; then
|
|
155
|
+
log_error "Unsupported event type: $event"
|
|
156
|
+
log_error "Supported events: ${SUPPORTED_EVENTS[*]}"
|
|
157
|
+
return $EXIT_VALIDATION_FAILED
|
|
158
|
+
fi
|
|
159
|
+
|
|
160
|
+
return $EXIT_SUCCESS
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
validate_timeout_value() {
|
|
164
|
+
local timeout="$1"
|
|
165
|
+
|
|
166
|
+
if [[ ! "$timeout" =~ ^[0-9]+$ ]]; then
|
|
167
|
+
log_error "Timeout must be a positive integer: $timeout"
|
|
168
|
+
return $EXIT_VALIDATION_FAILED
|
|
169
|
+
fi
|
|
170
|
+
|
|
171
|
+
if [[ "$timeout" -gt "$MAX_SUBAGENT_TIMEOUT" ]]; then
|
|
172
|
+
log_error "Timeout exceeds maximum: $timeout ms (max: $MAX_SUBAGENT_TIMEOUT ms)"
|
|
173
|
+
return $EXIT_VALIDATION_FAILED
|
|
174
|
+
fi
|
|
175
|
+
|
|
176
|
+
if [[ "$timeout" -lt 100 ]]; then
|
|
177
|
+
log_error "Timeout too small: $timeout ms (min: 100 ms)"
|
|
178
|
+
return $EXIT_VALIDATION_FAILED
|
|
179
|
+
fi
|
|
180
|
+
|
|
181
|
+
return $EXIT_SUCCESS
|
|
182
|
+
}
|
|
183
|
+
|
|
184
|
+
validate_config_file() {
|
|
185
|
+
local config_file="$1"
|
|
186
|
+
|
|
187
|
+
if [[ ! -f "$config_file" ]]; then
|
|
188
|
+
log_error "Configuration file not found: $config_file"
|
|
189
|
+
return $EXIT_GENERAL_ERROR
|
|
190
|
+
fi
|
|
191
|
+
|
|
192
|
+
if [[ ! -r "$config_file" ]]; then
|
|
193
|
+
log_error "Configuration file not readable: $config_file"
|
|
194
|
+
return $EXIT_GENERAL_ERROR
|
|
195
|
+
fi
|
|
196
|
+
|
|
197
|
+
# Basic YAML validation
|
|
198
|
+
if ! grep -q "^[a-z_][a-z0-9_-]*:" "$config_file"; then
|
|
199
|
+
log_error "Configuration file appears to be invalid YAML: $config_file"
|
|
200
|
+
return $EXIT_VALIDATION_FAILED
|
|
201
|
+
fi
|
|
202
|
+
|
|
203
|
+
return $EXIT_SUCCESS
|
|
204
|
+
}
|
|
205
|
+
|
|
206
|
+
##################################
|
|
207
|
+
# Argument Parsing Functions
|
|
208
|
+
##################################
|
|
209
|
+
|
|
210
|
+
parse_arguments() {
|
|
211
|
+
local args=("$@")
|
|
212
|
+
local arg_count=${#args[@]}
|
|
213
|
+
local current_arg=0
|
|
214
|
+
|
|
215
|
+
# Reset global variables
|
|
216
|
+
PARSED_SUBAGENT_NAME=""
|
|
217
|
+
PARSED_EVENT_TYPE="${CLAUDE_HOOK_TRIGGER:-manual}"
|
|
218
|
+
PARSED_ADDITIONAL_CONTEXT=""
|
|
219
|
+
PARSED_EXECUTION_MODE="auto"
|
|
220
|
+
PARSED_DEBUG_MODE=false
|
|
221
|
+
PARSED_DRY_RUN=false
|
|
222
|
+
PARSED_HELP_REQUESTED=false
|
|
223
|
+
|
|
224
|
+
# Handle no arguments
|
|
225
|
+
if [[ $arg_count -eq 0 ]]; then
|
|
226
|
+
log_error "No arguments provided"
|
|
227
|
+
show_usage
|
|
228
|
+
return $EXIT_VALIDATION_FAILED
|
|
229
|
+
fi
|
|
230
|
+
|
|
231
|
+
# Parse arguments
|
|
232
|
+
while [[ $current_arg -lt $arg_count ]]; do
|
|
233
|
+
local arg="${args[$current_arg]}"
|
|
234
|
+
|
|
235
|
+
case "$arg" in
|
|
236
|
+
--help|-h)
|
|
237
|
+
PARSED_HELP_REQUESTED=true
|
|
238
|
+
return $EXIT_SUCCESS
|
|
239
|
+
;;
|
|
240
|
+
--version|-v)
|
|
241
|
+
show_version
|
|
242
|
+
return $EXIT_SUCCESS
|
|
243
|
+
;;
|
|
244
|
+
--debug)
|
|
245
|
+
PARSED_DEBUG_MODE=true
|
|
246
|
+
export DEBUG=true
|
|
247
|
+
log_debug "Debug mode enabled"
|
|
248
|
+
;;
|
|
249
|
+
--dry-run)
|
|
250
|
+
PARSED_DRY_RUN=true
|
|
251
|
+
log_info "Dry run mode enabled"
|
|
252
|
+
;;
|
|
253
|
+
--non-blocking)
|
|
254
|
+
PARSED_EXECUTION_MODE="non-blocking"
|
|
255
|
+
log_debug "Forced non-blocking execution mode"
|
|
256
|
+
;;
|
|
257
|
+
--blocking)
|
|
258
|
+
PARSED_EXECUTION_MODE="blocking"
|
|
259
|
+
log_debug "Forced blocking execution mode"
|
|
260
|
+
;;
|
|
261
|
+
--timeout)
|
|
262
|
+
((current_arg++))
|
|
263
|
+
if [[ $current_arg -ge $arg_count ]]; then
|
|
264
|
+
log_error "--timeout requires a value"
|
|
265
|
+
return $EXIT_VALIDATION_FAILED
|
|
266
|
+
fi
|
|
267
|
+
local timeout_value="${args[$current_arg]}"
|
|
268
|
+
if ! validate_timeout_value "$timeout_value"; then
|
|
269
|
+
return $EXIT_VALIDATION_FAILED
|
|
270
|
+
fi
|
|
271
|
+
export SUBAGENT_TIMEOUT="$timeout_value"
|
|
272
|
+
log_debug "Custom timeout set: ${timeout_value}ms"
|
|
273
|
+
;;
|
|
274
|
+
--config)
|
|
275
|
+
((current_arg++))
|
|
276
|
+
if [[ $current_arg -ge $arg_count ]]; then
|
|
277
|
+
log_error "--config requires a file path"
|
|
278
|
+
return $EXIT_VALIDATION_FAILED
|
|
279
|
+
fi
|
|
280
|
+
local config_file="${args[$current_arg]}"
|
|
281
|
+
if ! validate_config_file "$config_file"; then
|
|
282
|
+
return $EXIT_VALIDATION_FAILED
|
|
283
|
+
fi
|
|
284
|
+
export CONFIG_FILE="$config_file"
|
|
285
|
+
log_debug "Custom config file: $config_file"
|
|
286
|
+
;;
|
|
287
|
+
--event)
|
|
288
|
+
((current_arg++))
|
|
289
|
+
if [[ $current_arg -ge $arg_count ]]; then
|
|
290
|
+
log_error "--event requires an event type"
|
|
291
|
+
return $EXIT_VALIDATION_FAILED
|
|
292
|
+
fi
|
|
293
|
+
PARSED_EXECUTION_MODE="event-based"
|
|
294
|
+
PARSED_EVENT_TYPE="${args[$current_arg]}"
|
|
295
|
+
if ! validate_event_type "$PARSED_EVENT_TYPE"; then
|
|
296
|
+
return $EXIT_VALIDATION_FAILED
|
|
297
|
+
fi
|
|
298
|
+
log_debug "Event-based execution for: $PARSED_EVENT_TYPE"
|
|
299
|
+
;;
|
|
300
|
+
--*)
|
|
301
|
+
log_error "Unknown option: $arg"
|
|
302
|
+
return $EXIT_VALIDATION_FAILED
|
|
303
|
+
;;
|
|
304
|
+
*)
|
|
305
|
+
# Positional arguments
|
|
306
|
+
if [[ -z "$PARSED_SUBAGENT_NAME" ]] && [[ "$PARSED_EXECUTION_MODE" != "event-based" ]]; then
|
|
307
|
+
PARSED_SUBAGENT_NAME="$arg"
|
|
308
|
+
if ! validate_subagent_name "$PARSED_SUBAGENT_NAME"; then
|
|
309
|
+
return $EXIT_VALIDATION_FAILED
|
|
310
|
+
fi
|
|
311
|
+
elif [[ -z "$PARSED_EVENT_TYPE" ]] || [[ "$PARSED_EVENT_TYPE" == "manual" ]]; then
|
|
312
|
+
PARSED_EVENT_TYPE="$arg"
|
|
313
|
+
if ! validate_event_type "$PARSED_EVENT_TYPE"; then
|
|
314
|
+
return $EXIT_VALIDATION_FAILED
|
|
315
|
+
fi
|
|
316
|
+
elif [[ -z "$PARSED_ADDITIONAL_CONTEXT" ]]; then
|
|
317
|
+
PARSED_ADDITIONAL_CONTEXT="$arg"
|
|
318
|
+
else
|
|
319
|
+
log_error "Too many positional arguments: $arg"
|
|
320
|
+
return $EXIT_VALIDATION_FAILED
|
|
321
|
+
fi
|
|
322
|
+
;;
|
|
323
|
+
esac
|
|
324
|
+
|
|
325
|
+
((current_arg++))
|
|
326
|
+
done
|
|
327
|
+
|
|
328
|
+
# Validate required arguments based on execution mode
|
|
329
|
+
if [[ "$PARSED_EXECUTION_MODE" == "event-based" ]]; then
|
|
330
|
+
if [[ -z "$PARSED_EVENT_TYPE" ]]; then
|
|
331
|
+
log_error "Event type is required for event-based execution"
|
|
332
|
+
return $EXIT_VALIDATION_FAILED
|
|
333
|
+
fi
|
|
334
|
+
else
|
|
335
|
+
if [[ -z "$PARSED_SUBAGENT_NAME" ]]; then
|
|
336
|
+
log_error "Subagent name is required for direct execution"
|
|
337
|
+
return $EXIT_VALIDATION_FAILED
|
|
338
|
+
fi
|
|
339
|
+
fi
|
|
340
|
+
|
|
341
|
+
log_debug "Arguments parsed successfully:"
|
|
342
|
+
log_debug " Subagent: ${PARSED_SUBAGENT_NAME:-'(event-based)'}"
|
|
343
|
+
log_debug " Event: $PARSED_EVENT_TYPE"
|
|
344
|
+
log_debug " Context: ${PARSED_ADDITIONAL_CONTEXT:-'none'}"
|
|
345
|
+
log_debug " Mode: $PARSED_EXECUTION_MODE"
|
|
346
|
+
|
|
347
|
+
return $EXIT_SUCCESS
|
|
348
|
+
}
|
|
349
|
+
|
|
350
|
+
##################################
|
|
351
|
+
# Argument Access Functions
|
|
352
|
+
##################################
|
|
353
|
+
|
|
354
|
+
get_parsed_subagent_name() {
|
|
355
|
+
echo "$PARSED_SUBAGENT_NAME"
|
|
356
|
+
}
|
|
357
|
+
|
|
358
|
+
get_parsed_event_type() {
|
|
359
|
+
echo "$PARSED_EVENT_TYPE"
|
|
360
|
+
}
|
|
361
|
+
|
|
362
|
+
get_parsed_additional_context() {
|
|
363
|
+
echo "$PARSED_ADDITIONAL_CONTEXT"
|
|
364
|
+
}
|
|
365
|
+
|
|
366
|
+
get_parsed_execution_mode() {
|
|
367
|
+
echo "$PARSED_EXECUTION_MODE"
|
|
368
|
+
}
|
|
369
|
+
|
|
370
|
+
is_debug_mode() {
|
|
371
|
+
[[ "$PARSED_DEBUG_MODE" == true ]]
|
|
372
|
+
return $?
|
|
373
|
+
}
|
|
374
|
+
|
|
375
|
+
is_dry_run() {
|
|
376
|
+
[[ "$PARSED_DRY_RUN" == true ]]
|
|
377
|
+
return $?
|
|
378
|
+
}
|
|
379
|
+
|
|
380
|
+
is_help_requested() {
|
|
381
|
+
[[ "$PARSED_HELP_REQUESTED" == true ]]
|
|
382
|
+
return $?
|
|
383
|
+
}
|
|
384
|
+
|
|
385
|
+
##################################
|
|
386
|
+
# Argument Logging
|
|
387
|
+
##################################
|
|
388
|
+
|
|
389
|
+
log_parsed_arguments() {
|
|
390
|
+
log_info "Parsed Arguments:"
|
|
391
|
+
log_info " Execution Mode: $PARSED_EXECUTION_MODE"
|
|
392
|
+
|
|
393
|
+
if [[ -n "$PARSED_SUBAGENT_NAME" ]]; then
|
|
394
|
+
log_info " Subagent Name: $PARSED_SUBAGENT_NAME"
|
|
395
|
+
fi
|
|
396
|
+
|
|
397
|
+
log_info " Event Type: $PARSED_EVENT_TYPE"
|
|
398
|
+
|
|
399
|
+
if [[ -n "$PARSED_ADDITIONAL_CONTEXT" ]]; then
|
|
400
|
+
log_info " Additional Context: $PARSED_ADDITIONAL_CONTEXT"
|
|
401
|
+
fi
|
|
402
|
+
|
|
403
|
+
if [[ "$PARSED_DEBUG_MODE" == true ]]; then
|
|
404
|
+
log_info " Debug Mode: enabled"
|
|
405
|
+
fi
|
|
406
|
+
|
|
407
|
+
if [[ "$PARSED_DRY_RUN" == true ]]; then
|
|
408
|
+
log_info " Dry Run: enabled"
|
|
409
|
+
fi
|
|
410
|
+
|
|
411
|
+
if [[ -n "${SUBAGENT_TIMEOUT:-}" ]]; then
|
|
412
|
+
log_info " Custom Timeout: ${SUBAGENT_TIMEOUT}ms"
|
|
413
|
+
fi
|
|
414
|
+
|
|
415
|
+
if [[ "${CONFIG_FILE:-$HOME/.claude/subagent-hooks.yaml}" != "$HOME/.claude/subagent-hooks.yaml" ]]; then
|
|
416
|
+
log_info " Custom Config: $CONFIG_FILE"
|
|
417
|
+
fi
|
|
418
|
+
}
|
|
419
|
+
|
|
420
|
+
##################################
|
|
421
|
+
# Initialization
|
|
422
|
+
##################################
|
|
423
|
+
|
|
424
|
+
initialize_argument_parser() {
|
|
425
|
+
log_debug "Argument parser module initialized"
|
|
426
|
+
return $EXIT_SUCCESS
|
|
427
|
+
}
|
|
@@ -0,0 +1,230 @@
|
|
|
1
|
+
#!/usr/bin/env bash
|
|
2
|
+
set -uo pipefail
|
|
3
|
+
|
|
4
|
+
# Configuration Constants for Subagent-Hook Integration
|
|
5
|
+
#
|
|
6
|
+
# This module defines all configuration constants used throughout the
|
|
7
|
+
# subagent-hook integration system to ensure consistency and maintainability.
|
|
8
|
+
|
|
9
|
+
# Prevent multiple loading of this module
|
|
10
|
+
if [[ -n "${CONFIG_CONSTANTS_LOADED:-}" ]]; then
|
|
11
|
+
return 0
|
|
12
|
+
fi
|
|
13
|
+
CONFIG_CONSTANTS_LOADED=1
|
|
14
|
+
|
|
15
|
+
##################################
|
|
16
|
+
# File and Directory Constants
|
|
17
|
+
##################################
|
|
18
|
+
readonly HOOK_NAME="subagent-trigger"
|
|
19
|
+
readonly SUBAGENT_FILE_EXTENSION=".md"
|
|
20
|
+
readonly CONFIG_FILE_NAME="subagent-hooks.yaml"
|
|
21
|
+
readonly LOG_FILE_NAME="subagent-hooks.log"
|
|
22
|
+
readonly VIOLATION_LOG_NAME="credential-violations.log"
|
|
23
|
+
|
|
24
|
+
##################################
|
|
25
|
+
# Directory Structure Constants
|
|
26
|
+
##################################
|
|
27
|
+
readonly CLAUDE_BASE_DIR="${HOME}/.claude"
|
|
28
|
+
readonly SUBAGENTS_DIR="${CLAUDE_BASE_DIR}/subagents"
|
|
29
|
+
readonly LOGS_DIR="${CLAUDE_BASE_DIR}/logs"
|
|
30
|
+
readonly CONFIG_DIR="${CLAUDE_BASE_DIR}"
|
|
31
|
+
readonly PROJECT_SUBAGENTS_DIR=".claude/subagents"
|
|
32
|
+
|
|
33
|
+
##################################
|
|
34
|
+
# File Path Constants
|
|
35
|
+
##################################
|
|
36
|
+
readonly CONFIG_FILE="${CONFIG_DIR}/${CONFIG_FILE_NAME}"
|
|
37
|
+
readonly LOG_FILE="${LOGS_DIR}/${LOG_FILE_NAME}"
|
|
38
|
+
readonly VIOLATION_LOG="${LOGS_DIR}/${VIOLATION_LOG_NAME}"
|
|
39
|
+
|
|
40
|
+
##################################
|
|
41
|
+
# Timeout Constants (in milliseconds)
|
|
42
|
+
##################################
|
|
43
|
+
readonly DEFAULT_TIMEOUT=5000
|
|
44
|
+
readonly SECURITY_CHECK_TIMEOUT=10000
|
|
45
|
+
readonly DEBUG_TIMEOUT=15000
|
|
46
|
+
readonly MAX_SUBAGENT_TIMEOUT=30000
|
|
47
|
+
readonly CONTEXT_TIMEOUT=2000
|
|
48
|
+
|
|
49
|
+
##################################
|
|
50
|
+
# File Permission Constants
|
|
51
|
+
##################################
|
|
52
|
+
readonly SECURE_DIR_PERMISSIONS=700
|
|
53
|
+
readonly SECURE_FILE_PERMISSIONS=600
|
|
54
|
+
readonly EXECUTABLE_PERMISSIONS=755
|
|
55
|
+
|
|
56
|
+
##################################
|
|
57
|
+
# Validation Constants
|
|
58
|
+
##################################
|
|
59
|
+
readonly MAX_FUNCTION_LENGTH=30
|
|
60
|
+
readonly MAX_SUBAGENT_NAME_LENGTH=50
|
|
61
|
+
readonly MIN_DESCRIPTION_LENGTH=10
|
|
62
|
+
readonly MAX_DESCRIPTION_LENGTH=200
|
|
63
|
+
readonly MAX_CONTEXT_FILE_SIZE=1048576 # 1MB
|
|
64
|
+
|
|
65
|
+
##################################
|
|
66
|
+
# Event Type Constants
|
|
67
|
+
##################################
|
|
68
|
+
readonly -a SUPPORTED_EVENTS=(
|
|
69
|
+
"pre_write"
|
|
70
|
+
"post_write"
|
|
71
|
+
"pre_commit"
|
|
72
|
+
"post_commit"
|
|
73
|
+
"pre_test"
|
|
74
|
+
"post_test"
|
|
75
|
+
"on_error"
|
|
76
|
+
"security_check"
|
|
77
|
+
"code_review"
|
|
78
|
+
"deployment"
|
|
79
|
+
)
|
|
80
|
+
|
|
81
|
+
##################################
|
|
82
|
+
# Tool Pattern Constants
|
|
83
|
+
##################################
|
|
84
|
+
readonly -a FILE_MODIFICATION_TOOLS=(
|
|
85
|
+
"Edit"
|
|
86
|
+
"Write"
|
|
87
|
+
"MultiEdit"
|
|
88
|
+
)
|
|
89
|
+
|
|
90
|
+
readonly -a SECURITY_RELEVANT_TOOLS=(
|
|
91
|
+
"Edit"
|
|
92
|
+
"Write"
|
|
93
|
+
"MultiEdit"
|
|
94
|
+
"Bash"
|
|
95
|
+
)
|
|
96
|
+
|
|
97
|
+
##################################
|
|
98
|
+
# Temporary File Constants
|
|
99
|
+
##################################
|
|
100
|
+
readonly CONTEXT_FILE_PREFIX="${TMPDIR:-/tmp}/claude-subagent-context"
|
|
101
|
+
readonly OUTPUT_FILE_PREFIX="${TMPDIR:-/tmp}/claude-subagent-output"
|
|
102
|
+
readonly TEMP_FILE_PATTERN="claude-subagent-XXXXXX"
|
|
103
|
+
|
|
104
|
+
##################################
|
|
105
|
+
# Logging Level Constants
|
|
106
|
+
##################################
|
|
107
|
+
readonly LOG_LEVEL_DEBUG=0
|
|
108
|
+
readonly LOG_LEVEL_INFO=1
|
|
109
|
+
readonly LOG_LEVEL_WARN=2
|
|
110
|
+
readonly LOG_LEVEL_ERROR=3
|
|
111
|
+
readonly LOG_LEVEL_CRITICAL=4
|
|
112
|
+
|
|
113
|
+
##################################
|
|
114
|
+
# Exit Code Constants
|
|
115
|
+
##################################
|
|
116
|
+
readonly EXIT_SUCCESS=0
|
|
117
|
+
readonly EXIT_GENERAL_ERROR=1
|
|
118
|
+
readonly EXIT_VALIDATION_FAILED=2
|
|
119
|
+
readonly EXIT_SUBAGENT_NOT_FOUND=3
|
|
120
|
+
readonly EXIT_EXECUTION_FAILED=4
|
|
121
|
+
readonly EXIT_TIMEOUT=5
|
|
122
|
+
readonly EXIT_SECURITY_VIOLATION=6
|
|
123
|
+
|
|
124
|
+
##################################
|
|
125
|
+
# Regular Expression Constants
|
|
126
|
+
##################################
|
|
127
|
+
readonly SUBAGENT_NAME_PATTERN='^[a-z][a-z0-9-]{0,49}$'
|
|
128
|
+
readonly EVENT_NAME_PATTERN='^[a-z][a-z0-9_-]*$'
|
|
129
|
+
readonly YAML_FRONTMATTER_START='^---$'
|
|
130
|
+
readonly YAML_FRONTMATTER_END='^---$'
|
|
131
|
+
|
|
132
|
+
##################################
|
|
133
|
+
# Priority Constants
|
|
134
|
+
##################################
|
|
135
|
+
readonly DEFAULT_PRIORITY=5
|
|
136
|
+
readonly HIGH_PRIORITY=1
|
|
137
|
+
readonly MEDIUM_PRIORITY=3
|
|
138
|
+
readonly LOW_PRIORITY=7
|
|
139
|
+
|
|
140
|
+
##################################
|
|
141
|
+
# Boolean Constants
|
|
142
|
+
##################################
|
|
143
|
+
readonly TRUE=1
|
|
144
|
+
readonly FALSE=0
|
|
145
|
+
|
|
146
|
+
##################################
|
|
147
|
+
# Configuration Validation
|
|
148
|
+
##################################
|
|
149
|
+
validate_constants() {
|
|
150
|
+
# Validate that required directories can be created
|
|
151
|
+
if ! mkdir -p "$CLAUDE_BASE_DIR" "$SUBAGENTS_DIR" "$LOGS_DIR" 2>/dev/null; then
|
|
152
|
+
echo "ERROR: Cannot create required directories" >&2
|
|
153
|
+
return $EXIT_GENERAL_ERROR
|
|
154
|
+
fi
|
|
155
|
+
|
|
156
|
+
# Validate timeout values
|
|
157
|
+
if [[ $DEFAULT_TIMEOUT -gt $MAX_SUBAGENT_TIMEOUT ]]; then
|
|
158
|
+
echo "ERROR: Default timeout exceeds maximum" >&2
|
|
159
|
+
return $EXIT_GENERAL_ERROR
|
|
160
|
+
fi
|
|
161
|
+
|
|
162
|
+
return $EXIT_SUCCESS
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
##################################
|
|
166
|
+
# Utility Functions for Constants
|
|
167
|
+
##################################
|
|
168
|
+
is_supported_event() {
|
|
169
|
+
local event="$1"
|
|
170
|
+
local supported_event
|
|
171
|
+
|
|
172
|
+
for supported_event in "${SUPPORTED_EVENTS[@]}"; do
|
|
173
|
+
if [[ "$event" == "$supported_event" ]]; then
|
|
174
|
+
return 0 # Success - event is supported
|
|
175
|
+
fi
|
|
176
|
+
done
|
|
177
|
+
|
|
178
|
+
return 1 # Failure - event is not supported
|
|
179
|
+
}
|
|
180
|
+
|
|
181
|
+
is_file_modification_tool() {
|
|
182
|
+
local tool="$1"
|
|
183
|
+
local file_tool
|
|
184
|
+
|
|
185
|
+
for file_tool in "${FILE_MODIFICATION_TOOLS[@]}"; do
|
|
186
|
+
if [[ "$tool" == "$file_tool" ]]; then
|
|
187
|
+
return 0 # Success - tool is file modification tool
|
|
188
|
+
fi
|
|
189
|
+
done
|
|
190
|
+
|
|
191
|
+
return 1 # Failure - tool is not file modification tool
|
|
192
|
+
}
|
|
193
|
+
|
|
194
|
+
get_timeout_for_event() {
|
|
195
|
+
local event="$1"
|
|
196
|
+
|
|
197
|
+
case "$event" in
|
|
198
|
+
"security_check"|"pre_write")
|
|
199
|
+
echo $SECURITY_CHECK_TIMEOUT
|
|
200
|
+
;;
|
|
201
|
+
"on_error"|"debug")
|
|
202
|
+
echo $DEBUG_TIMEOUT
|
|
203
|
+
;;
|
|
204
|
+
*)
|
|
205
|
+
echo $DEFAULT_TIMEOUT
|
|
206
|
+
;;
|
|
207
|
+
esac
|
|
208
|
+
}
|
|
209
|
+
|
|
210
|
+
##################################
|
|
211
|
+
# Environment Variable Defaults
|
|
212
|
+
##################################
|
|
213
|
+
export CLAUDE_HOOK_TRIGGER="${CLAUDE_HOOK_TRIGGER:-manual}"
|
|
214
|
+
export CLAUDE_TOOL="${CLAUDE_TOOL:-unknown}"
|
|
215
|
+
export CLAUDE_FILE="${CLAUDE_FILE:-}"
|
|
216
|
+
export CLAUDE_CONTENT="${CLAUDE_CONTENT:-}"
|
|
217
|
+
export CLAUDE_SESSION_ID="${CLAUDE_SESSION_ID:-$$}"
|
|
218
|
+
|
|
219
|
+
##################################
|
|
220
|
+
# Version Information
|
|
221
|
+
##################################
|
|
222
|
+
readonly SUBAGENT_HOOK_VERSION="1.0.0"
|
|
223
|
+
readonly COMPATIBLE_CLAUDE_VERSION=">=1.0.0"
|
|
224
|
+
readonly API_VERSION="v1"
|
|
225
|
+
|
|
226
|
+
# Validate constants on load
|
|
227
|
+
if ! validate_constants; then
|
|
228
|
+
echo "FATAL: Configuration constants validation failed" >&2
|
|
229
|
+
exit $EXIT_GENERAL_ERROR
|
|
230
|
+
fi
|