@juspay/yama 1.6.0 → 2.1.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 (79) hide show
  1. package/.mcp-config.example.json +26 -0
  2. package/CHANGELOG.md +46 -0
  3. package/README.md +311 -685
  4. package/dist/cli/v2.cli.d.ts +13 -0
  5. package/dist/cli/v2.cli.js +359 -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 +187 -0
  12. package/dist/v2/core/LearningOrchestrator.d.ts +65 -0
  13. package/dist/v2/core/LearningOrchestrator.js +499 -0
  14. package/dist/v2/core/MCPServerManager.d.ts +22 -0
  15. package/dist/v2/core/MCPServerManager.js +100 -0
  16. package/dist/v2/core/SessionManager.d.ts +72 -0
  17. package/dist/v2/core/SessionManager.js +200 -0
  18. package/dist/v2/core/YamaV2Orchestrator.d.ts +112 -0
  19. package/dist/v2/core/YamaV2Orchestrator.js +549 -0
  20. package/dist/v2/learning/FeedbackExtractor.d.ts +46 -0
  21. package/dist/v2/learning/FeedbackExtractor.js +237 -0
  22. package/dist/v2/learning/KnowledgeBaseManager.d.ts +91 -0
  23. package/dist/v2/learning/KnowledgeBaseManager.js +475 -0
  24. package/dist/v2/learning/types.d.ts +121 -0
  25. package/dist/v2/learning/types.js +15 -0
  26. package/dist/v2/prompts/EnhancementSystemPrompt.d.ts +8 -0
  27. package/dist/v2/prompts/EnhancementSystemPrompt.js +216 -0
  28. package/dist/v2/prompts/LangfusePromptManager.d.ts +48 -0
  29. package/dist/v2/prompts/LangfusePromptManager.js +144 -0
  30. package/dist/v2/prompts/LearningSystemPrompt.d.ts +11 -0
  31. package/dist/v2/prompts/LearningSystemPrompt.js +180 -0
  32. package/dist/v2/prompts/PromptBuilder.d.ts +45 -0
  33. package/dist/v2/prompts/PromptBuilder.js +257 -0
  34. package/dist/v2/prompts/ReviewSystemPrompt.d.ts +8 -0
  35. package/dist/v2/prompts/ReviewSystemPrompt.js +270 -0
  36. package/dist/v2/types/config.types.d.ts +141 -0
  37. package/dist/v2/types/config.types.js +5 -0
  38. package/dist/v2/types/mcp.types.d.ts +191 -0
  39. package/dist/v2/types/mcp.types.js +6 -0
  40. package/dist/v2/types/v2.types.d.ts +182 -0
  41. package/dist/v2/types/v2.types.js +42 -0
  42. package/dist/v2/utils/ObservabilityConfig.d.ts +22 -0
  43. package/dist/v2/utils/ObservabilityConfig.js +48 -0
  44. package/package.json +16 -10
  45. package/yama.config.example.yaml +259 -204
  46. package/dist/cli/index.d.ts +0 -12
  47. package/dist/cli/index.js +0 -538
  48. package/dist/core/ContextGatherer.d.ts +0 -110
  49. package/dist/core/ContextGatherer.js +0 -470
  50. package/dist/core/Guardian.d.ts +0 -81
  51. package/dist/core/Guardian.js +0 -480
  52. package/dist/core/providers/BitbucketProvider.d.ts +0 -105
  53. package/dist/core/providers/BitbucketProvider.js +0 -489
  54. package/dist/features/CodeReviewer.d.ts +0 -173
  55. package/dist/features/CodeReviewer.js +0 -1707
  56. package/dist/features/DescriptionEnhancer.d.ts +0 -70
  57. package/dist/features/DescriptionEnhancer.js +0 -511
  58. package/dist/features/MultiInstanceProcessor.d.ts +0 -74
  59. package/dist/features/MultiInstanceProcessor.js +0 -360
  60. package/dist/types/index.d.ts +0 -624
  61. package/dist/types/index.js +0 -104
  62. package/dist/utils/Cache.d.ts +0 -103
  63. package/dist/utils/Cache.js +0 -444
  64. package/dist/utils/ConfigManager.d.ts +0 -88
  65. package/dist/utils/ConfigManager.js +0 -602
  66. package/dist/utils/ContentSimilarityService.d.ts +0 -74
  67. package/dist/utils/ContentSimilarityService.js +0 -215
  68. package/dist/utils/ExactDuplicateRemover.d.ts +0 -77
  69. package/dist/utils/ExactDuplicateRemover.js +0 -361
  70. package/dist/utils/Logger.d.ts +0 -31
  71. package/dist/utils/Logger.js +0 -214
  72. package/dist/utils/MemoryBankManager.d.ts +0 -73
  73. package/dist/utils/MemoryBankManager.js +0 -310
  74. package/dist/utils/ParallelProcessing.d.ts +0 -140
  75. package/dist/utils/ParallelProcessing.js +0 -333
  76. package/dist/utils/ProviderLimits.d.ts +0 -58
  77. package/dist/utils/ProviderLimits.js +0 -143
  78. package/dist/utils/RetryManager.d.ts +0 -78
  79. package/dist/utils/RetryManager.js +0 -205
