@atlisp/mcp 1.4.1 → 1.4.2
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 +715 -287
- package/dist/cad-worker.js +48 -0
- package/package.json +1 -1
package/dist/atlisp-mcp.js
CHANGED
|
@@ -1,9 +1,11 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
|
|
3
3
|
// src/atlisp-mcp.js
|
|
4
|
-
import
|
|
5
|
-
import
|
|
4
|
+
import path7 from "path";
|
|
5
|
+
import fs6 from "fs";
|
|
6
|
+
import { fileURLToPath as fileURLToPath4 } from "url";
|
|
6
7
|
import { createRequire } from "module";
|
|
8
|
+
import os4 from "os";
|
|
7
9
|
import express from "express";
|
|
8
10
|
import rawBody from "raw-body";
|
|
9
11
|
import iconv from "iconv-lite";
|
|
@@ -34,8 +36,7 @@ var SessionTransport = class {
|
|
|
34
36
|
this._started = true;
|
|
35
37
|
}
|
|
36
38
|
async send(message) {
|
|
37
|
-
if (this._closed)
|
|
38
|
-
return;
|
|
39
|
+
if (this._closed) return;
|
|
39
40
|
if (this._pendingRequest) {
|
|
40
41
|
const { resolve, reject, timeout } = this._pendingRequest;
|
|
41
42
|
clearTimeout(timeout);
|
|
@@ -44,8 +45,7 @@ var SessionTransport = class {
|
|
|
44
45
|
}
|
|
45
46
|
}
|
|
46
47
|
async close() {
|
|
47
|
-
if (this._closed)
|
|
48
|
-
return;
|
|
48
|
+
if (this._closed) return;
|
|
49
49
|
this._closed = true;
|
|
50
50
|
if (this._pendingRequest) {
|
|
51
51
|
const { reject, timeout } = this._pendingRequest;
|
|
@@ -119,7 +119,7 @@ var FILE_EXTENSIONS = {
|
|
|
119
119
|
"BricsCAD": [".des"]
|
|
120
120
|
};
|
|
121
121
|
var SERVER_NAME = "atlisp-mcp-server";
|
|
122
|
-
var SERVER_VERSION = "1.4.
|
|
122
|
+
var SERVER_VERSION = "1.4.1";
|
|
123
123
|
var MOCK_PACKAGES = [
|
|
124
124
|
{ name: "base", description: "\u57FA\u7840\u51FD\u6570\u5E93", version: "1.0.0" },
|
|
125
125
|
{ name: "at-pm", description: "\u5DE5\u7A0B\u9879\u76EE\u7BA1\u7406", version: "2.1.0" },
|
|
@@ -176,6 +176,8 @@ var config_default = config;
|
|
|
176
176
|
// src/cad.js
|
|
177
177
|
var MESSAGE_TIMEOUT = config_default.messageTimeout;
|
|
178
178
|
var HEARTBEAT_INTERVAL = config_default.heartbeatInterval;
|
|
179
|
+
var MAX_RESTART_ATTEMPTS = 5;
|
|
180
|
+
var RESTART_BACKOFF_BASE = 1e3;
|
|
179
181
|
var __dirname = path.dirname(fileURLToPath(import.meta.url));
|
|
180
182
|
var workerPath = path.join(__dirname, "cad-worker.js");
|
|
181
183
|
var worker = null;
|
|
@@ -184,6 +186,8 @@ var heartbeatTimer = null;
|
|
|
184
186
|
var pendingRequests = /* @__PURE__ */ new Map();
|
|
185
187
|
var stdoutHandlerSetup = false;
|
|
186
188
|
var MAX_BUFFER_SIZE = 1024 * 1024;
|
|
189
|
+
var restartCount = 0;
|
|
190
|
+
var restartTimer = null;
|
|
187
191
|
function resetWorker() {
|
|
188
192
|
for (const [id, { reject, timeout }] of pendingRequests) {
|
|
189
193
|
clearTimeout(timeout);
|
|
@@ -200,6 +204,27 @@ function resetWorker() {
|
|
|
200
204
|
heartbeatTimer = null;
|
|
201
205
|
}
|
|
202
206
|
}
|
|
207
|
+
function scheduleRestart() {
|
|
208
|
+
if (restartTimer) {
|
|
209
|
+
clearTimeout(restartTimer);
|
|
210
|
+
restartTimer = null;
|
|
211
|
+
}
|
|
212
|
+
if (restartCount >= MAX_RESTART_ATTEMPTS) {
|
|
213
|
+
console.error("Max worker restart attempts reached, giving up");
|
|
214
|
+
return;
|
|
215
|
+
}
|
|
216
|
+
const delay = Math.min(RESTART_BACKOFF_BASE * Math.pow(2, restartCount), 3e4);
|
|
217
|
+
restartCount++;
|
|
218
|
+
console.error(`Scheduling worker restart in ${delay}ms (attempt ${restartCount}/${MAX_RESTART_ATTEMPTS})`);
|
|
219
|
+
restartTimer = setTimeout(() => {
|
|
220
|
+
restartTimer = null;
|
|
221
|
+
console.error("Attempting worker restart...");
|
|
222
|
+
getWorker(true);
|
|
223
|
+
}, delay);
|
|
224
|
+
}
|
|
225
|
+
function resetRestartCount() {
|
|
226
|
+
restartCount = 0;
|
|
227
|
+
}
|
|
203
228
|
function setupStdoutHandler(w) {
|
|
204
229
|
let buffer = "";
|
|
205
230
|
stdoutHandlerSetup = true;
|
|
@@ -212,8 +237,7 @@ function setupStdoutHandler(w) {
|
|
|
212
237
|
const lines = buffer.split("\n");
|
|
213
238
|
buffer = lines.pop() || "";
|
|
214
239
|
for (const line of lines) {
|
|
215
|
-
if (!line.trim())
|
|
216
|
-
continue;
|
|
240
|
+
if (!line.trim()) continue;
|
|
217
241
|
try {
|
|
218
242
|
const result = JSON.parse(line);
|
|
219
243
|
const rid = result.requestId;
|
|
@@ -235,21 +259,19 @@ function setupStdoutHandler(w) {
|
|
|
235
259
|
console.error("Unexpected error in worker stdout handler:", e.message);
|
|
236
260
|
}
|
|
237
261
|
});
|
|
262
|
+
w.stderr.on("data", (d) => console.error("worker stderr:", d.toString()));
|
|
238
263
|
}
|
|
239
|
-
function getWorker() {
|
|
240
|
-
if (!worker || !worker.connected) {
|
|
241
|
-
if (worker)
|
|
242
|
-
worker.kill();
|
|
264
|
+
function getWorker(force = false) {
|
|
265
|
+
if (!worker || !worker.connected || force) {
|
|
266
|
+
if (worker) worker.kill();
|
|
243
267
|
worker = spawn("node", [workerPath], {
|
|
244
268
|
stdio: ["pipe", "pipe", "pipe"]
|
|
245
269
|
});
|
|
246
270
|
worker.connected = true;
|
|
247
|
-
worker.stderr.on("data", (d) => console.error("worker stderr:", d.toString()));
|
|
248
271
|
const w = worker;
|
|
249
272
|
w.on("exit", (code) => {
|
|
250
|
-
console.error("worker exited:", code);
|
|
251
|
-
if (w !== worker)
|
|
252
|
-
return;
|
|
273
|
+
console.error("worker exited with code:", code);
|
|
274
|
+
if (w !== worker) return;
|
|
253
275
|
w.connected = false;
|
|
254
276
|
for (const [id, { reject, timeout }] of pendingRequests) {
|
|
255
277
|
clearTimeout(timeout);
|
|
@@ -261,15 +283,16 @@ function getWorker() {
|
|
|
261
283
|
clearInterval(heartbeatTimer);
|
|
262
284
|
heartbeatTimer = null;
|
|
263
285
|
}
|
|
286
|
+
scheduleRestart();
|
|
264
287
|
});
|
|
265
288
|
setupStdoutHandler(w);
|
|
266
289
|
startHeartbeat();
|
|
290
|
+
resetRestartCount();
|
|
267
291
|
}
|
|
268
292
|
return worker;
|
|
269
293
|
}
|
|
270
294
|
function startHeartbeat() {
|
|
271
|
-
if (heartbeatTimer)
|
|
272
|
-
clearInterval(heartbeatTimer);
|
|
295
|
+
if (heartbeatTimer) clearInterval(heartbeatTimer);
|
|
273
296
|
heartbeatTimer = setInterval(async () => {
|
|
274
297
|
try {
|
|
275
298
|
const result = await sendMessage({ type: "ping" });
|
|
@@ -313,11 +336,11 @@ var CadConnection = class {
|
|
|
313
336
|
isAvailable() {
|
|
314
337
|
return process.platform === "win32";
|
|
315
338
|
}
|
|
316
|
-
async connect() {
|
|
317
|
-
if (!this.isAvailable())
|
|
318
|
-
return false;
|
|
339
|
+
async connect(platform = null) {
|
|
340
|
+
if (!this.isAvailable()) return false;
|
|
319
341
|
try {
|
|
320
|
-
const
|
|
342
|
+
const msg = platform ? { type: "connect", platform } : { type: "connect" };
|
|
343
|
+
const result = await sendMessage(msg);
|
|
321
344
|
if (result && result.success) {
|
|
322
345
|
this.version = result.version;
|
|
323
346
|
this.product = result.platform;
|
|
@@ -331,16 +354,13 @@ var CadConnection = class {
|
|
|
331
354
|
return false;
|
|
332
355
|
}
|
|
333
356
|
async sendCommand(code) {
|
|
334
|
-
if (!this.connected)
|
|
335
|
-
throw new Error("\u672A\u8FDE\u63A5 CAD");
|
|
357
|
+
if (!this.connected) throw new Error("\u672A\u8FDE\u63A5 CAD");
|
|
336
358
|
const result = await sendMessage({ type: "send", code, platform: _platform });
|
|
337
|
-
if (result.success)
|
|
338
|
-
return true;
|
|
359
|
+
if (result.success) return true;
|
|
339
360
|
throw new Error(result.error || "\u53D1\u9001\u5931\u8D25");
|
|
340
361
|
}
|
|
341
362
|
async sendCommandWithResult(code, encoding = null) {
|
|
342
|
-
if (!this.connected)
|
|
343
|
-
throw new Error("\u672A\u8FDE\u63A5 CAD");
|
|
363
|
+
if (!this.connected) throw new Error("\u672A\u8FDE\u63A5 CAD");
|
|
344
364
|
const result = await sendMessage({ type: "sendResult", code, platform: _platform, encoding: encoding || "" });
|
|
345
365
|
if (result.success) {
|
|
346
366
|
return result.result || "";
|
|
@@ -354,8 +374,7 @@ var CadConnection = class {
|
|
|
354
374
|
return this.product;
|
|
355
375
|
}
|
|
356
376
|
async isBusy() {
|
|
357
|
-
if (!this.connected)
|
|
358
|
-
return false;
|
|
377
|
+
if (!this.connected) return false;
|
|
359
378
|
try {
|
|
360
379
|
const result = await sendMessage({ type: "isBusy", platform: _platform });
|
|
361
380
|
return result && result.isBusy;
|
|
@@ -364,8 +383,7 @@ var CadConnection = class {
|
|
|
364
383
|
}
|
|
365
384
|
}
|
|
366
385
|
async hasDoc() {
|
|
367
|
-
if (!this.connected)
|
|
368
|
-
return { hasDoc: false, docCount: 0 };
|
|
386
|
+
if (!this.connected) return { hasDoc: false, docCount: 0 };
|
|
369
387
|
try {
|
|
370
388
|
const result = await sendMessage({ type: "hasdoc", platform: _platform });
|
|
371
389
|
return result || { hasDoc: false, docCount: 0 };
|
|
@@ -374,8 +392,7 @@ var CadConnection = class {
|
|
|
374
392
|
}
|
|
375
393
|
}
|
|
376
394
|
async newDoc() {
|
|
377
|
-
if (!this.connected)
|
|
378
|
-
throw new Error("\u672A\u8FDE\u63A5 CAD");
|
|
395
|
+
if (!this.connected) throw new Error("\u672A\u8FDE\u63A5 CAD");
|
|
379
396
|
try {
|
|
380
397
|
const result = await sendMessage({ type: "newdoc", platform: _platform });
|
|
381
398
|
return result && result.success;
|
|
@@ -384,8 +401,7 @@ var CadConnection = class {
|
|
|
384
401
|
}
|
|
385
402
|
}
|
|
386
403
|
async bringToFront() {
|
|
387
|
-
if (!this.connected)
|
|
388
|
-
throw new Error("\u672A\u8FDE\u63A5 CAD");
|
|
404
|
+
if (!this.connected) throw new Error("\u672A\u8FDE\u63A5 CAD");
|
|
389
405
|
try {
|
|
390
406
|
const result = await sendMessage({ type: "bringToFront", platform: _platform });
|
|
391
407
|
return result && result.success;
|
|
@@ -394,8 +410,7 @@ var CadConnection = class {
|
|
|
394
410
|
}
|
|
395
411
|
}
|
|
396
412
|
async getInfo() {
|
|
397
|
-
if (!this.connected)
|
|
398
|
-
return "CAD \u672A\u8FDE\u63A5";
|
|
413
|
+
if (!this.connected) return "CAD \u672A\u8FDE\u63A5";
|
|
399
414
|
return `Platform: ${this.product}, Version: ${this.version}, Status: Connected`;
|
|
400
415
|
}
|
|
401
416
|
async disconnect() {
|
|
@@ -428,9 +443,35 @@ import fs from "fs";
|
|
|
428
443
|
import path2 from "path";
|
|
429
444
|
import os from "os";
|
|
430
445
|
var DEBUG_FILE = process.env.DEBUG_FILE || path2.join(os.tmpdir(), "mcp-server-debug.log");
|
|
446
|
+
var MAX_LOG_SIZE = 10 * 1024 * 1024;
|
|
447
|
+
var MAX_LOG_FILES = 5;
|
|
431
448
|
var stream = null;
|
|
449
|
+
function rotateLog() {
|
|
450
|
+
if (!fs.existsSync(DEBUG_FILE)) return;
|
|
451
|
+
const stat = fs.statSync(DEBUG_FILE);
|
|
452
|
+
if (stat.size < MAX_LOG_SIZE) return;
|
|
453
|
+
if (stream) {
|
|
454
|
+
stream.end();
|
|
455
|
+
stream = null;
|
|
456
|
+
}
|
|
457
|
+
for (let i = MAX_LOG_FILES - 1; i > 0; i--) {
|
|
458
|
+
const oldPath = `${DEBUG_FILE}.${i}`;
|
|
459
|
+
const newPath = `${DEBUG_FILE}.${i + 1}`;
|
|
460
|
+
if (fs.existsSync(oldPath)) {
|
|
461
|
+
try {
|
|
462
|
+
fs.renameSync(oldPath, newPath);
|
|
463
|
+
} catch {
|
|
464
|
+
}
|
|
465
|
+
}
|
|
466
|
+
}
|
|
467
|
+
try {
|
|
468
|
+
fs.renameSync(DEBUG_FILE, `${DEBUG_FILE}.1`);
|
|
469
|
+
} catch {
|
|
470
|
+
}
|
|
471
|
+
}
|
|
432
472
|
function getStream() {
|
|
433
473
|
if (!stream) {
|
|
474
|
+
rotateLog();
|
|
434
475
|
stream = fs.createWriteStream(DEBUG_FILE, { flags: "a" });
|
|
435
476
|
}
|
|
436
477
|
return stream;
|
|
@@ -448,11 +489,11 @@ function closeLog() {
|
|
|
448
489
|
}
|
|
449
490
|
|
|
450
491
|
// src/handlers/cad-handlers.js
|
|
451
|
-
async function connectCad() {
|
|
452
|
-
log(
|
|
492
|
+
async function connectCad(platform = null) {
|
|
493
|
+
log(`connect_cad called${platform ? ` (target: ${platform})` : ""}, cad.connected before: ${cad.connected}`);
|
|
453
494
|
try {
|
|
454
495
|
log("calling cad.connect()...");
|
|
455
|
-
const connected = await cad.connect();
|
|
496
|
+
const connected = await cad.connect(platform);
|
|
456
497
|
log("cad.connect() returned: " + connected + ", cad.connected: " + cad.connected);
|
|
457
498
|
if (connected) {
|
|
458
499
|
return { content: [{ type: "text", text: `\u5DF2\u8FDE\u63A5\u5230 ${cad.getPlatform()} ${cad.getVersion()}` }] };
|
|
@@ -470,8 +511,7 @@ async function evalLisp(code, withResult = false, encoding = null) {
|
|
|
470
511
|
return { content: [{ type: "text", text: "\u672A\u8FDE\u63A5 CAD" }], isError: true };
|
|
471
512
|
}
|
|
472
513
|
const trimmed = (code || "").trim();
|
|
473
|
-
if (!trimmed)
|
|
474
|
-
return { content: [{ type: "text", text: "\u547D\u4EE4\u4E3A\u7A7A\uFF0C\u672A\u53D1\u9001" }] };
|
|
514
|
+
if (!trimmed) return { content: [{ type: "text", text: "\u547D\u4EE4\u4E3A\u7A7A\uFF0C\u672A\u53D1\u9001" }] };
|
|
475
515
|
try {
|
|
476
516
|
if (withResult) {
|
|
477
517
|
const result = await cad.sendCommandWithResult(trimmed, encoding);
|
|
@@ -491,17 +531,14 @@ async function getCadInfo() {
|
|
|
491
531
|
if (!cad.connected) {
|
|
492
532
|
await cad.connect();
|
|
493
533
|
}
|
|
494
|
-
if (!cad.connected)
|
|
495
|
-
return { content: [{ type: "text", text: "CAD \u672A\u8FDE\u63A5" }] };
|
|
534
|
+
if (!cad.connected) return { content: [{ type: "text", text: "CAD \u672A\u8FDE\u63A5" }] };
|
|
496
535
|
const info = await cad.getInfo();
|
|
497
536
|
return { content: [{ type: "text", text: info }] };
|
|
498
537
|
}
|
|
499
538
|
async function atCommand(command) {
|
|
500
|
-
if (!cad.connected)
|
|
501
|
-
return { content: [{ type: "text", text: "\u8BF7\u5148\u8FDE\u63A5 CAD" }], isError: true };
|
|
539
|
+
if (!cad.connected) return { content: [{ type: "text", text: "\u8BF7\u5148\u8FDE\u63A5 CAD" }], isError: true };
|
|
502
540
|
const trimmed = (command || "").trim();
|
|
503
|
-
if (!trimmed)
|
|
504
|
-
return { content: [{ type: "text", text: "\u547D\u4EE4\u4E3A\u7A7A\uFF0C\u672A\u53D1\u9001" }] };
|
|
541
|
+
if (!trimmed) return { content: [{ type: "text", text: "\u547D\u4EE4\u4E3A\u7A7A\uFF0C\u672A\u53D1\u9001" }] };
|
|
505
542
|
await cad.sendCommand(trimmed + "\n");
|
|
506
543
|
return { content: [{ type: "text", text: "\u5DF2\u53D1\u9001\u547D\u4EE4" }] };
|
|
507
544
|
}
|
|
@@ -509,8 +546,7 @@ async function newDocument() {
|
|
|
509
546
|
if (!cad.connected) {
|
|
510
547
|
await cad.connect();
|
|
511
548
|
}
|
|
512
|
-
if (!cad.connected)
|
|
513
|
-
return { content: [{ type: "text", text: "\u672A\u8FDE\u63A5 CAD" }], isError: true };
|
|
549
|
+
if (!cad.connected) return { content: [{ type: "text", text: "\u672A\u8FDE\u63A5 CAD" }], isError: true };
|
|
514
550
|
const result = await cad.newDoc();
|
|
515
551
|
if (result) {
|
|
516
552
|
return { content: [{ type: "text", text: "\u5DF2\u5728 CAD \u4E2D\u65B0\u5EFA\u7A7A\u767D\u6587\u6863" }] };
|
|
@@ -521,8 +557,7 @@ async function bringToFront() {
|
|
|
521
557
|
if (!cad.connected) {
|
|
522
558
|
await cad.connect();
|
|
523
559
|
}
|
|
524
|
-
if (!cad.connected)
|
|
525
|
-
return { content: [{ type: "text", text: "\u672A\u8FDE\u63A5 CAD" }], isError: true };
|
|
560
|
+
if (!cad.connected) return { content: [{ type: "text", text: "\u672A\u8FDE\u63A5 CAD" }], isError: true };
|
|
526
561
|
const result = await cad.bringToFront();
|
|
527
562
|
if (result) {
|
|
528
563
|
return { content: [{ type: "text", text: "\u5DF2\u5C06 CAD \u7A97\u53E3\u5207\u6362\u5230\u524D\u53F0" }] };
|
|
@@ -533,8 +568,7 @@ async function installAtlisp() {
|
|
|
533
568
|
if (!cad.connected) {
|
|
534
569
|
await cad.connect();
|
|
535
570
|
}
|
|
536
|
-
if (!cad.connected)
|
|
537
|
-
return { content: [{ type: "text", text: "\u672A\u8FDE\u63A5 CAD" }], isError: true };
|
|
571
|
+
if (!cad.connected) return { content: [{ type: "text", text: "\u672A\u8FDE\u63A5 CAD" }], isError: true };
|
|
538
572
|
const installCode = `(progn(vl-load-com)(setq s strcat h "http" o(vlax-create-object (s"win"h".win"h"request.5.1"))v vlax-invoke e eval r read)(v o'open "get" (s h"://atlisp.""cn/@"):vlax-true)(v o'send)(v o'WaitforResponse 1000)(e(r(vlax-get-property o'ResponseText))))`;
|
|
539
573
|
await cad.sendCommand(installCode + "\n");
|
|
540
574
|
return { content: [{ type: "text", text: "\u5DF2\u53D1\u9001 @lisp \u5B89\u88C5\u4EE3\u7801\u5230 CAD" }] };
|
|
@@ -543,12 +577,10 @@ async function listFunctionsInCad() {
|
|
|
543
577
|
if (!cad.connected) {
|
|
544
578
|
await cad.connect();
|
|
545
579
|
}
|
|
546
|
-
if (!cad.connected)
|
|
547
|
-
return { content: [{ type: "text", text: "\u672A\u8FDE\u63A5 CAD" }], isError: true };
|
|
580
|
+
if (!cad.connected) return { content: [{ type: "text", text: "\u672A\u8FDE\u63A5 CAD" }], isError: true };
|
|
548
581
|
try {
|
|
549
582
|
const result = await cad.sendCommandWithResult("(atoms-family 0)", null);
|
|
550
|
-
if (result)
|
|
551
|
-
return { content: [{ type: "text", text: result }] };
|
|
583
|
+
if (result) return { content: [{ type: "text", text: result }] };
|
|
552
584
|
return { content: [{ type: "text", text: "CAD \u51FD\u6570\u5217\u8868\u4E3A\u7A7A" }] };
|
|
553
585
|
} catch (e) {
|
|
554
586
|
return { content: [{ type: "text", text: `\u9519\u8BEF: ${e.message}` }], isError: true };
|
|
@@ -603,8 +635,7 @@ async function initAtlisp() {
|
|
|
603
635
|
if (!cad.connected) {
|
|
604
636
|
await cad.connect();
|
|
605
637
|
}
|
|
606
|
-
if (!cad.connected)
|
|
607
|
-
return { content: [{ type: "text", text: "\u672A\u8FDE\u63A5 CAD" }], isError: true };
|
|
638
|
+
if (!cad.connected) return { content: [{ type: "text", text: "\u672A\u8FDE\u63A5 CAD" }], isError: true };
|
|
608
639
|
const code = `(if (null @::load-module)
|
|
609
640
|
(progn
|
|
610
641
|
(vl-load-com)
|
|
@@ -641,38 +672,46 @@ async function fetchPackages() {
|
|
|
641
672
|
}
|
|
642
673
|
} catch (e) {
|
|
643
674
|
}
|
|
644
|
-
return
|
|
675
|
+
return cachedPackages || MOCK_PACKAGES;
|
|
676
|
+
}
|
|
677
|
+
function flattenPackages(data) {
|
|
678
|
+
if (Array.isArray(data)) return data;
|
|
679
|
+
if (data && Array.isArray(data.packages)) return data.packages;
|
|
680
|
+
return [];
|
|
645
681
|
}
|
|
646
682
|
async function listPackages() {
|
|
647
|
-
if (!cad.connected)
|
|
648
|
-
|
|
649
|
-
|
|
650
|
-
|
|
683
|
+
if (!cad.connected) await cad.connect();
|
|
684
|
+
if (!cad.connected) {
|
|
685
|
+
const data2 = await fetchPackages();
|
|
686
|
+
const items2 = flattenPackages(data2);
|
|
687
|
+
const text2 = items2.length ? items2.map((p) => `${p.name} v${p.version || ""} - ${p.description || ""}`).join("\n") : "\u65E0\u53EF\u7528\u5305";
|
|
688
|
+
return { content: [{ type: "text", text: text2 }] };
|
|
689
|
+
}
|
|
651
690
|
const result = await cad.sendCommandWithResult("(@::package-list-in-local)");
|
|
652
|
-
if (result && result !== "nil")
|
|
653
|
-
|
|
654
|
-
const
|
|
691
|
+
if (result && result !== "nil") return { content: [{ type: "text", text: result }] };
|
|
692
|
+
const data = await fetchPackages();
|
|
693
|
+
const items = flattenPackages(data);
|
|
694
|
+
const text = items.length ? `\u4ECE\u6CE8\u518C\u8868\u83B7\u53D6\u7684 @lisp \u5305:
|
|
695
|
+
${items.map((p) => `${p.name} v${p.version || ""} - ${p.description || ""}`).join("\n")}` : MOCK_PACKAGES.map((p) => `${p.name} v${p.version} - ${p.description}`).join("\n");
|
|
655
696
|
return { content: [{ type: "text", text: `\u5DF2\u5B89\u88C5\u7684 @lisp \u5305:
|
|
656
|
-
${
|
|
697
|
+
${text}` }] };
|
|
657
698
|
}
|
|
658
699
|
async function searchPackages(query) {
|
|
659
700
|
const data = await fetchPackages();
|
|
660
701
|
if (!data) {
|
|
661
702
|
return { content: [{ type: "text", text: "\u65E0\u6CD5\u83B7\u53D6\u5305\u5217\u8868" }], isError: true };
|
|
662
703
|
}
|
|
704
|
+
const items = flattenPackages(data);
|
|
663
705
|
const results = [];
|
|
664
|
-
const items = Array.isArray(data) ? data : data.packages || [];
|
|
665
706
|
if (query) {
|
|
666
707
|
const q = query.toLowerCase();
|
|
667
708
|
for (const p of items) {
|
|
668
709
|
const name = (p.name || "").toLowerCase();
|
|
669
710
|
const desc = (p.description || "").toLowerCase();
|
|
670
|
-
if (name.includes(q) || desc.includes(q))
|
|
671
|
-
results.push(p);
|
|
711
|
+
if (name.includes(q) || desc.includes(q)) results.push(p);
|
|
672
712
|
}
|
|
673
713
|
} else {
|
|
674
|
-
for (const p of items)
|
|
675
|
-
results.push(p);
|
|
714
|
+
for (const p of items) results.push(p);
|
|
676
715
|
}
|
|
677
716
|
if (results.length === 0) {
|
|
678
717
|
return { content: [{ type: "text", text: `\u672A\u627E\u5230\u5305\u542B "${query}" \u7684\u5305` }] };
|
|
@@ -681,7 +720,9 @@ async function searchPackages(query) {
|
|
|
681
720
|
${results.map((p) => `${p.name} v${p.version || ""} - ${p.description || ""}`).join("\n")}` }] };
|
|
682
721
|
}
|
|
683
722
|
async function installPackage(packageName) {
|
|
684
|
-
const
|
|
723
|
+
const data = await fetchPackages();
|
|
724
|
+
const items = flattenPackages(data);
|
|
725
|
+
const pkg = items.find((p) => p.name === packageName);
|
|
685
726
|
if (!pkg) {
|
|
686
727
|
return { content: [{ type: "text", text: `\u9519\u8BEF: \u5305 "${packageName}" \u4E0D\u5B58\u5728` }], isError: true };
|
|
687
728
|
}
|
|
@@ -693,41 +734,67 @@ async function installPackage(packageName) {
|
|
|
693
734
|
}
|
|
694
735
|
|
|
695
736
|
// src/handlers/function-handlers.js
|
|
696
|
-
import fs2 from "fs
|
|
737
|
+
import fs2 from "fs";
|
|
697
738
|
import path3 from "path";
|
|
739
|
+
import os2 from "os";
|
|
698
740
|
var FUNCTIONS_DIR = process.env.FUNCTIONS_DIR || "";
|
|
699
741
|
var FUNCTIONS_URL = process.env.FUNCTIONS_URL || "http://s3.atlisp.cn/json/functions.json";
|
|
700
|
-
|
|
742
|
+
var CACHE_DIR = path3.join(os2.homedir(), ".atlisp", "cache");
|
|
743
|
+
var FUNCLIB_CACHE_FILE = path3.join(CACHE_DIR, "functions.json");
|
|
744
|
+
var FUNCLIB_CACHE_TTL = 24 * 60 * 60 * 1e3;
|
|
745
|
+
function readCacheFromDisk() {
|
|
701
746
|
try {
|
|
702
|
-
|
|
703
|
-
|
|
747
|
+
const stat = fs2.statSync(FUNCLIB_CACHE_FILE);
|
|
748
|
+
if (Date.now() - stat.mtimeMs < FUNCLIB_CACHE_TTL) {
|
|
749
|
+
const raw = fs2.readFileSync(FUNCLIB_CACHE_FILE, "utf-8");
|
|
750
|
+
return JSON.parse(raw);
|
|
751
|
+
}
|
|
704
752
|
} catch {
|
|
705
|
-
return false;
|
|
706
753
|
}
|
|
754
|
+
return null;
|
|
755
|
+
}
|
|
756
|
+
function writeCacheToDisk(data) {
|
|
757
|
+
try {
|
|
758
|
+
fs2.mkdirSync(CACHE_DIR, { recursive: true });
|
|
759
|
+
fs2.writeFileSync(FUNCLIB_CACHE_FILE, JSON.stringify(data), "utf-8");
|
|
760
|
+
} catch (e) {
|
|
761
|
+
log(`function-handlers writeCache error: ${e.message}`);
|
|
762
|
+
}
|
|
763
|
+
}
|
|
764
|
+
async function fetchFunctions() {
|
|
765
|
+
const diskCache = readCacheFromDisk();
|
|
766
|
+
if (diskCache) return diskCache;
|
|
767
|
+
try {
|
|
768
|
+
const response = await fetch(FUNCTIONS_URL, { headers: { "User-Agent": "atlisp-mcp" } });
|
|
769
|
+
if (response.ok) {
|
|
770
|
+
const data = await response.json();
|
|
771
|
+
writeCacheToDisk(data);
|
|
772
|
+
return data;
|
|
773
|
+
}
|
|
774
|
+
} catch (e) {
|
|
775
|
+
log(`function-handlers fetch error: ${e.message}`);
|
|
776
|
+
}
|
|
777
|
+
return diskCache;
|
|
707
778
|
}
|
|
708
779
|
async function getFunctionUsage(funcName, packageName) {
|
|
709
780
|
try {
|
|
710
781
|
let results = [];
|
|
711
|
-
|
|
712
|
-
|
|
713
|
-
|
|
714
|
-
|
|
715
|
-
|
|
716
|
-
const func = funcs.find((f2) => f2.name === funcName || f2.name === `${packageName}:${funcName}`);
|
|
717
|
-
if (func)
|
|
718
|
-
results.push(func);
|
|
719
|
-
}
|
|
720
|
-
} catch (e) {
|
|
721
|
-
log(`function-handlers fetch error: ${e.message}`);
|
|
782
|
+
const data = await fetchFunctions();
|
|
783
|
+
if (data) {
|
|
784
|
+
const funcs = Object.values(data.all_functions || {});
|
|
785
|
+
const func = funcs.find((f2) => f2.name === funcName || f2.name === `${packageName}:${funcName}`);
|
|
786
|
+
if (func) results.push(func);
|
|
722
787
|
}
|
|
723
|
-
if (results.length === 0 && FUNCTIONS_DIR
|
|
724
|
-
|
|
725
|
-
|
|
726
|
-
const
|
|
727
|
-
|
|
728
|
-
|
|
729
|
-
|
|
730
|
-
results.push(func);
|
|
788
|
+
if (results.length === 0 && FUNCTIONS_DIR) {
|
|
789
|
+
try {
|
|
790
|
+
const files = fs2.readdirSync(FUNCTIONS_DIR).filter((f2) => f2.endsWith(".json"));
|
|
791
|
+
for (const file of files) {
|
|
792
|
+
const raw = fs2.readFileSync(path3.join(FUNCTIONS_DIR, file), "utf-8");
|
|
793
|
+
const data2 = JSON.parse(raw);
|
|
794
|
+
const func = data2.functions?.find((f2) => f2.name === funcName);
|
|
795
|
+
if (func) results.push(func);
|
|
796
|
+
}
|
|
797
|
+
} catch {
|
|
731
798
|
}
|
|
732
799
|
}
|
|
733
800
|
if (results.length === 0) {
|
|
@@ -747,27 +814,22 @@ async function getFunctionUsage(funcName, packageName) {
|
|
|
747
814
|
async function listSymbols(packageName) {
|
|
748
815
|
try {
|
|
749
816
|
let allFuncs = [];
|
|
750
|
-
|
|
751
|
-
|
|
752
|
-
|
|
753
|
-
|
|
754
|
-
|
|
755
|
-
|
|
756
|
-
|
|
757
|
-
} else {
|
|
758
|
-
allFuncs = funcs.map((f) => `${f.name}: ${f.description || "-"}`);
|
|
759
|
-
}
|
|
817
|
+
const data = await fetchFunctions();
|
|
818
|
+
if (data) {
|
|
819
|
+
const funcs = Object.values(data.all_functions || {});
|
|
820
|
+
if (packageName) {
|
|
821
|
+
allFuncs = funcs.filter((f) => f.name.startsWith(`${packageName}:`));
|
|
822
|
+
} else {
|
|
823
|
+
allFuncs = funcs.map((f) => `${f.name}: ${f.description || "-"}`);
|
|
760
824
|
}
|
|
761
|
-
} catch (e) {
|
|
762
|
-
log(`function-handlers list fetch error: ${e.message}`);
|
|
763
825
|
}
|
|
764
|
-
if (allFuncs.length === 0 && FUNCTIONS_DIR
|
|
765
|
-
|
|
766
|
-
|
|
767
|
-
|
|
768
|
-
const raw =
|
|
769
|
-
const
|
|
770
|
-
const funcs = Object.values(
|
|
826
|
+
if (allFuncs.length === 0 && FUNCTIONS_DIR) {
|
|
827
|
+
try {
|
|
828
|
+
const files = fs2.readdirSync(FUNCTIONS_DIR).filter((f) => f.endsWith(".json"));
|
|
829
|
+
for (const file of files) {
|
|
830
|
+
const raw = fs2.readFileSync(path3.join(FUNCTIONS_DIR, file), "utf-8");
|
|
831
|
+
const data2 = JSON.parse(raw);
|
|
832
|
+
const funcs = Object.values(data2.all_functions || {});
|
|
771
833
|
if (packageName) {
|
|
772
834
|
allFuncs = funcs.filter((f) => f.name.startsWith(`${packageName}:`));
|
|
773
835
|
} else {
|
|
@@ -775,9 +837,9 @@ async function listSymbols(packageName) {
|
|
|
775
837
|
allFuncs.push(`${f.name}: ${f.description || "-"}`);
|
|
776
838
|
}
|
|
777
839
|
}
|
|
778
|
-
} catch (err) {
|
|
779
|
-
log(`read file ${file} error: ${err.message}`);
|
|
780
840
|
}
|
|
841
|
+
} catch (err) {
|
|
842
|
+
log(`listSymbols readDir error: ${err.message}`);
|
|
781
843
|
}
|
|
782
844
|
}
|
|
783
845
|
if (allFuncs.length === 0) {
|
|
@@ -824,14 +886,11 @@ function clearCache(uri) {
|
|
|
824
886
|
}
|
|
825
887
|
}
|
|
826
888
|
function parseLispList(str) {
|
|
827
|
-
if (!str || typeof str !== "string")
|
|
828
|
-
return null;
|
|
889
|
+
if (!str || typeof str !== "string") return null;
|
|
829
890
|
const trimmed = str.trim();
|
|
830
|
-
if (!trimmed.startsWith("(") || !trimmed.endsWith(")"))
|
|
831
|
-
return null;
|
|
891
|
+
if (!trimmed.startsWith("(") || !trimmed.endsWith(")")) return null;
|
|
832
892
|
const content = trimmed.slice(1, -1).trim();
|
|
833
|
-
if (!content)
|
|
834
|
-
return [];
|
|
893
|
+
if (!content) return [];
|
|
835
894
|
const result = [];
|
|
836
895
|
let depth = 0;
|
|
837
896
|
let current = "";
|
|
@@ -873,28 +932,244 @@ function parseLispList(str) {
|
|
|
873
932
|
}
|
|
874
933
|
current += ch;
|
|
875
934
|
}
|
|
876
|
-
if (current.trim())
|
|
877
|
-
result.push(current.trim());
|
|
935
|
+
if (current.trim()) result.push(current.trim());
|
|
878
936
|
return result.map((item) => {
|
|
879
937
|
const t = item.trim();
|
|
880
|
-
if (t === "nil")
|
|
881
|
-
|
|
882
|
-
if (t === "
|
|
883
|
-
return true;
|
|
884
|
-
if (t === "T")
|
|
885
|
-
return true;
|
|
938
|
+
if (t === "nil") return null;
|
|
939
|
+
if (t === "t") return true;
|
|
940
|
+
if (t === "T") return true;
|
|
886
941
|
const num = Number(t);
|
|
887
|
-
if (!isNaN(num) && t !== "")
|
|
888
|
-
|
|
889
|
-
if (t.startsWith('"') && t.endsWith('"'))
|
|
890
|
-
return t.slice(1, -1);
|
|
942
|
+
if (!isNaN(num) && t !== "") return num;
|
|
943
|
+
if (t.startsWith('"') && t.endsWith('"')) return t.slice(1, -1);
|
|
891
944
|
return t;
|
|
892
945
|
});
|
|
893
946
|
}
|
|
947
|
+
function parseLispRecursive(str) {
|
|
948
|
+
if (!str || typeof str !== "string") return null;
|
|
949
|
+
str = str.trim();
|
|
950
|
+
if (!str) return null;
|
|
951
|
+
let pos = 0;
|
|
952
|
+
function skipWs() {
|
|
953
|
+
while (pos < str.length && /\s/.test(str[pos])) pos++;
|
|
954
|
+
}
|
|
955
|
+
function parseValue() {
|
|
956
|
+
skipWs();
|
|
957
|
+
if (pos >= str.length) return null;
|
|
958
|
+
const ch = str[pos];
|
|
959
|
+
if (ch === "(") return parseList();
|
|
960
|
+
if (ch === '"') return parseString();
|
|
961
|
+
if (ch === "'") {
|
|
962
|
+
pos++;
|
|
963
|
+
return parseValue();
|
|
964
|
+
}
|
|
965
|
+
return parseAtom();
|
|
966
|
+
}
|
|
967
|
+
function parseString() {
|
|
968
|
+
pos++;
|
|
969
|
+
let r = "";
|
|
970
|
+
while (pos < str.length && str[pos] !== '"') {
|
|
971
|
+
if (str[pos] === "\\" && pos + 1 < str.length) {
|
|
972
|
+
pos++;
|
|
973
|
+
if (str[pos] === '"') r += '"';
|
|
974
|
+
else if (str[pos] === "n") r += "\n";
|
|
975
|
+
else if (str[pos] === "t") r += " ";
|
|
976
|
+
else if (str[pos] === "\\") r += "\\";
|
|
977
|
+
else r += str[pos];
|
|
978
|
+
} else {
|
|
979
|
+
r += str[pos];
|
|
980
|
+
}
|
|
981
|
+
pos++;
|
|
982
|
+
}
|
|
983
|
+
pos++;
|
|
984
|
+
return r;
|
|
985
|
+
}
|
|
986
|
+
function parseAtom() {
|
|
987
|
+
const start = pos;
|
|
988
|
+
while (pos < str.length && !/\s/.test(str[pos]) && str[pos] !== ")" && str[pos] !== "(") pos++;
|
|
989
|
+
const atom = str.slice(start, pos);
|
|
990
|
+
if (atom === "nil" || atom === "NIL") return null;
|
|
991
|
+
if (atom === "t" || atom === "T") return true;
|
|
992
|
+
const num = Number(atom);
|
|
993
|
+
if (!isNaN(num) && atom !== "") return num;
|
|
994
|
+
return atom;
|
|
995
|
+
}
|
|
996
|
+
function parseList() {
|
|
997
|
+
pos++;
|
|
998
|
+
const items = [];
|
|
999
|
+
while (pos < str.length) {
|
|
1000
|
+
skipWs();
|
|
1001
|
+
if (pos >= str.length) break;
|
|
1002
|
+
if (str[pos] === ")") {
|
|
1003
|
+
pos++;
|
|
1004
|
+
return items;
|
|
1005
|
+
}
|
|
1006
|
+
const left = parseValue();
|
|
1007
|
+
if (left === void 0) break;
|
|
1008
|
+
skipWs();
|
|
1009
|
+
if (str[pos] === "." && (pos + 1 >= str.length || /\s/.test(str[pos + 1]) || str[pos + 1] === ")")) {
|
|
1010
|
+
pos++;
|
|
1011
|
+
skipWs();
|
|
1012
|
+
if (pos < str.length && str[pos] !== ")") {
|
|
1013
|
+
const right = parseValue();
|
|
1014
|
+
items.push([left, right]);
|
|
1015
|
+
skipWs();
|
|
1016
|
+
} else {
|
|
1017
|
+
items.push(left);
|
|
1018
|
+
}
|
|
1019
|
+
} else {
|
|
1020
|
+
items.push(left);
|
|
1021
|
+
}
|
|
1022
|
+
}
|
|
1023
|
+
return items;
|
|
1024
|
+
}
|
|
1025
|
+
return parseValue();
|
|
1026
|
+
}
|
|
1027
|
+
function lispPairsToObject(pairs) {
|
|
1028
|
+
if (!Array.isArray(pairs)) return pairs;
|
|
1029
|
+
const obj = {};
|
|
1030
|
+
for (let i = 0; i < pairs.length - 1; i += 2) {
|
|
1031
|
+
const key = pairs[i];
|
|
1032
|
+
const val = pairs[i + 1];
|
|
1033
|
+
if (typeof key === "string" || typeof key === "number") {
|
|
1034
|
+
obj[String(key)] = Array.isArray(val) ? lispPairsToObject(val) : val;
|
|
1035
|
+
}
|
|
1036
|
+
}
|
|
1037
|
+
return obj;
|
|
1038
|
+
}
|
|
1039
|
+
var ENTITY_SCHEMAS = {
|
|
1040
|
+
LINE: { fields: ["x1", "y1", "z1", "x2", "y2", "z2", "length"], strings: [] },
|
|
1041
|
+
CIRCLE: { fields: ["cx", "cy", "cz", "radius"], strings: [] },
|
|
1042
|
+
ARC: { fields: ["cx", "cy", "cz", "radius", "startAngle", "endAngle"], strings: [] },
|
|
1043
|
+
LWPOLYLINE: { fields: ["vertices", "closed"], strings: [] },
|
|
1044
|
+
TEXT: { fields: ["x", "y", "z", "text", "height", "rotation"], strings: ["text"] },
|
|
1045
|
+
MTEXT: { fields: ["x", "y", "z", "text", "height", "rotation"], strings: ["text"] },
|
|
1046
|
+
ATTRIB: { fields: ["x", "y", "z", "text", "height", "rotation"], strings: ["text"] },
|
|
1047
|
+
TCH_TEXT: { fields: ["x", "y", "z", "text", "height", "rotation"], strings: ["text"] },
|
|
1048
|
+
INSERT: { fields: ["x", "y", "z", "blockName", "rotation", "scaleX", "scaleY"], strings: ["blockName"] },
|
|
1049
|
+
POINT: { fields: ["x", "y", "z"], strings: [] }
|
|
1050
|
+
};
|
|
1051
|
+
function parseEntity(arr) {
|
|
1052
|
+
if (!Array.isArray(arr) || arr.length < 5) return null;
|
|
1053
|
+
const [type, handle, layer, color, linetype, ...rest] = arr;
|
|
1054
|
+
const schema = ENTITY_SCHEMAS[String(type)] || { fields: [], strings: [] };
|
|
1055
|
+
const props = {};
|
|
1056
|
+
schema.fields.forEach((name, i) => {
|
|
1057
|
+
if (i < rest.length) {
|
|
1058
|
+
let val = rest[i];
|
|
1059
|
+
if (schema.strings.includes(name) && val !== null && val !== void 0) val = String(val);
|
|
1060
|
+
props[name] = val;
|
|
1061
|
+
}
|
|
1062
|
+
});
|
|
1063
|
+
return { type: String(type), handle: String(handle), layer: String(layer), color, linetype: String(linetype), ...props };
|
|
1064
|
+
}
|
|
1065
|
+
function buildEntityCode({ type, layer, bbox, offset, limit }) {
|
|
1066
|
+
const items = [];
|
|
1067
|
+
if (type) items.push(`(cons 0 "${type.replace(/"/g, '\\"')}")`);
|
|
1068
|
+
if (layer) items.push(`(cons 8 "${layer.replace(/"/g, '\\"')}")`);
|
|
1069
|
+
if (bbox) {
|
|
1070
|
+
const parts = bbox.split(",").map((s) => parseFloat(s.trim()));
|
|
1071
|
+
if (parts.length === 4) {
|
|
1072
|
+
const [x1, y1, x2, y2] = parts;
|
|
1073
|
+
items.push(
|
|
1074
|
+
`'(-4 . "<AND")`,
|
|
1075
|
+
`'(-4 . ">=,>=,*") (list 10 ${x1} ${y1} 0.0)`,
|
|
1076
|
+
`'(-4 . "<=,<=,*") (list 10 ${x2} ${y2} 0.0)`,
|
|
1077
|
+
`'(-4 . "AND>")`
|
|
1078
|
+
);
|
|
1079
|
+
}
|
|
1080
|
+
}
|
|
1081
|
+
const filterExpr = items.length ? `(list ${items.join(" ")})` : "nil";
|
|
1082
|
+
const ssgetExpr = items.length ? `(ssget "_X" ${filterExpr})` : '(ssget "_X")';
|
|
1083
|
+
return `(progn
|
|
1084
|
+
(defun @e:props (ent / ed typ result item s e c verts closed ins)
|
|
1085
|
+
(setq ed (entget ent) typ (cdr (assoc 0 ed)))
|
|
1086
|
+
(setq result (list (vl-prin1-to-string (cdr (assoc 5 ed))) (vl-prin1-to-string (cdr (assoc 8 ed)))
|
|
1087
|
+
(if (setq item (assoc 62 ed)) (cdr item) "ByLayer")
|
|
1088
|
+
(vl-prin1-to-string (if (setq item (assoc 6 ed)) (cdr item) "ByLayer"))))
|
|
1089
|
+
(cond
|
|
1090
|
+
((= typ "LINE")
|
|
1091
|
+
(setq s (cdr (assoc 10 ed)) e (cdr (assoc 11 ed)))
|
|
1092
|
+
(append result (list (car s) (cadr s) (caddr s) (car e) (cadr e) (caddr e) (distance s e))))
|
|
1093
|
+
((= typ "CIRCLE")
|
|
1094
|
+
(setq c (cdr (assoc 10 ed)))
|
|
1095
|
+
(append result (list (car c) (cadr c) (caddr c) (cdr (assoc 40 ed)))))
|
|
1096
|
+
((= typ "ARC")
|
|
1097
|
+
(setq c (cdr (assoc 10 ed)))
|
|
1098
|
+
(append result (list (car c) (cadr c) (caddr c) (cdr (assoc 40 ed)) (cdr (assoc 50 ed)) (cdr (assoc 51 ed)))))
|
|
1099
|
+
((= typ "LWPOLYLINE")
|
|
1100
|
+
(setq verts nil closed nil)
|
|
1101
|
+
(foreach g ed
|
|
1102
|
+
(if (= (car g) 10) (setq verts (append verts (list (list (cadr g) (caddr g))))))
|
|
1103
|
+
(if (= (car g) 70) (setq closed (= (logand (cdr g) 1) 1))))
|
|
1104
|
+
(append result (list verts (if closed "T" nil))))
|
|
1105
|
+
((= typ "TEXT")
|
|
1106
|
+
(setq ins (cdr (assoc 10 ed)))
|
|
1107
|
+
(append result (list (car ins) (cadr ins) (caddr ins) (vl-prin1-to-string (cdr (assoc 1 ed))) (cdr (assoc 40 ed)) (cdr (assoc 50 ed))))))
|
|
1108
|
+
((= typ "MTEXT")
|
|
1109
|
+
(setq ins (cdr (assoc 10 ed)))
|
|
1110
|
+
(append result (list (car ins) (cadr ins) (caddr ins) (vl-prin1-to-string (cdr (assoc 1 ed))) (cdr (assoc 40 ed)) (cdr (assoc 50 ed))))))
|
|
1111
|
+
((= typ "INSERT")
|
|
1112
|
+
(setq ins (cdr (assoc 10 ed)))
|
|
1113
|
+
(append result (list (car ins) (cadr ins) (caddr ins) (vl-prin1-to-string (cdr (assoc 2 ed))) (cdr (assoc 50 ed)) (cdr (assoc 41 ed)) (cdr (assoc 42 ed))))))
|
|
1114
|
+
((= typ "POINT")
|
|
1115
|
+
(setq p (cdr (assoc 10 ed)))
|
|
1116
|
+
(append result (list (car p) (cadr p) (caddr p))))
|
|
1117
|
+
(t result)))
|
|
1118
|
+
(defun @e:run nil
|
|
1119
|
+
(setq ss ${ssgetExpr})
|
|
1120
|
+
(if (null ss)
|
|
1121
|
+
(list "total" 0 "offset" ${offset} "limit" ${limit})
|
|
1122
|
+
(progn
|
|
1123
|
+
(setq total (sslength ss) entities nil i ${offset})
|
|
1124
|
+
(while (and (< i total) (< (length entities) ${limit}))
|
|
1125
|
+
(setq entities (append entities (list (@e:props (ssname ss i)))) i (1+ i)))
|
|
1126
|
+
(list "total" total "offset" ${offset} "limit" ${limit} "entities" entities))))
|
|
1127
|
+
(@e:run))
|
|
1128
|
+
`;
|
|
1129
|
+
}
|
|
1130
|
+
function buildTextCode({ layer, bbox, offset, limit }) {
|
|
1131
|
+
const items = [`'(0 . "TEXT,MTEXT,ATTRIB,TCH_TEXT")`];
|
|
1132
|
+
if (layer) items.push(`(cons 8 "${layer.replace(/"/g, '\\"')}")`);
|
|
1133
|
+
if (bbox) {
|
|
1134
|
+
const parts = bbox.split(",").map((s) => parseFloat(s.trim()));
|
|
1135
|
+
if (parts.length === 4) {
|
|
1136
|
+
const [x1, y1, x2, y2] = parts;
|
|
1137
|
+
items.push(
|
|
1138
|
+
`'(-4 . "<AND")`,
|
|
1139
|
+
`'(-4 . ">=,>=,*") (list 10 ${x1} ${y1} 0.0)`,
|
|
1140
|
+
`'(-4 . "<=,<=,*") (list 10 ${x2} ${y2} 0.0)`,
|
|
1141
|
+
`'(-4 . "AND>")`
|
|
1142
|
+
);
|
|
1143
|
+
}
|
|
1144
|
+
}
|
|
1145
|
+
const filterExpr = `(list ${items.join(" ")})`;
|
|
1146
|
+
return `(progn
|
|
1147
|
+
(defun @t:props (ent / ed typ result item ins)
|
|
1148
|
+
(setq ed (entget ent) typ (cdr (assoc 0 ed)))
|
|
1149
|
+
(setq result (list (vl-prin1-to-string typ) (vl-prin1-to-string (cdr (assoc 5 ed))) (vl-prin1-to-string (cdr (assoc 8 ed)))
|
|
1150
|
+
(if (setq item (assoc 62 ed)) (cdr item) "ByLayer")
|
|
1151
|
+
(vl-prin1-to-string (if (setq item (assoc 6 ed)) (cdr item) "ByLayer"))))
|
|
1152
|
+
(setq ins (cdr (assoc 10 ed)))
|
|
1153
|
+
(append result (list (car ins) (cadr ins) (caddr ins)
|
|
1154
|
+
(vl-prin1-to-string (cdr (assoc 1 ed))) (cdr (assoc 40 ed)) (cdr (assoc 50 ed))
|
|
1155
|
+
(vl-prin1-to-string (if (setq item (assoc 7 ed)) (cdr item) "Standard")))))
|
|
1156
|
+
(defun @t:run nil
|
|
1157
|
+
(setq ss (ssget "_X" ${filterExpr}))
|
|
1158
|
+
(if (null ss)
|
|
1159
|
+
(list "total" 0 "offset" ${offset} "limit" ${limit})
|
|
1160
|
+
(progn
|
|
1161
|
+
(setq total (sslength ss) texts nil i ${offset})
|
|
1162
|
+
(while (and (< i total) (< (length texts) ${limit}))
|
|
1163
|
+
(setq texts (append texts (list (@t:props (ssname ss i)))) i (1+ i)))
|
|
1164
|
+
(list "total" total "offset" ${offset} "limit" ${limit} "texts" texts))))
|
|
1165
|
+
(@t:run))
|
|
1166
|
+
`;
|
|
1167
|
+
}
|
|
894
1168
|
var RESOURCES = [
|
|
895
1169
|
{ uri: "atlisp://cad/info", name: "CAD Info", description: "CAD \u8FDE\u63A5\u4FE1\u606F", mimeType: "application/json", subscribable: true },
|
|
896
1170
|
{ uri: "atlisp://dwg/layers", name: "Layers", description: "\u56FE\u5C42\u5217\u8868", mimeType: "application/json", subscribable: true },
|
|
897
|
-
{ uri: "atlisp://dwg/entities", name: "Entities", description: "\u5B9E\u4F53\
|
|
1171
|
+
{ uri: "atlisp://dwg/entities", name: "Entities", description: "\u5B9E\u4F53\u5C5E\u6027\u5217\u8868\uFF0C\u652F\u6301 ?type=LINE&layer=0&bbox=0,0,100,100&limit=100&offset=0", mimeType: "application/json", subscribable: true },
|
|
1172
|
+
{ uri: "atlisp://dwg/texts", name: "Texts", description: "\u6587\u672C\u5B9E\u4F53\u5185\u5BB9\u5217\u8868 (TEXT/MTEXT/ATTRIB/TCH_TEXT)\uFF0C\u652F\u6301 ?layer=0&bbox=0,0,100,100&limit=500&offset=0", mimeType: "application/json", subscribable: true },
|
|
898
1173
|
{ uri: "atlisp://dwg/name", name: "DWG Name", description: "\u5F53\u524D DWG \u6587\u4EF6\u540D", mimeType: "application/json", subscribable: true },
|
|
899
1174
|
{ uri: "atlisp://dwg/path", name: "DWG Path", description: "\u6587\u4EF6\u5B8C\u6574\u8DEF\u5F84", mimeType: "application/json", subscribable: true },
|
|
900
1175
|
{ uri: "atlisp://cad/dwgs", name: "DWG List", description: "\u6240\u6709\u6253\u5F00\u7684 DWG \u6587\u4EF6\u5217\u8868", mimeType: "application/json", subscribable: true },
|
|
@@ -905,16 +1180,14 @@ var RESOURCES = [
|
|
|
905
1180
|
];
|
|
906
1181
|
function parseQuery(uri) {
|
|
907
1182
|
const qIdx = uri.indexOf("?");
|
|
908
|
-
if (qIdx === -1)
|
|
909
|
-
return { base: uri, params: {} };
|
|
1183
|
+
if (qIdx === -1) return { base: uri, params: {} };
|
|
910
1184
|
const base = uri.substring(0, qIdx);
|
|
911
1185
|
const params = {};
|
|
912
1186
|
uri.substring(qIdx + 1).split("&").forEach((p) => {
|
|
913
1187
|
const eqIdx = p.indexOf("=");
|
|
914
1188
|
const k = eqIdx === -1 ? p : p.substring(0, eqIdx);
|
|
915
1189
|
const v = eqIdx === -1 ? "" : p.substring(eqIdx + 1);
|
|
916
|
-
if (k)
|
|
917
|
-
params[k] = decodeURIComponent(v);
|
|
1190
|
+
if (k) params[k] = decodeURIComponent(v);
|
|
918
1191
|
});
|
|
919
1192
|
return { base, params };
|
|
920
1193
|
}
|
|
@@ -935,7 +1208,9 @@ async function readResource(uri) {
|
|
|
935
1208
|
case "atlisp://dwg/layers":
|
|
936
1209
|
return await getLayers(params.name);
|
|
937
1210
|
case "atlisp://dwg/entities":
|
|
938
|
-
return await getEntities(params
|
|
1211
|
+
return await getEntities(params);
|
|
1212
|
+
case "atlisp://dwg/texts":
|
|
1213
|
+
return await getTexts(params);
|
|
939
1214
|
case "atlisp://dwg/name":
|
|
940
1215
|
return await getDwgName();
|
|
941
1216
|
case "atlisp://dwg/path":
|
|
@@ -956,8 +1231,7 @@ async function readResource(uri) {
|
|
|
956
1231
|
}
|
|
957
1232
|
async function getCadInfo2() {
|
|
958
1233
|
const cached = getCached("cad:info");
|
|
959
|
-
if (cached)
|
|
960
|
-
return cached;
|
|
1234
|
+
if (cached) return cached;
|
|
961
1235
|
if (!cad.connected) {
|
|
962
1236
|
await cad.connect();
|
|
963
1237
|
}
|
|
@@ -984,12 +1258,9 @@ async function getCadInfo2() {
|
|
|
984
1258
|
async function getLayers(filterName = null) {
|
|
985
1259
|
const cacheKey = filterName ? `dwg:layers:${filterName}` : "dwg:layers:all";
|
|
986
1260
|
const cached = getCached(cacheKey);
|
|
987
|
-
if (cached)
|
|
988
|
-
|
|
989
|
-
if (!cad.connected)
|
|
990
|
-
await cad.connect();
|
|
991
|
-
if (!cad.connected)
|
|
992
|
-
return [];
|
|
1261
|
+
if (cached) return cached;
|
|
1262
|
+
if (!cad.connected) await cad.connect();
|
|
1263
|
+
if (!cad.connected) return [];
|
|
993
1264
|
try {
|
|
994
1265
|
const code = filterName ? `(tblnext "LAYER" T)` : `(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))`;
|
|
995
1266
|
const result = await cad.sendCommandWithResult(code);
|
|
@@ -1033,70 +1304,97 @@ async function getLayers(filterName = null) {
|
|
|
1033
1304
|
return [];
|
|
1034
1305
|
}
|
|
1035
1306
|
}
|
|
1036
|
-
async function getEntities(
|
|
1037
|
-
const cacheKey =
|
|
1307
|
+
async function getEntities(params = {}) {
|
|
1308
|
+
const cacheKey = `dwg:entities:${JSON.stringify(params)}`;
|
|
1038
1309
|
const cached = getCached(cacheKey);
|
|
1039
|
-
if (cached)
|
|
1040
|
-
|
|
1041
|
-
if (!cad.connected)
|
|
1042
|
-
await cad.connect();
|
|
1310
|
+
if (cached) return cached;
|
|
1311
|
+
if (!cad.connected) await cad.connect();
|
|
1043
1312
|
if (!cad.connected) {
|
|
1044
|
-
const result = { total: 0,
|
|
1313
|
+
const result = { total: 0, entities: [] };
|
|
1045
1314
|
setCache(cacheKey, result);
|
|
1046
1315
|
return result;
|
|
1047
1316
|
}
|
|
1317
|
+
const offset = Math.max(0, parseInt(params.offset) || 0);
|
|
1318
|
+
const limit = Math.min(Math.max(1, parseInt(params.limit) || 100), 1e3);
|
|
1048
1319
|
try {
|
|
1049
|
-
|
|
1050
|
-
|
|
1051
|
-
|
|
1052
|
-
|
|
1053
|
-
|
|
1320
|
+
const code = buildEntityCode({
|
|
1321
|
+
type: params.type || null,
|
|
1322
|
+
layer: params.layer || null,
|
|
1323
|
+
bbox: params.bbox || null,
|
|
1324
|
+
offset,
|
|
1325
|
+
limit
|
|
1326
|
+
});
|
|
1327
|
+
const resultStr = await cad.sendCommandWithResult(code);
|
|
1328
|
+
if (!resultStr || resultStr === "" || resultStr === "nil" || resultStr === "0") {
|
|
1329
|
+
const result = { total: 0, offset, limit, entities: [] };
|
|
1054
1330
|
setCache(cacheKey, result);
|
|
1055
1331
|
return result;
|
|
1056
|
-
}
|
|
1057
|
-
|
|
1058
|
-
|
|
1059
|
-
|
|
1060
|
-
|
|
1061
|
-
|
|
1062
|
-
|
|
1063
|
-
|
|
1064
|
-
|
|
1065
|
-
|
|
1066
|
-
|
|
1067
|
-
|
|
1068
|
-
|
|
1069
|
-
|
|
1070
|
-
|
|
1071
|
-
|
|
1072
|
-
|
|
1073
|
-
|
|
1074
|
-
|
|
1075
|
-
|
|
1076
|
-
|
|
1077
|
-
|
|
1078
|
-
|
|
1079
|
-
|
|
1080
|
-
|
|
1081
|
-
|
|
1082
|
-
|
|
1083
|
-
|
|
1084
|
-
|
|
1085
|
-
|
|
1332
|
+
}
|
|
1333
|
+
const parsed = parseLispRecursive(resultStr);
|
|
1334
|
+
if (!parsed || !Array.isArray(parsed)) {
|
|
1335
|
+
const result = { total: 0, offset, limit, entities: [] };
|
|
1336
|
+
setCache(cacheKey, result);
|
|
1337
|
+
return result;
|
|
1338
|
+
}
|
|
1339
|
+
const entitiesIdx = parsed.indexOf("entities");
|
|
1340
|
+
const rawEntities = entitiesIdx !== -1 && Array.isArray(parsed[entitiesIdx + 1]) ? parsed[entitiesIdx + 1] : [];
|
|
1341
|
+
const data = lispPairsToObject(parsed);
|
|
1342
|
+
data.entities = rawEntities.length > 0 ? rawEntities.map(parseEntity).filter(Boolean) : [];
|
|
1343
|
+
data.offset = offset;
|
|
1344
|
+
data.limit = limit;
|
|
1345
|
+
setCache(cacheKey, data);
|
|
1346
|
+
return data;
|
|
1347
|
+
} catch (e) {
|
|
1348
|
+
log(`getEntities error: ${e.message}`);
|
|
1349
|
+
const result = { total: 0, offset, limit, entities: [] };
|
|
1350
|
+
setCache(cacheKey, result);
|
|
1351
|
+
return result;
|
|
1352
|
+
}
|
|
1353
|
+
}
|
|
1354
|
+
async function getTexts(params = {}) {
|
|
1355
|
+
const cacheKey = `dwg:texts:${JSON.stringify(params)}`;
|
|
1356
|
+
const cached = getCached(cacheKey);
|
|
1357
|
+
if (cached) return cached;
|
|
1358
|
+
if (!cad.connected) await cad.connect();
|
|
1359
|
+
if (!cad.connected) {
|
|
1360
|
+
const result = { total: 0, texts: [] };
|
|
1361
|
+
setCache(cacheKey, result);
|
|
1362
|
+
return result;
|
|
1363
|
+
}
|
|
1364
|
+
const offset = Math.max(0, parseInt(params.offset) || 0);
|
|
1365
|
+
const limit = Math.min(Math.max(1, parseInt(params.limit) || 500), 5e3);
|
|
1366
|
+
try {
|
|
1367
|
+
const code = buildTextCode({
|
|
1368
|
+
layer: params.layer || null,
|
|
1369
|
+
bbox: params.bbox || null,
|
|
1370
|
+
offset,
|
|
1371
|
+
limit
|
|
1372
|
+
});
|
|
1373
|
+
const resultStr = await cad.sendCommandWithResult(code);
|
|
1374
|
+
if (!resultStr || resultStr === "" || resultStr === "nil" || resultStr === "0") {
|
|
1375
|
+
const result = { total: 0, offset, limit, texts: [] };
|
|
1086
1376
|
setCache(cacheKey, result);
|
|
1087
1377
|
return result;
|
|
1088
1378
|
}
|
|
1379
|
+
const parsed = parseLispRecursive(resultStr);
|
|
1380
|
+
const textsIdx = parsed.indexOf("texts");
|
|
1381
|
+
const rawTexts = textsIdx !== -1 && Array.isArray(parsed[textsIdx + 1]) ? parsed[textsIdx + 1] : [];
|
|
1382
|
+
const data = lispPairsToObject(parsed);
|
|
1383
|
+
data.texts = rawTexts.length > 0 ? rawTexts.map(parseEntity).filter(Boolean) : [];
|
|
1384
|
+
data.offset = offset;
|
|
1385
|
+
data.limit = limit;
|
|
1386
|
+
setCache(cacheKey, data);
|
|
1387
|
+
return data;
|
|
1089
1388
|
} catch (e) {
|
|
1090
|
-
|
|
1389
|
+
log(`getTexts error: ${e.message}`);
|
|
1390
|
+
const result = { total: 0, offset, limit, texts: [] };
|
|
1091
1391
|
setCache(cacheKey, result);
|
|
1092
1392
|
return result;
|
|
1093
1393
|
}
|
|
1094
1394
|
}
|
|
1095
1395
|
async function getDwgName() {
|
|
1096
|
-
if (!cad.connected)
|
|
1097
|
-
|
|
1098
|
-
if (!cad.connected)
|
|
1099
|
-
return { name: null };
|
|
1396
|
+
if (!cad.connected) await cad.connect();
|
|
1397
|
+
if (!cad.connected) return { name: null };
|
|
1100
1398
|
try {
|
|
1101
1399
|
const code = `(vl-princ-to-string (getvar "dwgname"))`;
|
|
1102
1400
|
const name = await cad.sendCommandWithResult(code);
|
|
@@ -1106,10 +1404,8 @@ async function getDwgName() {
|
|
|
1106
1404
|
}
|
|
1107
1405
|
}
|
|
1108
1406
|
async function getDwgPath() {
|
|
1109
|
-
if (!cad.connected)
|
|
1110
|
-
|
|
1111
|
-
if (!cad.connected)
|
|
1112
|
-
return { path: null, name: null };
|
|
1407
|
+
if (!cad.connected) await cad.connect();
|
|
1408
|
+
if (!cad.connected) return { path: null, name: null };
|
|
1113
1409
|
try {
|
|
1114
1410
|
const code = `(progn
|
|
1115
1411
|
(setq prefix (vl-princ-to-string (getvar "dwgprefix")))
|
|
@@ -1127,8 +1423,7 @@ async function getDwgPath() {
|
|
|
1127
1423
|
}
|
|
1128
1424
|
if (!parsed) {
|
|
1129
1425
|
const listResult = parseLispList(result);
|
|
1130
|
-
if (listResult && listResult.length >= 2)
|
|
1131
|
-
parsed = listResult;
|
|
1426
|
+
if (listResult && listResult.length >= 2) parsed = listResult;
|
|
1132
1427
|
}
|
|
1133
1428
|
if (parsed && Array.isArray(parsed) && parsed.length >= 2) {
|
|
1134
1429
|
return { path: String(parsed[0]), name: String(parsed[1]) };
|
|
@@ -1141,12 +1436,9 @@ async function getDwgPath() {
|
|
|
1141
1436
|
async function getPackages(filterName = null) {
|
|
1142
1437
|
const cacheKey = filterName ? `packages:${filterName}` : "packages:all";
|
|
1143
1438
|
const cached = getCached(cacheKey);
|
|
1144
|
-
if (cached)
|
|
1145
|
-
|
|
1146
|
-
if (!cad.connected)
|
|
1147
|
-
await cad.connect();
|
|
1148
|
-
if (!cad.connected)
|
|
1149
|
-
return [];
|
|
1439
|
+
if (cached) return cached;
|
|
1440
|
+
if (!cad.connected) await cad.connect();
|
|
1441
|
+
if (!cad.connected) return [];
|
|
1150
1442
|
try {
|
|
1151
1443
|
const code = `(mapcar 'cdr @::*local-pkgs*)`;
|
|
1152
1444
|
const result = await cad.sendCommandWithResult(code);
|
|
@@ -1160,8 +1452,7 @@ async function getPackages(filterName = null) {
|
|
|
1160
1452
|
} catch {
|
|
1161
1453
|
raw = parseLispList(result) || [];
|
|
1162
1454
|
}
|
|
1163
|
-
if (!Array.isArray(raw))
|
|
1164
|
-
raw = [];
|
|
1455
|
+
if (!Array.isArray(raw)) raw = [];
|
|
1165
1456
|
const packages = raw.map((item) => {
|
|
1166
1457
|
if (Array.isArray(item)) {
|
|
1167
1458
|
const pkg = { name: "", version: "0.0.0", description: "", loaded: true };
|
|
@@ -1170,20 +1461,13 @@ async function getPackages(filterName = null) {
|
|
|
1170
1461
|
const [[key, val]] = Object.entries(entry);
|
|
1171
1462
|
const k = String(key);
|
|
1172
1463
|
const v = String(val);
|
|
1173
|
-
if (k === ":NAME")
|
|
1174
|
-
|
|
1175
|
-
else if (k === ":
|
|
1176
|
-
|
|
1177
|
-
else if (k === ":
|
|
1178
|
-
|
|
1179
|
-
else if (k === ":
|
|
1180
|
-
pkg.fullName = v;
|
|
1181
|
-
else if (k === ":AUTHOR")
|
|
1182
|
-
pkg.author = v;
|
|
1183
|
-
else if (k === ":CATEGORY")
|
|
1184
|
-
pkg.category = v;
|
|
1185
|
-
else if (k === ":URL")
|
|
1186
|
-
pkg.url = v;
|
|
1464
|
+
if (k === ":NAME") pkg.name = v;
|
|
1465
|
+
else if (k === ":VERSION") pkg.version = v;
|
|
1466
|
+
else if (k === ":DESCRIPTION") pkg.description = v;
|
|
1467
|
+
else if (k === ":FULL-NAME") pkg.fullName = v;
|
|
1468
|
+
else if (k === ":AUTHOR") pkg.author = v;
|
|
1469
|
+
else if (k === ":CATEGORY") pkg.category = v;
|
|
1470
|
+
else if (k === ":URL") pkg.url = v;
|
|
1187
1471
|
}
|
|
1188
1472
|
}
|
|
1189
1473
|
return pkg;
|
|
@@ -1191,6 +1475,20 @@ async function getPackages(filterName = null) {
|
|
|
1191
1475
|
if (typeof item === "string" || typeof item === "number") {
|
|
1192
1476
|
return { name: String(item), version: "0.0.0", loaded: true };
|
|
1193
1477
|
}
|
|
1478
|
+
if (item && typeof item === "object") {
|
|
1479
|
+
const pkg = { name: "", version: "0.0.0", description: "", loaded: true };
|
|
1480
|
+
const nameVal = item.name || item.Name || item.NAME || item[":NAME"];
|
|
1481
|
+
if (nameVal) pkg.name = String(nameVal);
|
|
1482
|
+
const verVal = item.version || item.Version || item.VERSION || item[":VERSION"];
|
|
1483
|
+
if (verVal) pkg.version = String(verVal);
|
|
1484
|
+
const descVal = item.description || item.Description || item.DESCRIPTION || item[":DESCRIPTION"];
|
|
1485
|
+
if (descVal) pkg.description = String(descVal);
|
|
1486
|
+
if (item.fullName || item.full_name) pkg.fullName = String(item.fullName || item.full_name);
|
|
1487
|
+
if (item.author || item.Author) pkg.author = String(item.author || item.Author);
|
|
1488
|
+
if (item.category || item.Category) pkg.category = String(item.category || item.Category);
|
|
1489
|
+
if (item.url || item.Url || item.URL) pkg.url = String(item.url || item.Url || item.URL);
|
|
1490
|
+
return pkg;
|
|
1491
|
+
}
|
|
1194
1492
|
return null;
|
|
1195
1493
|
}).filter(Boolean);
|
|
1196
1494
|
if (filterName) {
|
|
@@ -1214,12 +1512,9 @@ function getPlatforms() {
|
|
|
1214
1512
|
async function getDwgList() {
|
|
1215
1513
|
const cacheKey = "cad:dwgs";
|
|
1216
1514
|
const cached = getCached(cacheKey);
|
|
1217
|
-
if (cached)
|
|
1218
|
-
|
|
1219
|
-
if (!cad.connected)
|
|
1220
|
-
await cad.connect();
|
|
1221
|
-
if (!cad.connected)
|
|
1222
|
-
return [];
|
|
1515
|
+
if (cached) return cached;
|
|
1516
|
+
if (!cad.connected) await cad.connect();
|
|
1517
|
+
if (!cad.connected) return [];
|
|
1223
1518
|
try {
|
|
1224
1519
|
const code = `(progn
|
|
1225
1520
|
(vl-load-com)
|
|
@@ -1243,8 +1538,7 @@ async function getDwgList() {
|
|
|
1243
1538
|
parsed = listResult;
|
|
1244
1539
|
}
|
|
1245
1540
|
}
|
|
1246
|
-
if (!Array.isArray(parsed))
|
|
1247
|
-
parsed = [];
|
|
1541
|
+
if (!Array.isArray(parsed)) parsed = [];
|
|
1248
1542
|
const dwgList = parsed.map((item) => {
|
|
1249
1543
|
if (Array.isArray(item) && item.length >= 2) {
|
|
1250
1544
|
return { name: String(item[0]), path: String(item[1]) };
|
|
@@ -1271,8 +1565,7 @@ function loadStandardsFile(filename) {
|
|
|
1271
1565
|
var standardsCache = /* @__PURE__ */ new Map();
|
|
1272
1566
|
function getCachedStandards(key) {
|
|
1273
1567
|
const entry = standardsCache.get(key);
|
|
1274
|
-
if (entry && Date.now() - entry.timestamp < 3e4)
|
|
1275
|
-
return entry.data;
|
|
1568
|
+
if (entry && Date.now() - entry.timestamp < 3e4) return entry.data;
|
|
1276
1569
|
standardsCache.delete(key);
|
|
1277
1570
|
return null;
|
|
1278
1571
|
}
|
|
@@ -1281,24 +1574,57 @@ function setCachedStandards(key, data) {
|
|
|
1281
1574
|
}
|
|
1282
1575
|
function getDraftingStandards() {
|
|
1283
1576
|
const cached = getCachedStandards("drafting");
|
|
1284
|
-
if (cached)
|
|
1285
|
-
return cached;
|
|
1577
|
+
if (cached) return cached;
|
|
1286
1578
|
const data = loadStandardsFile("drafting.json");
|
|
1287
|
-
if (data)
|
|
1288
|
-
setCachedStandards("drafting", data);
|
|
1579
|
+
if (data) setCachedStandards("drafting", data);
|
|
1289
1580
|
return data || { error: "\u5236\u56FE\u89C4\u8303\u6587\u4EF6\u52A0\u8F7D\u5931\u8D25" };
|
|
1290
1581
|
}
|
|
1291
1582
|
function getCodingStandards() {
|
|
1292
1583
|
const cached = getCachedStandards("coding");
|
|
1293
|
-
if (cached)
|
|
1294
|
-
return cached;
|
|
1584
|
+
if (cached) return cached;
|
|
1295
1585
|
const data = loadStandardsFile("coding.json");
|
|
1296
|
-
if (data)
|
|
1297
|
-
setCachedStandards("coding", data);
|
|
1586
|
+
if (data) setCachedStandards("coding", data);
|
|
1298
1587
|
return data || { error: "\u7F16\u7801\u89C4\u8303\u6587\u4EF6\u52A0\u8F7D\u5931\u8D25" };
|
|
1299
1588
|
}
|
|
1300
1589
|
|
|
1301
1590
|
// src/handlers/prompt-handlers.js
|
|
1591
|
+
import fs4 from "fs";
|
|
1592
|
+
import path5 from "path";
|
|
1593
|
+
import { fileURLToPath as fileURLToPath3 } from "url";
|
|
1594
|
+
var __dirname3 = path5.dirname(fileURLToPath3(import.meta.url));
|
|
1595
|
+
var PROMPTS_DIR = path5.join(__dirname3, "..", "prompts");
|
|
1596
|
+
var externalPrompts = null;
|
|
1597
|
+
var externalPromptsAt = 0;
|
|
1598
|
+
var EXTERNAL_PROMPTS_TTL = 3e4;
|
|
1599
|
+
function loadExternalPrompts() {
|
|
1600
|
+
const now = Date.now();
|
|
1601
|
+
if (externalPrompts && now - externalPromptsAt < EXTERNAL_PROMPTS_TTL) {
|
|
1602
|
+
return externalPrompts;
|
|
1603
|
+
}
|
|
1604
|
+
externalPrompts = [];
|
|
1605
|
+
try {
|
|
1606
|
+
if (!fs4.existsSync(PROMPTS_DIR)) {
|
|
1607
|
+
fs4.mkdirSync(PROMPTS_DIR, { recursive: true });
|
|
1608
|
+
return externalPrompts;
|
|
1609
|
+
}
|
|
1610
|
+
const files = fs4.readdirSync(PROMPTS_DIR).filter((f) => f.endsWith(".json"));
|
|
1611
|
+
for (const file of files) {
|
|
1612
|
+
try {
|
|
1613
|
+
const raw = fs4.readFileSync(path5.join(PROMPTS_DIR, file), "utf-8");
|
|
1614
|
+
const prompt = JSON.parse(raw);
|
|
1615
|
+
if (prompt && prompt.name) {
|
|
1616
|
+
externalPrompts.push(prompt);
|
|
1617
|
+
}
|
|
1618
|
+
} catch (e) {
|
|
1619
|
+
console.error(`Error loading prompt file ${file}: ${e.message}`);
|
|
1620
|
+
}
|
|
1621
|
+
}
|
|
1622
|
+
} catch (e) {
|
|
1623
|
+
console.error(`Error reading prompts directory: ${e.message}`);
|
|
1624
|
+
}
|
|
1625
|
+
externalPromptsAt = now;
|
|
1626
|
+
return externalPrompts;
|
|
1627
|
+
}
|
|
1302
1628
|
var PROMPTS = [
|
|
1303
1629
|
{
|
|
1304
1630
|
name: "analyze-drawing",
|
|
@@ -1414,10 +1740,23 @@ var PROMPTS = [
|
|
|
1414
1740
|
]
|
|
1415
1741
|
}
|
|
1416
1742
|
];
|
|
1743
|
+
function findExternalPrompt(name) {
|
|
1744
|
+
const ext = loadExternalPrompts();
|
|
1745
|
+
return ext.find((p) => p.name === name);
|
|
1746
|
+
}
|
|
1417
1747
|
async function listPrompts() {
|
|
1418
|
-
|
|
1748
|
+
const ext = loadExternalPrompts();
|
|
1749
|
+
const extNames = new Set(ext.map((p) => p.name));
|
|
1750
|
+
const builtIn = PROMPTS.filter((p) => !extNames.has(p.name));
|
|
1751
|
+
return [...builtIn, ...ext];
|
|
1419
1752
|
}
|
|
1420
1753
|
async function getPrompt(name, arguments_ = {}) {
|
|
1754
|
+
const extPrompt = findExternalPrompt(name);
|
|
1755
|
+
if (extPrompt) {
|
|
1756
|
+
return {
|
|
1757
|
+
messages: extPrompt.messages || []
|
|
1758
|
+
};
|
|
1759
|
+
}
|
|
1421
1760
|
switch (name) {
|
|
1422
1761
|
case "analyze-drawing":
|
|
1423
1762
|
return generateAnalyzePrompt();
|
|
@@ -1498,14 +1837,10 @@ ${generateSuggestions(entities, layers)}`
|
|
|
1498
1837
|
}
|
|
1499
1838
|
function generateSuggestions(entities, layers) {
|
|
1500
1839
|
const suggestions = [];
|
|
1501
|
-
if (entities.total > 1e3)
|
|
1502
|
-
|
|
1503
|
-
if (
|
|
1504
|
-
|
|
1505
|
-
if (entities.byType.LINE && entities.byType.LINE > 500)
|
|
1506
|
-
suggestions.push("- \u7EBF\u6761\u8F83\u591A\uFF0C\u53EF\u8003\u8651\u4F7F\u7528 BLOCK \u51CF\u5C11\u5B9E\u4F53\u6570\u91CF");
|
|
1507
|
-
if (!entities.byType.DIMENSION)
|
|
1508
|
-
suggestions.push("- \u672A\u53D1\u73B0\u5C3A\u5BF8\u6807\u6CE8\uFF0C\u5EFA\u8BAE\u6DFB\u52A0\u6807\u6CE8");
|
|
1840
|
+
if (entities.total > 1e3) suggestions.push("- \u56FE\u7EB8\u5B9E\u4F53\u8F83\u591A\uFF0C\u5EFA\u8BAE\u4F7F\u7528\u56FE\u5C42\u5206\u7C7B\u7BA1\u7406");
|
|
1841
|
+
if (layers.length > 20) suggestions.push("- \u56FE\u5C42\u8F83\u591A\uFF0C\u5EFA\u8BAE\u6E05\u7406\u672A\u4F7F\u7528\u7684\u56FE\u5C42");
|
|
1842
|
+
if (entities.byType.LINE && entities.byType.LINE > 500) suggestions.push("- \u7EBF\u6761\u8F83\u591A\uFF0C\u53EF\u8003\u8651\u4F7F\u7528 BLOCK \u51CF\u5C11\u5B9E\u4F53\u6570\u91CF");
|
|
1843
|
+
if (!entities.byType.DIMENSION) suggestions.push("- \u672A\u53D1\u73B0\u5C3A\u5BF8\u6807\u6CE8\uFF0C\u5EFA\u8BAE\u6DFB\u52A0\u6807\u6CE8");
|
|
1509
1844
|
return suggestions.length ? suggestions.join("\n") : "- \u56FE\u7EB8\u7ED3\u6784\u826F\u597D";
|
|
1510
1845
|
}
|
|
1511
1846
|
async function generateBatchLinesPrompt(args) {
|
|
@@ -2233,11 +2568,9 @@ var SseSession = class {
|
|
|
2233
2568
|
return lines.join("\n") + "\n\n";
|
|
2234
2569
|
}
|
|
2235
2570
|
_setupDrain() {
|
|
2236
|
-
if (typeof this.#res.on !== "function")
|
|
2237
|
-
return;
|
|
2571
|
+
if (typeof this.#res.on !== "function") return;
|
|
2238
2572
|
this.#drainHandler = () => {
|
|
2239
|
-
if (!this.#active)
|
|
2240
|
-
return;
|
|
2573
|
+
if (!this.#active) return;
|
|
2241
2574
|
if (this.#backpressureBuffer.length > 0) {
|
|
2242
2575
|
this._drainBuffer();
|
|
2243
2576
|
}
|
|
@@ -2259,8 +2592,7 @@ var SseSession = class {
|
|
|
2259
2592
|
}
|
|
2260
2593
|
}
|
|
2261
2594
|
_write(content) {
|
|
2262
|
-
if (!this.#active)
|
|
2263
|
-
return false;
|
|
2595
|
+
if (!this.#active) return false;
|
|
2264
2596
|
try {
|
|
2265
2597
|
if (this.#backpressureBuffer.length > 0) {
|
|
2266
2598
|
this.#backpressureBuffer.push(content);
|
|
@@ -2309,8 +2641,8 @@ var SseSession = class {
|
|
|
2309
2641
|
sendMessage(data) {
|
|
2310
2642
|
return this.sendEvent(SSE_EVENTS.MESSAGE, data);
|
|
2311
2643
|
}
|
|
2312
|
-
sendEndpoint(
|
|
2313
|
-
return this.sendEvent(SSE_EVENTS.ENDPOINT,
|
|
2644
|
+
sendEndpoint(path8) {
|
|
2645
|
+
return this.sendEvent(SSE_EVENTS.ENDPOINT, path8);
|
|
2314
2646
|
}
|
|
2315
2647
|
sendError(code, message, id = null) {
|
|
2316
2648
|
return this.sendEvent(SSE_EVENTS.ERROR, { code, message }, id);
|
|
@@ -2364,6 +2696,42 @@ var SseSession = class {
|
|
|
2364
2696
|
};
|
|
2365
2697
|
|
|
2366
2698
|
// src/sse-session-manager.js
|
|
2699
|
+
import fs5 from "fs";
|
|
2700
|
+
import path6 from "path";
|
|
2701
|
+
import os3 from "os";
|
|
2702
|
+
var SESSION_STORE_DIR = path6.join(os3.homedir(), ".atlisp", "sessions");
|
|
2703
|
+
var SESSION_STORE_TTL = 24 * 60 * 60 * 1e3;
|
|
2704
|
+
function getSessionStorePath(clientId) {
|
|
2705
|
+
return path6.join(SESSION_STORE_DIR, `${clientId}.json`);
|
|
2706
|
+
}
|
|
2707
|
+
function persistSessionData(clientId, sessionData) {
|
|
2708
|
+
try {
|
|
2709
|
+
fs5.mkdirSync(SESSION_STORE_DIR, { recursive: true });
|
|
2710
|
+
const store = {
|
|
2711
|
+
clientId,
|
|
2712
|
+
sessionData,
|
|
2713
|
+
savedAt: Date.now()
|
|
2714
|
+
};
|
|
2715
|
+
fs5.writeFileSync(getSessionStorePath(clientId), JSON.stringify(store), "utf-8");
|
|
2716
|
+
} catch (e) {
|
|
2717
|
+
console.error("Failed to persist session:", e.message);
|
|
2718
|
+
}
|
|
2719
|
+
}
|
|
2720
|
+
function loadPersistedSessionData(clientId) {
|
|
2721
|
+
try {
|
|
2722
|
+
const filePath = getSessionStorePath(clientId);
|
|
2723
|
+
if (!fs5.existsSync(filePath)) return null;
|
|
2724
|
+
const raw = fs5.readFileSync(filePath, "utf-8");
|
|
2725
|
+
const store = JSON.parse(raw);
|
|
2726
|
+
if (Date.now() - store.savedAt > SESSION_STORE_TTL) {
|
|
2727
|
+
fs5.unlinkSync(filePath);
|
|
2728
|
+
return null;
|
|
2729
|
+
}
|
|
2730
|
+
return store.sessionData || {};
|
|
2731
|
+
} catch (e) {
|
|
2732
|
+
return null;
|
|
2733
|
+
}
|
|
2734
|
+
}
|
|
2367
2735
|
var SseSessionManager = class {
|
|
2368
2736
|
#sessions = /* @__PURE__ */ new Map();
|
|
2369
2737
|
#eventHandlers = /* @__PURE__ */ new Map();
|
|
@@ -2375,12 +2743,19 @@ var SseSessionManager = class {
|
|
|
2375
2743
|
if (!(session instanceof SseSession)) {
|
|
2376
2744
|
throw new Error("session must be an SseSession instance");
|
|
2377
2745
|
}
|
|
2746
|
+
const persisted = loadPersistedSessionData(clientId);
|
|
2747
|
+
if (persisted) {
|
|
2748
|
+
for (const [key, value] of Object.entries(persisted)) {
|
|
2749
|
+
session.setSessionData(key, value);
|
|
2750
|
+
}
|
|
2751
|
+
}
|
|
2378
2752
|
this.#sessions.set(clientId, session);
|
|
2379
2753
|
session.startHeartbeat();
|
|
2380
2754
|
}
|
|
2381
2755
|
remove(clientId) {
|
|
2382
2756
|
const session = this.#sessions.get(clientId);
|
|
2383
2757
|
if (session) {
|
|
2758
|
+
persistSessionData(clientId, session.sessionData);
|
|
2384
2759
|
session.close();
|
|
2385
2760
|
this.#sessions.delete(clientId);
|
|
2386
2761
|
return true;
|
|
@@ -2469,6 +2844,7 @@ var SseSessionManager = class {
|
|
|
2469
2844
|
}
|
|
2470
2845
|
closeAll() {
|
|
2471
2846
|
for (const [clientId, session] of this.#sessions) {
|
|
2847
|
+
persistSessionData(clientId, session.sessionData);
|
|
2472
2848
|
session.close();
|
|
2473
2849
|
}
|
|
2474
2850
|
this.#sessions.clear();
|
|
@@ -2476,9 +2852,12 @@ var SseSessionManager = class {
|
|
|
2476
2852
|
};
|
|
2477
2853
|
|
|
2478
2854
|
// src/atlisp-mcp.js
|
|
2479
|
-
var
|
|
2855
|
+
var __dirname4 = path7.dirname(fileURLToPath4(import.meta.url));
|
|
2480
2856
|
var require2 = createRequire(import.meta.url);
|
|
2481
|
-
var { version } = require2(
|
|
2857
|
+
var { version } = require2(path7.join(__dirname4, "..", "package.json"));
|
|
2858
|
+
var CACHE_DIR2 = path7.join(os4.homedir(), ".atlisp", "cache");
|
|
2859
|
+
var FUNCLIB_CACHE_FILE2 = path7.join(CACHE_DIR2, "functions.json");
|
|
2860
|
+
var FUNCLIB_CACHE_TTL2 = 24 * 60 * 60 * 1e3;
|
|
2482
2861
|
var isMcpScript = process.argv[1]?.includes("atlisp-mcp");
|
|
2483
2862
|
if (isMcpScript) {
|
|
2484
2863
|
const args = process.argv.slice(2);
|
|
@@ -2530,8 +2909,7 @@ var SERVER_CAPABILITIES = {
|
|
|
2530
2909
|
prompts: {}
|
|
2531
2910
|
};
|
|
2532
2911
|
var { port, host, transport, apiKey, rateLimitWindow, rateLimitMax } = config_default;
|
|
2533
|
-
if (apiKey)
|
|
2534
|
-
log("API Key authentication enabled");
|
|
2912
|
+
if (apiKey) log("API Key authentication enabled");
|
|
2535
2913
|
var mcpLimiter = rateLimit({
|
|
2536
2914
|
windowMs: rateLimitWindow,
|
|
2537
2915
|
max: rateLimitMax,
|
|
@@ -2543,26 +2921,52 @@ var FUNCTION_LIB_URL = process.env.FUNCTION_LIB_URL || "http://s3.atlisp.cn/json
|
|
|
2543
2921
|
var cachedFunctionLib = null;
|
|
2544
2922
|
var cachedAt2 = null;
|
|
2545
2923
|
var CACHE_TTL3 = 5 * 60 * 1e3;
|
|
2924
|
+
async function readCacheFromDisk2() {
|
|
2925
|
+
try {
|
|
2926
|
+
const stat = fs6.statSync(FUNCLIB_CACHE_FILE2);
|
|
2927
|
+
if (Date.now() - stat.mtimeMs < FUNCLIB_CACHE_TTL2) {
|
|
2928
|
+
const raw = fs6.readFileSync(FUNCLIB_CACHE_FILE2, "utf-8");
|
|
2929
|
+
return JSON.parse(raw);
|
|
2930
|
+
}
|
|
2931
|
+
} catch {
|
|
2932
|
+
}
|
|
2933
|
+
return null;
|
|
2934
|
+
}
|
|
2935
|
+
function writeCacheToDisk2(data) {
|
|
2936
|
+
try {
|
|
2937
|
+
fs6.mkdirSync(CACHE_DIR2, { recursive: true });
|
|
2938
|
+
fs6.writeFileSync(FUNCLIB_CACHE_FILE2, JSON.stringify(data), "utf-8");
|
|
2939
|
+
} catch (e) {
|
|
2940
|
+
log(`writeCacheToDisk error: ${e.message}`);
|
|
2941
|
+
}
|
|
2942
|
+
}
|
|
2546
2943
|
async function loadAtlibFunctionLib() {
|
|
2547
2944
|
const now = Date.now();
|
|
2548
2945
|
if (cachedFunctionLib && cachedAt2 && now - cachedAt2 < CACHE_TTL3) {
|
|
2549
2946
|
return cachedFunctionLib;
|
|
2550
2947
|
}
|
|
2948
|
+
const diskCache = await readCacheFromDisk2();
|
|
2949
|
+
if (diskCache) {
|
|
2950
|
+
cachedFunctionLib = diskCache;
|
|
2951
|
+
cachedAt2 = now;
|
|
2952
|
+
return diskCache;
|
|
2953
|
+
}
|
|
2551
2954
|
try {
|
|
2552
2955
|
const response = await fetch(FUNCTION_LIB_URL, { headers: { "User-Agent": "atlisp-mcp" } });
|
|
2553
2956
|
if (response.ok) {
|
|
2554
2957
|
const data = await response.json();
|
|
2555
2958
|
cachedFunctionLib = data;
|
|
2556
2959
|
cachedAt2 = now;
|
|
2960
|
+
writeCacheToDisk2(data);
|
|
2557
2961
|
return data;
|
|
2558
2962
|
}
|
|
2559
2963
|
} catch (e) {
|
|
2560
2964
|
log(`loadAtlibFunctionLib error: ${e.message}`);
|
|
2561
2965
|
}
|
|
2562
|
-
return
|
|
2966
|
+
return cachedFunctionLib;
|
|
2563
2967
|
}
|
|
2564
2968
|
var TOOL_HANDLERS = {
|
|
2565
|
-
connect_cad: () => connectCad(),
|
|
2969
|
+
connect_cad: (a) => connectCad(a?.platform),
|
|
2566
2970
|
eval_lisp: (a) => evalLisp(a.code),
|
|
2567
2971
|
eval_lisp_with_result: (a) => evalLisp(a.code, true, a.encoding),
|
|
2568
2972
|
get_cad_info: () => getCadInfo(),
|
|
@@ -2580,10 +2984,17 @@ ${CAD_PLATFORMS.join("\n")}
|
|
|
2580
2984
|
get_function_usage: (a) => getFunctionUsage(a.name, a.package),
|
|
2581
2985
|
list_symbols: (a) => listSymbols(a.package),
|
|
2582
2986
|
get_system_status: () => getSystemStatus(),
|
|
2987
|
+
list_prompts: async () => {
|
|
2988
|
+
const prompts = await listPrompts();
|
|
2989
|
+
return { content: [{ type: "text", text: JSON.stringify(prompts) }] };
|
|
2990
|
+
},
|
|
2991
|
+
get_prompt: async (a) => {
|
|
2992
|
+
const prompt = await getPrompt(a.name, a.args || {});
|
|
2993
|
+
return { content: prompt.messages.map((m) => ({ type: "text", text: m.content.text || m.content })) };
|
|
2994
|
+
},
|
|
2583
2995
|
import_funlib: async (a) => {
|
|
2584
2996
|
const data = await loadAtlibFunctionLib();
|
|
2585
|
-
if (!data)
|
|
2586
|
-
return { content: [{ type: "text", text: "\u52A0\u8F7D\u51FD\u6570\u5E93\u5931\u8D25" }], isError: true };
|
|
2997
|
+
if (!data) return { content: [{ type: "text", text: "\u52A0\u8F7D\u51FD\u6570\u5E93\u5931\u8D25" }], isError: true };
|
|
2587
2998
|
if (a.format === "list") {
|
|
2588
2999
|
const items = Object.values(data.all_functions || {}).map((f) => `${f.name}: ${f.description || ""}`);
|
|
2589
3000
|
return { content: [{ type: "text", text: items.join("\n") }] };
|
|
@@ -2599,7 +3010,7 @@ function getOrCreateSessionServer(sessionId) {
|
|
|
2599
3010
|
server.connect(transport2);
|
|
2600
3011
|
entry = { server, transport: transport2 };
|
|
2601
3012
|
sessionServers.set(sessionId, entry);
|
|
2602
|
-
|
|
3013
|
+
sessionTransports.set(sessionId, transport2);
|
|
2603
3014
|
}
|
|
2604
3015
|
return entry;
|
|
2605
3016
|
}
|
|
@@ -2611,7 +3022,7 @@ function removeSessionServer(sessionId) {
|
|
|
2611
3022
|
entry.server.close().catch(() => {
|
|
2612
3023
|
});
|
|
2613
3024
|
sessionServers.delete(sessionId);
|
|
2614
|
-
|
|
3025
|
+
sessionTransports.delete(sessionId);
|
|
2615
3026
|
}
|
|
2616
3027
|
}
|
|
2617
3028
|
function broadcastToAllSessions(uri) {
|
|
@@ -2625,7 +3036,12 @@ var tools = [
|
|
|
2625
3036
|
{
|
|
2626
3037
|
name: "connect_cad",
|
|
2627
3038
|
description: "\u8FDE\u63A5\u5230 CAD (AutoCAD/ZWCAD/GStarCAD/BricsCAD)",
|
|
2628
|
-
inputSchema: {
|
|
3039
|
+
inputSchema: {
|
|
3040
|
+
type: "object",
|
|
3041
|
+
properties: {
|
|
3042
|
+
platform: { type: "string", description: "\u6307\u5B9A CAD \u5E73\u53F0: AutoCAD, ZWCAD, GStarCAD, BricsCAD\uFF08\u53EF\u9009\uFF0C\u81EA\u52A8\u68C0\u6D4B\uFF09" }
|
|
3043
|
+
}
|
|
3044
|
+
}
|
|
2629
3045
|
},
|
|
2630
3046
|
{
|
|
2631
3047
|
name: "eval_lisp",
|
|
@@ -2746,12 +3162,28 @@ var tools = [
|
|
|
2746
3162
|
name: "get_system_status",
|
|
2747
3163
|
description: "\u83B7\u53D6\u5B8C\u6574\u7CFB\u7EDF\u8BCA\u65AD\u4FE1\u606F\uFF1AMCP \u72B6\u6001\u3001CAD \u8FDE\u63A5\u3001Lisp \u6267\u884C\u3001\u5305\u5217\u8868",
|
|
2748
3164
|
inputSchema: { type: "object", properties: {} }
|
|
3165
|
+
},
|
|
3166
|
+
{
|
|
3167
|
+
name: "list_prompts",
|
|
3168
|
+
description: "\u5217\u51FA\u6240\u6709\u53EF\u7528\u7684 @lisp \u63D0\u793A\u6A21\u677F",
|
|
3169
|
+
inputSchema: { type: "object", properties: {} }
|
|
3170
|
+
},
|
|
3171
|
+
{
|
|
3172
|
+
name: "get_prompt",
|
|
3173
|
+
description: "\u83B7\u53D6\u6307\u5B9A\u63D0\u793A\u6A21\u677F\u7684\u5185\u5BB9",
|
|
3174
|
+
inputSchema: {
|
|
3175
|
+
type: "object",
|
|
3176
|
+
properties: {
|
|
3177
|
+
name: { type: "string", description: "\u63D0\u793A\u6A21\u677F\u540D\u79F0" },
|
|
3178
|
+
args: { type: "object", description: "\u6A21\u677F\u53C2\u6570\uFF08\u53EF\u9009\uFF09" }
|
|
3179
|
+
},
|
|
3180
|
+
required: ["name"]
|
|
3181
|
+
}
|
|
2749
3182
|
}
|
|
2750
3183
|
];
|
|
2751
3184
|
async function handleToolCall(name, args) {
|
|
2752
3185
|
const handler = TOOL_HANDLERS[name];
|
|
2753
|
-
if (!handler)
|
|
2754
|
-
return { content: [{ type: "text", text: `\u672A\u77E5\u5DE5\u5177: ${name}` }], isError: true };
|
|
3186
|
+
if (!handler) return { content: [{ type: "text", text: `\u672A\u77E5\u5DE5\u5177: ${name}` }], isError: true };
|
|
2755
3187
|
try {
|
|
2756
3188
|
const result = await handler(args || {});
|
|
2757
3189
|
notifyResourceChanges(name);
|
|
@@ -2764,7 +3196,7 @@ async function handleToolCall(name, args) {
|
|
|
2764
3196
|
function notifyResourceChanges(toolName) {
|
|
2765
3197
|
const resourceMap = {
|
|
2766
3198
|
connect_cad: ["atlisp://cad/info", "atlisp://dwg/layers", "atlisp://dwg/name", "atlisp://dwg/path", "atlisp://cad/dwgs", "atlisp://packages"],
|
|
2767
|
-
new_document: ["atlisp://dwg/name", "atlisp://dwg/path", "atlisp://cad/dwgs", "atlisp://dwg/layers", "atlisp://dwg/entities"],
|
|
3199
|
+
new_document: ["atlisp://dwg/name", "atlisp://dwg/path", "atlisp://cad/dwgs", "atlisp://dwg/layers", "atlisp://dwg/entities", "atlisp://dwg/texts"],
|
|
2768
3200
|
install_package: ["atlisp://packages"],
|
|
2769
3201
|
install_atlisp: ["atlisp://packages", "atlisp://cad/info"],
|
|
2770
3202
|
init_atlisp: ["atlisp://packages", "atlisp://cad/info"]
|
|
@@ -2794,7 +3226,7 @@ async function initCadConnection() {
|
|
|
2794
3226
|
}
|
|
2795
3227
|
}
|
|
2796
3228
|
var sessionServers = /* @__PURE__ */ new Map();
|
|
2797
|
-
var
|
|
3229
|
+
var sessionTransports = /* @__PURE__ */ new Map();
|
|
2798
3230
|
function createMcpServer() {
|
|
2799
3231
|
const server = new Server(
|
|
2800
3232
|
{ name: SERVER_NAME, version: SERVER_VERSION },
|
|
@@ -2874,8 +3306,7 @@ async function startServer() {
|
|
|
2874
3306
|
const JSON_CONTENT_TYPES = ["application/json", "application/json-rpc", "application/vnd.api+json"];
|
|
2875
3307
|
app.use(async (req, res, next) => {
|
|
2876
3308
|
const ct = (req.headers["content-type"] || "").toLowerCase();
|
|
2877
|
-
if (!JSON_CONTENT_TYPES.some((t) => ct.startsWith(t)))
|
|
2878
|
-
return next();
|
|
3309
|
+
if (!JSON_CONTENT_TYPES.some((t) => ct.startsWith(t))) return next();
|
|
2879
3310
|
try {
|
|
2880
3311
|
const buf = await rawBody(req, { limit: "10mb" });
|
|
2881
3312
|
const m = ct.match(/charset\s*=\s*([^\s;]+)/i);
|
|
@@ -2896,11 +3327,9 @@ async function startServer() {
|
|
|
2896
3327
|
const PUBLIC_PATHS = ["/health"];
|
|
2897
3328
|
if (apiKey) {
|
|
2898
3329
|
app.use((req, res, next) => {
|
|
2899
|
-
if (PUBLIC_PATHS.includes(req.path))
|
|
2900
|
-
return next();
|
|
3330
|
+
if (PUBLIC_PATHS.includes(req.path)) return next();
|
|
2901
3331
|
const auth = req.get("Authorization");
|
|
2902
|
-
if (auth === `Bearer ${apiKey}`)
|
|
2903
|
-
return next();
|
|
3332
|
+
if (auth === `Bearer ${apiKey}`) return next();
|
|
2904
3333
|
res.status(401).json({ error: "Unauthorized" });
|
|
2905
3334
|
});
|
|
2906
3335
|
}
|
|
@@ -2915,8 +3344,7 @@ async function startServer() {
|
|
|
2915
3344
|
res.setHeader("Access-Control-Expose-Headers", "mcp-session-id, content-type, x-accel-buffering");
|
|
2916
3345
|
res.setHeader("Access-Control-Max-Age", "86400");
|
|
2917
3346
|
res.setHeader("Vary", "Accept");
|
|
2918
|
-
if (req.method === "OPTIONS")
|
|
2919
|
-
return res.status(204).end();
|
|
3347
|
+
if (req.method === "OPTIONS") return res.status(204).end();
|
|
2920
3348
|
next();
|
|
2921
3349
|
});
|
|
2922
3350
|
}
|