@atlisp/mcp 1.5.1 → 1.5.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 +1855 -1975
- package/package.json +1 -1
package/dist/atlisp-mcp.js
CHANGED
|
@@ -1,43 +1,62 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
};
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
2
|
+
|
|
3
|
+
// src/atlisp-mcp.js
|
|
4
|
+
import path8 from "path";
|
|
5
|
+
import { fileURLToPath as fileURLToPath4 } from "url";
|
|
6
|
+
import { createRequire } from "module";
|
|
7
|
+
import express2 from "express";
|
|
8
|
+
import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
|
|
9
|
+
|
|
10
|
+
// src/cad.js
|
|
11
|
+
import { spawn } from "child_process";
|
|
12
|
+
import path from "path";
|
|
13
|
+
import { fileURLToPath } from "url";
|
|
14
|
+
import { randomUUID } from "crypto";
|
|
11
15
|
|
|
12
16
|
// src/constants.js
|
|
13
|
-
var CAD_PLATFORMS
|
|
14
|
-
var
|
|
15
|
-
"
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
{ name: "tips", description: "\u6BCF\u65E5\u63D0\u793A", version: "1.0.0" },
|
|
34
|
-
{ name: "function", description: "\u51FD\u6570\u5E93", version: "3.0.0" }
|
|
35
|
-
];
|
|
36
|
-
}
|
|
37
|
-
});
|
|
17
|
+
var CAD_PLATFORMS = ["AutoCAD", "ZWCAD", "GStarCAD", "BricsCAD"];
|
|
18
|
+
var FILE_EXTENSIONS = {
|
|
19
|
+
"AutoCAD": [".fas", ".vlx"],
|
|
20
|
+
"ZWCAD": [".zelx", ".vls"],
|
|
21
|
+
"GStarCAD": [".fas", ".vlx"],
|
|
22
|
+
"BricsCAD": [".des"]
|
|
23
|
+
};
|
|
24
|
+
var SERVER_NAME = "atlisp-mcp-server";
|
|
25
|
+
var SERVER_VERSION = "1.5.0";
|
|
26
|
+
var MOCK_PACKAGES = [
|
|
27
|
+
{ name: "base", description: "\u57FA\u7840\u51FD\u6570\u5E93", version: "1.0.0" },
|
|
28
|
+
{ name: "at-pm", description: "\u5DE5\u7A0B\u9879\u76EE\u7BA1\u7406", version: "2.1.0" },
|
|
29
|
+
{ name: "network", description: "\u7F51\u7EDC\u529F\u80FD\u6A21\u5757", version: "1.5.0" },
|
|
30
|
+
{ name: "userman", description: "\u7528\u6237\u7BA1\u7406", version: "1.2.0" },
|
|
31
|
+
{ name: "pkgman", description: "\u5305\u7BA1\u7406\u5668", version: "2.0.0" },
|
|
32
|
+
{ name: "sidebar", description: "\u4FA7\u8FB9\u680F\u5DE5\u5177", version: "1.0.0" },
|
|
33
|
+
{ name: "aibot", description: "AI \u52A9\u624B", version: "0.9.0" },
|
|
34
|
+
{ name: "tips", description: "\u6BCF\u65E5\u63D0\u793A", version: "1.0.0" },
|
|
35
|
+
{ name: "function", description: "\u51FD\u6570\u5E93", version: "3.0.0" }
|
|
36
|
+
];
|
|
38
37
|
|
|
39
38
|
// src/config.js
|
|
40
39
|
import { z } from "zod";
|
|
40
|
+
var envSchema = z.object({
|
|
41
|
+
PORT: z.string().optional().default("8110"),
|
|
42
|
+
HOST: z.string().optional().default("0.0.0.0"),
|
|
43
|
+
TRANSPORT: z.enum(["http", "stdio"]).optional().default("http"),
|
|
44
|
+
MCP_API_KEY: z.string().optional().default(""),
|
|
45
|
+
ENABLE_SSE: z.string().optional().default("true"),
|
|
46
|
+
MESSAGE_TIMEOUT: z.string().optional().default("60000"),
|
|
47
|
+
HEARTBEAT_INTERVAL: z.string().optional().default("30000"),
|
|
48
|
+
BUSY_RETRIES: z.string().optional().default("10"),
|
|
49
|
+
BUSY_DELAY: z.string().optional().default("500"),
|
|
50
|
+
ENABLE_CORS: z.string().optional().default("true"),
|
|
51
|
+
CORS_ORIGIN: z.string().optional().default("*"),
|
|
52
|
+
RATE_LIMIT_WINDOW: z.string().optional().default("60000"),
|
|
53
|
+
RATE_LIMIT_MAX: z.string().optional().default("100"),
|
|
54
|
+
RESOURCE_CACHE_TTL: z.string().optional().default("5000"),
|
|
55
|
+
FUNCTION_LIB_CACHE_TTL: z.string().optional().default("300000"),
|
|
56
|
+
DEBUG: z.string().optional().default("false"),
|
|
57
|
+
DEBUG_FILE: z.string().optional().default(""),
|
|
58
|
+
FUNCTION_LIB_URL: z.string().optional().default("http://s3.atlisp.cn/json/functions.json")
|
|
59
|
+
});
|
|
41
60
|
function parseArgs() {
|
|
42
61
|
const args = process.argv.slice(2);
|
|
43
62
|
const result = { transport: "http", port: "8110", host: "0.0.0.0" };
|
|
@@ -57,65 +76,50 @@ function parseArgs() {
|
|
|
57
76
|
}
|
|
58
77
|
return result;
|
|
59
78
|
}
|
|
60
|
-
var
|
|
61
|
-
var
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
}
|
|
89
|
-
env = envResult.data;
|
|
90
|
-
config = {
|
|
91
|
-
port: parseInt(env.PORT || cliArgs.port, 10),
|
|
92
|
-
host: env.HOST || cliArgs.host,
|
|
93
|
-
transport: process.env.TRANSPORT ? env.TRANSPORT : cliArgs.transport,
|
|
94
|
-
apiKey: env.MCP_API_KEY,
|
|
95
|
-
enableSse: env.ENABLE_SSE === "true",
|
|
96
|
-
messageTimeout: parseInt(env.MESSAGE_TIMEOUT, 10),
|
|
97
|
-
heartbeatInterval: parseInt(env.HEARTBEAT_INTERVAL, 10),
|
|
98
|
-
busyRetries: parseInt(env.BUSY_RETRIES, 10),
|
|
99
|
-
busyDelay: parseInt(env.BUSY_DELAY, 10),
|
|
100
|
-
enableCors: env.ENABLE_CORS === "true",
|
|
101
|
-
corsOrigin: env.CORS_ORIGIN,
|
|
102
|
-
rateLimitWindow: parseInt(env.RATE_LIMIT_WINDOW, 10),
|
|
103
|
-
rateLimitMax: parseInt(env.RATE_LIMIT_MAX, 10),
|
|
104
|
-
resourceCacheTtl: parseInt(env.RESOURCE_CACHE_TTL, 10),
|
|
105
|
-
functionLibCacheTtl: parseInt(env.FUNCTION_LIB_CACHE_TTL, 10),
|
|
106
|
-
debug: env.DEBUG === "true",
|
|
107
|
-
debugFile: env.DEBUG_FILE,
|
|
108
|
-
functionLibUrl: env.FUNCTION_LIB_URL
|
|
109
|
-
};
|
|
110
|
-
config_default = config;
|
|
111
|
-
}
|
|
112
|
-
});
|
|
79
|
+
var cliArgs = parseArgs();
|
|
80
|
+
var envResult = envSchema.safeParse(process.env);
|
|
81
|
+
if (!envResult.success) {
|
|
82
|
+
console.error("\u73AF\u5883\u53D8\u91CF\u914D\u7F6E\u9519\u8BEF:", envResult.error.flatten().fieldErrors);
|
|
83
|
+
process.exit(1);
|
|
84
|
+
}
|
|
85
|
+
var env = envResult.data;
|
|
86
|
+
var config = {
|
|
87
|
+
port: parseInt(env.PORT || cliArgs.port, 10),
|
|
88
|
+
host: env.HOST || cliArgs.host,
|
|
89
|
+
transport: process.env.TRANSPORT && env.TRANSPORT ? env.TRANSPORT : cliArgs.transport,
|
|
90
|
+
apiKey: env.MCP_API_KEY,
|
|
91
|
+
enableSse: env.ENABLE_SSE === "true",
|
|
92
|
+
messageTimeout: parseInt(env.MESSAGE_TIMEOUT, 10),
|
|
93
|
+
heartbeatInterval: parseInt(env.HEARTBEAT_INTERVAL, 10),
|
|
94
|
+
busyRetries: parseInt(env.BUSY_RETRIES, 10),
|
|
95
|
+
busyDelay: parseInt(env.BUSY_DELAY, 10),
|
|
96
|
+
enableCors: env.ENABLE_CORS === "true",
|
|
97
|
+
corsOrigin: env.CORS_ORIGIN,
|
|
98
|
+
rateLimitWindow: parseInt(env.RATE_LIMIT_WINDOW, 10),
|
|
99
|
+
rateLimitMax: parseInt(env.RATE_LIMIT_MAX, 10),
|
|
100
|
+
resourceCacheTtl: parseInt(env.RESOURCE_CACHE_TTL, 10),
|
|
101
|
+
functionLibCacheTtl: parseInt(env.FUNCTION_LIB_CACHE_TTL, 10),
|
|
102
|
+
debug: env.DEBUG === "true",
|
|
103
|
+
debugFile: env.DEBUG_FILE,
|
|
104
|
+
functionLibUrl: env.FUNCTION_LIB_URL
|
|
105
|
+
};
|
|
106
|
+
var config_default = config;
|
|
113
107
|
|
|
114
108
|
// src/cad.js
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
109
|
+
var MESSAGE_TIMEOUT = config_default.messageTimeout;
|
|
110
|
+
var HEARTBEAT_INTERVAL = config_default.heartbeatInterval;
|
|
111
|
+
var MAX_RESTART_ATTEMPTS = 5;
|
|
112
|
+
var RESTART_BACKOFF_BASE = 1e3;
|
|
113
|
+
var __dirname = path.dirname(fileURLToPath(import.meta.url));
|
|
114
|
+
var workerPath = path.join(__dirname, "cad-worker.js");
|
|
115
|
+
var worker = null;
|
|
116
|
+
var _platform = null;
|
|
117
|
+
var heartbeatTimer = null;
|
|
118
|
+
var pendingRequests = /* @__PURE__ */ new Map();
|
|
119
|
+
var stdoutHandlerSetup = false;
|
|
120
|
+
var MAX_BUFFER_SIZE = 1024 * 1024;
|
|
121
|
+
var restartCount = 0;
|
|
122
|
+
var restartTimer = null;
|
|
119
123
|
function resetWorker() {
|
|
120
124
|
for (const [id, { reject, timeout }] of pendingRequests) {
|
|
121
125
|
clearTimeout(timeout);
|
|
@@ -255,142 +259,125 @@ function sendMessage(msg) {
|
|
|
255
259
|
}
|
|
256
260
|
});
|
|
257
261
|
}
|
|
258
|
-
var
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
constructor() {
|
|
279
|
-
this.connected = false;
|
|
280
|
-
this.version = null;
|
|
281
|
-
this.product = null;
|
|
282
|
-
}
|
|
283
|
-
isAvailable() {
|
|
284
|
-
return process.platform === "win32";
|
|
285
|
-
}
|
|
286
|
-
async connect(platform = null) {
|
|
287
|
-
if (!this.isAvailable()) return false;
|
|
288
|
-
try {
|
|
289
|
-
const msg = platform ? { type: "connect", platform } : { type: "connect" };
|
|
290
|
-
const result = await sendMessage(msg);
|
|
291
|
-
if (result && result.success) {
|
|
292
|
-
this.version = result.version;
|
|
293
|
-
this.product = result.platform;
|
|
294
|
-
_platform = result.platform;
|
|
295
|
-
this.connected = true;
|
|
296
|
-
return true;
|
|
297
|
-
}
|
|
298
|
-
} catch (e) {
|
|
299
|
-
console.error("CAD connect error:", e.message);
|
|
300
|
-
}
|
|
301
|
-
return false;
|
|
302
|
-
}
|
|
303
|
-
async sendCommand(code) {
|
|
304
|
-
if (!this.connected) throw new Error("\u672A\u8FDE\u63A5 CAD");
|
|
305
|
-
const result = await sendMessage({ type: "send", code, platform: _platform });
|
|
306
|
-
if (result.success) return true;
|
|
307
|
-
throw new Error(result.error || "\u53D1\u9001\u5931\u8D25");
|
|
308
|
-
}
|
|
309
|
-
async sendCommandWithResult(code, encoding = null) {
|
|
310
|
-
if (!this.connected) throw new Error("\u672A\u8FDE\u63A5 CAD");
|
|
311
|
-
const result = await sendMessage({ type: "sendResult", code, platform: _platform, encoding: encoding || "" });
|
|
312
|
-
if (result.success) {
|
|
313
|
-
return result.result || "";
|
|
314
|
-
}
|
|
315
|
-
throw new Error(result.error || "\u53D1\u9001\u5931\u8D25");
|
|
316
|
-
}
|
|
317
|
-
getVersion() {
|
|
318
|
-
return this.version;
|
|
319
|
-
}
|
|
320
|
-
getPlatform() {
|
|
321
|
-
return this.product;
|
|
322
|
-
}
|
|
323
|
-
async isBusy() {
|
|
324
|
-
if (!this.connected) return false;
|
|
325
|
-
try {
|
|
326
|
-
const result = await sendMessage({ type: "isBusy", platform: _platform });
|
|
327
|
-
return result && result.isBusy;
|
|
328
|
-
} catch (e) {
|
|
329
|
-
return false;
|
|
330
|
-
}
|
|
331
|
-
}
|
|
332
|
-
async hasDoc() {
|
|
333
|
-
if (!this.connected) return { hasDoc: false, docCount: 0 };
|
|
334
|
-
try {
|
|
335
|
-
const result = await sendMessage({ type: "hasdoc", platform: _platform });
|
|
336
|
-
return result || { hasDoc: false, docCount: 0 };
|
|
337
|
-
} catch (e) {
|
|
338
|
-
return { hasDoc: false, docCount: 0 };
|
|
339
|
-
}
|
|
340
|
-
}
|
|
341
|
-
async newDoc() {
|
|
342
|
-
if (!this.connected) throw new Error("\u672A\u8FDE\u63A5 CAD");
|
|
343
|
-
try {
|
|
344
|
-
const result = await sendMessage({ type: "newdoc", platform: _platform });
|
|
345
|
-
return result && result.success;
|
|
346
|
-
} catch (e) {
|
|
347
|
-
return false;
|
|
348
|
-
}
|
|
349
|
-
}
|
|
350
|
-
async bringToFront() {
|
|
351
|
-
if (!this.connected) throw new Error("\u672A\u8FDE\u63A5 CAD");
|
|
352
|
-
try {
|
|
353
|
-
const result = await sendMessage({ type: "bringToFront", platform: _platform });
|
|
354
|
-
return result && result.success;
|
|
355
|
-
} catch (e) {
|
|
356
|
-
return false;
|
|
357
|
-
}
|
|
358
|
-
}
|
|
359
|
-
async getInfo() {
|
|
360
|
-
if (!this.connected) return "CAD \u672A\u8FDE\u63A5";
|
|
361
|
-
return `Platform: ${this.product}, Version: ${this.version}, Status: Connected`;
|
|
362
|
-
}
|
|
363
|
-
async disconnect() {
|
|
364
|
-
this.connected = false;
|
|
365
|
-
this.version = null;
|
|
366
|
-
this.product = null;
|
|
367
|
-
_platform = null;
|
|
368
|
-
resetWorker();
|
|
369
|
-
}
|
|
370
|
-
async ping() {
|
|
371
|
-
try {
|
|
372
|
-
const result = await sendMessage({ type: "ping" });
|
|
373
|
-
return result && result.pong;
|
|
374
|
-
} catch (e) {
|
|
375
|
-
return false;
|
|
376
|
-
}
|
|
377
|
-
}
|
|
378
|
-
_reset() {
|
|
379
|
-
this.connected = false;
|
|
380
|
-
this.version = null;
|
|
381
|
-
this.product = null;
|
|
382
|
-
_platform = null;
|
|
383
|
-
resetWorker();
|
|
262
|
+
var CadConnection = class {
|
|
263
|
+
constructor() {
|
|
264
|
+
this.connected = false;
|
|
265
|
+
this.version = null;
|
|
266
|
+
this.product = null;
|
|
267
|
+
}
|
|
268
|
+
isAvailable() {
|
|
269
|
+
return process.platform === "win32";
|
|
270
|
+
}
|
|
271
|
+
async connect(platform = null) {
|
|
272
|
+
if (!this.isAvailable()) return false;
|
|
273
|
+
try {
|
|
274
|
+
const msg = platform ? { type: "connect", platform } : { type: "connect" };
|
|
275
|
+
const result = await sendMessage(msg);
|
|
276
|
+
if (result && result.success) {
|
|
277
|
+
this.version = result.version;
|
|
278
|
+
this.product = result.platform;
|
|
279
|
+
_platform = result.platform;
|
|
280
|
+
this.connected = true;
|
|
281
|
+
return true;
|
|
384
282
|
}
|
|
385
|
-
}
|
|
386
|
-
|
|
283
|
+
} catch (e) {
|
|
284
|
+
console.error("CAD connect error:", e.message);
|
|
285
|
+
}
|
|
286
|
+
return false;
|
|
387
287
|
}
|
|
388
|
-
|
|
288
|
+
async sendCommand(code) {
|
|
289
|
+
if (!this.connected) throw new Error("\u672A\u8FDE\u63A5 CAD");
|
|
290
|
+
const result = await sendMessage({ type: "send", code, platform: _platform });
|
|
291
|
+
if (result.success) return true;
|
|
292
|
+
throw new Error(result.error || "\u53D1\u9001\u5931\u8D25");
|
|
293
|
+
}
|
|
294
|
+
async sendCommandWithResult(code, encoding = null) {
|
|
295
|
+
if (!this.connected) throw new Error("\u672A\u8FDE\u63A5 CAD");
|
|
296
|
+
const result = await sendMessage({ type: "sendResult", code, platform: _platform, encoding: encoding || "" });
|
|
297
|
+
if (result.success) {
|
|
298
|
+
return result.result || "";
|
|
299
|
+
}
|
|
300
|
+
throw new Error(result.error || "\u53D1\u9001\u5931\u8D25");
|
|
301
|
+
}
|
|
302
|
+
getVersion() {
|
|
303
|
+
return this.version;
|
|
304
|
+
}
|
|
305
|
+
getPlatform() {
|
|
306
|
+
return this.product;
|
|
307
|
+
}
|
|
308
|
+
async isBusy() {
|
|
309
|
+
if (!this.connected) return false;
|
|
310
|
+
try {
|
|
311
|
+
const result = await sendMessage({ type: "isBusy", platform: _platform });
|
|
312
|
+
return result && result.isBusy;
|
|
313
|
+
} catch (e) {
|
|
314
|
+
return false;
|
|
315
|
+
}
|
|
316
|
+
}
|
|
317
|
+
async hasDoc() {
|
|
318
|
+
if (!this.connected) return { hasDoc: false, docCount: 0 };
|
|
319
|
+
try {
|
|
320
|
+
const result = await sendMessage({ type: "hasdoc", platform: _platform });
|
|
321
|
+
return result || { hasDoc: false, docCount: 0 };
|
|
322
|
+
} catch (e) {
|
|
323
|
+
return { hasDoc: false, docCount: 0 };
|
|
324
|
+
}
|
|
325
|
+
}
|
|
326
|
+
async newDoc() {
|
|
327
|
+
if (!this.connected) throw new Error("\u672A\u8FDE\u63A5 CAD");
|
|
328
|
+
try {
|
|
329
|
+
const result = await sendMessage({ type: "newdoc", platform: _platform });
|
|
330
|
+
return result && result.success;
|
|
331
|
+
} catch (e) {
|
|
332
|
+
return false;
|
|
333
|
+
}
|
|
334
|
+
}
|
|
335
|
+
async bringToFront() {
|
|
336
|
+
if (!this.connected) throw new Error("\u672A\u8FDE\u63A5 CAD");
|
|
337
|
+
try {
|
|
338
|
+
const result = await sendMessage({ type: "bringToFront", platform: _platform });
|
|
339
|
+
return result && result.success;
|
|
340
|
+
} catch (e) {
|
|
341
|
+
return false;
|
|
342
|
+
}
|
|
343
|
+
}
|
|
344
|
+
async getInfo() {
|
|
345
|
+
if (!this.connected) return "CAD \u672A\u8FDE\u63A5";
|
|
346
|
+
return `Platform: ${this.product}, Version: ${this.version}, Status: Connected`;
|
|
347
|
+
}
|
|
348
|
+
async disconnect() {
|
|
349
|
+
this.connected = false;
|
|
350
|
+
this.version = null;
|
|
351
|
+
this.product = null;
|
|
352
|
+
_platform = null;
|
|
353
|
+
resetWorker();
|
|
354
|
+
}
|
|
355
|
+
async ping() {
|
|
356
|
+
try {
|
|
357
|
+
const result = await sendMessage({ type: "ping" });
|
|
358
|
+
return result && result.pong;
|
|
359
|
+
} catch (e) {
|
|
360
|
+
return false;
|
|
361
|
+
}
|
|
362
|
+
}
|
|
363
|
+
_reset() {
|
|
364
|
+
this.connected = false;
|
|
365
|
+
this.version = null;
|
|
366
|
+
this.product = null;
|
|
367
|
+
_platform = null;
|
|
368
|
+
resetWorker();
|
|
369
|
+
}
|
|
370
|
+
};
|
|
371
|
+
var cad = new CadConnection();
|
|
389
372
|
|
|
390
373
|
// src/logger.js
|
|
391
374
|
import fs from "fs";
|
|
392
375
|
import path2 from "path";
|
|
393
376
|
import os from "os";
|
|
377
|
+
var DEBUG_FILE = config_default.debugFile || path2.join(os.tmpdir(), "mcp-server-debug.log");
|
|
378
|
+
var MAX_LOG_SIZE = 10 * 1024 * 1024;
|
|
379
|
+
var MAX_LOG_FILES = 5;
|
|
380
|
+
var stream = null;
|
|
394
381
|
function rotateLog() {
|
|
395
382
|
if (!fs.existsSync(DEBUG_FILE)) return;
|
|
396
383
|
const stat = fs.statSync(DEBUG_FILE);
|
|
@@ -433,8 +420,9 @@ function formatMessage(level, message, meta = {}) {
|
|
|
433
420
|
return JSON.stringify(entry);
|
|
434
421
|
}
|
|
435
422
|
function log(message, meta = {}) {
|
|
423
|
+
getStream().write(formatMessage("INFO", message, meta) + "\n");
|
|
436
424
|
if (config_default.debug) {
|
|
437
|
-
|
|
425
|
+
console.log(`[INFO] ${message}`, meta);
|
|
438
426
|
}
|
|
439
427
|
}
|
|
440
428
|
function error(message, meta = {}) {
|
|
@@ -449,508 +437,115 @@ function closeLog() {
|
|
|
449
437
|
stream = null;
|
|
450
438
|
}
|
|
451
439
|
}
|
|
452
|
-
var DEBUG_FILE, MAX_LOG_SIZE, MAX_LOG_FILES, stream;
|
|
453
|
-
var init_logger = __esm({
|
|
454
|
-
"src/logger.js"() {
|
|
455
|
-
init_config();
|
|
456
|
-
DEBUG_FILE = config_default.debugFile || path2.join(os.tmpdir(), "mcp-server-debug.log");
|
|
457
|
-
MAX_LOG_SIZE = 10 * 1024 * 1024;
|
|
458
|
-
MAX_LOG_FILES = 5;
|
|
459
|
-
stream = null;
|
|
460
|
-
}
|
|
461
|
-
});
|
|
462
440
|
|
|
463
|
-
// src/handlers/
|
|
464
|
-
|
|
465
|
-
|
|
466
|
-
|
|
467
|
-
|
|
468
|
-
|
|
469
|
-
|
|
470
|
-
|
|
471
|
-
|
|
472
|
-
|
|
473
|
-
|
|
474
|
-
|
|
441
|
+
// src/handlers/resource-handlers.js
|
|
442
|
+
import fs2 from "fs";
|
|
443
|
+
import path3 from "path";
|
|
444
|
+
import { fileURLToPath as fileURLToPath2 } from "url";
|
|
445
|
+
var __dirname2 = path3.dirname(fileURLToPath2(import.meta.url));
|
|
446
|
+
var STANDARDS_DIR = path3.join(__dirname2, "..", "standards");
|
|
447
|
+
var CACHE_TTL = config_default.resourceCacheTtl;
|
|
448
|
+
var resourceCache = /* @__PURE__ */ new Map();
|
|
449
|
+
function getCached(key) {
|
|
450
|
+
const entry = resourceCache.get(key);
|
|
451
|
+
if (entry && Date.now() - entry.timestamp < CACHE_TTL) {
|
|
452
|
+
return entry.data;
|
|
475
453
|
}
|
|
476
|
-
|
|
454
|
+
resourceCache.delete(key);
|
|
455
|
+
return null;
|
|
477
456
|
}
|
|
478
|
-
|
|
479
|
-
|
|
480
|
-
|
|
481
|
-
|
|
482
|
-
if (
|
|
483
|
-
|
|
484
|
-
|
|
485
|
-
|
|
486
|
-
if (!trimmed) return { content: [{ type: "text", text: "\u547D\u4EE4\u4E3A\u7A7A\uFF0C\u672A\u53D1\u9001" }] };
|
|
487
|
-
try {
|
|
488
|
-
if (withResult) {
|
|
489
|
-
const result = await cad.sendCommandWithResult(trimmed, encoding);
|
|
490
|
-
if (result !== null) {
|
|
491
|
-
return { content: [{ type: "text", text: result }] };
|
|
457
|
+
function setCache(key, data) {
|
|
458
|
+
resourceCache.set(key, { data, timestamp: Date.now() });
|
|
459
|
+
}
|
|
460
|
+
function clearCache(uri) {
|
|
461
|
+
if (uri) {
|
|
462
|
+
for (const key of resourceCache.keys()) {
|
|
463
|
+
if (key.startsWith(uri.split("://")[1]?.split("/")[0] + ":")) {
|
|
464
|
+
resourceCache.delete(key);
|
|
492
465
|
}
|
|
493
|
-
return { content: [{ type: "text", text: "\u6267\u884C\u5931\u8D25\u6216\u65E0\u8FD4\u56DE\u503C" }], isError: true };
|
|
494
|
-
} else {
|
|
495
|
-
await cad.sendCommand(trimmed + "\n");
|
|
496
|
-
return { content: [{ type: "text", text: `\u5DF2\u53D1\u9001\u547D\u4EE4` }] };
|
|
497
466
|
}
|
|
498
|
-
}
|
|
499
|
-
|
|
467
|
+
} else {
|
|
468
|
+
resourceCache.clear();
|
|
500
469
|
}
|
|
501
470
|
}
|
|
502
|
-
|
|
503
|
-
if (!
|
|
504
|
-
|
|
471
|
+
function parseLispList(str) {
|
|
472
|
+
if (!str || typeof str !== "string") return null;
|
|
473
|
+
const trimmed = str.trim();
|
|
474
|
+
if (!trimmed.startsWith("(") || !trimmed.endsWith(")")) return null;
|
|
475
|
+
const content = trimmed.slice(1, -1).trim();
|
|
476
|
+
if (!content) return [];
|
|
477
|
+
const result = [];
|
|
478
|
+
let depth = 0;
|
|
479
|
+
let current = "";
|
|
480
|
+
let inString = false;
|
|
481
|
+
let escaped = false;
|
|
482
|
+
for (let i = 0; i < content.length; i++) {
|
|
483
|
+
const ch = content[i];
|
|
484
|
+
if (escaped) {
|
|
485
|
+
current += ch;
|
|
486
|
+
escaped = false;
|
|
487
|
+
continue;
|
|
488
|
+
}
|
|
489
|
+
if (ch === "\\") {
|
|
490
|
+
current += ch;
|
|
491
|
+
escaped = true;
|
|
492
|
+
continue;
|
|
493
|
+
}
|
|
494
|
+
if (ch === '"') {
|
|
495
|
+
current += ch;
|
|
496
|
+
inString = !inString;
|
|
497
|
+
continue;
|
|
498
|
+
}
|
|
499
|
+
if (inString) {
|
|
500
|
+
current += ch;
|
|
501
|
+
continue;
|
|
502
|
+
}
|
|
503
|
+
if (ch === "(" || ch === "[") {
|
|
504
|
+
current += ch;
|
|
505
|
+
depth++;
|
|
506
|
+
} else if (ch === ")" || ch === "]") {
|
|
507
|
+
current += ch;
|
|
508
|
+
depth--;
|
|
509
|
+
} else if (ch === " " && depth === 0) {
|
|
510
|
+
if (current.trim()) {
|
|
511
|
+
result.push(current.trim());
|
|
512
|
+
current = "";
|
|
513
|
+
}
|
|
514
|
+
continue;
|
|
515
|
+
}
|
|
516
|
+
current += ch;
|
|
505
517
|
}
|
|
506
|
-
if (
|
|
507
|
-
|
|
508
|
-
|
|
509
|
-
|
|
510
|
-
|
|
511
|
-
|
|
512
|
-
|
|
513
|
-
|
|
514
|
-
|
|
515
|
-
|
|
518
|
+
if (current.trim()) result.push(current.trim());
|
|
519
|
+
return result.map((item) => {
|
|
520
|
+
const t = item.trim();
|
|
521
|
+
if (t === "nil") return null;
|
|
522
|
+
if (t === "t") return true;
|
|
523
|
+
if (t === "T") return true;
|
|
524
|
+
const num = Number(t);
|
|
525
|
+
if (!isNaN(num) && t !== "") return num;
|
|
526
|
+
if (t.startsWith('"') && t.endsWith('"')) return t.slice(1, -1);
|
|
527
|
+
return t;
|
|
528
|
+
});
|
|
516
529
|
}
|
|
517
|
-
|
|
518
|
-
if (!
|
|
519
|
-
|
|
530
|
+
function parseLispRecursive(str) {
|
|
531
|
+
if (!str || typeof str !== "string") return null;
|
|
532
|
+
str = str.trim();
|
|
533
|
+
if (!str) return null;
|
|
534
|
+
let pos = 0;
|
|
535
|
+
function skipWs() {
|
|
536
|
+
while (pos < str.length && /\s/.test(str[pos])) pos++;
|
|
520
537
|
}
|
|
521
|
-
|
|
522
|
-
|
|
523
|
-
|
|
524
|
-
|
|
525
|
-
|
|
526
|
-
|
|
527
|
-
|
|
528
|
-
|
|
529
|
-
|
|
530
|
-
|
|
531
|
-
|
|
532
|
-
if (!cad.connected) return { content: [{ type: "text", text: "\u672A\u8FDE\u63A5 CAD" }], isError: true };
|
|
533
|
-
const result = await cad.bringToFront();
|
|
534
|
-
if (result) {
|
|
535
|
-
return { content: [{ type: "text", text: "\u5DF2\u5C06 CAD \u7A97\u53E3\u5207\u6362\u5230\u524D\u53F0" }] };
|
|
536
|
-
}
|
|
537
|
-
return { content: [{ type: "text", text: "\u5207\u6362\u524D\u53F0\u5931\u8D25" }], isError: true };
|
|
538
|
-
}
|
|
539
|
-
async function installAtlisp() {
|
|
540
|
-
if (!cad.connected) {
|
|
541
|
-
await cad.connect();
|
|
542
|
-
}
|
|
543
|
-
if (!cad.connected) return { content: [{ type: "text", text: "\u672A\u8FDE\u63A5 CAD" }], isError: true };
|
|
544
|
-
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))))`;
|
|
545
|
-
await cad.sendCommand(installCode + "\n");
|
|
546
|
-
return { content: [{ type: "text", text: "\u5DF2\u53D1\u9001 @lisp \u5B89\u88C5\u4EE3\u7801\u5230 CAD" }] };
|
|
547
|
-
}
|
|
548
|
-
async function listFunctionsInCad() {
|
|
549
|
-
if (!cad.connected) {
|
|
550
|
-
await cad.connect();
|
|
551
|
-
}
|
|
552
|
-
if (!cad.connected) return { content: [{ type: "text", text: "\u672A\u8FDE\u63A5 CAD" }], isError: true };
|
|
553
|
-
try {
|
|
554
|
-
const result = await cad.sendCommandWithResult("(atoms-family 0)", null);
|
|
555
|
-
if (result) return { content: [{ type: "text", text: result }] };
|
|
556
|
-
return { content: [{ type: "text", text: "CAD \u51FD\u6570\u5217\u8868\u4E3A\u7A7A" }] };
|
|
557
|
-
} catch (e) {
|
|
558
|
-
return { content: [{ type: "text", text: `\u9519\u8BEF: ${e.message}` }], isError: true };
|
|
559
|
-
}
|
|
560
|
-
}
|
|
561
|
-
async function getSystemStatus() {
|
|
562
|
-
const status = {
|
|
563
|
-
mcp: { version: process.env.npm_package_version || "unknown" },
|
|
564
|
-
worker: { alive: false },
|
|
565
|
-
cad: { connected: false, platform: null, version: null, busy: false, hasDoc: false },
|
|
566
|
-
lisp: { available: false, testResult: null, error: null },
|
|
567
|
-
packages: null
|
|
568
|
-
};
|
|
569
|
-
try {
|
|
570
|
-
status.worker.alive = await cad.ping();
|
|
571
|
-
} catch {
|
|
572
|
-
status.worker.alive = false;
|
|
573
|
-
}
|
|
574
|
-
status.cad.connected = cad.connected;
|
|
575
|
-
if (cad.connected) {
|
|
576
|
-
status.cad.platform = cad.getPlatform();
|
|
577
|
-
status.cad.version = cad.getVersion();
|
|
578
|
-
try {
|
|
579
|
-
status.cad.busy = await cad.isBusy();
|
|
580
|
-
} catch {
|
|
581
|
-
}
|
|
582
|
-
try {
|
|
583
|
-
const doc = await cad.hasDoc();
|
|
584
|
-
status.cad.hasDoc = doc.hasDoc;
|
|
585
|
-
} catch {
|
|
586
|
-
}
|
|
587
|
-
try {
|
|
588
|
-
const r = await cad.sendCommandWithResult("(+ 1 2)");
|
|
589
|
-
if (r !== null && r !== void 0) {
|
|
590
|
-
status.lisp.available = true;
|
|
591
|
-
status.lisp.testResult = String(r).trim();
|
|
592
|
-
}
|
|
593
|
-
} catch (e) {
|
|
594
|
-
status.lisp.error = e.message;
|
|
595
|
-
}
|
|
596
|
-
try {
|
|
597
|
-
const pkgResult = await cad.sendCommandWithResult("(@::package-list-in-local)");
|
|
598
|
-
if (pkgResult && pkgResult !== "nil") {
|
|
599
|
-
status.packages = pkgResult;
|
|
600
|
-
}
|
|
601
|
-
} catch {
|
|
602
|
-
}
|
|
603
|
-
}
|
|
604
|
-
return { content: [{ type: "text", text: JSON.stringify(status, null, 2) }] };
|
|
605
|
-
}
|
|
606
|
-
async function initAtlisp() {
|
|
607
|
-
if (!cad.connected) {
|
|
608
|
-
await cad.connect();
|
|
609
|
-
}
|
|
610
|
-
if (!cad.connected) return { content: [{ type: "text", text: "\u672A\u8FDE\u63A5 CAD" }], isError: true };
|
|
611
|
-
const code = `(if (null @::load-module)
|
|
612
|
-
(progn
|
|
613
|
-
(vl-load-com)
|
|
614
|
-
(setq s strcat h"http"o(vlax-create-object (s"win"h".win"h"request.5.1"))
|
|
615
|
-
v vlax-invoke e eval r read)(v o'open "get" (s h"://""atlisp.""cn/cloud"):vlax-true)
|
|
616
|
-
(v o'send)
|
|
617
|
-
(v o'WaitforResponse 1000)
|
|
618
|
-
(e(r(vlax-get o'ResponseText)))))`;
|
|
619
|
-
try {
|
|
620
|
-
await cad.sendCommand(code + "\n");
|
|
621
|
-
return { content: [{ type: "text", text: "\u5DF2\u53D1\u9001 @lisp \u51FD\u6570\u5E93\u52A0\u8F7D\u4EE3\u7801\u5230 CAD" }] };
|
|
622
|
-
} catch (e) {
|
|
623
|
-
return { content: [{ type: "text", text: `\u9519\u8BEF: ${e.message}` }], isError: true };
|
|
624
|
-
}
|
|
625
|
-
}
|
|
626
|
-
var init_cad_handlers = __esm({
|
|
627
|
-
"src/handlers/cad-handlers.js"() {
|
|
628
|
-
init_cad();
|
|
629
|
-
init_logger();
|
|
630
|
-
}
|
|
631
|
-
});
|
|
632
|
-
|
|
633
|
-
// src/handlers/package-handlers.js
|
|
634
|
-
async function fetchPackages() {
|
|
635
|
-
const now = Date.now();
|
|
636
|
-
if (cachedPackages && cachedAt && now - cachedAt < CACHE_TTL) {
|
|
637
|
-
return cachedPackages;
|
|
638
|
-
}
|
|
639
|
-
try {
|
|
640
|
-
const response = await fetch(PACKAGES_LIST_URL, { headers: { "User-Agent": "atlisp-mcp" } });
|
|
641
|
-
if (response.ok) {
|
|
642
|
-
const data = await response.json();
|
|
643
|
-
cachedPackages = data;
|
|
644
|
-
cachedAt = now;
|
|
645
|
-
return data;
|
|
646
|
-
}
|
|
647
|
-
} catch (e) {
|
|
648
|
-
}
|
|
649
|
-
return cachedPackages || MOCK_PACKAGES;
|
|
650
|
-
}
|
|
651
|
-
function flattenPackages(data) {
|
|
652
|
-
if (Array.isArray(data)) return data;
|
|
653
|
-
if (data && Array.isArray(data.packages)) return data.packages;
|
|
654
|
-
return [];
|
|
655
|
-
}
|
|
656
|
-
async function listPackages() {
|
|
657
|
-
if (!cad.connected) await cad.connect();
|
|
658
|
-
if (!cad.connected) {
|
|
659
|
-
const data2 = await fetchPackages();
|
|
660
|
-
const items2 = flattenPackages(data2);
|
|
661
|
-
const text2 = items2.length ? items2.map((p) => `${p.name} v${p.version || ""} - ${p.description || ""}`).join("\n") : "\u65E0\u53EF\u7528\u5305";
|
|
662
|
-
return { content: [{ type: "text", text: text2 }] };
|
|
663
|
-
}
|
|
664
|
-
const result = await cad.sendCommandWithResult("(@::package-list-in-local)");
|
|
665
|
-
if (result && result !== "nil") return { content: [{ type: "text", text: result }] };
|
|
666
|
-
const data = await fetchPackages();
|
|
667
|
-
const items = flattenPackages(data);
|
|
668
|
-
const text = items.length ? `\u4ECE\u6CE8\u518C\u8868\u83B7\u53D6\u7684 @lisp \u5305:
|
|
669
|
-
${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");
|
|
670
|
-
return { content: [{ type: "text", text: `\u5DF2\u5B89\u88C5\u7684 @lisp \u5305:
|
|
671
|
-
${text}` }] };
|
|
672
|
-
}
|
|
673
|
-
async function searchPackages(query) {
|
|
674
|
-
const data = await fetchPackages();
|
|
675
|
-
if (!data) {
|
|
676
|
-
return { content: [{ type: "text", text: "\u65E0\u6CD5\u83B7\u53D6\u5305\u5217\u8868" }], isError: true };
|
|
677
|
-
}
|
|
678
|
-
const items = flattenPackages(data);
|
|
679
|
-
const results = [];
|
|
680
|
-
if (query) {
|
|
681
|
-
const q = query.toLowerCase();
|
|
682
|
-
for (const p of items) {
|
|
683
|
-
const name = (p.name || "").toLowerCase();
|
|
684
|
-
const desc = (p.description || "").toLowerCase();
|
|
685
|
-
if (name.includes(q) || desc.includes(q)) results.push(p);
|
|
686
|
-
}
|
|
687
|
-
} else {
|
|
688
|
-
for (const p of items) results.push(p);
|
|
689
|
-
}
|
|
690
|
-
if (results.length === 0) {
|
|
691
|
-
return { content: [{ type: "text", text: `\u672A\u627E\u5230\u5305\u542B "${query}" \u7684\u5305` }] };
|
|
692
|
-
}
|
|
693
|
-
return { content: [{ type: "text", text: `\u641C\u7D22\u7ED3\u679C (${results.length}):
|
|
694
|
-
${results.map((p) => `${p.name} v${p.version || ""} - ${p.description || ""}`).join("\n")}` }] };
|
|
695
|
-
}
|
|
696
|
-
async function installPackage(packageName) {
|
|
697
|
-
const data = await fetchPackages();
|
|
698
|
-
const items = flattenPackages(data);
|
|
699
|
-
const pkg = items.find((p) => p.name === packageName);
|
|
700
|
-
if (!pkg) {
|
|
701
|
-
return { content: [{ type: "text", text: `\u9519\u8BEF: \u5305 "${packageName}" \u4E0D\u5B58\u5728` }], isError: true };
|
|
702
|
-
}
|
|
703
|
-
if (cad.connected) {
|
|
704
|
-
await cad.sendCommand(`(@::load-module '${packageName})
|
|
705
|
-
`);
|
|
706
|
-
}
|
|
707
|
-
return { content: [{ type: "text", text: `\u5305 "${packageName}" \u5B89\u88C5\u547D\u4EE4\u5DF2\u53D1\u9001\uFF01` }] };
|
|
708
|
-
}
|
|
709
|
-
var PACKAGES_LIST_URL, cachedPackages, cachedAt, CACHE_TTL;
|
|
710
|
-
var init_package_handlers = __esm({
|
|
711
|
-
"src/handlers/package-handlers.js"() {
|
|
712
|
-
init_cad();
|
|
713
|
-
init_constants();
|
|
714
|
-
PACKAGES_LIST_URL = process.env.PACKAGES_LIST_URL || "http://s3.atlisp.cn/packages-list?fmt=json";
|
|
715
|
-
cachedPackages = null;
|
|
716
|
-
cachedAt = null;
|
|
717
|
-
CACHE_TTL = 10 * 60 * 1e3;
|
|
718
|
-
}
|
|
719
|
-
});
|
|
720
|
-
|
|
721
|
-
// src/handlers/function-handlers.js
|
|
722
|
-
import fs2 from "fs";
|
|
723
|
-
import path3 from "path";
|
|
724
|
-
import os2 from "os";
|
|
725
|
-
function readCacheFromDisk() {
|
|
726
|
-
try {
|
|
727
|
-
const stat = fs2.statSync(FUNCLIB_CACHE_FILE);
|
|
728
|
-
if (Date.now() - stat.mtimeMs < FUNCLIB_CACHE_TTL) {
|
|
729
|
-
const raw = fs2.readFileSync(FUNCLIB_CACHE_FILE, "utf-8");
|
|
730
|
-
return JSON.parse(raw);
|
|
731
|
-
}
|
|
732
|
-
} catch {
|
|
733
|
-
}
|
|
734
|
-
return null;
|
|
735
|
-
}
|
|
736
|
-
function writeCacheToDisk(data) {
|
|
737
|
-
try {
|
|
738
|
-
fs2.mkdirSync(CACHE_DIR, { recursive: true });
|
|
739
|
-
fs2.writeFileSync(FUNCLIB_CACHE_FILE, JSON.stringify(data), "utf-8");
|
|
740
|
-
} catch (e) {
|
|
741
|
-
log(`function-handlers writeCache error: ${e.message}`);
|
|
742
|
-
}
|
|
743
|
-
}
|
|
744
|
-
async function fetchFunctions() {
|
|
745
|
-
const diskCache = readCacheFromDisk();
|
|
746
|
-
if (diskCache) return diskCache;
|
|
747
|
-
try {
|
|
748
|
-
const response = await fetch(FUNCTIONS_URL, { headers: { "User-Agent": "atlisp-mcp" } });
|
|
749
|
-
if (response.ok) {
|
|
750
|
-
const data = await response.json();
|
|
751
|
-
writeCacheToDisk(data);
|
|
752
|
-
return data;
|
|
753
|
-
}
|
|
754
|
-
} catch (e) {
|
|
755
|
-
log(`function-handlers fetch error: ${e.message}`);
|
|
756
|
-
}
|
|
757
|
-
return diskCache;
|
|
758
|
-
}
|
|
759
|
-
async function getFunctionUsage(funcName, packageName) {
|
|
760
|
-
try {
|
|
761
|
-
let results = [];
|
|
762
|
-
const data = await fetchFunctions();
|
|
763
|
-
if (data) {
|
|
764
|
-
const funcs = Object.values(data.all_functions || {});
|
|
765
|
-
const func = funcs.find((f2) => f2.name === funcName || f2.name === `${packageName}:${funcName}`);
|
|
766
|
-
if (func) results.push(func);
|
|
767
|
-
}
|
|
768
|
-
if (results.length === 0 && FUNCTIONS_DIR) {
|
|
769
|
-
try {
|
|
770
|
-
const files = fs2.readdirSync(FUNCTIONS_DIR).filter((f2) => f2.endsWith(".json"));
|
|
771
|
-
for (const file of files) {
|
|
772
|
-
const raw = fs2.readFileSync(path3.join(FUNCTIONS_DIR, file), "utf-8");
|
|
773
|
-
const data2 = JSON.parse(raw);
|
|
774
|
-
const func = data2.functions?.find((f2) => f2.name === funcName);
|
|
775
|
-
if (func) results.push(func);
|
|
776
|
-
}
|
|
777
|
-
} catch {
|
|
778
|
-
}
|
|
779
|
-
}
|
|
780
|
-
if (results.length === 0) {
|
|
781
|
-
return { content: [{ type: "text", text: `\u672A\u627E\u5230\u51FD\u6570: ${funcName}` }], isError: true };
|
|
782
|
-
}
|
|
783
|
-
const f = results[0];
|
|
784
|
-
const text = `\u51FD\u6570: ${f.name}
|
|
785
|
-
\u63CF\u8FF0: ${f.description || "-"}
|
|
786
|
-
\u53C2\u6570: ${f.params?.join(", ") || "-"}
|
|
787
|
-
\u8FD4\u56DE\u503C: ${f.return || "-"}
|
|
788
|
-
\u793A\u4F8B: ${f.usage || "-"}`;
|
|
789
|
-
return { content: [{ type: "text", text }] };
|
|
790
|
-
} catch (e) {
|
|
791
|
-
return { content: [{ type: "text", text: `\u9519\u8BEF: ${e.message}` }], isError: true };
|
|
792
|
-
}
|
|
793
|
-
}
|
|
794
|
-
async function listSymbols(packageName) {
|
|
795
|
-
try {
|
|
796
|
-
let allFuncs = [];
|
|
797
|
-
const data = await fetchFunctions();
|
|
798
|
-
if (data) {
|
|
799
|
-
const funcs = Object.values(data.all_functions || {});
|
|
800
|
-
if (packageName) {
|
|
801
|
-
allFuncs = funcs.filter((f) => f.name.startsWith(`${packageName}:`));
|
|
802
|
-
} else {
|
|
803
|
-
allFuncs = funcs.map((f) => `${f.name}: ${f.description || "-"}`);
|
|
804
|
-
}
|
|
805
|
-
}
|
|
806
|
-
if (allFuncs.length === 0 && FUNCTIONS_DIR) {
|
|
807
|
-
try {
|
|
808
|
-
const files = fs2.readdirSync(FUNCTIONS_DIR).filter((f) => f.endsWith(".json"));
|
|
809
|
-
for (const file of files) {
|
|
810
|
-
const raw = fs2.readFileSync(path3.join(FUNCTIONS_DIR, file), "utf-8");
|
|
811
|
-
const data2 = JSON.parse(raw);
|
|
812
|
-
const funcs = Object.values(data2.all_functions || {});
|
|
813
|
-
if (packageName) {
|
|
814
|
-
allFuncs = funcs.filter((f) => f.name.startsWith(`${packageName}:`));
|
|
815
|
-
} else {
|
|
816
|
-
for (const f of funcs) {
|
|
817
|
-
allFuncs.push(`${f.name}: ${f.description || "-"}`);
|
|
818
|
-
}
|
|
819
|
-
}
|
|
820
|
-
}
|
|
821
|
-
} catch (err) {
|
|
822
|
-
log(`listSymbols readDir error: ${err.message}`);
|
|
823
|
-
}
|
|
824
|
-
}
|
|
825
|
-
if (allFuncs.length === 0) {
|
|
826
|
-
return await listFunctionsInCad();
|
|
827
|
-
}
|
|
828
|
-
if (packageName) {
|
|
829
|
-
return { content: [{ type: "text", text: `${packageName} \u5305\u51FD\u6570 (${allFuncs.length}):
|
|
830
|
-
${allFuncs.map((f) => f.name).join("\n")}` }] };
|
|
831
|
-
}
|
|
832
|
-
return { content: [{ type: "text", text: allFuncs.join("\n") }] };
|
|
833
|
-
} catch (e) {
|
|
834
|
-
return { content: [{ type: "text", text: `\u9519\u8BEF: ${e.message}` }], isError: true };
|
|
835
|
-
}
|
|
836
|
-
}
|
|
837
|
-
var FUNCTIONS_DIR, FUNCTIONS_URL, CACHE_DIR, FUNCLIB_CACHE_FILE, FUNCLIB_CACHE_TTL;
|
|
838
|
-
var init_function_handlers = __esm({
|
|
839
|
-
"src/handlers/function-handlers.js"() {
|
|
840
|
-
init_logger();
|
|
841
|
-
init_cad_handlers();
|
|
842
|
-
FUNCTIONS_DIR = process.env.FUNCTIONS_DIR || "";
|
|
843
|
-
FUNCTIONS_URL = process.env.FUNCTIONS_URL || "http://s3.atlisp.cn/json/functions.json";
|
|
844
|
-
CACHE_DIR = path3.join(os2.homedir(), ".atlisp", "cache");
|
|
845
|
-
FUNCLIB_CACHE_FILE = path3.join(CACHE_DIR, "functions.json");
|
|
846
|
-
FUNCLIB_CACHE_TTL = 24 * 60 * 60 * 1e3;
|
|
847
|
-
}
|
|
848
|
-
});
|
|
849
|
-
|
|
850
|
-
// src/handlers/resource-handlers.js
|
|
851
|
-
import fs3 from "fs";
|
|
852
|
-
import path4 from "path";
|
|
853
|
-
import { fileURLToPath as fileURLToPath2 } from "url";
|
|
854
|
-
function getCached(key) {
|
|
855
|
-
const entry = resourceCache.get(key);
|
|
856
|
-
if (entry && Date.now() - entry.timestamp < CACHE_TTL2) {
|
|
857
|
-
return entry.data;
|
|
858
|
-
}
|
|
859
|
-
resourceCache.delete(key);
|
|
860
|
-
return null;
|
|
861
|
-
}
|
|
862
|
-
function setCache(key, data) {
|
|
863
|
-
resourceCache.set(key, { data, timestamp: Date.now() });
|
|
864
|
-
}
|
|
865
|
-
function clearCache(uri) {
|
|
866
|
-
if (uri) {
|
|
867
|
-
for (const key of resourceCache.keys()) {
|
|
868
|
-
if (key.startsWith(uri.split("://")[1]?.split("/")[0] + ":")) {
|
|
869
|
-
resourceCache.delete(key);
|
|
870
|
-
}
|
|
871
|
-
}
|
|
872
|
-
} else {
|
|
873
|
-
resourceCache.clear();
|
|
874
|
-
}
|
|
875
|
-
}
|
|
876
|
-
function parseLispList(str) {
|
|
877
|
-
if (!str || typeof str !== "string") return null;
|
|
878
|
-
const trimmed = str.trim();
|
|
879
|
-
if (!trimmed.startsWith("(") || !trimmed.endsWith(")")) return null;
|
|
880
|
-
const content = trimmed.slice(1, -1).trim();
|
|
881
|
-
if (!content) return [];
|
|
882
|
-
const result = [];
|
|
883
|
-
let depth = 0;
|
|
884
|
-
let current = "";
|
|
885
|
-
let inString = false;
|
|
886
|
-
let escaped = false;
|
|
887
|
-
for (let i = 0; i < content.length; i++) {
|
|
888
|
-
const ch = content[i];
|
|
889
|
-
if (escaped) {
|
|
890
|
-
current += ch;
|
|
891
|
-
escaped = false;
|
|
892
|
-
continue;
|
|
893
|
-
}
|
|
894
|
-
if (ch === "\\") {
|
|
895
|
-
current += ch;
|
|
896
|
-
escaped = true;
|
|
897
|
-
continue;
|
|
898
|
-
}
|
|
899
|
-
if (ch === '"') {
|
|
900
|
-
current += ch;
|
|
901
|
-
inString = !inString;
|
|
902
|
-
continue;
|
|
903
|
-
}
|
|
904
|
-
if (inString) {
|
|
905
|
-
current += ch;
|
|
906
|
-
continue;
|
|
907
|
-
}
|
|
908
|
-
if (ch === "(" || ch === "[") {
|
|
909
|
-
current += ch;
|
|
910
|
-
depth++;
|
|
911
|
-
} else if (ch === ")" || ch === "]") {
|
|
912
|
-
current += ch;
|
|
913
|
-
depth--;
|
|
914
|
-
} else if (ch === " " && depth === 0) {
|
|
915
|
-
if (current.trim()) {
|
|
916
|
-
result.push(current.trim());
|
|
917
|
-
current = "";
|
|
918
|
-
}
|
|
919
|
-
continue;
|
|
920
|
-
}
|
|
921
|
-
current += ch;
|
|
922
|
-
}
|
|
923
|
-
if (current.trim()) result.push(current.trim());
|
|
924
|
-
return result.map((item) => {
|
|
925
|
-
const t = item.trim();
|
|
926
|
-
if (t === "nil") return null;
|
|
927
|
-
if (t === "t") return true;
|
|
928
|
-
if (t === "T") return true;
|
|
929
|
-
const num = Number(t);
|
|
930
|
-
if (!isNaN(num) && t !== "") return num;
|
|
931
|
-
if (t.startsWith('"') && t.endsWith('"')) return t.slice(1, -1);
|
|
932
|
-
return t;
|
|
933
|
-
});
|
|
934
|
-
}
|
|
935
|
-
function parseLispRecursive(str) {
|
|
936
|
-
if (!str || typeof str !== "string") return null;
|
|
937
|
-
str = str.trim();
|
|
938
|
-
if (!str) return null;
|
|
939
|
-
let pos = 0;
|
|
940
|
-
function skipWs() {
|
|
941
|
-
while (pos < str.length && /\s/.test(str[pos])) pos++;
|
|
942
|
-
}
|
|
943
|
-
function parseValue() {
|
|
944
|
-
skipWs();
|
|
945
|
-
if (pos >= str.length) return null;
|
|
946
|
-
const ch = str[pos];
|
|
947
|
-
if (ch === "(") return parseList();
|
|
948
|
-
if (ch === '"') return parseString();
|
|
949
|
-
if (ch === "'") {
|
|
950
|
-
pos++;
|
|
951
|
-
return parseValue();
|
|
952
|
-
}
|
|
953
|
-
return parseAtom();
|
|
538
|
+
function parseValue() {
|
|
539
|
+
skipWs();
|
|
540
|
+
if (pos >= str.length) return null;
|
|
541
|
+
const ch = str[pos];
|
|
542
|
+
if (ch === "(") return parseList();
|
|
543
|
+
if (ch === '"') return parseString();
|
|
544
|
+
if (ch === "'") {
|
|
545
|
+
pos++;
|
|
546
|
+
return parseValue();
|
|
547
|
+
}
|
|
548
|
+
return parseAtom();
|
|
954
549
|
}
|
|
955
550
|
function parseString() {
|
|
956
551
|
pos++;
|
|
@@ -1131,6 +726,19 @@ function buildTextCode({ layer, bbox, offset, limit }) {
|
|
|
1131
726
|
(@t:run))
|
|
1132
727
|
`;
|
|
1133
728
|
}
|
|
729
|
+
var RESOURCES = [
|
|
730
|
+
{ uri: "atlisp://cad/info", name: "CAD Info", description: "CAD \u8FDE\u63A5\u4FE1\u606F", mimeType: "application/json", subscribable: true },
|
|
731
|
+
{ uri: "atlisp://dwg/layers", name: "Layers", description: "\u56FE\u5C42\u5217\u8868", mimeType: "application/json", subscribable: true },
|
|
732
|
+
{ uri: "atlisp://dwg/entities", name: "Entities", description: "\u56FE\u5143\u5217\u8868\uFF0C\u8FD4\u56DE\u603B\u6570\u548C\u524D3000\u4E2A\u56FE\u5143\uFF0C\u6587\u672C\u9644\u52A0 text \u5B57\u6BB5\uFF0C\u66F2\u7EBF\u9644\u52A0 points \u6570\u7EC4\uFF0CINSERT \u9644\u52A0 blockName\uFF0C\u652F\u6301 ?type=LINE&layer=0&bbox=0,0,100,100 \u8FC7\u6EE4", mimeType: "application/json", subscribable: true },
|
|
733
|
+
{ 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=5000&offset=0", mimeType: "application/json", subscribable: true },
|
|
734
|
+
{ uri: "atlisp://dwg/name", name: "DWG Name", description: "\u5F53\u524D DWG \u6587\u4EF6\u540D", mimeType: "application/json", subscribable: true },
|
|
735
|
+
{ uri: "atlisp://dwg/path", name: "DWG Path", description: "\u6587\u4EF6\u5B8C\u6574\u8DEF\u5F84", mimeType: "application/json", subscribable: true },
|
|
736
|
+
{ uri: "atlisp://cad/dwgs", name: "DWG List", description: "\u6240\u6709\u6253\u5F00\u7684 DWG \u6587\u4EF6\u5217\u8868", mimeType: "application/json", subscribable: true },
|
|
737
|
+
{ uri: "atlisp://packages", name: "Packages", description: "\u5DF2\u5B89\u88C5\u5305\u5217\u8868", mimeType: "application/json", subscribable: true },
|
|
738
|
+
{ uri: "atlisp://platforms", name: "Platforms", description: "\u652F\u6301\u7684\u5E73\u53F0\u4FE1\u606F", mimeType: "application/json", subscribable: false },
|
|
739
|
+
{ uri: "atlisp://standards/drafting", name: "Drafting Standards", description: "CAD \u5236\u56FE\u89C4\u8303", mimeType: "application/json", subscribable: false },
|
|
740
|
+
{ uri: "atlisp://standards/coding", name: "Coding Standards", description: "@lisp \u7F16\u7801\u89C4\u8303", mimeType: "application/json", subscribable: false }
|
|
741
|
+
];
|
|
1134
742
|
function parseQuery(uri) {
|
|
1135
743
|
const qIdx = uri.indexOf("?");
|
|
1136
744
|
if (qIdx === -1) return { base: uri, params: {} };
|
|
@@ -1157,7 +765,7 @@ async function readResource(uri) {
|
|
|
1157
765
|
const { base, params } = parseQuery(uri);
|
|
1158
766
|
switch (base) {
|
|
1159
767
|
case "atlisp://cad/info":
|
|
1160
|
-
return await
|
|
768
|
+
return await getCadInfo();
|
|
1161
769
|
case "atlisp://dwg/layers":
|
|
1162
770
|
return await getLayers(params.name);
|
|
1163
771
|
case "atlisp://dwg/entities":
|
|
@@ -1182,7 +790,7 @@ async function readResource(uri) {
|
|
|
1182
790
|
throw new Error(`\u8D44\u6E90\u4E0D\u5B58\u5728: ${uri}`);
|
|
1183
791
|
}
|
|
1184
792
|
}
|
|
1185
|
-
async function
|
|
793
|
+
async function getCadInfo() {
|
|
1186
794
|
const cached = getCached("cad:info");
|
|
1187
795
|
if (cached) return cached;
|
|
1188
796
|
if (!cad.connected) {
|
|
@@ -1476,94 +1084,666 @@ async function getDwgList() {
|
|
|
1476
1084
|
setCache(cacheKey, []);
|
|
1477
1085
|
return [];
|
|
1478
1086
|
}
|
|
1479
|
-
let parsed = [];
|
|
1480
|
-
try {
|
|
1481
|
-
parsed = JSON.parse(result);
|
|
1482
|
-
} catch (e) {
|
|
1483
|
-
const listResult = parseLispList(result);
|
|
1484
|
-
if (listResult) {
|
|
1485
|
-
parsed = listResult;
|
|
1087
|
+
let parsed = [];
|
|
1088
|
+
try {
|
|
1089
|
+
parsed = JSON.parse(result);
|
|
1090
|
+
} catch (e) {
|
|
1091
|
+
const listResult = parseLispList(result);
|
|
1092
|
+
if (listResult) {
|
|
1093
|
+
parsed = listResult;
|
|
1094
|
+
}
|
|
1095
|
+
}
|
|
1096
|
+
if (!Array.isArray(parsed)) parsed = [];
|
|
1097
|
+
const dwgList = parsed.map((item) => {
|
|
1098
|
+
if (Array.isArray(item) && item.length >= 2) {
|
|
1099
|
+
return { name: String(item[0]), path: String(item[1]) };
|
|
1100
|
+
}
|
|
1101
|
+
return null;
|
|
1102
|
+
}).filter(Boolean);
|
|
1103
|
+
setCache(cacheKey, dwgList);
|
|
1104
|
+
return dwgList;
|
|
1105
|
+
} catch (e) {
|
|
1106
|
+
setCache(cacheKey, []);
|
|
1107
|
+
return [];
|
|
1108
|
+
}
|
|
1109
|
+
}
|
|
1110
|
+
function loadStandardsFile(filename) {
|
|
1111
|
+
const filePath = path3.join(STANDARDS_DIR, filename);
|
|
1112
|
+
try {
|
|
1113
|
+
const raw = fs2.readFileSync(filePath, "utf-8");
|
|
1114
|
+
return JSON.parse(raw);
|
|
1115
|
+
} catch (e) {
|
|
1116
|
+
log(`Error loading standards file ${filename}: ${e.message}`);
|
|
1117
|
+
return null;
|
|
1118
|
+
}
|
|
1119
|
+
}
|
|
1120
|
+
var standardsCache = /* @__PURE__ */ new Map();
|
|
1121
|
+
function getCachedStandards(key) {
|
|
1122
|
+
const entry = standardsCache.get(key);
|
|
1123
|
+
if (entry && Date.now() - entry.timestamp < 3e4) return entry.data;
|
|
1124
|
+
standardsCache.delete(key);
|
|
1125
|
+
return null;
|
|
1126
|
+
}
|
|
1127
|
+
function setCachedStandards(key, data) {
|
|
1128
|
+
standardsCache.set(key, { data, timestamp: Date.now() });
|
|
1129
|
+
}
|
|
1130
|
+
function getDraftingStandards() {
|
|
1131
|
+
const cached = getCachedStandards("drafting");
|
|
1132
|
+
if (cached) return cached;
|
|
1133
|
+
const data = loadStandardsFile("drafting.json");
|
|
1134
|
+
if (data) setCachedStandards("drafting", data);
|
|
1135
|
+
return data || { error: "\u5236\u56FE\u89C4\u8303\u6587\u4EF6\u52A0\u8F7D\u5931\u8D25" };
|
|
1136
|
+
}
|
|
1137
|
+
function getCodingStandards() {
|
|
1138
|
+
const cached = getCachedStandards("coding");
|
|
1139
|
+
if (cached) return cached;
|
|
1140
|
+
const data = loadStandardsFile("coding.json");
|
|
1141
|
+
if (data) setCachedStandards("coding", data);
|
|
1142
|
+
return data || { error: "\u7F16\u7801\u89C4\u8303\u6587\u4EF6\u52A0\u8F7D\u5931\u8D25" };
|
|
1143
|
+
}
|
|
1144
|
+
|
|
1145
|
+
// src/session-manager.js
|
|
1146
|
+
var Session = class {
|
|
1147
|
+
constructor(clientId) {
|
|
1148
|
+
this.clientId = clientId;
|
|
1149
|
+
this.subscriptions = /* @__PURE__ */ new Set();
|
|
1150
|
+
this.createdAt = Date.now();
|
|
1151
|
+
this.connected = false;
|
|
1152
|
+
}
|
|
1153
|
+
};
|
|
1154
|
+
var SessionManager = class {
|
|
1155
|
+
#sessions = /* @__PURE__ */ new Map();
|
|
1156
|
+
createSession(clientId) {
|
|
1157
|
+
let session = this.#sessions.get(clientId);
|
|
1158
|
+
if (!session) {
|
|
1159
|
+
session = new Session(clientId);
|
|
1160
|
+
this.#sessions.set(clientId, session);
|
|
1161
|
+
}
|
|
1162
|
+
return session;
|
|
1163
|
+
}
|
|
1164
|
+
getSession(clientId) {
|
|
1165
|
+
return this.#sessions.get(clientId) || null;
|
|
1166
|
+
}
|
|
1167
|
+
hasSession(clientId) {
|
|
1168
|
+
return this.#sessions.has(clientId);
|
|
1169
|
+
}
|
|
1170
|
+
removeSession(clientId) {
|
|
1171
|
+
return this.#sessions.delete(clientId);
|
|
1172
|
+
}
|
|
1173
|
+
subscribe(clientId, uri) {
|
|
1174
|
+
const session = this.#sessions.get(clientId);
|
|
1175
|
+
if (session) {
|
|
1176
|
+
session.subscriptions.add(uri);
|
|
1177
|
+
return true;
|
|
1178
|
+
}
|
|
1179
|
+
return false;
|
|
1180
|
+
}
|
|
1181
|
+
unsubscribe(clientId, uri) {
|
|
1182
|
+
const session = this.#sessions.get(clientId);
|
|
1183
|
+
if (session) {
|
|
1184
|
+
return session.subscriptions.delete(uri);
|
|
1185
|
+
}
|
|
1186
|
+
return false;
|
|
1187
|
+
}
|
|
1188
|
+
getSubscriptions(clientId) {
|
|
1189
|
+
const session = this.#sessions.get(clientId);
|
|
1190
|
+
return session ? Array.from(session.subscriptions) : [];
|
|
1191
|
+
}
|
|
1192
|
+
isSubscribed(clientId, uri) {
|
|
1193
|
+
const session = this.#sessions.get(clientId);
|
|
1194
|
+
return session ? session.subscriptions.has(uri) : false;
|
|
1195
|
+
}
|
|
1196
|
+
getAllSubscribedUris() {
|
|
1197
|
+
const all = /* @__PURE__ */ new Set();
|
|
1198
|
+
for (const session of this.#sessions.values()) {
|
|
1199
|
+
for (const uri of session.subscriptions) {
|
|
1200
|
+
all.add(uri);
|
|
1201
|
+
}
|
|
1202
|
+
}
|
|
1203
|
+
return all;
|
|
1204
|
+
}
|
|
1205
|
+
list() {
|
|
1206
|
+
return Array.from(this.#sessions.entries()).map(([id, s]) => ({
|
|
1207
|
+
clientId: id,
|
|
1208
|
+
subscriptions: Array.from(s.subscriptions),
|
|
1209
|
+
createdAt: s.createdAt,
|
|
1210
|
+
connected: s.connected
|
|
1211
|
+
}));
|
|
1212
|
+
}
|
|
1213
|
+
count() {
|
|
1214
|
+
return this.#sessions.size;
|
|
1215
|
+
}
|
|
1216
|
+
clear() {
|
|
1217
|
+
this.#sessions.clear();
|
|
1218
|
+
}
|
|
1219
|
+
};
|
|
1220
|
+
|
|
1221
|
+
// src/subscription-manager.js
|
|
1222
|
+
var sessionManager = new SessionManager();
|
|
1223
|
+
var _notifyFn = null;
|
|
1224
|
+
function setNotify(fn) {
|
|
1225
|
+
_notifyFn = fn;
|
|
1226
|
+
}
|
|
1227
|
+
function subscribe(uri, sessionId) {
|
|
1228
|
+
if (sessionId) {
|
|
1229
|
+
return sessionManager.subscribe(sessionId, uri);
|
|
1230
|
+
}
|
|
1231
|
+
return true;
|
|
1232
|
+
}
|
|
1233
|
+
function unsubscribe(uri, sessionId) {
|
|
1234
|
+
if (sessionId) {
|
|
1235
|
+
return sessionManager.unsubscribe(sessionId, uri);
|
|
1236
|
+
}
|
|
1237
|
+
return true;
|
|
1238
|
+
}
|
|
1239
|
+
function list(sessionId) {
|
|
1240
|
+
if (sessionId) {
|
|
1241
|
+
return sessionManager.getSubscriptions(sessionId);
|
|
1242
|
+
}
|
|
1243
|
+
return Array.from(sessionManager.getAllSubscribedUris());
|
|
1244
|
+
}
|
|
1245
|
+
function isSubscribed(uri, sessionId) {
|
|
1246
|
+
if (sessionId) {
|
|
1247
|
+
return sessionManager.isSubscribed(sessionId, uri);
|
|
1248
|
+
}
|
|
1249
|
+
return sessionManager.getAllSubscribedUris().has(uri);
|
|
1250
|
+
}
|
|
1251
|
+
function notify(uri, data) {
|
|
1252
|
+
if (_notifyFn) {
|
|
1253
|
+
_notifyFn(uri, data);
|
|
1254
|
+
}
|
|
1255
|
+
}
|
|
1256
|
+
|
|
1257
|
+
// src/sse-session.js
|
|
1258
|
+
import { randomUUID as randomUUID2 } from "crypto";
|
|
1259
|
+
var DEFAULT_HEARTBEAT_INTERVAL = 3e4;
|
|
1260
|
+
var DEFAULT_RETRY_INTERVAL = 3e4;
|
|
1261
|
+
var MAX_SENT_MESSAGES = 1e3;
|
|
1262
|
+
var SSE_EVENTS = {
|
|
1263
|
+
MESSAGE: "message",
|
|
1264
|
+
ENDPOINT: "endpoint",
|
|
1265
|
+
PING: "ping",
|
|
1266
|
+
ERROR: "error",
|
|
1267
|
+
PROGRESS: "progress",
|
|
1268
|
+
CAPABILITIES: "capabilities"
|
|
1269
|
+
};
|
|
1270
|
+
var SseSession = class {
|
|
1271
|
+
#res;
|
|
1272
|
+
#clientId;
|
|
1273
|
+
#active = true;
|
|
1274
|
+
#heartbeatTimer = null;
|
|
1275
|
+
#lastEventId = 0;
|
|
1276
|
+
#heartbeatInterval;
|
|
1277
|
+
#retryInterval;
|
|
1278
|
+
#sessionData = {};
|
|
1279
|
+
#sentMessages = [];
|
|
1280
|
+
#backpressureBuffer = [];
|
|
1281
|
+
#drainHandler = null;
|
|
1282
|
+
constructor(res, options = {}) {
|
|
1283
|
+
this.#res = res;
|
|
1284
|
+
this.#clientId = options.clientId || randomUUID2();
|
|
1285
|
+
this.#heartbeatInterval = options.heartbeatInterval || DEFAULT_HEARTBEAT_INTERVAL;
|
|
1286
|
+
this.#retryInterval = options.retryInterval || DEFAULT_RETRY_INTERVAL;
|
|
1287
|
+
this.#sessionData = options.sessionData || {};
|
|
1288
|
+
if (options.resumeFromId && options.resumeFromId > 0) {
|
|
1289
|
+
this.#lastEventId = options.resumeFromId;
|
|
1290
|
+
}
|
|
1291
|
+
this._setupSseHeaders();
|
|
1292
|
+
this._sendRetry();
|
|
1293
|
+
this._setupDrain();
|
|
1294
|
+
}
|
|
1295
|
+
get clientId() {
|
|
1296
|
+
return this.#clientId;
|
|
1297
|
+
}
|
|
1298
|
+
get isActive() {
|
|
1299
|
+
return this.#active;
|
|
1300
|
+
}
|
|
1301
|
+
get lastEventId() {
|
|
1302
|
+
return this.#lastEventId;
|
|
1303
|
+
}
|
|
1304
|
+
get sessionData() {
|
|
1305
|
+
return this.#sessionData;
|
|
1306
|
+
}
|
|
1307
|
+
get sentMessages() {
|
|
1308
|
+
return [...this.#sentMessages];
|
|
1309
|
+
}
|
|
1310
|
+
getMessagesSince(eventId) {
|
|
1311
|
+
return this.#sentMessages.filter((m) => m.id > eventId);
|
|
1312
|
+
}
|
|
1313
|
+
setSessionData(key, value) {
|
|
1314
|
+
this.#sessionData[key] = value;
|
|
1315
|
+
}
|
|
1316
|
+
getSessionData(key) {
|
|
1317
|
+
return this.#sessionData[key];
|
|
1318
|
+
}
|
|
1319
|
+
get retryInterval() {
|
|
1320
|
+
return this.#retryInterval;
|
|
1321
|
+
}
|
|
1322
|
+
setRetryInterval(ms) {
|
|
1323
|
+
this.#retryInterval = ms;
|
|
1324
|
+
}
|
|
1325
|
+
_sendRetry() {
|
|
1326
|
+
this._write(`retry: ${this.#retryInterval}
|
|
1327
|
+
|
|
1328
|
+
`);
|
|
1329
|
+
}
|
|
1330
|
+
_setupSseHeaders() {
|
|
1331
|
+
this.#res.setHeader("Content-Type", "text/event-stream");
|
|
1332
|
+
this.#res.setHeader("Cache-Control", "no-cache");
|
|
1333
|
+
this.#res.setHeader("Connection", "keep-alive");
|
|
1334
|
+
this.#res.setHeader("Transfer-Encoding", "chunked");
|
|
1335
|
+
this.#res.setHeader("X-Accel-Buffering", "no");
|
|
1336
|
+
if (typeof this.#res.flush !== "function") {
|
|
1337
|
+
this.#res.flush = () => {
|
|
1338
|
+
};
|
|
1339
|
+
}
|
|
1340
|
+
}
|
|
1341
|
+
_formatEvent(event, data, id = null) {
|
|
1342
|
+
const lines = [];
|
|
1343
|
+
if (id !== null) {
|
|
1344
|
+
lines.push(`id: ${id}`);
|
|
1345
|
+
}
|
|
1346
|
+
lines.push(`event: ${event}`);
|
|
1347
|
+
if (data !== null && data !== void 0) {
|
|
1348
|
+
const jsonStr = JSON.stringify(data);
|
|
1349
|
+
lines.push(`data: ${jsonStr}`);
|
|
1350
|
+
} else {
|
|
1351
|
+
lines.push("data:");
|
|
1352
|
+
}
|
|
1353
|
+
return lines.join("\n") + "\n\n";
|
|
1354
|
+
}
|
|
1355
|
+
_setupDrain() {
|
|
1356
|
+
if (typeof this.#res.on !== "function") return;
|
|
1357
|
+
this.#drainHandler = () => {
|
|
1358
|
+
if (!this.#active) return;
|
|
1359
|
+
if (this.#backpressureBuffer.length > 0) {
|
|
1360
|
+
this._drainBuffer();
|
|
1361
|
+
}
|
|
1362
|
+
};
|
|
1363
|
+
this.#res.on("drain", this.#drainHandler);
|
|
1364
|
+
}
|
|
1365
|
+
_drainBuffer() {
|
|
1366
|
+
const batch = this.#backpressureBuffer.splice(0, 50);
|
|
1367
|
+
for (const item of batch) {
|
|
1368
|
+
const ok = this.#res.write(item);
|
|
1369
|
+
if (!ok) {
|
|
1370
|
+
this.#backpressureBuffer.unshift(...batch.slice(batch.indexOf(item)));
|
|
1371
|
+
return;
|
|
1372
|
+
}
|
|
1373
|
+
}
|
|
1374
|
+
this._flush();
|
|
1375
|
+
if (this.#backpressureBuffer.length > 0) {
|
|
1376
|
+
this._drainBuffer();
|
|
1377
|
+
}
|
|
1378
|
+
}
|
|
1379
|
+
_write(content) {
|
|
1380
|
+
if (!this.#active) return false;
|
|
1381
|
+
try {
|
|
1382
|
+
if (this.#backpressureBuffer.length > 0) {
|
|
1383
|
+
this.#backpressureBuffer.push(content);
|
|
1384
|
+
return true;
|
|
1385
|
+
}
|
|
1386
|
+
const result = this.#res.write(content);
|
|
1387
|
+
if (typeof this.#res.flush === "function") {
|
|
1388
|
+
this.#res.flush();
|
|
1389
|
+
}
|
|
1390
|
+
if (result === false) {
|
|
1391
|
+
this.#backpressureBuffer.push(content);
|
|
1392
|
+
return true;
|
|
1393
|
+
}
|
|
1394
|
+
return true;
|
|
1395
|
+
} catch (e) {
|
|
1396
|
+
this.#active = false;
|
|
1397
|
+
this.close();
|
|
1398
|
+
return false;
|
|
1399
|
+
}
|
|
1400
|
+
}
|
|
1401
|
+
_flush() {
|
|
1402
|
+
try {
|
|
1403
|
+
if (typeof this.#res.flush === "function") {
|
|
1404
|
+
this.#res.flush();
|
|
1405
|
+
}
|
|
1406
|
+
} catch (e) {
|
|
1407
|
+
}
|
|
1408
|
+
}
|
|
1409
|
+
flushBackpressure() {
|
|
1410
|
+
if (this.#backpressureBuffer.length > 0) {
|
|
1411
|
+
this._drainBuffer();
|
|
1412
|
+
}
|
|
1413
|
+
}
|
|
1414
|
+
sendEvent(event, data, id = null) {
|
|
1415
|
+
this.#lastEventId++;
|
|
1416
|
+
const eventId = id !== null ? id : this.#lastEventId;
|
|
1417
|
+
const formatted = this._formatEvent(event, data, eventId);
|
|
1418
|
+
this.#sentMessages.push({ event, data, id: eventId, timestamp: Date.now() });
|
|
1419
|
+
if (this.#sentMessages.length > MAX_SENT_MESSAGES) {
|
|
1420
|
+
this.#sentMessages.splice(0, this.#sentMessages.length - MAX_SENT_MESSAGES);
|
|
1421
|
+
}
|
|
1422
|
+
this._write(formatted);
|
|
1423
|
+
this._flush();
|
|
1424
|
+
return true;
|
|
1425
|
+
}
|
|
1426
|
+
sendMessage(data) {
|
|
1427
|
+
return this.sendEvent(SSE_EVENTS.MESSAGE, data);
|
|
1428
|
+
}
|
|
1429
|
+
sendEndpoint(path9) {
|
|
1430
|
+
return this.sendEvent(SSE_EVENTS.ENDPOINT, path9);
|
|
1431
|
+
}
|
|
1432
|
+
sendError(code, message, id = null) {
|
|
1433
|
+
return this.sendEvent(SSE_EVENTS.ERROR, { code, message }, id);
|
|
1434
|
+
}
|
|
1435
|
+
sendPing() {
|
|
1436
|
+
return this.sendEvent(SSE_EVENTS.PING, { timestamp: Date.now() });
|
|
1437
|
+
}
|
|
1438
|
+
sendProgress(current, total, message = "") {
|
|
1439
|
+
return this.sendEvent(SSE_EVENTS.PROGRESS, { current, total, message });
|
|
1440
|
+
}
|
|
1441
|
+
sendCapabilities(capabilities) {
|
|
1442
|
+
return this.sendEvent(SSE_EVENTS.CAPABILITIES, capabilities);
|
|
1443
|
+
}
|
|
1444
|
+
sendResponse(jsonrpcResponse, id = null) {
|
|
1445
|
+
const eventId = id !== null ? id : this.#lastEventId;
|
|
1446
|
+
return this.sendEvent(SSE_EVENTS.MESSAGE, jsonrpcResponse, eventId);
|
|
1447
|
+
}
|
|
1448
|
+
startHeartbeat(interval = null) {
|
|
1449
|
+
this.stopHeartbeat();
|
|
1450
|
+
const ms = interval || this.#heartbeatInterval;
|
|
1451
|
+
this.#heartbeatTimer = setInterval(() => {
|
|
1452
|
+
if (!this.#active) {
|
|
1453
|
+
this.stopHeartbeat();
|
|
1454
|
+
return;
|
|
1455
|
+
}
|
|
1456
|
+
if (!this.sendPing()) {
|
|
1457
|
+
this.stopHeartbeat();
|
|
1458
|
+
this.close();
|
|
1459
|
+
}
|
|
1460
|
+
}, ms);
|
|
1461
|
+
}
|
|
1462
|
+
stopHeartbeat() {
|
|
1463
|
+
if (this.#heartbeatTimer) {
|
|
1464
|
+
clearInterval(this.#heartbeatTimer);
|
|
1465
|
+
this.#heartbeatTimer = null;
|
|
1466
|
+
}
|
|
1467
|
+
}
|
|
1468
|
+
close() {
|
|
1469
|
+
this.#active = false;
|
|
1470
|
+
this.stopHeartbeat();
|
|
1471
|
+
if (this.#drainHandler) {
|
|
1472
|
+
this.#res.removeListener("drain", this.#drainHandler);
|
|
1473
|
+
this.#drainHandler = null;
|
|
1474
|
+
}
|
|
1475
|
+
this.#backpressureBuffer = [];
|
|
1476
|
+
try {
|
|
1477
|
+
this.#res.end();
|
|
1478
|
+
} catch (e) {
|
|
1479
|
+
}
|
|
1480
|
+
}
|
|
1481
|
+
};
|
|
1482
|
+
|
|
1483
|
+
// src/sse-session-manager.js
|
|
1484
|
+
import fs3 from "fs";
|
|
1485
|
+
import path4 from "path";
|
|
1486
|
+
import os2 from "os";
|
|
1487
|
+
var SESSION_STORE_DIR = path4.join(os2.homedir(), ".atlisp", "sessions");
|
|
1488
|
+
var SESSION_STORE_TTL = 24 * 60 * 60 * 1e3;
|
|
1489
|
+
function getSessionStorePath(clientId) {
|
|
1490
|
+
return path4.join(SESSION_STORE_DIR, `${clientId}.json`);
|
|
1491
|
+
}
|
|
1492
|
+
function persistSessionData(clientId, sessionData) {
|
|
1493
|
+
try {
|
|
1494
|
+
fs3.mkdirSync(SESSION_STORE_DIR, { recursive: true });
|
|
1495
|
+
const store = {
|
|
1496
|
+
clientId,
|
|
1497
|
+
sessionData,
|
|
1498
|
+
savedAt: Date.now()
|
|
1499
|
+
};
|
|
1500
|
+
fs3.writeFileSync(getSessionStorePath(clientId), JSON.stringify(store), "utf-8");
|
|
1501
|
+
} catch (e) {
|
|
1502
|
+
console.error("Failed to persist session:", e.message);
|
|
1503
|
+
}
|
|
1504
|
+
}
|
|
1505
|
+
function loadPersistedSessionData(clientId) {
|
|
1506
|
+
try {
|
|
1507
|
+
const filePath = getSessionStorePath(clientId);
|
|
1508
|
+
if (!fs3.existsSync(filePath)) return null;
|
|
1509
|
+
const raw = fs3.readFileSync(filePath, "utf-8");
|
|
1510
|
+
const store = JSON.parse(raw);
|
|
1511
|
+
if (Date.now() - store.savedAt > SESSION_STORE_TTL) {
|
|
1512
|
+
fs3.unlinkSync(filePath);
|
|
1513
|
+
return null;
|
|
1514
|
+
}
|
|
1515
|
+
return store.sessionData || {};
|
|
1516
|
+
} catch (e) {
|
|
1517
|
+
return null;
|
|
1518
|
+
}
|
|
1519
|
+
}
|
|
1520
|
+
var SseSessionManager = class {
|
|
1521
|
+
#sessions = /* @__PURE__ */ new Map();
|
|
1522
|
+
#eventHandlers = /* @__PURE__ */ new Map();
|
|
1523
|
+
constructor() {
|
|
1524
|
+
this.#sessions = /* @__PURE__ */ new Map();
|
|
1525
|
+
this.#eventHandlers = /* @__PURE__ */ new Map();
|
|
1526
|
+
}
|
|
1527
|
+
add(clientId, session) {
|
|
1528
|
+
if (!(session instanceof SseSession)) {
|
|
1529
|
+
throw new Error("session must be an SseSession instance");
|
|
1530
|
+
}
|
|
1531
|
+
const persisted = loadPersistedSessionData(clientId);
|
|
1532
|
+
if (persisted) {
|
|
1533
|
+
for (const [key, value] of Object.entries(persisted)) {
|
|
1534
|
+
session.setSessionData(key, value);
|
|
1535
|
+
}
|
|
1536
|
+
}
|
|
1537
|
+
this.#sessions.set(clientId, session);
|
|
1538
|
+
session.startHeartbeat();
|
|
1539
|
+
}
|
|
1540
|
+
remove(clientId) {
|
|
1541
|
+
const session = this.#sessions.get(clientId);
|
|
1542
|
+
if (session) {
|
|
1543
|
+
persistSessionData(clientId, session.sessionData);
|
|
1544
|
+
session.close();
|
|
1545
|
+
this.#sessions.delete(clientId);
|
|
1546
|
+
return true;
|
|
1547
|
+
}
|
|
1548
|
+
return false;
|
|
1549
|
+
}
|
|
1550
|
+
get(clientId) {
|
|
1551
|
+
return this.#sessions.get(clientId) || null;
|
|
1552
|
+
}
|
|
1553
|
+
has(clientId) {
|
|
1554
|
+
return this.#sessions.has(clientId);
|
|
1555
|
+
}
|
|
1556
|
+
list() {
|
|
1557
|
+
return Array.from(this.#sessions.keys()).map((id) => ({
|
|
1558
|
+
clientId: id,
|
|
1559
|
+
isActive: this.#sessions.get(id)?.isActive ?? false
|
|
1560
|
+
}));
|
|
1561
|
+
}
|
|
1562
|
+
listActive() {
|
|
1563
|
+
return this.list().filter((s) => s.isActive);
|
|
1564
|
+
}
|
|
1565
|
+
count() {
|
|
1566
|
+
return this.#sessions.size;
|
|
1567
|
+
}
|
|
1568
|
+
sendToClient(clientId, event, data, id = null) {
|
|
1569
|
+
const session = this.#sessions.get(clientId);
|
|
1570
|
+
if (!session || !session.isActive) {
|
|
1571
|
+
return false;
|
|
1572
|
+
}
|
|
1573
|
+
return session.sendEvent(event, data, id);
|
|
1574
|
+
}
|
|
1575
|
+
sendMessageToClient(clientId, data) {
|
|
1576
|
+
return this.sendToClient(clientId, SSE_EVENTS.MESSAGE, data);
|
|
1577
|
+
}
|
|
1578
|
+
sendErrorToClient(clientId, code, message, id = null) {
|
|
1579
|
+
return this.sendToClient(clientId, SSE_EVENTS.ERROR, { code, message }, id);
|
|
1580
|
+
}
|
|
1581
|
+
sendProgressToClient(clientId, current, total, message = "") {
|
|
1582
|
+
return this.sendToClient(clientId, SSE_EVENTS.PROGRESS, { current, total, message });
|
|
1583
|
+
}
|
|
1584
|
+
broadcast(event, data) {
|
|
1585
|
+
let successCount = 0;
|
|
1586
|
+
for (const [clientId, session] of this.#sessions) {
|
|
1587
|
+
if (session.isActive && session.sendEvent(event, data)) {
|
|
1588
|
+
successCount++;
|
|
1589
|
+
}
|
|
1590
|
+
}
|
|
1591
|
+
return successCount;
|
|
1592
|
+
}
|
|
1593
|
+
broadcastMessage(data) {
|
|
1594
|
+
return this.broadcast(SSE_EVENTS.MESSAGE, data);
|
|
1595
|
+
}
|
|
1596
|
+
broadcastError(code, message) {
|
|
1597
|
+
return this.broadcast(SSE_EVENTS.ERROR, { code, message });
|
|
1598
|
+
}
|
|
1599
|
+
on(event, handler) {
|
|
1600
|
+
if (!this.#eventHandlers.has(event)) {
|
|
1601
|
+
this.#eventHandlers.set(event, /* @__PURE__ */ new Set());
|
|
1602
|
+
}
|
|
1603
|
+
this.#eventHandlers.get(event).add(handler);
|
|
1604
|
+
}
|
|
1605
|
+
off(event, handler) {
|
|
1606
|
+
const handlers = this.#eventHandlers.get(event);
|
|
1607
|
+
if (handlers) {
|
|
1608
|
+
handlers.delete(handler);
|
|
1609
|
+
}
|
|
1610
|
+
}
|
|
1611
|
+
emit(event, data) {
|
|
1612
|
+
const handlers = this.#eventHandlers.get(event);
|
|
1613
|
+
if (handlers) {
|
|
1614
|
+
for (const handler of handlers) {
|
|
1615
|
+
try {
|
|
1616
|
+
handler(data);
|
|
1617
|
+
} catch (e) {
|
|
1618
|
+
}
|
|
1486
1619
|
}
|
|
1487
1620
|
}
|
|
1488
|
-
|
|
1489
|
-
|
|
1490
|
-
|
|
1491
|
-
|
|
1621
|
+
}
|
|
1622
|
+
cleanupInactive() {
|
|
1623
|
+
for (const [clientId, session] of this.#sessions) {
|
|
1624
|
+
if (!session.isActive) {
|
|
1625
|
+
session.close();
|
|
1626
|
+
this.#sessions.delete(clientId);
|
|
1492
1627
|
}
|
|
1628
|
+
}
|
|
1629
|
+
}
|
|
1630
|
+
closeAll() {
|
|
1631
|
+
for (const [clientId, session] of this.#sessions) {
|
|
1632
|
+
persistSessionData(clientId, session.sessionData);
|
|
1633
|
+
session.close();
|
|
1634
|
+
}
|
|
1635
|
+
this.#sessions.clear();
|
|
1636
|
+
}
|
|
1637
|
+
};
|
|
1638
|
+
|
|
1639
|
+
// src/routes.js
|
|
1640
|
+
import express from "express";
|
|
1641
|
+
import { randomUUID as randomUUID4 } from "crypto";
|
|
1642
|
+
import iconv from "iconv-lite";
|
|
1643
|
+
import rateLimit from "express-rate-limit";
|
|
1644
|
+
|
|
1645
|
+
// src/mcp-server-state.js
|
|
1646
|
+
import { AsyncLocalStorage } from "async_hooks";
|
|
1647
|
+
|
|
1648
|
+
// src/session-transport.js
|
|
1649
|
+
import { randomUUID as randomUUID3 } from "crypto";
|
|
1650
|
+
var SESSION_TIMEOUT = 30 * 60 * 1e3;
|
|
1651
|
+
var SessionTransport = class {
|
|
1652
|
+
constructor(sessionId) {
|
|
1653
|
+
this.sessionId = sessionId || randomUUID3();
|
|
1654
|
+
this.onclose = null;
|
|
1655
|
+
this.onerror = null;
|
|
1656
|
+
this.onmessage = null;
|
|
1657
|
+
this._pendingRequest = null;
|
|
1658
|
+
this._started = false;
|
|
1659
|
+
this._closed = false;
|
|
1660
|
+
this._cleanupTimer = null;
|
|
1661
|
+
}
|
|
1662
|
+
async start() {
|
|
1663
|
+
if (this._started) {
|
|
1664
|
+
throw new Error("Transport already started");
|
|
1665
|
+
}
|
|
1666
|
+
this._started = true;
|
|
1667
|
+
}
|
|
1668
|
+
async send(message) {
|
|
1669
|
+
if (this._closed) return;
|
|
1670
|
+
if (this._pendingRequest) {
|
|
1671
|
+
const { resolve, reject, timeout } = this._pendingRequest;
|
|
1672
|
+
clearTimeout(timeout);
|
|
1673
|
+
this._pendingRequest = null;
|
|
1674
|
+
resolve(message);
|
|
1675
|
+
}
|
|
1676
|
+
}
|
|
1677
|
+
async close() {
|
|
1678
|
+
if (this._closed) return;
|
|
1679
|
+
this._closed = true;
|
|
1680
|
+
if (this._pendingRequest) {
|
|
1681
|
+
const { reject, timeout } = this._pendingRequest;
|
|
1682
|
+
clearTimeout(timeout);
|
|
1683
|
+
this._pendingRequest = null;
|
|
1684
|
+
reject(new Error("Transport closed"));
|
|
1685
|
+
}
|
|
1686
|
+
this._clearCleanupTimer();
|
|
1687
|
+
this.onclose?.();
|
|
1688
|
+
}
|
|
1689
|
+
async handleRequest(message, timeoutMs = 6e4) {
|
|
1690
|
+
if (this._closed) {
|
|
1691
|
+
throw new Error("Transport closed");
|
|
1692
|
+
}
|
|
1693
|
+
if (!message || !message.method) {
|
|
1694
|
+
throw new Error("Invalid message");
|
|
1695
|
+
}
|
|
1696
|
+
if (!message.id) {
|
|
1697
|
+
this.onmessage?.(message);
|
|
1493
1698
|
return null;
|
|
1494
|
-
}
|
|
1495
|
-
|
|
1496
|
-
|
|
1497
|
-
|
|
1498
|
-
|
|
1499
|
-
|
|
1699
|
+
}
|
|
1700
|
+
return new Promise((resolve, reject) => {
|
|
1701
|
+
const timeout = setTimeout(() => {
|
|
1702
|
+
if (this._pendingRequest?.resolve === resolve) {
|
|
1703
|
+
this._pendingRequest = null;
|
|
1704
|
+
reject(new Error("Request timeout"));
|
|
1705
|
+
}
|
|
1706
|
+
}, timeoutMs);
|
|
1707
|
+
this._pendingRequest = { resolve, reject, timeout };
|
|
1708
|
+
this.onmessage?.(message);
|
|
1709
|
+
});
|
|
1500
1710
|
}
|
|
1501
|
-
|
|
1502
|
-
|
|
1503
|
-
|
|
1504
|
-
|
|
1505
|
-
|
|
1506
|
-
return JSON.parse(raw);
|
|
1507
|
-
} catch (e) {
|
|
1508
|
-
log(`Error loading standards file ${filename}: ${e.message}`);
|
|
1509
|
-
return null;
|
|
1711
|
+
resetCleanupTimer() {
|
|
1712
|
+
this._clearCleanupTimer();
|
|
1713
|
+
this._cleanupTimer = setTimeout(() => {
|
|
1714
|
+
this.close();
|
|
1715
|
+
}, SESSION_TIMEOUT);
|
|
1510
1716
|
}
|
|
1511
|
-
|
|
1512
|
-
|
|
1513
|
-
|
|
1514
|
-
|
|
1515
|
-
|
|
1516
|
-
return null;
|
|
1517
|
-
}
|
|
1518
|
-
function setCachedStandards(key, data) {
|
|
1519
|
-
standardsCache.set(key, { data, timestamp: Date.now() });
|
|
1520
|
-
}
|
|
1521
|
-
function getDraftingStandards() {
|
|
1522
|
-
const cached = getCachedStandards("drafting");
|
|
1523
|
-
if (cached) return cached;
|
|
1524
|
-
const data = loadStandardsFile("drafting.json");
|
|
1525
|
-
if (data) setCachedStandards("drafting", data);
|
|
1526
|
-
return data || { error: "\u5236\u56FE\u89C4\u8303\u6587\u4EF6\u52A0\u8F7D\u5931\u8D25" };
|
|
1527
|
-
}
|
|
1528
|
-
function getCodingStandards() {
|
|
1529
|
-
const cached = getCachedStandards("coding");
|
|
1530
|
-
if (cached) return cached;
|
|
1531
|
-
const data = loadStandardsFile("coding.json");
|
|
1532
|
-
if (data) setCachedStandards("coding", data);
|
|
1533
|
-
return data || { error: "\u7F16\u7801\u89C4\u8303\u6587\u4EF6\u52A0\u8F7D\u5931\u8D25" };
|
|
1534
|
-
}
|
|
1535
|
-
var __dirname2, STANDARDS_DIR, CACHE_TTL2, resourceCache, RESOURCES, standardsCache;
|
|
1536
|
-
var init_resource_handlers = __esm({
|
|
1537
|
-
"src/handlers/resource-handlers.js"() {
|
|
1538
|
-
init_cad();
|
|
1539
|
-
init_constants();
|
|
1540
|
-
init_logger();
|
|
1541
|
-
init_config();
|
|
1542
|
-
__dirname2 = path4.dirname(fileURLToPath2(import.meta.url));
|
|
1543
|
-
STANDARDS_DIR = path4.join(__dirname2, "..", "standards");
|
|
1544
|
-
CACHE_TTL2 = config_default.resourceCacheTtl;
|
|
1545
|
-
resourceCache = /* @__PURE__ */ new Map();
|
|
1546
|
-
RESOURCES = [
|
|
1547
|
-
{ uri: "atlisp://cad/info", name: "CAD Info", description: "CAD \u8FDE\u63A5\u4FE1\u606F", mimeType: "application/json", subscribable: true },
|
|
1548
|
-
{ uri: "atlisp://dwg/layers", name: "Layers", description: "\u56FE\u5C42\u5217\u8868", mimeType: "application/json", subscribable: true },
|
|
1549
|
-
{ uri: "atlisp://dwg/entities", name: "Entities", description: "\u56FE\u5143\u5217\u8868\uFF0C\u8FD4\u56DE\u603B\u6570\u548C\u524D3000\u4E2A\u56FE\u5143\uFF0C\u6587\u672C\u9644\u52A0 text \u5B57\u6BB5\uFF0C\u66F2\u7EBF\u9644\u52A0 points \u6570\u7EC4\uFF0CINSERT \u9644\u52A0 blockName\uFF0C\u652F\u6301 ?type=LINE&layer=0&bbox=0,0,100,100 \u8FC7\u6EE4", mimeType: "application/json", subscribable: true },
|
|
1550
|
-
{ 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=5000&offset=0", mimeType: "application/json", subscribable: true },
|
|
1551
|
-
{ uri: "atlisp://dwg/name", name: "DWG Name", description: "\u5F53\u524D DWG \u6587\u4EF6\u540D", mimeType: "application/json", subscribable: true },
|
|
1552
|
-
{ uri: "atlisp://dwg/path", name: "DWG Path", description: "\u6587\u4EF6\u5B8C\u6574\u8DEF\u5F84", mimeType: "application/json", subscribable: true },
|
|
1553
|
-
{ uri: "atlisp://cad/dwgs", name: "DWG List", description: "\u6240\u6709\u6253\u5F00\u7684 DWG \u6587\u4EF6\u5217\u8868", mimeType: "application/json", subscribable: true },
|
|
1554
|
-
{ uri: "atlisp://packages", name: "Packages", description: "\u5DF2\u5B89\u88C5\u5305\u5217\u8868", mimeType: "application/json", subscribable: true },
|
|
1555
|
-
{ uri: "atlisp://platforms", name: "Platforms", description: "\u652F\u6301\u7684\u5E73\u53F0\u4FE1\u606F", mimeType: "application/json", subscribable: false },
|
|
1556
|
-
{ uri: "atlisp://standards/drafting", name: "Drafting Standards", description: "CAD \u5236\u56FE\u89C4\u8303", mimeType: "application/json", subscribable: false },
|
|
1557
|
-
{ uri: "atlisp://standards/coding", name: "Coding Standards", description: "@lisp \u7F16\u7801\u89C4\u8303", mimeType: "application/json", subscribable: false }
|
|
1558
|
-
];
|
|
1559
|
-
standardsCache = /* @__PURE__ */ new Map();
|
|
1717
|
+
_clearCleanupTimer() {
|
|
1718
|
+
if (this._cleanupTimer) {
|
|
1719
|
+
clearTimeout(this._cleanupTimer);
|
|
1720
|
+
this._cleanupTimer = null;
|
|
1721
|
+
}
|
|
1560
1722
|
}
|
|
1561
|
-
}
|
|
1723
|
+
};
|
|
1724
|
+
|
|
1725
|
+
// src/mcp-handlers.js
|
|
1726
|
+
import {
|
|
1727
|
+
ListToolsRequestSchema,
|
|
1728
|
+
CallToolRequestSchema,
|
|
1729
|
+
ListResourcesRequestSchema,
|
|
1730
|
+
ReadResourceRequestSchema,
|
|
1731
|
+
SubscribeRequestSchema,
|
|
1732
|
+
UnsubscribeRequestSchema,
|
|
1733
|
+
ListPromptsRequestSchema,
|
|
1734
|
+
GetPromptRequestSchema
|
|
1735
|
+
} from "@modelcontextprotocol/sdk/types.js";
|
|
1736
|
+
import { Server } from "@modelcontextprotocol/sdk/server/index.js";
|
|
1562
1737
|
|
|
1563
1738
|
// src/handlers/prompt-handlers.js
|
|
1564
1739
|
import fs4 from "fs";
|
|
1565
1740
|
import path5 from "path";
|
|
1566
1741
|
import { fileURLToPath as fileURLToPath3 } from "url";
|
|
1742
|
+
var __dirname3 = path5.dirname(fileURLToPath3(import.meta.url));
|
|
1743
|
+
var PROMPTS_DIR = path5.join(__dirname3, "..", "prompts");
|
|
1744
|
+
var externalPrompts = null;
|
|
1745
|
+
var externalPromptsAt = 0;
|
|
1746
|
+
var EXTERNAL_PROMPTS_TTL = 3e4;
|
|
1567
1747
|
function loadExternalPrompts() {
|
|
1568
1748
|
const now = Date.now();
|
|
1569
1749
|
if (externalPrompts && now - externalPromptsAt < EXTERNAL_PROMPTS_TTL) {
|
|
@@ -1593,6 +1773,121 @@ function loadExternalPrompts() {
|
|
|
1593
1773
|
externalPromptsAt = now;
|
|
1594
1774
|
return externalPrompts;
|
|
1595
1775
|
}
|
|
1776
|
+
var PROMPTS = [
|
|
1777
|
+
{
|
|
1778
|
+
name: "analyze-drawing",
|
|
1779
|
+
description: "\u5206\u6790\u5F53\u524D\u56FE\u7EB8\u7EDF\u8BA1\u4FE1\u606F",
|
|
1780
|
+
arguments: []
|
|
1781
|
+
},
|
|
1782
|
+
{
|
|
1783
|
+
name: "batch-draw-lines",
|
|
1784
|
+
description: "\u6279\u91CF\u7ED8\u5236\u7EBF\u6BB5",
|
|
1785
|
+
arguments: [
|
|
1786
|
+
{ name: "count", description: "\u7EBF\u6BB5\u6570\u91CF", required: true },
|
|
1787
|
+
{ name: "length", description: "\u7EBF\u6BB5\u957F\u5EA6", required: false }
|
|
1788
|
+
]
|
|
1789
|
+
},
|
|
1790
|
+
{
|
|
1791
|
+
name: "generate-dimension",
|
|
1792
|
+
description: "\u751F\u6210\u5C3A\u5BF8\u6807\u6CE8",
|
|
1793
|
+
arguments: [
|
|
1794
|
+
{ name: "style", description: "\u6807\u6CE8\u6837\u5F0F (horizontal/vertical/aligned)", required: false }
|
|
1795
|
+
]
|
|
1796
|
+
},
|
|
1797
|
+
{
|
|
1798
|
+
name: "export-entities",
|
|
1799
|
+
description: "\u5BFC\u51FA\u56FE\u7EB8\u5B9E\u4F53\u7EDF\u8BA1",
|
|
1800
|
+
arguments: [
|
|
1801
|
+
{ name: "format", description: "\u5BFC\u51FA\u683C\u5F0F (json/list)", required: false }
|
|
1802
|
+
]
|
|
1803
|
+
},
|
|
1804
|
+
{
|
|
1805
|
+
name: "manage-layers",
|
|
1806
|
+
description: "\u56FE\u5C42\u7BA1\u7406\uFF1A\u521B\u5EFA\u3001\u51BB\u7ED3\u3001\u9501\u5B9A\u3001\u5220\u9664\u56FE\u5C42",
|
|
1807
|
+
arguments: [
|
|
1808
|
+
{ name: "action", description: "\u64CD\u4F5C\u7C7B\u578B (list/freeze/lock/off/make/delete)", required: true },
|
|
1809
|
+
{ name: "layers", description: "\u56FE\u5C42\u540D\uFF0C\u591A\u4E2A\u7528\u9017\u53F7\u5206\u9694", required: false },
|
|
1810
|
+
{ name: "color", description: '\u56FE\u5C42\u989C\u8272 (ACI\u53F7\u6216RGB\u5982 "1,2,3")', required: false }
|
|
1811
|
+
]
|
|
1812
|
+
},
|
|
1813
|
+
{
|
|
1814
|
+
name: "manage-blocks",
|
|
1815
|
+
description: "\u5757\u64CD\u4F5C\uFF1A\u63D2\u5165\u5757\u3001\u5217\u51FA\u5757\u3001\u83B7\u53D6/\u8BBE\u7F6E\u5C5E\u6027",
|
|
1816
|
+
arguments: [
|
|
1817
|
+
{ name: "action", description: "\u64CD\u4F5C\u7C7B\u578B (list/insert/attributes/dynprops)", required: true },
|
|
1818
|
+
{ name: "blockName", description: "\u5757\u540D", required: false },
|
|
1819
|
+
{ name: "insertPoint", description: '\u63D2\u5165\u70B9 "x,y"', required: false },
|
|
1820
|
+
{ name: "scale", description: "\u7F29\u653E\u6BD4\u4F8B", required: false }
|
|
1821
|
+
]
|
|
1822
|
+
},
|
|
1823
|
+
{
|
|
1824
|
+
name: "curve-analysis",
|
|
1825
|
+
description: "\u66F2\u7EBF\u5206\u6790\uFF1A\u4EA4\u70B9\u3001\u6700\u8FD1\u70B9\u3001\u5B50\u6BB5\u3001\u7F13\u51B2\u533A",
|
|
1826
|
+
arguments: [
|
|
1827
|
+
{ name: "action", description: "\u64CD\u4F5C (inters/subsegments/closestpoint/join)", required: true },
|
|
1828
|
+
{ name: "distance", description: "\u8FDE\u63A5\u5BB9\u5DEE/\u504F\u79FB\u8DDD\u79BB", required: false }
|
|
1829
|
+
]
|
|
1830
|
+
},
|
|
1831
|
+
{
|
|
1832
|
+
name: "geometry-calc",
|
|
1833
|
+
description: "\u51E0\u4F55\u8BA1\u7B97\uFF1A\u51F8\u5305\u3001\u70B9\u5230\u7EBF\u8DDD\u79BB\u3001\u9762\u5185\u6D4B\u8BD5\u3001\u53D8\u6362",
|
|
1834
|
+
arguments: [
|
|
1835
|
+
{ name: "action", description: "\u64CD\u4F5C (convexhull/dist-point-line/in-curve-p/transform/centroid)", required: true },
|
|
1836
|
+
{ name: "points", description: '\u70B9\u96C6 "x1,y1;x2,y2;..."', required: false }
|
|
1837
|
+
]
|
|
1838
|
+
},
|
|
1839
|
+
{
|
|
1840
|
+
name: "text-process",
|
|
1841
|
+
description: "\u6587\u672C\u5904\u7406\uFF1AMTEXT\u89E3\u6790\u3001Markdown\u8F6CMTEXT\u3001\u53BB\u683C\u5F0F",
|
|
1842
|
+
arguments: [
|
|
1843
|
+
{ name: "action", description: "\u64CD\u4F5C (parse-mtext/remove-fmt/from-markdown/mtext2text)", required: true },
|
|
1844
|
+
{ name: "markdown", description: "Markdown\u6587\u672C\uFF08from-markdown\u64CD\u4F5C\u65F6\u7528\uFF09", required: false }
|
|
1845
|
+
]
|
|
1846
|
+
},
|
|
1847
|
+
{
|
|
1848
|
+
name: "pickset-filter",
|
|
1849
|
+
description: "\u9009\u62E9\u96C6\u64CD\u4F5C\uFF1A\u8FC7\u6EE4\u3001\u8F6C\u6362\u3001\u6279\u91CF\u64CD\u4F5C",
|
|
1850
|
+
arguments: [
|
|
1851
|
+
{ name: "action", description: "\u64CD\u4F5C (by-layer/by-type/by-box/erase/zoom)", required: true },
|
|
1852
|
+
{ name: "dxfType", description: 'DXF\u7C7B\u578B "LINE, CIRCLE, LWPOLYLINE, INSERT, TEXT"', required: false },
|
|
1853
|
+
{ name: "layerName", description: "\u56FE\u5C42\u540D", required: false }
|
|
1854
|
+
]
|
|
1855
|
+
},
|
|
1856
|
+
{
|
|
1857
|
+
name: "color-convert",
|
|
1858
|
+
description: "\u989C\u8272\u8F6C\u6362\uFF1AACI/RGB/TrueColor/CSS\u4E92\u8F6C",
|
|
1859
|
+
arguments: [
|
|
1860
|
+
{ name: "action", description: "\u64CD\u4F5C (aci2rgb/rgb2css/truecolor2rgb/rgb2truecolor)", required: true },
|
|
1861
|
+
{ name: "value", description: "\u989C\u8272\u503C", required: true }
|
|
1862
|
+
]
|
|
1863
|
+
},
|
|
1864
|
+
{
|
|
1865
|
+
name: "json-exchange",
|
|
1866
|
+
description: "JSON\u6570\u636E\u4EA4\u6362\uFF1A\u4ECE\u5B57\u7B26\u4E32\u89E3\u6790JSON alist\uFF0C\u4ECEalist\u751F\u6210JSON",
|
|
1867
|
+
arguments: [
|
|
1868
|
+
{ name: "action", description: "\u64CD\u4F5C (encode/decode)", required: true },
|
|
1869
|
+
{ name: "data", description: "JSON\u5B57\u7B26\u4E32\u6216Lisp alist\u6587\u672C", required: true }
|
|
1870
|
+
]
|
|
1871
|
+
},
|
|
1872
|
+
{
|
|
1873
|
+
name: "excel-report",
|
|
1874
|
+
description: "Excel\u62A5\u8868\uFF1A\u5BFC\u51FACAD\u5B9E\u4F53\u6570\u636E\u5230Excel",
|
|
1875
|
+
arguments: [
|
|
1876
|
+
{ name: "visible", description: "\u662F\u5426\u663E\u793AExcel\u7A97\u53E3 (true/false)", required: false },
|
|
1877
|
+
{ name: "savePath", description: "\u4FDD\u5B58\u8DEF\u5F84\uFF0C\u4E0D\u586B\u5219\u4E0D\u4FDD\u5B58", required: false }
|
|
1878
|
+
]
|
|
1879
|
+
},
|
|
1880
|
+
{
|
|
1881
|
+
name: "string-process",
|
|
1882
|
+
description: "\u5B57\u7B26\u4E32\u5904\u7406\uFF1A\u683C\u5F0F\u5316\u3001\u62C6\u5206\u3001\u66FF\u6362\u3001\u6B63\u5219",
|
|
1883
|
+
arguments: [
|
|
1884
|
+
{ name: "action", description: "\u64CD\u4F5C (format/split/subst-all/regexp/trim/number2chinese)", required: true },
|
|
1885
|
+
{ name: "input", description: "\u8F93\u5165\u5B57\u7B26\u4E32", required: true },
|
|
1886
|
+
{ name: "arg1", description: "\u53C2\u65701\uFF08\u683C\u5F0F\u53C2\u6570/\u5206\u9694\u7B26/\u65E7\u4E32\uFF09", required: false },
|
|
1887
|
+
{ name: "arg2", description: "\u53C2\u65702\uFF08\u65B0\u4E32/\u6B63\u5219\u6A21\u5F0F\uFF09", required: false }
|
|
1888
|
+
]
|
|
1889
|
+
}
|
|
1890
|
+
];
|
|
1596
1891
|
function findExternalPrompt(name) {
|
|
1597
1892
|
const ext = loadExternalPrompts();
|
|
1598
1893
|
return ext.find((p) => p.name === name);
|
|
@@ -2209,825 +2504,766 @@ ${code}
|
|
|
2209
2504
|
}]
|
|
2210
2505
|
};
|
|
2211
2506
|
}
|
|
2212
|
-
|
|
2213
|
-
|
|
2214
|
-
|
|
2215
|
-
|
|
2216
|
-
|
|
2217
|
-
|
|
2218
|
-
|
|
2219
|
-
|
|
2220
|
-
|
|
2221
|
-
|
|
2222
|
-
|
|
2223
|
-
|
|
2224
|
-
|
|
2225
|
-
|
|
2226
|
-
|
|
2227
|
-
|
|
2228
|
-
|
|
2229
|
-
|
|
2230
|
-
|
|
2231
|
-
|
|
2232
|
-
|
|
2233
|
-
|
|
2234
|
-
|
|
2235
|
-
|
|
2236
|
-
|
|
2237
|
-
|
|
2238
|
-
|
|
2239
|
-
|
|
2240
|
-
|
|
2241
|
-
|
|
2242
|
-
{
|
|
2243
|
-
|
|
2244
|
-
|
|
2245
|
-
|
|
2246
|
-
|
|
2247
|
-
]
|
|
2248
|
-
}
|
|
2249
|
-
|
|
2250
|
-
|
|
2251
|
-
|
|
2252
|
-
|
|
2253
|
-
|
|
2254
|
-
|
|
2255
|
-
|
|
2256
|
-
|
|
2257
|
-
|
|
2258
|
-
|
|
2259
|
-
|
|
2260
|
-
|
|
2261
|
-
|
|
2262
|
-
|
|
2263
|
-
|
|
2264
|
-
|
|
2265
|
-
|
|
2266
|
-
|
|
2267
|
-
|
|
2268
|
-
|
|
2269
|
-
|
|
2270
|
-
|
|
2271
|
-
|
|
2272
|
-
|
|
2273
|
-
|
|
2274
|
-
|
|
2275
|
-
|
|
2276
|
-
|
|
2277
|
-
|
|
2278
|
-
|
|
2279
|
-
|
|
2280
|
-
|
|
2281
|
-
|
|
2282
|
-
|
|
2283
|
-
|
|
2284
|
-
|
|
2285
|
-
|
|
2286
|
-
|
|
2287
|
-
|
|
2288
|
-
|
|
2289
|
-
|
|
2290
|
-
|
|
2291
|
-
|
|
2292
|
-
|
|
2293
|
-
|
|
2294
|
-
|
|
2295
|
-
|
|
2296
|
-
|
|
2297
|
-
|
|
2298
|
-
|
|
2299
|
-
|
|
2300
|
-
|
|
2301
|
-
|
|
2302
|
-
|
|
2303
|
-
|
|
2304
|
-
|
|
2305
|
-
|
|
2306
|
-
|
|
2307
|
-
]
|
|
2308
|
-
}
|
|
2309
|
-
{
|
|
2310
|
-
|
|
2311
|
-
|
|
2312
|
-
|
|
2313
|
-
|
|
2314
|
-
|
|
2315
|
-
|
|
2316
|
-
|
|
2317
|
-
|
|
2318
|
-
|
|
2319
|
-
|
|
2320
|
-
|
|
2321
|
-
|
|
2322
|
-
|
|
2323
|
-
|
|
2324
|
-
|
|
2325
|
-
|
|
2326
|
-
|
|
2327
|
-
|
|
2328
|
-
|
|
2329
|
-
|
|
2330
|
-
|
|
2331
|
-
|
|
2332
|
-
|
|
2333
|
-
|
|
2334
|
-
|
|
2335
|
-
|
|
2507
|
+
|
|
2508
|
+
// src/mcp-handlers.js
|
|
2509
|
+
var SERVER_CAPABILITIES = {
|
|
2510
|
+
tools: {},
|
|
2511
|
+
resources: { subscribe: true, listChanged: true },
|
|
2512
|
+
prompts: {}
|
|
2513
|
+
};
|
|
2514
|
+
function createMcpServer(handlers = {}) {
|
|
2515
|
+
const { tools: tools2 = [], handleToolCall: handleToolCall2 = () => ({ content: [] }) } = handlers;
|
|
2516
|
+
const server = new Server(
|
|
2517
|
+
{ name: SERVER_NAME, version: SERVER_VERSION },
|
|
2518
|
+
{ capabilities: SERVER_CAPABILITIES }
|
|
2519
|
+
);
|
|
2520
|
+
server.setRequestHandler(ListToolsRequestSchema, async () => ({ tools: tools2 }));
|
|
2521
|
+
server.setRequestHandler(CallToolRequestSchema, async (request) => {
|
|
2522
|
+
const { name, arguments: args } = request.params;
|
|
2523
|
+
return await handleToolCall2(name, args || {});
|
|
2524
|
+
});
|
|
2525
|
+
server.setRequestHandler(ListResourcesRequestSchema, async (request) => {
|
|
2526
|
+
const ctx = mcpContext.getStore();
|
|
2527
|
+
const sessionId = ctx?.sessionId;
|
|
2528
|
+
const subscribedUris = sessionId ? list(sessionId) : list();
|
|
2529
|
+
return {
|
|
2530
|
+
resources: await listResources(subscribedUris)
|
|
2531
|
+
};
|
|
2532
|
+
});
|
|
2533
|
+
server.setRequestHandler(ReadResourceRequestSchema, async (request) => {
|
|
2534
|
+
const { uri } = request.params;
|
|
2535
|
+
try {
|
|
2536
|
+
const data = await readResource(uri);
|
|
2537
|
+
return {
|
|
2538
|
+
contents: [{
|
|
2539
|
+
uri,
|
|
2540
|
+
mimeType: "application/json",
|
|
2541
|
+
text: JSON.stringify(data)
|
|
2542
|
+
}]
|
|
2543
|
+
};
|
|
2544
|
+
} catch (e) {
|
|
2545
|
+
return {
|
|
2546
|
+
contents: [],
|
|
2547
|
+
isError: true,
|
|
2548
|
+
error: { code: -32603, message: e.message }
|
|
2549
|
+
};
|
|
2550
|
+
}
|
|
2551
|
+
});
|
|
2552
|
+
server.setRequestHandler(SubscribeRequestSchema, async (request) => {
|
|
2553
|
+
const { uri } = request.params;
|
|
2554
|
+
const ctx = mcpContext.getStore();
|
|
2555
|
+
subscribe(uri, ctx?.sessionId);
|
|
2556
|
+
return { success: true };
|
|
2557
|
+
});
|
|
2558
|
+
server.setRequestHandler(UnsubscribeRequestSchema, async (request) => {
|
|
2559
|
+
const { uri } = request.params;
|
|
2560
|
+
const ctx = mcpContext.getStore();
|
|
2561
|
+
unsubscribe(uri, ctx?.sessionId);
|
|
2562
|
+
return { success: true };
|
|
2563
|
+
});
|
|
2564
|
+
server.setRequestHandler(ListPromptsRequestSchema, async () => ({
|
|
2565
|
+
prompts: await listPrompts()
|
|
2566
|
+
}));
|
|
2567
|
+
server.setRequestHandler(GetPromptRequestSchema, async (request) => {
|
|
2568
|
+
const { name, arguments: args } = request.params;
|
|
2569
|
+
return await getPrompt(name, args || {});
|
|
2570
|
+
});
|
|
2571
|
+
return server;
|
|
2572
|
+
}
|
|
2573
|
+
|
|
2574
|
+
// src/handlers/cad-handlers.js
|
|
2575
|
+
async function connectCad(platform = null) {
|
|
2576
|
+
log(`connect_cad called${platform ? ` (target: ${platform})` : ""}, cad.connected before: ${cad.connected}`);
|
|
2577
|
+
try {
|
|
2578
|
+
log("calling cad.connect()...");
|
|
2579
|
+
const connected = await cad.connect(platform);
|
|
2580
|
+
log("cad.connect() returned: " + connected + ", cad.connected: " + cad.connected);
|
|
2581
|
+
if (connected) {
|
|
2582
|
+
return { content: [{ type: "text", text: `\u5DF2\u8FDE\u63A5\u5230 ${cad.getPlatform()} ${cad.getVersion()}` }] };
|
|
2583
|
+
}
|
|
2584
|
+
} catch (e) {
|
|
2585
|
+
log("connect_cad error: " + e.message);
|
|
2586
|
+
}
|
|
2587
|
+
return { content: [{ type: "text", text: "\u672A\u80FD\u8FDE\u63A5\u6216\u542F\u52A8 CAD\uFF0C\u8BF7\u786E\u4FDD CAD \u5DF2\u5B89\u88C5" }], isError: true };
|
|
2588
|
+
}
|
|
2589
|
+
async function evalLisp(code, withResult = false, encoding = null) {
|
|
2590
|
+
if (!cad.connected) {
|
|
2591
|
+
await cad.connect();
|
|
2592
|
+
}
|
|
2593
|
+
if (!cad.connected) {
|
|
2594
|
+
return { content: [{ type: "text", text: "\u672A\u8FDE\u63A5 CAD" }], isError: true };
|
|
2595
|
+
}
|
|
2596
|
+
const trimmed = (code || "").trim();
|
|
2597
|
+
if (!trimmed) return { content: [{ type: "text", text: "\u547D\u4EE4\u4E3A\u7A7A\uFF0C\u672A\u53D1\u9001" }] };
|
|
2598
|
+
try {
|
|
2599
|
+
if (withResult) {
|
|
2600
|
+
const result = await cad.sendCommandWithResult(trimmed, encoding);
|
|
2601
|
+
if (result !== null) {
|
|
2602
|
+
return { content: [{ type: "text", text: result }] };
|
|
2603
|
+
}
|
|
2604
|
+
return { content: [{ type: "text", text: "\u6267\u884C\u5931\u8D25\u6216\u65E0\u8FD4\u56DE\u503C" }], isError: true };
|
|
2605
|
+
} else {
|
|
2606
|
+
await cad.sendCommand(trimmed + "\n");
|
|
2607
|
+
return { content: [{ type: "text", text: `\u5DF2\u53D1\u9001\u547D\u4EE4` }] };
|
|
2608
|
+
}
|
|
2609
|
+
} catch (e) {
|
|
2610
|
+
return { content: [{ type: "text", text: `\u9519\u8BEF: ${e.message}` }], isError: true };
|
|
2611
|
+
}
|
|
2612
|
+
}
|
|
2613
|
+
async function getCadInfo2() {
|
|
2614
|
+
if (!cad.connected) {
|
|
2615
|
+
await cad.connect();
|
|
2616
|
+
}
|
|
2617
|
+
if (!cad.connected) return { content: [{ type: "text", text: "CAD \u672A\u8FDE\u63A5" }] };
|
|
2618
|
+
const info = await cad.getInfo();
|
|
2619
|
+
return { content: [{ type: "text", text: info }] };
|
|
2620
|
+
}
|
|
2621
|
+
async function atCommand(command) {
|
|
2622
|
+
if (!cad.connected) return { content: [{ type: "text", text: "\u8BF7\u5148\u8FDE\u63A5 CAD" }], isError: true };
|
|
2623
|
+
const trimmed = (command || "").trim();
|
|
2624
|
+
if (!trimmed) return { content: [{ type: "text", text: "\u547D\u4EE4\u4E3A\u7A7A\uFF0C\u672A\u53D1\u9001" }] };
|
|
2625
|
+
await cad.sendCommand(trimmed + "\n");
|
|
2626
|
+
return { content: [{ type: "text", text: "\u5DF2\u53D1\u9001\u547D\u4EE4" }] };
|
|
2627
|
+
}
|
|
2628
|
+
async function newDocument() {
|
|
2629
|
+
if (!cad.connected) {
|
|
2630
|
+
await cad.connect();
|
|
2631
|
+
}
|
|
2632
|
+
if (!cad.connected) return { content: [{ type: "text", text: "\u672A\u8FDE\u63A5 CAD" }], isError: true };
|
|
2633
|
+
const result = await cad.newDoc();
|
|
2634
|
+
if (result) {
|
|
2635
|
+
return { content: [{ type: "text", text: "\u5DF2\u5728 CAD \u4E2D\u65B0\u5EFA\u7A7A\u767D\u6587\u6863" }] };
|
|
2636
|
+
}
|
|
2637
|
+
return { content: [{ type: "text", text: "\u65B0\u5EFA\u6587\u6863\u5931\u8D25" }], isError: true };
|
|
2638
|
+
}
|
|
2639
|
+
async function bringToFront() {
|
|
2640
|
+
if (!cad.connected) {
|
|
2641
|
+
await cad.connect();
|
|
2642
|
+
}
|
|
2643
|
+
if (!cad.connected) return { content: [{ type: "text", text: "\u672A\u8FDE\u63A5 CAD" }], isError: true };
|
|
2644
|
+
const result = await cad.bringToFront();
|
|
2645
|
+
if (result) {
|
|
2646
|
+
return { content: [{ type: "text", text: "\u5DF2\u5C06 CAD \u7A97\u53E3\u5207\u6362\u5230\u524D\u53F0" }] };
|
|
2647
|
+
}
|
|
2648
|
+
return { content: [{ type: "text", text: "\u5207\u6362\u524D\u53F0\u5931\u8D25" }], isError: true };
|
|
2649
|
+
}
|
|
2650
|
+
async function installAtlisp() {
|
|
2651
|
+
if (!cad.connected) {
|
|
2652
|
+
await cad.connect();
|
|
2653
|
+
}
|
|
2654
|
+
if (!cad.connected) return { content: [{ type: "text", text: "\u672A\u8FDE\u63A5 CAD" }], isError: true };
|
|
2655
|
+
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))))`;
|
|
2656
|
+
await cad.sendCommand(installCode + "\n");
|
|
2657
|
+
return { content: [{ type: "text", text: "\u5DF2\u53D1\u9001 @lisp \u5B89\u88C5\u4EE3\u7801\u5230 CAD" }] };
|
|
2658
|
+
}
|
|
2659
|
+
async function listFunctionsInCad() {
|
|
2660
|
+
if (!cad.connected) {
|
|
2661
|
+
await cad.connect();
|
|
2662
|
+
}
|
|
2663
|
+
if (!cad.connected) return { content: [{ type: "text", text: "\u672A\u8FDE\u63A5 CAD" }], isError: true };
|
|
2664
|
+
try {
|
|
2665
|
+
const result = await cad.sendCommandWithResult("(atoms-family 0)", null);
|
|
2666
|
+
if (result) return { content: [{ type: "text", text: result }] };
|
|
2667
|
+
return { content: [{ type: "text", text: "CAD \u51FD\u6570\u5217\u8868\u4E3A\u7A7A" }] };
|
|
2668
|
+
} catch (e) {
|
|
2669
|
+
return { content: [{ type: "text", text: `\u9519\u8BEF: ${e.message}` }], isError: true };
|
|
2670
|
+
}
|
|
2671
|
+
}
|
|
2672
|
+
async function getSystemStatus() {
|
|
2673
|
+
const status = {
|
|
2674
|
+
mcp: { version: process.env.npm_package_version || "unknown" },
|
|
2675
|
+
worker: { alive: false },
|
|
2676
|
+
cad: { connected: false, platform: null, version: null, busy: false, hasDoc: false },
|
|
2677
|
+
lisp: { available: false, testResult: null, error: null },
|
|
2678
|
+
packages: null
|
|
2679
|
+
};
|
|
2680
|
+
try {
|
|
2681
|
+
status.worker.alive = await cad.ping();
|
|
2682
|
+
} catch {
|
|
2683
|
+
status.worker.alive = false;
|
|
2336
2684
|
}
|
|
2337
|
-
|
|
2338
|
-
|
|
2339
|
-
|
|
2340
|
-
|
|
2341
|
-
|
|
2342
|
-
|
|
2343
|
-
|
|
2344
|
-
|
|
2345
|
-
|
|
2346
|
-
|
|
2347
|
-
|
|
2348
|
-
|
|
2349
|
-
|
|
2350
|
-
|
|
2351
|
-
|
|
2352
|
-
|
|
2353
|
-
|
|
2354
|
-
|
|
2355
|
-
if (!session) {
|
|
2356
|
-
session = new Session(clientId);
|
|
2357
|
-
this.#sessions.set(clientId, session);
|
|
2358
|
-
}
|
|
2359
|
-
return session;
|
|
2360
|
-
}
|
|
2361
|
-
getSession(clientId) {
|
|
2362
|
-
return this.#sessions.get(clientId) || null;
|
|
2363
|
-
}
|
|
2364
|
-
hasSession(clientId) {
|
|
2365
|
-
return this.#sessions.has(clientId);
|
|
2366
|
-
}
|
|
2367
|
-
removeSession(clientId) {
|
|
2368
|
-
return this.#sessions.delete(clientId);
|
|
2369
|
-
}
|
|
2370
|
-
subscribe(clientId, uri) {
|
|
2371
|
-
const session = this.#sessions.get(clientId);
|
|
2372
|
-
if (session) {
|
|
2373
|
-
session.subscriptions.add(uri);
|
|
2374
|
-
return true;
|
|
2375
|
-
}
|
|
2376
|
-
return false;
|
|
2377
|
-
}
|
|
2378
|
-
unsubscribe(clientId, uri) {
|
|
2379
|
-
const session = this.#sessions.get(clientId);
|
|
2380
|
-
if (session) {
|
|
2381
|
-
return session.subscriptions.delete(uri);
|
|
2382
|
-
}
|
|
2383
|
-
return false;
|
|
2384
|
-
}
|
|
2385
|
-
getSubscriptions(clientId) {
|
|
2386
|
-
const session = this.#sessions.get(clientId);
|
|
2387
|
-
return session ? Array.from(session.subscriptions) : [];
|
|
2388
|
-
}
|
|
2389
|
-
isSubscribed(clientId, uri) {
|
|
2390
|
-
const session = this.#sessions.get(clientId);
|
|
2391
|
-
return session ? session.subscriptions.has(uri) : false;
|
|
2392
|
-
}
|
|
2393
|
-
getAllSubscribedUris() {
|
|
2394
|
-
const all = /* @__PURE__ */ new Set();
|
|
2395
|
-
for (const session of this.#sessions.values()) {
|
|
2396
|
-
for (const uri of session.subscriptions) {
|
|
2397
|
-
all.add(uri);
|
|
2398
|
-
}
|
|
2399
|
-
}
|
|
2400
|
-
return all;
|
|
2401
|
-
}
|
|
2402
|
-
list() {
|
|
2403
|
-
return Array.from(this.#sessions.entries()).map(([id, s]) => ({
|
|
2404
|
-
clientId: id,
|
|
2405
|
-
subscriptions: Array.from(s.subscriptions),
|
|
2406
|
-
createdAt: s.createdAt,
|
|
2407
|
-
connected: s.connected
|
|
2408
|
-
}));
|
|
2409
|
-
}
|
|
2410
|
-
count() {
|
|
2411
|
-
return this.#sessions.size;
|
|
2685
|
+
status.cad.connected = cad.connected;
|
|
2686
|
+
if (cad.connected) {
|
|
2687
|
+
status.cad.platform = cad.getPlatform();
|
|
2688
|
+
status.cad.version = cad.getVersion();
|
|
2689
|
+
try {
|
|
2690
|
+
status.cad.busy = await cad.isBusy();
|
|
2691
|
+
} catch {
|
|
2692
|
+
}
|
|
2693
|
+
try {
|
|
2694
|
+
const doc = await cad.hasDoc();
|
|
2695
|
+
status.cad.hasDoc = doc.hasDoc;
|
|
2696
|
+
} catch {
|
|
2697
|
+
}
|
|
2698
|
+
try {
|
|
2699
|
+
const r = await cad.sendCommandWithResult("(+ 1 2)");
|
|
2700
|
+
if (r !== null && r !== void 0) {
|
|
2701
|
+
status.lisp.available = true;
|
|
2702
|
+
status.lisp.testResult = String(r).trim();
|
|
2412
2703
|
}
|
|
2413
|
-
|
|
2414
|
-
|
|
2704
|
+
} catch (e) {
|
|
2705
|
+
status.lisp.error = e.message;
|
|
2706
|
+
}
|
|
2707
|
+
try {
|
|
2708
|
+
const pkgResult = await cad.sendCommandWithResult("(@::package-list-in-local)");
|
|
2709
|
+
if (pkgResult && pkgResult !== "nil") {
|
|
2710
|
+
status.packages = pkgResult;
|
|
2415
2711
|
}
|
|
2416
|
-
}
|
|
2712
|
+
} catch {
|
|
2713
|
+
}
|
|
2417
2714
|
}
|
|
2418
|
-
}
|
|
2419
|
-
|
|
2420
|
-
// src/subscription-manager.js
|
|
2421
|
-
function setNotify(fn) {
|
|
2422
|
-
_notifyFn = fn;
|
|
2715
|
+
return { content: [{ type: "text", text: JSON.stringify(status, null, 2) }] };
|
|
2423
2716
|
}
|
|
2424
|
-
function
|
|
2425
|
-
if (
|
|
2426
|
-
|
|
2717
|
+
async function initAtlisp() {
|
|
2718
|
+
if (!cad.connected) {
|
|
2719
|
+
await cad.connect();
|
|
2427
2720
|
}
|
|
2428
|
-
return true;
|
|
2429
|
-
|
|
2430
|
-
|
|
2431
|
-
|
|
2432
|
-
|
|
2721
|
+
if (!cad.connected) return { content: [{ type: "text", text: "\u672A\u8FDE\u63A5 CAD" }], isError: true };
|
|
2722
|
+
const code = `(if (null @::load-module)
|
|
2723
|
+
(progn
|
|
2724
|
+
(vl-load-com)
|
|
2725
|
+
(setq s strcat h"http"o(vlax-create-object (s"win"h".win"h"request.5.1"))
|
|
2726
|
+
v vlax-invoke e eval r read)(v o'open "get" (s h"://""atlisp.""cn/cloud"):vlax-true)
|
|
2727
|
+
(v o'send)
|
|
2728
|
+
(v o'WaitforResponse 1000)
|
|
2729
|
+
(e(r(vlax-get o'ResponseText)))))`;
|
|
2730
|
+
try {
|
|
2731
|
+
await cad.sendCommand(code + "\n");
|
|
2732
|
+
return { content: [{ type: "text", text: "\u5DF2\u53D1\u9001 @lisp \u51FD\u6570\u5E93\u52A0\u8F7D\u4EE3\u7801\u5230 CAD" }] };
|
|
2733
|
+
} catch (e) {
|
|
2734
|
+
return { content: [{ type: "text", text: `\u9519\u8BEF: ${e.message}` }], isError: true };
|
|
2433
2735
|
}
|
|
2434
|
-
return true;
|
|
2435
2736
|
}
|
|
2436
|
-
|
|
2437
|
-
|
|
2438
|
-
|
|
2737
|
+
|
|
2738
|
+
// src/handlers/package-handlers.js
|
|
2739
|
+
var PACKAGES_LIST_URL = process.env.PACKAGES_LIST_URL || "http://s3.atlisp.cn/packages-list?fmt=json";
|
|
2740
|
+
var cachedPackages = null;
|
|
2741
|
+
var cachedAt = null;
|
|
2742
|
+
var CACHE_TTL2 = 10 * 60 * 1e3;
|
|
2743
|
+
async function fetchPackages() {
|
|
2744
|
+
const now = Date.now();
|
|
2745
|
+
if (cachedPackages && cachedAt && now - cachedAt < CACHE_TTL2) {
|
|
2746
|
+
return cachedPackages;
|
|
2439
2747
|
}
|
|
2440
|
-
|
|
2748
|
+
try {
|
|
2749
|
+
const response = await fetch(PACKAGES_LIST_URL, { headers: { "User-Agent": "atlisp-mcp" } });
|
|
2750
|
+
if (response.ok) {
|
|
2751
|
+
const data = await response.json();
|
|
2752
|
+
cachedPackages = data;
|
|
2753
|
+
cachedAt = now;
|
|
2754
|
+
return data;
|
|
2755
|
+
}
|
|
2756
|
+
} catch (e) {
|
|
2757
|
+
}
|
|
2758
|
+
return cachedPackages || MOCK_PACKAGES;
|
|
2441
2759
|
}
|
|
2442
|
-
function
|
|
2443
|
-
if (
|
|
2444
|
-
|
|
2760
|
+
function flattenPackages(data) {
|
|
2761
|
+
if (Array.isArray(data)) return data;
|
|
2762
|
+
if (data && Array.isArray(data.packages)) return data.packages;
|
|
2763
|
+
return [];
|
|
2764
|
+
}
|
|
2765
|
+
async function listPackages() {
|
|
2766
|
+
if (!cad.connected) await cad.connect();
|
|
2767
|
+
if (!cad.connected) {
|
|
2768
|
+
const data2 = await fetchPackages();
|
|
2769
|
+
const items2 = flattenPackages(data2);
|
|
2770
|
+
const text2 = items2.length ? items2.map((p) => `${p.name} v${p.version || ""} - ${p.description || ""}`).join("\n") : "\u65E0\u53EF\u7528\u5305";
|
|
2771
|
+
return { content: [{ type: "text", text: text2 }] };
|
|
2445
2772
|
}
|
|
2446
|
-
|
|
2773
|
+
const result = await cad.sendCommandWithResult("(@::package-list-in-local)");
|
|
2774
|
+
if (result && result !== "nil") return { content: [{ type: "text", text: result }] };
|
|
2775
|
+
const data = await fetchPackages();
|
|
2776
|
+
const items = flattenPackages(data);
|
|
2777
|
+
const text = items.length ? `\u4ECE\u6CE8\u518C\u8868\u83B7\u53D6\u7684 @lisp \u5305:
|
|
2778
|
+
${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");
|
|
2779
|
+
return { content: [{ type: "text", text: `\u5DF2\u5B89\u88C5\u7684 @lisp \u5305:
|
|
2780
|
+
${text}` }] };
|
|
2447
2781
|
}
|
|
2448
|
-
function
|
|
2449
|
-
|
|
2450
|
-
|
|
2782
|
+
async function searchPackages(query) {
|
|
2783
|
+
const data = await fetchPackages();
|
|
2784
|
+
if (!data) {
|
|
2785
|
+
return { content: [{ type: "text", text: "\u65E0\u6CD5\u83B7\u53D6\u5305\u5217\u8868" }], isError: true };
|
|
2786
|
+
}
|
|
2787
|
+
const items = flattenPackages(data);
|
|
2788
|
+
const results = [];
|
|
2789
|
+
if (query) {
|
|
2790
|
+
const q = query.toLowerCase();
|
|
2791
|
+
for (const p of items) {
|
|
2792
|
+
const name = (p.name || "").toLowerCase();
|
|
2793
|
+
const desc = (p.description || "").toLowerCase();
|
|
2794
|
+
if (name.includes(q) || desc.includes(q)) results.push(p);
|
|
2795
|
+
}
|
|
2796
|
+
} else {
|
|
2797
|
+
for (const p of items) results.push(p);
|
|
2798
|
+
}
|
|
2799
|
+
if (results.length === 0) {
|
|
2800
|
+
return { content: [{ type: "text", text: `\u672A\u627E\u5230\u5305\u542B "${query}" \u7684\u5305` }] };
|
|
2451
2801
|
}
|
|
2802
|
+
return { content: [{ type: "text", text: `\u641C\u7D22\u7ED3\u679C (${results.length}):
|
|
2803
|
+
${results.map((p) => `${p.name} v${p.version || ""} - ${p.description || ""}`).join("\n")}` }] };
|
|
2452
2804
|
}
|
|
2453
|
-
|
|
2454
|
-
|
|
2455
|
-
|
|
2456
|
-
|
|
2457
|
-
|
|
2458
|
-
|
|
2805
|
+
async function installPackage(packageName) {
|
|
2806
|
+
const data = await fetchPackages();
|
|
2807
|
+
const items = flattenPackages(data);
|
|
2808
|
+
const pkg = items.find((p) => p.name === packageName);
|
|
2809
|
+
if (!pkg) {
|
|
2810
|
+
return { content: [{ type: "text", text: `\u9519\u8BEF: \u5305 "${packageName}" \u4E0D\u5B58\u5728` }], isError: true };
|
|
2459
2811
|
}
|
|
2460
|
-
|
|
2461
|
-
|
|
2462
|
-
// src/sse-session.js
|
|
2463
|
-
import { randomUUID as randomUUID2 } from "crypto";
|
|
2464
|
-
var DEFAULT_HEARTBEAT_INTERVAL, DEFAULT_RETRY_INTERVAL, MAX_SENT_MESSAGES, SSE_EVENTS, SseSession;
|
|
2465
|
-
var init_sse_session = __esm({
|
|
2466
|
-
"src/sse-session.js"() {
|
|
2467
|
-
DEFAULT_HEARTBEAT_INTERVAL = 3e4;
|
|
2468
|
-
DEFAULT_RETRY_INTERVAL = 3e4;
|
|
2469
|
-
MAX_SENT_MESSAGES = 1e3;
|
|
2470
|
-
SSE_EVENTS = {
|
|
2471
|
-
MESSAGE: "message",
|
|
2472
|
-
ENDPOINT: "endpoint",
|
|
2473
|
-
PING: "ping",
|
|
2474
|
-
ERROR: "error",
|
|
2475
|
-
PROGRESS: "progress",
|
|
2476
|
-
CAPABILITIES: "capabilities"
|
|
2477
|
-
};
|
|
2478
|
-
SseSession = class {
|
|
2479
|
-
#res;
|
|
2480
|
-
#clientId;
|
|
2481
|
-
#active = true;
|
|
2482
|
-
#heartbeatTimer = null;
|
|
2483
|
-
#lastEventId = 0;
|
|
2484
|
-
#heartbeatInterval;
|
|
2485
|
-
#retryInterval;
|
|
2486
|
-
#sessionData = {};
|
|
2487
|
-
#sentMessages = [];
|
|
2488
|
-
#backpressureBuffer = [];
|
|
2489
|
-
#drainHandler = null;
|
|
2490
|
-
constructor(res, options = {}) {
|
|
2491
|
-
this.#res = res;
|
|
2492
|
-
this.#clientId = options.clientId || randomUUID2();
|
|
2493
|
-
this.#heartbeatInterval = options.heartbeatInterval || DEFAULT_HEARTBEAT_INTERVAL;
|
|
2494
|
-
this.#retryInterval = options.retryInterval || DEFAULT_RETRY_INTERVAL;
|
|
2495
|
-
this.#sessionData = options.sessionData || {};
|
|
2496
|
-
if (options.resumeFromId && options.resumeFromId > 0) {
|
|
2497
|
-
this.#lastEventId = options.resumeFromId;
|
|
2498
|
-
}
|
|
2499
|
-
this._setupSseHeaders();
|
|
2500
|
-
this._sendRetry();
|
|
2501
|
-
this._setupDrain();
|
|
2502
|
-
}
|
|
2503
|
-
get clientId() {
|
|
2504
|
-
return this.#clientId;
|
|
2505
|
-
}
|
|
2506
|
-
get isActive() {
|
|
2507
|
-
return this.#active;
|
|
2508
|
-
}
|
|
2509
|
-
get lastEventId() {
|
|
2510
|
-
return this.#lastEventId;
|
|
2511
|
-
}
|
|
2512
|
-
get sessionData() {
|
|
2513
|
-
return this.#sessionData;
|
|
2514
|
-
}
|
|
2515
|
-
get sentMessages() {
|
|
2516
|
-
return [...this.#sentMessages];
|
|
2517
|
-
}
|
|
2518
|
-
getMessagesSince(eventId) {
|
|
2519
|
-
return this.#sentMessages.filter((m) => m.id > eventId);
|
|
2520
|
-
}
|
|
2521
|
-
setSessionData(key, value) {
|
|
2522
|
-
this.#sessionData[key] = value;
|
|
2523
|
-
}
|
|
2524
|
-
getSessionData(key) {
|
|
2525
|
-
return this.#sessionData[key];
|
|
2526
|
-
}
|
|
2527
|
-
get retryInterval() {
|
|
2528
|
-
return this.#retryInterval;
|
|
2529
|
-
}
|
|
2530
|
-
setRetryInterval(ms) {
|
|
2531
|
-
this.#retryInterval = ms;
|
|
2532
|
-
}
|
|
2533
|
-
_sendRetry() {
|
|
2534
|
-
this._write(`retry: ${this.#retryInterval}
|
|
2535
|
-
|
|
2812
|
+
if (cad.connected) {
|
|
2813
|
+
await cad.sendCommand(`(@::load-module '${packageName})
|
|
2536
2814
|
`);
|
|
2537
|
-
}
|
|
2538
|
-
_setupSseHeaders() {
|
|
2539
|
-
this.#res.setHeader("Content-Type", "text/event-stream");
|
|
2540
|
-
this.#res.setHeader("Cache-Control", "no-cache");
|
|
2541
|
-
this.#res.setHeader("Connection", "keep-alive");
|
|
2542
|
-
this.#res.setHeader("Transfer-Encoding", "chunked");
|
|
2543
|
-
this.#res.setHeader("X-Accel-Buffering", "no");
|
|
2544
|
-
if (typeof this.#res.flush !== "function") {
|
|
2545
|
-
this.#res.flush = () => {
|
|
2546
|
-
};
|
|
2547
|
-
}
|
|
2548
|
-
}
|
|
2549
|
-
_formatEvent(event, data, id = null) {
|
|
2550
|
-
const lines = [];
|
|
2551
|
-
if (id !== null) {
|
|
2552
|
-
lines.push(`id: ${id}`);
|
|
2553
|
-
}
|
|
2554
|
-
lines.push(`event: ${event}`);
|
|
2555
|
-
if (data !== null && data !== void 0) {
|
|
2556
|
-
const jsonStr = JSON.stringify(data);
|
|
2557
|
-
lines.push(`data: ${jsonStr}`);
|
|
2558
|
-
} else {
|
|
2559
|
-
lines.push("data:");
|
|
2560
|
-
}
|
|
2561
|
-
return lines.join("\n") + "\n\n";
|
|
2562
|
-
}
|
|
2563
|
-
_setupDrain() {
|
|
2564
|
-
if (typeof this.#res.on !== "function") return;
|
|
2565
|
-
this.#drainHandler = () => {
|
|
2566
|
-
if (!this.#active) return;
|
|
2567
|
-
if (this.#backpressureBuffer.length > 0) {
|
|
2568
|
-
this._drainBuffer();
|
|
2569
|
-
}
|
|
2570
|
-
};
|
|
2571
|
-
this.#res.on("drain", this.#drainHandler);
|
|
2572
|
-
}
|
|
2573
|
-
_drainBuffer() {
|
|
2574
|
-
const batch = this.#backpressureBuffer.splice(0, 50);
|
|
2575
|
-
for (const item of batch) {
|
|
2576
|
-
const ok = this.#res.write(item);
|
|
2577
|
-
if (!ok) {
|
|
2578
|
-
this.#backpressureBuffer.unshift(...batch.slice(batch.indexOf(item)));
|
|
2579
|
-
return;
|
|
2580
|
-
}
|
|
2581
|
-
}
|
|
2582
|
-
this._flush();
|
|
2583
|
-
if (this.#backpressureBuffer.length > 0) {
|
|
2584
|
-
this._drainBuffer();
|
|
2585
|
-
}
|
|
2586
|
-
}
|
|
2587
|
-
_write(content) {
|
|
2588
|
-
if (!this.#active) return false;
|
|
2589
|
-
try {
|
|
2590
|
-
if (this.#backpressureBuffer.length > 0) {
|
|
2591
|
-
this.#backpressureBuffer.push(content);
|
|
2592
|
-
return true;
|
|
2593
|
-
}
|
|
2594
|
-
const result = this.#res.write(content);
|
|
2595
|
-
if (typeof this.#res.flush === "function") {
|
|
2596
|
-
this.#res.flush();
|
|
2597
|
-
}
|
|
2598
|
-
if (result === false) {
|
|
2599
|
-
this.#backpressureBuffer.push(content);
|
|
2600
|
-
return true;
|
|
2601
|
-
}
|
|
2602
|
-
return true;
|
|
2603
|
-
} catch (e) {
|
|
2604
|
-
this.#active = false;
|
|
2605
|
-
this.close();
|
|
2606
|
-
return false;
|
|
2607
|
-
}
|
|
2608
|
-
}
|
|
2609
|
-
_flush() {
|
|
2610
|
-
try {
|
|
2611
|
-
if (typeof this.#res.flush === "function") {
|
|
2612
|
-
this.#res.flush();
|
|
2613
|
-
}
|
|
2614
|
-
} catch (e) {
|
|
2615
|
-
}
|
|
2616
|
-
}
|
|
2617
|
-
flushBackpressure() {
|
|
2618
|
-
if (this.#backpressureBuffer.length > 0) {
|
|
2619
|
-
this._drainBuffer();
|
|
2620
|
-
}
|
|
2621
|
-
}
|
|
2622
|
-
sendEvent(event, data, id = null) {
|
|
2623
|
-
this.#lastEventId++;
|
|
2624
|
-
const eventId = id !== null ? id : this.#lastEventId;
|
|
2625
|
-
const formatted = this._formatEvent(event, data, eventId);
|
|
2626
|
-
this.#sentMessages.push({ event, data, id: eventId, timestamp: Date.now() });
|
|
2627
|
-
if (this.#sentMessages.length > MAX_SENT_MESSAGES) {
|
|
2628
|
-
this.#sentMessages.splice(0, this.#sentMessages.length - MAX_SENT_MESSAGES);
|
|
2629
|
-
}
|
|
2630
|
-
this._write(formatted);
|
|
2631
|
-
this._flush();
|
|
2632
|
-
return true;
|
|
2633
|
-
}
|
|
2634
|
-
sendMessage(data) {
|
|
2635
|
-
return this.sendEvent(SSE_EVENTS.MESSAGE, data);
|
|
2636
|
-
}
|
|
2637
|
-
sendEndpoint(path8) {
|
|
2638
|
-
return this.sendEvent(SSE_EVENTS.ENDPOINT, path8);
|
|
2639
|
-
}
|
|
2640
|
-
sendError(code, message, id = null) {
|
|
2641
|
-
return this.sendEvent(SSE_EVENTS.ERROR, { code, message }, id);
|
|
2642
|
-
}
|
|
2643
|
-
sendPing() {
|
|
2644
|
-
return this.sendEvent(SSE_EVENTS.PING, { timestamp: Date.now() });
|
|
2645
|
-
}
|
|
2646
|
-
sendProgress(current, total, message = "") {
|
|
2647
|
-
return this.sendEvent(SSE_EVENTS.PROGRESS, { current, total, message });
|
|
2648
|
-
}
|
|
2649
|
-
sendCapabilities(capabilities) {
|
|
2650
|
-
return this.sendEvent(SSE_EVENTS.CAPABILITIES, capabilities);
|
|
2651
|
-
}
|
|
2652
|
-
sendResponse(jsonrpcResponse, id = null) {
|
|
2653
|
-
const eventId = id !== null ? id : this.#lastEventId;
|
|
2654
|
-
return this.sendEvent(SSE_EVENTS.MESSAGE, jsonrpcResponse, eventId);
|
|
2655
|
-
}
|
|
2656
|
-
startHeartbeat(interval = null) {
|
|
2657
|
-
this.stopHeartbeat();
|
|
2658
|
-
const ms = interval || this.#heartbeatInterval;
|
|
2659
|
-
this.#heartbeatTimer = setInterval(() => {
|
|
2660
|
-
if (!this.#active) {
|
|
2661
|
-
this.stopHeartbeat();
|
|
2662
|
-
return;
|
|
2663
|
-
}
|
|
2664
|
-
if (!this.sendPing()) {
|
|
2665
|
-
this.stopHeartbeat();
|
|
2666
|
-
this.close();
|
|
2667
|
-
}
|
|
2668
|
-
}, ms);
|
|
2669
|
-
}
|
|
2670
|
-
stopHeartbeat() {
|
|
2671
|
-
if (this.#heartbeatTimer) {
|
|
2672
|
-
clearInterval(this.#heartbeatTimer);
|
|
2673
|
-
this.#heartbeatTimer = null;
|
|
2674
|
-
}
|
|
2675
|
-
}
|
|
2676
|
-
close() {
|
|
2677
|
-
this.#active = false;
|
|
2678
|
-
this.stopHeartbeat();
|
|
2679
|
-
if (this.#drainHandler) {
|
|
2680
|
-
this.#res.removeListener("drain", this.#drainHandler);
|
|
2681
|
-
this.#drainHandler = null;
|
|
2682
|
-
}
|
|
2683
|
-
this.#backpressureBuffer = [];
|
|
2684
|
-
try {
|
|
2685
|
-
this.#res.end();
|
|
2686
|
-
} catch (e) {
|
|
2687
|
-
}
|
|
2688
|
-
}
|
|
2689
|
-
};
|
|
2690
2815
|
}
|
|
2691
|
-
}
|
|
2816
|
+
return { content: [{ type: "text", text: `\u5305 "${packageName}" \u5B89\u88C5\u547D\u4EE4\u5DF2\u53D1\u9001\uFF01` }] };
|
|
2817
|
+
}
|
|
2692
2818
|
|
|
2693
|
-
// src/
|
|
2819
|
+
// src/handlers/function-handlers.js
|
|
2694
2820
|
import fs5 from "fs";
|
|
2695
2821
|
import path6 from "path";
|
|
2696
2822
|
import os3 from "os";
|
|
2697
|
-
|
|
2698
|
-
|
|
2823
|
+
var FUNCTIONS_DIR = process.env.FUNCTIONS_DIR || "";
|
|
2824
|
+
var FUNCTIONS_URL = process.env.FUNCTIONS_URL || "http://s3.atlisp.cn/json/functions.json";
|
|
2825
|
+
var CACHE_DIR = path6.join(os3.homedir(), ".atlisp", "cache");
|
|
2826
|
+
var FUNCLIB_CACHE_FILE = path6.join(CACHE_DIR, "functions.json");
|
|
2827
|
+
var FUNCLIB_CACHE_TTL = 24 * 60 * 60 * 1e3;
|
|
2828
|
+
function readCacheFromDisk() {
|
|
2829
|
+
try {
|
|
2830
|
+
const stat = fs5.statSync(FUNCLIB_CACHE_FILE);
|
|
2831
|
+
if (Date.now() - stat.mtimeMs < FUNCLIB_CACHE_TTL) {
|
|
2832
|
+
const raw = fs5.readFileSync(FUNCLIB_CACHE_FILE, "utf-8");
|
|
2833
|
+
return JSON.parse(raw);
|
|
2834
|
+
}
|
|
2835
|
+
} catch {
|
|
2836
|
+
}
|
|
2837
|
+
return null;
|
|
2699
2838
|
}
|
|
2700
|
-
function
|
|
2839
|
+
function writeCacheToDisk(data) {
|
|
2701
2840
|
try {
|
|
2702
|
-
fs5.mkdirSync(
|
|
2703
|
-
|
|
2704
|
-
clientId,
|
|
2705
|
-
sessionData,
|
|
2706
|
-
savedAt: Date.now()
|
|
2707
|
-
};
|
|
2708
|
-
fs5.writeFileSync(getSessionStorePath(clientId), JSON.stringify(store), "utf-8");
|
|
2841
|
+
fs5.mkdirSync(CACHE_DIR, { recursive: true });
|
|
2842
|
+
fs5.writeFileSync(FUNCLIB_CACHE_FILE, JSON.stringify(data), "utf-8");
|
|
2709
2843
|
} catch (e) {
|
|
2710
|
-
|
|
2844
|
+
log(`function-handlers writeCache error: ${e.message}`);
|
|
2711
2845
|
}
|
|
2712
2846
|
}
|
|
2713
|
-
function
|
|
2847
|
+
async function fetchFunctions() {
|
|
2848
|
+
const diskCache = readCacheFromDisk();
|
|
2849
|
+
if (diskCache) return diskCache;
|
|
2714
2850
|
try {
|
|
2715
|
-
const
|
|
2716
|
-
if (
|
|
2717
|
-
|
|
2718
|
-
|
|
2719
|
-
|
|
2720
|
-
fs5.unlinkSync(filePath);
|
|
2721
|
-
return null;
|
|
2851
|
+
const response = await fetch(FUNCTIONS_URL, { headers: { "User-Agent": "atlisp-mcp" } });
|
|
2852
|
+
if (response.ok) {
|
|
2853
|
+
const data = await response.json();
|
|
2854
|
+
writeCacheToDisk(data);
|
|
2855
|
+
return data;
|
|
2722
2856
|
}
|
|
2723
|
-
return store.sessionData || {};
|
|
2724
2857
|
} catch (e) {
|
|
2725
|
-
|
|
2858
|
+
log(`function-handlers fetch error: ${e.message}`);
|
|
2726
2859
|
}
|
|
2860
|
+
return diskCache;
|
|
2727
2861
|
}
|
|
2728
|
-
|
|
2729
|
-
|
|
2730
|
-
|
|
2731
|
-
|
|
2732
|
-
|
|
2733
|
-
|
|
2734
|
-
|
|
2735
|
-
|
|
2736
|
-
|
|
2737
|
-
|
|
2738
|
-
|
|
2739
|
-
|
|
2740
|
-
|
|
2741
|
-
|
|
2742
|
-
|
|
2743
|
-
|
|
2744
|
-
|
|
2745
|
-
const persisted = loadPersistedSessionData(clientId);
|
|
2746
|
-
if (persisted) {
|
|
2747
|
-
for (const [key, value] of Object.entries(persisted)) {
|
|
2748
|
-
session.setSessionData(key, value);
|
|
2749
|
-
}
|
|
2750
|
-
}
|
|
2751
|
-
this.#sessions.set(clientId, session);
|
|
2752
|
-
session.startHeartbeat();
|
|
2753
|
-
}
|
|
2754
|
-
remove(clientId) {
|
|
2755
|
-
const session = this.#sessions.get(clientId);
|
|
2756
|
-
if (session) {
|
|
2757
|
-
persistSessionData(clientId, session.sessionData);
|
|
2758
|
-
session.close();
|
|
2759
|
-
this.#sessions.delete(clientId);
|
|
2760
|
-
return true;
|
|
2761
|
-
}
|
|
2762
|
-
return false;
|
|
2763
|
-
}
|
|
2764
|
-
get(clientId) {
|
|
2765
|
-
return this.#sessions.get(clientId) || null;
|
|
2766
|
-
}
|
|
2767
|
-
has(clientId) {
|
|
2768
|
-
return this.#sessions.has(clientId);
|
|
2769
|
-
}
|
|
2770
|
-
list() {
|
|
2771
|
-
return Array.from(this.#sessions.keys()).map((id) => ({
|
|
2772
|
-
clientId: id,
|
|
2773
|
-
isActive: this.#sessions.get(id)?.isActive ?? false
|
|
2774
|
-
}));
|
|
2775
|
-
}
|
|
2776
|
-
listActive() {
|
|
2777
|
-
return this.list().filter((s) => s.isActive);
|
|
2778
|
-
}
|
|
2779
|
-
count() {
|
|
2780
|
-
return this.#sessions.size;
|
|
2781
|
-
}
|
|
2782
|
-
sendToClient(clientId, event, data, id = null) {
|
|
2783
|
-
const session = this.#sessions.get(clientId);
|
|
2784
|
-
if (!session || !session.isActive) {
|
|
2785
|
-
return false;
|
|
2786
|
-
}
|
|
2787
|
-
return session.sendEvent(event, data, id);
|
|
2788
|
-
}
|
|
2789
|
-
sendMessageToClient(clientId, data) {
|
|
2790
|
-
return this.sendToClient(clientId, SSE_EVENTS.MESSAGE, data);
|
|
2791
|
-
}
|
|
2792
|
-
sendErrorToClient(clientId, code, message, id = null) {
|
|
2793
|
-
return this.sendToClient(clientId, SSE_EVENTS.ERROR, { code, message }, id);
|
|
2794
|
-
}
|
|
2795
|
-
sendProgressToClient(clientId, current, total, message = "") {
|
|
2796
|
-
return this.sendToClient(clientId, SSE_EVENTS.PROGRESS, { current, total, message });
|
|
2797
|
-
}
|
|
2798
|
-
broadcast(event, data) {
|
|
2799
|
-
let successCount = 0;
|
|
2800
|
-
for (const [clientId, session] of this.#sessions) {
|
|
2801
|
-
if (session.isActive && session.sendEvent(event, data)) {
|
|
2802
|
-
successCount++;
|
|
2803
|
-
}
|
|
2804
|
-
}
|
|
2805
|
-
return successCount;
|
|
2806
|
-
}
|
|
2807
|
-
broadcastMessage(data) {
|
|
2808
|
-
return this.broadcast(SSE_EVENTS.MESSAGE, data);
|
|
2809
|
-
}
|
|
2810
|
-
broadcastError(code, message) {
|
|
2811
|
-
return this.broadcast(SSE_EVENTS.ERROR, { code, message });
|
|
2812
|
-
}
|
|
2813
|
-
on(event, handler) {
|
|
2814
|
-
if (!this.#eventHandlers.has(event)) {
|
|
2815
|
-
this.#eventHandlers.set(event, /* @__PURE__ */ new Set());
|
|
2862
|
+
async function getFunctionUsage(funcName, packageName) {
|
|
2863
|
+
try {
|
|
2864
|
+
let results = [];
|
|
2865
|
+
const data = await fetchFunctions();
|
|
2866
|
+
if (data) {
|
|
2867
|
+
const funcs = Object.values(data.all_functions || {});
|
|
2868
|
+
const func = funcs.find((f2) => f2.name === funcName || f2.name === `${packageName}:${funcName}`);
|
|
2869
|
+
if (func) results.push(func);
|
|
2870
|
+
}
|
|
2871
|
+
if (results.length === 0 && FUNCTIONS_DIR) {
|
|
2872
|
+
try {
|
|
2873
|
+
const files = fs5.readdirSync(FUNCTIONS_DIR).filter((f2) => f2.endsWith(".json"));
|
|
2874
|
+
for (const file of files) {
|
|
2875
|
+
const raw = fs5.readFileSync(path6.join(FUNCTIONS_DIR, file), "utf-8");
|
|
2876
|
+
const data2 = JSON.parse(raw);
|
|
2877
|
+
const func = data2.functions?.find((f2) => f2.name === funcName);
|
|
2878
|
+
if (func) results.push(func);
|
|
2816
2879
|
}
|
|
2817
|
-
|
|
2880
|
+
} catch {
|
|
2818
2881
|
}
|
|
2819
|
-
|
|
2820
|
-
|
|
2821
|
-
|
|
2822
|
-
|
|
2823
|
-
|
|
2882
|
+
}
|
|
2883
|
+
if (results.length === 0) {
|
|
2884
|
+
return { content: [{ type: "text", text: `\u672A\u627E\u5230\u51FD\u6570: ${funcName}` }], isError: true };
|
|
2885
|
+
}
|
|
2886
|
+
const f = results[0];
|
|
2887
|
+
const text = `\u51FD\u6570: ${f.name}
|
|
2888
|
+
\u63CF\u8FF0: ${f.description || "-"}
|
|
2889
|
+
\u53C2\u6570: ${f.params?.join(", ") || "-"}
|
|
2890
|
+
\u8FD4\u56DE\u503C: ${f.return || "-"}
|
|
2891
|
+
\u793A\u4F8B: ${f.usage || "-"}`;
|
|
2892
|
+
return { content: [{ type: "text", text }] };
|
|
2893
|
+
} catch (e) {
|
|
2894
|
+
return { content: [{ type: "text", text: `\u9519\u8BEF: ${e.message}` }], isError: true };
|
|
2895
|
+
}
|
|
2896
|
+
}
|
|
2897
|
+
async function listSymbols(packageName) {
|
|
2898
|
+
try {
|
|
2899
|
+
let allFuncs = [];
|
|
2900
|
+
const data = await fetchFunctions();
|
|
2901
|
+
if (data) {
|
|
2902
|
+
const funcs = Object.values(data.all_functions || {});
|
|
2903
|
+
if (packageName) {
|
|
2904
|
+
allFuncs = funcs.filter((f) => f.name.startsWith(`${packageName}:`));
|
|
2905
|
+
} else {
|
|
2906
|
+
allFuncs = funcs.map((f) => `${f.name}: ${f.description || "-"}`);
|
|
2824
2907
|
}
|
|
2825
|
-
|
|
2826
|
-
|
|
2827
|
-
|
|
2828
|
-
|
|
2829
|
-
|
|
2830
|
-
|
|
2831
|
-
|
|
2908
|
+
}
|
|
2909
|
+
if (allFuncs.length === 0 && FUNCTIONS_DIR) {
|
|
2910
|
+
try {
|
|
2911
|
+
const files = fs5.readdirSync(FUNCTIONS_DIR).filter((f) => f.endsWith(".json"));
|
|
2912
|
+
for (const file of files) {
|
|
2913
|
+
const raw = fs5.readFileSync(path6.join(FUNCTIONS_DIR, file), "utf-8");
|
|
2914
|
+
const data2 = JSON.parse(raw);
|
|
2915
|
+
const funcs = Object.values(data2.all_functions || {});
|
|
2916
|
+
if (packageName) {
|
|
2917
|
+
allFuncs = funcs.filter((f) => f.name.startsWith(`${packageName}:`));
|
|
2918
|
+
} else {
|
|
2919
|
+
for (const f of funcs) {
|
|
2920
|
+
allFuncs.push(`${f.name}: ${f.description || "-"}`);
|
|
2832
2921
|
}
|
|
2833
2922
|
}
|
|
2834
2923
|
}
|
|
2924
|
+
} catch (err) {
|
|
2925
|
+
log(`listSymbols readDir error: ${err.message}`);
|
|
2835
2926
|
}
|
|
2836
|
-
|
|
2837
|
-
|
|
2838
|
-
|
|
2839
|
-
|
|
2840
|
-
|
|
2841
|
-
|
|
2842
|
-
|
|
2843
|
-
|
|
2844
|
-
|
|
2845
|
-
|
|
2846
|
-
|
|
2847
|
-
session.close();
|
|
2848
|
-
}
|
|
2849
|
-
this.#sessions.clear();
|
|
2850
|
-
}
|
|
2851
|
-
};
|
|
2927
|
+
}
|
|
2928
|
+
if (allFuncs.length === 0) {
|
|
2929
|
+
return await listFunctionsInCad();
|
|
2930
|
+
}
|
|
2931
|
+
if (packageName) {
|
|
2932
|
+
return { content: [{ type: "text", text: `${packageName} \u5305\u51FD\u6570 (${allFuncs.length}):
|
|
2933
|
+
${allFuncs.map((f) => f.name).join("\n")}` }] };
|
|
2934
|
+
}
|
|
2935
|
+
return { content: [{ type: "text", text: allFuncs.join("\n") }] };
|
|
2936
|
+
} catch (e) {
|
|
2937
|
+
return { content: [{ type: "text", text: `\u9519\u8BEF: ${e.message}` }], isError: true };
|
|
2852
2938
|
}
|
|
2853
|
-
}
|
|
2939
|
+
}
|
|
2854
2940
|
|
|
2855
|
-
// src/
|
|
2856
|
-
import
|
|
2857
|
-
|
|
2858
|
-
|
|
2859
|
-
|
|
2860
|
-
|
|
2861
|
-
|
|
2862
|
-
|
|
2863
|
-
|
|
2864
|
-
|
|
2865
|
-
|
|
2866
|
-
|
|
2867
|
-
|
|
2868
|
-
|
|
2869
|
-
|
|
2870
|
-
|
|
2871
|
-
|
|
2872
|
-
|
|
2873
|
-
if (this._started) {
|
|
2874
|
-
throw new Error("Transport already started");
|
|
2875
|
-
}
|
|
2876
|
-
this._started = true;
|
|
2877
|
-
}
|
|
2878
|
-
async send(message) {
|
|
2879
|
-
if (this._closed) return;
|
|
2880
|
-
if (this._pendingRequest) {
|
|
2881
|
-
const { resolve, reject, timeout } = this._pendingRequest;
|
|
2882
|
-
clearTimeout(timeout);
|
|
2883
|
-
this._pendingRequest = null;
|
|
2884
|
-
resolve(message);
|
|
2885
|
-
}
|
|
2886
|
-
}
|
|
2887
|
-
async close() {
|
|
2888
|
-
if (this._closed) return;
|
|
2889
|
-
this._closed = true;
|
|
2890
|
-
if (this._pendingRequest) {
|
|
2891
|
-
const { reject, timeout } = this._pendingRequest;
|
|
2892
|
-
clearTimeout(timeout);
|
|
2893
|
-
this._pendingRequest = null;
|
|
2894
|
-
reject(new Error("Transport closed"));
|
|
2895
|
-
}
|
|
2896
|
-
this._clearCleanupTimer();
|
|
2897
|
-
this.onclose?.();
|
|
2898
|
-
}
|
|
2899
|
-
async handleRequest(message, timeoutMs = 6e4) {
|
|
2900
|
-
if (this._closed) {
|
|
2901
|
-
throw new Error("Transport closed");
|
|
2902
|
-
}
|
|
2903
|
-
if (!message || !message.method) {
|
|
2904
|
-
throw new Error("Invalid message");
|
|
2905
|
-
}
|
|
2906
|
-
if (!message.id) {
|
|
2907
|
-
this.onmessage?.(message);
|
|
2908
|
-
return null;
|
|
2909
|
-
}
|
|
2910
|
-
return new Promise((resolve, reject) => {
|
|
2911
|
-
const timeout = setTimeout(() => {
|
|
2912
|
-
if (this._pendingRequest?.resolve === resolve) {
|
|
2913
|
-
this._pendingRequest = null;
|
|
2914
|
-
reject(new Error("Request timeout"));
|
|
2915
|
-
}
|
|
2916
|
-
}, timeoutMs);
|
|
2917
|
-
this._pendingRequest = { resolve, reject, timeout };
|
|
2918
|
-
this.onmessage?.(message);
|
|
2919
|
-
});
|
|
2920
|
-
}
|
|
2921
|
-
resetCleanupTimer() {
|
|
2922
|
-
this._clearCleanupTimer();
|
|
2923
|
-
this._cleanupTimer = setTimeout(() => {
|
|
2924
|
-
this.close();
|
|
2925
|
-
}, SESSION_TIMEOUT);
|
|
2926
|
-
}
|
|
2927
|
-
_clearCleanupTimer() {
|
|
2928
|
-
if (this._cleanupTimer) {
|
|
2929
|
-
clearTimeout(this._cleanupTimer);
|
|
2930
|
-
this._cleanupTimer = null;
|
|
2931
|
-
}
|
|
2932
|
-
}
|
|
2933
|
-
};
|
|
2941
|
+
// src/function-lib.js
|
|
2942
|
+
import path7 from "path";
|
|
2943
|
+
import fs6 from "fs";
|
|
2944
|
+
import os4 from "os";
|
|
2945
|
+
var CACHE_DIR2 = path7.join(os4.homedir(), ".atlisp", "cache");
|
|
2946
|
+
var FUNCLIB_CACHE_FILE2 = path7.join(CACHE_DIR2, "functions.json");
|
|
2947
|
+
var CACHE_TTL3 = config_default.functionLibCacheTtl || 5 * 60 * 1e3;
|
|
2948
|
+
var FUNCTION_LIB_URL = config_default.functionLibUrl || "http://s3.atlisp.cn/json/functions.json";
|
|
2949
|
+
var cachedFunctionLib = null;
|
|
2950
|
+
var cachedAt2 = null;
|
|
2951
|
+
async function readCacheFromDisk2() {
|
|
2952
|
+
try {
|
|
2953
|
+
const stat = fs6.statSync(FUNCLIB_CACHE_FILE2);
|
|
2954
|
+
if (Date.now() - stat.mtimeMs < CACHE_TTL3) {
|
|
2955
|
+
const raw = fs6.readFileSync(FUNCLIB_CACHE_FILE2, "utf-8");
|
|
2956
|
+
return JSON.parse(raw);
|
|
2957
|
+
}
|
|
2958
|
+
} catch {
|
|
2934
2959
|
}
|
|
2935
|
-
|
|
2960
|
+
return null;
|
|
2961
|
+
}
|
|
2962
|
+
function writeCacheToDisk2(data) {
|
|
2963
|
+
try {
|
|
2964
|
+
fs6.mkdirSync(CACHE_DIR2, { recursive: true });
|
|
2965
|
+
fs6.writeFileSync(FUNCLIB_CACHE_FILE2, JSON.stringify(data), "utf-8");
|
|
2966
|
+
} catch (e) {
|
|
2967
|
+
error(`writeCacheToDisk error: ${e.message}`);
|
|
2968
|
+
}
|
|
2969
|
+
}
|
|
2970
|
+
async function loadAtlibFunctionLib() {
|
|
2971
|
+
const now = Date.now();
|
|
2972
|
+
if (cachedFunctionLib && cachedAt2 && now - cachedAt2 < CACHE_TTL3) {
|
|
2973
|
+
return cachedFunctionLib;
|
|
2974
|
+
}
|
|
2975
|
+
const diskCache = await readCacheFromDisk2();
|
|
2976
|
+
if (diskCache) {
|
|
2977
|
+
cachedFunctionLib = diskCache;
|
|
2978
|
+
cachedAt2 = now;
|
|
2979
|
+
return diskCache;
|
|
2980
|
+
}
|
|
2981
|
+
try {
|
|
2982
|
+
const response = await fetch(FUNCTION_LIB_URL, { headers: { "User-Agent": "atlisp-mcp" } });
|
|
2983
|
+
if (response.ok) {
|
|
2984
|
+
const data = await response.json();
|
|
2985
|
+
cachedFunctionLib = data;
|
|
2986
|
+
cachedAt2 = now;
|
|
2987
|
+
writeCacheToDisk2(data);
|
|
2988
|
+
return data;
|
|
2989
|
+
}
|
|
2990
|
+
} catch (e) {
|
|
2991
|
+
error(`loadAtlibFunctionLib error: ${e.message}`);
|
|
2992
|
+
}
|
|
2993
|
+
return cachedFunctionLib;
|
|
2994
|
+
}
|
|
2936
2995
|
|
|
2937
|
-
// src/mcp-
|
|
2938
|
-
|
|
2939
|
-
|
|
2940
|
-
|
|
2941
|
-
|
|
2942
|
-
|
|
2943
|
-
|
|
2944
|
-
|
|
2945
|
-
|
|
2946
|
-
|
|
2947
|
-
|
|
2948
|
-
|
|
2949
|
-
|
|
2950
|
-
|
|
2951
|
-
|
|
2952
|
-
|
|
2953
|
-
|
|
2954
|
-
|
|
2955
|
-
|
|
2956
|
-
|
|
2957
|
-
|
|
2958
|
-
|
|
2959
|
-
|
|
2960
|
-
|
|
2961
|
-
|
|
2962
|
-
|
|
2963
|
-
|
|
2964
|
-
|
|
2965
|
-
|
|
2966
|
-
|
|
2967
|
-
|
|
2968
|
-
|
|
2969
|
-
|
|
2970
|
-
|
|
2971
|
-
|
|
2972
|
-
|
|
2973
|
-
|
|
2974
|
-
|
|
2975
|
-
|
|
2976
|
-
|
|
2977
|
-
|
|
2978
|
-
|
|
2979
|
-
|
|
2980
|
-
return {
|
|
2981
|
-
contents: [],
|
|
2982
|
-
isError: true,
|
|
2983
|
-
error: { code: -32603, message: e.message }
|
|
2984
|
-
};
|
|
2996
|
+
// src/mcp-tools.js
|
|
2997
|
+
var toolInputSchema = {
|
|
2998
|
+
connect_cad: { platform: "string?" },
|
|
2999
|
+
eval_lisp: { code: "string" },
|
|
3000
|
+
eval_lisp_with_result: { code: "string", encoding: "string?" },
|
|
3001
|
+
get_cad_info: {},
|
|
3002
|
+
list_packages: {},
|
|
3003
|
+
search_packages: { query: "string" },
|
|
3004
|
+
install_package: { packageName: "string" },
|
|
3005
|
+
get_platform_info: {},
|
|
3006
|
+
at_command: { command: "string" },
|
|
3007
|
+
new_document: {},
|
|
3008
|
+
bring_to_front: {},
|
|
3009
|
+
install_atlisp: {},
|
|
3010
|
+
init_atlisp: {},
|
|
3011
|
+
get_function_usage: { name: "string", package: "string?" },
|
|
3012
|
+
list_symbols: { package: "string?" },
|
|
3013
|
+
get_system_status: {},
|
|
3014
|
+
import_funlib: { format: "string?" },
|
|
3015
|
+
list_prompts: {},
|
|
3016
|
+
get_prompt: { name: "string", args: "object?" }
|
|
3017
|
+
};
|
|
3018
|
+
function validateToolArgs(name, args) {
|
|
3019
|
+
const schema = toolInputSchema[name];
|
|
3020
|
+
if (!schema) {
|
|
3021
|
+
throw new Error(`Unknown tool: ${name}`);
|
|
3022
|
+
}
|
|
3023
|
+
for (const [key, type] of Object.entries(schema)) {
|
|
3024
|
+
const isOptional = type.endsWith("?");
|
|
3025
|
+
const baseType = type.replace("?", "");
|
|
3026
|
+
if (!args[key]) {
|
|
3027
|
+
if (isOptional) continue;
|
|
3028
|
+
throw new Error(`Missing required argument: ${key}`);
|
|
3029
|
+
}
|
|
3030
|
+
const actualType = typeof args[key];
|
|
3031
|
+
if (baseType === "string" && actualType !== "string") {
|
|
3032
|
+
throw new Error(`Invalid type for argument ${key}: expected string, got ${actualType}`);
|
|
3033
|
+
}
|
|
3034
|
+
if (baseType === "object" && (actualType !== "object" || actualType === null)) {
|
|
3035
|
+
throw new Error(`Invalid type for argument ${key}: expected object, got ${actualType}`);
|
|
3036
|
+
}
|
|
3037
|
+
if (baseType === "number" && actualType !== "number") {
|
|
3038
|
+
throw new Error(`Invalid type for argument ${key}: expected number, got ${actualType}`);
|
|
2985
3039
|
}
|
|
2986
|
-
}
|
|
2987
|
-
|
|
2988
|
-
const { uri } = request.params;
|
|
2989
|
-
const ctx = mcpContext.getStore();
|
|
2990
|
-
subscribe(uri, ctx?.sessionId);
|
|
2991
|
-
return { success: true };
|
|
2992
|
-
});
|
|
2993
|
-
server.setRequestHandler(UnsubscribeRequestSchema, async (request) => {
|
|
2994
|
-
const { uri } = request.params;
|
|
2995
|
-
const ctx = mcpContext.getStore();
|
|
2996
|
-
unsubscribe(uri, ctx?.sessionId);
|
|
2997
|
-
return { success: true };
|
|
2998
|
-
});
|
|
2999
|
-
server.setRequestHandler(ListPromptsRequestSchema, async () => ({
|
|
3000
|
-
prompts: await listPrompts()
|
|
3001
|
-
}));
|
|
3002
|
-
server.setRequestHandler(GetPromptRequestSchema, async (request) => {
|
|
3003
|
-
const { name, arguments: args } = request.params;
|
|
3004
|
-
return await getPrompt(name, args || {});
|
|
3005
|
-
});
|
|
3006
|
-
return server;
|
|
3040
|
+
}
|
|
3041
|
+
return true;
|
|
3007
3042
|
}
|
|
3008
|
-
var
|
|
3009
|
-
|
|
3010
|
-
|
|
3011
|
-
|
|
3012
|
-
|
|
3013
|
-
|
|
3014
|
-
|
|
3015
|
-
|
|
3016
|
-
|
|
3017
|
-
|
|
3018
|
-
|
|
3019
|
-
|
|
3020
|
-
|
|
3043
|
+
var TOOL_HANDLERS = {
|
|
3044
|
+
connect_cad: (a) => connectCad(a?.platform),
|
|
3045
|
+
eval_lisp: (a) => evalLisp(a.code),
|
|
3046
|
+
eval_lisp_with_result: (a) => evalLisp(a.code, true, a.encoding),
|
|
3047
|
+
get_cad_info: () => getCadInfo2(),
|
|
3048
|
+
list_packages: () => listPackages(),
|
|
3049
|
+
search_packages: (a) => searchPackages(a.query),
|
|
3050
|
+
install_package: (a) => installPackage(a.packageName),
|
|
3051
|
+
get_platform_info: () => ({ content: [{ type: "text", text: `\u652F\u6301\u7684 CAD \u5E73\u53F0:
|
|
3052
|
+
${CAD_PLATFORMS.join("\n")}
|
|
3053
|
+
\u5F53\u524D\u8FDE\u63A5: ${cad.connected ? "\u5DF2\u8FDE\u63A5" : "\u672A\u8FDE\u63A5"}` }] }),
|
|
3054
|
+
at_command: (a) => atCommand(a.command),
|
|
3055
|
+
new_document: () => newDocument(),
|
|
3056
|
+
bring_to_front: () => bringToFront(),
|
|
3057
|
+
install_atlisp: () => installAtlisp(),
|
|
3058
|
+
init_atlisp: () => initAtlisp(),
|
|
3059
|
+
get_function_usage: (a) => getFunctionUsage(a.name, a.package),
|
|
3060
|
+
list_symbols: (a) => listSymbols(a.package),
|
|
3061
|
+
get_system_status: () => getSystemStatus(),
|
|
3062
|
+
list_prompts: async () => {
|
|
3063
|
+
const prompts = await listPrompts();
|
|
3064
|
+
return { content: [{ type: "text", text: JSON.stringify(prompts) }] };
|
|
3065
|
+
},
|
|
3066
|
+
get_prompt: async (a) => {
|
|
3067
|
+
const prompt = await getPrompt(a.name, a.args || {});
|
|
3068
|
+
return { content: prompt.messages.map((m) => ({ type: "text", text: m.content.text || m.content })) };
|
|
3069
|
+
},
|
|
3070
|
+
import_funlib: async (a) => {
|
|
3071
|
+
const data = await loadAtlibFunctionLib();
|
|
3072
|
+
if (!data) return { content: [{ type: "text", text: "\u52A0\u8F7D\u51FD\u6570\u5E93\u5931\u8D25" }], isError: true };
|
|
3073
|
+
if (a.format === "list") {
|
|
3074
|
+
const items = Object.values(data.all_functions || {}).map((f) => `${f.name}: ${f.description || ""}`);
|
|
3075
|
+
return { content: [{ type: "text", text: items.join("\n") }] };
|
|
3076
|
+
}
|
|
3077
|
+
return { content: [{ type: "text", text: JSON.stringify(data, null, 2) }] };
|
|
3021
3078
|
}
|
|
3022
|
-
}
|
|
3079
|
+
};
|
|
3080
|
+
var tools = [
|
|
3081
|
+
{
|
|
3082
|
+
name: "connect_cad",
|
|
3083
|
+
description: "\u8FDE\u63A5\u5230 CAD (AutoCAD/ZWCAD/GStarCAD/BricsCAD)",
|
|
3084
|
+
inputSchema: {
|
|
3085
|
+
type: "object",
|
|
3086
|
+
properties: {
|
|
3087
|
+
platform: { type: "string", description: "\u6307\u5B9A CAD \u5E73\u53F0: AutoCAD, ZWCAD, GStarCAD, BricsCAD\uFF08\u53EF\u9009\uFF0C\u81EA\u52A8\u68C0\u6D4B\uFF09" }
|
|
3088
|
+
}
|
|
3089
|
+
}
|
|
3090
|
+
},
|
|
3091
|
+
{
|
|
3092
|
+
name: "eval_lisp",
|
|
3093
|
+
description: "\u5728 CAD \u4E2D\u6267\u884C AutoLISP \u4EE3\u7801\uFF08\u4E0D\u8FD4\u56DE\u7ED3\u679C\uFF09",
|
|
3094
|
+
inputSchema: {
|
|
3095
|
+
type: "object",
|
|
3096
|
+
properties: { code: { type: "string", description: "\u8981\u6267\u884C\u7684 LISP \u4EE3\u7801" } },
|
|
3097
|
+
required: ["code"]
|
|
3098
|
+
}
|
|
3099
|
+
},
|
|
3100
|
+
{
|
|
3101
|
+
name: "eval_lisp_with_result",
|
|
3102
|
+
description: "\u5728 CAD \u4E2D\u6267\u884C AutoLISP \u4EE3\u7801\u5E76\u8FD4\u56DE\u7ED3\u679C",
|
|
3103
|
+
inputSchema: {
|
|
3104
|
+
type: "object",
|
|
3105
|
+
properties: {
|
|
3106
|
+
code: { type: "string", description: "\u8981\u6267\u884C\u7684 LISP \u4EE3\u7801" },
|
|
3107
|
+
encoding: { type: "string", description: "\u7ED3\u679C\u7F16\u7801\uFF0C\u5982 utf-8, gbk, gb2312, gb18030\uFF08\u53EF\u9009\uFF0C\u9ED8\u8BA4\u81EA\u52A8\u68C0\u6D4B\uFF09" }
|
|
3108
|
+
},
|
|
3109
|
+
required: ["code"]
|
|
3110
|
+
}
|
|
3111
|
+
},
|
|
3112
|
+
{
|
|
3113
|
+
name: "get_cad_info",
|
|
3114
|
+
description: "\u83B7\u53D6\u5F53\u524D CAD \u4FE1\u606F",
|
|
3115
|
+
inputSchema: { type: "object", properties: {} }
|
|
3116
|
+
},
|
|
3117
|
+
{
|
|
3118
|
+
name: "list_packages",
|
|
3119
|
+
description: "\u5217\u51FA\u5DF2\u5B89\u88C5\u7684 @lisp \u5305",
|
|
3120
|
+
inputSchema: { type: "object", properties: {} }
|
|
3121
|
+
},
|
|
3122
|
+
{
|
|
3123
|
+
name: "search_packages",
|
|
3124
|
+
description: "\u641C\u7D22 @lisp \u5305",
|
|
3125
|
+
inputSchema: {
|
|
3126
|
+
type: "object",
|
|
3127
|
+
properties: { query: { type: "string", description: "\u641C\u7D22\u5173\u952E\u8BCD" } },
|
|
3128
|
+
required: ["query"]
|
|
3129
|
+
}
|
|
3130
|
+
},
|
|
3131
|
+
{
|
|
3132
|
+
name: "install_package",
|
|
3133
|
+
description: "\u5B89\u88C5 @lisp \u5305\u5230 CAD",
|
|
3134
|
+
inputSchema: {
|
|
3135
|
+
type: "object",
|
|
3136
|
+
properties: { packageName: { type: "string", description: "\u5305\u540D\u79F0" } },
|
|
3137
|
+
required: ["packageName"]
|
|
3138
|
+
}
|
|
3139
|
+
},
|
|
3140
|
+
{
|
|
3141
|
+
name: "get_platform_info",
|
|
3142
|
+
description: "\u83B7\u53D6 CAD \u5E73\u53F0\u4FE1\u606F",
|
|
3143
|
+
inputSchema: { type: "object", properties: {} }
|
|
3144
|
+
},
|
|
3145
|
+
{
|
|
3146
|
+
name: "at_command",
|
|
3147
|
+
description: "\u6267\u884C @lisp \u547D\u4EE4",
|
|
3148
|
+
inputSchema: {
|
|
3149
|
+
type: "object",
|
|
3150
|
+
properties: { command: { type: "string", description: "@lisp \u547D\u4EE4" } },
|
|
3151
|
+
required: ["command"]
|
|
3152
|
+
}
|
|
3153
|
+
},
|
|
3154
|
+
{
|
|
3155
|
+
name: "new_document",
|
|
3156
|
+
description: "\u5728 CAD \u4E2D\u65B0\u5EFA\u7A7A\u767D\u6587\u6863",
|
|
3157
|
+
inputSchema: { type: "object", properties: {} }
|
|
3158
|
+
},
|
|
3159
|
+
{
|
|
3160
|
+
name: "bring_to_front",
|
|
3161
|
+
description: "\u5C06 CAD \u7A97\u53E3\u5207\u6362\u5230\u524D\u53F0\uFF08\u4ECE\u540E\u53F0\u8FD0\u884C\u72B6\u6001\u5524\u9192\uFF09",
|
|
3162
|
+
inputSchema: { type: "object", properties: {} }
|
|
3163
|
+
},
|
|
3164
|
+
{
|
|
3165
|
+
name: "install_atlisp",
|
|
3166
|
+
description: "\u5728 CAD \u4E2D\u5B89\u88C5 @lisp",
|
|
3167
|
+
inputSchema: { type: "object", properties: {} }
|
|
3168
|
+
},
|
|
3169
|
+
{
|
|
3170
|
+
name: "init_atlisp",
|
|
3171
|
+
description: "\u521D\u59CB\u5316 CAD \u4E2D\u7684 @lisp \u73AF\u5883\uFF0C\u52A0\u8F7D\u51FD\u6570\u5E93\u548C\u521D\u59CB\u53D8\u91CF",
|
|
3172
|
+
inputSchema: { type: "object", properties: {} }
|
|
3173
|
+
},
|
|
3174
|
+
{
|
|
3175
|
+
name: "get_function_usage",
|
|
3176
|
+
description: "\u83B7\u53D6 @lisp \u51FD\u6570\u7528\u6CD5",
|
|
3177
|
+
inputSchema: {
|
|
3178
|
+
type: "object",
|
|
3179
|
+
properties: {
|
|
3180
|
+
name: { type: "string", description: "\u51FD\u6570\u540D\uFF0C\u5982 string:length" },
|
|
3181
|
+
package: { type: "string", description: "\u5305\u540D\uFF0C\u5982 string\uFF08\u53EF\u9009\uFF0C\u4E0D\u4F20\u5219\u81EA\u52A8\u641C\u7D22\uFF09" }
|
|
3182
|
+
},
|
|
3183
|
+
required: ["name"]
|
|
3184
|
+
}
|
|
3185
|
+
},
|
|
3186
|
+
{
|
|
3187
|
+
name: "list_symbols",
|
|
3188
|
+
description: "\u5217\u51FA @lisp \u6240\u6709\u7B26\u53F7\uFF0C\u7528\u4E8E\u68C0\u67E5\u51FD\u6570\u548C\u53D8\u91CF",
|
|
3189
|
+
inputSchema: {
|
|
3190
|
+
type: "object",
|
|
3191
|
+
properties: {
|
|
3192
|
+
package: { type: "string", description: "\u5305\u540D\uFF08\u53EF\u9009\uFF09" }
|
|
3193
|
+
}
|
|
3194
|
+
}
|
|
3195
|
+
},
|
|
3196
|
+
{
|
|
3197
|
+
name: "import_funlib",
|
|
3198
|
+
description: "\u4ECE\u7F51\u7EDC\u5BFC\u5165 @lisp \u51FD\u6570\u5E93\u6570\u636E\u5230 AI Agent",
|
|
3199
|
+
inputSchema: {
|
|
3200
|
+
type: "object",
|
|
3201
|
+
properties: {
|
|
3202
|
+
format: { type: "string", enum: ["json", "list"], description: "\u8FD4\u56DE\u683C\u5F0F\uFF1Ajson\uFF08\u5B8C\u6574JSON\uFF09\u6216 list\uFF08\u51FD\u6570\u540D:\u63CF\u8FF0 \u5217\u8868\uFF09\uFF0C\u9ED8\u8BA4 json" }
|
|
3203
|
+
}
|
|
3204
|
+
}
|
|
3205
|
+
},
|
|
3206
|
+
{
|
|
3207
|
+
name: "get_system_status",
|
|
3208
|
+
description: "\u83B7\u53D6\u5B8C\u6574\u7CFB\u7EDF\u8BCA\u65AD\u4FE1\u606F\uFF1AMCP \u72B6\u6001\u3001CAD \u8FDE\u63A5\u3001Lisp \u6267\u884C\u3001\u5305\u5217\u8868",
|
|
3209
|
+
inputSchema: { type: "object", properties: {} }
|
|
3210
|
+
},
|
|
3211
|
+
{
|
|
3212
|
+
name: "list_prompts",
|
|
3213
|
+
description: "\u5217\u51FA\u6240\u6709\u53EF\u7528\u7684 @lisp \u63D0\u793A\u6A21\u677F",
|
|
3214
|
+
inputSchema: { type: "object", properties: {} }
|
|
3215
|
+
},
|
|
3216
|
+
{
|
|
3217
|
+
name: "get_prompt",
|
|
3218
|
+
description: "\u83B7\u53D6\u6307\u5B9A\u63D0\u793A\u6A21\u677F\u7684\u5185\u5BB9",
|
|
3219
|
+
inputSchema: {
|
|
3220
|
+
type: "object",
|
|
3221
|
+
properties: {
|
|
3222
|
+
name: { type: "string", description: "\u63D0\u793A\u6A21\u677F\u540D\u79F0" },
|
|
3223
|
+
args: { type: "object", description: "\u6A21\u677F\u53C2\u6570\uFF08\u53EF\u9009\uFF09" }
|
|
3224
|
+
},
|
|
3225
|
+
required: ["name"]
|
|
3226
|
+
}
|
|
3227
|
+
}
|
|
3228
|
+
];
|
|
3229
|
+
function notifyResourceChanges(toolName) {
|
|
3230
|
+
const resourceMap = {
|
|
3231
|
+
connect_cad: ["atlisp://cad/info", "atlisp://dwg/layers", "atlisp://dwg/name", "atlisp://dwg/path", "atlisp://cad/dwgs", "atlisp://packages"],
|
|
3232
|
+
new_document: ["atlisp://dwg/name", "atlisp://dwg/path", "atlisp://cad/dwgs", "atlisp://dwg/layers", "atlisp://dwg/entities", "atlisp://dwg/texts"],
|
|
3233
|
+
install_package: ["atlisp://packages"],
|
|
3234
|
+
install_atlisp: ["atlisp://packages", "atlisp://cad/info"],
|
|
3235
|
+
init_atlisp: ["atlisp://packages", "atlisp://cad/info"]
|
|
3236
|
+
};
|
|
3237
|
+
const uris = resourceMap[toolName];
|
|
3238
|
+
if (uris) {
|
|
3239
|
+
for (const uri of uris) {
|
|
3240
|
+
clearCache(uri);
|
|
3241
|
+
if (isSubscribed(uri)) {
|
|
3242
|
+
notify(uri, null);
|
|
3243
|
+
}
|
|
3244
|
+
}
|
|
3245
|
+
}
|
|
3246
|
+
}
|
|
3247
|
+
async function handleToolCall(name, args) {
|
|
3248
|
+
const handler = TOOL_HANDLERS[name];
|
|
3249
|
+
if (!handler) return { content: [{ type: "text", text: `\u672A\u77E5\u5DE5\u5177: ${name}` }], isError: true };
|
|
3250
|
+
try {
|
|
3251
|
+
validateToolArgs(name, args || {});
|
|
3252
|
+
const result = await handler(args || {});
|
|
3253
|
+
notifyResourceChanges(name);
|
|
3254
|
+
return result;
|
|
3255
|
+
} catch (e) {
|
|
3256
|
+
error(`Tool call error [${name}]: ${e.message}`, { tool: name, args });
|
|
3257
|
+
return { content: [{ type: "text", text: `\u5DE5\u5177\u6267\u884C\u9519\u8BEF: ${e.message}` }], isError: true };
|
|
3258
|
+
}
|
|
3259
|
+
}
|
|
3023
3260
|
|
|
3024
3261
|
// src/mcp-server-state.js
|
|
3025
|
-
|
|
3262
|
+
var mcpContext = new AsyncLocalStorage();
|
|
3263
|
+
var sessionServers = /* @__PURE__ */ new Map();
|
|
3264
|
+
var sessionTransports = /* @__PURE__ */ new Map();
|
|
3265
|
+
var mcpHandlers = { tools, handleToolCall };
|
|
3026
3266
|
async function getOrCreateSessionServer(sessionId) {
|
|
3027
|
-
if (!mcpHandlers) {
|
|
3028
|
-
const { tools: tools2, handleToolCall: handleToolCall2 } = await init_atlisp_mcp().then(() => atlisp_mcp_exports);
|
|
3029
|
-
mcpHandlers = { tools: tools2, handleToolCall: handleToolCall2 };
|
|
3030
|
-
}
|
|
3031
3267
|
let entry = sessionServers.get(sessionId);
|
|
3032
3268
|
if (!entry) {
|
|
3033
3269
|
const server = createMcpServer(mcpHandlers);
|
|
@@ -3061,24 +3297,18 @@ function broadcastToAllSessions(uri) {
|
|
|
3061
3297
|
});
|
|
3062
3298
|
}
|
|
3063
3299
|
}
|
|
3064
|
-
var mcpContext, sessionServers, sessionTransports, mcpHandlers;
|
|
3065
|
-
var init_mcp_server_state = __esm({
|
|
3066
|
-
"src/mcp-server-state.js"() {
|
|
3067
|
-
init_session_transport();
|
|
3068
|
-
init_mcp_handlers();
|
|
3069
|
-
init_logger();
|
|
3070
|
-
mcpContext = new AsyncLocalStorage();
|
|
3071
|
-
sessionServers = /* @__PURE__ */ new Map();
|
|
3072
|
-
sessionTransports = /* @__PURE__ */ new Map();
|
|
3073
|
-
mcpHandlers = null;
|
|
3074
|
-
}
|
|
3075
|
-
});
|
|
3076
3300
|
|
|
3077
3301
|
// src/routes.js
|
|
3078
|
-
|
|
3079
|
-
|
|
3080
|
-
|
|
3081
|
-
|
|
3302
|
+
var sseSessionManager = new SseSessionManager();
|
|
3303
|
+
var { apiKey, enableCors, corsOrigin, rateLimitWindow, rateLimitMax } = config_default;
|
|
3304
|
+
var mcpLimiter = rateLimit({
|
|
3305
|
+
windowMs: rateLimitWindow,
|
|
3306
|
+
max: rateLimitMax,
|
|
3307
|
+
standardHeaders: true,
|
|
3308
|
+
legacyHeaders: false,
|
|
3309
|
+
message: { error: "\u8BF7\u6C42\u8FC7\u4E8E\u9891\u7E41\uFF0C\u8BF7\u7A0D\u540E\u518D\u8BD5" }
|
|
3310
|
+
});
|
|
3311
|
+
var JSON_CONTENT_TYPES = ["application/json", "application/json-rpc", "application/vnd.api+json"];
|
|
3082
3312
|
function createJsonBodyParser() {
|
|
3083
3313
|
return async (req, res, next) => {
|
|
3084
3314
|
const ct = (req.headers["content-type"] || "").toLowerCase();
|
|
@@ -3246,132 +3476,55 @@ async function handleMessage(req, res) {
|
|
|
3246
3476
|
res.status(400).json({ error: "Invalid request" });
|
|
3247
3477
|
}
|
|
3248
3478
|
}
|
|
3249
|
-
var sseSessionManager, apiKey, enableCors, corsOrigin, rateLimitWindow, rateLimitMax, mcpLimiter, JSON_CONTENT_TYPES;
|
|
3250
|
-
var init_routes = __esm({
|
|
3251
|
-
"src/routes.js"() {
|
|
3252
|
-
init_config();
|
|
3253
|
-
init_logger();
|
|
3254
|
-
init_cad();
|
|
3255
|
-
init_subscription_manager();
|
|
3256
|
-
init_sse_session_manager();
|
|
3257
|
-
init_mcp_server_state();
|
|
3258
|
-
init_sse_session();
|
|
3259
|
-
sseSessionManager = new SseSessionManager();
|
|
3260
|
-
({ apiKey, enableCors, corsOrigin, rateLimitWindow, rateLimitMax } = config_default);
|
|
3261
|
-
mcpLimiter = rateLimit({
|
|
3262
|
-
windowMs: rateLimitWindow,
|
|
3263
|
-
max: rateLimitMax,
|
|
3264
|
-
standardHeaders: true,
|
|
3265
|
-
legacyHeaders: false,
|
|
3266
|
-
message: { error: "\u8BF7\u6C42\u8FC7\u4E8E\u9891\u7E41\uFF0C\u8BF7\u7A0D\u540E\u518D\u8BD5" }
|
|
3267
|
-
});
|
|
3268
|
-
JSON_CONTENT_TYPES = ["application/json", "application/json-rpc", "application/vnd.api+json"];
|
|
3269
|
-
}
|
|
3270
|
-
});
|
|
3271
3479
|
|
|
3272
3480
|
// src/atlisp-mcp.js
|
|
3273
|
-
var
|
|
3274
|
-
|
|
3275
|
-
|
|
3276
|
-
|
|
3277
|
-
|
|
3278
|
-
|
|
3279
|
-
|
|
3280
|
-
|
|
3281
|
-
|
|
3282
|
-
|
|
3283
|
-
|
|
3284
|
-
|
|
3285
|
-
|
|
3286
|
-
|
|
3287
|
-
|
|
3288
|
-
|
|
3289
|
-
|
|
3290
|
-
|
|
3291
|
-
|
|
3292
|
-
|
|
3293
|
-
|
|
3294
|
-
|
|
3295
|
-
|
|
3296
|
-
|
|
3297
|
-
|
|
3298
|
-
|
|
3299
|
-
|
|
3300
|
-
|
|
3301
|
-
|
|
3302
|
-
|
|
3303
|
-
|
|
3304
|
-
|
|
3305
|
-
|
|
3306
|
-
|
|
3307
|
-
|
|
3308
|
-
|
|
3309
|
-
|
|
3310
|
-
|
|
3311
|
-
|
|
3312
|
-
|
|
3313
|
-
|
|
3314
|
-
|
|
3315
|
-
|
|
3316
|
-
cachedAt2 = now;
|
|
3317
|
-
return diskCache;
|
|
3318
|
-
}
|
|
3319
|
-
try {
|
|
3320
|
-
const response = await fetch(FUNCTION_LIB_URL, { headers: { "User-Agent": "atlisp-mcp" } });
|
|
3321
|
-
if (response.ok) {
|
|
3322
|
-
const data = await response.json();
|
|
3323
|
-
cachedFunctionLib = data;
|
|
3324
|
-
cachedAt2 = now;
|
|
3325
|
-
writeCacheToDisk2(data);
|
|
3326
|
-
return data;
|
|
3327
|
-
}
|
|
3328
|
-
} catch (e) {
|
|
3329
|
-
error(`loadAtlibFunctionLib error: ${e.message}`);
|
|
3330
|
-
}
|
|
3331
|
-
return cachedFunctionLib;
|
|
3332
|
-
}
|
|
3333
|
-
function validateToolArgs(name, args) {
|
|
3334
|
-
const schema = toolInputSchema[name];
|
|
3335
|
-
if (!schema) return true;
|
|
3336
|
-
for (const [key, type] of Object.entries(schema)) {
|
|
3337
|
-
if (type.endsWith("?")) continue;
|
|
3338
|
-
if (!args[key]) {
|
|
3339
|
-
throw new Error(`Missing required argument: ${key}`);
|
|
3340
|
-
}
|
|
3341
|
-
}
|
|
3342
|
-
return true;
|
|
3343
|
-
}
|
|
3344
|
-
async function handleToolCall(name, args) {
|
|
3345
|
-
const handler = TOOL_HANDLERS[name];
|
|
3346
|
-
if (!handler) return { content: [{ type: "text", text: `\u672A\u77E5\u5DE5\u5177: ${name}` }], isError: true };
|
|
3347
|
-
try {
|
|
3348
|
-
validateToolArgs(name, args || {});
|
|
3349
|
-
const result = await handler(args || {});
|
|
3350
|
-
notifyResourceChanges(name);
|
|
3351
|
-
return result;
|
|
3352
|
-
} catch (e) {
|
|
3353
|
-
error(`Tool call error [${name}]: ${e.message}`, { tool: name, args });
|
|
3354
|
-
return { content: [{ type: "text", text: `\u5DE5\u5177\u6267\u884C\u9519\u8BEF: ${e.message}` }], isError: true };
|
|
3355
|
-
}
|
|
3356
|
-
}
|
|
3357
|
-
function notifyResourceChanges(toolName) {
|
|
3358
|
-
const resourceMap = {
|
|
3359
|
-
connect_cad: ["atlisp://cad/info", "atlisp://dwg/layers", "atlisp://dwg/name", "atlisp://dwg/path", "atlisp://cad/dwgs", "atlisp://packages"],
|
|
3360
|
-
new_document: ["atlisp://dwg/name", "atlisp://dwg/path", "atlisp://cad/dwgs", "atlisp://dwg/layers", "atlisp://dwg/entities", "atlisp://dwg/texts"],
|
|
3361
|
-
install_package: ["atlisp://packages"],
|
|
3362
|
-
install_atlisp: ["atlisp://packages", "atlisp://cad/info"],
|
|
3363
|
-
init_atlisp: ["atlisp://packages", "atlisp://cad/info"]
|
|
3364
|
-
};
|
|
3365
|
-
const uris = resourceMap[toolName];
|
|
3366
|
-
if (uris) {
|
|
3367
|
-
for (const uri of uris) {
|
|
3368
|
-
clearCache(uri);
|
|
3369
|
-
if (isSubscribed(uri)) {
|
|
3370
|
-
notify(uri, null);
|
|
3371
|
-
}
|
|
3481
|
+
var __dirname4 = path8.dirname(fileURLToPath4(import.meta.url));
|
|
3482
|
+
var require2 = createRequire(import.meta.url);
|
|
3483
|
+
var { version } = require2(path8.join(__dirname4, "..", "package.json"));
|
|
3484
|
+
var sseSessionManager2 = new SseSessionManager();
|
|
3485
|
+
var isMcpScript = process.argv[1]?.includes("atlisp-mcp");
|
|
3486
|
+
if (isMcpScript) {
|
|
3487
|
+
const args = process.argv.slice(2);
|
|
3488
|
+
for (let i = 0; i < args.length; i++) {
|
|
3489
|
+
if (args[i] === "--version" || args[i] === "-v") {
|
|
3490
|
+
console.log(`atlisp-mcp v${version}`);
|
|
3491
|
+
process.exit(0);
|
|
3492
|
+
} else if (args[i] === "--help" || args[i] === "-h") {
|
|
3493
|
+
console.log(`
|
|
3494
|
+
@lisp MCP Server v${version}
|
|
3495
|
+
|
|
3496
|
+
Usage: atlisp-mcp [options]
|
|
3497
|
+
|
|
3498
|
+
Options:
|
|
3499
|
+
-v, --version Show version number
|
|
3500
|
+
--transport <type> Transport type: http or stdio (default: http)
|
|
3501
|
+
--port <port> HTTP port (default: 8110)
|
|
3502
|
+
--host <host> HTTP host (default: 0.0.0.0)
|
|
3503
|
+
--stdio Shorthand for --transport stdio
|
|
3504
|
+
-h, --help Show this help message
|
|
3505
|
+
|
|
3506
|
+
Examples:
|
|
3507
|
+
atlisp-mcp # Start HTTP server on port 8110
|
|
3508
|
+
atlisp-mcp --port 3000 # Start HTTP server on port 3000
|
|
3509
|
+
atlisp-mcp --stdio # Start in stdio mode for MCP clients
|
|
3510
|
+
atlisp-mcp --transport stdio # Same as --stdio
|
|
3511
|
+
`);
|
|
3512
|
+
process.exit(0);
|
|
3513
|
+
} else if (args[i] === "--transport" && args[i + 1]) {
|
|
3514
|
+
process.env.TRANSPORT = args[i + 1];
|
|
3515
|
+
i++;
|
|
3516
|
+
} else if (args[i] === "--stdio") {
|
|
3517
|
+
process.env.TRANSPORT = "stdio";
|
|
3518
|
+
} else if (args[i] === "--port" && args[i + 1]) {
|
|
3519
|
+
process.env.PORT = args[i + 1];
|
|
3520
|
+
i++;
|
|
3521
|
+
} else if (args[i] === "--host" && args[i + 1]) {
|
|
3522
|
+
process.env.HOST = args[i + 1];
|
|
3523
|
+
i++;
|
|
3372
3524
|
}
|
|
3373
3525
|
}
|
|
3374
3526
|
}
|
|
3527
|
+
if (config_default.apiKey) log("API Key authentication enabled");
|
|
3375
3528
|
async function initCadConnection() {
|
|
3376
3529
|
log("Attempting to connect to CAD on startup...");
|
|
3377
3530
|
try {
|
|
@@ -3432,282 +3585,9 @@ async function startServer() {
|
|
|
3432
3585
|
process.on("SIGTERM", () => shutdown("SIGTERM"));
|
|
3433
3586
|
}
|
|
3434
3587
|
}
|
|
3435
|
-
|
|
3436
|
-
|
|
3437
|
-
|
|
3438
|
-
init_cad();
|
|
3439
|
-
init_constants();
|
|
3440
|
-
init_logger();
|
|
3441
|
-
init_cad_handlers();
|
|
3442
|
-
init_package_handlers();
|
|
3443
|
-
init_function_handlers();
|
|
3444
|
-
init_resource_handlers();
|
|
3445
|
-
init_prompt_handlers();
|
|
3446
|
-
init_subscription_manager();
|
|
3447
|
-
init_subscription_manager();
|
|
3448
|
-
init_sse_session_manager();
|
|
3449
|
-
init_sse_session();
|
|
3450
|
-
init_config();
|
|
3451
|
-
init_routes();
|
|
3452
|
-
init_mcp_server_state();
|
|
3453
|
-
init_constants();
|
|
3454
|
-
__dirname4 = path7.dirname(fileURLToPath4(import.meta.url));
|
|
3455
|
-
require2 = createRequire(import.meta.url);
|
|
3456
|
-
({ version } = require2(path7.join(__dirname4, "..", "package.json")));
|
|
3457
|
-
sseSessionManager2 = new SseSessionManager();
|
|
3458
|
-
isMcpScript = process.argv[1]?.includes("atlisp-mcp");
|
|
3459
|
-
if (isMcpScript) {
|
|
3460
|
-
const args = process.argv.slice(2);
|
|
3461
|
-
for (let i = 0; i < args.length; i++) {
|
|
3462
|
-
if (args[i] === "--version" || args[i] === "-v") {
|
|
3463
|
-
console.log(`atlisp-mcp v${version}`);
|
|
3464
|
-
process.exit(0);
|
|
3465
|
-
} else if (args[i] === "--help" || args[i] === "-h") {
|
|
3466
|
-
console.log(`
|
|
3467
|
-
@lisp MCP Server v${version}
|
|
3468
|
-
|
|
3469
|
-
Usage: atlisp-mcp [options]
|
|
3470
|
-
|
|
3471
|
-
Options:
|
|
3472
|
-
-v, --version Show version number
|
|
3473
|
-
--transport <type> Transport type: http or stdio (default: http)
|
|
3474
|
-
--port <port> HTTP port (default: 8110)
|
|
3475
|
-
--host <host> HTTP host (default: 0.0.0.0)
|
|
3476
|
-
--stdio Shorthand for --transport stdio
|
|
3477
|
-
-h, --help Show this help message
|
|
3478
|
-
|
|
3479
|
-
Examples:
|
|
3480
|
-
atlisp-mcp # Start HTTP server on port 8110
|
|
3481
|
-
atlisp-mcp --port 3000 # Start HTTP server on port 3000
|
|
3482
|
-
atlisp-mcp --stdio # Start in stdio mode for MCP clients
|
|
3483
|
-
atlisp-mcp --transport stdio # Same as --stdio
|
|
3484
|
-
`);
|
|
3485
|
-
process.exit(0);
|
|
3486
|
-
} else if (args[i] === "--transport" && args[i + 1]) {
|
|
3487
|
-
process.env.TRANSPORT = args[i + 1];
|
|
3488
|
-
i++;
|
|
3489
|
-
} else if (args[i] === "--stdio") {
|
|
3490
|
-
process.env.TRANSPORT = "stdio";
|
|
3491
|
-
} else if (args[i] === "--port" && args[i + 1]) {
|
|
3492
|
-
process.env.PORT = args[i + 1];
|
|
3493
|
-
i++;
|
|
3494
|
-
} else if (args[i] === "--host" && args[i + 1]) {
|
|
3495
|
-
process.env.HOST = args[i + 1];
|
|
3496
|
-
i++;
|
|
3497
|
-
}
|
|
3498
|
-
}
|
|
3499
|
-
}
|
|
3500
|
-
if (config_default.apiKey) log("API Key authentication enabled");
|
|
3501
|
-
CACHE_DIR2 = path7.join(os4.homedir(), ".atlisp", "cache");
|
|
3502
|
-
FUNCLIB_CACHE_FILE2 = path7.join(CACHE_DIR2, "functions.json");
|
|
3503
|
-
CACHE_TTL3 = config_default.functionLibCacheTtl || 5 * 60 * 1e3;
|
|
3504
|
-
FUNCTION_LIB_URL = config_default.functionLibUrl || "http://s3.atlisp.cn/json/functions.json";
|
|
3505
|
-
cachedFunctionLib = null;
|
|
3506
|
-
cachedAt2 = null;
|
|
3507
|
-
toolInputSchema = {
|
|
3508
|
-
connect_cad: { platform: "string?" },
|
|
3509
|
-
eval_lisp: { code: "string" },
|
|
3510
|
-
eval_lisp_with_result: { code: "string", encoding: "string?" },
|
|
3511
|
-
search_packages: { query: "string" },
|
|
3512
|
-
install_package: { packageName: "string" },
|
|
3513
|
-
at_command: { command: "string" },
|
|
3514
|
-
get_function_usage: { name: "string", package: "string?" },
|
|
3515
|
-
list_symbols: { package: "string?" },
|
|
3516
|
-
import_funlib: { format: "string?" },
|
|
3517
|
-
get_prompt: { name: "string", args: "object?" }
|
|
3518
|
-
};
|
|
3519
|
-
TOOL_HANDLERS = {
|
|
3520
|
-
connect_cad: (a) => connectCad(a?.platform),
|
|
3521
|
-
eval_lisp: (a) => evalLisp(a.code),
|
|
3522
|
-
eval_lisp_with_result: (a) => evalLisp(a.code, true, a.encoding),
|
|
3523
|
-
get_cad_info: () => getCadInfo(),
|
|
3524
|
-
list_packages: () => listPackages(),
|
|
3525
|
-
search_packages: (a) => searchPackages(a.query),
|
|
3526
|
-
install_package: (a) => installPackage(a.packageName),
|
|
3527
|
-
get_platform_info: () => ({ content: [{ type: "text", text: `\u652F\u6301\u7684 CAD \u5E73\u53F0:
|
|
3528
|
-
${CAD_PLATFORMS.join("\n")}
|
|
3529
|
-
\u5F53\u524D\u8FDE\u63A5: ${cad.connected ? "\u5DF2\u8FDE\u63A5" : "\u672A\u8FDE\u63A5"}` }] }),
|
|
3530
|
-
at_command: (a) => atCommand(a.command),
|
|
3531
|
-
new_document: () => newDocument(),
|
|
3532
|
-
bring_to_front: () => bringToFront(),
|
|
3533
|
-
install_atlisp: () => installAtlisp(),
|
|
3534
|
-
init_atlisp: () => initAtlisp(),
|
|
3535
|
-
get_function_usage: (a) => getFunctionUsage(a.name, a.package),
|
|
3536
|
-
list_symbols: (a) => listSymbols(a.package),
|
|
3537
|
-
get_system_status: () => getSystemStatus(),
|
|
3538
|
-
list_prompts: async () => {
|
|
3539
|
-
const prompts = await listPrompts();
|
|
3540
|
-
return { content: [{ type: "text", text: JSON.stringify(prompts) }] };
|
|
3541
|
-
},
|
|
3542
|
-
get_prompt: async (a) => {
|
|
3543
|
-
const prompt = await getPrompt(a.name, a.args || {});
|
|
3544
|
-
return { content: prompt.messages.map((m) => ({ type: "text", text: m.content.text || m.content })) };
|
|
3545
|
-
},
|
|
3546
|
-
import_funlib: async (a) => {
|
|
3547
|
-
const data = await loadAtlibFunctionLib();
|
|
3548
|
-
if (!data) return { content: [{ type: "text", text: "\u52A0\u8F7D\u51FD\u6570\u5E93\u5931\u8D25" }], isError: true };
|
|
3549
|
-
if (a.format === "list") {
|
|
3550
|
-
const items = Object.values(data.all_functions || {}).map((f) => `${f.name}: ${f.description || ""}`);
|
|
3551
|
-
return { content: [{ type: "text", text: items.join("\n") }] };
|
|
3552
|
-
}
|
|
3553
|
-
return { content: [{ type: "text", text: JSON.stringify(data, null, 2) }] };
|
|
3554
|
-
}
|
|
3555
|
-
};
|
|
3556
|
-
tools = [
|
|
3557
|
-
{
|
|
3558
|
-
name: "connect_cad",
|
|
3559
|
-
description: "\u8FDE\u63A5\u5230 CAD (AutoCAD/ZWCAD/GStarCAD/BricsCAD)",
|
|
3560
|
-
inputSchema: {
|
|
3561
|
-
type: "object",
|
|
3562
|
-
properties: {
|
|
3563
|
-
platform: { type: "string", description: "\u6307\u5B9A CAD \u5E73\u53F0: AutoCAD, ZWCAD, GStarCAD, BricsCAD\uFF08\u53EF\u9009\uFF0C\u81EA\u52A8\u68C0\u6D4B\uFF09" }
|
|
3564
|
-
}
|
|
3565
|
-
}
|
|
3566
|
-
},
|
|
3567
|
-
{
|
|
3568
|
-
name: "eval_lisp",
|
|
3569
|
-
description: "\u5728 CAD \u4E2D\u6267\u884C AutoLISP \u4EE3\u7801\uFF08\u4E0D\u8FD4\u56DE\u7ED3\u679C\uFF09",
|
|
3570
|
-
inputSchema: {
|
|
3571
|
-
type: "object",
|
|
3572
|
-
properties: { code: { type: "string", description: "\u8981\u6267\u884C\u7684 LISP \u4EE3\u7801" } },
|
|
3573
|
-
required: ["code"]
|
|
3574
|
-
}
|
|
3575
|
-
},
|
|
3576
|
-
{
|
|
3577
|
-
name: "eval_lisp_with_result",
|
|
3578
|
-
description: "\u5728 CAD \u4E2D\u6267\u884C AutoLISP \u4EE3\u7801\u5E76\u8FD4\u56DE\u7ED3\u679C",
|
|
3579
|
-
inputSchema: {
|
|
3580
|
-
type: "object",
|
|
3581
|
-
properties: {
|
|
3582
|
-
code: { type: "string", description: "\u8981\u6267\u884C\u7684 LISP \u4EE3\u7801" },
|
|
3583
|
-
encoding: { type: "string", description: "\u7ED3\u679C\u7F16\u7801\uFF0C\u5982 utf-8, gbk, gb2312, gb18030\uFF08\u53EF\u9009\uFF0C\u9ED8\u8BA4\u81EA\u52A8\u68C0\u6D4B\uFF09" }
|
|
3584
|
-
},
|
|
3585
|
-
required: ["code"]
|
|
3586
|
-
}
|
|
3587
|
-
},
|
|
3588
|
-
{
|
|
3589
|
-
name: "get_cad_info",
|
|
3590
|
-
description: "\u83B7\u53D6\u5F53\u524D CAD \u4FE1\u606F",
|
|
3591
|
-
inputSchema: { type: "object", properties: {} }
|
|
3592
|
-
},
|
|
3593
|
-
{
|
|
3594
|
-
name: "list_packages",
|
|
3595
|
-
description: "\u5217\u51FA\u5DF2\u5B89\u88C5\u7684 @lisp \u5305",
|
|
3596
|
-
inputSchema: { type: "object", properties: {} }
|
|
3597
|
-
},
|
|
3598
|
-
{
|
|
3599
|
-
name: "search_packages",
|
|
3600
|
-
description: "\u641C\u7D22 @lisp \u5305",
|
|
3601
|
-
inputSchema: {
|
|
3602
|
-
type: "object",
|
|
3603
|
-
properties: { query: { type: "string", description: "\u641C\u7D22\u5173\u952E\u8BCD" } },
|
|
3604
|
-
required: ["query"]
|
|
3605
|
-
}
|
|
3606
|
-
},
|
|
3607
|
-
{
|
|
3608
|
-
name: "install_package",
|
|
3609
|
-
description: "\u5B89\u88C5 @lisp \u5305\u5230 CAD",
|
|
3610
|
-
inputSchema: {
|
|
3611
|
-
type: "object",
|
|
3612
|
-
properties: { packageName: { type: "string", description: "\u5305\u540D\u79F0" } },
|
|
3613
|
-
required: ["packageName"]
|
|
3614
|
-
}
|
|
3615
|
-
},
|
|
3616
|
-
{
|
|
3617
|
-
name: "get_platform_info",
|
|
3618
|
-
description: "\u83B7\u53D6 CAD \u5E73\u53F0\u4FE1\u606F",
|
|
3619
|
-
inputSchema: { type: "object", properties: {} }
|
|
3620
|
-
},
|
|
3621
|
-
{
|
|
3622
|
-
name: "at_command",
|
|
3623
|
-
description: "\u6267\u884C @lisp \u547D\u4EE4",
|
|
3624
|
-
inputSchema: {
|
|
3625
|
-
type: "object",
|
|
3626
|
-
properties: { command: { type: "string", description: "@lisp \u547D\u4EE4" } },
|
|
3627
|
-
required: ["command"]
|
|
3628
|
-
}
|
|
3629
|
-
},
|
|
3630
|
-
{
|
|
3631
|
-
name: "new_document",
|
|
3632
|
-
description: "\u5728 CAD \u4E2D\u65B0\u5EFA\u7A7A\u767D\u6587\u6863",
|
|
3633
|
-
inputSchema: { type: "object", properties: {} }
|
|
3634
|
-
},
|
|
3635
|
-
{
|
|
3636
|
-
name: "bring_to_front",
|
|
3637
|
-
description: "\u5C06 CAD \u7A97\u53E3\u5207\u6362\u5230\u524D\u53F0\uFF08\u4ECE\u540E\u53F0\u8FD0\u884C\u72B6\u6001\u5524\u9192\uFF09",
|
|
3638
|
-
inputSchema: { type: "object", properties: {} }
|
|
3639
|
-
},
|
|
3640
|
-
{
|
|
3641
|
-
name: "install_atlisp",
|
|
3642
|
-
description: "\u5728 CAD \u4E2D\u5B89\u88C5 @lisp",
|
|
3643
|
-
inputSchema: { type: "object", properties: {} }
|
|
3644
|
-
},
|
|
3645
|
-
{
|
|
3646
|
-
name: "init_atlisp",
|
|
3647
|
-
description: "\u521D\u59CB\u5316 CAD \u4E2D\u7684 @lisp \u73AF\u5883\uFF0C\u52A0\u8F7D\u51FD\u6570\u5E93\u548C\u521D\u59CB\u53D8\u91CF",
|
|
3648
|
-
inputSchema: { type: "object", properties: {} }
|
|
3649
|
-
},
|
|
3650
|
-
{
|
|
3651
|
-
name: "get_function_usage",
|
|
3652
|
-
description: "\u83B7\u53D6 @lisp \u51FD\u6570\u7528\u6CD5",
|
|
3653
|
-
inputSchema: {
|
|
3654
|
-
type: "object",
|
|
3655
|
-
properties: {
|
|
3656
|
-
name: { type: "string", description: "\u51FD\u6570\u540D\uFF0C\u5982 string:length" },
|
|
3657
|
-
package: { type: "string", description: "\u5305\u540D\uFF0C\u5982 string\uFF08\u53EF\u9009\uFF0C\u4E0D\u4F20\u5219\u81EA\u52A8\u641C\u7D22\uFF09" }
|
|
3658
|
-
},
|
|
3659
|
-
required: ["name"]
|
|
3660
|
-
}
|
|
3661
|
-
},
|
|
3662
|
-
{
|
|
3663
|
-
name: "list_symbols",
|
|
3664
|
-
description: "\u5217\u51FA @lisp \u6240\u6709\u7B26\u53F7\uFF0C\u7528\u4E8E\u68C0\u67E5\u51FD\u6570\u548C\u53D8\u91CF",
|
|
3665
|
-
inputSchema: {
|
|
3666
|
-
type: "object",
|
|
3667
|
-
properties: {
|
|
3668
|
-
package: { type: "string", description: "\u5305\u540D\uFF08\u53EF\u9009\uFF09" }
|
|
3669
|
-
}
|
|
3670
|
-
}
|
|
3671
|
-
},
|
|
3672
|
-
{
|
|
3673
|
-
name: "import_funlib",
|
|
3674
|
-
description: "\u4ECE\u7F51\u7EDC\u5BFC\u5165 @lisp \u51FD\u6570\u5E93\u6570\u636E\u5230 AI Agent",
|
|
3675
|
-
inputSchema: {
|
|
3676
|
-
type: "object",
|
|
3677
|
-
properties: {
|
|
3678
|
-
format: { type: "string", enum: ["json", "list"], description: "\u8FD4\u56DE\u683C\u5F0F\uFF1Ajson\uFF08\u5B8C\u6574JSON\uFF09\u6216 list\uFF08\u51FD\u6570\u540D:\u63CF\u8FF0 \u5217\u8868\uFF09\uFF0C\u9ED8\u8BA4 json" }
|
|
3679
|
-
}
|
|
3680
|
-
}
|
|
3681
|
-
},
|
|
3682
|
-
{
|
|
3683
|
-
name: "get_system_status",
|
|
3684
|
-
description: "\u83B7\u53D6\u5B8C\u6574\u7CFB\u7EDF\u8BCA\u65AD\u4FE1\u606F\uFF1AMCP \u72B6\u6001\u3001CAD \u8FDE\u63A5\u3001Lisp \u6267\u884C\u3001\u5305\u5217\u8868",
|
|
3685
|
-
inputSchema: { type: "object", properties: {} }
|
|
3686
|
-
},
|
|
3687
|
-
{
|
|
3688
|
-
name: "list_prompts",
|
|
3689
|
-
description: "\u5217\u51FA\u6240\u6709\u53EF\u7528\u7684 @lisp \u63D0\u793A\u6A21\u677F",
|
|
3690
|
-
inputSchema: { type: "object", properties: {} }
|
|
3691
|
-
},
|
|
3692
|
-
{
|
|
3693
|
-
name: "get_prompt",
|
|
3694
|
-
description: "\u83B7\u53D6\u6307\u5B9A\u63D0\u793A\u6A21\u677F\u7684\u5185\u5BB9",
|
|
3695
|
-
inputSchema: {
|
|
3696
|
-
type: "object",
|
|
3697
|
-
properties: {
|
|
3698
|
-
name: { type: "string", description: "\u63D0\u793A\u6A21\u677F\u540D\u79F0" },
|
|
3699
|
-
args: { type: "object", description: "\u6A21\u677F\u53C2\u6570\uFF08\u53EF\u9009\uFF09" }
|
|
3700
|
-
},
|
|
3701
|
-
required: ["name"]
|
|
3702
|
-
}
|
|
3703
|
-
}
|
|
3704
|
-
];
|
|
3705
|
-
if (!process.env.VITEST) {
|
|
3706
|
-
await startServer();
|
|
3707
|
-
}
|
|
3708
|
-
}
|
|
3709
|
-
});
|
|
3710
|
-
await init_atlisp_mcp();
|
|
3588
|
+
if (!process.env.VITEST) {
|
|
3589
|
+
await startServer();
|
|
3590
|
+
}
|
|
3711
3591
|
export {
|
|
3712
3592
|
CAD_PLATFORMS,
|
|
3713
3593
|
FILE_EXTENSIONS,
|