davinci-resolve-mcp 2.212.1 → 2.212.2
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 +26 -0
- package/README.md +1 -1
- package/README.zh-CN.md +2 -2
- package/install.py +1 -1
- package/package.json +1 -1
- package/src/granular/common.py +1 -1
- package/src/server.py +1 -1
- package/src/utils/operation_result.py +45 -63
package/CHANGELOG.md
CHANGED
|
@@ -2,6 +2,32 @@
|
|
|
2
2
|
|
|
3
3
|
Release history for the DaVinci Resolve MCP Server. The latest release is summarized in the root README; older entries live here to keep the README focused.
|
|
4
4
|
|
|
5
|
+
## What's New in v2.212.2 — failed verification evidence survives the operation envelope
|
|
6
|
+
|
|
7
|
+
### Fixed
|
|
8
|
+
|
|
9
|
+
- **A payload that carried its own `verification` block won outright, hiding
|
|
10
|
+
contradicting evidence beside it.** `extract_verification` returned any
|
|
11
|
+
pre-shaped `verification` dict untouched, so a top-level `contradiction:
|
|
12
|
+
true`, a `readback.missing` list, or a failed check inside the block itself
|
|
13
|
+
could sit next to `status: "passed"`. Evidence now merges: the explicit
|
|
14
|
+
status, readback misses, post-state readback and property-restore failures
|
|
15
|
+
are all collected, and precedence runs contradiction > failed > partial >
|
|
16
|
+
passed > unverified. Contributed in #195 by @denoise.
|
|
17
|
+
- **Bulk command counts no longer count as verification.** `succeeded` /
|
|
18
|
+
`failed` tallies record what the server sent, not what Resolve honoured; a
|
|
19
|
+
`succeeded: 3, failed: 0` result used to read `verification.status:
|
|
20
|
+
"passed"` with no readback at all. The counts still drive the envelope's
|
|
21
|
+
own `status` (`partial` when both are non-zero), but the verification block
|
|
22
|
+
stays `unverified` until real evidence — a readback — arrives.
|
|
23
|
+
|
|
24
|
+
### Validation
|
|
25
|
+
|
|
26
|
+
- The PR's regression tests plus two added on landing: bulk counts cannot
|
|
27
|
+
mask a failed readback, and readback evidence is what establishes a pass on
|
|
28
|
+
a bulk result. Full offline suite, the drift guards and the advanced Node
|
|
29
|
+
suite are green. No Resolve behavior changed; live test not required.
|
|
30
|
+
|
|
5
31
|
## What's New in v2.212.1 — the networked transport's generated bearer token no longer lands in server.log
|
|
6
32
|
|
|
7
33
|
### Fixed
|
package/README.md
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
English | [简体中文](README.zh-CN.md)
|
|
4
4
|
|
|
5
|
-
[](https://github.com/samuelgursky/davinci-resolve-mcp/releases)
|
|
6
6
|
[](https://www.npmjs.com/package/davinci-resolve-mcp)
|
|
7
7
|
[](docs/reference/api-coverage.md)
|
|
8
8
|
[-blue.svg)](#server-modes)
|
package/README.zh-CN.md
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
[English](README.md) | 简体中文
|
|
4
4
|
|
|
5
|
-
[](https://github.com/samuelgursky/davinci-resolve-mcp/releases)
|
|
6
6
|
[](https://www.npmjs.com/package/davinci-resolve-mcp)
|
|
7
7
|
[](docs/reference/api-coverage.md)
|
|
8
8
|
[-blue.svg)](#服务器模式)
|
|
@@ -12,7 +12,7 @@
|
|
|
12
12
|
[](https://www.python.org/downloads/)
|
|
13
13
|
[](https://opensource.org/licenses/MIT)
|
|
14
14
|
|
|
15
|
-
> 本翻译对应 v2.212.
|
|
15
|
+
> 本翻译对应 v2.212.2 版 README。如与英文原版有出入,以 [英文原版](README.md) 为准。
|
|
16
16
|
|
|
17
17
|
一个 Model Context Protocol (MCP) 服务器,让 AI 助手通过官方脚本 API 控制 DaVinci Resolve Studio(达芬奇)。它提供完整的 API 覆盖,外加带护栏的工作流助手,涵盖剪辑、媒体池整理、渲染设置、审阅标记、调色、Fusion、Fairlight、项目生命周期任务、扩展开发,以及不碰源媒体的媒体分析。
|
|
18
18
|
|
package/install.py
CHANGED
|
@@ -37,7 +37,7 @@ from src.utils.update_check import (
|
|
|
37
37
|
|
|
38
38
|
# ─── Version ──────────────────────────────────────────────────────────────────
|
|
39
39
|
|
|
40
|
-
VERSION = "2.212.
|
|
40
|
+
VERSION = "2.212.2"
|
|
41
41
|
# Only hard floor: mcp[cli] requires Python 3.10+. There is no upper bound —
|
|
42
42
|
# Resolve's scripting bridge loads into newer interpreters on recent builds
|
|
43
43
|
# (Python 3.14 verified against Resolve Studio 20.3.2). Older Resolve builds
|
package/package.json
CHANGED
package/src/granular/common.py
CHANGED
|
@@ -87,7 +87,7 @@ if not logging.getLogger().handlers:
|
|
|
87
87
|
handlers=[logging.StreamHandler()],
|
|
88
88
|
)
|
|
89
89
|
|
|
90
|
-
VERSION = "2.212.
|
|
90
|
+
VERSION = "2.212.2"
|
|
91
91
|
logger = logging.getLogger("davinci-resolve-mcp")
|
|
92
92
|
logger.info(f"Starting DaVinci Resolve MCP Server v{VERSION}")
|
|
93
93
|
logger.info(f"Detected platform: {get_platform()}")
|
package/src/server.py
CHANGED
|
@@ -166,75 +166,57 @@ def extract_verification(raw: Any) -> Dict[str, Any]:
|
|
|
166
166
|
if not isinstance(raw, dict):
|
|
167
167
|
return unverified
|
|
168
168
|
|
|
169
|
-
# An impl that already speaks this shape wins outright.
|
|
170
169
|
existing = raw.get("verification")
|
|
171
|
-
if isinstance(existing, dict)
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
contradiction =
|
|
170
|
+
existing = existing if isinstance(existing, dict) else {}
|
|
171
|
+
checks = list(existing.get("checks") or [])
|
|
172
|
+
statuses = []
|
|
173
|
+
existing_status = existing.get("status")
|
|
174
|
+
if existing_status in {"passed", "failed", "partial", "contradiction"}:
|
|
175
|
+
statuses.append(existing_status)
|
|
176
|
+
elif existing.get("verified") is True:
|
|
177
|
+
statuses.append("passed")
|
|
178
|
+
elif existing.get("verified") is False:
|
|
179
|
+
statuses.append("failed")
|
|
180
|
+
contradiction = existing.get("contradiction") is True or raw.get("contradiction") is True
|
|
182
181
|
|
|
183
182
|
readback = raw.get("readback")
|
|
184
|
-
if isinstance(readback, dict):
|
|
185
|
-
missing = readback
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
# verify_by_readback's own shape: a mutation that reported success while the
|
|
195
|
-
# post-state disagrees is a contradiction, this repo's single most valuable
|
|
196
|
-
# reliability signal — it must not be flattened into a plain failure.
|
|
197
|
-
if "verified" in raw:
|
|
198
|
-
verified = bool(raw["verified"])
|
|
199
|
-
contradiction = bool(raw.get("contradiction"))
|
|
200
|
-
checks.append({
|
|
201
|
-
"check": "readback_post_state",
|
|
202
|
-
"passed": verified,
|
|
203
|
-
"contradiction": contradiction,
|
|
204
|
-
"observed": raw.get("observed"),
|
|
205
|
-
})
|
|
206
|
-
status = "contradiction" if contradiction else ("passed" if verified else "failed")
|
|
183
|
+
if isinstance(readback, dict) and isinstance(readback.get("missing"), list):
|
|
184
|
+
missing = readback["missing"]
|
|
185
|
+
checks.append({"check": "readback_verification", "passed": not missing,
|
|
186
|
+
"missing_items": len(missing)})
|
|
187
|
+
statuses.append("failed" if missing else "passed")
|
|
188
|
+
|
|
189
|
+
if type(raw.get("verified")) is bool:
|
|
190
|
+
checks.append({"check": "readback_post_state", "passed": raw["verified"],
|
|
191
|
+
"contradiction": contradiction, "observed": raw.get("observed")})
|
|
192
|
+
statuses.append("passed" if raw["verified"] else "failed")
|
|
207
193
|
|
|
208
194
|
if "property_restore_failures" in raw:
|
|
209
195
|
failures = _as_int(raw.get("property_restore_failures"))
|
|
210
|
-
checks.append({
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
"
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
if not checks:
|
|
236
|
-
return unverified
|
|
237
|
-
return {"status": status, "checks": checks, "contradiction": contradiction}
|
|
196
|
+
checks.append({"check": "property_restore", "passed": failures == 0,
|
|
197
|
+
"restored_items": _as_int(raw.get("properties_restored_items")),
|
|
198
|
+
"failures": failures})
|
|
199
|
+
if failures:
|
|
200
|
+
statuses.append("partial")
|
|
201
|
+
|
|
202
|
+
for check in checks:
|
|
203
|
+
if isinstance(check, dict):
|
|
204
|
+
contradiction = contradiction or check.get("contradiction") is True
|
|
205
|
+
if check.get("passed") is False:
|
|
206
|
+
statuses.append("partial" if check.get("check") == "property_restore" else "failed")
|
|
207
|
+
# Command counts are not evidence that Resolve honored those commands.
|
|
208
|
+
if contradiction or "contradiction" in statuses:
|
|
209
|
+
status = "contradiction"
|
|
210
|
+
contradiction = True
|
|
211
|
+
elif "failed" in statuses:
|
|
212
|
+
status = "failed"
|
|
213
|
+
elif "partial" in statuses:
|
|
214
|
+
status = "partial"
|
|
215
|
+
elif "passed" in statuses:
|
|
216
|
+
status = "passed"
|
|
217
|
+
else:
|
|
218
|
+
status = "unverified"
|
|
219
|
+
return {**existing, "status": status, "checks": checks, "contradiction": contradiction}
|
|
238
220
|
|
|
239
221
|
|
|
240
222
|
# ─── Changes ─────────────────────────────────────────────────────────────────
|