@atlisp/mcp 1.8.21 → 1.8.25
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +52 -4
- package/dist/atlisp-mcp.js +1978 -958
- package/dist/cad-rothelper.dll +0 -0
- package/dist/cad-worker.js +236 -174
- package/dist/config.js +59 -56
- package/dist/handlers/debug-handlers.js +126 -0
- package/dist/handlers/meta-handlers.js +70 -0
- package/dist/handlers/resource-cache.js +48 -16
- package/dist/handlers/resource-defs.js +3 -0
- package/dist/handlers/resource-handlers.js +123 -0
- package/dist/handlers/skill-handlers.js +152 -0
- package/dist/lisp-security.js +65 -0
- package/dist/prompts/definitions/workflow-batch-doc.json +27 -0
- package/package.json +3 -2
- package/dist/pipelines/analyze-and-report.json +0 -16
- package/dist/pipelines/batch-export-pdfs.json +0 -11
- package/dist/pipelines/batch-layer-move.json +0 -19
- package/dist/pipelines/export-current-drawing.json +0 -18
- package/dist/pipelines/purge-and-save.json +0 -16
package/dist/atlisp-mcp.js
CHANGED
|
@@ -7,10 +7,10 @@ var __require = /* @__PURE__ */ ((x) => typeof require !== "undefined" ? require
|
|
|
7
7
|
if (typeof require !== "undefined") return require.apply(this, arguments);
|
|
8
8
|
throw Error('Dynamic require of "' + x + '" is not supported');
|
|
9
9
|
});
|
|
10
|
-
var __glob = (map) => (
|
|
11
|
-
var fn = map[
|
|
10
|
+
var __glob = (map) => (path21) => {
|
|
11
|
+
var fn = map[path21];
|
|
12
12
|
if (fn) return fn();
|
|
13
|
-
throw new Error("Module not found in bundle: " +
|
|
13
|
+
throw new Error("Module not found in bundle: " + path21);
|
|
14
14
|
};
|
|
15
15
|
var __esm = (fn, res) => function __init() {
|
|
16
16
|
return fn && (res = (0, fn[__getOwnPropNames(fn)[0]])(fn = 0)), res;
|
|
@@ -37,7 +37,7 @@ function parseArgs() {
|
|
|
37
37
|
} else if (args[i] === "--ws") {
|
|
38
38
|
result.transport = "ws";
|
|
39
39
|
} else if (args[i] === "--port" && args[i + 1]) {
|
|
40
|
-
result.port = args[i + 1];
|
|
40
|
+
result.port = parseInt(args[i + 1], 10);
|
|
41
41
|
i++;
|
|
42
42
|
} else if (args[i] === "--host" && args[i + 1]) {
|
|
43
43
|
result.host = args[i + 1];
|
|
@@ -111,41 +111,42 @@ var envSchema, configSchema, cliArgs, envResult, env, configFilePath, fileConfig
|
|
|
111
111
|
var init_config = __esm({
|
|
112
112
|
"src/config.js"() {
|
|
113
113
|
envSchema = z.object({
|
|
114
|
-
PORT: z.
|
|
114
|
+
PORT: z.coerce.number().optional().default(8110),
|
|
115
115
|
HOST: z.string().optional().default("0.0.0.0"),
|
|
116
116
|
TRANSPORT: z.enum(["http", "stdio", "ws"]).optional().default("http"),
|
|
117
117
|
MCP_API_KEY: z.string().optional().default(""),
|
|
118
|
-
ENABLE_SSE: z.
|
|
119
|
-
MESSAGE_TIMEOUT: z.
|
|
120
|
-
HEARTBEAT_INTERVAL: z.
|
|
121
|
-
BUSY_RETRIES: z.
|
|
122
|
-
BUSY_DELAY: z.
|
|
123
|
-
ENABLE_CORS: z.
|
|
124
|
-
CORS_ORIGIN: z.string().optional().default("
|
|
125
|
-
RATE_LIMIT_WINDOW: z.
|
|
126
|
-
RATE_LIMIT_MAX: z.
|
|
127
|
-
RESOURCE_CACHE_TTL: z.
|
|
128
|
-
FUNCTION_LIB_CACHE_TTL: z.
|
|
129
|
-
DEBUG: z.
|
|
118
|
+
ENABLE_SSE: z.coerce.boolean().optional().default(true),
|
|
119
|
+
MESSAGE_TIMEOUT: z.coerce.number().optional().default(6e4),
|
|
120
|
+
HEARTBEAT_INTERVAL: z.coerce.number().optional().default(3e4),
|
|
121
|
+
BUSY_RETRIES: z.coerce.number().optional().default(10),
|
|
122
|
+
BUSY_DELAY: z.coerce.number().optional().default(500),
|
|
123
|
+
ENABLE_CORS: z.coerce.boolean().optional().default(true),
|
|
124
|
+
CORS_ORIGIN: z.string().optional().default("https://atlisp.cn"),
|
|
125
|
+
RATE_LIMIT_WINDOW: z.coerce.number().optional().default(6e4),
|
|
126
|
+
RATE_LIMIT_MAX: z.coerce.number().optional().default(100),
|
|
127
|
+
RESOURCE_CACHE_TTL: z.coerce.number().optional().default(5e3),
|
|
128
|
+
FUNCTION_LIB_CACHE_TTL: z.coerce.number().optional().default(3e5),
|
|
129
|
+
DEBUG: z.coerce.boolean().optional().default(false),
|
|
130
130
|
DEBUG_FILE: z.string().optional().default(""),
|
|
131
131
|
FUNCTION_LIB_URL: z.string().optional().default("http://s3.atlisp.cn/json/functions.json"),
|
|
132
132
|
CONFIG_FILE: z.string().optional().default(""),
|
|
133
|
-
API_KEY_RATE_LIMIT: z.
|
|
134
|
-
METRICS_ENABLED: z.
|
|
135
|
-
REQUEST_LOG_ENABLED: z.
|
|
133
|
+
API_KEY_RATE_LIMIT: z.coerce.number().optional().default(1e3),
|
|
134
|
+
METRICS_ENABLED: z.coerce.boolean().optional().default(true),
|
|
135
|
+
REQUEST_LOG_ENABLED: z.coerce.boolean().optional().default(true),
|
|
136
136
|
SSL_KEY_PATH: z.string().optional().default(""),
|
|
137
137
|
SSL_CERT_PATH: z.string().optional().default(""),
|
|
138
138
|
LLM_API_KEY: z.string().optional().default(""),
|
|
139
139
|
LLM_API_URL: z.string().optional().default("https://api.openai.com/v1/chat/completions"),
|
|
140
140
|
LLM_MODEL: z.string().optional().default("gpt-4o-mini"),
|
|
141
|
-
LLM_MAX_TOKENS: z.
|
|
142
|
-
LLM_TEMPERATURE: z.
|
|
143
|
-
WORKER_POOL_SIZE: z.
|
|
141
|
+
LLM_MAX_TOKENS: z.coerce.number().optional().default(4096),
|
|
142
|
+
LLM_TEMPERATURE: z.coerce.number().optional().default(0.7),
|
|
143
|
+
WORKER_POOL_SIZE: z.coerce.number().optional().default(2),
|
|
144
144
|
LINT_PRESET: z.string().optional().default(""),
|
|
145
145
|
LINT_CONFIG_PATH: z.string().optional().default(""),
|
|
146
146
|
LINT_LEVEL: z.string().optional().default(""),
|
|
147
|
-
NO_LINT: z.
|
|
148
|
-
SECURITY_LEVEL: z.string().optional().default("strict")
|
|
147
|
+
NO_LINT: z.coerce.boolean().optional().default(false),
|
|
148
|
+
SECURITY_LEVEL: z.string().optional().default("strict"),
|
|
149
|
+
CLIENT_ID: z.string().optional().default("")
|
|
149
150
|
});
|
|
150
151
|
configSchema = z.object({
|
|
151
152
|
port: z.number().optional(),
|
|
@@ -188,7 +189,8 @@ var init_config = __esm({
|
|
|
188
189
|
lintConfigPath: z.string().optional(),
|
|
189
190
|
lintLevel: z.string().optional(),
|
|
190
191
|
noLint: z.boolean().optional(),
|
|
191
|
-
securityLevel: z.enum(["strict", "standard", "relaxed"]).optional()
|
|
192
|
+
securityLevel: z.enum(["strict", "standard", "relaxed"]).optional(),
|
|
193
|
+
clientId: z.string().optional()
|
|
192
194
|
});
|
|
193
195
|
cliArgs = parseArgs();
|
|
194
196
|
envResult = envSchema.safeParse(process.env);
|
|
@@ -200,43 +202,44 @@ var init_config = __esm({
|
|
|
200
202
|
configFilePath = env.CONFIG_FILE || cliArgs.configFile || path.join(os.homedir(), ".atlisp", "atlisp.config.json");
|
|
201
203
|
fileConfig = loadConfigFile(configFilePath);
|
|
202
204
|
config = {
|
|
203
|
-
port: fileConfig?.port
|
|
204
|
-
host: fileConfig?.host
|
|
205
|
+
port: fileConfig?.port ?? cliArgs.port ?? env.PORT,
|
|
206
|
+
host: fileConfig?.host ?? cliArgs.host ?? env.HOST,
|
|
205
207
|
transport: fileConfig?.transport ?? cliArgs.transport ?? env.TRANSPORT,
|
|
206
|
-
apiKey: fileConfig?.apiKey
|
|
207
|
-
enableSse: fileConfig?.enableSse ?? env.ENABLE_SSE
|
|
208
|
-
messageTimeout: fileConfig?.messageTimeout
|
|
209
|
-
heartbeatInterval: fileConfig?.heartbeatInterval
|
|
210
|
-
busyRetries: fileConfig?.busyRetries
|
|
211
|
-
busyDelay: fileConfig?.busyDelay
|
|
212
|
-
enableCors: fileConfig?.enableCors ?? env.ENABLE_CORS
|
|
213
|
-
corsOrigin: fileConfig?.corsOrigin
|
|
214
|
-
rateLimitWindow: fileConfig?.rateLimitWindow
|
|
215
|
-
rateLimitMax: fileConfig?.rateLimitMax
|
|
216
|
-
resourceCacheTtl: fileConfig?.resourceCacheTtl
|
|
217
|
-
functionLibCacheTtl: fileConfig?.functionLibCacheTtl
|
|
218
|
-
debug: fileConfig?.debug ?? env.DEBUG
|
|
219
|
-
debugFile: fileConfig?.debugFile
|
|
220
|
-
functionLibUrl: fileConfig?.functionLibUrl
|
|
208
|
+
apiKey: fileConfig?.apiKey ?? env.MCP_API_KEY,
|
|
209
|
+
enableSse: fileConfig?.enableSse ?? env.ENABLE_SSE,
|
|
210
|
+
messageTimeout: fileConfig?.messageTimeout ?? env.MESSAGE_TIMEOUT,
|
|
211
|
+
heartbeatInterval: fileConfig?.heartbeatInterval ?? env.HEARTBEAT_INTERVAL,
|
|
212
|
+
busyRetries: fileConfig?.busyRetries ?? env.BUSY_RETRIES,
|
|
213
|
+
busyDelay: fileConfig?.busyDelay ?? env.BUSY_DELAY,
|
|
214
|
+
enableCors: fileConfig?.enableCors ?? env.ENABLE_CORS,
|
|
215
|
+
corsOrigin: fileConfig?.corsOrigin ?? env.CORS_ORIGIN,
|
|
216
|
+
rateLimitWindow: fileConfig?.rateLimitWindow ?? env.RATE_LIMIT_WINDOW,
|
|
217
|
+
rateLimitMax: fileConfig?.rateLimitMax ?? env.RATE_LIMIT_MAX,
|
|
218
|
+
resourceCacheTtl: fileConfig?.resourceCacheTtl ?? env.RESOURCE_CACHE_TTL,
|
|
219
|
+
functionLibCacheTtl: fileConfig?.functionLibCacheTtl ?? env.FUNCTION_LIB_CACHE_TTL,
|
|
220
|
+
debug: fileConfig?.debug ?? env.DEBUG,
|
|
221
|
+
debugFile: fileConfig?.debugFile ?? env.DEBUG_FILE,
|
|
222
|
+
functionLibUrl: fileConfig?.functionLibUrl ?? env.FUNCTION_LIB_URL,
|
|
221
223
|
configFile: configFilePath,
|
|
222
|
-
apiKeyRateLimit: fileConfig?.apiKeyRateLimit
|
|
223
|
-
apiKeys: fileConfig?.apiKeys
|
|
224
|
-
metricsEnabled: fileConfig?.metricsEnabled ?? env.METRICS_ENABLED
|
|
225
|
-
requestLogEnabled: fileConfig?.requestLogEnabled ?? env.REQUEST_LOG_ENABLED
|
|
226
|
-
sslKey: fileConfig?.sslKey
|
|
227
|
-
sslCert: fileConfig?.sslCert
|
|
228
|
-
llmApiKey: fileConfig?.llmApiKey
|
|
229
|
-
llmApiUrl: fileConfig?.llmApiUrl
|
|
230
|
-
llmModel: fileConfig?.llmModel
|
|
231
|
-
llmMaxTokens: fileConfig?.llmMaxTokens
|
|
232
|
-
llmTemperature: fileConfig?.llmTemperature
|
|
233
|
-
maxPoolSize: fileConfig?.maxPoolSize
|
|
234
|
-
workerPoolSize: fileConfig?.workerPoolSize
|
|
235
|
-
lintPreset: fileConfig?.lintPreset
|
|
236
|
-
lintConfigPath: fileConfig?.lintConfigPath
|
|
237
|
-
lintLevel: fileConfig?.lintLevel
|
|
238
|
-
noLint: fileConfig?.noLint ?? cliArgs.noLint ?? env.NO_LINT
|
|
239
|
-
securityLevel: fileConfig?.securityLevel ?? cliArgs.securityLevel ?? (env.SECURITY_LEVEL || "strict")
|
|
224
|
+
apiKeyRateLimit: fileConfig?.apiKeyRateLimit ?? env.API_KEY_RATE_LIMIT,
|
|
225
|
+
apiKeys: fileConfig?.apiKeys ?? [],
|
|
226
|
+
metricsEnabled: fileConfig?.metricsEnabled ?? env.METRICS_ENABLED,
|
|
227
|
+
requestLogEnabled: fileConfig?.requestLogEnabled ?? env.REQUEST_LOG_ENABLED,
|
|
228
|
+
sslKey: fileConfig?.sslKey ?? env.SSL_KEY_PATH ?? cliArgs.sslKey,
|
|
229
|
+
sslCert: fileConfig?.sslCert ?? env.SSL_CERT_PATH ?? cliArgs.sslCert,
|
|
230
|
+
llmApiKey: fileConfig?.llmApiKey ?? env.LLM_API_KEY,
|
|
231
|
+
llmApiUrl: fileConfig?.llmApiUrl ?? env.LLM_API_URL,
|
|
232
|
+
llmModel: fileConfig?.llmModel ?? env.LLM_MODEL,
|
|
233
|
+
llmMaxTokens: fileConfig?.llmMaxTokens ?? env.LLM_MAX_TOKENS,
|
|
234
|
+
llmTemperature: fileConfig?.llmTemperature ?? env.LLM_TEMPERATURE,
|
|
235
|
+
maxPoolSize: fileConfig?.maxPoolSize ?? 3,
|
|
236
|
+
workerPoolSize: fileConfig?.workerPoolSize ?? env.WORKER_POOL_SIZE,
|
|
237
|
+
lintPreset: fileConfig?.lintPreset ?? cliArgs.lintPreset ?? (env.LINT_PRESET || void 0),
|
|
238
|
+
lintConfigPath: fileConfig?.lintConfigPath ?? cliArgs.lintConfigPath ?? (env.LINT_CONFIG_PATH || void 0),
|
|
239
|
+
lintLevel: fileConfig?.lintLevel ?? cliArgs.lintLevel ?? (env.LINT_LEVEL || void 0),
|
|
240
|
+
noLint: fileConfig?.noLint ?? cliArgs.noLint ?? env.NO_LINT,
|
|
241
|
+
securityLevel: fileConfig?.securityLevel ?? cliArgs.securityLevel ?? (env.SECURITY_LEVEL || "strict"),
|
|
242
|
+
clientId: fileConfig?.clientId ?? (env.CLIENT_ID || "")
|
|
240
243
|
};
|
|
241
244
|
if (config.lintConfigPath) process.env.LINT_CONFIG_PATH = config.lintConfigPath;
|
|
242
245
|
if (config.lintPreset) process.env.LINT_PRESET = config.lintPreset;
|
|
@@ -453,15 +456,89 @@ var init_metrics = __esm({
|
|
|
453
456
|
}
|
|
454
457
|
});
|
|
455
458
|
|
|
459
|
+
// src/cad-circuit-breaker.js
|
|
460
|
+
var CB_CLOSED, CB_OPEN, CB_HALF_OPEN, CB_FAILURE_THRESHOLD, CB_RESET_TIMEOUT, CircuitBreaker;
|
|
461
|
+
var init_cad_circuit_breaker = __esm({
|
|
462
|
+
"src/cad-circuit-breaker.js"() {
|
|
463
|
+
CB_CLOSED = 0;
|
|
464
|
+
CB_OPEN = 1;
|
|
465
|
+
CB_HALF_OPEN = 2;
|
|
466
|
+
CB_FAILURE_THRESHOLD = 5;
|
|
467
|
+
CB_RESET_TIMEOUT = 1e4;
|
|
468
|
+
CircuitBreaker = class {
|
|
469
|
+
constructor(connectionId, onOpen, onHalfOpen) {
|
|
470
|
+
this._connId = connectionId;
|
|
471
|
+
this._state = CB_CLOSED;
|
|
472
|
+
this._failureCount = 0;
|
|
473
|
+
this._lastFailureTime = 0;
|
|
474
|
+
this._timer = null;
|
|
475
|
+
this._onOpen = onOpen;
|
|
476
|
+
this._onHalfOpen = onHalfOpen;
|
|
477
|
+
}
|
|
478
|
+
get state() {
|
|
479
|
+
return this._state;
|
|
480
|
+
}
|
|
481
|
+
get failureCount() {
|
|
482
|
+
return this._failureCount;
|
|
483
|
+
}
|
|
484
|
+
allowRequest() {
|
|
485
|
+
if (this._state === CB_OPEN) {
|
|
486
|
+
const elapsed = Date.now() - this._lastFailureTime;
|
|
487
|
+
if (elapsed >= CB_RESET_TIMEOUT) {
|
|
488
|
+
this._state = CB_HALF_OPEN;
|
|
489
|
+
if (this._onHalfOpen) this._onHalfOpen(this._connId);
|
|
490
|
+
} else {
|
|
491
|
+
return false;
|
|
492
|
+
}
|
|
493
|
+
}
|
|
494
|
+
return true;
|
|
495
|
+
}
|
|
496
|
+
recordSuccess() {
|
|
497
|
+
this._state = CB_CLOSED;
|
|
498
|
+
this._failureCount = 0;
|
|
499
|
+
if (this._timer) {
|
|
500
|
+
clearTimeout(this._timer);
|
|
501
|
+
this._timer = null;
|
|
502
|
+
}
|
|
503
|
+
}
|
|
504
|
+
recordFailure() {
|
|
505
|
+
this._failureCount++;
|
|
506
|
+
this._lastFailureTime = Date.now();
|
|
507
|
+
if (this._failureCount >= CB_FAILURE_THRESHOLD && this._state !== CB_OPEN) {
|
|
508
|
+
this._state = CB_OPEN;
|
|
509
|
+
if (this._onOpen) this._onOpen(this._connId);
|
|
510
|
+
this._timer = setTimeout(() => {
|
|
511
|
+
this._state = CB_HALF_OPEN;
|
|
512
|
+
if (this._onHalfOpen) this._onHalfOpen(this._connId);
|
|
513
|
+
}, CB_RESET_TIMEOUT);
|
|
514
|
+
}
|
|
515
|
+
}
|
|
516
|
+
reset() {
|
|
517
|
+
this._state = CB_CLOSED;
|
|
518
|
+
this._failureCount = 0;
|
|
519
|
+
this._lastFailureTime = 0;
|
|
520
|
+
if (this._timer) {
|
|
521
|
+
clearTimeout(this._timer);
|
|
522
|
+
this._timer = null;
|
|
523
|
+
}
|
|
524
|
+
}
|
|
525
|
+
};
|
|
526
|
+
}
|
|
527
|
+
});
|
|
528
|
+
|
|
456
529
|
// src/cad.js
|
|
457
530
|
var cad_exports = {};
|
|
458
531
|
__export(cad_exports, {
|
|
532
|
+
CommandQueue: () => CommandQueue,
|
|
533
|
+
ReadBatcher: () => ReadBatcher,
|
|
459
534
|
_setInstanceResolver: () => _setInstanceResolver,
|
|
460
535
|
cad: () => cad,
|
|
461
536
|
createCadConnection: () => createCadConnection,
|
|
462
537
|
default: () => cad_default,
|
|
463
538
|
getActiveConnection: () => getActiveConnection,
|
|
539
|
+
isReadCommand: () => isReadCommand,
|
|
464
540
|
onDocumentChanged: () => onDocumentChanged,
|
|
541
|
+
resolveCadConnection: () => resolveCadConnection,
|
|
465
542
|
setActiveConnection: () => setActiveConnection
|
|
466
543
|
});
|
|
467
544
|
import { spawn } from "child_process";
|
|
@@ -506,22 +583,21 @@ function _resolveConn() {
|
|
|
506
583
|
}
|
|
507
584
|
return _activeConnection;
|
|
508
585
|
}
|
|
509
|
-
|
|
586
|
+
function resolveCadConnection() {
|
|
587
|
+
return _resolveConn();
|
|
588
|
+
}
|
|
589
|
+
var __dirname, workerPath, MESSAGE_TIMEOUT, HEARTBEAT_INTERVAL, MAX_RESTART_ATTEMPTS, RESTART_BACKOFF_BASE, MAX_BUFFER_SIZE, PRIORITY_HIGH, PRIORITY_NORMAL, MAX_QUEUE_SIZE, READ_PREFIXES, _docChangeCallbacks, ReadBatcher, CommandQueue, CadConnection, _activeConnection, _resolveInstanceConn, cad, cad_default;
|
|
510
590
|
var init_cad = __esm({
|
|
511
591
|
"src/cad.js"() {
|
|
512
592
|
init_config();
|
|
513
593
|
init_metrics();
|
|
594
|
+
init_cad_circuit_breaker();
|
|
514
595
|
__dirname = path2.dirname(fileURLToPath(import.meta.url));
|
|
515
596
|
workerPath = path2.join(__dirname, "cad-worker.js");
|
|
516
597
|
MESSAGE_TIMEOUT = config_default.messageTimeout;
|
|
517
598
|
HEARTBEAT_INTERVAL = config_default.heartbeatInterval;
|
|
518
599
|
MAX_RESTART_ATTEMPTS = 5;
|
|
519
600
|
RESTART_BACKOFF_BASE = 1e3;
|
|
520
|
-
CB_CLOSED = 0;
|
|
521
|
-
CB_OPEN = 1;
|
|
522
|
-
CB_HALF_OPEN = 2;
|
|
523
|
-
CB_FAILURE_THRESHOLD = 5;
|
|
524
|
-
CB_RESET_TIMEOUT = 1e4;
|
|
525
601
|
MAX_BUFFER_SIZE = 1024 * 1024;
|
|
526
602
|
PRIORITY_HIGH = 0;
|
|
527
603
|
PRIORITY_NORMAL = 1;
|
|
@@ -708,10 +784,6 @@ var init_cad = __esm({
|
|
|
708
784
|
_heartbeatTimer = null;
|
|
709
785
|
_pendingRequests = /* @__PURE__ */ new Map();
|
|
710
786
|
_commandQueue = null;
|
|
711
|
-
_cbState = CB_CLOSED;
|
|
712
|
-
_cbFailureCount = 0;
|
|
713
|
-
_cbLastFailureTime = 0;
|
|
714
|
-
_cbTimer = null;
|
|
715
787
|
_restartCount = 0;
|
|
716
788
|
_restartTimer = null;
|
|
717
789
|
_activeDocName = null;
|
|
@@ -721,6 +793,11 @@ var init_cad = __esm({
|
|
|
721
793
|
constructor() {
|
|
722
794
|
this._connectionId = randomUUID().slice(0, 8);
|
|
723
795
|
this._commandQueue = new CommandQueue(this);
|
|
796
|
+
this._cb = new CircuitBreaker(
|
|
797
|
+
this._connectionId,
|
|
798
|
+
(id) => console.error(`[${id}] Circuit breaker OPEN`),
|
|
799
|
+
(id) => console.error(`[${id}] Circuit breaker HALF_OPEN, allowing trial request`)
|
|
800
|
+
);
|
|
724
801
|
}
|
|
725
802
|
get _workerPoolSize() {
|
|
726
803
|
return config_default.workerPoolSize || 2;
|
|
@@ -728,11 +805,15 @@ var init_cad = __esm({
|
|
|
728
805
|
isAvailable() {
|
|
729
806
|
return process.platform === "win32";
|
|
730
807
|
}
|
|
731
|
-
async connect(platform = null) {
|
|
808
|
+
async connect(platform = null, options = {}) {
|
|
732
809
|
if (!this.isAvailable()) return false;
|
|
733
|
-
this.
|
|
810
|
+
this._cb.recordSuccess();
|
|
734
811
|
try {
|
|
735
812
|
const msg = platform ? { type: "connect", platform } : { type: "connect" };
|
|
813
|
+
if (options.moniker) {
|
|
814
|
+
msg.moniker = options.moniker;
|
|
815
|
+
msg.monikerKey = options.key || "moniker";
|
|
816
|
+
}
|
|
736
817
|
const result = await this._sendMessage(msg);
|
|
737
818
|
if (result && result.success) {
|
|
738
819
|
this._version = result.version;
|
|
@@ -845,21 +926,8 @@ var init_cad = __esm({
|
|
|
845
926
|
return `Platform: ${this._product}, Version: ${this._version}, Status: Connected`;
|
|
846
927
|
}
|
|
847
928
|
async disconnect() {
|
|
848
|
-
this.
|
|
849
|
-
|
|
850
|
-
this._version = null;
|
|
851
|
-
this._product = null;
|
|
852
|
-
this._platform = null;
|
|
853
|
-
this._activeDocName = null;
|
|
854
|
-
this._monitorStarted = false;
|
|
855
|
-
this._commandQueue.clear();
|
|
856
|
-
this._cbState = CB_CLOSED;
|
|
857
|
-
this._cbFailureCount = 0;
|
|
858
|
-
if (this._cbTimer) {
|
|
859
|
-
clearTimeout(this._cbTimer);
|
|
860
|
-
this._cbTimer = null;
|
|
861
|
-
}
|
|
862
|
-
this._resetWorker();
|
|
929
|
+
this._reset();
|
|
930
|
+
this._cb.reset();
|
|
863
931
|
}
|
|
864
932
|
async ping() {
|
|
865
933
|
try {
|
|
@@ -878,12 +946,6 @@ var init_cad = __esm({
|
|
|
878
946
|
this._activeDocName = null;
|
|
879
947
|
this._monitorStarted = false;
|
|
880
948
|
this._commandQueue.clear();
|
|
881
|
-
this._cbState = CB_CLOSED;
|
|
882
|
-
this._cbFailureCount = 0;
|
|
883
|
-
if (this._cbTimer) {
|
|
884
|
-
clearTimeout(this._cbTimer);
|
|
885
|
-
this._cbTimer = null;
|
|
886
|
-
}
|
|
887
949
|
this._resetWorker();
|
|
888
950
|
}
|
|
889
951
|
_getQueueSize() {
|
|
@@ -892,44 +954,6 @@ var init_cad = __esm({
|
|
|
892
954
|
_getRestartCount() {
|
|
893
955
|
return this._restartCount;
|
|
894
956
|
}
|
|
895
|
-
// --- Circuit breaker ---
|
|
896
|
-
_cbSuccess() {
|
|
897
|
-
this._cbState = CB_CLOSED;
|
|
898
|
-
this._cbFailureCount = 0;
|
|
899
|
-
if (this._cbTimer) {
|
|
900
|
-
clearTimeout(this._cbTimer);
|
|
901
|
-
this._cbTimer = null;
|
|
902
|
-
}
|
|
903
|
-
}
|
|
904
|
-
_cbFailure() {
|
|
905
|
-
this._cbFailureCount++;
|
|
906
|
-
this._cbLastFailureTime = Date.now();
|
|
907
|
-
if (this._cbFailureCount >= CB_FAILURE_THRESHOLD && this._cbState !== CB_OPEN) {
|
|
908
|
-
this._cbState = CB_OPEN;
|
|
909
|
-
console.error(`[${this._connectionId}] Circuit breaker OPEN after ${this._cbFailureCount} failures`);
|
|
910
|
-
this._cbTimer = setTimeout(() => {
|
|
911
|
-
this._cbState = CB_HALF_OPEN;
|
|
912
|
-
console.error(`[${this._connectionId}] Circuit breaker HALF_OPEN, allowing trial request`);
|
|
913
|
-
}, CB_RESET_TIMEOUT);
|
|
914
|
-
}
|
|
915
|
-
}
|
|
916
|
-
_cbAllowRequest() {
|
|
917
|
-
if (this._cbState === CB_OPEN) {
|
|
918
|
-
const elapsed = Date.now() - this._cbLastFailureTime;
|
|
919
|
-
if (elapsed >= CB_RESET_TIMEOUT) {
|
|
920
|
-
this._cbState = CB_HALF_OPEN;
|
|
921
|
-
console.error(`[${this._connectionId}] Circuit breaker auto-transition to HALF_OPEN`);
|
|
922
|
-
} else {
|
|
923
|
-
return false;
|
|
924
|
-
}
|
|
925
|
-
}
|
|
926
|
-
return true;
|
|
927
|
-
}
|
|
928
|
-
// --- Worker management ---
|
|
929
|
-
_isReadOnlyMessage(msg) {
|
|
930
|
-
if (msg.code) return isReadCommand(msg.code);
|
|
931
|
-
return false;
|
|
932
|
-
}
|
|
933
957
|
_spawnWorker(type) {
|
|
934
958
|
const w = spawn("node", [workerPath], { stdio: ["pipe", "pipe", "pipe"] });
|
|
935
959
|
w.connected = true;
|
|
@@ -940,7 +964,7 @@ var init_cad = __esm({
|
|
|
940
964
|
w.connected = false;
|
|
941
965
|
if (type === "primary") {
|
|
942
966
|
if (w !== this._primaryWorker) return;
|
|
943
|
-
this.
|
|
967
|
+
this._cb.recordFailure();
|
|
944
968
|
const exitError = new Error(`Primary worker exited with code ${code}`);
|
|
945
969
|
for (const [id, entry] of this._pendingRequests) {
|
|
946
970
|
clearTimeout(entry.timeout);
|
|
@@ -977,7 +1001,7 @@ var init_cad = __esm({
|
|
|
977
1001
|
this._primaryWorker = null;
|
|
978
1002
|
}
|
|
979
1003
|
this._primaryWorker = this._spawnWorker("primary");
|
|
980
|
-
this.
|
|
1004
|
+
this._cb.recordSuccess();
|
|
981
1005
|
if (!this._heartbeatTimer) this._startHeartbeat();
|
|
982
1006
|
this._restartCount = 0;
|
|
983
1007
|
}
|
|
@@ -1118,14 +1142,9 @@ var init_cad = __esm({
|
|
|
1118
1142
|
}, delay);
|
|
1119
1143
|
}
|
|
1120
1144
|
async _sendMessage(msg) {
|
|
1121
|
-
if (!this.
|
|
1145
|
+
if (!this._cb.allowRequest()) {
|
|
1122
1146
|
console.error(`[${this._connectionId}] Circuit breaker OPEN, auto-recovering...`);
|
|
1123
|
-
this.
|
|
1124
|
-
this._cbFailureCount = 0;
|
|
1125
|
-
if (this._cbTimer) {
|
|
1126
|
-
clearTimeout(this._cbTimer);
|
|
1127
|
-
this._cbTimer = null;
|
|
1128
|
-
}
|
|
1147
|
+
this._cb.reset();
|
|
1129
1148
|
await this._resetWorker();
|
|
1130
1149
|
await this._getWorker(false);
|
|
1131
1150
|
}
|
|
@@ -1141,17 +1160,17 @@ var init_cad = __esm({
|
|
|
1141
1160
|
const p = self._pendingRequests.get(requestId);
|
|
1142
1161
|
if (p) {
|
|
1143
1162
|
self._pendingRequests.delete(requestId);
|
|
1144
|
-
if (!noCircuitBreaker) self.
|
|
1163
|
+
if (!noCircuitBreaker) self._cb.recordFailure();
|
|
1145
1164
|
reject(new Error("Timeout waiting for worker"));
|
|
1146
1165
|
}
|
|
1147
1166
|
}, MESSAGE_TIMEOUT);
|
|
1148
1167
|
const entry = {
|
|
1149
1168
|
resolve: (v) => {
|
|
1150
|
-
if (!noCircuitBreaker && !entry._skipCb) self.
|
|
1169
|
+
if (!noCircuitBreaker && !entry._skipCb) self._cb.recordSuccess();
|
|
1151
1170
|
resolve(v);
|
|
1152
1171
|
},
|
|
1153
1172
|
reject: (e) => {
|
|
1154
|
-
if (!noCircuitBreaker && !entry._skipCb) self.
|
|
1173
|
+
if (!noCircuitBreaker && !entry._skipCb) self._cb.recordFailure();
|
|
1155
1174
|
reject(e);
|
|
1156
1175
|
},
|
|
1157
1176
|
timeout
|
|
@@ -1162,11 +1181,15 @@ var init_cad = __esm({
|
|
|
1162
1181
|
} catch (e) {
|
|
1163
1182
|
clearTimeout(timeout);
|
|
1164
1183
|
self._pendingRequests.delete(requestId);
|
|
1165
|
-
if (!noCircuitBreaker) self.
|
|
1184
|
+
if (!noCircuitBreaker) self._cb.recordFailure();
|
|
1166
1185
|
reject(new Error(`Failed to write to worker: ${e.message}`));
|
|
1167
1186
|
}
|
|
1168
1187
|
});
|
|
1169
1188
|
}
|
|
1189
|
+
_isReadOnlyMessage(msg) {
|
|
1190
|
+
if (msg.code) return isReadCommand(msg.code);
|
|
1191
|
+
return false;
|
|
1192
|
+
}
|
|
1170
1193
|
};
|
|
1171
1194
|
_activeConnection = new CadConnection();
|
|
1172
1195
|
_resolveInstanceConn = null;
|
|
@@ -1175,28 +1198,28 @@ var init_cad = __esm({
|
|
|
1175
1198
|
return _resolveConn().connected;
|
|
1176
1199
|
},
|
|
1177
1200
|
set connected(v) {
|
|
1178
|
-
|
|
1201
|
+
_resolveConn().connected = v;
|
|
1179
1202
|
},
|
|
1180
1203
|
get version() {
|
|
1181
|
-
return
|
|
1204
|
+
return _resolveConn()._version;
|
|
1182
1205
|
},
|
|
1183
1206
|
set version(v) {
|
|
1184
|
-
|
|
1207
|
+
_resolveConn()._version = v;
|
|
1185
1208
|
},
|
|
1186
1209
|
get product() {
|
|
1187
|
-
return
|
|
1210
|
+
return _resolveConn()._product;
|
|
1188
1211
|
},
|
|
1189
1212
|
set product(v) {
|
|
1190
|
-
|
|
1213
|
+
_resolveConn()._product = v;
|
|
1191
1214
|
},
|
|
1192
1215
|
get _platform() {
|
|
1193
|
-
return
|
|
1216
|
+
return _resolveConn()._platform;
|
|
1194
1217
|
},
|
|
1195
1218
|
set _platform(v) {
|
|
1196
|
-
|
|
1219
|
+
_resolveConn()._platform = v;
|
|
1197
1220
|
},
|
|
1198
1221
|
async connect(platform) {
|
|
1199
|
-
return
|
|
1222
|
+
return _resolveConn().connect(platform);
|
|
1200
1223
|
},
|
|
1201
1224
|
async sendCommand(code) {
|
|
1202
1225
|
return _resolveConn().sendCommand(code);
|
|
@@ -1205,49 +1228,49 @@ var init_cad = __esm({
|
|
|
1205
1228
|
return _resolveConn().sendCommandWithResult(code, encoding);
|
|
1206
1229
|
},
|
|
1207
1230
|
getVersion() {
|
|
1208
|
-
return
|
|
1231
|
+
return _resolveConn().getVersion();
|
|
1209
1232
|
},
|
|
1210
1233
|
getPlatform() {
|
|
1211
|
-
return
|
|
1234
|
+
return _resolveConn().getPlatform();
|
|
1212
1235
|
},
|
|
1213
1236
|
getConnectionId() {
|
|
1214
|
-
return
|
|
1237
|
+
return _resolveConn().getConnectionId();
|
|
1215
1238
|
},
|
|
1216
1239
|
isAvailable() {
|
|
1217
|
-
return
|
|
1240
|
+
return _resolveConn().isAvailable();
|
|
1218
1241
|
},
|
|
1219
1242
|
async isBusy() {
|
|
1220
|
-
return
|
|
1243
|
+
return _resolveConn().isBusy();
|
|
1221
1244
|
},
|
|
1222
1245
|
async hasDoc() {
|
|
1223
|
-
return
|
|
1246
|
+
return _resolveConn().hasDoc();
|
|
1224
1247
|
},
|
|
1225
1248
|
async newDoc() {
|
|
1226
|
-
return
|
|
1249
|
+
return _resolveConn().newDoc();
|
|
1227
1250
|
},
|
|
1228
1251
|
async bringToFront() {
|
|
1229
|
-
return
|
|
1252
|
+
return _resolveConn().bringToFront();
|
|
1230
1253
|
},
|
|
1231
1254
|
async getActiveDocInfo() {
|
|
1232
|
-
return
|
|
1255
|
+
return _resolveConn().getActiveDocInfo();
|
|
1233
1256
|
},
|
|
1234
1257
|
async getInfo() {
|
|
1235
|
-
return
|
|
1258
|
+
return _resolveConn().getInfo();
|
|
1236
1259
|
},
|
|
1237
1260
|
async disconnect() {
|
|
1238
|
-
return
|
|
1261
|
+
return _resolveConn().disconnect();
|
|
1239
1262
|
},
|
|
1240
1263
|
async ping() {
|
|
1241
|
-
return
|
|
1264
|
+
return _resolveConn().ping();
|
|
1242
1265
|
},
|
|
1243
1266
|
_reset() {
|
|
1244
|
-
return
|
|
1267
|
+
return _resolveConn()._reset();
|
|
1245
1268
|
},
|
|
1246
1269
|
_getQueueSize() {
|
|
1247
|
-
return
|
|
1270
|
+
return _resolveConn()._getQueueSize();
|
|
1248
1271
|
},
|
|
1249
1272
|
_getRestartCount() {
|
|
1250
|
-
return
|
|
1273
|
+
return _resolveConn()._getRestartCount();
|
|
1251
1274
|
}
|
|
1252
1275
|
};
|
|
1253
1276
|
cad_default = CadConnection;
|
|
@@ -1258,7 +1281,7 @@ var init_cad = __esm({
|
|
|
1258
1281
|
import path3 from "path";
|
|
1259
1282
|
import { fileURLToPath as fileURLToPath2 } from "url";
|
|
1260
1283
|
import { createRequire } from "module";
|
|
1261
|
-
var CAD_PLATFORMS, FILE_EXTENSIONS, __dirname2, require2, version, SERVER_NAME, SERVER_VERSION, SERVER_CAPABILITIES, MOCK_PACKAGES;
|
|
1284
|
+
var CAD_PLATFORMS, FILE_EXTENSIONS, __dirname2, require2, version, SERVER_NAME, SERVER_VERSION, SERVER_CAPABILITIES, MOCK_PACKAGES, CAD_RESOURCE_URIS;
|
|
1262
1285
|
var init_constants = __esm({
|
|
1263
1286
|
"src/constants.js"() {
|
|
1264
1287
|
CAD_PLATFORMS = ["AutoCAD", "ZWCAD", "GStarCAD", "BricsCAD"];
|
|
@@ -1281,6 +1304,17 @@ var init_constants = __esm({
|
|
|
1281
1304
|
completions: {}
|
|
1282
1305
|
};
|
|
1283
1306
|
MOCK_PACKAGES = [];
|
|
1307
|
+
CAD_RESOURCE_URIS = [
|
|
1308
|
+
"atlisp://cad/info",
|
|
1309
|
+
"atlisp://dwg/name",
|
|
1310
|
+
"atlisp://dwg/path",
|
|
1311
|
+
"atlisp://dwg/entities",
|
|
1312
|
+
"atlisp://dwg/tbl",
|
|
1313
|
+
"atlisp://dwg/block-refs",
|
|
1314
|
+
"atlisp://dwg/text-content",
|
|
1315
|
+
"atlisp://cad/dwgs",
|
|
1316
|
+
"atlisp://packages"
|
|
1317
|
+
];
|
|
1284
1318
|
}
|
|
1285
1319
|
});
|
|
1286
1320
|
|
|
@@ -1481,7 +1515,10 @@ var init_resource_defs = __esm({
|
|
|
1481
1515
|
{ uri: "atlisp://standards/drafting", name: "Drafting Standards", description: "CAD \u5236\u56FE\u89C4\u8303", mimeType: "application/json", subscribable: false },
|
|
1482
1516
|
{ uri: "atlisp://standards/coding", name: "Coding Standards", description: "@lisp \u7F16\u7801\u89C4\u8303", mimeType: "application/json", subscribable: false },
|
|
1483
1517
|
{ uri: "atlisp://dwg/context", name: "DWG Context", description: "\u5F53\u524D\u56FE\u7EB8\u4E0A\u4E0B\u6587\u6458\u8981\u3002\u8FD4\u56DE\u6587\u6863\u540D/\u8DEF\u5F84/\u5E03\u5C40/UCS/\u56FE\u5C42\u5217\u8868/\u5B9E\u4F53\u7EDF\u8BA1/\u7CFB\u7EDF\u53D8\u91CF\u7EC4\u5408\u4FE1\u606F\uFF0C\u5E2E\u52A9\u5FEB\u901F\u4E86\u89E3\u5F53\u524D CAD \u72B6\u6001", mimeType: "application/json", subscribable: true },
|
|
1484
|
-
{ uri: "atlisp://tools/relationships", name: "Tool Relationships", description: "\u5DE5\u5177\u4F9D\u8D56\u5173\u7CFB\u56FE\u3002\u63CF\u8FF0\u5DE5\u5177\u95F4\u7684\u8C03\u7528\u94FE\u5173\u7CFB\uFF08\u5982 select_entities \u2192 batch_delete\uFF09\uFF0C\u5E2E\u52A9\u7406\u89E3\u5DE5\u5177\u7EC4\u5408\u4F7F\u7528\u65B9\u5F0F", mimeType: "application/json", subscribable: false }
|
|
1518
|
+
{ uri: "atlisp://tools/relationships", name: "Tool Relationships", description: "\u5DE5\u5177\u4F9D\u8D56\u5173\u7CFB\u56FE\u3002\u63CF\u8FF0\u5DE5\u5177\u95F4\u7684\u8C03\u7528\u94FE\u5173\u7CFB\uFF08\u5982 select_entities \u2192 batch_delete\uFF09\uFF0C\u5E2E\u52A9\u7406\u89E3\u5DE5\u5177\u7EC4\u5408\u4F7F\u7528\u65B9\u5F0F", mimeType: "application/json", subscribable: false },
|
|
1519
|
+
{ uri: "atlisp://dwg/analysis", name: "Drawing Analysis", description: "\u5F53\u524D\u56FE\u7EB8\u7EFC\u5408\u5206\u6790\uFF1A\u5B9E\u4F53\u7C7B\u578B\u7EDF\u8BA1\u3001\u5757\u4F7F\u7528\u7EDF\u8BA1\u3001\u56FE\u5C42\u6458\u8981\u3001\u6587\u5B57\u7EDF\u8BA1\u3001\u7CFB\u7EDF\u53D8\u91CF\u5FEB\u7167\u3002\u652F\u6301 ?type=summary\uFF08\u9ED8\u8BA4\uFF09\u6216 ?type=detailed", mimeType: "application/json", subscribable: true },
|
|
1520
|
+
{ uri: "atlisp://tools/categories", name: "Tool Categories", description: "\u5DE5\u5177\u5206\u7C7B\u6982\u89C8\u3002\u5217\u51FA\u6240\u6709\u5206\u7C7B\u53CA\u5176\u5305\u542B\u7684\u5DE5\u5177\u6570\u91CF", mimeType: "application/json", subscribable: false },
|
|
1521
|
+
{ uri: "atlisp://dwg/standards/check", name: "Drawing Standards Check", description: "\u68C0\u67E5\u5F53\u524D\u56FE\u7EB8\u662F\u5426\u7B26\u5408\u52A0\u8F7D\u7684\u5236\u56FE\u89C4\u8303\uFF08\u56FE\u5C42\u547D\u540D\u3001\u989C\u8272\u3001\u7EBF\u578B\u7B49\u89C4\u5219\uFF09", mimeType: "application/json", subscribable: false }
|
|
1485
1522
|
];
|
|
1486
1523
|
TBL_QUERIES = {
|
|
1487
1524
|
layer: { name: "layer", lisp: `(progn
|
|
@@ -1528,49 +1565,70 @@ var init_resource_defs = __esm({
|
|
|
1528
1565
|
});
|
|
1529
1566
|
|
|
1530
1567
|
// src/handlers/resource-cache.js
|
|
1568
|
+
function _getCache() {
|
|
1569
|
+
const key = _instanceKey || _defaultKey;
|
|
1570
|
+
if (!_instanceCaches.has(key)) {
|
|
1571
|
+
_instanceCaches.set(key, /* @__PURE__ */ new Map());
|
|
1572
|
+
}
|
|
1573
|
+
return _instanceCaches.get(key);
|
|
1574
|
+
}
|
|
1575
|
+
function _ttl() {
|
|
1576
|
+
return config_default.resourceCacheTtl;
|
|
1577
|
+
}
|
|
1531
1578
|
function ensureCleanup() {
|
|
1532
1579
|
if (cleanupTimer) return;
|
|
1533
1580
|
cleanupTimer = setInterval(() => {
|
|
1534
1581
|
const now = Date.now();
|
|
1535
|
-
|
|
1536
|
-
|
|
1537
|
-
|
|
1582
|
+
const ttl = _ttl();
|
|
1583
|
+
for (const cache of _instanceCaches.values()) {
|
|
1584
|
+
for (const [key, entry] of cache) {
|
|
1585
|
+
if (now - entry.timestamp >= ttl) {
|
|
1586
|
+
cache.delete(key);
|
|
1587
|
+
}
|
|
1538
1588
|
}
|
|
1539
1589
|
}
|
|
1540
1590
|
}, CLEANUP_INTERVAL);
|
|
1541
1591
|
cleanupTimer.unref();
|
|
1542
1592
|
}
|
|
1593
|
+
function setInstanceKey(key) {
|
|
1594
|
+
_instanceKey = key || null;
|
|
1595
|
+
}
|
|
1543
1596
|
function getCached(key) {
|
|
1544
|
-
const
|
|
1545
|
-
|
|
1597
|
+
const cache = _getCache();
|
|
1598
|
+
const entry = cache.get(key);
|
|
1599
|
+
if (entry && Date.now() - entry.timestamp < _ttl()) {
|
|
1546
1600
|
return entry.data;
|
|
1547
1601
|
}
|
|
1548
|
-
|
|
1602
|
+
cache.delete(key);
|
|
1549
1603
|
return null;
|
|
1550
1604
|
}
|
|
1551
1605
|
function setCache(key, data) {
|
|
1552
|
-
|
|
1606
|
+
_getCache().set(key, { data, timestamp: Date.now() });
|
|
1553
1607
|
}
|
|
1554
1608
|
function clearCache(uri) {
|
|
1555
|
-
const
|
|
1556
|
-
if (
|
|
1557
|
-
|
|
1558
|
-
|
|
1559
|
-
|
|
1609
|
+
const basePrefix = URI_CACHE_PREFIX[uri];
|
|
1610
|
+
if (basePrefix) {
|
|
1611
|
+
const cache = _getCache();
|
|
1612
|
+
for (const key of cache.keys()) {
|
|
1613
|
+
if (key === basePrefix || key.startsWith(basePrefix + ":")) {
|
|
1614
|
+
cache.delete(key);
|
|
1560
1615
|
}
|
|
1561
1616
|
}
|
|
1562
1617
|
} else if (!uri) {
|
|
1563
|
-
|
|
1618
|
+
const key = _instanceKey || _defaultKey;
|
|
1619
|
+
_instanceCaches.delete(key);
|
|
1620
|
+
_instanceCaches.set(key, /* @__PURE__ */ new Map());
|
|
1564
1621
|
}
|
|
1565
1622
|
}
|
|
1566
|
-
var
|
|
1623
|
+
var CLEANUP_INTERVAL, cleanupTimer, _instanceKey, _instanceCaches, _defaultKey, URI_CACHE_PREFIX;
|
|
1567
1624
|
var init_resource_cache = __esm({
|
|
1568
1625
|
"src/handlers/resource-cache.js"() {
|
|
1569
1626
|
init_config();
|
|
1570
|
-
CACHE_TTL = config_default.resourceCacheTtl;
|
|
1571
|
-
resourceCache = /* @__PURE__ */ new Map();
|
|
1572
1627
|
CLEANUP_INTERVAL = 6e4;
|
|
1573
1628
|
cleanupTimer = null;
|
|
1629
|
+
_instanceKey = null;
|
|
1630
|
+
_instanceCaches = /* @__PURE__ */ new Map();
|
|
1631
|
+
_defaultKey = "__default__";
|
|
1574
1632
|
ensureCleanup();
|
|
1575
1633
|
URI_CACHE_PREFIX = {
|
|
1576
1634
|
"atlisp://cad/info": "cad:info",
|
|
@@ -1591,6 +1649,23 @@ function createError(code, details = {}) {
|
|
|
1591
1649
|
const def = ERROR_DEFS[code] || ERROR_DEFS[ERROR_CODES.INTERNAL_ERROR];
|
|
1592
1650
|
return new MCPError(code, def.message, details);
|
|
1593
1651
|
}
|
|
1652
|
+
function toMcpError(error2) {
|
|
1653
|
+
if (error2 instanceof MCPError) return error2;
|
|
1654
|
+
if (error2 instanceof Error) {
|
|
1655
|
+
return new MCPError(ERROR_CODES.INTERNAL_ERROR, error2.message, { stack: error2.stack });
|
|
1656
|
+
}
|
|
1657
|
+
return new MCPError(ERROR_CODES.INTERNAL_ERROR, String(error2));
|
|
1658
|
+
}
|
|
1659
|
+
function mcpErrorResponse(error2) {
|
|
1660
|
+
const mcpErr = toMcpError(error2);
|
|
1661
|
+
const json = mcpErr.toJSON();
|
|
1662
|
+
return {
|
|
1663
|
+
content: [{ type: "text", text: `[${json.code}] ${json.message}
|
|
1664
|
+
\u63D0\u793A: ${json.hint}
|
|
1665
|
+
\u5EFA\u8BAE\u5DE5\u5177: ${json.suggestedTools.join(", ") || "\u65E0"}` }],
|
|
1666
|
+
isError: true
|
|
1667
|
+
};
|
|
1668
|
+
}
|
|
1594
1669
|
function mcpSuccessResponse(text) {
|
|
1595
1670
|
return { content: [{ type: "text", text: String(text) }] };
|
|
1596
1671
|
}
|
|
@@ -1604,9 +1679,14 @@ var init_errors = __esm({
|
|
|
1604
1679
|
LISP_PAREN_MISMATCH: "LISP_PAREN_MISMATCH",
|
|
1605
1680
|
TIMEOUT: "TIMEOUT",
|
|
1606
1681
|
INVALID_PARAMS: "INVALID_PARAMS",
|
|
1682
|
+
INVALID_ARGS: "INVALID_ARGS",
|
|
1607
1683
|
METHOD_NOT_FOUND: "METHOD_NOT_FOUND",
|
|
1684
|
+
HANDLER_NOT_FOUND: "HANDLER_NOT_FOUND",
|
|
1608
1685
|
RESOURCE_NOT_FOUND: "RESOURCE_NOT_FOUND",
|
|
1609
1686
|
PACKAGE_NOT_FOUND: "PACKAGE_NOT_FOUND",
|
|
1687
|
+
OPERATION_FAILED: "OPERATION_FAILED",
|
|
1688
|
+
RATE_LIMITED: "RATE_LIMITED",
|
|
1689
|
+
SESSION_NOT_FOUND: "SESSION_NOT_FOUND",
|
|
1610
1690
|
INTERNAL_ERROR: "INTERNAL_ERROR"
|
|
1611
1691
|
};
|
|
1612
1692
|
ERROR_DEFS = {
|
|
@@ -1640,6 +1720,31 @@ var init_errors = __esm({
|
|
|
1640
1720
|
hint: "\u8BF7\u68C0\u67E5\u5DE5\u5177\u53C2\u6570\u683C\u5F0F\u662F\u5426\u6B63\u786E\u3002\u4F7F\u7528 search_tools \u6216 list_tools_by_category \u67E5\u770B\u5DE5\u5177\u53C2\u6570\u8981\u6C42",
|
|
1641
1721
|
tools: ["search_tools", "list_tools_by_category"]
|
|
1642
1722
|
},
|
|
1723
|
+
[ERROR_CODES.INVALID_ARGS]: {
|
|
1724
|
+
message: "\u53C2\u6570\u6821\u9A8C\u5931\u8D25",
|
|
1725
|
+
hint: "\u5DE5\u5177\u6240\u9700\u53C2\u6570\u7F3A\u5931\u6216\u683C\u5F0F\u9519\u8BEF\u3002\u8BF7\u68C0\u67E5\u53C2\u6570\u7C7B\u578B\u548C\u5FC5\u586B\u5B57\u6BB5\uFF0C\u4F7F\u7528 search_tools \u67E5\u770B\u5DE5\u5177\u53C2\u6570\u8981\u6C42",
|
|
1726
|
+
tools: ["search_tools", "list_tools_by_category"]
|
|
1727
|
+
},
|
|
1728
|
+
[ERROR_CODES.HANDLER_NOT_FOUND]: {
|
|
1729
|
+
message: "\u5DE5\u5177\u672A\u627E\u5230",
|
|
1730
|
+
hint: "\u5DE5\u5177\u540D\u79F0\u4E0D\u5B58\u5728\u3002\u4F7F\u7528 search_tools \u641C\u7D22\u53EF\u7528\u5DE5\u5177\uFF0C\u6216 list_tools_by_category \u6D4F\u89C8\u5168\u90E8\u5206\u7C7B",
|
|
1731
|
+
tools: ["search_tools", "list_tools_by_category"]
|
|
1732
|
+
},
|
|
1733
|
+
[ERROR_CODES.OPERATION_FAILED]: {
|
|
1734
|
+
message: "\u64CD\u4F5C\u6267\u884C\u5931\u8D25",
|
|
1735
|
+
hint: "\u5DE5\u5177\u6267\u884C\u8FC7\u7A0B\u4E2D\u53D1\u751F\u9519\u8BEF\u3002\u53EF\u91CD\u8BD5\u64CD\u4F5C\uFF0C\u6216\u68C0\u67E5\u65E5\u5FD7\u83B7\u53D6\u8BE6\u7EC6\u4FE1\u606F",
|
|
1736
|
+
tools: ["get_system_status", "get_cad_info"]
|
|
1737
|
+
},
|
|
1738
|
+
[ERROR_CODES.RATE_LIMITED]: {
|
|
1739
|
+
message: "\u8C03\u7528\u9891\u7387\u8D85\u9650",
|
|
1740
|
+
hint: "\u5DE5\u5177\u8C03\u7528\u8FC7\u4E8E\u9891\u7E41\u3002\u8BF7\u7B49\u5F85\u4E00\u6BB5\u65F6\u95F4\u540E\u518D\u8BD5",
|
|
1741
|
+
tools: []
|
|
1742
|
+
},
|
|
1743
|
+
[ERROR_CODES.SESSION_NOT_FOUND]: {
|
|
1744
|
+
message: "\u4F1A\u8BDD\u672A\u627E\u5230",
|
|
1745
|
+
hint: "\u6307\u5B9A ID \u7684\u4F1A\u8BDD\u4E0D\u5B58\u5728\u3002\u8BF7\u68C0\u67E5 sessionId \u53C2\u6570\u662F\u5426\u6B63\u786E",
|
|
1746
|
+
tools: ["lisp_repl_list"]
|
|
1747
|
+
},
|
|
1643
1748
|
[ERROR_CODES.METHOD_NOT_FOUND]: {
|
|
1644
1749
|
message: "\u65B9\u6CD5\u4E0D\u5B58\u5728",
|
|
1645
1750
|
hint: "\u5DE5\u5177\u540D\u79F0\u8F93\u5165\u9519\u8BEF\u3002\u4F7F\u7528 search_tools \u641C\u7D22\u53EF\u7528\u5DE5\u5177\uFF0C\u6216 list_tools_by_category \u6D4F\u89C8\u5168\u90E8\u5206\u7C7B",
|
|
@@ -1784,8 +1889,8 @@ __export(renderer_exports, {
|
|
|
1784
1889
|
renderPrompt: () => renderPrompt,
|
|
1785
1890
|
renderTemplate: () => renderTemplate
|
|
1786
1891
|
});
|
|
1787
|
-
function resolvePath(obj,
|
|
1788
|
-
const parts =
|
|
1892
|
+
function resolvePath(obj, path21) {
|
|
1893
|
+
const parts = path21.split(/[.\[\]]/g).filter(Boolean);
|
|
1789
1894
|
let val = obj;
|
|
1790
1895
|
for (const p of parts) {
|
|
1791
1896
|
if (val == null) return void 0;
|
|
@@ -1795,8 +1900,8 @@ function resolvePath(obj, path20) {
|
|
|
1795
1900
|
}
|
|
1796
1901
|
function renderTemplate(template, args) {
|
|
1797
1902
|
return template.replace(PARAM_RE, (match, rawExpr, expr) => {
|
|
1798
|
-
const
|
|
1799
|
-
const val = resolvePath(args,
|
|
1903
|
+
const path21 = rawExpr || expr;
|
|
1904
|
+
const val = resolvePath(args, path21);
|
|
1800
1905
|
if (val == null) return "";
|
|
1801
1906
|
const strVal = String(val);
|
|
1802
1907
|
if (rawExpr) return strVal;
|
|
@@ -2228,8 +2333,8 @@ var init_sse_session = __esm({
|
|
|
2228
2333
|
sendMessage(data) {
|
|
2229
2334
|
return this.sendEvent(SSE_EVENTS.MESSAGE, data);
|
|
2230
2335
|
}
|
|
2231
|
-
sendEndpoint(
|
|
2232
|
-
return this.sendEvent(SSE_EVENTS.ENDPOINT,
|
|
2336
|
+
sendEndpoint(path21) {
|
|
2337
|
+
return this.sendEvent(SSE_EVENTS.ENDPOINT, path21);
|
|
2233
2338
|
}
|
|
2234
2339
|
sendError(code, message, id = null) {
|
|
2235
2340
|
return this.sendEvent(SSE_EVENTS.ERROR, { code, message }, id);
|
|
@@ -2951,7 +3056,8 @@ var init_info_tools = __esm({
|
|
|
2951
3056
|
}
|
|
2952
3057
|
},
|
|
2953
3058
|
{ name: "search_tools", description: "\u6309\u5173\u952E\u8BCD\u641C\u7D22\u53EF\u7528\u5DE5\u5177", inputSchema: { type: "object", properties: { query: { type: "string", description: "\u641C\u7D22\u5173\u952E\u8BCD(\u5339\u914D\u540D\u79F0\u548C\u63CF\u8FF0)" } }, required: ["query"] } },
|
|
2954
|
-
{ name: "list_tools_by_category", description: "\u6309\u5206\u7C7B\u5217\u51FA\u5DE5\u5177", inputSchema: { type: "object", properties: { category: { type: "string", description: "\u5206\u7C7B\u540D\u79F0(\u53EF\u9009,\u4E0D\u4F20\u5219\u5217\u51FA\u6240\u6709\u5206\u7C7B)" } } } }
|
|
3059
|
+
{ name: "list_tools_by_category", description: "\u6309\u5206\u7C7B\u5217\u51FA\u5DE5\u5177", inputSchema: { type: "object", properties: { category: { type: "string", description: "\u5206\u7C7B\u540D\u79F0(\u53EF\u9009,\u4E0D\u4F20\u5219\u5217\u51FA\u6240\u6709\u5206\u7C7B)" } } } },
|
|
3060
|
+
{ name: "get_tool_info", description: "\u83B7\u53D6\u5DE5\u5177\u7684\u8BE6\u7EC6\u4FE1\u606F\uFF08\u53C2\u6570\u3001\u5206\u7C7B\u3001\u53EA\u8BFB/\u7834\u574F\u6027\u6807\u8BB0\u7B49\uFF09", inputSchema: { type: "object", properties: { name: { type: "string", description: "\u5DE5\u5177\u540D\u79F0" } }, required: ["name"] } }
|
|
2955
3061
|
];
|
|
2956
3062
|
}
|
|
2957
3063
|
});
|
|
@@ -5492,12 +5598,12 @@ var init_pool_tools = __esm({
|
|
|
5492
5598
|
inputSchema: {
|
|
5493
5599
|
type: "object",
|
|
5494
5600
|
properties: {
|
|
5495
|
-
key: { type: "string", description: "\u5B9E\u4F8B\u6807\u8BC6\u952E\u540D\uFF08\u5982 autocad, zwcad, mycad\uFF09" },
|
|
5601
|
+
key: { type: "string", description: "\u5B9E\u4F8B\u6807\u8BC6\u952E\u540D\uFF08\u5982 autocad, zwcad, mycad\uFF1B\u4E0D\u4F20\u65F6\u7531 pid \u81EA\u52A8\u6D3E\u751F\uFF09" },
|
|
5496
5602
|
platform: { type: "string", description: "CAD \u5E73\u53F0: AutoCAD, ZWCAD, GStarCAD, BricsCAD\uFF08\u53EF\u9009\uFF0C\u81EA\u52A8\u68C0\u6D4B\uFF09" },
|
|
5603
|
+
pid: { type: "number", description: "\u76EE\u6807\u8FDB\u7A0B PID\uFF08\u53EF\u9009\uFF0C\u901A\u8FC7 ROT \u67E5\u627E\u540E\u8FDE\u63A5\uFF0C\u53EF\u4E0E pid \u81EA\u52A8\u6D3E\u751F key\uFF09" },
|
|
5497
5604
|
label: { type: "string", description: "\u5B9E\u4F8B\u663E\u793A\u6807\u7B7E\uFF08\u53EF\u9009\uFF09" },
|
|
5498
5605
|
makeActive: { type: "boolean", description: "\u8FDE\u63A5\u540E\u8BBE\u4E3A\u6D3B\u52A8\u5B9E\u4F8B\uFF08\u9ED8\u8BA4 true\uFF09" }
|
|
5499
|
-
}
|
|
5500
|
-
required: ["key"]
|
|
5606
|
+
}
|
|
5501
5607
|
}
|
|
5502
5608
|
},
|
|
5503
5609
|
{
|
|
@@ -6374,7 +6480,149 @@ var init_lint_tools = __esm({
|
|
|
6374
6480
|
}
|
|
6375
6481
|
});
|
|
6376
6482
|
|
|
6483
|
+
// src/tools/debug-tools.js
|
|
6484
|
+
var tools41;
|
|
6485
|
+
var init_debug_tools = __esm({
|
|
6486
|
+
"src/tools/debug-tools.js"() {
|
|
6487
|
+
tools41 = [
|
|
6488
|
+
{
|
|
6489
|
+
name: "debug_start",
|
|
6490
|
+
description: "\u542F\u52A8\u4EA4\u4E92\u5F0F\u8C03\u8BD5\u4F1A\u8BDD\u3002\u5C06\u4EE3\u7801\u6309\u5757\u62C6\u5206\u4E3A\u65AD\u70B9\u7EA7\u6267\u884C\uFF0C\u52A0\u8F7D\u8C03\u8BD5\u8F85\u52A9\u51FD\u6570\u5230 CAD\uFF0C\u8DF3\u8FC7\u975E\u65AD\u70B9\u524D\u7F6E\u5757",
|
|
6491
|
+
inputSchema: {
|
|
6492
|
+
type: "object",
|
|
6493
|
+
properties: {
|
|
6494
|
+
code: { type: "string", description: "\u539F\u59CB AutoLISP \u4EE3\u7801" },
|
|
6495
|
+
chunks: {
|
|
6496
|
+
type: "array",
|
|
6497
|
+
description: "\u7531\u6269\u5C55\u7AEF\u62C6\u5206\u597D\u7684\u4EE3\u7801\u5757\u5217\u8868",
|
|
6498
|
+
items: {
|
|
6499
|
+
type: "object",
|
|
6500
|
+
properties: {
|
|
6501
|
+
id: { type: "integer", description: "\u5757\u5E8F\u53F7 (1-based)" },
|
|
6502
|
+
line: { type: "integer", description: "\u6E90\u6587\u4EF6\u884C\u53F7" },
|
|
6503
|
+
code: { type: "string", description: "\u5757\u7684 AutoLISP \u4EE3\u7801" },
|
|
6504
|
+
vars: { type: "array", items: { type: "string" }, description: "\u8BE5\u5757\u9700\u6355\u83B7\u7684\u53D8\u91CF\u540D" },
|
|
6505
|
+
isBreakpoint: { type: "boolean", description: "\u8BE5\u884C\u6709\u65AD\u70B9" },
|
|
6506
|
+
isDefunStart: { type: "boolean", description: "\u662F defun \u5B9A\u4E49\u5F00\u5934" }
|
|
6507
|
+
},
|
|
6508
|
+
required: ["id", "line", "code", "vars", "isBreakpoint"]
|
|
6509
|
+
}
|
|
6510
|
+
},
|
|
6511
|
+
encoding: { type: "string", description: "\u7F16\u7801\uFF08\u9ED8\u8BA4 auto\uFF09" }
|
|
6512
|
+
},
|
|
6513
|
+
required: ["code", "chunks"]
|
|
6514
|
+
}
|
|
6515
|
+
},
|
|
6516
|
+
{
|
|
6517
|
+
name: "debug_step",
|
|
6518
|
+
description: "\u6267\u884C\u4E00\u6B65\uFF08step\uFF09\u6216\u7EE7\u7EED\u5230\u4E0B\u4E00\u65AD\u70B9\uFF08continue\uFF09",
|
|
6519
|
+
inputSchema: {
|
|
6520
|
+
type: "object",
|
|
6521
|
+
properties: {
|
|
6522
|
+
sessionId: { type: "string", description: "\u8C03\u8BD5\u4F1A\u8BDD ID" },
|
|
6523
|
+
action: { type: "string", enum: ["step", "continue"], description: "step=\u6267\u884C\u4E00\u4E2A\u5757, continue=\u5230\u4E0B\u4E00\u65AD\u70B9/\u7ED3\u675F" }
|
|
6524
|
+
},
|
|
6525
|
+
required: ["sessionId", "action"]
|
|
6526
|
+
}
|
|
6527
|
+
},
|
|
6528
|
+
{
|
|
6529
|
+
name: "debug_evaluate",
|
|
6530
|
+
description: "\u8C03\u8BD5\u6682\u505C\u65F6\u6C42\u503C AutoLISP \u8868\u8FBE\u5F0F",
|
|
6531
|
+
inputSchema: {
|
|
6532
|
+
type: "object",
|
|
6533
|
+
properties: {
|
|
6534
|
+
sessionId: { type: "string", description: "\u8C03\u8BD5\u4F1A\u8BDD ID" },
|
|
6535
|
+
expression: { type: "string", description: "\u4EFB\u610F AutoLISP \u8868\u8FBE\u5F0F" }
|
|
6536
|
+
},
|
|
6537
|
+
required: ["sessionId", "expression"]
|
|
6538
|
+
}
|
|
6539
|
+
},
|
|
6540
|
+
{
|
|
6541
|
+
name: "debug_get_state",
|
|
6542
|
+
description: "\u67E5\u8BE2\u8C03\u8BD5\u4F1A\u8BDD\u5F53\u524D\u72B6\u6001",
|
|
6543
|
+
inputSchema: {
|
|
6544
|
+
type: "object",
|
|
6545
|
+
properties: {
|
|
6546
|
+
sessionId: { type: "string", description: "\u8C03\u8BD5\u4F1A\u8BDD ID" }
|
|
6547
|
+
},
|
|
6548
|
+
required: ["sessionId"]
|
|
6549
|
+
}
|
|
6550
|
+
},
|
|
6551
|
+
{
|
|
6552
|
+
name: "debug_stop",
|
|
6553
|
+
description: "\u505C\u6B62\u8C03\u8BD5\u4F1A\u8BDD\uFF0C\u6E05\u7406 CAD \u5168\u5C40\u53D8\u91CF\u548C\u8F85\u52A9\u51FD\u6570",
|
|
6554
|
+
inputSchema: {
|
|
6555
|
+
type: "object",
|
|
6556
|
+
properties: {
|
|
6557
|
+
sessionId: { type: "string", description: "\u8C03\u8BD5\u4F1A\u8BDD ID" }
|
|
6558
|
+
},
|
|
6559
|
+
required: ["sessionId"]
|
|
6560
|
+
}
|
|
6561
|
+
}
|
|
6562
|
+
];
|
|
6563
|
+
}
|
|
6564
|
+
});
|
|
6565
|
+
|
|
6566
|
+
// src/tools/concurrent-tools.js
|
|
6567
|
+
var tools42;
|
|
6568
|
+
var init_concurrent_tools = __esm({
|
|
6569
|
+
"src/tools/concurrent-tools.js"() {
|
|
6570
|
+
tools42 = [
|
|
6571
|
+
{
|
|
6572
|
+
name: "batch_concurrent_tasks",
|
|
6573
|
+
description: "\u5E76\u53D1\u6267\u884C\u591A\u5B9E\u4F8B\u5DE5\u5177 \u2014 \u5C06\u591A\u4E2A\u5DE5\u5177\u8C03\u7528\u540C\u65F6\u8DEF\u7531\u5230\u4E0D\u540C CAD \u5B9E\u4F8B\u5E76\u884C\u6267\u884C\u3002\u5185\u90E8\u4F7F\u7528 Promise.allSettled\uFF0C\u4E00\u4E2A\u5931\u8D25\u4E0D\u5F71\u54CD\u5176\u4ED6\u3002",
|
|
6574
|
+
inputSchema: {
|
|
6575
|
+
type: "object",
|
|
6576
|
+
properties: {
|
|
6577
|
+
tasks: {
|
|
6578
|
+
type: "array",
|
|
6579
|
+
items: {
|
|
6580
|
+
type: "object",
|
|
6581
|
+
properties: {
|
|
6582
|
+
tool: { type: "string", description: "\u5DE5\u5177\u540D\u79F0" },
|
|
6583
|
+
args: { type: "object", description: "\u5DE5\u5177\u53C2\u6570\uFF08\u4E0D\u542B instance\uFF09" },
|
|
6584
|
+
instance: { type: "string", description: "\u76EE\u6807\u5B9E\u4F8B key" }
|
|
6585
|
+
},
|
|
6586
|
+
required: ["tool", "instance"]
|
|
6587
|
+
},
|
|
6588
|
+
description: "\u8981\u5E76\u53D1\u6267\u884C\u7684\u4EFB\u52A1\u5217\u8868"
|
|
6589
|
+
}
|
|
6590
|
+
},
|
|
6591
|
+
required: ["tasks"]
|
|
6592
|
+
}
|
|
6593
|
+
}
|
|
6594
|
+
];
|
|
6595
|
+
}
|
|
6596
|
+
});
|
|
6597
|
+
|
|
6377
6598
|
// src/tools/index.js
|
|
6599
|
+
function getToolCategory(name) {
|
|
6600
|
+
const n = name;
|
|
6601
|
+
if (/^(draw_|create_3d_|create_box|create_cone|create_cylinder|create_sphere|create_torus|create_wedge|extrude_|revolve_|boolean_|slice_solid|thicken_|offset_surface|create_loft_|create_region)/.test(n)) return "\u7ED8\u56FE\u4E0E3D";
|
|
6602
|
+
if (/^(move_|copy_|rotate_|scale_|mirror_|offset_|array_|batch_)/.test(n)) return "\u4FEE\u6539";
|
|
6603
|
+
if (/^(trim_|extend_|fillet|chamfer|break_|join_|stretch)/.test(n)) return "\u7F16\u8F91";
|
|
6604
|
+
if (/^(create_layer|delete_layer|set_layer|layer_)/.test(n)) return "\u56FE\u5C42";
|
|
6605
|
+
if (/^(create_block|insert_block|explode_block|get_block|set_block|batch_get_block|batch_set_block)/.test(n)) return "\u5757";
|
|
6606
|
+
if (/^(create_dim|list_dim|set_dim|create_hatch|set_hatch)/.test(n)) return "\u6807\u6CE8\u4E0E\u586B\u5145";
|
|
6607
|
+
if (/^(create_ucs|set_ucs|delete_ucs|list_ucs|get_current_ucs|create_layout|delete_layout|rename_layout|set_layout|list_layouts|get_current_layout)/.test(n)) return "\u5750\u6807\u7CFB\u4E0E\u5E03\u5C40";
|
|
6608
|
+
if (/^(create_viewport|set_viewport|lock_viewport|unlock_viewport|maximize_viewport)/.test(n)) return "\u89C6\u53E3";
|
|
6609
|
+
if (/^find_/.test(n)) return "\u7A7A\u95F4\u67E5\u8BE2";
|
|
6610
|
+
if (/^(select_|get_entity|set_entity|delete_entity|get_bounding_box)/.test(n)) return "\u9009\u62E9\u4E0E\u5C5E\u6027";
|
|
6611
|
+
if (/^(open_dwg|save_dwg|export_|import_|close_dwg|publish_)/.test(n)) return "\u6587\u4EF6";
|
|
6612
|
+
if (/^(plot_|save_pdf|batch_plot|publish_layouts)/.test(n)) return "\u6253\u5370";
|
|
6613
|
+
if (/^(get_xdata|set_xdata|delete_xdata|list_xdata|copxy_xdata|search_by_xdata|export_xdata|import_xdata)/.test(n)) return "\u6269\u5C55\u6570\u636E";
|
|
6614
|
+
if (/^(create_sheet|open_sheet|list_sheet|add_sheet|delete_sheet|publish_sheet|sheet_|reorder_sheet|create_subset|list_subset|set_sheet)/.test(n)) return "\u56FE\u7EB8\u96C6";
|
|
6615
|
+
if (/^(attach_|detach_|reload_|list_attached|get_pdf|create_dgn|create_dwf|import_dxf|import_dgn|export_dgn|create_hyper|remove_hyper|xref|bind_xref|clip_xref|path_xref)/.test(n)) return "\u53C2\u7167\u4E0E\u5E95\u56FE";
|
|
6616
|
+
if (/^(create_text|create_mleader|create_linetype|list_text|list_linetype|list_mleader|load_linetype|create_dimension_style|set_dimstyle|list_dimension_styles|set_mleader_style)/.test(n)) return "\u6837\u5F0F";
|
|
6617
|
+
if (/^(purge_|drawing_audit|drawing_recover|overkill)/.test(n)) return "\u6E05\u7406";
|
|
6618
|
+
if (/^(find_text|replace_text|set_text_|justify_|convert_text|explode_text)/.test(n)) return "\u6587\u5B57";
|
|
6619
|
+
if (/^(eval_lisp|connect_cad|get_cad|get_platform|get_system|at_command|new_document|bring_to_front|install_atlisp|init_atlisp|get_system_status)/.test(n)) return "\u7CFB\u7EDF";
|
|
6620
|
+
if (/^(list_packages|search_packages|install_package|get_function_usage|list_symbols|import_funlib)/.test(n)) return "\u5305\u4E0E\u51FD\u6570";
|
|
6621
|
+
if (/^(watch_|lisp_repl|webhook_|sandbox_|audit_|cad_pool_|external_|list_data|export_to|import_external)/.test(n)) return "\u9AD8\u7EA7";
|
|
6622
|
+
if (/^(list_prompts|get_prompt|search_tools|list_tools_by_category|get_tool_info)/.test(n)) return "\u5143\u5DE5\u5177";
|
|
6623
|
+
if (/^(agent_)/.test(n)) return "Agent\u4E0A\u4E0B\u6587";
|
|
6624
|
+
return "\u5176\u4ED6";
|
|
6625
|
+
}
|
|
6378
6626
|
function addAnnotations(tool) {
|
|
6379
6627
|
const isDeprecated = DEPRECATED_TOOLS.has(tool.name);
|
|
6380
6628
|
const isPoolTool = tool.name.startsWith("cad_pool_") || tool.name === "session_pin_instance" || tool.name === "session_unpin_instance";
|
|
@@ -6394,11 +6642,12 @@ function addAnnotations(tool) {
|
|
|
6394
6642
|
destructiveHint: tool.name.startsWith("delete_") || tool.name.startsWith("purge_") || tool.name.startsWith("boolean_") || EXTRA_DESTRUCTIVE.has(tool.name),
|
|
6395
6643
|
idempotentHint: READ_ONLY_TOOLS.has(tool.name) || IDEMPOTENT_WRITE_TOOLS.has(tool.name),
|
|
6396
6644
|
openWorldHint: OPEN_WORLD_TOOLS.has(tool.name),
|
|
6645
|
+
category: getToolCategory(tool.name),
|
|
6397
6646
|
...isDeprecated ? { deprecatedReason: "This tool has been superseded. Check documentation for alternatives." } : {}
|
|
6398
6647
|
}
|
|
6399
6648
|
};
|
|
6400
6649
|
}
|
|
6401
|
-
var READ_ONLY_TOOLS, DEPRECATED_TOOLS, EXTRA_DESTRUCTIVE, IDEMPOTENT_WRITE_TOOLS, OPEN_WORLD_TOOLS,
|
|
6650
|
+
var READ_ONLY_TOOLS, DEPRECATED_TOOLS, EXTRA_DESTRUCTIVE, IDEMPOTENT_WRITE_TOOLS, OPEN_WORLD_TOOLS, tools43, toolsByName;
|
|
6402
6651
|
var init_tools = __esm({
|
|
6403
6652
|
"src/tools/index.js"() {
|
|
6404
6653
|
init_cad_tools();
|
|
@@ -6441,6 +6690,8 @@ var init_tools = __esm({
|
|
|
6441
6690
|
init_context_tools();
|
|
6442
6691
|
init_batch_transaction_tools();
|
|
6443
6692
|
init_lint_tools();
|
|
6693
|
+
init_debug_tools();
|
|
6694
|
+
init_concurrent_tools();
|
|
6444
6695
|
READ_ONLY_TOOLS = /* @__PURE__ */ new Set([
|
|
6445
6696
|
"get_cad_info",
|
|
6446
6697
|
"get_platform_info",
|
|
@@ -6523,7 +6774,8 @@ var init_tools = __esm({
|
|
|
6523
6774
|
"analyze_lisp_code",
|
|
6524
6775
|
"format_lisp_code",
|
|
6525
6776
|
"list_lint_rules",
|
|
6526
|
-
"lint_project"
|
|
6777
|
+
"lint_project",
|
|
6778
|
+
"debug_get_state"
|
|
6527
6779
|
]);
|
|
6528
6780
|
DEPRECATED_TOOLS = /* @__PURE__ */ new Set([]);
|
|
6529
6781
|
EXTRA_DESTRUCTIVE = /* @__PURE__ */ new Set([
|
|
@@ -6579,7 +6831,7 @@ var init_tools = __esm({
|
|
|
6579
6831
|
"import_page_setup",
|
|
6580
6832
|
"load_linetype"
|
|
6581
6833
|
]);
|
|
6582
|
-
|
|
6834
|
+
tools43 = [
|
|
6583
6835
|
...tools,
|
|
6584
6836
|
...tools2,
|
|
6585
6837
|
...tools3,
|
|
@@ -6619,9 +6871,11 @@ var init_tools = __esm({
|
|
|
6619
6871
|
...tools38,
|
|
6620
6872
|
...tools39,
|
|
6621
6873
|
...tools37,
|
|
6622
|
-
...tools40
|
|
6874
|
+
...tools40,
|
|
6875
|
+
...tools41,
|
|
6876
|
+
...tools42
|
|
6623
6877
|
].map(addAnnotations);
|
|
6624
|
-
toolsByName = new Map(
|
|
6878
|
+
toolsByName = new Map(tools43.map((t) => [t.name, t]));
|
|
6625
6879
|
}
|
|
6626
6880
|
});
|
|
6627
6881
|
|
|
@@ -6674,7 +6928,7 @@ function parseLispList(str) {
|
|
|
6674
6928
|
});
|
|
6675
6929
|
}
|
|
6676
6930
|
function createMcpServer(handlers = {}) {
|
|
6677
|
-
const { tools:
|
|
6931
|
+
const { tools: tools44 = [], handleToolCall: handleToolCall2 = () => ({ content: [] }) } = handlers;
|
|
6678
6932
|
const server = new Server(
|
|
6679
6933
|
{ name: SERVER_NAME, version: SERVER_VERSION },
|
|
6680
6934
|
{
|
|
@@ -6697,8 +6951,8 @@ function createMcpServer(handlers = {}) {
|
|
|
6697
6951
|
const params = request.params || {};
|
|
6698
6952
|
const cursor = decodeCursor(params.cursor);
|
|
6699
6953
|
const PAGE_SIZE = 100;
|
|
6700
|
-
const page =
|
|
6701
|
-
const nextCursor = cursor + PAGE_SIZE <
|
|
6954
|
+
const page = tools44.slice(cursor, cursor + PAGE_SIZE);
|
|
6955
|
+
const nextCursor = cursor + PAGE_SIZE < tools44.length ? encodeCursor(cursor + PAGE_SIZE) : void 0;
|
|
6702
6956
|
return { tools: page, nextCursor };
|
|
6703
6957
|
});
|
|
6704
6958
|
server.setRequestHandler(CallToolRequestSchema, async (request) => {
|
|
@@ -7047,11 +7301,11 @@ function createMcpServer(handlers = {}) {
|
|
|
7047
7301
|
if (p.toLowerCase().startsWith(prefix)) values.push(p);
|
|
7048
7302
|
}
|
|
7049
7303
|
} else if (ref?.type === "tool") {
|
|
7050
|
-
for (const t of
|
|
7304
|
+
for (const t of tools44) {
|
|
7051
7305
|
if (t.name.toLowerCase().startsWith(prefix)) values.push(t.name);
|
|
7052
7306
|
}
|
|
7053
7307
|
} else if (ref?.type === "ref/parameter") {
|
|
7054
|
-
const toolDef =
|
|
7308
|
+
const toolDef = tools44.find((t) => t.name === ref.name);
|
|
7055
7309
|
if (toolDef?.inputSchema?.properties) {
|
|
7056
7310
|
const paramName = argument.name;
|
|
7057
7311
|
const paramDef = toolDef.inputSchema.properties[paramName];
|
|
@@ -8565,82 +8819,435 @@ var init_constraint_handlers = __esm({
|
|
|
8565
8819
|
}
|
|
8566
8820
|
});
|
|
8567
8821
|
|
|
8568
|
-
// src/
|
|
8569
|
-
|
|
8570
|
-
|
|
8571
|
-
batchSetLayer: () => batchSetLayer,
|
|
8572
|
-
createDimension: () => createDimension,
|
|
8573
|
-
createHatch: () => createHatch,
|
|
8574
|
-
createNamedView: () => createNamedView,
|
|
8575
|
-
exportDwf: () => exportDwf,
|
|
8576
|
-
exportDxf: () => exportDxf,
|
|
8577
|
-
getBlockAttributes: () => getBlockAttributes,
|
|
8578
|
-
getDimensionValue: () => getDimensionValue,
|
|
8579
|
-
listNamedViews: () => listNamedViews,
|
|
8580
|
-
restoreNamedView: () => restoreNamedView,
|
|
8581
|
-
setBlockAttribute: () => setBlockAttribute,
|
|
8582
|
-
setHatchProperties: () => setHatchProperties,
|
|
8583
|
-
zoomToExtents: () => zoomToExtents,
|
|
8584
|
-
zoomToWindow: () => zoomToWindow
|
|
8585
|
-
});
|
|
8586
|
-
function toSafePoint(pt) {
|
|
8587
|
-
const parts = (Array.isArray(pt) ? pt : String(pt).split(/[,\s]+/)).map(Number);
|
|
8588
|
-
return parts.filter((n) => !isNaN(n)).join(" ");
|
|
8589
|
-
}
|
|
8590
|
-
async function createDimension(type, points, style = {}) {
|
|
8822
|
+
// src/debug-engine.js
|
|
8823
|
+
import { randomUUID as randomUUID4 } from "crypto";
|
|
8824
|
+
async function ensureCad() {
|
|
8591
8825
|
if (!cad.connected) {
|
|
8826
|
+
log("Debug engine: CAD not connected, attempting auto-connect...");
|
|
8592
8827
|
await cad.connect();
|
|
8593
8828
|
}
|
|
8594
|
-
if (!cad.connected)
|
|
8595
|
-
|
|
8596
|
-
const validTypes = ["ALIGNED", "LINEAR", "ORDINATE", "RADIAL", "DIAMETER", "ANGULAR"];
|
|
8597
|
-
const dimType = (type || "ALIGNED").toUpperCase();
|
|
8598
|
-
if (!validTypes.includes(dimType)) {
|
|
8599
|
-
return { content: [{ type: "text", text: `\u4E0D\u652F\u6301\u7684\u6807\u6CE8\u7C7B\u578B: ${type}` }], isError: true };
|
|
8829
|
+
if (!cad.connected) {
|
|
8830
|
+
throw new Error("CAD \u672A\u8FDE\u63A5");
|
|
8600
8831
|
}
|
|
8601
|
-
|
|
8602
|
-
|
|
8603
|
-
|
|
8604
|
-
|
|
8605
|
-
|
|
8606
|
-
|
|
8607
|
-
|
|
8608
|
-
|
|
8609
|
-
|
|
8610
|
-
|
|
8611
|
-
|
|
8612
|
-
|
|
8613
|
-
|
|
8614
|
-
|
|
8615
|
-
|
|
8616
|
-
|
|
8617
|
-
|
|
8618
|
-
|
|
8619
|
-
|
|
8620
|
-
|
|
8621
|
-
|
|
8622
|
-
|
|
8623
|
-
break;
|
|
8832
|
+
}
|
|
8833
|
+
async function createSession(code, chunks, encoding) {
|
|
8834
|
+
if (sessions.size >= MAX_SESSIONS2) {
|
|
8835
|
+
let oldest = null;
|
|
8836
|
+
for (const [id, s] of sessions) {
|
|
8837
|
+
if (!oldest || s.createdAt < oldest.createdAt) oldest = { id, s };
|
|
8838
|
+
}
|
|
8839
|
+
if (oldest) {
|
|
8840
|
+
sessions.delete(oldest.id);
|
|
8841
|
+
log(`Debug session ${oldest.id} evicted (max sessions)`);
|
|
8842
|
+
}
|
|
8843
|
+
}
|
|
8844
|
+
if (!chunks || chunks.length === 0) {
|
|
8845
|
+
throw new Error("Chunks array is empty");
|
|
8846
|
+
}
|
|
8847
|
+
if (chunks.length > MAX_CHUNKS) {
|
|
8848
|
+
throw new Error(`Too many chunks: ${chunks.length} (max ${MAX_CHUNKS})`);
|
|
8849
|
+
}
|
|
8850
|
+
for (const chunk of chunks) {
|
|
8851
|
+
if (typeof chunk.id !== "number" || typeof chunk.code !== "string") {
|
|
8852
|
+
throw new Error("Each chunk must have id (number) and code (string)");
|
|
8853
|
+
}
|
|
8624
8854
|
}
|
|
8855
|
+
const sessionId = randomUUID4();
|
|
8856
|
+
const session = new DebugSession(sessionId, code, chunks, encoding);
|
|
8857
|
+
sessions.set(sessionId, session);
|
|
8858
|
+
return sessionId;
|
|
8859
|
+
}
|
|
8860
|
+
function getSession(id) {
|
|
8861
|
+
return sessions.get(id) || null;
|
|
8862
|
+
}
|
|
8863
|
+
async function closeSession(sessionId) {
|
|
8864
|
+
const session = sessions.get(sessionId);
|
|
8865
|
+
if (!session) return false;
|
|
8625
8866
|
try {
|
|
8626
|
-
|
|
8627
|
-
|
|
8867
|
+
if (cad.connected) {
|
|
8868
|
+
await cad.sendCommand(CLEANUP_CODE + "\n");
|
|
8869
|
+
}
|
|
8628
8870
|
} catch (e) {
|
|
8629
|
-
|
|
8871
|
+
log(`Debug cleanup warning: ${e.message}`);
|
|
8630
8872
|
}
|
|
8873
|
+
sessions.delete(sessionId);
|
|
8874
|
+
return true;
|
|
8631
8875
|
}
|
|
8632
|
-
async function
|
|
8633
|
-
|
|
8634
|
-
|
|
8876
|
+
async function loadHelpers(session) {
|
|
8877
|
+
await ensureCad();
|
|
8878
|
+
try {
|
|
8879
|
+
await cad.sendCommand(HELPER_DEFUNS + "\n");
|
|
8880
|
+
} catch (e) {
|
|
8881
|
+
throw new Error(`Failed to load debug helpers: ${e.message}`);
|
|
8635
8882
|
}
|
|
8636
|
-
|
|
8637
|
-
|
|
8638
|
-
|
|
8639
|
-
|
|
8640
|
-
|
|
8641
|
-
|
|
8642
|
-
|
|
8643
|
-
|
|
8883
|
+
}
|
|
8884
|
+
async function fastForward(session) {
|
|
8885
|
+
await ensureCad();
|
|
8886
|
+
session.state = "running";
|
|
8887
|
+
while (session.currentIndex < session.totalChunks) {
|
|
8888
|
+
const chunk = session.chunks[session.currentIndex];
|
|
8889
|
+
if (chunk.isBreakpoint) break;
|
|
8890
|
+
try {
|
|
8891
|
+
await cad.sendCommandWithResult(chunk.code, session.encoding);
|
|
8892
|
+
} catch (e) {
|
|
8893
|
+
session.state = "error";
|
|
8894
|
+
session.error = `Fast-forward error at chunk ${chunk.id}: ${e.message}`;
|
|
8895
|
+
throw new Error(session.error);
|
|
8896
|
+
}
|
|
8897
|
+
session.currentIndex++;
|
|
8898
|
+
}
|
|
8899
|
+
if (session.currentIndex >= session.totalChunks) {
|
|
8900
|
+
session.state = "done";
|
|
8901
|
+
return {
|
|
8902
|
+
done: true,
|
|
8903
|
+
finalResult: session.finalResult
|
|
8904
|
+
};
|
|
8905
|
+
}
|
|
8906
|
+
session.state = "paused";
|
|
8907
|
+
return {
|
|
8908
|
+
done: false,
|
|
8909
|
+
pausedAt: {
|
|
8910
|
+
id: session.chunks[session.currentIndex].id,
|
|
8911
|
+
line: session.chunks[session.currentIndex].line
|
|
8912
|
+
}
|
|
8913
|
+
};
|
|
8914
|
+
}
|
|
8915
|
+
async function executeStep(session) {
|
|
8916
|
+
await ensureCad();
|
|
8917
|
+
if (session.state !== "paused" && session.state !== "ready") {
|
|
8918
|
+
throw new Error(`Invalid state: ${session.state} (expected paused or ready)`);
|
|
8919
|
+
}
|
|
8920
|
+
if (session.currentIndex >= session.totalChunks) {
|
|
8921
|
+
session.state = "done";
|
|
8922
|
+
return { done: true, finalResult: session.finalResult };
|
|
8923
|
+
}
|
|
8924
|
+
const chunk = session.chunks[session.currentIndex];
|
|
8925
|
+
const vars = chunk.vars || [];
|
|
8926
|
+
session.state = "running";
|
|
8927
|
+
let rawResult;
|
|
8928
|
+
try {
|
|
8929
|
+
const varCapture = vars.length > 0 ? `(mapcar (function (lambda (v) (list (vl-prin1-to-string v) (if (boundp v) (vl-prin1-to-string (eval v)) nil)))) (list ${vars.map((v) => `'${v}`).join(" ")})` : "nil";
|
|
8930
|
+
const lispCode = `(progn
|
|
8931
|
+
(setq @::dbg/result (progn ${chunk.code}))
|
|
8932
|
+
(list
|
|
8933
|
+
(vl-prin1-to-string @::dbg/result)
|
|
8934
|
+
${varCapture}))`;
|
|
8935
|
+
rawResult = await cad.sendCommandWithResult(lispCode, session.encoding);
|
|
8936
|
+
} catch (e) {
|
|
8937
|
+
session.state = "error";
|
|
8938
|
+
session.error = `Step error at chunk ${chunk.id}: ${e.message}`;
|
|
8939
|
+
throw new Error(session.error);
|
|
8940
|
+
}
|
|
8941
|
+
session.currentIndex++;
|
|
8942
|
+
session.finalResult = rawResult;
|
|
8943
|
+
let parsedResult = rawResult;
|
|
8944
|
+
let variables = [];
|
|
8945
|
+
try {
|
|
8946
|
+
const parsed = parseLispRecursive(rawResult);
|
|
8947
|
+
if (Array.isArray(parsed) && parsed.length >= 2) {
|
|
8948
|
+
parsedResult = parsed[0] !== null ? String(parsed[0]) : "nil";
|
|
8949
|
+
if (Array.isArray(parsed[1])) {
|
|
8950
|
+
variables = parsed[1].map((item) => {
|
|
8951
|
+
if (Array.isArray(item) && item.length >= 2) {
|
|
8952
|
+
return { name: String(item[0] || ""), value: item[1] !== null ? String(item[1]) : "nil" };
|
|
8953
|
+
}
|
|
8954
|
+
return null;
|
|
8955
|
+
}).filter(Boolean);
|
|
8956
|
+
}
|
|
8957
|
+
}
|
|
8958
|
+
} catch {
|
|
8959
|
+
parsedResult = rawResult || "nil";
|
|
8960
|
+
}
|
|
8961
|
+
const checkpoint = {
|
|
8962
|
+
id: chunk.id,
|
|
8963
|
+
line: chunk.line,
|
|
8964
|
+
variables,
|
|
8965
|
+
result: parsedResult
|
|
8966
|
+
};
|
|
8967
|
+
session.lastCheckpoint = checkpoint;
|
|
8968
|
+
if (session.currentIndex >= session.totalChunks) {
|
|
8969
|
+
session.state = "done";
|
|
8970
|
+
return {
|
|
8971
|
+
done: true,
|
|
8972
|
+
checkpoint,
|
|
8973
|
+
finalResult: parsedResult
|
|
8974
|
+
};
|
|
8975
|
+
}
|
|
8976
|
+
session.state = "paused";
|
|
8977
|
+
return { done: false, checkpoint };
|
|
8978
|
+
}
|
|
8979
|
+
async function continueExecution(session) {
|
|
8980
|
+
await ensureCad();
|
|
8981
|
+
if (session.state !== "paused" && session.state !== "ready") {
|
|
8982
|
+
throw new Error(`Invalid state: ${session.state} (expected paused or ready)`);
|
|
8983
|
+
}
|
|
8984
|
+
while (session.currentIndex < session.totalChunks) {
|
|
8985
|
+
const chunk = session.chunks[session.currentIndex];
|
|
8986
|
+
if (chunk.isBreakpoint) {
|
|
8987
|
+
return await executeStep(session);
|
|
8988
|
+
}
|
|
8989
|
+
try {
|
|
8990
|
+
await cad.sendCommandWithResult(chunk.code, session.encoding);
|
|
8991
|
+
} catch (e) {
|
|
8992
|
+
session.state = "error";
|
|
8993
|
+
session.error = `Continue error at chunk ${chunk.id}: ${e.message}`;
|
|
8994
|
+
throw new Error(session.error);
|
|
8995
|
+
}
|
|
8996
|
+
session.currentIndex++;
|
|
8997
|
+
session.finalResult = null;
|
|
8998
|
+
}
|
|
8999
|
+
session.state = "done";
|
|
9000
|
+
return { done: true, finalResult: session.finalResult };
|
|
9001
|
+
}
|
|
9002
|
+
async function evaluateExpression(session, expression) {
|
|
9003
|
+
await ensureCad();
|
|
9004
|
+
if (session.state !== "paused") {
|
|
9005
|
+
throw new Error(`Invalid state: ${session.state} (expected paused)`);
|
|
9006
|
+
}
|
|
9007
|
+
try {
|
|
9008
|
+
const result = await cad.sendCommandWithResult(`(vl-prin1-to-string ${expression})`, session.encoding);
|
|
9009
|
+
return { value: result || "nil" };
|
|
9010
|
+
} catch (e) {
|
|
9011
|
+
return { error: `CAD error: ${e.message}` };
|
|
9012
|
+
}
|
|
9013
|
+
}
|
|
9014
|
+
var sessions, MAX_SESSIONS2, MAX_CHUNKS, HELPER_DEFUNS, CLEANUP_CODE, DebugSession;
|
|
9015
|
+
var init_debug_engine = __esm({
|
|
9016
|
+
"src/debug-engine.js"() {
|
|
9017
|
+
init_cad();
|
|
9018
|
+
init_logger();
|
|
9019
|
+
init_handler_utils();
|
|
9020
|
+
sessions = /* @__PURE__ */ new Map();
|
|
9021
|
+
MAX_SESSIONS2 = 10;
|
|
9022
|
+
MAX_CHUNKS = 500;
|
|
9023
|
+
HELPER_DEFUNS = `
|
|
9024
|
+
(defun @::dbg/exec-chunk (chunk-code var-names)
|
|
9025
|
+
(setq @::dbg/result (eval (read chunk-code)))
|
|
9026
|
+
(if var-names
|
|
9027
|
+
(setq @::dbg/snapshot
|
|
9028
|
+
(mapcar
|
|
9029
|
+
(function (lambda (v)
|
|
9030
|
+
(list (vl-prin1-to-string v)
|
|
9031
|
+
(if (boundp v) (vl-prin1-to-string (eval v)) nil))))
|
|
9032
|
+
var-names))
|
|
9033
|
+
(setq @::dbg/snapshot nil))
|
|
9034
|
+
(list @::dbg/result @::dbg/snapshot))
|
|
9035
|
+
`;
|
|
9036
|
+
CLEANUP_CODE = `
|
|
9037
|
+
(if (not (vl-catch-all-error-p (vl-catch-all-apply (function (lambda ()
|
|
9038
|
+
(mapcar (function (lambda (s) (set s nil)))
|
|
9039
|
+
(quote (@::dbg/result @::dbg/snapshot @::dbg/state @::dbg/chunks @::dbg/idx @::dbg/encoding))))))))
|
|
9040
|
+
(princ "ok"))
|
|
9041
|
+
`;
|
|
9042
|
+
DebugSession = class {
|
|
9043
|
+
constructor(sessionId, code, chunks, encoding) {
|
|
9044
|
+
this.sessionId = sessionId;
|
|
9045
|
+
this.code = code;
|
|
9046
|
+
this.chunks = chunks;
|
|
9047
|
+
this.totalChunks = chunks.length;
|
|
9048
|
+
this.currentIndex = 0;
|
|
9049
|
+
this.encoding = encoding || null;
|
|
9050
|
+
this.state = "ready";
|
|
9051
|
+
this.lastCheckpoint = null;
|
|
9052
|
+
this.finalResult = null;
|
|
9053
|
+
this.createdAt = Date.now();
|
|
9054
|
+
this.error = null;
|
|
9055
|
+
}
|
|
9056
|
+
};
|
|
9057
|
+
}
|
|
9058
|
+
});
|
|
9059
|
+
|
|
9060
|
+
// src/handlers/debug-handlers.js
|
|
9061
|
+
var debug_handlers_exports = {};
|
|
9062
|
+
__export(debug_handlers_exports, {
|
|
9063
|
+
debugEvaluate: () => debugEvaluate,
|
|
9064
|
+
debugGetState: () => debugGetState,
|
|
9065
|
+
debugStart: () => debugStart,
|
|
9066
|
+
debugStep: () => debugStep,
|
|
9067
|
+
debugStop: () => debugStop
|
|
9068
|
+
});
|
|
9069
|
+
async function debugGetState(args) {
|
|
9070
|
+
try {
|
|
9071
|
+
const { sessionId } = args || {};
|
|
9072
|
+
if (!sessionId) return mcpError("Missing required argument: sessionId");
|
|
9073
|
+
const session = getSession(sessionId);
|
|
9074
|
+
if (!session) return mcpError(`Debug session not found: ${sessionId}`);
|
|
9075
|
+
const checkpoint = session.lastCheckpoint;
|
|
9076
|
+
return mcpSuccess(JSON.stringify({
|
|
9077
|
+
state: session.state,
|
|
9078
|
+
currentIndex: session.currentIndex,
|
|
9079
|
+
totalChunks: session.totalChunks,
|
|
9080
|
+
currentCheckpoint: checkpoint || void 0,
|
|
9081
|
+
error: session.error
|
|
9082
|
+
}));
|
|
9083
|
+
} catch (e) {
|
|
9084
|
+
return mcpError(e.message);
|
|
9085
|
+
}
|
|
9086
|
+
}
|
|
9087
|
+
async function debugStop(args) {
|
|
9088
|
+
try {
|
|
9089
|
+
const { sessionId } = args || {};
|
|
9090
|
+
if (!sessionId) return mcpError("Missing required argument: sessionId");
|
|
9091
|
+
const session = getSession(sessionId);
|
|
9092
|
+
if (!session) {
|
|
9093
|
+
return mcpError(`Debug session not found: ${sessionId}`);
|
|
9094
|
+
}
|
|
9095
|
+
const ok = await closeSession(sessionId);
|
|
9096
|
+
return mcpSuccess(JSON.stringify({ success: ok }));
|
|
9097
|
+
} catch (e) {
|
|
9098
|
+
return mcpError(e.message);
|
|
9099
|
+
}
|
|
9100
|
+
}
|
|
9101
|
+
var debugStart, debugStep, debugEvaluate;
|
|
9102
|
+
var init_debug_handlers = __esm({
|
|
9103
|
+
"src/handlers/debug-handlers.js"() {
|
|
9104
|
+
init_handler_utils();
|
|
9105
|
+
init_debug_engine();
|
|
9106
|
+
debugStart = withCadConnection(async (args) => {
|
|
9107
|
+
try {
|
|
9108
|
+
const { code, chunks, encoding } = args || {};
|
|
9109
|
+
if (!code) return mcpError("Missing required argument: code");
|
|
9110
|
+
if (!chunks || !Array.isArray(chunks)) return mcpError("Missing required argument: chunks (must be an array)");
|
|
9111
|
+
const sessionId = await createSession(code, chunks, encoding);
|
|
9112
|
+
const session = getSession(sessionId);
|
|
9113
|
+
if (!session) return mcpError("Failed to create debug session");
|
|
9114
|
+
await loadHelpers(session);
|
|
9115
|
+
const ffResult = await fastForward(session);
|
|
9116
|
+
if (session.state === "error") {
|
|
9117
|
+
await closeSession(sessionId);
|
|
9118
|
+
return mcpError(session.error);
|
|
9119
|
+
}
|
|
9120
|
+
return mcpSuccess(JSON.stringify({
|
|
9121
|
+
sessionId,
|
|
9122
|
+
totalChunks: session.totalChunks,
|
|
9123
|
+
...ffResult
|
|
9124
|
+
}));
|
|
9125
|
+
} catch (e) {
|
|
9126
|
+
return mcpError(e.message);
|
|
9127
|
+
}
|
|
9128
|
+
});
|
|
9129
|
+
debugStep = withCadConnection(async (args) => {
|
|
9130
|
+
try {
|
|
9131
|
+
const { sessionId, action } = args || {};
|
|
9132
|
+
if (!sessionId) return mcpError("Missing required argument: sessionId");
|
|
9133
|
+
if (!action) return mcpError("Missing required argument: action");
|
|
9134
|
+
const session = getSession(sessionId);
|
|
9135
|
+
if (!session) return mcpError(`Debug session not found: ${sessionId}`);
|
|
9136
|
+
if (session.state !== "paused" && session.state !== "ready") {
|
|
9137
|
+
return mcpError(`Invalid state: ${session.state} (expected paused or ready)`);
|
|
9138
|
+
}
|
|
9139
|
+
let result;
|
|
9140
|
+
if (action === "step") {
|
|
9141
|
+
result = await executeStep(session);
|
|
9142
|
+
} else if (action === "continue") {
|
|
9143
|
+
result = await continueExecution(session);
|
|
9144
|
+
} else {
|
|
9145
|
+
return mcpError(`Invalid action: ${action} (expected step or continue)`);
|
|
9146
|
+
}
|
|
9147
|
+
if (session.state === "error") {
|
|
9148
|
+
return mcpError(session.error);
|
|
9149
|
+
}
|
|
9150
|
+
return mcpSuccess(JSON.stringify(result));
|
|
9151
|
+
} catch (e) {
|
|
9152
|
+
return mcpError(e.message);
|
|
9153
|
+
}
|
|
9154
|
+
});
|
|
9155
|
+
debugEvaluate = withCadConnection(async (args) => {
|
|
9156
|
+
try {
|
|
9157
|
+
const { sessionId, expression } = args || {};
|
|
9158
|
+
if (!sessionId) return mcpError("Missing required argument: sessionId");
|
|
9159
|
+
if (!expression) return mcpError("Missing required argument: expression");
|
|
9160
|
+
const session = getSession(sessionId);
|
|
9161
|
+
if (!session) return mcpError(`Debug session not found: ${sessionId}`);
|
|
9162
|
+
if (session.state !== "paused") {
|
|
9163
|
+
return mcpError(`Invalid state: ${session.state} (expected paused)`);
|
|
9164
|
+
}
|
|
9165
|
+
const result = await evaluateExpression(session, expression);
|
|
9166
|
+
if (result.error) return mcpError(result.error);
|
|
9167
|
+
return mcpSuccess(JSON.stringify({ value: result.value }));
|
|
9168
|
+
} catch (e) {
|
|
9169
|
+
return mcpError(e.message);
|
|
9170
|
+
}
|
|
9171
|
+
});
|
|
9172
|
+
}
|
|
9173
|
+
});
|
|
9174
|
+
|
|
9175
|
+
// src/handlers/dim-hatch-handlers.js
|
|
9176
|
+
var dim_hatch_handlers_exports = {};
|
|
9177
|
+
__export(dim_hatch_handlers_exports, {
|
|
9178
|
+
batchSetLayer: () => batchSetLayer,
|
|
9179
|
+
createDimension: () => createDimension,
|
|
9180
|
+
createHatch: () => createHatch,
|
|
9181
|
+
createNamedView: () => createNamedView,
|
|
9182
|
+
exportDwf: () => exportDwf,
|
|
9183
|
+
exportDxf: () => exportDxf,
|
|
9184
|
+
getBlockAttributes: () => getBlockAttributes,
|
|
9185
|
+
getDimensionValue: () => getDimensionValue,
|
|
9186
|
+
listNamedViews: () => listNamedViews,
|
|
9187
|
+
restoreNamedView: () => restoreNamedView,
|
|
9188
|
+
setBlockAttribute: () => setBlockAttribute,
|
|
9189
|
+
setHatchProperties: () => setHatchProperties,
|
|
9190
|
+
zoomToExtents: () => zoomToExtents,
|
|
9191
|
+
zoomToWindow: () => zoomToWindow
|
|
9192
|
+
});
|
|
9193
|
+
function toSafePoint(pt) {
|
|
9194
|
+
const parts = (Array.isArray(pt) ? pt : String(pt).split(/[,\s]+/)).map(Number);
|
|
9195
|
+
return parts.filter((n) => !isNaN(n)).join(" ");
|
|
9196
|
+
}
|
|
9197
|
+
async function createDimension(type, points, style = {}) {
|
|
9198
|
+
if (!cad.connected) {
|
|
9199
|
+
await cad.connect();
|
|
9200
|
+
}
|
|
9201
|
+
if (!cad.connected) return { content: [{ type: "text", text: "\u672A\u8FDE\u63A5 CAD" }], isError: true };
|
|
9202
|
+
let dimCode = "";
|
|
9203
|
+
const validTypes = ["ALIGNED", "LINEAR", "ORDINATE", "RADIAL", "DIAMETER", "ANGULAR"];
|
|
9204
|
+
const dimType = (type || "ALIGNED").toUpperCase();
|
|
9205
|
+
if (!validTypes.includes(dimType)) {
|
|
9206
|
+
return { content: [{ type: "text", text: `\u4E0D\u652F\u6301\u7684\u6807\u6CE8\u7C7B\u578B: ${type}` }], isError: true };
|
|
9207
|
+
}
|
|
9208
|
+
const defPt = toSafePoint(points.defPt || "0,0");
|
|
9209
|
+
const pt1 = toSafePoint(points.pt1 || points.pt || "0,0");
|
|
9210
|
+
const pt2 = toSafePoint(points.pt2 || "100,0");
|
|
9211
|
+
const leaderLen = parseFloat(style.leaderLength) || 10;
|
|
9212
|
+
switch (dimType) {
|
|
9213
|
+
case "ALIGNED":
|
|
9214
|
+
dimCode = `(command "._DIMALIGNED" (list ${pt1}) (list ${pt2}) (list ${defPt}))`;
|
|
9215
|
+
break;
|
|
9216
|
+
case "LINEAR":
|
|
9217
|
+
dimCode = `(command "._DIMLINEAR" (list ${pt1}) (list ${pt2}) (list ${defPt}))`;
|
|
9218
|
+
break;
|
|
9219
|
+
case "ORDINATE":
|
|
9220
|
+
dimCode = `(command "._DIMORDINATE" (list ${pt1}) (list ${defPt}))`;
|
|
9221
|
+
break;
|
|
9222
|
+
case "RADIAL":
|
|
9223
|
+
dimCode = `(command "._DIMRADIUS" (list ${defPt}) "${leaderLen}")`;
|
|
9224
|
+
break;
|
|
9225
|
+
case "DIAMETER":
|
|
9226
|
+
dimCode = `(command "._DIMDIAMETER" (list ${defPt}) "${leaderLen}")`;
|
|
9227
|
+
break;
|
|
9228
|
+
case "ANGULAR":
|
|
9229
|
+
dimCode = `(command "._DIMANGULAR" (list ${pt1}) (list ${pt2}) (list ${defPt}))`;
|
|
9230
|
+
break;
|
|
9231
|
+
}
|
|
9232
|
+
try {
|
|
9233
|
+
await cad.sendCommand(dimCode + "\n");
|
|
9234
|
+
return { content: [{ type: "text", text: `\u5DF2\u521B\u5EFA ${dimType} \u6807\u6CE8` }] };
|
|
9235
|
+
} catch (e) {
|
|
9236
|
+
return { content: [{ type: "text", text: `\u9519\u8BEF: ${e.message}` }], isError: true };
|
|
9237
|
+
}
|
|
9238
|
+
}
|
|
9239
|
+
async function getDimensionValue(handle) {
|
|
9240
|
+
if (!cad.connected) {
|
|
9241
|
+
await cad.connect();
|
|
9242
|
+
}
|
|
9243
|
+
if (!cad.connected) return { content: [{ type: "text", text: "\u672A\u8FDE\u63A5 CAD" }], isError: true };
|
|
9244
|
+
const code = `(progn
|
|
9245
|
+
(vl-load-com)
|
|
9246
|
+
(if (setq ent (handent "${escapeLispString(handle)}"))
|
|
9247
|
+
(progn
|
|
9248
|
+
(setq ed (entget ent) typ (cdr (assoc 0 ed)))
|
|
9249
|
+
(if (wcmatch typ "DIMENSION")
|
|
9250
|
+
(list
|
|
8644
9251
|
"type" typ
|
|
8645
9252
|
"handle" (cdr (assoc 5 ed))
|
|
8646
9253
|
"layer" (cdr (assoc 8 ed))
|
|
@@ -10231,6 +10838,87 @@ var init_lint_handlers = __esm({
|
|
|
10231
10838
|
}
|
|
10232
10839
|
});
|
|
10233
10840
|
|
|
10841
|
+
// src/handlers/meta-handlers.js
|
|
10842
|
+
var meta_handlers_exports = {};
|
|
10843
|
+
__export(meta_handlers_exports, {
|
|
10844
|
+
get_prompt_handler: () => get_prompt_handler,
|
|
10845
|
+
get_tool_info: () => get_tool_info,
|
|
10846
|
+
list_prompts_handler: () => list_prompts_handler,
|
|
10847
|
+
list_tools_by_category: () => list_tools_by_category,
|
|
10848
|
+
search_tools: () => search_tools
|
|
10849
|
+
});
|
|
10850
|
+
async function search_tools(a) {
|
|
10851
|
+
const q = (a.query || "").toLowerCase();
|
|
10852
|
+
const results = tools43.filter((t) => t.name.toLowerCase().includes(q) || (t.description || "").toLowerCase().includes(q));
|
|
10853
|
+
const text = results.length ? `\u627E\u5230 ${results.length} \u4E2A\u5DE5\u5177:
|
|
10854
|
+
${results.map((t) => `${t.name}: ${t.description}`).join("\n")}` : `\u672A\u627E\u5230\u5305\u542B "${a.query}" \u7684\u5DE5\u5177`;
|
|
10855
|
+
return { content: [{ type: "text", text }] };
|
|
10856
|
+
}
|
|
10857
|
+
async function list_tools_by_category(a) {
|
|
10858
|
+
const categories = {};
|
|
10859
|
+
for (const t of tools43) {
|
|
10860
|
+
const cat = t.annotations?.category || "\u5176\u4ED6";
|
|
10861
|
+
if (!categories[cat]) categories[cat] = [];
|
|
10862
|
+
categories[cat].push(t.name);
|
|
10863
|
+
}
|
|
10864
|
+
if (a.category) {
|
|
10865
|
+
const names = categories[a.category];
|
|
10866
|
+
return { content: [{ type: "text", text: names ? `${a.category} (${names.length}):
|
|
10867
|
+
${names.join("\n")}` : `\u672A\u627E\u5230\u5206\u7C7B: ${a.category}` }] };
|
|
10868
|
+
}
|
|
10869
|
+
const lines = [];
|
|
10870
|
+
for (const [cat, names] of Object.entries(categories)) {
|
|
10871
|
+
lines.push(`## ${cat} (${names.length})`);
|
|
10872
|
+
}
|
|
10873
|
+
lines.push(`
|
|
10874
|
+
\u5171 ${Object.keys(categories).length} \u4E2A\u5206\u7C7B`);
|
|
10875
|
+
return { content: [{ type: "text", text: lines.join("\n") }] };
|
|
10876
|
+
}
|
|
10877
|
+
async function get_tool_info(a) {
|
|
10878
|
+
if (!a.name) return { content: [{ type: "text", text: "\u9700\u8981 name \u53C2\u6570\uFF08\u5DE5\u5177\u540D\u79F0\uFF09" }], isError: true };
|
|
10879
|
+
const tool = tools43.find((t) => t.name === a.name);
|
|
10880
|
+
if (!tool) return { content: [{ type: "text", text: `\u672A\u627E\u5230\u5DE5\u5177: ${a.name}` }], isError: true };
|
|
10881
|
+
const ann = tool.annotations || {};
|
|
10882
|
+
const required = (tool.inputSchema?.required || []).join(", ") || "\u65E0";
|
|
10883
|
+
const props = tool.inputSchema?.properties || {};
|
|
10884
|
+
const params = Object.entries(props).map(([k, v]) => {
|
|
10885
|
+
const req = required.includes(k) ? "\u5FC5\u586B" : "\u53EF\u9009";
|
|
10886
|
+
const desc = v.description || "";
|
|
10887
|
+
return ` ${k} (${req}): ${desc}`;
|
|
10888
|
+
}).join("\n");
|
|
10889
|
+
const lines = [
|
|
10890
|
+
`## ${tool.name}`,
|
|
10891
|
+
`\u63CF\u8FF0: ${tool.description || "\u65E0"}`,
|
|
10892
|
+
`\u5206\u7C7B: ${ann.category || "\u5176\u4ED6"}`,
|
|
10893
|
+
`\u53EA\u8BFB: ${ann.readOnlyHint ? "\u662F" : "\u5426"}`,
|
|
10894
|
+
`\u7834\u574F\u6027: ${ann.destructiveHint ? "\u662F" : "\u5426"}`,
|
|
10895
|
+
`\u5E42\u7B49: ${ann.idempotentHint ? "\u662F" : "\u5426"}`,
|
|
10896
|
+
`\u5F00\u653E\u4E16\u754C: ${ann.openWorldHint ? "\u662F" : "\u5426"}`,
|
|
10897
|
+
``,
|
|
10898
|
+
`\u53C2\u6570:`,
|
|
10899
|
+
params || " \u65E0\u53C2\u6570"
|
|
10900
|
+
];
|
|
10901
|
+
if (ann.deprecatedReason) {
|
|
10902
|
+
lines.push(`
|
|
10903
|
+
\u5DF2\u5F03\u7528: ${ann.deprecatedReason}`);
|
|
10904
|
+
}
|
|
10905
|
+
return { content: [{ type: "text", text: lines.join("\n") }] };
|
|
10906
|
+
}
|
|
10907
|
+
async function list_prompts_handler() {
|
|
10908
|
+
const prompts = await listPrompts2();
|
|
10909
|
+
return { content: [{ type: "text", text: JSON.stringify(prompts) }] };
|
|
10910
|
+
}
|
|
10911
|
+
async function get_prompt_handler(a) {
|
|
10912
|
+
const prompt = await getPrompt2(a.name, a.args || {});
|
|
10913
|
+
return { content: prompt.messages.map((m) => ({ type: "text", text: m.content.text || m.content })) };
|
|
10914
|
+
}
|
|
10915
|
+
var init_meta_handlers = __esm({
|
|
10916
|
+
"src/handlers/meta-handlers.js"() {
|
|
10917
|
+
init_tools();
|
|
10918
|
+
init_prompt_handlers();
|
|
10919
|
+
}
|
|
10920
|
+
});
|
|
10921
|
+
|
|
10234
10922
|
// src/handlers/package-handlers.js
|
|
10235
10923
|
var package_handlers_exports = {};
|
|
10236
10924
|
__export(package_handlers_exports, {
|
|
@@ -10240,7 +10928,7 @@ __export(package_handlers_exports, {
|
|
|
10240
10928
|
});
|
|
10241
10929
|
async function fetchPackages() {
|
|
10242
10930
|
const now = Date.now();
|
|
10243
|
-
if (cachedPackages && cachedAt2 && now - cachedAt2 <
|
|
10931
|
+
if (cachedPackages && cachedAt2 && now - cachedAt2 < CACHE_TTL) {
|
|
10244
10932
|
return cachedPackages;
|
|
10245
10933
|
}
|
|
10246
10934
|
try {
|
|
@@ -10317,7 +11005,7 @@ async function installPackage(packageName) {
|
|
|
10317
11005
|
}
|
|
10318
11006
|
return { content: [{ type: "text", text: `\u5305 "${packageName}" \u5B89\u88C5\u547D\u4EE4\u5DF2\u53D1\u9001\uFF01` }] };
|
|
10319
11007
|
}
|
|
10320
|
-
var PACKAGES_LIST_URL, cachedPackages, cachedAt2,
|
|
11008
|
+
var PACKAGES_LIST_URL, cachedPackages, cachedAt2, CACHE_TTL;
|
|
10321
11009
|
var init_package_handlers = __esm({
|
|
10322
11010
|
"src/handlers/package-handlers.js"() {
|
|
10323
11011
|
init_logger();
|
|
@@ -10326,7 +11014,7 @@ var init_package_handlers = __esm({
|
|
|
10326
11014
|
PACKAGES_LIST_URL = process.env.PACKAGES_LIST_URL || "http://s3.atlisp.cn/packages-list?fmt=json";
|
|
10327
11015
|
cachedPackages = null;
|
|
10328
11016
|
cachedAt2 = null;
|
|
10329
|
-
|
|
11017
|
+
CACHE_TTL = 10 * 60 * 1e3;
|
|
10330
11018
|
}
|
|
10331
11019
|
});
|
|
10332
11020
|
|
|
@@ -12150,6 +12838,192 @@ var init_sheetset_handlers = __esm({
|
|
|
12150
12838
|
}
|
|
12151
12839
|
});
|
|
12152
12840
|
|
|
12841
|
+
// src/handlers/skill-handlers.js
|
|
12842
|
+
var skill_handlers_exports = {};
|
|
12843
|
+
__export(skill_handlers_exports, {
|
|
12844
|
+
skill_install: () => skill_install,
|
|
12845
|
+
skill_list_categories: () => skill_list_categories,
|
|
12846
|
+
skill_list_installed: () => skill_list_installed,
|
|
12847
|
+
skill_search: () => skill_search,
|
|
12848
|
+
skill_uninstall: () => skill_uninstall
|
|
12849
|
+
});
|
|
12850
|
+
import fs8 from "fs";
|
|
12851
|
+
import path12 from "path";
|
|
12852
|
+
import os7 from "os";
|
|
12853
|
+
function readCache() {
|
|
12854
|
+
try {
|
|
12855
|
+
if (fs8.existsSync(CACHE_PATH)) return JSON.parse(fs8.readFileSync(CACHE_PATH, "utf-8"));
|
|
12856
|
+
} catch {
|
|
12857
|
+
}
|
|
12858
|
+
return null;
|
|
12859
|
+
}
|
|
12860
|
+
function writeCache(data) {
|
|
12861
|
+
try {
|
|
12862
|
+
fs8.writeFileSync(CACHE_PATH, JSON.stringify(data, null, 2), "utf-8");
|
|
12863
|
+
} catch {
|
|
12864
|
+
}
|
|
12865
|
+
}
|
|
12866
|
+
async function fetchIndex() {
|
|
12867
|
+
let index = readCache();
|
|
12868
|
+
if (index && Date.now() - index.fetchedAt < 36e5) return index;
|
|
12869
|
+
try {
|
|
12870
|
+
const resp = await fetch(REGISTRY_URL, { headers: { "User-Agent": "atlisp-mcp" } });
|
|
12871
|
+
if (resp.ok) {
|
|
12872
|
+
index = await resp.json();
|
|
12873
|
+
index.fetchedAt = Date.now();
|
|
12874
|
+
writeCache(index);
|
|
12875
|
+
}
|
|
12876
|
+
} catch {
|
|
12877
|
+
}
|
|
12878
|
+
return index;
|
|
12879
|
+
}
|
|
12880
|
+
async function skill_search(a) {
|
|
12881
|
+
const index = await fetchIndex();
|
|
12882
|
+
if (!index?.skills) return { content: [{ type: "text", text: "\u65E0\u6CD5\u83B7\u53D6 skill \u6CE8\u518C\u8868\u7D22\u5F15" }], isError: true };
|
|
12883
|
+
const q = (a.query || "").toLowerCase();
|
|
12884
|
+
const results = index.skills.filter(
|
|
12885
|
+
(s) => s.name.toLowerCase().includes(q) || (s.description || "").toLowerCase().includes(q) || (s.tags || []).some((t) => t.toLowerCase().includes(q))
|
|
12886
|
+
);
|
|
12887
|
+
if (!results.length) return { content: [{ type: "text", text: `\u672A\u627E\u5230\u5339\u914D "${a.query}" \u7684 skill` }] };
|
|
12888
|
+
const lines = [`\u627E\u5230 ${results.length} \u4E2A skill:
|
|
12889
|
+
`];
|
|
12890
|
+
for (const s of results) {
|
|
12891
|
+
lines.push(`**${s.name}**`);
|
|
12892
|
+
if (s.description) lines.push(` \u63CF\u8FF0: ${s.description}`);
|
|
12893
|
+
if (s.tags?.length) lines.push(` \u6807\u7B7E: ${s.tags.join(", ")}`);
|
|
12894
|
+
if (s.version) lines.push(` \u7248\u672C: ${s.version}`);
|
|
12895
|
+
lines.push("");
|
|
12896
|
+
}
|
|
12897
|
+
return { content: [{ type: "text", text: lines.join("\n") }] };
|
|
12898
|
+
}
|
|
12899
|
+
async function skill_install(a) {
|
|
12900
|
+
if (!a.name) return { content: [{ type: "text", text: "\u9700\u8981 skill \u540D\u79F0" }], isError: true };
|
|
12901
|
+
const index = await fetchIndex();
|
|
12902
|
+
if (!index?.skills) return { content: [{ type: "text", text: "\u65E0\u6CD5\u83B7\u53D6 skill \u6CE8\u518C\u8868\u7D22\u5F15" }], isError: true };
|
|
12903
|
+
const skill = index.skills.find((s) => s.name === a.name);
|
|
12904
|
+
if (!skill) return { content: [{ type: "text", text: `\u672A\u627E\u5230 skill: ${a.name}` }], isError: true };
|
|
12905
|
+
const downloadUrl = skill.download_url || skill.url;
|
|
12906
|
+
if (!downloadUrl) return { content: [{ type: "text", text: `Skill "${a.name}" \u6CA1\u6709\u4E0B\u8F7D\u5730\u5740` }], isError: true };
|
|
12907
|
+
let content;
|
|
12908
|
+
try {
|
|
12909
|
+
const resp = await fetch(downloadUrl, { headers: { "User-Agent": "atlisp-mcp" } });
|
|
12910
|
+
if (!resp.ok) throw new Error(`HTTP ${resp.status}`);
|
|
12911
|
+
content = await resp.text();
|
|
12912
|
+
} catch (e) {
|
|
12913
|
+
return { content: [{ type: "text", text: `\u4E0B\u8F7D\u5931\u8D25: ${e.message}` }], isError: true };
|
|
12914
|
+
}
|
|
12915
|
+
try {
|
|
12916
|
+
fs8.mkdirSync(SKILLS_DIR, { recursive: true });
|
|
12917
|
+
} catch {
|
|
12918
|
+
}
|
|
12919
|
+
const safeName = a.name.replace(/[^a-zA-Z0-9\u4e00-\u9fff_-]/g, "-").substring(0, 40);
|
|
12920
|
+
const skillFile = path12.join(SKILLS_DIR, `skill-${safeName}.md`);
|
|
12921
|
+
if (fs8.existsSync(skillFile)) {
|
|
12922
|
+
return { content: [{ type: "text", text: `Skill "${a.name}" \u5DF2\u5B89\u88C5 (${skillFile})` }], isError: true };
|
|
12923
|
+
}
|
|
12924
|
+
let finalContent = content;
|
|
12925
|
+
if (!content.match(/^---\n/)) {
|
|
12926
|
+
const tags = (skill.tags || []).join(", ");
|
|
12927
|
+
finalContent = `---
|
|
12928
|
+
name: ${a.name}
|
|
12929
|
+
description: ${skill.description || ""}
|
|
12930
|
+
tags: ${tags}
|
|
12931
|
+
---
|
|
12932
|
+
|
|
12933
|
+
${content}`;
|
|
12934
|
+
}
|
|
12935
|
+
fs8.writeFileSync(skillFile, finalContent, "utf-8");
|
|
12936
|
+
return { content: [{ type: "text", text: `${skill.name} \u5B89\u88C5\u6210\u529F
|
|
12937
|
+
\u6587\u4EF6: ${skillFile}${skill.version ? `
|
|
12938
|
+
\u7248\u672C: ${skill.version}` : ""}` }] };
|
|
12939
|
+
}
|
|
12940
|
+
async function skill_list_installed() {
|
|
12941
|
+
if (!fs8.existsSync(SKILLS_DIR)) return { content: [{ type: "text", text: "\u6682\u65E0\u5DF2\u5B89\u88C5\u7684 skill" }] };
|
|
12942
|
+
const results = [];
|
|
12943
|
+
try {
|
|
12944
|
+
const entries = fs8.readdirSync(SKILLS_DIR, { withFileTypes: true });
|
|
12945
|
+
for (const entry of entries) {
|
|
12946
|
+
if (entry.isFile() && entry.name.endsWith(".md")) {
|
|
12947
|
+
const fullPath = path12.join(SKILLS_DIR, entry.name);
|
|
12948
|
+
try {
|
|
12949
|
+
const raw = fs8.readFileSync(fullPath, "utf-8");
|
|
12950
|
+
const match = raw.match(/^---\n([\s\S]*?)\n---/);
|
|
12951
|
+
if (match) {
|
|
12952
|
+
const fm = {};
|
|
12953
|
+
for (const line of match[1].split("\n")) {
|
|
12954
|
+
const sep = line.indexOf(":");
|
|
12955
|
+
if (sep > 0) fm[line.slice(0, sep).trim()] = line.slice(sep + 1).trim();
|
|
12956
|
+
}
|
|
12957
|
+
results.push({ name: fm.name || entry.name.replace(".md", ""), description: fm.description || "", tags: fm.tags || "" });
|
|
12958
|
+
} else {
|
|
12959
|
+
results.push({ name: entry.name.replace(".md", ""), description: "", tags: "" });
|
|
12960
|
+
}
|
|
12961
|
+
} catch {
|
|
12962
|
+
}
|
|
12963
|
+
}
|
|
12964
|
+
}
|
|
12965
|
+
} catch {
|
|
12966
|
+
}
|
|
12967
|
+
if (!results.length) return { content: [{ type: "text", text: "\u6682\u65E0\u5DF2\u5B89\u88C5\u7684 skill" }] };
|
|
12968
|
+
const lines = [`\u5DF2\u5B89\u88C5 ${results.length} \u4E2A skill:
|
|
12969
|
+
`];
|
|
12970
|
+
for (const s of results) {
|
|
12971
|
+
lines.push(`**${s.name}**${s.description ? ` \u2014 ${s.description}` : ""}`);
|
|
12972
|
+
if (s.tags) lines.push(` \u6807\u7B7E: ${s.tags}`);
|
|
12973
|
+
}
|
|
12974
|
+
return { content: [{ type: "text", text: lines.join("\n") }] };
|
|
12975
|
+
}
|
|
12976
|
+
async function skill_uninstall(a) {
|
|
12977
|
+
if (!a.name) return { content: [{ type: "text", text: "\u9700\u8981 skill \u540D\u79F0" }], isError: true };
|
|
12978
|
+
if (!fs8.existsSync(SKILLS_DIR)) return { content: [{ type: "text", text: `\u672A\u5B89\u88C5 skill: ${a.name}` }], isError: true };
|
|
12979
|
+
let found = null;
|
|
12980
|
+
try {
|
|
12981
|
+
const entries = fs8.readdirSync(SKILLS_DIR, { withFileTypes: true });
|
|
12982
|
+
for (const entry of entries) {
|
|
12983
|
+
if (entry.isFile() && entry.name.endsWith(".md")) {
|
|
12984
|
+
const fullPath = path12.join(SKILLS_DIR, entry.name);
|
|
12985
|
+
try {
|
|
12986
|
+
const raw = fs8.readFileSync(fullPath, "utf-8");
|
|
12987
|
+
const match = raw.match(/^---\n([\s\S]*?)\n---/);
|
|
12988
|
+
if (match) {
|
|
12989
|
+
for (const line of match[1].split("\n")) {
|
|
12990
|
+
if (line.startsWith("name:") && line.slice(5).trim() === a.name) {
|
|
12991
|
+
found = fullPath;
|
|
12992
|
+
break;
|
|
12993
|
+
}
|
|
12994
|
+
}
|
|
12995
|
+
} else if (entry.name.replace(".md", "") === a.name) {
|
|
12996
|
+
found = fullPath;
|
|
12997
|
+
}
|
|
12998
|
+
} catch {
|
|
12999
|
+
}
|
|
13000
|
+
if (found) break;
|
|
13001
|
+
}
|
|
13002
|
+
}
|
|
13003
|
+
} catch {
|
|
13004
|
+
}
|
|
13005
|
+
if (!found) return { content: [{ type: "text", text: `\u672A\u5B89\u88C5 skill: ${a.name}` }], isError: true };
|
|
13006
|
+
fs8.unlinkSync(found);
|
|
13007
|
+
return { content: [{ type: "text", text: `${a.name} \u5DF2\u5378\u8F7D` }] };
|
|
13008
|
+
}
|
|
13009
|
+
async function skill_list_categories() {
|
|
13010
|
+
const index = await fetchIndex();
|
|
13011
|
+
if (!index?.skills) return { content: [{ type: "text", text: "\u65E0\u6CD5\u83B7\u53D6 skill \u6CE8\u518C\u8868\u7D22\u5F15" }], isError: true };
|
|
13012
|
+
const cats = /* @__PURE__ */ new Set();
|
|
13013
|
+
for (const s of index.skills) for (const t of s.tags || []) cats.add(t);
|
|
13014
|
+
const sorted = Array.from(cats).sort();
|
|
13015
|
+
return { content: [{ type: "text", text: sorted.length ? `\u6CE8\u518C\u8868\u5206\u7C7B (${sorted.length}):
|
|
13016
|
+
${sorted.join("\n")}` : "\u6682\u65E0\u5206\u7C7B" }] };
|
|
13017
|
+
}
|
|
13018
|
+
var SKILLS_DIR, REGISTRY_URL, CACHE_PATH;
|
|
13019
|
+
var init_skill_handlers = __esm({
|
|
13020
|
+
"src/handlers/skill-handlers.js"() {
|
|
13021
|
+
SKILLS_DIR = path12.join(os7.homedir(), ".atlisp", "skills");
|
|
13022
|
+
REGISTRY_URL = process.env.SKILL_REGISTRY_URL || "https://raw.githubusercontent.com/atlisp/skill-registry/main/index.json";
|
|
13023
|
+
CACHE_PATH = path12.join(os7.homedir(), ".atlisp", "skill-registry-cache.json");
|
|
13024
|
+
}
|
|
13025
|
+
});
|
|
13026
|
+
|
|
12153
13027
|
// src/handlers/spatial-handlers.js
|
|
12154
13028
|
var spatial_handlers_exports = {};
|
|
12155
13029
|
__export(spatial_handlers_exports, {
|
|
@@ -13521,13 +14395,13 @@ function lispPoint(pt) {
|
|
|
13521
14395
|
}
|
|
13522
14396
|
async function attachXref(args) {
|
|
13523
14397
|
try {
|
|
13524
|
-
const
|
|
14398
|
+
const path21 = esc3(args.path);
|
|
13525
14399
|
const point = lispPoint(args.point);
|
|
13526
14400
|
const scale = args.scale || 1;
|
|
13527
14401
|
const rotation = args.rotation || 0;
|
|
13528
14402
|
const overlay = args.overlay ? "_O" : "_A";
|
|
13529
14403
|
const result = await cad.sendCommandWithResult(
|
|
13530
|
-
`(command "_.XATTACH" "${
|
|
14404
|
+
`(command "_.XATTACH" "${path21}" "${overlay}" "${point}" "${scale}" "${rotation}") (princ)`
|
|
13531
14405
|
);
|
|
13532
14406
|
return mcpSuccess(`\u5916\u90E8\u53C2\u7167\u5DF2\u9644\u7740: ${args.path}`);
|
|
13533
14407
|
} catch (e) {
|
|
@@ -13845,6 +14719,7 @@ var init_ = __esm({
|
|
|
13845
14719
|
"./handlers/block-handlers.js": () => Promise.resolve().then(() => (init_block_handlers(), block_handlers_exports)),
|
|
13846
14720
|
"./handlers/cad-handlers.js": () => Promise.resolve().then(() => (init_cad_handlers(), cad_handlers_exports)),
|
|
13847
14721
|
"./handlers/constraint-handlers.js": () => Promise.resolve().then(() => (init_constraint_handlers(), constraint_handlers_exports)),
|
|
14722
|
+
"./handlers/debug-handlers.js": () => Promise.resolve().then(() => (init_debug_handlers(), debug_handlers_exports)),
|
|
13848
14723
|
"./handlers/dim-hatch-handlers.js": () => Promise.resolve().then(() => (init_dim_hatch_handlers(), dim_hatch_handlers_exports)),
|
|
13849
14724
|
"./handlers/draw-handlers.js": () => Promise.resolve().then(() => (init_draw_handlers(), draw_handlers_exports)),
|
|
13850
14725
|
"./handlers/edit-handlers.js": () => Promise.resolve().then(() => (init_edit_handlers(), edit_handlers_exports)),
|
|
@@ -13854,6 +14729,7 @@ var init_ = __esm({
|
|
|
13854
14729
|
"./handlers/function-handlers.js": () => Promise.resolve().then(() => (init_function_handlers(), function_handlers_exports)),
|
|
13855
14730
|
"./handlers/layer-handlers.js": () => Promise.resolve().then(() => (init_layer_handlers(), layer_handlers_exports)),
|
|
13856
14731
|
"./handlers/lint-handlers.js": () => Promise.resolve().then(() => (init_lint_handlers(), lint_handlers_exports)),
|
|
14732
|
+
"./handlers/meta-handlers.js": () => Promise.resolve().then(() => (init_meta_handlers(), meta_handlers_exports)),
|
|
13857
14733
|
"./handlers/package-handlers.js": () => Promise.resolve().then(() => (init_package_handlers(), package_handlers_exports)),
|
|
13858
14734
|
"./handlers/parametric-handlers.js": () => Promise.resolve().then(() => (init_parametric_handlers(), parametric_handlers_exports)),
|
|
13859
14735
|
"./handlers/pdf-annotation-handlers.js": () => Promise.resolve().then(() => (init_pdf_annotation_handlers(), pdf_annotation_handlers_exports)),
|
|
@@ -13862,6 +14738,7 @@ var init_ = __esm({
|
|
|
13862
14738
|
"./handlers/query-print-handlers.js": () => Promise.resolve().then(() => (init_query_print_handlers(), query_print_handlers_exports)),
|
|
13863
14739
|
"./handlers/resource-handlers.js": () => Promise.resolve().then(() => (init_resource_handlers(), resource_handlers_exports)),
|
|
13864
14740
|
"./handlers/sheetset-handlers.js": () => Promise.resolve().then(() => (init_sheetset_handlers(), sheetset_handlers_exports)),
|
|
14741
|
+
"./handlers/skill-handlers.js": () => Promise.resolve().then(() => (init_skill_handlers(), skill_handlers_exports)),
|
|
13865
14742
|
"./handlers/spatial-handlers.js": () => Promise.resolve().then(() => (init_spatial_handlers(), spatial_handlers_exports)),
|
|
13866
14743
|
"./handlers/style-handlers.js": () => Promise.resolve().then(() => (init_style_handlers(), style_handlers_exports)),
|
|
13867
14744
|
"./handlers/text-handlers.js": () => Promise.resolve().then(() => (init_text_handlers(), text_handlers_exports)),
|
|
@@ -13874,8 +14751,8 @@ var init_ = __esm({
|
|
|
13874
14751
|
});
|
|
13875
14752
|
|
|
13876
14753
|
// src/handler-loader.js
|
|
13877
|
-
import
|
|
13878
|
-
import
|
|
14754
|
+
import fs9 from "fs";
|
|
14755
|
+
import path13 from "path";
|
|
13879
14756
|
import { fileURLToPath as fileURLToPath5 } from "url";
|
|
13880
14757
|
function toolNameToFuncName(toolName) {
|
|
13881
14758
|
if (FUNCTION_OVERRIDES[toolName]) return FUNCTION_OVERRIDES[toolName];
|
|
@@ -13925,10 +14802,10 @@ async function getHandlerModule(name) {
|
|
|
13925
14802
|
async function initHandlerModules() {
|
|
13926
14803
|
if (_handlerModulesInit) return;
|
|
13927
14804
|
_handlerModulesInit = true;
|
|
13928
|
-
const handlerDir =
|
|
14805
|
+
const handlerDir = path13.join(__dirname5, "handlers");
|
|
13929
14806
|
let names;
|
|
13930
14807
|
try {
|
|
13931
|
-
names = await
|
|
14808
|
+
names = await fs9.promises.readdir(handlerDir);
|
|
13932
14809
|
} catch {
|
|
13933
14810
|
log("Handler directory not found, using static manifest");
|
|
13934
14811
|
return;
|
|
@@ -13939,6 +14816,7 @@ async function initHandlerModules() {
|
|
|
13939
14816
|
handlerModules[name] = () => globImport_handlers_handlers_js(`./handlers/${name}-handlers.js`);
|
|
13940
14817
|
}
|
|
13941
14818
|
}
|
|
14819
|
+
watchHandlers();
|
|
13942
14820
|
}
|
|
13943
14821
|
async function getHandler(toolName) {
|
|
13944
14822
|
const resolved = await resolveHandler(toolName);
|
|
@@ -13947,12 +14825,40 @@ async function getHandler(toolName) {
|
|
|
13947
14825
|
if (!mod || typeof mod[resolved.funcName] !== "function") return null;
|
|
13948
14826
|
return mod[resolved.funcName];
|
|
13949
14827
|
}
|
|
13950
|
-
|
|
13951
|
-
|
|
14828
|
+
function watchHandlers() {
|
|
14829
|
+
if (_watcherInitialized) return;
|
|
14830
|
+
_watcherInitialized = true;
|
|
14831
|
+
const handlerDir = path13.join(__dirname5, "handlers");
|
|
14832
|
+
let debounceTimer = null;
|
|
14833
|
+
try {
|
|
14834
|
+
if (!fs9.existsSync(handlerDir)) return;
|
|
14835
|
+
fs9.watch(handlerDir, (eventType, filename) => {
|
|
14836
|
+
if (!filename || !filename.endsWith("-handlers.js")) return;
|
|
14837
|
+
if (debounceTimer) clearTimeout(debounceTimer);
|
|
14838
|
+
debounceTimer = setTimeout(async () => {
|
|
14839
|
+
const name = filename.replace("-handlers.js", "");
|
|
14840
|
+
moduleCache.delete(name);
|
|
14841
|
+
resolvedCache.clear();
|
|
14842
|
+
_handlerNameMapInit = false;
|
|
14843
|
+
_handlerModulesInit = false;
|
|
14844
|
+
try {
|
|
14845
|
+
await initHandlerModules();
|
|
14846
|
+
log(`Handler hot-reloaded: ${filename}`);
|
|
14847
|
+
} catch (e) {
|
|
14848
|
+
log(`Handler reload failed for ${filename}: ${e.message}`);
|
|
14849
|
+
}
|
|
14850
|
+
}, 300);
|
|
14851
|
+
});
|
|
14852
|
+
} catch (e) {
|
|
14853
|
+
log(`Handler watch error: ${e.message}`);
|
|
14854
|
+
}
|
|
14855
|
+
}
|
|
14856
|
+
var __dirname5, _handlerModulesInit, _handlerNameMapInit, handlerModules, moduleCache, resolvedCache, FUNCTION_OVERRIDES, _watcherInitialized;
|
|
14857
|
+
var init_handler_loader = __esm({
|
|
13952
14858
|
"src/handler-loader.js"() {
|
|
13953
14859
|
init_logger();
|
|
13954
14860
|
init_();
|
|
13955
|
-
__dirname5 =
|
|
14861
|
+
__dirname5 = path13.dirname(fileURLToPath5(import.meta.url));
|
|
13956
14862
|
_handlerModulesInit = false;
|
|
13957
14863
|
_handlerNameMapInit = false;
|
|
13958
14864
|
handlerModules = {};
|
|
@@ -13964,16 +14870,18 @@ var init_handler_loader = __esm({
|
|
|
13964
14870
|
get_dimension: "getDimensionValue",
|
|
13965
14871
|
eval_lisp_with_result: "evalLisp"
|
|
13966
14872
|
};
|
|
14873
|
+
_watcherInitialized = false;
|
|
13967
14874
|
}
|
|
13968
14875
|
});
|
|
13969
14876
|
|
|
13970
14877
|
// src/streaming.js
|
|
13971
|
-
|
|
13972
|
-
|
|
13973
|
-
|
|
13974
|
-
|
|
13975
|
-
|
|
13976
|
-
const ssgetExpr =
|
|
14878
|
+
function escapeLispStr(str) {
|
|
14879
|
+
if (typeof str !== "string") return "";
|
|
14880
|
+
return str.replace(/\\/g, "\\\\").replace(/"/g, '\\"');
|
|
14881
|
+
}
|
|
14882
|
+
async function streamEntities({ filterExpr, extractFields, itemMapper, offset, limit, hasFilter, warnThreshold, overLimitMsg, resultProp }) {
|
|
14883
|
+
const ssgetExpr = filterExpr ? `(ssget "_X" ${filterExpr})` : `(ssget "_X")`;
|
|
14884
|
+
const extractCode = extractFields.length === 1 ? `(list ${extractFields.join(" ")})` : `(list ${extractFields.join(" ")})`;
|
|
13977
14885
|
const lisp = `(progn
|
|
13978
14886
|
(setq ss ${ssgetExpr})
|
|
13979
14887
|
(setq total (if ss (sslength ss) 0))
|
|
@@ -13985,10 +14893,10 @@ async function streamEntitiesByType({ type = null, layer = null, chunk = STREAM_
|
|
|
13985
14893
|
(setq result (list total))
|
|
13986
14894
|
(setq i ${offset})
|
|
13987
14895
|
(setq count 0)
|
|
13988
|
-
(while (and (< i total) (< count ${
|
|
14896
|
+
(while (and (< i total) (< count ${limit}))
|
|
13989
14897
|
(setq e (ssname ss i))
|
|
13990
14898
|
(setq elist (entget e))
|
|
13991
|
-
(setq result (cons
|
|
14899
|
+
(setq result (cons ${extractCode} result))
|
|
13992
14900
|
(setq i (1+ i))
|
|
13993
14901
|
(setq count (1+ count)))
|
|
13994
14902
|
(reverse result)))))`;
|
|
@@ -14002,108 +14910,68 @@ async function streamEntitiesByType({ type = null, layer = null, chunk = STREAM_
|
|
|
14002
14910
|
offset: 0,
|
|
14003
14911
|
count: 0,
|
|
14004
14912
|
hasMore: false,
|
|
14005
|
-
|
|
14006
|
-
error: `\u5B9E\u4F53\u6570\u91CF (${parsed[1]}) \u8D85\u8FC7\u6700\u5927\u9650\u5236 (${MAX_ENTITY_LIMIT})\uFF0C
|
|
14913
|
+
[resultProp]: [],
|
|
14914
|
+
error: `\u5B9E\u4F53\u6570\u91CF (${parsed[1]}) \u8D85\u8FC7\u6700\u5927\u9650\u5236 (${MAX_ENTITY_LIMIT})\uFF0C${overLimitMsg}`
|
|
14007
14915
|
};
|
|
14008
14916
|
}
|
|
14009
|
-
const
|
|
14010
|
-
const result = {
|
|
14011
|
-
|
|
14012
|
-
|
|
14013
|
-
count: entities.length,
|
|
14014
|
-
hasMore: offset + entities.length < total,
|
|
14015
|
-
entities
|
|
14016
|
-
};
|
|
14017
|
-
if (!hasFilter && total > UNFILTERED_WARN_THRESHOLD) {
|
|
14018
|
-
result.warning = `\u672A\u63D0\u4F9B type/layer \u8FC7\u6EE4\uFF0C\u5168\u56FE\u626B\u63CF\u4E86 ${total} \u4E2A\u5B9E\u4F53\u3002\u5EFA\u8BAE\u6DFB\u52A0 type \u6216 layer \u53C2\u6570\u4EE5\u5927\u5E45\u63D0\u5347\u6027\u80FD\u548C\u964D\u4F4E\u5185\u5B58\u5360\u7528\u3002`;
|
|
14917
|
+
const items = parsed.slice(1).map(itemMapper);
|
|
14918
|
+
const result = { total, offset, count: items.length, hasMore: offset + items.length < total, [resultProp]: items };
|
|
14919
|
+
if (!hasFilter && total > warnThreshold) {
|
|
14920
|
+
result.warning = `\u672A\u63D0\u4F9B\u8FC7\u6EE4\u6761\u4EF6\uFF0C\u5168\u56FE\u626B\u63CF\u4E86 ${total} \u4E2A\u5B9E\u4F53\u3002\u5EFA\u8BAE\u6DFB\u52A0\u8FC7\u6EE4\u53C2\u6570\u4EE5\u63D0\u5347\u6027\u80FD\u3002`;
|
|
14019
14921
|
}
|
|
14020
14922
|
return result;
|
|
14021
14923
|
} catch {
|
|
14022
|
-
return { total: 0, offset: 0, count: 0, hasMore: false,
|
|
14924
|
+
return { total: 0, offset: 0, count: 0, hasMore: false, [resultProp]: [] };
|
|
14023
14925
|
}
|
|
14024
14926
|
}
|
|
14927
|
+
async function streamEntitiesByType({ type = null, layer = null, chunk = STREAM_CHUNK_SIZE, offset = 0 }) {
|
|
14928
|
+
const filters = [];
|
|
14929
|
+
if (type) filters.push(`(cons 0 "${escapeLispStr(type)}")`);
|
|
14930
|
+
if (layer) filters.push(`(cons 8 "${escapeLispStr(layer)}")`);
|
|
14931
|
+
const filterExpr = filters.length > 0 ? `(list ${filters.join(" ")})` : null;
|
|
14932
|
+
return streamEntities({
|
|
14933
|
+
filterExpr,
|
|
14934
|
+
extractFields: ["(list (cdr (assoc 0 elist)) (cdr (assoc 5 elist)) (cdr (assoc 8 elist)))"],
|
|
14935
|
+
itemMapper: (item) => ({ type: item[0], handle: item[1], layer: item[2] }),
|
|
14936
|
+
offset,
|
|
14937
|
+
limit: chunk,
|
|
14938
|
+
hasFilter: !!(type || layer),
|
|
14939
|
+
warnThreshold: UNFILTERED_WARN_THRESHOLD,
|
|
14940
|
+
overLimitMsg: "\u8BF7\u4F7F\u7528 type/layer \u8FC7\u6EE4",
|
|
14941
|
+
resultProp: "entities"
|
|
14942
|
+
});
|
|
14943
|
+
}
|
|
14025
14944
|
async function streamTextContent({ layer = null, bbox = null, offset = 0, limit = 100 }) {
|
|
14026
14945
|
const textFilters = [`(cons 0 "TEXT")`, `(cons 0 "MTEXT")`];
|
|
14027
|
-
if (layer) textFilters.push(`(cons 8 "${layer}")`);
|
|
14028
|
-
const
|
|
14029
|
-
|
|
14030
|
-
|
|
14031
|
-
(
|
|
14032
|
-
|
|
14033
|
-
|
|
14034
|
-
|
|
14035
|
-
|
|
14036
|
-
|
|
14037
|
-
|
|
14038
|
-
|
|
14039
|
-
|
|
14040
|
-
(setq e (ssname ss i))
|
|
14041
|
-
(setq elist (entget e))
|
|
14042
|
-
(setq txt (cdr (assoc 1 elist)))
|
|
14043
|
-
(setq result (cons (list (cdr (assoc 5 elist)) txt (cdr (assoc 10 elist))) result))
|
|
14044
|
-
(setq i (1+ i))
|
|
14045
|
-
(setq count (1+ count)))
|
|
14046
|
-
(reverse result)))))`;
|
|
14047
|
-
const raw = await cad.sendCommandWithResult(lisp);
|
|
14048
|
-
try {
|
|
14049
|
-
const parsed = JSON.parse(raw);
|
|
14050
|
-
const total = parsed[0] || 0;
|
|
14051
|
-
if (total === -1) {
|
|
14052
|
-
return {
|
|
14053
|
-
total: parsed[1] || 0,
|
|
14054
|
-
offset: 0,
|
|
14055
|
-
count: 0,
|
|
14056
|
-
hasMore: false,
|
|
14057
|
-
texts: [],
|
|
14058
|
-
error: `\u6587\u672C\u5B9E\u4F53\u6570\u91CF (${parsed[1]}) \u8D85\u8FC7\u6700\u5927\u9650\u5236 (${MAX_ENTITY_LIMIT})\uFF0C\u8BF7\u4F7F\u7528 layer \u8FC7\u6EE4`
|
|
14059
|
-
};
|
|
14060
|
-
}
|
|
14061
|
-
const texts = parsed.slice(1).map((t) => ({ handle: t[0], text: t[1], point: t[2] }));
|
|
14062
|
-
return { total, offset, count: texts.length, hasMore: offset + texts.length < total, texts };
|
|
14063
|
-
} catch {
|
|
14064
|
-
return { total: 0, offset: 0, count: 0, hasMore: false, texts: [] };
|
|
14065
|
-
}
|
|
14946
|
+
if (layer) textFilters.push(`(cons 8 "${escapeLispStr(layer)}")`);
|
|
14947
|
+
const filterExpr = `(list '(-4 . "<OR") ${textFilters.join(" ")} '(-4 . "OR>"))`;
|
|
14948
|
+
return streamEntities({
|
|
14949
|
+
filterExpr,
|
|
14950
|
+
extractFields: ["(list (cdr (assoc 5 elist)) (cdr (assoc 1 elist)) (cdr (assoc 10 elist)))"],
|
|
14951
|
+
itemMapper: (item) => ({ handle: item[0], text: item[1], point: item[2] }),
|
|
14952
|
+
offset,
|
|
14953
|
+
limit,
|
|
14954
|
+
hasFilter: !!layer,
|
|
14955
|
+
warnThreshold: UNFILTERED_WARN_THRESHOLD,
|
|
14956
|
+
overLimitMsg: "\u8BF7\u4F7F\u7528 layer \u8FC7\u6EE4",
|
|
14957
|
+
resultProp: "texts"
|
|
14958
|
+
});
|
|
14066
14959
|
}
|
|
14067
14960
|
async function streamBlockRefs({ blockName = null, offset = 0, limit = 100 }) {
|
|
14068
14961
|
const filters = [`(cons 0 "INSERT")`];
|
|
14069
|
-
if (blockName) filters.push(`(cons 2 "${blockName}")`);
|
|
14070
|
-
const
|
|
14071
|
-
|
|
14072
|
-
|
|
14073
|
-
(
|
|
14074
|
-
|
|
14075
|
-
|
|
14076
|
-
|
|
14077
|
-
|
|
14078
|
-
|
|
14079
|
-
|
|
14080
|
-
|
|
14081
|
-
|
|
14082
|
-
(setq e (ssname ss i))
|
|
14083
|
-
(setq elist (entget e))
|
|
14084
|
-
(setq result (cons (list (cdr (assoc 2 elist)) (cdr (assoc 5 elist)) (cdr (assoc 10 elist))) result))
|
|
14085
|
-
(setq i (1+ i))
|
|
14086
|
-
(setq count (1+ count)))
|
|
14087
|
-
(reverse result)))))`;
|
|
14088
|
-
const raw = await cad.sendCommandWithResult(lisp);
|
|
14089
|
-
try {
|
|
14090
|
-
const parsed = JSON.parse(raw);
|
|
14091
|
-
const total = parsed[0] || 0;
|
|
14092
|
-
if (total === -1) {
|
|
14093
|
-
return {
|
|
14094
|
-
total: parsed[1] || 0,
|
|
14095
|
-
offset: 0,
|
|
14096
|
-
count: 0,
|
|
14097
|
-
hasMore: false,
|
|
14098
|
-
refs: [],
|
|
14099
|
-
error: `\u5757\u53C2\u7167\u6570\u91CF (${parsed[1]}) \u8D85\u8FC7\u6700\u5927\u9650\u5236 (${MAX_ENTITY_LIMIT})\uFF0C\u8BF7\u4F7F\u7528 blockName \u8FC7\u6EE4`
|
|
14100
|
-
};
|
|
14101
|
-
}
|
|
14102
|
-
const refs = parsed.slice(1).map((r) => ({ blockName: r[0], handle: r[1], insertionPoint: r[2] }));
|
|
14103
|
-
return { total, offset, count: refs.length, hasMore: offset + refs.length < total, refs };
|
|
14104
|
-
} catch {
|
|
14105
|
-
return { total: 0, offset: 0, count: 0, hasMore: false, refs: [] };
|
|
14106
|
-
}
|
|
14962
|
+
if (blockName) filters.push(`(cons 2 "${escapeLispStr(blockName)}")`);
|
|
14963
|
+
const filterExpr = filters.length > 0 ? `(list ${filters.join(" ")})` : null;
|
|
14964
|
+
return streamEntities({
|
|
14965
|
+
filterExpr,
|
|
14966
|
+
extractFields: ["(list (cdr (assoc 2 elist)) (cdr (assoc 5 elist)) (cdr (assoc 10 elist)))"],
|
|
14967
|
+
itemMapper: (item) => ({ blockName: item[0], handle: item[1], insertionPoint: item[2] }),
|
|
14968
|
+
offset,
|
|
14969
|
+
limit,
|
|
14970
|
+
hasFilter: !!blockName,
|
|
14971
|
+
warnThreshold: UNFILTERED_WARN_THRESHOLD,
|
|
14972
|
+
overLimitMsg: "\u8BF7\u4F7F\u7528 blockName \u8FC7\u6EE4",
|
|
14973
|
+
resultProp: "refs"
|
|
14974
|
+
});
|
|
14107
14975
|
}
|
|
14108
14976
|
var STREAM_CHUNK_SIZE, MAX_ENTITY_LIMIT, UNFILTERED_WARN_THRESHOLD;
|
|
14109
14977
|
var init_streaming = __esm({
|
|
@@ -14115,6 +14983,74 @@ var init_streaming = __esm({
|
|
|
14115
14983
|
}
|
|
14116
14984
|
});
|
|
14117
14985
|
|
|
14986
|
+
// src/cad-rot-helper.js
|
|
14987
|
+
import edge from "edge-js";
|
|
14988
|
+
import path14 from "path";
|
|
14989
|
+
import { fileURLToPath as fileURLToPath6 } from "url";
|
|
14990
|
+
function getRotHelper() {
|
|
14991
|
+
if (_rotHelper) return _rotHelper;
|
|
14992
|
+
const dllPath = path14.join(projectRoot, "dist", "cad-rothelper.dll");
|
|
14993
|
+
try {
|
|
14994
|
+
_rotHelper = edge.func({
|
|
14995
|
+
assemblyFile: dllPath,
|
|
14996
|
+
typeName: "CadRotHelper.RotEnumerator",
|
|
14997
|
+
methodName: "EnumerateAll"
|
|
14998
|
+
});
|
|
14999
|
+
return _rotHelper;
|
|
15000
|
+
} catch (e) {
|
|
15001
|
+
error(`ROT \u5E2E\u52A9\u5668\u52A0\u8F7D\u5931\u8D25: ${e.message}`);
|
|
15002
|
+
return null;
|
|
15003
|
+
}
|
|
15004
|
+
}
|
|
15005
|
+
async function discoverCadInstances() {
|
|
15006
|
+
const helper = getRotHelper();
|
|
15007
|
+
if (!helper) {
|
|
15008
|
+
log("ROT \u5E2E\u52A9\u5668\u4E0D\u53EF\u7528\uFF0C\u8DF3\u8FC7 CAD \u5B9E\u4F8B\u53D1\u73B0");
|
|
15009
|
+
return [];
|
|
15010
|
+
}
|
|
15011
|
+
return new Promise((resolve) => {
|
|
15012
|
+
helper(null, (err, result) => {
|
|
15013
|
+
if (err) {
|
|
15014
|
+
error(`ROT \u679A\u4E3E\u5931\u8D25: ${err.message}`);
|
|
15015
|
+
resolve([]);
|
|
15016
|
+
return;
|
|
15017
|
+
}
|
|
15018
|
+
if (!Array.isArray(result)) {
|
|
15019
|
+
resolve([]);
|
|
15020
|
+
return;
|
|
15021
|
+
}
|
|
15022
|
+
const seen = /* @__PURE__ */ new Set();
|
|
15023
|
+
const instances = [];
|
|
15024
|
+
for (const entry of result) {
|
|
15025
|
+
if (!entry.appName) continue;
|
|
15026
|
+
const pidKey = `${entry.appName}-${entry.pid}`;
|
|
15027
|
+
if (seen.has(pidKey)) continue;
|
|
15028
|
+
seen.add(pidKey);
|
|
15029
|
+
const key = `${entry.appName.toLowerCase()}-${entry.pid}`;
|
|
15030
|
+
instances.push({
|
|
15031
|
+
key,
|
|
15032
|
+
platform: entry.appName,
|
|
15033
|
+
pid: entry.pid,
|
|
15034
|
+
hwnd: entry.hwnd,
|
|
15035
|
+
version: entry.version,
|
|
15036
|
+
moniker: entry.name
|
|
15037
|
+
});
|
|
15038
|
+
}
|
|
15039
|
+
log(`ROT \u53D1\u73B0: ${instances.length} \u4E2A CAD \u5B9E\u4F8B (${instances.map((i) => `${i.platform}#${i.pid}`).join(", ")})`);
|
|
15040
|
+
resolve(instances);
|
|
15041
|
+
});
|
|
15042
|
+
});
|
|
15043
|
+
}
|
|
15044
|
+
var __filename, projectRoot, _rotHelper;
|
|
15045
|
+
var init_cad_rot_helper = __esm({
|
|
15046
|
+
"src/cad-rot-helper.js"() {
|
|
15047
|
+
init_logger();
|
|
15048
|
+
__filename = fileURLToPath6(import.meta.url);
|
|
15049
|
+
projectRoot = path14.dirname(path14.dirname(__filename));
|
|
15050
|
+
_rotHelper = null;
|
|
15051
|
+
}
|
|
15052
|
+
});
|
|
15053
|
+
|
|
14118
15054
|
// src/cad-pool.js
|
|
14119
15055
|
var POOL_STRATEGIES, CadConnectionPool, pool;
|
|
14120
15056
|
var init_cad_pool = __esm({
|
|
@@ -14122,6 +15058,8 @@ var init_cad_pool = __esm({
|
|
|
14122
15058
|
init_cad();
|
|
14123
15059
|
init_logger();
|
|
14124
15060
|
init_config();
|
|
15061
|
+
init_cad_rot_helper();
|
|
15062
|
+
init_resource_cache();
|
|
14125
15063
|
POOL_STRATEGIES = {
|
|
14126
15064
|
ROUND_ROBIN: "round-robin",
|
|
14127
15065
|
LEAST_BUSY: "least-busy",
|
|
@@ -14130,9 +15068,8 @@ var init_cad_pool = __esm({
|
|
|
14130
15068
|
CadConnectionPool = class {
|
|
14131
15069
|
_instances = /* @__PURE__ */ new Map();
|
|
14132
15070
|
_maxPoolSize = 3;
|
|
14133
|
-
_activeKey =
|
|
15071
|
+
_activeKey = null;
|
|
14134
15072
|
_strategy = POOL_STRATEGIES.MANUAL;
|
|
14135
|
-
_rrIndex = 0;
|
|
14136
15073
|
_reconnectTimers = /* @__PURE__ */ new Map();
|
|
14137
15074
|
_reconnectCounts = /* @__PURE__ */ new Map();
|
|
14138
15075
|
_maxReconnectAttempts = 10;
|
|
@@ -14142,30 +15079,8 @@ var init_cad_pool = __esm({
|
|
|
14142
15079
|
this._maxPoolSize = config_default.maxPoolSize || 3;
|
|
14143
15080
|
}
|
|
14144
15081
|
getConnection(key) {
|
|
14145
|
-
this._ensureDefault();
|
|
14146
15082
|
return this._instances.get(key)?.connection || null;
|
|
14147
15083
|
}
|
|
14148
|
-
/**
|
|
14149
|
-
* Ensure the default entry exists. Created lazily to avoid
|
|
14150
|
-
* calling getActiveConnection() at module import time (which
|
|
14151
|
-
* breaks tests that mock cad.js).
|
|
14152
|
-
*/
|
|
14153
|
-
_ensureDefault() {
|
|
14154
|
-
if (!this._instances.has("default")) {
|
|
14155
|
-
const defaultConn = getActiveConnection();
|
|
14156
|
-
this._instances.set("default", {
|
|
14157
|
-
key: "default",
|
|
14158
|
-
connection: defaultConn,
|
|
14159
|
-
platform: null,
|
|
14160
|
-
version: null,
|
|
14161
|
-
connected: false,
|
|
14162
|
-
lastPing: Date.now(),
|
|
14163
|
-
createdAt: Date.now(),
|
|
14164
|
-
label: "\u9ED8\u8BA4 CAD",
|
|
14165
|
-
autoReconnect: true
|
|
14166
|
-
});
|
|
14167
|
-
}
|
|
14168
|
-
}
|
|
14169
15084
|
/**
|
|
14170
15085
|
* Connect to a CAD instance and add it to the pool.
|
|
14171
15086
|
* @param {string} key - Instance identifier
|
|
@@ -14173,14 +15088,30 @@ var init_cad_pool = __esm({
|
|
|
14173
15088
|
* @param {object} [options] - Additional options
|
|
14174
15089
|
* @param {string} [options.label] - Human-readable label
|
|
14175
15090
|
* @param {boolean} [options.autoReconnect=true] - Auto-reconnect on failure
|
|
15091
|
+
* @param {number} [options.pid] - Target process PID (find via ROT)
|
|
14176
15092
|
* @param {boolean} [options.makeActive=true] - Set as active after connecting
|
|
14177
15093
|
*/
|
|
14178
15094
|
async connect(key = "default", platform = null, options = {}) {
|
|
14179
|
-
|
|
14180
|
-
const { label, autoReconnect = true, makeActive = true } = options || {};
|
|
15095
|
+
const { label, autoReconnect = true, makeActive = true, pid } = options || {};
|
|
14181
15096
|
if (this._instances.size >= this._maxPoolSize && !this._instances.has(key)) {
|
|
14182
15097
|
throw new Error(`\u8FDE\u63A5\u6C60\u5DF2\u6EE1 (${this._maxPoolSize})\uFF0C\u65E0\u6CD5\u6DFB\u52A0\u65B0\u5B9E\u4F8B "${key}"`);
|
|
14183
15098
|
}
|
|
15099
|
+
if (pid != null) {
|
|
15100
|
+
const instances = await discoverCadInstances();
|
|
15101
|
+
const match = instances.find((i) => i.pid === pid);
|
|
15102
|
+
if (!match) {
|
|
15103
|
+
error(`\u8FDE\u63A5\u6C60: \u672A\u627E\u5230 PID ${pid} \u7684 CAD \u5B9E\u4F8B`);
|
|
15104
|
+
return false;
|
|
15105
|
+
}
|
|
15106
|
+
platform = platform || match.platform;
|
|
15107
|
+
if (key === "default" || key === pid.toString()) {
|
|
15108
|
+
key = match.key;
|
|
15109
|
+
}
|
|
15110
|
+
if (match.moniker) {
|
|
15111
|
+
if (!options) options = {};
|
|
15112
|
+
options._moniker = match.moniker;
|
|
15113
|
+
}
|
|
15114
|
+
}
|
|
14184
15115
|
let entry = this._instances.get(key);
|
|
14185
15116
|
if (entry && entry.connected) {
|
|
14186
15117
|
return true;
|
|
@@ -14202,7 +15133,9 @@ var init_cad_pool = __esm({
|
|
|
14202
15133
|
}
|
|
14203
15134
|
const conn = entry.connection;
|
|
14204
15135
|
try {
|
|
14205
|
-
const
|
|
15136
|
+
const moniker = options._moniker || entry.moniker;
|
|
15137
|
+
const connectOpts = moniker ? { moniker, key } : {};
|
|
15138
|
+
const ok = await conn.connect(platform, connectOpts);
|
|
14206
15139
|
if (ok) {
|
|
14207
15140
|
entry.connected = true;
|
|
14208
15141
|
entry.platform = conn.getPlatform();
|
|
@@ -14226,17 +15159,6 @@ var init_cad_pool = __esm({
|
|
|
14226
15159
|
* Disconnect and remove an instance from the pool.
|
|
14227
15160
|
*/
|
|
14228
15161
|
async disconnect(key) {
|
|
14229
|
-
this._ensureDefault();
|
|
14230
|
-
if (key === "default") {
|
|
14231
|
-
const entry2 = this._instances.get("default");
|
|
14232
|
-
if (entry2) {
|
|
14233
|
-
await entry2.connection.disconnect();
|
|
14234
|
-
entry2.connected = false;
|
|
14235
|
-
entry2.platform = null;
|
|
14236
|
-
entry2.version = null;
|
|
14237
|
-
}
|
|
14238
|
-
return true;
|
|
14239
|
-
}
|
|
14240
15162
|
const entry = this._instances.get(key);
|
|
14241
15163
|
if (!entry) return false;
|
|
14242
15164
|
this._clearReconnectTimer(key);
|
|
@@ -14247,7 +15169,12 @@ var init_cad_pool = __esm({
|
|
|
14247
15169
|
}
|
|
14248
15170
|
this._instances.delete(key);
|
|
14249
15171
|
if (this._activeKey === key) {
|
|
14250
|
-
this.
|
|
15172
|
+
const remaining = Array.from(this._instances.keys());
|
|
15173
|
+
if (remaining.length > 0) {
|
|
15174
|
+
this.setActive(remaining[0]);
|
|
15175
|
+
} else {
|
|
15176
|
+
this._activeKey = null;
|
|
15177
|
+
}
|
|
14251
15178
|
}
|
|
14252
15179
|
log(`\u8FDE\u63A5\u6C60: \u5B9E\u4F8B "${key}" \u5DF2\u65AD\u5F00\u5E76\u79FB\u9664`);
|
|
14253
15180
|
return true;
|
|
@@ -14256,7 +15183,6 @@ var init_cad_pool = __esm({
|
|
|
14256
15183
|
* Set the active instance. All cad.* calls will be routed here.
|
|
14257
15184
|
*/
|
|
14258
15185
|
setActive(key) {
|
|
14259
|
-
this._ensureDefault();
|
|
14260
15186
|
const entry = this._instances.get(key);
|
|
14261
15187
|
if (!entry) {
|
|
14262
15188
|
error(`\u8FDE\u63A5\u6C60: \u5B9E\u4F8B "${key}" \u4E0D\u5B58\u5728`);
|
|
@@ -14264,47 +15190,88 @@ var init_cad_pool = __esm({
|
|
|
14264
15190
|
}
|
|
14265
15191
|
this._activeKey = key;
|
|
14266
15192
|
setActiveConnection(entry.connection);
|
|
15193
|
+
setInstanceKey(key);
|
|
14267
15194
|
cad.connected = entry.connected;
|
|
14268
15195
|
log(`\u8FDE\u63A5\u6C60: \u5DF2\u5207\u6362\u5230\u5B9E\u4F8B "${key}"`);
|
|
15196
|
+
if (this._onInstanceSwitch) {
|
|
15197
|
+
try {
|
|
15198
|
+
this._onInstanceSwitch(key, entry);
|
|
15199
|
+
} catch (e) {
|
|
15200
|
+
error(`\u5207\u6362\u56DE\u8C03\u7528\u9519\u8BEF: ${e.message}`);
|
|
15201
|
+
}
|
|
15202
|
+
}
|
|
14269
15203
|
return true;
|
|
14270
15204
|
}
|
|
15205
|
+
/**
|
|
15206
|
+
* Register a callback invoked after every instance switch.
|
|
15207
|
+
* @param {function} fn - (key, entry) => void
|
|
15208
|
+
*/
|
|
15209
|
+
onInstanceSwitch(fn) {
|
|
15210
|
+
this._onInstanceSwitch = fn;
|
|
15211
|
+
}
|
|
14271
15212
|
/**
|
|
14272
15213
|
* Discover and add all running CAD instances.
|
|
14273
|
-
*
|
|
15214
|
+
* Uses ROT enumeration to find all instances (including multiple of the same platform).
|
|
15215
|
+
* Falls back to GetActiveObject per platform when ROT is unavailable.
|
|
14274
15216
|
*/
|
|
14275
15217
|
async discover() {
|
|
14276
|
-
|
|
14277
|
-
const
|
|
14278
|
-
|
|
14279
|
-
for (const
|
|
14280
|
-
const key =
|
|
15218
|
+
const resultEntries = [];
|
|
15219
|
+
const rotInstances = await discoverCadInstances();
|
|
15220
|
+
const rotHadResults = rotInstances.length > 0;
|
|
15221
|
+
for (const inst of rotInstances) {
|
|
15222
|
+
const key = inst.key;
|
|
14281
15223
|
if (this._instances.has(key) && this._instances.get(key).connected) {
|
|
14282
|
-
|
|
15224
|
+
resultEntries.push(this._instances.get(key));
|
|
14283
15225
|
continue;
|
|
14284
15226
|
}
|
|
14285
|
-
|
|
14286
|
-
|
|
14287
|
-
|
|
14288
|
-
|
|
14289
|
-
|
|
14290
|
-
|
|
14291
|
-
|
|
14292
|
-
|
|
14293
|
-
|
|
14294
|
-
|
|
14295
|
-
|
|
14296
|
-
|
|
14297
|
-
|
|
14298
|
-
|
|
14299
|
-
|
|
14300
|
-
|
|
14301
|
-
|
|
14302
|
-
|
|
15227
|
+
this._instances.set(key, {
|
|
15228
|
+
key,
|
|
15229
|
+
connection: null,
|
|
15230
|
+
platform: inst.platform,
|
|
15231
|
+
pid: inst.pid,
|
|
15232
|
+
version: inst.version,
|
|
15233
|
+
moniker: inst.moniker,
|
|
15234
|
+
connected: false,
|
|
15235
|
+
lastPing: Date.now(),
|
|
15236
|
+
createdAt: Date.now(),
|
|
15237
|
+
label: `${inst.platform} #${inst.pid} ${inst.version || ""}`.trim(),
|
|
15238
|
+
autoReconnect: false
|
|
15239
|
+
});
|
|
15240
|
+
log(`\u8FDE\u63A5\u6C60: \u53D1\u73B0 ${inst.platform} \u5B9E\u4F8B PID=${inst.pid}`);
|
|
15241
|
+
resultEntries.push(this._instances.get(key));
|
|
15242
|
+
}
|
|
15243
|
+
if (!rotHadResults) {
|
|
15244
|
+
const connectWithTimeout = (conn, platform, ms = 4e3) => Promise.race([
|
|
15245
|
+
conn.connect(platform),
|
|
15246
|
+
new Promise((_, reject) => setTimeout(() => reject(new Error("timeout")), ms))
|
|
15247
|
+
]);
|
|
15248
|
+
for (const platform of ["AutoCAD", "ZWCAD", "GStarCAD", "BricsCAD"]) {
|
|
15249
|
+
const key = platform.toLowerCase();
|
|
15250
|
+
if (this._instances.has(key) && this._instances.get(key).connected) continue;
|
|
15251
|
+
try {
|
|
15252
|
+
const tempConn = createCadConnection();
|
|
15253
|
+
const ok = await connectWithTimeout(tempConn, platform);
|
|
15254
|
+
if (ok) {
|
|
15255
|
+
const label = `${platform} ${tempConn.getVersion() || ""}`.trim();
|
|
15256
|
+
this._instances.set(key, {
|
|
15257
|
+
key,
|
|
15258
|
+
connection: tempConn,
|
|
15259
|
+
platform: tempConn.getPlatform(),
|
|
15260
|
+
version: tempConn.getVersion(),
|
|
15261
|
+
connected: true,
|
|
15262
|
+
lastPing: Date.now(),
|
|
15263
|
+
createdAt: Date.now(),
|
|
15264
|
+
label,
|
|
15265
|
+
autoReconnect: true
|
|
15266
|
+
});
|
|
15267
|
+
log(`\u8FDE\u63A5\u6C60: \u53D1\u73B0 ${label}`);
|
|
15268
|
+
resultEntries.push(this._instances.get(key));
|
|
15269
|
+
}
|
|
15270
|
+
} catch (e) {
|
|
14303
15271
|
}
|
|
14304
|
-
} catch (e) {
|
|
14305
15272
|
}
|
|
14306
15273
|
}
|
|
14307
|
-
return
|
|
15274
|
+
return resultEntries.map((e) => ({
|
|
14308
15275
|
key: e.key,
|
|
14309
15276
|
connected: e.connected,
|
|
14310
15277
|
platform: e.platform,
|
|
@@ -14317,7 +15284,6 @@ var init_cad_pool = __esm({
|
|
|
14317
15284
|
* Health check for all instances.
|
|
14318
15285
|
*/
|
|
14319
15286
|
async healthCheck() {
|
|
14320
|
-
this._ensureDefault();
|
|
14321
15287
|
const results = [];
|
|
14322
15288
|
for (const [key, entry] of this._instances) {
|
|
14323
15289
|
try {
|
|
@@ -14363,14 +15329,21 @@ var init_cad_pool = __esm({
|
|
|
14363
15329
|
* Get the active instance.
|
|
14364
15330
|
*/
|
|
14365
15331
|
getActive() {
|
|
14366
|
-
this._ensureDefault();
|
|
14367
15332
|
return this._instances.get(this._activeKey) || null;
|
|
14368
15333
|
}
|
|
14369
15334
|
/**
|
|
14370
15335
|
* Get stats for all instances.
|
|
14371
15336
|
*/
|
|
14372
15337
|
getStats() {
|
|
14373
|
-
this.
|
|
15338
|
+
if (this._instances.size === 0) {
|
|
15339
|
+
return {
|
|
15340
|
+
total: 0,
|
|
15341
|
+
maxPoolSize: this._maxPoolSize,
|
|
15342
|
+
active: null,
|
|
15343
|
+
strategy: this._strategy,
|
|
15344
|
+
instances: []
|
|
15345
|
+
};
|
|
15346
|
+
}
|
|
14374
15347
|
return {
|
|
14375
15348
|
total: this._instances.size,
|
|
14376
15349
|
maxPoolSize: this._maxPoolSize,
|
|
@@ -14382,7 +15355,7 @@ var init_cad_pool = __esm({
|
|
|
14382
15355
|
platform: i.platform,
|
|
14383
15356
|
version: i.version,
|
|
14384
15357
|
label: i.label,
|
|
14385
|
-
queueSize: i.connection
|
|
15358
|
+
queueSize: i.connection?._getQueueSize ? i.connection._getQueueSize() : 0,
|
|
14386
15359
|
lastPingAgo: Date.now() - (i.lastPing || 0),
|
|
14387
15360
|
uptime: i.connected ? Math.round((Date.now() - i.createdAt) / 1e3) : 0
|
|
14388
15361
|
}))
|
|
@@ -14392,7 +15365,7 @@ var init_cad_pool = __esm({
|
|
|
14392
15365
|
* List all instances.
|
|
14393
15366
|
*/
|
|
14394
15367
|
listInstances() {
|
|
14395
|
-
this.
|
|
15368
|
+
if (this._instances.size === 0) return [];
|
|
14396
15369
|
return Array.from(this._instances.values()).map((i) => ({
|
|
14397
15370
|
key: i.key,
|
|
14398
15371
|
connected: i.connected,
|
|
@@ -14404,7 +15377,7 @@ var init_cad_pool = __esm({
|
|
|
14404
15377
|
}));
|
|
14405
15378
|
}
|
|
14406
15379
|
/**
|
|
14407
|
-
* Disconnect all instances.
|
|
15380
|
+
* Disconnect all instances in parallel.
|
|
14408
15381
|
*/
|
|
14409
15382
|
async disconnectAll() {
|
|
14410
15383
|
this.stopHealthCheck();
|
|
@@ -14413,27 +15386,16 @@ var init_cad_pool = __esm({
|
|
|
14413
15386
|
}
|
|
14414
15387
|
this._reconnectTimers.clear();
|
|
14415
15388
|
this._reconnectCounts.clear();
|
|
14416
|
-
|
|
15389
|
+
const entries = Array.from(this._instances.entries());
|
|
15390
|
+
this._instances.clear();
|
|
15391
|
+
this._activeKey = null;
|
|
15392
|
+
await Promise.allSettled(entries.map(async ([key, entry]) => {
|
|
14417
15393
|
try {
|
|
14418
15394
|
await entry.connection.disconnect();
|
|
14419
15395
|
} catch (e) {
|
|
14420
15396
|
error(`\u8FDE\u63A5\u6C60: \u65AD\u5F00 "${key}" \u51FA\u9519: ${e.message}`);
|
|
14421
15397
|
}
|
|
14422
|
-
}
|
|
14423
|
-
this._instances.clear();
|
|
14424
|
-
this._activeKey = "default";
|
|
14425
|
-
const defaultConn = getActiveConnection();
|
|
14426
|
-
this._instances.set("default", {
|
|
14427
|
-
key: "default",
|
|
14428
|
-
connection: defaultConn,
|
|
14429
|
-
platform: null,
|
|
14430
|
-
version: null,
|
|
14431
|
-
connected: false,
|
|
14432
|
-
lastPing: Date.now(),
|
|
14433
|
-
createdAt: Date.now(),
|
|
14434
|
-
label: "\u9ED8\u8BA4 CAD",
|
|
14435
|
-
autoReconnect: true
|
|
14436
|
-
});
|
|
15398
|
+
}));
|
|
14437
15399
|
log("\u8FDE\u63A5\u6C60: \u6240\u6709\u5B9E\u4F8B\u5DF2\u65AD\u5F00");
|
|
14438
15400
|
}
|
|
14439
15401
|
// --- Internal ---
|
|
@@ -14493,7 +15455,7 @@ var init_cad_pool = __esm({
|
|
|
14493
15455
|
});
|
|
14494
15456
|
|
|
14495
15457
|
// src/trigger-engine.js
|
|
14496
|
-
function
|
|
15458
|
+
function escapeLispStr2(v) {
|
|
14497
15459
|
if (typeof v !== "string") return v;
|
|
14498
15460
|
return v.replace(/\\/g, "\\\\").replace(/"/g, '\\"');
|
|
14499
15461
|
}
|
|
@@ -14501,10 +15463,10 @@ function buildFilterExpr(filter) {
|
|
|
14501
15463
|
if (!filter || typeof filter !== "object") return "nil";
|
|
14502
15464
|
const parts = [];
|
|
14503
15465
|
if (filter.type) {
|
|
14504
|
-
parts.push(`(cons 0 "${
|
|
15466
|
+
parts.push(`(cons 0 "${escapeLispStr2(filter.type)}")`);
|
|
14505
15467
|
}
|
|
14506
15468
|
if (filter.layer) {
|
|
14507
|
-
parts.push(`(cons 8 "${
|
|
15469
|
+
parts.push(`(cons 8 "${escapeLispStr2(filter.layer)}")`);
|
|
14508
15470
|
}
|
|
14509
15471
|
if (parts.length === 0) return "nil";
|
|
14510
15472
|
return `(list ${parts.join(" ")})`;
|
|
@@ -14553,7 +15515,7 @@ async function evaluateWatch(watch) {
|
|
|
14553
15515
|
return { matched, data: { count } };
|
|
14554
15516
|
}
|
|
14555
15517
|
case "layer_exists": {
|
|
14556
|
-
const lName =
|
|
15518
|
+
const lName = escapeLispStr2(watch.layerName || "");
|
|
14557
15519
|
result = await cad.sendCommandWithResult(
|
|
14558
15520
|
`(progn (if (tblsearch "LAYER" "${lName}") (list 1) (list 0)))`
|
|
14559
15521
|
);
|
|
@@ -14561,7 +15523,7 @@ async function evaluateWatch(watch) {
|
|
|
14561
15523
|
return { matched: exists, data: { exists, layerName: watch.layerName } };
|
|
14562
15524
|
}
|
|
14563
15525
|
case "doc_name": {
|
|
14564
|
-
const pattern =
|
|
15526
|
+
const pattern = escapeLispStr2(watch.pattern || "*");
|
|
14565
15527
|
result = await cad.sendCommandWithResult(
|
|
14566
15528
|
`(progn (setq _dn (getvar "dwgname")) (setq _dm (if (wcmatch _dn "${pattern}") 1 0)) (list _dm _dn))`
|
|
14567
15529
|
);
|
|
@@ -14571,14 +15533,14 @@ async function evaluateWatch(watch) {
|
|
|
14571
15533
|
return { matched, data: { matched: Boolean(matched), name } };
|
|
14572
15534
|
}
|
|
14573
15535
|
case "doc_path": {
|
|
14574
|
-
const pattern =
|
|
15536
|
+
const pattern = escapeLispStr2(watch.pattern || "*");
|
|
14575
15537
|
result = await cad.sendCommandWithResult(
|
|
14576
15538
|
`(progn (setq _dp (getvar "dwgprefix")) (setq _dm (if (wcmatch _dp "${pattern}") 1 0)) (list _dm _dp))`
|
|
14577
15539
|
);
|
|
14578
15540
|
const arr = parseLispList2(result) || [];
|
|
14579
15541
|
const matched = Number(arr[0]) !== 0;
|
|
14580
|
-
const
|
|
14581
|
-
return { matched, data: { matched: Boolean(matched), path:
|
|
15542
|
+
const path21 = String(arr[1] || "");
|
|
15543
|
+
return { matched, data: { matched: Boolean(matched), path: path21 } };
|
|
14582
15544
|
}
|
|
14583
15545
|
case "entity_selected": {
|
|
14584
15546
|
result = await cad.sendCommandWithResult(
|
|
@@ -14748,53 +15710,6 @@ function stripStringsAndComments(code) {
|
|
|
14748
15710
|
const withoutStrings = code.replace(/"([^"\\]*(?:\\.[^"\\]*)*)"/g, "");
|
|
14749
15711
|
return withoutStrings.replace(/;.*$/gm, "");
|
|
14750
15712
|
}
|
|
14751
|
-
var THREAT_BLOCK, THREAT_WARN, THREAT_ALLOW, CVT, SECURITY_RULES, _cachedLevel;
|
|
14752
|
-
var init_lisp_security = __esm({
|
|
14753
|
-
"src/lisp-security.js"() {
|
|
14754
|
-
init_logger();
|
|
14755
|
-
init_config();
|
|
14756
|
-
THREAT_BLOCK = "block";
|
|
14757
|
-
THREAT_WARN = "warn";
|
|
14758
|
-
THREAT_ALLOW = "allow";
|
|
14759
|
-
CVT = {
|
|
14760
|
-
strict: THREAT_BLOCK,
|
|
14761
|
-
standard: THREAT_WARN,
|
|
14762
|
-
relaxed: THREAT_ALLOW
|
|
14763
|
-
};
|
|
14764
|
-
SECURITY_RULES = [
|
|
14765
|
-
{ re: /\bstartapp\s*[(\s]/i, baseSeverity: THREAT_BLOCK, msg: "\u7981\u6B62\u4F7F\u7528 startapp \u51FD\u6570" },
|
|
14766
|
-
{ re: /\bvl-bt\b/i, baseSeverity: THREAT_BLOCK, msg: "\u7981\u6B62\u4F7F\u7528 vl-bt \u51FD\u6570" },
|
|
14767
|
-
{ re: /\bvlax-import-type-library\b/i, baseSeverity: THREAT_BLOCK, msg: "\u7981\u6B62\u5BFC\u5165\u7C7B\u578B\u5E93" },
|
|
14768
|
-
{ re: /\bdos_command_string\s*[(\s]/i, baseSeverity: THREAT_BLOCK, msg: "\u7981\u6B62\u4F7F\u7528 dos_command_string" },
|
|
14769
|
-
{ re: /\beval\s*[(\s]/i, baseSeverity: THREAT_BLOCK, msg: "\u7981\u6B62\u4F7F\u7528 eval \u51FD\u6570" },
|
|
14770
|
-
{ re: /\bcommand\s*["\s]*[_(]?\s*["']?\.?\s*_?(?:shell|quit|exit|close|open|new|recover|audit|purge|wblock|export)/i, baseSeverity: THREAT_BLOCK, msg: "\u7981\u6B62\u4F7F\u7528\u5371\u9669 CAD \u547D\u4EE4" },
|
|
14771
|
-
{ re: /\bload\s*[(\s"]/i, baseSeverity: THREAT_BLOCK, msg: "load \u51FD\u6570\u53EF\u80FD\u52A0\u8F7D\u5916\u90E8\u4EE3\u7801" },
|
|
14772
|
-
{ re: /\b(?:read-line|read-char|write-line|write-char)\s*[(\s]/i, baseSeverity: THREAT_BLOCK, msg: "\u6587\u4EF6 I/O \u64CD\u4F5C\u53EF\u80FD\u5F71\u54CD\u7CFB\u7EDF" },
|
|
14773
|
-
{ re: /\bvl-file-copy\s*[(\s]/i, baseSeverity: THREAT_BLOCK, msg: "\u7981\u6B62\u6587\u4EF6\u590D\u5236" },
|
|
14774
|
-
{ re: /\bvl-file-delete\s*[(\s]/i, baseSeverity: THREAT_BLOCK, msg: "\u7981\u6B62\u6587\u4EF6\u5220\u9664" },
|
|
14775
|
-
{ re: /\bvl-file-rename\s*[(\s]/i, baseSeverity: THREAT_BLOCK, msg: "\u7981\u6B62\u6587\u4EF6\u91CD\u547D\u540D" },
|
|
14776
|
-
{ re: /\bvl-registry-write[\s\)]/i, baseSeverity: THREAT_BLOCK, msg: "vl-registry-write \u4F1A\u4FEE\u6539\u6CE8\u518C\u8868" },
|
|
14777
|
-
{ re: /\bvl-exit-with-value\b/i, baseSeverity: THREAT_BLOCK, msg: "\u7981\u6B62\u4F7F\u7528 vl-exit-with-value" },
|
|
14778
|
-
{ re: /\bvl-exit-with-error\b/i, baseSeverity: THREAT_BLOCK, msg: "\u7981\u6B62\u4F7F\u7528 vl-exit-with-error" },
|
|
14779
|
-
{ re: /\bvlax-add-cmd\b/i, baseSeverity: THREAT_BLOCK, msg: "\u7981\u6B62\u6CE8\u518C\u65B0\u547D\u4EE4" },
|
|
14780
|
-
{ re: /\bvla-Delete\b/i, baseSeverity: THREAT_BLOCK, msg: "\u7981\u6B62\u76F4\u63A5\u5220\u9664 vla \u5BF9\u8C61" },
|
|
14781
|
-
{ re: /\bvla-Save\s*[(\s]/i, baseSeverity: THREAT_BLOCK, msg: "\u7981\u6B62\u76F4\u63A5\u4FDD\u5B58\u6587\u6863" },
|
|
14782
|
-
{ re: /\bdirectory\s*[(\s]/i, baseSeverity: THREAT_BLOCK, msg: "\u7981\u6B62\u4F7F\u7528 directory \u51FD\u6570" },
|
|
14783
|
-
{ re: /\bvla-deletefile\b/i, baseSeverity: THREAT_BLOCK, msg: "\u7981\u6B62\u5220\u9664\u6587\u4EF6" },
|
|
14784
|
-
{ re: /\bvla-copyfile\b/i, baseSeverity: THREAT_BLOCK, msg: "\u7981\u6B62\u590D\u5236\u6587\u4EF6" },
|
|
14785
|
-
{ re: /\bvla-movefile\b/i, baseSeverity: THREAT_BLOCK, msg: "\u7981\u6B62\u79FB\u52A8\u6587\u4EF6" }
|
|
14786
|
-
];
|
|
14787
|
-
_cachedLevel = null;
|
|
14788
|
-
try {
|
|
14789
|
-
onConfigChange(() => {
|
|
14790
|
-
_cachedLevel = null;
|
|
14791
|
-
});
|
|
14792
|
-
} catch (_) {
|
|
14793
|
-
}
|
|
14794
|
-
}
|
|
14795
|
-
});
|
|
14796
|
-
|
|
14797
|
-
// src/lisp-sandbox.js
|
|
14798
15713
|
function getSessionAllowlist(sessionId) {
|
|
14799
15714
|
if (!sessionAllowlist.has(sessionId)) {
|
|
14800
15715
|
sessionAllowlist.set(sessionId, /* @__PURE__ */ new Set());
|
|
@@ -14838,66 +15753,103 @@ function validateLispCode(code, sessionId = null) {
|
|
|
14838
15753
|
summary: blocked ? `\u5B89\u5168\u9650\u5236: ${results.filter((r) => r.blocked).map((r) => r.message).join("; ")}` : "\u901A\u8FC7"
|
|
14839
15754
|
};
|
|
14840
15755
|
}
|
|
14841
|
-
var RULES2, sessionAllowlist;
|
|
14842
|
-
var
|
|
14843
|
-
"src/lisp-
|
|
15756
|
+
var THREAT_BLOCK, THREAT_WARN, THREAT_ALLOW, CVT, SECURITY_RULES, _cachedLevel, RULES2, sessionAllowlist;
|
|
15757
|
+
var init_lisp_security = __esm({
|
|
15758
|
+
"src/lisp-security.js"() {
|
|
14844
15759
|
init_logger();
|
|
14845
15760
|
init_config();
|
|
14846
|
-
|
|
15761
|
+
THREAT_BLOCK = "block";
|
|
15762
|
+
THREAT_WARN = "warn";
|
|
15763
|
+
THREAT_ALLOW = "allow";
|
|
15764
|
+
CVT = {
|
|
15765
|
+
strict: THREAT_BLOCK,
|
|
15766
|
+
standard: THREAT_WARN,
|
|
15767
|
+
relaxed: THREAT_ALLOW
|
|
15768
|
+
};
|
|
15769
|
+
SECURITY_RULES = [
|
|
15770
|
+
{ re: /\bstartapp\s*[(\s]/i, baseSeverity: THREAT_BLOCK, msg: "\u7981\u6B62\u4F7F\u7528 startapp \u51FD\u6570" },
|
|
15771
|
+
{ re: /\bvl-bt\b/i, baseSeverity: THREAT_BLOCK, msg: "\u7981\u6B62\u4F7F\u7528 vl-bt \u51FD\u6570" },
|
|
15772
|
+
{ re: /\bvlax-import-type-library\b/i, baseSeverity: THREAT_BLOCK, msg: "\u7981\u6B62\u5BFC\u5165\u7C7B\u578B\u5E93" },
|
|
15773
|
+
{ re: /\bdos_command_string\s*[(\s]/i, baseSeverity: THREAT_BLOCK, msg: "\u7981\u6B62\u4F7F\u7528 dos_command_string" },
|
|
15774
|
+
{ re: /\beval\s*[(\s]/i, baseSeverity: THREAT_BLOCK, msg: "\u7981\u6B62\u4F7F\u7528 eval \u51FD\u6570" },
|
|
15775
|
+
{ re: /\bcommand\s*["\s]*[_(]?\s*["']?\.?\s*_?(?:shell|quit|exit|close|open|new|recover|audit|purge|wblock|export)/i, baseSeverity: THREAT_BLOCK, msg: "\u7981\u6B62\u4F7F\u7528\u5371\u9669 CAD \u547D\u4EE4" },
|
|
15776
|
+
{ re: /\bload\s*[(\s"]/i, baseSeverity: THREAT_BLOCK, msg: "load \u51FD\u6570\u53EF\u80FD\u52A0\u8F7D\u5916\u90E8\u4EE3\u7801" },
|
|
15777
|
+
{ re: /\b(?:read-line|read-char|write-line|write-char)\s*[(\s]/i, baseSeverity: THREAT_BLOCK, msg: "\u6587\u4EF6 I/O \u64CD\u4F5C\u53EF\u80FD\u5F71\u54CD\u7CFB\u7EDF" },
|
|
15778
|
+
{ re: /\bvl-file-copy\s*[(\s]/i, baseSeverity: THREAT_BLOCK, msg: "\u7981\u6B62\u6587\u4EF6\u590D\u5236" },
|
|
15779
|
+
{ re: /\bvl-file-delete\s*[(\s]/i, baseSeverity: THREAT_BLOCK, msg: "\u7981\u6B62\u6587\u4EF6\u5220\u9664" },
|
|
15780
|
+
{ re: /\bvl-file-rename\s*[(\s]/i, baseSeverity: THREAT_BLOCK, msg: "\u7981\u6B62\u6587\u4EF6\u91CD\u547D\u540D" },
|
|
15781
|
+
{ re: /\bvl-registry-write[\s\)]/i, baseSeverity: THREAT_BLOCK, msg: "vl-registry-write \u4F1A\u4FEE\u6539\u6CE8\u518C\u8868" },
|
|
15782
|
+
{ re: /\bvl-exit-with-value\b/i, baseSeverity: THREAT_BLOCK, msg: "\u7981\u6B62\u4F7F\u7528 vl-exit-with-value" },
|
|
15783
|
+
{ re: /\bvl-exit-with-error\b/i, baseSeverity: THREAT_BLOCK, msg: "\u7981\u6B62\u4F7F\u7528 vl-exit-with-error" },
|
|
15784
|
+
{ re: /\bvlax-add-cmd\b/i, baseSeverity: THREAT_BLOCK, msg: "\u7981\u6B62\u6CE8\u518C\u65B0\u547D\u4EE4" },
|
|
15785
|
+
{ re: /\bvla-Delete\b/i, baseSeverity: THREAT_BLOCK, msg: "\u7981\u6B62\u76F4\u63A5\u5220\u9664 vla \u5BF9\u8C61" },
|
|
15786
|
+
{ re: /\bvla-Save\s*[(\s]/i, baseSeverity: THREAT_BLOCK, msg: "\u7981\u6B62\u76F4\u63A5\u4FDD\u5B58\u6587\u6863" },
|
|
15787
|
+
{ re: /\bdirectory\s*[(\s]/i, baseSeverity: THREAT_BLOCK, msg: "\u7981\u6B62\u4F7F\u7528 directory \u51FD\u6570" },
|
|
15788
|
+
{ re: /\bvla-deletefile\b/i, baseSeverity: THREAT_BLOCK, msg: "\u7981\u6B62\u5220\u9664\u6587\u4EF6" },
|
|
15789
|
+
{ re: /\bvla-copyfile\b/i, baseSeverity: THREAT_BLOCK, msg: "\u7981\u6B62\u590D\u5236\u6587\u4EF6" },
|
|
15790
|
+
{ re: /\bvla-movefile\b/i, baseSeverity: THREAT_BLOCK, msg: "\u7981\u6B62\u79FB\u52A8\u6587\u4EF6" }
|
|
15791
|
+
];
|
|
15792
|
+
_cachedLevel = null;
|
|
15793
|
+
try {
|
|
15794
|
+
onConfigChange(() => {
|
|
15795
|
+
_cachedLevel = null;
|
|
15796
|
+
});
|
|
15797
|
+
} catch (_) {
|
|
15798
|
+
}
|
|
14847
15799
|
RULES2 = SECURITY_RULES;
|
|
14848
15800
|
sessionAllowlist = /* @__PURE__ */ new Map();
|
|
14849
15801
|
}
|
|
14850
15802
|
});
|
|
14851
15803
|
|
|
14852
15804
|
// src/repl-engine.js
|
|
14853
|
-
import { randomUUID as
|
|
15805
|
+
import { randomUUID as randomUUID5 } from "crypto";
|
|
14854
15806
|
function ensureCleanup2() {
|
|
14855
15807
|
if (cleanupTimer2) return;
|
|
14856
15808
|
cleanupTimer2 = setInterval(() => {
|
|
14857
15809
|
const now = Date.now();
|
|
14858
|
-
for (const [id, session] of
|
|
15810
|
+
for (const [id, session] of sessions2) {
|
|
14859
15811
|
if (now - session.createdAt > SESSION_TTL) {
|
|
14860
|
-
|
|
15812
|
+
sessions2.delete(id);
|
|
14861
15813
|
log(`REPL session ${id} expired (TTL)`);
|
|
14862
15814
|
}
|
|
14863
15815
|
}
|
|
14864
15816
|
}, CLEANUP_INTERVAL3);
|
|
14865
15817
|
cleanupTimer2.unref();
|
|
14866
15818
|
}
|
|
14867
|
-
function
|
|
14868
|
-
if (
|
|
15819
|
+
function createSession2() {
|
|
15820
|
+
if (sessions2.size >= MAX_SESSIONS3) {
|
|
14869
15821
|
let oldest = null;
|
|
14870
|
-
for (const [id, s] of
|
|
15822
|
+
for (const [id, s] of sessions2) {
|
|
14871
15823
|
if (!oldest || s.lastActivity < oldest.lastActivity) oldest = { id, s };
|
|
14872
15824
|
}
|
|
14873
15825
|
if (oldest) {
|
|
14874
|
-
|
|
15826
|
+
sessions2.delete(oldest.id);
|
|
14875
15827
|
log(`REPL session ${oldest.id} evicted (max sessions reached)`);
|
|
14876
15828
|
}
|
|
14877
15829
|
}
|
|
14878
15830
|
ensureCleanup2();
|
|
14879
|
-
const sessionId =
|
|
15831
|
+
const sessionId = randomUUID5();
|
|
14880
15832
|
const session = new ReplSession(sessionId);
|
|
14881
|
-
|
|
15833
|
+
sessions2.set(sessionId, session);
|
|
14882
15834
|
return sessionId;
|
|
14883
15835
|
}
|
|
14884
15836
|
async function executeInSession(sessionId, code) {
|
|
14885
|
-
let session =
|
|
15837
|
+
let session = sessions2.get(sessionId);
|
|
14886
15838
|
if (!session) {
|
|
14887
|
-
sessionId =
|
|
14888
|
-
session =
|
|
15839
|
+
sessionId = createSession2();
|
|
15840
|
+
session = sessions2.get(sessionId);
|
|
14889
15841
|
}
|
|
14890
15842
|
const result = await session.execute(code);
|
|
14891
15843
|
return { sessionId, result, history: session.history };
|
|
14892
15844
|
}
|
|
14893
15845
|
function getHistory(sessionId) {
|
|
14894
|
-
const session =
|
|
15846
|
+
const session = sessions2.get(sessionId);
|
|
14895
15847
|
if (!session) return null;
|
|
14896
15848
|
return session.history;
|
|
14897
15849
|
}
|
|
14898
|
-
function
|
|
15850
|
+
function listSessions2() {
|
|
14899
15851
|
const result = [];
|
|
14900
|
-
for (const [id, session] of
|
|
15852
|
+
for (const [id, session] of sessions2) {
|
|
14901
15853
|
result.push({
|
|
14902
15854
|
sessionId: id,
|
|
14903
15855
|
historyCount: session.history.length,
|
|
@@ -14907,20 +15859,20 @@ function listSessions() {
|
|
|
14907
15859
|
}
|
|
14908
15860
|
return result;
|
|
14909
15861
|
}
|
|
14910
|
-
function
|
|
14911
|
-
const session =
|
|
15862
|
+
function closeSession2(id) {
|
|
15863
|
+
const session = sessions2.get(id);
|
|
14912
15864
|
if (!session) return false;
|
|
14913
|
-
|
|
15865
|
+
sessions2.delete(id);
|
|
14914
15866
|
return true;
|
|
14915
15867
|
}
|
|
14916
|
-
var
|
|
15868
|
+
var sessions2, MAX_SESSIONS3, SESSION_TTL, CLEANUP_INTERVAL3, cleanupTimer2, SETQ_RE, ReplSession;
|
|
14917
15869
|
var init_repl_engine = __esm({
|
|
14918
15870
|
"src/repl-engine.js"() {
|
|
14919
15871
|
init_cad();
|
|
14920
15872
|
init_logger();
|
|
14921
15873
|
init_lint_analyzer();
|
|
14922
|
-
|
|
14923
|
-
|
|
15874
|
+
sessions2 = /* @__PURE__ */ new Map();
|
|
15875
|
+
MAX_SESSIONS3 = 50;
|
|
14924
15876
|
SESSION_TTL = 30 * 60 * 1e3;
|
|
14925
15877
|
CLEANUP_INTERVAL3 = 5 * 60 * 1e3;
|
|
14926
15878
|
cleanupTimer2 = null;
|
|
@@ -14964,13 +15916,13 @@ ${analysis.errors.map((e) => ` L${e.line}: [${e.rule}] ${e.message}`).join("\n"
|
|
|
14964
15916
|
});
|
|
14965
15917
|
|
|
14966
15918
|
// src/webhook-engine.js
|
|
14967
|
-
import
|
|
14968
|
-
import
|
|
14969
|
-
import
|
|
15919
|
+
import fs10 from "fs";
|
|
15920
|
+
import path15 from "path";
|
|
15921
|
+
import os8 from "os";
|
|
14970
15922
|
function loadWebhooks() {
|
|
14971
15923
|
try {
|
|
14972
|
-
if (
|
|
14973
|
-
webhooks = JSON.parse(
|
|
15924
|
+
if (fs10.existsSync(WEBHOOKS_FILE)) {
|
|
15925
|
+
webhooks = JSON.parse(fs10.readFileSync(WEBHOOKS_FILE, "utf-8"));
|
|
14974
15926
|
}
|
|
14975
15927
|
} catch (e) {
|
|
14976
15928
|
error(`Webhook load error: ${e.message}`);
|
|
@@ -14978,8 +15930,8 @@ function loadWebhooks() {
|
|
|
14978
15930
|
}
|
|
14979
15931
|
function saveWebhooks() {
|
|
14980
15932
|
try {
|
|
14981
|
-
ensureDir(
|
|
14982
|
-
|
|
15933
|
+
ensureDir(path15.dirname(WEBHOOKS_FILE));
|
|
15934
|
+
fs10.writeFileSync(WEBHOOKS_FILE, JSON.stringify(webhooks, null, 2), "utf-8");
|
|
14983
15935
|
} catch (e) {
|
|
14984
15936
|
error(`Webhook save error: ${e.message}`);
|
|
14985
15937
|
}
|
|
@@ -15036,10 +15988,10 @@ function listWebhooks() {
|
|
|
15036
15988
|
}
|
|
15037
15989
|
function getWebhookLog(id) {
|
|
15038
15990
|
const sanitized = String(id).replace(/[^a-zA-Z0-9_-]/g, "_");
|
|
15039
|
-
const logPath =
|
|
15991
|
+
const logPath = path15.join(os8.homedir(), ".atlisp", `webhook-${sanitized}.log`);
|
|
15040
15992
|
try {
|
|
15041
|
-
if (!
|
|
15042
|
-
return
|
|
15993
|
+
if (!fs10.existsSync(logPath)) return [];
|
|
15994
|
+
return fs10.readFileSync(logPath, "utf-8").split("\n").filter(Boolean).map((l) => JSON.parse(l));
|
|
15043
15995
|
} catch (e) {
|
|
15044
15996
|
error(`Webhook log read error [${sanitized}]: ${e.message}`);
|
|
15045
15997
|
return [];
|
|
@@ -15050,30 +16002,30 @@ var init_webhook_engine = __esm({
|
|
|
15050
16002
|
"src/webhook-engine.js"() {
|
|
15051
16003
|
init_logger();
|
|
15052
16004
|
init_handler_utils();
|
|
15053
|
-
WEBHOOKS_FILE =
|
|
16005
|
+
WEBHOOKS_FILE = path15.join(os8.homedir(), ".atlisp", "webhooks.json");
|
|
15054
16006
|
webhooks = [];
|
|
15055
16007
|
loadWebhooks();
|
|
15056
16008
|
}
|
|
15057
16009
|
});
|
|
15058
16010
|
|
|
15059
16011
|
// src/audit-log.js
|
|
15060
|
-
import
|
|
15061
|
-
import
|
|
15062
|
-
import
|
|
16012
|
+
import fs11 from "fs";
|
|
16013
|
+
import path16 from "path";
|
|
16014
|
+
import os9 from "os";
|
|
15063
16015
|
import zlib from "zlib";
|
|
15064
16016
|
function rotateIfNeeded() {
|
|
15065
16017
|
try {
|
|
15066
|
-
if (
|
|
16018
|
+
if (fs11.existsSync(AUDIT_FILE) && fs11.statSync(AUDIT_FILE).size > MAX_LOG_SIZE2) {
|
|
15067
16019
|
const rotated = AUDIT_FILE.replace(".log", `.${Date.now()}.log`);
|
|
15068
|
-
|
|
16020
|
+
fs11.renameSync(AUDIT_FILE, rotated);
|
|
15069
16021
|
try {
|
|
15070
|
-
const compressed = zlib.gzipSync(
|
|
15071
|
-
|
|
15072
|
-
|
|
16022
|
+
const compressed = zlib.gzipSync(fs11.readFileSync(rotated));
|
|
16023
|
+
fs11.writeFileSync(rotated + ".gz", compressed);
|
|
16024
|
+
fs11.unlinkSync(rotated);
|
|
15073
16025
|
} catch (e) {
|
|
15074
16026
|
error(`Audit log compression failed, keeping raw file: ${e.message}`);
|
|
15075
16027
|
try {
|
|
15076
|
-
|
|
16028
|
+
fs11.unlinkSync(rotated + ".gz");
|
|
15077
16029
|
} catch {
|
|
15078
16030
|
}
|
|
15079
16031
|
}
|
|
@@ -15097,15 +16049,15 @@ function writeAuditEntry(entry) {
|
|
|
15097
16049
|
user: entry.user || "",
|
|
15098
16050
|
role: entry.role || ""
|
|
15099
16051
|
}) + "\n";
|
|
15100
|
-
|
|
16052
|
+
fs11.appendFileSync(AUDIT_FILE, line, "utf-8");
|
|
15101
16053
|
} catch (e) {
|
|
15102
16054
|
error(`Audit log write error: ${e.message}`);
|
|
15103
16055
|
}
|
|
15104
16056
|
}
|
|
15105
16057
|
function queryAuditLog(filters = {}) {
|
|
15106
16058
|
try {
|
|
15107
|
-
if (!
|
|
15108
|
-
const content =
|
|
16059
|
+
if (!fs11.existsSync(AUDIT_FILE)) return { total: 0, offset: 0, count: 0, entries: [] };
|
|
16060
|
+
const content = fs11.readFileSync(AUDIT_FILE, "utf-8");
|
|
15109
16061
|
const lines = content.trim().split("\n").filter(Boolean);
|
|
15110
16062
|
let entries = lines.map((l) => {
|
|
15111
16063
|
try {
|
|
@@ -15137,8 +16089,8 @@ function queryAuditLog(filters = {}) {
|
|
|
15137
16089
|
}
|
|
15138
16090
|
function getAuditStats() {
|
|
15139
16091
|
try {
|
|
15140
|
-
if (!
|
|
15141
|
-
const content =
|
|
16092
|
+
if (!fs11.existsSync(AUDIT_FILE)) return { totalEntries: 0, tools: {}, errors: 0 };
|
|
16093
|
+
const content = fs11.readFileSync(AUDIT_FILE, "utf-8");
|
|
15142
16094
|
const lines = content.trim().split("\n").filter(Boolean);
|
|
15143
16095
|
const toolCounts = {};
|
|
15144
16096
|
let errors = 0;
|
|
@@ -15154,7 +16106,7 @@ function getAuditStats() {
|
|
|
15154
16106
|
totalEntries: lines.length,
|
|
15155
16107
|
tools: toolCounts,
|
|
15156
16108
|
errors,
|
|
15157
|
-
fileSize:
|
|
16109
|
+
fileSize: fs11.existsSync(AUDIT_FILE) ? fs11.statSync(AUDIT_FILE).size : 0,
|
|
15158
16110
|
filePath: AUDIT_FILE
|
|
15159
16111
|
};
|
|
15160
16112
|
} catch (e) {
|
|
@@ -15166,8 +16118,8 @@ var init_audit_log = __esm({
|
|
|
15166
16118
|
"src/audit-log.js"() {
|
|
15167
16119
|
init_logger();
|
|
15168
16120
|
init_handler_utils();
|
|
15169
|
-
AUDIT_DIR =
|
|
15170
|
-
AUDIT_FILE =
|
|
16121
|
+
AUDIT_DIR = path16.join(os9.homedir(), "@lisp", "logs");
|
|
16122
|
+
AUDIT_FILE = path16.join(AUDIT_DIR, "audit.log");
|
|
15171
16123
|
MAX_LOG_SIZE2 = 10 * 1024 * 1024;
|
|
15172
16124
|
MAX_LOG_AGE = 90 * 24 * 60 * 60 * 1e3;
|
|
15173
16125
|
}
|
|
@@ -15201,14 +16153,17 @@ var init_agent_context = __esm({
|
|
|
15201
16153
|
});
|
|
15202
16154
|
|
|
15203
16155
|
// src/tool-validators.js
|
|
15204
|
-
function
|
|
16156
|
+
function validationError(msg) {
|
|
16157
|
+
return new MCPError(ERROR_CODES.INVALID_ARGS, msg);
|
|
16158
|
+
}
|
|
16159
|
+
function validateProps(args, props, required, path21 = "") {
|
|
15205
16160
|
for (const [key, prop] of Object.entries(props)) {
|
|
15206
|
-
const fullKey =
|
|
16161
|
+
const fullKey = path21 ? `${path21}.${key}` : key;
|
|
15207
16162
|
const isOptional = !required.includes(key);
|
|
15208
16163
|
const val = args[key];
|
|
15209
16164
|
if (val === void 0 || val === null) {
|
|
15210
16165
|
if (isOptional) continue;
|
|
15211
|
-
throw
|
|
16166
|
+
throw validationError(`Missing required argument: ${fullKey}`);
|
|
15212
16167
|
}
|
|
15213
16168
|
if (prop.type === "object" && prop.properties && typeof val === "object" && !Array.isArray(val)) {
|
|
15214
16169
|
const subRequired = prop.required || [];
|
|
@@ -15223,46 +16178,46 @@ function validateProps(args, props, required, path20 = "") {
|
|
|
15223
16178
|
const actualType = typeof val;
|
|
15224
16179
|
const expectedType = prop.type || "string";
|
|
15225
16180
|
if (expectedType === "string" && actualType !== "string" && actualType !== "number") {
|
|
15226
|
-
throw
|
|
16181
|
+
throw validationError(`Invalid type for argument ${fullKey}: expected string, got ${actualType}`);
|
|
15227
16182
|
}
|
|
15228
16183
|
if ((expectedType === "object" || expectedType === "array") && (actualType !== "object" || val === null)) {
|
|
15229
|
-
throw
|
|
16184
|
+
throw validationError(`Invalid type for argument ${fullKey}: expected ${expectedType}, got ${actualType}`);
|
|
15230
16185
|
}
|
|
15231
16186
|
if (expectedType === "array" && !Array.isArray(val)) {
|
|
15232
|
-
throw
|
|
16187
|
+
throw validationError(`Invalid type for argument ${fullKey}: expected array, got ${actualType}`);
|
|
15233
16188
|
}
|
|
15234
16189
|
if (expectedType === "object" && Array.isArray(val)) {
|
|
15235
|
-
throw
|
|
16190
|
+
throw validationError(`Invalid type for argument ${fullKey}: expected object, got array`);
|
|
15236
16191
|
}
|
|
15237
16192
|
if ((expectedType === "number" || expectedType === "integer") && actualType !== "number") {
|
|
15238
16193
|
if (expectedType === "integer" && !Number.isInteger(val)) {
|
|
15239
|
-
throw
|
|
16194
|
+
throw validationError(`Invalid type for argument ${fullKey}: expected integer, got ${actualType}`);
|
|
15240
16195
|
}
|
|
15241
16196
|
if (expectedType === "number") {
|
|
15242
|
-
throw
|
|
16197
|
+
throw validationError(`Invalid type for argument ${fullKey}: expected number, got ${actualType}`);
|
|
15243
16198
|
}
|
|
15244
16199
|
}
|
|
15245
16200
|
if (expectedType === "boolean" && actualType !== "boolean") {
|
|
15246
|
-
throw
|
|
16201
|
+
throw validationError(`Invalid type for argument ${fullKey}: expected boolean, got ${actualType}`);
|
|
15247
16202
|
}
|
|
15248
16203
|
if (prop.enum && !prop.enum.includes(val)) {
|
|
15249
|
-
throw
|
|
16204
|
+
throw validationError(`Invalid value for argument ${fullKey}: must be one of ${prop.enum.join(", ")}`);
|
|
15250
16205
|
}
|
|
15251
16206
|
if (expectedType === "string" && typeof prop.maxLength === "number" && String(val).length > prop.maxLength) {
|
|
15252
|
-
throw
|
|
16207
|
+
throw validationError(`Argument ${fullKey} exceeds max length of ${prop.maxLength}`);
|
|
15253
16208
|
}
|
|
15254
16209
|
if ((expectedType === "number" || expectedType === "integer") && prop.minimum != null && val < prop.minimum) {
|
|
15255
|
-
throw
|
|
16210
|
+
throw validationError(`Argument ${fullKey} must be >= ${prop.minimum}`);
|
|
15256
16211
|
}
|
|
15257
16212
|
if ((expectedType === "number" || expectedType === "integer") && prop.maximum != null && val > prop.maximum) {
|
|
15258
|
-
throw
|
|
16213
|
+
throw validationError(`Argument ${fullKey} must be <= ${prop.maximum}`);
|
|
15259
16214
|
}
|
|
15260
16215
|
}
|
|
15261
16216
|
}
|
|
15262
16217
|
function validateToolArgs(name, args) {
|
|
15263
16218
|
const toolDef = toolsByName.get(name);
|
|
15264
16219
|
if (!toolDef) {
|
|
15265
|
-
throw
|
|
16220
|
+
throw validationError(`Unknown tool: ${name}`);
|
|
15266
16221
|
}
|
|
15267
16222
|
const schema = toolDef.inputSchema;
|
|
15268
16223
|
if (!schema || !schema.properties) return true;
|
|
@@ -15270,7 +16225,7 @@ function validateToolArgs(name, args) {
|
|
|
15270
16225
|
const required = schema.required || [];
|
|
15271
16226
|
for (const req of required) {
|
|
15272
16227
|
if (!(req in (args || {}))) {
|
|
15273
|
-
throw
|
|
16228
|
+
throw validationError(`Missing required argument: ${req}`);
|
|
15274
16229
|
}
|
|
15275
16230
|
}
|
|
15276
16231
|
validateProps(args || {}, props, required);
|
|
@@ -15279,6 +16234,7 @@ function validateToolArgs(name, args) {
|
|
|
15279
16234
|
var init_tool_validators = __esm({
|
|
15280
16235
|
"src/tool-validators.js"() {
|
|
15281
16236
|
init_tools();
|
|
16237
|
+
init_errors();
|
|
15282
16238
|
}
|
|
15283
16239
|
});
|
|
15284
16240
|
|
|
@@ -15389,7 +16345,7 @@ function registerTool(toolDef, handler) {
|
|
|
15389
16345
|
}
|
|
15390
16346
|
customTools.push(toolDef);
|
|
15391
16347
|
customHandlers.set(toolDef.name, handler);
|
|
15392
|
-
|
|
16348
|
+
tools43.push(toolDef);
|
|
15393
16349
|
return true;
|
|
15394
16350
|
}
|
|
15395
16351
|
function callCustomTool(name, args) {
|
|
@@ -15409,73 +16365,92 @@ var init_tool_registry = __esm({
|
|
|
15409
16365
|
});
|
|
15410
16366
|
|
|
15411
16367
|
// src/tool-executor.js
|
|
16368
|
+
function resolveConn(instance) {
|
|
16369
|
+
if (instance) return pool.getConnection(instance) || resolveCadConnection();
|
|
16370
|
+
return cad;
|
|
16371
|
+
}
|
|
16372
|
+
async function writeAuditSuccess(name, args, options) {
|
|
16373
|
+
writeAuditEntry({
|
|
16374
|
+
timestamp: (/* @__PURE__ */ new Date()).toISOString(),
|
|
16375
|
+
tool: name,
|
|
16376
|
+
args: args || {},
|
|
16377
|
+
sessionId: options.sessionId || "",
|
|
16378
|
+
result: "success"
|
|
16379
|
+
});
|
|
16380
|
+
}
|
|
16381
|
+
async function writeAuditError(name, args, options, error2) {
|
|
16382
|
+
writeAuditEntry({
|
|
16383
|
+
timestamp: (/* @__PURE__ */ new Date()).toISOString(),
|
|
16384
|
+
tool: name,
|
|
16385
|
+
args: args || {},
|
|
16386
|
+
sessionId: options.sessionId || "",
|
|
16387
|
+
result: "error",
|
|
16388
|
+
error: error2.message
|
|
16389
|
+
});
|
|
16390
|
+
}
|
|
16391
|
+
async function beginUndo(instance) {
|
|
16392
|
+
const conn = resolveConn(instance);
|
|
16393
|
+
if (conn?.connected) {
|
|
16394
|
+
try {
|
|
16395
|
+
await conn.sendCommand('(command "_.UNDO" "_BEGIN")');
|
|
16396
|
+
return true;
|
|
16397
|
+
} catch (e) {
|
|
16398
|
+
error(`UNDO_BEGIN failed: ${e.message}`);
|
|
16399
|
+
}
|
|
16400
|
+
}
|
|
16401
|
+
return false;
|
|
16402
|
+
}
|
|
16403
|
+
async function endUndo(instance) {
|
|
16404
|
+
const conn = resolveConn(instance);
|
|
16405
|
+
try {
|
|
16406
|
+
await conn.sendCommand('(command "_.UNDO" "_END")');
|
|
16407
|
+
} catch (_) {
|
|
16408
|
+
}
|
|
16409
|
+
}
|
|
15412
16410
|
async function handleToolCall(name, args, options = {}) {
|
|
15413
16411
|
const handler = TOOL_HANDLERS[name];
|
|
15414
16412
|
if (!handler) {
|
|
15415
16413
|
const customResult = callCustomTool(name, args);
|
|
15416
16414
|
if (customResult !== null) return customResult;
|
|
15417
|
-
return
|
|
16415
|
+
return mcpErrorResponse(new MCPError(ERROR_CODES.HANDLER_NOT_FOUND, `\u672A\u77E5\u5DE5\u5177: ${name}`));
|
|
15418
16416
|
}
|
|
15419
16417
|
const isReadOnly = READ_ONLY_TOOLS.has(name);
|
|
15420
16418
|
const notifyProgress = options.notifyProgress || null;
|
|
15421
16419
|
const rateCheck = checkToolRateLimit(name, isReadOnly, options.sessionId);
|
|
15422
16420
|
if (!rateCheck.allowed) {
|
|
15423
|
-
return
|
|
16421
|
+
return mcpErrorResponse(new MCPError(ERROR_CODES.RATE_LIMITED, `\u5DE5\u5177\u8C03\u7528\u9891\u7387\u8D85\u9650\uFF0C\u8BF7 ${rateCheck.retryAfter} \u79D2\u540E\u91CD\u8BD5`));
|
|
15424
16422
|
}
|
|
15425
16423
|
return progressContext.run({ notifyProgress }, async () => {
|
|
15426
16424
|
setNotifyProgress(notifyProgress);
|
|
16425
|
+
const instance = args?.instance || null;
|
|
15427
16426
|
let undoBegun = false;
|
|
15428
16427
|
try {
|
|
15429
16428
|
validateToolArgs(name, args || {});
|
|
15430
|
-
const instance = args?.instance || null;
|
|
15431
16429
|
if (instance) {
|
|
15432
16430
|
const ctx = mcpContext.getStore();
|
|
15433
16431
|
ctx._toolInstance = instance;
|
|
15434
16432
|
}
|
|
15435
16433
|
if (!isReadOnly) {
|
|
15436
|
-
|
|
15437
|
-
if (targetConn?.connected) {
|
|
15438
|
-
try {
|
|
15439
|
-
await targetConn.sendCommand('(command "_.UNDO" "_BEGIN")');
|
|
15440
|
-
undoBegun = true;
|
|
15441
|
-
} catch (e) {
|
|
15442
|
-
error(`UNDO_BEGIN failed: ${e.message}`);
|
|
15443
|
-
}
|
|
15444
|
-
}
|
|
16434
|
+
undoBegun = await beginUndo(instance);
|
|
15445
16435
|
}
|
|
15446
16436
|
const np = getNotifyProgress();
|
|
15447
16437
|
if (np) np(1, 1, `\u6B63\u5728\u6267\u884C ${name}...`);
|
|
15448
16438
|
const result = await handler(args || {});
|
|
15449
16439
|
if (np) np(1, 1, `${name} \u6267\u884C\u5B8C\u6210`);
|
|
15450
|
-
|
|
15451
|
-
timestamp: (/* @__PURE__ */ new Date()).toISOString(),
|
|
15452
|
-
tool: name,
|
|
15453
|
-
args: args || {},
|
|
15454
|
-
sessionId: options.sessionId || "",
|
|
15455
|
-
result: result?.isError ? "error" : "success"
|
|
15456
|
-
});
|
|
16440
|
+
await writeAuditSuccess(name, args, options);
|
|
15457
16441
|
notifyResourceChanges(name);
|
|
15458
16442
|
return result;
|
|
15459
16443
|
} catch (e) {
|
|
15460
16444
|
error(`Tool call error [${name}]: ${e.message}`, { tool: name, args });
|
|
15461
|
-
|
|
15462
|
-
|
|
15463
|
-
|
|
15464
|
-
|
|
15465
|
-
|
|
15466
|
-
result: "error",
|
|
15467
|
-
error: e.message
|
|
15468
|
-
});
|
|
15469
|
-
return { content: [{ type: "text", text: `\u5DE5\u5177\u6267\u884C\u9519\u8BEF: ${e.message}` }], isError: true };
|
|
16445
|
+
await writeAuditError(name, args, options, e);
|
|
16446
|
+
if (e.message.startsWith("Missing required") || e.message.startsWith("Invalid type")) {
|
|
16447
|
+
return mcpErrorResponse(new MCPError(ERROR_CODES.INVALID_ARGS, e.message));
|
|
16448
|
+
}
|
|
16449
|
+
return mcpErrorResponse(e);
|
|
15470
16450
|
} finally {
|
|
15471
16451
|
const ctx = mcpContext.getStore();
|
|
15472
16452
|
if (ctx) ctx._toolInstance = null;
|
|
15473
|
-
if (undoBegun)
|
|
15474
|
-
try {
|
|
15475
|
-
await cad.sendCommand('(command "_.UNDO" "_END")');
|
|
15476
|
-
} catch (_) {
|
|
15477
|
-
}
|
|
15478
|
-
}
|
|
16453
|
+
if (undoBegun) await endUndo(instance);
|
|
15479
16454
|
}
|
|
15480
16455
|
});
|
|
15481
16456
|
}
|
|
@@ -15492,14 +16467,12 @@ var init_tool_executor = __esm({
|
|
|
15492
16467
|
init_cad();
|
|
15493
16468
|
init_cad_pool();
|
|
15494
16469
|
init_audit_log();
|
|
16470
|
+
init_errors();
|
|
15495
16471
|
init_tool_registry();
|
|
15496
16472
|
}
|
|
15497
16473
|
});
|
|
15498
16474
|
|
|
15499
16475
|
// src/mcp-tools.js
|
|
15500
|
-
import fs11 from "fs";
|
|
15501
|
-
import path15 from "path";
|
|
15502
|
-
import os9 from "os";
|
|
15503
16476
|
import { formatCode as formatCode2 } from "@atlisp/lint/dist/formatter.js";
|
|
15504
16477
|
import { lintProject as lintProject2 } from "@atlisp/lint/dist/project.js";
|
|
15505
16478
|
import { RULES as RULES3 } from "@atlisp/lint/dist/rules.js";
|
|
@@ -15516,7 +16489,6 @@ var TOOL_HANDLERS;
|
|
|
15516
16489
|
var init_mcp_tools = __esm({
|
|
15517
16490
|
"src/mcp-tools.js"() {
|
|
15518
16491
|
init_handler_loader();
|
|
15519
|
-
init_prompt_handlers();
|
|
15520
16492
|
init_streaming();
|
|
15521
16493
|
init_constants();
|
|
15522
16494
|
init_cad();
|
|
@@ -15524,13 +16496,24 @@ var init_mcp_tools = __esm({
|
|
|
15524
16496
|
init_tools();
|
|
15525
16497
|
init_mcp_server_state();
|
|
15526
16498
|
init_trigger_engine();
|
|
15527
|
-
|
|
16499
|
+
init_lisp_security();
|
|
15528
16500
|
init_lint_analyzer();
|
|
15529
16501
|
init_repl_engine();
|
|
15530
16502
|
init_webhook_engine();
|
|
15531
16503
|
init_audit_log();
|
|
15532
16504
|
init_agent_context();
|
|
16505
|
+
init_resource_handlers();
|
|
16506
|
+
init_subscription_manager();
|
|
16507
|
+
init_skill_handlers();
|
|
16508
|
+
init_meta_handlers();
|
|
15533
16509
|
init_tool_executor();
|
|
16510
|
+
pool.onInstanceSwitch(() => {
|
|
16511
|
+
for (const uri of CAD_RESOURCE_URIS) {
|
|
16512
|
+
if (isSubscribed(uri)) {
|
|
16513
|
+
notify2(uri, null);
|
|
16514
|
+
}
|
|
16515
|
+
}
|
|
16516
|
+
});
|
|
15534
16517
|
TOOL_HANDLERS = {
|
|
15535
16518
|
// === CAD Connection ===
|
|
15536
16519
|
connect_cad: lazy("connect_cad", (a) => a?.platform),
|
|
@@ -15567,14 +16550,8 @@ ${CAD_PLATFORMS.join("\n")}
|
|
|
15567
16550
|
return { content: [{ type: "text", text: JSON.stringify(data, null, 2) }] };
|
|
15568
16551
|
},
|
|
15569
16552
|
// === Prompts ===
|
|
15570
|
-
list_prompts:
|
|
15571
|
-
|
|
15572
|
-
return { content: [{ type: "text", text: JSON.stringify(prompts) }] };
|
|
15573
|
-
},
|
|
15574
|
-
get_prompt: async (a) => {
|
|
15575
|
-
const prompt = await getPrompt2(a.name, a.args || {});
|
|
15576
|
-
return { content: prompt.messages.map((m) => ({ type: "text", text: m.content.text || m.content })) };
|
|
15577
|
-
},
|
|
16553
|
+
list_prompts: list_prompts_handler,
|
|
16554
|
+
get_prompt: get_prompt_handler,
|
|
15578
16555
|
// === Entity Operations ===
|
|
15579
16556
|
get_entity: lazy("get_entity", (a) => a?.handle),
|
|
15580
16557
|
set_entity: lazy("set_entity", (a) => [a?.handle, a?.property, a?.value]),
|
|
@@ -15861,6 +16838,35 @@ ${CAD_PLATFORMS.join("\n")}
|
|
|
15861
16838
|
draw_ray: lazy("draw_ray", (a) => [a.point, a.direction]),
|
|
15862
16839
|
draw_leader: lazy("draw_leader", (a) => [a.points, a.annotation]),
|
|
15863
16840
|
draw_table: lazy("draw_table", (a) => [a.insertionPoint, a.rows, a.columns, a.rowHeight, a.colWidth]),
|
|
16841
|
+
// === Batch Concurrent ===
|
|
16842
|
+
batch_concurrent_tasks: async (a) => {
|
|
16843
|
+
if (!a.tasks || !Array.isArray(a.tasks) || a.tasks.length === 0) {
|
|
16844
|
+
return { content: [{ type: "text", text: "\u9700\u8981 tasks \u6570\u7EC4" }], isError: true };
|
|
16845
|
+
}
|
|
16846
|
+
if (a.tasks.length > 50) {
|
|
16847
|
+
return { content: [{ type: "text", text: "\u6700\u591A\u652F\u6301 50 \u4E2A\u5E76\u53D1\u4EFB\u52A1" }], isError: true };
|
|
16848
|
+
}
|
|
16849
|
+
const results = await Promise.allSettled(a.tasks.map(async (task, idx) => {
|
|
16850
|
+
const handler = TOOL_HANDLERS[task.tool];
|
|
16851
|
+
if (!handler) return { index: idx, tool: task.tool, instance: task.instance, ok: false, error: `\u672A\u77E5\u5DE5\u5177: ${task.tool}` };
|
|
16852
|
+
const ctx = mcpContext.getStore();
|
|
16853
|
+
const prevInstance = ctx?._toolInstance || null;
|
|
16854
|
+
if (ctx && task.instance) ctx._toolInstance = task.instance;
|
|
16855
|
+
try {
|
|
16856
|
+
const result = await handler(task.args || {});
|
|
16857
|
+
return { index: idx, tool: task.tool, instance: task.instance, ok: !result.isError, data: result.content?.[0]?.text || result };
|
|
16858
|
+
} catch (e) {
|
|
16859
|
+
return { index: idx, tool: task.tool, instance: task.instance, ok: false, error: e.message };
|
|
16860
|
+
} finally {
|
|
16861
|
+
if (ctx) ctx._toolInstance = prevInstance;
|
|
16862
|
+
}
|
|
16863
|
+
}));
|
|
16864
|
+
const output = results.map((r, idx) => {
|
|
16865
|
+
if (r.status === "fulfilled") return r.value;
|
|
16866
|
+
return { index: idx, tool: a.tasks[idx].tool, instance: a.tasks[idx].instance, ok: false, error: r.reason?.message || "Unknown error" };
|
|
16867
|
+
});
|
|
16868
|
+
return { content: [{ type: "text", text: JSON.stringify(output, null, 2) }] };
|
|
16869
|
+
},
|
|
15864
16870
|
// === Batch Transaction ===
|
|
15865
16871
|
batch_transaction: lazy("batch_transaction"),
|
|
15866
16872
|
// === Watch / Trigger ===
|
|
@@ -15907,10 +16913,10 @@ ${CAD_PLATFORMS.join("\n")}
|
|
|
15907
16913
|
return { content: [{ type: "text", text: JSON.stringify(history) }] };
|
|
15908
16914
|
},
|
|
15909
16915
|
lisp_repl_list: () => {
|
|
15910
|
-
return { content: [{ type: "text", text: JSON.stringify(
|
|
16916
|
+
return { content: [{ type: "text", text: JSON.stringify(listSessions2()) }] };
|
|
15911
16917
|
},
|
|
15912
16918
|
lisp_repl_close: (a) => {
|
|
15913
|
-
const ok =
|
|
16919
|
+
const ok = closeSession2(a.sessionId);
|
|
15914
16920
|
return { content: [{ type: "text", text: JSON.stringify({ success: ok }) }] };
|
|
15915
16921
|
},
|
|
15916
16922
|
// === Streaming ===
|
|
@@ -15982,6 +16988,12 @@ ${CAD_PLATFORMS.join("\n")}
|
|
|
15982
16988
|
return { content: [{ type: "text", text: `\u9879\u76EE\u5206\u6790\u5931\u8D25: ${e.message}` }], isError: true };
|
|
15983
16989
|
}
|
|
15984
16990
|
},
|
|
16991
|
+
// === Debug ===
|
|
16992
|
+
debug_start: lazy("debug_start", (a) => a),
|
|
16993
|
+
debug_step: lazy("debug_step", (a) => a),
|
|
16994
|
+
debug_evaluate: lazy("debug_evaluate", (a) => a),
|
|
16995
|
+
debug_get_state: lazy("debug_get_state", (a) => a),
|
|
16996
|
+
debug_stop: lazy("debug_stop", (a) => a),
|
|
15985
16997
|
// === Sandbox (Security) ===
|
|
15986
16998
|
sandbox_validate: (a) => {
|
|
15987
16999
|
const result = validateLispCode(a.code, a.sessionId || null);
|
|
@@ -16011,6 +17023,14 @@ ${CAD_PLATFORMS.join("\n")}
|
|
|
16011
17023
|
},
|
|
16012
17024
|
cad_pool_switch: (a) => {
|
|
16013
17025
|
const ok = pool.setActive(a.key);
|
|
17026
|
+
if (ok) {
|
|
17027
|
+
clearCache();
|
|
17028
|
+
for (const uri of CAD_RESOURCE_URIS) {
|
|
17029
|
+
if (isSubscribed(uri)) {
|
|
17030
|
+
notify2(uri, null);
|
|
17031
|
+
}
|
|
17032
|
+
}
|
|
17033
|
+
}
|
|
16014
17034
|
return { content: [{ type: "text", text: ok ? `\u5DF2\u5207\u6362\u5230\u5B9E\u4F8B ${a.key}` : `\u5B9E\u4F8B ${a.key} \u4E0D\u5B58\u5728` }] };
|
|
16015
17035
|
},
|
|
16016
17036
|
cad_pool_health: async () => {
|
|
@@ -16022,8 +17042,9 @@ ${CAD_PLATFORMS.join("\n")}
|
|
|
16022
17042
|
return { content: [{ type: "text", text: JSON.stringify(stats, null, 2) }] };
|
|
16023
17043
|
},
|
|
16024
17044
|
cad_pool_connect: async (a) => {
|
|
16025
|
-
const ok = await pool.connect(a.key, a.platform, { label: a.label, makeActive: a.makeActive !== false });
|
|
16026
|
-
|
|
17045
|
+
const ok = await pool.connect(a.key, a.platform, { label: a.label, pid: a.pid, makeActive: a.makeActive !== false });
|
|
17046
|
+
const label = a.key || (a.pid != null ? `PID ${a.pid}` : "default");
|
|
17047
|
+
return { content: [{ type: "text", text: ok ? `\u5B9E\u4F8B "${label}" \u5DF2\u8FDE\u63A5` : `\u5B9E\u4F8B "${label}" \u8FDE\u63A5\u5931\u8D25` }] };
|
|
16027
17048
|
},
|
|
16028
17049
|
cad_pool_disconnect: async (a) => {
|
|
16029
17050
|
const ok = await pool.disconnect(a.key);
|
|
@@ -16073,261 +17094,15 @@ ${CAD_PLATFORMS.join("\n")}
|
|
|
16073
17094
|
return { content: [{ type: "text", text: "\u4E0A\u4E0B\u6587\u5DF2\u6E05\u9664" }] };
|
|
16074
17095
|
},
|
|
16075
17096
|
// === Meta Tools ===
|
|
16076
|
-
search_tools
|
|
16077
|
-
|
|
16078
|
-
|
|
16079
|
-
const text = results.length ? `\u627E\u5230 ${results.length} \u4E2A\u5DE5\u5177:
|
|
16080
|
-
${results.map((t) => `${t.name}: ${t.description}`).join("\n")}` : `\u672A\u627E\u5230\u5305\u542B "${a.query}" \u7684\u5DE5\u5177`;
|
|
16081
|
-
return { content: [{ type: "text", text }] };
|
|
16082
|
-
},
|
|
16083
|
-
list_tools_by_category: async (a) => {
|
|
16084
|
-
const categories = {};
|
|
16085
|
-
for (const t of tools41) {
|
|
16086
|
-
let cat = "\u5176\u4ED6";
|
|
16087
|
-
const n = t.name;
|
|
16088
|
-
if (/^(draw_|create_3d_|create_box|create_cone|create_cylinder|create_sphere|create_torus|create_wedge|extrude_|revolve_|boolean_|slice_solid|thicken_|offset_surface|create_loft_|create_region)/.test(n)) cat = "\u7ED8\u56FE\u4E0E3D";
|
|
16089
|
-
else if (/^(move_|copy_|rotate_|scale_|mirror_|offset_|array_|batch_)/.test(n)) cat = "\u4FEE\u6539";
|
|
16090
|
-
else if (/^(trim_|extend_|fillet|chamfer|break_|join_|stretch)/.test(n)) cat = "\u7F16\u8F91";
|
|
16091
|
-
else if (/^(create_layer|delete_layer|set_layer|layer_)/.test(n)) cat = "\u56FE\u5C42";
|
|
16092
|
-
else if (/^(create_block|insert_block|explode_block|get_block|set_block|batch_get_block|batch_set_block)/.test(n)) cat = "\u5757";
|
|
16093
|
-
else if (/^(create_dim|list_dim|set_dim|create_hatch|set_hatch)/.test(n)) cat = "\u6807\u6CE8\u4E0E\u586B\u5145";
|
|
16094
|
-
else if (/^(create_ucs|set_ucs|delete_ucs|list_ucs|get_current_ucs|create_layout|delete_layout|rename_layout|set_layout|list_layouts|get_current_layout)/.test(n)) cat = "\u5750\u6807\u7CFB\u4E0E\u5E03\u5C40";
|
|
16095
|
-
else if (/^(create_viewport|set_viewport|lock_viewport|unlock_viewport|maximize_viewport)/.test(n)) cat = "\u89C6\u53E3";
|
|
16096
|
-
else if (/^find_/.test(n)) cat = "\u7A7A\u95F4\u67E5\u8BE2";
|
|
16097
|
-
else if (/^(select_|get_entity|set_entity|delete_entity|get_bounding_box)/.test(n)) cat = "\u9009\u62E9\u4E0E\u5C5E\u6027";
|
|
16098
|
-
else if (/^(open_dwg|save_dwg|export_|import_|close_dwg|publish_)/.test(n)) cat = "\u6587\u4EF6";
|
|
16099
|
-
else if (/^(plot_|save_pdf|batch_plot|publish_layouts)/.test(n)) cat = "\u6253\u5370";
|
|
16100
|
-
else if (/^(get_xdata|set_xdata|delete_xdata|list_xdata|copxy_xdata|search_by_xdata|export_xdata|import_xdata)/.test(n)) cat = "\u6269\u5C55\u6570\u636E";
|
|
16101
|
-
else if (/^(create_sheet|open_sheet|list_sheet|add_sheet|delete_sheet|publish_sheet|sheet_|reorder_sheet|create_subset|list_subset|set_sheet)/.test(n)) cat = "\u56FE\u7EB8\u96C6";
|
|
16102
|
-
else if (/^(attach_|detach_|reload_|list_attached|get_pdf|create_dgn|create_dwf|import_dxf|import_dgn|export_dgn|create_hyper|remove_hyper|xref|bind_xref|clip_xref|path_xref)/.test(n)) cat = "\u53C2\u7167\u4E0E\u5E95\u56FE";
|
|
16103
|
-
else if (/^(create_text|create_mleader|create_linetype|list_text|list_linetype|list_mleader|load_linetype|create_dimension_style|set_dimstyle|list_dimension_styles|set_mleader_style)/.test(n)) cat = "\u6837\u5F0F";
|
|
16104
|
-
else if (/^(purge_|drawing_audit|drawing_recover|overkill)/.test(n)) cat = "\u6E05\u7406";
|
|
16105
|
-
else if (/^(find_text|replace_text|set_text_|justify_|convert_text|explode_text)/.test(n)) cat = "\u6587\u5B57";
|
|
16106
|
-
else if (/^(eval_lisp|connect_cad|get_cad|get_platform|get_system|at_command|new_document|bring_to_front|install_atlisp|init_atlisp|get_system_status)/.test(n)) cat = "\u7CFB\u7EDF";
|
|
16107
|
-
else if (/^(list_packages|search_packages|install_package|get_function_usage|list_symbols|import_funlib)/.test(n)) cat = "\u5305\u4E0E\u51FD\u6570";
|
|
16108
|
-
else if (/^(pipeline_|watch_|lisp_repl|webhook_|sandbox_|audit_|cad_pool_|external_|list_data|export_to|import_external)/.test(n)) cat = "\u9AD8\u7EA7";
|
|
16109
|
-
else if (/^(list_prompts|get_prompt|search_tools|list_tools_by_category)/.test(n)) cat = "\u5143\u5DE5\u5177";
|
|
16110
|
-
else if (/^(agent_)/.test(n)) cat = "Agent\u4E0A\u4E0B\u6587";
|
|
16111
|
-
if (!categories[cat]) categories[cat] = [];
|
|
16112
|
-
categories[cat].push(t.name);
|
|
16113
|
-
}
|
|
16114
|
-
if (a.category) {
|
|
16115
|
-
const names = categories[a.category];
|
|
16116
|
-
return { content: [{ type: "text", text: names ? `${a.category} (${names.length}):
|
|
16117
|
-
${names.join("\n")}` : `\u672A\u627E\u5230\u5206\u7C7B: ${a.category}` }] };
|
|
16118
|
-
}
|
|
16119
|
-
const lines = [];
|
|
16120
|
-
for (const [cat, names] of Object.entries(categories)) {
|
|
16121
|
-
lines.push(`## ${cat} (${names.length})`);
|
|
16122
|
-
}
|
|
16123
|
-
lines.push(`
|
|
16124
|
-
\u5171 ${Object.keys(categories).length} \u4E2A\u5206\u7C7B`);
|
|
16125
|
-
return { content: [{ type: "text", text: lines.join("\n") }] };
|
|
16126
|
-
},
|
|
17097
|
+
search_tools,
|
|
17098
|
+
list_tools_by_category,
|
|
17099
|
+
get_tool_info,
|
|
16127
17100
|
// === Skill Management ===
|
|
16128
|
-
skill_search
|
|
16129
|
-
|
|
16130
|
-
|
|
16131
|
-
|
|
16132
|
-
|
|
16133
|
-
if (fs11.existsSync(cachePath)) cache = JSON.parse(fs11.readFileSync(cachePath, "utf-8"));
|
|
16134
|
-
} catch {
|
|
16135
|
-
}
|
|
16136
|
-
let index = cache && Date.now() - cache.fetchedAt < 36e5 ? cache : null;
|
|
16137
|
-
if (!index) {
|
|
16138
|
-
try {
|
|
16139
|
-
const resp = await fetch(registryUrl, { headers: { "User-Agent": "atlisp-mcp" } });
|
|
16140
|
-
if (resp.ok) {
|
|
16141
|
-
index = await resp.json();
|
|
16142
|
-
index.fetchedAt = Date.now();
|
|
16143
|
-
try {
|
|
16144
|
-
fs11.writeFileSync(cachePath, JSON.stringify(index, null, 2), "utf-8");
|
|
16145
|
-
} catch {
|
|
16146
|
-
}
|
|
16147
|
-
}
|
|
16148
|
-
} catch {
|
|
16149
|
-
}
|
|
16150
|
-
}
|
|
16151
|
-
if (!index || !index.skills) return { content: [{ type: "text", text: "\u65E0\u6CD5\u83B7\u53D6 skill \u6CE8\u518C\u8868\u7D22\u5F15" }], isError: true };
|
|
16152
|
-
const q = (a.query || "").toLowerCase();
|
|
16153
|
-
const results = index.skills.filter(
|
|
16154
|
-
(s) => s.name.toLowerCase().includes(q) || (s.description || "").toLowerCase().includes(q) || (s.tags || []).some((t) => t.toLowerCase().includes(q))
|
|
16155
|
-
);
|
|
16156
|
-
if (!results.length) return { content: [{ type: "text", text: `\u672A\u627E\u5230\u5339\u914D "${a.query}" \u7684 skill` }] };
|
|
16157
|
-
const lines = [`\u627E\u5230 ${results.length} \u4E2A skill:
|
|
16158
|
-
`];
|
|
16159
|
-
for (const s of results) {
|
|
16160
|
-
lines.push(`**${s.name}**`);
|
|
16161
|
-
if (s.description) lines.push(` \u63CF\u8FF0: ${s.description}`);
|
|
16162
|
-
if (s.tags?.length) lines.push(` \u6807\u7B7E: ${s.tags.join(", ")}`);
|
|
16163
|
-
if (s.version) lines.push(` \u7248\u672C: ${s.version}`);
|
|
16164
|
-
lines.push("");
|
|
16165
|
-
}
|
|
16166
|
-
return { content: [{ type: "text", text: lines.join("\n") }] };
|
|
16167
|
-
},
|
|
16168
|
-
skill_install: async (a) => {
|
|
16169
|
-
if (!a.name) return { content: [{ type: "text", text: "\u9700\u8981 skill \u540D\u79F0" }], isError: true };
|
|
16170
|
-
const registryUrl = process.env.SKILL_REGISTRY_URL || "https://raw.githubusercontent.com/atlisp/skill-registry/main/index.json";
|
|
16171
|
-
const cachePath = path15.join(os9.homedir(), ".atlisp", "skill-registry-cache.json");
|
|
16172
|
-
let cache = null;
|
|
16173
|
-
try {
|
|
16174
|
-
if (fs11.existsSync(cachePath)) cache = JSON.parse(fs11.readFileSync(cachePath, "utf-8"));
|
|
16175
|
-
} catch {
|
|
16176
|
-
}
|
|
16177
|
-
let index = cache;
|
|
16178
|
-
if (!index || Date.now() - index.fetchedAt > 36e5) {
|
|
16179
|
-
try {
|
|
16180
|
-
const resp = await fetch(registryUrl, { headers: { "User-Agent": "atlisp-mcp" } });
|
|
16181
|
-
if (resp.ok) {
|
|
16182
|
-
index = await resp.json();
|
|
16183
|
-
index.fetchedAt = Date.now();
|
|
16184
|
-
try {
|
|
16185
|
-
fs11.writeFileSync(cachePath, JSON.stringify(index, null, 2), "utf-8");
|
|
16186
|
-
} catch {
|
|
16187
|
-
}
|
|
16188
|
-
}
|
|
16189
|
-
} catch {
|
|
16190
|
-
}
|
|
16191
|
-
}
|
|
16192
|
-
if (!index || !index.skills) return { content: [{ type: "text", text: "\u65E0\u6CD5\u83B7\u53D6 skill \u6CE8\u518C\u8868\u7D22\u5F15" }], isError: true };
|
|
16193
|
-
const skill = index.skills.find((s) => s.name === a.name);
|
|
16194
|
-
if (!skill) return { content: [{ type: "text", text: `\u672A\u627E\u5230 skill: ${a.name}` }], isError: true };
|
|
16195
|
-
const downloadUrl = skill.download_url || skill.url;
|
|
16196
|
-
if (!downloadUrl) return { content: [{ type: "text", text: `Skill "${a.name}" \u6CA1\u6709\u4E0B\u8F7D\u5730\u5740` }], isError: true };
|
|
16197
|
-
let content;
|
|
16198
|
-
try {
|
|
16199
|
-
const resp = await fetch(downloadUrl, { headers: { "User-Agent": "atlisp-mcp" } });
|
|
16200
|
-
if (!resp.ok) throw new Error(`HTTP ${resp.status}`);
|
|
16201
|
-
content = await resp.text();
|
|
16202
|
-
} catch (e) {
|
|
16203
|
-
return { content: [{ type: "text", text: `\u4E0B\u8F7D\u5931\u8D25: ${e.message}` }], isError: true };
|
|
16204
|
-
}
|
|
16205
|
-
const skillsDir = path15.join(os9.homedir(), ".atlisp", "skills");
|
|
16206
|
-
try {
|
|
16207
|
-
fs11.mkdirSync(skillsDir, { recursive: true });
|
|
16208
|
-
} catch {
|
|
16209
|
-
}
|
|
16210
|
-
const safeName = a.name.replace(/[^a-zA-Z0-9\u4e00-\u9fff_-]/g, "-").substring(0, 40);
|
|
16211
|
-
const skillFile = path15.join(skillsDir, `skill-${safeName}.md`);
|
|
16212
|
-
if (fs11.existsSync(skillFile)) {
|
|
16213
|
-
return { content: [{ type: "text", text: `Skill "${a.name}" \u5DF2\u5B89\u88C5 (${skillFile})` }], isError: true };
|
|
16214
|
-
}
|
|
16215
|
-
let finalContent = content;
|
|
16216
|
-
if (!content.match(/^---\n/)) {
|
|
16217
|
-
const tags = (skill.tags || []).join(", ");
|
|
16218
|
-
finalContent = `---
|
|
16219
|
-
name: ${a.name}
|
|
16220
|
-
description: ${skill.description || ""}
|
|
16221
|
-
tags: ${tags}
|
|
16222
|
-
---
|
|
16223
|
-
|
|
16224
|
-
${content}`;
|
|
16225
|
-
}
|
|
16226
|
-
fs11.writeFileSync(skillFile, finalContent, "utf-8");
|
|
16227
|
-
return { content: [{ type: "text", text: `\u2705 ${skill.name} \u5B89\u88C5\u6210\u529F
|
|
16228
|
-
\u6587\u4EF6: ${skillFile}${skill.version ? `
|
|
16229
|
-
\u7248\u672C: ${skill.version}` : ""}` }] };
|
|
16230
|
-
},
|
|
16231
|
-
skill_list_installed: async () => {
|
|
16232
|
-
const skillsDir = path15.join(os9.homedir(), ".atlisp", "skills");
|
|
16233
|
-
if (!fs11.existsSync(skillsDir)) return { content: [{ type: "text", text: "\u6682\u65E0\u5DF2\u5B89\u88C5\u7684 skill" }] };
|
|
16234
|
-
const results = [];
|
|
16235
|
-
try {
|
|
16236
|
-
const entries = fs11.readdirSync(skillsDir, { withFileTypes: true });
|
|
16237
|
-
for (const entry of entries) {
|
|
16238
|
-
if (entry.isFile() && entry.name.endsWith(".md")) {
|
|
16239
|
-
const fullPath = path15.join(skillsDir, entry.name);
|
|
16240
|
-
try {
|
|
16241
|
-
const raw = fs11.readFileSync(fullPath, "utf-8");
|
|
16242
|
-
const match = raw.match(/^---\n([\s\S]*?)\n---/);
|
|
16243
|
-
if (match) {
|
|
16244
|
-
const fm = {};
|
|
16245
|
-
for (const line of match[1].split("\n")) {
|
|
16246
|
-
const sep = line.indexOf(":");
|
|
16247
|
-
if (sep > 0) fm[line.slice(0, sep).trim()] = line.slice(sep + 1).trim();
|
|
16248
|
-
}
|
|
16249
|
-
results.push({ name: fm.name || entry.name.replace(".md", ""), description: fm.description || "", tags: fm.tags || "" });
|
|
16250
|
-
} else {
|
|
16251
|
-
results.push({ name: entry.name.replace(".md", ""), description: "", tags: "" });
|
|
16252
|
-
}
|
|
16253
|
-
} catch {
|
|
16254
|
-
}
|
|
16255
|
-
}
|
|
16256
|
-
}
|
|
16257
|
-
} catch {
|
|
16258
|
-
}
|
|
16259
|
-
if (!results.length) return { content: [{ type: "text", text: "\u6682\u65E0\u5DF2\u5B89\u88C5\u7684 skill" }] };
|
|
16260
|
-
const lines = [`\u5DF2\u5B89\u88C5 ${results.length} \u4E2A skill:
|
|
16261
|
-
`];
|
|
16262
|
-
for (const s of results) {
|
|
16263
|
-
lines.push(`**${s.name}**${s.description ? ` \u2014 ${s.description}` : ""}`);
|
|
16264
|
-
if (s.tags) lines.push(` \u6807\u7B7E: ${s.tags}`);
|
|
16265
|
-
}
|
|
16266
|
-
return { content: [{ type: "text", text: lines.join("\n") }] };
|
|
16267
|
-
},
|
|
16268
|
-
skill_uninstall: async (a) => {
|
|
16269
|
-
if (!a.name) return { content: [{ type: "text", text: "\u9700\u8981 skill \u540D\u79F0" }], isError: true };
|
|
16270
|
-
const skillsDir = path15.join(os9.homedir(), ".atlisp", "skills");
|
|
16271
|
-
if (!fs11.existsSync(skillsDir)) return { content: [{ type: "text", text: `\u672A\u5B89\u88C5 skill: ${a.name}` }], isError: true };
|
|
16272
|
-
let found = null;
|
|
16273
|
-
try {
|
|
16274
|
-
const entries = fs11.readdirSync(skillsDir, { withFileTypes: true });
|
|
16275
|
-
for (const entry of entries) {
|
|
16276
|
-
if (entry.isFile() && entry.name.endsWith(".md")) {
|
|
16277
|
-
const fullPath = path15.join(skillsDir, entry.name);
|
|
16278
|
-
try {
|
|
16279
|
-
const raw = fs11.readFileSync(fullPath, "utf-8");
|
|
16280
|
-
const match = raw.match(/^---\n([\s\S]*?)\n---/);
|
|
16281
|
-
if (match) {
|
|
16282
|
-
for (const line of match[1].split("\n")) {
|
|
16283
|
-
if (line.startsWith("name:") && line.slice(5).trim() === a.name) {
|
|
16284
|
-
found = fullPath;
|
|
16285
|
-
break;
|
|
16286
|
-
}
|
|
16287
|
-
}
|
|
16288
|
-
} else if (entry.name.replace(".md", "") === a.name) {
|
|
16289
|
-
found = fullPath;
|
|
16290
|
-
}
|
|
16291
|
-
} catch {
|
|
16292
|
-
}
|
|
16293
|
-
if (found) break;
|
|
16294
|
-
}
|
|
16295
|
-
}
|
|
16296
|
-
} catch {
|
|
16297
|
-
}
|
|
16298
|
-
if (!found) return { content: [{ type: "text", text: `\u672A\u5B89\u88C5 skill: ${a.name}` }], isError: true };
|
|
16299
|
-
fs11.unlinkSync(found);
|
|
16300
|
-
return { content: [{ type: "text", text: `\u2705 ${a.name} \u5DF2\u5378\u8F7D` }] };
|
|
16301
|
-
},
|
|
16302
|
-
skill_list_categories: async () => {
|
|
16303
|
-
const registryUrl = process.env.SKILL_REGISTRY_URL || "https://raw.githubusercontent.com/atlisp/skill-registry/main/index.json";
|
|
16304
|
-
const cachePath = path15.join(os9.homedir(), ".atlisp", "skill-registry-cache.json");
|
|
16305
|
-
let cache = null;
|
|
16306
|
-
try {
|
|
16307
|
-
if (fs11.existsSync(cachePath)) cache = JSON.parse(fs11.readFileSync(cachePath, "utf-8"));
|
|
16308
|
-
} catch {
|
|
16309
|
-
}
|
|
16310
|
-
let index = cache && Date.now() - cache.fetchedAt < 36e5 ? cache : null;
|
|
16311
|
-
if (!index) {
|
|
16312
|
-
try {
|
|
16313
|
-
const resp = await fetch(registryUrl, { headers: { "User-Agent": "atlisp-mcp" } });
|
|
16314
|
-
if (resp.ok) {
|
|
16315
|
-
index = await resp.json();
|
|
16316
|
-
try {
|
|
16317
|
-
fs11.writeFileSync(cachePath, JSON.stringify(index, null, 2), "utf-8");
|
|
16318
|
-
} catch {
|
|
16319
|
-
}
|
|
16320
|
-
}
|
|
16321
|
-
} catch {
|
|
16322
|
-
}
|
|
16323
|
-
}
|
|
16324
|
-
if (!index || !index.skills) return { content: [{ type: "text", text: "\u65E0\u6CD5\u83B7\u53D6 skill \u6CE8\u518C\u8868\u7D22\u5F15" }], isError: true };
|
|
16325
|
-
const cats = /* @__PURE__ */ new Set();
|
|
16326
|
-
for (const s of index.skills) for (const t of s.tags || []) cats.add(t);
|
|
16327
|
-
const sorted = Array.from(cats).sort();
|
|
16328
|
-
return { content: [{ type: "text", text: sorted.length ? `\u6CE8\u518C\u8868\u5206\u7C7B (${sorted.length}):
|
|
16329
|
-
${sorted.join("\n")}` : "\u6682\u65E0\u5206\u7C7B" }] };
|
|
16330
|
-
}
|
|
17101
|
+
skill_search,
|
|
17102
|
+
skill_install,
|
|
17103
|
+
skill_list_installed,
|
|
17104
|
+
skill_uninstall,
|
|
17105
|
+
skill_list_categories
|
|
16331
17106
|
};
|
|
16332
17107
|
}
|
|
16333
17108
|
});
|
|
@@ -16418,7 +17193,7 @@ var init_mcp_server_state = __esm({
|
|
|
16418
17193
|
progressContext = new AsyncLocalStorage();
|
|
16419
17194
|
sessionServers = /* @__PURE__ */ new Map();
|
|
16420
17195
|
sessionTransports = /* @__PURE__ */ new Map();
|
|
16421
|
-
mcpHandlers = { tools:
|
|
17196
|
+
mcpHandlers = { tools: tools43, handleToolCall };
|
|
16422
17197
|
_stdioServer = null;
|
|
16423
17198
|
_pendingResourceUpdated = /* @__PURE__ */ new Set();
|
|
16424
17199
|
_resourceUpdatedTimer = null;
|
|
@@ -16442,11 +17217,12 @@ function mcpError(text) {
|
|
|
16442
17217
|
return { content: [{ type: "text", text: String(text) }], isError: true };
|
|
16443
17218
|
}
|
|
16444
17219
|
async function ensureCadConnected() {
|
|
16445
|
-
const { cad: cad2 } = await Promise.resolve().then(() => (init_cad(), cad_exports));
|
|
16446
|
-
|
|
16447
|
-
|
|
17220
|
+
const { cad: cad2, resolveCadConnection: resolveCadConnection2 } = await Promise.resolve().then(() => (init_cad(), cad_exports));
|
|
17221
|
+
const conn = resolveCadConnection2();
|
|
17222
|
+
if (!conn.connected) {
|
|
17223
|
+
await conn.connect();
|
|
16448
17224
|
}
|
|
16449
|
-
if (!
|
|
17225
|
+
if (!conn.connected) {
|
|
16450
17226
|
throw createError(ERROR_CODES.CAD_NOT_CONNECTED);
|
|
16451
17227
|
}
|
|
16452
17228
|
}
|
|
@@ -16631,7 +17407,7 @@ __export(resource_handlers_exports, {
|
|
|
16631
17407
|
readResource: () => readResource
|
|
16632
17408
|
});
|
|
16633
17409
|
import fs13 from "fs";
|
|
16634
|
-
import
|
|
17410
|
+
import path17 from "path";
|
|
16635
17411
|
function propertyPairsToObject(pairs) {
|
|
16636
17412
|
if (!Array.isArray(pairs)) return null;
|
|
16637
17413
|
const obj = {};
|
|
@@ -16642,7 +17418,7 @@ function propertyPairsToObject(pairs) {
|
|
|
16642
17418
|
}
|
|
16643
17419
|
return obj;
|
|
16644
17420
|
}
|
|
16645
|
-
async function
|
|
17421
|
+
async function ensureCad2() {
|
|
16646
17422
|
if (!cad.connected) await cad.connect();
|
|
16647
17423
|
if (!cad.connected) throw createError(ERROR_CODES.CAD_NOT_CONNECTED);
|
|
16648
17424
|
}
|
|
@@ -16810,7 +17586,7 @@ function parseTableRecord(rec, tableName) {
|
|
|
16810
17586
|
return obj.name ? obj : null;
|
|
16811
17587
|
}
|
|
16812
17588
|
async function getEntityByHandle(handle) {
|
|
16813
|
-
await
|
|
17589
|
+
await ensureCad2();
|
|
16814
17590
|
const code = `(progn
|
|
16815
17591
|
(vl-load-com)
|
|
16816
17592
|
(if (setq ent (handent "${escapeLispString(handle)}"))
|
|
@@ -16920,7 +17696,7 @@ async function getEntities(params = {}) {
|
|
|
16920
17696
|
const cacheKey = `dwg:entities:${JSON.stringify(params)}`;
|
|
16921
17697
|
const cached = getCached(cacheKey);
|
|
16922
17698
|
if (cached) return cached;
|
|
16923
|
-
await
|
|
17699
|
+
await ensureCad2();
|
|
16924
17700
|
const hasFilter = params.type || params.layer || params.bbox;
|
|
16925
17701
|
if (!hasFilter) {
|
|
16926
17702
|
return await getEntitiesSummary(cacheKey);
|
|
@@ -16956,7 +17732,7 @@ async function getTextContent(params = {}) {
|
|
|
16956
17732
|
const cacheKey = `dwg:text-content:${JSON.stringify(params)}`;
|
|
16957
17733
|
const cached = getCached(cacheKey);
|
|
16958
17734
|
if (cached) return cached;
|
|
16959
|
-
await
|
|
17735
|
+
await ensureCad2();
|
|
16960
17736
|
const offset = Math.max(0, parseInt(params.offset) || 0);
|
|
16961
17737
|
const limit = Math.min(Math.max(1, parseInt(params.limit) || 5e3), 5e3);
|
|
16962
17738
|
try {
|
|
@@ -17106,7 +17882,7 @@ async function combineText(params = {}) {
|
|
|
17106
17882
|
return { total: blocks.length, blocks, medianHeight: mh };
|
|
17107
17883
|
}
|
|
17108
17884
|
async function getDwgName() {
|
|
17109
|
-
await
|
|
17885
|
+
await ensureCad2();
|
|
17110
17886
|
try {
|
|
17111
17887
|
const code = `(vl-princ-to-string (getvar "dwgname"))`;
|
|
17112
17888
|
const name = await cad.sendCommandWithResult(code);
|
|
@@ -17116,7 +17892,7 @@ async function getDwgName() {
|
|
|
17116
17892
|
}
|
|
17117
17893
|
}
|
|
17118
17894
|
async function getDwgPath() {
|
|
17119
|
-
await
|
|
17895
|
+
await ensureCad2();
|
|
17120
17896
|
try {
|
|
17121
17897
|
const code = `(progn
|
|
17122
17898
|
(setq prefix (vl-princ-to-string (getvar "dwgprefix")))
|
|
@@ -17149,7 +17925,7 @@ async function getBlockRefs(params = {}) {
|
|
|
17149
17925
|
const cacheKey = `dwg:block-refs:${params.blockName || "all"}`;
|
|
17150
17926
|
const cached = getCached(cacheKey);
|
|
17151
17927
|
if (cached) return cached;
|
|
17152
|
-
await
|
|
17928
|
+
await ensureCad2();
|
|
17153
17929
|
try {
|
|
17154
17930
|
const code = buildBlockRefsCode(params.blockName);
|
|
17155
17931
|
const resultStr = await cad.sendCommandWithResult(code);
|
|
@@ -17211,7 +17987,7 @@ async function getTables(params = {}) {
|
|
|
17211
17987
|
const cacheKey = `dwg:tbl:${tblName}`;
|
|
17212
17988
|
const cached = getCached(cacheKey);
|
|
17213
17989
|
if (cached) return cached;
|
|
17214
|
-
await
|
|
17990
|
+
await ensureCad2();
|
|
17215
17991
|
try {
|
|
17216
17992
|
const code = buildTablesCode(tblName);
|
|
17217
17993
|
const resultStr = await cad.sendCommandWithResult(code);
|
|
@@ -17293,7 +18069,7 @@ async function getPackages(filterName = null) {
|
|
|
17293
18069
|
const cacheKey = filterName ? `packages:${filterName}` : "packages:all";
|
|
17294
18070
|
const cached = getCached(cacheKey);
|
|
17295
18071
|
if (cached) return cached;
|
|
17296
|
-
await
|
|
18072
|
+
await ensureCad2();
|
|
17297
18073
|
try {
|
|
17298
18074
|
const code = `(mapcar 'cdr @::*local-pkgs*)`;
|
|
17299
18075
|
const result = await cad.sendCommandWithResult(code);
|
|
@@ -17366,7 +18142,7 @@ async function getDwgList() {
|
|
|
17366
18142
|
const cacheKey = "cad:dwgs";
|
|
17367
18143
|
const cached = getCached(cacheKey);
|
|
17368
18144
|
if (cached) return cached;
|
|
17369
|
-
await
|
|
18145
|
+
await ensureCad2();
|
|
17370
18146
|
try {
|
|
17371
18147
|
const code = `(progn
|
|
17372
18148
|
(vl-load-com)
|
|
@@ -17403,7 +18179,7 @@ async function getDwgList() {
|
|
|
17403
18179
|
}
|
|
17404
18180
|
}
|
|
17405
18181
|
function loadStandardsFile(filename) {
|
|
17406
|
-
const filePath =
|
|
18182
|
+
const filePath = path17.join(STANDARDS_DIR, filename);
|
|
17407
18183
|
try {
|
|
17408
18184
|
const raw = fs13.readFileSync(filePath, "utf-8");
|
|
17409
18185
|
return JSON.parse(raw);
|
|
@@ -17436,7 +18212,7 @@ function getCodingStandards() {
|
|
|
17436
18212
|
return data || { error: "\u7F16\u7801\u89C4\u8303\u6587\u4EF6\u52A0\u8F7D\u5931\u8D25" };
|
|
17437
18213
|
}
|
|
17438
18214
|
async function getCadEvents(params) {
|
|
17439
|
-
await
|
|
18215
|
+
await ensureCad2();
|
|
17440
18216
|
try {
|
|
17441
18217
|
const code = `(progn (setq cnt 0) (if (setq ss (ssget "_X")) (setq cnt (sslength ss))) (list (cons "entityCount" cnt) (cons "dwgName" (getvar "dwgname")) (cons "dwgPath" (getvar "dwgprefix"))))`;
|
|
17442
18218
|
const result = await cad.sendCommandWithResult(code);
|
|
@@ -17503,6 +18279,119 @@ async function getDwgContext() {
|
|
|
17503
18279
|
};
|
|
17504
18280
|
}
|
|
17505
18281
|
}
|
|
18282
|
+
async function getDrawingAnalysis(params = {}) {
|
|
18283
|
+
const snapshot = await getCadSnapshot();
|
|
18284
|
+
if (!snapshot || !snapshot.cadConnected) {
|
|
18285
|
+
return { connected: false, error: "CAD \u672A\u8FDE\u63A5" };
|
|
18286
|
+
}
|
|
18287
|
+
try {
|
|
18288
|
+
const detailedCode = `(progn
|
|
18289
|
+
(vl-load-com)
|
|
18290
|
+
(setq r nil)
|
|
18291
|
+
;; entity counts by type
|
|
18292
|
+
(if (setq ss (ssget "_X"))
|
|
18293
|
+
(progn
|
|
18294
|
+
(setq total (sslength ss) i 0 cnt nil)
|
|
18295
|
+
(while (< i total)
|
|
18296
|
+
(setq typ (cdr (assoc 0 (entget (ssname ss i)))))
|
|
18297
|
+
(setq cnt (if (assoc typ cnt) (subst (cons typ (1+ (cdr (assoc typ cnt)))) (assoc typ cnt) cnt) (cons (cons typ 1) cnt)))
|
|
18298
|
+
(setq i (1+ i)))
|
|
18299
|
+
(setq r (cons (cons "entityCount" total) r))
|
|
18300
|
+
(setq r (cons (cons "entityByType" cnt) r)))
|
|
18301
|
+
(setq r (cons (cons "entityCount" 0) r)))
|
|
18302
|
+
;; block usage
|
|
18303
|
+
(setq blocks nil)
|
|
18304
|
+
(vlax-for b (vla-get-blocks (vla-get-activedocument (vlax-get-acad-object)))
|
|
18305
|
+
(if (and (= (vla-get-IsXref b) :vlax-false) (/= (vla-get-Name b) "*Model_Space") (/= (vla-get-Name b) "*Paper_Space"))
|
|
18306
|
+
(setq blocks (cons (list "name" (vla-get-Name b) "count" (vla-get-Count b) "isDynamic" (vla-get-IsDynamicBlock b)) blocks))))
|
|
18307
|
+
(setq r (cons (cons "blockUsage" blocks) r))
|
|
18308
|
+
;; layer summary
|
|
18309
|
+
(setq layers nil le (tblnext "layer" t))
|
|
18310
|
+
(while le
|
|
18311
|
+
(setq ln (cdr (assoc 2 le)) lc (cdr (assoc 62 le)) ll (cdr (assoc 6 le)))
|
|
18312
|
+
(setq layers (cons (list "name" ln "color" (if (< lc 0) (- lc) lc) "off" (< lc 0) "linetype" ll) layers))
|
|
18313
|
+
(setq le (tblnext "layer" nil)))
|
|
18314
|
+
(setq r (cons (cons "layers" layers) r))
|
|
18315
|
+
;; text stats
|
|
18316
|
+
(if (setq ts (ssget "_X" '((0 . "TEXT,MTEXT"))))
|
|
18317
|
+
(progn
|
|
18318
|
+
(setq tc (sslength ts) th nil ti 0)
|
|
18319
|
+
(while (< ti tc)
|
|
18320
|
+
(setq h (cdr (assoc 40 (entget (ssname ts ti)))))
|
|
18321
|
+
(if h (setq th (cons h th)))
|
|
18322
|
+
(setq ti (1+ ti)))
|
|
18323
|
+
(setq th (vl-sort th '<))
|
|
18324
|
+
(setq r (cons (cons "textCount" tc) r))
|
|
18325
|
+
(setq r (cons (cons "textHeights" (list "min" (car th) "max" (last th) "median" (nth (fix (/ (length th) 2)) th))) r)))
|
|
18326
|
+
(setq r (cons (cons "textCount" 0) r)))
|
|
18327
|
+
;; system variables
|
|
18328
|
+
(setq r (cons (cons "sysvars" (list
|
|
18329
|
+
(cons "ltscale" (getvar "ltscale"))
|
|
18330
|
+
(cons "dimscale" (getvar "dimscale"))
|
|
18331
|
+
(cons "insunits" (getvar "insunits"))
|
|
18332
|
+
(cons "measurement" (getvar "measurement"))
|
|
18333
|
+
(cons "celtype" (getvar "celtype"))
|
|
18334
|
+
(cons "clayer" (getvar "clayer"))
|
|
18335
|
+
(cons "cecolor" (getvar "cecolor"))
|
|
18336
|
+
(cons "osmode" (getvar "osmode"))
|
|
18337
|
+
(cons "snapmode" (getvar "snapmode"))
|
|
18338
|
+
(cons "gridmode" (getvar "gridmode"))
|
|
18339
|
+
(cons "orthomode" (getvar "orthomode"))
|
|
18340
|
+
(cons "plinetype" (getvar "plinetype"))
|
|
18341
|
+
(cons "fillmode" (getvar "fillmode"))
|
|
18342
|
+
(cons "pickstyle" (getvar "pickstyle"))
|
|
18343
|
+
)) r))
|
|
18344
|
+
(vl-prin1-to-string (reverse r)))`;
|
|
18345
|
+
const resultStr = await cad.sendCommandWithResult(detailedCode);
|
|
18346
|
+
const parsed = parseLispRecursive(resultStr);
|
|
18347
|
+
if (!parsed || !Array.isArray(parsed)) {
|
|
18348
|
+
return { connected: true, error: "\u5206\u6790\u7ED3\u679C\u89E3\u6790\u5931\u8D25" };
|
|
18349
|
+
}
|
|
18350
|
+
const analysis = {};
|
|
18351
|
+
for (const pair of parsed) {
|
|
18352
|
+
if (Array.isArray(pair) && pair.length >= 2) {
|
|
18353
|
+
analysis[String(pair[0])] = pair[1];
|
|
18354
|
+
}
|
|
18355
|
+
}
|
|
18356
|
+
return { connected: true, ...analysis };
|
|
18357
|
+
} catch (e) {
|
|
18358
|
+
log(`getDrawingAnalysis error: ${e.message}`);
|
|
18359
|
+
return { connected: true, error: e.message };
|
|
18360
|
+
}
|
|
18361
|
+
}
|
|
18362
|
+
function getToolCategories() {
|
|
18363
|
+
const cats = {};
|
|
18364
|
+
for (const t of tools43) {
|
|
18365
|
+
const cat = t.annotations?.category || "\u5176\u4ED6";
|
|
18366
|
+
if (!cats[cat]) cats[cat] = { count: 0, tools: [] };
|
|
18367
|
+
cats[cat].count++;
|
|
18368
|
+
cats[cat].tools.push(t.name);
|
|
18369
|
+
}
|
|
18370
|
+
return Object.entries(cats).map(([category, info]) => ({
|
|
18371
|
+
category,
|
|
18372
|
+
count: info.count,
|
|
18373
|
+
tools: info.tools
|
|
18374
|
+
})).sort((a, b) => b.count - a.count);
|
|
18375
|
+
}
|
|
18376
|
+
async function checkDrawingStandards() {
|
|
18377
|
+
const standards = getDraftingStandards();
|
|
18378
|
+
if (!standards || standards.error) {
|
|
18379
|
+
return { ok: false, error: standards?.error || "\u5236\u56FE\u89C4\u8303\u672A\u52A0\u8F7D" };
|
|
18380
|
+
}
|
|
18381
|
+
try {
|
|
18382
|
+
const issues = [];
|
|
18383
|
+
for (const rule of standards.layers || []) {
|
|
18384
|
+
const code = `(tblsearch "LAYER" "${escapeLispString(rule.name || rule.pattern)}")`;
|
|
18385
|
+
const exists = await cad.sendCommandWithResult(code);
|
|
18386
|
+
if (rule.required && (!exists || exists === "nil" || exists === "")) {
|
|
18387
|
+
issues.push({ type: "missing_layer", message: `\u7F3A\u5C11\u5FC5\u9700\u56FE\u5C42: ${rule.name}` });
|
|
18388
|
+
}
|
|
18389
|
+
}
|
|
18390
|
+
return { ok: issues.length === 0, issues };
|
|
18391
|
+
} catch (e) {
|
|
18392
|
+
return { ok: false, error: e.message };
|
|
18393
|
+
}
|
|
18394
|
+
}
|
|
17506
18395
|
function getToolRelationships() {
|
|
17507
18396
|
return {
|
|
17508
18397
|
selection: {
|
|
@@ -17758,6 +18647,12 @@ async function readResource(uri) {
|
|
|
17758
18647
|
return await getDwgContext();
|
|
17759
18648
|
case "atlisp://tools/relationships":
|
|
17760
18649
|
return getToolRelationships();
|
|
18650
|
+
case "atlisp://dwg/analysis":
|
|
18651
|
+
return await getDrawingAnalysis(params);
|
|
18652
|
+
case "atlisp://tools/categories":
|
|
18653
|
+
return getToolCategories();
|
|
18654
|
+
case "atlisp://dwg/standards/check":
|
|
18655
|
+
return await checkDrawingStandards();
|
|
17761
18656
|
default:
|
|
17762
18657
|
throw new Error(`\u8D44\u6E90\u4E0D\u5B58\u5728: ${uri}`);
|
|
17763
18658
|
}
|
|
@@ -17773,6 +18668,7 @@ var init_resource_handlers = __esm({
|
|
|
17773
18668
|
init_handler_utils();
|
|
17774
18669
|
init_errors();
|
|
17775
18670
|
init_config();
|
|
18671
|
+
init_tools();
|
|
17776
18672
|
ENTITY_PROPERTIES_LISP = `
|
|
17777
18673
|
(defun entity:to-list (val)
|
|
17778
18674
|
(cond
|
|
@@ -17852,11 +18748,11 @@ init_subscription_manager();
|
|
|
17852
18748
|
init_subscription_manager();
|
|
17853
18749
|
init_sse_session();
|
|
17854
18750
|
init_config();
|
|
17855
|
-
import
|
|
18751
|
+
import path20 from "path";
|
|
17856
18752
|
import fs16 from "fs";
|
|
17857
18753
|
import http from "http";
|
|
17858
18754
|
import https from "https";
|
|
17859
|
-
import { fileURLToPath as
|
|
18755
|
+
import { fileURLToPath as fileURLToPath8 } from "url";
|
|
17860
18756
|
import { createRequire as createRequire2 } from "module";
|
|
17861
18757
|
import express2 from "express";
|
|
17862
18758
|
import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
|
|
@@ -17869,11 +18765,12 @@ init_cad_pool();
|
|
|
17869
18765
|
init_subscription_manager();
|
|
17870
18766
|
init_mcp_server_state();
|
|
17871
18767
|
init_sse_session();
|
|
18768
|
+
import os10 from "os";
|
|
17872
18769
|
import express from "express";
|
|
17873
|
-
import { randomUUID as
|
|
18770
|
+
import { randomUUID as randomUUID6, createHash } from "crypto";
|
|
17874
18771
|
import fs14 from "fs";
|
|
17875
|
-
import
|
|
17876
|
-
import { fileURLToPath as
|
|
18772
|
+
import path18 from "path";
|
|
18773
|
+
import { fileURLToPath as fileURLToPath7 } from "url";
|
|
17877
18774
|
import iconv from "iconv-lite";
|
|
17878
18775
|
import { StreamableHTTPServerTransport } from "@modelcontextprotocol/sdk/server/streamableHttp.js";
|
|
17879
18776
|
|
|
@@ -17986,7 +18883,6 @@ var TOOL_PERMISSIONS = {
|
|
|
17986
18883
|
"measure_*": "read",
|
|
17987
18884
|
"stream_*": "read",
|
|
17988
18885
|
"watch_list": "read",
|
|
17989
|
-
"pipeline_list": "read",
|
|
17990
18886
|
// Write tools
|
|
17991
18887
|
"create_*": "write",
|
|
17992
18888
|
"set_*": "write",
|
|
@@ -18006,8 +18902,6 @@ var TOOL_PERMISSIONS = {
|
|
|
18006
18902
|
"import_*": "import",
|
|
18007
18903
|
// Admin
|
|
18008
18904
|
"config_*": "admin",
|
|
18009
|
-
"pipeline_save": "admin",
|
|
18010
|
-
"pipeline_delete": "admin",
|
|
18011
18905
|
"webhook_*": "admin",
|
|
18012
18906
|
"watch_remove": "admin"
|
|
18013
18907
|
};
|
|
@@ -18041,11 +18935,11 @@ function getApiKeyRole(apiKey2, config2) {
|
|
|
18041
18935
|
|
|
18042
18936
|
// src/routes.js
|
|
18043
18937
|
init_constants();
|
|
18044
|
-
var __dirname6 =
|
|
18045
|
-
var htmlDir =
|
|
18938
|
+
var __dirname6 = path18.dirname(fileURLToPath7(import.meta.url));
|
|
18939
|
+
var htmlDir = path18.join(__dirname6, "html");
|
|
18046
18940
|
function loadHtml(name, replacements = {}) {
|
|
18047
18941
|
if (!htmlCache[name]) {
|
|
18048
|
-
htmlCache[name] = fs14.readFileSync(
|
|
18942
|
+
htmlCache[name] = fs14.readFileSync(path18.join(htmlDir, `${name}.html`), "utf-8");
|
|
18049
18943
|
}
|
|
18050
18944
|
let html = htmlCache[name];
|
|
18051
18945
|
for (const [key, value] of Object.entries(replacements)) {
|
|
@@ -18058,7 +18952,7 @@ var cachedToolsJson = null;
|
|
|
18058
18952
|
var cachedToolsJsonAt = 0;
|
|
18059
18953
|
function getToolsJson() {
|
|
18060
18954
|
if (cachedToolsJson && Date.now() - cachedToolsJsonAt < 3e4) return cachedToolsJson;
|
|
18061
|
-
cachedToolsJson = JSON.stringify(
|
|
18955
|
+
cachedToolsJson = JSON.stringify(tools43.map((t) => ({
|
|
18062
18956
|
name: t.name,
|
|
18063
18957
|
description: t.description,
|
|
18064
18958
|
inputSchema: t.inputSchema
|
|
@@ -18128,15 +19022,45 @@ function createAuthMiddleware() {
|
|
|
18128
19022
|
return res.status(401).json({ error: "Unauthorized" });
|
|
18129
19023
|
};
|
|
18130
19024
|
}
|
|
19025
|
+
function originMatches(pattern, origin) {
|
|
19026
|
+
if (pattern === "*") return true;
|
|
19027
|
+
if (!origin) return false;
|
|
19028
|
+
const getHost = (s) => s.replace(/^https?:\/\//, "").replace(/:\d+$/, "").toLowerCase();
|
|
19029
|
+
const oHost = getHost(origin);
|
|
19030
|
+
let pHost = getHost(pattern);
|
|
19031
|
+
if (pHost.startsWith("*.")) {
|
|
19032
|
+
const suffix = pHost.slice(1);
|
|
19033
|
+
return oHost === suffix.slice(1) || oHost.endsWith(suffix);
|
|
19034
|
+
}
|
|
19035
|
+
return oHost === pHost;
|
|
19036
|
+
}
|
|
18131
19037
|
function createCorsMiddleware() {
|
|
19038
|
+
const allowedOrigins = corsOrigin.split(",").map((s) => s.trim()).filter(Boolean);
|
|
19039
|
+
const allowAll = allowedOrigins.includes("*");
|
|
18132
19040
|
return (req, res, next) => {
|
|
18133
19041
|
if (!enableCors) return next();
|
|
18134
|
-
|
|
19042
|
+
const origin = req.headers.origin;
|
|
19043
|
+
const isPnaPreflight = req.method === "OPTIONS" && req.headers["access-control-request-private-network"] === "true";
|
|
19044
|
+
if (allowAll) {
|
|
19045
|
+
if (isPnaPreflight && origin) {
|
|
19046
|
+
res.setHeader("Access-Control-Allow-Origin", origin);
|
|
19047
|
+
res.setHeader("Vary", "Origin");
|
|
19048
|
+
} else {
|
|
19049
|
+
res.setHeader("Access-Control-Allow-Origin", corsOrigin);
|
|
19050
|
+
}
|
|
19051
|
+
} else if (origin && allowedOrigins.some((p) => originMatches(p, origin))) {
|
|
19052
|
+
res.setHeader("Access-Control-Allow-Origin", origin);
|
|
19053
|
+
res.setHeader("Vary", "Origin");
|
|
19054
|
+
} else if (!origin) {
|
|
19055
|
+
res.setHeader("Access-Control-Allow-Origin", allowedOrigins[0] || "*");
|
|
19056
|
+
} else {
|
|
19057
|
+
return res.status(403).json({ error: "Origin not allowed" });
|
|
19058
|
+
}
|
|
18135
19059
|
res.setHeader("Access-Control-Allow-Methods", "GET, POST, OPTIONS, CONNECT");
|
|
18136
19060
|
res.setHeader("Access-Control-Allow-Headers", "Content-Type, Authorization, Accept, mcp-session-id, last-event-id");
|
|
18137
19061
|
res.setHeader("Access-Control-Expose-Headers", "mcp-session-id, content-type, x-accel-buffering");
|
|
18138
19062
|
res.setHeader("Access-Control-Max-Age", "86400");
|
|
18139
|
-
res.setHeader("
|
|
19063
|
+
res.setHeader("Access-Control-Allow-Private-Network", "true");
|
|
18140
19064
|
if (req.method === "OPTIONS") return res.status(204).end();
|
|
18141
19065
|
next();
|
|
18142
19066
|
};
|
|
@@ -18227,7 +19151,7 @@ function setupRoutes(app) {
|
|
|
18227
19151
|
},
|
|
18228
19152
|
mcp: {
|
|
18229
19153
|
sessions: sessionServers.size,
|
|
18230
|
-
tools:
|
|
19154
|
+
tools: tools43.length,
|
|
18231
19155
|
sseSessions: sseCount
|
|
18232
19156
|
},
|
|
18233
19157
|
pool: {
|
|
@@ -18237,6 +19161,11 @@ function setupRoutes(app) {
|
|
|
18237
19161
|
}
|
|
18238
19162
|
});
|
|
18239
19163
|
});
|
|
19164
|
+
app.get("/go", (req, res) => {
|
|
19165
|
+
const remoteUrl = "https://atlisp.cn/agent";
|
|
19166
|
+
const cid = config_default.clientId || os10.hostname();
|
|
19167
|
+
res.redirect(302, `${remoteUrl}?clientId=${encodeURIComponent(cid)}`);
|
|
19168
|
+
});
|
|
18240
19169
|
app.get("/health/full", async (req, res) => {
|
|
18241
19170
|
const memUsage = process.memoryUsage();
|
|
18242
19171
|
const poolStats = pool ? pool.getStats() : {};
|
|
@@ -18250,7 +19179,7 @@ function setupRoutes(app) {
|
|
|
18250
19179
|
timestamp: (/* @__PURE__ */ new Date()).toISOString(),
|
|
18251
19180
|
cad: { connected: cad.connected, platform: cad.getPlatform?.(), version: cad.getVersion?.(), commandQueueSize: cad._getQueueSize ? cad._getQueueSize() : 0, restartCount: cad._getRestartCount ? cad._getRestartCount() : 0 },
|
|
18252
19181
|
system: { uptime: process.uptime(), memory: { rssMB: Math.round(memUsage.rss / 1024 / 1024), heapUsedMB: Math.round(memUsage.heapUsed / 1024 / 1024), heapTotalMB: Math.round(memUsage.heapTotal / 1024 / 1024) }, cpu: process.cpuUsage() },
|
|
18253
|
-
mcp: { sessions: sessionServers.size, tools:
|
|
19182
|
+
mcp: { sessions: sessionServers.size, tools: tools43.length, sseSessions: sseCount },
|
|
18254
19183
|
pool: poolStats
|
|
18255
19184
|
});
|
|
18256
19185
|
});
|
|
@@ -18288,7 +19217,7 @@ function setupRoutes(app) {
|
|
|
18288
19217
|
app.get("/api/docs", (req, res) => {
|
|
18289
19218
|
const html = loadHtml("api-docs", {
|
|
18290
19219
|
VERSION: SERVER_VERSION,
|
|
18291
|
-
TOOLS_COUNT:
|
|
19220
|
+
TOOLS_COUNT: tools43.length
|
|
18292
19221
|
});
|
|
18293
19222
|
res.setHeader("Content-Type", "text/html; charset=utf-8");
|
|
18294
19223
|
res.send(html);
|
|
@@ -18309,7 +19238,7 @@ function setupRoutes(app) {
|
|
|
18309
19238
|
SESSIONS_COUNT: sessionServers.size,
|
|
18310
19239
|
CAD_STATUS_CLASS: cadConnected ? "status-ok" : "status-error",
|
|
18311
19240
|
CAD_STATUS_TEXT: cadStatusText,
|
|
18312
|
-
TOOLS_COUNT:
|
|
19241
|
+
TOOLS_COUNT: tools43.length
|
|
18313
19242
|
});
|
|
18314
19243
|
res.setHeader("Content-Type", "text/html; charset=utf-8");
|
|
18315
19244
|
res.send(html);
|
|
@@ -18327,7 +19256,7 @@ function setupRoutes(app) {
|
|
|
18327
19256
|
app.get("/sse", mcpLimiter, handleSse);
|
|
18328
19257
|
app.post("/message", mcpLimiter, handleMessage);
|
|
18329
19258
|
app.get("/cad/events", (req, res) => {
|
|
18330
|
-
const sessionId =
|
|
19259
|
+
const sessionId = randomUUID6();
|
|
18331
19260
|
subscribeEvents(sessionId, res);
|
|
18332
19261
|
req.on("close", () => {
|
|
18333
19262
|
unsubscribeEvents(sessionId);
|
|
@@ -18337,7 +19266,7 @@ function setupRoutes(app) {
|
|
|
18337
19266
|
return app;
|
|
18338
19267
|
}
|
|
18339
19268
|
async function handleMcpPost(req, res) {
|
|
18340
|
-
const sessionId = req.headers["mcp-session-id"] || req.query.sessionId ||
|
|
19269
|
+
const sessionId = req.headers["mcp-session-id"] || req.query.sessionId || randomUUID6();
|
|
18341
19270
|
sessionManager.createSession(sessionId);
|
|
18342
19271
|
const body = req.body;
|
|
18343
19272
|
if (!body) {
|
|
@@ -18405,7 +19334,7 @@ async function getMcpResponse(sessionId, body) {
|
|
|
18405
19334
|
}
|
|
18406
19335
|
async function handleSse(req, res) {
|
|
18407
19336
|
const lastEventId = parseLastEventId(req);
|
|
18408
|
-
let sessionId =
|
|
19337
|
+
let sessionId = randomUUID6();
|
|
18409
19338
|
let resumeMessages = [];
|
|
18410
19339
|
if (lastEventId !== null) {
|
|
18411
19340
|
const existingSession = sessionManager.get(sessionId);
|
|
@@ -18471,7 +19400,7 @@ init_cad();
|
|
|
18471
19400
|
init_constants();
|
|
18472
19401
|
init_tools();
|
|
18473
19402
|
init_subscription_manager();
|
|
18474
|
-
import { randomUUID as
|
|
19403
|
+
import { randomUUID as randomUUID7 } from "crypto";
|
|
18475
19404
|
import { WebSocketServer } from "ws";
|
|
18476
19405
|
var PING_INTERVAL = 3e4;
|
|
18477
19406
|
var CAD_POLL_INTERVAL = 5e3;
|
|
@@ -18501,7 +19430,7 @@ function sendWelcome(ws, clientId) {
|
|
|
18501
19430
|
server: { name: SERVER_NAME, version: SERVER_VERSION },
|
|
18502
19431
|
capabilities: SERVER_CAPABILITIES,
|
|
18503
19432
|
clientId,
|
|
18504
|
-
toolCount:
|
|
19433
|
+
toolCount: tools43.length,
|
|
18505
19434
|
cadConnected: cad.connected,
|
|
18506
19435
|
cadPlatform: cad.connected ? cad.getPlatform() : null,
|
|
18507
19436
|
cadVersion: cad.connected ? cad.getVersion() : null
|
|
@@ -18668,7 +19597,7 @@ function createWebSocketServer(httpServer) {
|
|
|
18668
19597
|
startCadPolling();
|
|
18669
19598
|
_wss = new WebSocketServer({ server: httpServer, path: "/ws" });
|
|
18670
19599
|
_wss.on("connection", (ws, req) => {
|
|
18671
|
-
const clientId =
|
|
19600
|
+
const clientId = randomUUID7();
|
|
18672
19601
|
connectedClients.set(clientId, ws);
|
|
18673
19602
|
log(`WebSocket connected: ${clientId} (${connectedClients.size} total) from ${req.socket.remoteAddress}`);
|
|
18674
19603
|
sendWelcome(ws, clientId);
|
|
@@ -18753,9 +19682,9 @@ function createWebSocketServer(httpServer) {
|
|
|
18753
19682
|
// src/plugin-loader.js
|
|
18754
19683
|
init_logger();
|
|
18755
19684
|
import fs15 from "fs";
|
|
18756
|
-
import
|
|
18757
|
-
import
|
|
18758
|
-
var PLUGIN_DIR =
|
|
19685
|
+
import path19 from "path";
|
|
19686
|
+
import os11 from "os";
|
|
19687
|
+
var PLUGIN_DIR = path19.join(os11.homedir(), ".atlisp", "mcp-plugins");
|
|
18759
19688
|
var loadedPlugins = [];
|
|
18760
19689
|
var watchCallbacks = [];
|
|
18761
19690
|
var watcher = null;
|
|
@@ -18780,7 +19709,7 @@ function clearModuleCache(pluginPath) {
|
|
|
18780
19709
|
if (key) delete import.meta[key];
|
|
18781
19710
|
}
|
|
18782
19711
|
async function loadSinglePlugin(file) {
|
|
18783
|
-
const pluginPath =
|
|
19712
|
+
const pluginPath = path19.join(PLUGIN_DIR, file);
|
|
18784
19713
|
clearModuleCache(pluginPath);
|
|
18785
19714
|
try {
|
|
18786
19715
|
const plugin = await import(`${pluginPath}?t=${Date.now()}`);
|
|
@@ -18830,7 +19759,7 @@ function startPluginWatcher() {
|
|
|
18830
19759
|
if (!filename || !filename.endsWith(".js") || filename.startsWith("_")) return;
|
|
18831
19760
|
const existingIndex = loadedPlugins.findIndex((p) => p.name === filename.replace(".js", "") || p._file === filename);
|
|
18832
19761
|
if (eventType === "rename") {
|
|
18833
|
-
const filePath =
|
|
19762
|
+
const filePath = path19.join(PLUGIN_DIR, filename);
|
|
18834
19763
|
if (!fs15.existsSync(filePath)) {
|
|
18835
19764
|
if (existingIndex !== -1) {
|
|
18836
19765
|
loadedPlugins.splice(existingIndex, 1);
|
|
@@ -18870,19 +19799,104 @@ function stopPluginWatcher() {
|
|
|
18870
19799
|
init_tool_registry();
|
|
18871
19800
|
init_mcp_server_state();
|
|
18872
19801
|
|
|
19802
|
+
// src/health-reporter.js
|
|
19803
|
+
init_config();
|
|
19804
|
+
init_cad();
|
|
19805
|
+
init_cad_pool();
|
|
19806
|
+
init_mcp_server_state();
|
|
19807
|
+
init_subscription_manager();
|
|
19808
|
+
init_logger();
|
|
19809
|
+
import os12 from "os";
|
|
19810
|
+
var REPORT_URL = "https://atlisp.cn/api/mcp/health";
|
|
19811
|
+
var REPORT_INTERVAL = 3e4;
|
|
19812
|
+
var intervalHandle = null;
|
|
19813
|
+
function gatherHealth() {
|
|
19814
|
+
let cadResponseTime = 0;
|
|
19815
|
+
if (cad.connected) {
|
|
19816
|
+
const t0 = Date.now();
|
|
19817
|
+
try {
|
|
19818
|
+
cad.ping();
|
|
19819
|
+
} catch {
|
|
19820
|
+
}
|
|
19821
|
+
cadResponseTime = Date.now() - t0;
|
|
19822
|
+
}
|
|
19823
|
+
const memUsage = process.memoryUsage();
|
|
19824
|
+
let sseCount = 0;
|
|
19825
|
+
try {
|
|
19826
|
+
sseCount = sessionManager?.count?.() || 0;
|
|
19827
|
+
} catch {
|
|
19828
|
+
}
|
|
19829
|
+
return {
|
|
19830
|
+
clientId: config_default.clientId || os12.hostname(),
|
|
19831
|
+
timestamp: (/* @__PURE__ */ new Date()).toISOString(),
|
|
19832
|
+
status: "ok",
|
|
19833
|
+
cad: {
|
|
19834
|
+
connected: cad.connected,
|
|
19835
|
+
platform: cad.getPlatform ? cad.getPlatform() : null,
|
|
19836
|
+
version: cad.getVersion ? cad.getVersion() : null,
|
|
19837
|
+
responseTime: cadResponseTime,
|
|
19838
|
+
commandQueueSize: cad._getQueueSize ? cad._getQueueSize() : 0,
|
|
19839
|
+
restartCount: cad._getRestartCount ? cad._getRestartCount() : 0
|
|
19840
|
+
},
|
|
19841
|
+
system: {
|
|
19842
|
+
uptime: process.uptime(),
|
|
19843
|
+
memory: {
|
|
19844
|
+
rss: Math.round(memUsage.rss / 1024 / 1024),
|
|
19845
|
+
heapUsed: Math.round(memUsage.heapUsed / 1024 / 1024),
|
|
19846
|
+
heapTotal: Math.round(memUsage.heapTotal / 1024 / 1024)
|
|
19847
|
+
}
|
|
19848
|
+
},
|
|
19849
|
+
mcp: {
|
|
19850
|
+
sessions: sessionServers.size,
|
|
19851
|
+
sseSessions: sseCount
|
|
19852
|
+
},
|
|
19853
|
+
pool: pool ? {
|
|
19854
|
+
total: pool.getStats().total,
|
|
19855
|
+
active: pool.getStats().active,
|
|
19856
|
+
instances: pool.getStats().instances
|
|
19857
|
+
} : null
|
|
19858
|
+
};
|
|
19859
|
+
}
|
|
19860
|
+
async function report() {
|
|
19861
|
+
try {
|
|
19862
|
+
const data = gatherHealth();
|
|
19863
|
+
const res = await fetch(REPORT_URL, {
|
|
19864
|
+
method: "POST",
|
|
19865
|
+
headers: { "Content-Type": "application/json" },
|
|
19866
|
+
body: JSON.stringify(data),
|
|
19867
|
+
signal: AbortSignal.timeout(1e4)
|
|
19868
|
+
});
|
|
19869
|
+
if (!res.ok) {
|
|
19870
|
+
error(`Health report failed: ${res.status}`);
|
|
19871
|
+
}
|
|
19872
|
+
} catch (e) {
|
|
19873
|
+
error(`Health report error: ${e.message}`);
|
|
19874
|
+
}
|
|
19875
|
+
}
|
|
19876
|
+
function startHealthReporter() {
|
|
19877
|
+
report();
|
|
19878
|
+
intervalHandle = setInterval(report, REPORT_INTERVAL);
|
|
19879
|
+
}
|
|
19880
|
+
function stopHealthReporter() {
|
|
19881
|
+
if (intervalHandle) {
|
|
19882
|
+
clearInterval(intervalHandle);
|
|
19883
|
+
intervalHandle = null;
|
|
19884
|
+
}
|
|
19885
|
+
}
|
|
19886
|
+
|
|
18873
19887
|
// src/streamable-http.js
|
|
18874
19888
|
init_logger();
|
|
18875
19889
|
init_mcp_handlers();
|
|
18876
19890
|
init_mcp_tools();
|
|
18877
19891
|
import { StreamableHTTPServerTransport as StreamableHTTPServerTransport2 } from "@modelcontextprotocol/sdk/server/streamableHttp.js";
|
|
18878
|
-
import { randomUUID as
|
|
19892
|
+
import { randomUUID as randomUUID8 } from "crypto";
|
|
18879
19893
|
var mcpServer = null;
|
|
18880
19894
|
var streamableTransport = null;
|
|
18881
19895
|
async function initStreamableHttpServer() {
|
|
18882
19896
|
if (mcpServer) return;
|
|
18883
|
-
mcpServer = createMcpServer({ tools:
|
|
19897
|
+
mcpServer = createMcpServer({ tools: tools43, handleToolCall });
|
|
18884
19898
|
streamableTransport = new StreamableHTTPServerTransport2({
|
|
18885
|
-
sessionIdGenerator: () =>
|
|
19899
|
+
sessionIdGenerator: () => randomUUID8()
|
|
18886
19900
|
});
|
|
18887
19901
|
await mcpServer.connect(streamableTransport);
|
|
18888
19902
|
streamableTransport.onerror = (err) => error(`Streamable HTTP transport error: ${err.message}`);
|
|
@@ -18931,9 +19945,9 @@ function setupStreamableHttpRoutes(app) {
|
|
|
18931
19945
|
init_mcp_tools();
|
|
18932
19946
|
init_function_handlers();
|
|
18933
19947
|
init_constants();
|
|
18934
|
-
var __dirname7 =
|
|
19948
|
+
var __dirname7 = path20.dirname(fileURLToPath8(import.meta.url));
|
|
18935
19949
|
var require3 = createRequire2(import.meta.url);
|
|
18936
|
-
var { version: version2 } = require3(
|
|
19950
|
+
var { version: version2 } = require3(path20.join(__dirname7, "..", "package.json"));
|
|
18937
19951
|
var isMcpScript = process.argv[1]?.includes("atlisp-mcp");
|
|
18938
19952
|
if (isMcpScript) {
|
|
18939
19953
|
const cliArgs2 = process.argv.slice(2);
|
|
@@ -18967,6 +19981,7 @@ Options:
|
|
|
18967
19981
|
--no-lint Disable lint pre-check for eval_lisp
|
|
18968
19982
|
--lint-off Same as --no-lint
|
|
18969
19983
|
--api-key <key> API key for authentication
|
|
19984
|
+
--client-id <id> Client identifier for remote health report
|
|
18970
19985
|
--security-level <type> Security level: strict, standard, relaxed (default: strict)
|
|
18971
19986
|
|
|
18972
19987
|
Environment Variables:
|
|
@@ -18987,7 +20002,8 @@ Environment Variables:
|
|
|
18987
20002
|
LINT_LEVEL Lint level (error/warn/off)
|
|
18988
20003
|
NO_LINT Disable lint (true/false)
|
|
18989
20004
|
REQUEST_LOG_ENABLED Enable request logging (true/false, default: true)
|
|
18990
|
-
CORS_ORIGIN CORS origin (default:
|
|
20005
|
+
CORS_ORIGIN CORS origin (default: https://atlisp.cn)
|
|
20006
|
+
CLIENT_ID Client identifier for remote health report
|
|
18991
20007
|
RATE_LIMIT_WINDOW Rate limit window in ms (default: 60000)
|
|
18992
20008
|
RATE_LIMIT_MAX Max requests per window (default: 100)
|
|
18993
20009
|
|
|
@@ -19043,6 +20059,8 @@ For more info: https://atlisp.cn
|
|
|
19043
20059
|
process.env.SSL_CERT_PATH = cliArgs2[++i];
|
|
19044
20060
|
} else if (arg === "--api-key" && cliArgs2[i + 1]) {
|
|
19045
20061
|
process.env.MCP_API_KEY = cliArgs2[++i];
|
|
20062
|
+
} else if (arg === "--client-id" && cliArgs2[i + 1]) {
|
|
20063
|
+
process.env.CLIENT_ID = cliArgs2[++i];
|
|
19046
20064
|
} else if (arg === "--metrics-enabled" && cliArgs2[i + 1]) {
|
|
19047
20065
|
process.env.METRICS_ENABLED = cliArgs2[++i];
|
|
19048
20066
|
}
|
|
@@ -19065,7 +20083,7 @@ async function initCadConnection() {
|
|
|
19065
20083
|
}
|
|
19066
20084
|
async function startServer() {
|
|
19067
20085
|
await loadPlugins();
|
|
19068
|
-
initPlugins({ cad, config: config_default, log, registerTool, tools:
|
|
20086
|
+
initPlugins({ cad, config: config_default, log, registerTool, tools: tools43 });
|
|
19069
20087
|
onPluginChange((type, name) => {
|
|
19070
20088
|
log(`Plugin changed: ${type} ${name}`);
|
|
19071
20089
|
broadcastToolListChanged();
|
|
@@ -19075,7 +20093,7 @@ async function startServer() {
|
|
|
19075
20093
|
startPluginWatcher();
|
|
19076
20094
|
let promptsWatcher = null;
|
|
19077
20095
|
try {
|
|
19078
|
-
const promptsDir =
|
|
20096
|
+
const promptsDir = path20.join(__dirname7, "..", "prompts");
|
|
19079
20097
|
if (fs16.existsSync(promptsDir)) {
|
|
19080
20098
|
promptsWatcher = fs16.watch(promptsDir, (eventType, filename) => {
|
|
19081
20099
|
if (filename && filename.endsWith(".json")) {
|
|
@@ -19089,7 +20107,7 @@ async function startServer() {
|
|
|
19089
20107
|
}
|
|
19090
20108
|
if (config_default.transport === "stdio") {
|
|
19091
20109
|
await initCadConnection();
|
|
19092
|
-
const mcpServer2 = createStdioServer({ tools:
|
|
20110
|
+
const mcpServer2 = createStdioServer({ tools: tools43, handleToolCall });
|
|
19093
20111
|
const transport = new StdioServerTransport();
|
|
19094
20112
|
const sessionId = "stdio-session";
|
|
19095
20113
|
sessionManager.createSession(sessionId);
|
|
@@ -19137,10 +20155,12 @@ async function startServer() {
|
|
|
19137
20155
|
const proto = useSsl ? "https" : "http";
|
|
19138
20156
|
const mode = config_default.transport === "ws" ? "WebSocket" : config_default.transport === "streamable-http" ? "Streamable HTTP" : "\u591A\u4F1A\u8BDD";
|
|
19139
20157
|
console.error(`@lisp MCP Server \u542F\u52A8 - ${proto}://${config_default.host}:${config_default.port} (${mode}\u6A21\u5F0F)`);
|
|
20158
|
+
startHealthReporter();
|
|
19140
20159
|
});
|
|
19141
20160
|
async function shutdown(signal) {
|
|
19142
20161
|
console.error(`
|
|
19143
20162
|
\u6536\u5230 ${signal}\uFF0C\u6B63\u5728\u4F18\u96C5\u5173\u95ED...`);
|
|
20163
|
+
stopHealthReporter();
|
|
19144
20164
|
stopPluginWatcher();
|
|
19145
20165
|
if (promptsWatcher) {
|
|
19146
20166
|
promptsWatcher.close();
|
|
@@ -19190,5 +20210,5 @@ export {
|
|
|
19190
20210
|
handleToolCall,
|
|
19191
20211
|
loadAtlibFunctionLib,
|
|
19192
20212
|
startServer,
|
|
19193
|
-
|
|
20213
|
+
tools43 as tools
|
|
19194
20214
|
};
|