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 +18 -18
- package/package.json +1 -1
- package/plugins/specweave/hooks/lib/common-setup.sh +11 -1
- package/plugins/specweave/hooks/v2/guards/completion-guard.sh +15 -11
- package/plugins/specweave/hooks/v2/guards/increment-duplicate-guard.sh +22 -11
- package/plugins/specweave/hooks/v2/guards/metadata-json-guard.sh +16 -11
- package/plugins/specweave/hooks/v2/guards/spec-validation-guard.sh +20 -16
package/CLAUDE.md
CHANGED
|
@@ -1,10 +1,10 @@
|
|
|
1
|
-
<!-- SW:META template="claude" version="1.0.
|
|
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.
|
|
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.
|
|
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.
|
|
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.
|
|
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.
|
|
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.
|
|
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.
|
|
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.
|
|
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.
|
|
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.
|
|
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.
|
|
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.
|
|
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.
|
|
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.
|
|
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.
|
|
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.
|
|
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.
|
|
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.
|
|
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 -
|
|
2
|
+
# completion-guard.sh - WARN (not block) on direct editing of metadata.json to "completed" status
|
|
3
3
|
#
|
|
4
|
-
# v0.28.63+:
|
|
5
|
-
# Status
|
|
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
|
-
#
|
|
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
|
-
#
|
|
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
|
-
#
|
|
61
|
-
cat << '
|
|
64
|
+
# WARN - trying to set completed without going through ready_for_review (v1.0.37)
|
|
65
|
+
cat << 'WARN_EOF'
|
|
62
66
|
{
|
|
63
|
-
"decision": "
|
|
64
|
-
"
|
|
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
|
-
|
|
67
|
-
exit
|
|
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 -
|
|
2
|
+
# increment-duplicate-guard.sh - WARN (not block) on duplicate increment IDs
|
|
3
3
|
#
|
|
4
|
-
# v0.33.0+:
|
|
5
|
-
# Also
|
|
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
|
-
#
|
|
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
|
-
#
|
|
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
|
|
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,
|
|
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
|
-
|
|
133
|
-
|
|
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
|
|
6
|
-
# This
|
|
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
|
-
#
|
|
16
|
-
#
|
|
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
|
|
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 -
|
|
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 <<
|
|
91
|
+
cat << WARN_EOF
|
|
87
92
|
{
|
|
88
|
-
"decision": "
|
|
89
|
-
"
|
|
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
|
-
|
|
96
|
+
WARN_EOF
|
|
92
97
|
|
|
93
|
-
exit
|
|
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
|
-
#
|
|
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":"
|
|
60
|
-
exit
|
|
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 (
|
|
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":"
|
|
84
|
-
exit
|
|
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":"
|
|
137
|
-
exit
|
|
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":"
|
|
143
|
-
exit
|
|
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":"
|
|
160
|
-
exit
|
|
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
|