@likec4/language-server 1.36.1 → 1.38.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/dist/LikeC4LanguageServices.d.ts +43 -7
- package/dist/LikeC4LanguageServices.js +51 -11
- package/dist/Rpc.js +22 -6
- package/dist/browser.d.ts +1 -1
- package/dist/browser.js +1 -1
- package/dist/bundled.mjs +4258 -3083
- package/dist/config/schema.d.ts +1 -1
- package/dist/config/schema.js +1 -1
- package/dist/empty.d.ts +2 -0
- package/dist/empty.js +1 -0
- package/dist/filesystem/ChokidarWatcher.d.ts +14 -0
- package/dist/filesystem/ChokidarWatcher.js +64 -0
- package/dist/filesystem/FileSystemWatcher.d.ts +19 -0
- package/dist/filesystem/FileSystemWatcher.js +11 -0
- package/dist/filesystem/LikeC4FileSystem.d.ts +5 -0
- package/dist/filesystem/LikeC4FileSystem.js +56 -0
- package/dist/filesystem/index.d.ts +20 -0
- package/dist/filesystem/index.js +16 -0
- package/dist/index.d.ts +18 -4
- package/dist/index.js +23 -10
- package/dist/likec4lib.d.ts +1 -1
- package/dist/lsp/DocumentLinkProvider.js +3 -3
- package/dist/lsp/DocumentSymbolProvider.js +1 -1
- package/dist/mcp/{sseserver/MCPServerFactory.d.ts → MCPServerFactory.d.ts} +1 -1
- package/dist/mcp/MCPServerFactory.js +69 -0
- package/dist/mcp/NoopLikeC4MCPServer.d.ts +4 -10
- package/dist/mcp/NoopLikeC4MCPServer.js +5 -10
- package/dist/mcp/interfaces.d.ts +7 -5
- package/dist/mcp/interfaces.js +4 -0
- package/dist/mcp/server/StdioLikeC4MCPServer.d.ts +16 -0
- package/dist/mcp/server/StdioLikeC4MCPServer.js +43 -0
- package/dist/mcp/{sseserver/MCPServer.d.ts → server/StreamableLikeC4MCPServer.d.ts} +3 -2
- package/dist/mcp/server/StreamableLikeC4MCPServer.js +156 -0
- package/dist/mcp/server/WithMCPServer.d.ts +2 -0
- package/dist/mcp/server/WithMCPServer.js +57 -0
- package/dist/mcp/tools/_common.d.ts +24 -5
- package/dist/mcp/tools/_common.js +31 -3
- package/dist/mcp/tools/find-relationships.d.ts +13 -0
- package/dist/mcp/tools/find-relationships.js +151 -0
- package/dist/mcp/tools/list-projects.js +42 -14
- package/dist/mcp/tools/open-view.d.ts +4 -3
- package/dist/mcp/tools/open-view.js +37 -14
- package/dist/mcp/tools/{read-project-elements.d.ts → read-deployment.d.ts} +6 -3
- package/dist/mcp/tools/read-deployment.js +130 -0
- package/dist/mcp/tools/read-element.d.ts +4 -3
- package/dist/mcp/tools/read-element.js +114 -51
- package/dist/mcp/tools/read-project-summary.d.ts +3 -2
- package/dist/mcp/tools/read-project-summary.js +141 -34
- package/dist/mcp/tools/read-view.d.ts +4 -3
- package/dist/mcp/tools/read-view.js +146 -105
- package/dist/mcp/tools/search-element.js +81 -30
- package/dist/mcp/utils.js +7 -4
- package/dist/model/builder/buildModel.d.ts +1 -1
- package/dist/model/builder/buildModel.js +4 -6
- package/dist/model/model-parser.d.ts +9 -9
- package/dist/model/model-parser.js +3 -0
- package/dist/model/parser/Base.d.ts +1 -1
- package/dist/model/parser/Base.js +1 -1
- package/dist/model/parser/DeploymentModelParser.d.ts +1 -1
- package/dist/model/parser/DeploymentViewParser.d.ts +1 -1
- package/dist/model/parser/DeploymentViewParser.js +2 -2
- package/dist/model/parser/FqnRefParser.d.ts +1 -1
- package/dist/model/parser/FqnRefParser.js +8 -1
- package/dist/model/parser/GlobalsParser.d.ts +1 -1
- package/dist/model/parser/ImportsParser.d.ts +1 -1
- package/dist/model/parser/ModelParser.d.ts +1 -1
- package/dist/model/parser/PredicatesParser.d.ts +1 -1
- package/dist/model/parser/SpecificationParser.d.ts +1 -1
- package/dist/model/parser/ViewsParser.d.ts +1 -1
- package/dist/model/parser/ViewsParser.js +3 -3
- package/dist/module.d.ts +13 -9
- package/dist/module.js +28 -30
- package/dist/protocol.d.ts +18 -4
- package/dist/protocol.js +5 -1
- package/dist/test/testServices.d.ts +5 -2
- package/dist/test/testServices.js +7 -3
- package/dist/validation/DocumentValidator.d.ts +11 -0
- package/dist/validation/DocumentValidator.js +16 -0
- package/dist/validation/index.d.ts +1 -1
- package/dist/validation/index.js +1 -0
- package/dist/workspace/LangiumDocuments.d.ts +1 -0
- package/dist/workspace/LangiumDocuments.js +10 -1
- package/dist/workspace/ProjectsManager.d.ts +35 -17
- package/dist/workspace/ProjectsManager.js +168 -54
- package/dist/workspace/WorkspaceManager.d.ts +9 -2
- package/dist/workspace/WorkspaceManager.js +31 -40
- package/package.json +14 -10
- package/dist/LikeC4FileSystem.d.ts +0 -14
- package/dist/LikeC4FileSystem.js +0 -39
- package/dist/mcp/sseserver/MCPServer.js +0 -80
- package/dist/mcp/sseserver/MCPServerFactory.js +0 -50
- package/dist/mcp/sseserver/WithMCPServer.d.ts +0 -9
- package/dist/mcp/sseserver/WithMCPServer.js +0 -53
- package/dist/mcp/tools/read-project-elements.js +0 -93
|
@@ -1,9 +1,6 @@
|
|
|
1
|
-
import { invariant } from "@likec4/core";
|
|
2
1
|
import z from "zod";
|
|
3
|
-
import { safeCall } from "../../utils/index.js";
|
|
4
|
-
import { ProjectsManager } from "../../workspace/index.js";
|
|
5
2
|
import { likec4Tool } from "../utils.js";
|
|
6
|
-
import { locationSchema } from "./_common.js";
|
|
3
|
+
import { locationSchema, mkLocate, projectIdSchema } from "./_common.js";
|
|
7
4
|
const modelRef = (node) => {
|
|
8
5
|
if (node.hasElement()) {
|
|
9
6
|
return node.element.id;
|
|
@@ -13,152 +10,196 @@ const modelRef = (node) => {
|
|
|
13
10
|
}
|
|
14
11
|
return null;
|
|
15
12
|
};
|
|
13
|
+
const nodeSchema = z.discriminatedUnion("type", [
|
|
14
|
+
z.object({
|
|
15
|
+
type: z.literal("element"),
|
|
16
|
+
id: z.string().describe("Node ID"),
|
|
17
|
+
elementId: z.string().describe("Element ID (FQN)"),
|
|
18
|
+
kind: z.string().describe("Element kind"),
|
|
19
|
+
title: z.string().describe("Node title"),
|
|
20
|
+
description: z.string().nullable(),
|
|
21
|
+
technology: z.string().nullable(),
|
|
22
|
+
children: z.array(z.string()).describe("Children nodes, array of node IDs"),
|
|
23
|
+
shape: z.string().describe("Rendered shape"),
|
|
24
|
+
color: z.string().describe("Rendered color"),
|
|
25
|
+
tags: z.array(z.string())
|
|
26
|
+
}),
|
|
27
|
+
z.object({
|
|
28
|
+
type: z.literal("deployment-node"),
|
|
29
|
+
id: z.string().describe("Node ID"),
|
|
30
|
+
deploymentId: z.string().describe("Deployment entity ID (FQN)"),
|
|
31
|
+
kind: z.string().describe("Deployment kind"),
|
|
32
|
+
title: z.string().describe("Node title"),
|
|
33
|
+
description: z.string().nullable(),
|
|
34
|
+
technology: z.string().nullable(),
|
|
35
|
+
children: z.array(z.string()).describe("Children nodes, array of node IDs"),
|
|
36
|
+
shape: z.string().describe("Rendered shape"),
|
|
37
|
+
color: z.string().describe("Rendered color"),
|
|
38
|
+
tags: z.array(z.string())
|
|
39
|
+
}),
|
|
40
|
+
z.object({
|
|
41
|
+
type: z.literal("deployed-instance"),
|
|
42
|
+
id: z.string().describe("Node ID"),
|
|
43
|
+
deploymentId: z.string().describe("Deployment entity ID (FQN)"),
|
|
44
|
+
title: z.string().describe("Node title"),
|
|
45
|
+
description: z.string().nullable(),
|
|
46
|
+
technology: z.string().nullable(),
|
|
47
|
+
referencedElement: z.object({
|
|
48
|
+
id: z.string().describe("Element ID (FQN)"),
|
|
49
|
+
kind: z.string().describe("Element kind"),
|
|
50
|
+
title: z.string().describe("Element title")
|
|
51
|
+
}),
|
|
52
|
+
shape: z.string().describe("Rendered shape"),
|
|
53
|
+
color: z.string().describe("Rendered color"),
|
|
54
|
+
tags: z.array(z.string())
|
|
55
|
+
})
|
|
56
|
+
]);
|
|
16
57
|
export const readView = likec4Tool({
|
|
17
58
|
name: "read-view",
|
|
18
59
|
description: `
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
-
|
|
23
|
-
- project
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
-
|
|
27
|
-
-
|
|
28
|
-
|
|
60
|
+
Read detailed information about a LikeC4 view.
|
|
61
|
+
|
|
62
|
+
Request:
|
|
63
|
+
- viewId: string \u2014 view id (name)
|
|
64
|
+
- project: string (optional) \u2014 project id. Defaults to "default" if omitted.
|
|
65
|
+
|
|
66
|
+
Response (JSON object):
|
|
67
|
+
- id: string \u2014 view id
|
|
68
|
+
- type: "element" | "deployment" | "dynamic" \u2014 view type
|
|
69
|
+
- title: string \u2014 view title (falls back to id if not set)
|
|
70
|
+
- description: string|null \u2014 optional description
|
|
71
|
+
- tags: string[] \u2014 view tags
|
|
72
|
+
- project: string \u2014 project id this view belongs to
|
|
73
|
+
- nodes: Node[] \u2014 nodes included in the view
|
|
74
|
+
- edges: Edge[] \u2014 relationships between nodes
|
|
75
|
+
- sourceLocation: { path: string, range: { start: { line: number, character: number }, end: { line: number, character: number } } } | null \u2014 source location if available
|
|
76
|
+
|
|
77
|
+
Node (discriminated union by "type"):
|
|
78
|
+
- type = "element": { id: string, elementId: string, kind: string, title: string, description: string|null, technology: string|null, children: string[], shape: string, color: string, tags: string[] }
|
|
79
|
+
- type = "deployment-node": { id: string, deploymentId: string, kind: string, title: string, description: string|null, technology: string|null, children: string[], shape: string, color: string, tags: string[] }
|
|
80
|
+
- type = "deployed-instance": { id: string, deploymentId: string, title: string, description: string|null, technology: string|null, referencedElement: { id: string, kind: string, title: string }, shape: string, color: string, tags: string[] }
|
|
81
|
+
|
|
82
|
+
Edge object:
|
|
83
|
+
- { source: string, target: string, label: string|null, description: string|null, technology: string|null, tags: string[] }
|
|
84
|
+
|
|
85
|
+
Notes:
|
|
86
|
+
- Read-only, idempotent, no side effects.
|
|
87
|
+
|
|
88
|
+
Example response:
|
|
89
|
+
{
|
|
90
|
+
"id": "system-overview",
|
|
91
|
+
"type": "element",
|
|
92
|
+
"title": "System Overview",
|
|
93
|
+
"description": null,
|
|
94
|
+
"tags": [],
|
|
95
|
+
"project": "default",
|
|
96
|
+
"nodes": [
|
|
97
|
+
{ "type": "logical", "id": "n1", "elementId": "shop.frontend", "kind": "container", "title": "Frontend", "description": null, "technology": "React", "children": [], "shape": "rounded-rectangle", "color": "#2F80ED", "tags": [] }
|
|
98
|
+
],
|
|
99
|
+
"edges": [
|
|
100
|
+
{ "source": "n1", "target": "n2", "label": "calls", "description": null, "technology": "HTTPS", "tags": [] }
|
|
101
|
+
],
|
|
102
|
+
"sourceLocation": {
|
|
103
|
+
"path": "/abs/path/project/model.c4",
|
|
104
|
+
"range": { "start": { "line": 10, "character": 0 }, "end": { "line": 30, "character": 0 } }
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
`,
|
|
29
108
|
annotations: {
|
|
30
|
-
readOnlyHint: true
|
|
109
|
+
readOnlyHint: true,
|
|
110
|
+
idempotentHint: true,
|
|
111
|
+
title: "Read view"
|
|
31
112
|
},
|
|
32
113
|
inputSchema: {
|
|
33
114
|
viewId: z.string().describe("View id (name)"),
|
|
34
|
-
project:
|
|
115
|
+
project: projectIdSchema
|
|
35
116
|
},
|
|
36
117
|
outputSchema: {
|
|
37
118
|
id: z.string(),
|
|
38
|
-
type: z.enum(["element", "deployment", "dynamic"]),
|
|
39
|
-
title: z.string()
|
|
40
|
-
description: z.string().
|
|
119
|
+
type: z.enum(["element", "deployment", "dynamic"]).describe("View type"),
|
|
120
|
+
title: z.string(),
|
|
121
|
+
description: z.string().nullable(),
|
|
41
122
|
tags: z.array(z.string()),
|
|
42
123
|
project: z.string(),
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
z.object({
|
|
46
|
-
type: z.literal("logical"),
|
|
47
|
-
id: z.string().describe("Element ID (FQN)"),
|
|
48
|
-
kind: z.string().describe("Element kind"),
|
|
49
|
-
title: z.string().describe("Element title"),
|
|
50
|
-
description: z.string().nullish(),
|
|
51
|
-
technology: z.string().nullish(),
|
|
52
|
-
children: z.array(z.string()),
|
|
53
|
-
shape: z.string().describe("Element shape"),
|
|
54
|
-
tags: z.array(z.string())
|
|
55
|
-
}),
|
|
56
|
-
z.object({
|
|
57
|
-
type: z.literal("deployment-node"),
|
|
58
|
-
id: z.string().describe("Deployment ID (FQN)"),
|
|
59
|
-
kind: z.string().describe("Deployment kind"),
|
|
60
|
-
title: z.string().describe("Deployment title"),
|
|
61
|
-
description: z.string().nullish(),
|
|
62
|
-
technology: z.string().nullish(),
|
|
63
|
-
children: z.array(z.string()),
|
|
64
|
-
shape: z.string().describe("Deployment shape"),
|
|
65
|
-
tags: z.array(z.string())
|
|
66
|
-
}),
|
|
67
|
-
z.object({
|
|
68
|
-
type: z.literal("deployed-instance"),
|
|
69
|
-
id: z.string().describe("Deployment ID (FQN)"),
|
|
70
|
-
title: z.string().describe("Deployment title"),
|
|
71
|
-
description: z.string().nullish(),
|
|
72
|
-
technology: z.string().nullish(),
|
|
73
|
-
logicalElementId: z.string().describe("Logical element ID (FQN)"),
|
|
74
|
-
shape: z.string().describe("Deployment shape"),
|
|
75
|
-
tags: z.array(z.string())
|
|
76
|
-
})
|
|
77
|
-
])
|
|
78
|
-
).describe("Elements in this view"),
|
|
79
|
-
relationships: z.array(
|
|
124
|
+
nodes: z.array(nodeSchema),
|
|
125
|
+
edges: z.array(
|
|
80
126
|
z.object({
|
|
81
|
-
source: z.string().describe("Source
|
|
82
|
-
target: z.string().describe("Target
|
|
83
|
-
|
|
84
|
-
description: z.string().
|
|
85
|
-
technology: z.string().
|
|
127
|
+
source: z.string().describe("Source node"),
|
|
128
|
+
target: z.string().describe("Target node"),
|
|
129
|
+
label: z.string().nullable(),
|
|
130
|
+
description: z.string().nullable(),
|
|
131
|
+
technology: z.string().nullable(),
|
|
86
132
|
tags: z.array(z.string())
|
|
87
133
|
})
|
|
88
|
-
).describe("
|
|
89
|
-
|
|
90
|
-
sourceLocation: locationSchema.nullish()
|
|
134
|
+
).describe("Edge represents relationship between nodes"),
|
|
135
|
+
sourceLocation: locationSchema
|
|
91
136
|
}
|
|
92
137
|
}, async (languageServices, args) => {
|
|
93
|
-
const projectId = args.project
|
|
94
|
-
const project = languageServices.
|
|
95
|
-
|
|
96
|
-
const model = await languageServices.computedModel(project.id);
|
|
138
|
+
const projectId = languageServices.projectsManager.ensureProjectId(args.project);
|
|
139
|
+
const project = languageServices.project(projectId);
|
|
140
|
+
const model = await languageServices.computedModel(projectId);
|
|
97
141
|
const view = model.findView(args.viewId);
|
|
98
142
|
if (!view) {
|
|
99
143
|
throw new Error(`View with ID '${args.viewId}' not found in project ${project.id}`);
|
|
100
144
|
}
|
|
145
|
+
const locate = mkLocate(languageServices, project.id);
|
|
101
146
|
return {
|
|
102
147
|
id: view.id,
|
|
103
148
|
type: view.$view._type,
|
|
104
|
-
title: view.title,
|
|
149
|
+
title: view.title ?? view.id,
|
|
105
150
|
description: view.description.text,
|
|
106
151
|
tags: [...view.tags],
|
|
107
152
|
project: project.id,
|
|
108
|
-
|
|
153
|
+
nodes: [...view.nodes()].flatMap((node) => {
|
|
154
|
+
const base = {
|
|
155
|
+
id: node.id,
|
|
156
|
+
title: node.title,
|
|
157
|
+
description: node.description.text,
|
|
158
|
+
technology: node.technology,
|
|
159
|
+
shape: node.shape,
|
|
160
|
+
color: node.color,
|
|
161
|
+
tags: [...node.tags]
|
|
162
|
+
};
|
|
109
163
|
if (node.hasDeployedInstance()) {
|
|
110
164
|
return {
|
|
165
|
+
...base,
|
|
111
166
|
type: "deployed-instance",
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
tags: [...node.tags]
|
|
167
|
+
deploymentId: node.deployment.id,
|
|
168
|
+
referencedElement: {
|
|
169
|
+
id: node.deployment.element.id,
|
|
170
|
+
kind: node.deployment.element.kind,
|
|
171
|
+
title: node.deployment.element.title
|
|
172
|
+
}
|
|
119
173
|
};
|
|
120
174
|
}
|
|
121
175
|
if (node.hasDeployment()) {
|
|
122
176
|
return {
|
|
177
|
+
...base,
|
|
123
178
|
type: "deployment-node",
|
|
124
|
-
id: node.deployment.id,
|
|
125
|
-
title: node.title,
|
|
126
179
|
kind: node.deployment.kind,
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
shape: node.shape,
|
|
130
|
-
tags: [...node.tags],
|
|
131
|
-
children: [...node.children()].flatMap((c) => modelRef(c) ?? [])
|
|
180
|
+
deploymentId: node.deployment.id,
|
|
181
|
+
children: [...node.children()].map((c) => c.id)
|
|
132
182
|
};
|
|
133
183
|
}
|
|
134
184
|
if (node.hasElement()) {
|
|
135
185
|
return {
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
186
|
+
...base,
|
|
187
|
+
type: "element",
|
|
188
|
+
elementId: node.element.id,
|
|
139
189
|
kind: node.element.kind,
|
|
140
|
-
description: node.description.text,
|
|
141
|
-
technology: node.technology,
|
|
142
|
-
shape: node.shape,
|
|
143
|
-
tags: [...node.tags],
|
|
144
190
|
children: [...node.children()].flatMap((c) => modelRef(c) ?? [])
|
|
145
191
|
};
|
|
146
192
|
}
|
|
147
193
|
return [];
|
|
148
194
|
}),
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
technology: r.technology,
|
|
159
|
-
tags: [...r.tags]
|
|
160
|
-
}] : [];
|
|
161
|
-
}),
|
|
162
|
-
sourceLocation: safeCall(() => languageServices.locate({ view: view.id, projectId }))
|
|
195
|
+
edges: [...view.edges()].map((r) => ({
|
|
196
|
+
source: r.source.id,
|
|
197
|
+
target: r.target.id,
|
|
198
|
+
label: r.label,
|
|
199
|
+
description: r.description.text,
|
|
200
|
+
technology: r.technology,
|
|
201
|
+
tags: [...r.tags]
|
|
202
|
+
})),
|
|
203
|
+
sourceLocation: locate({ view: view.id })
|
|
163
204
|
};
|
|
164
205
|
});
|
|
@@ -1,24 +1,31 @@
|
|
|
1
1
|
import { ifilter } from "@likec4/core/utils";
|
|
2
2
|
import z from "zod";
|
|
3
|
-
import { likec4Tool } from "../utils.js";
|
|
3
|
+
import { likec4Tool, logger } from "../utils.js";
|
|
4
|
+
import { includedInViews, includedInViewsSchema } from "./_common.js";
|
|
4
5
|
const searchResultSchema = z.array(
|
|
5
6
|
z.discriminatedUnion("type", [
|
|
6
7
|
z.object({
|
|
7
|
-
type: z.literal("
|
|
8
|
+
type: z.literal("element"),
|
|
9
|
+
project: z.string().describe("Project ID"),
|
|
8
10
|
id: z.string().describe("Element ID (FQN)"),
|
|
11
|
+
name: z.string().describe("Element name"),
|
|
9
12
|
kind: z.string(),
|
|
10
13
|
title: z.string(),
|
|
14
|
+
technology: z.string().nullable(),
|
|
11
15
|
shape: z.string(),
|
|
12
|
-
|
|
16
|
+
includedInViews: includedInViewsSchema,
|
|
13
17
|
tags: z.array(z.string())
|
|
14
18
|
}),
|
|
15
19
|
z.object({
|
|
16
20
|
type: z.literal("deployment-node"),
|
|
21
|
+
project: z.string().describe("Project ID"),
|
|
17
22
|
id: z.string().describe("Deployment ID (FQN)"),
|
|
23
|
+
name: z.string().describe("Deployment name"),
|
|
18
24
|
kind: z.string(),
|
|
19
25
|
title: z.string(),
|
|
26
|
+
technology: z.string().nullable(),
|
|
20
27
|
shape: z.string(),
|
|
21
|
-
|
|
28
|
+
includedInViews: includedInViewsSchema,
|
|
22
29
|
tags: z.array(z.string())
|
|
23
30
|
})
|
|
24
31
|
])
|
|
@@ -26,32 +33,69 @@ const searchResultSchema = z.array(
|
|
|
26
33
|
export const searchElement = likec4Tool({
|
|
27
34
|
name: "search-element",
|
|
28
35
|
annotations: {
|
|
29
|
-
readOnlyHint: true
|
|
36
|
+
readOnlyHint: true,
|
|
37
|
+
idempotentHint: true,
|
|
38
|
+
title: "Search elements"
|
|
30
39
|
},
|
|
31
40
|
description: `
|
|
32
|
-
Search
|
|
33
|
-
- id (FQN)
|
|
34
|
-
- title
|
|
35
|
-
- kind (if search string starts with "kind:")
|
|
36
|
-
- shape (if search string starts with "shape:")
|
|
37
|
-
- any assigned tags (if search string starts with "#")
|
|
41
|
+
Search LikeC4 elements and deployment nodes across all projects.
|
|
38
42
|
|
|
39
|
-
|
|
40
|
-
-
|
|
41
|
-
-
|
|
42
|
-
-
|
|
43
|
-
-
|
|
44
|
-
- shape
|
|
45
|
-
- project name this element belongs to
|
|
46
|
-
- assigned tags
|
|
43
|
+
Query syntax (case-insensitive):
|
|
44
|
+
- Free text: matches id (FQN) or title
|
|
45
|
+
- kind:<value>: filters by kind
|
|
46
|
+
- shape:<value>: filters by shape
|
|
47
|
+
- #<value>: matches assigned tags
|
|
47
48
|
|
|
48
|
-
|
|
49
|
-
|
|
49
|
+
Request:
|
|
50
|
+
- search: string \u2014 at least 2 characters
|
|
51
|
+
|
|
52
|
+
Response (JSON object):
|
|
53
|
+
- found: Result[] - returns top 20 results
|
|
54
|
+
- total: number - total number of results
|
|
55
|
+
|
|
56
|
+
Result (discriminated union by "type"):
|
|
57
|
+
- type = "element": { id: string, name: string, kind: string, title: string, technology: string|null, shape: string, project: string, includedInViews: View[], tags: string[] }
|
|
58
|
+
- type = "deployment-node": { id: string, name: string, kind: string, title: string, technology: string|null, shape: string, project: string, includedInViews: View[], tags: string[] }
|
|
59
|
+
|
|
60
|
+
View (object) fields:
|
|
61
|
+
- id: string \u2014 view identifier
|
|
62
|
+
- title: string \u2014 view title
|
|
63
|
+
- type: "element" | "deployment" | "dynamic"
|
|
64
|
+
|
|
65
|
+
Notes:
|
|
66
|
+
- Read-only, idempotent.
|
|
67
|
+
- Use results as input to other tools (e.g., read-element, read-view).
|
|
68
|
+
|
|
69
|
+
Example response:
|
|
70
|
+
{
|
|
71
|
+
"found": [
|
|
72
|
+
{
|
|
73
|
+
"type": "logical",
|
|
74
|
+
"project": "default",
|
|
75
|
+
"id": "shop.frontend",
|
|
76
|
+
"name": "frontend",
|
|
77
|
+
"kind": "container",
|
|
78
|
+
"title": "Frontend",
|
|
79
|
+
"technology": "React",
|
|
80
|
+
"shape": "rectangle",
|
|
81
|
+
"includedInViews": [
|
|
82
|
+
{
|
|
83
|
+
"id": "system-overview",
|
|
84
|
+
"title": "System Overview",
|
|
85
|
+
"type": "element"
|
|
86
|
+
}
|
|
87
|
+
],
|
|
88
|
+
"tags": ["public"]
|
|
89
|
+
}
|
|
90
|
+
]
|
|
91
|
+
}
|
|
92
|
+
`,
|
|
50
93
|
inputSchema: {
|
|
51
94
|
search: z.string().min(2, "Search must be at least 2 characters long")
|
|
52
95
|
},
|
|
53
96
|
outputSchema: {
|
|
54
|
-
found: searchResultSchema
|
|
97
|
+
found: searchResultSchema,
|
|
98
|
+
total: z.number()
|
|
55
99
|
}
|
|
56
100
|
}, async (languageServices, args) => {
|
|
57
101
|
const projects = languageServices.projects();
|
|
@@ -73,33 +117,40 @@ Can be used for further requests (like read-element or read-project-summary)
|
|
|
73
117
|
for (const project of projects) {
|
|
74
118
|
try {
|
|
75
119
|
const model = await languageServices.computedModel(project.id);
|
|
76
|
-
for (const el of ifilter(model.elements(), predicate)) {
|
|
120
|
+
for (const el of ifilter(model.elements(), (e) => !e.imported && predicate(e))) {
|
|
77
121
|
found.push({
|
|
78
|
-
type: "
|
|
122
|
+
type: "element",
|
|
123
|
+
project: project.id,
|
|
79
124
|
id: el.id,
|
|
125
|
+
name: el.name,
|
|
80
126
|
kind: el.kind,
|
|
81
127
|
title: el.title,
|
|
128
|
+
technology: el.technology,
|
|
82
129
|
shape: el.shape,
|
|
83
|
-
|
|
84
|
-
|
|
130
|
+
tags: [...el.tags],
|
|
131
|
+
includedInViews: includedInViews(el.views())
|
|
85
132
|
});
|
|
86
133
|
}
|
|
87
134
|
for (const el of ifilter(model.deployment.nodes(), predicate)) {
|
|
88
135
|
found.push({
|
|
89
136
|
type: "deployment-node",
|
|
137
|
+
project: project.id,
|
|
90
138
|
id: el.id,
|
|
139
|
+
name: el.name,
|
|
91
140
|
kind: el.kind,
|
|
92
141
|
title: el.title,
|
|
142
|
+
technology: el.technology,
|
|
93
143
|
shape: el.shape,
|
|
94
|
-
|
|
95
|
-
|
|
144
|
+
tags: [...el.tags],
|
|
145
|
+
includedInViews: includedInViews(el.views())
|
|
96
146
|
});
|
|
97
147
|
}
|
|
98
148
|
} catch (error) {
|
|
99
|
-
|
|
149
|
+
logger.error(`Error searching in project ${project.id}:`, { error });
|
|
100
150
|
}
|
|
101
151
|
}
|
|
102
152
|
return {
|
|
103
|
-
found
|
|
153
|
+
found: found.slice(0, 20),
|
|
154
|
+
total: found.length
|
|
104
155
|
};
|
|
105
156
|
});
|
package/dist/mcp/utils.js
CHANGED
|
@@ -2,17 +2,20 @@ import { loggable } from "@likec4/log";
|
|
|
2
2
|
import { logger as mainLogger } from "../logger.js";
|
|
3
3
|
export const logger = mainLogger.getChild("mcp");
|
|
4
4
|
export function likec4Tool(config, cb) {
|
|
5
|
-
const { name, ...rest } = config;
|
|
5
|
+
const { name, description, ...rest } = config;
|
|
6
6
|
return (languageServices) => [
|
|
7
7
|
name,
|
|
8
|
-
|
|
8
|
+
{
|
|
9
|
+
description: description?.trim() ?? "",
|
|
10
|
+
...rest
|
|
11
|
+
},
|
|
9
12
|
mkcallTool(name, languageServices, cb)
|
|
10
13
|
];
|
|
11
14
|
}
|
|
12
15
|
function mkcallTool(name, languageServices, cb) {
|
|
13
16
|
const tool = cb.bind(null, languageServices);
|
|
14
17
|
return async function callTool(args, extra) {
|
|
15
|
-
logger.debug("Calling tool {name}", { name, args });
|
|
18
|
+
logger.debug("Calling tool {name}, args: {args}", { name, args });
|
|
16
19
|
try {
|
|
17
20
|
const result = await tool.call(null, args, extra);
|
|
18
21
|
if (typeof result === "string") {
|
|
@@ -35,7 +38,7 @@ function mkcallTool(name, languageServices, cb) {
|
|
|
35
38
|
return {
|
|
36
39
|
content: [{
|
|
37
40
|
type: "text",
|
|
38
|
-
text: loggable(err)
|
|
41
|
+
text: err instanceof Error ? err.message : loggable(err)
|
|
39
42
|
}],
|
|
40
43
|
isError: true
|
|
41
44
|
};
|
|
@@ -190,16 +190,14 @@ export function buildModelData(project, docs) {
|
|
|
190
190
|
indexBy(prop("id")),
|
|
191
191
|
resolveRulesExtendedViews
|
|
192
192
|
);
|
|
193
|
-
const projectInfo = {
|
|
194
|
-
id: project.id,
|
|
195
|
-
name: project.config.name,
|
|
196
|
-
...project.config.title && { title: project.config.title }
|
|
197
|
-
};
|
|
198
193
|
return {
|
|
199
194
|
data: {
|
|
200
195
|
[c4._stage]: "parsed",
|
|
201
196
|
projectId: project.id,
|
|
202
|
-
project:
|
|
197
|
+
project: {
|
|
198
|
+
id: project.id,
|
|
199
|
+
title: project.config.title ?? project.config.name
|
|
200
|
+
},
|
|
203
201
|
specification: {
|
|
204
202
|
tags: c4Specification.tags,
|
|
205
203
|
elements: c4Specification.specs.elements,
|
|
@@ -57,7 +57,7 @@ declare const DocumentParserFromMixins: {
|
|
|
57
57
|
readonly doc: ParsedLikeC4LangiumDocument;
|
|
58
58
|
get project(): {
|
|
59
59
|
id: ProjectId;
|
|
60
|
-
|
|
60
|
+
folderUri: ProjectId;
|
|
61
61
|
config: Readonly<import("../config").ProjectConfig>;
|
|
62
62
|
};
|
|
63
63
|
resolveFqn(node: import("../generated/ast").FqnReferenceable): ProjectId;
|
|
@@ -150,7 +150,7 @@ declare const DocumentParserFromMixins: {
|
|
|
150
150
|
readonly doc: ParsedLikeC4LangiumDocument;
|
|
151
151
|
get project(): {
|
|
152
152
|
id: ProjectId;
|
|
153
|
-
|
|
153
|
+
folderUri: ProjectId;
|
|
154
154
|
config: Readonly<import("../config").ProjectConfig>;
|
|
155
155
|
};
|
|
156
156
|
resolveFqn(node: import("../generated/ast").FqnReferenceable): ProjectId;
|
|
@@ -205,7 +205,7 @@ declare const DocumentParserFromMixins: {
|
|
|
205
205
|
readonly doc: ParsedLikeC4LangiumDocument;
|
|
206
206
|
get project(): {
|
|
207
207
|
id: ProjectId;
|
|
208
|
-
|
|
208
|
+
folderUri: ProjectId;
|
|
209
209
|
config: Readonly<import("../config").ProjectConfig>;
|
|
210
210
|
};
|
|
211
211
|
resolveFqn(node: import("../generated/ast").FqnReferenceable): ProjectId;
|
|
@@ -274,7 +274,7 @@ declare const DocumentParserFromMixins: {
|
|
|
274
274
|
readonly doc: ParsedLikeC4LangiumDocument;
|
|
275
275
|
get project(): {
|
|
276
276
|
id: ProjectId;
|
|
277
|
-
|
|
277
|
+
folderUri: ProjectId;
|
|
278
278
|
config: Readonly<import("../config").ProjectConfig>;
|
|
279
279
|
};
|
|
280
280
|
resolveFqn(node: import("../generated/ast").FqnReferenceable): ProjectId;
|
|
@@ -336,7 +336,7 @@ declare const DocumentParserFromMixins: {
|
|
|
336
336
|
readonly doc: ParsedLikeC4LangiumDocument;
|
|
337
337
|
get project(): {
|
|
338
338
|
id: ProjectId;
|
|
339
|
-
|
|
339
|
+
folderUri: ProjectId;
|
|
340
340
|
config: Readonly<import("../config").ProjectConfig>;
|
|
341
341
|
};
|
|
342
342
|
resolveFqn(node: import("../generated/ast").FqnReferenceable): ProjectId;
|
|
@@ -406,7 +406,7 @@ declare const DocumentParserFromMixins: {
|
|
|
406
406
|
readonly doc: ParsedLikeC4LangiumDocument;
|
|
407
407
|
get project(): {
|
|
408
408
|
id: ProjectId;
|
|
409
|
-
|
|
409
|
+
folderUri: ProjectId;
|
|
410
410
|
config: Readonly<import("../config").ProjectConfig>;
|
|
411
411
|
};
|
|
412
412
|
resolveFqn(node: import("../generated/ast").FqnReferenceable): ProjectId;
|
|
@@ -469,7 +469,7 @@ declare const DocumentParserFromMixins: {
|
|
|
469
469
|
readonly doc: ParsedLikeC4LangiumDocument;
|
|
470
470
|
get project(): {
|
|
471
471
|
id: ProjectId;
|
|
472
|
-
|
|
472
|
+
folderUri: ProjectId;
|
|
473
473
|
config: Readonly<import("../config").ProjectConfig>;
|
|
474
474
|
};
|
|
475
475
|
resolveFqn(node: import("../generated/ast").FqnReferenceable): ProjectId;
|
|
@@ -512,7 +512,7 @@ declare const DocumentParserFromMixins: {
|
|
|
512
512
|
readonly doc: ParsedLikeC4LangiumDocument;
|
|
513
513
|
get project(): {
|
|
514
514
|
id: ProjectId;
|
|
515
|
-
|
|
515
|
+
folderUri: ProjectId;
|
|
516
516
|
config: Readonly<import("../config").ProjectConfig>;
|
|
517
517
|
};
|
|
518
518
|
resolveFqn(node: import("../generated/ast").FqnReferenceable): ProjectId;
|
|
@@ -570,7 +570,7 @@ declare const DocumentParserFromMixins: {
|
|
|
570
570
|
readonly doc: ParsedLikeC4LangiumDocument;
|
|
571
571
|
get project(): {
|
|
572
572
|
id: ProjectId;
|
|
573
|
-
|
|
573
|
+
folderUri: ProjectId;
|
|
574
574
|
config: Readonly<import("../config").ProjectConfig>;
|
|
575
575
|
};
|
|
576
576
|
resolveFqn(node: import("../generated/ast").FqnReferenceable): ProjectId;
|
|
@@ -37,6 +37,9 @@ export class LikeC4ModelParser {
|
|
|
37
37
|
DocumentState.Linked,
|
|
38
38
|
(doc) => {
|
|
39
39
|
try {
|
|
40
|
+
if (services.shared.workspace.ProjectsManager.checkIfExcluded(doc)) {
|
|
41
|
+
return;
|
|
42
|
+
}
|
|
40
43
|
if (!isLikeC4Builtin(doc.uri)) {
|
|
41
44
|
this.cachedParsers.set(doc, this.createParser(doc));
|
|
42
45
|
}
|
|
@@ -25,7 +25,7 @@ export declare class BaseParser {
|
|
|
25
25
|
constructor(services: LikeC4Services, doc: ParsedLikeC4LangiumDocument);
|
|
26
26
|
get project(): {
|
|
27
27
|
id: c4.ProjectId;
|
|
28
|
-
|
|
28
|
+
folderUri: URI;
|
|
29
29
|
config: Readonly<ProjectConfig>;
|
|
30
30
|
};
|
|
31
31
|
resolveFqn(node: ast.FqnReferenceable): c4.Fqn;
|
|
@@ -187,7 +187,7 @@ export class BaseParser {
|
|
|
187
187
|
return joinRelativeURL(this.doc.uri.toString(), "../", value);
|
|
188
188
|
}
|
|
189
189
|
case (value && hasLeadingSlash(value)): {
|
|
190
|
-
return joinURL(this.project.
|
|
190
|
+
return joinURL(this.project.folderUri.toString(), value);
|
|
191
191
|
}
|
|
192
192
|
default: {
|
|
193
193
|
return void 0;
|
|
@@ -32,7 +32,7 @@ export declare function DeploymentModelParser<TBase extends WithExpressionV2>(B:
|
|
|
32
32
|
readonly doc: import("../../ast").ParsedLikeC4LangiumDocument;
|
|
33
33
|
get project(): {
|
|
34
34
|
id: c4.ProjectId;
|
|
35
|
-
|
|
35
|
+
folderUri: c4;
|
|
36
36
|
config: Readonly<import("../../config").ProjectConfig>;
|
|
37
37
|
};
|
|
38
38
|
resolveFqn(node: ast.FqnReferenceable): c4.Fqn;
|