@juspay/yama 2.5.0 → 2.6.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/CHANGELOG.md +7 -0
- package/dist/v2/core/MCPServerManager.d.ts +8 -0
- package/dist/v2/core/MCPServerManager.js +40 -9
- package/dist/v2/core/YamaV2Orchestrator.js +1 -1
- package/dist/v2/exploration/ContextExplorerService.d.ts +2 -1
- package/dist/v2/exploration/ContextExplorerService.js +15 -4
- package/dist/v2/providers/ProviderToolset.js +19 -9
- package/package.json +2 -2
package/CHANGELOG.md
CHANGED
|
@@ -1,3 +1,10 @@
|
|
|
1
|
+
# [2.6.0](https://github.com/juspay/yama/compare/v2.5.0...v2.6.0) (2026-06-04)
|
|
2
|
+
|
|
3
|
+
|
|
4
|
+
### Features
|
|
5
|
+
|
|
6
|
+
* **action:** add Yama self-review workflow with LiteLLM/Vertex auth ([5ebb73f](https://github.com/juspay/yama/commit/5ebb73f2450951b5f97d97a6a3caa89377a150af))
|
|
7
|
+
|
|
1
8
|
# [2.5.0](https://github.com/juspay/yama/compare/v2.4.2...v2.5.0) (2026-06-03)
|
|
2
9
|
|
|
3
10
|
|
|
@@ -45,6 +45,14 @@ export declare class MCPServerManager {
|
|
|
45
45
|
* defaulting to the remote HTTP endpoint.
|
|
46
46
|
*/
|
|
47
47
|
private setupGitHubMCP;
|
|
48
|
+
/**
|
|
49
|
+
* Poll {@link listMCPServers} until the named server reports "connected" with
|
|
50
|
+
* at least one tool, or the timeout elapses. Returns the last-seen server
|
|
51
|
+
* entry (possibly not-yet-connected) so the caller can decide how to proceed.
|
|
52
|
+
*
|
|
53
|
+
* Bounded by `timeoutMs` via the loop condition — it cannot run indefinitely.
|
|
54
|
+
*/
|
|
55
|
+
private waitForMCPServer;
|
|
48
56
|
/**
|
|
49
57
|
* Build the remote HTTP GitHub MCP registration (default path).
|
|
50
58
|
* A Bearer token is required for the hosted endpoint.
|
|
@@ -240,17 +240,26 @@ export class MCPServerManager {
|
|
|
240
240
|
? this.buildGitHubStdioConfig(githubConfig, ghToken, blockedTools)
|
|
241
241
|
: this.buildGitHubHttpConfig(githubConfig, ghToken, blockedTools);
|
|
242
242
|
await neurolink.addExternalMCPServer("github", config);
|
|
243
|
-
//
|
|
244
|
-
//
|
|
245
|
-
//
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
243
|
+
// The remote HTTP endpoint (api.githubcopilot.com) connects asynchronously
|
|
244
|
+
// — TLS handshake + auth + tool discovery take ~3-4s, and NeuroLink may only
|
|
245
|
+
// finish discovery lazily on the first generate() call. Poll briefly for a
|
|
246
|
+
// healthy status, but for the HTTP transport DO NOT hard-fail if it is not
|
|
247
|
+
// yet "connected": the tools are resolved when the review runs (this mirrors
|
|
248
|
+
// Curator's proven pattern). For a local stdio server we keep the strict
|
|
249
|
+
// check, since a local process should connect promptly.
|
|
250
|
+
const ghServer = await this.waitForMCPServer(neurolink, "github", 12000);
|
|
251
|
+
const connected = ghServer?.status === "connected" && (ghServer?.tools?.length ?? 0) > 0;
|
|
252
|
+
if (transport === "stdio" && !connected) {
|
|
251
253
|
throw new MCPServerError(`GitHub MCP server registered but not connected (status: ${ghServer?.status ?? "unknown"}, tools: ${ghServer?.tools?.length ?? 0}). Possible startup timeout.`);
|
|
252
254
|
}
|
|
253
|
-
|
|
255
|
+
if (connected) {
|
|
256
|
+
console.log(` ✅ GitHub MCP server registered and tools available (transport: ${transport})`);
|
|
257
|
+
}
|
|
258
|
+
else {
|
|
259
|
+
console.warn(` ⚠️ GitHub MCP server registered but not yet reporting connected ` +
|
|
260
|
+
`(status: ${ghServer?.status ?? "unknown"}, tools: ${ghServer?.tools?.length ?? 0}). ` +
|
|
261
|
+
`Remote tools are discovered on first use; continuing.`);
|
|
262
|
+
}
|
|
254
263
|
if (transport === "http") {
|
|
255
264
|
console.log(` 🌐 Remote endpoint: ${config.url}`);
|
|
256
265
|
}
|
|
@@ -260,6 +269,28 @@ export class MCPServerManager {
|
|
|
260
269
|
throw new MCPServerError(`Failed to setup GitHub MCP server: ${error.message}`);
|
|
261
270
|
}
|
|
262
271
|
}
|
|
272
|
+
/**
|
|
273
|
+
* Poll {@link listMCPServers} until the named server reports "connected" with
|
|
274
|
+
* at least one tool, or the timeout elapses. Returns the last-seen server
|
|
275
|
+
* entry (possibly not-yet-connected) so the caller can decide how to proceed.
|
|
276
|
+
*
|
|
277
|
+
* Bounded by `timeoutMs` via the loop condition — it cannot run indefinitely.
|
|
278
|
+
*/
|
|
279
|
+
async waitForMCPServer(neurolink, name, timeoutMs) {
|
|
280
|
+
const deadline = Date.now() + timeoutMs;
|
|
281
|
+
let last;
|
|
282
|
+
while (Date.now() < deadline) {
|
|
283
|
+
const servers = await neurolink
|
|
284
|
+
.listMCPServers()
|
|
285
|
+
.catch(() => []);
|
|
286
|
+
last = (servers || []).find((server) => server.name === name);
|
|
287
|
+
if (last?.status === "connected" && (last.tools?.length ?? 0) > 0) {
|
|
288
|
+
return last;
|
|
289
|
+
}
|
|
290
|
+
await new Promise((resolve) => setTimeout(resolve, 1000));
|
|
291
|
+
}
|
|
292
|
+
return last;
|
|
293
|
+
}
|
|
263
294
|
/**
|
|
264
295
|
* Build the remote HTTP GitHub MCP registration (default path).
|
|
265
296
|
* A Bearer token is required for the hosted endpoint.
|
|
@@ -99,7 +99,7 @@ export class YamaOrchestrator {
|
|
|
99
99
|
if (!this.mcpInitialized) {
|
|
100
100
|
await this.mcpManager.setupMCPServers(this.neurolink, this.config.mcpServers, this.detectedProvider);
|
|
101
101
|
if (this.explorer && this.config.ai.explore.enabled) {
|
|
102
|
-
await this.explorer.initialize("pr");
|
|
102
|
+
await this.explorer.initialize("pr", this.detectedProvider);
|
|
103
103
|
}
|
|
104
104
|
this.mcpInitialized = true;
|
|
105
105
|
this.mcpProvider = this.detectedProvider;
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { YamaConfig } from "../types/config.types.js";
|
|
2
2
|
import { SessionManager } from "../core/SessionManager.js";
|
|
3
3
|
import { MemoryManager } from "../memory/MemoryManager.js";
|
|
4
|
+
import { type VCSProviderName } from "../providers/ProviderToolset.js";
|
|
4
5
|
import { ExploreContextInput, ExploreExecutionResult, ExploreRuntimeContext } from "./types.js";
|
|
5
6
|
export declare class ContextExplorerService {
|
|
6
7
|
private readonly config;
|
|
@@ -14,7 +15,7 @@ export declare class ContextExplorerService {
|
|
|
14
15
|
private prMcpInitialized;
|
|
15
16
|
private localMcpInitialized;
|
|
16
17
|
constructor(config: YamaConfig, sessionManager: SessionManager, memoryManager: MemoryManager | null, projectRoot?: string);
|
|
17
|
-
initialize(mode: "pr" | "local"): Promise<void>;
|
|
18
|
+
initialize(mode: "pr" | "local", provider?: VCSProviderName): Promise<void>;
|
|
18
19
|
explore(input: ExploreContextInput, runtimeContext: ExploreRuntimeContext): Promise<ExploreExecutionResult>;
|
|
19
20
|
private normalizeInput;
|
|
20
21
|
private buildCacheKey;
|
|
@@ -5,7 +5,7 @@ import { NeuroLink } from "@juspay/neurolink";
|
|
|
5
5
|
import { MCPServerManager } from "../core/MCPServerManager.js";
|
|
6
6
|
import { KnowledgeBaseManager } from "../learning/KnowledgeBaseManager.js";
|
|
7
7
|
import { buildObservabilityConfigFromEnv, validateObservabilityConfig, } from "../utils/ObservabilityConfig.js";
|
|
8
|
-
import { getProviderToolset } from "../providers/ProviderToolset.js";
|
|
8
|
+
import { getProviderToolset, } from "../providers/ProviderToolset.js";
|
|
9
9
|
import { ExplorerPromptBuilder } from "./ExplorerPromptBuilder.js";
|
|
10
10
|
import { RulesContextLoader } from "./RulesContextLoader.js";
|
|
11
11
|
export class ContextExplorerService {
|
|
@@ -27,9 +27,12 @@ export class ContextExplorerService {
|
|
|
27
27
|
this.rulesContextLoader = new RulesContextLoader(config.memoryBank, config.projectStandards, projectRoot);
|
|
28
28
|
this.neurolink = this.initializeNeurolink();
|
|
29
29
|
}
|
|
30
|
-
async initialize(mode) {
|
|
30
|
+
async initialize(mode, provider = "bitbucket") {
|
|
31
31
|
if (mode === "pr" && !this.prMcpInitialized) {
|
|
32
|
-
|
|
32
|
+
// The explore subagent gets its own MCP servers; they MUST match the
|
|
33
|
+
// detected provider, otherwise a GitHub run would try to start Bitbucket
|
|
34
|
+
// MCP (and fail on missing Bitbucket credentials).
|
|
35
|
+
await this.mcpManager.setupMCPServers(this.neurolink, this.config.mcpServers, provider);
|
|
33
36
|
this.prMcpInitialized = true;
|
|
34
37
|
return;
|
|
35
38
|
}
|
|
@@ -39,7 +42,15 @@ export class ContextExplorerService {
|
|
|
39
42
|
}
|
|
40
43
|
}
|
|
41
44
|
async explore(input, runtimeContext) {
|
|
42
|
-
|
|
45
|
+
// Pass the runtime provider through when it is a known VCS provider;
|
|
46
|
+
// otherwise fall back to the read-only default. VCSProviderName is the
|
|
47
|
+
// single source of truth for supported providers, so adding one there is
|
|
48
|
+
// all that's needed for the explore subagent to honour it.
|
|
49
|
+
const explorerProvider = runtimeContext.provider === "github" ||
|
|
50
|
+
runtimeContext.provider === "bitbucket"
|
|
51
|
+
? runtimeContext.provider
|
|
52
|
+
: "bitbucket";
|
|
53
|
+
await this.initialize(runtimeContext.mode, explorerProvider);
|
|
43
54
|
const normalizedInput = this.normalizeInput(input);
|
|
44
55
|
const cacheKey = this.buildCacheKey(normalizedInput, runtimeContext);
|
|
45
56
|
if (this.config.ai.explore.cacheResults) {
|
|
@@ -255,7 +255,8 @@ class GitHubToolset {
|
|
|
255
255
|
systemPromptToolsSection() {
|
|
256
256
|
return ` <tool-usage>
|
|
257
257
|
<tool name="pull_request_read">
|
|
258
|
-
<use-when>Read PR state
|
|
258
|
+
<use-when>Read PR state by method: "get" for PR metadata; "get_review_comments" to load EXISTING inline review comments (each thread carries isResolved/isOutdated) so you never repeat an already-raised point; "get_reviews" for prior submitted reviews; "get_files" to list changed files; "get_diff" for the unified diff. Always pass owner, repo, pullNumber.</use-when>
|
|
259
|
+
<important>method="get" does NOT include review comments on GitHub — you MUST call method="get_review_comments" to see them.</important>
|
|
259
260
|
</tool>
|
|
260
261
|
|
|
261
262
|
<tool name="search_code">
|
|
@@ -305,11 +306,16 @@ class GitHubToolset {
|
|
|
305
306
|
entry with severity=BLOCKING as a blocking criterion for this PR. If the block is
|
|
306
307
|
missing or empty, fall back to <focus-areas> and <blocking-criteria>.
|
|
307
308
|
|
|
308
|
-
STEP 2 — Read the PR shell
|
|
309
|
-
Call pull_request_read(method="get", owner, repo, pullNumber)
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
309
|
+
STEP 2 — Read the PR shell + EXISTING review comments
|
|
310
|
+
Call pull_request_read(method="get", owner, repo, pullNumber) for PR metadata,
|
|
311
|
+
then pull_request_read(method="get_review_comments", owner, repo, pullNumber) to
|
|
312
|
+
load existing inline review comments. (On GitHub, method="get" does NOT include
|
|
313
|
+
review comments — you MUST call get_review_comments.) Build a map of which
|
|
314
|
+
file+line locations already have comments. Treat any point an existing comment
|
|
315
|
+
already raises as ALREADY HANDLED: do NOT post a duplicate, and do NOT re-raise it
|
|
316
|
+
in your decision — especially threads marked isResolved or isOutdated. Then call
|
|
317
|
+
pull_request_read(method="get_files", ...) to list the changed files. Do NOT
|
|
318
|
+
request the full PR diff yet.
|
|
313
319
|
|
|
314
320
|
STEP 3 — Open ONE pending review
|
|
315
321
|
Call pull_request_review_write(method="create", owner, repo, pullNumber) to open a
|
|
@@ -329,9 +335,13 @@ class GitHubToolset {
|
|
|
329
335
|
e. Move to the next file. Never jump between files mid-review.
|
|
330
336
|
|
|
331
337
|
STEP 5 — Decision (submit the review)
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
338
|
+
Count ONLY the NEW issues you raised this run — exclude any point already covered by
|
|
339
|
+
an existing review comment (from STEP 2), and exclude resolved/outdated threads. Apply
|
|
340
|
+
<blocking-criteria> to that NEW set only. A concern that was already raised and
|
|
341
|
+
answered/justified in an existing comment thread is NOT grounds to block again.
|
|
342
|
+
Then call pull_request_review_write(method="submit", owner, repo, pullNumber,
|
|
343
|
+
body=<summary>) with event="APPROVE" when there are no NEW blocking issues, or
|
|
344
|
+
event="REQUEST_CHANGES" only when NEW blocking criteria are met this run.
|
|
335
345
|
|
|
336
346
|
STEP 6 — Summary comment
|
|
337
347
|
Use the submit body above for the summary (file count, issue counts by severity, next
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@juspay/yama",
|
|
3
|
-
"version": "2.
|
|
3
|
+
"version": "2.6.0",
|
|
4
4
|
"description": "Enterprise-grade Pull Request automation toolkit with AI-powered code review and description enhancement",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"pr",
|
|
@@ -160,7 +160,7 @@
|
|
|
160
160
|
],
|
|
161
161
|
"overrides": {
|
|
162
162
|
"@semantic-release/npm": "^13.1.2",
|
|
163
|
-
"undici": "
|
|
163
|
+
"undici": "~7.22.0"
|
|
164
164
|
}
|
|
165
165
|
},
|
|
166
166
|
"lint-staged": {
|