@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/CHANGELOG.md +36 -0
- package/cep-plugin/CSXS/manifest.xml +1 -1
- package/cep-plugin/i18n-core.cjs +224 -0
- package/cep-plugin/i18n-locales.js +3 -0
- package/cep-plugin/i18n-panel.cjs +178 -0
- package/cep-plugin/index.html +60 -25
- package/cep-plugin/main.js +793 -689
- package/dist/bridge/file-bridge.js +5 -4
- package/dist/http-server.d.ts +1 -0
- package/dist/http-server.js +3 -0
- package/dist/i18n.d.ts +42 -0
- package/dist/i18n.js +69 -0
- package/dist/index.js +41 -31
- package/dist/license.js +8 -6
- package/dist/server.js +9 -5
- package/dist/tools/effects.js +3 -2
- package/dist/tools/export.js +3 -2
- package/dist/tools/transitions.js +3 -2
- package/i18n/i18n-core.cjs +224 -0
- package/i18n/locales/de.json +1488 -0
- package/i18n/locales/en.json +1488 -0
- package/i18n/locales/es.json +1488 -0
- package/i18n/locales/fr.json +1488 -0
- package/i18n/locales/hashes/de.json +1488 -0
- package/i18n/locales/hashes/es.json +1488 -0
- package/i18n/locales/hashes/fr.json +1488 -0
- package/i18n/locales/hashes/ja.json +1488 -0
- package/i18n/locales/hashes/pt-BR.json +1488 -0
- package/i18n/locales/ja.json +1488 -0
- package/i18n/locales/pt-BR.json +1488 -0
- package/i18n/node.cjs +124 -0
- package/package.json +67 -65
- package/scripts/package.mjs +18 -2
- package/scripts/sync-i18n.mjs +117 -0
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.
|
|
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
|
-
"
|
|
14
|
-
"
|
|
15
|
-
"
|
|
16
|
-
"
|
|
17
|
-
"
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
"
|
|
22
|
-
"
|
|
23
|
-
"start
|
|
24
|
-
"
|
|
25
|
-
"test
|
|
26
|
-
"test:
|
|
27
|
-
"
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
"
|
|
42
|
-
"
|
|
43
|
-
"
|
|
44
|
-
"
|
|
45
|
-
"
|
|
46
|
-
"
|
|
47
|
-
"
|
|
48
|
-
"
|
|
49
|
-
"
|
|
50
|
-
"
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
"
|
|
64
|
-
"
|
|
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
|
}
|
package/scripts/package.mjs
CHANGED
|
@@ -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/");
|