opencode-gitlab-dap 1.0.0 → 1.1.1

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,130 @@
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 }
16
+ ```bash
17
+ opencode plugin opencode-gitlab-dap
85
18
  ```
86
19
 
87
- Set `fresh: true` to clear the cache and re-discover. The body is optional.
88
-
89
- **Response (pinned):**
20
+ Or add to your `~/.config/opencode/opencode.json`:
90
21
 
91
22
  ```json
92
23
  {
93
- "status": "pinned",
94
- "model": { "name": "Claude 4", "ref": "claude_4" }
24
+ "plugin": ["opencode-gitlab-dap"]
95
25
  }
96
26
  ```
97
27
 
98
- **Response (asked then selected):**
28
+ No further configuration needed. The plugin reads GitLab auth and model cache automatically.
99
29
 
100
- ```json
101
- {
102
- "status": "selected",
103
- "model": { "name": "GPT-5", "ref": "gpt_5" }
104
- }
105
- ```
30
+ ## How it works
106
31
 
107
- **Response (no auth):**
32
+ On every opencode startup the plugin:
108
33
 
109
- ```json
110
- {
111
- "status": "no_provider",
112
- "error": "No auth token found"
113
- }
114
- ```
34
+ 1. Reads the GitLab auth token from `~/.local/share/opencode/auth.json`
35
+ 2. Reads the already-cached GitLab workflow model from `gitlab-ai-provider`'s model cache (no extra network call)
36
+ 3. Queries two GitLab GraphQL APIs in parallel:
37
+ - `aiFoundationalChatAgents` project-scoped foundational agents (Planner, Data Analyst, Security Analyst, GitLab Duo, etc.)
38
+ - `aiCatalogConfiguredItems` — custom agents explicitly enabled for the project
39
+ 4. Injects all discovered agents into opencode's config via the `config` hook — they appear in the `/agents` dialog and the Tab agent picker
40
+ 5. Each agent runs through GitLab Duo Agent Platform (DWS), with tool actions executed locally by opencode
115
41
 
116
- Possible `status` values: `pinned`, `cached`, `default`, `selected`, `dismissed`, `no_provider`, `no_models`, `error`.
42
+ ## Agent types
117
43
 
118
- ---
44
+ ### Foundational agents
119
45
 
120
- ### POST /reply
46
+ Built-in GitLab agents available based on your project's Duo Workflow license:
121
47
 
122
- Save a model selection directly, bypassing the interactive prompt.
48
+ | Agent | Description |
49
+ | ---------------- | ------------------------------- |
50
+ | GitLab Duo | General-purpose agentic chat |
51
+ | Planner | Issue and project planning |
52
+ | Data Analyst | GitLab data analysis (GLQL) |
53
+ | Security Analyst | Security vulnerability analysis |
123
54
 
124
- **Request:**
55
+ These are fetched via `aiFoundationalChatAgents` and are scoped to what's enabled for your project.
125
56
 
126
- ```json
127
- { "ref": "claude_4" }
128
- ```
129
-
130
- **Response:**
131
-
132
- ```json
133
- { "ref": "claude_4", "name": "Claude 4" }
134
- ```
135
-
136
- ---
57
+ ### Custom agents
137
58
 
138
- ### POST /clear
59
+ User-defined agents created in the [GitLab AI Catalog](https://docs.gitlab.com/ee/user/ai_catalog/).
60
+ Custom agents must be explicitly enabled for the project to appear.
139
61
 
140
- Clear the cached discovery and selection for the current project.
62
+ Custom agents run with their full `flowConfig` (system prompt, tools, routing) sent directly to DWS.
63
+ Their sessions are linked to the correct agent page in the GitLab UI (`/automate/agents/<id>/`).
141
64
 
142
- **Response:**
65
+ ## Agent picker UX
143
66
 
144
- ```json
145
- true
146
- ```
67
+ Agents appear in:
147
68
 
148
- ---
69
+ - **`/agents` slash command** — shows all agents with `[GitLab Foundational Agent]` or `[GitLab Custom Agent]` labels
70
+ - **Tab agent switcher** — switch the active agent for the current session
71
+ - **Session header** — shows the active agent name
149
72
 
150
- ### GET /models
73
+ ## Self-hosted GitLab
151
74
 
152
- Return the current discovery state without triggering a new discovery.
75
+ For OAuth-based auth, the `enterpriseUrl` from `opencode-gitlab-auth` is used automatically.
153
76
 
154
- **Response:**
77
+ For PAT-based auth on self-hosted instances, set:
155
78
 
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
- }
79
+ ```bash
80
+ export GITLAB_INSTANCE_URL=https://your-instance.com
166
81
  ```
167
82
 
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
- ---
83
+ ## Logging
184
84
 
185
- ## Selection flow
85
+ The plugin writes debug logs to:
186
86
 
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
- ---
87
+ ```
88
+ ~/.local/share/opencode/log/gitlab-dap.log
89
+ ```
199
90
 
200
- ## Develop
91
+ Useful for debugging agent discovery issues.
201
92
 
202
- ### Build
93
+ ## Architecture
203
94
 
204
- ```sh
205
- npm run build
95
+ ```
96
+ Plugin init
97
+ └─ readAuth() reads ~/.local/share/opencode/auth.json
98
+ └─ GitLabModelCache reads ~/.cache/opencode/gitlab-workflow-model-cache.json
99
+ └─ fetchCatalogAgents()
100
+ ├─ aiFoundationalChatAgents (GraphQL) → foundational agents
101
+ └─ aiCatalogConfiguredItems (GraphQL) → custom agents
102
+ └─ aiCatalogAgentFlowConfig (GraphQL) → per-agent flow config YAML
103
+ └─ config hook mutates cfg.agent in-place
104
+ └─ Agent.Service reads the same config object → agents appear in picker
105
+
106
+ Per prompt (via gitlab-ai-provider):
107
+ └─ providerOptions.gitlab.workflowDefinition → DWS workflow type
108
+ └─ providerOptions.gitlab.flowConfig → custom agent flow config
109
+ └─ providerOptions.gitlab.aiCatalogItemVersionId → links session in GitLab UI
206
110
  ```
207
111
 
208
- Uses [tsup](https://tsup.egoist.dev) to produce CJS, ESM, and `.d.ts` outputs in `dist/`.
112
+ ## Development
209
113
 
210
- ### Test
114
+ ```bash
115
+ # Install dependencies
116
+ bun install
211
117
 
212
- ```sh
118
+ # Run tests
213
119
  npm test
214
- ```
215
-
216
- Runs [Vitest](https://vitest.dev) against `test/`. Watch mode is available with `npm run test:watch`.
217
120
 
218
- ### Lint and type-check
121
+ # Build dist
122
+ npm run build
219
123
 
220
- ```sh
221
- npm run lint
124
+ # Type check
222
125
  npm run type-check
223
126
  ```
224
127
 
225
- ### Clean
226
-
227
- ```sh
228
- npm run clean
229
- ```
230
-
231
- ---
232
-
233
128
  ## License
234
129
 
235
- [MIT](./LICENSE)
130
+ MIT