@atlisp/mcp 1.8.16 → 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 (34) hide show
  1. package/dist/atlisp-mcp.js +7 -7
  2. package/dist/handlers/3d-handlers.js +128 -0
  3. package/dist/handlers/batch-handlers.js +260 -0
  4. package/dist/handlers/block-handlers.js +214 -0
  5. package/dist/handlers/cad-handlers.js +180 -0
  6. package/dist/handlers/constraint-handlers.js +130 -0
  7. package/dist/handlers/dim-hatch-handlers.js +340 -0
  8. package/dist/handlers/draw-handlers.js +175 -0
  9. package/dist/handlers/edit-handlers.js +179 -0
  10. package/dist/handlers/entity-handlers.js +196 -0
  11. package/dist/handlers/external-handlers.js +218 -0
  12. package/dist/handlers/file-handlers.js +172 -0
  13. package/dist/handlers/function-handlers.js +158 -0
  14. package/dist/handlers/layer-handlers.js +181 -0
  15. package/dist/handlers/package-handlers.js +89 -0
  16. package/dist/handlers/parametric-handlers.js +272 -0
  17. package/dist/handlers/pdf-annotation-handlers.js +117 -0
  18. package/dist/handlers/prompt-handlers.js +9 -0
  19. package/dist/handlers/purge-handlers.js +137 -0
  20. package/dist/handlers/query-print-handlers.js +662 -0
  21. package/dist/handlers/resource-cache.js +63 -0
  22. package/dist/handlers/resource-defs.js +79 -0
  23. package/dist/handlers/resource-handlers.js +131 -0
  24. package/dist/handlers/resource-readers.js +1045 -0
  25. package/dist/handlers/sheetset-handlers.js +430 -0
  26. package/dist/handlers/spatial-handlers.js +174 -0
  27. package/dist/handlers/style-handlers.js +162 -0
  28. package/dist/handlers/text-handlers.js +198 -0
  29. package/dist/handlers/ucs-layout-handlers.js +271 -0
  30. package/dist/handlers/viewport-handlers.js +150 -0
  31. package/dist/handlers/xdata-handlers.js +148 -0
  32. package/dist/handlers/xref-handlers.js +334 -0
  33. package/dist/lisp-security.js +7 -2
  34. package/package.json +2 -2
