specweave 0.22.0 → 0.22.3

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 (220) hide show
  1. package/CLAUDE.md +373 -13
  2. package/README.md +5 -5
  3. package/bin/specweave.js +5 -8
  4. package/dist/plugins/specweave-github/lib/CodeValidator.d.ts +1 -1
  5. package/dist/plugins/specweave-github/lib/CodeValidator.js +1 -1
  6. package/dist/plugins/specweave-github/lib/github-client-v2.d.ts +10 -0
  7. package/dist/plugins/specweave-github/lib/github-client-v2.d.ts.map +1 -1
  8. package/dist/plugins/specweave-github/lib/github-client-v2.js +26 -0
  9. package/dist/plugins/specweave-github/lib/github-client-v2.js.map +1 -1
  10. package/dist/plugins/specweave-github/lib/task-sync.d.ts.map +1 -1
  11. package/dist/plugins/specweave-github/lib/task-sync.js +7 -0
  12. package/dist/plugins/specweave-github/lib/task-sync.js.map +1 -1
  13. package/dist/src/cli/commands/migrate-to-profiles.d.ts +1 -0
  14. package/dist/src/cli/commands/migrate-to-profiles.d.ts.map +1 -1
  15. package/dist/src/cli/commands/migrate-to-profiles.js +12 -1
  16. package/dist/src/cli/commands/migrate-to-profiles.js.map +1 -1
  17. package/dist/src/cli/commands/next-command.d.ts +52 -0
  18. package/dist/src/cli/commands/next-command.d.ts.map +1 -0
  19. package/dist/src/cli/commands/next-command.js +204 -0
  20. package/dist/src/cli/commands/next-command.js.map +1 -0
  21. package/dist/src/cli/commands/repair-status-desync.d.ts +69 -0
  22. package/dist/src/cli/commands/repair-status-desync.d.ts.map +1 -0
  23. package/dist/src/cli/commands/repair-status-desync.js +221 -0
  24. package/dist/src/cli/commands/repair-status-desync.js.map +1 -0
  25. package/dist/src/cli/commands/sync-specs.d.ts +16 -0
  26. package/dist/src/cli/commands/sync-specs.d.ts.map +1 -0
  27. package/dist/src/cli/commands/sync-specs.js +130 -0
  28. package/dist/src/cli/commands/sync-specs.js.map +1 -0
  29. package/dist/src/cli/commands/validate-status-sync.d.ts +52 -0
  30. package/dist/src/cli/commands/validate-status-sync.d.ts.map +1 -0
  31. package/dist/src/cli/commands/validate-status-sync.js +176 -0
  32. package/dist/src/cli/commands/validate-status-sync.js.map +1 -0
  33. package/dist/src/cli/count-tasks.d.ts +20 -0
  34. package/dist/src/cli/count-tasks.d.ts.map +1 -0
  35. package/dist/src/cli/count-tasks.js +50 -0
  36. package/dist/src/cli/count-tasks.js.map +1 -0
  37. package/dist/src/cli/update-status-line.d.ts +16 -0
  38. package/dist/src/cli/update-status-line.d.ts.map +1 -0
  39. package/dist/src/cli/update-status-line.js +44 -0
  40. package/dist/src/cli/update-status-line.js.map +1 -0
  41. package/dist/src/config/ConfigManager.d.ts.map +1 -1
  42. package/dist/src/config/ConfigManager.js +2 -1
  43. package/dist/src/config/ConfigManager.js.map +1 -1
  44. package/dist/src/config/types.d.ts +50 -50
  45. package/dist/src/core/cicd/state-manager.d.ts +8 -0
  46. package/dist/src/core/cicd/state-manager.d.ts.map +1 -1
  47. package/dist/src/core/cicd/state-manager.js +60 -15
  48. package/dist/src/core/cicd/state-manager.js.map +1 -1
  49. package/dist/src/core/cost-tracker.d.ts.map +1 -1
  50. package/dist/src/core/cost-tracker.js +2 -1
  51. package/dist/src/core/cost-tracker.js.map +1 -1
  52. package/dist/src/core/iac/template-engine.d.ts.map +1 -1
  53. package/dist/src/core/iac/template-engine.js +28 -0
  54. package/dist/src/core/iac/template-engine.js.map +1 -1
  55. package/dist/src/core/iac/template-generator.d.ts +53 -0
  56. package/dist/src/core/iac/template-generator.d.ts.map +1 -0
  57. package/dist/src/core/iac/template-generator.js +125 -0
  58. package/dist/src/core/iac/template-generator.js.map +1 -0
  59. package/dist/src/core/increment/completion-validator.d.ts +56 -0
  60. package/dist/src/core/increment/completion-validator.d.ts.map +1 -0
  61. package/dist/src/core/increment/completion-validator.js +102 -0
  62. package/dist/src/core/increment/completion-validator.js.map +1 -0
  63. package/dist/src/core/increment/metadata-manager.d.ts.map +1 -1
  64. package/dist/src/core/increment/metadata-manager.js +10 -0
  65. package/dist/src/core/increment/metadata-manager.js.map +1 -1
  66. package/dist/src/core/increment/spec-frontmatter-updater.d.ts +78 -0
  67. package/dist/src/core/increment/spec-frontmatter-updater.d.ts.map +1 -0
  68. package/dist/src/core/increment/spec-frontmatter-updater.js +152 -0
  69. package/dist/src/core/increment/spec-frontmatter-updater.js.map +1 -0
  70. package/dist/src/core/increment/status-auto-transition.js +3 -3
  71. package/dist/src/core/increment/status-auto-transition.js.map +1 -1
  72. package/dist/src/core/living-docs/CodeValidator.js +1 -1
  73. package/dist/src/core/living-docs/CodeValidator.js.map +1 -1
  74. package/dist/src/core/living-docs/content-distributor.d.ts.map +1 -1
  75. package/dist/src/core/living-docs/content-distributor.js +11 -1
  76. package/dist/src/core/living-docs/content-distributor.js.map +1 -1
  77. package/dist/src/core/living-docs/living-docs-sync.d.ts +166 -0
  78. package/dist/src/core/living-docs/living-docs-sync.d.ts.map +1 -0
  79. package/dist/src/core/living-docs/living-docs-sync.js +727 -0
  80. package/dist/src/core/living-docs/living-docs-sync.js.map +1 -0
  81. package/dist/src/core/living-docs/task-project-specific-generator.d.ts +7 -3
  82. package/dist/src/core/living-docs/task-project-specific-generator.d.ts.map +1 -1
  83. package/dist/src/core/living-docs/task-project-specific-generator.js +40 -24
  84. package/dist/src/core/living-docs/task-project-specific-generator.js.map +1 -1
  85. package/dist/src/core/plugin-loader.d.ts +7 -0
  86. package/dist/src/core/plugin-loader.d.ts.map +1 -1
  87. package/dist/src/core/plugin-loader.js +18 -1
  88. package/dist/src/core/plugin-loader.js.map +1 -1
  89. package/dist/src/core/serverless/platform-data-loader.d.ts +8 -0
  90. package/dist/src/core/serverless/platform-data-loader.d.ts.map +1 -1
  91. package/dist/src/core/serverless/platform-data-loader.js +14 -0
  92. package/dist/src/core/serverless/platform-data-loader.js.map +1 -1
  93. package/dist/src/core/serverless/types.d.ts +1 -1
  94. package/dist/src/core/serverless/types.d.ts.map +1 -1
  95. package/dist/src/core/status-line/status-line-manager.d.ts +7 -2
  96. package/dist/src/core/status-line/status-line-manager.d.ts.map +1 -1
  97. package/dist/src/core/status-line/status-line-manager.js +47 -18
  98. package/dist/src/core/status-line/status-line-manager.js.map +1 -1
  99. package/dist/src/core/status-line/status-line-updater.d.ts +67 -0
  100. package/dist/src/core/status-line/status-line-updater.d.ts.map +1 -0
  101. package/dist/src/core/status-line/status-line-updater.js +203 -0
  102. package/dist/src/core/status-line/status-line-updater.js.map +1 -0
  103. package/dist/src/core/status-line/task-counter.d.ts +69 -0
  104. package/dist/src/core/status-line/task-counter.d.ts.map +1 -0
  105. package/dist/src/core/status-line/task-counter.js +107 -0
  106. package/dist/src/core/status-line/task-counter.js.map +1 -0
  107. package/dist/src/core/status-line/types.d.ts +19 -5
  108. package/dist/src/core/status-line/types.d.ts.map +1 -1
  109. package/dist/src/core/status-line/types.js +3 -3
  110. package/dist/src/core/status-line/types.js.map +1 -1
  111. package/dist/src/core/workflow/autonomous-executor.d.ts +111 -0
  112. package/dist/src/core/workflow/autonomous-executor.d.ts.map +1 -0
  113. package/dist/src/core/workflow/autonomous-executor.js +275 -0
  114. package/dist/src/core/workflow/autonomous-executor.js.map +1 -0
  115. package/dist/src/core/workflow/backlog-scanner.d.ts +94 -0
  116. package/dist/src/core/workflow/backlog-scanner.d.ts.map +1 -0
  117. package/dist/src/core/workflow/backlog-scanner.js +170 -0
  118. package/dist/src/core/workflow/backlog-scanner.js.map +1 -0
  119. package/dist/src/core/workflow/command-invoker.d.ts +86 -0
  120. package/dist/src/core/workflow/command-invoker.d.ts.map +1 -0
  121. package/dist/src/core/workflow/command-invoker.js +131 -0
  122. package/dist/src/core/workflow/command-invoker.js.map +1 -0
  123. package/dist/src/core/workflow/cost-estimator.d.ts +120 -0
  124. package/dist/src/core/workflow/cost-estimator.d.ts.map +1 -0
  125. package/dist/src/core/workflow/cost-estimator.js +222 -0
  126. package/dist/src/core/workflow/cost-estimator.js.map +1 -0
  127. package/dist/src/core/workflow/index.d.ts +20 -0
  128. package/dist/src/core/workflow/index.d.ts.map +1 -0
  129. package/dist/src/core/workflow/index.js +24 -0
  130. package/dist/src/core/workflow/index.js.map +1 -0
  131. package/dist/src/core/workflow/state-manager.d.ts +107 -0
  132. package/dist/src/core/workflow/state-manager.d.ts.map +1 -0
  133. package/dist/src/core/workflow/state-manager.js +126 -0
  134. package/dist/src/core/workflow/state-manager.js.map +1 -0
  135. package/dist/src/core/workflow/workflow-orchestrator.d.ts +93 -0
  136. package/dist/src/core/workflow/workflow-orchestrator.d.ts.map +1 -0
  137. package/dist/src/core/workflow/workflow-orchestrator.js +195 -0
  138. package/dist/src/core/workflow/workflow-orchestrator.js.map +1 -0
  139. package/dist/src/init/architecture/types.d.ts +10 -10
  140. package/dist/src/metrics/dora-calculator.js +2 -2
  141. package/dist/src/metrics/dora-calculator.js.map +1 -1
  142. package/dist/src/utils/pricing-constants.d.ts +5 -2
  143. package/dist/src/utils/pricing-constants.d.ts.map +1 -1
  144. package/dist/src/utils/pricing-constants.js +3 -2
  145. package/dist/src/utils/pricing-constants.js.map +1 -1
  146. package/package.json +4 -4
  147. package/plugins/specweave/agents/infrastructure/AGENT.md +88 -46
  148. package/plugins/specweave/agents/pm/AGENT.md +58 -1
  149. package/plugins/specweave/commands/specweave-archive-features.md +1 -1
  150. package/plugins/specweave/commands/specweave-archive-increments.md +1 -1
  151. package/plugins/specweave/commands/specweave-check-hooks.md +5 -0
  152. package/plugins/specweave/commands/specweave-done.md +72 -4
  153. package/plugins/specweave/commands/specweave-plan.md +1 -1
  154. package/plugins/specweave/commands/specweave-progress.md +108 -379
  155. package/plugins/specweave/commands/specweave-reopen.md +30 -3
  156. package/plugins/specweave/commands/specweave-restore-feature.md +1 -1
  157. package/plugins/specweave/commands/specweave-sync-docs.md +71 -4
  158. package/plugins/specweave/commands/specweave-sync-specs.md +20 -48
  159. package/plugins/specweave/commands/specweave-update-status.md +151 -0
  160. package/plugins/specweave/hooks/lib/update-status-line.sh +78 -41
  161. package/plugins/specweave/hooks/lib/validate-spec-status.sh +163 -0
  162. package/plugins/specweave/hooks/user-prompt-submit.sh +38 -35
  163. package/plugins/specweave/hooks/validate-increment-completion.sh +113 -0
  164. package/plugins/specweave/lib/hooks/update-tasks-md.js +52 -9
  165. package/plugins/specweave/lib/hooks/update-tasks-md.ts +77 -16
  166. package/plugins/specweave/templates/iac/aws-lambda/defaults.json +24 -0
  167. package/plugins/specweave/templates/iac/aws-lambda/templates/README.md.hbs +260 -0
  168. package/plugins/specweave/templates/iac/aws-lambda/templates/environments/dev.tfvars.hbs +34 -0
  169. package/plugins/specweave/templates/iac/aws-lambda/templates/environments/prod.tfvars.hbs +37 -0
  170. package/plugins/specweave/templates/iac/aws-lambda/templates/environments/staging.tfvars.hbs +35 -0
  171. package/plugins/specweave/templates/iac/aws-lambda/templates/outputs.tf.hbs +77 -0
  172. package/plugins/specweave/templates/iac/aws-lambda/templates/providers.tf.hbs +36 -0
  173. package/plugins/specweave/templates/iac/aws-lambda/templates/variables.tf.hbs +115 -0
  174. package/plugins/specweave/templates/iac/azure-functions/defaults.json +25 -0
  175. package/plugins/specweave/templates/iac/azure-functions/templates/README.md.hbs +268 -0
  176. package/plugins/specweave/templates/iac/azure-functions/templates/environments/dev.tfvars.hbs +34 -0
  177. package/plugins/specweave/templates/iac/azure-functions/templates/environments/prod.tfvars.hbs +46 -0
  178. package/plugins/specweave/templates/iac/azure-functions/templates/environments/staging.tfvars.hbs +34 -0
  179. package/plugins/specweave/templates/iac/azure-functions/templates/main.tf.hbs +225 -0
  180. package/plugins/specweave/templates/iac/azure-functions/templates/outputs.tf.hbs +89 -0
  181. package/plugins/specweave/templates/iac/azure-functions/templates/provider.tf.hbs +27 -0
  182. package/plugins/specweave/templates/iac/azure-functions/templates/providers.tf.hbs +35 -0
  183. package/plugins/specweave/templates/iac/azure-functions/templates/variables.tf.hbs +124 -0
  184. package/plugins/specweave/templates/iac/firebase/defaults.json +29 -0
  185. package/plugins/specweave/templates/iac/firebase/templates/README.md.hbs +35 -0
  186. package/plugins/specweave/templates/iac/firebase/templates/environments/dev.tfvars.hbs +7 -0
  187. package/plugins/specweave/templates/iac/firebase/templates/environments/prod.tfvars.hbs +7 -0
  188. package/plugins/specweave/templates/iac/firebase/templates/environments/staging.tfvars.hbs +7 -0
  189. package/plugins/specweave/templates/iac/firebase/templates/main.tf.hbs +90 -0
  190. package/plugins/specweave/templates/iac/firebase/templates/outputs.tf.hbs +15 -0
  191. package/plugins/specweave/templates/iac/firebase/templates/providers.tf.hbs +23 -0
  192. package/plugins/specweave/templates/iac/firebase/templates/variables.tf.hbs +42 -0
  193. package/plugins/specweave/templates/iac/gcp-cloud-functions/defaults.json +26 -0
  194. package/plugins/specweave/templates/iac/gcp-cloud-functions/templates/README.md.hbs +299 -0
  195. package/plugins/specweave/templates/iac/gcp-cloud-functions/templates/environments/dev.tfvars.hbs +36 -0
  196. package/plugins/specweave/templates/iac/gcp-cloud-functions/templates/environments/prod.tfvars.hbs +48 -0
  197. package/plugins/specweave/templates/iac/gcp-cloud-functions/templates/environments/staging.tfvars.hbs +41 -0
  198. package/plugins/specweave/templates/iac/gcp-cloud-functions/templates/main.tf.hbs +192 -0
  199. package/plugins/specweave/templates/iac/gcp-cloud-functions/templates/outputs.tf.hbs +66 -0
  200. package/plugins/specweave/templates/iac/gcp-cloud-functions/templates/providers.tf.hbs +25 -0
  201. package/plugins/specweave/templates/iac/gcp-cloud-functions/templates/variables.tf.hbs +119 -0
  202. package/plugins/specweave/templates/iac/supabase/defaults.json +15 -0
  203. package/plugins/specweave/templates/iac/supabase/templates/README.md.hbs +46 -0
  204. package/plugins/specweave/templates/iac/supabase/templates/main.tf.hbs +50 -0
  205. package/plugins/specweave-ado/lib/ado-multi-project-sync.js +0 -1
  206. package/plugins/specweave-github/agents/github-manager/AGENT.md +39 -7
  207. package/plugins/specweave-github/commands/specweave-github-cleanup-duplicates.md +21 -0
  208. package/plugins/specweave-github/commands/specweave-github-create-issue.md +5 -5
  209. package/plugins/specweave-github/lib/CodeValidator.ts +1 -1
  210. package/plugins/specweave-github/lib/github-client-v2.js +29 -0
  211. package/plugins/specweave-github/lib/github-client-v2.ts +30 -0
  212. package/plugins/specweave-github/lib/task-sync.js +4 -0
  213. package/plugins/specweave-github/lib/task-sync.ts +7 -0
  214. package/src/templates/CLAUDE.md.template +31 -0
  215. package/dist/src/core/living-docs/ThreeLayerSyncManager.d.ts +0 -116
  216. package/dist/src/core/living-docs/ThreeLayerSyncManager.d.ts.map +0 -1
  217. package/dist/src/core/living-docs/ThreeLayerSyncManager.js +0 -356
  218. package/dist/src/core/living-docs/ThreeLayerSyncManager.js.map +0 -1
  219. package/plugins/specweave-ado/lib/enhanced-ado-sync.js +0 -170
  220. package/plugins/specweave-release/hooks/.specweave/logs/dora-tracking.log +0 -1200
