specweave 0.23.8 → 0.23.12
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-plugin/marketplace.json +7 -7
- package/CLAUDE.md +391 -1338
- package/dist/src/cli/commands/cleanup-cache.d.ts +14 -0
- package/dist/src/cli/commands/cleanup-cache.d.ts.map +1 -0
- package/dist/src/cli/commands/cleanup-cache.js +63 -0
- package/dist/src/cli/commands/cleanup-cache.js.map +1 -0
- package/dist/src/cli/commands/init.js +40 -0
- package/dist/src/cli/commands/init.js.map +1 -1
- package/dist/src/cli/commands/migrate-config.d.ts +22 -0
- package/dist/src/cli/commands/migrate-config.d.ts.map +1 -0
- package/dist/src/cli/commands/migrate-config.js +149 -0
- package/dist/src/cli/commands/migrate-config.js.map +1 -0
- package/dist/src/cli/helpers/async-project-loader.d.ts +148 -0
- package/dist/src/cli/helpers/async-project-loader.d.ts.map +1 -0
- package/dist/src/cli/helpers/async-project-loader.js +351 -0
- package/dist/src/cli/helpers/async-project-loader.js.map +1 -0
- package/dist/src/cli/helpers/cancelation-handler.d.ts +123 -0
- package/dist/src/cli/helpers/cancelation-handler.d.ts.map +1 -0
- package/dist/src/cli/helpers/cancelation-handler.js +187 -0
- package/dist/src/cli/helpers/cancelation-handler.js.map +1 -0
- package/dist/src/cli/helpers/import-strategy-prompter.d.ts +43 -0
- package/dist/src/cli/helpers/import-strategy-prompter.d.ts.map +1 -0
- package/dist/src/cli/helpers/import-strategy-prompter.js +136 -0
- package/dist/src/cli/helpers/import-strategy-prompter.js.map +1 -0
- package/dist/src/cli/helpers/issue-tracker/ado.d.ts +5 -2
- package/dist/src/cli/helpers/issue-tracker/ado.d.ts.map +1 -1
- package/dist/src/cli/helpers/issue-tracker/ado.js +90 -40
- package/dist/src/cli/helpers/issue-tracker/ado.js.map +1 -1
- package/dist/src/cli/helpers/issue-tracker/index.d.ts.map +1 -1
- package/dist/src/cli/helpers/issue-tracker/index.js +112 -60
- package/dist/src/cli/helpers/issue-tracker/index.js.map +1 -1
- package/dist/src/cli/helpers/issue-tracker/jira.d.ts +26 -2
- package/dist/src/cli/helpers/issue-tracker/jira.d.ts.map +1 -1
- package/dist/src/cli/helpers/issue-tracker/jira.js +197 -132
- package/dist/src/cli/helpers/issue-tracker/jira.js.map +1 -1
- package/dist/src/cli/helpers/progress-tracker.d.ts +121 -0
- package/dist/src/cli/helpers/progress-tracker.d.ts.map +1 -0
- package/dist/src/cli/helpers/progress-tracker.js +202 -0
- package/dist/src/cli/helpers/progress-tracker.js.map +1 -0
- package/dist/src/cli/helpers/project-count-fetcher.d.ts +69 -0
- package/dist/src/cli/helpers/project-count-fetcher.d.ts.map +1 -0
- package/dist/src/cli/helpers/project-count-fetcher.js +173 -0
- package/dist/src/cli/helpers/project-count-fetcher.js.map +1 -0
- package/dist/src/config/types.d.ts +14 -14
- package/dist/src/core/cache/cache-manager.d.ts +119 -0
- package/dist/src/core/cache/cache-manager.d.ts.map +1 -0
- package/dist/src/core/cache/cache-manager.js +304 -0
- package/dist/src/core/cache/cache-manager.js.map +1 -0
- package/dist/src/core/cache/rate-limit-checker.d.ts +92 -0
- package/dist/src/core/cache/rate-limit-checker.d.ts.map +1 -0
- package/dist/src/core/cache/rate-limit-checker.js +160 -0
- package/dist/src/core/cache/rate-limit-checker.js.map +1 -0
- package/dist/src/core/config/config-manager.d.ts +135 -0
- package/dist/src/core/config/config-manager.d.ts.map +1 -0
- package/dist/src/core/config/config-manager.js +341 -0
- package/dist/src/core/config/config-manager.js.map +1 -0
- package/dist/src/core/config/config-migrator.d.ts +102 -0
- package/dist/src/core/config/config-migrator.d.ts.map +1 -0
- package/dist/src/core/config/config-migrator.js +367 -0
- package/dist/src/core/config/config-migrator.js.map +1 -0
- package/dist/src/core/config/index.d.ts +10 -0
- package/dist/src/core/config/index.d.ts.map +1 -0
- package/dist/src/core/config/index.js +10 -0
- package/dist/src/core/config/index.js.map +1 -0
- package/dist/src/core/config/types.d.ts +216 -0
- package/dist/src/core/config/types.d.ts.map +1 -0
- package/dist/src/core/config/types.js +32 -0
- package/dist/src/core/config/types.js.map +1 -0
- package/dist/src/core/progress/cancelation-handler.d.ts +79 -0
- package/dist/src/core/progress/cancelation-handler.d.ts.map +1 -0
- package/dist/src/core/progress/cancelation-handler.js +111 -0
- package/dist/src/core/progress/cancelation-handler.js.map +1 -0
- package/dist/src/core/progress/import-state.d.ts +71 -0
- package/dist/src/core/progress/import-state.d.ts.map +1 -0
- package/dist/src/core/progress/import-state.js +96 -0
- package/dist/src/core/progress/import-state.js.map +1 -0
- package/dist/src/core/progress/progress-tracker.d.ts +139 -0
- package/dist/src/core/progress/progress-tracker.d.ts.map +1 -0
- package/dist/src/core/progress/progress-tracker.js +223 -0
- package/dist/src/core/progress/progress-tracker.js.map +1 -0
- package/dist/src/init/architecture/types.d.ts +6 -6
- package/dist/src/integrations/ado/ado-client.d.ts +25 -0
- package/dist/src/integrations/ado/ado-client.d.ts.map +1 -1
- package/dist/src/integrations/ado/ado-client.js +67 -0
- package/dist/src/integrations/ado/ado-client.js.map +1 -1
- package/dist/src/integrations/ado/ado-dependency-loader.d.ts +99 -0
- package/dist/src/integrations/ado/ado-dependency-loader.d.ts.map +1 -0
- package/dist/src/integrations/ado/ado-dependency-loader.js +207 -0
- package/dist/src/integrations/ado/ado-dependency-loader.js.map +1 -0
- package/dist/src/integrations/jira/jira-client.d.ts +32 -0
- package/dist/src/integrations/jira/jira-client.d.ts.map +1 -1
- package/dist/src/integrations/jira/jira-client.js +81 -0
- package/dist/src/integrations/jira/jira-client.js.map +1 -1
- package/dist/src/integrations/jira/jira-dependency-loader.d.ts +101 -0
- package/dist/src/integrations/jira/jira-dependency-loader.d.ts.map +1 -0
- package/dist/src/integrations/jira/jira-dependency-loader.js +200 -0
- package/dist/src/integrations/jira/jira-dependency-loader.js.map +1 -0
- package/dist/src/integrations/jira/jira-hierarchy-mapper.d.ts +104 -0
- package/dist/src/integrations/jira/jira-hierarchy-mapper.d.ts.map +1 -0
- package/dist/src/integrations/jira/jira-hierarchy-mapper.js +178 -0
- package/dist/src/integrations/jira/jira-hierarchy-mapper.js.map +1 -0
- package/package.json +1 -1
- package/plugins/specweave/.claude-plugin/plugin.json +20 -0
- package/plugins/specweave/agents/architect/AGENT.md +100 -602
- package/plugins/specweave/agents/pm/AGENT.md +96 -597
- package/plugins/specweave/agents/pm/AGENT.md.bak +1893 -0
- package/plugins/specweave/agents/pm/AGENT.md.bak2 +1754 -0
- package/plugins/specweave/commands/check-hooks.md +257 -0
- package/plugins/specweave/commands/migrate-config.md +104 -0
- package/plugins/specweave/hooks/post-edit-spec.sh +202 -31
- package/plugins/specweave/hooks/post-task-completion.sh +225 -228
- package/plugins/specweave/hooks/post-write-spec.sh +207 -31
- package/plugins/specweave/hooks/pre-edit-spec.sh +151 -0
- package/plugins/specweave/hooks/pre-task-completion.sh +5 -7
- package/plugins/specweave/hooks/pre-write-spec.sh +151 -0
- package/plugins/specweave/hooks/test-pretooluse-env.sh +72 -0
- package/plugins/specweave/skills/compliance-architecture/SKILL.md +374 -0
- package/plugins/specweave/skills/external-sync-wizard/SKILL.md +610 -0
- package/plugins/specweave/skills/pm-closure-validation/SKILL.md +541 -0
- package/plugins/specweave/skills/roadmap-planner/SKILL.md +473 -0
- package/plugins/specweave-ado/commands/refresh-cache.js +25 -0
- package/plugins/specweave-ado/commands/refresh-cache.ts +40 -0
- package/plugins/specweave-ado/hooks/post-task-completion.sh +1 -1
- package/plugins/specweave-github/hooks/post-task-completion.sh +1 -1
- package/plugins/specweave-jira/commands/refresh-cache.js +25 -0
- package/plugins/specweave-jira/commands/refresh-cache.ts +40 -0
- package/plugins/specweave-jira/hooks/post-task-completion.sh +1 -1
- package/plugins/specweave-kafka-streams/commands/topology.md +437 -0
- package/plugins/specweave-n8n/commands/workflow-template.md +262 -0
- package/plugins/specweave-release/hooks/.specweave/logs/dora-tracking.log +228 -6333
|
@@ -0,0 +1,160 @@
|
|
|
1
|
+
import { consoleLogger } from '../../utils/logger.js';
|
|
2
|
+
/**
|
|
3
|
+
* RateLimitChecker - Detects API rate limits and prevents hitting limits
|
|
4
|
+
*
|
|
5
|
+
* Features:
|
|
6
|
+
* - Parses rate limit headers from JIRA, GitHub, ADO
|
|
7
|
+
* - Handles 429 (Too Many Requests) errors
|
|
8
|
+
* - Suggests using stale cache when rate limit low
|
|
9
|
+
* - Supports exponential backoff
|
|
10
|
+
*
|
|
11
|
+
* Supported headers:
|
|
12
|
+
* - X-RateLimit-Remaining (JIRA Cloud, GitHub)
|
|
13
|
+
* - X-RateLimit-Reset (JIRA Cloud, GitHub)
|
|
14
|
+
* - Retry-After (Standard HTTP, JIRA Server, ADO)
|
|
15
|
+
* - x-ms-ratelimit-remaining (Azure DevOps)
|
|
16
|
+
*
|
|
17
|
+
* Threshold: 10 requests remaining (configurable)
|
|
18
|
+
*/
|
|
19
|
+
export class RateLimitChecker {
|
|
20
|
+
constructor(options = {}) {
|
|
21
|
+
this.logger = options.logger ?? consoleLogger;
|
|
22
|
+
this.threshold = options.threshold ?? 10; // Default: warn when < 10 requests remaining
|
|
23
|
+
}
|
|
24
|
+
/**
|
|
25
|
+
* Check if safe to proceed with API call based on response headers
|
|
26
|
+
*
|
|
27
|
+
* @param headers Response headers from previous API call
|
|
28
|
+
* @returns RateLimitCheckResult with canProceed flag
|
|
29
|
+
*/
|
|
30
|
+
shouldProceed(headers) {
|
|
31
|
+
const remaining = headers.remaining;
|
|
32
|
+
// No rate limit headers = assume safe to proceed
|
|
33
|
+
if (remaining === undefined) {
|
|
34
|
+
return { canProceed: true };
|
|
35
|
+
}
|
|
36
|
+
// Low rate limit = use stale cache instead
|
|
37
|
+
if (remaining < this.threshold) {
|
|
38
|
+
const reason = `Rate limit low (${remaining} requests remaining, threshold: ${this.threshold})`;
|
|
39
|
+
this.logger.warn(reason);
|
|
40
|
+
this.logger.warn('Suggestion: Use stale cache to avoid hitting rate limit');
|
|
41
|
+
return {
|
|
42
|
+
canProceed: false,
|
|
43
|
+
reason,
|
|
44
|
+
remaining,
|
|
45
|
+
};
|
|
46
|
+
}
|
|
47
|
+
// Safe to proceed
|
|
48
|
+
return {
|
|
49
|
+
canProceed: true,
|
|
50
|
+
remaining,
|
|
51
|
+
};
|
|
52
|
+
}
|
|
53
|
+
/**
|
|
54
|
+
* Handle 429 (Too Many Requests) error
|
|
55
|
+
*
|
|
56
|
+
* @param error Error object with response headers
|
|
57
|
+
* @returns Promise<void>
|
|
58
|
+
*/
|
|
59
|
+
async handleRateLimitError(error) {
|
|
60
|
+
const retryAfter = this.extractRetryAfter(error);
|
|
61
|
+
const reset = this.extractReset(error);
|
|
62
|
+
if (retryAfter) {
|
|
63
|
+
this.logger.error(`Rate limit exceeded. Retry after ${retryAfter} seconds.`);
|
|
64
|
+
this.logger.warn('Suggestion: Use stale cache while waiting for rate limit reset');
|
|
65
|
+
}
|
|
66
|
+
else if (reset) {
|
|
67
|
+
const waitTime = Math.max(0, reset - Date.now() / 1000);
|
|
68
|
+
this.logger.error(`Rate limit exceeded. Reset in ${Math.ceil(waitTime)} seconds.`);
|
|
69
|
+
this.logger.warn('Suggestion: Use stale cache while waiting for rate limit reset');
|
|
70
|
+
}
|
|
71
|
+
else {
|
|
72
|
+
this.logger.error('Rate limit exceeded (no retry time provided)');
|
|
73
|
+
this.logger.warn('Suggestion: Use stale cache and retry later');
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
/**
|
|
77
|
+
* Extract rate limit headers from HTTP response
|
|
78
|
+
*
|
|
79
|
+
* Supports multiple header formats:
|
|
80
|
+
* - JIRA Cloud: X-RateLimit-Remaining, X-RateLimit-Reset
|
|
81
|
+
* - GitHub: X-RateLimit-Remaining, X-RateLimit-Reset
|
|
82
|
+
* - ADO: x-ms-ratelimit-remaining-resource, Retry-After
|
|
83
|
+
* - Standard: Retry-After
|
|
84
|
+
*
|
|
85
|
+
* @param response HTTP response or response-like object
|
|
86
|
+
* @returns RateLimitHeaders object
|
|
87
|
+
*/
|
|
88
|
+
extractHeaders(response) {
|
|
89
|
+
const headers = {};
|
|
90
|
+
// Handle different response formats (axios, fetch, etc.)
|
|
91
|
+
const getHeader = (name) => {
|
|
92
|
+
if (response.headers) {
|
|
93
|
+
// Axios-style headers object
|
|
94
|
+
if (typeof response.headers.get === 'function') {
|
|
95
|
+
return response.headers.get(name) ?? undefined;
|
|
96
|
+
}
|
|
97
|
+
// Plain object headers
|
|
98
|
+
return response.headers[name] ?? response.headers[name.toLowerCase()] ?? undefined;
|
|
99
|
+
}
|
|
100
|
+
return undefined;
|
|
101
|
+
};
|
|
102
|
+
// X-RateLimit-Remaining (JIRA Cloud, GitHub)
|
|
103
|
+
const remaining = getHeader('X-RateLimit-Remaining') || getHeader('x-ms-ratelimit-remaining-resource');
|
|
104
|
+
if (remaining) {
|
|
105
|
+
headers.remaining = parseInt(remaining, 10);
|
|
106
|
+
}
|
|
107
|
+
// X-RateLimit-Reset (JIRA Cloud, GitHub)
|
|
108
|
+
const reset = getHeader('X-RateLimit-Reset');
|
|
109
|
+
if (reset) {
|
|
110
|
+
headers.reset = parseInt(reset, 10);
|
|
111
|
+
}
|
|
112
|
+
// Retry-After (Standard HTTP, JIRA Server, ADO)
|
|
113
|
+
const retryAfter = getHeader('Retry-After');
|
|
114
|
+
if (retryAfter) {
|
|
115
|
+
headers.retryAfter = parseInt(retryAfter, 10);
|
|
116
|
+
}
|
|
117
|
+
return headers;
|
|
118
|
+
}
|
|
119
|
+
/**
|
|
120
|
+
* Extract Retry-After from error response
|
|
121
|
+
*
|
|
122
|
+
* @param error Error object
|
|
123
|
+
* @returns Retry-After in seconds, or null
|
|
124
|
+
*/
|
|
125
|
+
extractRetryAfter(error) {
|
|
126
|
+
if (error.response?.headers) {
|
|
127
|
+
const retryAfter = error.response.headers['Retry-After'] || error.response.headers['retry-after'];
|
|
128
|
+
if (retryAfter) {
|
|
129
|
+
return parseInt(retryAfter, 10);
|
|
130
|
+
}
|
|
131
|
+
}
|
|
132
|
+
return null;
|
|
133
|
+
}
|
|
134
|
+
/**
|
|
135
|
+
* Extract X-RateLimit-Reset from error response
|
|
136
|
+
*
|
|
137
|
+
* @param error Error object
|
|
138
|
+
* @returns Reset timestamp (Unix seconds), or null
|
|
139
|
+
*/
|
|
140
|
+
extractReset(error) {
|
|
141
|
+
if (error.response?.headers) {
|
|
142
|
+
const reset = error.response.headers['X-RateLimit-Reset'] ||
|
|
143
|
+
error.response.headers['x-ratelimit-reset'];
|
|
144
|
+
if (reset) {
|
|
145
|
+
return parseInt(reset, 10);
|
|
146
|
+
}
|
|
147
|
+
}
|
|
148
|
+
return null;
|
|
149
|
+
}
|
|
150
|
+
/**
|
|
151
|
+
* Check if error is a rate limit error (429 status)
|
|
152
|
+
*
|
|
153
|
+
* @param error Error object
|
|
154
|
+
* @returns True if 429 error
|
|
155
|
+
*/
|
|
156
|
+
isRateLimitError(error) {
|
|
157
|
+
return error.response?.status === 429 || error.status === 429;
|
|
158
|
+
}
|
|
159
|
+
}
|
|
160
|
+
//# sourceMappingURL=rate-limit-checker.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"rate-limit-checker.js","sourceRoot":"","sources":["../../../../src/core/cache/rate-limit-checker.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,135 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* SpecWeave Configuration Manager
|
|
3
|
+
*
|
|
4
|
+
* Manages .specweave/config.json for non-sensitive configuration
|
|
5
|
+
* (Secrets like API tokens go in .env, NOT in config.json)
|
|
6
|
+
*
|
|
7
|
+
* @module core/config/config-manager
|
|
8
|
+
*/
|
|
9
|
+
import { SpecWeaveConfig, ValidationResult } from './types.js';
|
|
10
|
+
/**
|
|
11
|
+
* Manages SpecWeave configuration
|
|
12
|
+
*/
|
|
13
|
+
export declare class ConfigManager {
|
|
14
|
+
private configPath;
|
|
15
|
+
private config;
|
|
16
|
+
/**
|
|
17
|
+
* Create a new ConfigManager
|
|
18
|
+
*
|
|
19
|
+
* @param projectRoot - Path to project root (default: process.cwd())
|
|
20
|
+
*/
|
|
21
|
+
constructor(projectRoot?: string);
|
|
22
|
+
/**
|
|
23
|
+
* Read configuration from disk
|
|
24
|
+
*
|
|
25
|
+
* @returns Configuration object
|
|
26
|
+
*/
|
|
27
|
+
read(): Promise<SpecWeaveConfig>;
|
|
28
|
+
/**
|
|
29
|
+
* Read configuration synchronously
|
|
30
|
+
*
|
|
31
|
+
* @returns Configuration object
|
|
32
|
+
*/
|
|
33
|
+
readSync(): SpecWeaveConfig;
|
|
34
|
+
/**
|
|
35
|
+
* Write configuration to disk
|
|
36
|
+
*
|
|
37
|
+
* @param config - Configuration to write
|
|
38
|
+
*/
|
|
39
|
+
write(config: SpecWeaveConfig): Promise<void>;
|
|
40
|
+
/**
|
|
41
|
+
* Update configuration with partial values
|
|
42
|
+
*
|
|
43
|
+
* @param partial - Partial configuration to merge
|
|
44
|
+
*/
|
|
45
|
+
update(partial: Partial<SpecWeaveConfig>): Promise<void>;
|
|
46
|
+
/**
|
|
47
|
+
* Get a specific configuration value by path
|
|
48
|
+
*
|
|
49
|
+
* @param path - Dot-separated path (e.g., "issueTracker.domain")
|
|
50
|
+
* @returns Configuration value
|
|
51
|
+
*/
|
|
52
|
+
get(path: string): Promise<any>;
|
|
53
|
+
/**
|
|
54
|
+
* Set a specific configuration value by path
|
|
55
|
+
*
|
|
56
|
+
* @param path - Dot-separated path (e.g., "issueTracker.domain")
|
|
57
|
+
* @param value - Value to set
|
|
58
|
+
*/
|
|
59
|
+
set(path: string, value: any): Promise<void>;
|
|
60
|
+
/**
|
|
61
|
+
* Check if configuration file exists
|
|
62
|
+
*
|
|
63
|
+
* @returns True if config exists
|
|
64
|
+
*/
|
|
65
|
+
exists(): Promise<boolean>;
|
|
66
|
+
/**
|
|
67
|
+
* Validate configuration
|
|
68
|
+
*
|
|
69
|
+
* @param config - Configuration to validate (default: current config)
|
|
70
|
+
* @returns Validation result
|
|
71
|
+
*/
|
|
72
|
+
validate(config?: SpecWeaveConfig): ValidationResult;
|
|
73
|
+
/**
|
|
74
|
+
* Merge configuration with defaults
|
|
75
|
+
*
|
|
76
|
+
* @param config - User configuration
|
|
77
|
+
* @returns Merged configuration
|
|
78
|
+
*/
|
|
79
|
+
private mergeWithDefaults;
|
|
80
|
+
/**
|
|
81
|
+
* Deep merge two objects
|
|
82
|
+
*
|
|
83
|
+
* @param target - Target object
|
|
84
|
+
* @param source - Source object
|
|
85
|
+
* @returns Merged object
|
|
86
|
+
*/
|
|
87
|
+
private deepMerge;
|
|
88
|
+
/**
|
|
89
|
+
* Get value by dot-separated path
|
|
90
|
+
*
|
|
91
|
+
* @param obj - Object to get value from
|
|
92
|
+
* @param path - Dot-separated path
|
|
93
|
+
* @returns Value at path
|
|
94
|
+
*/
|
|
95
|
+
private getByPath;
|
|
96
|
+
/**
|
|
97
|
+
* Set value by dot-separated path
|
|
98
|
+
*
|
|
99
|
+
* @param obj - Object to set value in
|
|
100
|
+
* @param path - Dot-separated path
|
|
101
|
+
* @param value - Value to set
|
|
102
|
+
* @returns Updated object
|
|
103
|
+
*/
|
|
104
|
+
private setByPath;
|
|
105
|
+
/**
|
|
106
|
+
* Clear cached configuration
|
|
107
|
+
*/
|
|
108
|
+
clearCache(): void;
|
|
109
|
+
}
|
|
110
|
+
/**
|
|
111
|
+
* Get global config manager instance
|
|
112
|
+
*
|
|
113
|
+
* @param projectRoot - Path to project root (default: process.cwd())
|
|
114
|
+
* @returns ConfigManager instance
|
|
115
|
+
*/
|
|
116
|
+
export declare function getConfigManager(projectRoot?: string): ConfigManager;
|
|
117
|
+
/**
|
|
118
|
+
* Read configuration
|
|
119
|
+
*
|
|
120
|
+
* Convenience function for reading config
|
|
121
|
+
*
|
|
122
|
+
* @param projectRoot - Path to project root (default: process.cwd())
|
|
123
|
+
* @returns Configuration object
|
|
124
|
+
*/
|
|
125
|
+
export declare function readConfig(projectRoot?: string): Promise<SpecWeaveConfig>;
|
|
126
|
+
/**
|
|
127
|
+
* Write configuration
|
|
128
|
+
*
|
|
129
|
+
* Convenience function for writing config
|
|
130
|
+
*
|
|
131
|
+
* @param config - Configuration to write
|
|
132
|
+
* @param projectRoot - Path to project root (default: process.cwd())
|
|
133
|
+
*/
|
|
134
|
+
export declare function writeConfig(config: SpecWeaveConfig, projectRoot?: string): Promise<void>;
|
|
135
|
+
//# sourceMappingURL=config-manager.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"config-manager.d.ts","sourceRoot":"","sources":["../../../../src/core/config/config-manager.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAIH,OAAO,EACL,eAAe,EAEf,gBAAgB,EAEjB,MAAM,YAAY,CAAC;AAOpB;;GAEG;AACH,qBAAa,aAAa;IACxB,OAAO,CAAC,UAAU,CAAS;IAC3B,OAAO,CAAC,MAAM,CAAgC;IAE9C;;;;OAIG;gBACS,WAAW,GAAE,MAAsB;IAI/C;;;;OAIG;IACG,IAAI,IAAI,OAAO,CAAC,eAAe,CAAC;IAsBtC;;;;OAIG;IACH,QAAQ,IAAI,eAAe;IAuB3B;;;;OAIG;IACG,KAAK,CAAC,MAAM,EAAE,eAAe,GAAG,OAAO,CAAC,IAAI,CAAC;IAwBnD;;;;OAIG;IACG,MAAM,CAAC,OAAO,EAAE,OAAO,CAAC,eAAe,CAAC,GAAG,OAAO,CAAC,IAAI,CAAC;IAM9D;;;;;OAKG;IACG,GAAG,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,GAAG,CAAC;IAKrC;;;;;OAKG;IACG,GAAG,CAAC,IAAI,EAAE,MAAM,EAAE,KAAK,EAAE,GAAG,GAAG,OAAO,CAAC,IAAI,CAAC;IAMlD;;;;OAIG;IACG,MAAM,IAAI,OAAO,CAAC,OAAO,CAAC;IAShC;;;;;OAKG;IACH,QAAQ,CAAC,MAAM,CAAC,EAAE,eAAe,GAAG,gBAAgB;IA6EpD;;;;;OAKG;IACH,OAAO,CAAC,iBAAiB;IAIzB;;;;;;OAMG;IACH,OAAO,CAAC,SAAS;IAgBjB;;;;;;OAMG;IACH,OAAO,CAAC,SAAS;IAcjB;;;;;;;OAOG;IACH,OAAO,CAAC,SAAS;IAejB;;OAEG;IACH,UAAU,IAAI,IAAI;CAGnB;AAOD;;;;;GAKG;AACH,wBAAgB,gBAAgB,CAAC,WAAW,CAAC,EAAE,MAAM,GAAG,aAAa,CAKpE;AAED;;;;;;;GAOG;AACH,wBAAsB,UAAU,CAAC,WAAW,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,eAAe,CAAC,CAG/E;AAED;;;;;;;GAOG;AACH,wBAAsB,WAAW,CAAC,MAAM,EAAE,eAAe,EAAE,WAAW,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAG9F"}
|
|
@@ -0,0 +1,341 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* SpecWeave Configuration Manager
|
|
3
|
+
*
|
|
4
|
+
* Manages .specweave/config.json for non-sensitive configuration
|
|
5
|
+
* (Secrets like API tokens go in .env, NOT in config.json)
|
|
6
|
+
*
|
|
7
|
+
* @module core/config/config-manager
|
|
8
|
+
*/
|
|
9
|
+
import { promises as fs } from 'fs';
|
|
10
|
+
import path from 'path';
|
|
11
|
+
import { DEFAULT_CONFIG } from './types.js';
|
|
12
|
+
/**
|
|
13
|
+
* Configuration file path
|
|
14
|
+
*/
|
|
15
|
+
const CONFIG_FILE_NAME = 'config.json';
|
|
16
|
+
/**
|
|
17
|
+
* Manages SpecWeave configuration
|
|
18
|
+
*/
|
|
19
|
+
export class ConfigManager {
|
|
20
|
+
/**
|
|
21
|
+
* Create a new ConfigManager
|
|
22
|
+
*
|
|
23
|
+
* @param projectRoot - Path to project root (default: process.cwd())
|
|
24
|
+
*/
|
|
25
|
+
constructor(projectRoot = process.cwd()) {
|
|
26
|
+
this.config = null;
|
|
27
|
+
this.configPath = path.join(projectRoot, '.specweave', CONFIG_FILE_NAME);
|
|
28
|
+
}
|
|
29
|
+
/**
|
|
30
|
+
* Read configuration from disk
|
|
31
|
+
*
|
|
32
|
+
* @returns Configuration object
|
|
33
|
+
*/
|
|
34
|
+
async read() {
|
|
35
|
+
if (this.config) {
|
|
36
|
+
return this.config;
|
|
37
|
+
}
|
|
38
|
+
try {
|
|
39
|
+
const content = await fs.readFile(this.configPath, 'utf-8');
|
|
40
|
+
const parsed = JSON.parse(content);
|
|
41
|
+
// Merge with defaults (for backward compatibility)
|
|
42
|
+
this.config = this.mergeWithDefaults(parsed);
|
|
43
|
+
return this.config;
|
|
44
|
+
}
|
|
45
|
+
catch (error) {
|
|
46
|
+
if (error.code === 'ENOENT') {
|
|
47
|
+
// Config file doesn't exist, return defaults
|
|
48
|
+
this.config = { ...DEFAULT_CONFIG };
|
|
49
|
+
return this.config;
|
|
50
|
+
}
|
|
51
|
+
throw new Error(`Failed to read config: ${error.message}`);
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
/**
|
|
55
|
+
* Read configuration synchronously
|
|
56
|
+
*
|
|
57
|
+
* @returns Configuration object
|
|
58
|
+
*/
|
|
59
|
+
readSync() {
|
|
60
|
+
if (this.config) {
|
|
61
|
+
return this.config;
|
|
62
|
+
}
|
|
63
|
+
try {
|
|
64
|
+
const { readFileSync } = require('fs');
|
|
65
|
+
const content = readFileSync(this.configPath, 'utf-8');
|
|
66
|
+
const parsed = JSON.parse(content);
|
|
67
|
+
// Merge with defaults
|
|
68
|
+
this.config = this.mergeWithDefaults(parsed);
|
|
69
|
+
return this.config;
|
|
70
|
+
}
|
|
71
|
+
catch (error) {
|
|
72
|
+
if (error.code === 'ENOENT') {
|
|
73
|
+
// Config file doesn't exist, return defaults
|
|
74
|
+
this.config = { ...DEFAULT_CONFIG };
|
|
75
|
+
return this.config;
|
|
76
|
+
}
|
|
77
|
+
throw new Error(`Failed to read config: ${error.message}`);
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
/**
|
|
81
|
+
* Write configuration to disk
|
|
82
|
+
*
|
|
83
|
+
* @param config - Configuration to write
|
|
84
|
+
*/
|
|
85
|
+
async write(config) {
|
|
86
|
+
// Validate before writing
|
|
87
|
+
const validation = this.validate(config);
|
|
88
|
+
if (!validation.valid) {
|
|
89
|
+
const errorMessages = validation.errors.map(e => `${e.path}: ${e.message}`).join('\n');
|
|
90
|
+
throw new Error(`Invalid configuration:\n${errorMessages}`);
|
|
91
|
+
}
|
|
92
|
+
try {
|
|
93
|
+
// Ensure .specweave directory exists
|
|
94
|
+
const dir = path.dirname(this.configPath);
|
|
95
|
+
await fs.mkdir(dir, { recursive: true });
|
|
96
|
+
// Write with pretty formatting
|
|
97
|
+
const content = JSON.stringify(config, null, 2);
|
|
98
|
+
await fs.writeFile(this.configPath, content, 'utf-8');
|
|
99
|
+
// Update cached config
|
|
100
|
+
this.config = config;
|
|
101
|
+
}
|
|
102
|
+
catch (error) {
|
|
103
|
+
throw new Error(`Failed to write config: ${error.message}`);
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
/**
|
|
107
|
+
* Update configuration with partial values
|
|
108
|
+
*
|
|
109
|
+
* @param partial - Partial configuration to merge
|
|
110
|
+
*/
|
|
111
|
+
async update(partial) {
|
|
112
|
+
const current = await this.read();
|
|
113
|
+
const updated = this.deepMerge(current, partial);
|
|
114
|
+
await this.write(updated);
|
|
115
|
+
}
|
|
116
|
+
/**
|
|
117
|
+
* Get a specific configuration value by path
|
|
118
|
+
*
|
|
119
|
+
* @param path - Dot-separated path (e.g., "issueTracker.domain")
|
|
120
|
+
* @returns Configuration value
|
|
121
|
+
*/
|
|
122
|
+
async get(path) {
|
|
123
|
+
const config = await this.read();
|
|
124
|
+
return this.getByPath(config, path);
|
|
125
|
+
}
|
|
126
|
+
/**
|
|
127
|
+
* Set a specific configuration value by path
|
|
128
|
+
*
|
|
129
|
+
* @param path - Dot-separated path (e.g., "issueTracker.domain")
|
|
130
|
+
* @param value - Value to set
|
|
131
|
+
*/
|
|
132
|
+
async set(path, value) {
|
|
133
|
+
const config = await this.read();
|
|
134
|
+
const updated = this.setByPath(config, path, value);
|
|
135
|
+
await this.write(updated);
|
|
136
|
+
}
|
|
137
|
+
/**
|
|
138
|
+
* Check if configuration file exists
|
|
139
|
+
*
|
|
140
|
+
* @returns True if config exists
|
|
141
|
+
*/
|
|
142
|
+
async exists() {
|
|
143
|
+
try {
|
|
144
|
+
await fs.access(this.configPath);
|
|
145
|
+
return true;
|
|
146
|
+
}
|
|
147
|
+
catch {
|
|
148
|
+
return false;
|
|
149
|
+
}
|
|
150
|
+
}
|
|
151
|
+
/**
|
|
152
|
+
* Validate configuration
|
|
153
|
+
*
|
|
154
|
+
* @param config - Configuration to validate (default: current config)
|
|
155
|
+
* @returns Validation result
|
|
156
|
+
*/
|
|
157
|
+
validate(config) {
|
|
158
|
+
const errors = [];
|
|
159
|
+
const cfg = config || this.config || DEFAULT_CONFIG;
|
|
160
|
+
// Validate version
|
|
161
|
+
if (!cfg.version) {
|
|
162
|
+
errors.push({
|
|
163
|
+
path: 'version',
|
|
164
|
+
message: 'Version is required',
|
|
165
|
+
value: cfg.version
|
|
166
|
+
});
|
|
167
|
+
}
|
|
168
|
+
// Validate repository provider
|
|
169
|
+
if (cfg.repository?.provider) {
|
|
170
|
+
const validProviders = ['local', 'github', 'bitbucket', 'ado', 'gitlab', 'generic'];
|
|
171
|
+
if (!validProviders.includes(cfg.repository.provider)) {
|
|
172
|
+
errors.push({
|
|
173
|
+
path: 'repository.provider',
|
|
174
|
+
message: `Invalid provider. Must be one of: ${validProviders.join(', ')}`,
|
|
175
|
+
value: cfg.repository.provider
|
|
176
|
+
});
|
|
177
|
+
}
|
|
178
|
+
}
|
|
179
|
+
// Validate issue tracker provider
|
|
180
|
+
if (cfg.issueTracker?.provider) {
|
|
181
|
+
const validTrackers = ['none', 'jira', 'github', 'ado'];
|
|
182
|
+
if (!validTrackers.includes(cfg.issueTracker.provider)) {
|
|
183
|
+
errors.push({
|
|
184
|
+
path: 'issueTracker.provider',
|
|
185
|
+
message: `Invalid tracker. Must be one of: ${validTrackers.join(', ')}`,
|
|
186
|
+
value: cfg.issueTracker.provider
|
|
187
|
+
});
|
|
188
|
+
}
|
|
189
|
+
}
|
|
190
|
+
// Validate Jira configuration
|
|
191
|
+
if (cfg.issueTracker?.provider === 'jira') {
|
|
192
|
+
if (!cfg.issueTracker.domain) {
|
|
193
|
+
errors.push({
|
|
194
|
+
path: 'issueTracker.domain',
|
|
195
|
+
message: 'Domain is required for Jira',
|
|
196
|
+
value: cfg.issueTracker.domain
|
|
197
|
+
});
|
|
198
|
+
}
|
|
199
|
+
if (cfg.issueTracker.strategy) {
|
|
200
|
+
const validStrategies = ['single-project', 'project-per-team', 'component-based', 'board-based'];
|
|
201
|
+
if (!validStrategies.includes(cfg.issueTracker.strategy)) {
|
|
202
|
+
errors.push({
|
|
203
|
+
path: 'issueTracker.strategy',
|
|
204
|
+
message: `Invalid strategy. Must be one of: ${validStrategies.join(', ')}`,
|
|
205
|
+
value: cfg.issueTracker.strategy
|
|
206
|
+
});
|
|
207
|
+
}
|
|
208
|
+
}
|
|
209
|
+
}
|
|
210
|
+
// Validate sync direction
|
|
211
|
+
if (cfg.sync?.direction) {
|
|
212
|
+
const validDirections = ['import', 'export', 'bidirectional'];
|
|
213
|
+
if (!validDirections.includes(cfg.sync.direction)) {
|
|
214
|
+
errors.push({
|
|
215
|
+
path: 'sync.direction',
|
|
216
|
+
message: `Invalid direction. Must be one of: ${validDirections.join(', ')}`,
|
|
217
|
+
value: cfg.sync.direction
|
|
218
|
+
});
|
|
219
|
+
}
|
|
220
|
+
}
|
|
221
|
+
return {
|
|
222
|
+
valid: errors.length === 0,
|
|
223
|
+
errors
|
|
224
|
+
};
|
|
225
|
+
}
|
|
226
|
+
/**
|
|
227
|
+
* Merge configuration with defaults
|
|
228
|
+
*
|
|
229
|
+
* @param config - User configuration
|
|
230
|
+
* @returns Merged configuration
|
|
231
|
+
*/
|
|
232
|
+
mergeWithDefaults(config) {
|
|
233
|
+
return this.deepMerge(DEFAULT_CONFIG, config);
|
|
234
|
+
}
|
|
235
|
+
/**
|
|
236
|
+
* Deep merge two objects
|
|
237
|
+
*
|
|
238
|
+
* @param target - Target object
|
|
239
|
+
* @param source - Source object
|
|
240
|
+
* @returns Merged object
|
|
241
|
+
*/
|
|
242
|
+
deepMerge(target, source) {
|
|
243
|
+
const result = { ...target };
|
|
244
|
+
for (const key in source) {
|
|
245
|
+
if (source[key] !== undefined && source[key] !== null) {
|
|
246
|
+
if (typeof source[key] === 'object' && !Array.isArray(source[key])) {
|
|
247
|
+
result[key] = this.deepMerge(result[key] || {}, source[key]);
|
|
248
|
+
}
|
|
249
|
+
else {
|
|
250
|
+
result[key] = source[key];
|
|
251
|
+
}
|
|
252
|
+
}
|
|
253
|
+
}
|
|
254
|
+
return result;
|
|
255
|
+
}
|
|
256
|
+
/**
|
|
257
|
+
* Get value by dot-separated path
|
|
258
|
+
*
|
|
259
|
+
* @param obj - Object to get value from
|
|
260
|
+
* @param path - Dot-separated path
|
|
261
|
+
* @returns Value at path
|
|
262
|
+
*/
|
|
263
|
+
getByPath(obj, path) {
|
|
264
|
+
const parts = path.split('.');
|
|
265
|
+
let current = obj;
|
|
266
|
+
for (const part of parts) {
|
|
267
|
+
if (current === null || current === undefined) {
|
|
268
|
+
return undefined;
|
|
269
|
+
}
|
|
270
|
+
current = current[part];
|
|
271
|
+
}
|
|
272
|
+
return current;
|
|
273
|
+
}
|
|
274
|
+
/**
|
|
275
|
+
* Set value by dot-separated path
|
|
276
|
+
*
|
|
277
|
+
* @param obj - Object to set value in
|
|
278
|
+
* @param path - Dot-separated path
|
|
279
|
+
* @param value - Value to set
|
|
280
|
+
* @returns Updated object
|
|
281
|
+
*/
|
|
282
|
+
setByPath(obj, path, value) {
|
|
283
|
+
const parts = path.split('.');
|
|
284
|
+
const result = { ...obj };
|
|
285
|
+
let current = result;
|
|
286
|
+
for (let i = 0; i < parts.length - 1; i++) {
|
|
287
|
+
const part = parts[i];
|
|
288
|
+
current[part] = { ...(current[part] || {}) };
|
|
289
|
+
current = current[part];
|
|
290
|
+
}
|
|
291
|
+
current[parts[parts.length - 1]] = value;
|
|
292
|
+
return result;
|
|
293
|
+
}
|
|
294
|
+
/**
|
|
295
|
+
* Clear cached configuration
|
|
296
|
+
*/
|
|
297
|
+
clearCache() {
|
|
298
|
+
this.config = null;
|
|
299
|
+
}
|
|
300
|
+
}
|
|
301
|
+
/**
|
|
302
|
+
* Global config manager instance
|
|
303
|
+
*/
|
|
304
|
+
let globalConfigManager = null;
|
|
305
|
+
/**
|
|
306
|
+
* Get global config manager instance
|
|
307
|
+
*
|
|
308
|
+
* @param projectRoot - Path to project root (default: process.cwd())
|
|
309
|
+
* @returns ConfigManager instance
|
|
310
|
+
*/
|
|
311
|
+
export function getConfigManager(projectRoot) {
|
|
312
|
+
if (!globalConfigManager || projectRoot) {
|
|
313
|
+
globalConfigManager = new ConfigManager(projectRoot);
|
|
314
|
+
}
|
|
315
|
+
return globalConfigManager;
|
|
316
|
+
}
|
|
317
|
+
/**
|
|
318
|
+
* Read configuration
|
|
319
|
+
*
|
|
320
|
+
* Convenience function for reading config
|
|
321
|
+
*
|
|
322
|
+
* @param projectRoot - Path to project root (default: process.cwd())
|
|
323
|
+
* @returns Configuration object
|
|
324
|
+
*/
|
|
325
|
+
export async function readConfig(projectRoot) {
|
|
326
|
+
const manager = getConfigManager(projectRoot);
|
|
327
|
+
return manager.read();
|
|
328
|
+
}
|
|
329
|
+
/**
|
|
330
|
+
* Write configuration
|
|
331
|
+
*
|
|
332
|
+
* Convenience function for writing config
|
|
333
|
+
*
|
|
334
|
+
* @param config - Configuration to write
|
|
335
|
+
* @param projectRoot - Path to project root (default: process.cwd())
|
|
336
|
+
*/
|
|
337
|
+
export async function writeConfig(config, projectRoot) {
|
|
338
|
+
const manager = getConfigManager(projectRoot);
|
|
339
|
+
await manager.write(config);
|
|
340
|
+
}
|
|
341
|
+
//# sourceMappingURL=config-manager.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"config-manager.js","sourceRoot":"","sources":["../../../../src/core/config/config-manager.ts"],"names":[],"mappings":"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"}
|