@a-company/paradigm 5.21.2 → 5.23.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.
@@ -1,5 +1,5 @@
1
1
  #!/usr/bin/env node
2
- import*as e from'fs';import*as r from'path';import*as E from'os';import {execSync}from'child_process';import o from'chalk';var y=`#!/bin/sh
2
+ import*as e from'fs';import*as r from'path';import*as E from'os';import {execSync}from'child_process';import o from'chalk';var N=`#!/bin/sh
3
3
  # paradigm-common.sh \u2014 Shared compliance checks for Paradigm stop hooks
4
4
  # Sourced by claude-code-stop.sh and cursor-stop.sh
5
5
  #
@@ -30,6 +30,8 @@ import*as e from'fs';import*as r from'path';import*as E from'os';import {execSyn
30
30
  # 9. Purpose-required patterns from config.yaml
31
31
  # 10. Aspect drift detection with auto-heal (from unified compliance-check)
32
32
  # 11. Portal gate implementation compliance (from unified compliance-check)
33
+ # 12. Graduation failure tracking (auto-demotion)
34
+ # 13. Orchestration required for complex tasks
33
35
 
34
36
  VIOLATIONS=""
35
37
  VIOLATION_COUNT=0
@@ -37,6 +39,35 @@ AUTO_FIXED=""
37
39
  AUTO_FIX_COUNT=0
38
40
  PARADIGM_AUTO_FIX="\${PARADIGM_AUTO_FIX:-0}"
39
41
 
42
+ # --- Load enforcement config ---
43
+ ENFORCEMENT_MAP=""
44
+ if command -v paradigm >/dev/null 2>&1; then
45
+ ENFORCEMENT_MAP=$(paradigm enforcement resolve --json 2>/dev/null) || true
46
+ fi
47
+
48
+ # Helper: get severity for a check ID
49
+ _check_severity() {
50
+ _id="$1"
51
+ _default="$2"
52
+ if [ -z "$ENFORCEMENT_MAP" ]; then
53
+ echo "$_default"
54
+ return
55
+ fi
56
+ _val=$(echo "$ENFORCEMENT_MAP" | grep -o "\\"$_id\\":\\"[^\\"]*\\"" | sed 's/.*":\\"//' | sed 's/"//')
57
+ if [ -n "$_val" ]; then
58
+ echo "$_val"
59
+ else
60
+ echo "$_default"
61
+ fi
62
+ }
63
+
64
+ # Read orchestration threshold
65
+ ORCH_THRESHOLD=3
66
+ if [ -n "$ENFORCEMENT_MAP" ]; then
67
+ _ot=$(echo "$ENFORCEMENT_MAP" | grep -o '"orchestrationThreshold":[0-9]*' | sed 's/.*://')
68
+ [ -n "$_ot" ] && ORCH_THRESHOLD="$_ot"
69
+ fi
70
+
40
71
  # --- Cache .purpose file paths (avoid repeated find scans) ---
41
72
  PURPOSE_CACHE=".paradigm/.purpose-paths"
42
73
  if [ -f "$PURPOSE_CACHE" ]; then
@@ -103,17 +134,24 @@ for file in $MODIFIED; do
103
134
  done
104
135
 
105
136
  # Only flag if there are uncovered directories AND zero paradigm files were touched
106
- if [ -n "$UNCOVERED_SOURCE_DIRS" ] && [ "$PARADIGM_COUNT" -eq 0 ]; then
137
+ _SEV=$(_check_severity "purpose-coverage" "block")
138
+ if [ "$_SEV" != "off" ] && [ -n "$UNCOVERED_SOURCE_DIRS" ] && [ "$PARADIGM_COUNT" -eq 0 ]; then
107
139
  # Count uncovered dirs
108
140
  UNCOVERED_DIR_COUNT=0
109
141
  for _d in $UNCOVERED_SOURCE_DIRS; do
110
142
  UNCOVERED_DIR_COUNT=$((UNCOVERED_DIR_COUNT + 1))
111
143
  done
112
- VIOLATIONS="$VIOLATIONS
144
+ if [ "$_SEV" = "block" ]; then
145
+ VIOLATIONS="$VIOLATIONS
113
146
  - You modified source files in $UNCOVERED_DIR_COUNT director(ies) without updating their .purpose files:
114
147
  $UNCOVERED_SOURCE_DIRS
115
148
  Update the nearest .purpose file for each modified code area."
116
- VIOLATION_COUNT=$((VIOLATION_COUNT + 1))
149
+ VIOLATION_COUNT=$((VIOLATION_COUNT + 1))
150
+ else
151
+ ADVISORY="$ADVISORY
152
+ - (warn) Source files in $UNCOVERED_DIR_COUNT director(ies) modified without .purpose updates:
153
+ $UNCOVERED_SOURCE_DIRS"
154
+ fi
117
155
  fi
118
156
 
119
157
  # --- Check 2: Modified source directories missing .purpose files ---
@@ -149,7 +187,8 @@ for file in $MODIFIED; do
149
187
  fi
150
188
  done
151
189
 
152
- if [ -n "$DIRS_WITHOUT_PURPOSE" ]; then
190
+ _SEV=$(_check_severity "purpose-exists" "block")
191
+ if [ "$_SEV" != "off" ] && [ -n "$DIRS_WITHOUT_PURPOSE" ]; then
153
192
  if [ "$PARADIGM_AUTO_FIX" = "1" ]; then
154
193
  # Auto-fix: create stub .purpose files for directories missing them
155
194
  for dir in $DIRS_WITHOUT_PURPOSE; do
@@ -165,86 +204,107 @@ PURPOSEEOF
165
204
  - Created stub .purpose in $dir (update descriptions)"
166
205
  AUTO_FIX_COUNT=$((AUTO_FIX_COUNT + 1))
167
206
  done
168
- else
207
+ elif [ "$_SEV" = "block" ]; then
169
208
  VIOLATIONS="$VIOLATIONS
170
209
  - These directories have modified source files but no .purpose file anywhere in their path:
171
210
  $DIRS_WITHOUT_PURPOSE
172
211
  Create a .purpose file using paradigm_purpose_init + paradigm_purpose_add_component."
173
212
  VIOLATION_COUNT=$((VIOLATION_COUNT + 1))
213
+ else
214
+ ADVISORY="$ADVISORY
215
+ - (warn) Directories with modified source files but no .purpose file:
216
+ $DIRS_WITHOUT_PURPOSE"
174
217
  fi
175
218
  fi
176
219
 
177
220
  # --- Check 3: Route patterns added without portal.yaml ---
178
- if [ -f "portal.yaml" ] || echo "$MODIFIED" | grep -q "portal.yaml"; then
179
- : # portal.yaml exists or was modified \u2014 OK
180
- else
181
- # Check if any modified files contain route-like patterns
182
- # Skip: test/spec/fixture files, markdown, and comment-only matches
183
- ROUTE_FILES=""
184
- for file in $MODIFIED; do
185
- # Skip test, spec, and fixture files entirely
186
- case "$file" in
187
- *test*|*spec*|*fixture*|*__tests__*|*__mocks__*|*.test.*|*.spec.*) continue ;;
188
- esac
189
- case "$file" in
190
- *.ts|*.js|*.tsx|*.jsx|*.py|*.rs|*.go)
191
- if [ -f "$file" ]; then
192
- # Grep for route patterns, then filter out comment lines and description strings
193
- ROUTE_MATCH=$(grep -nE '\\.(get|post|put|patch|delete)\\s*\\(|router\\.|app\\.(get|post|put|delete)|@(Get|Post|Put|Delete)|#\\[actix_web::(get|post)' "$file" 2>/dev/null \\
194
- | grep -v '^\\s*[0-9]*:\\s*//' \\
195
- | grep -v '^\\s*[0-9]*:\\s*\\*' \\
196
- | grep -v '^\\s*[0-9]*:\\s*#' \\
197
- | grep -v '^\\s*[0-9]*:\\s*<!--' \\
198
- | grep -v 'description:' \\
199
- | grep -v 'summary:' \\
200
- | grep -v 'comment:' \\
201
- | grep -v '@example' \\
202
- | grep -v '@see' \\
203
- || true)
204
- if [ -n "$ROUTE_MATCH" ]; then
205
- ROUTE_FILES="$ROUTE_FILES $file"
221
+ _SEV=$(_check_severity "portal-gates" "block")
222
+ if [ "$_SEV" != "off" ]; then
223
+ if [ -f "portal.yaml" ] || echo "$MODIFIED" | grep -q "portal.yaml"; then
224
+ : # portal.yaml exists or was modified \u2014 OK
225
+ else
226
+ # Check if any modified files contain route-like patterns
227
+ # Skip: test/spec/fixture files, markdown, and comment-only matches
228
+ ROUTE_FILES=""
229
+ for file in $MODIFIED; do
230
+ # Skip test, spec, and fixture files entirely
231
+ case "$file" in
232
+ *test*|*spec*|*fixture*|*__tests__*|*__mocks__*|*.test.*|*.spec.*) continue ;;
233
+ esac
234
+ case "$file" in
235
+ *.ts|*.js|*.tsx|*.jsx|*.py|*.rs|*.go)
236
+ if [ -f "$file" ]; then
237
+ # Grep for route patterns, then filter out comment lines and description strings
238
+ ROUTE_MATCH=$(grep -nE '\\.(get|post|put|patch|delete)\\s*\\(|router\\.|app\\.(get|post|put|delete)|@(Get|Post|Put|Delete)|#\\[actix_web::(get|post)' "$file" 2>/dev/null \\
239
+ | grep -v '^\\s*[0-9]*:\\s*//' \\
240
+ | grep -v '^\\s*[0-9]*:\\s*\\*' \\
241
+ | grep -v '^\\s*[0-9]*:\\s*#' \\
242
+ | grep -v '^\\s*[0-9]*:\\s*<!--' \\
243
+ | grep -v 'description:' \\
244
+ | grep -v 'summary:' \\
245
+ | grep -v 'comment:' \\
246
+ | grep -v '@example' \\
247
+ | grep -v '@see' \\
248
+ || true)
249
+ if [ -n "$ROUTE_MATCH" ]; then
250
+ ROUTE_FILES="$ROUTE_FILES $file"
251
+ fi
206
252
  fi
