autoworkflow 3.6.0 → 3.7.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,10 +1,14 @@
1
1
  #!/bin/bash
2
- # AutoWorkflow Pre-Edit Hook
2
+ # AutoWorkflow Pre-Edit Hook (v3.7.0 - Fail-Closed Design)
3
3
  # Runs on: PreToolUse for Write/Edit tools
4
- # Purpose: Enforce plan approval before implementation
4
+ # Purpose: BLOCK edits by default unless workflow state is properly set
5
5
  #
6
- # This hook implements the plan_approval_gate enforcement
7
- # It BLOCKS Write/Edit operations if plan hasn't been approved
6
+ # DESIGN PRINCIPLE: Fail-closed
7
+ # - If state is not initialized BLOCK (auto-init as feature)
8
+ # - If plan not approved → BLOCK
9
+ # - If suggestions not shown (feature tasks) → BLOCK
10
+ # - If multiple edits per turn → BLOCK
11
+ # - Only allow edit if ALL checks pass
8
12
 
9
13
  # Colors
10
14
  RED='\033[0;31m'
@@ -24,14 +28,43 @@ TASK_TYPE_FILE="$STATE_DIR/task-type"
24
28
  PLAN_APPROVED_FILE="$STATE_DIR/plan-approved"
25
29
  SUGGESTIONS_SHOWN_FILE="$STATE_DIR/suggestions-shown"
26
30
  CURRENT_TURN_EDITS_FILE="$STATE_DIR/current-turn-edits"
27
- SELECTED_ITEMS_FILE="$STATE_DIR/selected-items"
31
+ WORKFLOW_INITIALIZED_FILE="$STATE_DIR/workflow-initialized"
32
+
33
+ # Auto-initialize workflow state with safe defaults
34
+ auto_init_state() {
35
+ mkdir -p "$STATE_DIR"
36
+
37
+ # Set safe defaults - assume feature task (strictest)
38
+ echo "feature" > "$TASK_TYPE_FILE"
39
+ echo "IMPLEMENT" > "$PHASE_FILE"
40
+ echo "false" > "$PLAN_APPROVED_FILE"
41
+ echo "false" > "$SUGGESTIONS_SHOWN_FILE"
42
+ echo "0" > "$CURRENT_TURN_EDITS_FILE"
43
+ echo "true" > "$WORKFLOW_INITIALIZED_FILE"
44
+
45
+ echo ""
46
+ echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
47
+ echo -e "${CYAN}${BOLD}📋 AUTOWORKFLOW: STATE INITIALIZED${NC}"
48
+ echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
49
+ echo ""
50
+ echo "Workflow state auto-initialized with safe defaults:"
51
+ echo " Task type: feature (strictest)"
52
+ echo " Plan approved: false"
53
+ echo " Suggestions shown: false"
54
+ echo ""
55
+ }
56
+
57
+ # Check if workflow is initialized
58
+ is_workflow_initialized() {
59
+ [ -d "$STATE_DIR" ] && [ -f "$WORKFLOW_INITIALIZED_FILE" ]
60
+ }
28
61
 
29
62
  # Get current phase
30
63
  get_phase() {
31
64
  if [ -f "$PHASE_FILE" ]; then
32
65
  cat "$PHASE_FILE"
33
66
  else
34
- echo "IDLE"
67
+ echo "UNKNOWN"
35
68
  fi
36
69
  }
37
70
 
@@ -40,7 +73,7 @@ get_task_type() {
40
73
  if [ -f "$TASK_TYPE_FILE" ]; then
41
74
  cat "$TASK_TYPE_FILE"
42
75
  else
43
- echo "unknown"
76
+ echo "feature" # Default to strictest
44
77
  fi
45
78
  }
46
79
 
@@ -53,7 +86,7 @@ is_plan_approved() {
53
86
  return 1
54
87
  }
55
88
 
