@atlisp/mcp 1.3.0 → 1.3.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/src/cad-worker.js DELETED
@@ -1,498 +0,0 @@
1
- #!/usr/bin/env node
2
- import edge from 'edge-js';
3
- import process from 'process';
4
- import fs from 'fs';
5
- import path from 'path';
6
-
7
- const BUSY_RETRIES = parseInt(process.env.BUSY_RETRIES || '10', 10);
8
- const BUSY_DELAY = parseInt(process.env.BUSY_DELAY || '500', 10);
9
-
10
- const DEBUG_FILE = process.env.DEBUG_FILE || path.join(process.env.TEMP || '/tmp', 'cad-worker-debug.log');
11
-
12
- function log(msg) {
13
- const entry = `${new Date().toISOString()} ${msg}\n`;
14
- if (process.env.DEBUG) {
15
- fs.appendFile(DEBUG_FILE, entry, () => {});
16
- }
17
- }
18
-
19
- const cadConnect = edge.func(function() {/*
20
- async (input) => {
21
- try {
22
- dynamic cad = System.Runtime.InteropServices.Marshal.GetActiveObject("AutoCAD.Application");
23
- if (cad != null) {
24
- string ver = cad.Version.ToString();
25
- return new { success = true, platform = "AutoCAD", version = ver };
26
- }
27
- } catch (Exception ex) {
28
- System.Diagnostics.Debug.WriteLine("AutoCAD connect error: " + ex.Message);
29
- }
30
- try {
31
- dynamic cad = System.Runtime.InteropServices.Marshal.GetActiveObject("ZWCAD.Application");
32
- if (cad != null) {
33
- string ver = cad.Version.ToString();
34
- return new { success = true, platform = "ZWCAD", version = ver };
35
- }
36
- } catch (Exception ex) {
37
- System.Diagnostics.Debug.WriteLine("ZWCAD connect error: " + ex.Message);
38
- }
39
- try {
40
- dynamic cad = System.Runtime.InteropServices.Marshal.GetActiveObject("GStarCAD.Application");
41
- if (cad != null) {
42
- string ver = cad.Version.ToString();
43
- return new { success = true, platform = "GStarCAD", version = ver };
44
- }
45
- } catch (Exception ex) {
46
- System.Diagnostics.Debug.WriteLine("GStarCAD connect error: " + ex.Message);
47
- }
48
- try {
49
- dynamic cad = System.Runtime.InteropServices.Marshal.GetActiveObject("BricsCAD.Application");
50
- if (cad != null) {
51
- string ver = cad.Version.ToString();
52
- return new { success = true, platform = "BricsCAD", version = ver };
53
- }
54
- } catch (Exception ex) {
55
- System.Diagnostics.Debug.WriteLine("BricsCAD connect error: " + ex.Message);
56
- }
57
- return new { success = false, error = "No CAD found" };
58
- }
59
- */});
60
-
61
- const cadLaunch = edge.func(function() {/*
62
- async (input) => {
63
- string[] platforms = { "AutoCAD", "ZWCAD", "GStarCAD", "BricsCAD" };
64
- string[] progIds = { "AutoCAD.Application", "ZWCAD.Application", "GStarCAD.Application", "BricsCAD.Application" };
65
-
66
- for (int i = 0; i < platforms.Length; i++) {
67
- try {
68
- dynamic cad = System.Runtime.InteropServices.Marshal.GetActiveObject(progIds[i]);
69
- if (cad != null) {
70
- string ver = cad.Version.ToString();
71
- return new { success = true, platform = platforms[i], version = ver, launched = false };
72
- }
73
- } catch {}
74
- }
75
-
76
- for (int i = 0; i < platforms.Length; i++) {
77
- try {
78
- var type = System.Type.GetTypeFromProgID(progIds[i]);
79
- if (type != null) {
80
- dynamic cad = System.Activator.CreateInstance(type);
81
- if (cad != null) {
82
- for (int retry = 0; retry < 60; retry++) {
83
- await System.Threading.Tasks.Task.Delay(500);
84
- try {
85
- string ver = cad.Version.ToString();
86
- return new { success = true, platform = platforms[i], version = ver, launched = true };
87
- } catch {}
88
- }
89
- }
90
- }
91
- } catch (Exception ex) {
92
- System.Diagnostics.Debug.WriteLine("Create COM " + platforms[i] + " error: " + ex.Message);
93
- }
94
- }
95
-
96
- return new { success = false, error = "No CAD found" };
97
- }
98
- */});
99
-
100
- const cadSend = edge.func(function() {/*
101
- async (input) => {
102
- try {
103
- dynamic d = input;
104
- string code = d.code.ToString();
105
- string platform = d.platform.ToString();
106
- string progId = platform + ".Application";
107
- dynamic cad = System.Runtime.InteropServices.Marshal.GetActiveObject(progId);
108
- if (cad != null) {
109
- dynamic doc = cad.ActiveDocument;
110
- if (doc != null) {
111
- doc.SendCommand(code);
112
- return new { success = true };
113
- }
114
- }
115
- } catch (Exception ex) {
116
- System.Diagnostics.Debug.WriteLine("cadSend error: " + ex.Message);
117
- }
118
- return new { success = false };
119
- }
120
- */});
121
-
122
- const cadSendWithResult = edge.func(function() {/*
123
- async (input) => {
124
- string tempFile = null;
125
- string lispFile = null;
126
- try {
127
- dynamic d = input;
128
- string code = d.code.ToString();
129
- string platform = d.platform.ToString();
130
- string encoding = d.encoding != null ? d.encoding.ToString() : "";
131
- string progId = platform + ".Application";
132
- string tempDir = System.IO.Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.UserProfile), "@lisp");
133
- System.IO.Directory.CreateDirectory(tempDir);
134
-
135
- tempFile = System.IO.Path.Combine(tempDir, "atlisp_result_" + System.Guid.NewGuid().ToString("N") + ".txt");
136
- lispFile = System.IO.Path.Combine(tempDir, "atlisp_code_" + System.Guid.NewGuid().ToString("N") + ".lsp");
137
-
138
- // 生成 LISP 代码:使用 vl-catch-all-apply 捕获结果和错误
139
- // 返回 (success . result) 或 (nil . error-msg)
140
- string lispCode = "(progn"
141
- + "(setq f(open \"" + tempFile.Replace("\\", "\\\\") + "\" \"w\"))"
142
- + "(setq r(vl-catch-all-apply '(lambda ()(progn " + code + "))))"
143
- + "(if (vl-catch-all-error-p r)"
144
- + "(princ(strcat \"ERROR:\"(vl-catch-all-error-message r)) f)"
145
- + "(princ r f))"
146
- + "(close f)"
147
- + "(princ))";
148
-
149
- // 使用系统 ANSI 编码以兼容 GstarCAD / ZWCAD
150
- System.IO.File.WriteAllText(lispFile, lispCode, System.Text.Encoding.GetEncoding(System.Globalization.CultureInfo.CurrentCulture.TextInfo.ANSICodePage));
151
-
152
- dynamic cad = System.Runtime.InteropServices.Marshal.GetActiveObject(progId);
153
- if (cad != null) {
154
- dynamic doc = cad.ActiveDocument;
155
- if (doc != null) {
156
- // 加载 .lsp 文件执行
157
- doc.SendCommand("(load \"" + lispFile.Replace("\\", "\\\\") + "\")\n");
158
-
159
- int retries = 10;
160
- string result = "";
161
- while (retries > 0 && !System.IO.File.Exists(tempFile)) {
162
- System.Threading.Thread.Sleep(200);
163
- retries--;
164
- }
165
- if (System.IO.File.Exists(tempFile)) {
166
- retries = 5;
167
- while (retries > 0) {
168
- try {
169
- byte[] bytes = System.IO.File.ReadAllBytes(tempFile);
170
- System.Text.Encoding enc;
171
-
172
- // 优先使用指定的编码
173
- if (!string.IsNullOrEmpty(encoding)) {
174
- enc = System.Text.Encoding.GetEncoding(encoding);
175
- } else {
176
- // 自动检测编码:先尝试 UTF-8,如果失败则使用 GBK
177
- try {
178
- string utf8Result = System.Text.Encoding.UTF8.GetString(bytes);
179
- if (!utf8Result.Contains("\ufffd")) {
180
- enc = System.Text.Encoding.UTF8;
181
- } else {
182
- enc = System.Text.Encoding.GetEncoding("gbk");
183
- }
184
- } catch {
185
- try {
186
- enc = System.Text.Encoding.GetEncoding("gbk");
187
- } catch {
188
- enc = System.Text.Encoding.Default;
189
- }
190
- }
191
- }
192
-
193
- result = enc.GetString(bytes).Trim();
194
-
195
- // 检查是否有错误前缀
196
- if (result.StartsWith("ERROR:")) {
197
- return new { success = false, error = result.Substring(6).Trim() };
198
- }
199
-
200
- try { System.IO.File.Delete(tempFile); } catch {}
201
- try { System.IO.File.Delete(lispFile); } catch {}
202
- break;
203
- } catch (System.IO.IOException) {
204
- System.Threading.Thread.Sleep(200);
205
- retries--;
206
- }
207
- }
208
- if (!string.IsNullOrEmpty(result)) {
209
- return new { success = true, result = result };
210
- }
211
- return new { success = true, result = "" };
212
- }
213
- return new { success = true, result = "" };
214
- }
215
- }
216
- } catch (Exception ex) {
217
- System.Diagnostics.Debug.WriteLine("cadSendWithResult error: " + ex.Message);
218
- if (tempFile != null) {
219
- try { if (System.IO.File.Exists(tempFile)) System.IO.File.Delete(tempFile); } catch {}
220
- }
221
- if (lispFile != null) {
222
- try { if (System.IO.File.Exists(lispFile)) System.IO.File.Delete(lispFile); } catch {}
223
- }
224
- return new { success = false, error = ex.Message };
225
- }
226
- if (tempFile != null) {
227
- try { if (System.IO.File.Exists(tempFile)) System.IO.File.Delete(tempFile); } catch {}
228
- }
229
- if (lispFile != null) {
230
- try { if (System.IO.File.Exists(lispFile)) System.IO.File.Delete(lispFile); } catch {}
231
- }
232
- return new { success = false };
233
- }
234
- */});
235
-
236
- process.stdin.setEncoding('utf8');
237
-
238
- let stdinBuffer = '';
239
- process.stdin.on('data', (data) => {
240
- stdinBuffer += data;
241
- const lines = stdinBuffer.split('\n');
242
- stdinBuffer = lines.pop() || '';
243
- for (const line of lines) {
244
- if (!line.trim()) continue;
245
- try {
246
- const msg = JSON.parse(line);
247
- const requestId = msg.requestId;
248
- handleMessage(msg).then(result => {
249
- process.stdout.write(JSON.stringify({ ...result, requestId }) + '\n');
250
- }).catch(err => {
251
- process.stdout.write(JSON.stringify({ error: err.message, requestId }) + '\n');
252
- });
253
- } catch (e) {
254
- process.stdout.write(JSON.stringify({ error: 'invalid message' }) + '\n');
255
- }
256
- }
257
- });
258
-
259
- const cadIsBusy = edge.func(function() {/*
260
- async (input) => {
261
- try {
262
- string platform = input.ToString();
263
- string progId = platform + ".Application";
264
- dynamic cad = System.Runtime.InteropServices.Marshal.GetActiveObject(progId);
265
- if (cad != null) {
266
- bool isBusy = false;
267
- if (platform == "ZWCAD") {
268
- isBusy = !(cad.GetZcadState().IsQuiescent);
269
- } else {
270
- isBusy = !(cad.GetAcadState().IsQuiescent);
271
- }
272
- return new { isBusy = isBusy };
273
- }
274
- } catch (Exception ex) {
275
- System.Diagnostics.Debug.WriteLine("cadIsBusy error: " + ex.Message);
276
- }
277
- return new { isBusy = false };
278
- }
279
- */});
280
-
281
- const cadHasDoc = edge.func(function() {/*
282
- async (input) => {
283
- try {
284
- string platform = input.ToString();
285
- string progId = platform + ".Application";
286
- dynamic cad = System.Runtime.InteropServices.Marshal.GetActiveObject(progId);
287
- if (cad != null) {
288
- int docCount = cad.Documents.Count;
289
- return new { hasDoc = docCount > 0, docCount = docCount };
290
- }
291
- } catch (Exception ex) {
292
- System.Diagnostics.Debug.WriteLine("cadHasDoc error: " + ex.Message);
293
- }
294
- return new { hasDoc = false, docCount = 0 };
295
- }
296
- */});
297
-
298
- const cadNewDoc = edge.func(function() {/*
299
- async (input) => {
300
- try {
301
- string platform = input.ToString();
302
- string progId = platform + ".Application";
303
- dynamic cad = System.Runtime.InteropServices.Marshal.GetActiveObject(progId);
304
- if (cad != null) {
305
- cad.Documents.Add();
306
- return new { success = true };
307
- }
308
- } catch (Exception ex) {
309
- System.Diagnostics.Debug.WriteLine("cadNewDoc error: " + ex.Message);
310
- return new { success = false, error = ex.Message };
311
- }
312
- return new { success = false, error = "CAD not found" };
313
- }
314
- */});
315
-
316
- const cadBringToFront = edge.func(function() {/*
317
- async (input) => {
318
- try {
319
- string platform = input.ToString();
320
- string progId = platform + ".Application";
321
- dynamic cad = System.Runtime.InteropServices.Marshal.GetActiveObject(progId);
322
- if (cad != null) {
323
- cad.Visible = true;
324
- return new { success = true };
325
- }
326
- } catch (Exception ex) {
327
- System.Diagnostics.Debug.WriteLine("cadBringToFront error: " + ex.Message);
328
- return new { success = false, error = ex.Message };
329
- }
330
- return new { success = false, error = "CAD not found" };
331
- }
332
- */});
333
-
334
- async function waitForIdle(platform) {
335
- let retries = BUSY_RETRIES;
336
- while (retries > 0) {
337
- const checkResult = await new Promise((resolve, reject) => {
338
- cadIsBusy(platform || 'AutoCAD', (e, r) => {
339
- if (e) reject(e);
340
- else resolve(r);
341
- });
342
- });
343
- if (!checkResult.isBusy) return true;
344
- retries--;
345
- if (retries > 0) await new Promise(resolve => setTimeout(resolve, BUSY_DELAY));
346
- }
347
- return false;
348
- }
349
-
350
- export function checkParens(code) {
351
- let depth = 0;
352
- let inString = false;
353
- for (let i = 0; i < code.length; i++) {
354
- const ch = code[i];
355
- if (inString) {
356
- if (ch === '\\' && i + 1 < code.length) {
357
- i++;
358
- continue;
359
- }
360
- if (ch === '"') {
361
- inString = false;
362
- }
363
- continue;
364
- }
365
- if (ch === '"') {
366
- inString = true;
367
- continue;
368
- }
369
- if (ch === ';') {
370
- while (i < code.length && code[i] !== '\n') i++;
371
- continue;
372
- }
373
- if (ch === '(') depth++;
374
- if (ch === ')') depth--;
375
- if (depth < 0) return { valid: false, error: '多余右括号 )', pos: i };
376
- }
377
- if (depth > 0) return { valid: false, error: `缺少 ${depth} 个右括号 )`, pos: code.length - 1 };
378
- if (depth < 0) return { valid: false, error: `多余 ${-depth} 个左括号 (` };
379
- return { valid: true };
380
- }
381
-
382
- async function handleMessage(msg) {
383
- if (msg.type === 'ping') {
384
- return { pong: true };
385
- }
386
- if (msg.type === 'connect') {
387
- try {
388
- const result = await new Promise((resolve, reject) => {
389
- cadConnect({}, (e, r) => {
390
- if (e) reject(e);
391
- else resolve(r);
392
- });
393
- });
394
- if (result && result.success) return result;
395
- } catch (e) {
396
- log('cadConnect failed: ' + e.message);
397
- }
398
- return new Promise((resolve, reject) => {
399
- cadLaunch({}, (e, r) => {
400
- if (e) reject(e);
401
- else resolve(r);
402
- });
403
- });
404
- }
405
- if (msg.type === 'hasdoc') {
406
- return new Promise((resolve, reject) => {
407
- cadHasDoc(msg.platform || 'AutoCAD', (e, r) => {
408
- if (e) reject(e);
409
- else resolve(r);
410
- });
411
- });
412
- }
413
- if (msg.type === 'newdoc') {
414
- return new Promise((resolve, reject) => {
415
- cadNewDoc(msg.platform || 'AutoCAD', (e, r) => {
416
- if (e) reject(e);
417
- else resolve(r);
418
- });
419
- });
420
- }
421
- if (msg.type === 'bringToFront') {
422
- return new Promise((resolve, reject) => {
423
- cadBringToFront(msg.platform || 'AutoCAD', (e, r) => {
424
- if (e) reject(e);
425
- else resolve(r);
426
- });
427
- });
428
- }
429
- if (msg.type === 'send') {
430
- const docCheck = await new Promise((resolve, reject) => {
431
- cadHasDoc(msg.platform || 'AutoCAD', (e, r) => {
432
- if (e) reject(e);
433
- else resolve(r);
434
- });
435
- });
436
- if (!docCheck.hasDoc) {
437
- return { success: false, error: 'No open document' };
438
- }
439
- const parenCheck = checkParens(msg.code);
440
- if (!parenCheck.valid) {
441
- return { success: false, error: `括号错误: ${parenCheck.error} (位置 ${parenCheck.pos})` };
442
- }
443
- if (!(await waitForIdle(msg.platform || 'AutoCAD'))) {
444
- return { success: false, error: 'CAD is busy, timeout' };
445
- }
446
- log(`send: ${msg.code}`);
447
- return new Promise((resolve, reject) => {
448
- cadSend({ code: msg.code, platform: msg.platform }, (e, r) => {
449
- if (e) {
450
- log(`send error: ${e.message}`);
451
- reject(e);
452
- } else {
453
- log(`send result: ${JSON.stringify(r)}`);
454
- resolve(r);
455
- }
456
- });
457
- });
458
- }
459
- if (msg.type === 'sendResult') {
460
- const docCheck = await new Promise((resolve, reject) => {
461
- cadHasDoc(msg.platform || 'AutoCAD', (e, r) => {
462
- if (e) reject(e);
463
- else resolve(r);
464
- });
465
- });
466
- if (!docCheck.hasDoc) {
467
- return { success: false, error: 'No open document' };
468
- }
469
- const parenCheck = checkParens(msg.code);
470
- if (!parenCheck.valid) {
471
- return { success: false, error: `括号错误: ${parenCheck.error} (位置 ${parenCheck.pos})` };
472
- }
473
- if (!(await waitForIdle(msg.platform))) {
474
- return { success: false, error: 'CAD is busy, timeout' };
475
- }
476
- log(`sendResult: ${msg.code}`);
477
- return new Promise((resolve, reject) => {
478
- cadSendWithResult({ code: msg.code, platform: msg.platform, encoding: msg.encoding || '' }, (e, r) => {
479
- if (e) {
480
- log(`sendResult error: ${e.message}`);
481
- reject(e);
482
- } else {
483
- log(`sendResult result: ${JSON.stringify(r)}`);
484
- resolve(r);
485
- }
486
- });
487
- });
488
- }
489
- if (msg.type === 'isBusy') {
490
- return new Promise((resolve, reject) => {
491
- cadIsBusy(msg.platform || 'AutoCAD', (e, r) => {
492
- if (e) reject(e);
493
- else resolve(r);
494
- });
495
- });
496
- }
497
- return { error: 'unknown message type' };
498
- }