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,698 @@
1
+ /**
2
+ * Page management handlers
3
+ */
4
+ import { ScriptExecutor } from '../core/scriptExecutor.js';
5
+ import { formatResponse, escapeJsxString, escapeFilePathForJsx } from '../utils/stringUtils.js';
6
+
7
+ export class PageHandlers {
8
+ /**
9
+ * Add a new page to the document
10
+ */
11
+ static async addPage(args) {
12
+ const { position = 'AT_END', referencePage } = args;
13
+
14
+ const script = [
15
+ 'if (app.documents.length === 0) {',
16
+ ' "No document open";',
17
+ '} else {',
18
+ ' var doc = app.activeDocument;',
19
+ ' var newPage;',
20
+ '',
21
+ ' try {',
22
+ ` if ("${position}" === "AT_END") {`,
23
+ ' newPage = doc.pages.add();',
24
+ ` } else if ("${position}" === "AT_BEGINNING") {`,
25
+ ' newPage = doc.pages.add(LocationOptions.AT_BEGINNING);',
26
+ ` } else if ("${position}" === "BEFORE" && ${referencePage} !== undefined) {`,
27
+ ` newPage = doc.pages.add(LocationOptions.BEFORE, doc.pages[${referencePage}]);`,
28
+ ` } else if ("${position}" === "AFTER" && ${referencePage} !== undefined) {`,
29
+ ` newPage = doc.pages.add(LocationOptions.AFTER, doc.pages[${referencePage}]);`,
30
+ ' } else {',
31
+ ' newPage = doc.pages.add();',
32
+ ' }',
33
+ '',
34
+ ' "Page added successfully. Total pages: " + doc.pages.length;',
35
+ ' } catch (error) {',
36
+ ' "Error adding page: " + error.message;',
37
+ ' }',
38
+ '}'
39
+ ].join('\n');
40
+
41
+ const result = await ScriptExecutor.executeInDesignScript(script);
42
+ return formatResponse(result, "Add Page");
43
+ }
44
+
45
+ /**
46
+ * Get detailed information about a specific page
47
+ */
48
+ static async getPageInfo(args) {
49
+ const { pageIndex } = args;
50
+
51
+ const script = [
52
+ 'if (app.documents.length === 0) {',
53
+ ' "No document open";',
54
+ '} else {',
55
+ ' var doc = app.activeDocument;',
56
+ ` if (${pageIndex} >= doc.pages.length) {`,
57
+ ' "Page index out of range";',
58
+ ' } else {',
59
+ ` var page = doc.pages[${pageIndex}];`,
60
+ ' var info = "=== PAGE INFO ===\\n";',
61
+ ' info += "Index: " + page.documentOffset + "\\n";',
62
+ ' info += "Name: " + page.name + "\\n";',
63
+ ' info += "Label: " + page.label + "\\n";',
64
+ ' info += "Bounds: " + page.bounds + "\\n";',
65
+ ' info += "Side: " + page.side + "\\n";',
66
+ ' info += "Applied Master: " + (page.appliedMaster ? page.appliedMaster.name : "None") + "\\n";',
67
+ ' info += "Page Color: " + page.pageColor + "\\n";',
68
+ ' info += "Optional Page: " + page.optionalPage + "\\n";',
69
+ ' info += "Layout Rule: " + page.layoutRule + "\\n";',
70
+ ' info;',
71
+ ' }',
72
+ '}'
73
+ ].join('\n');
74
+
75
+ const result = await ScriptExecutor.executeInDesignScript(script);
76
+ return formatResponse(result, "Get Page Info");
77
+ }
78
+
79
+ /**
80
+ * Navigate to a specific page
81
+ */
82
+ static async navigateToPage(args) {
83
+ const { pageIndex } = args;
84
+
85
+ const script = [
86
+ 'if (app.documents.length === 0) {',
87
+ ' "No document open";',
88
+ '} else {',
89
+ ' var doc = app.activeDocument;',
90
+ ` if (${pageIndex} >= doc.pages.length) {`,
91
+ ' "Page index out of range";',
92
+ ' } else {',
93
+ ` doc.pages[${pageIndex}].select();`,
94
+ ` "Navigated to page ${pageIndex}";`,
95
+ ' }',
96
+ '}'
97
+ ].join('\n');
98
+
99
+ const result = await ScriptExecutor.executeInDesignScript(script);
100
+ return formatResponse(result, "Navigate to Page");
101
+ }
102
+
103
+ /**
104
+ * Delete a specific page from the document
105
+ */
106
+ static async deletePage(args) {
107
+ const { pageIndex } = args;
108
+
109
+ const script = [
110
+ 'if (app.documents.length === 0) {',
111
+ ' "No document open";',
112
+ '} else {',
113
+ ' var doc = app.activeDocument;',
114
+ ` if (${pageIndex} >= doc.pages.length) {`,
115
+ ' "Page index out of range";',
116
+ ' } else {',
117
+ ' try {',
118
+ ` doc.pages[${pageIndex}].remove();`,
119
+ ' "Page deleted successfully. Total pages: " + doc.pages.length;',
120
+ ' } catch (error) {',
121
+ ' "Error deleting page: " + error.message;',
122
+ ' }',
123
+ ' }',
124
+ '}'
125
+ ].join('\n');
126
+
127
+ const result = await ScriptExecutor.executeInDesignScript(script);
128
+ return formatResponse(result, "Delete Page");
129
+ }
130
+
131
+ /**
132
+ * Duplicate a specific page
133
+ */
134
+ static async duplicatePage(args) {
135
+ const { pageIndex } = args;
136
+
137
+ const script = [
138
+ 'if (app.documents.length === 0) {',
139
+ ' "No document open";',
140
+ '} else {',
141
+ ' var doc = app.activeDocument;',
142
+ ` if (${pageIndex} >= doc.pages.length) {`,
143
+ ' "Page index out of range";',
144
+ ' } else {',
145
+ ' try {',
146
+ ` var originalPage = doc.pages[${pageIndex}];`,
147
+ ' var newPage = originalPage.duplicate();',
148
+ ' "Page duplicated successfully. Total pages: " + doc.pages.length;',
149
+ ' } catch (error) {',
150
+ ' "Error duplicating page: " + error.message;',
151
+ ' }',
152
+ ' }',
153
+ '}'
154
+ ].join('\n');
155
+
156
+ const result = await ScriptExecutor.executeInDesignScript(script);
157
+ return formatResponse(result, "Duplicate Page");
158
+ }
159
+
160
+ /**
161
+ * Move a page to a different position
162
+ */
163
+ static async movePage(args) {
164
+ const { pageIndex, newPosition } = args;
165
+
166
+ const script = [
167
+ 'if (app.documents.length === 0) {',
168
+ ' "No document open";',
169
+ '} else {',
170
+ ' var doc = app.activeDocument;',
171
+ ` if (${pageIndex} >= doc.pages.length) {`,
172
+ ' "Page index out of range";',
173
+ ' } else {',
174
+ ' try {',
175
+ ` var page = doc.pages[${pageIndex}];`,
176
+ ` page.move(LocationOptions.${newPosition});`,
177
+ ' "Page moved successfully";',
178
+ ' } catch (error) {',
179
+ ' "Error moving page: " + error.message;',
180
+ ' }',
181
+ ' }',
182
+ '}'
183
+ ].join('\n');
184
+
185
+ const result = await ScriptExecutor.executeInDesignScript(script);
186
+ return formatResponse(result, "Move Page");
187
+ }
188
+
189
+ /**
190
+ * Get all pages in the document
191
+ */
192
+ static async getAllPages(args) {
193
+ const script = [
194
+ 'if (app.documents.length === 0) {',
195
+ ' "No document open";',
196
+ '} else {',
197
+ ' var doc = app.activeDocument;',
198
+ ' var pages = doc.pages;',
199
+ ' var info = "=== ALL PAGES ===\\n";',
200
+ ' info += "Total pages: " + pages.length + "\\n\\n";',
201
+ ' for (var i = 0; i < pages.length; i++) {',
202
+ ' var page = pages[i];',
203
+ ' info += "Page " + i + ":\\n";',
204
+ ' info += " Name: " + page.name + "\\n";',
205
+ ' info += " Label: " + page.label + "\\n";',
206
+ ' info += " Applied Master: " + (page.appliedMaster ? page.appliedMaster.name : "None") + "\\n";',
207
+ ' info += "\\n";',
208
+ ' }',
209
+ ' info;',
210
+ '}'
211
+ ].join('\n');
212
+
213
+ const result = await ScriptExecutor.executeInDesignScript(script);
214
+ return formatResponse(result, "Get All Pages");
215
+ }
216
+
217
+ // =================== ADVANCED PAGE PROPERTIES ===================
218
+
219
+ /**
220
+ * Set properties for a page
221
+ */
222
+ static async setPageProperties(args) {
223
+ const { pageIndex, label, pageColor, optionalPage, layoutRule, snapshotBlendingMode, appliedTrapPreset } = args;
224
+ const pageColorLiteral = pageColor
225
+ ? (/^\s*\[/.test(String(pageColor))
226
+ ? String(pageColor)
227
+ : `UIColors.${/^[A-Z_]+$/.test(String(pageColor).trim().toUpperCase()) ? String(pageColor).trim().toUpperCase() : 'BLUE'}`)
228
+ : null;
229
+
230
+ const script = [
231
+ 'if (app.documents.length === 0) {',
232
+ ' "No document open";',
233
+ '} else {',
234
+ ' var doc = app.activeDocument;',
235
+ ` if (${pageIndex} >= doc.pages.length) {`,
236
+ ' "Page index out of range";',
237
+ ' } else {',
238
+ ` var page = doc.pages[${pageIndex}];`,
239
+ ' try {',
240
+ ...(label ? [` page.label = "${escapeJsxString(label)}";`] : []),
241
+ ...(pageColorLiteral ? [` page.pageColor = ${pageColorLiteral};`] : []),
242
+ ...(optionalPage !== undefined ? [` page.optionalPage = ${optionalPage};`] : []),
243
+ ...(layoutRule ? [` page.layoutRule = LayoutRule.${layoutRule};`] : []),
244
+ ...(snapshotBlendingMode ? [` page.snapshotBlendingMode = SnapshotBlendingMode.${snapshotBlendingMode};`] : []),
245
+ ...(appliedTrapPreset ? [` page.appliedTrapPreset = "${escapeJsxString(appliedTrapPreset)}";`] : []),
246
+ ' "Page properties updated successfully";',
247
+ ' } catch (error) {',
248
+ ' "Error updating page properties: " + error.message;',
249
+ ' }',
250
+ ' }',
251
+ '}'
252
+ ].join('\n');
253
+
254
+ const result = await ScriptExecutor.executeInDesignScript(script);
255
+ return formatResponse(result, "Set Page Properties");
256
+ }
257
+
258
+ /**
259
+ * Adjust page layout with new dimensions and margins
260
+ */
261
+ static async adjustPageLayout(args) {
262
+ const { pageIndex, width, height, bleedInside, bleedTop, bleedOutside, bleedBottom, leftMargin, topMargin, rightMargin, bottomMargin } = args;
263
+ const updates = [];
264
+ const safeSet = (name, statement) => (
265
+ `try { ${statement} updatedCount++; } catch (e) { skipped.push("${name}: " + e.message); }`
266
+ );
267
+ if (width) updates.push(safeSet('size', `page.resize(CoordinateSpaces.PAGE_COORDINATES, AnchorPoint.CENTER_ANCHOR, ResizeMethods.REPLACING_CURRENT_DIMENSIONS_WITH, UnitValue("${escapeJsxString(String(width))}"), UnitValue("${escapeJsxString(String(height || width))}"));`));
268
+ if (leftMargin) updates.push(safeSet('leftMargin', `page.marginPreferences.left = UnitValue("${escapeJsxString(String(leftMargin))}");`));
269
+ if (topMargin) updates.push(safeSet('topMargin', `page.marginPreferences.top = UnitValue("${escapeJsxString(String(topMargin))}");`));
270
+ if (rightMargin) updates.push(safeSet('rightMargin', `page.marginPreferences.right = UnitValue("${escapeJsxString(String(rightMargin))}");`));
271
+ if (bottomMargin) updates.push(safeSet('bottomMargin', `page.marginPreferences.bottom = UnitValue("${escapeJsxString(String(bottomMargin))}");`));
272
+ if (bleedInside) updates.push(safeSet('bleedInside', `page.bleedBoxPreferences.inside = UnitValue("${escapeJsxString(String(bleedInside))}");`));
273
+ if (bleedTop) updates.push(safeSet('bleedTop', `page.bleedBoxPreferences.top = UnitValue("${escapeJsxString(String(bleedTop))}");`));
274
+ if (bleedOutside) updates.push(safeSet('bleedOutside', `page.bleedBoxPreferences.outside = UnitValue("${escapeJsxString(String(bleedOutside))}");`));
275
+ if (bleedBottom) updates.push(safeSet('bleedBottom', `page.bleedBoxPreferences.bottom = UnitValue("${escapeJsxString(String(bleedBottom))}");`));
276
+
277
+ const script = [
278
+ 'if (app.documents.length === 0) {',
279
+ ' "No document open";',
280
+ '} else {',
281
+ ' var doc = app.activeDocument;',
282
+ ` if (${pageIndex} >= doc.pages.length) {`,
283
+ ' "Page index out of range";',
284
+ ' } else {',
285
+ ` var page = doc.pages[${pageIndex}];`,
286
+ ' var updatedCount = 0;',
287
+ ' var skipped = [];',
288
+ ' try {',
289
+ ...(updates.length ? updates : [' // No page layout changes provided']),
290
+ ' "Page layout adjusted successfully. Updated: " + updatedCount + ", skipped: " + skipped.length;',
291
+ ' } catch (error) {',
292
+ ' "Error adjusting page layout: " + error.message;',
293
+ ' }',
294
+ ' }',
295
+ '}'
296
+ ].join('\n');
297
+
298
+ const result = await ScriptExecutor.executeInDesignScript(script);
299
+ return formatResponse(result, "Adjust Page Layout");
300
+ }
301
+
302
+ /**
303
+ * Resize a page
304
+ */
305
+ static async resizePage(args) {
306
+ const { pageIndex, width, height, resizeMethod = 'REPLACING_CURRENT_DIMENSIONS_WITH', anchorPoint = 'CENTER_ANCHOR', coordinateSpace = 'PAGE_COORDINATES' } = args;
307
+
308
+ const script = [
309
+ 'if (app.documents.length === 0) {',
310
+ ' "No document open";',
311
+ '} else {',
312
+ ' var doc = app.activeDocument;',
313
+ ` if (${pageIndex} >= doc.pages.length) {`,
314
+ ' "Page index out of range";',
315
+ ' } else {',
316
+ ` var page = doc.pages[${pageIndex}];`,
317
+ ' try {',
318
+ ` try {`,
319
+ ` page.resize(CoordinateSpaces.${coordinateSpace}, AnchorPoint.${anchorPoint}, ResizeMethods.${resizeMethod}, [${width}, ${height}]);`,
320
+ ` } catch (resizeError) {`,
321
+ ` page.reframe(CoordinateSpaces.${coordinateSpace}, [[0, 0], [${width}, ${height}]]);`,
322
+ ` }`,
323
+ ' "Page resized successfully";',
324
+ ' } catch (error) {',
325
+ ' "Error resizing page: " + error.message;',
326
+ ' }',
327
+ ' }',
328
+ '}'
329
+ ].join('\n');
330
+
331
+ const result = await ScriptExecutor.executeInDesignScript(script);
332
+ return formatResponse(result, "Resize Page");
333
+ }
334
+
335
+ /**
336
+ * Place a file on a page
337
+ */
338
+ static async placeFileOnPage(args) {
339
+ const { pageIndex, filePath, x = 10, y = 10, layerName, showingOptions = false, autoflowing = false } = args;
340
+
341
+ const escapedFilePath = escapeFilePathForJsx(filePath);
342
+ const escapedLayerName = layerName ? escapeJsxString(layerName) : '';
343
+
344
+ const script = [
345
+ 'if (app.documents.length === 0) {',
346
+ ' "No document open";',
347
+ '} else {',
348
+ ' var doc = app.activeDocument;',
349
+ ` if (${pageIndex} >= doc.pages.length) {`,
350
+ ' "Page index out of range";',
351
+ ' } else {',
352
+ ` var page = doc.pages[${pageIndex}];`,
353
+ ` var file = File("${escapedFilePath}");`,
354
+ ' try {',
355
+ ' var previousLayer = doc.activeLayer;',
356
+ ...(escapedLayerName ? [
357
+ ` var layer = doc.layers.itemByName("${escapedLayerName}");`,
358
+ ' if (layer && layer.isValid) doc.activeLayer = layer;'
359
+ ] : []),
360
+ ` var placedItem = page.place(file, [${x}, ${y}]);`,
361
+ ' try { doc.activeLayer = previousLayer; } catch (restoreLayerError) {}',
362
+ ' "File placed successfully on page";',
363
+ ' } catch (error) {',
364
+ ' try { if (previousLayer && previousLayer.isValid) doc.activeLayer = previousLayer; } catch (restoreLayerError) {}',
365
+ ' "Error placing file: " + error.message;',
366
+ ' }',
367
+ ' }',
368
+ '}'
369
+ ].join('\n');
370
+
371
+ const result = await ScriptExecutor.executeInDesignScript(script);
372
+ return formatResponse(result, "Place File on Page");
373
+ }
374
+
375
+ /**
376
+ * Place XML content on a page
377
+ */
378
+ static async placeXmlOnPage(args) {
379
+ const { pageIndex, xmlElementName, x = 10, y = 10, autoflowing = false } = args;
380
+
381
+ const escapedXmlElementName = escapeJsxString(xmlElementName);
382
+
383
+ const script = [
384
+ 'if (app.documents.length === 0) {',
385
+ ' "No document open";',
386
+ '} else {',
387
+ ' var doc = app.activeDocument;',
388
+ ` if (${pageIndex} >= doc.pages.length) {`,
389
+ ' "Page index out of range";',
390
+ ' } else {',
391
+ ` var page = doc.pages[${pageIndex}];`,
392
+ ' try {',
393
+ ` var xmlElement = doc.xmlElements.itemByName("${escapedXmlElementName}");`,
394
+ ` var placedItem = page.placeXML(xmlElement, [${x}, ${y}], ${autoflowing});`,
395
+ ' "XML content placed successfully on page";',
396
+ ' } catch (error) {',
397
+ ' "Error placing XML content: " + error.message;',
398
+ ' }',
399
+ ' }',
400
+ '}'
401
+ ].join('\n');
402
+
403
+ const result = await ScriptExecutor.executeInDesignScript(script);
404
+ return formatResponse(result, "Place XML on Page");
405
+ }
406
+
407
+ /**
408
+ * Create a snapshot of the current page layout
409
+ */
410
+ static async snapshotPageLayout(args) {
411
+ const { pageIndex } = args;
412
+
413
+ const script = [
414
+ 'if (app.documents.length === 0) {',
415
+ ' "No document open";',
416
+ '} else {',
417
+ ' var doc = app.activeDocument;',
418
+ ` if (${pageIndex} >= doc.pages.length) {`,
419
+ ' "Page index out of range";',
420
+ ' } else {',
421
+ ` var page = doc.pages[${pageIndex}];`,
422
+ ' try {',
423
+ ' if (typeof page.createLayoutSnapshot === "function") {',
424
+ ' page.createLayoutSnapshot();',
425
+ ' "Page layout snapshot created successfully";',
426
+ ' } else {',
427
+ ' "Page layout snapshot not available in this InDesign version";',
428
+ ' }',
429
+ ' } catch (error) {',
430
+ ' "Error creating page layout snapshot: " + error.message;',
431
+ ' }',
432
+ ' }',
433
+ '}'
434
+ ].join('\n');
435
+
436
+ const result = await ScriptExecutor.executeInDesignScript(script);
437
+ return formatResponse(result, "Snapshot Page Layout");
438
+ }
439
+
440
+ /**
441
+ * Delete the layout snapshot for a page
442
+ */
443
+ static async deletePageLayoutSnapshot(args) {
444
+ const { pageIndex } = args;
445
+
446
+ const script = [
447
+ 'if (app.documents.length === 0) {',
448
+ ' "No document open";',
449
+ '} else {',
450
+ ' var doc = app.activeDocument;',
451
+ ` if (${pageIndex} >= doc.pages.length) {`,
452
+ ' "Page index out of range";',
453
+ ' } else {',
454
+ ` var page = doc.pages[${pageIndex}];`,
455
+ ' try {',
456
+ ' if (typeof page.deleteLayoutSnapshot === "function") {',
457
+ ' page.deleteLayoutSnapshot();',
458
+ ' "Page layout snapshot deleted successfully";',
459
+ ' } else {',
460
+ ' "Page layout snapshot delete not available in this InDesign version";',
461
+ ' }',
462
+ ' } catch (error) {',
463
+ ' "Error deleting page layout snapshot: " + error.message;',
464
+ ' }',
465
+ ' }',
466
+ '}'
467
+ ].join('\n');
468
+
469
+ const result = await ScriptExecutor.executeInDesignScript(script);
470
+ return formatResponse(result, "Delete Page Layout Snapshot");
471
+ }
472
+
473
+ /**
474
+ * Delete all layout snapshots for a page
475
+ */
476
+ static async deleteAllPageLayoutSnapshots(args) {
477
+ const { pageIndex } = args;
478
+
479
+ const script = [
480
+ 'if (app.documents.length === 0) {',
481
+ ' "No document open";',
482
+ '} else {',
483
+ ' var doc = app.activeDocument;',
484
+ ` if (${pageIndex} >= doc.pages.length) {`,
485
+ ' "Page index out of range";',
486
+ ' } else {',
487
+ ` var page = doc.pages[${pageIndex}];`,
488
+ ' try {',
489
+ ' if (typeof page.deleteAllLayoutSnapshots === "function") {',
490
+ ' page.deleteAllLayoutSnapshots();',
491
+ ' "All page layout snapshots deleted successfully";',
492
+ ' } else {',
493
+ ' "All page layout snapshot delete not available in this InDesign version";',
494
+ ' }',
495
+ ' } catch (error) {',
496
+ ' "Error deleting all page layout snapshots: " + error.message;',
497
+ ' }',
498
+ ' }',
499
+ '}'
500
+ ].join('\n');
501
+
502
+ const result = await ScriptExecutor.executeInDesignScript(script);
503
+ return formatResponse(result, "Delete All Page Layout Snapshots");
504
+ }
505
+
506
+ /**
507
+ * Reframe (resize) a page
508
+ */
509
+ static async reframePage(args) {
510
+ const { pageIndex, x1, y1, x2, y2, coordinateSpace = 'PAGE_COORDINATES' } = args;
511
+
512
+ const script = [
513
+ 'if (app.documents.length === 0) {',
514
+ ' "No document open";',
515
+ '} else {',
516
+ ' var doc = app.activeDocument;',
517
+ ` if (${pageIndex} >= doc.pages.length) {`,
518
+ ' "Page index out of range";',
519
+ ' } else {',
520
+ ` var page = doc.pages[${pageIndex}];`,
521
+ ' try {',
522
+ ` page.reframe(CoordinateSpaces.${coordinateSpace}, [[${x1}, ${y1}], [${x2}, ${y2}]]);`,
523
+ ' "Page reframed successfully";',
524
+ ' } catch (error) {',
525
+ ' "Error reframing page: " + error.message;',
526
+ ' }',
527
+ ' }',
528
+ '}'
529
+ ].join('\n');
530
+
531
+ const result = await ScriptExecutor.executeInDesignScript(script);
532
+ return formatResponse(result, "Reframe Page");
533
+ }
534
+
535
+ /**
536
+ * Create guides on a page
537
+ */
538
+ static async createPageGuides(args) {
539
+ const { pageIndex, numberOfRows = 0, numberOfColumns = 0, rowGutter = 5, columnGutter = 5, guideColor = 'BLUE', fitMargins = true, removeExisting = false, layerName } = args;
540
+
541
+ const escapedLayerName = layerName ? escapeJsxString(layerName) : '';
542
+ const formatUnit = (value) => {
543
+ const text = String(value);
544
+ return /[a-z%]/i.test(text) ? text : `${text}mm`;
545
+ };
546
+ const rowGutterUnit = escapeJsxString(formatUnit(rowGutter));
547
+ const columnGutterUnit = escapeJsxString(formatUnit(columnGutter));
548
+ const normalizedGuideColor = typeof guideColor === 'string' ? guideColor.trim() : 'BLUE';
549
+ const guideColorLiteral = /^\s*\[/.test(normalizedGuideColor)
550
+ ? normalizedGuideColor
551
+ : `UIColors.${/^[A-Z_]+$/.test(normalizedGuideColor.toUpperCase()) ? normalizedGuideColor.toUpperCase() : 'BLUE'}`;
552
+
553
+ const script = [
554
+ 'if (app.documents.length === 0) {',
555
+ ' "No document open";',
556
+ '} else {',
557
+ ' var doc = app.activeDocument;',
558
+ ` if (${pageIndex} >= doc.pages.length) {`,
559
+ ' "Page index out of range";',
560
+ ' } else {',
561
+ ` var page = doc.pages[${pageIndex}];`,
562
+ ' try {',
563
+ ...(escapedLayerName ? [` var layer = doc.layers.itemByName("${escapedLayerName}");`] : []),
564
+ ...(removeExisting ? [' page.guides.everyItem().remove();'] : []),
565
+ ' var guideTarget = (typeof page.createGuides === "function") ? page : page.parent;',
566
+ ` guideTarget.createGuides(${numberOfRows}, ${numberOfColumns}, "${rowGutterUnit}", "${columnGutterUnit}", ${guideColorLiteral}, ${fitMargins}${escapedLayerName ? ', layer' : ''});`,
567
+ ' "Page guides created successfully";',
568
+ ' } catch (error) {',
569
+ ' "Error creating page guides: " + error.message;',
570
+ ' }',
571
+ ' }',
572
+ '}'
573
+ ].join('\n');
574
+
575
+ const result = await ScriptExecutor.executeInDesignScript(script);
576
+ return formatResponse(result, "Create Page Guides");
577
+ }
578
+
579
+ /**
580
+ * Select a page
581
+ */
582
+ static async selectPage(args) {
583
+ const { pageIndex, selectionMode = 'REPLACE_WITH' } = args;
584
+
585
+ const script = [
586
+ 'if (app.documents.length === 0) {',
587
+ ' "No document open";',
588
+ '} else {',
589
+ ' var doc = app.activeDocument;',
590
+ ` if (${pageIndex} >= doc.pages.length) {`,
591
+ ' "Page index out of range";',
592
+ ' } else {',
593
+ ` var page = doc.pages[${pageIndex}];`,
594
+ ' try {',
595
+ ` page.select(SelectionOptions.${selectionMode});`,
596
+ ' "Page selected successfully";',
597
+ ' } catch (error) {',
598
+ ' "Error selecting page: " + error.message;',
599
+ ' }',
600
+ ' }',
601
+ '}'
602
+ ].join('\n');
603
+
604
+ const result = await ScriptExecutor.executeInDesignScript(script);
605
+ return formatResponse(result, "Select Page");
606
+ }
607
+
608
+ /**
609
+ * Get a summary of content on a page
610
+ */
611
+ static async getPageContentSummary(args) {
612
+ const { pageIndex } = args;
613
+
614
+ const script = [
615
+ 'if (app.documents.length === 0) {',
616
+ ' "No document open";',
617
+ '} else {',
618
+ ' var doc = app.activeDocument;',
619
+ ` if (${pageIndex} >= doc.pages.length) {`,
620
+ ' "Page index out of range";',
621
+ ' } else {',
622
+ ` var page = doc.pages[${pageIndex}];`,
623
+ ' var summary = "=== PAGE CONTENT SUMMARY ===\\n";',
624
+ ' summary += "Page: " + page.name + "\\n";',
625
+ ' summary += "Text Frames: " + page.textFrames.length + "\\n";',
626
+ ' summary += "Rectangles: " + page.rectangles.length + "\\n";',
627
+ ' summary += "Ellipses: " + page.ovals.length + "\\n";',
628
+ ' try { summary += "Graphics: " + page.graphics.length + "\\n"; } catch (graphicsError) { summary += "Graphics: Not available\\n"; }',
629
+ ' summary += "Groups: " + page.groups.length + "\\n";',
630
+ ' summary += "Total Items: " + page.allPageItems.length + "\\n";',
631
+ ' summary;',
632
+ ' }',
633
+ '}'
634
+ ].join('\n');
635
+
636
+ const result = await ScriptExecutor.executeInDesignScript(script);
637
+ return formatResponse(result, "Get Page Content Summary");
638
+ }
639
+
640
+ /**
641
+ * Set page background by creating a full-page rectangle
642
+ */
643
+ static async setPageBackground(args) {
644
+ const { pageIndex = 0, backgroundColor = 'White', opacity = 100 } = args;
645
+
646
+ const script = [
647
+ 'if (app.documents.length === 0) {',
648
+ ' "No document open";',
649
+ '} else {',
650
+ ' var doc = app.activeDocument;',
651
+ ` if (${pageIndex} >= doc.pages.length) {`,
652
+ ' "Page index out of range";',
653
+ ' } else {',
654
+ ` var page = doc.pages[${pageIndex}];`,
655
+ ' try {',
656
+ ' // Get page bounds',
657
+ ' var pageBounds = page.bounds;',
658
+ ' var pageWidth = pageBounds[3] - pageBounds[1];',
659
+ ' var pageHeight = pageBounds[2] - pageBounds[0];',
660
+ '',
661
+ ' // Create background rectangle',
662
+ ' var backgroundRect = page.rectangles.add();',
663
+ ' backgroundRect.geometricBounds = [0, 0, pageHeight, pageWidth];',
664
+ '',
665
+ ' // Set background color',
666
+ ` if ("${backgroundColor}" !== "White") {`,
667
+ ' try {',
668
+ ` var bgColor = doc.colors.itemByName("${escapeJsxString(backgroundColor)}");`,
669
+ ' if (bgColor.isValid) {',
670
+ ' backgroundRect.fillColor = bgColor;',
671
+ ' } else {',
672
+ ' backgroundRect.fillColor = doc.colors.itemByName("White");',
673
+ ' }',
674
+ ' } catch (colorError) {',
675
+ ' backgroundRect.fillColor = doc.colors.itemByName("White");',
676
+ ' }',
677
+ ' } else {',
678
+ ' backgroundRect.fillColor = doc.colors.itemByName("White");',
679
+ ' }',
680
+ '',
681
+ ' // Set opacity',
682
+ ` backgroundRect.transparencySettings.blendingSettings.opacity = ${opacity};`,
683
+ '',
684
+ ' // Send to back to ensure it\'s behind all content',
685
+ ' backgroundRect.sendToBack();',
686
+ '',
687
+ ` "Page background set successfully with color: ${backgroundColor} and opacity: ${opacity}%";`,
688
+ ' } catch (error) {',
689
+ ' "Error setting page background: " + error.message;',
690
+ ' }',
691
+ ' }',
692
+ '}'
693
+ ].join('\n');
694
+
695
+ const result = await ScriptExecutor.executeInDesignScript(script);
696
+ return formatResponse(result, "Set Page Background");
697
+ }
698
+ }