@paulduvall/claude-dev-toolkit 0.0.1-alpha.1 → 0.0.1-alpha.4

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 (117) hide show
  1. package/README.md +44 -6
  2. package/bin/claude-commands +20 -0
  3. package/commands/active/xarchitecture.md +393 -0
  4. package/commands/active/xconfig.md +127 -0
  5. package/commands/active/xdebug.md +130 -0
  6. package/commands/active/xdocs.md +178 -0
  7. package/commands/active/xgit.md +149 -0
  8. package/commands/active/xpipeline.md +152 -0
  9. package/commands/active/xquality.md +96 -0
  10. package/commands/active/xrefactor.md +198 -0
  11. package/commands/active/xrelease.md +142 -0
  12. package/commands/active/xsecurity.md +92 -0
  13. package/commands/active/xspec.md +174 -0
  14. package/commands/active/xtdd.md +151 -0
  15. package/commands/active/xtest.md +89 -0
  16. package/commands/experiments/xact.md +742 -0
  17. package/commands/experiments/xanalytics.md +113 -0
  18. package/commands/experiments/xanalyze.md +70 -0
  19. package/commands/experiments/xapi.md +161 -0
  20. package/commands/experiments/xatomic.md +112 -0
  21. package/commands/experiments/xaws.md +85 -0
  22. package/commands/experiments/xcicd.md +337 -0
  23. package/commands/experiments/xcommit.md +122 -0
  24. package/commands/experiments/xcompliance.md +182 -0
  25. package/commands/experiments/xconstraints.md +89 -0
  26. package/commands/experiments/xcoverage.md +90 -0
  27. package/commands/experiments/xdb.md +102 -0
  28. package/commands/experiments/xdesign.md +121 -0
  29. package/commands/experiments/xevaluate.md +111 -0
  30. package/commands/experiments/xfootnote.md +12 -0
  31. package/commands/experiments/xgenerate.md +117 -0
  32. package/commands/experiments/xgovernance.md +149 -0
  33. package/commands/experiments/xgreen.md +66 -0
  34. package/commands/experiments/xiac.md +118 -0
  35. package/commands/experiments/xincident.md +137 -0
  36. package/commands/experiments/xinfra.md +115 -0
  37. package/commands/experiments/xknowledge.md +115 -0
  38. package/commands/experiments/xmaturity.md +120 -0
  39. package/commands/experiments/xmetrics.md +118 -0
  40. package/commands/experiments/xmonitoring.md +128 -0
  41. package/commands/experiments/xnew.md +898 -0
  42. package/commands/experiments/xobservable.md +114 -0
  43. package/commands/experiments/xoidc.md +165 -0
  44. package/commands/experiments/xoptimize.md +115 -0
  45. package/commands/experiments/xperformance.md +112 -0
  46. package/commands/experiments/xplanning.md +131 -0
  47. package/commands/experiments/xpolicy.md +115 -0
  48. package/commands/experiments/xproduct.md +98 -0
  49. package/commands/experiments/xreadiness.md +75 -0
  50. package/commands/experiments/xred.md +55 -0
  51. package/commands/experiments/xrisk.md +128 -0
  52. package/commands/experiments/xrules.md +124 -0
  53. package/commands/experiments/xsandbox.md +120 -0
  54. package/commands/experiments/xscan.md +102 -0
  55. package/commands/experiments/xsetup.md +123 -0
  56. package/commands/experiments/xtemplate.md +116 -0
  57. package/commands/experiments/xtrace.md +212 -0
  58. package/commands/experiments/xux.md +171 -0
  59. package/commands/experiments/xvalidate.md +104 -0
  60. package/commands/experiments/xworkflow.md +113 -0
  61. package/hooks/README.md +231 -0
  62. package/hooks/file-logger.sh +98 -0
  63. package/hooks/lib/argument-parser.sh +422 -0
  64. package/hooks/lib/config-constants.sh +230 -0
  65. package/hooks/lib/context-manager.sh +549 -0
  66. package/hooks/lib/error-handler.sh +412 -0
  67. package/hooks/lib/execution-engine.sh +627 -0
  68. package/hooks/lib/file-utils.sh +375 -0
  69. package/hooks/lib/subagent-discovery.sh +465 -0
  70. package/hooks/lib/subagent-validator.sh +597 -0
  71. package/hooks/on-error-debug.sh +221 -0
  72. package/hooks/pre-commit-quality.sh +204 -0
  73. package/hooks/pre-write-security.sh +107 -0
  74. package/hooks/prevent-credential-exposure.sh +265 -0
  75. package/hooks/subagent-trigger-simple.sh +193 -0
  76. package/hooks/subagent-trigger.sh +253 -0
  77. package/lib/config.js +186 -3
  78. package/lib/hook-installer-core.js +2 -2
  79. package/lib/result.js +138 -0
  80. package/lib/subagent-formatter.js +278 -0
  81. package/lib/subagents-core.js +237 -0
  82. package/lib/subagents.js +508 -0
  83. package/lib/types.d.ts +183 -0
  84. package/package.json +14 -3
  85. package/subagents/api-guardian.md +29 -0
  86. package/subagents/audit-trail-verifier.md +24 -0
  87. package/subagents/change-scoper.md +23 -0
  88. package/subagents/ci-pipeline-curator.md +24 -0
  89. package/subagents/code-review-assistant.md +258 -0
  90. package/subagents/continuous-release-orchestrator.md +29 -0
  91. package/subagents/contract-tester.md +24 -0
  92. package/subagents/data-steward.md +29 -0
  93. package/subagents/debug-context.md +197 -0
  94. package/subagents/debug-specialist.md +138 -0
  95. package/subagents/dependency-steward.md +24 -0
  96. package/subagents/deployment-strategist.md +29 -0
  97. package/subagents/documentation-curator.md +29 -0
  98. package/subagents/environment-guardian.md +29 -0
  99. package/subagents/license-compliance-guardian.md +29 -0
  100. package/subagents/observability-engineer.md +25 -0
  101. package/subagents/performance-guardian.md +29 -0
  102. package/subagents/product-owner-proxy.md +28 -0
  103. package/subagents/requirements-reviewer.md +26 -0
  104. package/subagents/rollback-first-responder.md +24 -0
  105. package/subagents/sbom-provenance.md +25 -0
  106. package/subagents/security-auditor.md +29 -0
  107. package/subagents/style-enforcer.md +23 -0
  108. package/subagents/test-writer.md +24 -0
  109. package/subagents/trunk-guardian.md +29 -0
  110. package/subagents/workflow-coordinator.md +26 -0
  111. package/templates/README.md +100 -0
  112. package/templates/basic-settings.json +30 -0
  113. package/templates/comprehensive-settings.json +206 -0
  114. package/templates/hybrid-hook-config.yaml +133 -0
  115. package/templates/security-focused-settings.json +62 -0
  116. package/templates/subagent-hooks.yaml +188 -0
  117. package/tsconfig.json +37 -0
