premiere-pro-mcp 1.3.1 → 1.4.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.
Files changed (39) hide show
  1. package/CHANGELOG.md +17 -0
  2. package/README.md +121 -8
  3. package/artifacts/MCPBridgeCEP.zxp +0 -0
  4. package/cep-plugin/CSXS/manifest.xml +3 -3
  5. package/cep-plugin/index.html +18 -6
  6. package/cep-plugin/main.js +125 -1
  7. package/cep-plugin/styles.css +37 -1
  8. package/cep-plugin/updater.cjs +74 -0
  9. package/dist/advanced-feature-support.d.ts +140 -0
  10. package/dist/advanced-feature-support.js +157 -0
  11. package/dist/bridge/uxp-websocket-bridge.d.ts +61 -0
  12. package/dist/bridge/uxp-websocket-bridge.js +249 -0
  13. package/dist/index.js +24 -2
  14. package/dist/platform-capabilities.d.ts +32 -1
  15. package/dist/platform-capabilities.js +47 -2
  16. package/dist/security/capabilities.js +2 -2
  17. package/dist/server.d.ts +5 -1
  18. package/dist/server.js +13 -6
  19. package/dist/tool-capability-report.d.ts +55 -0
  20. package/dist/tool-capability-report.js +148 -0
  21. package/dist/tools/av-settings.d.ts +119 -0
  22. package/dist/tools/av-settings.js +210 -0
  23. package/dist/tools/export.d.ts +100 -0
  24. package/dist/tools/export.js +160 -2
  25. package/dist/tools/health.d.ts +206 -1
  26. package/dist/tools/health.js +49 -2
  27. package/dist/tools/recovery.d.ts +45 -0
  28. package/dist/tools/recovery.js +189 -0
  29. package/dist/tools/uxp.d.ts +71 -0
  30. package/dist/tools/uxp.js +53 -0
  31. package/package.json +5 -2
  32. package/scripts/build-claude-desktop.mjs +71 -0
  33. package/uxp-plugin/README.md +43 -2
  34. package/uxp-plugin/commands.cjs +163 -0
  35. package/uxp-plugin/index.cjs +327 -25
  36. package/uxp-plugin/index.html +7 -6
  37. package/uxp-plugin/manifest.json +1 -1
  38. package/uxp-plugin/protocol.cjs +82 -3
  39. package/uxp-plugin/transcript.cjs +95 -0
package/CHANGELOG.md CHANGED
@@ -6,6 +6,23 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/).
6
6
 
7
7
  ## [Unreleased]
8
8
 
9
+ ## [1.4.0] - 2026-07-26
10
+
11
+ ### Added
12
+
13
+ - Added in-panel connector update discovery and trusted downloads from GitHub Releases.
14
+ - Added authenticated MCP-to-UXP WebSocket transport, transcript and caption inspection, event-driven
15
+ state reporting, operation semantics, and supported video-transition workflows.
16
+ - Added recovery diagnostics, export verification, AV inspection, capability reporting, and
17
+ collaboration/AI feature eligibility discovery.
18
+ - Added installable Codex, Claude Code, and Claude Desktop distributions.
19
+
20
+ ### Changed
21
+
22
+ - Expanded the MCP surface to 278 tools and aligned documentation, plugin metadata, and distribution
23
+ manifests with the new release.
24
+ - Added automated signed CEP connector assets and Claude Desktop bundles to GitHub releases.
25
+
9
26
  ## [1.3.1] - 2026-07-25
10
27
 
11
28
  ### Fixed
package/README.md CHANGED
@@ -4,7 +4,7 @@
4
4
 
5
5
  **Give AI full control over Adobe Premiere Pro.**
6
6
 
7
- 269 tools across 29 modules, 3 resources, and 4 guided workflows.
7
+ 278 tools across 31 modules, 3 resources, and 4 guided workflows.
8
8
 
