specweave 0.26.11 → 0.26.13
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/plugins/specweave-github/lib/completion-calculator.d.ts +4 -1
- package/dist/plugins/specweave-github/lib/completion-calculator.d.ts.map +1 -1
- package/dist/plugins/specweave-github/lib/completion-calculator.js +49 -29
- package/dist/plugins/specweave-github/lib/completion-calculator.js.map +1 -1
- package/dist/src/core/increment/increment-archiver.d.ts +3 -0
- package/dist/src/core/increment/increment-archiver.d.ts.map +1 -1
- package/dist/src/core/increment/increment-archiver.js +35 -4
- package/dist/src/core/increment/increment-archiver.js.map +1 -1
- package/dist/src/core/living-docs/feature-archiver.d.ts +5 -0
- package/dist/src/core/living-docs/feature-archiver.d.ts.map +1 -1
- package/dist/src/core/living-docs/feature-archiver.js +66 -18
- package/dist/src/core/living-docs/feature-archiver.js.map +1 -1
- package/package.json +1 -1
- package/plugins/specweave/commands/specweave-archive.md +10 -1
- package/plugins/specweave/hooks/docs-changed.sh.backup +79 -0
- package/plugins/specweave/hooks/hooks.json +10 -0
- package/plugins/specweave/hooks/human-input-required.sh.backup +75 -0
- package/plugins/specweave/hooks/lib/update-active-increment.sh +96 -0
- package/plugins/specweave/hooks/lib/update-status-line.sh +153 -189
- package/plugins/specweave/hooks/post-edit-write-consolidated.sh +6 -0
- package/plugins/specweave/hooks/post-first-increment.sh.backup +61 -0
- package/plugins/specweave/hooks/post-increment-change.sh.backup +98 -0
- package/plugins/specweave/hooks/post-increment-completion.sh.backup +231 -0
- package/plugins/specweave/hooks/post-increment-planning.sh.backup +1048 -0
- package/plugins/specweave/hooks/post-increment-status-change.sh.backup +147 -0
- package/plugins/specweave/hooks/post-metadata-change.sh +9 -0
- package/plugins/specweave/hooks/post-spec-update.sh.backup +158 -0
- package/plugins/specweave/hooks/post-task-completion.sh +8 -0
- package/plugins/specweave/hooks/post-task-edit.sh +37 -0
- package/plugins/specweave/hooks/post-user-story-complete.sh.backup +179 -0
- package/plugins/specweave/hooks/pre-command-deduplication.sh +43 -53
- package/plugins/specweave/hooks/pre-command-deduplication.sh.backup +83 -0
- package/plugins/specweave/hooks/pre-implementation.sh.backup +67 -0
- package/plugins/specweave/hooks/pre-task-completion.sh.backup +194 -0
- package/plugins/specweave/hooks/pre-tool-use.sh +5 -0
- package/plugins/specweave/hooks/pre-tool-use.sh.backup +133 -0
- package/plugins/specweave/hooks/user-prompt-submit.sh +143 -289
- package/plugins/specweave/hooks/user-prompt-submit.sh.backup +386 -0
- package/plugins/specweave-ado/hooks/post-living-docs-update.sh.backup +353 -0
- package/plugins/specweave-ado/hooks/post-task-completion.sh.backup +172 -0
- package/plugins/specweave-ado/lib/ado-multi-project-sync.js +1 -0
- package/plugins/specweave-ado/lib/enhanced-ado-sync.js +170 -0
- package/plugins/specweave-github/hooks/.specweave/logs/hooks-debug.log +1098 -0
- package/plugins/specweave-github/hooks/post-task-completion.sh.backup +258 -0
- package/plugins/specweave-github/lib/completion-calculator.js +34 -16
- package/plugins/specweave-github/lib/completion-calculator.ts +54 -32
- package/plugins/specweave-jira/hooks/post-task-completion.sh.backup +172 -0
- package/plugins/specweave-jira/lib/enhanced-jira-sync.js +3 -3
- package/plugins/specweave-release/hooks/.specweave/logs/dora-tracking.log +1008 -0
- package/plugins/specweave-release/hooks/post-task-completion.sh.backup +110 -0
- package/src/templates/AGENTS.md.template +301 -2452
- package/src/templates/CLAUDE.md.template +99 -667
|
@@ -1,225 +1,189 @@
|
|
|
1
1
|
#!/usr/bin/env bash
|
|
2
2
|
#
|
|
3
|
-
# update-status-line.sh (
|
|
3
|
+
# update-status-line.sh (v0.26.13 - ULTRA-OPTIMIZED for crash prevention)
|
|
4
4
|
#
|
|
5
5
|
# Updates status line cache with current increment progress.
|
|
6
6
|
# Shows: [increment-name] ████░░░░ X/Y tasks | A/B ACs (Z open)
|
|
7
7
|
#
|
|
8
|
-
#
|
|
9
|
-
# 1.
|
|
10
|
-
# 2.
|
|
11
|
-
# 3.
|
|
12
|
-
# 4.
|
|
13
|
-
# 5.
|
|
14
|
-
# 6.
|
|
8
|
+
# OPTIMIZATIONS (v0.26.13):
|
|
9
|
+
# 1. TTL-based throttling (10s) - longer cache = fewer runs
|
|
10
|
+
# 2. Mtime checking via find -newer (no stat loops!)
|
|
11
|
+
# 3. Pure bash counting + JSON generation (NO jq!)
|
|
12
|
+
# 4. Single-pass awk for all counting (1 process vs 5 greps)
|
|
13
|
+
# 5. Exclude _archive/ with find -not -path
|
|
14
|
+
# 6. Lock file to prevent concurrent runs
|
|
15
15
|
#
|
|
16
|
-
# Performance:
|
|
16
|
+
# Performance: <5ms (cached) / 15-25ms (full scan)
|
|
17
17
|
#
|
|
18
|
-
# EMERGENCY FIX (v0.24.4): Changed from set -euo pipefail to set +e
|
|
19
|
-
# CRITICAL: Hooks MUST use set +e to prevent Claude Code crashes!
|
|
20
|
-
# See: CLAUDE.md section 9a - Hook Performance & Safety
|
|
21
|
-
|
|
22
18
|
set +e
|
|
23
19
|
|
|
24
|
-
#
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
20
|
+
# ============================================================================
|
|
21
|
+
# PROJECT ROOT (FAST - cached in env if available)
|
|
22
|
+
# ============================================================================
|
|
23
|
+
if [[ -n "$SPECWEAVE_PROJECT_ROOT" ]] && [[ -d "$SPECWEAVE_PROJECT_ROOT/.specweave" ]]; then
|
|
24
|
+
PROJECT_ROOT="$SPECWEAVE_PROJECT_ROOT"
|
|
25
|
+
else
|
|
26
|
+
PROJECT_ROOT="$PWD"
|
|
27
|
+
while [[ "$PROJECT_ROOT" != "/" ]] && [[ ! -d "$PROJECT_ROOT/.specweave" ]]; do
|
|
28
|
+
PROJECT_ROOT=$(dirname "$PROJECT_ROOT")
|
|
33
29
|
done
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
PROJECT_ROOT=$(find_project_root)
|
|
30
|
+
[[ ! -d "$PROJECT_ROOT/.specweave" ]] && PROJECT_ROOT="$PWD"
|
|
31
|
+
fi
|
|
38
32
|
|
|
39
33
|
# ============================================================================
|
|
40
|
-
#
|
|
34
|
+
# ULTRA-FAST EXITS
|
|
41
35
|
# ============================================================================
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
# This is a CRITICAL part of Fix #4 in the root cause analysis:
|
|
47
|
-
# See: .specweave/increments/0051-*/reports/GITHUB-COMMENT-RECURSION-ROOT-CAUSE-2025-11-24.md
|
|
36
|
+
STATE_DIR="$PROJECT_ROOT/.specweave/state"
|
|
37
|
+
CACHE_FILE="$STATE_DIR/status-line.json"
|
|
38
|
+
INCREMENTS_DIR="$PROJECT_ROOT/.specweave/increments"
|
|
39
|
+
LOCK_FILE="$STATE_DIR/.status-update.lock"
|
|
48
40
|
|
|
49
|
-
|
|
41
|
+
# No .specweave? Exit immediately
|
|
42
|
+
[[ ! -d "$PROJECT_ROOT/.specweave" ]] && exit 0
|
|
50
43
|
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
44
|
+
# Recursion guard
|
|
45
|
+
[[ -f "$STATE_DIR/.hook-recursion-guard" ]] && exit 0
|
|
46
|
+
|
|
47
|
+
# Lock check (prevent concurrent runs - causes crashes!)
|
|
48
|
+
if [[ -f "$LOCK_FILE" ]]; then
|
|
49
|
+
# Check if lock is stale (>30s)
|
|
50
|
+
if [[ "$(uname)" == "Darwin" ]]; then
|
|
51
|
+
LOCK_AGE=$(( $(date +%s) - $(stat -f %m "$LOCK_FILE" 2>/dev/null || echo 0) ))
|
|
52
|
+
else
|
|
53
|
+
LOCK_AGE=$(( $(date +%s) - $(stat -c %Y "$LOCK_FILE" 2>/dev/null || echo 0) ))
|
|
54
|
+
fi
|
|
55
|
+
[[ $LOCK_AGE -lt 30 ]] && exit 0
|
|
55
56
|
fi
|
|
56
57
|
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
if [[ -d "$INCREMENTS_DIR" ]]; then
|
|
71
|
-
for spec_file in "$INCREMENTS_DIR"/*/spec.md; do
|
|
72
|
-
if [[ -f "$spec_file" ]]; then
|
|
73
|
-
# Parse YAML frontmatter for status (source of truth)
|
|
74
|
-
status=$(grep -m1 "^status:" "$spec_file" 2>/dev/null | cut -d: -f2 | tr -d ' ' || echo "")
|
|
75
|
-
|
|
76
|
-
# Check if increment is open (active, planning, or in-progress)
|
|
77
|
-
# ONLY accepts official IncrementStatus enum values
|
|
78
|
-
if [[ "$status" == "active" ]] || [[ "$status" == "planning" ]] || [[ "$status" == "in-progress" ]]; then
|
|
79
|
-
increment_id=$(basename "$(dirname "$spec_file")")
|
|
80
|
-
# Parse created date from spec.md YAML frontmatter
|
|
81
|
-
created=$(grep -m1 "^created:" "$spec_file" 2>/dev/null | cut -d: -f2- | tr -d ' ' || echo "1970-01-01")
|
|
82
|
-
|
|
83
|
-
# Write to temp file
|
|
84
|
-
echo "$created $increment_id" >> "$TMP_FILE"
|
|
85
|
-
fi
|
|
86
|
-
fi
|
|
87
|
-
done
|
|
58
|
+
# ============================================================================
|
|
59
|
+
# TTL CHECK (10 seconds - balanced for UX vs performance)
|
|
60
|
+
# ============================================================================
|
|
61
|
+
TTL_SECONDS=10
|
|
62
|
+
|
|
63
|
+
if [[ -f "$CACHE_FILE" ]]; then
|
|
64
|
+
if [[ "$(uname)" == "Darwin" ]]; then
|
|
65
|
+
CACHE_AGE=$(( $(date +%s) - $(stat -f %m "$CACHE_FILE" 2>/dev/null || echo 0) ))
|
|
66
|
+
else
|
|
67
|
+
CACHE_AGE=$(( $(date +%s) - $(stat -c %Y "$CACHE_FILE" 2>/dev/null || echo 0) ))
|
|
68
|
+
fi
|
|
69
|
+
[[ $CACHE_AGE -lt $TTL_SECONDS ]] && exit 0
|
|
88
70
|
fi
|
|
89
71
|
|
|
90
|
-
#
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
if [[
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
current: null,
|
|
97
|
-
openCount: 0,
|
|
98
|
-
lastUpdate: (now | strftime("%Y-%m-%dT%H:%M:%SZ"))
|
|
99
|
-
}' > "$CACHE_FILE"
|
|
100
|
-
rm -f "$TMP_FILE"
|
|
72
|
+
# ============================================================================
|
|
73
|
+
# NO INCREMENTS? Write empty cache and exit
|
|
74
|
+
# ============================================================================
|
|
75
|
+
if [[ ! -d "$INCREMENTS_DIR" ]]; then
|
|
76
|
+
mkdir -p "$STATE_DIR"
|
|
77
|
+
printf '{"current":null,"openCount":0,"lastUpdate":"%s"}' "$(date -u +%Y-%m-%dT%H:%M:%SZ)" > "$CACHE_FILE"
|
|
101
78
|
exit 0
|
|
102
79
|
fi
|
|
103
80
|
|
|
104
|
-
#
|
|
105
|
-
|
|
81
|
+
# ============================================================================
|
|
82
|
+
# ACQUIRE LOCK
|
|
83
|
+
# ============================================================================
|
|
84
|
+
mkdir -p "$STATE_DIR"
|
|
85
|
+
echo $$ > "$LOCK_FILE"
|
|
86
|
+
trap 'rm -f "$LOCK_FILE"' EXIT
|
|
87
|
+
|
|
88
|
+
# ============================================================================
|
|
89
|
+
# FIND ACTIVE INCREMENTS (single find, no xargs)
|
|
90
|
+
# ============================================================================
|
|
91
|
+
ACTIVE_FILES=""
|
|
92
|
+
OPEN_COUNT=0
|
|
93
|
+
OLDEST_DATE="9999-99-99"
|
|
94
|
+
CURRENT_INCREMENT=""
|
|
106
95
|
|
|
107
|
-
|
|
108
|
-
|
|
96
|
+
while IFS= read -r spec_file; do
|
|
97
|
+
[[ -z "$spec_file" ]] && continue
|
|
109
98
|
|
|
110
|
-
#
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
PERCENTAGE=0
|
|
99
|
+
# Quick status check with head + grep (faster than full file grep)
|
|
100
|
+
if head -20 "$spec_file" 2>/dev/null | grep -qE '^status:\s*(active|planning|in-progress)'; then
|
|
101
|
+
OPEN_COUNT=$((OPEN_COUNT + 1))
|
|
102
|
+
increment_id=$(basename "$(dirname "$spec_file")")
|
|
115
103
|
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
COUNT_TASKS_CLI="$PROJECT_ROOT/dist/src/cli/count-tasks.js"
|
|
104
|
+
# Get created date (first 30 lines only)
|
|
105
|
+
created=$(head -30 "$spec_file" 2>/dev/null | grep -m1 "^created:" | cut -d: -f2- | tr -d ' "' || echo "9999-99-99")
|
|
119
106
|
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
TOTAL_TASKS=$(echo "$TASK_COUNTS" | jq -r '.total' 2>/dev/null || echo 0)
|
|
124
|
-
COMPLETED_TASKS=$(echo "$TASK_COUNTS" | jq -r '.completed' 2>/dev/null || echo 0)
|
|
125
|
-
PERCENTAGE=$(echo "$TASK_COUNTS" | jq -r '.percentage' 2>/dev/null || echo 0)
|
|
126
|
-
else
|
|
127
|
-
# Fallback to legacy counting if CLI not available (graceful degradation)
|
|
128
|
-
# Count total tasks (## T- or ### T- headings)
|
|
129
|
-
TOTAL_TASKS=$(grep -cE '^##+ T-' "$TASKS_FILE" 2>/dev/null || echo 0)
|
|
130
|
-
TOTAL_TASKS=$(echo "$TOTAL_TASKS" | tr -d '\n\r ' || echo 0)
|
|
131
|
-
|
|
132
|
-
# Count completed tasks - recognize all three completion marker formats:
|
|
133
|
-
# 1. **Completed**: <date> (preferred format)
|
|
134
|
-
# 2. **Status**: [x] (legacy format)
|
|
135
|
-
# 3. [x] at line start (legacy checkbox format)
|
|
136
|
-
COMPLETED_TASKS=$(grep -cE '(\*\*Completed\*\*:|\*\*Status\*\*:\s*\[x\]|^\[x\])' "$TASKS_FILE" 2>/dev/null || echo 0)
|
|
137
|
-
COMPLETED_TASKS=$(echo "$COMPLETED_TASKS" | tr -d '\n\r ' || echo 0)
|
|
138
|
-
|
|
139
|
-
# Calculate percentage
|
|
140
|
-
if [[ $TOTAL_TASKS -gt 0 ]]; then
|
|
141
|
-
PERCENTAGE=$((COMPLETED_TASKS * 100 / TOTAL_TASKS))
|
|
107
|
+
if [[ "$created" < "$OLDEST_DATE" ]]; then
|
|
108
|
+
OLDEST_DATE="$created"
|
|
109
|
+
CURRENT_INCREMENT="$increment_id"
|
|
142
110
|
fi
|
|
111
|
+
|
|
112
|
+
ACTIVE_FILES="$ACTIVE_FILES $spec_file"
|
|
143
113
|
fi
|
|
144
|
-
|
|
114
|
+
done < <(find "$INCREMENTS_DIR" -maxdepth 2 -name "spec.md" -not -path "*/_archive/*" 2>/dev/null)
|
|
145
115
|
|
|
146
|
-
#
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
OPEN_ACS=0
|
|
151
|
-
|
|
152
|
-
if [[ -f "$SPEC_FILE" ]]; then
|
|
153
|
-
# Count total ACs: both checked and unchecked
|
|
154
|
-
# Pattern: - [ ] **AC- OR - [x] **AC-
|
|
155
|
-
TOTAL_ACS=$(grep -cE '^- \[(x| )\] \*\*AC-' "$SPEC_FILE" 2>/dev/null || echo 0)
|
|
156
|
-
TOTAL_ACS=$(echo "$TOTAL_ACS" | tr -d '\n\r ' || echo 0)
|
|
157
|
-
|
|
158
|
-
# Count completed ACs (checked)
|
|
159
|
-
# Pattern: - [x] **AC-
|
|
160
|
-
COMPLETED_ACS=$(grep -cE '^- \[x\] \*\*AC-' "$SPEC_FILE" 2>/dev/null || echo 0)
|
|
161
|
-
COMPLETED_ACS=$(echo "$COMPLETED_ACS" | tr -d '\n\r ' || echo 0)
|
|
162
|
-
|
|
163
|
-
# Count open ACs (unchecked)
|
|
164
|
-
# Pattern: - [ ] **AC-
|
|
165
|
-
OPEN_ACS=$(grep -cE '^- \[ \] \*\*AC-' "$SPEC_FILE" 2>/dev/null || echo 0)
|
|
166
|
-
OPEN_ACS=$(echo "$OPEN_ACS" | tr -d '\n\r ' || echo 0)
|
|
116
|
+
# No active increments?
|
|
117
|
+
if [[ -z "$CURRENT_INCREMENT" ]]; then
|
|
118
|
+
printf '{"current":null,"openCount":0,"lastUpdate":"%s"}' "$(date -u +%Y-%m-%dT%H:%M:%SZ)" > "$CACHE_FILE"
|
|
119
|
+
exit 0
|
|
167
120
|
fi
|
|
168
121
|
|
|
169
|
-
#
|
|
170
|
-
#
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
#
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
[[ "$
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
[[ "$OPEN_COUNT" =~ ^[0-9]+$ ]] || OPEN_COUNT=0
|
|
186
|
-
|
|
187
|
-
# Generate cache to temp file first (atomic operation)
|
|
188
|
-
if jq -n \
|
|
189
|
-
--arg id "$CURRENT_INCREMENT" \
|
|
190
|
-
--arg name "$INCREMENT_NAME" \
|
|
191
|
-
--argjson completed "$COMPLETED_TASKS" \
|
|
192
|
-
--argjson total "$TOTAL_TASKS" \
|
|
193
|
-
--argjson percentage "$PERCENTAGE" \
|
|
194
|
-
--argjson acsCompleted "$COMPLETED_ACS" \
|
|
195
|
-
--argjson acsTotal "$TOTAL_ACS" \
|
|
196
|
-
--argjson openCount "$OPEN_COUNT" \
|
|
197
|
-
'{
|
|
198
|
-
current: {
|
|
199
|
-
id: $id,
|
|
200
|
-
name: $name,
|
|
201
|
-
completed: $completed,
|
|
202
|
-
total: $total,
|
|
203
|
-
percentage: $percentage,
|
|
204
|
-
acsCompleted: $acsCompleted,
|
|
205
|
-
acsTotal: $acsTotal
|
|
206
|
-
},
|
|
207
|
-
openCount: $openCount,
|
|
208
|
-
lastUpdate: (now | strftime("%Y-%m-%dT%H:%M:%SZ"))
|
|
209
|
-
}' > "$TMP_CACHE_FILE" 2>/dev/null; then
|
|
210
|
-
|
|
211
|
-
# Validate generated JSON before replacing cache (corruption prevention)
|
|
212
|
-
if jq empty "$TMP_CACHE_FILE" 2>/dev/null; then
|
|
213
|
-
mv "$TMP_CACHE_FILE" "$CACHE_FILE"
|
|
214
|
-
else
|
|
215
|
-
# Invalid JSON generated - keep old cache
|
|
216
|
-
echo "[$(date)] ERROR: Generated invalid JSON, keeping old cache" >> "$DEBUG_LOG" 2>/dev/null || true
|
|
217
|
-
rm -f "$TMP_CACHE_FILE"
|
|
122
|
+
# ============================================================================
|
|
123
|
+
# MTIME CHECK (using find -newer - single syscall!)
|
|
124
|
+
# ============================================================================
|
|
125
|
+
MTIME_FILE="$STATE_DIR/.status-mtime-$CURRENT_INCREMENT"
|
|
126
|
+
|
|
127
|
+
if [[ -f "$MTIME_FILE" ]] && [[ -f "$CACHE_FILE" ]]; then
|
|
128
|
+
# Check if any relevant files are newer than our marker
|
|
129
|
+
TASKS_FILE="$INCREMENTS_DIR/$CURRENT_INCREMENT/tasks.md"
|
|
130
|
+
SPEC_FILE="$INCREMENTS_DIR/$CURRENT_INCREMENT/spec.md"
|
|
131
|
+
|
|
132
|
+
NEWER_FILES=$(find "$SPEC_FILE" "$TASKS_FILE" -newer "$MTIME_FILE" 2>/dev/null | head -1)
|
|
133
|
+
|
|
134
|
+
if [[ -z "$NEWER_FILES" ]]; then
|
|
135
|
+
# No changes - just touch cache to reset TTL
|
|
136
|
+
touch "$CACHE_FILE"
|
|
137
|
+
exit 0
|
|
218
138
|
fi
|
|
219
|
-
else
|
|
220
|
-
# jq generation failed - keep old cache
|
|
221
|
-
echo "[$(date)] ERROR: jq failed to generate status cache (exit $?)" >> "$DEBUG_LOG" 2>/dev/null || true
|
|
222
|
-
rm -f "$TMP_CACHE_FILE"
|
|
223
139
|
fi
|
|
224
140
|
|
|
141
|
+
# ============================================================================
|
|
142
|
+
# SINGLE-PASS COUNTING WITH AWK (replaces 5 grep calls!)
|
|
143
|
+
# ============================================================================
|
|
144
|
+
TASKS_FILE="$INCREMENTS_DIR/$CURRENT_INCREMENT/tasks.md"
|
|
145
|
+
SPEC_FILE="$INCREMENTS_DIR/$CURRENT_INCREMENT/spec.md"
|
|
146
|
+
|
|
147
|
+
# Count tasks with single awk call
|
|
148
|
+
read -r TOTAL_TASKS COMPLETED_TASKS < <(
|
|
149
|
+
awk '
|
|
150
|
+
/^###? T-/ { total++ }
|
|
151
|
+
/\*\*Completed\*\*:|\*\*Status\*\*:[ \t]*\[x\]/ { completed++ }
|
|
152
|
+
END { print total+0, completed+0 }
|
|
153
|
+
' "$TASKS_FILE" 2>/dev/null || echo "0 0"
|
|
154
|
+
)
|
|
155
|
+
|
|
156
|
+
# Count ACs with single awk call
|
|
157
|
+
# Supports both formats: "- [ ] AC-US1-01:" and "- [ ] **AC-US1-01**:"
|
|
158
|
+
read -r TOTAL_ACS COMPLETED_ACS < <(
|
|
159
|
+
awk '
|
|
160
|
+
/^- \[(x| )\] (\*\*)?AC-/ { total++ }
|
|
161
|
+
/^- \[x\] (\*\*)?AC-/ { completed++ }
|
|
162
|
+
END { print total+0, completed+0 }
|
|
163
|
+
' "$SPEC_FILE" 2>/dev/null || echo "0 0"
|
|
164
|
+
)
|
|
165
|
+
|
|
166
|
+
# Calculate percentage (pure bash)
|
|
167
|
+
PERCENTAGE=0
|
|
168
|
+
[[ ${TOTAL_TASKS:-0} -gt 0 ]] && PERCENTAGE=$((${COMPLETED_TASKS:-0} * 100 / TOTAL_TASKS))
|
|
169
|
+
|
|
170
|
+
# ============================================================================
|
|
171
|
+
# WRITE CACHE (PURE BASH - NO jq!)
|
|
172
|
+
# ============================================================================
|
|
173
|
+
# Sanitize values
|
|
174
|
+
TOTAL_TASKS=${TOTAL_TASKS:-0}
|
|
175
|
+
COMPLETED_TASKS=${COMPLETED_TASKS:-0}
|
|
176
|
+
TOTAL_ACS=${TOTAL_ACS:-0}
|
|
177
|
+
COMPLETED_ACS=${COMPLETED_ACS:-0}
|
|
178
|
+
OPEN_COUNT=${OPEN_COUNT:-0}
|
|
179
|
+
PERCENTAGE=${PERCENTAGE:-0}
|
|
180
|
+
|
|
181
|
+
# Generate JSON directly (avoids jq subprocess entirely!)
|
|
182
|
+
cat > "$CACHE_FILE" << EOF
|
|
183
|
+
{"current":{"id":"$CURRENT_INCREMENT","name":"$CURRENT_INCREMENT","completed":$COMPLETED_TASKS,"total":$TOTAL_TASKS,"percentage":$PERCENTAGE,"acsCompleted":$COMPLETED_ACS,"acsTotal":$TOTAL_ACS},"openCount":$OPEN_COUNT,"lastUpdate":"$(date -u +%Y-%m-%dT%H:%M:%SZ)"}
|
|
184
|
+
EOF
|
|
185
|
+
|
|
186
|
+
# Update mtime marker
|
|
187
|
+
touch "$MTIME_FILE"
|
|
188
|
+
|
|
225
189
|
exit 0
|
|
@@ -49,6 +49,12 @@ find_project_root() {
|
|
|
49
49
|
}
|
|
50
50
|
|
|
51
51
|
PROJECT_ROOT=$(find_project_root)
|
|
52
|
+
|
|
53
|
+
# ULTRA-FAST EARLY EXIT FOR NON-SPECWEAVE PROJECTS (T-006 - v0.26.15)
|
|
54
|
+
if [[ ! -d "$PROJECT_ROOT/.specweave" ]]; then
|
|
55
|
+
exit 0
|
|
56
|
+
fi
|
|
57
|
+
|
|
52
58
|
LOGS_DIR="$PROJECT_ROOT/.specweave/logs"
|
|
53
59
|
DEBUG_LOG="$LOGS_DIR/hooks-debug.log"
|
|
54
60
|
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
#!/usr/bin/env bash
|
|
2
|
+
# SpecWeave Post-First-Increment Hook
|
|
3
|
+
#
|
|
4
|
+
# Triggers after the first increment is completed
|
|
5
|
+
# Congratulates the user on completing their first increment
|
|
6
|
+
#
|
|
7
|
+
# NON-INTERACTIVE: Just shows a message (hooks run in background)
|
|
8
|
+
|
|
9
|
+
set -euo pipefail
|
|
10
|
+
|
|
11
|
+
# Get project root (where .specweave/ lives)
|
|
12
|
+
PROJECT_ROOT="$(pwd)"
|
|
13
|
+
|
|
14
|
+
# Check if .specweave directory exists
|
|
15
|
+
if [ ! -d ".specweave" ]; then
|
|
16
|
+
# Not in SpecWeave project, skip
|
|
17
|
+
exit 0
|
|
18
|
+
fi
|
|
19
|
+
|
|
20
|
+
# Check if this is the first increment completion
|
|
21
|
+
# Count completed increments in .specweave/increments/
|
|
22
|
+
COMPLETED_COUNT=0
|
|
23
|
+
if [ -d ".specweave/increments" ]; then
|
|
24
|
+
# Count directories that have COMPLETION-REPORT.md or completion metadata
|
|
25
|
+
for inc_dir in .specweave/increments/[0-9][0-9][0-9][0-9]-*/; do
|
|
26
|
+
if [ -d "$inc_dir" ]; then
|
|
27
|
+
if [ -f "${inc_dir}reports/COMPLETION-REPORT.md" ] || \
|
|
28
|
+
[ -f "${inc_dir}COMPLETION-SUMMARY.md" ] || \
|
|
29
|
+
([ -f "${inc_dir}metadata.json" ] && grep -q '"status".*"completed"' "${inc_dir}metadata.json" 2>/dev/null); then
|
|
30
|
+
COMPLETED_COUNT=$((COMPLETED_COUNT + 1))
|
|
31
|
+
fi
|
|
32
|
+
fi
|
|
33
|
+
done
|
|
34
|
+
fi
|
|
35
|
+
|
|
36
|
+
# Only trigger on first completion
|
|
37
|
+
if [ "$COMPLETED_COUNT" -ne 1 ]; then
|
|
38
|
+
exit 0
|
|
39
|
+
fi
|
|
40
|
+
|
|
41
|
+
# Show congratulations message (non-interactive)
|
|
42
|
+
echo ""
|
|
43
|
+
echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
|
|
44
|
+
echo "🎉 Congratulations! You completed your first increment!"
|
|
45
|
+
echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
|
|
46
|
+
echo ""
|
|
47
|
+
echo "✅ Your increment has been documented in:"
|
|
48
|
+
echo " .specweave/increments/[increment-id]/"
|
|
49
|
+
echo ""
|
|
50
|
+
echo "📚 View your documentation:"
|
|
51
|
+
echo " - Specs: .specweave/docs/internal/specs/"
|
|
52
|
+
echo " - Architecture: .specweave/docs/internal/architecture/"
|
|
53
|
+
echo ""
|
|
54
|
+
echo "🚀 Next steps:"
|
|
55
|
+
echo " - Review your increment: /specweave:status"
|
|
56
|
+
echo " - Start next increment: /specweave:increment \"feature name\""
|
|
57
|
+
echo ""
|
|
58
|
+
echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
|
|
59
|
+
echo ""
|
|
60
|
+
|
|
61
|
+
exit 0
|
|
@@ -0,0 +1,98 @@
|
|
|
1
|
+
#!/bin/bash
|
|
2
|
+
|
|
3
|
+
# SpecWeave Post-Increment-Change Hook
|
|
4
|
+
# Runs automatically after increment files (spec.md, plan.md, tasks.md) are modified
|
|
5
|
+
#
|
|
6
|
+
# Trigger: File watcher or git hook (pre-commit/post-commit)
|
|
7
|
+
# Purpose: Sync increment file changes to GitHub issues
|
|
8
|
+
#
|
|
9
|
+
# What it does:
|
|
10
|
+
# 1. Detects which file changed (spec.md, plan.md, tasks.md)
|
|
11
|
+
# 2. Invokes GitHub sync for increment changes
|
|
12
|
+
# 3. Updates GitHub issue with scope/plan/task changes
|
|
13
|
+
#
|
|
14
|
+
# Usage:
|
|
15
|
+
# ./post-increment-change.sh <incrementId> <changedFile>
|
|
16
|
+
#
|
|
17
|
+
# Example:
|
|
18
|
+
# ./post-increment-change.sh 0015-hierarchical-sync spec.md
|
|
19
|
+
|
|
20
|
+
set -e
|
|
21
|
+
|
|
22
|
+
# Find project root
|
|
23
|
+
find_project_root() {
|
|
24
|
+
local dir="$1"
|
|
25
|
+
while [ "$dir" != "/" ]; do
|
|
26
|
+
if [ -d "$dir/.specweave" ]; then
|
|
27
|
+
echo "$dir"
|
|
28
|
+
return 0
|
|
29
|
+
fi
|
|
30
|
+
dir="$(dirname "$dir")"
|
|
31
|
+
done
|
|
32
|
+
pwd
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
PROJECT_ROOT="$(find_project_root "$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)")"
|
|
36
|
+
cd "$PROJECT_ROOT" 2>/dev/null || true
|
|
37
|
+
|
|
38
|
+
# Configuration
|
|
39
|
+
LOGS_DIR=".specweave/logs"
|
|
40
|
+
DEBUG_LOG="$LOGS_DIR/hooks-debug.log"
|
|
41
|
+
|
|
42
|
+
mkdir -p "$LOGS_DIR" 2>/dev/null || true
|
|
43
|
+
|
|
44
|
+
# Arguments
|
|
45
|
+
INCREMENT_ID="$1"
|
|
46
|
+
CHANGED_FILE="$2"
|
|
47
|
+
|
|
48
|
+
if [ -z "$INCREMENT_ID" ] || [ -z "$CHANGED_FILE" ]; then
|
|
49
|
+
echo "Usage: $0 <incrementId> <changedFile>" >&2
|
|
50
|
+
echo "Example: $0 0015-hierarchical-sync spec.md" >&2
|
|
51
|
+
exit 1
|
|
52
|
+
fi
|
|
53
|
+
|
|
54
|
+
echo "[$(date)] 📝 Increment file changed: $CHANGED_FILE" >> "$DEBUG_LOG" 2>/dev/null || true
|
|
55
|
+
|
|
56
|
+
# Validate changed file
|
|
57
|
+
case "$CHANGED_FILE" in
|
|
58
|
+
spec.md|plan.md|tasks.md)
|
|
59
|
+
;;
|
|
60
|
+
*)
|
|
61
|
+
echo "[$(date)] ⚠️ Unknown file type: $CHANGED_FILE (skipping sync)" >> "$DEBUG_LOG" 2>/dev/null || true
|
|
62
|
+
exit 0
|
|
63
|
+
;;
|
|
64
|
+
esac
|
|
65
|
+
|
|
66
|
+
# Check if Node.js available
|
|
67
|
+
if ! command -v node &> /dev/null; then
|
|
68
|
+
echo "[$(date)] ⚠️ Node.js not found, skipping sync" >> "$DEBUG_LOG" 2>/dev/null || true
|
|
69
|
+
exit 0
|
|
70
|
+
fi
|
|
71
|
+
|
|
72
|
+
# Check if GitHub CLI available
|
|
73
|
+
if ! command -v gh &> /dev/null; then
|
|
74
|
+
echo "[$(date)] ℹ️ GitHub CLI not found, skipping sync" >> "$DEBUG_LOG" 2>/dev/null || true
|
|
75
|
+
exit 0
|
|
76
|
+
fi
|
|
77
|
+
|
|
78
|
+
# Check if authenticated
|
|
79
|
+
if ! gh auth status &> /dev/null; then
|
|
80
|
+
echo "[$(date)] ℹ️ GitHub CLI not authenticated, skipping sync" >> "$DEBUG_LOG" 2>/dev/null || true
|
|
81
|
+
exit 0
|
|
82
|
+
fi
|
|
83
|
+
|
|
84
|
+
# Sync to GitHub
|
|
85
|
+
echo "[$(date)] 🔄 Syncing $CHANGED_FILE changes to GitHub..." >> "$DEBUG_LOG" 2>/dev/null || true
|
|
86
|
+
|
|
87
|
+
node dist/plugins/specweave-github/lib/github-sync-increment-changes.js "$INCREMENT_ID" "$CHANGED_FILE" 2>&1 | tee -a "$DEBUG_LOG" >/dev/null || {
|
|
88
|
+
echo "[$(date)] ⚠️ Failed to sync increment changes (non-blocking)" >> "$DEBUG_LOG" 2>/dev/null || true
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
echo "[$(date)] ✅ Post-increment-change hook complete" >> "$DEBUG_LOG" 2>/dev/null || true
|
|
92
|
+
|
|
93
|
+
# Update status line cache (increment changed)
|
|
94
|
+
HOOK_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
|
95
|
+
bash "$HOOK_DIR/lib/update-status-line.sh" 2>/dev/null || true
|
|
96
|
+
|
|
97
|
+
# Return success (non-blocking)
|
|
98
|
+
exit 0
|