opencode-gitlab-plugin 2.5.0 → 2.6.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.
@@ -28790,7 +28790,13 @@ var GitLabApiClient = class {
28790
28790
  }
28791
28791
  return projectId;
28792
28792
  }
28793
- async fetch(method, path2, body) {
28793
+ /**
28794
+ * Core HTTP request used by all REST helpers.
28795
+ *
28796
+ * Returns the raw `Response` after validating the status code so callers can
28797
+ * inspect headers (e.g. for pagination) before parsing the body.
28798
+ */
28799
+ async rawFetch(method, path2, body) {
28794
28800
  const url2 = `${this.instanceUrl}/api/v4${path2}`;
28795
28801
  const response = await fetch(url2, {
28796
28802
  method,
@@ -28801,12 +28807,53 @@ var GitLabApiClient = class {
28801
28807
  const errorText = await response.text();
28802
28808
  throw new Error(`GitLab API error ${response.status}: ${errorText}`);
28803
28809
  }
28810
+ return response;
28811
+ }
28812
+ async fetch(method, path2, body) {
28813
+ const response = await this.rawFetch(method, path2, body);
28804
28814
  const text = await response.text();
28805
28815
  if (!text) {
28806
28816
  return {};
28807
28817
  }
28808
28818
  return JSON.parse(text);
28809
28819
  }
28820
+ /**
28821
+ * Parse a numeric pagination header, guarding against empty strings.
28822
+ *
28823
+ * GitLab returns `""` (rather than omitting the header) for `X-Next-Page` and
28824
+ * `X-Prev-Page` when there is no next/prev page, and bare `parseInt` without
28825
+ * a radix on an empty string yields `NaN`. Treat empty/missing as `undefined`.
28826
+ */
28827
+ parsePaginationHeader(response, name) {
28828
+ const raw = response.headers.get(name);
28829
+ if (raw == null || raw === "") return void 0;
28830
+ const value = parseInt(raw, 10);
28831
+ return Number.isNaN(value) ? void 0 : value;
28832
+ }
28833
+ /**
28834
+ * Pagination info extracted from GitLab API response headers
28835
+ */
28836
+ extractPaginationInfo(response) {
28837
+ return {
28838
+ total: this.parsePaginationHeader(response, "X-Total"),
28839
+ totalPages: this.parsePaginationHeader(response, "X-Total-Pages"),
28840
+ page: this.parsePaginationHeader(response, "X-Page"),
28841
+ perPage: this.parsePaginationHeader(response, "X-Per-Page"),
28842
+ nextPage: this.parsePaginationHeader(response, "X-Next-Page"),
28843
+ prevPage: this.parsePaginationHeader(response, "X-Prev-Page")
28844
+ };
28845
+ }
28846
+ /**
28847
+ * Fetch with pagination info from response headers.
28848
+ * Use this for list endpoints where knowing if more data exists is important.
28849
+ */
28850
+ async fetchWithPagination(method, path2, body) {
28851
+ const response = await this.rawFetch(method, path2, body);
28852
+ const text = await response.text();
28853
+ const data = text ? JSON.parse(text) : [];
28854
+ const pagination = this.extractPaginationInfo(response);
28855
+ return { data, pagination };
28856
+ }
28810
28857
  async fetchText(method, path2) {
28811
28858
  const url2 = `${this.instanceUrl}/api/v4${path2}`;
28812
28859
  const response = await fetch(url2, {
@@ -29070,6 +29117,7 @@ var MergeRequestsClient = class extends GitLabApiClient {
29070
29117
  async listMergeRequests(options) {
29071
29118
  const params = new URLSearchParams();
29072
29119
  params.set("per_page", String(options.limit || 20));
29120
+ if (options.page) params.set("page", String(options.page));
29073
29121
  if (options.state) params.set("state", options.state);
29074
29122
  if (options.scope) params.set("scope", options.scope);
29075
29123
  if (options.search) params.set("search", options.search);
@@ -29081,7 +29129,7 @@ var MergeRequestsClient = class extends GitLabApiClient {
29081
29129
  } else {
29082
29130
  path2 = `/merge_requests?${params}`;
29083
29131
  }
29084
- return this.fetch("GET", path2);
29132
+ return this.fetchWithPagination("GET", path2);
29085
29133
  }
29086
29134
  async getMrChanges(projectId, mrIid) {
29087
29135
  const encodedProject = this.encodeProjectId(projectId);
@@ -29493,6 +29541,7 @@ var IssuesClient = class extends GitLabApiClient {
29493
29541
  async listIssues(options) {
29494
29542
  const params = new URLSearchParams();
29495
29543
  params.set("per_page", String(options.limit || 20));
29544
+ if (options.page) params.set("page", String(options.page));
29496
29545
  if (options.state) params.set("state", options.state);
29497
29546
  if (options.scope) params.set("scope", options.scope);
29498
29547
  if (options.search) params.set("search", options.search);
@@ -29505,7 +29554,7 @@ var IssuesClient = class extends GitLabApiClient {
29505
29554
  } else {
29506
29555
  path2 = `/issues?${params}`;
29507
29556
  }
29508
- return this.fetch("GET", path2);
29557
+ return this.fetchWithPagination("GET", path2);
29509
29558
  }
29510
29559
  /**
29511
29560
  * List notes on an issue using GraphQL API with pagination support
@@ -31417,26 +31466,31 @@ Returns: title, description, state, author, assignees, reviewers, labels, diff s
31417
31466
  }),
31418
31467
  gitlab_list_merge_requests: tool({
31419
31468
  description: `List merge requests for a project or search globally.
31420
- Can filter by state (opened, closed, merged, all), scope (assigned_to_me, created_by_me), and labels.`,
31469
+ Can filter by state (opened, closed, merged, all), scope (assigned_to_me, created_by_me), and labels.
31470
+
31471
+ IMPORTANT: Response includes pagination info. If nextPage exists, there are more results.
31472
+ Always paginate until you get an empty response or no nextPage to ensure you have all data.`,
31421
31473
  args: {
31422
31474
  project_id: z.string().optional().describe("The project ID or path. If not provided, searches globally."),
31423
31475
  state: z.enum(["opened", "closed", "merged", "all"]).optional().describe("Filter by MR state (default: opened)"),
31424
31476
  scope: z.enum(["assigned_to_me", "created_by_me", "all"]).optional().describe("Filter by scope"),
31425
31477
  search: z.string().optional().describe("Search MRs by title or description"),
31426
31478
  labels: z.string().optional().describe("Comma-separated list of labels to filter by"),
31427
- limit: z.number().optional().describe("Maximum number of results (default: 20)")
31479
+ limit: z.number().optional().describe("Maximum number of results per page (default: 20)"),
31480
+ page: z.number().optional().describe("Page number for pagination (default: 1)")
31428
31481
  },
31429
31482
  execute: async (args, _ctx) => {
31430
31483
  const client = getGitLabClient();
31431
- const mrs = await client.listMergeRequests({
31484
+ const result = await client.listMergeRequests({
31432
31485
  projectId: args.project_id,
31433
31486
  state: args.state,
31434
31487
  scope: args.scope,
31435
31488
  search: args.search,
31436
31489
  labels: args.labels,
31437
- limit: args.limit
31490
+ limit: args.limit,
31491
+ page: args.page
31438
31492
  });
31439
- return JSON.stringify(mrs, null, 2);
31493
+ return JSON.stringify(result, null, 2);
31440
31494
  }
31441
31495
  }),
31442
31496
  gitlab_get_mr_changes: tool({
@@ -31767,7 +31821,10 @@ Returns: title, description, state, author, assignees, labels, milestone, weight
31767
31821
  }),
31768
31822
  gitlab_list_issues: tool({
31769
31823
  description: `List issues for a project or search globally.
31770
- Can filter by state, labels, assignee, milestone.`,
31824
+ Can filter by state, labels, assignee, milestone.
31825
+
31826
+ IMPORTANT: Response includes pagination info. If nextPage exists, there are more results.
31827
+ Always paginate until you get an empty response or no nextPage to ensure you have all data.`,
31771
31828
  args: {
31772
31829
  project_id: z2.string().optional().describe("The project ID or path. If not provided, searches globally."),
31773
31830
  state: z2.enum(["opened", "closed", "all"]).optional().describe("Filter by issue state (default: opened)"),
@@ -31775,20 +31832,22 @@ Can filter by state, labels, assignee, milestone.`,
31775
31832
  search: z2.string().optional().describe("Search issues by title or description"),
31776
31833
  labels: z2.string().optional().describe("Comma-separated list of labels to filter by"),
31777
31834
  milestone: z2.string().optional().describe("Filter by milestone title"),
31778
- limit: z2.number().optional().describe("Maximum number of results (default: 20)")
31835
+ limit: z2.number().optional().describe("Maximum number of results per page (default: 20)"),
31836
+ page: z2.number().optional().describe("Page number for pagination (default: 1)")
31779
31837
  },
31780
31838
  execute: async (args, _ctx) => {
31781
31839
  const client = getGitLabClient();
31782
- const issues = await client.listIssues({
31840
+ const result = await client.listIssues({
31783
31841
  projectId: args.project_id,
31784
31842
  state: args.state,
31785
31843
  scope: args.scope,
31786
31844
  search: args.search,
31787
31845
  labels: args.labels,
31788
31846
  milestone: args.milestone,
31789
- limit: args.limit
31847
+ limit: args.limit,
31848
+ page: args.page
31790
31849
  });
31791
- return JSON.stringify(issues, null, 2);
31850
+ return JSON.stringify(result, null, 2);
31792
31851
  }
31793
31852
  })
31794
31853
  };
@@ -34016,7 +34075,7 @@ async function main() {
34016
34075
  ...auditTools,
34017
34076
  ...awardEmojiTools
34018
34077
  };
34019
- const version2 = true ? "2.5.0" : "0.0.0";
34078
+ const version2 = true ? "2.6.0" : "0.0.0";
34020
34079
  const server = new McpServer({ name: "gitlab", version: version2 });
34021
34080
  adaptToolsToMcp(server, allTools);
34022
34081
  const transport = new StdioServerTransport();