@gitlab/opencode-gitlab-plugin 1.5.6 → 1.5.7

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,13 @@
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.7](https://gitlab.com/gitlab-org/editor-extensions/opencode-gitlab-plugin/compare/v1.5.6...v1.5.7) (2026-02-03)
6
+
7
+
8
+ ### ♻️ Code Refactoring
9
+
10
+ * consolidate epic issue management tools into unified interface ([b8708d7](https://gitlab.com/gitlab-org/editor-extensions/opencode-gitlab-plugin/commit/b8708d7fa65e4fcc5fda0e46daaf2391d8bbc094))
11
+
5
12
  ## [1.5.6](https://gitlab.com/gitlab-org/editor-extensions/opencode-gitlab-plugin/compare/v1.5.5...v1.5.6) (2026-02-03)
6
13
 
7
14
 
package/README.md CHANGED
@@ -287,7 +287,7 @@ Or for API tokens:
287
287
 
288
288
  ## 🛠️ Available Tools
289
289
 
290
- The plugin provides **69 tools** organized into the following categories:
290
+ The plugin provides **67 tools** organized into the following categories:
291
291
 
292
292
  ### Merge Request Tools (9 tools)
293
293
 
@@ -311,17 +311,15 @@ The plugin provides **69 tools** organized into the following categories:
311
311
  | `gitlab_get_issue` | Get issue details including state, author, assignees, labels, and comments |
312
312
  | `gitlab_list_issues` | List issues with filtering by state, labels, assignee, and milestone |
313
313
 
314
- ### Epic Tools (7 tools)
315
-
316
- | Tool | Description |
317
- | ------------------------------- | ----------------------------------------------------------------------------- |
318
- | `gitlab_get_epic` | Get epic details with title, description, state, dates, and associated issues |
319
- | `gitlab_list_epics` | List epics with filtering by state, author, and labels |
320
- | `gitlab_create_epic` | Create a new epic in a group |
321
- | `gitlab_update_epic` | Update epic title, description, labels, dates, and state |
322
- | `gitlab_list_epic_issues` | Get all issues linked to an epic |
323
- | `gitlab_add_issue_to_epic` | Link an issue to an epic |
324
- | `gitlab_remove_issue_from_epic` | Unlink an issue from an epic |
314
+ ### Epic Tools (5 tools)
315
+
316
+ | Tool | Description |
317
+ | --------------------------- | ----------------------------------------------------------------------------- |
318
+ | `gitlab_get_epic` | Get epic details with title, description, state, dates, and associated issues |
319
+ | `gitlab_list_epics` | List epics with filtering by state, author, and labels |
320
+ | `gitlab_create_epic` | Create a new epic in a group |
321
+ | `gitlab_update_epic` | Update epic title, description, labels, dates, and state |
322
+ | `gitlab_manage_epic_issues` | Manage issues linked to an epic (list, add, remove) with action parameter |
325
323
 
326
324
  ### Pipeline Tools (8 tools)
327
325
 
package/dist/index.js CHANGED
@@ -2309,6 +2309,9 @@ Can filter by state, labels, assignee, milestone.`,
2309
2309
  // src/tools/epics.ts
2310
2310
  import { tool as tool3 } from "@opencode-ai/plugin";
2311
2311
  var z3 = tool3.schema;
2312
+ function validationError(message) {
2313
+ return JSON.stringify({ error: message }, null, 2);
2314
+ }
2312
2315
  var epicTools = {
2313
2316
  gitlab_get_epic: tool3({
2314
2317
  description: `Get details of a specific epic by group and epic IID.
@@ -2402,49 +2405,55 @@ Can update title, description, labels, dates, state, and confidentiality.`,
2402
2405
  return JSON.stringify(epic, null, 2);
2403
2406
  }
2404
2407
  }),
2405
- gitlab_list_epic_issues: tool3({
2406
- description: `Get all issues associated with an epic.
2407
- Returns the list of issues that are linked to the epic.`,
2408
- args: {
2409
- group_id: z3.string().describe("The group ID or URL-encoded path"),
2410
- epic_iid: z3.number().describe("The internal ID of the epic")
2411
- },
2412
- execute: async (args, _ctx) => {
2413
- const client = getGitLabClient();
2414
- const issues = await client.listEpicIssues(args.group_id, args.epic_iid);
2415
- return JSON.stringify(issues, null, 2);
2416
- }
2417
- }),
2418
- gitlab_add_issue_to_epic: tool3({
2419
- description: `Link an existing issue to an epic.
2420
- The issue can be from any project within the group hierarchy.`,
2421
- args: {
2422
- group_id: z3.string().describe("The group ID or URL-encoded path"),
2423
- epic_iid: z3.number().describe("The internal ID of the epic"),
2424
- issue_id: z3.number().describe("The global ID of the issue to add")
2425
- },
2426
- execute: async (args, _ctx) => {
2427
- const client = getGitLabClient();
2428
- const result = await client.addIssueToEpic(args.group_id, args.epic_iid, args.issue_id);
2429
- return JSON.stringify(result, null, 2);
2430
- }
2431
- }),
2432
- gitlab_remove_issue_from_epic: tool3({
2433
- description: `Unlink an issue from an epic.
2434
- Removes the association between the issue and the epic.`,
2408
+ gitlab_manage_epic_issues: tool3({
2409
+ description: `Manage issues linked to a GitLab epic.
2410
+
2411
+ Actions:
2412
+ - list: Get all issues associated with the epic
2413
+ - add: Link an existing issue to the epic (issue can be from any project within the group hierarchy)
2414
+ - remove: Unlink an issue from the epic
2415
+
2416
+ Examples:
2417
+ - List issues: action="list", group_id="gitlab-org", epic_iid=123
2418
+ - Add issue: action="add", group_id="gitlab-org", epic_iid=123, issue_id=456
2419
+ - Remove issue: action="remove", group_id="gitlab-org", epic_iid=123, epic_issue_id=789
2420
+
2421
+ Note: The epic_issue_id (for remove) is the ID of the epic-issue association, which can be obtained from the list action response.`,
2435
2422
  args: {
2423
+ action: z3.enum(["list", "add", "remove"]).describe("The action to perform"),
2436
2424
  group_id: z3.string().describe("The group ID or URL-encoded path"),
2437
- epic_iid: z3.number().describe("The internal ID of the epic"),
2438
- epic_issue_id: z3.number().describe("The ID of the epic-issue association (from list_epic_issues)")
2425
+ epic_iid: z3.number().describe("The internal ID of the epic within the group"),
2426
+ issue_id: z3.number().optional().describe('The global ID of the issue to add (required for "add" action)'),
2427
+ epic_issue_id: z3.number().optional().describe(
2428
+ 'The ID of the epic-issue association to remove (required for "remove" action, from list response)'
2429
+ )
2439
2430
  },
2440
2431
  execute: async (args, _ctx) => {
2441
2432
  const client = getGitLabClient();
2442
- const result = await client.removeIssueFromEpic(
2443
- args.group_id,
2444
- args.epic_iid,
2445
- args.epic_issue_id
2446
- );
2447
- return JSON.stringify(result, null, 2);
2433
+ switch (args.action) {
2434
+ case "list": {
2435
+ const issues = await client.listEpicIssues(args.group_id, args.epic_iid);
2436
+ return JSON.stringify(issues, null, 2);
2437
+ }
2438
+ case "add": {
2439
+ if (args.issue_id === void 0) {
2440
+ return validationError('issue_id is required for "add" action');
2441
+ }
2442
+ const result = await client.addIssueToEpic(args.group_id, args.epic_iid, args.issue_id);
2443
+ return JSON.stringify(result, null, 2);
2444
+ }
2445
+ case "remove": {
2446
+ if (args.epic_issue_id === void 0) {
2447
+ return validationError('epic_issue_id is required for "remove" action');
2448
+ }
2449
+ const result = await client.removeIssueFromEpic(
2450
+ args.group_id,
2451
+ args.epic_iid,
2452
+ args.epic_issue_id
2453
+ );
2454
+ return JSON.stringify(result, null, 2);
2455
+ }
2456
+ }
2448
2457
  }
2449
2458
  })
2450
2459
  };
@@ -2746,7 +2755,7 @@ var SPECIALIZED_SCOPES = [
2746
2755
  var ALL_SCOPES = [...GENERIC_SEARCH_SCOPES, ...SPECIALIZED_SCOPES];
2747
2756
  var REF_SUPPORTED_SCOPES = ["commits", "wiki_blobs"];
2748
2757
  var STATE_SUPPORTED_SCOPES = ["milestones"];
2749
- function validationError(param, scope) {
2758
+ function validationError2(param, scope) {
2750
2759
  return new Error(`Missing required parameter: '${param}' is required for scope '${scope}'`);
2751
2760
  }
2752
2761
  function invalidParamError(param, validScopes) {
@@ -2757,10 +2766,10 @@ function invalidParamError(param, validScopes) {
2757
2766
  function validateSearchParams(scope, args) {
2758
2767
  switch (scope) {
2759
2768
  case "notes":
2760
- if (!args.project_id) throw validationError("project_id", scope);
2769
+ if (!args.project_id) throw validationError2("project_id", scope);
2761
2770
  break;
2762
2771
  case "group_projects":
2763
- if (!args.group_id) throw validationError("group_id", scope);
2772
+ if (!args.group_id) throw validationError2("group_id", scope);
2764
2773
  break;
2765
2774
  }
2766
2775
  if (args.ref && !REF_SUPPORTED_SCOPES.includes(scope)) {
@@ -3696,7 +3705,7 @@ import { tool as tool13 } from "@opencode-ai/plugin";
3696
3705
  var z13 = tool13.schema;
3697
3706
  var VALID_LIST_CREATE_TYPES = ["merge_request", "issue", "epic", "snippet"];
3698
3707
  var VALID_GET_NOTE_TYPES = ["issue", "epic"];
3699
- function validationError2(param, resourceType) {
3708
+ function validationError3(param, resourceType) {
3700
3709
  return new Error(
3701
3710
  `Missing required parameter: '${param}' is required for resource_type '${resourceType}'`
3702
3711
  );
@@ -3710,16 +3719,16 @@ function validateListCreateParams(resourceType, args) {
3710
3719
  switch (resourceType) {
3711
3720
  case "merge_request":
3712
3721
  case "issue":
3713
- if (!args.project_id) throw validationError2("project_id", resourceType);
3714
- if (args.iid == null) throw validationError2("iid", resourceType);
3722
+ if (!args.project_id) throw validationError3("project_id", resourceType);
3723
+ if (args.iid == null) throw validationError3("iid", resourceType);
3715
3724
  break;
3716
3725
  case "epic":
3717
- if (!args.group_id) throw validationError2("group_id", resourceType);
3718
- if (args.iid == null) throw validationError2("iid", resourceType);
3726
+ if (!args.group_id) throw validationError3("group_id", resourceType);
3727
+ if (args.iid == null) throw validationError3("iid", resourceType);
3719
3728
  break;
3720
3729
  case "snippet":
3721
- if (!args.project_id) throw validationError2("project_id", resourceType);
3722
- if (args.snippet_id == null) throw validationError2("snippet_id", resourceType);
3730
+ if (!args.project_id) throw validationError3("project_id", resourceType);
3731
+ if (args.snippet_id == null) throw validationError3("snippet_id", resourceType);
3723
3732
  break;
3724
3733
  }
3725
3734
  }
@@ -3729,15 +3738,15 @@ function validateGetNoteParams(resourceType, args) {
3729
3738
  `Invalid resource_type '${resourceType}'. Must be one of: ${VALID_GET_NOTE_TYPES.join(", ")}`
3730
3739
  );
3731
3740
  }
3732
- if (args.note_id == null) throw validationError2("note_id", resourceType);
3741
+ if (args.note_id == null) throw validationError3("note_id", resourceType);
3733
3742
  switch (resourceType) {
3734
3743
  case "issue":
3735
- if (!args.project_id) throw validationError2("project_id", resourceType);
3736
- if (args.iid == null) throw validationError2("iid", resourceType);
3744
+ if (!args.project_id) throw validationError3("project_id", resourceType);
3745
+ if (args.iid == null) throw validationError3("iid", resourceType);
3737
3746
  break;
3738
3747
  case "epic":
3739
- if (!args.group_id) throw validationError2("group_id", resourceType);
3740
- if (args.iid == null) throw validationError2("iid", resourceType);
3748
+ if (!args.group_id) throw validationError3("group_id", resourceType);
3749
+ if (args.iid == null) throw validationError3("iid", resourceType);
3741
3750
  break;
3742
3751
  }
3743
3752
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@gitlab/opencode-gitlab-plugin",
3
- "version": "1.5.6",
3
+ "version": "1.5.7",
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",