specweave 1.0.38 → 1.0.39

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/CLAUDE.md CHANGED
@@ -1,10 +1,10 @@
1
- <!-- SW:META template="claude" version="1.0.34" sections="header,start,autodetect,metarule,rules,workflow,structure,taskformat,secrets,syncing,mapping,testing,limits,troubleshooting,principles,linking,docs" -->
1
+ <!-- SW:META template="claude" version="1.0.38" sections="header,start,autodetect,metarule,rules,workflow,structure,taskformat,secrets,syncing,mapping,testing,limits,troubleshooting,principles,linking,docs" -->
2
2
 
3
- <!-- SW:SECTION:header version="1.0.34" -->
3
+ <!-- SW:SECTION:header version="1.0.38" -->
4
4
  **Framework**: SpecWeave | **Truth**: `spec.md` + `tasks.md`
5
5
  <!-- SW:END:header -->
6
6
 
7
- <!-- SW:SECTION:start version="1.0.34" -->
7
+ <!-- SW:SECTION:start version="1.0.38" -->
8
8
  ## Getting Started
9
9
 
10
10
  **Initial increment**: `0001-project-setup` (auto-created by `specweave init`)
@@ -14,7 +14,7 @@
14
14
  2. **Customize**: Edit spec.md and use for setup tasks
15
15
  <!-- SW:END:start -->
16
16
 
17
- <!-- SW:SECTION:autodetect version="1.0.34" -->
17
+ <!-- SW:SECTION:autodetect version="1.0.38" -->
18
18
  ## Auto-Detection
19
19
 
20
20
  SpecWeave auto-detects product descriptions and routes to `/sw:increment`:
@@ -24,7 +24,7 @@ SpecWeave auto-detects product descriptions and routes to `/sw:increment`:
24
24
  **Opt-out phrases**: "Just brainstorm first" | "Don't plan yet" | "Quick discussion" | "Let's explore ideas"
25
25
  <!-- SW:END:autodetect -->
26
26
 
27
- <!-- SW:SECTION:metarule version="1.0.34" -->
27
+ <!-- SW:SECTION:metarule version="1.0.38" -->
28
28
  ## Meta-Rule: Think-Before-Act
29
29
 
30
30
  **Satisfy dependencies BEFORE dependent operations.**
@@ -35,7 +35,7 @@ SpecWeave auto-detects product descriptions and routes to `/sw:increment`:
35
35
  ```
36
36
  <!-- SW:END:metarule -->
37
37
 
38
- <!-- SW:SECTION:rules version="1.0.34" -->
38
+ <!-- SW:SECTION:rules version="1.0.38" -->
39
39
  ## Rules
40
40
 
41
41
  1. **Files** → `.specweave/increments/####-name/` (spec.md, plan.md, tasks.md at root; reports/, scripts/, logs/ subfolders)
@@ -45,7 +45,7 @@ SpecWeave auto-detects product descriptions and routes to `/sw:increment`:
45
45
  5. **Root clean**: NEVER create .md/reports/scripts in project root → use increment folders
46
46
  <!-- SW:END:rules -->
47
47
 
48
- <!-- SW:SECTION:workflow version="1.0.34" -->
48
+ <!-- SW:SECTION:workflow version="1.0.38" -->
49
49
  ## Workflow
50
50
 
51
51
  `/sw:increment "X"` → `/sw:do` → `/sw:progress` → `/sw:done 0001`
@@ -62,7 +62,7 @@ SpecWeave auto-detects product descriptions and routes to `/sw:increment`:
62
62
  **Natural language**: "Let's build X" → `/sw:increment` | "What's status?" → `/sw:progress` | "We're done" → `/sw:done`
63
63
  <!-- SW:END:workflow -->
64
64
 
65
- <!-- SW:SECTION:structure version="1.0.34" -->
65
+ <!-- SW:SECTION:structure version="1.0.38" -->
66
66
  ## Structure
67
67
 
