specweave 0.33.2 → 0.33.4

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 (101) hide show
  1. package/CLAUDE.md +133 -19
  2. package/dist/plugins/specweave-ado/lib/per-us-sync.d.ts +120 -0
  3. package/dist/plugins/specweave-ado/lib/per-us-sync.d.ts.map +1 -0
  4. package/dist/plugins/specweave-ado/lib/per-us-sync.js +276 -0
  5. package/dist/plugins/specweave-ado/lib/per-us-sync.js.map +1 -0
  6. package/dist/plugins/specweave-github/lib/github-client-v2.d.ts +4 -1
  7. package/dist/plugins/specweave-github/lib/github-client-v2.d.ts.map +1 -1
  8. package/dist/plugins/specweave-github/lib/github-client-v2.js +13 -3
  9. package/dist/plugins/specweave-github/lib/github-client-v2.js.map +1 -1
  10. package/dist/plugins/specweave-github/lib/per-us-sync.d.ts +97 -0
  11. package/dist/plugins/specweave-github/lib/per-us-sync.d.ts.map +1 -0
  12. package/dist/plugins/specweave-github/lib/per-us-sync.js +274 -0
  13. package/dist/plugins/specweave-github/lib/per-us-sync.js.map +1 -0
  14. package/dist/plugins/specweave-jira/lib/per-us-sync.d.ts +113 -0
  15. package/dist/plugins/specweave-jira/lib/per-us-sync.d.ts.map +1 -0
  16. package/dist/plugins/specweave-jira/lib/per-us-sync.js +254 -0
  17. package/dist/plugins/specweave-jira/lib/per-us-sync.js.map +1 -0
  18. package/dist/src/cli/cleanup-zombies.js +8 -5
  19. package/dist/src/cli/cleanup-zombies.js.map +1 -1
  20. package/dist/src/config/types.d.ts +203 -1208
  21. package/dist/src/config/types.d.ts.map +1 -1
  22. package/dist/src/core/config/config-manager.d.ts.map +1 -1
  23. package/dist/src/core/config/config-manager.js +58 -0
  24. package/dist/src/core/config/config-manager.js.map +1 -1
  25. package/dist/src/core/config/types.d.ts +80 -0
  26. package/dist/src/core/config/types.d.ts.map +1 -1
  27. package/dist/src/core/config/types.js.map +1 -1
  28. package/dist/src/core/living-docs/cross-project-sync.d.ts +87 -15
  29. package/dist/src/core/living-docs/cross-project-sync.d.ts.map +1 -1
  30. package/dist/src/core/living-docs/cross-project-sync.js +147 -28
  31. package/dist/src/core/living-docs/cross-project-sync.js.map +1 -1
  32. package/dist/src/core/living-docs/living-docs-sync.d.ts.map +1 -1
  33. package/dist/src/core/living-docs/living-docs-sync.js +26 -22
  34. package/dist/src/core/living-docs/living-docs-sync.js.map +1 -1
  35. package/dist/src/core/living-docs/types.d.ts +24 -3
  36. package/dist/src/core/living-docs/types.d.ts.map +1 -1
  37. package/dist/src/core/types/config.d.ts +79 -0
  38. package/dist/src/core/types/config.d.ts.map +1 -1
  39. package/dist/src/core/types/config.js.map +1 -1
  40. package/dist/src/importers/jira-importer.d.ts +10 -0
  41. package/dist/src/importers/jira-importer.d.ts.map +1 -1
  42. package/dist/src/importers/jira-importer.js +55 -5
  43. package/dist/src/importers/jira-importer.js.map +1 -1
  44. package/dist/src/init/architecture/types.d.ts +33 -140
  45. package/dist/src/init/architecture/types.d.ts.map +1 -1
  46. package/dist/src/init/compliance/types.d.ts +30 -27
  47. package/dist/src/init/compliance/types.d.ts.map +1 -1
  48. package/dist/src/init/repo/types.d.ts +11 -34
  49. package/dist/src/init/repo/types.d.ts.map +1 -1
  50. package/dist/src/init/research/src/config/types.d.ts +15 -82
  51. package/dist/src/init/research/src/config/types.d.ts.map +1 -1
  52. package/dist/src/init/research/types.d.ts +38 -93
  53. package/dist/src/init/research/types.d.ts.map +1 -1
  54. package/dist/src/init/team/types.d.ts +4 -42
  55. package/dist/src/init/team/types.d.ts.map +1 -1
  56. package/dist/src/sync/closure-metrics.d.ts +102 -0
  57. package/dist/src/sync/closure-metrics.d.ts.map +1 -0
  58. package/dist/src/sync/closure-metrics.js +267 -0
  59. package/dist/src/sync/closure-metrics.js.map +1 -0
  60. package/dist/src/sync/sync-coordinator.d.ts +49 -0
  61. package/dist/src/sync/sync-coordinator.d.ts.map +1 -1
  62. package/dist/src/sync/sync-coordinator.js +399 -37
  63. package/dist/src/sync/sync-coordinator.js.map +1 -1
  64. package/dist/src/utils/notification-constants.d.ts +85 -0
  65. package/dist/src/utils/notification-constants.d.ts.map +1 -0
  66. package/dist/src/utils/notification-constants.js +129 -0
  67. package/dist/src/utils/notification-constants.js.map +1 -0
  68. package/dist/src/utils/platform-utils.d.ts +13 -3
  69. package/dist/src/utils/platform-utils.d.ts.map +1 -1
  70. package/dist/src/utils/platform-utils.js +17 -6
  71. package/dist/src/utils/platform-utils.js.map +1 -1
  72. package/dist/src/utils/project-resolver.d.ts +156 -0
  73. package/dist/src/utils/project-resolver.d.ts.map +1 -0
  74. package/dist/src/utils/project-resolver.js +587 -0
  75. package/dist/src/utils/project-resolver.js.map +1 -0
  76. package/package.json +1 -1
  77. package/plugins/specweave/commands/specweave-increment.md +46 -0
  78. package/plugins/specweave/commands/specweave-jobs.md +153 -8
  79. package/plugins/specweave/hooks/hooks.json +10 -0
  80. package/plugins/specweave/hooks/spec-project-validator.sh +24 -2
  81. package/plugins/specweave/hooks/universal/hook-wrapper.cmd +26 -26
  82. package/plugins/specweave/hooks/universal/session-start.cmd +16 -16
  83. package/plugins/specweave/hooks/universal/session-start.ps1 +16 -16
  84. package/plugins/specweave/hooks/user-prompt-submit.sh +105 -3
  85. package/plugins/specweave/hooks/v2/guards/per-us-project-validator.sh +281 -0
  86. package/plugins/specweave/hooks/v2/handlers/living-specs-handler.sh +29 -0
  87. package/plugins/specweave/scripts/session-watchdog.sh +278 -130
  88. package/plugins/specweave/skills/increment-planner/SKILL.md +48 -18
  89. package/plugins/specweave/skills/increment-planner/templates/spec-multi-project.md +27 -14
  90. package/plugins/specweave/skills/increment-planner/templates/spec-single-project.md +16 -5
  91. package/plugins/specweave/skills/spec-generator/SKILL.md +74 -15
  92. package/plugins/specweave-ado/lib/per-us-sync.js +247 -0
  93. package/plugins/specweave-ado/lib/per-us-sync.ts +410 -0
  94. package/plugins/specweave-github/lib/github-client-v2.js +10 -3
  95. package/plugins/specweave-github/lib/github-client-v2.ts +15 -3
  96. package/plugins/specweave-github/lib/per-us-sync.js +241 -0
  97. package/plugins/specweave-github/lib/per-us-sync.ts +375 -0
  98. package/plugins/specweave-jira/lib/per-us-sync.js +224 -0
  99. package/plugins/specweave-jira/lib/per-us-sync.ts +366 -0
  100. package/plugins/specweave-github/hooks/.specweave/logs/hooks-debug.log +0 -738
  101. package/plugins/specweave-release/hooks/.specweave/logs/dora-tracking.log +0 -1107
