specweave 0.28.22 → 0.28.25

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 (55) hide show
  1. package/dist/src/cli/helpers/init/initial-increment-generator.d.ts.map +1 -1
  2. package/dist/src/cli/helpers/init/initial-increment-generator.js +123 -35
  3. package/dist/src/cli/helpers/init/initial-increment-generator.js.map +1 -1
  4. package/dist/src/cli/helpers/init/next-steps.d.ts.map +1 -1
  5. package/dist/src/cli/helpers/init/next-steps.js +16 -47
  6. package/dist/src/cli/helpers/init/next-steps.js.map +1 -1
  7. package/dist/src/core/sync/bidirectional-engine.d.ts.map +1 -1
  8. package/dist/src/core/sync/bidirectional-engine.js +3 -1
  9. package/dist/src/core/sync/bidirectional-engine.js.map +1 -1
  10. package/dist/src/importers/import-coordinator.d.ts.map +1 -1
  11. package/dist/src/importers/import-coordinator.js +17 -0
  12. package/dist/src/importers/import-coordinator.js.map +1 -1
  13. package/dist/src/init/repo/types.d.ts +1 -1
  14. package/dist/src/utils/multi-project-detector.d.ts +92 -0
  15. package/dist/src/utils/multi-project-detector.d.ts.map +1 -0
  16. package/dist/src/utils/multi-project-detector.js +369 -0
  17. package/dist/src/utils/multi-project-detector.js.map +1 -0
  18. package/package.json +1 -1
  19. package/plugins/specweave/agents/pm/AGENT.md +33 -12
  20. package/plugins/specweave/commands/specweave-import-external.md +1 -1
  21. package/plugins/specweave/commands/specweave.md +1 -1
  22. package/plugins/specweave/skills/increment-planner/SKILL.md +6 -13
  23. package/plugins/specweave/skills/spec-generator/SKILL.md +6 -11
  24. package/plugins/specweave-ado/commands/specweave-ado-sync.md +12 -12
  25. package/plugins/specweave-ado/lib/ado-multi-project-sync.js +0 -1
  26. package/plugins/specweave-github/agents/github-manager/AGENT.md +5 -5
  27. package/plugins/specweave-github/commands/specweave-github-sync.md +12 -12
  28. package/plugins/specweave-github/commands/specweave-github-update-user-story.md +1 -1
  29. package/plugins/specweave-github/skills/github-sync/SKILL.md +4 -4
  30. package/plugins/specweave-jira/commands/specweave-jira-sync.md +11 -11
  31. package/plugins/specweave-jira/lib/enhanced-jira-sync.js +3 -3
  32. package/plugins/specweave-jira/skills/specweave-jira-mapper/SKILL.md +2 -2
  33. package/plugins/specweave-release/commands/specweave-release-npm.md +94 -4
  34. package/plugins/specweave/hooks/docs-changed.sh.backup +0 -79
  35. package/plugins/specweave/hooks/human-input-required.sh.backup +0 -75
  36. package/plugins/specweave/hooks/post-first-increment.sh.backup +0 -61
  37. package/plugins/specweave/hooks/post-increment-change.sh.backup +0 -98
  38. package/plugins/specweave/hooks/post-increment-completion.sh.backup +0 -231
  39. package/plugins/specweave/hooks/post-increment-planning.sh.backup +0 -1048
  40. package/plugins/specweave/hooks/post-increment-status-change.sh.backup +0 -147
  41. package/plugins/specweave/hooks/post-spec-update.sh.backup +0 -158
  42. package/plugins/specweave/hooks/post-user-story-complete.sh.backup +0 -179
  43. package/plugins/specweave/hooks/pre-command-deduplication.sh.backup +0 -83
  44. package/plugins/specweave/hooks/pre-implementation.sh.backup +0 -67
  45. package/plugins/specweave/hooks/pre-task-completion.sh.backup +0 -194
  46. package/plugins/specweave/hooks/pre-tool-use.sh.backup +0 -133
  47. package/plugins/specweave/hooks/user-prompt-submit.sh.backup +0 -386
  48. package/plugins/specweave-ado/hooks/post-living-docs-update.sh.backup +0 -353
  49. package/plugins/specweave-ado/hooks/post-task-completion.sh.backup +0 -172
  50. package/plugins/specweave-ado/lib/enhanced-ado-sync.js +0 -170
  51. package/plugins/specweave-github/hooks/.specweave/logs/hooks-debug.log +0 -1238
  52. package/plugins/specweave-github/hooks/post-task-completion.sh.backup +0 -258
  53. package/plugins/specweave-jira/hooks/post-task-completion.sh.backup +0 -172
  54. package/plugins/specweave-release/hooks/.specweave/logs/dora-tracking.log +0 -1218
  55. package/plugins/specweave-release/hooks/post-task-completion.sh.backup +0 -110
