specweave 0.22.13 → 0.22.14

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 (188) hide show
  1. package/.claude-plugin/README.md +2 -2
  2. package/CLAUDE.md +269 -51
  3. package/README.md +33 -10
  4. package/dist/plugins/specweave-github/lib/ThreeLayerSyncManager.d.ts +1 -1
  5. package/dist/plugins/specweave-github/lib/ThreeLayerSyncManager.js +1 -1
  6. package/dist/plugins/specweave-github/lib/enhanced-github-sync.js +1 -1
  7. package/dist/plugins/specweave-github/lib/enhanced-github-sync.js.map +1 -1
  8. package/dist/plugins/specweave-github/lib/github-spec-content-sync.d.ts.map +1 -1
  9. package/dist/plugins/specweave-github/lib/github-spec-content-sync.js +4 -1
  10. package/dist/plugins/specweave-github/lib/github-spec-content-sync.js.map +1 -1
  11. package/dist/plugins/specweave-github/lib/github-spec-sync.d.ts +1 -1
  12. package/dist/plugins/specweave-github/lib/github-spec-sync.js +1 -1
  13. package/dist/plugins/specweave-github/lib/github-sync-bidirectional.d.ts +9 -0
  14. package/dist/plugins/specweave-github/lib/github-sync-bidirectional.d.ts.map +1 -1
  15. package/dist/plugins/specweave-github/lib/github-sync-bidirectional.js +10 -1
  16. package/dist/plugins/specweave-github/lib/github-sync-bidirectional.js.map +1 -1
  17. package/dist/plugins/specweave-github/lib/progress-comment-builder.js +2 -2
  18. package/dist/plugins/specweave-github/lib/progress-comment-builder.js.map +1 -1
  19. package/dist/plugins/specweave-github/lib/types.d.ts +1 -1
  20. package/dist/src/cli/commands/init.d.ts.map +1 -1
  21. package/dist/src/cli/commands/init.js +313 -1
  22. package/dist/src/cli/commands/init.js.map +1 -1
  23. package/dist/src/cli/helpers/issue-tracker/index.d.ts.map +1 -1
  24. package/dist/src/cli/helpers/issue-tracker/index.js +41 -24
  25. package/dist/src/cli/helpers/issue-tracker/index.js.map +1 -1
  26. package/dist/src/config/import-config.d.ts +69 -0
  27. package/dist/src/config/import-config.d.ts.map +1 -0
  28. package/dist/src/config/import-config.js +136 -0
  29. package/dist/src/config/import-config.js.map +1 -0
  30. package/dist/src/config/types.d.ts +10 -10
  31. package/dist/src/core/living-docs/living-docs-sync.d.ts +2 -0
  32. package/dist/src/core/living-docs/living-docs-sync.d.ts.map +1 -1
  33. package/dist/src/core/living-docs/living-docs-sync.js +10 -1
  34. package/dist/src/core/living-docs/living-docs-sync.js.map +1 -1
  35. package/dist/src/core/living-docs/task-project-specific-generator.d.ts +2 -2
  36. package/dist/src/core/living-docs/task-project-specific-generator.js +2 -2
  37. package/dist/src/core/repo-structure/prompt-consolidator.d.ts +2 -2
  38. package/dist/src/core/repo-structure/prompt-consolidator.d.ts.map +1 -1
  39. package/dist/src/core/repo-structure/prompt-consolidator.js +3 -15
  40. package/dist/src/core/repo-structure/prompt-consolidator.js.map +1 -1
  41. package/dist/src/core/repo-structure/repo-structure-manager.d.ts +1 -1
  42. package/dist/src/core/repo-structure/repo-structure-manager.d.ts.map +1 -1
  43. package/dist/src/core/repo-structure/repo-structure-manager.js +3 -6
  44. package/dist/src/core/repo-structure/repo-structure-manager.js.map +1 -1
  45. package/dist/src/core/spec-content-sync.d.ts +4 -1
  46. package/dist/src/core/spec-content-sync.d.ts.map +1 -1
  47. package/dist/src/core/spec-content-sync.js +139 -4
  48. package/dist/src/core/spec-content-sync.js.map +1 -1
  49. package/dist/src/core/spec-task-mapper.d.ts.map +1 -1
  50. package/dist/src/core/spec-task-mapper.js +9 -8
  51. package/dist/src/core/spec-task-mapper.js.map +1 -1
  52. package/dist/src/core/status-line-validator.d.ts +63 -0
  53. package/dist/src/core/status-line-validator.d.ts.map +1 -0
  54. package/dist/src/core/status-line-validator.js +253 -0
  55. package/dist/src/core/status-line-validator.js.map +1 -0
  56. package/dist/src/core/sync/bidirectional-engine.d.ts +10 -1
  57. package/dist/src/core/sync/bidirectional-engine.d.ts.map +1 -1
  58. package/dist/src/core/sync/bidirectional-engine.js +10 -1
  59. package/dist/src/core/sync/bidirectional-engine.js.map +1 -1
  60. package/dist/src/core/sync/profile-manager.d.ts.map +1 -1
  61. package/dist/src/core/sync/profile-manager.js +3 -0
  62. package/dist/src/core/sync/profile-manager.js.map +1 -1
  63. package/dist/src/core/sync/project-context.d.ts.map +1 -1
  64. package/dist/src/core/sync/project-context.js +3 -0
  65. package/dist/src/core/sync/project-context.js.map +1 -1
  66. package/dist/src/core/sync/status-sync-engine.d.ts +1 -1
  67. package/dist/src/core/sync/status-sync-engine.js +1 -1
  68. package/dist/src/core/types/origin-metadata.d.ts +153 -0
  69. package/dist/src/core/types/origin-metadata.d.ts.map +1 -0
  70. package/dist/src/core/types/origin-metadata.js +166 -0
  71. package/dist/src/core/types/origin-metadata.js.map +1 -0
  72. package/dist/src/core/types/sync-profile.d.ts +8 -2
  73. package/dist/src/core/types/sync-profile.d.ts.map +1 -1
  74. package/dist/src/core/types/sync-profile.js.map +1 -1
  75. package/dist/src/core/types/sync-settings.d.ts +73 -0
  76. package/dist/src/core/types/sync-settings.d.ts.map +1 -0
  77. package/dist/src/core/types/sync-settings.js +90 -0
  78. package/dist/src/core/types/sync-settings.js.map +1 -0
  79. package/dist/src/core/utils/permission-checker.d.ts +100 -0
  80. package/dist/src/core/utils/permission-checker.d.ts.map +1 -0
  81. package/dist/src/core/utils/permission-checker.js +166 -0
  82. package/dist/src/core/utils/permission-checker.js.map +1 -0
  83. package/dist/src/generators/spec/spec-parser.js +3 -3
  84. package/dist/src/generators/spec/spec-parser.js.map +1 -1
  85. package/dist/src/generators/spec/task-parser.js +4 -4
  86. package/dist/src/generators/spec/task-parser.js.map +1 -1
  87. package/dist/src/id-generators/task-id-generator.d.ts +96 -0
  88. package/dist/src/id-generators/task-id-generator.d.ts.map +1 -0
  89. package/dist/src/id-generators/task-id-generator.js +143 -0
  90. package/dist/src/id-generators/task-id-generator.js.map +1 -0
  91. package/dist/src/id-generators/us-id-generator.d.ts +96 -0
  92. package/dist/src/id-generators/us-id-generator.d.ts.map +1 -0
  93. package/dist/src/id-generators/us-id-generator.js +143 -0
  94. package/dist/src/id-generators/us-id-generator.js.map +1 -0
  95. package/dist/src/importers/ado-importer.d.ts +43 -0
  96. package/dist/src/importers/ado-importer.d.ts.map +1 -0
  97. package/dist/src/importers/ado-importer.js +234 -0
  98. package/dist/src/importers/ado-importer.js.map +1 -0
  99. package/dist/src/importers/external-importer.d.ts +96 -0
  100. package/dist/src/importers/external-importer.d.ts.map +1 -0
  101. package/dist/src/importers/external-importer.js +13 -0
  102. package/dist/src/importers/external-importer.js.map +1 -0
  103. package/dist/src/importers/github-importer.d.ts +37 -0
  104. package/dist/src/importers/github-importer.d.ts.map +1 -0
  105. package/dist/src/importers/github-importer.js +161 -0
  106. package/dist/src/importers/github-importer.js.map +1 -0
  107. package/dist/src/importers/import-coordinator.d.ts +90 -0
  108. package/dist/src/importers/import-coordinator.d.ts.map +1 -0
  109. package/dist/src/importers/import-coordinator.js +182 -0
  110. package/dist/src/importers/import-coordinator.js.map +1 -0
  111. package/dist/src/importers/item-converter.d.ts +91 -0
  112. package/dist/src/importers/item-converter.d.ts.map +1 -0
  113. package/dist/src/importers/item-converter.js +221 -0
  114. package/dist/src/importers/item-converter.js.map +1 -0
  115. package/dist/src/importers/jira-importer.d.ts +42 -0
  116. package/dist/src/importers/jira-importer.d.ts.map +1 -0
  117. package/dist/src/importers/jira-importer.js +221 -0
  118. package/dist/src/importers/jira-importer.js.map +1 -0
  119. package/dist/src/init/repo/types.d.ts +2 -2
  120. package/dist/src/integrations/jira/jira-mapper.d.ts +1 -1
  121. package/dist/src/integrations/jira/jira-mapper.js +1 -1
  122. package/dist/src/living-docs/fs-id-allocator.d.ts +149 -0
  123. package/dist/src/living-docs/fs-id-allocator.d.ts.map +1 -0
  124. package/dist/src/living-docs/fs-id-allocator.js +325 -0
  125. package/dist/src/living-docs/fs-id-allocator.js.map +1 -0
  126. package/dist/src/living-docs/id-registry.d.ts +124 -0
  127. package/dist/src/living-docs/id-registry.d.ts.map +1 -0
  128. package/dist/src/living-docs/id-registry.js +230 -0
  129. package/dist/src/living-docs/id-registry.js.map +1 -0
  130. package/dist/src/progress/us-progress-tracker.d.ts +68 -0
  131. package/dist/src/progress/us-progress-tracker.d.ts.map +1 -0
  132. package/dist/src/progress/us-progress-tracker.js +120 -0
  133. package/dist/src/progress/us-progress-tracker.js.map +1 -0
  134. package/package.json +1 -1
  135. package/plugins/specweave/.claude-plugin/plugin.json +16 -2
  136. package/plugins/specweave/agents/architect/AGENT.md +11 -2
  137. package/plugins/specweave/agents/test-aware-planner/AGENT.md +81 -25
  138. package/plugins/specweave/commands/specweave-import-docs.md +278 -88
  139. package/plugins/specweave/commands/specweave-progress.md +45 -97
  140. package/plugins/specweave/hooks/post-increment-completion.sh +168 -26
  141. package/plugins/specweave/hooks/post-increment-planning.sh +148 -4
  142. package/plugins/specweave/hooks/post-task-completion.sh +64 -4
  143. package/plugins/specweave/lib/hooks/sync-cache.js +294 -0
  144. package/plugins/specweave/lib/hooks/sync-living-docs.js +32 -1
  145. package/plugins/specweave/lib/hooks/sync-us-tasks.js +23 -13
  146. package/plugins/specweave-ado/.claude-plugin/plugin.json +1 -1
  147. package/plugins/specweave-ado/lib/conflict-resolver.ts +1 -1
  148. package/plugins/specweave-alternatives/.claude-plugin/plugin.json +1 -1
  149. package/plugins/specweave-backend/.claude-plugin/plugin.json +1 -1
  150. package/plugins/specweave-confluent/.claude-plugin/plugin.json +1 -1
  151. package/plugins/specweave-cost-optimizer/.claude-plugin/plugin.json +1 -1
  152. package/plugins/specweave-diagrams/.claude-plugin/plugin.json +1 -1
  153. package/plugins/specweave-docs/.claude-plugin/plugin.json +1 -1
  154. package/plugins/specweave-docs-preview/.claude-plugin/plugin.json +1 -1
  155. package/plugins/specweave-figma/.claude-plugin/plugin.json +1 -1
  156. package/plugins/specweave-frontend/.claude-plugin/plugin.json +1 -1
  157. package/plugins/specweave-github/.claude-plugin/plugin.json +1 -1
  158. package/plugins/specweave-github/hooks/post-task-completion.sh +37 -22
  159. package/plugins/specweave-github/lib/ThreeLayerSyncManager.ts +1 -1
  160. package/plugins/specweave-github/lib/enhanced-github-sync.js +1 -1
  161. package/plugins/specweave-github/lib/enhanced-github-sync.ts +1 -1
  162. package/plugins/specweave-github/lib/github-spec-content-sync.js +2 -1
  163. package/plugins/specweave-github/lib/github-spec-content-sync.ts +4 -1
  164. package/plugins/specweave-github/lib/github-spec-sync.js +1 -1
  165. package/plugins/specweave-github/lib/github-spec-sync.ts +1 -1
  166. package/plugins/specweave-github/lib/github-sync-bidirectional.js +1 -1
  167. package/plugins/specweave-github/lib/github-sync-bidirectional.ts +10 -1
  168. package/plugins/specweave-github/lib/progress-comment-builder.js +1 -1
  169. package/plugins/specweave-github/lib/progress-comment-builder.ts +2 -2
  170. package/plugins/specweave-github/lib/types.ts +1 -1
  171. package/plugins/specweave-infrastructure/.claude-plugin/plugin.json +1 -1
  172. package/plugins/specweave-jira/.claude-plugin/plugin.json +1 -1
  173. package/plugins/specweave-kafka/.claude-plugin/plugin.json +1 -1
  174. package/plugins/specweave-kafka-streams/.claude-plugin/plugin.json +1 -1
  175. package/plugins/specweave-kubernetes/.claude-plugin/plugin.json +1 -1
  176. package/plugins/specweave-ml/.claude-plugin/plugin.json +1 -1
  177. package/plugins/specweave-mobile/.claude-plugin/plugin.json +1 -1
  178. package/plugins/specweave-n8n/.claude-plugin/plugin.json +1 -1
  179. package/plugins/specweave-payments/.claude-plugin/plugin.json +1 -1
  180. package/plugins/specweave-release/.claude-plugin/plugin.json +1 -1
  181. package/plugins/specweave-release/hooks/.specweave/logs/dora-tracking.log +252 -0
  182. package/plugins/specweave-testing/.claude-plugin/plugin.json +1 -1
  183. package/plugins/specweave-tooling/.claude-plugin/plugin.json +1 -1
  184. package/plugins/specweave-ui/.claude-plugin/plugin.json +1 -1
  185. package/src/templates/.env.example +5 -0
  186. package/src/templates/config-permissions-guide.md +413 -0
  187. package/src/templates/config.json.template +68 -0
  188. package/src/templates/tasks.md.template +180 -201