56
- # Check if suggestions were shown (for feature tasks)
89
+ # Check if suggestions were shown
57
90
  suggestions_shown() {
58
91
  if [ -f "$SUGGESTIONS_SHOWN_FILE" ]; then
59
92
  local status=$(cat "$SUGGESTIONS_SHOWN_FILE")
@@ -79,142 +112,182 @@ increment_turn_edits() {
79
112
  echo "$next"
80
113
  }
81
114
 
82
- # Check if user has selected items to implement
83
- has_selected_items() {
84
- if [ -f "$SELECTED_ITEMS_FILE" ]; then
85
- local content=$(cat "$SELECTED_ITEMS_FILE")
86
- [ -n "$content" ] && return 0
87
- fi
88
- return 1
89
- }
90
-
91
- # Check if task type requires approval
92
- requires_approval() {
115
+ # Check if task type requires strict workflow
116
+ requires_strict_workflow() {
93
117
  local task_type="$1"
94
118
  case "$task_type" in
95
- # These task types require plan approval
119
+ # Strict workflow required
96
120
  feature|fix|refactor|perf|security|test)
97
121
  return 0
98
122
  ;;
99
- # These can proceed without explicit approval
100
- docs|style|config|query)
123
+ # Relaxed workflow
124
+ docs|style|config)
101
125
  return 1
102
126
  ;;
103
- # Unknown defaults to requiring approval
127
+ # Unknown = strict
104
128
  *)
105
129
  return 0
106
130
  ;;
107
131
  esac
108
132
  }
109
133
 
