autoworkflow 3.9.0 → 3.10.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,23 +1,15 @@
1
- # Blockers Memory
1
+ # Blockers
2
2
 
3
- > Document known issues, workarounds, and gotchas.
4
- > Saves time by not rediscovering the same problems.
3
+ > Known issues and workarounds. Claude edits directly.
5
4
 
6
5
  ---
7
6
 
8
- ## Template Entry
9
-
10
- *Recorded: YYYY-MM-DD HH:MM:SS*
7
+ ## Template
8
+ *YYYY-MM-DD*
11
9
 
12
10
  **Issue:** What is the problem?
13
-
14
- **Symptoms:** How does it manifest?
15
-
16
- **Root Cause:** Why does this happen? (if known)
17
-
18
11
  **Workaround:** How to work around it?
19
-
20
- **Status:** Open / Resolved / Won't Fix
12
+ **Status:** Open / Resolved
21
13
 
22
14
  ---
23
15
 
@@ -1,22 +1,14 @@
1
- # Decisions Memory
1
+ # Decisions
2
2
 
3
- > Document important architectural and implementation decisions here.
4
- > This helps maintain context across sessions and explains "why" for future reference.
3
+ > Architectural and implementation choices. Claude edits directly.
5
4
 
6
5
  ---
7
6
 
8
- ## Template Entry
9
-
10
- *Recorded: YYYY-MM-DD HH:MM:SS*
11
-
12
- **Context:** What was the situation or requirement?
13
-
14
- **Options Considered:**
15
- 1. Option A - pros/cons
16
- 2. Option B - pros/cons
7
+ ## Template
8
+ *YYYY-MM-DD*
17
9
 
10
+ **Context:** What was the situation?
18
11
  **Decision:** What was chosen and why?
19
-
20
12
  **Implications:** What does this mean going forward?
21
13
 
22
14
  ---
@@ -1,24 +1,15 @@
1
- # Patterns Memory
1
+ # Patterns
2
2
 
3
- > Document discovered patterns in this codebase.
4
- > Helps maintain consistency and avoid reinventing solutions.
3
+ > Discovered codebase patterns. Claude edits directly.
5
4
 
6
5
  ---
7
6
 
8
- ## Template Entry
7
+ ## Template
8
+ *YYYY-MM-DD*
9
9
 
10
- *Recorded: YYYY-MM-DD HH:MM:SS*
11
-
12
- **Pattern Name:** What is this pattern called?
13
-
14
- **Where Used:** Which files/components use this?
15
-
16
- **How It Works:**
17
- ```
18
- // Code example or description
19
- ```
20
-
21
- **When to Use:** What situations call for this pattern?
10
+ **Pattern:** What is this pattern?
11
+ **Where:** Which files/components use it?
12
+ **Usage:** When and how to use it?
22
13
 
23
14
  ---
24
15
 
