@gitlab/opencode-gitlab-plugin 1.6.2 → 1.7.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/CHANGELOG.md
CHANGED
|
@@ -2,6 +2,19 @@
|
|
|
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.7.0](https://gitlab.com/gitlab-org/editor-extensions/opencode-gitlab-plugin/compare/v1.6.2...v1.7.0) (2026-02-24)
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
### ✨ Features
|
|
9
|
+
|
|
10
|
+
* **award-emoji:** add tools for managing reactions on resources ([77b8ad5](https://gitlab.com/gitlab-org/editor-extensions/opencode-gitlab-plugin/commit/77b8ad5656b681c3a6c9395f2a0025126e4c39bb))
|
|
11
|
+
* **discussions:** use GraphQL for discussion resolution ([b6ed342](https://gitlab.com/gitlab-org/editor-extensions/opencode-gitlab-plugin/commit/b6ed342cea8f726b14a2850350d217a937406caa))
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
### 🐛 Bug Fixes
|
|
15
|
+
|
|
16
|
+
* **todos:** handle 404 gracefully when marking todo as done ([2a26763](https://gitlab.com/gitlab-org/editor-extensions/opencode-gitlab-plugin/commit/2a267632012d89884ebc3462ac0adafc5ffd9286))
|
|
17
|
+
|
|
5
18
|
## [1.6.2](https://gitlab.com/gitlab-org/editor-extensions/opencode-gitlab-plugin/compare/v1.6.1...v1.6.2) (2026-02-04)
|
|
6
19
|
|
|
7
20
|
|
|
Binary file
|
package/dist/index.js
CHANGED
|
@@ -277,6 +277,23 @@ var SET_AUTO_MERGE_MUTATION = `
|
|
|
277
277
|
}
|
|
278
278
|
}
|
|
279
279
|
`;
|
|
280
|
+
var RESOLVE_DISCUSSION_MUTATION = `
|
|
281
|
+
mutation resolveDiscussion($discussionId: DiscussionID!, $resolve: Boolean!) {
|
|
282
|
+
discussionToggleResolve(input: { id: $discussionId, resolve: $resolve }) {
|
|
283
|
+
discussion {
|
|
284
|
+
id
|
|
285
|
+
resolved
|
|
286
|
+
resolvedAt
|
|
287
|
+
resolvedBy {
|
|
288
|
+
id
|
|
289
|
+
username
|
|
290
|
+
name
|
|
291
|
+
}
|
|
292
|
+
}
|
|
293
|
+
errors
|
|
294
|
+
}
|
|
295
|
+
}
|
|
296
|
+
`;
|
|
280
297
|
var MergeRequestsClient = class extends GitLabApiClient {
|
|
281
298
|
async getMergeRequest(projectId, mrIid, includeChanges) {
|
|
282
299
|
const encodedProject = this.encodeProjectId(projectId);
|
|
@@ -368,6 +385,32 @@ var MergeRequestsClient = class extends GitLabApiClient {
|
|
|
368
385
|
{ resolved: false }
|
|
369
386
|
);
|
|
370
387
|
}
|
|
388
|
+
/**
|
|
389
|
+
* Resolve or unresolve a discussion using GraphQL API.
|
|
390
|
+
* This works for all discussions including outdated ones (resolved: null)
|
|
391
|
+
* which the REST API cannot handle.
|
|
392
|
+
*
|
|
393
|
+
* @param discussionId - The discussion ID (can be short ID or full gid://gitlab/Discussion/ID format)
|
|
394
|
+
* @param resolve - Whether to resolve (true) or unresolve (false) the discussion
|
|
395
|
+
*/
|
|
396
|
+
async toggleDiscussionResolved(discussionId, resolve2) {
|
|
397
|
+
const gid = discussionId.startsWith("gid://") ? discussionId : `gid://gitlab/Discussion/${discussionId}`;
|
|
398
|
+
const result = await this.fetchGraphQL(RESOLVE_DISCUSSION_MUTATION, {
|
|
399
|
+
discussionId: gid,
|
|
400
|
+
resolve: resolve2
|
|
401
|
+
});
|
|
402
|
+
if (result.discussionToggleResolve.errors.length > 0) {
|
|
403
|
+
throw new Error(
|
|
404
|
+
`Failed to ${resolve2 ? "resolve" : "unresolve"} discussion: ${result.discussionToggleResolve.errors.join(", ")}`
|
|
405
|
+
);
|
|
406
|
+
}
|
|
407
|
+
if (!result.discussionToggleResolve.discussion) {
|
|
408
|
+
throw new Error(
|
|
409
|
+
`Failed to ${resolve2 ? "resolve" : "unresolve"} discussion: No discussion returned`
|
|
410
|
+
);
|
|
411
|
+
}
|
|
412
|
+
return result.discussionToggleResolve.discussion;
|
|
413
|
+
}
|
|
371
414
|
async createMrDiscussion(projectId, mrIid, body, position) {
|
|
372
415
|
const encodedProject = this.encodeProjectId(projectId);
|
|
373
416
|
const requestBody = { body };
|
|
@@ -425,6 +468,32 @@ var MergeRequestsClient = class extends GitLabApiClient {
|
|
|
425
468
|
`/projects/${encodedProject}/merge_requests/${mrIid}/pipelines`
|
|
426
469
|
);
|
|
427
470
|
}
|
|
471
|
+
/**
|
|
472
|
+
* Add a reviewer to a merge request without affecting existing reviewers
|
|
473
|
+
*/
|
|
474
|
+
async addReviewer(projectId, mrIid, reviewerId) {
|
|
475
|
+
const mr = await this.getMergeRequest(projectId, mrIid);
|
|
476
|
+
const currentReviewers = mr.reviewers || [];
|
|
477
|
+
const currentReviewerIds = currentReviewers.map((r) => r.id);
|
|
478
|
+
if (currentReviewerIds.includes(reviewerId)) {
|
|
479
|
+
return mr;
|
|
480
|
+
}
|
|
481
|
+
const newReviewerIds = [...currentReviewerIds, reviewerId];
|
|
482
|
+
return this.updateMergeRequest(projectId, mrIid, { reviewer_ids: newReviewerIds });
|
|
483
|
+
}
|
|
484
|
+
/**
|
|
485
|
+
* Remove a reviewer from a merge request without affecting other reviewers
|
|
486
|
+
*/
|
|
487
|
+
async removeReviewer(projectId, mrIid, reviewerId) {
|
|
488
|
+
const mr = await this.getMergeRequest(projectId, mrIid);
|
|
489
|
+
const currentReviewers = mr.reviewers || [];
|
|
490
|
+
const currentReviewerIds = currentReviewers.map((r) => r.id);
|
|
491
|
+
if (!currentReviewerIds.includes(reviewerId)) {
|
|
492
|
+
return mr;
|
|
493
|
+
}
|
|
494
|
+
const newReviewerIds = currentReviewerIds.filter((id) => id !== reviewerId);
|
|
495
|
+
return this.updateMergeRequest(projectId, mrIid, { reviewer_ids: newReviewerIds });
|
|
496
|
+
}
|
|
428
497
|
async listMergeRequestDiffs(projectId, mrIid, options = {}) {
|
|
429
498
|
const encodedProject = this.encodeProjectId(projectId);
|
|
430
499
|
const params = new URLSearchParams();
|
|
@@ -1468,7 +1537,21 @@ var TodosClient = class extends GitLabApiClient {
|
|
|
1468
1537
|
return typeMap[type] || type;
|
|
1469
1538
|
}
|
|
1470
1539
|
async markTodoAsDone(todoId) {
|
|
1471
|
-
|
|
1540
|
+
try {
|
|
1541
|
+
const result = await this.fetch(
|
|
1542
|
+
"POST",
|
|
1543
|
+
`/todos/${todoId}/mark_as_done`
|
|
1544
|
+
);
|
|
1545
|
+
return { success: true, todo: result };
|
|
1546
|
+
} catch (error) {
|
|
1547
|
+
if (error instanceof Error && error.message.includes("404")) {
|
|
1548
|
+
return {
|
|
1549
|
+
success: false,
|
|
1550
|
+
message: `Todo ${todoId} not found. It may have already been marked as done or does not exist.`
|
|
1551
|
+
};
|
|
1552
|
+
}
|
|
1553
|
+
throw error;
|
|
1554
|
+
}
|
|
1472
1555
|
}
|
|
1473
1556
|
async markAllTodosAsDone() {
|
|
1474
1557
|
return this.fetch("POST", "/todos/mark_as_done");
|
|
@@ -1963,6 +2046,63 @@ var AuditClient = class extends GitLabApiClient {
|
|
|
1963
2046
|
}
|
|
1964
2047
|
};
|
|
1965
2048
|
|
|
2049
|
+
// src/client/award-emoji.ts
|
|
2050
|
+
var AwardEmojiClient = class extends GitLabApiClient {
|
|
2051
|
+
/**
|
|
2052
|
+
* Build the base path for award emoji operations
|
|
2053
|
+
*/
|
|
2054
|
+
buildAwardEmojiPath(resource) {
|
|
2055
|
+
const encodedProject = this.encodeProjectId(resource.projectId);
|
|
2056
|
+
let basePath;
|
|
2057
|
+
switch (resource.resourceType) {
|
|
2058
|
+
case "merge_request":
|
|
2059
|
+
basePath = `/projects/${encodedProject}/merge_requests/${resource.resourceIid}`;
|
|
2060
|
+
break;
|
|
2061
|
+
case "issue":
|
|
2062
|
+
basePath = `/projects/${encodedProject}/issues/${resource.resourceIid}`;
|
|
2063
|
+
break;
|
|
2064
|
+
case "snippet":
|
|
2065
|
+
basePath = `/projects/${encodedProject}/snippets/${resource.resourceIid}`;
|
|
2066
|
+
break;
|
|
2067
|
+
}
|
|
2068
|
+
if (resource.noteId) {
|
|
2069
|
+
return `${basePath}/notes/${resource.noteId}/award_emoji`;
|
|
2070
|
+
}
|
|
2071
|
+
return `${basePath}/award_emoji`;
|
|
2072
|
+
}
|
|
2073
|
+
/**
|
|
2074
|
+
* List all award emoji on a resource or note
|
|
2075
|
+
*/
|
|
2076
|
+
async listAwardEmoji(resource) {
|
|
2077
|
+
const path2 = this.buildAwardEmojiPath(resource);
|
|
2078
|
+
return this.fetch("GET", path2);
|
|
2079
|
+
}
|
|
2080
|
+
/**
|
|
2081
|
+
* Get a single award emoji by ID
|
|
2082
|
+
*/
|
|
2083
|
+
async getAwardEmoji(resource, awardId) {
|
|
2084
|
+
const path2 = `${this.buildAwardEmojiPath(resource)}/${awardId}`;
|
|
2085
|
+
return this.fetch("GET", path2);
|
|
2086
|
+
}
|
|
2087
|
+
/**
|
|
2088
|
+
* Add an award emoji (reaction) to a resource or note
|
|
2089
|
+
*
|
|
2090
|
+
* @param resource - The resource to add the emoji to
|
|
2091
|
+
* @param name - The emoji name without colons (e.g., 'thumbsup', 'rocket', 'eyes')
|
|
2092
|
+
*/
|
|
2093
|
+
async createAwardEmoji(resource, name) {
|
|
2094
|
+
const path2 = this.buildAwardEmojiPath(resource);
|
|
2095
|
+
return this.fetch("POST", path2, { name });
|
|
2096
|
+
}
|
|
2097
|
+
/**
|
|
2098
|
+
* Remove an award emoji from a resource or note
|
|
2099
|
+
*/
|
|
2100
|
+
async deleteAwardEmoji(resource, awardId) {
|
|
2101
|
+
const path2 = `${this.buildAwardEmojiPath(resource)}/${awardId}`;
|
|
2102
|
+
await this.fetch("DELETE", path2);
|
|
2103
|
+
}
|
|
2104
|
+
};
|
|
2105
|
+
|
|
1966
2106
|
// src/client/index.ts
|
|
1967
2107
|
var UnifiedGitLabClient = class extends GitLabApiClient {
|
|
1968
2108
|
};
|
|
@@ -1992,7 +2132,8 @@ applyMixins(UnifiedGitLabClient, [
|
|
|
1992
2132
|
EpicsClient,
|
|
1993
2133
|
SnippetsClient,
|
|
1994
2134
|
DiscussionsClient,
|
|
1995
|
-
AuditClient
|
|
2135
|
+
AuditClient,
|
|
2136
|
+
AwardEmojiClient
|
|
1996
2137
|
]);
|
|
1997
2138
|
|
|
1998
2139
|
// src/utils.ts
|
|
@@ -2203,6 +2344,36 @@ This is useful when you need to process diffs in chunks or when the MR has many
|
|
|
2203
2344
|
return JSON.stringify(diffs, null, 2);
|
|
2204
2345
|
}
|
|
2205
2346
|
}),
|
|
2347
|
+
gitlab_add_mr_reviewer: tool({
|
|
2348
|
+
description: `Add a reviewer to a merge request without affecting existing reviewers.
|
|
2349
|
+
This is safer than gitlab_update_merge_request when you only want to add a single reviewer,
|
|
2350
|
+
as it preserves all existing reviewers.`,
|
|
2351
|
+
args: {
|
|
2352
|
+
project_id: z.string().describe("The project ID or URL-encoded path"),
|
|
2353
|
+
mr_iid: z.number().describe("The internal ID of the merge request"),
|
|
2354
|
+
reviewer_id: z.number().describe("The user ID of the reviewer to add")
|
|
2355
|
+
},
|
|
2356
|
+
execute: async (args, _ctx) => {
|
|
2357
|
+
const client = getGitLabClient();
|
|
2358
|
+
const mr = await client.addReviewer(args.project_id, args.mr_iid, args.reviewer_id);
|
|
2359
|
+
return JSON.stringify(mr, null, 2);
|
|
2360
|
+
}
|
|
2361
|
+
}),
|
|
2362
|
+
gitlab_remove_mr_reviewer: tool({
|
|
2363
|
+
description: `Remove a reviewer from a merge request without affecting other reviewers.
|
|
2364
|
+
This is safer than gitlab_update_merge_request when you only want to remove a single reviewer,
|
|
2365
|
+
as it preserves all other reviewers.`,
|
|
2366
|
+
args: {
|
|
2367
|
+
project_id: z.string().describe("The project ID or URL-encoded path"),
|
|
2368
|
+
mr_iid: z.number().describe("The internal ID of the merge request"),
|
|
2369
|
+
reviewer_id: z.number().describe("The user ID of the reviewer to remove")
|
|
2370
|
+
},
|
|
2371
|
+
execute: async (args, _ctx) => {
|
|
2372
|
+
const client = getGitLabClient();
|
|
2373
|
+
const mr = await client.removeReviewer(args.project_id, args.mr_iid, args.reviewer_id);
|
|
2374
|
+
return JSON.stringify(mr, null, 2);
|
|
2375
|
+
}
|
|
2376
|
+
}),
|
|
2206
2377
|
gitlab_set_mr_auto_merge: tool({
|
|
2207
2378
|
description: `Enable auto-merge (MWPS - Merge When Pipeline Succeeds) on a merge request.
|
|
2208
2379
|
Uses the GitLab GraphQL API mergeRequestAccept mutation with a merge strategy.
|
|
@@ -3227,7 +3398,24 @@ Examples:
|
|
|
3227
3398
|
return JSON.stringify({ error: 'todo_id is required when action is "one"' }, null, 2);
|
|
3228
3399
|
}
|
|
3229
3400
|
const result = await client.markTodoAsDone(args.todo_id);
|
|
3230
|
-
|
|
3401
|
+
if (!result.success) {
|
|
3402
|
+
return JSON.stringify(
|
|
3403
|
+
{
|
|
3404
|
+
success: false,
|
|
3405
|
+
message: result.message
|
|
3406
|
+
},
|
|
3407
|
+
null,
|
|
3408
|
+
2
|
|
3409
|
+
);
|
|
3410
|
+
}
|
|
3411
|
+
return JSON.stringify(
|
|
3412
|
+
{
|
|
3413
|
+
success: true,
|
|
3414
|
+
todo: result.todo
|
|
3415
|
+
},
|
|
3416
|
+
null,
|
|
3417
|
+
2
|
|
3418
|
+
);
|
|
3231
3419
|
}
|
|
3232
3420
|
case "all": {
|
|
3233
3421
|
const result = await client.markAllTodosAsDone();
|
|
@@ -3678,6 +3866,9 @@ Examples:
|
|
|
3678
3866
|
description: `Mark a discussion thread as resolved or unresolve it.
|
|
3679
3867
|
Only works for resolvable discussions (MRs and issues only).
|
|
3680
3868
|
|
|
3869
|
+
Uses GraphQL API which handles all discussion types including outdated discussions
|
|
3870
|
+
(those with resolved: null) that the REST API cannot handle.
|
|
3871
|
+
|
|
3681
3872
|
Use after addressing feedback to indicate the discussion is complete.`,
|
|
3682
3873
|
args: {
|
|
3683
3874
|
resource_type: z12.enum(["merge_request", "issue"]).describe("Type of resource (only MR and issue discussions can be resolved)"),
|
|
@@ -3688,37 +3879,12 @@ Use after addressing feedback to indicate the discussion is complete.`,
|
|
|
3688
3879
|
},
|
|
3689
3880
|
execute: async (args, _ctx) => {
|
|
3690
3881
|
const client = getGitLabClient();
|
|
3691
|
-
|
|
3692
|
-
|
|
3693
|
-
|
|
3694
|
-
|
|
3695
|
-
|
|
3696
|
-
|
|
3697
|
-
2
|
|
3698
|
-
);
|
|
3699
|
-
case "issue":
|
|
3700
|
-
return JSON.stringify(
|
|
3701
|
-
await client.resolveIssueDiscussion(args.project_id, args.iid, args.discussion_id),
|
|
3702
|
-
null,
|
|
3703
|
-
2
|
|
3704
|
-
);
|
|
3705
|
-
}
|
|
3706
|
-
} else {
|
|
3707
|
-
switch (args.resource_type) {
|
|
3708
|
-
case "merge_request":
|
|
3709
|
-
return JSON.stringify(
|
|
3710
|
-
await client.unresolveMrDiscussion(args.project_id, args.iid, args.discussion_id),
|
|
3711
|
-
null,
|
|
3712
|
-
2
|
|
3713
|
-
);
|
|
3714
|
-
case "issue":
|
|
3715
|
-
return JSON.stringify(
|
|
3716
|
-
await client.unresolveIssueDiscussion(args.project_id, args.iid, args.discussion_id),
|
|
3717
|
-
null,
|
|
3718
|
-
2
|
|
3719
|
-
);
|
|
3720
|
-
}
|
|
3721
|
-
}
|
|
3882
|
+
const resolve2 = args.action === "resolve";
|
|
3883
|
+
return JSON.stringify(
|
|
3884
|
+
await client.toggleDiscussionResolved(args.discussion_id, resolve2),
|
|
3885
|
+
null,
|
|
3886
|
+
2
|
|
3887
|
+
);
|
|
3722
3888
|
}
|
|
3723
3889
|
})
|
|
3724
3890
|
};
|
|
@@ -4293,6 +4459,107 @@ Note: Requires administrator access.`,
|
|
|
4293
4459
|
})
|
|
4294
4460
|
};
|
|
4295
4461
|
|
|
4462
|
+
// src/tools/award-emoji.ts
|
|
4463
|
+
import { tool as tool16 } from "@opencode-ai/plugin";
|
|
4464
|
+
var z16 = tool16.schema;
|
|
4465
|
+
function validateAwardEmojiParams(args) {
|
|
4466
|
+
if (!args.project_id) {
|
|
4467
|
+
throw new Error("project_id is required");
|
|
4468
|
+
}
|
|
4469
|
+
if (args.resource_iid == null) {
|
|
4470
|
+
throw new Error("resource_iid is required");
|
|
4471
|
+
}
|
|
4472
|
+
}
|
|
4473
|
+
function buildResourceId(args) {
|
|
4474
|
+
return {
|
|
4475
|
+
projectId: args.project_id,
|
|
4476
|
+
resourceType: args.resource_type,
|
|
4477
|
+
resourceIid: args.resource_iid,
|
|
4478
|
+
noteId: args.note_id
|
|
4479
|
+
};
|
|
4480
|
+
}
|
|
4481
|
+
var awardEmojiTools = {
|
|
4482
|
+
/**
|
|
4483
|
+
* Add a reaction (award emoji) to a resource or note
|
|
4484
|
+
*/
|
|
4485
|
+
gitlab_create_award_emoji: tool16({
|
|
4486
|
+
description: `Add a reaction (award emoji) to a merge request, issue, snippet, or a note/comment on these resources.
|
|
4487
|
+
|
|
4488
|
+
Common emoji names: thumbsup, thumbsdown, smile, tada, rocket, eyes, heart, +1, -1
|
|
4489
|
+
|
|
4490
|
+
To react to a specific comment/note, provide the note_id parameter.
|
|
4491
|
+
|
|
4492
|
+
Examples:
|
|
4493
|
+
- React to MR: resource_type="merge_request", project_id="group/project", resource_iid=123, name="thumbsup"
|
|
4494
|
+
- React to issue comment: resource_type="issue", project_id="group/project", resource_iid=456, note_id=789, name="rocket"`,
|
|
4495
|
+
args: {
|
|
4496
|
+
resource_type: z16.enum(["merge_request", "issue", "snippet"]).describe("Type of resource to add the reaction to"),
|
|
4497
|
+
project_id: z16.string().describe("Project ID or URL-encoded path"),
|
|
4498
|
+
resource_iid: z16.number().describe("Internal ID of the merge request, issue, or snippet"),
|
|
4499
|
+
name: z16.string().describe(
|
|
4500
|
+
'Emoji name without colons (e.g., "thumbsup", "rocket", "eyes", "heart", "tada")'
|
|
4501
|
+
),
|
|
4502
|
+
note_id: z16.number().optional().describe("Note/comment ID to add the reaction to (if reacting to a specific comment)")
|
|
4503
|
+
},
|
|
4504
|
+
execute: async (args, _ctx) => {
|
|
4505
|
+
validateAwardEmojiParams(args);
|
|
4506
|
+
const client = getGitLabClient();
|
|
4507
|
+
const resource = buildResourceId(args);
|
|
4508
|
+
const result = await client.createAwardEmoji(resource, args.name);
|
|
4509
|
+
return JSON.stringify(result, null, 2);
|
|
4510
|
+
}
|
|
4511
|
+
}),
|
|
4512
|
+
/**
|
|
4513
|
+
* List all reactions on a resource or note
|
|
4514
|
+
*/
|
|
4515
|
+
gitlab_list_award_emoji: tool16({
|
|
4516
|
+
description: `List all reactions (award emoji) on a merge request, issue, snippet, or a specific note/comment.
|
|
4517
|
+
|
|
4518
|
+
Examples:
|
|
4519
|
+
- List reactions on MR: resource_type="merge_request", project_id="group/project", resource_iid=123
|
|
4520
|
+
- List reactions on a comment: resource_type="issue", project_id="group/project", resource_iid=456, note_id=789`,
|
|
4521
|
+
args: {
|
|
4522
|
+
resource_type: z16.enum(["merge_request", "issue", "snippet"]).describe("Type of resource"),
|
|
4523
|
+
project_id: z16.string().describe("Project ID or URL-encoded path"),
|
|
4524
|
+
resource_iid: z16.number().describe("Internal ID of the merge request, issue, or snippet"),
|
|
4525
|
+
note_id: z16.number().optional().describe("Note/comment ID to list reactions for (if listing for a specific comment)")
|
|
4526
|
+
},
|
|
4527
|
+
execute: async (args, _ctx) => {
|
|
4528
|
+
validateAwardEmojiParams(args);
|
|
4529
|
+
const client = getGitLabClient();
|
|
4530
|
+
const resource = buildResourceId(args);
|
|
4531
|
+
const result = await client.listAwardEmoji(resource);
|
|
4532
|
+
return JSON.stringify(result, null, 2);
|
|
4533
|
+
}
|
|
4534
|
+
}),
|
|
4535
|
+
/**
|
|
4536
|
+
* Remove a reaction from a resource or note
|
|
4537
|
+
*/
|
|
4538
|
+
gitlab_delete_award_emoji: tool16({
|
|
4539
|
+
description: `Remove a reaction (award emoji) from a merge request, issue, snippet, or note/comment.
|
|
4540
|
+
|
|
4541
|
+
You need the award_id which can be found using gitlab_list_award_emoji.
|
|
4542
|
+
|
|
4543
|
+
Examples:
|
|
4544
|
+
- Remove reaction from MR: resource_type="merge_request", project_id="group/project", resource_iid=123, award_id=456
|
|
4545
|
+
- Remove from comment: resource_type="issue", ..., note_id=789, award_id=456`,
|
|
4546
|
+
args: {
|
|
4547
|
+
resource_type: z16.enum(["merge_request", "issue", "snippet"]).describe("Type of resource"),
|
|
4548
|
+
project_id: z16.string().describe("Project ID or URL-encoded path"),
|
|
4549
|
+
resource_iid: z16.number().describe("Internal ID of the merge request, issue, or snippet"),
|
|
4550
|
+
award_id: z16.number().describe("ID of the award emoji to remove"),
|
|
4551
|
+
note_id: z16.number().optional().describe("Note/comment ID if removing from a specific comment")
|
|
4552
|
+
},
|
|
4553
|
+
execute: async (args, _ctx) => {
|
|
4554
|
+
validateAwardEmojiParams(args);
|
|
4555
|
+
const client = getGitLabClient();
|
|
4556
|
+
const resource = buildResourceId(args);
|
|
4557
|
+
await client.deleteAwardEmoji(resource, args.award_id);
|
|
4558
|
+
return JSON.stringify({ success: true, message: "Award emoji removed" }, null, 2);
|
|
4559
|
+
}
|
|
4560
|
+
})
|
|
4561
|
+
};
|
|
4562
|
+
|
|
4296
4563
|
// src/index.ts
|
|
4297
4564
|
var gitlabPlugin = async (_input) => {
|
|
4298
4565
|
return {
|
|
@@ -4328,7 +4595,9 @@ var gitlabPlugin = async (_input) => {
|
|
|
4328
4595
|
// Git Tools
|
|
4329
4596
|
...gitTools,
|
|
4330
4597
|
// Audit Tools
|
|
4331
|
-
...auditTools
|
|
4598
|
+
...auditTools,
|
|
4599
|
+
// Award Emoji (Reactions) Tools
|
|
4600
|
+
...awardEmojiTools
|
|
4332
4601
|
}
|
|
4333
4602
|
};
|
|
4334
4603
|
};
|
package/package.json
CHANGED
|
Binary file
|