@atlisp/mcp 1.8.20 → 1.8.23
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/atlisp-mcp.js +657 -121
- package/dist/cad-worker.js +6 -3
- package/dist/config.js +6 -0
- package/dist/handlers/debug-handlers.js +126 -0
- package/dist/lisp-security.js +66 -12
- package/package.json +1 -1
package/dist/atlisp-mcp.js
CHANGED
|
@@ -64,6 +64,9 @@ function parseArgs() {
|
|
|
64
64
|
i++;
|
|
65
65
|
} else if (args[i] === "--no-lint" || args[i] === "--lint-off") {
|
|
66
66
|
result.noLint = true;
|
|
67
|
+
} else if (args[i] === "--security-level" && args[i + 1]) {
|
|
68
|
+
result.securityLevel = args[i + 1];
|
|
69
|
+
i++;
|
|
67
70
|
}
|
|
68
71
|
}
|
|
69
72
|
return result;
|
|
@@ -101,6 +104,9 @@ function reloadConfig() {
|
|
|
101
104
|
configReloadLock = false;
|
|
102
105
|
return false;
|
|
103
106
|
}
|
|
107
|
+
function onConfigChange(callback) {
|
|
108
|
+
configWatchers.push(callback);
|
|
109
|
+
}
|
|
104
110
|
var envSchema, configSchema, cliArgs, envResult, env, configFilePath, fileConfig, config, configWatchers, configReloadLock, config_default;
|
|
105
111
|
var init_config = __esm({
|
|
106
112
|
"src/config.js"() {
|
|
@@ -138,7 +144,8 @@ var init_config = __esm({
|
|
|
138
144
|
LINT_PRESET: z.string().optional().default(""),
|
|
139
145
|
LINT_CONFIG_PATH: z.string().optional().default(""),
|
|
140
146
|
LINT_LEVEL: z.string().optional().default(""),
|
|
141
|
-
NO_LINT: z.string().optional().default("")
|
|
147
|
+
NO_LINT: z.string().optional().default(""),
|
|
148
|
+
SECURITY_LEVEL: z.string().optional().default("strict")
|
|
142
149
|
});
|
|
143
150
|
configSchema = z.object({
|
|
144
151
|
port: z.number().optional(),
|
|
@@ -180,7 +187,8 @@ var init_config = __esm({
|
|
|
180
187
|
lintPreset: z.string().optional(),
|
|
181
188
|
lintConfigPath: z.string().optional(),
|
|
182
189
|
lintLevel: z.string().optional(),
|
|
183
|
-
noLint: z.boolean().optional()
|
|
190
|
+
noLint: z.boolean().optional(),
|
|
191
|
+
securityLevel: z.enum(["strict", "standard", "relaxed"]).optional()
|
|
184
192
|
});
|
|
185
193
|
cliArgs = parseArgs();
|
|
186
194
|
envResult = envSchema.safeParse(process.env);
|
|
@@ -227,7 +235,8 @@ var init_config = __esm({
|
|
|
227
235
|
lintPreset: fileConfig?.lintPreset || cliArgs.lintPreset || env.LINT_PRESET || void 0,
|
|
228
236
|
lintConfigPath: fileConfig?.lintConfigPath || cliArgs.lintConfigPath || env.LINT_CONFIG_PATH || void 0,
|
|
229
237
|
lintLevel: fileConfig?.lintLevel || cliArgs.lintLevel || env.LINT_LEVEL || void 0,
|
|
230
|
-
noLint: fileConfig?.noLint ?? cliArgs.noLint ?? env.NO_LINT === "true"
|
|
238
|
+
noLint: fileConfig?.noLint ?? cliArgs.noLint ?? env.NO_LINT === "true",
|
|
239
|
+
securityLevel: fileConfig?.securityLevel ?? cliArgs.securityLevel ?? (env.SECURITY_LEVEL || "strict")
|
|
231
240
|
};
|
|
232
241
|
if (config.lintConfigPath) process.env.LINT_CONFIG_PATH = config.lintConfigPath;
|
|
233
242
|
if (config.lintPreset) process.env.LINT_PRESET = config.lintPreset;
|
|
@@ -6365,6 +6374,89 @@ var init_lint_tools = __esm({
|
|
|
6365
6374
|
}
|
|
6366
6375
|
});
|
|
6367
6376
|
|
|
6377
|
+
// src/tools/debug-tools.js
|
|
6378
|
+
var tools41;
|
|
6379
|
+
var init_debug_tools = __esm({
|
|
6380
|
+
"src/tools/debug-tools.js"() {
|
|
6381
|
+
tools41 = [
|
|
6382
|
+
{
|
|
6383
|
+
name: "debug_start",
|
|
6384
|
+
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",
|
|
6385
|
+
inputSchema: {
|
|
6386
|
+
type: "object",
|
|
6387
|
+
properties: {
|
|
6388
|
+
code: { type: "string", description: "\u539F\u59CB AutoLISP \u4EE3\u7801" },
|
|
6389
|
+
chunks: {
|
|
6390
|
+
type: "array",
|
|
6391
|
+
description: "\u7531\u6269\u5C55\u7AEF\u62C6\u5206\u597D\u7684\u4EE3\u7801\u5757\u5217\u8868",
|
|
6392
|
+
items: {
|
|
6393
|
+
type: "object",
|
|
6394
|
+
properties: {
|
|
6395
|
+
id: { type: "integer", description: "\u5757\u5E8F\u53F7 (1-based)" },
|
|
6396
|
+
line: { type: "integer", description: "\u6E90\u6587\u4EF6\u884C\u53F7" },
|
|
6397
|
+
code: { type: "string", description: "\u5757\u7684 AutoLISP \u4EE3\u7801" },
|
|
6398
|
+
vars: { type: "array", items: { type: "string" }, description: "\u8BE5\u5757\u9700\u6355\u83B7\u7684\u53D8\u91CF\u540D" },
|
|
6399
|
+
isBreakpoint: { type: "boolean", description: "\u8BE5\u884C\u6709\u65AD\u70B9" },
|
|
6400
|
+
isDefunStart: { type: "boolean", description: "\u662F defun \u5B9A\u4E49\u5F00\u5934" }
|
|
6401
|
+
},
|
|
6402
|
+
required: ["id", "line", "code", "vars", "isBreakpoint"]
|
|
6403
|
+
}
|
|
6404
|
+
},
|
|
6405
|
+
encoding: { type: "string", description: "\u7F16\u7801\uFF08\u9ED8\u8BA4 auto\uFF09" }
|
|
6406
|
+
},
|
|
6407
|
+
required: ["code", "chunks"]
|
|
6408
|
+
}
|
|
6409
|
+
},
|
|
6410
|
+
{
|
|
6411
|
+
name: "debug_step",
|
|
6412
|
+
description: "\u6267\u884C\u4E00\u6B65\uFF08step\uFF09\u6216\u7EE7\u7EED\u5230\u4E0B\u4E00\u65AD\u70B9\uFF08continue\uFF09",
|
|
6413
|
+
inputSchema: {
|
|
6414
|
+
type: "object",
|
|
6415
|
+
properties: {
|
|
6416
|
+
sessionId: { type: "string", description: "\u8C03\u8BD5\u4F1A\u8BDD ID" },
|
|
6417
|
+
action: { type: "string", enum: ["step", "continue"], description: "step=\u6267\u884C\u4E00\u4E2A\u5757, continue=\u5230\u4E0B\u4E00\u65AD\u70B9/\u7ED3\u675F" }
|
|
6418
|
+
},
|
|
6419
|
+
required: ["sessionId", "action"]
|
|
6420
|
+
}
|
|
6421
|
+
},
|
|
6422
|
+
{
|
|
6423
|
+
name: "debug_evaluate",
|
|
6424
|
+
description: "\u8C03\u8BD5\u6682\u505C\u65F6\u6C42\u503C AutoLISP \u8868\u8FBE\u5F0F",
|
|
6425
|
+
inputSchema: {
|
|
6426
|
+
type: "object",
|
|
6427
|
+
properties: {
|
|
6428
|
+
sessionId: { type: "string", description: "\u8C03\u8BD5\u4F1A\u8BDD ID" },
|
|
6429
|
+
expression: { type: "string", description: "\u4EFB\u610F AutoLISP \u8868\u8FBE\u5F0F" }
|
|
6430
|
+
},
|
|
6431
|
+
required: ["sessionId", "expression"]
|
|
6432
|
+
}
|
|
6433
|
+
},
|
|
6434
|
+
{
|
|
6435
|
+
name: "debug_get_state",
|
|
6436
|
+
description: "\u67E5\u8BE2\u8C03\u8BD5\u4F1A\u8BDD\u5F53\u524D\u72B6\u6001",
|
|
6437
|
+
inputSchema: {
|
|
6438
|
+
type: "object",
|
|
6439
|
+
properties: {
|
|
6440
|
+
sessionId: { type: "string", description: "\u8C03\u8BD5\u4F1A\u8BDD ID" }
|
|
6441
|
+
},
|
|
6442
|
+
required: ["sessionId"]
|
|
6443
|
+
}
|
|
6444
|
+
},
|
|
6445
|
+
{
|
|
6446
|
+
name: "debug_stop",
|
|
6447
|
+
description: "\u505C\u6B62\u8C03\u8BD5\u4F1A\u8BDD\uFF0C\u6E05\u7406 CAD \u5168\u5C40\u53D8\u91CF\u548C\u8F85\u52A9\u51FD\u6570",
|
|
6448
|
+
inputSchema: {
|
|
6449
|
+
type: "object",
|
|
6450
|
+
properties: {
|
|
6451
|
+
sessionId: { type: "string", description: "\u8C03\u8BD5\u4F1A\u8BDD ID" }
|
|
6452
|
+
},
|
|
6453
|
+
required: ["sessionId"]
|
|
6454
|
+
}
|
|
6455
|
+
}
|
|
6456
|
+
];
|
|
6457
|
+
}
|
|
6458
|
+
});
|
|
6459
|
+
|
|
6368
6460
|
// src/tools/index.js
|
|
6369
6461
|
function addAnnotations(tool) {
|
|
6370
6462
|
const isDeprecated = DEPRECATED_TOOLS.has(tool.name);
|
|
@@ -6389,7 +6481,7 @@ function addAnnotations(tool) {
|
|
|
6389
6481
|
}
|
|
6390
6482
|
};
|
|
6391
6483
|
}
|
|
6392
|
-
var READ_ONLY_TOOLS, DEPRECATED_TOOLS, EXTRA_DESTRUCTIVE, IDEMPOTENT_WRITE_TOOLS, OPEN_WORLD_TOOLS,
|
|
6484
|
+
var READ_ONLY_TOOLS, DEPRECATED_TOOLS, EXTRA_DESTRUCTIVE, IDEMPOTENT_WRITE_TOOLS, OPEN_WORLD_TOOLS, tools42, toolsByName;
|
|
6393
6485
|
var init_tools = __esm({
|
|
6394
6486
|
"src/tools/index.js"() {
|
|
6395
6487
|
init_cad_tools();
|
|
@@ -6432,6 +6524,7 @@ var init_tools = __esm({
|
|
|
6432
6524
|
init_context_tools();
|
|
6433
6525
|
init_batch_transaction_tools();
|
|
6434
6526
|
init_lint_tools();
|
|
6527
|
+
init_debug_tools();
|
|
6435
6528
|
READ_ONLY_TOOLS = /* @__PURE__ */ new Set([
|
|
6436
6529
|
"get_cad_info",
|
|
6437
6530
|
"get_platform_info",
|
|
@@ -6514,7 +6607,8 @@ var init_tools = __esm({
|
|
|
6514
6607
|
"analyze_lisp_code",
|
|
6515
6608
|
"format_lisp_code",
|
|
6516
6609
|
"list_lint_rules",
|
|
6517
|
-
"lint_project"
|
|
6610
|
+
"lint_project",
|
|
6611
|
+
"debug_get_state"
|
|
6518
6612
|
]);
|
|
6519
6613
|
DEPRECATED_TOOLS = /* @__PURE__ */ new Set([]);
|
|
6520
6614
|
EXTRA_DESTRUCTIVE = /* @__PURE__ */ new Set([
|
|
@@ -6570,7 +6664,7 @@ var init_tools = __esm({
|
|
|
6570
6664
|
"import_page_setup",
|
|
6571
6665
|
"load_linetype"
|
|
6572
6666
|
]);
|
|
6573
|
-
|
|
6667
|
+
tools42 = [
|
|
6574
6668
|
...tools,
|
|
6575
6669
|
...tools2,
|
|
6576
6670
|
...tools3,
|
|
@@ -6610,9 +6704,10 @@ var init_tools = __esm({
|
|
|
6610
6704
|
...tools38,
|
|
6611
6705
|
...tools39,
|
|
6612
6706
|
...tools37,
|
|
6613
|
-
...tools40
|
|
6707
|
+
...tools40,
|
|
6708
|
+
...tools41
|
|
6614
6709
|
].map(addAnnotations);
|
|
6615
|
-
toolsByName = new Map(
|
|
6710
|
+
toolsByName = new Map(tools42.map((t) => [t.name, t]));
|
|
6616
6711
|
}
|
|
6617
6712
|
});
|
|
6618
6713
|
|
|
@@ -6665,7 +6760,7 @@ function parseLispList(str) {
|
|
|
6665
6760
|
});
|
|
6666
6761
|
}
|
|
6667
6762
|
function createMcpServer(handlers = {}) {
|
|
6668
|
-
const { tools:
|
|
6763
|
+
const { tools: tools43 = [], handleToolCall: handleToolCall2 = () => ({ content: [] }) } = handlers;
|
|
6669
6764
|
const server = new Server(
|
|
6670
6765
|
{ name: SERVER_NAME, version: SERVER_VERSION },
|
|
6671
6766
|
{
|
|
@@ -6688,8 +6783,8 @@ function createMcpServer(handlers = {}) {
|
|
|
6688
6783
|
const params = request.params || {};
|
|
6689
6784
|
const cursor = decodeCursor(params.cursor);
|
|
6690
6785
|
const PAGE_SIZE = 100;
|
|
6691
|
-
const page =
|
|
6692
|
-
const nextCursor = cursor + PAGE_SIZE <
|
|
6786
|
+
const page = tools43.slice(cursor, cursor + PAGE_SIZE);
|
|
6787
|
+
const nextCursor = cursor + PAGE_SIZE < tools43.length ? encodeCursor(cursor + PAGE_SIZE) : void 0;
|
|
6693
6788
|
return { tools: page, nextCursor };
|
|
6694
6789
|
});
|
|
6695
6790
|
server.setRequestHandler(CallToolRequestSchema, async (request) => {
|
|
@@ -7038,11 +7133,11 @@ function createMcpServer(handlers = {}) {
|
|
|
7038
7133
|
if (p.toLowerCase().startsWith(prefix)) values.push(p);
|
|
7039
7134
|
}
|
|
7040
7135
|
} else if (ref?.type === "tool") {
|
|
7041
|
-
for (const t of
|
|
7136
|
+
for (const t of tools43) {
|
|
7042
7137
|
if (t.name.toLowerCase().startsWith(prefix)) values.push(t.name);
|
|
7043
7138
|
}
|
|
7044
7139
|
} else if (ref?.type === "ref/parameter") {
|
|
7045
|
-
const toolDef =
|
|
7140
|
+
const toolDef = tools43.find((t) => t.name === ref.name);
|
|
7046
7141
|
if (toolDef?.inputSchema?.properties) {
|
|
7047
7142
|
const paramName = argument.name;
|
|
7048
7143
|
const paramDef = toolDef.inputSchema.properties[paramName];
|
|
@@ -8160,17 +8255,27 @@ function analyzeLispCode(code, options = {}) {
|
|
|
8160
8255
|
if (process.env.NO_LINT === "true" && !options.force) {
|
|
8161
8256
|
return { valid: true, errors: [], warnings: [], issues: [], summary: "lint \u5DF2\u8DF3\u8FC7" };
|
|
8162
8257
|
}
|
|
8258
|
+
const securityLevel = config_default?.securityLevel || "strict";
|
|
8259
|
+
if (securityLevel === "relaxed" && !options.force) {
|
|
8260
|
+
return { valid: true, errors: [], warnings: [], issues: [], summary: "\u5B89\u5168\u9650\u5236\u5DF2\u5173\u95ED (relaxed)" };
|
|
8261
|
+
}
|
|
8163
8262
|
try {
|
|
8164
|
-
const
|
|
8165
|
-
|
|
8263
|
+
const lintConfig = options.lintConfig ? mergeConfig(getDefaultConfig(), options.lintConfig) : getDefaultConfig();
|
|
8264
|
+
if (securityLevel === "standard") {
|
|
8265
|
+
for (const key of Object.keys(REQUIRED_ERROR_CHECKS)) {
|
|
8266
|
+
lintConfig.checks[key] = "warn";
|
|
8267
|
+
}
|
|
8268
|
+
}
|
|
8269
|
+
const lintIssues = runChecks(code, options.file || "<eval>", lintConfig);
|
|
8166
8270
|
for (const rule of CUSTOM_RULES) {
|
|
8271
|
+
const effectiveSeverity = securityLevel === "standard" ? "warn" : rule.severity;
|
|
8167
8272
|
const match = code.match(rule.re);
|
|
8168
8273
|
if (match) {
|
|
8169
8274
|
const line = code.slice(0, match.index).split("\n").length;
|
|
8170
8275
|
lintIssues.push({
|
|
8171
8276
|
file: options.file || "<eval>",
|
|
8172
8277
|
line,
|
|
8173
|
-
severity:
|
|
8278
|
+
severity: effectiveSeverity,
|
|
8174
8279
|
rule: rule.rule,
|
|
8175
8280
|
message: rule.msg
|
|
8176
8281
|
});
|
|
@@ -8206,6 +8311,7 @@ function mergeConfig(base, overrides) {
|
|
|
8206
8311
|
var CUSTOM_RULES, defaultConfig, REQUIRED_ERROR_CHECKS;
|
|
8207
8312
|
var init_lint_analyzer = __esm({
|
|
8208
8313
|
"src/lint-analyzer.js"() {
|
|
8314
|
+
init_config();
|
|
8209
8315
|
CUSTOM_RULES = [
|
|
8210
8316
|
{ rule: "command_shell", severity: "error", re: /\(\s*command\s+"\s*[_.]*\s*shell\s*"/i, msg: '(command "shell" ...) \u4F1A\u542F\u52A8\u7CFB\u7EDF Shell' },
|
|
8211
8317
|
{ rule: "vl_registry_write", severity: "error", re: /\(\s*vl-registry-write[\s\)]/i, msg: "vl-registry-write \u4F1A\u4FEE\u6539 Windows \u6CE8\u518C\u8868" },
|
|
@@ -8545,6 +8651,359 @@ var init_constraint_handlers = __esm({
|
|
|
8545
8651
|
}
|
|
8546
8652
|
});
|
|
8547
8653
|
|
|
8654
|
+
// src/debug-engine.js
|
|
8655
|
+
import { randomUUID as randomUUID4 } from "crypto";
|
|
8656
|
+
async function ensureCad() {
|
|
8657
|
+
if (!cad.connected) {
|
|
8658
|
+
log("Debug engine: CAD not connected, attempting auto-connect...");
|
|
8659
|
+
await cad.connect();
|
|
8660
|
+
}
|
|
8661
|
+
if (!cad.connected) {
|
|
8662
|
+
throw new Error("CAD \u672A\u8FDE\u63A5");
|
|
8663
|
+
}
|
|
8664
|
+
}
|
|
8665
|
+
async function createSession(code, chunks, encoding) {
|
|
8666
|
+
if (sessions.size >= MAX_SESSIONS2) {
|
|
8667
|
+
let oldest = null;
|
|
8668
|
+
for (const [id, s] of sessions) {
|
|
8669
|
+
if (!oldest || s.createdAt < oldest.createdAt) oldest = { id, s };
|
|
8670
|
+
}
|
|
8671
|
+
if (oldest) {
|
|
8672
|
+
sessions.delete(oldest.id);
|
|
8673
|
+
log(`Debug session ${oldest.id} evicted (max sessions)`);
|
|
8674
|
+
}
|
|
8675
|
+
}
|
|
8676
|
+
if (!chunks || chunks.length === 0) {
|
|
8677
|
+
throw new Error("Chunks array is empty");
|
|
8678
|
+
}
|
|
8679
|
+
if (chunks.length > MAX_CHUNKS) {
|
|
8680
|
+
throw new Error(`Too many chunks: ${chunks.length} (max ${MAX_CHUNKS})`);
|
|
8681
|
+
}
|
|
8682
|
+
for (const chunk of chunks) {
|
|
8683
|
+
if (typeof chunk.id !== "number" || typeof chunk.code !== "string") {
|
|
8684
|
+
throw new Error("Each chunk must have id (number) and code (string)");
|
|
8685
|
+
}
|
|
8686
|
+
}
|
|
8687
|
+
const sessionId = randomUUID4();
|
|
8688
|
+
const session = new DebugSession(sessionId, code, chunks, encoding);
|
|
8689
|
+
sessions.set(sessionId, session);
|
|
8690
|
+
return sessionId;
|
|
8691
|
+
}
|
|
8692
|
+
function getSession(id) {
|
|
8693
|
+
return sessions.get(id) || null;
|
|
8694
|
+
}
|
|
8695
|
+
async function closeSession(sessionId) {
|
|
8696
|
+
const session = sessions.get(sessionId);
|
|
8697
|
+
if (!session) return false;
|
|
8698
|
+
try {
|
|
8699
|
+
if (cad.connected) {
|
|
8700
|
+
await cad.sendCommand(CLEANUP_CODE + "\n");
|
|
8701
|
+
}
|
|
8702
|
+
} catch (e) {
|
|
8703
|
+
log(`Debug cleanup warning: ${e.message}`);
|
|
8704
|
+
}
|
|
8705
|
+
sessions.delete(sessionId);
|
|
8706
|
+
return true;
|
|
8707
|
+
}
|
|
8708
|
+
async function loadHelpers(session) {
|
|
8709
|
+
await ensureCad();
|
|
8710
|
+
try {
|
|
8711
|
+
await cad.sendCommand(HELPER_DEFUNS + "\n");
|
|
8712
|
+
} catch (e) {
|
|
8713
|
+
throw new Error(`Failed to load debug helpers: ${e.message}`);
|
|
8714
|
+
}
|
|
8715
|
+
}
|
|
8716
|
+
async function fastForward(session) {
|
|
8717
|
+
await ensureCad();
|
|
8718
|
+
session.state = "running";
|
|
8719
|
+
while (session.currentIndex < session.totalChunks) {
|
|
8720
|
+
const chunk = session.chunks[session.currentIndex];
|
|
8721
|
+
if (chunk.isBreakpoint) break;
|
|
8722
|
+
try {
|
|
8723
|
+
await cad.sendCommandWithResult(chunk.code, session.encoding);
|
|
8724
|
+
} catch (e) {
|
|
8725
|
+
session.state = "error";
|
|
8726
|
+
session.error = `Fast-forward error at chunk ${chunk.id}: ${e.message}`;
|
|
8727
|
+
throw new Error(session.error);
|
|
8728
|
+
}
|
|
8729
|
+
session.currentIndex++;
|
|
8730
|
+
}
|
|
8731
|
+
if (session.currentIndex >= session.totalChunks) {
|
|
8732
|
+
session.state = "done";
|
|
8733
|
+
return {
|
|
8734
|
+
done: true,
|
|
8735
|
+
finalResult: session.finalResult
|
|
8736
|
+
};
|
|
8737
|
+
}
|
|
8738
|
+
session.state = "paused";
|
|
8739
|
+
return {
|
|
8740
|
+
done: false,
|
|
8741
|
+
pausedAt: {
|
|
8742
|
+
id: session.chunks[session.currentIndex].id,
|
|
8743
|
+
line: session.chunks[session.currentIndex].line
|
|
8744
|
+
}
|
|
8745
|
+
};
|
|
8746
|
+
}
|
|
8747
|
+
async function executeStep(session) {
|
|
8748
|
+
await ensureCad();
|
|
8749
|
+
if (session.state !== "paused" && session.state !== "ready") {
|
|
8750
|
+
throw new Error(`Invalid state: ${session.state} (expected paused or ready)`);
|
|
8751
|
+
}
|
|
8752
|
+
if (session.currentIndex >= session.totalChunks) {
|
|
8753
|
+
session.state = "done";
|
|
8754
|
+
return { done: true, finalResult: session.finalResult };
|
|
8755
|
+
}
|
|
8756
|
+
const chunk = session.chunks[session.currentIndex];
|
|
8757
|
+
const vars = chunk.vars || [];
|
|
8758
|
+
session.state = "running";
|
|
8759
|
+
let rawResult;
|
|
8760
|
+
try {
|
|
8761
|
+
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";
|
|
8762
|
+
const lispCode = `(progn
|
|
8763
|
+
(setq @::dbg/result (progn ${chunk.code}))
|
|
8764
|
+
(list
|
|
8765
|
+
(vl-prin1-to-string @::dbg/result)
|
|
8766
|
+
${varCapture}))`;
|
|
8767
|
+
rawResult = await cad.sendCommandWithResult(lispCode, session.encoding);
|
|
8768
|
+
} catch (e) {
|
|
8769
|
+
session.state = "error";
|
|
8770
|
+
session.error = `Step error at chunk ${chunk.id}: ${e.message}`;
|
|
8771
|
+
throw new Error(session.error);
|
|
8772
|
+
}
|
|
8773
|
+
session.currentIndex++;
|
|
8774
|
+
session.finalResult = rawResult;
|
|
8775
|
+
let parsedResult = rawResult;
|
|
8776
|
+
let variables = [];
|
|
8777
|
+
try {
|
|
8778
|
+
const parsed = parseLispRecursive(rawResult);
|
|
8779
|
+
if (Array.isArray(parsed) && parsed.length >= 2) {
|
|
8780
|
+
parsedResult = parsed[0] !== null ? String(parsed[0]) : "nil";
|
|
8781
|
+
if (Array.isArray(parsed[1])) {
|
|
8782
|
+
variables = parsed[1].map((item) => {
|
|
8783
|
+
if (Array.isArray(item) && item.length >= 2) {
|
|
8784
|
+
return { name: String(item[0] || ""), value: item[1] !== null ? String(item[1]) : "nil" };
|
|
8785
|
+
}
|
|
8786
|
+
return null;
|
|
8787
|
+
}).filter(Boolean);
|
|
8788
|
+
}
|
|
8789
|
+
}
|
|
8790
|
+
} catch {
|
|
8791
|
+
parsedResult = rawResult || "nil";
|
|
8792
|
+
}
|
|
8793
|
+
const checkpoint = {
|
|
8794
|
+
id: chunk.id,
|
|
8795
|
+
line: chunk.line,
|
|
8796
|
+
variables,
|
|
8797
|
+
result: parsedResult
|
|
8798
|
+
};
|
|
8799
|
+
session.lastCheckpoint = checkpoint;
|
|
8800
|
+
if (session.currentIndex >= session.totalChunks) {
|
|
8801
|
+
session.state = "done";
|
|
8802
|
+
return {
|
|
8803
|
+
done: true,
|
|
8804
|
+
checkpoint,
|
|
8805
|
+
finalResult: parsedResult
|
|
8806
|
+
};
|
|
8807
|
+
}
|
|
8808
|
+
session.state = "paused";
|
|
8809
|
+
return { done: false, checkpoint };
|
|
8810
|
+
}
|
|
8811
|
+
async function continueExecution(session) {
|
|
8812
|
+
await ensureCad();
|
|
8813
|
+
if (session.state !== "paused" && session.state !== "ready") {
|
|
8814
|
+
throw new Error(`Invalid state: ${session.state} (expected paused or ready)`);
|
|
8815
|
+
}
|
|
8816
|
+
while (session.currentIndex < session.totalChunks) {
|
|
8817
|
+
const chunk = session.chunks[session.currentIndex];
|
|
8818
|
+
if (chunk.isBreakpoint) {
|
|
8819
|
+
return await executeStep(session);
|
|
8820
|
+
}
|
|
8821
|
+
try {
|
|
8822
|
+
await cad.sendCommandWithResult(chunk.code, session.encoding);
|
|
8823
|
+
} catch (e) {
|
|
8824
|
+
session.state = "error";
|
|
8825
|
+
session.error = `Continue error at chunk ${chunk.id}: ${e.message}`;
|
|
8826
|
+
throw new Error(session.error);
|
|
8827
|
+
}
|
|
8828
|
+
session.currentIndex++;
|
|
8829
|
+
session.finalResult = null;
|
|
8830
|
+
}
|
|
8831
|
+
session.state = "done";
|
|
8832
|
+
return { done: true, finalResult: session.finalResult };
|
|
8833
|
+
}
|
|
8834
|
+
async function evaluateExpression(session, expression) {
|
|
8835
|
+
await ensureCad();
|
|
8836
|
+
if (session.state !== "paused") {
|
|
8837
|
+
throw new Error(`Invalid state: ${session.state} (expected paused)`);
|
|
8838
|
+
}
|
|
8839
|
+
try {
|
|
8840
|
+
const result = await cad.sendCommandWithResult(`(vl-prin1-to-string ${expression})`, session.encoding);
|
|
8841
|
+
return { value: result || "nil" };
|
|
8842
|
+
} catch (e) {
|
|
8843
|
+
return { error: `CAD error: ${e.message}` };
|
|
8844
|
+
}
|
|
8845
|
+
}
|
|
8846
|
+
var sessions, MAX_SESSIONS2, MAX_CHUNKS, HELPER_DEFUNS, CLEANUP_CODE, DebugSession;
|
|
8847
|
+
var init_debug_engine = __esm({
|
|
8848
|
+
"src/debug-engine.js"() {
|
|
8849
|
+
init_cad();
|
|
8850
|
+
init_logger();
|
|
8851
|
+
init_handler_utils();
|
|
8852
|
+
sessions = /* @__PURE__ */ new Map();
|
|
8853
|
+
MAX_SESSIONS2 = 10;
|
|
8854
|
+
MAX_CHUNKS = 500;
|
|
8855
|
+
HELPER_DEFUNS = `
|
|
8856
|
+
(defun @::dbg/exec-chunk (chunk-code var-names)
|
|
8857
|
+
(setq @::dbg/result (eval (read chunk-code)))
|
|
8858
|
+
(if var-names
|
|
8859
|
+
(setq @::dbg/snapshot
|
|
8860
|
+
(mapcar
|
|
8861
|
+
(function (lambda (v)
|
|
8862
|
+
(list (vl-prin1-to-string v)
|
|
8863
|
+
(if (boundp v) (vl-prin1-to-string (eval v)) nil))))
|
|
8864
|
+
var-names))
|
|
8865
|
+
(setq @::dbg/snapshot nil))
|
|
8866
|
+
(list @::dbg/result @::dbg/snapshot))
|
|
8867
|
+
`;
|
|
8868
|
+
CLEANUP_CODE = `
|
|
8869
|
+
(if (not (vl-catch-all-error-p (vl-catch-all-apply (function (lambda ()
|
|
8870
|
+
(mapcar (function (lambda (s) (set s nil)))
|
|
8871
|
+
(quote (@::dbg/result @::dbg/snapshot @::dbg/state @::dbg/chunks @::dbg/idx @::dbg/encoding))))))))
|
|
8872
|
+
(princ "ok"))
|
|
8873
|
+
`;
|
|
8874
|
+
DebugSession = class {
|
|
8875
|
+
constructor(sessionId, code, chunks, encoding) {
|
|
8876
|
+
this.sessionId = sessionId;
|
|
8877
|
+
this.code = code;
|
|
8878
|
+
this.chunks = chunks;
|
|
8879
|
+
this.totalChunks = chunks.length;
|
|
8880
|
+
this.currentIndex = 0;
|
|
8881
|
+
this.encoding = encoding || null;
|
|
8882
|
+
this.state = "ready";
|
|
8883
|
+
this.lastCheckpoint = null;
|
|
8884
|
+
this.finalResult = null;
|
|
8885
|
+
this.createdAt = Date.now();
|
|
8886
|
+
this.error = null;
|
|
8887
|
+
}
|
|
8888
|
+
};
|
|
8889
|
+
}
|
|
8890
|
+
});
|
|
8891
|
+
|
|
8892
|
+
// src/handlers/debug-handlers.js
|
|
8893
|
+
var debug_handlers_exports = {};
|
|
8894
|
+
__export(debug_handlers_exports, {
|
|
8895
|
+
debugEvaluate: () => debugEvaluate,
|
|
8896
|
+
debugGetState: () => debugGetState,
|
|
8897
|
+
debugStart: () => debugStart,
|
|
8898
|
+
debugStep: () => debugStep,
|
|
8899
|
+
debugStop: () => debugStop
|
|
8900
|
+
});
|
|
8901
|
+
async function debugGetState(args) {
|
|
8902
|
+
try {
|
|
8903
|
+
const { sessionId } = args || {};
|
|
8904
|
+
if (!sessionId) return mcpError("Missing required argument: sessionId");
|
|
8905
|
+
const session = getSession(sessionId);
|
|
8906
|
+
if (!session) return mcpError(`Debug session not found: ${sessionId}`);
|
|
8907
|
+
const checkpoint = session.lastCheckpoint;
|
|
8908
|
+
return mcpSuccess(JSON.stringify({
|
|
8909
|
+
state: session.state,
|
|
8910
|
+
currentIndex: session.currentIndex,
|
|
8911
|
+
totalChunks: session.totalChunks,
|
|
8912
|
+
currentCheckpoint: checkpoint || void 0,
|
|
8913
|
+
error: session.error
|
|
8914
|
+
}));
|
|
8915
|
+
} catch (e) {
|
|
8916
|
+
return mcpError(e.message);
|
|
8917
|
+
}
|
|
8918
|
+
}
|
|
8919
|
+
async function debugStop(args) {
|
|
8920
|
+
try {
|
|
8921
|
+
const { sessionId } = args || {};
|
|
8922
|
+
if (!sessionId) return mcpError("Missing required argument: sessionId");
|
|
8923
|
+
const session = getSession(sessionId);
|
|
8924
|
+
if (!session) {
|
|
8925
|
+
return mcpError(`Debug session not found: ${sessionId}`);
|
|
8926
|
+
}
|
|
8927
|
+
const ok = await closeSession(sessionId);
|
|
8928
|
+
return mcpSuccess(JSON.stringify({ success: ok }));
|
|
8929
|
+
} catch (e) {
|
|
8930
|
+
return mcpError(e.message);
|
|
8931
|
+
}
|
|
8932
|
+
}
|
|
8933
|
+
var debugStart, debugStep, debugEvaluate;
|
|
8934
|
+
var init_debug_handlers = __esm({
|
|
8935
|
+
"src/handlers/debug-handlers.js"() {
|
|
8936
|
+
init_handler_utils();
|
|
8937
|
+
init_debug_engine();
|
|
8938
|
+
debugStart = withCadConnection(async (args) => {
|
|
8939
|
+
try {
|
|
8940
|
+
const { code, chunks, encoding } = args || {};
|
|
8941
|
+
if (!code) return mcpError("Missing required argument: code");
|
|
8942
|
+
if (!chunks || !Array.isArray(chunks)) return mcpError("Missing required argument: chunks (must be an array)");
|
|
8943
|
+
const sessionId = await createSession(code, chunks, encoding);
|
|
8944
|
+
const session = getSession(sessionId);
|
|
8945
|
+
if (!session) return mcpError("Failed to create debug session");
|
|
8946
|
+
await loadHelpers(session);
|
|
8947
|
+
const ffResult = await fastForward(session);
|
|
8948
|
+
if (session.state === "error") {
|
|
8949
|
+
await closeSession(sessionId);
|
|
8950
|
+
return mcpError(session.error);
|
|
8951
|
+
}
|
|
8952
|
+
return mcpSuccess(JSON.stringify({
|
|
8953
|
+
sessionId,
|
|
8954
|
+
totalChunks: session.totalChunks,
|
|
8955
|
+
...ffResult
|
|
8956
|
+
}));
|
|
8957
|
+
} catch (e) {
|
|
8958
|
+
return mcpError(e.message);
|
|
8959
|
+
}
|
|
8960
|
+
});
|
|
8961
|
+
debugStep = withCadConnection(async (args) => {
|
|
8962
|
+
try {
|
|
8963
|
+
const { sessionId, action } = args || {};
|
|
8964
|
+
if (!sessionId) return mcpError("Missing required argument: sessionId");
|
|
8965
|
+
if (!action) return mcpError("Missing required argument: action");
|
|
8966
|
+
const session = getSession(sessionId);
|
|
8967
|
+
if (!session) return mcpError(`Debug session not found: ${sessionId}`);
|
|
8968
|
+
if (session.state !== "paused" && session.state !== "ready") {
|
|
8969
|
+
return mcpError(`Invalid state: ${session.state} (expected paused or ready)`);
|
|
8970
|
+
}
|
|
8971
|
+
let result;
|
|
8972
|
+
if (action === "step") {
|
|
8973
|
+
result = await executeStep(session);
|
|
8974
|
+
} else if (action === "continue") {
|
|
8975
|
+
result = await continueExecution(session);
|
|
8976
|
+
} else {
|
|
8977
|
+
return mcpError(`Invalid action: ${action} (expected step or continue)`);
|
|
8978
|
+
}
|
|
8979
|
+
if (session.state === "error") {
|
|
8980
|
+
return mcpError(session.error);
|
|
8981
|
+
}
|
|
8982
|
+
return mcpSuccess(JSON.stringify(result));
|
|
8983
|
+
} catch (e) {
|
|
8984
|
+
return mcpError(e.message);
|
|
8985
|
+
}
|
|
8986
|
+
});
|
|
8987
|
+
debugEvaluate = withCadConnection(async (args) => {
|
|
8988
|
+
try {
|
|
8989
|
+
const { sessionId, expression } = args || {};
|
|
8990
|
+
if (!sessionId) return mcpError("Missing required argument: sessionId");
|
|
8991
|
+
if (!expression) return mcpError("Missing required argument: expression");
|
|
8992
|
+
const session = getSession(sessionId);
|
|
8993
|
+
if (!session) return mcpError(`Debug session not found: ${sessionId}`);
|
|
8994
|
+
if (session.state !== "paused") {
|
|
8995
|
+
return mcpError(`Invalid state: ${session.state} (expected paused)`);
|
|
8996
|
+
}
|
|
8997
|
+
const result = await evaluateExpression(session, expression);
|
|
8998
|
+
if (result.error) return mcpError(result.error);
|
|
8999
|
+
return mcpSuccess(JSON.stringify({ value: result.value }));
|
|
9000
|
+
} catch (e) {
|
|
9001
|
+
return mcpError(e.message);
|
|
9002
|
+
}
|
|
9003
|
+
});
|
|
9004
|
+
}
|
|
9005
|
+
});
|
|
9006
|
+
|
|
8548
9007
|
// src/handlers/dim-hatch-handlers.js
|
|
8549
9008
|
var dim_hatch_handlers_exports = {};
|
|
8550
9009
|
__export(dim_hatch_handlers_exports, {
|
|
@@ -13825,6 +14284,7 @@ var init_ = __esm({
|
|
|
13825
14284
|
"./handlers/block-handlers.js": () => Promise.resolve().then(() => (init_block_handlers(), block_handlers_exports)),
|
|
13826
14285
|
"./handlers/cad-handlers.js": () => Promise.resolve().then(() => (init_cad_handlers(), cad_handlers_exports)),
|
|
13827
14286
|
"./handlers/constraint-handlers.js": () => Promise.resolve().then(() => (init_constraint_handlers(), constraint_handlers_exports)),
|
|
14287
|
+
"./handlers/debug-handlers.js": () => Promise.resolve().then(() => (init_debug_handlers(), debug_handlers_exports)),
|
|
13828
14288
|
"./handlers/dim-hatch-handlers.js": () => Promise.resolve().then(() => (init_dim_hatch_handlers(), dim_hatch_handlers_exports)),
|
|
13829
14289
|
"./handlers/draw-handlers.js": () => Promise.resolve().then(() => (init_draw_handlers(), draw_handlers_exports)),
|
|
13830
14290
|
"./handlers/edit-handlers.js": () => Promise.resolve().then(() => (init_edit_handlers(), edit_handlers_exports)),
|
|
@@ -14712,22 +15172,65 @@ var init_trigger_engine = __esm({
|
|
|
14712
15172
|
});
|
|
14713
15173
|
|
|
14714
15174
|
// src/lisp-security.js
|
|
15175
|
+
function getLevel() {
|
|
15176
|
+
const level = config_default?.securityLevel || "strict";
|
|
15177
|
+
return CVT[level] || THREAT_BLOCK;
|
|
15178
|
+
}
|
|
15179
|
+
function resolveSeverity(rule) {
|
|
15180
|
+
if (_cachedLevel) return _cachedLevel;
|
|
15181
|
+
_cachedLevel = getLevel();
|
|
15182
|
+
return _cachedLevel;
|
|
15183
|
+
}
|
|
15184
|
+
function getEffectiveSeverity() {
|
|
15185
|
+
return resolveSeverity();
|
|
15186
|
+
}
|
|
14715
15187
|
function stripStringsAndComments(code) {
|
|
14716
15188
|
const withoutStrings = code.replace(/"([^"\\]*(?:\\.[^"\\]*)*)"/g, "");
|
|
14717
15189
|
return withoutStrings.replace(/;.*$/gm, "");
|
|
14718
15190
|
}
|
|
14719
|
-
var THREAT_BLOCK, THREAT_WARN, SECURITY_RULES;
|
|
15191
|
+
var THREAT_BLOCK, THREAT_WARN, THREAT_ALLOW, CVT, SECURITY_RULES, _cachedLevel;
|
|
14720
15192
|
var init_lisp_security = __esm({
|
|
14721
15193
|
"src/lisp-security.js"() {
|
|
14722
15194
|
init_logger();
|
|
15195
|
+
init_config();
|
|
14723
15196
|
THREAT_BLOCK = "block";
|
|
14724
15197
|
THREAT_WARN = "warn";
|
|
15198
|
+
THREAT_ALLOW = "allow";
|
|
15199
|
+
CVT = {
|
|
15200
|
+
strict: THREAT_BLOCK,
|
|
15201
|
+
standard: THREAT_WARN,
|
|
15202
|
+
relaxed: THREAT_ALLOW
|
|
15203
|
+
};
|
|
14725
15204
|
SECURITY_RULES = [
|
|
14726
|
-
{ re: /\bstartapp\s*[(\s]/i,
|
|
14727
|
-
{ re: /\bvl-bt\b/i,
|
|
14728
|
-
{ re: /\bvlax-import-type-library\b/i,
|
|
14729
|
-
{ re: /\bdos_command_string\s*[(\s]/i,
|
|
15205
|
+
{ re: /\bstartapp\s*[(\s]/i, baseSeverity: THREAT_BLOCK, msg: "\u7981\u6B62\u4F7F\u7528 startapp \u51FD\u6570" },
|
|
15206
|
+
{ re: /\bvl-bt\b/i, baseSeverity: THREAT_BLOCK, msg: "\u7981\u6B62\u4F7F\u7528 vl-bt \u51FD\u6570" },
|
|
15207
|
+
{ re: /\bvlax-import-type-library\b/i, baseSeverity: THREAT_BLOCK, msg: "\u7981\u6B62\u5BFC\u5165\u7C7B\u578B\u5E93" },
|
|
15208
|
+
{ re: /\bdos_command_string\s*[(\s]/i, baseSeverity: THREAT_BLOCK, msg: "\u7981\u6B62\u4F7F\u7528 dos_command_string" },
|
|
15209
|
+
{ re: /\beval\s*[(\s]/i, baseSeverity: THREAT_BLOCK, msg: "\u7981\u6B62\u4F7F\u7528 eval \u51FD\u6570" },
|
|
15210
|
+
{ 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" },
|
|
15211
|
+
{ re: /\bload\s*[(\s"]/i, baseSeverity: THREAT_BLOCK, msg: "load \u51FD\u6570\u53EF\u80FD\u52A0\u8F7D\u5916\u90E8\u4EE3\u7801" },
|
|
15212
|
+
{ 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" },
|
|
15213
|
+
{ re: /\bvl-file-copy\s*[(\s]/i, baseSeverity: THREAT_BLOCK, msg: "\u7981\u6B62\u6587\u4EF6\u590D\u5236" },
|
|
15214
|
+
{ re: /\bvl-file-delete\s*[(\s]/i, baseSeverity: THREAT_BLOCK, msg: "\u7981\u6B62\u6587\u4EF6\u5220\u9664" },
|
|
15215
|
+
{ re: /\bvl-file-rename\s*[(\s]/i, baseSeverity: THREAT_BLOCK, msg: "\u7981\u6B62\u6587\u4EF6\u91CD\u547D\u540D" },
|
|
15216
|
+
{ re: /\bvl-registry-write[\s\)]/i, baseSeverity: THREAT_BLOCK, msg: "vl-registry-write \u4F1A\u4FEE\u6539\u6CE8\u518C\u8868" },
|
|
15217
|
+
{ re: /\bvl-exit-with-value\b/i, baseSeverity: THREAT_BLOCK, msg: "\u7981\u6B62\u4F7F\u7528 vl-exit-with-value" },
|
|
15218
|
+
{ re: /\bvl-exit-with-error\b/i, baseSeverity: THREAT_BLOCK, msg: "\u7981\u6B62\u4F7F\u7528 vl-exit-with-error" },
|
|
15219
|
+
{ re: /\bvlax-add-cmd\b/i, baseSeverity: THREAT_BLOCK, msg: "\u7981\u6B62\u6CE8\u518C\u65B0\u547D\u4EE4" },
|
|
15220
|
+
{ re: /\bvla-Delete\b/i, baseSeverity: THREAT_BLOCK, msg: "\u7981\u6B62\u76F4\u63A5\u5220\u9664 vla \u5BF9\u8C61" },
|
|
15221
|
+
{ re: /\bvla-Save\s*[(\s]/i, baseSeverity: THREAT_BLOCK, msg: "\u7981\u6B62\u76F4\u63A5\u4FDD\u5B58\u6587\u6863" },
|
|
15222
|
+
{ re: /\bdirectory\s*[(\s]/i, baseSeverity: THREAT_BLOCK, msg: "\u7981\u6B62\u4F7F\u7528 directory \u51FD\u6570" },
|
|
15223
|
+
{ re: /\bvla-deletefile\b/i, baseSeverity: THREAT_BLOCK, msg: "\u7981\u6B62\u5220\u9664\u6587\u4EF6" },
|
|
15224
|
+
{ re: /\bvla-copyfile\b/i, baseSeverity: THREAT_BLOCK, msg: "\u7981\u6B62\u590D\u5236\u6587\u4EF6" },
|
|
15225
|
+
{ re: /\bvla-movefile\b/i, baseSeverity: THREAT_BLOCK, msg: "\u7981\u6B62\u79FB\u52A8\u6587\u4EF6" }
|
|
14730
15226
|
];
|
|
15227
|
+
_cachedLevel = null;
|
|
15228
|
+
try {
|
|
15229
|
+
onConfigChange(() => {
|
|
15230
|
+
_cachedLevel = null;
|
|
15231
|
+
});
|
|
15232
|
+
} catch (_) {
|
|
15233
|
+
}
|
|
14731
15234
|
}
|
|
14732
15235
|
});
|
|
14733
15236
|
|
|
@@ -14747,21 +15250,23 @@ function clearSessionAllowlist(sessionId) {
|
|
|
14747
15250
|
}
|
|
14748
15251
|
function validateLispCode(code, sessionId = null) {
|
|
14749
15252
|
const withoutComments = stripStringsAndComments(code);
|
|
15253
|
+
const effectiveSeverity = getEffectiveSeverity();
|
|
14750
15254
|
const results = [];
|
|
14751
15255
|
let blocked = false;
|
|
14752
15256
|
for (let i = 0; i < RULES2.length; i++) {
|
|
14753
15257
|
const rule = RULES2[i];
|
|
14754
15258
|
if (rule.re.test(withoutComments)) {
|
|
14755
15259
|
const isAllowed = sessionId && getSessionAllowlist(sessionId).has(i);
|
|
15260
|
+
const severity = effectiveSeverity === THREAT_ALLOW ? THREAT_ALLOW : isAllowed ? THREAT_ALLOW : effectiveSeverity;
|
|
14756
15261
|
results.push({
|
|
14757
15262
|
ruleIndex: i,
|
|
14758
|
-
severity
|
|
15263
|
+
severity,
|
|
14759
15264
|
message: rule.msg,
|
|
14760
|
-
blocked:
|
|
14761
|
-
warned:
|
|
14762
|
-
allowed:
|
|
15265
|
+
blocked: severity === THREAT_BLOCK,
|
|
15266
|
+
warned: severity === THREAT_WARN,
|
|
15267
|
+
allowed: severity === THREAT_ALLOW
|
|
14763
15268
|
});
|
|
14764
|
-
if (
|
|
15269
|
+
if (severity === THREAT_BLOCK) {
|
|
14765
15270
|
blocked = true;
|
|
14766
15271
|
}
|
|
14767
15272
|
}
|
|
@@ -14777,6 +15282,7 @@ var RULES2, sessionAllowlist;
|
|
|
14777
15282
|
var init_lisp_sandbox = __esm({
|
|
14778
15283
|
"src/lisp-sandbox.js"() {
|
|
14779
15284
|
init_logger();
|
|
15285
|
+
init_config();
|
|
14780
15286
|
init_lisp_security();
|
|
14781
15287
|
RULES2 = SECURITY_RULES;
|
|
14782
15288
|
sessionAllowlist = /* @__PURE__ */ new Map();
|
|
@@ -14784,54 +15290,54 @@ var init_lisp_sandbox = __esm({
|
|
|
14784
15290
|
});
|
|
14785
15291
|
|
|
14786
15292
|
// src/repl-engine.js
|
|
14787
|
-
import { randomUUID as
|
|
15293
|
+
import { randomUUID as randomUUID5 } from "crypto";
|
|
14788
15294
|
function ensureCleanup2() {
|
|
14789
15295
|
if (cleanupTimer2) return;
|
|
14790
15296
|
cleanupTimer2 = setInterval(() => {
|
|
14791
15297
|
const now = Date.now();
|
|
14792
|
-
for (const [id, session] of
|
|
15298
|
+
for (const [id, session] of sessions2) {
|
|
14793
15299
|
if (now - session.createdAt > SESSION_TTL) {
|
|
14794
|
-
|
|
15300
|
+
sessions2.delete(id);
|
|
14795
15301
|
log(`REPL session ${id} expired (TTL)`);
|
|
14796
15302
|
}
|
|
14797
15303
|
}
|
|
14798
15304
|
}, CLEANUP_INTERVAL3);
|
|
14799
15305
|
cleanupTimer2.unref();
|
|
14800
15306
|
}
|
|
14801
|
-
function
|
|
14802
|
-
if (
|
|
15307
|
+
function createSession2() {
|
|
15308
|
+
if (sessions2.size >= MAX_SESSIONS3) {
|
|
14803
15309
|
let oldest = null;
|
|
14804
|
-
for (const [id, s] of
|
|
15310
|
+
for (const [id, s] of sessions2) {
|
|
14805
15311
|
if (!oldest || s.lastActivity < oldest.lastActivity) oldest = { id, s };
|
|
14806
15312
|
}
|
|
14807
15313
|
if (oldest) {
|
|
14808
|
-
|
|
15314
|
+
sessions2.delete(oldest.id);
|
|
14809
15315
|
log(`REPL session ${oldest.id} evicted (max sessions reached)`);
|
|
14810
15316
|
}
|
|
14811
15317
|
}
|
|
14812
15318
|
ensureCleanup2();
|
|
14813
|
-
const sessionId =
|
|
15319
|
+
const sessionId = randomUUID5();
|
|
14814
15320
|
const session = new ReplSession(sessionId);
|
|
14815
|
-
|
|
15321
|
+
sessions2.set(sessionId, session);
|
|
14816
15322
|
return sessionId;
|
|
14817
15323
|
}
|
|
14818
15324
|
async function executeInSession(sessionId, code) {
|
|
14819
|
-
let session =
|
|
15325
|
+
let session = sessions2.get(sessionId);
|
|
14820
15326
|
if (!session) {
|
|
14821
|
-
sessionId =
|
|
14822
|
-
session =
|
|
15327
|
+
sessionId = createSession2();
|
|
15328
|
+
session = sessions2.get(sessionId);
|
|
14823
15329
|
}
|
|
14824
15330
|
const result = await session.execute(code);
|
|
14825
15331
|
return { sessionId, result, history: session.history };
|
|
14826
15332
|
}
|
|
14827
15333
|
function getHistory(sessionId) {
|
|
14828
|
-
const session =
|
|
15334
|
+
const session = sessions2.get(sessionId);
|
|
14829
15335
|
if (!session) return null;
|
|
14830
15336
|
return session.history;
|
|
14831
15337
|
}
|
|
14832
|
-
function
|
|
15338
|
+
function listSessions2() {
|
|
14833
15339
|
const result = [];
|
|
14834
|
-
for (const [id, session] of
|
|
15340
|
+
for (const [id, session] of sessions2) {
|
|
14835
15341
|
result.push({
|
|
14836
15342
|
sessionId: id,
|
|
14837
15343
|
historyCount: session.history.length,
|
|
@@ -14841,20 +15347,20 @@ function listSessions() {
|
|
|
14841
15347
|
}
|
|
14842
15348
|
return result;
|
|
14843
15349
|
}
|
|
14844
|
-
function
|
|
14845
|
-
const session =
|
|
15350
|
+
function closeSession2(id) {
|
|
15351
|
+
const session = sessions2.get(id);
|
|
14846
15352
|
if (!session) return false;
|
|
14847
|
-
|
|
15353
|
+
sessions2.delete(id);
|
|
14848
15354
|
return true;
|
|
14849
15355
|
}
|
|
14850
|
-
var
|
|
15356
|
+
var sessions2, MAX_SESSIONS3, SESSION_TTL, CLEANUP_INTERVAL3, cleanupTimer2, SETQ_RE, ReplSession;
|
|
14851
15357
|
var init_repl_engine = __esm({
|
|
14852
15358
|
"src/repl-engine.js"() {
|
|
14853
15359
|
init_cad();
|
|
14854
15360
|
init_logger();
|
|
14855
15361
|
init_lint_analyzer();
|
|
14856
|
-
|
|
14857
|
-
|
|
15362
|
+
sessions2 = /* @__PURE__ */ new Map();
|
|
15363
|
+
MAX_SESSIONS3 = 50;
|
|
14858
15364
|
SESSION_TTL = 30 * 60 * 1e3;
|
|
14859
15365
|
CLEANUP_INTERVAL3 = 5 * 60 * 1e3;
|
|
14860
15366
|
cleanupTimer2 = null;
|
|
@@ -15323,7 +15829,7 @@ function registerTool(toolDef, handler) {
|
|
|
15323
15829
|
}
|
|
15324
15830
|
customTools.push(toolDef);
|
|
15325
15831
|
customHandlers.set(toolDef.name, handler);
|
|
15326
|
-
|
|
15832
|
+
tools42.push(toolDef);
|
|
15327
15833
|
return true;
|
|
15328
15834
|
}
|
|
15329
15835
|
function callCustomTool(name, args) {
|
|
@@ -15841,10 +16347,10 @@ ${CAD_PLATFORMS.join("\n")}
|
|
|
15841
16347
|
return { content: [{ type: "text", text: JSON.stringify(history) }] };
|
|
15842
16348
|
},
|
|
15843
16349
|
lisp_repl_list: () => {
|
|
15844
|
-
return { content: [{ type: "text", text: JSON.stringify(
|
|
16350
|
+
return { content: [{ type: "text", text: JSON.stringify(listSessions2()) }] };
|
|
15845
16351
|
},
|
|
15846
16352
|
lisp_repl_close: (a) => {
|
|
15847
|
-
const ok =
|
|
16353
|
+
const ok = closeSession2(a.sessionId);
|
|
15848
16354
|
return { content: [{ type: "text", text: JSON.stringify({ success: ok }) }] };
|
|
15849
16355
|
},
|
|
15850
16356
|
// === Streaming ===
|
|
@@ -15916,6 +16422,12 @@ ${CAD_PLATFORMS.join("\n")}
|
|
|
15916
16422
|
return { content: [{ type: "text", text: `\u9879\u76EE\u5206\u6790\u5931\u8D25: ${e.message}` }], isError: true };
|
|
15917
16423
|
}
|
|
15918
16424
|
},
|
|
16425
|
+
// === Debug ===
|
|
16426
|
+
debug_start: lazy("debug_start", (a) => a),
|
|
16427
|
+
debug_step: lazy("debug_step", (a) => a),
|
|
16428
|
+
debug_evaluate: lazy("debug_evaluate", (a) => a),
|
|
16429
|
+
debug_get_state: lazy("debug_get_state", (a) => a),
|
|
16430
|
+
debug_stop: lazy("debug_stop", (a) => a),
|
|
15919
16431
|
// === Sandbox (Security) ===
|
|
15920
16432
|
sandbox_validate: (a) => {
|
|
15921
16433
|
const result = validateLispCode(a.code, a.sessionId || null);
|
|
@@ -16009,14 +16521,14 @@ ${CAD_PLATFORMS.join("\n")}
|
|
|
16009
16521
|
// === Meta Tools ===
|
|
16010
16522
|
search_tools: async (a) => {
|
|
16011
16523
|
const q = (a.query || "").toLowerCase();
|
|
16012
|
-
const results =
|
|
16524
|
+
const results = tools42.filter((t) => t.name.toLowerCase().includes(q) || (t.description || "").toLowerCase().includes(q));
|
|
16013
16525
|
const text = results.length ? `\u627E\u5230 ${results.length} \u4E2A\u5DE5\u5177:
|
|
16014
16526
|
${results.map((t) => `${t.name}: ${t.description}`).join("\n")}` : `\u672A\u627E\u5230\u5305\u542B "${a.query}" \u7684\u5DE5\u5177`;
|
|
16015
16527
|
return { content: [{ type: "text", text }] };
|
|
16016
16528
|
},
|
|
16017
16529
|
list_tools_by_category: async (a) => {
|
|
16018
16530
|
const categories = {};
|
|
16019
|
-
for (const t of
|
|
16531
|
+
for (const t of tools42) {
|
|
16020
16532
|
let cat = "\u5176\u4ED6";
|
|
16021
16533
|
const n = t.name;
|
|
16022
16534
|
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";
|
|
@@ -16352,7 +16864,7 @@ var init_mcp_server_state = __esm({
|
|
|
16352
16864
|
progressContext = new AsyncLocalStorage();
|
|
16353
16865
|
sessionServers = /* @__PURE__ */ new Map();
|
|
16354
16866
|
sessionTransports = /* @__PURE__ */ new Map();
|
|
16355
|
-
mcpHandlers = { tools:
|
|
16867
|
+
mcpHandlers = { tools: tools42, handleToolCall };
|
|
16356
16868
|
_stdioServer = null;
|
|
16357
16869
|
_pendingResourceUpdated = /* @__PURE__ */ new Set();
|
|
16358
16870
|
_resourceUpdatedTimer = null;
|
|
@@ -16576,7 +17088,7 @@ function propertyPairsToObject(pairs) {
|
|
|
16576
17088
|
}
|
|
16577
17089
|
return obj;
|
|
16578
17090
|
}
|
|
16579
|
-
async function
|
|
17091
|
+
async function ensureCad2() {
|
|
16580
17092
|
if (!cad.connected) await cad.connect();
|
|
16581
17093
|
if (!cad.connected) throw createError(ERROR_CODES.CAD_NOT_CONNECTED);
|
|
16582
17094
|
}
|
|
@@ -16744,7 +17256,7 @@ function parseTableRecord(rec, tableName) {
|
|
|
16744
17256
|
return obj.name ? obj : null;
|
|
16745
17257
|
}
|
|
16746
17258
|
async function getEntityByHandle(handle) {
|
|
16747
|
-
await
|
|
17259
|
+
await ensureCad2();
|
|
16748
17260
|
const code = `(progn
|
|
16749
17261
|
(vl-load-com)
|
|
16750
17262
|
(if (setq ent (handent "${escapeLispString(handle)}"))
|
|
@@ -16854,7 +17366,7 @@ async function getEntities(params = {}) {
|
|
|
16854
17366
|
const cacheKey = `dwg:entities:${JSON.stringify(params)}`;
|
|
16855
17367
|
const cached = getCached(cacheKey);
|
|
16856
17368
|
if (cached) return cached;
|
|
16857
|
-
await
|
|
17369
|
+
await ensureCad2();
|
|
16858
17370
|
const hasFilter = params.type || params.layer || params.bbox;
|
|
16859
17371
|
if (!hasFilter) {
|
|
16860
17372
|
return await getEntitiesSummary(cacheKey);
|
|
@@ -16890,7 +17402,7 @@ async function getTextContent(params = {}) {
|
|
|
16890
17402
|
const cacheKey = `dwg:text-content:${JSON.stringify(params)}`;
|
|
16891
17403
|
const cached = getCached(cacheKey);
|
|
16892
17404
|
if (cached) return cached;
|
|
16893
|
-
await
|
|
17405
|
+
await ensureCad2();
|
|
16894
17406
|
const offset = Math.max(0, parseInt(params.offset) || 0);
|
|
16895
17407
|
const limit = Math.min(Math.max(1, parseInt(params.limit) || 5e3), 5e3);
|
|
16896
17408
|
try {
|
|
@@ -17040,7 +17552,7 @@ async function combineText(params = {}) {
|
|
|
17040
17552
|
return { total: blocks.length, blocks, medianHeight: mh };
|
|
17041
17553
|
}
|
|
17042
17554
|
async function getDwgName() {
|
|
17043
|
-
await
|
|
17555
|
+
await ensureCad2();
|
|
17044
17556
|
try {
|
|
17045
17557
|
const code = `(vl-princ-to-string (getvar "dwgname"))`;
|
|
17046
17558
|
const name = await cad.sendCommandWithResult(code);
|
|
@@ -17050,7 +17562,7 @@ async function getDwgName() {
|
|
|
17050
17562
|
}
|
|
17051
17563
|
}
|
|
17052
17564
|
async function getDwgPath() {
|
|
17053
|
-
await
|
|
17565
|
+
await ensureCad2();
|
|
17054
17566
|
try {
|
|
17055
17567
|
const code = `(progn
|
|
17056
17568
|
(setq prefix (vl-princ-to-string (getvar "dwgprefix")))
|
|
@@ -17083,7 +17595,7 @@ async function getBlockRefs(params = {}) {
|
|
|
17083
17595
|
const cacheKey = `dwg:block-refs:${params.blockName || "all"}`;
|
|
17084
17596
|
const cached = getCached(cacheKey);
|
|
17085
17597
|
if (cached) return cached;
|
|
17086
|
-
await
|
|
17598
|
+
await ensureCad2();
|
|
17087
17599
|
try {
|
|
17088
17600
|
const code = buildBlockRefsCode(params.blockName);
|
|
17089
17601
|
const resultStr = await cad.sendCommandWithResult(code);
|
|
@@ -17145,7 +17657,7 @@ async function getTables(params = {}) {
|
|
|
17145
17657
|
const cacheKey = `dwg:tbl:${tblName}`;
|
|
17146
17658
|
const cached = getCached(cacheKey);
|
|
17147
17659
|
if (cached) return cached;
|
|
17148
|
-
await
|
|
17660
|
+
await ensureCad2();
|
|
17149
17661
|
try {
|
|
17150
17662
|
const code = buildTablesCode(tblName);
|
|
17151
17663
|
const resultStr = await cad.sendCommandWithResult(code);
|
|
@@ -17227,7 +17739,7 @@ async function getPackages(filterName = null) {
|
|
|
17227
17739
|
const cacheKey = filterName ? `packages:${filterName}` : "packages:all";
|
|
17228
17740
|
const cached = getCached(cacheKey);
|
|
17229
17741
|
if (cached) return cached;
|
|
17230
|
-
await
|
|
17742
|
+
await ensureCad2();
|
|
17231
17743
|
try {
|
|
17232
17744
|
const code = `(mapcar 'cdr @::*local-pkgs*)`;
|
|
17233
17745
|
const result = await cad.sendCommandWithResult(code);
|
|
@@ -17300,7 +17812,7 @@ async function getDwgList() {
|
|
|
17300
17812
|
const cacheKey = "cad:dwgs";
|
|
17301
17813
|
const cached = getCached(cacheKey);
|
|
17302
17814
|
if (cached) return cached;
|
|
17303
|
-
await
|
|
17815
|
+
await ensureCad2();
|
|
17304
17816
|
try {
|
|
17305
17817
|
const code = `(progn
|
|
17306
17818
|
(vl-load-com)
|
|
@@ -17370,7 +17882,7 @@ function getCodingStandards() {
|
|
|
17370
17882
|
return data || { error: "\u7F16\u7801\u89C4\u8303\u6587\u4EF6\u52A0\u8F7D\u5931\u8D25" };
|
|
17371
17883
|
}
|
|
17372
17884
|
async function getCadEvents(params) {
|
|
17373
|
-
await
|
|
17885
|
+
await ensureCad2();
|
|
17374
17886
|
try {
|
|
17375
17887
|
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"))))`;
|
|
17376
17888
|
const result = await cad.sendCommandWithResult(code);
|
|
@@ -17804,7 +18316,7 @@ init_subscription_manager();
|
|
|
17804
18316
|
init_mcp_server_state();
|
|
17805
18317
|
init_sse_session();
|
|
17806
18318
|
import express from "express";
|
|
17807
|
-
import { randomUUID as
|
|
18319
|
+
import { randomUUID as randomUUID6, createHash } from "crypto";
|
|
17808
18320
|
import fs14 from "fs";
|
|
17809
18321
|
import path17 from "path";
|
|
17810
18322
|
import { fileURLToPath as fileURLToPath6 } from "url";
|
|
@@ -17992,7 +18504,7 @@ var cachedToolsJson = null;
|
|
|
17992
18504
|
var cachedToolsJsonAt = 0;
|
|
17993
18505
|
function getToolsJson() {
|
|
17994
18506
|
if (cachedToolsJson && Date.now() - cachedToolsJsonAt < 3e4) return cachedToolsJson;
|
|
17995
|
-
cachedToolsJson = JSON.stringify(
|
|
18507
|
+
cachedToolsJson = JSON.stringify(tools42.map((t) => ({
|
|
17996
18508
|
name: t.name,
|
|
17997
18509
|
description: t.description,
|
|
17998
18510
|
inputSchema: t.inputSchema
|
|
@@ -18161,7 +18673,7 @@ function setupRoutes(app) {
|
|
|
18161
18673
|
},
|
|
18162
18674
|
mcp: {
|
|
18163
18675
|
sessions: sessionServers.size,
|
|
18164
|
-
tools:
|
|
18676
|
+
tools: tools42.length,
|
|
18165
18677
|
sseSessions: sseCount
|
|
18166
18678
|
},
|
|
18167
18679
|
pool: {
|
|
@@ -18184,7 +18696,7 @@ function setupRoutes(app) {
|
|
|
18184
18696
|
timestamp: (/* @__PURE__ */ new Date()).toISOString(),
|
|
18185
18697
|
cad: { connected: cad.connected, platform: cad.getPlatform?.(), version: cad.getVersion?.(), commandQueueSize: cad._getQueueSize ? cad._getQueueSize() : 0, restartCount: cad._getRestartCount ? cad._getRestartCount() : 0 },
|
|
18186
18698
|
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() },
|
|
18187
|
-
mcp: { sessions: sessionServers.size, tools:
|
|
18699
|
+
mcp: { sessions: sessionServers.size, tools: tools42.length, sseSessions: sseCount },
|
|
18188
18700
|
pool: poolStats
|
|
18189
18701
|
});
|
|
18190
18702
|
});
|
|
@@ -18222,7 +18734,7 @@ function setupRoutes(app) {
|
|
|
18222
18734
|
app.get("/api/docs", (req, res) => {
|
|
18223
18735
|
const html = loadHtml("api-docs", {
|
|
18224
18736
|
VERSION: SERVER_VERSION,
|
|
18225
|
-
TOOLS_COUNT:
|
|
18737
|
+
TOOLS_COUNT: tools42.length
|
|
18226
18738
|
});
|
|
18227
18739
|
res.setHeader("Content-Type", "text/html; charset=utf-8");
|
|
18228
18740
|
res.send(html);
|
|
@@ -18243,7 +18755,7 @@ function setupRoutes(app) {
|
|
|
18243
18755
|
SESSIONS_COUNT: sessionServers.size,
|
|
18244
18756
|
CAD_STATUS_CLASS: cadConnected ? "status-ok" : "status-error",
|
|
18245
18757
|
CAD_STATUS_TEXT: cadStatusText,
|
|
18246
|
-
TOOLS_COUNT:
|
|
18758
|
+
TOOLS_COUNT: tools42.length
|
|
18247
18759
|
});
|
|
18248
18760
|
res.setHeader("Content-Type", "text/html; charset=utf-8");
|
|
18249
18761
|
res.send(html);
|
|
@@ -18261,7 +18773,7 @@ function setupRoutes(app) {
|
|
|
18261
18773
|
app.get("/sse", mcpLimiter, handleSse);
|
|
18262
18774
|
app.post("/message", mcpLimiter, handleMessage);
|
|
18263
18775
|
app.get("/cad/events", (req, res) => {
|
|
18264
|
-
const sessionId =
|
|
18776
|
+
const sessionId = randomUUID6();
|
|
18265
18777
|
subscribeEvents(sessionId, res);
|
|
18266
18778
|
req.on("close", () => {
|
|
18267
18779
|
unsubscribeEvents(sessionId);
|
|
@@ -18271,7 +18783,7 @@ function setupRoutes(app) {
|
|
|
18271
18783
|
return app;
|
|
18272
18784
|
}
|
|
18273
18785
|
async function handleMcpPost(req, res) {
|
|
18274
|
-
const sessionId = req.headers["mcp-session-id"] || req.query.sessionId ||
|
|
18786
|
+
const sessionId = req.headers["mcp-session-id"] || req.query.sessionId || randomUUID6();
|
|
18275
18787
|
sessionManager.createSession(sessionId);
|
|
18276
18788
|
const body = req.body;
|
|
18277
18789
|
if (!body) {
|
|
@@ -18339,7 +18851,7 @@ async function getMcpResponse(sessionId, body) {
|
|
|
18339
18851
|
}
|
|
18340
18852
|
async function handleSse(req, res) {
|
|
18341
18853
|
const lastEventId = parseLastEventId(req);
|
|
18342
|
-
let sessionId =
|
|
18854
|
+
let sessionId = randomUUID6();
|
|
18343
18855
|
let resumeMessages = [];
|
|
18344
18856
|
if (lastEventId !== null) {
|
|
18345
18857
|
const existingSession = sessionManager.get(sessionId);
|
|
@@ -18405,7 +18917,7 @@ init_cad();
|
|
|
18405
18917
|
init_constants();
|
|
18406
18918
|
init_tools();
|
|
18407
18919
|
init_subscription_manager();
|
|
18408
|
-
import { randomUUID as
|
|
18920
|
+
import { randomUUID as randomUUID7 } from "crypto";
|
|
18409
18921
|
import { WebSocketServer } from "ws";
|
|
18410
18922
|
var PING_INTERVAL = 3e4;
|
|
18411
18923
|
var CAD_POLL_INTERVAL = 5e3;
|
|
@@ -18435,7 +18947,7 @@ function sendWelcome(ws, clientId) {
|
|
|
18435
18947
|
server: { name: SERVER_NAME, version: SERVER_VERSION },
|
|
18436
18948
|
capabilities: SERVER_CAPABILITIES,
|
|
18437
18949
|
clientId,
|
|
18438
|
-
toolCount:
|
|
18950
|
+
toolCount: tools42.length,
|
|
18439
18951
|
cadConnected: cad.connected,
|
|
18440
18952
|
cadPlatform: cad.connected ? cad.getPlatform() : null,
|
|
18441
18953
|
cadVersion: cad.connected ? cad.getVersion() : null
|
|
@@ -18602,7 +19114,7 @@ function createWebSocketServer(httpServer) {
|
|
|
18602
19114
|
startCadPolling();
|
|
18603
19115
|
_wss = new WebSocketServer({ server: httpServer, path: "/ws" });
|
|
18604
19116
|
_wss.on("connection", (ws, req) => {
|
|
18605
|
-
const clientId =
|
|
19117
|
+
const clientId = randomUUID7();
|
|
18606
19118
|
connectedClients.set(clientId, ws);
|
|
18607
19119
|
log(`WebSocket connected: ${clientId} (${connectedClients.size} total) from ${req.socket.remoteAddress}`);
|
|
18608
19120
|
sendWelcome(ws, clientId);
|
|
@@ -18809,14 +19321,14 @@ init_logger();
|
|
|
18809
19321
|
init_mcp_handlers();
|
|
18810
19322
|
init_mcp_tools();
|
|
18811
19323
|
import { StreamableHTTPServerTransport as StreamableHTTPServerTransport2 } from "@modelcontextprotocol/sdk/server/streamableHttp.js";
|
|
18812
|
-
import { randomUUID as
|
|
19324
|
+
import { randomUUID as randomUUID8 } from "crypto";
|
|
18813
19325
|
var mcpServer = null;
|
|
18814
19326
|
var streamableTransport = null;
|
|
18815
19327
|
async function initStreamableHttpServer() {
|
|
18816
19328
|
if (mcpServer) return;
|
|
18817
|
-
mcpServer = createMcpServer({ tools:
|
|
19329
|
+
mcpServer = createMcpServer({ tools: tools42, handleToolCall });
|
|
18818
19330
|
streamableTransport = new StreamableHTTPServerTransport2({
|
|
18819
|
-
sessionIdGenerator: () =>
|
|
19331
|
+
sessionIdGenerator: () => randomUUID8()
|
|
18820
19332
|
});
|
|
18821
19333
|
await mcpServer.connect(streamableTransport);
|
|
18822
19334
|
streamableTransport.onerror = (err) => error(`Streamable HTTP transport error: ${err.message}`);
|
|
@@ -18883,51 +19395,65 @@ if (isMcpScript) {
|
|
|
18883
19395
|
Usage: atlisp-mcp [options]
|
|
18884
19396
|
|
|
18885
19397
|
Options:
|
|
18886
|
-
-v, --version
|
|
18887
|
-
-h, --help
|
|
18888
|
-
|
|
18889
|
-
--
|
|
18890
|
-
--
|
|
18891
|
-
|
|
18892
|
-
|
|
18893
|
-
|
|
18894
|
-
|
|
18895
|
-
|
|
18896
|
-
|
|
18897
|
-
|
|
18898
|
-
|
|
18899
|
-
|
|
18900
|
-
|
|
18901
|
-
|
|
19398
|
+
-v, --version Show version number
|
|
19399
|
+
-h, --help Show this help message
|
|
19400
|
+
--transport <type> Transport: http, stdio, ws (default: http)
|
|
19401
|
+
--stdio Shorthand for --transport stdio
|
|
19402
|
+
--ws Shorthand for --transport ws
|
|
19403
|
+
--port <port> HTTP port (default: 8110)
|
|
19404
|
+
--host <host> HTTP host (default: 0.0.0.0)
|
|
19405
|
+
--config <path> Path to config file (default: ~/.atlisp/atlisp.config.json)
|
|
19406
|
+
--ssl-key <path> SSL key file path (enables HTTPS)
|
|
19407
|
+
--ssl-cert <path> SSL certificate file path
|
|
19408
|
+
--debug Enable debug mode
|
|
19409
|
+
--metrics-enabled Enable /metrics endpoint (true/false)
|
|
19410
|
+
--lint-preset <type> Lint preset: recommended, strict, relaxed
|
|
19411
|
+
--lint-config <path> Path to atlisp-lint.json config file
|
|
19412
|
+
--lint-level <level> Lint level: error, warn, off
|
|
19413
|
+
--no-lint Disable lint pre-check for eval_lisp
|
|
19414
|
+
--lint-off Same as --no-lint
|
|
19415
|
+
--api-key <key> API key for authentication
|
|
19416
|
+
--security-level <type> Security level: strict, standard, relaxed (default: strict)
|
|
18902
19417
|
|
|
18903
19418
|
Environment Variables:
|
|
18904
|
-
|
|
18905
|
-
|
|
18906
|
-
|
|
18907
|
-
|
|
18908
|
-
|
|
18909
|
-
|
|
18910
|
-
|
|
18911
|
-
|
|
18912
|
-
|
|
19419
|
+
TRANSPORT Transport mode (http/stdio/ws)
|
|
19420
|
+
PORT HTTP port (default: 8110)
|
|
19421
|
+
HOST HTTP host (default: 0.0.0.0)
|
|
19422
|
+
MCP_API_KEY API key for authentication
|
|
19423
|
+
ENABLE_SSE Enable SSE (true/false, default: true)
|
|
19424
|
+
DEBUG Enable debug logging (true/false)
|
|
19425
|
+
DEBUG_FILE Debug log file path
|
|
19426
|
+
METRICS_ENABLED Enable /metrics endpoint (true/false, default: true)
|
|
19427
|
+
SSL_KEY_PATH SSL key file path
|
|
19428
|
+
SSL_CERT_PATH SSL certificate file path
|
|
19429
|
+
SECURITY_LEVEL Security level: strict, standard, relaxed (default: strict)
|
|
19430
|
+
CONFIG_FILE Path to config file
|
|
19431
|
+
LINT_PRESET Lint preset (recommended/strict/relaxed)
|
|
19432
|
+
LINT_CONFIG_PATH Path to atlisp-lint.json
|
|
19433
|
+
LINT_LEVEL Lint level (error/warn/off)
|
|
19434
|
+
NO_LINT Disable lint (true/false)
|
|
19435
|
+
REQUEST_LOG_ENABLED Enable request logging (true/false, default: true)
|
|
19436
|
+
CORS_ORIGIN CORS origin (default: *)
|
|
19437
|
+
RATE_LIMIT_WINDOW Rate limit window in ms (default: 60000)
|
|
19438
|
+
RATE_LIMIT_MAX Max requests per window (default: 100)
|
|
18913
19439
|
|
|
18914
19440
|
Examples:
|
|
18915
|
-
atlisp-mcp
|
|
18916
|
-
atlisp-mcp --port 3000
|
|
18917
|
-
atlisp-mcp --stdio
|
|
18918
|
-
atlisp-mcp --config ~/my.json
|
|
18919
|
-
atlisp-mcp --debug
|
|
18920
|
-
|
|
18921
|
-
atlisp-mcp
|
|
18922
|
-
TRANSPORT=ws atlisp-mcp
|
|
19441
|
+
atlisp-mcp Start HTTP server on port 8110
|
|
19442
|
+
atlisp-mcp --port 3000 Start HTTP server on port 3000
|
|
19443
|
+
atlisp-mcp --stdio Start in stdio mode for MCP clients
|
|
19444
|
+
atlisp-mcp --config ~/my.json Use custom config file
|
|
19445
|
+
atlisp-mcp --debug Enable debug output
|
|
19446
|
+
atlisp-mcp --ssl-key key.pem --ssl-cert cert.pem Start HTTPS server
|
|
19447
|
+
TRANSPORT=stdio atlisp-mcp Via env var for stdio mode
|
|
19448
|
+
TRANSPORT=ws atlisp-mcp Via env var for WebSocket mode
|
|
18923
19449
|
|
|
18924
19450
|
API Endpoints:
|
|
18925
|
-
GET /health
|
|
18926
|
-
GET /metrics
|
|
18927
|
-
POST /mcp
|
|
18928
|
-
GET /sse
|
|
18929
|
-
POST /message
|
|
18930
|
-
WS /ws
|
|
19451
|
+
GET /health Health check
|
|
19452
|
+
GET /metrics Prometheus metrics (if enabled)
|
|
19453
|
+
POST /mcp MCP JSON-RPC endpoint
|
|
19454
|
+
GET /sse Server-Sent Events endpoint
|
|
19455
|
+
POST /message SSE message endpoint
|
|
19456
|
+
WS /ws WebSocket endpoint
|
|
18931
19457
|
POST /config/reload Reload configuration
|
|
18932
19458
|
|
|
18933
19459
|
For more info: https://atlisp.cn
|
|
@@ -18955,6 +19481,16 @@ For more info: https://atlisp.cn
|
|
|
18955
19481
|
process.env.LINT_LEVEL = cliArgs2[++i];
|
|
18956
19482
|
} else if (arg === "--no-lint" || arg === "--lint-off") {
|
|
18957
19483
|
process.env.NO_LINT = "true";
|
|
19484
|
+
} else if (arg === "--security-level" && cliArgs2[i + 1]) {
|
|
19485
|
+
process.env.SECURITY_LEVEL = cliArgs2[++i];
|
|
19486
|
+
} else if (arg === "--ssl-key" && cliArgs2[i + 1]) {
|
|
19487
|
+
process.env.SSL_KEY_PATH = cliArgs2[++i];
|
|
19488
|
+
} else if (arg === "--ssl-cert" && cliArgs2[i + 1]) {
|
|
19489
|
+
process.env.SSL_CERT_PATH = cliArgs2[++i];
|
|
19490
|
+
} else if (arg === "--api-key" && cliArgs2[i + 1]) {
|
|
19491
|
+
process.env.MCP_API_KEY = cliArgs2[++i];
|
|
19492
|
+
} else if (arg === "--metrics-enabled" && cliArgs2[i + 1]) {
|
|
19493
|
+
process.env.METRICS_ENABLED = cliArgs2[++i];
|
|
18958
19494
|
}
|
|
18959
19495
|
}
|
|
18960
19496
|
}
|
|
@@ -18975,7 +19511,7 @@ async function initCadConnection() {
|
|
|
18975
19511
|
}
|
|
18976
19512
|
async function startServer() {
|
|
18977
19513
|
await loadPlugins();
|
|
18978
|
-
initPlugins({ cad, config: config_default, log, registerTool, tools:
|
|
19514
|
+
initPlugins({ cad, config: config_default, log, registerTool, tools: tools42 });
|
|
18979
19515
|
onPluginChange((type, name) => {
|
|
18980
19516
|
log(`Plugin changed: ${type} ${name}`);
|
|
18981
19517
|
broadcastToolListChanged();
|
|
@@ -18999,7 +19535,7 @@ async function startServer() {
|
|
|
18999
19535
|
}
|
|
19000
19536
|
if (config_default.transport === "stdio") {
|
|
19001
19537
|
await initCadConnection();
|
|
19002
|
-
const mcpServer2 = createStdioServer({ tools:
|
|
19538
|
+
const mcpServer2 = createStdioServer({ tools: tools42, handleToolCall });
|
|
19003
19539
|
const transport = new StdioServerTransport();
|
|
19004
19540
|
const sessionId = "stdio-session";
|
|
19005
19541
|
sessionManager.createSession(sessionId);
|
|
@@ -19100,5 +19636,5 @@ export {
|
|
|
19100
19636
|
handleToolCall,
|
|
19101
19637
|
loadAtlibFunctionLib,
|
|
19102
19638
|
startServer,
|
|
19103
|
-
|
|
19639
|
+
tools42 as tools
|
|
19104
19640
|
};
|