@atlisp/mcp 1.8.15 → 1.8.17

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (33) hide show
  1. package/dist/handlers/3d-handlers.js +128 -0
  2. package/dist/handlers/batch-handlers.js +260 -0
  3. package/dist/handlers/block-handlers.js +214 -0
  4. package/dist/handlers/cad-handlers.js +180 -0
  5. package/dist/handlers/constraint-handlers.js +130 -0
  6. package/dist/handlers/dim-hatch-handlers.js +340 -0
  7. package/dist/handlers/draw-handlers.js +175 -0
  8. package/dist/handlers/edit-handlers.js +179 -0
  9. package/dist/handlers/entity-handlers.js +196 -0
  10. package/dist/handlers/external-handlers.js +218 -0
  11. package/dist/handlers/file-handlers.js +172 -0
  12. package/dist/handlers/function-handlers.js +158 -0
  13. package/dist/handlers/layer-handlers.js +181 -0
  14. package/dist/handlers/package-handlers.js +89 -0
  15. package/dist/handlers/parametric-handlers.js +272 -0
  16. package/dist/handlers/pdf-annotation-handlers.js +117 -0
  17. package/dist/handlers/prompt-handlers.js +9 -0
  18. package/dist/handlers/purge-handlers.js +137 -0
  19. package/dist/handlers/query-print-handlers.js +662 -0
  20. package/dist/handlers/resource-cache.js +63 -0
  21. package/dist/handlers/resource-defs.js +79 -0
  22. package/dist/handlers/resource-handlers.js +131 -0
  23. package/dist/handlers/resource-readers.js +1045 -0
  24. package/dist/handlers/sheetset-handlers.js +430 -0
  25. package/dist/handlers/spatial-handlers.js +174 -0
  26. package/dist/handlers/style-handlers.js +162 -0
  27. package/dist/handlers/text-handlers.js +198 -0
  28. package/dist/handlers/ucs-layout-handlers.js +271 -0
  29. package/dist/handlers/viewport-handlers.js +150 -0
  30. package/dist/handlers/xdata-handlers.js +148 -0
  31. package/dist/handlers/xref-handlers.js +334 -0
  32. package/dist/lisp-security.js +7 -2
  33. package/package.json +2 -2
