@juspay/yama 2.2.1 → 2.3.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 (35) hide show
  1. package/CHANGELOG.md +14 -0
  2. package/LICENSE +21 -0
  3. package/README.md +73 -110
  4. package/dist/cli/cli.d.ts +13 -0
  5. package/dist/cli/cli.js +341 -0
  6. package/dist/cli/v2.cli.d.ts +2 -11
  7. package/dist/cli/v2.cli.js +4 -354
  8. package/dist/index.d.ts +7 -5
  9. package/dist/index.js +5 -3
  10. package/dist/v2/config/ConfigLoader.d.ts +20 -5
  11. package/dist/v2/config/ConfigLoader.js +76 -24
  12. package/dist/v2/config/DefaultConfig.d.ts +3 -3
  13. package/dist/v2/config/DefaultConfig.js +9 -2
  14. package/dist/v2/core/LearningOrchestrator.d.ts +1 -0
  15. package/dist/v2/core/LearningOrchestrator.js +64 -4
  16. package/dist/v2/core/LocalDiffSource.d.ts +26 -0
  17. package/dist/v2/core/LocalDiffSource.js +129 -0
  18. package/dist/v2/core/MCPServerManager.d.ts +13 -1
  19. package/dist/v2/core/MCPServerManager.js +111 -7
  20. package/dist/v2/core/SessionManager.d.ts +1 -1
  21. package/dist/v2/core/SessionManager.js +3 -3
  22. package/dist/v2/core/YamaV2Orchestrator.d.ts +48 -13
  23. package/dist/v2/core/YamaV2Orchestrator.js +543 -63
  24. package/dist/v2/learning/types.d.ts +10 -0
  25. package/dist/v2/memory/MemoryManager.d.ts +57 -0
  26. package/dist/v2/memory/MemoryManager.js +185 -0
  27. package/dist/v2/prompts/PromptBuilder.d.ts +10 -4
  28. package/dist/v2/prompts/PromptBuilder.js +94 -3
  29. package/dist/v2/prompts/ReviewSystemPrompt.d.ts +1 -1
  30. package/dist/v2/prompts/ReviewSystemPrompt.js +7 -5
  31. package/dist/v2/types/config.types.d.ts +61 -1
  32. package/dist/v2/types/v2.types.d.ts +66 -5
  33. package/dist/v2/types/v2.types.js +8 -6
  34. package/package.json +20 -15
  35. package/yama.config.example.yaml +23 -5
@@ -8,12 +8,14 @@ import { MCPServerManager } from "./MCPServerManager.js";
8
8
  import { ConfigLoader } from "../config/ConfigLoader.js";
9
9
  import { LangfusePromptManager } from "../prompts/LangfusePromptManager.js";
10
10
  import { KnowledgeBaseManager } from "../learning/KnowledgeBaseManager.js";
11
+ import { MemoryManager } from "../memory/MemoryManager.js";
11
12
  import { buildObservabilityConfigFromEnv, validateObservabilityConfig, } from "../utils/ObservabilityConfig.js";