@@ -0,0 +1,318 @@
1
+ #!/bin/bash
2
+ # AutoWorkflow Logger
3
+ # Centralized logging for all hooks, gates, and workflow events
4
+ #
5
+ # Usage:
6
+ # source logger.sh
7
+ # aw_log "HOOK" "session-check.sh" "START"
8
+ # aw_log "GATE" "plan_approval" "PASSED"
9
+ # aw_log "PHASE" "PLAN" "IMPLEMENT"
10
+ # aw_log "VERIFY" "1/10" "checking..."
11
+ # aw_log "ERROR" "pre-commit" "TypeScript errors found"
12
+
13
+ # ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
14
+ # CONFIGURATION
15
+ # ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
16
+
17
+ # Project directory
18
+ LOGGER_PROJECT_DIR="${CLAUDE_PROJECT_DIR:-.}"
19
+
20
+ # Log directory and file
21
+ LOG_DIR="$LOGGER_PROJECT_DIR/.claude/.autoworkflow/logs"
22
+ LOG_FILE="$LOG_DIR/aw.log"
23
+ MAX_LOG_SIZE=1048576 # 1MB
24
+ MAX_LOG_FILES=5
25
+
26
+ # Debug mode (set AUTOWORKFLOW_DEBUG=1 to enable verbose output)
27
+ DEBUG_MODE="${AUTOWORKFLOW_DEBUG:-0}"
28
+
29
+ # Colors for terminal output (when viewing with tail -f)
30
+ LOG_RED='\033[0;31m'
31
+ LOG_GREEN='\033[0;32m'
32
+ LOG_YELLOW='\033[1;33m'
33
+ LOG_CYAN='\033[0;36m'
34
+ LOG_BLUE='\033[0;34m'
35
+ LOG_MAGENTA='\033[0;35m'
36
+ LOG_BOLD='\033[1m'
37
+ LOG_DIM='\033[2m'
38
+ LOG_NC='\033[0m'
39
+
40
+ # ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
41
+ # INITIALIZATION
42
+ # ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
43
+
44
+ # Ensure log directory exists
45
+ mkdir -p "$LOG_DIR"
46
+
47
+ # ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
48
+ # LOG ROTATION
49
+ # ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
50
+
51
+ rotate_logs() {
52
+ if [ -f "$LOG_FILE" ]; then
53
+ local size=$(stat -f%z "$LOG_FILE" 2>/dev/null || stat -c%s "$LOG_FILE" 2>/dev/null || echo "0")
54
+
55
+ if [ "$size" -gt "$MAX_LOG_SIZE" ]; then
56
+ # Rotate existing logs
57
+ for i in $(seq $((MAX_LOG_FILES - 1)) -1 1); do
58
+ if [ -f "$LOG_FILE.$i" ]; then
59
+ mv "$LOG_FILE.$i" "$LOG_FILE.$((i + 1))"
60
+ fi
61
+ done
62
+
63
+ # Move current log to .1
64
+ mv "$LOG_FILE" "$LOG_FILE.1"
65
+
66
+ # Create new log file with header
67
+ echo "# AutoWorkflow Log - Rotated $(date '+%Y-%m-%d %H:%M:%S')" > "$LOG_FILE"
68
+ echo "# ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━" >> "$LOG_FILE"
69
+ echo "" >> "$LOG_FILE"
70
+
71
+ # Remove oldest if exceeds max
72
+ if [ -f "$LOG_FILE.$MAX_LOG_FILES" ]; then
73
+ rm -f "$LOG_FILE.$MAX_LOG_FILES"
74
+ fi
75
+ fi
76
+ fi
77
+ }
78
+
79
+ # ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
80
+ # LOGGING FUNCTIONS
81
+ # ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
82
+
83
+ # Get color for category
84
+ get_category_color() {
85
+ local category="$1"
86
+ case "$category" in
87
+ HOOK) echo "$LOG_CYAN" ;;
88
+ PHASE) echo "$LOG_BLUE" ;;
89
+ GATE) echo "$LOG_MAGENTA" ;;
90
+ VERIFY) echo "$LOG_GREEN" ;;
91
+ MEMORY) echo "$LOG_CYAN" ;;
92
+ COMMIT) echo "$LOG_GREEN" ;;
93
+ ERROR) echo "$LOG_RED" ;;
94
+ WARN) echo "$LOG_YELLOW" ;;
95
+ DEBUG) echo "$LOG_DIM" ;;
96
+ *) echo "$LOG_NC" ;;
97
+ esac
98
+ }
99
+
100
+ # Get symbol for status
101
+ get_status_symbol() {
102
+ local status="$1"
103
+ case "$status" in
104
+ START|STARTED) echo "▶" ;;
105
+ COMPLETE|DONE) echo "✓" ;;
106
+ PASSED|SUCCESS) echo "✓" ;;
107
+ FAILED|ERROR) echo "✗" ;;
108
+ BLOCKED|DENIED) echo "⛔" ;;
109
+ WAITING|PENDING) echo "◉" ;;
110
+ SKIPPED) echo "○" ;;
111
+ *) echo "●" ;;
112
+ esac
113
+ }
114
+
115
+ # Main logging function
116
+ # Usage: aw_log <CATEGORY> <SOURCE> <MESSAGE> [DETAILS]
117
+ aw_log() {
118
+ local category="${1:-INFO}"
119
+ local source="${2:-unknown}"
120
+ local message="${3:-}"
121
+ local details="${4:-}"
122
+
123
+ local timestamp=$(date '+%Y-%m-%d %H:%M:%S')
124
+ local time_only=$(date '+%H:%M:%S')
125
+
126
+ # Check for log rotation
127
+ rotate_logs
128
+
129
+ # Get color and symbol
130
+ local color=$(get_category_color "$category")
131
+ local symbol=$(get_status_symbol "$message")
132
+
133
+ # Format the log entry
134
+ local log_entry="[$time_only] [$category] $source $symbol $message"
135
+ [ -n "$details" ] && log_entry="$log_entry - $details"
136
+
137
+ # Write to log file (plain text, no colors)
138
+ echo "[$timestamp] [$category] $source $symbol $message${details:+ - $details}" >> "$LOG_FILE"
139
+
140
+ # If debug mode, also output to stderr (visible in terminal)
141
+ if [ "$DEBUG_MODE" = "1" ]; then
142
+ echo -e "${color}${log_entry}${LOG_NC}" >&2
143
+ fi
144
+ }
145
+
146
+ # Convenience functions for common log types
147
+ aw_log_hook() {
148
+ local hook_name="$1"
149
+ local status="$2"
150
+ local details="${3:-}"
151
+ aw_log "HOOK" "$hook_name" "$status" "$details"
152
+ }
153
+
154
+ aw_log_phase() {
155
+ local from="$1"
156
+ local to="$2"
157
+ aw_log "PHASE" "$from → $to" "TRANSITION"
158
+ }
159
+
160
+ aw_log_gate() {
161
+ local gate_name="$1"
162
+ local status="$2"
163
+ local details="${3:-}"
164
+ aw_log "GATE" "$gate_name" "$status" "$details"
165
+ }
166
+
167
+ aw_log_verify() {
168
+ local iteration="$1"
169
+ local status="$2"
170
+ local details="${3:-}"
171
+ aw_log "VERIFY" "iteration $iteration" "$status" "$details"
172
+ }
173
+
174
+ aw_log_memory() {
175
+ local action="$1"
176
+ local file="$2"
177
+ aw_log "MEMORY" "$action" "$file"
178
+ }
179
+
180
+ aw_log_commit() {
181
+ local status="$1"
182
+ local message="${2:-}"
183
+ aw_log "COMMIT" "$status" "$message"
184
+ }
185
+
186
+ aw_log_error() {
187
+ local source="$1"
188
+ local message="$2"
189
+ aw_log "ERROR" "$source" "FAILED" "$message"
190
+ }
191
+
192
+ aw_log_warn() {
193
+ local source="$1"
194
+ local message="$2"
195
+ aw_log "WARN" "$source" "WARNING" "$message"
196
+ }
197
+
198
+ aw_log_debug() {
199
+ if [ "$DEBUG_MODE" = "1" ]; then
200
+ local source="$1"
201
+ local message="$2"
202
+ aw_log "DEBUG" "$source" "DEBUG" "$message"
203
+ fi
204
+ }
205
+
206
+ # ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
207
+ # LOG VIEWING FUNCTIONS
208
+ # ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
209
+
210
+ # View logs in real-time (for CLI command)
211
+ view_logs_live() {
212
+ if [ -f "$LOG_FILE" ]; then
213
+ echo -e "${LOG_CYAN}━━━ AutoWorkflow Logs (live) ━━━${LOG_NC}"
214
+ echo -e "${LOG_DIM}Press Ctrl+C to stop${LOG_NC}"
215
+ echo ""
216
+ tail -f "$LOG_FILE"
217
+ else
218
+ echo "No log file found. Logs will appear after first hook execution."
219
+ fi
220
+ }
221
+
222
+ # View recent logs
223
+ view_logs_recent() {
224
+ local lines="${1:-50}"
225
+ if [ -f "$LOG_FILE" ]; then
226
+ echo -e "${LOG_CYAN}━━━ AutoWorkflow Logs (last $lines) ━━━${LOG_NC}"
227
+ echo ""
228
+ tail -n "$lines" "$LOG_FILE"
229
+ else
230
+ echo "No log file found."
231
+ fi
232
+ }
233
+
234
+ # View all logs
235
+ view_logs_all() {
236
+ if [ -f "$LOG_FILE" ]; then
237
+ echo -e "${LOG_CYAN}━━━ AutoWorkflow Logs (all) ━━━${LOG_NC}"
238
+ echo ""
239
+ cat "$LOG_FILE"
240
+ else
241
+ echo "No log file found."
242
+ fi
243
+ }
244
+
245
+ # Clear logs
246
+ clear_logs() {
247
+ rm -f "$LOG_FILE" "$LOG_FILE".*
248
+ echo -e "${LOG_GREEN}✓${LOG_NC} Logs cleared"
249
+ }
250
+
251
+ # Show log stats
252
+ show_log_stats() {
253
+ echo -e "${LOG_CYAN}━━━ Log Statistics ━━━${LOG_NC}"
254
+ echo ""
255
+
256
+ if [ -f "$LOG_FILE" ]; then
257
+ local size=$(stat -f%z "$LOG_FILE" 2>/dev/null || stat -c%s "$LOG_FILE" 2>/dev/null || echo "0")
258
+ local lines=$(wc -l < "$LOG_FILE" | tr -d ' ')
259
+ local hooks=$(grep -c "\[HOOK\]" "$LOG_FILE" 2>/dev/null || echo "0")
260
+ local phases=$(grep -c "\[PHASE\]" "$LOG_FILE" 2>/dev/null || echo "0")
261
+ local gates=$(grep -c "\[GATE\]" "$LOG_FILE" 2>/dev/null || echo "0")
262
+ local errors=$(grep -c "\[ERROR\]" "$LOG_FILE" 2>/dev/null || echo "0")
263
+
264
+ echo " Log file: $LOG_FILE"
265
+ echo " Size: $((size / 1024)) KB"
266
+ echo " Lines: $lines"
267
+ echo ""
268
+ echo " Events:"
269
+ echo " Hooks: $hooks"
270
+ echo " Phases: $phases"
271
+ echo " Gates: $gates"
272
+ echo " Errors: $errors"
273
+ else
274
+ echo " No log file found."
275
+ fi
276
+ echo ""
277
+ }
278
+
279
+ # ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
280
+ # CLI INTERFACE (when run directly)
281
+ # ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
282
+
283
+ if [ "${BASH_SOURCE[0]}" = "$0" ]; then
284
+ case "${1:-}" in
285
+ live|watch|tail|-f)
286
+ view_logs_live
287
+ ;;
288
+ recent)
289
+ view_logs_recent "${2:-50}"
290
+ ;;
291
+ all|--all|-a)
292
+ view_logs_all
293
+ ;;
294
+ clear|--clear|-c)
295
+ clear_logs
296
+ ;;
297
+ stats|--stats|-s)
298
+ show_log_stats
299
+ ;;
300
+ *)
301
+ echo "AutoWorkflow Logger"
302
+ echo ""
303
+ echo "Usage: logger.sh <command>"
304
+ echo ""
305
+ echo "Commands:"
306
+ echo " live, watch, tail, -f View logs in real-time"
307
+ echo " recent [n] Show last n log entries (default: 50)"
308
+ echo " all, --all, -a Show all logs"
309
+ echo " clear, --clear, -c Clear all logs"
310
+ echo " stats, --stats, -s Show log statistics"
311
+ echo ""
312
+ echo "Environment:"
313
+ echo " AUTOWORKFLOW_DEBUG=1 Enable debug output to terminal"
314
+ echo ""
315
+ echo "Log file: $LOG_FILE"
316
+ ;;
317
+ esac
318
+ fi
@@ -17,6 +17,10 @@ NC='\033[0m'
17
17
  # Project directory (use env var if set, otherwise current directory)
