@synthetic-ai/premiere-mcp 2.3.1 → 2.3.4

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.
package/i18n/node.cjs ADDED
@@ -0,0 +1,124 @@
1
+ /* synthetic-idiomas · core/node.cjs
2
+ *
3
+ * Lado Node (servers MCP): decide el idioma al arrancar y carga los diccionarios del producto.
4
+ *
5
+ * Orden para elegir el idioma (el primero que dé un idioma soportado gana):
6
+ * 1. Variable de entorno del producto (ej. PS_MCP_LANG), si el producto define una.
7
+ * 2. SYNTHETIC_LANG (vale para todos los productos).
8
+ * 3. settings.json del panel del producto: <USER_DATA>/<carpeta del panel>/settings.json
9
+ * 4. settings.json compartido de Synthetic: <USER_DATA>/com.synthetic/settings.json
10
+ * 5. Inglés.
11
+ *
12
+ * <USER_DATA> es la misma carpeta que devuelve CEP con SystemPath.USER_DATA:
13
+ * Windows: %APPDATA% · macOS: ~/Library/Application Support · Linux (dev): ~/.config
14
+ *
15
+ * El idioma se lee UNA vez al arrancar: las descripciones de las tools se registran al inicio
16
+ * de la sesión MCP y los clientes no las vuelven a pedir. Cambiar el idioma en el panel se
17
+ * aplica al reiniciar el server (o la app cliente).
18
+ */
19
+ 'use strict';
20
+ var fs = require('fs');
21
+ var path = require('path');
22
+ var os = require('os');
23
+ var core = require('./i18n-core.cjs');
24
+
25
+ var SHARED_FOLDER = 'com.synthetic';
26
+
27
+ function userDataDir(env, platform) {
28
+ env = env || process.env;
29
+ platform = platform || process.platform;
30
+ if (platform === 'win32') return env.APPDATA || path.join(os.homedir(), 'AppData', 'Roaming');
31
+ if (platform === 'darwin') return path.join(os.homedir(), 'Library', 'Application Support');
32
+ return env.XDG_CONFIG_HOME || path.join(os.homedir(), '.config');
33
+ }
34
+
35
+ function settingsPath(folder, env, platform) {
36
+ return path.join(userDataDir(env, platform), folder, 'settings.json');
37
+ }
38
+
39
+ function readJson(file) {
40
+ try { return JSON.parse(fs.readFileSync(file, 'utf8').replace(/^/, '')); } catch (e) { return null; }
41
+ }
42
+
43
+ /**
44
+ * @param {object} o
45
+ * envVar: variable propia del producto (ej. 'PS_MCP_LANG')
46
+ * settingsFolder: carpeta del panel dentro de USER_DATA (ej. 'com.synthetic.photoshop-mcp.bridge')
47
+ * @returns {{ language: string, source: string }}
48
+ */
49
+ function resolveLanguage(o) {
50
+ o = o || {};
51
+ var env = o.env || process.env;
52
+ var tries = [];
53
+ if (o.envVar) tries.push([env[o.envVar], 'env:' + o.envVar]);
54
+ tries.push([env.SYNTHETIC_LANG, 'env:SYNTHETIC_LANG']);
55
+ if (o.settingsFolder) {
56
+ var p = settingsPath(o.settingsFolder, env, o.platform);
57
+ var s = readJson(p);
58
+ tries.push([s && s.language, p]);
59
+ }
60
+ var shared = settingsPath(SHARED_FOLDER, env, o.platform);
61
+ var sh = readJson(shared);
62
+ tries.push([sh && sh.language, shared]);
63
+ for (var i = 0; i < tries.length; i++) {
64
+ var lang = core.normalizeLanguage(tries[i][0]);
65
+ if (lang) return { language: lang, source: tries[i][1] };
66
+ }
67
+ return { language: core.SOURCE, source: 'default' };
68
+ }
69
+
70
+ // Lee <dir>/<idioma>.json y <dir>/hashes/<idioma>.json para todos los idiomas soportados.
71
+ function loadLocales(dir) {
72
+ var locales = {}, hashes = {};
73
+ core.CODES.forEach(function (code) {
74
+ var d = readJson(path.join(dir, code + '.json'));
75
+ if (d) locales[code] = d;
76
+ var h = readJson(path.join(dir, 'hashes', code + '.json'));
77
+ if (h) hashes[code] = h;
78
+ });
79
+ return { locales: locales, hashes: hashes };
80
+ }
81
+
82
+ /**
83
+ * Atajo para un server MCP:
84
+ * const i18n = createServerI18n({ localesDir, envVar: 'PS_MCP_LANG', settingsFolder: '...' });
85
+ * i18n.t('msg.license.missing') // mensajes
86
+ * i18n.localizeTools(tools) // respuesta de tools/list
87
+ */
88
+ function createServerI18n(o) {
89
+ var picked = resolveLanguage(o);
90
+ var data = loadLocales(o.localesDir);
91
+ var i18n = core.createI18n({ locales: data.locales, hashes: data.hashes, language: picked.language });
92
+ i18n.languageSource = picked.source;
93
+ // Idioma pedido (puede diferir de `language` si ese idioma todavía no tiene diccionario).
94
+ i18n.requestedLanguage = picked.language;
95
+ return i18n;
96
+ }
97
+
98
+ // Para servers hechos con McpServer del SDK oficial: envuelve la respuesta de tools/list.
99
+ // Llamar DESPUÉS de registrar todas las tools y ANTES de server.connect().
100
+ function patchMcpServerToolsList(mcpServer, i18n) {
101
+ if (!i18n || i18n.language === core.SOURCE) return false;
102
+ var inner = mcpServer && (mcpServer.server || mcpServer);
103
+ var handlers = inner && inner._requestHandlers;
104
+ if (!handlers || typeof handlers.get !== 'function') return false;
105
+ var original = handlers.get('tools/list');
106
+ if (typeof original !== 'function') return false;
107
+ handlers.set('tools/list', async function (request, extra) {
108
+ var result = await original(request, extra);
109
+ if (result && Array.isArray(result.tools)) return Object.assign({}, result, { tools: i18n.localizeTools(result.tools) });
110
+ return result;
111
+ });
112
+ return true;
113
+ }
114
+
115
+ module.exports = {
116
+ SHARED_FOLDER: SHARED_FOLDER,
117
+ userDataDir: userDataDir,
118
+ settingsPath: settingsPath,
119
+ resolveLanguage: resolveLanguage,
120
+ loadLocales: loadLocales,
121
+ createServerI18n: createServerI18n,
122
+ patchMcpServerToolsList: patchMcpServerToolsList,
123
+ core: core
124
+ };
package/package.json CHANGED
@@ -1,66 +1,68 @@
1
- {
2
- "name": "@synthetic-ai/premiere-mcp",
3
- "version": "2.3.1",
4
- "description": "MCP server for controlling Adobe Premiere Pro via CEP/ExtendScript \u00e2\u20ac\u201d 437 tools for AI-driven video editing",
5
- "main": "dist/index.js",
6
- "type": "module",
7
- "bin": {
8
- "premiere-mcp": "dist/index.js"
9
- },
10
- "files": [
11
- "dist/**/*.js",
12
- "dist/**/*.d.ts",
13
- "cep-plugin",
14
- "scripts",
15
- "README.md",
16
- "LICENSE",
17
- "CHANGELOG.md"
18
- ],
19
- "scripts": {
20
- "build": "tsc",
21
- "dev": "tsc --watch",
22
- "start": "node dist/index.js",
23
- "start:http": "node dist/http-server.js",
24
- "test": "vitest run",
25
- "test:watch": "vitest",
26
- "test:coverage": "vitest run --coverage",
27
- "install-cep": "bash scripts/install-cep.sh"
28
- },
29
- "repository": {
30
- "type": "git",
31
- "url": "git+https://github.com/matiasEltrece/premiere-pro-mcp.git"
32
- },
33
- "homepage": "https://synthetic.com.ar",
34
- "bugs": {
35
- "url": "https://synthetic.com.ar"
36
- },
37
- "author": "Synthetic",
38
- "keywords": [
39
- "mcp",
40
- "model-context-protocol",
41
- "adobe",
42
- "premiere-pro",
43
- "video-editing",
44
- "ai",
45
- "extendscript",
46
- "cep",
47
- "claude",
48
- "windsurf",
49
- "cursor",
50
- "automation"
51
- ],
52
- "license": "MIT",
53
- "engines": {
54
- "node": ">=18.0.0"
55
- },
56
- "dependencies": {
57
- "@modelcontextprotocol/sdk": "^1.12.1",
58
- "zod": "^3.23.0"
59
- },
60
- "devDependencies": {
61
- "@types/node": "^22.10.0",
62
- "javascript-obfuscator": "^4.2.2",
63
- "typescript": "^5.7.0",
64
- "vitest": "^4.0.18"
65
- }
1
+ {
2
+ "name": "@synthetic-ai/premiere-mcp",
3
+ "version": "2.3.4",
4
+ "description": "MCP server for controlling Adobe Premiere Pro via CEP/ExtendScript \u00e2\u20ac\u201d 437 tools for AI-driven video editing",
5
+ "main": "dist/index.js",
6
+ "type": "module",
7
+ "bin": {
8
+ "premiere-mcp": "dist/index.js"
9
+ },
10
+ "files": [
11
+ "dist/**/*.js",
12
+ "dist/**/*.d.ts",
13
+ "i18n",
14
+ "cep-plugin",
15
+ "scripts",
16
+ "README.md",
17
+ "LICENSE",
18
+ "CHANGELOG.md"
19
+ ],
20
+ "scripts": {
21
+ "build": "tsc",
22
+ "dev": "tsc --watch",
23
+ "start": "node dist/index.js",
24
+ "start:http": "node dist/http-server.js",
25
+ "test": "vitest run",
26
+ "test:watch": "vitest",
27
+ "test:coverage": "vitest run --coverage",
28
+ "install-cep": "bash scripts/install-cep.sh",
29
+ "sync-i18n": "node scripts/sync-i18n.mjs"
30
+ },
31
+ "repository": {
32
+ "type": "git",
33
+ "url": "git+https://github.com/matiasEltrece/premiere-pro-mcp.git"
34
+ },
35
+ "homepage": "https://synthetic.com.ar",
36
+ "bugs": {
37
+ "url": "https://synthetic.com.ar"
38
+ },
39
+ "author": "Synthetic",
40
+ "keywords": [
41
+ "mcp",
42
+ "model-context-protocol",
43
+ "adobe",
44
+ "premiere-pro",
45
+ "video-editing",
46
+ "ai",
47
+ "extendscript",
48
+ "cep",
49
+ "claude",
50
+ "windsurf",
51
+ "cursor",
52
+ "automation"
53
+ ],
54
+ "license": "MIT",
55
+ "engines": {
56
+ "node": ">=18.0.0"
57
+ },
58
+ "dependencies": {
59
+ "@modelcontextprotocol/sdk": "^1.12.1",
60
+ "zod": "^3.23.0"
61
+ },
62
+ "devDependencies": {
63
+ "@types/node": "^22.10.0",
64
+ "javascript-obfuscator": "^4.2.2",
65
+ "typescript": "^5.7.0",
66
+ "vitest": "^4.0.18"
67
+ }
66
68
  }
@@ -5,6 +5,7 @@
5
5
  * release/
6
6
  * server/index.mjs bundled + minified (+ obfuscated) MCP server
7
7
  * server/package.json minimal ESM marker
8
+ * i18n/ translations + i18n runtime (server loads ../i18n at runtime)
8
9
  * MCPBridgeCEP.zxp signed CEP plugin (obfuscated main.js, verbatim premiere.jsx, no .debug)
9
10
  * install/ install scripts
10
11
  * README.md LICENSE
@@ -36,6 +37,22 @@ if (existsSync(REL)) rmSync(REL, { recursive: true, force: true });
36
37
  mkdirSync(join(REL, "server"), { recursive: true });
37
38
  console.log("✓ Cleaned release/");
38
39
 
40
+ // ─── 1b. Translations (vendored by scripts/sync-i18n.mjs) ────────────────────
41
+ // src/i18n.ts loads them at runtime from <module dir>/../i18n, which for the
42
+ // bundle below (release/server/index.mjs) is release/i18n. Staged before the
43
+ // bundle is validated so the server starts exactly as it will ship. The CEP
44
+ // panel's own copy (cep-plugin/i18n-*.{cjs,js}, at the extension ROOT — not
45
+ // cep-plugin/i18n/, see sync-i18n.mjs for why) rides along with the stage in
46
+ // step 4.
47
+ for (const p of [join(ROOT, "i18n", "node.cjs"), join(ROOT, "i18n", "locales", "en.json"), join(ROOT, "cep-plugin", "i18n-locales.js")]) {
48
+ if (!existsSync(p)) {
49
+ console.error(`✗ Missing ${p} — run: node scripts/sync-i18n.mjs`);
50
+ process.exit(1);
51
+ }
52
+ }
53
+ copyDirSync(join(ROOT, "i18n"), join(REL, "i18n"));
54
+ console.log("✓ Copied i18n/ → release/i18n");
55
+
39
56
  // ─── 2. Compile TS, then bundle with esbuild (single minified ESM file) ──────
40
57
  console.log("⚙ tsc build...");
41
58
  execSync("npm run build", { cwd: ROOT, stdio: "pipe" });
@@ -195,8 +212,7 @@ for (const f of ["main.js"]) {
195
212
  console.log("✓ Shipped cep/premiere.jsx verbatim (no obfuscation — see comment above)");
196
213
 
197
214
  // ─── 5. Sign the staged plugin into a .zxp ───────────────────────────────────
198
- const ZXP = process.env.ZXP_SIGN_CMD ||
199
- "C:\\Users\\Artear\\Documents\\CEP-Resources\\ZXPSignCMD\\4.1.3\\x64\\ZXPSignCmd.exe";
215
+ const ZXP = process.env.ZXP_SIGN_CMD || "ZXPSignCmd";
200
216
  const certPath = process.env.ZXP_CERT_PATH || join(ROOT, ".cert", "self-signed.p12");
201
217
  const certPass = process.env.ZXP_CERT_PASSWORD || "synthetic";
202
218
  const zxpOut = join(REL, "MCPBridgeCEP.zxp");
@@ -0,0 +1,117 @@
1
+ /**
2
+ * Synthetic Premiere Pro MCP — sync translations from synthetic-idiomas
3
+ *
4
+ * The language dictionaries and the shared i18n runtime live in the central
5
+ * synthetic-idiomas repo. This script vendors the pieces each part needs:
6
+ *
7
+ * i18n/ MCP server (loaded at runtime from dist/ → ../i18n)
8
+ * i18n-core.cjs node.cjs locales/<lang>.json locales/hashes/<lang>.json
9
+ * cep-plugin/ bridge panel — files at the extension ROOT, not a
10
+ * i18n-core.cjs subfolder: the in-panel hot-updater writes each
11
+ * i18n-panel.cjs manifest file via a flat path.join(extDir,
12
+ * i18n-locales.js f.name) with no mkdir step, so a panel already
13
+ * live making its first jump to this version
14
+ * would ENOENT on an "i18n/" subfolder that
15
+ * doesn't exist yet. Same bug found and fixed in
16
+ * Photoshop MCP's and AE MCP's panels
17
+ * (29/30-sep-2026). chat-plugin has no such
18
+ * updater (delivered only via a fresh .zxp
19
+ * install), so it's the one place a real i18n/
20
+ * subfolder is still safe.
21
+ * chat-plugin/i18n/ AI Chat panel ┐ i18n-core.cjs panel.cjs
22
+ * ┘ locales.js
23
+ *
24
+ * The copies are committed to this repo (CI, npm publish and the .zxp build
25
+ * don't have synthetic-idiomas next to them). Re-run after translations change:
26
+ *
27
+ * node scripts/sync-i18n.mjs (or: npm run sync-i18n)
28
+ *
29
+ * Source: $SYNTHETIC_IDIOMAS_DIR, else ../synthetic-idiomas next to this repo.
30
+ * In synthetic-idiomas, run `node tools/i18n.mjs build premiere-mcp` first so
31
+ * locales/en.json and dist/locales.js are current.
32
+ */
33
+ import { existsSync, mkdirSync, copyFileSync, rmSync, readdirSync, statSync, readFileSync } from "fs";
34
+ import { join, dirname, resolve } from "path";
35
+ import { fileURLToPath } from "url";
36
+ import { execSync } from "child_process";
37
+
38
+ const __dirname = dirname(fileURLToPath(import.meta.url));
39
+ const ROOT = join(__dirname, "..");
40
+ const PRODUCT = "premiere-mcp";
41
+ const SRC = resolve(process.env.SYNTHETIC_IDIOMAS_DIR || join(ROOT, "..", "synthetic-idiomas"));
42
+
43
+ const need = {
44
+ core: join(SRC, "core", "i18n-core.cjs"),
45
+ node: join(SRC, "core", "node.cjs"),
46
+ panel: join(SRC, "core", "panel.cjs"),
47
+ locales: join(SRC, PRODUCT, "locales"),
48
+ bundle: join(SRC, PRODUCT, "dist", "locales.js"),
49
+ };
50
+ const missing = Object.values(need).filter((p) => !existsSync(p));
51
+ if (missing.length) {
52
+ console.error(`✗ synthetic-idiomas not found or incomplete at ${SRC}`);
53
+ for (const p of missing) console.error(` missing: ${p}`);
54
+ console.error(" Clone it next to this repo, or set SYNTHETIC_IDIOMAS_DIR to its path.");
55
+ console.error(` If only the locale files are missing, run there: node tools/i18n.mjs build ${PRODUCT}`);
56
+ process.exit(1);
57
+ }
58
+ if (!existsSync(join(need.locales, "en.json"))) {
59
+ console.error(`✗ ${join(need.locales, "en.json")} not found — run: node tools/i18n.mjs build ${PRODUCT}`);
60
+ process.exit(1);
61
+ }
62
+
63
+ // Each target is rebuilt from scratch so removed languages/keys don't linger.
64
+ function resetDir(dir) {
65
+ rmSync(dir, { recursive: true, force: true });
66
+ mkdirSync(dir, { recursive: true });
67
+ }
68
+
69
+ function copyDirSync(src, dest) {
70
+ mkdirSync(dest, { recursive: true });
71
+ for (const entry of readdirSync(src)) {
72
+ const s = join(src, entry), d = join(dest, entry);
73
+ if (statSync(s).isDirectory()) copyDirSync(s, d);
74
+ else if (entry.endsWith(".json")) copyFileSync(s, d);
75
+ }
76
+ }
77
+
78
+ // ─── Server ──────────────────────────────────────────────────────────────────
79
+ const serverDir = join(ROOT, "i18n");
80
+ resetDir(serverDir);
81
+ copyFileSync(need.core, join(serverDir, "i18n-core.cjs"));
82
+ copyFileSync(need.node, join(serverDir, "node.cjs"));
83
+ copyDirSync(need.locales, join(serverDir, "locales"));
84
+
85
+ // ─── Bridge panel (cep-plugin) — files at the extension ROOT ────────────────
86
+ // NOT resetDir(): that would rmSync the whole folder, wiping main.js/
87
+ // index.html/CSXS/... since the dir is now cep-plugin/ itself, shared with
88
+ // everything else the panel ships. Only remove the 3 files we own.
89
+ {
90
+ const dir = join(ROOT, "cep-plugin");
91
+ for (const rel of ["i18n-core.cjs", "i18n-panel.cjs", "i18n-locales.js"]) {
92
+ rmSync(join(dir, rel), { force: true });
93
+ }
94
+ copyFileSync(need.core, join(dir, "i18n-core.cjs"));
95
+ copyFileSync(need.panel, join(dir, "i18n-panel.cjs"));
96
+ copyFileSync(need.bundle, join(dir, "i18n-locales.js"));
97
+ }
98
+
99
+ // ─── AI Chat panel (chat-plugin) — real i18n/ subfolder, safe here ──────────
100
+ // (no in-panel hot-updater for this one -- see file header)
101
+ {
102
+ const dir = join(ROOT, "chat-plugin", "i18n");
103
+ resetDir(dir);
104
+ copyFileSync(need.core, join(dir, "i18n-core.cjs"));
105
+ copyFileSync(need.panel, join(dir, "panel.cjs"));
106
+ copyFileSync(need.bundle, join(dir, "locales.js"));
107
+ }
108
+
109
+ // ─── Summary ─────────────────────────────────────────────────────────────────
110
+ const langs = readdirSync(join(serverDir, "locales")).filter((f) => f.endsWith(".json")).map((f) => f.slice(0, -5)).sort();
111
+ const enKeys = Object.keys(JSON.parse(readFileSync(join(serverDir, "locales", "en.json"), "utf-8"))).length;
112
+ let rev = "";
113
+ try { rev = execSync("git rev-parse --short HEAD", { cwd: SRC, stdio: ["ignore", "pipe", "ignore"] }).toString().trim(); } catch {}
114
+
115
+ console.log(`✓ Synced i18n from ${SRC}${rev ? ` (@${rev})` : ""}`);
116
+ console.log(` languages: ${langs.join(", ")} · ${enKeys} English keys`);
117
+ console.log(" → i18n/ cep-plugin/i18n-*.{cjs,js} chat-plugin/i18n/");