@atlisp/mcp 1.0.13 → 1.0.15
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/package.json +1 -1
- package/src/atlisp-mcp.js +87 -2
- package/src/cad-worker.js +49 -1
- package/src/handlers/cad-handlers.js +1 -1
- package/src/handlers/resource-handlers.js +304 -0
- package/src/subscription-manager.js +26 -0
package/package.json
CHANGED
package/src/atlisp-mcp.js
CHANGED
|
@@ -5,6 +5,10 @@ import { StdioServerTransport } from '@modelcontextprotocol/sdk/server/stdio.js'
|
|
|
5
5
|
import {
|
|
6
6
|
ListToolsRequestSchema,
|
|
7
7
|
CallToolRequestSchema,
|
|
8
|
+
ListResourcesRequestSchema,
|
|
9
|
+
ReadResourceRequestSchema,
|
|
10
|
+
SubscribeRequestSchema,
|
|
11
|
+
UnsubscribeRequestSchema,
|
|
8
12
|
} from '@modelcontextprotocol/sdk/types.js';
|
|
9
13
|
import { cad } from './cad.js';
|
|
10
14
|
import { CAD_PLATFORMS, FILE_EXTENSIONS, PROTOCOL_VERSION, SERVER_NAME, SERVER_VERSION } from './constants.js';
|
|
@@ -12,6 +16,8 @@ import { log } from './logger.js';
|
|
|
12
16
|
import * as cadHandlers from './handlers/cad-handlers.js';
|
|
13
17
|
import * as packageHandlers from './handlers/package-handlers.js';
|
|
14
18
|
import * as functionHandlers from './handlers/function-handlers.js';
|
|
19
|
+
import { listResources, readResource } from './handlers/resource-handlers.js';
|
|
20
|
+
import * as subMgr from './subscription-manager.js';
|
|
15
21
|
import { createSseResponseHandler } from './sse-utils.js';
|
|
16
22
|
|
|
17
23
|
const PORT = process.env.PORT || 8110;
|
|
@@ -184,7 +190,7 @@ let server = null;
|
|
|
184
190
|
export function createMcpServer() {
|
|
185
191
|
server = new Server(
|
|
186
192
|
{ name: SERVER_NAME, version: SERVER_VERSION },
|
|
187
|
-
{ capabilities: { tools: {} } }
|
|
193
|
+
{ capabilities: { tools: {}, resources: { subscribe: true, listChanged: true } } }
|
|
188
194
|
);
|
|
189
195
|
|
|
190
196
|
server.setRequestHandler(ListToolsRequestSchema, async () => ({ tools }));
|
|
@@ -194,6 +200,42 @@ export function createMcpServer() {
|
|
|
194
200
|
return await handleToolCall(name, args || {});
|
|
195
201
|
});
|
|
196
202
|
|
|
203
|
+
server.setRequestHandler(ListResourcesRequestSchema, async () => ({
|
|
204
|
+
resources: await listResources(subMgr.list())
|
|
205
|
+
}));
|
|
206
|
+
|
|
207
|
+
server.setRequestHandler(ReadResourceRequestSchema, async (request) => {
|
|
208
|
+
const { uri } = request.params;
|
|
209
|
+
try {
|
|
210
|
+
const data = await readResource(uri);
|
|
211
|
+
return {
|
|
212
|
+
contents: [{
|
|
213
|
+
uri,
|
|
214
|
+
mimeType: 'application/json',
|
|
215
|
+
text: JSON.stringify(data)
|
|
216
|
+
}]
|
|
217
|
+
};
|
|
218
|
+
} catch (e) {
|
|
219
|
+
return {
|
|
220
|
+
contents: [],
|
|
221
|
+
isError: true,
|
|
222
|
+
error: { code: -32603, message: e.message }
|
|
223
|
+
};
|
|
224
|
+
}
|
|
225
|
+
});
|
|
226
|
+
|
|
227
|
+
server.setRequestHandler(SubscribeRequestSchema, async (request) => {
|
|
228
|
+
const { uri } = request.params;
|
|
229
|
+
subMgr.subscribe(uri);
|
|
230
|
+
return { success: true };
|
|
231
|
+
});
|
|
232
|
+
|
|
233
|
+
server.setRequestHandler(UnsubscribeRequestSchema, async (request) => {
|
|
234
|
+
const { uri } = request.params;
|
|
235
|
+
subMgr.unsubscribe(uri);
|
|
236
|
+
return { success: true };
|
|
237
|
+
});
|
|
238
|
+
|
|
197
239
|
return server;
|
|
198
240
|
}
|
|
199
241
|
|
|
@@ -263,7 +305,7 @@ export async function startServer() {
|
|
|
263
305
|
if (method === 'initialize') {
|
|
264
306
|
send({ jsonrpc: '2.0', id, result: {
|
|
265
307
|
protocolVersion: PROTOCOL_VERSION,
|
|
266
|
-
capabilities: { tools: {} },
|
|
308
|
+
capabilities: { tools: {}, resources: { subscribe: true, listChanged: true } },
|
|
267
309
|
serverInfo: { name: SERVER_NAME, version: SERVER_VERSION }
|
|
268
310
|
} }, true);
|
|
269
311
|
return;
|
|
@@ -274,6 +316,49 @@ export async function startServer() {
|
|
|
274
316
|
return;
|
|
275
317
|
}
|
|
276
318
|
|
|
319
|
+
if (method === 'resources/list') {
|
|
320
|
+
const resources = await listResources(subMgr.list());
|
|
321
|
+
send({ jsonrpc: '2.0', id, result: { resources } }, true);
|
|
322
|
+
return;
|
|
323
|
+
}
|
|
324
|
+
|
|
325
|
+
if (method === 'resources/read') {
|
|
326
|
+
const uri = params?.uri;
|
|
327
|
+
if (!uri) {
|
|
328
|
+
send({ jsonrpc: '2.0', id, error: { code: -32600, message: '缺少 uri 参数' } }, true);
|
|
329
|
+
return;
|
|
330
|
+
}
|
|
331
|
+
try {
|
|
332
|
+
const data = await readResource(uri);
|
|
333
|
+
send({ jsonrpc: '2.0', id, result: { contents: [{ uri, mimeType: 'application/json', text: JSON.stringify(data) }] } }, true);
|
|
334
|
+
} catch (e) {
|
|
335
|
+
send({ jsonrpc: '2.0', id, error: { code: -32603, message: e.message } }, true);
|
|
336
|
+
}
|
|
337
|
+
return;
|
|
338
|
+
}
|
|
339
|
+
|
|
340
|
+
if (method === 'resources/subscribe') {
|
|
341
|
+
const uri = params?.uri;
|
|
342
|
+
if (!uri) {
|
|
343
|
+
send({ jsonrpc: '2.0', id, error: { code: -32600, message: '缺少 uri 参数' } }, true);
|
|
344
|
+
return;
|
|
345
|
+
}
|
|
346
|
+
subMgr.subscribe(uri);
|
|
347
|
+
send({ jsonrpc: '2.0', id, result: { success: true } }, true);
|
|
348
|
+
return;
|
|
349
|
+
}
|
|
350
|
+
|
|
351
|
+
if (method === 'resources/unsubscribe') {
|
|
352
|
+
const uri = params?.uri;
|
|
353
|
+
if (!uri) {
|
|
354
|
+
send({ jsonrpc: '2.0', id, error: { code: -32600, message: '缺少 uri 参数' } }, true);
|
|
355
|
+
return;
|
|
356
|
+
}
|
|
357
|
+
subMgr.unsubscribe(uri);
|
|
358
|
+
send({ jsonrpc: '2.0', id, result: { success: true } }, true);
|
|
359
|
+
return;
|
|
360
|
+
}
|
|
361
|
+
|
|
277
362
|
if (method === 'tools/call') {
|
|
278
363
|
const toolName = params?.name;
|
|
279
364
|
if (!toolName) {
|
package/src/cad-worker.js
CHANGED
|
@@ -47,6 +47,45 @@ const cadConnect = edge.func(function() {/*
|
|
|
47
47
|
}
|
|
48
48
|
*/});
|
|
49
49
|
|
|
50
|
+
const cadLaunch = edge.func(function() {/*
|
|
51
|
+
async (input) => {
|
|
52
|
+
string[] platforms = { "AutoCAD", "ZWCAD", "GStarCAD", "BricsCAD" };
|
|
53
|
+
string[] progIds = { "AutoCAD.Application", "ZWCAD.Application", "GStarCAD.Application", "BricsCAD.Application" };
|
|
54
|
+
|
|
55
|
+
for (int i = 0; i < platforms.Length; i++) {
|
|
56
|
+
try {
|
|
57
|
+
dynamic cad = System.Runtime.InteropServices.Marshal.GetActiveObject(progIds[i]);
|
|
58
|
+
if (cad != null) {
|
|
59
|
+
string ver = cad.Version.ToString();
|
|
60
|
+
return new { success = true, platform = platforms[i], version = ver, launched = false };
|
|
61
|
+
}
|
|
62
|
+
} catch {}
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
for (int i = 0; i < platforms.Length; i++) {
|
|
66
|
+
try {
|
|
67
|
+
var type = System.Type.GetTypeFromProgID(progIds[i]);
|
|
68
|
+
if (type != null) {
|
|
69
|
+
dynamic cad = System.Activator.CreateInstance(type);
|
|
70
|
+
if (cad != null) {
|
|
71
|
+
for (int retry = 0; retry < 60; retry++) {
|
|
72
|
+
await System.Threading.Tasks.Task.Delay(500);
|
|
73
|
+
try {
|
|
74
|
+
string ver = cad.Version.ToString();
|
|
75
|
+
return new { success = true, platform = platforms[i], version = ver, launched = true };
|
|
76
|
+
} catch {}
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
} catch (Exception ex) {
|
|
81
|
+
System.Diagnostics.Debug.WriteLine("Create COM " + platforms[i] + " error: " + ex.Message);
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
return new { success = false, error = "No CAD found" };
|
|
86
|
+
}
|
|
87
|
+
*/});
|
|
88
|
+
|
|
50
89
|
const cadSend = edge.func(function() {/*
|
|
51
90
|
async (input) => {
|
|
52
91
|
try {
|
|
@@ -255,8 +294,17 @@ async function handleMessage(msg) {
|
|
|
255
294
|
return { pong: true };
|
|
256
295
|
}
|
|
257
296
|
if (msg.type === 'connect') {
|
|
297
|
+
try {
|
|
298
|
+
const result = await new Promise((resolve, reject) => {
|
|
299
|
+
cadConnect({}, (e, r) => {
|
|
300
|
+
if (e) reject(e);
|
|
301
|
+
else resolve(r);
|
|
302
|
+
});
|
|
303
|
+
});
|
|
304
|
+
if (result && result.success) return result;
|
|
305
|
+
} catch (e) {}
|
|
258
306
|
return new Promise((resolve, reject) => {
|
|
259
|
-
|
|
307
|
+
cadLaunch({}, (e, r) => {
|
|
260
308
|
if (e) reject(e);
|
|
261
309
|
else resolve(r);
|
|
262
310
|
});
|
|
@@ -13,7 +13,7 @@ export async function connectCad() {
|
|
|
13
13
|
} catch (e) {
|
|
14
14
|
log('connect_cad error: ' + e.message);
|
|
15
15
|
}
|
|
16
|
-
return { content: [{ type: 'text', text: '
|
|
16
|
+
return { content: [{ type: 'text', text: '未能连接或启动 CAD,请确保 CAD 已安装' }], isError: true };
|
|
17
17
|
}
|
|
18
18
|
|
|
19
19
|
export async function evalLisp(code, withResult = false) {
|
|
@@ -0,0 +1,304 @@
|
|
|
1
|
+
import { cad } from '../cad.js';
|
|
2
|
+
import { CAD_PLATFORMS, FILE_EXTENSIONS, MOCK_PACKAGES } from '../constants.js';
|
|
3
|
+
|
|
4
|
+
function parseLispList(str) {
|
|
5
|
+
if (!str || typeof str !== 'string') return null;
|
|
6
|
+
const trimmed = str.trim();
|
|
7
|
+
if (!trimmed.startsWith('(') || !trimmed.endsWith(')')) return null;
|
|
8
|
+
const content = trimmed.slice(1, -1).trim();
|
|
9
|
+
if (!content) return [];
|
|
10
|
+
|
|
11
|
+
const result = [];
|
|
12
|
+
let depth = 0;
|
|
13
|
+
let current = '';
|
|
14
|
+
let inString = false;
|
|
15
|
+
let escaped = false;
|
|
16
|
+
|
|
17
|
+
for (let i = 0; i < content.length; i++) {
|
|
18
|
+
const ch = content[i];
|
|
19
|
+
if (escaped) {
|
|
20
|
+
current += ch;
|
|
21
|
+
escaped = false;
|
|
22
|
+
continue;
|
|
23
|
+
}
|
|
24
|
+
if (ch === '\\') {
|
|
25
|
+
current += ch;
|
|
26
|
+
escaped = true;
|
|
27
|
+
continue;
|
|
28
|
+
}
|
|
29
|
+
if (ch === '"') {
|
|
30
|
+
current += ch;
|
|
31
|
+
inString = !inString;
|
|
32
|
+
continue;
|
|
33
|
+
}
|
|
34
|
+
if (inString) {
|
|
35
|
+
current += ch;
|
|
36
|
+
continue;
|
|
37
|
+
}
|
|
38
|
+
if (ch === '(' || ch === '[') {
|
|
39
|
+
current += ch;
|
|
40
|
+
depth++;
|
|
41
|
+
} else if (ch === ')' || ch === ']') {
|
|
42
|
+
current += ch;
|
|
43
|
+
depth--;
|
|
44
|
+
} else if (ch === ' ' && depth === 0) {
|
|
45
|
+
if (current.trim()) {
|
|
46
|
+
result.push(current.trim());
|
|
47
|
+
current = '';
|
|
48
|
+
}
|
|
49
|
+
continue;
|
|
50
|
+
}
|
|
51
|
+
current += ch;
|
|
52
|
+
}
|
|
53
|
+
if (current.trim()) result.push(current.trim());
|
|
54
|
+
|
|
55
|
+
return result.map(item => {
|
|
56
|
+
const t = item.trim();
|
|
57
|
+
if (t === 'nil') return null;
|
|
58
|
+
if (t === 't') return true;
|
|
59
|
+
if (t === 'T') return true;
|
|
60
|
+
const num = Number(t);
|
|
61
|
+
if (!isNaN(num) && t !== '') return num;
|
|
62
|
+
if (t.startsWith('"') && t.endsWith('"')) return t.slice(1, -1);
|
|
63
|
+
return t;
|
|
64
|
+
});
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
export const RESOURCES = [
|
|
68
|
+
{ uri: 'atlisp://cad/info', name: 'CAD Info', description: 'CAD 连接信息', mimeType: 'application/json', subscribable: true },
|
|
69
|
+
{ uri: 'atlisp://cad/layers', name: 'Layers', description: '图层列表', mimeType: 'application/json', subscribable: true },
|
|
70
|
+
{ uri: 'atlisp://cad/entities', name: 'Entities', description: '实体统计', mimeType: 'application/json', subscribable: true },
|
|
71
|
+
{ uri: 'atlisp://dwg/name', name: 'DWG Name', description: '当前 DWG 文件名', mimeType: 'application/json', subscribable: true },
|
|
72
|
+
{ uri: 'atlisp://dwg/path', name: 'DWG Path', description: '文件完整路径', mimeType: 'application/json', subscribable: true },
|
|
73
|
+
{ uri: 'atlisp://packages', name: 'Packages', description: '已安装包列表', mimeType: 'application/json', subscribable: true },
|
|
74
|
+
{ uri: 'atlisp://platforms', name: 'Platforms', description: '支持的平台信息', mimeType: 'application/json', subscribable: false },
|
|
75
|
+
];
|
|
76
|
+
|
|
77
|
+
function parseQuery(uri) {
|
|
78
|
+
const qIdx = uri.indexOf('?');
|
|
79
|
+
if (qIdx === -1) return { base: uri, params: {} };
|
|
80
|
+
const base = uri.substring(0, qIdx);
|
|
81
|
+
const params = {};
|
|
82
|
+
uri.substring(qIdx + 1).split('&').forEach(p => {
|
|
83
|
+
const eqIdx = p.indexOf('=');
|
|
84
|
+
const k = eqIdx === -1 ? p : p.substring(0, eqIdx);
|
|
85
|
+
const v = eqIdx === -1 ? '' : p.substring(eqIdx + 1);
|
|
86
|
+
if (k) params[k] = decodeURIComponent(v);
|
|
87
|
+
});
|
|
88
|
+
return { base, params };
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
export async function listResources(subscribedUris = []) {
|
|
92
|
+
return RESOURCES.map(r => ({
|
|
93
|
+
uri: r.uri,
|
|
94
|
+
name: r.name,
|
|
95
|
+
description: r.description,
|
|
96
|
+
mimeType: r.mimeType,
|
|
97
|
+
subscribed: subscribedUris.includes(r.uri)
|
|
98
|
+
}));
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
export async function readResource(uri) {
|
|
102
|
+
const { base, params } = parseQuery(uri);
|
|
103
|
+
|
|
104
|
+
switch (base) {
|
|
105
|
+
case 'atlisp://cad/info':
|
|
106
|
+
return await getCadInfo();
|
|
107
|
+
case 'atlisp://cad/layers':
|
|
108
|
+
return await getLayers(params.name);
|
|
109
|
+
case 'atlisp://cad/entities':
|
|
110
|
+
return await getEntities(params.type);
|
|
111
|
+
case 'atlisp://dwg/name':
|
|
112
|
+
return await getDwgName();
|
|
113
|
+
case 'atlisp://dwg/path':
|
|
114
|
+
return await getDwgPath();
|
|
115
|
+
case 'atlisp://packages':
|
|
116
|
+
return await getPackages(params.name);
|
|
117
|
+
case 'atlisp://platforms':
|
|
118
|
+
return getPlatforms();
|
|
119
|
+
default:
|
|
120
|
+
throw new Error(`资源不存在: ${uri}`);
|
|
121
|
+
}
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
async function getCadInfo() {
|
|
125
|
+
if (!cad.connected) {
|
|
126
|
+
await cad.connect();
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
if (!cad.connected) {
|
|
130
|
+
return {
|
|
131
|
+
connected: false,
|
|
132
|
+
platform: null,
|
|
133
|
+
version: null,
|
|
134
|
+
busy: false
|
|
135
|
+
};
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
let busy = false;
|
|
139
|
+
try {
|
|
140
|
+
busy = await cad.isBusy();
|
|
141
|
+
} catch (e) {}
|
|
142
|
+
|
|
143
|
+
return {
|
|
144
|
+
connected: true,
|
|
145
|
+
platform: cad.getPlatform(),
|
|
146
|
+
version: cad.getVersion(),
|
|
147
|
+
busy
|
|
148
|
+
};
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
async function getLayers(filterName = null) {
|
|
152
|
+
if (!cad.connected) await cad.connect();
|
|
153
|
+
if (!cad.connected) return [];
|
|
154
|
+
|
|
155
|
+
try {
|
|
156
|
+
const code = filterName
|
|
157
|
+
? `(tblnext "LAYER" T)`
|
|
158
|
+
: `(progn (setq res nil)(while (setq e (tblnext "LAYER" (null res)))(setq res (cons (list (cdr (assoc 2 e)) (cdr (assoc 62 e)) (cdr (assoc 70 e))) res))) (reverse res))`;
|
|
159
|
+
|
|
160
|
+
const result = await cad.sendCommandWithResult(code);
|
|
161
|
+
|
|
162
|
+
if (!result || result === "" || result === "nil") return [];
|
|
163
|
+
|
|
164
|
+
let layers = [];
|
|
165
|
+
try {
|
|
166
|
+
layers = JSON.parse(result);
|
|
167
|
+
} catch (e) {
|
|
168
|
+
const parsed = parseLispList(result);
|
|
169
|
+
if (parsed) {
|
|
170
|
+
layers = parsed;
|
|
171
|
+
} else {
|
|
172
|
+
layers = [];
|
|
173
|
+
}
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
if (!Array.isArray(layers)) {
|
|
177
|
+
if (typeof layers === 'number') {
|
|
178
|
+
layers = [[result, layers, 0]];
|
|
179
|
+
} else if (typeof layers === 'string') {
|
|
180
|
+
layers = [[layers, 7, 0]];
|
|
181
|
+
}
|
|
182
|
+
}
|
|
183
|
+
|
|
184
|
+
return layers.map(l => {
|
|
185
|
+
const name = Array.isArray(l) ? l[0] : l;
|
|
186
|
+
const color = Array.isArray(l) && l[1] !== undefined ? l[1] : 7;
|
|
187
|
+
const flags = Array.isArray(l) && l[2] !== undefined ? l[2] : 0;
|
|
188
|
+
return {
|
|
189
|
+
name: String(name),
|
|
190
|
+
color: color,
|
|
191
|
+
locked: (flags & 4) !== 0,
|
|
192
|
+
frozen: (flags & 1) !== 0
|
|
193
|
+
};
|
|
194
|
+
});
|
|
195
|
+
} catch (e) {
|
|
196
|
+
return [];
|
|
197
|
+
}
|
|
198
|
+
}
|
|
199
|
+
|
|
200
|
+
async function getEntities(filterType = null) {
|
|
201
|
+
if (!cad.connected) await cad.connect();
|
|
202
|
+
if (!cad.connected) return { total: 0, byType: {} };
|
|
203
|
+
|
|
204
|
+
try {
|
|
205
|
+
let code;
|
|
206
|
+
if (filterType) {
|
|
207
|
+
code = `(sslength (ssget "_X" (list (cons 0 "${filterType}"))))`;
|
|
208
|
+
const count = await cad.sendCommandWithResult(code);
|
|
209
|
+
return {
|
|
210
|
+
type: filterType,
|
|
211
|
+
count: parseInt(count) || 0
|
|
212
|
+
};
|
|
213
|
+
} else {
|
|
214
|
+
code = `(progn(setq ss(ssget "_X"))(if ss(progn(setq elst(mapcar (quote(lambda(x)(cdr(assoc 0 (entget x))))) (pickset:to-list ss)))(stat:stat elst))))`;
|
|
215
|
+
const result = await cad.sendCommandWithResult(code);
|
|
216
|
+
|
|
217
|
+
if (!result || result === "" || result === "nil") {
|
|
218
|
+
return { total: 0, byType: {} };
|
|
219
|
+
}
|
|
220
|
+
|
|
221
|
+
let statResult = [];
|
|
222
|
+
try {
|
|
223
|
+
statResult = JSON.parse(result);
|
|
224
|
+
} catch (e) {
|
|
225
|
+
const parsed = parseLispList(result);
|
|
226
|
+
if (parsed) {
|
|
227
|
+
statResult = parsed;
|
|
228
|
+
}
|
|
229
|
+
}
|
|
230
|
+
|
|
231
|
+
if (!Array.isArray(statResult)) {
|
|
232
|
+
return { total: 0, byType: {} };
|
|
233
|
+
}
|
|
234
|
+
|
|
235
|
+
const byType = {};
|
|
236
|
+
statResult.forEach(item => {
|
|
237
|
+
if (Array.isArray(item) && item.length >= 2) {
|
|
238
|
+
byType[item[0]] = item[1];
|
|
239
|
+
}
|
|
240
|
+
});
|
|
241
|
+
|
|
242
|
+
const total = Object.values(byType).reduce((sum, n) => sum + n, 0);
|
|
243
|
+
return { total, byType };
|
|
244
|
+
}
|
|
245
|
+
} catch (e) {
|
|
246
|
+
return { total: 0, byType: {} };
|
|
247
|
+
}
|
|
248
|
+
}
|
|
249
|
+
|
|
250
|
+
async function getDwgName() {
|
|
251
|
+
if (!cad.connected) await cad.connect();
|
|
252
|
+
if (!cad.connected) return { name: null };
|
|
253
|
+
|
|
254
|
+
try {
|
|
255
|
+
const code = `(vl-princ-to-string (getvar "dwgname"))`;
|
|
256
|
+
const name = await cad.sendCommandWithResult(code);
|
|
257
|
+
return { name: name || null };
|
|
258
|
+
} catch (e) {
|
|
259
|
+
return { name: null };
|
|
260
|
+
}
|
|
261
|
+
}
|
|
262
|
+
|
|
263
|
+
async function getDwgPath() {
|
|
264
|
+
if (!cad.connected) await cad.connect();
|
|
265
|
+
if (!cad.connected) return { path: null, name: null };
|
|
266
|
+
|
|
267
|
+
try {
|
|
268
|
+
const code = `(strcat (vl-princ-to-string (getvar "dwgprefix")) (vl-princ-to-string (getvar "dwgname")))`;
|
|
269
|
+
const fullPath = await cad.sendCommandWithResult(code);
|
|
270
|
+
|
|
271
|
+
const nameCode = `(vl-princ-to-string (getvar "dwgname"))`;
|
|
272
|
+
const name = await cad.sendCommandWithResult(nameCode);
|
|
273
|
+
|
|
274
|
+
return {
|
|
275
|
+
path: fullPath || null,
|
|
276
|
+
name: name || null
|
|
277
|
+
};
|
|
278
|
+
} catch (e) {
|
|
279
|
+
return { path: null, name: null };
|
|
280
|
+
}
|
|
281
|
+
}
|
|
282
|
+
|
|
283
|
+
async function getPackages(filterName = null) {
|
|
284
|
+
const packages = MOCK_PACKAGES.map(p => ({
|
|
285
|
+
name: p.name,
|
|
286
|
+
version: p.version,
|
|
287
|
+
description: p.description,
|
|
288
|
+
loaded: true
|
|
289
|
+
}));
|
|
290
|
+
|
|
291
|
+
if (filterName) {
|
|
292
|
+
const pkg = packages.find(p => p.name === filterName);
|
|
293
|
+
return pkg ? [pkg] : [];
|
|
294
|
+
}
|
|
295
|
+
|
|
296
|
+
return packages;
|
|
297
|
+
}
|
|
298
|
+
|
|
299
|
+
function getPlatforms() {
|
|
300
|
+
return CAD_PLATFORMS.map(name => ({
|
|
301
|
+
name,
|
|
302
|
+
extensions: FILE_EXTENSIONS[name] || []
|
|
303
|
+
}));
|
|
304
|
+
}
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
const subscriptions = new Map();
|
|
2
|
+
|
|
3
|
+
export function subscribe(uri) {
|
|
4
|
+
subscriptions.set(uri, Date.now());
|
|
5
|
+
return true;
|
|
6
|
+
}
|
|
7
|
+
|
|
8
|
+
export function unsubscribe(uri) {
|
|
9
|
+
return subscriptions.delete(uri);
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
export function list() {
|
|
13
|
+
return Array.from(subscriptions.keys());
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
export function isSubscribed(uri) {
|
|
17
|
+
return subscriptions.has(uri);
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
export function clear() {
|
|
21
|
+
subscriptions.clear();
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
export function size() {
|
|
25
|
+
return subscriptions.size;
|
|
26
|
+
}
|