@synthetic-ai/premiere-mcp 2.3.1-dev.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
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { mkdirSync, writeFileSync, readFileSync, unlinkSync, existsSync, readdirSync, renameSync } from "node:fs";
|
|
2
2
|
import { join } from "node:path";
|
|
3
3
|
import { tmpdir } from "node:os";
|
|
4
|
+
import { t } from "../i18n.js";
|
|
4
5
|
const DEFAULT_TEMP_DIR = join(tmpdir(), "premiere-mcp-bridge");
|
|
5
6
|
const POLL_INTERVAL_MS = 100;
|
|
6
7
|
const DEFAULT_TIMEOUT_MS = 30000;
|
|
@@ -46,7 +47,7 @@ export async function sendCommand(script, options) {
|
|
|
46
47
|
function validateScript(script, allowUnsafe = false) {
|
|
47
48
|
const MAX_SCRIPT_SIZE = 500 * 1024; // 500KB
|
|
48
49
|
if (Buffer.byteLength(script, "utf-8") > MAX_SCRIPT_SIZE) {
|
|
49
|
-
throw new Error("
|
|
50
|
+
throw new Error(t("msg.bridge.scriptTooLarge", { limit: "500KB" }));
|
|
50
51
|
}
|
|
51
52
|
if (allowUnsafe)
|
|
52
53
|
return;
|
|
@@ -59,7 +60,7 @@ function validateScript(script, allowUnsafe = false) {
|
|
|
59
60
|
];
|
|
60
61
|
for (const pattern of dangerousPatterns) {
|
|
61
62
|
if (pattern.test(script)) {
|
|
62
|
-
throw new Error(
|
|
63
|
+
throw new Error(t("msg.bridge.blockedPattern", { pattern: pattern.source }));
|
|
63
64
|
}
|
|
64
65
|
}
|
|
65
66
|
}
|
|
@@ -96,7 +97,7 @@ async function pollForResponse(resFile, timeoutMs) {
|
|
|
96
97
|
catch (e) {
|
|
97
98
|
resolve({
|
|
98
99
|
success: false,
|
|
99
|
-
error:
|
|
100
|
+
error: t("msg.bridge.parseFailed", { error: e instanceof Error ? e.message : String(e) }),
|
|
100
101
|
});
|
|
101
102
|
}
|
|
102
103
|
return;
|
|
@@ -104,7 +105,7 @@ async function pollForResponse(resFile, timeoutMs) {
|
|
|
104
105
|
if (Date.now() - start > timeoutMs) {
|
|
105
106
|
resolve({
|
|
106
107
|
success: false,
|
|
107
|
-
error:
|
|
108
|
+
error: t("msg.bridge.timeout", { ms: timeoutMs }),
|
|
108
109
|
});
|
|
109
110
|
return;
|
|
110
111
|
}
|
package/dist/http-server.d.ts
CHANGED
|
@@ -16,6 +16,7 @@
|
|
|
16
16
|
* PREMIERE_TEMP_DIR Shared temp directory for the file bridge
|
|
17
17
|
* PREMIERE_TIMEOUT_MS Command timeout in ms (default: 30000)
|
|
18
18
|
* MCP_AUTH_TOKEN Optional bearer token to require on all requests
|
|
19
|
+
* PREMIERE_PRO_MCP_LANG Language of tool descriptions/messages (see src/i18n.ts)
|
|
19
20
|
*/
|
|
20
21
|
export {};
|
|
21
22
|
//# sourceMappingURL=http-server.d.ts.map
|
package/dist/http-server.js
CHANGED
|
@@ -16,6 +16,7 @@
|
|
|
16
16
|
* PREMIERE_TEMP_DIR Shared temp directory for the file bridge
|
|
17
17
|
* PREMIERE_TIMEOUT_MS Command timeout in ms (default: 30000)
|
|
18
18
|
* MCP_AUTH_TOKEN Optional bearer token to require on all requests
|
|
19
|
+
* PREMIERE_PRO_MCP_LANG Language of tool descriptions/messages (see src/i18n.ts)
|
|
19
20
|
*/
|
|
20
21
|
import http from "node:http";
|
|
21
22
|
import fs from "node:fs";
|
|
@@ -24,6 +25,7 @@ import { fileURLToPath } from "node:url";
|
|
|
24
25
|
import { StreamableHTTPServerTransport } from "@modelcontextprotocol/sdk/server/streamableHttp.js";
|
|
25
26
|
import { createServer } from "./server.js";
|
|
26
27
|
import { cleanupTempDir, getTempDir } from "./bridge/file-bridge.js";
|
|
28
|
+
import { logLanguage } from "./i18n.js";
|
|
27
29
|
const __dirname = path.dirname(fileURLToPath(import.meta.url));
|
|
28
30
|
const LANDING_DIR = path.resolve(__dirname, "../landing-dist");
|
|
29
31
|
const MIME = {
|
|
@@ -72,6 +74,7 @@ const bridgeOptions = {
|
|
|
72
74
|
const tempDir = getTempDir(bridgeOptions);
|
|
73
75
|
console.error(`[premiere-pro-mcp] Starting HTTP server on port ${PORT}...`);
|
|
74
76
|
console.error(`[premiere-pro-mcp] Temp directory: ${tempDir}`);
|
|
77
|
+
logLanguage();
|
|
75
78
|
cleanupTempDir(bridgeOptions);
|
|
76
79
|
// Each request gets its own transport+server instance (stateless per-request model)
|
|
77
80
|
const httpServer = http.createServer(async (req, res) => {
|
package/dist/i18n.d.ts
ADDED
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* i18n — language of the tool descriptions and of the messages this server
|
|
3
|
+
* prints or returns to the MCP client.
|
|
4
|
+
*
|
|
5
|
+
* The runtime (node.cjs + i18n-core.cjs) and the dictionaries come from the
|
|
6
|
+
* central synthetic-idiomas repo, vendored into <package root>/i18n by
|
|
7
|
+
* scripts/sync-i18n.mjs. They're loaded at runtime (not compiled in), resolved
|
|
8
|
+
* relative to this module: dist/i18n.js → ../i18n, and the esbuild bundle at
|
|
9
|
+
* release/server/index.mjs → release/i18n (scripts/package.mjs copies it).
|
|
10
|
+
*
|
|
11
|
+
* The language is picked ONCE at startup, first match wins:
|
|
12
|
+
* PREMIERE_PRO_MCP_LANG → SYNTHETIC_LANG →
|
|
13
|
+
* <USER_DATA>/com.mcp.premiere.bridge/settings.json (written by the panels'
|
|
14
|
+
* language selector) → <USER_DATA>/com.synthetic/settings.json → English.
|
|
15
|
+
* MCP clients only read tool descriptions when they connect, so a change in
|
|
16
|
+
* the panel applies after the MCP server (or the client app) restarts.
|
|
17
|
+
*/
|
|
18
|
+
import type { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
|
|
19
|
+
export declare const LANG_ENV_VAR = "PREMIERE_PRO_MCP_LANG";
|
|
20
|
+
export declare const SETTINGS_FOLDER = "com.mcp.premiere.bridge";
|
|
21
|
+
type Vars = Record<string, string | number | null | undefined>;
|
|
22
|
+
interface ServerI18n {
|
|
23
|
+
language: string;
|
|
24
|
+
languageSource: string;
|
|
25
|
+
t(key: string, vars?: Vars | null, fallbackText?: string): string;
|
|
26
|
+
}
|
|
27
|
+
export declare const i18n: ServerI18n;
|
|
28
|
+
/** Localized text for a `msg.*` key, with `{placeholders}` filled from `vars`. */
|
|
29
|
+
export declare function t(key: string, vars?: Vars): string;
|
|
30
|
+
/** Language codes supported by the dictionaries, e.g. "en, es, pt-BR, …". */
|
|
31
|
+
export declare function supportedLanguages(): string[];
|
|
32
|
+
/** Display name of the active language in its own language ("Español"). */
|
|
33
|
+
export declare function languageName(): string;
|
|
34
|
+
/**
|
|
35
|
+
* Serve translated tool descriptions from tools/list. Call after every tool
|
|
36
|
+
* is registered and before connect(). No-op in English.
|
|
37
|
+
*/
|
|
38
|
+
export declare function localizeToolsList(server: McpServer): boolean;
|
|
39
|
+
/** One stderr line at startup: which language and where the choice came from. */
|
|
40
|
+
export declare function logLanguage(): void;
|
|
41
|
+
export {};
|
|
42
|
+
//# sourceMappingURL=i18n.d.ts.map
|
package/dist/i18n.js
ADDED
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* i18n — language of the tool descriptions and of the messages this server
|
|
3
|
+
* prints or returns to the MCP client.
|
|
4
|
+
*
|
|
5
|
+
* The runtime (node.cjs + i18n-core.cjs) and the dictionaries come from the
|
|
6
|
+
* central synthetic-idiomas repo, vendored into <package root>/i18n by
|
|
7
|
+
* scripts/sync-i18n.mjs. They're loaded at runtime (not compiled in), resolved
|
|
8
|
+
* relative to this module: dist/i18n.js → ../i18n, and the esbuild bundle at
|
|
9
|
+
* release/server/index.mjs → release/i18n (scripts/package.mjs copies it).
|
|
10
|
+
*
|
|
11
|
+
* The language is picked ONCE at startup, first match wins:
|
|
12
|
+
* PREMIERE_PRO_MCP_LANG → SYNTHETIC_LANG →
|
|
13
|
+
* <USER_DATA>/com.mcp.premiere.bridge/settings.json (written by the panels'
|
|
14
|
+
* language selector) → <USER_DATA>/com.synthetic/settings.json → English.
|
|
15
|
+
* MCP clients only read tool descriptions when they connect, so a change in
|
|
16
|
+
* the panel applies after the MCP server (or the client app) restarts.
|
|
17
|
+
*/
|
|
18
|
+
import { createRequire } from "node:module";
|
|
19
|
+
import { fileURLToPath } from "node:url";
|
|
20
|
+
import path from "node:path";
|
|
21
|
+
export const LANG_ENV_VAR = "PREMIERE_PRO_MCP_LANG";
|
|
22
|
+
export const SETTINGS_FOLDER = "com.mcp.premiere.bridge";
|
|
23
|
+
const I18N_DIR = path.resolve(path.dirname(fileURLToPath(import.meta.url)), "..", "i18n");
|
|
24
|
+
// A local name (not `require`) so bundlers leave this runtime load alone.
|
|
25
|
+
const requireCjs = createRequire(import.meta.url);
|
|
26
|
+
let runtime = null;
|
|
27
|
+
let loadError = null;
|
|
28
|
+
try {
|
|
29
|
+
runtime = requireCjs(path.join(I18N_DIR, "node.cjs"));
|
|
30
|
+
}
|
|
31
|
+
catch (err) {
|
|
32
|
+
loadError = (err instanceof Error ? err.message : String(err)).split("\n")[0];
|
|
33
|
+
}
|
|
34
|
+
export const i18n = runtime
|
|
35
|
+
? runtime.createServerI18n({
|
|
36
|
+
localesDir: path.join(I18N_DIR, "locales"),
|
|
37
|
+
envVar: LANG_ENV_VAR,
|
|
38
|
+
settingsFolder: SETTINGS_FOLDER,
|
|
39
|
+
})
|
|
40
|
+
: { language: "en", languageSource: "default", t: (key) => key };
|
|
41
|
+
/** Localized text for a `msg.*` key, with `{placeholders}` filled from `vars`. */
|
|
42
|
+
export function t(key, vars) {
|
|
43
|
+
return i18n.t(key, vars);
|
|
44
|
+
}
|
|
45
|
+
/** Language codes supported by the dictionaries, e.g. "en, es, pt-BR, …". */
|
|
46
|
+
export function supportedLanguages() {
|
|
47
|
+
return runtime ? runtime.core.LANGUAGES.map((l) => l.code) : ["en"];
|
|
48
|
+
}
|
|
49
|
+
/** Display name of the active language in its own language ("Español"). */
|
|
50
|
+
export function languageName() {
|
|
51
|
+
const found = runtime?.core.LANGUAGES.find((l) => l.code === i18n.language);
|
|
52
|
+
return found ? found.name : i18n.language;
|
|
53
|
+
}
|
|
54
|
+
/**
|
|
55
|
+
* Serve translated tool descriptions from tools/list. Call after every tool
|
|
56
|
+
* is registered and before connect(). No-op in English.
|
|
57
|
+
*/
|
|
58
|
+
export function localizeToolsList(server) {
|
|
59
|
+
return runtime ? runtime.patchMcpServerToolsList(server, i18n) : false;
|
|
60
|
+
}
|
|
61
|
+
/** One stderr line at startup: which language and where the choice came from. */
|
|
62
|
+
export function logLanguage() {
|
|
63
|
+
if (loadError) {
|
|
64
|
+
console.error(`[premiere-pro-mcp] i18n not loaded from ${I18N_DIR} (${loadError}) — run scripts/sync-i18n.mjs`);
|
|
65
|
+
return;
|
|
66
|
+
}
|
|
67
|
+
console.error(`[premiere-pro-mcp] Language: ${i18n.language} (${i18n.languageSource})`);
|
|
68
|
+
}
|
|
69
|
+
//# sourceMappingURL=i18n.js.map
|
package/dist/index.js
CHANGED
|
@@ -3,6 +3,7 @@ import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js"
|
|
|
3
3
|
import { createServer } from "./server.js";
|
|
4
4
|
import { cleanupTempDir, getTempDir } from "./bridge/file-bridge.js";
|
|
5
5
|
import { checkLicense } from "./license.js";
|
|
6
|
+
import { t, i18n, languageName, logLanguage, supportedLanguages, LANG_ENV_VAR } from "./i18n.js";
|
|
6
7
|
import { execSync } from "child_process";
|
|
7
8
|
import { fileURLToPath } from "url";
|
|
8
9
|
import path from "path";
|
|
@@ -39,7 +40,7 @@ function premiereInstallCandidates() {
|
|
|
39
40
|
// ("UV_HANDLE_CLOSING", src/win/async.c) before the process actually exits.
|
|
40
41
|
// Setting exitCode and letting the event loop drain naturally avoids it.
|
|
41
42
|
async function runDoctor() {
|
|
42
|
-
console.log(`\n${DIM}
|
|
43
|
+
console.log(`\n${DIM}${t("msg.doctor.title")}${RESET}\n`);
|
|
43
44
|
let hasFail = false;
|
|
44
45
|
// 1. Node version
|
|
45
46
|
const nodeMajor = parseInt(process.version.slice(1).split(".")[0], 10);
|
|
@@ -48,35 +49,35 @@ async function runDoctor() {
|
|
|
48
49
|
}
|
|
49
50
|
else {
|
|
50
51
|
hasFail = true;
|
|
51
|
-
printCheck("fail", `Node.js ${process.version}`, "
|
|
52
|
+
printCheck("fail", `Node.js ${process.version}`, t("msg.doctor.nodeTooOld"));
|
|
52
53
|
}
|
|
53
54
|
// 2. OS (informational — both are supported, this just confirms detection)
|
|
54
55
|
const osLabel = process.platform === "darwin" ? "macOS" : process.platform === "win32" ? "Windows" : process.platform;
|
|
55
|
-
printCheck(process.platform === "darwin" || process.platform === "win32" ? "pass" : "warn",
|
|
56
|
+
printCheck(process.platform === "darwin" || process.platform === "win32" ? "pass" : "warn", t("msg.doctor.os", { os: osLabel }));
|
|
56
57
|
// 3. Premiere Pro install detected on disk
|
|
57
58
|
const found = premiereInstallCandidates().find((p) => existsSync(p));
|
|
58
59
|
if (found) {
|
|
59
|
-
printCheck("pass", "
|
|
60
|
+
printCheck("pass", t("msg.doctor.premiereFound"), found);
|
|
60
61
|
}
|
|
61
62
|
else {
|
|
62
|
-
printCheck("warn", "
|
|
63
|
+
printCheck("warn", t("msg.doctor.premiereNotFound"), t("msg.doctor.premiereNotFoundDetail"));
|
|
63
64
|
}
|
|
64
65
|
// 4. License key present
|
|
65
66
|
const licenseKey = process.env.PREMIERE_PRO_MCP_LICENSE;
|
|
66
67
|
if (!licenseKey) {
|
|
67
68
|
hasFail = true;
|
|
68
|
-
printCheck("fail", "
|
|
69
|
+
printCheck("fail", t("msg.doctor.licenseMissing"), t("msg.doctor.licenseMissingDetail"));
|
|
69
70
|
}
|
|
70
71
|
else {
|
|
71
|
-
printCheck("pass",
|
|
72
|
+
printCheck("pass", t("msg.doctor.licensePresent", { prefix: licenseKey.slice(0, 8) }));
|
|
72
73
|
// 5. Live validation against synthetic.com.ar (also exercises network reachability)
|
|
73
74
|
const result = await checkLicense();
|
|
74
75
|
if (result.valid) {
|
|
75
|
-
printCheck("pass", "
|
|
76
|
+
printCheck("pass", t("msg.doctor.licenseValid"), result.expiresAt ? t("msg.doctor.licenseExpires", { date: result.expiresAt }) : t("msg.doctor.licenseNoExpiration"));
|
|
76
77
|
}
|
|
77
78
|
else {
|
|
78
79
|
hasFail = true;
|
|
79
|
-
printCheck("fail", "
|
|
80
|
+
printCheck("fail", t("msg.doctor.licenseInvalid"), result.message ?? t("msg.doctor.unknownReason"));
|
|
80
81
|
}
|
|
81
82
|
}
|
|
82
83
|
// 6. Bridge temp directory writable
|
|
@@ -87,36 +88,44 @@ async function runDoctor() {
|
|
|
87
88
|
const probe = path.join(tempDir, `.doctor-probe-${Date.now()}`);
|
|
88
89
|
writeFileSync(probe, "ok");
|
|
89
90
|
unlinkSync(probe);
|
|
90
|
-
printCheck("pass", "
|
|
91
|
+
printCheck("pass", t("msg.doctor.tempWritable"), tempDir);
|
|
91
92
|
}
|
|
92
93
|
catch (err) {
|
|
93
94
|
hasFail = true;
|
|
94
|
-
printCheck("fail", "
|
|
95
|
+
printCheck("fail", t("msg.doctor.tempNotWritable"), `${tempDir} — ${err instanceof Error ? err.message : String(err)}`);
|
|
95
96
|
}
|
|
97
|
+
// 7. Language of tool descriptions + messages (informational)
|
|
98
|
+
printCheck("pass", t("msg.doctor.language", { language: languageName() }), i18n.languageSource === "default"
|
|
99
|
+
? t("msg.doctor.languageDefault")
|
|
100
|
+
: t("msg.doctor.languageFrom", { source: i18n.languageSource }));
|
|
96
101
|
console.log(hasFail
|
|
97
|
-
? `\n${RED}
|
|
98
|
-
: `\n${GREEN}
|
|
102
|
+
? `\n${RED}${t("msg.doctor.someFailed")}${RESET} ${t("msg.doctor.someFailedHint")}\n`
|
|
103
|
+
: `\n${GREEN}${t("msg.doctor.allGood")}${RESET}\n`);
|
|
99
104
|
return hasFail;
|
|
100
105
|
}
|
|
101
106
|
// Handle CLI flags
|
|
102
107
|
const args = process.argv.slice(2);
|
|
103
108
|
if (args.includes("--help") || args.includes("-h")) {
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
109
|
+
const row = (cmd, text, width) => ` ${cmd.padEnd(width)} ${text}`;
|
|
110
|
+
console.log([
|
|
111
|
+
"",
|
|
112
|
+
`premiere-pro-mcp — ${t("msg.help.title", { count: 437 })}`,
|
|
113
|
+
"",
|
|
114
|
+
t("msg.help.usage"),
|
|
115
|
+
row("premiere-pro-mcp", t("msg.help.start"), 31),
|
|
116
|
+
row("premiere-pro-mcp --doctor", t("msg.help.doctor"), 31),
|
|
117
|
+
row("premiere-pro-mcp --install-cep", t("msg.help.installCep"), 31),
|
|
118
|
+
row("premiere-pro-mcp --help", t("msg.help.help"), 31),
|
|
119
|
+
row("premiere-pro-mcp --version", t("msg.help.version"), 31),
|
|
120
|
+
"",
|
|
121
|
+
t("msg.help.env"),
|
|
122
|
+
row("PREMIERE_TEMP_DIR", t("msg.help.envTempDir"), 22),
|
|
123
|
+
row("PREMIERE_TIMEOUT_MS", t("msg.help.envTimeout"), 22),
|
|
124
|
+
row(LANG_ENV_VAR, t("msg.help.envLang", { languages: supportedLanguages().join(", ") }), 22),
|
|
125
|
+
"",
|
|
126
|
+
t("msg.help.moreInfo", { url: "https://synthetic.com.ar" }),
|
|
127
|
+
"",
|
|
128
|
+
].join("\n"));
|
|
120
129
|
process.exit(0);
|
|
121
130
|
}
|
|
122
131
|
if (args.includes("--version") || args.includes("-v")) {
|
|
@@ -132,12 +141,12 @@ if (args.includes("--doctor")) {
|
|
|
132
141
|
}
|
|
133
142
|
if (args.includes("--install-cep")) {
|
|
134
143
|
const scriptPath = path.join(projectRoot, "scripts", "install-cep.sh");
|
|
135
|
-
console.log("
|
|
144
|
+
console.log(`${t("msg.installCep.installing")}\n`);
|
|
136
145
|
try {
|
|
137
146
|
execSync(`bash "${scriptPath}"`, { stdio: "inherit", cwd: projectRoot });
|
|
138
147
|
}
|
|
139
148
|
catch {
|
|
140
|
-
console.error("
|
|
149
|
+
console.error(t("msg.installCep.failed"));
|
|
141
150
|
console.error(` bash "${scriptPath}"`);
|
|
142
151
|
process.exit(1);
|
|
143
152
|
}
|
|
@@ -153,6 +162,7 @@ async function main() {
|
|
|
153
162
|
const tempDir = getTempDir(bridgeOptions);
|
|
154
163
|
console.error(`[premiere-pro-mcp] Starting MCP server...`);
|
|
155
164
|
console.error(`[premiere-pro-mcp] Temp directory: ${tempDir}`);
|
|
165
|
+
logLanguage();
|
|
156
166
|
// Clean up any stale files from previous sessions
|
|
157
167
|
cleanupTempDir(bridgeOptions);
|
|
158
168
|
const server = createServer(bridgeOptions);
|
package/dist/license.js
CHANGED
|
@@ -7,6 +7,7 @@ import os from "node:os";
|
|
|
7
7
|
import fs from "node:fs";
|
|
8
8
|
import path from "node:path";
|
|
9
9
|
import crypto from "node:crypto";
|
|
10
|
+
import { t } from "./i18n.js";
|
|
10
11
|
const LICENSE_KEY = process.env.PREMIERE_PRO_MCP_LICENSE;
|
|
11
12
|
const LICENSE_VALIDATION_URL = "https://synthetic.com.ar/api/v1/license/validate";
|
|
12
13
|
const LICENSE_CACHE_TTL_MS = 60 * 60 * 1000; // 1 hour
|
|
@@ -68,7 +69,7 @@ export async function checkLicense() {
|
|
|
68
69
|
cache = {
|
|
69
70
|
valid: false,
|
|
70
71
|
plan: null,
|
|
71
|
-
message: "
|
|
72
|
+
message: t("msg.license.missing"),
|
|
72
73
|
checkedAt: Date.now(),
|
|
73
74
|
};
|
|
74
75
|
return cache;
|
|
@@ -91,7 +92,7 @@ export async function checkLicense() {
|
|
|
91
92
|
else {
|
|
92
93
|
cache = {
|
|
93
94
|
valid: false,
|
|
94
|
-
message: "
|
|
95
|
+
message: t("msg.license.unreachable"),
|
|
95
96
|
checkedAt: Date.now(),
|
|
96
97
|
};
|
|
97
98
|
}
|
|
@@ -99,23 +100,24 @@ export async function checkLicense() {
|
|
|
99
100
|
catch {
|
|
100
101
|
cache = {
|
|
101
102
|
valid: false,
|
|
102
|
-
message: "
|
|
103
|
+
message: t("msg.license.unreachable"),
|
|
103
104
|
checkedAt: Date.now(),
|
|
104
105
|
};
|
|
105
106
|
}
|
|
106
107
|
return cache;
|
|
107
108
|
}
|
|
108
109
|
export function licenseErrorResponse(toolName) {
|
|
109
|
-
|
|
110
|
+
// cache.message may come from the license server as-is (not translated here).
|
|
111
|
+
const msg = cache?.message ?? t("msg.license.invalid");
|
|
110
112
|
return {
|
|
111
113
|
content: [
|
|
112
114
|
{
|
|
113
115
|
type: "text",
|
|
114
116
|
text: JSON.stringify({
|
|
115
|
-
error: "
|
|
117
|
+
error: t("msg.license.required"),
|
|
116
118
|
detail: msg,
|
|
117
119
|
tool: toolName,
|
|
118
|
-
info: "
|
|
120
|
+
info: t("msg.license.getLicense"),
|
|
119
121
|
}),
|
|
120
122
|
},
|
|
121
123
|
],
|
package/dist/server.js
CHANGED
|
@@ -37,6 +37,7 @@ import { getExportPresetsTools } from "./tools/export-presets.js";
|
|
|
37
37
|
import { getSequenceSettingsTools } from "./tools/sequence-settings.js";
|
|
38
38
|
import { EXTENDSCRIPT_REFERENCE } from "./resources/extendscript-reference.js";
|
|
39
39
|
import { checkLicense, licenseErrorResponse, FREE_TOOLS } from "./license.js";
|
|
40
|
+
import { t, localizeToolsList } from "./i18n.js";
|
|
40
41
|
import { z } from "zod";
|
|
41
42
|
const PREMIERE_INSTRUCTIONS = `You are controlling Adobe Premiere Pro through MCP tools. Follow these best practices:
|
|
42
43
|
|
|
@@ -218,7 +219,7 @@ export function createServer(bridgeOptions) {
|
|
|
218
219
|
},
|
|
219
220
|
{
|
|
220
221
|
type: "text",
|
|
221
|
-
text: "
|
|
222
|
+
text: t("msg.tool.frameCaptured"),
|
|
222
223
|
},
|
|
223
224
|
],
|
|
224
225
|
};
|
|
@@ -237,7 +238,7 @@ export function createServer(bridgeOptions) {
|
|
|
237
238
|
content: [
|
|
238
239
|
{
|
|
239
240
|
type: "text",
|
|
240
|
-
text:
|
|
241
|
+
text: t("msg.tool.error", { message: String(result.error) }),
|
|
241
242
|
},
|
|
242
243
|
],
|
|
243
244
|
isError: true,
|
|
@@ -249,7 +250,7 @@ export function createServer(bridgeOptions) {
|
|
|
249
250
|
content: [
|
|
250
251
|
{
|
|
251
252
|
type: "text",
|
|
252
|
-
text:
|
|
253
|
+
text: t("msg.tool.error", { message: err instanceof Error ? err.message : String(err) }),
|
|
253
254
|
},
|
|
254
255
|
],
|
|
255
256
|
isError: true,
|
|
@@ -259,7 +260,7 @@ export function createServer(bridgeOptions) {
|
|
|
259
260
|
}
|
|
260
261
|
// Register LLM instructions resource
|
|
261
262
|
server.resource("premiere-instructions", "config://premiere-instructions", {
|
|
262
|
-
description: "
|
|
263
|
+
description: t("msg.resource.instructions"),
|
|
263
264
|
mimeType: "text/plain",
|
|
264
265
|
}, async (uri) => ({
|
|
265
266
|
contents: [
|
|
@@ -271,7 +272,7 @@ export function createServer(bridgeOptions) {
|
|
|
271
272
|
}));
|
|
272
273
|
// Register ExtendScript API reference resource
|
|
273
274
|
server.resource("extendscript-reference", "config://extendscript-reference", {
|
|
274
|
-
description: "
|
|
275
|
+
description: t("msg.resource.extendscriptReference"),
|
|
275
276
|
mimeType: "text/plain",
|
|
276
277
|
}, async (uri) => ({
|
|
277
278
|
contents: [
|
|
@@ -281,6 +282,9 @@ export function createServer(bridgeOptions) {
|
|
|
281
282
|
},
|
|
282
283
|
],
|
|
283
284
|
}));
|
|
285
|
+
// Translated tool descriptions in tools/list (both stdio and HTTP entry
|
|
286
|
+
// points build their server here, before connect()). No-op in English.
|
|
287
|
+
localizeToolsList(server);
|
|
284
288
|
const toolCount = Object.keys(toolModules).length;
|
|
285
289
|
console.error(`[premiere-pro-mcp] Registered ${toolCount} tools + 2 resources`);
|
|
286
290
|
return server;
|
package/dist/tools/effects.js
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { buildToolScript, escapeForExtendScript } from "../bridge/script-builder.js";
|
|
2
2
|
import { sendCommand } from "../bridge/file-bridge.js";
|
|
3
|
+
import { t } from "../i18n.js";
|
|
3
4
|
export function getEffectsTools(bridgeOptions) {
|
|
4
5
|
return {
|
|
5
6
|
apply_effect: {
|
|
@@ -232,7 +233,7 @@ Example: apply_effect({ node_id: "abc123", effect_name: "Lumetri Color" })`,
|
|
|
232
233
|
{ name: "Clip Name", category: "Utility" },
|
|
233
234
|
{ name: "SDR Conform", category: "Utility" },
|
|
234
235
|
];
|
|
235
|
-
return { success: true, data: { effects, count: effects.length, note: "
|
|
236
|
+
return { success: true, data: { effects, count: effects.length, note: t("msg.tool.videoEffectsNote") } };
|
|
236
237
|
},
|
|
237
238
|
},
|
|
238
239
|
list_available_audio_effects: {
|
|
@@ -279,7 +280,7 @@ Example: apply_effect({ node_id: "abc123", effect_name: "Lumetri Color" })`,
|
|
|
279
280
|
// Time & Pitch
|
|
280
281
|
{ name: "Pitch & Time", category: "Time & Pitch" },
|
|
281
282
|
];
|
|
282
|
-
return { success: true, data: { effects, count: effects.length, note: "
|
|
283
|
+
return { success: true, data: { effects, count: effects.length, note: t("msg.tool.audioEffectsNote") } };
|
|
283
284
|
},
|
|
284
285
|
},
|
|
285
286
|
color_correct: {
|
package/dist/tools/export.js
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { buildToolScript, escapeForExtendScript } from "../bridge/script-builder.js";
|
|
2
2
|
import { sendCommand } from "../bridge/file-bridge.js";
|
|
3
|
+
import { t } from "../i18n.js";
|
|
3
4
|
import { readFileSync, unlinkSync, existsSync } from "node:fs";
|
|
4
5
|
import { join } from "node:path";
|
|
5
6
|
import { tmpdir } from "node:os";
|
|
@@ -363,7 +364,7 @@ Example: export_sequence({ output_path: "/Users/me/exports/prores.mov", preset_p
|
|
|
363
364
|
attempts++;
|
|
364
365
|
}
|
|
365
366
|
if (!existsSync(tempPath)) {
|
|
366
|
-
return { success: false, error: "
|
|
367
|
+
return { success: false, error: t("msg.tool.frameNotFound", { path: tempPath }) };
|
|
367
368
|
}
|
|
368
369
|
try {
|
|
369
370
|
const imageData = readFileSync(tempPath);
|
|
@@ -383,7 +384,7 @@ Example: export_sequence({ output_path: "/Users/me/exports/prores.mov", preset_p
|
|
|
383
384
|
};
|
|
384
385
|
}
|
|
385
386
|
catch (e) {
|
|
386
|
-
return { success: false, error:
|
|
387
|
+
return { success: false, error: t("msg.tool.frameReadFailed", { error: e instanceof Error ? e.message : String(e) }) };
|
|
387
388
|
}
|
|
388
389
|
},
|
|
389
390
|
},
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { buildToolScript, escapeForExtendScript } from "../bridge/script-builder.js";
|
|
2
2
|
import { sendCommand } from "../bridge/file-bridge.js";
|
|
3
|
+
import { t } from "../i18n.js";
|
|
3
4
|
export function getTransitionsTools(bridgeOptions) {
|
|
4
5
|
return {
|
|
5
6
|
add_transition: {
|
|
@@ -247,7 +248,7 @@ export function getTransitionsTools(bridgeOptions) {
|
|
|
247
248
|
{ name: "Swing Out", category: "3D Motion" },
|
|
248
249
|
{ name: "Tumble Away", category: "3D Motion" },
|
|
249
250
|
];
|
|
250
|
-
return { success: true, data: { transitions, count: transitions.length, note: "
|
|
251
|
+
return { success: true, data: { transitions, count: transitions.length, note: t("msg.tool.videoTransitionsNote") } };
|
|
251
252
|
},
|
|
252
253
|
},
|
|
253
254
|
list_available_audio_transitions: {
|
|
@@ -259,7 +260,7 @@ export function getTransitionsTools(bridgeOptions) {
|
|
|
259
260
|
{ name: "Constant Power", category: "Crossfade", description: "Crossfade using constant power (equal loudness) - default" },
|
|
260
261
|
{ name: "Exponential Fade", category: "Crossfade", description: "Exponential fade curve" },
|
|
261
262
|
];
|
|
262
|
-
return { success: true, data: { transitions, count: transitions.length, note: "
|
|
263
|
+
return { success: true, data: { transitions, count: transitions.length, note: t("msg.tool.audioTransitionsNote") } };
|
|
263
264
|
},
|
|
264
265
|
},
|
|
265
266
|
};
|