@@ -0,0 +1,230 @@
1
+ /**
2
+ * ID Registry - Atomic Feature ID registration with collision detection
3
+ *
4
+ * Provides thread-safe ID registration using file-based locking to prevent
5
+ * race conditions during concurrent imports.
6
+ *
7
+ * Features:
8
+ * - File-based locking for atomic updates
9
+ * - Collision detection (checks both FS-XXX and FS-XXXE)
10
+ * - JSON-based persistent storage
11
+ * - Automatic lock cleanup with timeout
12
+ */
13
+ import fs from 'fs-extra';
14
+ import path from 'path';
15
+ /**
16
+ * ID Registry with atomic file-based locking
17
+ */
18
+ export class IDRegistry {
19
+ constructor(projectRoot) {
20
+ this.lockTimeout = 30000; // 30 seconds
21
+ this.retryDelay = 100; // 100ms
22
+ this.registryPath = path.join(projectRoot, '.specweave/.id-registry.json');
23
+ this.lockPath = path.join(projectRoot, '.specweave/.id-registry.lock');
24
+ }
25
+ /**
26
+ * Register a new Feature ID atomically
27
+ *
28
+ * @param fsId - Feature ID to register (e.g., "FS-042E")
29
+ * @param entry - Registry entry metadata
30
+ * @throws Error if collision detected or lock acquisition fails
31
+ */
32
+ async registerID(fsId, entry) {
33
+ // Acquire lock with timeout
34
+ await this.acquireLock();
35
+ try {
36
+ // Read current registry
37
+ const registry = await this.readRegistry();
38
+ // Check for collision (exact match or variant)
39
+ const collision = this.detectCollision(fsId, registry);
40
+ if (collision) {
41
+ throw new Error(`ID collision: ${fsId} conflicts with ${collision}`);
42
+ }
43
+ // Add new entry
44
+ registry.entries[fsId] = {
45
+ id: fsId,
46
+ ...entry
47
+ };
48
+ registry.lastUpdated = new Date().toISOString();
49
+ registry.version++;
50
+ // Write atomically
51
+ await this.writeRegistry(registry);
52
+ }
53
+ finally {
54
+ // Always release lock
55
+ await this.releaseLock();
56
+ }
57
+ }
58
+ /**
59
+ * Check if ID exists in registry
60
+ *
61
+ * @param fsId - Feature ID to check
62
+ * @returns True if ID is registered
63
+ */
64
+ async hasID(fsId) {
65
+ const registry = await this.readRegistry();
66
+ return fsId in registry.entries;
67
+ }
68
+ /**
69
+ * Get registry entry
70
+ *
71
+ * @param fsId - Feature ID to retrieve
72
+ * @returns Registry entry or null if not found
73
+ */
74
+ async getEntry(fsId) {
75
+ const registry = await this.readRegistry();
76
+ return registry.entries[fsId] || null;
77
+ }
78
+ /**
79
+ * Get all registered IDs
80
+ *
81
+ * @returns Array of all registered Feature IDs
82
+ */
83
+ async getAllIDs() {
84
+ const registry = await this.readRegistry();
85
+ return Object.keys(registry.entries);
86
+ }
87
+ /**
88
+ * Acquire lock file with timeout and retry
89
+ *
90
+ * @throws Error if lock cannot be acquired within timeout
91
+ */
92
+ async acquireLock() {
93
+ const startTime = Date.now();
94
+ // Ensure lock directory exists
95
+ await fs.ensureDir(path.dirname(this.lockPath));
96
+ while (true) {
97
+ try {
98
+ // Try to create lock file exclusively
99
+ await fs.writeFile(this.lockPath, Date.now().toString(), { flag: 'wx' });
100
+ return; // Lock acquired
101
+ }
102
+ catch (error) {
103
+ if (error.code !== 'EEXIST') {
104
+ throw error; // Unexpected error
105
+ }
106
+ // Lock exists, check timeout
107
+ const elapsed = Date.now() - startTime;
108
+ if (elapsed > this.lockTimeout) {
109
+ // Check if lock is stale
110
+ const lockAge = await this.getLockAge();
111
+ if (lockAge > this.lockTimeout) {
112
+ // Stale lock, force remove
113
+ await fs.remove(this.lockPath);
114
+ continue; // Retry
115
+ }
116
+ throw new Error(`Lock acquisition timeout after ${elapsed}ms`);
117
+ }
118
+ // Wait and retry
119
+ await this.sleep(this.retryDelay);
120
+ }
121
+ }
122
+ }
123
+ /**
124
+ * Release lock file
125
+ */
126
+ async releaseLock() {
127
+ try {
128
+ await fs.remove(this.lockPath);
129
+ }
130
+ catch (error) {
131
+ // Ignore if lock doesn't exist (already released)
132
+ if (error.code !== 'ENOENT') {
133
+ throw error;
134
+ }
135
+ }
136
+ }
137
+ /**
138
+ * Get lock file age in milliseconds
139
+ *
140
+ * @returns Lock age or Infinity if lock doesn't exist
141
+ */
142
+ async getLockAge() {
143
+ try {
144
+ const lockContent = await fs.readFile(this.lockPath, 'utf-8');
145
+ const lockTime = parseInt(lockContent, 10);
146
+ return Date.now() - lockTime;
147
+ }
148
+ catch (error) {
149
+ return Infinity; // Lock doesn't exist
150
+ }
151
+ }
152
+ /**
153
+ * Read registry from disk
154
+ *
155
+ * @returns Registry data
156
+ */
157
+ async readRegistry() {
158
+ try {
159
+ const content = await fs.readFile(this.registryPath, 'utf-8');
160
+ return JSON.parse(content);
161
+ }
162
+ catch (error) {
163
+ if (error.code === 'ENOENT') {
164
+ // Registry doesn't exist, return empty
165
+ return {
166
+ entries: {},
167
+ lastUpdated: new Date().toISOString(),
168
+ version: 1
169
+ };
170
+ }
171
+ throw error;
172
+ }
173
+ }
174
+ /**
175
+ * Write registry to disk atomically
176
+ *
177
+ * @param registry - Registry data to write
178
+ */
179
+ async writeRegistry(registry) {
180
+ await fs.ensureDir(path.dirname(this.registryPath));
181
+ // Write to temp file first
182
+ const tempPath = `${this.registryPath}.tmp`;
183
+ await fs.writeFile(tempPath, JSON.stringify(registry, null, 2));
184
+ // Atomic rename
185
+ await fs.rename(tempPath, this.registryPath);
186
+ }
187
+ /**
188
+ * Detect ID collision (exact match or variant)
189
+ *
190
+ * @param fsId - ID to check (e.g., "FS-042E")
191
+ * @param registry - Current registry
192
+ * @returns Conflicting ID or null if no collision
193
+ *
194
+ * @example
195
+ * // Given registry: {FS-042: {...}}
196
+ * detectCollision('FS-042E', registry) // Returns: 'FS-042'
197
+ * detectCollision('FS-043', registry) // Returns: null
198
+ */
199
+ detectCollision(fsId, registry) {
200
+ // Exact match
201
+ if (fsId in registry.entries) {
202
+ return fsId;
203
+ }
204
+ // Extract numeric part
205
+ const match = fsId.match(/^FS-(\d{3,})E?$/);
206
+ if (!match) {
207
+ throw new Error(`Invalid FS-ID format: ${fsId}`);
208
+ }
209
+ const number = parseInt(match[1], 10);
210
+ const internalId = `FS-${String(number).padStart(3, '0')}`;
211
+ const externalId = `FS-${String(number).padStart(3, '0')}E`;
212
+ // Check variant
213
+ if (internalId !== fsId && internalId in registry.entries) {
214
+ return internalId;
215
+ }
216
+ if (externalId !== fsId && externalId in registry.entries) {
217
+ return externalId;
218
+ }
219
+ return null; // No collision
220
+ }
221
+ /**
222
+ * Sleep for specified milliseconds
223
+ *
224
+ * @param ms - Milliseconds to sleep
225
+ */
226
+ sleep(ms) {
227
+ return new Promise(resolve => setTimeout(resolve, ms));
228
+ }
229
+ }
230
+ //# sourceMappingURL=id-registry.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"id-registry.js","sourceRoot":"","sources":["../../../src/living-docs/id-registry.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,68 @@
1
+ /**
2
+ * User Story Progress Tracking
3
+ *
4
+ * Calculates task completion statistics grouped by User Story.
5
+ * Provides per-US and aggregate completion percentages.
6
+ */
7
+ import { type Task, type TasksByUserStory } from '../generators/spec/task-parser.js';
8
+ /**
9
+ * Progress statistics for a single User Story
10
+ */
11
+ export interface USProgress {
12
+ usId: string;
13
+ totalTasks: number;
14
+ completedTasks: number;
15
+ inProgressTasks: number;
16
+ pendingTasks: number;
17
+ percentage: number;
18
+ tasks: Task[];
19
+ }
20
+ /**
21
+ * Aggregate progress across all User Stories
22
+ */
23
+ export interface AggregateProgress {
24
+ totalTasks: number;
25
+ completedTasks: number;
26
+ inProgressTasks: number;
27
+ pendingTasks: number;
28
+ percentage: number;
29
+ byUserStory: Map<string, USProgress>;
30
+ orphanTasks: Task[];
31
+ }
32
+ /**
33
+ * Calculate task completion statistics for a single User Story
34
+ */
35
+ export declare function calculateUSProgress(usId: string, tasks: Task[]): USProgress;
36
+ /**
37
+ * Calculate aggregate progress across all User Stories
38
+ */
39
+ export declare function calculateAggregateProgress(tasksByUS: TasksByUserStory): AggregateProgress;
40
+ /**
41
+ * Calculate progress from tasks.md file
42
+ */
43
+ export declare function calculateProgressFromTasksFile(tasksPath: string): Promise<AggregateProgress>;
44
+ /**
45
+ * Format US progress as string
46
+ */
47
+ export declare function formatUSProgress(progress: USProgress, includePercentage?: boolean): string;
48
+ /**
49
+ * Format aggregate progress as string
50
+ */
51
+ export declare function formatAggregateProgress(progress: AggregateProgress): string;
52
+ /**
53
+ * Get progress bar visualization
54
+ */
55
+ export declare function getProgressBar(percentage: number, width?: number): string;
56
+ /**
57
+ * Get color indicator based on percentage
58
+ */
59
+ export declare function getProgressColor(percentage: number): 'green' | 'yellow' | 'red';
60
+ /**
61
+ * Sort User Stories by completion percentage (descending)
62
+ */
63
+ export declare function sortUSByCompletion(progressMap: Map<string, USProgress>): USProgress[];
64
+ /**
65
+ * Sort User Stories by US-ID (ascending)
66
+ */
67
+ export declare function sortUSByID(progressMap: Map<string, USProgress>): USProgress[];
68
+ //# sourceMappingURL=us-progress-tracker.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"us-progress-tracker.d.ts","sourceRoot":"","sources":["../../../src/progress/us-progress-tracker.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,EAAsC,KAAK,IAAI,EAAE,KAAK,gBAAgB,EAAmB,MAAM,mCAAmC,CAAC;AAE1I;;GAEG;AACH,MAAM,WAAW,UAAU;IACzB,IAAI,EAAE,MAAM,CAAC;IACb,UAAU,EAAE,MAAM,CAAC;IACnB,cAAc,EAAE,MAAM,CAAC;IACvB,eAAe,EAAE,MAAM,CAAC;IACxB,YAAY,EAAE,MAAM,CAAC;IACrB,UAAU,EAAE,MAAM,CAAC;IACnB,KAAK,EAAE,IAAI,EAAE,CAAC;CACf;AAED;;GAEG;AACH,MAAM,WAAW,iBAAiB;IAChC,UAAU,EAAE,MAAM,CAAC;IACnB,cAAc,EAAE,MAAM,CAAC;IACvB,eAAe,EAAE,MAAM,CAAC;IACxB,YAAY,EAAE,MAAM,CAAC;IACrB,UAAU,EAAE,MAAM,CAAC;IACnB,WAAW,EAAE,GAAG,CAAC,MAAM,EAAE,UAAU,CAAC,CAAC;IACrC,WAAW,EAAE,IAAI,EAAE,CAAC;CACrB;AAED;;GAEG;AACH,wBAAgB,mBAAmB,CAAC,IAAI,EAAE,MAAM,EAAE,KAAK,EAAE,IAAI,EAAE,GAAG,UAAU,CAmB3E;AAED;;GAEG;AACH,wBAAgB,0BAA0B,CAAC,SAAS,EAAE,gBAAgB,GAAG,iBAAiB,CA0CzF;AAED;;GAEG;AACH,wBAAsB,8BAA8B,CAAC,SAAS,EAAE,MAAM,GAAG,OAAO,CAAC,iBAAiB,CAAC,CAGlG;AAED;;GAEG;AACH,wBAAgB,gBAAgB,CAAC,QAAQ,EAAE,UAAU,EAAE,iBAAiB,GAAE,OAAc,GAAG,MAAM,CAGhG;AAED;;GAEG;AACH,wBAAgB,uBAAuB,CAAC,QAAQ,EAAE,iBAAiB,GAAG,MAAM,CAE3E;AAED;;GAEG;AACH,wBAAgB,cAAc,CAAC,UAAU,EAAE,MAAM,EAAE,KAAK,GAAE,MAAW,GAAG,MAAM,CAI7E;AAED;;GAEG;AACH,wBAAgB,gBAAgB,CAAC,UAAU,EAAE,MAAM,GAAG,OAAO,GAAG,QAAQ,GAAG,KAAK,CAI/E;AAED;;GAEG;AACH,wBAAgB,kBAAkB,CAAC,WAAW,EAAE,GAAG,CAAC,MAAM,EAAE,UAAU,CAAC,GAAG,UAAU,EAAE,CAErF;AAED;;GAEG;AACH,wBAAgB,UAAU,CAAC,WAAW,EAAE,GAAG,CAAC,MAAM,EAAE,UAAU,CAAC,GAAG,UAAU,EAAE,CAM7E"}
@@ -0,0 +1,120 @@
1
+ /**
2
+ * User Story Progress Tracking
3
+ *
4
+ * Calculates task completion statistics grouped by User Story.
5
+ * Provides per-US and aggregate completion percentages.
6
+ */
7
+ import { parseTasksWithUSLinks } from '../generators/spec/task-parser.js';
8
+ /**
9
+ * Calculate task completion statistics for a single User Story
10
+ */
11
+ export function calculateUSProgress(usId, tasks) {
12
+ const totalTasks = tasks.length;
13
+ const completedTasks = tasks.filter((t) => t.status === 'completed').length;
14
+ const inProgressTasks = tasks.filter((t) => t.status === 'in_progress').length;
15
+ const pendingTasks = tasks.filter((t) => t.status === 'pending' || t.status === 'transferred' || t.status === 'canceled').length;
16
+ const percentage = totalTasks > 0 ? Math.round((completedTasks / totalTasks) * 100) : 0;
17
+ return {
18
+ usId,
19
+ totalTasks,
20
+ completedTasks,
21
+ inProgressTasks,
22
+ pendingTasks,
23
+ percentage,
24
+ tasks,
25
+ };
26
+ }
27
+ /**
28
+ * Calculate aggregate progress across all User Stories
29
+ */
30
+ export function calculateAggregateProgress(tasksByUS) {
31
+ const byUserStory = new Map();
32
+ let totalTasks = 0;
33
+ let completedTasks = 0;
34
+ let inProgressTasks = 0;
35
+ let pendingTasks = 0;
36
+ // Calculate per-US progress
37
+ for (const [usId, tasks] of Object.entries(tasksByUS)) {
38
+ if (usId === 'orphan' || usId === 'unknown')
39
+ continue; // Skip special keys
40
+ const usProgress = calculateUSProgress(usId, tasks);
41
+ byUserStory.set(usId, usProgress);
42
+ totalTasks += usProgress.totalTasks;
43
+ completedTasks += usProgress.completedTasks;
44
+ inProgressTasks += usProgress.inProgressTasks;
45
+ pendingTasks += usProgress.pendingTasks;
46
+ }
47
+ // Identify orphan tasks (tasks without userStory field)
48
+ const orphanTasks = tasksByUS['orphan'] || tasksByUS['unknown'] || [];
49
+ if (orphanTasks.length > 0) {
50
+ totalTasks += orphanTasks.length;
51
+ completedTasks += orphanTasks.filter((t) => t.status === 'completed').length;
52
+ inProgressTasks += orphanTasks.filter((t) => t.status === 'in_progress').length;
53
+ pendingTasks += orphanTasks.filter((t) => t.status === 'pending' || t.status === 'transferred' || t.status === 'canceled').length;
54
+ }
55
+ const percentage = totalTasks > 0 ? Math.round((completedTasks / totalTasks) * 100) : 0;
56
+ return {
57
+ totalTasks,
58
+ completedTasks,
59
+ inProgressTasks,
60
+ pendingTasks,
61
+ percentage,
62
+ byUserStory,
63
+ orphanTasks,
64
+ };
65
+ }
66
+ /**
67
+ * Calculate progress from tasks.md file
68
+ */
69
+ export async function calculateProgressFromTasksFile(tasksPath) {
70
+ const tasksByUS = await parseTasksWithUSLinks(tasksPath);
71
+ return calculateAggregateProgress(tasksByUS);
72
+ }
73
+ /**
74
+ * Format US progress as string
75
+ */
76
+ export function formatUSProgress(progress, includePercentage = true) {
77
+ const percentStr = includePercentage ? ` (${progress.percentage}%)` : '';
78
+ return `${progress.usId}: ${progress.completedTasks}/${progress.totalTasks} tasks${percentStr}`;
79
+ }
80
+ /**
81
+ * Format aggregate progress as string
82
+ */
83
+ export function formatAggregateProgress(progress) {
84
+ return `Overall: ${progress.completedTasks}/${progress.totalTasks} tasks (${progress.percentage}%)`;
85
+ }
86
+ /**
87
+ * Get progress bar visualization
88
+ */
89
+ export function getProgressBar(percentage, width = 20) {
90
+ const filledChars = Math.round((percentage / 100) * width);
91
+ const emptyChars = width - filledChars;
92
+ return '█'.repeat(filledChars) + '░'.repeat(emptyChars);
93
+ }
94
+ /**
95
+ * Get color indicator based on percentage
96
+ */
97
+ export function getProgressColor(percentage) {
98
+ if (percentage >= 80)
99
+ return 'green';
100
+ if (percentage >= 50)
101
+ return 'yellow';
102
+ return 'red';
103
+ }
104
+ /**
105
+ * Sort User Stories by completion percentage (descending)
106
+ */
107
+ export function sortUSByCompletion(progressMap) {
108
+ return Array.from(progressMap.values()).sort((a, b) => b.percentage - a.percentage);
109
+ }
110
+ /**
111
+ * Sort User Stories by US-ID (ascending)
112
+ */
113
+ export function sortUSByID(progressMap) {
114
+ return Array.from(progressMap.values()).sort((a, b) => {
115
+ const aNum = parseInt(a.usId.replace('US-', ''));
116
+ const bNum = parseInt(b.usId.replace('US-', ''));
117
+ return aNum - bNum;
118
+ });
119
+ }
120
+ //# sourceMappingURL=us-progress-tracker.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"us-progress-tracker.js","sourceRoot":"","sources":["../../../src/progress/us-progress-tracker.ts"],"names":[],"mappings":"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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "specweave",
3
- "version": "0.22.13",
3
+ "version": "0.22.14",
4
4
  "description": "Spec-driven development framework for Claude Code. AI-native workflow with living documentation, intelligent agents, and multilingual support (9 languages). Enterprise-grade traceability with permanent specs and temporary increments.",
