@gitlab/opencode-gitlab-plugin 1.7.0 → 1.8.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,20 @@
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.8.0](https://gitlab.com/gitlab-org/editor-extensions/opencode-gitlab-plugin/compare/v1.7.1...v1.8.0) (2026-02-25)
6
+
7
+
8
+ ### ✨ Features
9
+
10
+ * **users:** add user lookup and status tools ([992cb91](https://gitlab.com/gitlab-org/editor-extensions/opencode-gitlab-plugin/commit/992cb91565d94f9b69e764262c9f792fe05c1b12))
11
+
12
+ ## [1.7.1](https://gitlab.com/gitlab-org/editor-extensions/opencode-gitlab-plugin/compare/v1.7.0...v1.7.1) (2026-02-24)
13
+
14
+
15
+ ### 📚 Documentation
16
+
17
+ * **discussions:** improve gitlab_create_discussion description for reply use case ([a0d2296](https://gitlab.com/gitlab-org/editor-extensions/opencode-gitlab-plugin/commit/a0d2296cf2aa42258c7ca1749df86810c852174b))
18
+
5
19
  ## [1.7.0](https://gitlab.com/gitlab-org/editor-extensions/opencode-gitlab-plugin/compare/v1.6.2...v1.7.0) (2026-02-24)
6
20
 
7
21
 
package/dist/index.js CHANGED
@@ -1159,6 +1159,29 @@ var UsersClient = class extends GitLabApiClient {
1159
1159
  async getCurrentUser() {
1160
1160
  return this.fetch("GET", "/user");
1161
1161
  }
1162
+ /**
1163
+ * Get a user by ID
1164
+ * @param userId - The user ID
1165
+ */
1166
+ async getUser(userId) {
1167
+ return this.fetch("GET", `/users/${userId}`);
1168
+ }
1169
+ /**
1170
+ * Find users by username
1171
+ * @param username - The username to search for (exact match)
1172
+ */
1173
+ async getUserByUsername(username) {
1174
+ const params = new URLSearchParams();
1175
+ params.set("username", username);
1176
+ return this.fetch("GET", `/users?${params}`);
1177
+ }
1178
+ /**
1179
+ * Get a user's status
1180
+ * @param userId - The user ID
1181
+ */
1182
+ async getUserStatus(userId) {
1183
+ return this.fetch("GET", `/users/${userId}/status`);
1184
+ }
1162
1185
  };
1163
1186
 
1164
1187
  // src/client/wikis.ts
@@ -3144,8 +3167,12 @@ var projectTools = {
3144
3167
  }
3145
3168
  })
3146
3169
  };
3170
+
3171
+ // src/tools/users.ts
3172
+ import { tool as tool8 } from "@opencode-ai/plugin";
3173
+ var z8 = tool8.schema;
3147
3174
  var userTools = {
3148
- gitlab_get_current_user: tool7({
3175
+ gitlab_get_current_user: tool8({
3149
3176
  description: `Get current user information.
3150
3177
  Returns details about the authenticated user including username, email, and permissions.`,
3151
3178
  args: {},
@@ -3154,21 +3181,73 @@ Returns details about the authenticated user including username, email, and perm
3154
3181
  const user = await client.getCurrentUser();
3155
3182
  return JSON.stringify(user, null, 2);
3156
3183
  }
3184
+ }),
3185
+ gitlab_get_user: tool8({
3186
+ description: `Get a user by their ID.
3187
+ Returns user details including username, name, state, and profile information.`,
3188
+ args: {
3189
+ user_id: z8.number().describe("The user ID")
3190
+ },
3191
+ execute: async (args, _ctx) => {
3192
+ const client = getGitLabClient();
3193
+ const user = await client.getUser(args.user_id);
3194
+ return JSON.stringify(user, null, 2);
3195
+ }
3196
+ }),
3197
+ gitlab_get_user_by_username: tool8({
3198
+ description: `Find a user by their username.
3199
+ Returns user details including ID, name, state, and profile information.
3200
+ Useful for looking up a user's ID when you only know their username.`,
3201
+ args: {
3202
+ username: z8.string().describe("The username to look up (without @ prefix)")
3203
+ },
3204
+ execute: async (args, _ctx) => {
3205
+ const client = getGitLabClient();
3206
+ const username = args.username.replace(/^@/, "");
3207
+ const users = await client.getUserByUsername(username);
3208
+ if (users.length === 0) {
3209
+ return JSON.stringify({ error: `No user found with username: ${username}` });
3210
+ }
3211
+ if (users.length > 1) {
3212
+ return JSON.stringify(
3213
+ {
3214
+ warning: `Multiple users found for username: ${username}`,
3215
+ users
3216
+ },
3217
+ null,
3218
+ 2
3219
+ );
3220
+ }
3221
+ return JSON.stringify(users[0], null, 2);
3222
+ }
3223
+ }),
3224
+ gitlab_get_user_status: tool8({
3225
+ description: `Get a user's status including availability.
3226
+ Returns the user's status emoji, message, and availability (e.g., "busy").
3227
+ Useful for checking if someone is available before requesting a review.`,
3228
+ args: {
3229
+ user_id: z8.number().describe("The user ID")
3230
+ },
3231
+ execute: async (args, _ctx) => {
3232
+ const client = getGitLabClient();
3233
+ const status = await client.getUserStatus(args.user_id);
3234
+ return JSON.stringify(status, null, 2);
3235
+ }
3157
3236
  })
3158
3237
  };
3159
3238
 
3160
3239
  // src/tools/security.ts
3161
- import { tool as tool8 } from "@opencode-ai/plugin";
3162
- var z8 = tool8.schema;
3240
+ import { tool as tool9 } from "@opencode-ai/plugin";
3241
+ var z9 = tool9.schema;
3163
3242
  var securityTools = {
3164
- gitlab_list_vulnerabilities: tool8({
3243
+ gitlab_list_vulnerabilities: tool9({
3165
3244
  description: `List persisted vulnerabilities for a project.
3166
3245
  Returns security vulnerabilities detected in the project.`,
3167
3246
  args: {
3168
- project_id: z8.string().describe("The project ID or URL-encoded path"),
3169
- state: z8.enum(["detected", "confirmed", "dismissed", "resolved"]).optional().describe("Filter by vulnerability state"),
3170
- severity: z8.enum(["undefined", "info", "unknown", "low", "medium", "high", "critical"]).optional().describe("Filter by severity level"),
3171
- report_type: z8.enum([
3247
+ project_id: z9.string().describe("The project ID or URL-encoded path"),
3248
+ state: z9.enum(["detected", "confirmed", "dismissed", "resolved"]).optional().describe("Filter by vulnerability state"),
3249
+ severity: z9.enum(["undefined", "info", "unknown", "low", "medium", "high", "critical"]).optional().describe("Filter by severity level"),
3250
+ report_type: z9.enum([
3172
3251
  "sast",
3173
3252
  "dast",
3174
3253
  "dependency_scanning",
@@ -3177,7 +3256,7 @@ Returns security vulnerabilities detected in the project.`,
3177
3256
  "coverage_fuzzing",
3178
3257
  "api_fuzzing"
3179
3258
  ]).optional().describe("Filter by report type"),
3180
- limit: z8.number().optional().describe("Maximum number of results (default: 20)")
3259
+ limit: z9.number().optional().describe("Maximum number of results (default: 20)")
3181
3260
  },
3182
3261
  execute: async (args, _ctx) => {
3183
3262
  const client = getGitLabClient();
@@ -3190,12 +3269,12 @@ Returns security vulnerabilities detected in the project.`,
3190
3269
  return JSON.stringify(vulnerabilities, null, 2);
3191
3270
  }
3192
3271
  }),
3193
- gitlab_get_vulnerability_details: tool8({
3272
+ gitlab_get_vulnerability_details: tool9({
3194
3273
  description: `Get details for a specific vulnerability.
3195
3274
  Returns full information about a security vulnerability including description, location, and remediation.`,
3196
3275
  args: {
3197
- project_id: z8.string().describe("The project ID or URL-encoded path"),
3198
- vulnerability_id: z8.number().describe("The ID of the vulnerability")
3276
+ project_id: z9.string().describe("The project ID or URL-encoded path"),
3277
+ vulnerability_id: z9.number().describe("The ID of the vulnerability")
3199
3278
  },
3200
3279
  execute: async (args, _ctx) => {
3201
3280
  const client = getGitLabClient();
@@ -3206,13 +3285,13 @@ Returns full information about a security vulnerability including description, l
3206
3285
  return JSON.stringify(vulnerability, null, 2);
3207
3286
  }
3208
3287
  }),
3209
- gitlab_create_vulnerability_issue: tool8({
3288
+ gitlab_create_vulnerability_issue: tool9({
3210
3289
  description: `Create a new issue linked to one or more security vulnerabilities.
3211
3290
  This creates an issue in the project and automatically links it to the specified vulnerabilities.
3212
3291
  Requires Developer role or higher.`,
3213
3292
  args: {
3214
- project_path: z8.string().describe('Full path of the project (e.g., "group/project" or "group/subgroup/project")'),
3215
- vulnerability_ids: z8.array(z8.string()).describe(
3293
+ project_path: z9.string().describe('Full path of the project (e.g., "group/project" or "group/subgroup/project")'),
3294
+ vulnerability_ids: z9.array(z9.string()).describe(
3216
3295
  'Array of vulnerability IDs in format "gid://gitlab/Vulnerability/{id}". Get these from gitlab_list_vulnerabilities.'
3217
3296
  )
3218
3297
  },
@@ -3225,22 +3304,22 @@ Requires Developer role or higher.`,
3225
3304
  return JSON.stringify(issue, null, 2);
3226
3305
  }
3227
3306
  }),
3228
- gitlab_dismiss_vulnerability: tool8({
3307
+ gitlab_dismiss_vulnerability: tool9({
3229
3308
  description: `Dismiss a security vulnerability with a reason.
3230
3309
  Use this when a vulnerability is not applicable, is a false positive, or has been mitigated.
3231
3310
  Requires Developer role or higher.`,
3232
3311
  args: {
3233
- vulnerability_id: z8.string().describe(
3312
+ vulnerability_id: z9.string().describe(
3234
3313
  'Vulnerability ID in format "gid://gitlab/Vulnerability/{id}". Get this from gitlab_list_vulnerabilities.'
3235
3314
  ),
3236
- reason: z8.enum([
3315
+ reason: z9.enum([
3237
3316
  "ACCEPTABLE_RISK",
3238
3317
  "FALSE_POSITIVE",
3239
3318
  "MITIGATING_CONTROL",
3240
3319
  "USED_IN_TESTS",
3241
3320
  "NOT_APPLICABLE"
3242
3321
  ]).describe("Reason for dismissing the vulnerability"),
3243
- comment: z8.string().optional().describe("Optional comment explaining the dismissal")
3322
+ comment: z9.string().optional().describe("Optional comment explaining the dismissal")
3244
3323
  },
3245
3324
  execute: async (args, _ctx) => {
3246
3325
  const client = getGitLabClient();
@@ -3252,15 +3331,15 @@ Requires Developer role or higher.`,
3252
3331
  return JSON.stringify(vulnerability, null, 2);
3253
3332
  }
3254
3333
  }),
3255
- gitlab_confirm_vulnerability: tool8({
3334
+ gitlab_confirm_vulnerability: tool9({
3256
3335
  description: `Confirm a security vulnerability.
3257
3336
  Use this to acknowledge that a vulnerability is valid and needs attention.
3258
3337
  Requires Developer role or higher.`,
3259
3338
  args: {
3260
- vulnerability_id: z8.string().describe(
3339
+ vulnerability_id: z9.string().describe(
3261
3340
  'Vulnerability ID in format "gid://gitlab/Vulnerability/{id}". Get this from gitlab_list_vulnerabilities.'
3262
3341
  ),
3263
- comment: z8.string().optional().describe("Optional comment about the confirmation")
3342
+ comment: z9.string().optional().describe("Optional comment about the confirmation")
3264
3343
  },
3265
3344
  execute: async (args, _ctx) => {
3266
3345
  const client = getGitLabClient();
@@ -3268,15 +3347,15 @@ Requires Developer role or higher.`,
3268
3347
  return JSON.stringify(vulnerability, null, 2);
3269
3348
  }
3270
3349
  }),
3271
- gitlab_revert_vulnerability_to_detected: tool8({
3350
+ gitlab_revert_vulnerability_to_detected: tool9({
3272
3351
  description: `Revert a vulnerability back to detected state.
3273
3352
  Use this to undo a previous confirmation or dismissal.
3274
3353
  Requires Developer role or higher.`,
3275
3354
  args: {
3276
- vulnerability_id: z8.string().describe(
3355
+ vulnerability_id: z9.string().describe(
3277
3356
  'Vulnerability ID in format "gid://gitlab/Vulnerability/{id}". Get this from gitlab_list_vulnerabilities.'
3278
3357
  ),
3279
- comment: z8.string().optional().describe("Optional comment about reverting the state")
3358
+ comment: z9.string().optional().describe("Optional comment about reverting the state")
3280
3359
  },
3281
3360
  execute: async (args, _ctx) => {
3282
3361
  const client = getGitLabClient();
@@ -3284,16 +3363,16 @@ Requires Developer role or higher.`,
3284
3363
  return JSON.stringify(vulnerability, null, 2);
3285
3364
  }
3286
3365
  }),
3287
- gitlab_update_vulnerability_severity: tool8({
3366
+ gitlab_update_vulnerability_severity: tool9({
3288
3367
  description: `Update the severity level of one or more vulnerabilities.
3289
3368
  Use this to adjust the severity rating based on your assessment.
3290
3369
  Requires Developer role or higher.`,
3291
3370
  args: {
3292
- vulnerability_ids: z8.array(z8.string()).describe(
3371
+ vulnerability_ids: z9.array(z9.string()).describe(
3293
3372
  'Array of vulnerability IDs in format "gid://gitlab/Vulnerability/{id}". Get these from gitlab_list_vulnerabilities.'
3294
3373
  ),
3295
- severity: z8.enum(["CRITICAL", "HIGH", "MEDIUM", "LOW", "INFO", "UNKNOWN"]).describe("New severity level for the vulnerabilities"),
3296
- comment: z8.string().describe("Comment explaining the severity change (required)")
3374
+ severity: z9.enum(["CRITICAL", "HIGH", "MEDIUM", "LOW", "INFO", "UNKNOWN"]).describe("New severity level for the vulnerabilities"),
3375
+ comment: z9.string().describe("Comment explaining the severity change (required)")
3297
3376
  },
3298
3377
  execute: async (args, _ctx) => {
3299
3378
  const client = getGitLabClient();
@@ -3305,15 +3384,15 @@ Requires Developer role or higher.`,
3305
3384
  return JSON.stringify(vulnerabilities, null, 2);
3306
3385
  }
3307
3386
  }),
3308
- gitlab_link_vulnerability_to_issue: tool8({
3387
+ gitlab_link_vulnerability_to_issue: tool9({
3309
3388
  description: `Link an existing issue to one or more vulnerabilities.
3310
3389
  Use this to associate vulnerabilities with an existing issue for tracking.
3311
3390
  Requires Developer role or higher.`,
3312
3391
  args: {
3313
- issue_id: z8.string().describe(
3392
+ issue_id: z9.string().describe(
3314
3393
  'Issue ID in format "gid://gitlab/Issue/{id}". You can construct this from the issue IID.'
3315
3394
  ),
3316
- vulnerability_ids: z8.array(z8.string()).describe(
3395
+ vulnerability_ids: z9.array(z9.string()).describe(
3317
3396
  'Array of vulnerability IDs in format "gid://gitlab/Vulnerability/{id}". Get these from gitlab_list_vulnerabilities.'
3318
3397
  )
3319
3398
  },
@@ -3326,10 +3405,10 @@ Requires Developer role or higher.`,
3326
3405
  };
3327
3406
 
3328
3407
  // src/tools/todos.ts
3329
- import { tool as tool9 } from "@opencode-ai/plugin";
3330
- var z9 = tool9.schema;
3408
+ import { tool as tool10 } from "@opencode-ai/plugin";
3409
+ var z10 = tool10.schema;
3331
3410
  var todoTools = {
3332
- gitlab_list_todos: tool9({
3411
+ gitlab_list_todos: tool10({
3333
3412
  description: `List TODO items for the current user using GraphQL API with pagination support.
3334
3413
  Returns a list of pending or done TODO items assigned to the authenticated user.
3335
3414
  TODOs are created when you are assigned to an issue/MR, mentioned in a comment, or when someone requests your review.
@@ -3338,7 +3417,7 @@ The response includes pagination information (pageInfo) with cursors for fetchin
3338
3417
  Use 'after' with the 'endCursor' from pageInfo to get the next page.
3339
3418
  Use 'before' with the 'startCursor' from pageInfo to get the previous page.`,
3340
3419
  args: {
3341
- action: z9.enum([
3420
+ action: z10.enum([
3342
3421
  "assigned",
3343
3422
  "mentioned",
3344
3423
  "build_failed",
@@ -3349,15 +3428,15 @@ Use 'before' with the 'startCursor' from pageInfo to get the previous page.`,
3349
3428
  "merge_train_removed",
3350
3429
  "review_requested"
3351
3430
  ]).optional().describe("Filter by action type"),
3352
- author_id: z9.number().optional().describe("Filter by author ID"),
3353
- project_id: z9.string().optional().describe("Filter by project ID or path"),
3354
- group_id: z9.string().optional().describe("Filter by group ID"),
3355
- state: z9.enum(["pending", "done"]).optional().describe("Filter by state (default: pending)"),
3356
- type: z9.enum(["Issue", "MergeRequest", "DesignManagement::Design", "Alert", "Epic", "Commit"]).optional().describe("Filter by target type"),
3357
- first: z9.number().optional().describe("Number of items to return from the beginning (default: 20, max: 100)"),
3358
- after: z9.string().optional().describe("Cursor for forward pagination - use endCursor from previous response"),
3359
- last: z9.number().optional().describe("Number of items to return from the end (for backward pagination)"),
3360
- before: z9.string().optional().describe("Cursor for backward pagination - use startCursor from previous response")
3431
+ author_id: z10.number().optional().describe("Filter by author ID"),
3432
+ project_id: z10.string().optional().describe("Filter by project ID or path"),
3433
+ group_id: z10.string().optional().describe("Filter by group ID"),
3434
+ state: z10.enum(["pending", "done"]).optional().describe("Filter by state (default: pending)"),
3435
+ type: z10.enum(["Issue", "MergeRequest", "DesignManagement::Design", "Alert", "Epic", "Commit"]).optional().describe("Filter by target type"),
3436
+ first: z10.number().optional().describe("Number of items to return from the beginning (default: 20, max: 100)"),
3437
+ after: z10.string().optional().describe("Cursor for forward pagination - use endCursor from previous response"),
3438
+ last: z10.number().optional().describe("Number of items to return from the end (for backward pagination)"),
3439
+ before: z10.string().optional().describe("Cursor for backward pagination - use startCursor from previous response")
3361
3440
  },
3362
3441
  execute: async (args, _ctx) => {
3363
3442
  const client = getGitLabClient();
@@ -3376,7 +3455,7 @@ Use 'before' with the 'startCursor' from pageInfo to get the previous page.`,
3376
3455
  return JSON.stringify(result, null, 2);
3377
3456
  }
3378
3457
  }),
3379
- gitlab_mark_todo_done: tool9({
3458
+ gitlab_mark_todo_done: tool10({
3380
3459
  description: `Mark TODO items as done.
3381
3460
 
3382
3461
  Actions:
@@ -3387,8 +3466,8 @@ Examples:
3387
3466
  - Mark one: action="one", todo_id=123
3388
3467
  - Mark all: action="all"`,
3389
3468
  args: {
3390
- action: z9.enum(["one", "all"]).describe('Action to perform: "one" for single TODO, "all" for all TODOs'),
3391
- todo_id: z9.number().optional().describe('The ID of the TODO item (required for action="one")')
3469
+ action: z10.enum(["one", "all"]).describe('Action to perform: "one" for single TODO, "all" for all TODOs'),
3470
+ todo_id: z10.number().optional().describe('The ID of the TODO item (required for action="one")')
3392
3471
  },
3393
3472
  execute: async (args, _ctx) => {
3394
3473
  const client = getGitLabClient();
@@ -3424,7 +3503,7 @@ Examples:
3424
3503
  }
3425
3504
  }
3426
3505
  }),
3427
- gitlab_get_todo_count: tool9({
3506
+ gitlab_get_todo_count: tool10({
3428
3507
  description: `Get the count of pending TODO items.
3429
3508
  Returns the total number of pending TODOs for the current user.`,
3430
3509
  args: {},
@@ -3437,15 +3516,15 @@ Returns the total number of pending TODOs for the current user.`,
3437
3516
  };
3438
3517
 
3439
3518
  // src/tools/wikis.ts
3440
- import { tool as tool10 } from "@opencode-ai/plugin";
3441
- var z10 = tool10.schema;
3519
+ import { tool as tool11 } from "@opencode-ai/plugin";
3520
+ var z11 = tool11.schema;
3442
3521
  var wikiTools = {
3443
- gitlab_get_wiki_page: tool10({
3522
+ gitlab_get_wiki_page: tool11({
3444
3523
  description: `Get a wiki page with its content.
3445
3524
  Returns the wiki page content and metadata.`,
3446
3525
  args: {
3447
- project_id: z10.string().describe("The project ID or URL-encoded path"),
3448
- slug: z10.string().describe("The slug (URL-friendly name) of the wiki page")
3526
+ project_id: z11.string().describe("The project ID or URL-encoded path"),
3527
+ slug: z11.string().describe("The slug (URL-friendly name) of the wiki page")
3449
3528
  },
3450
3529
  execute: async (args, _ctx) => {
3451
3530
  const client = getGitLabClient();
@@ -3456,15 +3535,15 @@ Returns the wiki page content and metadata.`,
3456
3535
  };
3457
3536
 
3458
3537
  // src/tools/work-items.ts
3459
- import { tool as tool11 } from "@opencode-ai/plugin";
3460
- var z11 = tool11.schema;
3538
+ import { tool as tool12 } from "@opencode-ai/plugin";
3539
+ var z12 = tool12.schema;
3461
3540
  var workItemTools = {
3462
- gitlab_get_work_item: tool11({
3541
+ gitlab_get_work_item: tool12({
3463
3542
  description: `Get a single work item (issue, epic, task, etc.).
3464
3543
  Work items are the new unified model for issues, epics, tasks, and other work tracking items in GitLab.`,
3465
3544
  args: {
3466
- project_id: z11.string().describe("The project ID or URL-encoded path"),
3467
- work_item_id: z11.number().describe("The ID of the work item")
3545
+ project_id: z12.string().describe("The project ID or URL-encoded path"),
3546
+ work_item_id: z12.number().describe("The ID of the work item")
3468
3547
  },
3469
3548
  execute: async (args, _ctx) => {
3470
3549
  const client = getGitLabClient();
@@ -3472,17 +3551,17 @@ Work items are the new unified model for issues, epics, tasks, and other work tr
3472
3551
  return JSON.stringify(workItem, null, 2);
3473
3552
  }
3474
3553
  }),
3475
- gitlab_list_work_items: tool11({
3554
+ gitlab_list_work_items: tool12({
3476
3555
  description: `List work items in a project or group.
3477
3556
  Work items include issues, epics, tasks, and other work tracking items.`,
3478
3557
  args: {
3479
- project_id: z11.string().optional().describe("The project ID or URL-encoded path"),
3480
- group_id: z11.string().optional().describe("The group ID or URL-encoded path"),
3481
- state: z11.enum(["opened", "closed", "all"]).optional().describe("Filter by state (default: opened)"),
3482
- search: z11.string().optional().describe("Search work items by title or description"),
3483
- labels: z11.string().optional().describe("Comma-separated list of labels to filter by"),
3484
- work_item_type: z11.string().optional().describe("Filter by work item type (e.g., 'Issue', 'Epic', 'Task')"),
3485
- limit: z11.number().optional().describe("Maximum number of results (default: 20)")
3558
+ project_id: z12.string().optional().describe("The project ID or URL-encoded path"),
3559
+ group_id: z12.string().optional().describe("The group ID or URL-encoded path"),
3560
+ state: z12.enum(["opened", "closed", "all"]).optional().describe("Filter by state (default: opened)"),
3561
+ search: z12.string().optional().describe("Search work items by title or description"),
3562
+ labels: z12.string().optional().describe("Comma-separated list of labels to filter by"),
3563
+ work_item_type: z12.string().optional().describe("Filter by work item type (e.g., 'Issue', 'Epic', 'Task')"),
3564
+ limit: z12.number().optional().describe("Maximum number of results (default: 20)")
3486
3565
  },
3487
3566
  execute: async (args, _ctx) => {
3488
3567
  const client = getGitLabClient();
@@ -3498,12 +3577,12 @@ Work items include issues, epics, tasks, and other work tracking items.`,
3498
3577
  return JSON.stringify(workItems, null, 2);
3499
3578
  }
3500
3579
  }),
3501
- gitlab_get_work_item_notes: tool11({
3580
+ gitlab_get_work_item_notes: tool12({
3502
3581
  description: `Get all comments for a work item.
3503
3582
  Returns all notes/comments on the work item in chronological order.`,
3504
3583
  args: {
3505
- project_id: z11.string().describe("The project ID or URL-encoded path"),
3506
- work_item_id: z11.number().describe("The ID of the work item")
3584
+ project_id: z12.string().describe("The project ID or URL-encoded path"),
3585
+ work_item_id: z12.number().describe("The ID of the work item")
3507
3586
  },
3508
3587
  execute: async (args, _ctx) => {
3509
3588
  const client = getGitLabClient();
@@ -3511,16 +3590,16 @@ Returns all notes/comments on the work item in chronological order.`,
3511
3590
  return JSON.stringify(notes, null, 2);
3512
3591
  }
3513
3592
  }),
3514
- gitlab_create_work_item: tool11({
3593
+ gitlab_create_work_item: tool12({
3515
3594
  description: `Create a new work item (issue, task, etc.).
3516
3595
  Work items are the new unified model for issues, epics, tasks, and other work tracking items.`,
3517
3596
  args: {
3518
- project_id: z11.string().describe("The project ID or URL-encoded path"),
3519
- title: z11.string().describe("The title of the work item"),
3520
- work_item_type_id: z11.number().describe("The ID of the work item type (e.g., 1 for Issue, 2 for Task)"),
3521
- description: z11.string().optional().describe("The description of the work item (supports Markdown)"),
3522
- labels: z11.array(z11.string()).optional().describe("Array of label names"),
3523
- assignee_ids: z11.array(z11.number()).optional().describe("Array of user IDs to assign")
3597
+ project_id: z12.string().describe("The project ID or URL-encoded path"),
3598
+ title: z12.string().describe("The title of the work item"),
3599
+ work_item_type_id: z12.number().describe("The ID of the work item type (e.g., 1 for Issue, 2 for Task)"),
3600
+ description: z12.string().optional().describe("The description of the work item (supports Markdown)"),
3601
+ labels: z12.array(z12.string()).optional().describe("Array of label names"),
3602
+ assignee_ids: z12.array(z12.number()).optional().describe("Array of user IDs to assign")
3524
3603
  },
3525
3604
  execute: async (args, _ctx) => {
3526
3605
  const client = getGitLabClient();
@@ -3534,17 +3613,17 @@ Work items are the new unified model for issues, epics, tasks, and other work tr
3534
3613
  return JSON.stringify(workItem, null, 2);
3535
3614
  }
3536
3615
  }),
3537
- gitlab_update_work_item: tool11({
3616
+ gitlab_update_work_item: tool12({
3538
3617
  description: `Update an existing work item.
3539
3618
  Can update title, description, state, labels, and assignees.`,
3540
3619
  args: {
3541
- project_id: z11.string().describe("The project ID or URL-encoded path"),
3542
- work_item_id: z11.number().describe("The ID of the work item"),
3543
- title: z11.string().optional().describe("The new title"),
3544
- description: z11.string().optional().describe("The new description (supports Markdown)"),
3545
- state_event: z11.enum(["close", "reopen"]).optional().describe("Change the state (close or reopen)"),
3546
- labels: z11.array(z11.string()).optional().describe("Array of label names"),
3547
- assignee_ids: z11.array(z11.number()).optional().describe("Array of user IDs to assign")
3620
+ project_id: z12.string().describe("The project ID or URL-encoded path"),
3621
+ work_item_id: z12.number().describe("The ID of the work item"),
3622
+ title: z12.string().optional().describe("The new title"),
3623
+ description: z12.string().optional().describe("The new description (supports Markdown)"),
3624
+ state_event: z12.enum(["close", "reopen"]).optional().describe("Change the state (close or reopen)"),
3625
+ labels: z12.array(z12.string()).optional().describe("Array of label names"),
3626
+ assignee_ids: z12.array(z12.number()).optional().describe("Array of user IDs to assign")
3548
3627
  },
3549
3628
  execute: async (args, _ctx) => {
3550
3629
  const client = getGitLabClient();
@@ -3558,12 +3637,12 @@ Can update title, description, state, labels, and assignees.`,
3558
3637
  return JSON.stringify(workItem, null, 2);
3559
3638
  }
3560
3639
  }),
3561
- gitlab_create_work_item_note: tool11({
3640
+ gitlab_create_work_item_note: tool12({
3562
3641
  description: `Create a comment on a work item.`,
3563
3642
  args: {
3564
- project_id: z11.string().describe("The project ID or URL-encoded path"),
3565
- work_item_id: z11.number().describe("The ID of the work item"),
3566
- body: z11.string().describe("The content of the note/comment (supports Markdown)")
3643
+ project_id: z12.string().describe("The project ID or URL-encoded path"),
3644
+ work_item_id: z12.number().describe("The ID of the work item"),
3645
+ body: z12.string().describe("The content of the note/comment (supports Markdown)")
3567
3646
  },
3568
3647
  execute: async (args, _ctx) => {
3569
3648
  const client = getGitLabClient();
@@ -3574,8 +3653,8 @@ Can update title, description, state, labels, and assignees.`,
3574
3653
  };
3575
3654
 
3576
3655
  // src/tools/discussions-unified.ts
3577
- import { tool as tool12 } from "@opencode-ai/plugin";
3578
- var z12 = tool12.schema;
3656
+ import { tool as tool13 } from "@opencode-ai/plugin";
3657
+ var z13 = tool13.schema;
3579
3658
  function normalizeBoolean(value) {
3580
3659
  if (typeof value === "boolean") return value;
3581
3660
  if (value === "true") return true;
@@ -3596,15 +3675,15 @@ function filterDiscussionsByResolved(result, resolved) {
3596
3675
  }
3597
3676
  };
3598
3677
  }
3599
- var positionSchema = z12.object({
3600
- base_sha: z12.string().describe("SHA of the base commit"),
3601
- start_sha: z12.string().describe("SHA of the start commit"),
3602
- head_sha: z12.string().describe("SHA of the head commit"),
3603
- position_type: z12.enum(["text", "image"]).describe("Type of position"),
3604
- old_path: z12.string().optional().describe("Path of the file before changes"),
3605
- new_path: z12.string().optional().describe("Path of the file after changes"),
3606
- old_line: z12.number().optional().describe("Line number in the old version"),
3607
- new_line: z12.number().optional().describe("Line number in the new version")
3678
+ var positionSchema = z13.object({
3679
+ base_sha: z13.string().describe("SHA of the base commit"),
3680
+ start_sha: z13.string().describe("SHA of the start commit"),
3681
+ head_sha: z13.string().describe("SHA of the head commit"),
3682
+ position_type: z13.enum(["text", "image"]).describe("Type of position"),
3683
+ old_path: z13.string().optional().describe("Path of the file before changes"),
3684
+ new_path: z13.string().optional().describe("Path of the file after changes"),
3685
+ old_line: z13.number().optional().describe("Line number in the old version"),
3686
+ new_line: z13.number().optional().describe("Line number in the new version")
3608
3687
  });
3609
3688
  function validateResourceParams(resourceType, args) {
3610
3689
  switch (resourceType) {
@@ -3631,7 +3710,7 @@ var discussionsUnifiedTools = {
3631
3710
  /**
3632
3711
  * List discussions for any GitLab resource type
3633
3712
  */
3634
- gitlab_list_discussions: tool12({
3713
+ gitlab_list_discussions: tool13({
3635
3714
  description: `List discussions (comment threads) on any GitLab resource.
3636
3715
  Supports: merge_requests, issues, epics, commits, snippets.
3637
3716
 
@@ -3647,21 +3726,21 @@ Examples:
3647
3726
  - Commit: resource_type="commit", project_id="group/project", sha="abc123"
3648
3727
  - Snippet: resource_type="snippet", project_id="group/project", snippet_id=789`,
3649
3728
  args: {
3650
- resource_type: z12.enum(["merge_request", "issue", "epic", "commit", "snippet"]).describe("Type of GitLab resource"),
3651
- project_id: z12.string().optional().describe("Project ID or path. Required for merge_request, issue, commit, snippet"),
3652
- group_id: z12.string().optional().describe("Group ID or path. Required for epic"),
3653
- iid: z12.number().optional().describe("Internal ID of the resource (for merge_request, issue, epic)"),
3654
- sha: z12.string().optional().describe("Commit SHA (required for commit)"),
3655
- snippet_id: z12.number().optional().describe("Snippet ID (required for snippet)"),
3729
+ resource_type: z13.enum(["merge_request", "issue", "epic", "commit", "snippet"]).describe("Type of GitLab resource"),
3730
+ project_id: z13.string().optional().describe("Project ID or path. Required for merge_request, issue, commit, snippet"),
3731
+ group_id: z13.string().optional().describe("Group ID or path. Required for epic"),
3732
+ iid: z13.number().optional().describe("Internal ID of the resource (for merge_request, issue, epic)"),
3733
+ sha: z13.string().optional().describe("Commit SHA (required for commit)"),
3734
+ snippet_id: z13.number().optional().describe("Snippet ID (required for snippet)"),
3656
3735
  // Filtering
3657
- resolved: z12.boolean().optional().describe(
3736
+ resolved: z13.boolean().optional().describe(
3658
3737
  "Filter by resolved status: true for resolved, false for unresolved. Only returns resolvable discussions (excludes system notes). Client-side filtering."
3659
3738
  ),
3660
3739
  // Pagination
3661
- first: z12.number().optional().describe("Number of items to return (default: 20)"),
3662
- after: z12.string().optional().describe("Cursor for pagination - use endCursor from previous response"),
3663
- before: z12.string().optional().describe("Cursor for backward pagination"),
3664
- last: z12.number().optional().describe("Number of items from the end")
3740
+ first: z13.number().optional().describe("Number of items to return (default: 20)"),
3741
+ after: z13.string().optional().describe("Cursor for pagination - use endCursor from previous response"),
3742
+ before: z13.string().optional().describe("Cursor for backward pagination"),
3743
+ last: z13.number().optional().describe("Number of items from the end")
3665
3744
  },
3666
3745
  execute: async (args, _ctx) => {
3667
3746
  validateResourceParams(args.resource_type, args);
@@ -3710,7 +3789,7 @@ Examples:
3710
3789
  /**
3711
3790
  * Get a specific discussion thread from any GitLab resource
3712
3791
  */
3713
- gitlab_get_discussion: tool12({
3792
+ gitlab_get_discussion: tool13({
3714
3793
  description: `Get a specific discussion thread with all its replies.
3715
3794
  Returns the discussion with its 'notes' array containing all comments.
3716
3795
 
@@ -3723,13 +3802,13 @@ Required parameters vary by resource type:
3723
3802
  - commit: project_id, sha, discussion_id
3724
3803
  - snippet: project_id, snippet_id, discussion_id`,
3725
3804
  args: {
3726
- resource_type: z12.enum(["merge_request", "issue", "epic", "commit", "snippet"]).describe("Type of GitLab resource"),
3727
- discussion_id: z12.string().describe("The ID of the discussion thread"),
3728
- project_id: z12.string().optional().describe("Project ID or path"),
3729
- group_id: z12.string().optional().describe("Group ID or path (for epic)"),
3730
- iid: z12.number().optional().describe("Internal ID (for merge_request, issue, epic)"),
3731
- sha: z12.string().optional().describe("Commit SHA (for commit)"),
3732
- snippet_id: z12.number().optional().describe("Snippet ID (for snippet)")
3805
+ resource_type: z13.enum(["merge_request", "issue", "epic", "commit", "snippet"]).describe("Type of GitLab resource"),
3806
+ discussion_id: z13.string().describe("The ID of the discussion thread"),
3807
+ project_id: z13.string().optional().describe("Project ID or path"),
3808
+ group_id: z13.string().optional().describe("Group ID or path (for epic)"),
3809
+ iid: z13.number().optional().describe("Internal ID (for merge_request, issue, epic)"),
3810
+ sha: z13.string().optional().describe("Commit SHA (for commit)"),
3811
+ snippet_id: z13.number().optional().describe("Snippet ID (for snippet)")
3733
3812
  },
3734
3813
  execute: async (args, _ctx) => {
3735
3814
  validateResourceParams(args.resource_type, args);
@@ -3777,27 +3856,29 @@ Required parameters vary by resource type:
3777
3856
  /**
3778
3857
  * Create a new discussion thread or reply to an existing one
3779
3858
  */
3780
- gitlab_create_discussion: tool12({
3859
+ gitlab_create_discussion: tool13({
3781
3860
  description: `Create a new discussion thread or reply to an existing one.
3782
3861
 
3783
- For NEW discussion: Omit discussion_id
3784
- For REPLY to existing thread: Include discussion_id (preferred over gitlab_create_note for threaded conversations)
3862
+ REPLYING TO EXISTING THREADS:
3863
+ To reply to an existing discussion, provide the discussion_id parameter.
3864
+ This is the recommended way to reply in-thread rather than creating a standalone comment.
3785
3865
 
3786
- For code-specific comments on MRs/commits, provide position information.
3866
+ STARTING A NEW DISCUSSION:
3867
+ Omit discussion_id to create a new thread. For code-specific comments on MRs/commits, provide position information.
3787
3868
 
3788
3869
  Examples:
3789
- - New MR comment: resource_type="merge_request", project_id="...", iid=123, body="..."
3790
- - Reply to thread: resource_type="merge_request", ..., discussion_id="...", body="..."
3791
- - Code comment: resource_type="merge_request", ..., body="...", position={base_sha, head_sha, ...}`,
3870
+ - Reply to thread: resource_type="merge_request", project_id="group/project", iid=123, discussion_id="abc123def", body="Thanks for the feedback!"
3871
+ - New comment: resource_type="merge_request", project_id="group/project", iid=123, body="General comment"
3872
+ - Code comment: resource_type="merge_request", project_id="group/project", iid=123, body="...", position={base_sha, head_sha, new_path, new_line, ...}`,
3792
3873
  args: {
3793
- resource_type: z12.enum(["merge_request", "issue", "epic", "commit", "snippet"]).describe("Type of GitLab resource"),
3794
- body: z12.string().describe("The comment text (Markdown supported)"),
3795
- project_id: z12.string().optional().describe("Project ID or path"),
3796
- group_id: z12.string().optional().describe("Group ID or path (for epic)"),
3797
- iid: z12.number().optional().describe("Internal ID (for merge_request, issue, epic)"),
3798
- sha: z12.string().optional().describe("Commit SHA (for commit)"),
3799
- snippet_id: z12.number().optional().describe("Snippet ID (for snippet)"),
3800
- discussion_id: z12.string().optional().describe("If provided, replies to existing discussion. If omitted, creates new thread"),
3874
+ resource_type: z13.enum(["merge_request", "issue", "epic", "commit", "snippet"]).describe("Type of GitLab resource"),
3875
+ body: z13.string().describe("The comment text (Markdown supported)"),
3876
+ project_id: z13.string().optional().describe("Project ID or path"),
3877
+ group_id: z13.string().optional().describe("Group ID or path (for epic)"),
3878
+ iid: z13.number().optional().describe("Internal ID (for merge_request, issue, epic)"),
3879
+ sha: z13.string().optional().describe("Commit SHA (for commit)"),
3880
+ snippet_id: z13.number().optional().describe("Snippet ID (for snippet)"),
3881
+ discussion_id: z13.string().optional().describe("If provided, replies to existing discussion. If omitted, creates new thread"),
3801
3882
  position: positionSchema.optional().describe("Position for code-specific comments (MR/commit only)")
3802
3883
  },
3803
3884
  execute: async (args, _ctx) => {
@@ -3862,7 +3943,7 @@ Examples:
3862
3943
  /**
3863
3944
  * Resolve or unresolve a discussion thread
3864
3945
  */
3865
- gitlab_resolve_discussion: tool12({
3946
+ gitlab_resolve_discussion: tool13({
3866
3947
  description: `Mark a discussion thread as resolved or unresolve it.
3867
3948
  Only works for resolvable discussions (MRs and issues only).
3868
3949
 
@@ -3871,11 +3952,11 @@ Uses GraphQL API which handles all discussion types including outdated discussio
3871
3952
 
3872
3953
  Use after addressing feedback to indicate the discussion is complete.`,
3873
3954
  args: {
3874
- resource_type: z12.enum(["merge_request", "issue"]).describe("Type of resource (only MR and issue discussions can be resolved)"),
3875
- action: z12.enum(["resolve", "unresolve"]).describe("Whether to resolve or unresolve"),
3876
- discussion_id: z12.string().describe("The ID of the discussion thread"),
3877
- project_id: z12.string().describe("Project ID or path"),
3878
- iid: z12.number().describe("Internal ID of the MR or issue")
3955
+ resource_type: z13.enum(["merge_request", "issue"]).describe("Type of resource (only MR and issue discussions can be resolved)"),
3956
+ action: z13.enum(["resolve", "unresolve"]).describe("Whether to resolve or unresolve"),
3957
+ discussion_id: z13.string().describe("The ID of the discussion thread"),
3958
+ project_id: z13.string().describe("Project ID or path"),
3959
+ iid: z13.number().describe("Internal ID of the MR or issue")
3879
3960
  },
3880
3961
  execute: async (args, _ctx) => {
3881
3962
  const client = getGitLabClient();
@@ -3890,8 +3971,8 @@ Use after addressing feedback to indicate the discussion is complete.`,
3890
3971
  };
3891
3972
 
3892
3973
  // src/tools/notes-unified.ts
3893
- import { tool as tool13 } from "@opencode-ai/plugin";
3894
- var z13 = tool13.schema;
3974
+ import { tool as tool14 } from "@opencode-ai/plugin";
3975
+ var z14 = tool14.schema;
3895
3976
  function normalizeBoolean2(value) {
3896
3977
  if (typeof value === "boolean") return value;
3897
3978
  if (value === "true") return true;
@@ -3962,7 +4043,7 @@ var notesUnifiedTools = {
3962
4043
  /**
3963
4044
  * List notes/comments for any GitLab resource type
3964
4045
  */
3965
- gitlab_list_notes: tool13({
4046
+ gitlab_list_notes: tool14({
3966
4047
  description: `List all notes/comments on any GitLab resource using GraphQL API with pagination support.
3967
4048
  Returns all comments including system notes in chronological order.
3968
4049
  This is easier to read than discussions which have nested structure.
@@ -3977,20 +4058,20 @@ Examples:
3977
4058
  - Epic: resource_type="epic", group_id="my-group", iid=1
3978
4059
  - Snippet: resource_type="snippet", project_id="group/project", snippet_id=789`,
3979
4060
  args: {
3980
- resource_type: z13.enum(["merge_request", "issue", "epic", "snippet"]).describe("Type of GitLab resource"),
3981
- project_id: z13.string().optional().describe("Project ID or path. Required for merge_request, issue, snippet"),
3982
- group_id: z13.string().optional().describe("Group ID or path. Required for epic"),
3983
- iid: z13.number().optional().describe("Internal ID of the resource (for merge_request, issue, epic)"),
3984
- snippet_id: z13.number().optional().describe("Snippet ID (required for snippet)"),
4061
+ resource_type: z14.enum(["merge_request", "issue", "epic", "snippet"]).describe("Type of GitLab resource"),
4062
+ project_id: z14.string().optional().describe("Project ID or path. Required for merge_request, issue, snippet"),
4063
+ group_id: z14.string().optional().describe("Group ID or path. Required for epic"),
4064
+ iid: z14.number().optional().describe("Internal ID of the resource (for merge_request, issue, epic)"),
4065
+ snippet_id: z14.number().optional().describe("Snippet ID (required for snippet)"),
3985
4066
  // Filtering
3986
- resolved: z13.boolean().optional().describe(
4067
+ resolved: z14.boolean().optional().describe(
3987
4068
  "Filter by resolved status: true for resolved, false for unresolved. Only returns resolvable notes (excludes system notes). Client-side filtering."
3988
4069
  ),
3989
4070
  // Pagination
3990
- first: z13.number().optional().describe("Number of items to return from the beginning (default: 20, max: 100)"),
3991
- after: z13.string().optional().describe("Cursor for forward pagination - use endCursor from previous response"),
3992
- last: z13.number().optional().describe("Number of items to return from the end (for backward pagination)"),
3993
- before: z13.string().optional().describe("Cursor for backward pagination - use startCursor from previous response")
4071
+ first: z14.number().optional().describe("Number of items to return from the beginning (default: 20, max: 100)"),
4072
+ after: z14.string().optional().describe("Cursor for forward pagination - use endCursor from previous response"),
4073
+ last: z14.number().optional().describe("Number of items to return from the end (for backward pagination)"),
4074
+ before: z14.string().optional().describe("Cursor for backward pagination - use startCursor from previous response")
3994
4075
  },
3995
4076
  execute: async (args, _ctx) => {
3996
4077
  validateListCreateParams(args.resource_type, args);
@@ -4029,7 +4110,7 @@ Examples:
4029
4110
  /**
4030
4111
  * Get a single note/comment by its ID
4031
4112
  */
4032
- gitlab_get_note: tool13({
4113
+ gitlab_get_note: tool14({
4033
4114
  description: `Get a single note/comment from an issue or epic by its ID.
4034
4115
  Returns the full details of a specific note including author, body, timestamps, and metadata.
4035
4116
  Useful when you need to retrieve a specific comment without fetching all notes.
@@ -4040,11 +4121,11 @@ Examples:
4040
4121
  - Issue note: resource_type="issue", project_id="group/project", iid=456, note_id=123
4041
4122
  - Epic note: resource_type="epic", group_id="my-group", iid=1, note_id=456`,
4042
4123
  args: {
4043
- resource_type: z13.enum(["issue", "epic"]).describe("Type of GitLab resource (issue or epic only)"),
4044
- note_id: z13.number().describe("The ID of the note to retrieve"),
4045
- project_id: z13.string().optional().describe("Project ID or path. Required for issue"),
4046
- group_id: z13.string().optional().describe("Group ID or path. Required for epic"),
4047
- iid: z13.number().describe("Internal ID of the issue or epic")
4124
+ resource_type: z14.enum(["issue", "epic"]).describe("Type of GitLab resource (issue or epic only)"),
4125
+ note_id: z14.number().describe("The ID of the note to retrieve"),
4126
+ project_id: z14.string().optional().describe("Project ID or path. Required for issue"),
4127
+ group_id: z14.string().optional().describe("Group ID or path. Required for epic"),
4128
+ iid: z14.number().describe("Internal ID of the issue or epic")
4048
4129
  },
4049
4130
  execute: async (args, _ctx) => {
4050
4131
  validateGetNoteParams(args.resource_type, args);
@@ -4070,7 +4151,7 @@ Examples:
4070
4151
  /**
4071
4152
  * Create a simple note/comment on any GitLab resource
4072
4153
  */
4073
- gitlab_create_note: tool13({
4154
+ gitlab_create_note: tool14({
4074
4155
  description: `Add a simple comment/note to any GitLab resource.
4075
4156
  Creates a standalone comment (not part of a thread).
4076
4157
 
@@ -4083,12 +4164,12 @@ Examples:
4083
4164
  - Epic comment: resource_type="epic", group_id="my-group", iid=1, body="Planning complete"
4084
4165
  - Snippet comment: resource_type="snippet", project_id="group/project", snippet_id=789, body="Nice code!"`,
4085
4166
  args: {
4086
- resource_type: z13.enum(["merge_request", "issue", "epic", "snippet"]).describe("Type of GitLab resource"),
4087
- body: z13.string().describe("The content of the note/comment (supports Markdown)"),
4088
- project_id: z13.string().optional().describe("Project ID or path. Required for merge_request, issue, snippet"),
4089
- group_id: z13.string().optional().describe("Group ID or path. Required for epic"),
4090
- iid: z13.number().optional().describe("Internal ID of the resource (for merge_request, issue, epic)"),
4091
- snippet_id: z13.number().optional().describe("Snippet ID (required for snippet)")
4167
+ resource_type: z14.enum(["merge_request", "issue", "epic", "snippet"]).describe("Type of GitLab resource"),
4168
+ body: z14.string().describe("The content of the note/comment (supports Markdown)"),
4169
+ project_id: z14.string().optional().describe("Project ID or path. Required for merge_request, issue, snippet"),
4170
+ group_id: z14.string().optional().describe("Group ID or path. Required for epic"),
4171
+ iid: z14.number().optional().describe("Internal ID of the resource (for merge_request, issue, epic)"),
4172
+ snippet_id: z14.number().optional().describe("Snippet ID (required for snippet)")
4092
4173
  },
4093
4174
  execute: async (args, _ctx) => {
4094
4175
  validateListCreateParams(args.resource_type, args);
@@ -4126,7 +4207,7 @@ Examples:
4126
4207
  };
4127
4208
 
4128
4209
  // src/tools/git.ts
4129
- import { tool as tool14 } from "@opencode-ai/plugin";
4210
+ import { tool as tool15 } from "@opencode-ai/plugin";
4130
4211
 
4131
4212
  // src/client/git.ts
4132
4213
  import { execFile } from "child_process";
@@ -4295,7 +4376,7 @@ ${stderr}` : stdout;
4295
4376
  };
4296
4377
 
4297
4378
  // src/tools/git.ts
4298
- var z14 = tool14.schema;
4379
+ var z15 = tool15.schema;
4299
4380
  var gitClient = null;
4300
4381
  function getGitClient() {
4301
4382
  if (!gitClient) {
@@ -4304,7 +4385,7 @@ function getGitClient() {
4304
4385
  return gitClient;
4305
4386
  }
4306
4387
  var gitTools = {
4307
- run_git_command: tool14({
4388
+ run_git_command: tool15({
4308
4389
  description: `Execute safe, read-only git commands in the repository working directory.
4309
4390
 
4310
4391
  Security restrictions:
@@ -4346,9 +4427,9 @@ Examples:
4346
4427
  - run_git_command("branch", ["-a"]) - List all branches
4347
4428
  - run_git_command("show", ["HEAD:README.md"]) - Show README.md from HEAD commit`,
4348
4429
  args: {
4349
- command: z14.string().describe('The git command to execute (without "git" prefix)'),
4350
- args: z14.array(z14.string()).optional().describe("Array of arguments for the git command (default: [])"),
4351
- working_directory: z14.string().optional().describe(
4430
+ command: z15.string().describe('The git command to execute (without "git" prefix)'),
4431
+ args: z15.array(z15.string()).optional().describe("Array of arguments for the git command (default: [])"),
4432
+ working_directory: z15.string().optional().describe(
4352
4433
  "Path to the git repository (default: current working directory). Use this to execute git commands in a specific repository."
4353
4434
  )
4354
4435
  },
@@ -4371,22 +4452,22 @@ Examples:
4371
4452
  };
4372
4453
 
4373
4454
  // src/tools/audit.ts
4374
- import { tool as tool15 } from "@opencode-ai/plugin";
4375
- var z15 = tool15.schema;
4455
+ import { tool as tool16 } from "@opencode-ai/plugin";
4456
+ var z16 = tool16.schema;
4376
4457
  var auditTools = {
4377
- gitlab_list_project_audit_events: tool15({
4458
+ gitlab_list_project_audit_events: tool16({
4378
4459
  description: `List audit events for a project.
4379
4460
  Returns audit events including actions like project settings changes, member additions/removals, and other security-relevant activities.
4380
4461
  Note: Requires project owner role or higher.`,
4381
4462
  args: {
4382
- project_id: z15.string().describe("The project ID or URL-encoded path"),
4383
- created_after: z15.string().optional().describe("Return audit events created after this date (ISO 8601 format)"),
4384
- created_before: z15.string().optional().describe("Return audit events created before this date (ISO 8601 format)"),
4385
- entity_type: z15.string().optional().describe('Filter by entity type (e.g., "User", "Project", "Group")'),
4386
- entity_id: z15.number().optional().describe("Filter by entity ID"),
4387
- author_id: z15.number().optional().describe("Filter by author user ID"),
4388
- per_page: z15.number().optional().describe("Number of results per page (default: 20)"),
4389
- page: z15.number().optional().describe("Page number for pagination (default: 1)")
4463
+ project_id: z16.string().describe("The project ID or URL-encoded path"),
4464
+ created_after: z16.string().optional().describe("Return audit events created after this date (ISO 8601 format)"),
4465
+ created_before: z16.string().optional().describe("Return audit events created before this date (ISO 8601 format)"),
4466
+ entity_type: z16.string().optional().describe('Filter by entity type (e.g., "User", "Project", "Group")'),
4467
+ entity_id: z16.number().optional().describe("Filter by entity ID"),
4468
+ author_id: z16.number().optional().describe("Filter by author user ID"),
4469
+ per_page: z16.number().optional().describe("Number of results per page (default: 20)"),
4470
+ page: z16.number().optional().describe("Page number for pagination (default: 1)")
4390
4471
  },
4391
4472
  execute: async (args, _ctx) => {
4392
4473
  const client = getGitLabClient();
@@ -4402,19 +4483,19 @@ Note: Requires project owner role or higher.`,
4402
4483
  return JSON.stringify(events, null, 2);
4403
4484
  }
4404
4485
  }),
4405
- gitlab_list_group_audit_events: tool15({
4486
+ gitlab_list_group_audit_events: tool16({
4406
4487
  description: `List audit events for a group.
4407
4488
  Returns audit events including actions like group settings changes, member additions/removals, subgroup operations, and other security-relevant activities.
4408
4489
  Note: Requires group owner role or higher.`,
4409
4490
  args: {
4410
- group_id: z15.string().describe("The group ID or URL-encoded path"),
4411
- created_after: z15.string().optional().describe("Return audit events created after this date (ISO 8601 format)"),
4412
- created_before: z15.string().optional().describe("Return audit events created before this date (ISO 8601 format)"),
4413
- entity_type: z15.string().optional().describe('Filter by entity type (e.g., "User", "Project", "Group")'),
4414
- entity_id: z15.number().optional().describe("Filter by entity ID"),
4415
- author_id: z15.number().optional().describe("Filter by author user ID"),
4416
- per_page: z15.number().optional().describe("Number of results per page (default: 20)"),
4417
- page: z15.number().optional().describe("Page number for pagination (default: 1)")
4491
+ group_id: z16.string().describe("The group ID or URL-encoded path"),
4492
+ created_after: z16.string().optional().describe("Return audit events created after this date (ISO 8601 format)"),
4493
+ created_before: z16.string().optional().describe("Return audit events created before this date (ISO 8601 format)"),
4494
+ entity_type: z16.string().optional().describe('Filter by entity type (e.g., "User", "Project", "Group")'),
4495
+ entity_id: z16.number().optional().describe("Filter by entity ID"),
4496
+ author_id: z16.number().optional().describe("Filter by author user ID"),
4497
+ per_page: z16.number().optional().describe("Number of results per page (default: 20)"),
4498
+ page: z16.number().optional().describe("Page number for pagination (default: 1)")
4418
4499
  },
4419
4500
  execute: async (args, _ctx) => {
4420
4501
  const client = getGitLabClient();
@@ -4430,18 +4511,18 @@ Note: Requires group owner role or higher.`,
4430
4511
  return JSON.stringify(events, null, 2);
4431
4512
  }
4432
4513
  }),
4433
- gitlab_list_instance_audit_events: tool15({
4514
+ gitlab_list_instance_audit_events: tool16({
4434
4515
  description: `List instance-level audit events.
4435
4516
  Returns audit events for the entire GitLab instance including actions like instance settings changes, user management, license changes, and other system-wide security-relevant activities.
4436
4517
  Note: Requires administrator access.`,
4437
4518
  args: {
4438
- created_after: z15.string().optional().describe("Return audit events created after this date (ISO 8601 format)"),
4439
- created_before: z15.string().optional().describe("Return audit events created before this date (ISO 8601 format)"),
4440
- entity_type: z15.string().optional().describe('Filter by entity type (e.g., "User", "Project", "Group")'),
4441
- entity_id: z15.number().optional().describe("Filter by entity ID"),
4442
- author_id: z15.number().optional().describe("Filter by author user ID"),
4443
- per_page: z15.number().optional().describe("Number of results per page (default: 20)"),
4444
- page: z15.number().optional().describe("Page number for pagination (default: 1)")
4519
+ created_after: z16.string().optional().describe("Return audit events created after this date (ISO 8601 format)"),
4520
+ created_before: z16.string().optional().describe("Return audit events created before this date (ISO 8601 format)"),
4521
+ entity_type: z16.string().optional().describe('Filter by entity type (e.g., "User", "Project", "Group")'),
4522
+ entity_id: z16.number().optional().describe("Filter by entity ID"),
4523
+ author_id: z16.number().optional().describe("Filter by author user ID"),
4524
+ per_page: z16.number().optional().describe("Number of results per page (default: 20)"),
4525
+ page: z16.number().optional().describe("Page number for pagination (default: 1)")
4445
4526
  },
4446
4527
  execute: async (args, _ctx) => {
4447
4528
  const client = getGitLabClient();
@@ -4460,8 +4541,8 @@ Note: Requires administrator access.`,
4460
4541
  };
4461
4542
 
4462
4543
  // src/tools/award-emoji.ts
4463
- import { tool as tool16 } from "@opencode-ai/plugin";
4464
- var z16 = tool16.schema;
4544
+ import { tool as tool17 } from "@opencode-ai/plugin";
4545
+ var z17 = tool17.schema;
4465
4546
  function validateAwardEmojiParams(args) {
4466
4547
  if (!args.project_id) {
4467
4548
  throw new Error("project_id is required");
@@ -4482,7 +4563,7 @@ var awardEmojiTools = {
4482
4563
  /**
4483
4564
  * Add a reaction (award emoji) to a resource or note
4484
4565
  */
4485
- gitlab_create_award_emoji: tool16({
4566
+ gitlab_create_award_emoji: tool17({
4486
4567
  description: `Add a reaction (award emoji) to a merge request, issue, snippet, or a note/comment on these resources.
4487
4568
 
4488
4569
  Common emoji names: thumbsup, thumbsdown, smile, tada, rocket, eyes, heart, +1, -1
@@ -4493,13 +4574,13 @@ Examples:
4493
4574
  - React to MR: resource_type="merge_request", project_id="group/project", resource_iid=123, name="thumbsup"
4494
4575
  - React to issue comment: resource_type="issue", project_id="group/project", resource_iid=456, note_id=789, name="rocket"`,
4495
4576
  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(
4577
+ resource_type: z17.enum(["merge_request", "issue", "snippet"]).describe("Type of resource to add the reaction to"),
4578
+ project_id: z17.string().describe("Project ID or URL-encoded path"),
4579
+ resource_iid: z17.number().describe("Internal ID of the merge request, issue, or snippet"),
4580
+ name: z17.string().describe(
4500
4581
  'Emoji name without colons (e.g., "thumbsup", "rocket", "eyes", "heart", "tada")'
4501
4582
  ),
4502
- note_id: z16.number().optional().describe("Note/comment ID to add the reaction to (if reacting to a specific comment)")
4583
+ note_id: z17.number().optional().describe("Note/comment ID to add the reaction to (if reacting to a specific comment)")
4503
4584
  },
4504
4585
  execute: async (args, _ctx) => {
4505
4586
  validateAwardEmojiParams(args);
@@ -4512,17 +4593,17 @@ Examples:
4512
4593
  /**
4513
4594
  * List all reactions on a resource or note
4514
4595
  */
4515
- gitlab_list_award_emoji: tool16({
4596
+ gitlab_list_award_emoji: tool17({
4516
4597
  description: `List all reactions (award emoji) on a merge request, issue, snippet, or a specific note/comment.
4517
4598
 
4518
4599
  Examples:
4519
4600
  - List reactions on MR: resource_type="merge_request", project_id="group/project", resource_iid=123
4520
4601
  - List reactions on a comment: resource_type="issue", project_id="group/project", resource_iid=456, note_id=789`,
4521
4602
  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)")
4603
+ resource_type: z17.enum(["merge_request", "issue", "snippet"]).describe("Type of resource"),
4604
+ project_id: z17.string().describe("Project ID or URL-encoded path"),
4605
+ resource_iid: z17.number().describe("Internal ID of the merge request, issue, or snippet"),
4606
+ note_id: z17.number().optional().describe("Note/comment ID to list reactions for (if listing for a specific comment)")
4526
4607
  },
4527
4608
  execute: async (args, _ctx) => {
4528
4609
  validateAwardEmojiParams(args);
@@ -4535,7 +4616,7 @@ Examples:
4535
4616
  /**
4536
4617
  * Remove a reaction from a resource or note
4537
4618
  */
4538
- gitlab_delete_award_emoji: tool16({
4619
+ gitlab_delete_award_emoji: tool17({
4539
4620
  description: `Remove a reaction (award emoji) from a merge request, issue, snippet, or note/comment.
4540
4621
 
4541
4622
  You need the award_id which can be found using gitlab_list_award_emoji.
@@ -4544,11 +4625,11 @@ Examples:
4544
4625
  - Remove reaction from MR: resource_type="merge_request", project_id="group/project", resource_iid=123, award_id=456
4545
4626
  - Remove from comment: resource_type="issue", ..., note_id=789, award_id=456`,
4546
4627
  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")
4628
+ resource_type: z17.enum(["merge_request", "issue", "snippet"]).describe("Type of resource"),
4629
+ project_id: z17.string().describe("Project ID or URL-encoded path"),
4630
+ resource_iid: z17.number().describe("Internal ID of the merge request, issue, or snippet"),
4631
+ award_id: z17.number().describe("ID of the award emoji to remove"),
4632
+ note_id: z17.number().optional().describe("Note/comment ID if removing from a specific comment")
4552
4633
  },
4553
4634
  execute: async (args, _ctx) => {
4554
4635
  validateAwardEmojiParams(args);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@gitlab/opencode-gitlab-plugin",
3
- "version": "1.7.0",
3
+ "version": "1.8.0",
4
4
  "description": "GitLab tools plugin for OpenCode - provides GitLab API access for merge requests, issues, pipelines, and more",
5
5
  "type": "module",
6
6
  "main": "dist/index.js",