@atlisp/mcp 1.5.0 → 1.5.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/atlisp-mcp.js +1578 -1302
- package/package.json +2 -2
package/dist/atlisp-mcp.js
CHANGED
|
@@ -1,138 +1,43 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
import rawBody from "raw-body";
|
|
11
|
-
import iconv from "iconv-lite";
|
|
12
|
-
import rateLimit from "express-rate-limit";
|
|
13
|
-
import { randomUUID as randomUUID4 } from "crypto";
|
|
14
|
-
import { AsyncLocalStorage } from "async_hooks";
|
|
15
|
-
import { Server } from "@modelcontextprotocol/sdk/server/index.js";
|
|
16
|
-
import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
|
|
17
|
-
|
|
18
|
-
// src/session-transport.js
|
|
19
|
-
import { randomUUID } from "crypto";
|
|
20
|
-
var SESSION_TIMEOUT = 30 * 60 * 1e3;
|
|
21
|
-
var SessionTransport = class {
|
|
22
|
-
constructor(sessionId) {
|
|
23
|
-
this.sessionId = sessionId || randomUUID();
|
|
24
|
-
this.onclose = null;
|
|
25
|
-
this.onerror = null;
|
|
26
|
-
this.onmessage = null;
|
|
27
|
-
this._pendingRequest = null;
|
|
28
|
-
this._started = false;
|
|
29
|
-
this._closed = false;
|
|
30
|
-
this._cleanupTimer = null;
|
|
31
|
-
}
|
|
32
|
-
async start() {
|
|
33
|
-
if (this._started) {
|
|
34
|
-
throw new Error("Transport already started");
|
|
35
|
-
}
|
|
36
|
-
this._started = true;
|
|
37
|
-
}
|
|
38
|
-
async send(message) {
|
|
39
|
-
if (this._closed) return;
|
|
40
|
-
if (this._pendingRequest) {
|
|
41
|
-
const { resolve, reject, timeout } = this._pendingRequest;
|
|
42
|
-
clearTimeout(timeout);
|
|
43
|
-
this._pendingRequest = null;
|
|
44
|
-
resolve(message);
|
|
45
|
-
}
|
|
46
|
-
}
|
|
47
|
-
async close() {
|
|
48
|
-
if (this._closed) return;
|
|
49
|
-
this._closed = true;
|
|
50
|
-
if (this._pendingRequest) {
|
|
51
|
-
const { reject, timeout } = this._pendingRequest;
|
|
52
|
-
clearTimeout(timeout);
|
|
53
|
-
this._pendingRequest = null;
|
|
54
|
-
reject(new Error("Transport closed"));
|
|
55
|
-
}
|
|
56
|
-
this._clearCleanupTimer();
|
|
57
|
-
this.onclose?.();
|
|
58
|
-
}
|
|
59
|
-
async handleRequest(message, timeoutMs = 6e4) {
|
|
60
|
-
if (this._closed) {
|
|
61
|
-
throw new Error("Transport closed");
|
|
62
|
-
}
|
|
63
|
-
if (!message || !message.method) {
|
|
64
|
-
throw new Error("Invalid message");
|
|
65
|
-
}
|
|
66
|
-
if (!message.id) {
|
|
67
|
-
this.onmessage?.(message);
|
|
68
|
-
return null;
|
|
69
|
-
}
|
|
70
|
-
return new Promise((resolve, reject) => {
|
|
71
|
-
const timeout = setTimeout(() => {
|
|
72
|
-
if (this._pendingRequest?.resolve === resolve) {
|
|
73
|
-
this._pendingRequest = null;
|
|
74
|
-
reject(new Error("Request timeout"));
|
|
75
|
-
}
|
|
76
|
-
}, timeoutMs);
|
|
77
|
-
this._pendingRequest = { resolve, reject, timeout };
|
|
78
|
-
this.onmessage?.(message);
|
|
79
|
-
});
|
|
80
|
-
}
|
|
81
|
-
resetCleanupTimer() {
|
|
82
|
-
this._clearCleanupTimer();
|
|
83
|
-
this._cleanupTimer = setTimeout(() => {
|
|
84
|
-
this.close();
|
|
85
|
-
}, SESSION_TIMEOUT);
|
|
86
|
-
}
|
|
87
|
-
_clearCleanupTimer() {
|
|
88
|
-
if (this._cleanupTimer) {
|
|
89
|
-
clearTimeout(this._cleanupTimer);
|
|
90
|
-
this._cleanupTimer = null;
|
|
91
|
-
}
|
|
92
|
-
}
|
|
2
|
+
var __defProp = Object.defineProperty;
|
|
3
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
4
|
+
var __esm = (fn, res) => function __init() {
|
|
5
|
+
return fn && (res = (0, fn[__getOwnPropNames(fn)[0]])(fn = 0)), res;
|
|
6
|
+
};
|
|
7
|
+
var __export = (target, all) => {
|
|
8
|
+
for (var name in all)
|
|
9
|
+
__defProp(target, name, { get: all[name], enumerable: true });
|
|
93
10
|
};
|
|
94
|
-
|
|
95
|
-
// src/atlisp-mcp.js
|
|
96
|
-
import {
|
|
97
|
-
ListToolsRequestSchema,
|
|
98
|
-
CallToolRequestSchema,
|
|
99
|
-
ListResourcesRequestSchema,
|
|
100
|
-
ReadResourceRequestSchema,
|
|
101
|
-
SubscribeRequestSchema,
|
|
102
|
-
UnsubscribeRequestSchema,
|
|
103
|
-
ListPromptsRequestSchema,
|
|
104
|
-
GetPromptRequestSchema
|
|
105
|
-
} from "@modelcontextprotocol/sdk/types.js";
|
|
106
|
-
|
|
107
|
-
// src/cad.js
|
|
108
|
-
import { spawn } from "child_process";
|
|
109
|
-
import path from "path";
|
|
110
|
-
import { fileURLToPath } from "url";
|
|
111
|
-
import { randomUUID as randomUUID2 } from "crypto";
|
|
112
11
|
|
|
113
12
|
// src/constants.js
|
|
114
|
-
var CAD_PLATFORMS
|
|
115
|
-
var
|
|
116
|
-
"
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
13
|
+
var CAD_PLATFORMS, FILE_EXTENSIONS, SERVER_NAME, SERVER_VERSION, MOCK_PACKAGES;
|
|
14
|
+
var init_constants = __esm({
|
|
15
|
+
"src/constants.js"() {
|
|
16
|
+
CAD_PLATFORMS = ["AutoCAD", "ZWCAD", "GStarCAD", "BricsCAD"];
|
|
17
|
+
FILE_EXTENSIONS = {
|
|
18
|
+
"AutoCAD": [".fas", ".vlx"],
|
|
19
|
+
"ZWCAD": [".zelx", ".vls"],
|
|
20
|
+
"GStarCAD": [".fas", ".vlx"],
|
|
21
|
+
"BricsCAD": [".des"]
|
|
22
|
+
};
|
|
23
|
+
SERVER_NAME = "atlisp-mcp-server";
|
|
24
|
+
SERVER_VERSION = "1.5.0";
|
|
25
|
+
MOCK_PACKAGES = [
|
|
26
|
+
{ name: "base", description: "\u57FA\u7840\u51FD\u6570\u5E93", version: "1.0.0" },
|
|
27
|
+
{ name: "at-pm", description: "\u5DE5\u7A0B\u9879\u76EE\u7BA1\u7406", version: "2.1.0" },
|
|
28
|
+
{ name: "network", description: "\u7F51\u7EDC\u529F\u80FD\u6A21\u5757", version: "1.5.0" },
|
|
29
|
+
{ name: "userman", description: "\u7528\u6237\u7BA1\u7406", version: "1.2.0" },
|
|
30
|
+
{ name: "pkgman", description: "\u5305\u7BA1\u7406\u5668", version: "2.0.0" },
|
|
31
|
+
{ name: "sidebar", description: "\u4FA7\u8FB9\u680F\u5DE5\u5177", version: "1.0.0" },
|
|
32
|
+
{ name: "aibot", description: "AI \u52A9\u624B", version: "0.9.0" },
|
|
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
|
+
});
|
|
134
38
|
|
|
135
39
|
// src/config.js
|
|
40
|
+
import { z } from "zod";
|
|
136
41
|
function parseArgs() {
|
|
137
42
|
const args = process.argv.slice(2);
|
|
138
43
|
const result = { transport: "http", port: "8110", host: "0.0.0.0" };
|
|
@@ -152,42 +57,65 @@ function parseArgs() {
|
|
|
152
57
|
}
|
|
153
58
|
return result;
|
|
154
59
|
}
|
|
155
|
-
var cliArgs
|
|
156
|
-
var
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
60
|
+
var envSchema, cliArgs, envResult, env, config, config_default;
|
|
61
|
+
var init_config = __esm({
|
|
62
|
+
"src/config.js"() {
|
|
63
|
+
envSchema = z.object({
|
|
64
|
+
PORT: z.string().optional().default("8110"),
|
|
65
|
+
HOST: z.string().optional().default("0.0.0.0"),
|
|
66
|
+
TRANSPORT: z.enum(["http", "stdio"]).optional().default("http"),
|
|
67
|
+
MCP_API_KEY: z.string().optional().default(""),
|
|
68
|
+
ENABLE_SSE: z.string().optional().default("true"),
|
|
69
|
+
MESSAGE_TIMEOUT: z.string().optional().default("60000"),
|
|
70
|
+
HEARTBEAT_INTERVAL: z.string().optional().default("30000"),
|
|
71
|
+
BUSY_RETRIES: z.string().optional().default("10"),
|
|
72
|
+
BUSY_DELAY: z.string().optional().default("500"),
|
|
73
|
+
ENABLE_CORS: z.string().optional().default("true"),
|
|
74
|
+
CORS_ORIGIN: z.string().optional().default("*"),
|
|
75
|
+
RATE_LIMIT_WINDOW: z.string().optional().default("60000"),
|
|
76
|
+
RATE_LIMIT_MAX: z.string().optional().default("100"),
|
|
77
|
+
RESOURCE_CACHE_TTL: z.string().optional().default("5000"),
|
|
78
|
+
FUNCTION_LIB_CACHE_TTL: z.string().optional().default("300000"),
|
|
79
|
+
DEBUG: z.string().optional().default("false"),
|
|
80
|
+
DEBUG_FILE: z.string().optional().default(""),
|
|
81
|
+
FUNCTION_LIB_URL: z.string().optional().default("http://s3.atlisp.cn/json/functions.json")
|
|
82
|
+
});
|
|
83
|
+
cliArgs = parseArgs();
|
|
84
|
+
envResult = envSchema.safeParse(process.env);
|
|
85
|
+
if (!envResult.success) {
|
|
86
|
+
console.error("\u73AF\u5883\u53D8\u91CF\u914D\u7F6E\u9519\u8BEF:", envResult.error.flatten().fieldErrors);
|
|
87
|
+
process.exit(1);
|
|
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
|
+
});
|
|
175
113
|
|
|
176
114
|
// src/cad.js
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
var __dirname = path.dirname(fileURLToPath(import.meta.url));
|
|
182
|
-
var workerPath = path.join(__dirname, "cad-worker.js");
|
|
183
|
-
var worker = null;
|
|
184
|
-
var _platform = null;
|
|
185
|
-
var heartbeatTimer = null;
|
|
186
|
-
var pendingRequests = /* @__PURE__ */ new Map();
|
|
187
|
-
var stdoutHandlerSetup = false;
|
|
188
|
-
var MAX_BUFFER_SIZE = 1024 * 1024;
|
|
189
|
-
var restartCount = 0;
|
|
190
|
-
var restartTimer = null;
|
|
115
|
+
import { spawn } from "child_process";
|
|
116
|
+
import path from "path";
|
|
117
|
+
import { fileURLToPath } from "url";
|
|
118
|
+
import { randomUUID } from "crypto";
|
|
191
119
|
function resetWorker() {
|
|
192
120
|
for (const [id, { reject, timeout }] of pendingRequests) {
|
|
193
121
|
clearTimeout(timeout);
|
|
@@ -308,7 +236,7 @@ function startHeartbeat() {
|
|
|
308
236
|
}
|
|
309
237
|
function sendMessage(msg) {
|
|
310
238
|
const w = getWorker();
|
|
311
|
-
const requestId =
|
|
239
|
+
const requestId = randomUUID();
|
|
312
240
|
return new Promise((resolve, reject) => {
|
|
313
241
|
const timeout = setTimeout(() => {
|
|
314
242
|
const pending = pendingRequests.get(requestId);
|
|
@@ -327,125 +255,142 @@ function sendMessage(msg) {
|
|
|
327
255
|
}
|
|
328
256
|
});
|
|
329
257
|
}
|
|
330
|
-
var
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
const msg = platform ? { type: "connect", platform } : { type: "connect" };
|
|
343
|
-
const result = await sendMessage(msg);
|
|
344
|
-
if (result && result.success) {
|
|
345
|
-
this.version = result.version;
|
|
346
|
-
this.product = result.platform;
|
|
347
|
-
_platform = result.platform;
|
|
348
|
-
this.connected = true;
|
|
349
|
-
return true;
|
|
350
|
-
}
|
|
351
|
-
} catch (e) {
|
|
352
|
-
console.error("CAD connect error:", e.message);
|
|
353
|
-
}
|
|
354
|
-
return false;
|
|
355
|
-
}
|
|
356
|
-
async sendCommand(code) {
|
|
357
|
-
if (!this.connected) throw new Error("\u672A\u8FDE\u63A5 CAD");
|
|
358
|
-
const result = await sendMessage({ type: "send", code, platform: _platform });
|
|
359
|
-
if (result.success) return true;
|
|
360
|
-
throw new Error(result.error || "\u53D1\u9001\u5931\u8D25");
|
|
361
|
-
}
|
|
362
|
-
async sendCommandWithResult(code, encoding = null) {
|
|
363
|
-
if (!this.connected) throw new Error("\u672A\u8FDE\u63A5 CAD");
|
|
364
|
-
const result = await sendMessage({ type: "sendResult", code, platform: _platform, encoding: encoding || "" });
|
|
365
|
-
if (result.success) {
|
|
366
|
-
return result.result || "";
|
|
367
|
-
}
|
|
368
|
-
throw new Error(result.error || "\u53D1\u9001\u5931\u8D25");
|
|
369
|
-
}
|
|
370
|
-
getVersion() {
|
|
371
|
-
return this.version;
|
|
372
|
-
}
|
|
373
|
-
getPlatform() {
|
|
374
|
-
return this.product;
|
|
375
|
-
}
|
|
376
|
-
async isBusy() {
|
|
377
|
-
if (!this.connected) return false;
|
|
378
|
-
try {
|
|
379
|
-
const result = await sendMessage({ type: "isBusy", platform: _platform });
|
|
380
|
-
return result && result.isBusy;
|
|
381
|
-
} catch (e) {
|
|
382
|
-
return false;
|
|
383
|
-
}
|
|
384
|
-
}
|
|
385
|
-
async hasDoc() {
|
|
386
|
-
if (!this.connected) return { hasDoc: false, docCount: 0 };
|
|
387
|
-
try {
|
|
388
|
-
const result = await sendMessage({ type: "hasdoc", platform: _platform });
|
|
389
|
-
return result || { hasDoc: false, docCount: 0 };
|
|
390
|
-
} catch (e) {
|
|
391
|
-
return { hasDoc: false, docCount: 0 };
|
|
392
|
-
}
|
|
393
|
-
}
|
|
394
|
-
async newDoc() {
|
|
395
|
-
if (!this.connected) throw new Error("\u672A\u8FDE\u63A5 CAD");
|
|
396
|
-
try {
|
|
397
|
-
const result = await sendMessage({ type: "newdoc", platform: _platform });
|
|
398
|
-
return result && result.success;
|
|
399
|
-
} catch (e) {
|
|
400
|
-
return false;
|
|
401
|
-
}
|
|
402
|
-
}
|
|
403
|
-
async bringToFront() {
|
|
404
|
-
if (!this.connected) throw new Error("\u672A\u8FDE\u63A5 CAD");
|
|
405
|
-
try {
|
|
406
|
-
const result = await sendMessage({ type: "bringToFront", platform: _platform });
|
|
407
|
-
return result && result.success;
|
|
408
|
-
} catch (e) {
|
|
409
|
-
return false;
|
|
410
|
-
}
|
|
411
|
-
}
|
|
412
|
-
async getInfo() {
|
|
413
|
-
if (!this.connected) return "CAD \u672A\u8FDE\u63A5";
|
|
414
|
-
return `Platform: ${this.product}, Version: ${this.version}, Status: Connected`;
|
|
415
|
-
}
|
|
416
|
-
async disconnect() {
|
|
417
|
-
this.connected = false;
|
|
418
|
-
this.version = null;
|
|
419
|
-
this.product = null;
|
|
420
|
-
_platform = null;
|
|
421
|
-
resetWorker();
|
|
422
|
-
}
|
|
423
|
-
async ping() {
|
|
424
|
-
try {
|
|
425
|
-
const result = await sendMessage({ type: "ping" });
|
|
426
|
-
return result && result.pong;
|
|
427
|
-
} catch (e) {
|
|
428
|
-
return false;
|
|
429
|
-
}
|
|
430
|
-
}
|
|
431
|
-
_reset() {
|
|
432
|
-
this.connected = false;
|
|
433
|
-
this.version = null;
|
|
434
|
-
this.product = null;
|
|
258
|
+
var MESSAGE_TIMEOUT, HEARTBEAT_INTERVAL, MAX_RESTART_ATTEMPTS, RESTART_BACKOFF_BASE, __dirname, workerPath, worker, _platform, heartbeatTimer, pendingRequests, stdoutHandlerSetup, MAX_BUFFER_SIZE, restartCount, restartTimer, CadConnection, cad;
|
|
259
|
+
var init_cad = __esm({
|
|
260
|
+
"src/cad.js"() {
|
|
261
|
+
init_constants();
|
|
262
|
+
init_config();
|
|
263
|
+
MESSAGE_TIMEOUT = config_default.messageTimeout;
|
|
264
|
+
HEARTBEAT_INTERVAL = config_default.heartbeatInterval;
|
|
265
|
+
MAX_RESTART_ATTEMPTS = 5;
|
|
266
|
+
RESTART_BACKOFF_BASE = 1e3;
|
|
267
|
+
__dirname = path.dirname(fileURLToPath(import.meta.url));
|
|
268
|
+
workerPath = path.join(__dirname, "cad-worker.js");
|
|
269
|
+
worker = null;
|
|
435
270
|
_platform = null;
|
|
436
|
-
|
|
271
|
+
heartbeatTimer = null;
|
|
272
|
+
pendingRequests = /* @__PURE__ */ new Map();
|
|
273
|
+
stdoutHandlerSetup = false;
|
|
274
|
+
MAX_BUFFER_SIZE = 1024 * 1024;
|
|
275
|
+
restartCount = 0;
|
|
276
|
+
restartTimer = null;
|
|
277
|
+
CadConnection = class {
|
|
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();
|
|
384
|
+
}
|
|
385
|
+
};
|
|
386
|
+
cad = new CadConnection();
|
|
437
387
|
}
|
|
438
|
-
};
|
|
439
|
-
var cad = new CadConnection();
|
|
388
|
+
});
|
|
440
389
|
|
|
441
390
|
// src/logger.js
|
|
442
391
|
import fs from "fs";
|
|
443
392
|
import path2 from "path";
|
|
444
393
|
import os from "os";
|
|
445
|
-
var DEBUG_FILE = process.env.DEBUG_FILE || path2.join(os.tmpdir(), "mcp-server-debug.log");
|
|
446
|
-
var MAX_LOG_SIZE = 10 * 1024 * 1024;
|
|
447
|
-
var MAX_LOG_FILES = 5;
|
|
448
|
-
var stream = null;
|
|
449
394
|
function rotateLog() {
|
|
450
395
|
if (!fs.existsSync(DEBUG_FILE)) return;
|
|
451
396
|
const stat = fs.statSync(DEBUG_FILE);
|
|
@@ -476,10 +421,27 @@ function getStream() {
|
|
|
476
421
|
}
|
|
477
422
|
return stream;
|
|
478
423
|
}
|
|
479
|
-
function
|
|
480
|
-
const entry =
|
|
481
|
-
|
|
482
|
-
|
|
424
|
+
function formatMessage(level, message, meta = {}) {
|
|
425
|
+
const entry = {
|
|
426
|
+
timestamp: (/* @__PURE__ */ new Date()).toISOString(),
|
|
427
|
+
level,
|
|
428
|
+
message,
|
|
429
|
+
...meta,
|
|
430
|
+
pid: process.pid,
|
|
431
|
+
hostname: os.hostname()
|
|
432
|
+
};
|
|
433
|
+
return JSON.stringify(entry);
|
|
434
|
+
}
|
|
435
|
+
function log(message, meta = {}) {
|
|
436
|
+
if (config_default.debug) {
|
|
437
|
+
getStream().write(formatMessage("INFO", message, meta) + "\n");
|
|
438
|
+
}
|
|
439
|
+
}
|
|
440
|
+
function error(message, meta = {}) {
|
|
441
|
+
getStream().write(formatMessage("ERROR", message, meta) + "\n");
|
|
442
|
+
if (config_default.debug) {
|
|
443
|
+
console.error(`[ERROR] ${message}`, meta);
|
|
444
|
+
}
|
|
483
445
|
}
|
|
484
446
|
function closeLog() {
|
|
485
447
|
if (stream) {
|
|
@@ -487,6 +449,16 @@ function closeLog() {
|
|
|
487
449
|
stream = null;
|
|
488
450
|
}
|
|
489
451
|
}
|
|
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
|
+
});
|
|
490
462
|
|
|
491
463
|
// src/handlers/cad-handlers.js
|
|
492
464
|
async function connectCad(platform = null) {
|
|
@@ -651,12 +623,14 @@ async function initAtlisp() {
|
|
|
651
623
|
return { content: [{ type: "text", text: `\u9519\u8BEF: ${e.message}` }], isError: true };
|
|
652
624
|
}
|
|
653
625
|
}
|
|
626
|
+
var init_cad_handlers = __esm({
|
|
627
|
+
"src/handlers/cad-handlers.js"() {
|
|
628
|
+
init_cad();
|
|
629
|
+
init_logger();
|
|
630
|
+
}
|
|
631
|
+
});
|
|
654
632
|
|
|
655
633
|
// src/handlers/package-handlers.js
|
|
656
|
-
var PACKAGES_LIST_URL = process.env.PACKAGES_LIST_URL || "http://s3.atlisp.cn/packages-list?fmt=json";
|
|
657
|
-
var cachedPackages = null;
|
|
658
|
-
var cachedAt = null;
|
|
659
|
-
var CACHE_TTL = 10 * 60 * 1e3;
|
|
660
634
|
async function fetchPackages() {
|
|
661
635
|
const now = Date.now();
|
|
662
636
|
if (cachedPackages && cachedAt && now - cachedAt < CACHE_TTL) {
|
|
@@ -732,16 +706,22 @@ async function installPackage(packageName) {
|
|
|
732
706
|
}
|
|
733
707
|
return { content: [{ type: "text", text: `\u5305 "${packageName}" \u5B89\u88C5\u547D\u4EE4\u5DF2\u53D1\u9001\uFF01` }] };
|
|
734
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
|
+
});
|
|
735
720
|
|
|
736
721
|
// src/handlers/function-handlers.js
|
|
737
722
|
import fs2 from "fs";
|
|
738
723
|
import path3 from "path";
|
|
739
724
|
import os2 from "os";
|
|
740
|
-
var FUNCTIONS_DIR = process.env.FUNCTIONS_DIR || "";
|
|
741
|
-
var FUNCTIONS_URL = process.env.FUNCTIONS_URL || "http://s3.atlisp.cn/json/functions.json";
|
|
742
|
-
var CACHE_DIR = path3.join(os2.homedir(), ".atlisp", "cache");
|
|
743
|
-
var FUNCLIB_CACHE_FILE = path3.join(CACHE_DIR, "functions.json");
|
|
744
|
-
var FUNCLIB_CACHE_TTL = 24 * 60 * 60 * 1e3;
|
|
745
725
|
function readCacheFromDisk() {
|
|
746
726
|
try {
|
|
747
727
|
const stat = fs2.statSync(FUNCLIB_CACHE_FILE);
|
|
@@ -854,15 +834,23 @@ ${allFuncs.map((f) => f.name).join("\n")}` }] };
|
|
|
854
834
|
return { content: [{ type: "text", text: `\u9519\u8BEF: ${e.message}` }], isError: true };
|
|
855
835
|
}
|
|
856
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
|
+
});
|
|
857
849
|
|
|
858
850
|
// src/handlers/resource-handlers.js
|
|
859
851
|
import fs3 from "fs";
|
|
860
852
|
import path4 from "path";
|
|
861
853
|
import { fileURLToPath as fileURLToPath2 } from "url";
|
|
862
|
-
var __dirname2 = path4.dirname(fileURLToPath2(import.meta.url));
|
|
863
|
-
var STANDARDS_DIR = path4.join(__dirname2, "..", "standards");
|
|
864
|
-
var CACHE_TTL2 = config_default.resourceCacheTtl;
|
|
865
|
-
var resourceCache = /* @__PURE__ */ new Map();
|
|
866
854
|
function getCached(key) {
|
|
867
855
|
const entry = resourceCache.get(key);
|
|
868
856
|
if (entry && Date.now() - entry.timestamp < CACHE_TTL2) {
|
|
@@ -1143,19 +1131,6 @@ function buildTextCode({ layer, bbox, offset, limit }) {
|
|
|
1143
1131
|
(@t:run))
|
|
1144
1132
|
`;
|
|
1145
1133
|
}
|
|
1146
|
-
var RESOURCES = [
|
|
1147
|
-
{ uri: "atlisp://cad/info", name: "CAD Info", description: "CAD \u8FDE\u63A5\u4FE1\u606F", mimeType: "application/json", subscribable: true },
|
|
1148
|
-
{ uri: "atlisp://dwg/layers", name: "Layers", description: "\u56FE\u5C42\u5217\u8868", mimeType: "application/json", subscribable: true },
|
|
1149
|
-
{ 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 },
|
|
1150
|
-
{ 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 },
|
|
1151
|
-
{ uri: "atlisp://dwg/name", name: "DWG Name", description: "\u5F53\u524D DWG \u6587\u4EF6\u540D", mimeType: "application/json", subscribable: true },
|
|
1152
|
-
{ uri: "atlisp://dwg/path", name: "DWG Path", description: "\u6587\u4EF6\u5B8C\u6574\u8DEF\u5F84", mimeType: "application/json", subscribable: true },
|
|
1153
|
-
{ uri: "atlisp://cad/dwgs", name: "DWG List", description: "\u6240\u6709\u6253\u5F00\u7684 DWG \u6587\u4EF6\u5217\u8868", mimeType: "application/json", subscribable: true },
|
|
1154
|
-
{ uri: "atlisp://packages", name: "Packages", description: "\u5DF2\u5B89\u88C5\u5305\u5217\u8868", mimeType: "application/json", subscribable: true },
|
|
1155
|
-
{ uri: "atlisp://platforms", name: "Platforms", description: "\u652F\u6301\u7684\u5E73\u53F0\u4FE1\u606F", mimeType: "application/json", subscribable: false },
|
|
1156
|
-
{ uri: "atlisp://standards/drafting", name: "Drafting Standards", description: "CAD \u5236\u56FE\u89C4\u8303", mimeType: "application/json", subscribable: false },
|
|
1157
|
-
{ uri: "atlisp://standards/coding", name: "Coding Standards", description: "@lisp \u7F16\u7801\u89C4\u8303", mimeType: "application/json", subscribable: false }
|
|
1158
|
-
];
|
|
1159
1134
|
function parseQuery(uri) {
|
|
1160
1135
|
const qIdx = uri.indexOf("?");
|
|
1161
1136
|
if (qIdx === -1) return { base: uri, params: {} };
|
|
@@ -1534,7 +1509,6 @@ function loadStandardsFile(filename) {
|
|
|
1534
1509
|
return null;
|
|
1535
1510
|
}
|
|
1536
1511
|
}
|
|
1537
|
-
var standardsCache = /* @__PURE__ */ new Map();
|
|
1538
1512
|
function getCachedStandards(key) {
|
|
1539
1513
|
const entry = standardsCache.get(key);
|
|
1540
1514
|
if (entry && Date.now() - entry.timestamp < 3e4) return entry.data;
|
|
@@ -1558,16 +1532,38 @@ function getCodingStandards() {
|
|
|
1558
1532
|
if (data) setCachedStandards("coding", data);
|
|
1559
1533
|
return data || { error: "\u7F16\u7801\u89C4\u8303\u6587\u4EF6\u52A0\u8F7D\u5931\u8D25" };
|
|
1560
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();
|
|
1560
|
+
}
|
|
1561
|
+
});
|
|
1561
1562
|
|
|
1562
1563
|
// src/handlers/prompt-handlers.js
|
|
1563
1564
|
import fs4 from "fs";
|
|
1564
1565
|
import path5 from "path";
|
|
1565
1566
|
import { fileURLToPath as fileURLToPath3 } from "url";
|
|
1566
|
-
var __dirname3 = path5.dirname(fileURLToPath3(import.meta.url));
|
|
1567
|
-
var PROMPTS_DIR = path5.join(__dirname3, "..", "prompts");
|
|
1568
|
-
var externalPrompts = null;
|
|
1569
|
-
var externalPromptsAt = 0;
|
|
1570
|
-
var EXTERNAL_PROMPTS_TTL = 3e4;
|
|
1571
1567
|
function loadExternalPrompts() {
|
|
1572
1568
|
const now = Date.now();
|
|
1573
1569
|
if (externalPrompts && now - externalPromptsAt < EXTERNAL_PROMPTS_TTL) {
|
|
@@ -1597,121 +1593,6 @@ function loadExternalPrompts() {
|
|
|
1597
1593
|
externalPromptsAt = now;
|
|
1598
1594
|
return externalPrompts;
|
|
1599
1595
|
}
|
|
1600
|
-
var PROMPTS = [
|
|
1601
|
-
{
|
|
1602
|
-
name: "analyze-drawing",
|
|
1603
|
-
description: "\u5206\u6790\u5F53\u524D\u56FE\u7EB8\u7EDF\u8BA1\u4FE1\u606F",
|
|
1604
|
-
arguments: []
|
|
1605
|
-
},
|
|
1606
|
-
{
|
|
1607
|
-
name: "batch-draw-lines",
|
|
1608
|
-
description: "\u6279\u91CF\u7ED8\u5236\u7EBF\u6BB5",
|
|
1609
|
-
arguments: [
|
|
1610
|
-
{ name: "count", description: "\u7EBF\u6BB5\u6570\u91CF", required: true },
|
|
1611
|
-
{ name: "length", description: "\u7EBF\u6BB5\u957F\u5EA6", required: false }
|
|
1612
|
-
]
|
|
1613
|
-
},
|
|
1614
|
-
{
|
|
1615
|
-
name: "generate-dimension",
|
|
1616
|
-
description: "\u751F\u6210\u5C3A\u5BF8\u6807\u6CE8",
|
|
1617
|
-
arguments: [
|
|
1618
|
-
{ name: "style", description: "\u6807\u6CE8\u6837\u5F0F (horizontal/vertical/aligned)", required: false }
|
|
1619
|
-
]
|
|
1620
|
-
},
|
|
1621
|
-
{
|
|
1622
|
-
name: "export-entities",
|
|
1623
|
-
description: "\u5BFC\u51FA\u56FE\u7EB8\u5B9E\u4F53\u7EDF\u8BA1",
|
|
1624
|
-
arguments: [
|
|
1625
|
-
{ name: "format", description: "\u5BFC\u51FA\u683C\u5F0F (json/list)", required: false }
|
|
1626
|
-
]
|
|
1627
|
-
},
|
|
1628
|
-
{
|
|
1629
|
-
name: "manage-layers",
|
|
1630
|
-
description: "\u56FE\u5C42\u7BA1\u7406\uFF1A\u521B\u5EFA\u3001\u51BB\u7ED3\u3001\u9501\u5B9A\u3001\u5220\u9664\u56FE\u5C42",
|
|
1631
|
-
arguments: [
|
|
1632
|
-
{ name: "action", description: "\u64CD\u4F5C\u7C7B\u578B (list/freeze/lock/off/make/delete)", required: true },
|
|
1633
|
-
{ name: "layers", description: "\u56FE\u5C42\u540D\uFF0C\u591A\u4E2A\u7528\u9017\u53F7\u5206\u9694", required: false },
|
|
1634
|
-
{ name: "color", description: '\u56FE\u5C42\u989C\u8272 (ACI\u53F7\u6216RGB\u5982 "1,2,3")', required: false }
|
|
1635
|
-
]
|
|
1636
|
-
},
|
|
1637
|
-
{
|
|
1638
|
-
name: "manage-blocks",
|
|
1639
|
-
description: "\u5757\u64CD\u4F5C\uFF1A\u63D2\u5165\u5757\u3001\u5217\u51FA\u5757\u3001\u83B7\u53D6/\u8BBE\u7F6E\u5C5E\u6027",
|
|
1640
|
-
arguments: [
|
|
1641
|
-
{ name: "action", description: "\u64CD\u4F5C\u7C7B\u578B (list/insert/attributes/dynprops)", required: true },
|
|
1642
|
-
{ name: "blockName", description: "\u5757\u540D", required: false },
|
|
1643
|
-
{ name: "insertPoint", description: '\u63D2\u5165\u70B9 "x,y"', required: false },
|
|
1644
|
-
{ name: "scale", description: "\u7F29\u653E\u6BD4\u4F8B", required: false }
|
|
1645
|
-
]
|
|
1646
|
-
},
|
|
1647
|
-
{
|
|
1648
|
-
name: "curve-analysis",
|
|
1649
|
-
description: "\u66F2\u7EBF\u5206\u6790\uFF1A\u4EA4\u70B9\u3001\u6700\u8FD1\u70B9\u3001\u5B50\u6BB5\u3001\u7F13\u51B2\u533A",
|
|
1650
|
-
arguments: [
|
|
1651
|
-
{ name: "action", description: "\u64CD\u4F5C (inters/subsegments/closestpoint/join)", required: true },
|
|
1652
|
-
{ name: "distance", description: "\u8FDE\u63A5\u5BB9\u5DEE/\u504F\u79FB\u8DDD\u79BB", required: false }
|
|
1653
|
-
]
|
|
1654
|
-
},
|
|
1655
|
-
{
|
|
1656
|
-
name: "geometry-calc",
|
|
1657
|
-
description: "\u51E0\u4F55\u8BA1\u7B97\uFF1A\u51F8\u5305\u3001\u70B9\u5230\u7EBF\u8DDD\u79BB\u3001\u9762\u5185\u6D4B\u8BD5\u3001\u53D8\u6362",
|
|
1658
|
-
arguments: [
|
|
1659
|
-
{ name: "action", description: "\u64CD\u4F5C (convexhull/dist-point-line/in-curve-p/transform/centroid)", required: true },
|
|
1660
|
-
{ name: "points", description: '\u70B9\u96C6 "x1,y1;x2,y2;..."', required: false }
|
|
1661
|
-
]
|
|
1662
|
-
},
|
|
1663
|
-
{
|
|
1664
|
-
name: "text-process",
|
|
1665
|
-
description: "\u6587\u672C\u5904\u7406\uFF1AMTEXT\u89E3\u6790\u3001Markdown\u8F6CMTEXT\u3001\u53BB\u683C\u5F0F",
|
|
1666
|
-
arguments: [
|
|
1667
|
-
{ name: "action", description: "\u64CD\u4F5C (parse-mtext/remove-fmt/from-markdown/mtext2text)", required: true },
|
|
1668
|
-
{ name: "markdown", description: "Markdown\u6587\u672C\uFF08from-markdown\u64CD\u4F5C\u65F6\u7528\uFF09", required: false }
|
|
1669
|
-
]
|
|
1670
|
-
},
|
|
1671
|
-
{
|
|
1672
|
-
name: "pickset-filter",
|
|
1673
|
-
description: "\u9009\u62E9\u96C6\u64CD\u4F5C\uFF1A\u8FC7\u6EE4\u3001\u8F6C\u6362\u3001\u6279\u91CF\u64CD\u4F5C",
|
|
1674
|
-
arguments: [
|
|
1675
|
-
{ name: "action", description: "\u64CD\u4F5C (by-layer/by-type/by-box/erase/zoom)", required: true },
|
|
1676
|
-
{ name: "dxfType", description: 'DXF\u7C7B\u578B "LINE, CIRCLE, LWPOLYLINE, INSERT, TEXT"', required: false },
|
|
1677
|
-
{ name: "layerName", description: "\u56FE\u5C42\u540D", required: false }
|
|
1678
|
-
]
|
|
1679
|
-
},
|
|
1680
|
-
{
|
|
1681
|
-
name: "color-convert",
|
|
1682
|
-
description: "\u989C\u8272\u8F6C\u6362\uFF1AACI/RGB/TrueColor/CSS\u4E92\u8F6C",
|
|
1683
|
-
arguments: [
|
|
1684
|
-
{ name: "action", description: "\u64CD\u4F5C (aci2rgb/rgb2css/truecolor2rgb/rgb2truecolor)", required: true },
|
|
1685
|
-
{ name: "value", description: "\u989C\u8272\u503C", required: true }
|
|
1686
|
-
]
|
|
1687
|
-
},
|
|
1688
|
-
{
|
|
1689
|
-
name: "json-exchange",
|
|
1690
|
-
description: "JSON\u6570\u636E\u4EA4\u6362\uFF1A\u4ECE\u5B57\u7B26\u4E32\u89E3\u6790JSON alist\uFF0C\u4ECEalist\u751F\u6210JSON",
|
|
1691
|
-
arguments: [
|
|
1692
|
-
{ name: "action", description: "\u64CD\u4F5C (encode/decode)", required: true },
|
|
1693
|
-
{ name: "data", description: "JSON\u5B57\u7B26\u4E32\u6216Lisp alist\u6587\u672C", required: true }
|
|
1694
|
-
]
|
|
1695
|
-
},
|
|
1696
|
-
{
|
|
1697
|
-
name: "excel-report",
|
|
1698
|
-
description: "Excel\u62A5\u8868\uFF1A\u5BFC\u51FACAD\u5B9E\u4F53\u6570\u636E\u5230Excel",
|
|
1699
|
-
arguments: [
|
|
1700
|
-
{ name: "visible", description: "\u662F\u5426\u663E\u793AExcel\u7A97\u53E3 (true/false)", required: false },
|
|
1701
|
-
{ name: "savePath", description: "\u4FDD\u5B58\u8DEF\u5F84\uFF0C\u4E0D\u586B\u5219\u4E0D\u4FDD\u5B58", required: false }
|
|
1702
|
-
]
|
|
1703
|
-
},
|
|
1704
|
-
{
|
|
1705
|
-
name: "string-process",
|
|
1706
|
-
description: "\u5B57\u7B26\u4E32\u5904\u7406\uFF1A\u683C\u5F0F\u5316\u3001\u62C6\u5206\u3001\u66FF\u6362\u3001\u6B63\u5219",
|
|
1707
|
-
arguments: [
|
|
1708
|
-
{ name: "action", description: "\u64CD\u4F5C (format/split/subst-all/regexp/trim/number2chinese)", required: true },
|
|
1709
|
-
{ name: "input", description: "\u8F93\u5165\u5B57\u7B26\u4E32", required: true },
|
|
1710
|
-
{ name: "arg1", description: "\u53C2\u65701\uFF08\u683C\u5F0F\u53C2\u6570/\u5206\u9694\u7B26/\u65E7\u4E32\uFF09", required: false },
|
|
1711
|
-
{ name: "arg2", description: "\u53C2\u65702\uFF08\u65B0\u4E32/\u6B63\u5219\u6A21\u5F0F\uFF09", required: false }
|
|
1712
|
-
]
|
|
1713
|
-
}
|
|
1714
|
-
];
|
|
1715
1596
|
function findExternalPrompt(name) {
|
|
1716
1597
|
const ext = loadExternalPrompts();
|
|
1717
1598
|
return ext.find((p) => p.name === name);
|
|
@@ -2328,86 +2209,215 @@ ${code}
|
|
|
2328
2209
|
}]
|
|
2329
2210
|
};
|
|
2330
2211
|
}
|
|
2212
|
+
var __dirname3, PROMPTS_DIR, externalPrompts, externalPromptsAt, EXTERNAL_PROMPTS_TTL, PROMPTS;
|
|
2213
|
+
var init_prompt_handlers = __esm({
|
|
2214
|
+
"src/handlers/prompt-handlers.js"() {
|
|
2215
|
+
init_cad();
|
|
2216
|
+
__dirname3 = path5.dirname(fileURLToPath3(import.meta.url));
|
|
2217
|
+
PROMPTS_DIR = path5.join(__dirname3, "..", "prompts");
|
|
2218
|
+
externalPrompts = null;
|
|
2219
|
+
externalPromptsAt = 0;
|
|
2220
|
+
EXTERNAL_PROMPTS_TTL = 3e4;
|
|
2221
|
+
PROMPTS = [
|
|
2222
|
+
{
|
|
2223
|
+
name: "analyze-drawing",
|
|
2224
|
+
description: "\u5206\u6790\u5F53\u524D\u56FE\u7EB8\u7EDF\u8BA1\u4FE1\u606F",
|
|
2225
|
+
arguments: []
|
|
2226
|
+
},
|
|
2227
|
+
{
|
|
2228
|
+
name: "batch-draw-lines",
|
|
2229
|
+
description: "\u6279\u91CF\u7ED8\u5236\u7EBF\u6BB5",
|
|
2230
|
+
arguments: [
|
|
2231
|
+
{ name: "count", description: "\u7EBF\u6BB5\u6570\u91CF", required: true },
|
|
2232
|
+
{ name: "length", description: "\u7EBF\u6BB5\u957F\u5EA6", required: false }
|
|
2233
|
+
]
|
|
2234
|
+
},
|
|
2235
|
+
{
|
|
2236
|
+
name: "generate-dimension",
|
|
2237
|
+
description: "\u751F\u6210\u5C3A\u5BF8\u6807\u6CE8",
|
|
2238
|
+
arguments: [
|
|
2239
|
+
{ name: "style", description: "\u6807\u6CE8\u6837\u5F0F (horizontal/vertical/aligned)", required: false }
|
|
2240
|
+
]
|
|
2241
|
+
},
|
|
2242
|
+
{
|
|
2243
|
+
name: "export-entities",
|
|
2244
|
+
description: "\u5BFC\u51FA\u56FE\u7EB8\u5B9E\u4F53\u7EDF\u8BA1",
|
|
2245
|
+
arguments: [
|
|
2246
|
+
{ name: "format", description: "\u5BFC\u51FA\u683C\u5F0F (json/list)", required: false }
|
|
2247
|
+
]
|
|
2248
|
+
},
|
|
2249
|
+
{
|
|
2250
|
+
name: "manage-layers",
|
|
2251
|
+
description: "\u56FE\u5C42\u7BA1\u7406\uFF1A\u521B\u5EFA\u3001\u51BB\u7ED3\u3001\u9501\u5B9A\u3001\u5220\u9664\u56FE\u5C42",
|
|
2252
|
+
arguments: [
|
|
2253
|
+
{ name: "action", description: "\u64CD\u4F5C\u7C7B\u578B (list/freeze/lock/off/make/delete)", required: true },
|
|
2254
|
+
{ name: "layers", description: "\u56FE\u5C42\u540D\uFF0C\u591A\u4E2A\u7528\u9017\u53F7\u5206\u9694", required: false },
|
|
2255
|
+
{ name: "color", description: '\u56FE\u5C42\u989C\u8272 (ACI\u53F7\u6216RGB\u5982 "1,2,3")', required: false }
|
|
2256
|
+
]
|
|
2257
|
+
},
|
|
2258
|
+
{
|
|
2259
|
+
name: "manage-blocks",
|
|
2260
|
+
description: "\u5757\u64CD\u4F5C\uFF1A\u63D2\u5165\u5757\u3001\u5217\u51FA\u5757\u3001\u83B7\u53D6/\u8BBE\u7F6E\u5C5E\u6027",
|
|
2261
|
+
arguments: [
|
|
2262
|
+
{ name: "action", description: "\u64CD\u4F5C\u7C7B\u578B (list/insert/attributes/dynprops)", required: true },
|
|
2263
|
+
{ name: "blockName", description: "\u5757\u540D", required: false },
|
|
2264
|
+
{ name: "insertPoint", description: '\u63D2\u5165\u70B9 "x,y"', required: false },
|
|
2265
|
+
{ name: "scale", description: "\u7F29\u653E\u6BD4\u4F8B", required: false }
|
|
2266
|
+
]
|
|
2267
|
+
},
|
|
2268
|
+
{
|
|
2269
|
+
name: "curve-analysis",
|
|
2270
|
+
description: "\u66F2\u7EBF\u5206\u6790\uFF1A\u4EA4\u70B9\u3001\u6700\u8FD1\u70B9\u3001\u5B50\u6BB5\u3001\u7F13\u51B2\u533A",
|
|
2271
|
+
arguments: [
|
|
2272
|
+
{ name: "action", description: "\u64CD\u4F5C (inters/subsegments/closestpoint/join)", required: true },
|
|
2273
|
+
{ name: "distance", description: "\u8FDE\u63A5\u5BB9\u5DEE/\u504F\u79FB\u8DDD\u79BB", required: false }
|
|
2274
|
+
]
|
|
2275
|
+
},
|
|
2276
|
+
{
|
|
2277
|
+
name: "geometry-calc",
|
|
2278
|
+
description: "\u51E0\u4F55\u8BA1\u7B97\uFF1A\u51F8\u5305\u3001\u70B9\u5230\u7EBF\u8DDD\u79BB\u3001\u9762\u5185\u6D4B\u8BD5\u3001\u53D8\u6362",
|
|
2279
|
+
arguments: [
|
|
2280
|
+
{ name: "action", description: "\u64CD\u4F5C (convexhull/dist-point-line/in-curve-p/transform/centroid)", required: true },
|
|
2281
|
+
{ name: "points", description: '\u70B9\u96C6 "x1,y1;x2,y2;..."', required: false }
|
|
2282
|
+
]
|
|
2283
|
+
},
|
|
2284
|
+
{
|
|
2285
|
+
name: "text-process",
|
|
2286
|
+
description: "\u6587\u672C\u5904\u7406\uFF1AMTEXT\u89E3\u6790\u3001Markdown\u8F6CMTEXT\u3001\u53BB\u683C\u5F0F",
|
|
2287
|
+
arguments: [
|
|
2288
|
+
{ name: "action", description: "\u64CD\u4F5C (parse-mtext/remove-fmt/from-markdown/mtext2text)", required: true },
|
|
2289
|
+
{ name: "markdown", description: "Markdown\u6587\u672C\uFF08from-markdown\u64CD\u4F5C\u65F6\u7528\uFF09", required: false }
|
|
2290
|
+
]
|
|
2291
|
+
},
|
|
2292
|
+
{
|
|
2293
|
+
name: "pickset-filter",
|
|
2294
|
+
description: "\u9009\u62E9\u96C6\u64CD\u4F5C\uFF1A\u8FC7\u6EE4\u3001\u8F6C\u6362\u3001\u6279\u91CF\u64CD\u4F5C",
|
|
2295
|
+
arguments: [
|
|
2296
|
+
{ name: "action", description: "\u64CD\u4F5C (by-layer/by-type/by-box/erase/zoom)", required: true },
|
|
2297
|
+
{ name: "dxfType", description: 'DXF\u7C7B\u578B "LINE, CIRCLE, LWPOLYLINE, INSERT, TEXT"', required: false },
|
|
2298
|
+
{ name: "layerName", description: "\u56FE\u5C42\u540D", required: false }
|
|
2299
|
+
]
|
|
2300
|
+
},
|
|
2301
|
+
{
|
|
2302
|
+
name: "color-convert",
|
|
2303
|
+
description: "\u989C\u8272\u8F6C\u6362\uFF1AACI/RGB/TrueColor/CSS\u4E92\u8F6C",
|
|
2304
|
+
arguments: [
|
|
2305
|
+
{ name: "action", description: "\u64CD\u4F5C (aci2rgb/rgb2css/truecolor2rgb/rgb2truecolor)", required: true },
|
|
2306
|
+
{ name: "value", description: "\u989C\u8272\u503C", required: true }
|
|
2307
|
+
]
|
|
2308
|
+
},
|
|
2309
|
+
{
|
|
2310
|
+
name: "json-exchange",
|
|
2311
|
+
description: "JSON\u6570\u636E\u4EA4\u6362\uFF1A\u4ECE\u5B57\u7B26\u4E32\u89E3\u6790JSON alist\uFF0C\u4ECEalist\u751F\u6210JSON",
|
|
2312
|
+
arguments: [
|
|
2313
|
+
{ name: "action", description: "\u64CD\u4F5C (encode/decode)", required: true },
|
|
2314
|
+
{ name: "data", description: "JSON\u5B57\u7B26\u4E32\u6216Lisp alist\u6587\u672C", required: true }
|
|
2315
|
+
]
|
|
2316
|
+
},
|
|
2317
|
+
{
|
|
2318
|
+
name: "excel-report",
|
|
2319
|
+
description: "Excel\u62A5\u8868\uFF1A\u5BFC\u51FACAD\u5B9E\u4F53\u6570\u636E\u5230Excel",
|
|
2320
|
+
arguments: [
|
|
2321
|
+
{ name: "visible", description: "\u662F\u5426\u663E\u793AExcel\u7A97\u53E3 (true/false)", required: false },
|
|
2322
|
+
{ name: "savePath", description: "\u4FDD\u5B58\u8DEF\u5F84\uFF0C\u4E0D\u586B\u5219\u4E0D\u4FDD\u5B58", required: false }
|
|
2323
|
+
]
|
|
2324
|
+
},
|
|
2325
|
+
{
|
|
2326
|
+
name: "string-process",
|
|
2327
|
+
description: "\u5B57\u7B26\u4E32\u5904\u7406\uFF1A\u683C\u5F0F\u5316\u3001\u62C6\u5206\u3001\u66FF\u6362\u3001\u6B63\u5219",
|
|
2328
|
+
arguments: [
|
|
2329
|
+
{ name: "action", description: "\u64CD\u4F5C (format/split/subst-all/regexp/trim/number2chinese)", required: true },
|
|
2330
|
+
{ name: "input", description: "\u8F93\u5165\u5B57\u7B26\u4E32", required: true },
|
|
2331
|
+
{ name: "arg1", description: "\u53C2\u65701\uFF08\u683C\u5F0F\u53C2\u6570/\u5206\u9694\u7B26/\u65E7\u4E32\uFF09", required: false },
|
|
2332
|
+
{ name: "arg2", description: "\u53C2\u65702\uFF08\u65B0\u4E32/\u6B63\u5219\u6A21\u5F0F\uFF09", required: false }
|
|
2333
|
+
]
|
|
2334
|
+
}
|
|
2335
|
+
];
|
|
2336
|
+
}
|
|
2337
|
+
});
|
|
2331
2338
|
|
|
2332
2339
|
// src/session-manager.js
|
|
2333
|
-
var Session
|
|
2334
|
-
|
|
2335
|
-
|
|
2336
|
-
|
|
2337
|
-
|
|
2338
|
-
|
|
2339
|
-
|
|
2340
|
-
|
|
2341
|
-
|
|
2342
|
-
#sessions = /* @__PURE__ */ new Map();
|
|
2343
|
-
createSession(clientId) {
|
|
2344
|
-
let session = this.#sessions.get(clientId);
|
|
2345
|
-
if (!session) {
|
|
2346
|
-
session = new Session(clientId);
|
|
2347
|
-
this.#sessions.set(clientId, session);
|
|
2348
|
-
}
|
|
2349
|
-
return session;
|
|
2350
|
-
}
|
|
2351
|
-
getSession(clientId) {
|
|
2352
|
-
return this.#sessions.get(clientId) || null;
|
|
2353
|
-
}
|
|
2354
|
-
hasSession(clientId) {
|
|
2355
|
-
return this.#sessions.has(clientId);
|
|
2356
|
-
}
|
|
2357
|
-
removeSession(clientId) {
|
|
2358
|
-
return this.#sessions.delete(clientId);
|
|
2359
|
-
}
|
|
2360
|
-
subscribe(clientId, uri) {
|
|
2361
|
-
const session = this.#sessions.get(clientId);
|
|
2362
|
-
if (session) {
|
|
2363
|
-
session.subscriptions.add(uri);
|
|
2364
|
-
return true;
|
|
2365
|
-
}
|
|
2366
|
-
return false;
|
|
2367
|
-
}
|
|
2368
|
-
unsubscribe(clientId, uri) {
|
|
2369
|
-
const session = this.#sessions.get(clientId);
|
|
2370
|
-
if (session) {
|
|
2371
|
-
return session.subscriptions.delete(uri);
|
|
2372
|
-
}
|
|
2373
|
-
return false;
|
|
2374
|
-
}
|
|
2375
|
-
getSubscriptions(clientId) {
|
|
2376
|
-
const session = this.#sessions.get(clientId);
|
|
2377
|
-
return session ? Array.from(session.subscriptions) : [];
|
|
2378
|
-
}
|
|
2379
|
-
isSubscribed(clientId, uri) {
|
|
2380
|
-
const session = this.#sessions.get(clientId);
|
|
2381
|
-
return session ? session.subscriptions.has(uri) : false;
|
|
2382
|
-
}
|
|
2383
|
-
getAllSubscribedUris() {
|
|
2384
|
-
const all = /* @__PURE__ */ new Set();
|
|
2385
|
-
for (const session of this.#sessions.values()) {
|
|
2386
|
-
for (const uri of session.subscriptions) {
|
|
2387
|
-
all.add(uri);
|
|
2340
|
+
var Session, SessionManager;
|
|
2341
|
+
var init_session_manager = __esm({
|
|
2342
|
+
"src/session-manager.js"() {
|
|
2343
|
+
Session = class {
|
|
2344
|
+
constructor(clientId) {
|
|
2345
|
+
this.clientId = clientId;
|
|
2346
|
+
this.subscriptions = /* @__PURE__ */ new Set();
|
|
2347
|
+
this.createdAt = Date.now();
|
|
2348
|
+
this.connected = false;
|
|
2388
2349
|
}
|
|
2389
|
-
}
|
|
2390
|
-
|
|
2391
|
-
|
|
2392
|
-
|
|
2393
|
-
|
|
2394
|
-
|
|
2395
|
-
|
|
2396
|
-
|
|
2397
|
-
|
|
2398
|
-
|
|
2399
|
-
|
|
2400
|
-
|
|
2401
|
-
|
|
2402
|
-
|
|
2403
|
-
|
|
2404
|
-
|
|
2350
|
+
};
|
|
2351
|
+
SessionManager = class {
|
|
2352
|
+
#sessions = /* @__PURE__ */ new Map();
|
|
2353
|
+
createSession(clientId) {
|
|
2354
|
+
let session = this.#sessions.get(clientId);
|
|
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;
|
|
2412
|
+
}
|
|
2413
|
+
clear() {
|
|
2414
|
+
this.#sessions.clear();
|
|
2415
|
+
}
|
|
2416
|
+
};
|
|
2405
2417
|
}
|
|
2406
|
-
};
|
|
2418
|
+
});
|
|
2407
2419
|
|
|
2408
2420
|
// src/subscription-manager.js
|
|
2409
|
-
var sessionManager = new SessionManager();
|
|
2410
|
-
var _notifyFn = null;
|
|
2411
2421
|
function setNotify(fn) {
|
|
2412
2422
|
_notifyFn = fn;
|
|
2413
2423
|
}
|
|
@@ -2440,239 +2450,250 @@ function notify(uri, data) {
|
|
|
2440
2450
|
_notifyFn(uri, data);
|
|
2441
2451
|
}
|
|
2442
2452
|
}
|
|
2453
|
+
var sessionManager, _notifyFn;
|
|
2454
|
+
var init_subscription_manager = __esm({
|
|
2455
|
+
"src/subscription-manager.js"() {
|
|
2456
|
+
init_session_manager();
|
|
2457
|
+
sessionManager = new SessionManager();
|
|
2458
|
+
_notifyFn = null;
|
|
2459
|
+
}
|
|
2460
|
+
});
|
|
2443
2461
|
|
|
2444
2462
|
// src/sse-session.js
|
|
2445
|
-
import { randomUUID as
|
|
2446
|
-
var DEFAULT_HEARTBEAT_INTERVAL
|
|
2447
|
-
var
|
|
2448
|
-
|
|
2449
|
-
|
|
2450
|
-
|
|
2451
|
-
|
|
2452
|
-
|
|
2453
|
-
|
|
2454
|
-
|
|
2455
|
-
|
|
2456
|
-
|
|
2457
|
-
|
|
2458
|
-
|
|
2459
|
-
#clientId;
|
|
2460
|
-
#active = true;
|
|
2461
|
-
#heartbeatTimer = null;
|
|
2462
|
-
#lastEventId = 0;
|
|
2463
|
-
#heartbeatInterval;
|
|
2464
|
-
#retryInterval;
|
|
2465
|
-
#sessionData = {};
|
|
2466
|
-
#sentMessages = [];
|
|
2467
|
-
#backpressureBuffer = [];
|
|
2468
|
-
#drainHandler = null;
|
|
2469
|
-
constructor(res, options = {}) {
|
|
2470
|
-
this.#res = res;
|
|
2471
|
-
this.#clientId = options.clientId || randomUUID3();
|
|
2472
|
-
this.#heartbeatInterval = options.heartbeatInterval || DEFAULT_HEARTBEAT_INTERVAL;
|
|
2473
|
-
this.#retryInterval = options.retryInterval || DEFAULT_RETRY_INTERVAL;
|
|
2474
|
-
this.#sessionData = options.sessionData || {};
|
|
2475
|
-
if (options.resumeFromId && options.resumeFromId > 0) {
|
|
2476
|
-
this.#lastEventId = options.resumeFromId;
|
|
2477
|
-
}
|
|
2478
|
-
this._setupSseHeaders();
|
|
2479
|
-
this._sendRetry();
|
|
2480
|
-
this._setupDrain();
|
|
2481
|
-
}
|
|
2482
|
-
get clientId() {
|
|
2483
|
-
return this.#clientId;
|
|
2484
|
-
}
|
|
2485
|
-
get isActive() {
|
|
2486
|
-
return this.#active;
|
|
2487
|
-
}
|
|
2488
|
-
get lastEventId() {
|
|
2489
|
-
return this.#lastEventId;
|
|
2490
|
-
}
|
|
2491
|
-
get sessionData() {
|
|
2492
|
-
return this.#sessionData;
|
|
2493
|
-
}
|
|
2494
|
-
get sentMessages() {
|
|
2495
|
-
return [...this.#sentMessages];
|
|
2496
|
-
}
|
|
2497
|
-
getMessagesSince(eventId) {
|
|
2498
|
-
return this.#sentMessages.filter((m) => m.id > eventId);
|
|
2499
|
-
}
|
|
2500
|
-
setSessionData(key, value) {
|
|
2501
|
-
this.#sessionData[key] = value;
|
|
2502
|
-
}
|
|
2503
|
-
getSessionData(key) {
|
|
2504
|
-
return this.#sessionData[key];
|
|
2505
|
-
}
|
|
2506
|
-
get retryInterval() {
|
|
2507
|
-
return this.#retryInterval;
|
|
2508
|
-
}
|
|
2509
|
-
setRetryInterval(ms) {
|
|
2510
|
-
this.#retryInterval = ms;
|
|
2511
|
-
}
|
|
2512
|
-
_sendRetry() {
|
|
2513
|
-
this._write(`retry: ${this.#retryInterval}
|
|
2514
|
-
|
|
2515
|
-
`);
|
|
2516
|
-
}
|
|
2517
|
-
_setupSseHeaders() {
|
|
2518
|
-
this.#res.setHeader("Content-Type", "text/event-stream");
|
|
2519
|
-
this.#res.setHeader("Cache-Control", "no-cache");
|
|
2520
|
-
this.#res.setHeader("Connection", "keep-alive");
|
|
2521
|
-
this.#res.setHeader("Transfer-Encoding", "chunked");
|
|
2522
|
-
this.#res.setHeader("X-Accel-Buffering", "no");
|
|
2523
|
-
if (typeof this.#res.flush !== "function") {
|
|
2524
|
-
this.#res.flush = () => {
|
|
2525
|
-
};
|
|
2526
|
-
}
|
|
2527
|
-
}
|
|
2528
|
-
_formatEvent(event, data, id = null) {
|
|
2529
|
-
const lines = [];
|
|
2530
|
-
if (id !== null) {
|
|
2531
|
-
lines.push(`id: ${id}`);
|
|
2532
|
-
}
|
|
2533
|
-
lines.push(`event: ${event}`);
|
|
2534
|
-
if (data !== null && data !== void 0) {
|
|
2535
|
-
const jsonStr = JSON.stringify(data);
|
|
2536
|
-
lines.push(`data: ${jsonStr}`);
|
|
2537
|
-
} else {
|
|
2538
|
-
lines.push("data:");
|
|
2539
|
-
}
|
|
2540
|
-
return lines.join("\n") + "\n\n";
|
|
2541
|
-
}
|
|
2542
|
-
_setupDrain() {
|
|
2543
|
-
if (typeof this.#res.on !== "function") return;
|
|
2544
|
-
this.#drainHandler = () => {
|
|
2545
|
-
if (!this.#active) return;
|
|
2546
|
-
if (this.#backpressureBuffer.length > 0) {
|
|
2547
|
-
this._drainBuffer();
|
|
2548
|
-
}
|
|
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"
|
|
2549
2477
|
};
|
|
2550
|
-
|
|
2551
|
-
|
|
2552
|
-
|
|
2553
|
-
|
|
2554
|
-
|
|
2555
|
-
|
|
2556
|
-
|
|
2557
|
-
|
|
2558
|
-
|
|
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();
|
|
2559
2502
|
}
|
|
2560
|
-
|
|
2561
|
-
|
|
2562
|
-
if (this.#backpressureBuffer.length > 0) {
|
|
2563
|
-
this._drainBuffer();
|
|
2564
|
-
}
|
|
2565
|
-
}
|
|
2566
|
-
_write(content) {
|
|
2567
|
-
if (!this.#active) return false;
|
|
2568
|
-
try {
|
|
2569
|
-
if (this.#backpressureBuffer.length > 0) {
|
|
2570
|
-
this.#backpressureBuffer.push(content);
|
|
2571
|
-
return true;
|
|
2503
|
+
get clientId() {
|
|
2504
|
+
return this.#clientId;
|
|
2572
2505
|
}
|
|
2573
|
-
|
|
2574
|
-
|
|
2575
|
-
this.#res.flush();
|
|
2506
|
+
get isActive() {
|
|
2507
|
+
return this.#active;
|
|
2576
2508
|
}
|
|
2577
|
-
|
|
2578
|
-
this.#
|
|
2579
|
-
return true;
|
|
2509
|
+
get lastEventId() {
|
|
2510
|
+
return this.#lastEventId;
|
|
2580
2511
|
}
|
|
2581
|
-
|
|
2582
|
-
|
|
2583
|
-
this.#active = false;
|
|
2584
|
-
this.close();
|
|
2585
|
-
return false;
|
|
2586
|
-
}
|
|
2587
|
-
}
|
|
2588
|
-
_flush() {
|
|
2589
|
-
try {
|
|
2590
|
-
if (typeof this.#res.flush === "function") {
|
|
2591
|
-
this.#res.flush();
|
|
2512
|
+
get sessionData() {
|
|
2513
|
+
return this.#sessionData;
|
|
2592
2514
|
}
|
|
2593
|
-
|
|
2594
|
-
|
|
2595
|
-
|
|
2596
|
-
|
|
2597
|
-
|
|
2598
|
-
|
|
2599
|
-
|
|
2600
|
-
|
|
2601
|
-
|
|
2602
|
-
|
|
2603
|
-
|
|
2604
|
-
|
|
2605
|
-
|
|
2606
|
-
|
|
2607
|
-
|
|
2608
|
-
|
|
2609
|
-
|
|
2610
|
-
|
|
2611
|
-
|
|
2612
|
-
|
|
2613
|
-
|
|
2614
|
-
|
|
2615
|
-
|
|
2616
|
-
|
|
2617
|
-
|
|
2618
|
-
|
|
2619
|
-
|
|
2620
|
-
|
|
2621
|
-
|
|
2622
|
-
|
|
2623
|
-
|
|
2624
|
-
|
|
2625
|
-
|
|
2626
|
-
|
|
2627
|
-
|
|
2628
|
-
|
|
2629
|
-
|
|
2630
|
-
|
|
2631
|
-
|
|
2632
|
-
|
|
2633
|
-
|
|
2634
|
-
|
|
2635
|
-
|
|
2636
|
-
|
|
2637
|
-
|
|
2638
|
-
|
|
2639
|
-
|
|
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
|
+
|
|
2536
|
+
`);
|
|
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) {
|
|
2640
2657
|
this.stopHeartbeat();
|
|
2641
|
-
|
|
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
|
+
}
|
|
2642
2675
|
}
|
|
2643
|
-
|
|
2676
|
+
close() {
|
|
2677
|
+
this.#active = false;
|
|
2644
2678
|
this.stopHeartbeat();
|
|
2645
|
-
this
|
|
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
|
+
}
|
|
2646
2688
|
}
|
|
2647
|
-
}
|
|
2648
|
-
}
|
|
2649
|
-
stopHeartbeat() {
|
|
2650
|
-
if (this.#heartbeatTimer) {
|
|
2651
|
-
clearInterval(this.#heartbeatTimer);
|
|
2652
|
-
this.#heartbeatTimer = null;
|
|
2653
|
-
}
|
|
2654
|
-
}
|
|
2655
|
-
close() {
|
|
2656
|
-
this.#active = false;
|
|
2657
|
-
this.stopHeartbeat();
|
|
2658
|
-
if (this.#drainHandler) {
|
|
2659
|
-
this.#res.removeListener("drain", this.#drainHandler);
|
|
2660
|
-
this.#drainHandler = null;
|
|
2661
|
-
}
|
|
2662
|
-
this.#backpressureBuffer = [];
|
|
2663
|
-
try {
|
|
2664
|
-
this.#res.end();
|
|
2665
|
-
} catch (e) {
|
|
2666
|
-
}
|
|
2689
|
+
};
|
|
2667
2690
|
}
|
|
2668
|
-
};
|
|
2691
|
+
});
|
|
2669
2692
|
|
|
2670
2693
|
// src/sse-session-manager.js
|
|
2671
2694
|
import fs5 from "fs";
|
|
2672
2695
|
import path6 from "path";
|
|
2673
2696
|
import os3 from "os";
|
|
2674
|
-
var SESSION_STORE_DIR = path6.join(os3.homedir(), ".atlisp", "sessions");
|
|
2675
|
-
var SESSION_STORE_TTL = 24 * 60 * 60 * 1e3;
|
|
2676
2697
|
function getSessionStorePath(clientId) {
|
|
2677
2698
|
return path6.join(SESSION_STORE_DIR, `${clientId}.json`);
|
|
2678
2699
|
}
|
|
@@ -2704,199 +2725,571 @@ function loadPersistedSessionData(clientId) {
|
|
|
2704
2725
|
return null;
|
|
2705
2726
|
}
|
|
2706
2727
|
}
|
|
2707
|
-
var
|
|
2708
|
-
|
|
2709
|
-
|
|
2710
|
-
|
|
2711
|
-
|
|
2712
|
-
|
|
2713
|
-
|
|
2714
|
-
|
|
2715
|
-
|
|
2716
|
-
|
|
2717
|
-
|
|
2718
|
-
|
|
2719
|
-
|
|
2720
|
-
|
|
2721
|
-
session
|
|
2728
|
+
var SESSION_STORE_DIR, SESSION_STORE_TTL, SseSessionManager;
|
|
2729
|
+
var init_sse_session_manager = __esm({
|
|
2730
|
+
"src/sse-session-manager.js"() {
|
|
2731
|
+
init_sse_session();
|
|
2732
|
+
SESSION_STORE_DIR = path6.join(os3.homedir(), ".atlisp", "sessions");
|
|
2733
|
+
SESSION_STORE_TTL = 24 * 60 * 60 * 1e3;
|
|
2734
|
+
SseSessionManager = class {
|
|
2735
|
+
#sessions = /* @__PURE__ */ new Map();
|
|
2736
|
+
#eventHandlers = /* @__PURE__ */ new Map();
|
|
2737
|
+
constructor() {
|
|
2738
|
+
this.#sessions = /* @__PURE__ */ new Map();
|
|
2739
|
+
this.#eventHandlers = /* @__PURE__ */ new Map();
|
|
2740
|
+
}
|
|
2741
|
+
add(clientId, session) {
|
|
2742
|
+
if (!(session instanceof SseSession)) {
|
|
2743
|
+
throw new Error("session must be an SseSession instance");
|
|
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;
|
|
2722
2763
|
}
|
|
2723
|
-
|
|
2724
|
-
|
|
2725
|
-
|
|
2726
|
-
|
|
2727
|
-
|
|
2728
|
-
|
|
2729
|
-
|
|
2730
|
-
|
|
2731
|
-
|
|
2732
|
-
|
|
2733
|
-
|
|
2734
|
-
|
|
2735
|
-
|
|
2736
|
-
|
|
2737
|
-
|
|
2738
|
-
|
|
2739
|
-
|
|
2740
|
-
|
|
2741
|
-
|
|
2742
|
-
|
|
2743
|
-
|
|
2744
|
-
|
|
2745
|
-
|
|
2746
|
-
|
|
2747
|
-
|
|
2748
|
-
|
|
2749
|
-
|
|
2750
|
-
|
|
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());
|
|
2816
|
+
}
|
|
2817
|
+
this.#eventHandlers.get(event).add(handler);
|
|
2818
|
+
}
|
|
2819
|
+
off(event, handler) {
|
|
2820
|
+
const handlers = this.#eventHandlers.get(event);
|
|
2821
|
+
if (handlers) {
|
|
2822
|
+
handlers.delete(handler);
|
|
2823
|
+
}
|
|
2824
|
+
}
|
|
2825
|
+
emit(event, data) {
|
|
2826
|
+
const handlers = this.#eventHandlers.get(event);
|
|
2827
|
+
if (handlers) {
|
|
2828
|
+
for (const handler of handlers) {
|
|
2829
|
+
try {
|
|
2830
|
+
handler(data);
|
|
2831
|
+
} catch (e) {
|
|
2832
|
+
}
|
|
2833
|
+
}
|
|
2834
|
+
}
|
|
2835
|
+
}
|
|
2836
|
+
cleanupInactive() {
|
|
2837
|
+
for (const [clientId, session] of this.#sessions) {
|
|
2838
|
+
if (!session.isActive) {
|
|
2839
|
+
session.close();
|
|
2840
|
+
this.#sessions.delete(clientId);
|
|
2841
|
+
}
|
|
2842
|
+
}
|
|
2843
|
+
}
|
|
2844
|
+
closeAll() {
|
|
2845
|
+
for (const [clientId, session] of this.#sessions) {
|
|
2846
|
+
persistSessionData(clientId, session.sessionData);
|
|
2847
|
+
session.close();
|
|
2848
|
+
}
|
|
2849
|
+
this.#sessions.clear();
|
|
2850
|
+
}
|
|
2851
|
+
};
|
|
2751
2852
|
}
|
|
2752
|
-
|
|
2753
|
-
|
|
2853
|
+
});
|
|
2854
|
+
|
|
2855
|
+
// src/session-transport.js
|
|
2856
|
+
import { randomUUID as randomUUID3 } from "crypto";
|
|
2857
|
+
var SESSION_TIMEOUT, SessionTransport;
|
|
2858
|
+
var init_session_transport = __esm({
|
|
2859
|
+
"src/session-transport.js"() {
|
|
2860
|
+
SESSION_TIMEOUT = 30 * 60 * 1e3;
|
|
2861
|
+
SessionTransport = class {
|
|
2862
|
+
constructor(sessionId) {
|
|
2863
|
+
this.sessionId = sessionId || randomUUID3();
|
|
2864
|
+
this.onclose = null;
|
|
2865
|
+
this.onerror = null;
|
|
2866
|
+
this.onmessage = null;
|
|
2867
|
+
this._pendingRequest = null;
|
|
2868
|
+
this._started = false;
|
|
2869
|
+
this._closed = false;
|
|
2870
|
+
this._cleanupTimer = null;
|
|
2871
|
+
}
|
|
2872
|
+
async start() {
|
|
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
|
+
};
|
|
2754
2934
|
}
|
|
2755
|
-
|
|
2756
|
-
|
|
2757
|
-
|
|
2758
|
-
|
|
2935
|
+
});
|
|
2936
|
+
|
|
2937
|
+
// src/mcp-handlers.js
|
|
2938
|
+
import {
|
|
2939
|
+
ListToolsRequestSchema,
|
|
2940
|
+
CallToolRequestSchema,
|
|
2941
|
+
ListResourcesRequestSchema,
|
|
2942
|
+
ReadResourceRequestSchema,
|
|
2943
|
+
SubscribeRequestSchema,
|
|
2944
|
+
UnsubscribeRequestSchema,
|
|
2945
|
+
ListPromptsRequestSchema,
|
|
2946
|
+
GetPromptRequestSchema
|
|
2947
|
+
} from "@modelcontextprotocol/sdk/types.js";
|
|
2948
|
+
import { Server } from "@modelcontextprotocol/sdk/server/index.js";
|
|
2949
|
+
function createMcpServer(handlers = {}) {
|
|
2950
|
+
const { tools: tools2 = [], handleToolCall: handleToolCall2 = () => ({ content: [] }) } = handlers;
|
|
2951
|
+
const server = new Server(
|
|
2952
|
+
{ name: SERVER_NAME, version: SERVER_VERSION },
|
|
2953
|
+
{ capabilities: SERVER_CAPABILITIES }
|
|
2954
|
+
);
|
|
2955
|
+
server.setRequestHandler(ListToolsRequestSchema, async () => ({ tools: tools2 }));
|
|
2956
|
+
server.setRequestHandler(CallToolRequestSchema, async (request) => {
|
|
2957
|
+
const { name, arguments: args } = request.params;
|
|
2958
|
+
return await handleToolCall2(name, args || {});
|
|
2959
|
+
});
|
|
2960
|
+
server.setRequestHandler(ListResourcesRequestSchema, async (request) => {
|
|
2961
|
+
const ctx = mcpContext.getStore();
|
|
2962
|
+
const sessionId = ctx?.sessionId;
|
|
2963
|
+
const subscribedUris = sessionId ? list(sessionId) : list();
|
|
2964
|
+
return {
|
|
2965
|
+
resources: await listResources(subscribedUris)
|
|
2966
|
+
};
|
|
2967
|
+
});
|
|
2968
|
+
server.setRequestHandler(ReadResourceRequestSchema, async (request) => {
|
|
2969
|
+
const { uri } = request.params;
|
|
2970
|
+
try {
|
|
2971
|
+
const data = await readResource(uri);
|
|
2972
|
+
return {
|
|
2973
|
+
contents: [{
|
|
2974
|
+
uri,
|
|
2975
|
+
mimeType: "application/json",
|
|
2976
|
+
text: JSON.stringify(data)
|
|
2977
|
+
}]
|
|
2978
|
+
};
|
|
2979
|
+
} catch (e) {
|
|
2980
|
+
return {
|
|
2981
|
+
contents: [],
|
|
2982
|
+
isError: true,
|
|
2983
|
+
error: { code: -32603, message: e.message }
|
|
2984
|
+
};
|
|
2759
2985
|
}
|
|
2760
|
-
|
|
2761
|
-
|
|
2762
|
-
|
|
2763
|
-
|
|
2986
|
+
});
|
|
2987
|
+
server.setRequestHandler(SubscribeRequestSchema, async (request) => {
|
|
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;
|
|
3007
|
+
}
|
|
3008
|
+
var SERVER_CAPABILITIES;
|
|
3009
|
+
var init_mcp_handlers = __esm({
|
|
3010
|
+
"src/mcp-handlers.js"() {
|
|
3011
|
+
init_resource_handlers();
|
|
3012
|
+
init_prompt_handlers();
|
|
3013
|
+
init_constants();
|
|
3014
|
+
init_subscription_manager();
|
|
3015
|
+
init_mcp_server_state();
|
|
3016
|
+
SERVER_CAPABILITIES = {
|
|
3017
|
+
tools: {},
|
|
3018
|
+
resources: { subscribe: true, listChanged: true },
|
|
3019
|
+
prompts: {}
|
|
3020
|
+
};
|
|
2764
3021
|
}
|
|
2765
|
-
|
|
2766
|
-
|
|
3022
|
+
});
|
|
3023
|
+
|
|
3024
|
+
// src/mcp-server-state.js
|
|
3025
|
+
import { AsyncLocalStorage } from "async_hooks";
|
|
3026
|
+
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 };
|
|
2767
3030
|
}
|
|
2768
|
-
|
|
2769
|
-
|
|
3031
|
+
let entry = sessionServers.get(sessionId);
|
|
3032
|
+
if (!entry) {
|
|
3033
|
+
const server = createMcpServer(mcpHandlers);
|
|
3034
|
+
const transport = new SessionTransport(sessionId);
|
|
3035
|
+
server.connect(transport);
|
|
3036
|
+
entry = { server, transport };
|
|
3037
|
+
sessionServers.set(sessionId, entry);
|
|
3038
|
+
sessionTransports.set(sessionId, transport);
|
|
2770
3039
|
}
|
|
2771
|
-
|
|
2772
|
-
|
|
2773
|
-
|
|
2774
|
-
|
|
2775
|
-
|
|
2776
|
-
|
|
2777
|
-
|
|
2778
|
-
|
|
3040
|
+
return entry;
|
|
3041
|
+
}
|
|
3042
|
+
function createStdioServer(handlers) {
|
|
3043
|
+
mcpHandlers = handlers;
|
|
3044
|
+
return createMcpServer(handlers);
|
|
3045
|
+
}
|
|
3046
|
+
function removeSessionServer(sessionId) {
|
|
3047
|
+
const entry = sessionServers.get(sessionId);
|
|
3048
|
+
if (entry) {
|
|
3049
|
+
entry.transport.close().catch(() => {
|
|
3050
|
+
});
|
|
3051
|
+
entry.server.close().catch(() => {
|
|
3052
|
+
});
|
|
3053
|
+
sessionServers.delete(sessionId);
|
|
3054
|
+
sessionTransports.delete(sessionId);
|
|
2779
3055
|
}
|
|
2780
|
-
|
|
2781
|
-
|
|
3056
|
+
}
|
|
3057
|
+
function broadcastToAllSessions(uri) {
|
|
3058
|
+
for (const [sid, entry] of sessionServers) {
|
|
3059
|
+
entry.server.sendResourceUpdated({ uri }).catch((err) => {
|
|
3060
|
+
error(`Failed to send resource update to session ${sid}: ${err.message}`, { sessionId: sid, uri });
|
|
3061
|
+
});
|
|
2782
3062
|
}
|
|
2783
|
-
|
|
2784
|
-
|
|
3063
|
+
}
|
|
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;
|
|
2785
3074
|
}
|
|
2786
|
-
|
|
2787
|
-
|
|
2788
|
-
|
|
3075
|
+
});
|
|
3076
|
+
|
|
3077
|
+
// src/routes.js
|
|
3078
|
+
import express from "express";
|
|
3079
|
+
import { randomUUID as randomUUID4 } from "crypto";
|
|
3080
|
+
import iconv from "iconv-lite";
|
|
3081
|
+
import rateLimit from "express-rate-limit";
|
|
3082
|
+
function createJsonBodyParser() {
|
|
3083
|
+
return async (req, res, next) => {
|
|
3084
|
+
const ct = (req.headers["content-type"] || "").toLowerCase();
|
|
3085
|
+
if (!JSON_CONTENT_TYPES.some((t) => ct.startsWith(t))) return next();
|
|
3086
|
+
try {
|
|
3087
|
+
const chunks = [];
|
|
3088
|
+
for await (const chunk of req) {
|
|
3089
|
+
chunks.push(chunk);
|
|
3090
|
+
}
|
|
3091
|
+
const totalLength = chunks.reduce((acc, c) => acc + c.length, 0);
|
|
3092
|
+
if (totalLength > 10 * 1024 * 1024) {
|
|
3093
|
+
throw new Error("Request body too large");
|
|
3094
|
+
}
|
|
3095
|
+
const buf = Buffer.concat(chunks);
|
|
3096
|
+
const m = ct.match(/charset\s*=\s*([^\s;]+)/i);
|
|
3097
|
+
let charset = m ? m[1].toLowerCase() : "utf-8";
|
|
3098
|
+
const charsetMap = { "gb2312": "gbk", "gb18030": "gbk", "gbk": "gbk", "936": "gbk" };
|
|
3099
|
+
charset = charsetMap[charset] || charset;
|
|
3100
|
+
const str = iconv.decode(buf, charset);
|
|
3101
|
+
req.body = JSON.parse(str);
|
|
3102
|
+
next();
|
|
3103
|
+
} catch (e) {
|
|
3104
|
+
res.status(400).json({ error: "Invalid JSON body", message: e.message });
|
|
2789
3105
|
}
|
|
2790
|
-
|
|
2791
|
-
|
|
2792
|
-
|
|
2793
|
-
|
|
2794
|
-
|
|
2795
|
-
|
|
3106
|
+
};
|
|
3107
|
+
}
|
|
3108
|
+
function createLoggingMiddleware() {
|
|
3109
|
+
return (req, res, next) => {
|
|
3110
|
+
log(`${req.method} ${req.path}`, { method: req.method, path: req.path, query: req.query });
|
|
3111
|
+
next();
|
|
3112
|
+
};
|
|
3113
|
+
}
|
|
3114
|
+
function createAuthMiddleware() {
|
|
3115
|
+
const PUBLIC_PATHS = ["/health"];
|
|
3116
|
+
return (req, res, next) => {
|
|
3117
|
+
if (apiKey) {
|
|
3118
|
+
if (PUBLIC_PATHS.includes(req.path)) return next();
|
|
3119
|
+
const auth = req.get("Authorization");
|
|
3120
|
+
if (auth === `Bearer ${apiKey}`) return next();
|
|
3121
|
+
return res.status(401).json({ error: "Unauthorized" });
|
|
2796
3122
|
}
|
|
2797
|
-
|
|
2798
|
-
|
|
2799
|
-
|
|
2800
|
-
|
|
2801
|
-
|
|
2802
|
-
|
|
2803
|
-
|
|
2804
|
-
|
|
3123
|
+
next();
|
|
3124
|
+
};
|
|
3125
|
+
}
|
|
3126
|
+
function createCorsMiddleware() {
|
|
3127
|
+
return (req, res, next) => {
|
|
3128
|
+
if (!enableCors) return next();
|
|
3129
|
+
res.setHeader("Access-Control-Allow-Origin", corsOrigin);
|
|
3130
|
+
res.setHeader("Access-Control-Allow-Methods", "GET, POST, OPTIONS, CONNECT");
|
|
3131
|
+
res.setHeader("Access-Control-Allow-Headers", "Content-Type, Authorization, Accept, mcp-session-id, last-event-id");
|
|
3132
|
+
res.setHeader("Access-Control-Expose-Headers", "mcp-session-id, content-type, x-accel-buffering");
|
|
3133
|
+
res.setHeader("Access-Control-Max-Age", "86400");
|
|
3134
|
+
res.setHeader("Vary", "Accept");
|
|
3135
|
+
if (req.method === "OPTIONS") return res.status(204).end();
|
|
3136
|
+
next();
|
|
3137
|
+
};
|
|
3138
|
+
}
|
|
3139
|
+
function createErrorHandler() {
|
|
3140
|
+
return (err, req, res, next) => {
|
|
3141
|
+
error(`Unhandled error: ${err.message}`, { stack: err.stack, path: req.path });
|
|
3142
|
+
res.status(500).json({ error: "Internal server error", message: err.message });
|
|
3143
|
+
};
|
|
3144
|
+
}
|
|
3145
|
+
function setupRoutes(app) {
|
|
3146
|
+
app.use(createJsonBodyParser());
|
|
3147
|
+
app.use(createLoggingMiddleware());
|
|
3148
|
+
app.use(createAuthMiddleware());
|
|
3149
|
+
app.use(createCorsMiddleware());
|
|
3150
|
+
app.get("/health", (req, res) => {
|
|
3151
|
+
res.json({ status: "ok", cad: cad.connected ? "connected" : "disconnected" });
|
|
3152
|
+
});
|
|
3153
|
+
app.get("/api/docs", (req, res) => {
|
|
3154
|
+
res.json({
|
|
3155
|
+
openapi: "3.0.0",
|
|
3156
|
+
info: { title: "@lisp MCP Server", version: "1.5.0" },
|
|
3157
|
+
paths: {
|
|
3158
|
+
"/mcp": { post: { summary: "MCP JSON-RPC endpoint" } },
|
|
3159
|
+
"/sse": { get: { summary: "Server-Sent Events endpoint" } },
|
|
3160
|
+
"/message": { post: { summary: "SSE message endpoint" } },
|
|
3161
|
+
"/health": { get: { summary: "Health check" } }
|
|
3162
|
+
}
|
|
3163
|
+
});
|
|
3164
|
+
});
|
|
3165
|
+
app.all("/mcp", mcpLimiter, handleMcpPost);
|
|
3166
|
+
app.all("/mcp/:path", mcpLimiter, handleMcpPost);
|
|
3167
|
+
app.get("/mcp/stream", mcpLimiter, handleMcpPost);
|
|
3168
|
+
app.get("/sse", handleSse);
|
|
3169
|
+
app.post("/message", mcpLimiter, handleMessage);
|
|
3170
|
+
app.use(createErrorHandler());
|
|
3171
|
+
return app;
|
|
3172
|
+
}
|
|
3173
|
+
async function handleMcpPost(req, res) {
|
|
3174
|
+
const sessionId = req.headers["mcp-session-id"] || req.query.sessionId || randomUUID4();
|
|
3175
|
+
sessionManager.createSession(sessionId);
|
|
3176
|
+
const body = req.body;
|
|
3177
|
+
if (!body || !body.method) {
|
|
3178
|
+
return res.status(400).json({ error: "Invalid request" });
|
|
3179
|
+
}
|
|
3180
|
+
const { server, transport } = await getOrCreateSessionServer(sessionId);
|
|
3181
|
+
transport.resetCleanupTimer();
|
|
3182
|
+
await mcpContext.run({ sessionId }, async () => {
|
|
3183
|
+
try {
|
|
3184
|
+
const response = await transport.handleRequest(body);
|
|
3185
|
+
if (response) {
|
|
3186
|
+
const headers = { "Content-Type": "application/json" };
|
|
3187
|
+
if (transport.sessionId) {
|
|
3188
|
+
headers["mcp-session-id"] = transport.sessionId;
|
|
3189
|
+
}
|
|
3190
|
+
res.writeHead(200, headers);
|
|
3191
|
+
res.end(JSON.stringify(response));
|
|
3192
|
+
} else {
|
|
3193
|
+
if (!res.headersSent) {
|
|
3194
|
+
res.status(202).end();
|
|
2805
3195
|
}
|
|
2806
3196
|
}
|
|
2807
|
-
}
|
|
2808
|
-
|
|
2809
|
-
|
|
2810
|
-
|
|
2811
|
-
if (!session.isActive) {
|
|
2812
|
-
session.close();
|
|
2813
|
-
this.#sessions.delete(clientId);
|
|
3197
|
+
} catch (err) {
|
|
3198
|
+
error(`Transport error [${sessionId}]: ${err.message}`);
|
|
3199
|
+
if (!res.headersSent) {
|
|
3200
|
+
res.status(500).json({ error: "Internal server error", message: err.message });
|
|
2814
3201
|
}
|
|
2815
3202
|
}
|
|
3203
|
+
});
|
|
3204
|
+
}
|
|
3205
|
+
async function handleSse(req, res) {
|
|
3206
|
+
const sessionId = randomUUID4();
|
|
3207
|
+
sessionManager.createSession(sessionId);
|
|
3208
|
+
getOrCreateSessionServer(sessionId);
|
|
3209
|
+
const sseSession = new SseSession(res, { clientId: sessionId });
|
|
3210
|
+
sseSessionManager.add(sessionId, sseSession);
|
|
3211
|
+
sseSession.sendEndpoint(`/message?sessionId=${sessionId}`);
|
|
3212
|
+
req.on("close", () => {
|
|
3213
|
+
sseSessionManager.remove(sessionId);
|
|
3214
|
+
removeSessionServer(sessionId);
|
|
3215
|
+
});
|
|
3216
|
+
}
|
|
3217
|
+
async function handleMessage(req, res) {
|
|
3218
|
+
const sessionId = req.query.sessionId;
|
|
3219
|
+
if (!sessionId) {
|
|
3220
|
+
return res.status(400).json({ error: "Missing sessionId" });
|
|
3221
|
+
}
|
|
3222
|
+
const sseSession = sseSessionManager.get(sessionId);
|
|
3223
|
+
if (!sseSession) {
|
|
3224
|
+
return res.status(404).json({ error: "Session not found" });
|
|
2816
3225
|
}
|
|
2817
|
-
|
|
2818
|
-
|
|
2819
|
-
|
|
2820
|
-
|
|
3226
|
+
sessionManager.createSession(sessionId);
|
|
3227
|
+
const { server, transport } = await getOrCreateSessionServer(sessionId);
|
|
3228
|
+
transport.resetCleanupTimer();
|
|
3229
|
+
const body = req.body;
|
|
3230
|
+
if (body && body.method) {
|
|
3231
|
+
try {
|
|
3232
|
+
const response = await transport.handleRequest(body);
|
|
3233
|
+
if (response) {
|
|
3234
|
+
sseSession.sendResponse(response);
|
|
3235
|
+
}
|
|
3236
|
+
if (!res.headersSent) {
|
|
3237
|
+
res.status(202).end();
|
|
3238
|
+
}
|
|
3239
|
+
} catch (err) {
|
|
3240
|
+
error(`SSE message error [${sessionId}]: ${err.message}`);
|
|
3241
|
+
if (!res.headersSent) {
|
|
3242
|
+
res.status(500).json({ error: "Internal server error" });
|
|
3243
|
+
}
|
|
2821
3244
|
}
|
|
2822
|
-
|
|
3245
|
+
} else {
|
|
3246
|
+
res.status(400).json({ error: "Invalid request" });
|
|
3247
|
+
}
|
|
3248
|
+
}
|
|
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"];
|
|
2823
3269
|
}
|
|
2824
|
-
};
|
|
3270
|
+
});
|
|
2825
3271
|
|
|
2826
3272
|
// src/atlisp-mcp.js
|
|
2827
|
-
var
|
|
2828
|
-
|
|
2829
|
-
|
|
2830
|
-
|
|
2831
|
-
|
|
2832
|
-
|
|
2833
|
-
|
|
2834
|
-
|
|
2835
|
-
const args = process.argv.slice(2);
|
|
2836
|
-
for (let i = 0; i < args.length; i++) {
|
|
2837
|
-
if (args[i] === "--version" || args[i] === "-v") {
|
|
2838
|
-
console.log(`atlisp-mcp v${version}`);
|
|
2839
|
-
process.exit(0);
|
|
2840
|
-
} else if (args[i] === "--help" || args[i] === "-h") {
|
|
2841
|
-
console.log(`
|
|
2842
|
-
@lisp MCP Server v${version}
|
|
2843
|
-
|
|
2844
|
-
Usage: atlisp-mcp [options]
|
|
2845
|
-
|
|
2846
|
-
Options:
|
|
2847
|
-
-v, --version Show version number
|
|
2848
|
-
--transport <type> Transport type: http or stdio (default: http)
|
|
2849
|
-
--port <port> HTTP port (default: 8110)
|
|
2850
|
-
--host <host> HTTP host (default: 0.0.0.0)
|
|
2851
|
-
--stdio Shorthand for --transport stdio
|
|
2852
|
-
-h, --help Show this help message
|
|
2853
|
-
|
|
2854
|
-
Examples:
|
|
2855
|
-
atlisp-mcp # Start HTTP server on port 8110
|
|
2856
|
-
atlisp-mcp --port 3000 # Start HTTP server on port 3000
|
|
2857
|
-
atlisp-mcp --stdio # Start in stdio mode for MCP clients
|
|
2858
|
-
atlisp-mcp --transport stdio # Same as --stdio
|
|
2859
|
-
`);
|
|
2860
|
-
process.exit(0);
|
|
2861
|
-
} else if (args[i] === "--transport" && args[i + 1]) {
|
|
2862
|
-
process.env.TRANSPORT = args[i + 1];
|
|
2863
|
-
i++;
|
|
2864
|
-
} else if (args[i] === "--stdio") {
|
|
2865
|
-
process.env.TRANSPORT = "stdio";
|
|
2866
|
-
} else if (args[i] === "--port" && args[i + 1]) {
|
|
2867
|
-
process.env.PORT = args[i + 1];
|
|
2868
|
-
i++;
|
|
2869
|
-
} else if (args[i] === "--host" && args[i + 1]) {
|
|
2870
|
-
process.env.HOST = args[i + 1];
|
|
2871
|
-
i++;
|
|
2872
|
-
}
|
|
2873
|
-
}
|
|
2874
|
-
}
|
|
2875
|
-
var { decode: charsetDecode, encodingExists } = iconv;
|
|
2876
|
-
var mcpContext = new AsyncLocalStorage();
|
|
2877
|
-
var sseSessionManager = new SseSessionManager();
|
|
2878
|
-
var SERVER_CAPABILITIES = {
|
|
2879
|
-
tools: {},
|
|
2880
|
-
resources: { subscribe: true, listChanged: true },
|
|
2881
|
-
prompts: {}
|
|
2882
|
-
};
|
|
2883
|
-
var { port, host, transport, apiKey, rateLimitWindow, rateLimitMax } = config_default;
|
|
2884
|
-
if (apiKey) log("API Key authentication enabled");
|
|
2885
|
-
var mcpLimiter = rateLimit({
|
|
2886
|
-
windowMs: rateLimitWindow,
|
|
2887
|
-
max: rateLimitMax,
|
|
2888
|
-
standardHeaders: true,
|
|
2889
|
-
legacyHeaders: false,
|
|
2890
|
-
message: { error: "\u8BF7\u6C42\u8FC7\u4E8E\u9891\u7E41\uFF0C\u8BF7\u7A0D\u540E\u518D\u8BD5" }
|
|
3273
|
+
var atlisp_mcp_exports = {};
|
|
3274
|
+
__export(atlisp_mcp_exports, {
|
|
3275
|
+
CAD_PLATFORMS: () => CAD_PLATFORMS,
|
|
3276
|
+
FILE_EXTENSIONS: () => FILE_EXTENSIONS,
|
|
3277
|
+
handleToolCall: () => handleToolCall,
|
|
3278
|
+
loadAtlibFunctionLib: () => loadAtlibFunctionLib,
|
|
3279
|
+
startServer: () => startServer,
|
|
3280
|
+
tools: () => tools
|
|
2891
3281
|
});
|
|
2892
|
-
|
|
2893
|
-
|
|
2894
|
-
|
|
2895
|
-
|
|
3282
|
+
import path7 from "path";
|
|
3283
|
+
import fs6 from "fs";
|
|
3284
|
+
import { fileURLToPath as fileURLToPath4 } from "url";
|
|
3285
|
+
import { createRequire } from "module";
|
|
3286
|
+
import os4 from "os";
|
|
3287
|
+
import express2 from "express";
|
|
3288
|
+
import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
|
|
2896
3289
|
async function readCacheFromDisk2() {
|
|
2897
3290
|
try {
|
|
2898
3291
|
const stat = fs6.statSync(FUNCLIB_CACHE_FILE2);
|
|
2899
|
-
if (Date.now() - stat.mtimeMs <
|
|
3292
|
+
if (Date.now() - stat.mtimeMs < CACHE_TTL3) {
|
|
2900
3293
|
const raw = fs6.readFileSync(FUNCLIB_CACHE_FILE2, "utf-8");
|
|
2901
3294
|
return JSON.parse(raw);
|
|
2902
3295
|
}
|
|
@@ -2909,7 +3302,7 @@ function writeCacheToDisk2(data) {
|
|
|
2909
3302
|
fs6.mkdirSync(CACHE_DIR2, { recursive: true });
|
|
2910
3303
|
fs6.writeFileSync(FUNCLIB_CACHE_FILE2, JSON.stringify(data), "utf-8");
|
|
2911
3304
|
} catch (e) {
|
|
2912
|
-
|
|
3305
|
+
error(`writeCacheToDisk error: ${e.message}`);
|
|
2913
3306
|
}
|
|
2914
3307
|
}
|
|
2915
3308
|
async function loadAtlibFunctionLib() {
|
|
@@ -2933,235 +3326,31 @@ async function loadAtlibFunctionLib() {
|
|
|
2933
3326
|
return data;
|
|
2934
3327
|
}
|
|
2935
3328
|
} catch (e) {
|
|
2936
|
-
|
|
3329
|
+
error(`loadAtlibFunctionLib error: ${e.message}`);
|
|
2937
3330
|
}
|
|
2938
3331
|
return cachedFunctionLib;
|
|
2939
3332
|
}
|
|
2940
|
-
|
|
2941
|
-
|
|
2942
|
-
|
|
2943
|
-
|
|
2944
|
-
|
|
2945
|
-
|
|
2946
|
-
|
|
2947
|
-
install_package: (a) => installPackage(a.packageName),
|
|
2948
|
-
get_platform_info: () => ({ content: [{ type: "text", text: `\u652F\u6301\u7684 CAD \u5E73\u53F0:
|
|
2949
|
-
${CAD_PLATFORMS.join("\n")}
|
|
2950
|
-
\u5F53\u524D\u8FDE\u63A5: ${cad.connected ? "\u5DF2\u8FDE\u63A5" : "\u672A\u8FDE\u63A5"}` }] }),
|
|
2951
|
-
at_command: (a) => atCommand(a.command),
|
|
2952
|
-
new_document: () => newDocument(),
|
|
2953
|
-
bring_to_front: () => bringToFront(),
|
|
2954
|
-
install_atlisp: () => installAtlisp(),
|
|
2955
|
-
init_atlisp: () => initAtlisp(),
|
|
2956
|
-
get_function_usage: (a) => getFunctionUsage(a.name, a.package),
|
|
2957
|
-
list_symbols: (a) => listSymbols(a.package),
|
|
2958
|
-
get_system_status: () => getSystemStatus(),
|
|
2959
|
-
list_prompts: async () => {
|
|
2960
|
-
const prompts = await listPrompts();
|
|
2961
|
-
return { content: [{ type: "text", text: JSON.stringify(prompts) }] };
|
|
2962
|
-
},
|
|
2963
|
-
get_prompt: async (a) => {
|
|
2964
|
-
const prompt = await getPrompt(a.name, a.args || {});
|
|
2965
|
-
return { content: prompt.messages.map((m) => ({ type: "text", text: m.content.text || m.content })) };
|
|
2966
|
-
},
|
|
2967
|
-
import_funlib: async (a) => {
|
|
2968
|
-
const data = await loadAtlibFunctionLib();
|
|
2969
|
-
if (!data) return { content: [{ type: "text", text: "\u52A0\u8F7D\u51FD\u6570\u5E93\u5931\u8D25" }], isError: true };
|
|
2970
|
-
if (a.format === "list") {
|
|
2971
|
-
const items = Object.values(data.all_functions || {}).map((f) => `${f.name}: ${f.description || ""}`);
|
|
2972
|
-
return { content: [{ type: "text", text: items.join("\n") }] };
|
|
2973
|
-
}
|
|
2974
|
-
return { content: [{ type: "text", text: JSON.stringify(data, null, 2) }] };
|
|
2975
|
-
}
|
|
2976
|
-
};
|
|
2977
|
-
function getOrCreateSessionServer(sessionId) {
|
|
2978
|
-
let entry = sessionServers.get(sessionId);
|
|
2979
|
-
if (!entry) {
|
|
2980
|
-
const server = createMcpServer();
|
|
2981
|
-
const transport2 = new SessionTransport(sessionId);
|
|
2982
|
-
server.connect(transport2);
|
|
2983
|
-
entry = { server, transport: transport2 };
|
|
2984
|
-
sessionServers.set(sessionId, entry);
|
|
2985
|
-
sessionTransports.set(sessionId, transport2);
|
|
2986
|
-
}
|
|
2987
|
-
return entry;
|
|
2988
|
-
}
|
|
2989
|
-
function removeSessionServer(sessionId) {
|
|
2990
|
-
const entry = sessionServers.get(sessionId);
|
|
2991
|
-
if (entry) {
|
|
2992
|
-
entry.transport.close().catch(() => {
|
|
2993
|
-
});
|
|
2994
|
-
entry.server.close().catch(() => {
|
|
2995
|
-
});
|
|
2996
|
-
sessionServers.delete(sessionId);
|
|
2997
|
-
sessionTransports.delete(sessionId);
|
|
2998
|
-
}
|
|
2999
|
-
}
|
|
3000
|
-
function broadcastToAllSessions(uri) {
|
|
3001
|
-
for (const [sid, entry] of sessionServers) {
|
|
3002
|
-
entry.server.sendResourceUpdated({ uri }).catch((err) => {
|
|
3003
|
-
log(`Failed to send resource update to session ${sid}: ${err.message}`);
|
|
3004
|
-
});
|
|
3005
|
-
}
|
|
3006
|
-
}
|
|
3007
|
-
var tools = [
|
|
3008
|
-
{
|
|
3009
|
-
name: "connect_cad",
|
|
3010
|
-
description: "\u8FDE\u63A5\u5230 CAD (AutoCAD/ZWCAD/GStarCAD/BricsCAD)",
|
|
3011
|
-
inputSchema: {
|
|
3012
|
-
type: "object",
|
|
3013
|
-
properties: {
|
|
3014
|
-
platform: { type: "string", description: "\u6307\u5B9A CAD \u5E73\u53F0: AutoCAD, ZWCAD, GStarCAD, BricsCAD\uFF08\u53EF\u9009\uFF0C\u81EA\u52A8\u68C0\u6D4B\uFF09" }
|
|
3015
|
-
}
|
|
3016
|
-
}
|
|
3017
|
-
},
|
|
3018
|
-
{
|
|
3019
|
-
name: "eval_lisp",
|
|
3020
|
-
description: "\u5728 CAD \u4E2D\u6267\u884C AutoLISP \u4EE3\u7801\uFF08\u4E0D\u8FD4\u56DE\u7ED3\u679C\uFF09",
|
|
3021
|
-
inputSchema: {
|
|
3022
|
-
type: "object",
|
|
3023
|
-
properties: { code: { type: "string", description: "\u8981\u6267\u884C\u7684 LISP \u4EE3\u7801" } },
|
|
3024
|
-
required: ["code"]
|
|
3025
|
-
}
|
|
3026
|
-
},
|
|
3027
|
-
{
|
|
3028
|
-
name: "eval_lisp_with_result",
|
|
3029
|
-
description: "\u5728 CAD \u4E2D\u6267\u884C AutoLISP \u4EE3\u7801\u5E76\u8FD4\u56DE\u7ED3\u679C",
|
|
3030
|
-
inputSchema: {
|
|
3031
|
-
type: "object",
|
|
3032
|
-
properties: {
|
|
3033
|
-
code: { type: "string", description: "\u8981\u6267\u884C\u7684 LISP \u4EE3\u7801" },
|
|
3034
|
-
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" }
|
|
3035
|
-
},
|
|
3036
|
-
required: ["code"]
|
|
3037
|
-
}
|
|
3038
|
-
},
|
|
3039
|
-
{
|
|
3040
|
-
name: "get_cad_info",
|
|
3041
|
-
description: "\u83B7\u53D6\u5F53\u524D CAD \u4FE1\u606F",
|
|
3042
|
-
inputSchema: { type: "object", properties: {} }
|
|
3043
|
-
},
|
|
3044
|
-
{
|
|
3045
|
-
name: "list_packages",
|
|
3046
|
-
description: "\u5217\u51FA\u5DF2\u5B89\u88C5\u7684 @lisp \u5305",
|
|
3047
|
-
inputSchema: { type: "object", properties: {} }
|
|
3048
|
-
},
|
|
3049
|
-
{
|
|
3050
|
-
name: "search_packages",
|
|
3051
|
-
description: "\u641C\u7D22 @lisp \u5305",
|
|
3052
|
-
inputSchema: {
|
|
3053
|
-
type: "object",
|
|
3054
|
-
properties: { query: { type: "string", description: "\u641C\u7D22\u5173\u952E\u8BCD" } },
|
|
3055
|
-
required: ["query"]
|
|
3056
|
-
}
|
|
3057
|
-
},
|
|
3058
|
-
{
|
|
3059
|
-
name: "install_package",
|
|
3060
|
-
description: "\u5B89\u88C5 @lisp \u5305\u5230 CAD",
|
|
3061
|
-
inputSchema: {
|
|
3062
|
-
type: "object",
|
|
3063
|
-
properties: { packageName: { type: "string", description: "\u5305\u540D\u79F0" } },
|
|
3064
|
-
required: ["packageName"]
|
|
3065
|
-
}
|
|
3066
|
-
},
|
|
3067
|
-
{
|
|
3068
|
-
name: "get_platform_info",
|
|
3069
|
-
description: "\u83B7\u53D6 CAD \u5E73\u53F0\u4FE1\u606F",
|
|
3070
|
-
inputSchema: { type: "object", properties: {} }
|
|
3071
|
-
},
|
|
3072
|
-
{
|
|
3073
|
-
name: "at_command",
|
|
3074
|
-
description: "\u6267\u884C @lisp \u547D\u4EE4",
|
|
3075
|
-
inputSchema: {
|
|
3076
|
-
type: "object",
|
|
3077
|
-
properties: { command: { type: "string", description: "@lisp \u547D\u4EE4" } },
|
|
3078
|
-
required: ["command"]
|
|
3079
|
-
}
|
|
3080
|
-
},
|
|
3081
|
-
{
|
|
3082
|
-
name: "new_document",
|
|
3083
|
-
description: "\u5728 CAD \u4E2D\u65B0\u5EFA\u7A7A\u767D\u6587\u6863",
|
|
3084
|
-
inputSchema: { type: "object", properties: {} }
|
|
3085
|
-
},
|
|
3086
|
-
{
|
|
3087
|
-
name: "bring_to_front",
|
|
3088
|
-
description: "\u5C06 CAD \u7A97\u53E3\u5207\u6362\u5230\u524D\u53F0\uFF08\u4ECE\u540E\u53F0\u8FD0\u884C\u72B6\u6001\u5524\u9192\uFF09",
|
|
3089
|
-
inputSchema: { type: "object", properties: {} }
|
|
3090
|
-
},
|
|
3091
|
-
{
|
|
3092
|
-
name: "install_atlisp",
|
|
3093
|
-
description: "\u5728 CAD \u4E2D\u5B89\u88C5 @lisp",
|
|
3094
|
-
inputSchema: { type: "object", properties: {} }
|
|
3095
|
-
},
|
|
3096
|
-
{
|
|
3097
|
-
name: "init_atlisp",
|
|
3098
|
-
description: "\u521D\u59CB\u5316 CAD \u4E2D\u7684 @lisp \u73AF\u5883\uFF0C\u52A0\u8F7D\u51FD\u6570\u5E93\u548C\u521D\u59CB\u53D8\u91CF",
|
|
3099
|
-
inputSchema: { type: "object", properties: {} }
|
|
3100
|
-
},
|
|
3101
|
-
{
|
|
3102
|
-
name: "get_function_usage",
|
|
3103
|
-
description: "\u83B7\u53D6 @lisp \u51FD\u6570\u7528\u6CD5",
|
|
3104
|
-
inputSchema: {
|
|
3105
|
-
type: "object",
|
|
3106
|
-
properties: {
|
|
3107
|
-
name: { type: "string", description: "\u51FD\u6570\u540D\uFF0C\u5982 string:length" },
|
|
3108
|
-
package: { type: "string", description: "\u5305\u540D\uFF0C\u5982 string\uFF08\u53EF\u9009\uFF0C\u4E0D\u4F20\u5219\u81EA\u52A8\u641C\u7D22\uFF09" }
|
|
3109
|
-
},
|
|
3110
|
-
required: ["name"]
|
|
3111
|
-
}
|
|
3112
|
-
},
|
|
3113
|
-
{
|
|
3114
|
-
name: "list_symbols",
|
|
3115
|
-
description: "\u5217\u51FA @lisp \u6240\u6709\u7B26\u53F7\uFF0C\u7528\u4E8E\u68C0\u67E5\u51FD\u6570\u548C\u53D8\u91CF",
|
|
3116
|
-
inputSchema: {
|
|
3117
|
-
type: "object",
|
|
3118
|
-
properties: {
|
|
3119
|
-
package: { type: "string", description: "\u5305\u540D\uFF0C\u5982 string\uFF08\u53EF\u9009\uFF09" }
|
|
3120
|
-
}
|
|
3121
|
-
}
|
|
3122
|
-
},
|
|
3123
|
-
{
|
|
3124
|
-
name: "import_funlib",
|
|
3125
|
-
description: "\u4ECE\u7F51\u7EDC\u5BFC\u5165 @lisp \u51FD\u6570\u5E93\u6570\u636E\u5230 AI Agent",
|
|
3126
|
-
inputSchema: {
|
|
3127
|
-
type: "object",
|
|
3128
|
-
properties: {
|
|
3129
|
-
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" }
|
|
3130
|
-
}
|
|
3131
|
-
}
|
|
3132
|
-
},
|
|
3133
|
-
{
|
|
3134
|
-
name: "get_system_status",
|
|
3135
|
-
description: "\u83B7\u53D6\u5B8C\u6574\u7CFB\u7EDF\u8BCA\u65AD\u4FE1\u606F\uFF1AMCP \u72B6\u6001\u3001CAD \u8FDE\u63A5\u3001Lisp \u6267\u884C\u3001\u5305\u5217\u8868",
|
|
3136
|
-
inputSchema: { type: "object", properties: {} }
|
|
3137
|
-
},
|
|
3138
|
-
{
|
|
3139
|
-
name: "list_prompts",
|
|
3140
|
-
description: "\u5217\u51FA\u6240\u6709\u53EF\u7528\u7684 @lisp \u63D0\u793A\u6A21\u677F",
|
|
3141
|
-
inputSchema: { type: "object", properties: {} }
|
|
3142
|
-
},
|
|
3143
|
-
{
|
|
3144
|
-
name: "get_prompt",
|
|
3145
|
-
description: "\u83B7\u53D6\u6307\u5B9A\u63D0\u793A\u6A21\u677F\u7684\u5185\u5BB9",
|
|
3146
|
-
inputSchema: {
|
|
3147
|
-
type: "object",
|
|
3148
|
-
properties: {
|
|
3149
|
-
name: { type: "string", description: "\u63D0\u793A\u6A21\u677F\u540D\u79F0" },
|
|
3150
|
-
args: { type: "object", description: "\u6A21\u677F\u53C2\u6570\uFF08\u53EF\u9009\uFF09" }
|
|
3151
|
-
},
|
|
3152
|
-
required: ["name"]
|
|
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}`);
|
|
3153
3340
|
}
|
|
3154
3341
|
}
|
|
3155
|
-
|
|
3342
|
+
return true;
|
|
3343
|
+
}
|
|
3156
3344
|
async function handleToolCall(name, args) {
|
|
3157
3345
|
const handler = TOOL_HANDLERS[name];
|
|
3158
3346
|
if (!handler) return { content: [{ type: "text", text: `\u672A\u77E5\u5DE5\u5177: ${name}` }], isError: true };
|
|
3159
3347
|
try {
|
|
3348
|
+
validateToolArgs(name, args || {});
|
|
3160
3349
|
const result = await handler(args || {});
|
|
3161
3350
|
notifyResourceChanges(name);
|
|
3162
3351
|
return result;
|
|
3163
3352
|
} catch (e) {
|
|
3164
|
-
|
|
3353
|
+
error(`Tool call error [${name}]: ${e.message}`, { tool: name, args });
|
|
3165
3354
|
return { content: [{ type: "text", text: `\u5DE5\u5177\u6267\u884C\u9519\u8BEF: ${e.message}` }], isError: true };
|
|
3166
3355
|
}
|
|
3167
3356
|
}
|
|
@@ -3188,222 +3377,38 @@ async function initCadConnection() {
|
|
|
3188
3377
|
try {
|
|
3189
3378
|
const connected = await cad.connect();
|
|
3190
3379
|
if (connected) {
|
|
3191
|
-
log(
|
|
3192
|
-
console.error(
|
|
3380
|
+
log(`Auto-connected to CAD: ${cad.getPlatform()} ${cad.getVersion()}`);
|
|
3381
|
+
console.error(`\u5DF2\u81EA\u52A8\u8FDE\u63A5\u5230 CAD: ${cad.getPlatform()} ${cad.getVersion()}`);
|
|
3193
3382
|
} else {
|
|
3194
3383
|
log("No CAD found on startup");
|
|
3195
3384
|
}
|
|
3196
3385
|
} catch (e) {
|
|
3197
|
-
|
|
3386
|
+
error(`Auto-connect failed: ${e.message}`);
|
|
3198
3387
|
}
|
|
3199
3388
|
}
|
|
3200
|
-
var sessionServers = /* @__PURE__ */ new Map();
|
|
3201
|
-
var sessionTransports = /* @__PURE__ */ new Map();
|
|
3202
|
-
function createMcpServer() {
|
|
3203
|
-
const server = new Server(
|
|
3204
|
-
{ name: SERVER_NAME, version: SERVER_VERSION },
|
|
3205
|
-
{ capabilities: SERVER_CAPABILITIES }
|
|
3206
|
-
);
|
|
3207
|
-
server.setRequestHandler(ListToolsRequestSchema, async () => ({ tools }));
|
|
3208
|
-
server.setRequestHandler(CallToolRequestSchema, async (request) => {
|
|
3209
|
-
const { name, arguments: args } = request.params;
|
|
3210
|
-
return await handleToolCall(name, args || {});
|
|
3211
|
-
});
|
|
3212
|
-
server.setRequestHandler(ListResourcesRequestSchema, async (request) => {
|
|
3213
|
-
const ctx = mcpContext.getStore();
|
|
3214
|
-
const sessionId = ctx?.sessionId;
|
|
3215
|
-
const subscribedUris = sessionId ? list(sessionId) : list();
|
|
3216
|
-
return {
|
|
3217
|
-
resources: await listResources(subscribedUris)
|
|
3218
|
-
};
|
|
3219
|
-
});
|
|
3220
|
-
server.setRequestHandler(ReadResourceRequestSchema, async (request) => {
|
|
3221
|
-
const { uri } = request.params;
|
|
3222
|
-
try {
|
|
3223
|
-
const data = await readResource(uri);
|
|
3224
|
-
return {
|
|
3225
|
-
contents: [{
|
|
3226
|
-
uri,
|
|
3227
|
-
mimeType: "application/json",
|
|
3228
|
-
text: JSON.stringify(data)
|
|
3229
|
-
}]
|
|
3230
|
-
};
|
|
3231
|
-
} catch (e) {
|
|
3232
|
-
return {
|
|
3233
|
-
contents: [],
|
|
3234
|
-
isError: true,
|
|
3235
|
-
error: { code: -32603, message: e.message }
|
|
3236
|
-
};
|
|
3237
|
-
}
|
|
3238
|
-
});
|
|
3239
|
-
server.setRequestHandler(SubscribeRequestSchema, async (request) => {
|
|
3240
|
-
const { uri } = request.params;
|
|
3241
|
-
const ctx = mcpContext.getStore();
|
|
3242
|
-
subscribe(uri, ctx?.sessionId);
|
|
3243
|
-
return { success: true };
|
|
3244
|
-
});
|
|
3245
|
-
server.setRequestHandler(UnsubscribeRequestSchema, async (request) => {
|
|
3246
|
-
const { uri } = request.params;
|
|
3247
|
-
const ctx = mcpContext.getStore();
|
|
3248
|
-
unsubscribe(uri, ctx?.sessionId);
|
|
3249
|
-
return { success: true };
|
|
3250
|
-
});
|
|
3251
|
-
server.setRequestHandler(ListPromptsRequestSchema, async () => ({
|
|
3252
|
-
prompts: await listPrompts()
|
|
3253
|
-
}));
|
|
3254
|
-
server.setRequestHandler(GetPromptRequestSchema, async (request) => {
|
|
3255
|
-
const { name, arguments: args } = request.params;
|
|
3256
|
-
return await getPrompt(name, args || {});
|
|
3257
|
-
});
|
|
3258
|
-
return server;
|
|
3259
|
-
}
|
|
3260
3389
|
async function startServer() {
|
|
3261
3390
|
if (config_default.transport === "stdio") {
|
|
3262
3391
|
await initCadConnection();
|
|
3263
|
-
const mcpServer =
|
|
3264
|
-
const
|
|
3392
|
+
const mcpServer = createStdioServer({ tools, handleToolCall });
|
|
3393
|
+
const transport = new StdioServerTransport();
|
|
3265
3394
|
const sessionId = "stdio-session";
|
|
3266
3395
|
sessionManager.createSession(sessionId);
|
|
3267
3396
|
await mcpContext.run({ sessionId }, async () => {
|
|
3268
|
-
await mcpServer.connect(
|
|
3397
|
+
await mcpServer.connect(transport);
|
|
3269
3398
|
});
|
|
3270
3399
|
console.error(`${SERVER_NAME} \u8FD0\u884C\u5728 stdio \u6A21\u5F0F`);
|
|
3271
3400
|
setNotify((uri, data) => {
|
|
3272
3401
|
mcpServer.sendResourceUpdated({ uri }).catch((err) => {
|
|
3273
|
-
|
|
3402
|
+
error(`Failed to send resource update: ${err.message}`);
|
|
3274
3403
|
});
|
|
3275
3404
|
});
|
|
3276
3405
|
} else {
|
|
3277
|
-
const app =
|
|
3278
|
-
|
|
3279
|
-
app.use(async (req, res, next) => {
|
|
3280
|
-
const ct = (req.headers["content-type"] || "").toLowerCase();
|
|
3281
|
-
if (!JSON_CONTENT_TYPES.some((t) => ct.startsWith(t))) return next();
|
|
3282
|
-
try {
|
|
3283
|
-
const buf = await rawBody(req, { limit: "10mb" });
|
|
3284
|
-
const m = ct.match(/charset\s*=\s*([^\s;]+)/i);
|
|
3285
|
-
let charset = m ? m[1].toLowerCase() : "utf-8";
|
|
3286
|
-
const charsetMap = { "gb2312": "gbk", "gb18030": "gbk", "gbk": "gbk", "936": "gbk" };
|
|
3287
|
-
charset = charsetMap[charset] || charset;
|
|
3288
|
-
const str = encodingExists(charset) ? charsetDecode(buf, charset) : buf.toString("utf-8");
|
|
3289
|
-
req.body = JSON.parse(str);
|
|
3290
|
-
next();
|
|
3291
|
-
} catch (e) {
|
|
3292
|
-
res.status(400).json({ error: "Invalid JSON body", message: e.message });
|
|
3293
|
-
}
|
|
3294
|
-
});
|
|
3295
|
-
app.use((req, res, next) => {
|
|
3296
|
-
log(`${req.method} ${req.path}`);
|
|
3297
|
-
next();
|
|
3298
|
-
});
|
|
3299
|
-
const PUBLIC_PATHS = ["/health"];
|
|
3300
|
-
if (apiKey) {
|
|
3301
|
-
app.use((req, res, next) => {
|
|
3302
|
-
if (PUBLIC_PATHS.includes(req.path)) return next();
|
|
3303
|
-
const auth = req.get("Authorization");
|
|
3304
|
-
if (auth === `Bearer ${apiKey}`) return next();
|
|
3305
|
-
res.status(401).json({ error: "Unauthorized" });
|
|
3306
|
-
});
|
|
3307
|
-
}
|
|
3308
|
-
app.get("/health", (req, res) => {
|
|
3309
|
-
res.json({ status: "ok", cad: cad.connected ? "connected" : "disconnected" });
|
|
3310
|
-
});
|
|
3311
|
-
if (config_default.enableCors) {
|
|
3312
|
-
app.use((req, res, next) => {
|
|
3313
|
-
res.setHeader("Access-Control-Allow-Origin", config_default.corsOrigin);
|
|
3314
|
-
res.setHeader("Access-Control-Allow-Methods", "GET, POST, OPTIONS, CONNECT");
|
|
3315
|
-
res.setHeader("Access-Control-Allow-Headers", "Content-Type, Authorization, Accept, mcp-session-id, last-event-id");
|
|
3316
|
-
res.setHeader("Access-Control-Expose-Headers", "mcp-session-id, content-type, x-accel-buffering");
|
|
3317
|
-
res.setHeader("Access-Control-Max-Age", "86400");
|
|
3318
|
-
res.setHeader("Vary", "Accept");
|
|
3319
|
-
if (req.method === "OPTIONS") return res.status(204).end();
|
|
3320
|
-
next();
|
|
3321
|
-
});
|
|
3322
|
-
}
|
|
3406
|
+
const app = express2();
|
|
3407
|
+
setupRoutes(app);
|
|
3323
3408
|
setNotify((uri, data) => {
|
|
3324
3409
|
broadcastToAllSessions(uri);
|
|
3325
|
-
for (const session of
|
|
3326
|
-
|
|
3327
|
-
}
|
|
3328
|
-
});
|
|
3329
|
-
async function handleMcpPost(req, res) {
|
|
3330
|
-
const sessionId = req.headers["mcp-session-id"] || req.query.sessionId || randomUUID4();
|
|
3331
|
-
sessionManager.createSession(sessionId);
|
|
3332
|
-
const body = req.body;
|
|
3333
|
-
if (!body || !body.method) {
|
|
3334
|
-
return res.status(400).json({ error: "Invalid request" });
|
|
3335
|
-
}
|
|
3336
|
-
const { server, transport: transport2 } = getOrCreateSessionServer(sessionId);
|
|
3337
|
-
transport2.resetCleanupTimer();
|
|
3338
|
-
await mcpContext.run({ sessionId }, async () => {
|
|
3339
|
-
try {
|
|
3340
|
-
const response = await transport2.handleRequest(body);
|
|
3341
|
-
if (response) {
|
|
3342
|
-
const headers = { "Content-Type": "application/json" };
|
|
3343
|
-
if (transport2.sessionId) {
|
|
3344
|
-
headers["mcp-session-id"] = transport2.sessionId;
|
|
3345
|
-
}
|
|
3346
|
-
res.writeHead(200, headers);
|
|
3347
|
-
res.end(JSON.stringify(response));
|
|
3348
|
-
} else {
|
|
3349
|
-
if (!res.headersSent) {
|
|
3350
|
-
res.status(202).end();
|
|
3351
|
-
}
|
|
3352
|
-
}
|
|
3353
|
-
} catch (error) {
|
|
3354
|
-
log(`Transport error [${sessionId}]: ${error.message}`);
|
|
3355
|
-
if (!res.headersSent) {
|
|
3356
|
-
res.status(500).json({ error: "Internal server error", message: error.message });
|
|
3357
|
-
}
|
|
3358
|
-
}
|
|
3359
|
-
});
|
|
3360
|
-
}
|
|
3361
|
-
app.all("/mcp", mcpLimiter, handleMcpPost);
|
|
3362
|
-
app.all("/mcp/:path", mcpLimiter, handleMcpPost);
|
|
3363
|
-
app.get("/mcp/stream", mcpLimiter, handleMcpPost);
|
|
3364
|
-
const sseEndpoint = "/sse";
|
|
3365
|
-
app.get(sseEndpoint, async (req, res) => {
|
|
3366
|
-
const sessionId = randomUUID4();
|
|
3367
|
-
sessionManager.createSession(sessionId);
|
|
3368
|
-
getOrCreateSessionServer(sessionId);
|
|
3369
|
-
const sseSession = new SseSession(res, { clientId: sessionId });
|
|
3370
|
-
sseSessionManager.add(sessionId, sseSession);
|
|
3371
|
-
sseSession.sendEndpoint(`/message?sessionId=${sessionId}`);
|
|
3372
|
-
req.on("close", () => {
|
|
3373
|
-
sseSessionManager.remove(sessionId);
|
|
3374
|
-
removeSessionServer(sessionId);
|
|
3375
|
-
});
|
|
3376
|
-
});
|
|
3377
|
-
app.post("/message", mcpLimiter, async (req, res) => {
|
|
3378
|
-
const sessionId = req.query.sessionId;
|
|
3379
|
-
if (!sessionId) {
|
|
3380
|
-
return res.status(400).json({ error: "Missing sessionId" });
|
|
3381
|
-
}
|
|
3382
|
-
const sseSession = sseSessionManager.get(sessionId);
|
|
3383
|
-
if (!sseSession) {
|
|
3384
|
-
return res.status(404).json({ error: "Session not found" });
|
|
3385
|
-
}
|
|
3386
|
-
sessionManager.createSession(sessionId);
|
|
3387
|
-
const { server, transport: transport2 } = getOrCreateSessionServer(sessionId);
|
|
3388
|
-
transport2.resetCleanupTimer();
|
|
3389
|
-
const body = req.body;
|
|
3390
|
-
if (body && body.method) {
|
|
3391
|
-
try {
|
|
3392
|
-
const response = await transport2.handleRequest(body);
|
|
3393
|
-
if (response) {
|
|
3394
|
-
sseSession.sendResponse(response);
|
|
3395
|
-
}
|
|
3396
|
-
if (!res.headersSent) {
|
|
3397
|
-
res.status(202).end();
|
|
3398
|
-
}
|
|
3399
|
-
} catch (error) {
|
|
3400
|
-
log(`SSE message error [${sessionId}]: ${error.message}`);
|
|
3401
|
-
if (!res.headersSent) {
|
|
3402
|
-
res.status(500).json({ error: "Internal server error" });
|
|
3403
|
-
}
|
|
3404
|
-
}
|
|
3405
|
-
} else {
|
|
3406
|
-
res.status(400).json({ error: "Invalid request" });
|
|
3410
|
+
for (const session of sseSessionManager2.listActive()) {
|
|
3411
|
+
sseSessionManager2.sendToClient(session.clientId, "resource_updated", { uri });
|
|
3407
3412
|
}
|
|
3408
3413
|
});
|
|
3409
3414
|
const httpServer = app.listen(config_default.port, config_default.host, async () => {
|
|
@@ -3413,7 +3418,7 @@ async function startServer() {
|
|
|
3413
3418
|
async function shutdown(signal) {
|
|
3414
3419
|
console.error(`
|
|
3415
3420
|
\u6536\u5230 ${signal}\uFF0C\u6B63\u5728\u4F18\u96C5\u5173\u95ED...`);
|
|
3416
|
-
|
|
3421
|
+
sseSessionManager2.closeAll();
|
|
3417
3422
|
sessionManager.clear();
|
|
3418
3423
|
for (const [sid] of sessionServers) {
|
|
3419
3424
|
removeSessionServer(sid);
|
|
@@ -3427,14 +3432,285 @@ async function startServer() {
|
|
|
3427
3432
|
process.on("SIGTERM", () => shutdown("SIGTERM"));
|
|
3428
3433
|
}
|
|
3429
3434
|
}
|
|
3430
|
-
|
|
3431
|
-
|
|
3432
|
-
|
|
3435
|
+
var __dirname4, require2, version, sseSessionManager2, isMcpScript, CACHE_DIR2, FUNCLIB_CACHE_FILE2, CACHE_TTL3, FUNCTION_LIB_URL, cachedFunctionLib, cachedAt2, toolInputSchema, TOOL_HANDLERS, tools;
|
|
3436
|
+
var init_atlisp_mcp = __esm({
|
|
3437
|
+
async "src/atlisp-mcp.js"() {
|
|
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();
|
|
3433
3711
|
export {
|
|
3434
3712
|
CAD_PLATFORMS,
|
|
3435
3713
|
FILE_EXTENSIONS,
|
|
3436
|
-
MOCK_PACKAGES,
|
|
3437
|
-
createMcpServer,
|
|
3438
3714
|
handleToolCall,
|
|
3439
3715
|
loadAtlibFunctionLib,
|
|
3440
3716
|
startServer,
|