5
5
  "type": "module",
6
6
  "main": "dist/index.js",
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "specweave",
3
3
  "description": "SpecWeave framework. Provides increment planning (PM, Architect, Tech Lead agents), specification generation, TDD workflow, living docs sync, and brownfield support. Essential for all SpecWeave projects.",
4
- "version": "0.8.0",
4
+ "version": "0.22.14",
5
5
  "author": {
6
6
  "name": "SpecWeave Team",
7
7
  "url": "https://spec-weave.com"
@@ -18,5 +18,19 @@
18
18
  "pm",
19
19
  "architect",
20
20
  "living-docs"
21
- ]
21
+ ],
22
+ "hooks": {
23
+ "PostToolUse": [
24
+ {
25
+ "matcher": "TodoWrite",
26
+ "hooks": [
27
+ {
28
+ "type": "command",
29
+ "command": "${CLAUDE_PLUGIN_ROOT}/hooks/post-task-completion.sh",
30
+ "timeout": 10
31
+ }
32
+ ]
33
+ }
34
+ ]
35
+ }
22
36
  }
@@ -885,7 +885,11 @@ Before marking your work complete, verify:
885
885
  - Use template: Context → Decision → Consequences
886
886
  - Explain WHY not just WHAT
887
887
  - Document alternatives considered
