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,431 @@
1
+ /**
2
+ * Text frame handlers
3
+ */
4
+ import { ScriptExecutor } from '../core/scriptExecutor.js';
5
+ import { formatResponse, formatErrorResponse, escapeJsxString } from '../utils/stringUtils.js';
6
+ import { sessionManager } from '../core/sessionManager.js';
7
+
8
+ export class TextHandlers {
9
+ /**
10
+ * Create a text frame on the active page
11
+ */
12
+ static async createTextFrame(args) {
13
+ const {
14
+ content,
15
+ x,
16
+ y,
17
+ width,
18
+ height,
19
+ fontSize = 12,
20
+ fontName = 'Arial\\tRegular',
21
+ textColor = 'Black',
22
+ alignment = 'LEFT',
23
+ paragraphStyle = null,
24
+ characterStyle = null
25
+ } = args;
26
+
27
+ const numericInputs = { x, y, width, height, fontSize };
28
+ for (const [field, value] of Object.entries(numericInputs)) {
29
+ if (value !== undefined && (typeof value !== 'number' || !Number.isFinite(value))) {
30
+ return formatErrorResponse(`${field} must be a valid number`, "Create Text Frame");
31
+ }
32
+ }
33
+
34
+ // Use session manager for positioning if coordinates not provided
35
+ const positioning = sessionManager.getCalculatedPositioning({ x, y, width, height });
36
+
37
+ // Validate positioning before creating content
38
+ const validation = sessionManager.validatePositioning(positioning.x, positioning.y, positioning.width, positioning.height);
39
+ if (!validation.valid) {
40
+ // Apply suggested corrections if available, otherwise use safe defaults
41
+ if (validation.suggested) {
42
+ Object.assign(positioning, validation.suggested);
43
+ } else {
44
+ // Fallback to safe positioning
45
+ const safePos = sessionManager.getCalculatedPositioning({});
46
+ Object.assign(positioning, safePos);
47
+ }
48
+ }
49
+
50
+ const escapedContent = escapeJsxString(content);
51
+ const escapedFontName = escapeJsxString(fontName);
52
+ const escapedParagraphStyle = paragraphStyle ? escapeJsxString(paragraphStyle) : '';
53
+ const escapedCharacterStyle = characterStyle ? escapeJsxString(characterStyle) : '';
54
+ const sanitizedTextColor = typeof textColor === 'string' && textColor.trim() !== '' ? textColor : 'Black';
55
+ const escapedTextColor = escapeJsxString(sanitizedTextColor);
56
+ const alignmentOptions = new Set(['LEFT', 'CENTER', 'RIGHT', 'JUSTIFY']);
57
+ const normalizedAlignment = typeof alignment === 'string' ? alignment.trim().toUpperCase() : 'LEFT';
58
+ const safeAlignment = alignmentOptions.has(normalizedAlignment) ? normalizedAlignment : 'LEFT';
59
+ const escapedAlignment = escapeJsxString(safeAlignment);
60
+
61
+ const script = [
62
+ 'if (app.documents.length === 0) {',
63
+ ' "No document open";',
64
+ '} else {',
65
+ ' var doc = app.activeDocument;',
66
+ ' var page = app.activeWindow.activePage || doc.pages[0];',
67
+ ' var textFrame;',
68
+ ' var styleMessage = "";',
69
+ '',
70
+ ' try {',
71
+ ' // Create text frame',
72
+ ` textFrame = page.textFrames.add();`,
73
+ ` textFrame.geometricBounds = [${positioning.y}, ${positioning.x}, ${positioning.y + positioning.height}, ${positioning.x + positioning.width}];`,
74
+ ` textFrame.contents = "${escapedContent}";`,
75
+ '',
76
+ ' // Apply paragraph style if specified',
77
+ ` if ("${escapedParagraphStyle}" !== "") {`,
78
+ ' try {',
79
+ ` var paragraphStyle = doc.paragraphStyles.itemByName("${escapedParagraphStyle}");`,
80
+ ' if (paragraphStyle.isValid) {',
81
+ ' textFrame.paragraphs[0].appliedParagraphStyle = paragraphStyle;',
82
+ ` styleMessage += "Paragraph style '${escapedParagraphStyle}' applied. ";`,
83
+ ' } else {',
84
+ ` styleMessage += "Paragraph style '${escapedParagraphStyle}' not found. ";`,
85
+ ' }',
86
+ ' } catch (styleError) {',
87
+ ` styleMessage += "Error applying paragraph style: " + styleError.message + ". ";`,
88
+ ' }',
89
+ ' }',
90
+ '',
91
+ ' // Apply character style if specified',
92
+ ` if ("${escapedCharacterStyle}" !== "") {`,
93
+ ' try {',
94
+ ` var characterStyle = doc.characterStyles.itemByName("${escapedCharacterStyle}");`,
95
+ ' if (characterStyle.isValid) {',
96
+ ' textFrame.texts[0].appliedCharacterStyle = characterStyle;',
97
+ ` styleMessage += "Character style '${escapedCharacterStyle}' applied. ";`,
98
+ ' } else {',
99
+ ` styleMessage += "Character style '${escapedCharacterStyle}' not found. ";`,
100
+ ' }',
101
+ ' } catch (styleError) {',
102
+ ` styleMessage += "Error applying character style: " + styleError.message + ". ";`,
103
+ ' }',
104
+ ' }',
105
+ '',
106
+ ' // Apply direct formatting only if no styles were applied',
107
+ ` if ("${escapedParagraphStyle}" === "" && "${escapedCharacterStyle}" === "") {`,
108
+ ' // Apply text formatting',
109
+ ' try {',
110
+ ` textFrame.texts[0].appliedFont = app.fonts.itemByName("${escapedFontName}");`,
111
+ ' } catch (fontError) {',
112
+ ' // Keep the document default font when the requested font is unavailable.',
113
+ ' }',
114
+ ` textFrame.texts[0].pointSize = ${fontSize};`,
115
+ '',
116
+ ' // Apply color',
117
+ ` if ("${escapedTextColor}" !== "Black") {`,
118
+ ' try {',
119
+ ` textFrame.texts[0].fillColor = app.colors.itemByName("${escapedTextColor}");`,
120
+ ' } catch (colorError) {',
121
+ ' // Use default color if specified color not found',
122
+ ' }',
123
+ ' }',
124
+ '',
125
+ ' // Apply alignment',
126
+ ` if ("${escapedAlignment}" === "CENTER") {`,
127
+ ' textFrame.texts[0].justification = Justification.CENTER_ALIGN;',
128
+ ` } else if ("${escapedAlignment}" === "RIGHT") {`,
129
+ ' textFrame.texts[0].justification = Justification.RIGHT_ALIGN;',
130
+ ` } else if ("${escapedAlignment}" === "JUSTIFY") {`,
131
+ ' textFrame.texts[0].justification = Justification.FULLY_JUSTIFIED;',
132
+ ' } else {',
133
+ ' textFrame.texts[0].justification = Justification.LEFT_ALIGN;',
134
+ ' }',
135
+ ' }',
136
+ '',
137
+ ' "Text frame created successfully. " + styleMessage;',
138
+ ' } catch (error) {',
139
+ ' "Error creating text frame: " + error.message;',
140
+ ' }',
141
+ '}'
142
+ ].join('\n');
143
+
144
+ const result = await ScriptExecutor.executeInDesignScript(script);
145
+
146
+ // Check if the operation was successful
147
+ const isSuccess = result.includes("Text frame created successfully");
148
+
149
+ if (isSuccess) {
150
+ // Store the created item info in session
151
+ sessionManager.setLastCreatedItem({
152
+ type: 'textFrame',
153
+ content: content,
154
+ position: positioning,
155
+ fontSize: fontSize,
156
+ fontName: fontName,
157
+ paragraphStyle: paragraphStyle,
158
+ characterStyle: characterStyle,
159
+ textColor: sanitizedTextColor,
160
+ alignment: safeAlignment
161
+ });
162
+ }
163
+
164
+ return isSuccess ?
165
+ formatResponse(result, "Create Text Frame") :
166
+ formatErrorResponse(result, "Create Text Frame");
167
+ }
168
+
169
+ /**
170
+ * Edit an existing text frame
171
+ */
172
+ static async editTextFrame(args) {
173
+ const {
174
+ frameIndex,
175
+ content,
176
+ fontSize,
177
+ fontName,
178
+ textColor,
179
+ alignment
180
+ } = args;
181
+
182
+ const escapedContent = content ? escapeJsxString(content) : '';
183
+ const escapedFontName = fontName ? escapeJsxString(fontName) : '';
184
+ const sanitizedTextColor = typeof textColor === 'string' ? textColor.trim() : '';
185
+ const escapedTextColor = sanitizedTextColor ? escapeJsxString(sanitizedTextColor) : '';
186
+ const normalizedAlignment = typeof alignment === 'string' ? alignment.trim().toUpperCase() : '';
187
+ const safeAlignment = ['LEFT', 'CENTER', 'RIGHT', 'JUSTIFY'].includes(normalizedAlignment) ? normalizedAlignment : '';
188
+ const escapedAlignment = safeAlignment ? escapeJsxString(safeAlignment) : '';
189
+
190
+ const script = [
191
+ 'if (app.documents.length === 0) {',
192
+ ' "No document open";',
193
+ '} else {',
194
+ ' var doc = app.activeDocument;',
195
+ ' var page = app.activeWindow.activePage || doc.pages[0];',
196
+ '',
197
+ ' try {',
198
+ ` if (${frameIndex} >= page.textFrames.length) {`,
199
+ ' "Text frame index out of range";',
200
+ ' } else {',
201
+ ` var textFrame = page.textFrames[${frameIndex}];`,
202
+ '',
203
+ ` if ("${escapedContent}" !== "") {`,
204
+ ` textFrame.contents = "${escapedContent}";`,
205
+ ' }',
206
+ '',
207
+ ` if (${fontSize}) {`,
208
+ ` textFrame.texts[0].pointSize = ${fontSize};`,
209
+ ' }',
210
+ '',
211
+ ` if ("${escapedFontName}" !== "") {`,
212
+ ` textFrame.texts[0].appliedFont = app.fonts.itemByName("${escapedFontName}");`,
213
+ ' }',
214
+ '',
215
+ ` if ("${escapedTextColor}" !== "") {`,
216
+ ' try {',
217
+ ` textFrame.texts[0].fillColor = app.colors.itemByName("${escapedTextColor}");`,
218
+ ' } catch (colorError) {',
219
+ ' // Use default color if specified color not found',
220
+ ' }',
221
+ ' }',
222
+ '',
223
+ ` if ("${escapedAlignment}" !== "") {`,
224
+ ` if ("${escapedAlignment}" === "CENTER") {`,
225
+ ' textFrame.texts[0].justification = Justification.CENTER_ALIGN;',
226
+ ` } else if ("${escapedAlignment}" === "RIGHT") {`,
227
+ ' textFrame.texts[0].justification = Justification.RIGHT_ALIGN;',
228
+ ` } else if ("${escapedAlignment}" === "JUSTIFY") {`,
229
+ ' textFrame.texts[0].justification = Justification.FULLY_JUSTIFIED;',
230
+ ' } else {',
231
+ ' textFrame.texts[0].justification = Justification.LEFT_ALIGN;',
232
+ ' }',
233
+ ' }',
234
+ '',
235
+ ' "Text frame updated successfully";',
236
+ ' }',
237
+ ' } catch (error) {',
238
+ ' "Error updating text frame: " + error.message;',
239
+ ' }',
240
+ '}'
241
+ ].join('\n');
242
+
243
+ const result = await ScriptExecutor.executeInDesignScript(script);
244
+ return formatResponse(result, "Edit Text Frame");
245
+ }
246
+
247
+ /**
248
+ * Create a table on the active page
249
+ */
250
+ static async createTable(args) {
251
+ const {
252
+ rows = 3,
253
+ columns = 3,
254
+ x,
255
+ y,
256
+ width,
257
+ height,
258
+ headerRows = 1,
259
+ headerColumns = 0
260
+ } = args;
261
+
262
+ // Use session manager for positioning if coordinates not provided
263
+ const positioning = sessionManager.getCalculatedPositioning({ x, y, width, height });
264
+
265
+ const script = [
266
+ 'if (app.documents.length === 0) {',
267
+ ' "No document open";',
268
+ '} else {',
269
+ ' var doc = app.activeDocument;',
270
+ ' var page = app.activeWindow.activePage || doc.pages[0];',
271
+ ' var table;',
272
+ '',
273
+ ' try {',
274
+ ' // Create text frame for table',
275
+ ' var textFrame = page.textFrames.add();',
276
+ ` textFrame.geometricBounds = [${positioning.y}, ${positioning.x}, ${positioning.y + positioning.height}, ${positioning.x + positioning.width}];`,
277
+ '',
278
+ ' // Create table',
279
+ ` table = textFrame.insertionPoints[0].tables.add({bodyRowCount: ${rows}, bodyColumnCount: ${columns}});`,
280
+ '',
281
+ ' // Set header rows and columns',
282
+ ` try { table.headerRowCount = ${headerRows}; } catch (headerRowError) {}`,
283
+ ` try { table.headerColumnCount = ${headerColumns}; } catch (headerColumnError) {}`,
284
+ '',
285
+ ' "Table created successfully";',
286
+ ' } catch (error) {',
287
+ ' "Error creating table: " + error.message;',
288
+ ' }',
289
+ '}'
290
+ ].join('\n');
291
+
292
+ const result = await ScriptExecutor.executeInDesignScript(script);
293
+
294
+ // Store the created item info in session
295
+ sessionManager.setLastCreatedItem({
296
+ type: 'table',
297
+ rows: rows,
298
+ columns: columns,
299
+ position: positioning,
300
+ headerRows: headerRows,
301
+ headerColumns: headerColumns
302
+ });
303
+
304
+ return formatResponse(result, "Create Table");
305
+ }
306
+
307
+ /**
308
+ * Populate a table with data
309
+ */
310
+ static async populateTable(args) {
311
+ const {
312
+ tableIndex = 0,
313
+ data,
314
+ startRow = 0,
315
+ startColumn = 0
316
+ } = args;
317
+
318
+ if (!data || !Array.isArray(data)) {
319
+ return formatResponse("Invalid data provided. Expected array of arrays.", "Populate Table");
320
+ }
321
+
322
+ const escapedData = data.map(row =>
323
+ row.map(cell => escapeJsxString(cell.toString()))
324
+ );
325
+
326
+ const script = [
327
+ 'if (app.documents.length === 0) {',
328
+ ' "No document open";',
329
+ '} else {',
330
+ ' var doc = app.activeDocument;',
331
+ ' var page = app.activeWindow.activePage || doc.pages[0];',
332
+ '',
333
+ ' try {',
334
+ ' // Find table in text frames',
335
+ ' var table = null;',
336
+ ' var tableCount = 0;',
337
+ '',
338
+ ' for (var i = 0; i < page.textFrames.length; i++) {',
339
+ ' var textFrame = page.textFrames[i];',
340
+ ' if (textFrame.tables.length > 0) {',
341
+ ` if (tableCount === ${tableIndex}) {`,
342
+ ' table = textFrame.tables[0];',
343
+ ' break;',
344
+ ' }',
345
+ ' tableCount++;',
346
+ ' }',
347
+ ' }',
348
+ '',
349
+ ' if (!table) {',
350
+ ` "Table index ${tableIndex} not found";`,
351
+ ' } else {',
352
+ ' // Populate table with data',
353
+ ` var data = ${JSON.stringify(escapedData)};`,
354
+ ` var startRow = ${startRow};`,
355
+ ` var startColumn = ${startColumn};`,
356
+ '',
357
+ ' for (var row = 0; row < data.length; row++) {',
358
+ ' for (var col = 0; col < data[row].length; col++) {',
359
+ ' var cellRow = startRow + row;',
360
+ ' var cellCol = startColumn + col;',
361
+ '',
362
+ ' if (cellRow < table.rows.length && cellCol < table.columns.length) {',
363
+ ' var cell = table.cells.item(cellRow, cellCol);',
364
+ ' cell.contents = data[row][col];',
365
+ ' }',
366
+ ' }',
367
+ ' }',
368
+ '',
369
+ ' "Table populated successfully";',
370
+ ' }',
371
+ ' } catch (error) {',
372
+ ' "Error populating table: " + error.message;',
373
+ ' }',
374
+ '}'
375
+ ].join('\n');
376
+
377
+ const result = await ScriptExecutor.executeInDesignScript(script);
378
+ return formatResponse(result, "Populate Table");
379
+ }
380
+
381
+ /**
382
+ * Find and replace text in the document
383
+ */
384
+ static async findReplaceText(args) {
385
+ const {
386
+ findText,
387
+ replaceText,
388
+ caseSensitive = false,
389
+ wholeWord = false
390
+ } = args;
391
+
392
+ const escapedFindText = escapeJsxString(findText);
393
+ const escapedReplaceText = escapeJsxString(replaceText);
394
+
395
+ const script = [
396
+ 'if (app.documents.length === 0) {',
397
+ ' "No document open";',
398
+ '} else {',
399
+ ' var doc = app.activeDocument;',
400
+ ' var findTextPreferences = app.findTextPreferences;',
401
+ ' var changeTextPreferences = app.changeTextPreferences;',
402
+ '',
403
+ ' try {',
404
+ ' // Clear previous preferences',
405
+ ' app.findTextPreferences = NothingEnum.NOTHING;',
406
+ ' app.changeTextPreferences = NothingEnum.NOTHING;',
407
+ '',
408
+ ' // Set find preferences',
409
+ ` app.findTextPreferences.findWhat = "${escapedFindText}";`,
410
+ ` try { app.findTextPreferences.caseSensitive = ${caseSensitive}; } catch (caseError) {}`,
411
+ ` try { app.findTextPreferences.wholeWord = ${wholeWord}; } catch (wordError) {}`,
412
+ '',
413
+ ' // Set change preferences',
414
+ ` app.changeTextPreferences.changeTo = "${escapedReplaceText}";`,
415
+ '',
416
+ ' // Perform find and replace',
417
+ ' var foundItems = doc.changeText();',
418
+ ' app.findTextPreferences = NothingEnum.NOTHING;',
419
+ ' app.changeTextPreferences = NothingEnum.NOTHING;',
420
+ '',
421
+ ' "Find and replace completed. Items changed: " + foundItems.length;',
422
+ ' } catch (error) {',
423
+ ' "Error during find and replace: " + error.message;',
424
+ ' }',
425
+ '}'
426
+ ].join('\n');
427
+
428
+ const result = await ScriptExecutor.executeInDesignScript(script);
429
+ return formatResponse(result, "Find Replace Text");
430
+ }
431
+ }
@@ -0,0 +1,83 @@
1
+ /**
2
+ * Utility handlers for InDesign MCP Server
3
+ */
4
+ import { ScriptExecutor } from '../core/scriptExecutor.js';
5
+ import { formatResponse } from '../utils/stringUtils.js';
6
+ import { sessionManager } from '../core/sessionManager.js';
7
+
8
+ export class UtilityHandlers {
9
+ /**
10
+ * Execute custom InDesign code
11
+ */
12
+ static async executeInDesignCode(args) {
13
+ const { code } = args;
14
+ // Insert code as-is to avoid breaking syntax; execution wrapper handles errors
15
+ const script = [
16
+ 'try {',
17
+ ' app.scriptPreferences.userInteractionLevel = UserInteractionLevels.NEVER_INTERACT;',
18
+ code || '"No code provided";',
19
+ '} catch (error) {',
20
+ ' "Error executing code: " + error.message;',
21
+ '}'
22
+ ].join('\n');
23
+
24
+ const result = await ScriptExecutor.executeInDesignScript(script);
25
+ return formatResponse(result, "Execute InDesign Code");
26
+ }
27
+
28
+ /**
29
+ * View document information and current state
30
+ */
31
+ static async viewDocument() {
32
+ const script = [
33
+ 'if (app.documents.length === 0) {',
34
+ ' "No document open";',
35
+ '} else {',
36
+ ' var doc = app.activeDocument;',
37
+ ' var activePage = null;',
38
+ ' try { if (app.layoutWindows.length > 0) activePage = app.layoutWindows[0].activePage; } catch (activePageError) {}',
39
+ ' if (!activePage && doc.pages.length > 0) activePage = doc.pages[0];',
40
+ ' var info = "=== DOCUMENT VIEW ===\\n";',
41
+ ' info += "Document: " + doc.name + "\\n";',
42
+ ' info += "Pages: " + doc.pages.length + "\\n";',
43
+ ' info += "Active Page: " + (activePage ? activePage.name : "None") + "\\n";',
44
+ ' try { info += "Zoom: " + app.activeWindow.zoomPercentage + "%\\n"; } catch (zoomError) { info += "Zoom: Not available\\n"; }',
45
+ ' try { info += "View Mode: " + app.activeWindow.displaySettings.overprintPreview + "\\n"; } catch (viewError) { info += "View Mode: Not available\\n"; }',
46
+ '',
47
+ ' // Page information',
48
+ ' if (doc.pages.length > 0) {',
49
+ ' var page = doc.pages[0];',
50
+ ' info += "\\n=== FIRST PAGE INFO ===\\n";',
51
+ ' info += "Page Name: " + page.name + "\\n";',
52
+ ' info += "Page Width: " + (page.bounds[3] - page.bounds[1]) + "\\n";',
53
+ ' info += "Page Height: " + (page.bounds[2] - page.bounds[0]) + "\\n";',
54
+ ' info += "Text Frames: " + page.textFrames.length + "\\n";',
55
+ ' info += "Rectangles: " + page.rectangles.length + "\\n";',
56
+ ' info += "Ovals: " + page.ovals.length + "\\n";',
57
+ ' info += "Polygons: " + page.polygons.length + "\\n";',
58
+ ' }',
59
+ '',
60
+ ' info;',
61
+ '}'
62
+ ].join('\n');
63
+
64
+ const result = await ScriptExecutor.executeInDesignScript(script);
65
+ return formatResponse(result, "View Document");
66
+ }
67
+
68
+ /**
69
+ * Get session information
70
+ */
71
+ static async getSessionInfo() {
72
+ const sessionInfo = sessionManager.getSessionSummary();
73
+ return formatResponse(JSON.stringify(sessionInfo, null, 2), "Get Session Info");
74
+ }
75
+
76
+ /**
77
+ * Clear session data
78
+ */
79
+ static async clearSession() {
80
+ sessionManager.clearSession();
81
+ return formatResponse("Session data cleared successfully", "Clear Session");
82
+ }
83
+ }
@@ -0,0 +1,17 @@
1
+ /**
2
+ * Main entry point for InDesign MCP Server
3
+ */
4
+ import { InDesignMCPServer } from './core/InDesignMCPServer.js';
5
+
6
+ async function main() {
7
+ try {
8
+ const server = new InDesignMCPServer();
9
+ await server.run();
10
+ } catch (error) {
11
+ // Log to stderr instead of stdout to avoid interfering with MCP protocol
12
+ console.error('Failed to start server:', error);
13
+ process.exit(1);
14
+ }
15
+ }
16
+
17
+ main();
@@ -0,0 +1,106 @@
1
+ /**
2
+ * Tool definitions index for InDesign MCP Server
3
+ * Central import and export of all tool definitions
4
+ */
5
+
6
+ import { pageToolDefinitions as rawPageToolDefinitions } from './toolDefinitionsPage.js';
7
+ import { contentToolDefinitions as rawContentToolDefinitions } from './toolDefinitionsContent.js';
8
+ import { documentToolDefinitions as rawDocumentToolDefinitions } from './toolDefinitionsDocument.js';
9
+ import { exportToolDefinitions as rawExportToolDefinitions } from './toolDefinitionsExport.js';
10
+ import { presentationToolDefinitions as rawPresentationToolDefinitions } from './toolDefinitionsPresentation.js';
11
+ import { bookToolDefinitions as rawBookToolDefinitions } from './toolDefinitionsBook.js';
12
+ import { utilityToolDefinitions as rawUtilityToolDefinitions } from './toolDefinitionsUtility.js';
13
+ import { pageItemGroupToolDefinitions as rawPageItemGroupToolDefinitions } from './toolDefinitionsPageItemGroup.js';
14
+ import { masterSpreadToolDefinitions as rawMasterSpreadToolDefinitions } from './toolDefinitionsMasterSpread.js';
15
+ import { spreadToolDefinitions as rawSpreadToolDefinitions } from './toolDefinitionsSpread.js';
16
+ import { layerToolDefinitions as rawLayerToolDefinitions } from './toolDefinitionsLayer.js';
17
+
18
+ // Normalize schemas to comply with JSON Schema 2020-12 strictness
19
+ function normalizeSchema(schema) {
20
+ if (!schema || typeof schema !== 'object') return schema;
21
+
22
+ let normalized = { ...schema };
23
+
24
+ // Recurse common combinators
25
+ for (const key of ['anyOf', 'oneOf', 'allOf']) {
26
+ if (Array.isArray(normalized[key])) {
27
+ normalized[key] = normalized[key].map((s) => normalizeSchema(s));
28
+ }
29
+ }
30
+
31
+ if (normalized.type === 'object') {
32
+ if (!Object.prototype.hasOwnProperty.call(normalized, 'additionalProperties')) {
33
+ normalized.additionalProperties = false;
34
+ }
35
+ const requiredFromChildren = [];
36
+ if (normalized.properties && typeof normalized.properties === 'object') {
37
+ const newProps = {};
38
+ for (const [k, v] of Object.entries(normalized.properties)) {
39
+ // Capture non-standard property-level required: true
40
+ if (v && typeof v === 'object' && Object.prototype.hasOwnProperty.call(v, 'required')) {
41
+ if (v.required === true) {
42
+ requiredFromChildren.push(k);
43
+ }
44
+ // Remove invalid usage regardless of value type
45
+ const { required, ...rest } = v;
46
+ newProps[k] = normalizeSchema(rest);
47
+ } else {
48
+ newProps[k] = normalizeSchema(v);
49
+ }
50
+ }
51
+ normalized.properties = newProps;
52
+ }
53
+ if (requiredFromChildren.length) {
54
+ const existing = Array.isArray(normalized.required) ? normalized.required.slice() : [];
55
+ for (const r of requiredFromChildren) {
56
+ if (!existing.includes(r)) existing.push(r);
57
+ }
58
+ normalized.required = existing;
59
+ }
60
+ }
61
+
62
+ if (normalized.type === 'array' && normalized.items) {
63
+ normalized.items = normalizeSchema(normalized.items);
64
+ }
65
+
66
+ return normalized;
67
+ }
68
+
69
+ function normalizeToolDefinition(tool) {
70
+ if (!tool || typeof tool !== 'object') return tool;
71
+ const t = { ...tool };
72
+ if (t.inputSchema) {
73
+ t.inputSchema = normalizeSchema(t.inputSchema);
74
+ }
75
+ return t;
76
+ }
77
+
78
+ // Produce normalized exports used by the server
79
+ export const pageToolDefinitions = rawPageToolDefinitions.map(normalizeToolDefinition);
80
+ export const contentToolDefinitions = rawContentToolDefinitions.map(normalizeToolDefinition);
81
+ export const documentToolDefinitions = rawDocumentToolDefinitions.map(normalizeToolDefinition);
82
+ export const exportToolDefinitions = rawExportToolDefinitions.map(normalizeToolDefinition);
83
+ export const presentationToolDefinitions = rawPresentationToolDefinitions.map(normalizeToolDefinition);
84
+ export const bookToolDefinitions = rawBookToolDefinitions.map(normalizeToolDefinition);
85
+ export const utilityToolDefinitions = rawUtilityToolDefinitions.map(normalizeToolDefinition);
86
+ export const pageItemGroupToolDefinitions = rawPageItemGroupToolDefinitions.map(normalizeToolDefinition);
87
+ export const masterSpreadToolDefinitions = rawMasterSpreadToolDefinitions.map(normalizeToolDefinition);
88
+ export const spreadToolDefinitions = rawSpreadToolDefinitions.map(normalizeToolDefinition);
89
+ export const layerToolDefinitions = rawLayerToolDefinitions.map(normalizeToolDefinition);
90
+
91
+ // Combine all tool definitions into a single array
92
+ export const allToolDefinitions = [
93
+ ...pageToolDefinitions,
94
+ ...contentToolDefinitions,
95
+ ...documentToolDefinitions,
96
+ ...exportToolDefinitions,
97
+ ...presentationToolDefinitions,
98
+ ...bookToolDefinitions,
99
+ ...utilityToolDefinitions,
100
+ ...pageItemGroupToolDefinitions,
101
+ ...masterSpreadToolDefinitions,
102
+ ...spreadToolDefinitions,
103
+ ...layerToolDefinitions,
104
+ ];
105
+
106
+ // Named exports already declared above