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.
Files changed (166) hide show
  1. package/CLAUDE.md +1 -1
  2. package/bin/specweave.js +23 -1
  3. package/dist/src/cli/commands/hook.d.ts +15 -0
  4. package/dist/src/cli/commands/hook.d.ts.map +1 -0
  5. package/dist/src/cli/commands/hook.js +61 -0
  6. package/dist/src/cli/commands/hook.js.map +1 -0
  7. package/dist/src/cli/commands/init.d.ts.map +1 -1
  8. package/dist/src/cli/commands/init.js +5 -0
  9. package/dist/src/cli/commands/init.js.map +1 -1
  10. package/dist/src/cli/commands/refresh-plugins.d.ts.map +1 -1
  11. package/dist/src/cli/commands/refresh-plugins.js +11 -1
  12. package/dist/src/cli/commands/refresh-plugins.js.map +1 -1
  13. package/dist/src/cli/commands/sync-setup.d.ts.map +1 -1
  14. package/dist/src/cli/commands/sync-setup.js +7 -3
  15. package/dist/src/cli/commands/sync-setup.js.map +1 -1
  16. package/dist/src/cli/helpers/issue-tracker/project-mapping-wizard.d.ts +9 -0
  17. package/dist/src/cli/helpers/issue-tracker/project-mapping-wizard.d.ts.map +1 -1
  18. package/dist/src/cli/helpers/issue-tracker/project-mapping-wizard.js +9 -3
  19. package/dist/src/cli/helpers/issue-tracker/project-mapping-wizard.js.map +1 -1
  20. package/dist/src/config/types.d.ts +2 -2
  21. package/dist/src/core/config/types.d.ts +18 -2
  22. package/dist/src/core/config/types.d.ts.map +1 -1
  23. package/dist/src/core/config/types.js.map +1 -1
  24. package/dist/src/core/hooks/handlers/hook-router.d.ts +19 -0
  25. package/dist/src/core/hooks/handlers/hook-router.d.ts.map +1 -0
  26. package/dist/src/core/hooks/handlers/hook-router.js +75 -0
  27. package/dist/src/core/hooks/handlers/hook-router.js.map +1 -0
  28. package/dist/src/core/hooks/handlers/index.d.ts +10 -0
  29. package/dist/src/core/hooks/handlers/index.d.ts.map +1 -0
  30. package/dist/src/core/hooks/handlers/index.js +9 -0
  31. package/dist/src/core/hooks/handlers/index.js.map +1 -0
  32. package/dist/src/core/hooks/handlers/post-tool-use-analytics.d.ts +11 -0
  33. package/dist/src/core/hooks/handlers/post-tool-use-analytics.d.ts.map +1 -0
  34. package/dist/src/core/hooks/handlers/post-tool-use-analytics.js +73 -0
  35. package/dist/src/core/hooks/handlers/post-tool-use-analytics.js.map +1 -0
  36. package/dist/src/core/hooks/handlers/post-tool-use.d.ts +11 -0
  37. package/dist/src/core/hooks/handlers/post-tool-use.d.ts.map +1 -0
  38. package/dist/src/core/hooks/handlers/post-tool-use.js +76 -0
  39. package/dist/src/core/hooks/handlers/post-tool-use.js.map +1 -0
  40. package/dist/src/core/hooks/handlers/pre-compact.d.ts +11 -0
  41. package/dist/src/core/hooks/handlers/pre-compact.d.ts.map +1 -0
  42. package/dist/src/core/hooks/handlers/pre-compact.js +77 -0
  43. package/dist/src/core/hooks/handlers/pre-compact.js.map +1 -0
  44. package/dist/src/core/hooks/handlers/pre-tool-use.d.ts +11 -0
  45. package/dist/src/core/hooks/handlers/pre-tool-use.d.ts.map +1 -0
  46. package/dist/src/core/hooks/handlers/pre-tool-use.js +318 -0
  47. package/dist/src/core/hooks/handlers/pre-tool-use.js.map +1 -0
  48. package/dist/src/core/hooks/handlers/session-start.d.ts +9 -0
  49. package/dist/src/core/hooks/handlers/session-start.d.ts.map +1 -0
  50. package/dist/src/core/hooks/handlers/session-start.js +111 -0
  51. package/dist/src/core/hooks/handlers/session-start.js.map +1 -0
  52. package/dist/src/core/hooks/handlers/stop-auto.d.ts +16 -0
  53. package/dist/src/core/hooks/handlers/stop-auto.d.ts.map +1 -0
  54. package/dist/src/core/hooks/handlers/stop-auto.js +122 -0
  55. package/dist/src/core/hooks/handlers/stop-auto.js.map +1 -0
  56. package/dist/src/core/hooks/handlers/stop-reflect.d.ts +14 -0
  57. package/dist/src/core/hooks/handlers/stop-reflect.d.ts.map +1 -0
  58. package/dist/src/core/hooks/handlers/stop-reflect.js +43 -0
  59. package/dist/src/core/hooks/handlers/stop-reflect.js.map +1 -0
  60. package/dist/src/core/hooks/handlers/stop-sync.d.ts +15 -0
  61. package/dist/src/core/hooks/handlers/stop-sync.d.ts.map +1 -0
  62. package/dist/src/core/hooks/handlers/stop-sync.js +68 -0
  63. package/dist/src/core/hooks/handlers/stop-sync.js.map +1 -0
  64. package/dist/src/core/hooks/handlers/types.d.ts +63 -0
  65. package/dist/src/core/hooks/handlers/types.d.ts.map +1 -0
  66. package/dist/src/core/hooks/handlers/types.js +27 -0
  67. package/dist/src/core/hooks/handlers/types.js.map +1 -0
  68. package/dist/src/core/hooks/handlers/user-prompt-submit.d.ts +14 -0
  69. package/dist/src/core/hooks/handlers/user-prompt-submit.d.ts.map +1 -0
  70. package/dist/src/core/hooks/handlers/user-prompt-submit.js +173 -0
  71. package/dist/src/core/hooks/handlers/user-prompt-submit.js.map +1 -0
  72. package/dist/src/core/hooks/handlers/utils.d.ts +25 -0
  73. package/dist/src/core/hooks/handlers/utils.d.ts.map +1 -0
  74. package/dist/src/core/hooks/handlers/utils.js +64 -0
  75. package/dist/src/core/hooks/handlers/utils.js.map +1 -0
  76. package/dist/src/core/increment/completion-validator.d.ts.map +1 -1
  77. package/dist/src/core/increment/completion-validator.js +32 -0
  78. package/dist/src/core/increment/completion-validator.js.map +1 -1
  79. package/dist/src/init/research/types.d.ts +1 -1
  80. package/dist/src/sync/sync-target-resolver.js.map +1 -1
  81. package/dist/src/utils/lock-manager.d.ts.map +1 -1
  82. package/dist/src/utils/lock-manager.js +5 -0
  83. package/dist/src/utils/lock-manager.js.map +1 -1
  84. package/dist/src/utils/plugin-copier.d.ts +10 -0
  85. package/dist/src/utils/plugin-copier.d.ts.map +1 -1
  86. package/dist/src/utils/plugin-copier.js +63 -35
  87. package/dist/src/utils/plugin-copier.js.map +1 -1
  88. package/package.json +1 -1
  89. package/plugins/specweave/agents/sw-closer.md +3 -2
  90. package/plugins/specweave/hooks/hooks.json +10 -10
  91. package/plugins/specweave/skills/code-reviewer/SKILL.md +180 -16
  92. package/plugins/specweave/skills/code-reviewer/agents/reviewer-comments.md +83 -0
  93. package/plugins/specweave/skills/code-reviewer/agents/reviewer-silent-failures.md +19 -0
  94. package/plugins/specweave/skills/code-reviewer/agents/reviewer-spec-compliance.md +19 -0
  95. package/plugins/specweave/skills/code-reviewer/agents/reviewer-tests.md +101 -0
  96. package/plugins/specweave/skills/code-reviewer/agents/reviewer-types.md +20 -0
  97. package/plugins/specweave/skills/done/SKILL.md +56 -21
  98. package/plugins/specweave/skills/grill/SKILL.md +1 -1
  99. package/plugins/specweave/skills/team-lead/agents/reviewer-logic.md +19 -0
  100. package/plugins/specweave/skills/team-lead/agents/reviewer-performance.md +20 -0
  101. package/plugins/specweave/skills/team-lead/agents/reviewer-security.md +20 -0
  102. package/src/templates/CLAUDE.md.template +7 -4
  103. package/plugins/specweave/hooks/README.md +0 -493
  104. package/plugins/specweave/hooks/_archive/stop-auto-v4-legacy.sh +0 -1319
  105. package/plugins/specweave/hooks/lib/common-setup.sh +0 -144
  106. package/plugins/specweave/hooks/lib/hook-errors.sh +0 -414
  107. package/plugins/specweave/hooks/lib/migrate-increment-work.sh +0 -245
  108. package/plugins/specweave/hooks/lib/resolve-package.sh +0 -146
  109. package/plugins/specweave/hooks/lib/scheduler-startup.sh +0 -135
  110. package/plugins/specweave/hooks/lib/score-increment.sh +0 -87
  111. package/plugins/specweave/hooks/lib/sync-spec-content.sh +0 -193
  112. package/plugins/specweave/hooks/lib/update-active-increment.sh +0 -95
  113. package/plugins/specweave/hooks/lib/update-status-line.sh +0 -233
  114. package/plugins/specweave/hooks/lib/validate-spec-status.sh +0 -171
  115. package/plugins/specweave/hooks/llm-judge-validator.sh +0 -219
  116. package/plugins/specweave/hooks/log-decision.sh +0 -168
  117. package/plugins/specweave/hooks/pre-compact.sh +0 -64
  118. package/plugins/specweave/hooks/startup-health-check.sh +0 -64
  119. package/plugins/specweave/hooks/stop-auto-v5.sh +0 -276
  120. package/plugins/specweave/hooks/stop-reflect.sh +0 -336
  121. package/plugins/specweave/hooks/stop-sync.sh +0 -283
  122. package/plugins/specweave/hooks/tests/test-auto-context-integration.sh +0 -126
  123. package/plugins/specweave/hooks/tests/test-stop-auto-enriched.sh +0 -128
  124. package/plugins/specweave/hooks/universal/dispatcher.mjs +0 -336
  125. package/plugins/specweave/hooks/universal/fail-fast-wrapper.sh +0 -325
  126. package/plugins/specweave/hooks/universal/hook-wrapper.cmd +0 -26
  127. package/plugins/specweave/hooks/universal/hook-wrapper.sh +0 -69
  128. package/plugins/specweave/hooks/universal/run-hook.sh +0 -20
  129. package/plugins/specweave/hooks/universal/session-start.cmd +0 -16
  130. package/plugins/specweave/hooks/universal/session-start.ps1 +0 -16
  131. package/plugins/specweave/hooks/user-prompt-submit.sh +0 -2550
  132. package/plugins/specweave/hooks/v2/detectors/lifecycle-detector.sh +0 -87
  133. package/plugins/specweave/hooks/v2/detectors/us-completion-detector.sh +0 -186
  134. package/plugins/specweave/hooks/v2/dispatchers/post-tool-use-analytics.sh +0 -83
  135. package/plugins/specweave/hooks/v2/dispatchers/post-tool-use.sh +0 -447
  136. package/plugins/specweave/hooks/v2/dispatchers/pre-tool-use.sh +0 -104
  137. package/plugins/specweave/hooks/v2/dispatchers/session-start.sh +0 -270
  138. package/plugins/specweave/hooks/v2/guards/completion-guard.sh +0 -14
  139. package/plugins/specweave/hooks/v2/guards/increment-duplicate-guard.sh +0 -14
  140. package/plugins/specweave/hooks/v2/guards/increment-existence-guard.sh +0 -240
  141. package/plugins/specweave/hooks/v2/guards/interview-enforcement-guard.sh +0 -171
  142. package/plugins/specweave/hooks/v2/guards/metadata-json-guard.sh +0 -14
  143. package/plugins/specweave/hooks/v2/guards/skill-chain-enforcement-guard.sh +0 -222
  144. package/plugins/specweave/hooks/v2/guards/spec-template-enforcement-guard.sh +0 -21
  145. package/plugins/specweave/hooks/v2/guards/spec-validation-guard.sh +0 -14
  146. package/plugins/specweave/hooks/v2/guards/status-completion-guard.sh +0 -84
  147. package/plugins/specweave/hooks/v2/guards/task-ac-sync-guard.sh +0 -475
  148. package/plugins/specweave/hooks/v2/guards/tdd-enforcement-guard.sh +0 -268
  149. package/plugins/specweave/hooks/v2/handlers/ac-sync-dispatcher.sh +0 -332
  150. package/plugins/specweave/hooks/v2/handlers/ac-validation-handler.sh +0 -50
  151. package/plugins/specweave/hooks/v2/handlers/github-sync-handler.sh +0 -347
  152. package/plugins/specweave/hooks/v2/handlers/living-docs-handler.sh +0 -83
  153. package/plugins/specweave/hooks/v2/handlers/living-specs-handler.sh +0 -268
  154. package/plugins/specweave/hooks/v2/handlers/project-bridge-handler.sh +0 -104
  155. package/plugins/specweave/hooks/v2/handlers/status-line-handler.sh +0 -165
  156. package/plugins/specweave/hooks/v2/handlers/status-update.sh +0 -61
  157. package/plugins/specweave/hooks/v2/handlers/universal-auto-create-dispatcher.sh +0 -270
  158. package/plugins/specweave/hooks/v2/integrations/ado-post-living-docs-update.sh +0 -367
  159. package/plugins/specweave/hooks/v2/integrations/ado-post-task.sh +0 -179
  160. package/plugins/specweave/hooks/v2/integrations/github-auto-create-handler.sh +0 -553
  161. package/plugins/specweave/hooks/v2/integrations/github-post-task.sh +0 -345
  162. package/plugins/specweave/hooks/v2/integrations/jira-post-task.sh +0 -180
  163. package/plugins/specweave/hooks/v2/lib/check-provider-enabled.sh +0 -52
  164. package/plugins/specweave/hooks/v2/queue/enqueue.sh +0 -81
  165. package/plugins/specweave/hooks/v2/session-end.sh +0 -139
  166. package/plugins/specweave/hooks/validate-skill-activations.sh +0 -227