888
- - Save to `.specweave/docs/internal/architecture/adr/###-decision-title.md`
888
+ - **CRITICAL**: Save to `.specweave/docs/internal/architecture/adr/XXXX-decision-title.md`
889
+ - ✅ CORRECT: `0007-github-first-task-sync.md` (4-digit number, kebab-case)
890
+ - ❌ WRONG: `adr-0007-github-first-task-sync.md` (NO `adr-` prefix!)
891
+ - ❌ WRONG: `ADR-0007-github-first-task-sync.md` (lowercase filename)
892
+ - **Why**: The `adr-` prefix is redundant (already in `/adr/` directory)
889
893
 
890
894
  3. **Design API Contracts**
891
895
  - RESTful API design (resources, verbs, status codes)
@@ -945,8 +949,13 @@ High-level description of the system.
945
949
  ```
946
950
 
947
951
  ### ADR Template
952
+
953
+ **IMPORTANT**: Filename format vs. content header:
954
+ - **Filename**: `XXXX-decision-title.md` (e.g., `0007-github-first-task-sync.md`)
955
+ - **Header**: `# ADR-XXXX: Decision Title` (includes `ADR-` prefix for clarity in document)
956
+
948
957
  ```markdown
949
- # ADR-###: [Decision Title]
958
+ # ADR-XXXX: [Decision Title]
950
959
 
951
960
  **Date**: YYYY-MM-DD
952
961
  **Status**: [Proposed | Accepted | Deprecated | Superseded]
@@ -73,17 +73,24 @@ The test-aware-planner agent is responsible for generating `tasks.md` with **emb
73
73
 
74
74
  ---
75
75
 
76
- ## Task Format (NEW - With Embedded Tests)
76
+ ## Task Format (NEW - v0.23.0: Hierarchical US-Task Linkage)
77
+
78
+ **CRITICAL**: v0.23.0+ requires hierarchical structure grouped by User Story.
77
79
 
78
80
  Each task in `tasks.md` follows this format:
79
81
 
80
82
  ```markdown
