@atlisp/mcp 1.3.1 → 1.3.3
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/atlisp-mcp.js +6 -6
- package/dist/cad-worker.js +357 -80
- package/package.json +2 -2
package/dist/atlisp-mcp.js
CHANGED
|
@@ -633,7 +633,7 @@ async function getFunctionUsage(funcName, packageName) {
|
|
|
633
633
|
const response = await fetch(FUNCTIONS_URL, { headers: { "User-Agent": "atlisp-mcp" } });
|
|
634
634
|
if (response.ok) {
|
|
635
635
|
const data = await response.json();
|
|
636
|
-
const funcs = data.
|
|
636
|
+
const funcs = Object.values(data.all_functions || {});
|
|
637
637
|
const func = funcs.find((f2) => f2.name === funcName || f2.name === `${packageName}:${funcName}`);
|
|
638
638
|
if (func) results.push(func);
|
|
639
639
|
}
|
|
@@ -663,14 +663,14 @@ async function getFunctionUsage(funcName, packageName) {
|
|
|
663
663
|
return { content: [{ type: "text", text: `\u9519\u8BEF: ${e.message}` }], isError: true };
|
|
664
664
|
}
|
|
665
665
|
}
|
|
666
|
-
async function
|
|
666
|
+
async function listSymbols(packageName) {
|
|
667
667
|
try {
|
|
668
668
|
let allFuncs = [];
|
|
669
669
|
try {
|
|
670
670
|
const response = await fetch(FUNCTIONS_URL, { headers: { "User-Agent": "atlisp-mcp" } });
|
|
671
671
|
if (response.ok) {
|
|
672
672
|
const data = await response.json();
|
|
673
|
-
const funcs = data.
|
|
673
|
+
const funcs = Object.values(data.all_functions || {});
|
|
674
674
|
if (packageName) {
|
|
675
675
|
allFuncs = funcs.filter((f) => f.name.startsWith(`${packageName}:`));
|
|
676
676
|
} else {
|
|
@@ -686,7 +686,7 @@ async function listFunctions(packageName) {
|
|
|
686
686
|
try {
|
|
687
687
|
const raw = await fs2.readFile(path3.join(FUNCTIONS_DIR, file), "utf-8");
|
|
688
688
|
const data = JSON.parse(raw);
|
|
689
|
-
const funcs = data.
|
|
689
|
+
const funcs = Object.values(data.all_functions || {});
|
|
690
690
|
if (packageName) {
|
|
691
691
|
allFuncs = funcs.filter((f) => f.name.startsWith(`${packageName}:`));
|
|
692
692
|
} else {
|
|
@@ -1864,12 +1864,12 @@ ${CAD_PLATFORMS.join("\n")}
|
|
|
1864
1864
|
install_atlisp: () => installAtlisp(),
|
|
1865
1865
|
init_atlisp: () => initAtlisp(),
|
|
1866
1866
|
get_function_usage: (a) => getFunctionUsage(a.name, a.package),
|
|
1867
|
-
list_symbols: (a) =>
|
|
1867
|
+
list_symbols: (a) => listSymbols(a.package),
|
|
1868
1868
|
import_funlib: async (a) => {
|
|
1869
1869
|
const data = await loadAtlibFunctionLib();
|
|
1870
1870
|
if (!data) return { content: [{ type: "text", text: "\u52A0\u8F7D\u51FD\u6570\u5E93\u5931\u8D25" }], isError: true };
|
|
1871
1871
|
if (a.format === "list") {
|
|
1872
|
-
const items = data.
|
|
1872
|
+
const items = Object.values(data.all_functions || {}).map((f) => `${f.name}: ${f.description || ""}`);
|
|
1873
1873
|
return { content: [{ type: "text", text: items.join("\n") }] };
|
|
1874
1874
|
}
|
|
1875
1875
|
return { content: [{ type: "text", text: JSON.stringify(data, null, 2) }] };
|
package/dist/cad-worker.js
CHANGED
|
@@ -1,80 +1,359 @@
|
|
|
1
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');
|
|
2
11
|
|
|
3
|
-
// src/cad-worker.js
|
|
4
|
-
import edge from "edge-js";
|
|
5
|
-
import process from "process";
|
|
6
|
-
import fs from "fs";
|
|
7
|
-
import path from "path";
|
|
8
|
-
var BUSY_RETRIES = parseInt(process.env.BUSY_RETRIES || "10", 10);
|
|
9
|
-
var BUSY_DELAY = parseInt(process.env.BUSY_DELAY || "500", 10);
|
|
10
|
-
var DEBUG_FILE = process.env.DEBUG_FILE || path.join(process.env.TEMP || "/tmp", "cad-worker-debug.log");
|
|
11
12
|
function log(msg) {
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
});
|
|
17
|
-
}
|
|
13
|
+
const entry = `${new Date().toISOString()} ${msg}\n`;
|
|
14
|
+
if (process.env.DEBUG) {
|
|
15
|
+
fs.appendFile(DEBUG_FILE, entry, () => {});
|
|
16
|
+
}
|
|
18
17
|
}
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
}
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
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("\x1b\x1b(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) => {
|
|
30
240
|
stdinBuffer += data;
|
|
31
|
-
const lines = stdinBuffer.split(
|
|
32
|
-
stdinBuffer = lines.pop() ||
|
|
241
|
+
const lines = stdinBuffer.split('\n');
|
|
242
|
+
stdinBuffer = lines.pop() || '';
|
|
33
243
|
for (const line of lines) {
|
|
34
244
|
if (!line.trim()) continue;
|
|
35
245
|
try {
|
|
36
246
|
const msg = JSON.parse(line);
|
|
37
247
|
const requestId = msg.requestId;
|
|
38
|
-
handleMessage(msg).then(
|
|
39
|
-
process.stdout.write(JSON.stringify({ ...result, requestId }) +
|
|
40
|
-
}).catch(
|
|
41
|
-
process.stdout.write(JSON.stringify({ error: err.message, 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');
|
|
42
252
|
});
|
|
43
253
|
} catch (e) {
|
|
44
|
-
process.stdout.write(JSON.stringify({ error:
|
|
254
|
+
process.stdout.write(JSON.stringify({ error: 'invalid message' }) + '\n');
|
|
45
255
|
}
|
|
46
256
|
}
|
|
47
257
|
});
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
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
|
+
|
|
56
334
|
async function waitForIdle(platform) {
|
|
57
335
|
let retries = BUSY_RETRIES;
|
|
58
336
|
while (retries > 0) {
|
|
59
337
|
const checkResult = await new Promise((resolve, reject) => {
|
|
60
|
-
cadIsBusy(platform ||
|
|
338
|
+
cadIsBusy(platform || 'AutoCAD', (e, r) => {
|
|
61
339
|
if (e) reject(e);
|
|
62
340
|
else resolve(r);
|
|
63
341
|
});
|
|
64
342
|
});
|
|
65
343
|
if (!checkResult.isBusy) return true;
|
|
66
344
|
retries--;
|
|
67
|
-
if (retries > 0) await new Promise(
|
|
345
|
+
if (retries > 0) await new Promise(resolve => setTimeout(resolve, BUSY_DELAY));
|
|
68
346
|
}
|
|
69
347
|
return false;
|
|
70
348
|
}
|
|
71
|
-
|
|
349
|
+
|
|
350
|
+
export function checkParens(code) {
|
|
72
351
|
let depth = 0;
|
|
73
352
|
let inString = false;
|
|
74
353
|
for (let i = 0; i < code.length; i++) {
|
|
75
354
|
const ch = code[i];
|
|
76
355
|
if (inString) {
|
|
77
|
-
if (ch ===
|
|
356
|
+
if (ch === '\\' && i + 1 < code.length) {
|
|
78
357
|
i++;
|
|
79
358
|
continue;
|
|
80
359
|
}
|
|
@@ -87,23 +366,24 @@ function checkParens(code) {
|
|
|
87
366
|
inString = true;
|
|
88
367
|
continue;
|
|
89
368
|
}
|
|
90
|
-
if (ch ===
|
|
91
|
-
while (i < code.length && code[i] !==
|
|
369
|
+
if (ch === ';') {
|
|
370
|
+
while (i < code.length && code[i] !== '\n') i++;
|
|
92
371
|
continue;
|
|
93
372
|
}
|
|
94
|
-
if (ch ===
|
|
95
|
-
if (ch ===
|
|
96
|
-
if (depth < 0) return { valid: false, error:
|
|
373
|
+
if (ch === '(') depth++;
|
|
374
|
+
if (ch === ')') depth--;
|
|
375
|
+
if (depth < 0) return { valid: false, error: '多余右括号 )', pos: i };
|
|
97
376
|
}
|
|
98
|
-
if (depth > 0) return { valid: false, error:
|
|
99
|
-
if (depth < 0) return { valid: false, error:
|
|
377
|
+
if (depth > 0) return { valid: false, error: `缺少 ${depth} 个右括号 )`, pos: code.length - 1 };
|
|
378
|
+
if (depth < 0) return { valid: false, error: `多余 ${-depth} 个左括号 (` };
|
|
100
379
|
return { valid: true };
|
|
101
380
|
}
|
|
381
|
+
|
|
102
382
|
async function handleMessage(msg) {
|
|
103
|
-
if (msg.type ===
|
|
383
|
+
if (msg.type === 'ping') {
|
|
104
384
|
return { pong: true };
|
|
105
385
|
}
|
|
106
|
-
if (msg.type ===
|
|
386
|
+
if (msg.type === 'connect') {
|
|
107
387
|
try {
|
|
108
388
|
const result = await new Promise((resolve, reject) => {
|
|
109
389
|
cadConnect({}, (e, r) => {
|
|
@@ -113,7 +393,7 @@ async function handleMessage(msg) {
|
|
|
113
393
|
});
|
|
114
394
|
if (result && result.success) return result;
|
|
115
395
|
} catch (e) {
|
|
116
|
-
log(
|
|
396
|
+
log('cadConnect failed: ' + e.message);
|
|
117
397
|
}
|
|
118
398
|
return new Promise((resolve, reject) => {
|
|
119
399
|
cadLaunch({}, (e, r) => {
|
|
@@ -122,46 +402,46 @@ async function handleMessage(msg) {
|
|
|
122
402
|
});
|
|
123
403
|
});
|
|
124
404
|
}
|
|
125
|
-
if (msg.type ===
|
|
405
|
+
if (msg.type === 'hasdoc') {
|
|
126
406
|
return new Promise((resolve, reject) => {
|
|
127
|
-
cadHasDoc(msg.platform ||
|
|
407
|
+
cadHasDoc(msg.platform || 'AutoCAD', (e, r) => {
|
|
128
408
|
if (e) reject(e);
|
|
129
409
|
else resolve(r);
|
|
130
410
|
});
|
|
131
411
|
});
|
|
132
412
|
}
|
|
133
|
-
if (msg.type ===
|
|
413
|
+
if (msg.type === 'newdoc') {
|
|
134
414
|
return new Promise((resolve, reject) => {
|
|
135
|
-
cadNewDoc(msg.platform ||
|
|
415
|
+
cadNewDoc(msg.platform || 'AutoCAD', (e, r) => {
|
|
136
416
|
if (e) reject(e);
|
|
137
417
|
else resolve(r);
|
|
138
418
|
});
|
|
139
419
|
});
|
|
140
420
|
}
|
|
141
|
-
if (msg.type ===
|
|
421
|
+
if (msg.type === 'bringToFront') {
|
|
142
422
|
return new Promise((resolve, reject) => {
|
|
143
|
-
cadBringToFront(msg.platform ||
|
|
423
|
+
cadBringToFront(msg.platform || 'AutoCAD', (e, r) => {
|
|
144
424
|
if (e) reject(e);
|
|
145
425
|
else resolve(r);
|
|
146
426
|
});
|
|
147
427
|
});
|
|
148
428
|
}
|
|
149
|
-
if (msg.type ===
|
|
429
|
+
if (msg.type === 'send') {
|
|
150
430
|
const docCheck = await new Promise((resolve, reject) => {
|
|
151
|
-
cadHasDoc(msg.platform ||
|
|
431
|
+
cadHasDoc(msg.platform || 'AutoCAD', (e, r) => {
|
|
152
432
|
if (e) reject(e);
|
|
153
433
|
else resolve(r);
|
|
154
434
|
});
|
|
155
435
|
});
|
|
156
436
|
if (!docCheck.hasDoc) {
|
|
157
|
-
return { success: false, error:
|
|
437
|
+
return { success: false, error: 'No open document' };
|
|
158
438
|
}
|
|
159
439
|
const parenCheck = checkParens(msg.code);
|
|
160
440
|
if (!parenCheck.valid) {
|
|
161
|
-
return { success: false, error:
|
|
441
|
+
return { success: false, error: `括号错误: ${parenCheck.error} (位置 ${parenCheck.pos})` };
|
|
162
442
|
}
|
|
163
|
-
if (!await waitForIdle(msg.platform ||
|
|
164
|
-
return { success: false, error:
|
|
443
|
+
if (!(await waitForIdle(msg.platform || 'AutoCAD'))) {
|
|
444
|
+
return { success: false, error: 'CAD is busy, timeout' };
|
|
165
445
|
}
|
|
166
446
|
log(`send: ${msg.code}`);
|
|
167
447
|
return new Promise((resolve, reject) => {
|
|
@@ -176,26 +456,26 @@ async function handleMessage(msg) {
|
|
|
176
456
|
});
|
|
177
457
|
});
|
|
178
458
|
}
|
|
179
|
-
if (msg.type ===
|
|
459
|
+
if (msg.type === 'sendResult') {
|
|
180
460
|
const docCheck = await new Promise((resolve, reject) => {
|
|
181
|
-
cadHasDoc(msg.platform ||
|
|
461
|
+
cadHasDoc(msg.platform || 'AutoCAD', (e, r) => {
|
|
182
462
|
if (e) reject(e);
|
|
183
463
|
else resolve(r);
|
|
184
464
|
});
|
|
185
465
|
});
|
|
186
466
|
if (!docCheck.hasDoc) {
|
|
187
|
-
return { success: false, error:
|
|
467
|
+
return { success: false, error: 'No open document' };
|
|
188
468
|
}
|
|
189
469
|
const parenCheck = checkParens(msg.code);
|
|
190
470
|
if (!parenCheck.valid) {
|
|
191
|
-
return { success: false, error:
|
|
471
|
+
return { success: false, error: `括号错误: ${parenCheck.error} (位置 ${parenCheck.pos})` };
|
|
192
472
|
}
|
|
193
|
-
if (!await waitForIdle(msg.platform)) {
|
|
194
|
-
return { success: false, error:
|
|
473
|
+
if (!(await waitForIdle(msg.platform))) {
|
|
474
|
+
return { success: false, error: 'CAD is busy, timeout' };
|
|
195
475
|
}
|
|
196
476
|
log(`sendResult: ${msg.code}`);
|
|
197
477
|
return new Promise((resolve, reject) => {
|
|
198
|
-
cadSendWithResult({ code: msg.code, platform: msg.platform, encoding: msg.encoding ||
|
|
478
|
+
cadSendWithResult({ code: msg.code, platform: msg.platform, encoding: msg.encoding || '' }, (e, r) => {
|
|
199
479
|
if (e) {
|
|
200
480
|
log(`sendResult error: ${e.message}`);
|
|
201
481
|
reject(e);
|
|
@@ -206,16 +486,13 @@ async function handleMessage(msg) {
|
|
|
206
486
|
});
|
|
207
487
|
});
|
|
208
488
|
}
|
|
209
|
-
if (msg.type ===
|
|
489
|
+
if (msg.type === 'isBusy') {
|
|
210
490
|
return new Promise((resolve, reject) => {
|
|
211
|
-
cadIsBusy(msg.platform ||
|
|
491
|
+
cadIsBusy(msg.platform || 'AutoCAD', (e, r) => {
|
|
212
492
|
if (e) reject(e);
|
|
213
493
|
else resolve(r);
|
|
214
494
|
});
|
|
215
495
|
});
|
|
216
496
|
}
|
|
217
|
-
return { error:
|
|
218
|
-
}
|
|
219
|
-
export {
|
|
220
|
-
checkParens
|
|
221
|
-
};
|
|
497
|
+
return { error: 'unknown message type' };
|
|
498
|
+
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@atlisp/mcp",
|
|
3
|
-
"version": "1.3.
|
|
3
|
+
"version": "1.3.3",
|
|
4
4
|
"description": "MCP Server for @lisp on CAD",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"bin": {
|
|
@@ -18,7 +18,7 @@
|
|
|
18
18
|
"start": "node src/atlisp-mcp.js",
|
|
19
19
|
"build": "npm run build:main && npm run build:worker",
|
|
20
20
|
"build:main": "esbuild src/atlisp-mcp.js --bundle --platform=node --target=node18 --format=esm --outdir=dist --external:edge-js --packages=external --banner:js=\"#!/usr/bin/env node\"",
|
|
21
|
-
"build:worker": "
|
|
21
|
+
"build:worker": "node -e \"require('fs').copyFileSync('src/cad-worker.js','dist/cad-worker.js')\"",
|
|
22
22
|
"prepublishOnly": "npm run build",
|
|
23
23
|
"test": "vitest run",
|
|
24
24
|
"test:watch": "vitest"
|