specweave 0.26.14 → 0.27.0

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 (189) hide show
  1. package/CLAUDE.md +73 -1
  2. package/README.md +111 -466
  3. package/dist/plugins/specweave-jira/lib/setup-wizard.d.ts.map +1 -1
  4. package/dist/plugins/specweave-jira/lib/setup-wizard.js +57 -78
  5. package/dist/plugins/specweave-jira/lib/setup-wizard.js.map +1 -1
  6. package/dist/src/cli/commands/import-docs.d.ts.map +1 -1
  7. package/dist/src/cli/commands/import-docs.js +23 -31
  8. package/dist/src/cli/commands/import-docs.js.map +1 -1
  9. package/dist/src/cli/commands/import-external.d.ts.map +1 -1
  10. package/dist/src/cli/commands/import-external.js +6 -10
  11. package/dist/src/cli/commands/import-external.js.map +1 -1
  12. package/dist/src/cli/commands/init-multiproject.d.ts.map +1 -1
  13. package/dist/src/cli/commands/init-multiproject.js +58 -73
  14. package/dist/src/cli/commands/init-multiproject.js.map +1 -1
  15. package/dist/src/cli/commands/init.d.ts +17 -11
  16. package/dist/src/cli/commands/init.d.ts.map +1 -1
  17. package/dist/src/cli/commands/init.js +221 -1874
  18. package/dist/src/cli/commands/init.js.map +1 -1
  19. package/dist/src/cli/commands/install.d.ts.map +1 -1
  20. package/dist/src/cli/commands/install.js +14 -22
  21. package/dist/src/cli/commands/install.js.map +1 -1
  22. package/dist/src/cli/commands/migrate-config.d.ts.map +1 -1
  23. package/dist/src/cli/commands/migrate-config.js +6 -10
  24. package/dist/src/cli/commands/migrate-config.js.map +1 -1
  25. package/dist/src/cli/commands/switch-project.d.ts.map +1 -1
  26. package/dist/src/cli/commands/switch-project.js.map +1 -1
  27. package/dist/src/cli/helpers/ado-area-path-mapper.d.ts.map +1 -1
  28. package/dist/src/cli/helpers/ado-area-path-mapper.js +36 -49
  29. package/dist/src/cli/helpers/ado-area-path-mapper.js.map +1 -1
  30. package/dist/src/cli/helpers/github/increment-profile-selector.d.ts.map +1 -1
  31. package/dist/src/cli/helpers/github/increment-profile-selector.js.map +1 -1
  32. package/dist/src/cli/helpers/github/profile-manager.d.ts.map +1 -1
  33. package/dist/src/cli/helpers/github/profile-manager.js +8 -11
  34. package/dist/src/cli/helpers/github/profile-manager.js.map +1 -1
  35. package/dist/src/cli/helpers/github-repo-selector.d.ts.map +1 -1
  36. package/dist/src/cli/helpers/github-repo-selector.js +26 -50
  37. package/dist/src/cli/helpers/github-repo-selector.js.map +1 -1
  38. package/dist/src/cli/helpers/import-strategy-prompter.d.ts.map +1 -1
  39. package/dist/src/cli/helpers/import-strategy-prompter.js +39 -52
  40. package/dist/src/cli/helpers/import-strategy-prompter.js.map +1 -1
  41. package/dist/src/cli/helpers/init/config-detection.d.ts +40 -0
  42. package/dist/src/cli/helpers/init/config-detection.d.ts.map +1 -0
  43. package/dist/src/cli/helpers/init/config-detection.js +125 -0
  44. package/dist/src/cli/helpers/init/config-detection.js.map +1 -0
  45. package/dist/src/cli/helpers/init/directory-structure.d.ts +26 -0
  46. package/dist/src/cli/helpers/init/directory-structure.d.ts.map +1 -0
  47. package/dist/src/cli/helpers/init/directory-structure.js +190 -0
  48. package/dist/src/cli/helpers/init/directory-structure.js.map +1 -0
  49. package/dist/src/cli/helpers/init/external-import.d.ts +15 -0
  50. package/dist/src/cli/helpers/init/external-import.d.ts.map +1 -0
  51. package/dist/src/cli/helpers/init/external-import.js +251 -0
  52. package/dist/src/cli/helpers/init/external-import.js.map +1 -0
  53. package/dist/src/cli/helpers/init/index.d.ts +15 -0
  54. package/dist/src/cli/helpers/init/index.d.ts.map +1 -0
  55. package/dist/src/cli/helpers/init/index.js +26 -0
  56. package/dist/src/cli/helpers/init/index.js.map +1 -0
  57. package/dist/src/cli/helpers/init/next-steps.d.ts +15 -0
  58. package/dist/src/cli/helpers/init/next-steps.d.ts.map +1 -0
  59. package/dist/src/cli/helpers/init/next-steps.js +72 -0
  60. package/dist/src/cli/helpers/init/next-steps.js.map +1 -0
  61. package/dist/src/cli/helpers/init/path-utils.d.ts +41 -0
  62. package/dist/src/cli/helpers/init/path-utils.d.ts.map +1 -0
  63. package/dist/src/cli/helpers/init/path-utils.js +146 -0
  64. package/dist/src/cli/helpers/init/path-utils.js.map +1 -0
  65. package/dist/src/cli/helpers/init/plugin-installer.d.ts +28 -0
  66. package/dist/src/cli/helpers/init/plugin-installer.d.ts.map +1 -0
  67. package/dist/src/cli/helpers/init/plugin-installer.js +238 -0
  68. package/dist/src/cli/helpers/init/plugin-installer.js.map +1 -0
  69. package/dist/src/cli/helpers/init/repository-setup.d.ts +28 -0
  70. package/dist/src/cli/helpers/init/repository-setup.d.ts.map +1 -0
  71. package/dist/src/cli/helpers/init/repository-setup.js +78 -0
  72. package/dist/src/cli/helpers/init/repository-setup.js.map +1 -0
  73. package/dist/src/cli/helpers/init/smart-reinit.d.ts +30 -0
  74. package/dist/src/cli/helpers/init/smart-reinit.d.ts.map +1 -0
  75. package/dist/src/cli/helpers/init/smart-reinit.js +140 -0
  76. package/dist/src/cli/helpers/init/smart-reinit.js.map +1 -0
  77. package/dist/src/cli/helpers/init/testing-config.d.ts +27 -0
  78. package/dist/src/cli/helpers/init/testing-config.d.ts.map +1 -0
  79. package/dist/src/cli/helpers/init/testing-config.js +131 -0
  80. package/dist/src/cli/helpers/init/testing-config.js.map +1 -0
  81. package/dist/src/cli/helpers/init/types.d.ts +86 -0
  82. package/dist/src/cli/helpers/init/types.d.ts.map +1 -0
  83. package/dist/src/cli/helpers/init/types.js +5 -0
  84. package/dist/src/cli/helpers/init/types.js.map +1 -0
  85. package/dist/src/cli/helpers/issue-tracker/ado-auto-discover.d.ts.map +1 -1
  86. package/dist/src/cli/helpers/issue-tracker/ado-auto-discover.js +10 -12
  87. package/dist/src/cli/helpers/issue-tracker/ado-auto-discover.js.map +1 -1
  88. package/dist/src/cli/helpers/issue-tracker/ado.d.ts.map +1 -1
  89. package/dist/src/cli/helpers/issue-tracker/ado.js +43 -60
  90. package/dist/src/cli/helpers/issue-tracker/ado.js.map +1 -1
  91. package/dist/src/cli/helpers/issue-tracker/github-multi-repo.d.ts.map +1 -1
  92. package/dist/src/cli/helpers/issue-tracker/github-multi-repo.js +193 -230
  93. package/dist/src/cli/helpers/issue-tracker/github-multi-repo.js.map +1 -1
  94. package/dist/src/cli/helpers/issue-tracker/github.d.ts.map +1 -1
  95. package/dist/src/cli/helpers/issue-tracker/github.js +43 -54
  96. package/dist/src/cli/helpers/issue-tracker/github.js.map +1 -1
  97. package/dist/src/cli/helpers/issue-tracker/index.d.ts.map +1 -1
  98. package/dist/src/cli/helpers/issue-tracker/index.js +27 -40
  99. package/dist/src/cli/helpers/issue-tracker/index.js.map +1 -1
  100. package/dist/src/cli/helpers/issue-tracker/jira.d.ts.map +1 -1
  101. package/dist/src/cli/helpers/issue-tracker/jira.js +54 -70
  102. package/dist/src/cli/helpers/issue-tracker/jira.js.map +1 -1
  103. package/dist/src/cli/helpers/smart-filter.d.ts.map +1 -1
  104. package/dist/src/cli/helpers/smart-filter.js +62 -85
  105. package/dist/src/cli/helpers/smart-filter.js.map +1 -1
  106. package/dist/src/core/increment/auto-transition-manager.d.ts +12 -0
  107. package/dist/src/core/increment/auto-transition-manager.d.ts.map +1 -1
  108. package/dist/src/core/increment/auto-transition-manager.js +45 -0
  109. package/dist/src/core/increment/auto-transition-manager.js.map +1 -1
  110. package/dist/src/core/increment/metadata-manager.d.ts.map +1 -1
  111. package/dist/src/core/increment/metadata-manager.js +46 -0
  112. package/dist/src/core/increment/metadata-manager.js.map +1 -1
  113. package/dist/src/core/increment/status-change-sync-trigger.d.ts +12 -0
  114. package/dist/src/core/increment/status-change-sync-trigger.d.ts.map +1 -1
  115. package/dist/src/core/increment/status-change-sync-trigger.js +48 -2
  116. package/dist/src/core/increment/status-change-sync-trigger.js.map +1 -1
  117. package/dist/src/core/living-docs/living-docs-sync.d.ts +13 -0
  118. package/dist/src/core/living-docs/living-docs-sync.d.ts.map +1 -1
  119. package/dist/src/core/living-docs/living-docs-sync.js +40 -0
  120. package/dist/src/core/living-docs/living-docs-sync.js.map +1 -1
  121. package/dist/src/core/repo-structure/repo-bulk-discovery.d.ts.map +1 -1
  122. package/dist/src/core/repo-structure/repo-bulk-discovery.js +63 -83
  123. package/dist/src/core/repo-structure/repo-bulk-discovery.js.map +1 -1
  124. package/dist/src/core/repo-structure/repo-structure-manager.d.ts.map +1 -1
  125. package/dist/src/core/repo-structure/repo-structure-manager.js +339 -424
  126. package/dist/src/core/repo-structure/repo-structure-manager.js.map +1 -1
  127. package/dist/src/core/sync/bidirectional-engine.d.ts.map +1 -1
  128. package/dist/src/core/sync/bidirectional-engine.js +21 -29
  129. package/dist/src/core/sync/bidirectional-engine.js.map +1 -1
  130. package/dist/src/init/InitFlow.js +15 -19
  131. package/dist/src/init/InitFlow.js.map +1 -1
  132. package/dist/src/init/repo/types.d.ts +1 -1
  133. package/dist/src/integrations/ado/area-path-mapper.d.ts.map +1 -1
  134. package/dist/src/integrations/ado/area-path-mapper.js +19 -23
  135. package/dist/src/integrations/ado/area-path-mapper.js.map +1 -1
  136. package/dist/src/utils/external-resource-validator.d.ts.map +1 -1
  137. package/dist/src/utils/external-resource-validator.js +41 -65
  138. package/dist/src/utils/external-resource-validator.js.map +1 -1
  139. package/dist/src/utils/project-detection.d.ts.map +1 -1
  140. package/dist/src/utils/project-detection.js +19 -21
  141. package/dist/src/utils/project-detection.js.map +1 -1
  142. package/dist/src/utils/project-validator.d.ts.map +1 -1
  143. package/dist/src/utils/project-validator.js +5 -7
  144. package/dist/src/utils/project-validator.js.map +1 -1
  145. package/package.json +2 -3
  146. package/plugins/specweave/agents/tech-lead/AGENT.md +9 -0
  147. package/plugins/specweave/hooks/docs-changed.sh.backup +79 -0
  148. package/plugins/specweave/hooks/human-input-required.sh.backup +75 -0
  149. package/plugins/specweave/hooks/post-first-increment.sh.backup +61 -0
  150. package/plugins/specweave/hooks/post-increment-change.sh.backup +98 -0
  151. package/plugins/specweave/hooks/post-increment-completion.sh.backup +231 -0
  152. package/plugins/specweave/hooks/post-increment-planning.sh.backup +1048 -0
  153. package/plugins/specweave/hooks/post-increment-status-change.sh.backup +147 -0
  154. package/plugins/specweave/hooks/post-spec-update.sh.backup +158 -0
  155. package/plugins/specweave/hooks/post-user-story-complete.sh.backup +179 -0
  156. package/plugins/specweave/hooks/pre-command-deduplication.sh.backup +83 -0
  157. package/plugins/specweave/hooks/pre-implementation.sh.backup +67 -0
  158. package/plugins/specweave/hooks/pre-task-completion.sh.backup +194 -0
  159. package/plugins/specweave/hooks/pre-tool-use.sh.backup +133 -0
  160. package/plugins/specweave/hooks/user-prompt-submit.sh.backup +386 -0
  161. package/plugins/specweave/lib/vendor/core/increment/auto-transition-manager.d.ts +12 -0
  162. package/plugins/specweave/lib/vendor/core/increment/auto-transition-manager.js +45 -0
  163. package/plugins/specweave/lib/vendor/core/increment/auto-transition-manager.js.map +1 -1
  164. package/plugins/specweave/lib/vendor/core/increment/metadata-manager.js +46 -0
  165. package/plugins/specweave/lib/vendor/core/increment/metadata-manager.js.map +1 -1
  166. package/plugins/specweave/skills/increment-planner/SKILL.md +10 -5
  167. package/plugins/specweave/skills/specweave-framework/SKILL.md +6 -4
  168. package/plugins/specweave/templates/coding-standards.md.template +36 -0
  169. package/plugins/specweave-ado/hooks/post-living-docs-update.sh.backup +353 -0
  170. package/plugins/specweave-ado/hooks/post-task-completion.sh.backup +172 -0
  171. package/plugins/specweave-ado/lib/ado-multi-project-sync.js +1 -0
  172. package/plugins/specweave-ado/lib/enhanced-ado-sync.js +170 -0
  173. package/plugins/specweave-ado/lib/project-selector.js +56 -67
  174. package/plugins/specweave-ado/lib/project-selector.ts +72 -85
  175. package/plugins/specweave-github/hooks/.specweave/logs/hooks-debug.log +1104 -0
  176. package/plugins/specweave-github/hooks/post-task-completion.sh.backup +258 -0
  177. package/plugins/specweave-github/lib/repo-selector.js +55 -66
  178. package/plugins/specweave-github/lib/repo-selector.ts +73 -84
  179. package/plugins/specweave-jira/commands/import-projects.js +3 -5
  180. package/plugins/specweave-jira/commands/import-projects.ts +3 -5
  181. package/plugins/specweave-jira/hooks/post-task-completion.sh.backup +172 -0
  182. package/plugins/specweave-jira/lib/enhanced-jira-sync.js +3 -3
  183. package/plugins/specweave-jira/lib/project-selector.js +60 -71
  184. package/plugins/specweave-jira/lib/project-selector.ts +78 -91
  185. package/plugins/specweave-jira/lib/setup-wizard.js +51 -72
  186. package/plugins/specweave-jira/lib/setup-wizard.ts +56 -74
  187. package/plugins/specweave-release/hooks/.specweave/logs/dora-tracking.log +1017 -0
  188. package/plugins/specweave-release/hooks/post-task-completion.sh.backup +110 -0
  189. package/src/templates/CLAUDE.md.template +14 -0