83
+ ## User Story: US-001 - User Story Title
84
+
85
+ **Linked ACs**: AC-US1-01, AC-US1-02, AC-US1-03
86
+ **Tasks**: X total, 0 completed
87
+
81
88
  ### T-001: Implement Feature X
82
89
 
83
- **User Story**: US1
84
- **Acceptance Criteria**: AC-US1-01, AC-US1-02
85
- **Priority**: P1
86
- **Estimate**: 4 hours
90
+ **User Story**: US-001
91
+ **Satisfies ACs**: AC-US1-01, AC-US1-02
92
+ **Priority**: P0 (Critical) | P1 (Important) | P2 (Nice-to-have)
93
+ **Estimated Effort**: 4 hours
87
94
  **Status**: [ ] pending
88
95
 
89
96
  **Test Plan**:
@@ -667,44 +674,88 @@ If TDD mode is enabled (check frontmatter: `test_mode: TDD`), add TDD workflow s
667
674
 
668
675
  ### Phase 3: File Generation
669
676
 
670
- **Step 3.1: Generate tasks.md Frontmatter**
677
+ **Step 3.1: Generate tasks.md Frontmatter (v0.23.0+)**
671
678
 
672
679
  ```markdown
673
680
  ---
674
- increment: {increment-id}
675
681
  total_tasks: {count}
676
- completed_tasks: 0
677
- test_mode: {TDD|standard}
678
- coverage_target: {percentage}%
682
+ completed: 0
683
+ by_user_story:
684
+ US-001: {count_for_us1}
685
+ US-002: {count_for_us2}
686
+ US-003: {count_for_us3}
687
+ test_mode: {TDD|test-after}
688
+ coverage_target: {percentage}
679
689
  ---
680
690
 
681
- # Implementation Tasks
691
+ # Tasks: {Increment Title}
682
692
  ```
