@nodetool-ai/agents 0.8.1 → 0.8.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (361) 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/author-graph.d.ts +2 -3
  11. package/dist/author-graph.d.ts.map +1 -1
  12. package/dist/author-graph.js +3 -5
  13. package/dist/author-graph.js.map +1 -1
  14. package/dist/browser-gate.d.ts +2 -2
  15. package/dist/browser-gate.js +2 -2
  16. package/dist/capabilities/GamePublishRequest.d.ts +14 -0
  17. package/dist/capabilities/GamePublishRequest.d.ts.map +1 -0
  18. package/dist/capabilities/GamePublishRequest.js +2 -0
  19. package/dist/capabilities/GamePublishRequest.js.map +1 -0
  20. package/dist/capabilities/adapters.d.ts +4 -13
  21. package/dist/capabilities/adapters.d.ts.map +1 -1
  22. package/dist/capabilities/adapters.js +9 -14
  23. package/dist/capabilities/adapters.js.map +1 -1
  24. package/dist/capabilities/agent-activity.d.ts +27 -0
  25. package/dist/capabilities/agent-activity.d.ts.map +1 -0
  26. package/dist/capabilities/agent-activity.js +103 -0
  27. package/dist/capabilities/agent-activity.js.map +1 -0
  28. package/dist/capabilities/agentic-storyboard-finish.d.ts +67 -0
  29. package/dist/capabilities/agentic-storyboard-finish.d.ts.map +1 -0
  30. package/dist/capabilities/agentic-storyboard-finish.js +1321 -0
  31. package/dist/capabilities/agentic-storyboard-finish.js.map +1 -0
  32. package/dist/capabilities/agents.d.ts +5 -2
  33. package/dist/capabilities/agents.d.ts.map +1 -1
  34. package/dist/capabilities/agents.js +14 -4
  35. package/dist/capabilities/agents.js.map +1 -1
  36. package/dist/capabilities/agents.specs.d.ts +3 -0
  37. package/dist/capabilities/agents.specs.d.ts.map +1 -1
  38. package/dist/capabilities/agents.specs.js +71 -1
  39. package/dist/capabilities/agents.specs.js.map +1 -1
  40. package/dist/capabilities/analysis.d.ts.map +1 -1
  41. package/dist/capabilities/analysis.js +33 -22
  42. package/dist/capabilities/analysis.js.map +1 -1
  43. package/dist/capabilities/analysis.specs.js +2 -2
  44. package/dist/capabilities/analysis.specs.js.map +1 -1
  45. package/dist/capabilities/apps.d.ts.map +1 -1
  46. package/dist/capabilities/apps.js +5 -3
  47. package/dist/capabilities/apps.js.map +1 -1
  48. package/dist/capabilities/args.d.ts +2 -5
  49. package/dist/capabilities/args.d.ts.map +1 -1
  50. package/dist/capabilities/args.js +2 -5
  51. package/dist/capabilities/args.js.map +1 -1
  52. package/dist/capabilities/browser.d.ts +1 -1
  53. package/dist/capabilities/browser.js +1 -1
  54. package/dist/capabilities/browser.specs.d.ts +1 -1
  55. package/dist/capabilities/browser.specs.js +1 -1
  56. package/dist/capabilities/code.d.ts +5 -0
  57. package/dist/capabilities/code.d.ts.map +1 -1
  58. package/dist/capabilities/code.js +128 -89
  59. package/dist/capabilities/code.js.map +1 -1
  60. package/dist/capabilities/errors.d.ts +19 -0
  61. package/dist/capabilities/errors.d.ts.map +1 -0
  62. package/dist/capabilities/errors.js +109 -0
  63. package/dist/capabilities/errors.js.map +1 -0
  64. package/dist/capabilities/errors.specs.d.ts +11 -0
  65. package/dist/capabilities/errors.specs.d.ts.map +1 -0
  66. package/dist/capabilities/errors.specs.js +100 -0
  67. package/dist/capabilities/errors.specs.js.map +1 -0
  68. package/dist/capabilities/example-timelines.d.ts.map +1 -1
  69. package/dist/capabilities/example-timelines.js +52 -10
  70. package/dist/capabilities/example-timelines.js.map +1 -1
  71. package/dist/capabilities/example-timelines.specs.d.ts +1 -0
  72. package/dist/capabilities/example-timelines.specs.d.ts.map +1 -1
  73. package/dist/capabilities/example-timelines.specs.js +21 -3
  74. package/dist/capabilities/example-timelines.specs.js.map +1 -1
  75. package/dist/capabilities/finish-storyboard.d.ts +5 -0
  76. package/dist/capabilities/finish-storyboard.d.ts.map +1 -0
  77. package/dist/capabilities/finish-storyboard.js +278 -0
  78. package/dist/capabilities/finish-storyboard.js.map +1 -0
  79. package/dist/capabilities/game-asset-source.js +1 -1
  80. package/dist/capabilities/game-asset-source.js.map +1 -1
  81. package/dist/capabilities/game.d.ts +14 -2
  82. package/dist/capabilities/game.d.ts.map +1 -1
  83. package/dist/capabilities/game.js +209 -39
  84. package/dist/capabilities/game.js.map +1 -1
  85. package/dist/capabilities/game.specs.d.ts +2 -0
  86. package/dist/capabilities/game.specs.d.ts.map +1 -1
  87. package/dist/capabilities/game.specs.js +25 -11
  88. package/dist/capabilities/game.specs.js.map +1 -1
  89. package/dist/capabilities/game3d.d.ts +17 -0
  90. package/dist/capabilities/game3d.d.ts.map +1 -0
  91. package/dist/capabilities/game3d.js +433 -0
  92. package/dist/capabilities/game3d.js.map +1 -0
  93. package/dist/capabilities/gate-from-context.d.ts +1 -1
  94. package/dist/capabilities/gate-from-context.js +1 -1
  95. package/dist/capabilities/generations.d.ts +2 -0
  96. package/dist/capabilities/generations.d.ts.map +1 -1
  97. package/dist/capabilities/generations.js +7 -2
  98. package/dist/capabilities/generations.js.map +1 -1
  99. package/dist/capabilities/index.d.ts +2 -2
  100. package/dist/capabilities/index.d.ts.map +1 -1
  101. package/dist/capabilities/index.js +2 -2
  102. package/dist/capabilities/index.js.map +1 -1
  103. package/dist/capabilities/invoke.d.ts +14 -25
  104. package/dist/capabilities/invoke.d.ts.map +1 -1
  105. package/dist/capabilities/invoke.js +72 -35
  106. package/dist/capabilities/invoke.js.map +1 -1
  107. package/dist/capabilities/jobs.d.ts.map +1 -1
  108. package/dist/capabilities/jobs.js +47 -3
  109. package/dist/capabilities/jobs.js.map +1 -1
  110. package/dist/capabilities/jobs.specs.d.ts.map +1 -1
  111. package/dist/capabilities/jobs.specs.js +3 -1
  112. package/dist/capabilities/jobs.specs.js.map +1 -1
  113. package/dist/capabilities/js-scripts.d.ts +19 -1
  114. package/dist/capabilities/js-scripts.d.ts.map +1 -1
  115. package/dist/capabilities/js-scripts.js +109 -2
  116. package/dist/capabilities/js-scripts.js.map +1 -1
  117. package/dist/capabilities/js-scripts.specs.d.ts +2 -0
  118. package/dist/capabilities/js-scripts.specs.d.ts.map +1 -1
  119. package/dist/capabilities/js-scripts.specs.js +50 -0
  120. package/dist/capabilities/js-scripts.specs.js.map +1 -1
  121. package/dist/capabilities/lazy-tool.d.ts +23 -24
  122. package/dist/capabilities/lazy-tool.d.ts.map +1 -1
  123. package/dist/capabilities/lazy-tool.js +29 -35
  124. package/dist/capabilities/lazy-tool.js.map +1 -1
  125. package/dist/capabilities/legacy-tools.d.ts +15 -0
  126. package/dist/capabilities/legacy-tools.d.ts.map +1 -0
  127. package/dist/capabilities/legacy-tools.js +98 -0
  128. package/dist/capabilities/legacy-tools.js.map +1 -0
  129. package/dist/capabilities/media.d.ts +0 -9
  130. package/dist/capabilities/media.d.ts.map +1 -1
  131. package/dist/capabilities/media.js +301 -260
  132. package/dist/capabilities/media.js.map +1 -1
  133. package/dist/capabilities/models.d.ts +2 -2
  134. package/dist/capabilities/models.d.ts.map +1 -1
  135. package/dist/capabilities/models.js +5 -3
  136. package/dist/capabilities/models.js.map +1 -1
  137. package/dist/capabilities/registry.d.ts +2 -0
  138. package/dist/capabilities/registry.d.ts.map +1 -1
  139. package/dist/capabilities/registry.js +28 -0
  140. package/dist/capabilities/registry.js.map +1 -1
  141. package/dist/capabilities/run-agent.d.ts +19 -0
  142. package/dist/capabilities/run-agent.d.ts.map +1 -0
  143. package/dist/capabilities/run-agent.js +183 -0
  144. package/dist/capabilities/run-agent.js.map +1 -0
  145. package/dist/capabilities/runs.d.ts +9 -0
  146. package/dist/capabilities/runs.d.ts.map +1 -0
  147. package/dist/capabilities/runs.js +46 -0
  148. package/dist/capabilities/runs.js.map +1 -0
  149. package/dist/capabilities/runs.specs.d.ts +39 -0
  150. package/dist/capabilities/runs.specs.d.ts.map +1 -0
  151. package/dist/capabilities/runs.specs.js +52 -0
  152. package/dist/capabilities/runs.specs.js.map +1 -0
  153. package/dist/capabilities/scripts.d.ts.map +1 -1
  154. package/dist/capabilities/scripts.js +11 -5
  155. package/dist/capabilities/scripts.js.map +1 -1
  156. package/dist/capabilities/sketches.d.ts.map +1 -1
  157. package/dist/capabilities/sketches.js +4 -2
  158. package/dist/capabilities/sketches.js.map +1 -1
  159. package/dist/capabilities/skills.d.ts.map +1 -1
  160. package/dist/capabilities/skills.js +22 -2
  161. package/dist/capabilities/skills.js.map +1 -1
  162. package/dist/capabilities/storyboard-layout-check.d.ts +33 -0
  163. package/dist/capabilities/storyboard-layout-check.d.ts.map +1 -0
  164. package/dist/capabilities/storyboard-layout-check.js +229 -0
  165. package/dist/capabilities/storyboard-layout-check.js.map +1 -0
  166. package/dist/capabilities/storyboard-measured-sources.d.ts +10 -0
  167. package/dist/capabilities/storyboard-measured-sources.d.ts.map +1 -0
  168. package/dist/capabilities/storyboard-measured-sources.js +67 -0
  169. package/dist/capabilities/storyboard-measured-sources.js.map +1 -0
  170. package/dist/capabilities/storyboard-review-times.d.ts +4 -0
  171. package/dist/capabilities/storyboard-review-times.d.ts.map +1 -0
  172. package/dist/capabilities/storyboard-review-times.js +39 -0
  173. package/dist/capabilities/storyboard-review-times.js.map +1 -0
  174. package/dist/capabilities/storyboards.d.ts +2 -18
  175. package/dist/capabilities/storyboards.d.ts.map +1 -1
  176. package/dist/capabilities/storyboards.js +315 -94
  177. package/dist/capabilities/storyboards.js.map +1 -1
  178. package/dist/capabilities/storyboards.specs.d.ts +3 -0
  179. package/dist/capabilities/storyboards.specs.d.ts.map +1 -1
  180. package/dist/capabilities/storyboards.specs.js +42 -3
  181. package/dist/capabilities/storyboards.specs.js.map +1 -1
  182. package/dist/capabilities/timeline-bridge.d.ts +359 -0
  183. package/dist/capabilities/timeline-bridge.d.ts.map +1 -0
  184. package/dist/capabilities/timeline-bridge.js +1016 -0
  185. package/dist/capabilities/timeline-bridge.js.map +1 -0
  186. package/dist/capabilities/timeline-clip-frames.d.ts +17 -0
  187. package/dist/capabilities/timeline-clip-frames.d.ts.map +1 -0
  188. package/dist/capabilities/timeline-clip-frames.js +84 -0
  189. package/dist/capabilities/timeline-clip-frames.js.map +1 -0
  190. package/dist/capabilities/timeline-media-edit.d.ts +8 -0
  191. package/dist/capabilities/timeline-media-edit.d.ts.map +1 -0
  192. package/dist/capabilities/timeline-media-edit.js +94 -0
  193. package/dist/capabilities/timeline-media-edit.js.map +1 -0
  194. package/dist/capabilities/timeline-native-media.d.ts.map +1 -1
  195. package/dist/capabilities/timeline-native-media.js +40 -0
  196. package/dist/capabilities/timeline-native-media.js.map +1 -1
  197. package/dist/capabilities/timelines.d.ts +64 -4
  198. package/dist/capabilities/timelines.d.ts.map +1 -1
  199. package/dist/capabilities/timelines.js +566 -67
  200. package/dist/capabilities/timelines.js.map +1 -1
  201. package/dist/capabilities/timelines.specs.d.ts +8 -0
  202. package/dist/capabilities/timelines.specs.d.ts.map +1 -1
  203. package/dist/capabilities/timelines.specs.js +173 -8
  204. package/dist/capabilities/timelines.specs.js.map +1 -1
  205. package/dist/capabilities/types.d.ts +3 -1
  206. package/dist/capabilities/types.d.ts.map +1 -1
  207. package/dist/capabilities/types.js.map +1 -1
  208. package/dist/capabilities/ui.d.ts.map +1 -1
  209. package/dist/capabilities/ui.js +24 -2
  210. package/dist/capabilities/ui.js.map +1 -1
  211. package/dist/capabilities/workflows.d.ts.map +1 -1
  212. package/dist/capabilities/workflows.js +53 -26
  213. package/dist/capabilities/workflows.js.map +1 -1
  214. package/dist/capabilities/workflows.specs.d.ts.map +1 -1
  215. package/dist/capabilities/workflows.specs.js +7 -1
  216. package/dist/capabilities/workflows.specs.js.map +1 -1
  217. package/dist/codeact/action-diagnostics.d.ts.map +1 -1
  218. package/dist/codeact/action-diagnostics.js +51 -1
  219. package/dist/codeact/action-diagnostics.js.map +1 -1
  220. package/dist/codeact/codeact-executor.d.ts.map +1 -1
  221. package/dist/codeact/codeact-executor.js +16 -8
  222. package/dist/codeact/codeact-executor.js.map +1 -1
  223. package/dist/codeact/compact-ids.d.ts.map +1 -1
  224. package/dist/codeact/compact-ids.js +5 -1
  225. package/dist/codeact/compact-ids.js.map +1 -1
  226. package/dist/codeact/graph-model.d.ts +1 -1
  227. package/dist/codeact/graph-model.d.ts.map +1 -1
  228. package/dist/codeact/graph-model.js +2 -3
  229. package/dist/codeact/graph-model.js.map +1 -1
  230. package/dist/codeact/nodetool-api.d.ts +1 -1
  231. package/dist/codeact/nodetool-api.d.ts.map +1 -1
  232. package/dist/codeact/nodetool-api.js +202 -284
  233. package/dist/codeact/nodetool-api.js.map +1 -1
  234. package/dist/codeact/tool-api.d.ts +6 -3
  235. package/dist/codeact/tool-api.d.ts.map +1 -1
  236. package/dist/codeact/tool-api.js +22 -15
  237. package/dist/codeact/tool-api.js.map +1 -1
  238. package/dist/evals/codeact-api-cases.d.ts.map +1 -1
  239. package/dist/evals/codeact-api-cases.js +2 -0
  240. package/dist/evals/codeact-api-cases.js.map +1 -1
  241. package/dist/evals/codeact-api-runs.d.ts +3 -0
  242. package/dist/evals/codeact-api-runs.d.ts.map +1 -0
  243. package/dist/evals/codeact-api-runs.js +33 -0
  244. package/dist/evals/codeact-api-runs.js.map +1 -0
  245. package/dist/evals/surfaces/sketch.d.ts +2 -0
  246. package/dist/evals/surfaces/sketch.d.ts.map +1 -1
  247. package/dist/evals/surfaces/sketch.js +11 -3
  248. package/dist/evals/surfaces/sketch.js.map +1 -1
  249. package/dist/evals/surfaces/timeline.d.ts +4 -357
  250. package/dist/evals/surfaces/timeline.d.ts.map +1 -1
  251. package/dist/evals/surfaces/timeline.js +9 -2621
  252. package/dist/evals/surfaces/timeline.js.map +1 -1
  253. package/dist/evals/tool-loop-bridge.d.ts +4 -0
  254. package/dist/evals/tool-loop-bridge.d.ts.map +1 -1
  255. package/dist/evals/tool-loop-bridge.js.map +1 -1
  256. package/dist/evals/tool-loop-eval.d.ts +2 -0
  257. package/dist/evals/tool-loop-eval.d.ts.map +1 -1
  258. package/dist/evals/tool-loop-eval.js +6 -1
  259. package/dist/evals/tool-loop-eval.js.map +1 -1
  260. package/dist/evals/tool-loop-permission.d.ts +1 -15
  261. package/dist/evals/tool-loop-permission.d.ts.map +1 -1
  262. package/dist/evals/tool-loop-permission.js +23 -41
  263. package/dist/evals/tool-loop-permission.js.map +1 -1
  264. package/dist/game-authoring.d.ts +4737 -0
  265. package/dist/game-authoring.d.ts.map +1 -0
  266. package/dist/game-authoring.js +146 -0
  267. package/dist/game-authoring.js.map +1 -0
  268. package/dist/game-code-bake.d.ts +26 -0
  269. package/dist/game-code-bake.d.ts.map +1 -0
  270. package/dist/game-code-bake.js +98 -0
  271. package/dist/game-code-bake.js.map +1 -0
  272. package/dist/game-examples.d.ts +872 -16
  273. package/dist/game-examples.d.ts.map +1 -1
  274. package/dist/game-examples.js +5 -4
  275. package/dist/game-examples.js.map +1 -1
  276. package/dist/index.d.ts +15 -4
  277. package/dist/index.d.ts.map +1 -1
  278. package/dist/index.js +13 -3
  279. package/dist/index.js.map +1 -1
  280. package/dist/js-sandbox-worker/engine.d.ts +4 -0
  281. package/dist/js-sandbox-worker/engine.d.ts.map +1 -0
  282. package/dist/js-sandbox-worker/engine.js +45 -0
  283. package/dist/js-sandbox-worker/engine.js.map +1 -0
  284. package/dist/js-sandbox-worker/host.js +1 -1
  285. package/dist/js-sandbox-worker/host.js.map +1 -1
  286. package/dist/js-sandbox-worker/interpreter.d.ts +1 -1
  287. package/dist/js-sandbox-worker/interpreter.d.ts.map +1 -1
  288. package/dist/js-sandbox-worker/interpreter.js +94 -2
  289. package/dist/js-sandbox-worker/interpreter.js.map +1 -1
  290. package/dist/js-sandbox-worker/worker-entry.d.ts.map +1 -1
  291. package/dist/js-sandbox-worker/worker-entry.js +3 -2
  292. package/dist/js-sandbox-worker/worker-entry.js.map +1 -1
  293. package/dist/js-sandbox.d.ts +2 -0
  294. package/dist/js-sandbox.d.ts.map +1 -1
  295. package/dist/js-sandbox.js +56 -11
  296. package/dist/js-sandbox.js.map +1 -1
  297. package/dist/js-script-app-runner.d.ts +2 -0
  298. package/dist/js-script-app-runner.d.ts.map +1 -1
  299. package/dist/js-script-app-runner.js +8 -3
  300. package/dist/js-script-app-runner.js.map +1 -1
  301. package/dist/js-script-sandbox.d.ts +12 -18
  302. package/dist/js-script-sandbox.d.ts.map +1 -1
  303. package/dist/js-script-sandbox.js +3 -49
  304. package/dist/js-script-sandbox.js.map +1 -1
  305. package/dist/prompts/product-knowledge.d.ts +1 -1
  306. package/dist/prompts/product-knowledge.d.ts.map +1 -1
  307. package/dist/prompts/product-knowledge.js +82 -41
  308. package/dist/prompts/product-knowledge.js.map +1 -1
  309. package/dist/sandbox-pack-resolution.d.ts +21 -0
  310. package/dist/sandbox-pack-resolution.d.ts.map +1 -0
  311. package/dist/sandbox-pack-resolution.js +42 -0
  312. package/dist/sandbox-pack-resolution.js.map +1 -0
  313. package/dist/sandbox-toolbelt.d.ts +3 -1
  314. package/dist/sandbox-toolbelt.d.ts.map +1 -1
  315. package/dist/sandbox-toolbelt.js +8 -2
  316. package/dist/sandbox-toolbelt.js.map +1 -1
  317. package/dist/skill-prompt.d.ts +11 -1
  318. package/dist/skill-prompt.d.ts.map +1 -1
  319. package/dist/skill-prompt.js +17 -6
  320. package/dist/skill-prompt.js.map +1 -1
  321. package/dist/system-skills.d.ts +7 -1
  322. package/dist/system-skills.d.ts.map +1 -1
  323. package/dist/system-skills.js +2 -2
  324. package/dist/system-skills.js.map +1 -1
  325. package/dist/timeline-capture.d.ts +21 -0
  326. package/dist/timeline-capture.d.ts.map +1 -0
  327. package/dist/timeline-capture.js +564 -0
  328. package/dist/timeline-capture.js.map +1 -0
  329. package/dist/timeline-code-bake.d.ts +75 -0
  330. package/dist/timeline-code-bake.d.ts.map +1 -0
  331. package/dist/timeline-code-bake.js +327 -0
  332. package/dist/timeline-code-bake.js.map +1 -0
  333. package/dist/timeline-preview/frames.d.ts +26 -0
  334. package/dist/timeline-preview/frames.d.ts.map +1 -1
  335. package/dist/timeline-preview/frames.js +155 -70
  336. package/dist/timeline-preview/frames.js.map +1 -1
  337. package/dist/tools/base-tool.d.ts +1 -0
  338. package/dist/tools/base-tool.d.ts.map +1 -1
  339. package/dist/tools/base-tool.js +1 -1
  340. package/dist/tools/base-tool.js.map +1 -1
  341. package/dist/tools/builtin-tools.d.ts.map +1 -1
  342. package/dist/tools/builtin-tools.js +13 -0
  343. package/dist/tools/builtin-tools.js.map +1 -1
  344. package/dist/tools/external-capability-tools.d.ts +1 -1
  345. package/dist/tools/external-capability-tools.js +1 -1
  346. package/dist/tools/mcp-tool-support.d.ts +10 -9
  347. package/dist/tools/mcp-tool-support.d.ts.map +1 -1
  348. package/dist/tools/mcp-tool-support.js +14 -13
  349. package/dist/tools/mcp-tool-support.js.map +1 -1
  350. package/dist/tools/mcp-tools.d.ts +6 -4
  351. package/dist/tools/mcp-tools.d.ts.map +1 -1
  352. package/dist/tools/mcp-tools.js +65 -62
  353. package/dist/tools/mcp-tools.js.map +1 -1
  354. package/dist/tools/tool-permissions.d.ts +1 -1
  355. package/dist/tools/tool-permissions.js +1 -1
  356. package/package.json +24 -22
  357. package/dist/capabilities/gate-tools.d.ts +0 -18
  358. package/dist/capabilities/gate-tools.d.ts.map +0 -1
  359. package/dist/capabilities/gate-tools.js +0 -66
  360. package/dist/capabilities/gate-tools.js.map +0 -1
  361. 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, isFullResourceId, isShortResourceId, productionRequirement } from "@nodetool-ai/protocol";
