@atlisp/mcp 1.0.12 → 1.0.14
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 +24 -9
- package/src/constants.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
|
@@ -79,16 +79,31 @@ const cadSendWithResult = edge.func(function() {/*
|
|
|
79
79
|
string progId = platform + ".Application";
|
|
80
80
|
string tempDir = System.IO.Path.GetTempPath();
|
|
81
81
|
tempFile = System.IO.Path.Combine(tempDir, "atlisp_result_" + System.Guid.NewGuid().ToString("N") + ".txt");
|
|
82
|
-
string lispCode = "(progn(setq f(open \"" + tempFile.Replace("\\", "\\\\") + "\" \"w\"))(print " + code + " f)(close f))";
|
|
82
|
+
string lispCode = "(progn(setq f(open \"" + tempFile.Replace("\\", "\\\\") + "\" \"w\"))(print " + code + " f)(close f)(princ))";
|
|
83
83
|
dynamic cad = System.Runtime.InteropServices.Marshal.GetActiveObject(progId);
|
|
84
84
|
if (cad != null) {
|
|
85
85
|
dynamic doc = cad.ActiveDocument;
|
|
86
86
|
if (doc != null) {
|
|
87
87
|
doc.SendCommand(lispCode + "\n");
|
|
88
|
-
|
|
88
|
+
int retries = 10;
|
|
89
|
+
string result = "";
|
|
90
|
+
while (retries > 0 && !System.IO.File.Exists(tempFile)) {
|
|
91
|
+
System.Threading.Thread.Sleep(200);
|
|
92
|
+
retries--;
|
|
93
|
+
}
|
|
89
94
|
if (System.IO.File.Exists(tempFile)) {
|
|
90
|
-
|
|
91
|
-
|
|
95
|
+
retries = 5;
|
|
96
|
+
while (retries > 0) {
|
|
97
|
+
try {
|
|
98
|
+
byte[] bytes = System.IO.File.ReadAllBytes(tempFile);
|
|
99
|
+
result = System.Text.Encoding.GetEncoding("GBK").GetString(bytes).Trim();
|
|
100
|
+
try { System.IO.File.Delete(tempFile); } catch {}
|
|
101
|
+
break;
|
|
102
|
+
} catch (System.IO.IOException) {
|
|
103
|
+
System.Threading.Thread.Sleep(200);
|
|
104
|
+
retries--;
|
|
105
|
+
}
|
|
106
|
+
}
|
|
92
107
|
if (!string.IsNullOrEmpty(result)) {
|
|
93
108
|
return new { success = true, result = result };
|
|
94
109
|
}
|
|
@@ -99,17 +114,17 @@ const cadSendWithResult = edge.func(function() {/*
|
|
|
99
114
|
}
|
|
100
115
|
} catch (Exception ex) {
|
|
101
116
|
System.Diagnostics.Debug.WriteLine("cadSendWithResult error: " + ex.Message);
|
|
102
|
-
if (tempFile != null
|
|
103
|
-
try { System.IO.File.Delete(tempFile); } catch {}
|
|
117
|
+
if (tempFile != null) {
|
|
118
|
+
try { if (System.IO.File.Exists(tempFile)) System.IO.File.Delete(tempFile); } catch {}
|
|
104
119
|
}
|
|
105
120
|
return new { success = false, error = ex.Message };
|
|
106
121
|
}
|
|
107
|
-
if (tempFile != null
|
|
108
|
-
try { System.IO.File.Delete(tempFile); } catch {}
|
|
122
|
+
if (tempFile != null) {
|
|
123
|
+
try { if (System.IO.File.Exists(tempFile)) System.IO.File.Delete(tempFile); } catch {}
|
|
109
124
|
}
|
|
110
125
|
return new { success = false };
|
|
111
126
|
}
|
|
112
|
-
|
|
127
|
+
*/});
|
|
113
128
|
|
|
114
129
|
process.stdin.setEncoding('utf8');
|
|
115
130
|
|
package/src/constants.js
CHANGED
|
@@ -7,7 +7,7 @@ export const FILE_EXTENSIONS = {
|
|
|
7
7
|
|
|
8
8
|
export const PROTOCOL_VERSION = '2024-11-05';
|
|
9
9
|
export const SERVER_NAME = 'atlisp-mcp-server';
|
|
10
|
-
export const SERVER_VERSION = '1.0.
|
|
10
|
+
export const SERVER_VERSION = '1.0.13';
|
|
11
11
|
|
|
12
12
|
export const MOCK_PACKAGES = [
|
|
13
13
|
{ name: 'base', description: '基础函数库', version: '1.0.0' },
|
|
@@ -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
|
+
}
|