683
693
 
684
- **Rules:**
685
- - `increment`: Use increment ID from folder name
694
+ **Rules (v0.23.0+)**:
686
695
  - `total_tasks`: Count all generated tasks
687
- - `completed_tasks`: Always starts at 0
688
- - `test_mode`: TDD if user requested, standard otherwise
689
- - `coverage_target`: Overall target (typically 80-90%)
696
+ - `completed`: Always starts at 0
697
+ - `by_user_story`: Map of US-ID task count (REQUIRED for progress tracking)
698
+ - `test_mode`: TDD or test-after (no "standard")
699
+ - `coverage_target`: Number without % (e.g., 85, not 85%)
690
700
 
691
- **Step 3.2: Assemble All Tasks**
701
+ **Example**:
702
+ ```yaml
703
+ ---
704
+ total_tasks: 22
705
+ completed: 0
706
+ by_user_story:
707
+ US-001: 4
708
+ US-002: 3
709
+ US-003: 5
710
+ US-004: 3
711
+ US-005: 4
712
+ US-006: 3
713
+ test_mode: test-after
714
+ coverage_target: 90
715
+ ---
716
+ ```
692
717
 
693
- Combine all generated tasks in sequence:
718
+ **Step 3.2: Assemble All Tasks (v0.23.0+: Hierarchical by User Story)**
719
+
720
+ **CRITICAL**: Tasks MUST be grouped by User Story with section headers:
694
721
 