@@ -113,15 +113,17 @@ Every increment MUST have `metadata.json` or:
113
113
 
114
114
  ### 4. Increment Structure
115
115
 
116
- **Complete directory structure**:
116
+ **Directory structure**:
117
117
  ```
118
118
  .specweave/increments/0001-feature-name/
119
- ├── spec.md # WHAT & WHY (user stories, acceptance criteria)
120
- ├── plan.md # HOW (technical design, architecture)
121
- ├── tasks.md # STEPS (implementation tasks with embedded tests)
122
- └── metadata.json # Metadata (MANDATORY)
119
+ ├── spec.md # WHAT & WHY (user stories, acceptance criteria) - REQUIRED
120
+ ├── plan.md # HOW (technical design, architecture) - OPTIONAL
121
+ ├── tasks.md # STEPS (implementation tasks with embedded tests) - REQUIRED
122
+ └── metadata.json # Metadata - REQUIRED
123
123
  ```
124
124
 
125
+ **plan.md is OPTIONAL** - create only for complex features with architecture decisions. Skip for bug fixes, migrations, hotfixes.
126
+
125
127
  **NO separate tests.md** - tests embedded in tasks.md (v0.7.0+)
126
128
 
127
129
  ---
@@ -597,6 +599,8 @@ node plugins/specweave/skills/increment-planner/scripts/generate-short-name.js "
597
599
 