207
- fi
208
- ;;
209
- esac
210
- done
253
+ ;;
254
+ esac
255
+ done
211
256
 
212
- if [ -n "$ROUTE_FILES" ]; then
213
- VIOLATIONS="$VIOLATIONS
257
+ if [ -n "$ROUTE_FILES" ]; then
258
+ if [ "$_SEV" = "block" ]; then
259
+ VIOLATIONS="$VIOLATIONS
214
260
  - Route/endpoint patterns found in modified files but no portal.yaml exists:
215
261
  $ROUTE_FILES
216
262
  Create portal.yaml with gate definitions. Use paradigm_gates_for_route for suggestions."
217
- VIOLATION_COUNT=$((VIOLATION_COUNT + 1))
263
+ VIOLATION_COUNT=$((VIOLATION_COUNT + 1))
264
+ else
265
+ ADVISORY="$ADVISORY
266
+ - (warn) Route/endpoint patterns found without portal.yaml:
267
+ $ROUTE_FILES"
268
+ fi
269
+ fi
218
270
  fi
219
271
  fi
220
272
 
221
273
  # --- Check 4: Aspect anchor files that no longer exist ---
222
- for purpose_file in $PURPOSE_PATHS; do
223
- if grep -q "anchors:" "$purpose_file" 2>/dev/null; then
224
- purpose_dir=$(dirname "$purpose_file")
225
- in_anchors=false
226
- while IFS= read -r line; do
227
- case "$line" in
228
- *"anchors:"*) in_anchors=true; continue ;;
229
- *"- "*)
230
- if [ "$in_anchors" = true ]; then
231
- anchor_path=$(echo "$line" | sed 's/.*- //' | sed 's/:.*//' | tr -d ' ')
232
- if [ -n "$anchor_path" ]; then
233
- # Try relative to .purpose dir first, then project root
234
- if [ ! -f "$purpose_dir/$anchor_path" ] && [ ! -f "./$anchor_path" ]; then
235
- VIOLATIONS="$VIOLATIONS
274
+ _SEV=$(_check_severity "aspect-anchors" "block")
275
+ if [ "$_SEV" != "off" ]; then
276
+ for purpose_file in $PURPOSE_PATHS; do
277
+ if grep -q "anchors:" "$purpose_file" 2>/dev/null; then
278
+ purpose_dir=$(dirname "$purpose_file")
279
+ in_anchors=false
280
+ while IFS= read -r line; do
281
+ case "$line" in
282
+ *"anchors:"*) in_anchors=true; continue ;;
283
+ *"- "*)
284
+ if [ "$in_anchors" = true ]; then
285
+ anchor_path=$(echo "$line" | sed 's/.*- //' | sed 's/:.*//' | tr -d ' ')
286
+ if [ -n "$anchor_path" ]; then
287
+ # Try relative to .purpose dir first, then project root
288
+ if [ ! -f "$purpose_dir/$anchor_path" ] && [ ! -f "./$anchor_path" ]; then
289
+ if [ "$_SEV" = "block" ]; then
290
+ VIOLATIONS="$VIOLATIONS
236
291
  - Aspect anchor '$anchor_path' in $purpose_file does not exist.
237
292
  Update the anchor or remove the stale aspect."
238
- VIOLATION_COUNT=$((VIOLATION_COUNT + 1))
293
+ VIOLATION_COUNT=$((VIOLATION_COUNT + 1))
294
+ else
295
+ ADVISORY="$ADVISORY
296
+ - (warn) Aspect anchor '$anchor_path' in $purpose_file does not exist."
297
+ fi
298
+ fi
239
299
  fi
240
300
  fi
241
- fi
242
- ;;
243
- *) in_anchors=false ;;
244
- esac
245
- done < "$purpose_file"
246
- fi
247
- done
301
+ ;;
302
+ *) in_anchors=false ;;
303
+ esac
304
+ done < "$purpose_file"
305
+ fi
306
+ done
307
+ fi
248
308
 
249
309
  # --- Check 5: Per-directory .purpose freshness ---
250
310
  # Uses .pending-review if available, plus a git-based fallback that cross-references
@@ -328,51 +388,62 @@ for file in $MODIFIED; do
328
388
  fi
329
389
  done
330
390
 
331
- if [ -n "$STALE_PURPOSES" ]; then
332
- VIOLATIONS="$VIOLATIONS
391
+ _SEV=$(_check_severity "purpose-freshness" "warn")
392
+ if [ "$_SEV" != "off" ] && [ -n "$STALE_PURPOSES" ]; then
393
+ if [ "$_SEV" = "block" ]; then
394
+ VIOLATIONS="$VIOLATIONS
333
395
  - These .purpose files cover modified source code but were NOT updated:
334
396
  $STALE_PURPOSES
335
397
  Update each with: #components, ~aspects (with anchors), !signals, \\$flows, ^gates."
336
- VIOLATION_COUNT=$((VIOLATION_COUNT + 1))
398
+ VIOLATION_COUNT=$((VIOLATION_COUNT + 1))
399
+ else
400
+ ADVISORY="$ADVISORY
401
+ - (warn) These .purpose files cover modified source code but were NOT updated:
402
+ $STALE_PURPOSES"
403
+ fi
337
404
  fi
338
405
 
339
406
  # --- Check 6: Aspect coverage advisory ---
340
407
  ADVISORY=""
341
- HAS_ASPECTS=false
342
- for purpose_file in $PURPOSE_PATHS; do
343
- if grep -qE '^\\s*~' "$purpose_file" 2>/dev/null; then
344
- HAS_ASPECTS=true
345
- break
346
- fi
347
- done
348
-
349
- if [ "$HAS_ASPECTS" = true ] && [ "$SOURCE_COUNT" -gt 0 ]; then
350
- ASPECT_UPDATED=false
351
- for file in $MODIFIED; do
352
- case "$file" in
353
- *.purpose)
354
- if grep -qE '^\\s*~|anchors:|applies-to:' "$file" 2>/dev/null; then
355
- ASPECT_UPDATED=true
356
- break
357
- fi
358
- ;;
359
- esac
408
+ _SEV=$(_check_severity "aspect-advisory" "warn")
409
+ if [ "$_SEV" != "off" ]; then
410
+ HAS_ASPECTS=false
411
+ for purpose_file in $PURPOSE_PATHS; do
412
+ if grep -qE '^\\s*~' "$purpose_file" 2>/dev/null; then
413
+ HAS_ASPECTS=true
414
+ break
415
+ fi
360
416
  done
361
417
 
362
- if [ "$ASPECT_UPDATED" = false ]; then
363
- ADVISORY=" This project defines ~aspects with code anchors. Check if existing
418
+ if [ "$HAS_ASPECTS" = true ] && [ "$SOURCE_COUNT" -gt 0 ]; then
419
+ ASPECT_UPDATED=false
420
+ for file in $MODIFIED; do
421
+ case "$file" in
422
+ *.purpose)
423
+ if grep -qE '^\\s*~|anchors:|applies-to:' "$file" 2>/dev/null; then
424
+ ASPECT_UPDATED=true
425
+ break
426
+ fi
427
+ ;;
428
+ esac
429
+ done
430
+
431
+ if [ "$ASPECT_UPDATED" = false ]; then
432
+ ADVISORY=" This project defines ~aspects with code anchors. Check if existing
364
433
  ~aspects need updated anchors or applies-to patterns."
434
+ fi
365
435
  fi
366
436
  fi
367
437
 
368
438
  # --- Check 7: Lore entry expected for significant sessions ---
369
- if [ "$SOURCE_COUNT" -ge 3 ] && [ -d ".paradigm/lore" ]; then
439
+ _SEV=$(_check_severity "lore-required" "block")
440
+ if [ "$_SEV" != "off" ] && [ "$SOURCE_COUNT" -ge 3 ] && [ -d ".paradigm/lore" ]; then
370
441
  LORE_RECORDED=false
371
442
 
372
443
  # Check git diff first (covers staged/committed lore)
373
444
  for file in $MODIFIED; do
374
445
  case "$file" in
375
- .paradigm/lore/entries/*.yaml|.paradigm/lore/entries/*/*.yaml)
446
+ .paradigm/lore/entries/*.yaml|.paradigm/lore/entries/*/*.yaml|.paradigm/lore/entries/*.lore|.paradigm/lore/entries/*/*.lore)
376
447
  LORE_RECORDED=true
377
448
  break
378
449
  ;;
@@ -383,7 +454,7 @@ if [ "$SOURCE_COUNT" -ge 3 ] && [ -d ".paradigm/lore" ]; then
383
454
  if [ "$LORE_RECORDED" = false ]; then
384
455
  TODAY=$(date -u +"%Y-%m-%d")
385
456
  if [ -d ".paradigm/lore/entries/$TODAY" ]; then
