opencode-gitlab-dap 1.0.0 → 1.1.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 CHANGED
@@ -1,235 +1,132 @@
1
1
  # opencode-gitlab-dap
2
2
 
3
- OpenCode plugin for GitLab Duo Agent Platform (DAP) workflow model discovery and selection.
3
+ An [opencode](https://opencode.ai) plugin that discovers GitLab foundational and custom agents
4
+ from the [GitLab AI Catalog](https://docs.gitlab.com/ee/user/ai_catalog/) and injects them as
5
+ native agents into the opencode agent picker.
4
6
 
5
- ---
7
+ ## Requirements
6
8
 
7
- ## Overview
8
-
9
- This plugin connects OpenCode to the GitLab Duo Agent Platform so users can discover and select workflow models configured for their GitLab namespace. It detects the current GitLab project, queries the DAP API for available models, caches the user's choice per project, and surfaces a TUI selection prompt when multiple models are available.
10
-
11
- ---
12
-
13
- ## Architecture
14
-
15
- ```mermaid
16
- sequenceDiagram
17
- participant TUI as OpenCode TUI
18
- participant Server as OpenCode Server
19
- participant Plugin as gitlab-dap Plugin
20
- participant Cache as GitLabModelCache
21
- participant API as GitLab DAP API
22
-
23
- TUI->>Server: POST /plugin/gitlab/discover
24
- Server->>Plugin: route handler
25
- Plugin->>Cache: check cached selection
26
- alt cache hit
27
- Plugin-->>Server: { status: "cached", model }
28
- else no cache
29
- Plugin->>API: detect project + discover models
30
- API-->>Plugin: DiscoveredModels
31
- alt pinned model
32
- Plugin-->>Server: { status: "pinned", model }
33
- else multiple models
34
- Plugin->>Server: askUser via plugin-select bus
35
- Server->>TUI: render selection prompt
36
- TUI-->>Server: user picks model
37
- Server-->>Plugin: selected ref
38
- Plugin->>Cache: save selection
39
- Plugin-->>Server: { status: "selected", model }
40
- else default only
41
- Plugin-->>Server: { status: "default", model }
42
- end
43
- end
44
- Server-->>TUI: JSON response
45
- ```
46
-
47
- ---
9
+ - opencode with the `gitlab` provider configured and Duo Workflow (DWS) enabled
10
+ - GitLab OAuth or PAT authentication (via `opencode-gitlab-auth` or manual config)
11
+ - GitLab project with AI Catalog agents enabled
12
+ - `gitlab-ai-provider` >= 6.2.0 (peer dependency, bundled with opencode's gitlab provider)
48
13
 
49
14
  ## Install
50
15
 
51
- This plugin is bundled internally with OpenCode. It is not installed as a standalone package. The plugin entry is registered automatically and exposes routes under the `/plugin/gitlab/` prefix.
52
-
53
- ---
54
-
55
- ## Configure
56
-
57
- Authentication is resolved in this order:
58
-
59
- 1. Request headers (`x-plugin-auth-token`, `x-plugin-auth-instance`)
60
- 2. OpenCode auth store via `input.getAuth("gitlab")` (OAuth or API key)
61
- 3. Environment variables as fallback
62
-
63
- | Variable | Description | Default |
64
- | ------------------------ | ------------------------------------------------------- | -------------------- |
65
- | `GITLAB_INSTANCE_URL` | Base URL of your GitLab instance | `https://gitlab.com` |
66
- | `GITLAB_TOKEN` | Personal or project access token (when not using OAuth) | -- |
67
- | `GITLAB_OAUTH_CLIENT_ID` | OAuth application ID for the OAuth flow | -- |
68
-
69
- The plugin also reads `x-plugin-directory` from request headers to scope cache and project detection to a specific working directory.
70
-
71
- ---
72
-
73
- ## Routes
74
-
75
- All routes are prefixed with `/plugin/gitlab`.
76
-
77
- ### POST /discover
78
-
79
- Detect the GitLab project, query DAP for available models, and return the resolved model or prompt the user to pick one.
80
-
81
- **Request:**
82
-
83
- ```json
84
- { "fresh": true }
85
- ```
86
-
87
- Set `fresh: true` to clear the cache and re-discover. The body is optional.
88
-
89
- **Response (pinned):**
16
+ Add to your `~/.config/opencode/opencode.json`:
90
17
 
91
18
  ```json
92
19
  {
93
- "status": "pinned",
94
- "model": { "name": "Claude 4", "ref": "claude_4" }
20
+ "plugin": ["/path/to/opencode-gitlab-dap"]
95
21
  }
96
22
  ```
97
23
 
98
- **Response (asked then selected):**
24
+ Or once published to npm:
99
25
 
100
- ```json
101
- {
102
- "status": "selected",
103
- "model": { "name": "GPT-5", "ref": "gpt_5" }
104
- }
26
+ ```bash
27
+ opencode plugin opencode-gitlab-dap
105
28
  ```
106
29
 
107
- **Response (no auth):**
108
-
109
- ```json
110
- {
111
- "status": "no_provider",
112
- "error": "No auth token found"
113
- }
114
- ```
30
+ No further configuration needed. The plugin reads GitLab auth and model cache automatically.
115
31
 
116
- Possible `status` values: `pinned`, `cached`, `default`, `selected`, `dismissed`, `no_provider`, `no_models`, `error`.
32
+ ## How it works
117
33
 
118
- ---
34
+ On every opencode startup the plugin:
119
35
 
120
- ### POST /reply
36
+ 1. Reads the GitLab auth token from `~/.local/share/opencode/auth.json`
37
+ 2. Reads the already-cached GitLab workflow model from `gitlab-ai-provider`'s model cache (no extra network call)
38
+ 3. Queries two GitLab GraphQL APIs in parallel:
39
+ - `aiFoundationalChatAgents` — project-scoped foundational agents (Planner, Data Analyst, Security Analyst, GitLab Duo, etc.)
40
+ - `aiCatalogConfiguredItems` — custom agents explicitly enabled for the project
41
+ 4. Injects all discovered agents into opencode's config via the `config` hook — they appear in the `/agents` dialog and the Tab agent picker
42
+ 5. Each agent runs through GitLab Duo Agent Platform (DWS), with tool actions executed locally by opencode
121
43
 
122
- Save a model selection directly, bypassing the interactive prompt.
44
+ ## Agent types
123
45
 
124
- **Request:**
46
+ ### Foundational agents
125
47
 
126
- ```json
127
- { "ref": "claude_4" }
128
- ```
48
+ Built-in GitLab agents available based on your project's Duo Workflow license:
129
49
 
130
- **Response:**
50
+ | Agent | Description |
51
+ | ---------------- | ------------------------------- |
52
+ | GitLab Duo | General-purpose agentic chat |
53
+ | Planner | Issue and project planning |
54
+ | Data Analyst | GitLab data analysis (GLQL) |
55
+ | Security Analyst | Security vulnerability analysis |
131
56
 
132
- ```json
133
- { "ref": "claude_4", "name": "Claude 4" }
134
- ```
57
+ These are fetched via `aiFoundationalChatAgents` and are scoped to what's enabled for your project.
135
58
 
136
- ---
59
+ ### Custom agents
137
60
 
138
- ### POST /clear
61
+ User-defined agents created in the [GitLab AI Catalog](https://docs.gitlab.com/ee/user/ai_catalog/).
62
+ Custom agents must be explicitly enabled for the project to appear.
139
63
 
140
- Clear the cached discovery and selection for the current project.
64
+ Custom agents run with their full `flowConfig` (system prompt, tools, routing) sent directly to DWS.
65
+ Their sessions are linked to the correct agent page in the GitLab UI (`/automate/agents/<id>/`).
141
66
 
142
- **Response:**
67
+ ## Agent picker UX
143
68
 
144
- ```json
145
- true
146
- ```
69
+ Agents appear in:
147
70
 
148
- ---
71
+ - **`/agents` slash command** — shows all agents with `[GitLab Foundational Agent]` or `[GitLab Custom Agent]` labels
72
+ - **Tab agent switcher** — switch the active agent for the current session
73
+ - **Session header** — shows the active agent name
149
74
 
150
- ### GET /models
75
+ ## Self-hosted GitLab
151
76
 
152
- Return the current discovery state without triggering a new discovery.
77
+ For OAuth-based auth, the `enterpriseUrl` from `opencode-gitlab-auth` is used automatically.
153
78
 
154
- **Response:**
79
+ For PAT-based auth on self-hosted instances, set:
155
80
 
156
- ```json
157
- {
158
- "models": [
159
- { "name": "Claude 4", "ref": "claude_4" },
160
- { "name": "GPT-5", "ref": "gpt_5" }
161
- ],
162
- "pinned": null,
163
- "default": { "name": "Claude 4", "ref": "claude_4" },
164
- "switching": true
165
- }
81
+ ```bash
82
+ export GITLAB_INSTANCE_URL=https://your-instance.com
166
83
  ```
167
84
 
168
- ---
169
-
170
- ## Discovery flow
171
-
172
- The `discover` function resolves models through a priority chain:
173
-
174
- 1. **No token** -- returns `no_provider` immediately.
175
- 2. **Project detection** -- uses `GitLabProjectDetector` to find the namespace from the working directory. Fails with `no_provider` if no project is found.
176
- 3. **DAP query** -- calls `GitLabModelDiscovery.discover()` with the namespace GID. Returns `no_models` if the API returns nothing.
177
- 4. **Pinned** -- if the namespace has a pinned model, it is saved to cache and returned.
178
- 5. **Cached** -- if a previous selection exists in `GitLabModelCache`, it is returned.
179
- 6. **Asked** -- if selectable models exist and nothing is cached, the list is returned with `status: "asked"` so the route handler can prompt the user.
180
- 7. **Default** -- if only a default model exists (no selectable list), it is saved and returned.
181
- 8. **No models** -- fallthrough when none of the above match.
182
-
183
- ---
85
+ ## Logging
184
86
 
185
- ## Selection flow
87
+ The plugin writes debug logs to:
186
88
 
187
- When discovery returns `status: "asked"`, the route handler triggers an interactive prompt:
188
-
189
- 1. The `/discover` route calls `askUser()` with the list of models.
190
- 2. `askUser` sends a `POST` to the internal `plugin-select/ask` endpoint on the OpenCode server.
191
- 3. The server forwards the selection prompt to the TUI.
192
- 4. When the user picks a model, the response flows back through the same path.
193
- 5. The selected `ref` is saved via `saveSelection()` into `GitLabModelCache`.
194
- 6. Subsequent `/discover` calls return `status: "cached"` without prompting again.
195
-
196
- If the user dismisses the prompt, the response is `{ "status": "dismissed" }`.
197
-
198
- ---
89
+ ```
90
+ ~/.local/share/opencode/log/gitlab-dap.log
91
+ ```
199
92
 
200
- ## Develop
93
+ Useful for debugging agent discovery issues.
201
94
 
202
- ### Build
95
+ ## Architecture
203
96
 
204
- ```sh
205
- npm run build
97
+ ```
98
+ Plugin init
99
+ └─ readAuth() reads ~/.local/share/opencode/auth.json
100
+ └─ GitLabModelCache reads ~/.cache/opencode/gitlab-workflow-model-cache.json
101
+ └─ fetchCatalogAgents()
102
+ ├─ aiFoundationalChatAgents (GraphQL) → foundational agents
103
+ └─ aiCatalogConfiguredItems (GraphQL) → custom agents
104
+ └─ aiCatalogAgentFlowConfig (GraphQL) → per-agent flow config YAML
105
+ └─ config hook mutates cfg.agent in-place
106
+ └─ Agent.Service reads the same config object → agents appear in picker
107
+
108
+ Per prompt (via gitlab-ai-provider):
109
+ └─ providerOptions.gitlab.workflowDefinition → DWS workflow type
110
+ └─ providerOptions.gitlab.flowConfig → custom agent flow config
111
+ └─ providerOptions.gitlab.aiCatalogItemVersionId → links session in GitLab UI
206
112
  ```
207
113
 
208
- Uses [tsup](https://tsup.egoist.dev) to produce CJS, ESM, and `.d.ts` outputs in `dist/`.
114
+ ## Development
209
115
 
210
- ### Test
116
+ ```bash
117
+ # Install dependencies
118
+ bun install
211
119
 
212
- ```sh
120
+ # Run tests
213
121
  npm test
214
- ```
215
-
216
- Runs [Vitest](https://vitest.dev) against `test/`. Watch mode is available with `npm run test:watch`.
217
122
 
218
- ### Lint and type-check
123
+ # Build dist
124
+ npm run build
219
125
 
220
- ```sh
221
- npm run lint
126
+ # Type check
222
127
  npm run type-check
223
128
  ```
224
129
 
225
- ### Clean
226
-
227
- ```sh
228
- npm run clean
229
- ```
230
-
231
- ---
232
-
233
130
  ## License
234
131
 
235
- [MIT](./LICENSE)
132
+ MIT