opencode-gitlab-plugin 2.8.2 → 3.0.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/CHANGELOG.md +29 -0
- package/README.md +45 -3
- package/dist/index.d.ts +36 -4
- package/dist/index.js +251 -79
- package/dist/index.js.map +1 -1
- package/dist/mcp-server.cjs +447 -22
- package/dist/mcp-server.cjs.map +1 -1
- package/package.json +2 -1
package/CHANGELOG.md
CHANGED
|
@@ -2,6 +2,35 @@
|
|
|
2
2
|
|
|
3
3
|
All notable changes to this project will be documented in this file. See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
|
|
4
4
|
|
|
5
|
+
## [3.0.1](https://gitlab.com/vglafirov/opencode-gitlab-plugin/compare/v3.0.0...v3.0.1) (2026-10-06)
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
### 🐛 Bug Fixes
|
|
9
|
+
|
|
10
|
+
* **orbit:** update tools to current Knowledge Graph query DSL ([a62c60b](https://gitlab.com/vglafirov/opencode-gitlab-plugin/commit/a62c60bc195b63928868424cb5412bf579f23597))
|
|
11
|
+
|
|
12
|
+
## [3.0.0](https://gitlab.com/vglafirov/opencode-gitlab-plugin/compare/v2.8.2...v3.0.0) (2026-09-21)
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
### ⚠ BREAKING CHANGES
|
|
16
|
+
|
|
17
|
+
* the default export is a plugin definition object rather than a
|
|
18
|
+
plugin function. Anything importing the default export and calling it must use
|
|
19
|
+
the named `gitlabPlugin` export instead. OpenCode v1 hosts older than 1.18.29
|
|
20
|
+
do not understand object entrypoints and must stay on 2.x. On OpenCode v2 the
|
|
21
|
+
configuration key is `plugins`, and options move from a tuple to
|
|
22
|
+
`{ "package": "...", "options": { ... } }`; v1's `plugin` key is normalised
|
|
23
|
+
automatically.
|
|
24
|
+
|
|
25
|
+
### ✨ Features
|
|
26
|
+
|
|
27
|
+
* support the v2 plugin SDK ([0b0fe45](https://gitlab.com/vglafirov/opencode-gitlab-plugin/commit/0b0fe4521210820fe4a424499fecaee4d9f55ae6))
|
|
28
|
+
|
|
29
|
+
|
|
30
|
+
### 🐛 Bug Fixes
|
|
31
|
+
|
|
32
|
+
* **ci:** sync lockfile with npm 11.6.2 ([ceb68d7](https://gitlab.com/vglafirov/opencode-gitlab-plugin/commit/ceb68d7229d847070233566661472e43f4cdcc3a))
|
|
33
|
+
|
|
5
34
|
## [2.8.2](https://gitlab.com/vglafirov/opencode-gitlab-plugin/compare/v2.8.1...v2.8.2) (2026-09-18)
|
|
6
35
|
|
|
7
36
|
|
package/README.md
CHANGED
|
@@ -266,6 +266,14 @@ Full example with lazy-mcp configured in opencode (`~/.config/opencode/opencode.
|
|
|
266
266
|
"command": ["npx", "-y", "lazy-mcp@latest", "--config", "~/.config/lazy-mcp/servers.json"]
|
|
267
267
|
}
|
|
268
268
|
},
|
|
269
|
+
"plugins": [{ "package": "opencode-gitlab-plugin", "options": { "tools": false } }]
|
|
270
|
+
}
|
|
271
|
+
```
|
|
272
|
+
|
|
273
|
+
On OpenCode v1, use the legacy tuple form instead:
|
|
274
|
+
|
|
275
|
+
```json
|
|
276
|
+
{
|
|
269
277
|
"plugin": [["opencode-gitlab-plugin", { "tools": false }]]
|
|
270
278
|
}
|
|
271
279
|
```
|
|
@@ -298,6 +306,16 @@ export GITLAB_INSTANCE_URL=https://gitlab.example.com
|
|
|
298
306
|
|
|
299
307
|
Add the following plugin to your opencode configuration `~/.config/opencode/opencode.json`:
|
|
300
308
|
|
|
309
|
+
```json
|
|
310
|
+
{
|
|
311
|
+
"$schema": "https://opencode.ai/config.json",
|
|
312
|
+
"plugins": ["opencode-gitlab-plugin"]
|
|
313
|
+
}
|
|
314
|
+
```
|
|
315
|
+
|
|
316
|
+
The package ships both plugin SDK entrypoints, so it also works on OpenCode v1 with the
|
|
317
|
+
legacy `plugin` key:
|
|
318
|
+
|
|
301
319
|
```json
|
|
302
320
|
{
|
|
303
321
|
"$schema": "https://opencode.ai/config.json",
|
|
@@ -490,9 +508,9 @@ The plugin provides **64 tools** organized into the following categories:
|
|
|
490
508
|
### Example 1: Create and Manage Issues
|
|
491
509
|
|
|
492
510
|
```javascript
|
|
493
|
-
import
|
|
511
|
+
import { allTools } from 'opencode-gitlab-plugin';
|
|
494
512
|
|
|
495
|
-
const plugin =
|
|
513
|
+
const plugin = { tool: allTools };
|
|
496
514
|
|
|
497
515
|
// Create a new issue
|
|
498
516
|
const issue = await plugin.tool.gitlab_create_issue.execute({
|
|
@@ -782,6 +800,7 @@ await plugin.tool.gitlab_link_vulnerability_to_issue.execute({
|
|
|
782
800
|
|
|
783
801
|
```
|
|
784
802
|
opencode-gitlab-plugin/
|
|
803
|
+
├── index.ts # Package-root entrypoint for local v2 plugin loading
|
|
785
804
|
├── src/
|
|
786
805
|
│ ├── client/ # API client modules
|
|
787
806
|
│ │ ├── base.ts # Base client with HTTP & GraphQL methods
|
|
@@ -806,8 +825,12 @@ opencode-gitlab-plugin/
|
|
|
806
825
|
│ │ ├── repository.ts # Repository tool definitions
|
|
807
826
|
│ │ ├── discussions-unified.ts # Unified discussion tools (4 tools)
|
|
808
827
|
│ │ ├── notes-unified.ts # Unified notes tools (3 tools)
|
|
828
|
+
│ │ ├── index.ts # Aggregated tool registries
|
|
809
829
|
│ │ └── ... # Other tool definitions
|
|
810
|
-
│ ├──
|
|
830
|
+
│ ├── v2/ # Plugin SDK v2 entry point
|
|
831
|
+
│ │ ├── plugin.ts # Plugin.define({ id, setup })
|
|
832
|
+
│ │ └── tool-adapter.ts # v1 tool definitions -> v2 tool registrations
|
|
833
|
+
│ ├── index.ts # Main plugin entry point (v2 setup + v1 server)
|
|
811
834
|
│ ├── utils.ts # Utility functions
|
|
812
835
|
│ └── validation.ts # GID validation utilities
|
|
813
836
|
├── tests/ # Test suite (225 tests)
|
|
@@ -863,6 +886,25 @@ npm run format
|
|
|
863
886
|
npm run format:check
|
|
864
887
|
```
|
|
865
888
|
|
|
889
|
+
### Loading a Local Checkout
|
|
890
|
+
|
|
891
|
+
OpenCode v2 resolves a plugin configured by absolute path by probing
|
|
892
|
+
`<directory>/server` and `<directory>/index` — it does **not** read the package's
|
|
893
|
+
`main`/`exports`. The repository root ships an `index.ts` for exactly this, so point
|
|
894
|
+
the config at the checkout root:
|
|
895
|
+
|
|
896
|
+
```json
|
|
897
|
+
{
|
|
898
|
+
"plugins": [{ "package": "/abs/path/to/opencode-gitlab-plugin" }]
|
|
899
|
+
}
|
|
900
|
+
```
|
|
901
|
+
|
|
902
|
+
This loads `src/` directly, so OpenCode's watcher picks up edits without a rebuild.
|
|
903
|
+
Confirm it loaded with `opencode plugin list` — the `gitlab` plugin should be listed.
|
|
904
|
+
|
|
905
|
+
A path to a _file_ (for example `.../dist/index.js`) is rejected with
|
|
906
|
+
`configured plugin path must be a directory`.
|
|
907
|
+
|
|
866
908
|
### Git Hooks
|
|
867
909
|
|
|
868
910
|
The project uses Husky for Git hooks:
|
package/dist/index.d.ts
CHANGED
|
@@ -1,7 +1,19 @@
|
|
|
1
|
-
import
|
|
1
|
+
import * as _opencode_plugin_promise_plugin from '@opencode/plugin/promise/plugin';
|
|
2
|
+
import { ToolDefinition, Plugin as Plugin$1 } from '@opencode-ai/plugin';
|
|
3
|
+
import { Plugin } from '@opencode/plugin';
|
|
2
4
|
|
|
3
5
|
/**
|
|
4
|
-
*
|
|
6
|
+
* Tools exposed over the standalone MCP server (`opencode-gitlab-plugin` binary).
|
|
7
|
+
*/
|
|
8
|
+
declare const mcpTools: Record<string, ToolDefinition>;
|
|
9
|
+
/**
|
|
10
|
+
* Every tool registered by the OpenCode plugin.
|
|
11
|
+
*/
|
|
12
|
+
declare const allTools: Record<string, ToolDefinition>;
|
|
13
|
+
|
|
14
|
+
declare const PLUGIN_ID = "gitlab";
|
|
15
|
+
/**
|
|
16
|
+
* GitLab Tools Plugin for OpenCode (plugin SDK v2)
|
|
5
17
|
*
|
|
6
18
|
* Provides tools for interacting with GitLab:
|
|
7
19
|
* - Merge requests: get, list, changes, create, update, commits, pipelines, diffs (paginated), auto-merge
|
|
@@ -22,6 +34,26 @@ import { Plugin } from '@opencode-ai/plugin';
|
|
|
22
34
|
* - Git: execute safe, read-only git commands in repository
|
|
23
35
|
* - Orbit: Knowledge Graph API (status, schema, query, neighbors)
|
|
24
36
|
*/
|
|
25
|
-
declare const
|
|
37
|
+
declare const gitlabPluginV2: Plugin.Plugin;
|
|
38
|
+
|
|
39
|
+
/**
|
|
40
|
+
* GitLab Tools Plugin for OpenCode — legacy (v1) plugin SDK entrypoint.
|
|
41
|
+
*
|
|
42
|
+
* Kept so the package keeps working on OpenCode v1. New installs use the v2
|
|
43
|
+
* `setup()` implementation in `./v2/plugin.ts`.
|
|
44
|
+
*
|
|
45
|
+
* @deprecated Use the default export with the v2 plugin SDK.
|
|
46
|
+
*/
|
|
47
|
+
declare const gitlabPlugin: Plugin$1;
|
|
48
|
+
/**
|
|
49
|
+
* Dual entrypoint: OpenCode v2 calls `setup()`, OpenCode v1 calls `server()`.
|
|
50
|
+
*
|
|
51
|
+
* See https://opencode.ai/v2/docs/build/plugins/migrate-v1
|
|
52
|
+
*/
|
|
53
|
+
declare const _default: {
|
|
54
|
+
server: Plugin$1;
|
|
55
|
+
id: string;
|
|
56
|
+
setup: (context: _opencode_plugin_promise_plugin.Context) => Promise<_opencode_plugin_promise_plugin.Cleanup | void> | _opencode_plugin_promise_plugin.Cleanup | void;
|
|
57
|
+
};
|
|
26
58
|
|
|
27
|
-
export {
|
|
59
|
+
export { PLUGIN_ID, allTools, _default as default, gitlabPlugin, gitlabPluginV2, mcpTools };
|
package/dist/index.js
CHANGED
|
@@ -5450,6 +5450,50 @@ Examples:
|
|
|
5450
5450
|
// src/tools/orbit.ts
|
|
5451
5451
|
import { tool as tool18 } from "@opencode-ai/plugin";
|
|
5452
5452
|
var z18 = tool18.schema;
|
|
5453
|
+
function orbitRelTypes(entityType) {
|
|
5454
|
+
switch (entityType) {
|
|
5455
|
+
case "MergeRequest":
|
|
5456
|
+
return [
|
|
5457
|
+
"AUTHORED",
|
|
5458
|
+
"REVIEWER",
|
|
5459
|
+
"ASSIGNED",
|
|
5460
|
+
"CLOSES",
|
|
5461
|
+
"MENTIONS",
|
|
5462
|
+
"IN_PROJECT",
|
|
5463
|
+
"HAS_HEAD_PIPELINE",
|
|
5464
|
+
"TRIGGERED",
|
|
5465
|
+
"IN_MILESTONE",
|
|
5466
|
+
"HAS_LABEL"
|
|
5467
|
+
];
|
|
5468
|
+
case "WorkItem":
|
|
5469
|
+
return [
|
|
5470
|
+
"AUTHORED",
|
|
5471
|
+
"ASSIGNED",
|
|
5472
|
+
"CLOSES",
|
|
5473
|
+
"MENTIONS",
|
|
5474
|
+
"RELATED_TO",
|
|
5475
|
+
"CONTAINS",
|
|
5476
|
+
"IN_PROJECT",
|
|
5477
|
+
"IN_GROUP",
|
|
5478
|
+
"IN_MILESTONE",
|
|
5479
|
+
"HAS_LABEL"
|
|
5480
|
+
];
|
|
5481
|
+
case "User":
|
|
5482
|
+
return ["AUTHORED", "ASSIGNED", "REVIEWER", "MEMBER_OF", "OWNER", "CREATOR"];
|
|
5483
|
+
case "Project":
|
|
5484
|
+
return ["CONTAINS", "IN_PROJECT", "MEMBER_OF", "CREATOR"];
|
|
5485
|
+
case "Pipeline":
|
|
5486
|
+
return ["HAS_HEAD_PIPELINE", "TRIGGERED", "IN_PROJECT", "HAS_JOB", "HAS_STAGE"];
|
|
5487
|
+
case "File":
|
|
5488
|
+
return ["CONTAINS", "IMPORTS", "DEFINES", "CALLS", "ON_BRANCH"];
|
|
5489
|
+
case "Group":
|
|
5490
|
+
return ["CONTAINS", "MEMBER_OF", "OWNER", "IN_GROUP"];
|
|
5491
|
+
case "Commit":
|
|
5492
|
+
return ["MERGED_AT_COMMIT"];
|
|
5493
|
+
default:
|
|
5494
|
+
return ["AUTHORED", "ASSIGNED", "REVIEWER", "CLOSES", "MENTIONS", "RELATED_TO", "IN_PROJECT"];
|
|
5495
|
+
}
|
|
5496
|
+
}
|
|
5453
5497
|
var orbitTools = {
|
|
5454
5498
|
gitlab_orbit_status: tool18({
|
|
5455
5499
|
description: `Check GitLab Orbit Knowledge Graph API availability and health.
|
|
@@ -5583,47 +5627,64 @@ Note: Requires Orbit API to be available (Premium/Ultimate tier).`,
|
|
|
5583
5627
|
description: `Execute a query against the Orbit Knowledge Graph.
|
|
5584
5628
|
|
|
5585
5629
|
Query types:
|
|
5586
|
-
- traversal:
|
|
5587
|
-
- neighbors:
|
|
5630
|
+
- traversal: Fetch matching nodes or follow relationships between nodes
|
|
5631
|
+
- neighbors: Return nodes connected to one bounded node
|
|
5632
|
+
- aggregation: Count/sum/avg/group graph results
|
|
5633
|
+
- path_finding: Find a bounded path between two nodes
|
|
5588
5634
|
|
|
5589
|
-
|
|
5590
|
-
|
|
5591
|
-
|
|
5635
|
+
QUERY SHAPE (current DSL, format_version 5.x):
|
|
5636
|
+
Every query has a "query_type" and a "nodes" array of node selectors (max 5).
|
|
5637
|
+
A node selector names an entity and is made SELECTIVE via "node_ids" (exact
|
|
5638
|
+
internal ids) or "filters" (natural properties). Relationships between selectors
|
|
5639
|
+
go in a "relationships" array referencing selector "id" aliases.
|
|
5592
5640
|
|
|
5593
|
-
|
|
5641
|
+
IMPORTANT changes from older docs:
|
|
5642
|
+
- Use a top-level "nodes" ARRAY, not a single "node" object.
|
|
5643
|
+
- Pin ids with "node_ids": [123], NOT filters:{id:{op:"eq",value:123}}.
|
|
5644
|
+
- Filters use {op: value}, e.g. {"state": "merged"} or {"created_at": {"gte": "2026-01-01"}}.
|
|
5645
|
+
- A "neighbors" query uses a 1-element "nodes" array plus a top-level
|
|
5646
|
+
"neighbors": {direction, rel_types:[...]} object. rel_types is REQUIRED to
|
|
5647
|
+
bound the lookup and is capped at 10 entries.
|
|
5648
|
+
|
|
5649
|
+
Example neighbors query (an MR's graph neighbours):
|
|
5594
5650
|
{
|
|
5595
5651
|
"query_type": "neighbors",
|
|
5596
|
-
"
|
|
5597
|
-
|
|
5598
|
-
"
|
|
5599
|
-
"
|
|
5652
|
+
"nodes": [{ "id": "mr", "entity": "MergeRequest", "node_ids": [507483917] }],
|
|
5653
|
+
"neighbors": {
|
|
5654
|
+
"direction": "both",
|
|
5655
|
+
"rel_types": ["AUTHORED", "REVIEWER", "IN_PROJECT", "CLOSES", "HAS_HEAD_PIPELINE"]
|
|
5600
5656
|
},
|
|
5601
|
-
"
|
|
5602
|
-
"aggregations": [],
|
|
5603
|
-
"path": {"type": "shortest", "from": "p", "to": "p", "max_depth": 1}
|
|
5657
|
+
"limit": 30
|
|
5604
5658
|
}
|
|
5605
5659
|
|
|
5606
|
-
Example traversal
|
|
5660
|
+
Example traversal (merged MRs in a project):
|
|
5607
5661
|
{
|
|
5608
5662
|
"query_type": "traversal",
|
|
5609
|
-
"
|
|
5610
|
-
"entity": "
|
|
5611
|
-
"id": "mr",
|
|
5612
|
-
|
|
5613
|
-
|
|
5614
|
-
"
|
|
5615
|
-
"
|
|
5616
|
-
"path": {"type": "shortest", "from": "mr", "to": "mr", "max_depth": 1}
|
|
5663
|
+
"nodes": [
|
|
5664
|
+
{ "id": "project", "entity": "Project", "filters": {"full_path": "gitlab-org/gitlab"} },
|
|
5665
|
+
{ "id": "mr", "entity": "MergeRequest", "filters": {"state": "merged"},
|
|
5666
|
+
"columns": ["iid", "title", "merged_at"] }
|
|
5667
|
+
],
|
|
5668
|
+
"relationships": [{ "type": "IN_PROJECT", "from": "mr", "to": "project" }],
|
|
5669
|
+
"limit": 25
|
|
5617
5670
|
}
|
|
5618
5671
|
|
|
5619
|
-
|
|
5620
|
-
|
|
5672
|
+
Notes:
|
|
5673
|
+
- node_ids are GitLab *internal* numeric ids (not IIDs). For an MR, get it via
|
|
5674
|
+
gitlab_get_merge_request (the "id" field). For epics, use work_item_id.
|
|
5675
|
+
- Traversal/aggregation queries must include at least one selective node.
|
|
5676
|
+
- aggregation adds an "aggregations" array (e.g. [{"count":"mr"}]) with optional
|
|
5677
|
+
"group_by"; path_finding adds a "path":{from,to,max_depth} object between two
|
|
5678
|
+
node selectors. Both use the same envelope; see gitlab_orbit_schema and the
|
|
5679
|
+
Orbit query-language docs for the full grammar.
|
|
5680
|
+
- Use gitlab_orbit_schema to discover entities and relationship types.
|
|
5681
|
+
Returns nodes and edges arrays.`,
|
|
5621
5682
|
args: {
|
|
5622
5683
|
// Using a JSON string rather than a structured zod schema because the Orbit query
|
|
5623
5684
|
// format is still evolving. This allows flexibility as the API changes without
|
|
5624
5685
|
// requiring schema updates for each iteration.
|
|
5625
5686
|
query: z18.string().describe(
|
|
5626
|
-
|
|
5687
|
+
'JSON string containing the full query object. Must include "query_type" and a top-level "nodes" array of selectors (each pinned by "node_ids" or "filters"); add "relationships"/"neighbors"/"aggregations"/"path" per the query_type. See the tool description for the current DSL and worked examples.'
|
|
5627
5688
|
),
|
|
5628
5689
|
limit: z18.number().optional().describe("Maximum number of results (default: 30)")
|
|
5629
5690
|
},
|
|
@@ -5642,12 +5703,23 @@ Returns nodes array and edges array with relationship types.`,
|
|
|
5642
5703
|
2
|
|
5643
5704
|
);
|
|
5644
5705
|
}
|
|
5706
|
+
if (typeof queryObj !== "object" || queryObj === null || Array.isArray(queryObj)) {
|
|
5707
|
+
return JSON.stringify(
|
|
5708
|
+
{
|
|
5709
|
+
error: "Invalid query parameter",
|
|
5710
|
+
suggestion: 'The query must be a JSON object with a "query_type" and a "nodes" array.'
|
|
5711
|
+
},
|
|
5712
|
+
null,
|
|
5713
|
+
2
|
|
5714
|
+
);
|
|
5715
|
+
}
|
|
5716
|
+
if (args.limit !== void 0) {
|
|
5717
|
+
queryObj.limit = args.limit;
|
|
5718
|
+
}
|
|
5645
5719
|
const requestBody = {
|
|
5646
|
-
query: queryObj
|
|
5720
|
+
query: queryObj,
|
|
5721
|
+
response_format: "raw"
|
|
5647
5722
|
};
|
|
5648
|
-
if (args.limit) {
|
|
5649
|
-
requestBody.limit = args.limit;
|
|
5650
|
-
}
|
|
5651
5723
|
try {
|
|
5652
5724
|
const result = await client.fetch("POST", "/orbit/query", requestBody);
|
|
5653
5725
|
if (result.code) {
|
|
@@ -5656,7 +5728,7 @@ Returns nodes array and edges array with relationship types.`,
|
|
|
5656
5728
|
error: "Query compilation error",
|
|
5657
5729
|
code: result.code,
|
|
5658
5730
|
message: result.message,
|
|
5659
|
-
suggestion: 'Check query structure
|
|
5731
|
+
suggestion: 'Check query structure against the current DSL: top-level "nodes" array, pin ids with "node_ids", filters use {op: value}, and a "neighbors" query needs neighbors:{direction, rel_types} (max 10 rel_types).'
|
|
5660
5732
|
},
|
|
5661
5733
|
null,
|
|
5662
5734
|
2
|
|
@@ -5704,7 +5776,7 @@ Common use cases:
|
|
|
5704
5776
|
|
|
5705
5777
|
Note: Use GitLab internal numeric IDs (not IIDs).
|
|
5706
5778
|
Example: For MR !123 in gitlab-org/gitlab, first get the internal ID via gitlab_get_merge_request,
|
|
5707
|
-
then use that ID (e.g., 377844873).`,
|
|
5779
|
+
then use that ID (e.g., 377844873). For epics, use the work_item_id.`,
|
|
5708
5780
|
args: {
|
|
5709
5781
|
entity_type: z18.string().describe(
|
|
5710
5782
|
"Type of the entity (e.g., Project, MergeRequest, User, Pipeline, Commit, WorkItem, Group)"
|
|
@@ -5713,33 +5785,38 @@ then use that ID (e.g., 377844873).`,
|
|
|
5713
5785
|
"GitLab internal numeric ID (not IID). Get this from REST/GraphQL API responses."
|
|
5714
5786
|
),
|
|
5715
5787
|
direction: z18.enum(["incoming", "outgoing", "both"]).optional().describe("Direction of relationships to traverse (default: both)"),
|
|
5788
|
+
rel_types: z18.array(z18.string()).optional().describe(
|
|
5789
|
+
'Relationship types to follow. Required by the API to bound the lookup; if omitted, a sensible default set for the entity type is used. The API caps this at 10 per selector, so more than 10 entries are truncated to the first 10 and the response includes a "warnings" field. See gitlab_orbit_schema for valid edge types.'
|
|
5790
|
+
),
|
|
5716
5791
|
limit: z18.number().optional().describe("Maximum number of neighbors to return (default: 30)")
|
|
5717
5792
|
},
|
|
5718
5793
|
execute: async (args, _ctx) => {
|
|
5719
5794
|
const client = getGitLabClient();
|
|
5720
5795
|
const direction = args.direction || "both";
|
|
5796
|
+
const requestedRelTypes = args.rel_types?.length ? args.rel_types : orbitRelTypes(args.entity_type);
|
|
5797
|
+
const relTypes = requestedRelTypes.slice(0, 10);
|
|
5798
|
+
const warnings = requestedRelTypes.length > relTypes.length ? [`rel_types truncated to 10 (got ${requestedRelTypes.length})`] : [];
|
|
5721
5799
|
const queryObj = {
|
|
5722
5800
|
query_type: "neighbors",
|
|
5723
|
-
|
|
5724
|
-
|
|
5725
|
-
|
|
5726
|
-
|
|
5727
|
-
|
|
5801
|
+
nodes: [
|
|
5802
|
+
{
|
|
5803
|
+
id: "n",
|
|
5804
|
+
entity: args.entity_type,
|
|
5805
|
+
node_ids: [args.entity_id]
|
|
5728
5806
|
}
|
|
5729
|
-
|
|
5807
|
+
],
|
|
5730
5808
|
neighbors: {
|
|
5731
|
-
|
|
5732
|
-
|
|
5733
|
-
}
|
|
5734
|
-
aggregations: [],
|
|
5735
|
-
path: { type: "shortest", from: "n", to: "n", max_depth: 1 }
|
|
5809
|
+
direction,
|
|
5810
|
+
rel_types: relTypes
|
|
5811
|
+
}
|
|
5736
5812
|
};
|
|
5813
|
+
if (args.limit !== void 0) {
|
|
5814
|
+
queryObj.limit = args.limit;
|
|
5815
|
+
}
|
|
5737
5816
|
const requestBody = {
|
|
5738
|
-
query: queryObj
|
|
5817
|
+
query: queryObj,
|
|
5818
|
+
response_format: "raw"
|
|
5739
5819
|
};
|
|
5740
|
-
if (args.limit) {
|
|
5741
|
-
requestBody.limit = args.limit;
|
|
5742
|
-
}
|
|
5743
5820
|
try {
|
|
5744
5821
|
const result = await client.fetch("POST", "/orbit/query", requestBody);
|
|
5745
5822
|
if (result.code) {
|
|
@@ -5749,13 +5826,14 @@ then use that ID (e.g., 377844873).`,
|
|
|
5749
5826
|
code: result.code,
|
|
5750
5827
|
message: result.message,
|
|
5751
5828
|
entity_type: args.entity_type,
|
|
5752
|
-
entity_id: args.entity_id
|
|
5829
|
+
entity_id: args.entity_id,
|
|
5830
|
+
...warnings.length > 0 && { warnings }
|
|
5753
5831
|
},
|
|
5754
5832
|
null,
|
|
5755
5833
|
2
|
|
5756
5834
|
);
|
|
5757
5835
|
}
|
|
5758
|
-
return JSON.stringify(result, null, 2);
|
|
5836
|
+
return JSON.stringify(warnings.length > 0 ? { ...result, warnings } : result, null, 2);
|
|
5759
5837
|
} catch (error) {
|
|
5760
5838
|
const errorMessage = error instanceof Error ? error.message : String(error);
|
|
5761
5839
|
if (errorMessage.includes("404") || errorMessage.includes("not found")) {
|
|
@@ -5789,45 +5867,139 @@ then use that ID (e.g., 377844873).`,
|
|
|
5789
5867
|
})
|
|
5790
5868
|
};
|
|
5791
5869
|
|
|
5870
|
+
// src/tools/index.ts
|
|
5871
|
+
var mcpTools = {
|
|
5872
|
+
...mergeRequestTools,
|
|
5873
|
+
...issueTools,
|
|
5874
|
+
...epicTools,
|
|
5875
|
+
...pipelineTools,
|
|
5876
|
+
...repositoryTools,
|
|
5877
|
+
...searchTools,
|
|
5878
|
+
...projectTools,
|
|
5879
|
+
...userTools,
|
|
5880
|
+
...securityTools,
|
|
5881
|
+
...todoTools,
|
|
5882
|
+
...wikiTools,
|
|
5883
|
+
...workItemTools,
|
|
5884
|
+
...discussionsUnifiedTools,
|
|
5885
|
+
...notesUnifiedTools,
|
|
5886
|
+
...gitTools,
|
|
5887
|
+
...auditTools,
|
|
5888
|
+
...awardEmojiTools
|
|
5889
|
+
};
|
|
5890
|
+
var allTools = {
|
|
5891
|
+
...mcpTools,
|
|
5892
|
+
...orbitTools
|
|
5893
|
+
};
|
|
5894
|
+
|
|
5895
|
+
// src/v2/plugin.ts
|
|
5896
|
+
import { Plugin } from "@opencode/plugin";
|
|
5897
|
+
|
|
5898
|
+
// src/v2/tool-adapter.ts
|
|
5899
|
+
import { tool as tool19 } from "@opencode-ai/plugin";
|
|
5900
|
+
var z19 = tool19.schema;
|
|
5901
|
+
function toInputSchema(args) {
|
|
5902
|
+
const schema = z19.toJSONSchema(z19.object(args ?? {}), { io: "input" });
|
|
5903
|
+
delete schema["$schema"];
|
|
5904
|
+
return {
|
|
5905
|
+
type: "object",
|
|
5906
|
+
properties: {},
|
|
5907
|
+
additionalProperties: false,
|
|
5908
|
+
...schema
|
|
5909
|
+
};
|
|
5910
|
+
}
|
|
5911
|
+
function toToolResult(result) {
|
|
5912
|
+
if (typeof result === "string") {
|
|
5913
|
+
return { content: result };
|
|
5914
|
+
}
|
|
5915
|
+
const metadata = { ...result.metadata ?? {} };
|
|
5916
|
+
if (result.title !== void 0) metadata["title"] = result.title;
|
|
5917
|
+
if (result.attachments !== void 0) metadata["attachments"] = result.attachments;
|
|
5918
|
+
return {
|
|
5919
|
+
content: result.output,
|
|
5920
|
+
...Object.keys(metadata).length > 0 ? { metadata } : {}
|
|
5921
|
+
};
|
|
5922
|
+
}
|
|
5923
|
+
function toLegacyContext(context, directory, worktree) {
|
|
5924
|
+
return {
|
|
5925
|
+
sessionID: context.sessionID,
|
|
5926
|
+
messageID: context.messageID,
|
|
5927
|
+
agent: context.agent,
|
|
5928
|
+
directory,
|
|
5929
|
+
worktree,
|
|
5930
|
+
abort: context.signal,
|
|
5931
|
+
metadata: (update) => void context.progress(update),
|
|
5932
|
+
ask: async () => {
|
|
5933
|
+
}
|
|
5934
|
+
};
|
|
5935
|
+
}
|
|
5936
|
+
function adaptTool(name, definition, options) {
|
|
5937
|
+
const validator = z19.object(definition.args ?? {});
|
|
5938
|
+
return {
|
|
5939
|
+
name,
|
|
5940
|
+
description: definition.description,
|
|
5941
|
+
input: toInputSchema(definition.args),
|
|
5942
|
+
async execute(input, context) {
|
|
5943
|
+
const parsed = validator.parse(input ?? {});
|
|
5944
|
+
const legacyContext = toLegacyContext(context, options.directory, options.worktree);
|
|
5945
|
+
const result = await definition.execute(
|
|
5946
|
+
parsed,
|
|
5947
|
+
legacyContext
|
|
5948
|
+
);
|
|
5949
|
+
return toToolResult(result);
|
|
5950
|
+
}
|
|
5951
|
+
};
|
|
5952
|
+
}
|
|
5953
|
+
function adaptTools(tools, options) {
|
|
5954
|
+
return Object.entries(tools).map(([name, definition]) => adaptTool(name, definition, options));
|
|
5955
|
+
}
|
|
5956
|
+
|
|
5957
|
+
// src/v2/plugin.ts
|
|
5958
|
+
var PLUGIN_ID = "gitlab";
|
|
5959
|
+
var LAZY_MCP_HINT = `## GitLab Tools via lazy-mcp
|
|
5960
|
+
GitLab API tools (MRs, issues, pipelines, security, search, repos, users, todos, work items, discussions, notes, audit, git, award emoji) are served via the "gitlab" MCP server through lazy-mcp. Use lazy-mcp_list_commands with server "gitlab" to discover and call them.
|
|
5961
|
+
DAP tools (agents, flows, memory, skills) are on the "gitlab-dap" server instead.`;
|
|
5962
|
+
var gitlabPluginV2 = Plugin.define({
|
|
5963
|
+
id: PLUGIN_ID,
|
|
5964
|
+
async setup(ctx) {
|
|
5965
|
+
if (ctx.options["tools"] === false) {
|
|
5966
|
+
await ctx.session.hook("context", (event) => {
|
|
5967
|
+
event.system.push({ type: "text", text: LAZY_MCP_HINT });
|
|
5968
|
+
});
|
|
5969
|
+
return;
|
|
5970
|
+
}
|
|
5971
|
+
const directory = ctx.location.directory;
|
|
5972
|
+
const worktree = ctx.location.project.directory ?? directory;
|
|
5973
|
+
const tools = adaptTools(allTools, { directory, worktree });
|
|
5974
|
+
await ctx.tool.transform((editor) => {
|
|
5975
|
+
for (const definition of tools) {
|
|
5976
|
+
editor.add(definition);
|
|
5977
|
+
}
|
|
5978
|
+
});
|
|
5979
|
+
}
|
|
5980
|
+
});
|
|
5981
|
+
|
|
5792
5982
|
// src/index.ts
|
|
5793
5983
|
var gitlabPlugin = async (_input, options) => {
|
|
5794
|
-
if (options?.tools === false) {
|
|
5984
|
+
if (options?.["tools"] === false) {
|
|
5795
5985
|
return {
|
|
5796
|
-
"experimental.chat.system.transform": async (
|
|
5797
|
-
output.system.push(
|
|
5798
|
-
`## GitLab Tools via lazy-mcp
|
|
5799
|
-
GitLab API tools (MRs, issues, pipelines, security, search, repos, users, todos, work items, discussions, notes, audit, git, award emoji) are served via the "gitlab" MCP server through lazy-mcp. Use lazy-mcp_list_commands with server "gitlab" to discover and call them.
|
|
5800
|
-
DAP tools (agents, flows, memory, skills) are on the "gitlab-dap" server instead.`
|
|
5801
|
-
);
|
|
5986
|
+
"experimental.chat.system.transform": async (_hookInput, output) => {
|
|
5987
|
+
output.system.push(LAZY_MCP_HINT);
|
|
5802
5988
|
}
|
|
5803
5989
|
};
|
|
5804
5990
|
}
|
|
5805
|
-
return {
|
|
5806
|
-
|
|
5807
|
-
|
|
5808
|
-
|
|
5809
|
-
|
|
5810
|
-
...pipelineTools,
|
|
5811
|
-
...repositoryTools,
|
|
5812
|
-
...searchTools,
|
|
5813
|
-
...projectTools,
|
|
5814
|
-
...userTools,
|
|
5815
|
-
...securityTools,
|
|
5816
|
-
...todoTools,
|
|
5817
|
-
...wikiTools,
|
|
5818
|
-
...workItemTools,
|
|
5819
|
-
...discussionsUnifiedTools,
|
|
5820
|
-
...notesUnifiedTools,
|
|
5821
|
-
...gitTools,
|
|
5822
|
-
...auditTools,
|
|
5823
|
-
...awardEmojiTools,
|
|
5824
|
-
...orbitTools
|
|
5825
|
-
}
|
|
5826
|
-
};
|
|
5991
|
+
return { tool: allTools };
|
|
5992
|
+
};
|
|
5993
|
+
var index_default = {
|
|
5994
|
+
...gitlabPluginV2,
|
|
5995
|
+
server: gitlabPlugin
|
|
5827
5996
|
};
|
|
5828
|
-
var index_default = gitlabPlugin;
|
|
5829
5997
|
export {
|
|
5998
|
+
PLUGIN_ID,
|
|
5999
|
+
allTools,
|
|
5830
6000
|
index_default as default,
|
|
5831
|
-
gitlabPlugin
|
|
6001
|
+
gitlabPlugin,
|
|
6002
|
+
gitlabPluginV2,
|
|
6003
|
+
mcpTools
|
|
5832
6004
|
};
|
|
5833
6005
|
//# sourceMappingURL=index.js.map
|