@@ -0,0 +1,181 @@
1
+ import { cad } from '../cad.js';
2
+ import { escapeLispString } from '../handler-utils.js';
3
+
4
+ export async function createLayer(name, color = 7, linetype = 'Continuous') {
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 "LAYER" "${escapeLispString(name)}"))
11
+ (progn
12
+ (entmake
13
+ (list
14
+ (cons 0 "LAYER")
15
+ (cons 70 0)
16
+ (cons 2 "${escapeLispString(name)}")
17
+ (cons 62 ${color})
18
+ (cons 6 "${escapeLispString(linetype)}")
19
+ )
20
+ )
21
+ "CREATED"
22
+ )
23
+ "EXISTS"
24
+ )
25
+ )`;
26
+ try {
27
+ const result = await cad.sendCommandWithResult(code);
28
+ if (result === 'CREATED' || result === '"CREATED"') {
29
+ return { content: [{ type: 'text', text: `已创建图层: ${name}` }] };
30
+ }
31
+ if (result === 'EXISTS' || result === '"EXISTS"') {
32
+ return { content: [{ type: 'text', text: `图层已存在: ${name}` }] };
33
+ }
34
+ return { content: [{ type: 'text', text: `创建失败: ${result}` }], isError: true };
35
+ } catch (e) {
36
+ return { content: [{ type: 'text', text: `错误: ${e.message}` }], isError: true };
37
+ }
38
+ }
39
+
40
+ export async function deleteLayer(name) {
41
+ if (!cad.connected) { await cad.connect(); }
42
+ if (!cad.connected) return { content: [{ type: 'text', text: '未连接 CAD' }], isError: true };
43
+
44
+ const code = `(progn
45
+ (vl-load-com)
46
+ (cond
47
+ ((eq (getvar "CLAYER") "${escapeLispString(name)}")
48
+ "CURRENT")
49
+ ((tblsearch "LAYER" "${escapeLispString(name)}")
50
+ (command "._LAYER" "D" "${escapeLispString(name)}" "")
51
+ (if (not (tblsearch "LAYER" "${escapeLispString(name)}"))
52
+ "DELETED"
53
+ "FAILED"))
54
+ (t "NOTFOUND")
55
+ )
56
+ )`;
57
+ try {
58
+ const result = await cad.sendCommandWithResult(code);
59
+ if (result === 'DELETED' || result === '"DELETED"') {
60
+ return { content: [{ type: 'text', text: `已删除图层: ${name}` }] };
61
+ }
62
+ if (result === 'CURRENT' || result === '"CURRENT"') {
63
+ return { content: [{ type: 'text', text: `无法删除当前图层: ${name}` }], isError: true };
64
+ }
65
+ if (result === 'NOTFOUND' || result === '"NOTFOUND"') {
66
+ return { content: [{ type: 'text', text: `图层不存在: ${name}` }], isError: true };
67
+ }
68
+ return { content: [{ type: 'text', text: `删除失败: ${result}` }], isError: true };
69
+ } catch (e) {
70
+ return { content: [{ type: 'text', text: `错误: ${e.message}` }], isError: true };
71
+ }
72
+ }
73
+
74
+ export async function setLayerProperty(name, property, value) {
75
+ if (!cad.connected) { await cad.connect(); }
76
+ if (!cad.connected) return { content: [{ type: 'text', text: '未连接 CAD' }], isError: true };
77
+
78
+ let propCode = '';
79
+ switch (property) {
80
+ case 'color':
81
+ propCode = `(command "._LAYER" "P" "${escapeLispString(name)}" "C" ${isNaN(Number(value)) ? 7 : Number(value)} "")`;
82
+ break;
83
+ case 'linetype':
84
+ propCode = `(command "._LAYER" "P" "${escapeLispString(name)}" "L" "${escapeLispString(value)}" "")`;
85
+ break;
86
+ case 'freeze':
87
+ propCode = `(command "._LAYER" "F" "${escapeLispString(name)}" "")`;
88
+ break;
89
+ case 'thaw':
90
+ propCode = `(command "._LAYER" "T" "${escapeLispString(name)}" "")`;
91
+ break;
92
+ case 'lock':
93
+ propCode = `(command "._LAYER" "LO" "${escapeLispString(name)}" "")`;
94
+ break;
95
+ case 'unlock':
96
+ propCode = `(command "._LAYER" "U" "${escapeLispString(name)}" "")`;
97
+ break;
98
+ default:
99
+ return { content: [{ type: 'text', text: `不支持的属性: ${property}` }], isError: true };
100
+ }
101
+
102
+ const code = `(progn
103
+ (vl-load-com)
104
+ (if (tblsearch "LAYER" "${escapeLispString(name)}")
105
+ (progn
106
+ ${propCode}
107
+ "OK"
108
+ )
109
+ "NOTFOUND"
110
+ )
111
+ )`;
112
+ try {
113
+ const result = await cad.sendCommandWithResult(code);
114
+ if (result === 'OK' || result === '"OK"') {
115
+ return { content: [{ type: 'text', text: `已设置图层 ${name} 的 ${property} 为 ${value}` }] };
116
+ }
117
+ return { content: [{ type: 'text', text: `操作失败: ${result}` }], isError: true };
118
+ } catch (e) {
119
+ return { content: [{ type: 'text', text: `错误: ${e.message}` }], isError: true };
120
+ }
121
+ }
122
+
123
+ export async function setCurrentLayer(name) {
124
+ if (!cad.connected) { await cad.connect(); }
125
+ if (!cad.connected) return { content: [{ type: 'text', text: '未连接 CAD' }], isError: true };
126
+
127
+ const code = `(progn
128
+ (vl-load-com)
129
+ (if (tblsearch "LAYER" "${escapeLispString(name)}")
130
+ (progn
131
+ (setvar "CLAYER" "${escapeLispString(name)}")
132
+ "OK"
133
+ )
134
+ "NOTFOUND"
135
+ )
136
+ )`;
137
+ try {
138
+ const result = await cad.sendCommandWithResult(code);
139
+ if (result === 'OK' || result === '"OK"') {
140
+ return { content: [{ type: 'text', text: `已设置当前图层: ${name}` }] };
141
+ }
142
+ return { content: [{ type: 'text', text: `设置失败: ${result}` }], isError: true };
143
+ } catch (e) {
144
+ return { content: [{ type: 'text', text: `错误: ${e.message}` }], isError: true };
145
+ }
146
+ }
147
+ export async function layerIsolate(name) {
148
+ if (!cad.connected) { await cad.connect(); }
149
+ if (!cad.connected) return { content: [{ type: 'text', text: '未连接 CAD' }], isError: true };
150
+ try { await cad.sendCommand(`(command "_.LAYISO" "${escapeLispString(name)}" "")\n`); return { content: [{ type: 'text', text: `已隔离图层: ${name}` }] }; } catch (e) { return { content: [{ type: 'text', text: `错误: ${e.message}` }], isError: true }; }
151
+ }
152
+ export async function layerUnisolate() {
153
+ if (!cad.connected) { await cad.connect(); }
154
+ if (!cad.connected) return { content: [{ type: 'text', text: '未连接 CAD' }], isError: true };
155
+ try { await cad.sendCommand('(command "_.LAYUNISO")\n'); return { content: [{ type: 'text', text: '已取消图层隔离' }] }; } catch (e) { return { content: [{ type: 'text', text: `错误: ${e.message}` }], isError: true }; }
156
+ }
157
+ export async function layerFreezeAll() {
158
+ if (!cad.connected) { await cad.connect(); }
159
+ if (!cad.connected) return { content: [{ type: 'text', text: '未连接 CAD' }], isError: true };
160
+ try { await cad.sendCommand('(command "_.LAYER" "F" "*" "")\n'); return { content: [{ type: 'text', text: '已冻结所有图层' }] }; } catch (e) { return { content: [{ type: 'text', text: `错误: ${e.message}` }], isError: true }; }
161
+ }
162
+ export async function layerThawAll() {
163
+ if (!cad.connected) { await cad.connect(); }
164
+ if (!cad.connected) return { content: [{ type: 'text', text: '未连接 CAD' }], isError: true };
165
+ try { await cad.sendCommand('(command "_.LAYER" "T" "*" "")\n'); return { content: [{ type: 'text', text: '已解冻所有图层' }] }; } catch (e) { return { content: [{ type: 'text', text: `错误: ${e.message}` }], isError: true }; }
166
+ }
167
+ export async function layerLockAll() {
168
+ if (!cad.connected) { await cad.connect(); }
169
+ if (!cad.connected) return { content: [{ type: 'text', text: '未连接 CAD' }], isError: true };
170
+ try { await cad.sendCommand('(command "_.LAYER" "LO" "*" "")\n'); return { content: [{ type: 'text', text: '已锁定所有图层' }] }; } catch (e) { return { content: [{ type: 'text', text: `错误: ${e.message}` }], isError: true }; }
171
+ }
172
+ export async function layerUnlockAll() {
173
+ if (!cad.connected) { await cad.connect(); }
174
+ if (!cad.connected) return { content: [{ type: 'text', text: '未连接 CAD' }], isError: true };
175
+ try { await cad.sendCommand('(command "_.LAYER" "U" "*" "")\n'); return { content: [{ type: 'text', text: '已解锁所有图层' }] }; } catch (e) { return { content: [{ type: 'text', text: `错误: ${e.message}` }], isError: true }; }
176
+ }
177
+ export async function layerMerge(sourceName, targetName) {
178
+ if (!cad.connected) { await cad.connect(); }
179
+ if (!cad.connected) return { content: [{ type: 'text', text: '未连接 CAD' }], isError: true };
180
+ try { await cad.sendCommand(`(command "_.LAYMRG" "${escapeLispString(sourceName)}" "" "${escapeLispString(targetName)}" "Y")\n`); return { content: [{ type: 'text', text: `已将图层 ${sourceName} 合并到 ${targetName}` }] }; } catch (e) { return { content: [{ type: 'text', text: `错误: ${e.message}` }], isError: true }; }
181
+ }
@@ -0,0 +1,89 @@
1
+ import { log, error as logError } from '../logger.js';
2
+ const PACKAGES_LIST_URL = process.env.PACKAGES_LIST_URL || 'http://s3.atlisp.cn/packages-list?fmt=json';
3
+ import { cad } from '../cad.js';
4
+ import { MOCK_PACKAGES } from '../constants.js';
5
+ let cachedPackages = null;
6
+ let cachedAt = null;
7
+ const CACHE_TTL = 10 * 60 * 1000;
8
+
9
+ async function fetchPackages() {
10
+ const now = Date.now();
11
+ if (cachedPackages && cachedAt && (now - cachedAt) < CACHE_TTL) {
12
+ return cachedPackages;
13
+ }
14
+ try {
15
+ const response = await fetch(PACKAGES_LIST_URL, {
16
+ headers: { 'User-Agent': 'atlisp-mcp' },
17
+ signal: AbortSignal.timeout(10000),
18
+ });
19
+ if (response.ok) {
20
+ const data = await response.json();
21
+ cachedPackages = data;
22
+ cachedAt = now;
23
+ return data;
24
+ }
25
+ } catch (e) { logError(`Package fetch error: ${e.message}`); }
26
+ return cachedPackages || MOCK_PACKAGES;
27
+ }
28
+
29
+ function flattenPackages(data) {
30
+ if (Array.isArray(data)) return data;
31
+ if (data && Array.isArray(data.packages)) return data.packages;
32
+ return [];
33
+ }
34
+
35
+ export async function listPackages() {
36
+ if (!cad.connected) await cad.connect();
37
+ if (!cad.connected) {
38
+ const data = await fetchPackages();
39
+ const items = flattenPackages(data);
40
+ const text = items.length
41
+ ? items.map(p => `${p.name} v${p.version || ''} - ${p.description || ''}`).join('\n')
42
+ : '无可用包';
43
+ return { content: [{ type: 'text', text }] };
44
+ }
45
+ const result = await cad.sendCommandWithResult('(@::package-list-in-local)');
46
+ if (result && result !== 'nil') return { content: [{ type: 'text', text: result }] };
47
+ const data = await fetchPackages();
48
+ const items = flattenPackages(data);
49
+ const text = items.length
50
+ ? `从注册表获取的 @lisp 包:\n${items.map(p => `${p.name} v${p.version || ''} - ${p.description || ''}`).join('\n')}`
51
+ : MOCK_PACKAGES.map(p => `${p.name} v${p.version} - ${p.description}`).join('\n');
52
+ return { content: [{ type: 'text', text: `已安装的 @lisp 包:\n${text}` }] };
53
+ }
54
+
55
+ export async function searchPackages(query) {
56
+ const data = await fetchPackages();
57
+ if (!data) {
58
+ return { content: [{ type: 'text', text: '无法获取包列表' }], isError: true };
59
+ }
60
+ const items = flattenPackages(data);
61
+ const results = [];
62
+ if (query) {
63
+ const q = query.toLowerCase();
64
+ for (const p of items) {
65
+ const name = (p.name || '').toLowerCase();
66
+ const desc = (p.description || '').toLowerCase();
67
+ if (name.includes(q) || desc.includes(q)) results.push(p);
68
+ }
69
+ } else {
70
+ for (const p of items) results.push(p);
71
+ }
72
+ if (results.length === 0) {
73
+ return { content: [{ type: 'text', text: `未找到包含 "${query}" 的包` }] };
74
+ }
75
+ return { content: [{ type: 'text', text: `搜索结果 (${results.length}):\n${results.map(p => `${p.name} v${p.version || ''} - ${p.description || ''}`).join('\n')}` }] };
76
+ }
77
+
78
+ export async function installPackage(packageName) {
79
+ const data = await fetchPackages();
80
+ const items = flattenPackages(data);
81
+ const pkg = items.find(p => p.name === packageName);
82
+ if (!pkg) {
83
+ return { content: [{ type: 'text', text: `错误: 包 "${packageName}" 不存在` }], isError: true };
84
+ }
85
+ if (cad.connected) {
86
+ await cad.sendCommand(`(@::load-module '${packageName})\n`);
87
+ }
88
+ return { content: [{ type: 'text', text: `包 "${packageName}" 安装命令已发送!` }] };
89
+ }
@@ -0,0 +1,272 @@
1
+ import { cad } from '../cad.js';
2
+ import { mcpSuccess, mcpError, escapeLispString } from '../handler-utils.js';
3
+
4
+ function esc(s) {
5
+ return escapeLispString(String(s || ''));
6
+ }
7
+
8
+ export async function getDynamicBlockProperties(args) {
9
+ try {
10
+ if (!cad.connected) await cad.connect();
11
+ if (!cad.connected) return mcpError('未连接 CAD');
12
+ const handle = esc(args.blockHandle);
13
+ const code = `(progn
14
+ (vl-load-com)
15
+ (if (setq ent (handent "${handle}"))
16
+ (progn
17
+ (setq vobj (vlax-ename->vla-object ent))
18
+ (setq dynProps (vl-catch-all-apply 'vlax-invoke (list vobj 'GetDynamicBlockProperties)))
19
+ (if (vl-catch-all-error-p dynProps)
20
+ "NotDynamicBlock"
21
+ (progn
22
+ (setq result nil)
23
+ (foreach p dynProps
24
+ (setq allowed (vl-catch-all-apply 'vlax-invoke (list p 'GetAllowedValues)))
25
+ (if (vl-catch-all-error-p allowed) (setq allowed nil))
26
+ (setq result (cons (list
27
+ (cons "propertyName" (vla-get-propertyname p))
28
+ (cons "value" (vl-princ-to-string (vla-get-value p)))
29
+ (cons "typeCode" (vla-get-propertytype p))
30
+ (cons "allowedValues" (if allowed (vl-princ-to-string allowed) nil))
31
+ ) result))
32
+ )
33
+ (vl-princ-to-string (reverse result))
34
+ )
35
+ )
36
+ )
37
+ "EntityNotFound"
38
+ )
39
+ )`;
40
+ const result = await cad.sendCommandWithResult(code);
41
+ return mcpSuccess(result);
42
+ } catch (e) {
43
+ return mcpError(`错误: ${e.message}`);
44
+ }
45
+ }
46
+
47
+ export async function setDynamicBlockProperty(args) {
48
+ try {
49
+ if (!cad.connected) await cad.connect();
50
+ if (!cad.connected) return mcpError('未连接 CAD');
51
+ const handle = esc(args.blockHandle);
52
+ const propName = esc(args.propertyName);
53
+ const value = esc(args.value);
54
+ const code = `(progn
55
+ (vl-load-com)
56
+ (if (setq ent (handent "${handle}"))
57
+ (progn
58
+ (setq vobj (vlax-ename->vla-object ent))
59
+ (setq dynProps (vl-catch-all-apply 'vlax-invoke (list vobj 'GetDynamicBlockProperties)))
60
+ (if (vl-catch-all-error-p dynProps)
61
+ "NotDynamicBlock"
62
+ (progn
63
+ (setq found nil)
64
+ (foreach p dynProps
65
+ (if (= (strcase (vla-get-propertyname p)) (strcase "${propName}"))
66
+ (progn
67
+ (setq numVal (distof "${value}" 2))
68
+ (if numVal
69
+ (vla-put-value p numVal)
70
+ (vla-put-value p "${value}")
71
+ )
72
+ (setq found T)
73
+ )
74
+ )
75
+ )
76
+ (vla-update vobj)
77
+ (if found "ok" "PropertyNotFound")
78
+ )
79
+ )
80
+ )
81
+ "EntityNotFound"
82
+ )
83
+ )`;
84
+ const result = await cad.sendCommandWithResult(code);
85
+ if (result === 'ok') return mcpSuccess(`属性 ${args.propertyName} 已设置为 ${args.value}`);
86
+ return mcpError(`设置失败: ${result}`);
87
+ } catch (e) {
88
+ return mcpError(`错误: ${e.message}`);
89
+ }
90
+ }
91
+
92
+ export async function getBlockParameters(args) {
93
+ try {
94
+ if (!cad.connected) await cad.connect();
95
+ if (!cad.connected) return mcpError('未连接 CAD');
96
+ const handle = esc(args.blockHandle);
97
+ const code = `(progn
98
+ (vl-load-com)
99
+ (if (setq ent (handent "${handle}"))
100
+ (progn
101
+ (setq vobj (vlax-ename->vla-object ent))
102
+ (setq dynProps (vl-catch-all-apply 'vlax-invoke (list vobj 'GetDynamicBlockProperties)))
103
+ (if (vl-catch-all-error-p dynProps)
104
+ "NotDynamicBlock"
105
+ (progn
106
+ (setq result nil)
107
+ (foreach p dynProps
108
+ (setq tc (vla-get-propertytype p))
109
+ (if (>= tc 3)
110
+ (progn
111
+ (setq allowed (vl-catch-all-apply 'vlax-invoke (list p 'GetAllowedValues)))
112
+ (if (vl-catch-all-error-p allowed) (setq allowed nil))
113
+ (setq result (cons (list
114
+ (cons "parameterName" (vla-get-propertyname p))
115
+ (cons "value" (vl-princ-to-string (vla-get-value p)))
116
+ (cons "typeCode" tc)
117
+ (cons "allowedValues" (if allowed (vl-princ-to-string allowed) nil))
118
+ ) result))
119
+ )
120
+ )
121
+ )
122
+ (vl-princ-to-string (reverse result))
123
+ )
124
+ )
125
+ )
126
+ "EntityNotFound"
127
+ )
128
+ )`;
129
+ const result = await cad.sendCommandWithResult(code);
130
+ return mcpSuccess(result);
131
+ } catch (e) {
132
+ return mcpError(`错误: ${e.message}`);
133
+ }
134
+ }
135
+
136
+ export async function setBlockParameter(args) {
137
+ try {
138
+ if (!cad.connected) await cad.connect();
139
+ if (!cad.connected) return mcpError('未连接 CAD');
140
+ const handle = esc(args.blockHandle);
141
+ const paramName = esc(args.parameterName);
142
+ const value = esc(args.value);
143
+ const code = `(progn
144
+ (vl-load-com)
145
+ (if (setq ent (handent "${handle}"))
146
+ (progn
147
+ (setq vobj (vlax-ename->vla-object ent))
148
+ (setq dynProps (vl-catch-all-apply 'vlax-invoke (list vobj 'GetDynamicBlockProperties)))
149
+ (if (vl-catch-all-error-p dynProps)
150
+ "NotDynamicBlock"
151
+ (progn
152
+ (setq found nil)
153
+ (foreach p dynProps
154
+ (if (and (>= (vla-get-propertytype p) 3)
155
+ (= (strcase (vla-get-propertyname p)) (strcase "${paramName}")))
156
+ (progn
157
+ (setq numVal (distof "${value}" 2))
158
+ (if numVal
159
+ (vla-put-value p numVal)
160
+ (vla-put-value p "${value}")
161
+ )
162
+ (setq found T)
163
+ )
164
+ )
165
+ )
166
+ (vla-update vobj)
167
+ (if found "ok" "ParameterNotFound")
168
+ )
169
+ )
170
+ )
171
+ "EntityNotFound"
172
+ )
173
+ )`;
174
+ const result = await cad.sendCommandWithResult(code);
175
+ if (result === 'ok') return mcpSuccess(`参数 ${args.parameterName} 已设置为 ${args.value}`);
176
+ return mcpError(`设置失败: ${result}`);
177
+ } catch (e) {
178
+ return mcpError(`错误: ${e.message}`);
179
+ }
180
+ }
181
+
182
+ export async function listVisibilityStates(args) {
183
+ try {
184
+ if (!cad.connected) await cad.connect();
185
+ if (!cad.connected) return mcpError('未连接 CAD');
186
+ const handle = esc(args.blockHandle);
187
+ const code = `(progn
188
+ (vl-load-com)
189
+ (if (setq ent (handent "${handle}"))
190
+ (progn
191
+ (setq vobj (vlax-ename->vla-object ent))
192
+ (setq dynProps (vl-catch-all-apply 'vlax-invoke (list vobj 'GetDynamicBlockProperties)))
193
+ (if (vl-catch-all-error-p dynProps)
194
+ "NotDynamicBlock"
195
+ (progn
196
+ (setq visProp nil)
197
+ (foreach p dynProps
198
+ (if (= (strcase (vla-get-propertyname p)) "VISIBILITY")
199
+ (setq visProp p)
200
+ )
201
+ )
202
+ (if visProp
203
+ (progn
204
+ (setq allowed (vl-catch-all-apply 'vlax-invoke (list visProp 'GetAllowedValues)))
205
+ (if (vl-catch-all-error-p allowed) (setq allowed nil))
206
+ (setq current (vl-princ-to-string (vla-get-value visProp)))
207
+ (setq states nil)
208
+ (foreach s allowed
209
+ (setq states (cons (list
210
+ (cons "name" s)
211
+ (cons "isActive" (= (strcase (vl-princ-to-string s)) (strcase current)))
212
+ ) states))
213
+ )
214
+ (vl-princ-to-string (reverse states))
215
+ )
216
+ "NoVisibilityProperty"
217
+ )
218
+ )
219
+ )
220
+ )
221
+ "EntityNotFound"
222
+ )
223
+ )`;
224
+ const result = await cad.sendCommandWithResult(code);
225
+ return mcpSuccess(result);
226
+ } catch (e) {
227
+ return mcpError(`错误: ${e.message}`);
228
+ }
229
+ }
230
+
231
+ export async function setVisibilityState(args) {
232
+ try {
233
+ if (!cad.connected) await cad.connect();
234
+ if (!cad.connected) return mcpError('未连接 CAD');
235
+ const handle = esc(args.blockHandle);
236
+ const stateName = esc(args.stateName);
237
+ const code = `(progn
238
+ (vl-load-com)
239
+ (if (setq ent (handent "${handle}"))
240
+ (progn
241
+ (setq vobj (vlax-ename->vla-object ent))
242
+ (setq dynProps (vl-catch-all-apply 'vlax-invoke (list vobj 'GetDynamicBlockProperties)))
243
+ (if (vl-catch-all-error-p dynProps)
244
+ "NotDynamicBlock"
245
+ (progn
246
+ (setq visProp nil)
247
+ (foreach p dynProps
248
+ (if (= (strcase (vla-get-propertyname p)) "VISIBILITY")
249
+ (setq visProp p)
250
+ )
251
+ )
252
+ (if visProp
253
+ (progn
254
+ (vla-put-value visProp "${stateName}")
255
+ (vla-update vobj)
256
+ "ok"
257
+ )
258
+ "NoVisibilityProperty"
259
+ )
260
+ )
261
+ )
262
+ )
263
+ "EntityNotFound"
264
+ )
265
+ )`;
266
+ const result = await cad.sendCommandWithResult(code);
267
+ if (result === 'ok') return mcpSuccess(`可见性状态已切换为: ${args.stateName}`);
268
+ return mcpError(`设置失败: ${result}`);
269
+ } catch (e) {
270
+ return mcpError(`错误: ${e.message}`);
271
+ }
272
+ }
@@ -0,0 +1,117 @@
1
+ import { cad } from '../cad.js';
2
+ import { log } from '../logger.js';
3
+ import { mcpSuccess, mcpError, ensureCadConnected, escapeLispString } from '../handler-utils.js';
4
+
5
+ export async function attachPdf(point, pdfPath, scale = 1, rotation = 0) {
6
+ try { await ensureCadConnected(); const pt = Array.isArray(point) ? point.join(' ') : point; await cad.sendCommand(`(command "_.pdfattach" "${escapeLispString(pdfPath)}" "${escapeLispString(pt)}" "${scale}" "${rotation}")`); return mcpSuccess(JSON.stringify({ pdfPath, point: pt, scale, rotation })); } catch (e) { return mcpError(`错误: ${e.message}`); }
7
+ }
8
+
9
+ export async function listAttachedPdfs() {
10
+ try {
11
+ await ensureCadConnected();
12
+ const result = await cad.sendCommandWithResult(`(progn
13
+ (setq i -1 pdfs nil ss (ssget "X" (list (cons 0 "PDFREFERENCE"))))
14
+ (if ss (repeat (sslength ss) (setq ent (ssname ss (setq i (1+ i))) pdfs (cons (cdr (assoc -1 (entget ent))) pdfs))))
15
+ (princ (vl-prin1-to-string (reverse pdfs)))
16
+ )`);
17
+ let handles = [];
18
+ if (result && result !== 'nil') { try { handles = JSON.parse(result); } catch { handles = []; } }
19
+ return mcpSuccess(JSON.stringify({ handles, count: handles.length }));
20
+ } catch (e) { return mcpError(`错误: ${e.message}`); }
21
+ }
22
+
23
+ export async function reloadPdf(pdfHandle) {
24
+ try { await ensureCadConnected(); const result = await cad.sendCommandWithResult(`(progn (command "_.pdfreload" (handent "${escapeLispString(pdfHandle)}")) (princ "reloaded"))`); return mcpSuccess(JSON.stringify({ handle: pdfHandle, reloaded: result?.includes('reloaded') })); } catch (e) { return mcpError(`错误: ${e.message}`); }
25
+ }
26
+
27
+ export async function detachPdf(pdfHandle) {
28
+ try { await ensureCadConnected(); await cad.sendCommand(`(entdel (handent "${escapeLispString(pdfHandle)}"))`); return mcpSuccess(JSON.stringify({ handle: pdfHandle, detached: true })); } catch (e) { return mcpError(`错误: ${e.message}`); }
29
+ }
30
+
31
+ export async function getPdfInfo(pdfHandle) {
32
+ try {
33
+ await ensureCadConnected();
34
+ const result = await cad.sendCommandWithResult(`(progn
35
+ (setq ent (handent "${escapeLispString(pdfHandle)}"))
36
+ (if ent (princ (vl-prin1-to-string (list (cons "path" (cdr (assoc 1 (entget ent)))) (cons "name" (cdr (assoc 2 (entget ent))))))) (princ "nil"))
37
+ )`);
38
+ let info = {};
39
+ if (result && result !== 'nil') { try { info = JSON.parse(result); } catch { info = {}; } }
40
+ return mcpSuccess(JSON.stringify({ handle: pdfHandle, info }));
41
+ } catch (e) { return mcpError(`错误: ${e.message}`); }
42
+ }
43
+
44
+ export async function createDgnUnderlay(dgnPath, point, scale = 1) {
45
+ try { await ensureCadConnected(); const pt = Array.isArray(point) ? point.join(' ') : point; await cad.sendCommand(`(command "_.dgnattach" "${escapeLispString(dgnPath)}" "${escapeLispString(pt)}" "${scale}")`); return mcpSuccess(JSON.stringify({ dgnPath, point: pt, scale })); } catch (e) { return mcpError(`错误: ${e.message}`); }
46
+ }
47
+
48
+ export async function createDwfUnderlay(dwfPath, point, scale = 1) {
49
+ try { await ensureCadConnected(); const pt = Array.isArray(point) ? point.join(' ') : point; await cad.sendCommand(`(command "_.dwfattach" "${escapeLispString(dwfPath)}" "${escapeLispString(pt)}" "${scale}")`); return mcpSuccess(JSON.stringify({ dwfPath, point: pt, scale })); } catch (e) { return mcpError(`错误: ${e.message}`); }
50
+ }
51
+
52
+ export async function importDxf(dxfPath, explode = false) {
53
+ try { await ensureCadConnected(); await cad.sendCommand(`(command "_.dxfin" "${escapeLispString(dxfPath)}" ${explode ? '"explode"' : ''})`); return mcpSuccess(JSON.stringify({ dxfPath, explode })); } catch (e) { return mcpError(`错误: ${e.message}`); }
54
+ }
55
+
56
+ export async function importDgn(sourceFile, targetFile = '') {
57
+ try { await ensureCadConnected(); await cad.sendCommand(`(command "_.dgnin" "${escapeLispString(sourceFile)}" "${escapeLispString(targetFile)}")`); return mcpSuccess(JSON.stringify({ sourceFile, targetFile })); } catch (e) { return mcpError(`错误: ${e.message}`); }
58
+ }
59
+
60
+ export async function exportDgn(filePath) {
61
+ try { await ensureCadConnected(); await cad.sendCommand(`(command "_.dgnout" "${escapeLispString(filePath)}")`); return mcpSuccess(JSON.stringify({ filePath })); } catch (e) { return mcpError(`错误: ${e.message}`); }
62
+ }
63
+
64
+ export async function createHyperlink(handle, url, description = '') {
65
+ try {
66
+ await ensureCadConnected();
67
+ const result = await cad.sendCommandWithResult(`(progn
68
+ (vl-load-com)
69
+ (setq ent (handent "${escapeLispString(handle)}"))
70
+ (if ent (progn
71
+ (vla-put-hyperlinks (vlax-ename->vla-object ent) (vlax-add (vla-get-hyperlinks (vlax-ename->vla-object ent)) "${escapeLispString(url)}" "${escapeLispString(description)}"))
72
+ (princ "added")) (princ "nil"))
73
+ )`);
74
+ return mcpSuccess(JSON.stringify({ handle, url, description, added: result?.includes('added') }));
75
+ } catch (e) { return mcpError(`错误: ${e.message}`); }
76
+ }
77
+
78
+ export async function removeHyperlink(handle) {
79
+ try {
80
+ await ensureCadConnected();
81
+ const result = await cad.sendCommandWithResult(`(progn
82
+ (vl-load-com)
83
+ (setq ent (handent "${escapeLispString(handle)}"))
84
+ (if ent (progn (vla-clear (vla-get-hyperlinks (vlax-ename->vla-object ent))) (princ "removed")) (princ "nil"))
85
+ )`);
86
+ return mcpSuccess(JSON.stringify({ handle, removed: result?.includes('removed') }));
87
+ } catch (e) { return mcpError(`错误: ${e.message}`); }
88
+ }
89
+
90
+ export async function batchAttachPdfs(pdfFiles, basePoint, spacing = 0, direction = 'x') {
91
+ try {
92
+ await ensureCadConnected();
93
+ const results = [];
94
+ const pt = Array.isArray(basePoint) ? basePoint.join(' ') : basePoint;
95
+ for (let i = 0; i < pdfFiles.length; i++) {
96
+ try {
97
+ const offsetX = direction === 'x' ? 0 : spacing * i;
98
+ const offsetY = direction === 'y' ? 0 : spacing * i;
99
+ await cad.sendCommand(`(command "_.pdfattach" "${escapeLispString(pdfFiles[i])}" (getvar "viewctr") "1" "0")`);
100
+ if (spacing > 0 && i > 0) { await cad.sendCommand(`(command "_.move" "l" "" (getvar "viewctr") (list ${offsetX} ${offsetY} 0))`); }
101
+ results.push({ file: pdfFiles[i], success: true });
102
+ } catch (e) { results.push({ file: pdfFiles[i], error: e.message, success: false }); }
103
+ }
104
+ return mcpSuccess(JSON.stringify(results));
105
+ } catch (e) { return mcpError(`错误: ${e.message}`); }
106
+ }
107
+
108
+ export async function savePdfLayout(layoutName, outputPath, plotDevice = 'DWG to PDF.pc3', paperSize = 'A4') {
109
+ try {
110
+ await ensureCadConnected();
111
+ const result = await cad.sendCommandWithResult(`(progn
112
+ (command "_.plot" "y" "${escapeLispString(layoutName)}" "${escapeLispString(plotDevice)}" "${escapeLispString(paperSize)}" "Landscape" "n" "n" "n" "n" "n" "${escapeLispString(outputPath)}")
113
+ (princ "saved")
114
+ )`);
115
+ return mcpSuccess(JSON.stringify({ layoutName, outputPath, saved: result?.includes('saved') || result?.includes('配置') }));
116
+ } catch (e) { return mcpError(`错误: ${e.message}`); }
117
+ }
@@ -0,0 +1,9 @@
1
+ import { listPrompts as loaderList, getPrompt as loaderGet } from '../prompts/loader.js';
2
+
3
+ export async function listPrompts() {
4
+ return loaderList();
5
+ }
6
+
7
+ export async function getPrompt(name, arguments_ = {}) {
8
+ return loaderGet(name, arguments_);
9
+ }