@likec4/language-server 1.33.0 → 1.34.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 +27 -1
- package/dist/Rpc.d.ts +2 -0
- package/dist/Rpc.js +24 -6
- package/dist/bundled.mjs +2747 -2892
- package/dist/formatting/LikeC4Formatter.d.ts +1 -0
- package/dist/formatting/LikeC4Formatter.js +25 -1
- package/dist/generated/ast.d.ts +1 -1
- package/dist/generated/ast.js +5 -5
- package/dist/generated/grammar.js +1 -1
- package/dist/index.d.ts +0 -1
- package/dist/index.js +1 -2
- package/dist/mcp/{LikeC4MCPServerFactory.d.ts → NoopLikeC4MCPServer.d.ts} +1 -9
- package/dist/mcp/interfaces.d.ts +11 -0
- package/dist/mcp/interfaces.js +0 -0
- package/dist/mcp/sseserver/MCPServer.d.ts +1 -1
- package/dist/mcp/sseserver/MCPServer.js +5 -5
- package/dist/mcp/sseserver/MCPServerFactory.js +30 -58
- package/dist/mcp/sseserver/{with-mcp-server.d.ts → WithMCPServer.d.ts} +1 -1
- package/dist/mcp/tools/_common.d.ts +68 -0
- package/dist/mcp/tools/_common.js +14 -0
- package/dist/mcp/tools/list-projects.d.ts +6 -0
- package/dist/mcp/tools/list-projects.js +31 -0
- package/dist/mcp/tools/open-view.d.ts +10 -0
- package/dist/mcp/tools/open-view.js +29 -0
- package/dist/mcp/tools/read-element.d.ts +10 -0
- package/dist/mcp/tools/read-element.js +135 -0
- package/dist/mcp/tools/read-project-elements.d.ts +8 -0
- package/dist/mcp/tools/read-project-elements.js +93 -0
- package/dist/mcp/tools/read-project-summary.d.ts +8 -0
- package/dist/mcp/tools/read-project-summary.js +68 -0
- package/dist/mcp/tools/read-view.d.ts +10 -0
- package/dist/mcp/tools/read-view.js +164 -0
- package/dist/mcp/tools/search-element.d.ts +8 -0
- package/dist/mcp/tools/search-element.js +105 -0
- package/dist/mcp/utils.d.ts +17 -34
- package/dist/mcp/utils.js +41 -101
- package/dist/model/model-parser-where.d.ts +1 -0
- package/dist/model/model-parser-where.js +30 -24
- package/dist/model/model-parser.d.ts +14 -0
- package/dist/model/parser/DeploymentModelParser.d.ts +3 -1
- package/dist/model/parser/DeploymentViewParser.d.ts +3 -1
- package/dist/model/parser/FqnRefParser.d.ts +3 -1
- package/dist/model/parser/FqnRefParser.js +34 -10
- package/dist/model/parser/GlobalsParser.d.ts +3 -1
- package/dist/model/parser/ModelParser.d.ts +3 -1
- package/dist/model/parser/PredicatesParser.d.ts +3 -1
- package/dist/model/parser/ViewsParser.d.ts +3 -1
- package/dist/module.d.ts +1 -3
- package/dist/module.js +1 -6
- package/dist/protocol.d.ts +16 -0
- package/dist/protocol.js +4 -0
- package/dist/validation/property-checks.js +1 -1
- package/dist/views/likec4-views.d.ts +5 -0
- package/dist/views/likec4-views.js +6 -0
- package/package.json +8 -8
- package/dist/mcp/LikeC4MCPTools.d.ts +0 -96
- package/dist/mcp/LikeC4MCPTools.js +0 -293
- /package/dist/mcp/{LikeC4MCPServerFactory.js → NoopLikeC4MCPServer.js} +0 -0
- /package/dist/mcp/sseserver/{with-mcp-server.js → WithMCPServer.js} +0 -0
|
@@ -1,293 +0,0 @@
|
|
|
1
|
-
import { _type, RichText } from "@likec4/core";
|
|
2
|
-
import { loggable } from "@likec4/log";
|
|
3
|
-
import { flatMap } from "remeda";
|
|
4
|
-
import stripIndent from "strip-indent";
|
|
5
|
-
import { z } from "zod";
|
|
6
|
-
import { logger as mainLogger } from "../logger.js";
|
|
7
|
-
import { toSingleLine } from "../model/parser/Base.js";
|
|
8
|
-
import { ProjectsManager } from "../workspace/ProjectsManager.js";
|
|
9
|
-
import { elementResource, modelViewResource } from "./utils.js";
|
|
10
|
-
const logger = mainLogger.getChild("LikeC4MCPServices");
|
|
11
|
-
function singleLine(str) {
|
|
12
|
-
if (str === null || str === void 0) {
|
|
13
|
-
return "null";
|
|
14
|
-
}
|
|
15
|
-
const res = toSingleLine(RichText.from(str).text)?.replaceAll('"', "'");
|
|
16
|
-
return res ? `"${res}"` : "null";
|
|
17
|
-
}
|
|
18
|
-
function outputEach(iterator, ifEmpty, output) {
|
|
19
|
-
const items = [...iterator];
|
|
20
|
-
if (items.length === 0) {
|
|
21
|
-
return [ifEmpty];
|
|
22
|
-
}
|
|
23
|
-
return flatMap(items, output);
|
|
24
|
-
}
|
|
25
|
-
export var LikeC4MCPTools;
|
|
26
|
-
((LikeC4MCPTools2) => {
|
|
27
|
-
LikeC4MCPTools2.instructions = `This server provides access to LikeC4 model.
|
|
28
|
-
|
|
29
|
-
Key capabilities:
|
|
30
|
-
- List all available LikeC4 projects in the workspace
|
|
31
|
-
- Search for LikeC4 project and return its summary, that includes specifications, all elements and views
|
|
32
|
-
- Search for LikeC4 element by title
|
|
33
|
-
- Read details about LikeC4 element by id
|
|
34
|
-
- Read details about LikeC4 view by id
|
|
35
|
-
|
|
36
|
-
`;
|
|
37
|
-
LikeC4MCPTools2.listProjects = {
|
|
38
|
-
name: "list-projects",
|
|
39
|
-
description: "Lists all available LikeC4 projects in the workspace"
|
|
40
|
-
};
|
|
41
|
-
LikeC4MCPTools2.readProjectSummary = {
|
|
42
|
-
name: "read-project-summary",
|
|
43
|
-
description: stripIndent(`
|
|
44
|
-
Searches for LikeC4 project and returns its summary, specifications, elements and views
|
|
45
|
-
|
|
46
|
-
Args:
|
|
47
|
-
project: Project name
|
|
48
|
-
`),
|
|
49
|
-
paramsSchema: {
|
|
50
|
-
project: z.string().optional()
|
|
51
|
-
}
|
|
52
|
-
};
|
|
53
|
-
LikeC4MCPTools2.searchElement = {
|
|
54
|
-
name: "search-element",
|
|
55
|
-
description: stripIndent(`
|
|
56
|
-
Search for LikeC4 elements that have the search string in their names
|
|
57
|
-
Can be used to resolve projects for further requests (like read-element or read-project-summary)
|
|
58
|
-
|
|
59
|
-
Args:
|
|
60
|
-
search: non-empty string
|
|
61
|
-
`),
|
|
62
|
-
paramsSchema: {
|
|
63
|
-
search: z.string()
|
|
64
|
-
}
|
|
65
|
-
};
|
|
66
|
-
LikeC4MCPTools2.readElement = {
|
|
67
|
-
name: "read-element",
|
|
68
|
-
description: stripIndent(`
|
|
69
|
-
Read details about a LikeC4 element
|
|
70
|
-
|
|
71
|
-
Args:
|
|
72
|
-
id: Element id (FQN)
|
|
73
|
-
project: Project name (optional, will use default project if not specified)
|
|
74
|
-
`),
|
|
75
|
-
paramsSchema: {
|
|
76
|
-
id: z.string().min(1),
|
|
77
|
-
project: z.string().optional()
|
|
78
|
-
}
|
|
79
|
-
};
|
|
80
|
-
LikeC4MCPTools2.readView = {
|
|
81
|
-
name: "read-view",
|
|
82
|
-
description: stripIndent(`
|
|
83
|
-
Read details about a LikeC4 view
|
|
84
|
-
|
|
85
|
-
Args:
|
|
86
|
-
id: View id
|
|
87
|
-
project: Project name (optional, will use default project if not specified)
|
|
88
|
-
`),
|
|
89
|
-
paramsSchema: {
|
|
90
|
-
id: z.string().min(1),
|
|
91
|
-
project: z.string().optional()
|
|
92
|
-
}
|
|
93
|
-
};
|
|
94
|
-
})(LikeC4MCPTools || (LikeC4MCPTools = {}));
|
|
95
|
-
export class DefaultLikeC4MCPTools {
|
|
96
|
-
constructor(services) {
|
|
97
|
-
this.services = services;
|
|
98
|
-
this.languageServices = services.likec4.LanguageServices;
|
|
99
|
-
}
|
|
100
|
-
languageServices;
|
|
101
|
-
async listProjects() {
|
|
102
|
-
const projects = await this.languageServices.projects();
|
|
103
|
-
const response = [];
|
|
104
|
-
for (const project of projects) {
|
|
105
|
-
if (!project.documents) {
|
|
106
|
-
continue;
|
|
107
|
-
}
|
|
108
|
-
response.push(
|
|
109
|
-
`<likec4project>`,
|
|
110
|
-
`id: "${project.id}"`,
|
|
111
|
-
`folder: ${project.folder.toString()}`,
|
|
112
|
-
"sources:",
|
|
113
|
-
...project.documents.map((d) => `- ${d.toString()}`),
|
|
114
|
-
""
|
|
115
|
-
);
|
|
116
|
-
try {
|
|
117
|
-
const model = await this.languageServices.computedModel(project.id);
|
|
118
|
-
const elements = [...model.elements()];
|
|
119
|
-
if (elements.length > 0) {
|
|
120
|
-
response.push(
|
|
121
|
-
"elements:",
|
|
122
|
-
...elements.flatMap((el) => [
|
|
123
|
-
`- id: ${el.id}`,
|
|
124
|
-
` kind: ${el.kind}`,
|
|
125
|
-
` title: ${singleLine(el.title)}`,
|
|
126
|
-
""
|
|
127
|
-
]),
|
|
128
|
-
""
|
|
129
|
-
);
|
|
130
|
-
}
|
|
131
|
-
const views = [...model.views()];
|
|
132
|
-
if (views.length > 0) {
|
|
133
|
-
response.push(
|
|
134
|
-
"views:",
|
|
135
|
-
...views.flatMap((v) => [
|
|
136
|
-
`- id: ${v.id}`,
|
|
137
|
-
` title: ${singleLine(v.title)}`,
|
|
138
|
-
""
|
|
139
|
-
]),
|
|
140
|
-
""
|
|
141
|
-
);
|
|
142
|
-
}
|
|
143
|
-
} catch (error) {
|
|
144
|
-
logger.error(loggable(error));
|
|
145
|
-
}
|
|
146
|
-
response.push(`</likec4project>`);
|
|
147
|
-
}
|
|
148
|
-
if (response.length === 0) {
|
|
149
|
-
response.push(
|
|
150
|
-
`<likec4project>`,
|
|
151
|
-
`id: "default"`,
|
|
152
|
-
`folder: ${this.languageServices.workspaceUri.toString()}`,
|
|
153
|
-
`</likec4project>`
|
|
154
|
-
);
|
|
155
|
-
}
|
|
156
|
-
return response.join("\n");
|
|
157
|
-
}
|
|
158
|
-
async readProjectSummary(_project) {
|
|
159
|
-
const projectId = _project ?? ProjectsManager.DefaultProjectId;
|
|
160
|
-
const project = this.languageServices.projects().find((p) => p.id === projectId);
|
|
161
|
-
if (!project) {
|
|
162
|
-
return "Project not found";
|
|
163
|
-
}
|
|
164
|
-
const model = await this.languageServices.computedModel(project.id);
|
|
165
|
-
const response = [
|
|
166
|
-
`project: "${project.id}"`,
|
|
167
|
-
`folder: ${project.folder.toString()}`
|
|
168
|
-
];
|
|
169
|
-
if (project.documents) {
|
|
170
|
-
response.push(
|
|
171
|
-
"sources:",
|
|
172
|
-
...project.documents.map((d) => `- ${d.toString()}`),
|
|
173
|
-
""
|
|
174
|
-
);
|
|
175
|
-
}
|
|
176
|
-
response.push("<specifications>");
|
|
177
|
-
const elementKinds = Object.keys(model.$model.specification.elements);
|
|
178
|
-
if (elementKinds.length > 0) {
|
|
179
|
-
response.push(
|
|
180
|
-
"element kinds:",
|
|
181
|
-
...elementKinds.map((kind) => `- ${kind}`),
|
|
182
|
-
""
|
|
183
|
-
);
|
|
184
|
-
}
|
|
185
|
-
const relationshipKinds = Object.keys(model.$model.specification.relationships);
|
|
186
|
-
if (relationshipKinds.length > 0) {
|
|
187
|
-
response.push(
|
|
188
|
-
"relationship kinds:",
|
|
189
|
-
...relationshipKinds.map((kind) => `- ${kind}`),
|
|
190
|
-
""
|
|
191
|
-
);
|
|
192
|
-
}
|
|
193
|
-
const deploymentKinds = Object.keys(model.$model.specification.deployments);
|
|
194
|
-
if (deploymentKinds.length > 0) {
|
|
195
|
-
response.push(
|
|
196
|
-
"deployment node kinds:",
|
|
197
|
-
...deploymentKinds.map((kind) => `- ${kind}`),
|
|
198
|
-
""
|
|
199
|
-
);
|
|
200
|
-
}
|
|
201
|
-
const tags = model.tags;
|
|
202
|
-
if (tags.length > 0) {
|
|
203
|
-
response.push(
|
|
204
|
-
"tags:",
|
|
205
|
-
...tags.map((t) => `- ${t}`),
|
|
206
|
-
""
|
|
207
|
-
);
|
|
208
|
-
}
|
|
209
|
-
response.push(
|
|
210
|
-
"</specifications>",
|
|
211
|
-
""
|
|
212
|
-
);
|
|
213
|
-
response.push(
|
|
214
|
-
"<elements>",
|
|
215
|
-
...outputEach(model.elements(), "No elements", (el) => [
|
|
216
|
-
`- id: ${el.id}`,
|
|
217
|
-
...el.parent ? [
|
|
218
|
-
` parentId: ${el.parent.id}`
|
|
219
|
-
] : [],
|
|
220
|
-
` kind: ${el.kind}`,
|
|
221
|
-
` shape: ${el.shape}`,
|
|
222
|
-
` title: ${singleLine(el.title)}`,
|
|
223
|
-
` description: ${singleLine(el.description)}`,
|
|
224
|
-
` technology: ${singleLine(el.technology)}`,
|
|
225
|
-
` tags: ${JSON.stringify(el.tags)}`,
|
|
226
|
-
""
|
|
227
|
-
]),
|
|
228
|
-
"</elements>",
|
|
229
|
-
"<views>",
|
|
230
|
-
...outputEach(model.views(), "No views", (v) => [
|
|
231
|
-
`- id: ${v.id}`,
|
|
232
|
-
` viewType: ${v[_type]}`,
|
|
233
|
-
` title: ${singleLine(v.title)}`,
|
|
234
|
-
""
|
|
235
|
-
]),
|
|
236
|
-
"</views>"
|
|
237
|
-
);
|
|
238
|
-
return response.join("\n");
|
|
239
|
-
}
|
|
240
|
-
async searchElement(params) {
|
|
241
|
-
const search = params.search.toLowerCase();
|
|
242
|
-
const found = [];
|
|
243
|
-
for (const project of this.languageServices.projects()) {
|
|
244
|
-
try {
|
|
245
|
-
const model = await this.languageServices.computedModel(project.id);
|
|
246
|
-
const elements = [...model.elements()].filter((el) => el.title.toLowerCase().includes(search));
|
|
247
|
-
if (elements.length > 0) {
|
|
248
|
-
found.push(
|
|
249
|
-
"<project>",
|
|
250
|
-
`project: "${project.id}"`,
|
|
251
|
-
"found:",
|
|
252
|
-
...elements.flatMap((el) => [
|
|
253
|
-
`- id: ${el.id}`,
|
|
254
|
-
` kind: ${el.kind}`,
|
|
255
|
-
` title: ${singleLine(el.title)}`,
|
|
256
|
-
""
|
|
257
|
-
]),
|
|
258
|
-
"</project>"
|
|
259
|
-
);
|
|
260
|
-
}
|
|
261
|
-
} catch (error) {
|
|
262
|
-
logger.error(loggable(error));
|
|
263
|
-
}
|
|
264
|
-
}
|
|
265
|
-
return found.length > 0 ? found.join("\n") : "No elements with this name found";
|
|
266
|
-
}
|
|
267
|
-
async readElement(params) {
|
|
268
|
-
const projectId = params.project ?? ProjectsManager.DefaultProjectId;
|
|
269
|
-
const project = this.languageServices.projects().find((p) => p.id === projectId);
|
|
270
|
-
if (!project) {
|
|
271
|
-
return `Project "${projectId}" not found`;
|
|
272
|
-
}
|
|
273
|
-
const model = await this.languageServices.computedModel(project.id);
|
|
274
|
-
const element = model.findElement(params.id);
|
|
275
|
-
if (!element) {
|
|
276
|
-
return `Element "${params.id}" not found in project "${projectId}"`;
|
|
277
|
-
}
|
|
278
|
-
return JSON.stringify(elementResource(this.languageServices, element, project.id));
|
|
279
|
-
}
|
|
280
|
-
async readView(params) {
|
|
281
|
-
const projectId = params.project ?? ProjectsManager.DefaultProjectId;
|
|
282
|
-
const project = this.languageServices.projects().find((p) => p.id === projectId);
|
|
283
|
-
if (!project) {
|
|
284
|
-
return `Project "${projectId}" not found`;
|
|
285
|
-
}
|
|
286
|
-
const model = await this.languageServices.computedModel(project.id);
|
|
287
|
-
const view = model.findView(params.id);
|
|
288
|
-
if (!view) {
|
|
289
|
-
return `View "${params.id}" not found in project "${projectId}"`;
|
|
290
|
-
}
|
|
291
|
-
return JSON.stringify(modelViewResource(this.languageServices, view, project.id));
|
|
292
|
-
}
|
|
293
|
-
}
|
|
File without changes
|
|
File without changes
|