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,249 @@
1
+ /**
2
+ * Node-graph LAYOUT rewriter — repositions nodes in a DRX/LmVersion grade Body
3
+ * without touching any grade content.
4
+ *
5
+ * A grade Body is [0x81] + zstd(protobuf). Inside the protobuf, each F1 container
6
+ * holds F7 node messages whose F4 (xPos) / F5 (yPos) varints are the node-editor
7
+ * layout. Resolve's own "Cleanup Node Graph" rewrites ONLY those two fields
8
+ * (verified by before/after Project.db diff, 2026-07): its clean layout is an
9
+ * evenly spaced single row (observed x = 290/786/1280 at y = 428 for 3 nodes).
10
+ *
11
+ * This module replicates that: every byte other than the F4/F5 varints (and the
12
+ * containing length prefixes) survives verbatim, so the rewrite is lossless for
13
+ * OFX/uncalibrated params, keyframes, labels — everything.
14
+ *
15
+ * Consumed by the drx tool's `relayout` action (live single-shot path: grab →
16
+ * relayout → ApplyGradeFromDRX) and project_db's `relayout_node_graphs`
17
+ * (closed-project bulk patch of ListMgt::LmVersion rows).
18
+ */
19
+
20
+ 'use strict';
21
+
22
+ const nodeZlib = require('zlib');
23
+
24
+ // Same zstd backend priority as drx-generator.js: native node:zlib (Node 22+),
25
+ // zstd-codec (WASM), fzstd (decompress-only — compress throws clearly).
26
+ const HAS_NATIVE_ZSTD =
27
+ typeof nodeZlib.zstdCompressSync === 'function' && typeof nodeZlib.zstdDecompressSync === 'function';
28
+
29
+ let ZstdCodec = null;
30
+ try {
31
+ ZstdCodec = require('zstd-codec').ZstdCodec;
32
+ } catch {
33
+ /* optional */
34
+ }
35
+
36
+ let backend = null;
37
+ async function getZstd() {
38
+ if (backend) return backend;
39
+ if (HAS_NATIVE_ZSTD) {
40
+ backend = {
41
+ decompress: (data) => nodeZlib.zstdDecompressSync(Buffer.from(data)),
42
+ compress: (data) => nodeZlib.zstdCompressSync(Buffer.from(data)),
43
+ };
44
+ return backend;
45
+ }
46
+ if (ZstdCodec) {
47
+ backend = await new Promise((resolve) => {
48
+ ZstdCodec.run((zstd) => {
49
+ const simple = new zstd.Simple();
50
+ resolve({
51
+ decompress: (data) => Buffer.from(simple.decompress(new Uint8Array(data))),
52
+ compress: (data) => Buffer.from(simple.compress(new Uint8Array(data))),
53
+ });
54
+ });
55
+ });
56
+ return backend;
57
+ }
58
+ const fzstd = require('fzstd');
59
+ backend = {
60
+ decompress: (data) => Buffer.from(fzstd.decompress(new Uint8Array(data))),
61
+ compress: () => {
62
+ throw new Error('no zstd compressor available (need Node 22+ zlib zstd or zstd-codec)');
63
+ },
64
+ };
65
+ return backend;
66
+ }
67
+
68
+ // ---- minimal protobuf walker (varint + length-delimited only, as the Body uses) ----
69
+
70
+ function readVarint(buf, p) {
71
+ let v = 0n;
72
+ let s = 0n;
73
+ let i = p;
74
+ for (;;) {
75
+ const b = buf[i++];
76
+ v |= BigInt(b & 0x7f) << s;
77
+ if (!(b & 0x80)) break;
78
+ s += 7n;
79
+ }
80
+ return [v, i];
81
+ }
82
+
83
+ function encodeVarint(v) {
84
+ v = BigInt(v);
85
+ const out = [];
86
+ while (v > 0x7fn) {
87
+ out.push(Number(v & 0x7fn) | 0x80);
88
+ v >>= 7n;
89
+ }
90
+ out.push(Number(v));
91
+ return Buffer.from(out);
92
+ }
93
+
94
+ /** Decode one message level into {f, wt, start, end, val} field records. */
95
+ function fields(buf) {
96
+ const out = [];
97
+ let p = 0;
98
+ while (p < buf.length) {
99
+ const start = p;
100
+ let tag;
101
+ [tag, p] = readVarint(buf, p);
102
+ const f = Number(tag >> 3n);
103
+ const wt = Number(tag & 7n);
104
+ let end = p;
105
+ let val = null;
106
+ if (wt === 0) [val, end] = readVarint(buf, p);
107
+ else if (wt === 1) end = p + 8;
108
+ else if (wt === 5) end = p + 4;
109
+ else if (wt === 2) {
110
+ let len;
111
+ [len, p] = readVarint(buf, p);
112
+ end = p + Number(len);
113
+ val = buf.subarray(p, end);
114
+ } else throw new Error(`unsupported wire type ${wt} at offset ${start}`);
115
+ if (end > buf.length) throw new Error('truncated protobuf');
116
+ out.push({ f, wt, start, end, val });
117
+ p = end;
118
+ }
119
+ return out;
120
+ }
121
+
122
+ // Node message field numbers (see DRX-VALUE-SCALING.md / calibration notes):
123
+ // F4 = xPos varint, F5 = yPos varint.
124
+ const F_NODE = 7; // node message inside the F1 container
125
+ const F_X = 4;
126
+ const F_Y = 5;
127
+
128
+ /**
129
+ * Resolve-cleanup-style positions for n nodes: one evenly spaced row.
130
+ * Defaults are the exact values Resolve's own Cleanup Node Graph produced
131
+ * (3-node measurement); spacing stays fixed rather than adapting to n so the
132
+ * result matches native cleanup for typical graphs.
133
+ */
134
+ function cleanRowPositions(n, { originX = 290, originY = 428, spacingX = 495 } = {}) {
135
+ return Array.from({ length: n }, (_, i) => [originX + i * spacingX, originY]);
136
+ }
137
+
138
+ /** Rewrite F4/F5 in one node message buffer; appends them if absent. */
139
+ function rewriteNodeMessage(nodeBuf, x, y) {
140
+ const parts = [];
141
+ let sawX = false;
142
+ let sawY = false;
143
+ for (const h of fields(nodeBuf)) {
144
+ if (h.f === F_X && h.wt === 0) {
145
+ sawX = true;
146
+ parts.push(encodeVarint((F_X << 3) | 0), encodeVarint(x));
147
+ } else if (h.f === F_Y && h.wt === 0) {
148
+ sawY = true;
149
+ parts.push(encodeVarint((F_Y << 3) | 0), encodeVarint(y));
150
+ } else {
151
+ parts.push(nodeBuf.subarray(h.start, h.end));
152
+ }
153
+ }
154
+ if (!sawX) parts.push(encodeVarint((F_X << 3) | 0), encodeVarint(x));
155
+ if (!sawY) parts.push(encodeVarint((F_Y << 3) | 0), encodeVarint(y));
156
+ return Buffer.concat(parts);
157
+ }
158
+
159
+ /**
160
+ * Reposition every node in a grade Body.
161
+ *
162
+ * @param {Buffer} body — raw Body blob: 0x81 magic + zstd(protobuf)
163
+ * @param {Object} [options]
164
+ * @param {Array<[number,number]>} [options.positions] — explicit [x,y] per node
165
+ * (encounter order = node index order); omit for the clean-row layout.
166
+ * @param {number} [options.originX] @param {number} [options.originY]
167
+ * @param {number} [options.spacingX] — clean-row tuning when positions omitted.
168
+ * @returns {Promise<{body: Buffer, nodeCount: number, positions: Array<[number,number]>}>}
169
+ */
170
+ async function relayoutBody(body, options = {}) {
171
+ if (!Buffer.isBuffer(body)) body = Buffer.from(body);
172
+ if (body[0] !== 0x81) throw new Error('not a grade Body (missing 0x81 magic)');
173
+ const zstd = await getZstd();
174
+ const proto = zstd.decompress(body.subarray(1));
175
+
176
+ // First pass: count nodes so the default layout can be sized.
177
+ const top = fields(proto);
178
+ let nodeCount = 0;
179
+ for (const t of top) {
180
+ if (t.f === 1 && t.wt === 2) for (const g of fields(t.val)) if (g.f === F_NODE && g.wt === 2) nodeCount++;
181
+ }
182
+ if (nodeCount === 0) throw new Error('relayout refused: Body decodes to 0 nodes');
183
+
184
+ const positions = options.positions || cleanRowPositions(nodeCount, options);
185
+ if (positions.length < nodeCount) {
186
+ throw new Error(`positions has ${positions.length} entries but the grade has ${nodeCount} nodes`);
187
+ }
188
+ for (const [x, y] of positions.slice(0, nodeCount)) {
189
+ if (!Number.isInteger(x) || !Number.isInteger(y) || x < 0 || y < 0) {
190
+ throw new Error('positions must be non-negative integers (protobuf varints)');
191
+ }
192
+ }
193
+
194
+ // Second pass: rebuild, rewriting each node message and re-lengthing its containers.
195
+ let nodeIdx = 0;
196
+ const rebuilt = [];
197
+ for (const t of top) {
198
+ if (t.f === 1 && t.wt === 2) {
199
+ const innerParts = [];
200
+ for (const g of fields(t.val)) {
201
+ if (g.f === F_NODE && g.wt === 2) {
202
+ const [x, y] = positions[nodeIdx++];
203
+ const newNode = rewriteNodeMessage(g.val, x, y);
204
+ innerParts.push(encodeVarint((F_NODE << 3) | 2), encodeVarint(newNode.length), newNode);
205
+ } else {
206
+ innerParts.push(t.val.subarray(g.start, g.end));
207
+ }
208
+ }
209
+ const newInner = Buffer.concat(innerParts);
210
+ rebuilt.push(encodeVarint((1 << 3) | 2), encodeVarint(newInner.length), newInner);
211
+ } else {
212
+ rebuilt.push(proto.subarray(t.start, t.end));
213
+ }
214
+ }
215
+
216
+ const out = Buffer.concat([Buffer.from([0x81]), zstd.compress(Buffer.concat(rebuilt))]);
217
+ return { body: out, nodeCount, positions: positions.slice(0, nodeCount) };
218
+ }
219
+
220
+ /** Hex-string convenience wrapper (DRX <Body> / DB dumps are handled as hex upstream). */
221
+ async function relayoutBodyHex(bodyHex, options = {}) {
222
+ const r = await relayoutBody(Buffer.from(bodyHex.trim(), 'hex'), options);
223
+ return { ...r, bodyHex: r.body.toString('hex') };
224
+ }
225
+
226
+ /** Decode just the node positions from a Body (for dry runs / verification). */
227
+ async function readNodePositions(body) {
228
+ if (!Buffer.isBuffer(body)) body = Buffer.from(body);
229
+ if (body[0] !== 0x81) throw new Error('not a grade Body (missing 0x81 magic)');
230
+ const zstd = await getZstd();
231
+ const proto = zstd.decompress(body.subarray(1));
232
+ const positions = [];
233
+ for (const t of fields(proto)) {
234
+ if (t.f !== 1 || t.wt !== 2) continue;
235
+ for (const g of fields(t.val)) {
236
+ if (g.f !== F_NODE || g.wt !== 2) continue;
237
+ let x = null;
238
+ let y = null;
239
+ for (const h of fields(g.val)) {
240
+ if (h.f === F_X && h.wt === 0) x = Number(h.val);
241
+ if (h.f === F_Y && h.wt === 0) y = Number(h.val);
242
+ }
243
+ positions.push([x, y]);
244
+ }
245
+ }
246
+ return positions;
247
+ }
248
+
249
+ module.exports = { relayoutBody, relayoutBodyHex, readNodePositions, cleanRowPositions };
@@ -0,0 +1,393 @@
1
+ /**
2
+ * Resolved DRX Generator
3
+ *
4
+ * Integrates the Tool Resolver with the DRX Generator to provide
5
+ * intent-aware, tool-selection-based grade creation.
6
+ *
7
+ * This module wraps the existing drx-generator.js with tool resolution,
8
+ * ensuring that:
9
+ * - Contrast uses the appropriate tool (Lift/Gain vs. Contrast Corrector)
10
+ * - Exposure uses proper compensation (Offset vs. Gain)
11
+ * - Temperature uses the right approach (global vs. split)
12
+ * - User preferences are respected
13
+ *
14
+ * @module drx/resolved-drx-generator
15
+ */
16
+
17
+ const toolResolver = require('./tool-resolver');
18
+ const vocabularyIntents = require('./vocabulary-intents');
19
+ const drxGenerator = require('./drx-generator');
20
+
21
+ // ═══════════════════════════════════════════════════════════════════════════════
22
+ // RESOLVED PARAMETER CONVERSION
23
+ // ═══════════════════════════════════════════════════════════════════════════════
24
+
25
+ /**
26
+ * Convert tool-resolved parameters to DRX generator format
27
+ * The tool resolver outputs structured params, this converts them to flat format
28
+ *
29
+ * @param {Object} resolved - Output from toolResolver.resolve()
30
+ * @returns {Object} Flat parameter object for DRX generator
31
+ */
32
+ function convertResolvedToFlat(resolved) {
33
+ const flat = {};
34
+ const params = resolved.params || {};
35
+
36
+ // ═══════════════════════════════════════════════════════════════════════════
37
+ // Primary Wheels (Lift/Gamma/Gain)
38
+ // ═══════════════════════════════════════════════════════════════════════════
39
+
40
+ // Lift
41
+ if (params.liftR !== undefined) flat.liftR = params.liftR;
42
+ if (params.liftG !== undefined) flat.liftG = params.liftG;
43
+ if (params.liftB !== undefined) flat.liftB = params.liftB;
44
+ if (params.liftMaster !== undefined) flat.liftMaster = params.liftMaster;
45
+
46
+ // Gamma
47
+ if (params.gammaR !== undefined) flat.gammaR = params.gammaR;
48
+ if (params.gammaG !== undefined) flat.gammaG = params.gammaG;
49
+ if (params.gammaB !== undefined) flat.gammaB = params.gammaB;
50
+ if (params.gammaMaster !== undefined) flat.gammaMaster = params.gammaMaster;
51
+
52
+ // Gain
53
+ if (params.gainR !== undefined) flat.gainR = params.gainR;
54
+ if (params.gainG !== undefined) flat.gainG = params.gainG;
55
+ if (params.gainB !== undefined) flat.gainB = params.gainB;
56
+ if (params.gainMaster !== undefined) flat.gainMaster = params.gainMaster;
57
+
58
+ // Offset
59
+ if (params.offsetR !== undefined) flat.offsetR = params.offsetR;
60
+ if (params.offsetG !== undefined) flat.offsetG = params.offsetG;
61
+ if (params.offsetB !== undefined) flat.offsetB = params.offsetB;
62
+
63
+ // ═══════════════════════════════════════════════════════════════════════════
64
+ // Log Wheels
65
+ // ═══════════════════════════════════════════════════════════════════════════
66
+
67
+ if (params.logShadowR !== undefined) flat.logShadowR = params.logShadowR;
68
+ if (params.logShadowG !== undefined) flat.logShadowG = params.logShadowG;
69
+ if (params.logShadowB !== undefined) flat.logShadowB = params.logShadowB;
70
+ if (params.logMidR !== undefined) flat.logMidR = params.logMidR;
71
+ if (params.logMidG !== undefined) flat.logMidG = params.logMidG;
72
+ if (params.logMidB !== undefined) flat.logMidB = params.logMidB;
73
+ if (params.logHighR !== undefined) flat.logHighR = params.logHighR;
74
+ if (params.logHighG !== undefined) flat.logHighG = params.logHighG;
75
+ if (params.logHighB !== undefined) flat.logHighB = params.logHighB;
76
+
77
+ // ═══════════════════════════════════════════════════════════════════════════
78
+ // Contrast Corrector
79
+ // ═══════════════════════════════════════════════════════════════════════════
80
+
81
+ if (params.contrast !== undefined) flat.contrast = params.contrast;
82
+ if (params.pivot !== undefined) flat.pivot = params.pivot;
83
+ if (params.contrastHighRange !== undefined) flat.contrastHighRange = params.contrastHighRange;
84
+ if (params.contrastLowRange !== undefined) flat.contrastLowRange = params.contrastLowRange;
85
+ if (params.softClipHigh !== undefined) flat.softClipHigh = params.softClipHigh;
86
+ if (params.softClipLow !== undefined) flat.softClipLow = params.softClipLow;
87
+
88
+ // ═══════════════════════════════════════════════════════════════════════════
89
+ // Temperature/Tint/Saturation
90
+ // ═══════════════════════════════════════════════════════════════════════════
91
+
92
+ if (params.temperature !== undefined) flat.temperature = params.temperature;
93
+ if (params.tint !== undefined) flat.tint = params.tint;
94
+ if (params.saturation !== undefined) flat.saturation = params.saturation;
95
+ if (params.colorBoost !== undefined) flat.colorBoost = params.colorBoost;
96
+ if (params.midtoneDetail !== undefined) flat.midtoneDetail = params.midtoneDetail;
97
+
98
+ // ═══════════════════════════════════════════════════════════════════════════
99
+ // HDR Zones
100
+ // ═══════════════════════════════════════════════════════════════════════════
101
+
102
+ if (params.hdrDark !== undefined) flat.hdrDark = params.hdrDark;
103
+ if (params.hdrShadow !== undefined) flat.hdrShadow = params.hdrShadow;
104
+ if (params.hdrLight !== undefined) flat.hdrLight = params.hdrLight;
105
+ if (params.hdrHighlight !== undefined) flat.hdrHighlight = params.hdrHighlight;
106
+ if (params.hdrGlobal !== undefined) flat.hdrGlobal = params.hdrGlobal;
107
+
108
+ return flat;
109
+ }
110
+
111
+ // ═══════════════════════════════════════════════════════════════════════════════
112
+ // MAIN INTERFACE
113
+ // ═══════════════════════════════════════════════════════════════════════════════
114
+
115
+ /**
116
+ * Generate a DRX file with tool-aware parameter resolution
117
+ *
118
+ * @param {Object} options
119
+ * @param {Object} options.adjustments - Raw adjustments from AI or vocabulary
120
+ * { contrast, exposure, temperature, saturation, tint, shadowLift, etc. }
121
+ * @param {Object} options.intent - Optional intent signals
122
+ * { contrast: 'punchy', temperature: 'split', etc. }
123
+ * @param {string} options.nodeLabel - Node label for the grade
124
+ * @param {Object} options.userPreferences - Optional user preferences override
125
+ * @returns {Promise<Buffer>} DRX file buffer
126
+ */
127
+ async function generateResolvedDRX(options) {
128
+ const {
129
+ adjustments = {},
130
+ intent = {},
131
+ nodeLabel = 'Color Grade',
132
+ userPreferences = null,
133
+ } = options;
134
+
135
+ // Apply user preferences if provided
136
+ if (userPreferences) {
137
+ toolResolver.setUserPreferences(userPreferences);
138
+ }
139
+
140
+ // Resolve tools based on adjustments and intent
141
+ const resolved = toolResolver.resolve({ adjustments, intent });
142
+
143
+ // Log resolution for debugging
144
+ console.log('[ResolvedDRX] Tool resolution:', {
145
+ tools: resolved.tools,
146
+ inputAdjustments: Object.keys(adjustments).filter(k => adjustments[k] !== undefined),
147
+ intent: Object.keys(intent).filter(k => intent[k] !== undefined),
148
+ });
149
+
150
+ // Convert to flat format for DRX generator
151
+ const flatParams = convertResolvedToFlat(resolved);
152
+
153
+ // Convert flat params to structured format using parseAdjustments
154
+ const gradeParams = drxGenerator.parseAdjustments(flatParams);
155
+
156
+ // Generate DRX using existing generator
157
+ const drxContent = await drxGenerator.generateDRX(gradeParams, {
158
+ label: nodeLabel,
159
+ });
160
+
161
+ // Convert string to buffer for consistency
162
+ const drxBuffer = Buffer.from(drxContent, 'utf8');
163
+
164
+ return {
165
+ buffer: drxBuffer,
166
+ resolved: {
167
+ tools: resolved.tools,
168
+ params: flatParams,
169
+ intent,
170
+ metadata: resolved.metadata,
171
+ },
172
+ };
173
+ }
174
+
175
+ /**
176
+ * Generate a DRX file from a user request string
177
+ * Extracts intents automatically from the request text
178
+ *
179
+ * @param {Object} options
180
+ * @param {string} options.request - User request string (e.g., "make it punchy and warm")
181
+ * @param {Object} options.adjustments - Adjustments from vocabulary/AI lookup
182
+ * @param {string} options.nodeLabel - Node label
183
+ * @param {Object} options.userPreferences - Optional user preferences
184
+ * @returns {Promise<Object>} { buffer, resolved }
185
+ */
186
+ async function generateFromRequest(options) {
187
+ const {
188
+ request = '',
189
+ adjustments = {},
190
+ nodeLabel = 'Color Grade',
191
+ userPreferences = null,
192
+ } = options;
193
+
194
+ // Extract intents from the request string
195
+ const intent = vocabularyIntents.extractIntentsFromRequest(request);
196
+
197
+ console.log('[ResolvedDRX] Extracted intents from request:', {
198
+ request: request.substring(0, 50) + (request.length > 50 ? '...' : ''),
199
+ intent,
200
+ });
201
+
202
+ return generateResolvedDRX({
203
+ adjustments,
204
+ intent,
205
+ nodeLabel,
206
+ userPreferences,
207
+ });
208
+ }
209
+
210
+ /**
211
+ * Generate multi-node DRX with tool resolution
212
+ * Each node can have its own adjustments and intent
213
+ *
214
+ * @param {Object} options
215
+ * @param {Array} options.nodes - Array of { adjustments, intent, label }
216
+ * @param {Object} options.userPreferences - Optional user preferences
217
+ * @returns {Promise<Object>} { buffer, resolved }
218
+ */
219
+ async function generateMultiNodeResolvedDRX(options) {
220
+ const {
221
+ nodes = [],
222
+ userPreferences = null,
223
+ } = options;
224
+
225
+ if (userPreferences) {
226
+ toolResolver.setUserPreferences(userPreferences);
227
+ }
228
+
229
+ // Resolve each node
230
+ const resolvedNodes = nodes.map((node, idx) => {
231
+ const resolved = toolResolver.resolve({
232
+ adjustments: node.adjustments || {},
233
+ intent: node.intent || {},
234
+ });
235
+
236
+ const flatParams = convertResolvedToFlat(resolved);
237
+
238
+ return {
239
+ label: node.label || `Node ${idx + 1}`,
240
+ flatParams,
241
+ // Convert flat params to structured format for DRX generator
242
+ params: drxGenerator.parseAdjustments(flatParams),
243
+ tools: resolved.tools,
244
+ intent: node.intent || {},
245
+ };
246
+ });
247
+
248
+ // Convert to format expected by generateMultiNodeDRX
249
+ const nodeConfigs = resolvedNodes.map(node => ({
250
+ label: node.label,
251
+ params: node.params,
252
+ }));
253
+
254
+ // Build default serial connections (node 1 → 2 → 3 → ...)
255
+ const connections = [];
256
+ for (let i = 0; i < nodeConfigs.length - 1; i++) {
257
+ connections.push({ from: i + 1, to: i + 2 });
258
+ }
259
+
260
+ // Generate using existing multi-node generator
261
+ const drxContent = await drxGenerator.generateMultiNodeDRX(nodeConfigs, connections, {
262
+ label: 'Multi-Node Grade',
263
+ });
264
+
265
+ // Convert to buffer
266
+ const drxBuffer = Buffer.from(drxContent, 'utf8');
267
+
268
+ return {
269
+ buffer: drxBuffer,
270
+ resolved: resolvedNodes,
271
+ };
272
+ }
273
+
274
+ // ═══════════════════════════════════════════════════════════════════════════════
275
+ // UTILITY FUNCTIONS
276
+ // ═══════════════════════════════════════════════════════════════════════════════
277
+
278
+ /**
279
+ * Preview tool resolution without generating DRX
280
+ * Useful for debugging or showing users what tools will be used
281
+ *
282
+ * @param {Object} options
283
+ * @param {Object} options.adjustments - Raw adjustments
284
+ * @param {Object} options.intent - Intent signals
285
+ * @returns {Object} Resolution preview
286
+ */
287
+ function previewResolution(options) {
288
+ const { adjustments = {}, intent = {} } = options;
289
+
290
+ const resolved = toolResolver.resolve({ adjustments, intent });
291
+
292
+ // Build human-readable summary
293
+ const summary = [];
294
+
295
+ if (resolved.tools.contrast) {
296
+ const tool = toolResolver.getCurrentTool('contrast') || {};
297
+ summary.push({
298
+ adjustment: 'Contrast',
299
+ tool: resolved.tools.contrast,
300
+ toolName: tool.name || resolved.tools.contrast,
301
+ reason: intent.contrast ? `Intent: ${intent.contrast}` : 'Default preference',
302
+ });
303
+ }
304
+
305
+ if (resolved.tools.exposure) {
306
+ const tool = toolResolver.getCurrentTool('exposure') || {};
307
+ summary.push({
308
+ adjustment: 'Exposure',
309
+ tool: resolved.tools.exposure,
310
+ toolName: tool.name || resolved.tools.exposure,
311
+ reason: intent.exposure ? `Intent: ${intent.exposure}` : 'Default preference',
312
+ });
313
+ }
314
+
315
+ if (resolved.tools.temperature) {
316
+ const tool = toolResolver.getCurrentTool('temperature') || {};
317
+ summary.push({
318
+ adjustment: 'Temperature',
319
+ tool: resolved.tools.temperature,
320
+ toolName: tool.name || resolved.tools.temperature,
321
+ reason: intent.temperature ? `Intent: ${intent.temperature}` : 'Default preference',
322
+ });
323
+ }
324
+
325
+ if (resolved.tools.saturation) {
326
+ const tool = toolResolver.getCurrentTool('saturation') || {};
327
+ summary.push({
328
+ adjustment: 'Saturation',
329
+ tool: resolved.tools.saturation,
330
+ toolName: tool.name || resolved.tools.saturation,
331
+ reason: intent.saturation ? `Intent: ${intent.saturation}` : 'Default preference',
332
+ });
333
+ }
334
+
335
+ return {
336
+ summary,
337
+ tools: resolved.tools,
338
+ params: resolved.params,
339
+ metadata: resolved.metadata,
340
+ };
341
+ }
342
+
343
+ /**
344
+ * Get available tools for an adjustment type
345
+ * @param {string} adjustmentType
346
+ * @returns {Object[]} Array of tool descriptions
347
+ */
348
+ function getAvailableTools(adjustmentType) {
349
+ return toolResolver.getAvailableTools(adjustmentType);
350
+ }
351
+
352
+ /**
353
+ * Set user preferences for the resolver
354
+ * @param {Object} prefs
355
+ */
356
+ function setUserPreferences(prefs) {
357
+ toolResolver.setUserPreferences(prefs);
358
+ }
359
+
360
+ /**
361
+ * Get current user preferences
362
+ * @returns {Object}
363
+ */
364
+ function getUserPreferences() {
365
+ return toolResolver.defaultResolver.preferences;
366
+ }
367
+
368
+ // ═══════════════════════════════════════════════════════════════════════════════
369
+ // EXPORTS
370
+ // ═══════════════════════════════════════════════════════════════════════════════
371
+
372
+ module.exports = {
373
+ // Main generation functions
374
+ generateResolvedDRX,
375
+ generateFromRequest,
376
+ generateMultiNodeResolvedDRX,
377
+
378
+ // Utilities
379
+ previewResolution,
380
+ getAvailableTools,
381
+ setUserPreferences,
382
+ getUserPreferences,
383
+ convertResolvedToFlat,
384
+
385
+ // Re-export tool resolver for direct access
386
+ toolResolver,
387
+
388
+ // Re-export vocabulary intents for direct access
389
+ vocabularyIntents,
390
+
391
+ // Re-export original generator for bypass cases
392
+ drxGenerator,
393
+ };