specweave 0.28.20 → 0.28.24
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/dist/src/cli/commands/init.d.ts.map +1 -1
- package/dist/src/cli/commands/init.js +7 -3
- package/dist/src/cli/commands/init.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 +8 -5
- package/dist/src/cli/helpers/init/external-import.js.map +1 -1
- package/dist/src/cli/helpers/init/initial-increment-generator.d.ts.map +1 -1
- package/dist/src/cli/helpers/init/initial-increment-generator.js +123 -35
- package/dist/src/cli/helpers/init/initial-increment-generator.js.map +1 -1
- package/dist/src/cli/helpers/init/language-selection.js +1 -1
- package/dist/src/cli/helpers/init/language-selection.js.map +1 -1
- package/dist/src/cli/helpers/init/next-steps.d.ts.map +1 -1
- package/dist/src/cli/helpers/init/next-steps.js +16 -47
- package/dist/src/cli/helpers/init/next-steps.js.map +1 -1
- package/dist/src/cli/helpers/init/repository-setup.js +1 -1
- package/dist/src/cli/helpers/init/repository-setup.js.map +1 -1
- package/dist/src/core/repo-structure/prompt-consolidator.d.ts.map +1 -1
- package/dist/src/core/repo-structure/prompt-consolidator.js +6 -36
- package/dist/src/core/repo-structure/prompt-consolidator.js.map +1 -1
- package/dist/src/core/repo-structure/repo-initializer.d.ts.map +1 -1
- package/dist/src/core/repo-structure/repo-initializer.js +8 -0
- package/dist/src/core/repo-structure/repo-initializer.js.map +1 -1
- package/dist/src/core/sync/bidirectional-engine.d.ts.map +1 -1
- package/dist/src/core/sync/bidirectional-engine.js +3 -1
- package/dist/src/core/sync/bidirectional-engine.js.map +1 -1
- package/dist/src/importers/import-coordinator.d.ts.map +1 -1
- package/dist/src/importers/import-coordinator.js +17 -0
- package/dist/src/importers/import-coordinator.js.map +1 -1
- package/dist/src/init/repo/types.d.ts +1 -1
- package/dist/src/utils/multi-project-detector.d.ts +92 -0
- package/dist/src/utils/multi-project-detector.d.ts.map +1 -0
- package/dist/src/utils/multi-project-detector.js +369 -0
- package/dist/src/utils/multi-project-detector.js.map +1 -0
- package/package.json +1 -1
- package/plugins/specweave/agents/pm/AGENT.md +33 -12
- package/plugins/specweave/commands/specweave-import-external.md +1 -1
- package/plugins/specweave/commands/specweave.md +1 -1
- package/plugins/specweave/skills/increment-planner/SKILL.md +6 -13
- package/plugins/specweave/skills/spec-generator/SKILL.md +6 -11
- package/plugins/specweave-ado/commands/specweave-ado-sync.md +12 -12
- package/plugins/specweave-github/agents/github-manager/AGENT.md +5 -5
- package/plugins/specweave-github/commands/specweave-github-sync.md +12 -12
- package/plugins/specweave-github/commands/specweave-github-update-user-story.md +1 -1
- package/plugins/specweave-github/skills/github-sync/SKILL.md +4 -4
- package/plugins/specweave-jira/commands/specweave-jira-sync.md +11 -11
- package/plugins/specweave-jira/skills/specweave-jira-mapper/SKILL.md +2 -2
- package/plugins/specweave-release/commands/specweave-release-npm.md +187 -8
|
@@ -0,0 +1,369 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Multi-Project Detector
|
|
3
|
+
*
|
|
4
|
+
* Detects multi-project/umbrella configuration from:
|
|
5
|
+
* 1. config.json (umbrella.enabled, multiProject.enabled)
|
|
6
|
+
* 2. childRepos configuration
|
|
7
|
+
* 3. Project folders in specs/
|
|
8
|
+
* 4. Sync profile projects
|
|
9
|
+
*
|
|
10
|
+
* Used by PM Agent, spec generators, and initial-increment-generator
|
|
11
|
+
* to determine whether to generate project-scoped user stories.
|
|
12
|
+
*
|
|
13
|
+
* @module utils/multi-project-detector
|
|
14
|
+
*/
|
|
15
|
+
import * as fs from './fs-native.js';
|
|
16
|
+
import path from 'path';
|
|
17
|
+
/**
|
|
18
|
+
* Default project prefixes for common architectures
|
|
19
|
+
*/
|
|
20
|
+
const DEFAULT_PROJECT_PREFIXES = {
|
|
21
|
+
'fe': 'FE',
|
|
22
|
+
'frontend': 'FE',
|
|
23
|
+
'web': 'FE',
|
|
24
|
+
'ui': 'FE',
|
|
25
|
+
'client': 'FE',
|
|
26
|
+
'be': 'BE',
|
|
27
|
+
'backend': 'BE',
|
|
28
|
+
'api': 'BE',
|
|
29
|
+
'server': 'BE',
|
|
30
|
+
'service': 'BE',
|
|
31
|
+
'shared': 'SHARED',
|
|
32
|
+
'common': 'SHARED',
|
|
33
|
+
'lib': 'SHARED',
|
|
34
|
+
'types': 'SHARED',
|
|
35
|
+
'mobile': 'MOBILE',
|
|
36
|
+
'ios': 'MOBILE',
|
|
37
|
+
'android': 'MOBILE',
|
|
38
|
+
'app': 'MOBILE',
|
|
39
|
+
'infra': 'INFRA',
|
|
40
|
+
'infrastructure': 'INFRA',
|
|
41
|
+
'devops': 'INFRA',
|
|
42
|
+
'deploy': 'INFRA',
|
|
43
|
+
};
|
|
44
|
+
/**
|
|
45
|
+
* Infer project prefix from project ID/name
|
|
46
|
+
*/
|
|
47
|
+
export function inferProjectPrefix(projectId) {
|
|
48
|
+
const normalizedId = projectId.toLowerCase();
|
|
49
|
+
// Check for exact matches first
|
|
50
|
+
if (DEFAULT_PROJECT_PREFIXES[normalizedId]) {
|
|
51
|
+
return DEFAULT_PROJECT_PREFIXES[normalizedId];
|
|
52
|
+
}
|
|
53
|
+
// Check for suffix matches (e.g., 'my-app-fe' → 'FE')
|
|
54
|
+
for (const [key, prefix] of Object.entries(DEFAULT_PROJECT_PREFIXES)) {
|
|
55
|
+
if (normalizedId.endsWith(`-${key}`) || normalizedId.endsWith(`_${key}`)) {
|
|
56
|
+
return prefix;
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
// Check for contains (e.g., 'frontend-service' → 'FE')
|
|
60
|
+
for (const [key, prefix] of Object.entries(DEFAULT_PROJECT_PREFIXES)) {
|
|
61
|
+
if (normalizedId.includes(key)) {
|
|
62
|
+
return prefix;
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
// Default: uppercase first part of ID
|
|
66
|
+
const parts = projectId.split(/[-_]/);
|
|
67
|
+
return parts[0].toUpperCase().slice(0, 6);
|
|
68
|
+
}
|
|
69
|
+
/**
|
|
70
|
+
* Parse project configuration from childRepos
|
|
71
|
+
*/
|
|
72
|
+
function parseChildRepos(childRepos) {
|
|
73
|
+
const projects = [];
|
|
74
|
+
for (const repo of childRepos) {
|
|
75
|
+
if (!repo.id)
|
|
76
|
+
continue;
|
|
77
|
+
projects.push({
|
|
78
|
+
id: repo.id,
|
|
79
|
+
prefix: repo.prefix || inferProjectPrefix(repo.id),
|
|
80
|
+
name: repo.displayName || repo.id,
|
|
81
|
+
path: repo.path
|
|
82
|
+
});
|
|
83
|
+
}
|
|
84
|
+
return projects;
|
|
85
|
+
}
|
|
86
|
+
/**
|
|
87
|
+
* Parse project configuration from multiProject.projects
|
|
88
|
+
*/
|
|
89
|
+
function parseMultiProjectConfig(projectsConfig) {
|
|
90
|
+
const projects = [];
|
|
91
|
+
for (const [id, config] of Object.entries(projectsConfig)) {
|
|
92
|
+
if (typeof config !== 'object')
|
|
93
|
+
continue;
|
|
94
|
+
projects.push({
|
|
95
|
+
id: id,
|
|
96
|
+
prefix: config.prefix || inferProjectPrefix(id),
|
|
97
|
+
name: config.name || config.displayName || id,
|
|
98
|
+
path: config.path
|
|
99
|
+
});
|
|
100
|
+
}
|
|
101
|
+
return projects;
|
|
102
|
+
}
|
|
103
|
+
/**
|
|
104
|
+
* Detect projects from specs folder structure
|
|
105
|
+
*/
|
|
106
|
+
function detectProjectsFromFolders(specsPath) {
|
|
107
|
+
const projects = [];
|
|
108
|
+
if (!fs.existsSync(specsPath)) {
|
|
109
|
+
return projects;
|
|
110
|
+
}
|
|
111
|
+
try {
|
|
112
|
+
const entries = fs.readdirSync(specsPath, { withFileTypes: true });
|
|
113
|
+
for (const entry of entries) {
|
|
114
|
+
// Skip non-directories and special folders
|
|
115
|
+
if (!entry.isDirectory())
|
|
116
|
+
continue;
|
|
117
|
+
if (entry.name.startsWith('.') || entry.name.startsWith('_'))
|
|
118
|
+
continue;
|
|
119
|
+
if (entry.name === 'default')
|
|
120
|
+
continue;
|
|
121
|
+
projects.push({
|
|
122
|
+
id: entry.name,
|
|
123
|
+
prefix: inferProjectPrefix(entry.name),
|
|
124
|
+
name: entry.name,
|
|
125
|
+
path: path.join(specsPath, entry.name)
|
|
126
|
+
});
|
|
127
|
+
}
|
|
128
|
+
}
|
|
129
|
+
catch {
|
|
130
|
+
// Ignore read errors
|
|
131
|
+
}
|
|
132
|
+
return projects;
|
|
133
|
+
}
|
|
134
|
+
/**
|
|
135
|
+
* Parse projects from sync profile configuration
|
|
136
|
+
*/
|
|
137
|
+
function parseProjectsFromSyncProfiles(syncConfig) {
|
|
138
|
+
const projects = [];
|
|
139
|
+
const seenIds = new Set();
|
|
140
|
+
if (!syncConfig?.profiles)
|
|
141
|
+
return projects;
|
|
142
|
+
for (const [, profile] of Object.entries(syncConfig.profiles)) {
|
|
143
|
+
const profileConfig = profile?.config;
|
|
144
|
+
if (!profileConfig)
|
|
145
|
+
continue;
|
|
146
|
+
// Check for boardMapping (JIRA)
|
|
147
|
+
if (profileConfig.boardMapping) {
|
|
148
|
+
for (const [boardName, projectId] of Object.entries(profileConfig.boardMapping)) {
|
|
149
|
+
const id = String(projectId);
|
|
150
|
+
if (seenIds.has(id))
|
|
151
|
+
continue;
|
|
152
|
+
seenIds.add(id);
|
|
153
|
+
projects.push({
|
|
154
|
+
id: id,
|
|
155
|
+
prefix: inferProjectPrefix(id),
|
|
156
|
+
name: boardName || id
|
|
157
|
+
});
|
|
158
|
+
}
|
|
159
|
+
}
|
|
160
|
+
// Check for areaPathMapping (ADO)
|
|
161
|
+
if (profileConfig.areaPathMapping) {
|
|
162
|
+
for (const [areaPath, projectId] of Object.entries(profileConfig.areaPathMapping)) {
|
|
163
|
+
const id = String(projectId);
|
|
164
|
+
if (seenIds.has(id))
|
|
165
|
+
continue;
|
|
166
|
+
seenIds.add(id);
|
|
167
|
+
projects.push({
|
|
168
|
+
id: id,
|
|
169
|
+
prefix: inferProjectPrefix(id),
|
|
170
|
+
name: areaPath.split('\\').pop() || id
|
|
171
|
+
});
|
|
172
|
+
}
|
|
173
|
+
}
|
|
174
|
+
// Check for projects array
|
|
175
|
+
if (profileConfig.projects && Array.isArray(profileConfig.projects)) {
|
|
176
|
+
for (const projectId of profileConfig.projects) {
|
|
177
|
+
const id = String(projectId);
|
|
178
|
+
if (seenIds.has(id))
|
|
179
|
+
continue;
|
|
180
|
+
seenIds.add(id);
|
|
181
|
+
projects.push({
|
|
182
|
+
id: id,
|
|
183
|
+
prefix: inferProjectPrefix(id),
|
|
184
|
+
name: id
|
|
185
|
+
});
|
|
186
|
+
}
|
|
187
|
+
}
|
|
188
|
+
}
|
|
189
|
+
return projects;
|
|
190
|
+
}
|
|
191
|
+
/**
|
|
192
|
+
* Detect multi-project configuration
|
|
193
|
+
*
|
|
194
|
+
* @param projectRoot - Path to project root (default: process.cwd())
|
|
195
|
+
* @returns Detection result with project information
|
|
196
|
+
*/
|
|
197
|
+
export function detectMultiProjectMode(projectRoot = process.cwd()) {
|
|
198
|
+
const configPath = path.join(projectRoot, '.specweave', 'config.json');
|
|
199
|
+
const specsPath = path.join(projectRoot, '.specweave', 'docs', 'internal', 'specs');
|
|
200
|
+
let config = {};
|
|
201
|
+
// Read config.json if exists
|
|
202
|
+
if (fs.existsSync(configPath)) {
|
|
203
|
+
try {
|
|
204
|
+
config = JSON.parse(fs.readFileSync(configPath, 'utf-8'));
|
|
205
|
+
}
|
|
206
|
+
catch {
|
|
207
|
+
// Ignore parse errors
|
|
208
|
+
}
|
|
209
|
+
}
|
|
210
|
+
// Check 1: umbrella.enabled with 2+ child repos
|
|
211
|
+
if (config.umbrella?.enabled === true) {
|
|
212
|
+
const projects = config.umbrella?.childRepos
|
|
213
|
+
? parseChildRepos(config.umbrella.childRepos)
|
|
214
|
+
: [];
|
|
215
|
+
// Multi-project requires 2+ projects (1 project = single-project mode)
|
|
216
|
+
if (projects.length > 1) {
|
|
217
|
+
return {
|
|
218
|
+
isMultiProject: true,
|
|
219
|
+
detectionReason: 'umbrella.enabled with childRepos',
|
|
220
|
+
projects,
|
|
221
|
+
umbrellaEnabled: true,
|
|
222
|
+
hasBoardMapping: false
|
|
223
|
+
};
|
|
224
|
+
}
|
|
225
|
+
}
|
|
226
|
+
// Check 2: multiProject.enabled with 2+ projects
|
|
227
|
+
if (config.multiProject?.enabled === true) {
|
|
228
|
+
const projects = config.multiProject?.projects
|
|
229
|
+
? parseMultiProjectConfig(config.multiProject.projects)
|
|
230
|
+
: [];
|
|
231
|
+
// Multi-project requires 2+ projects (1 project = single-project mode)
|
|
232
|
+
if (projects.length > 1) {
|
|
233
|
+
return {
|
|
234
|
+
isMultiProject: true,
|
|
235
|
+
detectionReason: 'multiProject.enabled with projects config',
|
|
236
|
+
projects,
|
|
237
|
+
umbrellaEnabled: false,
|
|
238
|
+
hasBoardMapping: false
|
|
239
|
+
};
|
|
240
|
+
}
|
|
241
|
+
}
|
|
242
|
+
// Check 3: Sync profile with board/area path mapping
|
|
243
|
+
if (config.sync?.profiles) {
|
|
244
|
+
const syncProjects = parseProjectsFromSyncProfiles(config.sync);
|
|
245
|
+
const hasBoardMapping = Object.values(config.sync.profiles).some((p) => p?.config?.boardMapping || p?.config?.areaPathMapping);
|
|
246
|
+
if (syncProjects.length > 1) {
|
|
247
|
+
return {
|
|
248
|
+
isMultiProject: true,
|
|
249
|
+
detectionReason: 'sync profiles with multiple projects',
|
|
250
|
+
projects: syncProjects,
|
|
251
|
+
umbrellaEnabled: false,
|
|
252
|
+
hasBoardMapping
|
|
253
|
+
};
|
|
254
|
+
}
|
|
255
|
+
}
|
|
256
|
+
// Check 4: Multiple project folders in specs/
|
|
257
|
+
const folderProjects = detectProjectsFromFolders(specsPath);
|
|
258
|
+
if (folderProjects.length > 1) {
|
|
259
|
+
return {
|
|
260
|
+
isMultiProject: true,
|
|
261
|
+
detectionReason: 'multiple project folders in specs/',
|
|
262
|
+
projects: folderProjects,
|
|
263
|
+
umbrellaEnabled: false,
|
|
264
|
+
hasBoardMapping: false
|
|
265
|
+
};
|
|
266
|
+
}
|
|
267
|
+
// Single project mode
|
|
268
|
+
return {
|
|
269
|
+
isMultiProject: false,
|
|
270
|
+
detectionReason: 'no multi-project configuration detected',
|
|
271
|
+
projects: [],
|
|
272
|
+
umbrellaEnabled: false,
|
|
273
|
+
hasBoardMapping: false
|
|
274
|
+
};
|
|
275
|
+
}
|
|
276
|
+
/**
|
|
277
|
+
* Get project prefixes for user story generation
|
|
278
|
+
*
|
|
279
|
+
* @param projectRoot - Path to project root
|
|
280
|
+
* @returns Array of project prefixes (e.g., ['FE', 'BE', 'SHARED'])
|
|
281
|
+
*/
|
|
282
|
+
export function getProjectPrefixes(projectRoot = process.cwd()) {
|
|
283
|
+
const detection = detectMultiProjectMode(projectRoot);
|
|
284
|
+
if (!detection.isMultiProject || detection.projects.length === 0) {
|
|
285
|
+
return [];
|
|
286
|
+
}
|
|
287
|
+
return detection.projects.map(p => p.prefix);
|
|
288
|
+
}
|
|
289
|
+
/**
|
|
290
|
+
* Get project by prefix
|
|
291
|
+
*
|
|
292
|
+
* @param prefix - Project prefix (e.g., 'FE')
|
|
293
|
+
* @param projectRoot - Path to project root
|
|
294
|
+
* @returns Project or undefined
|
|
295
|
+
*/
|
|
296
|
+
export function getProjectByPrefix(prefix, projectRoot = process.cwd()) {
|
|
297
|
+
const detection = detectMultiProjectMode(projectRoot);
|
|
298
|
+
return detection.projects.find(p => p.prefix.toUpperCase() === prefix.toUpperCase());
|
|
299
|
+
}
|
|
300
|
+
/**
|
|
301
|
+
* Format user story ID with project prefix (if multi-project)
|
|
302
|
+
*
|
|
303
|
+
* @param storyNumber - Story number (1, 2, 3...)
|
|
304
|
+
* @param projectPrefix - Optional project prefix (e.g., 'FE')
|
|
305
|
+
* @param projectRoot - Path to project root
|
|
306
|
+
* @returns Formatted ID (e.g., 'US-FE-001' or 'US-001')
|
|
307
|
+
*/
|
|
308
|
+
export function formatUserStoryId(storyNumber, projectPrefix, projectRoot = process.cwd()) {
|
|
309
|
+
const paddedNumber = String(storyNumber).padStart(3, '0');
|
|
310
|
+
if (projectPrefix) {
|
|
311
|
+
return `US-${projectPrefix.toUpperCase()}-${paddedNumber}`;
|
|
312
|
+
}
|
|
313
|
+
// Auto-detect if multi-project
|
|
314
|
+
const detection = detectMultiProjectMode(projectRoot);
|
|
315
|
+
if (detection.isMultiProject) {
|
|
316
|
+
// If multi-project but no prefix provided, use generic format
|
|
317
|
+
// (caller should provide prefix for proper scoping)
|
|
318
|
+
return `US-${paddedNumber}`;
|
|
319
|
+
}
|
|
320
|
+
return `US-${paddedNumber}`;
|
|
321
|
+
}
|
|
322
|
+
/**
|
|
323
|
+
* Format acceptance criteria ID with project prefix (if multi-project)
|
|
324
|
+
*
|
|
325
|
+
* @param userStoryNumber - User story number (1, 2, 3...)
|
|
326
|
+
* @param acNumber - Acceptance criteria number within story (1, 2, 3...)
|
|
327
|
+
* @param projectPrefix - Optional project prefix (e.g., 'FE')
|
|
328
|
+
* @returns Formatted ID (e.g., 'AC-FE-US1-01' or 'AC-US1-01')
|
|
329
|
+
*/
|
|
330
|
+
export function formatAcceptanceCriteriaId(userStoryNumber, acNumber, projectPrefix) {
|
|
331
|
+
const paddedAcNumber = String(acNumber).padStart(2, '0');
|
|
332
|
+
if (projectPrefix) {
|
|
333
|
+
return `AC-${projectPrefix.toUpperCase()}-US${userStoryNumber}-${paddedAcNumber}`;
|
|
334
|
+
}
|
|
335
|
+
return `AC-US${userStoryNumber}-${paddedAcNumber}`;
|
|
336
|
+
}
|
|
337
|
+
/**
|
|
338
|
+
* Generate template variables for multi-project spec
|
|
339
|
+
*
|
|
340
|
+
* @param detection - Multi-project detection result
|
|
341
|
+
* @returns Template variable map
|
|
342
|
+
*/
|
|
343
|
+
export function generateMultiProjectTemplateVars(detection) {
|
|
344
|
+
const vars = {
|
|
345
|
+
MULTI_PROJECT: detection.isMultiProject ? 'true' : 'false'
|
|
346
|
+
};
|
|
347
|
+
if (!detection.isMultiProject) {
|
|
348
|
+
return vars;
|
|
349
|
+
}
|
|
350
|
+
// Add project-specific variables
|
|
351
|
+
for (const project of detection.projects) {
|
|
352
|
+
const prefixUpper = project.prefix.toUpperCase();
|
|
353
|
+
vars[`PROJECT_${prefixUpper}_ID`] = project.id;
|
|
354
|
+
vars[`PROJECT_${prefixUpper}_PREFIX`] = project.prefix;
|
|
355
|
+
vars[`PROJECT_${prefixUpper}_NAME`] = project.name;
|
|
356
|
+
}
|
|
357
|
+
// Add common project IDs for templates
|
|
358
|
+
const feProject = detection.projects.find(p => p.prefix.toUpperCase() === 'FE');
|
|
359
|
+
const beProject = detection.projects.find(p => p.prefix.toUpperCase() === 'BE');
|
|
360
|
+
const sharedProject = detection.projects.find(p => p.prefix.toUpperCase() === 'SHARED' || p.prefix.toUpperCase() === 'COMMON');
|
|
361
|
+
if (feProject)
|
|
362
|
+
vars.PROJECT_FE_ID = feProject.id;
|
|
363
|
+
if (beProject)
|
|
364
|
+
vars.PROJECT_BE_ID = beProject.id;
|
|
365
|
+
if (sharedProject)
|
|
366
|
+
vars.PROJECT_SHARED_ID = sharedProject.id;
|
|
367
|
+
return vars;
|
|
368
|
+
}
|
|
369
|
+
//# sourceMappingURL=multi-project-detector.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"multi-project-detector.js","sourceRoot":"","sources":["../../../src/utils/multi-project-detector.ts"],"names":[],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "specweave",
|
|
3
|
-
"version": "0.28.
|
|
3
|
+
"version": "0.28.24",
|
|
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",
|
|
@@ -445,24 +445,44 @@ graph TD
|
|
|
445
445
|
|
|
446
446
|
**YOU MUST CHECK THIS BEFORE WRITING ANY USER STORIES:**
|
|
447
447
|
|
|
448
|
-
|
|
449
|
-
# 1. Check config.json for umbrella mode
|
|
450
|
-
cat .specweave/config.json | jq '.umbrella.enabled'
|
|
448
|
+
**Detection Utility** (`src/utils/multi-project-detector.ts`): SpecWeave has automated multi-project detection. When generating specs programmatically, use `detectMultiProjectMode(projectRoot)`. For manual checks, run these commands:
|
|
451
449
|
|
|
452
|
-
|
|
453
|
-
|
|
450
|
+
```bash
|
|
451
|
+
# Quick check: Is multi-project mode enabled?
|
|
452
|
+
Read .specweave/config.json and check for:
|
|
453
|
+
# - umbrella.enabled: true
|
|
454
|
+
# - multiProject.enabled: true
|
|
455
|
+
# - umbrella.childRepos[] (array of repos)
|
|
456
|
+
# - sync.profiles[].config.boardMapping or areaPathMapping
|
|
454
457
|
|
|
455
|
-
#
|
|
456
|
-
|
|
458
|
+
# Alternative: Check for multiple project folders
|
|
459
|
+
Glob ".specweave/docs/internal/specs/*/" and count directories
|
|
460
|
+
# If > 1 directory (excluding 'default') → multi-project mode
|
|
457
461
|
```
|
|
458
462
|
|
|
459
463
|
**Decision Flow:**
|
|
460
464
|
```
|
|
461
|
-
|
|
462
|
-
|
|
463
|
-
|
|
464
|
-
|
|
465
|
-
|
|
465
|
+
Step 1: Read .specweave/config.json
|
|
466
|
+
Step 2: Check THESE conditions (ANY = multi-project):
|
|
467
|
+
├─ umbrella.enabled === true AND childRepos.length > 0?
|
|
468
|
+
│ → YES → Use project prefixes from childRepos[].prefix
|
|
469
|
+
├─ multiProject.enabled === true AND projects object has keys?
|
|
470
|
+
│ → YES → Use project prefixes from projects object
|
|
471
|
+
├─ sync.profiles[].config.boardMapping exists?
|
|
472
|
+
│ → YES → Use project IDs from boardMapping values
|
|
473
|
+
├─ Multiple folders in .specweave/docs/internal/specs/?
|
|
474
|
+
│ → YES → Use folder names as project IDs
|
|
475
|
+
└─ User prompt mentions "frontend", "backend", "3 repos"?
|
|
476
|
+
→ YES → Ask user to confirm project prefixes
|
|
477
|
+
|
|
478
|
+
Step 3: If multi-project detected:
|
|
479
|
+
→ MUST use project-scoped user stories (US-FE-001, US-BE-001)
|
|
480
|
+
→ MUST use project-scoped ACs (AC-FE-US1-01, AC-BE-US1-01)
|
|
481
|
+
→ Include 'projects:' array in spec.md frontmatter
|
|
482
|
+
|
|
483
|
+
Step 4: If NO multi-project config:
|
|
484
|
+
→ Use standard user stories (US-001, US-002)
|
|
485
|
+
→ Use standard ACs (AC-US1-01, AC-US2-01)
|
|
466
486
|
```
|
|
467
487
|
|
|
468
488
|
**If multi-project detected, NEVER generate:**
|
|
@@ -472,6 +492,7 @@ Is umbrella.enabled: true?
|
|
|
472
492
|
**ALWAYS generate:**
|
|
473
493
|
- ✅ `US-FE-001`, `US-BE-001`, `US-SHARED-001` (project-scoped)
|
|
474
494
|
- ✅ `AC-FE-US1-01`, `AC-BE-US1-01` (project-scoped ACs)
|
|
495
|
+
- ✅ Frontmatter with `multi_project: true` and `projects:` array
|
|
475
496
|
|
|
476
497
|
---
|
|
477
498
|
|
|
@@ -347,7 +347,7 @@ No tasks defined.
|
|
|
347
347
|
- **NO automatic increment creation**: Imported items live in living docs ONLY
|
|
348
348
|
- User must manually create increment when ready to work on external item
|
|
349
349
|
- **Read-only snapshot**: External items are imported as static snapshots
|
|
350
|
-
- No
|
|
350
|
+
- No two-way sync (external tool → SpecWeave only)
|
|
351
351
|
- **Pagination**: Large imports (500+ items) may take several minutes
|
|
352
352
|
- **API quota**: Uses GitHub/JIRA/ADO API quota
|
|
353
353
|
- GitHub: 5000 requests/hour (authenticated)
|
|
@@ -43,7 +43,7 @@ Claude Code does not support command routing. Each command must be invoked direc
|
|
|
43
43
|
| Command | Description | Example |
|
|
44
44
|
|---------|-------------|---------|
|
|
45
45
|
| `/specweave-github:create-issue` | Create GitHub issue | `/specweave-github:create-issue 0031` |
|
|
46
|
-
| `/specweave-github:sync` |
|
|
46
|
+
| `/specweave-github:sync` | Two-way sync | `/specweave-github:sync 0031` |
|
|
47
47
|
| `/specweave-github:sync-tasks` | Sync tasks as sub-issues | `/specweave-github:sync-tasks 0031` |
|
|
48
48
|
| `/specweave-github:close-issue` | Close GitHub issue | `/specweave-github:close-issue 0031` |
|
|
49
49
|
| `/specweave-github:status` | Show sync status | `/specweave-github:status` |
|
|
@@ -134,20 +134,13 @@ Every increment MUST have `metadata.json` or:
|
|
|
134
134
|
|
|
135
135
|
**⚠️ CRITICAL: Before creating ANY user stories, detect if this is a multi-project (umbrella) setup!**
|
|
136
136
|
|
|
137
|
-
|
|
138
|
-
# 1. Check config.json for umbrella mode
|
|
139
|
-
UMBRELLA_ENABLED=$(cat .specweave/config.json 2>/dev/null | jq -r '.umbrella.enabled // false')
|
|
140
|
-
|
|
141
|
-
# 2. Check for childRepos
|
|
142
|
-
CHILD_REPOS=$(cat .specweave/config.json 2>/dev/null | jq -r '.umbrella.childRepos[]?.id // empty' | tr '\n' ',')
|
|
137
|
+
**Automated Detection**: `src/utils/multi-project-detector.ts` provides `detectMultiProjectMode(projectRoot)` which checks ALL config formats and returns `{ isMultiProject, projects, detectionReason }`.
|
|
143
138
|
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
echo "Project folders: $PROJECT_FOLDERS"
|
|
150
|
-
```
|
|
139
|
+
**Manual check (for agents)**: Read `.specweave/config.json` and check:
|
|
140
|
+
- `umbrella.enabled: true` with `childRepos[]`
|
|
141
|
+
- `multiProject.enabled: true` with `projects{}`
|
|
142
|
+
- `sync.profiles[].config.boardMapping` exists
|
|
143
|
+
- Multiple folders in `.specweave/docs/internal/specs/`
|
|
151
144
|
|
|
152
145
|
**If multi-project detected (`umbrella.enabled: true` OR multiple project folders exist):**
|
|
153
146
|
- ✅ **MUST** generate project-scoped user stories: `US-FE-001`, `US-BE-001`, `US-SHARED-001`
|
|
@@ -360,18 +360,13 @@ spec_generator:
|
|
|
360
360
|
|
|
361
361
|
### Detection (MANDATORY FIRST STEP)
|
|
362
362
|
|
|
363
|
-
**
|
|
363
|
+
**Automated Detection**: Use `detectMultiProjectMode(projectRoot)` from `src/utils/multi-project-detector.ts`. This utility checks ALL config formats automatically.
|
|
364
364
|
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
cat .specweave/config.json | jq '.umbrella.childRepos[]'
|
|
371
|
-
|
|
372
|
-
# 3. Check for project folders in specs/
|
|
373
|
-
ls -la .specweave/docs/internal/specs/
|
|
374
|
-
```
|
|
365
|
+
**Manual check (for agents)**: Read `.specweave/config.json` and check:
|
|
366
|
+
- `umbrella.enabled` + `childRepos[]`
|
|
367
|
+
- `multiProject.enabled` + `projects{}`
|
|
368
|
+
- `sync.profiles[].config.boardMapping`
|
|
369
|
+
- Multiple folders in `.specweave/docs/internal/specs/`
|
|
375
370
|
|
|
376
371
|
**If ANY of these conditions are TRUE → Multi-project mode ACTIVE:**
|
|
377
372
|
- `umbrella.enabled: true` in config.json
|
|
@@ -1,29 +1,29 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: specweave-ado:sync
|
|
3
|
-
description:
|
|
3
|
+
description: Two-way sync between SpecWeave increment and Azure DevOps work item (push & pull by default)
|
|
4
4
|
---
|
|
5
5
|
|
|
6
6
|
# Sync ADO Work Item Command
|
|
7
7
|
|
|
8
8
|
**Usage**: `/specweave-ado:sync <increment-id> [options]`
|
|
9
9
|
|
|
10
|
-
**Purpose**:
|
|
10
|
+
**Purpose**: Two-way synchronization between SpecWeave increment and Azure DevOps work item
|
|
11
11
|
|
|
12
|
-
**Default**: Two-way sync (
|
|
12
|
+
**Default**: Two-way sync (push & pull)
|
|
13
13
|
|
|
14
14
|
---
|
|
15
15
|
|
|
16
16
|
## Options
|
|
17
17
|
|
|
18
|
-
- `--direction <mode>`: Sync direction (default: `
|
|
19
|
-
- `
|
|
18
|
+
- `--direction <mode>`: Sync direction (default: `two-way`)
|
|
19
|
+
- `two-way`: SpecWeave ↔ ADO (default - recommended)
|
|
20
20
|
- `to-ado`: SpecWeave → ADO only (push progress)
|
|
21
21
|
- `from-ado`: ADO → SpecWeave only (pull updates)
|
|
22
22
|
|
|
23
23
|
## Examples
|
|
24
24
|
|
|
25
25
|
```bash
|
|
26
|
-
#
|
|
26
|
+
# Two-way sync (default - both directions)
|
|
27
27
|
/specweave-ado:sync 0005
|
|
28
28
|
|
|
29
29
|
# Push only (one-way to ADO)
|
|
@@ -37,7 +37,7 @@ description: Bidirectional sync between SpecWeave increment and Azure DevOps wor
|
|
|
37
37
|
|
|
38
38
|
## Command Behavior
|
|
39
39
|
|
|
40
|
-
When user runs this command, invoke `ado-manager` agent to perform
|
|
40
|
+
When user runs this command, invoke `ado-manager` agent to perform two-way sync:
|
|
41
41
|
|
|
42
42
|
### Phase 1: Pull FROM ADO (default behavior)
|
|
43
43
|
1. Fetch work item state from ADO API
|
|
@@ -66,7 +66,7 @@ When user runs this command, invoke `ado-manager` agent to perform bidirectional
|
|
|
66
66
|
```
|
|
67
67
|
Use Task tool with subagent_type: "specweave-ado:ado-manager:ado-manager"
|
|
68
68
|
|
|
69
|
-
Prompt: "
|
|
69
|
+
Prompt: "Two-way sync for increment 0005-payment-integration with ADO.
|
|
70
70
|
|
|
71
71
|
Phase 1 - Pull FROM ADO:
|
|
72
72
|
1. Fetch work item #12345 from ADO API
|
|
@@ -83,20 +83,20 @@ Phase 2 - Push TO ADO:
|
|
|
83
83
|
6. POST comment to ADO API
|
|
84
84
|
7. Update work item state/fields
|
|
85
85
|
|
|
86
|
-
Display:
|
|
86
|
+
Display: Two-way sync summary"
|
|
87
87
|
```
|
|
88
88
|
|
|
89
89
|
---
|
|
90
90
|
|
|
91
91
|
## Example Output
|
|
92
92
|
|
|
93
|
-
###
|
|
93
|
+
### Two-way Sync (Default)
|
|
94
94
|
|
|
95
95
|
```
|
|
96
|
-
🔄
|
|
96
|
+
🔄 Two-way sync for increment 0005...
|
|
97
97
|
|
|
98
98
|
✓ Azure DevOps work item: #12345
|
|
99
|
-
✓ Sync direction:
|
|
99
|
+
✓ Sync direction: Two-way (push & pull)
|
|
100
100
|
|
|
101
101
|
Detecting changes (both directions)...
|
|
102
102
|
|
|
@@ -38,7 +38,7 @@ GitHub issues MUST use living docs format:
|
|
|
38
38
|
|
|
39
39
|
**Tools**: Read, Write, Edit, Bash (GitHub CLI)
|
|
40
40
|
|
|
41
|
-
**Default Behavior**: **
|
|
41
|
+
**Default Behavior**: **Two-way sync** (push & pull) - Synchronizes changes in both directions automatically
|
|
42
42
|
|
|
43
43
|
---
|
|
44
44
|
|
|
@@ -69,8 +69,8 @@ Task({
|
|
|
69
69
|
|
|
70
70
|
As the GitHub Manager agent, I specialize in:
|
|
71
71
|
|
|
72
|
-
### 1.
|
|
73
|
-
- **Two-
|
|
72
|
+
### 1. Two-way Synchronization (Default)
|
|
73
|
+
- **Two-way Sync**: Keep SpecWeave and GitHub synchronized automatically
|
|
74
74
|
- **FROM GitHub**: Pull status changes, labels, comments, state updates
|
|
75
75
|
- **TO GitHub**: Push task completion, progress updates, metadata
|
|
76
76
|
- **Conflict Resolution**: Detect and resolve conflicts between systems
|
|
@@ -79,7 +79,7 @@ As the GitHub Manager agent, I specialize in:
|
|
|
79
79
|
|
|
80
80
|
### 2. Issue Management
|
|
81
81
|
- **Create Issues**: Generate well-formatted GitHub issues from increment specs
|
|
82
|
-
- **Update Issues**: Sync progress, add comments, update labels (
|
|
82
|
+
- **Update Issues**: Sync progress, add comments, update labels (two-way)
|
|
83
83
|
- **Close Issues**: Close issues with completion summaries
|
|
84
84
|
- **Link Issues**: Connect related issues, PRs, and increments
|
|
85
85
|
- **Bulk Operations**: Batch create/update/close issues
|
|
@@ -87,7 +87,7 @@ As the GitHub Manager agent, I specialize in:
|
|
|
87
87
|
### 3. Progress Tracking
|
|
88
88
|
- **Task Checklists**: Generate and update task checklists in issues
|
|
89
89
|
- **Progress Comments**: Post detailed task completion comments
|
|
90
|
-
- **Status Updates**:
|
|
90
|
+
- **Status Updates**: Two-way sync of increment status ↔ GitHub issue state
|
|
91
91
|
- **Time Tracking**: Track estimated vs actual time per task
|
|
92
92
|
- **Milestone Progress**: Update milestone completion percentages
|
|
93
93
|
|