18
18
  PROJECT_DIR="${CLAUDE_PROJECT_DIR:-.}"
19
19
 
20
+ # Source the logger
21
+ SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
22
+ source "$SCRIPT_DIR/logger.sh" 2>/dev/null || true
23
+
20
24
  # State directory
21
25
  STATE_DIR="$PROJECT_DIR/.claude/.autoworkflow"
22
26
  mkdir -p "$STATE_DIR"
@@ -112,11 +116,13 @@ check_analyze_gate() {
112
116
  check_plan_approval_gate() {
113
117
  echo ""
114
118
  echo "Checking plan_approval_gate..."
119
+ aw_log_gate "plan_approval" "CHECKING"
115
120
 
116
121
  if [ -f "$APPROVAL_FILE" ]; then
117
122
  local approval=$(cat "$APPROVAL_FILE")
118
123
  if [ "$approval" = "approved" ]; then
119
124
  echo -e " ${GREEN}✅${NC} Plan has been approved"
125
+ aw_log_gate "plan_approval" "PASSED"
120
126
  return 0
121
127
  fi
122
128
  fi
@@ -127,6 +133,7 @@ check_plan_approval_gate() {
127
133
  echo ""
128
134
  echo "Wait for user to say 'yes', 'proceed', 'approved', etc."
129
135
  echo ""
136
+ aw_log_gate "plan_approval" "BLOCKED" "awaiting user approval"
130
137
  return 1
131
138
  }
132
139
 
@@ -134,11 +141,13 @@ check_plan_approval_gate() {
134
141
  check_verify_gate() {
135
142
  echo ""
136
143
  echo "Checking verify_gate..."
144
+ aw_log_gate "verify" "CHECKING"
137
145
 
138
146
  if [ -f "$STATE_DIR/verify-status" ]; then
139
147
  local status=$(cat "$STATE_DIR/verify-status")
140
148
  if [ "$status" = "PASSED" ]; then
141
149
  echo -e " ${GREEN}✅${NC} Verification passed"
150
+ aw_log_gate "verify" "PASSED"
142
151
  return 0
143
152
  fi
144
153
  fi
@@ -147,6 +156,7 @@ check_verify_gate() {
147
156
  echo ""
148
157
  echo -e "${YELLOW}BLOCKED:${NC} Run npm run verify and fix all errors first."
149
158
  echo ""
159
+ aw_log_gate "verify" "BLOCKED" "verification not passed"
150
160
  return 1
151
161
  }
152
162
 
@@ -190,6 +200,8 @@ transition() {
190
200
  local from="$1"
191
201
  local to="$2"
192
202
 
203
+ aw_log_phase "$from" "$to"
204
+
193
205
  echo ""
194
206
  echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
195
207
  echo -e "${BOLD}AUTOWORKFLOW: PHASE TRANSITION${NC}"
@@ -244,6 +256,9 @@ transition() {
244
256
  # Output reflection prompt for the new phase
245
257
  output_reflection_prompt "$to"
246
258
 
259
+ # Prompt to update memories based on completed phase
260
+ prompt_memory_update "$from"
261
+
247
262
  echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
248
263
  echo ""
249
264
 
@@ -287,127 +302,119 @@ reset_workflow() {
287
302
  }
288
303
 
289
304
  # ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
290
- # MEMORY SYSTEM (Serena-inspired)
291
- # Persistent context that survives across sessions
305
+ # MEMORY SYSTEM v2 (Serena-inspired)
306
+ # Claude edits files directly + hooks prompt at key moments
292
307
  # ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
293
308
 
294
309
  MEMORY_DIR="$STATE_DIR/memories"
295
310
  mkdir -p "$MEMORY_DIR"
296
311
 
297
- # Save a memory (key-value with optional category)
298
- save_memory() {
299
- local category="$1"
300
- local key="$2"
301
- local value="$3"
302
- local timestamp=$(date +"%Y-%m-%d %H:%M:%S")
303
-
304
- local memory_file="$MEMORY_DIR/${category}.md"
305
-
306
- # Create file with header if it doesn't exist
307
- if [ ! -f "$memory_file" ]; then
308
- cat > "$memory_file" << EOF
309
- # ${category^} Memory
310
-
311
- > Auto-generated memory store. Add entries as you work.
312
-
313
- ---
314
-
315
- EOF
316
- fi
317
-
318
- # Append new memory entry
319
- cat >> "$memory_file" << EOF
320
- ## $key
321
- *Recorded: $timestamp*
322
-
323
- $value
324
-
325
- ---
326
-
327
- EOF
328
-
329
- echo -e "${GREEN}✅${NC} Memory saved: $category/$key"
330
- }
312
+ # Prompt Claude to update memories (called at phase transitions)
313
+ prompt_memory_update() {
314
+ local phase="$1"
315
+ local memory_type=""
316
+ local prompt_text=""
331
317
 
332
- # Read memories for a category
333
- read_memories() {
334
- local category="$1"
335
- local memory_file="$MEMORY_DIR/${category}.md"
318
+ case "$phase" in
319
+ PLAN|CONFIRM)
320
+ memory_type="decisions"
321
+ prompt_text="If you made any architectural or implementation decisions, update .claude/.autoworkflow/memories/decisions.md"
322
+ ;;
323
+ IMPLEMENT|VERIFY)
324
+ memory_type="patterns"
325
+ prompt_text="If you discovered any codebase patterns, update .claude/.autoworkflow/memories/patterns.md"
326
+ ;;
327
+ COMMIT)
328
+ memory_type="context"
329
+ prompt_text="Update .claude/.autoworkflow/memories/context.md with session summary for continuity"
330
+ ;;
331
+ esac
336
332
 
337
- if [ -f "$memory_file" ]; then
338
- cat "$memory_file"
339
- else
340
- echo "No memories found for category: $category"
333
+ if [ -n "$memory_type" ]; then
334
+ echo ""
335
+ echo -e "${CYAN}━━━ MEMORY UPDATE ━━━${NC}"
336
+ echo -e "${DIM}$prompt_text${NC}"
337
+ echo ""
338
+ echo -e "${DIM}Format: Add a new ## Section with date and details${NC}"
339
+ echo -e "${CYAN}━━━━━━━━━━━━━━━━━━━━━${NC}"
340
+ echo ""
341
341
  fi
342
342
  }
343
343
 
344
- # List all memory categories
345
- list_memories() {
344
+ # Prompt to record a blocker (called when errors occur)
345
+ prompt_blocker_update() {
346
+ local error_context="$1"
346
347
  echo ""
347
- echo -e "${CYAN}Available Memory Categories:${NC}"
348
+ echo -e "${YELLOW}━━━ BLOCKER DETECTED ━━━${NC}"
349
+ echo -e "${DIM}Consider recording this in .claude/.autoworkflow/memories/blockers.md${NC}"
348
350
  echo ""
349
-
350
- if [ -d "$MEMORY_DIR" ]; then
351
- for file in "$MEMORY_DIR"/*.md; do
352
- if [ -f "$file" ]; then
353
- local category=$(basename "$file" .md)
354
- local count=$(grep -c "^## " "$file" 2>/dev/null || echo "0")
355
- echo " - $category ($count entries)"
356
- fi
357
- done
358
- else
359
- echo " No memories stored yet."
360
- fi
351
+ echo -e "${DIM}Include: Issue, Symptoms, Workaround, Status${NC}"
352
+ echo -e "${YELLOW}━━━━━━━━━━━━━━━━━━━━━━━━${NC}"
361
353
  echo ""
362
354
  }
363
355
 
364
- # Save context for session continuity
365
- save_context() {
366
- local task_description="$1"
367
- local current_phase=$(get_phase)
368
- local task_type=$(get_task_type)
369
- local timestamp=$(date +"%Y-%m-%d %H:%M:%S")
370
-
371
- local context_file="$MEMORY_DIR/context.md"
372
-
373
- cat > "$context_file" << EOF
374
- # Session Context
375
-
376
- > Last updated: $timestamp
377
-
378
- ## Current State
379
- - **Phase:** $current_phase
380
- - **Task Type:** $task_type
381
- - **Description:** $task_description
382
-
383
- ## What Was Done
384
- <!-- Claude should update this section as work progresses -->
356
+ # Load and display memories at session start
357
+ load_memories_summary() {
358
+ echo ""
359
+ echo -e "${CYAN}━━━ PROJECT MEMORIES ━━━${NC}"
385
360
 
386
- ## What Remains
387
- <!-- Claude should update this section -->
361
+ local has_memories=false
388
362
 
389
- ## Key Decisions Made
390
- <!-- Document important choices and their rationale -->
363
+ # Check decisions
364
+ if [ -f "$MEMORY_DIR/decisions.md" ]; then
365
+ local decision_count=$(grep -c "^## " "$MEMORY_DIR/decisions.md" 2>/dev/null || echo "0")
366
+ if [ "$decision_count" -gt 1 ]; then # More than template
367
+ echo -e " ${GREEN}●${NC} Decisions: $((decision_count - 1)) recorded"
368
+ has_memories=true
369
+ fi
370
+ fi
391
371
 
392
- ## Files Modified
393
- $(cat "$STATE_DIR/changed-files" 2>/dev/null || echo "None yet")
372
+ # Check patterns
373
+ if [ -f "$MEMORY_DIR/patterns.md" ]; then
374
+ local pattern_count=$(grep -c "^## " "$MEMORY_DIR/patterns.md" 2>/dev/null || echo "0")
375
+ if [ "$pattern_count" -gt 1 ]; then
376
+ echo -e " ${GREEN}●${NC} Patterns: $((pattern_count - 1)) recorded"
377
+ has_memories=true
378
+ fi
379
+ fi
394
380
 
395
- ---
381
+ # Check blockers
382
+ if [ -f "$MEMORY_DIR/blockers.md" ]; then
383
+ local blocker_count=$(grep -c "^## " "$MEMORY_DIR/blockers.md" 2>/dev/null || echo "0")
384
+ if [ "$blocker_count" -gt 1 ]; then
385
+ echo -e " ${YELLOW}●${NC} Blockers: $((blocker_count - 1)) recorded"
386
+ has_memories=true
387
+ fi
388
+ fi
396
389
 
397
- *Use this context to resume work in a new session.*
398
- EOF
390
+ if [ "$has_memories" = false ]; then
391
+ echo -e " ${DIM}No memories recorded yet${NC}"
392
+ fi
399
393
 
400
- echo -e "${GREEN}✅${NC} Context saved for session continuity"
394
+ echo ""
395
+ echo -e "${DIM}Read with: Read tool on .claude/.autoworkflow/memories/*.md${NC}"
396
+ echo -e "${CYAN}━━━━━━━━━━━━━━━━━━━━━━━━${NC}"
397
+ echo ""
401
398
  }
402
399
 
403
- # Load context summary
400
+ # Load context summary (for session resume)
404
401
  load_context() {
405
402
  local context_file="$MEMORY_DIR/context.md"
406
403
 
407
404
  if [ -f "$context_file" ]; then
408
405
  echo ""
409
406
  echo -e "${CYAN}━━━ PREVIOUS SESSION CONTEXT ━━━${NC}"
410
- cat "$context_file"
407
+ # Show just the key sections
408
+ if grep -q "## What Was Done" "$context_file"; then
409
+ echo -e "${BOLD}What Was Done:${NC}"
410
+ sed -n '/## What Was Done/,/## /p' "$context_file" | head -8 | tail -n +2
411
+ fi
412
+ if grep -q "## What Remains" "$context_file"; then
413
+ echo -e "${BOLD}What Remains:${NC}"
414
+ sed -n '/## What Remains/,/## /p' "$context_file" | head -8 | tail -n +2
415
+ fi
416
+ echo ""
417
+ echo -e "${DIM}Full context: .claude/.autoworkflow/memories/context.md${NC}"
411
418
  echo -e "${CYAN}━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━${NC}"
412
419
  echo ""
413
420
  fi
@@ -442,22 +449,16 @@ case "$1" in
442
449
  fi
443
450
  echo ""
444
451
  ;;
445
- # Memory commands (Serena-inspired)
446
- memory-save)
447
- save_memory "$2" "$3" "$4"
448
- ;;
449
- memory-read)
450
- read_memories "$2"
451
- ;;
452
- memory-list)
453
- list_memories
452
+ # Memory commands v2 (Claude edits files directly)
453
+ memories)
454
+ load_memories_summary
454
455
  ;;
455
- context-save)
456
- save_context "$2"
457
- ;;
458
- context-load)
456
+ context)
459
457
  load_context
460
458
  ;;
459
+ blocker)
460
+ prompt_blocker_update "$2"
461
+ ;;
461
462
  reflect)
462
463
  output_reflection_prompt "$2"
463
464
  ;;
@@ -471,12 +472,16 @@ case "$1" in
471
472
  echo " reset - Reset workflow state"
472
473
  echo " status - Show current state"
473
474
  echo ""
474
- echo "Memory Commands (Serena-inspired):"
475
- echo " memory-save <category> <key> <value> - Save a memory"
476
- echo " memory-read <category> - Read memories"
477
- echo " memory-list - List all categories"
478
- echo " context-save <description> - Save session context"
479
- echo " context-load - Load previous context"
480
- echo " reflect <phase> - Show reflection prompts"
475
+ echo "Memory Commands (Claude edits files directly):"
476
+ echo " memories - Show memory summary"
477
+ echo " context - Load previous session context"
478
+ echo " blocker - Prompt to record a blocker"
479
+ echo " reflect <phase> - Show reflection prompts"
480
+ echo ""
481
+ echo "Memory Files (edit directly with Claude):"
482
+ echo " .claude/.autoworkflow/memories/decisions.md"
483
+ echo " .claude/.autoworkflow/memories/patterns.md"
484
+ echo " .claude/.autoworkflow/memories/blockers.md"
485
+ echo " .claude/.autoworkflow/memories/context.md"
481
486
  ;;
482
487
  esac
@@ -20,6 +20,10 @@ NC='\033[0m'
20
20
  # Project directory (use env var if set, otherwise current directory)
21
21
  PROJECT_DIR="${CLAUDE_PROJECT_DIR:-.}"
22
22
 
23
+ # Source the logger
24
+ SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
25
+ source "$SCRIPT_DIR/logger.sh" 2>/dev/null || true
26
+
23
27
  # State directory
24
28
  STATE_DIR="$PROJECT_DIR/.claude/.autoworkflow"
25
29
  mkdir -p "$STATE_DIR"
@@ -311,6 +315,8 @@ run_verify() {
311
315
 
312
316
  # Main execution
313
317
  main() {
318
+ aw_log_hook "post-edit.sh" "START"
319
+
314
320
  local current_phase=$(get_phase)
315
321
 
316
322
  # Track that we're in VERIFY phase
@@ -318,6 +324,7 @@ main() {
318
324
 
319
325
  # Get current iteration and increment
320
326
  local iteration=$(increment_iteration)
327
+ aw_log_verify "$iteration/$MAX_ITERATIONS" "STARTED"
321
328
 
322
329
  # Check if we've exceeded max iterations
323
330
  if [ "$iteration" -gt "$MAX_ITERATIONS" ]; then
@@ -334,6 +341,7 @@ main() {
334
341
  echo " 2. Reset counter: rm $VERIFY_ITERATION_FILE"
335
342
  echo ""
336
343
  echo "BLOCKED" > "$VERIFY_STATUS_FILE"
344
+ aw_log_verify "$iteration/$MAX_ITERATIONS" "BLOCKED" "max iterations reached"
337
345
  # Don't exit with error - let Claude continue but report the issue
338
346
  exit 0
339
347
  fi
@@ -356,6 +364,7 @@ main() {
356
364
 
357
365
  # Update status
358
366
  echo "PASSED" > "$VERIFY_STATUS_FILE"
367
+ aw_log_verify "$iteration/$MAX_ITERATIONS" "PASSED" "0 errors"
359
368
 
360
369
  # Check if this was a feature/refactor that needs audit
361
370
  local task_type=""
@@ -386,6 +395,7 @@ main() {
386
395
  # Update status
387
396
  echo "FAILED" > "$VERIFY_STATUS_FILE"
388
397
  echo "$iteration" > "$VERIFY_ITERATION_FILE"
398
+ aw_log_verify "$iteration/$MAX_ITERATIONS" "FAILED" "errors found"
389
399
 
390
400
  echo "Fix the errors above and save the file."
391
401
  echo "Verification will re-run automatically."
@@ -396,6 +406,8 @@ main() {
396
406
  # Enter FIX phase
397
407
  set_phase "FIX"
398
408
  fi
409
+
410
+ aw_log_hook "post-edit.sh" "COMPLETE"
399
411
  }
400
412
 
401
413
  main
@@ -19,6 +19,10 @@ NC='\033[0m'
19
19
  # Project directory (use env var if set, otherwise current directory)
20
20
  PROJECT_DIR="${CLAUDE_PROJECT_DIR:-.}"
21
21
 
22
+ # Source the logger
23
+ SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
24
+ source "$SCRIPT_DIR/logger.sh" 2>/dev/null || true
25
+
22
26
  # State directory
23
27
  STATE_DIR="$PROJECT_DIR/.claude/.autoworkflow"
24
28
  mkdir -p "$STATE_DIR"
@@ -191,6 +195,8 @@ check_commit_message() {
191
195
 
192
196
  # Main execution
193
197
  main() {
198
+ aw_log_gate "pre_commit" "CHECKING" "7 checks"
199
+
194
200
  print_header
195
201
 
196
202
  echo "Checking requirements..."
@@ -219,6 +225,8 @@ main() {
219
225
  echo "BLOCKED" > "$STATE_DIR/gate-status"
220
226
  echo "$ERRORS" > "$STATE_DIR/gate-errors"
221
227
 
228
+ aw_log_gate "pre_commit" "BLOCKED" "$ERRORS errors"
229
+
222
230
  # EXIT WITH ERROR TO BLOCK THE COMMIT
223
231
  exit 1
224
232
  else
@@ -231,6 +239,8 @@ main() {
231
239
  echo "PASSED" > "$STATE_DIR/gate-status"
232
240
  echo "0" > "$STATE_DIR/gate-errors"
233
241
 
242
+ aw_log_gate "pre_commit" "PASSED" "7/7 checks"
243
+
234
244
  exit 0
235
245
  fi
236
246
  }
@@ -21,6 +21,10 @@ NC='\033[0m'
21
21
  # Project directory (use env var if set, otherwise current directory)
22
22
  PROJECT_DIR="${CLAUDE_PROJECT_DIR:-.}"
23
23
 
24
+ # Source the logger
25
+ SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
26
+ source "$SCRIPT_DIR/logger.sh" 2>/dev/null || true
27
+
24
28
  # State directory
25
29
  STATE_DIR="$PROJECT_DIR/.claude/.autoworkflow"
26
30
  mkdir -p "$STATE_DIR"
@@ -462,13 +466,57 @@ reset_turn_state() {
462
466
  echo "0" > "$CURRENT_TURN_EDITS_FILE"
463
467
  }
464
468
 
469
+ # Load and display memories summary (for context awareness)
470
+ show_memories_summary() {
471
+ local has_memories=false
472
+
473
+ # Check if any memories exist (beyond templates)
474
+ for file in "$MEMORY_DIR/decisions.md" "$MEMORY_DIR/patterns.md" "$MEMORY_DIR/blockers.md"; do
475
+ if [ -f "$file" ]; then
476
+ local count=$(grep -c "^## " "$file" 2>/dev/null || echo "0")
477
+ if [ "$count" -gt 1 ]; then
478
+ has_memories=true
479
+ break
480
+ fi
481
+ fi
482
+ done
483
+
484
+ if [ "$has_memories" = true ]; then
485
+ echo ""
486
+ echo -e "${CYAN}━━━ PROJECT MEMORIES ━━━${NC}"
487
+
488
+ if [ -f "$MEMORY_DIR/decisions.md" ]; then
489
+ local count=$(grep -c "^## " "$MEMORY_DIR/decisions.md" 2>/dev/null || echo "0")
490
+ [ "$count" -gt 1 ] && echo -e " ${GREEN}●${NC} Decisions: $((count - 1)) recorded"
491
+ fi
492
+
493
+ if [ -f "$MEMORY_DIR/patterns.md" ]; then
494
+ local count=$(grep -c "^## " "$MEMORY_DIR/patterns.md" 2>/dev/null || echo "0")
495
+ [ "$count" -gt 1 ] && echo -e " ${GREEN}●${NC} Patterns: $((count - 1)) recorded"
496
+ fi
497
+
498
+ if [ -f "$MEMORY_DIR/blockers.md" ]; then
499
+ local count=$(grep -c "^## " "$MEMORY_DIR/blockers.md" 2>/dev/null || echo "0")
500
+ [ "$count" -gt 1 ] && echo -e " ${YELLOW}●${NC} Blockers: $((count - 1)) recorded"
501
+ fi
502
+
503
+ echo ""
504
+ echo -e "${DIM}Read: .claude/.autoworkflow/memories/*.md${NC}"
505
+ echo -e "${CYAN}━━━━━━━━━━━━━━━━━━━━━━━━${NC}"
506
+ echo ""
507
+ fi
508
+ }
509
+
465
510
  # Main execution
466
511
  main() {
512
+ aw_log_hook "session-check.sh" "START"
513
+
467
514
  local is_new_session=false
468
515
 
469
516
  # Initialize session
470
517
  if init_session; then
471
518
  is_new_session=true
519
+ aw_log "HOOK" "session-check.sh" "NEW_SESSION"
472
520
  fi
473
521
 
474
522
  # Reset turn state on each user message
@@ -476,6 +524,7 @@ main() {
476
524
 
477
525
  # Check if init is needed (package installed but not set up)
478
526
  if check_init_needed; then
527
+ aw_log "HOOK" "session-check.sh" "INIT_NEEDED"
479
528
  exit 0
480
529
  fi
481
530
 
@@ -485,10 +534,17 @@ main() {
485
534
  fi
486
535
 
487
536
  # Check for missing blueprint (prompts user for documentation)
488
- check_blueprint
537
+ if ! check_blueprint; then
538
+ aw_log "HOOK" "session-check.sh" "DOCS_REQUIRED"
539
+ fi
540
+
541
+ # Show memories summary (if any exist)
542
+ show_memories_summary
489
543
 
490
544
  # Show current state if not idle
491
545
  show_state
546
+
547
+ aw_log_hook "session-check.sh" "COMPLETE"
492
548
  }
493
549
 
494
550
  main
@@ -144,7 +144,16 @@
144
144
  "- phase: Current phase (ANALYZE, PLAN, etc.)",
145
145
  "- task-type: Classified task type",
146
146
  "- verify-iteration: Current verify loop count",
147
- "- gate-status: Last gate check result"
147
+ "- gate-status: Last gate check result",
148
+ "",
149
+ "### Memory System (Persistent Context)",
150
+ "Edit these files directly using the Edit tool:",
151
+ "- `.claude/.autoworkflow/memories/decisions.md` - After PLAN: record architectural choices",
152
+ "- `.claude/.autoworkflow/memories/patterns.md` - After IMPLEMENT: record discovered patterns",
153
+ "- `.claude/.autoworkflow/memories/blockers.md` - When errors: record issues and workarounds",
154
+ "- `.claude/.autoworkflow/memories/context.md` - Before COMMIT: update session summary",
155
+ "",
156
+ "Format: ## Title, *Date*, Content, ---"
148
157
  ],
149
158
 
150
159
  "workflow": {
package/CLAUDE.md CHANGED
@@ -124,35 +124,77 @@ All state stored in `.claude/.autoworkflow/`:
124
124
 
125
125
  ---
126
126
 
127
- ## Memory System (Serena-inspired)
127
+ ## Logging System
128
128
 
129
- Persistent context that survives across sessions. Stored in `.claude/.autoworkflow/memories/`.
129
+ Real-time visibility into hook execution, gates, and workflow events.
130
130
 
131
- | File | Purpose |
132
- |------|---------|
133
- | `decisions.md` | Document architectural/implementation choices |
134
- | `patterns.md` | Record discovered codebase patterns |
135
- | `blockers.md` | Track known issues and workarounds |
136
- | `context.md` | Session continuity (auto-generated) |
131
+ **Log Location:** `.claude/.autoworkflow/logs/aw.log`
137
132
 
138
- **Memory Commands:**
133
+ **CLI Commands:**
139
134
  ```bash
140
- # Save a decision
141
- .claude/hooks/phase-transition.sh memory-save decisions "auth-approach" "Chose JWT over sessions for stateless API"
135
+ npx autoworkflow logs # Watch logs in real-time
136
+ npx autoworkflow logs --recent # Show last 50 entries
137
+ npx autoworkflow logs --all # Show all logs
138
+ npx autoworkflow logs --clear # Clear logs
139
+ npx autoworkflow logs --stats # Show statistics
140
+ ```
141
+
142
+ **Or use tail directly:**
143
+ ```bash
144
+ tail -f .claude/.autoworkflow/logs/aw.log
145
+ ```
146
+
147
+ **Log Categories:**
148
+ | Category | Events |
149
+ |----------|--------|
150
+ | HOOK | Hook start/complete |
151
+ | PHASE | Phase transitions |
152
+ | GATE | Gate checks (pass/block) |
153
+ | VERIFY | Verification iterations |
154
+ | MEMORY | Memory update prompts |
155
+ | COMMIT | Commit events |
156
+ | ERROR | Errors and failures |
157
+
158
+ **Debug Mode:** Set `AUTOWORKFLOW_DEBUG=1` to see logs in terminal.
142
159
 
143
- # Read memories
144
- .claude/hooks/phase-transition.sh memory-read decisions
160
+ ---
161
+
162
+ ## Memory System (Serena-inspired)
145
163
 
146
- # List all categories
147
- .claude/hooks/phase-transition.sh memory-list
164
+ Persistent context that survives across sessions. **Claude edits files directly** + hooks prompt at key moments.
148
165
 
149
- # Save context for next session
150
- .claude/hooks/phase-transition.sh context-save "Implementing user auth"
166
+ **Memory Files:** `.claude/.autoworkflow/memories/`
167
+ | File | Purpose | When to Update |
168
+ |------|---------|----------------|
169
+ | `decisions.md` | Architectural/implementation choices | After PLAN phase |
170
+ | `patterns.md` | Discovered codebase patterns | After IMPLEMENT |
171
+ | `blockers.md` | Known issues and workarounds | When hitting errors |
172
+ | `context.md` | Session continuity | Before COMMIT |
173
+
174
+ **How it works:**
175
+ 1. **Session Start** → Memories summary displayed automatically
176
+ 2. **Phase Transitions** → Hooks prompt to update relevant memory
177
+ 3. **Claude Edits Directly** → Use Edit tool on memory files
178
+ 4. **No Shell Commands** → Just read and edit the markdown files
151
179
 
152
- # Load previous context
153
- .claude/hooks/phase-transition.sh context-load
180
+ **Memory Format:**
181
+ ```markdown
182
+ ## [Entry Title]
183
+ *[Date]*
184
+
185
+ [Content - decisions made, patterns found, blockers hit]
186
+
187
+ ---
154
188
  ```
155
189
 
190
+ **Automated Prompts:**
191
+ | Trigger | Memory Prompt |
192
+ |---------|---------------|
193
+ | After PLAN | "Record any decisions made" |
194
+ | After IMPLEMENT | "Record any patterns discovered" |
195
+ | Before COMMIT | "Update context for next session" |
196
+ | Error encountered | "Consider recording this blocker" |
197
+
156
198
  ---
157
199
 
158
200
  ## Reflection Prompts (Serena-inspired)
@@ -239,6 +281,7 @@ npm run format # Prettier
239
281
  | `phase-transition.sh` | Manual call | State management |
240
282
  | `audit-runner.sh` | Manual call | Run UI + cycle audits |
241
283
  | `blueprint-generator.sh` | Manual call | Enhanced project discovery (8 scans) |
284
+ | `logger.sh` | Sourced by hooks | Centralized logging system |
242
285
 
243
286
  ---
244
287
 
package/bin/cli.js CHANGED
@@ -72,6 +72,12 @@ Commands:
72
72
  ${colors.cyan('update')} Smart update - core files only, preserve user files
73
73
  ${colors.cyan('status')} Show installed version and what would change
74
74
 
75
+ ${colors.cyan('logs')} View AutoWorkflow logs (real-time)
76
+ ${colors.cyan('logs --recent')} Show last 50 log entries
77
+ ${colors.cyan('logs --all')} Show all logs
78
+ ${colors.cyan('logs --clear')} Clear all logs
79
+ ${colors.cyan('logs --stats')} Show log statistics
80
+
75
81
  ${colors.cyan('help')} Show this help message
76
82
 
77
83
  Options:
@@ -82,7 +88,7 @@ Examples:
82
88
  npx autoworkflow init # Fresh install
83
89
  npx autoworkflow update # Update core files only
84
90
  npx autoworkflow status # Check what would change
85
- npx autoworkflow init --force # Full reinstall
91
+ npx autoworkflow logs # Watch logs in real-time
86
92
  `);
87
93
  }
88
94
 
@@ -453,6 +459,62 @@ function init(options = {}) {
453
459
  console.log(`${colors.dim('Optional: Edit instructions/AI_RULES.md to customize coding standards')}\n`);
454
460
  }
455
461
 
462
+ // Logs command
463
+ import { spawn } from 'child_process';
464
+
465
+ function logs() {
466
+ const cwd = process.cwd();
467
+ const loggerScript = join(cwd, '.claude', 'hooks', 'logger.sh');
468
+
469
+ // Check if logger exists
470
+ if (!existsSync(loggerScript)) {
471
+ console.log(`${colors.yellow('⚠')} AutoWorkflow not initialized in this directory.`);
472
+ console.log(` Run: npx autoworkflow init`);
473
+ process.exit(1);
474
+ }
475
+
476
+ // Determine subcommand
477
+ const subCommand = args[1] || 'live';
478
+
479
+ let loggerArg;
480
+ switch (subCommand) {
481
+ case '--recent':
482
+ case '-r':
483
+ loggerArg = 'recent';
484
+ break;
485
+ case '--all':
486
+ case '-a':
487
+ loggerArg = 'all';
488
+ break;
489
+ case '--clear':
490
+ case '-c':
491
+ loggerArg = 'clear';
492
+ break;
493
+ case '--stats':
494
+ case '-s':
495
+ loggerArg = 'stats';
496
+ break;
497
+ default:
498
+ loggerArg = 'live';
499
+ }
500
+
501
+ // Run the logger script
502
+ const child = spawn('bash', [loggerScript, loggerArg], {
503
+ cwd: cwd,
504
+ stdio: 'inherit',
505
+ env: { ...process.env, CLAUDE_PROJECT_DIR: cwd }
506
+ });
507
+
508
+ child.on('error', (err) => {
509
+ console.error(`${colors.red('Error:')} ${err.message}`);
510
+ process.exit(1);
511
+ });
512
+
513
+ child.on('exit', (code) => {
514
+ process.exit(code || 0);
515
+ });
516
+ }
517
+
456
518
  // Main
457
519
  switch (command) {
458
520
  case 'init':
@@ -464,6 +526,10 @@ switch (command) {
464
526
  case 'status':
465
527
  status();
466
528
  break;
529
+ case 'logs':
530
+ case 'log':
531
+ logs();
532
+ break;
467
533
  case 'help':
468
534
  case '--help':
469
535
  case '-h':
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "autoworkflow",
3
- "version": "3.9.0",
3
+ "version": "3.10.0",
4
4
  "description": "Automated workflow enforcement for Claude Code via hooks and system prompts",
5
5
  "type": "module",
6
6
  "bin": {