specweave 0.32.2 → 0.32.5
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 +51 -9
- 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-multiproject.js +1 -1
- package/dist/src/cli/commands/init-multiproject.js.map +1 -1
- 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/commands/migrate-to-multiproject.js +2 -2
- package/dist/src/cli/commands/migrate-to-multiproject.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/cross-project-sync.d.ts +97 -0
- package/dist/src/core/living-docs/cross-project-sync.d.ts.map +1 -0
- package/dist/src/core/living-docs/cross-project-sync.js +135 -0
- package/dist/src/core/living-docs/cross-project-sync.js.map +1 -0
- package/dist/src/core/living-docs/external-sync-orchestrator.d.ts +106 -0
- package/dist/src/core/living-docs/external-sync-orchestrator.d.ts.map +1 -0
- package/dist/src/core/living-docs/external-sync-orchestrator.js +146 -0
- package/dist/src/core/living-docs/external-sync-orchestrator.js.map +1 -0
- 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 +7 -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 +94 -10
- 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/living-docs/sync-helpers/generators.d.ts +8 -1
- package/dist/src/core/living-docs/sync-helpers/generators.d.ts.map +1 -1
- package/dist/src/core/living-docs/sync-helpers/generators.js +18 -1
- package/dist/src/core/living-docs/sync-helpers/generators.js.map +1 -1
- package/dist/src/core/living-docs/sync-helpers/index.d.ts +1 -1
- package/dist/src/core/living-docs/sync-helpers/index.d.ts.map +1 -1
- package/dist/src/core/living-docs/sync-helpers/index.js.map +1 -1
- package/dist/src/core/living-docs/sync-helpers/parsers.d.ts +3 -1
- package/dist/src/core/living-docs/sync-helpers/parsers.d.ts.map +1 -1
- package/dist/src/core/living-docs/sync-helpers/parsers.js +24 -2
- package/dist/src/core/living-docs/sync-helpers/parsers.js.map +1 -1
- package/dist/src/core/living-docs/types.d.ts +6 -0
- package/dist/src/core/living-docs/types.d.ts.map +1 -1
- package/dist/src/core/living-docs/validators/index.d.ts +7 -0
- package/dist/src/core/living-docs/validators/index.d.ts.map +1 -0
- package/dist/src/core/living-docs/validators/index.js +7 -0
- package/dist/src/core/living-docs/validators/index.js.map +1 -0
- package/dist/src/core/living-docs/validators/project-validator.d.ts +92 -0
- package/dist/src/core/living-docs/validators/project-validator.d.ts.map +1 -0
- package/dist/src/core/living-docs/validators/project-validator.js +142 -0
- package/dist/src/core/living-docs/validators/project-validator.js.map +1 -0
- 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/core/project/project-manager.d.ts.map +1 -1
- package/dist/src/core/project/project-manager.js +19 -17
- package/dist/src/core/project/project-manager.js.map +1 -1
- package/dist/src/core/types/config.d.ts +4 -2
- package/dist/src/core/types/config.d.ts.map +1 -1
- package/dist/src/core/types/config.js.map +1 -1
- package/dist/src/core/types/increment-metadata.d.ts +34 -0
- package/dist/src/core/types/increment-metadata.d.ts.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/cross-cutting-detector.d.ts +66 -0
- package/dist/src/utils/cross-cutting-detector.d.ts.map +1 -0
- package/dist/src/utils/cross-cutting-detector.js +179 -0
- package/dist/src/utils/cross-cutting-detector.js.map +1 -0
- 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/dist/src/utils/project-detection.d.ts +12 -8
- package/dist/src/utils/project-detection.d.ts.map +1 -1
- package/dist/src/utils/project-detection.js +13 -19
- package/dist/src/utils/project-detection.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-status.md +64 -0
- package/plugins/specweave/commands/specweave-validate.md +27 -1
- package/plugins/specweave/hooks/hooks.json +11 -1
- package/plugins/specweave/hooks/spec-project-validator.sh +81 -25
- package/plugins/specweave/hooks/v2/guards/increment-duplicate-guard.sh +135 -0
- package/plugins/specweave/lib/vendor/core/types/increment-metadata.d.ts +34 -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 +135 -29
- 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/skills/spec-generator/SKILL.md +78 -7
- 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
- package/plugins/specweave/commands/specweave-switch-project.md +0 -168
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"jira-token-provider.d.ts","sourceRoot":"","sources":["../../../../src/integrations/jira/jira-token-provider.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;GAiBG;AAEH;;GAEG;AACH,MAAM,WAAW,uBAAuB;IACtC,QAAQ,EAAE,MAAM,CAAC;IACjB,KAAK,EAAE,MAAM,CAAC;IACd,MAAM,EAAE,MAAM,CAAC;CAChB;AAqBD;;;;;;;;;;;;;GAaG;AACH,wBAAgB,YAAY,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,CAoBnD;AAED;;;;;;GAMG;AACH,wBAAgB,YAAY,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,CAkBnD;AAED;;;;;GAKG;AACH,wBAAgB,2BAA2B,CAAC,MAAM,EAAE,MAAM,GAAG,uBAAuB,CAMnF;AAED;;;;;GAKG;AACH,wBAAgB,kBAAkB,CAAC,MAAM,CAAC,EAAE,MAAM,GAAG,OAAO,CAS3D;AAED;;;;;;;;GAQG;AACH,wBAAgB,cAAc,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,CAErD;AAED;;;;;;;;GAQG;AACH,wBAAgB,cAAc,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,CAErD;AAED;;;;;;;GAOG;AACH,wBAAgB,qBAAqB,IAAI,MAAM,EAAE,CAchD"}
|
|
@@ -0,0 +1,160 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* JIRA Token Provider
|
|
3
|
+
*
|
|
4
|
+
* Centralized API token retrieval logic for JIRA.
|
|
5
|
+
* Supports domain-specific tokens via environment variables.
|
|
6
|
+
*
|
|
7
|
+
* Token Resolution Priority:
|
|
8
|
+
* 1. Domain-specific: JIRA_API_TOKEN_{DOMAIN} (e.g., JIRA_API_TOKEN_ACME)
|
|
9
|
+
* 2. Default: JIRA_API_TOKEN
|
|
10
|
+
*
|
|
11
|
+
* Email Resolution Priority:
|
|
12
|
+
* 1. Domain-specific: JIRA_EMAIL_{DOMAIN} (e.g., JIRA_EMAIL_ACME)
|
|
13
|
+
* 2. Default: JIRA_EMAIL
|
|
14
|
+
*
|
|
15
|
+
* This mirrors the ADO PAT provider pattern for consistency.
|
|
16
|
+
*
|
|
17
|
+
* @module integrations/jira/jira-token-provider
|
|
18
|
+
*/
|
|
19
|
+
/**
|
|
20
|
+
* Normalize domain to environment variable suffix
|
|
21
|
+
*
|
|
22
|
+
* @example
|
|
23
|
+
* normalizeDomainToEnvKey('company.atlassian.net') // 'COMPANY'
|
|
24
|
+
* normalizeDomainToEnvKey('acme-corp.atlassian.net') // 'ACME_CORP'
|
|
25
|
+
* normalizeDomainToEnvKey('https://jira.example.com') // 'JIRA_EXAMPLE_COM'
|
|
26
|
+
*/
|
|
27
|
+
function normalizeDomainToEnvKey(domain) {
|
|
28
|
+
// Remove protocol if present
|
|
29
|
+
let normalized = domain.replace(/^https?:\/\//, '');
|
|
30
|
+
// Remove .atlassian.net suffix for cleaner keys
|
|
31
|
+
normalized = normalized.replace(/\.atlassian\.net$/, '');
|
|
32
|
+
// Convert to uppercase and replace non-alphanumeric with underscore
|
|
33
|
+
return normalized.toUpperCase().replace(/[^A-Z0-9]/g, '_');
|
|
34
|
+
}
|
|
35
|
+
/**
|
|
36
|
+
* Get API token for a specific JIRA domain
|
|
37
|
+
*
|
|
38
|
+
* Supports domain-specific tokens via JIRA_API_TOKEN_{DOMAIN} env vars.
|
|
39
|
+
* This allows different JIRA instances to use different credentials.
|
|
40
|
+
*
|
|
41
|
+
* @param domain - The JIRA domain (e.g., company.atlassian.net)
|
|
42
|
+
* @returns The API token string
|
|
43
|
+
* @throws Error if no token is configured
|
|
44
|
+
*
|
|
45
|
+
* @example
|
|
46
|
+
* // Uses JIRA_API_TOKEN_ACME if set, otherwise JIRA_API_TOKEN
|
|
47
|
+
* const token = getJiraToken('acme.atlassian.net');
|
|
48
|
+
*/
|
|
49
|
+
export function getJiraToken(domain) {
|
|
50
|
+
// SECURITY: Never log the token value itself
|
|
51
|
+
// Try domain-specific token first (e.g., JIRA_API_TOKEN_ACME)
|
|
52
|
+
const domainEnvKey = `JIRA_API_TOKEN_${normalizeDomainToEnvKey(domain)}`;
|
|
53
|
+
const domainToken = process.env[domainEnvKey];
|
|
54
|
+
if (domainToken) {
|
|
55
|
+
return domainToken;
|
|
56
|
+
}
|
|
57
|
+
// Fall back to default token
|
|
58
|
+
const defaultToken = process.env.JIRA_API_TOKEN;
|
|
59
|
+
if (!defaultToken) {
|
|
60
|
+
throw new Error(`JIRA API token not found. Set JIRA_API_TOKEN in .env file ` +
|
|
61
|
+
`or ${domainEnvKey} for domain-specific token.`);
|
|
62
|
+
}
|
|
63
|
+
return defaultToken;
|
|
64
|
+
}
|
|
65
|
+
/**
|
|
66
|
+
* Get email for a specific JIRA domain
|
|
67
|
+
*
|
|
68
|
+
* @param domain - The JIRA domain
|
|
69
|
+
* @returns The email string
|
|
70
|
+
* @throws Error if no email is configured
|
|
71
|
+
*/
|
|
72
|
+
export function getJiraEmail(domain) {
|
|
73
|
+
// Try domain-specific email first
|
|
74
|
+
const domainEnvKey = `JIRA_EMAIL_${normalizeDomainToEnvKey(domain)}`;
|
|
75
|
+
const domainEmail = process.env[domainEnvKey];
|
|
76
|
+
if (domainEmail) {
|
|
77
|
+
return domainEmail;
|
|
78
|
+
}
|
|
79
|
+
// Fall back to default email
|
|
80
|
+
const defaultEmail = process.env.JIRA_EMAIL;
|
|
81
|
+
if (!defaultEmail) {
|
|
82
|
+
throw new Error(`JIRA email not found. Set JIRA_EMAIL in .env file ` +
|
|
83
|
+
`or ${domainEnvKey} for domain-specific email.`);
|
|
84
|
+
}
|
|
85
|
+
return defaultEmail;
|
|
86
|
+
}
|
|
87
|
+
/**
|
|
88
|
+
* Get full credentials for a JIRA domain
|
|
89
|
+
*
|
|
90
|
+
* @param domain - The JIRA domain
|
|
91
|
+
* @returns Complete credentials object
|
|
92
|
+
*/
|
|
93
|
+
export function getJiraCredentialsForDomain(domain) {
|
|
94
|
+
return {
|
|
95
|
+
apiToken: getJiraToken(domain),
|
|
96
|
+
email: getJiraEmail(domain),
|
|
97
|
+
domain,
|
|
98
|
+
};
|
|
99
|
+
}
|
|
100
|
+
/**
|
|
101
|
+
* Check if credentials are available for a domain
|
|
102
|
+
*
|
|
103
|
+
* @param domain - The JIRA domain (optional, checks default if not provided)
|
|
104
|
+
* @returns true if credentials are available (domain-specific or default)
|
|
105
|
+
*/
|
|
106
|
+
export function hasJiraCredentials(domain) {
|
|
107
|
+
if (domain) {
|
|
108
|
+
const domainEnvKey = `JIRA_API_TOKEN_${normalizeDomainToEnvKey(domain)}`;
|
|
109
|
+
if (process.env[domainEnvKey]) {
|
|
110
|
+
return true;
|
|
111
|
+
}
|
|
112
|
+
}
|
|
113
|
+
return !!process.env.JIRA_API_TOKEN;
|
|
114
|
+
}
|
|
115
|
+
/**
|
|
116
|
+
* Get the environment variable key for a domain's token
|
|
117
|
+
*
|
|
118
|
+
* @param domain - The JIRA domain
|
|
119
|
+
* @returns The environment variable key
|
|
120
|
+
*
|
|
121
|
+
* @example
|
|
122
|
+
* getTokenEnvKey('acme.atlassian.net') // returns 'JIRA_API_TOKEN_ACME'
|
|
123
|
+
*/
|
|
124
|
+
export function getTokenEnvKey(domain) {
|
|
125
|
+
return `JIRA_API_TOKEN_${normalizeDomainToEnvKey(domain)}`;
|
|
126
|
+
}
|
|
127
|
+
/**
|
|
128
|
+
* Get the environment variable key for a domain's email
|
|
129
|
+
*
|
|
130
|
+
* @param domain - The JIRA domain
|
|
131
|
+
* @returns The environment variable key
|
|
132
|
+
*
|
|
133
|
+
* @example
|
|
134
|
+
* getEmailEnvKey('acme.atlassian.net') // returns 'JIRA_EMAIL_ACME'
|
|
135
|
+
*/
|
|
136
|
+
export function getEmailEnvKey(domain) {
|
|
137
|
+
return `JIRA_EMAIL_${normalizeDomainToEnvKey(domain)}`;
|
|
138
|
+
}
|
|
139
|
+
/**
|
|
140
|
+
* List all configured JIRA domains from environment
|
|
141
|
+
*
|
|
142
|
+
* Scans environment variables for JIRA_API_TOKEN_* patterns
|
|
143
|
+
* and returns the list of configured domains.
|
|
144
|
+
*
|
|
145
|
+
* @returns Array of domain suffixes (e.g., ['ACME', 'CORP'])
|
|
146
|
+
*/
|
|
147
|
+
export function listConfiguredDomains() {
|
|
148
|
+
const domains = [];
|
|
149
|
+
const prefix = 'JIRA_API_TOKEN_';
|
|
150
|
+
for (const key of Object.keys(process.env)) {
|
|
151
|
+
if (key.startsWith(prefix) && key !== 'JIRA_API_TOKEN') {
|
|
152
|
+
const domainSuffix = key.substring(prefix.length);
|
|
153
|
+
if (domainSuffix) {
|
|
154
|
+
domains.push(domainSuffix);
|
|
155
|
+
}
|
|
156
|
+
}
|
|
157
|
+
}
|
|
158
|
+
return domains;
|
|
159
|
+
}
|
|
160
|
+
//# sourceMappingURL=jira-token-provider.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"jira-token-provider.js","sourceRoot":"","sources":["../../../../src/integrations/jira/jira-token-provider.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,92 @@
|
|
|
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 { Logger } from '../utils/logger.js';
|
|
17
|
+
export interface AdoReconcileOptions {
|
|
18
|
+
projectRoot: string;
|
|
19
|
+
dryRun?: boolean;
|
|
20
|
+
logger?: Logger;
|
|
21
|
+
}
|
|
22
|
+
export interface IncrementAdoState {
|
|
23
|
+
incrementId: string;
|
|
24
|
+
incrementPath: string;
|
|
25
|
+
metadataStatus: string;
|
|
26
|
+
featureId?: string;
|
|
27
|
+
workItem?: {
|
|
28
|
+
id: number;
|
|
29
|
+
url?: string;
|
|
30
|
+
};
|
|
31
|
+
userStoryWorkItems: Array<{
|
|
32
|
+
userStoryId: string;
|
|
33
|
+
workItemId: number;
|
|
34
|
+
}>;
|
|
35
|
+
}
|
|
36
|
+
export interface AdoReconcileResult {
|
|
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
|
+
workItemId: number;
|
|
46
|
+
reason: string;
|
|
47
|
+
}>;
|
|
48
|
+
}
|
|
49
|
+
export declare class AdoReconciler {
|
|
50
|
+
private projectRoot;
|
|
51
|
+
private dryRun;
|
|
52
|
+
private logger;
|
|
53
|
+
constructor(options: AdoReconcileOptions);
|
|
54
|
+
/**
|
|
55
|
+
* Main reconciliation entry point
|
|
56
|
+
*/
|
|
57
|
+
reconcile(): Promise<AdoReconcileResult>;
|
|
58
|
+
/**
|
|
59
|
+
* Reconcile a single increment
|
|
60
|
+
*/
|
|
61
|
+
private reconcileIncrement;
|
|
62
|
+
/**
|
|
63
|
+
* Reconcile a single work item
|
|
64
|
+
*/
|
|
65
|
+
private reconcileWorkItem;
|
|
66
|
+
/**
|
|
67
|
+
* Scan increments directory for non-archived increments
|
|
68
|
+
*/
|
|
69
|
+
private scanIncrements;
|
|
70
|
+
/**
|
|
71
|
+
* Load config.json
|
|
72
|
+
*/
|
|
73
|
+
private loadConfig;
|
|
74
|
+
/**
|
|
75
|
+
* Check if ADO credentials are configured
|
|
76
|
+
*/
|
|
77
|
+
private hasAdoCredentials;
|
|
78
|
+
/**
|
|
79
|
+
* Get work item from ADO API
|
|
80
|
+
*/
|
|
81
|
+
private getWorkItem;
|
|
82
|
+
/**
|
|
83
|
+
* Update work item state in ADO
|
|
84
|
+
*/
|
|
85
|
+
private updateWorkItemState;
|
|
86
|
+
}
|
|
87
|
+
/**
|
|
88
|
+
* Convenience function for quick reconciliation
|
|
89
|
+
*/
|
|
90
|
+
export declare function reconcileAdo(projectRoot?: string, dryRun?: boolean): Promise<AdoReconcileResult>;
|
|
91
|
+
export default AdoReconciler;
|
|
92
|
+
//# sourceMappingURL=ado-reconciler.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ado-reconciler.d.ts","sourceRoot":"","sources":["../../../src/sync/ado-reconciler.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;GAcG;AAIH,OAAO,EAAE,MAAM,EAAiB,MAAM,oBAAoB,CAAC;AAE3D,MAAM,WAAW,mBAAmB;IAClC,WAAW,EAAE,MAAM,CAAC;IACpB,MAAM,CAAC,EAAE,OAAO,CAAC;IACjB,MAAM,CAAC,EAAE,MAAM,CAAC;CACjB;AAED,MAAM,WAAW,iBAAiB;IAChC,WAAW,EAAE,MAAM,CAAC;IACpB,aAAa,EAAE,MAAM,CAAC;IACtB,cAAc,EAAE,MAAM,CAAC;IACvB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,QAAQ,CAAC,EAAE;QACT,EAAE,EAAE,MAAM,CAAC;QACX,GAAG,CAAC,EAAE,MAAM,CAAC;KACd,CAAC;IACF,kBAAkB,EAAE,KAAK,CAAC;QACxB,WAAW,EAAE,MAAM,CAAC;QACpB,UAAU,EAAE,MAAM,CAAC;KACpB,CAAC,CAAC;CACJ;AAED,MAAM,WAAW,kBAAkB;IACjC,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,UAAU,EAAE,MAAM,CAAC;QACnB,MAAM,EAAE,MAAM,CAAC;KAChB,CAAC,CAAC;CACJ;AAUD,qBAAa,aAAa;IACxB,OAAO,CAAC,WAAW,CAAS;IAC5B,OAAO,CAAC,MAAM,CAAU;IACxB,OAAO,CAAC,MAAM,CAAS;gBAEX,OAAO,EAAE,mBAAmB;IAMxC;;OAEG;IACG,SAAS,IAAI,OAAO,CAAC,kBAAkB,CAAC;IA+D9C;;OAEG;YACW,kBAAkB;IAmChC;;OAEG;YACW,iBAAiB;IA+F/B;;OAEG;YACW,cAAc;IA4D5B;;OAEG;YACW,UAAU;IAWxB;;OAEG;IACH,OAAO,CAAC,iBAAiB;IAIzB;;OAEG;YACW,WAAW;IAyBzB;;OAEG;YACW,mBAAmB;CA0ClC;AAED;;GAEG;AACH,wBAAsB,YAAY,CAChC,WAAW,GAAE,MAAsB,EACnC,MAAM,GAAE,OAAe,GACtB,OAAO,CAAC,kBAAkB,CAAC,CAG7B;AAED,eAAe,aAAa,CAAC"}
|
|
@@ -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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"}
|