@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,15 +1,21 @@
1
1
  import { createHash, randomUUID } from "node:crypto";
2
2
  import { mkdtemp, readFile, readdir, rm } from "node:fs/promises";
3
3
  import { join } from "node:path";
4
- import { getManagedWorkspaceDir, managedWorkspaceKey, workspaceStorageKind } from "@nodetool-ai/config";
5
- import { AmbiguousGameIdError, Asset, Game, Prediction, Project, Workspace } from "@nodetool-ai/models";
6
- import { gameAssetBinding, gameDocument, gameInputFrame, shortResourceId } from "@nodetool-ai/protocol";
7
- import { autoplayNativeGame, MAX_GAME_ROUTE_TICKS, createScriptedGameSession, createTopDownRoomGame, validateGame, gameDocumentOp, GameOpError } from "@nodetool-ai/game-runtime";
4
+ import { createLogger, getManagedWorkspaceDir, managedWorkspaceKey, workspaceStorageKind } from "@nodetool-ai/config";
5
+ import { AmbiguousGameIdError, MissingGameDraftSourceError, Asset, Game, Prediction, Project, Workspace } from "@nodetool-ai/models";
6
+ import { anyGameAssetBinding as gameAssetBinding, gameAssetBinding as legacyAssetBinding, gameAssetBinding3D, anyGameDocument as gameDocument, gameInputFrame, shortResourceId } from "@nodetool-ai/protocol";
7
+ import { autoplayNativeGame, MAX_GAME_ROUTE_TICKS, createScriptedGameSession, createTopDownRoomGame, createNative3DGame, decodePreparedGameCollider3D, validateAnyGame, trackGameAuthoringEdits, anyGameDocumentOp as gameDocumentOp, GameOpError } from "@nodetool-ai/game-runtime";
8
8
  import { workspaceFromRow } from "@nodetool-ai/execution/service";
9
9
  import { assetKeyCandidates, assetObjectKey } from "@nodetool-ai/storage";
10
+ import { gameOutline3D, inputFrames3D, playtestGame3D, captureFrames3D, colliderBinding3D, stageModelGameAsset3D } from "./game3d.js";
10
11
  import { gameSpecs } from "./game.specs.js";
11
12
  import { persistOutput } from "../tools/asset-persist.js";
12
13
  import { getExampleGameBundle, installExampleGameAssets, listExampleGames } from "../game-examples.js";
14
+ import { previewGameAuthoring, applyGameAuthoring } from "../game-authoring.js";
15
+ import { gameDocumentDigest } from "../game-code-bake.js";
16
+ import { previewGameAuthoringSpec, applyGameAuthoringSpec, browseGameAssetsSpec } from "./game.specs.js";
17
+ import { browseGameAssets } from "./game-asset-browser.js";
18
+ const log = createLogger("capabilities.game");
13
19
  const MAX_PLAYTEST_TICKS = MAX_GAME_ROUTE_TICKS;
14
20
  const MAX_CAPTURE_FRAMES = 8;
15
21
  const MAX_BUILD_ASSETS = 128;
@@ -24,7 +30,9 @@ const MEDIA_EXTENSIONS = {
24
30
  "audio/ogg": "ogg",
25
31
  "audio/mpeg": "mp3",
26
32
  "font/ttf": "ttf",
27
- "font/otf": "otf"
33
+ "font/otf": "otf",
34
+ "model/gltf-binary": "glb",
35
+ "application/json": "json"
28
36
  };
