@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,205 @@
1
+ /**
2
+ * Multi-Layer Configuration Loader for Yama V2
3
+ * Loads and merges configuration from multiple sources
4
+ */
5
+ import { readFile } from "fs/promises";
6
+ import { existsSync } from "fs";
7
+ import { parse as parseYAML } from "yaml";
8
+ import { resolve } from "path";
9
+ import { ConfigurationError } from "../types/v2.types.js";
10
+ import { DefaultConfig } from "./DefaultConfig.js";
11
+ export class ConfigLoader {
12
+ config = null;
13
+ configPath = null;
14
+ /**
15
+ * Load configuration from file with multi-layer support
16
+ */
17
+ async loadConfig(configPath) {
18
+ console.log("๐Ÿ“‹ Loading Yama V2 configuration...");
19
+ // Layer 1: Start with default config
20
+ let config = DefaultConfig.get();
21
+ // Layer 2: Load from file if provided or search for default locations
22
+ const filePath = await this.resolveConfigPath(configPath);
23
+ if (filePath) {
24
+ console.log(` Reading config from: ${filePath}`);
25
+ const fileConfig = await this.loadConfigFile(filePath);
26
+ config = this.mergeConfigs(config, fileConfig);
27
+ this.configPath = filePath;
28
+ }
29
+ else {
30
+ console.log(" Using default configuration (no config file found)");
31
+ }
32
+ // Layer 3: Apply environment variable overrides
33
+ config = this.applyEnvironmentOverrides(config);
34
+ // Validate configuration
35
+ this.validateConfig(config);
36
+ this.config = config;
37
+ console.log("โœ… Configuration loaded successfully\n");
38
+ return config;
39
+ }
40
+ /**
41
+ * Get current loaded configuration
42
+ */
43
+ getConfig() {
44
+ if (!this.config) {
45
+ throw new ConfigurationError("Configuration not loaded. Call loadConfig() first.");
46
+ }
47
+ return this.config;
48
+ }
49
+ /**
50
+ * Validate configuration completeness and correctness
51
+ */
52
+ async validate() {
53
+ if (!this.config) {
54
+ throw new ConfigurationError("No configuration to validate");
55
+ }
56
+ const errors = [];
57
+ // Validate AI config
58
+ if (!this.config.ai.provider) {
59
+ errors.push("AI provider not configured");
60
+ }
61
+ if (!this.config.ai.model) {
62
+ errors.push("AI model not configured");
63
+ }
64
+ // Check environment variables for Bitbucket (always required)
65
+ if (!process.env.BITBUCKET_USERNAME) {
66
+ errors.push("BITBUCKET_USERNAME environment variable not set");
67
+ }
68
+ if (!process.env.BITBUCKET_TOKEN) {
69
+ errors.push("BITBUCKET_TOKEN environment variable not set");
70
+ }
71
+ if (!process.env.BITBUCKET_BASE_URL) {
72
+ errors.push("BITBUCKET_BASE_URL environment variable not set");
73
+ }
74
+ if (this.config.mcpServers.jira.enabled) {
75
+ if (!process.env.JIRA_EMAIL) {
76
+ errors.push("JIRA_EMAIL environment variable not set");
77
+ }
78
+ if (!process.env.JIRA_API_TOKEN) {
79
+ errors.push("JIRA_API_TOKEN environment variable not set");
80
+ }
81
+ if (!process.env.JIRA_BASE_URL) {
82
+ errors.push("JIRA_BASE_URL environment variable not set");
83
+ }
84
+ }
85
+ if (errors.length > 0) {
86
+ throw new ConfigurationError(`Configuration validation failed:\n${errors.map((e) => ` - ${e}`).join("\n")}`);
87
+ }
88
+ }
89
+ /**
90
+ * Resolve configuration file path
91
+ */
92
+ async resolveConfigPath(configPath) {
93
+ // If explicit path provided, use it
94
+ if (configPath) {
95
+ const resolvedPath = resolve(configPath);
96
+ if (!existsSync(resolvedPath)) {
97
+ throw new ConfigurationError(`Configuration file not found: ${resolvedPath}`);
98
+ }
99
+ return resolvedPath;
100
+ }
101
+ // Search for default config files
102
+ const defaultPaths = [
103
+ "yama.config.yaml",
104
+ "config/yama.config.yaml",
105
+ ".yama/config.yaml",
106
+ ];
107
+ for (const path of defaultPaths) {
108
+ const resolvedPath = resolve(path);
109
+ if (existsSync(resolvedPath)) {
110
+ return resolvedPath;
111
+ }
112
+ }
113
+ return null;
114
+ }
115
+ /**
116
+ * Load configuration from YAML file
117
+ */
118
+ async loadConfigFile(filePath) {
119
+ try {
120
+ const content = await readFile(filePath, "utf-8");
121
+ const parsed = parseYAML(content);
122
+ return parsed;
123
+ }
124
+ catch (error) {
125
+ throw new ConfigurationError(`Failed to load config file: ${error.message}`, { filePath });
126
+ }
127
+ }
128
+ /**
129
+ * Deep merge two configuration objects
130
+ */
131
+ mergeConfigs(base, override) {
132
+ return this.deepMerge(base, override);
133
+ }
134
+ /**
135
+ * Deep merge utility
136
+ */
137
+ deepMerge(target, source) {
138
+ const output = { ...target };
139
+ if (this.isObject(target) && this.isObject(source)) {
140
+ Object.keys(source).forEach((key) => {
141
+ if (this.isObject(source[key])) {
142
+ if (!(key in target)) {
143
+ Object.assign(output, { [key]: source[key] });
144
+ }
145
+ else {
146
+ output[key] = this.deepMerge(target[key], source[key]);
147
+ }
148
+ }
149
+ else {
150
+ Object.assign(output, { [key]: source[key] });
151
+ }
152
+ });
153
+ }
154
+ return output;
155
+ }
156
+ /**
157
+ * Check if value is an object
158
+ */
159
+ isObject(item) {
160
+ return item && typeof item === "object" && !Array.isArray(item);
161
+ }
162
+ /**
163
+ * Apply environment variable overrides
164
+ */
165
+ applyEnvironmentOverrides(config) {
166
+ // Override AI provider if env var set
167
+ if (process.env.AI_PROVIDER) {
168
+ config.ai.provider = process.env.AI_PROVIDER;
169
+ }
170
+ // Override AI model if env var set
171
+ if (process.env.AI_MODEL) {
172
+ config.ai.model = process.env.AI_MODEL;
173
+ }
174
+ // Override temperature if env var set
175
+ if (process.env.AI_TEMPERATURE) {
176
+ config.ai.temperature = parseFloat(process.env.AI_TEMPERATURE);
177
+ }
178
+ // Override max tokens if env var set
179
+ if (process.env.AI_MAX_TOKENS) {
180
+ config.ai.maxTokens = parseInt(process.env.AI_MAX_TOKENS, 10);
181
+ }
182
+ return config;
183
+ }
184
+ /**
185
+ * Basic configuration validation
186
+ */
187
+ validateConfig(config) {
188
+ if (!config.version) {
189
+ throw new ConfigurationError("Configuration version not specified");
190
+ }
191
+ if (config.version !== 2) {
192
+ throw new ConfigurationError(`Invalid configuration version: ${config.version}. Expected version 2.`);
193
+ }
194
+ if (!config.ai) {
195
+ throw new ConfigurationError("AI configuration missing");
196
+ }
197
+ if (!config.mcpServers) {
198
+ throw new ConfigurationError("MCP servers configuration missing");
199
+ }
200
+ if (!config.review) {
201
+ throw new ConfigurationError("Review configuration missing");
202
+ }
203
+ }
204
+ }
205
+ //# sourceMappingURL=ConfigLoader.js.map
@@ -0,0 +1,9 @@
1
+ /**
2
+ * Default Configuration for Yama V2
3
+ * Provides sensible defaults when no config file is present
4
+ */
5
+ import { YamaV2Config } from "../types/config.types.js";
6
+ export declare class DefaultConfig {
7
+ static get(): YamaV2Config;
8
+ }
9
+ //# sourceMappingURL=DefaultConfig.d.ts.map
@@ -0,0 +1,187 @@
1
+ /**
2
+ * Default Configuration for Yama V2
3
+ * Provides sensible defaults when no config file is present
4
+ */
5
+ export class DefaultConfig {
6
+ static get() {
7
+ return {
8
+ version: 2,
9
+ configType: "yama-v2",
10
+ display: {
11
+ showBanner: true,
12
+ streamingMode: false,
13
+ verboseToolCalls: false,
14
+ showAIThinking: false,
15
+ },
16
+ ai: {
17
+ provider: "auto",
18
+ model: "gemini-2.5-pro",
19
+ temperature: 0.2,
20
+ maxTokens: 128000,
21
+ enableAnalytics: true,
22
+ enableEvaluation: false,
23
+ timeout: "15m",
24
+ retryAttempts: 3,
25
+ conversationMemory: {
26
+ enabled: true,
27
+ store: "memory",
28
+ maxSessions: 50,
29
+ maxTurnsPerSession: 300,
30
+ enableSummarization: false,
31
+ },
32
+ },
33
+ mcpServers: {
34
+ bitbucket: {
35
+ blockedTools: [],
36
+ },
37
+ jira: {
38
+ enabled: false, // Opt-in: users must explicitly enable Jira integration
39
+ blockedTools: [],
40
+ },
41
+ },
42
+ review: {
43
+ enabled: true,
44
+ workflowInstructions: `Follow the autonomous review workflow defined in the base system prompt.`,
45
+ focusAreas: [
46
+ {
47
+ name: "Security Analysis",
48
+ priority: "CRITICAL",
49
+ description: `
50
+ - SQL/NoSQL injection vulnerabilities
51
+ - Cross-Site Scripting (XSS)
52
+ - Authentication/Authorization flaws
53
+ - Hardcoded secrets, API keys, passwords
54
+ - Input validation and sanitization
55
+ - Data exposure and privacy violations
56
+ - Insecure dependencies
57
+ `.trim(),
58
+ },
59
+ {
60
+ name: "Performance Review",
61
+ priority: "MAJOR",
62
+ description: `
63
+ - N+1 database query patterns
64
+ - Missing indexes on queries
65
+ - Memory leaks and resource management
66
+ - Algorithm complexity (O(nยฒ) or worse)
67
+ - Inefficient loops and iterations
68
+ - Missing caching opportunities
69
+ - Blocking I/O in async contexts
70
+ `.trim(),
71
+ },
72
+ {
73
+ name: "Code Quality",
74
+ priority: "MAJOR",
75
+ description: `
76
+ - SOLID principle violations
77
+ - Poor error handling
78
+ - Missing edge case handling
79
+ - Code duplication (DRY violations)
80
+ - Poor naming conventions
81
+ - Lack of modularity
82
+ - Insufficient logging
83
+ `.trim(),
84
+ },
85
+ ],
86
+ blockingCriteria: [], // Empty by default - no auto-blocking. Users can add custom criteria in their config.
87
+ excludePatterns: [
88
+ "*.lock",
89
+ "*.svg",
90
+ "*.min.js",
91
+ "*.map",
92
+ "package-lock.json",
93
+ "pnpm-lock.yaml",
94
+ "yarn.lock",
95
+ ],
96
+ contextLines: 3,
97
+ maxFilesPerReview: 100,
98
+ fileAnalysisTimeout: "2m",
99
+ toolPreferences: {
100
+ lazyLoading: true,
101
+ cacheToolResults: true,
102
+ parallelToolCalls: false,
103
+ maxToolCallsPerFile: 20,
104
+ enableCodeSearch: true,
105
+ enableDirectoryListing: true,
106
+ },
107
+ },
108
+ descriptionEnhancement: {
109
+ enabled: true,
110
+ instructions: `Enhance the PR description using Jira requirements and diff analysis.`,
111
+ requiredSections: [
112
+ {
113
+ key: "summary",
114
+ name: "๐Ÿ“‹ Summary",
115
+ required: true,
116
+ description: "Clear overview of what this PR accomplishes",
117
+ },
118
+ {
119
+ key: "changes",
120
+ name: "๐Ÿ”ง Changes Made",
121
+ required: true,
122
+ description: "Specific technical changes with file references",
123
+ },
124
+ {
125
+ key: "jira",
126
+ name: "๐ŸŽซ Jira Reference",
127
+ required: false,
128
+ description: "Link to Jira ticket and requirement coverage",
129
+ },
130
+ {
131
+ key: "testing",
132
+ name: "๐Ÿงช Testing Strategy",
133
+ required: true,
134
+ description: "How changes were tested and validation approach",
135
+ },
136
+ ],
137
+ preserveContent: true,
138
+ autoFormat: true,
139
+ },
140
+ memoryBank: {
141
+ enabled: true,
142
+ path: "memory-bank",
143
+ fallbackPaths: ["docs/memory-bank", ".memory-bank"],
144
+ standardFiles: [
145
+ "project-overview.md",
146
+ "architecture.md",
147
+ "coding-standards.md",
148
+ "security-guidelines.md",
149
+ ],
150
+ },
151
+ knowledgeBase: {
152
+ enabled: true,
153
+ path: ".yama/knowledge-base.md",
154
+ aiAuthorPatterns: ["Yama", "yama-bot", "yama-review"],
155
+ maxEntriesBeforeSummarization: 50,
156
+ summaryRetentionCount: 20,
157
+ autoCommit: false,
158
+ },
159
+ projectStandards: {
160
+ customPromptsPath: "config/prompts/",
161
+ additionalFocusAreas: [],
162
+ customBlockingRules: [],
163
+ severityOverrides: {},
164
+ },
165
+ monitoring: {
166
+ enabled: true,
167
+ logToolCalls: true,
168
+ logAIDecisions: true,
169
+ logTokenUsage: true,
170
+ exportFormat: "json",
171
+ exportPath: ".yama/analytics/",
172
+ },
173
+ performance: {
174
+ maxReviewDuration: "15m",
175
+ tokenBudget: {
176
+ maxTokensPerReview: 500000,
177
+ warningThreshold: 400000,
178
+ },
179
+ costControls: {
180
+ maxCostPerReview: 2.0,
181
+ warningThreshold: 1.5,
182
+ },
183
+ },
184
+ };
185
+ }
186
+ }
187
+ //# sourceMappingURL=DefaultConfig.js.map
@@ -0,0 +1,65 @@
1
+ /**
2
+ * Learning Orchestrator
3
+ * Main entry point for the knowledge base learning feature
4
+ * Orchestrates PR comment extraction, AI analysis, and knowledge base updates
5
+ */
6
+ import { LearnRequest, LearnResult } from "../learning/types.js";
7
+ export declare class LearningOrchestrator {
8
+ private neurolink;
9
+ private mcpManager;
10
+ private configLoader;
11
+ private promptManager;
12
+ private config;
13
+ private initialized;
14
+ constructor();
15
+ /**
16
+ * Initialize the learning orchestrator
17
+ */
18
+ initialize(configPath?: string): Promise<void>;
19
+ /**
20
+ * Extract learnings from a merged PR
21
+ * Uses fully agentic AI approach - AI decides which tools to call
22
+ */
23
+ extractLearnings(request: LearnRequest): Promise<LearnResult>;
24
+ /**
25
+ * Build instructions for Step 1: Fetch PR comments
26
+ */
27
+ private buildFetchCommentsInstructions;
28
+ /**
29
+ * Build instructions for Step 2: Extract learnings from fetched data
30
+ */
31
+ private buildExtractionInstructions;
32
+ /**
33
+ * Parse structured response from AI output
34
+ */
35
+ private parseStructuredLearnings;
36
+ /**
37
+ * Initialize NeuroLink with observability
38
+ */
39
+ private initializeNeurolink;
40
+ /**
41
+ * Ensure orchestrator is initialized
42
+ */
43
+ private ensureInitialized;
44
+ /**
45
+ * Handle dry run mode
46
+ */
47
+ private handleDryRun;
48
+ /**
49
+ * Run AI-powered summarization
50
+ */
51
+ private runSummarization;
52
+ /**
53
+ * Create empty result for cases with no learnings
54
+ */
55
+ private createEmptyResult;
56
+ /**
57
+ * Log the final result
58
+ */
59
+ private logResult;
60
+ }
61
+ /**
62
+ * Factory function to create LearningOrchestrator
63
+ */
64
+ export declare function createLearningOrchestrator(): LearningOrchestrator;
65
+ //# sourceMappingURL=LearningOrchestrator.d.ts.map