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 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
- ### 20 DAP Tools
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"]}