29
37
  function userId(run) {
30
38
  return run.context.userId ?? null;
@@ -102,6 +110,9 @@ async function readSource(workspace, game, source, revision) {
102
110
  return draft?.document ?? null;
103
111
  }
104
112
  function outline(document) {
113
+ if (document.schemaVersion === 3) {
114
+ return gameOutline3D(document);
115
+ }
105
116
  return {
106
117
  settings: {
107
118
  schemaVersion: document.schemaVersion,
@@ -111,7 +122,8 @@ function outline(document) {
111
122
  inputActions: document.inputActions,
112
123
  collisionLayers: document.collisionLayers,
113
124
  renderEffects: document.renderEffects,
114
- hudEffectOrder: document.hudEffectOrder
125
+ hudEffectOrder: document.hudEffectOrder,
126
+ audio: document.audio
115
127
  },
116
128
  scenes: document.scenes.map((scene) => ({
117
129
  id: scene.id,
@@ -174,6 +186,8 @@ async function captureFrames(run, user, document, ticks, inputs, seed, options)
174
186
  return cancelled || wallTimeLimited;
175
187
  };
176
188
  const { captureGameFrame } = await import("@nodetool-ai/game-renderer/node");
189
+ const { GameParticles2D } = await import("@nodetool-ai/game-renderer");
190
+ const particles = new GameParticles2D(document.tickRate);
177
191
  const diagnostics = [];
178
192
  const storage = run.context.assetStorage;
179
193
  const assetCache = new Map();
@@ -211,7 +225,9 @@ async function captureFrames(run, user, document, ticks, inputs, seed, options)
211
225
  if (budgetReached()) {
212
226
  break;
213
227
  }
214
- simulatedTicks = session.step(inputs[simulatedTicks] ?? { pressed: [], justPressed: [] }).tick;
228
+ const step = session.step(inputs[simulatedTicks] ?? { pressed: [], justPressed: [] });
229
+ particles.tick(step.frame, session.takePresentationEvents());
230
+ simulatedTicks = step.tick;
215
231
  }
216
232
  if (budgetReached()) {
217
233
  break;
@@ -228,11 +244,11 @@ async function captureFrames(run, user, document, ticks, inputs, seed, options)
228
244
  const start = diagnostics.length;
229
245
  let png;
230
246
  try {
231
- png = await captureGameFrame(frame, { resolveAsset, scale, effects: document.renderEffects, hudEffectOrder: document.hudEffectOrder, backend: document.renderEffects?.length ? "webgpu" : "canvas2d", onDiagnostic: (message) => diagnostics.push(message) });
247
+ png = await captureGameFrame(frame, { resolveAsset, scale, particles, effects: document.renderEffects, hudEffectOrder: document.hudEffectOrder, backend: document.renderEffects?.length ? "webgpu" : "canvas2d", onDiagnostic: (message) => diagnostics.push(message) });
232
248
  }
233
249
  catch (error) {
234
250
  diagnostics.push(`WebGPU capture failed: ${error instanceof Error ? error.message : String(error)}`);
235
- png = await captureGameFrame(frame, { resolveAsset, scale, backend: "canvas2d", onDiagnostic: (message) => diagnostics.push(message) });
251
+ png = await captureGameFrame(frame, { resolveAsset, scale, particles, backend: "canvas2d", onDiagnostic: (message) => diagnostics.push(message) });
236
252
  }
237
253
  if (budgetReached()) {
238
254
  break;
@@ -308,8 +324,8 @@ function validateSource(source, gameId, revision) {
308
324
  const parsed = gameDocument.safeParse(source);
309
325
  if (!parsed.success)
310
326
  return { error: parsed.error.message };
311
- const result = validateGame({ ...parsed.data, id: gameId, revision });
312
- return result.document ?? { error: result.errors.join("; ") };
327
+ const result = validateAnyGame({ ...parsed.data, id: gameId, revision });
328
+ return result.valid ? result.document : { error: result.diagnostics.map((issue) => `${issue.code} ${issue.path.join(".")}: ${issue.message}`).join("; ") };
313
329
  }
314
330
  function summary(game) {
315
331
  return {
@@ -319,25 +335,52 @@ function summary(game) {
319
335
  workspace_id: game.workspace_id
320
336
  };
321
337
  }
322
- async function publish(user, game, baseRevision, source, message) {
338
+ async function publish(user, game, request) {
339
+ const baseRevision = request.base_revision;
323
340
  if (game.current_revision !== baseRevision)
324
341
  return { error: "Game was modified concurrently", current_revision: game.current_revision };
325
342
  const revision = randomUUID().replace(/-/g, "");
326
- const document = validateSource(source, game.id, revision);
327
- if ("error" in document)
328
- return document;
329
343
  const workspace = await workspaceOf(user, game);
330
344
  if (!workspace)
331
345
  return { error: "Game workspace is unavailable" };
332
346
  const draft = await Game.readDraft(user, game.id, workspace);
333
347
  if (!draft)
334
348
  return { error: "Game draft not found" };
349
+ const draftToken = request.document ? request.base_updated_at : draft.game.draft_updated_at;
350
+ if (draftToken !== draft.game.draft_updated_at) {
351
+ return { error: "Game draft was modified concurrently" };
352
+ }
353
+ let document = validateSource(request.document ?? draft.document, game.id, revision);
354
+ if ("error" in document)
355
+ return document;
356
+ if ((document.schemaVersion === 3) !== (draft.document.schemaVersion === 3)) {
357
+ return { error: "A game cannot change dimension" };
358
+ }
359
+ if (gameDocumentDigest(document.authoring) !== gameDocumentDigest(draft.document.authoring)) {
360
+ return { error: "Retained authoring metadata must be updated through construction preview and apply" };
361
+ }
362
+ document = trackGameAuthoringEdits(draft.document, document);
363
+ const checked = validateAnyGame(document);
364
+ if (!checked.valid) {
365
+ return { error: "Game publication rejected", diagnostics: checked.diagnostics };
366
+ }
335
367
  await workspace.write(revisionPath(game, revision), JSON.stringify(document), "application/json");
336
- const updated = await Game.publish(user, game.id, baseRevision, revision, draft.game.draft_updated_at, workspace, message);
337
- if (!updated)
368
+ const updated = await Game.publish(user, game.id, baseRevision, revision, draftToken, workspace, request.message);
369
+ if (!updated) {
370
+ try {
371
+ await workspace.delete(revisionPath(game, revision));
372
+ }
373
+ catch (error) {
374
+ log.error("Losing game publication revision cleanup failed", { gameId: game.id, revision, error: String(error) });
375
+ }
338
376
  return { error: "Game was modified concurrently" };
339
- await workspace.write(`${game.source_root}/drafts/${encodeURIComponent(updated.draft_updated_at)}.json`, JSON.stringify(document), "application/json");
340
- await workspace.write(`${game.source_root}/draft.json`, JSON.stringify(document), "application/json");
377
+ }
378
+ try {
379
+ await Game.pruneRevisionFiles(user, game.id, workspace);
380
+ }
381
+ catch (error) {
382
+ log.error("Game publication revision cleanup failed", { gameId: game.id, error: String(error) });
383
+ }
341
384
  return { game: summary(updated), document };
342
385
  }
343
386
  const create = {
@@ -349,14 +392,26 @@ const create = {
349
392
  if (!user || typeof projectId !== "string" || typeof name !== "string" || !name.trim()) {
350
393
  return { error: "project_id and name are required in a user session" };
351
394
  }
352
- const created = await createNativeGame(user, projectId, name.trim());
395
+ const dimension = args["dimension"];
396
+ if (dimension !== undefined && dimension !== "2d" && dimension !== "3d") {
397
+ return { error: "dimension must be 2d or 3d" };
398
+ }
399
+ if (args["template"] !== undefined && args["template"] !== "exploration" && args["template"] !== "topdown") {
400
+ return { error: "Unknown native game template" };
401
+ }
402
+ if (args["template"] !== undefined && args["template"] !== (dimension === "3d" ? "exploration" : "topdown")) {
403
+ return { error: "Template does not match the requested dimension" };
404
+ }
405
+ const created = await createNativeGame(user, projectId, name.trim(), undefined, dimension ?? "2d");
353
406
  return "error" in created
354
407
  ? created
355
408
  : { game: summary(created.game), document: created.document };
356
409
  }
357
410
  };
358
- /** Shared by explicit game creation and the guided asset workflow builder. */
359
- export async function createNativeGame(user, projectId, name, source) {
411
+ export async function createNativeGame(user, projectId, name, source, dimension = "2d") {
412
+ if (source?.authoring) {
413
+ return { error: "Attach retained construction through preview and apply after creating the game" };
414
+ }
360
415
  const project = await Project.findOwned(user, projectId);
361
416
  if (!project)
362
417
  return { error: "Project not found" };
@@ -366,9 +421,12 @@ export async function createNativeGame(user, projectId, name, source) {
366
421
  return { error: "Project workspace is unavailable" };
367
422
  const id = randomUUID().replace(/-/g, "");
368
423
  const revision = randomUUID().replace(/-/g, "");
369
- const document = validateSource(source ?? { ...createTopDownRoomGame(id), schemaVersion: 2 }, id, revision);
424
+ const document = validateSource(source ?? (dimension === "3d" ? createNative3DGame(id) : { ...createTopDownRoomGame(id), schemaVersion: 4, engineVersion: "3" }), id, revision);
370
425
  if ("error" in document)
371
426
  return document;
427
+ if (source && ((document.schemaVersion === 3) !== (dimension === "3d"))) {
428
+ return { error: "Supplied document does not match the requested dimension" };
429
+ }
372
430
  const game = new Game({
373
431
  id,
374
432
  user_id: user,
@@ -395,13 +453,18 @@ const get = {
395
453
  const id = args["game_id"];
396
454
  if (!user || typeof id !== "string")
397
455
  return { error: "game_id is required in a user session" };
398
- const game = await ownedGame(user, id);
456
+ let game = await ownedGame(user, id);
399
457
  if (!game)
400
458
  return { error: "Game not found" };
401
459
  const workspace = await workspaceOf(user, game);
402
460
  if (!workspace)
403
461
  return { error: "Game workspace is unavailable" };
404
- const document = await readSource(workspace, game, args["source"], args["revision"]);
462
+ const readsDraft = (args["source"] === undefined || args["source"] === "draft") && args["revision"] === undefined;
463
+ const draft = readsDraft ? await Game.readDraft(user, game.id, workspace) : null;
464
+ const document = readsDraft ? draft?.document : await readSource(workspace, game, args["source"], args["revision"]);
465
+ if (draft) {
466
+ game = draft.game;
467
+ }
405
468
  if (!document)
406
469
  return { error: "Game source not found" };
407
470
  const view = args["view"] ?? "outline";
@@ -430,11 +493,19 @@ const save = {
430
493
  const game = await ownedGame(user, id);
431
494
  if (!game)
432
495
  return { error: "Game not found" };
433
- const workspace = await workspaceOf(user, game);
434
- if (!workspace)
435
- return { error: "Game workspace is unavailable" };
436
- const document = args["document"] ?? await readSource(workspace, game, "draft", undefined);
437
- return document ? publish(user, game, base, document, typeof args["message"] === "string" ? args["message"] : undefined) : { error: "Game draft not found" };
496
+ const request = { game_id: id, base_revision: base, message: typeof args["message"] === "string" ? args["message"] : undefined };
497
+ if (args["document"] !== undefined) {
498
+ const token = args["base_updated_at"];
499
+ if (typeof token !== "string" || !token) {
500
+ return { error: "base_updated_at is required with an explicit document" };
501
+ }
502
+ const parsed = gameDocument.safeParse(args["document"]);
503
+ if (!parsed.success) {
504
+ return { error: parsed.error.message };
505
+ }
506
+ return publish(user, game, { ...request, document: parsed.data, base_updated_at: token });
507
+ }
508
+ return publish(user, game, request);
438
509
  }
439
510
  };
440
511
  const edit = {
@@ -494,6 +565,9 @@ const install = {
494
565
  if (parsed.data.mediaKind === "font" && !parsed.data.fontFormat) {
495
566
  return { error: "Font binding needs a TrueType or OpenType format" };
496
567
  }
568
+ if (parsed.data.mediaKind === "hdri") {
569
+ return { error: "HDRI candidates cannot be installed until HDRI preparation verifies their bytes and dimensions" };
570
+ }
497
571
  const workspace = await workspaceOf(user, game);
498
572
  if (!workspace)
499
573
  return { error: "Game workspace is unavailable" };
@@ -510,11 +584,13 @@ const install = {
510
584
  return { error: "Candidate workspace is unavailable" };
511
585
  candidateWorkspace = resolved;
512
586
  }
513
- const formats = parsed.data.mediaKind === "audio"
514
- ? [["wav", "audio/wav"], ["mp3", "audio/mpeg"], ["ogg", "audio/ogg"]]
515
- : parsed.data.mediaKind === "font"
516
- ? [[parsed.data.fontFormat, `font/${parsed.data.fontFormat}`]]
517
- : [["png", "image/png"], ["jpg", "image/jpeg"], ["webp", "image/webp"]];
587
+ const formats = parsed.data.mediaKind === "model" ? [["glb", "model/gltf-binary"]]
588
+ : parsed.data.mediaKind === "collider" ? [["json", "application/json"]]
589
+ : parsed.data.mediaKind === "audio"
590
+ ? [["wav", "audio/wav"], ["mp3", "audio/mpeg"], ["ogg", "audio/ogg"]]
591
+ : parsed.data.mediaKind === "font"
592
+ ? [[parsed.data.fontFormat, `font/${parsed.data.fontFormat}`]]
593
+ : [["png", "image/png"], ["jpg", "image/jpeg"], ["webp", "image/webp"]];
518
594
  let candidate = null;
519
595
  for (const [extension, contentType] of formats) {
520
596
  if (!extension)
@@ -536,6 +612,45 @@ const install = {
536
612
  if (!draft)
537
613
  return { error: "Game draft is missing" };
538
614
  const expectedUpdatedAt = typeof args["base_updated_at"] === "string" ? args["base_updated_at"] : draft.game.draft_updated_at;
615
+ let binding = parsed.data;
616
+ try {
617
+ if (binding.mediaKind === "model") {
618
+ const { prepareGameModelBinding3D } = await import("@nodetool-ai/game-renderer/preparation3d");
619
+ const prepared = await prepareGameModelBinding3D(bytes, { assetId: binding.assetId, expectedDigest: binding.digest, signal: run.context.signal });
620
+ if (!prepared.ok) {
621
+ return { error: "Model preparation failed", diagnostics: prepared.diagnostics };
622
+ }
623
+ const sourceAsset = binding.sourceAssetId ? await Asset.find(user, binding.sourceAssetId) : null;
624
+ if (binding.sourceAssetId && !sourceAsset) {
625
+ return { error: "Model source asset is not owned" };
626
+ }
627
+ const canonical = { ...prepared.binding, required: binding.required };
628
+ if (binding.provenance) {
629
+ canonical.provenance = binding.provenance;
630
+ }
631
+ if (binding.importSettings) {
632
+ canonical.importSettings = binding.importSettings;
633
+ }
634
+ if (binding.sourceDigest) {
635
+ canonical.sourceDigest = binding.sourceDigest;
636
+ }
637
+ if (sourceAsset) {
638
+ canonical.sourceAssetId = sourceAsset.id;
639
+ }
640
+ binding = canonical;
641
+ }
642
+ else if (binding.mediaKind === "collider") {
643
+ binding = colliderBinding3D(bytes, binding);
644
+ await decodePreparedGameCollider3D(bytes, gameAssetBinding3D.options[1].parse(binding));
645
+ }
646
+ }
647
+ catch (error) {
648
+ return { error: error instanceof Error ? error.message : String(error) };
649
+ }
650
+ const targetBinding = draft.document.schemaVersion === 3 ? gameAssetBinding3D.safeParse(binding) : legacyAssetBinding.safeParse(binding);
651
+ if (!targetBinding.success) {
652
+ return { error: "Asset binding does not match the game dimension" };
653
+ }
539
654
  const storage = run.context.assetStorage;
540
655
  if (!storage)
541
656
  return { error: "Asset storage is unavailable" };
@@ -558,7 +673,8 @@ const install = {
558
673
  uri = await storage.store(key, bytes, contentType);
559
674
  let result;
560
675
  try {
561
- const updated = await Game.updateDraft(user, game.id, expectedUpdatedAt, [{ op: "bind_asset", slot, binding: { ...parsed.data, assetId: installed.id } }], workspace, { actor: "agent", threadId: run.context.threadId ?? undefined, messageId: run.context.get?.("chat_message_id") ?? undefined });
676
+ const op = gameDocumentOp.parse({ op: "bind_asset", slot, binding: { ...targetBinding.data, assetId: installed.id } });
677
+ const updated = await Game.updateDraft(user, game.id, expectedUpdatedAt, [op], workspace, { actor: "agent", threadId: run.context.threadId ?? undefined, messageId: run.context.get?.("chat_message_id") ?? undefined });
562
678
  result = updated ? { game: summary(updated.game), draft_updated_at: updated.game.draft_updated_at, document: updated.document } : { error: "Game draft was modified concurrently" };
563
679
  }
564
680
  catch (error) {
@@ -597,6 +713,15 @@ const playtest = {
597
713
  const document = await readSource(workspace, game, args["source"], args["revision"]);
598
714
  if (!document)
599
715
  return { error: "Game source not found" };
716
+ if (document.schemaVersion === 3) {
717
+ try {
718
+ return await playtestGame3D(run, user, document, args);
719
+ }
720
+ catch (error) {
721
+ run.context.signal?.throwIfAborted();
722
+ return { error: error instanceof Error ? error.message : String(error), code: "game3d_preparation_failed" };
723
+ }
724
+ }
600
725
  const captures = captureTicks(args["capture_ticks"], []);
601
726
  if ("error" in captures)
602
727
  return captures;
@@ -732,6 +857,20 @@ const capture = {
732
857
  const ticks = captureTicks(args["ticks"], [0]);
733
858
  if ("error" in ticks)
734
859
  return ticks;
860
+ if (document.schemaVersion === 3) {
861
+ const inputs = inputFrames3D(args["inputs"], Math.max(0, ...ticks));
862
+ if ("error" in inputs) {
863
+ return inputs;
864
+ }
865
+ const seed = typeof args["seed"] === "number" && Number.isSafeInteger(args["seed"]) ? args["seed"] : 1;
866
+ try {
867
+ return await captureFrames3D(run, user, document, ticks, inputs, seed, args);
868
+ }
869
+ catch (error) {
870
+ run.context.signal?.throwIfAborted();
871
+ return { error: error instanceof Error ? error.message : String(error), code: "game3d_capture_failed" };
872
+ }
873
+ }
735
874
  const inputs = inputFrames(args["inputs"], Math.max(0, ...ticks));
736
875
  if ("error" in inputs)
737
876
  return inputs;
@@ -754,7 +893,7 @@ const generateAsset = {
754
893
  const kind = args["kind"];
755
894
  const prompt = args["prompt"];
756
895
  const inputFile = args["input_file"];
757
- if (!user || typeof id !== "string" || typeof slot !== "string" || !slot || !["image", "audio", "music", "sfx", "font"].includes(String(kind))) {
896
+ if (!user || typeof id !== "string" || typeof slot !== "string" || !slot || !["image", "audio", "music", "sfx", "font", "model", "collider"].includes(String(kind))) {
758
897
  return { error: "game_id, slot, and kind are required" };
759
898
  }
760
899
  if (inputFile !== undefined && (typeof inputFile !== "string" || !inputFile.trim())) {
@@ -772,6 +911,21 @@ const generateAsset = {
772
911
  if (!draft) {
773
912
  return { error: "Game draft not found" };
774
913
  }
914
+ if (kind === "model" || kind === "collider") {
915
+ if (draft.document.schemaVersion !== 3) {
916
+ return { error: "Model and collider assets require a 3D game" };
917
+ }
918
+ try {
919
+ return await stageModelGameAsset3D(run, game, workspace, draft.document, args);
920
+ }
921
+ catch (error) {
922
+ run.context.signal?.throwIfAborted();
923
+ return { error: error instanceof Error ? error.message : String(error) };
924
+ }
925
+ }
926
+ if (draft.document.schemaVersion === 3 && kind === "image") {
927
+ return { error: "3D games use model assets with embedded textures" };
928
+ }
775
929
  const reference = typeof args["reference_slot"] === "string" ? draft.document.assets[args["reference_slot"]] : undefined;
776
930
  if (args["reference_slot"] !== undefined && !reference) {
777
931
  return { error: "reference_slot is not bound" };
@@ -791,7 +945,7 @@ const generateAsset = {
791
945
  let provider = args["provider"];
792
946
  let model = args["model"];
793
947
  let generated = {};
794
- let sourceBytes = null;
948
+ let sourceBytes;
795
949
  const makeLut = settings?.success && settings.data.lut !== undefined;
796
950
  if (makeLut && (inputFile !== undefined || reference || args["generation_id"] !== undefined)) {
797
951
  return { error: "LUT preparation creates a color cube directly and cannot use input_file, reference_slot or generation_id" };
@@ -908,7 +1062,7 @@ const generateAsset = {
908
1062
  let height = 1;
909
1063
  const previous = draft.document.assets[slot];
910
1064
  const binding = {
911
- width, height, pivot: previous?.pivot ?? { x: 0.5, y: 0.5 }, sampling: previous?.sampling ?? "nearest"
1065
+ width, height, pivot: previous && "pivot" in previous ? previous.pivot : { x: 0.5, y: 0.5 }, sampling: previous && "sampling" in previous ? previous.sampling : "nearest"
912
1066
  };
913
1067
  let frames;
914
1068
  let tiles;
@@ -940,7 +1094,7 @@ const generateAsset = {
940
1094
  if (prepared.baseline !== undefined && frames?.[0]) {
941
1095
  binding.pivot = { x: 0.5, y: (prepared.baseline + 1) / frames[0].height };
942
1096
  }
943
- if (draft.document.schemaVersion === 2) {
1097
+ if (draft.document.schemaVersion !== 1) {
944
1098
  binding.preparation = imagePreparationMetadata(settings.data);
945
1099
  binding.originalDimensions = { width: prepared.originalWidth, height: prepared.originalHeight };
946
1100
  if (prepared.trim) {
@@ -978,10 +1132,41 @@ const generateAsset = {
978
1132
  binding.digest = digest;
979
1133
  binding.width = width;
980
1134
  binding.height = height;
981
- if (draft.document.schemaVersion === 2) {
1135
+ if (draft.document.schemaVersion !== 1 && draft.document.schemaVersion !== 3) {
982
1136
  binding.provenance = typeof inputFile === "string" ? `import:${inputFile}`
983
1137
  : makeLut ? "generated:color-cube" : kind === "sfx" ? `node:${args["node_type"]}` : `${provider}:${model}:${generated.generation_id ?? ""}`;
984
1138
  }
1139
+ if (draft.document.schemaVersion === 3) {
1140
+ delete binding.width;
1141
+ delete binding.height;
1142
+ delete binding.pivot;
1143
+ delete binding.sampling;
1144
+ const parsedBinding = gameAssetBinding3D.safeParse(binding);
1145
+ if (!parsedBinding.success) {
1146
+ return { error: "Invalid 3D asset binding", diagnostics: parsedBinding.error.issues };
1147
+ }
1148
+ return { game_id: shortResourceId(game.id), slot, binding: parsedBinding.data, candidate_workspace_id: game.workspace_id,
1149
+ draft_updated_at: draft.game.draft_updated_at, installed: false, next: "Call install_native_game_asset with this binding to install the candidate." };
1150
+ }
1151
+ if (args["install"] === false) {
1152
+ const parsedBinding = legacyAssetBinding.safeParse(binding);
1153
+ if (!parsedBinding.success) {
1154
+ return { error: "Invalid asset binding", diagnostics: parsedBinding.error.issues };
1155
+ }
1156
+ const staged = { game_id: shortResourceId(game.id), slot, binding: parsedBinding.data, candidate_workspace_id: game.workspace_id,
1157
+ draft_updated_at: draft.game.draft_updated_at, installed: false, generation_id: generated.generation_id,
1158
+ next: "Call install_native_game_asset with this binding to install the candidate." };
1159
+ if (frames) {
1160
+ staged.frames = frames;
1161
+ }
1162
+ if (tiles) {
1163
+ staged.tiles = tiles;
1164
+ }
1165
+ if (lutSize) {
1166
+ staged.lut_size = lutSize;
1167
+ }
1168
+ return staged;
1169
+ }
985
1170
  const installed = await install.impl(run, { game_id: game.id, slot, binding, base_updated_at: draft.game.draft_updated_at });
986
1171
  if (typeof installed !== "object" || installed === null) {
987
1172
  return { generation_id: generated.generation_id, result: installed };
@@ -1008,133 +1193,177 @@ const generateAsset = {
1008
1193
  return { generation_id: generated.generation_id, ...installed, ...extras };
1009
1194
  }
1010
1195
  };
1011
- const buildGame = {
1012
- spec: gameSpecs[5],
1013
- impl: async (run, args) => {
1014
- const user = userId(run);
1015
- const id = args["game_id"];
1016
- if (!user || typeof id !== "string")
1017
- return { error: "game_id is required in a user session" };
1018
- const game = await ownedGame(user, id);
1019
- if (!game)
1020
- return { error: "Game not found" };
1021
- const workspace = await workspaceOf(user, game);
1022
- if (!workspace)
1023
- return { error: "Game workspace is unavailable" };
1024
- const revision = typeof args["revision"] === "string" ? args["revision"] : game.current_revision;
1025
- const document = await readDocument(workspace, game, revision);
1026
- if (!document)
1027
- return { error: "Game revision not found" };
1028
- if (Object.keys(document.assets).length > MAX_BUILD_ASSETS) {
1029
- return { error: `A standalone build supports at most ${MAX_BUILD_ASSETS} assets` };
1196
+ const BUILD_CONTENT_TYPES = {
1197
+ js: "text/javascript", css: "text/css", json: "application/json", html: "text/html", png: "image/png", jpg: "image/jpeg",
1198
+ webp: "image/webp", wav: "audio/wav", ogg: "audio/ogg", mp3: "audio/mpeg", ttf: "font/ttf", otf: "font/otf",
1199
+ glb: "model/gltf-binary", wasm: "application/wasm", md: "text/markdown", toml: "text/plain", rs: "text/plain",
1200
+ ico: "image/vnd.microsoft.icon", icns: "image/icns"
1201
+ };
1202
+ /**
1203
+ * Builds an owned, published game revision into its project workspace: a static web player under
1204
+ * `game-builds/<game-id>/<revision>`, or a Tauri desktop project under `game-builds/<game-id>/<revision>-tauri-<settings>`.
1205
+ * The capability and the editor's export download share this path.
1206
+ */
1207
+ export async function buildOwnedNativeGame(request) {
1208
+ const user = request.userId;
1209
+ const target = request.target ?? "web";
1210
+ const game = await ownedGame(user, request.gameId);
1211
+ if (!game)
1212
+ return { error: "Game not found" };
1213
+ const workspace = await workspaceOf(user, game);
1214
+ if (!workspace)
1215
+ return { error: "Game workspace is unavailable" };
1216
+ const revision = request.revision ?? game.current_revision;
1217
+ const document = await readDocument(workspace, game, revision);
1218
+ if (!document)
1219
+ return { error: "Game revision not found" };
1220
+ if (Object.keys(document.assets).length > MAX_BUILD_ASSETS) {
1221
+ return { error: `A standalone build supports at most ${MAX_BUILD_ASSETS} assets` };
1222
+ }
1223
+ const expectedDigests = new Map();
1224
+ for (const binding of Object.values(document.assets)) {
1225
+ if (binding.assetId.startsWith("builtin:"))
1226
+ continue;
1227
+ const digests = expectedDigests.get(binding.assetId) ?? new Set();
1228
+ digests.add(binding.digest);
1229
+ expectedDigests.set(binding.assetId, digests);
1230
+ }
1231
+ if ([...expectedDigests.values()].some((digests) => digests.size !== 1)) {
1232
+ return { error: "One source asset has conflicting digests in this revision" };
1233
+ }
1234
+ let buildPath = `game-builds/${game.id}/${revision}`;
1235
+ let entryPath = `${buildPath}/index.html`;
1236
+ let tauriApp;
1237
+ let metadata;
1238
+ if (target === "tauri") {
1239
+ tauriApp = { name: game.name };
1240
+ const { tauriAppMetadata } = await import("@nodetool-ai/game-renderer/build-tauri");
1241
+ try {
1242
+ metadata = tauriAppMetadata(document, tauriApp);
1030
1243
  }
1031
- const expectedDigests = new Map();
1032
- for (const binding of Object.values(document.assets)) {
1033
- if (binding.assetId.startsWith("builtin:"))
1034
- continue;
1035
- const digests = expectedDigests.get(binding.assetId) ?? new Set();
1036
- digests.add(binding.digest);
1037
- expectedDigests.set(binding.assetId, digests);
1244
+ catch (error) {
1245
+ return { error: error instanceof Error ? error.message : String(error) };
1038
1246
  }
1039
- if ([...expectedDigests.values()].some((digests) => digests.size !== 1)) {
1040
- return { error: "One source asset has conflicting digests in this revision" };
1247
+ // The app name comes from the game row, which can change without a new revision.
1248
+ const settings = createHash("sha256").update(JSON.stringify(metadata)).digest("hex").slice(0, 12);
1249
+ buildPath = `game-builds/${game.id}/${revision}-tauri-${settings}`;
1250
+ entryPath = `${buildPath}/src-tauri/tauri.conf.json`;
1251
+ }
1252
+ const done = { game_id: game.id, revision, target, build_path: buildPath, entry_path: entryPath, workspace, app: metadata ?? null };
1253
+ if (await workspace.exists(entryPath)) {
1254
+ return { ...done, cached: true };
1255
+ }
1256
+ const storage = request.storage;
1257
+ const cache = new Map();
1258
+ let totalAssetBytes = 0;
1259
+ const resolveAsset = async (assetId) => {
1260
+ const cached = cache.get(assetId);
1261
+ if (cached)
1262
+ return cached;
1263
+ if (!/^[a-f0-9]{32}$/.test(assetId))
1264
+ return null;
1265
+ const asset = await Asset.find(user, assetId);
1266
+ if (!asset || !storage)
1267
+ return null;
1268
+ const extension = MEDIA_EXTENSIONS[asset.content_type];
1269
+ if (!extension || (asset.size !== null && asset.size > MAX_BUILD_ASSET_BYTES))
1270
+ return null;
1271
+ const keys = assetKeyCandidates(user, `${asset.id}.${extension}`);
1272
+ let bytes = null;
1273
+ for (const key of keys) {
1274
+ bytes = await storage.retrieve(storage.uriForKey(key));
1275
+ if (bytes)
1276
+ break;
1041
1277
  }
1042
- const buildPath = `game-builds/${game.id}/${revision}`;
1043
- const indexPath = `${buildPath}/index.html`;
1044
- if (await workspace.exists(indexPath)) {
1045
- return { game_id: game.id, revision, build_path: buildPath, entry_path: indexPath, cached: true };
1278
+ if (!bytes || bytes.byteLength > MAX_BUILD_ASSET_BYTES)
1279
+ return null;
1280
+ const digest = createHash("sha256").update(bytes).digest("hex");
1281
+ if (!expectedDigests.get(assetId)?.has(digest)) {
1282
+ throw new Error(`Asset digest changed for ${assetId}`);
1046
1283
  }
1047
- const storage = run.context.assetStorage;
1048
- const cache = new Map();
1049
- let totalAssetBytes = 0;
1050
- const resolveAsset = async (assetId) => {
1051
- const cached = cache.get(assetId);
1052
- if (cached)
1053
- return cached;
1054
- if (!/^[a-f0-9]{32}$/.test(assetId))
1055
- return null;
1056
- const asset = await Asset.find(user, assetId);
1057
- if (!asset || !storage)
1058
- return null;
1059
- const extension = MEDIA_EXTENSIONS[asset.content_type];
1060
- if (!extension || (asset.size !== null && asset.size > MAX_BUILD_ASSET_BYTES))
1061
- return null;
1062
- const keys = assetKeyCandidates(user, `${asset.id}.${extension}`);
1063
- let bytes = null;
1064
- for (const key of keys) {
1065
- bytes = await storage.retrieve(storage.uriForKey(key));
1066
- if (bytes)
1067
- break;
1068
- }
1069
- if (!bytes || bytes.byteLength > MAX_BUILD_ASSET_BYTES)
1070
- return null;
1071
- const digest = createHash("sha256").update(bytes).digest("hex");
1072
- if (!expectedDigests.get(assetId)?.has(digest)) {
1073
- throw new Error(`Asset digest changed for ${assetId}`);
1074
- }
1075
- totalAssetBytes += bytes.byteLength;
1076
- if (totalAssetBytes > MAX_BUILD_BYTES) {
1077
- throw new Error(`A standalone build supports at most ${MAX_BUILD_BYTES} asset bytes`);
1078
- }
1079
- const resolved = { bytes, mimeType: asset.content_type };
1080
- cache.set(assetId, resolved);
1081
- return resolved;
1082
- };
1083
- const scratch = await workspace.scratchDir();
1084
- const staging = await mkdtemp(join(scratch, ".native-game-build-"));
1085
- try {
1284
+ totalAssetBytes += bytes.byteLength;
1285
+ if (totalAssetBytes > MAX_BUILD_BYTES) {
1286
+ throw new Error(`A standalone build supports at most ${MAX_BUILD_BYTES} asset bytes`);
1287
+ }
1288
+ const resolved = { bytes, mimeType: asset.content_type };
1289
+ cache.set(assetId, resolved);
1290
+ return resolved;
1291
+ };
1292
+ const scratch = await workspace.scratchDir();
1293
+ const staging = await mkdtemp(join(scratch, ".native-game-build-"));
1294
+ try {
1295
+ const output = join(staging, "player");
1296
+ if (tauriApp) {
1297
+ const { buildTauriGameProject } = await import("@nodetool-ai/game-renderer/build-tauri");
1298
+ await buildTauriGameProject({ document, outputDir: output, resolveAsset, app: tauriApp, signal: request.signal });
1299
+ }
1300
+ else if (document.schemaVersion === 3) {
1301
+ const { buildStandaloneGame3D } = await import("@nodetool-ai/game-renderer/build3d");
1302
+ await buildStandaloneGame3D({ document, outputDir: output, resolveAsset, signal: request.signal });
1303
+ }
1304
+ else {
1086
1305
  const { buildStandaloneGame } = await import("@nodetool-ai/game-renderer/build");
1087
- await buildStandaloneGame({ document, outputDir: join(staging, "player"), resolveAsset });
1088
- const files = [];
1089
- const pending = [""];
1090
- let totalBytes = 0;
1091
- while (pending.length > 0) {
1092
- const directory = pending.pop() ?? "";
1093
- for (const entry of await readdir(join(staging, "player", directory), { withFileTypes: true })) {
1094
- const path = directory ? `${directory}/${entry.name}` : entry.name;
1095
- if (entry.isDirectory()) {
1096
- pending.push(path);
1097
- }
1098
- else if (entry.isFile()) {
1099
- const bytes = await readFile(join(staging, "player", path));
1100
- totalBytes += bytes.byteLength;
1101
- if (files.length >= MAX_BUILD_FILES || totalBytes > MAX_BUILD_BYTES) {
1102
- throw new Error("Standalone build exceeds file or byte limits");
1103
- }
1104
- files.push({ path, bytes });
1306
+ await buildStandaloneGame({ document, outputDir: output, resolveAsset });
1307
+ }
1308
+ const files = [];
1309
+ const pending = [""];
1310
+ let totalBytes = 0;
1311
+ while (pending.length > 0) {
1312
+ const directory = pending.pop() ?? "";
1313
+ for (const entry of await readdir(join(output, directory), { withFileTypes: true })) {
1314
+ const path = directory ? `${directory}/${entry.name}` : entry.name;
1315
+ if (entry.isDirectory()) {
1316
+ pending.push(path);
1317
+ }
1318
+ else if (entry.isFile()) {
1319
+ const bytes = await readFile(join(output, path));
1320
+ totalBytes += bytes.byteLength;
1321
+ if (files.length >= MAX_BUILD_FILES || totalBytes > MAX_BUILD_BYTES) {
1322
+ throw new Error("Standalone build exceeds file or byte limits");
1105
1323
  }
1324
+ files.push({ path, bytes });
1106
1325
  }
1107
1326
  }
1108
- if (!files.some((file) => file.path === "index.html")) {
1109
- throw new Error("Standalone player entry is missing");
1110
- }
1111
- for (const file of files.filter((item) => item.path !== "index.html")) {
1112
- const contentType = file.path.endsWith(".js") ? "text/javascript"
1113
- : file.path.endsWith(".css") ? "text/css"
1114
- : file.path.endsWith(".json") ? "application/json"
1115
- : file.path.endsWith(".png") ? "image/png"
1116
- : file.path.endsWith(".jpg") ? "image/jpeg"
1117
- : file.path.endsWith(".webp") ? "image/webp"
1118
- : file.path.endsWith(".wav") ? "audio/wav"
1119
- : file.path.endsWith(".ogg") ? "audio/ogg"
1120
- : file.path.endsWith(".mp3") ? "audio/mpeg"
1121
- : file.path.endsWith(".ttf") ? "font/ttf"
1122
- : file.path.endsWith(".otf") ? "font/otf"
1123
- : "application/octet-stream";
1124
- await workspace.write(`${buildPath}/${file.path}`, file.bytes, contentType);
1125
- }
1126
- const index = files.find((file) => file.path === "index.html");
1127
- if (!index)
1128
- throw new Error("Standalone player entry is missing");
1129
- await workspace.write(indexPath, index.bytes, "text/html");
1130
- return { game_id: game.id, revision, build_path: buildPath, entry_path: indexPath, cached: false };
1131
1327
  }
1132
- catch (error) {
1133
- return { error: error instanceof Error ? error.message : String(error) };
1134
- }
1135
- finally {
1136
- await rm(staging, { recursive: true, force: true });
1328
+ const entryFile = entryPath.slice(buildPath.length + 1);
1329
+ const entry = files.find((file) => file.path === entryFile);
1330
+ if (!entry)
1331
+ throw new Error("Standalone build entry is missing");
1332
+ const contentType = (path) => BUILD_CONTENT_TYPES[path.slice(path.lastIndexOf(".") + 1)] ?? "application/octet-stream";
1333
+ // The entry file is written last, so its presence marks a complete build for the cache check above.
1334
+ for (const file of files.filter((item) => item !== entry)) {
1335
+ await workspace.write(`${buildPath}/${file.path}`, file.bytes, contentType(file.path));
1137
1336
  }
1337
+ await workspace.write(entryPath, entry.bytes, contentType(entry.path));
1338
+ return { ...done, cached: false };
1339
+ }
1340
+ catch (error) {
1341
+ return { error: error instanceof Error ? error.message : String(error) };
1342
+ }
1343
+ finally {
1344
+ await rm(staging, { recursive: true, force: true });
1345
+ }
1346
+ }
1347
+ const buildGame = {
1348
+ spec: gameSpecs[5],
1349
+ impl: async (run, args) => {
1350
+ const user = userId(run);
1351
+ const id = args["game_id"];
1352
+ if (!user || typeof id !== "string")
1353
+ return { error: "game_id is required in a user session" };
1354
+ const target = args["target"] ?? "web";
1355
+ if (target !== "web" && target !== "tauri")
1356
+ return { error: "target must be web or tauri" };
1357
+ const revision = args["revision"];
1358
+ const result = await buildOwnedNativeGame({ userId: user, gameId: id, revision: typeof revision === "string" ? revision : undefined,
1359
+ target, storage: run.context.assetStorage, signal: run.context.signal });
1360
+ if ("error" in result)
1361
+ return { error: result.error };
1362
+ const report = { game_id: result.game_id, revision: result.revision, target: result.target, build_path: result.build_path,
1363
+ entry_path: result.entry_path, cached: result.cached };
1364
+ return target === "tauri"
1365
+ ? { ...report, next: "The project builds desktop installers with `npm install && npm run build` in a checkout that has Rust and the Tauri prerequisites." }
1366
+ : report;
1138
1367
  }
1139
1368
  };
1140
1369
  const listExamples = {
@@ -1193,7 +1422,7 @@ const installExample = {
1193
1422
  return { error: "Example game not found" };
1194
1423
  const installed = await installExampleGameAssets(user, projectId, {}, slug, storage);
1195
1424
  try {
1196
- const created = await createNativeGame(user, projectId, typeof name === "string" ? name.trim() : installed.bundle.name, installed.document);
1425
+ const created = await createNativeGame(user, projectId, typeof name === "string" ? name.trim() : installed.bundle.name, installed.document, installed.document.schemaVersion === 3 ? "3d" : "2d");
1197
1426
  if ("error" in created) {
1198
1427
  await installed.rollback();
1199
1428
  return created;
@@ -1222,6 +1451,9 @@ const autoplay = {
1222
1451
  const document = await readSource(workspace, game, args["source"], args["revision"]);
1223
1452
  if (!document)
1224
1453
  return { error: "Game source not found" };
1454
+ if (document.schemaVersion === 3) {
1455
+ return { status: "unsupported", dimension: "3d", code: "autoplay_3d_unsupported", message: "Use playtest_native_game with a recorded 3D route" };
1456
+ }
1225
1457
  const targetPrefix = args["target_prefix"];
1226
1458
  const playerId = args["player_id"];
1227
1459
  const win = args["win"];
@@ -1255,8 +1487,24 @@ const autoplay = {
1255
1487
  return { game_id: shortResourceId(game.id), revision: document.revision, ...route, win_tick: winTick, reached_targets: reachedTargets, level_stats: levelStats, state: snapshot };
1256
1488
  }
1257
1489
  };
1490
+ function withDraftRecovery(capability) {
1491
+ return { ...capability, impl: async (run, args) => {
1492
+ try {
1493
+ return await capability.impl(run, args);
1494
+ }
1495
+ catch (error) {
1496
+ if (error instanceof MissingGameDraftSourceError) {
1497
+ return { error: error.message, code: "game_draft_source_unavailable" };
1498
+ }
1499
+ throw error;
1500
+ }
1501
+ } };
1502
+ }
1258
1503
  export const module = {
1259
1504
  module: "game",
1260
- exports: [create, get, save, install, playtest, buildGame, edit, capture, generateAsset, listExamples, getExample, installExample, autoplay]
1505
+ exports: [create, get, save, install, playtest, buildGame, edit, capture, generateAsset, listExamples, getExample, installExample, autoplay,
1506
+ { spec: previewGameAuthoringSpec, impl: previewGameAuthoring },
1507
+ { spec: applyGameAuthoringSpec, impl: applyGameAuthoring },
1508
+ { spec: browseGameAssetsSpec, impl: browseGameAssets }].map(withDraftRecovery)
1261
1509
  };
1262
1510
  //# sourceMappingURL=game.js.map