386
- ENTRY_COUNT=$(find ".paradigm/lore/entries/$TODAY" -name "*.yaml" 2>/dev/null | head -1)
457
+ ENTRY_COUNT=$(find ".paradigm/lore/entries/$TODAY" \\( -name "*.yaml" -o -name "*.lore" \\) 2>/dev/null | head -1)
387
458
  if [ -n "$ENTRY_COUNT" ]; then
388
459
  LORE_RECORDED=true
389
460
  fi
@@ -424,12 +495,15 @@ LOREEOF
424
495
  AUTO_FIXED="$AUTO_FIXED
425
496
  - Created stub lore entry $LORE_ID (update with real summary)"
426
497
  AUTO_FIX_COUNT=$((AUTO_FIX_COUNT + 1))
427
- else
498
+ elif [ "$_SEV" = "block" ]; then
428
499
  VIOLATIONS="$VIOLATIONS
429
500
  - You modified $SOURCE_COUNT source files but recorded no lore entry.
430
501
  Record your session: paradigm_lore_record (MCP) or paradigm lore record (CLI).
431
502
  Include: type, title, summary, and symbols_touched."
432
503
  VIOLATION_COUNT=$((VIOLATION_COUNT + 1))
504
+ else
505
+ ADVISORY="$ADVISORY
506
+ - (warn) $SOURCE_COUNT source files modified without a lore entry."
433
507
  fi
434
508
  fi
435
509
  fi
@@ -446,17 +520,23 @@ fi
446
520
 
447
521
  if [ -n "$COMPLIANCE_RESULT" ]; then
448
522
  # --- Check 8: Blocking habits (from unified result) ---
449
- # The compliance-check command writes .habits-blocking marker internally
450
- if [ -f ".paradigm/.habits-blocking" ]; then
523
+ _SEV=$(_check_severity "habits-blocking" "block")
524
+ if [ "$_SEV" != "off" ] && [ -f ".paradigm/.habits-blocking" ]; then
451
525
  HABITS_BLOCKING=$(cat ".paradigm/.habits-blocking")
452
- VIOLATIONS="$VIOLATIONS
526
+ if [ "$_SEV" = "block" ]; then
527
+ VIOLATIONS="$VIOLATIONS
453
528
  - Blocking habit(s) not satisfied:
454
529
  $HABITS_BLOCKING
455
530
  Fix: satisfy the habit(s), or change severity to 'warn' in .paradigm/habits.yaml to make advisory."
456
- VIOLATION_COUNT=$((VIOLATION_COUNT + 1))
531
+ VIOLATION_COUNT=$((VIOLATION_COUNT + 1))
532
+ else
533
+ ADVISORY="$ADVISORY
534
+ - (warn) Blocking habit(s) not satisfied: $HABITS_BLOCKING"
535
+ fi
457
536
  fi
458
537
 
459
538
  # --- Check 10: Aspect drift (from unified result) ---
539
+ _SEV=$(_check_severity "drift-detection" "block")
460
540
  DRIFTED_COUNT=$(echo "$COMPLIANCE_RESULT" | grep -o '"driftedCount":[0-9]*' | sed 's/.*://')
461
541
  HEALED_COUNT=$(echo "$COMPLIANCE_RESULT" | grep -o '"healedCount":[0-9]*' | sed 's/.*://')
462
542
 
@@ -464,39 +544,57 @@ if [ -n "$COMPLIANCE_RESULT" ]; then
464
544
  echo "[paradigm] Auto-healed $HEALED_COUNT shifted anchor(s)." >&2
465
545
  fi
466
546
 
467
- if [ -n "$DRIFTED_COUNT" ] && [ "$DRIFTED_COUNT" -gt 0 ] 2>/dev/null; then
468
- VIOLATIONS="$VIOLATIONS
547
+ if [ "$_SEV" != "off" ] && [ -n "$DRIFTED_COUNT" ] && [ "$DRIFTED_COUNT" -gt 0 ] 2>/dev/null; then
548
+ if [ "$_SEV" = "block" ]; then
549
+ VIOLATIONS="$VIOLATIONS
469
550
  - $DRIFTED_COUNT aspect anchor(s) have drifted (content genuinely changed).
470
551
  Run paradigm_aspect_check to review. Update anchors in .purpose files."
471
- VIOLATION_COUNT=$((VIOLATION_COUNT + 1))
552
+ VIOLATION_COUNT=$((VIOLATION_COUNT + 1))
553
+ else
554
+ ADVISORY="$ADVISORY
555
+ - (warn) $DRIFTED_COUNT aspect anchor(s) have drifted."
556
+ fi
472
557
  fi
473
558
 
474
559
  # --- Check 11: Portal gate compliance (from unified result) ---
560
+ _SEV=$(_check_severity "portal-compliance" "block")
475
561
  UNDECLARED=$(echo "$COMPLIANCE_RESULT" | grep -o '"usedButUndeclaredCount":[0-9]*' | sed 's/.*://')
476
562
 
477
- if [ -n "$UNDECLARED" ] && [ "$UNDECLARED" -gt 0 ] 2>/dev/null; then
563
+ if [ "$_SEV" != "off" ] && [ -n "$UNDECLARED" ] && [ "$UNDECLARED" -gt 0 ] 2>/dev/null; then
478
564
  UNDECLARED_LIST=$(echo "$COMPLIANCE_RESULT" | grep -o '"usedButUndeclared":\\[[^]]*\\]' | sed 's/.*\\[//;s/\\].*//;s/"//g')
479
- VIOLATIONS="$VIOLATIONS
565
+ if [ "$_SEV" = "block" ]; then
566
+ VIOLATIONS="$VIOLATIONS
480
567
  - $UNDECLARED gate(s) used in code but not declared in portal.yaml:
481
568
  $UNDECLARED_LIST
482
569
  Add them to portal.yaml or use paradigm_portal_add_gate."
483
- VIOLATION_COUNT=$((VIOLATION_COUNT + 1))
570
+ VIOLATION_COUNT=$((VIOLATION_COUNT + 1))
571
+ else
572
+ ADVISORY="$ADVISORY
573
+ - (warn) $UNDECLARED gate(s) used in code but not declared in portal.yaml: $UNDECLARED_LIST"
574
+ fi
484
575
  fi
485
576
  else
486
577
  # Fallback: check habits blocking marker even if compliance-check unavailable
487
- if [ -f ".paradigm/.habits-blocking" ]; then
578
+ _SEV=$(_check_severity "habits-blocking" "block")
579
+ if [ "$_SEV" != "off" ] && [ -f ".paradigm/.habits-blocking" ]; then
488
580
  HABITS_BLOCKING=$(cat ".paradigm/.habits-blocking")
489
- VIOLATIONS="$VIOLATIONS
581
+ if [ "$_SEV" = "block" ]; then
582
+ VIOLATIONS="$VIOLATIONS
490
583
  - Blocking habit(s) not satisfied:
491
584
  $HABITS_BLOCKING
492
585
  Fix: satisfy the habit(s), or change severity to 'warn' in .paradigm/habits.yaml to make advisory."
493
- VIOLATION_COUNT=$((VIOLATION_COUNT + 1))
586
+ VIOLATION_COUNT=$((VIOLATION_COUNT + 1))
587
+ else
588
+ ADVISORY="$ADVISORY
589
+ - (warn) Blocking habit(s) not satisfied: $HABITS_BLOCKING"
590
+ fi
494
591
  fi
495
592
  fi
496
593
 
497
594
  # --- Check 9: Purpose-required patterns from config.yaml ---
595
+ _SEV=$(_check_severity "purpose-required-patterns" "block")
498
596
  CONFIG_FILE=".paradigm/config.yaml"
499
- if [ -f "$CONFIG_FILE" ]; then
597
+ if [ "$_SEV" != "off" ] && [ -f "$CONFIG_FILE" ]; then
500
598
  MISSING_REQUIRED=""
501
599
  in_section=false
502
600
  current_pattern=""
@@ -582,19 +680,24 @@ PURPOSEEOF
582
680
  - Created stub .purpose in $dir (purpose-required pattern)"
583
681
  AUTO_FIX_COUNT=$((AUTO_FIX_COUNT + 1))
584
682
  done
585
- else
683
+ elif [ "$_SEV" = "block" ]; then
586
684
  VIOLATIONS="$VIOLATIONS
587
685
  - These directories match purpose-required patterns but have no .purpose file:
588
686
  $MISSING_REQUIRED
589
687
  Create .purpose files: paradigm_purpose_init + paradigm_purpose_add_component."
590
688
  VIOLATION_COUNT=$((VIOLATION_COUNT + 1))
689
+ else
690
+ ADVISORY="$ADVISORY
691
+ - (warn) Directories matching purpose-required patterns without .purpose file:
692
+ $MISSING_REQUIRED"
591
693
  fi
592
694
  fi
593
695
  fi
594
696
 
595
697
  # --- Check 12: Graduation failure tracking ---
596
698
  # When violations occur for graduated habits, record failures for auto-demotion.
597
- if [ "$VIOLATION_COUNT" -gt 0 ] && [ -f ".paradigm/graduation.yaml" ]; then
699
+ _SEV=$(_check_severity "graduation-tracking" "warn")
700
+ if [ "$_SEV" != "off" ] && [ "$VIOLATION_COUNT" -gt 0 ] && [ -f ".paradigm/graduation.yaml" ]; then
598
701
  GRAD_FAILURES_DIR=".paradigm/.graduation-failures"
599
702
  mkdir -p "$GRAD_FAILURES_DIR" 2>/dev/null
