@nodetool-ai/agents 0.8.1 → 0.8.3

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 (477) hide show
  1. package/dist/.nodetool-build-stamp +1 -1
  2. package/dist/analysis/audio-dsp.d.ts +3 -2
  3. package/dist/analysis/audio-dsp.d.ts.map +1 -1
  4. package/dist/analysis/audio-dsp.js +11 -8
  5. package/dist/analysis/audio-dsp.js.map +1 -1
  6. package/dist/analysis/media-decode.d.ts +13 -0
  7. package/dist/analysis/media-decode.d.ts.map +1 -1
  8. package/dist/analysis/media-decode.js +33 -6
  9. package/dist/analysis/media-decode.js.map +1 -1
  10. package/dist/apify/assets.d.ts.map +1 -1
  11. package/dist/apify/assets.js +4 -0
  12. package/dist/apify/assets.js.map +1 -1
  13. package/dist/author-graph.d.ts +2 -3
  14. package/dist/author-graph.d.ts.map +1 -1
  15. package/dist/author-graph.js +3 -5
  16. package/dist/author-graph.js.map +1 -1
  17. package/dist/browser-gate.d.ts +2 -2
  18. package/dist/browser-gate.js +2 -2
  19. package/dist/capabilities/GamePublishRequest.d.ts +14 -0
  20. package/dist/capabilities/GamePublishRequest.d.ts.map +1 -0
  21. package/dist/capabilities/GamePublishRequest.js +2 -0
  22. package/dist/capabilities/GamePublishRequest.js.map +1 -0
  23. package/dist/capabilities/adapters.d.ts +4 -13
  24. package/dist/capabilities/adapters.d.ts.map +1 -1
  25. package/dist/capabilities/adapters.js +9 -14
  26. package/dist/capabilities/adapters.js.map +1 -1
  27. package/dist/capabilities/agent-activity.d.ts +27 -0
  28. package/dist/capabilities/agent-activity.d.ts.map +1 -0
  29. package/dist/capabilities/agent-activity.js +103 -0
  30. package/dist/capabilities/agent-activity.js.map +1 -0
  31. package/dist/capabilities/agentic-storyboard-finish.d.ts +67 -0
  32. package/dist/capabilities/agentic-storyboard-finish.d.ts.map +1 -0
  33. package/dist/capabilities/agentic-storyboard-finish.js +1321 -0
  34. package/dist/capabilities/agentic-storyboard-finish.js.map +1 -0
  35. package/dist/capabilities/agents.d.ts +5 -2
  36. package/dist/capabilities/agents.d.ts.map +1 -1
  37. package/dist/capabilities/agents.js +14 -4
  38. package/dist/capabilities/agents.js.map +1 -1
  39. package/dist/capabilities/agents.specs.d.ts +3 -0
  40. package/dist/capabilities/agents.specs.d.ts.map +1 -1
  41. package/dist/capabilities/agents.specs.js +71 -1
  42. package/dist/capabilities/agents.specs.js.map +1 -1
  43. package/dist/capabilities/analysis.d.ts.map +1 -1
  44. package/dist/capabilities/analysis.js +33 -22
  45. package/dist/capabilities/analysis.js.map +1 -1
  46. package/dist/capabilities/analysis.specs.js +2 -2
  47. package/dist/capabilities/analysis.specs.js.map +1 -1
  48. package/dist/capabilities/apps.d.ts.map +1 -1
  49. package/dist/capabilities/apps.js +5 -3
  50. package/dist/capabilities/apps.js.map +1 -1
  51. package/dist/capabilities/args.d.ts +2 -5
  52. package/dist/capabilities/args.d.ts.map +1 -1
  53. package/dist/capabilities/args.js +2 -5
  54. package/dist/capabilities/args.js.map +1 -1
  55. package/dist/capabilities/assets.d.ts.map +1 -1
  56. package/dist/capabilities/assets.js +40 -10
  57. package/dist/capabilities/assets.js.map +1 -1
  58. package/dist/capabilities/browser.d.ts +1 -1
  59. package/dist/capabilities/browser.js +1 -1
  60. package/dist/capabilities/browser.specs.d.ts +1 -1
  61. package/dist/capabilities/browser.specs.js +1 -1
  62. package/dist/capabilities/code.d.ts +5 -0
  63. package/dist/capabilities/code.d.ts.map +1 -1
  64. package/dist/capabilities/code.js +128 -89
  65. package/dist/capabilities/code.js.map +1 -1
  66. package/dist/capabilities/collections.d.ts +4 -6
  67. package/dist/capabilities/collections.d.ts.map +1 -1
  68. package/dist/capabilities/collections.js +16 -11
  69. package/dist/capabilities/collections.js.map +1 -1
  70. package/dist/capabilities/derive-shot.d.ts +45 -0
  71. package/dist/capabilities/derive-shot.d.ts.map +1 -0
  72. package/dist/capabilities/derive-shot.js +82 -0
  73. package/dist/capabilities/derive-shot.js.map +1 -0
  74. package/dist/capabilities/documents.d.ts +2 -1
  75. package/dist/capabilities/documents.d.ts.map +1 -1
  76. package/dist/capabilities/documents.js +12 -6
  77. package/dist/capabilities/documents.js.map +1 -1
  78. package/dist/capabilities/email.d.ts +2 -1
  79. package/dist/capabilities/email.d.ts.map +1 -1
  80. package/dist/capabilities/email.js +5 -3
  81. package/dist/capabilities/email.js.map +1 -1
  82. package/dist/capabilities/errors.d.ts +19 -0
  83. package/dist/capabilities/errors.d.ts.map +1 -0
  84. package/dist/capabilities/errors.js +109 -0
  85. package/dist/capabilities/errors.js.map +1 -0
  86. package/dist/capabilities/errors.specs.d.ts +11 -0
  87. package/dist/capabilities/errors.specs.d.ts.map +1 -0
  88. package/dist/capabilities/errors.specs.js +100 -0
  89. package/dist/capabilities/errors.specs.js.map +1 -0
  90. package/dist/capabilities/example-timelines.d.ts.map +1 -1
  91. package/dist/capabilities/example-timelines.js +52 -10
  92. package/dist/capabilities/example-timelines.js.map +1 -1
  93. package/dist/capabilities/example-timelines.specs.d.ts +1 -0
  94. package/dist/capabilities/example-timelines.specs.d.ts.map +1 -1
  95. package/dist/capabilities/example-timelines.specs.js +21 -3
  96. package/dist/capabilities/example-timelines.specs.js.map +1 -1
  97. package/dist/capabilities/finish-storyboard.d.ts +5 -0
  98. package/dist/capabilities/finish-storyboard.d.ts.map +1 -0
  99. package/dist/capabilities/finish-storyboard.js +278 -0
  100. package/dist/capabilities/finish-storyboard.js.map +1 -0
  101. package/dist/capabilities/game-asset-browser.d.ts +11 -0
  102. package/dist/capabilities/game-asset-browser.d.ts.map +1 -0
  103. package/dist/capabilities/game-asset-browser.js +152 -0
  104. package/dist/capabilities/game-asset-browser.js.map +1 -0
  105. package/dist/capabilities/game-asset-source.js +1 -1
  106. package/dist/capabilities/game-asset-source.js.map +1 -1
  107. package/dist/capabilities/game.d.ts +44 -2
  108. package/dist/capabilities/game.d.ts.map +1 -1
  109. package/dist/capabilities/game.js +408 -160
  110. package/dist/capabilities/game.js.map +1 -1
  111. package/dist/capabilities/game.specs.d.ts +4 -0
  112. package/dist/capabilities/game.specs.d.ts.map +1 -1
  113. package/dist/capabilities/game.specs.js +42 -13
  114. package/dist/capabilities/game.specs.js.map +1 -1
  115. package/dist/capabilities/game3d.d.ts +17 -0
  116. package/dist/capabilities/game3d.d.ts.map +1 -0
  117. package/dist/capabilities/game3d.js +434 -0
  118. package/dist/capabilities/game3d.js.map +1 -0
  119. package/dist/capabilities/gate-from-context.d.ts +1 -1
  120. package/dist/capabilities/gate-from-context.js +1 -1
  121. package/dist/capabilities/generations.d.ts +2 -0
  122. package/dist/capabilities/generations.d.ts.map +1 -1
  123. package/dist/capabilities/generations.js +14 -23
  124. package/dist/capabilities/generations.js.map +1 -1
  125. package/dist/capabilities/index.d.ts +2 -2
  126. package/dist/capabilities/index.d.ts.map +1 -1
  127. package/dist/capabilities/index.js +2 -2
  128. package/dist/capabilities/index.js.map +1 -1
  129. package/dist/capabilities/invoke.d.ts +14 -25
  130. package/dist/capabilities/invoke.d.ts.map +1 -1
  131. package/dist/capabilities/invoke.js +72 -35
  132. package/dist/capabilities/invoke.js.map +1 -1
  133. package/dist/capabilities/jobs.d.ts.map +1 -1
  134. package/dist/capabilities/jobs.js +47 -3
  135. package/dist/capabilities/jobs.js.map +1 -1
  136. package/dist/capabilities/jobs.specs.d.ts.map +1 -1
  137. package/dist/capabilities/jobs.specs.js +3 -1
  138. package/dist/capabilities/jobs.specs.js.map +1 -1
  139. package/dist/capabilities/js-scripts.d.ts +19 -1
  140. package/dist/capabilities/js-scripts.d.ts.map +1 -1
  141. package/dist/capabilities/js-scripts.js +109 -2
  142. package/dist/capabilities/js-scripts.js.map +1 -1
  143. package/dist/capabilities/js-scripts.specs.d.ts +2 -0
  144. package/dist/capabilities/js-scripts.specs.d.ts.map +1 -1
  145. package/dist/capabilities/js-scripts.specs.js +50 -0
  146. package/dist/capabilities/js-scripts.specs.js.map +1 -1
  147. package/dist/capabilities/lazy-tool-core.d.ts +23 -0
  148. package/dist/capabilities/lazy-tool-core.d.ts.map +1 -0
  149. package/dist/capabilities/lazy-tool-core.js +56 -0
  150. package/dist/capabilities/lazy-tool-core.js.map +1 -0
  151. package/dist/capabilities/lazy-tool.d.ts +3 -23
  152. package/dist/capabilities/lazy-tool.d.ts.map +1 -1
  153. package/dist/capabilities/lazy-tool.js +6 -64
  154. package/dist/capabilities/lazy-tool.js.map +1 -1
  155. package/dist/capabilities/legacy-tools.d.ts +15 -0
  156. package/dist/capabilities/legacy-tools.d.ts.map +1 -0
  157. package/dist/capabilities/legacy-tools.js +98 -0
  158. package/dist/capabilities/legacy-tools.js.map +1 -0
  159. package/dist/capabilities/media.d.ts +0 -9
  160. package/dist/capabilities/media.d.ts.map +1 -1
  161. package/dist/capabilities/media.js +314 -261
  162. package/dist/capabilities/media.js.map +1 -1
  163. package/dist/capabilities/media.specs.d.ts.map +1 -1
  164. package/dist/capabilities/media.specs.js +17 -0
  165. package/dist/capabilities/media.specs.js.map +1 -1
  166. package/dist/capabilities/metadata.d.ts +62 -0
  167. package/dist/capabilities/metadata.d.ts.map +1 -0
  168. package/dist/capabilities/metadata.js +114 -0
  169. package/dist/capabilities/metadata.js.map +1 -0
  170. package/dist/capabilities/model3d.d.ts.map +1 -1
  171. package/dist/capabilities/model3d.js +4 -0
  172. package/dist/capabilities/model3d.js.map +1 -1
  173. package/dist/capabilities/models.d.ts +2 -2
  174. package/dist/capabilities/models.d.ts.map +1 -1
  175. package/dist/capabilities/models.js +5 -3
  176. package/dist/capabilities/models.js.map +1 -1
  177. package/dist/capabilities/registry.d.ts +6 -19
  178. package/dist/capabilities/registry.d.ts.map +1 -1
  179. package/dist/capabilities/registry.js +72 -113
  180. package/dist/capabilities/registry.js.map +1 -1
  181. package/dist/capabilities/run-agent.d.ts +19 -0
  182. package/dist/capabilities/run-agent.d.ts.map +1 -0
  183. package/dist/capabilities/run-agent.js +183 -0
  184. package/dist/capabilities/run-agent.js.map +1 -0
  185. package/dist/capabilities/runs.d.ts +9 -0
  186. package/dist/capabilities/runs.d.ts.map +1 -0
  187. package/dist/capabilities/runs.js +46 -0
  188. package/dist/capabilities/runs.js.map +1 -0
  189. package/dist/capabilities/runs.specs.d.ts +39 -0
  190. package/dist/capabilities/runs.specs.d.ts.map +1 -0
  191. package/dist/capabilities/runs.specs.js +52 -0
  192. package/dist/capabilities/runs.specs.js.map +1 -0
  193. package/dist/capabilities/scripts.d.ts.map +1 -1
  194. package/dist/capabilities/scripts.js +11 -5
  195. package/dist/capabilities/scripts.js.map +1 -1
  196. package/dist/capabilities/settings.d.ts.map +1 -1
  197. package/dist/capabilities/settings.js +4 -2
  198. package/dist/capabilities/settings.js.map +1 -1
  199. package/dist/capabilities/sketches.d.ts.map +1 -1
  200. package/dist/capabilities/sketches.js +4 -2
  201. package/dist/capabilities/sketches.js.map +1 -1
  202. package/dist/capabilities/skills.d.ts.map +1 -1
  203. package/dist/capabilities/skills.js +22 -2
  204. package/dist/capabilities/skills.js.map +1 -1
  205. package/dist/capabilities/storyboard-layout-check.d.ts +33 -0
  206. package/dist/capabilities/storyboard-layout-check.d.ts.map +1 -0
  207. package/dist/capabilities/storyboard-layout-check.js +229 -0
  208. package/dist/capabilities/storyboard-layout-check.js.map +1 -0
  209. package/dist/capabilities/storyboard-measured-sources.d.ts +10 -0
  210. package/dist/capabilities/storyboard-measured-sources.d.ts.map +1 -0
  211. package/dist/capabilities/storyboard-measured-sources.js +67 -0
  212. package/dist/capabilities/storyboard-measured-sources.js.map +1 -0
  213. package/dist/capabilities/storyboard-review-times.d.ts +4 -0
  214. package/dist/capabilities/storyboard-review-times.d.ts.map +1 -0
  215. package/dist/capabilities/storyboard-review-times.js +39 -0
  216. package/dist/capabilities/storyboard-review-times.js.map +1 -0
  217. package/dist/capabilities/storyboards.d.ts +12 -18
  218. package/dist/capabilities/storyboards.d.ts.map +1 -1
  219. package/dist/capabilities/storyboards.js +779 -96
  220. package/dist/capabilities/storyboards.js.map +1 -1
  221. package/dist/capabilities/storyboards.specs.d.ts +9 -0
  222. package/dist/capabilities/storyboards.specs.d.ts.map +1 -1
  223. package/dist/capabilities/storyboards.specs.js +173 -5
  224. package/dist/capabilities/storyboards.specs.js.map +1 -1
  225. package/dist/capabilities/threads.js +1 -1
  226. package/dist/capabilities/threads.js.map +1 -1
  227. package/dist/capabilities/timeline-bridge.d.ts +368 -0
  228. package/dist/capabilities/timeline-bridge.d.ts.map +1 -0
  229. package/dist/capabilities/timeline-bridge.js +1008 -0
  230. package/dist/capabilities/timeline-bridge.js.map +1 -0
  231. package/dist/capabilities/timeline-clip-frames.d.ts +17 -0
  232. package/dist/capabilities/timeline-clip-frames.d.ts.map +1 -0
  233. package/dist/capabilities/timeline-clip-frames.js +84 -0
  234. package/dist/capabilities/timeline-clip-frames.js.map +1 -0
  235. package/dist/capabilities/timeline-media-edit.d.ts +8 -0
  236. package/dist/capabilities/timeline-media-edit.d.ts.map +1 -0
  237. package/dist/capabilities/timeline-media-edit.js +94 -0
  238. package/dist/capabilities/timeline-media-edit.js.map +1 -0
  239. package/dist/capabilities/timeline-native-media.d.ts.map +1 -1
  240. package/dist/capabilities/timeline-native-media.js +40 -0
  241. package/dist/capabilities/timeline-native-media.js.map +1 -1
  242. package/dist/capabilities/timeline-operations.d.ts +52 -0
  243. package/dist/capabilities/timeline-operations.d.ts.map +1 -0
  244. package/dist/capabilities/timeline-operations.js +413 -0
  245. package/dist/capabilities/timeline-operations.js.map +1 -0
  246. package/dist/capabilities/timelines.d.ts +28 -3
  247. package/dist/capabilities/timelines.d.ts.map +1 -1
  248. package/dist/capabilities/timelines.js +410 -294
  249. package/dist/capabilities/timelines.js.map +1 -1
  250. package/dist/capabilities/timelines.specs.d.ts +8 -0
  251. package/dist/capabilities/timelines.specs.d.ts.map +1 -1
  252. package/dist/capabilities/timelines.specs.js +178 -9
  253. package/dist/capabilities/timelines.specs.js.map +1 -1
  254. package/dist/capabilities/types.d.ts +3 -1
  255. package/dist/capabilities/types.d.ts.map +1 -1
  256. package/dist/capabilities/types.js.map +1 -1
  257. package/dist/capabilities/ui.d.ts.map +1 -1
  258. package/dist/capabilities/ui.js +24 -2
  259. package/dist/capabilities/ui.js.map +1 -1
  260. package/dist/capabilities/web.d.ts.map +1 -1
  261. package/dist/capabilities/web.js +4 -0
  262. package/dist/capabilities/web.js.map +1 -1
  263. package/dist/capabilities/workflows.d.ts +3 -1
  264. package/dist/capabilities/workflows.d.ts.map +1 -1
  265. package/dist/capabilities/workflows.js +244 -39
  266. package/dist/capabilities/workflows.js.map +1 -1
  267. package/dist/capabilities/workflows.specs.d.ts +2 -0
  268. package/dist/capabilities/workflows.specs.d.ts.map +1 -1
  269. package/dist/capabilities/workflows.specs.js +72 -2
  270. package/dist/capabilities/workflows.specs.js.map +1 -1
  271. package/dist/codeact/action-diagnostics.d.ts.map +1 -1
  272. package/dist/codeact/action-diagnostics.js +51 -1
  273. package/dist/codeact/action-diagnostics.js.map +1 -1
  274. package/dist/codeact/codeact-executor.d.ts.map +1 -1
  275. package/dist/codeact/codeact-executor.js +16 -8
  276. package/dist/codeact/codeact-executor.js.map +1 -1
  277. package/dist/codeact/compact-ids.d.ts.map +1 -1
  278. package/dist/codeact/compact-ids.js +5 -1
  279. package/dist/codeact/compact-ids.js.map +1 -1
  280. package/dist/codeact/graph-model.d.ts +1 -1
  281. package/dist/codeact/graph-model.d.ts.map +1 -1
  282. package/dist/codeact/graph-model.js +2 -3
  283. package/dist/codeact/graph-model.js.map +1 -1
  284. package/dist/codeact/nodetool-api.d.ts +1 -1
  285. package/dist/codeact/nodetool-api.d.ts.map +1 -1
  286. package/dist/codeact/nodetool-api.js +202 -284
  287. package/dist/codeact/nodetool-api.js.map +1 -1
  288. package/dist/codeact/sandbox-packages.d.ts +0 -7
  289. package/dist/codeact/sandbox-packages.d.ts.map +1 -1
  290. package/dist/codeact/sandbox-packages.js +1 -10
  291. package/dist/codeact/sandbox-packages.js.map +1 -1
  292. package/dist/codeact/tool-api.d.ts +6 -3
  293. package/dist/codeact/tool-api.d.ts.map +1 -1
  294. package/dist/codeact/tool-api.js +22 -15
  295. package/dist/codeact/tool-api.js.map +1 -1
  296. package/dist/evals/codeact-api-cases.d.ts.map +1 -1
  297. package/dist/evals/codeact-api-cases.js +2 -0
  298. package/dist/evals/codeact-api-cases.js.map +1 -1
  299. package/dist/evals/codeact-api-runs.d.ts +3 -0
  300. package/dist/evals/codeact-api-runs.d.ts.map +1 -0
  301. package/dist/evals/codeact-api-runs.js +33 -0
  302. package/dist/evals/codeact-api-runs.js.map +1 -0
  303. package/dist/evals/surfaces/game.d.ts +8 -2
  304. package/dist/evals/surfaces/game.d.ts.map +1 -1
  305. package/dist/evals/surfaces/game.js +460 -2
  306. package/dist/evals/surfaces/game.js.map +1 -1
  307. package/dist/evals/surfaces/sketch.d.ts +2 -0
  308. package/dist/evals/surfaces/sketch.d.ts.map +1 -1
  309. package/dist/evals/surfaces/sketch.js +11 -3
  310. package/dist/evals/surfaces/sketch.js.map +1 -1
  311. package/dist/evals/surfaces/timeline.d.ts +4 -357
  312. package/dist/evals/surfaces/timeline.d.ts.map +1 -1
  313. package/dist/evals/surfaces/timeline.js +9 -2621
  314. package/dist/evals/surfaces/timeline.js.map +1 -1
  315. package/dist/evals/tool-loop-bridge.d.ts +4 -0
  316. package/dist/evals/tool-loop-bridge.d.ts.map +1 -1
  317. package/dist/evals/tool-loop-bridge.js.map +1 -1
  318. package/dist/evals/tool-loop-eval.d.ts +2 -0
  319. package/dist/evals/tool-loop-eval.d.ts.map +1 -1
  320. package/dist/evals/tool-loop-eval.js +6 -1
  321. package/dist/evals/tool-loop-eval.js.map +1 -1
  322. package/dist/evals/tool-loop-permission.d.ts +1 -15
  323. package/dist/evals/tool-loop-permission.d.ts.map +1 -1
  324. package/dist/evals/tool-loop-permission.js +23 -41
  325. package/dist/evals/tool-loop-permission.js.map +1 -1
  326. package/dist/game-authoring.d.ts +9573 -0
  327. package/dist/game-authoring.d.ts.map +1 -0
  328. package/dist/game-authoring.js +146 -0
  329. package/dist/game-authoring.js.map +1 -0
  330. package/dist/game-build.d.ts +3 -0
  331. package/dist/game-build.d.ts.map +1 -0
  332. package/dist/game-build.js +3 -0
  333. package/dist/game-build.js.map +1 -0
  334. package/dist/game-code-bake.d.ts +26 -0
  335. package/dist/game-code-bake.d.ts.map +1 -0
  336. package/dist/game-code-bake.js +98 -0
  337. package/dist/game-code-bake.js.map +1 -0
  338. package/dist/game-examples.d.ts +2227 -18
  339. package/dist/game-examples.d.ts.map +1 -1
  340. package/dist/game-examples.js +5 -4
  341. package/dist/game-examples.js.map +1 -1
  342. package/dist/generation-cancel.d.ts +31 -0
  343. package/dist/generation-cancel.d.ts.map +1 -0
  344. package/dist/generation-cancel.js +28 -0
  345. package/dist/generation-cancel.js.map +1 -0
  346. package/dist/host-access-gate.d.ts +29 -0
  347. package/dist/host-access-gate.d.ts.map +1 -0
  348. package/dist/host-access-gate.js +39 -0
  349. package/dist/host-access-gate.js.map +1 -0
  350. package/dist/host-modules/dispatcher.d.ts +7 -1
  351. package/dist/host-modules/dispatcher.d.ts.map +1 -1
  352. package/dist/host-modules/dispatcher.js +13 -2
  353. package/dist/host-modules/dispatcher.js.map +1 -1
  354. package/dist/host-modules/docx.d.ts.map +1 -1
  355. package/dist/host-modules/docx.js +2 -2
  356. package/dist/host-modules/docx.js.map +1 -1
  357. package/dist/host-modules/epub.d.ts.map +1 -1
  358. package/dist/host-modules/epub.js +2 -2
  359. package/dist/host-modules/epub.js.map +1 -1
  360. package/dist/host-modules/fabric.d.ts.map +1 -1
  361. package/dist/host-modules/fabric.js +1 -1
  362. package/dist/host-modules/fabric.js.map +1 -1
  363. package/dist/host-modules/limits.d.ts +10 -8
  364. package/dist/host-modules/limits.d.ts.map +1 -1
  365. package/dist/host-modules/limits.js +14 -9
  366. package/dist/host-modules/limits.js.map +1 -1
  367. package/dist/host-modules/mammoth.d.ts.map +1 -1
  368. package/dist/host-modules/mammoth.js +2 -2
  369. package/dist/host-modules/mammoth.js.map +1 -1
  370. package/dist/host-modules/ocr.d.ts.map +1 -1
  371. package/dist/host-modules/ocr.js +1 -1
  372. package/dist/host-modules/ocr.js.map +1 -1
  373. package/dist/host-modules/pdf.d.ts.map +1 -1
  374. package/dist/host-modules/pdf.js +2 -2
  375. package/dist/host-modules/pdf.js.map +1 -1
  376. package/dist/host-modules/pdflib.d.ts.map +1 -1
  377. package/dist/host-modules/pdflib.js +2 -2
  378. package/dist/host-modules/pdflib.js.map +1 -1
  379. package/dist/host-modules/pptx.d.ts.map +1 -1
  380. package/dist/host-modules/pptx.js +2 -2
  381. package/dist/host-modules/pptx.js.map +1 -1
  382. package/dist/host-modules/pptxgen.d.ts.map +1 -1
  383. package/dist/host-modules/pptxgen.js +2 -2
  384. package/dist/host-modules/pptxgen.js.map +1 -1
  385. package/dist/host-modules/tfjs.d.ts.map +1 -1
  386. package/dist/host-modules/tfjs.js +4 -4
  387. package/dist/host-modules/tfjs.js.map +1 -1
  388. package/dist/host-modules/xlsx.d.ts.map +1 -1
  389. package/dist/host-modules/xlsx.js +2 -2
  390. package/dist/host-modules/xlsx.js.map +1 -1
  391. package/dist/index.d.ts +18 -4
  392. package/dist/index.d.ts.map +1 -1
  393. package/dist/index.js +17 -3
  394. package/dist/index.js.map +1 -1
  395. package/dist/js-sandbox-worker/engine.d.ts +4 -0
  396. package/dist/js-sandbox-worker/engine.d.ts.map +1 -0
  397. package/dist/js-sandbox-worker/engine.js +45 -0
  398. package/dist/js-sandbox-worker/engine.js.map +1 -0
  399. package/dist/js-sandbox-worker/host.js +1 -1
  400. package/dist/js-sandbox-worker/host.js.map +1 -1
  401. package/dist/js-sandbox-worker/interpreter.d.ts +1 -1
  402. package/dist/js-sandbox-worker/interpreter.d.ts.map +1 -1
  403. package/dist/js-sandbox-worker/interpreter.js +94 -2
  404. package/dist/js-sandbox-worker/interpreter.js.map +1 -1
  405. package/dist/js-sandbox-worker/worker-entry.d.ts.map +1 -1
  406. package/dist/js-sandbox-worker/worker-entry.js +3 -2
  407. package/dist/js-sandbox-worker/worker-entry.js.map +1 -1
  408. package/dist/js-sandbox.d.ts +9 -1
  409. package/dist/js-sandbox.d.ts.map +1 -1
  410. package/dist/js-sandbox.js +76 -15
  411. package/dist/js-sandbox.js.map +1 -1
  412. package/dist/js-script-app-runner.d.ts +2 -0
  413. package/dist/js-script-app-runner.d.ts.map +1 -1
  414. package/dist/js-script-app-runner.js +8 -3
  415. package/dist/js-script-app-runner.js.map +1 -1
  416. package/dist/js-script-sandbox.d.ts +12 -18
  417. package/dist/js-script-sandbox.d.ts.map +1 -1
  418. package/dist/js-script-sandbox.js +3 -49
  419. package/dist/js-script-sandbox.js.map +1 -1
  420. package/dist/prompts/product-knowledge.d.ts +1 -1
  421. package/dist/prompts/product-knowledge.d.ts.map +1 -1
  422. package/dist/prompts/product-knowledge.js +82 -41
  423. package/dist/prompts/product-knowledge.js.map +1 -1
  424. package/dist/sandbox-pack-resolution.d.ts +21 -0
  425. package/dist/sandbox-pack-resolution.d.ts.map +1 -0
  426. package/dist/sandbox-pack-resolution.js +42 -0
  427. package/dist/sandbox-pack-resolution.js.map +1 -0
  428. package/dist/sandbox-toolbelt.d.ts +3 -1
  429. package/dist/sandbox-toolbelt.d.ts.map +1 -1
  430. package/dist/sandbox-toolbelt.js +8 -2
  431. package/dist/sandbox-toolbelt.js.map +1 -1
  432. package/dist/skill-prompt.d.ts +11 -1
  433. package/dist/skill-prompt.d.ts.map +1 -1
  434. package/dist/skill-prompt.js +17 -6
  435. package/dist/skill-prompt.js.map +1 -1
  436. package/dist/system-skills.d.ts +7 -1
  437. package/dist/system-skills.d.ts.map +1 -1
  438. package/dist/system-skills.js +2 -2
  439. package/dist/system-skills.js.map +1 -1
  440. package/dist/timeline-capture.d.ts +21 -0
  441. package/dist/timeline-capture.d.ts.map +1 -0
  442. package/dist/timeline-capture.js +564 -0
  443. package/dist/timeline-capture.js.map +1 -0
  444. package/dist/timeline-code-bake.d.ts +75 -0
  445. package/dist/timeline-code-bake.d.ts.map +1 -0
  446. package/dist/timeline-code-bake.js +327 -0
  447. package/dist/timeline-code-bake.js.map +1 -0
  448. package/dist/timeline-preview/frames.d.ts +26 -0
  449. package/dist/timeline-preview/frames.d.ts.map +1 -1
  450. package/dist/timeline-preview/frames.js +155 -70
  451. package/dist/timeline-preview/frames.js.map +1 -1
  452. package/dist/tools/base-tool.d.ts +1 -0
  453. package/dist/tools/base-tool.d.ts.map +1 -1
  454. package/dist/tools/base-tool.js +1 -1
  455. package/dist/tools/base-tool.js.map +1 -1
  456. package/dist/tools/builtin-tools.d.ts +4 -3
  457. package/dist/tools/builtin-tools.d.ts.map +1 -1
  458. package/dist/tools/builtin-tools.js +24 -3
  459. package/dist/tools/builtin-tools.js.map +1 -1
  460. package/dist/tools/external-capability-tools.d.ts +1 -1
  461. package/dist/tools/external-capability-tools.js +1 -1
  462. package/dist/tools/mcp-tool-support.d.ts +10 -9
  463. package/dist/tools/mcp-tool-support.d.ts.map +1 -1
  464. package/dist/tools/mcp-tool-support.js +14 -13
  465. package/dist/tools/mcp-tool-support.js.map +1 -1
  466. package/dist/tools/mcp-tools.d.ts +6 -4
  467. package/dist/tools/mcp-tools.d.ts.map +1 -1
  468. package/dist/tools/mcp-tools.js +65 -62
  469. package/dist/tools/mcp-tools.js.map +1 -1
  470. package/dist/tools/tool-permissions.d.ts +1 -1
  471. package/dist/tools/tool-permissions.js +1 -1
  472. package/package.json +124 -41
  473. package/dist/capabilities/gate-tools.d.ts +0 -18
  474. package/dist/capabilities/gate-tools.d.ts.map +0 -1
  475. package/dist/capabilities/gate-tools.js +0 -66
  476. package/dist/capabilities/gate-tools.js.map +0 -1
  477. package/dist/tsconfig.tests.tmp.tsbuildinfo +0 -1