68
68
  ```
@@ -78,7 +78,7 @@ SpecWeave auto-detects product descriptions and routes to `/sw:increment`:
78
78
  **Multi-repo**: Clone to `/repositories`, not root → `repositories/backend/src/...`
79
79
  <!-- SW:END:structure -->
80
80
 
81
- <!-- SW:SECTION:taskformat version="1.0.34" -->
81
+ <!-- SW:SECTION:taskformat version="1.0.38" -->
82
82
  ## Task Format
83
83
 
84
84
  ```markdown
@@ -88,7 +88,7 @@ SpecWeave auto-detects product descriptions and routes to `/sw:increment`:
88
88
  ```
89
89
  <!-- SW:END:taskformat -->
90
90
 
91
- <!-- SW:SECTION:secrets version="1.0.34" -->
91
+ <!-- SW:SECTION:secrets version="1.0.38" -->
92
92
  ## Secrets Check
93
93
 
94
94
  **BEFORE CLI tools**: Check existing config first!
@@ -99,7 +99,7 @@ gh auth status
99
99
  ```
100
100
  <!-- SW:END:secrets -->
101
101
 
102
- <!-- SW:SECTION:syncing version="1.0.34" -->
102
+ <!-- SW:SECTION:syncing version="1.0.38" -->
103
103
  ## Auto-Sync (Hooks)
104
104
 
105
105
  Post-task: updates tasks.md → living docs → external trackers (if configured)