@@ -0,0 +1,92 @@
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
+ /**
16
+ * Project configuration detected from config or folder structure
17
+ */
18
+ export interface DetectedProject {
19
+ id: string;
20
+ prefix: string;
21
+ name: string;
22
+ path?: string;
23
+ }
24
+ /**
25
+ * Multi-project detection result
26
+ */
27
+ export interface MultiProjectDetectionResult {
28
+ /** Whether multi-project mode is active */
29
+ isMultiProject: boolean;
30
+ /** Reason for detection (for debugging/logging) */
31
+ detectionReason: string;
32
+ /** Detected projects (empty if single-project) */
33
+ projects: DetectedProject[];
34
+ /** Whether umbrella mode is enabled */
35
+ umbrellaEnabled: boolean;
36
+ /** Whether board/area path mapping is configured */
37
+ hasBoardMapping: boolean;
38
+ /** Primary project prefix for cross-cutting stories (e.g., 'AUTH' for auth) */
39
+ crossCuttingPrefix?: string;
40
+ }
41
+ /**
42
+ * Infer project prefix from project ID/name
43
+ */
44
+ export declare function inferProjectPrefix(projectId: string): string;
45
+ /**
46
+ * Detect multi-project configuration
47
+ *
48
+ * @param projectRoot - Path to project root (default: process.cwd())
49
+ * @returns Detection result with project information
50
+ */
51
+ export declare function detectMultiProjectMode(projectRoot?: string): MultiProjectDetectionResult;
52
+ /**
53
+ * Get project prefixes for user story generation
54
+ *
55
+ * @param projectRoot - Path to project root
56
+ * @returns Array of project prefixes (e.g., ['FE', 'BE', 'SHARED'])
57
+ */
58
+ export declare function getProjectPrefixes(projectRoot?: string): string[];
59
+ /**
60
+ * Get project by prefix
61
+ *
62
+ * @param prefix - Project prefix (e.g., 'FE')
63
+ * @param projectRoot - Path to project root
64
+ * @returns Project or undefined
65
+ */
66
+ export declare function getProjectByPrefix(prefix: string, projectRoot?: string): DetectedProject | undefined;
67
+ /**
68
+ * Format user story ID with project prefix (if multi-project)
69
+ *
70
+ * @param storyNumber - Story number (1, 2, 3...)
71
+ * @param projectPrefix - Optional project prefix (e.g., 'FE')
72
+ * @param projectRoot - Path to project root
73
+ * @returns Formatted ID (e.g., 'US-FE-001' or 'US-001')
74
+ */
75
+ export declare function formatUserStoryId(storyNumber: number, projectPrefix?: string, projectRoot?: string): string;
76
+ /**
77
+ * Format acceptance criteria ID with project prefix (if multi-project)
78
+ *
79
+ * @param userStoryNumber - User story number (1, 2, 3...)
80
+ * @param acNumber - Acceptance criteria number within story (1, 2, 3...)
81
+ * @param projectPrefix - Optional project prefix (e.g., 'FE')
82
+ * @returns Formatted ID (e.g., 'AC-FE-US1-01' or 'AC-US1-01')
83
+ */
84
+ export declare function formatAcceptanceCriteriaId(userStoryNumber: number, acNumber: number, projectPrefix?: string): string;
85
+ /**
86
+ * Generate template variables for multi-project spec
87
+ *
88
+ * @param detection - Multi-project detection result
89
+ * @returns Template variable map
90
+ */
91
+ export declare function generateMultiProjectTemplateVars(detection: MultiProjectDetectionResult): Record<string, string>;
92
+ //# sourceMappingURL=multi-project-detector.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"multi-project-detector.d.ts","sourceRoot":"","sources":["../../../src/utils/multi-project-detector.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;GAaG;AAKH;;GAEG;AACH,MAAM,WAAW,eAAe;IAC9B,EAAE,EAAE,MAAM,CAAC;IACX,MAAM,EAAE,MAAM,CAAC;IACf,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,CAAC,EAAE,MAAM,CAAC;CACf;AAED;;GAEG;AACH,MAAM,WAAW,2BAA2B;IAC1C,2CAA2C;IAC3C,cAAc,EAAE,OAAO,CAAC;IAExB,mDAAmD;IACnD,eAAe,EAAE,MAAM,CAAC;IAExB,kDAAkD;IAClD,QAAQ,EAAE,eAAe,EAAE,CAAC;IAE5B,uCAAuC;IACvC,eAAe,EAAE,OAAO,CAAC;IAEzB,oDAAoD;IACpD,eAAe,EAAE,OAAO,CAAC;IAEzB,+EAA+E;IAC/E,kBAAkB,CAAC,EAAE,MAAM,CAAC;CAC7B;AA8BD;;GAEG;AACH,wBAAgB,kBAAkB,CAAC,SAAS,EAAE,MAAM,GAAG,MAAM,CAyB5D;AAyID;;;;;GAKG;AACH,wBAAgB,sBAAsB,CAAC,WAAW,GAAE,MAAsB,GAAG,2BAA2B,CAyFvG;AAED;;;;;GAKG;AACH,wBAAgB,kBAAkB,CAAC,WAAW,GAAE,MAAsB,GAAG,MAAM,EAAE,CAQhF;AAED;;;;;;GAMG;AACH,wBAAgB,kBAAkB,CAChC,MAAM,EAAE,MAAM,EACd,WAAW,GAAE,MAAsB,GAClC,eAAe,GAAG,SAAS,CAK7B;AAED;;;;;;;GAOG;AACH,wBAAgB,iBAAiB,CAC/B,WAAW,EAAE,MAAM,EACnB,aAAa,CAAC,EAAE,MAAM,EACtB,WAAW,GAAE,MAAsB,GAClC,MAAM,CAgBR;AAED;;;;;;;GAOG;AACH,wBAAgB,0BAA0B,CACxC,eAAe,EAAE,MAAM,EACvB,QAAQ,EAAE,MAAM,EAChB,aAAa,CAAC,EAAE,MAAM,GACrB,MAAM,CAQR;AAED;;;;;GAKG;AACH,wBAAgB,gCAAgC,CAC9C,SAAS,EAAE,2BAA2B,GACrC,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CA6BxB"}
@@ -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.22",
3
+ "version": "0.28.25",
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
- ```bash
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
- # 2. Check for childRepos
453
- cat .specweave/config.json | jq '.umbrella.childRepos[]'
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
- # 3. Check for project folders
456
- ls -la .specweave/docs/internal/specs/
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
- Is umbrella.enabled: true?
462
- YES MUST use project-scoped user stories (US-FE-001, US-BE-001)
463
- NO Check for multiple project folders in specs/
464
- → YES → MUST use project-scoped user stories
465
- NO Use standard user stories (US-001, US-002)
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 bidirectional sync (external tool → SpecWeave only)
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` | Bidirectional sync | `/specweave-github:sync 0031` |
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
- ```bash
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
- # 3. Check for project folders in specs/
145
- PROJECT_FOLDERS=$(ls -1 .specweave/docs/internal/specs/ 2>/dev/null | grep -v "^_" | head -5)
146
-
147
- echo "Multi-project mode: $UMBRELLA_ENABLED"
148
- echo "Child repos: $CHILD_REPOS"
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
- **Before generating spec.md, ALWAYS check for multi-project mode:**
363
+ **Automated Detection**: Use `detectMultiProjectMode(projectRoot)` from `src/utils/multi-project-detector.ts`. This utility checks ALL config formats automatically.
364
364
 
365
- ```bash
366
- # 1. Check config.json for umbrella mode
367
- cat .specweave/config.json | jq '.umbrella.enabled'
368
-
369
- # 2. Check for childRepos configuration
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