npm package: @gitlab/opencode-gitlab-plugin
Description: GitLab tools plugin for OpenCode - provides GitLab API access for merge requests, issues, pipelines, and more
Author: Vladimir Glafirov
Latest version: 1.9.0
Deprecated: This package has moved to 'opencode-gitlab-plugin'. Please run: npm install opencode-gitlab-plugin

# OpenCode GitLab Plugin

[![GitLab CI](https://gitlab.com/gitlab-org/editor-extensions/opencode-gitlab-plugin/badges/main/pipeline.svg)](https://gitlab.com/gitlab-org/editor-extensions/opencode-gitlab-plugin/-/pipelines)
[![npm version](https://img.shields.io/npm/v/@gitlab/opencode-gitlab-plugin.svg)](https://www.npmjs.com/package/@gitlab/opencode-gitlab-plugin)
[![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT)

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.

## 📋 Table of Contents

- [Features](#-features)
- [Architecture](#-architecture)
- [Installation](#-installation)
- [Configuration](#-configuration)
- [Available Tools](#-available-tools)
- [Usage Examples](#-usage-examples)
- [Development](#-development)
- [CI/CD Pipeline](#-cicd-pipeline)
- [API Reference](#-api-reference)
- [Contributing](#-contributing)
- [License](#-license)

## ✨ Features

### Core Capabilities

- **🔀 Merge Requests**: Full CRUD operations, discussions, notes, changes, commits, and pipelines
- **📝 Issues**: Create, read, update, and comment on issues with advanced filtering
- **🎯 Work Items**: Unified interface for issues, epics, tasks, and other work tracking items
- **🚀 CI/CD Pipelines**: Monitor, analyze, retry pipeline jobs, and validate CI/CD configurations
- **📦 Repository Operations**: File management, commits, branches, tree navigation, and commit discussions
- **🔍 Advanced Search**: Multi-scope search across projects, code, issues, merge requests, commits, users, milestones, and documentation
- **📊 Epics**: Enterprise-level epic management with issue associations
- **💬 Snippets**: Snippet discussions, notes, and comments management
- **🔗 Universal Discussions**: Unified interface for discussions across all GitLab resources
- **✅ TODOs**: Personal task management and notifications
- **🔒 Security**: Vulnerability scanning and security report access
- **📚 Wiki**: Wiki page content retrieval
- **🔍 Audit Events**: Track project, group, and instance-level security events
- **🔧 Git Commands**: Execute safe, read-only git operations
- **👥 Project Management**: Member management and project details

### Technical Features

- **TypeScript**: Full type safety with comprehensive type definitions
- **ESM Support**: Modern ES modules for optimal tree-shaking
- **Zod Validation**: Runtime schema validation for all API inputs
- **GraphQL Support**: Native GraphQL API support with type-safe mutations and queries for TODOs, Notes, Discussions, Auto-merge, and Security tools
- **Cursor-Based Pagination**: GraphQL-powered pagination with `first`/`after` and `last`/`before` cursors for efficient data fetching
- **GID Validation**: Automatic validation of GitLab Global IDs with descriptive error messages
- **Error Handling**: Robust error handling with detailed error messages
- **Authentication**: Multiple authentication methods (OAuth, API tokens)
- **Rate Limiting**: Built-in handling for GitLab API rate limits
- **Caching**: Efficient API response handling
- **Modular Architecture**: Clean separation of concerns with client and tool modules
- **Comprehensive Testing**: 180 tests with full coverage of all features

### GraphQL-Powered Tools

The following tools use GitLab's GraphQL API for enhanced functionality:

| Category        | Tools                                                                                                       | Benefits                                                                                 |
| --------------- | ----------------------------------------------------------------------------------------------------------- | ---------------------------------------------------------------------------------------- |
| **TODOs**       | `gitlab_list_todos`, `gitlab_get_todo_count`                                                                | Cursor-based pagination, rich filtering                                                  |
| **Notes**       | `gitlab_list_notes`, `gitlab_get_note`, `gitlab_create_note`                                                | Unified interface for all resource types, efficient pagination                           |
| **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 |
| **Auto-merge**  | `gitlab_set_mr_auto_merge`                                                                                  | MWPS (Merge When Pipeline Succeeds), merge train support                                 |
| **Security**    | All vulnerability management tools                                                                          | Type-safe GID validation, mutation support                                               |

## 🏗️ Architecture

### System Architecture

```mermaid
graph TB
    subgraph "OpenCode Environment"
        AI[AI Assistant]
        Plugin[GitLab Plugin]
    end

    subgraph "Plugin Components"
        Tools[Tool Definitions]
        Client[GitLab API Client]
        Auth[Authentication Manager]
        Validator[Zod Schema Validator]
    end

    subgraph "GitLab API"
        REST[REST API v4]
        GraphQL[GraphQL API]
        MR[Merge Requests]
        Issues[Issues]
        Pipelines[Pipelines]
        Repos[Repositories]
        Epics[Epics]
        Security[Security]
    end

    AI -->|Natural Language| Plugin
    Plugin --> Tools
    Tools --> Validator
    Validator --> Client
    Client --> Auth
    Auth --> REST
    Auth --> GraphQL
    REST --> MR
    REST --> Issues
    REST --> Pipelines
    REST --> Repos
    REST --> Epics
    GraphQL --> Security
    GraphQL --> MR
```

### Plugin Structure

```mermaid
graph LR
    subgraph "src/index.ts"
        A[GitLabApiClient Class]
        B[Authentication Functions]
        C[Tool Definitions]
        D[Plugin Export]
    end

    A --> A1[HTTP Methods]
    A --> A2[Merge Request APIs]
    A --> A3[Issue APIs]
    A --> A4[Pipeline APIs]
    A --> A5[Repository APIs]
    A --> A6[Epic APIs]
    A --> A7[Search APIs]

    B --> B1[readTokenFromAuthStorage]
    B --> B2[getGitLabClient]

    C --> C1[69 Tool Definitions]

    D --> A
    D --> B
    D --> C
```

### Authentication Flow

```mermaid
sequenceDiagram
    participant User
    participant Plugin
    participant AuthManager
    participant Storage
    participant GitLab

    User->>Plugin: Initialize Plugin
    Plugin->>AuthManager: getGitLabClient()
    AuthManager->>AuthManager: Check GITLAB_TOKEN env
    alt Token in Environment
        AuthManager->>GitLab: Use env token
    else No env token
        AuthManager->>Storage: Read ~/.local/share/opencode/auth.json
        Storage->>AuthManager: Return token
        AuthManager->>GitLab: Use stored token
    end
    GitLab->>Plugin: API Response
    Plugin->>User: Tool Result
```

## 📦 Installation

### Prerequisites

- Node.js >= 18.0.0
- npm >= 9.0.0 or Bun
- GitLab account with API access
- GitLab Personal Access Token or OAuth token

### Install from npm

```bash
# Install the package
npm install @gitlab/opencode-gitlab-plugin

# Or with Bun
bun add @gitlab/opencode-gitlab-plugin

# Or with yarn
yarn add @gitlab/opencode-gitlab-plugin
```

### Install from GitLab Repository (Development)

```bash
# Using npm
npm install git+https://gitlab.com/gitlab-org/editor-extensions/opencode-gitlab-plugin.git

# Using Bun
bun add git+https://gitlab.com/gitlab-org/editor-extensions/opencode-gitlab-plugin.git
```

### Install Specific Version

```bash
# Install specific version from npm
npm install @gitlab/opencode-gitlab-plugin@1.0.0

# Install from specific git tag
npm install git+https://gitlab.com/gitlab-org/editor-extensions/opencode-gitlab-plugin.git#v1.0.0

# Install from specific branch
npm install git+https://gitlab.com/gitlab-org/editor-extensions/opencode-gitlab-plugin.git#main
```

### Using package.json

Add to your `package.json`:

```json
{
  "dependencies": {
    "@gitlab/opencode-gitlab-plugin": "^1.0.0"
  }
}
```

Then run:

```bash
npm install
```

## ⚙️ Configuration

### Environment Variables

```bash
# Required: GitLab API Token
export GITLAB_TOKEN=glpat-xxxxxxxxxxxxxxxxxxxx

# Optional: Custom GitLab Instance (defaults to https://gitlab.com)
export GITLAB_INSTANCE_URL=https://gitlab.example.com
```

### OpenCode Configuration

Add the following plugin to your opencode configuration `~/.config/opencode/opencode.json`:

```json
{
  "$schema": "https://opencode.ai/config.json",
  "plugin": ["@gitlab/opencode-gitlab-plugin"]
}
```

### Authentication Storage

The plugin supports reading tokens from OpenCode's auth storage:

**Location**: `~/.local/share/opencode/auth.json`

**Format**:

```json
{
  "gitlab": {
    "type": "oauth",
    "access": "your-oauth-token"
  }
}
```

Or for API tokens:

```json
{
  "gitlab": {
    "type": "api",
    "key": "glpat-xxxxxxxxxxxxxxxxxxxx"
  }
}
```

### Token Priority

1. `GITLAB_TOKEN` environment variable (highest priority)
2. OpenCode auth storage (`~/.local/share/opencode/auth.json`)
3. Error if no token found

## 🛠️ Available Tools

The plugin provides **64 tools** organized into the following categories:

### Merge Request Tools (8 tools)

| Tool                              | Description                                                                                                                  |
| --------------------------------- | ---------------------------------------------------------------------------------------------------------------------------- |
| `gitlab_get_merge_request`        | Get details of a specific merge request with title, description, state, author, assignees, reviewers, labels, and diff stats |
| `gitlab_list_merge_requests`      | List merge requests with filtering by state, scope, and labels                                                               |
| `gitlab_create_merge_request`     | Create a new merge request                                                                                                   |
| `gitlab_update_merge_request`     | Update merge request title, description, state, assignees, reviewers, and labels                                             |
| `gitlab_get_mr_changes`           | Get file changes/diffs for a merge request                                                                                   |
| `gitlab_get_mr_details`           | Get additional MR details (commits or pipelines) with detail_type parameter                                                  |
| `gitlab_list_merge_request_diffs` | List file diffs with pagination support for large changesets                                                                 |
| `gitlab_set_mr_auto_merge`        | Enable auto-merge (MWPS) using GraphQL API when pipeline succeeds                                                            |

### Issue Tools (3 tools)

| Tool                  | Description                                                                  |
| --------------------- | ---------------------------------------------------------------------------- |
| `gitlab_create_issue` | Create a new issue with title, description, labels, assignees, and milestone |
| `gitlab_get_issue`    | Get issue details including state, author, assignees, labels, and comments   |
| `gitlab_list_issues`  | List issues with filtering by state, labels, assignee, and milestone         |

### Epic Tools (5 tools)

| Tool                        | Description                                                                   |
| --------------------------- | ----------------------------------------------------------------------------- |
| `gitlab_get_epic`           | Get epic details with title, description, state, dates, and associated issues |
| `gitlab_list_epics`         | List epics with filtering by state, author, and labels                        |
| `gitlab_create_epic`        | Create a new epic in a group                                                  |
| `gitlab_update_epic`        | Update epic title, description, labels, dates, and state                      |
| `gitlab_manage_epic_issues` | Manage issues linked to an epic (list, add, remove) with action parameter     |

### Pipeline Tools (7 tools)

| Tool                               | Description                                                                     |
| ---------------------------------- | ------------------------------------------------------------------------------- |
| `gitlab_list_pipelines`            | List pipelines with filtering by status, ref, and username                      |
| `gitlab_get_pipeline`              | Get pipeline details with jobs and status                                       |
| `gitlab_list_pipeline_jobs`        | List all jobs in a pipeline with optional scope filtering                       |
| `gitlab_get_job_log`               | Get the log output of a specific CI job                                         |
| `gitlab_retry_job`                 | Retry a failed or canceled job                                                  |
| `gitlab_get_pipeline_failing_jobs` | Get only failed jobs for easier debugging                                       |
| `gitlab_lint_ci_config`            | Validate CI/CD YAML config with mode parameter (content or existing repository) |

### Repository Tools (7 tools)

| Tool                          | Description                                            |
| ----------------------------- | ------------------------------------------------------ |
| `gitlab_get_file`             | Get file contents from any branch, tag, or commit      |
| `gitlab_get_commit`           | Get commit details with metadata, author, and stats    |
| `gitlab_list_commits`         | List commits with filtering by branch, path, and dates |
| `gitlab_get_commit_diff`      | Get diff for a specific commit                         |
| `gitlab_list_repository_tree` | List files and directories at a given path             |
| `gitlab_list_branches`        | List all branches in a repository                      |
| `gitlab_get_commit_comments`  | Get all commit comments in flat structure              |

### Search Tools (2 tools)

| Tool                          | Description                                                                                                                                                                     |
| ----------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `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) |
| `gitlab_documentation_search` | Search GitLab official documentation at docs.gitlab.com                                                                                                                         |

### Work Item Tools (6 tools)

| Tool                           | Description                                              |
| ------------------------------ | -------------------------------------------------------- |
| `gitlab_get_work_item`         | Get a work item (unified model for issues, epics, tasks) |
| `gitlab_list_work_items`       | List work items in a project or group                    |
| `gitlab_get_work_item_notes`   | Get all comments for a work item                         |
| `gitlab_create_work_item`      | Create a new work item                                   |
| `gitlab_update_work_item`      | Update work item title, description, state, and labels   |
| `gitlab_create_work_item_note` | Add a comment to a work item                             |

### Security Tools (8 tools)

| Tool                                      | Description                                                               |
| ----------------------------------------- | ------------------------------------------------------------------------- |
| `gitlab_list_vulnerabilities`             | List security vulnerabilities with filtering by state, severity, and type |
| `gitlab_get_vulnerability_details`        | Get detailed vulnerability information with remediation                   |
| `gitlab_create_vulnerability_issue`       | Create an issue linked to vulnerabilities (GraphQL)                       |
| `gitlab_dismiss_vulnerability`            | Dismiss vulnerability with reason (GraphQL)                               |
| `gitlab_confirm_vulnerability`            | Confirm a vulnerability as valid (GraphQL)                                |
| `gitlab_revert_vulnerability_to_detected` | Revert vulnerability state (GraphQL)                                      |
| `gitlab_update_vulnerability_severity`    | Update vulnerability severity level (GraphQL)                             |
| `gitlab_link_vulnerability_to_issue`      | Link vulnerabilities to existing issue (GraphQL)                          |

**Note**: All GraphQL-based security tools include automatic GID (Global ID) format validation.

### TODO Tools (3 tools)

| Tool                    | Description                                            |
| ----------------------- | ------------------------------------------------------ |
| `gitlab_list_todos`     | List TODO items with cursor-based pagination (GraphQL) |
| `gitlab_mark_todo_done` | Mark TODOs as done with action parameter (one or all)  |
| `gitlab_get_todo_count` | Get count of pending TODOs (GraphQL)                   |

### Project & User Tools (3 tools)

| Tool                          | Description                        |
| ----------------------------- | ---------------------------------- |
| `gitlab_get_project`          | Get project details and metadata   |
| `gitlab_list_project_members` | List all members of a project      |
| `gitlab_get_current_user`     | Get authenticated user information |

### Discussion Tools (4 tools)

| Tool                        | Description                                                                                                              |
| --------------------------- | ------------------------------------------------------------------------------------------------------------------------ |
| `gitlab_list_discussions`   | List discussions (comment threads) on any GitLab resource (MRs, issues, epics, commits, snippets) with cursor pagination |
| `gitlab_get_discussion`     | Get a specific discussion thread with all replies from any resource type                                                 |
| `gitlab_create_discussion`  | Create a new discussion thread OR reply to an existing one (supports code-position comments for MRs and commits)         |
| `gitlab_resolve_discussion` | Mark a discussion thread as resolved or unresolve it (MRs and issues only)                                               |

### Notes Tools (3 tools)

| Tool                 | Description                                                                                         |
| -------------------- | --------------------------------------------------------------------------------------------------- |
| `gitlab_list_notes`  | List all notes/comments on any resource (MRs, issues, epics, snippets) with cursor-based pagination |
| `gitlab_get_note`    | Get a single note by ID (issues and epics only)                                                     |
| `gitlab_create_note` | Add a simple comment to any resource (for thread replies, use `gitlab_create_discussion`)           |

### Audit Event Tools (3 tools)

| Tool                                | Description                                              |
| ----------------------------------- | -------------------------------------------------------- |
| `gitlab_list_project_audit_events`  | List audit events for a project (requires owner role)    |
| `gitlab_list_group_audit_events`    | List audit events for a group (requires owner role)      |
| `gitlab_list_instance_audit_events` | List instance-level audit events (requires admin access) |

### Git Command Tool (1 tool)

| Tool              | Description                                                                                            |
| ----------------- | ------------------------------------------------------------------------------------------------------ |
| `run_git_command` | Execute safe, read-only git commands (status, log, show, diff, blame, etc.) with security restrictions |

### Wiki Tools (1 tool)

| Tool                   | Description                        |
| ---------------------- | ---------------------------------- |
| `gitlab_get_wiki_page` | Get wiki page content and metadata |

## 💡 Usage Examples

### Example 1: Create and Manage Issues

```javascript
import gitlabPlugin from '@gitlab/opencode-gitlab-plugin';

const plugin = await gitlabPlugin({});

// Create a new issue
const issue = await plugin.tool.gitlab_create_issue.execute({
  project_id: 'my-group/my-project',
  title: 'Fix authentication bug',
  description:
    '## Problem\n\nUsers cannot login with OAuth.\n\n## Steps to Reproduce\n1. Go to login page\n2. Click OAuth button\n3. Error occurs',
  labels: 'bug,authentication,priority::high',
  assignee_ids: [42],
  milestone_id: 10,
  due_date: '2025-12-31',
});

console.log(`Issue created: ${issue.web_url}`);

// Add a comment to the issue (using unified notes tool)
await plugin.tool.gitlab_create_note.execute({
  resource_type: 'issue',
  project_id: 'my-group/my-project',
  iid: issue.iid,
  body: 'I will start working on this today.',
});

// List all issues with specific labels
const issues = await plugin.tool.gitlab_list_issues.execute({
  project_id: 'my-group/my-project',
  labels: 'bug',
  state: 'opened',
});
```

### Example 2: Review Merge Request

```javascript
// Get merge request details
const mr = await plugin.tool.gitlab_get_merge_request.execute({
  project_id: 'gitlab-org/gitlab',
  mr_iid: 12345,
  include_changes: true,
});

// Get discussions (unified tool supports all resource types)
const discussions = await plugin.tool.gitlab_list_discussions.execute({
  resource_type: 'merge_request',
  project_id: 'gitlab-org/gitlab',
  iid: 12345,
});

// Add a review comment (creates a new discussion)
await plugin.tool.gitlab_create_discussion.execute({
  resource_type: 'merge_request',
  project_id: 'gitlab-org/gitlab',
  iid: 12345,
  body: 'LGTM! Great work on this feature.',
});

// Reply to an existing discussion thread
await plugin.tool.gitlab_create_discussion.execute({
  resource_type: 'merge_request',
  project_id: 'gitlab-org/gitlab',
  iid: 12345,
  discussion_id: discussions.discussions.nodes[0].id,
  body: 'Thanks for addressing the feedback!',
});
```

### Example 3: Debug Failed Pipeline

```javascript
// List recent pipelines
const pipelines = await plugin.tool.gitlab_list_pipelines.execute({
  project_id: 'my-group/my-project',
  status: 'failed',
  limit: 5,
});

// Get failed jobs
const failedJobs = await plugin.tool.gitlab_get_pipeline_failing_jobs.execute({
  project_id: 'my-group/my-project',
  pipeline_id: pipelines[0].id,
});

// Get job logs
for (const job of failedJobs) {
  const log = await plugin.tool.gitlab_get_job_log.execute({
    project_id: 'my-group/my-project',
    job_id: job.id,
  });
  console.log(`Job ${job.name} failed with:\n${log}`);
}

// Retry failed jobs
await plugin.tool.gitlab_retry_job.execute({
  project_id: 'my-group/my-project',
  job_id: failedJobs[0].id,
});
```

### Example 4: Create and Manage Epic

```javascript
// Create an epic
const epic = await plugin.tool.gitlab_create_epic.execute({
  group_id: 'my-group',
  title: 'Q1 2025 Features',
  description: 'All features planned for Q1 2025',
  start_date: '2025-01-01',
  end_date: '2025-03-31',
  labels: 'Q1,planning',
});

// Add issues to epic
await plugin.tool.gitlab_add_issue_to_epic.execute({
  group_id: 'my-group',
  epic_iid: epic.iid,
  issue_id: 123,
});

// List all issues in epic
const epicIssues = await plugin.tool.gitlab_list_epic_issues.execute({
  group_id: 'my-group',
  epic_iid: epic.iid,
});

// Add a comment (creates a new discussion)
await plugin.tool.gitlab_create_discussion.execute({
  resource_type: 'epic',
  group_id: 'my-group',
  iid: epic.iid,
  body: 'Epic created and issues linked successfully!',
});
```

### Example 5: Search and Analyze Code

```javascript
// Search for code containing specific patterns
const codeResults = await plugin.tool.gitlab_blob_search.execute({
  search: 'async function processPayment',
  project_id: 'my-group/my-project',
  limit: 10,
});

// Search for related issues
const issues = await plugin.tool.gitlab_issue_search.execute({
  search: 'payment processing bug',
  project_id: 'my-group/my-project',
  state: 'opened',
});

// Get file content
const fileContent = await plugin.tool.gitlab_get_file.execute({
  project_id: 'my-group/my-project',
  file_path: 'src/payment/processor.ts',
  ref: 'main',
});
```

### Example 6: Manage TODOs (GraphQL with Pagination)

```javascript
// Get TODO count (uses GraphQL)
const todoCount = await plugin.tool.gitlab_get_todo_count.execute({});

// List pending TODOs with cursor-based pagination
const firstPage = await plugin.tool.gitlab_list_todos.execute({
  state: 'pending',
  type: 'MergeRequest',
  first: 20,
});

// Get next page using cursor
if (firstPage.todos.pageInfo.hasNextPage) {
  const nextPage = await plugin.tool.gitlab_list_todos.execute({
    state: 'pending',
    type: 'MergeRequest',
    first: 20,
    after: firstPage.todos.pageInfo.endCursor,
  });
}

// Mark specific TODO as done
await plugin.tool.gitlab_mark_todo_done.execute({
  todo_id: firstPage.todos.nodes[0].id,
});

// Mark all TODOs as done
await plugin.tool.gitlab_mark_all_todos_done.execute({});
```

### Example 7: Create Commit with Multiple Files

```javascript
// Create a commit with multiple file operations
const commit = await plugin.tool.gitlab_create_commit.execute({
  project_id: 'my-group/my-project',
  branch: 'feature/new-api',
  commit_message: 'feat: add new API endpoints',
  actions: [
    {
      action: 'create',
      file_path: 'src/api/v2/users.ts',
      content: 'export const getUsers = async () => { ... }',
    },
    {
      action: 'update',
      file_path: 'src/api/index.ts',
      content: 'export * from "./v2/users";',
    },
    {
      action: 'delete',
      file_path: 'src/api/deprecated.ts',
    },
  ],
  author_name: 'John Doe',
  author_email: 'john@example.com',
});
```

### Example 8: Enable Auto-Merge (MWPS)

```javascript
// Get merge request to retrieve current HEAD SHA
const mr = await plugin.tool.gitlab_get_merge_request.execute({
  project_id: 'my-group/my-project',
  mr_iid: 123,
});

// Enable auto-merge when pipeline succeeds (GraphQL)
const result = await plugin.tool.gitlab_set_mr_auto_merge.execute({
  project_id: 'my-group/my-project',
  mr_iid: 123,
  sha: mr.sha, // Required to prevent race conditions
  strategy: 'MERGE_WHEN_CHECKS_PASS', // or 'ADD_TO_MERGE_TRAIN_WHEN_CHECKS_PASS'
});

console.log(`Auto-merge enabled: ${result.mergeRequest.autoMergeEnabled}`);
```

### Example 9: Manage Security Vulnerabilities

```javascript
// List vulnerabilities in a project
const vulnerabilities = await plugin.tool.gitlab_list_vulnerabilities.execute({
  project_id: 'my-group/my-project',
  state: 'detected',
  severity: 'high',
  report_type: 'sast',
});

// Create an issue for critical vulnerabilities
const issue = await plugin.tool.gitlab_create_vulnerability_issue.execute({
  project_path: 'my-group/my-project',
  vulnerability_ids: ['gid://gitlab/Vulnerability/123', 'gid://gitlab/Vulnerability/124'],
});

// Dismiss a false positive
await plugin.tool.gitlab_dismiss_vulnerability.execute({
  vulnerability_id: 'gid://gitlab/Vulnerability/125',
  reason: 'FALSE_POSITIVE',
  comment: 'This is a test file and not part of production code',
});

// Confirm a real vulnerability
await plugin.tool.gitlab_confirm_vulnerability.execute({
  vulnerability_id: 'gid://gitlab/Vulnerability/126',
  comment: 'Confirmed - needs immediate attention',
});

// Update severity based on assessment
await plugin.tool.gitlab_update_vulnerability_severity.execute({
  vulnerability_ids: ['gid://gitlab/Vulnerability/127'],
  severity: 'CRITICAL',
  comment: 'Upgrading to critical - affects production authentication',
});

// Link vulnerabilities to existing issue
await plugin.tool.gitlab_link_vulnerability_to_issue.execute({
  issue_id: 'gid://gitlab/Issue/42',
  vulnerability_ids: ['gid://gitlab/Vulnerability/128', 'gid://gitlab/Vulnerability/129'],
});
```

## 🔧 Development

### Project Structure

```
opencode-gitlab-plugin/
├── src/
│   ├── client/              # API client modules
│   │   ├── base.ts         # Base client with HTTP & GraphQL methods
│   │   ├── security.ts     # Security/vulnerability management
│   │   ├── issues.ts       # Issue management
│   │   ├── merge-requests.ts # Merge request operations
│   │   ├── pipelines.ts    # CI/CD pipeline operations
│   │   ├── repository.ts   # Repository operations
│   │   ├── epics.ts        # Epic management
│   │   ├── search.ts       # Search operations
│   │   ├── todos.ts        # TODO management
│   │   ├── wikis.ts        # Wiki operations
│   │   ├── work-items.ts   # Work item operations
│   │   ├── audit.ts        # Audit events
│   │   ├── git.ts          # Git operations
│   │   └── index.ts        # Client exports
│   ├── tools/              # Tool definitions
│   │   ├── security.ts     # Security tool definitions
│   │   ├── issues.ts       # Issue tool definitions
│   │   ├── merge-requests.ts # MR tool definitions
│   │   ├── pipelines.ts    # Pipeline tool definitions
│   │   ├── repository.ts   # Repository tool definitions
│   │   ├── discussions-unified.ts # Unified discussion tools (4 tools)
│   │   ├── notes-unified.ts # Unified notes tools (3 tools)
│   │   └── ...             # Other tool definitions
│   ├── index.ts            # Main plugin entry point
│   ├── utils.ts            # Utility functions
│   └── validation.ts       # GID validation utilities
├── tests/                  # Test suite (180 tests)
│   ├── client/             # Client tests
│   ├── tools/              # Tool tests
│   ├── validation.test.ts  # Validation tests
│   └── utils.test.ts       # Utility tests
├── dist/                   # Compiled output (generated)
│   ├── index.js           # ESM bundle
│   └── index.d.ts         # TypeScript definitions
├── .husky/                 # Git hooks
│   ├── commit-msg         # Commitlint hook
│   └── pre-commit         # Lint-staged hook
├── .gitlab-ci.yml         # CI/CD pipeline configuration
├── package.json           # Package metadata
├── tsconfig.json          # TypeScript configuration
├── vitest.config.ts       # Vitest test configuration
├── .eslintrc.json         # ESLint configuration
├── .prettierrc.json       # Prettier configuration
├── .commitlintrc.json     # Commitlint configuration
├── .releaserc.json        # Semantic-release configuration
├── CHANGELOG.md           # Auto-generated changelog
├── INSTALLATION.md        # Installation guide
└── README.md              # This file
```

### Setup Development Environment

```bash
# Clone the repository
git clone https://gitlab.com/gitlab-org/editor-extensions/opencode-gitlab-plugin.git
cd opencode-gitlab-plugin

# Install dependencies
npm install

# Build the plugin
npm run build

# Watch mode for development
npm run dev

# Run linting
npm run lint

# Fix linting issues
npm run lint:fix

# Format code
npm run format

# Check formatting
npm run format:check
```

### Git Hooks

The project uses Husky for Git hooks:

- **pre-commit**: Runs lint-staged to lint and format staged files
- **commit-msg**: Validates commit messages using commitlint

### Commit Message Convention

This project follows [Conventional Commits](https://www.conventionalcommits.org/):

```
<type>(<scope>): <subject>

<body>

<footer>
```

**Types:**

- `feat`: New feature
- `fix`: Bug fix
- `docs`: Documentation changes
- `style`: Code style changes (formatting, etc.)
- `refactor`: Code refactoring
- `perf`: Performance improvements
- `test`: Adding or updating tests
- `build`: Build system changes
- `ci`: CI/CD changes
- `chore`: Other changes (dependencies, etc.)
- `revert`: Revert a previous commit

**Examples:**

```bash
git commit -m "feat: add support for GitLab wiki pages"
git commit -m "fix: handle empty API responses correctly"
git commit -m "docs: update installation instructions"
git commit -m "ci: add automated release workflow"
```

### Building

```bash
# Build for production
npm run build

# The build process:
# 1. Compiles TypeScript to ESM
# 2. Generates type definitions
# 3. Outputs to dist/ directory
```

### Testing

```bash
# Run tests
npm test

# Run tests in watch mode
npm run test:watch

# Run tests with coverage
npm run test:coverage
```

**Test Coverage:**

- **180 tests** across 21 test files
- Client tests for all API methods (REST and GraphQL)
- Tool tests for all tool definitions
- Validation tests for GID utilities
- GraphQL method tests for Notes, Discussions, TODOs
- All tests passing ✅

## 🚀 CI/CD Pipeline

### Pipeline Stages

```mermaid
graph LR
    A[Test] --> B[Build]
    B --> C[Release]

    A --> A1[Lint]
    A --> A2[Format Check]
    A --> A3[Unit Tests]

    B --> B1[TypeScript Build]
    B --> B2[Generate Types]

    C --> C1[Semantic Release]
    C --> C2[Publish to Registry]
    C --> C3[Create Git Tag]
    C --> C4[Update Changelog]
```

### Pipeline Configuration

The `.gitlab-ci.yml` defines the following stages:

#### 1. Test Stage

- **test:lint**: Runs ESLint on source code
- **test:format**: Checks code formatting with Prettier
- **test:unit**: Runs unit tests (placeholder)

#### 2. Build Stage

- **build**: Compiles TypeScript and generates artifacts
  - Uses tsup for bundling
  - Generates ESM output
  - Creates TypeScript definitions
  - Artifacts expire in 1 week

#### 3. Release Stage

- **release**: Automated versioning and publishing
  - Only runs on main branch
  - Uses semantic-release
  - Publishes to GitLab Package Registry
  - Creates Git tags
  - Updates CHANGELOG.md
  - Artifacts never expire

### Semantic Release Workflow

```mermaid
sequenceDiagram
    participant Dev as Developer
    participant Git as Git Repository
    participant CI as GitLab CI
    participant SR as Semantic Release
    participant Reg as Package Registry

    Dev->>Git: Push to main branch
    Git->>CI: Trigger pipeline
    CI->>CI: Run tests
    CI->>CI: Build package
    CI->>SR: Run semantic-release
    SR->>SR: Analyze commits
    SR->>SR: Determine version
    SR->>SR: Generate changelog
    SR->>Git: Create tag & commit
    SR->>Reg: Publish package
    SR->>Git: Create GitLab release
```

### Release Process

The release process is fully automated using semantic-release:

1. **Commit Analysis**: Analyzes commit messages since last release
2. **Version Calculation**: Determines next version based on commit types
   - `fix:` → Patch version (1.0.x)
   - `feat:` → Minor version (1.x.0)
   - `BREAKING CHANGE:` → Major version (x.0.0)
3. **Changelog Generation**: Updates CHANGELOG.md
4. **Package Publishing**: Publishes to GitLab Package Registry
5. **Git Tagging**: Creates and pushes version tag
6. **GitLab Release**: Creates release notes on GitLab

### Environment Variables

The CI/CD pipeline uses the following variables:

- `CI_JOB_TOKEN`: GitLab CI token (automatic)
- `CI_PROJECT_ID`: Project ID (automatic)
- `CI_API_V4_URL`: GitLab API URL (automatic)
- `HUSKY`: Set to `0` to disable hooks in CI

## 📚 API Reference

### GitLabApiClient Class

The core API client that handles all GitLab REST API interactions.

#### Constructor

```typescript
constructor(instanceUrl: string, token: string)
```

#### HTTP Methods

```typescript
async fetch<T>(method: string, path: string, body?: unknown): Promise<T>
async fetchText(method: string, path: string): Promise<string>
```

#### GraphQL Methods

```typescript
/**
 * Execute a GraphQL query or mutation
 * @template T - The expected type of the data field in the GraphQL response
 * @param query - The GraphQL query or mutation string
 * @param variables - Optional variables for the query
 * @returns The data from the GraphQL response
 */
async fetchGraphQL<T>(query: string, variables?: Record<string, unknown>): Promise<T>
```

**Features:**

- Full TypeScript type safety with generic return types
- Automatic error handling for both HTTP and GraphQL errors
- Support for query variables
- Cursor-based pagination support for large result sets
- Used by TODOs, Notes, Discussions, Auto-merge, and Security tools

**Example:**

```typescript
const result = await client.fetchGraphQL<{ vulnerability: { id: string } }>(
  `mutation($id: VulnerabilityID!) {
    vulnerabilityConfirm(input: { id: $id }) {
      vulnerability { id state }
      errors
    }
  }`,
  { id: 'gid://gitlab/Vulnerability/123' }
);
```

**Pagination Example:**

```typescript
// First page
const page1 = await plugin.tool.gitlab_list_todos.execute({ first: 20 });
// Navigate with cursor
const page2 = await plugin.tool.gitlab_list_todos.execute({
  first: 20,
  after: page1.todos.pageInfo.endCursor,
});
```

#### Project ID Encoding

```typescript
private encodeProjectId(projectId: string): string
```

Handles URL encoding for project paths (e.g., `gitlab-org/gitlab` → `gitlab-org%2Fgitlab`)

### Authentication Functions

#### readTokenFromAuthStorage

```typescript
function readTokenFromAuthStorage(): string | undefined;
```

Reads GitLab token from OpenCode auth storage (`~/.local/share/opencode/auth.json`).

Supports:

- OAuth tokens: `{ type: "oauth", access: "token" }`
- API tokens: `{ type: "api", key: "token" }`

#### getGitLabClient

```typescript
function getGitLabClient(): GitLabApiClient;
```

Creates and returns a configured GitLab API client.

Priority:

1. `GITLAB_TOKEN` environment variable
2. OpenCode auth storage
3. Throws error if no token found

### Validation Functions

#### isValidGid

```typescript
function isValidGid(gid: string, expectedType?: string): boolean;
```

Validates GitLab Global ID (GID) format.

**Parameters:**

- `gid` - The GID to validate (e.g., `gid://gitlab/Vulnerability/123`)
- `expectedType` - Optional expected resource type (e.g., `'Vulnerability'`, `'Issue'`)

**Returns:** `true` if valid, `false` otherwise

**Example:**

```typescript
isValidGid('gid://gitlab/Vulnerability/123'); // true
isValidGid('gid://gitlab/Issue/456', 'Issue'); // true
isValidGid('gid://gitlab/Vulnerability/123', 'Issue'); // false (wrong type)
isValidGid('invalid-gid'); // false
```

#### validateGid

```typescript
function validateGid(gid: string, expectedType?: string): void;
```

Validates GID format and throws descriptive error if invalid.

**Parameters:**

- `gid` - The GID to validate
- `expectedType` - Optional expected resource type

**Throws:** `Error` with descriptive message if GID format is invalid

**Example:**

```typescript
validateGid('gid://gitlab/Vulnerability/123'); // No error
validateGid('invalid-gid'); // Throws: "Invalid GitLab Global ID: 'invalid-gid'. Expected format: gid://gitlab/ResourceType/{id}"
validateGid('gid://gitlab/Issue/123', 'Vulnerability'); // Throws: "Invalid GitLab Global ID of type 'Vulnerability'..."
```

**Usage in Security Tools:**

All GraphQL-based security tools automatically validate GID parameters:

- `createVulnerabilityIssue()` - validates vulnerability IDs
- `dismissVulnerability()` - validates vulnerability ID
- `confirmVulnerability()` - validates vulnerability ID
- `revertVulnerability()` - validates vulnerability ID
- `updateVulnerabilitySeverity()` - validates vulnerability IDs
- `linkVulnerabilityToIssue()` - validates both issue ID and vulnerability IDs

### Tool Schema Validation

All tools use Zod for runtime validation:

```typescript
import { tool } from '@opencode-ai/plugin';
const z = tool.schema; // Zod v4 compatible

// Example tool definition
gitlab_get_merge_request: tool({
  description: 'Get details of a specific merge request',
  args: {
    project_id: z.string().describe('The project ID or URL-encoded path'),
    mr_iid: z.number().describe('The internal ID of the merge request'),
    include_changes: z.boolean().optional().describe('Include file changes'),
  },
  execute: async (args, ctx) => {
    // Implementation
  },
});
```

### Error Handling

All API calls include comprehensive error handling:

```typescript
if (!response.ok) {
  const errorText = await response.text();
  throw new Error(`GitLab API error ${response.status}: ${errorText}`);
}
```

### Response Formatting

All tool responses are JSON-formatted:

```typescript
return JSON.stringify(result, null, 2);
```

## 🔐 Security Considerations

### Token Storage

- **Environment Variables**: Recommended for CI/CD and production
- **Auth Storage**: Convenient for local development
- **Never commit tokens**: Use `.gitignore` for sensitive files

### API Permissions

The plugin requires a GitLab token with appropriate scopes:

- `api`: Full API access (recommended)
- `read_api`: Read-only access (limited functionality)
- `read_repository`: Repository read access
- `write_repository`: Repository write access (for commits)

### Rate Limiting

GitLab API has rate limits:

- **Authenticated requests**: 2,000 requests per minute
- **Unauthenticated requests**: 10 requests per minute

The plugin does not implement rate limiting logic. Consider implementing retry logic in your application.

### HTTPS Only

The plugin enforces HTTPS for all API calls. HTTP URLs are not supported.

## 🤝 Contributing

Contributions are welcome! Please see our [Contributing Guide](https://gitlab.com/gitlab-org/editor-extensions/opencode-gitlab-plugin/-/blob/main/CONTRIBUTING.md) for detailed guidelines on:

- Code style and conventions
- Development workflow
- Testing requirements
- Submitting merge requests
- Developer Certificate of Origin and License

**Quick Start for Contributors**:

1. **Commit Messages**: Use conventional commits format

   ```
   feat(scope): add new feature
   fix(scope): fix bug
   docs(scope): update documentation
   ```

2. **Code Quality**: Ensure all checks pass

   ```bash
   npm run lint
   npm test
   ```

3. **Testing**: Add tests for new features

## 🔗 Links

- [GitLab Repository](https://gitlab.com/gitlab-org/editor-extensions/opencode-gitlab-plugin)
- [npm Package](https://www.npmjs.com/package/@gitlab/opencode-gitlab-plugin)
- [Issue Tracker](https://gitlab.com/gitlab-org/editor-extensions/opencode-gitlab-plugin/-/issues)
- [Merge Requests](https://gitlab.com/gitlab-org/editor-extensions/opencode-gitlab-plugin/-/merge_requests)
- [Contributing Guide](https://gitlab.com/gitlab-org/editor-extensions/opencode-gitlab-plugin/-/blob/main/CONTRIBUTING.md)
- [Changelog](https://gitlab.com/gitlab-org/editor-extensions/opencode-gitlab-plugin/-/blob/main/CHANGELOG.md)
- [CI/CD Pipelines](https://gitlab.com/gitlab-org/editor-extensions/opencode-gitlab-plugin/-/pipelines)
- [GitLab API Documentation](https://docs.gitlab.com/ee/api/)
- [OpenCode Plugin SDK](https://github.com/opencode-ai/plugin)

## 🙏 Acknowledgments

- **OpenCode Team**: For the plugin SDK and framework
- **GitLab**: For the comprehensive REST API
- **Contributors**: All contributors to this project

## 📞 Support

For questions, issues, or feature requests:

1. **Check existing issues**: <https://gitlab.com/gitlab-org/editor-extensions/opencode-gitlab-plugin/-/issues>
2. **Create new issue**: Use issue templates for bugs or features
3. **Discussions**: Use GitLab discussions for questions

## 📄 License

This project is licensed under the MIT License - see the [LICENSE](https://gitlab.com/gitlab-org/editor-extensions/opencode-gitlab-plugin/-/blob/main/LICENSE) file for details.

---

**Made with ❤️ for the OpenCode community**

---