598
600
  **✅ DO**:
599
601
  - Always create metadata.json (MANDATORY)
602
+ - Always create spec.md and tasks.md (MANDATORY)
603
+ - Create plan.md only for complex features with architecture decisions
600
604
  - Use descriptive increment names
601
605
  - Include AC-IDs in all acceptance criteria
602
606
  - Embed tests in tasks.md (NO separate tests.md)
@@ -607,6 +611,7 @@ node plugins/specweave/skills/increment-planner/scripts/generate-short-name.js "
607
611
  - Use bare numbers (0001) without description
608
612
  - Spawn agents from this skill (causes crashes)
609
613
  - Skip metadata.json creation
614
+ - Create plan.md for bug fixes, simple migrations, or hotfixes
610
615
  - Create separate tests.md (deprecated v0.7.0+)
611
616
  - Reference SpecWeave internal docs/ADRs (users won't have them)
612
617
  - Over-plan in skill (keep templates simple)
@@ -23,10 +23,12 @@ SpecWeave follows **spec-driven development** with **increment-based workflows**
23
23
  ### What is an Increment?
24
24
 
25
25
  An **increment** = a complete feature with:
26
- - `spec.md` - Product requirements (WHAT and WHY)
27
- - `plan.md` - Technical architecture (HOW to implement)
28
- - `tasks.md` - Task breakdown (WORK to do)
29
- - `tests.md` - Quality gates (TEST coverage)
26
+ - `spec.md` - Product requirements (WHAT and WHY) — **required**
27
+ - `plan.md` - Technical architecture (HOW to implement) — **optional**, for complex features only
28
+ - `tasks.md` - Task breakdown (WORK to do) — **required**
29
+ - `metadata.json` - State tracking — **required**
30
+
31
+ > **When to skip plan.md**: Bug fixes, simple migrations, hotfixes, and straightforward tasks where spec.md already describes the approach.
30
32
 
31
33
  ### Increment Naming Convention (v0.6.0+)
32
34
 
@@ -192,6 +192,42 @@
192
192
 
193
193
  ---
194
194
 
195
+ ### File Size Limits
196
+
197
+ **Critical for AI-assisted development** - Large files cause context overflow crashes.
198
+
199
+ | Lines | Status | Action Required |
200
+ |-------|--------|-----------------|
201
+ | 0-500 | ✅ OK | Normal development |
202
+ | 500-1000 | âš ī¸ Watch | Review before adding major features |
203
+ | 1000-1500 | đŸ”ļ Large | Extract modules before adding 100+ lines |
204
+ | 1500-2000 | 🔴 Critical | **MUST SPLIT** before any changes |
205
+ | 2000+ | ⛔ Forbidden | Immediate refactor required |
206
+
207
+ **Current Large Files** ({{large_file_count}} files >1000 lines):
208
+ {{large_files_list}}
209
+
210
+ **How to Split Large Files**:
211
+ ```
212
+ src/feature/module.ts ← Orchestrator only (300-500 lines)
213
+ src/feature/module/
214
+ ├── index.ts ← Barrel exports (re-export public API)
215
+ ├── types.ts ← Interfaces and types
216
+ ├── domain-logic-a.ts ← Single responsibility
217
+ ├── domain-logic-b.ts ← Single responsibility
218
+ └── internal-utils.ts ← Private helpers
219
+ ```
220
+
221
+ **Split Triggers**:
222
+ - File has 3+ distinct responsibilities
223
+ - Multiple unrelated import groups
224
+ - Testing requires mocking large portions
225
+ - Functions within file don't share state
226
+
227
+ **Recommendation**: {{file_size_recommendation}}
228
+
229
+ ---
230
+
195
231
  ### Function Style
196
232
 
197
233
  **Detected Pattern**:
@@ -0,0 +1,353 @@
1
+ #!/bin/bash
2
+
3
+ # ============================================================================
4
+ # Post Living Docs Update Hook - Azure DevOps Sync
5
+ # ============================================================================
6
+ #
7
+ # Triggered after living docs are updated to sync with Azure DevOps.
8
+ # CRITICAL: External tool status ALWAYS wins in conflicts!
9
+ #
10
+ # Triggers:
11
+ # 1. After /specweave:done (increment completion)
12
+ # 2. After /specweave:sync-docs update
13
+ # 3. After manual spec edits
14
+ # 4. After webhook from ADO
15
+ #
16
+ # ============================================================================
17
+
18
+ set -e
19
+
20
+ # Configuration
21
+ SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)"
22
+ PROJECT_ROOT="$(cd "$SCRIPT_DIR/../../.." && pwd)"
23
+ LIVING_DOCS_DIR="$PROJECT_ROOT/.specweave/docs/internal/specs"
24
+ LOG_FILE="$PROJECT_ROOT/.specweave/logs/ado-sync.log"
25
+ DEBUG=${DEBUG:-0}
26
+
27
+ # Ensure log directory exists
28
+ mkdir -p "$(dirname "$LOG_FILE")"
29
+
30
+ # ============================================================================
31
+ # Logging
32
+ # ============================================================================
33
+
34
+ log() {
35
+ local level=$1
36
+ shift
37
+ local message="$@"
38
+ local timestamp=$(date '+%Y-%m-%d %H:%M:%S')
39
+ echo "[$timestamp] [$level] $message" >> "$LOG_FILE"
40
+ [ "$DEBUG" -eq 1 ] && echo "[$level] $message" >&2
41
+ }
42
+
43
+ log_info() {
44
+ log "INFO" "$@"
45
+ }
46
+
47
+ log_error() {
48
+ log "ERROR" "$@"
49
+ }
50
+
51
+ log_debug() {
52
+ [ "$DEBUG" -eq 1 ] && log "DEBUG" "$@"
53
+ }
54
+
55
+ # ============================================================================
56
+ # External Tool Detection
57
+ # ============================================================================
58
+
59
+ detect_external_tool() {
60
+ local spec_path=$1
61
+
62
+ # Check for external links in spec metadata
63
+ if grep -q "externalLinks:" "$spec_path"; then
64
+ if grep -q "ado:" "$spec_path"; then
65
+ echo "ado"
66
+ elif grep -q "jira:" "$spec_path"; then
67
+ echo "jira"
68
+ elif grep -q "github:" "$spec_path"; then
69
+ echo "github"
70
+ fi
71
+ fi
72
+ }
73
+
74
+ # ============================================================================
75
+ # Status Mapping
76
+ # ============================================================================
77
+
78
+ map_ado_status_to_local() {
79
+ local ado_status=$1
80
+
81
+ case "$ado_status" in
82
+ "New")
83
+ echo "draft"
84
+ ;;
85
+ "Active")
86
+ echo "in-progress"
87
+ ;;
88
+ "Resolved")
89
+ echo "implemented"
90
+ ;;
91
+ "Closed")
92
+ echo "complete"
93
+ ;;
94
+ "In Review"|"In QA")
95
+ echo "in-qa"
96
+ ;;
97
+ *)
98
+ echo "unknown"
99
+ ;;
100
+ esac
101
+ }
102
+
103
+ map_local_status_to_ado() {
104
+ local local_status=$1
105
+
106
+ case "$local_status" in
107
+ "draft")
108
+ echo "New"
109
+ ;;
110
+ "in-progress")
111
+ echo "Active"
112
+ ;;
113
+ "implemented")
114
+ echo "Resolved"
115
+ ;;
116
+ "complete")
117
+ echo "Closed"
118
+ ;;
119
+ "in-qa")
120
+ echo "In Review"
121
+ ;;
122
+ *)
123
+ echo "Active"
124
+ ;;
125
+ esac
126
+ }
127
+
128
+ # ============================================================================
129
+ # ADO API Functions
130
+ # ============================================================================
131
+
132
+ get_ado_work_item_status() {
133
+ local work_item_id=$1
134
+ local org="${AZURE_DEVOPS_ORG}"
135
+ local project="${AZURE_DEVOPS_PROJECT}"
136
+ local pat="${AZURE_DEVOPS_PAT}"
137
+
138
+ if [ -z "$org" ] || [ -z "$pat" ]; then
139
+ log_error "ADO credentials not configured"
140
+ return 1
141
+ fi
142
+
143
+ local api_url="https://dev.azure.com/${org}/${project}/_apis/wit/workitems/${work_item_id}?api-version=7.0"
144
+
145
+ log_debug "Fetching ADO work item $work_item_id status"
146
+
147
+ local response=$(curl -s -u ":${pat}" \
148
+ -H "Content-Type: application/json" \
149
+ "$api_url")
150
+
151
+ if [ $? -ne 0 ]; then
152
+ log_error "Failed to fetch ADO work item status"
153
+ return 1
154
+ fi
155
+
156
+ # Extract status from response
157
+ local status=$(echo "$response" | jq -r '.fields["System.State"]')
158
+
159
+ if [ "$status" = "null" ] || [ -z "$status" ]; then
160
+ log_error "Could not extract status from ADO response"
161
+ return 1
162
+ fi
163
+
164
+ echo "$status"
165
+ }
166
+
167
+ update_ado_work_item() {
168
+ local work_item_id=$1
169
+ local spec_content=$2
170
+ local org="${AZURE_DEVOPS_ORG}"
171
+ local project="${AZURE_DEVOPS_PROJECT}"
172
+ local pat="${AZURE_DEVOPS_PAT}"
173
+
174
+ if [ -z "$org" ] || [ -z "$pat" ]; then
175
+ log_error "ADO credentials not configured"
176
+ return 1
177
+ fi
178
+
179
+ # Extract current status from spec
180
+ local local_status=$(echo "$spec_content" | grep "^status:" | cut -d: -f2 | tr -d ' ')
181
+ local ado_status=$(map_local_status_to_ado "$local_status")
182
+
183
+ local api_url="https://dev.azure.com/${org}/${project}/_apis/wit/workitems/${work_item_id}?api-version=7.0"
184
+
185
+ # Create update payload
186
+ local payload=$(cat <<EOF
187
+ [
188
+ {
189
+ "op": "add",
190
+ "path": "/fields/System.State",
191
+ "value": "$ado_status"
192
+ },
193
+ {
194
+ "op": "add",
195
+ "path": "/fields/System.History",
196
+ "value": "Updated from SpecWeave living docs"
197
+ }
198
+ ]
199
+ EOF
200
+ )
201
+
202
+ log_debug "Updating ADO work item $work_item_id with status: $ado_status"
203
+
204
+ curl -s -X PATCH \
205
+ -u ":${pat}" \
206
+ -H "Content-Type: application/json-patch+json" \
207
+ -d "$payload" \
208
+ "$api_url" > /dev/null
209
+
210
+ if [ $? -ne 0 ]; then
211
+ log_error "Failed to update ADO work item"
212
+ return 1
213
+ fi
214
+
215
+ log_info "Updated ADO work item $work_item_id"
216
+ }
217
+
218
+ # ============================================================================
219
+ # Conflict Resolution - CRITICAL: External Wins!
220
+ # ============================================================================
221
+
222
+ resolve_status_conflict() {
223
+ local spec_path=$1
224
+ local local_status=$2
225
+ local external_status=$3
226
+
227
+ local mapped_external=$(map_ado_status_to_local "$external_status")
228
+
229
+ if [ "$local_status" != "$mapped_external" ]; then
230
+ log_info "Status conflict detected:"
231
+ log_info " Local: $local_status"
232
+ log_info " External: $external_status (mapped: $mapped_external)"
233
+ log_info " Resolution: EXTERNAL WINS - applying $mapped_external"
234
+
235
+ # Update local spec with external status
236
+ sed -i.bak "s/^status: .*/status: $mapped_external/" "$spec_path"
237
+
238
+ # Add sync metadata
239
+ local timestamp=$(date -u '+%Y-%m-%dT%H:%M:%SZ')
240
+
241
+ # Check if syncedAt exists, update or add
242
+ if grep -q "syncedAt:" "$spec_path"; then
243
+ sed -i.bak "s/syncedAt: .*/syncedAt: \"$timestamp\"/" "$spec_path"
244
+ else
245
+ # Add after externalLinks section
246
+ sed -i.bak "/externalLinks:/a\\
247
+ syncedAt: \"$timestamp\"" "$spec_path"
248
+ fi
249
+
250
+ # Clean up backup files
251
+ rm -f "${spec_path}.bak"
252
+
253
+ log_info "Local spec updated with external status: $mapped_external"
254
+ return 0
255
+ else
256
+ log_debug "No status conflict - local and external match: $local_status"
257
+ return 0
258
+ fi
259
+ }
260
+
261
+ # ============================================================================
262
+ # Main Sync Function
263
+ # ============================================================================
264
+
265
+ sync_spec_with_ado() {
266
+ local spec_path=$1
267
+
268
+ if [ ! -f "$spec_path" ]; then
269
+ log_error "Spec file not found: $spec_path"
270
+ return 1
271
+ fi
272
+
273
+ local spec_name=$(basename "$spec_path")
274
+ log_info "Syncing spec: $spec_name"
275
+
276
+ # Read spec content
277
+ local spec_content=$(cat "$spec_path")
278
+
279
+ # Extract ADO work item ID from metadata
280
+ local work_item_id=$(echo "$spec_content" | grep -A5 "externalLinks:" | grep -A3 "ado:" | grep "featureId:" | cut -d: -f2 | tr -d ' ')
281
+
282
+ if [ -z "$work_item_id" ]; then
283
+ log_debug "No ADO work item linked to spec, skipping sync"
284
+ return 0
285
+ fi
286
+
287
+ log_info "Found ADO work item ID: $work_item_id"
288
+
289
+ # Step 1: Push updates to ADO (content changes)
290
+ update_ado_work_item "$work_item_id" "$spec_content"
291
+
292
+ # Step 2: CRITICAL - Pull status from ADO (external wins!)
293
+ local external_status=$(get_ado_work_item_status "$work_item_id")
294
+
295
+ if [ -z "$external_status" ]; then
296
+ log_error "Could not fetch ADO status"
297
+ return 1
298
+ fi
299
+
300
+ log_info "ADO status: $external_status"
301
+
302
+ # Step 3: Extract local status
303
+ local local_status=$(echo "$spec_content" | grep "^status:" | cut -d: -f2 | tr -d ' ')
304
+
305
+ log_info "Local status: $local_status"
306
+
307
+ # Step 4: Resolve conflicts - EXTERNAL WINS
308
+ resolve_status_conflict "$spec_path" "$local_status" "$external_status"
309
+
310
+ log_info "Sync completed for $spec_name"
311
+ }
312
+
313
+ # ============================================================================
314
+ # Entry Point
315
+ # ============================================================================
316
+
317
+ main() {
318
+ log_info "=== Post Living Docs Update Hook Started ==="
319
+
320
+ # Get the spec path from arguments or environment
321
+ local spec_path="${1:-$SPECWEAVE_UPDATED_SPEC}"
322
+
323
+ if [ -z "$spec_path" ]; then
324
+ log_error "No spec path provided"
325
+ exit 1
326
+ fi
327
+
328
+ # Detect external tool
329
+ local tool=$(detect_external_tool "$spec_path")
330
+
331
+ if [ "$tool" != "ado" ]; then
332
+ log_debug "Not an ADO-linked spec, skipping"
333
+ exit 0
334
+ fi
335
+
336
+ log_info "Detected ADO integration for spec"
337
+
338
+ # Perform sync
339
+ sync_spec_with_ado "$spec_path"
340
+
341
+ local exit_code=$?
342
+
343
+ if [ $exit_code -eq 0 ]; then
344
+ log_info "=== Sync completed successfully ==="
345
+ else
346
+ log_error "=== Sync failed with exit code: $exit_code ==="
347
+ fi
348
+
349
+ exit $exit_code
350
+ }
351
+
352
+ # Run main function
353
+ main "$@"
@@ -0,0 +1,172 @@
1
+ #!/bin/bash
2
+
3
+ # SpecWeave Azure DevOps Sync Hook
4
+ # Runs after task completion to sync progress to Azure DevOps Work Items
5
+ #
6
+ # This hook is part of the specweave-ado plugin and handles:
7
+ # - Syncing task completion state to Azure DevOps work items
8
+ # - Updating ADO work item status based on increment progress
9
+ #
10
+ # Dependencies:
11
+ # - Node.js for running sync scripts
12
+ # - jq for JSON parsing
13
+ # - metadata.json must have .ado.item field
14
+ # - Azure DevOps PAT in .env
15
+
16
+ set -e
17
+
18
+ # ============================================================================
19
+ # PROJECT ROOT DETECTION
20
+ # ============================================================================
21
+
22
+ # Find project root by searching upward for .specweave/ directory
23
+ find_project_root() {
24
+ local dir="$1"
25
+ while [ "$dir" != "/" ]; do
26
+ if [ -d "$dir/.specweave" ]; then
27
+ echo "$dir"
28
+ return 0
29
+ fi
30
+ dir="$(dirname "$dir")"
31
+ done
32
+ # Fallback: try current directory
33
+ if [ -d "$(pwd)/.specweave" ]; then
34
+ pwd
35
+ else
36
+ echo "$(pwd)"
37
+ fi
38
+ }
39
+
40
+ PROJECT_ROOT="$(find_project_root "$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)")"
41
+ cd "$PROJECT_ROOT" 2>/dev/null || true
42
+
43
+ # ============================================================================
44
+ # CONFIGURATION
45
+ # ============================================================================
46
+
47
+ LOGS_DIR=".specweave/logs"
48
+ DEBUG_LOG="$LOGS_DIR/hooks-debug.log"
49
+
50
+ mkdir -p "$LOGS_DIR" 2>/dev/null || true
51
+
52
+ # ============================================================================
53
+ # PRECONDITIONS CHECK
54
+ # ============================================================================
55
+
56
+ echo "[$(date)] [ADO] 🔗 Azure DevOps sync hook fired" >> "$DEBUG_LOG" 2>/dev/null || true
57
+
58
+ # Detect current increment
59
+ CURRENT_INCREMENT=$(ls -td .specweave/increments/*/ 2>/dev/null | xargs -n1 basename | grep -v "_backlog" | grep -v "_archive" | grep -v "_working" | head -1)
60
+
61
+ if [ -z "$CURRENT_INCREMENT" ]; then
62
+ echo "[$(date)] [ADO] â„šī¸ No active increment, skipping ADO sync" >> "$DEBUG_LOG" 2>/dev/null || true
63
+ cat <<EOF
64
+ {
65
+ "continue": true
66
+ }
67
+ EOF
68
+ exit 0
69
+ fi
70
+
71
+ # Check for metadata.json
72
+ METADATA_FILE=".specweave/increments/$CURRENT_INCREMENT/metadata.json"
73
+
74
+ if [ ! -f "$METADATA_FILE" ]; then
75
+ echo "[$(date)] [ADO] â„šī¸ No metadata.json for $CURRENT_INCREMENT, skipping ADO sync" >> "$DEBUG_LOG" 2>/dev/null || true
76
+ cat <<EOF
77
+ {
78
+ "continue": true
79
+ }
80
+ EOF
81
+ exit 0
82
+ fi
83
+
84
+ # Check for ADO work item link
85
+ if ! command -v jq &> /dev/null; then
86
+ echo "[$(date)] [ADO] âš ī¸ jq not found, skipping ADO sync" >> "$DEBUG_LOG" 2>/dev/null || true
87
+ cat <<EOF
88
+ {
89
+ "continue": true
90
+ }
91
+ EOF
92
+ exit 0
93
+ fi
94
+
95
+ ADO_ITEM=$(jq -r '.ado.item // empty' "$METADATA_FILE" 2>/dev/null)
96
+
97
+ if [ -z "$ADO_ITEM" ]; then
98
+ echo "[$(date)] [ADO] â„šī¸ No Azure DevOps work item linked to $CURRENT_INCREMENT, skipping sync" >> "$DEBUG_LOG" 2>/dev/null || true
99
+ cat <<EOF
100
+ {
101
+ "continue": true
102
+ }
103
+ EOF
104
+ exit 0
105
+ fi
106
+
107
+ # Check for Node.js
108
+ if ! command -v node &> /dev/null; then
109
+ echo "[$(date)] [ADO] âš ī¸ Node.js not found, skipping ADO sync" >> "$DEBUG_LOG" 2>/dev/null || true
110
+ cat <<EOF
111
+ {
112
+ "continue": true
113
+ }
114
+ EOF
115
+ exit 0
116
+ fi
117
+
118
+ # Check for ADO sync script
119
+ if [ ! -f "dist/commands/ado-sync.js" ]; then
120
+ echo "[$(date)] [ADO] âš ī¸ ado-sync.js not found, skipping ADO sync" >> "$DEBUG_LOG" 2>/dev/null || true
121
+ cat <<EOF
122
+ {
123
+ "continue": true
124
+ }
125
+ EOF
126
+ exit 0
127
+ fi
128
+
129
+ # ============================================================================
130
+ # AZURE DEVOPS SYNC LOGIC
131
+ # ============================================================================
132
+
133
+ echo "[$(date)] [ADO] 🔄 Syncing to Azure DevOps work item $ADO_ITEM" >> "$DEBUG_LOG" 2>/dev/null || true
134
+
135
+ # Run ADO sync command (non-blocking)
136
+ node dist/commands/ado-sync.js "$CURRENT_INCREMENT" 2>&1 | tee -a "$DEBUG_LOG" >/dev/null || {
137
+ echo "[$(date)] [ADO] âš ī¸ Failed to sync to Azure DevOps (non-blocking)" >> "$DEBUG_LOG" 2>/dev/null || true
138
+ }
139
+
140
+ echo "[$(date)] [ADO] ✅ Azure DevOps sync complete" >> "$DEBUG_LOG" 2>/dev/null || true
141
+
142
+ # ============================================================================
143
+ # SPEC COMMIT SYNC (NEW!)
144
+ # ============================================================================
145
+
146
+ echo "[$(date)] [ADO] 🔗 Checking for spec commit sync..." >> "$DEBUG_LOG" 2>/dev/null || true
147
+
148
+ # Call TypeScript CLI to sync commits
149
+ if command -v node &> /dev/null && [ -f "$PROJECT_ROOT/dist/cli/commands/sync-spec-commits.js" ]; then
150
+ echo "[$(date)] [ADO] 🚀 Running spec commit sync..." >> "$DEBUG_LOG" 2>/dev/null || true
151
+
152
+ node "$PROJECT_ROOT/dist/cli/commands/sync-spec-commits.js" \
153
+ --increment "$PROJECT_ROOT/.specweave/increments/$CURRENT_INCREMENT" \
154
+ --provider ado \
155
+ 2>&1 | tee -a "$DEBUG_LOG" >/dev/null || {
156
+ echo "[$(date)] [ADO] âš ī¸ Spec commit sync failed (non-blocking)" >> "$DEBUG_LOG" 2>/dev/null || true
157
+ }
158
+
159
+ echo "[$(date)] [ADO] ✅ Spec commit sync complete" >> "$DEBUG_LOG" 2>/dev/null || true
160
+ else
161
+ echo "[$(date)] [ADO] â„šī¸ Spec commit sync not available (node or script not found)" >> "$DEBUG_LOG" 2>/dev/null || true
162
+ fi
163
+
164
+ # ============================================================================
165
+ # OUTPUT TO CLAUDE
166
+ # ============================================================================
167
+
168
+ cat <<EOF
169
+ {
170
+ "continue": true
171
+ }
172
+ EOF
@@ -373,6 +373,7 @@ ${userStory.technicalContext}
373
373
  return mapping.task || "Task";
374
374
  case "Subtask":
375
375
  return mapping.task || "Task";
376
+ // ADO doesn't have subtasks, use Task
376
377
  default:
377
378
  return "User Story";
378
379
  }