@atlisp/mcp 1.6.8 → 1.6.10

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.
@@ -138,7 +138,7 @@ if (!envResult.success) {
138
138
  process.exit(1);
139
139
  }
140
140
  var env = envResult.data;
141
- var configFilePath = env.CONFIG_FILE || cliArgs.configFile || path.join(os.homedir(), "@lisp", "atlisp.config.json");
141
+ var configFilePath = env.CONFIG_FILE || cliArgs.configFile || path.join(os.homedir(), ".atlisp", "atlisp.config.json");
142
142
  var fileConfig = loadConfigFile(configFilePath);
143
143
  var config = {
144
144
  port: fileConfig?.port || parseInt(env.PORT || cliArgs.port, 10),
@@ -905,56 +905,14 @@ ${ENTITY_PROPERTIES_LISP}
905
905
  @e:i (1+ @e:i)))
906
906
  (vl-prin1-to-string (list @e:total (reverse @e:ents))))`;
907
907
  }
908
- function buildTextCode({ layer, bbox, offset, limit }) {
909
- const items = [`'(0 . "TEXT,MTEXT,ATTRIB,TCH_TEXT")`];
910
- if (layer)
911
- items.push(`(cons 8 "${layer.replace(/"/g, '\\"')}")`);
912
- if (bbox) {
913
- const parts = bbox.split(",").map((s) => parseFloat(s.trim()));
914
- if (parts.length === 4) {
915
- const [x1, y1, x2, y2] = parts;
916
- items.push(
917
- `'(-4 . "<AND")`,
918
- `'(-4 . ">=,>=,*") (list 10 ${x1} ${y1} 0.0)`,
919
- `'(-4 . "<=,<=,*") (list 10 ${x2} ${y2} 0.0)`,
920
- `'(-4 . "AND>")`
921
- );
922
- }
923
- }
924
- const filterExpr = `(list ${items.join(" ")})`;
925
- return `(progn
926
- (defun @t:props (ent / ed ins)
927
- (setq ed (entget ent) ins (cdr (assoc 10 ed)))
928
- (list
929
- (list "type" (vl-prin1-to-string (cdr (assoc 0 ed))))
930
- (list "handle" (vl-prin1-to-string (cdr (assoc 5 ed))))
931
- (list "layer" (vl-prin1-to-string (cdr (assoc 8 ed))))
932
- (list "color" (if (assoc 62 ed) (cdr (assoc 62 ed)) 256))
933
- (list "linetype" (vl-prin1-to-string (if (assoc 6 ed) (cdr (assoc 6 ed)) "ByLayer")))
934
- (list "text" (vl-prin1-to-string (cdr (assoc 1 ed))))
935
- (list "insert" (list (car ins) (cadr ins) (caddr ins)))
936
- (list "height" (cdr (assoc 40 ed)))
937
- (list "rotation" (cdr (assoc 50 ed)))
938
- (list "style" (vl-prin1-to-string (if (assoc 7 ed) (cdr (assoc 7 ed)) "Standard")))))
939
- (defun @t:run nil
940
- (setq ss (ssget "_X" ${filterExpr}))
941
- (if (null ss)
942
- (list "total" 0 "offset" ${offset} "limit" ${limit})
943
- (progn
944
- (setq total (sslength ss) texts nil i ${offset})
945
- (while (and (< i total) (< (length texts) ${limit}))
946
- (setq texts (append texts (list (@t:props (ssname ss i)))) i (1+ i)))
947
- (list "total" total "offset" ${offset} "limit" ${limit} "texts" texts))))
948
- (@t:run))
949
- `;
950
- }
951
908
  var RESOURCES = [
952
909
  { uri: "atlisp://cad/info", name: "CAD Info", description: "CAD \u8FDE\u63A5\u4FE1\u606F", mimeType: "application/json", subscribable: true },
953
- { uri: "atlisp://dwg/layers", name: "Layers", description: "\u56FE\u5C42\u5217\u8868", mimeType: "application/json", subscribable: true },
954
910
  { uri: "atlisp://dwg/entities", name: "Entities", description: "\u56FE\u5143\u5217\u8868\u3002\u65E0\u53C2\u6570\u65F6\u8FD4\u56DE\u603B\u6570\u548C\u6309\u7C7B\u578B\u7EDF\u8BA1\uFF1B\u6709\u53C2\u6570\u65F6\u8FD4\u56DE filtered \u56FE\u6587\u7684 entity:properties \u5168\u5C5E\u6027 JSON\uFF08ObjectName, Handle, Layer, Color, Center, Radius \u7B49\uFF09\uFF0C\u652F\u6301 ?type=LINE&layer=0&bbox=0,0,100,100", mimeType: "application/json", subscribable: true },
955
- { uri: "atlisp://dwg/texts", name: "Texts", description: "\u6587\u672C\u5B9E\u4F53 key:value \u5217\u8868 (TEXT/MTEXT/ATTRIB/TCH_TEXT)\uFF0C\u652F\u6301 ?layer=0&bbox=0,0,100,100&limit=5000&offset=0", mimeType: "application/json", subscribable: true },
911
+ { uri: "atlisp://dwg/text-content", name: "Text Content", description: "\u6587\u672C\u5185\u5BB9\u53CA\u4F4D\u7F6E\uFF0C\u7528\u4E8E\u8BED\u4E49\u5206\u6790\u3002\u652F\u6301 ?layer=0&bbox=0,0,100,100&limit=5000&offset=0", mimeType: "application/json", subscribable: true },
956
912
  { uri: "atlisp://dwg/name", name: "DWG Name", description: "\u5F53\u524D DWG \u6587\u4EF6\u540D", mimeType: "application/json", subscribable: true },
957
913
  { uri: "atlisp://dwg/path", name: "DWG Path", description: "\u6587\u4EF6\u5B8C\u6574\u8DEF\u5F84", mimeType: "application/json", subscribable: true },
914
+ { uri: "atlisp://dwg/block-refs", name: "Block References", description: "\u5757\u53C2\u7167\u5217\u8868\u53CA\u5C5E\u6027\u503C\u3001\u52A8\u6001\u5757\u7279\u6027\uFF0C\u652F\u6301\u8DEF\u5F84\u65B9\u5F0F atlisp://dwg/block-refs/{blockName}", mimeType: "application/json", subscribable: true },
915
+ { uri: "atlisp://dwg/tbl", name: "Tables", description: "CAD \u8868\u6570\u636E (layer, block, textstyle, dimstyle, linetype, ucs, view, viewport, regapp)\uFF0C\u652F\u6301\u8DEF\u5F84\u65B9\u5F0F atlisp://dwg/tbl/layer", mimeType: "application/json", subscribable: true },
958
916
  { uri: "atlisp://cad/dwgs", name: "DWG List", description: "\u6240\u6709\u6253\u5F00\u7684 DWG \u6587\u4EF6\u5217\u8868", mimeType: "application/json", subscribable: true },
959
917
  { uri: "atlisp://packages", name: "Packages", description: "\u5DF2\u5B89\u88C5\u5305\u5217\u8868", mimeType: "application/json", subscribable: true },
960
918
  { uri: "atlisp://platforms", name: "Platforms", description: "\u652F\u6301\u7684\u5E73\u53F0\u4FE1\u606F", mimeType: "application/json", subscribable: false },
@@ -977,9 +935,15 @@ function parseQuery(uri) {
977
935
  return { base, params };
978
936
  }
979
937
  function parseTemplateUri(uri) {
980
- const match = uri.match(/^atlisp:\/\/dwg\/entity\/([^?]+)$/);
981
- if (match)
982
- return { type: "entity", handle: match[1] };
938
+ const entityMatch = uri.match(/^atlisp:\/\/dwg\/entity\/([^?]+)$/);
939
+ if (entityMatch)
940
+ return { type: "entity", handle: entityMatch[1] };
941
+ const tblMatch = uri.match(/^atlisp:\/\/dwg\/tbl\/([^?]+)$/);
942
+ if (tblMatch)
943
+ return { type: "tbl", tblName: tblMatch[1] };
944
+ const blockRefMatch = uri.match(/^atlisp:\/\/dwg\/block-refs\/([^?]+)$/);
945
+ if (blockRefMatch)
946
+ return { type: "block-refs", blockName: blockRefMatch[1] };
983
947
  return null;
984
948
  }
985
949
  async function listResources(subscribedUris = []) {
@@ -993,23 +957,33 @@ async function listResources(subscribedUris = []) {
993
957
  }
994
958
  async function readResource(uri) {
995
959
  const templateMatch = parseTemplateUri(uri);
996
- if (templateMatch && templateMatch.type === "entity") {
997
- return await getEntityByHandle(templateMatch.handle);
960
+ if (templateMatch) {
961
+ if (templateMatch.type === "entity") {
962
+ return await getEntityByHandle(templateMatch.handle);
963
+ }
964
+ if (templateMatch.type === "tbl") {
965
+ return await getTables({ tbl: templateMatch.tblName });
966
+ }
967
+ if (templateMatch.type === "block-refs") {
968
+ return await getBlockRefs({ blockName: templateMatch.blockName });
969
+ }
998
970
  }
999
971
  const { base, params } = parseQuery(uri);
1000
972
  switch (base) {
1001
973
  case "atlisp://cad/info":
1002
974
  return await getCadInfo();
1003
- case "atlisp://dwg/layers":
1004
- return await getLayers(params.name);
1005
975
  case "atlisp://dwg/entities":
1006
976
  return await getEntities(params);
1007
- case "atlisp://dwg/texts":
1008
- return await getTexts(params);
977
+ case "atlisp://dwg/text-content":
978
+ return await getTextContent(params);
1009
979
  case "atlisp://dwg/name":
1010
980
  return await getDwgName();
1011
981
  case "atlisp://dwg/path":
1012
982
  return await getDwgPath();
983
+ case "atlisp://dwg/block-refs":
984
+ return await getBlockRefs(params);
985
+ case "atlisp://dwg/tbl":
986
+ return await getTables(params);
1013
987
  case "atlisp://cad/dwgs":
1014
988
  return await getDwgList();
1015
989
  case "atlisp://packages":
@@ -1086,58 +1060,6 @@ async function getCadInfo() {
1086
1060
  setCache("cad:info", result);
1087
1061
  return result;
1088
1062
  }
1089
- async function getLayers(filterName = null) {
1090
- const cacheKey = filterName ? `dwg:layers:${filterName}` : "dwg:layers:all";
1091
- const cached = getCached(cacheKey);
1092
- if (cached)
1093
- return cached;
1094
- if (!cad.connected)
1095
- await cad.connect();
1096
- if (!cad.connected)
1097
- return [];
1098
- try {
1099
- const code = filterName ? `(vl-prin1-to-string (cdr (assoc 2 (tblnext "LAYER" T))))` : `(progn (setq res nil)(while (setq e (tblnext "LAYER" (null res)))(setq res (cons (list (vl-prin1-to-string (cdr (assoc 2 e))) (cdr (assoc 62 e)) (cdr (assoc 70 e))) res))) (reverse res))`;
1100
- const result = await cad.sendCommandWithResult(code);
1101
- if (!result || result === "" || result === "nil") {
1102
- setCache(cacheKey, []);
1103
- return [];
1104
- }
1105
- let layers = [];
1106
- try {
1107
- layers = JSON.parse(result);
1108
- } catch (e) {
1109
- const parsed = parseLispList(result);
1110
- if (parsed) {
1111
- layers = parsed;
1112
- } else {
1113
- layers = [];
1114
- }
1115
- }
1116
- if (!Array.isArray(layers)) {
1117
- if (typeof layers === "number") {
1118
- layers = [[result, layers, 0]];
1119
- } else if (typeof layers === "string") {
1120
- layers = [[layers, 7, 0]];
1121
- }
1122
- }
1123
- const mapped = layers.map((l) => {
1124
- const name = Array.isArray(l) ? l[0] : l;
1125
- const color = Array.isArray(l) && l[1] !== void 0 ? l[1] : 7;
1126
- const flags = Array.isArray(l) && l[2] !== void 0 ? l[2] : 0;
1127
- return {
1128
- name: String(name),
1129
- color,
1130
- locked: (flags & 4) !== 0,
1131
- frozen: (flags & 1) !== 0
1132
- };
1133
- });
1134
- setCache(cacheKey, mapped);
1135
- return mapped;
1136
- } catch (e) {
1137
- setCache(cacheKey, []);
1138
- return [];
1139
- }
1140
- }
1141
1063
  async function getEntities(params = {}) {
1142
1064
  const cacheKey = `dwg:entities:${JSON.stringify(params)}`;
1143
1065
  const cached = getCached(cacheKey);
@@ -1243,27 +1165,51 @@ async function getEntitiesSummary(cacheKey) {
1243
1165
  return result;
1244
1166
  }
1245
1167
  }
1246
- async function getTexts(params = {}) {
1247
- const cacheKey = `dwg:texts:${JSON.stringify(params)}`;
1168
+ function buildTextContentCode({ layer, bbox, offset, limit }) {
1169
+ const items = [`'(0 . "TEXT,MTEXT,ATTRIB,TCH_TEXT")`];
1170
+ if (layer)
1171
+ items.push(`(cons 8 "${layer.replace(/"/g, '\\"')}")`);
1172
+ if (bbox) {
1173
+ const parts = bbox.split(",").map((s) => parseFloat(s.trim()));
1174
+ if (parts.length === 4) {
1175
+ const [x1, y1, x2, y2] = parts;
1176
+ items.push(
1177
+ `'(-4 . "<AND")`,
1178
+ `'(-4 . ">=,>=,*") (list 10 ${x1} ${y1} 0.0)`,
1179
+ `'(-4 . "<=,<=,*") (list 10 ${x2} ${y2} 0.0)`,
1180
+ `'(-4 . "AND>")`
1181
+ );
1182
+ }
1183
+ }
1184
+ const filterExpr = `(list ${items.join(" ")})`;
1185
+ return `(progn
1186
+ (setq ss (ssget "_X" ${filterExpr}))
1187
+ (if (null ss)
1188
+ (list "total" 0 "offset" ${offset} "limit" ${limit} "texts" nil)
1189
+ (progn
1190
+ (setq total (sslength ss) i ${offset} texts nil)
1191
+ (while (and (< i total) (< (length texts) ${limit}))
1192
+ (setq ent (ssname ss i) ed (entget ent) ins (cdr (assoc 10 ed)))
1193
+ (setq texts (append texts (list (list "text" (vl-prin1-to-string (cdr (assoc 1 ed))) "position" (list (car ins) (cadr ins) (caddr ins))))) i (1+ i)))
1194
+ (list "total" total "offset" ${offset} "limit" ${limit} "texts" texts))))
1195
+ )`;
1196
+ }
1197
+ async function getTextContent(params = {}) {
1198
+ const cacheKey = `dwg:text-content:${JSON.stringify(params)}`;
1248
1199
  const cached = getCached(cacheKey);
1249
1200
  if (cached)
1250
1201
  return cached;
1251
1202
  if (!cad.connected)
1252
1203
  await cad.connect();
1253
1204
  if (!cad.connected) {
1254
- const result = { total: 0, texts: [] };
1205
+ const result = { total: 0, offset: 0, limit: 5e3, texts: [] };
1255
1206
  setCache(cacheKey, result);
1256
1207
  return result;
1257
1208
  }
1258
1209
  const offset = Math.max(0, parseInt(params.offset) || 0);
1259
1210
  const limit = Math.min(Math.max(1, parseInt(params.limit) || 5e3), 5e3);
1260
1211
  try {
1261
- const code = buildTextCode({
1262
- layer: params.layer || null,
1263
- bbox: params.bbox || null,
1264
- offset,
1265
- limit
1266
- });
1212
+ const code = buildTextContentCode({ layer: params.layer, bbox: params.bbox, offset, limit });
1267
1213
  const resultStr = await cad.sendCommandWithResult(code);
1268
1214
  if (!resultStr || resultStr === "" || resultStr === "nil" || resultStr === "0") {
1269
1215
  const result = { total: 0, offset, limit, texts: [] };
@@ -1271,16 +1217,32 @@ async function getTexts(params = {}) {
1271
1217
  return result;
1272
1218
  }
1273
1219
  const parsed = parseLispRecursive(resultStr);
1274
- const textsIdx = parsed.indexOf("texts");
1275
- const rawTexts = textsIdx !== -1 && Array.isArray(parsed[textsIdx + 1]) ? parsed[textsIdx + 1] : [];
1220
+ if (!parsed || !Array.isArray(parsed)) {
1221
+ const result = { total: 0, offset, limit, texts: [] };
1222
+ setCache(cacheKey, result);
1223
+ return result;
1224
+ }
1276
1225
  const data = lispPairsToObject(parsed);
1277
- data.texts = rawTexts.length > 0 ? rawTexts.map(propertyPairsToObject).filter(Boolean) : [];
1278
- data.offset = offset;
1279
- data.limit = limit;
1226
+ const rawTexts = Array.isArray(data.texts) ? data.texts : [];
1227
+ data.texts = rawTexts.map((item) => {
1228
+ if (!Array.isArray(item))
1229
+ return null;
1230
+ const obj = {};
1231
+ item.forEach((pair) => {
1232
+ if (Array.isArray(pair) && pair.length >= 2) {
1233
+ if (pair[0] === "text")
1234
+ obj.text = String(pair[1] || "");
1235
+ else if (pair[0] === "position" && Array.isArray(pair[1])) {
1236
+ obj.position = pair[1].map((v) => typeof v === "number" ? v : 0);
1237
+ }
1238
+ }
1239
+ });
1240
+ return obj.text ? obj : null;
1241
+ }).filter(Boolean);
1280
1242
  setCache(cacheKey, data);
1281
1243
  return data;
1282
1244
  } catch (e) {
1283
- log(`getTexts error: ${e.message}`);
1245
+ log(`getTextContent error: ${e.message}`);
1284
1246
  const result = { total: 0, offset, limit, texts: [] };
1285
1247
  setCache(cacheKey, result);
1286
1248
  return result;
@@ -1332,6 +1294,316 @@ async function getDwgPath() {
1332
1294
  return { path: null, name: null };
1333
1295
  }
1334
1296
  }
1297
+ function buildBlockRefsCode(filterBlockName) {
1298
+ const filterExpr = filterBlockName ? `(list (cons 2 "${filterBlockName.replace(/"/g, '\\"')}"))` : "nil";
1299
+ return `(progn
1300
+ (vl-load-com)
1301
+ (defun @br:attr (ent / atts)
1302
+ (if (= (type ent) 'VLA-OBJECT)
1303
+ (progn
1304
+ (setq atts (vlax-variant-value (vla-getattributes ent)))
1305
+ (if (safearray-value atts)
1306
+ (mapcar '(lambda (x) (cons (vla-get-tagstring x) (vla-get-textstring x)))
1307
+ (vlax-safearray->list atts))
1308
+ nil))
1309
+ (if (setq att (entnext ent))
1310
+ (progn
1311
+ (setq atts nil)
1312
+ (while (= (cdr (assoc 0 (entget att))) "ATTRIB")
1313
+ (setq atts (cons (cons (cdr (assoc 2 (entget att))) (cdr (assoc 1 (entget att)))) atts))
1314
+ att (entnext att))
1315
+ (reverse atts))
1316
+ nil))))
1317
+
1318
+ (defun @br:dynprops (ent / obj props)
1319
+ (if (= (type ent) 'VLA-OBJECT)
1320
+ (progn
1321
+ (setq obj ent)
1322
+ (if (vlax-property-available-p obj 'isdynamicblock)
1323
+ (if (vla-get-isdynamicblock obj)
1324
+ (progn
1325
+ (setq props (vlax-invoke obj 'getdynamicblockproperties))
1326
+ (mapcar '(lambda (x)
1327
+ (cons (vla-get-propertyname x)
1328
+ (list (cons "value" (vla-get-value x))
1329
+ (cons "readOnly" (vla-get-readonly x))
1330
+ (cons "show" (vla-get-show x)))))
1331
+ (vlax-safearray->list props)))
1332
+ nil)
1333
+ nil))
1334
+ (if (and (setq obj (vlax-ename->vla-object ent))
1335
+ (vlax-property-available-p obj 'isdynamicblock)
1336
+ (vla-get-isdynamicblock obj))
1337
+ (progn
1338
+ (setq props (vlax-invoke obj 'getdynamicblockproperties))
1339
+ (mapcar '(lambda (x)
1340
+ (cons (vla-get-propertyname x)
1341
+ (list (cons "value" (vla-get-value x))
1342
+ (cons "readOnly" (vla-get-readonly x))
1343
+ (cons "show" (vla-get-show x)))))
1344
+ (vlax-safearray->list props)))
1345
+ nil)))
1346
+
1347
+ (defun @br:props (ent / obj blkname result)
1348
+ (setq obj (vlax-ename->vla-object ent))
1349
+ (setq result (list
1350
+ (cons "handle" (cdr (assoc 5 (entget ent))))
1351
+ (cons "layer" (cdr (assoc 8 (entget ent))))
1352
+ (cons "blockName" (vla-get-name obj))
1353
+ (cons "effectiveBlockName" (vla-get-effectivename obj))
1354
+ (cons "insertionPoint" (vlax-safearray->list (vla-get-insertionpoint obj)))
1355
+ (cons "rotation" (vla-get-rotation obj))
1356
+ (cons "scale" (list (vla-get-xscale obj) (vla-get-yscale obj) (vla-get-zscale obj)))
1357
+ (cons "isDynamic" (if (vlax-property-available-p obj 'isdynamicblock) (vla-get-isdynamicblock obj) nil))
1358
+ (cons "attributes" (@br:attr obj))
1359
+ (cons "dynamicProperties" (@br:dynprops obj))))
1360
+ result)
1361
+
1362
+ (setq ss (ssget "_X" (list (cons 0 "INSERT") ${filterExpr})))
1363
+ (if (null ss)
1364
+ (list (cons "total" 0) (cons "blockRefs" nil))
1365
+ (progn
1366
+ (setq total (sslength ss) i 0 refs nil)
1367
+ (while (< i total)
1368
+ (setq refs (cons (@br:props (ssname ss i)) refs) i (1+ i)))
1369
+ (list (cons "total" total) (cons "blockRefs" (reverse refs))))))`;
1370
+ }
1371
+ async function getBlockRefs(params = {}) {
1372
+ const cacheKey = `dwg:block-refs:${params.blockName || "all"}`;
1373
+ const cached = getCached(cacheKey);
1374
+ if (cached)
1375
+ return cached;
1376
+ if (!cad.connected)
1377
+ await cad.connect();
1378
+ if (!cad.connected) {
1379
+ const result = { total: 0, blockRefs: [] };
1380
+ setCache(cacheKey, result);
1381
+ return result;
1382
+ }
1383
+ try {
1384
+ const code = buildBlockRefsCode(params.blockName);
1385
+ const resultStr = await cad.sendCommandWithResult(code);
1386
+ if (!resultStr || resultStr === "" || resultStr === "nil") {
1387
+ const result2 = { total: 0, blockRefs: [] };
1388
+ setCache(cacheKey, result2);
1389
+ return result2;
1390
+ }
1391
+ const parsed = parseLispRecursive(resultStr);
1392
+ if (!parsed || !Array.isArray(parsed)) {
1393
+ const result2 = { total: 0, blockRefs: [] };
1394
+ setCache(cacheKey, result2);
1395
+ return result2;
1396
+ }
1397
+ const result = lispPairsToObject(parsed);
1398
+ const blockRefs = Array.isArray(result.blockRefs) ? result.blockRefs : [];
1399
+ const finalResult = {
1400
+ total: typeof result.total === "number" ? result.total : blockRefs.length,
1401
+ blockRefs: blockRefs.map((br) => {
1402
+ const obj = {};
1403
+ if (Array.isArray(br)) {
1404
+ br.forEach((pair) => {
1405
+ if (Array.isArray(pair) && pair.length >= 2) {
1406
+ const key = pair[0];
1407
+ let val = pair[1];
1408
+ if (key === "insertionPoint" && Array.isArray(val)) {
1409
+ val = val.map((v) => typeof v === "number" ? v : 0);
1410
+ } else if (key === "scale" && Array.isArray(val)) {
1411
+ val = val.map((v) => typeof v === "number" ? v : 1);
1412
+ } else if (key === "isDynamic") {
1413
+ val = val === true || val === "true" || val === 1;
1414
+ }
1415
+ obj[key] = val;
1416
+ }
1417
+ });
1418
+ }
1419
+ return obj;
1420
+ })
1421
+ };
1422
+ setCache(cacheKey, finalResult);
1423
+ return finalResult;
1424
+ } catch (e) {
1425
+ log(`getBlockRefs error: ${e.message}`);
1426
+ const result = { total: 0, blockRefs: [] };
1427
+ setCache(cacheKey, result);
1428
+ return result;
1429
+ }
1430
+ }
1431
+ var TBL_QUERIES = {
1432
+ layer: { name: "layer", lisp: `(progn
1433
+ (setq @d nil)
1434
+ (vlax-for e (vla-get-layers (vla-get-activedocument (vlax-get-acad-object)))
1435
+ (setq @d (cons (list
1436
+ (cons 2 (vla-get-name e))
1437
+ (cons 62 (vla-get-color e))
1438
+ (cons 6 (vla-get-linetype e))
1439
+ (cons 70 (logior (if (vla-get-freeze e) 1 0) (if (vla-get-lock e) 4 0)))
1440
+ (cons 60 (if (vla-get-layeron e) 0 1))
1441
+ ) @d)))
1442
+ (list (cons 'table 'layer) (cons 'total (length @d)) (cons 'data (list (reverse @d)))))` },
1443
+ block: { name: "block", lisp: `(progn
1444
+ (setq @d nil)
1445
+ (vlax-for e (vla-get-blocks (vla-get-activedocument (vlax-get-acad-object)))
1446
+ (if (not (and (vlax-property-available-p e 'isfoundation) (vlax-get e 'isfoundation)))
1447
+ (setq @d (cons (list (cons 2 (vla-get-name e)) (cons 70 (if (and (vlax-property-available-p e 'isxref) (vlax-get e 'isxref)) 1 0))) @d))))
1448
+ (list (cons 'table 'block) (cons 'total (length @d)) (cons 'data (list (reverse @d)))))` },
1449
+ style: { name: "style", lisp: `(progn
1450
+ (setq @d nil)
1451
+ (vlax-for e (vla-get-textstyles (vla-get-activedocument (vlax-get-acad-object)))
1452
+ (setq @d (cons (list (cons 2 (vla-get-name e)) (cons 70 0)) @d)))
1453
+ (list (cons 'table 'style) (cons 'total (length @d)) (cons 'data (list (reverse @d)))))` },
1454
+ dimstyle: { name: "dimstyle", lisp: `(progn
1455
+ (setq @d nil)
1456
+ (vlax-for e (vla-get-dimstyles (vla-get-activedocument (vlax-get-acad-object)))
1457
+ (setq @d (cons (list (cons 2 (vla-get-name e)) (cons 70 0)) @d)))
1458
+ (list (cons 'table 'dimstyle) (cons 'total (length @d)) (cons 'data (list (reverse @d)))))` },
1459
+ ltype: { name: "linetype", lisp: `(progn
1460
+ (setq @d nil)
1461
+ (vlax-for e (vla-get-linetypes (vla-get-activedocument (vlax-get-acad-object)))
1462
+ (setq @d (cons (list (cons 2 (vla-get-name e)) (cons 70 0)) @d)))
1463
+ (list (cons 'table 'linetype) (cons 'total (length @d)) (cons 'data (list (reverse @d)))))` }
1464
+ };
1465
+ function buildTablesCode(tblName) {
1466
+ const key = tblName.toLowerCase();
1467
+ const query = TBL_QUERIES[key];
1468
+ if (query) {
1469
+ return `(progn (vl-load-com) ${query.lisp})`;
1470
+ }
1471
+ const parts = Object.values(TBL_QUERIES).map((q) => q.lisp);
1472
+ return `(progn (vl-load-com) (list ${parts.join(" ")}))`;
1473
+ }
1474
+ function parseTableRecord(rec) {
1475
+ if (!rec || !Array.isArray(rec))
1476
+ return null;
1477
+ const obj = {};
1478
+ for (const pair of rec) {
1479
+ if (Array.isArray(pair) && pair.length >= 2) {
1480
+ const key = String(pair[0]);
1481
+ const val = pair[1];
1482
+ if (key === "2")
1483
+ obj.name = String(val);
1484
+ else if (key === "62")
1485
+ obj.color = typeof val === "number" ? val : 7;
1486
+ else if (key === "6")
1487
+ obj.linetype = String(val);
1488
+ else if (key === "70") {
1489
+ obj.flags = typeof val === "number" ? val : 0;
1490
+ obj.frozen = (val & 1) !== 0;
1491
+ obj.locked = (val & 4) !== 0;
1492
+ } else if (key === "60")
1493
+ obj.on = val === 0;
1494
+ else if (key === "1")
1495
+ obj.font = String(val);
1496
+ else if (key === "40")
1497
+ obj.height = typeof val === "number" ? val : 0;
1498
+ else if (key === "41")
1499
+ obj.width = typeof val === "number" ? val : 1;
1500
+ else if (key === "42")
1501
+ obj.oblique = typeof val === "number" ? val : 0;
1502
+ else if (key === "3")
1503
+ obj.description = String(val);
1504
+ }
1505
+ }
1506
+ return obj.name ? obj : null;
1507
+ }
1508
+ async function getTables(params = {}) {
1509
+ const tblName = params.tbl || params.type || "all";
1510
+ const cacheKey = `dwg:tbl:${tblName}`;
1511
+ const cached = getCached(cacheKey);
1512
+ if (cached)
1513
+ return cached;
1514
+ if (!cad.connected)
1515
+ await cad.connect();
1516
+ if (!cad.connected)
1517
+ return { table: tblName, data: [] };
1518
+ try {
1519
+ const code = buildTablesCode(tblName);
1520
+ const resultStr = await cad.sendCommandWithResult(code);
1521
+ if (!resultStr || resultStr === "" || resultStr === "nil") {
1522
+ const result2 = { table: tblName, data: [] };
1523
+ setCache(cacheKey, result2);
1524
+ return result2;
1525
+ }
1526
+ const parsed = parseLispRecursive(resultStr);
1527
+ if (!parsed || !Array.isArray(parsed)) {
1528
+ const result2 = { table: tblName, total: 0, data: [] };
1529
+ setCache(cacheKey, result2);
1530
+ return result2;
1531
+ }
1532
+ let result;
1533
+ if (parsed.length >= 3 && parsed[0] && String(parsed[0][0]).toUpperCase() === "TABLE") {
1534
+ const tableName = String(parsed[0][1]).toLowerCase();
1535
+ let total = 0;
1536
+ let tblData = [];
1537
+ for (const item of parsed) {
1538
+ if (Array.isArray(item) && item.length >= 2) {
1539
+ const key = String(item[0]).toUpperCase();
1540
+ if (key === "TOTAL")
1541
+ total = typeof item[1] === "number" ? item[1] : 0;
1542
+ else if (key === "DATA") {
1543
+ if (Array.isArray(item[1]) && item[1].length > 0 && item[1][0].length > 0 && !isNaN(parseInt(item[1][0][0]))) {
1544
+ tblData = item[1];
1545
+ }
1546
+ }
1547
+ }
1548
+ }
1549
+ if (tblData.length === 0 && parsed.length > 2) {
1550
+ tblData = parsed.slice(2);
1551
+ }
1552
+ result = {
1553
+ table: tableName,
1554
+ total,
1555
+ data: tblData.map(parseTableRecord).filter(Boolean)
1556
+ };
1557
+ } else {
1558
+ const allData = {};
1559
+ parsed.forEach((item) => {
1560
+ if (!Array.isArray(item) || item.length < 2)
1561
+ return;
1562
+ let tableKey = null;
1563
+ const entry = { total: 0, data: [] };
1564
+ if (Array.isArray(item[0]) && item[0].length >= 2 && String(item[0][0]).toLowerCase() === "table") {
1565
+ tableKey = String(item[0][1]).toLowerCase();
1566
+ for (let i = 1; i < item.length; i++) {
1567
+ const sub = item[i];
1568
+ if (!Array.isArray(sub) || sub.length < 2)
1569
+ continue;
1570
+ const subKey = String(sub[0]).toUpperCase();
1571
+ if (subKey === "TOTAL")
1572
+ entry.total = typeof sub[1] === "number" ? sub[1] : 0;
1573
+ else if (subKey === "DATA") {
1574
+ const raw = Array.isArray(sub[1]) ? sub[1] : sub.slice(1);
1575
+ entry.data = raw.map(parseTableRecord).filter(Boolean);
1576
+ }
1577
+ }
1578
+ } else {
1579
+ tableKey = String(item[0]).toLowerCase();
1580
+ for (let i = 1; i < item.length; i++) {
1581
+ const sub = item[i];
1582
+ if (!Array.isArray(sub) || sub.length < 2)
1583
+ continue;
1584
+ const subKey = String(sub[0]).toUpperCase();
1585
+ if (subKey === "TOTAL") {
1586
+ entry.total = typeof sub[1] === "number" ? sub[1] : 0;
1587
+ } else if (subKey === "DATA") {
1588
+ const raw = Array.isArray(sub[1]) ? sub[1] : sub.slice(1);
1589
+ entry.data = raw.map(parseTableRecord).filter(Boolean);
1590
+ }
1591
+ }
1592
+ }
1593
+ if (tableKey)
1594
+ allData[tableKey] = entry;
1595
+ });
1596
+ result = allData;
1597
+ }
1598
+ setCache(cacheKey, result);
1599
+ return result;
1600
+ } catch (e) {
1601
+ log(`getTables error: ${e.message}`);
1602
+ const result = { table: tblName, data: [] };
1603
+ setCache(cacheKey, result);
1604
+ return result;
1605
+ }
1606
+ }
1335
1607
  async function getPackages(filterName = null) {
1336
1608
  const cacheKey = filterName ? `packages:${filterName}` : "packages:all";
1337
1609
  const cached = getCached(cacheKey);
@@ -3018,12 +3290,6 @@ var RESOURCE_TEMPLATES = [
3018
3290
  description: "\u6309 type/layer/bbox \u8FC7\u6EE4\u56FE\u5143\uFF0C\u8FD4\u56DE entity:properties \u5168\u5C5E\u6027 JSON\uFF08ObjectName, Handle, Layer, Color, Center, Radius \u7B49\uFF09",
3019
3291
  mimeType: "application/json"
3020
3292
  },
3021
- {
3022
- uriTemplate: "atlisp://dwg/layers?name={name}",
3023
- name: "Layer by Name",
3024
- description: "\u6309\u540D\u79F0\u67E5\u8BE2\u56FE\u5C42",
3025
- mimeType: "application/json"
3026
- },
3027
3293
  {
3028
3294
  uriTemplate: "atlisp://packages?search={query}",
3029
3295
  name: "Package Search",
@@ -3031,9 +3297,21 @@ var RESOURCE_TEMPLATES = [
3031
3297
  mimeType: "application/json"
3032
3298
  },
3033
3299
  {
3034
- uriTemplate: "atlisp://dwg/texts?layer={layer}&offset={offset}&limit={limit}",
3035
- name: "Text Entities",
3036
- description: "\u5206\u9875\u83B7\u53D6\u6587\u672C\u5B9E\u4F53",
3300
+ uriTemplate: "atlisp://dwg/block-refs/{blockName}",
3301
+ name: "Block References",
3302
+ description: "\u83B7\u53D6\u5757\u53C2\u7167\u5217\u8868\uFF0C\u652F\u6301\u6309\u5757\u540D\u8FC7\u6EE4",
3303
+ mimeType: "application/json"
3304
+ },
3305
+ {
3306
+ uriTemplate: "atlisp://dwg/tbl/{tbl}",
3307
+ name: "CAD Tables",
3308
+ description: "\u83B7\u53D6 CAD \u8868\u6570\u636E (layer, block, textstyle, dimstyle, linetype, ucs, view, regapp)",
3309
+ mimeType: "application/json"
3310
+ },
3311
+ {
3312
+ uriTemplate: "atlisp://dwg/text-content?bbox={bbox}&layer={layer}&offset={offset}&limit={limit}",
3313
+ name: "Text Content",
3314
+ description: "\u6587\u672C\u5185\u5BB9\u53CA\u4F4D\u7F6E\uFF0C\u7528\u4E8E\u8BED\u4E49\u5206\u6790",
3037
3315
  mimeType: "application/json"
3038
3316
  }
3039
3317
  ];
@@ -8377,25 +8655,27 @@ var tools = [
8377
8655
  ];
8378
8656
  function notifyResourceChanges(toolName) {
8379
8657
  const resourceMap = {
8380
- connect_cad: ["atlisp://cad/info", "atlisp://dwg/layers", "atlisp://dwg/name", "atlisp://dwg/path", "atlisp://cad/dwgs", "atlisp://packages"],
8381
- new_document: ["atlisp://dwg/name", "atlisp://dwg/path", "atlisp://cad/dwgs", "atlisp://dwg/layers", "atlisp://dwg/entities", "atlisp://dwg/texts"],
8658
+ connect_cad: ["atlisp://cad/info", "atlisp://dwg/tbl", "atlisp://dwg/name", "atlisp://dwg/path", "atlisp://cad/dwgs", "atlisp://packages"],
8659
+ new_document: ["atlisp://dwg/name", "atlisp://dwg/path", "atlisp://cad/dwgs", "atlisp://dwg/tbl", "atlisp://dwg/entities", "atlisp://dwg/text-content"],
8382
8660
  install_package: ["atlisp://packages"],
8383
8661
  install_atlisp: ["atlisp://packages", "atlisp://cad/info"],
8384
8662
  init_atlisp: ["atlisp://packages", "atlisp://cad/info"],
8385
- create_layer: ["atlisp://dwg/layers"],
8386
- delete_layer: ["atlisp://dwg/layers"],
8387
- set_layer: ["atlisp://dwg/layers"],
8388
- set_current_layer: ["atlisp://dwg/layers"],
8389
- create_block: ["atlisp://dwg/blocks"],
8390
- open_dwg: ["atlisp://dwg/name", "atlisp://dwg/path", "atlisp://cad/dwgs", "atlisp://dwg/layers", "atlisp://dwg/entities"],
8663
+ create_layer: ["atlisp://dwg/tbl"],
8664
+ delete_layer: ["atlisp://dwg/tbl"],
8665
+ set_layer: ["atlisp://dwg/tbl"],
8666
+ set_current_layer: ["atlisp://dwg/tbl"],
8667
+ create_block: ["atlisp://dwg/block-refs", "atlisp://dwg/tbl"],
8668
+ open_dwg: ["atlisp://dwg/name", "atlisp://dwg/path", "atlisp://cad/dwgs", "atlisp://dwg/tbl", "atlisp://dwg/entities", "atlisp://dwg/block-refs", "atlisp://dwg/text-content"],
8391
8669
  save_dwg: ["atlisp://dwg/name", "atlisp://dwg/path"],
8392
8670
  export_pdf: [],
8393
- close_dwg: ["atlisp://dwg/name", "atlisp://dwg/path", "atlisp://cad/dwgs"],
8394
- batch_delete: ["atlisp://dwg/entities"],
8395
- batch_explode: ["atlisp://dwg/entities"],
8671
+ close_dwg: ["atlisp://dwg/name", "atlisp://dwg/path", "atlisp://cad/dwgs", "atlisp://dwg/block-refs", "atlisp://dwg/text-content"],
8672
+ delete_entity: ["atlisp://dwg/entities", "atlisp://dwg/block-refs"],
8673
+ batch_delete: ["atlisp://dwg/entities", "atlisp://dwg/block-refs"],
8674
+ batch_explode: ["atlisp://dwg/entities", "atlisp://dwg/block-refs"],
8675
+ explode_block: ["atlisp://dwg/entities", "atlisp://dwg/block-refs"],
8396
8676
  batch_set_color: ["atlisp://dwg/entities"],
8397
8677
  batch_set_linetype: ["atlisp://dwg/entities"],
8398
- batch_move: ["atlisp://dwg/entities", "atlisp://dwg/layers"],
8678
+ batch_move: ["atlisp://dwg/entities", "atlisp://dwg/tbl"],
8399
8679
  batch_rename: ["atlisp://dwg/entities"],
8400
8680
  batch_create_group: ["atlisp://dwg/groups"],
8401
8681
  batch_add_to_group: ["atlisp://dwg/groups"],
@@ -8421,10 +8701,10 @@ function notifyResourceChanges(toolName) {
8421
8701
  thicken_surface: ["atlisp://dwg/entities"],
8422
8702
  create_region: ["atlisp://dwg/entities"],
8423
8703
  create_loft_surface: ["atlisp://dwg/entities"],
8424
- create_dimension_style: [],
8425
- create_text_style: [],
8426
- create_linetype: [],
8427
- load_linetype: [],
8704
+ create_dimension_style: ["atlisp://dwg/tbl"],
8705
+ create_text_style: ["atlisp://dwg/tbl"],
8706
+ create_linetype: ["atlisp://dwg/tbl"],
8707
+ load_linetype: ["atlisp://dwg/tbl"],
8428
8708
  attach_pdf: ["atlisp://dwg/entities"],
8429
8709
  detach_pdf: ["atlisp://dwg/entities"],
8430
8710
  import_dxf: ["atlisp://dwg/entities"],
@@ -9038,7 +9318,7 @@ Options:
9038
9318
  --port <port> HTTP port (default: 8110)
9039
9319
  --host <host> HTTP host (default: 0.0.0.0)
9040
9320
  --stdio Shorthand for --transport stdio
9041
- --config <path> Path to config file (default: ~/.@lisp/atlisp.config.json)
9321
+ --config <path> Path to config file (default: ~/.atlisp/atlisp.config.json)
9042
9322
  --debug Enable debug mode
9043
9323
 
9044
9324
  Environment Variables:
@@ -124,29 +124,32 @@ const cadSendWithResult = edge.func(function() {/*
124
124
  async (input) => {
125
125
  string tempFile = null;
126
126
  string lispFile = null;
127
+ string userCodeFile = null;
127
128
  try {
128
129
  dynamic d = input;
129
130
  string code = d.code.ToString();
130
131
  string platform = d.platform.ToString();
131
132
  string encoding = d.encoding != null ? d.encoding.ToString() : "";
132
- string progId = platform == "BricsCAD" ? "BricscadApp.AadApplication" : platform + ".Application";
133
+ string progId = platform == "BricsCAD" ? "BricscadApp.AcadApplication" : platform + ".Application";
133
134
  string tempDir = System.IO.Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.UserProfile), "@lisp", "tmp");
134
135
  System.IO.Directory.CreateDirectory(tempDir);
135
136
 
136
137
  tempFile = System.IO.Path.Combine(tempDir, "atlisp_result_" + System.Guid.NewGuid().ToString("N") + ".txt");
137
138
  lispFile = System.IO.Path.Combine(tempDir, "atlisp_code_" + System.Guid.NewGuid().ToString("N") + ".lsp");
139
+ userCodeFile = System.IO.Path.Combine(tempDir, "atlisp_user_" + System.Guid.NewGuid().ToString("N") + ".lsp");
140
+
141
+ // 用户代码单独写入文件,避免拼接注入风险
142
+ System.IO.File.WriteAllText(userCodeFile, code, System.Text.Encoding.GetEncoding(System.Globalization.CultureInfo.CurrentCulture.TextInfo.ANSICodePage));
138
143
 
139
- // 生成 LISP 代码:使用 vl-catch-all-apply 捕获结果和错误
140
- // 返回 (success . result) 或 (nil . error-msg)
141
144
  string lispCode = "(progn"
142
145
  + "(setq f(open \"" + tempFile.Replace("\\", "\\\\") + "\" \"w\"))"
143
- + "(setq r(vl-catch-all-apply '(lambda ()(progn " + code + "))))"
146
+ + "(setq r(vl-catch-all-apply '(lambda ()(load \"" + userCodeFile.Replace("\\", "\\\\") + "\"))))"
144
147
  + "(if (vl-catch-all-error-p r)"
145
148
  + "(princ(strcat \"ERROR:\"(vl-catch-all-error-message r)) f)"
146
149
  + "(princ r f))"
147
150
  + "(close f)"
148
151
  + "(princ))";
149
-
152
+
150
153
  // 使用系统 ANSI 编码以兼容 GstarCAD / ZWCAD
151
154
  System.IO.File.WriteAllText(lispFile, lispCode, System.Text.Encoding.GetEncoding(System.Globalization.CultureInfo.CurrentCulture.TextInfo.ANSICodePage));
152
155
 
@@ -201,6 +204,7 @@ string encoding = d.encoding != null ? d.encoding.ToString() : "";
201
204
 
202
205
  try { System.IO.File.Delete(tempFile); } catch {}
203
206
  try { System.IO.File.Delete(lispFile); } catch {}
207
+ try { System.IO.File.Delete(userCodeFile); } catch {}
204
208
  break;
205
209
  } catch (System.IO.IOException) {
206
210
  System.Threading.Thread.Sleep(200);
@@ -223,6 +227,9 @@ string encoding = d.encoding != null ? d.encoding.ToString() : "";
223
227
  if (lispFile != null) {
224
228
  try { if (System.IO.File.Exists(lispFile)) System.IO.File.Delete(lispFile); } catch {}
225
229
  }
230
+ if (userCodeFile != null) {
231
+ try { if (System.IO.File.Exists(userCodeFile)) System.IO.File.Delete(userCodeFile); } catch {}
232
+ }
226
233
  return new { success = false, error = ex.Message };
227
234
  }
228
235
  if (tempFile != null) {
@@ -231,6 +238,9 @@ string encoding = d.encoding != null ? d.encoding.ToString() : "";
231
238
  if (lispFile != null) {
232
239
  try { if (System.IO.File.Exists(lispFile)) System.IO.File.Delete(lispFile); } catch {}
233
240
  }
241
+ if (userCodeFile != null) {
242
+ try { if (System.IO.File.Exists(userCodeFile)) System.IO.File.Delete(userCodeFile); } catch {}
243
+ }
234
244
  return new { success = false };
235
245
  }
236
246
  */});
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@atlisp/mcp",
3
- "version": "1.6.8",
3
+ "version": "1.6.10",
4
4
  "description": "MCP Server for @lisp on CAD,support AutoCAD/GstarCAD/ZWCAD/BricsCAD or CAD platform compatible with AutoLISP",
5
5
  "type": "module",
6
6
  "bin": {