indesign-cli 0.2.0__py3-none-any.whl

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 (72) hide show
  1. cli_anything/indesign/README.md +32 -0
  2. cli_anything/indesign/__init__.py +1 -0
  3. cli_anything/indesign/__main__.py +5 -0
  4. cli_anything/indesign/core/artifacts.py +57 -0
  5. cli_anything/indesign/core/catalog.py +405 -0
  6. cli_anything/indesign/core/domains.py +178 -0
  7. cli_anything/indesign/core/envelope.py +65 -0
  8. cli_anything/indesign/core/errors.py +30 -0
  9. cli_anything/indesign/core/health.py +46 -0
  10. cli_anything/indesign/core/hidden_backend.py +116 -0
  11. cli_anything/indesign/core/hidden_handler_schemas.py +223 -0
  12. cli_anything/indesign/core/mcp_backend.py +152 -0
  13. cli_anything/indesign/core/node_setup.py +35 -0
  14. cli_anything/indesign/core/paths.py +41 -0
  15. cli_anything/indesign/core/plugins/__init__.py +2 -0
  16. cli_anything/indesign/core/plugins/backend.py +90 -0
  17. cli_anything/indesign/core/plugins/discovery.py +69 -0
  18. cli_anything/indesign/core/plugins/host_actions.py +76 -0
  19. cli_anything/indesign/core/plugins/install.py +38 -0
  20. cli_anything/indesign/core/plugins/manifest.py +279 -0
  21. cli_anything/indesign/core/plugins/validate.py +181 -0
  22. cli_anything/indesign/core/router.py +217 -0
  23. cli_anything/indesign/core/runtime.py +59 -0
  24. cli_anything/indesign/core/scripts.py +44 -0
  25. cli_anything/indesign/core/session.py +68 -0
  26. cli_anything/indesign/indesign_cli.py +320 -0
  27. cli_anything/indesign/node/hidden_handler_bridge.mjs +111 -0
  28. cli_anything/indesign/server/package-lock.json +168 -0
  29. cli_anything/indesign/server/package.json +45 -0
  30. cli_anything/indesign/server/src/advanced/index.js +76 -0
  31. cli_anything/indesign/server/src/core/InDesignMCPServer.js +273 -0
  32. cli_anything/indesign/server/src/core/scriptExecutor.js +271 -0
  33. cli_anything/indesign/server/src/core/sessionManager.js +545 -0
  34. cli_anything/indesign/server/src/handlers/advancedTemplateHandlers.js +1072 -0
  35. cli_anything/indesign/server/src/handlers/bookHandlers.js +490 -0
  36. cli_anything/indesign/server/src/handlers/documentHandlers.js +1472 -0
  37. cli_anything/indesign/server/src/handlers/exportHandlers.js +208 -0
  38. cli_anything/indesign/server/src/handlers/graphicsHandlers.js +605 -0
  39. cli_anything/indesign/server/src/handlers/groupHandlers.js +358 -0
  40. cli_anything/indesign/server/src/handlers/helpHandlers.js +347 -0
  41. cli_anything/indesign/server/src/handlers/index.js +77 -0
  42. cli_anything/indesign/server/src/handlers/layerHandlers.js +75 -0
  43. cli_anything/indesign/server/src/handlers/masterSpreadHandlers.js +451 -0
  44. cli_anything/indesign/server/src/handlers/pageHandlers.js +698 -0
  45. cli_anything/indesign/server/src/handlers/pageItemHandlers.js +704 -0
  46. cli_anything/indesign/server/src/handlers/presentationHandlers.js +220 -0
  47. cli_anything/indesign/server/src/handlers/spreadHandlers.js +348 -0
  48. cli_anything/indesign/server/src/handlers/styleHandlers.js +458 -0
  49. cli_anything/indesign/server/src/handlers/textHandlers.js +431 -0
  50. cli_anything/indesign/server/src/handlers/utilityHandlers.js +83 -0
  51. cli_anything/indesign/server/src/index.js +17 -0
  52. cli_anything/indesign/server/src/types/index.js +106 -0
  53. cli_anything/indesign/server/src/types/toolDefinitionsAdvancedTemplates.js +144 -0
  54. cli_anything/indesign/server/src/types/toolDefinitionsBook.js +224 -0
  55. cli_anything/indesign/server/src/types/toolDefinitionsContent.js +353 -0
  56. cli_anything/indesign/server/src/types/toolDefinitionsDocument.js +409 -0
  57. cli_anything/indesign/server/src/types/toolDefinitionsExport.js +65 -0
  58. cli_anything/indesign/server/src/types/toolDefinitionsLayer.js +40 -0
  59. cli_anything/indesign/server/src/types/toolDefinitionsMasterSpread.js +160 -0
  60. cli_anything/indesign/server/src/types/toolDefinitionsPage.js +271 -0
  61. cli_anything/indesign/server/src/types/toolDefinitionsPageItemGroup.js +437 -0
  62. cli_anything/indesign/server/src/types/toolDefinitionsPresentation.js +83 -0
  63. cli_anything/indesign/server/src/types/toolDefinitionsSpread.js +158 -0
  64. cli_anything/indesign/server/src/types/toolDefinitionsUtility.js +40 -0
  65. cli_anything/indesign/server/src/utils/stringUtils.js +107 -0
  66. cli_anything/indesign/skills/SKILL.md +198 -0
  67. indesign_cli-0.2.0.dist-info/METADATA +267 -0
  68. indesign_cli-0.2.0.dist-info/RECORD +72 -0
  69. indesign_cli-0.2.0.dist-info/WHEEL +5 -0
  70. indesign_cli-0.2.0.dist-info/entry_points.txt +3 -0
  71. indesign_cli-0.2.0.dist-info/licenses/LICENSE +21 -0
  72. indesign_cli-0.2.0.dist-info/top_level.txt +1 -0
