opencode-gitlab-dap 0.1.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 +79 -182
- package/dist/index.cjs +2793 -164
- package/dist/index.cjs.map +1 -1
- package/dist/index.js +2785 -164
- package/dist/index.js.map +1 -1
- package/package.json +6 -7
package/README.md
CHANGED
|
@@ -1,235 +1,132 @@
|
|
|
1
1
|
# opencode-gitlab-dap
|
|
2
2
|
|
|
3
|
-
|
|
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
|
-
|
|
8
|
-
|
|
9
|
-
|
|
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
|
-
|
|
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
|
-
"
|
|
94
|
-
"model": { "name": "Claude 4", "ref": "claude_4" }
|
|
20
|
+
"plugin": ["/path/to/opencode-gitlab-dap"]
|
|
95
21
|
}
|
|
96
22
|
```
|
|
97
23
|
|
|
98
|
-
|
|
24
|
+
Or once published to npm:
|
|
99
25
|
|
|
100
|
-
```
|
|
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
|
-
|
|
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
|
-
|
|
32
|
+
## How it works
|
|
117
33
|
|
|
118
|
-
|
|
34
|
+
On every opencode startup the plugin:
|
|
119
35
|
|
|
120
|
-
|
|
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
|
-
|
|
44
|
+
## Agent types
|
|
123
45
|
|
|
124
|
-
|
|
46
|
+
### Foundational agents
|
|
125
47
|
|
|
126
|
-
|
|
127
|
-
{ "ref": "claude_4" }
|
|
128
|
-
```
|
|
48
|
+
Built-in GitLab agents available based on your project's Duo Workflow license:
|
|
129
49
|
|
|
130
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
67
|
+
## Agent picker UX
|
|
143
68
|
|
|
144
|
-
|
|
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
|
-
|
|
75
|
+
## Self-hosted GitLab
|
|
151
76
|
|
|
152
|
-
|
|
77
|
+
For OAuth-based auth, the `enterpriseUrl` from `opencode-gitlab-auth` is used automatically.
|
|
153
78
|
|
|
154
|
-
|
|
79
|
+
For PAT-based auth on self-hosted instances, set:
|
|
155
80
|
|
|
156
|
-
```
|
|
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
|
-
|
|
87
|
+
The plugin writes debug logs to:
|
|
186
88
|
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
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
|
-
|
|
93
|
+
Useful for debugging agent discovery issues.
|
|
201
94
|
|
|
202
|
-
|
|
95
|
+
## Architecture
|
|
203
96
|
|
|
204
|
-
```
|
|
205
|
-
|
|
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
|
-
|
|
114
|
+
## Development
|
|
209
115
|
|
|
210
|
-
|
|
116
|
+
```bash
|
|
117
|
+
# Install dependencies
|
|
118
|
+
bun install
|
|
211
119
|
|
|
212
|
-
|
|
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
|
-
|
|
123
|
+
# Build dist
|
|
124
|
+
npm run build
|
|
219
125
|
|
|
220
|
-
|
|
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
|
-
|
|
132
|
+
MIT
|