specweave 0.28.7 → 0.28.11
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/dist/src/cli/commands/init.d.ts.map +1 -1
- package/dist/src/cli/commands/init.js +17 -1
- package/dist/src/cli/commands/init.js.map +1 -1
- package/dist/src/cli/helpers/init/index.d.ts +1 -0
- package/dist/src/cli/helpers/init/index.d.ts.map +1 -1
- package/dist/src/cli/helpers/init/index.js +2 -0
- package/dist/src/cli/helpers/init/index.js.map +1 -1
- package/dist/src/cli/helpers/init/translation-config.d.ts +53 -0
- package/dist/src/cli/helpers/init/translation-config.d.ts.map +1 -0
- package/dist/src/cli/helpers/init/translation-config.js +216 -0
- package/dist/src/cli/helpers/init/translation-config.js.map +1 -0
- package/dist/src/cli/helpers/init/types.d.ts +33 -0
- package/dist/src/cli/helpers/init/types.d.ts.map +1 -1
- package/dist/src/core/config/types.d.ts +115 -0
- package/dist/src/core/config/types.d.ts.map +1 -1
- package/dist/src/core/config/types.js.map +1 -1
- package/dist/src/core/repo-structure/repo-id-generator.d.ts +24 -95
- package/dist/src/core/repo-structure/repo-id-generator.d.ts.map +1 -1
- package/dist/src/core/repo-structure/repo-id-generator.js +31 -223
- package/dist/src/core/repo-structure/repo-id-generator.js.map +1 -1
- package/dist/src/core/repo-structure/repo-structure-manager.d.ts.map +1 -1
- package/dist/src/core/repo-structure/repo-structure-manager.js +12 -46
- package/dist/src/core/repo-structure/repo-structure-manager.js.map +1 -1
- package/dist/src/utils/multi-repo-detector.d.ts +85 -0
- package/dist/src/utils/multi-repo-detector.d.ts.map +1 -0
- package/dist/src/utils/multi-repo-detector.js +264 -0
- package/dist/src/utils/multi-repo-detector.js.map +1 -0
- package/package.json +1 -1
- package/plugins/specweave/agents/pm/AGENT.md +141 -0
- package/plugins/specweave/commands/specweave-done.md +28 -0
- package/plugins/specweave/hooks/hooks.json +12 -0
- package/plugins/specweave/hooks/post-increment-completion.sh +59 -0
- package/plugins/specweave/hooks/post-increment-planning.sh +95 -51
- package/plugins/specweave/hooks/pre-task-completion-edit.sh +355 -0
- package/plugins/specweave/lib/hooks/sync-living-docs.js +43 -0
- package/plugins/specweave/skills/umbrella-repo-detector/SKILL.md +219 -0
- package/plugins/specweave-github/hooks/.specweave/logs/hooks-debug.log +18 -0
- package/plugins/specweave-infrastructure/skills/hetzner-provisioner/README.md +1 -1
- package/plugins/specweave-release/hooks/.specweave/logs/dora-tracking.log +27 -0
|
@@ -0,0 +1,355 @@
|
|
|
1
|
+
#!/bin/bash
|
|
2
|
+
#
|
|
3
|
+
# pre-task-completion-edit.sh (v1.0.0)
|
|
4
|
+
#
|
|
5
|
+
# QUALITY GATE: Validates AC completion BEFORE allowing task status change to completed
|
|
6
|
+
#
|
|
7
|
+
# Triggered by: PreToolUse:Edit on .specweave/increments/*/tasks.md
|
|
8
|
+
#
|
|
9
|
+
# WORKFLOW:
|
|
10
|
+
# =========
|
|
11
|
+
# 1. Edit tool called on tasks.md
|
|
12
|
+
# 2. This hook fires (PreToolUse - BEFORE the edit executes)
|
|
13
|
+
# 3. Detect if edit is marking a task as completed ([ ] → [x])
|
|
14
|
+
# 4. Extract task's "Satisfies ACs" (e.g., AC-US1-01, AC-US1-02)
|
|
15
|
+
# 5. Verify those ACs are checked [x] in spec.md
|
|
16
|
+
# 6. If ACs verified → Allow edit (continue: true)
|
|
17
|
+
# 7. If ACs NOT verified → BLOCK edit (continue: false)
|
|
18
|
+
#
|
|
19
|
+
# ENFORCEMENT:
|
|
20
|
+
# ============
|
|
21
|
+
# Tasks CANNOT be marked complete unless their linked ACs are verified.
|
|
22
|
+
# This is the ONLY enforcement point - cannot be bypassed.
|
|
23
|
+
#
|
|
24
|
+
# See: ADR-0xxx (AC Verification Quality Gate)
|
|
25
|
+
|
|
26
|
+
set +e # CRITICAL: Never crash Claude Code
|
|
27
|
+
|
|
28
|
+
# ============================================================================
|
|
29
|
+
# EMERGENCY KILL SWITCH
|
|
30
|
+
# ============================================================================
|
|
31
|
+
if [[ "${SPECWEAVE_DISABLE_HOOKS:-0}" == "1" ]]; then
|
|
32
|
+
cat <<EOF
|
|
33
|
+
{"continue": true}
|
|
34
|
+
EOF
|
|
35
|
+
exit 0
|
|
36
|
+
fi
|
|
37
|
+
|
|
38
|
+
# ============================================================================
|
|
39
|
+
# RECURSION PREVENTION (v0.26.0 pattern)
|
|
40
|
+
# ============================================================================
|
|
41
|
+
find_project_root() {
|
|
42
|
+
local dir="$PWD"
|
|
43
|
+
while [[ "$dir" != "/" ]]; do
|
|
44
|
+
if [[ -d "$dir/.specweave" ]]; then
|
|
45
|
+
echo "$dir"
|
|
46
|
+
return 0
|
|
47
|
+
fi
|
|
48
|
+
dir=$(dirname "$dir")
|
|
49
|
+
done
|
|
50
|
+
echo "$PWD"
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
PROJECT_ROOT=$(find_project_root)
|
|
54
|
+
|
|
55
|
+
if [[ ! -d "$PROJECT_ROOT/.specweave" ]]; then
|
|
56
|
+
cat <<EOF
|
|
57
|
+
{"continue": true}
|
|
58
|
+
EOF
|
|
59
|
+
exit 0
|
|
60
|
+
fi
|
|
61
|
+
|
|
62
|
+
RECURSION_GUARD_FILE="$PROJECT_ROOT/.specweave/state/.hook-recursion-guard"
|
|
63
|
+
if [[ -f "$RECURSION_GUARD_FILE" ]]; then
|
|
64
|
+
cat <<EOF
|
|
65
|
+
{"continue": true}
|
|
66
|
+
EOF
|
|
67
|
+
exit 0
|
|
68
|
+
fi
|
|
69
|
+
|
|
70
|
+
# ============================================================================
|
|
71
|
+
# SETUP
|
|
72
|
+
# ============================================================================
|
|
73
|
+
LOGS_DIR="$PROJECT_ROOT/.specweave/logs"
|
|
74
|
+
DEBUG_LOG="$LOGS_DIR/hooks-debug.log"
|
|
75
|
+
mkdir -p "$LOGS_DIR" 2>/dev/null || true
|
|
76
|
+
|
|
77
|
+
echo "[$(date)] pre-task-completion-edit: Hook triggered" >> "$DEBUG_LOG" 2>/dev/null || true
|
|
78
|
+
|
|
79
|
+
# ============================================================================
|
|
80
|
+
# CAPTURE INPUT (PreToolUse receives tool_input JSON)
|
|
81
|
+
# ============================================================================
|
|
82
|
+
STDIN_DATA=$(cat)
|
|
83
|
+
|
|
84
|
+
# Log the input for debugging
|
|
85
|
+
echo "[$(date)] pre-task-completion-edit: Input: $STDIN_DATA" >> "$DEBUG_LOG" 2>/dev/null || true
|
|
86
|
+
|
|
87
|
+
# ============================================================================
|
|
88
|
+
# EXTRACT EDIT DETAILS
|
|
89
|
+
# ============================================================================
|
|
90
|
+
# PreToolUse:Edit receives: { "tool_input": { "file_path": "...", "old_string": "...", "new_string": "..." } }
|
|
91
|
+
|
|
92
|
+
FILE_PATH=""
|
|
93
|
+
OLD_STRING=""
|
|
94
|
+
NEW_STRING=""
|
|
95
|
+
|
|
96
|
+
if command -v jq &>/dev/null; then
|
|
97
|
+
FILE_PATH=$(echo "$STDIN_DATA" | jq -r '.tool_input.file_path // empty' 2>/dev/null || echo "")
|
|
98
|
+
OLD_STRING=$(echo "$STDIN_DATA" | jq -r '.tool_input.old_string // empty' 2>/dev/null || echo "")
|
|
99
|
+
NEW_STRING=$(echo "$STDIN_DATA" | jq -r '.tool_input.new_string // empty' 2>/dev/null || echo "")
|
|
100
|
+
else
|
|
101
|
+
# Fallback: basic regex extraction
|
|
102
|
+
FILE_PATH=$(echo "$STDIN_DATA" | grep -o '"file_path"[[:space:]]*:[[:space:]]*"[^"]*"' | head -1 | sed 's/.*"\([^"]*\)".*/\1/' || echo "")
|
|
103
|
+
fi
|
|
104
|
+
|
|
105
|
+
echo "[$(date)] pre-task-completion-edit: file_path=$FILE_PATH" >> "$DEBUG_LOG" 2>/dev/null || true
|
|
106
|
+
|
|
107
|
+
# ============================================================================
|
|
108
|
+
# EARLY EXIT: Only process tasks.md in active increments
|
|
109
|
+
# ============================================================================
|
|
110
|
+
if [[ "$FILE_PATH" != *"/tasks.md" ]]; then
|
|
111
|
+
echo "[$(date)] pre-task-completion-edit: Not tasks.md, skipping" >> "$DEBUG_LOG" 2>/dev/null || true
|
|
112
|
+
cat <<EOF
|
|
113
|
+
{"continue": true}
|
|
114
|
+
EOF
|
|
115
|
+
exit 0
|
|
116
|
+
fi
|
|
117
|
+
|
|
118
|
+
if [[ "$FILE_PATH" != *"/.specweave/increments/"* ]] && [[ "$FILE_PATH" != *".specweave/increments/"* ]]; then
|
|
119
|
+
echo "[$(date)] pre-task-completion-edit: Not in increments/, skipping" >> "$DEBUG_LOG" 2>/dev/null || true
|
|
120
|
+
cat <<EOF
|
|
121
|
+
{"continue": true}
|
|
122
|
+
EOF
|
|
123
|
+
exit 0
|
|
124
|
+
fi
|
|
125
|
+
|
|
126
|
+
if [[ "$FILE_PATH" == *"/_archive/"* ]]; then
|
|
127
|
+
echo "[$(date)] pre-task-completion-edit: Archived increment, skipping" >> "$DEBUG_LOG" 2>/dev/null || true
|
|
128
|
+
cat <<EOF
|
|
129
|
+
{"continue": true}
|
|
130
|
+
EOF
|
|
131
|
+
exit 0
|
|
132
|
+
fi
|
|
133
|
+
|
|
134
|
+
# ============================================================================
|
|
135
|
+
# DETECT TASK COMPLETION PATTERN
|
|
136
|
+
# ============================================================================
|
|
137
|
+
# Check if edit is changing status from pending to completed:
|
|
138
|
+
# old_string: "**Status**: [ ] pending" or "**Status**: [ ]"
|
|
139
|
+
# new_string: "**Status**: [x] completed" or "**Status**: [x]"
|
|
140
|
+
|
|
141
|
+
IS_COMPLETION=false
|
|
142
|
+
|
|
143
|
+
# Pattern 1: Full status line change
|
|
144
|
+
if [[ "$OLD_STRING" == *"**Status**:"*"[ ]"* ]] && [[ "$NEW_STRING" == *"**Status**:"*"[x]"* ]]; then
|
|
145
|
+
IS_COMPLETION=true
|
|
146
|
+
fi
|
|
147
|
+
|
|
148
|
+
# Pattern 2: Just checkbox change (some formats)
|
|
149
|
+
if [[ "$OLD_STRING" == *"[ ] pending"* ]] && [[ "$NEW_STRING" == *"[x] completed"* ]]; then
|
|
150
|
+
IS_COMPLETION=true
|
|
151
|
+
fi
|
|
152
|
+
|
|
153
|
+
# Pattern 3: Minimal checkbox change
|
|
154
|
+
if [[ "$OLD_STRING" == "[ ]"* ]] && [[ "$NEW_STRING" == "[x]"* ]]; then
|
|
155
|
+
IS_COMPLETION=true
|
|
156
|
+
fi
|
|
157
|
+
|
|
158
|
+
if [[ "$IS_COMPLETION" != "true" ]]; then
|
|
159
|
+
echo "[$(date)] pre-task-completion-edit: Not a completion edit, allowing" >> "$DEBUG_LOG" 2>/dev/null || true
|
|
160
|
+
cat <<EOF
|
|
161
|
+
{"continue": true}
|
|
162
|
+
EOF
|
|
163
|
+
exit 0
|
|
164
|
+
fi
|
|
165
|
+
|
|
166
|
+
echo "[$(date)] pre-task-completion-edit: COMPLETION DETECTED - Validating ACs" >> "$DEBUG_LOG" 2>/dev/null || true
|
|
167
|
+
|
|
168
|
+
# ============================================================================
|
|
169
|
+
# EXTRACT INCREMENT AND TASK INFO
|
|
170
|
+
# ============================================================================
|
|
171
|
+
# Parse increment name from file path
|
|
172
|
+
# Pattern: .specweave/increments/XXXX-name/tasks.md
|
|
173
|
+
INCREMENT_NAME=$(echo "$FILE_PATH" | grep -o '[0-9]\{4\}-[a-zA-Z0-9_-]*' | tail -1 || echo "")
|
|
174
|
+
INCREMENT_DIR="$PROJECT_ROOT/.specweave/increments/$INCREMENT_NAME"
|
|
175
|
+
TASKS_FILE="$INCREMENT_DIR/tasks.md"
|
|
176
|
+
SPEC_FILE="$INCREMENT_DIR/spec.md"
|
|
177
|
+
|
|
178
|
+
echo "[$(date)] pre-task-completion-edit: INCREMENT=$INCREMENT_NAME" >> "$DEBUG_LOG" 2>/dev/null || true
|
|
179
|
+
|
|
180
|
+
if [[ -z "$INCREMENT_NAME" ]] || [[ ! -f "$TASKS_FILE" ]]; then
|
|
181
|
+
echo "[$(date)] pre-task-completion-edit: Cannot find increment, allowing (safety)" >> "$DEBUG_LOG" 2>/dev/null || true
|
|
182
|
+
cat <<EOF
|
|
183
|
+
{"continue": true}
|
|
184
|
+
EOF
|
|
185
|
+
exit 0
|
|
186
|
+
fi
|
|
187
|
+
|
|
188
|
+
if [[ ! -f "$SPEC_FILE" ]]; then
|
|
189
|
+
echo "[$(date)] pre-task-completion-edit: No spec.md found, allowing (no ACs to verify)" >> "$DEBUG_LOG" 2>/dev/null || true
|
|
190
|
+
cat <<EOF
|
|
191
|
+
{"continue": true}
|
|
192
|
+
EOF
|
|
193
|
+
exit 0
|
|
194
|
+
fi
|
|
195
|
+
|
|
196
|
+
# ============================================================================
|
|
197
|
+
# FIND TASK BEING COMPLETED
|
|
198
|
+
# ============================================================================
|
|
199
|
+
# We need to find which task is being completed by matching the old_string context
|
|
200
|
+
# Look for the task section that contains this status line
|
|
201
|
+
|
|
202
|
+
# Extract task context from old_string (task header should be nearby)
|
|
203
|
+
# First, read tasks.md and find the task that contains this status line
|
|
204
|
+
|
|
205
|
+
TASK_ID=""
|
|
206
|
+
SATISFIES_ACS=""
|
|
207
|
+
|
|
208
|
+
# Read tasks.md and find the task context
|
|
209
|
+
TASKS_CONTENT=$(cat "$TASKS_FILE" 2>/dev/null || echo "")
|
|
210
|
+
|
|
211
|
+
# Find the task ID that precedes the old_string status
|
|
212
|
+
# Tasks follow pattern:
|
|
213
|
+
# ### T-XXX: Title
|
|
214
|
+
# **User Story**: US-XXX
|
|
215
|
+
# **Satisfies ACs**: AC-XXX-YY, AC-XXX-ZZ
|
|
216
|
+
# **Status**: [ ] pending
|
|
217
|
+
|
|
218
|
+
# Strategy: Search for task header, then check if its status matches old_string
|
|
219
|
+
CURRENT_TASK_ID=""
|
|
220
|
+
CURRENT_ACS=""
|
|
221
|
+
IN_TASK=false
|
|
222
|
+
|
|
223
|
+
while IFS= read -r line; do
|
|
224
|
+
# Detect task header
|
|
225
|
+
if [[ "$line" =~ ^###[[:space:]]+(T-[0-9]+): ]]; then
|
|
226
|
+
CURRENT_TASK_ID="${BASH_REMATCH[1]}"
|
|
227
|
+
CURRENT_ACS=""
|
|
228
|
+
IN_TASK=true
|
|
229
|
+
fi
|
|
230
|
+
|
|
231
|
+
# Capture Satisfies ACs
|
|
232
|
+
if [[ "$IN_TASK" == "true" ]] && [[ "$line" == *"**Satisfies ACs**:"* ]]; then
|
|
233
|
+
# Extract AC IDs (comma-separated)
|
|
234
|
+
CURRENT_ACS=$(echo "$line" | sed 's/.*\*\*Satisfies ACs\*\*:[[:space:]]*//' | tr -d '\r')
|
|
235
|
+
fi
|
|
236
|
+
|
|
237
|
+
# Check if this task's status matches what we're editing
|
|
238
|
+
if [[ "$IN_TASK" == "true" ]] && [[ "$line" == *"**Status**:"*"[ ]"* ]]; then
|
|
239
|
+
# This task is pending - check if the old_string matches
|
|
240
|
+
# Compare by checking if old_string is a substring of status line
|
|
241
|
+
if [[ "$OLD_STRING" == *"[ ]"* ]]; then
|
|
242
|
+
TASK_ID="$CURRENT_TASK_ID"
|
|
243
|
+
SATISFIES_ACS="$CURRENT_ACS"
|
|
244
|
+
# Don't break - continue to find the EXACT task
|
|
245
|
+
fi
|
|
246
|
+
fi
|
|
247
|
+
|
|
248
|
+
# Task boundary
|
|
249
|
+
if [[ "$line" == "---" ]]; then
|
|
250
|
+
IN_TASK=false
|
|
251
|
+
fi
|
|
252
|
+
done <<< "$TASKS_CONTENT"
|
|
253
|
+
|
|
254
|
+
echo "[$(date)] pre-task-completion-edit: TASK_ID=$TASK_ID, SATISFIES_ACS=$SATISFIES_ACS" >> "$DEBUG_LOG" 2>/dev/null || true
|
|
255
|
+
|
|
256
|
+
if [[ -z "$TASK_ID" ]]; then
|
|
257
|
+
echo "[$(date)] pre-task-completion-edit: Could not identify task, allowing (safety)" >> "$DEBUG_LOG" 2>/dev/null || true
|
|
258
|
+
cat <<EOF
|
|
259
|
+
{"continue": true, "systemMessage": "Warning: Could not identify which task is being completed. AC verification skipped."}
|
|
260
|
+
EOF
|
|
261
|
+
exit 0
|
|
262
|
+
fi
|
|
263
|
+
|
|
264
|
+
if [[ -z "$SATISFIES_ACS" ]]; then
|
|
265
|
+
echo "[$(date)] pre-task-completion-edit: Task has no ACs, allowing" >> "$DEBUG_LOG" 2>/dev/null || true
|
|
266
|
+
cat <<EOF
|
|
267
|
+
{"continue": true, "systemMessage": "Task $TASK_ID has no Acceptance Criteria linked. Consider adding 'Satisfies ACs' field."}
|
|
268
|
+
EOF
|
|
269
|
+
exit 0
|
|
270
|
+
fi
|
|
271
|
+
|
|
272
|
+
# ============================================================================
|
|
273
|
+
# VERIFY ACs IN spec.md
|
|
274
|
+
# ============================================================================
|
|
275
|
+
# Check that each AC in SATISFIES_ACS is marked [x] (checked) in spec.md
|
|
276
|
+
# AC format in spec.md:
|
|
277
|
+
# - [x] **AC-US1-01**: Description...
|
|
278
|
+
# - [ ] **AC-US1-02**: Description...
|
|
279
|
+
|
|
280
|
+
SPEC_CONTENT=$(cat "$SPEC_FILE" 2>/dev/null || echo "")
|
|
281
|
+
FAILED_ACS=""
|
|
282
|
+
PASSED_ACS=""
|
|
283
|
+
|
|
284
|
+
# Parse comma-separated ACs
|
|
285
|
+
IFS=',' read -ra AC_ARRAY <<< "$SATISFIES_ACS"
|
|
286
|
+
|
|
287
|
+
for ac_raw in "${AC_ARRAY[@]}"; do
|
|
288
|
+
# Trim whitespace
|
|
289
|
+
AC_ID=$(echo "$ac_raw" | sed 's/^[[:space:]]*//;s/[[:space:]]*$//')
|
|
290
|
+
|
|
291
|
+
if [[ -z "$AC_ID" ]]; then
|
|
292
|
+
continue
|
|
293
|
+
fi
|
|
294
|
+
|
|
295
|
+
echo "[$(date)] pre-task-completion-edit: Checking AC: $AC_ID" >> "$DEBUG_LOG" 2>/dev/null || true
|
|
296
|
+
|
|
297
|
+
# Check if AC is checked [x] in spec.md
|
|
298
|
+
# Look for: - [x] **AC-US1-01** (with optional bold around ID)
|
|
299
|
+
if echo "$SPEC_CONTENT" | grep -qE "^\s*-\s*\[x\]\s*\*\*${AC_ID}\*\*"; then
|
|
300
|
+
PASSED_ACS="$PASSED_ACS $AC_ID"
|
|
301
|
+
echo "[$(date)] pre-task-completion-edit: $AC_ID is VERIFIED (checked in spec.md)" >> "$DEBUG_LOG" 2>/dev/null || true
|
|
302
|
+
elif echo "$SPEC_CONTENT" | grep -qE "^\s*-\s*\[ \]\s*\*\*${AC_ID}\*\*"; then
|
|
303
|
+
FAILED_ACS="$FAILED_ACS $AC_ID"
|
|
304
|
+
echo "[$(date)] pre-task-completion-edit: $AC_ID is NOT verified (unchecked in spec.md)" >> "$DEBUG_LOG" 2>/dev/null || true
|
|
305
|
+
else
|
|
306
|
+
# AC not found in spec.md - warn but allow
|
|
307
|
+
echo "[$(date)] pre-task-completion-edit: $AC_ID not found in spec.md (warning)" >> "$DEBUG_LOG" 2>/dev/null || true
|
|
308
|
+
fi
|
|
309
|
+
done
|
|
310
|
+
|
|
311
|
+
# ============================================================================
|
|
312
|
+
# DECISION: ALLOW OR BLOCK
|
|
313
|
+
# ============================================================================
|
|
314
|
+
FAILED_ACS=$(echo "$FAILED_ACS" | sed 's/^[[:space:]]*//')
|
|
315
|
+
|
|
316
|
+
if [[ -n "$FAILED_ACS" ]]; then
|
|
317
|
+
# BLOCK the completion - ACs not verified
|
|
318
|
+
echo "[$(date)] pre-task-completion-edit: BLOCKING - Unverified ACs: $FAILED_ACS" >> "$DEBUG_LOG" 2>/dev/null || true
|
|
319
|
+
|
|
320
|
+
# Escape for JSON
|
|
321
|
+
FAILED_ACS_ESCAPED=$(echo "$FAILED_ACS" | sed 's/"/\\"/g')
|
|
322
|
+
|
|
323
|
+
cat <<EOF
|
|
324
|
+
{
|
|
325
|
+
"continue": false,
|
|
326
|
+
"systemMessage": "BLOCKED: Task $TASK_ID cannot be marked complete.
|
|
327
|
+
|
|
328
|
+
Unverified Acceptance Criteria: $FAILED_ACS_ESCAPED
|
|
329
|
+
|
|
330
|
+
These ACs are NOT checked [x] in spec.md:
|
|
331
|
+
$FAILED_ACS_ESCAPED
|
|
332
|
+
|
|
333
|
+
ACTION REQUIRED:
|
|
334
|
+
1. Verify each AC is actually satisfied by the implementation
|
|
335
|
+
2. Check the AC in spec.md: Edit the line from [ ] to [x]
|
|
336
|
+
3. Then retry marking this task as completed
|
|
337
|
+
|
|
338
|
+
This quality gate ensures tasks are only completed when their ACs are verified."
|
|
339
|
+
}
|
|
340
|
+
EOF
|
|
341
|
+
exit 0
|
|
342
|
+
fi
|
|
343
|
+
|
|
344
|
+
# All ACs verified - allow completion
|
|
345
|
+
echo "[$(date)] pre-task-completion-edit: ALLOWING - All ACs verified" >> "$DEBUG_LOG" 2>/dev/null || true
|
|
346
|
+
|
|
347
|
+
PASSED_ACS=$(echo "$PASSED_ACS" | sed 's/^[[:space:]]*//')
|
|
348
|
+
cat <<EOF
|
|
349
|
+
{
|
|
350
|
+
"continue": true,
|
|
351
|
+
"systemMessage": "AC Verification Passed for $TASK_ID. Verified ACs:$PASSED_ACS"
|
|
352
|
+
}
|
|
353
|
+
EOF
|
|
354
|
+
|
|
355
|
+
exit 0
|
|
@@ -70,6 +70,49 @@ async function syncLivingDocs(incrementId) {
|
|
|
70
70
|
}
|
|
71
71
|
console.log(`\u{1F4C4} Changed/created ${changedDocs.length} file(s)`);
|
|
72
72
|
|
|
73
|
+
// ========================================================================
|
|
74
|
+
// TRANSLATION TRIGGER (v0.29.0+ - Multi-Language Support)
|
|
75
|
+
// ========================================================================
|
|
76
|
+
// After living docs sync, check if translation is needed.
|
|
77
|
+
// User MUST opt-in during init (cost warning shown).
|
|
78
|
+
// Translation only happens if:
|
|
79
|
+
// - config.language != 'en'
|
|
80
|
+
// - config.translation.enabled == true
|
|
81
|
+
// - config.translation.scope.livingDocs == true
|
|
82
|
+
const targetLang = config.language || 'en';
|
|
83
|
+
const translationEnabled = config.translation?.enabled ?? false;
|
|
84
|
+
const translateLivingDocs = config.translation?.scope?.livingDocs ?? false;
|
|
85
|
+
|
|
86
|
+
if (targetLang !== 'en' && translationEnabled && translateLivingDocs && changedDocs.length > 0) {
|
|
87
|
+
console.log(`\n\u{1F30D} Translating ${changedDocs.length} updated file(s) to ${targetLang}...`);
|
|
88
|
+
|
|
89
|
+
try {
|
|
90
|
+
// Try to load translate-file module
|
|
91
|
+
const { translateFile } = await import('./translate-file.js');
|
|
92
|
+
|
|
93
|
+
for (const docPath of changedDocs) {
|
|
94
|
+
try {
|
|
95
|
+
await translateFile({
|
|
96
|
+
filePath: docPath,
|
|
97
|
+
targetLang,
|
|
98
|
+
preview: false,
|
|
99
|
+
verbose: false,
|
|
100
|
+
});
|
|
101
|
+
console.log(` \u2705 ${path.basename(docPath)}`);
|
|
102
|
+
} catch (err) {
|
|
103
|
+
console.warn(` \u26A0\uFE0F Failed to translate ${path.basename(docPath)}: ${err.message}`);
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
console.log(`\u2705 Living docs translation complete`);
|
|
107
|
+
} catch (importErr) {
|
|
108
|
+
// translate-file.js may not be compiled yet
|
|
109
|
+
console.log(` \u2139\uFE0F Translation module not available (run 'npm run build')`);
|
|
110
|
+
console.log(` \u{1F4A1} Tip: Run /specweave:translate to translate manually`);
|
|
111
|
+
}
|
|
112
|
+
} else if (targetLang !== 'en' && !translationEnabled) {
|
|
113
|
+
console.log(` \u2139\uFE0F Translation disabled (use /specweave:translate manually)`);
|
|
114
|
+
}
|
|
115
|
+
|
|
73
116
|
// ========================================================================
|
|
74
117
|
// CHECK PERMISSION: canUpdateExternalItems (v0.24.0 - Three-Permission Architecture)
|
|
75
118
|
// ========================================================================
|
|
@@ -0,0 +1,219 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: umbrella-repo-detector
|
|
3
|
+
description: Detects multi-repo architecture from user prompts and guides setup. Activates for: multiple repos, 3 repos, frontend repo, backend repo, shared library repo, monorepo services, microservices, separate repos, FE/BE/Shared, multi-repo architecture, independent repos.
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# Umbrella Multi-Repo Architecture Detector
|
|
7
|
+
|
|
8
|
+
## When This Skill Activates
|
|
9
|
+
|
|
10
|
+
Activates when user describes:
|
|
11
|
+
- Multiple repos: "3 repos", "frontend repo", "backend repo", "shared library"
|
|
12
|
+
- Architecture patterns: "monorepo with services", "microservices", "multi-repo"
|
|
13
|
+
- Explicit splits: "FE/BE/Shared", "frontend/backend/common"
|
|
14
|
+
- GitHub URLs for multiple repositories
|
|
15
|
+
|
|
16
|
+
## My Role
|
|
17
|
+
|
|
18
|
+
When I detect a multi-repo architecture in the user's prompt:
|
|
19
|
+
|
|
20
|
+
1. **Acknowledge the architecture** with detected repos
|
|
21
|
+
2. **Explain project-scoped user stories** (US-FE-*, US-BE-*, US-SHARED-*)
|
|
22
|
+
3. **Guide the init flow** for proper setup
|
|
23
|
+
4. **Route to PM agent** with multi-repo context
|
|
24
|
+
|
|
25
|
+
## Detection Patterns
|
|
26
|
+
|
|
27
|
+
| Pattern | Example | Detected As |
|
|
28
|
+
|---------|---------|-------------|
|
|
29
|
+
| Repo count | "3 repos", "multiple repos" | Multi-repo intent |
|
|
30
|
+
| Frontend repo | "Frontend repo", "UI repo", "web app" | Type: frontend, Prefix: FE |
|
|
31
|
+
| Backend repo | "Backend API repo", "server", "API" | Type: backend, Prefix: BE |
|
|
32
|
+
| Shared repo | "Shared library", "common types" | Type: shared, Prefix: SHARED |
|
|
33
|
+
| Mobile repo | "Mobile app", "iOS/Android" | Type: mobile, Prefix: MOBILE |
|
|
34
|
+
| Infra repo | "Infrastructure", "Terraform" | Type: infrastructure, Prefix: INFRA |
|
|
35
|
+
|
|
36
|
+
## Project-Scoped User Stories
|
|
37
|
+
|
|
38
|
+
When user describes multi-repo, user stories MUST be prefixed:
|
|
39
|
+
|
|
40
|
+
```markdown
|
|
41
|
+
## Instead of (generic):
|
|
42
|
+
US-001: User Registration
|
|
43
|
+
US-002: Registration API
|
|
44
|
+
US-003: Validation Schema
|
|
45
|
+
|
|
46
|
+
## Generate (project-scoped):
|
|
47
|
+
US-FE-001: User Registration Form
|
|
48
|
+
- Related repo: frontend
|
|
49
|
+
- Keywords: form, UI, validation display
|
|
50
|
+
|
|
51
|
+
US-BE-001: Registration API Endpoint
|
|
52
|
+
- Related repo: backend
|
|
53
|
+
- Keywords: API, endpoint, database
|
|
54
|
+
|
|
55
|
+
US-SHARED-001: Registration Validation Schema
|
|
56
|
+
- Related repo: shared
|
|
57
|
+
- Keywords: validator, schema, types
|
|
58
|
+
```
|
|
59
|
+
|
|
60
|
+
## Cross-Cutting User Stories
|
|
61
|
+
|
|
62
|
+
For features that span multiple repos, use cross-project tagging:
|
|
63
|
+
|
|
64
|
+
```markdown
|
|
65
|
+
US-AUTH-001: OAuth Integration
|
|
66
|
+
- Tags: ["cross-project", "frontend", "backend"]
|
|
67
|
+
- Creates linked issues in: FE repo, BE repo
|
|
68
|
+
- Child stories:
|
|
69
|
+
- US-FE-002: OAuth Login Button (frontend)
|
|
70
|
+
- US-BE-002: OAuth Token Validation (backend)
|
|
71
|
+
```
|
|
72
|
+
|
|
73
|
+
## Setup Flow Guidance
|
|
74
|
+
|
|
75
|
+
When multi-repo detected, guide user through options:
|
|
76
|
+
|
|
77
|
+
### Option 1: Clone from GitHub (Recommended)
|
|
78
|
+
```
|
|
79
|
+
You have existing repos? Let's clone them:
|
|
80
|
+
1. Provide GitHub URLs (comma-separated or one per line)
|
|
81
|
+
2. Each repo gets its own .specweave/ configuration
|
|
82
|
+
3. Each repo syncs to its own GitHub issues
|
|
83
|
+
```
|
|
84
|
+
|
|
85
|
+
### Option 2: Create New Repos
|
|
86
|
+
```
|
|
87
|
+
Creating fresh repos:
|
|
88
|
+
1. I'll create repos on GitHub for you
|
|
89
|
+
2. Each gets initialized with .specweave/
|
|
90
|
+
3. External tool sync configured per repo
|
|
91
|
+
```
|
|
92
|
+
|
|
93
|
+
### Option 3: Initialize Local Folders
|
|
94
|
+
```
|
|
95
|
+
Have local folders already?
|
|
96
|
+
1. Point me to each folder
|
|
97
|
+
2. I'll initialize .specweave/ in each
|
|
98
|
+
3. Configure external tools per repo
|
|
99
|
+
```
|
|
100
|
+
|
|
101
|
+
## Umbrella Repo Structure
|
|
102
|
+
|
|
103
|
+
```
|
|
104
|
+
umbrella-project/ # Optional parent repo
|
|
105
|
+
├── .specweave/
|
|
106
|
+
│ ├── config.json # umbrella config with childRepos[]
|
|
107
|
+
│ └── docs/ # High-level PRD, roadmap only
|
|
108
|
+
│
|
|
109
|
+
├── my-app-fe/ # Frontend repo (cloned/created)
|
|
110
|
+
│ └── .specweave/
|
|
111
|
+
│ ├── config.json # sync → my-app-fe GitHub issues
|
|
112
|
+
│ └── increments/
|
|
113
|
+
│ └── 0001-feature/
|
|
114
|
+
│ └── spec.md # Only US-FE-* stories
|
|
115
|
+
│
|
|
116
|
+
├── my-app-be/ # Backend repo (cloned/created)
|
|
117
|
+
│ └── .specweave/
|
|
118
|
+
│ └── ... # sync → my-app-be GitHub issues
|
|
119
|
+
│
|
|
120
|
+
└── my-app-shared/ # Shared repo (cloned/created)
|
|
121
|
+
└── .specweave/
|
|
122
|
+
└── ... # sync → my-app-shared GitHub issues
|
|
123
|
+
```
|
|
124
|
+
|
|
125
|
+
## Config Example
|
|
126
|
+
|
|
127
|
+
**Parent umbrella config** (`.specweave/config.json`):
|
|
128
|
+
```json
|
|
129
|
+
{
|
|
130
|
+
"umbrella": {
|
|
131
|
+
"enabled": true,
|
|
132
|
+
"childRepos": [
|
|
133
|
+
{
|
|
134
|
+
"id": "fe",
|
|
135
|
+
"path": "./my-app-fe",
|
|
136
|
+
"prefix": "FE",
|
|
137
|
+
"githubUrl": "https://github.com/myorg/my-app-fe"
|
|
138
|
+
},
|
|
139
|
+
{
|
|
140
|
+
"id": "be",
|
|
141
|
+
"path": "./my-app-be",
|
|
142
|
+
"prefix": "BE",
|
|
143
|
+
"githubUrl": "https://github.com/myorg/my-app-be"
|
|
144
|
+
},
|
|
145
|
+
{
|
|
146
|
+
"id": "shared",
|
|
147
|
+
"path": "./my-app-shared",
|
|
148
|
+
"prefix": "SHARED",
|
|
149
|
+
"githubUrl": "https://github.com/myorg/my-app-shared"
|
|
150
|
+
}
|
|
151
|
+
]
|
|
152
|
+
}
|
|
153
|
+
}
|
|
154
|
+
```
|
|
155
|
+
|
|
156
|
+
**Child repo config** (`my-app-fe/.specweave/config.json`):
|
|
157
|
+
```json
|
|
158
|
+
{
|
|
159
|
+
"project": {
|
|
160
|
+
"name": "My App Frontend",
|
|
161
|
+
"prefix": "FE"
|
|
162
|
+
},
|
|
163
|
+
"sync": {
|
|
164
|
+
"activeProfile": "github",
|
|
165
|
+
"profiles": {
|
|
166
|
+
"github": {
|
|
167
|
+
"provider": "github",
|
|
168
|
+
"config": {
|
|
169
|
+
"owner": "myorg",
|
|
170
|
+
"repo": "my-app-fe"
|
|
171
|
+
}
|
|
172
|
+
}
|
|
173
|
+
}
|
|
174
|
+
}
|
|
175
|
+
}
|
|
176
|
+
```
|
|
177
|
+
|
|
178
|
+
## Response Template
|
|
179
|
+
|
|
180
|
+
When I detect multi-repo intent, respond:
|
|
181
|
+
|
|
182
|
+
```
|
|
183
|
+
I detected a **multi-repo architecture** in your description:
|
|
184
|
+
|
|
185
|
+
**Detected Repos:**
|
|
186
|
+
- Frontend (prefix: FE) - [matched keywords]
|
|
187
|
+
- Backend (prefix: BE) - [matched keywords]
|
|
188
|
+
- Shared (prefix: SHARED) - [matched keywords]
|
|
189
|
+
|
|
190
|
+
**User Story Format:**
|
|
191
|
+
User stories will be project-scoped:
|
|
192
|
+
- `US-FE-001`: Frontend stories
|
|
193
|
+
- `US-BE-001`: Backend stories
|
|
194
|
+
- `US-SHARED-001`: Shared library stories
|
|
195
|
+
|
|
196
|
+
**Setup Options:**
|
|
197
|
+
1. **Clone from GitHub** - Provide URLs, I'll clone and initialize each
|
|
198
|
+
2. **Create new repos** - I'll create on GitHub and initialize
|
|
199
|
+
3. **Initialize local folders** - Point to existing folders
|
|
200
|
+
|
|
201
|
+
Which would you like to do?
|
|
202
|
+
```
|
|
203
|
+
|
|
204
|
+
## Keywords for Story Routing
|
|
205
|
+
|
|
206
|
+
| Keywords | Routes To | Prefix |
|
|
207
|
+
|----------|-----------|--------|
|
|
208
|
+
| UI, component, page, form, view, theme, drag-drop, builder | Frontend | FE |
|
|
209
|
+
| API, endpoint, CRUD, webhook, notification, analytics | Backend | BE |
|
|
210
|
+
| schema, validator, types, utilities, localization | Shared | SHARED |
|
|
211
|
+
| iOS, Android, mobile, push notification | Mobile | MOBILE |
|
|
212
|
+
| Terraform, K8s, Docker, CI/CD | Infrastructure | INFRA |
|
|
213
|
+
|
|
214
|
+
## Important Notes
|
|
215
|
+
|
|
216
|
+
1. **Each repo is independent** - Own `.specweave/`, own increments, own external tool sync
|
|
217
|
+
2. **Parent repo is optional** - Can have umbrella config or just independent repos
|
|
218
|
+
3. **User stories MUST have project prefix** - Never generate generic `US-001` in multi-repo mode
|
|
219
|
+
4. **Cross-project stories get special handling** - Tagged and linked across repos
|
|
@@ -1114,3 +1114,21 @@
|
|
|
1114
1114
|
[Tue Nov 25 02:03:38 EST 2025] [GitHub] ⚠️ sync-spec-content CLI not found at /Users/antonabyzov/Projects/github/specweave/plugins/specweave-github/hooks/dist/src/cli/commands/sync-spec-content.js, skipping sync
|
|
1115
1115
|
[Tue Nov 25 02:03:39 EST 2025] [GitHub] 🔗 GitHub sync hook fired
|
|
1116
1116
|
[Tue Nov 25 02:03:39 EST 2025] [GitHub] ⚠️ sync-spec-content CLI not found at /Users/antonabyzov/Projects/github/specweave/plugins/specweave-github/hooks/dist/src/cli/commands/sync-spec-content.js, skipping sync
|
|
1117
|
+
[Tue Nov 25 03:33:47 EST 2025] [GitHub] 🔗 GitHub sync hook fired
|
|
1118
|
+
[Tue Nov 25 03:33:47 EST 2025] [GitHub] ⚠️ sync-spec-content CLI not found at /Users/antonabyzov/Projects/github/specweave/plugins/specweave-github/hooks/dist/src/cli/commands/sync-spec-content.js, skipping sync
|
|
1119
|
+
[Tue Nov 25 03:33:47 EST 2025] [GitHub] 🔗 GitHub sync hook fired
|
|
1120
|
+
[Tue Nov 25 03:33:47 EST 2025] [GitHub] ⚠️ sync-spec-content CLI not found at /Users/antonabyzov/Projects/github/specweave/plugins/specweave-github/hooks/dist/src/cli/commands/sync-spec-content.js, skipping sync
|
|
1121
|
+
[Tue Nov 25 03:33:47 EST 2025] [GitHub] 🔗 GitHub sync hook fired
|
|
1122
|
+
[Tue Nov 25 03:33:47 EST 2025] [GitHub] ⚠️ sync-spec-content CLI not found at /Users/antonabyzov/Projects/github/specweave/plugins/specweave-github/hooks/dist/src/cli/commands/sync-spec-content.js, skipping sync
|
|
1123
|
+
[Tue Nov 25 03:36:17 EST 2025] [GitHub] 🔗 GitHub sync hook fired
|
|
1124
|
+
[Tue Nov 25 03:36:17 EST 2025] [GitHub] ⚠️ sync-spec-content CLI not found at /Users/antonabyzov/Projects/github/specweave/plugins/specweave-github/hooks/dist/src/cli/commands/sync-spec-content.js, skipping sync
|
|
1125
|
+
[Tue Nov 25 03:36:17 EST 2025] [GitHub] 🔗 GitHub sync hook fired
|
|
1126
|
+
[Tue Nov 25 03:36:17 EST 2025] [GitHub] ⚠️ sync-spec-content CLI not found at /Users/antonabyzov/Projects/github/specweave/plugins/specweave-github/hooks/dist/src/cli/commands/sync-spec-content.js, skipping sync
|
|
1127
|
+
[Tue Nov 25 03:36:18 EST 2025] [GitHub] 🔗 GitHub sync hook fired
|
|
1128
|
+
[Tue Nov 25 03:36:18 EST 2025] [GitHub] ⚠️ sync-spec-content CLI not found at /Users/antonabyzov/Projects/github/specweave/plugins/specweave-github/hooks/dist/src/cli/commands/sync-spec-content.js, skipping sync
|
|
1129
|
+
[Tue Nov 25 04:01:54 EST 2025] [GitHub] 🔗 GitHub sync hook fired
|
|
1130
|
+
[Tue Nov 25 04:01:54 EST 2025] [GitHub] ⚠️ sync-spec-content CLI not found at /Users/antonabyzov/Projects/github/specweave/plugins/specweave-github/hooks/dist/src/cli/commands/sync-spec-content.js, skipping sync
|
|
1131
|
+
[Tue Nov 25 04:01:54 EST 2025] [GitHub] 🔗 GitHub sync hook fired
|
|
1132
|
+
[Tue Nov 25 04:01:54 EST 2025] [GitHub] ⚠️ sync-spec-content CLI not found at /Users/antonabyzov/Projects/github/specweave/plugins/specweave-github/hooks/dist/src/cli/commands/sync-spec-content.js, skipping sync
|
|
1133
|
+
[Tue Nov 25 04:01:54 EST 2025] [GitHub] 🔗 GitHub sync hook fired
|
|
1134
|
+
[Tue Nov 25 04:01:54 EST 2025] [GitHub] ⚠️ sync-spec-content CLI not found at /Users/antonabyzov/Projects/github/specweave/plugins/specweave-github/hooks/dist/src/cli/commands/sync-spec-content.js, skipping sync
|