@gitlab/opencode-gitlab-plugin 1.5.2 → 1.5.4
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 +20 -0
- package/README.md +66 -74
- package/dist/gitlab-opencode-gitlab-plugin-1.5.4.tgz +0 -0
- package/dist/index.d.ts +5 -5
- package/dist/index.js +304 -572
- package/package.json +1 -1
- package/dist/gitlab-opencode-gitlab-plugin-1.5.2.tgz +0 -0
package/CHANGELOG.md
CHANGED
|
@@ -2,6 +2,26 @@
|
|
|
2
2
|
|
|
3
3
|
All notable changes to this project will be documented in this file. See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
|
|
4
4
|
|
|
5
|
+
## [1.5.4](https://gitlab.com/gitlab-org/editor-extensions/opencode-gitlab-plugin/compare/v1.5.3...v1.5.4) (2026-02-03)
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
### 📚 Documentation
|
|
9
|
+
|
|
10
|
+
* update README for unified discussion tools consolidation ([a832573](https://gitlab.com/gitlab-org/editor-extensions/opencode-gitlab-plugin/commit/a832573159b157c0cfe806ab1f12047325e14c56))
|
|
11
|
+
|
|
12
|
+
## [1.5.3](https://gitlab.com/gitlab-org/editor-extensions/opencode-gitlab-plugin/compare/v1.5.2...v1.5.3) (2026-02-03)
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
### 🐛 Bug Fixes
|
|
16
|
+
|
|
17
|
+
* use null checks for stricter validation ([6c39c81](https://gitlab.com/gitlab-org/editor-extensions/opencode-gitlab-plugin/commit/6c39c81aa839a99a0c12b3aa57d9376e5e3788d4))
|
|
18
|
+
|
|
19
|
+
|
|
20
|
+
### ♻️ Code Refactoring
|
|
21
|
+
|
|
22
|
+
* consolidate discussion tools into unified interface ([aa0cefd](https://gitlab.com/gitlab-org/editor-extensions/opencode-gitlab-plugin/commit/aa0cefdcc36fbd00c375ca17b0d75dbda3ecbe18))
|
|
23
|
+
* remove gitlab_create_commit tool ([4c4944d](https://gitlab.com/gitlab-org/editor-extensions/opencode-gitlab-plugin/commit/4c4944d8afcd710e7b0910d82197802eee75e6fd))
|
|
24
|
+
|
|
5
25
|
## [1.5.2](https://gitlab.com/gitlab-org/editor-extensions/opencode-gitlab-plugin/compare/v1.5.1...v1.5.2) (2026-02-02)
|
|
6
26
|
|
|
7
27
|
|
package/README.md
CHANGED
|
@@ -53,19 +53,19 @@ A comprehensive GitLab API plugin for OpenCode that provides AI-powered access t
|
|
|
53
53
|
- **Rate Limiting**: Built-in handling for GitLab API rate limits
|
|
54
54
|
- **Caching**: Efficient API response handling
|
|
55
55
|
- **Modular Architecture**: Clean separation of concerns with client and tool modules
|
|
56
|
-
- **Comprehensive Testing**:
|
|
56
|
+
- **Comprehensive Testing**: 180 tests with full coverage of all features
|
|
57
57
|
|
|
58
58
|
### GraphQL-Powered Tools
|
|
59
59
|
|
|
60
60
|
The following tools use GitLab's GraphQL API for enhanced functionality:
|
|
61
61
|
|
|
62
|
-
| Category | Tools
|
|
63
|
-
| --------------- |
|
|
64
|
-
| **TODOs** | `gitlab_list_todos`, `gitlab_get_todo_count`
|
|
65
|
-
| **Notes** | `gitlab_list_mr_notes`, `gitlab_list_issue_notes`, `gitlab_list_epic_notes`, `gitlab_list_snippet_notes`
|
|
66
|
-
| **Discussions** | `
|
|
67
|
-
| **Auto-merge** | `gitlab_set_mr_auto_merge`
|
|
68
|
-
| **Security** | All vulnerability management tools
|
|
62
|
+
| Category | Tools | Benefits |
|
|
63
|
+
| --------------- | ----------------------------------------------------------------------------------------------------------- | ---------------------------------------------------------------------------------------- |
|
|
64
|
+
| **TODOs** | `gitlab_list_todos`, `gitlab_get_todo_count` | Cursor-based pagination, rich filtering |
|
|
65
|
+
| **Notes** | `gitlab_list_mr_notes`, `gitlab_list_issue_notes`, `gitlab_list_epic_notes`, `gitlab_list_snippet_notes` | Efficient pagination, consistent response format |
|
|
66
|
+
| **Discussions** | `gitlab_list_discussions`, `gitlab_get_discussion`, `gitlab_create_discussion`, `gitlab_resolve_discussion` | Unified interface for all resource types, cursor-based pagination, code position support |
|
|
67
|
+
| **Auto-merge** | `gitlab_set_mr_auto_merge` | MWPS (Merge When Pipeline Succeeds), merge train support |
|
|
68
|
+
| **Security** | All vulnerability management tools | Type-safe GID validation, mutation support |
|
|
69
69
|
|
|
70
70
|
## 🏗️ Architecture
|
|
71
71
|
|
|
@@ -134,7 +134,7 @@ graph LR
|
|
|
134
134
|
B --> B1[readTokenFromAuthStorage]
|
|
135
135
|
B --> B2[getGitLabClient]
|
|
136
136
|
|
|
137
|
-
C --> C1[
|
|
137
|
+
C --> C1[81 Tool Definitions]
|
|
138
138
|
|
|
139
139
|
D --> A
|
|
140
140
|
D --> B
|
|
@@ -287,9 +287,9 @@ Or for API tokens:
|
|
|
287
287
|
|
|
288
288
|
## 🛠️ Available Tools
|
|
289
289
|
|
|
290
|
-
The plugin provides **
|
|
290
|
+
The plugin provides **81 tools** organized into the following categories:
|
|
291
291
|
|
|
292
|
-
### Merge Request Tools (
|
|
292
|
+
### Merge Request Tools (10 tools)
|
|
293
293
|
|
|
294
294
|
| Tool | Description |
|
|
295
295
|
| --------------------------------- | ---------------------------------------------------------------------------------------------------------------------------- |
|
|
@@ -298,34 +298,23 @@ The plugin provides **102 tools** organized into the following categories:
|
|
|
298
298
|
| `gitlab_create_merge_request` | Create a new merge request |
|
|
299
299
|
| `gitlab_update_merge_request` | Update merge request title, description, state, assignees, reviewers, and labels |
|
|
300
300
|
| `gitlab_get_mr_changes` | Get file changes/diffs for a merge request |
|
|
301
|
-
| `gitlab_list_mr_discussions` | List discussion threads on a merge request (GraphQL with cursor-based pagination) |
|
|
302
|
-
| `gitlab_get_mr_discussion` | Get a specific discussion thread with all replies |
|
|
303
301
|
| `gitlab_list_mr_notes` | List all comments with cursor-based pagination (GraphQL) |
|
|
304
|
-
| `gitlab_create_mr_note` | Add a comment or reply to a merge request discussion |
|
|
305
|
-
| `gitlab_create_mr_discussion` | Start a new discussion thread (optionally on specific code lines) |
|
|
306
|
-
| `gitlab_resolve_mr_discussion` | Mark a discussion as resolved after addressing feedback |
|
|
307
|
-
| `gitlab_unresolve_mr_discussion` | Reopen a resolved discussion |
|
|
308
302
|
| `gitlab_get_mr_commits` | Get all commits in a merge request |
|
|
309
303
|
| `gitlab_get_mr_pipelines` | Get all pipelines for a merge request |
|
|
310
304
|
| `gitlab_list_merge_request_diffs` | List file diffs with pagination support for large changesets |
|
|
311
305
|
| `gitlab_set_mr_auto_merge` | Enable auto-merge (MWPS) using GraphQL API when pipeline succeeds |
|
|
312
306
|
|
|
313
|
-
### Issue Tools (
|
|
307
|
+
### Issue Tools (5 tools)
|
|
314
308
|
|
|
315
|
-
| Tool
|
|
316
|
-
|
|
|
317
|
-
| `gitlab_create_issue`
|
|
318
|
-
| `gitlab_get_issue`
|
|
319
|
-
| `gitlab_list_issues`
|
|
320
|
-
| `gitlab_list_issue_notes`
|
|
321
|
-
| `
|
|
322
|
-
| `gitlab_get_issue_discussion` | Get a specific discussion thread with context |
|
|
323
|
-
| `gitlab_create_issue_note` | Add a comment or reply to an issue discussion |
|
|
324
|
-
| `gitlab_get_issue_note` | Get a specific note by ID with full details |
|
|
325
|
-
| `gitlab_resolve_issue_discussion` | Mark an issue discussion as resolved |
|
|
326
|
-
| `gitlab_unresolve_issue_discussion` | Reopen a resolved issue discussion |
|
|
309
|
+
| Tool | Description |
|
|
310
|
+
| ------------------------- | ---------------------------------------------------------------------------- |
|
|
311
|
+
| `gitlab_create_issue` | Create a new issue with title, description, labels, assignees, and milestone |
|
|
312
|
+
| `gitlab_get_issue` | Get issue details including state, author, assignees, labels, and comments |
|
|
313
|
+
| `gitlab_list_issues` | List issues with filtering by state, labels, assignee, and milestone |
|
|
314
|
+
| `gitlab_list_issue_notes` | List all comments with cursor-based pagination (GraphQL) |
|
|
315
|
+
| `gitlab_get_issue_note` | Get a specific note by ID with full details |
|
|
327
316
|
|
|
328
|
-
### Epic Tools (
|
|
317
|
+
### Epic Tools (9 tools)
|
|
329
318
|
|
|
330
319
|
| Tool | Description |
|
|
331
320
|
| ------------------------------- | ----------------------------------------------------------------------------- |
|
|
@@ -337,9 +326,6 @@ The plugin provides **102 tools** organized into the following categories:
|
|
|
337
326
|
| `gitlab_add_issue_to_epic` | Link an issue to an epic |
|
|
338
327
|
| `gitlab_remove_issue_from_epic` | Unlink an issue from an epic |
|
|
339
328
|
| `gitlab_list_epic_notes` | List all comments with cursor-based pagination (GraphQL) |
|
|
340
|
-
| `gitlab_list_epic_discussions` | List discussion threads with cursor-based pagination (GraphQL) |
|
|
341
|
-
| `gitlab_create_epic_note` | Add a comment or reply to an epic discussion |
|
|
342
|
-
| `gitlab_get_epic_discussion` | Get a specific epic discussion thread |
|
|
343
329
|
| `gitlab_get_epic_note` | Get a specific epic note by ID |
|
|
344
330
|
|
|
345
331
|
### Pipeline Tools (8 tools)
|
|
@@ -355,22 +341,17 @@ The plugin provides **102 tools** organized into the following categories:
|
|
|
355
341
|
| `gitlab_lint_ci_config` | Validate CI/CD YAML configuration with project context |
|
|
356
342
|
| `gitlab_lint_existing_ci_config` | Validate existing .gitlab-ci.yml from repository |
|
|
357
343
|
|
|
358
|
-
### Repository Tools (
|
|
359
|
-
|
|
360
|
-
| Tool
|
|
361
|
-
|
|
|
362
|
-
| `gitlab_get_file`
|
|
363
|
-
| `gitlab_get_commit`
|
|
364
|
-
| `gitlab_list_commits`
|
|
365
|
-
| `gitlab_get_commit_diff`
|
|
366
|
-
| `
|
|
367
|
-
| `
|
|
368
|
-
| `
|
|
369
|
-
| `gitlab_list_commit_discussions` | List discussion threads on a commit |
|
|
370
|
-
| `gitlab_get_commit_discussion` | Get a specific commit discussion thread |
|
|
371
|
-
| `gitlab_create_commit_note` | Add a comment to a commit (optionally line-specific) |
|
|
372
|
-
| `gitlab_create_commit_discussion` | Start a new discussion on a commit |
|
|
373
|
-
| `gitlab_get_commit_comments` | Get all commit comments in flat structure |
|
|
344
|
+
### Repository Tools (7 tools)
|
|
345
|
+
|
|
346
|
+
| Tool | Description |
|
|
347
|
+
| ----------------------------- | ------------------------------------------------------ |
|
|
348
|
+
| `gitlab_get_file` | Get file contents from any branch, tag, or commit |
|
|
349
|
+
| `gitlab_get_commit` | Get commit details with metadata, author, and stats |
|
|
350
|
+
| `gitlab_list_commits` | List commits with filtering by branch, path, and dates |
|
|
351
|
+
| `gitlab_get_commit_diff` | Get diff for a specific commit |
|
|
352
|
+
| `gitlab_list_repository_tree` | List files and directories at a given path |
|
|
353
|
+
| `gitlab_list_branches` | List all branches in a repository |
|
|
354
|
+
| `gitlab_get_commit_comments` | Get all commit comments in flat structure |
|
|
374
355
|
|
|
375
356
|
### Search Tools (11 tools)
|
|
376
357
|
|
|
@@ -431,22 +412,20 @@ The plugin provides **102 tools** organized into the following categories:
|
|
|
431
412
|
| `gitlab_list_project_members` | List all members of a project |
|
|
432
413
|
| `gitlab_get_current_user` | Get authenticated user information |
|
|
433
414
|
|
|
434
|
-
### Snippet Tools (
|
|
415
|
+
### Snippet Tools (1 tool)
|
|
435
416
|
|
|
436
|
-
| Tool
|
|
437
|
-
|
|
|
438
|
-
| `
|
|
439
|
-
| `gitlab_get_snippet_discussion` | Get a specific snippet discussion thread |
|
|
440
|
-
| `gitlab_list_snippet_notes` | List all comments with cursor-based pagination (GraphQL) |
|
|
441
|
-
| `gitlab_create_snippet_note` | Add a comment or reply to a snippet discussion |
|
|
442
|
-
| `gitlab_create_snippet_discussion` | Start a new discussion on a snippet |
|
|
417
|
+
| Tool | Description |
|
|
418
|
+
| --------------------------- | -------------------------------------------------------- |
|
|
419
|
+
| `gitlab_list_snippet_notes` | List all comments with cursor-based pagination (GraphQL) |
|
|
443
420
|
|
|
444
|
-
### Discussion Tools (
|
|
421
|
+
### Discussion Tools (4 tools)
|
|
445
422
|
|
|
446
|
-
| Tool
|
|
447
|
-
|
|
|
448
|
-
| `
|
|
449
|
-
| `gitlab_get_discussion`
|
|
423
|
+
| Tool | Description |
|
|
424
|
+
| --------------------------- | ------------------------------------------------------------------------------------------------------------------------ |
|
|
425
|
+
| `gitlab_list_discussions` | List discussions (comment threads) on any GitLab resource (MRs, issues, epics, commits, snippets) with cursor pagination |
|
|
426
|
+
| `gitlab_get_discussion` | Get a specific discussion thread with all replies from any resource type |
|
|
427
|
+
| `gitlab_create_discussion` | Create a new discussion thread OR reply to an existing one (supports code-position comments for MRs and commits) |
|
|
428
|
+
| `gitlab_resolve_discussion` | Mark a discussion thread as resolved or unresolve it (MRs and issues only) |
|
|
450
429
|
|
|
451
430
|
### Audit Event Tools (3 tools)
|
|
452
431
|
|
|
@@ -516,18 +495,29 @@ const mr = await plugin.tool.gitlab_get_merge_request.execute({
|
|
|
516
495
|
include_changes: true,
|
|
517
496
|
});
|
|
518
497
|
|
|
519
|
-
// Get discussions
|
|
520
|
-
const discussions = await plugin.tool.
|
|
498
|
+
// Get discussions (unified tool supports all resource types)
|
|
499
|
+
const discussions = await plugin.tool.gitlab_list_discussions.execute({
|
|
500
|
+
resource_type: 'merge_request',
|
|
521
501
|
project_id: 'gitlab-org/gitlab',
|
|
522
|
-
|
|
502
|
+
iid: 12345,
|
|
523
503
|
});
|
|
524
504
|
|
|
525
|
-
// Add a review comment
|
|
526
|
-
await plugin.tool.
|
|
505
|
+
// Add a review comment (creates a new discussion)
|
|
506
|
+
await plugin.tool.gitlab_create_discussion.execute({
|
|
507
|
+
resource_type: 'merge_request',
|
|
527
508
|
project_id: 'gitlab-org/gitlab',
|
|
528
|
-
|
|
509
|
+
iid: 12345,
|
|
529
510
|
body: 'LGTM! Great work on this feature.',
|
|
530
511
|
});
|
|
512
|
+
|
|
513
|
+
// Reply to an existing discussion thread
|
|
514
|
+
await plugin.tool.gitlab_create_discussion.execute({
|
|
515
|
+
resource_type: 'merge_request',
|
|
516
|
+
project_id: 'gitlab-org/gitlab',
|
|
517
|
+
iid: 12345,
|
|
518
|
+
discussion_id: discussions.discussions.nodes[0].id,
|
|
519
|
+
body: 'Thanks for addressing the feedback!',
|
|
520
|
+
});
|
|
531
521
|
```
|
|
532
522
|
|
|
533
523
|
### Example 3: Debug Failed Pipeline
|
|
@@ -588,10 +578,11 @@ const epicIssues = await plugin.tool.gitlab_list_epic_issues.execute({
|
|
|
588
578
|
epic_iid: epic.iid,
|
|
589
579
|
});
|
|
590
580
|
|
|
591
|
-
// Add a comment
|
|
592
|
-
await plugin.tool.
|
|
581
|
+
// Add a comment (creates a new discussion)
|
|
582
|
+
await plugin.tool.gitlab_create_discussion.execute({
|
|
583
|
+
resource_type: 'epic',
|
|
593
584
|
group_id: 'my-group',
|
|
594
|
-
|
|
585
|
+
iid: epic.iid,
|
|
595
586
|
body: 'Epic created and issues linked successfully!',
|
|
596
587
|
});
|
|
597
588
|
```
|
|
@@ -774,11 +765,12 @@ opencode-gitlab-plugin/
|
|
|
774
765
|
│ │ ├── merge-requests.ts # MR tool definitions
|
|
775
766
|
│ │ ├── pipelines.ts # Pipeline tool definitions
|
|
776
767
|
│ │ ├── repository.ts # Repository tool definitions
|
|
768
|
+
│ │ ├── discussions-unified.ts # Unified discussion tools (4 tools)
|
|
777
769
|
│ │ └── ... # Other tool definitions
|
|
778
770
|
│ ├── index.ts # Main plugin entry point
|
|
779
771
|
│ ├── utils.ts # Utility functions
|
|
780
772
|
│ └── validation.ts # GID validation utilities
|
|
781
|
-
├── tests/ # Test suite (
|
|
773
|
+
├── tests/ # Test suite (180 tests)
|
|
782
774
|
│ ├── client/ # Client tests
|
|
783
775
|
│ ├── tools/ # Tool tests
|
|
784
776
|
│ ├── validation.test.ts # Validation tests
|
|
@@ -900,7 +892,7 @@ npm run test:coverage
|
|
|
900
892
|
|
|
901
893
|
**Test Coverage:**
|
|
902
894
|
|
|
903
|
-
- **
|
|
895
|
+
- **180 tests** across 21 test files
|
|
904
896
|
- Client tests for all API methods (REST and GraphQL)
|
|
905
897
|
- Tool tests for all tool definitions
|
|
906
898
|
- Validation tests for GID utilities
|
|
Binary file
|
package/dist/index.d.ts
CHANGED
|
@@ -4,9 +4,9 @@ import { Plugin } from '@opencode-ai/plugin';
|
|
|
4
4
|
* GitLab Tools Plugin for OpenCode
|
|
5
5
|
*
|
|
6
6
|
* Provides tools for interacting with GitLab:
|
|
7
|
-
* - Merge requests: get, list, changes,
|
|
8
|
-
* - Issues: create, get, list
|
|
9
|
-
* - Epics: get, list, create, update, manage issues
|
|
7
|
+
* - Merge requests: get, list, changes, create, update, commits, pipelines, diffs (paginated), auto-merge
|
|
8
|
+
* - Issues: create, get, list
|
|
9
|
+
* - Epics: get, list, create, update, manage issues
|
|
10
10
|
* - Pipelines: list, get, jobs, logs, retry, failing jobs, CI linter
|
|
11
11
|
* - Repository: get file, commits, diff, branches, tree, create commit, commit comments
|
|
12
12
|
* - Search: projects, issues, MRs, blobs, commits, etc.
|
|
@@ -17,8 +17,8 @@ import { Plugin } from '@opencode-ai/plugin';
|
|
|
17
17
|
* - Audit: list project/group/instance audit events
|
|
18
18
|
* - Wikis: get wiki page
|
|
19
19
|
* - Work Items: get, list, create, update, notes
|
|
20
|
-
* -
|
|
21
|
-
* -
|
|
20
|
+
* - Discussions: unified tools for all resource types (list, get, create/reply, resolve)
|
|
21
|
+
* - Notes: list/get notes (flat view) for MR, issue, epic, snippet
|
|
22
22
|
* - Git: execute safe, read-only git commands in repository
|
|
23
23
|
*/
|
|
24
24
|
declare const gitlabPlugin: Plugin;
|
package/dist/index.js
CHANGED
|
@@ -2086,29 +2086,6 @@ Returns the list of files changed with their diffs.`,
|
|
|
2086
2086
|
return JSON.stringify(changes, null, 2);
|
|
2087
2087
|
}
|
|
2088
2088
|
}),
|
|
2089
|
-
gitlab_list_mr_discussions: tool({
|
|
2090
|
-
description: `List discussions (comment threads) on a merge request.
|
|
2091
|
-
Returns all discussion threads with nested notes. Each discussion contains a 'notes' array with individual comments.
|
|
2092
|
-
Note: For a flattened list of all comments, use gitlab_list_mr_notes instead.`,
|
|
2093
|
-
args: {
|
|
2094
|
-
project_id: z.string().describe("The project ID or URL-encoded path"),
|
|
2095
|
-
mr_iid: z.number().describe("The internal ID of the merge request"),
|
|
2096
|
-
first: z.number().optional().describe("Number of discussions to fetch from the beginning (default: 20)"),
|
|
2097
|
-
after: z.string().optional().describe("Cursor for forward pagination (from pageInfo.endCursor)"),
|
|
2098
|
-
last: z.number().optional().describe("Number of discussions to fetch from the end"),
|
|
2099
|
-
before: z.string().optional().describe("Cursor for backward pagination (from pageInfo.startCursor)")
|
|
2100
|
-
},
|
|
2101
|
-
execute: async (args, _ctx) => {
|
|
2102
|
-
const client = getGitLabClient();
|
|
2103
|
-
const discussions = await client.listMrDiscussions(args.project_id, args.mr_iid, {
|
|
2104
|
-
first: args.first,
|
|
2105
|
-
after: args.after,
|
|
2106
|
-
last: args.last,
|
|
2107
|
-
before: args.before
|
|
2108
|
-
});
|
|
2109
|
-
return JSON.stringify(discussions, null, 2);
|
|
2110
|
-
}
|
|
2111
|
-
}),
|
|
2112
2089
|
gitlab_list_mr_notes: tool({
|
|
2113
2090
|
description: `List all notes/comments on a merge request using GraphQL API with pagination support.
|
|
2114
2091
|
Returns all comments including system notes, code review comments, and general discussion.
|
|
@@ -2136,117 +2113,6 @@ Use 'before' with the 'startCursor' from pageInfo to get the previous page.`,
|
|
|
2136
2113
|
return JSON.stringify(result, null, 2);
|
|
2137
2114
|
}
|
|
2138
2115
|
}),
|
|
2139
|
-
gitlab_create_mr_note: tool({
|
|
2140
|
-
description: `Add a comment/note to a merge request.
|
|
2141
|
-
If discussion_id is provided, the note will be added as a reply to an existing discussion thread.
|
|
2142
|
-
Use gitlab_list_mr_discussions to find discussion IDs for existing threads.`,
|
|
2143
|
-
args: {
|
|
2144
|
-
project_id: z.string().describe("The project ID or URL-encoded path"),
|
|
2145
|
-
mr_iid: z.number().describe("The internal ID of the merge request"),
|
|
2146
|
-
body: z.string().describe("The content of the note/comment (supports Markdown)"),
|
|
2147
|
-
discussion_id: z.string().optional().describe(
|
|
2148
|
-
"The ID of a discussion thread to reply to. If provided, the note will be added as a reply to that discussion."
|
|
2149
|
-
)
|
|
2150
|
-
},
|
|
2151
|
-
execute: async (args, _ctx) => {
|
|
2152
|
-
const client = getGitLabClient();
|
|
2153
|
-
const note = await client.createMrNote(
|
|
2154
|
-
args.project_id,
|
|
2155
|
-
args.mr_iid,
|
|
2156
|
-
args.body,
|
|
2157
|
-
args.discussion_id
|
|
2158
|
-
);
|
|
2159
|
-
return JSON.stringify(note, null, 2);
|
|
2160
|
-
}
|
|
2161
|
-
}),
|
|
2162
|
-
gitlab_get_mr_discussion: tool({
|
|
2163
|
-
description: `Get a specific discussion thread from a merge request with all its replies.
|
|
2164
|
-
Returns the discussion with its 'notes' array containing all comments in the thread.
|
|
2165
|
-
Use this to get the full context of a specific conversation.`,
|
|
2166
|
-
args: {
|
|
2167
|
-
project_id: z.string().describe("The project ID or URL-encoded path"),
|
|
2168
|
-
mr_iid: z.number().describe("The internal ID of the merge request"),
|
|
2169
|
-
discussion_id: z.string().describe("The ID of the discussion thread")
|
|
2170
|
-
},
|
|
2171
|
-
execute: async (args, _ctx) => {
|
|
2172
|
-
const client = getGitLabClient();
|
|
2173
|
-
const discussion = await client.getMrDiscussion(
|
|
2174
|
-
args.project_id,
|
|
2175
|
-
args.mr_iid,
|
|
2176
|
-
args.discussion_id
|
|
2177
|
-
);
|
|
2178
|
-
return JSON.stringify(discussion, null, 2);
|
|
2179
|
-
}
|
|
2180
|
-
}),
|
|
2181
|
-
gitlab_resolve_mr_discussion: tool({
|
|
2182
|
-
description: `Mark a merge request discussion thread as resolved.
|
|
2183
|
-
Use this after addressing feedback in a code review to indicate the discussion is complete.
|
|
2184
|
-
Only works for resolvable discussions (typically code review comments).`,
|
|
2185
|
-
args: {
|
|
2186
|
-
project_id: z.string().describe("The project ID or URL-encoded path"),
|
|
2187
|
-
mr_iid: z.number().describe("The internal ID of the merge request"),
|
|
2188
|
-
discussion_id: z.string().describe("The ID of the discussion thread to resolve")
|
|
2189
|
-
},
|
|
2190
|
-
execute: async (args, _ctx) => {
|
|
2191
|
-
const client = getGitLabClient();
|
|
2192
|
-
const discussion = await client.resolveMrDiscussion(
|
|
2193
|
-
args.project_id,
|
|
2194
|
-
args.mr_iid,
|
|
2195
|
-
args.discussion_id
|
|
2196
|
-
);
|
|
2197
|
-
return JSON.stringify(discussion, null, 2);
|
|
2198
|
-
}
|
|
2199
|
-
}),
|
|
2200
|
-
gitlab_unresolve_mr_discussion: tool({
|
|
2201
|
-
description: `Reopen a resolved merge request discussion thread.
|
|
2202
|
-
Use this to indicate that a previously resolved discussion needs more attention.`,
|
|
2203
|
-
args: {
|
|
2204
|
-
project_id: z.string().describe("The project ID or URL-encoded path"),
|
|
2205
|
-
mr_iid: z.number().describe("The internal ID of the merge request"),
|
|
2206
|
-
discussion_id: z.string().describe("The ID of the discussion thread to unresolve")
|
|
2207
|
-
},
|
|
2208
|
-
execute: async (args, _ctx) => {
|
|
2209
|
-
const client = getGitLabClient();
|
|
2210
|
-
const discussion = await client.unresolveMrDiscussion(
|
|
2211
|
-
args.project_id,
|
|
2212
|
-
args.mr_iid,
|
|
2213
|
-
args.discussion_id
|
|
2214
|
-
);
|
|
2215
|
-
return JSON.stringify(discussion, null, 2);
|
|
2216
|
-
}
|
|
2217
|
-
}),
|
|
2218
|
-
gitlab_create_mr_discussion: tool({
|
|
2219
|
-
description: `Start a new discussion thread on a merge request.
|
|
2220
|
-
Creates a new discussion with an initial comment. Optionally can be positioned on specific code.
|
|
2221
|
-
For general comments, just provide the body. For code comments, provide position information.`,
|
|
2222
|
-
args: {
|
|
2223
|
-
project_id: z.string().describe("The project ID or URL-encoded path"),
|
|
2224
|
-
mr_iid: z.number().describe("The internal ID of the merge request"),
|
|
2225
|
-
body: z.string().describe("The content of the initial comment (supports Markdown)"),
|
|
2226
|
-
position: z.object({
|
|
2227
|
-
base_sha: z.string().describe("SHA of the base commit (merge base)"),
|
|
2228
|
-
start_sha: z.string().describe("SHA of the commit when the MR was created"),
|
|
2229
|
-
head_sha: z.string().describe("SHA of the HEAD commit"),
|
|
2230
|
-
position_type: z.enum(["text", "image"]).describe("Type of position (text or image)"),
|
|
2231
|
-
new_path: z.string().optional().describe("Path of the file after changes"),
|
|
2232
|
-
old_path: z.string().optional().describe("Path of the file before changes"),
|
|
2233
|
-
new_line: z.number().optional().describe("Line number in the new version"),
|
|
2234
|
-
old_line: z.number().optional().describe("Line number in the old version")
|
|
2235
|
-
}).optional().describe(
|
|
2236
|
-
"Position information for code comments. Required fields: base_sha, start_sha, head_sha, position_type. For line comments also provide new_path/old_path and new_line/old_line."
|
|
2237
|
-
)
|
|
2238
|
-
},
|
|
2239
|
-
execute: async (args, _ctx) => {
|
|
2240
|
-
const client = getGitLabClient();
|
|
2241
|
-
const discussion = await client.createMrDiscussion(
|
|
2242
|
-
args.project_id,
|
|
2243
|
-
args.mr_iid,
|
|
2244
|
-
args.body,
|
|
2245
|
-
args.position
|
|
2246
|
-
);
|
|
2247
|
-
return JSON.stringify(discussion, null, 2);
|
|
2248
|
-
}
|
|
2249
|
-
}),
|
|
2250
2116
|
gitlab_create_merge_request: tool({
|
|
2251
2117
|
description: `Create a new merge request.
|
|
2252
2118
|
Returns the created merge request with all details.`,
|
|
@@ -2491,108 +2357,6 @@ Use 'before' with the 'startCursor' from pageInfo to get the previous page.`,
|
|
|
2491
2357
|
return JSON.stringify(result, null, 2);
|
|
2492
2358
|
}
|
|
2493
2359
|
}),
|
|
2494
|
-
gitlab_list_issue_discussions: tool2({
|
|
2495
|
-
description: `List discussions (comment threads) on an issue.
|
|
2496
|
-
Returns all discussion threads with nested notes. Each discussion contains a 'notes' array with individual comments.
|
|
2497
|
-
Use the discussion 'id' field to reply to a specific thread with gitlab_create_issue_note.`,
|
|
2498
|
-
args: {
|
|
2499
|
-
project_id: z2.string().describe("The project ID or URL-encoded path"),
|
|
2500
|
-
issue_iid: z2.number().describe("The internal ID of the issue"),
|
|
2501
|
-
first: z2.number().optional().describe("Number of discussions to fetch from the beginning (default: 20)"),
|
|
2502
|
-
after: z2.string().optional().describe("Cursor for forward pagination (from pageInfo.endCursor)"),
|
|
2503
|
-
last: z2.number().optional().describe("Number of discussions to fetch from the end"),
|
|
2504
|
-
before: z2.string().optional().describe("Cursor for backward pagination (from pageInfo.startCursor)")
|
|
2505
|
-
},
|
|
2506
|
-
execute: async (args, _ctx) => {
|
|
2507
|
-
const client = getGitLabClient();
|
|
2508
|
-
const discussions = await client.listIssueDiscussions(args.project_id, args.issue_iid, {
|
|
2509
|
-
first: args.first,
|
|
2510
|
-
after: args.after,
|
|
2511
|
-
last: args.last,
|
|
2512
|
-
before: args.before
|
|
2513
|
-
});
|
|
2514
|
-
return JSON.stringify(discussions, null, 2);
|
|
2515
|
-
}
|
|
2516
|
-
}),
|
|
2517
|
-
gitlab_create_issue_note: tool2({
|
|
2518
|
-
description: `Add a comment/note to an issue.
|
|
2519
|
-
If discussion_id is provided, the note will be added as a reply to an existing discussion thread.
|
|
2520
|
-
Use gitlab_list_issue_discussions to find discussion IDs for existing threads.`,
|
|
2521
|
-
args: {
|
|
2522
|
-
project_id: z2.string().describe("The project ID or URL-encoded path"),
|
|
2523
|
-
issue_iid: z2.number().describe("The internal ID of the issue"),
|
|
2524
|
-
body: z2.string().describe("The content of the note/comment (supports Markdown)"),
|
|
2525
|
-
discussion_id: z2.string().optional().describe(
|
|
2526
|
-
"The ID of a discussion thread to reply to. If provided, the note will be added as a reply to that discussion."
|
|
2527
|
-
)
|
|
2528
|
-
},
|
|
2529
|
-
execute: async (args, _ctx) => {
|
|
2530
|
-
const client = getGitLabClient();
|
|
2531
|
-
const note = await client.createIssueNote(
|
|
2532
|
-
args.project_id,
|
|
2533
|
-
args.issue_iid,
|
|
2534
|
-
args.body,
|
|
2535
|
-
args.discussion_id
|
|
2536
|
-
);
|
|
2537
|
-
return JSON.stringify(note, null, 2);
|
|
2538
|
-
}
|
|
2539
|
-
}),
|
|
2540
|
-
gitlab_get_issue_discussion: tool2({
|
|
2541
|
-
description: `Get a specific discussion thread from an issue with all its replies.
|
|
2542
|
-
Returns the discussion with its 'notes' array containing all comments in the thread.
|
|
2543
|
-
Use this to get the full context of a specific conversation.`,
|
|
2544
|
-
args: {
|
|
2545
|
-
project_id: z2.string().describe("The project ID or URL-encoded path"),
|
|
2546
|
-
issue_iid: z2.number().describe("The internal ID of the issue"),
|
|
2547
|
-
discussion_id: z2.string().describe("The ID of the discussion thread")
|
|
2548
|
-
},
|
|
2549
|
-
execute: async (args, _ctx) => {
|
|
2550
|
-
const client = getGitLabClient();
|
|
2551
|
-
const discussion = await client.getIssueDiscussion(
|
|
2552
|
-
args.project_id,
|
|
2553
|
-
args.issue_iid,
|
|
2554
|
-
args.discussion_id
|
|
2555
|
-
);
|
|
2556
|
-
return JSON.stringify(discussion, null, 2);
|
|
2557
|
-
}
|
|
2558
|
-
}),
|
|
2559
|
-
gitlab_resolve_issue_discussion: tool2({
|
|
2560
|
-
description: `Mark an issue discussion thread as resolved.
|
|
2561
|
-
Use this after addressing feedback in a code review or issue discussion to indicate the discussion is complete.
|
|
2562
|
-
Only works for resolvable discussions (typically multi-note threads, not individual notes).`,
|
|
2563
|
-
args: {
|
|
2564
|
-
project_id: z2.string().describe("The project ID or URL-encoded path"),
|
|
2565
|
-
issue_iid: z2.number().describe("The internal ID of the issue"),
|
|
2566
|
-
discussion_id: z2.string().describe("The ID of the discussion thread to resolve")
|
|
2567
|
-
},
|
|
2568
|
-
execute: async (args, _ctx) => {
|
|
2569
|
-
const client = getGitLabClient();
|
|
2570
|
-
const discussion = await client.resolveIssueDiscussion(
|
|
2571
|
-
args.project_id,
|
|
2572
|
-
args.issue_iid,
|
|
2573
|
-
args.discussion_id
|
|
2574
|
-
);
|
|
2575
|
-
return JSON.stringify(discussion, null, 2);
|
|
2576
|
-
}
|
|
2577
|
-
}),
|
|
2578
|
-
gitlab_unresolve_issue_discussion: tool2({
|
|
2579
|
-
description: `Reopen a resolved issue discussion thread.
|
|
2580
|
-
Use this to indicate that a previously resolved discussion needs more attention or further discussion.`,
|
|
2581
|
-
args: {
|
|
2582
|
-
project_id: z2.string().describe("The project ID or URL-encoded path"),
|
|
2583
|
-
issue_iid: z2.number().describe("The internal ID of the issue"),
|
|
2584
|
-
discussion_id: z2.string().describe("The ID of the discussion thread to unresolve")
|
|
2585
|
-
},
|
|
2586
|
-
execute: async (args, _ctx) => {
|
|
2587
|
-
const client = getGitLabClient();
|
|
2588
|
-
const discussion = await client.unresolveIssueDiscussion(
|
|
2589
|
-
args.project_id,
|
|
2590
|
-
args.issue_iid,
|
|
2591
|
-
args.discussion_id
|
|
2592
|
-
);
|
|
2593
|
-
return JSON.stringify(discussion, null, 2);
|
|
2594
|
-
}
|
|
2595
|
-
}),
|
|
2596
2360
|
gitlab_get_issue_note: tool2({
|
|
2597
2361
|
description: `Get a single note/comment from an issue by its ID.
|
|
2598
2362
|
Returns the full details of a specific note including author, body, timestamps, and metadata.
|
|
@@ -2777,71 +2541,6 @@ Use 'before' with the 'startCursor' from pageInfo to get the previous page.`,
|
|
|
2777
2541
|
return JSON.stringify(result, null, 2);
|
|
2778
2542
|
}
|
|
2779
2543
|
}),
|
|
2780
|
-
gitlab_list_epic_discussions: tool3({
|
|
2781
|
-
description: `List discussions (comment threads) on an epic.
|
|
2782
|
-
Returns all discussion threads with nested notes. Each discussion contains a 'notes' array with individual comments.
|
|
2783
|
-
Use the discussion 'id' field to reply to a specific thread with gitlab_create_epic_note.`,
|
|
2784
|
-
args: {
|
|
2785
|
-
group_id: z3.string().describe("The group ID or URL-encoded path"),
|
|
2786
|
-
epic_iid: z3.number().describe("The internal ID of the epic"),
|
|
2787
|
-
first: z3.number().optional().describe("Number of discussions to fetch from the beginning (default: 20)"),
|
|
2788
|
-
after: z3.string().optional().describe("Cursor for forward pagination (from pageInfo.endCursor)"),
|
|
2789
|
-
last: z3.number().optional().describe("Number of discussions to fetch from the end"),
|
|
2790
|
-
before: z3.string().optional().describe("Cursor for backward pagination (from pageInfo.startCursor)")
|
|
2791
|
-
},
|
|
2792
|
-
execute: async (args, _ctx) => {
|
|
2793
|
-
const client = getGitLabClient();
|
|
2794
|
-
const discussions = await client.listEpicDiscussions(args.group_id, args.epic_iid, {
|
|
2795
|
-
first: args.first,
|
|
2796
|
-
after: args.after,
|
|
2797
|
-
last: args.last,
|
|
2798
|
-
before: args.before
|
|
2799
|
-
});
|
|
2800
|
-
return JSON.stringify(discussions, null, 2);
|
|
2801
|
-
}
|
|
2802
|
-
}),
|
|
2803
|
-
gitlab_create_epic_note: tool3({
|
|
2804
|
-
description: `Add a comment/note to an epic.
|
|
2805
|
-
If discussion_id is provided, the note will be added as a reply to an existing discussion thread.
|
|
2806
|
-
Use gitlab_list_epic_discussions to find discussion IDs for existing threads.`,
|
|
2807
|
-
args: {
|
|
2808
|
-
group_id: z3.string().describe("The group ID or URL-encoded path"),
|
|
2809
|
-
epic_iid: z3.number().describe("The internal ID of the epic"),
|
|
2810
|
-
body: z3.string().describe("The content of the note/comment (supports Markdown)"),
|
|
2811
|
-
discussion_id: z3.string().optional().describe(
|
|
2812
|
-
"The ID of a discussion thread to reply to. If provided, the note will be added as a reply to that discussion."
|
|
2813
|
-
)
|
|
2814
|
-
},
|
|
2815
|
-
execute: async (args, _ctx) => {
|
|
2816
|
-
const client = getGitLabClient();
|
|
2817
|
-
const note = await client.createEpicNote(
|
|
2818
|
-
args.group_id,
|
|
2819
|
-
args.epic_iid,
|
|
2820
|
-
args.body,
|
|
2821
|
-
args.discussion_id
|
|
2822
|
-
);
|
|
2823
|
-
return JSON.stringify(note, null, 2);
|
|
2824
|
-
}
|
|
2825
|
-
}),
|
|
2826
|
-
gitlab_get_epic_discussion: tool3({
|
|
2827
|
-
description: `Get a specific discussion thread from an epic with all its replies.
|
|
2828
|
-
Returns the discussion with its 'notes' array containing all comments in the thread.
|
|
2829
|
-
Use this to get the full context of a specific conversation.`,
|
|
2830
|
-
args: {
|
|
2831
|
-
group_id: z3.string().describe("The group ID or URL-encoded path"),
|
|
2832
|
-
epic_iid: z3.number().describe("The internal ID of the epic"),
|
|
2833
|
-
discussion_id: z3.string().describe("The ID of the discussion thread")
|
|
2834
|
-
},
|
|
2835
|
-
execute: async (args, _ctx) => {
|
|
2836
|
-
const client = getGitLabClient();
|
|
2837
|
-
const discussion = await client.getEpicDiscussion(
|
|
2838
|
-
args.group_id,
|
|
2839
|
-
args.epic_iid,
|
|
2840
|
-
args.discussion_id
|
|
2841
|
-
);
|
|
2842
|
-
return JSON.stringify(discussion, null, 2);
|
|
2843
|
-
}
|
|
2844
|
-
}),
|
|
2845
2544
|
gitlab_get_epic_note: tool3({
|
|
2846
2545
|
description: `Get a single note/comment from an epic by its ID.
|
|
2847
2546
|
Returns the full details of a specific note including author, body, timestamps, and metadata.
|
|
@@ -3092,40 +2791,6 @@ Returns commit metadata including author, message, stats, and parent commits.`,
|
|
|
3092
2791
|
return JSON.stringify(diff, null, 2);
|
|
3093
2792
|
}
|
|
3094
2793
|
}),
|
|
3095
|
-
gitlab_create_commit: tool5({
|
|
3096
|
-
description: `Create a commit with multiple file actions.
|
|
3097
|
-
Supports creating, updating, deleting, moving files, and changing permissions.`,
|
|
3098
|
-
args: {
|
|
3099
|
-
project_id: z5.string().describe("The project ID or URL-encoded path"),
|
|
3100
|
-
branch: z5.string().describe("Name of the branch to commit into"),
|
|
3101
|
-
commit_message: z5.string().describe("Commit message"),
|
|
3102
|
-
actions: z5.array(
|
|
3103
|
-
z5.object({
|
|
3104
|
-
action: z5.enum(["create", "delete", "move", "update", "chmod"]).describe("The action to perform"),
|
|
3105
|
-
file_path: z5.string().describe("Full path to the file"),
|
|
3106
|
-
content: z5.string().optional().describe("File content (required for create/update)"),
|
|
3107
|
-
encoding: z5.enum(["text", "base64"]).optional().describe("Encoding of content (default: text)"),
|
|
3108
|
-
previous_path: z5.string().optional().describe("Original path (required for move)"),
|
|
3109
|
-
execute_filemode: z5.boolean().optional().describe("Enable/disable execute flag (for chmod)")
|
|
3110
|
-
})
|
|
3111
|
-
).describe("Array of file actions to perform"),
|
|
3112
|
-
author_email: z5.string().optional().describe("Author email address"),
|
|
3113
|
-
author_name: z5.string().optional().describe("Author name"),
|
|
3114
|
-
start_branch: z5.string().optional().describe("Name of the branch to start from (if different from target branch)")
|
|
3115
|
-
},
|
|
3116
|
-
execute: async (args, _ctx) => {
|
|
3117
|
-
const client = getGitLabClient();
|
|
3118
|
-
const commit = await client.createCommit(args.project_id, {
|
|
3119
|
-
branch: args.branch,
|
|
3120
|
-
commit_message: args.commit_message,
|
|
3121
|
-
actions: args.actions,
|
|
3122
|
-
author_email: args.author_email,
|
|
3123
|
-
author_name: args.author_name,
|
|
3124
|
-
start_branch: args.start_branch
|
|
3125
|
-
});
|
|
3126
|
-
return JSON.stringify(commit, null, 2);
|
|
3127
|
-
}
|
|
3128
|
-
}),
|
|
3129
2794
|
gitlab_list_repository_tree: tool5({
|
|
3130
2795
|
description: `List files and directories in a repository.
|
|
3131
2796
|
Returns the tree structure of the repository at a given path and ref.`,
|
|
@@ -3159,101 +2824,6 @@ Returns the tree structure of the repository at a given path and ref.`,
|
|
|
3159
2824
|
return JSON.stringify(branches, null, 2);
|
|
3160
2825
|
}
|
|
3161
2826
|
}),
|
|
3162
|
-
// ========== Commit Discussion Tools ==========
|
|
3163
|
-
gitlab_list_commit_discussions: tool5({
|
|
3164
|
-
description: `List discussions (comment threads) on a commit.
|
|
3165
|
-
Returns all discussion threads with nested notes. Each discussion contains a 'notes' array with individual comments.
|
|
3166
|
-
Use the discussion 'id' field to reply to a specific thread with gitlab_create_commit_note.`,
|
|
3167
|
-
args: {
|
|
3168
|
-
project_id: z5.string().describe("The project ID or URL-encoded path"),
|
|
3169
|
-
sha: z5.string().describe("The commit SHA")
|
|
3170
|
-
},
|
|
3171
|
-
execute: async (args, _ctx) => {
|
|
3172
|
-
const client = getGitLabClient();
|
|
3173
|
-
const discussions = await client.listCommitDiscussions(args.project_id, args.sha);
|
|
3174
|
-
return JSON.stringify(discussions, null, 2);
|
|
3175
|
-
}
|
|
3176
|
-
}),
|
|
3177
|
-
gitlab_get_commit_discussion: tool5({
|
|
3178
|
-
description: `Get a specific discussion thread from a commit with all its replies.
|
|
3179
|
-
Returns the discussion with its 'notes' array containing all comments in the thread.
|
|
3180
|
-
Use this to get the full context of a specific conversation.`,
|
|
3181
|
-
args: {
|
|
3182
|
-
project_id: z5.string().describe("The project ID or URL-encoded path"),
|
|
3183
|
-
sha: z5.string().describe("The commit SHA"),
|
|
3184
|
-
discussion_id: z5.string().describe("The ID of the discussion thread")
|
|
3185
|
-
},
|
|
3186
|
-
execute: async (args, _ctx) => {
|
|
3187
|
-
const client = getGitLabClient();
|
|
3188
|
-
const discussion = await client.getCommitDiscussion(
|
|
3189
|
-
args.project_id,
|
|
3190
|
-
args.sha,
|
|
3191
|
-
args.discussion_id
|
|
3192
|
-
);
|
|
3193
|
-
return JSON.stringify(discussion, null, 2);
|
|
3194
|
-
}
|
|
3195
|
-
}),
|
|
3196
|
-
gitlab_create_commit_note: tool5({
|
|
3197
|
-
description: `Add a comment/note to a commit.
|
|
3198
|
-
If discussion_id is provided, the note will be added as a reply to an existing discussion thread.
|
|
3199
|
-
Optionally, you can create a line-specific comment by providing path, line, and line_type.
|
|
3200
|
-
Use gitlab_list_commit_discussions to find discussion IDs for existing threads.`,
|
|
3201
|
-
args: {
|
|
3202
|
-
project_id: z5.string().describe("The project ID or URL-encoded path"),
|
|
3203
|
-
sha: z5.string().describe("The commit SHA"),
|
|
3204
|
-
body: z5.string().describe("The content of the note/comment (supports Markdown)"),
|
|
3205
|
-
discussion_id: z5.string().optional().describe(
|
|
3206
|
-
"The ID of a discussion thread to reply to. If provided, the note will be added as a reply to that discussion."
|
|
3207
|
-
),
|
|
3208
|
-
path: z5.string().optional().describe("The file path to comment on (for line-specific comments)"),
|
|
3209
|
-
line: z5.number().optional().describe("The line number to comment on (for line-specific comments)"),
|
|
3210
|
-
line_type: z5.enum(["new", "old"]).optional().describe(
|
|
3211
|
-
'The type of line being commented on: "new" for added lines, "old" for removed lines'
|
|
3212
|
-
)
|
|
3213
|
-
},
|
|
3214
|
-
execute: async (args, _ctx) => {
|
|
3215
|
-
const client = getGitLabClient();
|
|
3216
|
-
const note = await client.createCommitNote(args.project_id, args.sha, args.body, {
|
|
3217
|
-
discussion_id: args.discussion_id,
|
|
3218
|
-
path: args.path,
|
|
3219
|
-
line: args.line,
|
|
3220
|
-
line_type: args.line_type
|
|
3221
|
-
});
|
|
3222
|
-
return JSON.stringify(note, null, 2);
|
|
3223
|
-
}
|
|
3224
|
-
}),
|
|
3225
|
-
gitlab_create_commit_discussion: tool5({
|
|
3226
|
-
description: `Start a new discussion thread on a commit.
|
|
3227
|
-
Creates a new discussion with an initial comment. Optionally can be positioned on specific code.
|
|
3228
|
-
For general comments, just provide the body. For code comments, provide position information.`,
|
|
3229
|
-
args: {
|
|
3230
|
-
project_id: z5.string().describe("The project ID or URL-encoded path"),
|
|
3231
|
-
sha: z5.string().describe("The commit SHA"),
|
|
3232
|
-
body: z5.string().describe("The content of the initial comment (supports Markdown)"),
|
|
3233
|
-
position: z5.object({
|
|
3234
|
-
base_sha: z5.string().describe("SHA of the base commit"),
|
|
3235
|
-
start_sha: z5.string().describe("SHA of the start commit"),
|
|
3236
|
-
head_sha: z5.string().describe("SHA of the HEAD commit"),
|
|
3237
|
-
position_type: z5.enum(["text", "image"]).describe("Type of position (text or image)"),
|
|
3238
|
-
new_path: z5.string().optional().describe("Path of the file after changes"),
|
|
3239
|
-
old_path: z5.string().optional().describe("Path of the file before changes"),
|
|
3240
|
-
new_line: z5.number().optional().describe("Line number in the new version"),
|
|
3241
|
-
old_line: z5.number().optional().describe("Line number in the old version")
|
|
3242
|
-
}).optional().describe(
|
|
3243
|
-
"Position information for code comments. Required fields: base_sha, start_sha, head_sha, position_type. For line comments also provide new_path/old_path and new_line/old_line."
|
|
3244
|
-
)
|
|
3245
|
-
},
|
|
3246
|
-
execute: async (args, _ctx) => {
|
|
3247
|
-
const client = getGitLabClient();
|
|
3248
|
-
const discussion = await client.createCommitDiscussion(
|
|
3249
|
-
args.project_id,
|
|
3250
|
-
args.sha,
|
|
3251
|
-
args.body,
|
|
3252
|
-
args.position
|
|
3253
|
-
);
|
|
3254
|
-
return JSON.stringify(discussion, null, 2);
|
|
3255
|
-
}
|
|
3256
|
-
}),
|
|
3257
2827
|
gitlab_get_commit_comments: tool5({
|
|
3258
2828
|
description: `Get all comments on a specific commit.
|
|
3259
2829
|
Returns all comments (notes) that have been added to a commit, including line-specific comments.
|
|
@@ -3269,12 +2839,6 @@ This is different from discussions - it returns individual comments in a flat st
|
|
|
3269
2839
|
}
|
|
3270
2840
|
})
|
|
3271
2841
|
};
|
|
3272
|
-
var commitDiscussionTools = {
|
|
3273
|
-
gitlab_list_commit_discussions: repositoryTools.gitlab_list_commit_discussions,
|
|
3274
|
-
gitlab_get_commit_discussion: repositoryTools.gitlab_get_commit_discussion,
|
|
3275
|
-
gitlab_create_commit_note: repositoryTools.gitlab_create_commit_note,
|
|
3276
|
-
gitlab_create_commit_discussion: repositoryTools.gitlab_create_commit_discussion
|
|
3277
|
-
};
|
|
3278
2842
|
|
|
3279
2843
|
// src/tools/search.ts
|
|
3280
2844
|
import { tool as tool6 } from "@opencode-ai/plugin";
|
|
@@ -3760,48 +3324,6 @@ Requires Developer role or higher.`,
|
|
|
3760
3324
|
import { tool as tool9 } from "@opencode-ai/plugin";
|
|
3761
3325
|
var z9 = tool9.schema;
|
|
3762
3326
|
var snippetTools = {
|
|
3763
|
-
gitlab_list_snippet_discussions: tool9({
|
|
3764
|
-
description: `List discussions (comment threads) on a project snippet.
|
|
3765
|
-
Returns all discussion threads with nested notes. Each discussion contains a 'notes' array with individual comments.
|
|
3766
|
-
Use the discussion 'id' field to reply to a specific thread with gitlab_create_snippet_note.`,
|
|
3767
|
-
args: {
|
|
3768
|
-
project_id: z9.string().describe("The project ID or URL-encoded path"),
|
|
3769
|
-
snippet_id: z9.number().describe("The ID of the snippet"),
|
|
3770
|
-
first: z9.number().optional().describe("Number of discussions to fetch from the beginning (default: 20)"),
|
|
3771
|
-
after: z9.string().optional().describe("Cursor for forward pagination (from pageInfo.endCursor)"),
|
|
3772
|
-
last: z9.number().optional().describe("Number of discussions to fetch from the end"),
|
|
3773
|
-
before: z9.string().optional().describe("Cursor for backward pagination (from pageInfo.startCursor)")
|
|
3774
|
-
},
|
|
3775
|
-
execute: async (args, _ctx) => {
|
|
3776
|
-
const client = getGitLabClient();
|
|
3777
|
-
const discussions = await client.listSnippetDiscussions(args.project_id, args.snippet_id, {
|
|
3778
|
-
first: args.first,
|
|
3779
|
-
after: args.after,
|
|
3780
|
-
last: args.last,
|
|
3781
|
-
before: args.before
|
|
3782
|
-
});
|
|
3783
|
-
return JSON.stringify(discussions, null, 2);
|
|
3784
|
-
}
|
|
3785
|
-
}),
|
|
3786
|
-
gitlab_get_snippet_discussion: tool9({
|
|
3787
|
-
description: `Get a specific discussion thread from a snippet with all its replies.
|
|
3788
|
-
Returns the discussion with its 'notes' array containing all comments in the thread.
|
|
3789
|
-
Use this to get the full context of a specific conversation.`,
|
|
3790
|
-
args: {
|
|
3791
|
-
project_id: z9.string().describe("The project ID or URL-encoded path"),
|
|
3792
|
-
snippet_id: z9.number().describe("The ID of the snippet"),
|
|
3793
|
-
discussion_id: z9.string().describe("The ID of the discussion thread")
|
|
3794
|
-
},
|
|
3795
|
-
execute: async (args, _ctx) => {
|
|
3796
|
-
const client = getGitLabClient();
|
|
3797
|
-
const discussion = await client.getSnippetDiscussion(
|
|
3798
|
-
args.project_id,
|
|
3799
|
-
args.snippet_id,
|
|
3800
|
-
args.discussion_id
|
|
3801
|
-
);
|
|
3802
|
-
return JSON.stringify(discussion, null, 2);
|
|
3803
|
-
}
|
|
3804
|
-
}),
|
|
3805
3327
|
gitlab_list_snippet_notes: tool9({
|
|
3806
3328
|
description: `List all notes/comments on a project snippet using GraphQL API with pagination support.
|
|
3807
3329
|
Returns all comments including system notes in chronological order.
|
|
@@ -3827,47 +3349,6 @@ Use 'before' with the 'startCursor' from pageInfo to get the previous page.`,
|
|
|
3827
3349
|
});
|
|
3828
3350
|
return JSON.stringify(result, null, 2);
|
|
3829
3351
|
}
|
|
3830
|
-
}),
|
|
3831
|
-
gitlab_create_snippet_note: tool9({
|
|
3832
|
-
description: `Add a comment/note to a project snippet.
|
|
3833
|
-
If discussion_id is provided, the note will be added as a reply to an existing discussion thread.
|
|
3834
|
-
Use gitlab_list_snippet_discussions to find discussion IDs for existing threads.`,
|
|
3835
|
-
args: {
|
|
3836
|
-
project_id: z9.string().describe("The project ID or URL-encoded path"),
|
|
3837
|
-
snippet_id: z9.number().describe("The ID of the snippet"),
|
|
3838
|
-
body: z9.string().describe("The content of the note/comment (supports Markdown)"),
|
|
3839
|
-
discussion_id: z9.string().optional().describe(
|
|
3840
|
-
"The ID of a discussion thread to reply to. If provided, the note will be added as a reply to that discussion."
|
|
3841
|
-
)
|
|
3842
|
-
},
|
|
3843
|
-
execute: async (args, _ctx) => {
|
|
3844
|
-
const client = getGitLabClient();
|
|
3845
|
-
const note = await client.createSnippetNote(
|
|
3846
|
-
args.project_id,
|
|
3847
|
-
args.snippet_id,
|
|
3848
|
-
args.body,
|
|
3849
|
-
args.discussion_id
|
|
3850
|
-
);
|
|
3851
|
-
return JSON.stringify(note, null, 2);
|
|
3852
|
-
}
|
|
3853
|
-
}),
|
|
3854
|
-
gitlab_create_snippet_discussion: tool9({
|
|
3855
|
-
description: `Start a new discussion thread on a project snippet.
|
|
3856
|
-
Creates a new discussion with an initial comment.`,
|
|
3857
|
-
args: {
|
|
3858
|
-
project_id: z9.string().describe("The project ID or URL-encoded path"),
|
|
3859
|
-
snippet_id: z9.number().describe("The ID of the snippet"),
|
|
3860
|
-
body: z9.string().describe("The content of the initial comment (supports Markdown)")
|
|
3861
|
-
},
|
|
3862
|
-
execute: async (args, _ctx) => {
|
|
3863
|
-
const client = getGitLabClient();
|
|
3864
|
-
const discussion = await client.createSnippetDiscussion(
|
|
3865
|
-
args.project_id,
|
|
3866
|
-
args.snippet_id,
|
|
3867
|
-
args.body
|
|
3868
|
-
);
|
|
3869
|
-
return JSON.stringify(discussion, null, 2);
|
|
3870
|
-
}
|
|
3871
3352
|
})
|
|
3872
3353
|
};
|
|
3873
3354
|
|
|
@@ -4093,68 +3574,321 @@ Can update title, description, state, labels, and assignees.`,
|
|
|
4093
3574
|
})
|
|
4094
3575
|
};
|
|
4095
3576
|
|
|
4096
|
-
// src/tools/discussions.ts
|
|
3577
|
+
// src/tools/discussions-unified.ts
|
|
4097
3578
|
import { tool as tool13 } from "@opencode-ai/plugin";
|
|
4098
3579
|
var z13 = tool13.schema;
|
|
4099
|
-
var
|
|
4100
|
-
|
|
4101
|
-
|
|
4102
|
-
|
|
4103
|
-
|
|
3580
|
+
var positionSchema = z13.object({
|
|
3581
|
+
base_sha: z13.string().describe("SHA of the base commit"),
|
|
3582
|
+
start_sha: z13.string().describe("SHA of the start commit"),
|
|
3583
|
+
head_sha: z13.string().describe("SHA of the head commit"),
|
|
3584
|
+
position_type: z13.enum(["text", "image"]).describe("Type of position"),
|
|
3585
|
+
old_path: z13.string().optional().describe("Path of the file before changes"),
|
|
3586
|
+
new_path: z13.string().optional().describe("Path of the file after changes"),
|
|
3587
|
+
old_line: z13.number().optional().describe("Line number in the old version"),
|
|
3588
|
+
new_line: z13.number().optional().describe("Line number in the new version")
|
|
3589
|
+
});
|
|
3590
|
+
function validateResourceParams(resourceType, args) {
|
|
3591
|
+
switch (resourceType) {
|
|
3592
|
+
case "merge_request":
|
|
3593
|
+
case "issue":
|
|
3594
|
+
if (!args.project_id) throw new Error(`project_id is required for ${resourceType}`);
|
|
3595
|
+
if (args.iid == null) throw new Error(`iid is required for ${resourceType}`);
|
|
3596
|
+
break;
|
|
3597
|
+
case "epic":
|
|
3598
|
+
if (!args.group_id) throw new Error("group_id is required for epic");
|
|
3599
|
+
if (args.iid == null) throw new Error("iid is required for epic");
|
|
3600
|
+
break;
|
|
3601
|
+
case "commit":
|
|
3602
|
+
if (!args.project_id) throw new Error("project_id is required for commit");
|
|
3603
|
+
if (!args.sha) throw new Error("sha is required for commit");
|
|
3604
|
+
break;
|
|
3605
|
+
case "snippet":
|
|
3606
|
+
if (!args.project_id) throw new Error("project_id is required for snippet");
|
|
3607
|
+
if (args.snippet_id == null) throw new Error("snippet_id is required for snippet");
|
|
3608
|
+
break;
|
|
3609
|
+
}
|
|
3610
|
+
}
|
|
3611
|
+
var discussionsUnifiedTools = {
|
|
3612
|
+
/**
|
|
3613
|
+
* List discussions for any GitLab resource type
|
|
3614
|
+
*/
|
|
3615
|
+
gitlab_list_discussions: tool13({
|
|
3616
|
+
description: `List discussions (comment threads) on any GitLab resource.
|
|
3617
|
+
Supports: merge_requests, issues, epics, commits, snippets.
|
|
3618
|
+
|
|
3619
|
+
Returns discussion threads with nested notes. Each discussion contains
|
|
3620
|
+
a 'notes' array with individual comments.
|
|
3621
|
+
|
|
3622
|
+
For pagination, use 'after' with the 'endCursor' from pageInfo to get the next page.
|
|
3623
|
+
|
|
3624
|
+
Examples:
|
|
3625
|
+
- MR: resource_type="merge_request", project_id="group/project", iid=123
|
|
3626
|
+
- Issue: resource_type="issue", project_id="group/project", iid=456
|
|
3627
|
+
- Epic: resource_type="epic", group_id="my-group", iid=1
|
|
3628
|
+
- Commit: resource_type="commit", project_id="group/project", sha="abc123"
|
|
3629
|
+
- Snippet: resource_type="snippet", project_id="group/project", snippet_id=789`,
|
|
4104
3630
|
args: {
|
|
4105
|
-
resource_type: z13.enum(["merge_request", "issue", "epic", "commit", "snippet"]).describe("
|
|
4106
|
-
project_id: z13.string().optional().describe("
|
|
4107
|
-
group_id: z13.string().optional().describe("
|
|
4108
|
-
iid: z13.number().optional().describe("
|
|
4109
|
-
sha: z13.string().optional().describe("
|
|
4110
|
-
snippet_id: z13.number().optional().describe("
|
|
4111
|
-
|
|
4112
|
-
|
|
3631
|
+
resource_type: z13.enum(["merge_request", "issue", "epic", "commit", "snippet"]).describe("Type of GitLab resource"),
|
|
3632
|
+
project_id: z13.string().optional().describe("Project ID or path. Required for merge_request, issue, commit, snippet"),
|
|
3633
|
+
group_id: z13.string().optional().describe("Group ID or path. Required for epic"),
|
|
3634
|
+
iid: z13.number().optional().describe("Internal ID of the resource (for merge_request, issue, epic)"),
|
|
3635
|
+
sha: z13.string().optional().describe("Commit SHA (required for commit)"),
|
|
3636
|
+
snippet_id: z13.number().optional().describe("Snippet ID (required for snippet)"),
|
|
3637
|
+
// Pagination
|
|
3638
|
+
first: z13.number().optional().describe("Number of items to return (default: 20)"),
|
|
3639
|
+
after: z13.string().optional().describe("Cursor for pagination - use endCursor from previous response"),
|
|
3640
|
+
before: z13.string().optional().describe("Cursor for backward pagination"),
|
|
3641
|
+
last: z13.number().optional().describe("Number of items from the end")
|
|
4113
3642
|
},
|
|
4114
3643
|
execute: async (args, _ctx) => {
|
|
3644
|
+
validateResourceParams(args.resource_type, args);
|
|
4115
3645
|
const client = getGitLabClient();
|
|
4116
|
-
const
|
|
4117
|
-
args.
|
|
4118
|
-
|
|
4119
|
-
|
|
4120
|
-
|
|
4121
|
-
|
|
4122
|
-
|
|
4123
|
-
|
|
4124
|
-
|
|
4125
|
-
|
|
4126
|
-
|
|
4127
|
-
|
|
4128
|
-
|
|
3646
|
+
const paginationOptions = {
|
|
3647
|
+
first: args.first,
|
|
3648
|
+
after: args.after,
|
|
3649
|
+
before: args.before,
|
|
3650
|
+
last: args.last
|
|
3651
|
+
};
|
|
3652
|
+
switch (args.resource_type) {
|
|
3653
|
+
case "merge_request":
|
|
3654
|
+
return JSON.stringify(
|
|
3655
|
+
await client.listMrDiscussions(args.project_id, args.iid, paginationOptions),
|
|
3656
|
+
null,
|
|
3657
|
+
2
|
|
3658
|
+
);
|
|
3659
|
+
case "issue":
|
|
3660
|
+
return JSON.stringify(
|
|
3661
|
+
await client.listIssueDiscussions(args.project_id, args.iid, paginationOptions),
|
|
3662
|
+
null,
|
|
3663
|
+
2
|
|
3664
|
+
);
|
|
3665
|
+
case "epic":
|
|
3666
|
+
return JSON.stringify(
|
|
3667
|
+
await client.listEpicDiscussions(args.group_id, args.iid, paginationOptions),
|
|
3668
|
+
null,
|
|
3669
|
+
2
|
|
3670
|
+
);
|
|
3671
|
+
case "commit":
|
|
3672
|
+
return JSON.stringify(
|
|
3673
|
+
await client.listCommitDiscussions(args.project_id, args.sha),
|
|
3674
|
+
null,
|
|
3675
|
+
2
|
|
3676
|
+
);
|
|
3677
|
+
case "snippet":
|
|
3678
|
+
return JSON.stringify(
|
|
3679
|
+
await client.listSnippetDiscussions(
|
|
3680
|
+
args.project_id,
|
|
3681
|
+
args.snippet_id,
|
|
3682
|
+
paginationOptions
|
|
3683
|
+
),
|
|
3684
|
+
null,
|
|
3685
|
+
2
|
|
3686
|
+
);
|
|
3687
|
+
default:
|
|
3688
|
+
throw new Error(`Unsupported resource type: ${args.resource_type}`);
|
|
3689
|
+
}
|
|
4129
3690
|
}
|
|
4130
3691
|
}),
|
|
3692
|
+
/**
|
|
3693
|
+
* Get a specific discussion thread from any GitLab resource
|
|
3694
|
+
*/
|
|
4131
3695
|
gitlab_get_discussion: tool13({
|
|
4132
|
-
description: `
|
|
4133
|
-
|
|
4134
|
-
|
|
3696
|
+
description: `Get a specific discussion thread with all its replies.
|
|
3697
|
+
Returns the discussion with its 'notes' array containing all comments.
|
|
3698
|
+
|
|
3699
|
+
Use this to get full context of a specific conversation.
|
|
3700
|
+
|
|
3701
|
+
Required parameters vary by resource type:
|
|
3702
|
+
- merge_request: project_id, iid, discussion_id
|
|
3703
|
+
- issue: project_id, iid, discussion_id
|
|
3704
|
+
- epic: group_id, iid, discussion_id
|
|
3705
|
+
- commit: project_id, sha, discussion_id
|
|
3706
|
+
- snippet: project_id, snippet_id, discussion_id`,
|
|
4135
3707
|
args: {
|
|
4136
|
-
resource_type: z13.enum(["merge_request", "issue", "epic", "commit", "snippet"]).describe("
|
|
4137
|
-
|
|
4138
|
-
|
|
4139
|
-
|
|
4140
|
-
|
|
4141
|
-
|
|
4142
|
-
|
|
3708
|
+
resource_type: z13.enum(["merge_request", "issue", "epic", "commit", "snippet"]).describe("Type of GitLab resource"),
|
|
3709
|
+
discussion_id: z13.string().describe("The ID of the discussion thread"),
|
|
3710
|
+
project_id: z13.string().optional().describe("Project ID or path"),
|
|
3711
|
+
group_id: z13.string().optional().describe("Group ID or path (for epic)"),
|
|
3712
|
+
iid: z13.number().optional().describe("Internal ID (for merge_request, issue, epic)"),
|
|
3713
|
+
sha: z13.string().optional().describe("Commit SHA (for commit)"),
|
|
3714
|
+
snippet_id: z13.number().optional().describe("Snippet ID (for snippet)")
|
|
4143
3715
|
},
|
|
4144
3716
|
execute: async (args, _ctx) => {
|
|
3717
|
+
validateResourceParams(args.resource_type, args);
|
|
4145
3718
|
const client = getGitLabClient();
|
|
4146
|
-
|
|
4147
|
-
|
|
4148
|
-
|
|
4149
|
-
|
|
4150
|
-
|
|
4151
|
-
|
|
4152
|
-
|
|
4153
|
-
|
|
4154
|
-
|
|
4155
|
-
|
|
4156
|
-
|
|
4157
|
-
|
|
3719
|
+
switch (args.resource_type) {
|
|
3720
|
+
case "merge_request":
|
|
3721
|
+
return JSON.stringify(
|
|
3722
|
+
await client.getMrDiscussion(args.project_id, args.iid, args.discussion_id),
|
|
3723
|
+
null,
|
|
3724
|
+
2
|
|
3725
|
+
);
|
|
3726
|
+
case "issue":
|
|
3727
|
+
return JSON.stringify(
|
|
3728
|
+
await client.getIssueDiscussion(args.project_id, args.iid, args.discussion_id),
|
|
3729
|
+
null,
|
|
3730
|
+
2
|
|
3731
|
+
);
|
|
3732
|
+
case "epic":
|
|
3733
|
+
return JSON.stringify(
|
|
3734
|
+
await client.getEpicDiscussion(args.group_id, args.iid, args.discussion_id),
|
|
3735
|
+
null,
|
|
3736
|
+
2
|
|
3737
|
+
);
|
|
3738
|
+
case "commit":
|
|
3739
|
+
return JSON.stringify(
|
|
3740
|
+
await client.getCommitDiscussion(args.project_id, args.sha, args.discussion_id),
|
|
3741
|
+
null,
|
|
3742
|
+
2
|
|
3743
|
+
);
|
|
3744
|
+
case "snippet":
|
|
3745
|
+
return JSON.stringify(
|
|
3746
|
+
await client.getSnippetDiscussion(
|
|
3747
|
+
args.project_id,
|
|
3748
|
+
args.snippet_id,
|
|
3749
|
+
args.discussion_id
|
|
3750
|
+
),
|
|
3751
|
+
null,
|
|
3752
|
+
2
|
|
3753
|
+
);
|
|
3754
|
+
default:
|
|
3755
|
+
throw new Error(`Unsupported resource type: ${args.resource_type}`);
|
|
3756
|
+
}
|
|
3757
|
+
}
|
|
3758
|
+
}),
|
|
3759
|
+
/**
|
|
3760
|
+
* Create a new discussion thread or reply to an existing one
|
|
3761
|
+
*/
|
|
3762
|
+
gitlab_create_discussion: tool13({
|
|
3763
|
+
description: `Create a new discussion thread or reply to an existing one.
|
|
3764
|
+
|
|
3765
|
+
For NEW discussion: Omit discussion_id
|
|
3766
|
+
For REPLY to existing thread: Include discussion_id (preferred over gitlab_create_note for threaded conversations)
|
|
3767
|
+
|
|
3768
|
+
For code-specific comments on MRs/commits, provide position information.
|
|
3769
|
+
|
|
3770
|
+
Examples:
|
|
3771
|
+
- New MR comment: resource_type="merge_request", project_id="...", iid=123, body="..."
|
|
3772
|
+
- Reply to thread: resource_type="merge_request", ..., discussion_id="...", body="..."
|
|
3773
|
+
- Code comment: resource_type="merge_request", ..., body="...", position={base_sha, head_sha, ...}`,
|
|
3774
|
+
args: {
|
|
3775
|
+
resource_type: z13.enum(["merge_request", "issue", "epic", "commit", "snippet"]).describe("Type of GitLab resource"),
|
|
3776
|
+
body: z13.string().describe("The comment text (Markdown supported)"),
|
|
3777
|
+
project_id: z13.string().optional().describe("Project ID or path"),
|
|
3778
|
+
group_id: z13.string().optional().describe("Group ID or path (for epic)"),
|
|
3779
|
+
iid: z13.number().optional().describe("Internal ID (for merge_request, issue, epic)"),
|
|
3780
|
+
sha: z13.string().optional().describe("Commit SHA (for commit)"),
|
|
3781
|
+
snippet_id: z13.number().optional().describe("Snippet ID (for snippet)"),
|
|
3782
|
+
discussion_id: z13.string().optional().describe("If provided, replies to existing discussion. If omitted, creates new thread"),
|
|
3783
|
+
position: positionSchema.optional().describe("Position for code-specific comments (MR/commit only)")
|
|
3784
|
+
},
|
|
3785
|
+
execute: async (args, _ctx) => {
|
|
3786
|
+
validateResourceParams(args.resource_type, args);
|
|
3787
|
+
const client = getGitLabClient();
|
|
3788
|
+
if (args.discussion_id) {
|
|
3789
|
+
const note = await client.replyToDiscussion(
|
|
3790
|
+
args.resource_type,
|
|
3791
|
+
{
|
|
3792
|
+
projectId: args.project_id,
|
|
3793
|
+
groupId: args.group_id,
|
|
3794
|
+
iid: args.iid,
|
|
3795
|
+
sha: args.sha,
|
|
3796
|
+
snippetId: args.snippet_id
|
|
3797
|
+
},
|
|
3798
|
+
args.discussion_id,
|
|
3799
|
+
args.body
|
|
3800
|
+
);
|
|
3801
|
+
return JSON.stringify(note, null, 2);
|
|
3802
|
+
}
|
|
3803
|
+
switch (args.resource_type) {
|
|
3804
|
+
case "merge_request":
|
|
3805
|
+
return JSON.stringify(
|
|
3806
|
+
await client.createMrDiscussion(args.project_id, args.iid, args.body, args.position),
|
|
3807
|
+
null,
|
|
3808
|
+
2
|
|
3809
|
+
);
|
|
3810
|
+
case "issue":
|
|
3811
|
+
return JSON.stringify(
|
|
3812
|
+
await client.createIssueNote(args.project_id, args.iid, args.body),
|
|
3813
|
+
null,
|
|
3814
|
+
2
|
|
3815
|
+
);
|
|
3816
|
+
case "epic":
|
|
3817
|
+
return JSON.stringify(
|
|
3818
|
+
await client.createEpicNote(args.group_id, args.iid, args.body),
|
|
3819
|
+
null,
|
|
3820
|
+
2
|
|
3821
|
+
);
|
|
3822
|
+
case "commit":
|
|
3823
|
+
return JSON.stringify(
|
|
3824
|
+
await client.createCommitDiscussion(
|
|
3825
|
+
args.project_id,
|
|
3826
|
+
args.sha,
|
|
3827
|
+
args.body,
|
|
3828
|
+
args.position
|
|
3829
|
+
),
|
|
3830
|
+
null,
|
|
3831
|
+
2
|
|
3832
|
+
);
|
|
3833
|
+
case "snippet":
|
|
3834
|
+
return JSON.stringify(
|
|
3835
|
+
await client.createSnippetDiscussion(args.project_id, args.snippet_id, args.body),
|
|
3836
|
+
null,
|
|
3837
|
+
2
|
|
3838
|
+
);
|
|
3839
|
+
default:
|
|
3840
|
+
throw new Error(`Unsupported resource type: ${args.resource_type}`);
|
|
3841
|
+
}
|
|
3842
|
+
}
|
|
3843
|
+
}),
|
|
3844
|
+
/**
|
|
3845
|
+
* Resolve or unresolve a discussion thread
|
|
3846
|
+
*/
|
|
3847
|
+
gitlab_resolve_discussion: tool13({
|
|
3848
|
+
description: `Mark a discussion thread as resolved or unresolve it.
|
|
3849
|
+
Only works for resolvable discussions (MRs and issues only).
|
|
3850
|
+
|
|
3851
|
+
Use after addressing feedback to indicate the discussion is complete.`,
|
|
3852
|
+
args: {
|
|
3853
|
+
resource_type: z13.enum(["merge_request", "issue"]).describe("Type of resource (only MR and issue discussions can be resolved)"),
|
|
3854
|
+
action: z13.enum(["resolve", "unresolve"]).describe("Whether to resolve or unresolve"),
|
|
3855
|
+
discussion_id: z13.string().describe("The ID of the discussion thread"),
|
|
3856
|
+
project_id: z13.string().describe("Project ID or path"),
|
|
3857
|
+
iid: z13.number().describe("Internal ID of the MR or issue")
|
|
3858
|
+
},
|
|
3859
|
+
execute: async (args, _ctx) => {
|
|
3860
|
+
const client = getGitLabClient();
|
|
3861
|
+
if (args.action === "resolve") {
|
|
3862
|
+
switch (args.resource_type) {
|
|
3863
|
+
case "merge_request":
|
|
3864
|
+
return JSON.stringify(
|
|
3865
|
+
await client.resolveMrDiscussion(args.project_id, args.iid, args.discussion_id),
|
|
3866
|
+
null,
|
|
3867
|
+
2
|
|
3868
|
+
);
|
|
3869
|
+
case "issue":
|
|
3870
|
+
return JSON.stringify(
|
|
3871
|
+
await client.resolveIssueDiscussion(args.project_id, args.iid, args.discussion_id),
|
|
3872
|
+
null,
|
|
3873
|
+
2
|
|
3874
|
+
);
|
|
3875
|
+
}
|
|
3876
|
+
} else {
|
|
3877
|
+
switch (args.resource_type) {
|
|
3878
|
+
case "merge_request":
|
|
3879
|
+
return JSON.stringify(
|
|
3880
|
+
await client.unresolveMrDiscussion(args.project_id, args.iid, args.discussion_id),
|
|
3881
|
+
null,
|
|
3882
|
+
2
|
|
3883
|
+
);
|
|
3884
|
+
case "issue":
|
|
3885
|
+
return JSON.stringify(
|
|
3886
|
+
await client.unresolveIssueDiscussion(args.project_id, args.iid, args.discussion_id),
|
|
3887
|
+
null,
|
|
3888
|
+
2
|
|
3889
|
+
);
|
|
3890
|
+
}
|
|
3891
|
+
}
|
|
4158
3892
|
}
|
|
4159
3893
|
})
|
|
4160
3894
|
};
|
|
@@ -4523,10 +4257,8 @@ var gitlabPlugin = async (_input) => {
|
|
|
4523
4257
|
...wikiTools,
|
|
4524
4258
|
// Work Item Tools
|
|
4525
4259
|
...workItemTools,
|
|
4526
|
-
//
|
|
4527
|
-
...
|
|
4528
|
-
// Universal Discussion Tools
|
|
4529
|
-
...discussionTools,
|
|
4260
|
+
// Unified Discussion Tools (covers MR, issue, epic, commit, snippet discussions)
|
|
4261
|
+
...discussionsUnifiedTools,
|
|
4530
4262
|
// Git Tools
|
|
4531
4263
|
...gitTools,
|
|
4532
4264
|
// Audit Tools
|
package/package.json
CHANGED
|
Binary file
|