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,605 @@
1
+ /**
2
+ * Graphics management handlers
3
+ */
4
+ import { ScriptExecutor } from '../core/scriptExecutor.js';
5
+ import { formatResponse, formatErrorResponse, escapeJsxString, escapeFilePathForJsx } from '../utils/stringUtils.js';
6
+ import { sessionManager } from '../core/sessionManager.js';
7
+
8
+ export class GraphicsHandlers {
9
+ /**
10
+ * Create a rectangle on the active page
11
+ */
12
+ static async createRectangle(args) {
13
+ const {
14
+ x,
15
+ y,
16
+ width,
17
+ height,
18
+ fillColor,
19
+ strokeColor,
20
+ strokeWidth = 1,
21
+ cornerRadius = 0
22
+ } = args;
23
+
24
+ // Use session manager for positioning if coordinates not provided
25
+ const positioning = sessionManager.getCalculatedPositioning({ x, y, width, height });
26
+
27
+ // Validate positioning before creating content
28
+ const validation = sessionManager.validatePositioning(positioning.x, positioning.y, positioning.width, positioning.height);
29
+ if (!validation.valid) {
30
+ // Apply suggested corrections if available, otherwise use safe defaults
31
+ if (validation.suggested) {
32
+ Object.assign(positioning, validation.suggested);
33
+ } else {
34
+ // Fallback to safe positioning
35
+ const safePos = sessionManager.getCalculatedPositioning({});
36
+ Object.assign(positioning, safePos);
37
+ }
38
+ }
39
+
40
+ const script = [
41
+ 'if (app.documents.length === 0) {',
42
+ ' "No document open";',
43
+ '} else {',
44
+ ' var doc = app.activeDocument;',
45
+ ' var page = app.activeWindow.activePage || doc.pages[0];',
46
+ ' var rectangle;',
47
+ '',
48
+ ' try {',
49
+ ' // Create rectangle',
50
+ ` rectangle = page.rectangles.add();`,
51
+ ` rectangle.geometricBounds = [${positioning.y}, ${positioning.x}, ${positioning.y + positioning.height}, ${positioning.x + positioning.width}];`,
52
+ '',
53
+ ' // Apply fill color',
54
+ ` if ("${fillColor}" !== "") {`,
55
+ ' try {',
56
+ ` rectangle.fillColor = doc.colors.itemByName("${fillColor}");`,
57
+ ' } catch (colorError) {',
58
+ ' // Use default color if specified color not found',
59
+ ' }',
60
+ ' }',
61
+ '',
62
+ ' // Apply stroke color',
63
+ ` if ("${strokeColor}" !== "") {`,
64
+ ' try {',
65
+ ` rectangle.strokeColor = doc.colors.itemByName("${strokeColor}");`,
66
+ ` rectangle.strokeWeight = ${strokeWidth};`,
67
+ ' } catch (colorError) {',
68
+ ' // Use default stroke if specified color not found',
69
+ ' }',
70
+ ' }',
71
+ '',
72
+ ' // Apply corner radius',
73
+ ` if (${cornerRadius} > 0) {`,
74
+ ` rectangle.topLeftCornerOption = CornerOptions.ROUNDED_CORNER;`,
75
+ ` rectangle.topRightCornerOption = CornerOptions.ROUNDED_CORNER;`,
76
+ ` rectangle.bottomLeftCornerOption = CornerOptions.ROUNDED_CORNER;`,
77
+ ` rectangle.bottomRightCornerOption = CornerOptions.ROUNDED_CORNER;`,
78
+ ` rectangle.cornerRadius = ${cornerRadius};`,
79
+ ' }',
80
+ '',
81
+ ' "Rectangle created successfully";',
82
+ ' } catch (error) {',
83
+ ' "Error creating rectangle: " + error.message;',
84
+ ' }',
85
+ '}'
86
+ ].join('\n');
87
+
88
+ const result = await ScriptExecutor.executeInDesignScript(script);
89
+
90
+ // Store the created item info in session
91
+ sessionManager.setLastCreatedItem({
92
+ type: 'rectangle',
93
+ position: positioning,
94
+ fillColor: fillColor,
95
+ strokeColor: strokeColor,
96
+ strokeWidth: strokeWidth,
97
+ cornerRadius: cornerRadius
98
+ });
99
+
100
+ return formatResponse(result, "Create Rectangle");
101
+ }
102
+
103
+ /**
104
+ * Create an ellipse on the active page
105
+ */
106
+ static async createEllipse(args) {
107
+ const {
108
+ x,
109
+ y,
110
+ width,
111
+ height,
112
+ fillColor,
113
+ strokeColor,
114
+ strokeWidth = 1
115
+ } = args;
116
+
117
+ // Use session manager for positioning if coordinates not provided
118
+ const positioning = sessionManager.getCalculatedPositioning({ x, y, width, height });
119
+
120
+ // Validate positioning before creating content
121
+ const validation = sessionManager.validatePositioning(positioning.x, positioning.y, positioning.width, positioning.height);
122
+ if (!validation.valid) {
123
+ // Apply suggested corrections if available, otherwise use safe defaults
124
+ if (validation.suggested) {
125
+ Object.assign(positioning, validation.suggested);
126
+ } else {
127
+ // Fallback to safe positioning
128
+ const safePos = sessionManager.getCalculatedPositioning({});
129
+ Object.assign(positioning, safePos);
130
+ }
131
+ }
132
+
133
+ const script = [
134
+ 'if (app.documents.length === 0) {',
135
+ ' "No document open";',
136
+ '} else {',
137
+ ' var doc = app.activeDocument;',
138
+ ' var page = doc.pages[0];',
139
+ ' var ellipse;',
140
+ '',
141
+ ' try {',
142
+ ' // Create ellipse',
143
+ ` ellipse = page.ovals.add();`,
144
+ ` ellipse.geometricBounds = [${positioning.y}, ${positioning.x}, ${positioning.y + positioning.height}, ${positioning.x + positioning.width}];`,
145
+ '',
146
+ ' // Apply fill color',
147
+ ` if ("${fillColor}" !== "") {`,
148
+ ' try {',
149
+ ` ellipse.fillColor = doc.colors.itemByName("${fillColor}");`,
150
+ ' } catch (colorError) {',
151
+ ' // Use default color if specified color not found',
152
+ ' }',
153
+ ' }',
154
+ '',
155
+ ' // Apply stroke color',
156
+ ` if ("${strokeColor}" !== "") {`,
157
+ ' try {',
158
+ ` ellipse.strokeColor = doc.colors.itemByName("${strokeColor}");`,
159
+ ` ellipse.strokeWeight = ${strokeWidth};`,
160
+ ' } catch (colorError) {',
161
+ ' // Use default stroke if specified color not found',
162
+ ' }',
163
+ ' }',
164
+ '',
165
+ ' "Ellipse created successfully";',
166
+ ' } catch (error) {',
167
+ ' "Error creating ellipse: " + error.message;',
168
+ ' }',
169
+ '}'
170
+ ].join('\n');
171
+
172
+ const result = await ScriptExecutor.executeInDesignScript(script);
173
+
174
+ // Store the created item info in session
175
+ sessionManager.setLastCreatedItem({
176
+ type: 'ellipse',
177
+ position: positioning,
178
+ fillColor: fillColor,
179
+ strokeColor: strokeColor,
180
+ strokeWidth: strokeWidth
181
+ });
182
+
183
+ return formatResponse(result, "Create Ellipse");
184
+ }
185
+
186
+ /**
187
+ * Create a polygon on the active page
188
+ */
189
+ static async createPolygon(args) {
190
+ const {
191
+ x,
192
+ y,
193
+ width,
194
+ height,
195
+ sides = 6,
196
+ fillColor,
197
+ strokeColor,
198
+ strokeWidth = 1
199
+ } = args;
200
+
201
+ // Use session manager for positioning if coordinates not provided
202
+ const positioning = sessionManager.getCalculatedPositioning({ x, y, width, height });
203
+
204
+ const script = [
205
+ 'if (app.documents.length === 0) {',
206
+ ' "No document open";',
207
+ '} else {',
208
+ ' var doc = app.activeDocument;',
209
+ ' var page = doc.pages[0];',
210
+ ' var polygon;',
211
+ '',
212
+ ' try {',
213
+ ' // Create polygon',
214
+ ` polygon = page.polygons.add();`,
215
+ ` polygon.geometricBounds = [${positioning.y}, ${positioning.x}, ${positioning.y + positioning.height}, ${positioning.x + positioning.width}];`,
216
+ ` try { polygon.polygonSides = ${sides}; } catch (sideError) {}`,
217
+ '',
218
+ ' // Apply fill color',
219
+ ` if ("${fillColor}" !== "") {`,
220
+ ' try {',
221
+ ` polygon.fillColor = doc.colors.itemByName("${fillColor}");`,
222
+ ' } catch (colorError) {',
223
+ ' // Use default color if specified color not found',
224
+ ' }',
225
+ ' }',
226
+ '',
227
+ ' // Apply stroke color',
228
+ ` if ("${strokeColor}" !== "") {`,
229
+ ' try {',
230
+ ` polygon.strokeColor = doc.colors.itemByName("${strokeColor}");`,
231
+ ` polygon.strokeWeight = ${strokeWidth};`,
232
+ ' } catch (colorError) {',
233
+ ' // Use default stroke if specified color not found',
234
+ ' }',
235
+ ' }',
236
+ '',
237
+ ' "Polygon created successfully";',
238
+ ' } catch (error) {',
239
+ ' "Error creating polygon: " + error.message;',
240
+ ' }',
241
+ '}'
242
+ ].join('\n');
243
+
244
+ const result = await ScriptExecutor.executeInDesignScript(script);
245
+
246
+ // Store the created item info in session
247
+ sessionManager.setLastCreatedItem({
248
+ type: 'polygon',
249
+ sides: sides,
250
+ position: positioning,
251
+ fillColor: fillColor,
252
+ strokeColor: strokeColor,
253
+ strokeWidth: strokeWidth
254
+ });
255
+
256
+ return formatResponse(result, "Create Polygon");
257
+ }
258
+
259
+ /**
260
+ * Place an image on the active page with enhanced options
261
+ */
262
+ static async placeImage(args) {
263
+ const {
264
+ filePath,
265
+ x,
266
+ y,
267
+ width,
268
+ height,
269
+ linkImage = true,
270
+ createProxy = false,
271
+ applyObjectStyle = '',
272
+ imagePreference = {},
273
+ scale = 100,
274
+ fitMode = 'PROPORTIONALLY'
275
+ } = args;
276
+
277
+ // Use session manager for positioning if coordinates not provided
278
+ const positioning = sessionManager.getCalculatedPositioning({ x, y, width, height });
279
+ const escapedFilePath = escapeFilePathForJsx(filePath);
280
+ const escapedObjectStyle = escapeJsxString(applyObjectStyle);
281
+
282
+ const script = [
283
+ 'if (app.documents.length === 0) {',
284
+ ' "No document open";',
285
+ '} else {',
286
+ ' var doc = app.activeDocument;',
287
+ ' var page = app.activeWindow.activePage || doc.pages[0];',
288
+ ' var imageFile;',
289
+ ' var image;',
290
+ '',
291
+ ' try {',
292
+ ` imageFile = File("${escapedFilePath}");`,
293
+ ' if (!imageFile.exists) {',
294
+ ` "ERROR: Image file not found: ${escapedFilePath}";`,
295
+ ' } else {',
296
+ ' // Place image',
297
+ ` image = page.rectangles.add();`,
298
+ ` image.geometricBounds = [${positioning.y}, ${positioning.x}, ${positioning.y + positioning.height}, ${positioning.x + positioning.width}];`,
299
+ '',
300
+ ' // Place the image in the rectangle',
301
+ ' try {',
302
+ ` image.place(imageFile);`,
303
+ '',
304
+ ' // Note: Linking preferences are set automatically by InDesign',
305
+ '',
306
+ ' // Apply object style if specified',
307
+ ` if ("${escapedObjectStyle}" !== "") {`,
308
+ ' try {',
309
+ ` var objectStyle = doc.objectStyles.itemByName("${escapedObjectStyle}");`,
310
+ ' if (objectStyle.isValid) {',
311
+ ' image.appliedObjectStyle = objectStyle;',
312
+ ' }',
313
+ ' } catch (styleError) {',
314
+ ' // Object style not found, continue without it',
315
+ ' }',
316
+ ' }',
317
+ '',
318
+ ' // Apply image scaling and fitting options',
319
+ ' if (image.graphics.length > 0) {',
320
+ ' var graphic = image.graphics[0];',
321
+ ' if (graphic.constructor.name === "Image") {',
322
+ ' // Apply scaling',
323
+ ` if (${scale} !== 100) {`,
324
+ ` graphic.horizontalScale = ${scale};`,
325
+ ` graphic.verticalScale = ${scale};`,
326
+ ' }',
327
+ '',
328
+ ' // Set image fitting options',
329
+ ` if ("${fitMode}" === "FILL_FRAME") {`,
330
+ ' graphic.fit(FitOptions.FILL_PROPORTIONALLY);',
331
+ ` } else if ("${fitMode}" === "FIT_CONTENT") {`,
332
+ ' graphic.fit(FitOptions.CONTENT_TO_FRAME);',
333
+ ` } else if ("${fitMode}" === "FIT_FRAME") {`,
334
+ ' graphic.fit(FitOptions.FRAME_TO_CONTENT);',
335
+ ' } else {',
336
+ ' graphic.fit(FitOptions.PROPORTIONALLY);',
337
+ ' }',
338
+ '',
339
+ ' // Set alignment',
340
+ ' graphic.horizontalAlignment = HorizontalAlignment.CENTER_ALIGN;',
341
+ ' graphic.verticalAlignment = VerticalAlignment.CENTER_ALIGN;',
342
+ ' }',
343
+ ' }',
344
+ '',
345
+ ' "SUCCESS: Image placed successfully at " + imageFile.fsName;',
346
+ ' } catch (placeError) {',
347
+ ' // Remove the rectangle if image placement failed',
348
+ ' image.remove();',
349
+ ` "ERROR: Failed to place image: " + placeError.message;`,
350
+ ' }',
351
+ ' }',
352
+ ' } catch (error) {',
353
+ ' "ERROR: Error placing image: " + error.message;',
354
+ ' }',
355
+ '}'
356
+ ].join('\n');
357
+
358
+ const result = await ScriptExecutor.executeInDesignScript(script);
359
+
360
+ // Check if the operation was successful
361
+ const isSuccess = result.includes("SUCCESS:") && !result.includes("ERROR:");
362
+
363
+ if (isSuccess) {
364
+ // Store the created item info in session
365
+ sessionManager.setLastCreatedItem({
366
+ type: 'image',
367
+ filePath: filePath,
368
+ position: positioning,
369
+ linkImage: linkImage,
370
+ objectStyle: applyObjectStyle
371
+ });
372
+ }
373
+
374
+ return isSuccess ?
375
+ formatResponse(result, "Place Image") :
376
+ formatErrorResponse(result, "Place Image");
377
+ }
378
+
379
+ /**
380
+ * Create an object style
381
+ */
382
+ static async createObjectStyle(args) {
383
+ const {
384
+ name,
385
+ fillColor,
386
+ strokeColor,
387
+ strokeWeight = 1,
388
+ cornerRadius = 0,
389
+ transparency = 100
390
+ } = args;
391
+
392
+ const escapedName = escapeJsxString(name);
393
+
394
+ const script = [
395
+ 'if (app.documents.length === 0) {',
396
+ ' "No document open";',
397
+ '} else {',
398
+ ' var doc = app.activeDocument;',
399
+ '',
400
+ ' try {',
401
+ ` var objectStyle = doc.objectStyles.add({name: "${escapedName}"});`,
402
+ '',
403
+ ' // Apply fill color',
404
+ ` if ("${fillColor}" !== "") {`,
405
+ ' try {',
406
+ ` objectStyle.fillColor = doc.colors.itemByName("${fillColor}");`,
407
+ ' } catch (colorError) {',
408
+ ' // Use default color if specified color not found',
409
+ ' }',
410
+ ' }',
411
+ '',
412
+ ' // Apply stroke color',
413
+ ` if ("${strokeColor}" !== "") {`,
414
+ ' try {',
415
+ ` objectStyle.strokeColor = doc.colors.itemByName("${strokeColor}");`,
416
+ ` objectStyle.strokeWeight = ${strokeWeight};`,
417
+ ' } catch (colorError) {',
418
+ ' // Use default stroke if specified color not found',
419
+ ' }',
420
+ ' }',
421
+ '',
422
+ ' // Apply corner radius',
423
+ ` if (${cornerRadius} > 0) {`,
424
+ ` objectStyle.topLeftCornerOption = CornerOptions.ROUNDED_CORNER;`,
425
+ ` objectStyle.topRightCornerOption = CornerOptions.ROUNDED_CORNER;`,
426
+ ` objectStyle.bottomLeftCornerOption = CornerOptions.ROUNDED_CORNER;`,
427
+ ` objectStyle.bottomRightCornerOption = CornerOptions.ROUNDED_CORNER;`,
428
+ ` objectStyle.topLeftCornerRadius = ${cornerRadius};`,
429
+ ` objectStyle.topRightCornerRadius = ${cornerRadius};`,
430
+ ` objectStyle.bottomLeftCornerRadius = ${cornerRadius};`,
431
+ ` objectStyle.bottomRightCornerRadius = ${cornerRadius};`,
432
+ ' }',
433
+ '',
434
+ ' // Apply transparency',
435
+ ` if (${transparency} < 100) {`,
436
+ ` objectStyle.transparencySettings.blendingSettings.opacity = ${transparency};`,
437
+ ' }',
438
+ '',
439
+ ` "Object style '${escapedName}' created successfully";`,
440
+ ' } catch (error) {',
441
+ ' "Error creating object style: " + error.message;',
442
+ ' }',
443
+ '}'
444
+ ].join('\n');
445
+
446
+ const result = await ScriptExecutor.executeInDesignScript(script);
447
+ return result.includes("created successfully") ?
448
+ formatResponse(result, "Create Object Style") :
449
+ formatErrorResponse(result, "Create Object Style");
450
+ }
451
+
452
+ /**
453
+ * List all object styles
454
+ */
455
+ static async listObjectStyles() {
456
+ const script = [
457
+ 'if (app.documents.length === 0) {',
458
+ ' "No document open";',
459
+ '} else {',
460
+ ' var doc = app.activeDocument;',
461
+ ' var info = "=== OBJECT STYLES ===\\n";',
462
+ '',
463
+ ' for (var i = 0; i < doc.objectStyles.length; i++) {',
464
+ ' var style = doc.objectStyles[i];',
465
+ ' if (style.isValid) {',
466
+ ' info += "Name: " + style.name + "\\n";',
467
+ ' try { info += " Fill Color: " + (style.fillColor ? style.fillColor.name : "None") + "\\n"; } catch (_) {}',
468
+ ' try { info += " Stroke Color: " + (style.strokeColor ? style.strokeColor.name : "None") + "\\n"; } catch (_) {}',
469
+ ' try { info += " Stroke Weight: " + style.strokeWeight + "\\n"; } catch (_) {}',
470
+ ' try { info += " Top Left Corner: " + style.topLeftCornerOption + "\\n"; } catch (_) {}',
471
+ ' try { info += " Top Left Corner Radius: " + style.topLeftCornerRadius + "\\n"; } catch (_) {}',
472
+ ' info += "\\n";',
473
+ ' }',
474
+ ' }',
475
+ '',
476
+ ' info;',
477
+ '}'
478
+ ].join('\n');
479
+
480
+ const result = await ScriptExecutor.executeInDesignScript(script);
481
+ return formatResponse(result, "List Object Styles");
482
+ }
483
+
484
+ /**
485
+ * Apply object style to a page item
486
+ */
487
+ static async applyObjectStyle(args) {
488
+ const {
489
+ styleName,
490
+ itemType = 'rectangle',
491
+ itemIndex = 0
492
+ } = args;
493
+
494
+ const escapedStyleName = escapeJsxString(styleName);
495
+
496
+ const script = [
497
+ 'if (app.documents.length === 0) {',
498
+ ' "No document open";',
499
+ '} else {',
500
+ ' var doc = app.activeDocument;',
501
+ ' var page = doc.pages[0];',
502
+ '',
503
+ ' try {',
504
+ ` var objectStyle = doc.objectStyles.itemByName("${escapedStyleName}");`,
505
+ ' if (!objectStyle.isValid) {',
506
+ ` "Object style '${escapedStyleName}' not found";`,
507
+ ' } else {',
508
+ ` var item;`,
509
+ ` if ("${itemType}" === "rectangle") {`,
510
+ ` if (${itemIndex} >= page.rectangles.length) {`,
511
+ ' "Rectangle index out of range";',
512
+ ' } else {',
513
+ ` item = page.rectangles[${itemIndex}];`,
514
+ ' }',
515
+ ` } else if ("${itemType}" === "ellipse") {`,
516
+ ` if (${itemIndex} >= page.ovals.length) {`,
517
+ ' "Ellipse index out of range";',
518
+ ' } else {',
519
+ ` item = page.ovals[${itemIndex}];`,
520
+ ' }',
521
+ ` } else if ("${itemType}" === "polygon") {`,
522
+ ` if (${itemIndex} >= page.polygons.length) {`,
523
+ ' "Polygon index out of range";',
524
+ ' } else {',
525
+ ` item = page.polygons[${itemIndex}];`,
526
+ ' }',
527
+ ' } else {',
528
+ ' "Invalid item type. Use: rectangle, ellipse, or polygon";',
529
+ ' }',
530
+ '',
531
+ ' if (item) {',
532
+ ' item.appliedObjectStyle = objectStyle;',
533
+ ` "Object style '${escapedStyleName}' applied successfully";`,
534
+ ' }',
535
+ ' }',
536
+ ' } catch (error) {',
537
+ ' "Error applying object style: " + error.message;',
538
+ ' }',
539
+ '}'
540
+ ].join('\n');
541
+
542
+ const result = await ScriptExecutor.executeInDesignScript(script);
543
+ return formatResponse(result, "Apply Object Style");
544
+ }
545
+
546
+ /**
547
+ * Get image information
548
+ */
549
+ static async getImageInfo(args) {
550
+ const { itemIndex = 0 } = args;
551
+
552
+ const script = [
553
+ 'if (app.documents.length === 0) {',
554
+ ' "No document open";',
555
+ '} else {',
556
+ ' var doc = app.activeDocument;',
557
+ ' var info = "=== IMAGE INFORMATION ===\\n";',
558
+ '',
559
+ ' try {',
560
+ ' // Find placed graphics in rectangles',
561
+ ' var imageCount = 0;',
562
+ ' var foundInfo = "";',
563
+ ' for (var p = 0; p < doc.pages.length; p++) {',
564
+ ' var page = doc.pages[p];',
565
+ ' for (var i = 0; i < page.rectangles.length; i++) {',
566
+ ' var rect = page.rectangles[i];',
567
+ ' if (rect.graphics.length > 0) {',
568
+ ' for (var j = 0; j < rect.graphics.length; j++) {',
569
+ ' var graphic = rect.graphics[j];',
570
+ ` if (imageCount === ${itemIndex}) {`,
571
+ ' foundInfo += "Image " + imageCount + ":\\n";',
572
+ ' foundInfo += " Page: " + (p + 1) + "\\n";',
573
+ ' foundInfo += " Graphic Type: " + graphic.constructor.name + "\\n";',
574
+ ' try { foundInfo += " File Path: " + graphic.itemLink.filePath + "\\n"; } catch (_) {}',
575
+ ' try { foundInfo += " File Name: " + graphic.itemLink.name + "\\n"; } catch (_) {}',
576
+ ' try { foundInfo += " Link Status: " + graphic.itemLink.status + "\\n"; } catch (_) {}',
577
+ ' try { foundInfo += " Image Type: " + graphic.imageTypeName + "\\n"; } catch (_) {}',
578
+ ' try { foundInfo += " Actual PPI: " + graphic.actualPpi + "\\n"; } catch (_) {}',
579
+ ' try { foundInfo += " Effective PPI: " + graphic.effectivePpi + "\\n"; } catch (_) {}',
580
+ ' try { foundInfo += " Geometric Bounds: " + graphic.geometricBounds + "\\n"; } catch (_) {}',
581
+ ' try { foundInfo += " Visible Bounds: " + graphic.visibleBounds + "\\n"; } catch (_) {}',
582
+ ' }',
583
+ ' imageCount++;',
584
+ ' }',
585
+ ' }',
586
+ ' }',
587
+ ' }',
588
+ '',
589
+ ` if (imageCount === 0) {`,
590
+ ' "No images found on page";',
591
+ ` } else if (imageCount <= ${itemIndex}) {`,
592
+ ` "Image index ${itemIndex} not found. Total images: " + imageCount;`,
593
+ ' } else {',
594
+ ' info + foundInfo;',
595
+ ' }',
596
+ ' } catch (error) {',
597
+ ' "Error getting image information: " + error.message;',
598
+ ' }',
599
+ '}'
600
+ ].join('\n');
601
+
602
+ const result = await ScriptExecutor.executeInDesignScript(script);
603
+ return formatResponse(result, "Get Image Info");
604
+ }
605
+ }