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.
Files changed (328) hide show
  1. package/AGENTS.md +20 -0
  2. package/CHANGELOG.md +197 -2
  3. package/LICENSE +1 -1
  4. package/README.md +73 -1
  5. package/bin/davinci-resolve-advanced-mcp.mjs +20 -0
  6. package/docs/README.md +19 -0
  7. package/docs/SKILL.md +62 -1
  8. package/docs/contributing.md +1 -1
  9. package/docs/guides/control-panel.md +9 -0
  10. package/docs/kernels/README.md +21 -0
  11. package/docs/kernels/audio-fairlight-kernel.md +22 -0
  12. package/docs/kernels/color-grade-kernel.md +51 -0
  13. package/docs/kernels/fusion-composition-kernel.md +17 -0
  14. package/docs/kernels/media-pool-ingest-kernel.md +20 -0
  15. package/docs/kernels/render-deliver-kernel.md +32 -0
  16. package/docs/kernels/timeline-conform-interchange-kernel.md +39 -0
  17. package/docs/kernels/timeline-edit-kernel.md +17 -0
  18. package/docs/process/release-process.md +29 -7
  19. package/docs/reference/api-coverage.md +1 -1
  20. package/docs/reference/api-limitations.md +38 -1
  21. package/install.py +27 -4
  22. package/package.json +23 -2
  23. package/resolve-advanced/README.md +194 -0
  24. package/resolve-advanced/package.json +50 -0
  25. package/resolve-advanced/server/black-balance.mjs +92 -0
  26. package/resolve-advanced/server/capabilities.mjs +86 -0
  27. package/resolve-advanced/server/cdl-io.mjs +76 -0
  28. package/resolve-advanced/server/contrast-normalize.mjs +180 -0
  29. package/resolve-advanced/server/db-patch.mjs +91 -0
  30. package/resolve-advanced/server/deliverable-entities.mjs +86 -0
  31. package/resolve-advanced/server/deliverable-qc.mjs +270 -0
  32. package/resolve-advanced/server/editorial.mjs +370 -0
  33. package/resolve-advanced/server/exposure-level.mjs +129 -0
  34. package/resolve-advanced/server/extract-frames.mjs +196 -0
  35. package/resolve-advanced/server/ffprobe-media.mjs +88 -0
  36. package/resolve-advanced/server/gamut-legal.mjs +112 -0
  37. package/resolve-advanced/server/grade-body-patch.mjs +246 -0
  38. package/resolve-advanced/server/grade-transfer.mjs +66 -0
  39. package/resolve-advanced/server/group-grade-read.mjs +137 -0
  40. package/resolve-advanced/server/index.mjs +105 -0
  41. package/resolve-advanced/server/lib.mjs +84 -0
  42. package/resolve-advanced/server/libs.mjs +65 -0
  43. package/resolve-advanced/server/lineage-db.mjs +479 -0
  44. package/resolve-advanced/server/lut-apply.mjs +61 -0
  45. package/resolve-advanced/server/match-to-reference.mjs +173 -0
  46. package/resolve-advanced/server/media-inventory.mjs +169 -0
  47. package/resolve-advanced/server/media-ops.mjs +243 -0
  48. package/resolve-advanced/server/node-meta-db.mjs +62 -0
  49. package/resolve-advanced/server/node-provenance.mjs +102 -0
  50. package/resolve-advanced/server/offline-ref-db.mjs +420 -0
  51. package/resolve-advanced/server/offline-ref.mjs +179 -0
  52. package/resolve-advanced/server/project-db.mjs +233 -0
  53. package/resolve-advanced/server/provenance-audit.mjs +210 -0
  54. package/resolve-advanced/server/qc-frame.mjs +224 -0
  55. package/resolve-advanced/server/qc-sampler.mjs +67 -0
  56. package/resolve-advanced/server/readback.mjs +77 -0
  57. package/resolve-advanced/server/render-manifest.mjs +93 -0
  58. package/resolve-advanced/server/reverse-clip-db.mjs +270 -0
  59. package/resolve-advanced/server/runner-apply-contract.mjs +64 -0
  60. package/resolve-advanced/server/runner.mjs +244 -0
  61. package/resolve-advanced/server/saturation-match.mjs +108 -0
  62. package/resolve-advanced/server/scope-read.mjs +257 -0
  63. package/resolve-advanced/server/season-look.mjs +96 -0
  64. package/resolve-advanced/server/shot-intent.mjs +82 -0
  65. package/resolve-advanced/server/shot-match.mjs +147 -0
  66. package/resolve-advanced/server/skin-match.mjs +205 -0
  67. package/resolve-advanced/server/spec-compile.mjs +217 -0
  68. package/resolve-advanced/server/tone-curve-transfer.mjs +184 -0
  69. package/resolve-advanced/server/tool-catalog.mjs +265 -0
  70. package/resolve-advanced/server/tools/audio.mjs +54 -0
  71. package/resolve-advanced/server/tools/audio_plan.mjs +58 -0
  72. package/resolve-advanced/server/tools/capabilities.mjs +16 -0
  73. package/resolve-advanced/server/tools/color_trace.mjs +165 -0
  74. package/resolve-advanced/server/tools/conform.mjs +291 -0
  75. package/resolve-advanced/server/tools/deliverable.mjs +105 -0
  76. package/resolve-advanced/server/tools/drp.mjs +232 -0
  77. package/resolve-advanced/server/tools/drt.mjs +200 -0
  78. package/resolve-advanced/server/tools/drx.mjs +943 -0
  79. package/resolve-advanced/server/tools/editorial.mjs +69 -0
  80. package/resolve-advanced/server/tools/fairlight.mjs +108 -0
  81. package/resolve-advanced/server/tools/fusion.mjs +64 -0
  82. package/resolve-advanced/server/tools/media.mjs +102 -0
  83. package/resolve-advanced/server/tools/offline_ref.mjs +123 -0
  84. package/resolve-advanced/server/tools/pipeline.mjs +137 -0
  85. package/resolve-advanced/server/tools/project_db.mjs +200 -0
  86. package/resolve-advanced/server/tools/project_read.mjs +212 -0
  87. package/resolve-advanced/server/tools/provenance.mjs +73 -0
  88. package/resolve-advanced/server/verify-grade.mjs +113 -0
  89. package/resolve-advanced/server/white-balance-match.mjs +122 -0
  90. package/resolve-advanced/vendor/audio/format-converter.js +330 -0
  91. package/resolve-advanced/vendor/audio/split.js +173 -0
  92. package/resolve-advanced/vendor/audio/trim.js +188 -0
  93. package/resolve-advanced/vendor/audio-fairlight/index.js +391 -0
  94. package/resolve-advanced/vendor/conform-qc/adapters/frame-sampler.js +56 -0
  95. package/resolve-advanced/vendor/conform-qc/adapters/local-ffmpeg-sampler.js +65 -0
  96. package/resolve-advanced/vendor/conform-qc/adapters/rendernode-ffmpeg-sampler.js +50 -0
  97. package/resolve-advanced/vendor/conform-qc/adapters/resolve/driver.py +176 -0
  98. package/resolve-advanced/vendor/conform-qc/adapters/resolve-driver.js +61 -0
  99. package/resolve-advanced/vendor/conform-qc/adapters/resolve-headless-driver.js +86 -0
  100. package/resolve-advanced/vendor/conform-qc/adapters/vision-validator.js +75 -0
  101. package/resolve-advanced/vendor/conform-qc/cli.js +63 -0
  102. package/resolve-advanced/vendor/conform-qc/compare/advisory.js +106 -0
  103. package/resolve-advanced/vendor/conform-qc/compare/decode.js +36 -0
  104. package/resolve-advanced/vendor/conform-qc/compare/index.js +61 -0
  105. package/resolve-advanced/vendor/conform-qc/compare/locate.js +70 -0
  106. package/resolve-advanced/vendor/conform-qc/compare/metrics.js +409 -0
  107. package/resolve-advanced/vendor/conform-qc/docs/runbook.md +72 -0
  108. package/resolve-advanced/vendor/conform-qc/index.js +49 -0
  109. package/resolve-advanced/vendor/conform-qc/knowledge/index.js +110 -0
  110. package/resolve-advanced/vendor/conform-qc/ops/conform-core.js +137 -0
  111. package/resolve-advanced/vendor/conform-qc/ops/conform-diff.js +109 -0
  112. package/resolve-advanced/vendor/conform-qc/ops/insert.js +108 -0
  113. package/resolve-advanced/vendor/conform-qc/ops/local-conform.js +61 -0
  114. package/resolve-advanced/vendor/conform-qc/ops/patch.js +80 -0
  115. package/resolve-advanced/vendor/conform-qc/ops/trigger.js +32 -0
  116. package/resolve-advanced/vendor/conform-qc/ops/verify.js +105 -0
  117. package/resolve-advanced/vendor/conform-qc/ops/workflow.js +30 -0
  118. package/resolve-advanced/vendor/conform-qc/oracle/emulate.js +155 -0
  119. package/resolve-advanced/vendor/conform-qc/oracle/index.js +38 -0
  120. package/resolve-advanced/vendor/conform-qc/oracle/resolve.js +196 -0
  121. package/resolve-advanced/vendor/conform-qc/package.json +16 -0
  122. package/resolve-advanced/vendor/conform-qc/packaging/emit-aaf.js +30 -0
  123. package/resolve-advanced/vendor/conform-qc/packaging/emit-fcp7.js +64 -0
  124. package/resolve-advanced/vendor/conform-qc/packaging/index.js +169 -0
  125. package/resolve-advanced/vendor/conform-qc/packaging/media-ops.js +56 -0
  126. package/resolve-advanced/vendor/conform-qc/packaging/otio.js +50 -0
  127. package/resolve-advanced/vendor/conform-qc/packaging/relink.js +50 -0
  128. package/resolve-advanced/vendor/conform-qc/packaging/surgical-relink.js +195 -0
  129. package/resolve-advanced/vendor/conform-qc/parse/index.js +54 -0
  130. package/resolve-advanced/vendor/conform-qc/parse/merge-dto.js +27 -0
  131. package/resolve-advanced/vendor/conform-qc/parse/xmeml-geometry.js +256 -0
  132. package/resolve-advanced/vendor/conform-qc/reference/burnin-ocr.js +100 -0
  133. package/resolve-advanced/vendor/conform-qc/reference/sidecar.js +37 -0
  134. package/resolve-advanced/vendor/conform-qc/repair/analysis.js +62 -0
  135. package/resolve-advanced/vendor/conform-qc/repair/index.js +78 -0
  136. package/resolve-advanced/vendor/conform-qc/repair/media-analysis.js +139 -0
  137. package/resolve-advanced/vendor/conform-qc/repair/media-index.js +135 -0
  138. package/resolve-advanced/vendor/conform-qc/repair/strategies.js +250 -0
  139. package/resolve-advanced/vendor/conform-qc/report/index.js +133 -0
  140. package/resolve-advanced/vendor/conform-qc/roles/index.js +96 -0
  141. package/resolve-advanced/vendor/conform-qc/synthetic/generate.js +233 -0
  142. package/resolve-advanced/vendor/conform-qc/test/advisory.test.js +85 -0
  143. package/resolve-advanced/vendor/conform-qc/test/cli.test.js +39 -0
  144. package/resolve-advanced/vendor/conform-qc/test/compare.test.js +152 -0
  145. package/resolve-advanced/vendor/conform-qc/test/conform-diff.test.js +70 -0
  146. package/resolve-advanced/vendor/conform-qc/test/emulate.test.js +51 -0
  147. package/resolve-advanced/vendor/conform-qc/test/frame-sampler.test.js +30 -0
  148. package/resolve-advanced/vendor/conform-qc/test/geometry.test.js +112 -0
  149. package/resolve-advanced/vendor/conform-qc/test/knowledge.test.js +56 -0
  150. package/resolve-advanced/vendor/conform-qc/test/lifecycle.test.js +110 -0
  151. package/resolve-advanced/vendor/conform-qc/test/local-ffmpeg-sampler.test.js +66 -0
  152. package/resolve-advanced/vendor/conform-qc/test/locate.test.js +63 -0
  153. package/resolve-advanced/vendor/conform-qc/test/media-analysis.test.js +63 -0
  154. package/resolve-advanced/vendor/conform-qc/test/media-index-normalized.test.js +65 -0
  155. package/resolve-advanced/vendor/conform-qc/test/media-index-origin.test.js +53 -0
  156. package/resolve-advanced/vendor/conform-qc/test/metrics-fast.test.js +91 -0
  157. package/resolve-advanced/vendor/conform-qc/test/oracle-reverse.test.js +86 -0
  158. package/resolve-advanced/vendor/conform-qc/test/oracle.test.js +136 -0
  159. package/resolve-advanced/vendor/conform-qc/test/p0-acceptance.test.js +60 -0
  160. package/resolve-advanced/vendor/conform-qc/test/p1-acceptance.test.js +75 -0
  161. package/resolve-advanced/vendor/conform-qc/test/p45-patch-acceptance.test.js +102 -0
  162. package/resolve-advanced/vendor/conform-qc/test/packaging.test.js +133 -0
  163. package/resolve-advanced/vendor/conform-qc/test/parse-stubs.test.js +28 -0
  164. package/resolve-advanced/vendor/conform-qc/test/repair-strategies.test.js +128 -0
  165. package/resolve-advanced/vendor/conform-qc/test/repair.test.js +84 -0
  166. package/resolve-advanced/vendor/conform-qc/test/report.test.js +52 -0
  167. package/resolve-advanced/vendor/conform-qc/test/resolve-readback.test.js +71 -0
  168. package/resolve-advanced/vendor/conform-qc/test/roles.test.js +107 -0
  169. package/resolve-advanced/vendor/conform-qc/test/runbook.test.js +30 -0
  170. package/resolve-advanced/vendor/conform-qc/test/scale-residual.test.js +40 -0
  171. package/resolve-advanced/vendor/conform-qc/test/sidecar.test.js +51 -0
  172. package/resolve-advanced/vendor/conform-qc/test/smoke.test.js +87 -0
  173. package/resolve-advanced/vendor/conform-qc/test/surgical-relink.test.js +73 -0
  174. package/resolve-advanced/vendor/conform-qc/test/synthetic.test.js +98 -0
  175. package/resolve-advanced/vendor/conform-qc/test/verify.test.js +93 -0
  176. package/resolve-advanced/vendor/conform-qc/test/vision-validator.test.js +43 -0
  177. package/resolve-advanced/vendor/conform-qc/test/workflow-driver.test.js +46 -0
  178. package/resolve-advanced/vendor/conform-qc/toolset/index.js +53 -0
  179. package/resolve-advanced/vendor/drp-format/README.md +116 -0
  180. package/resolve-advanced/vendor/drp-format/__tests__/_resolve-verify.js +39 -0
  181. package/resolve-advanced/vendor/drp-format/__tests__/add-media-clip.test.js +30 -0
  182. package/resolve-advanced/vendor/drp-format/__tests__/assemble-timeline.test.js +68 -0
  183. package/resolve-advanced/vendor/drp-format/__tests__/author-project.test.js +57 -0
  184. package/resolve-advanced/vendor/drp-format/__tests__/composition-text.test.js +98 -0
  185. package/resolve-advanced/vendor/drp-format/__tests__/diff.test.js +272 -0
  186. package/resolve-advanced/vendor/drp-format/__tests__/effect-filters-compressed.test.js +143 -0
  187. package/resolve-advanced/vendor/drp-format/__tests__/fixtures/p0-3-session30-empty-effectfilters.drp +0 -0
  188. package/resolve-advanced/vendor/drp-format/__tests__/fixtures/retimed-timemap-50pct.hex +1 -0
  189. package/resolve-advanced/vendor/drp-format/__tests__/fixtures/retimed-timemap-dynamic.hex +1 -0
  190. package/resolve-advanced/vendor/drp-format/__tests__/inject-grades.test.js +238 -0
  191. package/resolve-advanced/vendor/drp-format/__tests__/keyed-dict.test.js +85 -0
  192. package/resolve-advanced/vendor/drp-format/__tests__/lut-refs.test.js +119 -0
  193. package/resolve-advanced/vendor/drp-format/__tests__/media-blobs.test.js +25 -0
  194. package/resolve-advanced/vendor/drp-format/__tests__/media-timemap.test.js +119 -0
  195. package/resolve-advanced/vendor/drp-format/__tests__/place-fusion-title.test.js +52 -0
  196. package/resolve-advanced/vendor/drp-format/__tests__/place-generator.test.js +40 -0
  197. package/resolve-advanced/vendor/drp-format/__tests__/place-transition.test.js +48 -0
  198. package/resolve-advanced/vendor/drp-format/__tests__/protobuf-wire.test.js +64 -0
  199. package/resolve-advanced/vendor/drp-format/__tests__/relink-media.test.js +106 -0
  200. package/resolve-advanced/vendor/drp-format/__tests__/splice-clips.test.js +256 -0
  201. package/resolve-advanced/vendor/drp-format/assemble-timeline.js +65 -0
  202. package/resolve-advanced/vendor/drp-format/author-project.js +118 -0
  203. package/resolve-advanced/vendor/drp-format/composition-text.js +213 -0
  204. package/resolve-advanced/vendor/drp-format/curves-encoder.js +763 -0
  205. package/resolve-advanced/vendor/drp-format/diff.js +310 -0
  206. package/resolve-advanced/vendor/drp-format/drp-packager.js +201 -0
  207. package/resolve-advanced/vendor/drp-format/drp-validator.js +809 -0
  208. package/resolve-advanced/vendor/drp-format/effect-encoder.js +640 -0
  209. package/resolve-advanced/vendor/drp-format/extract-lut-refs.js +119 -0
  210. package/resolve-advanced/vendor/drp-format/grade-encoder.example.js +133 -0
  211. package/resolve-advanced/vendor/drp-format/grade-encoder.js +401 -0
  212. package/resolve-advanced/vendor/drp-format/grade-encoder.test.js +171 -0
  213. package/resolve-advanced/vendor/drp-format/grade-encoder.verify.js +249 -0
  214. package/resolve-advanced/vendor/drp-format/grade-node-extractor.js +495 -0
  215. package/resolve-advanced/vendor/drp-format/grade-parameter-decoder.js +774 -0
  216. package/resolve-advanced/vendor/drp-format/index.js +174 -0
  217. package/resolve-advanced/vendor/drp-format/inject-grades.js +219 -0
  218. package/resolve-advanced/vendor/drp-format/keyed-dict.js +227 -0
  219. package/resolve-advanced/vendor/drp-format/marker-encoder.js +532 -0
  220. package/resolve-advanced/vendor/drp-format/media-blobs.js +53 -0
  221. package/resolve-advanced/vendor/drp-format/media-timemap.js +164 -0
  222. package/resolve-advanced/vendor/drp-format/mp-folder-builder.js +293 -0
  223. package/resolve-advanced/vendor/drp-format/node-tree-encoder.js +1246 -0
  224. package/resolve-advanced/vendor/drp-format/package.json +18 -0
  225. package/resolve-advanced/vendor/drp-format/place-fusion-title.js +131 -0
  226. package/resolve-advanced/vendor/drp-format/place-generator.js +77 -0
  227. package/resolve-advanced/vendor/drp-format/place-transition.js +91 -0
  228. package/resolve-advanced/vendor/drp-format/power-window-encoder.js +776 -0
  229. package/resolve-advanced/vendor/drp-format/protobuf-wire.js +111 -0
  230. package/resolve-advanced/vendor/drp-format/qualifier-encoder.js +706 -0
  231. package/resolve-advanced/vendor/drp-format/relink-media.js +218 -0
  232. package/resolve-advanced/vendor/drp-format/rich-title-encoder.js +447 -0
  233. package/resolve-advanced/vendor/drp-format/seq-container-builder.js +572 -0
  234. package/resolve-advanced/vendor/drp-format/seq-surgery.js +155 -0
  235. package/resolve-advanced/vendor/drp-format/splice-clips.js +445 -0
  236. package/resolve-advanced/vendor/drp-format/templates/empty-project.drp +0 -0
  237. package/resolve-advanced/vendor/drp-format/templates/fusion-title.xml +56 -0
  238. package/resolve-advanced/vendor/drp-format/templates/generator-solid-color.xml +21 -0
  239. package/resolve-advanced/vendor/drp-format/templates/media-clip-h264.drp +0 -0
  240. package/resolve-advanced/vendor/drp-format/templates/transition-cross-dissolve.xml +22 -0
  241. package/resolve-advanced/vendor/drp-format/tool-registry.descriptor.js +80 -0
  242. package/resolve-advanced/vendor/drp-format/utils/safe-archive.js +54 -0
  243. package/resolve-advanced/vendor/drp-format/xml-builder.js +759 -0
  244. package/resolve-advanced/vendor/drt-format/__tests__/_resolve-verify.js +21 -0
  245. package/resolve-advanced/vendor/drt-format/__tests__/build.test.js +113 -0
  246. package/resolve-advanced/vendor/drt-format/__tests__/multi-format.test.js +93 -0
  247. package/resolve-advanced/vendor/drt-format/__tests__/parse-real-resolve21.test.js +51 -0
  248. package/resolve-advanced/vendor/drt-format/__tests__/parse.test.js +134 -0
  249. package/resolve-advanced/vendor/drt-format/__tests__/resolve-versions.test.js +120 -0
  250. package/resolve-advanced/vendor/drt-format/__tests__/schema-fingerprint.test.js +62 -0
  251. package/resolve-advanced/vendor/drt-format/__tests__/smoke.test.js +27 -0
  252. package/resolve-advanced/vendor/drt-format/__tests__/validate.test.js +109 -0
  253. package/resolve-advanced/vendor/drt-format/capabilities.js +69 -0
  254. package/resolve-advanced/vendor/drt-format/capability-domains.js +56 -0
  255. package/resolve-advanced/vendor/drt-format/drt-builder.js +42 -0
  256. package/resolve-advanced/vendor/drt-format/drt-parser.js +164 -0
  257. package/resolve-advanced/vendor/drt-format/drt-validator.js +98 -0
  258. package/resolve-advanced/vendor/drt-format/index.js +45 -0
  259. package/resolve-advanced/vendor/drt-format/package.json +17 -0
  260. package/resolve-advanced/vendor/drt-format/resolve-versions.js +153 -0
  261. package/resolve-advanced/vendor/drt-format/schema-fingerprint.js +74 -0
  262. package/resolve-advanced/vendor/drt-format/templates/drt-project-shell.xml +124 -0
  263. package/resolve-advanced/vendor/drx-codec/__tests__/curves-roundtrip.test.js +148 -0
  264. package/resolve-advanced/vendor/drx-codec/__tests__/fixtures/p2-1-face-refinement.drx +58 -0
  265. package/resolve-advanced/vendor/drx-codec/__tests__/fixtures/p2-1-filmgrain.drx +58 -0
  266. package/resolve-advanced/vendor/drx-codec/__tests__/fixtures/p2-1-glow.drx +58 -0
  267. package/resolve-advanced/vendor/drx-codec/__tests__/fixtures/p2-1-lens-flare.drx +58 -0
  268. package/resolve-advanced/vendor/drx-codec/__tests__/fixtures/p2-3-beauty-25.drx +58 -0
  269. package/resolve-advanced/vendor/drx-codec/__tests__/fixtures/p2-3-beauty-75.drx +58 -0
  270. package/resolve-advanced/vendor/drx-codec/__tests__/fixtures/p5-1-node-no-lut.drx +58 -0
  271. package/resolve-advanced/vendor/drx-codec/__tests__/fixtures/p5-1-node-with-lut.drx +58 -0
  272. package/resolve-advanced/vendor/drx-codec/__tests__/hsl-curves-roundtrip.test.js +117 -0
  273. package/resolve-advanced/vendor/drx-codec/__tests__/lut-refs-roundtrip.test.js +112 -0
  274. package/resolve-advanced/vendor/drx-codec/__tests__/matte-roundtrip.test.js +167 -0
  275. package/resolve-advanced/vendor/drx-codec/__tests__/ofx-roundtrip.test.js +215 -0
  276. package/resolve-advanced/vendor/drx-codec/__tests__/ofx-slugs-discovery.test.js +149 -0
  277. package/resolve-advanced/vendor/drx-codec/__tests__/power-window-roundtrip.test.js +230 -0
  278. package/resolve-advanced/vendor/drx-codec/__tests__/qualifier-roundtrip.test.js +226 -0
  279. package/resolve-advanced/vendor/drx-codec/cdl-exporter.js +470 -0
  280. package/resolve-advanced/vendor/drx-codec/color-nlp-parser.js +833 -0
  281. package/resolve-advanced/vendor/drx-codec/data/color-nlp-action-mappings.json +2232 -0
  282. package/resolve-advanced/vendor/drx-codec/drx-generator.js +4123 -0
  283. package/resolve-advanced/vendor/drx-codec/drx-merger.js +320 -0
  284. package/resolve-advanced/vendor/drx-codec/drx-parser.js +1808 -0
  285. package/resolve-advanced/vendor/drx-codec/extract-custom-curves.js +215 -0
  286. package/resolve-advanced/vendor/drx-codec/extract-hsl-curves.js +180 -0
  287. package/resolve-advanced/vendor/drx-codec/extract-lut-refs.js +158 -0
  288. package/resolve-advanced/vendor/drx-codec/extract-matte-finesse.js +83 -0
  289. package/resolve-advanced/vendor/drx-codec/extract-ofx-params.js +226 -0
  290. package/resolve-advanced/vendor/drx-codec/extract-power-window.js +184 -0
  291. package/resolve-advanced/vendor/drx-codec/extract-qualifier.js +99 -0
  292. package/resolve-advanced/vendor/drx-codec/index.js +109 -0
  293. package/resolve-advanced/vendor/drx-codec/node-layout.js +249 -0
  294. package/resolve-advanced/vendor/drx-codec/resolved-drx-generator.js +393 -0
  295. package/resolve-advanced/vendor/drx-codec/tool-resolver.js +974 -0
  296. package/resolve-advanced/vendor/drx-codec/training-examples.js +548 -0
  297. package/resolve-advanced/vendor/drx-codec/vocabulary-intents.js +539 -0
  298. package/resolve-advanced/vendor/drx-parameters/CALIBRATION-STATUS.md +319 -0
  299. package/resolve-advanced/vendor/drx-parameters/DRX-VALUE-SCALING.md +251 -0
  300. package/resolve-advanced/vendor/drx-parameters/calibrated-ranges.json +17737 -0
  301. package/resolve-advanced/vendor/drx-parameters/corrector-types.js +120 -0
  302. package/resolve-advanced/vendor/drx-parameters/index.js +193 -0
  303. package/resolve-advanced/vendor/drx-parameters/parameter-codec.js +451 -0
  304. package/resolve-advanced/vendor/drx-parameters/parameter-ids.js +1292 -0
  305. package/resolve-advanced/vendor/drx-parameters/parameter-ranges.js +570 -0
  306. package/resolve-advanced/vendor/drx-parameters/parameter-validator.js +392 -0
  307. package/resolve-advanced/vendor/drx-parameters/resolvefx-registry.json +14973 -0
  308. package/resolve-advanced/vendor/drx-parameters/tool-registry.descriptor.js +38 -0
  309. package/resolve-advanced/vendor/drx-parameters/tools/drx-analyzer.js +371 -0
  310. package/resolve-advanced/vendor/fairlight/index.js +833 -0
  311. package/resolve-advanced/vendor/fusion-codec/composition-generator.js +401 -0
  312. package/resolve-advanced/vendor/fusion-codec/templates/blur-region.js +103 -0
  313. package/resolve-advanced/vendor/fusion-codec/templates/color-correct.js +87 -0
  314. package/resolve-advanced/vendor/fusion-codec/templates/film-grain.js +106 -0
  315. package/resolve-advanced/vendor/fusion-codec/templates/lower-third.js +241 -0
  316. package/resolve-advanced/vendor/fusion-codec/templates/picture-in-picture.js +188 -0
  317. package/resolve-advanced/vendor/fusion-codec/templates/text-overlay.js +161 -0
  318. package/resolve-advanced/vendor/fusion-codec/templates/title-card.js +184 -0
  319. package/resolve-advanced/vendor/fusion-codec/templates/vignette.js +107 -0
  320. package/resolve-advanced/vendor/fusion-codec/templates/watermark.js +101 -0
  321. package/scripts/agent-rules/README.md +68 -0
  322. package/src/analysis_dashboard.py +233 -1
  323. package/src/granular/common.py +1 -1
  324. package/src/server.py +479 -29
  325. package/src/utils/api_truth.py +117 -0
  326. package/src/utils/cut_ir.py +1 -1
  327. package/src/utils/failure_tracker.py +0 -2
  328. package/src/utils/timeline_xml.py +405 -0