9
9
  [![License: MIT](https://img.shields.io/badge/License-MIT-blue.svg)](LICENSE)
10
10
  [![Node.js](https://img.shields.io/badge/Node.js-20.19%2B-green.svg)](https://nodejs.org)
@@ -25,7 +25,7 @@ An [MCP (Model Context Protocol)](https://modelcontextprotocol.io) server that l
25
25
  "Add the B-roll clips to V2, apply a cross dissolve between each, color correct them to match the A-roll, and export a 1080p ProRes."
26
26
  ```
27
27
 
28
- The AI handles the entire workflow through 269 tools spanning the supported ExtendScript, QE DOM, and safe edit-planning surfaces.
28
+ The AI handles the entire workflow through 278 tools spanning the supported ExtendScript, QE DOM, and safe edit-planning surfaces.
29
29
 
30
30
  ### What's new in 1.3.1
31
31
 
@@ -43,7 +43,7 @@ The AI handles the entire workflow through 269 tools spanning the supported Exte
43
43
  - **Safe edit plans:** preview compound insert/remove operations, bind approval to a SHA-256 plan token, then apply the validated plan in one bridge command.
44
44
  - **Capability profiles:** unsafe scripting is disabled by default and requires explicit `unsafe-script` authority.
45
45
  - **Modern MCP responses:** tools expose safety annotations and structured results; four workflow prompts and a machine-readable workflow resource guide common edits.
46
- - **UXP bridge preview:** a packaged Premiere 25.6+ panel adds capability discovery, state events, reconnecting WebSocket transport, and supported frame export with file verification. Live host verification is still required.
46
+ - **UXP bridge preview:** a packaged Premiere 25.6+ panel adds capability discovery, event-driven state notifications with a deduplicated polling fallback, correlated operation lifecycle events, reconnecting WebSocket transport, and supported frame export with file verification. Cancellation is cooperative before non-cancellable host calls; no atomic rollback is claimed. Live host verification is still required.
47
47
 
48
48
  ---
49
49
 
@@ -217,6 +217,58 @@ Add to your VS Code MCP server configuration:
217
217
 
218
218
  The default bridge directory is derived from the operating system on both sides, so most local setups should not set `PREMIERE_TEMP_DIR`. If you override it, use the same absolute path in the MCP server and CEP panel; Windows and macOS paths are not interchangeable.
219
219
 
220
+ ### Codex plugin
221
+
222
+ This repository includes an installable Codex plugin that bundles the local MCP
223
+ server with a safety-oriented Premiere editing skill.
224
+
225
+ From a clone of this repository:
226
+
227
+ ```bash
228
+ codex plugin marketplace add .
229
+ codex plugin add premiere-pro@premiere-pro-mcp
230
+ npx -y premiere-pro-mcp@1.3.1 --install-cep
231
+ ```
232
+
233
+ Restart Premiere Pro and start a new Codex session after installation. The plugin
234
+ launches `premiere-pro-mcp@1.3.1` through `npx`; the separate CEP installation is
235
+ required because the MCP server communicates with the running Premiere host through
236
+ the local bridge.
237
+
238
+ The plugin source lives in [`plugins/premiere-pro`](plugins/premiere-pro), and the
239
+ repository marketplace manifest lives in
240
+ [`.agents/plugins/marketplace.json`](.agents/plugins/marketplace.json).
241
+
242
+ ### Claude
243
+
244
+ For Claude Code, add this repository as a marketplace and install the plugin:
245
+
246
+ ```text
247
+ /plugin marketplace add leancoderkavy/premiere-pro-mcp
248
+ /plugin install premiere-pro@premiere-pro-mcp
249
+ ```
250
+
251
+ Then install the Premiere bridge and start a new Claude Code session:
252
+
253
+ ```bash
254
+ npx -y premiere-pro-mcp@1.3.1 --install-cep
255
+ ```
256
+
257
+ The Claude Code package lives in
258
+ [`claude-plugins/premiere-pro`](claude-plugins/premiere-pro), with its marketplace
259
+ at [`.claude-plugin/marketplace.json`](.claude-plugin/marketplace.json).
260
+
261
+ Claude Desktop uses the self-contained MCP Bundle format, formerly called Desktop
262
+ Extensions. Build both the current `.mcpb` artifact and a legacy `.dxt` copy with:
263
+
264
+ ```bash
265
+ npm run build:claude
266
+ ```
267
+
268
+ Install the resulting file from `artifacts/` through **Settings > Extensions >
269
+ Advanced settings > Install Extension**. The Premiere CEP bridge must still be
270
+ installed separately.
271
+
220
272
  ### Windows and macOS capability coverage
221
273
 
222
274
  | Surface | Windows | macOS | Verification boundary |
@@ -226,7 +278,58 @@ The default bridge directory is derived from the operating system on both sides,
226
278
  | npm CEP installer | Copies plugin and verifies `REG_SZ` debug keys | Copies plugin and verifies the installed manifest/debug settings | Restart Premiere after installation |
227
279
  | CI build and unit tests | Node 18 and 22 | Node 18 and 22 | GitHub-hosted OS runners; no Adobe host is available in CI |
228
280
 
229
- `get_capabilities` reports the current operating system, temp directory, CEP/UXP coverage, enabled authority profile, and any live-host verification still required. It does not claim a Premiere operation succeeded; use `ping` and inspect each tool result for runtime evidence.
281
+ `get_capabilities` reports the current operating system, temp directory, CEP/UXP coverage, enabled authority profile, and any live-host verification still required. It also includes a `tools` catalog generated from the tools actually registered by the server. Every entry identifies:
282
+
283
+ - the execution backend (`local`, CEP/ExtendScript, QE, or orchestrator);
284
+ - static support status (`supported`, `limited`, `experimental`, or `unsupported`);
285
+ - the minimum Premiere version known to the server;
286
+ - the required authority and whether the current profile enables it;
287
+ - the verification boundary and whether a live Premiere host is required; and
288
+ - relevant operational notes.
289
+
290
+ QE-backed tools are reported as `experimental` because QE is undocumented and can vary between Premiere builds. Authority availability is reported separately from implementation support, so disabling `edit`, for example, does not incorrectly label editing tools as unsupported. Static metadata never claims that a Premiere operation succeeded; use `ping` and inspect each tool result for runtime evidence.
291
+
292
+ Tools with mixed execution boundaries can provide explicit operational metadata at registration. This is used for local file verification, static feature-support reports, and hybrid local-plus-Premiere validation so the capability catalog does not infer a host dependency from naming alone.
293
+
294
+ ### Collaboration and AI feature boundaries
295
+
296
+ `get_advanced_feature_support` returns a machine-readable matrix for Productions,
297
+ Team Projects, Frame.io, Media Intelligence, Generative Extend, Object Mask,
298
+ caption translation, Speech-to-Text, Enhance Speech, and Remix. Pass an optional
299
+ Premiere version, intended backend, confirmed entitlements, and network state to
300
+ evaluate prerequisites without conflating them with API availability. It
301
+ distinguishes documented APIs from entitlements, network prerequisites, separate
302
+ service APIs, and user-assisted operations without using menu automation or
303
+ private APIs.
304
+
305
+ The report tool itself is local: it does not contact Premiere and is callable
306
+ through the current MCP server. Each feature entry separately reports whether
307
+ its operations are callable through the production CEP transport. Productions
308
+ reports only static backend/version eligibility until a UXP host performs live
309
+ capability negotiation.
310
+
311
+ - Productions exposes documented read-only state through UXP, but the production
312
+ MCP transport is still CEP.
313
+ - Frame.io needs a separately authenticated Frame.io API integration; an account
314
+ entitlement alone does not make it callable through Premiere's DOM.
315
+ - Transcript JSON import/export is documented in UXP. Starting Speech-to-Text is not.
316
+ - The remaining AI operations are user-assisted or unsupported by documented
317
+ public APIs. The tool explains what can be inspected after a user completes
318
+ the operation and where artifact provenance cannot be established safely.
319
+ - The server never uses menu automation, private APIs, clip-name heuristics, or
320
+ duration changes as proof that an AI operation occurred.
321
+
322
+ ### Authenticated UXP connection
323
+
324
+ The MCP server can accept a local UXP panel connection and invoke the UXP commands that are currently implemented:
325
+
326
+ ```bash
327
+ PREMIERE_UXP_TOKEN="replace-with-a-long-random-secret" premiere-pro-mcp
328
+ ```
329
+
330
+ Enter the same token in the UXP panel. The listener binds only to `127.0.0.1:7777`, authenticates the WebSocket upgrade, requires a versioned capability handshake, correlates concurrent requests, and fails pending work on timeout or disconnect. Set `PREMIERE_UXP_PORT` to use another loopback port.
331
+
332
+ When enabled, MCP discovery includes `get_uxp_capabilities`, `get_uxp_state`, and `export_frame_uxp`. A failed UXP command is never silently retried through CEP because the first operation may have partially succeeded.
230
333
 
231
334
  ---
232
335
 
@@ -270,7 +373,7 @@ The file-based IPC bridge is simple, reliable, and works across macOS and Window
270
373
 
271
374
  ---
272
375
 
273
- ## Tools (269)
376
+ ## Tools (278)
274
377
 
275
378
  ### Discovery & Inspection (10 + 10)
276
379
 
@@ -286,6 +389,7 @@ The file-based IPC bridge is simple, reliable, and works across macOS and Window
286
389
  | `search_project_items` | Filter by name, extension, offline status, color label |
287
390
  | `get_premiere_state` | Full snapshot: project, sequence, playhead, selection |
288
391
  | `inspect_dom_object` | Explore any Premiere Pro DOM object interactively |
392
+ | `get_advanced_feature_support` | Collaboration/AI API support, prerequisites, entitlements, and user-assisted boundaries |
289
393
 
290
394
  ### Project Management (26)
291
395
 
@@ -341,16 +445,23 @@ The file-based IPC bridge is simple, reliable, and works across macOS and Window
341
445
  | `get_value_at_time` | Query interpolated value at any time |
342
446
  | `set_color_value` | Set color properties on effects |
343
447
 
344
- ### Export & Encoding (14)
448
+ ### Export & Encoding (16)
345
449
 
346
450
  | Tool | Description |
347
451
  | :--- | :---------- |
348
452
  | `export_sequence` | Export via Adobe Media Encoder |
453
+ | `validate_export_preset` | Validate an `.epr` file and resolve its output extension in Premiere |
454
+ | `verify_delivery_file` | Verify output size and calculate SHA-256/SHA-512 checksums |
349
455
  | `capture_frame` | Export frame as PNG, return as base64 image |
350
456
  | `export_as_fcp_xml` / `export_aaf` / `export_omf` | Interchange formats |
351
457
  | `encode_project_item` / `encode_file` | Direct encoding |
352
458
  | `start_batch_encode` | Start render queue |
353
459
 
460
+ Premiere's documented automation surfaces do not currently expose OTIO or EDL
461
+ interchange, Render and Replace, cloud publishing, or Content Credentials export
462
+ configuration. `get_capabilities` reports these delivery gaps explicitly rather
463
+ than presenting UI-only operations as available tools.
464
+
354
465
  ### Source Monitor & Playback (7 + 4)
355
466
 
356
467
  | Tool | Description |
@@ -495,12 +606,13 @@ premiere-pro-mcp/
495
606
  ├── src/
496
607
  │ ├── index.ts # Entry point — stdio transport setup
497
608
  │ ├── http-server.ts # Entry point — HTTP/SSE transport (Fly.io / remote)
498
- │ ├── server.ts # MCP server — registers 269 tools + 3 resources + 4 prompts
609
+ │ ├── server.ts # MCP server — registers 278 tools + 3 resources + 4 prompts
499
610
  │ ├── bridge/
500
611
  │ │ ├── file-bridge.ts # File-based IPC (write .jsx, poll .json)
501
612
  │ │ └── script-builder.ts # ExtendScript generator with ES3 helpers
502
- │ ├── tools/ # 29 tool modules
613
+ │ ├── tools/ # 31 tool modules
503
614
  │ │ ├── discovery.ts # Project discovery and queries
615
+ │ │ ├── recovery.ts # Read-only autosave discovery and private bridge telemetry
504
616
  │ │ ├── project.ts # Project management and import
505
617
  │ │ ├── media.ts # Media and proxy management
506
618
  │ │ ├── sequence.ts # Sequence creation and settings
@@ -508,6 +620,7 @@ premiere-pro-mcp/
508
620
  │ │ ├── effects.ts # Effect application and color correction
509
621
  │ │ ├── transitions.ts # Transition management (QE DOM)
510
622
  │ │ ├── audio.ts # Audio levels and keyframes
623
+ │ │ ├── av-settings.ts # Documented AV inspection, mapping, and capability boundaries
511
624
  │ │ ├── text.ts # Text overlays and MOGRTs
512
625
  │ │ ├── markers.ts # Sequence and clip markers
513
626
  │ │ ├── tracks.ts # Track add/delete/lock/visibility
Binary file
@@ -1,8 +1,8 @@
1
1
  <?xml version="1.0" encoding="UTF-8"?>
2
- <ExtensionManifest Version="7.0" ExtensionBundleId="com.mcp.premiere.bridge" ExtensionBundleVersion="1.3.1" ExtensionBundleName="MCP Bridge">
2
+ <ExtensionManifest Version="7.0" ExtensionBundleId="com.mcp.premiere.bridge" ExtensionBundleVersion="1.4.0" ExtensionBundleName="MCP Bridge">
3
3
  <ExtensionList>
4
- <Extension Id="com.mcp.premiere.bridge.panel" Version="1.3.1"/>
5
- <Extension Id="com.mcp.premiere.bridge.headless" Version="1.3.1"/>
4
+ <Extension Id="com.mcp.premiere.bridge.panel" Version="1.4.0"/>
5
+ <Extension Id="com.mcp.premiere.bridge.headless" Version="1.4.0"/>
6
6
  </ExtensionList>
7
7
  <ExecutionEnvironment>
8
8
  <HostList>
@@ -17,7 +17,7 @@
17
17
  <div class="auto-start"><span></span>Auto-start</div>
18
18
  </header>
19
19
 
20
- <section class="status-panel" aria-live="polite">
20
+ <section class="status-panel" role="status" aria-live="polite" aria-atomic="true">
21
21
  <div class="status-indicator" aria-hidden="true">
22
22
  <div class="status-ring"><div class="status-dot connected" id="statusDot"></div></div>
23
23
  </div>
@@ -46,22 +46,33 @@
46
46
  <label class="sr-only" for="tempDir">Temporary bridge directory</label>
47
47
  <div class="path-field">
48
48
  <svg viewBox="0 0 20 20" aria-hidden="true"><path d="M2.5 5.5h5l1.5 2h8.5v8h-15v-10Z"/></svg>
49
- <input type="text" id="tempDir" value="" spellcheck="false">
49
+ <input type="text" id="tempDir" value="" spellcheck="false" autocomplete="off" aria-describedby="tempDirHelp">
50
50
  </div>
51
- <p class="field-help">Commands and responses are exchanged through this local folder.</p>
51
+ <p class="field-help" id="tempDirHelp">Commands and responses are exchanged through this local folder.</p>
52
52
  </section>
53
53
 
54
54
  <div class="action-row">
55
- <button id="btnStart" class="button button-primary" onclick="startBridge()" type="button">
55
+ <button id="btnStart" class="button button-primary" onclick="startBridge()" type="button" aria-controls="log">
56
56
  <svg viewBox="0 0 20 20" aria-hidden="true"><path class="fill-icon" d="m7 5 8 5-8 5V5Z"/></svg>
57
57
  Start Bridge
58
58
  </button>
59
- <button id="btnStop" class="button button-stop" onclick="stopBridge()" type="button" disabled>
59
+ <button id="btnStop" class="button button-stop" onclick="stopBridge()" type="button" aria-controls="log" disabled>
60
60
  <svg viewBox="0 0 20 20" aria-hidden="true"><rect class="fill-icon" x="6" y="6" width="8" height="8" rx="1"/></svg>
61
61
  Stop
62
62
  </button>
63
63
  </div>
64
64
 
65
+ <section class="update-section" aria-live="polite">
66
+ <div class="update-copy">
67
+ <span class="section-label">Connector updates</span>
68
+ <strong id="updateTitle">Version 1.4.0</strong>
69
+ <span id="updateDetail">Checking for updates…</span>
70
+ </div>
71
+ <button id="btnUpdate" class="button button-update" onclick="handleUpdateClick()" type="button" disabled>
72
+ Check again
73
+ </button>
74
+ </section>
75
+
65
76
  <section class="activity-section">
66
77
  <div class="section-heading activity-heading">
67
78
  <div>
@@ -70,11 +81,12 @@
70
81
  </div>
71
82
  <span class="activity-state"><span></span>Listening</span>
72
83
  </div>
73
- <div id="log" role="log" aria-live="polite"></div>
84
+ <div id="log" role="log" aria-live="polite" aria-relevant="additions" tabindex="0" aria-label="Bridge activity log"></div>
74
85
  </section>
75
86
  </main>
76
87
 
77
88
  <script src="CSInterface.js"></script>
89
+ <script src="updater.cjs"></script>
78
90
  <script src="main.js"></script>
79
91
  </body>
80
92
  </html>
@@ -26,7 +26,9 @@ function log(msg, cls) {
26
26
  function setStatus(state, text) {
27
27
  var dot = document.getElementById("statusDot");
28
28
  dot.className = "status-dot " + state;
29
- document.getElementById("statusText").textContent = text;
29
+ var statusText = document.getElementById("statusText");
30
+ statusText.textContent = text;
31
+ statusText.setAttribute("data-state", state || "stopped");
30
32
  var detail = document.getElementById("statusDetail");
31
33
  if (detail) {
32
34
  if (state === "connected") detail.textContent = "Premiere Pro link is active";
@@ -55,7 +57,9 @@ function nodeRequire(moduleName) {
55
57
  var fs = nodeRequire("fs");
56
58
  var path = nodeRequire("path");
57
59
  var os = nodeRequire("os");
60
+ var https = nodeRequire("https");
58
61
  tempDir = path.join(os.tmpdir(), "premiere-mcp-bridge");
62
+ var latestUpdate = null;
59
63
 
60
64
  function ensureDir(dir) {
61
65
  try {
@@ -204,6 +208,7 @@ function startBridge() {
204
208
  tempDir = document.getElementById("tempDir").value.trim();
205
209
  if (!tempDir) {
206
210
  log("Please set a temp directory", "err");
211
+ document.getElementById("tempDir").focus();
207
212
  return;
208
213
  }
209
214
 
@@ -250,6 +255,124 @@ function saveTempDir() {
250
255
  } catch (e) {}
251
256
  }
252
257
 
258
+ // ---- Connector Updates ----
259
+ function setUpdateUI(title, detail, buttonText, disabled) {
260
+ document.getElementById("updateTitle").textContent = title;
261
+ document.getElementById("updateDetail").textContent = detail;
262
+ var button = document.getElementById("btnUpdate");
263
+ button.textContent = buttonText;
264
+ button.disabled = !!disabled;
265
+ }
266
+
267
+ function checkForUpdates() {
268
+ latestUpdate = null;
269
+ setUpdateUI(
270
+ "Version " + MCPBridgeUpdater.CURRENT_VERSION,
271
+ "Checking for updates…",
272
+ "Checking…",
273
+ true
274
+ );
275
+
276
+ var request = https.get(
277
+ MCPBridgeUpdater.LATEST_RELEASE_API,
278
+ {
279
+ headers: {
280
+ Accept: "application/vnd.github+json",
281
+ "User-Agent": "premiere-pro-mcp-connector/" + MCPBridgeUpdater.CURRENT_VERSION,
282
+ },
283
+ },
284
+ function (response) {
285
+ var body = "";
286
+ response.setEncoding("utf8");
287
+ response.on("data", function (chunk) {
288
+ if (body.length < 1024 * 1024) body += chunk;
289
+ });
290
+ response.on("end", function () {
291
+ if (response.statusCode !== 200) {
292
+ showUpdateCheckError("Could not check GitHub (HTTP " + response.statusCode + ").");
293
+ return;
294
+ }
295
+ try {
296
+ var release = JSON.parse(body);
297
+ var latestVersion = MCPBridgeUpdater.normalizeVersion(
298
+ release.tag_name || release.name
299
+ );
300
+ if (!latestVersion) throw new Error("Release has no version");
301
+
302
+ if (
303
+ MCPBridgeUpdater.compareVersions(
304
+ latestVersion,
305
+ MCPBridgeUpdater.CURRENT_VERSION
306
+ ) > 0
307
+ ) {
308
+ latestUpdate = {
309
+ version: latestVersion,
310
+ url: MCPBridgeUpdater.chooseDownloadUrl(release),
311
+ };
312
+ setUpdateUI(
313
+ "Version " + latestVersion + " is available",
314
+ "Download it, then close Premiere and run the installer.",
315
+ "Download update",
316
+ false
317
+ );
318
+ } else {
319
+ setUpdateUI(
320
+ "Version " + MCPBridgeUpdater.CURRENT_VERSION,
321
+ "You have the latest connector.",
322
+ "Check again",
323
+ false
324
+ );
325
+ }
326
+ } catch (e) {
327
+ showUpdateCheckError("GitHub returned an unreadable release.");
328
+ }
329
+ });
330
+ }
331
+ );
332
+ request.setTimeout(10000, function () {
333
+ request.destroy(new Error("Update check timed out"));
334
+ });
335
+ request.on("error", function () {
336
+ showUpdateCheckError("Unable to check while offline.");
337
+ });
338
+ }
339
+
340
+ function showUpdateCheckError(message) {
341
+ setUpdateUI(
342
+ "Version " + MCPBridgeUpdater.CURRENT_VERSION,
343
+ message,
344
+ "Check again",
345
+ false
346
+ );
347
+ }
348
+
349
+ function handleUpdateClick() {
350
+ if (!latestUpdate) {
351
+ checkForUpdates();
352
+ return;
353
+ }
354
+ if (!MCPBridgeUpdater.isTrustedDownloadUrl(latestUpdate.url)) {
355
+ showUpdateCheckError("The update link was not trusted.");
356
+ return;
357
+ }
358
+ try {
359
+ var childProcess = nodeRequire("child_process");
360
+ var command =
361
+ os.platform() === "win32"
362
+ ? ["cmd.exe", ["/d", "/s", "/c", "start", "", latestUpdate.url]]
363
+ : ["open", [latestUpdate.url]];
364
+ var child = childProcess.spawn(command[0], command[1], {
365
+ detached: true,
366
+ stdio: "ignore",
367
+ });
368
+ child.unref();
369
+ document.getElementById("updateDetail").textContent =
370
+ "Download opened. Close Premiere before installing.";
371
+ } catch (e) {
372
+ showUpdateCheckError("Could not open the download. Try again.");
373
+ }
374
+ }
375
+
253
376
  // ---- Init ----
254
377
  (function init() {
255
378
  // Set the default temp dir in the input field
@@ -273,4 +396,5 @@ function saveTempDir() {
273
396
  ensureDir(tempDir);
274
397
  log("Auto-starting bridge...");
275
398
  setTimeout(startBridge, 500);
399
+ setTimeout(checkForUpdates, 1200);
276
400
  })();
@@ -117,6 +117,10 @@ button { -webkit-appearance: none; }
117
117
  .section-label { display: block; margin-bottom: 4px; color: var(--text-muted); font-size: 9px; font-weight: 650; letter-spacing: .09em; text-transform: uppercase; }
118
118
  .status-copy { min-width: 0; }
119
119
  .status-copy strong { display: block; overflow: hidden; color: var(--text); font-size: 14px; font-weight: 650; line-height: 1.3; text-overflow: ellipsis; white-space: nowrap; }
120
+ .status-copy strong::before { content: "■ "; color: var(--text-muted); }
121
+ .status-copy strong[data-state="connected"]::before { content: "✓ "; color: var(--green); }
122
+ .status-copy strong[data-state="waiting"]::before { content: "… "; color: var(--amber); }
123
+ .status-copy strong[data-state="error"]::before { content: "! "; color: var(--red); }
120
124
  .status-copy #statusDetail { display: block; overflow: hidden; margin-top: 3px; color: var(--text-secondary); font-size: 10px; text-overflow: ellipsis; white-space: nowrap; }
121
125
 
122
126
  .command-stat { padding-left: 14px; text-align: right; }
@@ -183,6 +187,32 @@ button { -webkit-appearance: none; }
183
187
  .button-stop:hover { border-color: var(--red); background: rgba(255, 101, 101, .08); }
184
188
  .button:disabled { border-color: var(--border); background: var(--surface); color: #5f5e65; cursor: default; }
185
189
 
190
+ .update-section {
191
+ display: flex;
192
+ align-items: center;
193
+ gap: 12px;
194
+ margin-bottom: 14px;
195
+ padding: 11px 12px;
196
+ border: 1px solid var(--border);
197
+ border-radius: var(--radius);
198
+ background: var(--surface);
199
+ }
200
+ .update-copy { min-width: 0; flex: 1; }
201
+ .update-copy strong, .update-copy > span:last-child { display: block; }
202
+ .update-copy strong { font-size: 11px; font-weight: 600; }
203
+ .update-copy > span:last-child { margin-top: 3px; color: var(--text-muted); font-size: 9px; line-height: 1.4; }
204
+ .button-update {
205
+ width: auto;
206
+ min-width: 92px;
207
+ height: 30px;
208
+ padding: 0 10px;
209
+ border-color: var(--border-strong);
210
+ background: var(--surface-raised);
211
+ color: var(--violet-hover);
212
+ white-space: nowrap;
213
+ }
214
+ .button-update:hover { border-color: var(--violet); background: var(--violet-soft); }
215
+
186
216
  .activity-section { display: flex; flex: 1; min-height: 120px; flex-direction: column; }
187
217
  .activity-heading { align-items: center; margin: 2px 0 8px; }
188
218
  .activity-state { display: flex; align-items: center; gap: 6px; color: var(--text-muted); font-size: 9px; }
@@ -211,7 +241,7 @@ button { -webkit-appearance: none; }
211
241
 
212
242
  .sr-only { position: absolute; width: 1px; height: 1px; padding: 0; margin: -1px; overflow: hidden; clip: rect(0, 0, 0, 0); white-space: nowrap; border: 0; }
213
243
 
214
- button:focus-visible { outline: 1px solid var(--violet); outline-offset: 2px; }
244
+ button:focus-visible, input:focus-visible, #log:focus-visible { outline: 2px solid var(--violet-hover); outline-offset: 2px; }
215
245
 
216
246
  @media (max-width: 330px) {
217
247
  .panel-shell { padding-right: 10px; padding-left: 10px; }
@@ -225,3 +255,9 @@ button:focus-visible { outline: 1px solid var(--violet); outline-offset: 2px; }
225
255
  @media (prefers-reduced-motion: reduce) {
226
256
  *, *::before, *::after { animation-duration: .01ms !important; animation-iteration-count: 1 !important; }
227
257
  }
258
+
259
+ @media (forced-colors: active) {
260
+ .status-dot, .auto-start > span, .activity-state > span { forced-color-adjust: none; border: 1px solid CanvasText; }
261
+ .button, .path-field input, #log, .status-panel { border-color: CanvasText; }
262
+ .status-copy strong::before { color: CanvasText !important; }
263
+ }
@@ -0,0 +1,74 @@
1
+ /* MCP Bridge update helpers. Kept dependency-free for the older Chromium
2
+ * runtime embedded in CEP. */
3
+ (function (root, factory) {
4
+ var api = factory();
5
+ if (typeof module === "object" && module.exports) module.exports = api;
6
+ root.MCPBridgeUpdater = api;
7
+ })(this, function () {
8
+ "use strict";
9
+
10
+ var CURRENT_VERSION = "1.4.0";
11
+ var LATEST_RELEASE_API =
12
+ "https://api.github.com/repos/leancoderkavy/premiere-pro-mcp/releases/latest";
13
+ var RELEASES_URL =
14
+ "https://github.com/leancoderkavy/premiere-pro-mcp/releases/latest";
15
+
16
+ function normalizeVersion(value) {
17
+ return String(value || "")
18
+ .trim()
19
+ .replace(/^v/i, "")
20
+ .split("-")[0];
21
+ }
22
+
23
+ function compareVersions(left, right) {
24
+ var a = normalizeVersion(left).split(".");
25
+ var b = normalizeVersion(right).split(".");
26
+ var length = Math.max(a.length, b.length);
27
+ for (var i = 0; i < length; i++) {
28
+ var aPart = parseInt(a[i] || "0", 10);
29
+ var bPart = parseInt(b[i] || "0", 10);
30
+ if (aPart > bPart) return 1;
31
+ if (aPart < bPart) return -1;
32
+ }
33
+ return 0;
34
+ }
35
+
36
+ function chooseDownloadUrl(release) {
37
+ var assets = release && release.assets ? release.assets : [];
38
+ var preferredNames = [
39
+ /^MCPBridgeCEP(?:-[\w.-]+)?\.zxp$/i,
40
+ /premiere.*(?:connector|bridge).*\.zxp$/i,
41
+ /\.zxp$/i,
42
+ /premiere.*(?:connector|bridge).*\.(?:zip|dmg|exe)$/i,
43
+ ];
44
+ for (var p = 0; p < preferredNames.length; p++) {
45
+ for (var i = 0; i < assets.length; i++) {
46
+ if (
47
+ preferredNames[p].test(assets[i].name || "") &&
48
+ isTrustedDownloadUrl(assets[i].browser_download_url)
49
+ ) {
50
+ return assets[i].browser_download_url;
51
+ }
52
+ }
53
+ }
54
+ return isTrustedDownloadUrl(release && release.html_url)
55
+ ? release.html_url
56
+ : RELEASES_URL;
57
+ }
58
+
59
+ function isTrustedDownloadUrl(value) {
60
+ return /^https:\/\/(?:github\.com|api\.github\.com|objects\.githubusercontent\.com)\//i.test(
61
+ String(value || "")
62
+ );
63
+ }
64
+
65
+ return {
66
+ CURRENT_VERSION: CURRENT_VERSION,
67
+ LATEST_RELEASE_API: LATEST_RELEASE_API,
68
+ RELEASES_URL: RELEASES_URL,
69
+ normalizeVersion: normalizeVersion,
70
+ compareVersions: compareVersions,
71
+ chooseDownloadUrl: chooseDownloadUrl,
72
+ isTrustedDownloadUrl: isTrustedDownloadUrl,
73
+ };
74
+ });