@@ -1,193 +0,0 @@
1
- #!/bin/bash
2
- #
3
- # Sync Spec Content to External Tools
4
- #
5
- # This script automatically syncs spec CONTENT (title, description, user stories)
6
- # to external tools (GitHub Issues, JIRA Epics, Azure DevOps Features).
7
- #
8
- # CRITICAL: This does NOT sync STATUS - that's managed by external tools.
9
- #
10
- # Sync Direction:
11
- # - Title/Description/User Stories: SpecWeave → External Tool (we update)
12
- # - Status/State: External Tool → SpecWeave (we read)
13
- #
14
- # Usage:
15
- # sync-spec-content.sh <spec-path>
16
- #
17
- # v1.0.71 - Fixed: Use specweave package location, not PROJECT_ROOT/dist
18
-
19
- set +e # EMERGENCY FIX: Changed from set -euo pipefail to prevent Claude Code crashes
20
-
21
- # Get script directory
22
- SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
23
-
24
- # =============================================================================
25
- # CRITICAL FIX: Resolve specweave package location for CLI scripts
26
- # =============================================================================
27
- resolve_specweave_package() {
28
- local script_dir="$1"
29
-
30
- # From hooks/lib/ go up to package root (lib -> hooks -> specweave -> plugins -> root)
31
- local package_root="$(cd "$script_dir/../../.." 2>/dev/null && pwd)"
32
-
33
- if [[ -d "$package_root/dist/src/cli" ]]; then
34
- echo "$package_root"
35
- return 0
36
- fi
37
-
38
- # Fallback: Try global npm installation
39
- local npm_root
40
- npm_root="$(npm root -g 2>/dev/null)"
41
- if [[ -d "$npm_root/specweave/dist/src/cli" ]]; then
42
- echo "$npm_root/specweave"
43
- return 0
44
- fi
45
-
46
- # Fallback: Try which specweave
47
- local npx_path
48
- npx_path="$(which specweave 2>/dev/null)"
49
- if [[ -n "$npx_path" ]]; then
50
- local bin_dir="$(dirname "$npx_path")"
51
- local pkg_dir="$(cd "$bin_dir/.." 2>/dev/null && pwd)"
52
- if [[ -d "$pkg_dir/dist/src/cli" ]]; then
53
- echo "$pkg_dir"
54
- return 0
55
- fi
56
- fi
57
-
58
- return 1
59
- }
60
-
61
- SPECWEAVE_PKG="$(resolve_specweave_package "$SCRIPT_DIR")"
62
- PROJECT_ROOT="$(cd "$SCRIPT_DIR/../../../.." && pwd)"
63
-
64
- # Input validation - exit 0 for safety (never exit 1 in hooks)
65
- if [ $# -lt 1 ]; then
66
- echo "Usage: $0 <spec-path>" >&2
67
- exit 0 # SAFETY: Never use exit 1 in hooks
68
- fi
69
-
70
- SPEC_PATH="$1"
71
-
72
- # Validate spec file exists
73
- if [ ! -f "$SPEC_PATH" ]; then
74
- echo "❌ Spec file not found: $SPEC_PATH" >&2
75
- exit 0 # SAFETY: Never use exit 1 in hooks
76
- fi
77
-
78
- # Check if sync is enabled
79
- CONFIG_FILE="$PROJECT_ROOT/.specweave/config.json"
80
- if [ ! -f "$CONFIG_FILE" ]; then
81
- echo "ℹ️ No config file found, skipping spec content sync" >&2
82
- exit 0
83
- fi
84
-
85
- # Check if sync is enabled in config
86
- SYNC_ENABLED=$(node -p "
87
- try {
88
- const config = require('$CONFIG_FILE');
89
- config.sync?.enabled ?? false;
90
- } catch {
91
- false;
92
- }
93
- " 2>/dev/null || echo "false")
94
-
95
- if [ "$SYNC_ENABLED" != "true" ]; then
96
- echo "ℹ️ Sync disabled in config, skipping spec content sync" >&2
97
- exit 0
98
- fi
99
-
100
- # Check if spec content sync is enabled
101
- SPEC_SYNC_ENABLED=$(node -p "
102
- try {
103
- const config = require('$CONFIG_FILE');
104
- config.sync?.settings?.syncSpecContent ?? true;
105
- } catch {
106
- true;
107
- }
108
- " 2>/dev/null || echo "true")
109
-
110
- if [ "$SPEC_SYNC_ENABLED" != "true" ]; then
111
- echo "ℹ️ Spec content sync disabled in config" >&2
112
- exit 0
113
- fi
114
-
115
- # Get default profile
116
- DEFAULT_PROFILE=$(node -p "
117
- try {
118
- const config = require('$CONFIG_FILE');
119
- config.sync?.defaultProfile ?? null;
120
- } catch {
121
- null;
122
- }
123
- " 2>/dev/null || echo "null")
124
-
125
- if [ "$DEFAULT_PROFILE" = "null" ]; then
126
- echo "ℹ️ No default sync profile, skipping spec content sync" >&2
127
- exit 0
128
- fi
129
-
130
- # Get provider from default profile
131
- PROVIDER=$(node -p "
132
- try {
133
- const config = require('$CONFIG_FILE');
134
- config.sync?.profiles?.['"$DEFAULT_PROFILE"']?.provider ?? null;
135
- } catch {
136
- null;
137
- }
138
- " 2>/dev/null || echo "null")
139
-
140
- if [ "$PROVIDER" = "null" ]; then
141
- echo "ℹ️ No provider configured for profile '$DEFAULT_PROFILE'" >&2
142
- exit 0
143
- fi
144
-
145
- # Validate provider
146
- if [[ ! "$PROVIDER" =~ ^(github|jira|ado)$ ]]; then
147
- echo "❌ Invalid provider: $PROVIDER (must be github, jira, or ado)" >&2
148
- exit 0 # SAFETY: Never use exit 1 in hooks
149
- fi
150
-
151
- # Check if sync CLI command exists
152
- if [[ -z "$SPECWEAVE_PKG" ]]; then
153
- echo "ℹ️ SpecWeave package not found, skipping spec content sync" >&2
154
- exit 0
155
- fi
156
-
157
- SYNC_CLI="$SPECWEAVE_PKG/dist/src/cli/commands/sync-spec-content.js"
158
- if [ ! -f "$SYNC_CLI" ]; then
159
- echo "ℹ️ Sync CLI not found at $SYNC_CLI, skipping spec content sync" >&2
160
- exit 0
161
- fi
162
-
163
- # Check if Node.js is available
164
- if ! command -v node &> /dev/null; then
165
- echo "❌ Node.js not found, cannot sync spec content" >&2
166
- exit 0 # SAFETY: Never use exit 1 in hooks
167
- fi
168
-
169
- echo ""
170
- echo "🔄 Syncing spec content to $PROVIDER..."
171
- echo " Spec: $(basename "$SPEC_PATH")"
172
- echo ""
173
-
174
- # Run sync
175
- set +e
176
- node "$SYNC_CLI" --spec "$SPEC_PATH" --provider "$PROVIDER"
177
- SYNC_EXIT_CODE=$?
178
- set +e # EMERGENCY FIX: Changed from set -e to prevent Claude Code crashes
179
-
180
- if [ $SYNC_EXIT_CODE -eq 0 ]; then
181
- echo ""
182
- echo "✅ Spec content synced successfully"
183
- echo ""
184
- else
185
- echo ""
186
- echo "⚠️ Spec content sync failed (exit code: $SYNC_EXIT_CODE)" >&2
187
- echo " This is non-blocking. You can sync manually later:" >&2
188
- echo " node dist/src/cli/commands/sync-spec-content.js --spec \"$SPEC_PATH\" --provider $PROVIDER" >&2
189
- echo ""
190
- # Non-blocking: continue execution even if sync fails
191
- fi
192
-
193
- exit 0
@@ -1,95 +0,0 @@
1
- #!/usr/bin/env bash
2
- #
3
- # update-active-increment.sh (v0.26.15)
4
- #
5
- # Maintains .specweave/state/active-increment.json in sync with metadata.json
6
- #
7
- # CRITICAL FIX: Hooks depend on active-increment.json to know which increments to sync.
8
- # Without this, post-task-completion.sh sees empty array and skips ALL sync work!
9
- #
10
- # See: Root cause analysis in increment 0059
11
- #
12
- set +e
13
-
14
- # ============================================================================
15
- # PROJECT ROOT DETECTION (CRITICAL - must NOT fallback to pwd!)
16
- # ============================================================================
17
- if [[ -n "$SPECWEAVE_PROJECT_ROOT" ]] && [[ -f "$SPECWEAVE_PROJECT_ROOT/.specweave/config.json" ]]; then
18
- PROJECT_ROOT="$SPECWEAVE_PROJECT_ROOT"
19
- else
20
- PROJECT_ROOT="$PWD"
21
- while [[ "$PROJECT_ROOT" != "/" ]] && [[ ! -f "$PROJECT_ROOT/.specweave/config.json" ]]; do
22
- PROJECT_ROOT=$(dirname "$PROJECT_ROOT")
23
- done
24
- fi
25
-
26
- # No .specweave/config.json? Exit BEFORE any mkdir (prevents .specweave pollution)
27
- [[ ! -f "$PROJECT_ROOT/.specweave/config.json" ]] && exit 0
28
-
29
- STATE_DIR="$PROJECT_ROOT/.specweave/state"
30
- ACTIVE_FILE="$STATE_DIR/active-increment.json"
31
- INCREMENTS_DIR="$PROJECT_ROOT/.specweave/increments"
32
- DEBUG_LOG="$PROJECT_ROOT/.specweave/logs/hooks-debug.log"
33
-
34
- mkdir -p "$STATE_DIR" 2>/dev/null || true
35
-
36
- # ============================================================================
37
- # SCAN ALL INCREMENTS FOR ACTIVE STATUS
38
- # ============================================================================
39
- # Strategy: Scan metadata.json files for status=active|planning|backlog|ready_for_review
40
- # This matches what ActiveIncrementManager.smartUpdate() does in TypeScript
41
-
42
- ACTIVE_IDS=()
43
-
44
- while IFS= read -r metadata_file; do
45
- [[ -z "$metadata_file" ]] && continue
46
-
47
- # Extract status from metadata.json
48
- if command -v jq >/dev/null 2>&1; then
49
- status=$(jq -r '.status // "unknown"' "$metadata_file" 2>/dev/null || echo "unknown")
50
- else
51
- # Fallback: sed parsing (portable - works on macOS BSD and Linux GNU)
52
- status=$(sed -n 's/.*"status"[[:space:]]*:[[:space:]]*"\([^"]*\)".*/\1/p' "$metadata_file" 2>/dev/null || echo "unknown")
53
- fi
54
-
55
- # Check if status is active-like
56
- if [[ "$status" == "active" ]] || [[ "$status" == "planning" ]] || [[ "$status" == "backlog" ]] || [[ "$status" == "ready_for_review" ]]; then
57
- increment_id=$(basename "$(dirname "$metadata_file")")
58
- ACTIVE_IDS+=("$increment_id")
59
- echo "[$(date)] update-active-increment: Found active: $increment_id (status: $status)" >> "$DEBUG_LOG" 2>/dev/null || true
60
- fi
61
- done < <(find "$INCREMENTS_DIR" -maxdepth 2 -name "metadata.json" -not -path "*/_archive/*" 2>/dev/null)
62
-
63
- # ============================================================================
64
- # WRITE ACTIVE INCREMENT STATE (max 2)
65
- # ============================================================================
66
- # Take first 2 active increments (matches ActiveIncrementManager behavior)
67
- ACTIVE_IDS=("${ACTIVE_IDS[@]:0:2}")
68
-
69
- # Build JSON array
70
- if [[ ${#ACTIVE_IDS[@]} -eq 0 ]]; then
71
- IDS_JSON="[]"
72
- else
73
- # Build JSON array manually (no jq dependency)
74
- IDS_JSON="["
75
- for i in "${!ACTIVE_IDS[@]}"; do
76
- [[ $i -gt 0 ]] && IDS_JSON+=","
77
- IDS_JSON+="\"${ACTIVE_IDS[$i]}\""
78
- done
79
- IDS_JSON+="]"
80
- fi
81
-
82
- # Atomic write
83
- TEMP_FILE="$ACTIVE_FILE.tmp"
84
- cat > "$TEMP_FILE" << EOF
85
- {
86
- "ids": $IDS_JSON,
87
- "lastUpdated": "$(date -u +%Y-%m-%dT%H:%M:%SZ)"
88
- }
89
- EOF
90
-
91
- mv "$TEMP_FILE" "$ACTIVE_FILE"
92
-
93
- echo "[$(date)] update-active-increment: Updated with ${#ACTIVE_IDS[@]} active increment(s): ${ACTIVE_IDS[*]}" >> "$DEBUG_LOG" 2>/dev/null || true
94
-
95
- exit 0
@@ -1,233 +0,0 @@
1
- #!/usr/bin/env bash
2
- #
3
- # update-status-line.sh (v0.26.13 - ULTRA-OPTIMIZED for crash prevention)
4
- #
5
- # Updates status line cache with current increment progress.
6
- # Shows: [increment-name] ████░░░░ X/Y tasks | A/B ACs (Z open)
7
- #
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
- #
16
- # Performance: <5ms (cached) / 15-25ms (full scan)
17
- #
18
- set +e
19
-
20
- # ============================================================================
21
- # PROJECT ROOT (FAST - cached in env if available)
22
- # CRITICAL: Must NOT fallback to pwd (prevents .specweave pollution)
23
- # ============================================================================
24
- if [[ -n "$SPECWEAVE_PROJECT_ROOT" ]] && [[ -f "$SPECWEAVE_PROJECT_ROOT/.specweave/config.json" ]]; then
25
- PROJECT_ROOT="$SPECWEAVE_PROJECT_ROOT"
26
- else
27
- PROJECT_ROOT="$PWD"
28
- while [[ "$PROJECT_ROOT" != "/" ]] && [[ ! -f "$PROJECT_ROOT/.specweave/config.json" ]]; do
29
- PROJECT_ROOT=$(dirname "$PROJECT_ROOT")
30
- done
31
- fi
32
-
33
- # No .specweave/config.json? Exit immediately BEFORE any variable init (prevents pollution)
34
- [[ ! -f "$PROJECT_ROOT/.specweave/config.json" ]] && exit 0
35
-
36
- # ============================================================================
37
- # ULTRA-FAST EXITS
38
- # ============================================================================
39
- STATE_DIR="$PROJECT_ROOT/.specweave/state"
40
- CACHE_FILE="$STATE_DIR/status-line.json"
41
- INCREMENTS_DIR="$PROJECT_ROOT/.specweave/increments"
42
- LOCK_FILE="$STATE_DIR/.status-update.lock"
43
-
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
56
- fi
57
-
58
- # ============================================================================
59
- # TTL CHECK (10 seconds - balanced for UX vs performance)
60
- # ============================================================================
61
- # TTL check (skip if --force flag provided or SPECWEAVE_FORCE_STATUS_UPDATE=1)
62
- # ============================================================================
63
- TTL_SECONDS=10
64
- FORCE_UPDATE=0
65
-
66
- # Check for --force flag
67
- if [[ "${1:-}" == "--force" ]] || [[ "${SPECWEAVE_FORCE_STATUS_UPDATE:-0}" == "1" ]]; then
68
- FORCE_UPDATE=1
69
- fi
70
-
71
- if [[ "$FORCE_UPDATE" -eq 0 ]] && [[ -f "$CACHE_FILE" ]]; then
72
- if [[ "$(uname)" == "Darwin" ]]; then
73
- CACHE_AGE=$(( $(date +%s) - $(stat -f %m "$CACHE_FILE" 2>/dev/null || echo 0) ))
74
- else
75
- CACHE_AGE=$(( $(date +%s) - $(stat -c %Y "$CACHE_FILE" 2>/dev/null || echo 0) ))
76
- fi
77
- [[ $CACHE_AGE -lt $TTL_SECONDS ]] && exit 0
78
- fi
79
-
80
- # ============================================================================
81
- # NO INCREMENTS? Write empty cache and exit
82
- # ============================================================================
83
- if [[ ! -d "$INCREMENTS_DIR" ]]; then
84
- mkdir -p "$STATE_DIR"
85
- printf '{"current":null,"openCount":0,"lastUpdate":"%s"}' "$(date -u +%Y-%m-%dT%H:%M:%SZ)" > "$CACHE_FILE"
86
- exit 0
87
- fi
88
-
89
- # ============================================================================
90
- # ACQUIRE LOCK (ATOMIC - mkdir pattern prevents TOCTOU race!)
91
- # ============================================================================
92
- mkdir -p "$STATE_DIR"
93
- LOCK_DIR="$STATE_DIR/.status-update.lockdir"
94
- if ! mkdir "$LOCK_DIR" 2>/dev/null; then
95
- # Lock exists - check if stale (>30s)
96
- if [[ "$(uname)" == "Darwin" ]]; then
97
- LOCK_AGE=$(( $(date +%s) - $(stat -f %m "$LOCK_DIR" 2>/dev/null || echo 0) ))
98
- else
99
- LOCK_AGE=$(( $(date +%s) - $(stat -c %Y "$LOCK_DIR" 2>/dev/null || echo 0) ))
100
- fi
101
- if [[ $LOCK_AGE -lt 30 ]]; then
102
- exit 0 # Another process holds lock
103
- fi
104
- # Stale lock - remove and retry
105
- rm -rf "$LOCK_DIR"
106
- mkdir "$LOCK_DIR" 2>/dev/null || exit 0
107
- fi
108
- echo $$ > "$LOCK_DIR/pid"
109
- trap 'rm -rf "$LOCK_DIR"' EXIT
110
-
111
- # ============================================================================
112
- # FIND ACTIVE INCREMENTS (uses metadata.json - SOURCE OF TRUTH!)
113
- # ============================================================================
114
- ACTIVE_FILES=""
115
- OPEN_COUNT=0
116
- OLDEST_DATE="9999-99-99"
117
- CURRENT_INCREMENT=""
118
-
119
- while IFS= read -r metadata_file; do
120
- [[ -z "$metadata_file" ]] && continue
121
-
122
- # Extract status from metadata.json (jq if available, grep fallback)
123
- if command -v jq >/dev/null 2>&1; then
124
- status=$(jq -r '.status // "unknown"' "$metadata_file" 2>/dev/null || echo "unknown")
125
- created=$(jq -r '.created // "9999-99-99"' "$metadata_file" 2>/dev/null || echo "9999-99-99")
126
- else
127
- status=$(sed -n 's/.*"status"[[:space:]]*:[[:space:]]*"\([^"]*\)".*/\1/p' "$metadata_file" 2>/dev/null || echo "unknown")
128
- created=$(sed -n 's/.*"created"[[:space:]]*:[[:space:]]*"\([^"]*\)".*/\1/p' "$metadata_file" 2>/dev/null || echo "9999-99-99")
129
- fi
130
-
131
- # Check if active
132
- if [[ "$status" == "active" || "$status" == "planning" || "$status" == "backlog" || "$status" == "ready_for_review" ]]; then
133
- OPEN_COUNT=$((OPEN_COUNT + 1))
134
- increment_id=$(basename "$(dirname "$metadata_file")")
135
-
136
- if [[ "$created" < "$OLDEST_DATE" ]]; then
137
- OLDEST_DATE="$created"
138
- CURRENT_INCREMENT="$increment_id"
139
- fi
140
-
141
- spec_file="$(dirname "$metadata_file")/spec.md"
142
- ACTIVE_FILES="$ACTIVE_FILES $spec_file"
143
- fi
144
- done < <(find "$INCREMENTS_DIR" -maxdepth 2 -name "metadata.json" -not -path "*/_archive/*" 2>/dev/null)
145
-
146
- # No active increments?
147
- if [[ -z "$CURRENT_INCREMENT" ]]; then
148
- printf '{"current":null,"openCount":0,"lastUpdate":"%s"}' "$(date -u +%Y-%m-%dT%H:%M:%SZ)" > "$CACHE_FILE"
149
- exit 0
150
- fi
151
-
152
- # ============================================================================
153
- # MTIME CHECK (using find -newer - single syscall!)
154
- # ============================================================================
155
- MTIME_FILE="$STATE_DIR/.status-mtime-$CURRENT_INCREMENT"
156
-
157
- if [[ -f "$MTIME_FILE" ]] && [[ -f "$CACHE_FILE" ]]; then
158
- # Check if any relevant files are newer than our marker
159
- TASKS_FILE="$INCREMENTS_DIR/$CURRENT_INCREMENT/tasks.md"
160
- SPEC_FILE="$INCREMENTS_DIR/$CURRENT_INCREMENT/spec.md"
161
-
162
- NEWER_FILES=$(find "$SPEC_FILE" "$TASKS_FILE" -newer "$MTIME_FILE" 2>/dev/null | head -1)
163
-
164
- if [[ -z "$NEWER_FILES" ]]; then
165
- # No changes - just touch cache to reset TTL
166
- touch "$CACHE_FILE"
167
- exit 0
168
- fi
169
- fi
170
-
171
- # ============================================================================
172
- # SINGLE-PASS COUNTING WITH AWK (replaces 5 grep calls!)
173
- # ============================================================================
174
- TASKS_FILE="$INCREMENTS_DIR/$CURRENT_INCREMENT/tasks.md"
175
- SPEC_FILE="$INCREMENTS_DIR/$CURRENT_INCREMENT/spec.md"
176
-
177
- # Count tasks with single awk call (per-task completion tracking!)
178
- # Bug fix: Each task counts as 0 or 1 completed, regardless of marker count
179
- read -r TOTAL_TASKS COMPLETED_TASKS < <(
180
- awk '
181
- BEGIN { total=0; completed=0; in_task=0; task_complete=0 }
182
- /^###? T-/ {
183
- if (in_task && task_complete) completed++
184
- total++
185
- in_task=1
186
- task_complete=0
187
- }
188
- /\*\*Completed\*\*:|\*\*Status\*\*:[ \t]*\[x\]|^\[x\]/ {
189
- if (in_task) task_complete=1
190
- }
191
- END {
192
- if (in_task && task_complete) completed++
193
- print total, completed
194
- }
195
- ' "$TASKS_FILE" 2>/dev/null || echo "0 0"
196
- )
197
-
198
- # Count ACs with single awk call
199
- # Supports both formats: "- [ ] AC-US1-01:" and "- [ ] **AC-US1-01**:"
200
- read -r TOTAL_ACS COMPLETED_ACS < <(
201
- awk '
202
- /^- \[(x| )\] (\*\*)?AC-/ { total++ }
203
- /^- \[x\] (\*\*)?AC-/ { completed++ }
204
- END { print total+0, completed+0 }
205
- ' "$SPEC_FILE" 2>/dev/null || echo "0 0"
206
- )
207
-
208
- # Calculate percentage (pure bash)
209
- PERCENTAGE=0
210
- [[ ${TOTAL_TASKS:-0} -gt 0 ]] && PERCENTAGE=$((${COMPLETED_TASKS:-0} * 100 / TOTAL_TASKS))
211
-
212
- # ============================================================================
213
- # WRITE CACHE (PURE BASH - NO jq!)
214
- # ============================================================================
215
- # Sanitize values
216
- TOTAL_TASKS=${TOTAL_TASKS:-0}
217
- COMPLETED_TASKS=${COMPLETED_TASKS:-0}
218
- TOTAL_ACS=${TOTAL_ACS:-0}
219
- COMPLETED_ACS=${COMPLETED_ACS:-0}
220
- OPEN_COUNT=${OPEN_COUNT:-0}
221
- PERCENTAGE=${PERCENTAGE:-0}
222
-
223
- # Generate JSON directly (ATOMIC: write temp then mv to prevent partial reads!)
224
- TEMP_CACHE="$CACHE_FILE.tmp.$$"
225
- cat > "$TEMP_CACHE" << EOF
226
- {"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)"}
227
- EOF
228
- mv "$TEMP_CACHE" "$CACHE_FILE"
229
-
230
- # Update mtime marker
231
- touch "$MTIME_FILE"
232
-
233
- exit 0
@@ -1,171 +0,0 @@
1
- #!/bin/bash
2
- #
3
- # validate-spec-status.sh
4
- #
5
- # Validates that spec.md status values match IncrementStatus enum.
6
- # Prevents vocabulary drift and ensures status line hook compatibility.
7
- #
8
- # Usage:
9
- # bash validate-spec-status.sh <increment-id>
10
- # bash validate-spec-status.sh --all # Validate all increments
11
- #
12
- # Exit codes:
13
- # 0 = Valid
14
- # 1 = Invalid status found
15
- # 2 = Error (file not found, etc.)
16
- #
17
- # Requires: bash 4.0+ (for associative arrays)
18
-
19
- set +e # EMERGENCY FIX: Changed from set -euo pipefail to prevent Claude Code crashes
20
-
21
- # Find project root (CRITICAL: must NOT fallback to pwd!)
22
- find_project_root() {
23
- local dir="$PWD"
24
- while [[ "$dir" != "/" ]]; do
25
- if [[ -f "$dir/.specweave/config.json" ]]; then
26
- echo "$dir"
27
- return 0
28
- fi
29
- dir=$(dirname "$dir")
30
- done
31
- # Return empty - NOT pwd (prevents .specweave pollution)
32
- return 1
33
- }
34
-
35
- PROJECT_ROOT=$(find_project_root)
36
-
37
- # Exit early if not a SpecWeave project (prevents .specweave pollution)
38
- if [[ -z "$PROJECT_ROOT" ]] || [[ ! -f "$PROJECT_ROOT/.specweave/config.json" ]]; then
39
- echo "Not a SpecWeave project - skipping validation"
40
- exit 0
41
- fi
42
-
43
- INCREMENTS_DIR="$PROJECT_ROOT/.specweave/increments"
44
-
45
- # Valid IncrementStatus enum values (from src/core/types/increment-metadata.ts)
46
- VALID_STATUSES=("planning" "active" "backlog" "paused" "completed" "abandoned")
47
-
48
- # Get suggested correction for invalid status
49
- get_correction() {
50
- local status="$1"
51
- case "$status" in
52
- "planned") echo "planning" ;;
53
- "in-progress"|"in_progress") echo "active" ;;
54
- "done") echo "completed" ;;
55
- "cancelled"|"canceled") echo "abandoned" ;;
56
- *) echo "" ;;
57
- esac
58
- }
59
-
60
- # Validate a single spec file
61
- validate_spec() {
62
- local spec_file="$1"
63
- local increment_id=$(basename "$(dirname "$spec_file")")
64
-
65
- if [[ ! -f "$spec_file" ]]; then
66
- echo "❌ Error: spec.md not found for increment $increment_id"
67
- return 2
68
- fi
69
-
70
- # Extract status from YAML frontmatter
71
- local status=$(grep -m1 "^status:" "$spec_file" 2>/dev/null | cut -d: -f2 | tr -d ' "' || echo "")
72
-
73
- if [[ -z "$status" ]]; then
74
- echo "⚠️ Warning: No status field in $increment_id/spec.md"
75
- return 0 # Not an error, just a warning
76
- fi
77
-
78
- # Check if status is valid
79
- local is_valid=0
80
- for valid_status in "${VALID_STATUSES[@]}"; do
81
- if [[ "$status" == "$valid_status" ]]; then
82
- is_valid=1
83
- break
84
- fi
85
- done
86
-
87
- if [[ $is_valid -eq 1 ]]; then
88
- echo "✅ $increment_id: status '$status' is valid"
89
- return 0
90
- else
91
- # Invalid status found - suggest correction
92
- echo ""
93
- echo "❌ Invalid status in $increment_id/spec.md"
94
- echo " Found: '$status'"
95
- echo ""
96
-
97
- # Check if we have a suggested correction
98
- local correction=$(get_correction "$status")
99
- if [[ -n "$correction" ]]; then
100
- echo " 💡 Did you mean: '$correction'?"
101
- echo ""
102
- echo " Fix:"
103
- echo " sed -i '' 's/^status: $status/status: $correction/' $spec_file"
104
- else
105
- echo " Valid statuses: ${VALID_STATUSES[*]}"
106
- fi
107
- echo ""
108
-
109
- return 1
110
- fi
111
- }
112
-
113
- # Validate all increments
114
- validate_all() {
115
- local exit_code=0
116
- local total=0
117
- local valid=0
118
- local invalid=0
119
-
120
- echo "Validating all increments in $INCREMENTS_DIR"
121
- echo ""
122
-
123
- for spec_file in "$INCREMENTS_DIR"/*/spec.md; do
124
- if [[ -f "$spec_file" ]]; then
125
- total=$((total + 1))
126
- if validate_spec "$spec_file"; then
127
- valid=$((valid + 1))
128
- else
129
- invalid=$((invalid + 1))
130
- exit_code=1
131
- fi
132
- fi
133
- done
134
-
135
- echo ""
136
- echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
137
- echo "Summary: $total increments checked"
138
- echo " ✅ Valid: $valid"
139
- echo " ❌ Invalid: $invalid"
140
- echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
141
-
142
- if [[ $invalid -gt 0 ]]; then
143
- echo ""
144
- echo "⚠️ Please fix invalid status values to use official IncrementStatus enum."
145
- echo ""
146
- echo "Valid statuses:"
147
- for status in "${VALID_STATUSES[@]}"; do
148
- echo " - $status"
149
- done
150
- fi
151
-
152
- return $exit_code
153
- }
154
-
155
- # Main logic
156
- if [[ $# -eq 0 ]]; then
157
- echo "Usage: $0 <increment-id> | --all"
158
- echo ""
159
- echo "Examples:"
160
- echo " $0 0042-test-infrastructure-cleanup"
161
- echo " $0 --all"
162
- exit 2
163
- fi
164
-
165
- if [[ "$1" == "--all" ]]; then
166
- validate_all
167
- else
168
- INCREMENT_ID="$1"
169
- SPEC_FILE="$INCREMENTS_DIR/$INCREMENT_ID/spec.md"
170
- validate_spec "$SPEC_FILE"
171
- fi