@renfeng/kiro-code-review 1.9.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/LICENSE +21 -0
- package/README.md +69 -0
- package/dist/api/gitlab-api.d.ts +122 -0
- package/dist/api/gitlab-api.d.ts.map +1 -0
- package/dist/api/gitlab-api.js +334 -0
- package/dist/api/gitlab-api.js.map +1 -0
- package/dist/bin/index.d.ts +11 -0
- package/dist/bin/index.d.ts.map +1 -0
- package/dist/bin/index.js +67 -0
- package/dist/bin/index.js.map +1 -0
- package/dist/config/glab-config.loader.d.ts +14 -0
- package/dist/config/glab-config.loader.d.ts.map +1 -0
- package/dist/config/glab-config.loader.js +87 -0
- package/dist/config/glab-config.loader.js.map +1 -0
- package/dist/errors/error-handler.d.ts +45 -0
- package/dist/errors/error-handler.d.ts.map +1 -0
- package/dist/errors/error-handler.js +134 -0
- package/dist/errors/error-handler.js.map +1 -0
- package/dist/logging/index.d.ts +2 -0
- package/dist/logging/index.d.ts.map +1 -0
- package/dist/logging/index.js +2 -0
- package/dist/logging/index.js.map +1 -0
- package/dist/logging/logger.service.d.ts +34 -0
- package/dist/logging/logger.service.d.ts.map +1 -0
- package/dist/logging/logger.service.js +91 -0
- package/dist/logging/logger.service.js.map +1 -0
- package/dist/servers/general-server.d.ts +18 -0
- package/dist/servers/general-server.d.ts.map +1 -0
- package/dist/servers/general-server.js +73 -0
- package/dist/servers/general-server.js.map +1 -0
- package/dist/servers/git-server.d.ts +17 -0
- package/dist/servers/git-server.d.ts.map +1 -0
- package/dist/servers/git-server.js +74 -0
- package/dist/servers/git-server.js.map +1 -0
- package/dist/servers/gitlab-server.d.ts +18 -0
- package/dist/servers/gitlab-server.d.ts.map +1 -0
- package/dist/servers/gitlab-server.js +139 -0
- package/dist/servers/gitlab-server.js.map +1 -0
- package/dist/services/__tests__/batch-retro.service.test.d.ts +9 -0
- package/dist/services/__tests__/batch-retro.service.test.d.ts.map +1 -0
- package/dist/services/__tests__/batch-retro.service.test.js +235 -0
- package/dist/services/__tests__/batch-retro.service.test.js.map +1 -0
- package/dist/services/__tests__/general-save-diffs.test.d.ts +5 -0
- package/dist/services/__tests__/general-save-diffs.test.d.ts.map +1 -0
- package/dist/services/__tests__/general-save-diffs.test.js +99 -0
- package/dist/services/__tests__/general-save-diffs.test.js.map +1 -0
- package/dist/services/__tests__/git-diff-files.test.d.ts +8 -0
- package/dist/services/__tests__/git-diff-files.test.d.ts.map +1 -0
- package/dist/services/__tests__/git-diff-files.test.js +64 -0
- package/dist/services/__tests__/git-diff-files.test.js.map +1 -0
- package/dist/services/__tests__/review-tools.service.test.d.ts +8 -0
- package/dist/services/__tests__/review-tools.service.test.d.ts.map +1 -0
- package/dist/services/__tests__/review-tools.service.test.js +169 -0
- package/dist/services/__tests__/review-tools.service.test.js.map +1 -0
- package/dist/services/__tests__/review-utils.service.test.d.ts +8 -0
- package/dist/services/__tests__/review-utils.service.test.d.ts.map +1 -0
- package/dist/services/__tests__/review-utils.service.test.js +306 -0
- package/dist/services/__tests__/review-utils.service.test.js.map +1 -0
- package/dist/services/anchor-resolver.d.ts +29 -0
- package/dist/services/anchor-resolver.d.ts.map +1 -0
- package/dist/services/anchor-resolver.js +97 -0
- package/dist/services/anchor-resolver.js.map +1 -0
- package/dist/services/general.service.d.ts +42 -0
- package/dist/services/general.service.d.ts.map +1 -0
- package/dist/services/general.service.js +157 -0
- package/dist/services/general.service.js.map +1 -0
- package/dist/services/git-tools.service.d.ts +123 -0
- package/dist/services/git-tools.service.d.ts.map +1 -0
- package/dist/services/git-tools.service.js +231 -0
- package/dist/services/git-tools.service.js.map +1 -0
- package/dist/services/review-tools.service.d.ts +130 -0
- package/dist/services/review-tools.service.d.ts.map +1 -0
- package/dist/services/review-tools.service.js +902 -0
- package/dist/services/review-tools.service.js.map +1 -0
- package/dist/tools/general-tools.d.ts +9 -0
- package/dist/tools/general-tools.d.ts.map +1 -0
- package/dist/tools/general-tools.js +99 -0
- package/dist/tools/general-tools.js.map +1 -0
- package/dist/tools/git-tools.d.ts +8 -0
- package/dist/tools/git-tools.d.ts.map +1 -0
- package/dist/tools/git-tools.js +175 -0
- package/dist/tools/git-tools.js.map +1 -0
- package/dist/tools/gitlab-tools.d.ts +8 -0
- package/dist/tools/gitlab-tools.d.ts.map +1 -0
- package/dist/tools/gitlab-tools.js +348 -0
- package/dist/tools/gitlab-tools.js.map +1 -0
- package/dist/types.d.ts +294 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/types.js +7 -0
- package/dist/types.js.map +1 -0
- package/package.json +51 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 ai-code-review contributors
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
ADDED
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
# AI Code Review
|
|
2
|
+
|
|
3
|
+
A Kiro workspace for AI-assisted code review automation — skills, a custom agent, and a power backed by two MCP servers.
|
|
4
|
+
|
|
5
|
+
## What's Included
|
|
6
|
+
|
|
7
|
+
### Skills (auto-registered)
|
|
8
|
+
|
|
9
|
+
| Skill | Description |
|
|
10
|
+
|-------|-------------|
|
|
11
|
+
| `code-change-review` | Platform-agnostic diff analysis. Traces callers, types, imports, tests. Produces structured findings JSON. |
|
|
12
|
+
| `gitlab-mr-review` | End-to-end GitLab MR review. Clones, analyzes, posts draft notes, publishes with verdict. Supports batch reviews. |
|
|
13
|
+
| `gitlab-todo-triage` | GitLab todo list cleanup. Marks merged/closed/draft MRs as done, delegates open MRs for review. |
|
|
14
|
+
|
|
15
|
+
### Agent (auto-registered)
|
|
16
|
+
|
|
17
|
+
`Code Change Reviewer` — subagent used by `gitlab-mr-review` for code analysis. Reads diffs in full codebase context and produces structured findings.
|
|
18
|
+
|
|
19
|
+
### Power (manual import)
|
|
20
|
+
|
|
21
|
+
`code-review` — two MCP servers from the `@renfeng/kiro-code-review` npm package:
|
|
22
|
+
- `git` — platform-agnostic git operations (clone, diff, show, log, grep)
|
|
23
|
+
- `gitlab` — GitLab API tools (MR metadata, draft notes, publish, todos)
|
|
24
|
+
|
|
25
|
+
## Usage
|
|
26
|
+
|
|
27
|
+
### 1. Add as a workspace folder
|
|
28
|
+
|
|
29
|
+
Add this repo to your `.code-workspace` file:
|
|
30
|
+
|
|
31
|
+
```json
|
|
32
|
+
{
|
|
33
|
+
"folders": [
|
|
34
|
+
{ "name": "ai-code-review", "path": "../path/to/ai-code-review" }
|
|
35
|
+
]
|
|
36
|
+
}
|
|
37
|
+
```
|
|
38
|
+
|
|
39
|
+
This auto-registers the skills and the `Code Change Reviewer` agent.
|
|
40
|
+
|
|
41
|
+
### 2. Install the power
|
|
42
|
+
|
|
43
|
+
The power provides the MCP servers that the skills depend on.
|
|
44
|
+
|
|
45
|
+
In Kiro: Powers panel → Add power from Local Path → select `.kiro/powers/code-review/` within this repo.
|
|
46
|
+
|
|
47
|
+
To update the power after pulling new changes: reinstall from the same path.
|
|
48
|
+
|
|
49
|
+
## Prerequisites
|
|
50
|
+
|
|
51
|
+
- Node.js 18+ (for `npx` to run the MCP servers)
|
|
52
|
+
- GitLab authentication via one of: `GITLAB_TOKEN` + `GITLAB_URL` env vars in the power's `mcp.json`, or `glab` CLI (`glab auth login`)
|
|
53
|
+
- SSH keys configured for git clone operations
|
|
54
|
+
|
|
55
|
+
## Troubleshooting
|
|
56
|
+
|
|
57
|
+
### 401 "Token is expired" when using glab OAuth
|
|
58
|
+
|
|
59
|
+
The `gitlab` MCP server reads the token from the `glab` config file but does not perform OAuth refresh. If the token has expired, API calls fail with `401 Unauthorized`.
|
|
60
|
+
|
|
61
|
+
Fix: run `glab auth status` — this silently refreshes the OAuth token and writes it to disk. The MCP server picks up the new token on the next call, no restart needed.
|
|
62
|
+
|
|
63
|
+
## Contributing
|
|
64
|
+
|
|
65
|
+
See [CONTRIBUTING.md](CONTRIBUTING.md).
|
|
66
|
+
|
|
67
|
+
## License
|
|
68
|
+
|
|
69
|
+
MIT
|
|
@@ -0,0 +1,122 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* GitLab API client for review-related operations.
|
|
3
|
+
*
|
|
4
|
+
* Trimmed from auto-reviewers — only methods used by ReviewToolsService are kept.
|
|
5
|
+
*/
|
|
6
|
+
import { Logger } from '../logging/logger.service.js';
|
|
7
|
+
export interface GitLabConfig {
|
|
8
|
+
baseUrl: string;
|
|
9
|
+
token: string;
|
|
10
|
+
}
|
|
11
|
+
export declare class GitLabAPI {
|
|
12
|
+
private baseUrl;
|
|
13
|
+
private token;
|
|
14
|
+
private logger;
|
|
15
|
+
constructor(config: GitLabConfig, logger?: Logger);
|
|
16
|
+
private httpGet;
|
|
17
|
+
private httpPost;
|
|
18
|
+
private httpPut;
|
|
19
|
+
private httpDelete;
|
|
20
|
+
getProjectSettings(project: string): Promise<{
|
|
21
|
+
only_allow_merge_if_all_discussions_are_resolved: boolean;
|
|
22
|
+
}>;
|
|
23
|
+
getMergeRequest(project: string, mr: number): Promise<{
|
|
24
|
+
source_branch: string;
|
|
25
|
+
target_branch: string;
|
|
26
|
+
author?: {
|
|
27
|
+
username: string;
|
|
28
|
+
};
|
|
29
|
+
} | null>;
|
|
30
|
+
getMergeRequestMetadata(project: string, mr: number): Promise<{
|
|
31
|
+
source_branch: string;
|
|
32
|
+
target_branch: string;
|
|
33
|
+
}>;
|
|
34
|
+
getMergeRequestVersions(project: string, mr: number): Promise<Array<{
|
|
35
|
+
id: number;
|
|
36
|
+
head_commit_sha: string;
|
|
37
|
+
base_commit_sha: string;
|
|
38
|
+
start_commit_sha: string;
|
|
39
|
+
created_at: string;
|
|
40
|
+
}>>;
|
|
41
|
+
getDiscussions(project: string, mr: number): Promise<unknown[]>;
|
|
42
|
+
resolveDiscussion(project: string, mr: number, discussionId: string): Promise<void>;
|
|
43
|
+
getDraftNotes(project: string, mr: number): Promise<Array<{
|
|
44
|
+
id: number;
|
|
45
|
+
note: string;
|
|
46
|
+
line_code?: string | null;
|
|
47
|
+
position?: {
|
|
48
|
+
new_path?: string;
|
|
49
|
+
old_path?: string;
|
|
50
|
+
new_line?: number | null;
|
|
51
|
+
old_line?: number | null;
|
|
52
|
+
};
|
|
53
|
+
}>>;
|
|
54
|
+
postDraftNote(project: string, mr: number, body: Record<string, unknown>): Promise<{
|
|
55
|
+
id: number;
|
|
56
|
+
line_code: string | null;
|
|
57
|
+
}>;
|
|
58
|
+
deleteDraftNote(project: string, mr: number, draftNoteId: number): Promise<void>;
|
|
59
|
+
bulkPublishDraftNotes(project: string, mr: number): Promise<boolean>;
|
|
60
|
+
getTodos(state?: string): Promise<unknown[]>;
|
|
61
|
+
markTodoDone(todoId: number): Promise<{
|
|
62
|
+
id: number;
|
|
63
|
+
state: string;
|
|
64
|
+
}>;
|
|
65
|
+
getCurrentUser(): Promise<{
|
|
66
|
+
username: string;
|
|
67
|
+
id: number;
|
|
68
|
+
}>;
|
|
69
|
+
postNote(project: string, mr: number, body: string): Promise<unknown>;
|
|
70
|
+
editNote(project: string, mr: number, noteId: number, body: string): Promise<{
|
|
71
|
+
id: number;
|
|
72
|
+
body: string;
|
|
73
|
+
}>;
|
|
74
|
+
getNotes(project: string, mr: number, sort?: 'asc' | 'desc', perPage?: number): Promise<Array<{
|
|
75
|
+
id: number;
|
|
76
|
+
body: string;
|
|
77
|
+
author: {
|
|
78
|
+
username: string;
|
|
79
|
+
};
|
|
80
|
+
system: boolean;
|
|
81
|
+
created_at: string;
|
|
82
|
+
noteable_id: number;
|
|
83
|
+
}>>;
|
|
84
|
+
replyToDiscussion(project: string, mr: number, discussionId: string, body: string): Promise<{
|
|
85
|
+
id: number;
|
|
86
|
+
body: string;
|
|
87
|
+
}>;
|
|
88
|
+
setDiscussionResolved(project: string, mr: number, discussionId: string, resolved: boolean): Promise<void>;
|
|
89
|
+
/**
|
|
90
|
+
* Get the changed files for a specific MR diff version.
|
|
91
|
+
*/
|
|
92
|
+
getMergeRequestVersionDiffs(project: string, mr: number, versionId: number): Promise<string[]>;
|
|
93
|
+
/**
|
|
94
|
+
* Execute a GraphQL query or mutation against the GitLab API.
|
|
95
|
+
* Retries on transient errors (maxRetries: 2). Callers of mutations must
|
|
96
|
+
* handle idempotency themselves (e.g. catch "already exists" errors) since
|
|
97
|
+
* retrying a mutation can cause duplicate side effects.
|
|
98
|
+
*/
|
|
99
|
+
private graphql;
|
|
100
|
+
/**
|
|
101
|
+
* Check if a custom emoji exists in a group.
|
|
102
|
+
* Fetches all emoji (unpaginated — limited to the default page size ~100).
|
|
103
|
+
*/
|
|
104
|
+
getCustomEmoji(groupPath: string, emojiName: string): Promise<{
|
|
105
|
+
name: string;
|
|
106
|
+
url: string;
|
|
107
|
+
} | null>;
|
|
108
|
+
/**
|
|
109
|
+
* Add an emoji reaction to an MR or a specific note on an MR.
|
|
110
|
+
* Returns the awarded emoji on success, or a result with id=0 on 409 (duplicate).
|
|
111
|
+
*/
|
|
112
|
+
awardEmoji(project: string, mr: number, emojiName: string, noteId?: number): Promise<{
|
|
113
|
+
id: number;
|
|
114
|
+
name: string;
|
|
115
|
+
}>;
|
|
116
|
+
/**
|
|
117
|
+
* List merge requests across all projects (top-level /merge_requests endpoint).
|
|
118
|
+
* Mirrors the GitLab dashboard views (e.g. /dashboard/merge_requests/merged).
|
|
119
|
+
*/
|
|
120
|
+
listMergeRequests(queryParams: Record<string, string>): Promise<unknown[]>;
|
|
121
|
+
}
|
|
122
|
+
//# sourceMappingURL=gitlab-api.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"gitlab-api.d.ts","sourceRoot":"","sources":["../../src/api/gitlab-api.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,334 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* GitLab API client for review-related operations.
|
|
3
|
+
*
|
|
4
|
+
* Trimmed from auto-reviewers — only methods used by ReviewToolsService are kept.
|
|
5
|
+
*/
|
|
6
|
+
import { Logger } from '../logging/logger.service.js';
|
|
7
|
+
import { ErrorHandler } from '../errors/error-handler.js';
|
|
8
|
+
export class GitLabAPI {
|
|
9
|
+
baseUrl;
|
|
10
|
+
token;
|
|
11
|
+
logger;
|
|
12
|
+
constructor(config, logger) {
|
|
13
|
+
this.baseUrl = `${config.baseUrl}/api/v4`;
|
|
14
|
+
this.token = config.token;
|
|
15
|
+
this.logger = logger || new Logger('GitLabAPI');
|
|
16
|
+
}
|
|
17
|
+
async httpGet(url, accept = "application/json") {
|
|
18
|
+
return ErrorHandler.withRetry(async () => {
|
|
19
|
+
this.logger.debug('HTTP GET request', { url });
|
|
20
|
+
const response = await fetch(url, {
|
|
21
|
+
headers: { Accept: accept, Authorization: `Bearer ${this.token}` },
|
|
22
|
+
});
|
|
23
|
+
if (response.ok) {
|
|
24
|
+
const data = await response.json();
|
|
25
|
+
this.logger.debug('HTTP GET success', { url, status: response.status });
|
|
26
|
+
return { data, nextPage: response.headers.get("x-next-page") || undefined };
|
|
27
|
+
}
|
|
28
|
+
if (response.status === 404) {
|
|
29
|
+
this.logger.debug('HTTP GET not found', { url, status: 404 });
|
|
30
|
+
return { data: null };
|
|
31
|
+
}
|
|
32
|
+
let errorDetails = "";
|
|
33
|
+
try {
|
|
34
|
+
const errorBody = await response.json();
|
|
35
|
+
errorDetails = `: ${JSON.stringify(errorBody)}`;
|
|
36
|
+
}
|
|
37
|
+
catch {
|
|
38
|
+
try {
|
|
39
|
+
errorDetails = `: ${await response.text()}`;
|
|
40
|
+
}
|
|
41
|
+
catch { /* ignore */ }
|
|
42
|
+
}
|
|
43
|
+
const error = new Error(`${response.status} ${response.statusText}${errorDetails}`);
|
|
44
|
+
this.logger.error('HTTP GET failed', error, { url, status: response.status });
|
|
45
|
+
throw error;
|
|
46
|
+
}, { maxRetries: 3, delayMs: 1000, backoffMultiplier: 2 });
|
|
47
|
+
}
|
|
48
|
+
async httpPost(url, body) {
|
|
49
|
+
return ErrorHandler.withRetry(async () => {
|
|
50
|
+
this.logger.debug('HTTP POST request', { url });
|
|
51
|
+
const response = await fetch(url, {
|
|
52
|
+
method: 'POST',
|
|
53
|
+
headers: { 'Content-Type': 'application/json', Authorization: `Bearer ${this.token}` },
|
|
54
|
+
body: JSON.stringify(body),
|
|
55
|
+
});
|
|
56
|
+
if (response.ok) {
|
|
57
|
+
const text = await response.text();
|
|
58
|
+
return text ? JSON.parse(text) : {};
|
|
59
|
+
}
|
|
60
|
+
let details = '';
|
|
61
|
+
try {
|
|
62
|
+
details = `: ${await response.text()}`;
|
|
63
|
+
}
|
|
64
|
+
catch { /* ignore */ }
|
|
65
|
+
throw new Error(`POST ${url} failed: ${response.status} ${response.statusText}${details}`);
|
|
66
|
+
}, { maxRetries: 2, delayMs: 1000, backoffMultiplier: 2 });
|
|
67
|
+
}
|
|
68
|
+
async httpPut(url, body) {
|
|
69
|
+
return ErrorHandler.withRetry(async () => {
|
|
70
|
+
this.logger.debug('HTTP PUT request', { url });
|
|
71
|
+
const response = await fetch(url, {
|
|
72
|
+
method: 'PUT',
|
|
73
|
+
headers: { 'Content-Type': 'application/json', Authorization: `Bearer ${this.token}` },
|
|
74
|
+
body: JSON.stringify(body),
|
|
75
|
+
});
|
|
76
|
+
if (response.ok) {
|
|
77
|
+
const text = await response.text();
|
|
78
|
+
return text ? JSON.parse(text) : {};
|
|
79
|
+
}
|
|
80
|
+
let details = '';
|
|
81
|
+
try {
|
|
82
|
+
details = `: ${await response.text()}`;
|
|
83
|
+
}
|
|
84
|
+
catch { /* ignore */ }
|
|
85
|
+
throw new Error(`PUT ${url} failed: ${response.status} ${response.statusText}${details}`);
|
|
86
|
+
}, { maxRetries: 2, delayMs: 1000, backoffMultiplier: 2 });
|
|
87
|
+
}
|
|
88
|
+
async httpDelete(url) {
|
|
89
|
+
return ErrorHandler.withRetry(async () => {
|
|
90
|
+
this.logger.debug('HTTP DELETE request', { url });
|
|
91
|
+
const response = await fetch(url, {
|
|
92
|
+
method: 'DELETE',
|
|
93
|
+
headers: { Authorization: `Bearer ${this.token}` },
|
|
94
|
+
});
|
|
95
|
+
if (response.ok)
|
|
96
|
+
return;
|
|
97
|
+
let details = '';
|
|
98
|
+
try {
|
|
99
|
+
details = `: ${await response.text()}`;
|
|
100
|
+
}
|
|
101
|
+
catch { /* ignore */ }
|
|
102
|
+
throw new Error(`DELETE ${url} failed: ${response.status} ${response.statusText}${details}`);
|
|
103
|
+
}, { maxRetries: 2, delayMs: 1000, backoffMultiplier: 2 });
|
|
104
|
+
}
|
|
105
|
+
// --- Project Settings ---
|
|
106
|
+
async getProjectSettings(project) {
|
|
107
|
+
const url = `${this.baseUrl}/projects/${encodeURIComponent(project)}?simple=true`;
|
|
108
|
+
const { data } = await this.httpGet(url);
|
|
109
|
+
return { only_allow_merge_if_all_discussions_are_resolved: data?.only_allow_merge_if_all_discussions_are_resolved ?? false };
|
|
110
|
+
}
|
|
111
|
+
// --- MR Metadata ---
|
|
112
|
+
async getMergeRequest(project, mr) {
|
|
113
|
+
const url = `${this.baseUrl}/projects/${encodeURIComponent(project)}/merge_requests/${mr}`;
|
|
114
|
+
const { data } = await this.httpGet(url);
|
|
115
|
+
return data;
|
|
116
|
+
}
|
|
117
|
+
async getMergeRequestMetadata(project, mr) {
|
|
118
|
+
const data = await this.getMergeRequest(project, mr);
|
|
119
|
+
if (!data)
|
|
120
|
+
throw new Error(`MR !${mr} not found in project ${project}`);
|
|
121
|
+
return { source_branch: data.source_branch, target_branch: data.target_branch };
|
|
122
|
+
}
|
|
123
|
+
async getMergeRequestVersions(project, mr) {
|
|
124
|
+
const url = `${this.baseUrl}/projects/${encodeURIComponent(project)}/merge_requests/${mr}/versions`;
|
|
125
|
+
const { data } = await this.httpGet(url);
|
|
126
|
+
return data || [];
|
|
127
|
+
}
|
|
128
|
+
// --- Discussions ---
|
|
129
|
+
async getDiscussions(project, mr) {
|
|
130
|
+
const discussions = [];
|
|
131
|
+
let page = 1;
|
|
132
|
+
do {
|
|
133
|
+
const url = `${this.baseUrl}/projects/${encodeURIComponent(project)}/merge_requests/${mr}/discussions?per_page=100&page=${page}`;
|
|
134
|
+
const { data, nextPage } = await this.httpGet(url);
|
|
135
|
+
if (data)
|
|
136
|
+
discussions.push(...data);
|
|
137
|
+
page = nextPage ? parseInt(nextPage) : 0;
|
|
138
|
+
} while (page);
|
|
139
|
+
return discussions;
|
|
140
|
+
}
|
|
141
|
+
async resolveDiscussion(project, mr, discussionId) {
|
|
142
|
+
const url = `${this.baseUrl}/projects/${encodeURIComponent(project)}/merge_requests/${mr}/discussions/${discussionId}`;
|
|
143
|
+
await this.httpPut(url, { resolved: true });
|
|
144
|
+
}
|
|
145
|
+
// --- Draft Notes ---
|
|
146
|
+
async getDraftNotes(project, mr) {
|
|
147
|
+
const url = `${this.baseUrl}/projects/${encodeURIComponent(project)}/merge_requests/${mr}/draft_notes`;
|
|
148
|
+
const { data } = await this.httpGet(url);
|
|
149
|
+
return data || [];
|
|
150
|
+
}
|
|
151
|
+
async postDraftNote(project, mr, body) {
|
|
152
|
+
const url = `${this.baseUrl}/projects/${encodeURIComponent(project)}/merge_requests/${mr}/draft_notes`;
|
|
153
|
+
return this.httpPost(url, body);
|
|
154
|
+
}
|
|
155
|
+
async deleteDraftNote(project, mr, draftNoteId) {
|
|
156
|
+
const url = `${this.baseUrl}/projects/${encodeURIComponent(project)}/merge_requests/${mr}/draft_notes/${draftNoteId}`;
|
|
157
|
+
await this.httpDelete(url);
|
|
158
|
+
}
|
|
159
|
+
async bulkPublishDraftNotes(project, mr) {
|
|
160
|
+
const url = `${this.baseUrl}/projects/${encodeURIComponent(project)}/merge_requests/${mr}/draft_notes/bulk_publish`;
|
|
161
|
+
try {
|
|
162
|
+
await this.httpPost(url, {});
|
|
163
|
+
return true;
|
|
164
|
+
}
|
|
165
|
+
catch (bulkErr) {
|
|
166
|
+
this.logger.warn('bulk_publish failed, falling back to individual publish', {
|
|
167
|
+
project, mr, error: bulkErr instanceof Error ? bulkErr.message : String(bulkErr),
|
|
168
|
+
});
|
|
169
|
+
try {
|
|
170
|
+
const drafts = await this.getDraftNotes(project, mr);
|
|
171
|
+
if (drafts.length === 0)
|
|
172
|
+
return true;
|
|
173
|
+
let published = 0;
|
|
174
|
+
for (const draft of drafts) {
|
|
175
|
+
try {
|
|
176
|
+
const pubUrl = `${this.baseUrl}/projects/${encodeURIComponent(project)}/merge_requests/${mr}/draft_notes/${draft.id}/publish`;
|
|
177
|
+
await this.httpPut(pubUrl, {});
|
|
178
|
+
published++;
|
|
179
|
+
}
|
|
180
|
+
catch (err) {
|
|
181
|
+
this.logger.warn(`Failed to publish draft ${draft.id}`, {
|
|
182
|
+
error: err instanceof Error ? err.message : String(err),
|
|
183
|
+
});
|
|
184
|
+
}
|
|
185
|
+
}
|
|
186
|
+
this.logger.info(`Individual publish fallback: ${published}/${drafts.length} drafts published`);
|
|
187
|
+
return published === drafts.length;
|
|
188
|
+
}
|
|
189
|
+
catch (fallbackErr) {
|
|
190
|
+
this.logger.error('Individual publish fallback also failed', fallbackErr instanceof Error ? fallbackErr : new Error(String(fallbackErr)));
|
|
191
|
+
return false;
|
|
192
|
+
}
|
|
193
|
+
}
|
|
194
|
+
}
|
|
195
|
+
// --- Todos ---
|
|
196
|
+
async getTodos(state = 'pending') {
|
|
197
|
+
const todos = [];
|
|
198
|
+
let page = 1;
|
|
199
|
+
do {
|
|
200
|
+
const url = `${this.baseUrl}/todos?state=${state}&per_page=100&page=${page}`;
|
|
201
|
+
const { data, nextPage } = await this.httpGet(url);
|
|
202
|
+
if (data)
|
|
203
|
+
todos.push(...data);
|
|
204
|
+
page = nextPage ? parseInt(nextPage) : 0;
|
|
205
|
+
} while (page);
|
|
206
|
+
return todos;
|
|
207
|
+
}
|
|
208
|
+
async markTodoDone(todoId) {
|
|
209
|
+
const url = `${this.baseUrl}/todos/${todoId}/mark_as_done`;
|
|
210
|
+
return this.httpPost(url, {});
|
|
211
|
+
}
|
|
212
|
+
// --- Current User ---
|
|
213
|
+
async getCurrentUser() {
|
|
214
|
+
const url = `${this.baseUrl}/user`;
|
|
215
|
+
const { data } = await this.httpGet(url);
|
|
216
|
+
return data;
|
|
217
|
+
}
|
|
218
|
+
// --- Post note (for slash commands like /approve, /request_changes) ---
|
|
219
|
+
async postNote(project, mr, body) {
|
|
220
|
+
const url = `${this.baseUrl}/projects/${encodeURIComponent(project)}/merge_requests/${mr}/notes`;
|
|
221
|
+
return this.httpPost(url, { body });
|
|
222
|
+
}
|
|
223
|
+
async editNote(project, mr, noteId, body) {
|
|
224
|
+
const url = `${this.baseUrl}/projects/${encodeURIComponent(project)}/merge_requests/${mr}/notes/${noteId}`;
|
|
225
|
+
return this.httpPut(url, { body });
|
|
226
|
+
}
|
|
227
|
+
// --- Notes (author-utils) ---
|
|
228
|
+
async getNotes(project, mr, sort = 'desc', perPage = 20) {
|
|
229
|
+
const capped = Math.min(Math.max(perPage, 1), 100);
|
|
230
|
+
const url = `${this.baseUrl}/projects/${encodeURIComponent(project)}/merge_requests/${mr}/notes?per_page=${capped}&sort=${sort}&order_by=created_at`;
|
|
231
|
+
const { data } = await this.httpGet(url);
|
|
232
|
+
return data || [];
|
|
233
|
+
}
|
|
234
|
+
async replyToDiscussion(project, mr, discussionId, body) {
|
|
235
|
+
const url = `${this.baseUrl}/projects/${encodeURIComponent(project)}/merge_requests/${mr}/discussions/${discussionId}/notes`;
|
|
236
|
+
return this.httpPost(url, { body });
|
|
237
|
+
}
|
|
238
|
+
async setDiscussionResolved(project, mr, discussionId, resolved) {
|
|
239
|
+
const url = `${this.baseUrl}/projects/${encodeURIComponent(project)}/merge_requests/${mr}/discussions/${discussionId}`;
|
|
240
|
+
await this.httpPut(url, { resolved });
|
|
241
|
+
}
|
|
242
|
+
/**
|
|
243
|
+
* Get the changed files for a specific MR diff version.
|
|
244
|
+
*/
|
|
245
|
+
async getMergeRequestVersionDiffs(project, mr, versionId) {
|
|
246
|
+
const url = `${this.baseUrl}/projects/${encodeURIComponent(project)}/merge_requests/${mr}/versions/${versionId}`;
|
|
247
|
+
const { data } = await this.httpGet(url);
|
|
248
|
+
if (!data?.diffs)
|
|
249
|
+
return [];
|
|
250
|
+
return data.diffs.map(d => d.new_path);
|
|
251
|
+
}
|
|
252
|
+
/**
|
|
253
|
+
* Execute a GraphQL query or mutation against the GitLab API.
|
|
254
|
+
* Retries on transient errors (maxRetries: 2). Callers of mutations must
|
|
255
|
+
* handle idempotency themselves (e.g. catch "already exists" errors) since
|
|
256
|
+
* retrying a mutation can cause duplicate side effects.
|
|
257
|
+
*/
|
|
258
|
+
async graphql(query, variables = {}) {
|
|
259
|
+
const url = this.baseUrl.replace('/api/v4', '/api/graphql');
|
|
260
|
+
return ErrorHandler.withRetry(async () => {
|
|
261
|
+
this.logger.debug('GraphQL request', { url });
|
|
262
|
+
const response = await fetch(url, {
|
|
263
|
+
method: 'POST',
|
|
264
|
+
headers: { 'Content-Type': 'application/json', Authorization: `Bearer ${this.token}` },
|
|
265
|
+
body: JSON.stringify({ query, variables }),
|
|
266
|
+
});
|
|
267
|
+
if (!response.ok) {
|
|
268
|
+
let details = '';
|
|
269
|
+
try {
|
|
270
|
+
details = `: ${await response.text()}`;
|
|
271
|
+
}
|
|
272
|
+
catch { /* ignore */ }
|
|
273
|
+
throw new Error(`GraphQL ${url} failed: ${response.status} ${response.statusText}${details}`);
|
|
274
|
+
}
|
|
275
|
+
const result = await response.json();
|
|
276
|
+
if (result.errors?.length) {
|
|
277
|
+
throw new Error(`GraphQL errors: ${result.errors.map(e => e.message).join('; ')}`);
|
|
278
|
+
}
|
|
279
|
+
if (!result.data) {
|
|
280
|
+
throw new Error('GraphQL response missing data field');
|
|
281
|
+
}
|
|
282
|
+
return result.data;
|
|
283
|
+
}, { maxRetries: 2, delayMs: 1000, backoffMultiplier: 2 });
|
|
284
|
+
}
|
|
285
|
+
/**
|
|
286
|
+
* Check if a custom emoji exists in a group.
|
|
287
|
+
* Fetches all emoji (unpaginated — limited to the default page size ~100).
|
|
288
|
+
*/
|
|
289
|
+
async getCustomEmoji(groupPath, emojiName) {
|
|
290
|
+
const query = `
|
|
291
|
+
query GetCustomEmoji($groupPath: ID!) {
|
|
292
|
+
group(fullPath: $groupPath) {
|
|
293
|
+
customEmoji {
|
|
294
|
+
nodes { name, url }
|
|
295
|
+
}
|
|
296
|
+
}
|
|
297
|
+
}
|
|
298
|
+
`;
|
|
299
|
+
const data = await this.graphql(query, { groupPath });
|
|
300
|
+
const nodes = data?.group?.customEmoji?.nodes || [];
|
|
301
|
+
return nodes.find(e => e.name === emojiName) || null;
|
|
302
|
+
}
|
|
303
|
+
/**
|
|
304
|
+
* Add an emoji reaction to an MR or a specific note on an MR.
|
|
305
|
+
* Returns the awarded emoji on success, or a result with id=0 on 409 (duplicate).
|
|
306
|
+
*/
|
|
307
|
+
async awardEmoji(project, mr, emojiName, noteId) {
|
|
308
|
+
const base = `${this.baseUrl}/projects/${encodeURIComponent(project)}/merge_requests/${mr}`;
|
|
309
|
+
const url = noteId ? `${base}/notes/${noteId}/award_emoji` : `${base}/award_emoji`;
|
|
310
|
+
return this.httpPost(url, { name: emojiName });
|
|
311
|
+
}
|
|
312
|
+
/**
|
|
313
|
+
* List merge requests across all projects (top-level /merge_requests endpoint).
|
|
314
|
+
* Mirrors the GitLab dashboard views (e.g. /dashboard/merge_requests/merged).
|
|
315
|
+
*/
|
|
316
|
+
async listMergeRequests(queryParams) {
|
|
317
|
+
const results = [];
|
|
318
|
+
let page = 1;
|
|
319
|
+
const perPage = parseInt(queryParams.per_page || '20', 10);
|
|
320
|
+
const maxPages = Math.ceil(100 / perPage); // Cap at ~100 MRs total
|
|
321
|
+
do {
|
|
322
|
+
const qs = new URLSearchParams({ per_page: '20', ...queryParams, page: String(page) });
|
|
323
|
+
const url = `${this.baseUrl}/merge_requests?${qs}`;
|
|
324
|
+
const { data, nextPage } = await this.httpGet(url);
|
|
325
|
+
if (data)
|
|
326
|
+
results.push(...data);
|
|
327
|
+
page = nextPage ? parseInt(nextPage) : 0;
|
|
328
|
+
if (page > maxPages)
|
|
329
|
+
break;
|
|
330
|
+
} while (page);
|
|
331
|
+
return results;
|
|
332
|
+
}
|
|
333
|
+
}
|
|
334
|
+
//# sourceMappingURL=gitlab-api.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"gitlab-api.js","sourceRoot":"","sources":["../../src/api/gitlab-api.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
/**
|
|
3
|
+
* kiro-code-review entry point
|
|
4
|
+
*
|
|
5
|
+
* Routes to the git, gitlab, or general MCP server based on the subcommand:
|
|
6
|
+
* kiro-code-review git → Git MCP server
|
|
7
|
+
* kiro-code-review gitlab → GitLab MCP server
|
|
8
|
+
* kiro-code-review general → General MCP server
|
|
9
|
+
*/
|
|
10
|
+
export {};
|
|
11
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/bin/index.ts"],"names":[],"mappings":";AAEA;;;;;;;GAOG"}
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
/**
|
|
3
|
+
* kiro-code-review entry point
|
|
4
|
+
*
|
|
5
|
+
* Routes to the git, gitlab, or general MCP server based on the subcommand:
|
|
6
|
+
* kiro-code-review git → Git MCP server
|
|
7
|
+
* kiro-code-review gitlab → GitLab MCP server
|
|
8
|
+
* kiro-code-review general → General MCP server
|
|
9
|
+
*/
|
|
10
|
+
import { config } from 'dotenv';
|
|
11
|
+
config();
|
|
12
|
+
function displayHelp() {
|
|
13
|
+
console.log(`
|
|
14
|
+
kiro-code-review
|
|
15
|
+
|
|
16
|
+
USAGE:
|
|
17
|
+
kiro-code-review <SUBCOMMAND>
|
|
18
|
+
|
|
19
|
+
SUBCOMMANDS:
|
|
20
|
+
git Start the Git MCP server (clone, diff, show, log, grep)
|
|
21
|
+
gitlab Start the GitLab MCP server (MR metadata, draft notes, publish, todos, author tools)
|
|
22
|
+
general Start the General MCP server (write findings, resolve anchors, staleness checks)
|
|
23
|
+
|
|
24
|
+
EXAMPLES:
|
|
25
|
+
npx @renfeng/kiro-code-review git
|
|
26
|
+
npx @renfeng/kiro-code-review gitlab
|
|
27
|
+
npx @renfeng/kiro-code-review general
|
|
28
|
+
`);
|
|
29
|
+
}
|
|
30
|
+
async function main() {
|
|
31
|
+
const subcommand = process.argv[2];
|
|
32
|
+
if (!subcommand || subcommand === '--help' || subcommand === '-h') {
|
|
33
|
+
displayHelp();
|
|
34
|
+
process.exit(0);
|
|
35
|
+
}
|
|
36
|
+
if (subcommand === 'git') {
|
|
37
|
+
const { GitMCPServer } = await import('../servers/git-server.js');
|
|
38
|
+
const server = new GitMCPServer();
|
|
39
|
+
process.on('SIGINT', async () => { await server.shutdown(); process.exit(0); });
|
|
40
|
+
process.on('SIGTERM', async () => { await server.shutdown(); process.exit(0); });
|
|
41
|
+
await server.run();
|
|
42
|
+
}
|
|
43
|
+
else if (subcommand === 'gitlab') {
|
|
44
|
+
const { GitLabMCPServer } = await import('../servers/gitlab-server.js');
|
|
45
|
+
const server = new GitLabMCPServer();
|
|
46
|
+
process.on('SIGINT', async () => { await server.shutdown(); process.exit(0); });
|
|
47
|
+
process.on('SIGTERM', async () => { await server.shutdown(); process.exit(0); });
|
|
48
|
+
await server.run();
|
|
49
|
+
}
|
|
50
|
+
else if (subcommand === 'general') {
|
|
51
|
+
const { GeneralMCPServer } = await import('../servers/general-server.js');
|
|
52
|
+
const server = new GeneralMCPServer();
|
|
53
|
+
process.on('SIGINT', async () => { await server.shutdown(); process.exit(0); });
|
|
54
|
+
process.on('SIGTERM', async () => { await server.shutdown(); process.exit(0); });
|
|
55
|
+
await server.run();
|
|
56
|
+
}
|
|
57
|
+
else {
|
|
58
|
+
console.error(`Error: Unknown subcommand: ${subcommand}`);
|
|
59
|
+
console.error('Available subcommands: git, gitlab, general');
|
|
60
|
+
process.exit(1);
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
main().catch((error) => {
|
|
64
|
+
console.error('Fatal error:', error.message);
|
|
65
|
+
process.exit(1);
|
|
66
|
+
});
|
|
67
|
+
//# sourceMappingURL=index.js.map
|