specweave 1.0.551 → 1.0.552
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/bin/specweave.js +23 -1
- package/dist/src/cli/commands/hook.d.ts +15 -0
- package/dist/src/cli/commands/hook.d.ts.map +1 -0
- package/dist/src/cli/commands/hook.js +61 -0
- package/dist/src/cli/commands/hook.js.map +1 -0
- package/dist/src/config/types.d.ts +2 -2
- package/dist/src/core/hooks/handlers/hook-router.d.ts +19 -0
- package/dist/src/core/hooks/handlers/hook-router.d.ts.map +1 -0
- package/dist/src/core/hooks/handlers/hook-router.js +75 -0
- package/dist/src/core/hooks/handlers/hook-router.js.map +1 -0
- package/dist/src/core/hooks/handlers/index.d.ts +10 -0
- package/dist/src/core/hooks/handlers/index.d.ts.map +1 -0
- package/dist/src/core/hooks/handlers/index.js +9 -0
- package/dist/src/core/hooks/handlers/index.js.map +1 -0
- package/dist/src/core/hooks/handlers/post-tool-use-analytics.d.ts +11 -0
- package/dist/src/core/hooks/handlers/post-tool-use-analytics.d.ts.map +1 -0
- package/dist/src/core/hooks/handlers/post-tool-use-analytics.js +73 -0
- package/dist/src/core/hooks/handlers/post-tool-use-analytics.js.map +1 -0
- package/dist/src/core/hooks/handlers/post-tool-use.d.ts +11 -0
- package/dist/src/core/hooks/handlers/post-tool-use.d.ts.map +1 -0
- package/dist/src/core/hooks/handlers/post-tool-use.js +76 -0
- package/dist/src/core/hooks/handlers/post-tool-use.js.map +1 -0
- package/dist/src/core/hooks/handlers/pre-compact.d.ts +11 -0
- package/dist/src/core/hooks/handlers/pre-compact.d.ts.map +1 -0
- package/dist/src/core/hooks/handlers/pre-compact.js +77 -0
- package/dist/src/core/hooks/handlers/pre-compact.js.map +1 -0
- package/dist/src/core/hooks/handlers/pre-tool-use.d.ts +11 -0
- package/dist/src/core/hooks/handlers/pre-tool-use.d.ts.map +1 -0
- package/dist/src/core/hooks/handlers/pre-tool-use.js +318 -0
- package/dist/src/core/hooks/handlers/pre-tool-use.js.map +1 -0
- package/dist/src/core/hooks/handlers/session-start.d.ts +9 -0
- package/dist/src/core/hooks/handlers/session-start.d.ts.map +1 -0
- package/dist/src/core/hooks/handlers/session-start.js +111 -0
- package/dist/src/core/hooks/handlers/session-start.js.map +1 -0
- package/dist/src/core/hooks/handlers/stop-auto.d.ts +16 -0
- package/dist/src/core/hooks/handlers/stop-auto.d.ts.map +1 -0
- package/dist/src/core/hooks/handlers/stop-auto.js +122 -0
- package/dist/src/core/hooks/handlers/stop-auto.js.map +1 -0
- package/dist/src/core/hooks/handlers/stop-reflect.d.ts +14 -0
- package/dist/src/core/hooks/handlers/stop-reflect.d.ts.map +1 -0
- package/dist/src/core/hooks/handlers/stop-reflect.js +43 -0
- package/dist/src/core/hooks/handlers/stop-reflect.js.map +1 -0
- package/dist/src/core/hooks/handlers/stop-sync.d.ts +15 -0
- package/dist/src/core/hooks/handlers/stop-sync.d.ts.map +1 -0
- package/dist/src/core/hooks/handlers/stop-sync.js +68 -0
- package/dist/src/core/hooks/handlers/stop-sync.js.map +1 -0
- package/dist/src/core/hooks/handlers/types.d.ts +63 -0
- package/dist/src/core/hooks/handlers/types.d.ts.map +1 -0
- package/dist/src/core/hooks/handlers/types.js +27 -0
- package/dist/src/core/hooks/handlers/types.js.map +1 -0
- package/dist/src/core/hooks/handlers/user-prompt-submit.d.ts +14 -0
- package/dist/src/core/hooks/handlers/user-prompt-submit.d.ts.map +1 -0
- package/dist/src/core/hooks/handlers/user-prompt-submit.js +173 -0
- package/dist/src/core/hooks/handlers/user-prompt-submit.js.map +1 -0
- package/dist/src/core/hooks/handlers/utils.d.ts +25 -0
- package/dist/src/core/hooks/handlers/utils.d.ts.map +1 -0
- package/dist/src/core/hooks/handlers/utils.js +64 -0
- package/dist/src/core/hooks/handlers/utils.js.map +1 -0
- package/dist/src/init/research/types.d.ts +1 -1
- package/dist/src/sync/sync-target-resolver.js.map +1 -1
- package/dist/src/utils/lock-manager.d.ts.map +1 -1
- package/dist/src/utils/lock-manager.js +5 -0
- package/dist/src/utils/lock-manager.js.map +1 -1
- package/dist/src/utils/plugin-copier.d.ts.map +1 -1
- package/dist/src/utils/plugin-copier.js +3 -30
- package/dist/src/utils/plugin-copier.js.map +1 -1
- package/package.json +1 -1
- package/plugins/specweave/hooks/hooks.json +10 -10
- package/plugins/specweave/hooks/README.md +0 -493
- package/plugins/specweave/hooks/_archive/stop-auto-v4-legacy.sh +0 -1319
- package/plugins/specweave/hooks/lib/common-setup.sh +0 -144
- package/plugins/specweave/hooks/lib/hook-errors.sh +0 -414
- package/plugins/specweave/hooks/lib/migrate-increment-work.sh +0 -245
- package/plugins/specweave/hooks/lib/resolve-package.sh +0 -146
- package/plugins/specweave/hooks/lib/scheduler-startup.sh +0 -135
- package/plugins/specweave/hooks/lib/score-increment.sh +0 -87
- package/plugins/specweave/hooks/lib/sync-spec-content.sh +0 -193
- package/plugins/specweave/hooks/lib/update-active-increment.sh +0 -95
- package/plugins/specweave/hooks/lib/update-status-line.sh +0 -233
- package/plugins/specweave/hooks/lib/validate-spec-status.sh +0 -171
- package/plugins/specweave/hooks/llm-judge-validator.sh +0 -219
- package/plugins/specweave/hooks/log-decision.sh +0 -168
- package/plugins/specweave/hooks/pre-compact.sh +0 -64
- package/plugins/specweave/hooks/startup-health-check.sh +0 -64
- package/plugins/specweave/hooks/stop-auto-v5.sh +0 -276
- package/plugins/specweave/hooks/stop-reflect.sh +0 -336
- package/plugins/specweave/hooks/stop-sync.sh +0 -283
- package/plugins/specweave/hooks/tests/test-auto-context-integration.sh +0 -126
- package/plugins/specweave/hooks/tests/test-stop-auto-enriched.sh +0 -128
- package/plugins/specweave/hooks/universal/dispatcher.mjs +0 -336
- package/plugins/specweave/hooks/universal/fail-fast-wrapper.sh +0 -325
- package/plugins/specweave/hooks/universal/hook-wrapper.cmd +0 -26
- package/plugins/specweave/hooks/universal/hook-wrapper.sh +0 -69
- package/plugins/specweave/hooks/universal/run-hook.sh +0 -20
- package/plugins/specweave/hooks/universal/session-start.cmd +0 -16
- package/plugins/specweave/hooks/universal/session-start.ps1 +0 -16
- package/plugins/specweave/hooks/user-prompt-submit.sh +0 -2550
- package/plugins/specweave/hooks/v2/detectors/lifecycle-detector.sh +0 -87
- package/plugins/specweave/hooks/v2/detectors/us-completion-detector.sh +0 -186
- package/plugins/specweave/hooks/v2/dispatchers/post-tool-use-analytics.sh +0 -83
- package/plugins/specweave/hooks/v2/dispatchers/post-tool-use.sh +0 -447
- package/plugins/specweave/hooks/v2/dispatchers/pre-tool-use.sh +0 -104
- package/plugins/specweave/hooks/v2/dispatchers/session-start.sh +0 -270
- package/plugins/specweave/hooks/v2/guards/completion-guard.sh +0 -14
- package/plugins/specweave/hooks/v2/guards/increment-duplicate-guard.sh +0 -14
- package/plugins/specweave/hooks/v2/guards/increment-existence-guard.sh +0 -240
- package/plugins/specweave/hooks/v2/guards/interview-enforcement-guard.sh +0 -171
- package/plugins/specweave/hooks/v2/guards/metadata-json-guard.sh +0 -14
- package/plugins/specweave/hooks/v2/guards/skill-chain-enforcement-guard.sh +0 -222
- package/plugins/specweave/hooks/v2/guards/spec-template-enforcement-guard.sh +0 -21
- package/plugins/specweave/hooks/v2/guards/spec-validation-guard.sh +0 -14
- package/plugins/specweave/hooks/v2/guards/status-completion-guard.sh +0 -84
- package/plugins/specweave/hooks/v2/guards/task-ac-sync-guard.sh +0 -475
- package/plugins/specweave/hooks/v2/guards/tdd-enforcement-guard.sh +0 -268
- package/plugins/specweave/hooks/v2/handlers/ac-sync-dispatcher.sh +0 -332
- package/plugins/specweave/hooks/v2/handlers/ac-validation-handler.sh +0 -50
- package/plugins/specweave/hooks/v2/handlers/github-sync-handler.sh +0 -347
- package/plugins/specweave/hooks/v2/handlers/living-docs-handler.sh +0 -83
- package/plugins/specweave/hooks/v2/handlers/living-specs-handler.sh +0 -268
- package/plugins/specweave/hooks/v2/handlers/project-bridge-handler.sh +0 -104
- package/plugins/specweave/hooks/v2/handlers/status-line-handler.sh +0 -165
- package/plugins/specweave/hooks/v2/handlers/status-update.sh +0 -61
- package/plugins/specweave/hooks/v2/handlers/universal-auto-create-dispatcher.sh +0 -270
- package/plugins/specweave/hooks/v2/integrations/ado-post-living-docs-update.sh +0 -367
- package/plugins/specweave/hooks/v2/integrations/ado-post-task.sh +0 -179
- package/plugins/specweave/hooks/v2/integrations/github-auto-create-handler.sh +0 -553
- package/plugins/specweave/hooks/v2/integrations/github-post-task.sh +0 -345
- package/plugins/specweave/hooks/v2/integrations/jira-post-task.sh +0 -180
- package/plugins/specweave/hooks/v2/lib/check-provider-enabled.sh +0 -52
- package/plugins/specweave/hooks/v2/queue/enqueue.sh +0 -81
- package/plugins/specweave/hooks/v2/session-end.sh +0 -139
- package/plugins/specweave/hooks/validate-skill-activations.sh +0 -227
|
@@ -1,283 +0,0 @@
|
|
|
1
|
-
#!/bin/bash
|
|
2
|
-
# stop-sync.sh - Batched external tool sync at session end
|
|
3
|
-
#
|
|
4
|
-
# NEW ARCHITECTURE (v1.0.148):
|
|
5
|
-
# - NO background processor - sync happens at session end
|
|
6
|
-
# - Batches all pending events, deduplicates, syncs once per increment
|
|
7
|
-
# - Calls project-bridge-handler for universal sync (GitHub/JIRA/ADO)
|
|
8
|
-
#
|
|
9
|
-
# This runs AFTER stop-reflect.sh and stop-auto.sh in the Stop hook chain.
|
|
10
|
-
#
|
|
11
|
-
# Design:
|
|
12
|
-
# 1. Read pending events from .specweave/state/event-queue/pending.jsonl
|
|
13
|
-
# 2. Deduplicate by increment ID (process each increment ONCE)
|
|
14
|
-
# 3. Call project-bridge-handler for each unique increment
|
|
15
|
-
# 4. Clean up processed events
|
|
16
|
-
#
|
|
17
|
-
# IMPORTANT: Always returns approve, never blocks session exit
|
|
18
|
-
|
|
19
|
-
set +e # Never fail
|
|
20
|
-
|
|
21
|
-
# Read input from stdin (required by Claude Code)
|
|
22
|
-
INPUT=$(cat)
|
|
23
|
-
|
|
24
|
-
# Project root detection (walk up to find .specweave/ — prevents pollution of subdirectories)
|
|
25
|
-
if [[ -n "${PROJECT_ROOT:-}" ]] && [[ -f "$PROJECT_ROOT/.specweave/config.json" ]]; then
|
|
26
|
-
: # env var already set and valid
|
|
27
|
-
else
|
|
28
|
-
PROJECT_ROOT="$PWD"
|
|
29
|
-
while [[ "$PROJECT_ROOT" != "/" ]] && [[ ! -f "$PROJECT_ROOT/.specweave/config.json" ]]; do
|
|
30
|
-
PROJECT_ROOT=$(dirname "$PROJECT_ROOT")
|
|
31
|
-
done
|
|
32
|
-
fi
|
|
33
|
-
|
|
34
|
-
# Silent approve helper
|
|
35
|
-
silent_approve() {
|
|
36
|
-
echo '{"decision":"approve"}'
|
|
37
|
-
exit 0
|
|
38
|
-
}
|
|
39
|
-
|
|
40
|
-
# Not a SpecWeave project — approve and exit (MUST be before any mkdir)
|
|
41
|
-
[ ! -f "$PROJECT_ROOT/.specweave/config.json" ] && silent_approve
|
|
42
|
-
|
|
43
|
-
STATE_DIR="$PROJECT_ROOT/.specweave/state"
|
|
44
|
-
QUEUE_DIR="$STATE_DIR/event-queue"
|
|
45
|
-
PENDING_FILE="$QUEUE_DIR/pending.jsonl"
|
|
46
|
-
LOGS_DIR="$PROJECT_ROOT/.specweave/logs"
|
|
47
|
-
LOG_FILE="$LOGS_DIR/stop-sync.log"
|
|
48
|
-
HANDLER_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")/v2/handlers" 2>/dev/null && pwd)"
|
|
49
|
-
|
|
50
|
-
# Create logs directory
|
|
51
|
-
mkdir -p "$LOGS_DIR" 2>/dev/null || true
|
|
52
|
-
|
|
53
|
-
log() {
|
|
54
|
-
echo "[$(date -u +%Y-%m-%dT%H:%M:%SZ)] $1" >> "$LOG_FILE" 2>/dev/null
|
|
55
|
-
}
|
|
56
|
-
|
|
57
|
-
log "Stop-sync started"
|
|
58
|
-
|
|
59
|
-
# Check if there are pending events
|
|
60
|
-
if [ ! -f "$PENDING_FILE" ] || [ ! -s "$PENDING_FILE" ]; then
|
|
61
|
-
# Also check old-style .event files for migration
|
|
62
|
-
OLD_EVENTS=$(find "$QUEUE_DIR" -name "*.event" 2>/dev/null | head -1)
|
|
63
|
-
if [ -z "$OLD_EVENTS" ]; then
|
|
64
|
-
log "No pending events to sync"
|
|
65
|
-
silent_approve
|
|
66
|
-
fi
|
|
67
|
-
fi
|
|
68
|
-
|
|
69
|
-
# Check if project-bridge-handler exists
|
|
70
|
-
BRIDGE_HANDLER="$HANDLER_DIR/project-bridge-handler.sh"
|
|
71
|
-
if [ ! -f "$BRIDGE_HANDLER" ]; then
|
|
72
|
-
log "WARN: project-bridge-handler.sh not found at $BRIDGE_HANDLER"
|
|
73
|
-
silent_approve
|
|
74
|
-
fi
|
|
75
|
-
|
|
76
|
-
# Cross-platform timeout wrapper
|
|
77
|
-
# FIXED (v1.0.302): Don't suppress stderr from inner commands
|
|
78
|
-
run_with_timeout() {
|
|
79
|
-
local timeout_secs="$1"
|
|
80
|
-
shift
|
|
81
|
-
if command -v timeout >/dev/null 2>&1; then
|
|
82
|
-
timeout "$timeout_secs" "$@" || true
|
|
83
|
-
elif command -v gtimeout >/dev/null 2>&1; then
|
|
84
|
-
gtimeout "$timeout_secs" "$@" || true
|
|
85
|
-
else
|
|
86
|
-
"$@" || true
|
|
87
|
-
fi
|
|
88
|
-
}
|
|
89
|
-
|
|
90
|
-
# ============================================================================
|
|
91
|
-
# COLLECT UNIQUE INCREMENTS TO SYNC
|
|
92
|
-
# Deduplication: each increment synced only ONCE regardless of event count
|
|
93
|
-
# ============================================================================
|
|
94
|
-
|
|
95
|
-
INCREMENTS_TO_SYNC=""
|
|
96
|
-
PROCESSED_FILE="$QUEUE_DIR/.processed-$$"
|
|
97
|
-
EVENT_TYPES_FILE="$QUEUE_DIR/.event-types-$$"
|
|
98
|
-
> "$EVENT_TYPES_FILE" 2>/dev/null || true
|
|
99
|
-
|
|
100
|
-
# Process new-style pending.jsonl
|
|
101
|
-
if [ -f "$PENDING_FILE" ] && [ -s "$PENDING_FILE" ]; then
|
|
102
|
-
log "Processing pending.jsonl..."
|
|
103
|
-
|
|
104
|
-
# Extract unique increment IDs and track event types
|
|
105
|
-
while IFS= read -r line; do
|
|
106
|
-
[ -z "$line" ] && continue
|
|
107
|
-
|
|
108
|
-
# Extract increment ID from event data
|
|
109
|
-
# Format: {"type":"task.updated","data":"0001-feature-name","ts":"..."}
|
|
110
|
-
INC_ID=$(echo "$line" | grep -o '"data":"[^"]*"' | cut -d'"' -f4 | grep -o '^[0-9][0-9][0-9][0-9]-[^:]*' | head -1)
|
|
111
|
-
EVENT_TYPE=$(echo "$line" | grep -o '"type":"[^"]*"' | cut -d'"' -f4)
|
|
112
|
-
|
|
113
|
-
if [ -n "$INC_ID" ]; then
|
|
114
|
-
# Add to list if not already present
|
|
115
|
-
if ! echo "$INCREMENTS_TO_SYNC" | grep -q "$INC_ID"; then
|
|
116
|
-
INCREMENTS_TO_SYNC="$INCREMENTS_TO_SYNC $INC_ID"
|
|
117
|
-
log "Queued for sync: $INC_ID"
|
|
118
|
-
fi
|
|
119
|
-
# Track event type for this increment
|
|
120
|
-
if [ -n "$EVENT_TYPE" ]; then
|
|
121
|
-
echo "${INC_ID}|${EVENT_TYPE}" >> "$EVENT_TYPES_FILE" 2>/dev/null
|
|
122
|
-
fi
|
|
123
|
-
fi
|
|
124
|
-
done < "$PENDING_FILE"
|
|
125
|
-
fi
|
|
126
|
-
|
|
127
|
-
# Process old-style .event files (migration path)
|
|
128
|
-
# Use nullglob to handle empty glob (no matching files)
|
|
129
|
-
shopt -s nullglob
|
|
130
|
-
for event_file in "$QUEUE_DIR"/*.event; do
|
|
131
|
-
[ ! -f "$event_file" ] && continue
|
|
132
|
-
|
|
133
|
-
# Extract increment ID from event
|
|
134
|
-
INC_ID=$(cat "$event_file" 2>/dev/null | grep -o '"data":"[^"]*"' | cut -d'"' -f4 | grep -o '^[0-9][0-9][0-9][0-9]-[^:]*' | head -1)
|
|
135
|
-
|
|
136
|
-
if [ -n "$INC_ID" ]; then
|
|
137
|
-
if ! echo "$INCREMENTS_TO_SYNC" | grep -q "$INC_ID"; then
|
|
138
|
-
INCREMENTS_TO_SYNC="$INCREMENTS_TO_SYNC $INC_ID"
|
|
139
|
-
log "Queued for sync (legacy): $INC_ID"
|
|
140
|
-
fi
|
|
141
|
-
fi
|
|
142
|
-
|
|
143
|
-
# Mark for cleanup
|
|
144
|
-
echo "$event_file" >> "$PROCESSED_FILE"
|
|
145
|
-
done
|
|
146
|
-
shopt -u nullglob # Restore default glob behavior
|
|
147
|
-
|
|
148
|
-
# ============================================================================
|
|
149
|
-
# SYNC EACH INCREMENT (batched, deduplicated)
|
|
150
|
-
# ============================================================================
|
|
151
|
-
|
|
152
|
-
SYNC_COUNT=0
|
|
153
|
-
SYNC_FAILED=0
|
|
154
|
-
|
|
155
|
-
# Determine best event type for an increment from queued events
|
|
156
|
-
# Priority: done > created > user-story.completed > reopened > user-story.reopened > sync (catch-all)
|
|
157
|
-
get_best_event_type() {
|
|
158
|
-
local inc_id="$1"
|
|
159
|
-
if [ -f "$EVENT_TYPES_FILE" ]; then
|
|
160
|
-
if grep -q "^${inc_id}|increment\.done$" "$EVENT_TYPES_FILE" 2>/dev/null; then
|
|
161
|
-
echo "increment.done"
|
|
162
|
-
elif grep -q "^${inc_id}|increment\.created$" "$EVENT_TYPES_FILE" 2>/dev/null; then
|
|
163
|
-
echo "increment.created"
|
|
164
|
-
elif grep -q "^${inc_id}|user-story\.completed$" "$EVENT_TYPES_FILE" 2>/dev/null; then
|
|
165
|
-
echo "user-story.completed"
|
|
166
|
-
elif grep -q "^${inc_id}|increment\.reopened$" "$EVENT_TYPES_FILE" 2>/dev/null; then
|
|
167
|
-
echo "increment.reopened"
|
|
168
|
-
elif grep -q "^${inc_id}|user-story\.reopened$" "$EVENT_TYPES_FILE" 2>/dev/null; then
|
|
169
|
-
echo "user-story.reopened"
|
|
170
|
-
else
|
|
171
|
-
echo "increment.sync"
|
|
172
|
-
fi
|
|
173
|
-
else
|
|
174
|
-
echo "increment.sync"
|
|
175
|
-
fi
|
|
176
|
-
}
|
|
177
|
-
|
|
178
|
-
# Resolve github-sync-handler path (for user-story event routing)
|
|
179
|
-
GITHUB_SYNC_HANDLER="$HANDLER_DIR/github-sync-handler.sh"
|
|
180
|
-
|
|
181
|
-
# Resolve living-specs-handler path (for lifecycle event routing)
|
|
182
|
-
# BUGFIX: living-specs-handler was never called after v1.0.148 migration from processor.js
|
|
183
|
-
# This handler updates .specweave/docs/internal/specs/ on lifecycle changes
|
|
184
|
-
LIVING_SPECS_HANDLER="$HANDLER_DIR/living-specs-handler.sh"
|
|
185
|
-
|
|
186
|
-
for INC_ID in $INCREMENTS_TO_SYNC; do
|
|
187
|
-
[ -z "$INC_ID" ] && continue
|
|
188
|
-
|
|
189
|
-
# Preserve original event type from pending.jsonl (best priority wins)
|
|
190
|
-
EVENT_TYPE=$(get_best_event_type "$INC_ID")
|
|
191
|
-
log "Syncing increment: $INC_ID (event: $EVENT_TYPE)"
|
|
192
|
-
|
|
193
|
-
if run_with_timeout 30 bash "$BRIDGE_HANDLER" "$EVENT_TYPE" "$INC_ID"; then
|
|
194
|
-
SYNC_COUNT=$((SYNC_COUNT + 1))
|
|
195
|
-
log "Sync succeeded: $INC_ID"
|
|
196
|
-
else
|
|
197
|
-
SYNC_FAILED=$((SYNC_FAILED + 1))
|
|
198
|
-
log "Sync failed: $INC_ID"
|
|
199
|
-
fi
|
|
200
|
-
|
|
201
|
-
# Route lifecycle events to living-specs-handler
|
|
202
|
-
# Updates living docs (specs/) on increment create/done/archive/reopen
|
|
203
|
-
if [ -f "$LIVING_SPECS_HANDLER" ]; then
|
|
204
|
-
case "$EVENT_TYPE" in
|
|
205
|
-
increment.created|increment.done|increment.archived|increment.reopened)
|
|
206
|
-
log "Routing lifecycle event to living-specs-handler: $EVENT_TYPE $INC_ID"
|
|
207
|
-
run_with_timeout 30 bash "$LIVING_SPECS_HANDLER" "$EVENT_TYPE" "$INC_ID"
|
|
208
|
-
;;
|
|
209
|
-
esac
|
|
210
|
-
fi
|
|
211
|
-
|
|
212
|
-
# Route user-story events to github-sync-handler (v1.0.262+)
|
|
213
|
-
# github-sync-handler understands user-story.completed/reopened with INC_ID:US_ID data
|
|
214
|
-
# FIXED (v1.0.302): Filter by BOTH event type AND increment ID to prevent
|
|
215
|
-
# routing all events to the first matching increment's US event.
|
|
216
|
-
if [ -f "$GITHUB_SYNC_HANDLER" ] && [ -f "$EVENT_TYPES_FILE" ]; then
|
|
217
|
-
while IFS='|' read -r _inc_id us_event_type; do
|
|
218
|
-
[ -z "$us_event_type" ] && continue
|
|
219
|
-
# Extract US data (INC_ID:US_ID) from pending.jsonl for THIS increment
|
|
220
|
-
# Must match both the event type AND the increment ID in the data field
|
|
221
|
-
US_DATA=$(grep "\"type\":\"${us_event_type}\"" "$PENDING_FILE" 2>/dev/null \
|
|
222
|
-
| grep "\"data\":\"${INC_ID}:" \
|
|
223
|
-
| grep -o '"data":"[^"]*"' | cut -d'"' -f4 | head -1)
|
|
224
|
-
if [ -n "$US_DATA" ]; then
|
|
225
|
-
log "Routing user-story event to github-sync-handler: $us_event_type $US_DATA"
|
|
226
|
-
run_with_timeout 30 bash "$GITHUB_SYNC_HANDLER" "$us_event_type" "$US_DATA"
|
|
227
|
-
fi
|
|
228
|
-
done < <(grep "^${INC_ID}|user-story\." "$EVENT_TYPES_FILE" 2>/dev/null | sort -u)
|
|
229
|
-
fi
|
|
230
|
-
done
|
|
231
|
-
|
|
232
|
-
# ============================================================================
|
|
233
|
-
# CLEANUP PROCESSED EVENTS
|
|
234
|
-
# ============================================================================
|
|
235
|
-
|
|
236
|
-
# Clear pending.jsonl (all events processed)
|
|
237
|
-
if [ -f "$PENDING_FILE" ]; then
|
|
238
|
-
> "$PENDING_FILE" # Truncate file
|
|
239
|
-
log "Cleared pending.jsonl"
|
|
240
|
-
fi
|
|
241
|
-
|
|
242
|
-
# Remove old-style .event files
|
|
243
|
-
if [ -f "$PROCESSED_FILE" ]; then
|
|
244
|
-
while IFS= read -r event_file; do
|
|
245
|
-
rm -f "$event_file" 2>/dev/null
|
|
246
|
-
done < "$PROCESSED_FILE"
|
|
247
|
-
rm -f "$PROCESSED_FILE"
|
|
248
|
-
log "Cleaned up legacy .event files"
|
|
249
|
-
fi
|
|
250
|
-
|
|
251
|
-
# Clean up event-types temp file
|
|
252
|
-
rm -f "$EVENT_TYPES_FILE" 2>/dev/null
|
|
253
|
-
|
|
254
|
-
# ============================================================================
|
|
255
|
-
# REPORT RESULTS
|
|
256
|
-
# ============================================================================
|
|
257
|
-
|
|
258
|
-
if [ "$SYNC_COUNT" -gt 0 ] || [ "$SYNC_FAILED" -gt 0 ]; then
|
|
259
|
-
log "Sync complete: $SYNC_COUNT succeeded, $SYNC_FAILED failed"
|
|
260
|
-
|
|
261
|
-
if [ "$SYNC_FAILED" -gt 0 ]; then
|
|
262
|
-
# Show warning but don't block
|
|
263
|
-
SYNC_MSG="
|
|
264
|
-
┌─────────────────────────────────────────────────────────────────────────────┐
|
|
265
|
-
│ 🔄 EXTERNAL SYNC: $SYNC_COUNT synced, $SYNC_FAILED failed │
|
|
266
|
-
├─────────────────────────────────────────────────────────────────────────────┤
|
|
267
|
-
│ Some increments failed to sync to external tools. │
|
|
268
|
-
│ Check logs: .specweave/logs/stop-sync.log │
|
|
269
|
-
│ │
|
|
270
|
-
│ 💡 Run /sw-github:sync or /sw-jira:sync manually to retry │
|
|
271
|
-
└─────────────────────────────────────────────────────────────────────────────┘"
|
|
272
|
-
|
|
273
|
-
jq -n \
|
|
274
|
-
--arg decision "approve" \
|
|
275
|
-
--arg reason "External sync completed with $SYNC_FAILED failures" \
|
|
276
|
-
--arg systemMessage "$SYNC_MSG" \
|
|
277
|
-
'{decision: $decision, reason: $reason, systemMessage: $systemMessage}'
|
|
278
|
-
exit 0
|
|
279
|
-
fi
|
|
280
|
-
fi
|
|
281
|
-
|
|
282
|
-
# Silent success
|
|
283
|
-
silent_approve
|
|
@@ -1,126 +0,0 @@
|
|
|
1
|
-
#!/bin/bash
|
|
2
|
-
# Integration test: scored selection + enriched feedback (T-012, AC-US1-01, AC-US2-01, AC-US3-01)
|
|
3
|
-
# Creates a mock .specweave/ project, scores increments, and verifies enrichment helpers.
|
|
4
|
-
|
|
5
|
-
set -e
|
|
6
|
-
|
|
7
|
-
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
|
8
|
-
SCORE_SCRIPT="$SCRIPT_DIR/../lib/score-increment.sh"
|
|
9
|
-
STOP_HOOK="$SCRIPT_DIR/../stop-auto-v5.sh"
|
|
10
|
-
TMPDIR_ROOT=$(mktemp -d)
|
|
11
|
-
trap 'rm -rf "$TMPDIR_ROOT"' EXIT
|
|
12
|
-
|
|
13
|
-
PASS=0; FAIL=0
|
|
14
|
-
|
|
15
|
-
assert_eq() {
|
|
16
|
-
if [ "$1" = "$2" ]; then
|
|
17
|
-
echo " ✓ $3"; PASS=$((PASS+1))
|
|
18
|
-
else
|
|
19
|
-
echo " ✗ $3 (expected '$2', got '$1')"; FAIL=$((FAIL+1))
|
|
20
|
-
fi
|
|
21
|
-
}
|
|
22
|
-
|
|
23
|
-
assert_gt() {
|
|
24
|
-
if [ "$1" -gt "$2" ]; then
|
|
25
|
-
echo " ✓ $3 ($1 > $2)"; PASS=$((PASS+1))
|
|
26
|
-
else
|
|
27
|
-
echo " ✗ $3 (expected $1 > $2)"; FAIL=$((FAIL+1))
|
|
28
|
-
fi
|
|
29
|
-
}
|
|
30
|
-
|
|
31
|
-
assert_contains() {
|
|
32
|
-
if echo "$1" | grep -q "$2"; then
|
|
33
|
-
echo " ✓ $3"; PASS=$((PASS+1))
|
|
34
|
-
else
|
|
35
|
-
echo " ✗ $3 (expected '$1' to contain '$2')"; FAIL=$((FAIL+1))
|
|
36
|
-
fi
|
|
37
|
-
}
|
|
38
|
-
|
|
39
|
-
echo "Integration: scored selection + enriched feedback"
|
|
40
|
-
echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
|
|
41
|
-
|
|
42
|
-
# Setup mock .specweave/ structure
|
|
43
|
-
SW="$TMPDIR_ROOT/.specweave"
|
|
44
|
-
INC_DIR="$SW/increments"
|
|
45
|
-
STATE_DIR="$SW/state"
|
|
46
|
-
LOGS_DIR="$SW/logs"
|
|
47
|
-
mkdir -p "$INC_DIR/0100-user-auth" "$INC_DIR/0101-deploy-pipeline" "$STATE_DIR" "$LOGS_DIR"
|
|
48
|
-
|
|
49
|
-
# Create increment 0100: auth
|
|
50
|
-
echo '{"title":"User Authentication Feature","status":"active","lastActivity":"2026-02-18T10:00:00Z"}' \
|
|
51
|
-
> "$INC_DIR/0100-user-auth/metadata.json"
|
|
52
|
-
cat > "$INC_DIR/0100-user-auth/spec.md" << 'EOF'
|
|
53
|
-
# User Authentication Feature
|
|
54
|
-
|
|
55
|
-
Implement login, signup, and OAuth for user authentication.
|
|
56
|
-
EOF
|
|
57
|
-
cat > "$INC_DIR/0100-user-auth/tasks.md" << 'EOF'
|
|
58
|
-
### T-001: Add login endpoint
|
|
59
|
-
**Status**: [x] completed
|
|
60
|
-
### T-002: Add signup endpoint
|
|
61
|
-
**Status**: [x] completed
|
|
62
|
-
### T-003: OAuth integration
|
|
63
|
-
**Status**: [ ] pending
|
|
64
|
-
### T-004: Session management
|
|
65
|
-
**Status**: [ ] pending
|
|
66
|
-
EOF
|
|
67
|
-
|
|
68
|
-
# Create increment 0101: deploy
|
|
69
|
-
echo '{"title":"CI/CD Deploy Pipeline","status":"active","lastActivity":"2026-02-17T10:00:00Z"}' \
|
|
70
|
-
> "$INC_DIR/0101-deploy-pipeline/metadata.json"
|
|
71
|
-
cat > "$INC_DIR/0101-deploy-pipeline/spec.md" << 'EOF'
|
|
72
|
-
# CI/CD Deploy Pipeline
|
|
73
|
-
|
|
74
|
-
Setup continuous integration and deployment pipeline with Docker and GitHub Actions.
|
|
75
|
-
EOF
|
|
76
|
-
cat > "$INC_DIR/0101-deploy-pipeline/tasks.md" << 'EOF'
|
|
77
|
-
### T-001: Create Dockerfile
|
|
78
|
-
**Status**: [x] completed
|
|
79
|
-
### T-002: Configure GitHub Actions
|
|
80
|
-
**Status**: [ ] pending
|
|
81
|
-
### T-003: Set up staging environment
|
|
82
|
-
**Status**: [ ] pending
|
|
83
|
-
EOF
|
|
84
|
-
|
|
85
|
-
# TC-015: Scored selection — auth scores higher for "fix authentication"
|
|
86
|
-
s_auth=$(bash "$SCORE_SCRIPT" "$INC_DIR/0100-user-auth" "fix authentication" 2>/dev/null)
|
|
87
|
-
s_deploy=$(bash "$SCORE_SCRIPT" "$INC_DIR/0101-deploy-pipeline" "fix authentication" 2>/dev/null)
|
|
88
|
-
assert_gt "$s_auth" "$s_deploy" "TC-015a: auth scores higher than deploy for auth prompt"
|
|
89
|
-
|
|
90
|
-
# TC-015b: Deploy scores higher for "deploy pipeline docker"
|
|
91
|
-
s_auth2=$(bash "$SCORE_SCRIPT" "$INC_DIR/0100-user-auth" "deploy pipeline docker" 2>/dev/null)
|
|
92
|
-
s_deploy2=$(bash "$SCORE_SCRIPT" "$INC_DIR/0101-deploy-pipeline" "deploy pipeline docker" 2>/dev/null)
|
|
93
|
-
assert_gt "$s_deploy2" "$s_auth2" "TC-015b: deploy scores higher for deploy prompt"
|
|
94
|
-
|
|
95
|
-
# TC-015c: userGoal wiring — verify logic matches setup-auto.sh
|
|
96
|
-
AUTO_MODE_FILE="$STATE_DIR/auto-mode.json"
|
|
97
|
-
PROMPT="fix authentication"
|
|
98
|
-
if [ -f "$AUTO_MODE_FILE" ]; then
|
|
99
|
-
if [ -n "$PROMPT" ]; then
|
|
100
|
-
_UPDATED=$(jq --arg g "$PROMPT" '.userGoal = $g' "$AUTO_MODE_FILE" 2>/dev/null)
|
|
101
|
-
else
|
|
102
|
-
_UPDATED=$(jq '.userGoal = null' "$AUTO_MODE_FILE" 2>/dev/null)
|
|
103
|
-
fi
|
|
104
|
-
[ -n "$_UPDATED" ] && echo "$_UPDATED" > "$AUTO_MODE_FILE"
|
|
105
|
-
elif [ -n "$PROMPT" ]; then
|
|
106
|
-
jq -n --arg g "$PROMPT" '{"active":false,"userGoal":$g}' > "$AUTO_MODE_FILE"
|
|
107
|
-
fi
|
|
108
|
-
goal=$(jq -r '.userGoal' "$AUTO_MODE_FILE")
|
|
109
|
-
assert_eq "$goal" "fix authentication" "TC-015c: userGoal written to auto-mode.json"
|
|
110
|
-
|
|
111
|
-
# TC-015d: Stop hook enrichment — source hook, test helpers
|
|
112
|
-
export PROJECT_ROOT="$TMPDIR_ROOT"
|
|
113
|
-
export __STOP_AUTO_V5_SOURCED=1
|
|
114
|
-
source "$STOP_HOOK" 2>/dev/null
|
|
115
|
-
|
|
116
|
-
next_auth=$(get_next_task_title "$INC_DIR/0100-user-auth/tasks.md")
|
|
117
|
-
assert_eq "$next_auth" "OAuth integration" "TC-015d: enriched next task from auth increment"
|
|
118
|
-
|
|
119
|
-
done_auth=$(count_completed_tasks "$INC_DIR/0100-user-auth/tasks.md")
|
|
120
|
-
pending_auth=$(count_pending_tasks "$INC_DIR/0100-user-auth/tasks.md")
|
|
121
|
-
assert_eq "$done_auth" "2" "TC-015e: auth increment done count = 2"
|
|
122
|
-
assert_eq "$pending_auth" "2" "TC-015f: auth increment pending count = 2"
|
|
123
|
-
|
|
124
|
-
echo ""
|
|
125
|
-
echo "Results: $PASS passed, $FAIL failed"
|
|
126
|
-
[ "$FAIL" -eq 0 ] || exit 1
|
|
@@ -1,128 +0,0 @@
|
|
|
1
|
-
#!/bin/bash
|
|
2
|
-
# Tests for enriched stop hook feedback (AC-US3-01, AC-US3-02, AC-US3-03, AC-US4-01, AC-US4-03)
|
|
3
|
-
# Sources stop-auto-v5.sh to load helper functions only.
|
|
4
|
-
|
|
5
|
-
set -e
|
|
6
|
-
|
|
7
|
-
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
|
8
|
-
STOP_HOOK="$SCRIPT_DIR/../stop-auto-v5.sh"
|
|
9
|
-
TMPDIR_ROOT=$(mktemp -d)
|
|
10
|
-
trap 'rm -rf "$TMPDIR_ROOT"' EXIT
|
|
11
|
-
|
|
12
|
-
PASS=0; FAIL=0
|
|
13
|
-
|
|
14
|
-
assert_eq() {
|
|
15
|
-
if [ "$1" = "$2" ]; then
|
|
16
|
-
echo " ✓ $3"; PASS=$((PASS+1))
|
|
17
|
-
else
|
|
18
|
-
echo " ✗ $3 (expected '$2', got '$1')"; FAIL=$((FAIL+1))
|
|
19
|
-
fi
|
|
20
|
-
}
|
|
21
|
-
|
|
22
|
-
assert_ge() {
|
|
23
|
-
if [ "$1" -ge "$2" ]; then
|
|
24
|
-
echo " ✓ $3 ($1 >= $2)"; PASS=$((PASS+1))
|
|
25
|
-
else
|
|
26
|
-
echo " ✗ $3 (expected >= $2, got $1)"; FAIL=$((FAIL+1))
|
|
27
|
-
fi
|
|
28
|
-
}
|
|
29
|
-
|
|
30
|
-
# Set up minimal .specweave structure so sourcing succeeds
|
|
31
|
-
export PROJECT_ROOT="$TMPDIR_ROOT"
|
|
32
|
-
mkdir -p "$TMPDIR_ROOT/.specweave/logs" "$TMPDIR_ROOT/.specweave/state" "$TMPDIR_ROOT/.specweave/increments"
|
|
33
|
-
|
|
34
|
-
# Source only (loads helper functions, skips main execution)
|
|
35
|
-
export __STOP_AUTO_V5_SOURCED=1
|
|
36
|
-
source "$STOP_HOOK" 2>/dev/null
|
|
37
|
-
|
|
38
|
-
echo "stop-auto-v5.sh enrichment function tests"
|
|
39
|
-
echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
|
|
40
|
-
|
|
41
|
-
# Create a tasks.md with known counts
|
|
42
|
-
TASKS_FILE="$TMPDIR_ROOT/tasks.md"
|
|
43
|
-
cat > "$TASKS_FILE" << 'EOF'
|
|
44
|
-
### T-001: Setup database
|
|
45
|
-
**User Story**: US-001 | **Status**: [x] completed
|
|
46
|
-
|
|
47
|
-
### T-002: Implement login
|
|
48
|
-
**User Story**: US-001 | **Status**: [x] completed
|
|
49
|
-
|
|
50
|
-
### T-003: Add unit tests
|
|
51
|
-
**User Story**: US-001 | **Status**: [x] completed
|
|
52
|
-
|
|
53
|
-
### T-004: Write integration tests
|
|
54
|
-
**User Story**: US-001 | **Status**: [x] completed
|
|
55
|
-
|
|
56
|
-
### T-005: Deploy to staging
|
|
57
|
-
**User Story**: US-001 | **Status**: [x] completed
|
|
58
|
-
|
|
59
|
-
### T-006: Configure auth middleware
|
|
60
|
-
**User Story**: US-001 | **Status**: [ ] pending
|
|
61
|
-
|
|
62
|
-
### T-007: Add error handling
|
|
63
|
-
**User Story**: US-001 | **Status**: [ ] pending
|
|
64
|
-
|
|
65
|
-
### T-008: Final review and cleanup
|
|
66
|
-
**User Story**: US-001 | **Status**: [ ] pending
|
|
67
|
-
EOF
|
|
68
|
-
|
|
69
|
-
# TC-010: Block message includes next task title (AC-US3-01)
|
|
70
|
-
result=$(get_next_task_title "$TASKS_FILE")
|
|
71
|
-
assert_eq "$result" "Configure auth middleware" "TC-010: get_next_task_title returns first pending task"
|
|
72
|
-
|
|
73
|
-
# TC-011: count_completed_tasks counts [x] entries
|
|
74
|
-
done_count=$(count_completed_tasks "$TASKS_FILE")
|
|
75
|
-
assert_eq "$done_count" "5" "TC-011: count_completed_tasks = 5"
|
|
76
|
-
|
|
77
|
-
# TC-012: count_pending_tasks counts [ ] entries (AC-US3-03)
|
|
78
|
-
pending_count=$(count_pending_tasks "$TASKS_FILE")
|
|
79
|
-
assert_eq "$pending_count" "3" "TC-012: count_pending_tasks = 3"
|
|
80
|
-
|
|
81
|
-
# TC-012b: Progress fraction calculation
|
|
82
|
-
total=$((done_count + pending_count))
|
|
83
|
-
assert_eq "$total" "8" "TC-012b: total = done + pending = 8"
|
|
84
|
-
|
|
85
|
-
# TC-013: Empty tasks file → zeros
|
|
86
|
-
EMPTY_FILE="$TMPDIR_ROOT/empty.md"
|
|
87
|
-
touch "$EMPTY_FILE"
|
|
88
|
-
done_empty=$(count_completed_tasks "$EMPTY_FILE")
|
|
89
|
-
pending_empty=$(count_pending_tasks "$EMPTY_FILE")
|
|
90
|
-
assert_eq "$done_empty" "0" "TC-013: empty file → 0 completed"
|
|
91
|
-
assert_eq "$pending_empty" "0" "TC-013b: empty file → 0 pending"
|
|
92
|
-
|
|
93
|
-
# TC-013c: get_next_task_title on empty file → empty string
|
|
94
|
-
next_empty=$(get_next_task_title "$EMPTY_FILE")
|
|
95
|
-
assert_eq "$next_empty" "" "TC-013c: empty file → no next title"
|
|
96
|
-
|
|
97
|
-
# TC-014: Missing file → zeros
|
|
98
|
-
done_missing=$(count_completed_tasks "/nonexistent/tasks.md")
|
|
99
|
-
assert_eq "$done_missing" "0" "TC-014: missing file → 0 completed"
|
|
100
|
-
|
|
101
|
-
# TC-015: get_next_task_title with all completed → empty
|
|
102
|
-
ALL_DONE_FILE="$TMPDIR_ROOT/all-done.md"
|
|
103
|
-
cat > "$ALL_DONE_FILE" << 'EOF'
|
|
104
|
-
### T-001: Done task one
|
|
105
|
-
**Status**: [x] completed
|
|
106
|
-
|
|
107
|
-
### T-002: Done task two
|
|
108
|
-
**Status**: [x] completed
|
|
109
|
-
EOF
|
|
110
|
-
next_done=$(get_next_task_title "$ALL_DONE_FILE")
|
|
111
|
-
assert_eq "$next_done" "" "TC-015: all done → no next title"
|
|
112
|
-
|
|
113
|
-
# TC-016: get_next_task_title with task without title pattern
|
|
114
|
-
MIXED_FILE="$TMPDIR_ROOT/mixed.md"
|
|
115
|
-
cat > "$MIXED_FILE" << 'EOF'
|
|
116
|
-
### T-001: First Task Title
|
|
117
|
-
**Status**: [x] completed
|
|
118
|
-
### T-002: Second Task Title
|
|
119
|
-
**Status**: [ ] pending
|
|
120
|
-
### T-003: Third Task Title
|
|
121
|
-
**Status**: [ ] pending
|
|
122
|
-
EOF
|
|
123
|
-
next_mixed=$(get_next_task_title "$MIXED_FILE")
|
|
124
|
-
assert_eq "$next_mixed" "Second Task Title" "TC-016: returns first pending task title"
|
|
125
|
-
|
|
126
|
-
echo ""
|
|
127
|
-
echo "Results: $PASS passed, $FAIL failed"
|
|
128
|
-
[ "$FAIL" -eq 0 ] || exit 1
|