@@ -0,0 +1,128 @@
1
+ import { cad } from '../cad.js';
2
+ import { log } from '../logger.js';
3
+ import { mcpSuccess, mcpError, ensureCadConnected, escapeLispString } from '../handler-utils.js';
4
+
5
+ function parsePoint(point) {
6
+ if (Array.isArray(point)) return point.join(' ');
7
+ if (typeof point === 'string') return point;
8
+ return '0,0,0';
9
+ }
10
+
11
+ export async function createBox(center, length, width, height) {
12
+ try { await ensureCadConnected(); const pt = parsePoint(center); await cad.sendCommand(`(command "_.box" "${escapeLispString(pt)}" "${length}" "${width}" "${height}" "")`); return mcpSuccess(JSON.stringify({ center: pt, dimensions: { length, width, height } })); } catch (e) { return mcpError(`错误: ${e.message}`); }
13
+ }
14
+
15
+ export async function createSphere(center, radius) {
16
+ try { await ensureCadConnected(); const pt = parsePoint(center); await cad.sendCommand(`(command "_.sphere" "${escapeLispString(pt)}" "${radius}" "")`); return mcpSuccess(JSON.stringify({ center: pt, radius })); } catch (e) { return mcpError(`错误: ${e.message}`); }
17
+ }
18
+
19
+ export async function createCylinder(center, radius, height) {
20
+ try { await ensureCadConnected(); const pt = parsePoint(center); await cad.sendCommand(`(command "_.cylinder" "${escapeLispString(pt)}" "${radius}" "${height}" "")`); return mcpSuccess(JSON.stringify({ center: pt, radius, height })); } catch (e) { return mcpError(`错误: ${e.message}`); }
21
+ }
22
+
23
+ export async function createCone(center, radius, height) {
24
+ try { await ensureCadConnected(); const pt = parsePoint(center); await cad.sendCommand(`(command "_.cone" "${escapeLispString(pt)}" "${radius}" "${height}" "")`); return mcpSuccess(JSON.stringify({ center: pt, radius, height })); } catch (e) { return mcpError(`错误: ${e.message}`); }
25
+ }
26
+
27
+ export async function createTorus(center, majorRadius, minorRadius) {
28
+ try { await ensureCadConnected(); const pt = parsePoint(center); await cad.sendCommand(`(command "_.torus" "${escapeLispString(pt)}" "${majorRadius}" "${minorRadius}" "")`); return mcpSuccess(JSON.stringify({ center: pt, majorRadius, minorRadius })); } catch (e) { return mcpError(`错误: ${e.message}`); }
29
+ }
30
+
31
+ export async function createWedge(center, length, width, height) {
32
+ try { await ensureCadConnected(); const pt = parsePoint(center); await cad.sendCommand(`(command "_.wedge" "${escapeLispString(pt)}" "${length}" "${width}" "${height}" "")`); return mcpSuccess(JSON.stringify({ center: pt, dimensions: { length, width, height } })); } catch (e) { return mcpError(`错误: ${e.message}`); }
33
+ }
34
+
35
+ export async function create3DFace(points) {
36
+ try { await ensureCadConnected(); const ptList = Array.isArray(points) ? points.join(' ') : points; await cad.sendCommand(`(command "_.3dface" ${ptList} "")`); return mcpSuccess(JSON.stringify({ points })); } catch (e) { return mcpError(`错误: ${e.message}`); }
37
+ }
38
+
39
+ export async function createMesh(rows, columns, points) {
40
+ try { await ensureCadConnected(); const ptList = typeof points === 'string' ? points : (Array.isArray(points) ? points.join(' ') : points); await cad.sendCommand(`(command "_.mesh" "${rows}" "${columns}" ${ptList} "")`); return mcpSuccess(JSON.stringify({ rows, columns })); } catch (e) { return mcpError(`错误: ${e.message}`); }
41
+ }
42
+
43
+ export async function extrudeSolid(profileHandle, height, taperAngle = 0) {
44
+ try { await ensureCadConnected(); await cad.sendCommand(`(command "_.extrude" (handent "${escapeLispString(profileHandle)}") "${height}" "${taperAngle}" "")`); return mcpSuccess(JSON.stringify({ profileHandle, height, taperAngle })); } catch (e) { return mcpError(`错误: ${e.message}`); }
45
+ }
46
+
47
+ export async function revolveSolid(profileHandle, axisStart, axisEnd, angle = 360) {
48
+ try { await ensureCadConnected(); const startPt = parsePoint(axisStart); const endPt = parsePoint(axisEnd); await cad.sendCommand(`(command "_.revolve" (handent "${escapeLispString(profileHandle)}") "${escapeLispString(startPt)}" "${escapeLispString(endPt)}" "${angle}" "")`); return mcpSuccess(JSON.stringify({ profileHandle, axisStart: startPt, axisEnd: endPt, angle })); } catch (e) { return mcpError(`错误: ${e.message}`); }
49
+ }
50
+
51
+ export async function create3DPolyline(points) {
52
+ try { await ensureCadConnected(); const ptList = Array.isArray(points) ? points.map(p => parsePoint(p)).join(' ') : points; await cad.sendCommand(`(command "_.3dpoly" ${ptList} "")`); return mcpSuccess(JSON.stringify({ points })); } catch (e) { return mcpError(`错误: ${e.message}`); }
53
+ }
54
+
55
+ export async function createRegion(handles) {
56
+ try { await ensureCadConnected(); const handleList = Array.isArray(handles) ? handles : handles.split(',').map(h => h.trim()); const handleStr = handleList.map(h => `(handent "${escapeLispString(h)}")`).join(' '); await cad.sendCommand(`(command "_.region" ${handleStr} "")`); return mcpSuccess(JSON.stringify({ handleCount: handleList.length })); } catch (e) { return mcpError(`错误: ${e.message}`); }
57
+ }
58
+
59
+ export async function booleanUnion(handles) {
60
+ try { await ensureCadConnected(); const handleList = Array.isArray(handles) ? handles : handles.split(',').map(h => h.trim()); await cad.sendCommand(`(command "_.union" ${handleList.map(h => `(handent "${escapeLispString(h)}")`).join(' ')} "")`); return mcpSuccess(JSON.stringify({ operation: 'union' })); } catch (e) { return mcpError(`错误: ${e.message}`); }
61
+ }
62
+
63
+ export async function booleanSubtract(handles, subtractFromHandles = []) {
64
+ try {
65
+ await ensureCadConnected();
66
+ const handleList = Array.isArray(handles) ? handles : handles.split(',').map(h => h.trim());
67
+ const fromList = subtractFromHandles.length ? (Array.isArray(subtractFromHandles) ? subtractFromHandles : subtractFromHandles.split(',').map(h => h.trim())) : [handleList.shift()];
68
+ const fromStr = fromList.map(h => `(handent "${escapeLispString(h)}")`).join(' ');
69
+ const subtractStr = handleList.map(h => `(handent "${escapeLispString(h)}")`).join(' ');
70
+ await cad.sendCommand(`(command "_.subtract" ${fromStr} "" ${subtractStr} "")`);
71
+ return mcpSuccess(JSON.stringify({ subtractFrom: fromList, subtractThese: handleList }));
72
+ } catch (e) { return mcpError(`错误: ${e.message}`); }
73
+ }
74
+
75
+ export async function booleanIntersect(handles) {
76
+ try { await ensureCadConnected(); const handleList = Array.isArray(handles) ? handles : handles.split(',').map(h => h.trim()); await cad.sendCommand(`(command "_.intersect" ${handleList.map(h => `(handent "${escapeLispString(h)}")`).join(' ')} "")`); return mcpSuccess(JSON.stringify({ operation: 'intersect' })); } catch (e) { return mcpError(`错误: ${e.message}`); }
77
+ }
78
+
79
+ export async function sliceSolid(solidHandle, planePoint, planeNormal, keepBoth = true) {
80
+ try { await ensureCadConnected(); const pt = parsePoint(planePoint); const normal = parsePoint(planeNormal); const side = keepBoth ? 'Both' : 'No'; await cad.sendCommand(`(command "_.slice" (handent "${escapeLispString(solidHandle)}") "${escapeLispString(pt)}" "${escapeLispString(normal)}" "${side}")`); return mcpSuccess(JSON.stringify({ solidHandle, planePoint: pt, planeNormal: normal, keepBoth })); } catch (e) { return mcpError(`错误: ${e.message}`); }
81
+ }
82
+
83
+ export async function createLoftSurface(profileHandles, guideHandles = []) {
84
+ try {
85
+ await ensureCadConnected();
86
+ const profileList = Array.isArray(profileHandles) ? profileHandles : profileHandles.split(',').map(h => h.trim());
87
+ const guideList = Array.isArray(guideHandles) ? guideHandles : guideHandles.split(',').map(h => h.trim());
88
+ const cmd = `(progn
89
+ (command "_.loft")
90
+ ${profileList.map(h => `(handent "${escapeLispString(h)}")`).join(' ')}
91
+ ${guideList.length > 0 ? guideList.map(h => `(handent "${escapeLispString(h)}")`).join(' ') : ''}
92
+ ""
93
+ )`;
94
+ await cad.sendCommand(cmd);
95
+ return mcpSuccess(JSON.stringify({ profileCount: profileList.length, guideCount: guideList.length }));
96
+ } catch (e) { return mcpError(`错误: ${e.message}`); }
97
+ }
98
+
99
+ export async function get3DSolidInfo(handle) {
100
+ try {
101
+ await ensureCadConnected();
102
+ const result = await cad.sendCommandWithResult(`(progn
103
+ (setq ent (handent "${escapeLispString(handle)}"))
104
+ (if ent
105
+ (progn
106
+ (setq vla (vlax-ename->vla-object ent))
107
+ (princ (vl-prin1-to-string (list
108
+ (cons "type" (vla-get-objectname vla))
109
+ (cons "volume" (vla-get-volume vla))
110
+ (cons "surfaceArea" (vla-get-area vla))
111
+ )))
112
+ )
113
+ (princ "nil")
114
+ )
115
+ )`);
116
+ let info = {};
117
+ if (result && result !== 'nil') { try { info = JSON.parse(result); } catch { info = {}; } }
118
+ return mcpSuccess(JSON.stringify({ handle, info }));
119
+ } catch (e) { return mcpError(`错误: ${e.message}`); }
120
+ }
121
+
122
+ export async function thickenSurface(surfaceHandle, thickness) {
123
+ try { await ensureCadConnected(); await cad.sendCommand(`(command "_.thicken" (handent "${escapeLispString(surfaceHandle)}") "${thickness}")`); return mcpSuccess(JSON.stringify({ surfaceHandle, thickness })); } catch (e) { return mcpError(`错误: ${e.message}`); }
124
+ }
125
+
126
+ export async function offsetSurface(surfaceHandle, distance) {
127
+ try { await ensureCadConnected(); await cad.sendCommand(`(command "_.offset" (handent "${escapeLispString(surfaceHandle)}") "${distance}")`); return mcpSuccess(JSON.stringify({ surfaceHandle, distance })); } catch (e) { return mcpError(`错误: ${e.message}`); }
128
+ }
@@ -0,0 +1,260 @@
1
+ import { cad } from '../cad.js';
2
+ import { log } from '../logger.js';
3
+ import { mcpSuccess, mcpError, ensureCadConnected, escapeLispString } from '../handler-utils.js';
4
+
5
+ function parseHandleList(handles) {
6
+ if (typeof handles === 'string') {
7
+ const trimmed = handles.trim();
8
+ if (trimmed.startsWith('[')) {
9
+ try { handles = JSON.parse(trimmed); } catch { handles = handles.split(',').map(h => h.trim()); }
10
+ } else {
11
+ handles = handles.split(',').map(h => h.trim());
12
+ }
13
+ }
14
+ if (!Array.isArray(handles)) handles = [handles];
15
+ return handles;
16
+ }
17
+
18
+ export async function batchRename(handles, newNameTemplate, startNum = 1) {
19
+ try {
20
+ await ensureCadConnected();
21
+ const handleList = parseHandleList(handles);
22
+ const results = [];
23
+ for (let i = 0; i < handleList.length; i++) {
24
+ const handle = handleList[i];
25
+ const newName = newNameTemplate.replace('{n}', String(startNum + i).padStart(3, '0'));
26
+ try {
27
+ await cad.sendCommand(`(_vlax-set-property (vla-item (vla-get-blocks (vla-get-document (vlax-ename->vla-object (handent "${escapeLispString(handle)}")))) (handent "${escapeLispString(handle)}")) 'Name "${escapeLispString(newName)}")`);
28
+ results.push({ handle, newName, success: true });
29
+ } catch (e) {
30
+ results.push({ handle, error: e.message, success: false });
31
+ }
32
+ }
33
+ return mcpSuccess(JSON.stringify(results));
34
+ } catch (e) { return mcpError(`错误: ${e.message}`); }
35
+ }
36
+
37
+ export async function batchMove(handles, fromLayer, toLayer) {
38
+ try {
39
+ await ensureCadConnected();
40
+ const handleList = parseHandleList(handles);
41
+ const results = [];
42
+ for (const handle of handleList) {
43
+ try {
44
+ const cond = fromLayer ? `(= (cdr (assoc 8 (entget ent))) "${escapeLispString(fromLayer)}")` : 't';
45
+ await cad.sendCommand(`(progn (setq ent (handent "${escapeLispString(handle)}")) (if ${cond} (entmod (subst (cons 8 "${escapeLispString(toLayer)}") (assoc 8 (entget ent)) (entget ent)))))`);
46
+ results.push({ handle, fromLayer, toLayer, success: true });
47
+ } catch (e) { results.push({ handle, error: e.message, success: false }); }
48
+ }
49
+ return mcpSuccess(JSON.stringify(results));
50
+ } catch (e) { return mcpError(`错误: ${e.message}`); }
51
+ }
52
+
53
+ export async function batchCopy(handles, dx, dy, dz = 0) {
54
+ try {
55
+ await ensureCadConnected();
56
+ const handleList = parseHandleList(handles);
57
+ const results = [];
58
+ for (const handle of handleList) {
59
+ try {
60
+ await cad.sendCommand(`(command "_.copy" (handent "${escapeLispString(handle)}") "" (list 0 0 0) (list ${dx} ${dy} ${dz}))`);
61
+ results.push({ originalHandle: handle, offset: { dx, dy, dz }, success: true });
62
+ } catch (e) { results.push({ handle, error: e.message, success: false }); }
63
+ }
64
+ return mcpSuccess(JSON.stringify(results));
65
+ } catch (e) { return mcpError(`错误: ${e.message}`); }
66
+ }
67
+
68
+ export async function batchDelete(handles) {
69
+ try {
70
+ await ensureCadConnected();
71
+ const handleList = parseHandleList(handles);
72
+ const results = [];
73
+ for (const handle of handleList) {
74
+ try {
75
+ await cad.sendCommand(`(entdel (handent "${escapeLispString(handle)}"))`);
76
+ results.push({ handle, success: true });
77
+ } catch (e) { results.push({ handle, error: e.message, success: false }); }
78
+ }
79
+ return mcpSuccess(JSON.stringify(results));
80
+ } catch (e) { return mcpError(`错误: ${e.message}`); }
81
+ }
82
+
83
+ export async function batchSetColor(handles, color) {
84
+ try {
85
+ await ensureCadConnected();
86
+ const handleList = parseHandleList(handles);
87
+ const results = [];
88
+ for (const handle of handleList) {
89
+ try {
90
+ await cad.sendCommand(`(progn (setq ent (handent "${escapeLispString(handle)}")) (entmod (subst (cons 62 ${color}) (assoc 62 (entget ent)) (entget ent))) (princ "ok"))`);
91
+ results.push({ handle, color, success: true });
92
+ } catch (e) { results.push({ handle, error: e.message, success: false }); }
93
+ }
94
+ return mcpSuccess(JSON.stringify(results));
95
+ } catch (e) { return mcpError(`错误: ${e.message}`); }
96
+ }
97
+
98
+ export async function batchExplode(handles) {
99
+ try {
100
+ await ensureCadConnected();
101
+ const handleList = parseHandleList(handles);
102
+ const results = [];
103
+ for (const handle of handleList) {
104
+ try {
105
+ await cad.sendCommand(`(progn (command "_.explode" (handent "${escapeLispString(handle)}")) (princ "ok"))`);
106
+ results.push({ handle, success: true });
107
+ } catch (e) { results.push({ handle, error: e.message, success: false }); }
108
+ }
109
+ return mcpSuccess(JSON.stringify(results));
110
+ } catch (e) { return mcpError(`错误: ${e.message}`); }
111
+ }
112
+
113
+ export async function batchMirror(handles, startPoint, endPoint, deleteOriginal = false) {
114
+ try {
115
+ await ensureCadConnected();
116
+ const handleList = parseHandleList(handles);
117
+ const results = [];
118
+ for (const handle of handleList) {
119
+ try {
120
+ const pt1 = typeof startPoint === 'string' ? startPoint : startPoint.join(' ');
121
+ const pt2 = typeof endPoint === 'string' ? endPoint : endPoint.join(' ');
122
+ const delOpt = deleteOriginal ? 'yes' : 'no';
123
+ await cad.sendCommand(`(progn (command "_.mirror" (handent "${escapeLispString(handle)}") "" "${escapeLispString(pt1)}" "${escapeLispString(pt2)}" "${delOpt}") (princ "ok"))`);
124
+ results.push({ handle, success: true });
125
+ } catch (e) { results.push({ handle, error: e.message, success: false }); }
126
+ }
127
+ return mcpSuccess(JSON.stringify(results));
128
+ } catch (e) { return mcpError(`错误: ${e.message}`); }
129
+ }
130
+
131
+ export async function batchOffset(handles, distance, side = 'both') {
132
+ try {
133
+ await ensureCadConnected();
134
+ const handleList = parseHandleList(handles);
135
+ const results = [];
136
+ for (const handle of handleList) {
137
+ try {
138
+ if (side === 'both') {
139
+ await cad.sendCommand(`(command "_.offset" ${distance} (handent "${escapeLispString(handle)}") (list 0 0 0))`);
140
+ } else {
141
+ await cad.sendCommand(`(command "_.offset" ${distance} (handent "${escapeLispString(handle)}"))`);
142
+ }
143
+ results.push({ handle, distance, success: true });
144
+ } catch (e) { results.push({ handle, error: e.message, success: false }); }
145
+ }
146
+ return mcpSuccess(JSON.stringify(results));
147
+ } catch (e) { return mcpError(`错误: ${e.message}`); }
148
+ }
149
+
150
+ export async function batchRotate(handles, angle, basePoint = null) {
151
+ try {
152
+ await ensureCadConnected();
153
+ const handleList = parseHandleList(handles);
154
+ const base = basePoint ? (Array.isArray(basePoint) ? basePoint.join(' ') : basePoint) : '0,0';
155
+ const results = [];
156
+ for (const handle of handleList) {
157
+ try {
158
+ await cad.sendCommand(`(command "_.rotate" (handent "${escapeLispString(handle)}") "" "${escapeLispString(base)}" "${angle}")`);
159
+ results.push({ handle, angle, success: true });
160
+ } catch (e) { results.push({ handle, error: e.message, success: false }); }
161
+ }
162
+ return mcpSuccess(JSON.stringify(results));
163
+ } catch (e) { return mcpError(`错误: ${e.message}`); }
164
+ }
165
+
166
+ export async function batchScale(handles, scaleFactor, basePoint = null) {
167
+ try {
168
+ await ensureCadConnected();
169
+ const handleList = parseHandleList(handles);
170
+ const base = basePoint ? (Array.isArray(basePoint) ? basePoint.join(' ') : basePoint) : '0,0';
171
+ const results = [];
172
+ for (const handle of handleList) {
173
+ try {
174
+ await cad.sendCommand(`(command "_.scale" (handent "${escapeLispString(handle)}") "" "${escapeLispString(base)}" "${scaleFactor}")`);
175
+ results.push({ handle, scaleFactor, success: true });
176
+ } catch (e) { results.push({ handle, error: e.message, success: false }); }
177
+ }
178
+ return mcpSuccess(JSON.stringify(results));
179
+ } catch (e) { return mcpError(`错误: ${e.message}`); }
180
+ }
181
+
182
+ export async function batchSetLinetype(handles, linetypeName) {
183
+ try {
184
+ await ensureCadConnected();
185
+ const handleList = parseHandleList(handles);
186
+ const results = [];
187
+ for (const handle of handleList) {
188
+ try {
189
+ await cad.sendCommand(`(progn (command "_.chltype" (handent "${escapeLispString(handle)}") "${escapeLispString(linetypeName)}") (princ "ok"))`);
190
+ results.push({ handle, linetype: linetypeName, success: true });
191
+ } catch (e) { results.push({ handle, error: e.message, success: false }); }
192
+ }
193
+ return mcpSuccess(JSON.stringify(results));
194
+ } catch (e) { return mcpError(`错误: ${e.message}`); }
195
+ }
196
+
197
+ export async function batchMatchProperties(sourceHandle, targetHandles) {
198
+ try {
199
+ await ensureCadConnected();
200
+ const handleList = parseHandleList(targetHandles);
201
+ const results = [];
202
+ for (const handle of handleList) {
203
+ try {
204
+ await cad.sendCommand(`(command "_.matchprop" (handent "${escapeLispString(sourceHandle)}") (handent "${escapeLispString(handle)}"))`);
205
+ results.push({ from: sourceHandle, to: handle, success: true });
206
+ } catch (e) { results.push({ from: sourceHandle, to: handle, error: e.message, success: false }); }
207
+ }
208
+ return mcpSuccess(JSON.stringify(results));
209
+ } catch (e) { return mcpError(`错误: ${e.message}`); }
210
+ }
211
+
212
+ export async function batchCreateGroup(name, handles) {
213
+ try {
214
+ await ensureCadConnected();
215
+ const handleList = parseHandleList(handles);
216
+ const handleStr = handleList.map(h => `(handent "${escapeLispString(h)}")`).join(' ');
217
+ const result = await cad.sendCommandWithResult(`(group (list ${handleStr}))`);
218
+ return mcpSuccess(JSON.stringify({ name, handle: result?.trim() }));
219
+ } catch (e) { return mcpError(`错误: ${e.message}`); }
220
+ }
221
+
222
+ export async function batchAddToGroup(groupName, handles) {
223
+ try {
224
+ await ensureCadConnected();
225
+ const handleList = parseHandleList(handles);
226
+ const results = [];
227
+ for (const handle of handleList) {
228
+ try {
229
+ await cad.sendCommand(`(progn (setq grp (cdr (assoc -3 (entget (tblobjname "group" "${escapeLispString(groupName)}"))))) (entmod (append (entget (tblobjname "group" "${escapeLispString(groupName)}")) (list (cons -3 (append grp (list (handent "${escapeLispString(handle)}"))))))) )`);
230
+ results.push({ handle, group: groupName, success: true });
231
+ } catch (e) { results.push({ handle, group: groupName, error: e.message, success: false }); }
232
+ }
233
+ return mcpSuccess(JSON.stringify(results));
234
+ } catch (e) { return mcpError(`错误: ${e.message}`); }
235
+ }
236
+
237
+ export async function moveEntity(handle, dx, dy, dz = 0) {
238
+ try { await ensureCadConnected(); await cad.sendCommand(`(command "_.MOVE" (handent "${escapeLispString(handle)}") "" (list ${dx} ${dy} ${dz}) "")\n`); return mcpSuccess(JSON.stringify({ handle, dx, dy, dz })); } catch (e) { return mcpError(`错误: ${e.message}`); }
239
+ }
240
+ export async function copyEntity(handle, dx, dy, dz = 0) {
241
+ try { await ensureCadConnected(); await cad.sendCommand(`(command "_.COPY" (handent "${escapeLispString(handle)}") "" (list ${dx} ${dy} ${dz}) "")\n`); return mcpSuccess(JSON.stringify({ handle, dx, dy, dz })); } catch (e) { return mcpError(`错误: ${e.message}`); }
242
+ }
243
+ export async function rotateEntity(handle, angle, basePoint = '0,0') {
244
+ try { await ensureCadConnected(); await cad.sendCommand(`(command "_.ROTATE" (handent "${escapeLispString(handle)}") "" (list ${(basePoint||'0,0').replace(/,/g,' ')}) ${angle})\n`); return mcpSuccess(JSON.stringify({ handle, angle, basePoint })); } catch (e) { return mcpError(`错误: ${e.message}`); }
245
+ }
246
+ export async function scaleEntity(handle, scaleFactor, basePoint = '0,0') {
247
+ try { await ensureCadConnected(); await cad.sendCommand(`(command "_.SCALE" (handent "${escapeLispString(handle)}") "" (list ${(basePoint||'0,0').replace(/,/g,' ')}) ${scaleFactor})\n`); return mcpSuccess(JSON.stringify({ handle, scaleFactor, basePoint })); } catch (e) { return mcpError(`错误: ${e.message}`); }
248
+ }
249
+ export async function mirrorEntity(handle, startPoint, endPoint, deleteOriginal = false) {
250
+ try { await ensureCadConnected(); await cad.sendCommand(`(command "_.MIRROR" (handent "${escapeLispString(handle)}") "" (list ${startPoint.replace(/,/g,' ')}) (list ${endPoint.replace(/,/g,' ')}) ${deleteOriginal ? '"_Y"' : '"_N"'})\n`); return mcpSuccess(JSON.stringify({ handle, startPoint, endPoint, deleteOriginal })); } catch (e) { return mcpError(`错误: ${e.message}`); }
251
+ }
252
+ export async function offsetEntity(handle, distance, side) {
253
+ try { await ensureCadConnected(); await cad.sendCommand(`(command "_.OFFSET" ${distance} (handent "${escapeLispString(handle)}") (list ${side.replace(/,/g,' ')}) "")\n`); return mcpSuccess(JSON.stringify({ handle, distance, side })); } catch (e) { return mcpError(`错误: ${e.message}`); }
254
+ }
255
+ export async function arrayRectangular(handle, rows, cols, rowSpacing, colSpacing) {
256
+ try { await ensureCadConnected(); await cad.sendCommand(`(command "_.ARRAY" (handent "${escapeLispString(handle)}") "" "_R" ${rows} ${cols} ${rowSpacing} ${colSpacing})\n`); return mcpSuccess(JSON.stringify({ handle, rows, cols, rowSpacing, colSpacing })); } catch (e) { return mcpError(`错误: ${e.message}`); }
257
+ }
258
+ export async function arrayPolar(handle, center, count, angle = 360) {
259
+ try { await ensureCadConnected(); await cad.sendCommand(`(command "_.ARRAY" (handent "${escapeLispString(handle)}") "" "_P" (list ${center.replace(/,/g,' ')}) ${count} ${angle} "")\n`); return mcpSuccess(JSON.stringify({ handle, center, count, angle })); } catch (e) { return mcpError(`错误: ${e.message}`); }
260
+ }
@@ -0,0 +1,214 @@
1
+ import { cad } from '../cad.js';
2
+ import { mcpSuccess, mcpError, escapeLispString, getNotifyProgress } from '../handler-utils.js';
3
+
4
+ export async function createBlock(name, entities) {
5
+ if (!cad.connected) { await cad.connect(); }
6
+ if (!cad.connected) return { content: [{ type: 'text', text: '未连接 CAD' }], isError: true };
7
+
8
+ const code = `(progn
9
+ (vl-load-com)
10
+ (if (not (tblsearch "BLOCK" "${escapeLispString(name)}"))
11
+ (progn
12
+ (entmake
13
+ (list
14
+ (cons 0 "BLOCK")
15
+ (cons 70 0)
16
+ (cons 2 "${escapeLispString(name)}")
17
+ (cons 10 (list 0 0 0))
18
+ )
19
+ )
20
+ ${entities}
21
+ (entmake (list (cons 0 "ENDBLK")))
22
+ "CREATED"
23
+ )
24
+ "EXISTS"
25
+ )
26
+ )`;
27
+ try {
28
+ const result = await cad.sendCommandWithResult(code);
29
+ if (result === 'CREATED' || result === '"CREATED"') {
30
+ return { content: [{ type: 'text', text: `已创建块: ${name}` }] };
31
+ }
32
+ if (result === 'EXISTS' || result === '"EXISTS"') {
33
+ return { content: [{ type: 'text', text: `块已存在: ${name}` }], isError: true };
34
+ }
35
+ return { content: [{ type: 'text', text: `创建失败: ${result}` }], isError: true };
36
+ } catch (e) {
37
+ return { content: [{ type: 'text', text: `错误: ${e.message}` }], isError: true };
38
+ }
39
+ }
40
+
41
+ export async function insertBlock(blockName, point, scale = 1, rotation = 0) {
42
+ if (!cad.connected) { await cad.connect(); }
43
+ if (!cad.connected) return { content: [{ type: 'text', text: '未连接 CAD' }], isError: true };
44
+
45
+ const coords = Array.isArray(point) ? point : point.split(',').map(s => parseFloat(s.trim()));
46
+ if (coords.length < 2) {
47
+ return { content: [{ type: 'text', text: '插入点格式错误,需要 x,y 或 [x,y,z]' }], isError: true };
48
+ }
49
+ const [x, y, z = 0] = coords;
50
+
51
+ const code = `(progn
52
+ (vl-load-com)
53
+ (if (tblsearch "BLOCK" "${escapeLispString(blockName)}")
54
+ (progn
55
+ (command "._INSERT" "${escapeLispString(blockName)}" (list ${x} ${y} ${z}) ${scale} ${rotation} 0 "")
56
+ "INSERTED"
57
+ )
58
+ "NOTFOUND"
59
+ )
60
+ )`;
61
+ try {
62
+ const result = await cad.sendCommandWithResult(code);
63
+ if (result === 'INSERTED' || result === '"INSERTED"') {
64
+ return { content: [{ type: 'text', text: `已插入块: ${blockName}` }] };
65
+ }
66
+ return { content: [{ type: 'text', text: `插入失败: ${result}` }], isError: true };
67
+ } catch (e) {
68
+ return { content: [{ type: 'text', text: `错误: ${e.message}` }], isError: true };
69
+ }
70
+ }
71
+
72
+ export async function getBlocks() {
73
+ if (!cad.connected) { await cad.connect(); }
74
+ if (!cad.connected) return { content: [{ type: 'text', text: '未连接 CAD' }], isError: true };
75
+
76
+ const code = `(progn
77
+ (vl-load-com)
78
+ (setq blocks nil)
79
+ (while (setq blk (tblnext "BLOCK" (null blocks)))
80
+ (setq blocks (cons (cdr (assoc 2 blk)) blocks))
81
+ )
82
+ (reverse blocks)
83
+ )`;
84
+ try {
85
+ const result = await cad.sendCommandWithResult(code);
86
+ if (!result || result === 'nil') {
87
+ return { content: [{ type: 'text', text: '当前图形中没有块定义' }] };
88
+ }
89
+ return { content: [{ type: 'text', text: result }] };
90
+ } catch (e) {
91
+ return { content: [{ type: 'text', text: `错误: ${e.message}` }], isError: true };
92
+ }
93
+ }
94
+
95
+ export async function batchGetBlockAttributes(args) {
96
+ if (!cad.connected) { await cad.connect(); }
97
+ if (!cad.connected) return mcpError('未连接 CAD');
98
+ try {
99
+ const filter = args.filter || '';
100
+ const blockName = args.blockName || '';
101
+ const lay = args.layer || '';
102
+ let lispFilter = '(ssget "_X" ';
103
+ const flist = [];
104
+ if (blockName) flist.push(`(cons 2 "${escapeLispString(blockName)}")`);
105
+ if (lay) flist.push(`(cons 8 "${escapeLispString(lay)}")`);
106
+ flist.push('(cons 0 "INSERT")');
107
+ lispFilter += `(list ${flist.join(' ')})`;
108
+
109
+ const code = `(progn
110
+ (vl-load-com)
111
+ (setq ss ${lispFilter})
112
+ (setq result nil)
113
+ (if ss
114
+ (progn
115
+ (vlax-for blk (vla-get-activeselectionset
116
+ (vla-get-activedocument (vlax-get-acad-object)))
117
+ (setq atts nil
118
+ atts-raw (vlax-invoke blk 'GetAttributes))
119
+ (if atts-raw
120
+ (foreach a atts-raw
121
+ (setq atts (cons (list (cons "tag" (vla-get-tagstring a))
122
+ (cons "value" (vla-get-textstring a))
123
+ (cons "handle" (vla-get-handle a))) atts)))
124
+ )
125
+ (setq result (cons (list (cons "handle" (vla-get-handle blk))
126
+ (cons "blockName" (vla-get-name blk))
127
+ (cons "layer" (vla-get-layer blk))
128
+ (cons "attributes" atts)) result))
129
+ )
130
+ )
131
+ )
132
+ (if result (vl-princ-to-string result) "[]")
133
+ )`;
134
+ const result = await cad.sendCommandWithResult(code);
135
+ return mcpSuccess(result || '[]');
136
+ } catch (e) {
137
+ return mcpError(`批量获取块属性失败: ${e.message}`);
138
+ }
139
+ }
140
+
141
+ export async function batchSetBlockAttributes(args) {
142
+ if (!cad.connected) { await cad.connect(); }
143
+ if (!cad.connected) return mcpError('未连接 CAD');
144
+ try {
145
+ const items = args.items || [];
146
+ let totalOk = 0;
147
+ let totalFail = 0;
148
+ const total = items.length;
149
+ for (let idx = 0; idx < total; idx++) {
150
+ const item = items[idx];
151
+ const np = getNotifyProgress();
152
+ if (np) np(idx + 1, total, `正在处理块 ${idx + 1}/${total}`);
153
+ try {
154
+ const handle = item.handle;
155
+ const attrs = item.attributes || {};
156
+ for (const [tag, value] of Object.entries(attrs)) {
157
+ await cad.sendCommandWithResult(
158
+ `(progn
159
+ (vl-load-com)
160
+ (if (setq ent (handent "${escapeLispString(handle)}"))
161
+ (progn
162
+ (setq vobj (vlax-ename->vla-object ent))
163
+ (setq atts (vlax-invoke vobj 'GetAttributes))
164
+ (if atts
165
+ (foreach a atts
166
+ (if (= (vla-get-tagstring a) "${escapeLispString(tag)}")
167
+ (vla-put-textstring a "${escapeLispString(String(value))}")
168
+ )
169
+ )
170
+ )
171
+ (princ "ok")
172
+ )
173
+ (princ "nf")
174
+ )
175
+ )`
176
+ );
177
+ }
178
+ totalOk++;
179
+ } catch (e) {
180
+ totalFail++;
181
+ }
182
+ }
183
+ const msg = `批量设置块属性完成: 成功 ${totalOk}, 失败 ${totalFail}`;
184
+ if (totalFail > 0) return mcpError(msg);
185
+ return mcpSuccess(msg);
186
+ } catch (e) {
187
+ return mcpError(`批量设置块属性失败: ${e.message}`);
188
+ }
189
+ }
190
+
191
+ export async function explodeBlock(handle) {
192
+ if (!cad.connected) { await cad.connect(); }
193
+ if (!cad.connected) return { content: [{ type: 'text', text: '未连接 CAD' }], isError: true };
194
+
195
+ const code = `(progn
196
+ (vl-load-com)
197
+ (if (setq ent (handent "${escapeLispString(handle)}"))
198
+ (progn
199
+ (command "._EXPLODE" (ssadd ent (ssadd)))
200
+ "EXPLODED"
201
+ )
202
+ "NOTFOUND"
203
+ )
204
+ )`;
205
+ try {
206
+ const result = await cad.sendCommandWithResult(code);
207
+ if (result === 'EXPLODED' || result === '"EXPLODED"') {
208
+ return { content: [{ type: 'text', text: `已炸开块: ${handle}` }] };
209
+ }
210
+ return { content: [{ type: 'text', text: `操作失败: ${result}` }], isError: true };
211
+ } catch (e) {
212
+ return { content: [{ type: 'text', text: `错误: ${e.message}` }], isError: true };
213
+ }
214
+ }