@juspay/yama 1.5.1 → 2.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (67) hide show
  1. package/.mcp-config.example.json +26 -0
  2. package/CHANGELOG.md +40 -0
  3. package/README.md +311 -685
  4. package/dist/cli/v2.cli.d.ts +13 -0
  5. package/dist/cli/v2.cli.js +290 -0
  6. package/dist/index.d.ts +12 -13
  7. package/dist/index.js +18 -19
  8. package/dist/v2/config/ConfigLoader.d.ts +50 -0
  9. package/dist/v2/config/ConfigLoader.js +205 -0
  10. package/dist/v2/config/DefaultConfig.d.ts +9 -0
  11. package/dist/v2/config/DefaultConfig.js +191 -0
  12. package/dist/v2/core/MCPServerManager.d.ts +22 -0
  13. package/dist/v2/core/MCPServerManager.js +92 -0
  14. package/dist/v2/core/SessionManager.d.ts +72 -0
  15. package/dist/v2/core/SessionManager.js +200 -0
  16. package/dist/v2/core/YamaV2Orchestrator.d.ts +112 -0
  17. package/dist/v2/core/YamaV2Orchestrator.js +549 -0
  18. package/dist/v2/prompts/EnhancementSystemPrompt.d.ts +8 -0
  19. package/dist/v2/prompts/EnhancementSystemPrompt.js +216 -0
  20. package/dist/v2/prompts/PromptBuilder.d.ts +38 -0
  21. package/dist/v2/prompts/PromptBuilder.js +228 -0
  22. package/dist/v2/prompts/ReviewSystemPrompt.d.ts +8 -0
  23. package/dist/v2/prompts/ReviewSystemPrompt.js +270 -0
  24. package/dist/v2/types/config.types.d.ts +120 -0
  25. package/dist/v2/types/config.types.js +5 -0
  26. package/dist/v2/types/mcp.types.d.ts +191 -0
  27. package/dist/v2/types/mcp.types.js +6 -0
  28. package/dist/v2/types/v2.types.d.ts +182 -0
  29. package/dist/v2/types/v2.types.js +42 -0
  30. package/dist/v2/utils/ObservabilityConfig.d.ts +22 -0
  31. package/dist/v2/utils/ObservabilityConfig.js +48 -0
  32. package/package.json +11 -9
  33. package/yama.config.example.yaml +214 -193
  34. package/dist/cli/index.d.ts +0 -12
  35. package/dist/cli/index.js +0 -538
  36. package/dist/core/ContextGatherer.d.ts +0 -110
  37. package/dist/core/ContextGatherer.js +0 -470
  38. package/dist/core/Guardian.d.ts +0 -81
  39. package/dist/core/Guardian.js +0 -474
  40. package/dist/core/providers/BitbucketProvider.d.ts +0 -105
  41. package/dist/core/providers/BitbucketProvider.js +0 -489
  42. package/dist/features/CodeReviewer.d.ts +0 -173
  43. package/dist/features/CodeReviewer.js +0 -1707
  44. package/dist/features/DescriptionEnhancer.d.ts +0 -64
  45. package/dist/features/DescriptionEnhancer.js +0 -445
  46. package/dist/features/MultiInstanceProcessor.d.ts +0 -74
  47. package/dist/features/MultiInstanceProcessor.js +0 -360
  48. package/dist/types/index.d.ts +0 -624
  49. package/dist/types/index.js +0 -104
  50. package/dist/utils/Cache.d.ts +0 -103
  51. package/dist/utils/Cache.js +0 -444
  52. package/dist/utils/ConfigManager.d.ts +0 -88
  53. package/dist/utils/ConfigManager.js +0 -603
  54. package/dist/utils/ContentSimilarityService.d.ts +0 -74
  55. package/dist/utils/ContentSimilarityService.js +0 -215
  56. package/dist/utils/ExactDuplicateRemover.d.ts +0 -77
  57. package/dist/utils/ExactDuplicateRemover.js +0 -361
  58. package/dist/utils/Logger.d.ts +0 -31
  59. package/dist/utils/Logger.js +0 -214
  60. package/dist/utils/MemoryBankManager.d.ts +0 -73
  61. package/dist/utils/MemoryBankManager.js +0 -310
  62. package/dist/utils/ParallelProcessing.d.ts +0 -140
  63. package/dist/utils/ParallelProcessing.js +0 -333
  64. package/dist/utils/ProviderLimits.d.ts +0 -58
  65. package/dist/utils/ProviderLimits.js +0 -143
  66. package/dist/utils/RetryManager.d.ts +0 -78
  67. package/dist/utils/RetryManager.js +0 -205