12
13
  export class LearningOrchestrator {
13
14
  neurolink;
14
15
  mcpManager;
15
16
  configLoader;
16
17
  promptManager;
18
+ memoryManager = null;
17
19
  config;
18
20
  initialized = false;
19
21
  constructor() {
@@ -32,7 +34,12 @@ export class LearningOrchestrator {
32
34
  try {
33
35
  // Load configuration
34
36
  this.config = await this.configLoader.loadConfig(configPath);
35
- // Initialize NeuroLink
37
+ // Initialize Memory Manager (if enabled) — must happen before NeuroLink
38
+ if (this.config.memory?.enabled) {
39
+ this.memoryManager = new MemoryManager(this.config.memory, this.config.ai.provider, this.config.ai.model);
40
+ console.log(" 🧠 Per-repo memory enabled\n");
41
+ }
42
+ // Initialize NeuroLink with memory config injected
36
43
  console.log(" 🔧 Initializing NeuroLink AI engine...");
37
44
  this.neurolink = this.initializeNeurolink();
38
45
  console.log(" ✅ NeuroLink initialized\n");
@@ -126,6 +133,52 @@ export class LearningOrchestrator {
126
133
  if (duplicateCount > 0) {
127
134
  console.log(` ⏭️ Skipped ${duplicateCount} duplicates`);
128
135
  }
136
+ // Resolve commit mode: commitMode takes precedence, fall back to legacy commit flag
137
+ const commitMode = request.commitMode ||
138
+ (request.commit || this.config.knowledgeBase.autoCommit
139
+ ? "kb"
140
+ : undefined);
141
+ const shouldCommitMemory = commitMode === "memory" || commitMode === "all";
142
+ const shouldCommitKb = commitMode === "kb" || commitMode === "all";
143
+ // Store learnings in per-repo memory via NeuroLink
144
+ // read: false (we don't need to read memory here)
145
+ // write: true (condense learnings into memory file)
146
+ if (this.memoryManager && addedCount > 0 && shouldCommitMemory) {
147
+ try {
148
+ const byCategory = new Map();
149
+ for (const l of learnings) {
150
+ const cat = l.category.replace(/_/g, " ");
151
+ if (!byCategory.has(cat)) {
152
+ byCategory.set(cat, []);
153
+ }
154
+ byCategory.get(cat).push(l.learning);
155
+ }
156
+ const parts = [];
157
+ for (const [category, items] of byCategory) {
158
+ parts.push(`${category}: ${items.join("; ")}`);
159
+ }
160
+ const ownerId = MemoryManager.buildOwnerId(request.workspace, request.repository);
161
+ await this.neurolink.generate({
162
+ input: { text: parts.join(". ") },
163
+ provider: this.config.ai.provider,
164
+ model: this.config.ai.model,
165
+ temperature: 0.1,
166
+ maxTokens: 100,
167
+ disableTools: true,
168
+ context: {
169
+ userId: ownerId,
170
+ operation: "memory-store-learnings",
171
+ },
172
+ memory: { read: false, write: true },
173
+ });
174
+ console.log(` 🧠 Learning memory stored for ${ownerId}`);
175
+ // Auto-commit and push memory files to repo
176
+ await this.memoryManager.commitMemoryChanges();
177
+ }
178
+ catch (error) {
179
+ console.warn(` ⚠️ Failed to store learning memory: ${error.message}`);
180
+ }
181
+ }
129
182
  // Check if summarization is needed
130
183
  let summarized = false;
131
184
  if (request.summarize || (await kbManager.needsSummarization())) {
@@ -134,9 +187,9 @@ export class LearningOrchestrator {
134
187
  summarized = true;
135
188
  console.log(" ✅ Summarization complete");
136
189
  }
137
- // Commit if requested
190
+ // Commit knowledge base if requested
138
191
  let committed = false;
139
- if (request.commit || this.config.knowledgeBase.autoCommit) {
192
+ if (shouldCommitKb) {
140
193
  console.log("\n📤 Committing knowledge base...");
141
194
  await kbManager.commit(request.pullRequestId, addedCount);
142
195
  committed = true;
@@ -352,8 +405,15 @@ Analyze the PR data above and extract learnings.
352
405
  */
353
406
  initializeNeurolink() {
354
407
  const observabilityConfig = buildObservabilityConfigFromEnv();
408
+ const conversationMemory = {
409
+ ...this.config.ai.conversationMemory,
410
+ };
411
+ if (this.memoryManager) {
412
+ conversationMemory.memory =
413
+ this.memoryManager.buildNeuroLinkMemoryConfig();
414
+ }
355
415
  const neurolinkConfig = {
356
- conversationMemory: this.config.ai.conversationMemory,
416
+ conversationMemory,
357
417
  };
358
418
  if (observabilityConfig &&
359
419
  validateObservabilityConfig(observabilityConfig)) {
@@ -0,0 +1,26 @@
1
+ /**
2
+ * Local diff source for SDK mode.
3
+ * Extracts git diffs from a local repository without requiring MCP tools.
4
+ */
5
+ import { LocalReviewRequest } from "../types/v2.types.js";
6
+ export interface LocalDiffContext {
7
+ repoPath: string;
8
+ diffSource: "staged" | "uncommitted" | "range";
9
+ baseRef?: string;
10
+ headRef?: string;
11
+ changedFiles: string[];
12
+ additions: number;
13
+ deletions: number;
14
+ diff: string;
15
+ truncated: boolean;
16
+ }
17
+ export declare class LocalDiffSource {
18
+ getDiffContext(request: LocalReviewRequest): LocalDiffContext;
19
+ private ensureGitRepo;
20
+ private runGit;
21
+ private buildDiffArgs;
22
+ private buildNameOnlyArgs;
23
+ private buildNumStatArgs;
24
+ private parseNumStat;
25
+ }
26
+ //# sourceMappingURL=LocalDiffSource.d.ts.map
@@ -0,0 +1,129 @@
1
+ /**
2
+ * Local diff source for SDK mode.
3
+ * Extracts git diffs from a local repository without requiring MCP tools.
4
+ */
5
+ import { existsSync } from "fs";
6
+ import { resolve } from "path";
7
+ import { spawnSync } from "child_process";
8
+ export class LocalDiffSource {
9
+ getDiffContext(request) {
10
+ const repoPath = resolve(request.repoPath || process.cwd());
11
+ if (!existsSync(repoPath)) {
12
+ throw new Error(`Repository path does not exist: ${repoPath}`);
13
+ }
14
+ this.ensureGitRepo(repoPath);
15
+ const diffSource = request.diffSource || "uncommitted";
16
+ const includePaths = request.includePaths || [];
17
+ const maxDiffChars = request.maxDiffChars || 120_000;
18
+ const contextLines = 3;
19
+ const diffArgs = this.buildDiffArgs(diffSource, request.baseRef, request.headRef, contextLines, includePaths);
20
+ const nameOnlyArgs = this.buildNameOnlyArgs(diffSource, request.baseRef, request.headRef, includePaths);
21
+ const numStatArgs = this.buildNumStatArgs(diffSource, request.baseRef, request.headRef, includePaths);
22
+ const diffOutput = this.runGit(repoPath, diffArgs);
23
+ const changedFilesOutput = this.runGit(repoPath, nameOnlyArgs);
24
+ const numStatOutput = this.runGit(repoPath, numStatArgs);
25
+ const changedFiles = changedFilesOutput
26
+ .split("\n")
27
+ .map((line) => line.trim())
28
+ .filter(Boolean);
29
+ const { additions, deletions } = this.parseNumStat(numStatOutput);
30
+ const truncated = diffOutput.length > maxDiffChars;
31
+ const diff = truncated ? diffOutput.slice(0, maxDiffChars) : diffOutput;
32
+ return {
33
+ repoPath,
34
+ diffSource,
35
+ baseRef: diffSource === "range" ? request.baseRef : undefined,
36
+ headRef: diffSource === "range" ? request.headRef || "HEAD" : undefined,
37
+ changedFiles,
38
+ additions,
39
+ deletions,
40
+ diff,
41
+ truncated,
42
+ };
43
+ }
44
+ ensureGitRepo(repoPath) {
45
+ const probe = spawnSync("git", ["rev-parse", "--is-inside-work-tree"], {
46
+ cwd: repoPath,
47
+ encoding: "utf-8",
48
+ });
49
+ if (probe.status !== 0 || probe.stdout.trim() !== "true") {
50
+ throw new Error(`Path is not a git repository: ${repoPath}`);
51
+ }
52
+ }
53
+ runGit(repoPath, args) {
54
+ const result = spawnSync("git", args, {
55
+ cwd: repoPath,
56
+ encoding: "utf-8",
57
+ maxBuffer: 10 * 1024 * 1024,
58
+ });
59
+ if (result.status !== 0) {
60
+ throw new Error(`git ${args.join(" ")} failed: ${(result.stderr || result.stdout || "").trim()}`);
61
+ }
62
+ return result.stdout || "";
63
+ }
64
+ buildDiffArgs(diffSource, baseRef, headRef, contextLines, includePaths) {
65
+ const args = ["diff", "--no-color", `--unified=${contextLines}`];
66
+ if (diffSource === "staged") {
67
+ args.push("--staged");
68
+ }
69
+ else if (diffSource === "range") {
70
+ if (!baseRef) {
71
+ throw new Error("baseRef is required when diffSource is 'range'");
72
+ }
73
+ args.push(`${baseRef}..${headRef || "HEAD"}`);
74
+ }
75
+ if (includePaths.length > 0) {
76
+ args.push("--", ...includePaths);
77
+ }
78
+ return args;
79
+ }
80
+ buildNameOnlyArgs(diffSource, baseRef, headRef, includePaths) {
81
+ const args = ["diff", "--name-only"];
82
+ if (diffSource === "staged") {
83
+ args.push("--staged");
84
+ }
85
+ else if (diffSource === "range") {
86
+ if (!baseRef) {
87
+ throw new Error("baseRef is required when diffSource is 'range'");
88
+ }
89
+ args.push(`${baseRef}..${headRef || "HEAD"}`);
90
+ }
91
+ if (includePaths.length > 0) {
92
+ args.push("--", ...includePaths);
93
+ }
94
+ return args;
95
+ }
96
+ buildNumStatArgs(diffSource, baseRef, headRef, includePaths) {
97
+ const args = ["diff", "--numstat"];
98
+ if (diffSource === "staged") {
99
+ args.push("--staged");
100
+ }
101
+ else if (diffSource === "range") {
102
+ if (!baseRef) {
103
+ throw new Error("baseRef is required when diffSource is 'range'");
104
+ }
105
+ args.push(`${baseRef}..${headRef || "HEAD"}`);
106
+ }
107
+ if (includePaths.length > 0) {
108
+ args.push("--", ...includePaths);
109
+ }
110
+ return args;
111
+ }
112
+ parseNumStat(numStat) {
113
+ let additions = 0;
114
+ let deletions = 0;
115
+ const lines = numStat
116
+ .split("\n")
117
+ .map((line) => line.trim())
118
+ .filter(Boolean);
119
+ for (const line of lines) {
120
+ const [addRaw, delRaw] = line.split("\t");
121
+ const addCount = addRaw === "-" ? 0 : parseInt(addRaw, 10);
122
+ const delCount = delRaw === "-" ? 0 : parseInt(delRaw, 10);
123
+ additions += Number.isNaN(addCount) ? 0 : addCount;
124
+ deletions += Number.isNaN(delCount) ? 0 : delCount;
125
+ }
126
+ return { additions, deletions };
127
+ }
128
+ }
129
+ //# sourceMappingURL=LocalDiffSource.js.map
@@ -1,6 +1,6 @@
1
1
  /**
2
2
  * MCP Server Manager for Yama V2
3
- * Manages lifecycle and health of Bitbucket and Jira MCP servers
3
+ * Manages lifecycle and health of PR/local MCP servers
4
4
  */
5
5
  import { MCPServersConfig } from "../types/config.types.js";
6
6
  export declare class MCPServerManager {
@@ -10,6 +10,14 @@ export declare class MCPServerManager {
10
10
  * Bitbucket is always enabled, Jira is optional based on config
11
11
  */
12
12
  setupMCPServers(neurolink: any, config: MCPServersConfig): Promise<void>;
13
+ /**
14
+ * Setup local git MCP server for SDK/local mode.
15
+ * Mandatory in local mode.
16
+ */
17
+ setupLocalGitMCPServer(neurolink: any): Promise<void>;
18
+ private buildLocalGitServerConfig;
19
+ private getLocalGitToolNames;
20
+ private isMutatingGitTool;
13
21
  /**
14
22
  * Setup Bitbucket MCP server (hardcoded, always enabled)
15
23
  */
@@ -18,5 +26,9 @@ export declare class MCPServerManager {
18
26
  * Setup Jira MCP server (hardcoded, optionally enabled)
19
27
  */
20
28
  private setupJiraMCP;
29
+ /**
30
+ * MCP preflight diagnostics after registration.
31
+ */
32
+ private logDiagnostics;
21
33
  }
22
34
  //# sourceMappingURL=MCPServerManager.d.ts.map
@@ -1,7 +1,8 @@
1
1
  /**
2
2
  * MCP Server Manager for Yama V2
3
- * Manages lifecycle and health of Bitbucket and Jira MCP servers
3
+ * Manages lifecycle and health of PR/local MCP servers
4
4
  */
5
+ import { join } from "path";
5
6
  import { MCPServerError } from "../types/v2.types.js";
6
7
  export class MCPServerManager {
7
8
  // MCP servers are managed entirely by NeuroLink
@@ -12,6 +13,9 @@ export class MCPServerManager {
12
13
  * Bitbucket is always enabled, Jira is optional based on config
13
14
  */
14
15
  async setupMCPServers(neurolink, config) {
16
+ if (this.initialized) {
17
+ return;
18
+ }
15
19
  console.log("🔌 Setting up MCP servers...");
16
20
  // Setup Bitbucket MCP (always enabled)
17
21
  await this.setupBitbucketMCP(neurolink, config.bitbucket?.blockedTools);
@@ -23,8 +27,79 @@ export class MCPServerManager {
23
27
  console.log(" ⏭️ Jira MCP disabled in config");
24
28
  }
25
29
  this.initialized = true;
30
+ await this.logDiagnostics(neurolink);
26
31
  console.log("✅ MCP servers configured\n");
27
32
  }
33
+ /**
34
+ * Setup local git MCP server for SDK/local mode.
35
+ * Mandatory in local mode.
36
+ */
37
+ async setupLocalGitMCPServer(neurolink) {
38
+ try {
39
+ console.log("🔌 Setting up local Git MCP server...");
40
+ await neurolink.addExternalMCPServer("local-git", this.buildLocalGitServerConfig([]));
41
+ const discoveredToolNames = this.getLocalGitToolNames(neurolink);
42
+ // Fail closed: if tool discovery returns nothing we cannot verify read-only
43
+ // safety, so refuse to proceed rather than silently exposing write operations.
44
+ if (discoveredToolNames.length === 0) {
45
+ await neurolink
46
+ .removeExternalMCPServer("local-git")
47
+ .catch(() => undefined);
48
+ throw new MCPServerError("local-git MCP server returned no tools — cannot verify read-only filtering. Aborting local mode setup.");
49
+ }
50
+ const mutatingTools = discoveredToolNames.filter((name) => this.isMutatingGitTool(name));
51
+ // Enforce hard safety at MCP layer: mutating tools are removed from registry.
52
+ if (mutatingTools.length > 0) {
53
+ await neurolink.removeExternalMCPServer("local-git");
54
+ await neurolink.addExternalMCPServer("local-git", this.buildLocalGitServerConfig(mutatingTools));
55
+ // Verify the re-registration actually removed all mutating tools.
56
+ const remainingMutating = this.getLocalGitToolNames(neurolink).filter((name) => this.isMutatingGitTool(name));
57
+ if (remainingMutating.length > 0) {
58
+ await neurolink
59
+ .removeExternalMCPServer("local-git")
60
+ .catch(() => undefined);
61
+ throw new MCPServerError(`Read-only enforcement failed — mutating tools still present after blocking: ${remainingMutating.join(", ")}`);
62
+ }
63
+ }
64
+ console.log(" ✅ Local Git MCP server registered");
65
+ console.log(" 🔒 Local mode enforces regex-derived read-only blocking at MCP layer");
66
+ if (mutatingTools.length > 0) {
67
+ console.log(` 🚫 Blocked local-git tools: ${mutatingTools.join(", ")}`);
68
+ }
69
+ try {
70
+ const toolNames = this.getLocalGitToolNames(neurolink);
71
+ if (toolNames.length > 0) {
72
+ console.log(` 🧰 local-git tools (available): ${toolNames.join(", ")}`);
73
+ }
74
+ }
75
+ catch {
76
+ // Optional introspection only
77
+ }
78
+ await this.logDiagnostics(neurolink);
79
+ }
80
+ catch (error) {
81
+ throw new MCPServerError(`Failed to setup local Git MCP server: ${error.message}`);
82
+ }
83
+ }
84
+ buildLocalGitServerConfig(blockedTools) {
85
+ return {
86
+ // Launch via package script: tries uvx first, falls back to npx package.
87
+ command: "npm",
88
+ args: ["run", "-s", "mcp:git:server"],
89
+ transport: "stdio",
90
+ blockedTools,
91
+ };
92
+ }
93
+ getLocalGitToolNames(neurolink) {
94
+ return (neurolink.getExternalMCPServerTools?.("local-git") || [])
95
+ .map((tool) => tool?.name)
96
+ .filter((name) => typeof name === "string");
97
+ }
98
+ isMutatingGitTool(toolName) {
99
+ // Handles plain names (git_commit) and prefixed names (local-git.git_commit).
100
+ const normalized = toolName.split(/[.:/]/).pop() || toolName;
101
+ return /^git_(commit|push|add|checkout|create_branch|merge|rebase|cherry_pick|reset|revert|tag|rm|clean|stash|apply)\b/i.test(normalized);
102
+ }
28
103
  /**
29
104
  * Setup Bitbucket MCP server (hardcoded, always enabled)
30
105
  */
@@ -37,10 +112,13 @@ export class MCPServerManager {
37
112
  !process.env.BITBUCKET_BASE_URL) {
38
113
  throw new MCPServerError("Missing required environment variables: BITBUCKET_USERNAME, BITBUCKET_TOKEN, or BITBUCKET_BASE_URL");
39
114
  }
40
- // Hardcoded Bitbucket MCP configuration
115
+ // Use the locally installed binary instead of `npx @latest`, which forces
116
+ // a registry check + possible download in CI and causes the 30s circuit-breaker
117
+ // to fire intermittently.
118
+ const bitbucketBin = join(process.cwd(), "node_modules/.bin/bitbucket-mcp-server");
41
119
  await neurolink.addExternalMCPServer("bitbucket", {
42
- command: "npx",
43
- args: ["-y", "@nexus2520/bitbucket-mcp-server@latest"],
120
+ command: bitbucketBin,
121
+ args: [],
44
122
  transport: "stdio",
45
123
  env: {
46
124
  BITBUCKET_USERNAME: process.env.BITBUCKET_USERNAME,
@@ -49,6 +127,15 @@ export class MCPServerManager {
49
127
  },
50
128
  blockedTools: blockedTools || [],
51
129
  });
130
+ // Verify the server actually connected — NeuroLink resolves the promise
131
+ // even on timeout, so we must check the status explicitly.
132
+ const servers = await neurolink.listMCPServers();
133
+ const bbServer = (servers || []).find((s) => s.name === "bitbucket");
134
+ if (!bbServer ||
135
+ bbServer.status !== "connected" ||
136
+ bbServer.tools?.length === 0) {
137
+ throw new MCPServerError(`Bitbucket MCP server registered but not connected (status: ${bbServer?.status ?? "unknown"}, tools: ${bbServer?.tools?.length ?? 0}). Possible startup timeout.`);
138
+ }
52
139
  console.log(" ✅ Bitbucket MCP server registered and tools available");
53
140
  if (blockedTools && blockedTools.length > 0) {
54
141
  console.log(` 🚫 Blocked tools: ${blockedTools.join(", ")}`);
@@ -73,10 +160,11 @@ export class MCPServerManager {
73
160
  console.warn(" Skipping Jira integration...");
74
161
  return;
75
162
  }
76
- // Hardcoded Jira MCP configuration
163
+ // Use the locally installed binary (same reason as Bitbucket above).
164
+ const jiraBin = join(process.cwd(), "node_modules/.bin/jira-mcp-server");
77
165
  await neurolink.addExternalMCPServer("jira", {
78
- command: "npx",
79
- args: ["-y", "@nexus2520/jira-mcp-server"],
166
+ command: jiraBin,
167
+ args: [],
80
168
  transport: "stdio",
81
169
  env: {
82
170
  JIRA_EMAIL: process.env.JIRA_EMAIL,
@@ -96,5 +184,21 @@ export class MCPServerManager {
96
184
  console.warn(" Continuing without Jira integration...");
97
185
  }
98
186
  }
187
+ /**
188
+ * MCP preflight diagnostics after registration.
189
+ */
190
+ async logDiagnostics(neurolink) {
191
+ try {
192
+ const status = await neurolink.getMCPStatus();
193
+ const servers = await neurolink.listMCPServers();
194
+ console.log(" 📊 MCP diagnostics:");
195
+ console.log(` Servers: ${status.totalServers}`);
196
+ console.log(` Tools: ${status.totalTools}`);
197
+ console.log(` Connected: ${(servers || []).filter((server) => server?.status === "connected").length}`);
198
+ }
199
+ catch (error) {
200
+ console.warn(` ⚠️ MCP diagnostics unavailable: ${error.message}`);
201
+ }
202
+ }
99
203
  }
100
204
  //# sourceMappingURL=MCPServerManager.js.map
@@ -1,5 +1,5 @@
1
1
  /**
2
- * Session Manager for Yama V2
2
+ * Session Manager for Yama
3
3
  * Tracks review sessions, tool calls, and maintains state
4
4
  */
5
5
  import { ReviewSession, ReviewRequest, ReviewResult, SessionMetadata } from "../types/v2.types.js";
@@ -1,5 +1,5 @@
1
1
  /**
2
- * Session Manager for Yama V2
2
+ * Session Manager for Yama
3
3
  * Tracks review sessions, tool calls, and maintains state
4
4
  */
5
5
  import { randomBytes } from "crypto";
@@ -18,7 +18,7 @@ export class SessionManager {
18
18
  status: "running",
19
19
  toolCalls: [],
20
20
  metadata: {
21
- yamaVersion: "2.0.0",
21
+ yamaVersion: "2.2.1",
22
22
  aiProvider: "auto",
23
23
  aiModel: "unknown",
24
24
  totalTokens: 0,
@@ -122,7 +122,7 @@ export class SessionManager {
122
122
  generateSessionId() {
123
123
  const timestamp = Date.now().toString(36);
124
124
  const random = randomBytes(4).toString("hex");
125
- return `yama-v2-${timestamp}-${random}`;
125
+ return `yama-${timestamp}-${random}`;
126
126
  }
127
127
  /**
128
128
  * Clean up old sessions (keep most recent 100)
@@ -1,25 +1,39 @@
1
1
  /**
2
- * Yama V2 Orchestrator
2
+ * Yama Orchestrator
3
3
  * Main entry point for AI-native autonomous code review
4
4
  */
5
- import { ReviewRequest, ReviewResult, ReviewUpdate } from "../types/v2.types.js";
6
- export declare class YamaV2Orchestrator {
5
+ import { LocalReviewRequest, LocalReviewResult, ReviewRequest, ReviewResult, ReviewMode, ReviewUpdate, UnifiedReviewRequest } from "../types/v2.types.js";
6
+ import { YamaInitOptions } from "../types/config.types.js";
7
+ export declare class YamaOrchestrator {
7
8
  private neurolink;
8
9
  private mcpManager;
9
10
  private configLoader;
10
11
  private promptBuilder;
11
12
  private sessionManager;
13
+ private memoryManager;
14
+ private localDiffSource;
12
15
  private config;
13
16
  private initialized;
14
- constructor();
17
+ private mcpInitialized;
18
+ private localGitMcpInitialized;
19
+ private initOptions;
20
+ constructor(options?: YamaInitOptions);
15
21
  /**
16
- * Initialize Yama V2 with configuration and MCP servers
22
+ * Initialize Yama with configuration and MCP servers
17
23
  */
18
- initialize(configPath?: string): Promise<void>;
24
+ initialize(configPath?: string, mode?: ReviewMode): Promise<void>;
19
25
  /**
20
26
  * Start autonomous AI review
21
27
  */
22
28
  startReview(request: ReviewRequest): Promise<ReviewResult>;
29
+ /**
30
+ * Unified review entry for SDK consumers.
31
+ */
32
+ review(request: UnifiedReviewRequest): Promise<ReviewResult | LocalReviewResult>;
33
+ /**
34
+ * Local SDK mode review from git diff (no PR/MCP dependency).
35
+ */
36
+ reviewLocalDiff(request: LocalReviewRequest): Promise<LocalReviewResult>;
23
37
  /**
24
38
  * Stream review with real-time updates (for verbose mode)
25
39
  */
@@ -51,14 +65,24 @@ export declare class YamaV2Orchestrator {
51
65
  * Export session data
52
66
  */
53
67
  exportSession(sessionId: string): any;
54
- /**
55
- * Create tool context for AI
56
- */
68
+ private getUserId;
57
69
  private createToolContext;
58
70
  /**
59
71
  * Parse AI response into structured review result
60
72
  */
61
73
  private parseReviewResult;
74
+ private recordToolCallsFromResponse;
75
+ /**
76
+ * Parse local SDK mode response into strict LocalReviewResult.
77
+ */
78
+ private parseLocalReviewResult;
79
+ private sanitizeLocalSummary;
80
+ private removeDelimitedSections;
81
+ private extractJsonPayload;
82
+ private normalizeFindings;
83
+ private normalizeSeverity;
84
+ private countFindingsBySeverity;
85
+ private normalizeDecision;
62
86
  /**
63
87
  * Extract decision from AI response
64
88
  */
@@ -79,10 +103,19 @@ export declare class YamaV2Orchestrator {
79
103
  * Calculate cost estimate from token usage
80
104
  */
81
105
  private calculateCost;
106
+ private toSafeNumber;
107
+ private isLocalReviewRequest;
108
+ /**
109
+ * Query-level tool filtering for PR mode.
110
+ * Conservative strategy: only exclude Jira tools when there is no Jira signal.
111
+ */
112
+ private getPRToolFilteringOptions;
82
113
  /**
83
- * Generate userId for NeuroLink context from repository and branch/PR
114
+ * Query-level read-only filtering for local-git MCP tools.
115
+ * Uses regex-based mutation detection instead of hardcoded tool-name lists.
84
116
  */
85
- private generateUserId;
117
+ private getLocalToolFilteringOptions;
118
+ private normalizeToolName;
86
119
  /**
87
120
  * Initialize NeuroLink with observability configuration
88
121
  */
@@ -92,7 +125,7 @@ export declare class YamaV2Orchestrator {
92
125
  */
93
126
  private ensureInitialized;
94
127
  /**
95
- * Show Yama V2 banner
128
+ * Show Yama banner
96
129
  */
97
130
  private showBanner;
98
131
  /**
@@ -108,5 +141,7 @@ export declare class YamaV2Orchestrator {
108
141
  */
109
142
  private formatDecision;
110
143
  }
111
- export declare function createYamaV2(): YamaV2Orchestrator;
144
+ export declare function createYamaV2(options?: YamaInitOptions): YamaOrchestrator;
145
+ export declare function createYama(options?: YamaInitOptions): YamaOrchestrator;
146
+ export { YamaOrchestrator as YamaV2Orchestrator };
112
147
  //# sourceMappingURL=YamaV2Orchestrator.d.ts.map