@synthetic-ai/premiere-mcp 2.3.5 → 3.0.0
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/LICENSE +5 -21
- package/README.md +10 -242
- package/launcher.mjs +111 -0
- package/package.json +10 -54
- package/CHANGELOG.md +0 -180
- package/cep-plugin/.debug +0 -8
- package/cep-plugin/CSInterface.js +0 -92
- package/cep-plugin/CSXS/manifest.xml +0 -49
- package/cep-plugin/host.jsx +0 -7
- package/cep-plugin/i18n-core.cjs +0 -224
- package/cep-plugin/i18n-locales.js +0 -3
- package/cep-plugin/i18n-panel.cjs +0 -178
- package/cep-plugin/index.html +0 -507
- package/cep-plugin/main.js +0 -793
- package/cep-plugin/premiere.jsx +0 -24947
- package/cep-plugin/synthetic-logo.png +0 -0
- package/dist/bridge/file-bridge.d.ts +0 -29
- package/dist/bridge/file-bridge.js +0 -146
- package/dist/bridge/script-builder.d.ts +0 -19
- package/dist/bridge/script-builder.js +0 -408
- package/dist/http-server.d.ts +0 -22
- package/dist/http-server.js +0 -143
- package/dist/i18n.d.ts +0 -42
- package/dist/i18n.js +0 -69
- package/dist/index.d.ts +0 -3
- package/dist/index.js +0 -179
- package/dist/license.d.ts +0 -22
- package/dist/license.js +0 -129
- package/dist/resources/extendscript-reference.d.ts +0 -2
- package/dist/resources/extendscript-reference.js +0 -219
- package/dist/server.d.ts +0 -4
- package/dist/server.js +0 -292
- package/dist/tools/advanced.d.ts +0 -530
- package/dist/tools/advanced.js +0 -923
- package/dist/tools/audio-advanced.d.ts +0 -847
- package/dist/tools/audio-advanced.js +0 -1653
- package/dist/tools/audio.d.ts +0 -84
- package/dist/tools/audio.js +0 -123
- package/dist/tools/captions.d.ts +0 -30
- package/dist/tools/captions.js +0 -73
- package/dist/tools/clipboard.d.ts +0 -153
- package/dist/tools/clipboard.js +0 -381
- package/dist/tools/color-advanced.d.ts +0 -821
- package/dist/tools/color-advanced.js +0 -772
- package/dist/tools/discovery.d.ts +0 -128
- package/dist/tools/discovery.js +0 -445
- package/dist/tools/effects.d.ts +0 -211
- package/dist/tools/effects.js +0 -555
- package/dist/tools/export-presets.d.ts +0 -333
- package/dist/tools/export-presets.js +0 -490
- package/dist/tools/export.d.ts +0 -320
- package/dist/tools/export.js +0 -619
- package/dist/tools/health.d.ts +0 -9
- package/dist/tools/health.js +0 -25
- package/dist/tools/inspection.d.ts +0 -179
- package/dist/tools/inspection.js +0 -1089
- package/dist/tools/keyframes.d.ts +0 -253
- package/dist/tools/keyframes.js +0 -611
- package/dist/tools/markers.d.ts +0 -117
- package/dist/tools/markers.js +0 -206
- package/dist/tools/media.d.ts +0 -297
- package/dist/tools/media.js +0 -493
- package/dist/tools/metadata.d.ts +0 -178
- package/dist/tools/metadata.js +0 -278
- package/dist/tools/multicam.d.ts +0 -199
- package/dist/tools/multicam.js +0 -212
- package/dist/tools/playback.d.ts +0 -34
- package/dist/tools/playback.js +0 -63
- package/dist/tools/playhead.d.ts +0 -77
- package/dist/tools/playhead.js +0 -185
- package/dist/tools/project-manager.d.ts +0 -65
- package/dist/tools/project-manager.js +0 -81
- package/dist/tools/project.d.ts +0 -390
- package/dist/tools/project.js +0 -596
- package/dist/tools/scripting.d.ts +0 -98
- package/dist/tools/scripting.js +0 -434
- package/dist/tools/selection.d.ts +0 -120
- package/dist/tools/selection.js +0 -334
- package/dist/tools/sequence-advanced.d.ts +0 -84
- package/dist/tools/sequence-advanced.js +0 -476
- package/dist/tools/sequence-settings.d.ts +0 -397
- package/dist/tools/sequence-settings.js +0 -975
- package/dist/tools/sequence.d.ts +0 -211
- package/dist/tools/sequence.js +0 -400
- package/dist/tools/source-monitor.d.ts +0 -95
- package/dist/tools/source-monitor.js +0 -180
- package/dist/tools/text.d.ts +0 -97
- package/dist/tools/text.js +0 -159
- package/dist/tools/timeline.d.ts +0 -265
- package/dist/tools/timeline.js +0 -575
- package/dist/tools/track-management.d.ts +0 -482
- package/dist/tools/track-management.js +0 -787
- package/dist/tools/track-targeting.d.ts +0 -666
- package/dist/tools/track-targeting.js +0 -1318
- package/dist/tools/tracks.d.ts +0 -90
- package/dist/tools/tracks.js +0 -183
- package/dist/tools/transitions-motion.d.ts +0 -788
- package/dist/tools/transitions-motion.js +0 -680
- package/dist/tools/transitions.d.ts +0 -124
- package/dist/tools/transitions.js +0 -268
- package/dist/tools/utility.d.ts +0 -469
- package/dist/tools/utility.js +0 -1118
- package/dist/tools/workspace.d.ts +0 -25
- package/dist/tools/workspace.js +0 -61
- package/i18n/i18n-core.cjs +0 -224
- package/i18n/locales/de.json +0 -1488
- package/i18n/locales/en.json +0 -1488
- package/i18n/locales/es.json +0 -1488
- package/i18n/locales/fr.json +0 -1488
- package/i18n/locales/hashes/de.json +0 -1488
- package/i18n/locales/hashes/es.json +0 -1488
- package/i18n/locales/hashes/fr.json +0 -1488
- package/i18n/locales/hashes/ja.json +0 -1488
- package/i18n/locales/hashes/pt-BR.json +0 -1488
- package/i18n/locales/ja.json +0 -1488
- package/i18n/locales/pt-BR.json +0 -1488
- package/i18n/node.cjs +0 -124
- package/scripts/build-chat-dmg.sh +0 -210
- package/scripts/build-chat-zip.sh +0 -291
- package/scripts/install-cep-windows.ps1 +0 -99
- package/scripts/install-cep.sh +0 -66
- package/scripts/install-chat-plugin.bat +0 -67
- package/scripts/install-chat-plugin.sh +0 -85
- package/scripts/install-windows.bat +0 -95
- package/scripts/package.mjs +0 -270
- package/scripts/sync-i18n.mjs +0 -117
package/LICENSE
CHANGED
|
@@ -1,21 +1,5 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
-
in the Software without restriction, including without limitation the rights
|
|
8
|
-
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
-
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
-
furnished to do so, subject to the following conditions:
|
|
11
|
-
|
|
12
|
-
The above copyright notice and this permission notice shall be included in all
|
|
13
|
-
copies or substantial portions of the Software.
|
|
14
|
-
|
|
15
|
-
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
-
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
-
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
-
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
-
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
-
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
-
SOFTWARE.
|
|
1
|
+
Copyright (c) 2026 Synthetic. All rights reserved.
|
|
2
|
+
|
|
3
|
+
This package contains only a small launcher. The Synthetic MCP software it starts is NOT part of this package: it is downloaded from synthetic.com.ar
|
|
4
|
+
and can only be used with a valid Synthetic license (https://synthetic.com.ar). Using the launcher does not grant any right to the downloaded software
|
|
5
|
+
beyond what your license gives you.
|
package/README.md
CHANGED
|
@@ -1,242 +1,10 @@
|
|
|
1
|
-
#
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
[
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
## What it does
|
|
12
|
-
|
|
13
|
-
```
|
|
14
|
-
You: "Apply a cinematic look to all clips on V1, ducking the music
|
|
15
|
-
when there's voice, and export to YouTube 1080p."
|
|
16
|
-
|
|
17
|
-
Claude: ✓ Applied Lumetri (-15K temperature, +10 contrast) to 4 clips
|
|
18
|
-
✓ Added voiceover ducking on A2 (-12dB during A1 voice)
|
|
19
|
-
✓ Queued H.264 1080p export to ~/Videos/final.mp4
|
|
20
|
-
```
|
|
21
|
-
|
|
22
|
-
437 tools exposed via MCP to drive Premiere Pro 2026 from any LLM agent.
|
|
23
|
-
Tested in runtime against PP 2026.2.2 on Spanish-localized Windows install.
|
|
24
|
-
|
|
25
|
-
---
|
|
26
|
-
|
|
27
|
-
## Highlights
|
|
28
|
-
|
|
29
|
-
- **Locale-resilient**: works on Premiere Pro in Spanish, German, French, etc.
|
|
30
|
-
(most competitors hardcode English component names and silently fail)
|
|
31
|
-
- **Honest errors**: when a Premiere host API genuinely doesn't expose
|
|
32
|
-
something (PP 2026 has known limitations), you get a clear error with
|
|
33
|
-
the recommended workaround — not a silent no-op
|
|
34
|
-
- **Battle-tested**: 137 tools validated in live runtime against PP 2026 with
|
|
35
|
-
detailed bug fixes (see [CHANGELOG.md](CHANGELOG.md))
|
|
36
|
-
- **AI-first**: built for LLM-driven workflows. Pair it with Whisper for
|
|
37
|
-
speech-to-text, ComfyUI for thumbnails, FFmpeg for analysis — chain MCPs
|
|
38
|
-
|
|
39
|
-
---
|
|
40
|
-
|
|
41
|
-
## Quick start
|
|
42
|
-
|
|
43
|
-
### 1. Install the CEP plugin
|
|
44
|
-
|
|
45
|
-
Copy `cep-plugin/` to your Adobe CEP extensions folder:
|
|
46
|
-
|
|
47
|
-
- **Windows**: `%APPDATA%\Adobe\CEP\extensions\MCPBridgeCEP\`
|
|
48
|
-
- **macOS**: `~/Library/Application Support/Adobe/CEP/extensions/MCPBridgeCEP/`
|
|
49
|
-
|
|
50
|
-
Enable CEP debugging:
|
|
51
|
-
```powershell
|
|
52
|
-
# Windows
|
|
53
|
-
reg add HKCU\Software\Adobe\CSXS.11 /v PlayerDebugMode /t REG_SZ /d 1 /f
|
|
54
|
-
```
|
|
55
|
-
|
|
56
|
-
### 2. Build the MCP server
|
|
57
|
-
|
|
58
|
-
```bash
|
|
59
|
-
cd premiere-pro-mcp
|
|
60
|
-
npm install
|
|
61
|
-
npm run build
|
|
62
|
-
```
|
|
63
|
-
|
|
64
|
-
### 3. Register with Claude Desktop
|
|
65
|
-
|
|
66
|
-
Add to `%APPDATA%\Claude\claude_desktop_config.json`:
|
|
67
|
-
|
|
68
|
-
```json
|
|
69
|
-
{
|
|
70
|
-
"mcpServers": {
|
|
71
|
-
"premiere-pro": {
|
|
72
|
-
"command": "node",
|
|
73
|
-
"args": ["C:/path/to/premiere-pro-mcp/dist/index.js"]
|
|
74
|
-
}
|
|
75
|
-
}
|
|
76
|
-
}
|
|
77
|
-
```
|
|
78
|
-
|
|
79
|
-
### 4. Open Premiere Pro
|
|
80
|
-
|
|
81
|
-
- Launch Premiere Pro 2026
|
|
82
|
-
- `Window > Extensions > MCPBridgeCEP` (the bridge panel)
|
|
83
|
-
- Click "Start Bridge"
|
|
84
|
-
|
|
85
|
-
### 5. Talk to Claude
|
|
86
|
-
|
|
87
|
-
```
|
|
88
|
-
"Show me the active sequence structure."
|
|
89
|
-
"Add a 1-second fade-in to the audio clip on A2."
|
|
90
|
-
"Apply Cross Dissolve at every cut on V1, 0.5 seconds each."
|
|
91
|
-
```
|
|
92
|
-
|
|
93
|
-
---
|
|
94
|
-
|
|
95
|
-
## What works (validated runtime, PP 2026 es-ES)
|
|
96
|
-
|
|
97
|
-
### Project & Inspection
|
|
98
|
-
- Full project / sequence / clip overviews
|
|
99
|
-
- Bins, markers, metadata (XMP), color labels
|
|
100
|
-
- Effect properties with all values, keyframes, source media details
|
|
101
|
-
- Find/search project items, list sequences
|
|
102
|
-
|
|
103
|
-
### Timeline editing
|
|
104
|
-
- Add/remove/move/duplicate clips, split, trim
|
|
105
|
-
- Set in/out points, playhead, work area
|
|
106
|
-
- Selection by name/range/color, invert, deselect
|
|
107
|
-
- Enable/disable clips, link/unlink
|
|
108
|
-
|
|
109
|
-
### Transform & Motion
|
|
110
|
-
- Position, scale, rotation, opacity (locale-resilient)
|
|
111
|
-
- Anchor point, blend mode
|
|
112
|
-
- Position/scale keyframes via `add_keyframe`
|
|
113
|
-
|
|
114
|
-
### Color
|
|
115
|
-
- Lumetri full parameter control: exposure, contrast, highlights/shadows,
|
|
116
|
-
whites/blacks, temperature/tint, saturation, vibrance, sharpen, vignette,
|
|
117
|
-
faded film
|
|
118
|
-
- LUTs apply
|
|
119
|
-
- Copy/paste color grade across clips
|
|
120
|
-
- ⚠️ See limitations: applying Lumetri *for the first time* requires manual UI
|
|
121
|
-
|
|
122
|
-
### Audio
|
|
123
|
-
- Per-clip volume, fade in/out (locale-resilient)
|
|
124
|
-
- Volume/panning keyframes
|
|
125
|
-
- Audio FX pipeline: Compressor, EQ, De-Esser, De-Hum, De-Reverb, Limiter,
|
|
126
|
-
Noise Reduction
|
|
127
|
-
- Voiceover ducking
|
|
128
|
-
- Normalize, detect clipping
|
|
129
|
-
|
|
130
|
-
### Effects & Transitions
|
|
131
|
-
- 60+ video effects (Gaussian/Directional Blur, Sharpen, Warp Stabilizer,
|
|
132
|
-
Noise Reduction, Mirror, Spherize, Corner Pin, Lens Distortion, etc.)
|
|
133
|
-
- Transitions with locale-aware name lookup (Cross Dissolve works on any
|
|
134
|
-
language install)
|
|
135
|
-
- Batch apply across cuts
|
|
136
|
-
|
|
137
|
-
### Captions
|
|
138
|
-
- Import SRT files as caption tracks
|
|
139
|
-
- Pipeline integration: Whisper-transcribe → SRT → MCP creates captions
|
|
140
|
-
|
|
141
|
-
### Export
|
|
142
|
-
- Single sequence + batch export via Adobe Media Encoder
|
|
143
|
-
- Match Source presets, YouTube/Vimeo/Twitter/Facebook presets
|
|
144
|
-
- Encode arbitrary files via AME
|
|
145
|
-
- AAF, OMF, FCPXML export
|
|
146
|
-
|
|
147
|
-
### Multicam
|
|
148
|
-
- Create multicam sequences, switch angles, flatten
|
|
149
|
-
|
|
150
|
-
### Markers
|
|
151
|
-
- Add/update/delete on sequence or clip
|
|
152
|
-
- Color labels, comments, in/out range
|
|
153
|
-
- Import/export CSV
|
|
154
|
-
|
|
155
|
-
---
|
|
156
|
-
|
|
157
|
-
## Known limitations (PP 2026 host)
|
|
158
|
-
|
|
159
|
-
These are not bugs in this MCP — they're verified limitations of Premiere Pro
|
|
160
|
-
2026's ExtendScript/QE-DOM surface. Each tool returns a clear actionable error
|
|
161
|
-
with the recommended workaround.
|
|
162
|
-
|
|
163
|
-
| Feature | Status | Workaround |
|
|
164
|
-
|---------|--------|------------|
|
|
165
|
-
| `capture_frame` programmatic | ❌ `qeSeq.exportFramePNG` reports success but never writes file | UI: File > Export > Media > Single Frame |
|
|
166
|
-
| `set_track_volume` | ❌ Audio track DOM no longer exposes `.components` or `.volume`; QE has no `setVolume` | Use `add_audio_keyframes` per-clip, or Audio Track Mixer |
|
|
167
|
-
| `speed_change` programmatic | ❌ `qeClip.setSpeed` signature changed in PP 2026 (rejects all known forms) | UI: Clip > Speed/Duration, or change duration with `trim_clip` |
|
|
168
|
-
| Apply Lumetri for the first time | ❌ `addVideoEffect` reports success but doesn't add component | Apply Lumetri manually once; afterwards all 28 setters work perfectly |
|
|
169
|
-
| LUFS integrated measurement | ❌ Not scriptable | Export and measure with ffmpeg-loudnorm |
|
|
170
|
-
| Native PP Speech-to-Text | ❌ Adobe AI STT not exposed | Use Whisper + `create_caption_track` (works great) |
|
|
171
|
-
| Adobe Libraries MOGRT | ❌ Adobe Libraries not scriptable | Use local `.mogrt` files via `import_mogrt` |
|
|
172
|
-
| Dynamic Link with AE | ❌ `import_ae_comps` not implemented | Render from AE and import as video |
|
|
173
|
-
| Async export completion | ⚠️ AME runs async, no callback | Poll `get_render_queue_status` |
|
|
174
|
-
|
|
175
|
-
---
|
|
176
|
-
|
|
177
|
-
## Architecture
|
|
178
|
-
|
|
179
|
-
```
|
|
180
|
-
┌─────────────┐ ┌──────────────┐ ┌─────────────┐
|
|
181
|
-
│ Claude │ │ Node.js │ │ Premiere │
|
|
182
|
-
│ (or LLM) │◄───────►│ MCP server │◄───────►│ Pro CEP │
|
|
183
|
-
└─────────────┘ stdio └──────────────┘ files │ plugin │
|
|
184
|
-
│ (panel) │
|
|
185
|
-
└─────────────┘
|
|
186
|
-
│
|
|
187
|
-
▼
|
|
188
|
-
┌──────────────┐
|
|
189
|
-
│ ExtendScript │
|
|
190
|
-
│ DOM + QE │
|
|
191
|
-
└──────────────┘
|
|
192
|
-
```
|
|
193
|
-
|
|
194
|
-
The bridge automatically prepends locale-resilient helpers to every script:
|
|
195
|
-
|
|
196
|
-
```javascript
|
|
197
|
-
__findIntrinsic(clip, "motion" | "opacity" | "volume" | "lumetri" | "timeRemap")
|
|
198
|
-
// tries matchName ("AE.ADBE Motion") first — locale-INDEPENDENT —
|
|
199
|
-
// then localized displayName ("Movimiento", "Bewegung", "Mouvement", etc.)
|
|
200
|
-
|
|
201
|
-
__findProp(component, ["Position", "Posición", "Position", "Position"])
|
|
202
|
-
// also descends one level into nested groups (needed for Lumetri's
|
|
203
|
-
// grouped parameters like Exposure inside Basic Correction)
|
|
204
|
-
|
|
205
|
-
__readMaybe(obj, "isMuted", false)
|
|
206
|
-
// reads members that are property in some PP versions, method in others
|
|
207
|
-
|
|
208
|
-
__findTransition(name, "video")
|
|
209
|
-
// resolves transition names across locales:
|
|
210
|
-
// "Cross Dissolve" matches "Disolvencia cruzada" / "Fondu enchaîné"
|
|
211
|
-
```
|
|
212
|
-
|
|
213
|
-
---
|
|
214
|
-
|
|
215
|
-
## Development
|
|
216
|
-
|
|
217
|
-
```bash
|
|
218
|
-
npm run dev # Watch mode
|
|
219
|
-
npm run build # Build dist/
|
|
220
|
-
npx tsc --noEmit # Type-check only
|
|
221
|
-
```
|
|
222
|
-
|
|
223
|
-
When adding a tool, prefer:
|
|
224
|
-
- `__findIntrinsic` / `__findComponent` over hardcoded `displayName === "Motion"`
|
|
225
|
-
- `__readMaybe` for any `isSomething()` / `isSomething` property
|
|
226
|
-
- Pass `.ticks` strings (not Time objects) to `insertClip`/`setInPoint`/etc.
|
|
227
|
-
|
|
228
|
-
---
|
|
229
|
-
|
|
230
|
-
## Credits
|
|
231
|
-
|
|
232
|
-
Built on top of work from
|
|
233
|
-
[`AdobePremiereProMCP`](https://github.com/bdenney99/AdobePremiereProMCP)
|
|
234
|
-
with extensive fixes for PP 2026 compatibility, locale resilience, and
|
|
235
|
-
runtime-validated behavior. See [CHANGELOG.md](CHANGELOG.md) for the full
|
|
236
|
-
fix log.
|
|
237
|
-
|
|
238
|
-
---
|
|
239
|
-
|
|
240
|
-
## License
|
|
241
|
-
|
|
242
|
-
MIT
|
|
1
|
+
# @synthetic-ai/premiere-mcp
|
|
2
|
+
|
|
3
|
+
Synthetic MCP launcher. Set your license in your MCP client's configuration and keep using `npx -y @synthetic-ai/premiere-mcp`:
|
|
4
|
+
|
|
5
|
+
```json
|
|
6
|
+
{ "mcpServers": { "premiere-mcp": { "command": "npx", "args": ["-y", "@synthetic-ai/premiere-mcp"], "env": { "PREMIERE_PRO_MCP_LICENSE": "<your license key>" } } } }
|
|
7
|
+
```
|
|
8
|
+
|
|
9
|
+
On start it checks your license with synthetic.com.ar, downloads the current server (verified with a sha256) and runs it. Without a connection it runs the last
|
|
10
|
+
downloaded copy. Your key is in https://synthetic.com.ar/dashboard.
|
package/launcher.mjs
ADDED
|
@@ -0,0 +1,111 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
// Synthetic MCP launcher — ZERO dependencies (Node >= 18). This is the only thing that goes on npm; the real server is downloaded with the
|
|
3
|
+
// customer's license from synthetic.com.ar, verified (sha256), cached under ~/.synthetic/mcp/<product>/ and run. See docs/MCP_DISTRIBUTION_PLAN.md.
|
|
4
|
+
//
|
|
5
|
+
// 1. reads the license from the product's environment variable (the same one the customer already has in their MCP config)
|
|
6
|
+
// 2. asks POST /api/v1/mcp/bundle for the current version; the server validates the license and registers the device
|
|
7
|
+
// 3. downloads the bundle (short-lived signed URL), checks its sha256, unpacks it atomically
|
|
8
|
+
// 4. runs `node server.mjs` with the same stdio, so the MCP client talks to the real server
|
|
9
|
+
// Offline / server down: runs the last cached version. Invalid or revoked license: it does NOT run, and says why.
|
|
10
|
+
import fs from "node:fs";
|
|
11
|
+
import os from "node:os";
|
|
12
|
+
import path from "node:path";
|
|
13
|
+
import zlib from "node:zlib";
|
|
14
|
+
import crypto from "node:crypto";
|
|
15
|
+
import { spawn } from "node:child_process";
|
|
16
|
+
import { fileURLToPath } from "node:url";
|
|
17
|
+
|
|
18
|
+
export const DEFAULTS = {
|
|
19
|
+
product: "premiere-mcp", // set per package by the publisher
|
|
20
|
+
licenseEnv: "PREMIERE_PRO_MCP_LICENSE",
|
|
21
|
+
api: process.env.SYNTHETIC_API_URL || "https://synthetic.com.ar", // the override is for tests against a local/dev site
|
|
22
|
+
};
|
|
23
|
+
|
|
24
|
+
const say = (m) => process.stderr.write(`[synthetic] ${m}\n`);
|
|
25
|
+
|
|
26
|
+
/** ~/.synthetic/device-id: the SAME file the servers and panels use, so launcher + server + panel count as one device. */
|
|
27
|
+
function deviceId(home) {
|
|
28
|
+
const dir = path.join(home, ".synthetic"), file = path.join(dir, "device-id");
|
|
29
|
+
try { const v = fs.readFileSync(file, "utf8").trim(); if (v) return v; } catch { /* first run */ }
|
|
30
|
+
const id = crypto.randomUUID();
|
|
31
|
+
try { fs.mkdirSync(dir, { recursive: true }); fs.writeFileSync(file, id, "utf8"); } catch { /* read-only home: the id just won't persist */ }
|
|
32
|
+
return id;
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
/** Unpacks a container {files:{path:{enc,data}}} into dir. Refuses any path that would escape it. */
|
|
36
|
+
export function unpackContainer(buf, dir) {
|
|
37
|
+
const json = JSON.parse(zlib.gunzipSync(buf).toString("utf8"));
|
|
38
|
+
const root = path.resolve(dir);
|
|
39
|
+
for (const [rel, f] of Object.entries(json.files)) {
|
|
40
|
+
const target = path.resolve(root, rel);
|
|
41
|
+
if (target !== root && !target.startsWith(root + path.sep)) throw new Error(`ruta no permitida en el paquete: ${rel}`);
|
|
42
|
+
fs.mkdirSync(path.dirname(target), { recursive: true });
|
|
43
|
+
fs.writeFileSync(target, f.enc === "b64" ? Buffer.from(f.data, "base64") : f.data, f.enc === "b64" ? undefined : "utf8");
|
|
44
|
+
}
|
|
45
|
+
return json;
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
const readJson = (p) => { try { return JSON.parse(fs.readFileSync(p, "utf8")); } catch { return null; } };
|
|
49
|
+
/** The file to run inside an unpacked bundle: launch.json says (AE keeps dist/server.mjs); older bundles have server.mjs at the root. */
|
|
50
|
+
export const entryOf = (dir) => readJson(path.join(dir, "launch.json"))?.entry || "server.mjs";
|
|
51
|
+
|
|
52
|
+
/** Makes sure a runnable server is in the cache and returns its folder. Throws {kind:"license"|"network"|"other"}. */
|
|
53
|
+
export async function ensureBundle(opts = {}) {
|
|
54
|
+
const o = { ...DEFAULTS, home: os.homedir(), env: process.env, fetchImpl: globalThis.fetch, ...opts };
|
|
55
|
+
const license = (o.env[o.licenseEnv] ?? "").trim();
|
|
56
|
+
if (!license) throw Object.assign(new Error(`Falta la licencia: configurá ${o.licenseEnv} en tu cliente MCP (tu clave está en synthetic.com.ar/dashboard).`), { kind: "license" });
|
|
57
|
+
const cacheDir = path.join(o.home, ".synthetic", "mcp", o.product);
|
|
58
|
+
const current = readJson(path.join(cacheDir, "current.json")); // {version, sha256}
|
|
59
|
+
const have = current && fs.existsSync(path.join(cacheDir, current.version, entryOf(path.join(cacheDir, current.version)))) ? current : null;
|
|
60
|
+
|
|
61
|
+
let answer;
|
|
62
|
+
try {
|
|
63
|
+
const res = await o.fetchImpl(`${o.api}/api/v1/mcp/bundle`, {
|
|
64
|
+
method: "POST", headers: { "Content-Type": "application/json" },
|
|
65
|
+
body: JSON.stringify({ product: o.product, licenseKey: license, machineId: deviceId(o.home), deviceLabel: `${os.hostname()} (${process.platform})`, have: have?.version ?? null }),
|
|
66
|
+
signal: AbortSignal.timeout(15_000),
|
|
67
|
+
});
|
|
68
|
+
const body = await res.json().catch(() => ({}));
|
|
69
|
+
if (res.status === 401 || res.status === 403) throw Object.assign(new Error(body.error || "Licencia no válida."), { kind: "license" });
|
|
70
|
+
if (!res.ok) throw Object.assign(new Error(`El servidor respondió ${res.status}`), { kind: "network" });
|
|
71
|
+
answer = body;
|
|
72
|
+
} catch (e) {
|
|
73
|
+
if (e.kind === "license") throw e;
|
|
74
|
+
if (have) { say(`Sin conexión con synthetic.com.ar: uso la versión ${have.version} guardada.`); return { dir: path.join(cacheDir, have.version), version: have.version, offline: true }; }
|
|
75
|
+
throw Object.assign(new Error(`No pude conectar con synthetic.com.ar para descargar el servidor (${e.message}).`), { kind: "network" });
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
if (answer.upToDate && have) return { dir: path.join(cacheDir, have.version), version: have.version };
|
|
79
|
+
if (!answer.url || !answer.sha256 || !answer.version) throw Object.assign(new Error("Respuesta inesperada del servidor."), { kind: "other" });
|
|
80
|
+
|
|
81
|
+
const dl = await o.fetchImpl(answer.url, { signal: AbortSignal.timeout(60_000) });
|
|
82
|
+
if (!dl.ok) throw Object.assign(new Error(`No pude descargar el servidor (${dl.status}).`), { kind: "network" });
|
|
83
|
+
const buf = Buffer.from(await dl.arrayBuffer());
|
|
84
|
+
const got = crypto.createHash("sha256").update(buf).digest("hex");
|
|
85
|
+
if (got !== answer.sha256) throw Object.assign(new Error("El archivo descargado no coincide con su firma (sha256): no se ejecuta."), { kind: "other" });
|
|
86
|
+
|
|
87
|
+
const finalDir = path.join(cacheDir, answer.version), tmp = `${finalDir}.tmp-${process.pid}`;
|
|
88
|
+
fs.rmSync(tmp, { recursive: true, force: true });
|
|
89
|
+
fs.mkdirSync(tmp, { recursive: true });
|
|
90
|
+
unpackContainer(buf, tmp);
|
|
91
|
+
fs.rmSync(finalDir, { recursive: true, force: true });
|
|
92
|
+
fs.renameSync(tmp, finalDir);
|
|
93
|
+
fs.writeFileSync(path.join(cacheDir, "current.json"), JSON.stringify({ version: answer.version, sha256: answer.sha256 }));
|
|
94
|
+
for (const d of fs.readdirSync(cacheDir)) { // keep this version and the previous one only
|
|
95
|
+
if (d !== answer.version && d !== have?.version && fs.statSync(path.join(cacheDir, d)).isDirectory()) fs.rmSync(path.join(cacheDir, d), { recursive: true, force: true });
|
|
96
|
+
}
|
|
97
|
+
return { dir: finalDir, version: answer.version, downloaded: true };
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
export async function main(opts = {}) {
|
|
101
|
+
let r;
|
|
102
|
+
try { r = await ensureBundle(opts); }
|
|
103
|
+
// No process.exit() here: on Windows it can abort with a native crash code while the download's socket is still closing.
|
|
104
|
+
// Setting exitCode lets Node leave on its own once the connection is released.
|
|
105
|
+
catch (e) { say(e.message); process.exitCode = e.kind === "license" ? 2 : 1; return; }
|
|
106
|
+
const child = spawn(process.execPath, [path.join(r.dir, entryOf(r.dir)), ...process.argv.slice(2)], { stdio: "inherit", env: process.env });
|
|
107
|
+
for (const sig of ["SIGINT", "SIGTERM"]) process.on(sig, () => child.kill(sig));
|
|
108
|
+
child.on("exit", (code, signal) => process.exit(code ?? (signal ? 1 : 0)));
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
if (process.argv[1] && path.resolve(process.argv[1]) === fileURLToPath(import.meta.url)) await main();
|
package/package.json
CHANGED
|
@@ -1,68 +1,24 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@synthetic-ai/premiere-mcp",
|
|
3
|
-
"version": "
|
|
4
|
-
"description": "
|
|
5
|
-
"main": "dist/index.js",
|
|
3
|
+
"version": "3.0.0",
|
|
4
|
+
"description": "Launcher for the Synthetic premiere-mcp MCP server. Requires a license from https://synthetic.com.ar",
|
|
6
5
|
"type": "module",
|
|
7
6
|
"bin": {
|
|
8
|
-
"premiere-mcp": "
|
|
7
|
+
"premiere-mcp": "launcher.mjs"
|
|
9
8
|
},
|
|
10
9
|
"files": [
|
|
11
|
-
"
|
|
12
|
-
"dist/**/*.d.ts",
|
|
13
|
-
"i18n",
|
|
14
|
-
"cep-plugin",
|
|
15
|
-
"scripts",
|
|
10
|
+
"launcher.mjs",
|
|
16
11
|
"README.md",
|
|
17
|
-
"LICENSE"
|
|
18
|
-
"CHANGELOG.md"
|
|
12
|
+
"LICENSE"
|
|
19
13
|
],
|
|
20
|
-
"
|
|
21
|
-
"
|
|
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/SyntheticArtOk/premiere-pro-mcp.git"
|
|
14
|
+
"engines": {
|
|
15
|
+
"node": ">=18"
|
|
34
16
|
},
|
|
17
|
+
"license": "SEE LICENSE IN LICENSE",
|
|
35
18
|
"homepage": "https://synthetic.com.ar",
|
|
36
|
-
"bugs": {
|
|
37
|
-
"url": "https://synthetic.com.ar"
|
|
38
|
-
},
|
|
39
|
-
"author": "Synthetic",
|
|
40
19
|
"keywords": [
|
|
41
20
|
"mcp",
|
|
42
|
-
"model-context-protocol",
|
|
43
21
|
"adobe",
|
|
44
|
-
"
|
|
45
|
-
|
|
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
|
-
}
|
|
22
|
+
"synthetic"
|
|
23
|
+
]
|
|
68
24
|
}
|
package/CHANGELOG.md
DELETED
|
@@ -1,180 +0,0 @@
|
|
|
1
|
-
# Changelog
|
|
2
|
-
|
|
3
|
-
## [v2.3.4] — The "Reload panel" button no longer reloads in place
|
|
4
|
-
|
|
5
|
-
v2.3.3's `stopBridge()`-before-`location.reload()` fix wasn't enough —
|
|
6
|
-
confirmed live, twice, on a clean install + full Premiere Pro restart, that
|
|
7
|
-
`location.reload()` doesn't reliably re-run `init()` in this CEP host. Root
|
|
8
|
-
cause found: each reload leaks the old page's `CEPHtmlEngine` subprocesses
|
|
9
|
-
instead of terminating them — 37 orphaned processes were found accumulated
|
|
10
|
-
from repeated testing today, versus ~6 for one cleanly opened panel. Rather
|
|
11
|
-
than keep guessing at ways to make an in-place reload work, the ⟳ button no
|
|
12
|
-
longer calls `location.reload()` at all — it stops the bridge and tells the
|
|
13
|
-
user to restart Premiere Pro, the one path confirmed to always leave the
|
|
14
|
-
panel correct.
|
|
15
|
-
|
|
16
|
-
## [v2.3.3] — Fixed the "Reload panel" button
|
|
17
|
-
|
|
18
|
-
It called a bare `location.reload()`, which could leave the old poll
|
|
19
|
-
interval running underneath the fresh page and race with `init()`
|
|
20
|
-
re-running — the panel could get stuck showing the raw HTML placeholder
|
|
21
|
-
badge, an empty temp dir field, and a spurious "Please set a temp
|
|
22
|
-
directory" error, all while the actually-installed files were fine. Now
|
|
23
|
-
stops the bridge (clearing the interval) before reloading, same fix class
|
|
24
|
-
as Photoshop MCP's `wss.close()`-before-reload.
|
|
25
|
-
|
|
26
|
-
## [v2.3.2] — Reverted the license.json USER_DATA change
|
|
27
|
-
|
|
28
|
-
v2.3.1 (panel side, unreleased separately from the npm tag) moved
|
|
29
|
-
`getLicensePath()` from `SystemPath.EXTENSION` to `SystemPath.USER_DATA` to
|
|
30
|
-
fix license saves failing with EPERM under a system-wide install. Live
|
|
31
|
-
testing found a deeper issue: the CEP panel's embedded Node
|
|
32
|
-
`fs.writeFileSync` can report success without the write actually landing on
|
|
33
|
-
disk on this Premiere Pro version — confirmed by writing the target file
|
|
34
|
-
directly and watching Premiere's own "successful" save leave it untouched.
|
|
35
|
-
Reverted back to `SystemPath.EXTENSION` (pre-fix behavior) until this CEP
|
|
36
|
-
Node.js reliability issue is understood; the original EPERM bug is still
|
|
37
|
-
open, to be investigated outside production.
|
|
38
|
-
|
|
39
|
-
## [v2.3.1] — macOS example paths in tool descriptions
|
|
40
|
-
|
|
41
|
-
`create_sequence`'s description and example calls only showed Windows
|
|
42
|
-
`C:\Program Files\...` preset paths, even though the actual runtime preset
|
|
43
|
-
lookup already searched macOS `/Applications/...` locations too — now the
|
|
44
|
-
description and both examples (Windows + macOS) match what the code
|
|
45
|
-
actually does, so the LLM doesn't suggest a Windows-only path to a Mac
|
|
46
|
-
user. No runtime/behavior change.
|
|
47
|
-
|
|
48
|
-
## [v2.2.0] — `--doctor` diagnostic command
|
|
49
|
-
|
|
50
|
-
`premiere-pro-mcp --doctor` runs a standalone setup check — no MCP client or
|
|
51
|
-
Premiere Pro needs to be running: Node version, Premiere Pro install
|
|
52
|
-
detected on disk, license key present + live-validated against
|
|
53
|
-
synthetic.com.ar, and the CEP bridge temp directory is writable. Prints a
|
|
54
|
-
pass/warn/fail summary and exits 1 if anything failed, so it's scriptable.
|
|
55
|
-
Fixed a real crash found while building this: forcing `process.exit()`
|
|
56
|
-
right after the live license check's `fetch()` call could crash with a
|
|
57
|
-
libuv assertion on Windows (`UV_HANDLE_CLOSING`, src/win/async.c) — now
|
|
58
|
-
sets `process.exitCode` and lets the event loop drain naturally instead.
|
|
59
|
-
|
|
60
|
-
## [v2.1.0] — CRITICAL: correct the version line, ship everything since 2.0.0
|
|
61
|
-
|
|
62
|
-
`@synthetic-ai/premiere-mcp@2.0.0` (published 2026-06-10, the npm rename
|
|
63
|
-
from unscoped `premiere-pro-mcp`) has been the only version ever actually
|
|
64
|
-
published to the registry — `npm view` confirms `dist-tags.latest` and the
|
|
65
|
-
full `versions` list both show only `2.0.0`, right up until this release.
|
|
66
|
-
Six commits after the rename (v1.1.2 through v1.1.8, including v1.1.7's
|
|
67
|
-
**server-side license enforcement**) bumped `package.json`'s version
|
|
68
|
-
*backward* into a stale pre-rename 1.1.x line instead of continuing from
|
|
69
|
-
2.0.0, and were committed/tested but never `npm publish`ed under that
|
|
70
|
-
wrong version number. Net effect: every customer running
|
|
71
|
-
`npx @synthetic-ai/premiere-mcp` has been getting the unmodified 2.0.0
|
|
72
|
-
tarball — with **zero license checking on any of the 437 tools** — for
|
|
73
|
-
over three months, discovered 2026-09-23 while shipping the macOS preset
|
|
74
|
-
fix below. This release corrects the version line (2.0.0 → 2.1.0, a real
|
|
75
|
-
semver increase) and ships every accumulated fix at once:
|
|
76
|
-
- License enforcement (was v1.1.7): every tool except `ping` /
|
|
77
|
-
`get_version_info` now validates `PREMIERE_PRO_MCP_LICENSE`.
|
|
78
|
-
- In-panel auto-update + local license storage (was v1.1.2).
|
|
79
|
-
- ExtendScript obfuscation breaking `evalFile()` (was v1.1.4).
|
|
80
|
-
- Bridge could wedge forever after a single failed command read (was v1.1.5).
|
|
81
|
-
- macOS default sequence-preset paths (was v1.1.8, see below).
|
|
82
|
-
|
|
83
|
-
## [v1.1.8] — macOS default preset paths (superseded by v2.1.0, never actually reached "latest" — see above)
|
|
84
|
-
|
|
85
|
-
`create_sequence`, `create_sequence_from_clip`, and `get_default_sequence_presets`
|
|
86
|
-
only ever probed Windows install paths for the default `.sqpreset` (and, for
|
|
87
|
-
`create_sequence`, only a single hardcoded PP 2026 path with no probing at
|
|
88
|
-
all). All three now check both Windows and macOS locations across PP
|
|
89
|
-
2026/2025/2024/CC 2023, matching the pattern `export_sequence` already used
|
|
90
|
-
for AME presets. When nothing is found, the tools return a clear error
|
|
91
|
-
asking for an explicit `preset_path` instead of silently using a
|
|
92
|
-
definitely-wrong fallback. Found via a site-wide macOS-compatibility audit
|
|
93
|
-
of every Synthetic product (2026-09-23) — this was the one confirmed gap in
|
|
94
|
-
an otherwise genuinely cross-platform architecture (no launch step to
|
|
95
|
-
break, unlike ae-mcp). Unverified on real macOS hardware — no Mac available
|
|
96
|
-
to test against yet.
|
|
97
|
-
|
|
98
|
-
## [v1.1.7] — License enforcement
|
|
99
|
-
|
|
100
|
-
The MCP server itself (all 437 tools) never actually validated
|
|
101
|
-
`PREMIERE_PRO_MCP_LICENSE` — the CEP panel had a license field for its own
|
|
102
|
-
auto-update, but the server side was wide open. Added the same
|
|
103
|
-
`checkLicense()` gate ae-mcp and photoshop-mcp already have: every tool
|
|
104
|
-
except `ping` / `get_version_info` now requires a valid license, validated
|
|
105
|
-
against `https://synthetic.com.ar/api/v1/license/validate` and cached for an
|
|
106
|
-
hour.
|
|
107
|
-
|
|
108
|
-
---
|
|
109
|
-
|
|
110
|
-
All notable changes to this MCP server. Every fix below was discovered via
|
|
111
|
-
**static audit + live runtime testing against Premiere Pro 2026.2.2 on
|
|
112
|
-
Spanish-localized Windows**.
|
|
113
|
-
|
|
114
|
-
The audit started at **31/100 sellability score** (22% green tools) and
|
|
115
|
-
finished at **~78/100** (~75% green) after the rounds below.
|
|
116
|
-
|
|
117
|
-
---
|
|
118
|
-
|
|
119
|
-
## [v1.2.0] — PP 2026 compatibility + locale resilience
|
|
120
|
-
|
|
121
|
-
### Round 6 — Live runtime validation
|
|
122
|
-
- `6f20892` capture_frame: honest error for PP 2026 host limitation
|
|
123
|
-
- `8152021` bridge: sanitize NaN and Infinity to null
|
|
124
|
-
- `a74ce33` Round 5: 8 more fixes from full smoke test (137 tools tested)
|
|
125
|
-
- `45fdaba` track-targeting: locale-resilient set_clip_position/scale/rotation
|
|
126
|
-
- `f9589cb` premiere.jsx: locale-resilient fadeIn/fadeOut/crossFadeClips
|
|
127
|
-
- `29e941d` graceful fallbacks for setSpeed signature + track volume
|
|
128
|
-
- `0533162` Live-test fixes: setSpeed signature, locale prop names, audio clip volume
|
|
129
|
-
- `084ef49` Live-test fixes: set_clip_opacity locale, color_correct Lumetri name
|
|
130
|
-
|
|
131
|
-
### Round 5 — Bridge JSON sanitization
|
|
132
|
-
- `f3d83d7` Fix bridge JSON: ExtendScript ignores replacer; sanitize tree pre-stringify
|
|
133
|
-
|
|
134
|
-
### Round 4 — premiere.jsx loading (single highest-impact fix)
|
|
135
|
-
- `366f325` Fix premiere.jsx SyntaxError that broke ALL JSX helpers
|
|
136
|
-
- **1-char fix, ~30+ tools unblocked**
|
|
137
|
-
- `premiere.jsx` (22k lines) had `package:` as bare property name at line
|
|
138
|
-
22006. ExtendScript is strict ES3 where `package` is reserved → entire
|
|
139
|
-
file fails to parse → every JSX-helper-backed tool returns
|
|
140
|
-
`ReferenceError: <fn> is not a function`. Quoting fixes everything.
|
|
141
|
-
- `b12a0d8` Round 4: bridge JSON-parse failure + locale-resilient transition lookup
|
|
142
|
-
|
|
143
|
-
### Round 3 — Concrete code bugs from re-audit
|
|
144
|
-
- `21bf821` Round 3 part 2: fix remaining 9 files
|
|
145
|
-
- `e4534d5` Round 3: fix 32 concrete code bugs from re-audit
|
|
146
|
-
- ticks/Time correctness (markers, source-monitor, scripting, clipboard, audio)
|
|
147
|
-
- property-vs-method (media.check_offline_media)
|
|
148
|
-
- QE-only methods routed correctly (timeline.move_clip/speed_change, transitions)
|
|
149
|
-
- missing `app.enableQE()` guards
|
|
150
|
-
- nested Lumetri prop lookup via `__findProp`
|
|
151
|
-
|
|
152
|
-
### Round 2 — Locale-resilient helpers
|
|
153
|
-
- `bdaebaa` Round 2: guard QE multicam enumeration and proxy detach
|
|
154
|
-
- `48d3648` Round 2 part 2: fix remaining 8 files
|
|
155
|
-
- `2b718b3` Round 2 part 1: locale-resilient helpers + fix 13 tool files
|
|
156
|
-
- Added `__findIntrinsic(clip, key)` with matchName-first lookup
|
|
157
|
-
- Added `__findComponent`, `__findProp`, `__readMaybe`, `__findTransition`
|
|
158
|
-
|
|
159
|
-
### Round 1 — Property-vs-method bugs
|
|
160
|
-
- `ffe6931` Fix 21 red tools: property-vs-method bugs, missing APIs, stub handlers
|
|
161
|
-
- `35ecbfa` Fix PP 2026 compatibility: sequence creation, tracks, audio, effects, export
|
|
162
|
-
|
|
163
|
-
---
|
|
164
|
-
|
|
165
|
-
## Validated tool inventory
|
|
166
|
-
|
|
167
|
-
### ✅ 66 tools confirmed working in runtime (PP 2026.2.2 es-ES)
|
|
168
|
-
Inspection, transform, audio/video FX, timeline editing, selection, markers,
|
|
169
|
-
sequence ops, project/bins, captions, source monitor, track management,
|
|
170
|
-
metadata, scripting, export. Full list in [README.md](README.md).
|
|
171
|
-
|
|
172
|
-
### ⚠️ Honest errors (PP 2026 host limitations, not bugs)
|
|
173
|
-
- `set_track_volume`, `speed_change`, `capture_frame`, Lumetri-when-not-applied
|
|
174
|
-
- All return clear errors with the recommended UI workaround
|
|
175
|
-
|
|
176
|
-
### Validated against
|
|
177
|
-
- Premiere Pro 2026.2.2 on Windows
|
|
178
|
-
- Spanish (es-ES) locale — names like "Opacidad", "Movimiento", "Escala",
|
|
179
|
-
"Posición", "Disolvencia cruzada" all handled
|
|
180
|
-
- 15-item test project with multi-track timeline, transitions, fades, Lumetri
|