@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.
@@ -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, tools41, toolsByName;
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
- tools41 = [
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(tools41.map((t) => [t.name, t]));
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: tools42 = [], handleToolCall: handleToolCall2 = () => ({ content: [] }) } = handlers;
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 = tools42.slice(cursor, cursor + PAGE_SIZE);
6692
- const nextCursor = cursor + PAGE_SIZE < tools42.length ? encodeCursor(cursor + PAGE_SIZE) : void 0;
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 tools42) {
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 = tools42.find((t) => t.name === ref.name);
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 config2 = options.lintConfig ? mergeConfig(getDefaultConfig(), options.lintConfig) : getDefaultConfig();
8165
- const lintIssues = runChecks(code, options.file || "<eval>", config2);
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: rule.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, severity: THREAT_BLOCK, msg: "\u7981\u6B62\u4F7F\u7528 startapp \u51FD\u6570" },
14727
- { re: /\bvl-bt\b/i, severity: THREAT_BLOCK, msg: "\u7981\u6B62\u4F7F\u7528 vl-bt \u51FD\u6570" },
14728
- { re: /\bvlax-import-type-library\b/i, severity: THREAT_BLOCK, msg: "\u7981\u6B62\u5BFC\u5165\u7C7B\u578B\u5E93" },
14729
- { re: /\bdos_command_string\s*[(\s]/i, severity: THREAT_BLOCK, msg: "\u7981\u6B62\u4F7F\u7528 dos_command_string" }
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: rule.severity,
15263
+ severity,
14759
15264
  message: rule.msg,
14760
- blocked: !isAllowed && rule.severity === THREAT_BLOCK,
14761
- warned: !isAllowed && rule.severity === THREAT_WARN,
14762
- allowed: isAllowed
15265
+ blocked: severity === THREAT_BLOCK,
15266
+ warned: severity === THREAT_WARN,
15267
+ allowed: severity === THREAT_ALLOW
14763
15268
  });