@@ -1,88 +0,0 @@
1
- /**
2
- * Enhanced Configuration Manager for Yama
3
- * Handles configuration loading, validation, and merging from multiple sources
4
- */
5
- import { GuardianConfig } from "../types/index.js";
6
- export declare class ConfigManager {
7
- private config;
8
- private configPaths;
9
- /**
10
- * Default configuration
11
- */
12
- private static readonly DEFAULT_CONFIG;
13
- constructor();
14
- /**
15
- * Setup configuration file search paths
16
- */
17
- private setupConfigPaths;
18
- /**
19
- * Load configuration from files and environment
20
- */
21
- loadConfig(configPath?: string): Promise<GuardianConfig>;
22
- /**
23
- * Load configuration from a specific file
24
- */
25
- private loadConfigFile;
26
- /**
27
- * Apply provider-aware token limits using shared utility
28
- */
29
- private applyProviderTokenLimits;
30
- /**
31
- * Apply environment variable overrides
32
- */
33
- private applyEnvironmentOverrides;
34
- /**
35
- * Validate configuration
36
- */
37
- private validateConfig;
38
- /**
39
- * Merge two configuration objects deeply
40
- */
41
- private mergeConfigs;
42
- /**
43
- * Deep merge utility
44
- */
45
- private deepMerge;
46
- /**
47
- * Deep clone utility
48
- */
49
- private deepClone;
50
- /**
51
- * Get current configuration
52
- */
53
- getConfig(): GuardianConfig;
54
- /**
55
- * Create default configuration file
56
- */
57
- createDefaultConfig(outputPath?: string): Promise<string>;
58
- /**
59
- * Add helpful comments to configuration file
60
- */
61
- private addConfigComments;
62
- /**
63
- * Validate specific configuration section
64
- */
65
- validateSection(section: keyof GuardianConfig, config: any): boolean;
66
- private validateProviders;
67
- private validateFeatures;
68
- private validateCache;
69
- /**
70
- * Get configuration schema for validation
71
- */
72
- getSchema(): any;
73
- /**
74
- * Find the first available configuration file
75
- */
76
- private findConfigFile;
77
- /**
78
- * Watch configuration file for changes and reload automatically
79
- */
80
- watchConfig(callback?: (config: GuardianConfig) => void): () => void;
81
- /**
82
- * Enable hot-reload for configuration
83
- */
84
- enableHotReload(callback?: (config: GuardianConfig) => void): () => void;
85
- }
86
- export declare const configManager: ConfigManager;
87
- export declare function createConfigManager(): ConfigManager;
88
- //# sourceMappingURL=ConfigManager.d.ts.map
@@ -1,603 +0,0 @@
1
- /**
2
- * Enhanced Configuration Manager for Yama
3
- * Handles configuration loading, validation, and merging from multiple sources
4
- */
5
- import fs from "fs";
6
- import path from "path";
7
- import yaml from "yaml";
8
- import { homedir } from "os";
9
- import { ConfigurationError } from "../types/index.js";
10
- import { logger } from "./Logger.js";
11
- import { validateProviderTokenLimit } from "./ProviderLimits.js";
12
- export class ConfigManager {
13
- config = null;
14
- configPaths = [];
15
- /**
16
- * Default configuration
17
- */
18
- static DEFAULT_CONFIG = {
19
- providers: {
20
- ai: {
21
- provider: "auto",
22
- enableFallback: true,
23
- enableAnalytics: false,
24
- enableEvaluation: false,
25
- timeout: "10m",
26
- retryAttempts: 3,
27
- temperature: 0.3,
28
- maxTokens: 65000,
29
- },
30
- git: {
31
- platform: "bitbucket",
32
- credentials: {
33
- username: process.env.BITBUCKET_USERNAME || "",
34
- token: process.env.BITBUCKET_TOKEN || "",
35
- baseUrl: process.env.BITBUCKET_BASE_URL ||
36
- "https://your-bitbucket-server.com",
37
- },
38
- },
39
- },
40
- features: {
41
- codeReview: {
42
- enabled: true,
43
- severityLevels: ["CRITICAL", "MAJOR", "MINOR", "SUGGESTION"],
44
- categories: [
45
- "security",
46
- "performance",
47
- "maintainability",
48
- "functionality",
49
- "error_handling",
50
- "testing",
51
- ],
52
- excludePatterns: ["*.lock", "*.svg", "*.min.js", "*.map"],
53
- contextLines: 3,
54
- systemPrompt: "You are an Expert Security Code Reviewer for enterprise applications. Your role is to:\n\n🔒 SECURITY FIRST: Prioritize security vulnerabilities and data protection\n⚡ PERFORMANCE AWARE: Identify performance bottlenecks and optimization opportunities\n🏗️ QUALITY FOCUSED: Ensure maintainable, readable, and robust code\n🛡️ ERROR RESILIENT: Verify comprehensive error handling and edge cases\n\nYou provide actionable, educational feedback with specific examples and solutions.\nFocus on critical issues that could impact production systems.",
55
- focusAreas: [
56
- "🔒 Security Analysis (CRITICAL PRIORITY)",
57
- "⚡ Performance Review",
58
- "🏗️ Code Quality",
59
- "🧪 Testing & Error Handling",
60
- ],
61
- },
62
- descriptionEnhancement: {
63
- enabled: true,
64
- preserveContent: true,
65
- requiredSections: [
66
- {
67
- key: "changelog",
68
- name: "Changelog (Modules Modified)",
69
- required: true,
70
- },
71
- {
72
- key: "testcases",
73
- name: "Test Cases (What to be tested)",
74
- required: true,
75
- },
76
- {
77
- key: "config_changes",
78
- name: "CAC Config Or Service Config Changes",
79
- required: true,
80
- },
81
- ],
82
- autoFormat: true,
83
- systemPrompt: "You are an Expert Technical Writer specializing in pull request documentation. Your role is to:\n\n📝 CLARITY FIRST: Create clear, comprehensive PR descriptions that help reviewers understand the changes\n🎥 STORY TELLING: Explain the 'why' behind changes, not just the 'what'\n📈 STRUCTURED: Follow consistent formatting with required sections\n🔗 CONTEXTUAL: Link changes to business value and technical rationale\n\nCRITICAL INSTRUCTION: Return ONLY the enhanced PR description content as clean markdown. Do NOT include any meta-commentary, explanations about what you're doing, or introductory text like \"I will enhance...\" or \"Here is the enhanced description:\". \n\nOutput the enhanced description directly without any wrapper text or explanations.",
84
- outputTemplate: "# PR Title Enhancement (if needed)\n\n## Summary\n[Clear overview of what this PR accomplishes]\n\n## Changes Made\n[Specific technical changes - be precise]\n\n## Testing\n[How the changes were tested]\n\n## Impact\n[Business/technical impact and considerations]\n\n## Additional Notes\n[Any deployment notes, follow-ups, or special considerations]",
85
- enhancementInstructions: 'Return ONLY the enhanced PR description as clean markdown. Do NOT include any explanatory text, meta-commentary, or phrases like "Here is the enhanced description:" or "I will enhance...".\n\nStart directly with the enhanced description content using this structure:',
86
- },
87
- securityScan: {
88
- enabled: true,
89
- level: "strict",
90
- scanTypes: ["secrets", "vulnerabilities", "dependencies"],
91
- },
92
- analytics: {
93
- enabled: true,
94
- trackMetrics: true,
95
- exportFormat: "json",
96
- },
97
- },
98
- cache: {
99
- enabled: true,
100
- ttl: "1h",
101
- maxSize: "100MB",
102
- storage: "memory",
103
- },
104
- performance: {
105
- batch: {
106
- enabled: true,
107
- maxConcurrent: 5,
108
- delayBetween: "1s",
109
- },
110
- optimization: {
111
- reuseConnections: true,
112
- compressRequests: true,
113
- enableHttp2: true,
114
- },
115
- },
116
- rules: {
117
- security: [
118
- {
119
- name: "No hardcoded secrets",
120
- pattern: "(password|secret|key|token)\\s*[=:]\\s*['\"][^'\"]{8,}['\"]",
121
- severity: "CRITICAL",
122
- message: "Hardcoded secrets detected",
123
- suggestion: "Use environment variables or secure configuration management",
124
- },
125
- ],
126
- performance: [
127
- {
128
- name: "Avoid N+1 queries",
129
- pattern: "for.*\\.(find|get|query|select)",
130
- severity: "MAJOR",
131
- message: "Potential N+1 query pattern detected",
132
- suggestion: "Consider using batch queries or joins",
133
- },
134
- ],
135
- },
136
- reporting: {
137
- formats: ["markdown", "json"],
138
- includeAnalytics: true,
139
- includeMetrics: true,
140
- },
141
- monitoring: {
142
- enabled: true,
143
- metrics: ["performance", "cache", "api_calls"],
144
- exportFormat: "json",
145
- interval: "5m",
146
- },
147
- memoryBank: {
148
- enabled: true,
149
- path: "memory-bank",
150
- fallbackPaths: ["docs/memory-bank", ".memory-bank"],
151
- },
152
- };
153
- constructor() {
154
- this.setupConfigPaths();
155
- }
156
- /**
157
- * Setup configuration file search paths
158
- */
159
- setupConfigPaths() {
160
- const cwd = process.cwd();
161
- const homeDir = homedir();
162
- this.configPaths = [
163
- path.join(cwd, "yama.config.yaml"),
164
- path.join(cwd, "yama.config.yml"),
165
- path.join(cwd, "yama.config.json"),
166
- path.join(cwd, ".yama.yaml"),
167
- path.join(cwd, ".yama.yml"),
168
- path.join(cwd, ".yama.json"),
169
- path.join(homeDir, ".yama", "config.yaml"),
170
- path.join(homeDir, ".yama", "config.yml"),
171
- path.join(homeDir, ".yama", "config.json"),
172
- path.join(homeDir, ".config", "yama", "config.yaml"),
173
- path.join(homeDir, ".config", "yama", "config.yml"),
174
- path.join(homeDir, ".config", "yama", "config.json"),
175
- ];
176
- }
177
- /**
178
- * Load configuration from files and environment
179
- */
180
- async loadConfig(configPath) {
181
- if (this.config) {
182
- return this.config;
183
- }
184
- logger.debug("Loading Yama configuration...");
185
- // Start with default config
186
- let config = this.deepClone(ConfigManager.DEFAULT_CONFIG);
187
- // If specific config path provided, use only that
188
- if (configPath) {
189
- if (!fs.existsSync(configPath)) {
190
- throw new ConfigurationError(`Configuration file not found: ${configPath}`);
191
- }
192
- const fileConfig = await this.loadConfigFile(configPath);
193
- config = this.mergeConfigs(config, fileConfig);
194
- logger.debug(`Loaded configuration from: ${configPath}`);
195
- }
196
- else {
197
- // Search for config files in predefined paths
198
- for (const configFilePath of this.configPaths) {
199
- if (fs.existsSync(configFilePath)) {
200
- try {
201
- const fileConfig = await this.loadConfigFile(configFilePath);
202
- config = this.mergeConfigs(config, fileConfig);
203
- logger.debug(`Loaded configuration from: ${configFilePath}`);
204
- break;
205
- }
206
- catch (error) {
207
- logger.warn(`Failed to load config from ${configFilePath}:`, error);
208
- }
209
- }
210
- }
211
- }
212
- // Override with environment variables
213
- config = this.applyEnvironmentOverrides(config);
214
- // Apply provider-aware token limits
215
- config = this.applyProviderTokenLimits(config);
216
- // Validate configuration
217
- this.validateConfig(config);
218
- this.config = config;
219
- logger.debug("Configuration loaded successfully");
220
- return config;
221
- }
222
- /**
223
- * Load configuration from a specific file
224
- */
225
- async loadConfigFile(filePath) {
226
- try {
227
- const content = fs.readFileSync(filePath, "utf8");
228
- const ext = path.extname(filePath).toLowerCase();
229
- switch (ext) {
230
- case ".yaml":
231
- case ".yml":
232
- return yaml.parse(content);
233
- case ".json":
234
- return JSON.parse(content);
235
- default:
236
- throw new ConfigurationError(`Unsupported config file format: ${ext}`);
237
- }
238
- }
239
- catch (error) {
240
- throw new ConfigurationError(`Failed to parse config file ${filePath}: ${error.message}`);
241
- }
242
- }
243
- /**
244
- * Apply provider-aware token limits using shared utility
245
- */
246
- applyProviderTokenLimits(config) {
247
- const provider = config.providers.ai.provider || 'auto';
248
- const configuredTokens = config.providers.ai.maxTokens;
249
- // Use the shared utility to validate and adjust token limits
250
- const validatedTokens = validateProviderTokenLimit(provider, configuredTokens, false // Use standard limits for configuration
251
- );
252
- config.providers.ai.maxTokens = validatedTokens;
253
- return config;
254
- }
255
- /**
256
- * Apply environment variable overrides
257
- */
258
- applyEnvironmentOverrides(config) {
259
- const env = process.env;
260
- // AI Provider overrides
261
- if (env.AI_PROVIDER) {
262
- config.providers.ai.provider = env.AI_PROVIDER;
263
- }
264
- if (env.AI_MODEL) {
265
- config.providers.ai.model = env.AI_MODEL;
266
- }
267
- if (env.AI_TIMEOUT) {
268
- config.providers.ai.timeout = env.AI_TIMEOUT;
269
- }
270
- if (env.AI_TEMPERATURE) {
271
- config.providers.ai.temperature = parseFloat(env.AI_TEMPERATURE);
272
- }
273
- if (env.AI_MAX_TOKENS) {
274
- config.providers.ai.maxTokens = parseInt(env.AI_MAX_TOKENS);
275
- }
276
- // Git Provider overrides
277
- if (env.BITBUCKET_USERNAME) {
278
- config.providers.git.credentials.username = env.BITBUCKET_USERNAME;
279
- }
280
- if (env.BITBUCKET_TOKEN) {
281
- config.providers.git.credentials.token = env.BITBUCKET_TOKEN;
282
- }
283
- if (env.BITBUCKET_BASE_URL) {
284
- config.providers.git.credentials.baseUrl = env.BITBUCKET_BASE_URL;
285
- }
286
- // Feature toggles
287
- if (env.ENABLE_CODE_REVIEW !== undefined) {
288
- config.features.codeReview.enabled = env.ENABLE_CODE_REVIEW === "true";
289
- }
290
- if (env.ENABLE_DESCRIPTION_ENHANCEMENT !== undefined) {
291
- config.features.descriptionEnhancement.enabled =
292
- env.ENABLE_DESCRIPTION_ENHANCEMENT === "true";
293
- }
294
- if (env.ENABLE_SECURITY_SCAN !== undefined) {
295
- config.features.securityScan.enabled =
296
- env.ENABLE_SECURITY_SCAN === "true";
297
- }
298
- if (env.ENABLE_ANALYTICS !== undefined) {
299
- config.features.analytics.enabled = env.ENABLE_ANALYTICS === "true";
300
- }
301
- // Cache configuration
302
- if (env.CACHE_ENABLED !== undefined) {
303
- config.cache.enabled = env.CACHE_ENABLED === "true";
304
- }
305
- if (env.CACHE_TTL) {
306
- config.cache.ttl = env.CACHE_TTL;
307
- }
308
- if (env.CACHE_STORAGE) {
309
- config.cache.storage = env.CACHE_STORAGE;
310
- }
311
- // Debug mode
312
- if (env.GUARDIAN_DEBUG === "true") {
313
- logger.setLevel("debug");
314
- logger.setVerbose(true);
315
- }
316
- logger.debug("Applied environment variable overrides");
317
- return config;
318
- }
319
- /**
320
- * Validate configuration
321
- */
322
- validateConfig(config) {
323
- const errors = [];
324
- // Validate AI provider credentials
325
- if (!config.providers.ai.provider) {
326
- errors.push("AI provider must be specified");
327
- }
328
- // Validate Git provider credentials
329
- if (!config.providers.git.credentials.username) {
330
- errors.push("Git username must be specified");
331
- }
332
- if (!config.providers.git.credentials.token) {
333
- errors.push("Git token must be specified");
334
- }
335
- // Validate enabled features have required configuration
336
- if (config.features.codeReview.enabled) {
337
- if (!config.features.codeReview.severityLevels?.length) {
338
- errors.push("Code review severity levels must be specified when enabled");
339
- }
340
- }
341
- if (config.features.descriptionEnhancement.enabled) {
342
- if (!config.features.descriptionEnhancement.requiredSections?.length) {
343
- errors.push("Description enhancement required sections must be specified when enabled");
344
- }
345
- }
346
- // Validate cache configuration
347
- if (config.cache?.enabled) {
348
- if (!config.cache.storage) {
349
- errors.push("Cache storage type must be specified when cache is enabled");
350
- }
351
- }
352
- if (errors.length > 0) {
353
- throw new ConfigurationError(`Configuration validation failed:\n${errors.map((e) => ` - ${e}`).join("\n")}`);
354
- }
355
- logger.debug("Configuration validation passed");
356
- }
357
- /**
358
- * Merge two configuration objects deeply
359
- */
360
- mergeConfigs(base, override) {
361
- return this.deepMerge(base, override);
362
- }
363
- /**
364
- * Deep merge utility
365
- */
366
- deepMerge(target, source) {
367
- const result = { ...target };
368
- for (const key in source) {
369
- if (source[key] !== null &&
370
- typeof source[key] === "object" &&
371
- !Array.isArray(source[key])) {
372
- result[key] = this.deepMerge(target[key] || {}, source[key]);
373
- }
374
- else {
375
- result[key] = source[key];
376
- }
377
- }
378
- return result;
379
- }
380
- /**
381
- * Deep clone utility
382
- */
383
- deepClone(obj) {
384
- return JSON.parse(JSON.stringify(obj));
385
- }
386
- /**
387
- * Get current configuration
388
- */
389
- getConfig() {
390
- if (!this.config) {
391
- throw new ConfigurationError("Configuration not loaded. Call loadConfig() first.");
392
- }
393
- return this.config;
394
- }
395
- /**
396
- * Create default configuration file
397
- */
398
- async createDefaultConfig(outputPath) {
399
- const defaultPath = outputPath || path.join(process.cwd(), "yama.config.yaml");
400
- const configContent = yaml.stringify(ConfigManager.DEFAULT_CONFIG, {
401
- indent: 2,
402
- lineWidth: 100,
403
- });
404
- // Add comments to make the config file more user-friendly
405
- const commentedConfig = this.addConfigComments(configContent);
406
- fs.writeFileSync(defaultPath, commentedConfig, "utf8");
407
- logger.info(`Default configuration created at: ${defaultPath}`);
408
- return defaultPath;
409
- }
410
- /**
411
- * Add helpful comments to configuration file
412
- */
413
- addConfigComments(content) {
414
- const header = `# Yama Configuration
415
- # This file configures all aspects of Yama behavior
416
- # For more information, visit: https://github.com/juspay/yama
417
-
418
- `;
419
- const sections = [
420
- "# AI Provider Configuration",
421
- "# Git Platform Configuration",
422
- "# Feature Configuration",
423
- "# Cache Configuration",
424
- "# Performance Configuration",
425
- "# Custom Rules Configuration",
426
- "# Reporting Configuration",
427
- ];
428
- let commented = header + content;
429
- // Add section comments (this is a simplified approach)
430
- sections.forEach((section) => {
431
- const key = section.split(" ")[1].toLowerCase();
432
- commented = commented.replace(new RegExp(`^(${key}:)`, "m"), `${section}\n$1`);
433
- });
434
- return commented;
435
- }
436
- /**
437
- * Validate specific configuration section
438
- */
439
- validateSection(section, config) {
440
- try {
441
- switch (section) {
442
- case "providers":
443
- return this.validateProviders(config);
444
- case "features":
445
- return this.validateFeatures(config);
446
- case "cache":
447
- return this.validateCache(config);
448
- default:
449
- return true;
450
- }
451
- }
452
- catch (error) {
453
- logger.error(`Validation failed for section ${String(section)}:`, error);
454
- return false;
455
- }
456
- }
457
- validateProviders(providers) {
458
- return !!(providers?.ai?.provider &&
459
- providers?.git?.credentials?.username &&
460
- providers?.git?.credentials?.token);
461
- }
462
- validateFeatures(features) {
463
- return !!(features && typeof features === "object");
464
- }
465
- validateCache(cacheConfig) {
466
- if (!cacheConfig?.enabled) {
467
- return true;
468
- }
469
- return !!(cacheConfig.storage && cacheConfig.ttl);
470
- }
471
- /**
472
- * Get configuration schema for validation
473
- */
474
- getSchema() {
475
- return {
476
- type: "object",
477
- required: ["providers", "features"],
478
- properties: {
479
- providers: {
480
- type: "object",
481
- required: ["ai", "git"],
482
- properties: {
483
- ai: {
484
- type: "object",
485
- required: ["provider"],
486
- properties: {
487
- provider: { type: "string" },
488
- model: { type: "string" },
489
- enableFallback: { type: "boolean" },
490
- enableAnalytics: { type: "boolean" },
491
- timeout: { type: ["string", "number"] },
492
- temperature: { type: "number", minimum: 0, maximum: 2 },
493
- maxTokens: { type: "number", minimum: 1 },
494
- },
495
- },
496
- git: {
497
- type: "object",
498
- required: ["platform", "credentials"],
499
- properties: {
500
- platform: {
501
- type: "string",
502
- enum: ["bitbucket", "github", "gitlab", "azure-devops"],
503
- },
504
- credentials: {
505
- type: "object",
506
- required: ["username", "token"],
507
- properties: {
508
- username: { type: "string" },
509
- token: { type: "string" },
510
- baseUrl: { type: "string" },
511
- },
512
- },
513
- },
514
- },
515
- },
516
- },
517
- features: {
518
- type: "object",
519
- required: ["codeReview", "descriptionEnhancement"],
520
- properties: {
521
- codeReview: {
522
- type: "object",
523
- required: ["enabled"],
524
- properties: {
525
- enabled: { type: "boolean" },
526
- severityLevels: { type: "array", items: { type: "string" } },
527
- categories: { type: "array", items: { type: "string" } },
528
- excludePatterns: { type: "array", items: { type: "string" } },
529
- },
530
- },
531
- descriptionEnhancement: {
532
- type: "object",
533
- required: ["enabled"],
534
- properties: {
535
- enabled: { type: "boolean" },
536
- preserveContent: { type: "boolean" },
537
- requiredSections: { type: "array" },
538
- autoFormat: { type: "boolean" },
539
- },
540
- },
541
- },
542
- },
543
- },
544
- };
545
- }
546
- /**
547
- * Find the first available configuration file
548
- */
549
- findConfigFile() {
550
- for (const configPath of this.configPaths) {
551
- if (fs.existsSync(configPath)) {
552
- return configPath;
553
- }
554
- }
555
- return null;
556
- }
557
- /**
558
- * Watch configuration file for changes and reload automatically
559
- */
560
- watchConfig(callback) {
561
- if (!this.configPaths.length) {
562
- logger.warn("No configuration file found to watch");
563
- return () => { };
564
- }
565
- const configPath = this.findConfigFile();
566
- if (!configPath) {
567
- logger.warn("No configuration file found to watch");
568
- return () => { };
569
- }
570
- logger.debug(`Watching configuration file: ${configPath}`);
571
- fs.watchFile(configPath, { interval: 1000 }, async () => {
572
- try {
573
- logger.info("Configuration file changed, reloading...");
574
- const newConfig = await this.loadConfig();
575
- if (callback) {
576
- callback(newConfig);
577
- }
578
- logger.success("Configuration reloaded successfully");
579
- }
580
- catch (error) {
581
- logger.error(`Failed to reload configuration: ${error.message}`);
582
- }
583
- });
584
- // Return cleanup function
585
- return () => {
586
- fs.unwatchFile(configPath);
587
- logger.debug("Stopped watching configuration file");
588
- };
589
- }
590
- /**
591
- * Enable hot-reload for configuration
592
- */
593
- enableHotReload(callback) {
594
- return this.watchConfig(callback);
595
- }
596
- }
597
- // Export singleton instance
598
- export const configManager = new ConfigManager();
599
- // Export factory function
600
- export function createConfigManager() {
601
- return new ConfigManager();
602
- }
603
- //# sourceMappingURL=ConfigManager.js.map