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,320 @@
1
+ from __future__ import annotations
2
+
3
+ import argparse
4
+ import json
5
+ import sys
6
+ from pathlib import Path
7
+ from typing import Any
8
+
9
+ from . import __version__
10
+ from .core.artifacts import parse_timestamp, verify_artifact
11
+ from .core.catalog import Catalog
12
+ from .core.catalog import plugin_tool_entries
13
+ from .core.envelope import failure, now_ms, success
14
+ from .core.errors import CliError
15
+ from .core.health import health
16
+ from .core.mcp_backend import McpBackend
17
+ from .core.node_setup import setup_node_dependencies
18
+ from .core.plugins.backend import PluginBackend
19
+ from .core.plugins.discovery import discover_plugins
20
+ from .core.plugins.install import install_plugin, list_plugins, remove_plugin
21
+ from .core.plugins.validate import doctor_plugin, validate_plugin_path
22
+ from .core.router import Router, load_args
23
+ from .core.runtime import install_skill, resolve_server_root
24
+ from .core.scripts import run_script, run_stdin_script
25
+ from .core.session import SessionStore
26
+
27
+
28
+ SERVER_ROOT = resolve_server_root()
29
+ REPO_ROOT = SERVER_ROOT
30
+
31
+
32
+ def emit(payload: dict[str, Any]) -> int:
33
+ print(json.dumps(payload, ensure_ascii=True, indent=2))
34
+ return int(payload.get("exit_code", 0))
35
+
36
+
37
+ def version_payload() -> dict[str, Any]:
38
+ return success(
39
+ command="version",
40
+ data={
41
+ "name": "indesign-cli",
42
+ "version": __version__,
43
+ "aliases": ["cli-anything-indesign"],
44
+ },
45
+ duration_ms=0,
46
+ )
47
+
48
+
49
+ def build_parser() -> argparse.ArgumentParser:
50
+ parser = argparse.ArgumentParser(prog="indesign-cli")
51
+ parser.add_argument("--version", action="store_true")
52
+ parser.add_argument("--json", action="store_true")
53
+ parser.add_argument("--pretty", action="store_true")
54
+ subparsers = parser.add_subparsers(dest="group")
55
+
56
+ tool_parser = subparsers.add_parser("tool")
57
+ tool_sub = tool_parser.add_subparsers(dest="tool_command")
58
+ tool_sub.add_parser("domains")
59
+ list_parser = tool_sub.add_parser("list")
60
+ list_parser.add_argument("--domain")
61
+ list_parser.add_argument("--source")
62
+ list_parser.add_argument("--callable-only", action="store_true")
63
+ search_parser = tool_sub.add_parser("search")
64
+ search_parser.add_argument("--domain")
65
+ search_parser.add_argument("--source")
66
+ search_parser.add_argument("--query", required=True)
67
+ schema_parser = tool_sub.add_parser("schema")
68
+ schema_parser.add_argument("tool_id")
69
+ call_parser = tool_sub.add_parser("call")
70
+ call_parser.add_argument("tool_id")
71
+ call_parser.add_argument("--args", required=True)
72
+ call_parser.add_argument("--timeout", type=int, help="MCP/script backend timeout in seconds")
73
+
74
+ script_parser = subparsers.add_parser("script")
75
+ script_sub = script_parser.add_subparsers(dest="script_command")
76
+ run_parser = script_sub.add_parser("run")
77
+ run_parser.add_argument("file", nargs="?")
78
+ run_parser.add_argument("--stdin", action="store_true")
79
+ run_parser.add_argument("--timeout", type=int, default=300, help="Script backend timeout in seconds")
80
+
81
+ export_parser = subparsers.add_parser("export")
82
+ export_sub = export_parser.add_subparsers(dest="export_command")
83
+ verify_parser = export_sub.add_parser("verify")
84
+ verify_parser.add_argument("path")
85
+ verify_parser.add_argument("--created-after")
86
+
87
+ session_parser = subparsers.add_parser("session")
88
+ session_sub = session_parser.add_subparsers(dest="session_command")
89
+ show_parser = session_sub.add_parser("show")
90
+ show_parser.add_argument("--verbose", action="store_true")
91
+ session_sub.add_parser("clear")
92
+
93
+ server_parser = subparsers.add_parser("server")
94
+ server_sub = server_parser.add_subparsers(dest="server_command")
95
+ health_parser = server_sub.add_parser("health")
96
+ health_parser.add_argument("--deep", action="store_true")
97
+ server_sub.add_parser("setup")
98
+
99
+ skill_parser = subparsers.add_parser("skill")
100
+ skill_sub = skill_parser.add_subparsers(dest="skill_command")
101
+ install_parser = skill_sub.add_parser("install")
102
+ install_parser.add_argument("--target", default=".")
103
+
104
+ plugin_parser = subparsers.add_parser("plugin")
105
+ plugin_sub = plugin_parser.add_subparsers(dest="plugin_command")
106
+ plugin_sub.add_parser("list")
107
+ plugin_install = plugin_sub.add_parser("install")
108
+ plugin_install.add_argument("path")
109
+ plugin_remove = plugin_sub.add_parser("remove")
110
+ plugin_remove.add_argument("id")
111
+ plugin_validate = plugin_sub.add_parser("validate")
112
+ plugin_validate.add_argument("path")
113
+ plugin_doctor = plugin_sub.add_parser("doctor")
114
+ plugin_doctor.add_argument("id")
115
+ plugin_doctor.add_argument("--deep", action="store_true")
116
+ return parser
117
+
118
+
119
+ def build_catalog_with_backends() -> tuple[Catalog, list[str]]:
120
+ base = Catalog(repo_root=REPO_ROOT)
121
+ warnings: list[str] = []
122
+ advanced_tools: list[dict[str, Any]] = []
123
+ classic_tools: list[dict[str, Any]] = []
124
+ plugin_tools: list[dict[str, Any]] = []
125
+ plugin_domain_summaries: dict[str, str] = {}
126
+ plugin_records = {}
127
+ for source, entry, sink in (
128
+ ("advanced", "src/advanced/index.js", advanced_tools),
129
+ ("classic", "src/index.js", classic_tools),
130
+ ):
131
+ try:
132
+ sink.extend(McpBackend(repo_root=REPO_ROOT, entry=entry).list_tools())
133
+ except CliError as exc:
134
+ warnings.append(f"{source} backend unavailable: {exc.code}")
135
+ try:
136
+ discovered, plugin_warnings = discover_plugins(Path.cwd(), host_version=__version__)
137
+ warnings.extend(plugin_warnings)
138
+ except CliError as exc:
139
+ discovered = []
140
+ warnings.append(f"plugin discovery unavailable: {exc.code}")
141
+ for record in discovered:
142
+ try:
143
+ backend = PluginBackend(record)
144
+ backend.handshake({"name": "indesign-cli", "version": __version__, "protocol": record.manifest["protocol"]})
145
+ plugin_tools.extend(plugin_tool_entries(record, backend.list_tools()))
146
+ plugin_domain_summaries[record.domain] = str(record.manifest.get("description") or f"{record.id} plugin tools")
147
+ plugin_records[record.id] = record
148
+ except CliError as exc:
149
+ warnings.append(f"plugin {record.id} unavailable: {exc.code}")
150
+ return (
151
+ base.with_exposed_tools(
152
+ advanced_tools=advanced_tools,
153
+ classic_tools=classic_tools,
154
+ plugin_tools=plugin_tools,
155
+ plugin_domain_summaries=plugin_domain_summaries,
156
+ plugin_records=plugin_records,
157
+ ),
158
+ warnings,
159
+ )
160
+
161
+
162
+ def emit_check(command: str, data: dict[str, Any], *, tool_id: str | None = None) -> int:
163
+ payload = success(command=command, data=data, duration_ms=0, tool_id=tool_id)
164
+ if data.get("ok") is False:
165
+ payload["ok"] = False
166
+ payload["exit_code"] = 1
167
+ payload["tool_success"] = False
168
+ return emit(payload)
169
+
170
+
171
+ def run(argv: list[str] | None = None) -> int:
172
+ parser = build_parser()
173
+ args = parser.parse_args(argv)
174
+ if args.version:
175
+ return emit(version_payload())
176
+ if args.group == "tool":
177
+ catalog, warnings = build_catalog_with_backends()
178
+ if args.tool_command == "domains" or args.tool_command is None:
179
+ return emit(success(command="tool domains", data=catalog.domains(), duration_ms=0, warnings=warnings))
180
+ if args.tool_command == "list":
181
+ if not args.domain and not args.source:
182
+ return emit(success(command="tool list", data=catalog.domains(), duration_ms=0, warnings=warnings))
183
+ data = catalog.list_tools(
184
+ domain=args.domain,
185
+ source=args.source,
186
+ callable_only=args.callable_only,
187
+ )
188
+ return emit(success(command="tool list", data=data, duration_ms=0, warnings=warnings))
189
+ if args.tool_command == "search":
190
+ data = catalog.list_tools(domain=args.domain, source=args.source, query=args.query)
191
+ return emit(success(command="tool search", data=data, duration_ms=0, warnings=warnings))
192
+ router = Router(catalog=catalog, repo_root=REPO_ROOT, backend_timeout_seconds=getattr(args, "timeout", None))
193
+ if args.tool_command == "schema":
194
+ data = router.schema(args.tool_id)
195
+ return emit(success(command="tool schema", data=data, duration_ms=0, tool_id=args.tool_id, warnings=warnings))
196
+ if args.tool_command == "call":
197
+ call_args = load_args(args.args)
198
+ tool = router._find(args.tool_id)
199
+ store = SessionStore(Path.cwd())
200
+ try:
201
+ data = router.call(args.tool_id, call_args)
202
+ except CliError:
203
+ store.record_call(
204
+ tool_id=args.tool_id,
205
+ domain=tool["domain"],
206
+ source=tool["source"],
207
+ ok=False,
208
+ duration_ms=0,
209
+ plugin=tool.get("plugin"),
210
+ )
211
+ raise
212
+ store.record_call(
213
+ tool_id=args.tool_id,
214
+ domain=tool["domain"],
215
+ source=tool["source"],
216
+ ok=True,
217
+ duration_ms=0,
218
+ plugin=tool.get("plugin"),
219
+ artifacts=data.get("artifacts") if isinstance(data, dict) else None,
220
+ )
221
+ return emit(
222
+ success(
223
+ command="tool call",
224
+ data=data,
225
+ duration_ms=0,
226
+ tool_id=args.tool_id,
227
+ domain=tool["domain"],
228
+ source=tool["source"],
229
+ warnings=warnings,
230
+ )
231
+ )
232
+ if args.group == "plugin":
233
+ if args.plugin_command == "list" or args.plugin_command is None:
234
+ data = list_plugins(cwd=Path.cwd(), host_version=__version__)
235
+ return emit(success(command="plugin list", data=data, duration_ms=0, tool_id="plugin.list", domain="plugin", source="cli", warnings=data.get("warnings", [])))
236
+ if args.plugin_command == "install":
237
+ data = install_plugin(args.path, cwd=Path.cwd(), host_version=__version__)
238
+ return emit(success(command="plugin install", data=data, duration_ms=0, tool_id="plugin.install", domain="plugin", source="cli"))
239
+ if args.plugin_command == "remove":
240
+ data = remove_plugin(args.id, cwd=Path.cwd())
241
+ return emit(success(command="plugin remove", data=data, duration_ms=0, tool_id="plugin.remove", domain="plugin", source="cli"))
242
+ if args.plugin_command == "validate":
243
+ data = validate_plugin_path(args.path, host_version=__version__)
244
+ return emit_check("plugin validate", data, tool_id="plugin.validate")
245
+ if args.plugin_command == "doctor":
246
+ data = doctor_plugin(args.id, cwd=Path.cwd(), host_version=__version__, deep=bool(args.deep))
247
+ return emit_check("plugin doctor", data, tool_id="plugin.doctor")
248
+ if args.group == "script" and args.script_command == "run":
249
+ catalog, warnings = build_catalog_with_backends()
250
+ router = Router(catalog=catalog, repo_root=REPO_ROOT, backend_timeout_seconds=args.timeout)
251
+ store = SessionStore(Path.cwd())
252
+ try:
253
+ if args.stdin:
254
+ data = run_stdin_script(router, Path.cwd())
255
+ elif args.file:
256
+ data = run_script(router, Path(args.file))
257
+ else:
258
+ raise CliError("script run requires a file path or --stdin", code="SCRIPT_INPUT_REQUIRED")
259
+ except Exception:
260
+ store.record_call(tool_id="script.run", domain="script", source="script", ok=False, duration_ms=0)
261
+ raise
262
+ store.record_call(tool_id="script.run", domain="script", source="script", ok=True, duration_ms=0)
263
+ return emit(success(command="script run", data=data, duration_ms=0, tool_id="script.run", domain="script", source="script", warnings=warnings))
264
+ if args.group == "export" and args.export_command == "verify":
265
+ try:
266
+ created_after = parse_timestamp(args.created_after) if args.created_after else None
267
+ except ValueError as exc:
268
+ raise CliError("created-after must be an ISO timestamp", code="BAD_TIMESTAMP") from exc
269
+ data = verify_artifact(Path(args.path), created_after=created_after, cwd=Path.cwd())
270
+ SessionStore(Path.cwd()).record_call(tool_id="export.verify", domain="export", source="cli", ok=True, duration_ms=0)
271
+ return emit(success(command="export verify", data=data, duration_ms=0, tool_id="export.verify", domain="export", source="cli"))
272
+ if args.group == "session":
273
+ store = SessionStore(Path.cwd())
274
+ if args.session_command == "show" or args.session_command is None:
275
+ data = store.read(compact=not getattr(args, "verbose", False))
276
+ return emit(success(command="session show", data=data, duration_ms=0, tool_id="session.show"))
277
+ if args.session_command == "clear":
278
+ store.clear()
279
+ return emit(success(command="session clear", data={"cleared": True}, duration_ms=0, tool_id="session.clear"))
280
+ if args.group == "server" and (args.server_command == "health" or args.server_command is None):
281
+ data = health(REPO_ROOT, deep=getattr(args, "deep", False))
282
+ return emit(success(command="server health", data=data, duration_ms=0, tool_id="server.health"))
283
+ if args.group == "server" and args.server_command == "setup":
284
+ data = setup_node_dependencies(REPO_ROOT)
285
+ return emit(success(command="server setup", data=data, duration_ms=0, tool_id="server.setup", domain="server", source="cli"))
286
+ if args.group == "skill" and args.skill_command == "install":
287
+ data = install_skill(Path(args.target))
288
+ return emit(success(command="skill install", data=data, duration_ms=0, tool_id="skill.install", domain="skill", source="cli"))
289
+ raise CliError(
290
+ "Command is required",
291
+ code="COMMAND_REQUIRED",
292
+ details={"groups": ["tool", "script", "export", "session", "server", "skill", "plugin"]},
293
+ hint="先用 tool domains 查看工具域,或用 tool search --query <关键词> 查找工具。",
294
+ )
295
+
296
+
297
+ def safe_command(argv: list[str] | None) -> str:
298
+ parts = list(argv if argv is not None else sys.argv[1:])
299
+ while parts and parts[0] in {"--json", "--pretty"}:
300
+ parts.pop(0)
301
+ if not parts:
302
+ return "cli"
303
+ if parts[0] == "tool" and len(parts) > 1:
304
+ return f"tool {parts[1]}"
305
+ if parts[0] in {"script", "export", "session", "skill", "plugin"} and len(parts) > 1:
306
+ return f"{parts[0]} {parts[1]}"
307
+ return parts[0]
308
+
309
+
310
+ def main(argv: list[str] | None = None) -> int:
311
+ start = now_ms()
312
+ try:
313
+ return run(argv)
314
+ except CliError as exc:
315
+ duration_ms = now_ms() - start
316
+ return emit(failure(command=safe_command(argv), error=exc, duration_ms=duration_ms))
317
+ except Exception as exc:
318
+ duration_ms = now_ms() - start
319
+ error = CliError("Unexpected CLI error", code="UNEXPECTED_ERROR", details={"type": exc.__class__.__name__})
320
+ return emit(failure(command=safe_command(argv), error=error, duration_ms=duration_ms))
@@ -0,0 +1,111 @@
1
+ #!/usr/bin/env node
2
+ import fs from 'node:fs';
3
+ import path from 'node:path';
4
+ import { env, stdin, stdout } from 'node:process';
5
+ import { fileURLToPath, pathToFileURL } from 'node:url';
6
+
7
+ const __dirname = path.dirname(fileURLToPath(import.meta.url));
8
+
9
+ function resolveServerRoot() {
10
+ const candidates = [
11
+ env.INDESIGN_CLI_SERVER_ROOT,
12
+ path.resolve(__dirname, '../../../../'),
13
+ path.resolve(__dirname, '../server'),
14
+ ].filter(Boolean);
15
+
16
+ for (const candidate of candidates) {
17
+ if (
18
+ fs.existsSync(path.join(candidate, 'src', 'handlers', 'bookHandlers.js')) &&
19
+ fs.existsSync(path.join(candidate, 'src', 'handlers', 'presentationHandlers.js'))
20
+ ) {
21
+ return candidate;
22
+ }
23
+ }
24
+
25
+ throw new Error('Unable to resolve InDesign CLI server root');
26
+ }
27
+
28
+ const serverRoot = resolveServerRoot();
29
+ const { BookHandlers } = await import(pathToFileURL(path.join(serverRoot, 'src', 'handlers', 'bookHandlers.js')).href);
30
+ const { PresentationHandlers } = await import(
31
+ pathToFileURL(path.join(serverRoot, 'src', 'handlers', 'presentationHandlers.js')).href
32
+ );
33
+
34
+ const HANDLERS = {
35
+ book: BookHandlers,
36
+ presentation: PresentationHandlers,
37
+ };
38
+
39
+ function readStdin() {
40
+ return new Promise((resolve, reject) => {
41
+ let data = '';
42
+ stdin.setEncoding('utf8');
43
+ stdin.on('data', chunk => {
44
+ data += chunk;
45
+ });
46
+ stdin.on('end', () => resolve(data));
47
+ stdin.on('error', reject);
48
+ });
49
+ }
50
+
51
+ function snakeToCamel(value) {
52
+ return String(value || '').replace(/_([a-z0-9])/g, (_match, letter) => letter.toUpperCase());
53
+ }
54
+
55
+ function camelToSnake(value) {
56
+ return String(value || '')
57
+ .replace(/(.)([A-Z][a-z]+)/g, '$1_$2')
58
+ .replace(/([a-z0-9])([A-Z])/g, '$1_$2')
59
+ .toLowerCase();
60
+ }
61
+
62
+ function resolveMethodName(handlerClass, name) {
63
+ const normalized = String(name || '');
64
+ for (const candidate of Object.getOwnPropertyNames(handlerClass)) {
65
+ if (typeof handlerClass[candidate] === 'function' && camelToSnake(candidate) === normalized) {
66
+ return candidate;
67
+ }
68
+ }
69
+ return snakeToCamel(normalized);
70
+ }
71
+
72
+ function failure(code, message) {
73
+ return {
74
+ ok: false,
75
+ error: { code, message },
76
+ };
77
+ }
78
+
79
+ async function main() {
80
+ const input = await readStdin();
81
+ const request = JSON.parse(input || '{}');
82
+ const domain = request.domain;
83
+ const name = request.name;
84
+ const args = request.args || {};
85
+
86
+ const handlerClass = HANDLERS[domain];
87
+ if (!handlerClass) {
88
+ return failure('HIDDEN_HANDLER_DOMAIN_NOT_FOUND', `Unknown hidden handler domain: ${domain}`);
89
+ }
90
+
91
+ const methodName = resolveMethodName(handlerClass, name);
92
+ const method = handlerClass[methodName];
93
+ if (typeof method !== 'function') {
94
+ return failure('HIDDEN_HANDLER_METHOD_NOT_FOUND', `Unknown hidden handler method: ${domain}.${name}`);
95
+ }
96
+
97
+ if (request.resolveOnly) {
98
+ return { ok: true, methodName };
99
+ }
100
+
101
+ const result = await method.call(handlerClass, args);
102
+ return { ok: true, result };
103
+ }
104
+
105
+ main()
106
+ .then(payload => {
107
+ stdout.write(JSON.stringify(payload));
108
+ })
109
+ .catch(error => {
110
+ stdout.write(JSON.stringify(failure('HIDDEN_HANDLER_EXCEPTION', error?.message || String(error))));
111
+ });
@@ -0,0 +1,168 @@
1
+ {
2
+ "name": "indesign-cli",
3
+ "version": "0.2.0",
4
+ "lockfileVersion": 3,
5
+ "requires": true,
6
+ "packages": {
7
+ "": {
8
+ "name": "indesign-cli",
9
+ "version": "0.2.0",
10
+ "license": "MIT",
11
+ "dependencies": {
12
+ "@modelcontextprotocol/sdk": "^0.5.0",
13
+ "winax": "^3.6.2"
14
+ },
15
+ "engines": {
16
+ "node": ">=18.0.0"
17
+ }
18
+ },
19
+ "node_modules/@modelcontextprotocol/sdk": {
20
+ "version": "0.5.0",
21
+ "resolved": "https://registry.npmjs.org/@modelcontextprotocol/sdk/-/sdk-0.5.0.tgz",
22
+ "integrity": "sha512-RXgulUX6ewvxjAG0kOpLMEdXXWkzWgaoCGaA2CwNW7cQCIphjpJhjpHSiaPdVCnisjRF/0Cm9KWHUuIoeiAblQ==",
23
+ "license": "MIT",
24
+ "dependencies": {
25
+ "content-type": "^1.0.5",
26
+ "raw-body": "^3.0.0",
27
+ "zod": "^3.23.8"
28
+ }
29
+ },
30
+ "node_modules/bytes": {
31
+ "version": "3.1.2",
32
+ "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.1.2.tgz",
33
+ "integrity": "sha512-/Nf7TyzTx6S3yRJObOAV7956r8cr2+Oj8AC5dt8wSP3BQAoeX58NoHyCU8P8zGkNXStjTSi6fzO6F0pBdcYbEg==",
34
+ "license": "MIT",
35
+ "engines": {
36
+ "node": ">= 0.8"
37
+ }
38
+ },
39
+ "node_modules/content-type": {
40
+ "version": "1.0.5",
41
+ "resolved": "https://registry.npmjs.org/content-type/-/content-type-1.0.5.tgz",
42
+ "integrity": "sha512-nTjqfcBFEipKdXCv4YDQWCfmcLZKm81ldF0pAopTvyrFGVbcR6P/VAAd5G7N+0tTr8QqiU0tFadD6FK4NtJwOA==",
43
+ "license": "MIT",
44
+ "engines": {
45
+ "node": ">= 0.6"
46
+ }
47
+ },
48
+ "node_modules/depd": {
49
+ "version": "2.0.0",
50
+ "resolved": "https://registry.npmjs.org/depd/-/depd-2.0.0.tgz",
51
+ "integrity": "sha512-g7nH6P6dyDioJogAAGprGpCtVImJhpPk/roCzdb3fIh61/s/nPsfR6onyMwkCAR/OlC3yBC0lESvUoQEAssIrw==",
52
+ "license": "MIT",
53
+ "engines": {
54
+ "node": ">= 0.8"
55
+ }
56
+ },
57
+ "node_modules/http-errors": {
58
+ "version": "2.0.0",
59
+ "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-2.0.0.tgz",
60
+ "integrity": "sha512-FtwrG/euBzaEjYeRqOgly7G0qviiXoJWnvEH2Z1plBdXgbyjv34pHTSb9zoeHMyDy33+DWy5Wt9Wo+TURtOYSQ==",
61
+ "license": "MIT",
62
+ "dependencies": {
63
+ "depd": "2.0.0",
64
+ "inherits": "2.0.4",
65
+ "setprototypeof": "1.2.0",
66
+ "statuses": "2.0.1",
67
+ "toidentifier": "1.0.1"
68
+ },
69
+ "engines": {
70
+ "node": ">= 0.8"
71
+ }
72
+ },
73
+ "node_modules/iconv-lite": {
74
+ "version": "0.6.3",
75
+ "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.6.3.tgz",
76
+ "integrity": "sha512-4fCk79wshMdzMp2rH06qWrJE4iolqLhCUH+OiuIgU++RB0+94NlDL81atO7GX55uUKueo0txHNtvEyI6D7WdMw==",
77
+ "license": "MIT",
78
+ "dependencies": {
79
+ "safer-buffer": ">= 2.1.2 < 3.0.0"
80
+ },
81
+ "engines": {
82
+ "node": ">=0.10.0"
83
+ }
84
+ },
85
+ "node_modules/inherits": {
86
+ "version": "2.0.4",
87
+ "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz",
88
+ "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==",
89
+ "license": "ISC"
90
+ },
91
+ "node_modules/raw-body": {
92
+ "version": "3.0.0",
93
+ "resolved": "https://registry.npmjs.org/raw-body/-/raw-body-3.0.0.tgz",
94
+ "integrity": "sha512-RmkhL8CAyCRPXCE28MMH0z2PNWQBNk2Q09ZdxM9IOOXwxwZbN+qbWaatPkdkWIKL2ZVDImrN/pK5HTRz2PcS4g==",
95
+ "license": "MIT",
96
+ "dependencies": {
97
+ "bytes": "3.1.2",
98
+ "http-errors": "2.0.0",
99
+ "iconv-lite": "0.6.3",
100
+ "unpipe": "1.0.0"
101
+ },
102
+ "engines": {
103
+ "node": ">= 0.8"
104
+ }
105
+ },
106
+ "node_modules/safer-buffer": {
107
+ "version": "2.1.2",
108
+ "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz",
109
+ "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==",
110
+ "license": "MIT"
111
+ },
112
+ "node_modules/setprototypeof": {
113
+ "version": "1.2.0",
114
+ "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.2.0.tgz",
115
+ "integrity": "sha512-E5LDX7Wrp85Kil5bhZv46j8jOeboKq5JMmYM3gVGdGH8xFpPWXUMsNrlODCrkoxMEeNi/XZIwuRvY4XNwYMJpw==",
116
+ "license": "ISC"
117
+ },
118
+ "node_modules/statuses": {
119
+ "version": "2.0.1",
120
+ "resolved": "https://registry.npmjs.org/statuses/-/statuses-2.0.1.tgz",
121
+ "integrity": "sha512-RwNA9Z/7PrK06rYLIzFMlaF+l73iwpzsqRIFgbMLbTcLD6cOao82TaWefPXQvB2fOC4AjuYSEndS7N/mTCbkdQ==",
122
+ "license": "MIT",
123
+ "engines": {
124
+ "node": ">= 0.8"
125
+ }
126
+ },
127
+ "node_modules/toidentifier": {
128
+ "version": "1.0.1",
129
+ "resolved": "https://registry.npmjs.org/toidentifier/-/toidentifier-1.0.1.tgz",
130
+ "integrity": "sha512-o5sSPKEkg/DIQNmH43V0/uerLrpzVedkUh8tGNvaeXpfpuwjKenlSox/2O/BTlZUtEe+JG7s5YhEz608PlAHRA==",
131
+ "license": "MIT",
132
+ "engines": {
133
+ "node": ">=0.6"
134
+ }
135
+ },
136
+ "node_modules/unpipe": {
137
+ "version": "1.0.0",
138
+ "resolved": "https://registry.npmjs.org/unpipe/-/unpipe-1.0.0.tgz",
139
+ "integrity": "sha512-pjy2bYhSsufwWlKwPc+l3cN7+wuJlK6uz0YdJEOlQDbl6jo/YlPi4mb8agUkVC8BF7V8NuzeyPNqRksA3hztKQ==",
140
+ "license": "MIT",
141
+ "engines": {
142
+ "node": ">= 0.8"
143
+ }
144
+ },
145
+ "node_modules/winax": {
146
+ "version": "3.6.2",
147
+ "resolved": "https://registry.npmjs.org/winax/-/winax-3.6.2.tgz",
148
+ "integrity": "sha512-KvNO9lBBW//F4k4kE3QzKWHyGchMswrwSC2TD/rS4BYLaypECPCRXQIyjmQHVteK7cBEqqdF288brwnig/67Ow==",
149
+ "hasInstallScript": true,
150
+ "license": "MIT",
151
+ "bin": {
152
+ "nodewscript": "NodeWScript.js"
153
+ },
154
+ "engines": {
155
+ "node": ">= 10.0.0"
156
+ }
157
+ },
158
+ "node_modules/zod": {
159
+ "version": "3.25.76",
160
+ "resolved": "https://registry.npmjs.org/zod/-/zod-3.25.76.tgz",
161
+ "integrity": "sha512-gzUt/qt81nXsFGKIFcC3YnfEAx5NkunCfnDlvuBSSFS02bcXu4Lmea0AFIUwbLWxWPx3d9p8S5QoaujKcNQxcQ==",
162
+ "license": "MIT",
163
+ "funding": {
164
+ "url": "https://github.com/sponsors/colinhacks"
165
+ }
166
+ }
167
+ }
168
+ }
@@ -0,0 +1,45 @@
1
+ {
2
+ "name": "indesign-cli",
3
+ "version": "0.2.0",
4
+ "description": "Agent-native CLI and MCP runtime for Adobe InDesign automation",
5
+ "main": "src/index.js",
6
+ "type": "module",
7
+ "scripts": {
8
+ "start": "node src/index.js",
9
+ "dev": "node --inspect src/index.js",
10
+ "build": "echo 'No build step required for Node.js'",
11
+ "test": "echo 'No tests specified'"
12
+ },
13
+ "keywords": [
14
+ "mcp",
15
+ "model-context-protocol",
16
+ "indesign",
17
+ "adobe",
18
+ "automation",
19
+ "publishing",
20
+ "desktop-publishing",
21
+ "claude",
22
+ "ai",
23
+ "llm",
24
+ "design-automation",
25
+ "document-creation",
26
+ "layout-automation"
27
+ ],
28
+ "author": "Sa",
29
+ "license": "MIT",
30
+ "dependencies": {
31
+ "@modelcontextprotocol/sdk": "^0.5.0",
32
+ "winax": "^3.6.2"
33
+ },
34
+ "engines": {
35
+ "node": ">=18.0.0"
36
+ },
37
+ "repository": {
38
+ "type": "git",
39
+ "url": "git+https://github.com/zhanglongxiao111/indesign-cli.git"
40
+ },
41
+ "bugs": {
42
+ "url": "https://github.com/zhanglongxiao111/indesign-cli/issues"
43
+ },
44
+ "homepage": "https://github.com/zhanglongxiao111/indesign-cli#readme"
45
+ }