695
722
  ```markdown
696
- ### T-001: [Task 1]
723
+ ## User Story: US-001 - User Story Title
724
+
725
+ **Linked ACs**: AC-US1-01, AC-US1-02, AC-US1-03
726
+ **Tasks**: 4 total, 0 completed
727
+
728
+ ### T-001: [First task for US-001]
729
+ **User Story**: US-001
730
+ **Satisfies ACs**: AC-US1-01, AC-US1-02
697
731
  [Full task format from Phase 2]
698
732
 
699
- ### T-002: [Task 2]
733
+ ### T-002: [Second task for US-001]
734
+ **User Story**: US-001
735
+ **Satisfies ACs**: AC-US1-03
700
736
  [Full task format from Phase 2]
701
737
 
702
- ...
738
+ ---
703
739
 
704
- ### T-{N}: [Last task]
740
+ ## User Story: US-002 - Another User Story Title
741
+
742
+ **Linked ACs**: AC-US2-01, AC-US2-02
743
+ **Tasks**: 3 total, 0 completed
744
+
745
+ ### T-003: [First task for US-002]
746
+ **User Story**: US-002
747
+ **Satisfies ACs**: AC-US2-01
705
748
  [Full task format from Phase 2]
749
+
750
+ ...
706
751
  ```
707
752
 
