@juspay/yama 2.4.2 → 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.
@@ -1,212 +1,124 @@
1
1
  /**
2
- * MCP Tool Response Type Definitions
3
- * Types for Bitbucket and Jira MCP tool responses
2
+ * MCP (Model Context Protocol) response type definitions.
3
+ *
4
+ * These describe the shapes Yama reads back from VCS MCP tool calls
5
+ * (Bitbucket / GitHub pull requests, diffs, code search, Jira issues).
6
+ *
7
+ * The fictional `NeuroLinkAPI`/`callTool` interface and the unused
8
+ * server-management helper types were removed when the dead VCSProvider
9
+ * classes were deleted — only these still-used response shapes (re-exported
10
+ * from src/index.ts) remain.
11
+ */
12
+ /**
13
+ * Bitbucket/GitHub Pull Request response from a PR-read tool call
4
14
  */
5
- export interface MCPStatus {
6
- totalServers: number;
7
- totalTools: number;
8
- servers: MCPServerStatus[];
9
- }
10
- export interface MCPServerStatus {
11
- id: string;
12
- connected: boolean;
13
- tools: string[];
14
- lastHealthCheck?: Date;
15
- error?: string;
16
- }
17
15
  export interface GetPullRequestResponse {
18
- id: number;
19
- title: string;
20
- description: string;
21
- author: {
22
- name: string;
23
- displayName: string;
24
- emailAddress?: string;
25
- };
26
- state: "OPEN" | "MERGED" | "DECLINED";
27
- source: {
28
- branch: {
29
- name: string;
16
+ id?: number | string;
17
+ number?: number;
18
+ title?: string;
19
+ description?: string;
20
+ state?: string;
21
+ source?: {
22
+ branch?: {
23
+ name?: string;
30
24
  };
31
- commit: {
32
- id: string;
25
+ repository?: {
26
+ full_slug?: string;
33
27
  };
34
28
  };
35
- destination: {
36
- branch: {
37
- name: string;
29
+ destination?: {
30
+ branch?: {
31
+ name?: string;
38
32
  };
39
- commit: {
40
- id: string;
33
+ repository?: {
34
+ full_slug?: string;
41
35
  };
42
36
  };
43
- createdDate: string;
44
- updatedDate: string;
45
- reviewers: Reviewer[];
46
- active_comments?: Comment[];
47
- file_changes?: FileChange[];
48
- }
49
- export interface Reviewer {
50
- user: {
51
- name: string;
52
- displayName: string;
53
- emailAddress?: string;
54
- };
55
- approved: boolean;
56
- status: "APPROVED" | "UNAPPROVED" | "NEEDS_WORK";
57
- }
58
- export interface Comment {
59
- id: number;
60
- text: string;
61
- author: {
62
- name: string;
63
- displayName: string;
64
- };
65
- createdDate: string;
66
- updatedDate: string;
67
- anchor?: CommentAnchor;
68
- }
69
- export interface CommentAnchor {
70
- filePath: string;
71
- lineFrom: number;
72
- lineTo: number;
73
- lineType: "ADDED" | "REMOVED" | "CONTEXT";
74
- }
75
- export interface FileChange {
76
- path: string;
77
- file?: string;
78
- type: "ADD" | "MODIFY" | "DELETE" | "RENAME";
79
- }
80
- export interface DiffLine {
81
- source_line: number | null;
82
- destination_line: number | null;
83
- type: "ADDED" | "REMOVED" | "CONTEXT";
84
- content: string;
85
- }
86
- export interface DiffHunk {
87
- source_start: number;
88
- source_length: number;
89
- destination_start: number;
90
- destination_length: number;
91
- lines: DiffLine[];
92
- }
93
- export interface DiffFile {
94
- file_path: string;
95
- old_path?: string;
96
- status: "added" | "modified" | "deleted" | "renamed";
97
- hunks: DiffHunk[];
98
- }
99
- export interface GetPullRequestDiffResponse {
100
- files: DiffFile[];
101
- stats?: {
102
- additions: number;
103
- deletions: number;
104
- files_changed: number;
105
- };
106
- }
107
- export interface AddCommentRequest {
108
- workspace: string;
109
- repository: string;
110
- pull_request_id: number;
111
- comment_text: string;
112
- file_path: string;
113
- line_number: number;
114
- line_type: "ADDED" | "REMOVED" | "CONTEXT";
115
- suggestion?: string;
116
- parent_comment_id?: number;
117
- }
118
- export interface AddCommentResponse {
119
- id: number;
120
- text: string;
121
- author: string;
122
- createdDate: string;
123
- anchor?: CommentAnchor;
124
- }
125
- export interface UpdatePullRequestRequest {
126
- workspace: string;
127
- repository: string;
128
- pull_request_id: number;
129
- title?: string;
130
- description?: string;
131
- reviewers?: string[];
132
- }
133
- export interface GetFileContentResponse {
134
- content: string;
135
- path: string;
136
- size: number;
137
- encoding?: string;
138
- }
139
- export interface ListDirectoryContentResponse {
140
- path: string;
141
- items: DirectoryItem[];
142
- }
143
- export interface DirectoryItem {
144
- type: "file" | "directory";
145
- path: string;
146
- name: string;
147
- size?: number;
148
- }
149
- export interface SearchCodeResponse {
150
- results: SearchResult[];
151
- totalCount: number;
152
- }
153
- export interface SearchResult {
154
- file: string;
155
- line: number;
156
- content: string;
157
- matches: string[];
158
- }
159
- export interface GetIssueResponse {
160
- key: string;
161
- id: string;
162
- summary: string;
163
- description: string;
164
- status: {
165
- name: string;
166
- category: string;
37
+ head?: {
38
+ ref?: string;
167
39
  };
168
- issueType: {
169
- name: string;
170
- description: string;
40
+ base?: {
41
+ ref?: string;
171
42
  };
172
- priority: {
173
- name: string;
43
+ user?: {
44
+ login?: string;
174
45
  };
175
- assignee?: {
176
- displayName: string;
177
- emailAddress: string;
46
+ author?: {
47
+ username?: string;
178
48
  };
179
- reporter: {
180
- displayName: string;
181
- emailAddress: string;
49
+ created_on?: string;
50
+ createdAt?: string;
51
+ updated_on?: string;
52
+ updatedAt?: string;
53
+ links?: {
54
+ html?: {
55
+ href?: string;
56
+ };
182
57
  };
183
- created: string;
184
- updated: string;
185
- customFields?: Record<string, any>;
186
- }
187
- export interface SearchIssuesRequest {
188
- jql: string;
189
- maxResults?: number;
190
- startAt?: number;
191
- }
192
- export interface SearchIssuesResponse {
193
- issues: GetIssueResponse[];
194
- total: number;
195
- startAt: number;
196
- maxResults: number;
58
+ html_url?: string;
59
+ [key: string]: unknown;
197
60
  }
198
- export interface GetIssueCommentsResponse {
199
- comments: JiraComment[];
200
- total: number;
61
+ /**
62
+ * Pull request diff response from a diff-read tool call
63
+ */
64
+ export interface GetPullRequestDiffResponse {
65
+ diffs?: Array<{
66
+ source?: {
67
+ path?: string;
68
+ };
69
+ destination?: {
70
+ path?: string;
71
+ };
72
+ lines?: Array<{
73
+ type?: string;
74
+ content?: string;
75
+ line_number?: number;
76
+ old_line_number?: number;
77
+ }>;
78
+ }>;
79
+ files?: Array<{
80
+ filename?: string;
81
+ patch?: string;
82
+ changes?: number;
83
+ additions?: number;
84
+ deletions?: number;
85
+ }>;
86
+ [key: string]: unknown;
201
87
  }
202
- export interface JiraComment {
203
- id: string;
204
- author: {
205
- displayName: string;
206
- emailAddress: string;
88
+ /**
89
+ * Jira issue response from an issue-read tool call
90
+ */
91
+ export interface GetIssueResponse {
92
+ key?: string;
93
+ id?: string;
94
+ fields?: {
95
+ summary?: string;
96
+ description?: string;
97
+ status?: {
98
+ name?: string;
99
+ };
100
+ issuetype?: {
101
+ name?: string;
102
+ };
103
+ [key: string]: unknown;
207
104
  };
208
- body: string;
209
- created: string;
210
- updated: string;
105
+ [key: string]: unknown;
106
+ }
107
+ /**
108
+ * Code search response from a code-search tool call
109
+ */
110
+ export interface SearchCodeResponse {
111
+ results?: Array<{
112
+ file?: {
113
+ path?: string;
114
+ };
115
+ path?: string;
116
+ lines?: Array<{
117
+ content?: string;
118
+ line_number?: number;
119
+ }>;
120
+ content?: string;
121
+ }>;
122
+ [key: string]: unknown;
211
123
  }
212
124
  //# sourceMappingURL=mcp.types.d.ts.map
@@ -1,6 +1,13 @@
1
1
  /**
2
- * MCP Tool Response Type Definitions
3
- * Types for Bitbucket and Jira MCP tool responses
2
+ * MCP (Model Context Protocol) response type definitions.
3
+ *
4
+ * These describe the shapes Yama reads back from VCS MCP tool calls
5
+ * (Bitbucket / GitHub pull requests, diffs, code search, Jira issues).
6
+ *
7
+ * The fictional `NeuroLinkAPI`/`callTool` interface and the unused
8
+ * server-management helper types were removed when the dead VCSProvider
9
+ * classes were deleted — only these still-used response shapes (re-exported
10
+ * from src/index.ts) remain.
4
11
  */
5
12
  export {};
6
13
  //# sourceMappingURL=mcp.types.js.map
@@ -4,10 +4,15 @@
4
4
  */
5
5
  export interface ReviewRequest {
6
6
  mode: "pr";
7
- workspace: string;
8
- repository: string;
7
+ provider?: "github" | "bitbucket";
8
+ workspace?: string;
9
+ repository?: string;
10
+ owner?: string;
11
+ repo?: string;
12
+ prNumber?: number;
9
13
  pullRequestId?: number;
10
14
  branch?: string;
15
+ cloneUrl?: string;
11
16
  dryRun?: boolean;
12
17
  verbose?: boolean;
13
18
  configPath?: string;
@@ -0,0 +1,57 @@
1
+ /**
2
+ * Provider Detection Utility
3
+ * Automatically detects GitHub vs Bitbucket from environment, CLI params, or URLs
4
+ */
5
+ import type { ReviewRequest } from "../types/v2.types.js";
6
+ export type VCSProvider = "github" | "bitbucket";
7
+ export declare class ProviderDetector {
8
+ /**
9
+ * Detect VCS provider with intelligent fallback chain
10
+ * Priority: GitHub env → Request params → Clone URL → Config default → Bitbucket
11
+ */
12
+ static detect(request: ReviewRequest, env?: NodeJS.ProcessEnv, configDefault?: VCSProvider): VCSProvider;
13
+ /**
14
+ * Extract the hostname from a clone/remote URL.
15
+ * Supports SCP/SSH form (git@host:owner/repo, no scheme) and standard URLs.
16
+ * Returns a lowercased hostname, or '' if it cannot be determined.
17
+ */
18
+ private static extractHostname;
19
+ /**
20
+ * Detect provider from a clone/remote URL.
21
+ *
22
+ * Classification is based on the parsed HOSTNAME (not substring matching) to
23
+ * avoid spoofing via crafted paths or hosts such as
24
+ * "https://github.com.evil.com/...".
25
+ */
26
+ static detectFromUrl(url: string): VCSProvider;
27
+ /**
28
+ * Returns true when the host's first DNS label equals `label` AND the host
29
+ * is not a spoof where a public domain (e.g. "github.com") is embedded as a
30
+ * sub-label (e.g. "github.com.evil.com"). The latter is detected by a second
31
+ * label that is a common public TLD.
32
+ */
33
+ private static firstLabelIs;
34
+ /**
35
+ * Extract owner from GitHub URL or context
36
+ * github.com:owner/repo.git → owner
37
+ * https://github.com/owner/repo → owner
38
+ */
39
+ static extractGitHubOwner(url: string): string | null;
40
+ /**
41
+ * Extract repo name from GitHub URL
42
+ * github.com:owner/repo.git → repo
43
+ * https://github.com/owner/repo → repo
44
+ */
45
+ static extractGitHubRepo(url: string): string | null;
46
+ /**
47
+ * Extract workspace from Bitbucket URL
48
+ * bitbucket.com:workspace/repo.git → workspace
49
+ */
50
+ static extractBitbucketWorkspace(url: string): string | null;
51
+ }
52
+ /**
53
+ * Helper to detect provider from ReviewRequest
54
+ * Usage: const provider = detectProvider(request);
55
+ */
56
+ export declare function detectProvider(request: ReviewRequest, configDefault?: VCSProvider): VCSProvider;
57
+ //# sourceMappingURL=ProviderDetector.d.ts.map
@@ -0,0 +1,187 @@
1
+ /**
2
+ * Provider Detection Utility
3
+ * Automatically detects GitHub vs Bitbucket from environment, CLI params, or URLs
4
+ */
5
+ export class ProviderDetector {
6
+ /**
7
+ * Detect VCS provider with intelligent fallback chain
8
+ * Priority: GitHub env → Request params → Clone URL → Config default → Bitbucket
9
+ */
10
+ static detect(request, env = process.env, configDefault) {
11
+ // 1. Explicit provider in request
12
+ if (request.provider) {
13
+ return request.provider;
14
+ }
15
+ // 2. GitHub Actions environment
16
+ if (env.GITHUB_SERVER_URL ||
17
+ env.GITHUB_REPOSITORY ||
18
+ env.GITHUB_ACTION ||
19
+ env.GITHUB_ACTIONS === "true") {
20
+ return "github";
21
+ }
22
+ // 3. GitHub CLI parameters
23
+ if (request.owner || request.prNumber !== undefined) {
24
+ // If owner is provided, it's GitHub
25
+ if (request.owner) {
26
+ return "github";
27
+ }
28
+ }
29
+ // 4. Bitbucket CLI parameters
30
+ if (request.workspace) {
31
+ return "bitbucket";
32
+ }
33
+ // 5. Clone URL detection
34
+ if (request.cloneUrl) {
35
+ return ProviderDetector.detectFromUrl(request.cloneUrl);
36
+ }
37
+ // 6. Config-level default
38
+ if (configDefault) {
39
+ return configDefault;
40
+ }
41
+ // 7. Fallback to Bitbucket (backward compatibility)
42
+ return "bitbucket";
43
+ }
44
+ /**
45
+ * Extract the hostname from a clone/remote URL.
46
+ * Supports SCP/SSH form (git@host:owner/repo, no scheme) and standard URLs.
47
+ * Returns a lowercased hostname, or '' if it cannot be determined.
48
+ */
49
+ static extractHostname(url) {
50
+ try {
51
+ // SCP/SSH form has no scheme: [user@]host:path (path is not //...)
52
+ if (!url.includes("://")) {
53
+ const scpMatch = url.match(/^(?:[^@/]+@)?([^/:]+):(?!\/)/);
54
+ if (scpMatch) {
55
+ return scpMatch[1].toLowerCase();
56
+ }
57
+ }
58
+ // Standard URL form. Prepend a scheme if missing so URL() can parse it.
59
+ const withScheme = url.includes("://") ? url : `https://${url}`;
60
+ return new URL(withScheme).hostname.toLowerCase();
61
+ }
62
+ catch {
63
+ return "";
64
+ }
65
+ }
66
+ /**
67
+ * Detect provider from a clone/remote URL.
68
+ *
69
+ * Classification is based on the parsed HOSTNAME (not substring matching) to
70
+ * avoid spoofing via crafted paths or hosts such as
71
+ * "https://github.com.evil.com/...".
72
+ */
73
+ static detectFromUrl(url) {
74
+ const host = ProviderDetector.extractHostname(url);
75
+ // GitHub.com and GitHub Enterprise (e.g. github.enterprise.com).
76
+ // The first-label check covers Enterprise hosts whose first label is
77
+ // literally "github" (github.enterprise.com), while rejecting spoofs
78
+ // like "github.com.evil.com" where "github.com" is used as a sub-label.
79
+ if (host === "github.com" ||
80
+ host.endsWith(".github.com") ||
81
+ ProviderDetector.firstLabelIs(host, "github")) {
82
+ return "github";
83
+ }
84
+ // Bitbucket.org and Bitbucket Server/Data Center variants
85
+ if (host === "bitbucket.org" ||
86
+ host.endsWith(".bitbucket.org") ||
87
+ ProviderDetector.firstLabelIs(host, "bitbucket")) {
88
+ return "bitbucket";
89
+ }
90
+ // Default to Bitbucket if unclear (backward compatibility)
91
+ return "bitbucket";
92
+ }
93
+ /**
94
+ * Returns true when the host's first DNS label equals `label` AND the host
95
+ * is not a spoof where a public domain (e.g. "github.com") is embedded as a
96
+ * sub-label (e.g. "github.com.evil.com"). The latter is detected by a second
97
+ * label that is a common public TLD.
98
+ */
99
+ static firstLabelIs(host, label) {
100
+ const labels = host.split(".");
101
+ if (labels[0] !== label) {
102
+ return false;
103
+ }
104
+ // Reject "<label>.<tld>.<...>" spoofs (e.g. github.com.evil.com).
105
+ const tlds = new Set(["com", "org", "net", "io", "co", "dev"]);
106
+ if (labels.length > 2 && tlds.has(labels[1])) {
107
+ return false;
108
+ }
109
+ return true;
110
+ }
111
+ /**
112
+ * Extract owner from GitHub URL or context
113
+ * github.com:owner/repo.git → owner
114
+ * https://github.com/owner/repo → owner
115
+ */
116
+ static extractGitHubOwner(url) {
117
+ try {
118
+ // SSH format: git@github.com:owner/repo.git
119
+ const sshMatch = url.match(/git@github\.com:([^/]+)\//);
120
+ if (sshMatch) {
121
+ return sshMatch[1];
122
+ }
123
+ // HTTPS format: https://github.com/owner/repo
124
+ const httpsMatch = url.match(/github\.com\/([^/]+)\//);
125
+ if (httpsMatch) {
126
+ return httpsMatch[1];
127
+ }
128
+ return null;
129
+ }
130
+ catch {
131
+ return null;
132
+ }
133
+ }
134
+ /**
135
+ * Extract repo name from GitHub URL
136
+ * github.com:owner/repo.git → repo
137
+ * https://github.com/owner/repo → repo
138
+ */
139
+ static extractGitHubRepo(url) {
140
+ try {
141
+ // SSH format: git@github.com:owner/repo.git
142
+ const sshMatch = url.match(/\/([^/]+?)(?:\.git)?$/);
143
+ if (sshMatch) {
144
+ return sshMatch[1];
145
+ }
146
+ // HTTPS format: https://github.com/owner/repo
147
+ const httpsMatch = url.match(/\/([^/]+?)(?:\.git)?$/);
148
+ if (httpsMatch) {
149
+ return httpsMatch[1];
150
+ }
151
+ return null;
152
+ }
153
+ catch {
154
+ return null;
155
+ }
156
+ }
157
+ /**
158
+ * Extract workspace from Bitbucket URL
159
+ * bitbucket.com:workspace/repo.git → workspace
160
+ */
161
+ static extractBitbucketWorkspace(url) {
162
+ try {
163
+ // SSH format: git@bitbucket.org:workspace/repo.git
164
+ const match = url.match(/bitbucket[^:]*:([^/]+)\//);
165
+ if (match) {
166
+ return match[1];
167
+ }
168
+ // HTTPS format: https://bitbucket.org/workspace/repo
169
+ const httpsMatch = url.match(/bitbucket\.org\/([^/]+)\//);
170
+ if (httpsMatch) {
171
+ return httpsMatch[1];
172
+ }
173
+ return null;
174
+ }
175
+ catch {
176
+ return null;
177
+ }
178
+ }
179
+ }
180
+ /**
181
+ * Helper to detect provider from ReviewRequest
182
+ * Usage: const provider = detectProvider(request);
183
+ */
184
+ export function detectProvider(request, configDefault) {
185
+ return ProviderDetector.detect(request, process.env, configDefault);
186
+ }
187
+ //# sourceMappingURL=ProviderDetector.js.map
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@juspay/yama",
3
- "version": "2.4.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",
@@ -54,6 +54,7 @@
54
54
  ],
55
55
  "scripts": {
56
56
  "build": "rimraf dist && tsc && tsc-alias",
57
+ "build:action": "npm run build",
57
58
  "dev": "tsx watch src/cli/cli.ts",
58
59
  "dev:run": "tsx src/cli/cli.ts",
59
60
  "mcp:git:server": "uvx mcp-server-git || npx -y @modelcontextprotocol/server-git",
@@ -159,7 +160,7 @@
159
160
  ],
160
161
  "overrides": {
161
162
  "@semantic-release/npm": "^13.1.2",
162
- "undici": "^5.28.5"
163
+ "undici": "~7.22.0"
163
164
  }
164
165
  },
165
166
  "lint-staged": {