14764
- if (!isAllowed && rule.severity === THREAT_BLOCK) {
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 randomUUID4 } from "crypto";
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 sessions) {
15298
+ for (const [id, session] of sessions2) {
14793
15299
  if (now - session.createdAt > SESSION_TTL) {
14794
- sessions.delete(id);
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 createSession() {
14802
- if (sessions.size >= MAX_SESSIONS2) {
15307
+ function createSession2() {
15308
+ if (sessions2.size >= MAX_SESSIONS3) {
14803
15309
  let oldest = null;
14804
- for (const [id, s] of sessions) {
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
- sessions.delete(oldest.id);
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 = randomUUID4();
15319
+ const sessionId = randomUUID5();
14814
15320
  const session = new ReplSession(sessionId);
14815
- sessions.set(sessionId, session);
15321
+ sessions2.set(sessionId, session);
14816
15322
  return sessionId;
14817
15323
  }
14818
15324
  async function executeInSession(sessionId, code) {
14819
- let session = sessions.get(sessionId);
15325
+ let session = sessions2.get(sessionId);
14820
15326
  if (!session) {
14821
- sessionId = createSession();
14822
- session = sessions.get(sessionId);
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 = sessions.get(sessionId);
15334
+ const session = sessions2.get(sessionId);
14829
15335
  if (!session) return null;
14830
15336
  return session.history;
14831
15337
  }
14832
- function listSessions() {
15338
+ function listSessions2() {
14833
15339
  const result = [];
14834
- for (const [id, session] of sessions) {
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 closeSession(id) {
14845
- const session = sessions.get(id);
15350
+ function closeSession2(id) {
15351
+ const session = sessions2.get(id);
14846
15352
  if (!session) return false;
14847
- sessions.delete(id);
15353
+ sessions2.delete(id);
14848
15354
  return true;
14849
15355
  }
14850
- var sessions, MAX_SESSIONS2, SESSION_TTL, CLEANUP_INTERVAL3, cleanupTimer2, SETQ_RE, ReplSession;
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
- sessions = /* @__PURE__ */ new Map();
14857
- MAX_SESSIONS2 = 50;
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
- tools41.push(toolDef);
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(listSessions()) }] };
16350
+ return { content: [{ type: "text", text: JSON.stringify(listSessions2()) }] };
15845
16351
  },
15846
16352
  lisp_repl_close: (a) => {
15847
- const ok = closeSession(a.sessionId);
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 = tools41.filter((t) => t.name.toLowerCase().includes(q) || (t.description || "").toLowerCase().includes(q));
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 tools41) {
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: tools41, handleToolCall };
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 ensureCad() {
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 ensureCad();
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 ensureCad();
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 ensureCad();
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 ensureCad();
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 ensureCad();
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 ensureCad();
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 ensureCad();
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 ensureCad();
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 ensureCad();
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 ensureCad();
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 randomUUID5, createHash } from "crypto";
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(tools41.map((t) => ({
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: tools41.length,
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: tools41.length, sseSessions: sseCount },
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: tools41.length
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: tools41.length
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 = randomUUID5();
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 || randomUUID5();
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 = randomUUID5();
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 randomUUID6 } from "crypto";
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: tools41.length,
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 = randomUUID6();
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 randomUUID7 } from "crypto";
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: tools41, handleToolCall });
19329
+ mcpServer = createMcpServer({ tools: tools42, handleToolCall });
18818
19330
  streamableTransport = new StreamableHTTPServerTransport2({
18819
- sessionIdGenerator: () => randomUUID7()
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 Show version number
18887
- -h, --help Show this help message
18888
- --transport <type> Transport: http, stdio, or ws (default: http)
18889
- --port <port> HTTP port (default: 8110)
18890
- --host <host> HTTP host (default: 0.0.0.0)
18891
- --stdio Shorthand for --transport stdio
18892
- --ws Shorthand for --transport ws
18893
- --config <path> Path to config file (default: ~/.atlisp/atlisp.config.json)
18894
- --ssl-key <path> SSL key file path (enables HTTPS)
18895
- --ssl-cert <path> SSL certificate file path
18896
- --debug Enable debug mode
18897
- --lint-preset <type> Lint preset: recommended, strict, or relaxed
18898
- --lint-config <path> Path to atlisp-lint.json config file
18899
- --lint-level <level> Lint level: error, warn, or off
18900
- --no-lint Disable lint pre-check for eval_lisp
18901
- --lint-off Same as --no-lint
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
- TRANSPORT Transport mode (http/stdio/ws)
18905
- PORT HTTP port
18906
- HOST HTTP host
18907
- MCP_API_KEY API key for authentication
18908
- ENABLE_SSE Enable SSE (true/false)
18909
- DEBUG Enable debug logging (true/false)
18910
- METRICS_ENABLED Enable /metrics endpoint (true/false)
18911
- SSL_KEY_PATH SSL key file path
18912
- SSL_CERT_PATH SSL certificate file path
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 Start HTTP server on port 8110
18916
- atlisp-mcp --port 3000 Start HTTP server on port 3000
18917
- atlisp-mcp --stdio Start in stdio mode for MCP clients
18918
- atlisp-mcp --config ~/my.json Use custom config file
18919
- atlisp-mcp --debug Enable debug output
18920
- TRANSPORT=stdio atlisp-mcp Via env var for stdio mode
18921
- atlisp-mcp --ws Start WebSocket server on port 8110
18922
- TRANSPORT=ws atlisp-mcp Via env var for WebSocket mode
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 Health check
18926
- GET /metrics Prometheus metrics (if enabled)
18927
- POST /mcp MCP JSON-RPC endpoint
18928
- GET /sse Server-Sent Events endpoint
18929
- POST /message SSE message endpoint
18930
- WS /ws WebSocket endpoint
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: tools41 });
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: tools41, handleToolCall });
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
- tools41 as tools
19639
+ tools42 as tools
19104
19640
  };