specweave 0.22.3 → 0.22.5
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 +281 -1050
- package/dist/src/cli/commands/init.d.ts +2 -0
- package/dist/src/cli/commands/init.d.ts.map +1 -1
- package/dist/src/cli/commands/init.js +141 -95
- package/dist/src/cli/commands/init.js.map +1 -1
- package/dist/src/cli/commands/sync-specs.d.ts +4 -1
- package/dist/src/cli/commands/sync-specs.d.ts.map +1 -1
- package/dist/src/cli/commands/sync-specs.js +99 -49
- package/dist/src/cli/commands/sync-specs.js.map +1 -1
- package/dist/src/core/cicd/workflow-monitor.d.ts +4 -0
- package/dist/src/core/cicd/workflow-monitor.d.ts.map +1 -1
- package/dist/src/core/cicd/workflow-monitor.js +6 -2
- package/dist/src/core/cicd/workflow-monitor.js.map +1 -1
- package/dist/src/core/increment/increment-archiver.d.ts +4 -1
- package/dist/src/core/increment/increment-archiver.d.ts.map +1 -1
- package/dist/src/core/increment/increment-archiver.js +21 -9
- package/dist/src/core/increment/increment-archiver.js.map +1 -1
- package/dist/src/core/increment/metadata-manager.d.ts +22 -0
- package/dist/src/core/increment/metadata-manager.d.ts.map +1 -1
- package/dist/src/core/increment/metadata-manager.js +57 -5
- package/dist/src/core/increment/metadata-manager.js.map +1 -1
- package/dist/src/core/increment/spec-sync-manager.d.ts +5 -1
- package/dist/src/core/increment/spec-sync-manager.d.ts.map +1 -1
- package/dist/src/core/increment/spec-sync-manager.js +4 -2
- package/dist/src/core/increment/spec-sync-manager.js.map +1 -1
- package/dist/src/core/increment-utils.d.ts.map +1 -1
- package/dist/src/core/increment-utils.js +18 -1
- package/dist/src/core/increment-utils.js.map +1 -1
- package/dist/src/core/living-docs/living-docs-sync.d.ts +5 -1
- package/dist/src/core/living-docs/living-docs-sync.d.ts.map +1 -1
- package/dist/src/core/living-docs/living-docs-sync.js +34 -32
- package/dist/src/core/living-docs/living-docs-sync.js.map +1 -1
- package/dist/src/core/living-docs/task-project-specific-generator.d.ts.map +1 -1
- package/dist/src/core/living-docs/task-project-specific-generator.js +13 -8
- package/dist/src/core/living-docs/task-project-specific-generator.js.map +1 -1
- package/dist/src/core/status-line/status-line-manager.d.ts.map +1 -1
- package/dist/src/core/status-line/status-line-manager.js +3 -1
- package/dist/src/core/status-line/status-line-manager.js.map +1 -1
- package/dist/src/integrations/jira/jira-incremental-mapper.d.ts.map +1 -1
- package/dist/src/integrations/jira/jira-incremental-mapper.js +4 -0
- package/dist/src/integrations/jira/jira-incremental-mapper.js.map +1 -1
- package/dist/src/integrations/jira/jira-mapper.d.ts.map +1 -1
- package/dist/src/integrations/jira/jira-mapper.js +4 -0
- package/dist/src/integrations/jira/jira-mapper.js.map +1 -1
- package/dist/src/utils/logger.d.ts +48 -0
- package/dist/src/utils/logger.d.ts.map +1 -0
- package/dist/src/utils/logger.js +53 -0
- package/dist/src/utils/logger.js.map +1 -0
- package/package.json +3 -2
- package/plugins/specweave/agents/code-standards-detective/AGENT.md +828 -0
- package/plugins/specweave/agents/test-aware-planner/templates/task-non-testable.md.template +12 -0
- package/plugins/specweave/agents/test-aware-planner/templates/task-testable.md.template +12 -0
- package/plugins/specweave/commands/specweave-analyze-standards.sh +315 -0
- package/plugins/specweave/commands/specweave-done.md +33 -2
- package/plugins/specweave/commands/specweave-sync-docs.md +66 -18
- package/plugins/specweave/hooks/lib/update-status-line.sh +5 -2
- package/plugins/specweave/skills/brownfield-analyzer/SKILL.md +40 -3
- package/plugins/specweave/skills/code-standards-analyzer/SKILL.md +455 -0
- package/plugins/specweave/templates/coding-standards.md.template +447 -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-jira/lib/enhanced-jira-sync.js +3 -3
- package/plugins/specweave-release/hooks/.specweave/logs/dora-tracking.log +5238 -0
|
@@ -0,0 +1,447 @@
|
|
|
1
|
+
# Coding Standards
|
|
2
|
+
|
|
3
|
+
**Auto-Generated**: {{timestamp}}
|
|
4
|
+
**Codebase**: {{project_name}}
|
|
5
|
+
**Analysis**: {{file_count}} files, {{line_count}} lines of code
|
|
6
|
+
**Overall Confidence**: {{overall_confidence}}%
|
|
7
|
+
|
|
8
|
+
> 📊 This document combines:
|
|
9
|
+
> - ✅ **Explicit Standards** - Declared in ESLint, Prettier, CLAUDE.md
|
|
10
|
+
> - 📈 **Implicit Standards** - Detected from codebase analysis ({{file_count}} files)
|
|
11
|
+
> - 🚨 **Issues** - Anti-patterns and security concerns
|
|
12
|
+
|
|
13
|
+
---
|
|
14
|
+
|
|
15
|
+
## Table of Contents
|
|
16
|
+
|
|
17
|
+
1. [Summary](#summary)
|
|
18
|
+
2. [Naming Conventions](#naming-conventions)
|
|
19
|
+
3. [Import Patterns](#import-patterns)
|
|
20
|
+
4. [Function Guidelines](#function-guidelines)
|
|
21
|
+
5. [Type Safety](#type-safety)
|
|
22
|
+
6. [Error Handling](#error-handling)
|
|
23
|
+
7. [Security](#security)
|
|
24
|
+
8. [Performance](#performance)
|
|
25
|
+
9. [SpecWeave-Specific Rules](#specweave-specific-rules)
|
|
26
|
+
10. [Anti-Patterns & Issues](#anti-patterns--issues)
|
|
27
|
+
11. [Next Steps](#next-steps)
|
|
28
|
+
12. [Appendix](#appendix)
|
|
29
|
+
|
|
30
|
+
---
|
|
31
|
+
|
|
32
|
+
## Summary
|
|
33
|
+
|
|
34
|
+
### Confidence Levels
|
|
35
|
+
|
|
36
|
+
| Level | Criteria | Meaning |
|
|
37
|
+
|-------|----------|---------|
|
|
38
|
+
| **ENFORCED** | 100% | Linter/compiler enforced |
|
|
39
|
+
| **HIGH** | 90%+ | Overwhelming compliance |
|
|
40
|
+
| **MEDIUM** | 70-89% | Majority compliance |
|
|
41
|
+
| **LOW** | 50-69% | Weak pattern |
|
|
42
|
+
| **CONFLICT** | <50% | Inconsistent, needs decision |
|
|
43
|
+
|
|
44
|
+
### Overall Health
|
|
45
|
+
|
|
46
|
+
{{overall_health_summary}}
|
|
47
|
+
|
|
48
|
+
---
|
|
49
|
+
|
|
50
|
+
## 1. Naming Conventions
|
|
51
|
+
|
|
52
|
+
### Variables
|
|
53
|
+
|
|
54
|
+
**Standard**: {{variable_naming_standard}}
|
|
55
|
+
**Confidence**: {{variable_naming_confidence}}
|
|
56
|
+
**Compliance**: {{variable_naming_compliance}}%
|
|
57
|
+
**Samples**: {{variable_naming_samples}}
|
|
58
|
+
|
|
59
|
+
**Enforced by**: {{variable_naming_enforcement}}
|
|
60
|
+
|
|
61
|
+
**Examples**:
|
|
62
|
+
```typescript
|
|
63
|
+
// ✅ Good ({{variable_naming_good_percent}}% of codebase)
|
|
64
|
+
{{variable_naming_good_examples}}
|
|
65
|
+
|
|
66
|
+
// ❌ Bad ({{variable_naming_bad_percent}}% of codebase)
|
|
67
|
+
{{variable_naming_bad_examples}}
|
|
68
|
+
```
|
|
69
|
+
|
|
70
|
+
**Recommendation**: {{variable_naming_recommendation}}
|
|
71
|
+
|
|
72
|
+
---
|
|
73
|
+
|
|
74
|
+
### Functions
|
|
75
|
+
|
|
76
|
+
**Standard**: {{function_naming_standard}}
|
|
77
|
+
**Confidence**: {{function_naming_confidence}}
|
|
78
|
+
**Compliance**: {{function_naming_compliance}}%
|
|
79
|
+
**Samples**: {{function_naming_samples}}
|
|
80
|
+
|
|
81
|
+
**Examples**:
|
|
82
|
+
```typescript
|
|
83
|
+
// ✅ Good
|
|
84
|
+
{{function_naming_good_examples}}
|
|
85
|
+
|
|
86
|
+
// ❌ Bad
|
|
87
|
+
{{function_naming_bad_examples}}
|
|
88
|
+
```
|
|
89
|
+
|
|
90
|
+
**Recommendation**: {{function_naming_recommendation}}
|
|
91
|
+
|
|
92
|
+
---
|
|
93
|
+
|
|
94
|
+
### Classes
|
|
95
|
+
|
|
96
|
+
**Standard**: {{class_naming_standard}}
|
|
97
|
+
**Confidence**: {{class_naming_confidence}}
|
|
98
|
+
**Compliance**: {{class_naming_compliance}}%
|
|
99
|
+
**Samples**: {{class_naming_samples}}
|
|
100
|
+
|
|
101
|
+
**Examples**:
|
|
102
|
+
```typescript
|
|
103
|
+
// ✅ Good
|
|
104
|
+
{{class_naming_good_examples}}
|
|
105
|
+
|
|
106
|
+
// ❌ Bad (if any)
|
|
107
|
+
{{class_naming_bad_examples}}
|
|
108
|
+
```
|
|
109
|
+
|
|
110
|
+
**Recommendation**: {{class_naming_recommendation}}
|
|
111
|
+
|
|
112
|
+
---
|
|
113
|
+
|
|
114
|
+
### Constants
|
|
115
|
+
|
|
116
|
+
**Standard**: {{constant_naming_standard}}
|
|
117
|
+
**Confidence**: {{constant_naming_confidence}}
|
|
118
|
+
**Compliance**: {{constant_naming_compliance}}%
|
|
119
|
+
**Samples**: {{constant_naming_samples}}
|
|
120
|
+
|
|
121
|
+
**Examples**:
|
|
122
|
+
```typescript
|
|
123
|
+
// ✅ Good
|
|
124
|
+
{{constant_naming_good_examples}}
|
|
125
|
+
|
|
126
|
+
// ⚠️ Inconsistent ({{constant_naming_bad_percent}}% use different convention)
|
|
127
|
+
{{constant_naming_bad_examples}}
|
|
128
|
+
```
|
|
129
|
+
|
|
130
|
+
**Recommendation**: {{constant_naming_recommendation}}
|
|
131
|
+
|
|
132
|
+
---
|
|
133
|
+
|
|
134
|
+
## 2. Import Patterns
|
|
135
|
+
|
|
136
|
+
### File Extensions
|
|
137
|
+
|
|
138
|
+
**Standard**: {{import_extension_standard}}
|
|
139
|
+
**Confidence**: {{import_extension_confidence}}
|
|
140
|
+
**Compliance**: {{import_extension_compliance}}%
|
|
141
|
+
|
|
142
|
+
**Enforced by**: {{import_extension_enforcement}}
|
|
143
|
+
|
|
144
|
+
**Examples**:
|
|
145
|
+
```typescript
|
|
146
|
+
// ✅ Good ({{import_extension_good_percent}}% compliance)
|
|
147
|
+
{{import_extension_good_examples}}
|
|
148
|
+
|
|
149
|
+
// ❌ Bad ({{import_extension_bad_percent}}% if any)
|
|
150
|
+
{{import_extension_bad_examples}}
|
|
151
|
+
```
|
|
152
|
+
|
|
153
|
+
**Recommendation**: {{import_extension_recommendation}}
|
|
154
|
+
|
|
155
|
+
---
|
|
156
|
+
|
|
157
|
+
### Import Ordering
|
|
158
|
+
|
|
159
|
+
**Standard**: {{import_ordering_standard}}
|
|
160
|
+
**Confidence**: {{import_ordering_confidence}}
|
|
161
|
+
**Compliance**: {{import_ordering_compliance}}%
|
|
162
|
+
|
|
163
|
+
**Examples**:
|
|
164
|
+
```typescript
|
|
165
|
+
// ✅ Good ({{import_ordering_good_percent}}% of files)
|
|
166
|
+
{{import_ordering_good_examples}}
|
|
167
|
+
|
|
168
|
+
// ⚠️ Not followed ({{import_ordering_bad_percent}}% of files)
|
|
169
|
+
{{import_ordering_bad_examples}}
|
|
170
|
+
```
|
|
171
|
+
|
|
172
|
+
**Recommendation**: {{import_ordering_recommendation}}
|
|
173
|
+
|
|
174
|
+
---
|
|
175
|
+
|
|
176
|
+
## 3. Function Guidelines
|
|
177
|
+
|
|
178
|
+
### Function Length
|
|
179
|
+
|
|
180
|
+
**Detected Pattern**:
|
|
181
|
+
- **Average**: {{function_length_avg}} lines
|
|
182
|
+
- **Median**: {{function_length_median}} lines
|
|
183
|
+
- **90th percentile**: {{function_length_p90}} lines
|
|
184
|
+
- **Max**: {{function_length_max}} lines ({{function_length_max_location}})
|
|
185
|
+
|
|
186
|
+
**Recommended**: <50 lines (ideal), <100 lines (max)
|
|
187
|
+
|
|
188
|
+
**Violations** ({{function_length_violations}} functions >100 lines):
|
|
189
|
+
{{function_length_violations_list}}
|
|
190
|
+
|
|
191
|
+
**Recommendation**: {{function_length_recommendation}}
|
|
192
|
+
|
|
193
|
+
---
|
|
194
|
+
|
|
195
|
+
### Function Style
|
|
196
|
+
|
|
197
|
+
**Detected Pattern**:
|
|
198
|
+
- Arrow functions: {{arrow_function_percent}}%
|
|
199
|
+
- Regular functions: {{regular_function_percent}}%
|
|
200
|
+
|
|
201
|
+
**Examples**:
|
|
202
|
+
```typescript
|
|
203
|
+
// Preferred ({{arrow_function_percent}}% of codebase)
|
|
204
|
+
{{arrow_function_examples}}
|
|
205
|
+
|
|
206
|
+
// Also acceptable ({{regular_function_percent}}% of codebase)
|
|
207
|
+
{{regular_function_examples}}
|
|
208
|
+
```
|
|
209
|
+
|
|
210
|
+
**Recommendation**: {{function_style_recommendation}}
|
|
211
|
+
|
|
212
|
+
---
|
|
213
|
+
|
|
214
|
+
## 4. Type Safety
|
|
215
|
+
|
|
216
|
+
### Avoid `any` Type
|
|
217
|
+
|
|
218
|
+
**Detected**: {{any_type_count}} instances of `any` type
|
|
219
|
+
|
|
220
|
+
**Enforced by**: {{any_type_enforcement}}
|
|
221
|
+
|
|
222
|
+
**Violations**:
|
|
223
|
+
{{any_type_violations_list}}
|
|
224
|
+
|
|
225
|
+
**Recommendation**: {{any_type_recommendation}}
|
|
226
|
+
|
|
227
|
+
---
|
|
228
|
+
|
|
229
|
+
### Interface vs Type
|
|
230
|
+
|
|
231
|
+
**Detected Pattern**:
|
|
232
|
+
- Interfaces: {{interface_percent}}%
|
|
233
|
+
- Types: {{type_percent}}%
|
|
234
|
+
|
|
235
|
+
**Examples**:
|
|
236
|
+
```typescript
|
|
237
|
+
// Preferred for objects ({{interface_percent}}% of codebase)
|
|
238
|
+
{{interface_examples}}
|
|
239
|
+
|
|
240
|
+
// Preferred for unions/aliases ({{type_percent}}% of codebase)
|
|
241
|
+
{{type_examples}}
|
|
242
|
+
```
|
|
243
|
+
|
|
244
|
+
**Recommendation**: {{interface_type_recommendation}}
|
|
245
|
+
|
|
246
|
+
---
|
|
247
|
+
|
|
248
|
+
## 5. Error Handling
|
|
249
|
+
|
|
250
|
+
### Custom Error Types
|
|
251
|
+
|
|
252
|
+
**Detected**: {{custom_error_count}} custom error classes
|
|
253
|
+
|
|
254
|
+
**Examples**:
|
|
255
|
+
```typescript
|
|
256
|
+
{{custom_error_examples}}
|
|
257
|
+
```
|
|
258
|
+
|
|
259
|
+
**Recommendation**: {{custom_error_recommendation}}
|
|
260
|
+
|
|
261
|
+
---
|
|
262
|
+
|
|
263
|
+
### Try/Catch Usage
|
|
264
|
+
|
|
265
|
+
**Detected**: {{try_catch_percent}}% of async functions have try/catch
|
|
266
|
+
|
|
267
|
+
**Examples**:
|
|
268
|
+
```typescript
|
|
269
|
+
// ✅ Good ({{try_catch_good_count}} functions)
|
|
270
|
+
{{try_catch_good_examples}}
|
|
271
|
+
|
|
272
|
+
// ⚠️ Missing error handling ({{try_catch_missing_count}} functions)
|
|
273
|
+
{{try_catch_missing_list}}
|
|
274
|
+
```
|
|
275
|
+
|
|
276
|
+
**Recommendation**: {{try_catch_recommendation}}
|
|
277
|
+
|
|
278
|
+
---
|
|
279
|
+
|
|
280
|
+
## 6. Security
|
|
281
|
+
|
|
282
|
+
### No Hardcoded Secrets
|
|
283
|
+
|
|
284
|
+
**Status**: {{hardcoded_secrets_status}}
|
|
285
|
+
|
|
286
|
+
**Violations** ({{hardcoded_secrets_count}} instances):
|
|
287
|
+
{{hardcoded_secrets_list}}
|
|
288
|
+
|
|
289
|
+
**Recommendation**: {{hardcoded_secrets_recommendation}}
|
|
290
|
+
|
|
291
|
+
---
|
|
292
|
+
|
|
293
|
+
### No console.* in Production
|
|
294
|
+
|
|
295
|
+
**Status**: {{console_usage_status}}
|
|
296
|
+
|
|
297
|
+
**Violations** ({{console_usage_count}} instances):
|
|
298
|
+
{{console_usage_list}}
|
|
299
|
+
|
|
300
|
+
**Recommendation**: {{console_usage_recommendation}}
|
|
301
|
+
|
|
302
|
+
---
|
|
303
|
+
|
|
304
|
+
## 7. Performance
|
|
305
|
+
|
|
306
|
+
### No N+1 Queries
|
|
307
|
+
|
|
308
|
+
**Status**: {{n_plus_one_status}}
|
|
309
|
+
|
|
310
|
+
{{n_plus_one_details}}
|
|
311
|
+
|
|
312
|
+
**Recommendation**: {{n_plus_one_recommendation}}
|
|
313
|
+
|
|
314
|
+
---
|
|
315
|
+
|
|
316
|
+
## 8. SpecWeave-Specific Rules
|
|
317
|
+
|
|
318
|
+
### 1. Logger Abstraction
|
|
319
|
+
|
|
320
|
+
**Rule**: NEVER use console.* in src/
|
|
321
|
+
|
|
322
|
+
**Compliance**: {{logger_compliance}}%
|
|
323
|
+
|
|
324
|
+
**Violations**: {{logger_violations_count}} instances
|
|
325
|
+
|
|
326
|
+
**Correct usage**:
|
|
327
|
+
```typescript
|
|
328
|
+
import { logger } from '../utils/logger.js';
|
|
329
|
+
logger.info('Message');
|
|
330
|
+
logger.error('Error', error);
|
|
331
|
+
```
|
|
332
|
+
|
|
333
|
+
---
|
|
334
|
+
|
|
335
|
+
### 2. Test File Naming
|
|
336
|
+
|
|
337
|
+
**Rule**: Use .test.ts suffix (NEVER .spec.ts)
|
|
338
|
+
|
|
339
|
+
**Compliance**: {{test_naming_compliance}}%
|
|
340
|
+
|
|
341
|
+
---
|
|
342
|
+
|
|
343
|
+
### 3. Import Extensions
|
|
344
|
+
|
|
345
|
+
**Rule**: ALWAYS use .js extensions for ESM compatibility
|
|
346
|
+
|
|
347
|
+
**Compliance**: {{import_extension_compliance}}%
|
|
348
|
+
|
|
349
|
+
---
|
|
350
|
+
|
|
351
|
+
## 9. Anti-Patterns & Issues
|
|
352
|
+
|
|
353
|
+
### 🔴 CRITICAL ({{critical_issues_count}} issues)
|
|
354
|
+
|
|
355
|
+
{{critical_issues_list}}
|
|
356
|
+
|
|
357
|
+
---
|
|
358
|
+
|
|
359
|
+
### 🟠 HIGH ({{high_issues_count}} issues)
|
|
360
|
+
|
|
361
|
+
{{high_issues_list}}
|
|
362
|
+
|
|
363
|
+
---
|
|
364
|
+
|
|
365
|
+
### 🟡 MEDIUM ({{medium_issues_count}} issues)
|
|
366
|
+
|
|
367
|
+
{{medium_issues_list}}
|
|
368
|
+
|
|
369
|
+
---
|
|
370
|
+
|
|
371
|
+
### 🟢 LOW
|
|
372
|
+
|
|
373
|
+
{{low_issues_summary}}
|
|
374
|
+
|
|
375
|
+
---
|
|
376
|
+
|
|
377
|
+
## 10. Next Steps
|
|
378
|
+
|
|
379
|
+
### Critical (Fix Immediately)
|
|
380
|
+
{{critical_next_steps}}
|
|
381
|
+
|
|
382
|
+
### High Priority (This Sprint)
|
|
383
|
+
{{high_priority_next_steps}}
|
|
384
|
+
|
|
385
|
+
### Medium Priority (Next Sprint)
|
|
386
|
+
{{medium_priority_next_steps}}
|
|
387
|
+
|
|
388
|
+
### Documentation
|
|
389
|
+
{{documentation_next_steps}}
|
|
390
|
+
|
|
391
|
+
---
|
|
392
|
+
|
|
393
|
+
## 11. Appendix
|
|
394
|
+
|
|
395
|
+
### Configuration Files
|
|
396
|
+
|
|
397
|
+
#### .eslintrc.json
|
|
398
|
+
```json
|
|
399
|
+
{{eslint_config}}
|
|
400
|
+
```
|
|
401
|
+
|
|
402
|
+
#### .prettierrc
|
|
403
|
+
```json
|
|
404
|
+
{{prettier_config}}
|
|
405
|
+
```
|
|
406
|
+
|
|
407
|
+
#### tsconfig.json (relevant sections)
|
|
408
|
+
```json
|
|
409
|
+
{{tsconfig_config}}
|
|
410
|
+
```
|
|
411
|
+
|
|
412
|
+
---
|
|
413
|
+
|
|
414
|
+
### Statistics
|
|
415
|
+
|
|
416
|
+
| Metric | Value |
|
|
417
|
+
|--------|-------|
|
|
418
|
+
| Total Files | {{file_count}} |
|
|
419
|
+
| Total LOC | {{line_count}} |
|
|
420
|
+
| Variables Analyzed | {{variable_count}} |
|
|
421
|
+
| Functions Analyzed | {{function_count}} |
|
|
422
|
+
| Classes Analyzed | {{class_count}} |
|
|
423
|
+
| Imports Analyzed | {{import_count}} |
|
|
424
|
+
| Analysis Duration | {{analysis_duration}} |
|
|
425
|
+
|
|
426
|
+
---
|
|
427
|
+
|
|
428
|
+
### Change Log
|
|
429
|
+
|
|
430
|
+
**Previous Analysis**: {{previous_analysis_date}}
|
|
431
|
+
**This Analysis**: {{current_analysis_date}}
|
|
432
|
+
|
|
433
|
+
**Changes Since Last Analysis**:
|
|
434
|
+
{{change_log}}
|
|
435
|
+
|
|
436
|
+
---
|
|
437
|
+
|
|
438
|
+
## Metadata
|
|
439
|
+
|
|
440
|
+
**Generated by**: SpecWeave code-standards-detective agent
|
|
441
|
+
**Version**: {{specweave_version}}
|
|
442
|
+
**Analysis Date**: {{analysis_date}}
|
|
443
|
+
**Next Review**: {{next_review_date}} (recommended: quarterly)
|
|
444
|
+
|
|
445
|
+
---
|
|
446
|
+
|
|
447
|
+
*This document is auto-generated. For questions or updates, consult the development team.*
|
|
@@ -0,0 +1,170 @@
|
|
|
1
|
+
import { AdoClientV2 } from "./ado-client-v2.js";
|
|
2
|
+
import { EnhancedContentBuilder } from "../../../src/core/sync/enhanced-content-builder.js";
|
|
3
|
+
import { SpecIncrementMapper } from "../../../src/core/sync/spec-increment-mapper.js";
|
|
4
|
+
import { parseSpecContent } from "../../../src/core/spec-content-sync.js";
|
|
5
|
+
import path from "path";
|
|
6
|
+
import fs from "fs/promises";
|
|
7
|
+
async function syncSpecToAdoWithEnhancedContent(options) {
|
|
8
|
+
const { specPath, organization, project, dryRun = false, verbose = false } = options;
|
|
9
|
+
try {
|
|
10
|
+
const baseSpec = await parseSpecContent(specPath);
|
|
11
|
+
if (!baseSpec) {
|
|
12
|
+
return {
|
|
13
|
+
success: false,
|
|
14
|
+
action: "error",
|
|
15
|
+
error: "Failed to parse spec content"
|
|
16
|
+
};
|
|
17
|
+
}
|
|
18
|
+
if (verbose) {
|
|
19
|
+
console.log(`\u{1F4C4} Parsed spec: ${baseSpec.identifier.compact}`);
|
|
20
|
+
}
|
|
21
|
+
const specId = baseSpec.identifier.full || baseSpec.identifier.compact;
|
|
22
|
+
const rootDir = await findSpecWeaveRoot(specPath);
|
|
23
|
+
const mapper = new SpecIncrementMapper(rootDir);
|
|
24
|
+
const mapping = await mapper.mapSpecToIncrements(specId);
|
|
25
|
+
if (verbose) {
|
|
26
|
+
console.log(`\u{1F517} Found ${mapping.increments.length} related increments`);
|
|
27
|
+
}
|
|
28
|
+
const taskMapping = buildTaskMapping(mapping.increments, organization, project);
|
|
29
|
+
const architectureDocs = await findArchitectureDocs(rootDir, specId);
|
|
30
|
+
const enhancedSpec = {
|
|
31
|
+
...baseSpec,
|
|
32
|
+
summary: baseSpec.description,
|
|
33
|
+
taskMapping,
|
|
34
|
+
architectureDocs
|
|
35
|
+
};
|
|
36
|
+
const builder = new EnhancedContentBuilder();
|
|
37
|
+
const description = builder.buildExternalDescription(enhancedSpec);
|
|
38
|
+
if (verbose) {
|
|
39
|
+
console.log(`\u{1F4DD} Generated description: ${description.length} characters`);
|
|
40
|
+
}
|
|
41
|
+
if (dryRun) {
|
|
42
|
+
console.log("\u{1F50D} DRY RUN - Would create/update feature with:");
|
|
43
|
+
console.log(` Title: ${baseSpec.title}`);
|
|
44
|
+
console.log(` Description length: ${description.length}`);
|
|
45
|
+
return {
|
|
46
|
+
success: true,
|
|
47
|
+
action: "no-change",
|
|
48
|
+
tasksLinked: taskMapping?.tasks.length || 0
|
|
49
|
+
};
|
|
50
|
+
}
|
|
51
|
+
if (!organization || !project) {
|
|
52
|
+
return {
|
|
53
|
+
success: false,
|
|
54
|
+
action: "error",
|
|
55
|
+
error: "Azure DevOps organization/project not specified"
|
|
56
|
+
};
|
|
57
|
+
}
|
|
58
|
+
const profile = {
|
|
59
|
+
provider: "ado",
|
|
60
|
+
displayName: `${organization}/${project}`,
|
|
61
|
+
config: {
|
|
62
|
+
organization,
|
|
63
|
+
project
|
|
64
|
+
},
|
|
65
|
+
timeRange: { default: "1M", max: "6M" }
|
|
66
|
+
};
|
|
67
|
+
const pat = process.env.AZURE_DEVOPS_PAT || "";
|
|
68
|
+
const client = new AdoClientV2(profile, pat);
|
|
69
|
+
const existingFeature = await findExistingFeature(client, baseSpec.identifier.compact);
|
|
70
|
+
let result;
|
|
71
|
+
if (existingFeature) {
|
|
72
|
+
await client.updateWorkItem(existingFeature.id, {
|
|
73
|
+
title: `[${baseSpec.identifier.compact}] ${baseSpec.title}`,
|
|
74
|
+
description
|
|
75
|
+
});
|
|
76
|
+
result = {
|
|
77
|
+
success: true,
|
|
78
|
+
action: "updated",
|
|
79
|
+
featureId: existingFeature.id,
|
|
80
|
+
featureUrl: `https://dev.azure.com/${organization}/${project}/_workitems/edit/${existingFeature.id}`,
|
|
81
|
+
tasksLinked: taskMapping?.tasks.length || 0
|
|
82
|
+
};
|
|
83
|
+
} else {
|
|
84
|
+
const feature = await client.createEpic({
|
|
85
|
+
title: `[${baseSpec.identifier.compact}] ${baseSpec.title}`,
|
|
86
|
+
description,
|
|
87
|
+
tags: ["spec", "external-tool-sync"]
|
|
88
|
+
});
|
|
89
|
+
result = {
|
|
90
|
+
success: true,
|
|
91
|
+
action: "created",
|
|
92
|
+
featureId: feature.id,
|
|
93
|
+
featureUrl: `https://dev.azure.com/${organization}/${project}/_workitems/edit/${feature.id}`,
|
|
94
|
+
tasksLinked: taskMapping?.tasks.length || 0
|
|
95
|
+
};
|
|
96
|
+
}
|
|
97
|
+
if (verbose) {
|
|
98
|
+
console.log(`\u2705 ${result.action === "created" ? "Created" : "Updated"} feature #${result.featureId}`);
|
|
99
|
+
}
|
|
100
|
+
return result;
|
|
101
|
+
} catch (error) {
|
|
102
|
+
return {
|
|
103
|
+
success: false,
|
|
104
|
+
action: "error",
|
|
105
|
+
error: error.message
|
|
106
|
+
};
|
|
107
|
+
}
|
|
108
|
+
}
|
|
109
|
+
async function findSpecWeaveRoot(specPath) {
|
|
110
|
+
let currentDir = path.dirname(specPath);
|
|
111
|
+
while (true) {
|
|
112
|
+
const specweaveDir = path.join(currentDir, ".specweave");
|
|
113
|
+
try {
|
|
114
|
+
await fs.access(specweaveDir);
|
|
115
|
+
return currentDir;
|
|
116
|
+
} catch {
|
|
117
|
+
const parentDir = path.dirname(currentDir);
|
|
118
|
+
if (parentDir === currentDir) {
|
|
119
|
+
throw new Error(".specweave directory not found");
|
|
120
|
+
}
|
|
121
|
+
currentDir = parentDir;
|
|
122
|
+
}
|
|
123
|
+
}
|
|
124
|
+
}
|
|
125
|
+
function buildTaskMapping(increments, organization, project) {
|
|
126
|
+
if (increments.length === 0) return void 0;
|
|
127
|
+
const firstIncrement = increments[0];
|
|
128
|
+
const tasks = firstIncrement.tasks.map((task) => ({
|
|
129
|
+
id: task.id,
|
|
130
|
+
title: task.title,
|
|
131
|
+
userStories: task.userStories
|
|
132
|
+
}));
|
|
133
|
+
return {
|
|
134
|
+
incrementId: firstIncrement.id,
|
|
135
|
+
tasks,
|
|
136
|
+
tasksUrl: `https://dev.azure.com/${organization}/${project}/_git/repo?path=/.specweave/increments/${firstIncrement.id}/tasks.md`
|
|
137
|
+
};
|
|
138
|
+
}
|
|
139
|
+
async function findArchitectureDocs(rootDir, specId) {
|
|
140
|
+
const docs = [];
|
|
141
|
+
const archDir = path.join(rootDir, ".specweave/docs/internal/architecture");
|
|
142
|
+
try {
|
|
143
|
+
const adrDir = path.join(archDir, "adr");
|
|
144
|
+
try {
|
|
145
|
+
const adrs = await fs.readdir(adrDir);
|
|
146
|
+
const relatedAdrs = adrs.filter((file) => file.includes(specId.replace("spec-", "")));
|
|
147
|
+
for (const adr of relatedAdrs) {
|
|
148
|
+
docs.push({
|
|
149
|
+
type: "adr",
|
|
150
|
+
path: path.join(adrDir, adr),
|
|
151
|
+
title: adr.replace(".md", "").replace(/-/g, " ")
|
|
152
|
+
});
|
|
153
|
+
}
|
|
154
|
+
} catch {
|
|
155
|
+
}
|
|
156
|
+
} catch {
|
|
157
|
+
}
|
|
158
|
+
return docs;
|
|
159
|
+
}
|
|
160
|
+
async function findExistingFeature(client, specId) {
|
|
161
|
+
try {
|
|
162
|
+
const features = await client.queryWorkItems(`[System.Title] Contains '[${specId}]' AND [System.WorkItemType] = 'Feature'`);
|
|
163
|
+
return features[0] || null;
|
|
164
|
+
} catch {
|
|
165
|
+
return null;
|
|
166
|
+
}
|
|
167
|
+
}
|
|
168
|
+
export {
|
|
169
|
+
syncSpecToAdoWithEnhancedContent
|
|
170
|
+
};
|
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
import { EnhancedContentBuilder } from "../../../src/core/sync/enhanced-content-builder.js";
|
|
2
|
-
import { SpecIncrementMapper } from "../../../src/core/sync/spec-increment-mapper.js";
|
|
3
|
-
import { parseSpecContent } from "../../../src/core/spec-content-sync.js";
|
|
1
|
+
import { EnhancedContentBuilder } from "../../../dist/src/core/sync/enhanced-content-builder.js";
|
|
2
|
+
import { SpecIncrementMapper } from "../../../dist/src/core/sync/spec-increment-mapper.js";
|
|
3
|
+
import { parseSpecContent } from "../../../dist/src/core/spec-content-sync.js";
|
|
4
4
|
import * as path from "path";
|
|
5
5
|
import * as fs from "fs/promises";
|
|
6
6
|
async function syncSpecToJiraWithEnhancedContent(options) {
|