specweave 0.32.2 → 0.32.3
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/CLAUDE.md +39 -0
- package/bin/specweave.js +34 -0
- package/dist/plugins/specweave-ado/lib/ado-duplicate-detector.d.ts +100 -0
- package/dist/plugins/specweave-ado/lib/ado-duplicate-detector.d.ts.map +1 -0
- package/dist/plugins/specweave-ado/lib/ado-duplicate-detector.js +291 -0
- package/dist/plugins/specweave-ado/lib/ado-duplicate-detector.js.map +1 -0
- package/dist/plugins/specweave-jira/lib/jira-duplicate-detector.d.ts +103 -0
- package/dist/plugins/specweave-jira/lib/jira-duplicate-detector.d.ts.map +1 -0
- package/dist/plugins/specweave-jira/lib/jira-duplicate-detector.js +310 -0
- package/dist/plugins/specweave-jira/lib/jira-duplicate-detector.js.map +1 -0
- package/dist/plugins/specweave-jira/lib/jira-permission-gate.d.ts +126 -0
- package/dist/plugins/specweave-jira/lib/jira-permission-gate.d.ts.map +1 -0
- package/dist/plugins/specweave-jira/lib/jira-permission-gate.js +207 -0
- package/dist/plugins/specweave-jira/lib/jira-permission-gate.js.map +1 -0
- package/dist/src/adapters/codex/README.md +1 -1
- package/dist/src/adapters/codex/adapter.js +1 -1
- package/dist/src/cli/commands/archive.d.ts +2 -0
- package/dist/src/cli/commands/archive.d.ts.map +1 -1
- package/dist/src/cli/commands/archive.js +33 -0
- package/dist/src/cli/commands/archive.js.map +1 -1
- package/dist/src/cli/commands/context.d.ts +92 -0
- package/dist/src/cli/commands/context.d.ts.map +1 -0
- package/dist/src/cli/commands/context.js +205 -0
- package/dist/src/cli/commands/context.js.map +1 -0
- package/dist/src/cli/commands/init.d.ts.map +1 -1
- package/dist/src/cli/commands/init.js +111 -69
- package/dist/src/cli/commands/init.js.map +1 -1
- package/dist/src/cli/helpers/init/external-import.d.ts +3 -0
- package/dist/src/cli/helpers/init/external-import.d.ts.map +1 -1
- package/dist/src/cli/helpers/init/external-import.js +17 -4
- package/dist/src/cli/helpers/init/external-import.js.map +1 -1
- package/dist/src/cli/helpers/init/index.d.ts +1 -0
- package/dist/src/cli/helpers/init/index.d.ts.map +1 -1
- package/dist/src/cli/helpers/init/index.js +2 -0
- package/dist/src/cli/helpers/init/index.js.map +1 -1
- package/dist/src/cli/helpers/init/jira-ado-auto-detect.d.ts +70 -0
- package/dist/src/cli/helpers/init/jira-ado-auto-detect.d.ts.map +1 -1
- package/dist/src/cli/helpers/init/jira-ado-auto-detect.js +214 -4
- package/dist/src/cli/helpers/init/jira-ado-auto-detect.js.map +1 -1
- package/dist/src/cli/helpers/init/living-docs-preflight.d.ts +4 -0
- package/dist/src/cli/helpers/init/living-docs-preflight.d.ts.map +1 -1
- package/dist/src/cli/helpers/init/living-docs-preflight.js +34 -3
- package/dist/src/cli/helpers/init/living-docs-preflight.js.map +1 -1
- package/dist/src/cli/helpers/init/testing-config.d.ts +3 -0
- package/dist/src/cli/helpers/init/testing-config.d.ts.map +1 -1
- package/dist/src/cli/helpers/init/testing-config.js +9 -2
- package/dist/src/cli/helpers/init/testing-config.js.map +1 -1
- package/dist/src/cli/helpers/init/translation-config.d.ts +3 -0
- package/dist/src/cli/helpers/init/translation-config.d.ts.map +1 -1
- package/dist/src/cli/helpers/init/translation-config.js +21 -4
- package/dist/src/cli/helpers/init/translation-config.js.map +1 -1
- package/dist/src/cli/helpers/init/wizard-navigation.d.ts +45 -0
- package/dist/src/cli/helpers/init/wizard-navigation.d.ts.map +1 -0
- package/dist/src/cli/helpers/init/wizard-navigation.js +97 -0
- package/dist/src/cli/helpers/init/wizard-navigation.js.map +1 -0
- package/dist/src/core/increment/increment-archiver.d.ts +25 -4
- package/dist/src/core/increment/increment-archiver.d.ts.map +1 -1
- package/dist/src/core/increment/increment-archiver.js +64 -20
- package/dist/src/core/increment/increment-archiver.js.map +1 -1
- package/dist/src/core/increment/increment-utils.d.ts +65 -0
- package/dist/src/core/increment/increment-utils.d.ts.map +1 -1
- package/dist/src/core/increment/increment-utils.js +114 -0
- package/dist/src/core/increment/increment-utils.js.map +1 -1
- package/dist/src/core/living-docs/feature-archiver.d.ts +4 -0
- package/dist/src/core/living-docs/feature-archiver.d.ts.map +1 -1
- package/dist/src/core/living-docs/feature-archiver.js +32 -10
- package/dist/src/core/living-docs/feature-archiver.js.map +1 -1
- package/dist/src/core/living-docs/feature-id-manager.d.ts.map +1 -1
- package/dist/src/core/living-docs/feature-id-manager.js +7 -3
- package/dist/src/core/living-docs/feature-id-manager.js.map +1 -1
- package/dist/src/core/living-docs/governance/ecosystem-detector.d.ts +38 -0
- package/dist/src/core/living-docs/governance/ecosystem-detector.d.ts.map +1 -0
- package/dist/src/core/living-docs/governance/ecosystem-detector.js +325 -0
- package/dist/src/core/living-docs/governance/ecosystem-detector.js.map +1 -0
- package/dist/src/core/living-docs/governance/frontend-standards-parser.d.ts +74 -0
- package/dist/src/core/living-docs/governance/frontend-standards-parser.d.ts.map +1 -0
- package/dist/src/core/living-docs/governance/frontend-standards-parser.js +366 -0
- package/dist/src/core/living-docs/governance/frontend-standards-parser.js.map +1 -0
- package/dist/src/core/living-docs/governance/go-standards-parser.d.ts +64 -0
- package/dist/src/core/living-docs/governance/go-standards-parser.d.ts.map +1 -0
- package/dist/src/core/living-docs/governance/go-standards-parser.js +229 -0
- package/dist/src/core/living-docs/governance/go-standards-parser.js.map +1 -0
- package/dist/src/core/living-docs/governance/index.d.ts +50 -0
- package/dist/src/core/living-docs/governance/index.d.ts.map +1 -0
- package/dist/src/core/living-docs/governance/index.js +56 -0
- package/dist/src/core/living-docs/governance/index.js.map +1 -0
- package/dist/src/core/living-docs/governance/java-standards-parser.d.ts +89 -0
- package/dist/src/core/living-docs/governance/java-standards-parser.d.ts.map +1 -0
- package/dist/src/core/living-docs/governance/java-standards-parser.js +356 -0
- package/dist/src/core/living-docs/governance/java-standards-parser.js.map +1 -0
- package/dist/src/core/living-docs/governance/python-standards-parser.d.ts +83 -0
- package/dist/src/core/living-docs/governance/python-standards-parser.d.ts.map +1 -0
- package/dist/src/core/living-docs/governance/python-standards-parser.js +347 -0
- package/dist/src/core/living-docs/governance/python-standards-parser.js.map +1 -0
- package/dist/src/core/living-docs/governance/standards-generator.d.ts +38 -0
- package/dist/src/core/living-docs/governance/standards-generator.d.ts.map +1 -0
- package/dist/src/core/living-docs/governance/standards-generator.js +476 -0
- package/dist/src/core/living-docs/governance/standards-generator.js.map +1 -0
- package/dist/src/core/living-docs/intelligent-analyzer/architecture-generator.d.ts.map +1 -1
- package/dist/src/core/living-docs/intelligent-analyzer/architecture-generator.js +54 -2
- package/dist/src/core/living-docs/intelligent-analyzer/architecture-generator.js.map +1 -1
- package/dist/src/core/living-docs/intelligent-analyzer/organization-synthesizer.d.ts +5 -1
- package/dist/src/core/living-docs/intelligent-analyzer/organization-synthesizer.d.ts.map +1 -1
- package/dist/src/core/living-docs/intelligent-analyzer/organization-synthesizer.js +358 -30
- package/dist/src/core/living-docs/intelligent-analyzer/organization-synthesizer.js.map +1 -1
- package/dist/src/core/living-docs/intelligent-analyzer/types.d.ts +44 -0
- package/dist/src/core/living-docs/intelligent-analyzer/types.d.ts.map +1 -1
- package/dist/src/core/living-docs/living-docs-sync.d.ts +6 -3
- package/dist/src/core/living-docs/living-docs-sync.d.ts.map +1 -1
- package/dist/src/core/living-docs/living-docs-sync.js +17 -8
- package/dist/src/core/living-docs/living-docs-sync.js.map +1 -1
- package/dist/src/core/living-docs/module-analyzer.d.ts +22 -0
- package/dist/src/core/living-docs/module-analyzer.d.ts.map +1 -1
- package/dist/src/core/living-docs/module-analyzer.js +123 -19
- package/dist/src/core/living-docs/module-analyzer.js.map +1 -1
- package/dist/src/core/llm/provider-factory.js +2 -2
- package/dist/src/core/llm/provider-factory.js.map +1 -1
- package/dist/src/core/llm/providers/anthropic-provider.js +1 -1
- package/dist/src/core/llm/providers/bedrock-provider.d.ts.map +1 -1
- package/dist/src/core/llm/providers/bedrock-provider.js +8 -4
- package/dist/src/core/llm/providers/bedrock-provider.js.map +1 -1
- package/dist/src/importers/jira-importer.d.ts +14 -0
- package/dist/src/importers/jira-importer.d.ts.map +1 -1
- package/dist/src/importers/jira-importer.js +75 -0
- package/dist/src/importers/jira-importer.js.map +1 -1
- package/dist/src/integrations/jira/jira-token-provider.d.ts +93 -0
- package/dist/src/integrations/jira/jira-token-provider.d.ts.map +1 -0
- package/dist/src/integrations/jira/jira-token-provider.js +160 -0
- package/dist/src/integrations/jira/jira-token-provider.js.map +1 -0
- package/dist/src/sync/ado-reconciler.d.ts +92 -0
- package/dist/src/sync/ado-reconciler.d.ts.map +1 -0
- package/dist/src/sync/ado-reconciler.js +335 -0
- package/dist/src/sync/ado-reconciler.js.map +1 -0
- package/dist/src/sync/jira-reconciler.d.ts +106 -0
- package/dist/src/sync/jira-reconciler.d.ts.map +1 -0
- package/dist/src/sync/jira-reconciler.js +405 -0
- package/dist/src/sync/jira-reconciler.js.map +1 -0
- package/dist/src/types/model-selection.d.ts +6 -4
- package/dist/src/types/model-selection.d.ts.map +1 -1
- package/dist/src/types/model-selection.js +3 -1
- package/dist/src/types/model-selection.js.map +1 -1
- package/dist/src/utils/external-tool-drift-detector.d.ts +1 -1
- package/dist/src/utils/external-tool-drift-detector.d.ts.map +1 -1
- package/dist/src/utils/external-tool-drift-detector.js +5 -4
- package/dist/src/utils/external-tool-drift-detector.js.map +1 -1
- package/dist/src/utils/feature-id-derivation.d.ts +8 -3
- package/dist/src/utils/feature-id-derivation.d.ts.map +1 -1
- package/dist/src/utils/feature-id-derivation.js +14 -6
- package/dist/src/utils/feature-id-derivation.js.map +1 -1
- package/dist/src/utils/model-selection.d.ts +3 -4
- package/dist/src/utils/model-selection.d.ts.map +1 -1
- package/dist/src/utils/model-selection.js +3 -4
- package/dist/src/utils/model-selection.js.map +1 -1
- package/package.json +1 -1
- package/plugins/specweave/agents/code-standards-detective/AGENT.md +48 -0
- package/plugins/specweave/commands/specweave-costs.md +4 -4
- package/plugins/specweave/commands/specweave-do.md +9 -9
- package/plugins/specweave/commands/specweave-done.md +13 -0
- package/plugins/specweave/commands/specweave-validate.md +27 -1
- package/plugins/specweave/hooks/hooks.json +10 -0
- package/plugins/specweave/hooks/spec-project-validator.sh +80 -25
- package/plugins/specweave/hooks/v2/guards/increment-duplicate-guard.sh +135 -0
- package/plugins/specweave/scripts/read-costs.sh +3 -3
- package/plugins/specweave/skills/code-standards-analyzer/SKILL.md +58 -6
- package/plugins/specweave/skills/increment-planner/SKILL.md +56 -25
- package/plugins/specweave/skills/increment-planner/templates/spec-multi-project.md +4 -2
- package/plugins/specweave/skills/increment-planner/templates/spec-single-project.md +2 -1
- package/plugins/specweave/skills/increment-planner/templates/tasks-multi-project.md +1 -1
- package/plugins/specweave/skills/increment-planner/templates/tasks-single-project.md +1 -1
- package/plugins/specweave-ado/commands/cleanup-duplicates.md +212 -0
- package/plugins/specweave-ado/commands/reconcile.md +120 -0
- package/plugins/specweave-ado/lib/ado-duplicate-detector.js +279 -0
- package/plugins/specweave-ado/lib/ado-duplicate-detector.ts +407 -0
- package/plugins/specweave-github/agents/github-manager/AGENT.md +2 -2
- package/plugins/specweave-infrastructure/skills/hetzner-provisioner/README.md +1 -1
- package/plugins/specweave-jira/agents/jira-manager/AGENT.md +1 -1
- package/plugins/specweave-jira/agents/jira-multi-project-mapper/AGENT.md +530 -0
- package/plugins/specweave-jira/agents/jira-sync-judge/AGENT.md +438 -0
- package/plugins/specweave-jira/commands/cleanup-duplicates.md +219 -0
- package/plugins/specweave-jira/commands/close.md +297 -0
- package/plugins/specweave-jira/commands/create.md +198 -0
- package/plugins/specweave-jira/commands/reconcile.md +123 -0
- package/plugins/specweave-jira/commands/status.md +215 -0
- package/plugins/specweave-jira/lib/jira-duplicate-detector.js +296 -0
- package/plugins/specweave-jira/lib/jira-duplicate-detector.ts +434 -0
- package/plugins/specweave-jira/lib/jira-permission-gate.js +160 -0
- package/plugins/specweave-jira/lib/jira-permission-gate.ts +276 -0
- package/plugins/specweave-jira/lib/jira-profile-resolver.js +222 -0
- package/plugins/specweave-jira/lib/jira-profile-resolver.ts +427 -0
- package/plugins/specweave-jira/reference/jira-specweave-mapping.md +16 -11
- package/plugins/specweave-release/commands/specweave-release-npm.md +140 -14
|
@@ -0,0 +1,335 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Azure DevOps Reconciler (NEW in v0.33.0)
|
|
3
|
+
*
|
|
4
|
+
* Reconciles ADO work item states with increment metadata.json statuses.
|
|
5
|
+
* Fixes drift between local SpecWeave state and ADO:
|
|
6
|
+
* - Closes work items for completed increments that are still active
|
|
7
|
+
* - Reactivates work items for in-progress increments that are closed
|
|
8
|
+
*
|
|
9
|
+
* Mirrors the GitHub reconciler pattern for consistency.
|
|
10
|
+
*
|
|
11
|
+
* Triggered by:
|
|
12
|
+
* - /specweave-ado:reconcile command (manual)
|
|
13
|
+
* - SessionStart hook (automatic, if configured)
|
|
14
|
+
* - post-increment-status-change.sh (on resume/abandon)
|
|
15
|
+
*/
|
|
16
|
+
import { promises as fs, existsSync } from 'fs';
|
|
17
|
+
import path from 'path';
|
|
18
|
+
import { consoleLogger } from '../utils/logger.js';
|
|
19
|
+
/**
|
|
20
|
+
* ADO Status Mapping
|
|
21
|
+
*/
|
|
22
|
+
const ADO_STATUSES = {
|
|
23
|
+
CLOSED: ['Closed', 'Done', 'Resolved', 'Removed'],
|
|
24
|
+
ACTIVE: ['Active', 'New', 'In Progress', 'Committed'],
|
|
25
|
+
};
|
|
26
|
+
export class AdoReconciler {
|
|
27
|
+
constructor(options) {
|
|
28
|
+
this.projectRoot = options.projectRoot;
|
|
29
|
+
this.dryRun = options.dryRun ?? false;
|
|
30
|
+
this.logger = options.logger ?? consoleLogger;
|
|
31
|
+
}
|
|
32
|
+
/**
|
|
33
|
+
* Main reconciliation entry point
|
|
34
|
+
*/
|
|
35
|
+
async reconcile() {
|
|
36
|
+
const result = {
|
|
37
|
+
scanned: 0,
|
|
38
|
+
mismatches: 0,
|
|
39
|
+
closed: 0,
|
|
40
|
+
reopened: 0,
|
|
41
|
+
errors: [],
|
|
42
|
+
details: [],
|
|
43
|
+
};
|
|
44
|
+
try {
|
|
45
|
+
// 1. Check if ADO sync is enabled
|
|
46
|
+
const config = await this.loadConfig();
|
|
47
|
+
const canUpdate = config.sync?.settings?.canUpdateExternalItems ?? false;
|
|
48
|
+
const adoEnabled = config.sync?.ado?.enabled ?? false;
|
|
49
|
+
if (!canUpdate || !adoEnabled) {
|
|
50
|
+
this.logger.log('ℹ️ ADO sync is disabled - skipping reconciliation');
|
|
51
|
+
this.logger.log(' Enable with: canUpdateExternalItems=true AND sync.ado.enabled=true');
|
|
52
|
+
return result;
|
|
53
|
+
}
|
|
54
|
+
// 2. Verify ADO credentials
|
|
55
|
+
const hasCredentials = this.hasAdoCredentials();
|
|
56
|
+
if (!hasCredentials) {
|
|
57
|
+
result.errors.push('ADO credentials not configured');
|
|
58
|
+
this.logger.error('❌ ADO PAT not found. Set AZURE_DEVOPS_PAT environment variable.');
|
|
59
|
+
return result;
|
|
60
|
+
}
|
|
61
|
+
// 3. Scan all non-archived increments
|
|
62
|
+
const increments = await this.scanIncrements();
|
|
63
|
+
result.scanned = increments.length;
|
|
64
|
+
this.logger.log(`\n📊 Scanning ${increments.length} increment(s) for ADO state drift...\n`);
|
|
65
|
+
// 4. Check and fix each increment
|
|
66
|
+
for (const inc of increments) {
|
|
67
|
+
await this.reconcileIncrement(inc, result);
|
|
68
|
+
}
|
|
69
|
+
// 5. Report summary
|
|
70
|
+
this.logger.log('\n━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━');
|
|
71
|
+
this.logger.log('📊 ADO RECONCILIATION SUMMARY');
|
|
72
|
+
this.logger.log('━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━');
|
|
73
|
+
this.logger.log(` Increments scanned: ${result.scanned}`);
|
|
74
|
+
this.logger.log(` Mismatches found: ${result.mismatches}`);
|
|
75
|
+
this.logger.log(` Work items closed: ${result.closed}`);
|
|
76
|
+
this.logger.log(` Work items reopened: ${result.reopened}`);
|
|
77
|
+
this.logger.log(` Errors: ${result.errors.length}`);
|
|
78
|
+
if (this.dryRun) {
|
|
79
|
+
this.logger.log('\n ⚠️ DRY RUN - No changes were made');
|
|
80
|
+
}
|
|
81
|
+
this.logger.log('━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n');
|
|
82
|
+
return result;
|
|
83
|
+
}
|
|
84
|
+
catch (error) {
|
|
85
|
+
result.errors.push(`Reconciliation error: ${error.message}`);
|
|
86
|
+
this.logger.error('❌ Reconciliation failed:', error.message);
|
|
87
|
+
return result;
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
/**
|
|
91
|
+
* Reconcile a single increment
|
|
92
|
+
*/
|
|
93
|
+
async reconcileIncrement(inc, result) {
|
|
94
|
+
const status = inc.metadataStatus;
|
|
95
|
+
// Determine expected ADO state
|
|
96
|
+
const shouldBeClosed = status === 'completed' || status === 'abandoned';
|
|
97
|
+
const shouldBeActive = status === 'in-progress' || status === 'active' || status === 'planning';
|
|
98
|
+
// Check main work item
|
|
99
|
+
if (inc.workItem) {
|
|
100
|
+
await this.reconcileWorkItem(inc.incrementId, inc.workItem.id, shouldBeClosed, shouldBeActive, status, result);
|
|
101
|
+
}
|
|
102
|
+
// Check User Story work items
|
|
103
|
+
for (const us of inc.userStoryWorkItems) {
|
|
104
|
+
await this.reconcileWorkItem(`${inc.incrementId}/${us.userStoryId}`, us.workItemId, shouldBeClosed, shouldBeActive, status, result);
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
/**
|
|
108
|
+
* Reconcile a single work item
|
|
109
|
+
*/
|
|
110
|
+
async reconcileWorkItem(context, workItemId, shouldBeClosed, shouldBeActive, metadataStatus, result) {
|
|
111
|
+
try {
|
|
112
|
+
// Get current ADO state
|
|
113
|
+
const workItem = await this.getWorkItem(workItemId);
|
|
114
|
+
const currentState = workItem?.fields?.['System.State'] ?? 'Unknown';
|
|
115
|
+
const isCurrentlyClosed = ADO_STATUSES.CLOSED.includes(currentState);
|
|
116
|
+
// Check for mismatch
|
|
117
|
+
if (shouldBeClosed && !isCurrentlyClosed) {
|
|
118
|
+
// Should be closed but is active
|
|
119
|
+
result.mismatches++;
|
|
120
|
+
this.logger.log(` ❌ Work Item #${workItemId} (${context}): ${currentState} but should be CLOSED (status=${metadataStatus})`);
|
|
121
|
+
if (!this.dryRun) {
|
|
122
|
+
const comment = `## 🔄 Auto-Reconciled by SpecWeave
|
|
123
|
+
|
|
124
|
+
This work item was closed by SpecWeave reconciliation.
|
|
125
|
+
|
|
126
|
+
**Reason**: Increment status is \`${metadataStatus}\` but ADO work item was still active.
|
|
127
|
+
|
|
128
|
+
---
|
|
129
|
+
🤖 Auto-reconciled by SpecWeave`;
|
|
130
|
+
await this.updateWorkItemState(workItemId, 'Closed', comment);
|
|
131
|
+
result.closed++;
|
|
132
|
+
this.logger.log(` ✅ Closed work item #${workItemId}`);
|
|
133
|
+
}
|
|
134
|
+
else {
|
|
135
|
+
this.logger.log(` [DRY RUN] Would close work item #${workItemId}`);
|
|
136
|
+
}
|
|
137
|
+
result.details.push({
|
|
138
|
+
incrementId: context,
|
|
139
|
+
action: this.dryRun ? 'skip' : 'close',
|
|
140
|
+
workItemId,
|
|
141
|
+
reason: `Status=${metadataStatus}, ADO=${currentState}`,
|
|
142
|
+
});
|
|
143
|
+
}
|
|
144
|
+
else if (shouldBeActive && isCurrentlyClosed) {
|
|
145
|
+
// Should be active but is closed
|
|
146
|
+
result.mismatches++;
|
|
147
|
+
this.logger.log(` ❌ Work Item #${workItemId} (${context}): CLOSED but should be ACTIVE (status=${metadataStatus})`);
|
|
148
|
+
if (!this.dryRun) {
|
|
149
|
+
const comment = `## 🔄 Auto-Reconciled by SpecWeave
|
|
150
|
+
|
|
151
|
+
This work item was reactivated by SpecWeave reconciliation.
|
|
152
|
+
|
|
153
|
+
**Reason**: Increment status is \`${metadataStatus}\` but ADO work item was closed.
|
|
154
|
+
This typically happens when an increment was resumed after being paused/completed.
|
|
155
|
+
|
|
156
|
+
---
|
|
157
|
+
🤖 Auto-reconciled by SpecWeave`;
|
|
158
|
+
await this.updateWorkItemState(workItemId, 'Active', comment);
|
|
159
|
+
result.reopened++;
|
|
160
|
+
this.logger.log(` ✅ Reactivated work item #${workItemId}`);
|
|
161
|
+
}
|
|
162
|
+
else {
|
|
163
|
+
this.logger.log(` [DRY RUN] Would reactivate work item #${workItemId}`);
|
|
164
|
+
}
|
|
165
|
+
result.details.push({
|
|
166
|
+
incrementId: context,
|
|
167
|
+
action: this.dryRun ? 'skip' : 'reopen',
|
|
168
|
+
workItemId,
|
|
169
|
+
reason: `Status=${metadataStatus}, ADO=${currentState}`,
|
|
170
|
+
});
|
|
171
|
+
}
|
|
172
|
+
else {
|
|
173
|
+
// State matches
|
|
174
|
+
this.logger.log(` ✅ Work Item #${workItemId} (${context}): State matches (${currentState})`);
|
|
175
|
+
result.details.push({
|
|
176
|
+
incrementId: context,
|
|
177
|
+
action: 'skip',
|
|
178
|
+
workItemId,
|
|
179
|
+
reason: 'State matches',
|
|
180
|
+
});
|
|
181
|
+
}
|
|
182
|
+
}
|
|
183
|
+
catch (error) {
|
|
184
|
+
result.errors.push(`Work item #${workItemId}: ${error.message}`);
|
|
185
|
+
result.details.push({
|
|
186
|
+
incrementId: context,
|
|
187
|
+
action: 'error',
|
|
188
|
+
workItemId,
|
|
189
|
+
reason: error.message,
|
|
190
|
+
});
|
|
191
|
+
}
|
|
192
|
+
}
|
|
193
|
+
/**
|
|
194
|
+
* Scan increments directory for non-archived increments
|
|
195
|
+
*/
|
|
196
|
+
async scanIncrements() {
|
|
197
|
+
const incrementsPath = path.join(this.projectRoot, '.specweave', 'increments');
|
|
198
|
+
const results = [];
|
|
199
|
+
if (!existsSync(incrementsPath)) {
|
|
200
|
+
return results;
|
|
201
|
+
}
|
|
202
|
+
const entries = await fs.readdir(incrementsPath, { withFileTypes: true });
|
|
203
|
+
for (const entry of entries) {
|
|
204
|
+
if (!entry.isDirectory())
|
|
205
|
+
continue;
|
|
206
|
+
if (entry.name === '_archive' || entry.name.startsWith('.'))
|
|
207
|
+
continue;
|
|
208
|
+
const incrementPath = path.join(incrementsPath, entry.name);
|
|
209
|
+
const metadataPath = path.join(incrementPath, 'metadata.json');
|
|
210
|
+
if (!existsSync(metadataPath))
|
|
211
|
+
continue;
|
|
212
|
+
try {
|
|
213
|
+
const metadataContent = await fs.readFile(metadataPath, 'utf-8');
|
|
214
|
+
const metadata = JSON.parse(metadataContent);
|
|
215
|
+
// Check for ADO work item link
|
|
216
|
+
const adoSync = metadata.external_sync?.ado;
|
|
217
|
+
if (!adoSync?.workItemId)
|
|
218
|
+
continue;
|
|
219
|
+
const state = {
|
|
220
|
+
incrementId: entry.name,
|
|
221
|
+
incrementPath,
|
|
222
|
+
metadataStatus: metadata.status || 'unknown',
|
|
223
|
+
featureId: metadata.featureId,
|
|
224
|
+
workItem: {
|
|
225
|
+
id: adoSync.workItemId,
|
|
226
|
+
url: adoSync.workItemUrl,
|
|
227
|
+
},
|
|
228
|
+
userStoryWorkItems: [],
|
|
229
|
+
};
|
|
230
|
+
// Extract user story work items if present
|
|
231
|
+
if (adoSync.userStories && Array.isArray(adoSync.userStories)) {
|
|
232
|
+
for (const us of adoSync.userStories) {
|
|
233
|
+
if (us.workItemId) {
|
|
234
|
+
state.userStoryWorkItems.push({
|
|
235
|
+
userStoryId: us.id || us.userStoryId,
|
|
236
|
+
workItemId: us.workItemId,
|
|
237
|
+
});
|
|
238
|
+
}
|
|
239
|
+
}
|
|
240
|
+
}
|
|
241
|
+
results.push(state);
|
|
242
|
+
}
|
|
243
|
+
catch {
|
|
244
|
+
// Skip invalid metadata
|
|
245
|
+
}
|
|
246
|
+
}
|
|
247
|
+
return results;
|
|
248
|
+
}
|
|
249
|
+
/**
|
|
250
|
+
* Load config.json
|
|
251
|
+
*/
|
|
252
|
+
async loadConfig() {
|
|
253
|
+
const configPath = path.join(this.projectRoot, '.specweave', 'config.json');
|
|
254
|
+
try {
|
|
255
|
+
const content = await fs.readFile(configPath, 'utf-8');
|
|
256
|
+
return JSON.parse(content);
|
|
257
|
+
}
|
|
258
|
+
catch {
|
|
259
|
+
return {};
|
|
260
|
+
}
|
|
261
|
+
}
|
|
262
|
+
/**
|
|
263
|
+
* Check if ADO credentials are configured
|
|
264
|
+
*/
|
|
265
|
+
hasAdoCredentials() {
|
|
266
|
+
return !!(process.env.AZURE_DEVOPS_PAT || process.env.AZURE_DEVOPS_TOKEN);
|
|
267
|
+
}
|
|
268
|
+
/**
|
|
269
|
+
* Get work item from ADO API
|
|
270
|
+
*/
|
|
271
|
+
async getWorkItem(workItemId) {
|
|
272
|
+
const org = process.env.AZURE_DEVOPS_ORG;
|
|
273
|
+
const pat = process.env.AZURE_DEVOPS_PAT || process.env.AZURE_DEVOPS_TOKEN;
|
|
274
|
+
if (!org || !pat) {
|
|
275
|
+
throw new Error('ADO credentials not configured');
|
|
276
|
+
}
|
|
277
|
+
const url = `https://dev.azure.com/${org}/_apis/wit/workitems/${workItemId}?api-version=7.1`;
|
|
278
|
+
const auth = Buffer.from(`:${pat}`).toString('base64');
|
|
279
|
+
const response = await fetch(url, {
|
|
280
|
+
headers: {
|
|
281
|
+
Authorization: `Basic ${auth}`,
|
|
282
|
+
'Content-Type': 'application/json',
|
|
283
|
+
},
|
|
284
|
+
});
|
|
285
|
+
if (!response.ok) {
|
|
286
|
+
throw new Error(`Failed to get work item: ${response.status}`);
|
|
287
|
+
}
|
|
288
|
+
return response.json();
|
|
289
|
+
}
|
|
290
|
+
/**
|
|
291
|
+
* Update work item state in ADO
|
|
292
|
+
*/
|
|
293
|
+
async updateWorkItemState(workItemId, newState, comment) {
|
|
294
|
+
const org = process.env.AZURE_DEVOPS_ORG;
|
|
295
|
+
const pat = process.env.AZURE_DEVOPS_PAT || process.env.AZURE_DEVOPS_TOKEN;
|
|
296
|
+
if (!org || !pat) {
|
|
297
|
+
throw new Error('ADO credentials not configured');
|
|
298
|
+
}
|
|
299
|
+
const url = `https://dev.azure.com/${org}/_apis/wit/workitems/${workItemId}?api-version=7.1`;
|
|
300
|
+
const auth = Buffer.from(`:${pat}`).toString('base64');
|
|
301
|
+
const operations = [
|
|
302
|
+
{
|
|
303
|
+
op: 'add',
|
|
304
|
+
path: '/fields/System.State',
|
|
305
|
+
value: newState,
|
|
306
|
+
},
|
|
307
|
+
{
|
|
308
|
+
op: 'add',
|
|
309
|
+
path: '/fields/System.History',
|
|
310
|
+
value: comment,
|
|
311
|
+
},
|
|
312
|
+
];
|
|
313
|
+
const response = await fetch(url, {
|
|
314
|
+
method: 'PATCH',
|
|
315
|
+
headers: {
|
|
316
|
+
Authorization: `Basic ${auth}`,
|
|
317
|
+
'Content-Type': 'application/json-patch+json',
|
|
318
|
+
},
|
|
319
|
+
body: JSON.stringify(operations),
|
|
320
|
+
});
|
|
321
|
+
if (!response.ok) {
|
|
322
|
+
const error = await response.text();
|
|
323
|
+
throw new Error(`Failed to update work item: ${response.status} - ${error}`);
|
|
324
|
+
}
|
|
325
|
+
}
|
|
326
|
+
}
|
|
327
|
+
/**
|
|
328
|
+
* Convenience function for quick reconciliation
|
|
329
|
+
*/
|
|
330
|
+
export async function reconcileAdo(projectRoot = process.cwd(), dryRun = false) {
|
|
331
|
+
const reconciler = new AdoReconciler({ projectRoot, dryRun });
|
|
332
|
+
return reconciler.reconcile();
|
|
333
|
+
}
|
|
334
|
+
export default AdoReconciler;
|
|
335
|
+
//# sourceMappingURL=ado-reconciler.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ado-reconciler.js","sourceRoot":"","sources":["../../../src/sync/ado-reconciler.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,106 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* JIRA Reconciler (NEW in v0.33.0)
|
|
3
|
+
*
|
|
4
|
+
* Reconciles JIRA issue states with increment metadata.json statuses.
|
|
5
|
+
* Fixes drift between local SpecWeave state and JIRA:
|
|
6
|
+
* - Closes issues for completed increments that are still open
|
|
7
|
+
* - Reopens issues for in-progress increments that are closed
|
|
8
|
+
*
|
|
9
|
+
* Mirrors the GitHub reconciler pattern for consistency.
|
|
10
|
+
*
|
|
11
|
+
* Triggered by:
|
|
12
|
+
* - /specweave-jira:reconcile command (manual)
|
|
13
|
+
* - SessionStart hook (automatic, if configured)
|
|
14
|
+
* - post-increment-status-change.sh (on resume/abandon)
|
|
15
|
+
*/
|
|
16
|
+
import { Logger } from '../utils/logger.js';
|
|
17
|
+
export interface JiraReconcileOptions {
|
|
18
|
+
projectRoot: string;
|
|
19
|
+
dryRun?: boolean;
|
|
20
|
+
logger?: Logger;
|
|
21
|
+
}
|
|
22
|
+
export interface IncrementJiraState {
|
|
23
|
+
incrementId: string;
|
|
24
|
+
incrementPath: string;
|
|
25
|
+
metadataStatus: string;
|
|
26
|
+
featureId?: string;
|
|
27
|
+
issue?: {
|
|
28
|
+
key: string;
|
|
29
|
+
url?: string;
|
|
30
|
+
};
|
|
31
|
+
userStoryIssues: Array<{
|
|
32
|
+
userStoryId: string;
|
|
33
|
+
issueKey: string;
|
|
34
|
+
}>;
|
|
35
|
+
}
|
|
36
|
+
export interface JiraReconcileResult {
|
|
37
|
+
scanned: number;
|
|
38
|
+
mismatches: number;
|
|
39
|
+
closed: number;
|
|
40
|
+
reopened: number;
|
|
41
|
+
errors: string[];
|
|
42
|
+
details: Array<{
|
|
43
|
+
incrementId: string;
|
|
44
|
+
action: 'close' | 'reopen' | 'skip' | 'error';
|
|
45
|
+
issueKey: string;
|
|
46
|
+
reason: string;
|
|
47
|
+
}>;
|
|
48
|
+
}
|
|
49
|
+
export declare class JiraReconciler {
|
|
50
|
+
private projectRoot;
|
|
51
|
+
private dryRun;
|
|
52
|
+
private logger;
|
|
53
|
+
private domain;
|
|
54
|
+
private auth;
|
|
55
|
+
constructor(options: JiraReconcileOptions);
|
|
56
|
+
/**
|
|
57
|
+
* Main reconciliation entry point
|
|
58
|
+
*/
|
|
59
|
+
reconcile(): Promise<JiraReconcileResult>;
|
|
60
|
+
/**
|
|
61
|
+
* Reconcile a single increment
|
|
62
|
+
*/
|
|
63
|
+
private reconcileIncrement;
|
|
64
|
+
/**
|
|
65
|
+
* Reconcile a single issue
|
|
66
|
+
*/
|
|
67
|
+
private reconcileIssue;
|
|
68
|
+
/**
|
|
69
|
+
* Scan increments directory for non-archived increments
|
|
70
|
+
*/
|
|
71
|
+
private scanIncrements;
|
|
72
|
+
/**
|
|
73
|
+
* Load config.json
|
|
74
|
+
*/
|
|
75
|
+
private loadConfig;
|
|
76
|
+
/**
|
|
77
|
+
* Initialize JIRA credentials
|
|
78
|
+
*/
|
|
79
|
+
private initCredentials;
|
|
80
|
+
/**
|
|
81
|
+
* Get issue from JIRA API
|
|
82
|
+
*/
|
|
83
|
+
private getIssue;
|
|
84
|
+
/**
|
|
85
|
+
* Get available transitions for an issue
|
|
86
|
+
*/
|
|
87
|
+
private getTransitions;
|
|
88
|
+
/**
|
|
89
|
+
* Transition issue to new status and add comment
|
|
90
|
+
*/
|
|
91
|
+
private transitionIssue;
|
|
92
|
+
/**
|
|
93
|
+
* Execute transition
|
|
94
|
+
*/
|
|
95
|
+
private doTransition;
|
|
96
|
+
/**
|
|
97
|
+
* Add comment to issue
|
|
98
|
+
*/
|
|
99
|
+
private addComment;
|
|
100
|
+
}
|
|
101
|
+
/**
|
|
102
|
+
* Convenience function for quick reconciliation
|
|
103
|
+
*/
|
|
104
|
+
export declare function reconcileJira(projectRoot?: string, dryRun?: boolean): Promise<JiraReconcileResult>;
|
|
105
|
+
export default JiraReconciler;
|
|
106
|
+
//# sourceMappingURL=jira-reconciler.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"jira-reconciler.d.ts","sourceRoot":"","sources":["../../../src/sync/jira-reconciler.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;GAcG;AAIH,OAAO,EAAE,MAAM,EAAiB,MAAM,oBAAoB,CAAC;AAE3D,MAAM,WAAW,oBAAoB;IACnC,WAAW,EAAE,MAAM,CAAC;IACpB,MAAM,CAAC,EAAE,OAAO,CAAC;IACjB,MAAM,CAAC,EAAE,MAAM,CAAC;CACjB;AAED,MAAM,WAAW,kBAAkB;IACjC,WAAW,EAAE,MAAM,CAAC;IACpB,aAAa,EAAE,MAAM,CAAC;IACtB,cAAc,EAAE,MAAM,CAAC;IACvB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,KAAK,CAAC,EAAE;QACN,GAAG,EAAE,MAAM,CAAC;QACZ,GAAG,CAAC,EAAE,MAAM,CAAC;KACd,CAAC;IACF,eAAe,EAAE,KAAK,CAAC;QACrB,WAAW,EAAE,MAAM,CAAC;QACpB,QAAQ,EAAE,MAAM,CAAC;KAClB,CAAC,CAAC;CACJ;AAED,MAAM,WAAW,mBAAmB;IAClC,OAAO,EAAE,MAAM,CAAC;IAChB,UAAU,EAAE,MAAM,CAAC;IACnB,MAAM,EAAE,MAAM,CAAC;IACf,QAAQ,EAAE,MAAM,CAAC;IACjB,MAAM,EAAE,MAAM,EAAE,CAAC;IACjB,OAAO,EAAE,KAAK,CAAC;QACb,WAAW,EAAE,MAAM,CAAC;QACpB,MAAM,EAAE,OAAO,GAAG,QAAQ,GAAG,MAAM,GAAG,OAAO,CAAC;QAC9C,QAAQ,EAAE,MAAM,CAAC;QACjB,MAAM,EAAE,MAAM,CAAC;KAChB,CAAC,CAAC;CACJ;AAUD,qBAAa,cAAc;IACzB,OAAO,CAAC,WAAW,CAAS;IAC5B,OAAO,CAAC,MAAM,CAAU;IACxB,OAAO,CAAC,MAAM,CAAS;IACvB,OAAO,CAAC,MAAM,CAAc;IAC5B,OAAO,CAAC,IAAI,CAAc;gBAEd,OAAO,EAAE,oBAAoB;IAMzC;;OAEG;IACG,SAAS,IAAI,OAAO,CAAC,mBAAmB,CAAC;IAqE/C;;OAEG;YACW,kBAAkB;IAmChC;;OAEG;YACW,cAAc;IA+F5B;;OAEG;YACW,cAAc;IA4D5B;;OAEG;YACW,UAAU;IAWxB;;OAEG;IACH,OAAO,CAAC,eAAe;IAavB;;OAEG;YACW,QAAQ;IAiBtB;;OAEG;YACW,cAAc;IAkB5B;;OAEG;YACW,eAAe;IAwC7B;;OAEG;YACW,YAAY;IAoB1B;;OAEG;YACW,UAAU;CAiCzB;AAED;;GAEG;AACH,wBAAsB,aAAa,CACjC,WAAW,GAAE,MAAsB,EACnC,MAAM,GAAE,OAAe,GACtB,OAAO,CAAC,mBAAmB,CAAC,CAG9B;AAED,eAAe,cAAc,CAAC"}
|