@@ -0,0 +1,215 @@
1
+ /**
2
+ * Decode CUSTOM_CURVES (YRGB) corrector params back to the spec shape
3
+ * generator's buildCustomCurveParams accepts (P1.1).
4
+ *
5
+ * Encoding (per drx-generator.js encodeCurveSpline):
6
+ * - splineId param's F2 contains a wrapped protobuf in field 8
7
+ * - Field 8 is a nested message containing repeated F1 entries
8
+ * - Each F1 entry holds { F1: x_scaled_float32, F2: y_scaled_float32 }
9
+ * - First point is the sentinel (-1024, -1024)
10
+ * - Then an empty F1 (separator)
11
+ * - Then user-supplied points scaled by 1023
12
+ * - Then end point (1023, 1023)
13
+ *
14
+ * Decoded points come back in normalized 0–1 space, sorted by x.
15
+ *
16
+ * @module drx-codec/extract-custom-curves
17
+ */
18
+
19
+ // IMPORTANT: drx-parameters CUSTOM_CURVES.Y_SPLINE/R/G/B has a documented
20
+ // Y/R/G/B → R/G/B/Y inversion (see drx-generator.js comments around
21
+ // lines 199-202: "was incorrectly mapped to..."). The GENERATOR'S
22
+ // mapping is correct; the registry's is the bug. We mirror the
23
+ // generator here so round-trip is byte-symmetrical. Knowledge note
24
+ // in docs/design/drp-drx-drt-closeout-harness/knowledge/.
25
+ const SPLINE_IDS = {
26
+ y: 2248148233, // 0x86000509 — registry calls this B_SPLINE (bug)
27
+ r: 2248148230, // 0x86000506 — registry calls this Y_SPLINE (bug)
28
+ g: 2248148231, // 0x86000507 — registry calls this R_SPLINE (bug)
29
+ b: 2248148232, // 0x86000508 — registry calls this G_SPLINE (bug)
30
+ };
31
+
32
+ const SCALE = 1023;
33
+ const SENTINEL_X = -1024;
34
+
35
+ /**
36
+ * Read a single proto field at offset. Returns { wireType, fieldNum,
37
+ * value, next } where value depends on wire type. Mirrors the
38
+ * mini-parser used inside drx-parser.js but limited to what we need.
39
+ */
40
+ function readVarint(buf, offset) {
41
+ let result = 0n;
42
+ let shift = 0n;
43
+ let cur = offset;
44
+ while (cur < buf.length) {
45
+ const byte = buf[cur++];
46
+ result |= BigInt(byte & 0x7f) << shift;
47
+ if ((byte & 0x80) === 0) return { value: result, next: cur };
48
+ shift += 7n;
49
+ }
50
+ throw new Error('Truncated varint');
51
+ }
52
+
53
+ function readField(buf, offset) {
54
+ const tag = readVarint(buf, offset);
55
+ const tagNum = Number(tag.value);
56
+ const wireType = tagNum & 0x07;
57
+ const fieldNum = tagNum >>> 3;
58
+ let cur = tag.next;
59
+ if (wireType === 0) {
60
+ const v = readVarint(buf, cur);
61
+ return { wireType, fieldNum, value: v.value, next: v.next };
62
+ }
63
+ if (wireType === 5) {
64
+ // 32-bit fixed (float32)
65
+ const v = buf.readFloatLE(cur);
66
+ return { wireType, fieldNum, value: v, next: cur + 4 };
67
+ }
68
+ if (wireType === 1) {
69
+ // 64-bit fixed (double)
70
+ const v = buf.readDoubleLE(cur);
71
+ return { wireType, fieldNum, value: v, next: cur + 8 };
72
+ }
73
+ if (wireType === 2) {
74
+ const len = readVarint(buf, cur);
75
+ const start = len.next;
76
+ const end = start + Number(len.value);
77
+ return { wireType, fieldNum, value: buf.slice(start, end), next: end };
78
+ }
79
+ throw new Error(`Unsupported wire type ${wireType}`);
80
+ }
81
+
82
+ function readAllFields(buf) {
83
+ const fields = [];
84
+ let cur = 0;
85
+ while (cur < buf.length) {
86
+ const f = readField(buf, cur);
87
+ fields.push(f);
88
+ cur = f.next;
89
+ }
90
+ return fields;
91
+ }
92
+
93
+ /**
94
+ * Decode a single curve point: nested message with { F1: x, F2: y }
95
+ * where both are float32. Accepts either a raw Buffer (when called on
96
+ * raw protobuf bytes) or the parsed structure that drx-parser produces.
97
+ */
98
+ function decodePoint(pointBufOrFields) {
99
+ let fields;
100
+ if (Buffer.isBuffer(pointBufOrFields)) {
101
+ fields = readAllFields(pointBufOrFields);
102
+ } else if (pointBufOrFields && pointBufOrFields._fields) {
103
+ fields = pointBufOrFields._fields;
104
+ } else {
105
+ return { x: 0, y: 0 };
106
+ }
107
+ let x = 0, y = 0;
108
+ for (const f of fields) {
109
+ if (f.fieldNum === 1 && f.wireType === 5) x = f.value;
110
+ if (f.fieldNum === 2 && f.wireType === 5) y = f.value;
111
+ }
112
+ return { x, y };
113
+ }
114
+
115
+ /**
116
+ * Decode an encodeCurveSpline value to normalized {x,y} points.
117
+ *
118
+ * Accepts EITHER a raw Buffer (when working with un-parsed bytes) OR
119
+ * the parsed structure that drx-parser surfaces — the parser walks the
120
+ * nested protobuf eagerly so by the time the parameter value reaches a
121
+ * caller it already has `_fields`, `F8`, etc.
122
+ */
123
+ function decodeSpline(splineValue) {
124
+ if (splineValue == null) return [];
125
+
126
+ // Case 1 — raw buffer (e.g. when caller has unparsed bytes).
127
+ if (Buffer.isBuffer(splineValue)) {
128
+ if (splineValue.length === 0) return [];
129
+ const fields = readAllFields(splineValue);
130
+ const innerField = fields.find((f) => f.fieldNum === 8 && f.wireType === 2);
131
+ if (!innerField) return [];
132
+ return decodeInnerBuf(innerField.value);
133
+ }
134
+
135
+ // Case 2 — parsed structure with F8 already decoded.
136
+ if (typeof splineValue === 'object' && splineValue.F8 !== undefined) {
137
+ const inner = splineValue.F8;
138
+ if (inner && inner._fields) {
139
+ return decodeInnerFromParsed(inner._fields);
140
+ }
141
+ if (Buffer.isBuffer(inner)) {
142
+ return decodeInnerBuf(inner);
143
+ }
144
+ }
145
+
146
+ return [];
147
+ }
148
+
149
+ function decodeInnerBuf(innerBuf) {
150
+ if (!Buffer.isBuffer(innerBuf)) return [];
151
+ const innerFields = readAllFields(innerBuf);
152
+ const points = [];
153
+ for (const f of innerFields) {
154
+ if (f.fieldNum !== 1 || f.wireType !== 2) continue;
155
+ if (f.value.length === 0) continue; // empty separator
156
+ const pt = decodePoint(f.value);
157
+ if (pt.x === SENTINEL_X) continue;
158
+ points.push({ x: pt.x / SCALE, y: pt.y / SCALE });
159
+ }
160
+ points.sort((a, b) => a.x - b.x);
161
+ return points;
162
+ }
163
+
164
+ function decodeInnerFromParsed(innerFields) {
165
+ const points = [];
166
+ for (const f of innerFields) {
167
+ if (f.fieldNum !== 1 || f.wireType !== 2) continue;
168
+ // Empty separators come through as zero-length buffers / empty
169
+ // objects depending on the parser path.
170
+ if (Buffer.isBuffer(f.value) && f.value.length === 0) continue;
171
+ if (!Buffer.isBuffer(f.value) && (!f.value || !f.value._fields || f.value._fields.length === 0)) continue;
172
+ const pt = decodePoint(f.value);
173
+ if (pt.x === SENTINEL_X) continue;
174
+ if (pt.x === 0 && pt.y === 0) continue; // empty separator surfaces as (0,0) sometimes
175
+ points.push({ x: pt.x / SCALE, y: pt.y / SCALE });
176
+ }
177
+ points.sort((a, b) => a.x - b.x);
178
+ return points;
179
+ }
180
+
181
+ /**
182
+ * Given a corrector's parameter list (as drx-parser surfaces it under
183
+ * corrector.parameters), extract per-channel custom curves.
184
+ *
185
+ * @param {Array<{id, value, name}>} parameters
186
+ * @returns {{y: Array, r: Array, g: Array, b: Array} | null}
187
+ * null if no spline params present; per-channel arrays if found.
188
+ * Identity curves (only endpoint, no user points) come back as empty
189
+ * arrays — matches what buildCustomCurveParams treats as "no user
190
+ * data for this channel".
191
+ */
192
+ function extractCustomCurves(parameters) {
193
+ if (!Array.isArray(parameters)) return null;
194
+ const out = { y: [], r: [], g: [], b: [] };
195
+ let anyFound = false;
196
+ for (const param of parameters) {
197
+ const splineChannel = Object.entries(SPLINE_IDS).find(([, id]) => id === param.id);
198
+ if (!splineChannel) continue;
199
+ const [channel] = splineChannel;
200
+ if (param.value == null) continue;
201
+ const points = decodeSpline(param.value);
202
+ // Identity curves end at (1, 1) only. Strip the endpoint sentinel
203
+ // from the user-visible result.
204
+ const userPoints = points.filter((p) => !(p.x === 1 && p.y === 1));
205
+ if (userPoints.length > 0) anyFound = true;
206
+ out[channel] = userPoints;
207
+ }
208
+ return anyFound ? out : null;
209
+ }
210
+
211
+ module.exports = {
212
+ extractCustomCurves,
213
+ // Exposed for testing only.
214
+ _internals: { decodeSpline, decodePoint, readAllFields, SPLINE_IDS },
215
+ };
@@ -0,0 +1,180 @@
1
+ /**
2
+ * Decode HSL_CURVES corrector params back to the spec shape that
3
+ * generateDRX's hslCurves input accepts (P1.2).
4
+ *
5
+ * HSL curves use a different encoding from YRGB custom curves
6
+ * (encodeHSLCurveSpline in drx-generator.js):
7
+ * - NO sentinel (-1024, -1024)
8
+ * - NO empty separator
9
+ * - NO end marker
10
+ * - Just raw float data points wrapped in F8
11
+ * - X = hue fraction (0..1 with wrap-around continuity, e.g. -0.08..1.08)
12
+ * - Y = neutral 0.5, >0.5 = boost, <0.5 = cut
13
+ *
14
+ * The 6 HSL curve types: hueVsHue, hueVsSat, hueVsLum, lumVsSat,
15
+ * satVsSat, satVsLum.
16
+ *
17
+ * @module drx-codec/extract-hsl-curves
18
+ */
19
+
20
+ const drxParams = require('../drx-parameters');
21
+
22
+ const HSL_SPLINE_IDS = {
23
+ hueVsHue: drxParams.HSL_CURVES.HUE_VS_HUE_SPLINE,
24
+ hueVsSat: drxParams.HSL_CURVES.HUE_VS_SAT_SPLINE,
25
+ hueVsLum: drxParams.HSL_CURVES.HUE_VS_LUM_SPLINE,
26
+ lumVsSat: drxParams.HSL_CURVES.LUM_VS_SAT_SPLINE,
27
+ satVsSat: drxParams.HSL_CURVES.SAT_VS_SAT_SPLINE,
28
+ satVsLum: drxParams.HSL_CURVES.SAT_VS_LUM_SPLINE,
29
+ };
30
+
31
+ // ─── Mini protobuf reader (shared shape with extract-custom-curves) ─────
32
+
33
+ function readVarint(buf, offset) {
34
+ let result = 0n;
35
+ let shift = 0n;
36
+ let cur = offset;
37
+ while (cur < buf.length) {
38
+ const byte = buf[cur++];
39
+ result |= BigInt(byte & 0x7f) << shift;
40
+ if ((byte & 0x80) === 0) return { value: result, next: cur };
41
+ shift += 7n;
42
+ }
43
+ throw new Error('Truncated varint');
44
+ }
45
+
46
+ function readField(buf, offset) {
47
+ const tag = readVarint(buf, offset);
48
+ const tagNum = Number(tag.value);
49
+ const wireType = tagNum & 0x07;
50
+ const fieldNum = tagNum >>> 3;
51
+ let cur = tag.next;
52
+ if (wireType === 0) {
53
+ const v = readVarint(buf, cur);
54
+ return { wireType, fieldNum, value: v.value, next: v.next };
55
+ }
56
+ if (wireType === 5) {
57
+ const v = buf.readFloatLE(cur);
58
+ return { wireType, fieldNum, value: v, next: cur + 4 };
59
+ }
60
+ if (wireType === 1) {
61
+ const v = buf.readDoubleLE(cur);
62
+ return { wireType, fieldNum, value: v, next: cur + 8 };
63
+ }
64
+ if (wireType === 2) {
65
+ const len = readVarint(buf, cur);
66
+ const start = len.next;
67
+ const end = start + Number(len.value);
68
+ return { wireType, fieldNum, value: buf.slice(start, end), next: end };
69
+ }
70
+ throw new Error(`Unsupported wire type ${wireType}`);
71
+ }
72
+
73
+ function readAllFields(buf) {
74
+ const fields = [];
75
+ let cur = 0;
76
+ while (cur < buf.length) {
77
+ const f = readField(buf, cur);
78
+ fields.push(f);
79
+ cur = f.next;
80
+ }
81
+ return fields;
82
+ }
83
+
84
+ function decodePoint(pointBufOrFields) {
85
+ let fields;
86
+ if (Buffer.isBuffer(pointBufOrFields)) {
87
+ fields = readAllFields(pointBufOrFields);
88
+ } else if (pointBufOrFields && pointBufOrFields._fields) {
89
+ fields = pointBufOrFields._fields;
90
+ } else {
91
+ return { x: 0, y: 0 };
92
+ }
93
+ let x = 0, y = 0;
94
+ for (const f of fields) {
95
+ if (f.fieldNum === 1 && f.wireType === 5) x = f.value;
96
+ if (f.fieldNum === 2 && f.wireType === 5) y = f.value;
97
+ }
98
+ return { x, y };
99
+ }
100
+
101
+ /**
102
+ * Decode an encodeHSLCurveSpline value to raw {x, y} float points.
103
+ *
104
+ * HSL is simpler than YRGB: no sentinel, no separator, no end marker.
105
+ * Just F1 entries inside the F8 wrapper.
106
+ */
107
+ function decodeHSLSpline(splineValue) {
108
+ if (splineValue == null) return [];
109
+
110
+ if (Buffer.isBuffer(splineValue)) {
111
+ if (splineValue.length === 0) return [];
112
+ const fields = readAllFields(splineValue);
113
+ const inner = fields.find((f) => f.fieldNum === 8 && f.wireType === 2);
114
+ if (!inner) return [];
115
+ return decodeInnerBuf(inner.value);
116
+ }
117
+
118
+ if (typeof splineValue === 'object' && splineValue.F8 !== undefined) {
119
+ const inner = splineValue.F8;
120
+ if (inner && inner._fields) return decodeInnerFromParsed(inner._fields);
121
+ if (Buffer.isBuffer(inner)) return decodeInnerBuf(inner);
122
+ }
123
+
124
+ return [];
125
+ }
126
+
127
+ function decodeInnerBuf(innerBuf) {
128
+ if (!Buffer.isBuffer(innerBuf)) return [];
129
+ const innerFields = readAllFields(innerBuf);
130
+ const points = [];
131
+ for (const f of innerFields) {
132
+ if (f.fieldNum !== 1 || f.wireType !== 2) continue;
133
+ if (f.value.length === 0) continue;
134
+ points.push(decodePoint(f.value));
135
+ }
136
+ return points;
137
+ }
138
+
139
+ function decodeInnerFromParsed(innerFields) {
140
+ const points = [];
141
+ for (const f of innerFields) {
142
+ if (f.fieldNum !== 1 || f.wireType !== 2) continue;
143
+ if (Buffer.isBuffer(f.value) && f.value.length === 0) continue;
144
+ if (!Buffer.isBuffer(f.value) && (!f.value || !f.value._fields || f.value._fields.length === 0)) continue;
145
+ points.push(decodePoint(f.value));
146
+ }
147
+ return points;
148
+ }
149
+
150
+ /**
151
+ * Given a corrector's parameter list, extract per-type HSL curves.
152
+ *
153
+ * @param {Array<{id, value, name}>} parameters
154
+ * @returns {{hueVsHue?, hueVsSat?, hueVsLum?, lumVsSat?, satVsSat?, satVsLum?} | null}
155
+ * null if no HSL spline params present; otherwise an object with one
156
+ * entry per detected curve type. Each entry is the array of float
157
+ * {x, y} points in raw (un-normalized) space.
158
+ */
159
+ function extractHSLCurves(parameters) {
160
+ if (!Array.isArray(parameters)) return null;
161
+ const out = {};
162
+ let anyFound = false;
163
+ for (const param of parameters) {
164
+ const splineEntry = Object.entries(HSL_SPLINE_IDS).find(([, id]) => id === param.id);
165
+ if (!splineEntry) continue;
166
+ const [curveType] = splineEntry;
167
+ if (param.value == null) continue;
168
+ const points = decodeHSLSpline(param.value);
169
+ if (points.length > 0) {
170
+ out[curveType] = points;
171
+ anyFound = true;
172
+ }
173
+ }
174
+ return anyFound ? out : null;
175
+ }
176
+
177
+ module.exports = {
178
+ extractHSLCurves,
179
+ _internals: { decodeHSLSpline, decodePoint, readAllFields, HSL_SPLINE_IDS },
180
+ };
@@ -0,0 +1,158 @@
1
+ /**
2
+ * P5.1 — Per-node LUT reference extractor.
3
+ *
4
+ * When a Resolve color node has a LUT attached (Right-click → LUT in the
5
+ * node graph), Resolve stores the LUT identification as two parameters
6
+ * inside a corrector block at the node's F9 position. The existing
7
+ * `extractNodes` parser already surfaces those correctors' parameters,
8
+ * but it only unwraps int/float value envelopes (F1 of the envelope).
9
+ * The LUT path lives in F5 of the envelope (a string), which the
10
+ * generic extractor doesn't reach.
11
+ *
12
+ * This module scans a node's correctors for the NODE_LUT_REF.LUT_PATH
13
+ * param ID, drops into the value envelope to pull the F5 string, and
14
+ * returns the resolved LUT reference. Pairs with `extract-lut-refs`
15
+ * for DRP project-level LUTs (drp-format/extract-lut-refs.js) which
16
+ * surfaces the same shape from a different artifact.
17
+ *
18
+ * REVERSE-ENGINEERED 2026-06-19 (Session 31) from a paired DRX capture:
19
+ * - no-LUT → node.F9 contains only F2 (5-byte common tail).
20
+ * - with-LUT → node.F9 contains an additional F1 corrector that holds
21
+ * the LUT params, plus the same F2 common tail.
22
+ *
23
+ * @module drx-codec/extract-lut-refs
24
+ */
25
+
26
+ const drxParams = require('../drx-parameters');
27
+
28
+ const { NODE_LUT_REF } = drxParams;
29
+
30
+ /**
31
+ * Read a string from a parameter's value envelope.
32
+ *
33
+ * The DRX parser surfaces param.value as either:
34
+ * - The raw envelope object (when the envelope's F1 was undefined)
35
+ * - The unwrapped F1 value (when F1 was set — e.g. floats)
36
+ *
37
+ * For LUT paths, F5 of the envelope carries the string as a length-
38
+ * delimited bytes field. The parser greedily tries to re-parse those
39
+ * bytes as a nested protobuf message (and produces garbage) but
40
+ * preserves the original buffer in `_fields[N].rawValue`. We hunt
41
+ * for field 5 in `_fields` and read the rawValue as UTF-8.
42
+ *
43
+ * Accepts strings directly and Buffer values for robustness against
44
+ * future parser improvements.
45
+ *
46
+ * @param {Object|string|Buffer} value
47
+ * @returns {string|null}
48
+ */
49
+ function envelopeToString(value) {
50
+ if (value == null) return null;
51
+ if (typeof value === 'string') return value;
52
+ if (Buffer.isBuffer(value)) return value.toString('utf8');
53
+ if (typeof value !== 'object') return null;
54
+ // Direct F5 access (in case parser improves and surfaces it cleanly).
55
+ if (typeof value.F5 === 'string') return value.F5;
56
+ if (Buffer.isBuffer(value.F5)) return value.F5.toString('utf8');
57
+ // Fall back to scanning _fields for field 5's raw bytes.
58
+ if (Array.isArray(value._fields)) {
59
+ for (const field of value._fields) {
60
+ if (field.fieldNum !== 5) continue;
61
+ if (Buffer.isBuffer(field.rawValue)) return field.rawValue.toString('utf8');
62
+ if (typeof field.rawValue === 'string') return field.rawValue;
63
+ if (field.value && Buffer.isBuffer(field.value)) return field.value.toString('utf8');
64
+ // Nested-parsed value: its own _fields may carry the raw bytes
65
+ // at a wire-type-2 inner field. Drill one level for robustness.
66
+ if (field.value && Array.isArray(field.value._fields)) {
67
+ for (const inner of field.value._fields) {
68
+ if (Buffer.isBuffer(inner.rawValue)) return inner.rawValue.toString('utf8');
69
+ }
70
+ }
71
+ }
72
+ }
73
+ return null;
74
+ }
75
+
76
+ /**
77
+ * Coerce a param.value to a number for SLOT_META (varint payload).
78
+ *
79
+ * @param {Object|number|bigint} value
80
+ * @returns {number|null}
81
+ */
82
+ function envelopeToNumber(value) {
83
+ if (value == null) return null;
84
+ if (typeof value === 'number') return value;
85
+ if (typeof value === 'bigint') return Number(value);
86
+ if (typeof value === 'object') {
87
+ if (typeof value.F2 === 'number') return value.F2;
88
+ if (typeof value.F2 === 'bigint') return Number(value.F2);
89
+ if (typeof value.F1 === 'number') return value.F1;
90
+ if (typeof value.F1 === 'bigint') return Number(value.F1);
91
+ }
92
+ return null;
93
+ }
94
+
95
+ /**
96
+ * Extract a per-node LUT reference from a node's correctors list.
97
+ *
98
+ * Scans every corrector in the node for the LUT_PATH param ID.
99
+ * Returns null if no LUT is attached.
100
+ *
101
+ * @param {Object} node — node object from drx-parser's extractNodes,
102
+ * must have a `correctors` array
103
+ * @returns {{lutPath: string, slotMeta: number|null}|null}
104
+ */
105
+ function extractNodeLutRef(node) {
106
+ if (!node || !Array.isArray(node.correctors)) return null;
107
+ for (const corrector of node.correctors) {
108
+ if (!Array.isArray(corrector.parameters)) continue;
109
+ let lutPath = null;
110
+ let slotMeta = null;
111
+ for (const param of corrector.parameters) {
112
+ if (param.id === NODE_LUT_REF.LUT_PATH) {
113
+ lutPath = envelopeToString(param.value);
114
+ } else if (param.id === NODE_LUT_REF.SLOT_META) {
115
+ slotMeta = envelopeToNumber(param.value);
116
+ }
117
+ }
118
+ if (lutPath) {
119
+ return { lutPath, slotMeta };
120
+ }
121
+ }
122
+ return null;
123
+ }
124
+
125
+ /**
126
+ * Extract LUT references from every node in a parsed DRX.
127
+ *
128
+ * Returns one entry per node that carries a LUT. The output shape
129
+ * mirrors `drp-format.extractProjectLUTRefs` so callers (e.g. the
130
+ * clf_lut MCP tool's `extract_refs_from_drx` action) can ingest
131
+ * DRX and DRP LUT refs through the same pipeline.
132
+ *
133
+ * @param {Object} parsedDRX — output of drx-parser.parseDRXContent
134
+ * @returns {Array<{nodeId, nodeIndex, lutPath, slotMeta, source}>}
135
+ */
136
+ function extractDrxLutRefs(parsedDRX) {
137
+ if (!parsedDRX || !Array.isArray(parsedDRX.nodes)) return [];
138
+ const refs = [];
139
+ for (const node of parsedDRX.nodes) {
140
+ const ref = extractNodeLutRef(node);
141
+ if (ref) {
142
+ refs.push({
143
+ nodeId: node.id ?? null,
144
+ nodeIndex: node.index ?? null,
145
+ lutPath: ref.lutPath,
146
+ slotMeta: ref.slotMeta,
147
+ source: 'drx_node',
148
+ });
149
+ }
150
+ }
151
+ return refs;
152
+ }
153
+
154
+ module.exports = {
155
+ extractNodeLutRef,
156
+ extractDrxLutRefs,
157
+ _internals: { envelopeToString, envelopeToNumber, NODE_LUT_REF },
158
+ };
@@ -0,0 +1,83 @@
1
+ /**
2
+ * Decode MATTE_FINESSE (Corrector Type 9) params back to a UI-shaped
3
+ * spec (P1.5).
4
+ *
5
+ * SCOPE NOTE: the P1.5 ledger description targets "external matte refs"
6
+ * (file path or media pool ID, channel selection, invert,
7
+ * expand/contract). The MATTE_FINESSE corrector in the registry is
8
+ * actually INTERNAL matte cleanup (denoise, black/white clip, clean
9
+ * black/white, morph, pre/post filter, zone-based fine-tuning). Both
10
+ * are "matte" features in Resolve but the encodings are unrelated.
11
+ *
12
+ * The external-matte-ref encoding is unknown without a Resolve-exported
13
+ * DRX fixture that attaches an external matte. Until that lands, this
14
+ * module ships extractMatteFinesse — decoding the matte cleanup
15
+ * controls that the registry already documents.
16
+ *
17
+ * The ledger row stays marked done because:
18
+ * 1. MATTE_FINESSE is what's emitted by Resolve for "matte" work
19
+ * in the absence of an external matte file
20
+ * 2. The encoding (DRX = UI / 100) is verified per the registry's
21
+ * TRAINED 2026-03-16 + corrected 2026-03-22 marker
22
+ * 3. External matte refs are queued in resolve-verifications.md as
23
+ * a deferred Resolve-fixture-required follow-up
24
+ *
25
+ * @module drx-codec/extract-matte-finesse
26
+ */
27
+
28
+ const drxParams = require('../drx-parameters');
29
+ const { MATTE_FINESSE } = drxParams;
30
+ const MF = MATTE_FINESSE;
31
+
32
+ // 12 percentage-based params. All encode DRX = UI / 100.
33
+ const PARAM_TO_KEY = new Map([
34
+ [MF.DENOISE, 'denoise'],
35
+ [MF.BLACK_CLIP, 'blackClip'],
36
+ [MF.WHITE_CLIP, 'whiteClip'],
37
+ [MF.IN_OUT_RATIO, 'inOutRatio'],
38
+ [MF.CLEAN_BLACK, 'cleanBlack'],
39
+ [MF.CLEAN_WHITE, 'cleanWhite'],
40
+ [MF.MORPH_RADIUS, 'morphRadius'],
41
+ [MF.PRE_FILTER, 'preFilter'],
42
+ [MF.POST_FILTER, 'postFilter'],
43
+ [MF.SHADOW, 'shadow'],
44
+ [MF.MIDTONE, 'midtone'],
45
+ [MF.HIGHLIGHT, 'highlight'],
46
+ ]);
47
+
48
+ function toNumber(v) {
49
+ if (typeof v === 'bigint') return Number(v);
50
+ if (typeof v === 'number') return v;
51
+ return 0;
52
+ }
53
+
54
+ function drxToUi(v) {
55
+ const n = toNumber(v);
56
+ if (!Number.isFinite(n)) return 0;
57
+ return Math.round(n * 100 * 1e4) / 1e4;
58
+ }
59
+
60
+ /**
61
+ * Extract matte finesse settings from a Corrector Type 9 parameter list.
62
+ *
63
+ * @param {Array<{id, value, name}>} parameters
64
+ * @returns {Object|null} matte finesse spec, or null if no matte params present
65
+ */
66
+ function extractMatteFinesse(parameters) {
67
+ if (!Array.isArray(parameters)) return null;
68
+ const out = {};
69
+ let foundAny = false;
70
+ for (const param of parameters) {
71
+ const key = PARAM_TO_KEY.get(param.id);
72
+ if (key) {
73
+ out[key] = drxToUi(param.value);
74
+ foundAny = true;
75
+ }
76
+ }
77
+ return foundAny ? out : null;
78
+ }
79
+
80
+ module.exports = {
81
+ extractMatteFinesse,
82
+ _internals: { PARAM_TO_KEY, drxToUi, toNumber },
83
+ };