specweave 0.28.17 → 0.28.20
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/plugins/specweave-ado/lib/ado-board-resolver.d.ts +94 -0
- package/dist/plugins/specweave-ado/lib/ado-board-resolver.d.ts.map +1 -0
- package/dist/plugins/specweave-ado/lib/ado-board-resolver.js +219 -0
- package/dist/plugins/specweave-ado/lib/ado-board-resolver.js.map +1 -0
- package/dist/plugins/specweave-ado/lib/ado-spec-sync.d.ts +16 -0
- package/dist/plugins/specweave-ado/lib/ado-spec-sync.d.ts.map +1 -1
- package/dist/plugins/specweave-ado/lib/ado-spec-sync.js +63 -3
- package/dist/plugins/specweave-ado/lib/ado-spec-sync.js.map +1 -1
- package/dist/plugins/specweave-ado/lib/ado-status-sync.d.ts +12 -3
- package/dist/plugins/specweave-ado/lib/ado-status-sync.d.ts.map +1 -1
- package/dist/plugins/specweave-ado/lib/ado-status-sync.js +37 -3
- package/dist/plugins/specweave-ado/lib/ado-status-sync.js.map +1 -1
- package/dist/plugins/specweave-github/lib/github-feature-sync.d.ts +6 -11
- package/dist/plugins/specweave-github/lib/github-feature-sync.d.ts.map +1 -1
- package/dist/plugins/specweave-github/lib/github-feature-sync.js +6 -11
- package/dist/plugins/specweave-github/lib/github-feature-sync.js.map +1 -1
- package/dist/plugins/specweave-github/lib/github-increment-sync-cli.d.ts +21 -0
- package/dist/plugins/specweave-github/lib/github-increment-sync-cli.d.ts.map +1 -0
- package/dist/plugins/specweave-github/lib/github-increment-sync-cli.js +445 -0
- package/dist/plugins/specweave-github/lib/github-increment-sync-cli.js.map +1 -0
- package/dist/plugins/specweave-github/lib/github-status-sync.d.ts +10 -0
- package/dist/plugins/specweave-github/lib/github-status-sync.d.ts.map +1 -1
- package/dist/plugins/specweave-github/lib/github-status-sync.js +40 -2
- package/dist/plugins/specweave-github/lib/github-status-sync.js.map +1 -1
- package/dist/plugins/specweave-github/lib/increment-issue-builder.d.ts +94 -0
- package/dist/plugins/specweave-github/lib/increment-issue-builder.d.ts.map +1 -0
- package/dist/plugins/specweave-github/lib/increment-issue-builder.js +369 -0
- package/dist/plugins/specweave-github/lib/increment-issue-builder.js.map +1 -0
- package/dist/plugins/specweave-jira/lib/jira-board-resolver.d.ts +50 -0
- package/dist/plugins/specweave-jira/lib/jira-board-resolver.d.ts.map +1 -0
- package/dist/plugins/specweave-jira/lib/jira-board-resolver.js +84 -0
- package/dist/plugins/specweave-jira/lib/jira-board-resolver.js.map +1 -0
- package/dist/plugins/specweave-jira/lib/jira-spec-sync.d.ts +12 -0
- package/dist/plugins/specweave-jira/lib/jira-spec-sync.d.ts.map +1 -1
- package/dist/plugins/specweave-jira/lib/jira-spec-sync.js +57 -5
- package/dist/plugins/specweave-jira/lib/jira-spec-sync.js.map +1 -1
- package/dist/plugins/specweave-jira/lib/jira-status-sync.d.ts +5 -1
- package/dist/plugins/specweave-jira/lib/jira-status-sync.d.ts.map +1 -1
- package/dist/plugins/specweave-jira/lib/jira-status-sync.js +12 -4
- package/dist/plugins/specweave-jira/lib/jira-status-sync.js.map +1 -1
- package/dist/src/cli/commands/import-external.d.ts.map +1 -1
- package/dist/src/cli/commands/import-external.js +12 -7
- package/dist/src/cli/commands/import-external.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 +308 -36
- package/dist/src/cli/helpers/init/external-import.js.map +1 -1
- package/dist/src/cli/helpers/init/jira-ado-auto-detect.d.ts +115 -0
- package/dist/src/cli/helpers/init/jira-ado-auto-detect.d.ts.map +1 -0
- package/dist/src/cli/helpers/init/jira-ado-auto-detect.js +590 -0
- package/dist/src/cli/helpers/init/jira-ado-auto-detect.js.map +1 -0
- package/dist/src/cli/helpers/issue-tracker/ado-area-selection.d.ts +65 -0
- package/dist/src/cli/helpers/issue-tracker/ado-area-selection.d.ts.map +1 -0
- package/dist/src/cli/helpers/issue-tracker/ado-area-selection.js +278 -0
- package/dist/src/cli/helpers/issue-tracker/ado-area-selection.js.map +1 -0
- package/dist/src/cli/helpers/issue-tracker/jira-board-selection.d.ts +64 -0
- package/dist/src/cli/helpers/issue-tracker/jira-board-selection.d.ts.map +1 -0
- package/dist/src/cli/helpers/issue-tracker/jira-board-selection.js +251 -0
- package/dist/src/cli/helpers/issue-tracker/jira-board-selection.js.map +1 -0
- package/dist/src/config/types.d.ts +6 -6
- package/dist/src/core/ac-test-validator-cli.js +4 -1
- package/dist/src/core/ac-test-validator-cli.js.map +1 -1
- package/dist/src/core/ac-test-validator.d.ts.map +1 -1
- package/dist/src/core/ac-test-validator.js +4 -1
- package/dist/src/core/ac-test-validator.js.map +1 -1
- package/dist/src/core/background/index.d.ts +11 -0
- package/dist/src/core/background/index.d.ts.map +1 -0
- package/dist/src/core/background/index.js +11 -0
- package/dist/src/core/background/index.js.map +1 -0
- package/dist/src/core/background/job-manager.d.ts +65 -0
- package/dist/src/core/background/job-manager.d.ts.map +1 -0
- package/dist/src/core/background/job-manager.js +192 -0
- package/dist/src/core/background/job-manager.js.map +1 -0
- package/dist/src/core/background/types.d.ts +59 -0
- package/dist/src/core/background/types.d.ts.map +1 -0
- package/dist/src/core/background/types.js +8 -0
- package/dist/src/core/background/types.js.map +1 -0
- package/dist/src/core/repo-structure/multi-repo-configurator.d.ts +25 -0
- package/dist/src/core/repo-structure/multi-repo-configurator.d.ts.map +1 -0
- package/dist/src/core/repo-structure/multi-repo-configurator.js +614 -0
- package/dist/src/core/repo-structure/multi-repo-configurator.js.map +1 -0
- package/dist/src/core/repo-structure/repo-initializer.d.ts +40 -0
- package/dist/src/core/repo-structure/repo-initializer.d.ts.map +1 -0
- package/dist/src/core/repo-structure/repo-initializer.js +252 -0
- package/dist/src/core/repo-structure/repo-initializer.js.map +1 -0
- package/dist/src/core/repo-structure/repo-structure-manager.d.ts +3 -37
- package/dist/src/core/repo-structure/repo-structure-manager.d.ts.map +1 -1
- package/dist/src/core/repo-structure/repo-structure-manager.js +23 -803
- package/dist/src/core/repo-structure/repo-structure-manager.js.map +1 -1
- package/dist/src/core/types/increment-metadata.d.ts +75 -0
- package/dist/src/core/types/increment-metadata.d.ts.map +1 -1
- package/dist/src/core/types/spec-metadata.d.ts +2 -0
- package/dist/src/core/types/spec-metadata.d.ts.map +1 -1
- package/dist/src/core/types/sync-profile.d.ts +137 -5
- package/dist/src/core/types/sync-profile.d.ts.map +1 -1
- package/dist/src/core/types/sync-profile.js +63 -0
- package/dist/src/core/types/sync-profile.js.map +1 -1
- package/dist/src/importers/external-importer.d.ts +25 -0
- package/dist/src/importers/external-importer.d.ts.map +1 -1
- package/dist/src/importers/github-importer.d.ts.map +1 -1
- package/dist/src/importers/github-importer.js +5 -3
- package/dist/src/importers/github-importer.js.map +1 -1
- package/dist/src/importers/import-coordinator.d.ts +20 -0
- package/dist/src/importers/import-coordinator.d.ts.map +1 -1
- package/dist/src/importers/import-coordinator.js.map +1 -1
- package/dist/src/importers/item-converter.d.ts +51 -0
- package/dist/src/importers/item-converter.d.ts.map +1 -1
- package/dist/src/importers/item-converter.js +39 -12
- package/dist/src/importers/item-converter.js.map +1 -1
- package/dist/src/init/architecture/types.d.ts +2 -2
- package/dist/src/init/compliance/types.d.ts +1 -1
- package/dist/src/init/repo/types.d.ts +1 -1
- package/dist/src/living-docs/fs-id-allocator.d.ts +72 -3
- package/dist/src/living-docs/fs-id-allocator.d.ts.map +1 -1
- package/dist/src/living-docs/fs-id-allocator.js +142 -16
- package/dist/src/living-docs/fs-id-allocator.js.map +1 -1
- package/dist/src/locales/de/cli.json +14 -0
- package/dist/src/locales/es/cli.json +14 -0
- package/dist/src/locales/fr/cli.json +14 -0
- package/dist/src/locales/ja/cli.json +14 -0
- package/dist/src/locales/ko/cli.json +14 -0
- package/dist/src/locales/pt/cli.json +14 -0
- package/dist/src/locales/ru/cli.json +14 -0
- package/dist/src/locales/zh/cli.json +14 -0
- package/dist/src/utils/chalk-fallback.d.ts +38 -0
- package/dist/src/utils/chalk-fallback.d.ts.map +1 -0
- package/dist/src/utils/chalk-fallback.js +118 -0
- package/dist/src/utils/chalk-fallback.js.map +1 -0
- package/dist/src/utils/project-id-generator.d.ts +127 -0
- package/dist/src/utils/project-id-generator.d.ts.map +1 -0
- package/dist/src/utils/project-id-generator.js +228 -0
- package/dist/src/utils/project-id-generator.js.map +1 -0
- package/package.json +1 -1
- package/plugins/specweave/agents/pm/AGENT.md +202 -0
- package/plugins/specweave/commands/specweave-import-external.md +5 -3
- package/plugins/specweave/commands/specweave-jobs.md +160 -0
- package/plugins/specweave/commands/specweave-sync-docs.md +6 -2
- package/plugins/specweave/hooks/pre-task-completion.sh +35 -17
- package/plugins/specweave/lib/vendor/core/ac-test-validator-cli.d.ts +16 -0
- package/plugins/specweave/lib/vendor/core/ac-test-validator-cli.js +121 -0
- package/plugins/specweave/lib/vendor/core/ac-test-validator-cli.js.map +1 -0
- package/plugins/specweave/lib/vendor/core/ac-test-validator.d.ts +111 -0
- package/plugins/specweave/lib/vendor/core/ac-test-validator.js +295 -0
- package/plugins/specweave/lib/vendor/core/ac-test-validator.js.map +1 -0
- package/plugins/specweave/lib/vendor/core/types/increment-metadata.d.ts +75 -0
- package/plugins/specweave/lib/vendor/utils/chalk-fallback.d.ts +38 -0
- package/plugins/specweave/lib/vendor/utils/chalk-fallback.js +118 -0
- package/plugins/specweave/lib/vendor/utils/chalk-fallback.js.map +1 -0
- package/plugins/specweave/lib/vendor/utils/fs-native.d.ts +179 -0
- package/plugins/specweave/lib/vendor/utils/fs-native.js +319 -0
- package/plugins/specweave/lib/vendor/utils/fs-native.js.map +1 -0
- package/plugins/specweave/skills/code-reviewer/SKILL.md +1 -1
- package/plugins/specweave/skills/docs-updater/SKILL.md +61 -0
- package/plugins/specweave/skills/increment-planner/SKILL.md +10 -335
- package/plugins/specweave/skills/increment-planner/templates/metadata.json +13 -0
- package/plugins/specweave/skills/increment-planner/templates/plan.md +50 -0
- package/plugins/specweave/skills/increment-planner/templates/spec-multi-project.md +86 -0
- package/plugins/specweave/skills/increment-planner/templates/spec-single-project.md +50 -0
- package/plugins/specweave/skills/increment-planner/templates/tasks-multi-project.md +86 -0
- package/plugins/specweave/skills/increment-planner/templates/tasks-single-project.md +48 -0
- package/plugins/specweave-ado/commands/specweave-ado-import-areas.md +358 -0
- package/plugins/specweave-ado/lib/ado-spec-sync.js +59 -3
- package/plugins/specweave-ado/lib/ado-spec-sync.ts +72 -3
- package/plugins/specweave-ado/lib/ado-status-sync.js +35 -3
- package/plugins/specweave-ado/lib/ado-status-sync.ts +48 -4
- package/plugins/specweave-alternatives/skills/architecture-alternatives/SKILL.md +1 -0
- package/plugins/specweave-alternatives/skills/bmad-method/SKILL.md +1 -0
- package/plugins/specweave-core/skills/code-quality/SKILL.md +1 -0
- package/plugins/specweave-core/skills/design-patterns/SKILL.md +1 -0
- package/plugins/specweave-core/skills/software-architecture/SKILL.md +1 -0
- package/plugins/specweave-github/commands/specweave-github-cleanup-duplicates.md +14 -10
- package/plugins/specweave-github/commands/specweave-github-sync.md +57 -0
- package/plugins/specweave-github/hooks/.specweave/logs/hooks-debug.log +74 -0
- package/plugins/specweave-github/lib/github-feature-sync.ts +6 -11
- package/plugins/specweave-github/lib/github-increment-sync-cli.js +456 -0
- package/plugins/specweave-github/lib/github-increment-sync-cli.ts +588 -0
- package/plugins/specweave-github/lib/github-status-sync.js +37 -1
- package/plugins/specweave-github/lib/github-status-sync.ts +60 -4
- package/plugins/specweave-github/lib/increment-issue-builder.js +389 -0
- package/plugins/specweave-github/lib/increment-issue-builder.ts +502 -0
- package/plugins/specweave-github/skills/github-issue-standard/SKILL.md +19 -24
- package/plugins/specweave-infrastructure/agents/observability-engineer/AGENT.md +15 -23
- package/plugins/specweave-jira/commands/specweave-jira-import-boards.md +331 -0
- package/plugins/specweave-jira/lib/jira-spec-sync.js +53 -5
- package/plugins/specweave-jira/lib/jira-spec-sync.ts +87 -7
- package/plugins/specweave-jira/lib/jira-status-sync.js +9 -3
- package/plugins/specweave-jira/lib/jira-status-sync.ts +15 -6
- package/plugins/specweave-ml/agents/data-scientist/AGENT.md +16 -20
- package/plugins/specweave-ml/agents/ml-engineer/AGENT.md +18 -19
- package/plugins/specweave-ml/skills/{ml-pipeline-workflow → mlops-dag-builder}/SKILL.md +18 -14
- package/plugins/specweave-release/hooks/.specweave/logs/dora-tracking.log +111 -0
- package/plugins/specweave-ui/skills/browser-automation/SKILL.md +1 -1
- package/plugins/specweave-ui/skills/ui-testing/SKILL.md +10 -122
- package/dist/plugins/specweave-github/lib/epic-content-builder.d.ts +0 -70
- package/dist/plugins/specweave-github/lib/epic-content-builder.d.ts.map +0 -1
- package/dist/plugins/specweave-github/lib/epic-content-builder.js +0 -258
- package/dist/plugins/specweave-github/lib/epic-content-builder.js.map +0 -1
- package/dist/plugins/specweave-github/lib/github-epic-sync.d.ts +0 -83
- package/dist/plugins/specweave-github/lib/github-epic-sync.d.ts.map +0 -1
- package/dist/plugins/specweave-github/lib/github-epic-sync.js +0 -466
- package/dist/plugins/specweave-github/lib/github-epic-sync.js.map +0 -1
- package/plugins/specweave-github/lib/epic-content-builder.js +0 -265
- package/plugins/specweave-github/lib/epic-content-builder.ts +0 -376
- package/plugins/specweave-github/lib/github-epic-sync.js +0 -488
- package/plugins/specweave-github/lib/github-epic-sync.ts +0 -715
|
@@ -0,0 +1,127 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Project ID Generator with Duplicate Prevention (v0.29.0+)
|
|
3
|
+
*
|
|
4
|
+
* Generates unique SpecWeave project IDs from external tool entities:
|
|
5
|
+
* - JIRA boards → Project IDs
|
|
6
|
+
* - ADO area paths → Project IDs
|
|
7
|
+
* - GitHub repos → Project IDs
|
|
8
|
+
*
|
|
9
|
+
* Handles collision detection and composite key generation.
|
|
10
|
+
*/
|
|
11
|
+
/**
|
|
12
|
+
* Project ID generation options
|
|
13
|
+
*/
|
|
14
|
+
export interface ProjectIdOptions {
|
|
15
|
+
/** External container (JIRA project key, ADO project name) */
|
|
16
|
+
externalContainer: string;
|
|
17
|
+
/** Local name (board name, area path, repo name) */
|
|
18
|
+
localName: string;
|
|
19
|
+
/** Provider type */
|
|
20
|
+
provider: 'jira' | 'ado' | 'github';
|
|
21
|
+
/** Existing project IDs to check for collisions */
|
|
22
|
+
existingIds?: string[];
|
|
23
|
+
}
|
|
24
|
+
/**
|
|
25
|
+
* Generated project ID result
|
|
26
|
+
*/
|
|
27
|
+
export interface ProjectIdResult {
|
|
28
|
+
/** Generated project ID */
|
|
29
|
+
id: string;
|
|
30
|
+
/** Whether collision was detected and prefix was added */
|
|
31
|
+
hadCollision: boolean;
|
|
32
|
+
/** Original local name before sanitization */
|
|
33
|
+
originalName: string;
|
|
34
|
+
/** Full composite key (container + local) */
|
|
35
|
+
compositeKey: string;
|
|
36
|
+
}
|
|
37
|
+
/**
|
|
38
|
+
* Normalize a string to a valid project ID
|
|
39
|
+
* - Lowercase
|
|
40
|
+
* - Replace spaces and special chars with hyphens
|
|
41
|
+
* - Remove consecutive hyphens
|
|
42
|
+
* - Remove leading/trailing hyphens
|
|
43
|
+
*/
|
|
44
|
+
export declare function normalizeToProjectId(name: string): string;
|
|
45
|
+
/**
|
|
46
|
+
* Generate a short prefix from external container name
|
|
47
|
+
* Used when collision is detected
|
|
48
|
+
*/
|
|
49
|
+
export declare function generateContainerPrefix(container: string): string;
|
|
50
|
+
/**
|
|
51
|
+
* Generate unique project ID with collision detection
|
|
52
|
+
*
|
|
53
|
+
* Algorithm:
|
|
54
|
+
* 1. Normalize local name to project ID format
|
|
55
|
+
* 2. Check if ID exists in existingIds
|
|
56
|
+
* 3. If collision, add container prefix: "core-fe" instead of "fe"
|
|
57
|
+
* 4. If still collision (rare), add numeric suffix: "core-fe-2"
|
|
58
|
+
*
|
|
59
|
+
* @param options Generation options
|
|
60
|
+
* @returns Generated project ID with metadata
|
|
61
|
+
*/
|
|
62
|
+
export declare function generateProjectId(options: ProjectIdOptions): ProjectIdResult;
|
|
63
|
+
/**
|
|
64
|
+
* Batch generate project IDs from multiple sources
|
|
65
|
+
* Ensures no collisions within the batch and with existing IDs
|
|
66
|
+
*/
|
|
67
|
+
export declare function generateProjectIdsBatch(sources: Array<{
|
|
68
|
+
container: string;
|
|
69
|
+
localName: string;
|
|
70
|
+
provider: 'jira' | 'ado' | 'github';
|
|
71
|
+
}>, existingIds?: string[]): Map<string, ProjectIdResult>;
|
|
72
|
+
/**
|
|
73
|
+
* Get existing project IDs from a SpecWeave project
|
|
74
|
+
*
|
|
75
|
+
* @param projectRoot Path to project root
|
|
76
|
+
* @returns Array of existing project IDs
|
|
77
|
+
*/
|
|
78
|
+
export declare function getExistingProjectIds(projectRoot: string): string[];
|
|
79
|
+
/**
|
|
80
|
+
* Create 2-level directory structure for JIRA/ADO projects
|
|
81
|
+
*
|
|
82
|
+
* Structure:
|
|
83
|
+
* .specweave/docs/internal/specs/
|
|
84
|
+
* ├── JIRA-CORE/ (external container level)
|
|
85
|
+
* │ ├── fe/ (SpecWeave project level)
|
|
86
|
+
* │ ├── be/
|
|
87
|
+
* │ └── mobile/
|
|
88
|
+
* └── ADO-MyProduct/
|
|
89
|
+
* ├── fe/
|
|
90
|
+
* └── be/
|
|
91
|
+
*
|
|
92
|
+
* @param projectRoot Path to project root
|
|
93
|
+
* @param containerType Type of external container
|
|
94
|
+
* @param containerId External container ID (JIRA project key or ADO project name)
|
|
95
|
+
* @param specweaveProjectId SpecWeave project ID
|
|
96
|
+
*/
|
|
97
|
+
export declare function createTwoLevelProjectDir(projectRoot: string, containerType: 'jira' | 'ado', containerId: string, specweaveProjectId: string): string;
|
|
98
|
+
/**
|
|
99
|
+
* Get the 2-level path for a project
|
|
100
|
+
*
|
|
101
|
+
* @param projectRoot Path to project root
|
|
102
|
+
* @param containerType Type of external container
|
|
103
|
+
* @param containerId External container ID
|
|
104
|
+
* @param specweaveProjectId SpecWeave project ID
|
|
105
|
+
* @returns Full path or undefined if using flat structure
|
|
106
|
+
*/
|
|
107
|
+
export declare function getTwoLevelProjectPath(projectRoot: string, containerType: 'jira' | 'ado' | null, containerId: string | null, specweaveProjectId: string): string;
|
|
108
|
+
/**
|
|
109
|
+
* Parse a 2-level project path to extract container and project info
|
|
110
|
+
*
|
|
111
|
+
* @param projectPath Path like ".specweave/docs/internal/specs/JIRA-CORE/fe"
|
|
112
|
+
* @returns Parsed container and project info
|
|
113
|
+
*/
|
|
114
|
+
export declare function parseTwoLevelPath(projectPath: string): {
|
|
115
|
+
containerType: 'jira' | 'ado' | null;
|
|
116
|
+
containerId: string | null;
|
|
117
|
+
projectId: string;
|
|
118
|
+
} | null;
|
|
119
|
+
/**
|
|
120
|
+
* Validate project ID format
|
|
121
|
+
*/
|
|
122
|
+
export declare function isValidProjectId(id: string): boolean;
|
|
123
|
+
/**
|
|
124
|
+
* Suggest a valid project ID from an invalid one
|
|
125
|
+
*/
|
|
126
|
+
export declare function suggestProjectId(invalidId: string): string;
|
|
127
|
+
//# sourceMappingURL=project-id-generator.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"project-id-generator.d.ts","sourceRoot":"","sources":["../../../src/utils/project-id-generator.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAKH;;GAEG;AACH,MAAM,WAAW,gBAAgB;IAC/B,8DAA8D;IAC9D,iBAAiB,EAAE,MAAM,CAAC;IAE1B,oDAAoD;IACpD,SAAS,EAAE,MAAM,CAAC;IAElB,oBAAoB;IACpB,QAAQ,EAAE,MAAM,GAAG,KAAK,GAAG,QAAQ,CAAC;IAEpC,mDAAmD;IACnD,WAAW,CAAC,EAAE,MAAM,EAAE,CAAC;CACxB;AAED;;GAEG;AACH,MAAM,WAAW,eAAe;IAC9B,2BAA2B;IAC3B,EAAE,EAAE,MAAM,CAAC;IAEX,0DAA0D;IAC1D,YAAY,EAAE,OAAO,CAAC;IAEtB,8CAA8C;IAC9C,YAAY,EAAE,MAAM,CAAC;IAErB,6CAA6C;IAC7C,YAAY,EAAE,MAAM,CAAC;CACtB;AAED;;;;;;GAMG;AACH,wBAAgB,oBAAoB,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAMzD;AAED;;;GAGG;AACH,wBAAgB,uBAAuB,CAAC,SAAS,EAAE,MAAM,GAAG,MAAM,CAgBjE;AAED;;;;;;;;;;;GAWG;AACH,wBAAgB,iBAAiB,CAAC,OAAO,EAAE,gBAAgB,GAAG,eAAe,CA6C5E;AAED;;;GAGG;AACH,wBAAgB,uBAAuB,CACrC,OAAO,EAAE,KAAK,CAAC;IAAE,SAAS,EAAE,MAAM,CAAC;IAAC,SAAS,EAAE,MAAM,CAAC;IAAC,QAAQ,EAAE,MAAM,GAAG,KAAK,GAAG,QAAQ,CAAA;CAAE,CAAC,EAC7F,WAAW,GAAE,MAAM,EAAO,GACzB,GAAG,CAAC,MAAM,EAAE,eAAe,CAAC,CAoB9B;AAED;;;;;GAKG;AACH,wBAAgB,qBAAqB,CAAC,WAAW,EAAE,MAAM,GAAG,MAAM,EAAE,CAenE;AAED;;;;;;;;;;;;;;;;;GAiBG;AACH,wBAAgB,wBAAwB,CACtC,WAAW,EAAE,MAAM,EACnB,aAAa,EAAE,MAAM,GAAG,KAAK,EAC7B,WAAW,EAAE,MAAM,EACnB,kBAAkB,EAAE,MAAM,GACzB,MAAM,CAoBR;AAED;;;;;;;;GAQG;AACH,wBAAgB,sBAAsB,CACpC,WAAW,EAAE,MAAM,EACnB,aAAa,EAAE,MAAM,GAAG,KAAK,GAAG,IAAI,EACpC,WAAW,EAAE,MAAM,GAAG,IAAI,EAC1B,kBAAkB,EAAE,MAAM,GACzB,MAAM,CAwBR;AAED;;;;;GAKG;AACH,wBAAgB,iBAAiB,CAAC,WAAW,EAAE,MAAM,GAAG;IACtD,aAAa,EAAE,MAAM,GAAG,KAAK,GAAG,IAAI,CAAC;IACrC,WAAW,EAAE,MAAM,GAAG,IAAI,CAAC;IAC3B,SAAS,EAAE,MAAM,CAAC;CACnB,GAAG,IAAI,CAyBP;AAED;;GAEG;AACH,wBAAgB,gBAAgB,CAAC,EAAE,EAAE,MAAM,GAAG,OAAO,CAEpD;AAED;;GAEG;AACH,wBAAgB,gBAAgB,CAAC,SAAS,EAAE,MAAM,GAAG,MAAM,CAG1D"}
|
|
@@ -0,0 +1,228 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Project ID Generator with Duplicate Prevention (v0.29.0+)
|
|
3
|
+
*
|
|
4
|
+
* Generates unique SpecWeave project IDs from external tool entities:
|
|
5
|
+
* - JIRA boards → Project IDs
|
|
6
|
+
* - ADO area paths → Project IDs
|
|
7
|
+
* - GitHub repos → Project IDs
|
|
8
|
+
*
|
|
9
|
+
* Handles collision detection and composite key generation.
|
|
10
|
+
*/
|
|
11
|
+
import * as fs from './fs-native.js';
|
|
12
|
+
import * as path from 'path';
|
|
13
|
+
/**
|
|
14
|
+
* Normalize a string to a valid project ID
|
|
15
|
+
* - Lowercase
|
|
16
|
+
* - Replace spaces and special chars with hyphens
|
|
17
|
+
* - Remove consecutive hyphens
|
|
18
|
+
* - Remove leading/trailing hyphens
|
|
19
|
+
*/
|
|
20
|
+
export function normalizeToProjectId(name) {
|
|
21
|
+
return name
|
|
22
|
+
.toLowerCase()
|
|
23
|
+
.replace(/[^a-z0-9]+/g, '-') // Replace non-alphanumeric with hyphens
|
|
24
|
+
.replace(/-+/g, '-') // Remove consecutive hyphens
|
|
25
|
+
.replace(/^-|-$/g, ''); // Remove leading/trailing hyphens
|
|
26
|
+
}
|
|
27
|
+
/**
|
|
28
|
+
* Generate a short prefix from external container name
|
|
29
|
+
* Used when collision is detected
|
|
30
|
+
*/
|
|
31
|
+
export function generateContainerPrefix(container) {
|
|
32
|
+
// For JIRA project keys like "CORE", use as-is (already short)
|
|
33
|
+
if (/^[A-Z]{2,10}$/.test(container)) {
|
|
34
|
+
return container.toLowerCase();
|
|
35
|
+
}
|
|
36
|
+
// For longer names, create abbreviation
|
|
37
|
+
// "MyProduct" → "mp", "Backend-Services" → "bs"
|
|
38
|
+
const words = container.split(/[-_\s]+/);
|
|
39
|
+
if (words.length === 1) {
|
|
40
|
+
// Single word: use first 3 chars
|
|
41
|
+
return container.substring(0, 3).toLowerCase();
|
|
42
|
+
}
|
|
43
|
+
// Multiple words: use first letter of each
|
|
44
|
+
return words.map(w => w[0]).join('').toLowerCase();
|
|
45
|
+
}
|
|
46
|
+
/**
|
|
47
|
+
* Generate unique project ID with collision detection
|
|
48
|
+
*
|
|
49
|
+
* Algorithm:
|
|
50
|
+
* 1. Normalize local name to project ID format
|
|
51
|
+
* 2. Check if ID exists in existingIds
|
|
52
|
+
* 3. If collision, add container prefix: "core-fe" instead of "fe"
|
|
53
|
+
* 4. If still collision (rare), add numeric suffix: "core-fe-2"
|
|
54
|
+
*
|
|
55
|
+
* @param options Generation options
|
|
56
|
+
* @returns Generated project ID with metadata
|
|
57
|
+
*/
|
|
58
|
+
export function generateProjectId(options) {
|
|
59
|
+
const { externalContainer, localName, provider, existingIds = [] } = options;
|
|
60
|
+
// Step 1: Normalize local name
|
|
61
|
+
const baseId = normalizeToProjectId(localName);
|
|
62
|
+
const compositeKey = `${externalContainer}/${localName}`;
|
|
63
|
+
// Step 2: Check for collision
|
|
64
|
+
if (!existingIds.includes(baseId)) {
|
|
65
|
+
return {
|
|
66
|
+
id: baseId,
|
|
67
|
+
hadCollision: false,
|
|
68
|
+
originalName: localName,
|
|
69
|
+
compositeKey,
|
|
70
|
+
};
|
|
71
|
+
}
|
|
72
|
+
// Step 3: Collision detected - add container prefix
|
|
73
|
+
const prefix = generateContainerPrefix(externalContainer);
|
|
74
|
+
let prefixedId = `${prefix}-${baseId}`;
|
|
75
|
+
if (!existingIds.includes(prefixedId)) {
|
|
76
|
+
return {
|
|
77
|
+
id: prefixedId,
|
|
78
|
+
hadCollision: true,
|
|
79
|
+
originalName: localName,
|
|
80
|
+
compositeKey,
|
|
81
|
+
};
|
|
82
|
+
}
|
|
83
|
+
// Step 4: Still collision (rare) - add numeric suffix
|
|
84
|
+
let suffix = 2;
|
|
85
|
+
while (existingIds.includes(`${prefixedId}-${suffix}`)) {
|
|
86
|
+
suffix++;
|
|
87
|
+
if (suffix > 100) {
|
|
88
|
+
throw new Error(`Cannot generate unique ID for ${compositeKey} after 100 attempts`);
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
return {
|
|
92
|
+
id: `${prefixedId}-${suffix}`,
|
|
93
|
+
hadCollision: true,
|
|
94
|
+
originalName: localName,
|
|
95
|
+
compositeKey,
|
|
96
|
+
};
|
|
97
|
+
}
|
|
98
|
+
/**
|
|
99
|
+
* Batch generate project IDs from multiple sources
|
|
100
|
+
* Ensures no collisions within the batch and with existing IDs
|
|
101
|
+
*/
|
|
102
|
+
export function generateProjectIdsBatch(sources, existingIds = []) {
|
|
103
|
+
const results = new Map();
|
|
104
|
+
const allIds = [...existingIds];
|
|
105
|
+
for (const source of sources) {
|
|
106
|
+
const result = generateProjectId({
|
|
107
|
+
externalContainer: source.container,
|
|
108
|
+
localName: source.localName,
|
|
109
|
+
provider: source.provider,
|
|
110
|
+
existingIds: allIds,
|
|
111
|
+
});
|
|
112
|
+
// Add to tracking to prevent intra-batch collisions
|
|
113
|
+
allIds.push(result.id);
|
|
114
|
+
// Key by composite key for easy lookup
|
|
115
|
+
results.set(result.compositeKey, result);
|
|
116
|
+
}
|
|
117
|
+
return results;
|
|
118
|
+
}
|
|
119
|
+
/**
|
|
120
|
+
* Get existing project IDs from a SpecWeave project
|
|
121
|
+
*
|
|
122
|
+
* @param projectRoot Path to project root
|
|
123
|
+
* @returns Array of existing project IDs
|
|
124
|
+
*/
|
|
125
|
+
export function getExistingProjectIds(projectRoot) {
|
|
126
|
+
const specsDir = path.join(projectRoot, '.specweave', 'docs', 'internal', 'specs');
|
|
127
|
+
if (!fs.existsSync(specsDir)) {
|
|
128
|
+
return [];
|
|
129
|
+
}
|
|
130
|
+
try {
|
|
131
|
+
const entries = fs.readdirSync(specsDir, { withFileTypes: true });
|
|
132
|
+
return entries
|
|
133
|
+
.filter(entry => entry.isDirectory() && !entry.name.startsWith('_'))
|
|
134
|
+
.map(entry => entry.name);
|
|
135
|
+
}
|
|
136
|
+
catch {
|
|
137
|
+
return [];
|
|
138
|
+
}
|
|
139
|
+
}
|
|
140
|
+
/**
|
|
141
|
+
* Create 2-level directory structure for JIRA/ADO projects
|
|
142
|
+
*
|
|
143
|
+
* Structure:
|
|
144
|
+
* .specweave/docs/internal/specs/
|
|
145
|
+
* ├── JIRA-CORE/ (external container level)
|
|
146
|
+
* │ ├── fe/ (SpecWeave project level)
|
|
147
|
+
* │ ├── be/
|
|
148
|
+
* │ └── mobile/
|
|
149
|
+
* └── ADO-MyProduct/
|
|
150
|
+
* ├── fe/
|
|
151
|
+
* └── be/
|
|
152
|
+
*
|
|
153
|
+
* @param projectRoot Path to project root
|
|
154
|
+
* @param containerType Type of external container
|
|
155
|
+
* @param containerId External container ID (JIRA project key or ADO project name)
|
|
156
|
+
* @param specweaveProjectId SpecWeave project ID
|
|
157
|
+
*/
|
|
158
|
+
export function createTwoLevelProjectDir(projectRoot, containerType, containerId, specweaveProjectId) {
|
|
159
|
+
// Normalize container ID to directory-safe name
|
|
160
|
+
const containerDirName = `${containerType.toUpperCase()}-${normalizeToProjectId(containerId)}`;
|
|
161
|
+
const projectDirName = specweaveProjectId;
|
|
162
|
+
const fullPath = path.join(projectRoot, '.specweave', 'docs', 'internal', 'specs', containerDirName, projectDirName);
|
|
163
|
+
if (!fs.existsSync(fullPath)) {
|
|
164
|
+
fs.mkdirSync(fullPath, { recursive: true });
|
|
165
|
+
}
|
|
166
|
+
return fullPath;
|
|
167
|
+
}
|
|
168
|
+
/**
|
|
169
|
+
* Get the 2-level path for a project
|
|
170
|
+
*
|
|
171
|
+
* @param projectRoot Path to project root
|
|
172
|
+
* @param containerType Type of external container
|
|
173
|
+
* @param containerId External container ID
|
|
174
|
+
* @param specweaveProjectId SpecWeave project ID
|
|
175
|
+
* @returns Full path or undefined if using flat structure
|
|
176
|
+
*/
|
|
177
|
+
export function getTwoLevelProjectPath(projectRoot, containerType, containerId, specweaveProjectId) {
|
|
178
|
+
// If no container type, use flat structure (GitHub or single project)
|
|
179
|
+
if (!containerType || !containerId) {
|
|
180
|
+
return path.join(projectRoot, '.specweave', 'docs', 'internal', 'specs', specweaveProjectId);
|
|
181
|
+
}
|
|
182
|
+
// 2-level structure for JIRA/ADO
|
|
183
|
+
const containerDirName = `${containerType.toUpperCase()}-${normalizeToProjectId(containerId)}`;
|
|
184
|
+
return path.join(projectRoot, '.specweave', 'docs', 'internal', 'specs', containerDirName, specweaveProjectId);
|
|
185
|
+
}
|
|
186
|
+
/**
|
|
187
|
+
* Parse a 2-level project path to extract container and project info
|
|
188
|
+
*
|
|
189
|
+
* @param projectPath Path like ".specweave/docs/internal/specs/JIRA-CORE/fe"
|
|
190
|
+
* @returns Parsed container and project info
|
|
191
|
+
*/
|
|
192
|
+
export function parseTwoLevelPath(projectPath) {
|
|
193
|
+
// Match pattern: .../specs/{CONTAINER-TYPE-ID}/{PROJECT-ID}
|
|
194
|
+
const match = projectPath.match(/specs[/\\]((?:JIRA|ADO)-([^/\\]+))[/\\]([^/\\]+)/);
|
|
195
|
+
if (!match) {
|
|
196
|
+
// Try flat structure: .../specs/{PROJECT-ID}
|
|
197
|
+
const flatMatch = projectPath.match(/specs[/\\]([^/\\]+)$/);
|
|
198
|
+
if (flatMatch) {
|
|
199
|
+
return {
|
|
200
|
+
containerType: null,
|
|
201
|
+
containerId: null,
|
|
202
|
+
projectId: flatMatch[1],
|
|
203
|
+
};
|
|
204
|
+
}
|
|
205
|
+
return null;
|
|
206
|
+
}
|
|
207
|
+
const [, containerDir, containerId, projectId] = match;
|
|
208
|
+
const containerType = containerDir.startsWith('JIRA-') ? 'jira' : 'ado';
|
|
209
|
+
return {
|
|
210
|
+
containerType,
|
|
211
|
+
containerId,
|
|
212
|
+
projectId,
|
|
213
|
+
};
|
|
214
|
+
}
|
|
215
|
+
/**
|
|
216
|
+
* Validate project ID format
|
|
217
|
+
*/
|
|
218
|
+
export function isValidProjectId(id) {
|
|
219
|
+
return /^[a-z0-9][a-z0-9-]*[a-z0-9]$|^[a-z0-9]$/.test(id);
|
|
220
|
+
}
|
|
221
|
+
/**
|
|
222
|
+
* Suggest a valid project ID from an invalid one
|
|
223
|
+
*/
|
|
224
|
+
export function suggestProjectId(invalidId) {
|
|
225
|
+
const suggestion = normalizeToProjectId(invalidId);
|
|
226
|
+
return suggestion || 'project';
|
|
227
|
+
}
|
|
228
|
+
//# sourceMappingURL=project-id-generator.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"project-id-generator.js","sourceRoot":"","sources":["../../../src/utils/project-id-generator.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.20",
|
|
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",
|
|
@@ -615,6 +615,208 @@ With project-scoped stories:
|
|
|
615
615
|
|
|
616
616
|
---
|
|
617
617
|
|
|
618
|
+
## 🌐 Multi-Project User Stories (v0.29.0+ - JIRA Boards/ADO Area Paths)
|
|
619
|
+
|
|
620
|
+
**⚠️ CRITICAL: User Stories MUST Consider ALL Relevant Projects!**
|
|
621
|
+
|
|
622
|
+
When working with enterprise setups where JIRA boards or ADO area paths map to SpecWeave projects, a single user story often spans MULTIPLE projects.
|
|
623
|
+
|
|
624
|
+
### STEP 0C: Detect Multi-Project Mode (Board/Area Path Mapping)
|
|
625
|
+
|
|
626
|
+
**YOU MUST CHECK THIS BEFORE WRITING ANY USER STORIES:**
|
|
627
|
+
|
|
628
|
+
```bash
|
|
629
|
+
# Check for JIRA board mapping
|
|
630
|
+
cat .specweave/config.json | jq '.sync.profiles[].config.boardMapping'
|
|
631
|
+
|
|
632
|
+
# Check for ADO area path mapping
|
|
633
|
+
cat .specweave/config.json | jq '.sync.profiles[].config.areaPathMapping'
|
|
634
|
+
|
|
635
|
+
# Check for 2-level spec structure
|
|
636
|
+
ls -la .specweave/docs/internal/specs/JIRA-*/
|
|
637
|
+
ls -la .specweave/docs/internal/specs/ADO-*/
|
|
638
|
+
```
|
|
639
|
+
|
|
640
|
+
**Decision Flow:**
|
|
641
|
+
```
|
|
642
|
+
Is boardMapping or areaPathMapping configured?
|
|
643
|
+
→ YES → MUST use multi-project-aware user stories
|
|
644
|
+
Each US must list ALL affected projects with scope
|
|
645
|
+
→ NO → Check for umbrella mode (see Step 0)
|
|
646
|
+
Use standard or project-scoped user stories
|
|
647
|
+
```
|
|
648
|
+
|
|
649
|
+
### Multi-Project User Story Format (v0.29.0+)
|
|
650
|
+
|
|
651
|
+
**When board/area path mapping is detected, EVERY user story MUST:**
|
|
652
|
+
|
|
653
|
+
1. List ALL projects it touches
|
|
654
|
+
2. Define scope per project
|
|
655
|
+
3. Identify cross-project dependencies
|
|
656
|
+
|
|
657
|
+
**Example: OAuth Implementation Spanning 3 Projects**
|
|
658
|
+
|
|
659
|
+
```markdown
|
|
660
|
+
### US-001: OAuth Authentication (Priority: P0 - Critical)
|
|
661
|
+
|
|
662
|
+
**Projects Involved**:
|
|
663
|
+
| Project | Scope | Keywords |
|
|
664
|
+
|---------|-------|----------|
|
|
665
|
+
| BE (Backend Board) | OAuth API endpoints, token validation, session management | api, oauth, token, session |
|
|
666
|
+
| FE (Frontend Board) | Login UI with OIDC, token storage, logout flow | ui, login, oidc, logout |
|
|
667
|
+
| Shared | Common auth types, interfaces, JWT utilities | types, interfaces, jwt |
|
|
668
|
+
|
|
669
|
+
**As a** user
|
|
670
|
+
**I want** to log in using Google OAuth
|
|
671
|
+
**So that** I can access the system without creating a new password
|
|
672
|
+
|
|
673
|
+
**Cross-Project Dependencies**:
|
|
674
|
+
- FE depends on Shared (auth types/interfaces)
|
|
675
|
+
- BE depends on Shared (JWT utilities)
|
|
676
|
+
- FE calls BE (OAuth callback API)
|
|
677
|
+
|
|
678
|
+
**Acceptance Criteria**:
|
|
679
|
+
|
|
680
|
+
**BE Project (Backend Board)**:
|
|
681
|
+
- [ ] **AC-BE-US1-01**: POST /api/auth/oauth/google initiates OAuth flow
|
|
682
|
+
- Priority: P0
|
|
683
|
+
- Testable: Yes (integration test)
|
|
684
|
+
- [ ] **AC-BE-US1-02**: GET /api/auth/oauth/callback processes OAuth response
|
|
685
|
+
- Priority: P0
|
|
686
|
+
- Testable: Yes (integration test)
|
|
687
|
+
- [ ] **AC-BE-US1-03**: JWT tokens generated with 1-hour expiry
|
|
688
|
+
- Priority: P0
|
|
689
|
+
- Testable: Yes (unit test)
|
|
690
|
+
|
|
691
|
+
**FE Project (Frontend Board)**:
|
|
692
|
+
- [ ] **AC-FE-US1-01**: "Sign in with Google" button visible on login page
|
|
693
|
+
- Priority: P0
|
|
694
|
+
- Testable: Yes (E2E test)
|
|
695
|
+
- [ ] **AC-FE-US1-02**: OAuth redirect handled correctly
|
|
696
|
+
- Priority: P0
|
|
697
|
+
- Testable: Yes (E2E test)
|
|
698
|
+
- [ ] **AC-FE-US1-03**: Token stored securely in HTTP-only cookie
|
|
699
|
+
- Priority: P0
|
|
700
|
+
- Testable: Yes (security test)
|
|
701
|
+
|
|
702
|
+
**Shared Project**:
|
|
703
|
+
- [ ] **AC-SHARED-US1-01**: AuthUser interface defined with OAuth fields
|
|
704
|
+
- Priority: P0
|
|
705
|
+
- Testable: Yes (type check)
|
|
706
|
+
- [ ] **AC-SHARED-US1-02**: JWT decode utility function
|
|
707
|
+
- Priority: P0
|
|
708
|
+
- Testable: Yes (unit test)
|
|
709
|
+
```
|
|
710
|
+
|
|
711
|
+
### spec.md Frontmatter for Multi-Project US
|
|
712
|
+
|
|
713
|
+
```yaml
|
|
714
|
+
---
|
|
715
|
+
increment: 0001-oauth-implementation
|
|
716
|
+
feature_id: FS-001
|
|
717
|
+
status: active
|
|
718
|
+
|
|
719
|
+
# Single project (legacy - backward compatible)
|
|
720
|
+
# project: BE
|
|
721
|
+
|
|
722
|
+
# Multi-project user story (v0.29.0+)
|
|
723
|
+
projects:
|
|
724
|
+
- id: BE
|
|
725
|
+
scope: "OAuth API endpoints, token validation, session management"
|
|
726
|
+
keywords: ["api", "oauth", "token", "session"]
|
|
727
|
+
effort_percentage: 50
|
|
728
|
+
- id: FE
|
|
729
|
+
scope: "Login UI with OIDC, token storage, logout flow"
|
|
730
|
+
keywords: ["ui", "login", "oidc", "logout"]
|
|
731
|
+
effort_percentage: 35
|
|
732
|
+
- id: Shared
|
|
733
|
+
scope: "Common auth types, interfaces, JWT utilities"
|
|
734
|
+
keywords: ["types", "interfaces", "jwt"]
|
|
735
|
+
effort_percentage: 15
|
|
736
|
+
|
|
737
|
+
cross_dependencies:
|
|
738
|
+
- from: FE
|
|
739
|
+
to: Shared
|
|
740
|
+
reason: "FE uses auth types from Shared"
|
|
741
|
+
- from: BE
|
|
742
|
+
to: Shared
|
|
743
|
+
reason: "BE uses JWT utilities from Shared"
|
|
744
|
+
- from: FE
|
|
745
|
+
to: BE
|
|
746
|
+
reason: "FE calls OAuth callback API"
|
|
747
|
+
|
|
748
|
+
sync_strategy: linked # 'linked' | 'primary-only' | 'all'
|
|
749
|
+
primary_project: BE # Which project owns the main issue
|
|
750
|
+
---
|
|
751
|
+
```
|
|
752
|
+
|
|
753
|
+
### Sync Behavior for Multi-Project US
|
|
754
|
+
|
|
755
|
+
**sync_strategy options**:
|
|
756
|
+
|
|
757
|
+
| Strategy | Behavior |
|
|
758
|
+
|----------|----------|
|
|
759
|
+
| `linked` | Create main issue in primary_project, linked child issues in others |
|
|
760
|
+
| `primary-only` | Only create issue in primary_project |
|
|
761
|
+
| `all` | Create full issues in all projects (may cause duplication) |
|
|
762
|
+
|
|
763
|
+
**Example: `linked` strategy with JIRA boards**:
|
|
764
|
+
```
|
|
765
|
+
JIRA Project: CORE
|
|
766
|
+
|
|
767
|
+
Backend Board (BE project):
|
|
768
|
+
→ CORE-123: [Epic] OAuth Authentication (parent)
|
|
769
|
+
→ CORE-124: OAuth API endpoints
|
|
770
|
+
→ CORE-125: Token validation
|
|
771
|
+
|
|
772
|
+
Frontend Board (FE project):
|
|
773
|
+
→ CORE-130: OAuth Login UI (linked to CORE-123)
|
|
774
|
+
→ CORE-131: Google sign-in button
|
|
775
|
+
→ CORE-132: Token storage
|
|
776
|
+
|
|
777
|
+
Both boards can track progress, but CORE-123 is the parent epic.
|
|
778
|
+
```
|
|
779
|
+
|
|
780
|
+
### Why Multi-Project Awareness Matters
|
|
781
|
+
|
|
782
|
+
**Without multi-project awareness**:
|
|
783
|
+
- ❌ US created in ONE board/area only (wrong!)
|
|
784
|
+
- ❌ Cross-team dependencies unclear
|
|
785
|
+
- ❌ Frontend dev doesn't know backend is a blocker
|
|
786
|
+
- ❌ Shared changes not communicated to dependent teams
|
|
787
|
+
- ❌ Progress tracking incomplete
|
|
788
|
+
|
|
789
|
+
**With multi-project awareness**:
|
|
790
|
+
- ✅ Each board/area gets relevant ACs
|
|
791
|
+
- ✅ Clear cross-project dependencies
|
|
792
|
+
- ✅ All teams know their scope
|
|
793
|
+
- ✅ Linked issues enable coordination
|
|
794
|
+
- ✅ Progress tracked across all projects
|
|
795
|
+
|
|
796
|
+
### PM Agent Workflow for Multi-Project US
|
|
797
|
+
|
|
798
|
+
1. **Detect** board/area path mapping in config.json
|
|
799
|
+
2. **Analyze** user story for multi-project scope
|
|
800
|
+
3. **Ask** user: "This feature spans BE, FE, and Shared. Should I create linked issues?"
|
|
801
|
+
4. **Generate** spec.md with `projects` array in frontmatter
|
|
802
|
+
5. **Create** ACs grouped by project (AC-BE-*, AC-FE-*, AC-SHARED-*)
|
|
803
|
+
6. **Document** cross-project dependencies
|
|
804
|
+
7. **Sync** to external tool based on sync_strategy
|
|
805
|
+
|
|
806
|
+
### Validation Checklist for Multi-Project US
|
|
807
|
+
|
|
808
|
+
Before finalizing any user story:
|
|
809
|
+
|
|
810
|
+
- [ ] Analyzed scope across ALL configured projects (BE, FE, Shared, etc.)
|
|
811
|
+
- [ ] `projects` array in frontmatter lists all affected projects
|
|
812
|
+
- [ ] Each project has defined scope and keywords
|
|
813
|
+
- [ ] ACs are grouped by project with correct prefixes
|
|
814
|
+
- [ ] Cross-project dependencies documented
|
|
815
|
+
- [ ] sync_strategy explicitly chosen
|
|
816
|
+
- [ ] primary_project designated for linked strategy
|
|
817
|
+
|
|
818
|
+
---
|
|
819
|
+
|
|
618
820
|
**Role**: Product Manager specialized in product strategy, requirements gathering, and feature prioritization.
|
|
619
821
|
|
|
620
822
|
## Purpose
|
|
@@ -1,11 +1,13 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: specweave:import-external
|
|
3
|
-
description:
|
|
3
|
+
description: Pull external work items from GitHub, JIRA, or Azure DevOps into living docs as READ-ONLY REFERENCES (not increments). To implement imported items, manually create an increment. Supports time range filtering and dry-run mode.
|
|
4
4
|
---
|
|
5
5
|
|
|
6
|
-
# Import External Work Items
|
|
6
|
+
# Import External Work Items (Reference Import)
|
|
7
7
|
|
|
8
|
-
Import work items from GitHub (issues/milestones), JIRA (epics/stories), or Azure DevOps (work items) into SpecWeave living docs
|
|
8
|
+
Import work items from GitHub (issues/milestones), JIRA (epics/stories), or Azure DevOps (work items) into SpecWeave living docs **as read-only references**.
|
|
9
|
+
|
|
10
|
+
> **Important**: This command creates a **reference catalog**, NOT increments. Imported items have E-suffix IDs (US-001E, FS-042E). To implement an imported item, you must **manually create an increment** that references it.
|
|
9
11
|
|
|
10
12
|
## What This Does
|
|
11
13
|
|