@@ -0,0 +1,549 @@
1
+ /**
2
+ * Yama V2 Orchestrator
3
+ * Main entry point for AI-native autonomous code review
4
+ */
5
+ import { NeuroLink } from "@juspay/neurolink";
6
+ import { MCPServerManager } from "./MCPServerManager.js";
7
+ import { ConfigLoader } from "../config/ConfigLoader.js";
8
+ import { PromptBuilder } from "../prompts/PromptBuilder.js";
9
+ import { SessionManager } from "./SessionManager.js";
10
+ import { buildObservabilityConfigFromEnv, validateObservabilityConfig, } from "../utils/ObservabilityConfig.js";
11
+ export class YamaV2Orchestrator {
12
+ neurolink;
13
+ mcpManager;
14
+ configLoader;
15
+ promptBuilder;
16
+ sessionManager;
17
+ config;
18
+ initialized = false;
19
+ constructor() {
20
+ this.configLoader = new ConfigLoader();
21
+ this.mcpManager = new MCPServerManager();
22
+ this.promptBuilder = new PromptBuilder();
23
+ this.sessionManager = new SessionManager();
24
+ }
25
+ /**
26
+ * Initialize Yama V2 with configuration and MCP servers
27
+ */
28
+ async initialize(configPath) {
29
+ if (this.initialized) {
30
+ return;
31
+ }
32
+ this.showBanner();
33
+ console.log("🚀 Initializing Yama V2...\n");
34
+ try {
35
+ // Step 1: Load configuration
36
+ this.config = await this.configLoader.loadConfig(configPath);
37
+ // Step 2: Initialize NeuroLink with observability
38
+ console.log("🧠 Initializing NeuroLink AI engine...");
39
+ this.neurolink = this.initializeNeurolink();
40
+ console.log("✅ NeuroLink initialized\n");
41
+ // Step 3: Setup MCP servers
42
+ await this.mcpManager.setupMCPServers(this.neurolink, this.config.mcpServers);
43
+ console.log("✅ MCP servers ready (tools managed by NeuroLink)\n");
44
+ // Step 4: Validate configuration
45
+ await this.configLoader.validate();
46
+ this.initialized = true;
47
+ console.log("✅ Yama V2 initialized successfully\n");
48
+ console.log("═".repeat(60) + "\n");
49
+ }
50
+ catch (error) {
51
+ console.error("\n❌ Initialization failed:", error.message);
52
+ throw error;
53
+ }
54
+ }
55
+ /**
56
+ * Start autonomous AI review
57
+ */
58
+ async startReview(request) {
59
+ await this.ensureInitialized();
60
+ const startTime = Date.now();
61
+ const sessionId = this.sessionManager.createSession(request);
62
+ this.logReviewStart(request, sessionId);
63
+ try {
64
+ // Build comprehensive AI instructions
65
+ const instructions = await this.promptBuilder.buildReviewInstructions(request, this.config);
66
+ if (this.config.display.verboseToolCalls) {
67
+ console.log("\n📝 AI Instructions built:");
68
+ console.log(` Instruction length: ${instructions.length} characters\n`);
69
+ }
70
+ // Create tool context for AI
71
+ const toolContext = this.createToolContext(sessionId, request);
72
+ // Set tool context in NeuroLink (using type assertion as setToolContext is documented but may not be in type definitions)
73
+ this.neurolink.setToolContext(toolContext);
74
+ // Update session metadata
75
+ this.sessionManager.updateMetadata(sessionId, {
76
+ aiProvider: this.config.ai.provider,
77
+ aiModel: this.config.ai.model,
78
+ });
79
+ // Execute autonomous AI review
80
+ console.log("🤖 Starting autonomous AI review...");
81
+ console.log(" AI will now make decisions and execute actions autonomously\n");
82
+ const aiResponse = await this.neurolink.generate({
83
+ input: { text: instructions },
84
+ provider: this.config.ai.provider,
85
+ model: this.config.ai.model,
86
+ temperature: this.config.ai.temperature,
87
+ maxTokens: this.config.ai.maxTokens,
88
+ timeout: this.config.ai.timeout,
89
+ context: {
90
+ sessionId,
91
+ userId: this.generateUserId(request),
92
+ operation: "code-review",
93
+ metadata: toolContext.metadata,
94
+ },
95
+ enableAnalytics: this.config.ai.enableAnalytics,
96
+ enableEvaluation: this.config.ai.enableEvaluation,
97
+ });
98
+ // Extract and parse results
99
+ const result = this.parseReviewResult(aiResponse, startTime, sessionId);
100
+ // Update session with results
101
+ this.sessionManager.completeSession(sessionId, result);
102
+ this.logReviewComplete(result);
103
+ return result;
104
+ }
105
+ catch (error) {
106
+ this.sessionManager.failSession(sessionId, error);
107
+ console.error("\n❌ Review failed:", error.message);
108
+ throw error;
109
+ }
110
+ }
111
+ /**
112
+ * Stream review with real-time updates (for verbose mode)
113
+ */
114
+ async *streamReview(request) {
115
+ await this.ensureInitialized();
116
+ const sessionId = this.sessionManager.createSession(request);
117
+ try {
118
+ // Build instructions
119
+ const instructions = await this.promptBuilder.buildReviewInstructions(request, this.config);
120
+ // Create tool context
121
+ const toolContext = this.createToolContext(sessionId, request);
122
+ this.neurolink.setToolContext(toolContext);
123
+ // Stream AI execution
124
+ yield {
125
+ type: "progress",
126
+ timestamp: new Date().toISOString(),
127
+ sessionId,
128
+ data: {
129
+ phase: "context_gathering",
130
+ progress: 0,
131
+ message: "Starting review...",
132
+ },
133
+ };
134
+ // Note: NeuroLink streaming implementation depends on version
135
+ // This is a placeholder for streaming functionality
136
+ const aiResponse = await this.neurolink.generate({
137
+ input: { text: instructions },
138
+ provider: this.config.ai.provider,
139
+ model: this.config.ai.model,
140
+ context: {
141
+ sessionId,
142
+ userId: this.generateUserId(request),
143
+ },
144
+ enableAnalytics: true,
145
+ });
146
+ yield {
147
+ type: "progress",
148
+ timestamp: new Date().toISOString(),
149
+ sessionId,
150
+ data: {
151
+ phase: "decision_making",
152
+ progress: 100,
153
+ message: "Review complete",
154
+ },
155
+ };
156
+ }
157
+ catch (error) {
158
+ this.sessionManager.failSession(sessionId, error);
159
+ throw error;
160
+ }
161
+ }
162
+ /**
163
+ * Start review and then enhance description in the same session
164
+ * This allows the AI to use knowledge gained during review to write better descriptions
165
+ */
166
+ async startReviewAndEnhance(request) {
167
+ await this.ensureInitialized();
168
+ const startTime = Date.now();
169
+ const sessionId = this.sessionManager.createSession(request);
170
+ this.logReviewStart(request, sessionId);
171
+ try {
172
+ // ========================================================================
173
+ // PHASE 1: Code Review
174
+ // ========================================================================
175
+ // Build review instructions
176
+ const reviewInstructions = await this.promptBuilder.buildReviewInstructions(request, this.config);
177
+ if (this.config.display.verboseToolCalls) {
178
+ console.log("\n📝 Review instructions built:");
179
+ console.log(` Instruction length: ${reviewInstructions.length} characters\n`);
180
+ }
181
+ // Create tool context
182
+ const toolContext = this.createToolContext(sessionId, request);
183
+ this.neurolink.setToolContext(toolContext);
184
+ // Update session metadata
185
+ this.sessionManager.updateMetadata(sessionId, {
186
+ aiProvider: this.config.ai.provider,
187
+ aiModel: this.config.ai.model,
188
+ });
189
+ // Execute review
190
+ console.log("🤖 Phase 1: Starting autonomous AI code review...");
191
+ console.log(" AI will analyze files and post comments\n");
192
+ const reviewResponse = await this.neurolink.generate({
193
+ input: { text: reviewInstructions },
194
+ provider: this.config.ai.provider,
195
+ model: this.config.ai.model,
196
+ temperature: this.config.ai.temperature,
197
+ maxTokens: this.config.ai.maxTokens,
198
+ timeout: this.config.ai.timeout,
199
+ context: {
200
+ sessionId,
201
+ userId: this.generateUserId(request),
202
+ operation: "code-review",
203
+ metadata: toolContext.metadata,
204
+ },
205
+ enableAnalytics: this.config.ai.enableAnalytics,
206
+ enableEvaluation: this.config.ai.enableEvaluation,
207
+ });
208
+ // Parse review results
209
+ const reviewResult = this.parseReviewResult(reviewResponse, startTime, sessionId);
210
+ console.log("\n✅ Phase 1 complete: Code review finished");
211
+ console.log(` Decision: ${reviewResult.decision}`);
212
+ console.log(` Comments: ${reviewResult.statistics.totalComments}\n`);
213
+ // ========================================================================
214
+ // PHASE 2: Description Enhancement (using same session)
215
+ // ========================================================================
216
+ if (this.config.descriptionEnhancement.enabled) {
217
+ console.log("📝 Phase 2: Enhancing PR description...");
218
+ console.log(" AI will use review insights to write description\n");
219
+ const enhanceInstructions = await this.promptBuilder.buildDescriptionEnhancementInstructions(request, this.config);
220
+ // Continue the SAME session - AI remembers everything from review
221
+ const enhanceResponse = await this.neurolink.generate({
222
+ input: { text: enhanceInstructions },
223
+ provider: this.config.ai.provider,
224
+ model: this.config.ai.model,
225
+ temperature: this.config.ai.temperature,
226
+ maxTokens: this.config.ai.maxTokens,
227
+ timeout: this.config.ai.timeout,
228
+ context: {
229
+ sessionId, // SAME sessionId = AI remembers review context
230
+ userId: this.generateUserId(request),
231
+ operation: "description-enhancement",
232
+ metadata: toolContext.metadata,
233
+ },
234
+ enableAnalytics: this.config.ai.enableAnalytics,
235
+ enableEvaluation: this.config.ai.enableEvaluation,
236
+ });
237
+ console.log("✅ Phase 2 complete: Description enhanced\n");
238
+ // Add enhancement status to result
239
+ reviewResult.descriptionEnhanced = true;
240
+ }
241
+ else {
242
+ console.log("⏭️ Skipping description enhancement (disabled in config)\n");
243
+ reviewResult.descriptionEnhanced = false;
244
+ }
245
+ // Update session with final results
246
+ this.sessionManager.completeSession(sessionId, reviewResult);
247
+ this.logReviewComplete(reviewResult);
248
+ return reviewResult;
249
+ }
250
+ catch (error) {
251
+ this.sessionManager.failSession(sessionId, error);
252
+ console.error("\n❌ Review failed:", error.message);
253
+ throw error;
254
+ }
255
+ }
256
+ /**
257
+ * Enhance PR description only (without full review)
258
+ */
259
+ async enhanceDescription(request) {
260
+ await this.ensureInitialized();
261
+ const sessionId = this.sessionManager.createSession(request);
262
+ try {
263
+ console.log("\n📝 Enhancing PR description...\n");
264
+ const instructions = await this.promptBuilder.buildDescriptionEnhancementInstructions(request, this.config);
265
+ const toolContext = this.createToolContext(sessionId, request);
266
+ this.neurolink.setToolContext(toolContext);
267
+ const aiResponse = await this.neurolink.generate({
268
+ input: { text: instructions },
269
+ provider: this.config.ai.provider,
270
+ model: this.config.ai.model,
271
+ context: {
272
+ sessionId,
273
+ userId: this.generateUserId(request),
274
+ operation: "description-enhancement",
275
+ },
276
+ enableAnalytics: true,
277
+ });
278
+ console.log("✅ Description enhanced successfully\n");
279
+ return {
280
+ success: true,
281
+ enhanced: true,
282
+ sessionId,
283
+ };
284
+ }
285
+ catch (error) {
286
+ this.sessionManager.failSession(sessionId, error);
287
+ throw error;
288
+ }
289
+ }
290
+ /**
291
+ * Get session information
292
+ */
293
+ getSession(sessionId) {
294
+ return this.sessionManager.getSession(sessionId);
295
+ }
296
+ /**
297
+ * Get session statistics
298
+ */
299
+ getSessionStats(sessionId) {
300
+ return this.sessionManager.getSessionStats(sessionId);
301
+ }
302
+ /**
303
+ * Export session data
304
+ */
305
+ exportSession(sessionId) {
306
+ return this.sessionManager.exportSession(sessionId);
307
+ }
308
+ /**
309
+ * Create tool context for AI
310
+ */
311
+ createToolContext(sessionId, request) {
312
+ return {
313
+ sessionId,
314
+ workspace: request.workspace,
315
+ repository: request.repository,
316
+ pullRequestId: request.pullRequestId,
317
+ branch: request.branch,
318
+ dryRun: request.dryRun || false,
319
+ metadata: {
320
+ yamaVersion: "2.0.0",
321
+ startTime: new Date().toISOString(),
322
+ },
323
+ };
324
+ }
325
+ /**
326
+ * Parse AI response into structured review result
327
+ */
328
+ parseReviewResult(aiResponse, startTime, sessionId) {
329
+ const session = this.sessionManager.getSession(sessionId);
330
+ const duration = Math.round((Date.now() - startTime) / 1000);
331
+ // Extract decision from AI response or tool calls
332
+ const decision = this.extractDecision(aiResponse, session);
333
+ // Calculate statistics from session tool calls
334
+ const statistics = this.calculateStatistics(session);
335
+ return {
336
+ prId: session.request.pullRequestId || 0,
337
+ decision,
338
+ statistics,
339
+ summary: this.extractSummary(aiResponse),
340
+ duration,
341
+ tokenUsage: {
342
+ input: aiResponse.usage?.inputTokens || 0,
343
+ output: aiResponse.usage?.outputTokens || 0,
344
+ total: aiResponse.usage?.totalTokens || 0,
345
+ },
346
+ costEstimate: this.calculateCost(aiResponse.usage),
347
+ sessionId,
348
+ };
349
+ }
350
+ /**
351
+ * Extract decision from AI response
352
+ */
353
+ extractDecision(aiResponse, session) {
354
+ // Check if AI called approve_pull_request or request_changes
355
+ const toolCalls = session.toolCalls || [];
356
+ const approveCall = toolCalls.find((tc) => tc.toolName === "approve_pull_request");
357
+ const requestChangesCall = toolCalls.find((tc) => tc.toolName === "request_changes");
358
+ if (approveCall) {
359
+ return "APPROVED";
360
+ }
361
+ if (requestChangesCall) {
362
+ return "BLOCKED";
363
+ }
364
+ // Default to changes requested if unclear
365
+ return "CHANGES_REQUESTED";
366
+ }
367
+ /**
368
+ * Calculate statistics from session
369
+ */
370
+ calculateStatistics(session) {
371
+ const toolCalls = session.toolCalls || [];
372
+ // Count file diffs read
373
+ const filesReviewed = toolCalls.filter((tc) => tc.toolName === "get_pull_request_diff").length;
374
+ // Try to extract issue counts from comments
375
+ const commentCalls = toolCalls.filter((tc) => tc.toolName === "add_comment");
376
+ const issuesFound = this.extractIssueCountsFromComments(commentCalls);
377
+ return {
378
+ filesReviewed,
379
+ issuesFound,
380
+ requirementCoverage: 0, // Would need to parse from Jira comparison
381
+ codeQualityScore: 0, // Would need AI to provide this
382
+ toolCallsMade: toolCalls.length,
383
+ cacheHits: 0,
384
+ totalComments: commentCalls.length,
385
+ };
386
+ }
387
+ /**
388
+ * Extract issue counts from comment tool calls
389
+ */
390
+ extractIssueCountsFromComments(commentCalls) {
391
+ const counts = {
392
+ critical: 0,
393
+ major: 0,
394
+ minor: 0,
395
+ suggestions: 0,
396
+ };
397
+ commentCalls.forEach((call) => {
398
+ const text = call.args?.comment_text || "";
399
+ if (text.includes("🔒 CRITICAL") || text.includes("CRITICAL:")) {
400
+ counts.critical++;
401
+ }
402
+ else if (text.includes("⚠️ MAJOR") || text.includes("MAJOR:")) {
403
+ counts.major++;
404
+ }
405
+ else if (text.includes("💡 MINOR") || text.includes("MINOR:")) {
406
+ counts.minor++;
407
+ }
408
+ else if (text.includes("💬 SUGGESTION") ||
409
+ text.includes("SUGGESTION:")) {
410
+ counts.suggestions++;
411
+ }
412
+ });
413
+ return counts;
414
+ }
415
+ /**
416
+ * Extract summary from AI response
417
+ */
418
+ extractSummary(aiResponse) {
419
+ return aiResponse.content || aiResponse.text || "Review completed";
420
+ }
421
+ /**
422
+ * Calculate cost estimate from token usage
423
+ */
424
+ calculateCost(usage) {
425
+ if (!usage) {
426
+ return 0;
427
+ }
428
+ // Rough estimates (update with actual pricing)
429
+ const inputCostPer1M = 0.25; // $0.25 per 1M input tokens (Gemini 2.0 Flash)
430
+ const outputCostPer1M = 1.0; // $1.00 per 1M output tokens
431
+ const inputCost = (usage.inputTokens / 1_000_000) * inputCostPer1M;
432
+ const outputCost = (usage.outputTokens / 1_000_000) * outputCostPer1M;
433
+ return Number((inputCost + outputCost).toFixed(4));
434
+ }
435
+ /**
436
+ * Generate userId for NeuroLink context from repository and branch/PR
437
+ */
438
+ generateUserId(request) {
439
+ const repo = request.repository;
440
+ const identifier = request.branch || `pr-${request.pullRequestId}`;
441
+ return `${repo}-${identifier}`;
442
+ }
443
+ /**
444
+ * Initialize NeuroLink with observability configuration
445
+ */
446
+ initializeNeurolink() {
447
+ try {
448
+ const observabilityConfig = buildObservabilityConfigFromEnv();
449
+ const neurolinkConfig = {
450
+ conversationMemory: this.config.ai.conversationMemory,
451
+ };
452
+ if (observabilityConfig) {
453
+ // Validate observability config
454
+ if (!validateObservabilityConfig(observabilityConfig)) {
455
+ throw new Error("Invalid observability configuration");
456
+ }
457
+ neurolinkConfig.observability = observabilityConfig;
458
+ console.log(" 📊 Observability enabled (Langfuse tracing active)");
459
+ }
460
+ else {
461
+ console.log(" 📊 Observability not configured (set LANGFUSE_* env vars to enable)");
462
+ }
463
+ const neurolink = new NeuroLink(neurolinkConfig);
464
+ return neurolink;
465
+ }
466
+ catch (error) {
467
+ console.error("❌ Failed to initialize NeuroLink:", error.message);
468
+ throw new Error(`NeuroLink initialization failed: ${error}`);
469
+ }
470
+ }
471
+ /**
472
+ * Ensure orchestrator is initialized
473
+ */
474
+ async ensureInitialized() {
475
+ if (!this.initialized) {
476
+ await this.initialize();
477
+ }
478
+ }
479
+ /**
480
+ * Show Yama V2 banner
481
+ */
482
+ showBanner() {
483
+ if (!this.config?.display?.showBanner) {
484
+ return;
485
+ }
486
+ console.log("\n" + "═".repeat(60));
487
+ console.log(`
488
+ ⚔️ YAMA V2 - AI-Native Code Review Guardian
489
+
490
+ Version: 2.0.0
491
+ Mode: Autonomous AI-Powered Review
492
+ Powered by: NeuroLink + MCP Tools
493
+ `);
494
+ console.log("═".repeat(60) + "\n");
495
+ }
496
+ /**
497
+ * Log review start
498
+ */
499
+ logReviewStart(request, sessionId) {
500
+ console.log("\n" + "─".repeat(60));
501
+ console.log(`📋 Review Session Started`);
502
+ console.log("─".repeat(60));
503
+ console.log(` Session ID: ${sessionId}`);
504
+ console.log(` Workspace: ${request.workspace}`);
505
+ console.log(` Repository: ${request.repository}`);
506
+ console.log(` PR: ${request.pullRequestId || request.branch}`);
507
+ console.log(` Mode: ${request.dryRun ? "🔵 DRY RUN" : "🔴 LIVE"}`);
508
+ console.log("─".repeat(60) + "\n");
509
+ }
510
+ /**
511
+ * Log review completion
512
+ */
513
+ logReviewComplete(result) {
514
+ console.log("\n" + "═".repeat(60));
515
+ console.log(`✅ Review Completed Successfully`);
516
+ console.log("═".repeat(60));
517
+ console.log(` Decision: ${this.formatDecision(result.decision)}`);
518
+ console.log(` Duration: ${result.duration}s`);
519
+ console.log(` Files Reviewed: ${result.statistics.filesReviewed}`);
520
+ console.log(` Issues Found:`);
521
+ console.log(` 🔒 CRITICAL: ${result.statistics.issuesFound.critical}`);
522
+ console.log(` ⚠️ MAJOR: ${result.statistics.issuesFound.major}`);
523
+ console.log(` 💡 MINOR: ${result.statistics.issuesFound.minor}`);
524
+ console.log(` 💬 SUGGESTIONS: ${result.statistics.issuesFound.suggestions}`);
525
+ console.log(` Token Usage: ${result.tokenUsage.total.toLocaleString()}`);
526
+ console.log(` Cost Estimate: $${result.costEstimate.toFixed(4)}`);
527
+ console.log("═".repeat(60) + "\n");
528
+ }
529
+ /**
530
+ * Format decision for display
531
+ */
532
+ formatDecision(decision) {
533
+ switch (decision) {
534
+ case "APPROVED":
535
+ return "✅ APPROVED";
536
+ case "BLOCKED":
537
+ return "🚫 BLOCKED";
538
+ case "CHANGES_REQUESTED":
539
+ return "⚠️ CHANGES REQUESTED";
540
+ default:
541
+ return decision;
542
+ }
543
+ }
544
+ }
545
+ // Export factory function
546
+ export function createYamaV2() {
547
+ return new YamaV2Orchestrator();
548
+ }
549
+ //# sourceMappingURL=YamaV2Orchestrator.js.map
@@ -0,0 +1,46 @@
1
+ /**
2
+ * Feedback Extractor
3
+ * Identifies AI comments and developer replies from PR comments
4
+ */
5
+ import { KnowledgeBaseConfig } from "../types/config.types.js";
6
+ import { PRComment, CommentPair } from "./types.js";
7
+ export declare class FeedbackExtractor {
8
+ private config;
9
+ constructor(config: KnowledgeBaseConfig);
10
+ /**
11
+ * Check if a comment is from AI based on author and text patterns
12
+ */
13
+ isAIComment(comment: PRComment): boolean;
14
+ /**
15
+ * Check if a comment is a developer reply (not from AI)
16
+ */
17
+ isDeveloperComment(comment: PRComment): boolean;
18
+ /**
19
+ * Extract AI comment + developer reply pairs from a list of comments
20
+ */
21
+ extractCommentPairs(comments: PRComment[]): CommentPair[];
22
+ /**
23
+ * Find comment pairs based on file/line proximity (for inline comments)
24
+ */
25
+ private findInlineCommentPairs;
26
+ /**
27
+ * Convert raw Bitbucket API comment to PRComment
28
+ */
29
+ convertBitbucketComment(rawComment: Record<string, unknown>): PRComment;
30
+ /**
31
+ * Extract meaningful feedback from a comment pair
32
+ * Determines if the developer reply contains actionable feedback
33
+ */
34
+ hasActionableFeedback(pair: CommentPair): boolean;
35
+ /**
36
+ * Get statistics about comment analysis
37
+ */
38
+ getCommentStats(comments: PRComment[]): {
39
+ total: number;
40
+ aiComments: number;
41
+ developerComments: number;
42
+ pairs: number;
43
+ actionablePairs: number;
44
+ };
45
+ }
46
+ //# sourceMappingURL=FeedbackExtractor.d.ts.map