@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.
- package/.mcp-config.example.json +26 -0
- package/CHANGELOG.md +40 -0
- package/README.md +311 -685
- package/dist/cli/v2.cli.d.ts +13 -0
- package/dist/cli/v2.cli.js +290 -0
- package/dist/index.d.ts +12 -13
- package/dist/index.js +18 -19
- package/dist/v2/config/ConfigLoader.d.ts +50 -0
- package/dist/v2/config/ConfigLoader.js +205 -0
- package/dist/v2/config/DefaultConfig.d.ts +9 -0
- package/dist/v2/config/DefaultConfig.js +191 -0
- package/dist/v2/core/MCPServerManager.d.ts +22 -0
- package/dist/v2/core/MCPServerManager.js +92 -0
- package/dist/v2/core/SessionManager.d.ts +72 -0
- package/dist/v2/core/SessionManager.js +200 -0
- package/dist/v2/core/YamaV2Orchestrator.d.ts +112 -0
- package/dist/v2/core/YamaV2Orchestrator.js +549 -0
- package/dist/v2/prompts/EnhancementSystemPrompt.d.ts +8 -0
- package/dist/v2/prompts/EnhancementSystemPrompt.js +216 -0
- package/dist/v2/prompts/PromptBuilder.d.ts +38 -0
- package/dist/v2/prompts/PromptBuilder.js +228 -0
- package/dist/v2/prompts/ReviewSystemPrompt.d.ts +8 -0
- package/dist/v2/prompts/ReviewSystemPrompt.js +270 -0
- package/dist/v2/types/config.types.d.ts +120 -0
- package/dist/v2/types/config.types.js +5 -0
- package/dist/v2/types/mcp.types.d.ts +191 -0
- package/dist/v2/types/mcp.types.js +6 -0
- package/dist/v2/types/v2.types.d.ts +182 -0
- package/dist/v2/types/v2.types.js +42 -0
- package/dist/v2/utils/ObservabilityConfig.d.ts +22 -0
- package/dist/v2/utils/ObservabilityConfig.js +48 -0
- package/package.json +11 -9
- package/yama.config.example.yaml +214 -193
- package/dist/cli/index.d.ts +0 -12
- package/dist/cli/index.js +0 -538
- package/dist/core/ContextGatherer.d.ts +0 -110
- package/dist/core/ContextGatherer.js +0 -470
- package/dist/core/Guardian.d.ts +0 -81
- package/dist/core/Guardian.js +0 -474
- package/dist/core/providers/BitbucketProvider.d.ts +0 -105
- package/dist/core/providers/BitbucketProvider.js +0 -489
- package/dist/features/CodeReviewer.d.ts +0 -173
- package/dist/features/CodeReviewer.js +0 -1707
- package/dist/features/DescriptionEnhancer.d.ts +0 -64
- package/dist/features/DescriptionEnhancer.js +0 -445
- package/dist/features/MultiInstanceProcessor.d.ts +0 -74
- package/dist/features/MultiInstanceProcessor.js +0 -360
- package/dist/types/index.d.ts +0 -624
- package/dist/types/index.js +0 -104
- package/dist/utils/Cache.d.ts +0 -103
- package/dist/utils/Cache.js +0 -444
- package/dist/utils/ConfigManager.d.ts +0 -88
- package/dist/utils/ConfigManager.js +0 -603
- package/dist/utils/ContentSimilarityService.d.ts +0 -74
- package/dist/utils/ContentSimilarityService.js +0 -215
- package/dist/utils/ExactDuplicateRemover.d.ts +0 -77
- package/dist/utils/ExactDuplicateRemover.js +0 -361
- package/dist/utils/Logger.d.ts +0 -31
- package/dist/utils/Logger.js +0 -214
- package/dist/utils/MemoryBankManager.d.ts +0 -73
- package/dist/utils/MemoryBankManager.js +0 -310
- package/dist/utils/ParallelProcessing.d.ts +0 -140
- package/dist/utils/ParallelProcessing.js +0 -333
- package/dist/utils/ProviderLimits.d.ts +0 -58
- package/dist/utils/ProviderLimits.js +0 -143
- package/dist/utils/RetryManager.d.ts +0 -78
- package/dist/utils/RetryManager.js +0 -205
|
@@ -0,0 +1,191 @@
|
|
|
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
|
+
jira: {
|
|
35
|
+
enabled: false, // Opt-in: users must explicitly enable Jira integration
|
|
36
|
+
},
|
|
37
|
+
},
|
|
38
|
+
review: {
|
|
39
|
+
enabled: true,
|
|
40
|
+
workflowInstructions: `Follow the autonomous review workflow defined in the base system prompt.`,
|
|
41
|
+
focusAreas: [
|
|
42
|
+
{
|
|
43
|
+
name: "Security Analysis",
|
|
44
|
+
priority: "CRITICAL",
|
|
45
|
+
description: `
|
|
46
|
+
- SQL/NoSQL injection vulnerabilities
|
|
47
|
+
- Cross-Site Scripting (XSS)
|
|
48
|
+
- Authentication/Authorization flaws
|
|
49
|
+
- Hardcoded secrets, API keys, passwords
|
|
50
|
+
- Input validation and sanitization
|
|
51
|
+
- Data exposure and privacy violations
|
|
52
|
+
- Insecure dependencies
|
|
53
|
+
`.trim(),
|
|
54
|
+
},
|
|
55
|
+
{
|
|
56
|
+
name: "Performance Review",
|
|
57
|
+
priority: "MAJOR",
|
|
58
|
+
description: `
|
|
59
|
+
- N+1 database query patterns
|
|
60
|
+
- Missing indexes on queries
|
|
61
|
+
- Memory leaks and resource management
|
|
62
|
+
- Algorithm complexity (O(n²) or worse)
|
|
63
|
+
- Inefficient loops and iterations
|
|
64
|
+
- Missing caching opportunities
|
|
65
|
+
- Blocking I/O in async contexts
|
|
66
|
+
`.trim(),
|
|
67
|
+
},
|
|
68
|
+
{
|
|
69
|
+
name: "Code Quality",
|
|
70
|
+
priority: "MAJOR",
|
|
71
|
+
description: `
|
|
72
|
+
- SOLID principle violations
|
|
73
|
+
- Poor error handling
|
|
74
|
+
- Missing edge case handling
|
|
75
|
+
- Code duplication (DRY violations)
|
|
76
|
+
- Poor naming conventions
|
|
77
|
+
- Lack of modularity
|
|
78
|
+
- Insufficient logging
|
|
79
|
+
`.trim(),
|
|
80
|
+
},
|
|
81
|
+
],
|
|
82
|
+
blockingCriteria: [
|
|
83
|
+
{
|
|
84
|
+
condition: "ANY CRITICAL severity issue",
|
|
85
|
+
action: "BLOCK",
|
|
86
|
+
reason: "Security or data loss risk",
|
|
87
|
+
},
|
|
88
|
+
{
|
|
89
|
+
condition: "3 or more MAJOR severity issues",
|
|
90
|
+
action: "BLOCK",
|
|
91
|
+
reason: "Too many significant bugs/performance issues",
|
|
92
|
+
},
|
|
93
|
+
{
|
|
94
|
+
condition: "Jira requirement coverage < 70% (only when Jira is enabled)",
|
|
95
|
+
action: "BLOCK",
|
|
96
|
+
reason: "Incomplete implementation of requirements",
|
|
97
|
+
},
|
|
98
|
+
],
|
|
99
|
+
excludePatterns: [
|
|
100
|
+
"*.lock",
|
|
101
|
+
"*.svg",
|
|
102
|
+
"*.min.js",
|
|
103
|
+
"*.map",
|
|
104
|
+
"package-lock.json",
|
|
105
|
+
"pnpm-lock.yaml",
|
|
106
|
+
"yarn.lock",
|
|
107
|
+
],
|
|
108
|
+
contextLines: 3,
|
|
109
|
+
maxFilesPerReview: 100,
|
|
110
|
+
fileAnalysisTimeout: "2m",
|
|
111
|
+
toolPreferences: {
|
|
112
|
+
lazyLoading: true,
|
|
113
|
+
cacheToolResults: true,
|
|
114
|
+
parallelToolCalls: false,
|
|
115
|
+
maxToolCallsPerFile: 20,
|
|
116
|
+
enableCodeSearch: true,
|
|
117
|
+
enableDirectoryListing: true,
|
|
118
|
+
},
|
|
119
|
+
},
|
|
120
|
+
descriptionEnhancement: {
|
|
121
|
+
enabled: true,
|
|
122
|
+
instructions: `Enhance the PR description using Jira requirements and diff analysis.`,
|
|
123
|
+
requiredSections: [
|
|
124
|
+
{
|
|
125
|
+
key: "summary",
|
|
126
|
+
name: "📋 Summary",
|
|
127
|
+
required: true,
|
|
128
|
+
description: "Clear overview of what this PR accomplishes",
|
|
129
|
+
},
|
|
130
|
+
{
|
|
131
|
+
key: "changes",
|
|
132
|
+
name: "🔧 Changes Made",
|
|
133
|
+
required: true,
|
|
134
|
+
description: "Specific technical changes with file references",
|
|
135
|
+
},
|
|
136
|
+
{
|
|
137
|
+
key: "jira",
|
|
138
|
+
name: "🎫 Jira Reference",
|
|
139
|
+
required: false,
|
|
140
|
+
description: "Link to Jira ticket and requirement coverage",
|
|
141
|
+
},
|
|
142
|
+
{
|
|
143
|
+
key: "testing",
|
|
144
|
+
name: "🧪 Testing Strategy",
|
|
145
|
+
required: true,
|
|
146
|
+
description: "How changes were tested and validation approach",
|
|
147
|
+
},
|
|
148
|
+
],
|
|
149
|
+
preserveContent: true,
|
|
150
|
+
autoFormat: true,
|
|
151
|
+
},
|
|
152
|
+
memoryBank: {
|
|
153
|
+
enabled: true,
|
|
154
|
+
path: "memory-bank",
|
|
155
|
+
fallbackPaths: ["docs/memory-bank", ".memory-bank"],
|
|
156
|
+
standardFiles: [
|
|
157
|
+
"project-overview.md",
|
|
158
|
+
"architecture.md",
|
|
159
|
+
"coding-standards.md",
|
|
160
|
+
"security-guidelines.md",
|
|
161
|
+
],
|
|
162
|
+
},
|
|
163
|
+
projectStandards: {
|
|
164
|
+
customPromptsPath: "config/prompts/",
|
|
165
|
+
additionalFocusAreas: [],
|
|
166
|
+
customBlockingRules: [],
|
|
167
|
+
severityOverrides: {},
|
|
168
|
+
},
|
|
169
|
+
monitoring: {
|
|
170
|
+
enabled: true,
|
|
171
|
+
logToolCalls: true,
|
|
172
|
+
logAIDecisions: true,
|
|
173
|
+
logTokenUsage: true,
|
|
174
|
+
exportFormat: "json",
|
|
175
|
+
exportPath: ".yama/analytics/",
|
|
176
|
+
},
|
|
177
|
+
performance: {
|
|
178
|
+
maxReviewDuration: "15m",
|
|
179
|
+
tokenBudget: {
|
|
180
|
+
maxTokensPerReview: 500000,
|
|
181
|
+
warningThreshold: 400000,
|
|
182
|
+
},
|
|
183
|
+
costControls: {
|
|
184
|
+
maxCostPerReview: 2.0,
|
|
185
|
+
warningThreshold: 1.5,
|
|
186
|
+
},
|
|
187
|
+
},
|
|
188
|
+
};
|
|
189
|
+
}
|
|
190
|
+
}
|
|
191
|
+
//# sourceMappingURL=DefaultConfig.js.map
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* MCP Server Manager for Yama V2
|
|
3
|
+
* Manages lifecycle and health of Bitbucket and Jira MCP servers
|
|
4
|
+
*/
|
|
5
|
+
import { MCPServersConfig } from "../types/config.types.js";
|
|
6
|
+
export declare class MCPServerManager {
|
|
7
|
+
private initialized;
|
|
8
|
+
/**
|
|
9
|
+
* Setup all MCP servers in NeuroLink
|
|
10
|
+
* Bitbucket is always enabled, Jira is optional based on config
|
|
11
|
+
*/
|
|
12
|
+
setupMCPServers(neurolink: any, config: MCPServersConfig): Promise<void>;
|
|
13
|
+
/**
|
|
14
|
+
* Setup Bitbucket MCP server (hardcoded, always enabled)
|
|
15
|
+
*/
|
|
16
|
+
private setupBitbucketMCP;
|
|
17
|
+
/**
|
|
18
|
+
* Setup Jira MCP server (hardcoded, optionally enabled)
|
|
19
|
+
*/
|
|
20
|
+
private setupJiraMCP;
|
|
21
|
+
}
|
|
22
|
+
//# sourceMappingURL=MCPServerManager.d.ts.map
|
|
@@ -0,0 +1,92 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* MCP Server Manager for Yama V2
|
|
3
|
+
* Manages lifecycle and health of Bitbucket and Jira MCP servers
|
|
4
|
+
*/
|
|
5
|
+
import { MCPServerError } from "../types/v2.types.js";
|
|
6
|
+
export class MCPServerManager {
|
|
7
|
+
// MCP servers are managed entirely by NeuroLink
|
|
8
|
+
// No need to track tools locally
|
|
9
|
+
initialized = false;
|
|
10
|
+
/**
|
|
11
|
+
* Setup all MCP servers in NeuroLink
|
|
12
|
+
* Bitbucket is always enabled, Jira is optional based on config
|
|
13
|
+
*/
|
|
14
|
+
async setupMCPServers(neurolink, config) {
|
|
15
|
+
console.log("🔌 Setting up MCP servers...");
|
|
16
|
+
// Setup Bitbucket MCP (always enabled)
|
|
17
|
+
await this.setupBitbucketMCP(neurolink);
|
|
18
|
+
// Setup Jira MCP (optional)
|
|
19
|
+
if (config.jira.enabled) {
|
|
20
|
+
await this.setupJiraMCP(neurolink);
|
|
21
|
+
}
|
|
22
|
+
else {
|
|
23
|
+
console.log(" ⏭️ Jira MCP disabled in config");
|
|
24
|
+
}
|
|
25
|
+
this.initialized = true;
|
|
26
|
+
console.log("✅ MCP servers configured\n");
|
|
27
|
+
}
|
|
28
|
+
/**
|
|
29
|
+
* Setup Bitbucket MCP server (hardcoded, always enabled)
|
|
30
|
+
*/
|
|
31
|
+
async setupBitbucketMCP(neurolink) {
|
|
32
|
+
try {
|
|
33
|
+
console.log(" 🔧 Registering Bitbucket MCP server...");
|
|
34
|
+
// Verify environment variables
|
|
35
|
+
if (!process.env.BITBUCKET_USERNAME ||
|
|
36
|
+
!process.env.BITBUCKET_TOKEN ||
|
|
37
|
+
!process.env.BITBUCKET_BASE_URL) {
|
|
38
|
+
throw new MCPServerError("Missing required environment variables: BITBUCKET_USERNAME, BITBUCKET_TOKEN, or BITBUCKET_BASE_URL");
|
|
39
|
+
}
|
|
40
|
+
// Hardcoded Bitbucket MCP configuration
|
|
41
|
+
await neurolink.addExternalMCPServer("bitbucket", {
|
|
42
|
+
command: "npx",
|
|
43
|
+
args: ["-y", "@nexus2520/bitbucket-mcp-server"],
|
|
44
|
+
transport: "stdio",
|
|
45
|
+
env: {
|
|
46
|
+
BITBUCKET_USERNAME: process.env.BITBUCKET_USERNAME,
|
|
47
|
+
BITBUCKET_TOKEN: process.env.BITBUCKET_TOKEN,
|
|
48
|
+
BITBUCKET_BASE_URL: process.env.BITBUCKET_BASE_URL,
|
|
49
|
+
},
|
|
50
|
+
});
|
|
51
|
+
console.log(" ✅ Bitbucket MCP server registered and tools available");
|
|
52
|
+
}
|
|
53
|
+
catch (error) {
|
|
54
|
+
throw new MCPServerError(`Failed to setup Bitbucket MCP server: ${error.message}`);
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
/**
|
|
58
|
+
* Setup Jira MCP server (hardcoded, optionally enabled)
|
|
59
|
+
*/
|
|
60
|
+
async setupJiraMCP(neurolink) {
|
|
61
|
+
try {
|
|
62
|
+
console.log(" 🔧 Registering Jira MCP server...");
|
|
63
|
+
// Validate required Jira environment variables
|
|
64
|
+
const jiraEmail = process.env.JIRA_EMAIL;
|
|
65
|
+
const jiraToken = process.env.JIRA_API_TOKEN;
|
|
66
|
+
const jiraBaseUrl = process.env.JIRA_BASE_URL;
|
|
67
|
+
if (!jiraEmail || !jiraToken || !jiraBaseUrl) {
|
|
68
|
+
console.warn(" ⚠️ Missing Jira environment variables (JIRA_EMAIL, JIRA_API_TOKEN, or JIRA_BASE_URL)");
|
|
69
|
+
console.warn(" Skipping Jira integration...");
|
|
70
|
+
return;
|
|
71
|
+
}
|
|
72
|
+
// Hardcoded Jira MCP configuration
|
|
73
|
+
await neurolink.addExternalMCPServer("jira", {
|
|
74
|
+
command: "npx",
|
|
75
|
+
args: ["-y", "@nexus2520/jira-mcp-server"],
|
|
76
|
+
transport: "stdio",
|
|
77
|
+
env: {
|
|
78
|
+
JIRA_EMAIL: process.env.JIRA_EMAIL,
|
|
79
|
+
JIRA_API_TOKEN: process.env.JIRA_API_TOKEN,
|
|
80
|
+
JIRA_BASE_URL: process.env.JIRA_BASE_URL,
|
|
81
|
+
},
|
|
82
|
+
});
|
|
83
|
+
console.log(" ✅ Jira MCP server registered and tools available");
|
|
84
|
+
}
|
|
85
|
+
catch (error) {
|
|
86
|
+
// Jira is optional, so we warn instead of throwing
|
|
87
|
+
console.warn(` ⚠️ Failed to setup Jira MCP server: ${error.message}`);
|
|
88
|
+
console.warn(" Continuing without Jira integration...");
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
//# sourceMappingURL=MCPServerManager.js.map
|
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Session Manager for Yama V2
|
|
3
|
+
* Tracks review sessions, tool calls, and maintains state
|
|
4
|
+
*/
|
|
5
|
+
import { ReviewSession, ReviewRequest, ReviewResult, SessionMetadata } from "../types/v2.types.js";
|
|
6
|
+
export declare class SessionManager {
|
|
7
|
+
private sessions;
|
|
8
|
+
private maxSessions;
|
|
9
|
+
/**
|
|
10
|
+
* Create a new review session
|
|
11
|
+
*/
|
|
12
|
+
createSession(request: ReviewRequest): string;
|
|
13
|
+
/**
|
|
14
|
+
* Get session by ID
|
|
15
|
+
*/
|
|
16
|
+
getSession(sessionId: string): ReviewSession;
|
|
17
|
+
/**
|
|
18
|
+
* Record a tool call in the session
|
|
19
|
+
*/
|
|
20
|
+
recordToolCall(sessionId: string, toolName: string, args: any, result: any, duration: number, error?: string): void;
|
|
21
|
+
/**
|
|
22
|
+
* Update session metadata
|
|
23
|
+
*/
|
|
24
|
+
updateMetadata(sessionId: string, updates: Partial<SessionMetadata>): void;
|
|
25
|
+
/**
|
|
26
|
+
* Mark session as completed
|
|
27
|
+
*/
|
|
28
|
+
completeSession(sessionId: string, result: ReviewResult): void;
|
|
29
|
+
/**
|
|
30
|
+
* Mark session as failed
|
|
31
|
+
*/
|
|
32
|
+
failSession(sessionId: string, error: Error): void;
|
|
33
|
+
/**
|
|
34
|
+
* Get all active sessions
|
|
35
|
+
*/
|
|
36
|
+
getActiveSessions(): ReviewSession[];
|
|
37
|
+
/**
|
|
38
|
+
* Get session statistics
|
|
39
|
+
*/
|
|
40
|
+
getSessionStats(sessionId: string): {
|
|
41
|
+
duration: number;
|
|
42
|
+
toolCallCount: number;
|
|
43
|
+
uniqueTools: number;
|
|
44
|
+
averageToolCallDuration: number;
|
|
45
|
+
toolCallsByName: Record<string, number>;
|
|
46
|
+
};
|
|
47
|
+
/**
|
|
48
|
+
* Generate unique session ID
|
|
49
|
+
*/
|
|
50
|
+
private generateSessionId;
|
|
51
|
+
/**
|
|
52
|
+
* Clean up old sessions (keep most recent 100)
|
|
53
|
+
*/
|
|
54
|
+
private cleanupOldSessions;
|
|
55
|
+
/**
|
|
56
|
+
* Export session data for debugging
|
|
57
|
+
*/
|
|
58
|
+
exportSession(sessionId: string): any;
|
|
59
|
+
/**
|
|
60
|
+
* Summarize tool result for logging
|
|
61
|
+
*/
|
|
62
|
+
private summarizeToolResult;
|
|
63
|
+
/**
|
|
64
|
+
* Clear all sessions
|
|
65
|
+
*/
|
|
66
|
+
clearAll(): void;
|
|
67
|
+
/**
|
|
68
|
+
* Get session count
|
|
69
|
+
*/
|
|
70
|
+
getSessionCount(): number;
|
|
71
|
+
}
|
|
72
|
+
//# sourceMappingURL=SessionManager.d.ts.map
|
|
@@ -0,0 +1,200 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Session Manager for Yama V2
|
|
3
|
+
* Tracks review sessions, tool calls, and maintains state
|
|
4
|
+
*/
|
|
5
|
+
import { randomBytes } from "crypto";
|
|
6
|
+
export class SessionManager {
|
|
7
|
+
sessions = new Map();
|
|
8
|
+
maxSessions = 100;
|
|
9
|
+
/**
|
|
10
|
+
* Create a new review session
|
|
11
|
+
*/
|
|
12
|
+
createSession(request) {
|
|
13
|
+
const sessionId = this.generateSessionId();
|
|
14
|
+
const session = {
|
|
15
|
+
sessionId,
|
|
16
|
+
request,
|
|
17
|
+
startTime: new Date(),
|
|
18
|
+
status: "running",
|
|
19
|
+
toolCalls: [],
|
|
20
|
+
metadata: {
|
|
21
|
+
yamaVersion: "2.0.0",
|
|
22
|
+
aiProvider: "auto",
|
|
23
|
+
aiModel: "unknown",
|
|
24
|
+
totalTokens: 0,
|
|
25
|
+
totalCost: 0,
|
|
26
|
+
cacheHitRatio: 0,
|
|
27
|
+
},
|
|
28
|
+
};
|
|
29
|
+
this.sessions.set(sessionId, session);
|
|
30
|
+
// Clean up old sessions if we exceed max
|
|
31
|
+
if (this.sessions.size > this.maxSessions) {
|
|
32
|
+
this.cleanupOldSessions();
|
|
33
|
+
}
|
|
34
|
+
return sessionId;
|
|
35
|
+
}
|
|
36
|
+
/**
|
|
37
|
+
* Get session by ID
|
|
38
|
+
*/
|
|
39
|
+
getSession(sessionId) {
|
|
40
|
+
const session = this.sessions.get(sessionId);
|
|
41
|
+
if (!session) {
|
|
42
|
+
throw new Error(`Session not found: ${sessionId}`);
|
|
43
|
+
}
|
|
44
|
+
return session;
|
|
45
|
+
}
|
|
46
|
+
/**
|
|
47
|
+
* Record a tool call in the session
|
|
48
|
+
*/
|
|
49
|
+
recordToolCall(sessionId, toolName, args, result, duration, error) {
|
|
50
|
+
const session = this.getSession(sessionId);
|
|
51
|
+
const toolCall = {
|
|
52
|
+
timestamp: new Date(),
|
|
53
|
+
toolName,
|
|
54
|
+
args,
|
|
55
|
+
result,
|
|
56
|
+
error,
|
|
57
|
+
duration,
|
|
58
|
+
};
|
|
59
|
+
session.toolCalls.push(toolCall);
|
|
60
|
+
}
|
|
61
|
+
/**
|
|
62
|
+
* Update session metadata
|
|
63
|
+
*/
|
|
64
|
+
updateMetadata(sessionId, updates) {
|
|
65
|
+
const session = this.getSession(sessionId);
|
|
66
|
+
session.metadata = {
|
|
67
|
+
...session.metadata,
|
|
68
|
+
...updates,
|
|
69
|
+
};
|
|
70
|
+
}
|
|
71
|
+
/**
|
|
72
|
+
* Mark session as completed
|
|
73
|
+
*/
|
|
74
|
+
completeSession(sessionId, result) {
|
|
75
|
+
const session = this.getSession(sessionId);
|
|
76
|
+
session.status = "completed";
|
|
77
|
+
session.endTime = new Date();
|
|
78
|
+
session.result = result;
|
|
79
|
+
}
|
|
80
|
+
/**
|
|
81
|
+
* Mark session as failed
|
|
82
|
+
*/
|
|
83
|
+
failSession(sessionId, error) {
|
|
84
|
+
const session = this.getSession(sessionId);
|
|
85
|
+
session.status = "failed";
|
|
86
|
+
session.endTime = new Date();
|
|
87
|
+
session.error = error;
|
|
88
|
+
}
|
|
89
|
+
/**
|
|
90
|
+
* Get all active sessions
|
|
91
|
+
*/
|
|
92
|
+
getActiveSessions() {
|
|
93
|
+
return Array.from(this.sessions.values()).filter((s) => s.status === "running");
|
|
94
|
+
}
|
|
95
|
+
/**
|
|
96
|
+
* Get session statistics
|
|
97
|
+
*/
|
|
98
|
+
getSessionStats(sessionId) {
|
|
99
|
+
const session = this.getSession(sessionId);
|
|
100
|
+
const duration = session.endTime
|
|
101
|
+
? session.endTime.getTime() - session.startTime.getTime()
|
|
102
|
+
: Date.now() - session.startTime.getTime();
|
|
103
|
+
const toolCallsByName = {};
|
|
104
|
+
let totalToolDuration = 0;
|
|
105
|
+
session.toolCalls.forEach((tc) => {
|
|
106
|
+
toolCallsByName[tc.toolName] = (toolCallsByName[tc.toolName] || 0) + 1;
|
|
107
|
+
totalToolDuration += tc.duration;
|
|
108
|
+
});
|
|
109
|
+
return {
|
|
110
|
+
duration: Math.round(duration / 1000), // seconds
|
|
111
|
+
toolCallCount: session.toolCalls.length,
|
|
112
|
+
uniqueTools: Object.keys(toolCallsByName).length,
|
|
113
|
+
averageToolCallDuration: session.toolCalls.length > 0
|
|
114
|
+
? Math.round(totalToolDuration / session.toolCalls.length)
|
|
115
|
+
: 0,
|
|
116
|
+
toolCallsByName,
|
|
117
|
+
};
|
|
118
|
+
}
|
|
119
|
+
/**
|
|
120
|
+
* Generate unique session ID
|
|
121
|
+
*/
|
|
122
|
+
generateSessionId() {
|
|
123
|
+
const timestamp = Date.now().toString(36);
|
|
124
|
+
const random = randomBytes(4).toString("hex");
|
|
125
|
+
return `yama-v2-${timestamp}-${random}`;
|
|
126
|
+
}
|
|
127
|
+
/**
|
|
128
|
+
* Clean up old sessions (keep most recent 100)
|
|
129
|
+
*/
|
|
130
|
+
cleanupOldSessions() {
|
|
131
|
+
const sessions = Array.from(this.sessions.entries());
|
|
132
|
+
// Sort by start time (oldest first)
|
|
133
|
+
sessions.sort((a, b) => {
|
|
134
|
+
return a[1].startTime.getTime() - b[1].startTime.getTime();
|
|
135
|
+
});
|
|
136
|
+
// Remove oldest sessions
|
|
137
|
+
const toRemove = sessions.length - this.maxSessions;
|
|
138
|
+
for (let i = 0; i < toRemove; i++) {
|
|
139
|
+
this.sessions.delete(sessions[i][0]);
|
|
140
|
+
}
|
|
141
|
+
}
|
|
142
|
+
/**
|
|
143
|
+
* Export session data for debugging
|
|
144
|
+
*/
|
|
145
|
+
exportSession(sessionId) {
|
|
146
|
+
const session = this.getSession(sessionId);
|
|
147
|
+
const stats = this.getSessionStats(sessionId);
|
|
148
|
+
return {
|
|
149
|
+
session: {
|
|
150
|
+
sessionId: session.sessionId,
|
|
151
|
+
request: session.request,
|
|
152
|
+
startTime: session.startTime.toISOString(),
|
|
153
|
+
endTime: session.endTime?.toISOString(),
|
|
154
|
+
status: session.status,
|
|
155
|
+
metadata: session.metadata,
|
|
156
|
+
result: session.result,
|
|
157
|
+
error: session.error?.message,
|
|
158
|
+
},
|
|
159
|
+
statistics: stats,
|
|
160
|
+
toolCalls: session.toolCalls.map((tc) => ({
|
|
161
|
+
timestamp: tc.timestamp.toISOString(),
|
|
162
|
+
toolName: tc.toolName,
|
|
163
|
+
args: tc.args,
|
|
164
|
+
duration: tc.duration,
|
|
165
|
+
error: tc.error,
|
|
166
|
+
// Don't include full result in export (can be very large)
|
|
167
|
+
resultSummary: this.summarizeToolResult(tc.result),
|
|
168
|
+
})),
|
|
169
|
+
};
|
|
170
|
+
}
|
|
171
|
+
/**
|
|
172
|
+
* Summarize tool result for logging
|
|
173
|
+
*/
|
|
174
|
+
summarizeToolResult(result) {
|
|
175
|
+
if (!result) {
|
|
176
|
+
return "null";
|
|
177
|
+
}
|
|
178
|
+
if (typeof result === "string") {
|
|
179
|
+
return result.length > 100 ? `${result.substring(0, 100)}...` : result;
|
|
180
|
+
}
|
|
181
|
+
if (typeof result === "object") {
|
|
182
|
+
const keys = Object.keys(result);
|
|
183
|
+
return `{${keys.slice(0, 5).join(", ")}${keys.length > 5 ? ", ..." : ""}}`;
|
|
184
|
+
}
|
|
185
|
+
return String(result);
|
|
186
|
+
}
|
|
187
|
+
/**
|
|
188
|
+
* Clear all sessions
|
|
189
|
+
*/
|
|
190
|
+
clearAll() {
|
|
191
|
+
this.sessions.clear();
|
|
192
|
+
}
|
|
193
|
+
/**
|
|
194
|
+
* Get session count
|
|
195
|
+
*/
|
|
196
|
+
getSessionCount() {
|
|
197
|
+
return this.sessions.size;
|
|
198
|
+
}
|
|
199
|
+
}
|
|
200
|
+
//# sourceMappingURL=SessionManager.js.map
|
|
@@ -0,0 +1,112 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Yama V2 Orchestrator
|
|
3
|
+
* Main entry point for AI-native autonomous code review
|
|
4
|
+
*/
|
|
5
|
+
import { ReviewRequest, ReviewResult, ReviewUpdate } from "../types/v2.types.js";
|
|
6
|
+
export declare class YamaV2Orchestrator {
|
|
7
|
+
private neurolink;
|
|
8
|
+
private mcpManager;
|
|
9
|
+
private configLoader;
|
|
10
|
+
private promptBuilder;
|
|
11
|
+
private sessionManager;
|
|
12
|
+
private config;
|
|
13
|
+
private initialized;
|
|
14
|
+
constructor();
|
|
15
|
+
/**
|
|
16
|
+
* Initialize Yama V2 with configuration and MCP servers
|
|
17
|
+
*/
|
|
18
|
+
initialize(configPath?: string): Promise<void>;
|
|
19
|
+
/**
|
|
20
|
+
* Start autonomous AI review
|
|
21
|
+
*/
|
|
22
|
+
startReview(request: ReviewRequest): Promise<ReviewResult>;
|
|
23
|
+
/**
|
|
24
|
+
* Stream review with real-time updates (for verbose mode)
|
|
25
|
+
*/
|
|
26
|
+
streamReview(request: ReviewRequest): AsyncIterableIterator<ReviewUpdate>;
|
|
27
|
+
/**
|
|
28
|
+
* Start review and then enhance description in the same session
|
|
29
|
+
* This allows the AI to use knowledge gained during review to write better descriptions
|
|
30
|
+
*/
|
|
31
|
+
startReviewAndEnhance(request: ReviewRequest): Promise<ReviewResult>;
|
|
32
|
+
/**
|
|
33
|
+
* Enhance PR description only (without full review)
|
|
34
|
+
*/
|
|
35
|
+
enhanceDescription(request: ReviewRequest): Promise<any>;
|
|
36
|
+
/**
|
|
37
|
+
* Get session information
|
|
38
|
+
*/
|
|
39
|
+
getSession(sessionId: string): import("../types/v2.types.js").ReviewSession;
|
|
40
|
+
/**
|
|
41
|
+
* Get session statistics
|
|
42
|
+
*/
|
|
43
|
+
getSessionStats(sessionId: string): {
|
|
44
|
+
duration: number;
|
|
45
|
+
toolCallCount: number;
|
|
46
|
+
uniqueTools: number;
|
|
47
|
+
averageToolCallDuration: number;
|
|
48
|
+
toolCallsByName: Record<string, number>;
|
|
49
|
+
};
|
|
50
|
+
/**
|
|
51
|
+
* Export session data
|
|
52
|
+
*/
|
|
53
|
+
exportSession(sessionId: string): any;
|
|
54
|
+
/**
|
|
55
|
+
* Create tool context for AI
|
|
56
|
+
*/
|
|
57
|
+
private createToolContext;
|
|
58
|
+
/**
|
|
59
|
+
* Parse AI response into structured review result
|
|
60
|
+
*/
|
|
61
|
+
private parseReviewResult;
|
|
62
|
+
/**
|
|
63
|
+
* Extract decision from AI response
|
|
64
|
+
*/
|
|
65
|
+
private extractDecision;
|
|
66
|
+
/**
|
|
67
|
+
* Calculate statistics from session
|
|
68
|
+
*/
|
|
69
|
+
private calculateStatistics;
|
|
70
|
+
/**
|
|
71
|
+
* Extract issue counts from comment tool calls
|
|
72
|
+
*/
|
|
73
|
+
private extractIssueCountsFromComments;
|
|
74
|
+
/**
|
|
75
|
+
* Extract summary from AI response
|
|
76
|
+
*/
|
|
77
|
+
private extractSummary;
|
|
78
|
+
/**
|
|
79
|
+
* Calculate cost estimate from token usage
|
|
80
|
+
*/
|
|
81
|
+
private calculateCost;
|
|
82
|
+
/**
|
|
83
|
+
* Generate userId for NeuroLink context from repository and branch/PR
|
|
84
|
+
*/
|
|
85
|
+
private generateUserId;
|
|
86
|
+
/**
|
|
87
|
+
* Initialize NeuroLink with observability configuration
|
|
88
|
+
*/
|
|
89
|
+
private initializeNeurolink;
|
|
90
|
+
/**
|
|
91
|
+
* Ensure orchestrator is initialized
|
|
92
|
+
*/
|
|
93
|
+
private ensureInitialized;
|
|
94
|
+
/**
|
|
95
|
+
* Show Yama V2 banner
|
|
96
|
+
*/
|
|
97
|
+
private showBanner;
|
|
98
|
+
/**
|
|
99
|
+
* Log review start
|
|
100
|
+
*/
|
|
101
|
+
private logReviewStart;
|
|
102
|
+
/**
|
|
103
|
+
* Log review completion
|
|
104
|
+
*/
|
|
105
|
+
private logReviewComplete;
|
|
106
|
+
/**
|
|
107
|
+
* Format decision for display
|
|
108
|
+
*/
|
|
109
|
+
private formatDecision;
|
|
110
|
+
}
|
|
111
|
+
export declare function createYamaV2(): YamaV2Orchestrator;
|
|
112
|
+
//# sourceMappingURL=YamaV2Orchestrator.d.ts.map
|