@@ -107,7 +107,7 @@ Post-task: updates tasks.md → living docs → external trackers (if configured
107
107
  Config: `.specweave/config.json` → `hooks.post_task_completion`
108
108
  <!-- SW:END:syncing -->
109
109
 
110
- <!-- SW:SECTION:mapping version="1.0.34" -->
110
+ <!-- SW:SECTION:mapping version="1.0.38" -->
111
111
  ## GitHub Mapping
112
112
 
113
113
  | SpecWeave | GitHub |
@@ -117,7 +117,7 @@ Config: `.specweave/config.json` → `hooks.post_task_completion`
117
117
  | Task T-XXX | Checkbox |
118
118
  <!-- SW:END:mapping -->
119
119
 
120
- <!-- SW:SECTION:testing version="1.0.34" -->
120
+ <!-- SW:SECTION:testing version="1.0.38" -->
121
121
  ## Testing
122
122
 
123
123
  BDD in tasks.md | Unit >80% | `.test.ts` (Vitest)
@@ -129,13 +129,13 @@ vi.mock('fs', () => ({ readFile: vi.fn() }));
129
129
  ```
130
130
  <!-- SW:END:testing -->
131
131
 
132
- <!-- SW:SECTION:limits version="1.0.34" -->
132
+ <!-- SW:SECTION:limits version="1.0.38" -->
133
133
  ## Limits
134
134
 
135
135
  **Max 1500 lines/file** — extract before adding
136
136
  <!-- SW:END:limits -->
137
137
 
138
- <!-- SW:SECTION:troubleshooting version="1.0.34" -->
138
+ <!-- SW:SECTION:troubleshooting version="1.0.38" -->
139
139
  ## Troubleshooting
140
140
 
141
141
  | Issue | Fix |
@@ -149,7 +149,7 @@ vi.mock('fs', () => ({ readFile: vi.fn() }));
149
149
  | External not syncing | Check `config.json` → `external_tracker_sync: true` |
150
150
  <!-- SW:END:troubleshooting -->
151
151
 
152
- <!-- SW:SECTION:principles version="1.0.34" -->
152
+ <!-- SW:SECTION:principles version="1.0.38" -->
153
153
  ## Principles
154
154
 
155
155
  1. **Spec-first**: `/sw:increment` before coding
@@ -159,7 +159,7 @@ vi.mock('fs', () => ({ readFile: vi.fn() }));
159
159
  5. **Clean**: All files in increment folders
160
160
  <!-- SW:END:principles -->
161
161
 
162
- <!-- SW:SECTION:linking version="1.0.34" -->
162
+ <!-- SW:SECTION:linking version="1.0.38" -->
163
163
  ## Bidirectional Linking
164
164
 
165
165
  Tasks ↔ User Stories auto-linked via AC-IDs: `AC-US1-01` → `US-001`
@@ -167,7 +167,7 @@ Tasks ↔ User Stories auto-linked via AC-IDs: `AC-US1-01` → `US-001`
167
167
  Task format: `**AC**: AC-US1-01, AC-US1-02` (CRITICAL for linking)
168
168
  <!-- SW:END:linking -->
169
169
 
170
- <!-- SW:SECTION:docs version="1.0.34" -->
170
+ <!-- SW:SECTION:docs version="1.0.38" -->
171
171
  ## Docs
172
172
 
173
173
  [spec-weave.com](https://spec-weave.com) | `.specweave/docs/internal/`
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "specweave",
3
- "version": "1.0.38",
3
+ "version": "1.0.39",
4
4
  "description": "Spec-driven development framework for Claude Code. AI-native workflow with living documentation, intelligent agents, and multilingual support (9 languages). Enterprise-grade traceability with permanent specs and temporary increments.",
5
5
  "type": "module",
6
6
  "main": "dist/index.js",
@@ -77,7 +77,8 @@ guard_allow() {
77
77
  exit 0
78
78
  }
79
79
 
80
- # Block the tool call with reason
80
+ # Block the tool call with reason (DEPRECATED v1.0.37 - use guard_warn instead)
81
+ # NOTE: Blocking is discouraged. Use guard_warn for most cases.
81
82
  guard_block() {
82
83
  local reason="$1"
83
84
  reason=$(echo "$reason" | sed 's/"/\\"/g' | sed ':a;N;$!ba;s/\n/\\n/g')
@@ -85,6 +86,15 @@ guard_block() {
85
86
  exit 2
86
87
  }
87
88
 
89
+ # Warn but ALLOW the tool call (v1.0.37+)
90
+ # This is the PREFERRED approach - never block operations, always allow with warnings.
91
+ guard_warn() {
92
+ local message="$1"
93
+ message=$(echo "$message" | sed 's/"/\\"/g' | sed ':a;N;$!ba;s/\n/\\n/g')
94
+ printf '{"decision":"allow","message":"%s"}\n' "$message"
95
+ exit 0
96
+ }
97
+
88
98
  # ============================================================================
89
99
  # SIMPLE LOGGING (optional, writes to .specweave/logs/hooks.log)
90
100
  # ============================================================================
@@ -1,12 +1,16 @@
1
1
  #!/bin/bash
2
- # completion-guard.sh - Block direct editing of metadata.json to "completed" status
2
+ # completion-guard.sh - WARN (not block) on direct editing of metadata.json to "completed" status
3
3
  #
4
- # v0.28.63+: Prevents the auto-completion bug by blocking direct status changes to completed.
5
- # Status MUST go through ready_for_review first, and only /sw:done can mark completed.
4
+ # v0.28.63+: Detects the auto-completion bug by warning on direct status changes to completed.
5
+ # Status SHOULD go through ready_for_review first, and /sw:done marks completed with validation.
6
6
  #
7
- # PreToolUse hook - can BLOCK the tool call by returning non-zero exit code
7
+ # v1.0.37+: CRITICAL CHANGE - Now WARNS instead of BLOCKING!
8
+ # User feedback: "you MUST NEVER block such operations... do at least warning"
9
+ # Business logic and validation should be in scripts/agents, not hard blocks.
8
10
  #
9
- # IMPORTANT: This is a safety guard. Exit 0 allows, exit 2 blocks.
11
+ # PreToolUse hook - WARNS but ALLOWS the tool call
12
+ #
13
+ # IMPORTANT: This is a safety guard. Exit 0 allows (with warning if needed).
10
14
  # All exit paths MUST output JSON for proper Claude Code handling.
11
15
  set +e
12
16
 
@@ -57,14 +61,14 @@ if echo "$NEW_CONTENT" | grep -q '"status"[[:space:]]*:[[:space:]]*"completed"';
57
61
  fi
58
62
  fi
59
63
 
60
- # BLOCK - trying to set completed without going through ready_for_review
61
- cat << 'BLOCK_EOF'
64
+ # WARN - trying to set completed without going through ready_for_review (v1.0.37)
65
+ cat << 'WARN_EOF'
62
66
  {
63
- "decision": "block",
64
- "reason": "🚫 BLOCKED: Direct status change to \"completed\" is not allowed (v0.28.63+)\n\nYou cannot directly set status to \"completed\" in metadata.json.\n\nCORRECT WORKFLOW:\n1. All tasks completed → status auto-transitions to \"ready_for_review\"\n2. Run /sw:done <increment-id> with explicit user confirmation\n3. Only then does status become \"completed\"\n\nWHY THIS MATTERS:\n• Ensures all ACs are checked in spec.md before closure\n• Requires explicit user approval\n• Maintains audit trail (approvedAt timestamp)\n\n🔧 If implementing closure logic, use:\n MetadataManager.updateStatus(incrementId, IncrementStatus.COMPLETED)"
67
+ "decision": "allow",
68
+ "message": "⚠️ WARNING: Direct status change to \"completed\" detected!\n\n🚨 RECOMMENDED WORKFLOW:\n1. All tasks completed → status auto-transitions to \"ready_for_review\"\n2. Run /sw:done <increment-id> with explicit user confirmation\n3. Only then does status become \"completed\"\n\nWHY THIS MATTERS:\n• Ensures all ACs are checked in spec.md before closure\n• Requires explicit user approval\n• Maintains audit trail (approvedAt timestamp)\n\n💡 If implementing closure logic, use:\n MetadataManager.updateStatus(incrementId, IncrementStatus.COMPLETED)\n\nOperation ALLOWED - proceeding with status change."
65
69
  }
66
- BLOCK_EOF
67
- exit 2 # Block the tool call
70
+ WARN_EOF
71
+ exit 0 # ALLOW with warning (v1.0.37)
68
72
  fi
69
73
 
70
74
  # Allow other edits to metadata.json
@@ -1,16 +1,16 @@
1
1
  #!/bin/bash
2
- # increment-duplicate-guard.sh - Block creation of duplicate increment IDs
2
+ # increment-duplicate-guard.sh - WARN (not block) on duplicate increment IDs
3
3
  #
4
- # v0.33.0+: Prevents duplicate increment numbers (0121 and 0121 both existing)
5
- # Also prevents 0001 and 0001E collisions (they share the same base number)
4
+ # v0.33.0+: Detects duplicate increment numbers (0121 and 0121 both existing)
5
+ # Also detects 0001 and 0001E collisions (they share the same base number)
6
6
  #
7
- # PreToolUse hook for Write tool - BLOCKS the tool call if duplicate detected
7
+ # v1.0.37+: CRITICAL CHANGE - Now WARNS instead of BLOCKING!
8
+ # User feedback: "you MUST NEVER block such operations... do at least warning"
9
+ # Business logic and validation should be in scripts/agents, not hard blocks.
8
10
  #
9
- # CRITICAL: This guards against the BUG where two increments get the same ID:
10
- # - 0121-ado-jira-feature-parity-p2-p3
11
- # - 0121-intelligent-living-docs-content
11
+ # PreToolUse hook for Write tool - WARNS but ALLOWS the tool call
12
12
  #
13
- # Exit 0 = allow (with JSON), Exit 2 = block (with JSON)
13
+ # Exit 0 = allow (with JSON warning message if duplicate detected)
14
14
  set +e
15
15
 
16
16
  [[ "${SPECWEAVE_DISABLE_HOOKS:-0}" == "1" ]] && echo '{"decision":"allow"}' && exit 0
@@ -32,6 +32,15 @@ if [[ "$FILE_PATH" != *.specweave/increments/* ]]; then
32
32
  exit 0 # Not an increment file - allow
33
33
  fi
34
34
 
35
+ # CRITICAL FIX (v1.0.37): ALWAYS allow metadata.json writes!
36
+ # metadata.json is the FIRST file created for any increment - it MUST succeed.
37
+ # Duplicate detection only makes sense for the INCREMENT FOLDER, not individual files.
38
+ # Once the folder exists, any file writes within it should be allowed.
39
+ if [[ "$FILE_PATH" == *metadata.json ]]; then
40
+ echo '{"decision":"allow","message":"metadata.json write allowed (increment creation)"}'
41
+ exit 0
42
+ fi
43
+
35
44
  # Extract the increment folder name from the path
36
45
  # Pattern: .specweave/increments/XXXX-name/file.md or .specweave/increments/XXXX-name/subfolder/file
37
46
  # We need to extract "XXXX-name" part
@@ -109,7 +118,7 @@ for DIR in "${DIRS_TO_CHECK[@]}"; do
109
118
  done < <(find "$DIR" -maxdepth 1 -type d -name "${INCREMENT_NUM}*" -print0 2>/dev/null)
110
119
  done
111
120
 
112
- # If duplicates found, BLOCK the operation and provide the correct number to use
121
+ # If duplicates found, WARN but ALLOW the operation (v1.0.37+: no blocking!)
113
122
  if [[ ${#FOUND_DUPLICATES[@]} -gt 0 ]]; then
114
123
  # Format duplicates for JSON
115
124
  DUP_LIST=""
@@ -129,8 +138,10 @@ if [[ ${#FOUND_DUPLICATES[@]} -gt 0 ]]; then
129
138
  FOLDER_NAME_PART=$(echo "$INCREMENT_FOLDER" | sed 's/^[0-9]\{3,4\}E\?-//')
130
139
  SUGGESTED_FOLDER="${NEXT_NUM_PADDED}-${FOLDER_NAME_PART}"
131
140
 
132
- printf '{"decision":"block","reason":"🚫 DUPLICATE INCREMENT ID - Use this instead:\\n\\n✅ CORRECT: %s\\n❌ ATTEMPTED: %s\\n\\nNumber %s already exists:%s\\n\\n🔧 IMMEDIATE FIX: Replace your file path with:\\n .specweave/increments/%s/...\\n\\nThe guard calculated the next available number for you."}\n' "$SUGGESTED_FOLDER" "$INCREMENT_FOLDER" "$INCREMENT_NUM" "$DUP_LIST" "$SUGGESTED_FOLDER"
133
- exit 2 # Block the tool call
141
+ # v1.0.37: ALLOW with WARNING instead of blocking
142
+ # User can still proceed - the warning provides guidance
143
+ printf '{"decision":"allow","message":"⚠️ DUPLICATE INCREMENT ID DETECTED\\n\\n✅ SUGGESTED: %s\\n⚠️ CURRENT: %s\\n\\nNumber %s already exists:%s\\n\\n💡 RECOMMENDATION: Consider using .specweave/increments/%s/ instead.\\n\\nOperation ALLOWED - proceeding with current path."}\n' "$SUGGESTED_FOLDER" "$INCREMENT_FOLDER" "$INCREMENT_NUM" "$DUP_LIST" "$SUGGESTED_FOLDER"
144
+ exit 0 # ALLOW with warning (v1.0.37: no blocking!)
134
145
  fi
135
146
 
136
147
  # No duplicates - allow
@@ -2,8 +2,8 @@
2
2
  #
3
3
  # metadata-json-guard.sh
4
4
  #
5
- # Pre-tool-use hook that ensures metadata.json exists BEFORE spec.md can be created.
6
- # This prevents increments from being created without proper metadata.
5
+ # Pre-tool-use hook that WARNS (not blocks) if metadata.json is missing before spec.md creation.
6
+ # This helps ensure proper increment creation workflow.
7
7
  #
8
8
  # ROOT CAUSE: When Claude creates increments via user prompt (not /sw:increment),
9
9
  # metadata.json may be forgotten, causing:
@@ -12,18 +12,23 @@
12
12
  # - External sync fails (GitHub/Jira/ADO)
13
13
  # - All increment commands fail
14
14
  #
15
- # SOLUTION: Block spec.md creation if metadata.json doesn't exist in same increment folder.
16
- # Claude MUST create metadata.json FIRST, then spec.md.
15
+ # v1.0.37+: CRITICAL CHANGE - Now WARNS instead of BLOCKING!
16
+ # User feedback: "you MUST NEVER block such operations... do at least warning"
17
+ # Business logic and validation should be in scripts/agents, not hard blocks.
18
+ #
19
+ # SOLUTION: WARN if spec.md is created without metadata.json, but ALLOW the operation.
20
+ # The warning prompts Claude to create metadata.json immediately after.
17
21
  #
18
22
  # Activation:
19
23
  # - tool_name: Write
20
24
  # - file_path matches: .specweave/increments/*/spec.md
21
25
  #
22
- # Returns exit code 2 (block) if metadata.json missing, 0 (allow) otherwise.
26
+ # Returns exit 0 (allow) with warning message if metadata.json missing
23
27
  #
24
28
  # Bypass: Set SPECWEAVE_FORCE_METADATA=1 to skip validation
25
29
  #
26
30
  # v0.34.0 - Initial implementation based on user project bug analysis
31
+ # v1.0.37 - Changed from BLOCK to WARN (allow with warning message)
27
32
 
28
33
  set +e # CRITICAL: Never use set -e in hooks (causes cascading failures)
29
34
 
@@ -80,14 +85,14 @@ if [ -f "$METADATA_PATH" ]; then
80
85
  exit 0
81
86
  fi
82
87
 
83
- # metadata.json doesn't exist - BLOCK spec.md creation
88
+ # metadata.json doesn't exist - WARN but ALLOW spec.md creation (v1.0.37)
84
89
  NOW=$(date -u +"%Y-%m-%dT%H:%M:%SZ")
85
90
 
86
- cat << BLOCK_EOF
91
+ cat << WARN_EOF
87
92
  {
88
- "decision": "block",
89
- "reason": "🚫 BLOCKED: Cannot create spec.md without metadata.json\n\n⚠️ CRITICAL RULE: metadata.json MUST be created FIRST!\n\nWithout metadata.json:\n - ❌ Status tracking broken\n - ❌ WIP limits don't work\n - ❌ External sync fails (GitHub/Jira/ADO)\n - ❌ All increment commands fail\n\n📋 CORRECT WORKFLOW:\n1. Create metadata.json FIRST:\n Write({\n file_path: \"${METADATA_PATH}\",\n content: {\n \"id\": \"${INCREMENT_ID}\",\n \"status\": \"planned\",\n \"type\": \"feature\",\n \"priority\": \"P1\",\n \"created\": \"${NOW}\",\n \"lastActivity\": \"${NOW}\",\n \"testMode\": \"TDD\",\n \"coverageTarget\": 95,\n \"feature_id\": null,\n \"epic_id\": null,\n \"externalLinks\": {}\n }\n })\n\n2. THEN create spec.md\n\n📖 See: CLAUDE.md section '3. metadata.json is MANDATORY'\n\n💡 Bypass: Set SPECWEAVE_FORCE_METADATA=1 to skip this validation"
93
+ "decision": "allow",
94
+ "message": "⚠️ WARNING: metadata.json MISSING - Creating spec.md without it!\n\n🚨 IMMEDIATE ACTION REQUIRED:\nCreate metadata.json NOW for this increment to work properly.\n\nWithout metadata.json:\n - ❌ Status tracking broken\n - ❌ WIP limits don't work\n - ❌ External sync fails (GitHub/Jira/ADO)\n - ❌ All increment commands fail\n\n📋 CREATE metadata.json:\n Write({\n file_path: \"${METADATA_PATH}\",\n content: {\n \"id\": \"${INCREMENT_ID}\",\n \"status\": \"planned\",\n \"type\": \"feature\",\n \"priority\": \"P1\",\n \"created\": \"${NOW}\",\n \"lastActivity\": \"${NOW}\",\n \"testMode\": \"TDD\",\n \"coverageTarget\": 95,\n \"feature_id\": null,\n \"epic_id\": null,\n \"externalLinks\": {}\n }\n })\n\nOperation ALLOWED - proceeding with spec.md write."
90
95
  }
91
- BLOCK_EOF
96
+ WARN_EOF
92
97
 
93
- exit 2
98
+ exit 0
@@ -10,7 +10,11 @@
10
10
  # - tool_name: Write
11
11
  # - file_path matches: .specweave/increments/*/spec.md OR .specweave/docs/internal/specs/*/
12
12
  #
13
- # Exit 0 = allow (with JSON), Exit 2 = block (with JSON)
13
+ # v1.0.37+: CRITICAL CHANGE - All validations now WARN instead of BLOCK!
14
+ # User feedback: "you MUST NEVER block such operations... do at least warning"
15
+ # Business logic and validation should be in scripts/agents, not hard blocks.
16
+ #
17
+ # Exit 0 = allow (with JSON warning message if validation fails)
14
18
  #
15
19
  # Bypasses:
16
20
  # - SPECWEAVE_DISABLE_HOOKS=1 - Disable all hooks
@@ -53,11 +57,11 @@ fi
53
57
  # ============================================================================
54
58
  if [[ "$HOOK_FILE_PATH" =~ \.specweave/increments/[0-9]{3,4}E?-[^/]+/spec\.md$ ]]; then
55
59
 
56
- # Check for unresolved {{...}} placeholders
60
+ # Check for unresolved {{...}} placeholders - WARN only (v1.0.37)
57
61
  if echo "$HOOK_CONTENT" | grep -qE '\{\{[A-Z_]+\}\}'; then
58
62
  PLACEHOLDERS=$(echo "$HOOK_CONTENT" | grep -oE '\{\{[A-Z_]+\}\}' | sort -u | tr '\n' ', ' | sed 's/,$//')
59
- printf '{"decision":"block","reason":"🚫 UNRESOLVED PLACEHOLDERS\\n\\nFound: %s\\n\\n🔧 FIX: Replace placeholders with actual values.\\nRun: specweave context projects\\nThen use values from the JSON output."}\n' "$PLACEHOLDERS"
60
- exit 2
63
+ printf '{"decision":"allow","message":"⚠️ UNRESOLVED PLACEHOLDERS DETECTED\\n\\nFound: %s\\n\\n🔧 FIX: Replace placeholders with actual values.\\nRun: specweave context projects\\nThen use values from the JSON output.\\n\\nOperation ALLOWED - proceeding anyway."}\n' "$PLACEHOLDERS"
64
+ exit 0
61
65
  fi
62
66
 
63
67
  # Check for **Project**: field in User Stories (soft validation - warn, don't block)
@@ -78,10 +82,10 @@ if [[ "$HOOK_FILE_PATH" =~ \.specweave/increments/[0-9]{3,4}E?-[^/]+/spec\.md$ ]
78
82
  exit 0
79
83
  fi
80
84
 
81
- # Check for comma-separated projects (forbidden - 1:1 mapping required)
85
+ # Check for comma-separated projects (1:1 mapping required) - WARN only (v1.0.37)
82
86
  if echo "$HOOK_CONTENT" | grep -qE '^\*\*Project\*\*:.*,'; then
83
- printf '{"decision":"block","reason":"🚫 MULTIPLE PROJECTS IN ONE US\\n\\nEach User Story MUST map to exactly ONE project.\\n\\n🔧 FIX: Split cross-project features into separate User Stories:\\n\\nWRONG:\\n### US-001: OAuth Implementation\\n**Project**: frontend, backend\\n\\nCORRECT:\\n### US-001: OAuth Login Form\\n**Project**: frontend\\n\\n### US-002: OAuth API\\n**Project**: backend"}\n'
84
- exit 2
87
+ printf '{"decision":"allow","message":"⚠️ MULTIPLE PROJECTS IN ONE US DETECTED\\n\\nEach User Story should map to exactly ONE project.\\n\\n💡 RECOMMENDATION: Split cross-project features into separate User Stories:\\n\\nWRONG:\\n### US-001: OAuth Implementation\\n**Project**: frontend, backend\\n\\nCORRECT:\\n### US-001: OAuth Login Form\\n**Project**: frontend\\n\\n### US-002: OAuth API\\n**Project**: backend\\n\\nOperation ALLOWED - proceeding anyway."}\n'
88
+ exit 0
85
89
  fi
86
90
 
87
91
  # Check structure level to validate **Board**: fields
@@ -131,19 +135,19 @@ if [[ "$HOOK_FILE_PATH" =~ \.specweave/docs/internal/specs/([^/]+)/ ]]; then
131
135
  [[ "$PROJECT_NAME" == "_features" ]] && echo '{"decision":"allow"}' && exit 0
132
136
  [[ "$PROJECT_NAME" == "_archive" ]] && echo '{"decision":"allow"}' && exit 0
133
137
 
134
- # Check for template placeholders
138
+ # Check for template placeholders - WARN only (v1.0.37)
135
139
  if [[ "$PROJECT_NAME" =~ \{\{.*\}\} ]]; then
136
- printf '{"decision":"block","reason":"🚫 UNRESOLVED PLACEHOLDER: %s\\n\\n🔧 FIX: Replace {{...}} with actual project name"}\n' "$PROJECT_NAME"
137
- exit 2
140
+ printf '{"decision":"allow","message":"⚠️ UNRESOLVED PLACEHOLDER: %s\\n\\n🔧 FIX: Replace {{...}} with actual project name\\n\\nOperation ALLOWED - proceeding anyway."}\n' "$PROJECT_NAME"
141
+ exit 0
138
142
  fi
139
143
 
140
- # Check for comma-separated (invalid)
144
+ # Check for comma-separated (invalid) - WARN only (v1.0.37)
141
145
  if [[ "$PROJECT_NAME" =~ , ]]; then
142
- printf '{"decision":"block","reason":"🚫 COMMA-SEPARATED PROJECTS: %s\\n\\nEach User Story = ONE project folder.\\n\\n🔧 FIX: Split into separate specs"}\n' "$PROJECT_NAME"
143
- exit 2
146
+ printf '{"decision":"allow","message":"⚠️ COMMA-SEPARATED PROJECTS: %s\\n\\nEach User Story should have ONE project folder.\\n\\n💡 RECOMMENDATION: Split into separate specs\\n\\nOperation ALLOWED - proceeding anyway."}\n' "$PROJECT_NAME"
147
+ exit 0
144
148
  fi
145
149
 
146
- # Check for common example/placeholder names
150
+ # Check for common example/placeholder names - WARN only (v1.0.37)
147
151
  EXAMPLE_NAMES="frontend-app|backend-api|mobile-app|shared-lib|acme-corp|my-app|myapp|example-project|test-project"
148
152
  if [[ "$PROJECT_NAME" =~ ^($EXAMPLE_NAMES)$ ]]; then
149
153
  # Try to get valid projects from config
@@ -156,8 +160,8 @@ if [[ "$HOOK_FILE_PATH" =~ \.specweave/docs/internal/specs/([^/]+)/ ]]; then
156
160
 
157
161
  if [[ "$IS_CONFIGURED" != "true" ]]; then
158
162
  VALID_PROJECTS=$(jq -r '.multiProject.projects | keys | join(", ") // .project.name // "specweave"' "$CONFIG_FILE" 2>/dev/null || echo "specweave")
159
- printf '{"decision":"block","reason":"🚫 EXAMPLE PROJECT NAME: %s\\n\\nThis looks like a placeholder/example name from documentation.\\n\\nConfigured projects: %s\\n\\n🔧 FIX: Edit spec.md and use a real project name"}\n' "$PROJECT_NAME" "$VALID_PROJECTS"
160
- exit 2
163
+ printf '{"decision":"allow","message":"⚠️ EXAMPLE PROJECT NAME DETECTED: %s\\n\\nThis looks like a placeholder/example name from documentation.\\n\\nConfigured projects: %s\\n\\n💡 RECOMMENDATION: Edit spec.md and use a real project name\\n\\nOperation ALLOWED - proceeding anyway."}\n' "$PROJECT_NAME" "$VALID_PROJECTS"
164
+ exit 0
161
165
  fi
162
166
  fi
163
167
  fi