opencode-gitlab-dap 1.6.0 → 1.7.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 +31 -1
- package/dist/chunk-DPR6OUYG.js +119 -0
- package/dist/chunk-DPR6OUYG.js.map +1 -0
- package/dist/index.cjs +1463 -1074
- package/dist/index.cjs.map +1 -1
- package/dist/index.js +1216 -962
- package/dist/index.js.map +1 -1
- package/dist/mcp-servers-2HCDB7XM.js +11 -0
- package/dist/mcp-servers-2HCDB7XM.js.map +1 -0
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -110,7 +110,9 @@ The plugin provides a multi-round design workflow:
|
|
|
110
110
|
|
|
111
111
|
The vendored `flow_v2.json` schema from GitLab Rails powers client-side validation using `ajv`, catching errors before hitting the API.
|
|
112
112
|
|
|
113
|
-
###
|
|
113
|
+
### 26 Tools
|
|
114
|
+
|
|
115
|
+
#### DAP Tools (20)
|
|
114
116
|
|
|
115
117
|
| Tool | Description |
|
|
116
118
|
| --------------------------------- | ------------------------------------------------------- |
|
|
@@ -135,6 +137,34 @@ The vendored `flow_v2.json` schema from GitLab Rails powers client-side validati
|
|
|
135
137
|
| `gitlab_get_workflow_status` | Monitor workflow execution status and logs |
|
|
136
138
|
| `gitlab_list_project_mcp_servers` | List MCP servers available for project agents |
|
|
137
139
|
|
|
140
|
+
#### Wiki Memory Tools (6)
|
|
141
|
+
|
|
142
|
+
Persistent project memory and skill storage via GitLab wikis.
|
|
143
|
+
|
|
144
|
+
| Tool | Description |
|
|
145
|
+
| -------------------- | -------------------------------------------------------- |
|
|
146
|
+
| `gitlab_wiki_read` | Read a wiki page by slug |
|
|
147
|
+
| `gitlab_wiki_write` | Create or update a wiki page (upsert) |
|
|
148
|
+
| `gitlab_wiki_append` | Append text to a wiki page (create if missing) |
|
|
149
|
+
| `gitlab_wiki_list` | List wiki pages with optional prefix filter |
|
|
150
|
+
| `gitlab_wiki_delete` | Delete a wiki page |
|
|
151
|
+
| `gitlab_wiki_search` | Search wiki pages by content (server-side GitLab search) |
|
|
152
|
+
|
|
153
|
+
All wiki tools support both project wikis (default) and group wikis (`scope="groups"`).
|
|
154
|
+
|
|
155
|
+
##### Recommended Wiki Structure
|
|
156
|
+
|
|
157
|
+
```
|
|
158
|
+
memory/
|
|
159
|
+
├── facts # Stable project truths (append-only)
|
|
160
|
+
├── decisions # Architecture decisions with context
|
|
161
|
+
├── patterns # Observations across sessions
|
|
162
|
+
└── sessions/ # Per-session learning logs
|
|
163
|
+
skills/
|
|
164
|
+
├── index # Skill routing table
|
|
165
|
+
└── <name> # Individual skill pages
|
|
166
|
+
```
|
|
167
|
+
|
|
138
168
|
### Dynamic Refresh
|
|
139
169
|
|
|
140
170
|
After enabling or disabling an agent/flow, the plugin automatically refreshes the
|
|
@@ -0,0 +1,119 @@
|
|
|
1
|
+
// src/graphql.ts
|
|
2
|
+
async function gql(instanceUrl, token, query, variables) {
|
|
3
|
+
const res = await fetch(`${instanceUrl.replace(/\/$/, "")}/api/graphql`, {
|
|
4
|
+
method: "POST",
|
|
5
|
+
headers: { "Content-Type": "application/json", Authorization: `Bearer ${token}` },
|
|
6
|
+
body: JSON.stringify({ query, variables })
|
|
7
|
+
});
|
|
8
|
+
const json = await res.json();
|
|
9
|
+
if (json.errors?.length) throw new Error(json.errors[0].message);
|
|
10
|
+
return json.data;
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
// src/mcp-servers.ts
|
|
14
|
+
var MCP_SERVERS_QUERY = `
|
|
15
|
+
query AiCatalogMcpServers($projectId: ProjectID!, $after: String) {
|
|
16
|
+
aiCatalogConfiguredItems(first: 50, projectId: $projectId, itemTypes: [AGENT], after: $after) {
|
|
17
|
+
pageInfo { hasNextPage endCursor }
|
|
18
|
+
nodes {
|
|
19
|
+
item {
|
|
20
|
+
id
|
|
21
|
+
name
|
|
22
|
+
latestVersion {
|
|
23
|
+
... on AiCatalogAgentVersion {
|
|
24
|
+
mcpServers {
|
|
25
|
+
nodes { id name description url transport authType currentUserConnected }
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
}`;
|
|
33
|
+
async function fetchMcpServers(instanceUrl, token, projectId, agents) {
|
|
34
|
+
try {
|
|
35
|
+
let after = null;
|
|
36
|
+
const serversByAgent = /* @__PURE__ */ new Map();
|
|
37
|
+
for (; ; ) {
|
|
38
|
+
const data = await gql(instanceUrl, token, MCP_SERVERS_QUERY, {
|
|
39
|
+
projectId,
|
|
40
|
+
...after ? { after } : {}
|
|
41
|
+
});
|
|
42
|
+
const page = data?.aiCatalogConfiguredItems;
|
|
43
|
+
if (!page) break;
|
|
44
|
+
for (const node of page.nodes ?? []) {
|
|
45
|
+
const item = node.item;
|
|
46
|
+
const version = item?.latestVersion;
|
|
47
|
+
if (!version?.mcpServers?.nodes?.length) continue;
|
|
48
|
+
const servers = version.mcpServers.nodes.map((s) => ({
|
|
49
|
+
id: s.id,
|
|
50
|
+
name: s.name,
|
|
51
|
+
description: s.description ?? "",
|
|
52
|
+
url: s.url,
|
|
53
|
+
transport: s.transport,
|
|
54
|
+
authType: s.authType,
|
|
55
|
+
currentUserConnected: !!s.currentUserConnected
|
|
56
|
+
}));
|
|
57
|
+
serversByAgent.set(item.id, servers);
|
|
58
|
+
}
|
|
59
|
+
if (!page.pageInfo?.hasNextPage) break;
|
|
60
|
+
after = page.pageInfo.endCursor;
|
|
61
|
+
}
|
|
62
|
+
for (const agent of agents) {
|
|
63
|
+
const servers = serversByAgent.get(agent.identifier);
|
|
64
|
+
if (servers?.length) agent.mcpServers = servers;
|
|
65
|
+
}
|
|
66
|
+
} catch {
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
async function listMcpServerTools(server) {
|
|
70
|
+
try {
|
|
71
|
+
const res = await fetch(server.url, {
|
|
72
|
+
method: "POST",
|
|
73
|
+
headers: {
|
|
74
|
+
"Content-Type": "application/json",
|
|
75
|
+
Accept: "application/json, text/event-stream"
|
|
76
|
+
},
|
|
77
|
+
body: JSON.stringify({ jsonrpc: "2.0", id: 1, method: "tools/list", params: {} })
|
|
78
|
+
});
|
|
79
|
+
if (!res.ok) return [];
|
|
80
|
+
const data = await res.json();
|
|
81
|
+
const tools = data?.result?.tools;
|
|
82
|
+
if (!Array.isArray(tools)) return [];
|
|
83
|
+
return tools.map((t) => ({ name: t.name, description: t.description ?? "" }));
|
|
84
|
+
} catch {
|
|
85
|
+
return [];
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
async function discoverMcpToolNames(agents) {
|
|
89
|
+
const result = /* @__PURE__ */ new Map();
|
|
90
|
+
const seen = /* @__PURE__ */ new Set();
|
|
91
|
+
for (const agent of agents) {
|
|
92
|
+
if (!agent.mcpServers?.length) continue;
|
|
93
|
+
const agentToolNames = [];
|
|
94
|
+
for (const server of agent.mcpServers) {
|
|
95
|
+
if (seen.has(server.id)) {
|
|
96
|
+
const key2 = server.name.toLowerCase().replace(/[^a-z0-9]+/g, "_");
|
|
97
|
+
const cached = result.get(server.id);
|
|
98
|
+
if (cached) agentToolNames.push(...cached.map((t) => `${key2}_${t}`));
|
|
99
|
+
continue;
|
|
100
|
+
}
|
|
101
|
+
seen.add(server.id);
|
|
102
|
+
const tools = await listMcpServerTools(server);
|
|
103
|
+
const toolNames = tools.map((t) => t.name);
|
|
104
|
+
result.set(server.id, toolNames);
|
|
105
|
+
const key = server.name.toLowerCase().replace(/[^a-z0-9]+/g, "_");
|
|
106
|
+
agentToolNames.push(...toolNames.map((t) => `${key}_${t}`));
|
|
107
|
+
}
|
|
108
|
+
result.set(agent.identifier, agentToolNames);
|
|
109
|
+
}
|
|
110
|
+
return result;
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
export {
|
|
114
|
+
gql,
|
|
115
|
+
fetchMcpServers,
|
|
116
|
+
listMcpServerTools,
|
|
117
|
+
discoverMcpToolNames
|
|
118
|
+
};
|
|
119
|
+
//# sourceMappingURL=chunk-DPR6OUYG.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/graphql.ts","../src/mcp-servers.ts"],"sourcesContent":["export async function gql(\n instanceUrl: string,\n token: string,\n query: string,\n variables: Record<string, unknown>\n): Promise<any> {\n const res = await fetch(`${instanceUrl.replace(/\\/$/, \"\")}/api/graphql`, {\n method: \"POST\",\n headers: { \"Content-Type\": \"application/json\", Authorization: `Bearer ${token}` },\n body: JSON.stringify({ query, variables }),\n });\n const json = (await res.json()) as any;\n if (json.errors?.length) throw new Error(json.errors[0].message);\n return json.data;\n}\n","import { gql } from \"./graphql\";\nimport type { CatalogAgent, McpServerInfo } from \"./types\";\n\nconst MCP_SERVERS_QUERY = `\nquery AiCatalogMcpServers($projectId: ProjectID!, $after: String) {\n aiCatalogConfiguredItems(first: 50, projectId: $projectId, itemTypes: [AGENT], after: $after) {\n pageInfo { hasNextPage endCursor }\n nodes {\n item {\n id\n name\n latestVersion {\n ... on AiCatalogAgentVersion {\n mcpServers {\n nodes { id name description url transport authType currentUserConnected }\n }\n }\n }\n }\n }\n }\n}`;\n\nexport async function fetchMcpServers(\n instanceUrl: string,\n token: string,\n projectId: string,\n agents: CatalogAgent[]\n): Promise<void> {\n try {\n let after: string | null = null;\n const serversByAgent = new Map<string, McpServerInfo[]>();\n\n for (;;) {\n const data = await gql(instanceUrl, token, MCP_SERVERS_QUERY, {\n projectId,\n ...(after ? { after } : {}),\n });\n const page = data?.aiCatalogConfiguredItems;\n if (!page) break;\n\n for (const node of page.nodes ?? []) {\n const item = node.item;\n const version = item?.latestVersion;\n if (!version?.mcpServers?.nodes?.length) continue;\n const servers: McpServerInfo[] = version.mcpServers.nodes.map((s: any) => ({\n id: s.id,\n name: s.name,\n description: s.description ?? \"\",\n url: s.url,\n transport: s.transport,\n authType: s.authType,\n currentUserConnected: !!s.currentUserConnected,\n }));\n serversByAgent.set(item.id, servers);\n }\n\n if (!page.pageInfo?.hasNextPage) break;\n after = page.pageInfo.endCursor;\n }\n\n for (const agent of agents) {\n const servers = serversByAgent.get(agent.identifier);\n if (servers?.length) agent.mcpServers = servers;\n }\n } catch {\n // MCP servers query not available — silently skip\n }\n}\n\nexport async function listMcpServerTools(\n server: McpServerInfo\n): Promise<Array<{ name: string; description: string }>> {\n try {\n const res = await fetch(server.url, {\n method: \"POST\",\n headers: {\n \"Content-Type\": \"application/json\",\n Accept: \"application/json, text/event-stream\",\n },\n body: JSON.stringify({ jsonrpc: \"2.0\", id: 1, method: \"tools/list\", params: {} }),\n });\n if (!res.ok) return [];\n const data = await res.json();\n const tools = data?.result?.tools;\n if (!Array.isArray(tools)) return [];\n return tools.map((t: any) => ({ name: t.name, description: t.description ?? \"\" }));\n } catch {\n return [];\n }\n}\n\nexport async function discoverMcpToolNames(agents: CatalogAgent[]): Promise<Map<string, string[]>> {\n const result = new Map<string, string[]>();\n const seen = new Set<string>();\n\n for (const agent of agents) {\n if (!agent.mcpServers?.length) continue;\n const agentToolNames: string[] = [];\n for (const server of agent.mcpServers) {\n if (seen.has(server.id)) {\n const key = server.name.toLowerCase().replace(/[^a-z0-9]+/g, \"_\");\n const cached = result.get(server.id);\n if (cached) agentToolNames.push(...cached.map((t) => `${key}_${t}`));\n continue;\n }\n seen.add(server.id);\n const tools = await listMcpServerTools(server);\n const toolNames = tools.map((t) => t.name);\n result.set(server.id, toolNames);\n const key = server.name.toLowerCase().replace(/[^a-z0-9]+/g, \"_\");\n agentToolNames.push(...toolNames.map((t) => `${key}_${t}`));\n }\n result.set(agent.identifier, agentToolNames);\n }\n return result;\n}\n"],"mappings":"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","names":["key"]}
|