@@ -0,0 +1,1072 @@
1
+ import fs from 'fs';
2
+ import path from 'path';
3
+ import { ScriptExecutor } from '../core/scriptExecutor.js';
4
+ import {
5
+ escapeFilePathForJsx,
6
+ escapeJsxString,
7
+ normalizeFsPathForJsx,
8
+ formatResponse,
9
+ formatErrorResponse
10
+ } from '../utils/stringUtils.js';
11
+
12
+ const JSON_HELPERS_SNIPPET = `
13
+ function __mcpSeenContains(arr, value) {
14
+ for (var i = 0; i < arr.length; i++) {
15
+ if (arr[i] === value) {
16
+ return true;
17
+ }
18
+ }
19
+ return false;
20
+ }
21
+ function __mcpEscapeJsonString(str) {
22
+ if (str === null || str === undefined) return "";
23
+ var result = "";
24
+ var backslash = String.fromCharCode(92);
25
+ for (var i = 0; i < str.length; i++) {
26
+ var ch = str.charAt(i);
27
+ var code = str.charCodeAt(i);
28
+ if (code === 34) { // "
29
+ result += backslash + '"';
30
+ } else if (code === 92) { // \
31
+ result += backslash + backslash;
32
+ } else if (code === 8) { // \b
33
+ result += backslash + "b";
34
+ } else if (code === 9) { // \t
35
+ result += backslash + "t";
36
+ } else if (code === 10) { // \n
37
+ result += backslash + "n";
38
+ } else if (code === 12) { // \f
39
+ result += backslash + "f";
40
+ } else if (code === 13) { // \r
41
+ result += backslash + "r";
42
+ } else if (code === 0x2028 || code === 0x2029) {
43
+ result += backslash + "u" + code.toString(16);
44
+ } else if (code < 32) {
45
+ var hex = code.toString(16);
46
+ result += backslash + "u" + ("0000" + hex).slice(-4);
47
+ } else {
48
+ result += ch;
49
+ }
50
+ }
51
+ return result;
52
+ }
53
+ function __mcpSerialize(value) {
54
+ var seen = [];
55
+ function serialize(v) {
56
+ if (v === null) return "null";
57
+ var t = typeof v;
58
+ if (t === "number" || t === "boolean") {
59
+ return String(v);
60
+ }
61
+ if (t === "string") {
62
+ return "\\""+__mcpEscapeJsonString(v)+"\\"";
63
+ }
64
+ if (v instanceof Array) {
65
+ var arr = [];
66
+ for (var i = 0; i < v.length; i++) {
67
+ arr.push(serialize(v[i]));
68
+ }
69
+ return "[" + arr.join(",") + "]";
70
+ }
71
+ if (t === "object") {
72
+ if (__mcpSeenContains(seen, v)) {
73
+ return '"[Circular]"';
74
+ }
75
+ seen.push(v);
76
+ var props = [];
77
+ for (var key in v) {
78
+ if (!v.hasOwnProperty(key)) continue;
79
+ props.push("\\"" + __mcpEscapeJsonString(key) + "\\":" + serialize(v[key]));
80
+ }
81
+ seen.pop();
82
+ return "{" + props.join(",") + "}";
83
+ }
84
+ return "null";
85
+ }
86
+ return serialize(value);
87
+ }
88
+ `;
89
+
90
+ const LABEL_PARSER_SNIPPET = `
91
+ function __mcpParseSlotLabel(rawLabel) {
92
+ var result = { raw: rawLabel, fields: {}, slotName: "", declaredType: "", description: "" };
93
+ if (!rawLabel) {
94
+ return result;
95
+ }
96
+ var segments = rawLabel.split(/[;;\\n]/);
97
+ for (var i = 0; i < segments.length; i++) {
98
+ var seg = segments[i];
99
+ if (!seg) continue;
100
+ var parts = seg.split(/[:=:]/);
101
+ if (parts.length < 2) continue;
102
+ var key = parts.shift();
103
+ var value = parts.join('=');
104
+ key = key.replace(/^\\s+|\\s+$/g, '');
105
+ value = value.replace(/^\\s+|\\s+$/g, '');
106
+ if (!key) continue;
107
+ result.fields[key] = value;
108
+ }
109
+ result.slotName = result.fields["槽位"] || result.fields["名称"] || result.fields["名字"] || result.fields["slot"] || result.fields["name"] || "";
110
+ result.declaredType = result.fields["类型"] || result.fields["type"] || "";
111
+ result.description = result.fields["说明"] || result.fields["备注"] || result.fields["描述"] || result.fields["desc"] || "";
112
+ return result;
113
+ }
114
+ `;
115
+
116
+ const FIT_RESOLVER_SNIPPET = `
117
+ function __mcpResolveFitOption(name) {
118
+ if (!name) return FitOptions.PROPORTIONALLY;
119
+ var n = String(name).toUpperCase();
120
+ if (n === "FILL_FRAME" || n === "FILL_PROPORTIONALLY" || n === "填满框架") {
121
+ return FitOptions.FILL_PROPORTIONALLY;
122
+ }
123
+ if (n === "FIT_CONTENT" || n === "CONTENT_TO_FRAME" || n === "内容适应") {
124
+ return FitOptions.CONTENT_TO_FRAME;
125
+ }
126
+ if (n === "FIT_FRAME" || n === "FRAME_TO_CONTENT" || n === "框架适应内容") {
127
+ return FitOptions.FRAME_TO_CONTENT;
128
+ }
129
+ if (n === "CENTER" || n === "CENTER_CONTENT" || n === "居中") {
130
+ return FitOptions.CENTER_CONTENT;
131
+ }
132
+ return FitOptions.PROPORTIONALLY;
133
+ }
134
+ `;
135
+
136
+ const SLOT_COLLECTION_SNIPPET = `
137
+ function __mcpBuildSlotInfo(item, parsed, mmPerPoint, context) {
138
+ var gb = item.geometricBounds;
139
+ var slotInfo = {
140
+ slotName: parsed.slotName,
141
+ declaredType: parsed.declaredType,
142
+ description: parsed.description,
143
+ frameType: item.constructor ? item.constructor.name : "",
144
+ reflectName: item.reflect ? item.reflect.name : "",
145
+ layer: (item.itemLayer && item.itemLayer.isValid) ? item.itemLayer.name : "",
146
+ label: item.label,
147
+ contextType: context.type || "",
148
+ pageIndex: (typeof context.pageIndex === "number") ? context.pageIndex : null,
149
+ pageName: context.pageName || "",
150
+ masterIndex: (typeof context.masterIndex === "number") ? context.masterIndex : null,
151
+ masterName: context.masterName || "",
152
+ boundsPoints: {
153
+ top: gb[0],
154
+ left: gb[1],
155
+ bottom: gb[2],
156
+ right: gb[3]
157
+ },
158
+ boundsMillimeters: {
159
+ top: gb[0] * mmPerPoint,
160
+ left: gb[1] * mmPerPoint,
161
+ bottom: gb[2] * mmPerPoint,
162
+ right: gb[3] * mmPerPoint,
163
+ width: (gb[3] - gb[1]) * mmPerPoint,
164
+ height: (gb[2] - gb[0]) * mmPerPoint
165
+ },
166
+ hasGraphic: (item.graphics && item.graphics.length > 0),
167
+ textPreview: "",
168
+ isOverride: false,
169
+ childCount: 0
170
+ };
171
+ if (parsed.fields) {
172
+ slotInfo.metadata = parsed.fields;
173
+ }
174
+ try {
175
+ var previewContents = "";
176
+ if (slotInfo.frameType === "TextFrame") {
177
+ previewContents = item.contents;
178
+ } else if (typeof item.contents !== 'undefined') {
179
+ previewContents = item.contents;
180
+ }
181
+ if (!previewContents && item.textFrames && item.textFrames.length) {
182
+ previewContents = item.textFrames[0].contents;
183
+ }
184
+ if (previewContents && previewContents.length > 120) {
185
+ previewContents = previewContents.substr(0, 120);
186
+ }
187
+ slotInfo.textPreview = previewContents || "";
188
+ } catch(_previewErr) {
189
+ slotInfo.textPreview = "";
190
+ }
191
+ try {
192
+ if (item.hasOwnProperty('isOverridden')) {
193
+ slotInfo.isOverride = item.isOverridden === true;
194
+ }
195
+ } catch(_overrideFlagError) {}
196
+ try {
197
+ var children = item.pageItems;
198
+ if (children && children.length) {
199
+ slotInfo.childCount = children.length;
200
+ var childSummary = [];
201
+ for (var ci = 0; ci < children.length; ci++) {
202
+ var child = children[ci];
203
+ childSummary.push({
204
+ label: child.label,
205
+ frameType: child.constructor ? child.constructor.name : "",
206
+ reflectName: child.reflect ? child.reflect.name : ""
207
+ });
208
+ }
209
+ slotInfo.children = childSummary;
210
+ }
211
+ } catch(_childInfoErr) {}
212
+ return slotInfo;
213
+ }
214
+
215
+ function __mcpAddSummary(summaryMap, slotInfo, parsed, context) {
216
+ var entry = summaryMap[slotInfo.slotName];
217
+ if (!entry) {
218
+ entry = {
219
+ slotName: slotInfo.slotName,
220
+ declaredType: parsed.declaredType || "",
221
+ occurrences: 0,
222
+ contexts: []
223
+ };
224
+ summaryMap[slotInfo.slotName] = entry;
225
+ }
226
+ entry.occurrences += 1;
227
+ if (!entry.declaredType && parsed.declaredType) {
228
+ entry.declaredType = parsed.declaredType;
229
+ }
230
+ entry.contexts.push({
231
+ contextType: context.type || "",
232
+ pageIndex: (typeof context.pageIndex === "number") ? context.pageIndex : null,
233
+ pageName: context.pageName || "",
234
+ masterIndex: (typeof context.masterIndex === "number") ? context.masterIndex : null,
235
+ masterName: context.masterName || "",
236
+ frameType: slotInfo.frameType
237
+ });
238
+ }
239
+
240
+ function __mcpCollectSlotsFromItem(item, slotsArray, summaryMap, mmPerPoint, context) {
241
+ if (!item || !item.isValid) return;
242
+ if (item.itemLayer && item.itemLayer.isValid && item.itemLayer.name === "PageNotes") return;
243
+ if (item.label && item.label !== "") {
244
+ var parsed = __mcpParseSlotLabel(item.label);
245
+ if (parsed.slotName) {
246
+ var slotInfo = __mcpBuildSlotInfo(item, parsed, mmPerPoint, context);
247
+ slotsArray.push(slotInfo);
248
+ if (summaryMap) {
249
+ __mcpAddSummary(summaryMap, slotInfo, parsed, context);
250
+ }
251
+ }
252
+ }
253
+ var childItems = null;
254
+ try {
255
+ childItems = item.pageItems;
256
+ } catch (_childErr) {
257
+ childItems = null;
258
+ }
259
+ if (childItems && childItems.length) {
260
+ for (var c = 0; c < childItems.length; c++) {
261
+ __mcpCollectSlotsFromItem(childItems[c], slotsArray, summaryMap, mmPerPoint, context);
262
+ }
263
+ }
264
+ }
265
+
266
+ function __mcpCollectSlotsFromItems(items, slotsArray, summaryMap, mmPerPoint, context) {
267
+ if (!items || !items.length) return;
268
+ for (var idx = 0; idx < items.length; idx++) {
269
+ __mcpCollectSlotsFromItem(items[idx], slotsArray, summaryMap, mmPerPoint, context);
270
+ }
271
+ }
272
+ `;
273
+
274
+ function parseJsonResult(raw, operationName) {
275
+ const trimmed = (raw ?? '').trim();
276
+ if (!trimmed) {
277
+ throw new Error('InDesign 未返回任何数据。');
278
+ }
279
+ if (trimmed.startsWith('Error:')) {
280
+ const message = trimmed.slice(6).trim();
281
+ throw new Error(message || `InDesign 执行失败: ${trimmed}`);
282
+ }
283
+ let parsed;
284
+ try {
285
+ parsed = JSON.parse(trimmed);
286
+ } catch (error) {
287
+ const preview = trimmed.length > 500 ? trimmed.substring(0, 500) + '...[truncated]' : trimmed;
288
+ throw new Error(`无法解析 InDesign 返回结果(${operationName}): ${preview}\n解析错误: ${error.message}`);
289
+ }
290
+ if (parsed && typeof parsed === 'object' && parsed.success === false) {
291
+ throw new Error(parsed.error || `${operationName} 在 InDesign 中执行失败`);
292
+ }
293
+ return (parsed && typeof parsed === 'object' && Object.prototype.hasOwnProperty.call(parsed, 'data'))
294
+ ? parsed.data
295
+ : parsed;
296
+ }
297
+
298
+ function buildSlotValuesScript(slotValues) {
299
+ const lines = ['var slotValues = {};'];
300
+ if (!slotValues || typeof slotValues !== 'object') {
301
+ return lines.join('\n');
302
+ }
303
+ for (const [slotName, rawValue] of Object.entries(slotValues)) {
304
+ if (rawValue === undefined || rawValue === null) continue;
305
+ const slotKey = escapeJsxString(slotName);
306
+ let value = rawValue;
307
+ if (typeof value === 'string' || typeof value === 'number' || typeof value === 'boolean') {
308
+ value = { text: String(value) };
309
+ }
310
+ if (typeof value !== 'object') continue;
311
+
312
+ const props = [];
313
+ if (value.text !== undefined && value.text !== null) {
314
+ props.push(`text: "${escapeJsxString(String(value.text))}"`);
315
+ }
316
+ if (value.imagePath !== undefined && value.imagePath !== null) {
317
+ props.push(`imagePath: "${escapeFilePathForJsx(String(value.imagePath))}"`);
318
+ }
319
+ if (value.fit !== undefined && value.fit !== null) {
320
+ props.push(`fit: "${escapeJsxString(String(value.fit).toUpperCase())}"`);
321
+ }
322
+ if (value.clearExisting !== undefined) {
323
+ props.push(`clearExisting: ${value.clearExisting ? 'true' : 'false'}`);
324
+ }
325
+ if (value.declaredType !== undefined && value.declaredType !== null) {
326
+ props.push(`declaredType: "${escapeJsxString(String(value.declaredType))}"`);
327
+ }
328
+ if (!props.length) continue;
329
+ lines.push(`slotValues["${slotKey}"] = { ${props.join(', ')} };`);
330
+ }
331
+ return lines.join('\n');
332
+ }
333
+
334
+ export class AdvancedTemplateHandlers {
335
+ static async runJsxFile(args) {
336
+ const { filePath } = args || {};
337
+ if (!filePath || typeof filePath !== 'string' || !filePath.trim()) {
338
+ return formatErrorResponse('filePath 必须是 JSX 文件的有效路径。', 'Run JSX File');
339
+ }
340
+
341
+ const resolvedPath = path.resolve(filePath);
342
+ const ext = path.extname(resolvedPath).toLowerCase();
343
+ if (ext && ext !== '.jsx') {
344
+ return formatErrorResponse('filePath 需要指向 .jsx 文件。', 'Run JSX File');
345
+ }
346
+
347
+ try {
348
+ const stats = fs.statSync(resolvedPath);
349
+ if (!stats.isFile()) {
350
+ return formatErrorResponse(`指定路径不是文件:${resolvedPath}`, 'Run JSX File');
351
+ }
352
+ if (stats.size === 0) {
353
+ return formatErrorResponse('JSX 文件为空,无法执行。', 'Run JSX File');
354
+ }
355
+ } catch (error) {
356
+ return formatErrorResponse(`无法访问 JSX 文件:${error.message}`, 'Run JSX File');
357
+ }
358
+
359
+ try {
360
+ // 执行文件本身,保留 $.fileName 与相对路径环境
361
+ const result = await ScriptExecutor.executeInDesignScriptFile(resolvedPath);
362
+ if (typeof result === 'string' && result.trim().startsWith('Error:')) {
363
+ return formatErrorResponse(result, 'Run JSX File');
364
+ }
365
+ return formatResponse(result, 'Run JSX File');
366
+ } catch (error) {
367
+ return formatErrorResponse(error.message, 'Run JSX File');
368
+ }
369
+ }
370
+
371
+ static async inspectTemplate(args) {
372
+ const { templatePath } = args || {};
373
+ const hasPath = typeof templatePath === 'string' && templatePath.trim().length > 0;
374
+ const normalizedPath = hasPath ? normalizeFsPathForJsx(templatePath) : '';
375
+ const templatePathJsx = hasPath ? escapeFilePathForJsx(templatePath) : '';
376
+ const script = [
377
+ JSON_HELPERS_SNIPPET,
378
+ LABEL_PARSER_SNIPPET,
379
+ SLOT_COLLECTION_SNIPPET,
380
+ `
381
+ var useActive = ${hasPath ? 'false' : 'true'};
382
+ var templatePathValue = "${templatePathJsx}";
383
+ var normalizedPathValue = "${escapeJsxString(normalizedPath)}";
384
+ var doc = null;
385
+ var __mcpResult = null;
386
+
387
+ try {
388
+ if (useActive) {
389
+ if (app.documents.length === 0) {
390
+ __mcpResult = { success: false, error: "没有打开的文档,请提供模板路径。" };
391
+ } else {
392
+ doc = app.activeDocument;
393
+ templatePathValue = doc.fullName ? doc.fullName.fsName : "";
394
+ normalizedPathValue = doc.fullName ? doc.fullName.fsName : doc.name;
395
+ }
396
+ } else {
397
+ var templateFile = File(templatePathValue);
398
+ if (!templateFile.exists) {
399
+ __mcpResult = { success: false, error: "模板文件不存在: " + templatePathValue };
400
+ } else {
401
+ doc = app.open(templateFile, false);
402
+ templatePathValue = templateFile.fsName;
403
+ normalizedPathValue = "${escapeJsxString(normalizedPath)}";
404
+ }
405
+ }
406
+
407
+ if (!__mcpResult) {
408
+ var mmPerPoint = 25.4 / 72;
409
+ var templatePathJson = normalizedPathValue ? String(normalizedPathValue).replace(/\\\\/g, '/') : "";
410
+ var templateFsPathJson = templatePathValue ? String(templatePathValue).replace(/\\\\/g, '/') : "";
411
+ var data = {
412
+ templatePath: templatePathJson,
413
+ templateFsPath: templateFsPathJson,
414
+ documentName: doc.name,
415
+ pageCount: doc.pages.length,
416
+ pages: [],
417
+ masters: []
418
+ };
419
+ var summaryMap = {};
420
+ var notesLayer = null;
421
+ try {
422
+ notesLayer = doc.layers.itemByName("PageNotes");
423
+ if (!notesLayer || !notesLayer.isValid) {
424
+ notesLayer = null;
425
+ }
426
+ } catch (_notesError) {
427
+ notesLayer = null;
428
+ }
429
+
430
+ for (var i = 0; i < doc.pages.length; i++) {
431
+ var page = doc.pages[i];
432
+ var pageEntry = {
433
+ pageIndex: i,
434
+ pageName: page.name,
435
+ notes: "",
436
+ slots: []
437
+ };
438
+ if (notesLayer) {
439
+ var notes = [];
440
+ var noteFrames = notesLayer.textFrames;
441
+ for (var n = 0; n < noteFrames.length; n++) {
442
+ var noteFrame = noteFrames[n];
443
+ if (noteFrame && noteFrame.isValid && noteFrame.parentPage && noteFrame.parentPage.id === page.id) {
444
+ notes.push(noteFrame.contents);
445
+ }
446
+ }
447
+ if (notes.length) {
448
+ pageEntry.notes = notes.join("\\n").replace(/\\s+$/, "");
449
+ }
450
+ }
451
+ __mcpCollectSlotsFromItems(
452
+ page.pageItems,
453
+ pageEntry.slots,
454
+ summaryMap,
455
+ mmPerPoint,
456
+ { type: "page", pageIndex: i, pageName: page.name }
457
+ );
458
+ data.pages.push(pageEntry);
459
+ }
460
+
461
+ for (var m = 0; m < doc.masterSpreads.length; m++) {
462
+ var master = doc.masterSpreads[m];
463
+ if (!master || !master.isValid) continue;
464
+ var masterEntry = {
465
+ masterIndex: m,
466
+ masterName: master.name,
467
+ slots: []
468
+ };
469
+ __mcpCollectSlotsFromItems(
470
+ master.pageItems,
471
+ masterEntry.slots,
472
+ summaryMap,
473
+ mmPerPoint,
474
+ { type: "master", masterIndex: m, masterName: master.name }
475
+ );
476
+ data.masters.push(masterEntry);
477
+ }
478
+
479
+ data.slotSummary = [];
480
+ for (var key in summaryMap) {
481
+ if (!summaryMap.hasOwnProperty(key)) continue;
482
+ data.slotSummary.push(summaryMap[key]);
483
+ }
484
+ __mcpResult = { success: true, data: data };
485
+ }
486
+ } catch (err) {
487
+ __mcpResult = { success: false, error: err.message || String(err) };
488
+ } finally {
489
+ if (!useActive && doc && doc.isValid) {
490
+ doc.close(SaveOptions.NO);
491
+ }
492
+ __mcpSerialize(__mcpResult || { success: false, error: "未知错误" });
493
+ }
494
+ `
495
+ ].join('\n');
496
+
497
+ try {
498
+ const rawResult = await ScriptExecutor.executeInDesignScript(script);
499
+ const data = parseJsonResult(rawResult, 'Inspect Template Blueprint');
500
+ return formatResponse(data, 'Inspect Template Blueprint');
501
+ } catch (error) {
502
+ return formatErrorResponse(error.message, 'Inspect Template Blueprint');
503
+ }
504
+ }
505
+
506
+ static async listTemplateBlueprints() {
507
+ const script = [
508
+ JSON_HELPERS_SNIPPET,
509
+ LABEL_PARSER_SNIPPET,
510
+ SLOT_COLLECTION_SNIPPET,
511
+ `
512
+ if (app.documents.length === 0) {
513
+ __mcpSerialize({ success: false, error: "没有打开的文档。" });
514
+ } else {
515
+ var doc = app.activeDocument;
516
+ var mmPerPoint = 25.4 / 72;
517
+ var results = [];
518
+ for (var m = 0; m < doc.masterSpreads.length; m++) {
519
+ var master = doc.masterSpreads[m];
520
+ if (!master || !master.isValid) continue;
521
+ var slots = [];
522
+ __mcpCollectSlotsFromItems(
523
+ master.pageItems,
524
+ slots,
525
+ null,
526
+ mmPerPoint,
527
+ { type: "master", masterIndex: m, masterName: master.name }
528
+ );
529
+ var slotNames = [];
530
+ for (var s = 0; s < slots.length; s++) {
531
+ var name = slots[s].slotName;
532
+ var exists = false;
533
+ for (var n = 0; n < slotNames.length; n++) {
534
+ if (slotNames[n] === name) { exists = true; break; }
535
+ }
536
+ if (!exists) slotNames.push(name);
537
+ }
538
+ results.push({
539
+ masterIndex: m,
540
+ masterName: master.name,
541
+ slotCount: slots.length,
542
+ slotNames: slotNames
543
+ });
544
+ }
545
+ __mcpSerialize({ success: true, data: results });
546
+ }
547
+ `
548
+ ].join('\n');
549
+
550
+ try {
551
+ const rawResult = await ScriptExecutor.executeInDesignScript(script);
552
+ const data = parseJsonResult(rawResult, 'List Template Blueprints');
553
+ return formatResponse(data, 'List Template Blueprints');
554
+ } catch (error) {
555
+ return formatErrorResponse(error.message, 'List Template Blueprints');
556
+ }
557
+ }
558
+
559
+ static async createPageWithTemplate(args) {
560
+ const {
561
+ templateName,
562
+ position = 'AT_END',
563
+ referencePageIndex,
564
+ label = ''
565
+ } = args || {};
566
+
567
+ if (!templateName || typeof templateName !== 'string') {
568
+ return formatErrorResponse('templateName 必须是母版名称字符串。', 'Create Page With Template');
569
+ }
570
+
571
+ const script = [
572
+ JSON_HELPERS_SNIPPET,
573
+ LABEL_PARSER_SNIPPET,
574
+ SLOT_COLLECTION_SNIPPET,
575
+ `
576
+ if (app.documents.length === 0) {
577
+ __mcpSerialize({ success: false, error: "没有打开的文档。" });
578
+ } else {
579
+ var doc = app.activeDocument;
580
+ var master = doc.masterSpreads.itemByName("${escapeJsxString(templateName)}");
581
+ if (!master || !master.isValid) {
582
+ __mcpSerialize({ success: false, error: "未找到母版:" + "${escapeJsxString(templateName)}" });
583
+ } else {
584
+ var pos = "${escapeJsxString(position || '')}";
585
+ var refIndex = ${Number.isInteger(referencePageIndex) ? referencePageIndex : 'null'};
586
+ var resultObj = null;
587
+ var newPage = null;
588
+ try {
589
+ if (pos === "AT_BEGINNING") {
590
+ newPage = doc.pages.add(LocationOptions.AT_BEGINNING);
591
+ } else if (pos === "BEFORE" && refIndex !== null && refIndex >= 0 && refIndex < doc.pages.length) {
592
+ newPage = doc.pages.add(LocationOptions.BEFORE, doc.pages[refIndex]);
593
+ } else if (pos === "AFTER" && refIndex !== null && refIndex >= 0 && refIndex < doc.pages.length) {
594
+ newPage = doc.pages.add(LocationOptions.AFTER, doc.pages[refIndex]);
595
+ } else {
596
+ newPage = doc.pages.add();
597
+ }
598
+ newPage.appliedMaster = master;
599
+ if ("${escapeJsxString(label)}" !== "") {
600
+ try { newPage.label = "${escapeJsxString(label)}"; } catch(_labelErr) {}
601
+ }
602
+ var overrideCount = 0;
603
+ try {
604
+ var masterItems = master.pageItems;
605
+ for (var i = 0; i < masterItems.length; i++) {
606
+ var item = masterItems[i];
607
+ try {
608
+ item.override(newPage);
609
+ overrideCount++;
610
+ } catch (_overrideErr) {}
611
+ }
612
+ } catch (_missingMasterItems) {}
613
+ try {
614
+ var mx = newPage.masterPageTransform;
615
+ if (mx && (mx.horizontalTranslation !== 0 || mx.verticalTranslation !== 0)) {
616
+ newPage.transform(
617
+ CoordinateSpaces.INNER_COORDINATES,
618
+ AnchorPoint.CENTER_ANCHOR,
619
+ mx.invertMatrix()
620
+ );
621
+ }
622
+ } catch(_transformErr) {}
623
+
624
+ var mmPerPoint = 25.4 / 72;
625
+ var collectedSlots = [];
626
+ var slotSummaryMap = {};
627
+ try {
628
+ __mcpCollectSlotsFromItems(
629
+ newPage.pageItems,
630
+ collectedSlots,
631
+ slotSummaryMap,
632
+ mmPerPoint,
633
+ { type: "page", pageIndex: newPage.documentOffset, pageName: newPage.name }
634
+ );
635
+ } catch(_collectErr) {}
636
+
637
+ var slotSummaries = [];
638
+ for (var s = 0; s < collectedSlots.length; s++) {
639
+ var slot = collectedSlots[s];
640
+ if (!slot) continue;
641
+ var summary = {
642
+ slotName: slot.slotName || "",
643
+ declaredType: slot.declaredType || "",
644
+ description: slot.description || ""
645
+ };
646
+ if (slot.metadata && typeof slot.metadata === "object") {
647
+ summary.metadata = slot.metadata;
648
+ }
649
+ slotSummaries.push(summary);
650
+ }
651
+
652
+ resultObj = {
653
+ success: true,
654
+ data: {
655
+ pageIndex: newPage.documentOffset,
656
+ pageName: newPage.name,
657
+ appliedMaster: master.name,
658
+ overrideCount: overrideCount,
659
+ totalMasterItems: master.pageItems.length,
660
+ slotCount: slotSummaries.length,
661
+ slots: slotSummaries
662
+ }
663
+ };
664
+ } catch (pageErr) {
665
+ resultObj = { success: false, error: "新增页面失败:" + pageErr.message };
666
+ }
667
+
668
+ if (!resultObj) {
669
+ resultObj = { success: false, error: "未知错误" };
670
+ }
671
+ __mcpSerialize(resultObj);
672
+ }
673
+ }
674
+ `
675
+ ].join('\n');
676
+
677
+ try {
678
+ const rawResult = await ScriptExecutor.executeInDesignScript(script);
679
+ const data = parseJsonResult(rawResult, 'Create Page With Template');
680
+ return formatResponse(data, 'Create Page With Template');
681
+ } catch (error) {
682
+ return formatErrorResponse(error.message, 'Create Page With Template');
683
+ }
684
+ }
685
+
686
+ static async getPageInformation(args) {
687
+ const { pageIndex } = args || {};
688
+ if (!Number.isInteger(pageIndex) || pageIndex < 0) {
689
+ return formatErrorResponse('pageIndex 必须是非负整数。', 'Get Page Information');
690
+ }
691
+
692
+ const script = [
693
+ JSON_HELPERS_SNIPPET,
694
+ LABEL_PARSER_SNIPPET,
695
+ SLOT_COLLECTION_SNIPPET,
696
+ `
697
+ if (app.documents.length === 0) {
698
+ __mcpSerialize({ success: false, error: "没有打开的文档。" });
699
+ } else {
700
+ var doc = app.activeDocument;
701
+ if (${pageIndex} >= doc.pages.length) {
702
+ __mcpSerialize({ success: false, error: "页面索引超出范围。" });
703
+ } else {
704
+ var page = doc.pages[${pageIndex}];
705
+ var mmPerPoint = 25.4 / 72;
706
+ var slots = [];
707
+ __mcpCollectSlotsFromItems(
708
+ page.pageItems,
709
+ slots,
710
+ null,
711
+ mmPerPoint,
712
+ { type: "page", pageIndex: page.documentOffset, pageName: page.name }
713
+ );
714
+
715
+ var appliedMasterName = "";
716
+ try {
717
+ if (page.appliedMaster && page.appliedMaster.isValid) {
718
+ appliedMasterName = page.appliedMaster.name;
719
+ }
720
+ } catch(_masterErr) {}
721
+
722
+ var response = {
723
+ pageIndex: page.documentOffset,
724
+ pageName: page.name,
725
+ appliedMaster: appliedMasterName,
726
+ slotCount: slots.length,
727
+ slots: slots
728
+ };
729
+ __mcpSerialize({ success: true, data: response });
730
+ }
731
+ }
732
+ `
733
+ ].join('\n');
734
+
735
+ try {
736
+ const rawResult = await ScriptExecutor.executeInDesignScript(script);
737
+ const data = parseJsonResult(rawResult, 'Get Page Information');
738
+ return formatResponse(data, 'Get Page Information');
739
+ } catch (error) {
740
+ return formatErrorResponse(error.message, 'Get Page Information');
741
+ }
742
+ }
743
+
744
+ static async fillTemplateFromSlots(args) {
745
+ const { templatePath, outputPath, values, pageIndex } = args || {};
746
+ if (!values || typeof values !== 'object' || !Object.keys(values).length) {
747
+ return formatErrorResponse('values 必须是包含至少一个槽位的对象。', 'Populate Template Slots');
748
+ }
749
+
750
+ const hasPath = typeof templatePath === 'string' && templatePath.trim().length > 0;
751
+ const templatePathJsx = hasPath ? escapeFilePathForJsx(templatePath) : '';
752
+ const normalizedTemplatePath = hasPath ? normalizeFsPathForJsx(templatePath) : '';
753
+ const slotValuesScript = buildSlotValuesScript(values);
754
+ const outputPathProvided = outputPath && typeof outputPath === 'string' && outputPath.trim().length;
755
+ const outputPathJsx = outputPathProvided ? escapeFilePathForJsx(outputPath) : '';
756
+
757
+ const scriptParts = [
758
+ JSON_HELPERS_SNIPPET,
759
+ LABEL_PARSER_SNIPPET,
760
+ SLOT_COLLECTION_SNIPPET,
761
+ FIT_RESOLVER_SNIPPET,
762
+ slotValuesScript,
763
+ `
764
+ var templatePath = "${templatePathJsx}";
765
+ var useActive = ${hasPath ? 'false' : 'true'};
766
+ var doc = null;
767
+ var templateFsPath = "";
768
+ var templateDisplayPath = "${escapeJsxString(normalizedTemplatePath)}";
769
+ var __mcpResult = null;
770
+ var targetPageIndex = ${Number.isInteger(pageIndex) ? pageIndex : 'null'};
771
+
772
+ function __mcpCollectSlotTargetsFromItem(item, slotTargets, context) {
773
+ if (!item || !item.isValid) return;
774
+ if (item.itemLayer && item.itemLayer.isValid && item.itemLayer.name === "PageNotes") return;
775
+ if (item.label && item.label !== "") {
776
+ var parsed = __mcpParseSlotLabel(item.label);
777
+ if (parsed.slotName) {
778
+ if (!slotTargets[parsed.slotName]) {
779
+ slotTargets[parsed.slotName] = [];
780
+ }
781
+ slotTargets[parsed.slotName].push({
782
+ item: item,
783
+ parsed: parsed,
784
+ context: context
785
+ });
786
+ }
787
+ }
788
+ var childItems = null;
789
+ try {
790
+ childItems = item.pageItems;
791
+ } catch (_childErr) {
792
+ childItems = null;
793
+ }
794
+ if (childItems && childItems.length) {
795
+ for (var c = 0; c < childItems.length; c++) {
796
+ __mcpCollectSlotTargetsFromItem(childItems[c], slotTargets, context);
797
+ }
798
+ }
799
+ }
800
+
801
+ function __mcpCollectSlotTargetsFromItems(items, slotTargets, context) {
802
+ if (!items || !items.length) return;
803
+ for (var idx = 0; idx < items.length; idx++) {
804
+ __mcpCollectSlotTargetsFromItem(items[idx], slotTargets, context);
805
+ }
806
+ }
807
+
808
+ if (useActive) {
809
+ if (app.documents.length === 0) {
810
+ __mcpResult = { success: false, error: "没有打开的文档,请提供模板路径或先打开文档。" };
811
+ } else {
812
+ doc = app.activeDocument;
813
+ templateFsPath = doc.fullName ? doc.fullName.fsName : "";
814
+ templateDisplayPath = templateFsPath || doc.name;
815
+ }
816
+ } else {
817
+ var templateFile = File(templatePath);
818
+ if (!templateFile.exists) {
819
+ __mcpResult = { success: false, error: "模板文件不存在: " + templatePath };
820
+ } else {
821
+ doc = app.open(templateFile, false);
822
+ templateFsPath = templateFile.fsName;
823
+ templateDisplayPath = "${escapeJsxString(normalizedTemplatePath)}";
824
+ }
825
+ }
826
+
827
+ var templatePathJson = templateDisplayPath ? String(templateDisplayPath).replace(/\\\\/g, '/') : "";
828
+ var templateFsPathJson = templateFsPath ? String(templateFsPath).replace(/\\\\/g, '/') : "";
829
+
830
+ var report = {
831
+ templatePath: templatePathJson,
832
+ templateFsPath: templateFsPathJson,
833
+ applied: [],
834
+ warnings: [],
835
+ missingSlots: [],
836
+ savedPath: ""
837
+ };
838
+
839
+ try {
840
+ if (!__mcpResult) {
841
+ var slotTargets = {};
842
+ for (var p = 0; p < doc.pages.length; p++) {
843
+ var page = doc.pages[p];
844
+ if (targetPageIndex !== null && p !== targetPageIndex) {
845
+ continue;
846
+ }
847
+ __mcpCollectSlotTargetsFromItems(
848
+ page.pageItems,
849
+ slotTargets,
850
+ { type: "page", pageIndex: p, pageName: page.name }
851
+ );
852
+ }
853
+
854
+ for (var key in slotValues) {
855
+ if (!slotValues.hasOwnProperty(key)) continue;
856
+ var value = slotValues[key];
857
+ var targets = slotTargets[key];
858
+ if (!targets || !targets.length) {
859
+ report.missingSlots.push(key);
860
+ continue;
861
+ }
862
+ var filteredTargets = [];
863
+ for (var tIndex = 0; tIndex < targets.length; tIndex++) {
864
+ var ctx = targets[tIndex].context || {};
865
+ if (targetPageIndex !== null && ctx.pageIndex !== targetPageIndex) {
866
+ continue;
867
+ }
868
+ filteredTargets.push(targets[tIndex]);
869
+ }
870
+ if (targetPageIndex !== null) {
871
+ targets = filteredTargets;
872
+ }
873
+ if (!targets.length) {
874
+ report.missingSlots.push(key + "(页面 " + targetPageIndex + ")");
875
+ continue;
876
+ }
877
+ for (var t = 0; t < targets.length; t++) {
878
+ var target = targets[t];
879
+ var frame = target.item;
880
+ if (!frame || !frame.isValid) continue;
881
+ var frameType = frame.constructor ? frame.constructor.name : "";
882
+ var appliedDetail = {
883
+ slotName: key,
884
+ pageIndex: target.context ? target.context.pageIndex : null,
885
+ pageName: target.context ? target.context.pageName : "",
886
+ frameType: frameType,
887
+ actions: []
888
+ };
889
+
890
+ if (value.text !== undefined) {
891
+ var applyTextResult = (function() {
892
+ var queue = [frame];
893
+ var visited = {};
894
+ while (queue.length) {
895
+ var current = queue.shift();
896
+ if (!current || !current.isValid) continue;
897
+ var idKey = "";
898
+ try { idKey = String(current.id); } catch(_idErr) {}
899
+ if (idKey && visited[idKey]) continue;
900
+ if (idKey) visited[idKey] = true;
901
+
902
+ try {
903
+ current.contents = value.text;
904
+ if (current.contents === value.text) {
905
+ return { success: true, targetType: current.constructor ? current.constructor.name : frameType };
906
+ }
907
+ } catch(_tryText) {}
908
+
909
+ try {
910
+ var texts = current.texts;
911
+ if (texts && texts.length) {
912
+ texts[0].contents = value.text;
913
+ return { success: true, targetType: current.constructor ? current.constructor.name : frameType };
914
+ }
915
+ } catch(_textsErr) {}
916
+
917
+ try {
918
+ var tf = current.textFrames;
919
+ if (tf && tf.length) {
920
+ for (var ti = 0; ti < tf.length; ti++) {
921
+ try {
922
+ tf[ti].contents = value.text;
923
+ if (tf[ti].contents === value.text) {
924
+ return { success: true, targetType: tf[ti].constructor ? tf[ti].constructor.name : frameType };
925
+ }
926
+ } catch(_textFrameErr) {}
927
+ }
928
+ }
929
+ } catch(_tfErr) {}
930
+
931
+ try {
932
+ var elements = current.getElements();
933
+ if (elements && elements.length) {
934
+ for (var ei = 0; ei < elements.length; ei++) {
935
+ var el = elements[ei];
936
+ try {
937
+ if (typeof el.contents !== 'undefined') {
938
+ el.contents = value.text;
939
+ if (el.contents === value.text) {
940
+ return { success: true, targetType: el.constructor ? el.constructor.name : frameType };
941
+ }
942
+ }
943
+ } catch(_elementsErr) {}
944
+ }
945
+ }
946
+ } catch(_getElementsErr) {}
947
+
948
+ try {
949
+ var children = current.pageItems;
950
+ if (children && children.length) {
951
+ for (var ci = 0; ci < children.length; ci++) {
952
+ queue.push(children[ci]);
953
+ }
954
+ }
955
+ } catch(_childErr) {}
956
+ }
957
+ return { success: false };
958
+ })();
959
+
960
+ if (applyTextResult.success) {
961
+ appliedDetail.actions.push("text(" + applyTextResult.targetType + ")");
962
+ } else {
963
+ report.warnings.push("槽位 " + key + " 文本填充失败:未找到可写入的文本对象");
964
+ }
965
+ }
966
+
967
+ if (value.imagePath !== undefined) {
968
+ var imgFile = File(value.imagePath);
969
+ if (!imgFile.exists) {
970
+ report.warnings.push("槽位 " + key + " 图片不存在: " + value.imagePath);
971
+ } else {
972
+ var applyImageResult = (function() {
973
+ var queueImg = [frame];
974
+ var visitedImg = {};
975
+ while (queueImg.length) {
976
+ var currentImg = queueImg.shift();
977
+ if (!currentImg || !currentImg.isValid) continue;
978
+ var idKeyImg = "";
979
+ try { idKeyImg = String(currentImg.id); } catch(_imgIdErr) {}
980
+ if (idKeyImg && visitedImg[idKeyImg]) continue;
981
+ if (idKeyImg) visitedImg[idKeyImg] = true;
982
+
983
+ try {
984
+ if (value.clearExisting === true && currentImg.graphics && currentImg.graphics.length) {
985
+ for (var g = currentImg.graphics.length - 1; g >= 0; g--) {
986
+ try { currentImg.graphics[g].remove(); } catch (_removeErr) {}
987
+ }
988
+ }
989
+ } catch(_clearErr) {}
990
+
991
+ try {
992
+ var placed = currentImg.place(imgFile);
993
+ if (placed) {
994
+ var fitName = value.fit || "PROPORTIONALLY";
995
+ try {
996
+ var fitOption = __mcpResolveFitOption(fitName);
997
+ if (fitOption) {
998
+ currentImg.fit(fitOption);
999
+ }
1000
+ } catch(_fitErr) {}
1001
+ return { success: true, targetType: currentImg.constructor ? currentImg.constructor.name : frameType };
1002
+ }
1003
+ } catch(placeErr) {}
1004
+
1005
+ try {
1006
+ var childItemsImg = currentImg.pageItems;
1007
+ if (childItemsImg && childItemsImg.length) {
1008
+ for (var cj = 0; cj < childItemsImg.length; cj++) {
1009
+ queueImg.push(childItemsImg[cj]);
1010
+ }
1011
+ }
1012
+ } catch(_imgChildErr) {}
1013
+ }
1014
+ return { success: false };
1015
+ })();
1016
+
1017
+ if (applyImageResult.success) {
1018
+ appliedDetail.actions.push("image(" + applyImageResult.targetType + ")");
1019
+ } else {
1020
+ report.warnings.push("槽位 " + key + " 图片填充失败:未找到可放置的图形对象");
1021
+ }
1022
+ }
1023
+ }
1024
+
1025
+ if (appliedDetail.actions.length) {
1026
+ report.applied.push(appliedDetail);
1027
+ }
1028
+ }
1029
+ }
1030
+
1031
+ for (var targetSlot in slotTargets) {
1032
+ if (!slotTargets.hasOwnProperty(targetSlot)) continue;
1033
+ if (!slotValues.hasOwnProperty(targetSlot)) {
1034
+ report.warnings.push("模板槽位 " + targetSlot + " 未提供填充数据");
1035
+ }
1036
+ }
1037
+
1038
+ ${outputPathProvided ? `
1039
+ var outputFile = File("${outputPathJsx}");
1040
+ try {
1041
+ if (outputFile.parent && !outputFile.parent.exists) {
1042
+ outputFile.parent.create();
1043
+ }
1044
+ } catch (_mkdirErr) {}
1045
+ doc.save(outputFile);
1046
+ report.savedPath = outputFile.fsName ? String(outputFile.fsName).replace(/\\\\/g, '/') : "";
1047
+ ` : ''}
1048
+
1049
+ __mcpResult = { success: true, data: report };
1050
+ }
1051
+ } catch (err) {
1052
+ __mcpResult = { success: false, error: err.message || String(err) };
1053
+ } finally {
1054
+ if (!useActive && doc && doc.isValid) {
1055
+ doc.close(SaveOptions.NO);
1056
+ }
1057
+ __mcpSerialize(__mcpResult || { success: false, error: "未知错误" });
1058
+ }
1059
+ `
1060
+ ];
1061
+
1062
+ const script = scriptParts.join('\n');
1063
+
1064
+ try {
1065
+ const rawResult = await ScriptExecutor.executeInDesignScript(script);
1066
+ const data = parseJsonResult(rawResult, 'Populate Template Slots');
1067
+ return formatResponse(data, 'Populate Template Slots');
1068
+ } catch (error) {
1069
+ return formatErrorResponse(error.message, 'Populate Template Slots');
1070
+ }
1071
+ }
1072
+ }