@@ -1,11 +1,11 @@
1
1
  ---
2
2
  name: specweave:sync-specs
3
- description: Sync only specs folder to living docs - distributes increment specs into hierarchical user stories without updating architecture, operations, or other docs
3
+ description: Sync increment specifications to living docs structure. Auto-generates feature IDs for greenfield increments (FS-XXX). Use after completing an increment to make it visible in living docs.
4
4
  ---
5
5
 
6
- # Sync Specs Only
6
+ # Sync Increment Specifications to Living Docs
7
7
 
8
- You are executing the SpecWeave specs-only sync command. This distributes increment specs specifically into the living docs specs folder using the Universal Hierarchy (Epic Feature → User Story → Task), without touching other documentation areas.
8
+ Syncs increment specs to living docs structure for stakeholder visibility. Auto-generates feature IDs for greenfield increments.
9
9
 
10
10
  ---
11
11
 
@@ -85,58 +85,30 @@ fi
85
85
 
86
86
  ---
87
87
 
88
- ## STEP 3: Execute Spec Distribution
88
+ ## STEP 3: Execute Spec Sync
89
89
 
90
- ### 3.1 Run SpecDistributor
90
+ ### 3.1 Run Sync Command
91
91
 
92
- **Execute the distribution using Node.js**:
92
+ **Execute the sync using the CLI command**:
93
93
 