110
- # Main check
111
- main() {
112
- local phase=$(get_phase)
113
- local task_type=$(get_task_type)
134
+ # GATE 1: Plan Approval Check
135
+ check_plan_approval() {
136
+ local task_type="$1"
114
137
 
115
- # Skip check if no task is active
116
- if [ "$phase" = "IDLE" ]; then
117
- exit 0
138
+ if ! requires_strict_workflow "$task_type"; then
139
+ return 0 # Pass for relaxed task types
118
140
  fi
119
141
 
120
- # Skip check for task types that don't require approval
121
- if ! requires_approval "$task_type"; then
122
- exit 0
142
+ if ! is_plan_approved; then
143
+ echo ""
144
+ echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
145
+ echo -e "${RED}${BOLD}⛔ GATE 1: PLAN APPROVAL REQUIRED${NC}"
146
+ echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
147
+ echo ""
148
+ echo -e "${CYAN}Task Type:${NC} $task_type"
149
+ echo -e "${CYAN}Plan Approved:${NC} NO"
150
+ echo ""
151
+ echo "You MUST get user approval before making any edits."
152
+ echo ""
153
+ echo -e "${BOLD}Required steps:${NC}"
154
+ echo " 1. Analyze the codebase"
155
+ echo " 2. Present your plan to the user"
156
+ echo " 3. Wait for explicit approval (yes/proceed/approved)"
157
+ echo " 4. THEN implement"
158
+ echo ""
159
+ echo -e "${DIM}To mark approved: echo 'true' > $PLAN_APPROVED_FILE${NC}"
160
+ echo ""
161
+ echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
162
+ echo ""
163
+ return 1
123
164
  fi
165
+ return 0
166
+ }
124
167
 
125
- # Skip check if already in IMPLEMENT or later phases
126
- case "$phase" in
127
- IMPLEMENT|VERIFY|FIX|AUDIT|PRE_COMMIT|COMMIT|UPDATE)
128
- # Already past approval, allow edits
129
- exit 0
130
- ;;
131
- esac
168
+ # GATE 2: Suggestions Check (for feature tasks)
169
+ check_suggestions() {
170
+ local task_type="$1"
171
+
172
+ # Only enforce for feature tasks
173
+ if [ "$task_type" != "feature" ]; then
174
+ return 0
175
+ fi
176
+
177
+ if ! suggestions_shown; then
178
+ echo ""
179
+ echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
180
+ echo -e "${RED}${BOLD}⛔ GATE 2: SUGGESTIONS REQUIRED${NC}"
181
+ echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
182
+ echo ""
183
+ echo -e "${CYAN}Task Type:${NC} feature"
184
+ echo ""
185
+ echo "For feature tasks, you MUST show 3-tier suggestions FIRST:"
186
+ echo ""
187
+ echo " 🔴 Required - Must implement"
188
+ echo " 🟡 Recommended - Should implement"
189
+ echo " 🟢 Optional - Nice to have"
190
+ echo ""
191
+ echo "Show suggestions, let user select, THEN implement ONE at a time."
192
+ echo ""
193
+ echo -e "${DIM}To mark shown: echo 'true' > $SUGGESTIONS_SHOWN_FILE${NC}"
194
+ echo ""
195
+ echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
196
+ echo ""
197
+ return 1
198
+ fi
199
+ return 0
200
+ }
201
+
202
+ # GATE 3: One Edit Per Turn Check (applies to ALL implementation)
203
+ check_one_edit_per_turn() {
204
+ local task_type="$1"
132
205
 
133
- # Check if we're in a pre-approval phase
134
- if [ "$phase" = "ANALYZE" ] || [ "$phase" = "PLAN" ]; then
135
- if ! is_plan_approved; then
136
- echo ""
137
- echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
138
- echo -e "${RED}${BOLD}⛔ AUTOWORKFLOW: PLAN APPROVAL REQUIRED${NC}"
139
- echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
140
- echo ""
141
- echo -e "${CYAN}Current Phase:${NC} $phase"
142
- echo -e "${CYAN}Task Type:${NC} $task_type"
143
- echo -e "${CYAN}Plan Approved:${NC} NO"
144
- echo ""
145
- echo "Cannot edit files before plan approval."
146
- echo ""
147
- echo -e "${BOLD}Required workflow:${NC}"
148
- echo " 1. Complete ANALYZE phase (read relevant files)"
149
- echo " 2. Present PLAN with suggestions"
150
- echo " 3. Wait for user approval"
151
- echo " 4. THEN implement"
152
- echo ""
153
- echo -e "${DIM}To approve, user must say: yes, proceed, approved, go ahead${NC}"
154
- echo ""
155
- echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
156
- echo ""
157
-
158
- # Exit with error to BLOCK the edit
159
- exit 1
160
- fi
206
+ if ! requires_strict_workflow "$task_type"; then
207
+ return 0 # Pass for relaxed task types
161
208
  fi
162
209
 
163
- # CHECK: Suggestions must be shown for feature tasks before implementing
164
- if [ "$task_type" = "feature" ] && [ "$phase" = "IMPLEMENT" ]; then
165
- if ! suggestions_shown; then
166
- echo ""
167
- echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
168
- echo -e "${RED}${BOLD}⛔ AUTOWORKFLOW: SUGGESTIONS REQUIRED${NC}"
169
- echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
170
- echo ""
171
- echo -e "${CYAN}Task Type:${NC} feature"
172
- echo ""
173
- echo "For feature tasks, you MUST show 3-tier suggestions first:"
174
- echo ""
175
- echo " 🔴 Required - Must implement"
176
- echo " 🟡 Recommended - Should implement"
177
- echo " 🟢 Optional - Nice to have"
178
- echo ""
179
- echo "Show suggestions, let user select items, THEN implement."
180
- echo ""
181
- echo -e "${DIM}To mark suggestions shown: echo 'true' > $SUGGESTIONS_SHOWN_FILE${NC}"
182
- echo ""
183
- echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
184
- echo ""
185
- exit 1
186
- fi
210
+ local edit_count=$(get_turn_edit_count)
211
+
212
+ if [ "$edit_count" -ge 1 ]; then
213
+ echo ""
214
+ echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
215
+ echo -e "${YELLOW}${BOLD}⛔ GATE 3: ONE EDIT PER TURN${NC}"
216
+ echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
217
+ echo ""
218
+ echo -e "${CYAN}Edits this turn:${NC} $edit_count"
219
+ echo ""
220
+ echo "You can only make ONE edit per user turn."
221
+ echo ""
222
+ echo "This ensures:"
223
+ echo " 1. Easier to track changes"
224
+ echo " 2. Errors caught early"
225
+ echo " 3. User can review incrementally"
226
+ echo ""
227
+ echo "Wait for user's next message before making another edit."
228
+ echo ""
229
+ echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
230
+ echo ""
231
+ return 1
187
232
  fi
188
233
 
189
- # CHECK: One fix at a time (max 1 edit per turn in FIX phase)
190
- if [ "$phase" = "FIX" ]; then
191
- local edit_count=$(get_turn_edit_count)
192
- if [ "$edit_count" -ge 1 ]; then
193
- echo ""
194
- echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
195
- echo -e "${YELLOW}${BOLD}⚠ AUTOWORKFLOW: ONE FIX AT A TIME${NC}"
196
- echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
197
- echo ""
198
- echo -e "${CYAN}Edits this turn:${NC} $edit_count"
199
- echo ""
200
- echo "Fix ONE issue at a time, then verify."
201
- echo ""
202
- echo "This ensures:"
203
- echo " 1. Easier to track what changed"
204
- echo " 2. Errors caught early"
205
- echo " 3. User can review incrementally"
206
- echo ""
207
- echo "Wait for verification to complete before next fix."
208
- echo ""
209
- echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
210
- echo ""
211
- exit 1
212
- fi
213
- # Track this edit
214
- increment_turn_edits > /dev/null
234
+ return 0
235
+ }
236
+
237
+ # Main execution
238
+ main() {
239
+ # STEP 1: Check if workflow is initialized
240
+ if ! is_workflow_initialized; then
241
+ # Auto-initialize with safe defaults
242
+ auto_init_state
243
+
244
+ # After init, BLOCK this edit attempt
245
+ echo ""
246
+ echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
247
+ echo -e "${RED}${BOLD}⛔ AUTOWORKFLOW: EDIT BLOCKED${NC}"
248
+ echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
249
+ echo ""
250
+ echo "Workflow just initialized. Cannot edit yet."
251
+ echo ""
252
+ echo "You must first:"
253
+ echo " 1. Show your analysis/plan to the user"
254
+ echo " 2. Get user approval"
255
+ echo " 3. For features: Show 3-tier suggestions"
256
+ echo " 4. THEN implement one fix at a time"
257
+ echo ""
258
+ echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
259
+ echo ""
260
+ exit 1
215
261
  fi
216
262
 
217
- # All checks passed, allow edit
263
+ # Get current state
264
+ local task_type=$(get_task_type)
265
+ local phase=$(get_phase)
266
+
267
+ # STEP 2: Run all gates
268
+
269
+ # GATE 1: Plan Approval
270
+ if ! check_plan_approval "$task_type"; then
271
+ exit 1
272
+ fi
273
+
274
+ # GATE 2: Suggestions (feature tasks only)
275
+ if ! check_suggestions "$task_type"; then
276
+ exit 1
277
+ fi
278
+
279
+ # GATE 3: One Edit Per Turn
280
+ if ! check_one_edit_per_turn "$task_type"; then
281
+ exit 1
282
+ fi
283
+
284
+ # ALL GATES PASSED - Allow edit and track it
285
+ increment_turn_edits > /dev/null
286
+
287
+ echo ""
288
+ echo -e "${GREEN}✓${NC} Edit allowed (turn edit #$(get_turn_edit_count))"
289
+ echo ""
290
+
218
291
  exit 0
219
292
  }
