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,427 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* JIRA Profile Resolver
|
|
3
|
+
*
|
|
4
|
+
* Resolves the correct JIRA profile to use for sync operations.
|
|
5
|
+
* Priority:
|
|
6
|
+
* 1. Increment's stored profile (metadata.json -> external_sync.jira.profile)
|
|
7
|
+
* 2. Global defaultProfile (config.json -> sync.defaultProfile)
|
|
8
|
+
* 3. Legacy: Global activeProfile (config.json -> sync.activeProfile)
|
|
9
|
+
*
|
|
10
|
+
* This allows each increment to sync to its designated JIRA project
|
|
11
|
+
* without requiring manual profile switching.
|
|
12
|
+
*
|
|
13
|
+
* NOTE (v0.31.0): Renamed from "activeProfile" to "defaultProfile" for clarity.
|
|
14
|
+
* The default profile is a FALLBACK, not a constraint. Bulk operations
|
|
15
|
+
* iterate ALL profiles.
|
|
16
|
+
*
|
|
17
|
+
* Usage:
|
|
18
|
+
* ```typescript
|
|
19
|
+
* const resolver = await createJiraProfileResolver();
|
|
20
|
+
* const profile = await resolver.resolveProfile('0093-my-increment');
|
|
21
|
+
* // profile contains domain, projectKey, etc.
|
|
22
|
+
* ```
|
|
23
|
+
*
|
|
24
|
+
* @module jira-profile-resolver
|
|
25
|
+
*/
|
|
26
|
+
|
|
27
|
+
import { promises as fs } from 'node:fs';
|
|
28
|
+
import * as path from 'node:path';
|
|
29
|
+
|
|
30
|
+
/**
|
|
31
|
+
* JIRA profile configuration
|
|
32
|
+
*/
|
|
33
|
+
export interface JiraProfileConfig {
|
|
34
|
+
/**
|
|
35
|
+
* Profile name (for display/logging)
|
|
36
|
+
*/
|
|
37
|
+
profileName: string;
|
|
38
|
+
|
|
39
|
+
/**
|
|
40
|
+
* JIRA domain (e.g., company.atlassian.net)
|
|
41
|
+
*/
|
|
42
|
+
domain: string;
|
|
43
|
+
|
|
44
|
+
/**
|
|
45
|
+
* JIRA project key (e.g., PROJ)
|
|
46
|
+
*/
|
|
47
|
+
projectKey: string;
|
|
48
|
+
|
|
49
|
+
/**
|
|
50
|
+
* Display name (optional)
|
|
51
|
+
*/
|
|
52
|
+
displayName?: string;
|
|
53
|
+
|
|
54
|
+
/**
|
|
55
|
+
* Board ID (optional, for 2-level structure)
|
|
56
|
+
*/
|
|
57
|
+
boardId?: number;
|
|
58
|
+
|
|
59
|
+
/**
|
|
60
|
+
* Board name (optional)
|
|
61
|
+
*/
|
|
62
|
+
boardName?: string;
|
|
63
|
+
|
|
64
|
+
/**
|
|
65
|
+
* Instance type: cloud or server
|
|
66
|
+
*/
|
|
67
|
+
instanceType?: 'cloud' | 'server';
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
/**
|
|
71
|
+
* Profile resolution result
|
|
72
|
+
*/
|
|
73
|
+
export interface ProfileResolutionResult {
|
|
74
|
+
/**
|
|
75
|
+
* Whether resolution succeeded
|
|
76
|
+
*/
|
|
77
|
+
success: boolean;
|
|
78
|
+
|
|
79
|
+
/**
|
|
80
|
+
* Resolved profile config (if success)
|
|
81
|
+
*/
|
|
82
|
+
profile?: JiraProfileConfig;
|
|
83
|
+
|
|
84
|
+
/**
|
|
85
|
+
* Source of the profile
|
|
86
|
+
*/
|
|
87
|
+
source?: 'increment' | 'global';
|
|
88
|
+
|
|
89
|
+
/**
|
|
90
|
+
* Error message (if failed)
|
|
91
|
+
*/
|
|
92
|
+
error?: string;
|
|
93
|
+
|
|
94
|
+
/**
|
|
95
|
+
* Increment ID that was checked
|
|
96
|
+
*/
|
|
97
|
+
incrementId?: string;
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
/**
|
|
101
|
+
* Sync profile from config.json
|
|
102
|
+
*/
|
|
103
|
+
interface ConfigProfile {
|
|
104
|
+
provider: string;
|
|
105
|
+
displayName?: string;
|
|
106
|
+
config: {
|
|
107
|
+
domain: string;
|
|
108
|
+
projectKey: string;
|
|
109
|
+
boardId?: number;
|
|
110
|
+
boardName?: string;
|
|
111
|
+
instanceType?: 'cloud' | 'server';
|
|
112
|
+
};
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
/**
|
|
116
|
+
* Sync config from config.json
|
|
117
|
+
*/
|
|
118
|
+
interface SyncConfig {
|
|
119
|
+
/** @since v0.31.0 - preferred */
|
|
120
|
+
defaultProfile?: string;
|
|
121
|
+
/** @deprecated Use defaultProfile */
|
|
122
|
+
activeProfile?: string;
|
|
123
|
+
profiles?: Record<string, ConfigProfile>;
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
/**
|
|
127
|
+
* Config structure
|
|
128
|
+
*/
|
|
129
|
+
interface SpecWeaveConfig {
|
|
130
|
+
sync?: SyncConfig;
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
/**
|
|
134
|
+
* JIRA Profile Resolver
|
|
135
|
+
*/
|
|
136
|
+
export class JiraProfileResolver {
|
|
137
|
+
private projectRoot: string;
|
|
138
|
+
private configPath: string;
|
|
139
|
+
private incrementsPath: string;
|
|
140
|
+
|
|
141
|
+
constructor(projectRoot: string = process.cwd()) {
|
|
142
|
+
this.projectRoot = projectRoot;
|
|
143
|
+
this.configPath = path.join(projectRoot, '.specweave', 'config.json');
|
|
144
|
+
this.incrementsPath = path.join(projectRoot, '.specweave', 'increments');
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
/**
|
|
148
|
+
* Resolve the JIRA profile for an increment
|
|
149
|
+
*
|
|
150
|
+
* Priority:
|
|
151
|
+
* 1. Increment's metadata.json -> external_sync.jira.profile
|
|
152
|
+
* 2. Config.json -> sync.defaultProfile (v0.31.0+)
|
|
153
|
+
* 3. Config.json -> sync.activeProfile (legacy fallback)
|
|
154
|
+
*
|
|
155
|
+
* @param incrementId - Increment ID (e.g., "0093-my-feature")
|
|
156
|
+
* @returns Profile resolution result
|
|
157
|
+
*/
|
|
158
|
+
async resolveProfile(incrementId: string): Promise<ProfileResolutionResult> {
|
|
159
|
+
// Load global config
|
|
160
|
+
const config = await this.loadConfig();
|
|
161
|
+
if (!config) {
|
|
162
|
+
return {
|
|
163
|
+
success: false,
|
|
164
|
+
error: 'Failed to load .specweave/config.json',
|
|
165
|
+
incrementId,
|
|
166
|
+
};
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
// Try to get increment-specific profile first
|
|
170
|
+
const incrementProfile = await this.getIncrementProfile(incrementId);
|
|
171
|
+
|
|
172
|
+
// Determine which profile to use (defaultProfile preferred over activeProfile)
|
|
173
|
+
const globalDefaultProfile = config.sync?.defaultProfile ?? config.sync?.activeProfile;
|
|
174
|
+
const profileName = incrementProfile || globalDefaultProfile;
|
|
175
|
+
|
|
176
|
+
if (!profileName) {
|
|
177
|
+
return {
|
|
178
|
+
success: false,
|
|
179
|
+
error: 'No JIRA profile configured. Set sync.defaultProfile in config.json or external_sync.jira.profile in increment metadata.',
|
|
180
|
+
incrementId,
|
|
181
|
+
};
|
|
182
|
+
}
|
|
183
|
+
|
|
184
|
+
// Check if profile is for JIRA provider
|
|
185
|
+
const profiles = config.sync?.profiles || {};
|
|
186
|
+
const profileConfig = profiles[profileName] as ConfigProfile | undefined;
|
|
187
|
+
|
|
188
|
+
if (!profileConfig) {
|
|
189
|
+
return {
|
|
190
|
+
success: false,
|
|
191
|
+
error: `Profile "${profileName}" not found in config.sync.profiles`,
|
|
192
|
+
incrementId,
|
|
193
|
+
};
|
|
194
|
+
}
|
|
195
|
+
|
|
196
|
+
if (profileConfig.provider !== 'jira') {
|
|
197
|
+
return {
|
|
198
|
+
success: false,
|
|
199
|
+
error: `Profile "${profileName}" is not a JIRA profile (provider: ${profileConfig.provider})`,
|
|
200
|
+
incrementId,
|
|
201
|
+
};
|
|
202
|
+
}
|
|
203
|
+
|
|
204
|
+
// Validate required fields
|
|
205
|
+
if (!profileConfig.config?.domain || !profileConfig.config?.projectKey) {
|
|
206
|
+
return {
|
|
207
|
+
success: false,
|
|
208
|
+
error: `Profile "${profileName}" missing required fields (domain, projectKey)`,
|
|
209
|
+
incrementId,
|
|
210
|
+
};
|
|
211
|
+
}
|
|
212
|
+
|
|
213
|
+
return {
|
|
214
|
+
success: true,
|
|
215
|
+
profile: {
|
|
216
|
+
profileName,
|
|
217
|
+
domain: profileConfig.config.domain,
|
|
218
|
+
projectKey: profileConfig.config.projectKey,
|
|
219
|
+
displayName: profileConfig.displayName,
|
|
220
|
+
boardId: profileConfig.config.boardId,
|
|
221
|
+
boardName: profileConfig.config.boardName,
|
|
222
|
+
instanceType: profileConfig.config.instanceType ?? 'cloud',
|
|
223
|
+
},
|
|
224
|
+
source: incrementProfile ? 'increment' : 'global',
|
|
225
|
+
incrementId,
|
|
226
|
+
};
|
|
227
|
+
}
|
|
228
|
+
|
|
229
|
+
/**
|
|
230
|
+
* Get increment's stored JIRA profile name
|
|
231
|
+
*
|
|
232
|
+
* @param incrementId - Increment ID
|
|
233
|
+
* @returns Profile name or null if not set
|
|
234
|
+
*/
|
|
235
|
+
async getIncrementProfile(incrementId: string): Promise<string | null> {
|
|
236
|
+
const metadataPath = path.join(this.incrementsPath, incrementId, 'metadata.json');
|
|
237
|
+
|
|
238
|
+
try {
|
|
239
|
+
const content = await fs.readFile(metadataPath, 'utf-8');
|
|
240
|
+
const metadata = JSON.parse(content);
|
|
241
|
+
|
|
242
|
+
// Check for profile in external_sync.jira.profile (standardized naming)
|
|
243
|
+
// Also support legacy external_ids.jira for backwards compatibility
|
|
244
|
+
return metadata?.external_sync?.jira?.profile
|
|
245
|
+
|| metadata?.external_ids?.jira?.profile
|
|
246
|
+
|| null;
|
|
247
|
+
} catch {
|
|
248
|
+
// Metadata not found or invalid - return null
|
|
249
|
+
return null;
|
|
250
|
+
}
|
|
251
|
+
}
|
|
252
|
+
|
|
253
|
+
/**
|
|
254
|
+
* Get increment's stored JIRA issue key
|
|
255
|
+
*
|
|
256
|
+
* @param incrementId - Increment ID
|
|
257
|
+
* @returns Issue key (e.g., PROJ-123) or null if not linked
|
|
258
|
+
*/
|
|
259
|
+
async getIncrementIssueKey(incrementId: string): Promise<string | null> {
|
|
260
|
+
const metadataPath = path.join(this.incrementsPath, incrementId, 'metadata.json');
|
|
261
|
+
|
|
262
|
+
try {
|
|
263
|
+
const content = await fs.readFile(metadataPath, 'utf-8');
|
|
264
|
+
const metadata = JSON.parse(content);
|
|
265
|
+
|
|
266
|
+
// Check both standardized and legacy paths
|
|
267
|
+
return metadata?.external_sync?.jira?.issueKey
|
|
268
|
+
|| metadata?.external_ids?.jira?.epic
|
|
269
|
+
|| metadata?.external_ids?.jira?.issueKey
|
|
270
|
+
|| null;
|
|
271
|
+
} catch {
|
|
272
|
+
return null;
|
|
273
|
+
}
|
|
274
|
+
}
|
|
275
|
+
|
|
276
|
+
/**
|
|
277
|
+
* Set increment's JIRA profile
|
|
278
|
+
*
|
|
279
|
+
* Stores the profile name in the increment's metadata.json
|
|
280
|
+
*
|
|
281
|
+
* @param incrementId - Increment ID
|
|
282
|
+
* @param profileName - Profile name to set
|
|
283
|
+
*/
|
|
284
|
+
async setIncrementProfile(incrementId: string, profileName: string): Promise<void> {
|
|
285
|
+
const metadataPath = path.join(this.incrementsPath, incrementId, 'metadata.json');
|
|
286
|
+
|
|
287
|
+
// Load existing metadata
|
|
288
|
+
let metadata: Record<string, unknown> = {};
|
|
289
|
+
try {
|
|
290
|
+
const content = await fs.readFile(metadataPath, 'utf-8');
|
|
291
|
+
metadata = JSON.parse(content);
|
|
292
|
+
} catch {
|
|
293
|
+
// Start with empty metadata if not found
|
|
294
|
+
}
|
|
295
|
+
|
|
296
|
+
// Set external_sync.jira.profile (standardized naming)
|
|
297
|
+
if (!metadata.external_sync) {
|
|
298
|
+
metadata.external_sync = {};
|
|
299
|
+
}
|
|
300
|
+
if (!(metadata.external_sync as Record<string, unknown>).jira) {
|
|
301
|
+
(metadata.external_sync as Record<string, unknown>).jira = {};
|
|
302
|
+
}
|
|
303
|
+
((metadata.external_sync as Record<string, unknown>).jira as Record<string, unknown>).profile = profileName;
|
|
304
|
+
|
|
305
|
+
// Write back
|
|
306
|
+
await fs.writeFile(metadataPath, JSON.stringify(metadata, null, 2) + '\n', 'utf-8');
|
|
307
|
+
}
|
|
308
|
+
|
|
309
|
+
/**
|
|
310
|
+
* Set increment's JIRA issue key
|
|
311
|
+
*
|
|
312
|
+
* @param incrementId - Increment ID
|
|
313
|
+
* @param issueKey - JIRA issue key (e.g., PROJ-123)
|
|
314
|
+
*/
|
|
315
|
+
async setIncrementIssueKey(incrementId: string, issueKey: string): Promise<void> {
|
|
316
|
+
const metadataPath = path.join(this.incrementsPath, incrementId, 'metadata.json');
|
|
317
|
+
|
|
318
|
+
// Load existing metadata
|
|
319
|
+
let metadata: Record<string, unknown> = {};
|
|
320
|
+
try {
|
|
321
|
+
const content = await fs.readFile(metadataPath, 'utf-8');
|
|
322
|
+
metadata = JSON.parse(content);
|
|
323
|
+
} catch {
|
|
324
|
+
// Start with empty metadata if not found
|
|
325
|
+
}
|
|
326
|
+
|
|
327
|
+
// Set external_sync.jira.issueKey (standardized naming)
|
|
328
|
+
if (!metadata.external_sync) {
|
|
329
|
+
metadata.external_sync = {};
|
|
330
|
+
}
|
|
331
|
+
if (!(metadata.external_sync as Record<string, unknown>).jira) {
|
|
332
|
+
(metadata.external_sync as Record<string, unknown>).jira = {};
|
|
333
|
+
}
|
|
334
|
+
const jiraSync = (metadata.external_sync as Record<string, unknown>).jira as Record<string, unknown>;
|
|
335
|
+
jiraSync.issueKey = issueKey;
|
|
336
|
+
jiraSync.lastSyncedAt = new Date().toISOString();
|
|
337
|
+
|
|
338
|
+
// Write back
|
|
339
|
+
await fs.writeFile(metadataPath, JSON.stringify(metadata, null, 2) + '\n', 'utf-8');
|
|
340
|
+
}
|
|
341
|
+
|
|
342
|
+
/**
|
|
343
|
+
* List available JIRA profiles
|
|
344
|
+
*
|
|
345
|
+
* @returns Array of profile names
|
|
346
|
+
*/
|
|
347
|
+
async listJiraProfiles(): Promise<string[]> {
|
|
348
|
+
const config = await this.loadConfig();
|
|
349
|
+
if (!config?.sync?.profiles) {
|
|
350
|
+
return [];
|
|
351
|
+
}
|
|
352
|
+
|
|
353
|
+
const profiles = config.sync.profiles as Record<string, ConfigProfile>;
|
|
354
|
+
return Object.entries(profiles)
|
|
355
|
+
.filter(([_, p]) => p.provider === 'jira')
|
|
356
|
+
.map(([name]) => name);
|
|
357
|
+
}
|
|
358
|
+
|
|
359
|
+
/**
|
|
360
|
+
* Get profile details by name
|
|
361
|
+
*
|
|
362
|
+
* @param profileName - Profile name
|
|
363
|
+
* @returns Profile config or null
|
|
364
|
+
*/
|
|
365
|
+
async getProfileByName(profileName: string): Promise<JiraProfileConfig | null> {
|
|
366
|
+
const config = await this.loadConfig();
|
|
367
|
+
if (!config?.sync?.profiles) {
|
|
368
|
+
return null;
|
|
369
|
+
}
|
|
370
|
+
|
|
371
|
+
const profileConfig = config.sync.profiles[profileName] as ConfigProfile | undefined;
|
|
372
|
+
if (!profileConfig || profileConfig.provider !== 'jira') {
|
|
373
|
+
return null;
|
|
374
|
+
}
|
|
375
|
+
|
|
376
|
+
return {
|
|
377
|
+
profileName,
|
|
378
|
+
domain: profileConfig.config.domain,
|
|
379
|
+
projectKey: profileConfig.config.projectKey,
|
|
380
|
+
displayName: profileConfig.displayName,
|
|
381
|
+
boardId: profileConfig.config.boardId,
|
|
382
|
+
boardName: profileConfig.config.boardName,
|
|
383
|
+
instanceType: profileConfig.config.instanceType ?? 'cloud',
|
|
384
|
+
};
|
|
385
|
+
}
|
|
386
|
+
|
|
387
|
+
/**
|
|
388
|
+
* Load config.json
|
|
389
|
+
*/
|
|
390
|
+
private async loadConfig(): Promise<SpecWeaveConfig | null> {
|
|
391
|
+
try {
|
|
392
|
+
const content = await fs.readFile(this.configPath, 'utf-8');
|
|
393
|
+
return JSON.parse(content) as SpecWeaveConfig;
|
|
394
|
+
} catch {
|
|
395
|
+
return null;
|
|
396
|
+
}
|
|
397
|
+
}
|
|
398
|
+
}
|
|
399
|
+
|
|
400
|
+
/**
|
|
401
|
+
* Create a JiraProfileResolver instance
|
|
402
|
+
*
|
|
403
|
+
* @param projectRoot - Project root directory (defaults to cwd)
|
|
404
|
+
* @returns JiraProfileResolver instance
|
|
405
|
+
*/
|
|
406
|
+
export async function createJiraProfileResolver(
|
|
407
|
+
projectRoot: string = process.cwd()
|
|
408
|
+
): Promise<JiraProfileResolver> {
|
|
409
|
+
return new JiraProfileResolver(projectRoot);
|
|
410
|
+
}
|
|
411
|
+
|
|
412
|
+
/**
|
|
413
|
+
* Quick resolve: Get JIRA profile for an increment
|
|
414
|
+
*
|
|
415
|
+
* @param incrementId - Increment ID
|
|
416
|
+
* @param projectRoot - Project root directory
|
|
417
|
+
* @returns Profile resolution result
|
|
418
|
+
*/
|
|
419
|
+
export async function resolveJiraProfile(
|
|
420
|
+
incrementId: string,
|
|
421
|
+
projectRoot: string = process.cwd()
|
|
422
|
+
): Promise<ProfileResolutionResult> {
|
|
423
|
+
const resolver = new JiraProfileResolver(projectRoot);
|
|
424
|
+
return resolver.resolveProfile(incrementId);
|
|
425
|
+
}
|
|
426
|
+
|
|
427
|
+
export default JiraProfileResolver;
|
|
@@ -41,16 +41,21 @@ This is the **MOST CRITICAL** mapping. Never deviate from this 1:1 relationship.
|
|
|
41
41
|
```yaml
|
|
42
42
|
# .specweave/increments/####-{name}/metadata.json
|
|
43
43
|
{
|
|
44
|
-
"
|
|
44
|
+
"external_sync": {
|
|
45
45
|
"jira": {
|
|
46
|
-
"
|
|
47
|
-
"
|
|
48
|
-
"
|
|
46
|
+
"profile": "jira-my-project",
|
|
47
|
+
"issueKey": "PROJ-123",
|
|
48
|
+
"issueUrl": "https://company.atlassian.net/browse/PROJ-123",
|
|
49
|
+
"projectKey": "PROJ",
|
|
50
|
+
"lastSyncedAt": "2025-12-07T04:30:00Z"
|
|
49
51
|
}
|
|
50
52
|
}
|
|
51
53
|
}
|
|
52
54
|
```
|
|
53
55
|
|
|
56
|
+
**NOTE (v0.32.0+)**: Standardized to `external_sync.jira.*` for consistency with ADO (`external_sync.ado.*`).
|
|
57
|
+
Legacy `external_ids.jira.*` is still supported for backwards compatibility.
|
|
58
|
+
|
|
54
59
|
**Example**:
|
|
55
60
|
```
|
|
56
61
|
Jira Epic: PROJ-123 "User Authentication"
|
|
@@ -180,12 +185,12 @@ SpecWeave: .specweave/docs/internal/delivery/release-v1.0.md
|
|
|
180
185
|
```yaml
|
|
181
186
|
# metadata.json
|
|
182
187
|
{
|
|
183
|
-
"
|
|
188
|
+
"external_sync": {
|
|
184
189
|
"jira": {
|
|
185
190
|
"tasks": [
|
|
186
|
-
{"id": "T-001", "
|
|
187
|
-
{"id": "T-002", "
|
|
188
|
-
{"id": "T-003", "
|
|
191
|
+
{"id": "T-001", "issueKey": "PROJ-126"},
|
|
192
|
+
{"id": "T-002", "issueKey": "PROJ-127"},
|
|
193
|
+
{"id": "T-003", "issueKey": "PROJ-128"}
|
|
189
194
|
]
|
|
190
195
|
}
|
|
191
196
|
}
|
|
@@ -264,7 +269,7 @@ SpecWeave: .specweave/docs/internal/architecture/frontend-auth/
|
|
|
264
269
|
3. SpecWeave creates new increment:
|
|
265
270
|
```bash
|
|
266
271
|
.specweave/increments/0001-user-authentication/
|
|
267
|
-
├── metadata.json #
|
|
272
|
+
├── metadata.json # external_sync.jira.issueKey = PROJ-123
|
|
268
273
|
├── spec.md
|
|
269
274
|
├── plan.md
|
|
270
275
|
└── tasks.md
|
|
@@ -301,7 +306,7 @@ SpecWeave: .specweave/docs/internal/architecture/frontend-auth/
|
|
|
301
306
|
4. SpecWeave updates `metadata.json`:
|
|
302
307
|
```json
|
|
303
308
|
{
|
|
304
|
-
"
|
|
309
|
+
"external_sync": {
|
|
305
310
|
"jira": {
|
|
306
311
|
"stories": ["PROJ-124"]
|
|
307
312
|
}
|
|
@@ -330,7 +335,7 @@ SpecWeave: .specweave/docs/internal/architecture/frontend-auth/
|
|
|
330
335
|
6. SpecWeave updates `metadata.json`:
|
|
331
336
|
```json
|
|
332
337
|
{
|
|
333
|
-
"
|
|
338
|
+
"external_sync": {
|
|
334
339
|
"jira": {
|
|
335
340
|
"stories": ["PROJ-124", "PROJ-131"]
|
|
336
341
|
}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: specweave-release:npm
|
|
3
|
-
description: Bump patch version, auto-commit dirty changes, push to GitHub, build, publish to npmjs.org. Use --ci for GitHub Actions publish. Use --only for local publish without git push. Use --only --local for version bump only.
|
|
3
|
+
description: Bump patch version, auto-commit dirty changes, push to GitHub, build, publish to npmjs.org. Use --quick for save+release (no GH workflow). Use --ci for GitHub Actions publish. Use --only for local publish without git push. Use --only --local for version bump only.
|
|
4
4
|
---
|
|
5
5
|
|
|
6
6
|
# /specweave-release:npm - NPM Release Automation
|
|
@@ -12,6 +12,7 @@ You are the NPM Release Assistant. Your job is to automate the patch version rel
|
|
|
12
12
|
| Command | Flow | Use Case |
|
|
13
13
|
|---------|------|----------|
|
|
14
14
|
| `/specweave-release:npm` | Auto-commit → **PUSH** → Bump → Build → **Publish** → Push tag | **DEFAULT: INSTANT RELEASE** |
|
|
15
|
+
| `/specweave-release:npm --quick` | Auto-commit → **PUSH** → Bump → Build → **Publish locally** → NO GH workflow | **QUICK: Save + Local Release** |
|
|
15
16
|
| `/specweave-release:npm --ci` | Bump → Push → **CI publishes** | Let GitHub Actions handle npm publish |
|
|
16
17
|
| `/specweave-release:npm --only` | Bump → Build → **Publish locally** → NO push | Quick local release, push later |
|
|
17
18
|
| `/specweave-release:npm --only --local` | **Bump ONLY** → NO build, NO publish, NO git | FASTEST: Local testing only |
|
|
@@ -21,6 +22,7 @@ You are the NPM Release Assistant. Your job is to automate the patch version rel
|
|
|
21
22
|
Check flags in the command invocation:
|
|
22
23
|
|
|
23
24
|
```
|
|
25
|
+
--quick → QUICK MODE: save (commit+push) + local npm publish (NO GH workflow trigger)
|
|
24
26
|
--ci → CI MODE: push to git, GitHub Actions publishes (requires clean working tree)
|
|
25
27
|
--only --local → Version bump ONLY (no build, no publish, no git) - FASTEST
|
|
26
28
|
--only → Direct publish to npm (bypass CI), no git push
|
|
@@ -28,12 +30,14 @@ Check flags in the command invocation:
|
|
|
28
30
|
```
|
|
29
31
|
|
|
30
32
|
**Flag Detection Order:**
|
|
31
|
-
1. Check for `--
|
|
32
|
-
2. Check for `--
|
|
33
|
-
3.
|
|
34
|
-
4. If `--only`
|
|
35
|
-
5.
|
|
36
|
-
|
|
33
|
+
1. Check for `--quick` flag → QUICK MODE (save + local publish, NO GH workflow)
|
|
34
|
+
2. Check for `--ci` flag → CI MODE (GitHub Actions publishes)
|
|
35
|
+
3. Check for `--only` flag
|
|
36
|
+
4. If `--only` present, check for `--local` flag → LOCAL MODE (fastest)
|
|
37
|
+
5. If `--only` only → DIRECT MODE
|
|
38
|
+
6. No flags → **DEFAULT: INSTANT RELEASE** (auto-commit dirty, push, build, publish)
|
|
39
|
+
|
|
40
|
+
**If `--quick`**: Use QUICK MODE (section "Quick Mode Workflow")
|
|
37
41
|
**If `--ci`**: Use CI MODE (section "CI Mode Workflow")
|
|
38
42
|
**If `--only --local`**: Use LOCAL MODE (section "Local Mode Workflow") - FASTEST!
|
|
39
43
|
**If `--only` only**: Use DIRECT MODE (section "Direct Mode Workflow")
|
|
@@ -160,6 +164,124 @@ git push origin develop --follow-tags
|
|
|
160
164
|
|
|
161
165
|
---
|
|
162
166
|
|
|
167
|
+
## QUICK MODE WORKFLOW (--quick flag) - SAVE + LOCAL RELEASE
|
|
168
|
+
|
|
169
|
+
Use this workflow when `--quick` flag is detected. This combines `/specweave:save` behavior with local npm publish. **NO GitHub workflow trigger** - everything happens locally.
|
|
170
|
+
|
|
171
|
+
**Use case**: You want to quickly save your work AND release a new patch version without waiting for GitHub Actions. Perfect for:
|
|
172
|
+
- Hotfixes that need immediate npm availability
|
|
173
|
+
- Iterative releases during active development
|
|
174
|
+
- When GitHub Actions are slow or unavailable
|
|
175
|
+
|
|
176
|
+
**Key difference from DEFAULT mode**: Does NOT push the version tag, so GitHub Actions release workflow is NOT triggered.
|
|
177
|
+
|
|
178
|
+
### 1. Pre-flight Check
|
|
179
|
+
|
|
180
|
+
```bash
|
|
181
|
+
# Verify we're on develop branch
|
|
182
|
+
git rev-parse --abbrev-ref HEAD
|
|
183
|
+
|
|
184
|
+
# Get current version
|
|
185
|
+
node -p "require('./package.json').version"
|
|
186
|
+
```
|
|
187
|
+
|
|
188
|
+
**STOP if**: Not on `develop` branch (ask user to switch)
|
|
189
|
+
|
|
190
|
+
### 2. Auto-Commit Dirty Changes (if any)
|
|
191
|
+
|
|
192
|
+
```bash
|
|
193
|
+
# Check for uncommitted changes
|
|
194
|
+
git status --porcelain
|
|
195
|
+
```
|
|
196
|
+
|
|
197
|
+
If dirty, generate smart commit message and commit:
|
|
198
|
+
|
|
199
|
+
```bash
|
|
200
|
+
git add -A
|
|
201
|
+
git commit -m "[auto-generated message based on changed files]"
|
|
202
|
+
```
|
|
203
|
+
|
|
204
|
+
**Message generation rules:**
|
|
205
|
+
- `src/**` changes → `fix: update implementation`
|
|
206
|
+
- `plugins/**` changes → `feat(plugins): update plugin`
|
|
207
|
+
- `.specweave/**` changes → `chore: update specweave config`
|
|
208
|
+
- `*.md` changes → `docs: update documentation`
|
|
209
|
+
- Mixed → `chore: update code and documentation`
|
|
210
|
+
|
|
211
|
+
### 3. Push Dirty Commit to Remote
|
|
212
|
+
|
|
213
|
+
```bash
|
|
214
|
+
# Push dirty commit to remote - ensures code is safe before release
|
|
215
|
+
git push origin develop
|
|
216
|
+
```
|
|
217
|
+
|
|
218
|
+
### 4. Bump Patch Version
|
|
219
|
+
|
|
220
|
+
```bash
|
|
221
|
+
npm version patch -m "chore: bump version to %s"
|
|
222
|
+
```
|
|
223
|
+
|
|
224
|
+
This creates a NEW commit + tag locally.
|
|
225
|
+
|
|
226
|
+
### 5. Build Package
|
|
227
|
+
|
|
228
|
+
```bash
|
|
229
|
+
npm run rebuild
|
|
230
|
+
```
|
|
231
|
+
|
|
232
|
+
### 6. Publish to NPM Locally
|
|
233
|
+
|
|
234
|
+
```bash
|
|
235
|
+
# Publish directly to npmjs.org (NO GitHub Actions!)
|
|
236
|
+
npm publish --registry https://registry.npmjs.org
|
|
237
|
+
```
|
|
238
|
+
|
|
239
|
+
### 7. Push Version Commit ONLY (NO tag!)
|
|
240
|
+
|
|
241
|
+
```bash
|
|
242
|
+
# Push ONLY the version commit, NOT the tag
|
|
243
|
+
# This prevents GitHub Actions release workflow from triggering
|
|
244
|
+
git push origin develop
|
|
245
|
+
```
|
|
246
|
+
|
|
247
|
+
**CRITICAL**: Do NOT use `--follow-tags`! We want local npm publish only.
|
|
248
|
+
|
|
249
|
+
### 8. Report Results
|
|
250
|
+
|
|
251
|
+
```markdown
|
|
252
|
+
✅ **Quick release complete!**
|
|
253
|
+
|
|
254
|
+
📦 **Version**: vX.Y.Z
|
|
255
|
+
🔗 **NPM**: https://www.npmjs.com/package/specweave
|
|
256
|
+
🏷️ **Git Tag**: vX.Y.Z (local only - NOT pushed)
|
|
257
|
+
|
|
258
|
+
**What happened**:
|
|
259
|
+
- ✅ Dirty changes auto-committed
|
|
260
|
+
- ✅ Pushed to GitHub (code safe!)
|
|
261
|
+
- ✅ Version bumped to X.Y.Z
|
|
262
|
+
- ✅ Package built
|
|
263
|
+
- ✅ Published to npmjs.org (locally)
|
|
264
|
+
- ⏭️ Tag NOT pushed (no GitHub Actions triggered)
|
|
265
|
+
|
|
266
|
+
**Verify**: `npm view specweave version --registry https://registry.npmjs.org`
|
|
267
|
+
|
|
268
|
+
**If you want to push the tag later** (triggers GH release):
|
|
269
|
+
`git push origin vX.Y.Z`
|
|
270
|
+
```
|
|
271
|
+
|
|
272
|
+
## Quick Mode Success Criteria
|
|
273
|
+
|
|
274
|
+
✅ Any dirty changes auto-committed
|
|
275
|
+
✅ Dirty commit pushed to remote
|
|
276
|
+
✅ Version bumped in package.json
|
|
277
|
+
✅ Git commit and tag created locally
|
|
278
|
+
✅ Package rebuilt
|
|
279
|
+
✅ Published to npmjs.org (explicit registry!)
|
|
280
|
+
✅ Version commit pushed to GitHub
|
|
281
|
+
⏭️ Tag NOT pushed (no GitHub Actions)
|
|
282
|
+
|
|
283
|
+
---
|
|
284
|
+
|
|
163
285
|
## CI MODE WORKFLOW (--ci flag)
|
|
164
286
|
|
|
165
287
|
Use this workflow when `--ci` flag is detected. Push to git and let GitHub Actions handle npm publish.
|
|
@@ -337,9 +459,12 @@ Show the user:
|
|
|
337
459
|
## Quick Reference
|
|
338
460
|
|
|
339
461
|
```bash
|
|
340
|
-
# DEFAULT: Instant release (auto-commits dirty, publishes, pushes)
|
|
462
|
+
# DEFAULT: Instant release (auto-commits dirty, publishes, pushes + tag)
|
|
341
463
|
/specweave-release:npm
|
|
342
464
|
|
|
465
|
+
# QUICK: Save + local release (auto-commits, pushes, publishes - NO GH workflow)
|
|
466
|
+
/specweave-release:npm --quick
|
|
467
|
+
|
|
343
468
|
# CI release (GitHub Actions handles npm publish) - requires clean tree
|
|
344
469
|
/specweave-release:npm --ci
|
|
345
470
|
|
|
@@ -350,12 +475,13 @@ Show the user:
|
|
|
350
475
|
/specweave-release:npm --only --local
|
|
351
476
|
```
|
|
352
477
|
|
|
353
|
-
| Scenario | Command | Auto-Commit Dirty? | NPM Published By | Git Pushed |
|
|
354
|
-
|
|
355
|
-
| **INSTANT RELEASE** | (no flags) | ✅ Yes | You (npmjs.org) | ✅ Yes |
|
|
356
|
-
|
|
|
357
|
-
|
|
|
358
|
-
|
|
|
478
|
+
| Scenario | Command | Auto-Commit Dirty? | NPM Published By | Git Pushed | Tag Pushed |
|
|
479
|
+
|----------|---------|-------------------|------------------|------------|------------|
|
|
480
|
+
| **INSTANT RELEASE** | (no flags) | ✅ Yes | You (npmjs.org) | ✅ Yes | ✅ Yes (triggers GH) |
|
|
481
|
+
| **QUICK RELEASE** | `--quick` | ✅ Yes | You (npmjs.org) | ✅ Yes | ❌ No (no GH workflow) |
|
|
482
|
+
| CI release | `--ci` | ❌ STOP | GitHub Actions | ✅ Yes | ✅ Yes |
|
|
483
|
+
| Quick local, push later | `--only` | ❌ STOP | You (npmjs.org) | ❌ No | ❌ No |
|
|
484
|
+
| **FASTEST local test** | `--only --local` | N/A | ❌ None | ❌ No | ❌ No |
|
|
359
485
|
|
|
360
486
|
---
|
|
361
487
|
|