19
24
  import { stampScriptStoryboardId } from "./script-link.js";
20
25
  import { listStoryboardsSpec, createStoryboardSpec, getStoryboardSpec, renderStoryboardStillsSpec, renderStoryboardClipsSpec, reviseStoryboardClipSpec, assembleStoryboardTimelineSpec, editStoryboardSpec, directStoryboardSpec, extractScriptFromStoryboardSpec, deleteStoryboardSpec } from "./storyboards.specs.js";
21
- import { clampConcurrency, mapWithConcurrency } from "./concurrency.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,8 @@ const getStoryboard = {
429
439
  action: shot.action,
430
440
  camera: shot.camera,
431
441
  motion: shot.motion,
442
+ graphics: shot.graphics,
443
+ production: shot.production,
432
444
  duration_seconds: shot.duration_seconds,
433
445
  status: shot.status,
434
446
  has_keyframe: !!shot.keyframe,
@@ -531,6 +543,71 @@ async function filterStale(selected, params, doc, entities, kind) {
531
543
  .map((shot) => shot.id)
532
544
  };
533
545
  }
546
+ function modelOverrides(params) {
547
+ const options = {};
548
+ if (isNonBlankString(params["provider"])) {
549
+ options.provider = params["provider"];
550
+ }
551
+ if (isNonBlankString(params["model"])) {
552
+ options.model = params["model"];
553
+ }
554
+ return options;
555
+ }
556
+ function missingPlanModel(plan) {
557
+ if (plan.model.provider && plan.model.model) {
558
+ return undefined;
559
+ }
560
+ return {
561
+ 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.`
562
+ };
563
+ }
564
+ async function clipModelError(context, plans) {
565
+ const groups = new Map();
566
+ for (const plan of plans) {
567
+ const error = missingPlanModel(plan);
568
+ if (error) {
569
+ return error;
570
+ }
571
+ if (plan.preflightError) {
572
+ continue;
573
+ }
574
+ const key = JSON.stringify([plan.model.provider, plan.model.model]);
575
+ const group = groups.get(key) ?? [];
576
+ group.push(plan);
577
+ groups.set(key, group);
578
+ }
579
+ for (const group of groups.values()) {
580
+ const model = group[0].model;
581
+ let supportedTasks = model.supportedTasks;
582
+ try {
583
+ const provider = await context.getProvider(model.provider);
584
+ const models = await provider.getAvailableVideoModels();
585
+ supportedTasks =
586
+ models.find((entry) => entry.id === model.model)?.supportedTasks ??
587
+ supportedTasks;
588
+ }
589
+ catch {
590
+ // Legacy providers can lack discovery, so their persisted task declarations apply.
591
+ }
592
+ const unsupported = group.find((plan) => {
593
+ const task = plan.mode === "direct" ? "text_to_video" : plan.mode === "reference" ? "reference_to_video" : "image_to_video";
594
+ return supportedTasks?.length && !supportedTasks.includes(task);
595
+ });
596
+ if (unsupported) {
597
+ const task = unsupported.mode === "direct" ? "text_to_video" : unsupported.mode === "reference" ? "reference_to_video" : "image_to_video";
598
+ return {
599
+ error: `The selected clip model ${model.provider}/${model.model} does not support ${task}; choose a model that supports the selected shot mode.`
600
+ };
601
+ }
602
+ }
603
+ return undefined;
604
+ }
605
+ function uniformModel(plans) {
606
+ const model = plans[0]?.model;
607
+ return model && plans.every((plan) => plan.model.provider === model.provider && plan.model.model === model.model)
608
+ ? { provider: model.provider, model: model.model }
609
+ : {};
610
+ }
534
611
  const renderStoryboardStills = {
535
612
  spec: renderStoryboardStillsSpec,
536
613
  impl: async (run, params) => {
@@ -539,14 +616,11 @@ const renderStoryboardStills = {
539
616
  if (isError(board))
540
617
  return board;
541
618
  const { row, doc } = board;
542
- const model = resolveModel(params, doc.imageModel, "still", "text_to_image");
543
- if (isError(model))
544
- return model;
545
619
  const { shotRenderMode } = await import("@nodetool-ai/protocol");
546
620
  // A direct shot renders its clip from the prompt, so it needs no still.
547
621
  // Naming it in `targets` still renders one — a board frame to look at is
548
622
  // worth having even when the clip does not come from it.
549
- const selected = selectShots(doc.shots, params["targets"], (s) => !s.keyframe &&
623
+ const selected = selectShots(doc.shots, params["targets"], (s) => (params["stale_only"] === true ? !!s.keyframe : !s.keyframe) &&
550
624
  shotRenderMode(s) !== "direct" &&
551
625
  !shotHasPicture(s, doc.shots));
552
626
  if (isError(selected))
@@ -565,6 +639,10 @@ const renderStoryboardStills = {
565
639
  : "No shot needs a still: each already has one, or renders its clip directly."
566
640
  };
567
641
  }
642
+ const protectedStill = chosen.find((shot) => shot.production?.protected_inputs?.some((input) => input.asset_id));
643
+ if (protectedStill) {
644
+ 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.` };
645
+ }
568
646
  if (chosen.length > MAX_SHOTS_PER_CALL) {
569
647
  return {
570
648
  error: `${chosen.length} shots selected, over the ${MAX_SHOTS_PER_CALL}-shot per-call limit. Pass targets in batches.`
@@ -575,22 +653,34 @@ const renderStoryboardStills = {
575
653
  // says: `style` and `model` can be overridden per call. Recording the
576
654
  // override is the point — a version rendered against something other than
577
655
  // the board's settings reads stale against the board, correctly.
578
- const planOptions = {
579
- provider: model.provider,
580
- model: model.model
581
- };
656
+ const planOptions = modelOverrides(params);
582
657
  if (isString(params["style"])) {
583
658
  planOptions.style = params["style"];
584
659
  }
585
660
  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"])
661
+ const { imageModelSupportsTask } = await import("@nodetool-ai/runtime");
662
+ for (const plan of plans) {
663
+ const modelError = missingPlanModel(plan);
664
+ if (modelError) {
665
+ return modelError;
666
+ }
667
+ plan.stillModelTakesImages = await imageModelSupportsTask(context, plan.model, "image_to_image", plan.model.supportedTasks);
668
+ }
669
+ const outcomes = await withSpan("render", {
670
+ "document.id": row.id,
671
+ "render.kind": "keyframe",
672
+ "render.shot_count": plans.length
673
+ }, async (span) => {
674
+ const rendered = await renderShots(renderHost(context), { id: row.id }, plans, { concurrency: clampConcurrency(params["concurrency"]) });
675
+ if (rendered.some((outcome) => !outcome.ok)) {
676
+ span?.setStatus({ code: SpanStatusCode.ERROR });
677
+ }
678
+ return rendered;
588
679
  });
589
680
  const results = outcomes.map((outcome) => outcomeRow(outcome, false));
590
681
  return {
591
682
  storyboard_id: row.id,
592
- provider: model.provider,
593
- model: model.model,
683
+ ...uniformModel(plans),
594
684
  rendered: results.filter((r) => r.ok).length,
595
685
  failed: results.filter((r) => !r.ok).length,
596
686
  skipped,
@@ -613,43 +703,23 @@ const renderStoryboardClips = {
613
703
  override !== "reference") {
614
704
  return { error: 'mode must be "keyframe", "direct", or "reference".' };
615
705
  }
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
- }
706
+ const candidates = selectShots(doc.shots, params["targets"], (shot) => (params["stale_only"] === true ? !!shot.clip : !shotHasPicture(shot, doc.shots)) &&
707
+ !shot.covered_by?.shot_id);
708
+ if (isError(candidates)) {
709
+ return candidates;
651
710
  }
652
711
  const entities = await loadBoardEntities(context, doc);
712
+ const { planShotRenders, renderShots } = await import("@nodetool-ai/storyboard");
713
+ const readinessOptions = modelOverrides(params);
714
+ if (override !== undefined) {
715
+ readinessOptions.mode = override;
716
+ }
717
+ const ready = new Set(planShotRenders(doc, entities, "clip", candidates.map((shot) => shot.id), readinessOptions)
718
+ .filter((plan) => plan.mode !== "keyframe" || !!plan.sourceKeyframe)
719
+ .map((plan) => plan.shotId));
720
+ const selected = params["targets"] === undefined || params["targets"] === null
721
+ ? candidates.filter((shot) => ready.has(shot.id))
722
+ : candidates;
653
723
  const fresh = await filterStale(selected, params, doc, entities, "clip");
654
724
  const skipped = fresh.skipped;
655
725
  const chosen = fresh.shots;
@@ -663,13 +733,16 @@ const renderStoryboardClips = {
663
733
  : '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
734
  };
665
735
  }
736
+ const forbiddenClip = chosen.find((shot) => shot.production?.media_strategy === "still_motion_graphics");
737
+ if (forbiddenClip) {
738
+ return { error: `Shot ${forbiddenClip.id} is still_motion_graphics; video generation is forbidden. Materialize its still/assets as Timeline layers instead.` };
739
+ }
666
740
  if (chosen.length > MAX_SHOTS_PER_CALL) {
667
741
  return {
668
742
  error: `${chosen.length} shots selected, over the ${MAX_SHOTS_PER_CALL}-shot per-call limit. Pass targets in batches.`
669
743
  };
670
744
  }
671
745
  const { scriptLinesById } = await import("@nodetool-ai/timeline");
672
- const { planShotRenders, renderShots } = await import("@nodetool-ai/storyboard");
673
746
  // A linked board times its shots from the words they cover, so a clip is
674
747
  // rendered long enough to hold its voiceover (design §2.3). A shot pinned
675
748
  // to `manual`, an unvoiced line, or an unlinked board keeps
@@ -678,8 +751,7 @@ const renderStoryboardClips = {
678
751
  // As in the stills path: the record says what this call rendered with, so
679
752
  // a per-call model or style override reads stale against the board.
680
753
  const planOptions = {
681
- provider: model.provider,
682
- model: model.model,
754
+ ...modelOverrides(params),
683
755
  style: isString(params["style"]) ? params["style"] : doc.style || "",
684
756
  scriptLines: scriptLinesById(scriptDoc?.sections ?? [])
685
757
  };
@@ -687,18 +759,31 @@ const renderStoryboardClips = {
687
759
  planOptions.mode = override;
688
760
  }
689
761
  const plans = planShotRenders(doc, entities, "clip", chosen.map((shot) => shot.id), planOptions);
762
+ const modelError = await clipModelError(context, plans);
763
+ if (modelError) {
764
+ return modelError;
765
+ }
690
766
  const renderOptions = {
691
767
  concurrency: clampConcurrency(params["concurrency"])
692
768
  };
693
769
  if (isString(params["resolution"])) {
694
770
  renderOptions.resolution = params["resolution"];
695
771
  }
696
- const outcomes = await renderShots(renderHost(context), { id: row.id }, plans, renderOptions);
772
+ const outcomes = await withSpan("render", {
773
+ "document.id": row.id,
774
+ "render.kind": "clip",
775
+ "render.shot_count": plans.length
776
+ }, async (span) => {
777
+ const rendered = await renderShots(renderHost(context), { id: row.id }, plans, renderOptions);
778
+ if (rendered.some((outcome) => !outcome.ok)) {
779
+ span?.setStatus({ code: SpanStatusCode.ERROR });
780
+ }
781
+ return rendered;
782
+ });
697
783
  const results = outcomes.map((outcome) => outcomeRow(outcome, true));
698
784
  return {
699
785
  storyboard_id: row.id,
700
- provider: model.provider,
701
- model: model.model,
786
+ ...uniformModel(plans),
702
787
  rendered: results.filter((r) => r.ok).length,
703
788
  failed: results.filter((r) => !r.ok).length,
704
789
  skipped,
@@ -723,6 +808,15 @@ const reviseStoryboardClip = {
723
808
  error: `No shot matches "${String(params["target"])}". Call get_storyboard to list shot ids.`
724
809
  };
725
810
  }
811
+ if (shot.production?.media_strategy === "still_motion_graphics") {
812
+ return { error: `Shot ${shot.id} is still_motion_graphics; video revision is forbidden.` };
813
+ }
814
+ try {
815
+ assertProductionGenerationAllowed(shot.production, "video_to_video");
816
+ }
817
+ catch (error) {
818
+ return { error: error instanceof Error ? error.message : String(error) };
819
+ }
726
820
  if (!shot.clip) {
727
821
  return {
728
822
  error: "Shot has no clip to revise. Run render_storyboard_clips first."
@@ -739,6 +833,13 @@ const reviseStoryboardClip = {
739
833
  error: "The shot's clip could not be read back from storage."
740
834
  };
741
835
  }
836
+ const current = await loadBoard(run, row.id);
837
+ if (isError(current))
838
+ return current;
839
+ const currentShot = current.doc.shots.find((value) => value.id === shot.id);
840
+ if (!currentShot)
841
+ return { error: `Shot ${shot.id} no longer exists.` };
842
+ assertProductionGenerationAllowed(currentShot.production, "video_to_video");
742
843
  const saved = await renderMedia(context, {
743
844
  provider: model.provider,
744
845
  capability: "video_to_video",
@@ -786,7 +887,7 @@ const assembleStoryboardTimeline = {
786
887
  return board;
787
888
  const { row, doc } = board;
788
889
  const { Storyboard, TimelineSequence } = await import("@nodetool-ai/models");
789
- const { buildLinkedTimeline, buildStoryboardTimeline, foreignTimelineParts, frameSizeForAspect } = await import("@nodetool-ai/timeline");
890
+ const { buildLinkedTimeline, buildStoryboardTimeline, foreignTimelineParts, assertStoryboardReassemblyAllowed, frameSizeForAspect } = await import("@nodetool-ai/timeline");
790
891
  // A board that links a script is cut against the words: shot lengths come
791
892
  // from the takes and every voiced line gets its own clip. A link pointing
792
893
  // at a script that is gone is a warning, not a failure — the board still
@@ -799,33 +900,7 @@ const assembleStoryboardTimeline = {
799
900
  if (scriptId && !script) {
800
901
  warnings.push(`Script ${scriptId} is linked but could not be loaded, so the board was assembled on its own.`);
801
902
  }
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);
903
+ const measuredShots = await measureStoryboardSources(doc.shots, context);
829
904
  const assembled = script
830
905
  ? buildLinkedTimeline({
831
906
  boardId: row.id,
@@ -865,9 +940,9 @@ const assembleStoryboardTimeline = {
865
940
  `(${worst.usedMs}ms in the cut, ${worst.sourceMs}ms rendered). ` +
866
941
  `Re-render those shots at the length their lines need.`);
867
942
  }
868
- if (assembled.clips.length === 0) {
943
+ if (assembled.durationMs === 0) {
869
944
  return {
870
- error: "No shot has a rendered clip, so there is nothing to assemble. Run render_storyboard_stills, then render_storyboard_clips.",
945
+ 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
946
  skipped_shot_ids: assembled.skippedShotIds,
872
947
  skipped_line_ids: skippedLineIds
873
948
  };
@@ -934,11 +1009,12 @@ const assembleStoryboardTimeline = {
934
1009
  };
935
1010
  }
936
1011
  const previous = current.toDocument();
1012
+ assertStoryboardReassemblyAllowed(previous, row.id);
937
1013
  const foreign = foreignTimelineParts(previous, (clip) => clip.storyboardBoardId === row.id ||
938
1014
  (!!scriptId && clip.scriptId === scriptId));
939
1015
  const tracks = [...assembled.tracks, ...foreign.tracks];
940
1016
  const clips = [...assembled.clips, ...foreign.clips];
941
- const durationMs = clips.reduce((end, clip) => Math.max(end, clip.startMs + clip.durationMs), 0);
1017
+ const durationMs = clips.reduce((end, clip) => Math.max(end, clip.startMs + clip.durationMs), assembled.durationMs);
942
1018
  const nextDocument = {
943
1019
  ...previous,
944
1020
  tracks,
@@ -1215,6 +1291,8 @@ const SHOT_EDIT_FIELDS = new Set([
1215
1291
  "slug",
1216
1292
  "camera",
1217
1293
  "motion",
1294
+ "graphics",
1295
+ "production",
1218
1296
  "dialogue",
1219
1297
  "narration",
1220
1298
  "notes",
@@ -1267,8 +1345,16 @@ const BOARD_EDIT_FIELDS = new Set([
1267
1345
  "aspect_ratio",
1268
1346
  "entity_ids",
1269
1347
  "image_model",
1270
- "video_model"
1348
+ "video_model",
1349
+ "narration",
1350
+ "music_prompt",
1351
+ "motion_design"
1271
1352
  ]);
1353
+ const screenplayDirection = z.object({
1354
+ narration: z.string().optional(),
1355
+ music_prompt: z.string().optional(),
1356
+ motion_design: storyboardMotionDesign.nullable().optional()
1357
+ });
1272
1358
  /**
1273
1359
  * The board-level twin of {@link assertKnownShotFields}.
1274
1360
  *
@@ -1350,6 +1436,34 @@ function applyShotFields(shot, args, shots = []) {
1350
1436
  next.camera = args["camera"];
1351
1437
  if (args["motion"] !== undefined)
1352
1438
  next.motion = String(args["motion"]);
1439
+ if (args["graphics"] !== undefined) {
1440
+ if (args["graphics"] === null) {
1441
+ delete next.graphics;
1442
+ }
1443
+ else {
1444
+ const parsed = storyboardShotGraphics.safeParse(args["graphics"]);
1445
+ if (!parsed.success) {
1446
+ throw new Error(`graphics must be a valid Storyboard graphics object: ${parsed.error.issues
1447
+ .map((issue) => issue.path.join(".") || issue.message)
1448
+ .join(", ")}.`);
1449
+ }
1450
+ next.graphics = parsed.data;
1451
+ }
1452
+ }
1453
+ if (args["production"] !== undefined) {
1454
+ if (args["production"] === null) {
1455
+ delete next.production;
1456
+ }
1457
+ else {
1458
+ const parsed = productionRequirement.safeParse(args["production"]);
1459
+ if (!parsed.success) {
1460
+ throw new Error(`production must be a valid production requirement: ${parsed.error.issues
1461
+ .map((issue) => issue.path.join(".") || issue.message)
1462
+ .join(", ")}.`);
1463
+ }
1464
+ next.production = parsed.data;
1465
+ }
1466
+ }
1353
1467
  if (args["dialogue"] !== undefined)
1354
1468
  next.dialogue = String(args["dialogue"]);
1355
1469
  if (args["narration"] !== undefined)
@@ -1763,6 +1877,13 @@ function applyBoardOp(doc, { op, args }, entities = []) {
1763
1877
  }
1764
1878
  case "set_board": {
1765
1879
  assertKnownBoardFields(args);
1880
+ const direction = screenplayDirection.safeParse(args);
1881
+ if (!direction.success) {
1882
+ throw new Error("set_board has invalid screenplay direction: " +
1883
+ direction.error.issues
1884
+ .map((issue) => `${issue.path.join(".") || "direction"}: ${issue.message}`)
1885
+ .join("; "));
1886
+ }
1766
1887
  if (args["brief"] !== undefined)
1767
1888
  doc.brief = String(args["brief"]);
1768
1889
  if (args["style"] !== undefined)
@@ -1797,13 +1918,45 @@ function applyBoardOp(doc, { op, args }, entities = []) {
1797
1918
  }
1798
1919
  doc.videoModel = videoModel;
1799
1920
  }
1921
+ if (args["narration"] !== undefined ||
1922
+ args["music_prompt"] !== undefined ||
1923
+ args["motion_design"] !== undefined) {
1924
+ const needsScreenplay = args["narration"] !== undefined ||
1925
+ args["music_prompt"] !== undefined ||
1926
+ direction.data.motion_design !== null;
1927
+ if (needsScreenplay) {
1928
+ doc.screenplay = doc.screenplay ?? {
1929
+ type: "screenplay",
1930
+ id: newDocId("sp"),
1931
+ title: "",
1932
+ shots: []
1933
+ };
1934
+ }
1935
+ if (doc.screenplay && direction.data.narration !== undefined) {
1936
+ doc.screenplay.narration = direction.data.narration;
1937
+ }
1938
+ if (doc.screenplay && direction.data.music_prompt !== undefined) {
1939
+ doc.screenplay.music_prompt = direction.data.music_prompt;
1940
+ }
1941
+ if (doc.screenplay && direction.data.motion_design !== undefined) {
1942
+ if (direction.data.motion_design === null) {
1943
+ delete doc.screenplay.motion_design;
1944
+ }
1945
+ else {
1946
+ doc.screenplay.motion_design = direction.data.motion_design;
1947
+ }
1948
+ }
1949
+ }
1800
1950
  return {
1801
1951
  brief: doc.brief,
1802
1952
  style: doc.style,
1803
1953
  aspect_ratio: doc.aspectRatio,
1804
1954
  entity_ids: doc.entityIds,
1805
1955
  image_model: doc.imageModel,
1806
- video_model: doc.videoModel
1956
+ video_model: doc.videoModel,
1957
+ narration: doc.screenplay?.narration,
1958
+ music_prompt: doc.screenplay?.music_prompt,
1959
+ motion_design: doc.screenplay?.motion_design
1807
1960
  };
1808
1961
  }
1809
1962
  }
@@ -1830,6 +1983,50 @@ async function loadStyleEntities(run, doc, ops) {
1830
1983
  });
1831
1984
  return [...cast, ...extra];
1832
1985
  }
1986
+ /** Resolve source refs before any edit writes. Guest IDs stay short, stored refs stay canonical. */
1987
+ async function resolveStoryboardEditSources(run, ops) {
1988
+ const { Asset } = await import("@nodetool-ai/models");
1989
+ const canonical = new Map();
1990
+ const resolve = async (id) => {
1991
+ if (!isFullResourceId(id) && !isShortResourceId(id)) {
1992
+ return id;
1993
+ }
1994
+ const cached = canonical.get(id);
1995
+ if (cached) {
1996
+ return cached;
1997
+ }
1998
+ const asset = run.context.userId ? await Asset.find(run.context.userId, id) : null;
1999
+ if (!asset) {
2000
+ throw new Error(`Source asset or entity ${id} is unavailable.`);
2001
+ }
2002
+ canonical.set(id, asset.id);
2003
+ return asset.id;
2004
+ };
2005
+ const resolved = structuredClone(ops);
2006
+ for (const { args } of resolved) {
2007
+ const references = [args];
2008
+ const graphics = args["graphics"];
2009
+ if (isRecord(graphics) && Array.isArray(graphics["elements"])) {
2010
+ references.push(...graphics["elements"].filter(isRecord));
2011
+ }
2012
+ const production = args["production"];
2013
+ if (isRecord(production) && Array.isArray(production["protected_inputs"])) {
2014
+ references.push(...production["protected_inputs"].filter(isRecord));
2015
+ }
2016
+ for (const reference of references) {
2017
+ for (const field of ["asset_id", "entity_id", "location_id"]) {
2018
+ const id = reference[field];
2019
+ if (isString(id)) {
2020
+ reference[field] = await resolve(id);
2021
+ }
2022
+ }
2023
+ }
2024
+ if (Array.isArray(args["entity_ids"])) {
2025
+ args["entity_ids"] = await Promise.all(args["entity_ids"].map(async (id) => isString(id) ? resolve(id) : id));
2026
+ }
2027
+ }
2028
+ return resolved;
2029
+ }
1833
2030
  const editStoryboard = {
1834
2031
  spec: editStoryboardSpec,
1835
2032
  impl: async (run, params) => {
@@ -1842,12 +2039,22 @@ const editStoryboard = {
1842
2039
  if (isError(board))
1843
2040
  return board;
1844
2041
  const { row, doc } = board;
2042
+ if (params["expected_revision"] !== undefined && params["expected_revision"] !== row.revision) {
2043
+ return { error: "Storyboard revision conflict. Refresh the board before editing." };
2044
+ }
1845
2045
  // A failing op is recorded and the script continues: stopping at the
1846
2046
  // first error hides every problem behind it.
1847
2047
  const records = [];
1848
- const entities = await loadStyleEntities(run, doc, ops);
2048
+ let sourceOps;
2049
+ try {
2050
+ sourceOps = await resolveStoryboardEditSources(run, ops);
2051
+ }
2052
+ catch (error) {
2053
+ return { error: error instanceof Error ? error.message : String(error) };
2054
+ }
2055
+ const entities = await loadStyleEntities(run, doc, sourceOps);
1849
2056
  const resolvedOps = [];
1850
- for (const parsed of ops) {
2057
+ for (const parsed of sourceOps) {
1851
2058
  try {
1852
2059
  const result = applyBoardOp(doc, parsed, entities);
1853
2060
  records.push({
@@ -1888,6 +2095,9 @@ const editStoryboard = {
1888
2095
  resolvedOps.push({ tool: parsed.op, input: parsed.args });
1889
2096
  }
1890
2097
  }
2098
+ if (doc.screenplay) {
2099
+ doc.screenplay.shots = doc.shots;
2100
+ }
1891
2101
  const saved = await Storyboard.updateFieldsIfUnchanged(row.id, row.updated_at, {
1892
2102
  document: JSON.stringify(doc)
1893
2103
  },
@@ -1900,6 +2110,7 @@ const editStoryboard = {
1900
2110
  return {
1901
2111
  storyboard_id: row.id,
1902
2112
  updated_at: saved.updated_at,
2113
+ revision: saved.revision,
1903
2114
  applied: records.length - failed.length,
1904
2115
  failed: failed.length,
1905
2116
  ops: records,
@@ -2021,6 +2232,8 @@ const directStoryboard = {
2021
2232
  ...held,
2022
2233
  ...shot,
2023
2234
  index,
2235
+ graphics: held.graphics,
2236
+ production: held.production,
2024
2237
  keyframe: held.keyframe,
2025
2238
  keyframe_versions: held.keyframe_versions,
2026
2239
  clip: held.clip,
@@ -2029,7 +2242,11 @@ const directStoryboard = {
2029
2242
  status: held.status
2030
2243
  };
2031
2244
  });
2032
- next.screenplay = screenplay;
2245
+ const previousMotionDesign = next.screenplay?.motion_design;
2246
+ next.screenplay = { ...screenplay, shots: next.shots };
2247
+ if (previousMotionDesign !== undefined) {
2248
+ next.screenplay.motion_design = previousMotionDesign;
2249
+ }
2033
2250
  next.style = screenplay.style_bible ?? next.style;
2034
2251
  next.aspectRatio = screenplay.aspect_ratio ?? next.aspectRatio;
2035
2252
  if (screenplay.genre)
@@ -2040,6 +2257,7 @@ const directStoryboard = {
2040
2257
  return {
2041
2258
  storyboard_id: current.row.id,
2042
2259
  updated_at: saved.updated_at,
2260
+ revision: saved.revision,
2043
2261
  title: screenplay.title,
2044
2262
  genre: next.genre,
2045
2263
  redirected: params["redirect"] === true,
@@ -2226,6 +2444,9 @@ const deleteStoryboard = {
2226
2444
  }
2227
2445
  };
2228
2446
  export const STORYBOARD_CAPABILITIES = [
2447
+ finishStoryboard,
2448
+ layoutStoryboard,
2449
+ previewStoryboardDesign,
2229
2450
  listStoryboards,
2230
2451
  createStoryboard,
2231
2452
  getStoryboard,
@@ -2242,5 +2463,5 @@ export const module = {
2242
2463
  module: "storyboards",
2243
2464
  exports: STORYBOARD_CAPABILITIES
2244
2465
  };
2245
- export { listStoryboards, createStoryboard, getStoryboard, renderStoryboardStills, renderStoryboardClips, reviseStoryboardClip, assembleStoryboardTimeline, editStoryboard, directStoryboard, extractScriptFromStoryboard, deleteStoryboard };
2466
+ export { finishStoryboard, layoutStoryboard, previewStoryboardDesign, listStoryboards, createStoryboard, getStoryboard, renderStoryboardStills, renderStoryboardClips, reviseStoryboardClip, assembleStoryboardTimeline, editStoryboard, directStoryboard, extractScriptFromStoryboard, deleteStoryboard };
2246
2467
  //# sourceMappingURL=storyboards.js.map