220
293
 
@@ -15,7 +15,8 @@
15
15
  "Bash(unzip:*)",
16
16
  "Bash(node:*)",
17
17
  "Bash(echo:*)",
18
- "Bash(ls:*)"
18
+ "Bash(ls:*)",
19
+ "Bash(npm view:*)"
19
20
  ]
20
21
  }
21
22
  }
package/README.md CHANGED
@@ -2,7 +2,7 @@
2
2
 
3
3
  > Automated workflow enforcement for Claude Code via hooks and system prompts.
4
4
 
5
- **v3.6.0** - Multi-language support, one-fix-at-a-time enforcement, suggestions gate.
5
+ **v3.7.0** - Fail-closed enforcement: BLOCKS edits by default unless all gates pass.
6
6
 
7
7
  When you use Claude Code with AutoWorkflow, hooks automatically enforce workflow phases, block unauthorized edits, and guide Claude through a structured process for all coding tasks.
8
8
 
@@ -21,6 +21,35 @@ Options:
21
21
 
22
22
  ---
23
23
 
24
+ ## What's New in v3.7.0
25
+
26
+ ### Fail-Closed Enforcement Design
27
+ Previous versions "failed open" - if state wasn't set, edits were allowed. v3.7.0 "fails closed":
28
+
29
+ | Scenario | Before (v3.6) | After (v3.7) |
30
+ |----------|---------------|--------------|
31
+ | No workflow state | ✅ Allowed | ⛔ BLOCKED |
32
+ | Plan not approved | ⛔ Blocked (in PLAN phase only) | ⛔ BLOCKED (always) |
33
+ | No suggestions shown | ⛔ Blocked (in IMPLEMENT only) | ⛔ BLOCKED (always for features) |
34
+ | Multiple edits/turn | ⛔ Blocked (in FIX only) | ⛔ BLOCKED (always) |
35
+
36
+ ### Auto-Initialization with Safe Defaults
37
+ When Claude attempts the first edit without workflow state:
38
+ 1. Auto-creates state with `task-type: feature` (strictest)
39
+ 2. Sets `plan-approved: false`
40
+ 3. Sets `suggestions-shown: false`
41
+ 4. **BLOCKS the edit** immediately
42
+ 5. Claude must show plan/suggestions first, get approval, then try again
43
+
44
+ ### Three Gates (All Must Pass)
45
+ ```
46
+ GATE 1: Plan Approval → Must have user approval
47
+ GATE 2: Suggestions → Must show 3-tier suggestions (features)
48
+ GATE 3: One Edit/Turn → Max 1 edit per user message
49
+ ```
50
+
51
+ ---
52
+
24
53
  ## What's New in v3.6.0
