@likec4/language-server 1.33.0 → 1.34.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/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 +7 -7
- 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
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
import { invariant } from "@likec4/core";
|
|
2
|
+
import { keys } from "remeda";
|
|
3
|
+
import z from "zod";
|
|
4
|
+
import { ProjectsManager } from "../../workspace/index.js";
|
|
5
|
+
import { likec4Tool } from "../utils.js";
|
|
6
|
+
import { locationSchema } from "./_common.js";
|
|
7
|
+
export const readProjectSummary = likec4Tool({
|
|
8
|
+
name: "read-project-summary",
|
|
9
|
+
annotations: {
|
|
10
|
+
readOnlyHint: true
|
|
11
|
+
},
|
|
12
|
+
description: `
|
|
13
|
+
Searches for LikeC4 project by name in workspace and returns its summary:
|
|
14
|
+
- project folder
|
|
15
|
+
- array of the source filenames
|
|
16
|
+
- specification:
|
|
17
|
+
- all element kinds
|
|
18
|
+
- all relationship kinds
|
|
19
|
+
- all deployment kinds
|
|
20
|
+
- all tags (used and unused)
|
|
21
|
+
- used metadata keys
|
|
22
|
+
- array of the views, where each view:
|
|
23
|
+
- name
|
|
24
|
+
- type ("element", "deployment", "dynamic")
|
|
25
|
+
- title
|
|
26
|
+
`,
|
|
27
|
+
inputSchema: {
|
|
28
|
+
project: z.string().optional().describe('Project name (optional, will use "default" if not specified)')
|
|
29
|
+
},
|
|
30
|
+
outputSchema: {
|
|
31
|
+
folder: z.string(),
|
|
32
|
+
sources: z.array(z.string()),
|
|
33
|
+
specification: z.object({
|
|
34
|
+
elementKinds: z.array(z.string()),
|
|
35
|
+
relationshipKinds: z.array(z.string()),
|
|
36
|
+
deploymentKinds: z.array(z.string()),
|
|
37
|
+
tags: z.array(z.string()),
|
|
38
|
+
metadataKeys: z.array(z.string())
|
|
39
|
+
}),
|
|
40
|
+
views: z.array(z.object({
|
|
41
|
+
name: z.string(),
|
|
42
|
+
title: z.string().nullable(),
|
|
43
|
+
type: z.enum(["element", "deployment", "dynamic"]),
|
|
44
|
+
sourceLocation: locationSchema.nullish()
|
|
45
|
+
}))
|
|
46
|
+
}
|
|
47
|
+
}, async (languageServices, args) => {
|
|
48
|
+
const projectId = args.project ?? ProjectsManager.DefaultProjectId;
|
|
49
|
+
const project = languageServices.projects().find((p) => p.id === projectId);
|
|
50
|
+
invariant(project, `Project "${projectId}" not found`);
|
|
51
|
+
const model = await languageServices.computedModel(project.id);
|
|
52
|
+
return {
|
|
53
|
+
folder: project.folder.toString(),
|
|
54
|
+
sources: project.documents?.map((d) => d.toString()) ?? [],
|
|
55
|
+
specification: {
|
|
56
|
+
elementKinds: keys(model.specification.elements),
|
|
57
|
+
relationshipKinds: keys(model.specification.relationships),
|
|
58
|
+
deploymentKinds: keys(model.specification.deployments),
|
|
59
|
+
tags: [...model.tags],
|
|
60
|
+
metadataKeys: model.specification.metadataKeys ?? []
|
|
61
|
+
},
|
|
62
|
+
views: [...model.views()].map((v) => ({
|
|
63
|
+
name: v.id,
|
|
64
|
+
title: v.title,
|
|
65
|
+
type: v.$view._type
|
|
66
|
+
}))
|
|
67
|
+
};
|
|
68
|
+
});
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import z from 'zod';
|
|
2
|
+
export declare const readView: (languageServices: import("../..").LikeC4LanguageServices) => [string, {
|
|
3
|
+
inputSchema?: {
|
|
4
|
+
viewId: z.ZodString;
|
|
5
|
+
project: z.ZodOptional<z.ZodString>;
|
|
6
|
+
} | undefined;
|
|
7
|
+
}, (args: {
|
|
8
|
+
viewId: string;
|
|
9
|
+
project?: string | undefined;
|
|
10
|
+
}, extra: import("@modelcontextprotocol/sdk/shared/protocol").RequestHandlerExtra<import("@modelcontextprotocol/sdk/types").ServerRequest, import("@modelcontextprotocol/sdk/types").ServerNotification>) => import("@modelcontextprotocol/sdk/types").CallToolResult | Promise<import("@modelcontextprotocol/sdk/types").CallToolResult>];
|
|
@@ -0,0 +1,164 @@
|
|
|
1
|
+
import { invariant } from "@likec4/core";
|
|
2
|
+
import z from "zod";
|
|
3
|
+
import { safeCall } from "../../utils/index.js";
|
|
4
|
+
import { ProjectsManager } from "../../workspace/index.js";
|
|
5
|
+
import { likec4Tool } from "../utils.js";
|
|
6
|
+
import { locationSchema } from "./_common.js";
|
|
7
|
+
const modelRef = (node) => {
|
|
8
|
+
if (node.hasElement()) {
|
|
9
|
+
return node.element.id;
|
|
10
|
+
}
|
|
11
|
+
if (node.hasDeployment()) {
|
|
12
|
+
return node.deployment.id;
|
|
13
|
+
}
|
|
14
|
+
return null;
|
|
15
|
+
};
|
|
16
|
+
export const readView = likec4Tool({
|
|
17
|
+
name: "read-view",
|
|
18
|
+
description: `
|
|
19
|
+
Returns information about LikeC4 view, includes:
|
|
20
|
+
- id (view name)
|
|
21
|
+
- type (element, deployment, dynamic)
|
|
22
|
+
- title, description, tags
|
|
23
|
+
- project name this view belongs to
|
|
24
|
+
- array of elements included in this view
|
|
25
|
+
- array of relationships in this view (source, target, title, description, technology, tags)
|
|
26
|
+
- viewOf (element id this view is the default view of)
|
|
27
|
+
- source location (if running in the editor)
|
|
28
|
+
`.trimStart(),
|
|
29
|
+
annotations: {
|
|
30
|
+
readOnlyHint: true
|
|
31
|
+
},
|
|
32
|
+
inputSchema: {
|
|
33
|
+
viewId: z.string().describe("View id (name)"),
|
|
34
|
+
project: z.string().optional().describe('Project name (optional, will use "default" if not specified)')
|
|
35
|
+
},
|
|
36
|
+
outputSchema: {
|
|
37
|
+
id: z.string(),
|
|
38
|
+
type: z.enum(["element", "deployment", "dynamic"]),
|
|
39
|
+
title: z.string().nullish(),
|
|
40
|
+
description: z.string().nullish(),
|
|
41
|
+
tags: z.array(z.string()),
|
|
42
|
+
project: z.string(),
|
|
43
|
+
elements: z.array(
|
|
44
|
+
z.discriminatedUnion("type", [
|
|
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(
|
|
80
|
+
z.object({
|
|
81
|
+
source: z.string().describe("Source element ID"),
|
|
82
|
+
target: z.string().describe("Target element ID"),
|
|
83
|
+
title: z.string().nullish(),
|
|
84
|
+
description: z.string().nullish(),
|
|
85
|
+
technology: z.string().nullish(),
|
|
86
|
+
tags: z.array(z.string())
|
|
87
|
+
})
|
|
88
|
+
).describe("Relationships in this view"),
|
|
89
|
+
defaultViewOf: z.string().optional().describe("Element ID (FQN) this view is the default view of"),
|
|
90
|
+
sourceLocation: locationSchema.nullish()
|
|
91
|
+
}
|
|
92
|
+
}, async (languageServices, args) => {
|
|
93
|
+
const projectId = args.project ?? ProjectsManager.DefaultProjectId;
|
|
94
|
+
const project = languageServices.projects().find((p) => p.id === projectId);
|
|
95
|
+
invariant(project, `Project "${projectId}" not found`);
|
|
96
|
+
const model = await languageServices.computedModel(project.id);
|
|
97
|
+
const view = model.findView(args.viewId);
|
|
98
|
+
if (!view) {
|
|
99
|
+
throw new Error(`View with ID '${args.viewId}' not found in project ${project.id}`);
|
|
100
|
+
}
|
|
101
|
+
return {
|
|
102
|
+
id: view.id,
|
|
103
|
+
type: view.$view._type,
|
|
104
|
+
title: view.title,
|
|
105
|
+
description: view.description.text,
|
|
106
|
+
tags: [...view.tags],
|
|
107
|
+
project: project.id,
|
|
108
|
+
elements: [...view.nodes()].flatMap((node) => {
|
|
109
|
+
if (node.hasDeployedInstance()) {
|
|
110
|
+
return {
|
|
111
|
+
type: "deployed-instance",
|
|
112
|
+
id: node.deployment.id,
|
|
113
|
+
title: node.title,
|
|
114
|
+
logicalElementId: node.deployment.element.id,
|
|
115
|
+
description: node.description.text,
|
|
116
|
+
technology: node.technology,
|
|
117
|
+
shape: node.shape,
|
|
118
|
+
tags: [...node.tags]
|
|
119
|
+
};
|
|
120
|
+
}
|
|
121
|
+
if (node.hasDeployment()) {
|
|
122
|
+
return {
|
|
123
|
+
type: "deployment-node",
|
|
124
|
+
id: node.deployment.id,
|
|
125
|
+
title: node.title,
|
|
126
|
+
kind: node.deployment.kind,
|
|
127
|
+
description: node.description.text,
|
|
128
|
+
technology: node.technology,
|
|
129
|
+
shape: node.shape,
|
|
130
|
+
tags: [...node.tags],
|
|
131
|
+
children: [...node.children()].flatMap((c) => modelRef(c) ?? [])
|
|
132
|
+
};
|
|
133
|
+
}
|
|
134
|
+
if (node.hasElement()) {
|
|
135
|
+
return {
|
|
136
|
+
type: "logical",
|
|
137
|
+
id: node.element.id,
|
|
138
|
+
title: node.title,
|
|
139
|
+
kind: node.element.kind,
|
|
140
|
+
description: node.description.text,
|
|
141
|
+
technology: node.technology,
|
|
142
|
+
shape: node.shape,
|
|
143
|
+
tags: [...node.tags],
|
|
144
|
+
children: [...node.children()].flatMap((c) => modelRef(c) ?? [])
|
|
145
|
+
};
|
|
146
|
+
}
|
|
147
|
+
return [];
|
|
148
|
+
}),
|
|
149
|
+
viewOf: view.viewOf?.id,
|
|
150
|
+
relationships: [...view.edges()].flatMap((r) => {
|
|
151
|
+
const source = modelRef(r.source);
|
|
152
|
+
const target = modelRef(r.target);
|
|
153
|
+
return source && target ? [{
|
|
154
|
+
source,
|
|
155
|
+
target,
|
|
156
|
+
title: r.label,
|
|
157
|
+
description: r.description.text,
|
|
158
|
+
technology: r.technology,
|
|
159
|
+
tags: [...r.tags]
|
|
160
|
+
}] : [];
|
|
161
|
+
}),
|
|
162
|
+
sourceLocation: safeCall(() => languageServices.locate({ view: view.id, projectId }))
|
|
163
|
+
};
|
|
164
|
+
});
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import z from 'zod';
|
|
2
|
+
export declare const searchElement: (languageServices: import("../..").LikeC4LanguageServices) => [string, {
|
|
3
|
+
inputSchema?: {
|
|
4
|
+
search: z.ZodString;
|
|
5
|
+
} | undefined;
|
|
6
|
+
}, (args: {
|
|
7
|
+
search: string;
|
|
8
|
+
}, extra: import("@modelcontextprotocol/sdk/shared/protocol").RequestHandlerExtra<import("@modelcontextprotocol/sdk/types").ServerRequest, import("@modelcontextprotocol/sdk/types").ServerNotification>) => import("@modelcontextprotocol/sdk/types").CallToolResult | Promise<import("@modelcontextprotocol/sdk/types").CallToolResult>];
|
|
@@ -0,0 +1,105 @@
|
|
|
1
|
+
import { ifilter } from "@likec4/core/utils";
|
|
2
|
+
import z from "zod";
|
|
3
|
+
import { likec4Tool } from "../utils.js";
|
|
4
|
+
const searchResultSchema = z.array(
|
|
5
|
+
z.discriminatedUnion("type", [
|
|
6
|
+
z.object({
|
|
7
|
+
type: z.literal("logical"),
|
|
8
|
+
id: z.string().describe("Element ID (FQN)"),
|
|
9
|
+
kind: z.string(),
|
|
10
|
+
title: z.string(),
|
|
11
|
+
shape: z.string(),
|
|
12
|
+
project: z.string().describe("Project name"),
|
|
13
|
+
tags: z.array(z.string())
|
|
14
|
+
}),
|
|
15
|
+
z.object({
|
|
16
|
+
type: z.literal("deployment-node"),
|
|
17
|
+
id: z.string().describe("Deployment ID (FQN)"),
|
|
18
|
+
kind: z.string(),
|
|
19
|
+
title: z.string(),
|
|
20
|
+
shape: z.string(),
|
|
21
|
+
project: z.string().describe("Project name"),
|
|
22
|
+
tags: z.array(z.string())
|
|
23
|
+
})
|
|
24
|
+
])
|
|
25
|
+
);
|
|
26
|
+
export const searchElement = likec4Tool({
|
|
27
|
+
name: "search-element",
|
|
28
|
+
annotations: {
|
|
29
|
+
readOnlyHint: true
|
|
30
|
+
},
|
|
31
|
+
description: `
|
|
32
|
+
Search for LikeC4 elements and deployment nodes by partial match of:
|
|
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 "#")
|
|
38
|
+
|
|
39
|
+
Returns array of found elements with:
|
|
40
|
+
- type (logical or deployment-node)
|
|
41
|
+
- id (FQN)
|
|
42
|
+
- kind
|
|
43
|
+
- title
|
|
44
|
+
- shape
|
|
45
|
+
- project name this element belongs to
|
|
46
|
+
- assigned tags
|
|
47
|
+
|
|
48
|
+
Can be used for further requests (like read-element or read-project-summary)
|
|
49
|
+
`.trimStart(),
|
|
50
|
+
inputSchema: {
|
|
51
|
+
search: z.string().min(2, "Search must be at least 2 characters long")
|
|
52
|
+
},
|
|
53
|
+
outputSchema: {
|
|
54
|
+
found: searchResultSchema
|
|
55
|
+
}
|
|
56
|
+
}, async (languageServices, args) => {
|
|
57
|
+
const projects = languageServices.projects();
|
|
58
|
+
const found = [];
|
|
59
|
+
let search = args.search.toLowerCase();
|
|
60
|
+
let predicate;
|
|
61
|
+
if (search.startsWith("kind:")) {
|
|
62
|
+
search = search.slice(5);
|
|
63
|
+
predicate = (el) => el.kind.toLowerCase().includes(search);
|
|
64
|
+
} else if (search.startsWith("shape:")) {
|
|
65
|
+
search = search.slice(6);
|
|
66
|
+
predicate = (el) => el.shape.toLowerCase().includes(search);
|
|
67
|
+
} else if (search.startsWith("#")) {
|
|
68
|
+
search = search.slice(1);
|
|
69
|
+
predicate = (el) => el.tags.some((tag) => tag.toLowerCase().includes(search));
|
|
70
|
+
} else {
|
|
71
|
+
predicate = (el) => el.id.toLowerCase().includes(search) || el.title.toLowerCase().includes(search);
|
|
72
|
+
}
|
|
73
|
+
for (const project of projects) {
|
|
74
|
+
try {
|
|
75
|
+
const model = await languageServices.computedModel(project.id);
|
|
76
|
+
for (const el of ifilter(model.elements(), predicate)) {
|
|
77
|
+
found.push({
|
|
78
|
+
type: "logical",
|
|
79
|
+
id: el.id,
|
|
80
|
+
kind: el.kind,
|
|
81
|
+
title: el.title,
|
|
82
|
+
shape: el.shape,
|
|
83
|
+
project: project.id,
|
|
84
|
+
tags: [...el.tags]
|
|
85
|
+
});
|
|
86
|
+
}
|
|
87
|
+
for (const el of ifilter(model.deployment.nodes(), predicate)) {
|
|
88
|
+
found.push({
|
|
89
|
+
type: "deployment-node",
|
|
90
|
+
id: el.id,
|
|
91
|
+
kind: el.kind,
|
|
92
|
+
title: el.title,
|
|
93
|
+
shape: el.shape,
|
|
94
|
+
project: project.id,
|
|
95
|
+
tags: [...el.tags]
|
|
96
|
+
});
|
|
97
|
+
}
|
|
98
|
+
} catch (error) {
|
|
99
|
+
console.error(`Error searching in project ${project.id}:`, error);
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
return {
|
|
103
|
+
found
|
|
104
|
+
};
|
|
105
|
+
});
|
package/dist/mcp/utils.d.ts
CHANGED
|
@@ -1,35 +1,18 @@
|
|
|
1
|
-
import
|
|
2
|
-
import {
|
|
1
|
+
import type { RequestHandlerExtra } from '@modelcontextprotocol/sdk/shared/protocol.js';
|
|
2
|
+
import type { ServerNotification, ServerRequest, ToolAnnotations } from '@modelcontextprotocol/sdk/types.js';
|
|
3
|
+
import type { z, ZodRawShape, ZodTypeAny } from 'zod';
|
|
4
|
+
import type { ToolCallback } from '@modelcontextprotocol/sdk/server/mcp.js';
|
|
3
5
|
import type { LikeC4LanguageServices } from '../LikeC4LanguageServices';
|
|
4
|
-
export declare
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
tags: any;
|
|
18
|
-
children: any;
|
|
19
|
-
relations: {
|
|
20
|
-
incoming: any;
|
|
21
|
-
outgoing: any;
|
|
22
|
-
};
|
|
23
|
-
views: any;
|
|
24
|
-
sourceFile: import("../protocol").Locate.Res;
|
|
25
|
-
};
|
|
26
|
-
export declare function modelViewResource(languageServices: LikeC4LanguageServices, view: LikeC4ViewModel<aux.Any>, projectId?: ProjectId): {
|
|
27
|
-
id: any;
|
|
28
|
-
title: any;
|
|
29
|
-
projectId: any;
|
|
30
|
-
viewType: LikeC4ViewModel<aux.Any>;
|
|
31
|
-
description: any;
|
|
32
|
-
tags: any;
|
|
33
|
-
nodes: any;
|
|
34
|
-
sourceFile: import("../protocol").Locate.Res;
|
|
35
|
-
};
|
|
6
|
+
export declare const logger: any;
|
|
7
|
+
type ToolResult<Out extends undefined | ZodRawShape = undefined> = Out extends ZodRawShape ? z.objectOutputType<Out, ZodTypeAny> : string;
|
|
8
|
+
type LikeC4ToolCallback<Args extends undefined | ZodRawShape, Out extends undefined | ZodRawShape> = Args extends ZodRawShape ? (languageServices: LikeC4LanguageServices, args: z.objectOutputType<Args, ZodTypeAny>, extra: RequestHandlerExtra<ServerRequest, ServerNotification>) => Promise<ToolResult<Out>> : (languageServices: LikeC4LanguageServices, extra: RequestHandlerExtra<ServerRequest, ServerNotification>) => Promise<ToolResult<Out>>;
|
|
9
|
+
export declare function likec4Tool<InputArgs extends ZodRawShape, OutputArgs extends ZodRawShape, Cb extends LikeC4ToolCallback<InputArgs, OutputArgs>>(config: {
|
|
10
|
+
name: string;
|
|
11
|
+
description?: string;
|
|
12
|
+
inputSchema?: InputArgs;
|
|
13
|
+
outputSchema?: OutputArgs;
|
|
14
|
+
annotations?: ToolAnnotations;
|
|
15
|
+
}, cb: Cb): (languageServices: LikeC4LanguageServices) => [string, {
|
|
16
|
+
inputSchema?: InputArgs;
|
|
17
|
+
}, ToolCallback<InputArgs>];
|
|
18
|
+
export {};
|
package/dist/mcp/utils.js
CHANGED
|
@@ -1,104 +1,44 @@
|
|
|
1
|
-
import {
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
title: el.title,
|
|
12
|
-
kind: el.kind,
|
|
13
|
-
shape: el.shape,
|
|
14
|
-
technology: el.technology,
|
|
15
|
-
description: el.description,
|
|
16
|
-
tags: el.tags,
|
|
17
|
-
children: toArray(imap(el.children(), (c) => ({
|
|
18
|
-
id: c.id,
|
|
19
|
-
title: c.title,
|
|
20
|
-
kind: el.kind
|
|
21
|
-
}))),
|
|
22
|
-
relations: {
|
|
23
|
-
incoming: toArray(imap(el.incoming(), (r) => ({
|
|
24
|
-
id: r.id,
|
|
25
|
-
title: r.title,
|
|
26
|
-
description: r.description,
|
|
27
|
-
technology: r.technology,
|
|
28
|
-
source: {
|
|
29
|
-
id: r.source.id,
|
|
30
|
-
title: r.source.title,
|
|
31
|
-
kind: r.source.kind
|
|
32
|
-
},
|
|
33
|
-
...r.target.id === el.id ? {
|
|
34
|
-
type: "direct"
|
|
35
|
-
} : {
|
|
36
|
-
type: "implicit, to nested",
|
|
37
|
-
target: {
|
|
38
|
-
id: r.target.id,
|
|
39
|
-
title: r.target.title,
|
|
40
|
-
kind: r.target.kind
|
|
41
|
-
}
|
|
42
|
-
}
|
|
43
|
-
}))),
|
|
44
|
-
outgoing: toArray(imap(el.outgoing(), (r) => ({
|
|
45
|
-
id: r.id,
|
|
46
|
-
title: r.title,
|
|
47
|
-
description: r.description,
|
|
48
|
-
technology: r.technology,
|
|
49
|
-
target: {
|
|
50
|
-
id: r.target.id,
|
|
51
|
-
title: r.target.title,
|
|
52
|
-
kind: r.target.kind
|
|
53
|
-
},
|
|
54
|
-
...r.source.id === el.id ? {
|
|
55
|
-
type: "direct"
|
|
56
|
-
} : {
|
|
57
|
-
type: "implicit, from nested",
|
|
58
|
-
source: {
|
|
59
|
-
id: r.source.id,
|
|
60
|
-
title: r.source.title,
|
|
61
|
-
kind: r.source.kind
|
|
62
|
-
}
|
|
63
|
-
}
|
|
64
|
-
})))
|
|
65
|
-
},
|
|
66
|
-
views: toArray(imap(el.views(), (v) => ({
|
|
67
|
-
id: v.id,
|
|
68
|
-
title: v.title
|
|
69
|
-
}))),
|
|
70
|
-
sourceFile: languageServices.locate({
|
|
71
|
-
element: el.id,
|
|
72
|
-
projectId
|
|
73
|
-
})
|
|
74
|
-
};
|
|
1
|
+
import { loggable } from "@likec4/log";
|
|
2
|
+
import { logger as mainLogger } from "../logger.js";
|
|
3
|
+
export const logger = mainLogger.getChild("mcp");
|
|
4
|
+
export function likec4Tool(config, cb) {
|
|
5
|
+
const { name, ...rest } = config;
|
|
6
|
+
return (languageServices) => [
|
|
7
|
+
name,
|
|
8
|
+
rest,
|
|
9
|
+
mkcallTool(name, languageServices, cb)
|
|
10
|
+
];
|
|
75
11
|
}
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
}
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
12
|
+
function mkcallTool(name, languageServices, cb) {
|
|
13
|
+
const tool = cb.bind(null, languageServices);
|
|
14
|
+
return async function callTool(args, extra) {
|
|
15
|
+
logger.debug("Calling tool {name}", { name, args });
|
|
16
|
+
try {
|
|
17
|
+
const result = await tool.call(null, args, extra);
|
|
18
|
+
if (typeof result === "string") {
|
|
19
|
+
return {
|
|
20
|
+
content: [{
|
|
21
|
+
type: "text",
|
|
22
|
+
text: result
|
|
23
|
+
}]
|
|
24
|
+
};
|
|
25
|
+
}
|
|
26
|
+
return {
|
|
27
|
+
content: [{
|
|
28
|
+
type: "text",
|
|
29
|
+
text: JSON.stringify(result)
|
|
30
|
+
}],
|
|
31
|
+
structuredContent: result
|
|
32
|
+
};
|
|
33
|
+
} catch (err) {
|
|
34
|
+
logger.error(`Tool ${name} failed`, { err });
|
|
35
|
+
return {
|
|
36
|
+
content: [{
|
|
37
|
+
type: "text",
|
|
38
|
+
text: loggable(err)
|
|
39
|
+
}],
|
|
40
|
+
isError: true
|
|
41
|
+
};
|
|
42
|
+
}
|
|
103
43
|
};
|
|
104
44
|
}
|
|
@@ -1,3 +1,4 @@
|
|
|
1
1
|
import type * as c4 from '@likec4/core';
|
|
2
2
|
import { ast } from '../ast';
|
|
3
3
|
export declare function parseWhereClause(astNode: ast.WhereExpression): c4.WhereOperator;
|
|
4
|
+
export declare function createBinaryOperator(operator: Lowercase<ast.WhereBinaryExpression['operator']>, left: c4.WhereOperator, right: c4.WhereOperator | null): c4.WhereOperator;
|
|
@@ -45,32 +45,38 @@ export function parseWhereClause(astNode) {
|
|
|
45
45
|
const left = parseWhereClause(astNode.left);
|
|
46
46
|
const right = parseWhereClause(astNode.right);
|
|
47
47
|
const operator = astNode.operator.toLowerCase();
|
|
48
|
-
|
|
49
|
-
case "and": {
|
|
50
|
-
const operands = [
|
|
51
|
-
isAndOperator(left) ? left.and : left,
|
|
52
|
-
isAndOperator(right) ? right.and : right
|
|
53
|
-
].flat();
|
|
54
|
-
invariant(isNonEmptyArray(operands), "Expected non-empty array");
|
|
55
|
-
return {
|
|
56
|
-
and: operands
|
|
57
|
-
};
|
|
58
|
-
}
|
|
59
|
-
case "or": {
|
|
60
|
-
const operands = [
|
|
61
|
-
isOrOperator(left) ? left.or : left,
|
|
62
|
-
isOrOperator(right) ? right.or : right
|
|
63
|
-
].flat();
|
|
64
|
-
invariant(isNonEmptyArray(operands), "Expected non-empty array");
|
|
65
|
-
return {
|
|
66
|
-
or: operands
|
|
67
|
-
};
|
|
68
|
-
}
|
|
69
|
-
default:
|
|
70
|
-
nonexhaustive(operator);
|
|
71
|
-
}
|
|
48
|
+
return createBinaryOperator(operator, left, right);
|
|
72
49
|
}
|
|
73
50
|
default:
|
|
74
51
|
nonexhaustive(astNode);
|
|
75
52
|
}
|
|
76
53
|
}
|
|
54
|
+
export function createBinaryOperator(operator, left, right) {
|
|
55
|
+
if (right === null) {
|
|
56
|
+
return left;
|
|
57
|
+
}
|
|
58
|
+
switch (operator) {
|
|
59
|
+
case "and": {
|
|
60
|
+
const operands = [
|
|
61
|
+
isAndOperator(left) ? left.and : left,
|
|
62
|
+
isAndOperator(right) ? right.and : right
|
|
63
|
+
].flat();
|
|
64
|
+
invariant(isNonEmptyArray(operands), "Expected non-empty array");
|
|
65
|
+
return {
|
|
66
|
+
and: operands
|
|
67
|
+
};
|
|
68
|
+
}
|
|
69
|
+
case "or": {
|
|
70
|
+
const operands = [
|
|
71
|
+
isOrOperator(left) ? left.or : left,
|
|
72
|
+
isOrOperator(right) ? right.or : right
|
|
73
|
+
].flat();
|
|
74
|
+
invariant(isNonEmptyArray(operands), "Expected non-empty array");
|
|
75
|
+
return {
|
|
76
|
+
or: operands
|
|
77
|
+
};
|
|
78
|
+
}
|
|
79
|
+
default:
|
|
80
|
+
nonexhaustive(operator);
|
|
81
|
+
}
|
|
82
|
+
}
|