600
703
 
@@ -639,6 +742,81 @@ if [ "$VIOLATION_COUNT" -gt 0 ] && [ -f ".paradigm/graduation.yaml" ]; then
639
742
  fi
640
743
  done
641
744
  fi
745
+
746
+ # --- Check 13: Orchestration required for complex tasks (magnitude-based) ---
747
+ _SEV=$(_check_severity "orchestration-required" "warn")
748
+ if [ "$_SEV" != "off" ]; then
749
+ # Compute magnitude score from multiple signals
750
+ MAGNITUDE=0
751
+ MAGNITUDE_REASONS=""
752
+
753
+ # Signal 1: Source files modified (1 point each)
754
+ MAGNITUDE=$((MAGNITUDE + SOURCE_COUNT))
755
+ [ "$SOURCE_COUNT" -gt 0 ] && MAGNITUDE_REASONS="$SOURCE_COUNT source files"
756
+
757
+ # Signal 2: Cross-package changes (2 points \u2014 different packages/ dirs)
758
+ CROSS_PKG_COUNT=0
759
+ SEEN_PKGS=""
760
+ for file in $MODIFIED; do
761
+ case "$file" in
762
+ packages/*)
763
+ _pkg=$(echo "$file" | cut -d'/' -f2)
764
+ case "$SEEN_PKGS" in
765
+ *"|$_pkg|"*) ;;
766
+ *)
767
+ SEEN_PKGS="$SEEN_PKGS|$_pkg|"
768
+ CROSS_PKG_COUNT=$((CROSS_PKG_COUNT + 1))
769
+ ;;
770
+ esac
771
+ ;;
772
+ esac
773
+ done
774
+ if [ "$CROSS_PKG_COUNT" -ge 2 ]; then
775
+ MAGNITUDE=$((MAGNITUDE + 2))
776
+ MAGNITUDE_REASONS="$MAGNITUDE_REASONS, $CROSS_PKG_COUNT packages"
777
+ fi
778
+
779
+ # Signal 3: Security-adjacent files (2 points each)
780
+ SEC_ADJACENT=0
781
+ for file in $MODIFIED; do
782
+ case "$file" in
783
+ portal.yaml|*/portal.yaml) SEC_ADJACENT=$((SEC_ADJACENT + 1)) ;;
784
+ *auth*|*permission*|*gate*|*security*|*token*|*session*) SEC_ADJACENT=$((SEC_ADJACENT + 1)) ;;
785
+ esac
786
+ done
787
+ if [ "$SEC_ADJACENT" -gt 0 ]; then
788
+ MAGNITUDE=$((MAGNITUDE + SEC_ADJACENT * 2))
789
+ MAGNITUDE_REASONS="$MAGNITUDE_REASONS, $SEC_ADJACENT security-adjacent"
790
+ fi
791
+
792
+ # Signal 4: Symbol-bearing files (1 point if .purpose files were changed alongside source)
793
+ SYMBOL_FILES=0
794
+ for file in $MODIFIED; do
795
+ case "$file" in
796
+ *.purpose) SYMBOL_FILES=$((SYMBOL_FILES + 1)) ;;
797
+ esac
798
+ done
799
+ if [ "$SYMBOL_FILES" -ge 2 ]; then
800
+ MAGNITUDE=$((MAGNITUDE + 1))
801
+ MAGNITUDE_REASONS="$MAGNITUDE_REASONS, $SYMBOL_FILES .purpose files"
802
+ fi
803
+
804
+ # Compare magnitude against threshold (default 3)
805
+ if [ "$MAGNITUDE" -ge "$ORCH_THRESHOLD" ]; then
806
+ if [ ! -f ".paradigm/.orchestrated" ]; then
807
+ if [ "$_SEV" = "block" ]; then
808
+ VIOLATIONS="$VIOLATIONS
809
+ - Task magnitude $MAGNITUDE >= $ORCH_THRESHOLD without orchestration ($MAGNITUDE_REASONS).
810
+ Run paradigm_orchestrate_inline mode=\\"quick\\" for fast pre-check.
811
+ Override: paradigm enforcement override orchestration-required warn"
812
+ VIOLATION_COUNT=$((VIOLATION_COUNT + 1))
813
+ else
814
+ ADVISORY="$ADVISORY
815
+ - (orchestration) Magnitude $MAGNITUDE ($MAGNITUDE_REASONS) without team orchestration."
816
+ fi
817
+ fi
818
+ fi
819
+ fi
642
820
  `,R=`#!/bin/sh
643
821
  # Paradigm Claude Code Stop Hook (v2)
644
822
  # Validates paradigm compliance before allowing the agent to finish.
@@ -647,7 +825,7 @@ fi
647
825
  # Hook type: Stop
648
826
  # Exit 0 = allow, Exit 2 = block with message
649
827
  #
650
- # Checks 1\u201311 are defined in paradigm-common.sh (shared with Cursor hook).
828
+ # Checks 1\u201313 are defined in paradigm-common.sh (shared with Cursor hook).
651
829
 
652
830
  # Read JSON from stdin (hook input)
653
831
  INPUT=$(cat)
@@ -747,13 +925,14 @@ rm -f ".paradigm/.pending-review"
747
925
  rm -f ".paradigm/.habits-blocking"
748
926
  rm -f ".paradigm/.session-started"
749
927
  rm -f ".paradigm/.purpose-paths"
928
+ rm -f ".paradigm/.orchestrated"
750
929
 
751
930
  exit 0
752
- `,U=`#!/bin/sh
931
+ `,A=`#!/bin/sh
753
932
  # Legacy afterFileEdit hook \u2014 replaced by paradigm-posttooluse.sh (postToolUse)
754
933
  # Kept as a no-op because Claude Code expects the file to exist.
755
934
  exit 0
756
- `,A=`#!/bin/sh
935
+ `,U=`#!/bin/sh
757
936
  # Paradigm Claude Code Pre-Commit Hook
758
937
  # Intercepts git commit Bash calls and auto-rebuilds the index.
759
938
  # Installed by: paradigm hooks install --claude-code
@@ -798,7 +977,7 @@ done
798
977
 
799
978
  # Never block \u2014 exit 0
800
979
  exit 0
801
- `,P=`#!/bin/sh
980
+ `,D=`#!/bin/sh
802
981
  # Paradigm Cursor Session Start Hook
803
982
  # Fires before the agent does anything \u2014 injects additional_context
804
983
  # that acts as a deterministic system prompt (not subject to context compaction).
@@ -898,7 +1077,7 @@ fi
898
1077
  printf '{"additional_context":"%s","continue":true}\\n' "$CONTEXT"
899
1078
 
900
1079
  exit 0
901
- `,v=`#!/bin/sh
1080
+ `,P=`#!/bin/sh
902
1081
  # Paradigm Cursor Stop Hook (v2)
903
1082
  # Validates paradigm compliance before allowing the agent to finish.
904
1083
  # Installed by: paradigm hooks install --cursor
@@ -906,7 +1085,7 @@ exit 0
906
1085
  # Hook type: stop
907
1086
  # Exit 0 = allow, Exit 2 = block with message
908
1087
  #
909
- # Checks 1\u201311 are defined in paradigm-common.sh (shared with Claude Code hook).
1088
+ # Checks 1\u201313 are defined in paradigm-common.sh (shared with Claude Code hook).
910
1089
 
911
1090
  # Read JSON from stdin (hook input)
912
1091
  INPUT=$(cat)
@@ -1028,9 +1207,10 @@ rm -f ".paradigm/.habits-blocking"
1028
1207
  rm -f ".paradigm/.stop-hook-active"
1029
1208
  rm -f ".paradigm/.session-started"
1030
1209
  rm -f ".paradigm/.purpose-paths"
1210
+ rm -f ".paradigm/.orchestrated"
1031
1211
 
1032
1212
  exit 0
1033
- `,D=`#!/bin/sh
1213
+ `,v=`#!/bin/sh
1034
1214
  # Legacy afterFileEdit hook \u2014 replaced by paradigm-posttooluse.sh (postToolUse)
1035
1215
  # Kept as a no-op because Cursor expects the file to exist.
1036
1216
  exit 0
@@ -1348,9 +1528,9 @@ if [ "$PENDING_COUNT" -ge 30 ]; then
1348
1528
  fi
1349
1529
 
1350
1530
  exit 0
