@juspay/yama 1.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.
@@ -0,0 +1,255 @@
1
+ "use strict";
2
+ /**
3
+ * Enhanced Cache utility for Yama
4
+ * Provides intelligent caching for PR data, file contents, and AI responses
5
+ */
6
+ var __importDefault = (this && this.__importDefault) || function (mod) {
7
+ return (mod && mod.__esModule) ? mod : { "default": mod };
8
+ };
9
+ Object.defineProperty(exports, "__esModule", { value: true });
10
+ exports.cache = exports.Cache = void 0;
11
+ exports.createCache = createCache;
12
+ const node_cache_1 = __importDefault(require("node-cache"));
13
+ const Logger_1 = require("./Logger");
14
+ class Cache {
15
+ constructor(options = {}) {
16
+ this.statsData = {
17
+ hits: 0,
18
+ misses: 0,
19
+ };
20
+ /**
21
+ * Cache with tags for group invalidation
22
+ */
23
+ this.tags = new Map();
24
+ const { ttl = 3600, // 1 hour default
25
+ maxSize = 100, // 100 keys max
26
+ checkPeriod = 600, // Check every 10 minutes
27
+ } = options;
28
+ this.cache = new node_cache_1.default({
29
+ stdTTL: ttl,
30
+ maxKeys: maxSize,
31
+ checkperiod: checkPeriod,
32
+ useClones: false,
33
+ deleteOnExpire: true,
34
+ });
35
+ this.cache.on("set", (key, _value) => {
36
+ Logger_1.logger.debug(`Cache SET: ${key}`);
37
+ });
38
+ this.cache.on("expired", (key, _value) => {
39
+ Logger_1.logger.debug(`Cache EXPIRED: ${key}`);
40
+ });
41
+ this.cache.on("del", (key, _value) => {
42
+ Logger_1.logger.debug(`Cache DELETE: ${key}`);
43
+ });
44
+ }
45
+ /**
46
+ * Get value from cache
47
+ */
48
+ get(key) {
49
+ const value = this.cache.get(key);
50
+ if (value !== undefined) {
51
+ this.statsData.hits++;
52
+ Logger_1.logger.debug(`Cache HIT: ${key}`);
53
+ return value;
54
+ }
55
+ else {
56
+ this.statsData.misses++;
57
+ Logger_1.logger.debug(`Cache MISS: ${key}`);
58
+ return undefined;
59
+ }
60
+ }
61
+ /**
62
+ * Set value in cache with optional TTL
63
+ */
64
+ set(key, value, ttl) {
65
+ try {
66
+ const success = this.cache.set(key, value, ttl || 0);
67
+ if (success) {
68
+ Logger_1.logger.debug(`Cache SET successful: ${key}`);
69
+ }
70
+ else {
71
+ Logger_1.logger.warn(`Cache SET failed: ${key}`);
72
+ }
73
+ return success;
74
+ }
75
+ catch (error) {
76
+ Logger_1.logger.error(`Cache SET error: ${key}`, error);
77
+ return false;
78
+ }
79
+ }
80
+ /**
81
+ * Delete key from cache
82
+ */
83
+ del(key) {
84
+ const deleted = this.cache.del(key);
85
+ Logger_1.logger.debug(`Cache DELETE: ${key}, deleted: ${deleted}`);
86
+ return deleted;
87
+ }
88
+ /**
89
+ * Check if key exists in cache
90
+ */
91
+ has(key) {
92
+ return this.cache.has(key);
93
+ }
94
+ /**
95
+ * Clear all cache entries
96
+ */
97
+ clear() {
98
+ this.cache.flushAll();
99
+ this.statsData.hits = 0;
100
+ this.statsData.misses = 0;
101
+ Logger_1.logger.debug("Cache cleared");
102
+ }
103
+ /**
104
+ * Get all cache keys
105
+ */
106
+ keys() {
107
+ return this.cache.keys();
108
+ }
109
+ /**
110
+ * Get cache statistics
111
+ */
112
+ stats() {
113
+ return {
114
+ hits: this.statsData.hits,
115
+ misses: this.statsData.misses,
116
+ keys: this.cache.keys().length,
117
+ size: this.cache.getStats().keys,
118
+ };
119
+ }
120
+ /**
121
+ * Get detailed cache statistics from node-cache
122
+ */
123
+ getDetailedStats() {
124
+ return this.cache.getStats();
125
+ }
126
+ /**
127
+ * Get or set pattern - common caching pattern
128
+ */
129
+ async getOrSet(key, fetchFn, ttl) {
130
+ const cached = this.get(key);
131
+ if (cached !== undefined) {
132
+ return cached;
133
+ }
134
+ try {
135
+ Logger_1.logger.debug(`Cache FETCH: ${key}`);
136
+ const value = await fetchFn();
137
+ this.set(key, value, ttl);
138
+ return value;
139
+ }
140
+ catch (error) {
141
+ Logger_1.logger.error(`Cache FETCH error: ${key}`, error);
142
+ throw error;
143
+ }
144
+ }
145
+ setWithTags(key, value, tags, ttl) {
146
+ const success = this.set(key, value, ttl);
147
+ if (success) {
148
+ // Associate key with tags
149
+ tags.forEach((tag) => {
150
+ if (!this.tags.has(tag)) {
151
+ this.tags.set(tag, new Set());
152
+ }
153
+ this.tags.get(tag).add(key);
154
+ });
155
+ }
156
+ return success;
157
+ }
158
+ /**
159
+ * Invalidate all keys with a specific tag
160
+ */
161
+ invalidateTag(tag) {
162
+ const keys = this.tags.get(tag);
163
+ if (!keys) {
164
+ return 0;
165
+ }
166
+ let deleted = 0;
167
+ keys.forEach((key) => {
168
+ deleted += this.del(key);
169
+ });
170
+ // Clean up tag associations
171
+ this.tags.delete(tag);
172
+ Logger_1.logger.debug(`Invalidated tag "${tag}": ${deleted} keys`);
173
+ return deleted;
174
+ }
175
+ /**
176
+ * Smart cache warming for common patterns
177
+ */
178
+ async warmPRCache(workspace, repository, prId) {
179
+ Logger_1.logger.debug(`Warming cache for PR ${workspace}/${repository}#${prId}`);
180
+ // Pre-generate cache keys that are likely to be needed
181
+ const keys = [
182
+ Cache.keys.prInfo(workspace, repository, prId),
183
+ Cache.keys.prDiff(workspace, repository, prId),
184
+ ];
185
+ // This would be implemented by the calling code to actually fetch the data
186
+ Logger_1.logger.debug(`Cache warming prepared for keys: ${keys.join(", ")}`);
187
+ }
188
+ /**
189
+ * Cleanup expired entries and optimize memory
190
+ */
191
+ cleanup() {
192
+ // Node-cache handles TTL cleanup automatically, but we can force it
193
+ const beforeKeys = this.cache.keys().length;
194
+ // Force check for expired keys
195
+ this.cache.keys().forEach((key) => {
196
+ this.cache.get(key); // This triggers expiry check
197
+ });
198
+ const afterKeys = this.cache.keys().length;
199
+ const cleaned = beforeKeys - afterKeys;
200
+ if (cleaned > 0) {
201
+ Logger_1.logger.debug(`Cache cleanup: removed ${cleaned} expired entries`);
202
+ }
203
+ // Clean up tag associations for deleted keys
204
+ this.tags.forEach((keys, tag) => {
205
+ const validKeys = new Set([...keys].filter((key) => this.cache.has(key)));
206
+ if (validKeys.size !== keys.size) {
207
+ this.tags.set(tag, validKeys);
208
+ }
209
+ });
210
+ }
211
+ /**
212
+ * Get cache hit ratio
213
+ */
214
+ getHitRatio() {
215
+ const total = this.statsData.hits + this.statsData.misses;
216
+ return total > 0 ? this.statsData.hits / total : 0;
217
+ }
218
+ /**
219
+ * Export cache state for debugging
220
+ */
221
+ debug() {
222
+ return {
223
+ stats: this.stats(),
224
+ hitRatio: this.getHitRatio(),
225
+ detailedStats: this.getDetailedStats(),
226
+ keys: this.keys(),
227
+ tags: Object.fromEntries(this.tags.entries()),
228
+ };
229
+ }
230
+ }
231
+ exports.Cache = Cache;
232
+ /**
233
+ * Cache key generators for common patterns
234
+ */
235
+ Cache.keys = {
236
+ prInfo: (workspace, repository, prId) => `pr:${workspace}:${repository}:${prId}`,
237
+ prDiff: (workspace, repository, prId) => `diff:${workspace}:${repository}:${prId}`,
238
+ fileContent: (workspace, repository, filePath, branch) => `file:${workspace}:${repository}:${branch}:${filePath}`,
239
+ directoryContent: (workspace, repository, path, branch) => `dir:${workspace}:${repository}:${branch}:${path}`,
240
+ branchInfo: (workspace, repository, branch) => `branch:${workspace}:${repository}:${branch}`,
241
+ aiResponse: (prompt, provider, model) => {
242
+ // Create a hash of the prompt for consistent keys
243
+ const hash = Buffer.from(prompt).toString("base64").slice(0, 16);
244
+ return `ai:${provider}:${model}:${hash}`;
245
+ },
246
+ projectContext: (workspace, repository, branch) => `context:${workspace}:${repository}:${branch}`,
247
+ reviewResult: (workspace, repository, prId, configHash) => `review:${workspace}:${repository}:${prId}:${configHash}`,
248
+ };
249
+ // Export singleton instance
250
+ exports.cache = new Cache();
251
+ // Export factory function
252
+ function createCache(options) {
253
+ return new Cache(options);
254
+ }
255
+ //# sourceMappingURL=Cache.js.map
@@ -0,0 +1,84 @@
1
+ /**
2
+ * Enhanced Configuration Manager for Yama
3
+ * Handles configuration loading, validation, and merging from multiple sources
4
+ */
5
+ import { GuardianConfig } from "../types";
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 environment variable overrides
28
+ */
29
+ private applyEnvironmentOverrides;
30
+ /**
31
+ * Validate configuration
32
+ */
33
+ private validateConfig;
34
+ /**
35
+ * Merge two configuration objects deeply
36
+ */
37
+ private mergeConfigs;
38
+ /**
39
+ * Deep merge utility
40
+ */
41
+ private deepMerge;
42
+ /**
43
+ * Deep clone utility
44
+ */
45
+ private deepClone;
46
+ /**
47
+ * Get current configuration
48
+ */
49
+ getConfig(): GuardianConfig;
50
+ /**
51
+ * Create default configuration file
52
+ */
53
+ createDefaultConfig(outputPath?: string): Promise<string>;
54
+ /**
55
+ * Add helpful comments to configuration file
56
+ */
57
+ private addConfigComments;
58
+ /**
59
+ * Validate specific configuration section
60
+ */
61
+ validateSection(section: keyof GuardianConfig, config: any): boolean;
62
+ private validateProviders;
63
+ private validateFeatures;
64
+ private validateCache;
65
+ /**
66
+ * Get configuration schema for validation
67
+ */
68
+ getSchema(): any;
69
+ /**
70
+ * Find the first available configuration file
71
+ */
72
+ private findConfigFile;
73
+ /**
74
+ * Watch configuration file for changes and reload automatically
75
+ */
76
+ watchConfig(callback?: (config: GuardianConfig) => void): () => void;
77
+ /**
78
+ * Enable hot-reload for configuration
79
+ */
80
+ enableHotReload(callback?: (config: GuardianConfig) => void): () => void;
81
+ }
82
+ export declare const configManager: ConfigManager;
83
+ export declare function createConfigManager(): ConfigManager;
84
+ //# sourceMappingURL=ConfigManager.d.ts.map