@gitlab/opencode-gitlab-plugin 1.3.0 → 1.5.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,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.0](https://gitlab.com/gitlab-org/editor-extensions/opencode-gitlab-plugin/compare/v1.4.0...v1.5.0) (2026-02-02)
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
### ✨ Features
|
|
9
|
+
|
|
10
|
+
* migrate discussions to GraphQL with cursor-based pagination ([1c61895](https://gitlab.com/gitlab-org/editor-extensions/opencode-gitlab-plugin/commit/1c61895a8f0146f40d7a29a303cdc49e91280280))
|
|
11
|
+
|
|
12
|
+
## [1.4.0](https://gitlab.com/gitlab-org/editor-extensions/opencode-gitlab-plugin/compare/v1.3.0...v1.4.0) (2026-02-02)
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
### ✨ Features
|
|
16
|
+
|
|
17
|
+
* **todos:** migrate listTodos to GraphQL API with pagination support ([5726c8b](https://gitlab.com/gitlab-org/editor-extensions/opencode-gitlab-plugin/commit/5726c8bb3b8fbce6f014c0f3500bf4d913eb4033))
|
|
18
|
+
|
|
19
|
+
|
|
20
|
+
### 🐛 Bug Fixes
|
|
21
|
+
|
|
22
|
+
* **todos:** add validation for conflicting pagination parameters ([f46d8c2](https://gitlab.com/gitlab-org/editor-extensions/opencode-gitlab-plugin/commit/f46d8c2d4c0f4e4b6363013fc3bcee676b78d777))
|
|
23
|
+
* **todos:** address MR review feedback ([87b3afa](https://gitlab.com/gitlab-org/editor-extensions/opencode-gitlab-plugin/commit/87b3afae2992e789c59f0c908c7b48a957e4a931))
|
|
24
|
+
|
|
5
25
|
## [1.3.0](https://gitlab.com/gitlab-org/editor-extensions/opencode-gitlab-plugin/compare/v1.2.0...v1.3.0) (2026-01-30)
|
|
6
26
|
|
|
7
27
|
|
|
Binary file
|
package/dist/index.js
CHANGED
|
@@ -132,6 +132,74 @@ var NOTES_CONNECTION_FRAGMENT = `
|
|
|
132
132
|
}
|
|
133
133
|
`;
|
|
134
134
|
|
|
135
|
+
// src/client/discussions-types.ts
|
|
136
|
+
function buildDiscussionsPaginationVariables(options) {
|
|
137
|
+
const variables = {};
|
|
138
|
+
if (options?.first !== void 0) {
|
|
139
|
+
variables.first = options.first;
|
|
140
|
+
} else if (options?.last == null) {
|
|
141
|
+
variables.first = 20;
|
|
142
|
+
}
|
|
143
|
+
if (options?.after) variables.after = options.after;
|
|
144
|
+
if (options?.last !== void 0) variables.last = options.last;
|
|
145
|
+
if (options?.before) variables.before = options.before;
|
|
146
|
+
return variables;
|
|
147
|
+
}
|
|
148
|
+
var DISCUSSION_NOTE_FRAGMENT = `
|
|
149
|
+
fragment DiscussionNoteFields on Note {
|
|
150
|
+
id
|
|
151
|
+
body
|
|
152
|
+
bodyHtml
|
|
153
|
+
createdAt
|
|
154
|
+
updatedAt
|
|
155
|
+
system
|
|
156
|
+
resolvable
|
|
157
|
+
resolved
|
|
158
|
+
resolvedAt
|
|
159
|
+
url
|
|
160
|
+
author {
|
|
161
|
+
id
|
|
162
|
+
username
|
|
163
|
+
name
|
|
164
|
+
avatarUrl
|
|
165
|
+
}
|
|
166
|
+
}
|
|
167
|
+
`;
|
|
168
|
+
var DISCUSSION_FRAGMENT = `
|
|
169
|
+
fragment DiscussionFields on Discussion {
|
|
170
|
+
id
|
|
171
|
+
replyId
|
|
172
|
+
createdAt
|
|
173
|
+
resolved
|
|
174
|
+
resolvable
|
|
175
|
+
resolvedAt
|
|
176
|
+
resolvedBy {
|
|
177
|
+
id
|
|
178
|
+
username
|
|
179
|
+
name
|
|
180
|
+
avatarUrl
|
|
181
|
+
}
|
|
182
|
+
notes {
|
|
183
|
+
nodes {
|
|
184
|
+
...DiscussionNoteFields
|
|
185
|
+
}
|
|
186
|
+
}
|
|
187
|
+
}
|
|
188
|
+
`;
|
|
189
|
+
var DISCUSSIONS_CONNECTION_FRAGMENT = `
|
|
190
|
+
fragment DiscussionsConnectionFields on DiscussionConnection {
|
|
191
|
+
pageInfo {
|
|
192
|
+
hasNextPage
|
|
193
|
+
hasPreviousPage
|
|
194
|
+
startCursor
|
|
195
|
+
endCursor
|
|
196
|
+
}
|
|
197
|
+
nodes {
|
|
198
|
+
...DiscussionFields
|
|
199
|
+
}
|
|
200
|
+
}
|
|
201
|
+
`;
|
|
202
|
+
|
|
135
203
|
// src/client/merge-requests.ts
|
|
136
204
|
var LIST_MR_NOTES_QUERY = `
|
|
137
205
|
${NOTES_FRAGMENT}
|
|
@@ -160,6 +228,32 @@ var LIST_MR_NOTES_QUERY = `
|
|
|
160
228
|
}
|
|
161
229
|
}
|
|
162
230
|
`;
|
|
231
|
+
var LIST_MR_DISCUSSIONS_QUERY = `
|
|
232
|
+
${DISCUSSION_NOTE_FRAGMENT}
|
|
233
|
+
${DISCUSSION_FRAGMENT}
|
|
234
|
+
${DISCUSSIONS_CONNECTION_FRAGMENT}
|
|
235
|
+
query listMrDiscussions(
|
|
236
|
+
$projectPath: ID!
|
|
237
|
+
$mrIid: String!
|
|
238
|
+
$first: Int
|
|
239
|
+
$after: String
|
|
240
|
+
$last: Int
|
|
241
|
+
$before: String
|
|
242
|
+
) {
|
|
243
|
+
project(fullPath: $projectPath) {
|
|
244
|
+
mergeRequest(iid: $mrIid) {
|
|
245
|
+
discussions(
|
|
246
|
+
first: $first
|
|
247
|
+
after: $after
|
|
248
|
+
last: $last
|
|
249
|
+
before: $before
|
|
250
|
+
) {
|
|
251
|
+
...DiscussionsConnectionFields
|
|
252
|
+
}
|
|
253
|
+
}
|
|
254
|
+
}
|
|
255
|
+
}
|
|
256
|
+
`;
|
|
163
257
|
var SET_AUTO_MERGE_MUTATION = `
|
|
164
258
|
mutation setAutoMerge(
|
|
165
259
|
$projectPath: ID!
|
|
@@ -218,12 +312,41 @@ var MergeRequestsClient = class extends GitLabApiClient {
|
|
|
218
312
|
`/projects/${encodedProject}/merge_requests/${mrIid}/changes`
|
|
219
313
|
);
|
|
220
314
|
}
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
315
|
+
/**
|
|
316
|
+
* List notes on a merge request using GraphQL API with pagination support
|
|
317
|
+
*/
|
|
318
|
+
async listMrNotes(projectId, mrIid, options) {
|
|
319
|
+
const variables = {
|
|
320
|
+
projectPath: projectId,
|
|
321
|
+
mrIid: String(mrIid),
|
|
322
|
+
...buildPaginationVariables(options)
|
|
323
|
+
};
|
|
324
|
+
const result = await this.fetchGraphQL(LIST_MR_NOTES_QUERY, variables);
|
|
325
|
+
const notes = result.project?.mergeRequest?.notes;
|
|
326
|
+
if (!notes) {
|
|
327
|
+
throw new Error("Merge request not found or access denied");
|
|
328
|
+
}
|
|
329
|
+
return {
|
|
330
|
+
notes,
|
|
331
|
+
pageInfo: notes.pageInfo,
|
|
332
|
+
totalCount: notes.count
|
|
333
|
+
};
|
|
334
|
+
}
|
|
335
|
+
/**
|
|
336
|
+
* List discussions on a merge request using GraphQL API with pagination support
|
|
337
|
+
*/
|
|
338
|
+
async listMrDiscussions(projectId, mrIid, options) {
|
|
339
|
+
const variables = {
|
|
340
|
+
projectPath: projectId,
|
|
341
|
+
mrIid: String(mrIid),
|
|
342
|
+
...buildDiscussionsPaginationVariables(options)
|
|
343
|
+
};
|
|
344
|
+
const result = await this.fetchGraphQL(LIST_MR_DISCUSSIONS_QUERY, variables);
|
|
345
|
+
const discussions = result.project?.mergeRequest?.discussions;
|
|
346
|
+
if (!discussions) {
|
|
347
|
+
throw new Error("Merge request not found or access denied");
|
|
348
|
+
}
|
|
349
|
+
return { discussions };
|
|
227
350
|
}
|
|
228
351
|
async getMrDiscussion(projectId, mrIid, discussionId) {
|
|
229
352
|
const encodedProject = this.encodeProjectId(projectId);
|
|
@@ -260,26 +383,6 @@ var MergeRequestsClient = class extends GitLabApiClient {
|
|
|
260
383
|
requestBody
|
|
261
384
|
);
|
|
262
385
|
}
|
|
263
|
-
/**
|
|
264
|
-
* List notes on a merge request using GraphQL API with pagination support
|
|
265
|
-
*/
|
|
266
|
-
async listMrNotes(projectId, mrIid, options) {
|
|
267
|
-
const variables = {
|
|
268
|
-
projectPath: projectId,
|
|
269
|
-
mrIid: String(mrIid),
|
|
270
|
-
...buildPaginationVariables(options)
|
|
271
|
-
};
|
|
272
|
-
const result = await this.fetchGraphQL(LIST_MR_NOTES_QUERY, variables);
|
|
273
|
-
const notes = result.project?.mergeRequest?.notes;
|
|
274
|
-
if (!notes) {
|
|
275
|
-
throw new Error("Merge request not found or access denied");
|
|
276
|
-
}
|
|
277
|
-
return {
|
|
278
|
-
notes,
|
|
279
|
-
pageInfo: notes.pageInfo,
|
|
280
|
-
totalCount: notes.count
|
|
281
|
-
};
|
|
282
|
-
}
|
|
283
386
|
async createMrNote(projectId, mrIid, body, discussionId) {
|
|
284
387
|
const encodedProject = this.encodeProjectId(projectId);
|
|
285
388
|
if (discussionId) {
|
|
@@ -383,6 +486,32 @@ var LIST_ISSUE_NOTES_QUERY = `
|
|
|
383
486
|
}
|
|
384
487
|
}
|
|
385
488
|
`;
|
|
489
|
+
var LIST_ISSUE_DISCUSSIONS_QUERY = `
|
|
490
|
+
${DISCUSSION_NOTE_FRAGMENT}
|
|
491
|
+
${DISCUSSION_FRAGMENT}
|
|
492
|
+
${DISCUSSIONS_CONNECTION_FRAGMENT}
|
|
493
|
+
query listIssueDiscussions(
|
|
494
|
+
$projectPath: ID!
|
|
495
|
+
$issueIid: String!
|
|
496
|
+
$first: Int
|
|
497
|
+
$after: String
|
|
498
|
+
$last: Int
|
|
499
|
+
$before: String
|
|
500
|
+
) {
|
|
501
|
+
project(fullPath: $projectPath) {
|
|
502
|
+
issue(iid: $issueIid) {
|
|
503
|
+
discussions(
|
|
504
|
+
first: $first
|
|
505
|
+
after: $after
|
|
506
|
+
last: $last
|
|
507
|
+
before: $before
|
|
508
|
+
) {
|
|
509
|
+
...DiscussionsConnectionFields
|
|
510
|
+
}
|
|
511
|
+
}
|
|
512
|
+
}
|
|
513
|
+
}
|
|
514
|
+
`;
|
|
386
515
|
var IssuesClient = class extends GitLabApiClient {
|
|
387
516
|
async createIssue(projectId, title, options) {
|
|
388
517
|
const encodedProject = this.encodeProjectId(projectId);
|
|
@@ -438,12 +567,21 @@ var IssuesClient = class extends GitLabApiClient {
|
|
|
438
567
|
totalCount: notes.count
|
|
439
568
|
};
|
|
440
569
|
}
|
|
441
|
-
|
|
442
|
-
|
|
443
|
-
|
|
444
|
-
|
|
445
|
-
|
|
446
|
-
|
|
570
|
+
/**
|
|
571
|
+
* List discussions on an issue using GraphQL API with pagination support
|
|
572
|
+
*/
|
|
573
|
+
async listIssueDiscussions(projectId, issueIid, options) {
|
|
574
|
+
const variables = {
|
|
575
|
+
projectPath: projectId,
|
|
576
|
+
issueIid: String(issueIid),
|
|
577
|
+
...buildDiscussionsPaginationVariables(options)
|
|
578
|
+
};
|
|
579
|
+
const result = await this.fetchGraphQL(LIST_ISSUE_DISCUSSIONS_QUERY, variables);
|
|
580
|
+
const discussions = result.project?.issue?.discussions;
|
|
581
|
+
if (!discussions) {
|
|
582
|
+
throw new Error("Issue not found or access denied");
|
|
583
|
+
}
|
|
584
|
+
return { discussions };
|
|
447
585
|
}
|
|
448
586
|
async getIssueDiscussion(projectId, issueIid, discussionId) {
|
|
449
587
|
const encodedProject = this.encodeProjectId(projectId);
|
|
@@ -1206,20 +1344,163 @@ var SecurityClient = class extends GitLabApiClient {
|
|
|
1206
1344
|
};
|
|
1207
1345
|
|
|
1208
1346
|
// src/client/todos.ts
|
|
1347
|
+
var LIST_TODOS_QUERY = `
|
|
1348
|
+
query listTodos(
|
|
1349
|
+
$state: [TodoStateEnum!]
|
|
1350
|
+
$action: [TodoActionEnum!]
|
|
1351
|
+
$type: [TodoTargetEnum!]
|
|
1352
|
+
$projectId: [ID!]
|
|
1353
|
+
$groupId: [ID!]
|
|
1354
|
+
$authorId: [ID!]
|
|
1355
|
+
$first: Int
|
|
1356
|
+
$after: String
|
|
1357
|
+
$last: Int
|
|
1358
|
+
$before: String
|
|
1359
|
+
) {
|
|
1360
|
+
currentUser {
|
|
1361
|
+
todos(
|
|
1362
|
+
state: $state
|
|
1363
|
+
action: $action
|
|
1364
|
+
type: $type
|
|
1365
|
+
projectId: $projectId
|
|
1366
|
+
groupId: $groupId
|
|
1367
|
+
authorId: $authorId
|
|
1368
|
+
first: $first
|
|
1369
|
+
after: $after
|
|
1370
|
+
last: $last
|
|
1371
|
+
before: $before
|
|
1372
|
+
) {
|
|
1373
|
+
count
|
|
1374
|
+
pageInfo {
|
|
1375
|
+
hasNextPage
|
|
1376
|
+
hasPreviousPage
|
|
1377
|
+
startCursor
|
|
1378
|
+
endCursor
|
|
1379
|
+
}
|
|
1380
|
+
nodes {
|
|
1381
|
+
id
|
|
1382
|
+
body
|
|
1383
|
+
state
|
|
1384
|
+
action
|
|
1385
|
+
createdAt
|
|
1386
|
+
targetType
|
|
1387
|
+
targetUrl
|
|
1388
|
+
snoozedUntil
|
|
1389
|
+
project {
|
|
1390
|
+
id
|
|
1391
|
+
name
|
|
1392
|
+
fullPath
|
|
1393
|
+
}
|
|
1394
|
+
group {
|
|
1395
|
+
id
|
|
1396
|
+
name
|
|
1397
|
+
fullPath
|
|
1398
|
+
}
|
|
1399
|
+
author {
|
|
1400
|
+
id
|
|
1401
|
+
username
|
|
1402
|
+
name
|
|
1403
|
+
avatarUrl
|
|
1404
|
+
}
|
|
1405
|
+
targetEntity {
|
|
1406
|
+
__typename
|
|
1407
|
+
... on Issue {
|
|
1408
|
+
id
|
|
1409
|
+
title
|
|
1410
|
+
iid
|
|
1411
|
+
}
|
|
1412
|
+
... on MergeRequest {
|
|
1413
|
+
id
|
|
1414
|
+
title
|
|
1415
|
+
iid
|
|
1416
|
+
}
|
|
1417
|
+
... on Epic {
|
|
1418
|
+
id
|
|
1419
|
+
title
|
|
1420
|
+
iid
|
|
1421
|
+
}
|
|
1422
|
+
... on Commit {
|
|
1423
|
+
id
|
|
1424
|
+
title
|
|
1425
|
+
}
|
|
1426
|
+
... on DesignManagement__Design {
|
|
1427
|
+
id
|
|
1428
|
+
}
|
|
1429
|
+
... on AlertManagement__Alert {
|
|
1430
|
+
id
|
|
1431
|
+
title
|
|
1432
|
+
iid
|
|
1433
|
+
}
|
|
1434
|
+
}
|
|
1435
|
+
}
|
|
1436
|
+
}
|
|
1437
|
+
}
|
|
1438
|
+
}
|
|
1439
|
+
`;
|
|
1209
1440
|
var TodosClient = class extends GitLabApiClient {
|
|
1210
1441
|
async listTodos(options) {
|
|
1211
|
-
|
|
1212
|
-
|
|
1213
|
-
|
|
1214
|
-
|
|
1442
|
+
if (options?.first !== void 0 && options?.last !== void 0) {
|
|
1443
|
+
throw new Error(
|
|
1444
|
+
'Cannot specify both "first" and "last" pagination parameters. Use "first"/"after" for forward pagination or "last"/"before" for backward pagination.'
|
|
1445
|
+
);
|
|
1446
|
+
}
|
|
1447
|
+
const variables = {};
|
|
1448
|
+
if (options?.first !== void 0) {
|
|
1449
|
+
variables.first = options.first;
|
|
1450
|
+
} else if (options?.last === void 0) {
|
|
1451
|
+
variables.first = 20;
|
|
1452
|
+
}
|
|
1453
|
+
if (options?.after) variables.after = options.after;
|
|
1454
|
+
if (options?.last !== void 0) variables.last = options.last;
|
|
1455
|
+
if (options?.before) variables.before = options.before;
|
|
1456
|
+
if (options?.action) {
|
|
1457
|
+
variables.action = [this.mapTodoAction(options.action)];
|
|
1458
|
+
}
|
|
1459
|
+
if (options?.author_id) {
|
|
1460
|
+
variables.authorId = [`gid://gitlab/User/${options.author_id}`];
|
|
1461
|
+
}
|
|
1215
1462
|
if (options?.project_id) {
|
|
1216
|
-
|
|
1217
|
-
params.set("project_id", encodedProject);
|
|
1463
|
+
variables.projectId = [options.project_id];
|
|
1218
1464
|
}
|
|
1219
|
-
if (options?.group_id)
|
|
1220
|
-
|
|
1221
|
-
|
|
1222
|
-
|
|
1465
|
+
if (options?.group_id) {
|
|
1466
|
+
variables.groupId = [options.group_id];
|
|
1467
|
+
}
|
|
1468
|
+
if (options?.state) {
|
|
1469
|
+
variables.state = [options.state.toLowerCase()];
|
|
1470
|
+
}
|
|
1471
|
+
if (options?.type) {
|
|
1472
|
+
variables.type = [this.mapTodoTargetType(options.type)];
|
|
1473
|
+
}
|
|
1474
|
+
const result = await this.fetchGraphQL(LIST_TODOS_QUERY, variables);
|
|
1475
|
+
const todos = result.currentUser.todos;
|
|
1476
|
+
return {
|
|
1477
|
+
todos
|
|
1478
|
+
};
|
|
1479
|
+
}
|
|
1480
|
+
mapTodoAction(action) {
|
|
1481
|
+
const actionMap = {
|
|
1482
|
+
assigned: "ASSIGNED",
|
|
1483
|
+
mentioned: "MENTIONED",
|
|
1484
|
+
build_failed: "BUILD_FAILED",
|
|
1485
|
+
marked: "MARKED",
|
|
1486
|
+
approval_required: "APPROVAL_REQUIRED",
|
|
1487
|
+
unmergeable: "UNMERGEABLE",
|
|
1488
|
+
directly_addressed: "DIRECTLY_ADDRESSED",
|
|
1489
|
+
merge_train_removed: "MERGE_TRAIN_REMOVED",
|
|
1490
|
+
review_requested: "REVIEW_REQUESTED"
|
|
1491
|
+
};
|
|
1492
|
+
return actionMap[action] || action.toUpperCase();
|
|
1493
|
+
}
|
|
1494
|
+
mapTodoTargetType(type) {
|
|
1495
|
+
const typeMap = {
|
|
1496
|
+
Issue: "ISSUE",
|
|
1497
|
+
MergeRequest: "MERGEREQUEST",
|
|
1498
|
+
"DesignManagement::Design": "DESIGN",
|
|
1499
|
+
Alert: "ALERT",
|
|
1500
|
+
Commit: "COMMIT",
|
|
1501
|
+
Epic: "EPIC"
|
|
1502
|
+
};
|
|
1503
|
+
return typeMap[type] || type;
|
|
1223
1504
|
}
|
|
1224
1505
|
async markTodoAsDone(todoId) {
|
|
1225
1506
|
return this.fetch("POST", `/todos/${todoId}/mark_as_done`);
|
|
@@ -1228,7 +1509,8 @@ var TodosClient = class extends GitLabApiClient {
|
|
|
1228
1509
|
return this.fetch("POST", "/todos/mark_as_done");
|
|
1229
1510
|
}
|
|
1230
1511
|
async getTodoCount() {
|
|
1231
|
-
|
|
1512
|
+
const result = await this.fetchGraphQL(`query { currentUser { todos(state: [pending]) { count } } }`);
|
|
1513
|
+
return { count: result.currentUser.todos.count };
|
|
1232
1514
|
}
|
|
1233
1515
|
};
|
|
1234
1516
|
|
|
@@ -1238,7 +1520,7 @@ var LIST_EPIC_NOTES_QUERY = `
|
|
|
1238
1520
|
${NOTES_CONNECTION_FRAGMENT}
|
|
1239
1521
|
query listEpicNotes(
|
|
1240
1522
|
$groupPath: ID!
|
|
1241
|
-
$epicIid:
|
|
1523
|
+
$epicIid: String!
|
|
1242
1524
|
$first: Int
|
|
1243
1525
|
$after: String
|
|
1244
1526
|
$last: Int
|
|
@@ -1258,6 +1540,32 @@ var LIST_EPIC_NOTES_QUERY = `
|
|
|
1258
1540
|
}
|
|
1259
1541
|
}
|
|
1260
1542
|
`;
|
|
1543
|
+
var LIST_EPIC_DISCUSSIONS_QUERY = `
|
|
1544
|
+
${DISCUSSION_NOTE_FRAGMENT}
|
|
1545
|
+
${DISCUSSION_FRAGMENT}
|
|
1546
|
+
${DISCUSSIONS_CONNECTION_FRAGMENT}
|
|
1547
|
+
query listEpicDiscussions(
|
|
1548
|
+
$groupPath: ID!
|
|
1549
|
+
$epicIid: String!
|
|
1550
|
+
$first: Int
|
|
1551
|
+
$after: String
|
|
1552
|
+
$last: Int
|
|
1553
|
+
$before: String
|
|
1554
|
+
) {
|
|
1555
|
+
group(fullPath: $groupPath) {
|
|
1556
|
+
epic(iid: $epicIid) {
|
|
1557
|
+
discussions(
|
|
1558
|
+
first: $first
|
|
1559
|
+
after: $after
|
|
1560
|
+
last: $last
|
|
1561
|
+
before: $before
|
|
1562
|
+
) {
|
|
1563
|
+
...DiscussionsConnectionFields
|
|
1564
|
+
}
|
|
1565
|
+
}
|
|
1566
|
+
}
|
|
1567
|
+
}
|
|
1568
|
+
`;
|
|
1261
1569
|
var EpicsClient = class extends GitLabApiClient {
|
|
1262
1570
|
async getEpic(groupId, epicIid) {
|
|
1263
1571
|
const encodedGroup = encodeURIComponent(groupId);
|
|
@@ -1326,12 +1634,21 @@ var EpicsClient = class extends GitLabApiClient {
|
|
|
1326
1634
|
totalCount: notes.count
|
|
1327
1635
|
};
|
|
1328
1636
|
}
|
|
1329
|
-
|
|
1330
|
-
|
|
1331
|
-
|
|
1332
|
-
|
|
1333
|
-
|
|
1334
|
-
|
|
1637
|
+
/**
|
|
1638
|
+
* List discussions on an epic using GraphQL API with pagination support
|
|
1639
|
+
*/
|
|
1640
|
+
async listEpicDiscussions(groupId, epicIid, options) {
|
|
1641
|
+
const variables = {
|
|
1642
|
+
groupPath: groupId,
|
|
1643
|
+
epicIid: String(epicIid),
|
|
1644
|
+
...buildDiscussionsPaginationVariables(options)
|
|
1645
|
+
};
|
|
1646
|
+
const result = await this.fetchGraphQL(LIST_EPIC_DISCUSSIONS_QUERY, variables);
|
|
1647
|
+
const discussions = result.group?.epic?.discussions;
|
|
1648
|
+
if (!discussions) {
|
|
1649
|
+
throw new Error("Epic not found or access denied");
|
|
1650
|
+
}
|
|
1651
|
+
return { discussions };
|
|
1335
1652
|
}
|
|
1336
1653
|
async getEpicDiscussion(groupId, epicIid, discussionId) {
|
|
1337
1654
|
const encodedGroup = encodeURIComponent(groupId);
|
|
@@ -1389,21 +1706,32 @@ var LIST_SNIPPET_NOTES_QUERY = `
|
|
|
1389
1706
|
}
|
|
1390
1707
|
}
|
|
1391
1708
|
`;
|
|
1392
|
-
var
|
|
1393
|
-
|
|
1394
|
-
|
|
1395
|
-
|
|
1396
|
-
|
|
1397
|
-
|
|
1398
|
-
|
|
1399
|
-
|
|
1400
|
-
|
|
1401
|
-
|
|
1402
|
-
|
|
1403
|
-
|
|
1404
|
-
|
|
1405
|
-
|
|
1709
|
+
var LIST_SNIPPET_DISCUSSIONS_QUERY = `
|
|
1710
|
+
${DISCUSSION_NOTE_FRAGMENT}
|
|
1711
|
+
${DISCUSSION_FRAGMENT}
|
|
1712
|
+
${DISCUSSIONS_CONNECTION_FRAGMENT}
|
|
1713
|
+
query listSnippetDiscussions(
|
|
1714
|
+
$snippetGid: SnippetID!
|
|
1715
|
+
$first: Int
|
|
1716
|
+
$after: String
|
|
1717
|
+
$last: Int
|
|
1718
|
+
$before: String
|
|
1719
|
+
) {
|
|
1720
|
+
snippets(ids: [$snippetGid]) {
|
|
1721
|
+
nodes {
|
|
1722
|
+
discussions(
|
|
1723
|
+
first: $first
|
|
1724
|
+
after: $after
|
|
1725
|
+
last: $last
|
|
1726
|
+
before: $before
|
|
1727
|
+
) {
|
|
1728
|
+
...DiscussionsConnectionFields
|
|
1729
|
+
}
|
|
1730
|
+
}
|
|
1731
|
+
}
|
|
1406
1732
|
}
|
|
1733
|
+
`;
|
|
1734
|
+
var SnippetsClient = class extends GitLabApiClient {
|
|
1407
1735
|
/**
|
|
1408
1736
|
* List notes on a snippet using GraphQL API with pagination support
|
|
1409
1737
|
*/
|
|
@@ -1429,6 +1757,33 @@ var SnippetsClient = class extends GitLabApiClient {
|
|
|
1429
1757
|
totalCount: notes.count
|
|
1430
1758
|
};
|
|
1431
1759
|
}
|
|
1760
|
+
/**
|
|
1761
|
+
* List discussions on a snippet using GraphQL API with pagination support
|
|
1762
|
+
*/
|
|
1763
|
+
async listSnippetDiscussions(projectId, snippetId, options) {
|
|
1764
|
+
const variables = {
|
|
1765
|
+
snippetGid: `gid://gitlab/ProjectSnippet/${snippetId}`,
|
|
1766
|
+
...buildDiscussionsPaginationVariables(options)
|
|
1767
|
+
};
|
|
1768
|
+
const result = await this.fetchGraphQL(LIST_SNIPPET_DISCUSSIONS_QUERY, variables);
|
|
1769
|
+
const discussions = result.snippets.nodes[0]?.discussions || {
|
|
1770
|
+
nodes: [],
|
|
1771
|
+
pageInfo: {
|
|
1772
|
+
hasNextPage: false,
|
|
1773
|
+
hasPreviousPage: false,
|
|
1774
|
+
startCursor: null,
|
|
1775
|
+
endCursor: null
|
|
1776
|
+
}
|
|
1777
|
+
};
|
|
1778
|
+
return { discussions };
|
|
1779
|
+
}
|
|
1780
|
+
async getSnippetDiscussion(projectId, snippetId, discussionId) {
|
|
1781
|
+
const encodedProject = this.encodeProjectId(projectId);
|
|
1782
|
+
return this.fetch(
|
|
1783
|
+
"GET",
|
|
1784
|
+
`/projects/${encodedProject}/snippets/${snippetId}/discussions/${discussionId}`
|
|
1785
|
+
);
|
|
1786
|
+
}
|
|
1432
1787
|
async createSnippetNote(projectId, snippetId, body, discussionId) {
|
|
1433
1788
|
const encodedProject = this.encodeProjectId(projectId);
|
|
1434
1789
|
if (discussionId) {
|
|
@@ -1772,11 +2127,20 @@ Returns all discussion threads with nested notes. Each discussion contains a 'no
|
|
|
1772
2127
|
Note: For a flattened list of all comments, use gitlab_list_mr_notes instead.`,
|
|
1773
2128
|
args: {
|
|
1774
2129
|
project_id: z.string().describe("The project ID or URL-encoded path"),
|
|
1775
|
-
mr_iid: z.number().describe("The internal ID of the merge request")
|
|
2130
|
+
mr_iid: z.number().describe("The internal ID of the merge request"),
|
|
2131
|
+
first: z.number().optional().describe("Number of discussions to fetch from the beginning (default: 20)"),
|
|
2132
|
+
after: z.string().optional().describe("Cursor for forward pagination (from pageInfo.endCursor)"),
|
|
2133
|
+
last: z.number().optional().describe("Number of discussions to fetch from the end"),
|
|
2134
|
+
before: z.string().optional().describe("Cursor for backward pagination (from pageInfo.startCursor)")
|
|
1776
2135
|
},
|
|
1777
2136
|
execute: async (args, _ctx) => {
|
|
1778
2137
|
const client = getGitLabClient();
|
|
1779
|
-
const discussions = await client.listMrDiscussions(args.project_id, args.mr_iid
|
|
2138
|
+
const discussions = await client.listMrDiscussions(args.project_id, args.mr_iid, {
|
|
2139
|
+
first: args.first,
|
|
2140
|
+
after: args.after,
|
|
2141
|
+
last: args.last,
|
|
2142
|
+
before: args.before
|
|
2143
|
+
});
|
|
1780
2144
|
return JSON.stringify(discussions, null, 2);
|
|
1781
2145
|
}
|
|
1782
2146
|
}),
|
|
@@ -2172,11 +2536,20 @@ Returns all discussion threads with nested notes. Each discussion contains a 'no
|
|
|
2172
2536
|
Use the discussion 'id' field to reply to a specific thread with gitlab_create_issue_note.`,
|
|
2173
2537
|
args: {
|
|
2174
2538
|
project_id: z2.string().describe("The project ID or URL-encoded path"),
|
|
2175
|
-
issue_iid: z2.number().describe("The internal ID of the issue")
|
|
2539
|
+
issue_iid: z2.number().describe("The internal ID of the issue"),
|
|
2540
|
+
first: z2.number().optional().describe("Number of discussions to fetch from the beginning (default: 20)"),
|
|
2541
|
+
after: z2.string().optional().describe("Cursor for forward pagination (from pageInfo.endCursor)"),
|
|
2542
|
+
last: z2.number().optional().describe("Number of discussions to fetch from the end"),
|
|
2543
|
+
before: z2.string().optional().describe("Cursor for backward pagination (from pageInfo.startCursor)")
|
|
2176
2544
|
},
|
|
2177
2545
|
execute: async (args, _ctx) => {
|
|
2178
2546
|
const client = getGitLabClient();
|
|
2179
|
-
const discussions = await client.listIssueDiscussions(args.project_id, args.issue_iid
|
|
2547
|
+
const discussions = await client.listIssueDiscussions(args.project_id, args.issue_iid, {
|
|
2548
|
+
first: args.first,
|
|
2549
|
+
after: args.after,
|
|
2550
|
+
last: args.last,
|
|
2551
|
+
before: args.before
|
|
2552
|
+
});
|
|
2180
2553
|
return JSON.stringify(discussions, null, 2);
|
|
2181
2554
|
}
|
|
2182
2555
|
}),
|
|
@@ -2449,11 +2822,20 @@ Returns all discussion threads with nested notes. Each discussion contains a 'no
|
|
|
2449
2822
|
Use the discussion 'id' field to reply to a specific thread with gitlab_create_epic_note.`,
|
|
2450
2823
|
args: {
|
|
2451
2824
|
group_id: z3.string().describe("The group ID or URL-encoded path"),
|
|
2452
|
-
epic_iid: z3.number().describe("The internal ID of the epic")
|
|
2825
|
+
epic_iid: z3.number().describe("The internal ID of the epic"),
|
|
2826
|
+
first: z3.number().optional().describe("Number of discussions to fetch from the beginning (default: 20)"),
|
|
2827
|
+
after: z3.string().optional().describe("Cursor for forward pagination (from pageInfo.endCursor)"),
|
|
2828
|
+
last: z3.number().optional().describe("Number of discussions to fetch from the end"),
|
|
2829
|
+
before: z3.string().optional().describe("Cursor for backward pagination (from pageInfo.startCursor)")
|
|
2453
2830
|
},
|
|
2454
2831
|
execute: async (args, _ctx) => {
|
|
2455
2832
|
const client = getGitLabClient();
|
|
2456
|
-
const discussions = await client.listEpicDiscussions(args.group_id, args.epic_iid
|
|
2833
|
+
const discussions = await client.listEpicDiscussions(args.group_id, args.epic_iid, {
|
|
2834
|
+
first: args.first,
|
|
2835
|
+
after: args.after,
|
|
2836
|
+
last: args.last,
|
|
2837
|
+
before: args.before
|
|
2838
|
+
});
|
|
2457
2839
|
return JSON.stringify(discussions, null, 2);
|
|
2458
2840
|
}
|
|
2459
2841
|
}),
|
|
@@ -3423,11 +3805,20 @@ Returns all discussion threads with nested notes. Each discussion contains a 'no
|
|
|
3423
3805
|
Use the discussion 'id' field to reply to a specific thread with gitlab_create_snippet_note.`,
|
|
3424
3806
|
args: {
|
|
3425
3807
|
project_id: z9.string().describe("The project ID or URL-encoded path"),
|
|
3426
|
-
snippet_id: z9.number().describe("The ID of the snippet")
|
|
3808
|
+
snippet_id: z9.number().describe("The ID of the snippet"),
|
|
3809
|
+
first: z9.number().optional().describe("Number of discussions to fetch from the beginning (default: 20)"),
|
|
3810
|
+
after: z9.string().optional().describe("Cursor for forward pagination (from pageInfo.endCursor)"),
|
|
3811
|
+
last: z9.number().optional().describe("Number of discussions to fetch from the end"),
|
|
3812
|
+
before: z9.string().optional().describe("Cursor for backward pagination (from pageInfo.startCursor)")
|
|
3427
3813
|
},
|
|
3428
3814
|
execute: async (args, _ctx) => {
|
|
3429
3815
|
const client = getGitLabClient();
|
|
3430
|
-
const discussions = await client.listSnippetDiscussions(args.project_id, args.snippet_id
|
|
3816
|
+
const discussions = await client.listSnippetDiscussions(args.project_id, args.snippet_id, {
|
|
3817
|
+
first: args.first,
|
|
3818
|
+
after: args.after,
|
|
3819
|
+
last: args.last,
|
|
3820
|
+
before: args.before
|
|
3821
|
+
});
|
|
3431
3822
|
return JSON.stringify(discussions, null, 2);
|
|
3432
3823
|
}
|
|
3433
3824
|
}),
|
|
@@ -3524,9 +3915,13 @@ import { tool as tool10 } from "@opencode-ai/plugin";
|
|
|
3524
3915
|
var z10 = tool10.schema;
|
|
3525
3916
|
var todoTools = {
|
|
3526
3917
|
gitlab_list_todos: tool10({
|
|
3527
|
-
description: `List TODO items for the current user.
|
|
3918
|
+
description: `List TODO items for the current user using GraphQL API with pagination support.
|
|
3528
3919
|
Returns a list of pending or done TODO items assigned to the authenticated user.
|
|
3529
|
-
TODOs are created when you are assigned to an issue/MR, mentioned in a comment, or when someone requests your review
|
|
3920
|
+
TODOs are created when you are assigned to an issue/MR, mentioned in a comment, or when someone requests your review.
|
|
3921
|
+
|
|
3922
|
+
The response includes pagination information (pageInfo) with cursors for fetching additional pages.
|
|
3923
|
+
Use 'after' with the 'endCursor' from pageInfo to get the next page.
|
|
3924
|
+
Use 'before' with the 'startCursor' from pageInfo to get the previous page.`,
|
|
3530
3925
|
args: {
|
|
3531
3926
|
action: z10.enum([
|
|
3532
3927
|
"assigned",
|
|
@@ -3543,21 +3938,27 @@ TODOs are created when you are assigned to an issue/MR, mentioned in a comment,
|
|
|
3543
3938
|
project_id: z10.string().optional().describe("Filter by project ID or path"),
|
|
3544
3939
|
group_id: z10.string().optional().describe("Filter by group ID"),
|
|
3545
3940
|
state: z10.enum(["pending", "done"]).optional().describe("Filter by state (default: pending)"),
|
|
3546
|
-
type: z10.enum(["Issue", "MergeRequest", "DesignManagement::Design", "Alert"]).optional().describe("Filter by target type"),
|
|
3547
|
-
|
|
3941
|
+
type: z10.enum(["Issue", "MergeRequest", "DesignManagement::Design", "Alert", "Epic", "Commit"]).optional().describe("Filter by target type"),
|
|
3942
|
+
first: z10.number().optional().describe("Number of items to return from the beginning (default: 20, max: 100)"),
|
|
3943
|
+
after: z10.string().optional().describe("Cursor for forward pagination - use endCursor from previous response"),
|
|
3944
|
+
last: z10.number().optional().describe("Number of items to return from the end (for backward pagination)"),
|
|
3945
|
+
before: z10.string().optional().describe("Cursor for backward pagination - use startCursor from previous response")
|
|
3548
3946
|
},
|
|
3549
3947
|
execute: async (args, _ctx) => {
|
|
3550
3948
|
const client = getGitLabClient();
|
|
3551
|
-
const
|
|
3949
|
+
const result = await client.listTodos({
|
|
3552
3950
|
action: args.action,
|
|
3553
3951
|
author_id: args.author_id,
|
|
3554
3952
|
project_id: args.project_id,
|
|
3555
3953
|
group_id: args.group_id,
|
|
3556
3954
|
state: args.state,
|
|
3557
3955
|
type: args.type,
|
|
3558
|
-
|
|
3956
|
+
first: args.first,
|
|
3957
|
+
after: args.after,
|
|
3958
|
+
last: args.last,
|
|
3959
|
+
before: args.before
|
|
3559
3960
|
});
|
|
3560
|
-
return JSON.stringify(
|
|
3961
|
+
return JSON.stringify(result, null, 2);
|
|
3561
3962
|
}
|
|
3562
3963
|
}),
|
|
3563
3964
|
gitlab_mark_todo_done: tool10({
|
package/package.json
CHANGED
|
Binary file
|