davinci-resolve-mcp 2.57.4 → 2.58.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/AGENTS.md +20 -0
- package/CHANGELOG.md +197 -2
- package/LICENSE +1 -1
- package/README.md +73 -1
- package/bin/davinci-resolve-advanced-mcp.mjs +20 -0
- package/docs/README.md +19 -0
- package/docs/SKILL.md +62 -1
- package/docs/contributing.md +1 -1
- package/docs/guides/control-panel.md +9 -0
- package/docs/kernels/README.md +21 -0
- package/docs/kernels/audio-fairlight-kernel.md +22 -0
- package/docs/kernels/color-grade-kernel.md +51 -0
- package/docs/kernels/fusion-composition-kernel.md +17 -0
- package/docs/kernels/media-pool-ingest-kernel.md +20 -0
- package/docs/kernels/render-deliver-kernel.md +32 -0
- package/docs/kernels/timeline-conform-interchange-kernel.md +39 -0
- package/docs/kernels/timeline-edit-kernel.md +17 -0
- package/docs/process/release-process.md +29 -7
- package/docs/reference/api-coverage.md +1 -1
- package/docs/reference/api-limitations.md +38 -1
- package/install.py +27 -4
- package/package.json +23 -2
- package/resolve-advanced/README.md +194 -0
- package/resolve-advanced/package.json +50 -0
- package/resolve-advanced/server/black-balance.mjs +92 -0
- package/resolve-advanced/server/capabilities.mjs +86 -0
- package/resolve-advanced/server/cdl-io.mjs +76 -0
- package/resolve-advanced/server/contrast-normalize.mjs +180 -0
- package/resolve-advanced/server/db-patch.mjs +91 -0
- package/resolve-advanced/server/deliverable-entities.mjs +86 -0
- package/resolve-advanced/server/deliverable-qc.mjs +270 -0
- package/resolve-advanced/server/editorial.mjs +370 -0
- package/resolve-advanced/server/exposure-level.mjs +129 -0
- package/resolve-advanced/server/extract-frames.mjs +196 -0
- package/resolve-advanced/server/ffprobe-media.mjs +88 -0
- package/resolve-advanced/server/gamut-legal.mjs +112 -0
- package/resolve-advanced/server/grade-body-patch.mjs +246 -0
- package/resolve-advanced/server/grade-transfer.mjs +66 -0
- package/resolve-advanced/server/group-grade-read.mjs +137 -0
- package/resolve-advanced/server/index.mjs +105 -0
- package/resolve-advanced/server/lib.mjs +84 -0
- package/resolve-advanced/server/libs.mjs +65 -0
- package/resolve-advanced/server/lineage-db.mjs +479 -0
- package/resolve-advanced/server/lut-apply.mjs +61 -0
- package/resolve-advanced/server/match-to-reference.mjs +173 -0
- package/resolve-advanced/server/media-inventory.mjs +169 -0
- package/resolve-advanced/server/media-ops.mjs +243 -0
- package/resolve-advanced/server/node-meta-db.mjs +62 -0
- package/resolve-advanced/server/node-provenance.mjs +102 -0
- package/resolve-advanced/server/offline-ref-db.mjs +420 -0
- package/resolve-advanced/server/offline-ref.mjs +179 -0
- package/resolve-advanced/server/project-db.mjs +233 -0
- package/resolve-advanced/server/provenance-audit.mjs +210 -0
- package/resolve-advanced/server/qc-frame.mjs +224 -0
- package/resolve-advanced/server/qc-sampler.mjs +67 -0
- package/resolve-advanced/server/readback.mjs +77 -0
- package/resolve-advanced/server/render-manifest.mjs +93 -0
- package/resolve-advanced/server/reverse-clip-db.mjs +270 -0
- package/resolve-advanced/server/runner-apply-contract.mjs +64 -0
- package/resolve-advanced/server/runner.mjs +244 -0
- package/resolve-advanced/server/saturation-match.mjs +108 -0
- package/resolve-advanced/server/scope-read.mjs +257 -0
- package/resolve-advanced/server/season-look.mjs +96 -0
- package/resolve-advanced/server/shot-intent.mjs +82 -0
- package/resolve-advanced/server/shot-match.mjs +147 -0
- package/resolve-advanced/server/skin-match.mjs +205 -0
- package/resolve-advanced/server/spec-compile.mjs +217 -0
- package/resolve-advanced/server/tone-curve-transfer.mjs +184 -0
- package/resolve-advanced/server/tool-catalog.mjs +265 -0
- package/resolve-advanced/server/tools/audio.mjs +54 -0
- package/resolve-advanced/server/tools/audio_plan.mjs +58 -0
- package/resolve-advanced/server/tools/capabilities.mjs +16 -0
- package/resolve-advanced/server/tools/color_trace.mjs +165 -0
- package/resolve-advanced/server/tools/conform.mjs +291 -0
- package/resolve-advanced/server/tools/deliverable.mjs +105 -0
- package/resolve-advanced/server/tools/drp.mjs +232 -0
- package/resolve-advanced/server/tools/drt.mjs +200 -0
- package/resolve-advanced/server/tools/drx.mjs +943 -0
- package/resolve-advanced/server/tools/editorial.mjs +69 -0
- package/resolve-advanced/server/tools/fairlight.mjs +108 -0
- package/resolve-advanced/server/tools/fusion.mjs +64 -0
- package/resolve-advanced/server/tools/media.mjs +102 -0
- package/resolve-advanced/server/tools/offline_ref.mjs +123 -0
- package/resolve-advanced/server/tools/pipeline.mjs +137 -0
- package/resolve-advanced/server/tools/project_db.mjs +200 -0
- package/resolve-advanced/server/tools/project_read.mjs +212 -0
- package/resolve-advanced/server/tools/provenance.mjs +73 -0
- package/resolve-advanced/server/verify-grade.mjs +113 -0
- package/resolve-advanced/server/white-balance-match.mjs +122 -0
- package/resolve-advanced/vendor/audio/format-converter.js +330 -0
- package/resolve-advanced/vendor/audio/split.js +173 -0
- package/resolve-advanced/vendor/audio/trim.js +188 -0
- package/resolve-advanced/vendor/audio-fairlight/index.js +391 -0
- package/resolve-advanced/vendor/conform-qc/adapters/frame-sampler.js +56 -0
- package/resolve-advanced/vendor/conform-qc/adapters/local-ffmpeg-sampler.js +65 -0
- package/resolve-advanced/vendor/conform-qc/adapters/rendernode-ffmpeg-sampler.js +50 -0
- package/resolve-advanced/vendor/conform-qc/adapters/resolve/driver.py +176 -0
- package/resolve-advanced/vendor/conform-qc/adapters/resolve-driver.js +61 -0
- package/resolve-advanced/vendor/conform-qc/adapters/resolve-headless-driver.js +86 -0
- package/resolve-advanced/vendor/conform-qc/adapters/vision-validator.js +75 -0
- package/resolve-advanced/vendor/conform-qc/cli.js +63 -0
- package/resolve-advanced/vendor/conform-qc/compare/advisory.js +106 -0
- package/resolve-advanced/vendor/conform-qc/compare/decode.js +36 -0
- package/resolve-advanced/vendor/conform-qc/compare/index.js +61 -0
- package/resolve-advanced/vendor/conform-qc/compare/locate.js +70 -0
- package/resolve-advanced/vendor/conform-qc/compare/metrics.js +409 -0
- package/resolve-advanced/vendor/conform-qc/docs/runbook.md +72 -0
- package/resolve-advanced/vendor/conform-qc/index.js +49 -0
- package/resolve-advanced/vendor/conform-qc/knowledge/index.js +110 -0
- package/resolve-advanced/vendor/conform-qc/ops/conform-core.js +137 -0
- package/resolve-advanced/vendor/conform-qc/ops/conform-diff.js +109 -0
- package/resolve-advanced/vendor/conform-qc/ops/insert.js +108 -0
- package/resolve-advanced/vendor/conform-qc/ops/local-conform.js +61 -0
- package/resolve-advanced/vendor/conform-qc/ops/patch.js +80 -0
- package/resolve-advanced/vendor/conform-qc/ops/trigger.js +32 -0
- package/resolve-advanced/vendor/conform-qc/ops/verify.js +105 -0
- package/resolve-advanced/vendor/conform-qc/ops/workflow.js +30 -0
- package/resolve-advanced/vendor/conform-qc/oracle/emulate.js +155 -0
- package/resolve-advanced/vendor/conform-qc/oracle/index.js +38 -0
- package/resolve-advanced/vendor/conform-qc/oracle/resolve.js +196 -0
- package/resolve-advanced/vendor/conform-qc/package.json +16 -0
- package/resolve-advanced/vendor/conform-qc/packaging/emit-aaf.js +30 -0
- package/resolve-advanced/vendor/conform-qc/packaging/emit-fcp7.js +64 -0
- package/resolve-advanced/vendor/conform-qc/packaging/index.js +169 -0
- package/resolve-advanced/vendor/conform-qc/packaging/media-ops.js +56 -0
- package/resolve-advanced/vendor/conform-qc/packaging/otio.js +50 -0
- package/resolve-advanced/vendor/conform-qc/packaging/relink.js +50 -0
- package/resolve-advanced/vendor/conform-qc/packaging/surgical-relink.js +195 -0
- package/resolve-advanced/vendor/conform-qc/parse/index.js +54 -0
- package/resolve-advanced/vendor/conform-qc/parse/merge-dto.js +27 -0
- package/resolve-advanced/vendor/conform-qc/parse/xmeml-geometry.js +256 -0
- package/resolve-advanced/vendor/conform-qc/reference/burnin-ocr.js +100 -0
- package/resolve-advanced/vendor/conform-qc/reference/sidecar.js +37 -0
- package/resolve-advanced/vendor/conform-qc/repair/analysis.js +62 -0
- package/resolve-advanced/vendor/conform-qc/repair/index.js +78 -0
- package/resolve-advanced/vendor/conform-qc/repair/media-analysis.js +139 -0
- package/resolve-advanced/vendor/conform-qc/repair/media-index.js +135 -0
- package/resolve-advanced/vendor/conform-qc/repair/strategies.js +250 -0
- package/resolve-advanced/vendor/conform-qc/report/index.js +133 -0
- package/resolve-advanced/vendor/conform-qc/roles/index.js +96 -0
- package/resolve-advanced/vendor/conform-qc/synthetic/generate.js +233 -0
- package/resolve-advanced/vendor/conform-qc/test/advisory.test.js +85 -0
- package/resolve-advanced/vendor/conform-qc/test/cli.test.js +39 -0
- package/resolve-advanced/vendor/conform-qc/test/compare.test.js +152 -0
- package/resolve-advanced/vendor/conform-qc/test/conform-diff.test.js +70 -0
- package/resolve-advanced/vendor/conform-qc/test/emulate.test.js +51 -0
- package/resolve-advanced/vendor/conform-qc/test/frame-sampler.test.js +30 -0
- package/resolve-advanced/vendor/conform-qc/test/geometry.test.js +112 -0
- package/resolve-advanced/vendor/conform-qc/test/knowledge.test.js +56 -0
- package/resolve-advanced/vendor/conform-qc/test/lifecycle.test.js +110 -0
- package/resolve-advanced/vendor/conform-qc/test/local-ffmpeg-sampler.test.js +66 -0
- package/resolve-advanced/vendor/conform-qc/test/locate.test.js +63 -0
- package/resolve-advanced/vendor/conform-qc/test/media-analysis.test.js +63 -0
- package/resolve-advanced/vendor/conform-qc/test/media-index-normalized.test.js +65 -0
- package/resolve-advanced/vendor/conform-qc/test/media-index-origin.test.js +53 -0
- package/resolve-advanced/vendor/conform-qc/test/metrics-fast.test.js +91 -0
- package/resolve-advanced/vendor/conform-qc/test/oracle-reverse.test.js +86 -0
- package/resolve-advanced/vendor/conform-qc/test/oracle.test.js +136 -0
- package/resolve-advanced/vendor/conform-qc/test/p0-acceptance.test.js +60 -0
- package/resolve-advanced/vendor/conform-qc/test/p1-acceptance.test.js +75 -0
- package/resolve-advanced/vendor/conform-qc/test/p45-patch-acceptance.test.js +102 -0
- package/resolve-advanced/vendor/conform-qc/test/packaging.test.js +133 -0
- package/resolve-advanced/vendor/conform-qc/test/parse-stubs.test.js +28 -0
- package/resolve-advanced/vendor/conform-qc/test/repair-strategies.test.js +128 -0
- package/resolve-advanced/vendor/conform-qc/test/repair.test.js +84 -0
- package/resolve-advanced/vendor/conform-qc/test/report.test.js +52 -0
- package/resolve-advanced/vendor/conform-qc/test/resolve-readback.test.js +71 -0
- package/resolve-advanced/vendor/conform-qc/test/roles.test.js +107 -0
- package/resolve-advanced/vendor/conform-qc/test/runbook.test.js +30 -0
- package/resolve-advanced/vendor/conform-qc/test/scale-residual.test.js +40 -0
- package/resolve-advanced/vendor/conform-qc/test/sidecar.test.js +51 -0
- package/resolve-advanced/vendor/conform-qc/test/smoke.test.js +87 -0
- package/resolve-advanced/vendor/conform-qc/test/surgical-relink.test.js +73 -0
- package/resolve-advanced/vendor/conform-qc/test/synthetic.test.js +98 -0
- package/resolve-advanced/vendor/conform-qc/test/verify.test.js +93 -0
- package/resolve-advanced/vendor/conform-qc/test/vision-validator.test.js +43 -0
- package/resolve-advanced/vendor/conform-qc/test/workflow-driver.test.js +46 -0
- package/resolve-advanced/vendor/conform-qc/toolset/index.js +53 -0
- package/resolve-advanced/vendor/drp-format/README.md +116 -0
- package/resolve-advanced/vendor/drp-format/__tests__/_resolve-verify.js +39 -0
- package/resolve-advanced/vendor/drp-format/__tests__/add-media-clip.test.js +30 -0
- package/resolve-advanced/vendor/drp-format/__tests__/assemble-timeline.test.js +68 -0
- package/resolve-advanced/vendor/drp-format/__tests__/author-project.test.js +57 -0
- package/resolve-advanced/vendor/drp-format/__tests__/composition-text.test.js +98 -0
- package/resolve-advanced/vendor/drp-format/__tests__/diff.test.js +272 -0
- package/resolve-advanced/vendor/drp-format/__tests__/effect-filters-compressed.test.js +143 -0
- package/resolve-advanced/vendor/drp-format/__tests__/fixtures/p0-3-session30-empty-effectfilters.drp +0 -0
- package/resolve-advanced/vendor/drp-format/__tests__/fixtures/retimed-timemap-50pct.hex +1 -0
- package/resolve-advanced/vendor/drp-format/__tests__/fixtures/retimed-timemap-dynamic.hex +1 -0
- package/resolve-advanced/vendor/drp-format/__tests__/inject-grades.test.js +238 -0
- package/resolve-advanced/vendor/drp-format/__tests__/keyed-dict.test.js +85 -0
- package/resolve-advanced/vendor/drp-format/__tests__/lut-refs.test.js +119 -0
- package/resolve-advanced/vendor/drp-format/__tests__/media-blobs.test.js +25 -0
- package/resolve-advanced/vendor/drp-format/__tests__/media-timemap.test.js +119 -0
- package/resolve-advanced/vendor/drp-format/__tests__/place-fusion-title.test.js +52 -0
- package/resolve-advanced/vendor/drp-format/__tests__/place-generator.test.js +40 -0
- package/resolve-advanced/vendor/drp-format/__tests__/place-transition.test.js +48 -0
- package/resolve-advanced/vendor/drp-format/__tests__/protobuf-wire.test.js +64 -0
- package/resolve-advanced/vendor/drp-format/__tests__/relink-media.test.js +106 -0
- package/resolve-advanced/vendor/drp-format/__tests__/splice-clips.test.js +256 -0
- package/resolve-advanced/vendor/drp-format/assemble-timeline.js +65 -0
- package/resolve-advanced/vendor/drp-format/author-project.js +118 -0
- package/resolve-advanced/vendor/drp-format/composition-text.js +213 -0
- package/resolve-advanced/vendor/drp-format/curves-encoder.js +763 -0
- package/resolve-advanced/vendor/drp-format/diff.js +310 -0
- package/resolve-advanced/vendor/drp-format/drp-packager.js +201 -0
- package/resolve-advanced/vendor/drp-format/drp-validator.js +809 -0
- package/resolve-advanced/vendor/drp-format/effect-encoder.js +640 -0
- package/resolve-advanced/vendor/drp-format/extract-lut-refs.js +119 -0
- package/resolve-advanced/vendor/drp-format/grade-encoder.example.js +133 -0
- package/resolve-advanced/vendor/drp-format/grade-encoder.js +401 -0
- package/resolve-advanced/vendor/drp-format/grade-encoder.test.js +171 -0
- package/resolve-advanced/vendor/drp-format/grade-encoder.verify.js +249 -0
- package/resolve-advanced/vendor/drp-format/grade-node-extractor.js +495 -0
- package/resolve-advanced/vendor/drp-format/grade-parameter-decoder.js +774 -0
- package/resolve-advanced/vendor/drp-format/index.js +174 -0
- package/resolve-advanced/vendor/drp-format/inject-grades.js +219 -0
- package/resolve-advanced/vendor/drp-format/keyed-dict.js +227 -0
- package/resolve-advanced/vendor/drp-format/marker-encoder.js +532 -0
- package/resolve-advanced/vendor/drp-format/media-blobs.js +53 -0
- package/resolve-advanced/vendor/drp-format/media-timemap.js +164 -0
- package/resolve-advanced/vendor/drp-format/mp-folder-builder.js +293 -0
- package/resolve-advanced/vendor/drp-format/node-tree-encoder.js +1246 -0
- package/resolve-advanced/vendor/drp-format/package.json +18 -0
- package/resolve-advanced/vendor/drp-format/place-fusion-title.js +131 -0
- package/resolve-advanced/vendor/drp-format/place-generator.js +77 -0
- package/resolve-advanced/vendor/drp-format/place-transition.js +91 -0
- package/resolve-advanced/vendor/drp-format/power-window-encoder.js +776 -0
- package/resolve-advanced/vendor/drp-format/protobuf-wire.js +111 -0
- package/resolve-advanced/vendor/drp-format/qualifier-encoder.js +706 -0
- package/resolve-advanced/vendor/drp-format/relink-media.js +218 -0
- package/resolve-advanced/vendor/drp-format/rich-title-encoder.js +447 -0
- package/resolve-advanced/vendor/drp-format/seq-container-builder.js +572 -0
- package/resolve-advanced/vendor/drp-format/seq-surgery.js +155 -0
- package/resolve-advanced/vendor/drp-format/splice-clips.js +445 -0
- package/resolve-advanced/vendor/drp-format/templates/empty-project.drp +0 -0
- package/resolve-advanced/vendor/drp-format/templates/fusion-title.xml +56 -0
- package/resolve-advanced/vendor/drp-format/templates/generator-solid-color.xml +21 -0
- package/resolve-advanced/vendor/drp-format/templates/media-clip-h264.drp +0 -0
- package/resolve-advanced/vendor/drp-format/templates/transition-cross-dissolve.xml +22 -0
- package/resolve-advanced/vendor/drp-format/tool-registry.descriptor.js +80 -0
- package/resolve-advanced/vendor/drp-format/utils/safe-archive.js +54 -0
- package/resolve-advanced/vendor/drp-format/xml-builder.js +759 -0
- package/resolve-advanced/vendor/drt-format/__tests__/_resolve-verify.js +21 -0
- package/resolve-advanced/vendor/drt-format/__tests__/build.test.js +113 -0
- package/resolve-advanced/vendor/drt-format/__tests__/multi-format.test.js +93 -0
- package/resolve-advanced/vendor/drt-format/__tests__/parse-real-resolve21.test.js +51 -0
- package/resolve-advanced/vendor/drt-format/__tests__/parse.test.js +134 -0
- package/resolve-advanced/vendor/drt-format/__tests__/resolve-versions.test.js +120 -0
- package/resolve-advanced/vendor/drt-format/__tests__/schema-fingerprint.test.js +62 -0
- package/resolve-advanced/vendor/drt-format/__tests__/smoke.test.js +27 -0
- package/resolve-advanced/vendor/drt-format/__tests__/validate.test.js +109 -0
- package/resolve-advanced/vendor/drt-format/capabilities.js +69 -0
- package/resolve-advanced/vendor/drt-format/capability-domains.js +56 -0
- package/resolve-advanced/vendor/drt-format/drt-builder.js +42 -0
- package/resolve-advanced/vendor/drt-format/drt-parser.js +164 -0
- package/resolve-advanced/vendor/drt-format/drt-validator.js +98 -0
- package/resolve-advanced/vendor/drt-format/index.js +45 -0
- package/resolve-advanced/vendor/drt-format/package.json +17 -0
- package/resolve-advanced/vendor/drt-format/resolve-versions.js +153 -0
- package/resolve-advanced/vendor/drt-format/schema-fingerprint.js +74 -0
- package/resolve-advanced/vendor/drt-format/templates/drt-project-shell.xml +124 -0
- package/resolve-advanced/vendor/drx-codec/__tests__/curves-roundtrip.test.js +148 -0
- package/resolve-advanced/vendor/drx-codec/__tests__/fixtures/p2-1-face-refinement.drx +58 -0
- package/resolve-advanced/vendor/drx-codec/__tests__/fixtures/p2-1-filmgrain.drx +58 -0
- package/resolve-advanced/vendor/drx-codec/__tests__/fixtures/p2-1-glow.drx +58 -0
- package/resolve-advanced/vendor/drx-codec/__tests__/fixtures/p2-1-lens-flare.drx +58 -0
- package/resolve-advanced/vendor/drx-codec/__tests__/fixtures/p2-3-beauty-25.drx +58 -0
- package/resolve-advanced/vendor/drx-codec/__tests__/fixtures/p2-3-beauty-75.drx +58 -0
- package/resolve-advanced/vendor/drx-codec/__tests__/fixtures/p5-1-node-no-lut.drx +58 -0
- package/resolve-advanced/vendor/drx-codec/__tests__/fixtures/p5-1-node-with-lut.drx +58 -0
- package/resolve-advanced/vendor/drx-codec/__tests__/hsl-curves-roundtrip.test.js +117 -0
- package/resolve-advanced/vendor/drx-codec/__tests__/lut-refs-roundtrip.test.js +112 -0
- package/resolve-advanced/vendor/drx-codec/__tests__/matte-roundtrip.test.js +167 -0
- package/resolve-advanced/vendor/drx-codec/__tests__/ofx-roundtrip.test.js +215 -0
- package/resolve-advanced/vendor/drx-codec/__tests__/ofx-slugs-discovery.test.js +149 -0
- package/resolve-advanced/vendor/drx-codec/__tests__/power-window-roundtrip.test.js +230 -0
- package/resolve-advanced/vendor/drx-codec/__tests__/qualifier-roundtrip.test.js +226 -0
- package/resolve-advanced/vendor/drx-codec/cdl-exporter.js +470 -0
- package/resolve-advanced/vendor/drx-codec/color-nlp-parser.js +833 -0
- package/resolve-advanced/vendor/drx-codec/data/color-nlp-action-mappings.json +2232 -0
- package/resolve-advanced/vendor/drx-codec/drx-generator.js +4123 -0
- package/resolve-advanced/vendor/drx-codec/drx-merger.js +320 -0
- package/resolve-advanced/vendor/drx-codec/drx-parser.js +1808 -0
- package/resolve-advanced/vendor/drx-codec/extract-custom-curves.js +215 -0
- package/resolve-advanced/vendor/drx-codec/extract-hsl-curves.js +180 -0
- package/resolve-advanced/vendor/drx-codec/extract-lut-refs.js +158 -0
- package/resolve-advanced/vendor/drx-codec/extract-matte-finesse.js +83 -0
- package/resolve-advanced/vendor/drx-codec/extract-ofx-params.js +226 -0
- package/resolve-advanced/vendor/drx-codec/extract-power-window.js +184 -0
- package/resolve-advanced/vendor/drx-codec/extract-qualifier.js +99 -0
- package/resolve-advanced/vendor/drx-codec/index.js +109 -0
- package/resolve-advanced/vendor/drx-codec/node-layout.js +249 -0
- package/resolve-advanced/vendor/drx-codec/resolved-drx-generator.js +393 -0
- package/resolve-advanced/vendor/drx-codec/tool-resolver.js +974 -0
- package/resolve-advanced/vendor/drx-codec/training-examples.js +548 -0
- package/resolve-advanced/vendor/drx-codec/vocabulary-intents.js +539 -0
- package/resolve-advanced/vendor/drx-parameters/CALIBRATION-STATUS.md +319 -0
- package/resolve-advanced/vendor/drx-parameters/DRX-VALUE-SCALING.md +251 -0
- package/resolve-advanced/vendor/drx-parameters/calibrated-ranges.json +17737 -0
- package/resolve-advanced/vendor/drx-parameters/corrector-types.js +120 -0
- package/resolve-advanced/vendor/drx-parameters/index.js +193 -0
- package/resolve-advanced/vendor/drx-parameters/parameter-codec.js +451 -0
- package/resolve-advanced/vendor/drx-parameters/parameter-ids.js +1292 -0
- package/resolve-advanced/vendor/drx-parameters/parameter-ranges.js +570 -0
- package/resolve-advanced/vendor/drx-parameters/parameter-validator.js +392 -0
- package/resolve-advanced/vendor/drx-parameters/resolvefx-registry.json +14973 -0
- package/resolve-advanced/vendor/drx-parameters/tool-registry.descriptor.js +38 -0
- package/resolve-advanced/vendor/drx-parameters/tools/drx-analyzer.js +371 -0
- package/resolve-advanced/vendor/fairlight/index.js +833 -0
- package/resolve-advanced/vendor/fusion-codec/composition-generator.js +401 -0
- package/resolve-advanced/vendor/fusion-codec/templates/blur-region.js +103 -0
- package/resolve-advanced/vendor/fusion-codec/templates/color-correct.js +87 -0
- package/resolve-advanced/vendor/fusion-codec/templates/film-grain.js +106 -0
- package/resolve-advanced/vendor/fusion-codec/templates/lower-third.js +241 -0
- package/resolve-advanced/vendor/fusion-codec/templates/picture-in-picture.js +188 -0
- package/resolve-advanced/vendor/fusion-codec/templates/text-overlay.js +161 -0
- package/resolve-advanced/vendor/fusion-codec/templates/title-card.js +184 -0
- package/resolve-advanced/vendor/fusion-codec/templates/vignette.js +107 -0
- package/resolve-advanced/vendor/fusion-codec/templates/watermark.js +101 -0
- package/scripts/agent-rules/README.md +68 -0
- package/src/analysis_dashboard.py +233 -1
- package/src/granular/common.py +1 -1
- package/src/server.py +479 -29
- package/src/utils/api_truth.py +117 -0
- package/src/utils/cut_ir.py +1 -1
- package/src/utils/failure_tracker.py +0 -2
- package/src/utils/timeline_xml.py +405 -0
package/src/server.py
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
"""
|
|
3
3
|
DaVinci Resolve MCP Server (Compound Tools)
|
|
4
4
|
|
|
5
|
-
|
|
5
|
+
34 compound tools covering 100% of the DaVinci Resolve Scripting API (336 methods)
|
|
6
6
|
plus Fusion Fuse, DCTL, and Resolve-page Script authoring tools.
|
|
7
7
|
Each tool groups related operations via an 'action' parameter.
|
|
8
8
|
|
|
@@ -11,7 +11,7 @@ Usage:
|
|
|
11
11
|
python src/server.py --full # Start the 341-tool granular server instead
|
|
12
12
|
"""
|
|
13
13
|
|
|
14
|
-
VERSION = "2.
|
|
14
|
+
VERSION = "2.58.0"
|
|
15
15
|
|
|
16
16
|
import base64
|
|
17
17
|
import os
|
|
@@ -104,6 +104,7 @@ from src.utils.timeline_title_text import (
|
|
|
104
104
|
timeline_item_get_property_map as _timeline_item_get_property_map,
|
|
105
105
|
)
|
|
106
106
|
from src.utils.multicam import build_multicam_setup_plan
|
|
107
|
+
from src.utils.timeline_xml import analyze_timeline_xml, sanitize_timeline_xml
|
|
107
108
|
from src.utils.fusion_group_settings import (
|
|
108
109
|
FUSION_COMMIT_CHECKLIST,
|
|
109
110
|
FUSION_GROUP_GUARDRAILS,
|
|
@@ -402,7 +403,7 @@ When finished, report exactly which media_analysis call was made, whether artifa
|
|
|
402
403
|
|
|
403
404
|
|
|
404
405
|
# ─── F2 — MCP Prompts for common multi-step workflows ──────────────────────────
|
|
405
|
-
#
|
|
406
|
+
# (agentic-flow improvement F2: structured confirm-token envelope.)
|
|
406
407
|
# These surface as slash commands in the host UI (e.g. /davinci-resolve:match-bin-to-hero).
|
|
407
408
|
|
|
408
409
|
|
|
@@ -508,6 +509,224 @@ def prep_color_handoff(output_dir: str = "") -> str:
|
|
|
508
509
|
5. Surface the manifest path back to the user. Do not write beside source media."""
|
|
509
510
|
|
|
510
511
|
|
|
512
|
+
# ─── Per-domain workflow routers ───────────────────────────────────────────────
|
|
513
|
+
# Cross-platform depth: these surface as slash commands in EVERY MCP client
|
|
514
|
+
# (Codex, Cursor, Copilot, Continue, Claude Desktop, …), so per-domain routing is
|
|
515
|
+
# not limited to Claude Code's .claude/skills/. They mirror the repo skills of the
|
|
516
|
+
# same name; keep them in sync with docs/kernels/*.
|
|
517
|
+
|
|
518
|
+
|
|
519
|
+
@mcp.prompt(
|
|
520
|
+
name="color_grade_workflow",
|
|
521
|
+
title="Color / Grade Workflow",
|
|
522
|
+
description="Route a grading/look/shot-match task across the live color tools and the offline advanced grading/QC catalog.",
|
|
523
|
+
)
|
|
524
|
+
def color_grade_workflow() -> str:
|
|
525
|
+
return """Color / grade work spans two servers: the live Python server drives a
|
|
526
|
+
running Resolve; the advanced (offline) server computes grades from frames and
|
|
527
|
+
reads/writes .drx/.drp with no Resolve open. Compute offline, apply live.
|
|
528
|
+
|
|
529
|
+
Frame-first rule (non-negotiable): before applying any grade, look, shot match,
|
|
530
|
+
LUT, CDL, DRX, or copied grade, inspect representative Resolve-rendered frames
|
|
531
|
+
(thumbnails/contact sheet/Gallery stills/marker frames) and compare
|
|
532
|
+
bypass/current/after at matched timecodes; restore prior version/node state after
|
|
533
|
+
a temporary bypass. Never grade from metadata or a style label alone. Preserve a
|
|
534
|
+
recoverable grade version.
|
|
535
|
+
|
|
536
|
+
- Live: timeline_item_color.grade_boundary_report / probe_node_graph /
|
|
537
|
+
safe_set_cdl / safe_apply_drx / grade_version_snapshot|restore; graph;
|
|
538
|
+
gallery_stills; color_group.
|
|
539
|
+
- Offline (advanced server `drx` actions): match_to_reference, level_clips,
|
|
540
|
+
skin_match, shot_match, white_balance_match, contrast_normalize,
|
|
541
|
+
saturation_match, black_balance, cdl_io, grade_transfer, lut_apply,
|
|
542
|
+
author_look|carry_look, scope_read|intent_tags|gamut_legal, verify_grade.
|
|
543
|
+
- Value space: drx generate/merge default to space='ui' (panel units, saturation
|
|
544
|
+
0-100 neutral 50); a `warnings` array means a hue curve rendered FLAT — surface
|
|
545
|
+
it. safe_apply_drx defaults to V1/item0 — always pass explicit track/item indices
|
|
546
|
+
and back up a still first; ApplyGradeFromDRX replaces the graph.
|
|
547
|
+
- Relayout ("Cleanup Node Graph", no UI API): grab still -> drx relayout ->
|
|
548
|
+
graph.reset_all_grades -> safe_apply_drx (a same-structure apply keeps the old
|
|
549
|
+
layout). Whole project: project_db.relayout_node_graphs.
|
|
550
|
+
|
|
551
|
+
Depth: docs/kernels/color-grade-kernel.md, docs/guides/color-decision-guide.md.
|
|
552
|
+
The advanced grading catalog needs `sharp`; call the advanced `capabilities` tool.
|
|
553
|
+
Never modify/transcode/derive source media (see AGENTS.md)."""
|
|
554
|
+
|
|
555
|
+
|
|
556
|
+
@mcp.prompt(
|
|
557
|
+
name="timeline_edit_workflow",
|
|
558
|
+
title="Timeline Edit Workflow",
|
|
559
|
+
description="Route a cutting/trimming/restructuring/changelist task across the live edit tools and the offline editorial tools.",
|
|
560
|
+
)
|
|
561
|
+
def timeline_edit_workflow() -> str:
|
|
562
|
+
return """Editing spans two servers: the live Python server restructures a
|
|
563
|
+
running timeline; the advanced (offline) server authors/diffs .drt files and
|
|
564
|
+
reasons over editorial interchange with no Resolve open.
|
|
565
|
+
|
|
566
|
+
- Live: timeline duplicate_clips/copy_clips/move_clips (include_linked carries
|
|
567
|
+
linked audio); copy_range/duplicate_range/overwrite_range/lift_range (no public
|
|
568
|
+
razor/split — partial overlaps blocked unless allow_partial_item_delete);
|
|
569
|
+
copy_properties (scope with a group list); edit_engine (selects/tighten/swap,
|
|
570
|
+
plan -> confirm -> execute; tighten can carry audio via keep_ranges/include_audio).
|
|
571
|
+
- Offline (advanced server `editorial` actions): parse_interchange (EDL/OTIO/XMEML;
|
|
572
|
+
AAF = honest refuse), turnover_changelist (moved/retimed/replaced/new/gone with
|
|
573
|
+
timing guards), conform_manifest, marker_roundtrip; `drt` for timeline files.
|
|
574
|
+
|
|
575
|
+
Use the offline tools to answer "what changed between v3 and v4" without opening
|
|
576
|
+
either cut. Edits reference existing Media Pool items — never transcode/proxy/derive
|
|
577
|
+
source media (see AGENTS.md).
|
|
578
|
+
|
|
579
|
+
Depth: docs/kernels/timeline-edit-kernel.md, docs/guides/editorial-decision-guide.md."""
|
|
580
|
+
|
|
581
|
+
|
|
582
|
+
@mcp.prompt(
|
|
583
|
+
name="conform_workflow",
|
|
584
|
+
title="Conform / Interchange Workflow",
|
|
585
|
+
description="Route a conform/relink/finishing-QC/grade-trace task across the live conform tools and the offline conform QC engine.",
|
|
586
|
+
)
|
|
587
|
+
def conform_workflow() -> str:
|
|
588
|
+
return """Conforming spans two servers: the live Python server imports/relinks/
|
|
589
|
+
compares a running conform; the advanced (offline) server does frame-oracle QC,
|
|
590
|
+
reverse-subclip repair, lineage, and grade tracing with no Resolve open.
|
|
591
|
+
|
|
592
|
+
- Live: timeline probe_timeline_structure / detect_gaps_overlaps /
|
|
593
|
+
source_range_report / conform_boundary_report; export_timeline_checked /
|
|
594
|
+
import_timeline_checked (drt is the only lossless project-native round-trip;
|
|
595
|
+
EDL/FCPXML drop relationships); detect_missing_media -> build_relink_plan
|
|
596
|
+
(read-only, bounded) -> media_pool.safe_relink with approved paths only.
|
|
597
|
+
- XML import via the scripting API goes OFFLINE (missing-media/generators abort);
|
|
598
|
+
use import_timeline_checked with media sanitize (FCP7/FCPXML), then exact-path
|
|
599
|
+
relink; restart a running MCP server to pick up the sanitize fix.
|
|
600
|
+
- Offline (advanced server): conform (frame-oracle QC — catches wrong-but-similar
|
|
601
|
+
relinks; reversed source_start = masterFrames-1-endoffset; lineage store+diff;
|
|
602
|
+
per-cut frame QC vs reference render), color_trace (carry grades across a
|
|
603
|
+
re-conform), offline_ref (<OfflineClip> patch — no scripting API), editorial,
|
|
604
|
+
drt, project_db.
|
|
605
|
+
- .drt for Resolve 19.1.3: set DbPrjVer 17 -> 16. project_db patches need the
|
|
606
|
+
project CLOSED + iConfirmProjectClosed:true, auto-backup + read-back verify, and
|
|
607
|
+
a full QUIT+relaunch of Resolve before the change is visible.
|
|
608
|
+
|
|
609
|
+
Depth: docs/kernels/timeline-conform-interchange-kernel.md. better-sqlite3 gates
|
|
610
|
+
lineage/reverse/DB, sharp/ffmpeg gate frame compare — call advanced `capabilities`.
|
|
611
|
+
Relink plans are read-only until executed; never derive source media (see AGENTS.md)."""
|
|
612
|
+
|
|
613
|
+
|
|
614
|
+
@mcp.prompt(
|
|
615
|
+
name="delivery_workflow",
|
|
616
|
+
title="Delivery / Deliverable QC Workflow",
|
|
617
|
+
description="Route a render/deliverable-QC/media-provenance task across the live render tools and the offline deliverable/media/provenance tools.",
|
|
618
|
+
)
|
|
619
|
+
def delivery_workflow() -> str:
|
|
620
|
+
return """Delivery spans two servers: the live Python server plans/validates/runs
|
|
621
|
+
renders in a running Resolve; the advanced (offline) server QCs the FINISHED render
|
|
622
|
+
and manages media/provenance with no Resolve open. Deliverable QC is report-only:
|
|
623
|
+
gate=review, never auto-pass-clear.
|
|
624
|
+
|
|
625
|
+
- Live: render probe_render_matrix -> validate_render_settings ->
|
|
626
|
+
safe_set_render_settings (dry-run) -> prepare_render_job (adds, does not start;
|
|
627
|
+
temp output dirs by default). safe_quick_export forces EnableUpload=False and
|
|
628
|
+
needs allow_render=True. GetRenderSettings readback is version/page dependent.
|
|
629
|
+
- Offline `deliverable` actions: deliverable_qc (ffprobe vs spec, pass/fail per
|
|
630
|
+
field), loudness_qc (ebur128 LUFS/true-peak/LRA), reframe_blanking_check,
|
|
631
|
+
conform_completeness, re_delivery_diff, render_manifest, expand_deliverable
|
|
632
|
+
(texted/textless/stems/slate/leader).
|
|
633
|
+
- Offline `media`: ingest_verify (hash seal/verify/dupes), media_inventory,
|
|
634
|
+
sync (picture<->sound TC + drift/MOS), relink_manifest, rename_plan (refuses
|
|
635
|
+
camera originals) / reel_normalize, turnover_package, project_hygiene.
|
|
636
|
+
- Offline `provenance`: grade_provenance, gallery_lineage, cdl_export/cdl_diff
|
|
637
|
+
(round-trip asserted), revision_tracking, episode_report.
|
|
638
|
+
|
|
639
|
+
QC refuses rather than fabricates; gates never auto-clear — surface per-field
|
|
640
|
+
verdicts to a human. deliverable/media QC needs ffmpeg+ffprobe on PATH (GPL, not
|
|
641
|
+
bundled) — call advanced `capabilities`. Render probes touch only synthetic
|
|
642
|
+
fixtures, never user source media (see AGENTS.md).
|
|
643
|
+
|
|
644
|
+
Depth: docs/kernels/render-deliver-kernel.md."""
|
|
645
|
+
|
|
646
|
+
|
|
647
|
+
@mcp.prompt(
|
|
648
|
+
name="fusion_workflow",
|
|
649
|
+
title="Fusion Composition Workflow",
|
|
650
|
+
description="Route a Fusion comp task across the live fusion_comp tools and the offline .comp authoring tool.",
|
|
651
|
+
)
|
|
652
|
+
def fusion_workflow() -> str:
|
|
653
|
+
return """Fusion work spans two servers: the live Python server builds a comp on a
|
|
654
|
+
running timeline item; the advanced (offline) server authors a .comp from a spec
|
|
655
|
+
or template with no Resolve open. Author offline, apply live.
|
|
656
|
+
|
|
657
|
+
- Live: fusion_comp probe_fusion_comp / probe_fusion_tool / safe_add_tool /
|
|
658
|
+
safe_set_inputs / safe_connect_tools / fusion_boundary_report.
|
|
659
|
+
- Offline (advanced `fusion` tool): generate / generate_from_template /
|
|
660
|
+
list_templates / to_api_calls.
|
|
661
|
+
|
|
662
|
+
Flow: fusion generate|to_api_calls offline -> apply live via safe_add_tool ->
|
|
663
|
+
safe_set_inputs -> safe_connect_tools (to_api_calls maps directly onto those).
|
|
664
|
+
Probe first — tool availability and input readability vary by Resolve/Fusion
|
|
665
|
+
build; some inputs coerce or are write-only; bulk mutation needs timeline scope,
|
|
666
|
+
not the active Fusion page.
|
|
667
|
+
|
|
668
|
+
Depth: docs/kernels/fusion-composition-kernel.md. Never derive source media (AGENTS.md)."""
|
|
669
|
+
|
|
670
|
+
|
|
671
|
+
@mcp.prompt(
|
|
672
|
+
name="audio_workflow",
|
|
673
|
+
title="Audio / Fairlight Workflow",
|
|
674
|
+
description="Route an audio/Fairlight task across the live audio tools and the offline planning/bus-routing tools.",
|
|
675
|
+
)
|
|
676
|
+
def audio_workflow() -> str:
|
|
677
|
+
return """Audio work spans two servers: the live Python server drives audio on a
|
|
678
|
+
running Resolve; the advanced (offline) server plans tracks, routes buses, and
|
|
679
|
+
edits audio files with no Resolve open. Plan/measure offline, apply live.
|
|
680
|
+
|
|
681
|
+
- Live: timeline probe_audio_item|track / safe_set_audio_properties /
|
|
682
|
+
safe_auto_sync_audio / voice_isolation_capabilities / subtitle_generation_probe
|
|
683
|
+
/ fairlight_boundary_report.
|
|
684
|
+
- Offline `audio_plan` (pure Node): list_templates, select_template, track_plan,
|
|
685
|
+
analyze_coverage, check_loudness (R128 -23 / ATSC -24 / streaming -14).
|
|
686
|
+
- Offline `fairlight`: bus routing has NO scripting API — patches the
|
|
687
|
+
FLStudioModelBA blob. read_buses_from_blob (offline); read_buses_from_db,
|
|
688
|
+
expand_buses, export_template/import_template, backup, restore (DB path; needs
|
|
689
|
+
better-sqlite3; project CLOSED + quit/relaunch like other DB patches).
|
|
690
|
+
- Offline `audio`: split (silence/TC/intervals) / trim / convert (needs ffmpeg on
|
|
691
|
+
PATH — GPL, not bundled). Align/loudness-measure not yet vendored.
|
|
692
|
+
|
|
693
|
+
Timeline audio SetProperty (e.g. Volume) can return false for some item types;
|
|
694
|
+
the public API exposes no Fairlight automation curves — use fairlight for bus
|
|
695
|
+
structure only. The offline audio ops write NEW files to scratch, never over
|
|
696
|
+
source (AGENTS.md).
|
|
697
|
+
|
|
698
|
+
Depth: docs/kernels/audio-fairlight-kernel.md."""
|
|
699
|
+
|
|
700
|
+
|
|
701
|
+
@mcp.prompt(
|
|
702
|
+
name="media_pool_workflow",
|
|
703
|
+
title="Media Pool / Ingest Workflow",
|
|
704
|
+
description="Route a media-pool ingest/organization task across the live media_pool tools and the offline media front-end tool.",
|
|
705
|
+
)
|
|
706
|
+
def media_pool_workflow() -> str:
|
|
707
|
+
return """Media pool work spans two servers: the live Python server imports and
|
|
708
|
+
organizes media in a running Resolve; the advanced (offline) server verifies and
|
|
709
|
+
inventories a card with no Resolve open. Verify offline, import live.
|
|
710
|
+
|
|
711
|
+
- Live: media_pool safe_import_media|sequence|folder / organize_clips /
|
|
712
|
+
normalize_metadata / safe_relink|unlink / link_proxy_checked / set_clip_marks /
|
|
713
|
+
setup_multicam_timeline.
|
|
714
|
+
- Offline `media` (needs ffmpeg + ffprobe on PATH): ingest_verify (hash
|
|
715
|
+
seal/verify/dupes), media_inventory (fps/codec/colorspace/TC + card gaps), sync
|
|
716
|
+
(picture<->sound TC + drift/MOS), relink_manifest, rename_plan (refuses camera
|
|
717
|
+
originals) / reel_normalize, turnover_package, project_hygiene.
|
|
718
|
+
|
|
719
|
+
Rule of thumb: verify + inventory the card offline BEFORE importing, then import
|
|
720
|
+
and organize live. Non-media files are not imported; the kernel never proxies,
|
|
721
|
+
transcodes, or derives source media. Native multicam clip creation isn't in the
|
|
722
|
+
public API — the setup helper preps a stacked timeline you convert in Resolve's
|
|
723
|
+
UI. Never rename/derive camera originals without explicit approval (AGENTS.md).
|
|
724
|
+
For reading/analyzing footage content use the analyze_media prompt; for
|
|
725
|
+
deliverable-side media QC use delivery_workflow.
|
|
726
|
+
|
|
727
|
+
Depth: docs/kernels/media-pool-ingest-kernel.md, docs/guides/multicam-setup-guide.md."""
|
|
728
|
+
|
|
729
|
+
|
|
511
730
|
# ─── Python Version Check ────────────────────────────────────────────────────
|
|
512
731
|
|
|
513
732
|
_py_ver = sys.version_info[:2]
|
|
@@ -862,13 +1081,15 @@ _media_analysis_module.register_caps_overrides_provider(_caps_overrides_provider
|
|
|
862
1081
|
def _resolve_safe_dir(path):
|
|
863
1082
|
"""Redirect sandbox/temp paths that Resolve can't access to ~/Desktop/resolve-stills.
|
|
864
1083
|
|
|
865
|
-
Covers macOS (/var/folders, /private/var
|
|
866
|
-
and Windows (AppData\\Local\\Temp) sandbox temp directories.
|
|
1084
|
+
Covers macOS (/var/folders, /private/var, /tmp, /private/tmp), Linux (/tmp,
|
|
1085
|
+
/var/tmp), and Windows (AppData\\Local\\Temp) sandbox temp directories.
|
|
867
1086
|
"""
|
|
868
1087
|
system_temp = tempfile.gettempdir()
|
|
869
1088
|
_is_sandbox = False
|
|
870
1089
|
if platform.system() == "Darwin":
|
|
871
|
-
|
|
1090
|
+
# /tmp is a symlink to /private/tmp on macOS — Resolve's still/gallery export
|
|
1091
|
+
# silently fails into both (live-verified 2026-07-03), same as /var/folders.
|
|
1092
|
+
_is_sandbox = path.startswith(("/var/", "/private/var/", "/tmp/", "/private/tmp/")) or path in ("/tmp", "/private/tmp")
|
|
872
1093
|
elif platform.system() == "Linux":
|
|
873
1094
|
_is_sandbox = path.startswith("/tmp") or path.startswith("/var/tmp")
|
|
874
1095
|
elif platform.system() == "Windows":
|
|
@@ -882,8 +1103,7 @@ def _resolve_safe_dir(path):
|
|
|
882
1103
|
return os.path.join(os.path.expanduser("~"), "Documents", "resolve-stills")
|
|
883
1104
|
return path
|
|
884
1105
|
|
|
885
|
-
# Error envelope categories
|
|
886
|
-
# and local/design/agentic-flow-improvements-gameplan-2.md D1 for the retryable
|
|
1106
|
+
# Error envelope categories (agentic-flow improvements A1/D1) — see the retryable
|
|
887
1107
|
# default policy. Lock these names; downstream agents and tests route on them.
|
|
888
1108
|
ERROR_CATEGORIES = (
|
|
889
1109
|
"precondition", # missing current timeline/clip/project; tell user what to do
|
|
@@ -5100,37 +5320,144 @@ def _export_timeline_checked(tl, p: Dict[str, Any]):
|
|
|
5100
5320
|
}
|
|
5101
5321
|
|
|
5102
5322
|
|
|
5323
|
+
def _timeline_media_coverage(tl) -> Dict[str, Any]:
|
|
5324
|
+
"""Count how many timeline items are linked to a Media Pool Item vs. offline.
|
|
5325
|
+
|
|
5326
|
+
An FCP7/FCPXML imported timeline whose media did not link has items with no
|
|
5327
|
+
backing Media Pool Item — this surfaces that honestly instead of claiming a
|
|
5328
|
+
clean import.
|
|
5329
|
+
"""
|
|
5330
|
+
total = 0
|
|
5331
|
+
linked = 0
|
|
5332
|
+
for track_type in ("video", "audio"):
|
|
5333
|
+
try:
|
|
5334
|
+
count = int(tl.GetTrackCount(track_type) or 0)
|
|
5335
|
+
except Exception:
|
|
5336
|
+
count = 0
|
|
5337
|
+
for i in range(1, count + 1):
|
|
5338
|
+
for item in (tl.GetItemListInTrack(track_type, i) or []):
|
|
5339
|
+
total += 1
|
|
5340
|
+
try:
|
|
5341
|
+
if item.GetMediaPoolItem():
|
|
5342
|
+
linked += 1
|
|
5343
|
+
except Exception:
|
|
5344
|
+
pass
|
|
5345
|
+
return {"total": total, "linked": linked, "offline": total - linked}
|
|
5346
|
+
|
|
5347
|
+
|
|
5103
5348
|
def _import_timeline_checked(proj, mp, p: Dict[str, Any]):
|
|
5104
5349
|
path = p.get("path")
|
|
5105
5350
|
if not path:
|
|
5106
5351
|
return _err("path is required")
|
|
5107
5352
|
if not os.path.exists(path):
|
|
5108
5353
|
return _err(f"path does not exist: {path}")
|
|
5109
|
-
|
|
5110
|
-
|
|
5354
|
+
# sanitize_media (alias: relink_media) rewrites the XML to drop clipitems that
|
|
5355
|
+
# reference missing media or are generators (slug/solid w/ no pathurl) — both
|
|
5356
|
+
# abort Resolve's scripting-API import and leave the timeline fully offline.
|
|
5357
|
+
# The original is only read; the sanitized copy lands in a temp dir, so the
|
|
5358
|
+
# temp-path guard never applies to it.
|
|
5359
|
+
sanitize = bool(p.get("sanitize_media") or p.get("relink_media"))
|
|
5360
|
+
if not sanitize and p.get("require_temp_path", True) and not _render_temp_path_ok(path):
|
|
5361
|
+
return _err(
|
|
5362
|
+
"path must be under the system temp directory unless require_temp_path=False",
|
|
5363
|
+
remediation="Pass require_temp_path=False to import from this location, or "
|
|
5364
|
+
"sanitize_media=True to rewrite the XML for reliable media linking.",
|
|
5365
|
+
)
|
|
5111
5366
|
options = dict(p.get("options") or {})
|
|
5112
5367
|
if p.get("timeline_name") and "timelineName" not in options:
|
|
5113
5368
|
options["timelineName"] = p["timeline_name"]
|
|
5114
5369
|
if "import_source_clips" in p and "importSourceClips" not in options:
|
|
5115
5370
|
options["importSourceClips"] = bool(p["import_source_clips"])
|
|
5371
|
+
|
|
5372
|
+
# Optional fuzzy relink: when search roots are given, missing-at-original-path
|
|
5373
|
+
# clips are matched against on-disk media (exact/ext-agnostic/normalized/reel)
|
|
5374
|
+
# and their pathurl rewritten so they relink instead of being dropped.
|
|
5375
|
+
search_roots = p.get("relink_search_roots") or p.get("search_roots")
|
|
5376
|
+
if isinstance(search_roots, str):
|
|
5377
|
+
search_roots = [search_roots]
|
|
5378
|
+
if search_roots and not sanitize:
|
|
5379
|
+
sanitize = True # relinking is meaningless without the sanitize/rewrite pass
|
|
5380
|
+
|
|
5381
|
+
sanitize_report = None
|
|
5382
|
+
import_path = path
|
|
5383
|
+
if sanitize:
|
|
5384
|
+
san_kwargs = {}
|
|
5385
|
+
if search_roots:
|
|
5386
|
+
san_kwargs["search_roots"] = list(search_roots)
|
|
5387
|
+
if p.get("relink_min_confidence") is not None:
|
|
5388
|
+
san_kwargs["min_confidence"] = float(p["relink_min_confidence"])
|
|
5389
|
+
if p.get("verify_visually") or p.get("reference_movie"):
|
|
5390
|
+
san_kwargs["verify_visually"] = True
|
|
5391
|
+
if p.get("reference_movie"):
|
|
5392
|
+
san_kwargs["reference_movie"] = p["reference_movie"]
|
|
5393
|
+
if p.get("verify_threshold") is not None:
|
|
5394
|
+
san_kwargs["verify_threshold"] = float(p["verify_threshold"])
|
|
5395
|
+
try:
|
|
5396
|
+
sres = sanitize_timeline_xml(path, **san_kwargs)
|
|
5397
|
+
except Exception as e:
|
|
5398
|
+
return _err(f"Failed to sanitize timeline XML: {e}",
|
|
5399
|
+
category="invalid_input")
|
|
5400
|
+
import_path = sres["output_path"]
|
|
5401
|
+
sanitize_report = {
|
|
5402
|
+
k: sres[k] for k in (
|
|
5403
|
+
"output_path", "timeline_name", "clip_total", "kept",
|
|
5404
|
+
"removed_total", "missing_media_count", "generator_count",
|
|
5405
|
+
"missing_media", "generators", "relinked_count", "relinked",
|
|
5406
|
+
"ambiguous_count", "ambiguous", "scan",
|
|
5407
|
+
"verified_count", "flagged_count", "flagged", "unverified_count",
|
|
5408
|
+
) if k in sres
|
|
5409
|
+
}
|
|
5410
|
+
|
|
5116
5411
|
if p.get("dry_run"):
|
|
5117
|
-
|
|
5412
|
+
out = _ok(path=path, import_path=import_path, options=options, would_import=True)
|
|
5413
|
+
if sanitize_report is not None:
|
|
5414
|
+
out["sanitize"] = sanitize_report
|
|
5415
|
+
return out
|
|
5416
|
+
|
|
5118
5417
|
before_ids = set()
|
|
5119
5418
|
for index in range(1, int(proj.GetTimelineCount() or 0) + 1):
|
|
5120
5419
|
tl_existing = proj.GetTimelineByIndex(index)
|
|
5121
5420
|
if tl_existing:
|
|
5122
5421
|
before_ids.add(str(tl_existing.GetUniqueId()))
|
|
5123
5422
|
with long_resolve_op("timeline.import_timeline_checked"):
|
|
5124
|
-
imported = mp.ImportTimelineFromFile(
|
|
5423
|
+
imported = mp.ImportTimelineFromFile(import_path, options)
|
|
5424
|
+
|
|
5425
|
+
# Resolve's API returns None even when it created an (offline) timeline. Detect
|
|
5426
|
+
# the newly-created timeline via the before/after id diff so we never report a
|
|
5427
|
+
# false "Failed to import" for what is really a partial success.
|
|
5428
|
+
api_returned_object = bool(imported)
|
|
5429
|
+
if not imported:
|
|
5430
|
+
for index in range(1, int(proj.GetTimelineCount() or 0) + 1):
|
|
5431
|
+
t = proj.GetTimelineByIndex(index)
|
|
5432
|
+
if t and str(t.GetUniqueId()) not in before_ids:
|
|
5433
|
+
imported = t
|
|
5125
5434
|
if not imported:
|
|
5126
|
-
return _err(
|
|
5435
|
+
return _err(
|
|
5436
|
+
"Failed to import timeline (Resolve created no timeline)",
|
|
5437
|
+
remediation=None if sanitize else
|
|
5438
|
+
"This XML may reference missing media or contain generator clips, which "
|
|
5439
|
+
"abort the scripting-API import. Retry with sanitize_media=True.",
|
|
5440
|
+
)
|
|
5441
|
+
|
|
5127
5442
|
imported_id = str(imported.GetUniqueId())
|
|
5128
|
-
|
|
5443
|
+
media = _timeline_media_coverage(imported)
|
|
5444
|
+
out = _ok(
|
|
5129
5445
|
name=imported.GetName(),
|
|
5130
5446
|
id=imported_id,
|
|
5131
5447
|
created_new=imported_id not in before_ids,
|
|
5132
5448
|
timeline_count=proj.GetTimelineCount(),
|
|
5449
|
+
api_returned_object=api_returned_object,
|
|
5450
|
+
media=media,
|
|
5133
5451
|
)
|
|
5452
|
+
if sanitize_report is not None:
|
|
5453
|
+
out["sanitize"] = sanitize_report
|
|
5454
|
+
if media["total"] and media["offline"]:
|
|
5455
|
+
msg = f"{media['offline']} of {media['total']} timeline items are offline (no linked media)."
|
|
5456
|
+
if not sanitize:
|
|
5457
|
+
msg += (" Retry with sanitize_media=True to drop missing-media/generator "
|
|
5458
|
+
"clips so the remaining media links automatically.")
|
|
5459
|
+
out["warning"] = msg
|
|
5460
|
+
return out
|
|
5134
5461
|
|
|
5135
5462
|
|
|
5136
5463
|
def _timeline_by_selector(proj, p: Dict[str, Any], *, prefix: str):
|
|
@@ -6559,6 +6886,78 @@ def _safe_clip_call(clip, method_name: str, *args):
|
|
|
6559
6886
|
return None, str(exc)
|
|
6560
6887
|
|
|
6561
6888
|
|
|
6889
|
+
# Clip-property keys whose SetClipProperty/SetMetadata write returns True but is
|
|
6890
|
+
# silently dropped by Resolve under common project configurations (issue #77).
|
|
6891
|
+
# For these we read the value back and refuse to report success unless it stuck.
|
|
6892
|
+
_WRITEBACK_VERIFY_KEYS = frozenset({"Reel Name"})
|
|
6893
|
+
|
|
6894
|
+
# Per-key hint explaining the most common cause of a non-persisting write.
|
|
6895
|
+
_WRITEBACK_VERIFY_HINTS = {
|
|
6896
|
+
"Reel Name": (
|
|
6897
|
+
"Reel Name is commonly gated by the project setting "
|
|
6898
|
+
"'General Options > Assist using reel names from the:'. When that is "
|
|
6899
|
+
"set to derive reel names from the source clip / embedding / filename "
|
|
6900
|
+
"pattern, Resolve ignores scripted writes to 'Reel Name' (the call "
|
|
6901
|
+
"still returns True). Set that option to blank/manual, or assign reel "
|
|
6902
|
+
"names in the Resolve UI; the scripting API cannot override the gate."
|
|
6903
|
+
),
|
|
6904
|
+
}
|
|
6905
|
+
|
|
6906
|
+
|
|
6907
|
+
def _normalize_clip_property_value(value):
|
|
6908
|
+
"""Coerce a clip-property value to a comparable, trimmed string."""
|
|
6909
|
+
if value is None:
|
|
6910
|
+
return ""
|
|
6911
|
+
return str(value).strip()
|
|
6912
|
+
|
|
6913
|
+
|
|
6914
|
+
def _verify_clip_property_writeback(clip, key, value):
|
|
6915
|
+
"""Confirm a just-written, known-unreliable clip property actually persisted.
|
|
6916
|
+
|
|
6917
|
+
Returns a structured failure dict when Resolve accepted the write (returned
|
|
6918
|
+
True) but the value did not stick on read-back; returns ``None`` when the
|
|
6919
|
+
write verified, the key is not in the watch list, or we cannot read it back
|
|
6920
|
+
(in which case we don't override the original success). See issue #77.
|
|
6921
|
+
"""
|
|
6922
|
+
if key not in _WRITEBACK_VERIFY_KEYS:
|
|
6923
|
+
return None
|
|
6924
|
+
actual, err = _safe_clip_call(clip, "GetClipProperty", key)
|
|
6925
|
+
if err is not None:
|
|
6926
|
+
return None # can't read back — don't contradict the reported result
|
|
6927
|
+
if isinstance(actual, dict): # GetClipProperty('') style dict, just in case
|
|
6928
|
+
actual = actual.get(key)
|
|
6929
|
+
if _normalize_clip_property_value(actual) == _normalize_clip_property_value(value):
|
|
6930
|
+
return None
|
|
6931
|
+
return {
|
|
6932
|
+
"success": False,
|
|
6933
|
+
"verified": False,
|
|
6934
|
+
"key": key,
|
|
6935
|
+
"requested": value,
|
|
6936
|
+
"actual": actual,
|
|
6937
|
+
"error": (
|
|
6938
|
+
f"Resolve reported success writing {key!r} but the value did not "
|
|
6939
|
+
f"persist (read-back returned {actual!r})."
|
|
6940
|
+
),
|
|
6941
|
+
"hint": _WRITEBACK_VERIFY_HINTS.get(key),
|
|
6942
|
+
}
|
|
6943
|
+
|
|
6944
|
+
|
|
6945
|
+
def _verify_writeback(clip, written):
|
|
6946
|
+
"""Verify a batch of just-written {key: value} pairs.
|
|
6947
|
+
|
|
6948
|
+
Returns the first silent-revert failure dict, else ``None``. Only keys in
|
|
6949
|
+
``_WRITEBACK_VERIFY_KEYS`` are checked, so ordinary writes pay nothing.
|
|
6950
|
+
"""
|
|
6951
|
+
if not isinstance(written, dict):
|
|
6952
|
+
return None
|
|
6953
|
+
for key, value in written.items():
|
|
6954
|
+
if key in _WRITEBACK_VERIFY_KEYS:
|
|
6955
|
+
fail = _verify_clip_property_writeback(clip, key, value)
|
|
6956
|
+
if fail:
|
|
6957
|
+
return fail
|
|
6958
|
+
return None
|
|
6959
|
+
|
|
6960
|
+
|
|
6562
6961
|
def _media_pool_item_summary(clip):
|
|
6563
6962
|
if not clip:
|
|
6564
6963
|
return None
|
|
@@ -10213,7 +10612,17 @@ def _normalize_metadata(root, mp, p: Dict[str, Any]):
|
|
|
10213
10612
|
third_party_ok = True
|
|
10214
10613
|
for key, value in third_party.items():
|
|
10215
10614
|
third_party_ok = bool(clip.SetThirdPartyMetadata(key, value)) and third_party_ok
|
|
10216
|
-
|
|
10615
|
+
row = {"clip_id": clip_id, "success": ok and third_party_ok}
|
|
10616
|
+
if ok and metadata:
|
|
10617
|
+
silent = _verify_writeback(clip, metadata)
|
|
10618
|
+
if silent:
|
|
10619
|
+
row["success"] = False
|
|
10620
|
+
row["verified"] = False
|
|
10621
|
+
row["unpersisted"] = {silent["key"]: silent["actual"]}
|
|
10622
|
+
row["error"] = silent["error"]
|
|
10623
|
+
if silent.get("hint"):
|
|
10624
|
+
row["hint"] = silent["hint"]
|
|
10625
|
+
results.append(row)
|
|
10217
10626
|
return {"success": all(row.get("success") for row in results), "count": len(results), "missing": missing, "results": results}
|
|
10218
10627
|
|
|
10219
10628
|
|
|
@@ -11957,7 +12366,11 @@ def resolve_control(action: str, params: Optional[Dict[str, Any]] = None) -> Dic
|
|
|
11957
12366
|
|
|
11958
12367
|
Actions:
|
|
11959
12368
|
launch() -> {success, message} — Launch DaVinci Resolve if not running. Call this FIRST if any tool returns a 'Not connected' error.
|
|
11960
|
-
get_version() -> {product, version, version_string}
|
|
12369
|
+
get_version() -> {product, version, version_string, mcp: {version, update, update_decision}}
|
|
12370
|
+
— mcp.update_decision piggybacks the cached update check: if its action is
|
|
12371
|
+
"notify" or "prompt", mention the available MCP update to the user ONCE
|
|
12372
|
+
per session (do not nag, do not auto-apply; updates are applied via
|
|
12373
|
+
install.py or the control panel).
|
|
11961
12374
|
mcp_update_status(force_check?) -> {version, update, decision}
|
|
11962
12375
|
set_mcp_update_policy(mode) -> {success, version, update, decision}
|
|
11963
12376
|
ignore_mcp_update() -> {success, version, update, decision}
|
|
@@ -12106,7 +12519,7 @@ def resolve_control(action: str, params: Optional[Dict[str, Any]] = None) -> Dic
|
|
|
12106
12519
|
# "value": <any JSON>,
|
|
12107
12520
|
# "confidence": "low|medium|high",
|
|
12108
12521
|
# "source": "human" | "vision_v0.2",
|
|
12109
|
-
# "author": "
|
|
12522
|
+
# "author": "editor@example.com",
|
|
12110
12523
|
# "timestamp": "2026-05-19T...Z"
|
|
12111
12524
|
# }
|
|
12112
12525
|
# },
|
|
@@ -15696,8 +16109,18 @@ def media_pool_item(action: str, params: Optional[Dict[str, Any]] = None) -> Dic
|
|
|
15696
16109
|
return {"metadata": _ser(clip.GetMetadata(p.get("key", "")))}
|
|
15697
16110
|
elif action == "set_metadata":
|
|
15698
16111
|
if "metadata" in p:
|
|
15699
|
-
|
|
15700
|
-
|
|
16112
|
+
ok = bool(clip.SetMetadata(p["metadata"]))
|
|
16113
|
+
if ok:
|
|
16114
|
+
silent = _verify_writeback(clip, p["metadata"])
|
|
16115
|
+
if silent:
|
|
16116
|
+
return silent
|
|
16117
|
+
return {"success": ok}
|
|
16118
|
+
ok = bool(clip.SetMetadata(p["key"], p["value"]))
|
|
16119
|
+
if ok:
|
|
16120
|
+
silent = _verify_clip_property_writeback(clip, p["key"], p["value"])
|
|
16121
|
+
if silent:
|
|
16122
|
+
return silent
|
|
16123
|
+
return {"success": ok}
|
|
15701
16124
|
elif action == "get_third_party_metadata":
|
|
15702
16125
|
return {"metadata": _ser(clip.GetThirdPartyMetadata(p.get("key", "")))}
|
|
15703
16126
|
elif action == "set_third_party_metadata":
|
|
@@ -15707,7 +16130,12 @@ def media_pool_item(action: str, params: Optional[Dict[str, Any]] = None) -> Dic
|
|
|
15707
16130
|
elif action == "get_clip_property":
|
|
15708
16131
|
return {"properties": _ser(clip.GetClipProperty(p.get("key", "")))}
|
|
15709
16132
|
elif action == "set_clip_property":
|
|
15710
|
-
|
|
16133
|
+
ok = bool(clip.SetClipProperty(p["key"], p["value"]))
|
|
16134
|
+
if ok:
|
|
16135
|
+
silent = _verify_clip_property_writeback(clip, p["key"], p["value"])
|
|
16136
|
+
if silent:
|
|
16137
|
+
return silent
|
|
16138
|
+
return {"success": ok}
|
|
15711
16139
|
elif action == "get_clip_color":
|
|
15712
16140
|
return {"color": clip.GetClipColor()}
|
|
15713
16141
|
elif action == "set_clip_color":
|
|
@@ -17937,7 +18365,25 @@ def timeline(action: str, params: Optional[Dict[str, Any]] = None) -> Dict[str,
|
|
|
17937
18365
|
detect_gaps_overlaps(track_types?, min_gap?) -> {gaps, overlaps}
|
|
17938
18366
|
source_range_report(handles?, merge?) -> {ranges, occurrences}
|
|
17939
18367
|
export_timeline_checked(path, format?|type?, subtype?, require_temp_path?, dry_run?) -> {success, path, size}
|
|
17940
|
-
import_timeline_checked(path, options?, timeline_name?, import_source_clips?, require_temp_path?, dry_run?) -> {success, name, id}
|
|
18368
|
+
import_timeline_checked(path, options?, timeline_name?, import_source_clips?, sanitize_media?, require_temp_path?, dry_run?) -> {success, name, id, media, sanitize?, warning?}
|
|
18369
|
+
Imports an FCP7 xmeml / FCPXML timeline. `media` reports {total, linked, offline}
|
|
18370
|
+
coverage; `warning` flags offline items. sanitize_media=True (recommended for
|
|
18371
|
+
Premiere/FCP exports) rewrites the XML first — dropping clipitems that reference
|
|
18372
|
+
MISSING media or are generators (slug/solid with no media file), both of which
|
|
18373
|
+
otherwise abort the scripting-API import and leave the whole timeline offline.
|
|
18374
|
+
Returns `sanitize` with the kept/removed breakdown. The original is only read;
|
|
18375
|
+
the sanitized copy goes to a temp dir (no require_temp_path needed when sanitizing).
|
|
18376
|
+
relink_search_roots (str|list) enables fuzzy relink: clips missing at their
|
|
18377
|
+
original path are matched against media under those roots (exact/ext-agnostic/
|
|
18378
|
+
normalized/reel + IDF true-source) and their pathurl rewritten so they relink
|
|
18379
|
+
instead of being dropped. relink_min_confidence (default 0.7) gates matches;
|
|
18380
|
+
`sanitize.relinked` / `sanitize.ambiguous` report the outcome.
|
|
18381
|
+
verify_visually=True (or passing reference_movie) frame-checks each proposed
|
|
18382
|
+
relink against a reference (reference_movie at the clip's record position, else
|
|
18383
|
+
the offline proxy at the original path) using a brightness-robust SSIM-structure
|
|
18384
|
+
metric; a conflicting relink is VETOED — reverted and reported under
|
|
18385
|
+
`sanitize.flagged` for human review, never silently applied. verify_threshold
|
|
18386
|
+
(default 0.90) sets the structural-match bar.
|
|
17941
18387
|
compare_timelines(right_timeline_id?|right_timeline_index?|left_snapshot?, right_snapshot?) -> {match, differences}
|
|
17942
18388
|
probe_interchange_roundtrip(format?, output_dir?, cleanup_imported?) -> {success, export, import, comparison}
|
|
17943
18389
|
detect_missing_media(sanitized?|sanitize_paths?, omit_raw_paths?) -> {missing, missing_count, diagnosis}
|
|
@@ -18688,7 +19134,7 @@ def timeline_ai(action: str, params: Optional[Dict[str, Any]] = None) -> Dict[st
|
|
|
18688
19134
|
@_destructive_op("timeline_item")
|
|
18689
19135
|
def timeline_item(action: str, params: Optional[Dict[str, Any]] = None) -> Dict[str, Any]:
|
|
18690
19136
|
"""Properties, transforms, speed, keyframes, and metadata for a timeline item.
|
|
18691
|
-
Identify by track_type, track_index, item_index.
|
|
19137
|
+
Identify by track_type, track_index, item_index (item_index is 0-BASED: 0 = first clip; track_index is 1-based).
|
|
18692
19138
|
|
|
18693
19139
|
Actions:
|
|
18694
19140
|
get_name(track_type?, track_index?, item_index?) -> {name}
|
|
@@ -18926,7 +19372,7 @@ def timeline_item(action: str, params: Optional[Dict[str, Any]] = None) -> Dict[
|
|
|
18926
19372
|
@mcp.tool()
|
|
18927
19373
|
@_destructive_op("timeline_item_markers")
|
|
18928
19374
|
def timeline_item_markers(action: str, params: Optional[Dict[str, Any]] = None) -> Dict[str, Any]:
|
|
18929
|
-
"""Markers, flags, and clip color on timeline items. Identify by track_type, track_index, item_index.
|
|
19375
|
+
"""Markers, flags, and clip color on timeline items. Identify by track_type, track_index, item_index (item_index is 0-BASED: 0 = first clip; track_index is 1-based).
|
|
18930
19376
|
|
|
18931
19377
|
Actions:
|
|
18932
19378
|
add(frame|frame_id|frameId, color?, name?, note?, duration?, custom_data?, ...) -> {success, frame}
|
|
@@ -19003,7 +19449,7 @@ def timeline_item_markers(action: str, params: Optional[Dict[str, Any]] = None)
|
|
|
19003
19449
|
@mcp.tool()
|
|
19004
19450
|
@_destructive_op("timeline_item_fusion")
|
|
19005
19451
|
def timeline_item_fusion(action: str, params: Optional[Dict[str, Any]] = None) -> Dict[str, Any]:
|
|
19006
|
-
"""Fusion composition operations on timeline items. Identify by track_type, track_index, item_index.
|
|
19452
|
+
"""Fusion composition operations on timeline items. Identify by track_type, track_index, item_index (item_index is 0-BASED: 0 = first clip; track_index is 1-based).
|
|
19007
19453
|
|
|
19008
19454
|
Actions:
|
|
19009
19455
|
add_comp(...) -> {success}
|
|
@@ -20263,7 +20709,7 @@ def _grade_evidence_base(proj, item, p: Dict[str, Any]) -> Dict[str, Any]:
|
|
|
20263
20709
|
@mcp.tool()
|
|
20264
20710
|
@_destructive_op("timeline_item_color")
|
|
20265
20711
|
def timeline_item_color(action: str, params: Optional[Dict[str, Any]] = None) -> Dict[str, Any]:
|
|
20266
|
-
"""Color grading, versions, LUTs, cache, and AI tools on timeline items. Identify by track_type, track_index, item_index.
|
|
20712
|
+
"""Color grading, versions, LUTs, cache, and AI tools on timeline items. Identify by track_type, track_index, item_index (item_index is 0-BASED: 0 = first clip; track_index is 1-based).
|
|
20267
20713
|
|
|
20268
20714
|
<when_to_use>
|
|
20269
20715
|
- For ANY grade recommendation, lead with action="grade_evidence_base" — composes
|
|
@@ -20468,7 +20914,7 @@ def timeline_item_color(action: str, params: Optional[Dict[str, Any]] = None) ->
|
|
|
20468
20914
|
@mcp.tool()
|
|
20469
20915
|
@_destructive_op("timeline_item_takes")
|
|
20470
20916
|
def timeline_item_takes(action: str, params: Optional[Dict[str, Any]] = None) -> Dict[str, Any]:
|
|
20471
|
-
"""Take management on timeline items. Identify by track_type, track_index, item_index.
|
|
20917
|
+
"""Take management on timeline items. Identify by track_type, track_index, item_index (item_index is 0-BASED: 0 = first clip; track_index is 1-based).
|
|
20472
20918
|
|
|
20473
20919
|
Actions:
|
|
20474
20920
|
add(clip_id, start_frame?, end_frame?, ...) -> {success}
|
|
@@ -20753,8 +21199,12 @@ def graph(action: str, params: Optional[Dict[str, Any]] = None) -> Dict[str, Any
|
|
|
20753
21199
|
set_node_enabled(node_index, enabled, source?, ...) -> {success}
|
|
20754
21200
|
apply_grade_from_drx(path, grade_mode?, source?, ...) -> {success}
|
|
20755
21201
|
CATASTROPHIC. REPLACES the entire node graph. Prefer timeline_item_color.safe_apply_drx
|
|
20756
|
-
(
|
|
20757
|
-
|
|
21202
|
+
(confirm-token gated + validated; it does NOT snapshot — grab a still/.drx backup
|
|
21203
|
+
first, and ALWAYS pass track_type/track_index/item_index explicitly: the default
|
|
21204
|
+
target is video track 1 item 0, not the current clip). All grade_modes are full
|
|
21205
|
+
replacement — there is no append mode. Same-structure applies keep the existing
|
|
21206
|
+
node layout (positions in the .drx are ignored unless the graph differs, e.g.
|
|
21207
|
+
after reset_all_grades).
|
|
20758
21208
|
grade_mode: 0="No keyframes" (default), 1="Source Timecode aligned", 2="Start Frames aligned"
|
|
20759
21209
|
apply_arri_cdl_lut(source?, ...) -> {success}
|
|
20760
21210
|
DESTRUCTIVE. Bakes a CDL LUT into the graph.
|
|
@@ -23804,7 +24254,7 @@ def script_plugin(action: str, params: Optional[Dict[str, Any]] = None) -> Dict[
|
|
|
23804
24254
|
|
|
23805
24255
|
|
|
23806
24256
|
# ═══════════════════════════════════════════════════════════════════════════════
|
|
23807
|
-
# MCP Resources —
|
|
24257
|
+
# MCP Resources — agentic-flow improvement E1
|
|
23808
24258
|
#
|
|
23809
24259
|
# Resources are read-only state surfaces that hosts can pull WITHOUT consuming
|
|
23810
24260
|
# a turn (unlike tools, which require a tool_use round-trip). They mirror
|