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.
- package/CLAUDE.md +73 -1
- package/README.md +111 -466
- package/dist/plugins/specweave-jira/lib/setup-wizard.d.ts.map +1 -1
- package/dist/plugins/specweave-jira/lib/setup-wizard.js +57 -78
- package/dist/plugins/specweave-jira/lib/setup-wizard.js.map +1 -1
- package/dist/src/cli/commands/import-docs.d.ts.map +1 -1
- package/dist/src/cli/commands/import-docs.js +23 -31
- package/dist/src/cli/commands/import-docs.js.map +1 -1
- package/dist/src/cli/commands/import-external.d.ts.map +1 -1
- package/dist/src/cli/commands/import-external.js +6 -10
- package/dist/src/cli/commands/import-external.js.map +1 -1
- package/dist/src/cli/commands/init-multiproject.d.ts.map +1 -1
- package/dist/src/cli/commands/init-multiproject.js +58 -73
- package/dist/src/cli/commands/init-multiproject.js.map +1 -1
- package/dist/src/cli/commands/init.d.ts +17 -11
- package/dist/src/cli/commands/init.d.ts.map +1 -1
- package/dist/src/cli/commands/init.js +221 -1874
- package/dist/src/cli/commands/init.js.map +1 -1
- package/dist/src/cli/commands/install.d.ts.map +1 -1
- package/dist/src/cli/commands/install.js +14 -22
- package/dist/src/cli/commands/install.js.map +1 -1
- package/dist/src/cli/commands/migrate-config.d.ts.map +1 -1
- package/dist/src/cli/commands/migrate-config.js +6 -10
- package/dist/src/cli/commands/migrate-config.js.map +1 -1
- package/dist/src/cli/commands/switch-project.d.ts.map +1 -1
- package/dist/src/cli/commands/switch-project.js.map +1 -1
- package/dist/src/cli/helpers/ado-area-path-mapper.d.ts.map +1 -1
- package/dist/src/cli/helpers/ado-area-path-mapper.js +36 -49
- package/dist/src/cli/helpers/ado-area-path-mapper.js.map +1 -1
- package/dist/src/cli/helpers/github/increment-profile-selector.d.ts.map +1 -1
- package/dist/src/cli/helpers/github/increment-profile-selector.js.map +1 -1
- package/dist/src/cli/helpers/github/profile-manager.d.ts.map +1 -1
- package/dist/src/cli/helpers/github/profile-manager.js +8 -11
- package/dist/src/cli/helpers/github/profile-manager.js.map +1 -1
- package/dist/src/cli/helpers/github-repo-selector.d.ts.map +1 -1
- package/dist/src/cli/helpers/github-repo-selector.js +26 -50
- package/dist/src/cli/helpers/github-repo-selector.js.map +1 -1
- package/dist/src/cli/helpers/import-strategy-prompter.d.ts.map +1 -1
- package/dist/src/cli/helpers/import-strategy-prompter.js +39 -52
- package/dist/src/cli/helpers/import-strategy-prompter.js.map +1 -1
- package/dist/src/cli/helpers/init/config-detection.d.ts +40 -0
- package/dist/src/cli/helpers/init/config-detection.d.ts.map +1 -0
- package/dist/src/cli/helpers/init/config-detection.js +125 -0
- package/dist/src/cli/helpers/init/config-detection.js.map +1 -0
- package/dist/src/cli/helpers/init/directory-structure.d.ts +26 -0
- package/dist/src/cli/helpers/init/directory-structure.d.ts.map +1 -0
- package/dist/src/cli/helpers/init/directory-structure.js +190 -0
- package/dist/src/cli/helpers/init/directory-structure.js.map +1 -0
- package/dist/src/cli/helpers/init/external-import.d.ts +15 -0
- package/dist/src/cli/helpers/init/external-import.d.ts.map +1 -0
- package/dist/src/cli/helpers/init/external-import.js +251 -0
- package/dist/src/cli/helpers/init/external-import.js.map +1 -0
- package/dist/src/cli/helpers/init/index.d.ts +15 -0
- package/dist/src/cli/helpers/init/index.d.ts.map +1 -0
- package/dist/src/cli/helpers/init/index.js +26 -0
- package/dist/src/cli/helpers/init/index.js.map +1 -0
- package/dist/src/cli/helpers/init/next-steps.d.ts +15 -0
- package/dist/src/cli/helpers/init/next-steps.d.ts.map +1 -0
- package/dist/src/cli/helpers/init/next-steps.js +72 -0
- package/dist/src/cli/helpers/init/next-steps.js.map +1 -0
- package/dist/src/cli/helpers/init/path-utils.d.ts +41 -0
- package/dist/src/cli/helpers/init/path-utils.d.ts.map +1 -0
- package/dist/src/cli/helpers/init/path-utils.js +146 -0
- package/dist/src/cli/helpers/init/path-utils.js.map +1 -0
- package/dist/src/cli/helpers/init/plugin-installer.d.ts +28 -0
- package/dist/src/cli/helpers/init/plugin-installer.d.ts.map +1 -0
- package/dist/src/cli/helpers/init/plugin-installer.js +238 -0
- package/dist/src/cli/helpers/init/plugin-installer.js.map +1 -0
- package/dist/src/cli/helpers/init/repository-setup.d.ts +28 -0
- package/dist/src/cli/helpers/init/repository-setup.d.ts.map +1 -0
- package/dist/src/cli/helpers/init/repository-setup.js +78 -0
- package/dist/src/cli/helpers/init/repository-setup.js.map +1 -0
- package/dist/src/cli/helpers/init/smart-reinit.d.ts +30 -0
- package/dist/src/cli/helpers/init/smart-reinit.d.ts.map +1 -0
- package/dist/src/cli/helpers/init/smart-reinit.js +140 -0
- package/dist/src/cli/helpers/init/smart-reinit.js.map +1 -0
- package/dist/src/cli/helpers/init/testing-config.d.ts +27 -0
- package/dist/src/cli/helpers/init/testing-config.d.ts.map +1 -0
- package/dist/src/cli/helpers/init/testing-config.js +131 -0
- package/dist/src/cli/helpers/init/testing-config.js.map +1 -0
- package/dist/src/cli/helpers/init/types.d.ts +86 -0
- package/dist/src/cli/helpers/init/types.d.ts.map +1 -0
- package/dist/src/cli/helpers/init/types.js +5 -0
- package/dist/src/cli/helpers/init/types.js.map +1 -0
- package/dist/src/cli/helpers/issue-tracker/ado-auto-discover.d.ts.map +1 -1
- package/dist/src/cli/helpers/issue-tracker/ado-auto-discover.js +10 -12
- package/dist/src/cli/helpers/issue-tracker/ado-auto-discover.js.map +1 -1
- package/dist/src/cli/helpers/issue-tracker/ado.d.ts.map +1 -1
- package/dist/src/cli/helpers/issue-tracker/ado.js +43 -60
- package/dist/src/cli/helpers/issue-tracker/ado.js.map +1 -1
- package/dist/src/cli/helpers/issue-tracker/github-multi-repo.d.ts.map +1 -1
- package/dist/src/cli/helpers/issue-tracker/github-multi-repo.js +193 -230
- package/dist/src/cli/helpers/issue-tracker/github-multi-repo.js.map +1 -1
- package/dist/src/cli/helpers/issue-tracker/github.d.ts.map +1 -1
- package/dist/src/cli/helpers/issue-tracker/github.js +43 -54
- package/dist/src/cli/helpers/issue-tracker/github.js.map +1 -1
- package/dist/src/cli/helpers/issue-tracker/index.d.ts.map +1 -1
- package/dist/src/cli/helpers/issue-tracker/index.js +27 -40
- package/dist/src/cli/helpers/issue-tracker/index.js.map +1 -1
- package/dist/src/cli/helpers/issue-tracker/jira.d.ts.map +1 -1
- package/dist/src/cli/helpers/issue-tracker/jira.js +54 -70
- package/dist/src/cli/helpers/issue-tracker/jira.js.map +1 -1
- package/dist/src/cli/helpers/smart-filter.d.ts.map +1 -1
- package/dist/src/cli/helpers/smart-filter.js +62 -85
- package/dist/src/cli/helpers/smart-filter.js.map +1 -1
- package/dist/src/core/increment/auto-transition-manager.d.ts +12 -0
- package/dist/src/core/increment/auto-transition-manager.d.ts.map +1 -1
- package/dist/src/core/increment/auto-transition-manager.js +45 -0
- package/dist/src/core/increment/auto-transition-manager.js.map +1 -1
- package/dist/src/core/increment/metadata-manager.d.ts.map +1 -1
- package/dist/src/core/increment/metadata-manager.js +46 -0
- package/dist/src/core/increment/metadata-manager.js.map +1 -1
- package/dist/src/core/increment/status-change-sync-trigger.d.ts +12 -0
- package/dist/src/core/increment/status-change-sync-trigger.d.ts.map +1 -1
- package/dist/src/core/increment/status-change-sync-trigger.js +48 -2
- package/dist/src/core/increment/status-change-sync-trigger.js.map +1 -1
- package/dist/src/core/living-docs/living-docs-sync.d.ts +13 -0
- package/dist/src/core/living-docs/living-docs-sync.d.ts.map +1 -1
- package/dist/src/core/living-docs/living-docs-sync.js +40 -0
- package/dist/src/core/living-docs/living-docs-sync.js.map +1 -1
- package/dist/src/core/repo-structure/repo-bulk-discovery.d.ts.map +1 -1
- package/dist/src/core/repo-structure/repo-bulk-discovery.js +63 -83
- package/dist/src/core/repo-structure/repo-bulk-discovery.js.map +1 -1
- package/dist/src/core/repo-structure/repo-structure-manager.d.ts.map +1 -1
- package/dist/src/core/repo-structure/repo-structure-manager.js +339 -424
- package/dist/src/core/repo-structure/repo-structure-manager.js.map +1 -1
- package/dist/src/core/sync/bidirectional-engine.d.ts.map +1 -1
- package/dist/src/core/sync/bidirectional-engine.js +21 -29
- package/dist/src/core/sync/bidirectional-engine.js.map +1 -1
- package/dist/src/init/InitFlow.js +15 -19
- package/dist/src/init/InitFlow.js.map +1 -1
- package/dist/src/init/repo/types.d.ts +1 -1
- package/dist/src/integrations/ado/area-path-mapper.d.ts.map +1 -1
- package/dist/src/integrations/ado/area-path-mapper.js +19 -23
- package/dist/src/integrations/ado/area-path-mapper.js.map +1 -1
- package/dist/src/utils/external-resource-validator.d.ts.map +1 -1
- package/dist/src/utils/external-resource-validator.js +41 -65
- package/dist/src/utils/external-resource-validator.js.map +1 -1
- package/dist/src/utils/project-detection.d.ts.map +1 -1
- package/dist/src/utils/project-detection.js +19 -21
- package/dist/src/utils/project-detection.js.map +1 -1
- package/dist/src/utils/project-validator.d.ts.map +1 -1
- package/dist/src/utils/project-validator.js +5 -7
- package/dist/src/utils/project-validator.js.map +1 -1
- package/package.json +2 -3
- package/plugins/specweave/agents/tech-lead/AGENT.md +9 -0
- package/plugins/specweave/hooks/docs-changed.sh.backup +79 -0
- package/plugins/specweave/hooks/human-input-required.sh.backup +75 -0
- package/plugins/specweave/hooks/post-first-increment.sh.backup +61 -0
- package/plugins/specweave/hooks/post-increment-change.sh.backup +98 -0
- package/plugins/specweave/hooks/post-increment-completion.sh.backup +231 -0
- package/plugins/specweave/hooks/post-increment-planning.sh.backup +1048 -0
- package/plugins/specweave/hooks/post-increment-status-change.sh.backup +147 -0
- package/plugins/specweave/hooks/post-spec-update.sh.backup +158 -0
- package/plugins/specweave/hooks/post-user-story-complete.sh.backup +179 -0
- package/plugins/specweave/hooks/pre-command-deduplication.sh.backup +83 -0
- package/plugins/specweave/hooks/pre-implementation.sh.backup +67 -0
- package/plugins/specweave/hooks/pre-task-completion.sh.backup +194 -0
- package/plugins/specweave/hooks/pre-tool-use.sh.backup +133 -0
- package/plugins/specweave/hooks/user-prompt-submit.sh.backup +386 -0
- package/plugins/specweave/lib/vendor/core/increment/auto-transition-manager.d.ts +12 -0
- package/plugins/specweave/lib/vendor/core/increment/auto-transition-manager.js +45 -0
- package/plugins/specweave/lib/vendor/core/increment/auto-transition-manager.js.map +1 -1
- package/plugins/specweave/lib/vendor/core/increment/metadata-manager.js +46 -0
- package/plugins/specweave/lib/vendor/core/increment/metadata-manager.js.map +1 -1
- package/plugins/specweave/skills/increment-planner/SKILL.md +10 -5
- package/plugins/specweave/skills/specweave-framework/SKILL.md +6 -4
- package/plugins/specweave/templates/coding-standards.md.template +36 -0
- package/plugins/specweave-ado/hooks/post-living-docs-update.sh.backup +353 -0
- package/plugins/specweave-ado/hooks/post-task-completion.sh.backup +172 -0
- package/plugins/specweave-ado/lib/ado-multi-project-sync.js +1 -0
- package/plugins/specweave-ado/lib/enhanced-ado-sync.js +170 -0
- package/plugins/specweave-ado/lib/project-selector.js +56 -67
- package/plugins/specweave-ado/lib/project-selector.ts +72 -85
- package/plugins/specweave-github/hooks/.specweave/logs/hooks-debug.log +1104 -0
- package/plugins/specweave-github/hooks/post-task-completion.sh.backup +258 -0
- package/plugins/specweave-github/lib/repo-selector.js +55 -66
- package/plugins/specweave-github/lib/repo-selector.ts +73 -84
- package/plugins/specweave-jira/commands/import-projects.js +3 -5
- package/plugins/specweave-jira/commands/import-projects.ts +3 -5
- package/plugins/specweave-jira/hooks/post-task-completion.sh.backup +172 -0
- package/plugins/specweave-jira/lib/enhanced-jira-sync.js +3 -3
- package/plugins/specweave-jira/lib/project-selector.js +60 -71
- package/plugins/specweave-jira/lib/project-selector.ts +78 -91
- package/plugins/specweave-jira/lib/setup-wizard.js +51 -72
- package/plugins/specweave-jira/lib/setup-wizard.ts +56 -74
- package/plugins/specweave-release/hooks/.specweave/logs/dora-tracking.log +1017 -0
- package/plugins/specweave-release/hooks/post-task-completion.sh.backup +110 -0
- 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
|
-
**
|
|
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
|
|
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
|
-
- `
|
|
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
|