@@ -0,0 +1,597 @@
1
+ #!/usr/bin/env bash
2
+
3
+ # Subagent Validator Module for Subagent-Hook Integration
4
+ #
5
+ # This module provides comprehensive validation functionality for subagents,
6
+ # including format validation, content validation, and security checks.
7
+
8
+ # Source required modules
9
+ SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
10
+ source "$SCRIPT_DIR/config-constants.sh"
11
+ source "$SCRIPT_DIR/file-utils.sh"
12
+ source "$SCRIPT_DIR/error-handler.sh"
13
+
14
+ ##################################
15
+ # Basic Validation Functions
16
+ ##################################
17
+
18
+ validate_subagent_file() {
19
+ local subagent_file="$1"
20
+ local validation_mode="${2:-strict}"
21
+
22
+ if [[ -z "$subagent_file" ]]; then
23
+ log_error "Subagent file path is required"
24
+ return $EXIT_VALIDATION_FAILED
25
+ fi
26
+
27
+ log_debug "Validating subagent file: $subagent_file (mode: $validation_mode)"
28
+
29
+ # Basic file validation
30
+ if ! validate_file_existence "$subagent_file"; then
31
+ return $EXIT_VALIDATION_FAILED
32
+ fi
33
+
34
+ if ! validate_file_security "$subagent_file"; then
35
+ return $EXIT_SECURITY_VIOLATION
36
+ fi
37
+
38
+ if ! validate_file_format "$subagent_file"; then
39
+ return $EXIT_VALIDATION_FAILED
40
+ fi
41
+
42
+ if ! validate_yaml_frontmatter "$subagent_file"; then
43
+ return $EXIT_VALIDATION_FAILED
44
+ fi
45
+
46
+ if [[ "$validation_mode" == "strict" ]]; then
47
+ if ! validate_subagent_content "$subagent_file"; then
48
+ return $EXIT_VALIDATION_FAILED
49
+ fi
50
+
51
+ if ! validate_subagent_metadata "$subagent_file"; then
52
+ return $EXIT_VALIDATION_FAILED
53
+ fi
54
+ fi
55
+
56
+ log_debug "Subagent file validation passed: $subagent_file"
57
+ return $EXIT_SUCCESS
58
+ }
59
+
60
+ validate_file_existence() {
61
+ local file_path="$1"
62
+
63
+ if [[ ! -f "$file_path" ]]; then
64
+ handle_missing_subagent "$(basename "$file_path" "$SUBAGENT_FILE_EXTENSION")"
65
+ return $EXIT_SUBAGENT_NOT_FOUND
66
+ fi
67
+
68
+ if [[ ! -r "$file_path" ]]; then
69
+ log_error "Subagent file not readable: $file_path"
70
+ return $EXIT_VALIDATION_FAILED
71
+ fi
72
+
73
+ return $EXIT_SUCCESS
74
+ }
75
+
76
+ validate_file_security() {
77
+ local file_path="$1"
78
+
79
+ # Validate file permissions
80
+ if ! validate_file_permissions "$file_path"; then
81
+ handle_security_violation "insecure_file_permissions" \
82
+ "File has insecure permissions" "$file_path"
83
+ return $EXIT_SECURITY_VIOLATION
84
+ fi
85
+
86
+ # Validate path safety
87
+ if ! validate_path_safety "$file_path"; then
88
+ handle_security_violation "unsafe_file_path" \
89
+ "File path contains unsafe elements" "$file_path"
90
+ return $EXIT_SECURITY_VIOLATION
91
+ fi
92
+
93
+ return $EXIT_SUCCESS
94
+ }
95
+
96
+ validate_file_format() {
97
+ local file_path="$1"
98
+
99
+ # Check file extension
100
+ if ! file_has_extension "$file_path" "$SUBAGENT_FILE_EXTENSION"; then
101
+ log_error "Invalid file extension: $file_path (expected: $SUBAGENT_FILE_EXTENSION)"
102
+ return $EXIT_VALIDATION_FAILED
103
+ fi
104
+
105
+ # Check file size
106
+ local file_content
107
+ if ! file_content=$(read_file_with_size_limit "$file_path"); then
108
+ log_error "File too large or unreadable: $file_path"
109
+ return $EXIT_VALIDATION_FAILED
110
+ fi
111
+
112
+ # Check if file appears to be binary
113
+ if file "$file_path" 2>/dev/null | grep -q "binary"; then
114
+ log_error "File appears to be binary: $file_path"
115
+ return $EXIT_VALIDATION_FAILED
116
+ fi
117
+
118
+ return $EXIT_SUCCESS
119
+ }
120
+
121
+ ##################################
122
+ # YAML Frontmatter Validation
123
+ ##################################
124
+
125
+ validate_yaml_frontmatter() {
126
+ local file_path="$1"
127
+
128
+ local content
129
+ if ! content=$(read_file_safely "$file_path"); then
130
+ log_error "Failed to read file for frontmatter validation: $file_path"
131
+ return $EXIT_VALIDATION_FAILED
132
+ fi
133
+
134
+ # Check for YAML frontmatter start
135
+ if ! echo "$content" | head -1 | grep -q "$YAML_FRONTMATTER_START"; then
136
+ log_error "Missing YAML frontmatter start marker in: $file_path"
137
+ return $EXIT_VALIDATION_FAILED
138
+ fi
139
+
140
+ # Find frontmatter end
141
+ local frontmatter_end_found=false
142
+ local line_count=0
143
+
144
+ while IFS= read -r line; do
145
+ ((line_count++))
146
+
147
+ # Skip first line (start marker)
148
+ if [[ $line_count -eq 1 ]]; then
149
+ continue
150
+ fi
151
+
152
+ if [[ "$line" == "---" ]]; then
153
+ frontmatter_end_found=true
154
+ break
155
+ fi
156
+
157
+ # Prevent infinite search
158
+ if [[ $line_count -gt 100 ]]; then
159
+ break
160
+ fi
161
+ done <<< "$content"
162
+
163
+ if [[ "$frontmatter_end_found" != true ]]; then
164
+ log_error "Missing YAML frontmatter end marker in: $file_path"
165
+ return $EXIT_VALIDATION_FAILED
166
+ fi
167
+
168
+ log_debug "YAML frontmatter structure valid: $file_path"
169
+ return $EXIT_SUCCESS
170
+ }
171
+
172
+ extract_frontmatter_field() {
173
+ local file_path="$1"
174
+ local field_name="$2"
175
+ local required="${3:-false}"
176
+
177
+ if [[ -z "$file_path" ]] || [[ -z "$field_name" ]]; then
178
+ log_error "File path and field name are required"
179
+ return $EXIT_VALIDATION_FAILED
180
+ fi
181
+
182
+ local content
183
+ if ! content=$(read_file_safely "$file_path"); then
184
+ log_error "Failed to read file: $file_path"
185
+ return $EXIT_VALIDATION_FAILED
186
+ fi
187
+
188
+ local in_frontmatter=false
189
+ local field_value=""
190
+
191
+ while IFS= read -r line; do
192
+ if [[ "$line" == "---" ]]; then
193
+ if [[ "$in_frontmatter" == true ]]; then
194
+ break # End of frontmatter
195
+ else
196
+ in_frontmatter=true
197
+ continue
198
+ fi
199
+ fi
200
+
201
+ if [[ "$in_frontmatter" == true ]]; then
202
+ if [[ "$line" =~ ^${field_name}:[[:space:]]*(.*)$ ]]; then
203
+ field_value="${BASH_REMATCH[1]}"
204
+ # Remove quotes if present
205
+ field_value="${field_value#\"}"
206
+ field_value="${field_value%\"}"
207
+ break
208
+ fi
209
+ fi
210
+ done <<< "$content"
211
+
212
+ if [[ -z "$field_value" ]] && [[ "$required" == true ]]; then
213
+ log_error "Required field missing: $field_name in $file_path"
214
+ return $EXIT_VALIDATION_FAILED
215
+ fi
216
+
217
+ echo "$field_value"
218
+ return $EXIT_SUCCESS
219
+ }
220
+
221
+ ##################################
222
+ # Content Validation Functions
223
+ ##################################
224
+
225
+ validate_subagent_metadata() {
226
+ local file_path="$1"
227
+
228
+ log_debug "Validating subagent metadata: $file_path"
229
+
230
+ # Validate required fields
231
+ local required_fields=("name" "description")
232
+ local field
233
+
234
+ for field in "${required_fields[@]}"; do
235
+ local field_value
236
+ if ! field_value=$(extract_frontmatter_field "$file_path" "$field" true); then
237
+ return $EXIT_VALIDATION_FAILED
238
+ fi
239
+
240
+ case "$field" in
241
+ "name")
242
+ if ! validate_subagent_name_field "$field_value"; then
243
+ log_error "Invalid name field in: $file_path"
244
+ return $EXIT_VALIDATION_FAILED
245
+ fi
246
+ ;;
247
+ "description")
248
+ if ! validate_description_field "$field_value"; then
249
+ log_error "Invalid description field in: $file_path"
250
+ return $EXIT_VALIDATION_FAILED
251
+ fi
252
+ ;;
253
+ esac
254
+ done
255
+
256
+ # Validate optional fields if present
257
+ local optional_fields=("version" "tools" "tags")
258
+ for field in "${optional_fields[@]}"; do
259
+ local field_value
260
+ if field_value=$(extract_frontmatter_field "$file_path" "$field" false); then
261
+ if [[ -n "$field_value" ]]; then
262
+ case "$field" in
263
+ "version")
264
+ validate_version_field "$field_value" || {
265
+ log_warning "Invalid version field in: $file_path"
266
+ }
267
+ ;;
268
+ "tools")
269
+ validate_tools_field "$field_value" || {
270
+ log_warning "Invalid tools field in: $file_path"
271
+ }
272
+ ;;
273
+ "tags")
274
+ validate_tags_field "$field_value" || {
275
+ log_warning "Invalid tags field in: $file_path"
276
+ }
277
+ ;;
278
+ esac
279
+ fi
280
+ fi
281
+ done
282
+
283
+ log_debug "Subagent metadata validation passed: $file_path"
284
+ return $EXIT_SUCCESS
285
+ }
286
+
287
+ validate_subagent_content() {
288
+ local file_path="$1"
289
+
290
+ log_debug "Validating subagent content: $file_path"
291
+
292
+ local content
293
+ if ! content=$(read_file_safely "$file_path"); then
294
+ log_error "Failed to read file for content validation: $file_path"
295
+ return $EXIT_VALIDATION_FAILED
296
+ fi
297
+
298
+ # Check for minimum content after frontmatter
299
+ local in_frontmatter=false
300
+ local frontmatter_ended=false
301
+ local content_lines=0
302
+
303
+ while IFS= read -r line; do
304
+ if [[ "$line" == "---" ]]; then
305
+ if [[ "$in_frontmatter" == true ]]; then
306
+ frontmatter_ended=true
307
+ else
308
+ in_frontmatter=true
309
+ fi
310
+ continue
311
+ fi
312
+
313
+ if [[ "$frontmatter_ended" == true ]]; then
314
+ # Count non-empty lines
315
+ if [[ -n "${line// }" ]]; then
316
+ ((content_lines++))
317
+ fi
318
+ fi
319
+ done <<< "$content"
320
+
321
+ if [[ $content_lines -lt 3 ]]; then
322
+ log_error "Insufficient content after frontmatter in: $file_path"
323
+ return $EXIT_VALIDATION_FAILED
324
+ fi
325
+
326
+ # Check for suspicious content patterns
327
+ if ! validate_content_security "$content" "$file_path"; then
328
+ return $EXIT_SECURITY_VIOLATION
329
+ fi
330
+
331
+ log_debug "Subagent content validation passed: $file_path"
332
+ return $EXIT_SUCCESS
333
+ }
334
+
335
+ ##################################
336
+ # Field Validation Functions
337
+ ##################################
338
+
339
+ validate_subagent_name_field() {
340
+ local name="$1"
341
+
342
+ if [[ -z "$name" ]]; then
343
+ log_error "Subagent name cannot be empty"
344
+ return $EXIT_VALIDATION_FAILED
345
+ fi
346
+
347
+ if [[ ${#name} -gt $MAX_SUBAGENT_NAME_LENGTH ]]; then
348
+ log_error "Subagent name too long: ${#name} chars (max: $MAX_SUBAGENT_NAME_LENGTH)"
349
+ return $EXIT_VALIDATION_FAILED
350
+ fi
351
+
352
+ if [[ ! "$name" =~ $SUBAGENT_NAME_PATTERN ]]; then
353
+ log_error "Invalid subagent name format: $name"
354
+ return $EXIT_VALIDATION_FAILED
355
+ fi
356
+
357
+ return $EXIT_SUCCESS
358
+ }
359
+
360
+ validate_description_field() {
361
+ local description="$1"
362
+
363
+ if [[ -z "$description" ]]; then
364
+ log_error "Description cannot be empty"
365
+ return $EXIT_VALIDATION_FAILED
366
+ fi
367
+
368
+ if [[ ${#description} -lt $MIN_DESCRIPTION_LENGTH ]]; then
369
+ log_error "Description too short: ${#description} chars (min: $MIN_DESCRIPTION_LENGTH)"
370
+ return $EXIT_VALIDATION_FAILED
371
+ fi
372
+
373
+ if [[ ${#description} -gt $MAX_DESCRIPTION_LENGTH ]]; then
374
+ log_error "Description too long: ${#description} chars (max: $MAX_DESCRIPTION_LENGTH)"
375
+ return $EXIT_VALIDATION_FAILED
376
+ fi
377
+
378
+ return $EXIT_SUCCESS
379
+ }
380
+
381
+ validate_version_field() {
382
+ local version="$1"
383
+
384
+ # Semantic versioning pattern
385
+ if [[ "$version" =~ ^[0-9]+\.[0-9]+\.[0-9]+(-[a-zA-Z0-9.-]+)?(\+[a-zA-Z0-9.-]+)?$ ]]; then
386
+ return $EXIT_SUCCESS
387
+ fi
388
+
389
+ # Simple versioning pattern
390
+ if [[ "$version" =~ ^[0-9]+(\.[0-9]+)*$ ]]; then
391
+ return $EXIT_SUCCESS
392
+ fi
393
+
394
+ log_error "Invalid version format: $version"
395
+ return $EXIT_VALIDATION_FAILED
396
+ }
397
+
398
+ validate_tools_field() {
399
+ local tools="$1"
400
+
401
+ # Tools can be comma-separated or a single word
402
+ # Allow: "Read, Edit, MultiEdit" or "Read,Edit,MultiEdit" or "Read"
403
+ if [[ "$tools" =~ ^[a-zA-Z][a-zA-Z0-9_]*([[:space:]]*,[[:space:]]*[a-zA-Z][a-zA-Z0-9_]*)*$ ]]; then
404
+ return $EXIT_SUCCESS
405
+ fi
406
+
407
+ log_error "Invalid tools format: $tools"
408
+ return $EXIT_VALIDATION_FAILED
409
+ }
410
+
411
+ validate_tags_field() {
412
+ local tags="$1"
413
+
414
+ # Tags can be array format or comma-separated
415
+ if [[ "$tags" =~ ^\[.*\]$ ]] || [[ "$tags" =~ ^[a-zA-Z][a-zA-Z0-9_,-\s]*$ ]]; then
416
+ return $EXIT_SUCCESS
417
+ fi
418
+
419
+ log_error "Invalid tags format: $tags"
420
+ return $EXIT_VALIDATION_FAILED
421
+ }
422
+
423
+ ##################################
424
+ # Security Validation Functions
425
+ ##################################
426
+
427
+ validate_content_security() {
428
+ local content="$1"
429
+ local file_path="$2"
430
+
431
+ log_debug "Performing security validation on content"
432
+
433
+ # Check for suspicious patterns
434
+ local suspicious_patterns=(
435
+ 'rm\s+-rf'
436
+ 'curl\s+.*\|\s*sh'
437
+ 'wget\s+.*\|\s*sh'
438
+ 'eval\s*\$'
439
+ '`.*`'
440
+ '\$\(.*\)'
441
+ 'exec\s+["\047]'
442
+ )
443
+
444
+ local pattern
445
+ for pattern in "${suspicious_patterns[@]}"; do
446
+ if echo "$content" | grep -qE "$pattern"; then
447
+ handle_security_violation "suspicious_content" \
448
+ "Suspicious pattern detected: $pattern" "$file_path"
449
+ return $EXIT_SECURITY_VIOLATION
450
+ fi
451
+ done
452
+
453
+ # Check for potential credential exposure
454
+ local credential_patterns=(
455
+ 'password\s*[:=]\s*["\047]?[^"\047[:space:]]+["\047]?'
456
+ 'token\s*[:=]\s*["\047]?[^"\047[:space:]]+["\047]?'
457
+ 'api[_-]?key\s*[:=]\s*["\047]?[^"\047[:space:]]+["\047]?'
458
+ 'secret\s*[:=]\s*["\047]?[^"\047[:space:]]+["\047]?'
459
+ )
460
+
461
+ for pattern in "${credential_patterns[@]}"; do
462
+ if echo "$content" | grep -qiE "$pattern"; then
463
+ handle_security_violation "potential_credential_exposure" \
464
+ "Potential credential pattern detected: $pattern" "$file_path"
465
+ return $EXIT_SECURITY_VIOLATION
466
+ fi
467
+ done
468
+
469
+ log_debug "Content security validation passed"
470
+ return $EXIT_SUCCESS
471
+ }
472
+
473
+ ##################################
474
+ # Batch Validation Functions
475
+ ##################################
476
+
477
+ validate_all_subagents() {
478
+ local directory="${1:-$SUBAGENTS_DIR}"
479
+ local validation_mode="${2:-strict}"
480
+ local validation_results=()
481
+ local total_count=0
482
+ local passed_count=0
483
+ local failed_count=0
484
+
485
+ log_info "Validating all subagents in: $directory"
486
+
487
+ if [[ ! -d "$directory" ]]; then
488
+ log_error "Directory not found: $directory"
489
+ return $EXIT_GENERAL_ERROR
490
+ fi
491
+
492
+ find "$directory" -name "*$SUBAGENT_FILE_EXTENSION" -type f 2>/dev/null | while read -r file; do
493
+ ((total_count++))
494
+ local filename=$(basename "$file")
495
+
496
+ if validate_subagent_file "$file" "$validation_mode" 2>/dev/null; then
497
+ ((passed_count++))
498
+ validation_results+=("PASS: $filename")
499
+ log_debug "Validation passed: $filename"
500
+ else
501
+ ((failed_count++))
502
+ validation_results+=("FAIL: $filename")
503
+ log_debug "Validation failed: $filename"
504
+ fi
505
+ done
506
+
507
+ # Output results
508
+ log_info "Validation Summary:"
509
+ log_info " Total subagents: $total_count"
510
+ log_info " Passed: $passed_count"
511
+ log_info " Failed: $failed_count"
512
+
513
+ # Detailed results in debug mode
514
+ if is_debug_mode 2>/dev/null; then
515
+ for result in "${validation_results[@]}"; do
516
+ log_debug " $result"
517
+ done
518
+ fi
519
+
520
+ if [[ $failed_count -gt 0 ]]; then
521
+ return $EXIT_VALIDATION_FAILED
522
+ fi
523
+
524
+ return $EXIT_SUCCESS
525
+ }
526
+
527
+ ##################################
528
+ # Validation Reporting Functions
529
+ ##################################
530
+
531
+ generate_validation_report() {
532
+ local directory="${1:-$SUBAGENTS_DIR}"
533
+ local output_format="${2:-text}"
534
+
535
+ log_info "Generating validation report for: $directory"
536
+
537
+ case "$output_format" in
538
+ "json")
539
+ generate_json_validation_report "$directory"
540
+ ;;
541
+ "text"|*)
542
+ generate_text_validation_report "$directory"
543
+ ;;
544
+ esac
545
+ }
546
+
547
+ generate_text_validation_report() {
548
+ local directory="$1"
549
+
550
+ echo "Subagent Validation Report"
551
+ echo "========================="
552
+ echo "Directory: $directory"
553
+ echo "Generated: $(date)"
554
+ echo ""
555
+
556
+ local total=0 passed=0 failed=0
557
+
558
+ find "$directory" -name "*$SUBAGENT_FILE_EXTENSION" -type f 2>/dev/null | while read -r file; do
559
+ ((total++))
560
+ local filename=$(basename "$file")
561
+ local name=$(basename "$file" "$SUBAGENT_FILE_EXTENSION")
562
+
563
+ echo -n "Validating $name... "
564
+
565
+ if validate_subagent_file "$file" "strict" 2>/dev/null; then
566
+ ((passed++))
567
+ echo "PASSED"
568
+ else
569
+ ((failed++))
570
+ echo "FAILED"
571
+
572
+ # Show specific validation errors
573
+ validate_subagent_file "$file" "strict" 2>&1 | sed "s/^/ Error: /"
574
+ fi
575
+ echo ""
576
+ done
577
+
578
+ echo "Summary:"
579
+ echo " Total: $total"
580
+ echo " Passed: $passed"
581
+ echo " Failed: $failed"
582
+
583
+ if [[ $failed -eq 0 ]]; then
584
+ echo " Status: ALL VALID ✓"
585
+ else
586
+ echo " Status: ISSUES FOUND ✗"
587
+ fi
588
+ }
589
+
590
+ ##################################
591
+ # Initialization
592
+ ##################################
593
+
594
+ initialize_subagent_validator() {
595
+ log_debug "Subagent validator module initialized"
596
+ return $EXIT_SUCCESS
597
+ }