opencode-gitlab-plugin 2.0.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/README.md ADDED
@@ -0,0 +1,1280 @@
1
+ # OpenCode GitLab Plugin
2
+
3
+ [![GitLab CI](https://gitlab.com/vglafirov/opencode-gitlab-plugin/badges/main/pipeline.svg)](https://gitlab.com/vglafirov/opencode-gitlab-plugin/-/pipelines)
4
+ [![npm version](https://img.shields.io/npm/v/opencode-gitlab-plugin.svg)](https://www.npmjs.com/package/opencode-gitlab-plugin)
5
+ [![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT)
6
+
7
+ A comprehensive GitLab API plugin for OpenCode that provides AI-powered access to GitLab's REST and GraphQL APIs. This plugin enables seamless interaction with merge requests, issues, pipelines, repositories, epics, snippets, audit events, and more through natural language commands.
8
+
9
+ ## 📋 Table of Contents
10
+
11
+ - [Features](#-features)
12
+ - [Architecture](#-architecture)
13
+ - [Installation](#-installation)
14
+ - [Configuration](#-configuration)
15
+ - [Available Tools](#-available-tools)
16
+ - [Usage Examples](#-usage-examples)
17
+ - [Development](#-development)
18
+ - [CI/CD Pipeline](#-cicd-pipeline)
19
+ - [API Reference](#-api-reference)
20
+ - [Contributing](#-contributing)
21
+ - [License](#-license)
22
+
23
+ ## ✨ Features
24
+
25
+ ### Core Capabilities
26
+
27
+ - **🔀 Merge Requests**: Full CRUD operations, discussions, notes, changes, commits, and pipelines
28
+ - **📝 Issues**: Create, read, update, and comment on issues with advanced filtering
29
+ - **🎯 Work Items**: Unified interface for issues, epics, tasks, and other work tracking items
30
+ - **🚀 CI/CD Pipelines**: Monitor, analyze, retry pipeline jobs, and validate CI/CD configurations
31
+ - **📦 Repository Operations**: File management, commits, branches, tree navigation, and commit discussions
32
+ - **🔍 Advanced Search**: Multi-scope search across projects, code, issues, merge requests, commits, users, milestones, and documentation
33
+ - **📊 Epics**: Enterprise-level epic management with issue associations
34
+ - **💬 Snippets**: Snippet discussions, notes, and comments management
35
+ - **🔗 Universal Discussions**: Unified interface for discussions across all GitLab resources
36
+ - **✅ TODOs**: Personal task management and notifications
37
+ - **🔒 Security**: Vulnerability scanning and security report access
38
+ - **📚 Wiki**: Wiki page content retrieval
39
+ - **🔍 Audit Events**: Track project, group, and instance-level security events
40
+ - **🔧 Git Commands**: Execute safe, read-only git operations
41
+ - **👥 Project Management**: Member management and project details
42
+
43
+ ### Technical Features
44
+
45
+ - **TypeScript**: Full type safety with comprehensive type definitions
46
+ - **ESM Support**: Modern ES modules for optimal tree-shaking
47
+ - **Zod Validation**: Runtime schema validation for all API inputs
48
+ - **GraphQL Support**: Native GraphQL API support with type-safe mutations and queries for TODOs, Notes, Discussions, Auto-merge, and Security tools
49
+ - **Cursor-Based Pagination**: GraphQL-powered pagination with `first`/`after` and `last`/`before` cursors for efficient data fetching
50
+ - **GID Validation**: Automatic validation of GitLab Global IDs with descriptive error messages
51
+ - **Error Handling**: Robust error handling with detailed error messages
52
+ - **Authentication**: Multiple authentication methods (OAuth, API tokens)
53
+ - **Rate Limiting**: Built-in handling for GitLab API rate limits
54
+ - **Caching**: Efficient API response handling
55
+ - **Modular Architecture**: Clean separation of concerns with client and tool modules
56
+ - **Comprehensive Testing**: 180 tests with full coverage of all features
57
+
58
+ ### GraphQL-Powered Tools
59
+
60
+ The following tools use GitLab's GraphQL API for enhanced functionality:
61
+
62
+ | Category | Tools | Benefits |
63
+ | --------------- | ----------------------------------------------------------------------------------------------------------- | ---------------------------------------------------------------------------------------- |
64
+ | **TODOs** | `gitlab_list_todos`, `gitlab_get_todo_count` | Cursor-based pagination, rich filtering |
65
+ | **Notes** | `gitlab_list_notes`, `gitlab_get_note`, `gitlab_create_note` | Unified interface for all resource types, efficient pagination |
66
+ | **Discussions** | `gitlab_list_discussions`, `gitlab_get_discussion`, `gitlab_create_discussion`, `gitlab_resolve_discussion` | Unified interface for all resource types, cursor-based pagination, code position support |
67
+ | **Auto-merge** | `gitlab_set_mr_auto_merge` | MWPS (Merge When Pipeline Succeeds), merge train support |
68
+ | **Security** | All vulnerability management tools | Type-safe GID validation, mutation support |
69
+
70
+ ## 🏗️ Architecture
71
+
72
+ ### System Architecture
73
+
74
+ ```mermaid
75
+ graph TB
76
+ subgraph "OpenCode Environment"
77
+ AI[AI Assistant]
78
+ Plugin[GitLab Plugin]
79
+ end
80
+
81
+ subgraph "Plugin Components"
82
+ Tools[Tool Definitions]
83
+ Client[GitLab API Client]
84
+ Auth[Authentication Manager]
85
+ Validator[Zod Schema Validator]
86
+ end
87
+
88
+ subgraph "GitLab API"
89
+ REST[REST API v4]
90
+ GraphQL[GraphQL API]
91
+ MR[Merge Requests]
92
+ Issues[Issues]
93
+ Pipelines[Pipelines]
94
+ Repos[Repositories]
95
+ Epics[Epics]
96
+ Security[Security]
97
+ end
98
+
99
+ AI -->|Natural Language| Plugin
100
+ Plugin --> Tools
101
+ Tools --> Validator
102
+ Validator --> Client
103
+ Client --> Auth
104
+ Auth --> REST
105
+ Auth --> GraphQL
106
+ REST --> MR
107
+ REST --> Issues
108
+ REST --> Pipelines
109
+ REST --> Repos
110
+ REST --> Epics
111
+ GraphQL --> Security
112
+ GraphQL --> MR
113
+ ```
114
+
115
+ ### Plugin Structure
116
+
117
+ ```mermaid
118
+ graph LR
119
+ subgraph "src/index.ts"
120
+ A[GitLabApiClient Class]
121
+ B[Authentication Functions]
122
+ C[Tool Definitions]
123
+ D[Plugin Export]
124
+ end
125
+
126
+ A --> A1[HTTP Methods]
127
+ A --> A2[Merge Request APIs]
128
+ A --> A3[Issue APIs]
129
+ A --> A4[Pipeline APIs]
130
+ A --> A5[Repository APIs]
131
+ A --> A6[Epic APIs]
132
+ A --> A7[Search APIs]
133
+
134
+ B --> B1[readTokenFromAuthStorage]
135
+ B --> B2[getGitLabClient]
136
+
137
+ C --> C1[69 Tool Definitions]
138
+
139
+ D --> A
140
+ D --> B
141
+ D --> C
142
+ ```
143
+
144
+ ### Authentication Flow
145
+
146
+ ```mermaid
147
+ sequenceDiagram
148
+ participant User
149
+ participant Plugin
150
+ participant AuthManager
151
+ participant Storage
152
+ participant GitLab
153
+
154
+ User->>Plugin: Initialize Plugin
155
+ Plugin->>AuthManager: getGitLabClient()
156
+ AuthManager->>AuthManager: Check GITLAB_TOKEN env
157
+ alt Token in Environment
158
+ AuthManager->>GitLab: Use env token
159
+ else No env token
160
+ AuthManager->>Storage: Read ~/.local/share/opencode/auth.json
161
+ Storage->>AuthManager: Return token
162
+ AuthManager->>GitLab: Use stored token
163
+ end
164
+ GitLab->>Plugin: API Response
165
+ Plugin->>User: Tool Result
166
+ ```
167
+
168
+ ## 📦 Installation
169
+
170
+ ### Prerequisites
171
+
172
+ - Node.js >= 18.0.0
173
+ - npm >= 9.0.0 or Bun
174
+ - GitLab account with API access
175
+ - GitLab Personal Access Token or OAuth token
176
+
177
+ ### Install from npm
178
+
179
+ ```bash
180
+ # Install the package
181
+ npm install opencode-gitlab-plugin
182
+
183
+ # Or with Bun
184
+ bun add opencode-gitlab-plugin
185
+
186
+ # Or with yarn
187
+ yarn add opencode-gitlab-plugin
188
+ ```
189
+
190
+ ### Install from GitLab Repository (Development)
191
+
192
+ ```bash
193
+ # Using npm
194
+ npm install git+https://gitlab.com/vglafirov/opencode-gitlab-plugin.git
195
+
196
+ # Using Bun
197
+ bun add git+https://gitlab.com/vglafirov/opencode-gitlab-plugin.git
198
+ ```
199
+
200
+ ### Install Specific Version
201
+
202
+ ```bash
203
+ # Install specific version from npm
204
+ npm install opencode-gitlab-plugin@1.0.0
205
+
206
+ # Install from specific git tag
207
+ npm install git+https://gitlab.com/vglafirov/opencode-gitlab-plugin.git#v1.0.0
208
+
209
+ # Install from specific branch
210
+ npm install git+https://gitlab.com/vglafirov/opencode-gitlab-plugin.git#main
211
+ ```
212
+
213
+ ### Using package.json
214
+
215
+ Add to your `package.json`:
216
+
217
+ ```json
218
+ {
219
+ "dependencies": {
220
+ "opencode-gitlab-plugin": "^1.0.0"
221
+ }
222
+ }
223
+ ```
224
+
225
+ Then run:
226
+
227
+ ```bash
228
+ npm install
229
+ ```
230
+
231
+ ## ⚙️ Configuration
232
+
233
+ ### Environment Variables
234
+
235
+ ```bash
236
+ # Required: GitLab API Token
237
+ export GITLAB_TOKEN=glpat-xxxxxxxxxxxxxxxxxxxx
238
+
239
+ # Optional: Custom GitLab Instance (defaults to https://gitlab.com)
240
+ export GITLAB_INSTANCE_URL=https://gitlab.example.com
241
+ ```
242
+
243
+ ### OpenCode Configuration
244
+
245
+ Add the following plugin to your opencode configuration `~/.config/opencode/opencode.json`:
246
+
247
+ ```json
248
+ {
249
+ "$schema": "https://opencode.ai/config.json",
250
+ "plugin": ["opencode-gitlab-plugin"]
251
+ }
252
+ ```
253
+
254
+ ### Authentication Storage
255
+
256
+ The plugin supports reading tokens from OpenCode's auth storage:
257
+
258
+ **Location**: `~/.local/share/opencode/auth.json`
259
+
260
+ **Format**:
261
+
262
+ ```json
263
+ {
264
+ "gitlab": {
265
+ "type": "oauth",
266
+ "access": "your-oauth-token"
267
+ }
268
+ }
269
+ ```
270
+
271
+ Or for API tokens:
272
+
273
+ ```json
274
+ {
275
+ "gitlab": {
276
+ "type": "api",
277
+ "key": "glpat-xxxxxxxxxxxxxxxxxxxx"
278
+ }
279
+ }
280
+ ```
281
+
282
+ ### Token Priority
283
+
284
+ 1. `GITLAB_TOKEN` environment variable (highest priority)
285
+ 2. OpenCode auth storage (`~/.local/share/opencode/auth.json`)
286
+ 3. Error if no token found
287
+
288
+ ## 🛠️ Available Tools
289
+
290
+ The plugin provides **64 tools** organized into the following categories:
291
+
292
+ ### Merge Request Tools (8 tools)
293
+
294
+ | Tool | Description |
295
+ | --------------------------------- | ---------------------------------------------------------------------------------------------------------------------------- |
296
+ | `gitlab_get_merge_request` | Get details of a specific merge request with title, description, state, author, assignees, reviewers, labels, and diff stats |
297
+ | `gitlab_list_merge_requests` | List merge requests with filtering by state, scope, and labels |
298
+ | `gitlab_create_merge_request` | Create a new merge request |
299
+ | `gitlab_update_merge_request` | Update merge request title, description, state, assignees, reviewers, and labels |
300
+ | `gitlab_get_mr_changes` | Get file changes/diffs for a merge request |
301
+ | `gitlab_get_mr_details` | Get additional MR details (commits or pipelines) with detail_type parameter |
302
+ | `gitlab_list_merge_request_diffs` | List file diffs with pagination support for large changesets |
303
+ | `gitlab_set_mr_auto_merge` | Enable auto-merge (MWPS) using GraphQL API when pipeline succeeds |
304
+
305
+ ### Issue Tools (3 tools)
306
+
307
+ | Tool | Description |
308
+ | --------------------- | ---------------------------------------------------------------------------- |
309
+ | `gitlab_create_issue` | Create a new issue with title, description, labels, assignees, and milestone |
310
+ | `gitlab_get_issue` | Get issue details including state, author, assignees, labels, and comments |
311
+ | `gitlab_list_issues` | List issues with filtering by state, labels, assignee, and milestone |
312
+
313
+ ### Epic Tools (5 tools)
314
+
315
+ | Tool | Description |
316
+ | --------------------------- | ----------------------------------------------------------------------------- |
317
+ | `gitlab_get_epic` | Get epic details with title, description, state, dates, and associated issues |
318
+ | `gitlab_list_epics` | List epics with filtering by state, author, and labels |
319
+ | `gitlab_create_epic` | Create a new epic in a group |
320
+ | `gitlab_update_epic` | Update epic title, description, labels, dates, and state |
321
+ | `gitlab_manage_epic_issues` | Manage issues linked to an epic (list, add, remove) with action parameter |
322
+
323
+ ### Pipeline Tools (7 tools)
324
+
325
+ | Tool | Description |
326
+ | ---------------------------------- | ------------------------------------------------------------------------------- |
327
+ | `gitlab_list_pipelines` | List pipelines with filtering by status, ref, and username |
328
+ | `gitlab_get_pipeline` | Get pipeline details with jobs and status |
329
+ | `gitlab_list_pipeline_jobs` | List all jobs in a pipeline with optional scope filtering |
330
+ | `gitlab_get_job_log` | Get the log output of a specific CI job |
331
+ | `gitlab_retry_job` | Retry a failed or canceled job |
332
+ | `gitlab_get_pipeline_failing_jobs` | Get only failed jobs for easier debugging |
333
+ | `gitlab_lint_ci_config` | Validate CI/CD YAML config with mode parameter (content or existing repository) |
334
+
335
+ ### Repository Tools (7 tools)
336
+
337
+ | Tool | Description |
338
+ | ----------------------------- | ------------------------------------------------------ |
339
+ | `gitlab_get_file` | Get file contents from any branch, tag, or commit |
340
+ | `gitlab_get_commit` | Get commit details with metadata, author, and stats |
341
+ | `gitlab_list_commits` | List commits with filtering by branch, path, and dates |
342
+ | `gitlab_get_commit_diff` | Get diff for a specific commit |
343
+ | `gitlab_list_repository_tree` | List files and directories at a given path |
344
+ | `gitlab_list_branches` | List all branches in a repository |
345
+ | `gitlab_get_commit_comments` | Get all commit comments in flat structure |
346
+
347
+ ### Search Tools (2 tools)
348
+
349
+ | Tool | Description |
350
+ | ----------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
351
+ | `gitlab_search` | Unified search across all GitLab resources with scope-specific options (projects, issues, merge_requests, milestones, users, blobs, commits, notes, wiki_blobs, group_projects) |
352
+ | `gitlab_documentation_search` | Search GitLab official documentation at docs.gitlab.com |
353
+
354
+ ### Work Item Tools (6 tools)
355
+
356
+ | Tool | Description |
357
+ | ------------------------------ | -------------------------------------------------------- |
358
+ | `gitlab_get_work_item` | Get a work item (unified model for issues, epics, tasks) |
359
+ | `gitlab_list_work_items` | List work items in a project or group |
360
+ | `gitlab_get_work_item_notes` | Get all comments for a work item |
361
+ | `gitlab_create_work_item` | Create a new work item |
362
+ | `gitlab_update_work_item` | Update work item title, description, state, and labels |
363
+ | `gitlab_create_work_item_note` | Add a comment to a work item |
364
+
365
+ ### Security Tools (8 tools)
366
+
367
+ | Tool | Description |
368
+ | ----------------------------------------- | ------------------------------------------------------------------------- |
369
+ | `gitlab_list_vulnerabilities` | List security vulnerabilities with filtering by state, severity, and type |
370
+ | `gitlab_get_vulnerability_details` | Get detailed vulnerability information with remediation |
371
+ | `gitlab_create_vulnerability_issue` | Create an issue linked to vulnerabilities (GraphQL) |
372
+ | `gitlab_dismiss_vulnerability` | Dismiss vulnerability with reason (GraphQL) |
373
+ | `gitlab_confirm_vulnerability` | Confirm a vulnerability as valid (GraphQL) |
374
+ | `gitlab_revert_vulnerability_to_detected` | Revert vulnerability state (GraphQL) |
375
+ | `gitlab_update_vulnerability_severity` | Update vulnerability severity level (GraphQL) |
376
+ | `gitlab_link_vulnerability_to_issue` | Link vulnerabilities to existing issue (GraphQL) |
377
+
378
+ **Note**: All GraphQL-based security tools include automatic GID (Global ID) format validation.
379
+
380
+ ### TODO Tools (3 tools)
381
+
382
+ | Tool | Description |
383
+ | ----------------------- | ------------------------------------------------------ |
384
+ | `gitlab_list_todos` | List TODO items with cursor-based pagination (GraphQL) |
385
+ | `gitlab_mark_todo_done` | Mark TODOs as done with action parameter (one or all) |
386
+ | `gitlab_get_todo_count` | Get count of pending TODOs (GraphQL) |
387
+
388
+ ### Project & User Tools (3 tools)
389
+
390
+ | Tool | Description |
391
+ | ----------------------------- | ---------------------------------- |
392
+ | `gitlab_get_project` | Get project details and metadata |
393
+ | `gitlab_list_project_members` | List all members of a project |
394
+ | `gitlab_get_current_user` | Get authenticated user information |
395
+
396
+ ### Discussion Tools (4 tools)
397
+
398
+ | Tool | Description |
399
+ | --------------------------- | ------------------------------------------------------------------------------------------------------------------------ |
400
+ | `gitlab_list_discussions` | List discussions (comment threads) on any GitLab resource (MRs, issues, epics, commits, snippets) with cursor pagination |
401
+ | `gitlab_get_discussion` | Get a specific discussion thread with all replies from any resource type |
402
+ | `gitlab_create_discussion` | Create a new discussion thread OR reply to an existing one (supports code-position comments for MRs and commits) |
403
+ | `gitlab_resolve_discussion` | Mark a discussion thread as resolved or unresolve it (MRs and issues only) |
404
+
405
+ ### Notes Tools (3 tools)
406
+
407
+ | Tool | Description |
408
+ | -------------------- | --------------------------------------------------------------------------------------------------- |
409
+ | `gitlab_list_notes` | List all notes/comments on any resource (MRs, issues, epics, snippets) with cursor-based pagination |
410
+ | `gitlab_get_note` | Get a single note by ID (issues and epics only) |
411
+ | `gitlab_create_note` | Add a simple comment to any resource (for thread replies, use `gitlab_create_discussion`) |
412
+
413
+ ### Audit Event Tools (3 tools)
414
+
415
+ | Tool | Description |
416
+ | ----------------------------------- | -------------------------------------------------------- |
417
+ | `gitlab_list_project_audit_events` | List audit events for a project (requires owner role) |
418
+ | `gitlab_list_group_audit_events` | List audit events for a group (requires owner role) |
419
+ | `gitlab_list_instance_audit_events` | List instance-level audit events (requires admin access) |
420
+
421
+ ### Git Command Tool (1 tool)
422
+
423
+ | Tool | Description |
424
+ | ----------------- | ------------------------------------------------------------------------------------------------------ |
425
+ | `run_git_command` | Execute safe, read-only git commands (status, log, show, diff, blame, etc.) with security restrictions |
426
+
427
+ ### Wiki Tools (1 tool)
428
+
429
+ | Tool | Description |
430
+ | ---------------------- | ---------------------------------- |
431
+ | `gitlab_get_wiki_page` | Get wiki page content and metadata |
432
+
433
+ ## 💡 Usage Examples
434
+
435
+ ### Example 1: Create and Manage Issues
436
+
437
+ ```javascript
438
+ import gitlabPlugin from 'opencode-gitlab-plugin';
439
+
440
+ const plugin = await gitlabPlugin({});
441
+
442
+ // Create a new issue
443
+ const issue = await plugin.tool.gitlab_create_issue.execute({
444
+ project_id: 'my-group/my-project',
445
+ title: 'Fix authentication bug',
446
+ description:
447
+ '## Problem\n\nUsers cannot login with OAuth.\n\n## Steps to Reproduce\n1. Go to login page\n2. Click OAuth button\n3. Error occurs',
448
+ labels: 'bug,authentication,priority::high',
449
+ assignee_ids: [42],
450
+ milestone_id: 10,
451
+ due_date: '2025-12-31',
452
+ });
453
+
454
+ console.log(`Issue created: ${issue.web_url}`);
455
+
456
+ // Add a comment to the issue (using unified notes tool)
457
+ await plugin.tool.gitlab_create_note.execute({
458
+ resource_type: 'issue',
459
+ project_id: 'my-group/my-project',
460
+ iid: issue.iid,
461
+ body: 'I will start working on this today.',
462
+ });
463
+
464
+ // List all issues with specific labels
465
+ const issues = await plugin.tool.gitlab_list_issues.execute({
466
+ project_id: 'my-group/my-project',
467
+ labels: 'bug',
468
+ state: 'opened',
469
+ });
470
+ ```
471
+
472
+ ### Example 2: Review Merge Request
473
+
474
+ ```javascript
475
+ // Get merge request details
476
+ const mr = await plugin.tool.gitlab_get_merge_request.execute({
477
+ project_id: 'gitlab-org/gitlab',
478
+ mr_iid: 12345,
479
+ include_changes: true,
480
+ });
481
+
482
+ // Get discussions (unified tool supports all resource types)
483
+ const discussions = await plugin.tool.gitlab_list_discussions.execute({
484
+ resource_type: 'merge_request',
485
+ project_id: 'gitlab-org/gitlab',
486
+ iid: 12345,
487
+ });
488
+
489
+ // Add a review comment (creates a new discussion)
490
+ await plugin.tool.gitlab_create_discussion.execute({
491
+ resource_type: 'merge_request',
492
+ project_id: 'gitlab-org/gitlab',
493
+ iid: 12345,
494
+ body: 'LGTM! Great work on this feature.',
495
+ });
496
+
497
+ // Reply to an existing discussion thread
498
+ await plugin.tool.gitlab_create_discussion.execute({
499
+ resource_type: 'merge_request',
500
+ project_id: 'gitlab-org/gitlab',
501
+ iid: 12345,
502
+ discussion_id: discussions.discussions.nodes[0].id,
503
+ body: 'Thanks for addressing the feedback!',
504
+ });
505
+ ```
506
+
507
+ ### Example 3: Debug Failed Pipeline
508
+
509
+ ```javascript
510
+ // List recent pipelines
511
+ const pipelines = await plugin.tool.gitlab_list_pipelines.execute({
512
+ project_id: 'my-group/my-project',
513
+ status: 'failed',
514
+ limit: 5,
515
+ });
516
+
517
+ // Get failed jobs
518
+ const failedJobs = await plugin.tool.gitlab_get_pipeline_failing_jobs.execute({
519
+ project_id: 'my-group/my-project',
520
+ pipeline_id: pipelines[0].id,
521
+ });
522
+
523
+ // Get job logs
524
+ for (const job of failedJobs) {
525
+ const log = await plugin.tool.gitlab_get_job_log.execute({
526
+ project_id: 'my-group/my-project',
527
+ job_id: job.id,
528
+ });
529
+ console.log(`Job ${job.name} failed with:\n${log}`);
530
+ }
531
+
532
+ // Retry failed jobs
533
+ await plugin.tool.gitlab_retry_job.execute({
534
+ project_id: 'my-group/my-project',
535
+ job_id: failedJobs[0].id,
536
+ });
537
+ ```
538
+
539
+ ### Example 4: Create and Manage Epic
540
+
541
+ ```javascript
542
+ // Create an epic
543
+ const epic = await plugin.tool.gitlab_create_epic.execute({
544
+ group_id: 'my-group',
545
+ title: 'Q1 2025 Features',
546
+ description: 'All features planned for Q1 2025',
547
+ start_date: '2025-01-01',
548
+ end_date: '2025-03-31',
549
+ labels: 'Q1,planning',
550
+ });
551
+
552
+ // Add issues to epic
553
+ await plugin.tool.gitlab_add_issue_to_epic.execute({
554
+ group_id: 'my-group',
555
+ epic_iid: epic.iid,
556
+ issue_id: 123,
557
+ });
558
+
559
+ // List all issues in epic
560
+ const epicIssues = await plugin.tool.gitlab_list_epic_issues.execute({
561
+ group_id: 'my-group',
562
+ epic_iid: epic.iid,
563
+ });
564
+
565
+ // Add a comment (creates a new discussion)
566
+ await plugin.tool.gitlab_create_discussion.execute({
567
+ resource_type: 'epic',
568
+ group_id: 'my-group',
569
+ iid: epic.iid,
570
+ body: 'Epic created and issues linked successfully!',
571
+ });
572
+ ```
573
+
574
+ ### Example 5: Search and Analyze Code
575
+
576
+ ```javascript
577
+ // Search for code containing specific patterns
578
+ const codeResults = await plugin.tool.gitlab_blob_search.execute({
579
+ search: 'async function processPayment',
580
+ project_id: 'my-group/my-project',
581
+ limit: 10,
582
+ });
583
+
584
+ // Search for related issues
585
+ const issues = await plugin.tool.gitlab_issue_search.execute({
586
+ search: 'payment processing bug',
587
+ project_id: 'my-group/my-project',
588
+ state: 'opened',
589
+ });
590
+
591
+ // Get file content
592
+ const fileContent = await plugin.tool.gitlab_get_file.execute({
593
+ project_id: 'my-group/my-project',
594
+ file_path: 'src/payment/processor.ts',
595
+ ref: 'main',
596
+ });
597
+ ```
598
+
599
+ ### Example 6: Manage TODOs (GraphQL with Pagination)
600
+
601
+ ```javascript
602
+ // Get TODO count (uses GraphQL)
603
+ const todoCount = await plugin.tool.gitlab_get_todo_count.execute({});
604
+
605
+ // List pending TODOs with cursor-based pagination
606
+ const firstPage = await plugin.tool.gitlab_list_todos.execute({
607
+ state: 'pending',
608
+ type: 'MergeRequest',
609
+ first: 20,
610
+ });
611
+
612
+ // Get next page using cursor
613
+ if (firstPage.todos.pageInfo.hasNextPage) {
614
+ const nextPage = await plugin.tool.gitlab_list_todos.execute({
615
+ state: 'pending',
616
+ type: 'MergeRequest',
617
+ first: 20,
618
+ after: firstPage.todos.pageInfo.endCursor,
619
+ });
620
+ }
621
+
622
+ // Mark specific TODO as done
623
+ await plugin.tool.gitlab_mark_todo_done.execute({
624
+ todo_id: firstPage.todos.nodes[0].id,
625
+ });
626
+
627
+ // Mark all TODOs as done
628
+ await plugin.tool.gitlab_mark_all_todos_done.execute({});
629
+ ```
630
+
631
+ ### Example 7: Create Commit with Multiple Files
632
+
633
+ ```javascript
634
+ // Create a commit with multiple file operations
635
+ const commit = await plugin.tool.gitlab_create_commit.execute({
636
+ project_id: 'my-group/my-project',
637
+ branch: 'feature/new-api',
638
+ commit_message: 'feat: add new API endpoints',
639
+ actions: [
640
+ {
641
+ action: 'create',
642
+ file_path: 'src/api/v2/users.ts',
643
+ content: 'export const getUsers = async () => { ... }',
644
+ },
645
+ {
646
+ action: 'update',
647
+ file_path: 'src/api/index.ts',
648
+ content: 'export * from "./v2/users";',
649
+ },
650
+ {
651
+ action: 'delete',
652
+ file_path: 'src/api/deprecated.ts',
653
+ },
654
+ ],
655
+ author_name: 'John Doe',
656
+ author_email: 'john@example.com',
657
+ });
658
+ ```
659
+
660
+ ### Example 8: Enable Auto-Merge (MWPS)
661
+
662
+ ```javascript
663
+ // Get merge request to retrieve current HEAD SHA
664
+ const mr = await plugin.tool.gitlab_get_merge_request.execute({
665
+ project_id: 'my-group/my-project',
666
+ mr_iid: 123,
667
+ });
668
+
669
+ // Enable auto-merge when pipeline succeeds (GraphQL)
670
+ const result = await plugin.tool.gitlab_set_mr_auto_merge.execute({
671
+ project_id: 'my-group/my-project',
672
+ mr_iid: 123,
673
+ sha: mr.sha, // Required to prevent race conditions
674
+ strategy: 'MERGE_WHEN_CHECKS_PASS', // or 'ADD_TO_MERGE_TRAIN_WHEN_CHECKS_PASS'
675
+ });
676
+
677
+ console.log(`Auto-merge enabled: ${result.mergeRequest.autoMergeEnabled}`);
678
+ ```
679
+
680
+ ### Example 9: Manage Security Vulnerabilities
681
+
682
+ ```javascript
683
+ // List vulnerabilities in a project
684
+ const vulnerabilities = await plugin.tool.gitlab_list_vulnerabilities.execute({
685
+ project_id: 'my-group/my-project',
686
+ state: 'detected',
687
+ severity: 'high',
688
+ report_type: 'sast',
689
+ });
690
+
691
+ // Create an issue for critical vulnerabilities
692
+ const issue = await plugin.tool.gitlab_create_vulnerability_issue.execute({
693
+ project_path: 'my-group/my-project',
694
+ vulnerability_ids: ['gid://gitlab/Vulnerability/123', 'gid://gitlab/Vulnerability/124'],
695
+ });
696
+
697
+ // Dismiss a false positive
698
+ await plugin.tool.gitlab_dismiss_vulnerability.execute({
699
+ vulnerability_id: 'gid://gitlab/Vulnerability/125',
700
+ reason: 'FALSE_POSITIVE',
701
+ comment: 'This is a test file and not part of production code',
702
+ });
703
+
704
+ // Confirm a real vulnerability
705
+ await plugin.tool.gitlab_confirm_vulnerability.execute({
706
+ vulnerability_id: 'gid://gitlab/Vulnerability/126',
707
+ comment: 'Confirmed - needs immediate attention',
708
+ });
709
+
710
+ // Update severity based on assessment
711
+ await plugin.tool.gitlab_update_vulnerability_severity.execute({
712
+ vulnerability_ids: ['gid://gitlab/Vulnerability/127'],
713
+ severity: 'CRITICAL',
714
+ comment: 'Upgrading to critical - affects production authentication',
715
+ });
716
+
717
+ // Link vulnerabilities to existing issue
718
+ await plugin.tool.gitlab_link_vulnerability_to_issue.execute({
719
+ issue_id: 'gid://gitlab/Issue/42',
720
+ vulnerability_ids: ['gid://gitlab/Vulnerability/128', 'gid://gitlab/Vulnerability/129'],
721
+ });
722
+ ```
723
+
724
+ ## 🔧 Development
725
+
726
+ ### Project Structure
727
+
728
+ ```
729
+ opencode-gitlab-plugin/
730
+ ├── src/
731
+ │ ├── client/ # API client modules
732
+ │ │ ├── base.ts # Base client with HTTP & GraphQL methods
733
+ │ │ ├── security.ts # Security/vulnerability management
734
+ │ │ ├── issues.ts # Issue management
735
+ │ │ ├── merge-requests.ts # Merge request operations
736
+ │ │ ├── pipelines.ts # CI/CD pipeline operations
737
+ │ │ ├── repository.ts # Repository operations
738
+ │ │ ├── epics.ts # Epic management
739
+ │ │ ├── search.ts # Search operations
740
+ │ │ ├── todos.ts # TODO management
741
+ │ │ ├── wikis.ts # Wiki operations
742
+ │ │ ├── work-items.ts # Work item operations
743
+ │ │ ├── audit.ts # Audit events
744
+ │ │ ├── git.ts # Git operations
745
+ │ │ └── index.ts # Client exports
746
+ │ ├── tools/ # Tool definitions
747
+ │ │ ├── security.ts # Security tool definitions
748
+ │ │ ├── issues.ts # Issue tool definitions
749
+ │ │ ├── merge-requests.ts # MR tool definitions
750
+ │ │ ├── pipelines.ts # Pipeline tool definitions
751
+ │ │ ├── repository.ts # Repository tool definitions
752
+ │ │ ├── discussions-unified.ts # Unified discussion tools (4 tools)
753
+ │ │ ├── notes-unified.ts # Unified notes tools (3 tools)
754
+ │ │ └── ... # Other tool definitions
755
+ │ ├── index.ts # Main plugin entry point
756
+ │ ├── utils.ts # Utility functions
757
+ │ └── validation.ts # GID validation utilities
758
+ ├── tests/ # Test suite (180 tests)
759
+ │ ├── client/ # Client tests
760
+ │ ├── tools/ # Tool tests
761
+ │ ├── validation.test.ts # Validation tests
762
+ │ └── utils.test.ts # Utility tests
763
+ ├── dist/ # Compiled output (generated)
764
+ │ ├── index.js # ESM bundle
765
+ │ └── index.d.ts # TypeScript definitions
766
+ ├── .husky/ # Git hooks
767
+ │ ├── commit-msg # Commitlint hook
768
+ │ └── pre-commit # Lint-staged hook
769
+ ├── .gitlab-ci.yml # CI/CD pipeline configuration
770
+ ├── package.json # Package metadata
771
+ ├── tsconfig.json # TypeScript configuration
772
+ ├── vitest.config.ts # Vitest test configuration
773
+ ├── .eslintrc.json # ESLint configuration
774
+ ├── .prettierrc.json # Prettier configuration
775
+ ├── .commitlintrc.json # Commitlint configuration
776
+ ├── .releaserc.json # Semantic-release configuration
777
+ ├── CHANGELOG.md # Auto-generated changelog
778
+ ├── INSTALLATION.md # Installation guide
779
+ └── README.md # This file
780
+ ```
781
+
782
+ ### Setup Development Environment
783
+
784
+ ```bash
785
+ # Clone the repository
786
+ git clone https://gitlab.com/vglafirov/opencode-gitlab-plugin.git
787
+ cd opencode-gitlab-plugin
788
+
789
+ # Install dependencies
790
+ npm install
791
+
792
+ # Build the plugin
793
+ npm run build
794
+
795
+ # Watch mode for development
796
+ npm run dev
797
+
798
+ # Run linting
799
+ npm run lint
800
+
801
+ # Fix linting issues
802
+ npm run lint:fix
803
+
804
+ # Format code
805
+ npm run format
806
+
807
+ # Check formatting
808
+ npm run format:check
809
+ ```
810
+
811
+ ### Git Hooks
812
+
813
+ The project uses Husky for Git hooks:
814
+
815
+ - **pre-commit**: Runs lint-staged to lint and format staged files
816
+ - **commit-msg**: Validates commit messages using commitlint
817
+
818
+ ### Commit Message Convention
819
+
820
+ This project follows [Conventional Commits](https://www.conventionalcommits.org/):
821
+
822
+ ```
823
+ <type>(<scope>): <subject>
824
+
825
+ <body>
826
+
827
+ <footer>
828
+ ```
829
+
830
+ **Types:**
831
+
832
+ - `feat`: New feature
833
+ - `fix`: Bug fix
834
+ - `docs`: Documentation changes
835
+ - `style`: Code style changes (formatting, etc.)
836
+ - `refactor`: Code refactoring
837
+ - `perf`: Performance improvements
838
+ - `test`: Adding or updating tests
839
+ - `build`: Build system changes
840
+ - `ci`: CI/CD changes
841
+ - `chore`: Other changes (dependencies, etc.)
842
+ - `revert`: Revert a previous commit
843
+
844
+ **Examples:**
845
+
846
+ ```bash
847
+ git commit -m "feat: add support for GitLab wiki pages"
848
+ git commit -m "fix: handle empty API responses correctly"
849
+ git commit -m "docs: update installation instructions"
850
+ git commit -m "ci: add automated release workflow"
851
+ ```
852
+
853
+ ### Building
854
+
855
+ ```bash
856
+ # Build for production
857
+ npm run build
858
+
859
+ # The build process:
860
+ # 1. Compiles TypeScript to ESM
861
+ # 2. Generates type definitions
862
+ # 3. Outputs to dist/ directory
863
+ ```
864
+
865
+ ### Testing
866
+
867
+ ```bash
868
+ # Run tests
869
+ npm test
870
+
871
+ # Run tests in watch mode
872
+ npm run test:watch
873
+
874
+ # Run tests with coverage
875
+ npm run test:coverage
876
+ ```
877
+
878
+ **Test Coverage:**
879
+
880
+ - **180 tests** across 21 test files
881
+ - Client tests for all API methods (REST and GraphQL)
882
+ - Tool tests for all tool definitions
883
+ - Validation tests for GID utilities
884
+ - GraphQL method tests for Notes, Discussions, TODOs
885
+ - All tests passing ✅
886
+
887
+ ## 🚀 CI/CD Pipeline
888
+
889
+ ### Pipeline Stages
890
+
891
+ ```mermaid
892
+ graph LR
893
+ A[Test] --> B[Build]
894
+ B --> C[Release]
895
+
896
+ A --> A1[Lint]
897
+ A --> A2[Format Check]
898
+ A --> A3[Unit Tests]
899
+
900
+ B --> B1[TypeScript Build]
901
+ B --> B2[Generate Types]
902
+
903
+ C --> C1[Semantic Release]
904
+ C --> C2[Publish to Registry]
905
+ C --> C3[Create Git Tag]
906
+ C --> C4[Update Changelog]
907
+ ```
908
+
909
+ ### Pipeline Configuration
910
+
911
+ The `.gitlab-ci.yml` defines the following stages:
912
+
913
+ #### 1. Test Stage
914
+
915
+ - **test:lint**: Runs ESLint on source code
916
+ - **test:format**: Checks code formatting with Prettier
917
+ - **test:unit**: Runs unit tests (placeholder)
918
+
919
+ #### 2. Build Stage
920
+
921
+ - **build**: Compiles TypeScript and generates artifacts
922
+ - Uses tsup for bundling
923
+ - Generates ESM output
924
+ - Creates TypeScript definitions
925
+ - Artifacts expire in 1 week
926
+
927
+ #### 3. Release Stage
928
+
929
+ - **release**: Automated versioning and publishing
930
+ - Only runs on main branch
931
+ - Uses semantic-release
932
+ - Publishes to GitLab Package Registry
933
+ - Creates Git tags
934
+ - Updates CHANGELOG.md
935
+ - Artifacts never expire
936
+
937
+ ### Semantic Release Workflow
938
+
939
+ ```mermaid
940
+ sequenceDiagram
941
+ participant Dev as Developer
942
+ participant Git as Git Repository
943
+ participant CI as GitLab CI
944
+ participant SR as Semantic Release
945
+ participant Reg as Package Registry
946
+
947
+ Dev->>Git: Push to main branch
948
+ Git->>CI: Trigger pipeline
949
+ CI->>CI: Run tests
950
+ CI->>CI: Build package
951
+ CI->>SR: Run semantic-release
952
+ SR->>SR: Analyze commits
953
+ SR->>SR: Determine version
954
+ SR->>SR: Generate changelog
955
+ SR->>Git: Create tag & commit
956
+ SR->>Reg: Publish package
957
+ SR->>Git: Create GitLab release
958
+ ```
959
+
960
+ ### Release Process
961
+
962
+ The release process is fully automated using semantic-release:
963
+
964
+ 1. **Commit Analysis**: Analyzes commit messages since last release
965
+ 2. **Version Calculation**: Determines next version based on commit types
966
+ - `fix:` → Patch version (1.0.x)
967
+ - `feat:` → Minor version (1.x.0)
968
+ - `BREAKING CHANGE:` → Major version (x.0.0)
969
+ 3. **Changelog Generation**: Updates CHANGELOG.md
970
+ 4. **Package Publishing**: Publishes to GitLab Package Registry
971
+ 5. **Git Tagging**: Creates and pushes version tag
972
+ 6. **GitLab Release**: Creates release notes on GitLab
973
+
974
+ ### Environment Variables
975
+
976
+ The CI/CD pipeline uses the following variables:
977
+
978
+ - `CI_JOB_TOKEN`: GitLab CI token (automatic)
979
+ - `CI_PROJECT_ID`: Project ID (automatic)
980
+ - `CI_API_V4_URL`: GitLab API URL (automatic)
981
+ - `HUSKY`: Set to `0` to disable hooks in CI
982
+
983
+ ## 📚 API Reference
984
+
985
+ ### GitLabApiClient Class
986
+
987
+ The core API client that handles all GitLab REST API interactions.
988
+
989
+ #### Constructor
990
+
991
+ ```typescript
992
+ constructor(instanceUrl: string, token: string)
993
+ ```
994
+
995
+ #### HTTP Methods
996
+
997
+ ```typescript
998
+ async fetch<T>(method: string, path: string, body?: unknown): Promise<T>
999
+ async fetchText(method: string, path: string): Promise<string>
1000
+ ```
1001
+
1002
+ #### GraphQL Methods
1003
+
1004
+ ```typescript
1005
+ /**
1006
+ * Execute a GraphQL query or mutation
1007
+ * @template T - The expected type of the data field in the GraphQL response
1008
+ * @param query - The GraphQL query or mutation string
1009
+ * @param variables - Optional variables for the query
1010
+ * @returns The data from the GraphQL response
1011
+ */
1012
+ async fetchGraphQL<T>(query: string, variables?: Record<string, unknown>): Promise<T>
1013
+ ```
1014
+
1015
+ **Features:**
1016
+
1017
+ - Full TypeScript type safety with generic return types
1018
+ - Automatic error handling for both HTTP and GraphQL errors
1019
+ - Support for query variables
1020
+ - Cursor-based pagination support for large result sets
1021
+ - Used by TODOs, Notes, Discussions, Auto-merge, and Security tools
1022
+
1023
+ **Example:**
1024
+
1025
+ ```typescript
1026
+ const result = await client.fetchGraphQL<{ vulnerability: { id: string } }>(
1027
+ `mutation($id: VulnerabilityID!) {
1028
+ vulnerabilityConfirm(input: { id: $id }) {
1029
+ vulnerability { id state }
1030
+ errors
1031
+ }
1032
+ }`,
1033
+ { id: 'gid://gitlab/Vulnerability/123' }
1034
+ );
1035
+ ```
1036
+
1037
+ **Pagination Example:**
1038
+
1039
+ ```typescript
1040
+ // First page
1041
+ const page1 = await plugin.tool.gitlab_list_todos.execute({ first: 20 });
1042
+ // Navigate with cursor
1043
+ const page2 = await plugin.tool.gitlab_list_todos.execute({
1044
+ first: 20,
1045
+ after: page1.todos.pageInfo.endCursor,
1046
+ });
1047
+ ```
1048
+
1049
+ #### Project ID Encoding
1050
+
1051
+ ```typescript
1052
+ private encodeProjectId(projectId: string): string
1053
+ ```
1054
+
1055
+ Handles URL encoding for project paths (e.g., `gitlab-org/gitlab` → `gitlab-org%2Fgitlab`)
1056
+
1057
+ ### Authentication Functions
1058
+
1059
+ #### readTokenFromAuthStorage
1060
+
1061
+ ```typescript
1062
+ function readTokenFromAuthStorage(): string | undefined;
1063
+ ```
1064
+
1065
+ Reads GitLab token from OpenCode auth storage (`~/.local/share/opencode/auth.json`).
1066
+
1067
+ Supports:
1068
+
1069
+ - OAuth tokens: `{ type: "oauth", access: "token" }`
1070
+ - API tokens: `{ type: "api", key: "token" }`
1071
+
1072
+ #### getGitLabClient
1073
+
1074
+ ```typescript
1075
+ function getGitLabClient(): GitLabApiClient;
1076
+ ```
1077
+
1078
+ Creates and returns a configured GitLab API client.
1079
+
1080
+ Priority:
1081
+
1082
+ 1. `GITLAB_TOKEN` environment variable
1083
+ 2. OpenCode auth storage
1084
+ 3. Throws error if no token found
1085
+
1086
+ ### Validation Functions
1087
+
1088
+ #### isValidGid
1089
+
1090
+ ```typescript
1091
+ function isValidGid(gid: string, expectedType?: string): boolean;
1092
+ ```
1093
+
1094
+ Validates GitLab Global ID (GID) format.
1095
+
1096
+ **Parameters:**
1097
+
1098
+ - `gid` - The GID to validate (e.g., `gid://gitlab/Vulnerability/123`)
1099
+ - `expectedType` - Optional expected resource type (e.g., `'Vulnerability'`, `'Issue'`)
1100
+
1101
+ **Returns:** `true` if valid, `false` otherwise
1102
+
1103
+ **Example:**
1104
+
1105
+ ```typescript
1106
+ isValidGid('gid://gitlab/Vulnerability/123'); // true
1107
+ isValidGid('gid://gitlab/Issue/456', 'Issue'); // true
1108
+ isValidGid('gid://gitlab/Vulnerability/123', 'Issue'); // false (wrong type)
1109
+ isValidGid('invalid-gid'); // false
1110
+ ```
1111
+
1112
+ #### validateGid
1113
+
1114
+ ```typescript
1115
+ function validateGid(gid: string, expectedType?: string): void;
1116
+ ```
1117
+
1118
+ Validates GID format and throws descriptive error if invalid.
1119
+
1120
+ **Parameters:**
1121
+
1122
+ - `gid` - The GID to validate
1123
+ - `expectedType` - Optional expected resource type
1124
+
1125
+ **Throws:** `Error` with descriptive message if GID format is invalid
1126
+
1127
+ **Example:**
1128
+
1129
+ ```typescript
1130
+ validateGid('gid://gitlab/Vulnerability/123'); // No error
1131
+ validateGid('invalid-gid'); // Throws: "Invalid GitLab Global ID: 'invalid-gid'. Expected format: gid://gitlab/ResourceType/{id}"
1132
+ validateGid('gid://gitlab/Issue/123', 'Vulnerability'); // Throws: "Invalid GitLab Global ID of type 'Vulnerability'..."
1133
+ ```
1134
+
1135
+ **Usage in Security Tools:**
1136
+
1137
+ All GraphQL-based security tools automatically validate GID parameters:
1138
+
1139
+ - `createVulnerabilityIssue()` - validates vulnerability IDs
1140
+ - `dismissVulnerability()` - validates vulnerability ID
1141
+ - `confirmVulnerability()` - validates vulnerability ID
1142
+ - `revertVulnerability()` - validates vulnerability ID
1143
+ - `updateVulnerabilitySeverity()` - validates vulnerability IDs
1144
+ - `linkVulnerabilityToIssue()` - validates both issue ID and vulnerability IDs
1145
+
1146
+ ### Tool Schema Validation
1147
+
1148
+ All tools use Zod for runtime validation:
1149
+
1150
+ ```typescript
1151
+ import { tool } from '@opencode-ai/plugin';
1152
+ const z = tool.schema; // Zod v4 compatible
1153
+
1154
+ // Example tool definition
1155
+ gitlab_get_merge_request: tool({
1156
+ description: 'Get details of a specific merge request',
1157
+ args: {
1158
+ project_id: z.string().describe('The project ID or URL-encoded path'),
1159
+ mr_iid: z.number().describe('The internal ID of the merge request'),
1160
+ include_changes: z.boolean().optional().describe('Include file changes'),
1161
+ },
1162
+ execute: async (args, ctx) => {
1163
+ // Implementation
1164
+ },
1165
+ });
1166
+ ```
1167
+
1168
+ ### Error Handling
1169
+
1170
+ All API calls include comprehensive error handling:
1171
+
1172
+ ```typescript
1173
+ if (!response.ok) {
1174
+ const errorText = await response.text();
1175
+ throw new Error(`GitLab API error ${response.status}: ${errorText}`);
1176
+ }
1177
+ ```
1178
+
1179
+ ### Response Formatting
1180
+
1181
+ All tool responses are JSON-formatted:
1182
+
1183
+ ```typescript
1184
+ return JSON.stringify(result, null, 2);
1185
+ ```
1186
+
1187
+ ## 🔐 Security Considerations
1188
+
1189
+ ### Token Storage
1190
+
1191
+ - **Environment Variables**: Recommended for CI/CD and production
1192
+ - **Auth Storage**: Convenient for local development
1193
+ - **Never commit tokens**: Use `.gitignore` for sensitive files
1194
+
1195
+ ### API Permissions
1196
+
1197
+ The plugin requires a GitLab token with appropriate scopes:
1198
+
1199
+ - `api`: Full API access (recommended)
1200
+ - `read_api`: Read-only access (limited functionality)
1201
+ - `read_repository`: Repository read access
1202
+ - `write_repository`: Repository write access (for commits)
1203
+
1204
+ ### Rate Limiting
1205
+
1206
+ GitLab API has rate limits:
1207
+
1208
+ - **Authenticated requests**: 2,000 requests per minute
1209
+ - **Unauthenticated requests**: 10 requests per minute
1210
+
1211
+ The plugin does not implement rate limiting logic. Consider implementing retry logic in your application.
1212
+
1213
+ ### HTTPS Only
1214
+
1215
+ The plugin enforces HTTPS for all API calls. HTTP URLs are not supported.
1216
+
1217
+ ## 🤝 Contributing
1218
+
1219
+ Contributions are welcome! Please see our [Contributing Guide](https://gitlab.com/vglafirov/opencode-gitlab-plugin/-/blob/main/CONTRIBUTING.md) for detailed guidelines on:
1220
+
1221
+ - Code style and conventions
1222
+ - Development workflow
1223
+ - Testing requirements
1224
+ - Submitting merge requests
1225
+ - Developer Certificate of Origin and License
1226
+
1227
+ **Quick Start for Contributors**:
1228
+
1229
+ 1. **Commit Messages**: Use conventional commits format
1230
+
1231
+ ```
1232
+ feat(scope): add new feature
1233
+ fix(scope): fix bug
1234
+ docs(scope): update documentation
1235
+ ```
1236
+
1237
+ 2. **Code Quality**: Ensure all checks pass
1238
+
1239
+ ```bash
1240
+ npm run lint
1241
+ npm test
1242
+ ```
1243
+
1244
+ 3. **Testing**: Add tests for new features
1245
+
1246
+ ## 🔗 Links
1247
+
1248
+ - [GitLab Repository](https://gitlab.com/vglafirov/opencode-gitlab-plugin)
1249
+ - [npm Package](https://www.npmjs.com/package/opencode-gitlab-plugin)
1250
+ - [Issue Tracker](https://gitlab.com/vglafirov/opencode-gitlab-plugin/-/issues)
1251
+ - [Merge Requests](https://gitlab.com/vglafirov/opencode-gitlab-plugin/-/merge_requests)
1252
+ - [Contributing Guide](https://gitlab.com/vglafirov/opencode-gitlab-plugin/-/blob/main/CONTRIBUTING.md)
1253
+ - [Changelog](https://gitlab.com/vglafirov/opencode-gitlab-plugin/-/blob/main/CHANGELOG.md)
1254
+ - [CI/CD Pipelines](https://gitlab.com/vglafirov/opencode-gitlab-plugin/-/pipelines)
1255
+ - [GitLab API Documentation](https://docs.gitlab.com/ee/api/)
1256
+ - [OpenCode Plugin SDK](https://github.com/opencode-ai/plugin)
1257
+
1258
+ ## 🙏 Acknowledgments
1259
+
1260
+ - **OpenCode Team**: For the plugin SDK and framework
1261
+ - **GitLab**: For the comprehensive REST API
1262
+ - **Contributors**: All contributors to this project
1263
+
1264
+ ## 📞 Support
1265
+
1266
+ For questions, issues, or feature requests:
1267
+
1268
+ 1. **Check existing issues**: <https://gitlab.com/vglafirov/opencode-gitlab-plugin/-/issues>
1269
+ 2. **Create new issue**: Use issue templates for bugs or features
1270
+ 3. **Discussions**: Use GitLab discussions for questions
1271
+
1272
+ ## 📄 License
1273
+
1274
+ This project is licensed under the MIT License - see the [LICENSE](https://gitlab.com/vglafirov/opencode-gitlab-plugin/-/blob/main/LICENSE) file for details.
1275
+
1276
+ ---
1277
+
1278
+ **Made with ❤️ for the OpenCode community**
1279
+
1280
+ ---