specweave 0.28.33 → 0.28.36
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/README.md +40 -27
- package/dist/plugins/specweave-github/lib/user-story-issue-builder.js +6 -6
- package/dist/plugins/specweave-github/lib/user-story-issue-builder.js.map +1 -1
- package/dist/src/cli/commands/delete-feature.d.ts.map +1 -1
- package/dist/src/cli/commands/delete-feature.js +5 -4
- package/dist/src/cli/commands/delete-feature.js.map +1 -1
- package/dist/src/cli/helpers/init/external-import.d.ts.map +1 -1
- package/dist/src/cli/helpers/init/external-import.js +31 -2
- package/dist/src/cli/helpers/init/external-import.js.map +1 -1
- package/dist/src/core/feature-deleter/github-service.js +2 -2
- package/dist/src/core/feature-deleter/github-service.js.map +1 -1
- package/dist/src/core/increment/increment-archiver.d.ts +43 -6
- package/dist/src/core/increment/increment-archiver.d.ts.map +1 -1
- package/dist/src/core/increment/increment-archiver.js +179 -85
- package/dist/src/core/increment/increment-archiver.js.map +1 -1
- package/dist/src/core/living-docs/feature-id-manager.d.ts +6 -0
- package/dist/src/core/living-docs/feature-id-manager.d.ts.map +1 -1
- package/dist/src/core/living-docs/feature-id-manager.js +54 -8
- package/dist/src/core/living-docs/feature-id-manager.js.map +1 -1
- package/dist/src/core/living-docs/hierarchy-mapper.d.ts.map +1 -1
- package/dist/src/core/living-docs/hierarchy-mapper.js +28 -17
- package/dist/src/core/living-docs/hierarchy-mapper.js.map +1 -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 +26 -4
- package/dist/src/core/living-docs/living-docs-sync.js.map +1 -1
- package/dist/src/core/validation/three-file-validator.js +8 -8
- package/dist/src/core/validation/three-file-validator.js.map +1 -1
- package/dist/src/generators/spec/spec-parser.d.ts.map +1 -1
- package/dist/src/generators/spec/spec-parser.js +4 -3
- package/dist/src/generators/spec/spec-parser.js.map +1 -1
- package/dist/src/generators/spec/task-parser.d.ts.map +1 -1
- package/dist/src/generators/spec/task-parser.js +11 -10
- package/dist/src/generators/spec/task-parser.js.map +1 -1
- package/dist/src/importers/duplicate-detector.d.ts +5 -2
- package/dist/src/importers/duplicate-detector.d.ts.map +1 -1
- package/dist/src/importers/duplicate-detector.js +8 -2
- package/dist/src/importers/duplicate-detector.js.map +1 -1
- package/dist/src/importers/github-importer.d.ts.map +1 -1
- package/dist/src/importers/github-importer.js +24 -1
- package/dist/src/importers/github-importer.js.map +1 -1
- package/dist/src/importers/item-converter.d.ts.map +1 -1
- package/dist/src/importers/item-converter.js +17 -1
- package/dist/src/importers/item-converter.js.map +1 -1
- package/dist/src/living-docs/fs-id-allocator.js +4 -4
- package/dist/src/living-docs/fs-id-allocator.js.map +1 -1
- package/dist/src/utils/feature-id-collision.d.ts +70 -0
- package/dist/src/utils/feature-id-collision.d.ts.map +1 -0
- package/dist/src/utils/feature-id-collision.js +142 -0
- package/dist/src/utils/feature-id-collision.js.map +1 -0
- package/package.json +3 -3
- package/plugins/specweave/lib/vendor/generators/spec/task-parser.js +11 -10
- package/plugins/specweave/lib/vendor/generators/spec/task-parser.js.map +1 -1
- package/plugins/specweave-github/lib/user-story-issue-builder.js +4 -4
- package/plugins/specweave-github/lib/user-story-issue-builder.ts +6 -6
|
@@ -0,0 +1,142 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Feature ID Collision Detection Utility
|
|
3
|
+
*
|
|
4
|
+
* CRITICAL (2025-11-26): Prevents FS-XXX vs FS-XXXE collisions
|
|
5
|
+
*
|
|
6
|
+
* Problem: Internal feature IDs (FS-001) were generated without checking
|
|
7
|
+
* if external features (FS-001E) existed with the same numeric index.
|
|
8
|
+
*
|
|
9
|
+
* Solution: Before generating any internal feature ID, check if either
|
|
10
|
+
* FS-XXX or FS-XXXE exists. If collision detected, increment to next available.
|
|
11
|
+
*
|
|
12
|
+
* Usage:
|
|
13
|
+
* ```typescript
|
|
14
|
+
* // Instead of: const featureId = `FS-${num.toString().padStart(3, '0')}`;
|
|
15
|
+
* // Use:
|
|
16
|
+
* const num = await findNextAvailableInternalId(incrementNum, specsPath, projectId);
|
|
17
|
+
* const featureId = `FS-${num.toString().padStart(3, '0')}`;
|
|
18
|
+
* ```
|
|
19
|
+
*/
|
|
20
|
+
import * as fs from './fs-native.js';
|
|
21
|
+
import path from 'path';
|
|
22
|
+
import { consoleLogger } from './logger.js';
|
|
23
|
+
/**
|
|
24
|
+
* Find the next available internal feature ID number that doesn't collide
|
|
25
|
+
* with existing internal OR external features.
|
|
26
|
+
*
|
|
27
|
+
* CRITICAL: This function prevents FS-001 vs FS-001E collision by checking
|
|
28
|
+
* if either variant exists before returning a number.
|
|
29
|
+
*
|
|
30
|
+
* @param baseNumber - Starting number (typically from increment ID)
|
|
31
|
+
* @param specsPath - Path to specs directory (e.g., .specweave/docs/internal/specs)
|
|
32
|
+
* @param projectId - Project ID for multi-project mode (e.g., "sw-meeting-cost-be")
|
|
33
|
+
* @param options - Optional configuration
|
|
34
|
+
* @returns Next available number that doesn't conflict with existing features
|
|
35
|
+
*
|
|
36
|
+
* @example
|
|
37
|
+
* ```typescript
|
|
38
|
+
* // Increment 0001 would normally generate FS-001
|
|
39
|
+
* // But if FS-001E exists, this returns 2 (for FS-002)
|
|
40
|
+
* const num = await findNextAvailableInternalId(1, specsPath, 'my-project');
|
|
41
|
+
* ```
|
|
42
|
+
*/
|
|
43
|
+
export async function findNextAvailableInternalId(baseNumber, specsPath, projectId, options = {}) {
|
|
44
|
+
const logger = options.logger ?? consoleLogger;
|
|
45
|
+
const maxIterations = options.maxIterations ?? 1000;
|
|
46
|
+
// Build path to project's specs folder
|
|
47
|
+
const projectSpecsPath = path.join(specsPath, projectId);
|
|
48
|
+
// If project folder doesn't exist, no collision possible
|
|
49
|
+
if (!fs.existsSync(projectSpecsPath)) {
|
|
50
|
+
return baseNumber;
|
|
51
|
+
}
|
|
52
|
+
let currentNumber = baseNumber;
|
|
53
|
+
let iterations = 0;
|
|
54
|
+
while (iterations < maxIterations) {
|
|
55
|
+
const internalId = `FS-${currentNumber.toString().padStart(3, '0')}`;
|
|
56
|
+
const externalId = `FS-${currentNumber.toString().padStart(3, '0')}E`;
|
|
57
|
+
const internalPath = path.join(projectSpecsPath, internalId);
|
|
58
|
+
const externalPath = path.join(projectSpecsPath, externalId);
|
|
59
|
+
const internalExists = fs.existsSync(internalPath);
|
|
60
|
+
const externalExists = fs.existsSync(externalPath);
|
|
61
|
+
if (!internalExists && !externalExists) {
|
|
62
|
+
// Found available slot
|
|
63
|
+
if (currentNumber !== baseNumber) {
|
|
64
|
+
logger.warn(`⚠️ Feature ID collision avoided: ${projectId}/FS-${baseNumber.toString().padStart(3, '0')}E exists, ` +
|
|
65
|
+
`using FS-${currentNumber.toString().padStart(3, '0')} instead`);
|
|
66
|
+
}
|
|
67
|
+
return currentNumber;
|
|
68
|
+
}
|
|
69
|
+
// Log what we found for debugging
|
|
70
|
+
if (iterations === 0 && (internalExists || externalExists)) {
|
|
71
|
+
const existingId = externalExists ? externalId : internalId;
|
|
72
|
+
logger.log(` 📋 Checking for collision: ${projectId}/${existingId} exists`);
|
|
73
|
+
}
|
|
74
|
+
currentNumber++;
|
|
75
|
+
iterations++;
|
|
76
|
+
}
|
|
77
|
+
// Safety: Should never reach here
|
|
78
|
+
throw new Error(`Unable to find available feature ID after ${maxIterations} iterations. ` +
|
|
79
|
+
`Started at ${baseNumber}, checked up to ${currentNumber - 1}. ` +
|
|
80
|
+
`This indicates a serious problem with the specs folder.`);
|
|
81
|
+
}
|
|
82
|
+
/**
|
|
83
|
+
* Synchronous version of findNextAvailableInternalId
|
|
84
|
+
*
|
|
85
|
+
* Use this in synchronous contexts where async isn't available.
|
|
86
|
+
*/
|
|
87
|
+
export function findNextAvailableInternalIdSync(baseNumber, specsPath, projectId, options = {}) {
|
|
88
|
+
const logger = options.logger ?? consoleLogger;
|
|
89
|
+
const maxIterations = options.maxIterations ?? 1000;
|
|
90
|
+
// Build path to project's specs folder
|
|
91
|
+
const projectSpecsPath = path.join(specsPath, projectId);
|
|
92
|
+
// If project folder doesn't exist, no collision possible
|
|
93
|
+
if (!fs.existsSync(projectSpecsPath)) {
|
|
94
|
+
return baseNumber;
|
|
95
|
+
}
|
|
96
|
+
let currentNumber = baseNumber;
|
|
97
|
+
let iterations = 0;
|
|
98
|
+
while (iterations < maxIterations) {
|
|
99
|
+
const internalId = `FS-${currentNumber.toString().padStart(3, '0')}`;
|
|
100
|
+
const externalId = `FS-${currentNumber.toString().padStart(3, '0')}E`;
|
|
101
|
+
const internalPath = path.join(projectSpecsPath, internalId);
|
|
102
|
+
const externalPath = path.join(projectSpecsPath, externalId);
|
|
103
|
+
const internalExists = fs.existsSync(internalPath);
|
|
104
|
+
const externalExists = fs.existsSync(externalPath);
|
|
105
|
+
if (!internalExists && !externalExists) {
|
|
106
|
+
// Found available slot
|
|
107
|
+
if (currentNumber !== baseNumber) {
|
|
108
|
+
logger.warn(`⚠️ Feature ID collision avoided: ${projectId}/FS-${baseNumber.toString().padStart(3, '0')}E exists, ` +
|
|
109
|
+
`using FS-${currentNumber.toString().padStart(3, '0')} instead`);
|
|
110
|
+
}
|
|
111
|
+
return currentNumber;
|
|
112
|
+
}
|
|
113
|
+
currentNumber++;
|
|
114
|
+
iterations++;
|
|
115
|
+
}
|
|
116
|
+
// Safety: Should never reach here
|
|
117
|
+
throw new Error(`Unable to find available feature ID after ${maxIterations} iterations.`);
|
|
118
|
+
}
|
|
119
|
+
/**
|
|
120
|
+
* Check if a specific numeric index has a collision (either FS-XXX or FS-XXXE exists)
|
|
121
|
+
*
|
|
122
|
+
* @param number - Numeric index to check
|
|
123
|
+
* @param specsPath - Path to specs directory
|
|
124
|
+
* @param projectId - Project ID
|
|
125
|
+
* @returns Object indicating which variants exist
|
|
126
|
+
*/
|
|
127
|
+
export function checkFeatureIdCollision(number, specsPath, projectId) {
|
|
128
|
+
const projectSpecsPath = path.join(specsPath, projectId);
|
|
129
|
+
if (!fs.existsSync(projectSpecsPath)) {
|
|
130
|
+
return { internalExists: false, externalExists: false, hasCollision: false };
|
|
131
|
+
}
|
|
132
|
+
const internalId = `FS-${number.toString().padStart(3, '0')}`;
|
|
133
|
+
const externalId = `FS-${number.toString().padStart(3, '0')}E`;
|
|
134
|
+
const internalExists = fs.existsSync(path.join(projectSpecsPath, internalId));
|
|
135
|
+
const externalExists = fs.existsSync(path.join(projectSpecsPath, externalId));
|
|
136
|
+
return {
|
|
137
|
+
internalExists,
|
|
138
|
+
externalExists,
|
|
139
|
+
hasCollision: internalExists || externalExists
|
|
140
|
+
};
|
|
141
|
+
}
|
|
142
|
+
//# sourceMappingURL=feature-id-collision.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"feature-id-collision.js","sourceRoot":"","sources":["../../../src/utils/feature-id-collision.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;GAkBG;AAEH,OAAO,KAAK,EAAE,MAAM,gBAAgB,CAAC;AACrC,OAAO,IAAI,MAAM,MAAM,CAAC;AACxB,OAAO,EAAU,aAAa,EAAE,MAAM,aAAa,CAAC;AAapD;;;;;;;;;;;;;;;;;;;GAmBG;AACH,MAAM,CAAC,KAAK,UAAU,2BAA2B,CAC/C,UAAkB,EAClB,SAAiB,EACjB,SAAiB,EACjB,UAAiC,EAAE;IAEnC,MAAM,MAAM,GAAG,OAAO,CAAC,MAAM,IAAI,aAAa,CAAC;IAC/C,MAAM,aAAa,GAAG,OAAO,CAAC,aAAa,IAAI,IAAI,CAAC;IAEpD,uCAAuC;IACvC,MAAM,gBAAgB,GAAG,IAAI,CAAC,IAAI,CAAC,SAAS,EAAE,SAAS,CAAC,CAAC;IAEzD,yDAAyD;IACzD,IAAI,CAAC,EAAE,CAAC,UAAU,CAAC,gBAAgB,CAAC,EAAE,CAAC;QACrC,OAAO,UAAU,CAAC;IACpB,CAAC;IAED,IAAI,aAAa,GAAG,UAAU,CAAC;IAC/B,IAAI,UAAU,GAAG,CAAC,CAAC;IAEnB,OAAO,UAAU,GAAG,aAAa,EAAE,CAAC;QAClC,MAAM,UAAU,GAAG,MAAM,aAAa,CAAC,QAAQ,EAAE,CAAC,QAAQ,CAAC,CAAC,EAAE,GAAG,CAAC,EAAE,CAAC;QACrE,MAAM,UAAU,GAAG,MAAM,aAAa,CAAC,QAAQ,EAAE,CAAC,QAAQ,CAAC,CAAC,EAAE,GAAG,CAAC,GAAG,CAAC;QAEtE,MAAM,YAAY,GAAG,IAAI,CAAC,IAAI,CAAC,gBAAgB,EAAE,UAAU,CAAC,CAAC;QAC7D,MAAM,YAAY,GAAG,IAAI,CAAC,IAAI,CAAC,gBAAgB,EAAE,UAAU,CAAC,CAAC;QAE7D,MAAM,cAAc,GAAG,EAAE,CAAC,UAAU,CAAC,YAAY,CAAC,CAAC;QACnD,MAAM,cAAc,GAAG,EAAE,CAAC,UAAU,CAAC,YAAY,CAAC,CAAC;QAEnD,IAAI,CAAC,cAAc,IAAI,CAAC,cAAc,EAAE,CAAC;YACvC,uBAAuB;YACvB,IAAI,aAAa,KAAK,UAAU,EAAE,CAAC;gBACjC,MAAM,CAAC,IAAI,CACT,oCAAoC,SAAS,OAAO,UAAU,CAAC,QAAQ,EAAE,CAAC,QAAQ,CAAC,CAAC,EAAE,GAAG,CAAC,YAAY;oBACtG,YAAY,aAAa,CAAC,QAAQ,EAAE,CAAC,QAAQ,CAAC,CAAC,EAAE,GAAG,CAAC,UAAU,CAChE,CAAC;YACJ,CAAC;YACD,OAAO,aAAa,CAAC;QACvB,CAAC;QAED,kCAAkC;QAClC,IAAI,UAAU,KAAK,CAAC,IAAI,CAAC,cAAc,IAAI,cAAc,CAAC,EAAE,CAAC;YAC3D,MAAM,UAAU,GAAG,cAAc,CAAC,CAAC,CAAC,UAAU,CAAC,CAAC,CAAC,UAAU,CAAC;YAC5D,MAAM,CAAC,GAAG,CAAC,iCAAiC,SAAS,IAAI,UAAU,SAAS,CAAC,CAAC;QAChF,CAAC;QAED,aAAa,EAAE,CAAC;QAChB,UAAU,EAAE,CAAC;IACf,CAAC;IAED,kCAAkC;IAClC,MAAM,IAAI,KAAK,CACb,6CAA6C,aAAa,eAAe;QACzE,cAAc,UAAU,mBAAmB,aAAa,GAAG,CAAC,IAAI;QAChE,yDAAyD,CAC1D,CAAC;AACJ,CAAC;AAED;;;;GAIG;AACH,MAAM,UAAU,+BAA+B,CAC7C,UAAkB,EAClB,SAAiB,EACjB,SAAiB,EACjB,UAAiC,EAAE;IAEnC,MAAM,MAAM,GAAG,OAAO,CAAC,MAAM,IAAI,aAAa,CAAC;IAC/C,MAAM,aAAa,GAAG,OAAO,CAAC,aAAa,IAAI,IAAI,CAAC;IAEpD,uCAAuC;IACvC,MAAM,gBAAgB,GAAG,IAAI,CAAC,IAAI,CAAC,SAAS,EAAE,SAAS,CAAC,CAAC;IAEzD,yDAAyD;IACzD,IAAI,CAAC,EAAE,CAAC,UAAU,CAAC,gBAAgB,CAAC,EAAE,CAAC;QACrC,OAAO,UAAU,CAAC;IACpB,CAAC;IAED,IAAI,aAAa,GAAG,UAAU,CAAC;IAC/B,IAAI,UAAU,GAAG,CAAC,CAAC;IAEnB,OAAO,UAAU,GAAG,aAAa,EAAE,CAAC;QAClC,MAAM,UAAU,GAAG,MAAM,aAAa,CAAC,QAAQ,EAAE,CAAC,QAAQ,CAAC,CAAC,EAAE,GAAG,CAAC,EAAE,CAAC;QACrE,MAAM,UAAU,GAAG,MAAM,aAAa,CAAC,QAAQ,EAAE,CAAC,QAAQ,CAAC,CAAC,EAAE,GAAG,CAAC,GAAG,CAAC;QAEtE,MAAM,YAAY,GAAG,IAAI,CAAC,IAAI,CAAC,gBAAgB,EAAE,UAAU,CAAC,CAAC;QAC7D,MAAM,YAAY,GAAG,IAAI,CAAC,IAAI,CAAC,gBAAgB,EAAE,UAAU,CAAC,CAAC;QAE7D,MAAM,cAAc,GAAG,EAAE,CAAC,UAAU,CAAC,YAAY,CAAC,CAAC;QACnD,MAAM,cAAc,GAAG,EAAE,CAAC,UAAU,CAAC,YAAY,CAAC,CAAC;QAEnD,IAAI,CAAC,cAAc,IAAI,CAAC,cAAc,EAAE,CAAC;YACvC,uBAAuB;YACvB,IAAI,aAAa,KAAK,UAAU,EAAE,CAAC;gBACjC,MAAM,CAAC,IAAI,CACT,oCAAoC,SAAS,OAAO,UAAU,CAAC,QAAQ,EAAE,CAAC,QAAQ,CAAC,CAAC,EAAE,GAAG,CAAC,YAAY;oBACtG,YAAY,aAAa,CAAC,QAAQ,EAAE,CAAC,QAAQ,CAAC,CAAC,EAAE,GAAG,CAAC,UAAU,CAChE,CAAC;YACJ,CAAC;YACD,OAAO,aAAa,CAAC;QACvB,CAAC;QAED,aAAa,EAAE,CAAC;QAChB,UAAU,EAAE,CAAC;IACf,CAAC;IAED,kCAAkC;IAClC,MAAM,IAAI,KAAK,CACb,6CAA6C,aAAa,cAAc,CACzE,CAAC;AACJ,CAAC;AAED;;;;;;;GAOG;AACH,MAAM,UAAU,uBAAuB,CACrC,MAAc,EACd,SAAiB,EACjB,SAAiB;IAEjB,MAAM,gBAAgB,GAAG,IAAI,CAAC,IAAI,CAAC,SAAS,EAAE,SAAS,CAAC,CAAC;IAEzD,IAAI,CAAC,EAAE,CAAC,UAAU,CAAC,gBAAgB,CAAC,EAAE,CAAC;QACrC,OAAO,EAAE,cAAc,EAAE,KAAK,EAAE,cAAc,EAAE,KAAK,EAAE,YAAY,EAAE,KAAK,EAAE,CAAC;IAC/E,CAAC;IAED,MAAM,UAAU,GAAG,MAAM,MAAM,CAAC,QAAQ,EAAE,CAAC,QAAQ,CAAC,CAAC,EAAE,GAAG,CAAC,EAAE,CAAC;IAC9D,MAAM,UAAU,GAAG,MAAM,MAAM,CAAC,QAAQ,EAAE,CAAC,QAAQ,CAAC,CAAC,EAAE,GAAG,CAAC,GAAG,CAAC;IAE/D,MAAM,cAAc,GAAG,EAAE,CAAC,UAAU,CAAC,IAAI,CAAC,IAAI,CAAC,gBAAgB,EAAE,UAAU,CAAC,CAAC,CAAC;IAC9E,MAAM,cAAc,GAAG,EAAE,CAAC,UAAU,CAAC,IAAI,CAAC,IAAI,CAAC,gBAAgB,EAAE,UAAU,CAAC,CAAC,CAAC;IAE9E,OAAO;QACL,cAAc;QACd,cAAc;QACd,YAAY,EAAE,cAAc,IAAI,cAAc;KAC/C,CAAC;AACJ,CAAC"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "specweave",
|
|
3
|
-
"version": "0.28.
|
|
3
|
+
"version": "0.28.36",
|
|
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",
|
|
@@ -33,8 +33,8 @@
|
|
|
33
33
|
"docs:dev": "cd docs-site && npm start",
|
|
34
34
|
"docs:build": "cd docs-site && npm run build",
|
|
35
35
|
"docs:install": "cd docs-site && npm install --legacy-peer-deps",
|
|
36
|
-
"docs:internal": "
|
|
37
|
-
"docs:internal:build": "
|
|
36
|
+
"docs:internal": "cd docs-site && npm run start:internal",
|
|
37
|
+
"docs:internal:build": "cd docs-site && npm run build:internal",
|
|
38
38
|
"release:patch": "bash scripts/bump-version.sh patch",
|
|
39
39
|
"release:minor": "bash scripts/bump-version.sh minor",
|
|
40
40
|
"release:major": "bash scripts/bump-version.sh major",
|
|
@@ -22,8 +22,9 @@ export function parseTasksWithUSLinks(tasksPath) {
|
|
|
22
22
|
// Split content into lines for line number tracking
|
|
23
23
|
const lines = content.split('\n');
|
|
24
24
|
// Regex patterns for task parsing (T-029: Support E suffix for external IDs)
|
|
25
|
-
|
|
26
|
-
const
|
|
25
|
+
// Updated: Support 3+ digits for T-XXX and US-XXX (Y2K fix)
|
|
26
|
+
const taskHeaderRegex = /^###\s+(T-\d{3,}E?):\s*(.+)$/;
|
|
27
|
+
const userStoryRegex = /^\*\*User Story\*\*:\s*(US-\d{3,}E?)/;
|
|
27
28
|
const satisfiesACsRegex = /^\*\*Satisfies ACs\*\*:\s*(AC-US\d+E?-\d{2}(?:,\s*AC-US\d+E?-\d{2})*)/;
|
|
28
29
|
const statusRegex = /^\*\*Status\*\*:\s*\[([x ])\]\s*(\w+)/;
|
|
29
30
|
const priorityRegex = /^\*\*Priority\*\*:\s*(.+)/;
|
|
@@ -104,11 +105,11 @@ export function parseTasksWithUSLinks(tasksPath) {
|
|
|
104
105
|
}
|
|
105
106
|
const dependenciesMatch = line.match(dependenciesRegex);
|
|
106
107
|
if (dependenciesMatch) {
|
|
107
|
-
// Parse dependencies (T-001, T-002, etc.)
|
|
108
|
+
// Parse dependencies (T-001, T-002, T-1000, etc.)
|
|
108
109
|
currentTask.dependencies = dependenciesMatch[1]
|
|
109
110
|
.split(',')
|
|
110
111
|
.map(dep => dep.trim())
|
|
111
|
-
.filter(dep => dep.match(/^T-\d{3}$/));
|
|
112
|
+
.filter(dep => dep.match(/^T-\d{3,}$/));
|
|
112
113
|
continue;
|
|
113
114
|
}
|
|
114
115
|
// Track sections for description parsing
|
|
@@ -178,14 +179,14 @@ export function validateTaskLinkage(task, validUSIds, validACIds) {
|
|
|
178
179
|
const errors = [];
|
|
179
180
|
// Validate userStory field
|
|
180
181
|
if (task.userStory) {
|
|
181
|
-
// Check format (US-XXX)
|
|
182
|
-
if (!task.userStory.match(/^US-\d{3}$/)) {
|
|
182
|
+
// Check format (US-XXX, 3+ digits)
|
|
183
|
+
if (!task.userStory.match(/^US-\d{3,}$/)) {
|
|
183
184
|
errors.push({
|
|
184
185
|
taskId: task.id,
|
|
185
186
|
field: 'userStory',
|
|
186
187
|
value: task.userStory,
|
|
187
|
-
message: `Invalid US-ID format: "${task.userStory}" (expected format: US-001)`,
|
|
188
|
-
suggestedFix: 'Use format: US-XXX where XXX is
|
|
188
|
+
message: `Invalid US-ID format: "${task.userStory}" (expected format: US-001 or US-1000)`,
|
|
189
|
+
suggestedFix: 'Use format: US-XXX where XXX is 3 or more digits'
|
|
189
190
|
});
|
|
190
191
|
}
|
|
191
192
|
// Check if US exists in spec.md
|
|
@@ -250,10 +251,10 @@ function extractUSNumberFromACId(acId) {
|
|
|
250
251
|
return match ? parseInt(match[1], 10) : -1;
|
|
251
252
|
}
|
|
252
253
|
/**
|
|
253
|
-
* Extract US number from US-ID (US-001 → 1)
|
|
254
|
+
* Extract US number from US-ID (US-001 → 1, US-1000 → 1000)
|
|
254
255
|
*/
|
|
255
256
|
function extractUSNumber(usId) {
|
|
256
|
-
const match = usId.match(/^US-(\d{3})$/);
|
|
257
|
+
const match = usId.match(/^US-(\d{3,})$/);
|
|
257
258
|
return match ? parseInt(match[1], 10) : -1;
|
|
258
259
|
}
|
|
259
260
|
/**
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"task-parser.js","sourceRoot":"","sources":["../../../../src/generators/spec/task-parser.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAEH,OAAO,EAAE,YAAY,EAAE,MAAM,IAAI,CAAC;AAgElC;;;;;;GAMG;AACH,MAAM,UAAU,qBAAqB,CAAC,SAAiB;IACrD,IAAI,CAAC;QACH,MAAM,OAAO,GAAG,YAAY,CAAC,SAAS,EAAE,OAAO,CAAC,CAAC;QACjD,MAAM,KAAK,GAAqB,EAAE,CAAC;QAEnC,oDAAoD;QACpD,MAAM,KAAK,GAAG,OAAO,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC;QAElC,6EAA6E;QAC7E,MAAM,eAAe,GAAG,
|
|
1
|
+
{"version":3,"file":"task-parser.js","sourceRoot":"","sources":["../../../../src/generators/spec/task-parser.ts"],"names":[],"mappings":"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"}
|
|
@@ -12,10 +12,10 @@ This prevents incorrect issue titles like [undefined][US-XXX] or [SP-US-XXX].
|
|
|
12
12
|
Provide the correct Feature ID (e.g., "FS-047") when constructing this builder.`
|
|
13
13
|
);
|
|
14
14
|
}
|
|
15
|
-
if (!/^FS-\d{3}$/.test(featureId)) {
|
|
15
|
+
if (!/^FS-\d{3,}$/.test(featureId)) {
|
|
16
16
|
throw new Error(
|
|
17
17
|
`UserStoryIssueBuilder: Invalid featureId format "${featureId}".
|
|
18
|
-
Expected format: FS-XXX (e.g., "FS-047", "FS-123").
|
|
18
|
+
Expected format: FS-XXX (e.g., "FS-047", "FS-123", "FS-1000").
|
|
19
19
|
This prevents incorrect issue titles like [SP-US-XXX] or [${featureId}][US-XXX].`
|
|
20
20
|
);
|
|
21
21
|
}
|
|
@@ -43,11 +43,11 @@ This prevents incorrect issue titles like [SP-US-XXX] or [${featureId}][US-XXX].
|
|
|
43
43
|
const acceptanceCriteria = this.extractAcceptanceCriteria(bodyContent);
|
|
44
44
|
const tasks = await this.extractTasks(bodyContent, frontmatter.id);
|
|
45
45
|
const title = `[${this.featureId}][${frontmatter.id}] ${frontmatter.title}`;
|
|
46
|
-
const titlePattern = /^\[FS-\d{3}\]\[US-\d{3}\] .+$/;
|
|
46
|
+
const titlePattern = /^\[FS-\d{3,}\]\[US-\d{3,}\] .+$/;
|
|
47
47
|
if (!titlePattern.test(title)) {
|
|
48
48
|
throw new Error(
|
|
49
49
|
`Generated issue title has incorrect format: "${title}"
|
|
50
|
-
Expected: [FS-XXX][US-YYY] Title
|
|
50
|
+
Expected: [FS-XXX][US-YYY] Title (3+ digits each)
|
|
51
51
|
This indicates a bug in UserStoryIssueBuilder or invalid frontmatter.
|
|
52
52
|
Feature ID: ${this.featureId}
|
|
53
53
|
User Story ID: ${frontmatter.id}`
|
|
@@ -65,11 +65,11 @@ export class UserStoryIssueBuilder {
|
|
|
65
65
|
);
|
|
66
66
|
}
|
|
67
67
|
|
|
68
|
-
// ✅ VALIDATION: Ensure featureId matches expected pattern (FS-XXX)
|
|
69
|
-
if (!/^FS-\d{3}$/.test(featureId)) {
|
|
68
|
+
// ✅ VALIDATION: Ensure featureId matches expected pattern (FS-XXX, 3+ digits)
|
|
69
|
+
if (!/^FS-\d{3,}$/.test(featureId)) {
|
|
70
70
|
throw new Error(
|
|
71
71
|
`UserStoryIssueBuilder: Invalid featureId format "${featureId}".\n` +
|
|
72
|
-
`Expected format: FS-XXX (e.g., "FS-047", "FS-123").\n` +
|
|
72
|
+
`Expected format: FS-XXX (e.g., "FS-047", "FS-123", "FS-1000").\n` +
|
|
73
73
|
`This prevents incorrect issue titles like [SP-US-XXX] or [${featureId}][US-XXX].`
|
|
74
74
|
);
|
|
75
75
|
}
|
|
@@ -114,12 +114,12 @@ export class UserStoryIssueBuilder {
|
|
|
114
114
|
// This prevents issues like [SP-US-XXX] or [undefined][US-XXX]
|
|
115
115
|
const title = `[${this.featureId}][${frontmatter.id}] ${frontmatter.title}`;
|
|
116
116
|
|
|
117
|
-
// ✅ SAFETY CHECK: Ensure title matches expected pattern
|
|
118
|
-
const titlePattern = /^\[FS-\d{3}\]\[US-\d{3}\] .+$/;
|
|
117
|
+
// ✅ SAFETY CHECK: Ensure title matches expected pattern (3+ digits)
|
|
118
|
+
const titlePattern = /^\[FS-\d{3,}\]\[US-\d{3,}\] .+$/;
|
|
119
119
|
if (!titlePattern.test(title)) {
|
|
120
120
|
throw new Error(
|
|
121
121
|
`Generated issue title has incorrect format: "${title}"\n` +
|
|
122
|
-
`Expected: [FS-XXX][US-YYY] Title\n` +
|
|
122
|
+
`Expected: [FS-XXX][US-YYY] Title (3+ digits each)\n` +
|
|
123
123
|
`This indicates a bug in UserStoryIssueBuilder or invalid frontmatter.\n` +
|
|
124
124
|
`Feature ID: ${this.featureId}\n` +
|
|
125
125
|
`User Story ID: ${frontmatter.id}`
|