753
+ **Rules**:
754
+ - Group tasks by User Story using `## User Story: US-XXX - Title` headers
755
+ - Each section shows linked ACs and task count
756
+ - Tasks within section MUST link to that User Story
757
+ - Use `---` separator between User Story sections
758
+
708
759
  **Step 3.3: Write tasks.md**
709
760
 
710
761
  Save the complete file to:
@@ -719,9 +770,14 @@ Save the complete file to:
719
770
 
720
771
  Before finalizing, validate the generated tasks.md:
721
772
 
722
- **Validation Checklist:**
773
+ **Validation Checklist (v0.23.0+)**:
723
774
 
724
- - [ ] **AC-ID Coverage**: Every AC-ID from spec.md is referenced in at least one task
775
+ - [ ] **AC-ID Coverage**: Every AC-ID from spec.md is referenced in at least one task (100% coverage required)
776
+ - [ ] **US-Task Linkage**: Every task has **User Story** field linking to valid US-ID
777
+ - [ ] **AC Linkage**: Every task has **Satisfies ACs** field with valid AC-IDs
778
+ - [ ] **Hierarchical Structure**: Tasks grouped by User Story with section headers
779
+ - [ ] **by_user_story Map**: Frontmatter includes by_user_story with correct counts
780
+ - [ ] **No Orphan Tasks**: All tasks link to at least one AC
725
781
  - [ ] **Task Format**: Each task follows the standard format (header, test plan, test cases, implementation)
726
782
  - [ ] **Test Plans**: All testable tasks have Given/When/Then
727
783
  - [ ] **Test Cases**: Test file paths follow project conventions
@@ -731,7 +787,7 @@ Before finalizing, validate the generated tasks.md:
731
787
  - [ ] **TDD Workflow**: Included if test_mode is TDD
732
788
  - [ ] **Estimates**: Realistic (2-8 hours typical per task)
733
789
  - [ ] **Dependencies**: Tasks ordered by dependencies
734
- - [ ] **Frontmatter**: Correct increment ID, task count, test mode
790
+ - [ ] **Frontmatter**: Correct total_tasks, by_user_story map, test_mode, coverage_target
735
791
 
736
792
  **Validation Script Example:**
737
793