1351
- `;function x(){try{let i=r.join(E.homedir(),".claude","settings.json");if(!e.existsSync(i))return {active:!1};if(!JSON.parse(e.readFileSync(i,"utf8")).enabledPlugins?.["paradigm@a-paradigm"])return {active:!1};let d=r.join(E.homedir(),".claude","plugins","cache","a-paradigm","paradigm");if(!e.existsSync(d))return {active:!1};let a=e.readdirSync(d).filter(s=>e.statSync(r.join(d,s)).isDirectory()).sort().reverse();if(a.length===0)return {active:!1};let p=r.join(d,a[0]),l=r.join(p,"hooks","hooks.json");return e.existsSync(l)?{active:!0,cacheVersion:a[0]}:{active:!1}}catch{return {active:false}}}function X(){try{let i=x();if(!i.active||!i.cacheVersion)return {compatible:!0};let h=r.join(E.homedir(),".claude","plugins","cache","a-paradigm","paradigm",i.cacheVersion,"hooks.json");if(!e.existsSync(h))return {compatible:!0};let d=JSON.parse(e.readFileSync(h,"utf8")).compatibleVersions;if(!d)return {compatible:!0};let a=W();if(!a)return {compatible:!0};let p=d.split(/\s+/);for(let l of p){let s=l.match(/^(>=?|<=?)\s*(\d+\.\d+\.\d+)/);if(!s)continue;let[,t,n]=s,f=Y(a,n);if(t===">="&&f<0)return {compatible:!1,message:`Plugin requires paradigm ${d}, current: ${a}`};if(t===">"&&f<=0)return {compatible:!1,message:`Plugin requires paradigm ${d}, current: ${a}`};if(t==="<="&&f>0)return {compatible:!1,message:`Plugin requires paradigm ${d}, current: ${a}`};if(t==="<"&&f>=0)return {compatible:!1,message:`Plugin requires paradigm ${d}, current: ${a}`}}return {compatible:!0}}catch{return {compatible:true}}}function W(){try{let i=r.join(r.dirname(new URL(import.meta.url).pathname),"..","..","package.json");return JSON.parse(e.readFileSync(i,"utf8")).version||null}catch{return null}}function Y(i,h){let c=i.split(".").map(Number),d=h.split(".").map(Number);for(let a=0;a<3;a++){if((c[a]||0)<(d[a]||0))return -1;if((c[a]||0)>(d[a]||0))return 1}return 0}function J(i){let h=[],c=r.join(i,".claude","hooks");if(e.existsSync(c)){for(let a of ["paradigm-common.sh","paradigm-stop.sh","paradigm-precommit.sh","paradigm-postwrite.sh"]){let p=r.join(c,a);e.existsSync(p)&&(e.unlinkSync(p),h.push(a));}try{e.readdirSync(c).length===0&&e.rmdirSync(c);}catch{}}let d=r.join(i,".claude","settings.json");if(e.existsSync(d))try{let a=JSON.parse(e.readFileSync(d,"utf8")),p=a.hooks;if(p){let l=!1;for(let[s,t]of Object.entries(p)){if(!Array.isArray(t))continue;let n=t.filter(f=>!JSON.stringify(f).includes("paradigm-"));n.length!==t.length&&(l=!0,n.length===0?delete p[s]:p[s]=n);}l&&(Object.keys(p).length===0?delete a.hooks:a.hooks=p,e.writeFileSync(d,JSON.stringify(a,null,2)+`
1531
+ `;function x(){try{let i=r.join(E.homedir(),".claude","settings.json");if(!e.existsSync(i))return {active:!1};if(!JSON.parse(e.readFileSync(i,"utf8")).enabledPlugins?.["paradigm@a-paradigm"])return {active:!1};let d=r.join(E.homedir(),".claude","plugins","cache","a-paradigm","paradigm");if(!e.existsSync(d))return {active:!1};let a=e.readdirSync(d).filter(s=>e.statSync(r.join(d,s)).isDirectory()).sort().reverse();if(a.length===0)return {active:!1};let p=r.join(d,a[0]),l=r.join(p,"hooks","hooks.json");return e.existsSync(l)?{active:!0,cacheVersion:a[0]}:{active:!1}}catch{return {active:false}}}function Y(){try{let i=x();if(!i.active||!i.cacheVersion)return {compatible:!0};let h=r.join(E.homedir(),".claude","plugins","cache","a-paradigm","paradigm",i.cacheVersion,"hooks.json");if(!e.existsSync(h))return {compatible:!0};let d=JSON.parse(e.readFileSync(h,"utf8")).compatibleVersions;if(!d)return {compatible:!0};let a=X();if(!a)return {compatible:!0};let p=d.split(/\s+/);for(let l of p){let s=l.match(/^(>=?|<=?)\s*(\d+\.\d+\.\d+)/);if(!s)continue;let[,t,n]=s,f=W(a,n);if(t===">="&&f<0)return {compatible:!1,message:`Plugin requires paradigm ${d}, current: ${a}`};if(t===">"&&f<=0)return {compatible:!1,message:`Plugin requires paradigm ${d}, current: ${a}`};if(t==="<="&&f>0)return {compatible:!1,message:`Plugin requires paradigm ${d}, current: ${a}`};if(t==="<"&&f>=0)return {compatible:!1,message:`Plugin requires paradigm ${d}, current: ${a}`}}return {compatible:!0}}catch{return {compatible:true}}}function X(){try{let i=r.join(r.dirname(new URL(import.meta.url).pathname),"..","..","package.json");return JSON.parse(e.readFileSync(i,"utf8")).version||null}catch{return null}}function W(i,h){let c=i.split(".").map(Number),d=h.split(".").map(Number);for(let a=0;a<3;a++){if((c[a]||0)<(d[a]||0))return -1;if((c[a]||0)>(d[a]||0))return 1}return 0}function J(i){let h=[],c=r.join(i,".claude","hooks");if(e.existsSync(c)){for(let a of ["paradigm-common.sh","paradigm-stop.sh","paradigm-precommit.sh","paradigm-postwrite.sh"]){let p=r.join(c,a);e.existsSync(p)&&(e.unlinkSync(p),h.push(a));}try{e.readdirSync(c).length===0&&e.rmdirSync(c);}catch{}}let d=r.join(i,".claude","settings.json");if(e.existsSync(d))try{let a=JSON.parse(e.readFileSync(d,"utf8")),p=a.hooks;if(p){let l=!1;for(let[s,t]of Object.entries(p)){if(!Array.isArray(t))continue;let n=t.filter(f=>!JSON.stringify(f).includes("paradigm-"));n.length!==t.length&&(l=!0,n.length===0?delete p[s]:p[s]=n);}l&&(Object.keys(p).length===0?delete a.hooks:a.hooks=p,e.writeFileSync(d,JSON.stringify(a,null,2)+`
1352
1532
  `,"utf8"),h.push("settings.json hooks"));}}catch{}return {cleaned:h.length>0,removed:h}}function q(i,h){try{let c=r.join(E.tmpdir(),`paradigm-hook-validate-${Date.now()}.sh`);e.writeFileSync(c,i,"utf8");try{return execSync(`bash -n "${c}" 2>&1`,{encoding:"utf-8"}),null}catch(d){return `${h}: bash syntax error \u2014 ${d.message?.split(`
1353
- `)[0]||"unknown error"}`}finally{try{e.unlinkSync(c);}catch{}}}catch{return null}}var H=`#!/bin/sh
1533
+ `)[0]||"unknown error"}`}finally{try{e.unlinkSync(c);}catch{}}}catch{return null}}var F=`#!/bin/sh
1354
1534
  # Paradigm post-commit hook - captures history from commits
1355
1535
  # Installed by: paradigm hooks install
1356
1536
 
@@ -1434,7 +1614,7 @@ if [ -n "$SYMBOLS" ] && [ -d ".paradigm/history" ]; then
1434
1614
 
1435
1615
  echo "[paradigm] History entry $ID recorded"
1436
1616
  fi
1437
- `,j=`#!/bin/sh
1617
+ `,V=`#!/bin/sh
1438
1618
  # Paradigm pre-push hook - reindex history before pushing
1439
1619
  # Installed by: paradigm hooks install
1440
1620
 
@@ -1444,12 +1624,12 @@ if [ -d ".paradigm/history" ] && [ -f ".paradigm/history/log.jsonl" ]; then
1444
1624
  fi
1445
1625
  `;async function te(i={}){let h=process.cwd(),c=i.dryRun||false;c&&console.log(o.cyan(`
1446
1626
  [dry-run] Showing what would be installed:
1447
- `));let d=i.claudeCode&&!i.postCommit&&!i.prePush&&!i.cursor,a=i.cursor&&!i.postCommit&&!i.prePush&&!i.claudeCode;if(!c){let s=[{name:"post-commit",content:H},{name:"pre-push",content:j},{name:"paradigm-common",content:y},{name:"claude-code-stop",content:R},{name:"claude-code-precommit",content:A},{name:"claude-code-postwrite",content:U},{name:"cursor-session-start",content:P},{name:"cursor-stop",content:v},{name:"cursor-precommit",content:b},{name:"cursor-postwrite",content:D},{name:"cursor-pretooluse",content:L},{name:"cursor-posttooluse",content:w}];for(let t of s){let n=q(t.content,t.name);if(n){console.log(o.red(`Hook syntax error: ${n}`)),console.log(o.gray("Aborting installation. Fix the hook script and try again."));return}}}let p=X();if(p.compatible||(console.log(o.yellow(`
1627
+ `));let d=i.claudeCode&&!i.postCommit&&!i.prePush&&!i.cursor,a=i.cursor&&!i.postCommit&&!i.prePush&&!i.claudeCode;if(!c){let s=[{name:"post-commit",content:F},{name:"pre-push",content:V},{name:"paradigm-common",content:N},{name:"claude-code-stop",content:R},{name:"claude-code-precommit",content:U},{name:"claude-code-postwrite",content:A},{name:"cursor-session-start",content:D},{name:"cursor-stop",content:P},{name:"cursor-precommit",content:b},{name:"cursor-postwrite",content:v},{name:"cursor-pretooluse",content:L},{name:"cursor-posttooluse",content:w}];for(let t of s){let n=q(t.content,t.name);if(n){console.log(o.red(`Hook syntax error: ${n}`)),console.log(o.gray("Aborting installation. Fix the hook script and try again."));return}}}let p=Y();if(p.compatible||(console.log(o.yellow(`
1448
1628
  \u26A0 ${p.message}`)),console.log(o.gray(` Hook installation will continue, but behavior may differ from plugin expectations.
1449
- `))),!d&&!a){let s=r.join(h,".git");if(!e.existsSync(s)){console.log(o.red("Not a git repository."));return}let t=r.join(s,"hooks"),n=!i.postCommit&&!i.prePush&&!i.claudeCode,f=[];if(n||i.postCommit){let u=r.join(t,"post-commit");if(c){let g=e.existsSync(u)&&!i.force?"skip (exists)":"install";console.log(o.gray(` post-commit: ${g} \u2192 ${u}`));}else e.existsSync(u)&&!i.force?e.readFileSync(u,"utf8").includes("paradigm")?console.log(o.gray("post-commit hook already installed by paradigm")):console.log(o.yellow("post-commit hook exists. Use --force to overwrite.")):(e.mkdirSync(t,{recursive:true}),e.writeFileSync(u,H),e.chmodSync(u,"755"),f.push("post-commit"));}if(n||i.prePush){let u=r.join(t,"pre-push");if(c){let g=e.existsSync(u)&&!i.force?"skip (exists)":"install";console.log(o.gray(` pre-push: ${g} \u2192 ${u}`));}else e.existsSync(u)&&!i.force?e.readFileSync(u,"utf8").includes("paradigm")?console.log(o.gray("pre-push hook already installed by paradigm")):console.log(o.yellow("pre-push hook exists. Use --force to overwrite.")):(e.mkdirSync(t,{recursive:true}),e.writeFileSync(u,j),e.chmodSync(u,"755"),f.push("pre-push"));}!c&&f.length>0&&console.log(o.green(`Git hooks installed: ${f.join(", ")}`));let _=r.join(h,".paradigm/history");!e.existsSync(_)&&!c&&console.log(o.gray("Tip: Run `paradigm history init` to initialize history tracking"));}let l=!i.postCommit&&!i.prePush&&!i.claudeCode&&!i.cursor;(l||i.claudeCode)&&(c?(console.log(o.gray(" Claude Code hooks: would install paradigm-stop.sh, paradigm-precommit.sh, paradigm-postwrite.sh")),console.log(o.gray(` \u2192 ${r.join(h,".claude","hooks")}/`)),console.log(o.gray(" \u2192 Update .claude/settings.json with hook configuration"))):await B(h,i.force)),(l||i.cursor)&&(c?(console.log(o.gray(" Cursor hooks: would install paradigm-session-start.sh, paradigm-stop.sh, paradigm-precommit.sh, paradigm-postwrite.sh, paradigm-pretooluse.sh, paradigm-posttooluse.sh")),console.log(o.gray(` \u2192 ${r.join(h,".cursor","hooks")}/`)),console.log(o.gray(" \u2192 Update .cursor/hooks.json"))):await K(h,i.force)),c&&console.log(o.cyan(`
1629
+ `))),!d&&!a){let s=r.join(h,".git");if(!e.existsSync(s)){console.log(o.red("Not a git repository."));return}let t=r.join(s,"hooks"),n=!i.postCommit&&!i.prePush&&!i.claudeCode,f=[];if(n||i.postCommit){let u=r.join(t,"post-commit");if(c){let g=e.existsSync(u)&&!i.force?"skip (exists)":"install";console.log(o.gray(` post-commit: ${g} \u2192 ${u}`));}else e.existsSync(u)&&!i.force?e.readFileSync(u,"utf8").includes("paradigm")?console.log(o.gray("post-commit hook already installed by paradigm")):console.log(o.yellow("post-commit hook exists. Use --force to overwrite.")):(e.mkdirSync(t,{recursive:true}),e.writeFileSync(u,F),e.chmodSync(u,"755"),f.push("post-commit"));}if(n||i.prePush){let u=r.join(t,"pre-push");if(c){let g=e.existsSync(u)&&!i.force?"skip (exists)":"install";console.log(o.gray(` pre-push: ${g} \u2192 ${u}`));}else e.existsSync(u)&&!i.force?e.readFileSync(u,"utf8").includes("paradigm")?console.log(o.gray("pre-push hook already installed by paradigm")):console.log(o.yellow("pre-push hook exists. Use --force to overwrite.")):(e.mkdirSync(t,{recursive:true}),e.writeFileSync(u,V),e.chmodSync(u,"755"),f.push("pre-push"));}!c&&f.length>0&&console.log(o.green(`Git hooks installed: ${f.join(", ")}`));let O=r.join(h,".paradigm/history");!e.existsSync(O)&&!c&&console.log(o.gray("Tip: Run `paradigm history init` to initialize history tracking"));}let l=!i.postCommit&&!i.prePush&&!i.claudeCode&&!i.cursor;(l||i.claudeCode)&&(c?(console.log(o.gray(" Claude Code hooks: would install paradigm-stop.sh, paradigm-precommit.sh, paradigm-postwrite.sh")),console.log(o.gray(` \u2192 ${r.join(h,".claude","hooks")}/`)),console.log(o.gray(" \u2192 Update .claude/settings.json with hook configuration"))):await B(h,i.force)),(l||i.cursor)&&(c?(console.log(o.gray(" Cursor hooks: would install paradigm-session-start.sh, paradigm-stop.sh, paradigm-precommit.sh, paradigm-postwrite.sh, paradigm-pretooluse.sh, paradigm-posttooluse.sh")),console.log(o.gray(` \u2192 ${r.join(h,".cursor","hooks")}/`)),console.log(o.gray(" \u2192 Update .cursor/hooks.json"))):await K(h,i.force)),c&&console.log(o.cyan(`
1450
1630
  [dry-run] No changes made.
1451
- `));}async function B(i,h){let c=x();if(c.active){console.log(o.cyan(` Paradigm plugin v${c.cacheVersion} is active \u2014 hooks are managed by the plugin.`));let{cleaned:O,removed:$}=J(i);console.log(O?o.green(` Cleaned up stale project hooks: ${$.join(", ")}`):o.gray(" No stale project hooks to clean up.")),console.log(o.gray(" Plugin hooks auto-update with each session \u2014 no manual install needed."));return}let d=r.join(i,".claude","hooks");e.mkdirSync(d,{recursive:true});let a=[],p=r.join(d,"paradigm-common.sh");e.writeFileSync(p,y,"utf8"),e.chmodSync(p,"755");let l=[{name:"paradigm-stop.sh",content:R},{name:"paradigm-precommit.sh",content:A},{name:"paradigm-postwrite.sh",content:U}];for(let O of l){let $=r.join(d,O.name);if(e.existsSync($)&&!h){console.log(o.gray(` ${O.name}: already installed`));continue}e.writeFileSync($,O.content,"utf8"),e.chmodSync($,"755"),a.push(O.name);}let s=r.join(i,".claude","settings.json"),t={};if(e.existsSync(s))try{t=JSON.parse(e.readFileSync(s,"utf8"));}catch{}let n=t.hooks||{},f={hooks:[{type:"command",command:'bash "$CLAUDE_PROJECT_DIR/.claude/hooks/paradigm-stop.sh"',timeout:10}]},_={matcher:"Bash",hooks:[{type:"command",command:'bash "$CLAUDE_PROJECT_DIR/.claude/hooks/paradigm-precommit.sh"',timeout:30}]},u=n.Stop||[];u.some(O=>JSON.stringify(O).includes("paradigm-stop.sh"))||u.push(f),n.Stop=u;let S=n.PreToolUse||[];S.some(O=>JSON.stringify(O).includes("paradigm-precommit.sh"))||S.push(_),n.PreToolUse=S;let F={matcher:"Edit,Write",hooks:[{type:"command",command:'bash "$CLAUDE_PROJECT_DIR/.claude/hooks/paradigm-postwrite.sh"',timeout:5}]},T=n.PostToolUse||[];T.some(O=>JSON.stringify(O).includes("paradigm-postwrite.sh"))||T.push(F),n.PostToolUse=T,t.hooks=n,e.writeFileSync(s,JSON.stringify(t,null,2)+`
1452
- `,"utf8"),a.length>0&&console.log(o.green(`Claude Code hooks installed: ${a.join(", ")}`)),console.log(o.green("Claude Code settings.json updated with hook configuration"));}async function K(i,h){let c=r.join(i,".cursor","hooks");e.mkdirSync(c,{recursive:true});let d=[],a=r.join(c,"paradigm-common.sh");e.writeFileSync(a,y,"utf8"),e.chmodSync(a,"755");let p=[{name:"paradigm-session-start.sh",content:P},{name:"paradigm-stop.sh",content:v},{name:"paradigm-precommit.sh",content:b},{name:"paradigm-postwrite.sh",content:D},{name:"paradigm-pretooluse.sh",content:L},{name:"paradigm-posttooluse.sh",content:w}];for(let m of p){let k=r.join(c,m.name);if(e.existsSync(k)&&!h){console.log(o.gray(` ${m.name}: already installed (Cursor)`));continue}e.writeFileSync(k,m.content,"utf8"),e.chmodSync(k,"755"),d.push(m.name);}let l=r.join(i,".cursor","hooks.json"),s={};if(e.existsSync(l))try{s=JSON.parse(e.readFileSync(l,"utf8"));}catch{}s.version=1;let t=s.hooks||{},n={command:".cursor/hooks/paradigm-session-start.sh",timeout:5},f={command:".cursor/hooks/paradigm-stop.sh",timeout:10,loop_limit:3},_={command:".cursor/hooks/paradigm-postwrite.sh",timeout:5},u={command:".cursor/hooks/paradigm-precommit.sh",matcher:"git commit",timeout:30},g=t.sessionStart||[];g.some(m=>JSON.stringify(m).includes("paradigm-session-start.sh"))||g.push(n),t.sessionStart=g;let I=t.stop||[];I.some(m=>JSON.stringify(m).includes("paradigm-stop.sh"))||I.push(f),t.stop=I;let T=t.afterFileEdit||[];T.some(m=>JSON.stringify(m).includes("paradigm-postwrite.sh"))||T.push(_),t.afterFileEdit=T;let O={command:".cursor/hooks/paradigm-pretooluse.sh",matcher:"Edit|Write",timeout:5},$=t.preToolUse||[];$.some(m=>JSON.stringify(m).includes("paradigm-pretooluse.sh"))||$.push(O),t.preToolUse=$;let V={command:".cursor/hooks/paradigm-posttooluse.sh",matcher:"Edit|Write",timeout:5},C=t.postToolUse||[];C.some(m=>JSON.stringify(m).includes("paradigm-posttooluse.sh"))||C.push(V),t.postToolUse=C;let N=t.beforeShellExecution||[];N.some(m=>JSON.stringify(m).includes("paradigm-precommit.sh"))||N.push(u),t.beforeShellExecution=N,s.hooks=t,e.writeFileSync(l,JSON.stringify(s,null,2)+`
1631
+ `));}async function B(i,h){let c=x();if(c.active){console.log(o.cyan(` Paradigm plugin v${c.cacheVersion} is active \u2014 hooks are managed by the plugin.`));let{cleaned:_,removed:$}=J(i);console.log(_?o.green(` Cleaned up stale project hooks: ${$.join(", ")}`):o.gray(" No stale project hooks to clean up.")),console.log(o.gray(" Plugin hooks auto-update with each session \u2014 no manual install needed."));return}let d=r.join(i,".claude","hooks");e.mkdirSync(d,{recursive:true});let a=[],p=r.join(d,"paradigm-common.sh");e.writeFileSync(p,N,"utf8"),e.chmodSync(p,"755");let l=[{name:"paradigm-stop.sh",content:R},{name:"paradigm-precommit.sh",content:U},{name:"paradigm-postwrite.sh",content:A}];for(let _ of l){let $=r.join(d,_.name);if(e.existsSync($)&&!h){console.log(o.gray(` ${_.name}: already installed`));continue}e.writeFileSync($,_.content,"utf8"),e.chmodSync($,"755"),a.push(_.name);}let s=r.join(i,".claude","settings.json"),t={};if(e.existsSync(s))try{t=JSON.parse(e.readFileSync(s,"utf8"));}catch{}let n=t.hooks||{},f={hooks:[{type:"command",command:'bash "$CLAUDE_PROJECT_DIR/.claude/hooks/paradigm-stop.sh"',timeout:10}]},O={matcher:"Bash",hooks:[{type:"command",command:'bash "$CLAUDE_PROJECT_DIR/.claude/hooks/paradigm-precommit.sh"',timeout:30}]},u=n.Stop||[];u.some(_=>JSON.stringify(_).includes("paradigm-stop.sh"))||u.push(f),n.Stop=u;let T=n.PreToolUse||[];T.some(_=>JSON.stringify(_).includes("paradigm-precommit.sh"))||T.push(O),n.PreToolUse=T;let M={matcher:"Edit,Write",hooks:[{type:"command",command:'bash "$CLAUDE_PROJECT_DIR/.claude/hooks/paradigm-postwrite.sh"',timeout:5}]},S=n.PostToolUse||[];S.some(_=>JSON.stringify(_).includes("paradigm-postwrite.sh"))||S.push(M),n.PostToolUse=S,t.hooks=n,e.writeFileSync(s,JSON.stringify(t,null,2)+`
1632
+ `,"utf8"),a.length>0&&console.log(o.green(`Claude Code hooks installed: ${a.join(", ")}`)),console.log(o.green("Claude Code settings.json updated with hook configuration"));}async function K(i,h){let c=r.join(i,".cursor","hooks");e.mkdirSync(c,{recursive:true});let d=[],a=r.join(c,"paradigm-common.sh");e.writeFileSync(a,N,"utf8"),e.chmodSync(a,"755");let p=[{name:"paradigm-session-start.sh",content:D},{name:"paradigm-stop.sh",content:P},{name:"paradigm-precommit.sh",content:b},{name:"paradigm-postwrite.sh",content:v},{name:"paradigm-pretooluse.sh",content:L},{name:"paradigm-posttooluse.sh",content:w}];for(let m of p){let k=r.join(c,m.name);if(e.existsSync(k)&&!h){console.log(o.gray(` ${m.name}: already installed (Cursor)`));continue}e.writeFileSync(k,m.content,"utf8"),e.chmodSync(k,"755"),d.push(m.name);}let l=r.join(i,".cursor","hooks.json"),s={};if(e.existsSync(l))try{s=JSON.parse(e.readFileSync(l,"utf8"));}catch{}s.version=1;let t=s.hooks||{},n={command:".cursor/hooks/paradigm-session-start.sh",timeout:5},f={command:".cursor/hooks/paradigm-stop.sh",timeout:10,loop_limit:3},O={command:".cursor/hooks/paradigm-postwrite.sh",timeout:5},u={command:".cursor/hooks/paradigm-precommit.sh",matcher:"git commit",timeout:30},g=t.sessionStart||[];g.some(m=>JSON.stringify(m).includes("paradigm-session-start.sh"))||g.push(n),t.sessionStart=g;let I=t.stop||[];I.some(m=>JSON.stringify(m).includes("paradigm-stop.sh"))||I.push(f),t.stop=I;let S=t.afterFileEdit||[];S.some(m=>JSON.stringify(m).includes("paradigm-postwrite.sh"))||S.push(O),t.afterFileEdit=S;let _={command:".cursor/hooks/paradigm-pretooluse.sh",matcher:"Edit|Write",timeout:5},$=t.preToolUse||[];$.some(m=>JSON.stringify(m).includes("paradigm-pretooluse.sh"))||$.push(_),t.preToolUse=$;let j={command:".cursor/hooks/paradigm-posttooluse.sh",matcher:"Edit|Write",timeout:5},C=t.postToolUse||[];C.some(m=>JSON.stringify(m).includes("paradigm-posttooluse.sh"))||C.push(j),t.postToolUse=C;let y=t.beforeShellExecution||[];y.some(m=>JSON.stringify(m).includes("paradigm-precommit.sh"))||y.push(u),t.beforeShellExecution=y,s.hooks=t,e.writeFileSync(l,JSON.stringify(s,null,2)+`
1453
1633
  `,"utf8"),d.length>0&&console.log(o.green(`Cursor hooks installed: ${d.join(", ")}`)),console.log(o.green("Cursor hooks.json updated with hook configuration"));}async function re(i={}){let h=process.cwd(),c=i.dryRun||false;if(c&&console.log(o.cyan(`
1454
1634
  [dry-run] Showing what would be removed:
1455
1635
  `)),!i.cursor){let d=r.join(h,".git");if(!e.existsSync(d)){console.log(o.red("Not a git repository."));return}let a=r.join(d,"hooks"),p=[];for(let l of ["post-commit","pre-push"]){let s=r.join(a,l);e.existsSync(s)&&e.readFileSync(s,"utf8").includes("paradigm")&&(c?console.log(o.gray(` Would remove: ${s}`)):e.unlinkSync(s),p.push(l));}c?p.length===0&&console.log(o.gray(" No paradigm git hooks to remove")):p.length>0?console.log(o.green(`Git hooks removed: ${p.join(", ")}`)):console.log(o.gray("No paradigm git hooks found to remove"));}if(i.cursor){let d=r.join(h,".cursor","hooks"),a=[];for(let l of ["paradigm-session-start.sh","paradigm-stop.sh","paradigm-precommit.sh","paradigm-postwrite.sh","paradigm-pretooluse.sh","paradigm-posttooluse.sh"]){let s=r.join(d,l);e.existsSync(s)&&(c?console.log(o.gray(` Would remove: ${s}`)):e.unlinkSync(s),a.push(l));}let p=r.join(h,".cursor","hooks.json");if(e.existsSync(p))if(c)console.log(o.gray(` Would clean paradigm entries from: ${p}`));else try{let l=JSON.parse(e.readFileSync(p,"utf8")),s=l.hooks||{};for(let t of ["sessionStart","stop","afterFileEdit","beforeShellExecution","preToolUse","postToolUse"])Array.isArray(s[t])&&(s[t]=s[t].filter(n=>!JSON.stringify(n).includes("paradigm-")),s[t].length===0&&delete s[t]);l.hooks=s,e.writeFileSync(p,JSON.stringify(l,null,2)+`
@@ -1457,10 +1637,10 @@ fi
1457
1637
  [dry-run] No changes made.
1458
1638
  `));}async function ae(){let i=process.cwd(),h=r.join(i,".git");if(e.existsSync(h)){console.log(o.magenta(`
1459
1639
  Git Hooks Status
1460
- `));let l=r.join(h,"hooks"),s=["post-commit","pre-push"];for(let n of s){let f=r.join(l,n);e.existsSync(f)?e.readFileSync(f,"utf8").includes("paradigm")?console.log(o.green(` ${n}: installed (paradigm)`)):console.log(o.yellow(` ${n}: exists (other)`)):console.log(o.gray(` ${n}: not installed`));}console.log();let t=r.join(i,".paradigm/history");if(e.existsSync(t)){let n=r.join(t,"log.jsonl");if(e.existsSync(n)){let _=e.readFileSync(n,"utf8").split(`
1461
- `).filter(u=>u.trim()).length;console.log(o.white(` History entries: ${_}`));}}else console.log(o.gray(" History: not initialized")),console.log(o.gray(" Run `paradigm history init` to enable"));}else console.log(o.gray(`
1640
+ `));let l=r.join(h,"hooks"),s=["post-commit","pre-push"];for(let n of s){let f=r.join(l,n);e.existsSync(f)?e.readFileSync(f,"utf8").includes("paradigm")?console.log(o.green(` ${n}: installed (paradigm)`)):console.log(o.yellow(` ${n}: exists (other)`)):console.log(o.gray(` ${n}: not installed`));}console.log();let t=r.join(i,".paradigm/history");if(e.existsSync(t)){let n=r.join(t,"log.jsonl");if(e.existsSync(n)){let O=e.readFileSync(n,"utf8").split(`
1641
+ `).filter(u=>u.trim()).length;console.log(o.white(` History entries: ${O}`));}}else console.log(o.gray(" History: not initialized")),console.log(o.gray(" Run `paradigm history init` to enable"));}else console.log(o.gray(`
1462
1642
  Not a git repository (git hooks N/A)
1463
1643
  `));console.log(o.magenta(` Claude Code Hooks Status
1464
- `));let c=x();if(c.active){console.log(o.cyan(` Plugin: paradigm v${c.cacheVersion} (active)`)),console.log(o.green(" Hooks are managed by the plugin \u2014 auto-updates with each session."));let l=r.join(i,".claude","hooks"),s=[];for(let f of ["paradigm-common.sh","paradigm-stop.sh","paradigm-precommit.sh","paradigm-postwrite.sh"])e.existsSync(r.join(l,f))&&s.push(f);let t=r.join(i,".claude","settings.json"),n=false;if(e.existsSync(t))try{let f=JSON.parse(e.readFileSync(t,"utf8"));n=JSON.stringify(f.hooks||{}).includes("paradigm-");}catch{}(s.length>0||n)&&(console.log(o.yellow(` WARNING: Stale project hooks detected (${s.join(", ")}${n?", settings.json entries":""})`)),console.log(o.yellow(" These shadow the plugin hooks and may run outdated logic.")),console.log(o.gray(" Run `paradigm hooks install --claude-code` to clean them up.")));}else {console.log(o.gray(" Plugin: not active (using project-level hooks)"));let l=r.join(i,".claude","hooks"),s=["paradigm-stop.sh","paradigm-precommit.sh","paradigm-postwrite.sh"];for(let n of s){let f=r.join(l,n);e.existsSync(f)?console.log(o.green(` ${n}: installed`)):console.log(o.gray(` ${n}: not installed`));}let t=r.join(i,".claude","settings.json");if(e.existsSync(t))try{let f=JSON.parse(e.readFileSync(t,"utf8")).hooks||{},_=JSON.stringify(f.Stop||[]).includes("paradigm-stop.sh"),u=JSON.stringify(f.PreToolUse||[]).includes("paradigm-precommit.sh"),g=JSON.stringify(f.PostToolUse||[]).includes("paradigm-postwrite.sh");console.log(o.gray(` settings.json Stop hook: ${_?"configured":"missing"}`)),console.log(o.gray(` settings.json PreToolUse hook: ${u?"configured":"missing"}`)),console.log(o.gray(` settings.json PostToolUse hook: ${g?"configured":"missing"}`));}catch{console.log(o.yellow(" settings.json: parse error"));}else console.log(o.gray(" settings.json: not found"));}console.log(o.magenta(`
1644
+ `));let c=x();if(c.active){console.log(o.cyan(` Plugin: paradigm v${c.cacheVersion} (active)`)),console.log(o.green(" Hooks are managed by the plugin \u2014 auto-updates with each session."));let l=r.join(i,".claude","hooks"),s=[];for(let f of ["paradigm-common.sh","paradigm-stop.sh","paradigm-precommit.sh","paradigm-postwrite.sh"])e.existsSync(r.join(l,f))&&s.push(f);let t=r.join(i,".claude","settings.json"),n=false;if(e.existsSync(t))try{let f=JSON.parse(e.readFileSync(t,"utf8"));n=JSON.stringify(f.hooks||{}).includes("paradigm-");}catch{}(s.length>0||n)&&(console.log(o.yellow(` WARNING: Stale project hooks detected (${s.join(", ")}${n?", settings.json entries":""})`)),console.log(o.yellow(" These shadow the plugin hooks and may run outdated logic.")),console.log(o.gray(" Run `paradigm hooks install --claude-code` to clean them up.")));}else {console.log(o.gray(" Plugin: not active (using project-level hooks)"));let l=r.join(i,".claude","hooks"),s=["paradigm-stop.sh","paradigm-precommit.sh","paradigm-postwrite.sh"];for(let n of s){let f=r.join(l,n);e.existsSync(f)?console.log(o.green(` ${n}: installed`)):console.log(o.gray(` ${n}: not installed`));}let t=r.join(i,".claude","settings.json");if(e.existsSync(t))try{let f=JSON.parse(e.readFileSync(t,"utf8")).hooks||{},O=JSON.stringify(f.Stop||[]).includes("paradigm-stop.sh"),u=JSON.stringify(f.PreToolUse||[]).includes("paradigm-precommit.sh"),g=JSON.stringify(f.PostToolUse||[]).includes("paradigm-postwrite.sh");console.log(o.gray(` settings.json Stop hook: ${O?"configured":"missing"}`)),console.log(o.gray(` settings.json PreToolUse hook: ${u?"configured":"missing"}`)),console.log(o.gray(` settings.json PostToolUse hook: ${g?"configured":"missing"}`));}catch{console.log(o.yellow(" settings.json: parse error"));}else console.log(o.gray(" settings.json: not found"));}console.log(o.magenta(`
1465
1645
  Cursor Hooks Status
1466
- `));let d=r.join(i,".cursor","hooks"),a=["paradigm-session-start.sh","paradigm-stop.sh","paradigm-precommit.sh","paradigm-postwrite.sh","paradigm-pretooluse.sh","paradigm-posttooluse.sh"];for(let l of a){let s=r.join(d,l);e.existsSync(s)?console.log(o.green(` ${l}: installed`)):console.log(o.gray(` ${l}: not installed`));}let p=r.join(i,".cursor","hooks.json");if(e.existsSync(p))try{let s=JSON.parse(e.readFileSync(p,"utf8")).hooks||{},t=JSON.stringify(s.sessionStart||[]).includes("paradigm-session-start.sh"),n=JSON.stringify(s.stop||[]).includes("paradigm-stop.sh"),f=JSON.stringify(s.afterFileEdit||[]).includes("paradigm-postwrite.sh"),_=JSON.stringify(s.beforeShellExecution||[]).includes("paradigm-precommit.sh"),u=JSON.stringify(s.preToolUse||[]).includes("paradigm-pretooluse.sh"),g=JSON.stringify(s.postToolUse||[]).includes("paradigm-posttooluse.sh");console.log(o.gray(` hooks.json sessionStart: ${t?"configured":"missing"}`)),console.log(o.gray(` hooks.json stop: ${n?"configured":"missing"}`)),console.log(o.gray(` hooks.json afterFileEdit: ${f?"configured":"missing"}`)),console.log(o.gray(` hooks.json preToolUse: ${u?"configured":"missing"}`)),console.log(o.gray(` hooks.json postToolUse: ${g?"configured":"missing"}`)),console.log(o.gray(` hooks.json beforeShellExecution: ${_?"configured":"missing"}`));}catch{console.log(o.yellow(" hooks.json: parse error"));}else console.log(o.gray(" hooks.json: not found"));console.log();}export{te as a,re as b,ae as c};
1646
+ `));let d=r.join(i,".cursor","hooks"),a=["paradigm-session-start.sh","paradigm-stop.sh","paradigm-precommit.sh","paradigm-postwrite.sh","paradigm-pretooluse.sh","paradigm-posttooluse.sh"];for(let l of a){let s=r.join(d,l);e.existsSync(s)?console.log(o.green(` ${l}: installed`)):console.log(o.gray(` ${l}: not installed`));}let p=r.join(i,".cursor","hooks.json");if(e.existsSync(p))try{let s=JSON.parse(e.readFileSync(p,"utf8")).hooks||{},t=JSON.stringify(s.sessionStart||[]).includes("paradigm-session-start.sh"),n=JSON.stringify(s.stop||[]).includes("paradigm-stop.sh"),f=JSON.stringify(s.afterFileEdit||[]).includes("paradigm-postwrite.sh"),O=JSON.stringify(s.beforeShellExecution||[]).includes("paradigm-precommit.sh"),u=JSON.stringify(s.preToolUse||[]).includes("paradigm-pretooluse.sh"),g=JSON.stringify(s.postToolUse||[]).includes("paradigm-posttooluse.sh");console.log(o.gray(` hooks.json sessionStart: ${t?"configured":"missing"}`)),console.log(o.gray(` hooks.json stop: ${n?"configured":"missing"}`)),console.log(o.gray(` hooks.json afterFileEdit: ${f?"configured":"missing"}`)),console.log(o.gray(` hooks.json preToolUse: ${u?"configured":"missing"}`)),console.log(o.gray(` hooks.json postToolUse: ${g?"configured":"missing"}`)),console.log(o.gray(` hooks.json beforeShellExecution: ${O?"configured":"missing"}`));}catch{console.log(o.yellow(" hooks.json: parse error"));}else console.log(o.gray(" hooks.json: not found"));console.log();}export{te as a,re as b,ae as c};