package/CLAUDE.md CHANGED
@@ -77,42 +77,118 @@ MetadataManager.updateStatus(incrementId, IncrementStatus.COMPLETED);
77
77
  // Only succeeds if current status is "ready_for_review"
78
78
  ```
79
79
 
80
- ### 2c. spec.md MUST Have project: (and board: for 2-level) (v0.31.0+)
80
+ ### 2c. spec.md MUST Have project: (and board: for 2-level) - RESOLVED VALUES ONLY! (v0.34.0+)
81
81
 
82
- **Increment creation WITHOUT project context = SYNC FAILURE**
82
+ **Increment creation WITHOUT resolved project context = SYNC FAILURE**
83
+
84
+ **⛔ YOU MUST RUN `specweave context projects` BEFORE GENERATING spec.md!**
85
+
86
+ ```bash
87
+ # MANDATORY FIRST STEP - run this BEFORE generating any spec.md:
88
+ specweave context projects
89
+
90
+ # Parse the JSON output:
91
+ # 1-level: {"level": 1, "projects": [{"id": "frontend-app"}, {"id": "backend-api"}]}
92
+ # 2-level: {"level": 2, "projects": [...], "boardsByProject": {"project-id": [{"id": "board-1"}]}}
93
+
94
+ # USE the actual IDs from the output - NEVER use placeholders!
95
+ ```
83
96
 
84
97
  ```yaml
