@atlisp/mcp 1.4.4 → 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.
Files changed (2) hide show
  1. package/dist/atlisp-mcp.js +1721 -1536
  2. package/package.json +2 -2
@@ -1,140 +1,43 @@
1
1
  #!/usr/bin/env node
2
-
3
- // src/atlisp-mcp.js
4
- import path7 from "path";
5
- import fs6 from "fs";
6
- import { fileURLToPath as fileURLToPath4 } from "url";
7
- import { createRequire } from "module";
8
- import os4 from "os";
9
- import express from "express";
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)
40
- return;
41
- if (this._pendingRequest) {
42
- const { resolve, reject, timeout } = this._pendingRequest;
43
- clearTimeout(timeout);
44
- this._pendingRequest = null;
45
- resolve(message);
46
- }
47
- }
48
- async close() {
49
- if (this._closed)
50
- return;
51
- this._closed = true;
52
- if (this._pendingRequest) {
53
- const { reject, timeout } = this._pendingRequest;
54
- clearTimeout(timeout);
55
- this._pendingRequest = null;
56
- reject(new Error("Transport closed"));
57
- }
58
- this._clearCleanupTimer();
59
- this.onclose?.();
60
- }
61
- async handleRequest(message, timeoutMs = 6e4) {
62
- if (this._closed) {
63
- throw new Error("Transport closed");
64
- }
65
- if (!message || !message.method) {
66
- throw new Error("Invalid message");
67
- }
68
- if (!message.id) {
69
- this.onmessage?.(message);
70
- return null;
71
- }
72
- return new Promise((resolve, reject) => {
73
- const timeout = setTimeout(() => {
74
- if (this._pendingRequest?.resolve === resolve) {
75
- this._pendingRequest = null;
76
- reject(new Error("Request timeout"));
77
- }
78
- }, timeoutMs);
79
- this._pendingRequest = { resolve, reject, timeout };
80
- this.onmessage?.(message);
81
- });
82
- }
83
- resetCleanupTimer() {
84
- this._clearCleanupTimer();
85
- this._cleanupTimer = setTimeout(() => {
86
- this.close();
87
- }, SESSION_TIMEOUT);
88
- }
89
- _clearCleanupTimer() {
90
- if (this._cleanupTimer) {
91
- clearTimeout(this._cleanupTimer);
92
- this._cleanupTimer = null;
93
- }
94
- }
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 });
95
10
  };
96
-
97
- // src/atlisp-mcp.js
98
- import {
99
- ListToolsRequestSchema,
100
- CallToolRequestSchema,
101
- ListResourcesRequestSchema,
102
- ReadResourceRequestSchema,
103
- SubscribeRequestSchema,
104
- UnsubscribeRequestSchema,
105
- ListPromptsRequestSchema,
106
- GetPromptRequestSchema
107
- } from "@modelcontextprotocol/sdk/types.js";
108
-
109
- // src/cad.js
110
- import { spawn } from "child_process";
111
- import path from "path";
112
- import { fileURLToPath } from "url";
113
- import { randomUUID as randomUUID2 } from "crypto";
114
11
 
115
12
  // src/constants.js
116
- var CAD_PLATFORMS = ["AutoCAD", "ZWCAD", "GStarCAD", "BricsCAD"];
117
- var FILE_EXTENSIONS = {
118
- "AutoCAD": [".fas", ".vlx"],
119
- "ZWCAD": [".zelx", ".vls"],
120
- "GStarCAD": [".fas", ".vlx"],
121
- "BricsCAD": [".des"]
122
- };
123
- var SERVER_NAME = "atlisp-mcp-server";
124
- var SERVER_VERSION = "1.4.4";
125
- var MOCK_PACKAGES = [
126
- { name: "base", description: "\u57FA\u7840\u51FD\u6570\u5E93", version: "1.0.0" },
127
- { name: "at-pm", description: "\u5DE5\u7A0B\u9879\u76EE\u7BA1\u7406", version: "2.1.0" },
128
- { name: "network", description: "\u7F51\u7EDC\u529F\u80FD\u6A21\u5757", version: "1.5.0" },
129
- { name: "userman", description: "\u7528\u6237\u7BA1\u7406", version: "1.2.0" },
130
- { name: "pkgman", description: "\u5305\u7BA1\u7406\u5668", version: "2.0.0" },
131
- { name: "sidebar", description: "\u4FA7\u8FB9\u680F\u5DE5\u5177", version: "1.0.0" },
132
- { name: "aibot", description: "AI \u52A9\u624B", version: "0.9.0" },
133
- { name: "tips", description: "\u6BCF\u65E5\u63D0\u793A", version: "1.0.0" },
134
- { name: "function", description: "\u51FD\u6570\u5E93", version: "3.0.0" }
135
- ];
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
+ });
136
38
 
137
39
  // src/config.js
40
+ import { z } from "zod";
138
41
  function parseArgs() {
139
42
  const args = process.argv.slice(2);
140
43
  const result = { transport: "http", port: "8110", host: "0.0.0.0" };
@@ -154,42 +57,65 @@ function parseArgs() {
154
57
  }
155
58
  return result;
156
59
  }
157
- var cliArgs = parseArgs();
158
- var config = {
159
- port: parseInt(process.env.PORT || cliArgs.port, 10),
160
- host: process.env.HOST || cliArgs.host,
161
- transport: process.env.TRANSPORT || cliArgs.transport,
162
- apiKey: process.env.MCP_API_KEY || "",
163
- enableSse: process.env.ENABLE_SSE !== "false",
164
- messageTimeout: parseInt(process.env.MESSAGE_TIMEOUT || "60000", 10),
165
- heartbeatInterval: parseInt(process.env.HEARTBEAT_INTERVAL || "30000", 10),
166
- busyRetries: parseInt(process.env.BUSY_RETRIES || "10", 10),
167
- busyDelay: parseInt(process.env.BUSY_DELAY || "500", 10),
168
- enableCors: process.env.ENABLE_CORS !== "false",
169
- corsOrigin: process.env.CORS_ORIGIN || "*",
170
- rateLimitWindow: parseInt(process.env.RATE_LIMIT_WINDOW || "60000", 10),
171
- rateLimitMax: parseInt(process.env.RATE_LIMIT_MAX || "100", 10),
172
- resourceCacheTtl: parseInt(process.env.RESOURCE_CACHE_TTL || "5000", 10),
173
- debug: process.env.DEBUG === "true",
174
- debugFile: process.env.DEBUG_FILE || ""
175
- };
176
- var config_default = config;
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
+ });
177
113
 
178
114
  // src/cad.js