94
- ```javascript
95
- // Direct execution via Node.js
96
- node -e "
97
- import('./dist/src/core/living-docs/spec-distributor.js').then(async ({ SpecDistributor }) => {
98
- const distributor = new SpecDistributor(process.cwd());
94
+ ```typescript
95
+ import { syncSpecs } from './dist/src/cli/commands/sync-specs.js';
99
96
 
100
- console.log('🚀 Starting spec distribution...');
101
- console.log(' 📄 Reading spec.md from increment ${INCREMENT_ID}');
97
+ // Parse arguments
98
+ const args = process.argv.slice(2); // e.g., ['0040', '--dry-run']
102
99
 
103
- try {
104
- const result = await distributor.distribute('${INCREMENT_ID}');
105
-
106
- console.log('');
107
- console.log('✅ Distribution successful!');
108
- console.log(' 📊 Total stories: ' + result.totalStories);
109
- console.log(' 📁 Total files created: ' + result.totalFiles);
110
- console.log(' 🎯 Feature ID: ' + result.specId);
111
-
112
- if (result.epicPath) {
113
- console.log(' 📂 Feature path: ' + result.epicPath);
114
- }
115
-
116
- if (result.userStoryPaths && result.userStoryPaths.length > 0) {
117
- console.log(' 📝 User stories created:');
118
- result.userStoryPaths.forEach(p => console.log(' • ' + p));
119
- }
120
-
121
- if (result.warnings && result.warnings.length > 0) {
122
- console.log('');
123
- console.log('⚠️ Warnings:');
124
- result.warnings.forEach(w => console.log(' • ' + w));
125
- }
126
-
127
- // Update acceptance criteria status based on completed tasks
128
- console.log('');
129
- console.log('📊 Updating acceptance criteria status...');
130
- await distributor.updateAcceptanceCriteriaStatus('${INCREMENT_ID}');
131
-
132
- } catch (error) {
133
- console.error('❌ Distribution failed:', error.message);
134
- process.exit(1);
135
- }
136
- });
137
- "
100
+ // Execute sync
101
+ await syncSpecs(args);
138
102
  ```
139
103
 
104
+ **This will**:
105
+ 1. Auto-generate feature ID for greenfield increments (FS-040, FS-041, etc.)
106
+ 2. Parse spec.md for user stories and acceptance criteria
107
+ 3. Create living docs structure:
108
+ - `.specweave/docs/internal/specs/_features/FS-XXX/FEATURE.md`
109
+ - `.specweave/docs/internal/specs/specweave/FS-XXX/README.md`
110
+ - `.specweave/docs/internal/specs/specweave/FS-XXX/us-*.md`
111
+
140
112
  ---
141
113
 
142
114
  ## STEP 4: Report Distribution Results
@@ -0,0 +1,151 @@
1
+ ---
2
+ name: specweave:update-status
3
+ description: Force-update status line cache with latest increment status
4
+ ---
5
+
6
+ # Update Status Line
7
+
8
+ **Purpose**: Force-refresh status line cache when it appears stale or after making changes.
9
+
10
+ **Use When**:
11
+ - Status line doesn't reflect recent changes
12
+ - After completing tasks (want to see updated progress immediately)
13
+ - After status transitions (active → completed)
14
+ - Before checking progress with `/specweave:progress`
15
+ - When status line shows outdated information
16
+
17
+ ---
18
+
19
+ ## How It Works
20
+
21
+ 1. **Scan All Increments**
22
+ - Reads all spec.md files in `.specweave/increments/`
23
+ - Identifies open increments (status = active/planning/in-progress)
24
+ - Extracts creation dates from YAML frontmatter
25
+
26
+ 2. **Select Current Increment**
27
+ - Sorts by creation date (oldest first)
28
+ - Takes first as current active increment
29
+ - Counts total open increments
30
+
31
+ 3. **Parse Task Progress**
32
+ - Reads tasks.md from current increment
33
+ - Uses TaskCounter for accurate counting (no overcounting)
34
+ - Calculates: completed, total, percentage
35
+
36
+ 4. **Update Cache**
37
+ - Writes `.specweave/state/status-line.json`
38
+ - Atomic write (temp file → rename)
39
+ - Runs SYNCHRONOUSLY (user waits ~50-100ms)
40
+
41
+ ---
42
+
43
+ ## Usage
44
+
45
+ ```bash
46
+ # Force-update status line (no arguments)
47
+ /specweave:update-status
48
+ ```
49
+
50
+ **Output**:
51
+ ```
52
+ ✓ Status line cache updated
53
+ ```
54
+
55
+ ---
56
+
57
+ ## Example
58
+
59
+ **Before Update** (stale cache):
60
+ ```
61
+ Status Line: [0043] ████░░░░ 5/8 tasks (2 open)
62
+ ```
63
+
64
+ **After Update** (fresh cache):
65
+ ```
66
+ Status Line: [0043] ████████ 8/8 tasks (1 open) ✓
67
+ ```
68
+
69
+ ---
70
+
71
+ ## Integration with Other Commands
72
+
73
+ This command is automatically called by:
74
+
75
+ 1. **`/specweave:progress`**
76
+ - Ensures status line is fresh before showing progress
77
+ - User always sees accurate completion percentages
78
+
79
+ 2. **`/specweave:done`**
80
+ - Refreshes status line before PM validation
81
+ - Ensures final progress is accurate
82
+
83
+ 3. **`/specweave:status`**
84
+ - Updates cache before showing increment list
85
+ - Shows current increment status
86
+
87
+ ---
88
+
89
+ ## Technical Details
90
+
91
+ **Performance**: ~50-100ms (synchronous execution)
92
+
93
+ **Cache Location**: `.specweave/state/status-line.json`
94
+
95
+ **Cache Format**:
96
+ ```json
97
+ {
98
+ "current": {
99
+ "id": "0043-spec-md-desync-fix",
100
+ "name": "0043-spec-md-desync-fix",
101
+ "completed": 8,
102
+ "total": 8,
103
+ "percentage": 100
104
+ },
105
+ "openCount": 1,
106
+ "lastUpdate": "2025-11-18T15:30:00Z"
107
+ }
108
+ ```
109
+
110
+ **Source of Truth**:
111
+ - Increment status: `spec.md` YAML frontmatter (NOT metadata.json)
112
+ - Task progress: `tasks.md` (TaskCounter for accuracy)
113
+
114
+ **Atomicity**: Uses temp file → rename pattern to prevent cache corruption
115
+
116
+ ---
117
+
118
+ ## Troubleshooting
119
+
120
+ **Status line still stale after update?**
121
+ 1. Check if `.specweave/state/status-line.json` was modified
122
+ 2. Verify spec.md has correct status in YAML frontmatter
123
+ 3. Check tasks.md has proper task format (## T-001, etc.)
124
+
125
+ **Error: "Failed to update status line"**
126
+ - Ensure `.specweave/increments/` exists
127
+ - Check file permissions on `.specweave/state/`
128
+ - Verify spec.md has valid YAML frontmatter
129
+
130
+ **Cache shows wrong increment?**
131
+ - Status line shows oldest active increment by default
132
+ - Complete older increments first
133
+ - Or check `created` date in spec.md frontmatter
134
+
135
+ ---
136
+
137
+ ## Implementation
138
+
139
+ **CLI**: `src/cli/update-status-line.ts`
140
+ **Core Logic**: `src/core/status-line/status-line-updater.ts`
141
+ **Hook (async)**: `plugins/specweave/hooks/lib/update-status-line.sh`
142
+
143
+ **Difference from Hook**:
144
+ - **Command**: SYNCHRONOUS (user waits, sees immediate result)
145
+ - **Hook**: ASYNCHRONOUS (background refresh, no blocking)
146
+
147
+ Both use same logic, different execution model.
148
+
149
+ ---
150
+
151
+ **This command ensures status line is ALWAYS fresh when you need it!** ✓
@@ -1,16 +1,17 @@
1
1
  #!/usr/bin/env bash
2
2
  #
3
- # update-status-line.sh (Simplified)
3
+ # update-status-line.sh (Enhanced with AC Metrics)
4
4
  #
5
5
  # Updates status line cache with current increment progress.
6
- # Shows: [increment-name] ████░░░░ X/Y tasks (Z open)
6
+ # Shows: [increment-name] ████░░░░ X/Y tasks | A/B ACs (Z open)
7
7
  #
8
8
  # Logic:
9
- # 1. Scan all metadata.json for status=active/in-progress/planning
9
+ # 1. Scan all spec.md for status=active/planning (SOURCE OF TRUTH!)
10
10
  # 2. Take first (oldest) as current increment
11
- # 3. Count all active/in-progress/planning as openCount
12
- # 4. Parse current increment's tasks.md for progress
13
- # 5. Write to cache
11
+ # 3. Count all active/planning as openCount
12
+ # 4. Parse current increment's tasks.md for task progress
13
+ # 5. Parse current increment's spec.md for AC progress
14
+ # 6. Write to cache
14
15
  #
15
16
  # Performance: 50-100ms (runs async, user doesn't wait)
16
17
 
@@ -37,19 +38,24 @@ TMP_FILE="$PROJECT_ROOT/.specweave/state/.status-line-tmp.txt"
37
38
  # Ensure state directory exists
38
39
  mkdir -p "$PROJECT_ROOT/.specweave/state"
39
40
 
40
- # Step 1: Find all open increments (active/in-progress/planning)
41
+ # Step 1: Find all open increments (active/planning)
42
+ # Read from spec.md (source of truth), not metadata.json
43
+ # ONLY accepts official IncrementStatus enum values
41
44
  # Write to temp file: "timestamp increment_id"
42
45
  > "$TMP_FILE"
43
46
 
44
47
  if [[ -d "$INCREMENTS_DIR" ]]; then
45
- for metadata in "$INCREMENTS_DIR"/*/metadata.json; do
46
- if [[ -f "$metadata" ]]; then
47
- status=$(jq -r '.status // ""' "$metadata" 2>/dev/null || echo "")
48
-
49
- # Check if increment is open (active, in-progress, or planning)
50
- if [[ "$status" == "active" ]] || [[ "$status" == "in-progress" ]] || [[ "$status" == "planning" ]]; then
51
- increment_id=$(basename "$(dirname "$metadata")")
52
- created=$(jq -r '.created // ""' "$metadata" 2>/dev/null || echo "1970-01-01T00:00:00Z")
48
+ for spec_file in "$INCREMENTS_DIR"/*/spec.md; do
49
+ if [[ -f "$spec_file" ]]; then
50
+ # Parse YAML frontmatter for status (source of truth)
51
+ status=$(grep -m1 "^status:" "$spec_file" 2>/dev/null | cut -d: -f2 | tr -d ' ' || echo "")
52
+
53
+ # Check if increment is open (active, planning, or in-progress)
54
+ # ONLY accepts official IncrementStatus enum values
55
+ if [[ "$status" == "active" ]] || [[ "$status" == "planning" ]] || [[ "$status" == "in-progress" ]]; then
56
+ increment_id=$(basename "$(dirname "$spec_file")")
57
+ # Parse created date from spec.md YAML frontmatter
58
+ created=$(grep -m1 "^created:" "$spec_file" 2>/dev/null | cut -d: -f2- | tr -d ' ' || echo "1970-01-01")
53
59
 
54
60
  # Write to temp file
55
61
  echo "$created $increment_id" >> "$TMP_FILE"
@@ -85,41 +91,70 @@ COMPLETED_TASKS=0
85
91
  PERCENTAGE=0
86
92
 
87
93
  if [[ -f "$TASKS_FILE" ]]; then
88
- # Count total tasks (## T- or ### T- headings)
89
- TOTAL_TASKS=$(grep -cE '^##+ T-' "$TASKS_FILE" 2>/dev/null || echo 0)
90
- TOTAL_TASKS=$(echo "$TOTAL_TASKS" | tr -d '\n\r ' || echo 0)
91
-
92
- # Count completed tasks (multiple formats)
93
- # Format 1: [x] at line start (legacy)
94
- COMPLETED_STANDARD=$(grep -c '^\[x\]' "$TASKS_FILE" 2>/dev/null || echo 0)
95
- COMPLETED_STANDARD=$(echo "$COMPLETED_STANDARD" | tr -d '\n\r ' || echo 0)
96
-
97
- # Format 2: **Status**: [x] inline (legacy)
98
- COMPLETED_INLINE=$(grep -c '\*\*Status\*\*: \[x\]' "$TASKS_FILE" 2>/dev/null || echo 0)
99
- COMPLETED_INLINE=$(echo "$COMPLETED_INLINE" | tr -d '\n\r ' || echo 0)
100
-
101
- # Format 3: **Completed**: <date> (current format)
102
- COMPLETED_DATE=$(grep -c '\*\*Completed\*\*:' "$TASKS_FILE" 2>/dev/null || echo 0)
103
- COMPLETED_DATE=$(echo "$COMPLETED_DATE" | tr -d '\n\r ' || echo 0)
104
-
105
- COMPLETED_TASKS=$((COMPLETED_STANDARD + COMPLETED_INLINE + COMPLETED_DATE))
106
-
107
- # Calculate percentage
108
- if [[ $TOTAL_TASKS -gt 0 ]]; then
109
- PERCENTAGE=$((COMPLETED_TASKS * 100 / TOTAL_TASKS))
94
+ # Use TaskCounter CLI for accurate counting (fixes overcounting bug)
95
+ COUNT_TASKS_CLI="$PROJECT_ROOT/dist/src/cli/count-tasks.js"
96
+
97
+ if [[ -f "$COUNT_TASKS_CLI" ]]; then
98
+ # Call CLI and parse JSON output
99
+ TASK_COUNTS=$(node "$COUNT_TASKS_CLI" "$TASKS_FILE" 2>/dev/null || echo '{"total":0,"completed":0,"percentage":0}')
100
+ TOTAL_TASKS=$(echo "$TASK_COUNTS" | jq -r '.total' 2>/dev/null || echo 0)
101
+ COMPLETED_TASKS=$(echo "$TASK_COUNTS" | jq -r '.completed' 2>/dev/null || echo 0)
102
+ PERCENTAGE=$(echo "$TASK_COUNTS" | jq -r '.percentage' 2>/dev/null || echo 0)
103
+ else
104
+ # Fallback to legacy counting if CLI not available (graceful degradation)
105
+ # Count total tasks (## T- or ### T- headings)
106
+ TOTAL_TASKS=$(grep -cE '^##+ T-' "$TASKS_FILE" 2>/dev/null || echo 0)
107
+ TOTAL_TASKS=$(echo "$TOTAL_TASKS" | tr -d '\n\r ' || echo 0)
108
+
109
+ # Count completed tasks - use most reliable single marker (**Completed**: format)
110
+ COMPLETED_TASKS=$(grep -c '\*\*Completed\*\*:' "$TASKS_FILE" 2>/dev/null || echo 0)
111
+ COMPLETED_TASKS=$(echo "$COMPLETED_TASKS" | tr -d '\n\r ' || echo 0)
112
+
113
+ # Calculate percentage
114
+ if [[ $TOTAL_TASKS -gt 0 ]]; then
115
+ PERCENTAGE=$((COMPLETED_TASKS * 100 / TOTAL_TASKS))
116
+ fi
110
117
  fi
111
118
  fi
112
119
 
113
- # Step 5: Extract increment name (remove 4-digit prefix)
114
- INCREMENT_NAME=$(echo "$CURRENT_INCREMENT" | sed 's/^[0-9]\{4\}-//')
120
+ # Step 4b: Parse spec.md for AC (Acceptance Criteria) progress
121
+ SPEC_FILE="$INCREMENTS_DIR/$CURRENT_INCREMENT/spec.md"
122
+ TOTAL_ACS=0
123
+ COMPLETED_ACS=0
124
+ OPEN_ACS=0
125
+
126
+ if [[ -f "$SPEC_FILE" ]]; then
127
+ # Count total ACs: both checked and unchecked
128
+ # Pattern: - [ ] **AC- OR - [x] **AC-
129
+ TOTAL_ACS=$(grep -cE '^- \[(x| )\] \*\*AC-' "$SPEC_FILE" 2>/dev/null || echo 0)
130
+ TOTAL_ACS=$(echo "$TOTAL_ACS" | tr -d '\n\r ' || echo 0)
131
+
132
+ # Count completed ACs (checked)
133
+ # Pattern: - [x] **AC-
134
+ COMPLETED_ACS=$(grep -cE '^- \[x\] \*\*AC-' "$SPEC_FILE" 2>/dev/null || echo 0)
135
+ COMPLETED_ACS=$(echo "$COMPLETED_ACS" | tr -d '\n\r ' || echo 0)
136
+
137
+ # Count open ACs (unchecked)
138
+ # Pattern: - [ ] **AC-
139
+ OPEN_ACS=$(grep -cE '^- \[ \] \*\*AC-' "$SPEC_FILE" 2>/dev/null || echo 0)
140
+ OPEN_ACS=$(echo "$OPEN_ACS" | tr -d '\n\r ' || echo 0)
141
+ fi
142
+
143
+ # Step 5: Extract increment ID and name
144
+ # Format: XXXX-name where XXXX is 4-digit prefix (brackets added by manager)
145
+ INCREMENT_ID=$(echo "$CURRENT_INCREMENT" | grep -oE '^[0-9]{4}')
146
+ INCREMENT_NAME_ONLY=$(echo "$CURRENT_INCREMENT" | sed 's/^[0-9]\{4\}-//')
147
+ INCREMENT_NAME="$INCREMENT_ID-$INCREMENT_NAME_ONLY"
115
148
 
116
- # Step 6: Write cache
149
+ # Step 6: Write cache (now includes AC metrics)
117
150
  jq -n \
118
151
  --arg id "$CURRENT_INCREMENT" \
119
152
  --arg name "$INCREMENT_NAME" \
120
153
  --argjson completed "$COMPLETED_TASKS" \
121
154
  --argjson total "$TOTAL_TASKS" \
122
155
  --argjson percentage "$PERCENTAGE" \
156
+ --argjson acsCompleted "$COMPLETED_ACS" \
157
+ --argjson acsTotal "$TOTAL_ACS" \
123
158
  --argjson openCount "$OPEN_COUNT" \
124
159
  '{
125
160
  current: {
@@ -127,7 +162,9 @@ jq -n \
127
162
  name: $name,
128
163
  completed: $completed,
129
164
  total: $total,
130
- percentage: $percentage
165
+ percentage: $percentage,
166
+ acsCompleted: $acsCompleted,
167
+ acsTotal: $acsTotal
131
168
  },
132
169
  openCount: $openCount,
133
170
  lastUpdate: (now | strftime("%Y-%m-%dT%H:%M:%SZ"))
@@ -0,0 +1,163 @@
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 -euo pipefail
20
+
21
+ # Find project root
22
+ find_project_root() {
23
+ local dir="$PWD"
24
+ while [[ "$dir" != "/" ]]; do
25
+ if [[ -d "$dir/.specweave" ]]; then
26
+ echo "$dir"
27
+ return 0
28
+ fi
29
+ dir=$(dirname "$dir")
30
+ done
31
+ echo "$PWD"
32
+ }
33
+
34
+ PROJECT_ROOT=$(find_project_root)
35
+ INCREMENTS_DIR="$PROJECT_ROOT/.specweave/increments"
36
+
37
+ # Valid IncrementStatus enum values (from src/core/types/increment-metadata.ts)
38
+ VALID_STATUSES=("planning" "active" "backlog" "paused" "completed" "abandoned")
39
+
40
+ # Get suggested correction for invalid status
41
+ get_correction() {
42
+ local status="$1"
43
+ case "$status" in
44
+ "planned") echo "planning" ;;
45
+ "in-progress"|"in_progress") echo "active" ;;
46
+ "done") echo "completed" ;;
47
+ "cancelled"|"canceled") echo "abandoned" ;;
48
+ *) echo "" ;;
49
+ esac
50
+ }
51
+
52
+ # Validate a single spec file
53
+ validate_spec() {
54
+ local spec_file="$1"
55
+ local increment_id=$(basename "$(dirname "$spec_file")")
56
+
57
+ if [[ ! -f "$spec_file" ]]; then
58
+ echo "❌ Error: spec.md not found for increment $increment_id"
59
+ return 2
60
+ fi
61
+
62
+ # Extract status from YAML frontmatter
63
+ local status=$(grep -m1 "^status:" "$spec_file" 2>/dev/null | cut -d: -f2 | tr -d ' "' || echo "")
64
+
65
+ if [[ -z "$status" ]]; then
66
+ echo "⚠️ Warning: No status field in $increment_id/spec.md"
67
+ return 0 # Not an error, just a warning
68
+ fi
69
+
70
+ # Check if status is valid
71
+ local is_valid=0
72
+ for valid_status in "${VALID_STATUSES[@]}"; do
73
+ if [[ "$status" == "$valid_status" ]]; then
74
+ is_valid=1
75
+ break
76
+ fi
77
+ done
78
+
79
+ if [[ $is_valid -eq 1 ]]; then
80
+ echo "✅ $increment_id: status '$status' is valid"
81
+ return 0
82
+ else
83
+ # Invalid status found - suggest correction
84
+ echo ""
85
+ echo "❌ Invalid status in $increment_id/spec.md"
86
+ echo " Found: '$status'"
87
+ echo ""
88
+
89
+ # Check if we have a suggested correction
90
+ local correction=$(get_correction "$status")
91
+ if [[ -n "$correction" ]]; then
92
+ echo " 💡 Did you mean: '$correction'?"
93
+ echo ""
94
+ echo " Fix:"
95
+ echo " sed -i '' 's/^status: $status/status: $correction/' $spec_file"
96
+ else
97
+ echo " Valid statuses: ${VALID_STATUSES[*]}"
98
+ fi
99
+ echo ""
100
+
101
+ return 1
102
+ fi
103
+ }
104
+
105
+ # Validate all increments
106
+ validate_all() {
107
+ local exit_code=0
108
+ local total=0
109
+ local valid=0
110
+ local invalid=0
111
+
112
+ echo "Validating all increments in $INCREMENTS_DIR"
113
+ echo ""
114
+
115
+ for spec_file in "$INCREMENTS_DIR"/*/spec.md; do
116
+ if [[ -f "$spec_file" ]]; then
117
+ total=$((total + 1))
118
+ if validate_spec "$spec_file"; then
119
+ valid=$((valid + 1))
120
+ else
121
+ invalid=$((invalid + 1))
122
+ exit_code=1
123
+ fi
124
+ fi
125
+ done
126
+
127
+ echo ""
128
+ echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
129
+ echo "Summary: $total increments checked"
130
+ echo " ✅ Valid: $valid"
131
+ echo " ❌ Invalid: $invalid"
132
+ echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
133
+
134
+ if [[ $invalid -gt 0 ]]; then
135
+ echo ""
136
+ echo "⚠️ Please fix invalid status values to use official IncrementStatus enum."
137
+ echo ""
138
+ echo "Valid statuses:"
139
+ for status in "${VALID_STATUSES[@]}"; do
140
+ echo " - $status"
141
+ done
142
+ fi
143
+
144
+ return $exit_code
145
+ }
146
+
147
+ # Main logic
148
+ if [[ $# -eq 0 ]]; then
149
+ echo "Usage: $0 <increment-id> | --all"
150
+ echo ""
151
+ echo "Examples:"
152
+ echo " $0 0042-test-infrastructure-cleanup"
153
+ echo " $0 --all"
154
+ exit 2
155
+ fi
156
+
157
+ if [[ "$1" == "--all" ]]; then
158
+ validate_all
159
+ else
160
+ INCREMENT_ID="$1"
161
+ SPEC_FILE="$INCREMENTS_DIR/$INCREMENT_ID/spec.md"
162
+ validate_spec "$SPEC_FILE"
163
+ fi
@@ -303,44 +303,26 @@ if [[ -d ".specweave/increments" ]]; then
303
303
  done)
304
304
 
305
305
  if [[ -n "$ACTIVE_INCREMENT" ]]; then
306
- # Use status line cache for consistent display
307
- STATUS_LINE_CACHE=".specweave/state/status-line.json"
308
- if [[ -f "$STATUS_LINE_CACHE" ]]; then
309
- # Get status line from cache (ultra-fast)
310
- STATUS_LINE=$(node -e "
311
- try {
312
- const { StatusLineManager } = require('./dist/src/core/status-line/status-line-manager.js');
313
- const manager = new StatusLineManager(process.cwd());
314
- const result = manager.render();
315
- console.log(result || '');
316
- } catch (e) {
317
- // Fallback: show increment name only
318
- console.log('');
319
- }
320
- " 2>/dev/null || echo "")
321
-
322
- if [[ -n "$STATUS_LINE" ]]; then
323
- CONTEXT="✓ $STATUS_LINE"
306
+ # Simple status: parse tasks.md for completion
307
+ TASKS_FILE=".specweave/increments/$ACTIVE_INCREMENT/tasks.md"
308
+ if [[ -f "$TASKS_FILE" ]]; then
309
+ # Count tasks (headers with T-NNN format - both ### and ####)
310
+ TOTAL_TASKS=$(grep -cE '^#{3,4}\s*T-[0-9]' "$TASKS_FILE" 2>/dev/null | tr -d '\n' || echo "0")
311
+ # Count completed (various formats)
312
+ COMPLETED_TASKS=$(grep -cE '(✅ COMPLETE|\[COMPLETED\]|\[x\] Completed)' "$TASKS_FILE" 2>/dev/null | tr -d '\n' || echo "0")
313
+
314
+ # Ensure valid numbers
315
+ TOTAL_TASKS=${TOTAL_TASKS:-0}
316
+ COMPLETED_TASKS=${COMPLETED_TASKS:-0}
317
+
318
+ if [[ "$TOTAL_TASKS" -gt 0 ]] 2>/dev/null; then
319
+ PERCENTAGE=$(( COMPLETED_TASKS * 100 / TOTAL_TASKS ))
320
+ CONTEXT=" Active: $ACTIVE_INCREMENT ($COMPLETED_TASKS/$TOTAL_TASKS tasks, $PERCENTAGE%)"
324
321
  else
325
- # Fallback: parse tasks.md manually
326
- TASKS_FILE=".specweave/increments/$ACTIVE_INCREMENT/tasks.md"
327
- if [[ -f "$TASKS_FILE" ]]; then
328
- TASK_STATS=$(grep -E "^\s*-\s*\[[ x]\]" "$TASKS_FILE" 2>/dev/null | wc -l | xargs || echo "0")
329
- COMPLETED_TASKS=$(grep -E "^\s*-\s*\[x\]" "$TASKS_FILE" 2>/dev/null | wc -l | xargs || echo "0")
330
-
331
- if [[ "$TASK_STATS" -gt 0 ]]; then
332
- PERCENTAGE=$(( COMPLETED_TASKS * 100 / TASK_STATS ))
333
- CONTEXT="✓ Active Increment: $ACTIVE_INCREMENT ($PERCENTAGE% complete, $COMPLETED_TASKS/$TASK_STATS tasks)"
334
- else
335
- CONTEXT="✓ Active Increment: $ACTIVE_INCREMENT"
336
- fi
337
- else
338
- CONTEXT="✓ Active Increment: $ACTIVE_INCREMENT"
339
- fi
322
+ CONTEXT="✓ Active: $ACTIVE_INCREMENT"
340
323
  fi
341
324
  else
342
- # No cache, fall back to increment name only
343
- CONTEXT="✓ Active Increment: $ACTIVE_INCREMENT"
325
+ CONTEXT="✓ Active: $ACTIVE_INCREMENT"
344
326
  fi
345
327
  fi
346
328
  fi
@@ -360,6 +342,27 @@ if echo "$PROMPT" | grep -qiE "(add|create|implement|build|develop)" && ! echo "
360
342
  fi
361
343
  fi
362
344
 
345
+ # ==============================================================================
346
+ # STATUS LINE REFRESH: Ensure cache is fresh before showing context
347
+ # ==============================================================================
348
+ # Performance: ~50-100ms (acceptable for UX)
349
+ # Frequency: Every user prompt (high coverage)
350
+ # Benefit: Catches ALL edge cases (manual edits, resume, direct changes)
351
+ #
352
+ # Why here? This hook runs on EVERY user prompt, ensuring status line
353
+ # is ALWAYS up-to-date before showing context to the user.
354
+ #
355
+ # Prevents desync scenarios:
356
+ # - Manual spec.md edits (status: planning → active)
357
+ # - /specweave:resume (status: paused → active)
358
+ # - Direct metadata changes (without hook triggers)
359
+ # - File system operations bypassing hooks
360
+ #
361
+ # Background execution: Runs async, doesn't block user prompt
362
+
363
+ HOOK_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
364
+ bash "$HOOK_DIR/lib/update-status-line.sh" 2>/dev/null || true
365
+
363
366
  # ==============================================================================
364
367
  # OUTPUT: Approve with context or no context
365
368
  # ==============================================================================