@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,474 +0,0 @@
1
- /**
2
- * Yama - Unified orchestrator class
3
- * The main class that coordinates all operations using shared context
4
- */
5
- import { GuardianError, } from "../types/index.js";
6
- import { BitbucketProvider } from "./providers/BitbucketProvider.js";
7
- import { ContextGatherer } from "./ContextGatherer.js";
8
- import { CodeReviewer } from "../features/CodeReviewer.js";
9
- import { DescriptionEnhancer } from "../features/DescriptionEnhancer.js";
10
- import { logger, createLogger } from "../utils/Logger.js";
11
- import { configManager } from "../utils/ConfigManager.js";
12
- import { cache } from "../utils/Cache.js";
13
- export class Guardian {
14
- config;
15
- bitbucketProvider;
16
- contextGatherer;
17
- codeReviewer;
18
- descriptionEnhancer;
19
- neurolink;
20
- initialized = false;
21
- logger = logger; // Default logger, will be updated after config load
22
- constructor(config) {
23
- this.config = {};
24
- if (config) {
25
- this.config = { ...this.config, ...config };
26
- }
27
- }
28
- /**
29
- * Initialize Guardian with configuration
30
- */
31
- async initialize(configPath) {
32
- if (this.initialized) {
33
- return;
34
- }
35
- try {
36
- // Load configuration first
37
- const loaded = await configManager.loadConfig(configPath);
38
- // Loaded file first, then in-memory overrides last
39
- this.config = { ...loaded, ...this.config };
40
- // Create logger with banner configuration if needed
41
- const showBanner = this.config.display?.showBanner ?? true;
42
- if (showBanner !== true) {
43
- // Only create a new logger if we need to change the banner setting
44
- this.logger = createLogger(logger.getConfig(), showBanner);
45
- }
46
- // Otherwise, keep using the default logger
47
- this.logger.badge();
48
- this.logger.phase("🚀 Initializing Yama...");
49
- // Initialize providers
50
- this.bitbucketProvider = new BitbucketProvider(this.config.providers.git.credentials);
51
- await this.bitbucketProvider.initialize();
52
- // Initialize NeuroLink with native ESM dynamic import
53
- const { NeuroLink } = await import("@juspay/neurolink");
54
- this.neurolink = new NeuroLink();
55
- // Initialize core components
56
- this.contextGatherer = new ContextGatherer(this.bitbucketProvider, this.config.providers.ai, this.config.memoryBank || {
57
- enabled: true,
58
- path: "memory-bank",
59
- fallbackPaths: ["docs/memory-bank", ".memory-bank"],
60
- });
61
- this.codeReviewer = new CodeReviewer(this.bitbucketProvider, this.config.providers.ai, this.config.features.codeReview);
62
- this.descriptionEnhancer = new DescriptionEnhancer(this.bitbucketProvider, this.config.providers.ai);
63
- this.initialized = true;
64
- logger.success("✅ Yama initialized successfully");
65
- }
66
- catch (error) {
67
- logger.error(`Failed to initialize Yama: ${error.message}`);
68
- throw new GuardianError("INITIALIZATION_ERROR", `Initialization failed: ${error.message}`);
69
- }
70
- }
71
- /**
72
- * Main method: Process PR with multiple operations using unified context
73
- */
74
- async processPR(options) {
75
- await this.ensureInitialized();
76
- const startTime = Date.now();
77
- const operations = [];
78
- try {
79
- logger.operation("PR Processing", "started");
80
- logger.info(`Target: ${options.workspace}/${options.repository}`);
81
- logger.info(`Operations: ${options.operations.join(", ")}`);
82
- logger.info(`Mode: ${options.dryRun ? "DRY RUN" : "LIVE"}`);
83
- // Step 1: Gather unified context ONCE for all operations
84
- logger.phase("📋 Gathering unified context...");
85
- const context = await this.gatherUnifiedContext(options);
86
- logger.success(`Context ready: PR #${context.pr.id} - "${context.pr.title}"`);
87
- logger.info(`Files: ${context.diffStrategy.fileCount}, Strategy: ${context.diffStrategy.strategy}`);
88
- // Step 2: Execute requested operations using shared context
89
- for (const operation of options.operations) {
90
- if (operation === "all") {
91
- // Execute all available operations
92
- operations.push(await this.executeOperation("review", context, options));
93
- operations.push(await this.executeOperation("enhance-description", context, options));
94
- }
95
- else {
96
- operations.push(await this.executeOperation(operation, context, options));
97
- }
98
- }
99
- const duration = Date.now() - startTime;
100
- const successCount = operations.filter((op) => op.status === "success").length;
101
- const errorCount = operations.filter((op) => op.status === "error").length;
102
- const skippedCount = operations.filter((op) => op.status === "skipped").length;
103
- const result = {
104
- pullRequest: context.pr,
105
- operations,
106
- summary: {
107
- totalOperations: operations.length,
108
- successCount,
109
- errorCount,
110
- skippedCount,
111
- totalDuration: duration,
112
- },
113
- };
114
- logger.operation("PR Processing", "completed");
115
- logger.success(`✅ Processing completed in ${Math.round(duration / 1000)}s: ` +
116
- `${successCount} success, ${errorCount} errors, ${skippedCount} skipped`);
117
- return result;
118
- }
119
- catch (error) {
120
- logger.operation("PR Processing", "failed");
121
- logger.error(`Processing failed: ${error.message}`);
122
- throw error;
123
- }
124
- }
125
- /**
126
- * Streaming version of processPR for real-time updates
127
- */
128
- async *processPRStream(options, _streamOptions) {
129
- await this.ensureInitialized();
130
- const startTime = Date.now();
131
- try {
132
- // Initial update
133
- yield {
134
- operation: "all",
135
- status: "started",
136
- message: "Yama processing initiated",
137
- timestamp: new Date().toISOString(),
138
- };
139
- // Context gathering phase
140
- yield {
141
- operation: "all",
142
- status: "progress",
143
- progress: 10,
144
- message: "Gathering unified context...",
145
- timestamp: new Date().toISOString(),
146
- };
147
- const context = await this.gatherUnifiedContext(options);
148
- yield {
149
- operation: "all",
150
- status: "progress",
151
- progress: 30,
152
- message: `Context ready: PR #${context.pr.id}`,
153
- data: { prId: context.pr.id, title: context.pr.title },
154
- timestamp: new Date().toISOString(),
155
- };
156
- // Execute operations with progress updates
157
- const totalOps = options.operations.length;
158
- let completedOps = 0;
159
- for (const operation of options.operations) {
160
- yield {
161
- operation,
162
- status: "started",
163
- message: `Starting ${operation}...`,
164
- timestamp: new Date().toISOString(),
165
- };
166
- try {
167
- const result = await this.executeOperation(operation, context, options);
168
- if (result.status === "error") {
169
- yield {
170
- operation,
171
- status: "error",
172
- message: `${operation} failed: ${result.error}`,
173
- timestamp: new Date().toISOString(),
174
- };
175
- }
176
- else {
177
- completedOps++;
178
- yield {
179
- operation,
180
- status: "completed",
181
- progress: 30 + Math.round((completedOps / totalOps) * 60),
182
- message: `${operation} completed`,
183
- data: result,
184
- timestamp: new Date().toISOString(),
185
- };
186
- }
187
- }
188
- catch (error) {
189
- // This catch is for unexpected errors that bypass executeOperation's own error handling
190
- yield {
191
- operation,
192
- status: "error",
193
- message: `${operation} failed: ${error.message}`,
194
- timestamp: new Date().toISOString(),
195
- };
196
- }
197
- }
198
- // Final completion
199
- const duration = Date.now() - startTime;
200
- yield {
201
- operation: "all",
202
- status: "completed",
203
- progress: 100,
204
- message: `Processing completed in ${Math.round(duration / 1000)}s`,
205
- timestamp: new Date().toISOString(),
206
- };
207
- }
208
- catch (error) {
209
- yield {
210
- operation: "all",
211
- status: "error",
212
- message: `Processing failed: ${error.message}`,
213
- timestamp: new Date().toISOString(),
214
- };
215
- }
216
- }
217
- /**
218
- * Gather unified context (cached and reusable)
219
- */
220
- async gatherUnifiedContext(options) {
221
- const identifier = {
222
- workspace: options.workspace,
223
- repository: options.repository,
224
- branch: options.branch,
225
- pullRequestId: options.pullRequestId,
226
- };
227
- // Check if we have cached context first
228
- const cachedContext = await this.contextGatherer.getCachedContext(identifier);
229
- if (cachedContext && options.config?.cache?.enabled !== false) {
230
- logger.debug("✓ Using cached context");
231
- return cachedContext;
232
- }
233
- // Determine what operations need diff data
234
- const needsDiff = options.operations.some((op) => op === "review" || op === "security-scan" || op === "all");
235
- const contextOptions = {
236
- excludePatterns: this.config.features.codeReview.excludePatterns,
237
- contextLines: this.config.features.codeReview.contextLines,
238
- forceRefresh: false,
239
- includeDiff: needsDiff,
240
- diffStrategyConfig: this.config.features.diffStrategy,
241
- };
242
- return await this.contextGatherer.gatherContext(identifier, contextOptions);
243
- }
244
- /**
245
- * Execute individual operation using shared context
246
- */
247
- async executeOperation(operation, context, options) {
248
- const startTime = Date.now();
249
- try {
250
- let data;
251
- switch (operation) {
252
- case "review":
253
- data = await this.executeCodeReview(context, options);
254
- break;
255
- case "enhance-description":
256
- data = await this.executeDescriptionEnhancement(context, options);
257
- break;
258
- case "security-scan":
259
- // TODO: Implement in future phases
260
- throw new Error("Security scan not implemented in Phase 1");
261
- case "analytics":
262
- // TODO: Implement in future phases
263
- throw new Error("Analytics not implemented in Phase 1");
264
- default:
265
- throw new Error(`Unknown operation: ${operation}`);
266
- }
267
- return {
268
- operation,
269
- status: "success",
270
- data,
271
- duration: Date.now() - startTime,
272
- timestamp: new Date().toISOString(),
273
- };
274
- }
275
- catch (error) {
276
- logger.error(`Operation ${operation} failed: ${error.message}`);
277
- return {
278
- operation,
279
- status: "error",
280
- error: error.message,
281
- duration: Date.now() - startTime,
282
- timestamp: new Date().toISOString(),
283
- };
284
- }
285
- }
286
- /**
287
- * Execute code review using shared context
288
- */
289
- async executeCodeReview(context, options) {
290
- if (!this.config.features.codeReview.enabled) {
291
- logger.info("Code review is disabled in configuration");
292
- return { skipped: true, reason: "disabled in config" };
293
- }
294
- const reviewOptions = {
295
- workspace: context.identifier.workspace,
296
- repository: context.identifier.repository,
297
- pullRequestId: context.identifier.pullRequestId,
298
- dryRun: options.dryRun,
299
- verbose: logger.getConfig().verbose,
300
- excludePatterns: this.config.features.codeReview.excludePatterns,
301
- contextLines: this.config.features.codeReview.contextLines,
302
- };
303
- logger.phase("🔍 Executing code review...");
304
- // Check if multi-instance processing is configured
305
- const multiInstanceConfig = this.config.features?.codeReview
306
- ?.multiInstance;
307
- // Use code review with multi-instance support
308
- return await this.codeReviewer.reviewCodeWithContext(context, reviewOptions, multiInstanceConfig);
309
- }
310
- /**
311
- * Execute description enhancement using shared context
312
- */
313
- async executeDescriptionEnhancement(context, options) {
314
- if (!this.config.features.descriptionEnhancement.enabled) {
315
- logger.info("Description enhancement is disabled in configuration");
316
- return { skipped: true, reason: "disabled in config" };
317
- }
318
- logger.phase("📝 Executing description enhancement...");
319
- const enhancementOptions = {
320
- workspace: context.identifier.workspace,
321
- repository: context.identifier.repository,
322
- pullRequestId: context.identifier.pullRequestId,
323
- dryRun: options.dryRun,
324
- verbose: logger.getConfig().verbose,
325
- preserveContent: this.config.features.descriptionEnhancement.preserveContent,
326
- ensureRequiredSections: true,
327
- customSections: this.config.features.descriptionEnhancement.requiredSections,
328
- };
329
- // Use the already gathered context instead of gathering again
330
- return await this.descriptionEnhancer.enhanceWithContext(context, enhancementOptions);
331
- }
332
- /**
333
- * Individual operation methods for backwards compatibility
334
- */
335
- /**
336
- * Code review operation (standalone)
337
- */
338
- async reviewCode(options) {
339
- await this.ensureInitialized();
340
- const identifier = {
341
- workspace: options.workspace,
342
- repository: options.repository,
343
- branch: options.branch,
344
- pullRequestId: options.pullRequestId,
345
- };
346
- logger.operation("Code Review", "started");
347
- try {
348
- // Gather context specifically for code review
349
- const context = await this.contextGatherer.gatherContext(identifier, {
350
- excludePatterns: options.excludePatterns,
351
- contextLines: options.contextLines,
352
- includeDiff: true,
353
- });
354
- const result = await this.codeReviewer.reviewCodeWithContext(context, options);
355
- logger.operation("Code Review", "completed");
356
- return result;
357
- }
358
- catch (error) {
359
- logger.operation("Code Review", "failed");
360
- throw error;
361
- }
362
- }
363
- /**
364
- * Description enhancement operation (standalone)
365
- */
366
- async enhanceDescription(options) {
367
- await this.ensureInitialized();
368
- const identifier = {
369
- workspace: options.workspace,
370
- repository: options.repository,
371
- branch: options.branch,
372
- pullRequestId: options.pullRequestId,
373
- };
374
- logger.operation("Description Enhancement", "started");
375
- try {
376
- // Gather context specifically for description enhancement
377
- const context = await this.contextGatherer.gatherContext(identifier, {
378
- includeDiff: true, // Description enhancement may need to see changes
379
- });
380
- const result = await this.descriptionEnhancer.enhanceWithContext(context, options);
381
- logger.operation("Description Enhancement", "completed");
382
- return result;
383
- }
384
- catch (error) {
385
- logger.operation("Description Enhancement", "failed");
386
- throw error;
387
- }
388
- }
389
- /**
390
- * Health check for all components
391
- */
392
- async healthCheck() {
393
- const components = {};
394
- try {
395
- // Check Bitbucket provider
396
- components.bitbucket = await this.bitbucketProvider.healthCheck();
397
- // Check cache
398
- components.cache = {
399
- healthy: true,
400
- stats: cache.stats(),
401
- };
402
- // Check NeuroLink (if initialized)
403
- components.neurolink = {
404
- healthy: true,
405
- initialized: !!this.neurolink,
406
- };
407
- const allHealthy = Object.values(components).every((comp) => comp.healthy);
408
- return {
409
- healthy: allHealthy,
410
- components,
411
- };
412
- }
413
- catch (error) {
414
- return {
415
- healthy: false,
416
- components: {
417
- ...components,
418
- error: error.message,
419
- },
420
- };
421
- }
422
- }
423
- /**
424
- * Get comprehensive statistics
425
- */
426
- getStats() {
427
- return {
428
- initialized: this.initialized,
429
- config: {
430
- features: Object.keys(this.config.features || {}),
431
- cacheEnabled: this.config.cache?.enabled,
432
- },
433
- providers: {
434
- bitbucket: this.bitbucketProvider?.getStats(),
435
- context: this.contextGatherer?.getStats(),
436
- },
437
- cache: cache.stats(),
438
- };
439
- }
440
- /**
441
- * Clear all caches
442
- */
443
- clearCache() {
444
- cache.clear();
445
- this.bitbucketProvider?.clearCache();
446
- logger.info("All caches cleared");
447
- }
448
- /**
449
- * Ensure Guardian is initialized
450
- */
451
- async ensureInitialized() {
452
- if (!this.initialized) {
453
- await this.initialize();
454
- }
455
- }
456
- /**
457
- * Shutdown Guardian gracefully
458
- */
459
- async shutdown() {
460
- logger.info("Shutting down Yama...");
461
- // Clear caches
462
- this.clearCache();
463
- // Reset state
464
- this.initialized = false;
465
- logger.success("Yama shutdown complete");
466
- }
467
- }
468
- // Export factory function
469
- export function createGuardian(config) {
470
- return new Guardian(config);
471
- }
472
- // Export default instance
473
- export const guardian = new Guardian();
474
- //# sourceMappingURL=Guardian.js.map
@@ -1,105 +0,0 @@
1
- /**
2
- * Enhanced Bitbucket Provider - Optimized from both pr-police.js and pr-describe.js
3
- * Provides unified, cached, and optimized Bitbucket operations
4
- */
5
- import { PRIdentifier, PRInfo, PRDiff, GitCredentials } from "../../types/index.js";
6
- export interface BitbucketMCPResponse {
7
- content?: Array<{
8
- text?: string;
9
- }>;
10
- message?: string;
11
- error?: string;
12
- }
13
- export declare class BitbucketProvider {
14
- private apiClient;
15
- private branchHandlers;
16
- private pullRequestHandlers;
17
- private reviewHandlers;
18
- private fileHandlers;
19
- private initialized;
20
- private baseUrl;
21
- private credentials;
22
- constructor(credentials: GitCredentials);
23
- /**
24
- * Initialize MCP handlers with lazy loading and connection reuse
25
- */
26
- initialize(): Promise<void>;
27
- /**
28
- * Parse MCP response - exactly matching the working pr-police.js implementation
29
- */
30
- private parseMCPResponse;
31
- /**
32
- * Find PR for branch with intelligent caching
33
- */
34
- findPRForBranch(identifier: PRIdentifier): Promise<PRInfo>;
35
- /**
36
- * Get PR details with enhanced caching
37
- */
38
- getPRDetails(identifier: PRIdentifier): Promise<PRInfo>;
39
- /**
40
- * Get PR diff with smart caching and filtering
41
- */
42
- getPRDiff(identifier: PRIdentifier, contextLines?: number, excludePatterns?: string[], includePatterns?: string[]): Promise<PRDiff>;
43
- /**
44
- * Get file content with caching
45
- */
46
- getFileContent(workspace: string, repository: string, filePath: string, branch: string): Promise<string>;
47
- /**
48
- * List directory content with caching
49
- */
50
- listDirectoryContent(workspace: string, repository: string, path: string, branch: string): Promise<any[]>;
51
- /**
52
- * Update PR description with reviewer preservation
53
- */
54
- updatePRDescription(identifier: PRIdentifier, description: string): Promise<{
55
- success: boolean;
56
- message: string;
57
- }>;
58
- /**
59
- * Add comment to PR with smart positioning and validation
60
- */
61
- addComment(identifier: PRIdentifier, commentText: string, options?: {
62
- filePath?: string;
63
- lineNumber?: number;
64
- lineType?: "ADDED" | "REMOVED" | "CONTEXT";
65
- codeSnippet?: string;
66
- searchContext?: {
67
- before: string[];
68
- after: string[];
69
- };
70
- matchStrategy?: "exact" | "best" | "strict";
71
- suggestion?: string;
72
- }): Promise<{
73
- success: boolean;
74
- commentId?: number;
75
- }>;
76
- /**
77
- * Batch operation support for multiple API calls
78
- */
79
- batchOperations<T>(operations: Array<() => Promise<T>>, options?: {
80
- maxConcurrent?: number;
81
- delayBetween?: number;
82
- continueOnError?: boolean;
83
- }): Promise<Array<{
84
- success: boolean;
85
- data?: T;
86
- error?: string;
87
- }>>;
88
- /**
89
- * Health check for the provider
90
- */
91
- healthCheck(): Promise<{
92
- healthy: boolean;
93
- details: any;
94
- }>;
95
- /**
96
- * Get provider statistics and cache metrics
97
- */
98
- getStats(): any;
99
- /**
100
- * Clear provider-related cache entries
101
- */
102
- clearCache(): void;
103
- }
104
- export declare function createBitbucketProvider(credentials: GitCredentials): BitbucketProvider;
105
- //# sourceMappingURL=BitbucketProvider.d.ts.map