85
- # 1-level structure (single project or multi-project):
98
+ # 1-level structure (RESOLVED values only):
86
99
  ---
87
100
  increment: 0001-feature-name
88
- project: my-project # ← MANDATORY
101
+ project: frontend-app # ← RESOLVED from context API (NOT {{PROJECT_ID}})
89
102
  ---
90
103
 
91
- # 2-level structure (ADO area paths, JIRA boards):
104
+ # 2-level structure (BOTH RESOLVED):
92
105
  ---
93
106
  increment: 0001-feature-name
94
- project: acme-corp # ← MANDATORY
95
- board: digital-operations # ← MANDATORY for 2-level
107
+ project: acme-corp # ← RESOLVED from projects[].id
108
+ board: digital-operations # ← RESOLVED from boardsByProject[project][].id
96
109
  ---
97
110
  ```
98
111
 
99
- **Detection**: Use `src/utils/structure-level-detector.ts`:
100
- ```typescript
101
- import { detectStructureLevel } from './utils/structure-level-detector.js';
102
- const config = detectStructureLevel(projectRoot);
103
- // config.level === 1 project required
104
- // config.level === 2 → project AND board required
112
+ **Per-US Project/Board (v0.34.0+ MANDATORY):**
113
+ ```markdown
114
+ ### US-001: Login Form
115
+ **Project**: frontend-app # RESOLVED value, not placeholder!
116
+ **Board**: ui-team # RESOLVED value (2-level only)
105
117
  ```
106
118
 
107
- **VALIDATION RULES:**
119
+ **VALIDATION RULES (ENFORCED BY HOOK):**
108
120
  ```
109
- ❌ FORBIDDEN: Creating spec.md with project: {{PROJECT_ID}} (unresolved placeholder)
110
- ❌ FORBIDDEN: Creating spec.md for 2-level without board: field
111
- ❌ FORBIDDEN: Vague increments without knowing sync target
112
- REQUIRED: Always select project (and board for 2-level) BEFORE generating spec.md
121
+ ❌ FORBIDDEN: Generating spec.md WITHOUT running "specweave context projects" first
122
+ ❌ FORBIDDEN: Using {{PROJECT_ID}}, {{BOARD_ID}}, {{RESOLVED_PROJECT}} placeholders
123
+ ❌ FORBIDDEN: Inventing project/board names not in the API response
124
+ FORBIDDEN: User stories without **Project**: field
125
+ ❌ FORBIDDEN: User stories in 2-level without **Board**: field
126
+ ✅ REQUIRED: Run "specweave context projects" and parse output BEFORE generating
127
+ ✅ REQUIRED: Each US has **Project**: with RESOLVED value from API
128
+ ✅ REQUIRED: Each US (2-level) has **Board**: with RESOLVED value from API
113
129
  ```
114
130
 