25
54
 
26
55
  ### Multi-Language Project Support
@@ -88,10 +117,11 @@ guardrails:
88
117
  ┌─────────────────────────────────────────────────────────────┐
89
118
  │ HOOKS (Automatic) │
90
119
  │ │
91
- │ UserPromptSubmit → session-check.sh (resume, blueprint)
92
- │ PreToolUse → pre-edit.sh (BLOCKS without approval)
120
+ │ UserPromptSubmit → session-check.sh (resume, turn reset)
121
+ │ PreToolUse → pre-edit.sh (3 gates: approval,
122
+ │ suggestions, one-fix-at-a-time) │
93
123
  │ PreToolUse → pre-commit-check.sh (BLOCKS bad code) │
94
- │ PostToolUse → post-edit.sh (verification loop) │
124
+ │ PostToolUse → post-edit.sh (multi-lang verify) │
95
125
  │ PostToolUse → post-commit.sh (BLUEPRINT reminder) │
96
126
  │ │
97
127
  │ Hooks ENFORCE workflow - they physically block actions │
@@ -140,22 +170,26 @@ ANALYZE → PLAN → CONFIRM → IMPLEMENT → VERIFY → AUDIT → COMMIT → U
140
170
 
141
171
  | Hook | Trigger | Action |
142
172
  |------|---------|--------|
143
- | `session-check.sh` | Every user message | Resume previous session, check BLUEPRINT.md |
144
- | `pre-edit.sh` | Before Write/Edit | **BLOCK if plan not approved** |
145
- | `post-edit.sh` | After Write/Edit | Run verification loop (max 10 iterations) |
173
+ | `session-check.sh` | Every user message | Resume session, reset turn counter |
174
+ | `pre-edit.sh` | Before Write/Edit | **BLOCK** if: no approval, no suggestions, or multiple fixes |
175
+ | `post-edit.sh` | After Write/Edit | Detect project type, run verification |
146
176
  | `pre-commit-check.sh` | Before git commit | **BLOCK if TODO/console.log/errors** |
147
177
  | `post-commit.sh` | After git commit | Remind to update BLUEPRINT.md |
148
178
 
149
179
  ---
150
180
 
151
- ## Blocking Gates
181
+ ## Blocking Gates (Fail-Closed)
182
+
183
+ | Gate | Blocks If | Applies To |
184
+ |------|-----------|------------|
185
+ | **State Init** | No workflow state exists | ALL tasks |
186
+ | **Plan Approval** | User hasn't approved | feature, fix, refactor, perf, security, test |
187
+ | **Suggestions** | 3-tier suggestions not shown | feature tasks |
188
+ | **One Edit/Turn** | Already edited this turn | feature, fix, refactor, perf, security, test |
189
+ | **Verify** | Language-specific errors | ALL (post-edit) |
190
+ | **Pre-Commit** | TODO/FIXME, console.log | ALL commits |
152
191
 
153
- | Gate | Blocks If | Enforced By |
154
- |------|-----------|-------------|
155
- | Plan Approval | User hasn't approved the plan | `pre-edit.sh` (exit 1) |
156
- | Verify | TypeScript or ESLint errors exist | `post-edit.sh` loop |
157
- | Audit | Orphan features or circular dependencies | Required before commit |
158
- | Pre-Commit | TODO/FIXME, console.log, bad format | `pre-commit-check.sh` (exit 1) |
192
+ **Design:** All gates are checked on EVERY edit. Unknown state = strictest defaults.
159
193
 
160
194
  ---
161
195
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "autoworkflow",
3
- "version": "3.6.0",
3
+ "version": "3.7.0",
4
4
  "description": "Automated workflow enforcement for Claude Code via hooks and system prompts",
5
5
  "type": "module",
6
6
  "bin": {