179
- var MESSAGE_TIMEOUT = config_default.messageTimeout;
180
- var HEARTBEAT_INTERVAL = config_default.heartbeatInterval;
181
- var MAX_RESTART_ATTEMPTS = 5;
182
- var RESTART_BACKOFF_BASE = 1e3;
183
- var __dirname = path.dirname(fileURLToPath(import.meta.url));
184
- var workerPath = path.join(__dirname, "cad-worker.js");
185
- var worker = null;
186
- var _platform = null;
187
- var heartbeatTimer = null;
188
- var pendingRequests = /* @__PURE__ */ new Map();
189
- var stdoutHandlerSetup = false;
190
- var MAX_BUFFER_SIZE = 1024 * 1024;
191
- var restartCount = 0;
192
- var restartTimer = null;
115
+ import { spawn } from "child_process";
116
+ import path from "path";
117
+ import { fileURLToPath } from "url";
118
+ import { randomUUID } from "crypto";
193
119
  function resetWorker() {
194
120
  for (const [id, { reject, timeout }] of pendingRequests) {
195
121
  clearTimeout(timeout);
@@ -239,8 +165,7 @@ function setupStdoutHandler(w) {
239
165
  const lines = buffer.split("\n");
240
166
  buffer = lines.pop() || "";
241
167
  for (const line of lines) {
242
- if (!line.trim())
243
- continue;
168
+ if (!line.trim()) continue;
244
169
  try {
245
170
  const result = JSON.parse(line);
246
171
  const rid = result.requestId;
@@ -266,8 +191,7 @@ function setupStdoutHandler(w) {
266
191
  }
267
192
  function getWorker(force = false) {
268
193
  if (!worker || !worker.connected || force) {
269
- if (worker)
270
- worker.kill();
194
+ if (worker) worker.kill();
271
195
  worker = spawn("node", [workerPath], {
272
196
  stdio: ["pipe", "pipe", "pipe"]
273
197
  });
@@ -275,8 +199,7 @@ function getWorker(force = false) {
275
199
  const w = worker;
276
200
  w.on("exit", (code) => {
277
201
  console.error("worker exited with code:", code);
278
- if (w !== worker)
279
- return;
202
+ if (w !== worker) return;
280
203
  w.connected = false;
281
204
  for (const [id, { reject, timeout }] of pendingRequests) {
282
205
  clearTimeout(timeout);
@@ -297,8 +220,7 @@ function getWorker(force = false) {
297
220
  return worker;
298
221
  }
299
222
  function startHeartbeat() {
300
- if (heartbeatTimer)
301
- clearInterval(heartbeatTimer);
223
+ if (heartbeatTimer) clearInterval(heartbeatTimer);
302
224
  heartbeatTimer = setInterval(async () => {
303
225
  try {
304
226
  const result = await sendMessage({ type: "ping" });
@@ -314,7 +236,7 @@ function startHeartbeat() {
314
236
  }
315
237
  function sendMessage(msg) {
316
238
  const w = getWorker();
317
- const requestId = randomUUID2();
239
+ const requestId = randomUUID();
318
240
  return new Promise((resolve, reject) => {
319
241
  const timeout = setTimeout(() => {
320
242
  const pending = pendingRequests.get(requestId);
@@ -333,140 +255,146 @@ function sendMessage(msg) {
333
255
  }
334
256
  });
335
257
  }
336
- var CadConnection = class {
337
- constructor() {
338
- this.connected = false;
339
- this.version = null;
340
- this.product = null;
341
- }
342
- isAvailable() {
343
- return process.platform === "win32";
344
- }
345
- async connect(platform = null) {
346
- if (!this.isAvailable())
347
- return false;
348
- try {
349
- const msg = platform ? { type: "connect", platform } : { type: "connect" };
350
- const result = await sendMessage(msg);
351
- if (result && result.success) {
352
- this.version = result.version;
353
- this.product = result.platform;
354
- _platform = result.platform;
355
- this.connected = true;
356
- return true;
357
- }
358
- } catch (e) {
359
- console.error("CAD connect error:", e.message);
360
- }
361
- return false;
362
- }
363
- async sendCommand(code) {
364
- if (!this.connected)
365
- throw new Error("\u672A\u8FDE\u63A5 CAD");
366
- const result = await sendMessage({ type: "send", code, platform: _platform });
367
- if (result.success)
368
- return true;
369
- throw new Error(result.error || "\u53D1\u9001\u5931\u8D25");
370
- }
371
- async sendCommandWithResult(code, encoding = null) {
372
- if (!this.connected)
373
- throw new Error("\u672A\u8FDE\u63A5 CAD");
374
- const result = await sendMessage({ type: "sendResult", code, platform: _platform, encoding: encoding || "" });
375
- if (result.success) {
376
- return result.result || "";
377
- }
378
- throw new Error(result.error || "\u53D1\u9001\u5931\u8D25");
379
- }
380
- getVersion() {
381
- return this.version;
382
- }
383
- getPlatform() {
384
- return this.product;
385
- }
386
- async isBusy() {
387
- if (!this.connected)
388
- return false;
389
- try {
390
- const result = await sendMessage({ type: "isBusy", platform: _platform });
391
- return result && result.isBusy;
392
- } catch (e) {
393
- return false;
394
- }
395
- }
396
- async hasDoc() {
397
- if (!this.connected)
398
- return { hasDoc: false, docCount: 0 };
399
- try {
400
- const result = await sendMessage({ type: "hasdoc", platform: _platform });
401
- return result || { hasDoc: false, docCount: 0 };
402
- } catch (e) {
403
- return { hasDoc: false, docCount: 0 };
404
- }
405
- }
406
- async newDoc() {
407
- if (!this.connected)
408
- throw new Error("\u672A\u8FDE\u63A5 CAD");
409
- try {
410
- const result = await sendMessage({ type: "newdoc", platform: _platform });
411
- return result && result.success;
412
- } catch (e) {
413
- return false;
414
- }
415
- }
416
- async bringToFront() {
417
- if (!this.connected)
418
- throw new Error("\u672A\u8FDE\u63A5 CAD");
419
- try {
420
- const result = await sendMessage({ type: "bringToFront", platform: _platform });
421
- return result && result.success;
422
- } catch (e) {
423
- return false;
424
- }
425
- }
426
- async getInfo() {
427
- if (!this.connected)
428
- return "CAD \u672A\u8FDE\u63A5";
429
- return `Platform: ${this.product}, Version: ${this.version}, Status: Connected`;
430
- }
431
- async disconnect() {
432
- this.connected = false;
433
- this.version = null;
434
- this.product = null;
435
- _platform = null;
436
- resetWorker();
437
- }
438
- async ping() {
439
- try {
440
- const result = await sendMessage({ type: "ping" });
441
- return result && result.pong;
442
- } catch (e) {
443
- return false;
444
- }
445
- }
446
- _reset() {
447
- this.connected = false;
448
- this.version = null;
449
- 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;
450
270
  _platform = null;
451
- resetWorker();
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();
452
387
  }
453
- };
454
- var cad = new CadConnection();
388
+ });
455
389
 
456
390
  // src/logger.js
457
391
  import fs from "fs";
458
392
  import path2 from "path";
459
393
  import os from "os";
460
- var DEBUG_FILE = process.env.DEBUG_FILE || path2.join(os.tmpdir(), "mcp-server-debug.log");
461
- var MAX_LOG_SIZE = 10 * 1024 * 1024;
462
- var MAX_LOG_FILES = 5;
463
- var stream = null;
464
394
  function rotateLog() {
465
- if (!fs.existsSync(DEBUG_FILE))
466
- return;
395
+ if (!fs.existsSync(DEBUG_FILE)) return;
467
396
  const stat = fs.statSync(DEBUG_FILE);
468
- if (stat.size < MAX_LOG_SIZE)
469
- return;
397
+ if (stat.size < MAX_LOG_SIZE) return;
470
398
  if (stream) {
471
399
  stream.end();
472
400
  stream = null;
@@ -493,10 +421,27 @@ function getStream() {
493
421
  }
494
422
  return stream;
495
423
  }
496
- function log(msg) {
497
- const entry = `${(/* @__PURE__ */ new Date()).toISOString()} ${msg}
498
- `;
499
- getStream().write(entry);
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
+ }
500
445
  }
501
446
  function closeLog() {
502
447
  if (stream) {
@@ -504,6 +449,16 @@ function closeLog() {
504
449
  stream = null;
505
450
  }
506
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
+ });
507
462
 
508
463
  // src/handlers/cad-handlers.js
509
464
  async function connectCad(platform = null) {
@@ -528,8 +483,7 @@ async function evalLisp(code, withResult = false, encoding = null) {
528
483
  return { content: [{ type: "text", text: "\u672A\u8FDE\u63A5 CAD" }], isError: true };
529
484
  }
530
485
  const trimmed = (code || "").trim();
531
- if (!trimmed)
532
- return { content: [{ type: "text", text: "\u547D\u4EE4\u4E3A\u7A7A\uFF0C\u672A\u53D1\u9001" }] };
486
+ if (!trimmed) return { content: [{ type: "text", text: "\u547D\u4EE4\u4E3A\u7A7A\uFF0C\u672A\u53D1\u9001" }] };
533
487
  try {
534
488
  if (withResult) {
535
489
  const result = await cad.sendCommandWithResult(trimmed, encoding);
@@ -549,17 +503,14 @@ async function getCadInfo() {
549
503
  if (!cad.connected) {
550
504
  await cad.connect();
551
505
  }
552
- if (!cad.connected)
553
- return { content: [{ type: "text", text: "CAD \u672A\u8FDE\u63A5" }] };
506
+ if (!cad.connected) return { content: [{ type: "text", text: "CAD \u672A\u8FDE\u63A5" }] };
554
507
  const info = await cad.getInfo();
555
508
  return { content: [{ type: "text", text: info }] };
556
509
  }
557
510
  async function atCommand(command) {
558
- if (!cad.connected)
559
- return { content: [{ type: "text", text: "\u8BF7\u5148\u8FDE\u63A5 CAD" }], isError: true };
511
+ if (!cad.connected) return { content: [{ type: "text", text: "\u8BF7\u5148\u8FDE\u63A5 CAD" }], isError: true };
560
512
  const trimmed = (command || "").trim();
561
- if (!trimmed)
562
- return { content: [{ type: "text", text: "\u547D\u4EE4\u4E3A\u7A7A\uFF0C\u672A\u53D1\u9001" }] };
513
+ if (!trimmed) return { content: [{ type: "text", text: "\u547D\u4EE4\u4E3A\u7A7A\uFF0C\u672A\u53D1\u9001" }] };
563
514
  await cad.sendCommand(trimmed + "\n");
564
515
  return { content: [{ type: "text", text: "\u5DF2\u53D1\u9001\u547D\u4EE4" }] };
565
516
  }
@@ -567,8 +518,7 @@ async function newDocument() {
567
518
  if (!cad.connected) {
568
519
  await cad.connect();
569
520
  }
570
- if (!cad.connected)
571
- return { content: [{ type: "text", text: "\u672A\u8FDE\u63A5 CAD" }], isError: true };
521
+ if (!cad.connected) return { content: [{ type: "text", text: "\u672A\u8FDE\u63A5 CAD" }], isError: true };
572
522
  const result = await cad.newDoc();
573
523
  if (result) {
574
524
  return { content: [{ type: "text", text: "\u5DF2\u5728 CAD \u4E2D\u65B0\u5EFA\u7A7A\u767D\u6587\u6863" }] };
@@ -579,8 +529,7 @@ async function bringToFront() {
579
529
  if (!cad.connected) {
580
530
  await cad.connect();
581
531
  }
582
- if (!cad.connected)
583
- return { content: [{ type: "text", text: "\u672A\u8FDE\u63A5 CAD" }], isError: true };
532
+ if (!cad.connected) return { content: [{ type: "text", text: "\u672A\u8FDE\u63A5 CAD" }], isError: true };
584
533
  const result = await cad.bringToFront();
585
534
  if (result) {
586
535
  return { content: [{ type: "text", text: "\u5DF2\u5C06 CAD \u7A97\u53E3\u5207\u6362\u5230\u524D\u53F0" }] };
@@ -591,8 +540,7 @@ async function installAtlisp() {
591
540
  if (!cad.connected) {
592
541
  await cad.connect();
593
542
  }
594
- if (!cad.connected)
595
- return { content: [{ type: "text", text: "\u672A\u8FDE\u63A5 CAD" }], isError: true };
543
+ if (!cad.connected) return { content: [{ type: "text", text: "\u672A\u8FDE\u63A5 CAD" }], isError: true };
596
544
  const installCode = `(progn(vl-load-com)(setq s strcat h "http" o(vlax-create-object (s"win"h".win"h"request.5.1"))v vlax-invoke e eval r read)(v o'open "get" (s h"://atlisp.""cn/@"):vlax-true)(v o'send)(v o'WaitforResponse 1000)(e(r(vlax-get-property o'ResponseText))))`;
597
545
  await cad.sendCommand(installCode + "\n");
598
546
  return { content: [{ type: "text", text: "\u5DF2\u53D1\u9001 @lisp \u5B89\u88C5\u4EE3\u7801\u5230 CAD" }] };
@@ -601,12 +549,10 @@ async function listFunctionsInCad() {
601
549
  if (!cad.connected) {
602
550
  await cad.connect();
603
551
  }
604
- if (!cad.connected)
605
- return { content: [{ type: "text", text: "\u672A\u8FDE\u63A5 CAD" }], isError: true };
552
+ if (!cad.connected) return { content: [{ type: "text", text: "\u672A\u8FDE\u63A5 CAD" }], isError: true };
606
553
  try {
607
554
  const result = await cad.sendCommandWithResult("(atoms-family 0)", null);
608
- if (result)
609
- return { content: [{ type: "text", text: result }] };
555
+ if (result) return { content: [{ type: "text", text: result }] };
610
556
  return { content: [{ type: "text", text: "CAD \u51FD\u6570\u5217\u8868\u4E3A\u7A7A" }] };
611
557
  } catch (e) {
612
558
  return { content: [{ type: "text", text: `\u9519\u8BEF: ${e.message}` }], isError: true };
@@ -661,8 +607,7 @@ async function initAtlisp() {
661
607
  if (!cad.connected) {
662
608
  await cad.connect();
663
609
  }
664
- if (!cad.connected)
665
- return { content: [{ type: "text", text: "\u672A\u8FDE\u63A5 CAD" }], isError: true };
610
+ if (!cad.connected) return { content: [{ type: "text", text: "\u672A\u8FDE\u63A5 CAD" }], isError: true };
666
611
  const code = `(if (null @::load-module)
667
612
  (progn
668
613
  (vl-load-com)
@@ -678,12 +623,14 @@ async function initAtlisp() {
678
623
  return { content: [{ type: "text", text: `\u9519\u8BEF: ${e.message}` }], isError: true };
679
624
  }
680
625
  }
626
+ var init_cad_handlers = __esm({
627
+ "src/handlers/cad-handlers.js"() {
628
+ init_cad();
629
+ init_logger();
630
+ }
631
+ });
681
632
 
682
633
  // src/handlers/package-handlers.js
683
- var PACKAGES_LIST_URL = process.env.PACKAGES_LIST_URL || "http://s3.atlisp.cn/packages-list?fmt=json";
684
- var cachedPackages = null;
685
- var cachedAt = null;
686
- var CACHE_TTL = 10 * 60 * 1e3;
687
634
  async function fetchPackages() {
688
635
  const now = Date.now();
689
636
  if (cachedPackages && cachedAt && now - cachedAt < CACHE_TTL) {
@@ -702,15 +649,12 @@ async function fetchPackages() {
702
649
  return cachedPackages || MOCK_PACKAGES;
703
650
  }
704
651
  function flattenPackages(data) {
705
- if (Array.isArray(data))
706
- return data;
707
- if (data && Array.isArray(data.packages))
708
- return data.packages;
652
+ if (Array.isArray(data)) return data;
653
+ if (data && Array.isArray(data.packages)) return data.packages;
709
654
  return [];
710
655
  }
711
656
  async function listPackages() {
712
- if (!cad.connected)
713
- await cad.connect();
657
+ if (!cad.connected) await cad.connect();
714
658
  if (!cad.connected) {
715
659
  const data2 = await fetchPackages();
716
660
  const items2 = flattenPackages(data2);
@@ -718,8 +662,7 @@ async function listPackages() {
718
662
  return { content: [{ type: "text", text: text2 }] };
719
663
  }
720
664
  const result = await cad.sendCommandWithResult("(@::package-list-in-local)");
721
- if (result && result !== "nil")
722
- return { content: [{ type: "text", text: result }] };
665
+ if (result && result !== "nil") return { content: [{ type: "text", text: result }] };
723
666
  const data = await fetchPackages();
724
667
  const items = flattenPackages(data);
725
668
  const text = items.length ? `\u4ECE\u6CE8\u518C\u8868\u83B7\u53D6\u7684 @lisp \u5305:
@@ -739,12 +682,10 @@ async function searchPackages(query) {
739
682
  for (const p of items) {
740
683
  const name = (p.name || "").toLowerCase();
741
684
  const desc = (p.description || "").toLowerCase();
742
- if (name.includes(q) || desc.includes(q))
743
- results.push(p);
685
+ if (name.includes(q) || desc.includes(q)) results.push(p);
744
686
  }
745
687
  } else {
746
- for (const p of items)
747
- results.push(p);
688
+ for (const p of items) results.push(p);
748
689
  }
749
690
  if (results.length === 0) {
750
691
  return { content: [{ type: "text", text: `\u672A\u627E\u5230\u5305\u542B "${query}" \u7684\u5305` }] };
@@ -765,16 +706,22 @@ async function installPackage(packageName) {
765
706
  }
766
707
  return { content: [{ type: "text", text: `\u5305 "${packageName}" \u5B89\u88C5\u547D\u4EE4\u5DF2\u53D1\u9001\uFF01` }] };
767
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
+ });
768
720
 
769
721
  // src/handlers/function-handlers.js
770
722
  import fs2 from "fs";
771
723
  import path3 from "path";
772
724
  import os2 from "os";
773
- var FUNCTIONS_DIR = process.env.FUNCTIONS_DIR || "";
774
- var FUNCTIONS_URL = process.env.FUNCTIONS_URL || "http://s3.atlisp.cn/json/functions.json";
775
- var CACHE_DIR = path3.join(os2.homedir(), ".atlisp", "cache");
776
- var FUNCLIB_CACHE_FILE = path3.join(CACHE_DIR, "functions.json");
777
- var FUNCLIB_CACHE_TTL = 24 * 60 * 60 * 1e3;
778
725
  function readCacheFromDisk() {
779
726
  try {
780
727
  const stat = fs2.statSync(FUNCLIB_CACHE_FILE);
@@ -796,8 +743,7 @@ function writeCacheToDisk(data) {
796
743
  }
797
744
  async function fetchFunctions() {
798
745
  const diskCache = readCacheFromDisk();
799
- if (diskCache)
800
- return diskCache;
746
+ if (diskCache) return diskCache;
801
747
  try {
802
748
  const response = await fetch(FUNCTIONS_URL, { headers: { "User-Agent": "atlisp-mcp" } });
803
749
  if (response.ok) {
@@ -817,8 +763,7 @@ async function getFunctionUsage(funcName, packageName) {
817
763
  if (data) {
818
764
  const funcs = Object.values(data.all_functions || {});
819
765
  const func = funcs.find((f2) => f2.name === funcName || f2.name === `${packageName}:${funcName}`);
820
- if (func)
821
- results.push(func);
766
+ if (func) results.push(func);
822
767
  }
823
768
  if (results.length === 0 && FUNCTIONS_DIR) {
824
769
  try {
@@ -827,8 +772,7 @@ async function getFunctionUsage(funcName, packageName) {
827
772
  const raw = fs2.readFileSync(path3.join(FUNCTIONS_DIR, file), "utf-8");
828
773
  const data2 = JSON.parse(raw);
829
774
  const func = data2.functions?.find((f2) => f2.name === funcName);
830
- if (func)
831
- results.push(func);
775
+ if (func) results.push(func);
832
776
  }
833
777
  } catch {
834
778
  }
@@ -890,15 +834,23 @@ ${allFuncs.map((f) => f.name).join("\n")}` }] };
890
834
  return { content: [{ type: "text", text: `\u9519\u8BEF: ${e.message}` }], isError: true };
891
835
  }
892
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
+ });
893
849
 
894
850
  // src/handlers/resource-handlers.js
895
851
  import fs3 from "fs";
896
852
  import path4 from "path";
897
853
  import { fileURLToPath as fileURLToPath2 } from "url";
898
- var __dirname2 = path4.dirname(fileURLToPath2(import.meta.url));
899
- var STANDARDS_DIR = path4.join(__dirname2, "..", "standards");
900
- var CACHE_TTL2 = config_default.resourceCacheTtl;
901
- var resourceCache = /* @__PURE__ */ new Map();
902
854
  function getCached(key) {
903
855
  const entry = resourceCache.get(key);
904
856
  if (entry && Date.now() - entry.timestamp < CACHE_TTL2) {
@@ -922,14 +874,11 @@ function clearCache(uri) {
922
874
  }
923
875
  }
924
876
  function parseLispList(str) {
925
- if (!str || typeof str !== "string")
926
- return null;
877
+ if (!str || typeof str !== "string") return null;
927
878
  const trimmed = str.trim();
928
- if (!trimmed.startsWith("(") || !trimmed.endsWith(")"))
929
- return null;
879
+ if (!trimmed.startsWith("(") || !trimmed.endsWith(")")) return null;
930
880
  const content = trimmed.slice(1, -1).trim();
931
- if (!content)
932
- return [];
881
+ if (!content) return [];
933
882
  const result = [];
934
883
  let depth = 0;
935
884
  let current = "";
@@ -971,44 +920,32 @@ function parseLispList(str) {
971
920
  }
972
921
  current += ch;
973
922
  }
974
- if (current.trim())
975
- result.push(current.trim());
923
+ if (current.trim()) result.push(current.trim());
976
924
  return result.map((item) => {
977
925
  const t = item.trim();
978
- if (t === "nil")
979
- return null;
980
- if (t === "t")
981
- return true;
982
- if (t === "T")
983
- return true;
926
+ if (t === "nil") return null;
927
+ if (t === "t") return true;
928
+ if (t === "T") return true;
984
929
  const num = Number(t);
985
- if (!isNaN(num) && t !== "")
986
- return num;
987
- if (t.startsWith('"') && t.endsWith('"'))
988
- return t.slice(1, -1);
930
+ if (!isNaN(num) && t !== "") return num;
931
+ if (t.startsWith('"') && t.endsWith('"')) return t.slice(1, -1);
989
932
  return t;
990
933
  });
991
934
  }
992
935
  function parseLispRecursive(str) {
993
- if (!str || typeof str !== "string")
994
- return null;
936
+ if (!str || typeof str !== "string") return null;
995
937
  str = str.trim();
996
- if (!str)
997
- return null;
938
+ if (!str) return null;
998
939
  let pos = 0;
999
940
  function skipWs() {
1000
- while (pos < str.length && /\s/.test(str[pos]))
1001
- pos++;
941
+ while (pos < str.length && /\s/.test(str[pos])) pos++;
1002
942
  }
1003
943
  function parseValue() {
1004
944
  skipWs();
1005
- if (pos >= str.length)
1006
- return null;
945
+ if (pos >= str.length) return null;
1007
946
  const ch = str[pos];
1008
- if (ch === "(")
1009
- return parseList();
1010
- if (ch === '"')
1011
- return parseString();
947
+ if (ch === "(") return parseList();
948
+ if (ch === '"') return parseString();
1012
949
  if (ch === "'") {
1013
950
  pos++;
1014
951
  return parseValue();
@@ -1021,16 +958,11 @@ function parseLispRecursive(str) {
1021
958
  while (pos < str.length && str[pos] !== '"') {
1022
959
  if (str[pos] === "\\" && pos + 1 < str.length) {
1023
960
  pos++;
1024
- if (str[pos] === '"')
1025
- r += '"';
1026
- else if (str[pos] === "n")
1027
- r += "\n";
1028
- else if (str[pos] === "t")
1029
- r += " ";
1030
- else if (str[pos] === "\\")
1031
- r += "\\";
1032
- else
1033
- r += str[pos];
961
+ if (str[pos] === '"') r += '"';
962
+ else if (str[pos] === "n") r += "\n";
963
+ else if (str[pos] === "t") r += " ";
964
+ else if (str[pos] === "\\") r += "\\";
965
+ else r += str[pos];
1034
966
  } else {
1035
967
  r += str[pos];
1036
968
  }
@@ -1041,16 +973,12 @@ function parseLispRecursive(str) {
1041
973
  }
1042
974
  function parseAtom() {
1043
975
  const start = pos;
1044
- while (pos < str.length && !/\s/.test(str[pos]) && str[pos] !== ")" && str[pos] !== "(")
1045
- pos++;
976
+ while (pos < str.length && !/\s/.test(str[pos]) && str[pos] !== ")" && str[pos] !== "(") pos++;
1046
977
  const atom = str.slice(start, pos);
1047
- if (atom === "nil" || atom === "NIL")
1048
- return null;
1049
- if (atom === "t" || atom === "T")
1050
- return true;
978
+ if (atom === "nil" || atom === "NIL") return null;
979
+ if (atom === "t" || atom === "T") return true;
1051
980
  const num = Number(atom);
1052
- if (!isNaN(num) && atom !== "")
1053
- return num;
981
+ if (!isNaN(num) && atom !== "") return num;
1054
982
  return atom;
1055
983
  }
1056
984
  function parseList() {
@@ -1058,15 +986,13 @@ function parseLispRecursive(str) {
1058
986
  const items = [];
1059
987
  while (pos < str.length) {
1060
988
  skipWs();
1061
- if (pos >= str.length)
1062
- break;
989
+ if (pos >= str.length) break;
1063
990
  if (str[pos] === ")") {
1064
991
  pos++;
1065
992
  return items;
1066
993
  }
1067
994
  const left = parseValue();
1068
- if (left === void 0)
1069
- break;
995
+ if (left === void 0) break;
1070
996
  skipWs();
1071
997
  if (str[pos] === "." && (pos + 1 >= str.length || /\s/.test(str[pos + 1]) || str[pos + 1] === ")")) {
1072
998
  pos++;
@@ -1087,8 +1013,7 @@ function parseLispRecursive(str) {
1087
1013
  return parseValue();
1088
1014
  }
1089
1015
  function lispPairsToObject(pairs) {
1090
- if (!Array.isArray(pairs))
1091
- return pairs;
1016
+ if (!Array.isArray(pairs)) return pairs;
1092
1017
  const obj = {};
1093
1018
  for (let i = 0; i < pairs.length - 1; i += 2) {
1094
1019
  const key = pairs[i];
@@ -1100,17 +1025,35 @@ function lispPairsToObject(pairs) {
1100
1025
  return obj;
1101
1026
  }
1102
1027
  function parseEntity(arr) {
1103
- if (!Array.isArray(arr) || arr.length < 5)
1104
- return null;
1105
- const [type, handle, layer, color, linetype] = arr;
1106
- return { type: String(type), handle: String(handle), layer: String(layer), color, linetype: String(linetype) };
1028
+ if (!Array.isArray(arr) || arr.length < 5) return null;
1029
+ const [type, handle, layer, color, linetype, ...rest] = arr;
1030
+ const entity = {
1031
+ type: String(type).toUpperCase().replace(/^"|"$/g, ""),
1032
+ handle: String(handle),
1033
+ layer: String(layer),
1034
+ color,
1035
+ linetype: String(linetype)
1036
+ };
1037
+ const entType = typeof entity.type === "string" ? entity.type.toUpperCase() : entity.type;
1038
+ if (/^(TEXT|MTEXT|ATTRIB|TCH_TEXT)$/.test(entType) && rest[0] != null) {
1039
+ entity.text = String(rest[0]);
1040
+ }
1041
+ if (/^(LINE|LWPOLYLINE|POLYLINE|ARC|CIRCLE|SPLINE|ELLIPSE|XLINE|RAY)$/.test(entType) && Array.isArray(rest[0])) {
1042
+ entity.points = rest[0].map((pt) => {
1043
+ if (Array.isArray(pt) && pt.length >= 2)
1044
+ return { x: Number(pt[0]), y: Number(pt[1]), z: Number(pt[2] || 0) };
1045
+ return null;
1046
+ }).filter(Boolean);
1047
+ }
1048
+ if (entType === "INSERT" && rest[0] != null) {
1049
+ entity.blockName = String(rest[0]);
1050
+ }
1051
+ return entity;
1107
1052
  }
1108
1053
  function buildEntityCode({ type, layer, bbox }) {
1109
1054
  const items = [];
1110
- if (type)
1111
- items.push(`(cons 0 "${type.replace(/"/g, '\\"')}")`);
1112
- if (layer)
1113
- items.push(`(cons 8 "${layer.replace(/"/g, '\\"')}")`);
1055
+ if (type) items.push(`(cons 0 "${type.replace(/"/g, '\\"')}")`);
1056
+ if (layer) items.push(`(cons 8 "${layer.replace(/"/g, '\\"')}")`);
1114
1057
  if (bbox) {
1115
1058
  const parts = bbox.split(",").map((s) => parseFloat(s.trim()));
1116
1059
  if (parts.length === 4) {
@@ -1127,21 +1070,32 @@ function buildEntityCode({ type, layer, bbox }) {
1127
1070
  const ssgetExpr = items.length ? `(ssget "_X" ${filterExpr})` : '(ssget "_X")';
1128
1071
  return `(progn
1129
1072
  (vl-load-com)
1130
- (defun @e:dp (ent / ed typ gc is)
1131
- (setq ed (entget ent) typ (cdr (assoc 0 ed)) gc (assoc 62 ed) is (assoc 6 ed))
1132
- (list typ (cdr (assoc 5 ed)) (cdr (assoc 8 ed))
1133
- (if gc (cdr gc) 256)
1134
- (if is (cdr is) "ByLayer")))
1073
+ (defun @e:safe-fn (f ent / r)
1074
+ (setq r (vl-catch-all-apply f (list ent)))
1075
+ (if (vl-catch-all-error-p r) nil r))
1076
+ (defun @e:dp (ent / ed typ gcl is)
1077
+ (setq ed (entget ent) typ (cdr (assoc 0 ed)) gcl (assoc 62 ed) is (assoc 6 ed))
1078
+ (append
1079
+ (list typ (cdr (assoc 5 ed)) (cdr (assoc 8 ed))
1080
+ (if gcl (cdr gcl) 256)
1081
+ (if is (cdr is) "ByLayer"))
1082
+ (cond
1083
+ ((wcmatch typ "TEXT,MTEXT,ATTRIB,TCH_TEXT")
1084
+ (list (@e:safe-fn '(lambda (e) (text:remove-fmt (text:get-mtext e))) ent)))
1085
+ ((wcmatch typ "LINE,LWPOLYLINE,POLYLINE,ARC,CIRCLE,SPLINE,ELLIPSE,XLINE,RAY")
1086
+ (list (@e:safe-fn 'curve:get-points ent)))
1087
+ ((= typ "INSERT")
1088
+ (list (@e:safe-fn 'block:get-effectivename ent)))
1089
+ (t nil))))
1135
1090
  (setq @e:total (if (setq @e:ss ${ssgetExpr}) (sslength @e:ss) 0)
1136
1091
  @e:ents nil @e:i 0)
1137
- (while (and @e:ss (< @e:i @e:total)(< (length @e:ents) 100))
1092
+ (while (and @e:ss (< @e:i @e:total)(< (length @e:ents) 3000))
1138
1093
  (setq @e:ents (cons (@e:dp (ssname @e:ss @e:i)) @e:ents) @e:i (1+ @e:i)))
1139
1094
  (vl-prin1-to-string (list @e:total (reverse @e:ents))))`;
1140
1095
  }
1141
1096
  function buildTextCode({ layer, bbox, offset, limit }) {
1142
1097
  const items = [`'(0 . "TEXT,MTEXT,ATTRIB,TCH_TEXT")`];
1143
- if (layer)
1144
- items.push(`(cons 8 "${layer.replace(/"/g, '\\"')}")`);
1098
+ if (layer) items.push(`(cons 8 "${layer.replace(/"/g, '\\"')}")`);
1145
1099
  if (bbox) {
1146
1100
  const parts = bbox.split(",").map((s) => parseFloat(s.trim()));
1147
1101
  if (parts.length === 4) {
@@ -1177,31 +1131,16 @@ function buildTextCode({ layer, bbox, offset, limit }) {
1177
1131
  (@t:run))
1178
1132
  `;
1179
1133
  }
1180
- var RESOURCES = [
1181
- { uri: "atlisp://cad/info", name: "CAD Info", description: "CAD \u8FDE\u63A5\u4FE1\u606F", mimeType: "application/json", subscribable: true },
1182
- { uri: "atlisp://dwg/layers", name: "Layers", description: "\u56FE\u5C42\u5217\u8868", mimeType: "application/json", subscribable: true },
1183
- { uri: "atlisp://dwg/entities", name: "Entities", description: "\u56FE\u5143\u5217\u8868\uFF0C\u8FD4\u56DE\u603B\u6570\u548C\u524D100\u4E2A\u56FE\u5143\uFF08\u7C7B\u578B\u3001\u53E5\u67C4\u3001\u56FE\u5C42\u3001\u989C\u8272\u3001\u7EBF\u578B\uFF09\uFF0C\u652F\u6301 ?type=LINE&layer=0&bbox=0,0,100,100 \u8FC7\u6EE4", mimeType: "application/json", subscribable: true },
1184
- { 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 },
1185
- { uri: "atlisp://dwg/name", name: "DWG Name", description: "\u5F53\u524D DWG \u6587\u4EF6\u540D", mimeType: "application/json", subscribable: true },
1186
- { uri: "atlisp://dwg/path", name: "DWG Path", description: "\u6587\u4EF6\u5B8C\u6574\u8DEF\u5F84", mimeType: "application/json", subscribable: true },
1187
- { uri: "atlisp://cad/dwgs", name: "DWG List", description: "\u6240\u6709\u6253\u5F00\u7684 DWG \u6587\u4EF6\u5217\u8868", mimeType: "application/json", subscribable: true },
1188
- { uri: "atlisp://packages", name: "Packages", description: "\u5DF2\u5B89\u88C5\u5305\u5217\u8868", mimeType: "application/json", subscribable: true },
1189
- { uri: "atlisp://platforms", name: "Platforms", description: "\u652F\u6301\u7684\u5E73\u53F0\u4FE1\u606F", mimeType: "application/json", subscribable: false },
1190
- { uri: "atlisp://standards/drafting", name: "Drafting Standards", description: "CAD \u5236\u56FE\u89C4\u8303", mimeType: "application/json", subscribable: false },
1191
- { uri: "atlisp://standards/coding", name: "Coding Standards", description: "@lisp \u7F16\u7801\u89C4\u8303", mimeType: "application/json", subscribable: false }
1192
- ];
1193
1134
  function parseQuery(uri) {
1194
1135
  const qIdx = uri.indexOf("?");
1195
- if (qIdx === -1)
1196
- return { base: uri, params: {} };
1136
+ if (qIdx === -1) return { base: uri, params: {} };
1197
1137
  const base = uri.substring(0, qIdx);
1198
1138
  const params = {};
1199
1139
  uri.substring(qIdx + 1).split("&").forEach((p) => {
1200
1140
  const eqIdx = p.indexOf("=");
1201
1141
  const k = eqIdx === -1 ? p : p.substring(0, eqIdx);
1202
1142
  const v = eqIdx === -1 ? "" : p.substring(eqIdx + 1);
1203
- if (k)
1204
- params[k] = decodeURIComponent(v);
1143
+ if (k) params[k] = decodeURIComponent(v);
1205
1144
  });
1206
1145
  return { base, params };
1207
1146
  }
@@ -1245,8 +1184,7 @@ async function readResource(uri) {
1245
1184
  }
1246
1185
  async function getCadInfo2() {
1247
1186
  const cached = getCached("cad:info");
1248
- if (cached)
1249
- return cached;
1187
+ if (cached) return cached;
1250
1188
  if (!cad.connected) {
1251
1189
  await cad.connect();
1252
1190
  }
@@ -1273,12 +1211,9 @@ async function getCadInfo2() {
1273
1211
  async function getLayers(filterName = null) {
1274
1212
  const cacheKey = filterName ? `dwg:layers:${filterName}` : "dwg:layers:all";
1275
1213
  const cached = getCached(cacheKey);
1276
- if (cached)
1277
- return cached;
1278
- if (!cad.connected)
1279
- await cad.connect();
1280
- if (!cad.connected)
1281
- return [];
1214
+ if (cached) return cached;
1215
+ if (!cad.connected) await cad.connect();
1216
+ if (!cad.connected) return [];
1282
1217
  try {
1283
1218
  const code = filterName ? `(vl-prin1-to-string (cdr (assoc 2 (tblnext "LAYER" T))))` : `(progn (setq res nil)(while (setq e (tblnext "LAYER" (null res)))(setq res (cons (list (vl-prin1-to-string (cdr (assoc 2 e))) (cdr (assoc 62 e)) (cdr (assoc 70 e))) res))) (reverse res))`;
1284
1219
  const result = await cad.sendCommandWithResult(code);
@@ -1325,10 +1260,8 @@ async function getLayers(filterName = null) {
1325
1260
  async function getEntities(params = {}) {
1326
1261
  const cacheKey = `dwg:entities:${JSON.stringify(params)}`;
1327
1262
  const cached = getCached(cacheKey);
1328
- if (cached)
1329
- return cached;
1330
- if (!cad.connected)
1331
- await cad.connect();
1263
+ if (cached) return cached;
1264
+ if (!cad.connected) await cad.connect();
1332
1265
  if (!cad.connected) {
1333
1266
  const result = { total: 0, entities: [] };
1334
1267
  setCache(cacheKey, result);
@@ -1368,10 +1301,8 @@ async function getEntities(params = {}) {
1368
1301
  async function getTexts(params = {}) {
1369
1302
  const cacheKey = `dwg:texts:${JSON.stringify(params)}`;
1370
1303
  const cached = getCached(cacheKey);
1371
- if (cached)
1372
- return cached;
1373
- if (!cad.connected)
1374
- await cad.connect();
1304
+ if (cached) return cached;
1305
+ if (!cad.connected) await cad.connect();
1375
1306
  if (!cad.connected) {
1376
1307
  const result = { total: 0, texts: [] };
1377
1308
  setCache(cacheKey, result);
@@ -1409,10 +1340,8 @@ async function getTexts(params = {}) {
1409
1340
  }
1410
1341
  }
1411
1342
  async function getDwgName() {
1412
- if (!cad.connected)
1413
- await cad.connect();
1414
- if (!cad.connected)
1415
- return { name: null };
1343
+ if (!cad.connected) await cad.connect();
1344
+ if (!cad.connected) return { name: null };
1416
1345
  try {
1417
1346
  const code = `(vl-princ-to-string (getvar "dwgname"))`;
1418
1347
  const name = await cad.sendCommandWithResult(code);
@@ -1422,10 +1351,8 @@ async function getDwgName() {
1422
1351
  }
1423
1352
  }
1424
1353
  async function getDwgPath() {
1425
- if (!cad.connected)
1426
- await cad.connect();
1427
- if (!cad.connected)
1428
- return { path: null, name: null };
1354
+ if (!cad.connected) await cad.connect();
1355
+ if (!cad.connected) return { path: null, name: null };
1429
1356
  try {
1430
1357
  const code = `(progn
1431
1358
  (setq prefix (vl-princ-to-string (getvar "dwgprefix")))
@@ -1443,8 +1370,7 @@ async function getDwgPath() {
1443
1370
  }
1444
1371
  if (!parsed) {
1445
1372
  const listResult = parseLispList(result);
1446
- if (listResult && listResult.length >= 2)
1447
- parsed = listResult;
1373
+ if (listResult && listResult.length >= 2) parsed = listResult;
1448
1374
  }
1449
1375
  if (parsed && Array.isArray(parsed) && parsed.length >= 2) {
1450
1376
  return { path: String(parsed[0]), name: String(parsed[1]) };
@@ -1457,12 +1383,9 @@ async function getDwgPath() {
1457
1383
  async function getPackages(filterName = null) {
1458
1384
  const cacheKey = filterName ? `packages:${filterName}` : "packages:all";
1459
1385
  const cached = getCached(cacheKey);
1460
- if (cached)
1461
- return cached;
1462
- if (!cad.connected)
1463
- await cad.connect();
1464
- if (!cad.connected)
1465
- return [];
1386
+ if (cached) return cached;
1387
+ if (!cad.connected) await cad.connect();
1388
+ if (!cad.connected) return [];
1466
1389
  try {
1467
1390
  const code = `(mapcar 'cdr @::*local-pkgs*)`;
1468
1391
  const result = await cad.sendCommandWithResult(code);
@@ -1476,8 +1399,7 @@ async function getPackages(filterName = null) {
1476
1399
  } catch {
1477
1400
  raw = parseLispList(result) || [];
1478
1401
  }
1479
- if (!Array.isArray(raw))
1480
- raw = [];
1402
+ if (!Array.isArray(raw)) raw = [];
1481
1403
  const packages = raw.map((item) => {
1482
1404
  if (Array.isArray(item)) {
1483
1405
  const pkg = { name: "", version: "0.0.0", description: "", loaded: true };
@@ -1486,20 +1408,13 @@ async function getPackages(filterName = null) {
1486
1408
  const [[key, val]] = Object.entries(entry);
1487
1409
  const k = String(key);
1488
1410
  const v = String(val);
1489
- if (k === ":NAME")
1490
- pkg.name = v;
1491
- else if (k === ":VERSION")
1492
- pkg.version = v;
1493
- else if (k === ":DESCRIPTION")
1494
- pkg.description = v;
1495
- else if (k === ":FULL-NAME")
1496
- pkg.fullName = v;
1497
- else if (k === ":AUTHOR")
1498
- pkg.author = v;
1499
- else if (k === ":CATEGORY")
1500
- pkg.category = v;
1501
- else if (k === ":URL")
1502
- pkg.url = v;
1411
+ if (k === ":NAME") pkg.name = v;
1412
+ else if (k === ":VERSION") pkg.version = v;
1413
+ else if (k === ":DESCRIPTION") pkg.description = v;
1414
+ else if (k === ":FULL-NAME") pkg.fullName = v;
1415
+ else if (k === ":AUTHOR") pkg.author = v;
1416
+ else if (k === ":CATEGORY") pkg.category = v;
1417
+ else if (k === ":URL") pkg.url = v;
1503
1418
  }
1504
1419
  }
1505
1420
  return pkg;
@@ -1510,22 +1425,15 @@ async function getPackages(filterName = null) {
1510
1425
  if (item && typeof item === "object") {
1511
1426
  const pkg = { name: "", version: "0.0.0", description: "", loaded: true };
1512
1427
  const nameVal = item.name || item.Name || item.NAME || item[":NAME"];
1513
- if (nameVal)
1514
- pkg.name = String(nameVal);
1428
+ if (nameVal) pkg.name = String(nameVal);
1515
1429
  const verVal = item.version || item.Version || item.VERSION || item[":VERSION"];
1516
- if (verVal)
1517
- pkg.version = String(verVal);
1430
+ if (verVal) pkg.version = String(verVal);
1518
1431
  const descVal = item.description || item.Description || item.DESCRIPTION || item[":DESCRIPTION"];
1519
- if (descVal)
1520
- pkg.description = String(descVal);
1521
- if (item.fullName || item.full_name)
1522
- pkg.fullName = String(item.fullName || item.full_name);
1523
- if (item.author || item.Author)
1524
- pkg.author = String(item.author || item.Author);
1525
- if (item.category || item.Category)
1526
- pkg.category = String(item.category || item.Category);
1527
- if (item.url || item.Url || item.URL)
1528
- pkg.url = String(item.url || item.Url || item.URL);
1432
+ if (descVal) pkg.description = String(descVal);
1433
+ if (item.fullName || item.full_name) pkg.fullName = String(item.fullName || item.full_name);
1434
+ if (item.author || item.Author) pkg.author = String(item.author || item.Author);
1435
+ if (item.category || item.Category) pkg.category = String(item.category || item.Category);
1436
+ if (item.url || item.Url || item.URL) pkg.url = String(item.url || item.Url || item.URL);
1529
1437
  return pkg;
1530
1438
  }
1531
1439
  return null;
@@ -1551,12 +1459,9 @@ function getPlatforms() {
1551
1459
  async function getDwgList() {
1552
1460
  const cacheKey = "cad:dwgs";
1553
1461
  const cached = getCached(cacheKey);
1554
- if (cached)
1555
- return cached;
1556
- if (!cad.connected)
1557
- await cad.connect();
1558
- if (!cad.connected)
1559
- return [];
1462
+ if (cached) return cached;
1463
+ if (!cad.connected) await cad.connect();
1464
+ if (!cad.connected) return [];
1560
1465
  try {
1561
1466
  const code = `(progn
1562
1467
  (vl-load-com)
@@ -1580,8 +1485,7 @@ async function getDwgList() {
1580
1485
  parsed = listResult;
1581
1486
  }
1582
1487
  }
1583
- if (!Array.isArray(parsed))
1584
- parsed = [];
1488
+ if (!Array.isArray(parsed)) parsed = [];
1585
1489
  const dwgList = parsed.map((item) => {
1586
1490
  if (Array.isArray(item) && item.length >= 2) {
1587
1491
  return { name: String(item[0]), path: String(item[1]) };
@@ -1605,11 +1509,9 @@ function loadStandardsFile(filename) {
1605
1509
  return null;
1606
1510
  }
1607
1511
  }
1608
- var standardsCache = /* @__PURE__ */ new Map();
1609
1512
  function getCachedStandards(key) {
1610
1513
  const entry = standardsCache.get(key);
1611
- if (entry && Date.now() - entry.timestamp < 3e4)
1612
- return entry.data;
1514
+ if (entry && Date.now() - entry.timestamp < 3e4) return entry.data;
1613
1515
  standardsCache.delete(key);
1614
1516
  return null;
1615
1517
  }
@@ -1618,32 +1520,50 @@ function setCachedStandards(key, data) {
1618
1520
  }
1619
1521
  function getDraftingStandards() {
1620
1522
  const cached = getCachedStandards("drafting");
1621
- if (cached)
1622
- return cached;
1523
+ if (cached) return cached;
1623
1524
  const data = loadStandardsFile("drafting.json");
1624
- if (data)
1625
- setCachedStandards("drafting", data);
1525
+ if (data) setCachedStandards("drafting", data);
1626
1526
  return data || { error: "\u5236\u56FE\u89C4\u8303\u6587\u4EF6\u52A0\u8F7D\u5931\u8D25" };
1627
1527
  }
1628
1528
  function getCodingStandards() {
1629
1529
  const cached = getCachedStandards("coding");
1630
- if (cached)
1631
- return cached;
1530
+ if (cached) return cached;
1632
1531
  const data = loadStandardsFile("coding.json");
1633
- if (data)
1634
- setCachedStandards("coding", data);
1532
+ if (data) setCachedStandards("coding", data);
1635
1533
  return data || { error: "\u7F16\u7801\u89C4\u8303\u6587\u4EF6\u52A0\u8F7D\u5931\u8D25" };
1636
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
+ });
1637
1562
 
1638
1563
  // src/handlers/prompt-handlers.js
1639
1564
  import fs4 from "fs";
1640
1565
  import path5 from "path";
1641
1566
  import { fileURLToPath as fileURLToPath3 } from "url";
1642
- var __dirname3 = path5.dirname(fileURLToPath3(import.meta.url));
1643
- var PROMPTS_DIR = path5.join(__dirname3, "..", "prompts");
1644
- var externalPrompts = null;
1645
- var externalPromptsAt = 0;
1646
- var EXTERNAL_PROMPTS_TTL = 3e4;
1647
1567
  function loadExternalPrompts() {
1648
1568
  const now = Date.now();
1649
1569
  if (externalPrompts && now - externalPromptsAt < EXTERNAL_PROMPTS_TTL) {
@@ -1673,121 +1593,6 @@ function loadExternalPrompts() {
1673
1593
  externalPromptsAt = now;
1674
1594
  return externalPrompts;
1675
1595
  }
1676
- var PROMPTS = [
1677
- {
1678
- name: "analyze-drawing",
1679
- description: "\u5206\u6790\u5F53\u524D\u56FE\u7EB8\u7EDF\u8BA1\u4FE1\u606F",
1680
- arguments: []
1681
- },
1682
- {
1683
- name: "batch-draw-lines",
1684
- description: "\u6279\u91CF\u7ED8\u5236\u7EBF\u6BB5",
1685
- arguments: [
1686
- { name: "count", description: "\u7EBF\u6BB5\u6570\u91CF", required: true },
1687
- { name: "length", description: "\u7EBF\u6BB5\u957F\u5EA6", required: false }
1688
- ]
1689
- },
1690
- {
1691
- name: "generate-dimension",
1692
- description: "\u751F\u6210\u5C3A\u5BF8\u6807\u6CE8",
1693
- arguments: [
1694
- { name: "style", description: "\u6807\u6CE8\u6837\u5F0F (horizontal/vertical/aligned)", required: false }
1695
- ]
1696
- },
1697
- {
1698
- name: "export-entities",
1699
- description: "\u5BFC\u51FA\u56FE\u7EB8\u5B9E\u4F53\u7EDF\u8BA1",
1700
- arguments: [
1701
- { name: "format", description: "\u5BFC\u51FA\u683C\u5F0F (json/list)", required: false }
1702
- ]
1703
- },
1704
- {
1705
- name: "manage-layers",
1706
- description: "\u56FE\u5C42\u7BA1\u7406\uFF1A\u521B\u5EFA\u3001\u51BB\u7ED3\u3001\u9501\u5B9A\u3001\u5220\u9664\u56FE\u5C42",
1707
- arguments: [
1708
- { name: "action", description: "\u64CD\u4F5C\u7C7B\u578B (list/freeze/lock/off/make/delete)", required: true },
1709
- { name: "layers", description: "\u56FE\u5C42\u540D\uFF0C\u591A\u4E2A\u7528\u9017\u53F7\u5206\u9694", required: false },
1710
- { name: "color", description: '\u56FE\u5C42\u989C\u8272 (ACI\u53F7\u6216RGB\u5982 "1,2,3")', required: false }
1711
- ]
1712
- },
1713
- {
1714
- name: "manage-blocks",
1715
- description: "\u5757\u64CD\u4F5C\uFF1A\u63D2\u5165\u5757\u3001\u5217\u51FA\u5757\u3001\u83B7\u53D6/\u8BBE\u7F6E\u5C5E\u6027",
1716
- arguments: [
1717
- { name: "action", description: "\u64CD\u4F5C\u7C7B\u578B (list/insert/attributes/dynprops)", required: true },
1718
- { name: "blockName", description: "\u5757\u540D", required: false },
1719
- { name: "insertPoint", description: '\u63D2\u5165\u70B9 "x,y"', required: false },
1720
- { name: "scale", description: "\u7F29\u653E\u6BD4\u4F8B", required: false }
1721
- ]
1722
- },
1723
- {
1724
- name: "curve-analysis",
1725
- description: "\u66F2\u7EBF\u5206\u6790\uFF1A\u4EA4\u70B9\u3001\u6700\u8FD1\u70B9\u3001\u5B50\u6BB5\u3001\u7F13\u51B2\u533A",
1726
- arguments: [
1727
- { name: "action", description: "\u64CD\u4F5C (inters/subsegments/closestpoint/join)", required: true },
1728
- { name: "distance", description: "\u8FDE\u63A5\u5BB9\u5DEE/\u504F\u79FB\u8DDD\u79BB", required: false }
1729
- ]
1730
- },
1731
- {
1732
- name: "geometry-calc",
1733
- description: "\u51E0\u4F55\u8BA1\u7B97\uFF1A\u51F8\u5305\u3001\u70B9\u5230\u7EBF\u8DDD\u79BB\u3001\u9762\u5185\u6D4B\u8BD5\u3001\u53D8\u6362",
1734
- arguments: [
1735
- { name: "action", description: "\u64CD\u4F5C (convexhull/dist-point-line/in-curve-p/transform/centroid)", required: true },
1736
- { name: "points", description: '\u70B9\u96C6 "x1,y1;x2,y2;..."', required: false }
1737
- ]
1738
- },
1739
- {
1740
- name: "text-process",
1741
- description: "\u6587\u672C\u5904\u7406\uFF1AMTEXT\u89E3\u6790\u3001Markdown\u8F6CMTEXT\u3001\u53BB\u683C\u5F0F",
1742
- arguments: [
1743
- { name: "action", description: "\u64CD\u4F5C (parse-mtext/remove-fmt/from-markdown/mtext2text)", required: true },
1744
- { name: "markdown", description: "Markdown\u6587\u672C\uFF08from-markdown\u64CD\u4F5C\u65F6\u7528\uFF09", required: false }
1745
- ]
1746
- },
1747
- {
1748
- name: "pickset-filter",
1749
- description: "\u9009\u62E9\u96C6\u64CD\u4F5C\uFF1A\u8FC7\u6EE4\u3001\u8F6C\u6362\u3001\u6279\u91CF\u64CD\u4F5C",
1750
- arguments: [
1751
- { name: "action", description: "\u64CD\u4F5C (by-layer/by-type/by-box/erase/zoom)", required: true },
1752
- { name: "dxfType", description: 'DXF\u7C7B\u578B "LINE, CIRCLE, LWPOLYLINE, INSERT, TEXT"', required: false },
1753
- { name: "layerName", description: "\u56FE\u5C42\u540D", required: false }
1754
- ]
1755
- },
1756
- {
1757
- name: "color-convert",
1758
- description: "\u989C\u8272\u8F6C\u6362\uFF1AACI/RGB/TrueColor/CSS\u4E92\u8F6C",
1759
- arguments: [
1760
- { name: "action", description: "\u64CD\u4F5C (aci2rgb/rgb2css/truecolor2rgb/rgb2truecolor)", required: true },
1761
- { name: "value", description: "\u989C\u8272\u503C", required: true }
1762
- ]
1763
- },
1764
- {
1765
- name: "json-exchange",
1766
- description: "JSON\u6570\u636E\u4EA4\u6362\uFF1A\u4ECE\u5B57\u7B26\u4E32\u89E3\u6790JSON alist\uFF0C\u4ECEalist\u751F\u6210JSON",
1767
- arguments: [
1768
- { name: "action", description: "\u64CD\u4F5C (encode/decode)", required: true },
1769
- { name: "data", description: "JSON\u5B57\u7B26\u4E32\u6216Lisp alist\u6587\u672C", required: true }
1770
- ]
1771
- },
1772
- {
1773
- name: "excel-report",
1774
- description: "Excel\u62A5\u8868\uFF1A\u5BFC\u51FACAD\u5B9E\u4F53\u6570\u636E\u5230Excel",
1775
- arguments: [
1776
- { name: "visible", description: "\u662F\u5426\u663E\u793AExcel\u7A97\u53E3 (true/false)", required: false },
1777
- { name: "savePath", description: "\u4FDD\u5B58\u8DEF\u5F84\uFF0C\u4E0D\u586B\u5219\u4E0D\u4FDD\u5B58", required: false }
1778
- ]
1779
- },
1780
- {
1781
- name: "string-process",
1782
- description: "\u5B57\u7B26\u4E32\u5904\u7406\uFF1A\u683C\u5F0F\u5316\u3001\u62C6\u5206\u3001\u66FF\u6362\u3001\u6B63\u5219",
1783
- arguments: [
1784
- { name: "action", description: "\u64CD\u4F5C (format/split/subst-all/regexp/trim/number2chinese)", required: true },
1785
- { name: "input", description: "\u8F93\u5165\u5B57\u7B26\u4E32", required: true },
1786
- { name: "arg1", description: "\u53C2\u65701\uFF08\u683C\u5F0F\u53C2\u6570/\u5206\u9694\u7B26/\u65E7\u4E32\uFF09", required: false },
1787
- { name: "arg2", description: "\u53C2\u65702\uFF08\u65B0\u4E32/\u6B63\u5219\u6A21\u5F0F\uFF09", required: false }
1788
- ]
1789
- }
1790
- ];
1791
1596
  function findExternalPrompt(name) {
1792
1597
  const ext = loadExternalPrompts();
1793
1598
  return ext.find((p) => p.name === name);
@@ -1885,14 +1690,10 @@ ${generateSuggestions(entities, layers)}`
1885
1690
  }
1886
1691
  function generateSuggestions(entities, layers) {
1887
1692
  const suggestions = [];
1888
- if (entities.total > 1e3)
1889
- suggestions.push("- \u56FE\u7EB8\u5B9E\u4F53\u8F83\u591A\uFF0C\u5EFA\u8BAE\u4F7F\u7528\u56FE\u5C42\u5206\u7C7B\u7BA1\u7406");
1890
- if (layers.length > 20)
1891
- suggestions.push("- \u56FE\u5C42\u8F83\u591A\uFF0C\u5EFA\u8BAE\u6E05\u7406\u672A\u4F7F\u7528\u7684\u56FE\u5C42");
1892
- if (entities.byType.LINE && entities.byType.LINE > 500)
1893
- suggestions.push("- \u7EBF\u6761\u8F83\u591A\uFF0C\u53EF\u8003\u8651\u4F7F\u7528 BLOCK \u51CF\u5C11\u5B9E\u4F53\u6570\u91CF");
1894
- if (!entities.byType.DIMENSION)
1895
- suggestions.push("- \u672A\u53D1\u73B0\u5C3A\u5BF8\u6807\u6CE8\uFF0C\u5EFA\u8BAE\u6DFB\u52A0\u6807\u6CE8");
1693
+ if (entities.total > 1e3) suggestions.push("- \u56FE\u7EB8\u5B9E\u4F53\u8F83\u591A\uFF0C\u5EFA\u8BAE\u4F7F\u7528\u56FE\u5C42\u5206\u7C7B\u7BA1\u7406");
1694
+ if (layers.length > 20) suggestions.push("- \u56FE\u5C42\u8F83\u591A\uFF0C\u5EFA\u8BAE\u6E05\u7406\u672A\u4F7F\u7528\u7684\u56FE\u5C42");
1695
+ if (entities.byType.LINE && entities.byType.LINE > 500) suggestions.push("- \u7EBF\u6761\u8F83\u591A\uFF0C\u53EF\u8003\u8651\u4F7F\u7528 BLOCK \u51CF\u5C11\u5B9E\u4F53\u6570\u91CF");
1696
+ if (!entities.byType.DIMENSION) suggestions.push("- \u672A\u53D1\u73B0\u5C3A\u5BF8\u6807\u6CE8\uFF0C\u5EFA\u8BAE\u6DFB\u52A0\u6807\u6CE8");
1896
1697
  return suggestions.length ? suggestions.join("\n") : "- \u56FE\u7EB8\u7ED3\u6784\u826F\u597D";
1897
1698
  }
1898
1699
  async function generateBatchLinesPrompt(args) {
@@ -2408,86 +2209,215 @@ ${code}
2408
2209
  }]
2409
2210
  };
2410
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
+ });
2411
2338
 
2412
2339
  // src/session-manager.js
2413
- var Session = class {
2414
- constructor(clientId) {
2415
- this.clientId = clientId;
2416
- this.subscriptions = /* @__PURE__ */ new Set();
2417
- this.createdAt = Date.now();
2418
- this.connected = false;
2419
- }
2420
- };
2421
- var SessionManager = class {
2422
- #sessions = /* @__PURE__ */ new Map();
2423
- createSession(clientId) {
2424
- let session = this.#sessions.get(clientId);
2425
- if (!session) {
2426
- session = new Session(clientId);
2427
- this.#sessions.set(clientId, session);
2428
- }
2429
- return session;
2430
- }
2431
- getSession(clientId) {
2432
- return this.#sessions.get(clientId) || null;
2433
- }
2434
- hasSession(clientId) {
2435
- return this.#sessions.has(clientId);
2436
- }
2437
- removeSession(clientId) {
2438
- return this.#sessions.delete(clientId);
2439
- }
2440
- subscribe(clientId, uri) {
2441
- const session = this.#sessions.get(clientId);
2442
- if (session) {
2443
- session.subscriptions.add(uri);
2444
- return true;
2445
- }
2446
- return false;
2447
- }
2448
- unsubscribe(clientId, uri) {
2449
- const session = this.#sessions.get(clientId);
2450
- if (session) {
2451
- return session.subscriptions.delete(uri);
2452
- }
2453
- return false;
2454
- }
2455
- getSubscriptions(clientId) {
2456
- const session = this.#sessions.get(clientId);
2457
- return session ? Array.from(session.subscriptions) : [];
2458
- }
2459
- isSubscribed(clientId, uri) {
2460
- const session = this.#sessions.get(clientId);
2461
- return session ? session.subscriptions.has(uri) : false;
2462
- }
2463
- getAllSubscribedUris() {
2464
- const all = /* @__PURE__ */ new Set();
2465
- for (const session of this.#sessions.values()) {
2466
- for (const uri of session.subscriptions) {
2467
- 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;
2468
2349
  }
2469
- }
2470
- return all;
2471
- }
2472
- list() {
2473
- return Array.from(this.#sessions.entries()).map(([id, s]) => ({
2474
- clientId: id,
2475
- subscriptions: Array.from(s.subscriptions),
2476
- createdAt: s.createdAt,
2477
- connected: s.connected
2478
- }));
2479
- }
2480
- count() {
2481
- return this.#sessions.size;
2482
- }
2483
- clear() {
2484
- this.#sessions.clear();
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
+ };
2485
2417
  }
2486
- };
2418
+ });
2487
2419
 
2488
2420
  // src/subscription-manager.js
2489
- var sessionManager = new SessionManager();
2490
- var _notifyFn = null;
2491
2421
  function setNotify(fn) {
2492
2422
  _notifyFn = fn;
2493
2423
  }
@@ -2520,242 +2450,250 @@ function notify(uri, data) {
2520
2450
  _notifyFn(uri, data);
2521
2451
  }
2522
2452
  }
2523
-
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
+ });
2461
+
2524
2462
  // src/sse-session.js
2525
- import { randomUUID as randomUUID3 } from "crypto";
2526
- var DEFAULT_HEARTBEAT_INTERVAL = 3e4;
2527
- var DEFAULT_RETRY_INTERVAL = 3e4;
2528
- var MAX_SENT_MESSAGES = 1e3;
2529
- var SSE_EVENTS = {
2530
- MESSAGE: "message",
2531
- ENDPOINT: "endpoint",
2532
- PING: "ping",
2533
- ERROR: "error",
2534
- PROGRESS: "progress",
2535
- CAPABILITIES: "capabilities"
2536
- };
2537
- var SseSession = class {
2538
- #res;
2539
- #clientId;
2540
- #active = true;
2541
- #heartbeatTimer = null;
2542
- #lastEventId = 0;
2543
- #heartbeatInterval;
2544
- #retryInterval;
2545
- #sessionData = {};
2546
- #sentMessages = [];
2547
- #backpressureBuffer = [];
2548
- #drainHandler = null;
2549
- constructor(res, options = {}) {
2550
- this.#res = res;
2551
- this.#clientId = options.clientId || randomUUID3();
2552
- this.#heartbeatInterval = options.heartbeatInterval || DEFAULT_HEARTBEAT_INTERVAL;
2553
- this.#retryInterval = options.retryInterval || DEFAULT_RETRY_INTERVAL;
2554
- this.#sessionData = options.sessionData || {};
2555
- if (options.resumeFromId && options.resumeFromId > 0) {
2556
- this.#lastEventId = options.resumeFromId;
2557
- }
2558
- this._setupSseHeaders();
2559
- this._sendRetry();
2560
- this._setupDrain();
2561
- }
2562
- get clientId() {
2563
- return this.#clientId;
2564
- }
2565
- get isActive() {
2566
- return this.#active;
2567
- }
2568
- get lastEventId() {
2569
- return this.#lastEventId;
2570
- }
2571
- get sessionData() {
2572
- return this.#sessionData;
2573
- }
2574
- get sentMessages() {
2575
- return [...this.#sentMessages];
2576
- }
2577
- getMessagesSince(eventId) {
2578
- return this.#sentMessages.filter((m) => m.id > eventId);
2579
- }
2580
- setSessionData(key, value) {
2581
- this.#sessionData[key] = value;
2582
- }
2583
- getSessionData(key) {
2584
- return this.#sessionData[key];
2585
- }
2586
- get retryInterval() {
2587
- return this.#retryInterval;
2588
- }
2589
- setRetryInterval(ms) {
2590
- this.#retryInterval = ms;
2591
- }
2592
- _sendRetry() {
2593
- this._write(`retry: ${this.#retryInterval}
2463
+ import { randomUUID as randomUUID2 } from "crypto";
2464
+ var DEFAULT_HEARTBEAT_INTERVAL, DEFAULT_RETRY_INTERVAL, MAX_SENT_MESSAGES, SSE_EVENTS, SseSession;
2465
+ var init_sse_session = __esm({
2466
+ "src/sse-session.js"() {
2467
+ DEFAULT_HEARTBEAT_INTERVAL = 3e4;
2468
+ DEFAULT_RETRY_INTERVAL = 3e4;
2469
+ MAX_SENT_MESSAGES = 1e3;
2470
+ SSE_EVENTS = {
2471
+ MESSAGE: "message",
2472
+ ENDPOINT: "endpoint",
2473
+ PING: "ping",
2474
+ ERROR: "error",
2475
+ PROGRESS: "progress",
2476
+ CAPABILITIES: "capabilities"
2477
+ };
2478
+ SseSession = class {
2479
+ #res;
2480
+ #clientId;
2481
+ #active = true;
2482
+ #heartbeatTimer = null;
2483
+ #lastEventId = 0;
2484
+ #heartbeatInterval;
2485
+ #retryInterval;
2486
+ #sessionData = {};
2487
+ #sentMessages = [];
2488
+ #backpressureBuffer = [];
2489
+ #drainHandler = null;
2490
+ constructor(res, options = {}) {
2491
+ this.#res = res;
2492
+ this.#clientId = options.clientId || randomUUID2();
2493
+ this.#heartbeatInterval = options.heartbeatInterval || DEFAULT_HEARTBEAT_INTERVAL;
2494
+ this.#retryInterval = options.retryInterval || DEFAULT_RETRY_INTERVAL;
2495
+ this.#sessionData = options.sessionData || {};
2496
+ if (options.resumeFromId && options.resumeFromId > 0) {
2497
+ this.#lastEventId = options.resumeFromId;
2498
+ }
2499
+ this._setupSseHeaders();
2500
+ this._sendRetry();
2501
+ this._setupDrain();
2502
+ }
2503
+ get clientId() {
2504
+ return this.#clientId;
2505
+ }
2506
+ get isActive() {
2507
+ return this.#active;
2508
+ }
2509
+ get lastEventId() {
2510
+ return this.#lastEventId;
2511
+ }
2512
+ get sessionData() {
2513
+ return this.#sessionData;
2514
+ }
2515
+ get sentMessages() {
2516
+ return [...this.#sentMessages];
2517
+ }
2518
+ getMessagesSince(eventId) {
2519
+ return this.#sentMessages.filter((m) => m.id > eventId);
2520
+ }
2521
+ setSessionData(key, value) {
2522
+ this.#sessionData[key] = value;
2523
+ }
2524
+ getSessionData(key) {
2525
+ return this.#sessionData[key];
2526
+ }
2527
+ get retryInterval() {
2528
+ return this.#retryInterval;
2529
+ }
2530
+ setRetryInterval(ms) {
2531
+ this.#retryInterval = ms;
2532
+ }
2533
+ _sendRetry() {
2534
+ this._write(`retry: ${this.#retryInterval}
2594
2535
 
2595
2536
  `);
2596
- }
2597
- _setupSseHeaders() {
2598
- this.#res.setHeader("Content-Type", "text/event-stream");
2599
- this.#res.setHeader("Cache-Control", "no-cache");
2600
- this.#res.setHeader("Connection", "keep-alive");
2601
- this.#res.setHeader("Transfer-Encoding", "chunked");
2602
- this.#res.setHeader("X-Accel-Buffering", "no");
2603
- if (typeof this.#res.flush !== "function") {
2604
- this.#res.flush = () => {
2605
- };
2606
- }
2607
- }
2608
- _formatEvent(event, data, id = null) {
2609
- const lines = [];
2610
- if (id !== null) {
2611
- lines.push(`id: ${id}`);
2612
- }
2613
- lines.push(`event: ${event}`);
2614
- if (data !== null && data !== void 0) {
2615
- const jsonStr = JSON.stringify(data);
2616
- lines.push(`data: ${jsonStr}`);
2617
- } else {
2618
- lines.push("data:");
2619
- }
2620
- return lines.join("\n") + "\n\n";
2621
- }
2622
- _setupDrain() {
2623
- if (typeof this.#res.on !== "function")
2624
- return;
2625
- this.#drainHandler = () => {
2626
- if (!this.#active)
2627
- return;
2628
- if (this.#backpressureBuffer.length > 0) {
2629
- this._drainBuffer();
2630
2537
  }
2631
- };
2632
- this.#res.on("drain", this.#drainHandler);
2633
- }
2634
- _drainBuffer() {
2635
- const batch = this.#backpressureBuffer.splice(0, 50);
2636
- for (const item of batch) {
2637
- const ok = this.#res.write(item);
2638
- if (!ok) {
2639
- this.#backpressureBuffer.unshift(...batch.slice(batch.indexOf(item)));
2640
- return;
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
+ }
2641
2548
  }
2642
- }
2643
- this._flush();
2644
- if (this.#backpressureBuffer.length > 0) {
2645
- this._drainBuffer();
2646
- }
2647
- }
2648
- _write(content) {
2649
- if (!this.#active)
2650
- return false;
2651
- try {
2652
- if (this.#backpressureBuffer.length > 0) {
2653
- this.#backpressureBuffer.push(content);
2654
- return true;
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
+ }
2655
2586
  }
2656
- const result = this.#res.write(content);
2657
- if (typeof this.#res.flush === "function") {
2658
- this.#res.flush();
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
+ }
2659
2608
  }
2660
- if (result === false) {
2661
- this.#backpressureBuffer.push(content);
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();
2662
2632
  return true;
2663
2633
  }
2664
- return true;
2665
- } catch (e) {
2666
- this.#active = false;
2667
- this.close();
2668
- return false;
2669
- }
2670
- }
2671
- _flush() {
2672
- try {
2673
- if (typeof this.#res.flush === "function") {
2674
- this.#res.flush();
2634
+ sendMessage(data) {
2635
+ return this.sendEvent(SSE_EVENTS.MESSAGE, data);
2675
2636
  }
2676
- } catch (e) {
2677
- }
2678
- }
2679
- flushBackpressure() {
2680
- if (this.#backpressureBuffer.length > 0) {
2681
- this._drainBuffer();
2682
- }
2683
- }
2684
- sendEvent(event, data, id = null) {
2685
- this.#lastEventId++;
2686
- const eventId = id !== null ? id : this.#lastEventId;
2687
- const formatted = this._formatEvent(event, data, eventId);
2688
- this.#sentMessages.push({ event, data, id: eventId, timestamp: Date.now() });
2689
- if (this.#sentMessages.length > MAX_SENT_MESSAGES) {
2690
- this.#sentMessages.splice(0, this.#sentMessages.length - MAX_SENT_MESSAGES);
2691
- }
2692
- this._write(formatted);
2693
- this._flush();
2694
- return true;
2695
- }
2696
- sendMessage(data) {
2697
- return this.sendEvent(SSE_EVENTS.MESSAGE, data);
2698
- }
2699
- sendEndpoint(path8) {
2700
- return this.sendEvent(SSE_EVENTS.ENDPOINT, path8);
2701
- }
2702
- sendError(code, message, id = null) {
2703
- return this.sendEvent(SSE_EVENTS.ERROR, { code, message }, id);
2704
- }
2705
- sendPing() {
2706
- return this.sendEvent(SSE_EVENTS.PING, { timestamp: Date.now() });
2707
- }
2708
- sendProgress(current, total, message = "") {
2709
- return this.sendEvent(SSE_EVENTS.PROGRESS, { current, total, message });
2710
- }
2711
- sendCapabilities(capabilities) {
2712
- return this.sendEvent(SSE_EVENTS.CAPABILITIES, capabilities);
2713
- }
2714
- sendResponse(jsonrpcResponse, id = null) {
2715
- const eventId = id !== null ? id : this.#lastEventId;
2716
- return this.sendEvent(SSE_EVENTS.MESSAGE, jsonrpcResponse, eventId);
2717
- }
2718
- startHeartbeat(interval = null) {
2719
- this.stopHeartbeat();
2720
- const ms = interval || this.#heartbeatInterval;
2721
- this.#heartbeatTimer = setInterval(() => {
2722
- if (!this.#active) {
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) {
2723
2657
  this.stopHeartbeat();
2724
- return;
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);
2725
2669
  }
2726
- if (!this.sendPing()) {
2670
+ stopHeartbeat() {
2671
+ if (this.#heartbeatTimer) {
2672
+ clearInterval(this.#heartbeatTimer);
2673
+ this.#heartbeatTimer = null;
2674
+ }
2675
+ }
2676
+ close() {
2677
+ this.#active = false;
2727
2678
  this.stopHeartbeat();
2728
- this.close();
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
+ }
2729
2688
  }
2730
- }, ms);
2731
- }
2732
- stopHeartbeat() {
2733
- if (this.#heartbeatTimer) {
2734
- clearInterval(this.#heartbeatTimer);
2735
- this.#heartbeatTimer = null;
2736
- }
2737
- }
2738
- close() {
2739
- this.#active = false;
2740
- this.stopHeartbeat();
2741
- if (this.#drainHandler) {
2742
- this.#res.removeListener("drain", this.#drainHandler);
2743
- this.#drainHandler = null;
2744
- }
2745
- this.#backpressureBuffer = [];
2746
- try {
2747
- this.#res.end();
2748
- } catch (e) {
2749
- }
2689
+ };
2750
2690
  }
2751
- };
2691
+ });
2752
2692
 
2753
2693
  // src/sse-session-manager.js
2754
2694
  import fs5 from "fs";
2755
2695
  import path6 from "path";
2756
2696
  import os3 from "os";
2757
- var SESSION_STORE_DIR = path6.join(os3.homedir(), ".atlisp", "sessions");
2758
- var SESSION_STORE_TTL = 24 * 60 * 60 * 1e3;
2759
2697
  function getSessionStorePath(clientId) {
2760
2698
  return path6.join(SESSION_STORE_DIR, `${clientId}.json`);
2761
2699
  }
@@ -2775,8 +2713,7 @@ function persistSessionData(clientId, sessionData) {
2775
2713
  function loadPersistedSessionData(clientId) {
2776
2714
  try {
2777
2715
  const filePath = getSessionStorePath(clientId);
2778
- if (!fs5.existsSync(filePath))
2779
- return null;
2716
+ if (!fs5.existsSync(filePath)) return null;
2780
2717
  const raw = fs5.readFileSync(filePath, "utf-8");
2781
2718
  const store = JSON.parse(raw);
2782
2719
  if (Date.now() - store.savedAt > SESSION_STORE_TTL) {
@@ -2788,200 +2725,571 @@ function loadPersistedSessionData(clientId) {
2788
2725
  return null;
2789
2726
  }
2790
2727
  }
2791
- var SseSessionManager = class {
2792
- #sessions = /* @__PURE__ */ new Map();
2793
- #eventHandlers = /* @__PURE__ */ new Map();
2794
- constructor() {
2795
- this.#sessions = /* @__PURE__ */ new Map();
2796
- this.#eventHandlers = /* @__PURE__ */ new Map();
2797
- }
2798
- add(clientId, session) {
2799
- if (!(session instanceof SseSession)) {
2800
- throw new Error("session must be an SseSession instance");
2801
- }
2802
- const persisted = loadPersistedSessionData(clientId);
2803
- if (persisted) {
2804
- for (const [key, value] of Object.entries(persisted)) {
2805
- session.setSessionData(key, value);
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;
2806
2763
  }
2807
- }
2808
- this.#sessions.set(clientId, session);
2809
- session.startHeartbeat();
2810
- }
2811
- remove(clientId) {
2812
- const session = this.#sessions.get(clientId);
2813
- if (session) {
2814
- persistSessionData(clientId, session.sessionData);
2815
- session.close();
2816
- this.#sessions.delete(clientId);
2817
- return true;
2818
- }
2819
- return false;
2820
- }
2821
- get(clientId) {
2822
- return this.#sessions.get(clientId) || null;
2823
- }
2824
- has(clientId) {
2825
- return this.#sessions.has(clientId);
2826
- }
2827
- list() {
2828
- return Array.from(this.#sessions.keys()).map((id) => ({
2829
- clientId: id,
2830
- isActive: this.#sessions.get(id)?.isActive ?? false
2831
- }));
2832
- }
2833
- listActive() {
2834
- return this.list().filter((s) => s.isActive);
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
+ };
2835
2852
  }
2836
- count() {
2837
- return this.#sessions.size;
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
+ };
2838
2934
  }
2839
- sendToClient(clientId, event, data, id = null) {
2840
- const session = this.#sessions.get(clientId);
2841
- if (!session || !session.isActive) {
2842
- return false;
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
+ };
2843
2985
  }
2844
- return session.sendEvent(event, data, id);
2845
- }
2846
- sendMessageToClient(clientId, data) {
2847
- return this.sendToClient(clientId, SSE_EVENTS.MESSAGE, data);
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
+ };
2848
3021
  }
2849
- sendErrorToClient(clientId, code, message, id = null) {
2850
- return this.sendToClient(clientId, SSE_EVENTS.ERROR, { code, message }, id);
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 };
2851
3030
  }
2852
- sendProgressToClient(clientId, current, total, message = "") {
2853
- return this.sendToClient(clientId, SSE_EVENTS.PROGRESS, { current, total, message });
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);
2854
3039
  }
2855
- broadcast(event, data) {
2856
- let successCount = 0;
2857
- for (const [clientId, session] of this.#sessions) {
2858
- if (session.isActive && session.sendEvent(event, data)) {
2859
- successCount++;
2860
- }
2861
- }
2862
- return successCount;
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);
2863
3055
  }
2864
- broadcastMessage(data) {
2865
- return this.broadcast(SSE_EVENTS.MESSAGE, data);
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
+ });
2866
3062
  }
2867
- broadcastError(code, message) {
2868
- return this.broadcast(SSE_EVENTS.ERROR, { code, message });
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;
2869
3074
  }
2870
- on(event, handler) {
2871
- if (!this.#eventHandlers.has(event)) {
2872
- this.#eventHandlers.set(event, /* @__PURE__ */ new Set());
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 });
2873
3105
  }
2874
- this.#eventHandlers.get(event).add(handler);
2875
- }
2876
- off(event, handler) {
2877
- const handlers = this.#eventHandlers.get(event);
2878
- if (handlers) {
2879
- handlers.delete(handler);
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" });
2880
3122
  }
2881
- }
2882
- emit(event, data) {
2883
- const handlers = this.#eventHandlers.get(event);
2884
- if (handlers) {
2885
- for (const handler of handlers) {
2886
- try {
2887
- handler(data);
2888
- } catch (e) {
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();
2889
3195
  }
2890
3196
  }
2891
- }
2892
- }
2893
- cleanupInactive() {
2894
- for (const [clientId, session] of this.#sessions) {
2895
- if (!session.isActive) {
2896
- session.close();
2897
- 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 });
2898
3201
  }
2899
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" });
2900
3221
  }
2901
- closeAll() {
2902
- for (const [clientId, session] of this.#sessions) {
2903
- persistSessionData(clientId, session.sessionData);
2904
- session.close();
3222
+ const sseSession = sseSessionManager.get(sessionId);
3223
+ if (!sseSession) {
3224
+ return res.status(404).json({ error: "Session not found" });
3225
+ }
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
+ }
2905
3244
  }
2906
- this.#sessions.clear();
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"];
2907
3269
  }
2908
- };
3270
+ });
2909
3271
 
2910
3272
  // src/atlisp-mcp.js
2911
- var __dirname4 = path7.dirname(fileURLToPath4(import.meta.url));
2912
- var require2 = createRequire(import.meta.url);
2913
- var { version } = require2(path7.join(__dirname4, "..", "package.json"));
2914
- var CACHE_DIR2 = path7.join(os4.homedir(), ".atlisp", "cache");
2915
- var FUNCLIB_CACHE_FILE2 = path7.join(CACHE_DIR2, "functions.json");
2916
- var FUNCLIB_CACHE_TTL2 = 24 * 60 * 60 * 1e3;
2917
- var isMcpScript = process.argv[1]?.includes("atlisp-mcp");
2918
- if (isMcpScript) {
2919
- const args = process.argv.slice(2);
2920
- for (let i = 0; i < args.length; i++) {
2921
- if (args[i] === "--version" || args[i] === "-v") {
2922
- console.log(`atlisp-mcp v${version}`);
2923
- process.exit(0);
2924
- } else if (args[i] === "--help" || args[i] === "-h") {
2925
- console.log(`
2926
- @lisp MCP Server v${version}
2927
-
2928
- Usage: atlisp-mcp [options]
2929
-
2930
- Options:
2931
- -v, --version Show version number
2932
- --transport <type> Transport type: http or stdio (default: http)
2933
- --port <port> HTTP port (default: 8110)
2934
- --host <host> HTTP host (default: 0.0.0.0)
2935
- --stdio Shorthand for --transport stdio
2936
- -h, --help Show this help message
2937
-
2938
- Examples:
2939
- atlisp-mcp # Start HTTP server on port 8110
2940
- atlisp-mcp --port 3000 # Start HTTP server on port 3000
2941
- atlisp-mcp --stdio # Start in stdio mode for MCP clients
2942
- atlisp-mcp --transport stdio # Same as --stdio
2943
- `);
2944
- process.exit(0);
2945
- } else if (args[i] === "--transport" && args[i + 1]) {
2946
- process.env.TRANSPORT = args[i + 1];
2947
- i++;
2948
- } else if (args[i] === "--stdio") {
2949
- process.env.TRANSPORT = "stdio";
2950
- } else if (args[i] === "--port" && args[i + 1]) {
2951
- process.env.PORT = args[i + 1];
2952
- i++;
2953
- } else if (args[i] === "--host" && args[i + 1]) {
2954
- process.env.HOST = args[i + 1];
2955
- i++;
2956
- }
2957
- }
2958
- }
2959
- var { decode: charsetDecode, encodingExists } = iconv;
2960
- var mcpContext = new AsyncLocalStorage();
2961
- var sseSessionManager = new SseSessionManager();
2962
- var SERVER_CAPABILITIES = {
2963
- tools: {},
2964
- resources: { subscribe: true, listChanged: true },
2965
- prompts: {}
2966
- };
2967
- var { port, host, transport, apiKey, rateLimitWindow, rateLimitMax } = config_default;
2968
- if (apiKey)
2969
- log("API Key authentication enabled");
2970
- var mcpLimiter = rateLimit({
2971
- windowMs: rateLimitWindow,
2972
- max: rateLimitMax,
2973
- standardHeaders: true,
2974
- legacyHeaders: false,
2975
- 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
2976
3281
  });
2977
- var FUNCTION_LIB_URL = process.env.FUNCTION_LIB_URL || "http://s3.atlisp.cn/json/functions.json";
2978
- var cachedFunctionLib = null;
2979
- var cachedAt2 = null;
2980
- var CACHE_TTL3 = 5 * 60 * 1e3;
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";
2981
3289
  async function readCacheFromDisk2() {
2982
3290
  try {
2983
3291
  const stat = fs6.statSync(FUNCLIB_CACHE_FILE2);
2984
- if (Date.now() - stat.mtimeMs < FUNCLIB_CACHE_TTL2) {
3292
+ if (Date.now() - stat.mtimeMs < CACHE_TTL3) {
2985
3293
  const raw = fs6.readFileSync(FUNCLIB_CACHE_FILE2, "utf-8");
2986
3294
  return JSON.parse(raw);
2987
3295
  }
@@ -2994,7 +3302,7 @@ function writeCacheToDisk2(data) {
2994
3302
  fs6.mkdirSync(CACHE_DIR2, { recursive: true });
2995
3303
  fs6.writeFileSync(FUNCLIB_CACHE_FILE2, JSON.stringify(data), "utf-8");
2996
3304
  } catch (e) {
2997
- log(`writeCacheToDisk error: ${e.message}`);
3305
+ error(`writeCacheToDisk error: ${e.message}`);
2998
3306
  }
2999
3307
  }
3000
3308
  async function loadAtlibFunctionLib() {
@@ -3018,237 +3326,31 @@ async function loadAtlibFunctionLib() {
3018
3326
  return data;
3019
3327
  }
3020
3328
  } catch (e) {
3021
- log(`loadAtlibFunctionLib error: ${e.message}`);
3329
+ error(`loadAtlibFunctionLib error: ${e.message}`);
3022
3330
  }
3023
3331
  return cachedFunctionLib;
3024
3332
  }
3025
- var TOOL_HANDLERS = {
3026
- connect_cad: (a) => connectCad(a?.platform),
3027
- eval_lisp: (a) => evalLisp(a.code),
3028
- eval_lisp_with_result: (a) => evalLisp(a.code, true, a.encoding),
3029
- get_cad_info: () => getCadInfo(),
3030
- list_packages: () => listPackages(),
3031
- search_packages: (a) => searchPackages(a.query),
3032
- install_package: (a) => installPackage(a.packageName),
3033
- get_platform_info: () => ({ content: [{ type: "text", text: `\u652F\u6301\u7684 CAD \u5E73\u53F0:
3034
- ${CAD_PLATFORMS.join("\n")}
3035
- \u5F53\u524D\u8FDE\u63A5: ${cad.connected ? "\u5DF2\u8FDE\u63A5" : "\u672A\u8FDE\u63A5"}` }] }),
3036
- at_command: (a) => atCommand(a.command),
3037
- new_document: () => newDocument(),
3038
- bring_to_front: () => bringToFront(),
3039
- install_atlisp: () => installAtlisp(),
3040
- init_atlisp: () => initAtlisp(),
3041
- get_function_usage: (a) => getFunctionUsage(a.name, a.package),
3042
- list_symbols: (a) => listSymbols(a.package),
3043
- get_system_status: () => getSystemStatus(),
3044
- list_prompts: async () => {
3045
- const prompts = await listPrompts();
3046
- return { content: [{ type: "text", text: JSON.stringify(prompts) }] };
3047
- },
3048
- get_prompt: async (a) => {
3049
- const prompt = await getPrompt(a.name, a.args || {});
3050
- return { content: prompt.messages.map((m) => ({ type: "text", text: m.content.text || m.content })) };
3051
- },
3052
- import_funlib: async (a) => {
3053
- const data = await loadAtlibFunctionLib();
3054
- if (!data)
3055
- return { content: [{ type: "text", text: "\u52A0\u8F7D\u51FD\u6570\u5E93\u5931\u8D25" }], isError: true };
3056
- if (a.format === "list") {
3057
- const items = Object.values(data.all_functions || {}).map((f) => `${f.name}: ${f.description || ""}`);
3058
- return { content: [{ type: "text", text: items.join("\n") }] };
3059
- }
3060
- return { content: [{ type: "text", text: JSON.stringify(data, null, 2) }] };
3061
- }
3062
- };
3063
- function getOrCreateSessionServer(sessionId) {
3064
- let entry = sessionServers.get(sessionId);
3065
- if (!entry) {
3066
- const server = createMcpServer();
3067
- const transport2 = new SessionTransport(sessionId);
3068
- server.connect(transport2);
3069
- entry = { server, transport: transport2 };
3070
- sessionServers.set(sessionId, entry);
3071
- sessionTransports.set(sessionId, transport2);
3072
- }
3073
- return entry;
3074
- }
3075
- function removeSessionServer(sessionId) {
3076
- const entry = sessionServers.get(sessionId);
3077
- if (entry) {
3078
- entry.transport.close().catch(() => {
3079
- });
3080
- entry.server.close().catch(() => {
3081
- });
3082
- sessionServers.delete(sessionId);
3083
- sessionTransports.delete(sessionId);
3084
- }
3085
- }
3086
- function broadcastToAllSessions(uri) {
3087
- for (const [sid, entry] of sessionServers) {
3088
- entry.server.sendResourceUpdated({ uri }).catch((err) => {
3089
- log(`Failed to send resource update to session ${sid}: ${err.message}`);
3090
- });
3091
- }
3092
- }
3093
- var tools = [
3094
- {
3095
- name: "connect_cad",
3096
- description: "\u8FDE\u63A5\u5230 CAD (AutoCAD/ZWCAD/GStarCAD/BricsCAD)",
3097
- inputSchema: {
3098
- type: "object",
3099
- properties: {
3100
- platform: { type: "string", description: "\u6307\u5B9A CAD \u5E73\u53F0: AutoCAD, ZWCAD, GStarCAD, BricsCAD\uFF08\u53EF\u9009\uFF0C\u81EA\u52A8\u68C0\u6D4B\uFF09" }
3101
- }
3102
- }
3103
- },
3104
- {
3105
- name: "eval_lisp",
3106
- description: "\u5728 CAD \u4E2D\u6267\u884C AutoLISP \u4EE3\u7801\uFF08\u4E0D\u8FD4\u56DE\u7ED3\u679C\uFF09",
3107
- inputSchema: {
3108
- type: "object",
3109
- properties: { code: { type: "string", description: "\u8981\u6267\u884C\u7684 LISP \u4EE3\u7801" } },
3110
- required: ["code"]
3111
- }
3112
- },
3113
- {
3114
- name: "eval_lisp_with_result",
3115
- description: "\u5728 CAD \u4E2D\u6267\u884C AutoLISP \u4EE3\u7801\u5E76\u8FD4\u56DE\u7ED3\u679C",
3116
- inputSchema: {
3117
- type: "object",
3118
- properties: {
3119
- code: { type: "string", description: "\u8981\u6267\u884C\u7684 LISP \u4EE3\u7801" },
3120
- 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" }
3121
- },
3122
- required: ["code"]
3123
- }
3124
- },
3125
- {
3126
- name: "get_cad_info",
3127
- description: "\u83B7\u53D6\u5F53\u524D CAD \u4FE1\u606F",
3128
- inputSchema: { type: "object", properties: {} }
3129
- },
3130
- {
3131
- name: "list_packages",
3132
- description: "\u5217\u51FA\u5DF2\u5B89\u88C5\u7684 @lisp \u5305",
3133
- inputSchema: { type: "object", properties: {} }
3134
- },
3135
- {
3136
- name: "search_packages",
3137
- description: "\u641C\u7D22 @lisp \u5305",
3138
- inputSchema: {
3139
- type: "object",
3140
- properties: { query: { type: "string", description: "\u641C\u7D22\u5173\u952E\u8BCD" } },
3141
- required: ["query"]
3142
- }
3143
- },
3144
- {
3145
- name: "install_package",
3146
- description: "\u5B89\u88C5 @lisp \u5305\u5230 CAD",
3147
- inputSchema: {
3148
- type: "object",
3149
- properties: { packageName: { type: "string", description: "\u5305\u540D\u79F0" } },
3150
- required: ["packageName"]
3151
- }
3152
- },
3153
- {
3154
- name: "get_platform_info",
3155
- description: "\u83B7\u53D6 CAD \u5E73\u53F0\u4FE1\u606F",
3156
- inputSchema: { type: "object", properties: {} }
3157
- },
3158
- {
3159
- name: "at_command",
3160
- description: "\u6267\u884C @lisp \u547D\u4EE4",
3161
- inputSchema: {
3162
- type: "object",
3163
- properties: { command: { type: "string", description: "@lisp \u547D\u4EE4" } },
3164
- required: ["command"]
3165
- }
3166
- },
3167
- {
3168
- name: "new_document",
3169
- description: "\u5728 CAD \u4E2D\u65B0\u5EFA\u7A7A\u767D\u6587\u6863",
3170
- inputSchema: { type: "object", properties: {} }
3171
- },
3172
- {
3173
- name: "bring_to_front",
3174
- description: "\u5C06 CAD \u7A97\u53E3\u5207\u6362\u5230\u524D\u53F0\uFF08\u4ECE\u540E\u53F0\u8FD0\u884C\u72B6\u6001\u5524\u9192\uFF09",
3175
- inputSchema: { type: "object", properties: {} }
3176
- },
3177
- {
3178
- name: "install_atlisp",
3179
- description: "\u5728 CAD \u4E2D\u5B89\u88C5 @lisp",
3180
- inputSchema: { type: "object", properties: {} }
3181
- },
3182
- {
3183
- name: "init_atlisp",
3184
- description: "\u521D\u59CB\u5316 CAD \u4E2D\u7684 @lisp \u73AF\u5883\uFF0C\u52A0\u8F7D\u51FD\u6570\u5E93\u548C\u521D\u59CB\u53D8\u91CF",
3185
- inputSchema: { type: "object", properties: {} }
3186
- },
3187
- {
3188
- name: "get_function_usage",
3189
- description: "\u83B7\u53D6 @lisp \u51FD\u6570\u7528\u6CD5",
3190
- inputSchema: {
3191
- type: "object",
3192
- properties: {
3193
- name: { type: "string", description: "\u51FD\u6570\u540D\uFF0C\u5982 string:length" },
3194
- package: { type: "string", description: "\u5305\u540D\uFF0C\u5982 string\uFF08\u53EF\u9009\uFF0C\u4E0D\u4F20\u5219\u81EA\u52A8\u641C\u7D22\uFF09" }
3195
- },
3196
- required: ["name"]
3197
- }
3198
- },
3199
- {
3200
- name: "list_symbols",
3201
- description: "\u5217\u51FA @lisp \u6240\u6709\u7B26\u53F7\uFF0C\u7528\u4E8E\u68C0\u67E5\u51FD\u6570\u548C\u53D8\u91CF",
3202
- inputSchema: {
3203
- type: "object",
3204
- properties: {
3205
- package: { type: "string", description: "\u5305\u540D\uFF0C\u5982 string\uFF08\u53EF\u9009\uFF09" }
3206
- }
3207
- }
3208
- },
3209
- {
3210
- name: "import_funlib",
3211
- description: "\u4ECE\u7F51\u7EDC\u5BFC\u5165 @lisp \u51FD\u6570\u5E93\u6570\u636E\u5230 AI Agent",
3212
- inputSchema: {
3213
- type: "object",
3214
- properties: {
3215
- 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" }
3216
- }
3217
- }
3218
- },
3219
- {
3220
- name: "get_system_status",
3221
- description: "\u83B7\u53D6\u5B8C\u6574\u7CFB\u7EDF\u8BCA\u65AD\u4FE1\u606F\uFF1AMCP \u72B6\u6001\u3001CAD \u8FDE\u63A5\u3001Lisp \u6267\u884C\u3001\u5305\u5217\u8868",
3222
- inputSchema: { type: "object", properties: {} }
3223
- },
3224
- {
3225
- name: "list_prompts",
3226
- description: "\u5217\u51FA\u6240\u6709\u53EF\u7528\u7684 @lisp \u63D0\u793A\u6A21\u677F",
3227
- inputSchema: { type: "object", properties: {} }
3228
- },
3229
- {
3230
- name: "get_prompt",
3231
- description: "\u83B7\u53D6\u6307\u5B9A\u63D0\u793A\u6A21\u677F\u7684\u5185\u5BB9",
3232
- inputSchema: {
3233
- type: "object",
3234
- properties: {
3235
- name: { type: "string", description: "\u63D0\u793A\u6A21\u677F\u540D\u79F0" },
3236
- args: { type: "object", description: "\u6A21\u677F\u53C2\u6570\uFF08\u53EF\u9009\uFF09" }
3237
- },
3238
- 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}`);
3239
3340
  }
3240
3341
  }
3241
- ];
3342
+ return true;
3343
+ }
3242
3344
  async function handleToolCall(name, args) {
3243
3345
  const handler = TOOL_HANDLERS[name];
3244
- if (!handler)
3245
- return { content: [{ type: "text", text: `\u672A\u77E5\u5DE5\u5177: ${name}` }], isError: true };
3346
+ if (!handler) return { content: [{ type: "text", text: `\u672A\u77E5\u5DE5\u5177: ${name}` }], isError: true };
3246
3347
  try {
3348
+ validateToolArgs(name, args || {});
3247
3349
  const result = await handler(args || {});
3248
3350
  notifyResourceChanges(name);
3249
3351
  return result;
3250
3352
  } catch (e) {
3251
- log(`Tool call error [${name}]: ${e.message}`);
3353
+ error(`Tool call error [${name}]: ${e.message}`, { tool: name, args });
3252
3354
  return { content: [{ type: "text", text: `\u5DE5\u5177\u6267\u884C\u9519\u8BEF: ${e.message}` }], isError: true };
3253
3355
  }
3254
3356
  }
@@ -3275,226 +3377,38 @@ async function initCadConnection() {
3275
3377
  try {
3276
3378
  const connected = await cad.connect();
3277
3379
  if (connected) {
3278
- log("Auto-connected to CAD: " + cad.getPlatform() + " " + cad.getVersion());
3279
- console.error("\u5DF2\u81EA\u52A8\u8FDE\u63A5\u5230 CAD: " + cad.getPlatform() + " " + cad.getVersion());
3380
+ log(`Auto-connected to CAD: ${cad.getPlatform()} ${cad.getVersion()}`);
3381
+ console.error(`\u5DF2\u81EA\u52A8\u8FDE\u63A5\u5230 CAD: ${cad.getPlatform()} ${cad.getVersion()}`);
3280
3382
  } else {
3281
3383
  log("No CAD found on startup");
3282
3384
  }
3283
3385
  } catch (e) {
3284
- log("Auto-connect failed: " + e.message);
3386
+ error(`Auto-connect failed: ${e.message}`);
3285
3387
  }
3286
3388
  }
3287
- var sessionServers = /* @__PURE__ */ new Map();
3288
- var sessionTransports = /* @__PURE__ */ new Map();
3289
- function createMcpServer() {
3290
- const server = new Server(
3291
- { name: SERVER_NAME, version: SERVER_VERSION },
3292
- { capabilities: SERVER_CAPABILITIES }
3293
- );
3294
- server.setRequestHandler(ListToolsRequestSchema, async () => ({ tools }));
3295
- server.setRequestHandler(CallToolRequestSchema, async (request) => {
3296
- const { name, arguments: args } = request.params;
3297
- return await handleToolCall(name, args || {});
3298
- });
3299
- server.setRequestHandler(ListResourcesRequestSchema, async (request) => {
3300
- const ctx = mcpContext.getStore();
3301
- const sessionId = ctx?.sessionId;
3302
- const subscribedUris = sessionId ? list(sessionId) : list();
3303
- return {
3304
- resources: await listResources(subscribedUris)
3305
- };
3306
- });
3307
- server.setRequestHandler(ReadResourceRequestSchema, async (request) => {
3308
- const { uri } = request.params;
3309
- try {
3310
- const data = await readResource(uri);
3311
- return {
3312
- contents: [{
3313
- uri,
3314
- mimeType: "application/json",
3315
- text: JSON.stringify(data)
3316
- }]
3317
- };
3318
- } catch (e) {
3319
- return {
3320
- contents: [],
3321
- isError: true,
3322
- error: { code: -32603, message: e.message }
3323
- };
3324
- }
3325
- });
3326
- server.setRequestHandler(SubscribeRequestSchema, async (request) => {
3327
- const { uri } = request.params;
3328
- const ctx = mcpContext.getStore();
3329
- subscribe(uri, ctx?.sessionId);
3330
- return { success: true };
3331
- });
3332
- server.setRequestHandler(UnsubscribeRequestSchema, async (request) => {
3333
- const { uri } = request.params;
3334
- const ctx = mcpContext.getStore();
3335
- unsubscribe(uri, ctx?.sessionId);
3336
- return { success: true };
3337
- });
3338
- server.setRequestHandler(ListPromptsRequestSchema, async () => ({
3339
- prompts: await listPrompts()
3340
- }));
3341
- server.setRequestHandler(GetPromptRequestSchema, async (request) => {
3342
- const { name, arguments: args } = request.params;
3343
- return await getPrompt(name, args || {});
3344
- });
3345
- return server;
3346
- }
3347
3389
  async function startServer() {
3348
3390
  if (config_default.transport === "stdio") {
3349
3391
  await initCadConnection();
3350
- const mcpServer = createMcpServer();
3351
- const transport2 = new StdioServerTransport();
3392
+ const mcpServer = createStdioServer({ tools, handleToolCall });
3393
+ const transport = new StdioServerTransport();
3352
3394
  const sessionId = "stdio-session";
3353
3395
  sessionManager.createSession(sessionId);
3354
3396
  await mcpContext.run({ sessionId }, async () => {
3355
- await mcpServer.connect(transport2);
3397
+ await mcpServer.connect(transport);
3356
3398
  });
3357
3399
  console.error(`${SERVER_NAME} \u8FD0\u884C\u5728 stdio \u6A21\u5F0F`);
3358
3400
  setNotify((uri, data) => {
3359
3401
  mcpServer.sendResourceUpdated({ uri }).catch((err) => {
3360
- log(`Failed to send resource update: ${err.message}`);
3402
+ error(`Failed to send resource update: ${err.message}`);
3361
3403
  });
3362
3404
  });
3363
3405
  } else {
3364
- const app = express();
3365
- const JSON_CONTENT_TYPES = ["application/json", "application/json-rpc", "application/vnd.api+json"];
3366
- app.use(async (req, res, next) => {
3367
- const ct = (req.headers["content-type"] || "").toLowerCase();
3368
- if (!JSON_CONTENT_TYPES.some((t) => ct.startsWith(t)))
3369
- return next();
3370
- try {
3371
- const buf = await rawBody(req, { limit: "10mb" });
3372
- const m = ct.match(/charset\s*=\s*([^\s;]+)/i);
3373
- let charset = m ? m[1].toLowerCase() : "utf-8";
3374
- const charsetMap = { "gb2312": "gbk", "gb18030": "gbk", "gbk": "gbk", "936": "gbk" };
3375
- charset = charsetMap[charset] || charset;
3376
- const str = encodingExists(charset) ? charsetDecode(buf, charset) : buf.toString("utf-8");
3377
- req.body = JSON.parse(str);
3378
- next();
3379
- } catch (e) {
3380
- res.status(400).json({ error: "Invalid JSON body", message: e.message });
3381
- }
3382
- });
3383
- app.use((req, res, next) => {
3384
- log(`${req.method} ${req.path}`);
3385
- next();
3386
- });
3387
- const PUBLIC_PATHS = ["/health"];
3388
- if (apiKey) {
3389
- app.use((req, res, next) => {
3390
- if (PUBLIC_PATHS.includes(req.path))
3391
- return next();
3392
- const auth = req.get("Authorization");
3393
- if (auth === `Bearer ${apiKey}`)
3394
- return next();
3395
- res.status(401).json({ error: "Unauthorized" });
3396
- });
3397
- }
3398
- app.get("/health", (req, res) => {
3399
- res.json({ status: "ok", cad: cad.connected ? "connected" : "disconnected" });
3400
- });
3401
- if (config_default.enableCors) {
3402
- app.use((req, res, next) => {
3403
- res.setHeader("Access-Control-Allow-Origin", config_default.corsOrigin);
3404
- res.setHeader("Access-Control-Allow-Methods", "GET, POST, OPTIONS, CONNECT");
3405
- res.setHeader("Access-Control-Allow-Headers", "Content-Type, Authorization, Accept, mcp-session-id, last-event-id");
3406
- res.setHeader("Access-Control-Expose-Headers", "mcp-session-id, content-type, x-accel-buffering");
3407
- res.setHeader("Access-Control-Max-Age", "86400");
3408
- res.setHeader("Vary", "Accept");
3409
- if (req.method === "OPTIONS")
3410
- return res.status(204).end();
3411
- next();
3412
- });
3413
- }
3406
+ const app = express2();
3407
+ setupRoutes(app);
3414
3408
  setNotify((uri, data) => {
3415
3409
  broadcastToAllSessions(uri);
3416
- for (const session of sseSessionManager.listActive()) {
3417
- sseSessionManager.sendToClient(session.clientId, "resource_updated", { uri });
3418
- }
3419
- });
3420
- async function handleMcpPost(req, res) {
3421
- const sessionId = req.headers["mcp-session-id"] || req.query.sessionId || randomUUID4();
3422
- sessionManager.createSession(sessionId);
3423
- const body = req.body;
3424
- if (!body || !body.method) {
3425
- return res.status(400).json({ error: "Invalid request" });
3426
- }
3427
- const { server, transport: transport2 } = getOrCreateSessionServer(sessionId);
3428
- transport2.resetCleanupTimer();
3429
- await mcpContext.run({ sessionId }, async () => {
3430
- try {
3431
- const response = await transport2.handleRequest(body);
3432
- if (response) {
3433
- const headers = { "Content-Type": "application/json" };
3434
- if (transport2.sessionId) {
3435
- headers["mcp-session-id"] = transport2.sessionId;
3436
- }
3437
- res.writeHead(200, headers);
3438
- res.end(JSON.stringify(response));
3439
- } else {
3440
- if (!res.headersSent) {
3441
- res.status(202).end();
3442
- }
3443
- }
3444
- } catch (error) {
3445
- log(`Transport error [${sessionId}]: ${error.message}`);
3446
- if (!res.headersSent) {
3447
- res.status(500).json({ error: "Internal server error", message: error.message });
3448
- }
3449
- }
3450
- });
3451
- }
3452
- app.all("/mcp", mcpLimiter, handleMcpPost);
3453
- app.all("/mcp/:path", mcpLimiter, handleMcpPost);
3454
- app.get("/mcp/stream", mcpLimiter, handleMcpPost);
3455
- const sseEndpoint = "/sse";
3456
- app.get(sseEndpoint, async (req, res) => {
3457
- const sessionId = randomUUID4();
3458
- sessionManager.createSession(sessionId);
3459
- getOrCreateSessionServer(sessionId);
3460
- const sseSession = new SseSession(res, { clientId: sessionId });
3461
- sseSessionManager.add(sessionId, sseSession);
3462
- sseSession.sendEndpoint(`/message?sessionId=${sessionId}`);
3463
- req.on("close", () => {
3464
- sseSessionManager.remove(sessionId);
3465
- removeSessionServer(sessionId);
3466
- });
3467
- });
3468
- app.post("/message", mcpLimiter, async (req, res) => {
3469
- const sessionId = req.query.sessionId;
3470
- if (!sessionId) {
3471
- return res.status(400).json({ error: "Missing sessionId" });
3472
- }
3473
- const sseSession = sseSessionManager.get(sessionId);
3474
- if (!sseSession) {
3475
- return res.status(404).json({ error: "Session not found" });
3476
- }
3477
- sessionManager.createSession(sessionId);
3478
- const { server, transport: transport2 } = getOrCreateSessionServer(sessionId);
3479
- transport2.resetCleanupTimer();
3480
- const body = req.body;
3481
- if (body && body.method) {
3482
- try {
3483
- const response = await transport2.handleRequest(body);
3484
- if (response) {
3485
- sseSession.sendResponse(response);
3486
- }
3487
- if (!res.headersSent) {
3488
- res.status(202).end();
3489
- }
3490
- } catch (error) {
3491
- log(`SSE message error [${sessionId}]: ${error.message}`);
3492
- if (!res.headersSent) {
3493
- res.status(500).json({ error: "Internal server error" });
3494
- }
3495
- }
3496
- } else {
3497
- res.status(400).json({ error: "Invalid request" });
3410
+ for (const session of sseSessionManager2.listActive()) {
3411
+ sseSessionManager2.sendToClient(session.clientId, "resource_updated", { uri });
3498
3412
  }
3499
3413
  });
3500
3414
  const httpServer = app.listen(config_default.port, config_default.host, async () => {
@@ -3504,7 +3418,7 @@ async function startServer() {
3504
3418
  async function shutdown(signal) {
3505
3419
  console.error(`
3506
3420
  \u6536\u5230 ${signal}\uFF0C\u6B63\u5728\u4F18\u96C5\u5173\u95ED...`);
3507
- sseSessionManager.closeAll();
3421
+ sseSessionManager2.closeAll();
3508
3422
  sessionManager.clear();
3509
3423
  for (const [sid] of sessionServers) {
3510
3424
  removeSessionServer(sid);
@@ -3518,14 +3432,285 @@ async function startServer() {
3518
3432
  process.on("SIGTERM", () => shutdown("SIGTERM"));
3519
3433
  }
3520
3434
  }
3521
- if (!process.env.VITEST) {
3522
- await startServer();
3523
- }
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();
3524
3711
  export {
3525
3712
  CAD_PLATFORMS,
3526
3713
  FILE_EXTENSIONS,
3527
- MOCK_PACKAGES,
3528
- createMcpServer,
3529
3714
  handleToolCall,
3530
3715
  loadAtlibFunctionLib,
3531
3716
  startServer,