115
- **Pre-tool-use hook `spec-project-validator.sh` BLOCKS spec.md without required fields (2-level).**
131
+ **Pre-tool-use hook `spec-project-validator.sh` BLOCKS:**
132
+ - spec.md with `{{...}}` placeholders
133
+ - spec.md without `project:` field
134
+ - spec.md (2-level) without `board:` field
135
+ - User stories with unresolved `**Project**:` or `**Board**:` placeholders
136
+
137
+ ### 2c-bis. Each User Story MUST Have **Project**: (and **Board**: for 2-level) (v0.34.0+)
138
+
139
+ **CRITICAL 1:1 MAPPING RULE: Each User Story maps to EXACTLY ONE project and ONE board!**
140
+
141
+ ```markdown
142
+ ### US-001: Login Form UI
143
+ **Project**: frontend-app ← MANDATORY (exactly ONE project)
144
+ **Board**: ui-team ← MANDATORY for 2-level (exactly ONE board)
145
+ **As a** user, I want a login form...
146
+
147
+ ### US-002: Auth API Endpoints
148
+ **Project**: backend-api ← DIFFERENT project = OK
149
+ **Board**: api-team ← DIFFERENT board = OK
150
+ **As a** developer, I want JWT auth API...
151
+ ```
152
+
153
+ **1:1 MAPPING ENFORCEMENT:**
154
+ ```
155
+ ❌ FORBIDDEN: **Project**: frontend-app, backend-api (MULTIPLE projects)
156
+ ❌ FORBIDDEN: **Board**: ui-team, api-team (MULTIPLE boards)
157
+ ❌ FORBIDDEN: User Story without **Project**: field
158
+
159
+ ✅ REQUIRED: Each US has exactly ONE **Project**: value
160
+ ✅ REQUIRED: Each US has exactly ONE **Board**: value (2-level)
161
+ ✅ CROSS-PROJECT: Split into separate USs per project
162
+ ```
163
+
164
+ **Cross-project features → Create SEPARATE User Stories:**
165
+ ```markdown
166
+ ## OAuth Feature (Cross-Project)
167
+
168
+ ### US-001: OAuth Login Form
169
+ **Project**: frontend-app ← One project per US
170
+ ...
171
+
172
+ ### US-002: OAuth API Endpoints
173
+ **Project**: backend-api ← Different project = separate US
174
+ ...
175
+
176
+ ### US-003: OAuth Mobile Screen
177
+ **Project**: mobile-app ← Different project = separate US
178
+ ...
179
+ ```
180
+
181
+ **Pre-tool-use hook `per-us-project-validator.sh` BLOCKS spec.md with:**
182
+ - Missing `**Project**:` field per US
183
+ - Missing `**Board**:` field per US (2-level)
184
+ - Multiple comma-separated projects
185
+ - Multiple comma-separated boards
186
+
187
+ **Bypass (EMERGENCY ONLY):**
188
+ ```bash
189
+ SPECWEAVE_FORCE_PROJECT=1 # Skip all validation
190
+ SPECWEAVE_LEGACY_SPEC=1 # Allow legacy specs without per-US fields
191
+ ```
116
192
 
117
193
  ### 2d. NEVER Create Files in _features/ Folder (OBSOLETE v5.0.0+)
118
194
 