@@ -1,3 +1,4 @@
1
+ import { finishStoryboard, layoutStoryboard, previewStoryboardDesign } from "./finish-storyboard.js";
1
2
  /**
2
3
  * The `storyboards` capability module.
3
4
  *
@@ -15,10 +16,15 @@
15
16
  *
16
17
  * Design: docs/tool-class-retirement-design.md § "Migration".
17
18
  */
18
- import { mp4DurationSeconds } from "@nodetool-ai/runtime";
19
+ import { z } from "zod";
20
+ import { SpanStatusCode } from "@opentelemetry/api";
21
+ import { mp4DurationSeconds, withSpan } from "@nodetool-ai/runtime";
22
+ import { storyboardMotionDesign, storyboardShotGraphics } from "@nodetool-ai/protocol/api-schemas/storyboards.js";
23
+ import { assertProductionGenerationAllowed, compileOneTake, isFullResourceId, isShortResourceId, productionRequirement } from "@nodetool-ai/protocol";
19
24
  import { stampScriptStoryboardId } from "./script-link.js";
20
- import { listStoryboardsSpec, createStoryboardSpec, getStoryboardSpec, renderStoryboardStillsSpec, renderStoryboardClipsSpec, reviseStoryboardClipSpec, assembleStoryboardTimelineSpec, editStoryboardSpec, directStoryboardSpec, extractScriptFromStoryboardSpec, deleteStoryboardSpec } from "./storyboards.specs.js";
21
- import { clampConcurrency, mapWithConcurrency } from "./concurrency.js";
25
+ import { listStoryboardsSpec, createStoryboardSpec, getStoryboardSpec, renderStoryboardStillsSpec, renderStoryboardClipsSpec, reviseStoryboardClipSpec, assembleStoryboardTimelineSpec, deriveShotFromClipSpec, editStoryboardSpec, directStoryboardSpec, extractScriptFromStoryboardSpec, deleteStoryboardSpec, getStoryboardOneTakeSpec, updateStoryboardOneTakeSpec } from "./storyboards.specs.js";
26
+ import { measureStoryboardSources } from "./storyboard-measured-sources.js";
27
+ import { clampConcurrency } from "./concurrency.js";
22
28
  import { isNonBlankString, isNumber, isRecord, isString } from "../utils/type-guards.js";
