specweave 1.0.550 → 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/CLAUDE.md +1 -1
- 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/cli/commands/init.d.ts.map +1 -1
- package/dist/src/cli/commands/init.js +5 -0
- package/dist/src/cli/commands/init.js.map +1 -1
- package/dist/src/cli/commands/refresh-plugins.d.ts.map +1 -1
- package/dist/src/cli/commands/refresh-plugins.js +11 -1
- package/dist/src/cli/commands/refresh-plugins.js.map +1 -1
- package/dist/src/cli/commands/sync-setup.d.ts.map +1 -1
- package/dist/src/cli/commands/sync-setup.js +7 -3
- package/dist/src/cli/commands/sync-setup.js.map +1 -1
- package/dist/src/cli/helpers/issue-tracker/project-mapping-wizard.d.ts +9 -0
- package/dist/src/cli/helpers/issue-tracker/project-mapping-wizard.d.ts.map +1 -1
- package/dist/src/cli/helpers/issue-tracker/project-mapping-wizard.js +9 -3
- package/dist/src/cli/helpers/issue-tracker/project-mapping-wizard.js.map +1 -1
- package/dist/src/config/types.d.ts +2 -2
- package/dist/src/core/config/types.d.ts +18 -2
- 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/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/core/increment/completion-validator.d.ts.map +1 -1
- package/dist/src/core/increment/completion-validator.js +32 -0
- package/dist/src/core/increment/completion-validator.js.map +1 -1
- 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 +10 -0
- package/dist/src/utils/plugin-copier.d.ts.map +1 -1
- package/dist/src/utils/plugin-copier.js +63 -35
- package/dist/src/utils/plugin-copier.js.map +1 -1
- package/package.json +1 -1
- package/plugins/specweave/agents/sw-closer.md +3 -2
- package/plugins/specweave/hooks/hooks.json +10 -10
- package/plugins/specweave/skills/code-reviewer/SKILL.md +180 -16
- package/plugins/specweave/skills/code-reviewer/agents/reviewer-comments.md +83 -0
- package/plugins/specweave/skills/code-reviewer/agents/reviewer-silent-failures.md +19 -0
- package/plugins/specweave/skills/code-reviewer/agents/reviewer-spec-compliance.md +19 -0
- package/plugins/specweave/skills/code-reviewer/agents/reviewer-tests.md +101 -0
- package/plugins/specweave/skills/code-reviewer/agents/reviewer-types.md +20 -0
- package/plugins/specweave/skills/done/SKILL.md +56 -21
- package/plugins/specweave/skills/grill/SKILL.md +1 -1
- package/plugins/specweave/skills/team-lead/agents/reviewer-logic.md +19 -0
- package/plugins/specweave/skills/team-lead/agents/reviewer-performance.md +20 -0
- package/plugins/specweave/skills/team-lead/agents/reviewer-security.md +20 -0
- package/src/templates/CLAUDE.md.template +7 -4
- 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,268 +0,0 @@
|
|
|
1
|
-
#!/bin/bash
|
|
2
|
-
# tdd-enforcement-guard.sh - Warn on TDD discipline violations (v1.0.105)
|
|
3
|
-
#
|
|
4
|
-
# Called from: post-tool-use.sh when tasks.md is edited
|
|
5
|
-
# Action: WARNING only (not blocking) - educates users
|
|
6
|
-
#
|
|
7
|
-
# TDD Violations detected:
|
|
8
|
-
# 1. GREEN task completed before RED task
|
|
9
|
-
# 2. REFACTOR task completed before GREEN task
|
|
10
|
-
#
|
|
11
|
-
# IMPORTANT: This is a WARNING-ONLY hook. It never blocks operations.
|
|
12
|
-
# The goal is to educate users about TDD discipline, not punish them.
|
|
13
|
-
#
|
|
14
|
-
# COMPATIBILITY: Works on macOS (bash 3.2) and Linux (bash 4+)
|
|
15
|
-
|
|
16
|
-
set +e # CRITICAL: Never exit on error - this is a warning-only hook
|
|
17
|
-
|
|
18
|
-
# ============================================================================
|
|
19
|
-
# CONFIGURATION
|
|
20
|
-
# ============================================================================
|
|
21
|
-
|
|
22
|
-
PROJECT_ROOT="${1:-$(pwd)}"
|
|
23
|
-
FILE_PATH="${2:-}"
|
|
24
|
-
TOOL_NAME="${3:-Edit}"
|
|
25
|
-
|
|
26
|
-
# Debug logging
|
|
27
|
-
LOGS_DIR="$PROJECT_ROOT/.specweave/logs"
|
|
28
|
-
DEBUG_LOG="$LOGS_DIR/tdd-enforcement.log"
|
|
29
|
-
mkdir -p "$LOGS_DIR" 2>/dev/null || true
|
|
30
|
-
|
|
31
|
-
log_debug() {
|
|
32
|
-
echo "[$(date '+%Y-%m-%d %H:%M:%S')] $*" >> "$DEBUG_LOG" 2>/dev/null || true
|
|
33
|
-
}
|
|
34
|
-
|
|
35
|
-
log_debug "tdd-enforcement-guard invoked: FILE_PATH=$FILE_PATH TOOL_NAME=$TOOL_NAME"
|
|
36
|
-
|
|
37
|
-
# ============================================================================
|
|
38
|
-
# VALIDATION
|
|
39
|
-
# ============================================================================
|
|
40
|
-
|
|
41
|
-
# Only process tasks.md files
|
|
42
|
-
case "$FILE_PATH" in
|
|
43
|
-
*tasks.md) ;;
|
|
44
|
-
*)
|
|
45
|
-
log_debug "Not a tasks.md file, skipping"
|
|
46
|
-
exit 0
|
|
47
|
-
;;
|
|
48
|
-
esac
|
|
49
|
-
|
|
50
|
-
# Extract increment directory
|
|
51
|
-
INC_DIR=$(dirname "$FILE_PATH")
|
|
52
|
-
META_FILE="$INC_DIR/metadata.json"
|
|
53
|
-
TASKS_FILE="$FILE_PATH"
|
|
54
|
-
|
|
55
|
-
# Check if files exist
|
|
56
|
-
if [ ! -f "$META_FILE" ]; then
|
|
57
|
-
log_debug "No metadata.json found at $META_FILE, skipping"
|
|
58
|
-
exit 0
|
|
59
|
-
fi
|
|
60
|
-
|
|
61
|
-
if [ ! -f "$TASKS_FILE" ]; then
|
|
62
|
-
log_debug "No tasks.md found at $TASKS_FILE, skipping"
|
|
63
|
-
exit 0
|
|
64
|
-
fi
|
|
65
|
-
|
|
66
|
-
# ============================================================================
|
|
67
|
-
# READ TEST MODE FROM METADATA
|
|
68
|
-
# ============================================================================
|
|
69
|
-
|
|
70
|
-
TEST_MODE=""
|
|
71
|
-
|
|
72
|
-
if command -v jq >/dev/null 2>&1; then
|
|
73
|
-
TEST_MODE=$(jq -r '.testMode // "test-after"' "$META_FILE" 2>/dev/null || echo "test-after")
|
|
74
|
-
else
|
|
75
|
-
# Fallback: portable grep parsing (no -P flag for macOS compatibility)
|
|
76
|
-
TEST_MODE=$(grep '"testMode"' "$META_FILE" 2>/dev/null | sed 's/.*"testMode"[[:space:]]*:[[:space:]]*"\([^"]*\)".*/\1/' || echo "test-after")
|
|
77
|
-
fi
|
|
78
|
-
|
|
79
|
-
# Default to test-after if empty
|
|
80
|
-
TEST_MODE="${TEST_MODE:-test-after}"
|
|
81
|
-
|
|
82
|
-
log_debug "testMode detected: $TEST_MODE"
|
|
83
|
-
|
|
84
|
-
# Skip if not TDD mode
|
|
85
|
-
if [ "$TEST_MODE" != "TDD" ]; then
|
|
86
|
-
log_debug "testMode is not TDD ($TEST_MODE), skipping enforcement"
|
|
87
|
-
exit 0
|
|
88
|
-
fi
|
|
89
|
-
|
|
90
|
-
# ============================================================================
|
|
91
|
-
# READ ENFORCEMENT LEVEL FROM CONFIG (v1.0.111+)
|
|
92
|
-
# ============================================================================
|
|
93
|
-
|
|
94
|
-
TDD_ENFORCEMENT="warn" # Default: warn but allow
|
|
95
|
-
|
|
96
|
-
CONFIG_FILE="$PROJECT_ROOT/.specweave/config.json"
|
|
97
|
-
if [ -f "$CONFIG_FILE" ]; then
|
|
98
|
-
if command -v jq >/dev/null 2>&1; then
|
|
99
|
-
TDD_ENFORCEMENT=$(jq -r '.testing.tddEnforcement // "warn"' "$CONFIG_FILE" 2>/dev/null || echo "warn")
|
|
100
|
-
else
|
|
101
|
-
# Fallback: grep parsing
|
|
102
|
-
TDD_ENFORCEMENT=$(grep '"tddEnforcement"' "$CONFIG_FILE" 2>/dev/null | sed 's/.*"tddEnforcement"[[:space:]]*:[[:space:]]*"\([^"]*\)".*/\1/' || echo "warn")
|
|
103
|
-
fi
|
|
104
|
-
fi
|
|
105
|
-
|
|
106
|
-
# Validate enforcement level
|
|
107
|
-
case "$TDD_ENFORCEMENT" in
|
|
108
|
-
strict|warn|off) ;;
|
|
109
|
-
*) TDD_ENFORCEMENT="warn" ;;
|
|
110
|
-
esac
|
|
111
|
-
|
|
112
|
-
log_debug "tddEnforcement level: $TDD_ENFORCEMENT"
|
|
113
|
-
|
|
114
|
-
# Skip if enforcement is off
|
|
115
|
-
if [ "$TDD_ENFORCEMENT" = "off" ]; then
|
|
116
|
-
log_debug "TDD enforcement is off, skipping"
|
|
117
|
-
exit 0
|
|
118
|
-
fi
|
|
119
|
-
|
|
120
|
-
# ============================================================================
|
|
121
|
-
# PARSE TASKS FOR TDD VIOLATIONS (macOS-compatible, no associative arrays)
|
|
122
|
-
# ============================================================================
|
|
123
|
-
|
|
124
|
-
VIOLATION_LOG="$LOGS_DIR/tdd-violations.log"
|
|
125
|
-
|
|
126
|
-
# Use temp files for cross-platform compatibility (no associative arrays)
|
|
127
|
-
COMPLETED_TASKS_FILE=$(mktemp)
|
|
128
|
-
cleanup() {
|
|
129
|
-
rm -f "$COMPLETED_TASKS_FILE" 2>/dev/null || true
|
|
130
|
-
}
|
|
131
|
-
trap cleanup EXIT
|
|
132
|
-
|
|
133
|
-
# Parse task sections and find completed TDD tasks
|
|
134
|
-
# Format: TASK_ID:PHASE
|
|
135
|
-
current_task=""
|
|
136
|
-
current_phase=""
|
|
137
|
-
|
|
138
|
-
while IFS= read -r line; do
|
|
139
|
-
# Task header: ### T-001: [RED] ... or ### T-001: [GREEN] ... or ### T-001: [REFACTOR] ...
|
|
140
|
-
case "$line" in
|
|
141
|
-
"### T-"*": ["*"]"*)
|
|
142
|
-
# Extract task ID (T-XXX)
|
|
143
|
-
current_task=$(echo "$line" | sed -n 's/^### \(T-[0-9]*\):.*/\1/p')
|
|
144
|
-
# Extract phase
|
|
145
|
-
case "$line" in
|
|
146
|
-
*"[RED]"*) current_phase="RED" ;;
|
|
147
|
-
*"[GREEN]"*) current_phase="GREEN" ;;
|
|
148
|
-
*"[REFACTOR]"*) current_phase="REFACTOR" ;;
|
|
149
|
-
*) current_phase="" ;;
|
|
150
|
-
esac
|
|
151
|
-
log_debug "Found task $current_task with phase $current_phase"
|
|
152
|
-
;;
|
|
153
|
-
esac
|
|
154
|
-
|
|
155
|
-
# Status line: **Status**: [x] completed
|
|
156
|
-
case "$line" in
|
|
157
|
-
"**Status**: [x]"*)
|
|
158
|
-
if [ -n "$current_task" ] && [ -n "$current_phase" ]; then
|
|
159
|
-
echo "$current_task:$current_phase" >> "$COMPLETED_TASKS_FILE"
|
|
160
|
-
log_debug "Task $current_task ($current_phase) is completed"
|
|
161
|
-
fi
|
|
162
|
-
current_task=""
|
|
163
|
-
current_phase=""
|
|
164
|
-
;;
|
|
165
|
-
esac
|
|
166
|
-
done < "$TASKS_FILE"
|
|
167
|
-
|
|
168
|
-
# ============================================================================
|
|
169
|
-
# CHECK FOR VIOLATIONS
|
|
170
|
-
# ============================================================================
|
|
171
|
-
|
|
172
|
-
VIOLATIONS=""
|
|
173
|
-
VIOLATION_COUNT=0
|
|
174
|
-
|
|
175
|
-
# Helper to check if a task is completed with a specific phase
|
|
176
|
-
is_completed_with_phase() {
|
|
177
|
-
local task_id="$1"
|
|
178
|
-
local expected_phase="$2"
|
|
179
|
-
grep -q "^${task_id}:${expected_phase}$" "$COMPLETED_TASKS_FILE" 2>/dev/null
|
|
180
|
-
}
|
|
181
|
-
|
|
182
|
-
# Check each completed task
|
|
183
|
-
while IFS=: read -r task_id phase; do
|
|
184
|
-
[ -z "$task_id" ] && continue
|
|
185
|
-
|
|
186
|
-
if [ "$phase" = "GREEN" ]; then
|
|
187
|
-
# GREEN task completed - check if corresponding RED is done
|
|
188
|
-
# Extract number, subtract 1, format back
|
|
189
|
-
task_num=$(echo "$task_id" | sed 's/T-0*//')
|
|
190
|
-
red_task_num=$((task_num - 1))
|
|
191
|
-
red_task_id=$(printf "T-%03d" "$red_task_num")
|
|
192
|
-
|
|
193
|
-
if ! is_completed_with_phase "$red_task_id" "RED"; then
|
|
194
|
-
VIOLATIONS="$VIOLATIONS
|
|
195
|
-
• $task_id (GREEN) completed but $red_task_id (RED) not found or not completed"
|
|
196
|
-
VIOLATION_COUNT=$((VIOLATION_COUNT + 1))
|
|
197
|
-
log_debug "VIOLATION: $task_id GREEN completed before $red_task_id RED"
|
|
198
|
-
fi
|
|
199
|
-
fi
|
|
200
|
-
|
|
201
|
-
if [ "$phase" = "REFACTOR" ]; then
|
|
202
|
-
# REFACTOR task completed - check if corresponding GREEN is done
|
|
203
|
-
task_num=$(echo "$task_id" | sed 's/T-0*//')
|
|
204
|
-
green_task_num=$((task_num - 1))
|
|
205
|
-
green_task_id=$(printf "T-%03d" "$green_task_num")
|
|
206
|
-
|
|
207
|
-
if ! is_completed_with_phase "$green_task_id" "GREEN"; then
|
|
208
|
-
VIOLATIONS="$VIOLATIONS
|
|
209
|
-
• $task_id (REFACTOR) completed but $green_task_id (GREEN) not found or not completed"
|
|
210
|
-
VIOLATION_COUNT=$((VIOLATION_COUNT + 1))
|
|
211
|
-
log_debug "VIOLATION: $task_id REFACTOR completed before $green_task_id GREEN"
|
|
212
|
-
fi
|
|
213
|
-
fi
|
|
214
|
-
done < "$COMPLETED_TASKS_FILE"
|
|
215
|
-
|
|
216
|
-
# ============================================================================
|
|
217
|
-
# OUTPUT WARNINGS
|
|
218
|
-
# ============================================================================
|
|
219
|
-
|
|
220
|
-
if [ "$VIOLATION_COUNT" -gt 0 ]; then
|
|
221
|
-
# Log violations
|
|
222
|
-
{
|
|
223
|
-
echo "[$(date '+%Y-%m-%d %H:%M:%S')] TDD violations in $(basename "$INC_DIR") (enforcement: $TDD_ENFORCEMENT):"
|
|
224
|
-
echo "$VIOLATIONS" | while IFS= read -r v; do
|
|
225
|
-
[ -n "$v" ] && echo " -$v"
|
|
226
|
-
done
|
|
227
|
-
echo ""
|
|
228
|
-
} >> "$VIOLATION_LOG" 2>/dev/null || true
|
|
229
|
-
|
|
230
|
-
# Handle based on enforcement level
|
|
231
|
-
if [ "$TDD_ENFORCEMENT" = "strict" ]; then
|
|
232
|
-
echo ""
|
|
233
|
-
echo "❌ TDD ENFORCEMENT BLOCKED"
|
|
234
|
-
echo " ────────────────────────"
|
|
235
|
-
echo " Your increment is configured for TDD mode with STRICT enforcement."
|
|
236
|
-
echo ""
|
|
237
|
-
echo " Violations detected:$VIOLATIONS"
|
|
238
|
-
echo ""
|
|
239
|
-
echo " 💡 TDD Discipline: RED → GREEN → REFACTOR"
|
|
240
|
-
echo " 1. 🔴 Complete RED (test) task FIRST"
|
|
241
|
-
echo " 2. 🟢 Then complete GREEN (implementation) task"
|
|
242
|
-
echo " 3. 🔵 Finally complete REFACTOR task"
|
|
243
|
-
echo ""
|
|
244
|
-
echo " To bypass: Set testing.tddEnforcement: \"warn\" in .specweave/config.json"
|
|
245
|
-
echo ""
|
|
246
|
-
log_debug "BLOCKING due to TDD violations (strict mode)"
|
|
247
|
-
exit 1 # BLOCK in strict mode
|
|
248
|
-
else
|
|
249
|
-
# warn mode
|
|
250
|
-
echo ""
|
|
251
|
-
echo "⚠️ TDD DISCIPLINE WARNING"
|
|
252
|
-
echo " ────────────────────────"
|
|
253
|
-
echo " Your increment is configured for TDD mode (testMode: TDD)"
|
|
254
|
-
echo ""
|
|
255
|
-
echo " Potential violations detected:$VIOLATIONS"
|
|
256
|
-
echo ""
|
|
257
|
-
echo " 💡 TDD Best Practice: RED → GREEN → REFACTOR"
|
|
258
|
-
echo " 1. 🔴 Write failing test FIRST"
|
|
259
|
-
echo " 2. 🟢 Make test pass with minimal code"
|
|
260
|
-
echo " 3. 🔵 Refactor while keeping tests green"
|
|
261
|
-
echo ""
|
|
262
|
-
echo " 💡 To enforce strictly: Set testing.tddEnforcement: \"strict\" in config.json"
|
|
263
|
-
echo ""
|
|
264
|
-
fi
|
|
265
|
-
fi
|
|
266
|
-
|
|
267
|
-
# Exit 0 for warn mode (allow), exit 1 for strict mode (handled above)
|
|
268
|
-
exit 0
|
|
@@ -1,332 +0,0 @@
|
|
|
1
|
-
#!/bin/bash
|
|
2
|
-
|
|
3
|
-
# SpecWeave Provider-Agnostic AC Sync Dispatcher (v1.0.255+)
|
|
4
|
-
# Background handler: syncs AC progress to ALL enabled providers (GitHub, JIRA, ADO).
|
|
5
|
-
#
|
|
6
|
-
# Replaces the GitHub-only github-ac-sync-handler.sh with a unified dispatcher
|
|
7
|
-
# that calls syncACProgressToProviders() for all configured providers.
|
|
8
|
-
#
|
|
9
|
-
# Triggered by post-tool-use.sh after task-ac-sync-guard updates spec.md ACs.
|
|
10
|
-
# Runs in BACKGROUND via safe_run_background — never blocks the main chain.
|
|
11
|
-
#
|
|
12
|
-
# Features:
|
|
13
|
-
# - 5s debounce (batches rapid AC changes)
|
|
14
|
-
# - Per-provider circuit breakers (managed in TypeScript)
|
|
15
|
-
# - File locking (prevents concurrent handler executions)
|
|
16
|
-
# - Non-blocking (all errors → exit 0 with logging)
|
|
17
|
-
#
|
|
18
|
-
# Usage: ac-sync-dispatcher.sh <INCREMENT_ID>
|
|
19
|
-
# Called by: safe_run_background in post-tool-use.sh
|
|
20
|
-
|
|
21
|
-
set +e # Never crash Claude Code
|
|
22
|
-
|
|
23
|
-
# EMERGENCY KILL SWITCH
|
|
24
|
-
if [[ "${SPECWEAVE_DISABLE_HOOKS:-0}" == "1" ]]; then
|
|
25
|
-
exit 0
|
|
26
|
-
fi
|
|
27
|
-
|
|
28
|
-
# ============================================================================
|
|
29
|
-
# PROJECT ROOT DETECTION
|
|
30
|
-
# ============================================================================
|
|
31
|
-
|
|
32
|
-
find_project_root() {
|
|
33
|
-
local dir="$1"
|
|
34
|
-
while [ "$dir" != "/" ]; do
|
|
35
|
-
if [ -f "$dir/.specweave/config.json" ]; then
|
|
36
|
-
echo "$dir"
|
|
37
|
-
return 0
|
|
38
|
-
fi
|
|
39
|
-
dir="$(dirname "$dir")"
|
|
40
|
-
done
|
|
41
|
-
return 1
|
|
42
|
-
}
|
|
43
|
-
|
|
44
|
-
PROJECT_ROOT="$(find_project_root "$(pwd)")"
|
|
45
|
-
if [[ -z "$PROJECT_ROOT" ]]; then
|
|
46
|
-
exit 0
|
|
47
|
-
fi
|
|
48
|
-
cd "$PROJECT_ROOT" 2>/dev/null || exit 0
|
|
49
|
-
|
|
50
|
-
# ============================================================================
|
|
51
|
-
# ARGUMENTS
|
|
52
|
-
# ============================================================================
|
|
53
|
-
|
|
54
|
-
INC_ID="$1"
|
|
55
|
-
if [[ -z "$INC_ID" ]]; then
|
|
56
|
-
exit 0
|
|
57
|
-
fi
|
|
58
|
-
|
|
59
|
-
# Validate INC_ID format (defense-in-depth against injection)
|
|
60
|
-
if [[ ! "$INC_ID" =~ ^[0-9]{4}[A-Za-z0-9_-]*$ ]]; then
|
|
61
|
-
exit 0
|
|
62
|
-
fi
|
|
63
|
-
|
|
64
|
-
SPEC_PATH="$PROJECT_ROOT/.specweave/increments/$INC_ID/spec.md"
|
|
65
|
-
METADATA_PATH="$PROJECT_ROOT/.specweave/increments/$INC_ID/metadata.json"
|
|
66
|
-
CONFIG_PATH="$PROJECT_ROOT/.specweave/config.json"
|
|
67
|
-
|
|
68
|
-
if [[ ! -f "$SPEC_PATH" ]]; then
|
|
69
|
-
exit 0
|
|
70
|
-
fi
|
|
71
|
-
|
|
72
|
-
# ============================================================================
|
|
73
|
-
# LOGGING
|
|
74
|
-
# ============================================================================
|
|
75
|
-
|
|
76
|
-
LOGS_DIR="$PROJECT_ROOT/.specweave/logs"
|
|
77
|
-
LOG_FILE="$LOGS_DIR/ac-sync-dispatcher.log"
|
|
78
|
-
mkdir -p "$LOGS_DIR" 2>/dev/null || true
|
|
79
|
-
|
|
80
|
-
log() {
|
|
81
|
-
echo "[$(date '+%Y-%m-%d %H:%M:%S')] [ac-sync] $1" >> "$LOG_FILE" 2>/dev/null || true
|
|
82
|
-
}
|
|
83
|
-
|
|
84
|
-
# ============================================================================
|
|
85
|
-
# CHECK ANY PROVIDER ENABLED
|
|
86
|
-
# ============================================================================
|
|
87
|
-
|
|
88
|
-
if [[ ! -f "$CONFIG_PATH" ]] || ! command -v jq >/dev/null 2>&1; then
|
|
89
|
-
log "Config not found or jq unavailable. Skipping."
|
|
90
|
-
exit 0
|
|
91
|
-
fi
|
|
92
|
-
|
|
93
|
-
# Use shared provider detection (supports PROFILES, LEGACY DIRECT, LEGACY PROVIDER formats)
|
|
94
|
-
HANDLER_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
|
95
|
-
SHARED_LIB="$HANDLER_DIR/../lib/check-provider-enabled.sh"
|
|
96
|
-
if [[ -f "$SHARED_LIB" ]]; then
|
|
97
|
-
source "$SHARED_LIB"
|
|
98
|
-
fi
|
|
99
|
-
|
|
100
|
-
# Source resolve-package.sh for dynamic specweave path resolution
|
|
101
|
-
RESOLVE_LIB="$HANDLER_DIR/../../lib/resolve-package.sh"
|
|
102
|
-
if [[ -f "$RESOLVE_LIB" ]]; then
|
|
103
|
-
source "$RESOLVE_LIB"
|
|
104
|
-
fi
|
|
105
|
-
|
|
106
|
-
GH_ENABLED="false"
|
|
107
|
-
JIRA_ENABLED="false"
|
|
108
|
-
ADO_ENABLED="false"
|
|
109
|
-
|
|
110
|
-
if type check_provider_enabled &>/dev/null; then
|
|
111
|
-
check_provider_enabled "$CONFIG_PATH" "github" && GH_ENABLED="true"
|
|
112
|
-
check_provider_enabled "$CONFIG_PATH" "jira" && JIRA_ENABLED="true"
|
|
113
|
-
check_provider_enabled "$CONFIG_PATH" "ado" && ADO_ENABLED="true"
|
|
114
|
-
else
|
|
115
|
-
# Fallback to legacy jq check if shared lib not available
|
|
116
|
-
GH_ENABLED=$(jq -r '.sync.github.enabled // false' "$CONFIG_PATH" 2>/dev/null)
|
|
117
|
-
JIRA_ENABLED=$(jq -r '.sync.jira.enabled // false' "$CONFIG_PATH" 2>/dev/null)
|
|
118
|
-
ADO_ENABLED=$(jq -r '.sync.ado.enabled // false' "$CONFIG_PATH" 2>/dev/null)
|
|
119
|
-
fi
|
|
120
|
-
|
|
121
|
-
if [[ "$GH_ENABLED" != "true" && "$JIRA_ENABLED" != "true" && "$ADO_ENABLED" != "true" ]]; then
|
|
122
|
-
log "No providers enabled. Skipping."
|
|
123
|
-
exit 0
|
|
124
|
-
fi
|
|
125
|
-
|
|
126
|
-
# ============================================================================
|
|
127
|
-
# FILE LOCKING
|
|
128
|
-
# ============================================================================
|
|
129
|
-
|
|
130
|
-
STATE_DIR="$PROJECT_ROOT/.specweave/state"
|
|
131
|
-
mkdir -p "$STATE_DIR" 2>/dev/null || true
|
|
132
|
-
|
|
133
|
-
LOCK_FILE="$STATE_DIR/.hook-ac-sync-dispatcher.lock"
|
|
134
|
-
LOCK_TIMEOUT=15
|
|
135
|
-
|
|
136
|
-
LOCK_ACQUIRED=false
|
|
137
|
-
for i in {1..10}; do
|
|
138
|
-
if mkdir "$LOCK_FILE" 2>/dev/null; then
|
|
139
|
-
LOCK_ACQUIRED=true
|
|
140
|
-
trap 'rmdir "$LOCK_FILE" 2>/dev/null || true' EXIT
|
|
141
|
-
break
|
|
142
|
-
fi
|
|
143
|
-
|
|
144
|
-
# Check for stale lock
|
|
145
|
-
if [[ -d "$LOCK_FILE" ]]; then
|
|
146
|
-
LOCK_AGE=$(($(date +%s) - $(stat -f%m "$LOCK_FILE" 2>/dev/null || stat -c%Y "$LOCK_FILE" 2>/dev/null || echo 0)))
|
|
147
|
-
if (( LOCK_AGE > LOCK_TIMEOUT )); then
|
|
148
|
-
rmdir "$LOCK_FILE" 2>/dev/null || true
|
|
149
|
-
continue
|
|
150
|
-
fi
|
|
151
|
-
fi
|
|
152
|
-
|
|
153
|
-
sleep 0.3
|
|
154
|
-
done
|
|
155
|
-
|
|
156
|
-
if [[ "$LOCK_ACQUIRED" == "false" ]]; then
|
|
157
|
-
log "Lock not acquired. Another instance running. Skipping."
|
|
158
|
-
exit 0
|
|
159
|
-
fi
|
|
160
|
-
|
|
161
|
-
# ============================================================================
|
|
162
|
-
# DEBOUNCE (5s window)
|
|
163
|
-
# ============================================================================
|
|
164
|
-
|
|
165
|
-
SIGNAL_FILE="$STATE_DIR/.ac-sync-pending-$INC_ID"
|
|
166
|
-
|
|
167
|
-
if [[ -f "$SIGNAL_FILE" ]]; then
|
|
168
|
-
SIGNAL_AGE=$(($(date +%s) - $(stat -f%m "$SIGNAL_FILE" 2>/dev/null || stat -c%Y "$SIGNAL_FILE" 2>/dev/null || echo 0)))
|
|
169
|
-
if (( SIGNAL_AGE < 5 )); then
|
|
170
|
-
log "Debounce: signal file age ${SIGNAL_AGE}s < 5s. Deferring."
|
|
171
|
-
exit 0
|
|
172
|
-
fi
|
|
173
|
-
fi
|
|
174
|
-
|
|
175
|
-
# Create/update signal file and wait for debounce window
|
|
176
|
-
echo "$(date +%s)" > "$SIGNAL_FILE" 2>/dev/null || true
|
|
177
|
-
sleep 5
|
|
178
|
-
|
|
179
|
-
# After sleeping, check if a NEWER invocation took over
|
|
180
|
-
if [[ -f "$SIGNAL_FILE" ]]; then
|
|
181
|
-
CURRENT_SIGNAL=$(cat "$SIGNAL_FILE" 2>/dev/null || echo 0)
|
|
182
|
-
NOW=$(date +%s)
|
|
183
|
-
SIGNAL_AGE=$((NOW - CURRENT_SIGNAL))
|
|
184
|
-
if (( SIGNAL_AGE > 6 )); then
|
|
185
|
-
log "Debounce: newer invocation detected. Exiting."
|
|
186
|
-
exit 0
|
|
187
|
-
fi
|
|
188
|
-
fi
|
|
189
|
-
|
|
190
|
-
rm -f "$SIGNAL_FILE" 2>/dev/null || true
|
|
191
|
-
|
|
192
|
-
# ============================================================================
|
|
193
|
-
# PRECONDITIONS
|
|
194
|
-
# ============================================================================
|
|
195
|
-
|
|
196
|
-
if ! command -v node &>/dev/null; then
|
|
197
|
-
log "Node.js not found. Skipping."
|
|
198
|
-
exit 0
|
|
199
|
-
fi
|
|
200
|
-
|
|
201
|
-
# ============================================================================
|
|
202
|
-
# EXTRACT AFFECTED USER STORY IDS
|
|
203
|
-
# ============================================================================
|
|
204
|
-
|
|
205
|
-
# Get all US IDs that have external links from metadata.json
|
|
206
|
-
# Reads BOTH new format (externalLinks.github.issues) and old format (github.issues[].userStory)
|
|
207
|
-
AFFECTED_US_IDS="[]"
|
|
208
|
-
if [[ -f "$METADATA_PATH" ]]; then
|
|
209
|
-
AFFECTED_US_IDS=$(jq -r '
|
|
210
|
-
[
|
|
211
|
-
(.externalLinks.github.issues // {} | keys[]),
|
|
212
|
-
(.externalLinks.jira.userStories // {} | keys[]),
|
|
213
|
-
(.externalLinks.ado.userStories // {} | keys[]),
|
|
214
|
-
(.github.issues // [] | .[].userStory // empty)
|
|
215
|
-
] | flatten | unique
|
|
216
|
-
' "$METADATA_PATH" 2>/dev/null) || AFFECTED_US_IDS="[]"
|
|
217
|
-
fi
|
|
218
|
-
|
|
219
|
-
if [[ "$AFFECTED_US_IDS" == "[]" || -z "$AFFECTED_US_IDS" ]]; then
|
|
220
|
-
log "No affected US IDs found. Skipping."
|
|
221
|
-
exit 0
|
|
222
|
-
fi
|
|
223
|
-
|
|
224
|
-
# Validate AFFECTED_US_IDS is valid JSON (defense-in-depth against injection)
|
|
225
|
-
if ! echo "$AFFECTED_US_IDS" | jq empty 2>/dev/null; then
|
|
226
|
-
log "Invalid US IDs JSON. Skipping."
|
|
227
|
-
exit 0
|
|
228
|
-
fi
|
|
229
|
-
|
|
230
|
-
# ============================================================================
|
|
231
|
-
# BUILD CONFIG FROM SPECWEAVE CONFIG + METADATA
|
|
232
|
-
# ============================================================================
|
|
233
|
-
|
|
234
|
-
# Find the sync module (compiled output) — check multiple locations
|
|
235
|
-
# Same fallback pattern as universal-auto-create-dispatcher.sh
|
|
236
|
-
SYNC_MODULE=""
|
|
237
|
-
# Derive package root from script location (handlers/ → v2/ → hooks/ → specweave/ → plugins/ → package root)
|
|
238
|
-
PKG_ROOT="$(cd "$HANDLER_DIR/../../../../.." 2>/dev/null && pwd)"
|
|
239
|
-
# 0. SPECWEAVE_PKG (set by Claude Code hook infrastructure, most reliable)
|
|
240
|
-
if [[ -n "${SPECWEAVE_PKG:-}" ]]; then
|
|
241
|
-
CANDIDATE="${SPECWEAVE_PKG}/dist/src/core/ac-progress-sync.js"
|
|
242
|
-
[[ -f "$CANDIDATE" ]] && SYNC_MODULE="$CANDIDATE"
|
|
243
|
-
fi
|
|
244
|
-
# 1. Package root (derived from script location — works for both npm and dev)
|
|
245
|
-
if [[ -z "$SYNC_MODULE" ]]; then
|
|
246
|
-
CANDIDATE="${PKG_ROOT:-$PROJECT_ROOT}/dist/src/core/ac-progress-sync.js"
|
|
247
|
-
[[ -f "$CANDIDATE" ]] && SYNC_MODULE="$CANDIDATE"
|
|
248
|
-
fi
|
|
249
|
-
# 2. resolve-package.sh (dynamic resolution)
|
|
250
|
-
if [[ -z "$SYNC_MODULE" ]]; then
|
|
251
|
-
CANDIDATE=$(find_specweave_script "dist/src/core/ac-progress-sync.js" 2>/dev/null)
|
|
252
|
-
[[ -n "$CANDIDATE" ]] && SYNC_MODULE="$CANDIDATE"
|
|
253
|
-
fi
|
|
254
|
-
# 3. Legacy: PROJECT_ROOT/dist/ (dev-only, running from source repo)
|
|
255
|
-
if [[ -z "$SYNC_MODULE" ]]; then
|
|
256
|
-
CANDIDATE="$PROJECT_ROOT/dist/src/core/ac-progress-sync.js"
|
|
257
|
-
[[ -f "$CANDIDATE" ]] && SYNC_MODULE="$CANDIDATE"
|
|
258
|
-
fi
|
|
259
|
-
|
|
260
|
-
if [[ -z "$SYNC_MODULE" ]]; then
|
|
261
|
-
log "Sync module not found at any known path. Checked: SPECWEAVE_PKG=${SPECWEAVE_PKG:-unset}, PKG_ROOT=${PKG_ROOT:-unset}, node_modules, PROJECT_ROOT/dist. Skipping."
|
|
262
|
-
exit 0
|
|
263
|
-
fi
|
|
264
|
-
log "Using sync module: $SYNC_MODULE"
|
|
265
|
-
|
|
266
|
-
log "Syncing AC progress for increment $INC_ID to enabled providers..."
|
|
267
|
-
log "Providers: github=$GH_ENABLED jira=$JIRA_ENABLED ado=$ADO_ENABLED"
|
|
268
|
-
log "Affected US IDs: $AFFECTED_US_IDS"
|
|
269
|
-
|
|
270
|
-
# ============================================================================
|
|
271
|
-
# RUN PROVIDER-AGNOSTIC SYNC
|
|
272
|
-
# ============================================================================
|
|
273
|
-
|
|
274
|
-
# Build inline Node.js script that constructs config and calls sync
|
|
275
|
-
# Pass all values via environment variables to prevent command injection
|
|
276
|
-
OUTPUT=$(SW_SYNC_MODULE="$SYNC_MODULE" \
|
|
277
|
-
SW_CONFIG_PATH="$CONFIG_PATH" \
|
|
278
|
-
SW_METADATA_PATH="$METADATA_PATH" \
|
|
279
|
-
SW_SPEC_PATH="$SPEC_PATH" \
|
|
280
|
-
SW_INC_ID="$INC_ID" \
|
|
281
|
-
SW_AFFECTED_US_IDS="$AFFECTED_US_IDS" \
|
|
282
|
-
SW_CLOSE_ALL="${SPECWEAVE_CLOSE_ALL:-0}" \
|
|
283
|
-
node --input-type=module -e "
|
|
284
|
-
import { readFile } from 'fs/promises';
|
|
285
|
-
|
|
286
|
-
const { SW_SYNC_MODULE, SW_CONFIG_PATH, SW_METADATA_PATH,
|
|
287
|
-
SW_SPEC_PATH, SW_INC_ID, SW_AFFECTED_US_IDS, SW_CLOSE_ALL } = process.env;
|
|
288
|
-
|
|
289
|
-
const mod = await import(SW_SYNC_MODULE);
|
|
290
|
-
const affectedUSIds = JSON.parse(SW_AFFECTED_US_IDS);
|
|
291
|
-
|
|
292
|
-
try {
|
|
293
|
-
const rawConfig = JSON.parse(await readFile(SW_CONFIG_PATH, 'utf-8'));
|
|
294
|
-
const metadata = JSON.parse(await readFile(SW_METADATA_PATH, 'utf-8'));
|
|
295
|
-
|
|
296
|
-
const config = {
|
|
297
|
-
sync: {
|
|
298
|
-
github: { enabled: rawConfig?.sync?.github?.enabled === true },
|
|
299
|
-
jira: { enabled: rawConfig?.sync?.jira?.enabled === true },
|
|
300
|
-
ado: { enabled: rawConfig?.sync?.ado?.enabled === true },
|
|
301
|
-
},
|
|
302
|
-
github: rawConfig?.sync?.github || {},
|
|
303
|
-
jira: rawConfig?.sync?.jira || {},
|
|
304
|
-
ado: rawConfig?.sync?.ado || {},
|
|
305
|
-
externalLinks: metadata?.externalLinks || {},
|
|
306
|
-
};
|
|
307
|
-
|
|
308
|
-
let result;
|
|
309
|
-
if (SW_CLOSE_ALL === '1' && mod.closeIncrementIssues) {
|
|
310
|
-
// Force-close all external issues for completed increment
|
|
311
|
-
result = await mod.closeIncrementIssues(SW_INC_ID, SW_SPEC_PATH, config);
|
|
312
|
-
} else {
|
|
313
|
-
result = await mod.syncACProgressToProviders(
|
|
314
|
-
SW_INC_ID, affectedUSIds, SW_SPEC_PATH, config,
|
|
315
|
-
);
|
|
316
|
-
}
|
|
317
|
-
|
|
318
|
-
console.log(JSON.stringify(result, null, 2));
|
|
319
|
-
} catch (err) {
|
|
320
|
-
console.error('AC sync dispatcher error:', err.message || err);
|
|
321
|
-
process.exit(1);
|
|
322
|
-
}
|
|
323
|
-
" 2>&1)
|
|
324
|
-
EXIT_CODE=$?
|
|
325
|
-
|
|
326
|
-
if [[ $EXIT_CODE -ne 0 ]]; then
|
|
327
|
-
log "Sync failed (exit $EXIT_CODE): $OUTPUT"
|
|
328
|
-
exit 0
|
|
329
|
-
fi
|
|
330
|
-
|
|
331
|
-
log "Sync completed: $OUTPUT"
|
|
332
|
-
exit 0
|
|
@@ -1,50 +0,0 @@
|
|
|
1
|
-
#!/bin/bash
|
|
2
|
-
# ac-validation-handler.sh - Validate AC completion status
|
|
3
|
-
# Checks that completed tasks have their ACs checked in spec.md
|
|
4
|
-
# Non-blocking, logs warnings only
|
|
5
|
-
#
|
|
6
|
-
# IMPORTANT: Never crash Claude, always exit 0
|
|
7
|
-
set +e
|
|
8
|
-
|
|
9
|
-
[[ "${SPECWEAVE_DISABLE_HOOKS:-0}" == "1" ]] && exit 0
|
|
10
|
-
|
|
11
|
-
INC_ID="${1:-}"
|
|
12
|
-
[[ -z "$INC_ID" ]] && exit 0
|
|
13
|
-
|
|
14
|
-
# Find project root
|
|
15
|
-
PROJECT_ROOT="$PWD"
|
|
16
|
-
while [[ "$PROJECT_ROOT" != "/" ]] && [[ ! -f "$PROJECT_ROOT/.specweave/config.json" ]]; do
|
|
17
|
-
PROJECT_ROOT=$(dirname "$PROJECT_ROOT")
|
|
18
|
-
done
|
|
19
|
-
[[ ! -f "$PROJECT_ROOT/.specweave/config.json" ]] && exit 0
|
|
20
|
-
|
|
21
|
-
INC_DIR="$PROJECT_ROOT/.specweave/increments/$INC_ID"
|
|
22
|
-
TASKS_FILE="$INC_DIR/tasks.md"
|
|
23
|
-
SPEC_FILE="$INC_DIR/spec.md"
|
|
24
|
-
LOG_FILE="$PROJECT_ROOT/.specweave/logs/ac-validation.log"
|
|
25
|
-
|
|
26
|
-
[[ ! -f "$TASKS_FILE" ]] || [[ ! -f "$SPEC_FILE" ]] && exit 0
|
|
27
|
-
|
|
28
|
-
mkdir -p "$(dirname "$LOG_FILE")" 2>/dev/null
|
|
29
|
-
|
|
30
|
-
# Find completed tasks and their ACs
|
|
31
|
-
WARNINGS=""
|
|
32
|
-
while IFS= read -r line; do
|
|
33
|
-
if [[ "$line" =~ ^\*\*Satisfies\ ACs\*\*:\ (.+)$ ]]; then
|
|
34
|
-
ACS="${BASH_REMATCH[1]}"
|
|
35
|
-
# Check each AC
|
|
36
|
-
for ac in $(echo "$ACS" | tr ',' ' '); do
|
|
37
|
-
ac=$(echo "$ac" | tr -d ' ')
|
|
38
|
-
[[ -z "$ac" ]] && continue
|
|
39
|
-
# Check if AC is checked in spec.md
|
|
40
|
-
if ! grep -qE "^\s*-\s*\[x\]\s*\*\*${ac}\*\*" "$SPEC_FILE" 2>/dev/null; then
|
|
41
|
-
WARNINGS="$WARNINGS\n - $ac not checked in spec.md"
|
|
42
|
-
fi
|
|
43
|
-
done
|
|
44
|
-
fi
|
|
45
|
-
done < <(grep -A5 "\[x\] completed" "$TASKS_FILE" 2>/dev/null | grep "Satisfies ACs")
|
|
46
|
-
|
|
47
|
-
if [[ -n "$WARNINGS" ]]; then
|
|
48
|
-
echo "[$(date)] $INC_ID: AC validation warnings:$WARNINGS" >> "$LOG_FILE"
|
|
49
|
-
fi
|
|
50
|
-
exit 0
|