@@ -388,6 +464,44 @@ rm -f .specweave/state/.dedup-cache/*.lock
388
464
 
389
465
  **Mental model**: Bash = "run a program". Write/Edit/Read = "modify files".
390
466
 
467
+ ### 11. macOS Notifications - MUST Be Explicit (v0.33.3+)
468
+
469
+ **Vague notifications = user confusion!** Every notification MUST clearly state:
470
+ 1. **WHO** sent it (always start with "SpecWeave:")
471
+ 2. **WHAT** happened (specific action, not vague alert)
472
+ 3. **ACTION** needed (or "No action needed" if informational)
473
+
474
+ ```
475
+ ❌ FORBIDDEN (vague, alarming):
476
+ Title: "🚨 Zombie Cleanup" ← What does this mean?!
477
+ Sound: "Basso" (error sound) ← Red alert icon, scary!
478
+ Message: "Cleaned up 5 processes" ← So what?
479
+
480
+ ✅ CORRECT (explicit, calm):
481
+ Title: "SpecWeave: Cleanup Done" ← Clear source
482
+ Sound: "Pop" (neutral) ← Not alarming
483
+ Message: "Cleaned up 5 zombie processes. No action needed."
484
+ ```
485
+
486
+ **Sound selection rules:**
487
+ | Sound | When to use |
488
+ |-------|-------------|
489
+ | `Pop` | Success, completion (neutral) |
490
+ | `Glass` | Informational (gentle) |
491
+ | `Submarine` | Warning (not critical) |
492
+ | `Basso` | ONLY critical errors requiring immediate action |
493
+
494
+ **Use notification constants from `src/utils/notification-constants.ts`:**
495
+ ```typescript
496
+ import { getTitleForType, buildNotificationMessage, getSoundForType } from './notification-constants.js';
497
+
498
+ const title = getTitleForType('cleanup'); // "SpecWeave: Cleanup Done"
499
+ const msg = buildNotificationMessage('cleanup', { count: 5 }); // "Cleaned up 5 zombie..."
500
+ const sound = getSoundForType('cleanup'); // "Pop"
501
+ ```
502
+
503
+ **Pre-commit hook validates notification messages in new code (v0.33.3+).**
504
+
391
505
  ---
392
506
 
393
507
  ## Development Setup
@@ -0,0 +1,120 @@
1
+ /**
2
+ * Per-US Azure DevOps Sync (v0.34.0+)
3
+ *
4
+ * Syncs each User Story to its explicitly declared project's ADO project/area.
5
+ * Uses the **Project**: and **Board**: fields in spec.md (NOT keyword-based classification).
6
+ *
7
+ * Key difference from multi-project-sync:
8
+ * - Multi-project sync uses keyword/heuristic classification
9
+ * - Per-US sync uses EXPLICIT **Project**: and **Board**: fields from spec.md
10
+ *
11
+ * @module per-us-sync
12
+ * @since v0.34.0
13
+ */
14
+ import type { UserStoryData } from '../../../src/core/living-docs/types.js';
15
+ import type { ProjectMappings } from '../../../src/core/types/config.js';
16
+ import type { USExternalRefsMap } from '../../../src/core/types/increment-metadata.js';
17
+ import { Logger } from '../../../src/utils/logger.js';
18
+ /**
19
+ * Result of syncing a single US to ADO
20
+ */
21
+ export interface USSyncResult {
22
+ usId: string;
23
+ projectId: string;
24
+ adoProject: string;
25
+ areaPath: string;
26
+ workItemId: number;
27
+ url: string;
28
+ action: 'created' | 'updated' | 'skipped';
29
+ error?: string;
30
+ }
31
+ /**
32
+ * Result of syncing all USs in an increment
33
+ */
34
+ export interface PerUSSyncResult {
35
+ success: boolean;
36
+ synced: USSyncResult[];
37
+ failed: USSyncResult[];
38
+ externalRefs: USExternalRefsMap;
39
+ summary: {
40
+ total: number;
41
+ created: number;
42
+ updated: number;
43
+ skipped: number;
44
+ failed: number;
45
+ };
46
+ }
47
+ /**
48
+ * Options for per-US sync
49
+ */
50
+ export interface PerUSSyncOptions {
51
+ dryRun?: boolean;
52
+ force?: boolean;
53
+ defaultProject?: string;
54
+ defaultBoard?: string;
55
+ logger?: Logger;
56
+ }
57
+ /**
58
+ * ADO client interface (to be injected)
59
+ */
60
+ export interface AdoClient {
61
+ createWorkItem(project: string, workItemType: string, title: string, description: string, areaPath?: string): Promise<{
62
+ id: number;
63
+ url: string;
64
+ }>;
65
+ updateWorkItem(project: string, workItemId: number, title: string, description: string, areaPath?: string): Promise<void>;
66
+ searchWorkItems(project: string, query: string): Promise<Array<{
67
+ id: number;
68
+ fields: {
69
+ 'System.Title': string;
70
+ };
71
+ }>>;
72
+ getWorkItemUrl(project: string, workItemId: number): string;
73
+ }
74
+ /**
75
+ * Per-US ADO Sync
76
+ *
77
+ * Syncs each US to its declared project's ADO project/area path.
78
+ * For 2-level structures, uses **Board**: to determine area path.
79
+ */
80
+ export declare class PerUSAdoSync {
81
+ private projectMappings;
82
+ private adoClient;
83
+ private logger;
84
+ constructor(adoClient: AdoClient, projectMappings: ProjectMappings, options?: {
85
+ logger?: Logger;
86
+ });
87
+ /**
88
+ * Sync all user stories to their respective ADO projects
89
+ *
90
+ * @param userStories - User stories with explicit project/board fields
91
+ * @param featureId - Feature ID (e.g., "FS-137")
92
+ * @param options - Sync options
93
+ */
94
+ syncUserStories(userStories: UserStoryData[], featureId: string, options?: PerUSSyncOptions): Promise<PerUSSyncResult>;
95
+ /**
96
+ * Sync a single user story to ADO
97
+ *
98
+ * For 2-level structures:
99
+ * - **Project**: maps to ADO project
100
+ * - **Board**: maps to area path under the project
101
+ */
102
+ private syncUserStory;
103
+ /**
104
+ * Find existing work item by US ID in title
105
+ */
106
+ private findExistingWorkItem;
107
+ /**
108
+ * Build work item description from user story
109
+ */
110
+ private buildWorkItemDescription;
111
+ /**
112
+ * Group user stories by their explicit project field
113
+ */
114
+ private groupByProject;
115
+ }
116
+ /**
117
+ * Format per-US sync results for display
118
+ */
119
+ export declare function formatPerUSSyncResults(result: PerUSSyncResult): string;
120
+ //# sourceMappingURL=per-us-sync.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"per-us-sync.d.ts","sourceRoot":"","sources":["../../../../plugins/specweave-ado/lib/per-us-sync.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,276 @@
1
+ /**
2
+ * Per-US Azure DevOps Sync (v0.34.0+)
3
+ *
4
+ * Syncs each User Story to its explicitly declared project's ADO project/area.
5
+ * Uses the **Project**: and **Board**: fields in spec.md (NOT keyword-based classification).
6
+ *
7
+ * Key difference from multi-project-sync:
8
+ * - Multi-project sync uses keyword/heuristic classification
9
+ * - Per-US sync uses EXPLICIT **Project**: and **Board**: fields from spec.md
10
+ *
11
+ * @module per-us-sync
12
+ * @since v0.34.0
13
+ */
14
+ import { consoleLogger } from '../../../src/utils/logger.js';
15
+ /**
16
+ * Per-US ADO Sync
17
+ *
18
+ * Syncs each US to its declared project's ADO project/area path.
19
+ * For 2-level structures, uses **Board**: to determine area path.
20
+ */
21
+ export class PerUSAdoSync {
22
+ constructor(adoClient, projectMappings, options = {}) {
23
+ this.adoClient = adoClient;
24
+ this.projectMappings = projectMappings;
25
+ this.logger = options.logger ?? consoleLogger;
26
+ }
27
+ /**
28
+ * Sync all user stories to their respective ADO projects
29
+ *
30
+ * @param userStories - User stories with explicit project/board fields
31
+ * @param featureId - Feature ID (e.g., "FS-137")
32
+ * @param options - Sync options
33
+ */
34
+ async syncUserStories(userStories, featureId, options = {}) {
35
+ const synced = [];
36
+ const failed = [];
37
+ const externalRefs = {};
38
+ // Group USs by their declared project
39
+ const groups = this.groupByProject(userStories, options.defaultProject);
40
+ this.logger.log(`📡 Per-US ADO Sync: ${userStories.length} USs across ${groups.size} projects`);
41
+ for (const [projectId, stories] of groups) {
42
+ // Get ADO mapping for this project
43
+ const mapping = this.projectMappings[projectId]?.ado;
44
+ if (!mapping) {
45
+ // No ADO mapping for this project
46
+ this.logger.warn(` ⚠️ No ADO mapping for project "${projectId}" - skipping ${stories.length} USs`);
47
+ for (const story of stories) {
48
+ failed.push({
49
+ usId: story.id,
50
+ projectId,
51
+ adoProject: 'N/A',
52
+ areaPath: '',
53
+ workItemId: 0,
54
+ url: '',
55
+ action: 'skipped',
56
+ error: `No ADO mapping for project "${projectId}"`
57
+ });
58
+ }
59
+ continue;
60
+ }
61
+ // Sync each US to this project's ADO project
62
+ for (const story of stories) {
63
+ try {
64
+ const result = await this.syncUserStory(story, mapping, featureId, options);
65
+ synced.push({
66
+ ...result,
67
+ projectId
68
+ });
69
+ // Build external ref
70
+ if (!options.dryRun && result.action !== 'skipped') {
71
+ externalRefs[story.id] = {
72
+ ado: {
73
+ provider: 'ado',
74
+ issueNumber: result.workItemId,
75
+ url: result.url,
76
+ targetProject: projectId,
77
+ lastSynced: new Date().toISOString()
78
+ }
79
+ };
80
+ }
81
+ }
82
+ catch (error) {
83
+ failed.push({
84
+ usId: story.id,
85
+ projectId,
86
+ adoProject: mapping.project,
87
+ areaPath: mapping.areaPath || '',
88
+ workItemId: 0,
89
+ url: '',
90
+ action: 'skipped',
91
+ error: error instanceof Error ? error.message : String(error)
92
+ });
93
+ }
94
+ }
95
+ }
96
+ // Calculate summary
97
+ const created = synced.filter(r => r.action === 'created').length;
98
+ const updated = synced.filter(r => r.action === 'updated').length;
99
+ const skipped = synced.filter(r => r.action === 'skipped').length;
100
+ return {
101
+ success: failed.length === 0,
102
+ synced,
103
+ failed,
104
+ externalRefs,
105
+ summary: {
106
+ total: userStories.length,
107
+ created,
108
+ updated,
109
+ skipped,
110
+ failed: failed.length
111
+ }
112
+ };
113
+ }
114
+ /**
115
+ * Sync a single user story to ADO
116
+ *
117
+ * For 2-level structures:
118
+ * - **Project**: maps to ADO project
119
+ * - **Board**: maps to area path under the project
120
+ */
121
+ async syncUserStory(story, mapping, featureId, options) {
122
+ const title = `[${featureId}][${story.id}] ${story.title}`;
123
+ const description = this.buildWorkItemDescription(story, featureId);
124
+ // Determine area path:
125
+ // - Use story.board if available (2-level structure)
126
+ // - Fall back to mapping.areaPath
127
+ // - Fall back to project root
128
+ let areaPath = mapping.areaPath || mapping.project;
129
+ if (story.board) {
130
+ // 2-level structure: append board as area path segment
131
+ areaPath = `${mapping.project}\\${story.board}`;
132
+ }
133
+ if (options.dryRun) {
134
+ this.logger.log(` 🔍 [DRY-RUN] Would sync ${story.id} to ${mapping.project} (area: ${areaPath})`);
135
+ return {
136
+ usId: story.id,
137
+ projectId: story.project || 'unknown',
138
+ adoProject: mapping.project,
139
+ areaPath,
140
+ workItemId: 0,
141
+ url: '',
142
+ action: 'skipped'
143
+ };
144
+ }
145
+ // Check for existing work item
146
+ const existingItem = await this.findExistingWorkItem(mapping.project, story.id);
147
+ if (existingItem) {
148
+ // Update existing work item
149
+ await this.adoClient.updateWorkItem(mapping.project, existingItem.id, title, description, areaPath);
150
+ this.logger.log(` 🔄 Updated ${story.id} → ${mapping.project}/${existingItem.id}`);
151
+ return {
152
+ usId: story.id,
153
+ projectId: story.project || 'unknown',
154
+ adoProject: mapping.project,
155
+ areaPath,
156
+ workItemId: existingItem.id,
157
+ url: this.adoClient.getWorkItemUrl(mapping.project, existingItem.id),
158
+ action: 'updated'
159
+ };
160
+ }
161
+ else {
162
+ // Create new work item
163
+ const newItem = await this.adoClient.createWorkItem(mapping.project, 'User Story', title, description, areaPath);
164
+ this.logger.log(` ✅ Created ${story.id} → ${mapping.project}/${newItem.id}`);
165
+ return {
166
+ usId: story.id,
167
+ projectId: story.project || 'unknown',
168
+ adoProject: mapping.project,
169
+ areaPath,
170
+ workItemId: newItem.id,
171
+ url: newItem.url,
172
+ action: 'created'
173
+ };
174
+ }
175
+ }
176
+ /**
177
+ * Find existing work item by US ID in title
178
+ */
179
+ async findExistingWorkItem(project, usId) {
180
+ try {
181
+ const query = `[System.Title] Contains '[${usId}]'`;
182
+ const results = await this.adoClient.searchWorkItems(project, query);
183
+ return results.length > 0 ? { id: results[0].id } : null;
184
+ }
185
+ catch {
186
+ return null;
187
+ }
188
+ }
189
+ /**
190
+ * Build work item description from user story
191
+ */
192
+ buildWorkItemDescription(story, featureId) {
193
+ const lines = [];
194
+ lines.push(`<h1>${story.title}</h1>`);
195
+ lines.push('');
196
+ if (story.description) {
197
+ lines.push(`<p>${story.description}</p>`);
198
+ lines.push('');
199
+ }
200
+ if (story.acceptanceCriteria && story.acceptanceCriteria.length > 0) {
201
+ lines.push('<h2>Acceptance Criteria</h2>');
202
+ lines.push('<ul>');
203
+ for (const ac of story.acceptanceCriteria) {
204
+ lines.push(` <li>${ac}</li>`);
205
+ }
206
+ lines.push('</ul>');
207
+ lines.push('');
208
+ }
209
+ lines.push('<hr/>');
210
+ lines.push('');
211
+ lines.push(`<p><strong>Feature</strong>: ${featureId}</p>`);
212
+ lines.push(`<p><strong>User Story</strong>: ${story.id}</p>`);
213
+ if (story.project) {
214
+ lines.push(`<p><strong>Project</strong>: ${story.project}</p>`);
215
+ }
216
+ if (story.board) {
217
+ lines.push(`<p><strong>Board</strong>: ${story.board}</p>`);
218
+ }
219
+ lines.push('');
220
+ lines.push('<p><em>Auto-generated by SpecWeave</em></p>');
221
+ return lines.join('\n');
222
+ }
223
+ /**
224
+ * Group user stories by their explicit project field
225
+ */
226
+ groupByProject(userStories, defaultProject) {
227
+ const groups = new Map();
228
+ for (const story of userStories) {
229
+ const project = story.project || defaultProject || 'default';
230
+ if (!groups.has(project)) {
231
+ groups.set(project, []);
232
+ }
233
+ groups.get(project).push(story);
234
+ }
235
+ return groups;
236
+ }
237
+ }
238
+ /**
239
+ * Format per-US sync results for display
240
+ */
241
+ export function formatPerUSSyncResults(result) {
242
+ const lines = [];
243
+ lines.push('');
244
+ lines.push('📊 Per-US ADO Sync Results');
245
+ lines.push('');
246
+ // Group by project
247
+ const byProject = new Map();
248
+ for (const r of [...result.synced, ...result.failed]) {
249
+ const existing = byProject.get(r.projectId) || [];
250
+ existing.push(r);
251
+ byProject.set(r.projectId, existing);
252
+ }
253
+ for (const [projectId, results] of byProject) {
254
+ const adoProject = results[0]?.adoProject || 'N/A';
255
+ const areaPath = results[0]?.areaPath || '';
256
+ lines.push(`**${projectId}** (→ ${adoProject}${areaPath ? ` [${areaPath}]` : ''}):`);
257
+ for (const r of results) {
258
+ const icon = r.action === 'created' ? '✅' :
259
+ r.action === 'updated' ? '🔄' :
260
+ r.error ? '❌' : '⏭️';
261
+ if (r.workItemId > 0) {
262
+ lines.push(` ${icon} ${r.usId} → ${r.adoProject}/${r.workItemId}`);
263
+ }
264
+ else if (r.error) {
265
+ lines.push(` ${icon} ${r.usId}: ${r.error}`);
266
+ }
267
+ else {
268
+ lines.push(` ${icon} ${r.usId} (${r.action})`);
269
+ }
270
+ }
271
+ lines.push('');
272
+ }
273
+ lines.push(`📈 Summary: ${result.summary.created} created, ${result.summary.updated} updated, ${result.summary.failed} failed`);
274
+ return lines.join('\n');
275
+ }
276
+ //# sourceMappingURL=per-us-sync.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"per-us-sync.js","sourceRoot":"","sources":["../../../../plugins/specweave-ado/lib/per-us-sync.ts"],"names":[],"mappings":"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"}
@@ -101,8 +101,11 @@ export declare class GitHubClientV2 {
101
101
  * Search for issue by exact title match
102
102
  *
103
103
  * IDEMPOTENCY: Use this before creating issues to prevent duplicates
104
+ *
105
+ * @param title - Title pattern to search for (e.g., "[FS-136][US-001]")
106
+ * @param includeClosedIssues - If true, searches all issues (open+closed). Default: false (open only)
104
107
  */
105
- searchIssueByTitle(title: string): Promise<GitHubIssue | null>;
108
+ searchIssueByTitle(title: string, includeClosedIssues?: boolean): Promise<GitHubIssue | null>;
106
109
  /**
107
110
  * Update issue body
108
111
  */
@@ -1 +1 @@
1
- {"version":3,"file":"github-client-v2.d.ts","sourceRoot":"","sources":["../../../../plugins/specweave-github/lib/github-client-v2.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"github-client-v2.d.ts","sourceRoot":"","sources":["../../../../plugins/specweave-github/lib/github-client-v2.ts"],"names":[],"mappings":"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"}
@@ -299,11 +299,14 @@ export class GitHubClientV2 {
299
299
  * Search for issue by exact title match
300
300
  *
301
301
  * IDEMPOTENCY: Use this before creating issues to prevent duplicates
302
+ *
303
+ * @param title - Title pattern to search for (e.g., "[FS-136][US-001]")
304
+ * @param includeClosedIssues - If true, searches all issues (open+closed). Default: false (open only)
302
305
  */
303
- async searchIssueByTitle(title) {
306
+ async searchIssueByTitle(title, includeClosedIssues = false) {
304
307
  // Escape double quotes in title for gh search
305
308
  const escapedTitle = title.replace(/"/g, '\\"');
306
- const result = await execFileNoThrow('gh', [
309
+ const args = [
307
310
  'issue',
308
311
  'list',
309
312
  '--repo',
@@ -314,7 +317,14 @@ export class GitHubClientV2 {
314
317
  'number,title,state,url,labels',
315
318
  '--limit',
316
319
  '50', // ✅ FIX: Increased from 1 to 50 to catch duplicates (Issue #0047)
317
- ]);
320
+ ];
321
+ // v0.34.0: Add --state all to search closed issues too (for closure flow)
322
+ // Without this, closeGitHubIssuesForUserStories() can't find already-closed issues
323
+ // and reports "No GitHub issue found" instead of "already closed"
324
+ if (includeClosedIssues) {
325
+ args.push('--state', 'all');
326
+ }
327
+ const result = await execFileNoThrow('gh', args);
318
328
  if (result.exitCode !== 0) {
319
329
  // Search failed, return null (treat as not found)
320
330
  return null;