23
29
  import { resolveProjectId } from "./project-scope.js";
24
30
  /** Shots one call may render, so a stray `targets: "all"` cannot bankrupt a run. */
@@ -323,7 +329,8 @@ const listStoryboards = {
323
329
  with_keyframe: doc.shots.filter((s) => !!s.keyframe).length,
324
330
  with_clip: doc.shots.filter((s) => !!s.clip).length,
325
331
  timeline_id: row.timeline_id ?? undefined,
326
- updated_at: row.updated_at
332
+ updated_at: row.updated_at,
333
+ revision: row.revision
327
334
  };
328
335
  })
329
336
  };
@@ -342,7 +349,8 @@ function createdBoardSummary(row) {
342
349
  name: row.name,
343
350
  project_id: row.project_id,
344
351
  shots: doc.shots.length,
345
- updated_at: row.updated_at
352
+ updated_at: row.updated_at,
353
+ revision: row.revision
346
354
  };
347
355
  }
348
356
  const createStoryboard = {
@@ -408,6 +416,7 @@ const getStoryboard = {
408
416
  const drifted = new Set(link.drifted_shot_ids);
409
417
  return {
410
418
  id: row.id,
419
+ revision: row.revision,
411
420
  name: row.name,
412
421
  brief: doc.brief,
413
422
  style: doc.style,
@@ -418,6 +427,7 @@ const getStoryboard = {
418
427
  timeline_id: row.timeline_id ?? undefined,
419
428
  narration: doc.screenplay?.narration ?? undefined,
420
429
  music_prompt: doc.screenplay?.music_prompt ?? undefined,
430
+ motion_design: doc.screenplay?.motion_design ?? null,
421
431
  script_id: link.script_id,
422
432
  script_link: link,
423
433
  shots: [...doc.shots]
@@ -429,6 +439,10 @@ const getStoryboard = {
429
439
  action: shot.action,
430
440
  camera: shot.camera,
431
441
  motion: shot.motion,
442
+ end_state: shot.end_state,
443
+ sound: shot.sound,
444
+ graphics: shot.graphics,
445
+ production: shot.production,
432
446
  duration_seconds: shot.duration_seconds,
433
447
  status: shot.status,
434
448
  has_keyframe: !!shot.keyframe,
@@ -531,6 +545,71 @@ async function filterStale(selected, params, doc, entities, kind) {
531
545
  .map((shot) => shot.id)
532
546
  };
533
547
  }
548
+ function modelOverrides(params) {
549
+ const options = {};
550
+ if (isNonBlankString(params["provider"])) {
551
+ options.provider = params["provider"];
552
+ }
553
+ if (isNonBlankString(params["model"])) {
554
+ options.model = params["model"];
555
+ }
556
+ return options;
557
+ }
558
+ function missingPlanModel(plan) {
559
+ if (plan.model.provider && plan.model.model) {
560
+ return undefined;
561
+ }
562
+ return {
563
+ error: `No ${plan.kind === "keyframe" ? "still" : "clip"} model is set for shot ${plan.shotId}. Pass provider + model (use find_model), or set one on the shot or board.`
564
+ };
565
+ }
566
+ async function clipModelError(context, plans) {
567
+ const groups = new Map();
568
+ for (const plan of plans) {
569
+ const error = missingPlanModel(plan);
570
+ if (error) {
571
+ return error;
572
+ }
573
+ if (plan.preflightError) {
574
+ continue;
575
+ }
576
+ const key = JSON.stringify([plan.model.provider, plan.model.model]);
577
+ const group = groups.get(key) ?? [];
578
+ group.push(plan);
579
+ groups.set(key, group);
580
+ }
581
+ for (const group of groups.values()) {
582
+ const model = group[0].model;
583
+ let supportedTasks = model.supportedTasks;
584
+ try {
585
+ const provider = await context.getProvider(model.provider);
586
+ const models = await provider.getAvailableVideoModels();
587
+ supportedTasks =
588
+ models.find((entry) => entry.id === model.model)?.supportedTasks ??
589
+ supportedTasks;
590
+ }
591
+ catch {
592
+ // Legacy providers can lack discovery, so their persisted task declarations apply.
593
+ }
594
+ const unsupported = group.find((plan) => {
595
+ const task = plan.mode === "direct" ? "text_to_video" : plan.mode === "reference" ? "reference_to_video" : "image_to_video";
596
+ return supportedTasks?.length && !supportedTasks.includes(task);
597
+ });
598
+ if (unsupported) {
599
+ const task = unsupported.mode === "direct" ? "text_to_video" : unsupported.mode === "reference" ? "reference_to_video" : "image_to_video";
600
+ return {
601
+ error: `The selected clip model ${model.provider}/${model.model} does not support ${task}; choose a model that supports the selected shot mode.`
602
+ };
603
+ }
604
+ }
605
+ return undefined;
606
+ }
607
+ function uniformModel(plans) {
608
+ const model = plans[0]?.model;
609
+ return model && plans.every((plan) => plan.model.provider === model.provider && plan.model.model === model.model)
610
+ ? { provider: model.provider, model: model.model }
611
+ : {};
612
+ }
534
613
  const renderStoryboardStills = {
535
614
  spec: renderStoryboardStillsSpec,
536
615
  impl: async (run, params) => {
@@ -539,14 +618,11 @@ const renderStoryboardStills = {
539
618
  if (isError(board))
540
619
  return board;
541
620
  const { row, doc } = board;
542
- const model = resolveModel(params, doc.imageModel, "still", "text_to_image");
543
- if (isError(model))
544
- return model;
545
621
  const { shotRenderMode } = await import("@nodetool-ai/protocol");
546
622
  // A direct shot renders its clip from the prompt, so it needs no still.
547
623
  // Naming it in `targets` still renders one — a board frame to look at is
548
624
  // worth having even when the clip does not come from it.
549
- const selected = selectShots(doc.shots, params["targets"], (s) => !s.keyframe &&
625
+ const selected = selectShots(doc.shots, params["targets"], (s) => (params["stale_only"] === true ? !!s.keyframe : !s.keyframe) &&
550
626
  shotRenderMode(s) !== "direct" &&
551
627
  !shotHasPicture(s, doc.shots));
552
628
  if (isError(selected))
@@ -565,6 +641,10 @@ const renderStoryboardStills = {
565
641
  : "No shot needs a still: each already has one, or renders its clip directly."
566
642
  };
567
643
  }
644
+ const protectedStill = chosen.find((shot) => shot.production?.protected_inputs?.some((input) => input.asset_id));
645
+ if (protectedStill) {
646
+ return { error: `Shot ${protectedStill.id} protects source assets; the current still renderer cannot prove source fidelity. Use those assets directly in Timeline materialization or a policy-aware finishing path.` };
647
+ }
568
648
  if (chosen.length > MAX_SHOTS_PER_CALL) {
569
649
  return {
570
650
  error: `${chosen.length} shots selected, over the ${MAX_SHOTS_PER_CALL}-shot per-call limit. Pass targets in batches.`
@@ -575,22 +655,34 @@ const renderStoryboardStills = {
575
655
  // says: `style` and `model` can be overridden per call. Recording the
576
656
  // override is the point — a version rendered against something other than
577
657
  // the board's settings reads stale against the board, correctly.
578
- const planOptions = {
579
- provider: model.provider,
580
- model: model.model
581
- };
658
+ const planOptions = modelOverrides(params);
582
659
  if (isString(params["style"])) {
583
660
  planOptions.style = params["style"];
584
661
  }
585
662
  const plans = planShotRenders(doc, entities, "keyframe", chosen.map((shot) => shot.id), planOptions);
586
- const outcomes = await renderShots(renderHost(context), { id: row.id }, plans, {
587
- concurrency: clampConcurrency(params["concurrency"])
663
+ const { imageModelSupportsTask } = await import("@nodetool-ai/runtime");
664
+ for (const plan of plans) {
665
+ const modelError = missingPlanModel(plan);
666
+ if (modelError) {
667
+ return modelError;
668
+ }
669
+ plan.stillModelTakesImages = await imageModelSupportsTask(context, plan.model, "image_to_image", plan.model.supportedTasks);
670
+ }
671
+ const outcomes = await withSpan("render", {
672
+ "document.id": row.id,
673
+ "render.kind": "keyframe",
674
+ "render.shot_count": plans.length
675
+ }, async (span) => {
676
+ const rendered = await renderShots(renderHost(context), { id: row.id }, plans, { concurrency: clampConcurrency(params["concurrency"]) });
677
+ if (rendered.some((outcome) => !outcome.ok)) {
678
+ span?.setStatus({ code: SpanStatusCode.ERROR });
679
+ }
680
+ return rendered;
588
681
  });
589
682
  const results = outcomes.map((outcome) => outcomeRow(outcome, false));
590
683
  return {
591
684
  storyboard_id: row.id,
592
- provider: model.provider,
593
- model: model.model,
685
+ ...uniformModel(plans),
594
686
  rendered: results.filter((r) => r.ok).length,
595
687
  failed: results.filter((r) => !r.ok).length,
596
688
  skipped,
@@ -613,43 +705,23 @@ const renderStoryboardClips = {
613
705
  override !== "reference") {
614
706
  return { error: 'mode must be "keyframe", "direct", or "reference".' };
615
707
  }
616
- // The call's override wins over the shot's own setting, for this call only.
617
- const { shotRenderMode } = await import("@nodetool-ai/protocol");
618
- const modeOf = (shot) => override === "keyframe" ||
619
- override === "direct" ||
620
- override === "reference"
621
- ? override
622
- : shotRenderMode(shot);
623
- const selected = selectShots(doc.shots, params["targets"], (s) => !shotHasPicture(s, doc.shots) &&
624
- (modeOf(s) === "direct" || modeOf(s) === "reference" || !!s.keyframe));
625
- if (isError(selected))
626
- return selected;
627
- const requiredCapabilities = new Set(selected.map((shot) => modeOf(shot) === "direct"
628
- ? "text_to_video"
629
- : modeOf(shot) === "reference"
630
- ? "reference_to_video"
631
- : "image_to_video"));
632
- const capability = requiredCapabilities.has("reference_to_video")
633
- ? "reference_to_video"
634
- : requiredCapabilities.has("image_to_video")
635
- ? "image_to_video"
636
- : "text_to_video";
637
- const model = resolveModel(params, doc.videoModel, "clip", capability);
638
- if (isError(model))
639
- return model;
640
- const declaredTasks = doc.videoModel?.supported_tasks;
641
- if (Array.isArray(declaredTasks) &&
642
- declaredTasks.length > 0 &&
643
- model.model === doc.videoModel?.id &&
644
- model.provider === doc.videoModel?.provider) {
645
- const unsupported = [...requiredCapabilities].find((task) => !declaredTasks.includes(task));
646
- if (unsupported) {
647
- return {
648
- error: `The selected clip model does not support ${unsupported}; choose a model that supports every selected shot mode.`
649
- };
650
- }
708
+ const candidates = selectShots(doc.shots, params["targets"], (shot) => (params["stale_only"] === true ? !!shot.clip : !shotHasPicture(shot, doc.shots)) &&
709
+ !shot.covered_by?.shot_id);
710
+ if (isError(candidates)) {
711
+ return candidates;
651
712
  }
652
713
  const entities = await loadBoardEntities(context, doc);
714
+ const { planShotRenders, renderShots } = await import("@nodetool-ai/storyboard");
715
+ const readinessOptions = modelOverrides(params);
716
+ if (override !== undefined) {
717
+ readinessOptions.mode = override;
718
+ }
719
+ const ready = new Set(planShotRenders(doc, entities, "clip", candidates.map((shot) => shot.id), readinessOptions)
720
+ .filter((plan) => plan.mode !== "keyframe" || !!plan.sourceKeyframe)
721
+ .map((plan) => plan.shotId));
722
+ const selected = params["targets"] === undefined || params["targets"] === null
723
+ ? candidates.filter((shot) => ready.has(shot.id))
724
+ : candidates;
653
725
  const fresh = await filterStale(selected, params, doc, entities, "clip");
654
726
  const skipped = fresh.skipped;
655
727
  const chosen = fresh.shots;
@@ -663,13 +735,16 @@ const renderStoryboardClips = {
663
735
  : 'No shot is ready for a clip. A keyframe-mode shot needs a still first (render_storyboard_stills), or set its render_mode to "direct" — or pass mode: "direct" here — to render straight from the prompt. Name shots explicitly with `targets` to override the selection.'
664
736
  };
665
737
  }
738
+ const forbiddenClip = chosen.find((shot) => shot.production?.media_strategy === "still_motion_graphics");
739
+ if (forbiddenClip) {
740
+ return { error: `Shot ${forbiddenClip.id} is still_motion_graphics; video generation is forbidden. Materialize its still/assets as Timeline layers instead.` };
741
+ }
666
742
  if (chosen.length > MAX_SHOTS_PER_CALL) {
667
743
  return {
668
744
  error: `${chosen.length} shots selected, over the ${MAX_SHOTS_PER_CALL}-shot per-call limit. Pass targets in batches.`
669
745
  };
670
746
  }
671
747
  const { scriptLinesById } = await import("@nodetool-ai/timeline");
672
- const { planShotRenders, renderShots } = await import("@nodetool-ai/storyboard");
673
748
  // A linked board times its shots from the words they cover, so a clip is
674
749
  // rendered long enough to hold its voiceover (design §2.3). A shot pinned
675
750
  // to `manual`, an unvoiced line, or an unlinked board keeps
@@ -678,8 +753,7 @@ const renderStoryboardClips = {
678
753
  // As in the stills path: the record says what this call rendered with, so
679
754
  // a per-call model or style override reads stale against the board.
680
755
  const planOptions = {
681
- provider: model.provider,
682
- model: model.model,
756
+ ...modelOverrides(params),
683
757
  style: isString(params["style"]) ? params["style"] : doc.style || "",
684
758
  scriptLines: scriptLinesById(scriptDoc?.sections ?? [])
685
759
  };
@@ -687,18 +761,31 @@ const renderStoryboardClips = {
687
761
  planOptions.mode = override;
688
762
  }
689
763
  const plans = planShotRenders(doc, entities, "clip", chosen.map((shot) => shot.id), planOptions);
764
+ const modelError = await clipModelError(context, plans);
765
+ if (modelError) {
766
+ return modelError;
767
+ }
690
768
  const renderOptions = {
691
769
  concurrency: clampConcurrency(params["concurrency"])
692
770
  };
693
771
  if (isString(params["resolution"])) {
694
772
  renderOptions.resolution = params["resolution"];
695
773
  }
696
- const outcomes = await renderShots(renderHost(context), { id: row.id }, plans, renderOptions);
774
+ const outcomes = await withSpan("render", {
775
+ "document.id": row.id,
776
+ "render.kind": "clip",
777
+ "render.shot_count": plans.length
778
+ }, async (span) => {
779
+ const rendered = await renderShots(renderHost(context), { id: row.id }, plans, renderOptions);
780
+ if (rendered.some((outcome) => !outcome.ok)) {
781
+ span?.setStatus({ code: SpanStatusCode.ERROR });
782
+ }
783
+ return rendered;
784
+ });
697
785
  const results = outcomes.map((outcome) => outcomeRow(outcome, true));
698
786
  return {
699
787
  storyboard_id: row.id,
700
- provider: model.provider,
701
- model: model.model,
788
+ ...uniformModel(plans),
702
789
  rendered: results.filter((r) => r.ok).length,
703
790
  failed: results.filter((r) => !r.ok).length,
704
791
  skipped,
@@ -723,6 +810,15 @@ const reviseStoryboardClip = {
723
810
  error: `No shot matches "${String(params["target"])}". Call get_storyboard to list shot ids.`
724
811
  };
725
812
  }
813
+ if (shot.production?.media_strategy === "still_motion_graphics") {
814
+ return { error: `Shot ${shot.id} is still_motion_graphics; video revision is forbidden.` };
815
+ }
816
+ try {
817
+ assertProductionGenerationAllowed(shot.production, "video_to_video");
818
+ }
819
+ catch (error) {
820
+ return { error: error instanceof Error ? error.message : String(error) };
821
+ }
726
822
  if (!shot.clip) {
727
823
  return {
728
824
  error: "Shot has no clip to revise. Run render_storyboard_clips first."
@@ -739,6 +835,13 @@ const reviseStoryboardClip = {
739
835
  error: "The shot's clip could not be read back from storage."
740
836
  };
741
837
  }
838
+ const current = await loadBoard(run, row.id);
839
+ if (isError(current))
840
+ return current;
841
+ const currentShot = current.doc.shots.find((value) => value.id === shot.id);
842
+ if (!currentShot)
843
+ return { error: `Shot ${shot.id} no longer exists.` };
844
+ assertProductionGenerationAllowed(currentShot.production, "video_to_video");
742
845
  const saved = await renderMedia(context, {
743
846
  provider: model.provider,
744
847
  capability: "video_to_video",
@@ -786,7 +889,7 @@ const assembleStoryboardTimeline = {
786
889
  return board;
787
890
  const { row, doc } = board;
788
891
  const { Storyboard, TimelineSequence } = await import("@nodetool-ai/models");
789
- const { buildLinkedTimeline, buildStoryboardTimeline, foreignTimelineParts, frameSizeForAspect } = await import("@nodetool-ai/timeline");
892
+ const { buildLinkedTimeline, buildStoryboardTimeline, foreignTimelineParts, assertStoryboardReassemblyAllowed, frameSizeForAspect } = await import("@nodetool-ai/timeline");
790
893
  // A board that links a script is cut against the words: shot lengths come
791
894
  // from the takes and every voiced line gets its own clip. A link pointing
792
895
  // at a script that is gone is a warning, not a failure — the board still
@@ -799,33 +902,7 @@ const assembleStoryboardTimeline = {
799
902
  if (scriptId && !script) {
800
903
  warnings.push(`Script ${scriptId} is linked but could not be loaded, so the board was assembled on its own.`);
801
904
  }
802
- const { loadMediaRefBytes, probeVideoDurationSeconds } = await import("@nodetool-ai/runtime");
803
- const { applyMeasuredShotClipDurations } = await import("@nodetool-ai/timeline");
804
- const signal = context.signal ?? new AbortController().signal;
805
- const measurements = await mapWithConcurrency(doc.shots, clampConcurrency(undefined), async (shot) => {
806
- const clip = shot.clip;
807
- const assetId = clip?.asset_id;
808
- if (shot.status !== "rendered" || !assetId)
809
- return null;
810
- try {
811
- const bytes = await loadMediaRefBytes(clip, context);
812
- const seconds = bytes?.length
813
- ? await probeVideoDurationSeconds(bytes, signal)
814
- : null;
815
- return seconds === null ? null : [assetId, seconds];
816
- }
817
- catch (error) {
818
- if (signal.aborted)
819
- throw error;
820
- return null;
821
- }
822
- });
823
- const durations = new Map();
824
- for (const measurement of measurements) {
825
- if (measurement)
826
- durations.set(...measurement);
827
- }
828
- const measuredShots = applyMeasuredShotClipDurations(doc.shots, durations);
905
+ const measuredShots = await measureStoryboardSources(doc.shots, context);
829
906
  const assembled = script
830
907
  ? buildLinkedTimeline({
831
908
  boardId: row.id,
@@ -865,9 +942,9 @@ const assembleStoryboardTimeline = {
865
942
  `(${worst.usedMs}ms in the cut, ${worst.sourceMs}ms rendered). ` +
866
943
  `Re-render those shots at the length their lines need.`);
867
944
  }
868
- if (assembled.clips.length === 0) {
945
+ if (assembled.durationMs === 0) {
869
946
  return {
870
- error: "No shot has a rendered clip, so there is nothing to assemble. Run render_storyboard_stills, then render_storyboard_clips.",
947
+ error: "No shot has an allowed still, video, or graphics source. Add graphics intent or use render_storyboard_stills / render_storyboard_clips where allowed by the shot production policy.",
871
948
  skipped_shot_ids: assembled.skippedShotIds,
872
949
  skipped_line_ids: skippedLineIds
873
950
  };
@@ -934,11 +1011,12 @@ const assembleStoryboardTimeline = {
934
1011
  };
935
1012
  }
936
1013
  const previous = current.toDocument();
1014
+ assertStoryboardReassemblyAllowed(previous, row.id);
937
1015
  const foreign = foreignTimelineParts(previous, (clip) => clip.storyboardBoardId === row.id ||
938
1016
  (!!scriptId && clip.scriptId === scriptId));
939
1017
  const tracks = [...assembled.tracks, ...foreign.tracks];
940
1018
  const clips = [...assembled.clips, ...foreign.clips];
941
- const durationMs = clips.reduce((end, clip) => Math.max(end, clip.startMs + clip.durationMs), 0);
1019
+ const durationMs = clips.reduce((end, clip) => Math.max(end, clip.startMs + clip.durationMs), assembled.durationMs);
942
1020
  const nextDocument = {
943
1021
  ...previous,
944
1022
  tracks,
@@ -1215,6 +1293,10 @@ const SHOT_EDIT_FIELDS = new Set([
1215
1293
  "slug",
1216
1294
  "camera",
1217
1295
  "motion",
1296
+ "end_state",
1297
+ "sound",
1298
+ "graphics",
1299
+ "production",
1218
1300
  "dialogue",
1219
1301
  "narration",
1220
1302
  "notes",
@@ -1267,8 +1349,16 @@ const BOARD_EDIT_FIELDS = new Set([
1267
1349
  "aspect_ratio",
1268
1350
  "entity_ids",
1269
1351
  "image_model",
1270
- "video_model"
1352
+ "video_model",
1353
+ "narration",
1354
+ "music_prompt",
1355
+ "motion_design"
1271
1356
  ]);
1357
+ const screenplayDirection = z.object({
1358
+ narration: z.string().optional(),
1359
+ music_prompt: z.string().optional(),
1360
+ motion_design: storyboardMotionDesign.nullable().optional()
1361
+ });
1272
1362
  /**
1273
1363
  * The board-level twin of {@link assertKnownShotFields}.
1274
1364
  *
@@ -1350,6 +1440,45 @@ function applyShotFields(shot, args, shots = []) {
1350
1440
  next.camera = args["camera"];
1351
1441
  if (args["motion"] !== undefined)
1352
1442
  next.motion = String(args["motion"]);
1443
+ for (const field of ["end_state", "sound"]) {
1444
+ const value = args[field];
1445
+ if (value === undefined)
1446
+ continue;
1447
+ if (value === null || String(value).trim() === "") {
1448
+ delete next[field];
1449
+ }
1450
+ else {
1451
+ next[field] = String(value);
1452
+ }
1453
+ }
1454
+ if (args["graphics"] !== undefined) {
1455
+ if (args["graphics"] === null) {
1456
+ delete next.graphics;
1457
+ }
1458
+ else {
1459
+ const parsed = storyboardShotGraphics.safeParse(args["graphics"]);
1460
+ if (!parsed.success) {
1461
+ throw new Error(`graphics must be a valid Storyboard graphics object: ${parsed.error.issues
1462
+ .map((issue) => issue.path.join(".") || issue.message)
1463
+ .join(", ")}.`);
1464
+ }
1465
+ next.graphics = parsed.data;
1466
+ }
1467
+ }
1468
+ if (args["production"] !== undefined) {
1469
+ if (args["production"] === null) {
1470
+ delete next.production;
1471
+ }
1472
+ else {
1473
+ const parsed = productionRequirement.safeParse(args["production"]);
1474
+ if (!parsed.success) {
1475
+ throw new Error(`production must be a valid production requirement: ${parsed.error.issues
1476
+ .map((issue) => issue.path.join(".") || issue.message)
1477
+ .join(", ")}.`);
1478
+ }
1479
+ next.production = parsed.data;
1480
+ }
1481
+ }
1353
1482
  if (args["dialogue"] !== undefined)
1354
1483
  next.dialogue = String(args["dialogue"]);
1355
1484
  if (args["narration"] !== undefined)
@@ -1763,6 +1892,13 @@ function applyBoardOp(doc, { op, args }, entities = []) {
1763
1892
  }
1764
1893
  case "set_board": {
1765
1894
  assertKnownBoardFields(args);
1895
+ const direction = screenplayDirection.safeParse(args);
1896
+ if (!direction.success) {
1897
+ throw new Error("set_board has invalid screenplay direction: " +
1898
+ direction.error.issues
1899
+ .map((issue) => `${issue.path.join(".") || "direction"}: ${issue.message}`)
1900
+ .join("; "));
1901
+ }
1766
1902
  if (args["brief"] !== undefined)
1767
1903
  doc.brief = String(args["brief"]);
1768
1904
  if (args["style"] !== undefined)
@@ -1797,13 +1933,45 @@ function applyBoardOp(doc, { op, args }, entities = []) {
1797
1933
  }
1798
1934
  doc.videoModel = videoModel;
1799
1935
  }
1936
+ if (args["narration"] !== undefined ||
1937
+ args["music_prompt"] !== undefined ||
1938
+ args["motion_design"] !== undefined) {
1939
+ const needsScreenplay = args["narration"] !== undefined ||
1940
+ args["music_prompt"] !== undefined ||
1941
+ direction.data.motion_design !== null;
1942
+ if (needsScreenplay) {
1943
+ doc.screenplay = doc.screenplay ?? {
1944
+ type: "screenplay",
1945
+ id: newDocId("sp"),
1946
+ title: "",
1947
+ shots: []
1948
+ };
1949
+ }
1950
+ if (doc.screenplay && direction.data.narration !== undefined) {
1951
+ doc.screenplay.narration = direction.data.narration;
1952
+ }
1953
+ if (doc.screenplay && direction.data.music_prompt !== undefined) {
1954
+ doc.screenplay.music_prompt = direction.data.music_prompt;
1955
+ }
1956
+ if (doc.screenplay && direction.data.motion_design !== undefined) {
1957
+ if (direction.data.motion_design === null) {
1958
+ delete doc.screenplay.motion_design;
1959
+ }
1960
+ else {
1961
+ doc.screenplay.motion_design = direction.data.motion_design;
1962
+ }
1963
+ }
1964
+ }
1800
1965
  return {
1801
1966
  brief: doc.brief,
1802
1967
  style: doc.style,
1803
1968
  aspect_ratio: doc.aspectRatio,
1804
1969
  entity_ids: doc.entityIds,
1805
1970
  image_model: doc.imageModel,
1806
- video_model: doc.videoModel
1971
+ video_model: doc.videoModel,
1972
+ narration: doc.screenplay?.narration,
1973
+ music_prompt: doc.screenplay?.music_prompt,
1974
+ motion_design: doc.screenplay?.motion_design
1807
1975
  };
1808
1976
  }
1809
1977
  }
@@ -1830,6 +1998,50 @@ async function loadStyleEntities(run, doc, ops) {
1830
1998
  });
1831
1999
  return [...cast, ...extra];
1832
2000
  }
2001
+ /** Resolve source refs before any edit writes. Guest IDs stay short, stored refs stay canonical. */
2002
+ async function resolveStoryboardEditSources(run, ops) {
2003
+ const { Asset } = await import("@nodetool-ai/models");
2004
+ const canonical = new Map();
2005
+ const resolve = async (id) => {
2006
+ if (!isFullResourceId(id) && !isShortResourceId(id)) {
2007
+ return id;
2008
+ }
2009
+ const cached = canonical.get(id);
2010
+ if (cached) {
2011
+ return cached;
2012
+ }
2013
+ const asset = run.context.userId ? await Asset.find(run.context.userId, id) : null;
2014
+ if (!asset) {
2015
+ throw new Error(`Source asset or entity ${id} is unavailable.`);
2016
+ }
2017
+ canonical.set(id, asset.id);
2018
+ return asset.id;
2019
+ };
2020
+ const resolved = structuredClone(ops);
2021
+ for (const { args } of resolved) {
2022
+ const references = [args];
2023
+ const graphics = args["graphics"];
2024
+ if (isRecord(graphics) && Array.isArray(graphics["elements"])) {
2025
+ references.push(...graphics["elements"].filter(isRecord));
2026
+ }
2027
+ const production = args["production"];
2028
+ if (isRecord(production) && Array.isArray(production["protected_inputs"])) {
2029
+ references.push(...production["protected_inputs"].filter(isRecord));
2030
+ }
2031
+ for (const reference of references) {
2032
+ for (const field of ["asset_id", "entity_id", "location_id"]) {
2033
+ const id = reference[field];
2034
+ if (isString(id)) {
2035
+ reference[field] = await resolve(id);
2036
+ }
2037
+ }
2038
+ }
2039
+ if (Array.isArray(args["entity_ids"])) {
2040
+ args["entity_ids"] = await Promise.all(args["entity_ids"].map(async (id) => isString(id) ? resolve(id) : id));
2041
+ }
2042
+ }
2043
+ return resolved;
2044
+ }
1833
2045
  const editStoryboard = {
1834
2046
  spec: editStoryboardSpec,
1835
2047
  impl: async (run, params) => {
@@ -1842,12 +2054,22 @@ const editStoryboard = {
1842
2054
  if (isError(board))
1843
2055
  return board;
1844
2056
  const { row, doc } = board;
2057
+ if (params["expected_revision"] !== undefined && params["expected_revision"] !== row.revision) {
2058
+ return { error: "Storyboard revision conflict. Refresh the board before editing." };
2059
+ }
1845
2060
  // A failing op is recorded and the script continues: stopping at the
1846
2061
  // first error hides every problem behind it.
1847
2062
  const records = [];
1848
- const entities = await loadStyleEntities(run, doc, ops);
2063
+ let sourceOps;
2064
+ try {
2065
+ sourceOps = await resolveStoryboardEditSources(run, ops);
2066
+ }
2067
+ catch (error) {
2068
+ return { error: error instanceof Error ? error.message : String(error) };
2069
+ }
2070
+ const entities = await loadStyleEntities(run, doc, sourceOps);
1849
2071
  const resolvedOps = [];
1850
- for (const parsed of ops) {
2072
+ for (const parsed of sourceOps) {
1851
2073
  try {
1852
2074
  const result = applyBoardOp(doc, parsed, entities);
1853
2075
  records.push({
@@ -1888,6 +2110,9 @@ const editStoryboard = {
1888
2110
  resolvedOps.push({ tool: parsed.op, input: parsed.args });
1889
2111
  }
1890
2112
  }
2113
+ if (doc.screenplay) {
2114
+ doc.screenplay.shots = doc.shots;
2115
+ }
1891
2116
  const saved = await Storyboard.updateFieldsIfUnchanged(row.id, row.updated_at, {
1892
2117
  document: JSON.stringify(doc)
1893
2118
  },
@@ -1900,6 +2125,7 @@ const editStoryboard = {
1900
2125
  return {
1901
2126
  storyboard_id: row.id,
1902
2127
  updated_at: saved.updated_at,
2128
+ revision: saved.revision,
1903
2129
  applied: records.length - failed.length,
1904
2130
  failed: failed.length,
1905
2131
  ops: records,
@@ -1920,6 +2146,212 @@ const editStoryboard = {
1920
2146
  }
1921
2147
  };
1922
2148
  // ---------------------------------------------------------------------------
2149
+ // derive_shot_from_clip
2150
+ // ---------------------------------------------------------------------------
2151
+ const DEFAULT_DERIVED_FRAMES = 3;
2152
+ const formatSeconds = (ms) => `${(ms / 1000).toFixed(1)}s`;
2153
+ /**
2154
+ * The headless twin of the editor's Derived shot section
2155
+ * (`useDeriveShotFromClip`): frames → assets → a shot after the source shot
2156
+ * → a clip following it on a new track above the source clip. The board is
2157
+ * written before the timeline, so a timeline conflict leaves the shot on the
2158
+ * board and says so.
2159
+ */
2160
+ const deriveShotFromClip = {
2161
+ spec: deriveShotFromClipSpec,
2162
+ impl: async (run, params) => {
2163
+ const timelineId = params["timeline_id"];
2164
+ if (!isNonBlankString(timelineId)) {
2165
+ return {
2166
+ error: "timeline_id is required (use list_timelines to find one)."
2167
+ };
2168
+ }
2169
+ if (!isNonBlankString(params["clip_id"])) {
2170
+ return { error: "clip_id is required (a clip id or name)." };
2171
+ }
2172
+ const { MAX_DERIVED_FRAMES } = await import("@nodetool-ai/timeline");
2173
+ const frameCount = params["frame_count"] === undefined
2174
+ ? DEFAULT_DERIVED_FRAMES
2175
+ : params["frame_count"];
2176
+ if (!isNumber(frameCount) ||
2177
+ !Number.isInteger(frameCount) ||
2178
+ frameCount < 1 ||
2179
+ frameCount > MAX_DERIVED_FRAMES) {
2180
+ return {
2181
+ error: `frame_count must be a whole number from 1 to ${MAX_DERIVED_FRAMES}.`
2182
+ };
2183
+ }
2184
+ const actionParam = params["action"];
2185
+ if (actionParam !== undefined && !isString(actionParam)) {
2186
+ return { error: "action must be a string." };
2187
+ }
2188
+ const { TimelineSequence, Storyboard } = await import("@nodetool-ai/models");
2189
+ const sequence = await TimelineSequence.findById(timelineId);
2190
+ if (!sequence || sequence.user_id !== run.context.userId) {
2191
+ return { error: `Timeline ${timelineId} was not found.` };
2192
+ }
2193
+ const { findDocumentClip, captureDerivedFrames, placeDerivedShotClip } = await import("./derive-shot.js");
2194
+ const source = findDocumentClip(sequence.toDocument().clips, params["clip_id"]);
2195
+ if (!source) {
2196
+ return {
2197
+ error: `No clip matching "${params["clip_id"]}" in timeline ${timelineId}.`
2198
+ };
2199
+ }
2200
+ const boardId = source.storyboardBoardId;
2201
+ const sourceShotId = source.storyboardShotId;
2202
+ if (!boardId || !sourceShotId) {
2203
+ return {
2204
+ error: `Clip "${source.name}" is not linked to a storyboard shot.`
2205
+ };
2206
+ }
2207
+ if (source.mediaType !== "video" || !source.currentAssetId) {
2208
+ return {
2209
+ error: "Reference frames come from a video clip with footage."
2210
+ };
2211
+ }
2212
+ const board = await loadBoard(run, boardId);
2213
+ if (isError(board))
2214
+ return board;
2215
+ const sourceShot = board.doc.shots.find((shot) => shot.id === sourceShotId);
2216
+ if (!sourceShot) {
2217
+ return {
2218
+ error: `The shot clip "${source.name}" follows is no longer on its board.`
2219
+ };
2220
+ }
2221
+ const label = sourceShot.slug ?? `Shot ${sourceShot.index + 1}`;
2222
+ let frames;
2223
+ try {
2224
+ frames = await captureDerivedFrames(run.context, source, frameCount);
2225
+ }
2226
+ catch (error) {
2227
+ return { error: error instanceof Error ? error.message : String(error) };
2228
+ }
2229
+ const bindings = [];
2230
+ for (const [index, frame] of frames.entries()) {
2231
+ const created = await run.context.createAsset({
2232
+ name: `${label}-frame-${index + 1}.png`,
2233
+ contentType: "image/png",
2234
+ content: frame.png
2235
+ });
2236
+ const assetId = isRecord(created) && isString(created["id"]) ? created["id"] : null;
2237
+ if (!assetId) {
2238
+ return { error: "A reference frame was saved without an asset id." };
2239
+ }
2240
+ bindings.push({
2241
+ kind: "style",
2242
+ asset_id: assetId,
2243
+ label: `${label} at ${formatSeconds(frame.sourceTimeMs)}`
2244
+ });
2245
+ }
2246
+ const action = actionParam?.trim() || sourceShot.action;
2247
+ const shotArgs = {
2248
+ after_shot_id: sourceShot.id,
2249
+ action,
2250
+ slug: `${label} (derived)`,
2251
+ duration_seconds: source.durationMs / 1000,
2252
+ duration_source: "manual",
2253
+ render_mode: "reference",
2254
+ production: {
2255
+ schema_version: 1,
2256
+ speech_mode: "none",
2257
+ requested_take_count: 1,
2258
+ reference_bindings: bindings
2259
+ }
2260
+ };
2261
+ if (sourceShot.camera !== undefined)
2262
+ shotArgs["camera"] = sourceShot.camera;
2263
+ if (sourceShot.motion !== undefined)
2264
+ shotArgs["motion"] = sourceShot.motion;
2265
+ if (sourceShot.entity_ids !== undefined) {
2266
+ shotArgs["entity_ids"] = sourceShot.entity_ids;
2267
+ }
2268
+ if (sourceShot.location_id !== undefined) {
2269
+ shotArgs["location_id"] = sourceShot.location_id;
2270
+ }
2271
+ let shot;
2272
+ for (let attempt = 0; attempt < CAS_ATTEMPTS && !shot; attempt++) {
2273
+ const current = await loadBoard(run, boardId);
2274
+ if (isError(current))
2275
+ return current;
2276
+ const { row, doc } = current;
2277
+ let shotId;
2278
+ try {
2279
+ const added = applyBoardOp(doc, { op: "add_shot", args: shotArgs });
2280
+ shotId = added.id;
2281
+ }
2282
+ catch (error) {
2283
+ return {
2284
+ error: error instanceof Error ? error.message : String(error)
2285
+ };
2286
+ }
2287
+ const index = doc.shots.findIndex((candidate) => candidate.id === shotId);
2288
+ if (sourceShot.clip_model !== undefined) {
2289
+ doc.shots[index] = {
2290
+ ...doc.shots[index],
2291
+ clip_model: sourceShot.clip_model
2292
+ };
2293
+ }
2294
+ if (doc.screenplay) {
2295
+ doc.screenplay.shots = doc.shots;
2296
+ }
2297
+ const saved = await Storyboard.updateFieldsIfUnchanged(row.id, row.updated_at, { document: JSON.stringify(doc) }, { ops: [{ tool: "add_shot", input: { ...shotArgs, id: shotId } }] });
2298
+ if (saved)
2299
+ shot = doc.shots[index];
2300
+ }
2301
+ if (!shot) {
2302
+ return {
2303
+ error: `Storyboard ${boardId} is being modified concurrently; nothing was saved. Retry the call.`
2304
+ };
2305
+ }
2306
+ for (let attempt = 0; attempt < CAS_ATTEMPTS; attempt++) {
2307
+ const current = await TimelineSequence.findById(timelineId);
2308
+ if (!current)
2309
+ break;
2310
+ const document = current.toDocument();
2311
+ const latest = document.clips.find((clip) => clip.id === source.id);
2312
+ if (!latest)
2313
+ break;
2314
+ const placed = placeDerivedShotClip(document, latest, {
2315
+ boardId,
2316
+ shotId: shot.id,
2317
+ name: shot.slug ?? "Derived shot"
2318
+ });
2319
+ const saved = await TimelineSequence.updateDocumentIfUnchanged(current.id, current.updated_at, { ...document, tracks: placed.tracks, clips: placed.clips }, {
2320
+ ops: [
2321
+ {
2322
+ tool: "ui_timeline_add_track",
2323
+ input: { id: placed.trackId, type: "video" }
2324
+ },
2325
+ {
2326
+ tool: "ui_timeline_add_media_clip",
2327
+ input: { id: placed.clipId, track_id: placed.trackId }
2328
+ }
2329
+ ]
2330
+ });
2331
+ if (saved) {
2332
+ return {
2333
+ storyboard_id: boardId,
2334
+ shot_id: shot.id,
2335
+ shot_index: shot.index,
2336
+ slug: shot.slug,
2337
+ reference_asset_ids: bindings.map((binding) => binding.asset_id),
2338
+ timeline_id: timelineId,
2339
+ track_id: placed.trackId,
2340
+ clip_id: placed.clipId,
2341
+ next: "Render the shot with render_storyboard_clips, targets " +
2342
+ `["${shot.id}"]. The clip plays the take once it lands.`
2343
+ };
2344
+ }
2345
+ }
2346
+ return {
2347
+ error: `Shot ${shot.id} was added to storyboard ${boardId}, but timeline ` +
2348
+ `${timelineId} changed or its source clip was removed, so no clip ` +
2349
+ "was placed. Add a clip for the shot with edit_timeline, or remove " +
2350
+ "the shot with edit_storyboard."
2351
+ };
2352
+ }
2353
+ };
2354
+ // ---------------------------------------------------------------------------
1923
2355
  // direct_storyboard
1924
2356
  // ---------------------------------------------------------------------------
1925
2357
  const DEFAULT_DIRECTED_SHOTS = 6;
@@ -2021,6 +2453,8 @@ const directStoryboard = {
2021
2453
  ...held,
2022
2454
  ...shot,
2023
2455
  index,
2456
+ graphics: held.graphics,
2457
+ production: held.production,
2024
2458
  keyframe: held.keyframe,
2025
2459
  keyframe_versions: held.keyframe_versions,
2026
2460
  clip: held.clip,
@@ -2029,7 +2463,11 @@ const directStoryboard = {
2029
2463
  status: held.status
2030
2464
  };
2031
2465
  });
2032
- next.screenplay = screenplay;
2466
+ const previousMotionDesign = next.screenplay?.motion_design;
2467
+ next.screenplay = { ...screenplay, shots: next.shots };
2468
+ if (previousMotionDesign !== undefined) {
2469
+ next.screenplay.motion_design = previousMotionDesign;
2470
+ }
2033
2471
  next.style = screenplay.style_bible ?? next.style;
2034
2472
  next.aspectRatio = screenplay.aspect_ratio ?? next.aspectRatio;
2035
2473
  if (screenplay.genre)
@@ -2040,6 +2478,7 @@ const directStoryboard = {
2040
2478
  return {
2041
2479
  storyboard_id: current.row.id,
2042
2480
  updated_at: saved.updated_at,
2481
+ revision: saved.revision,
2043
2482
  title: screenplay.title,
2044
2483
  genre: next.genre,
2045
2484
  redirected: params["redirect"] === true,
@@ -2225,7 +2664,248 @@ const deleteStoryboard = {
2225
2664
  : { error: `Storyboard ${id} was not found, or it is not yours.` };
2226
2665
  }
2227
2666
  };
2667
+ // ---------------------------------------------------------------------------
2668
+ // get_storyboard_one_take / update_storyboard_one_take
2669
+ // ---------------------------------------------------------------------------
2670
+ /** Above this the providers that take one continuous clip refuse or truncate. */
2671
+ const ONE_TAKE_MAX_SECONDS = 30;
2672
+ /** The most reference images a one-take provider accepts. */
2673
+ const ONE_TAKE_MAX_IMAGES = 9;
2674
+ const oneTakeUpdateInput = z.object({
2675
+ prompt: z.string().optional(),
2676
+ duration_seconds: z.number().positive().nullable().optional(),
2677
+ aspect_ratio: z.string().trim().min(1).nullable().optional(),
2678
+ resolution: z.string().trim().min(1).nullable().optional(),
2679
+ model: z
2680
+ .object({
2681
+ provider: z.string().trim().min(1),
2682
+ id: z.string().trim().min(1),
2683
+ name: z.string().optional()
2684
+ })
2685
+ .nullable()
2686
+ .optional(),
2687
+ shots: z
2688
+ .array(z.object({
2689
+ shot_id: z.string().trim().min(1),
2690
+ end_state: z.string().nullable().optional(),
2691
+ sound: z.string().nullable().optional()
2692
+ }))
2693
+ .optional()
2694
+ });
2695
+ /** The one-take render settings a call may set; null clears one. */
2696
+ const ONE_TAKE_SETTINGS = [
2697
+ "duration_seconds",
2698
+ "aspect_ratio",
2699
+ "resolution",
2700
+ "model"
2701
+ ];
2702
+ /** The board's `videoModel` as a model ref, or null when it names none. */
2703
+ function boardVideoModel(value) {
2704
+ if (!value || typeof value !== "object")
2705
+ return null;
2706
+ const record = value;
2707
+ const id = record["id"];
2708
+ const provider = record["provider"];
2709
+ if (typeof id !== "string" || id === "" || typeof provider !== "string" || provider === "") {
2710
+ return null;
2711
+ }
2712
+ const model = {
2713
+ id,
2714
+ provider: provider
2715
+ };
2716
+ const name = record["name"];
2717
+ if (typeof name === "string") {
2718
+ model.name = name;
2719
+ }
2720
+ return model;
2721
+ }
2722
+ /** The shape both one-take capabilities return. */
2723
+ function oneTakeSummary(row, doc) {
2724
+ const compiled = compileOneTake({
2725
+ shots: doc.shots,
2726
+ oneTake: doc.one_take
2727
+ });
2728
+ const direction = doc.one_take;
2729
+ const settings = {
2730
+ duration_seconds: direction?.duration_seconds ?? null,
2731
+ aspect_ratio: direction?.aspect_ratio ?? null,
2732
+ resolution: direction?.resolution ?? null,
2733
+ model: direction?.model ?? null
2734
+ };
2735
+ const effective = {
2736
+ duration_seconds: compiled.duration_seconds,
2737
+ shot_total_seconds: compiled.shot_total_seconds,
2738
+ aspect_ratio: settings.aspect_ratio ?? doc.aspectRatio ?? null,
2739
+ resolution: settings.resolution,
2740
+ model: settings.model ?? boardVideoModel(doc.videoModel)
2741
+ };
2742
+ const warnings = [];
2743
+ if (!effective.model) {
2744
+ warnings.push("No video model is chosen: set `model` here or the board's video model.");
2745
+ }
2746
+ if (compiled.duration_seconds > ONE_TAKE_MAX_SECONDS) {
2747
+ warnings.push(`The take runs ${compiled.duration_seconds}s, over the ${ONE_TAKE_MAX_SECONDS}s one-take limit.`);
2748
+ }
2749
+ if (compiled.references.length > ONE_TAKE_MAX_IMAGES) {
2750
+ warnings.push(`${compiled.references.length} reference images; one-take models accept at most ${ONE_TAKE_MAX_IMAGES}.`);
2751
+ }
2752
+ const byId = new Map(doc.shots.map((shot) => [shot.id, shot]));
2753
+ const withoutStill = compiled.steps
2754
+ .map((step) => byId.get(step.shot_id))
2755
+ .filter((shot) => !!shot && !shot.keyframe?.asset_id);
2756
+ if (withoutStill.length > 0) {
2757
+ warnings.push(`Shots without a still send no image: ${withoutStill
2758
+ .map((shot) => shot.slug?.trim() || shot.id)
2759
+ .join(", ")}.`);
2760
+ }
2761
+ return {
2762
+ storyboard_id: row.id,
2763
+ revision: row.revision,
2764
+ updated_at: row.updated_at,
2765
+ stored: doc.one_take !== undefined,
2766
+ prompt: doc.one_take?.prompt ?? "",
2767
+ compiled: compiled.compiled,
2768
+ full_prompt: compiled.prompt,
2769
+ references: compiled.references.map((reference, index) => ({
2770
+ image_number: index + 1,
2771
+ marker: `[Image ${index + 1}]`,
2772
+ ...reference
2773
+ })),
2774
+ steps: compiled.steps.map((step) => {
2775
+ const shot = byId.get(step.shot_id);
2776
+ return {
2777
+ shot_id: step.shot_id,
2778
+ index: shot?.index,
2779
+ slug: shot?.slug,
2780
+ start_seconds: step.start_seconds,
2781
+ end_seconds: step.end_seconds,
2782
+ end_state: shot?.end_state ?? null,
2783
+ sound: shot?.sound ?? null
2784
+ };
2785
+ }),
2786
+ duration_seconds: compiled.duration_seconds,
2787
+ settings,
2788
+ effective,
2789
+ warnings
2790
+ };
2791
+ }
2792
+ const getStoryboardOneTake = {
2793
+ spec: getStoryboardOneTakeSpec,
2794
+ impl: async (run, params) => {
2795
+ const board = await loadBoard(run, params["storyboard_id"]);
2796
+ if (isError(board))
2797
+ return board;
2798
+ return oneTakeSummary(board.row, board.doc);
2799
+ }
2800
+ };
2801
+ const updateStoryboardOneTake = {
2802
+ spec: updateStoryboardOneTakeSpec,
2803
+ impl: async (run, params) => {
2804
+ const parsed = oneTakeUpdateInput.safeParse({
2805
+ prompt: params["prompt"],
2806
+ duration_seconds: params["duration_seconds"],
2807
+ aspect_ratio: params["aspect_ratio"],
2808
+ resolution: params["resolution"],
2809
+ model: params["model"],
2810
+ shots: params["shots"]
2811
+ });
2812
+ if (!parsed.success) {
2813
+ return {
2814
+ error: parsed.error.issues
2815
+ .map((issue) => `${issue.path.join(".") || "input"}: ${issue.message}`)
2816
+ .join("; ")
2817
+ };
2818
+ }
2819
+ const { prompt, shots: shotPatches } = parsed.data;
2820
+ const settingsGiven = ONE_TAKE_SETTINGS.filter((key) => parsed.data[key] !== undefined);
2821
+ if (prompt === undefined && settingsGiven.length === 0 && !shotPatches) {
2822
+ return {
2823
+ error: "Pass prompt, duration_seconds, aspect_ratio, resolution, model or shots to update."
2824
+ };
2825
+ }
2826
+ const { Storyboard } = await import("@nodetool-ai/models");
2827
+ for (let attempt = 0; attempt < CAS_ATTEMPTS; attempt++) {
2828
+ const board = await loadBoard(run, params["storyboard_id"]);
2829
+ if (isError(board))
2830
+ return board;
2831
+ const { row } = board;
2832
+ const doc = board.doc;
2833
+ if (params["expected_revision"] !== undefined &&
2834
+ params["expected_revision"] !== row.revision) {
2835
+ return {
2836
+ error: "Storyboard revision conflict. Refresh the board before editing."
2837
+ };
2838
+ }
2839
+ const ops = [];
2840
+ if (prompt !== undefined || settingsGiven.length > 0) {
2841
+ const next = {
2842
+ ...doc.one_take,
2843
+ prompt: prompt ?? doc.one_take?.prompt ?? ""
2844
+ };
2845
+ const { duration_seconds, aspect_ratio, resolution, model } = parsed.data;
2846
+ if (duration_seconds !== undefined)
2847
+ next.duration_seconds = duration_seconds;
2848
+ if (aspect_ratio !== undefined)
2849
+ next.aspect_ratio = aspect_ratio;
2850
+ if (resolution !== undefined)
2851
+ next.resolution = resolution;
2852
+ if (model !== undefined) {
2853
+ next.model = model && {
2854
+ ...model,
2855
+ provider: model.provider
2856
+ };
2857
+ }
2858
+ // A null clears the setting: store it absent, not null.
2859
+ for (const key of ONE_TAKE_SETTINGS) {
2860
+ if (next[key] === null)
2861
+ delete next[key];
2862
+ }
2863
+ doc.one_take = next;
2864
+ // Field-level, the way set_board is: an open editor takes the
2865
+ // direction whole.
2866
+ ops.push({ tool: "set_board", input: { one_take: doc.one_take } });
2867
+ }
2868
+ for (const patch of shotPatches ?? []) {
2869
+ const shot = findShot(doc.shots, patch.shot_id);
2870
+ if (!shot) {
2871
+ return {
2872
+ error: `No shot matches "${patch.shot_id}". Call get_storyboard for shot ids.`
2873
+ };
2874
+ }
2875
+ const next = { ...shot };
2876
+ for (const field of ["end_state", "sound"]) {
2877
+ const value = patch[field];
2878
+ if (value === undefined)
2879
+ continue;
2880
+ if (value === null || value.trim() === "") {
2881
+ delete next[field];
2882
+ }
2883
+ else {
2884
+ next[field] = value;
2885
+ }
2886
+ }
2887
+ doc.shots = doc.shots.map((s) => (s.id === shot.id ? next : s));
2888
+ ops.push({
2889
+ tool: "update_shot",
2890
+ input: { id: shot.id, target: shot.id }
2891
+ });
2892
+ }
2893
+ if (doc.screenplay)
2894
+ doc.screenplay.shots = doc.shots;
2895
+ const saved = await Storyboard.updateFieldsIfUnchanged(row.id, row.updated_at, { document: JSON.stringify(doc) }, { ops });
2896
+ if (!saved)
2897
+ continue;
2898
+ return oneTakeSummary(saved, doc);
2899
+ }
2900
+ return {
2901
+ error: `Storyboard ${String(params["storyboard_id"])} is being modified concurrently; nothing was saved. Retry the call.`
2902
+ };
2903
+ }
2904
+ };
2228
2905
  export const STORYBOARD_CAPABILITIES = [
2906
+ finishStoryboard,
2907
+ layoutStoryboard,
2908
+ previewStoryboardDesign,
2229
2909
  listStoryboards,
2230
2910
  createStoryboard,
2231
2911
  getStoryboard,
@@ -2233,14 +2913,17 @@ export const STORYBOARD_CAPABILITIES = [
2233
2913
  renderStoryboardClips,
2234
2914
  reviseStoryboardClip,
2235
2915
  assembleStoryboardTimeline,
2916
+ deriveShotFromClip,
2236
2917
  editStoryboard,
2237
2918
  directStoryboard,
2238
2919
  extractScriptFromStoryboard,
2239
- deleteStoryboard
2920
+ deleteStoryboard,
2921
+ getStoryboardOneTake,
2922
+ updateStoryboardOneTake
2240
2923
  ];
2241
2924
  export const module = {
2242
2925
  module: "storyboards",
2243
2926
  exports: STORYBOARD_CAPABILITIES
2244
2927
  };
2245
- export { listStoryboards, createStoryboard, getStoryboard, renderStoryboardStills, renderStoryboardClips, reviseStoryboardClip, assembleStoryboardTimeline, editStoryboard, directStoryboard, extractScriptFromStoryboard, deleteStoryboard };
2928
+ export { finishStoryboard, layoutStoryboard, previewStoryboardDesign, listStoryboards, createStoryboard, getStoryboard, renderStoryboardStills, renderStoryboardClips, reviseStoryboardClip, assembleStoryboardTimeline, deriveShotFromClip, editStoryboard, directStoryboard, extractScriptFromStoryboard, deleteStoryboard, getStoryboardOneTake, updateStoryboardOneTake };
2246
2929
  //# sourceMappingURL=storyboards.js.map