@volter/editor-core 0.5.57

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 (719) hide show
  1. package/BUNDLED_NOTICES +1527 -0
  2. package/LICENSE +686 -0
  3. package/LICENSE-APACHE +202 -0
  4. package/NOTICE +18 -0
  5. package/README.md +24 -0
  6. package/dist/build/chunk-JS4D4XZ3.js +175 -0
  7. package/dist/build/chunk-JS4D4XZ3.js.map +7 -0
  8. package/dist/build/vite-plugin-product-contributions.js +100 -0
  9. package/dist/build/vite-plugin-product-contributions.js.map +7 -0
  10. package/dist/build/vite-plugin-shared-react.js +25 -0
  11. package/dist/build/vite-plugin-shared-react.js.map +7 -0
  12. package/dist/build/vite-plugin-shared-three.js +86 -0
  13. package/dist/build/vite-plugin-shared-three.js.map +7 -0
  14. package/dist/server/chunk-KMJC7AGO.js +98 -0
  15. package/dist/server/chunk-KMJC7AGO.js.map +7 -0
  16. package/dist/server/chunk-PSILUMGS.js +46 -0
  17. package/dist/server/chunk-PSILUMGS.js.map +7 -0
  18. package/dist/server/frame-proxy.js +255 -0
  19. package/dist/server/frame-proxy.js.map +7 -0
  20. package/dist/server/open-browser.js +53 -0
  21. package/dist/server/open-browser.js.map +7 -0
  22. package/dist/server/process-shutdown.js +127 -0
  23. package/dist/server/process-shutdown.js.map +7 -0
  24. package/dist/server/session-registry.js +141 -0
  25. package/dist/server/session-registry.js.map +7 -0
  26. package/dist/server/spawn-opener.js +11 -0
  27. package/dist/server/spawn-opener.js.map +7 -0
  28. package/dist/server/worktree-identity.js +11 -0
  29. package/dist/server/worktree-identity.js.map +7 -0
  30. package/dist-server/packaged.mjs +88816 -0
  31. package/package.json +118 -0
  32. package/scripts/build-plugins.mjs +14 -0
  33. package/scripts/build-server.mjs +26 -0
  34. package/scripts/build-session.mjs +9 -0
  35. package/server/account-credentials.ts +60 -0
  36. package/server/account-service.ts +1434 -0
  37. package/server/adapter-region-includes.ts +47 -0
  38. package/server/asset-catalog-v2.ts +175 -0
  39. package/server/asset-history-snapshots.ts +196 -0
  40. package/server/asset-ledger-store.ts +195 -0
  41. package/server/asset-library-routes.ts +1595 -0
  42. package/server/blender-wasm-artifact.ts +430 -0
  43. package/server/boot-timings.ts +106 -0
  44. package/server/canonical-path.ts +50 -0
  45. package/server/checkout-workspace-preflight.ts +349 -0
  46. package/server/cloud-asset-catalog.ts +158 -0
  47. package/server/coding-inference-launch.ts +237 -0
  48. package/server/collaboration-account-client.ts +202 -0
  49. package/server/collaboration-attribution.ts +122 -0
  50. package/server/collaboration-session.ts +934 -0
  51. package/server/comfyui-bridge.ts +248 -0
  52. package/server/console-ledger.ts +499 -0
  53. package/server/creation-site-transform.ts +304 -0
  54. package/server/creation-site-write.ts +648 -0
  55. package/server/data-file-serialize.ts +158 -0
  56. package/server/editor-brand-html.ts +72 -0
  57. package/server/editor-control-socket.ts +366 -0
  58. package/server/editor-server-options.ts +190 -0
  59. package/server/editor-server.ts +1483 -0
  60. package/server/editor-sse.ts +352 -0
  61. package/server/engine-provenance.ts +169 -0
  62. package/server/engine-source-restart.ts +117 -0
  63. package/server/frame-bridge.ts +115 -0
  64. package/server/frame-proxy.ts +490 -0
  65. package/server/frame-workbench.ts +259 -0
  66. package/server/frontend-handoff.ts +229 -0
  67. package/server/game-globals-shadow.ts +113 -0
  68. package/server/gameplay-session-retention.ts +149 -0
  69. package/server/gameplay-sessions.ts +123 -0
  70. package/server/generation-jobs.ts +201 -0
  71. package/server/generation-reconciler.ts +137 -0
  72. package/server/generative-execution-context.ts +59 -0
  73. package/server/git-workflow.ts +612 -0
  74. package/server/harness-chat-caller.ts +36 -0
  75. package/server/harness-chat-service.ts +1681 -0
  76. package/server/idle-shutdown.ts +170 -0
  77. package/server/js-profiling-policy.ts +52 -0
  78. package/server/launcher-settings.ts +84 -0
  79. package/server/local-asset-catalog.ts +410 -0
  80. package/server/managed-account-defaults.ts +22 -0
  81. package/server/mock-control-plane.ts +540 -0
  82. package/server/model-import-conversion.ts +345 -0
  83. package/server/native-credential-store.ts +162 -0
  84. package/server/open-browser.ts +118 -0
  85. package/server/packaged.ts +1192 -0
  86. package/server/play-stall.ts +126 -0
  87. package/server/process-shutdown.ts +218 -0
  88. package/server/product-presets.ts +55 -0
  89. package/server/project-build-artifact.ts +95 -0
  90. package/server/project-components.ts +100 -0
  91. package/server/project-dependency-invalidation.ts +114 -0
  92. package/server/project-file-scan.ts +235 -0
  93. package/server/project-hmr-files.ts +215 -0
  94. package/server/project-install-roots.ts +210 -0
  95. package/server/project-kinds.ts +71 -0
  96. package/server/project-mcp-servers.ts +82 -0
  97. package/server/project-module-freshness.ts +109 -0
  98. package/server/project-module-instance.ts +375 -0
  99. package/server/project-optimize-deps-entries.ts +827 -0
  100. package/server/project-output-writer.ts +679 -0
  101. package/server/project-package-origin.ts +63 -0
  102. package/server/project-root-surface.ts +831 -0
  103. package/server/project-scratch-path.ts +47 -0
  104. package/server/project-script-hmr.ts +619 -0
  105. package/server/project-serving-plugins.ts +236 -0
  106. package/server/project-tools.ts +653 -0
  107. package/server/project-validation.ts +250 -0
  108. package/server/project-verbs.ts +127 -0
  109. package/server/project-view.ts +52 -0
  110. package/server/project-watch.ts +1134 -0
  111. package/server/project-work-coordinator.ts +288 -0
  112. package/server/provider-credentials.ts +331 -0
  113. package/server/recent-projects-store.ts +98 -0
  114. package/server/redact-secrets.ts +71 -0
  115. package/server/repository-presence.ts +267 -0
  116. package/server/routes/account.ts +357 -0
  117. package/server/routes/agents.ts +60 -0
  118. package/server/routes/assets.ts +154 -0
  119. package/server/routes/build.ts +13 -0
  120. package/server/routes/collaboration.ts +595 -0
  121. package/server/routes/configurations.ts +419 -0
  122. package/server/routes/context.ts +264 -0
  123. package/server/routes/control-plane.ts +1811 -0
  124. package/server/routes/logs.ts +272 -0
  125. package/server/routes/project-identity.ts +302 -0
  126. package/server/routes/project-open.ts +429 -0
  127. package/server/routes/project-source.ts +686 -0
  128. package/server/routes/project-state.ts +383 -0
  129. package/server/routes/relay.ts +1029 -0
  130. package/server/routes/route-helpers.ts +29 -0
  131. package/server/routes/served-modules.ts +138 -0
  132. package/server/routes/session-tabs.ts +196 -0
  133. package/server/routes/settings.ts +121 -0
  134. package/server/routes/share-control.ts +486 -0
  135. package/server/routes/themes.ts +116 -0
  136. package/server/routes/tools.ts +230 -0
  137. package/server/routes/worktrees.ts +595 -0
  138. package/server/scoped-game-css.ts +461 -0
  139. package/server/server-utils.ts +1194 -0
  140. package/server/session-product.ts +112 -0
  141. package/server/session-registry.ts +230 -0
  142. package/server/share-claims.ts +138 -0
  143. package/server/share-host.ts +526 -0
  144. package/server/share-session-gateway.ts +1362 -0
  145. package/server/share-tunnel.ts +123 -0
  146. package/server/spawn-opener.ts +74 -0
  147. package/server/support/play/log-format.ts +76 -0
  148. package/server/support/play/session-record.ts +199 -0
  149. package/server/support/project/build-discipline.ts +718 -0
  150. package/server/support/project/inspection-node.ts +119 -0
  151. package/server/support/project/log-naming.ts +54 -0
  152. package/server/support/project/provenance.ts +290 -0
  153. package/server/support/project/run-name.ts +18 -0
  154. package/server/support/project/session-journal.ts +830 -0
  155. package/server/support/project/shared.ts +327 -0
  156. package/server/tab-bootstrap.ts +62 -0
  157. package/server/tab-heartbeat.ts +477 -0
  158. package/server/tab-lifecycle.ts +550 -0
  159. package/server/tab-presence.ts +1508 -0
  160. package/server/team-agent-mirror.ts +95 -0
  161. package/server/twin-auth.ts +138 -0
  162. package/server/vendored-lock-recorder.ts +968 -0
  163. package/server/worktree-identity.ts +121 -0
  164. package/server/worktree-management.ts +398 -0
  165. package/server/worktree-retention.d.mts +13 -0
  166. package/server/worktree-retention.mjs +205 -0
  167. package/src/EditorContext.tsx +169 -0
  168. package/src/account.ts +333 -0
  169. package/src/action-registry.ts +532 -0
  170. package/src/active-product.ts +74 -0
  171. package/src/active-project.ts +155 -0
  172. package/src/adapter-editor-config.ts +25 -0
  173. package/src/adapter-observation.ts +49 -0
  174. package/src/animation/stage-transport.ts +379 -0
  175. package/src/animation/three-clips-subject.ts +172 -0
  176. package/src/api/asset-library-wire.ts +45 -0
  177. package/src/api/assets.ts +365 -0
  178. package/src/api/base.ts +10 -0
  179. package/src/api/build.ts +99 -0
  180. package/src/api/git-wire.ts +56 -0
  181. package/src/api/logs.ts +92 -0
  182. package/src/api/project-identity.ts +74 -0
  183. package/src/api/project-open.ts +355 -0
  184. package/src/api/project-source.ts +162 -0
  185. package/src/api/project-state.ts +107 -0
  186. package/src/api/relay.ts +268 -0
  187. package/src/api/settings.ts +36 -0
  188. package/src/api/themes.ts +45 -0
  189. package/src/api/worktrees.ts +257 -0
  190. package/src/asset-compare-core.ts +171 -0
  191. package/src/asset-compare.ts +294 -0
  192. package/src/asset-editor-context.tsx +100 -0
  193. package/src/asset-events.ts +97 -0
  194. package/src/asset-inspector-actions.ts +87 -0
  195. package/src/asset-preview-framing.ts +357 -0
  196. package/src/asset-preview.ts +2802 -0
  197. package/src/asset-selection-viewer-registry.ts +113 -0
  198. package/src/asset-selection.ts +133 -0
  199. package/src/asset-workflow/asset-capabilities.ts +344 -0
  200. package/src/asset-workflow/asset-import-jobs.ts +106 -0
  201. package/src/asset-workflow/asset-ledger-backend.ts +126 -0
  202. package/src/asset-workflow/asset-ledger.ts +156 -0
  203. package/src/asset-workflow/asset-materialization-report.ts +140 -0
  204. package/src/asset-workflow/asset-pack-manifest.ts +320 -0
  205. package/src/asset-workflow/asset-types.ts +142 -0
  206. package/src/asset-workflow/asset-workflow-quality.ts +61 -0
  207. package/src/asset-workflow/audio-preview-player.ts +193 -0
  208. package/src/asset-workflow/audio-waveform.ts +22 -0
  209. package/src/asset-workflow/cloud-asset-client.ts +263 -0
  210. package/src/asset-workflow/folder-preview.ts +345 -0
  211. package/src/asset-workflow/hosted-asset-materialization.ts +236 -0
  212. package/src/asset-workflow/image-view-scale.ts +32 -0
  213. package/src/asset-workflow/import-contract.ts +124 -0
  214. package/src/asset-workflow/ledger-write-lock.ts +244 -0
  215. package/src/asset-workflow/model-inspection.ts +818 -0
  216. package/src/asset-workflow/pixi-spritesheet.ts +197 -0
  217. package/src/asset-workflow/preview-resource-lifetime.ts +44 -0
  218. package/src/asset-workflow/project-asset-commands.ts +23 -0
  219. package/src/asset-workflow/project-asset-health.ts +139 -0
  220. package/src/asset-workflow/project-asset-operations.ts +154 -0
  221. package/src/asset-workflow/project-asset-roots.ts +68 -0
  222. package/src/asset-workflow/project-content.ts +288 -0
  223. package/src/asset-workflow/project-source-index.ts +550 -0
  224. package/src/asset-workflow/thumbnail-system.ts +256 -0
  225. package/src/authoring/active-adapter.ts +199 -0
  226. package/src/authoring/active-systems.ts +422 -0
  227. package/src/authoring/adapter-key.ts +18 -0
  228. package/src/authoring/authoring-asset-url.ts +27 -0
  229. package/src/authoring/bootstrap-state.ts +49 -0
  230. package/src/authoring/boundary-authoring-adapter.ts +184 -0
  231. package/src/authoring/breakpoint-state.ts +43 -0
  232. package/src/authoring/canvas-scene-guides.ts +76 -0
  233. package/src/authoring/component-instance-root.ts +171 -0
  234. package/src/authoring/composite-authoring-adapter.ts +2110 -0
  235. package/src/authoring/consumer-actions.ts +520 -0
  236. package/src/authoring/css-numeric-style.ts +97 -0
  237. package/src/authoring/design-time-layers.ts +849 -0
  238. package/src/authoring/design-time-mount-registry.ts +235 -0
  239. package/src/authoring/design-time-settle.ts +343 -0
  240. package/src/authoring/edit-mode-authoring.ts +619 -0
  241. package/src/authoring/eyedropper-session.ts +60 -0
  242. package/src/authoring/instance-source-menu-register.ts +13 -0
  243. package/src/authoring/instance-source-menu.ts +135 -0
  244. package/src/authoring/layered-pick.ts +183 -0
  245. package/src/authoring/live-gesture-lock.ts +50 -0
  246. package/src/authoring/live-object-transform.ts +62 -0
  247. package/src/authoring/mount-failure-report.ts +154 -0
  248. package/src/authoring/mounted-root-subjects.ts +144 -0
  249. package/src/authoring/no-authoring-adapter.ts +55 -0
  250. package/src/authoring/null-inspection-subjects.tsx +75 -0
  251. package/src/authoring/object3d-document-persistence.ts +106 -0
  252. package/src/authoring/object3d-document-session-registry.ts +120 -0
  253. package/src/authoring/object3d-document-session.ts +1326 -0
  254. package/src/authoring/object3d-gesture-controller.ts +113 -0
  255. package/src/authoring/panel-authoring.ts +121 -0
  256. package/src/authoring/prefab-instance-inspector-section.tsx +237 -0
  257. package/src/authoring/prefab-instance-section-model.ts +55 -0
  258. package/src/authoring/project-authoring-session.ts +105 -0
  259. package/src/authoring/provenance.ts +99 -0
  260. package/src/authoring/quarks-particle-systems.ts +19 -0
  261. package/src/authoring/react-canvas-navigation.ts +255 -0
  262. package/src/authoring/react-design-canvas-style.ts +20 -0
  263. package/src/authoring/react-story-board.ts +937 -0
  264. package/src/authoring/selection-scope.ts +195 -0
  265. package/src/authoring/shell-document-ops.ts +169 -0
  266. package/src/authoring/shell-object3d-document-write-policy.ts +108 -0
  267. package/src/authoring/shell-viewport-policy.ts +48 -0
  268. package/src/authoring/source-object3d-authoring-adapter.ts +526 -0
  269. package/src/authoring/stories-scope.ts +35 -0
  270. package/src/authoring/story-board-chrome-fit.ts +107 -0
  271. package/src/authoring/story-board-presentation.ts +111 -0
  272. package/src/authoring/three-projection-core.ts +226 -0
  273. package/src/authoring/viewport-pick-context.ts +40 -0
  274. package/src/authoring/viewport-raycast.ts +240 -0
  275. package/src/authoring/viewport-tool-context.ts +73 -0
  276. package/src/authoring/world-canvas-viewport-state.ts +35 -0
  277. package/src/authoring/world-hidden-viewport.ts +152 -0
  278. package/src/authoring/world-pan-state.ts +198 -0
  279. package/src/authoring/world-session-state.ts +101 -0
  280. package/src/authoring/write-pipe.ts +173 -0
  281. package/src/availability-tick.ts +66 -0
  282. package/src/bitmap-label.ts +120 -0
  283. package/src/blender-tab-metrics.ts +161 -0
  284. package/src/board-open-actions.ts +20 -0
  285. package/src/boot-routing.ts +391 -0
  286. package/src/build-identity.ts +15 -0
  287. package/src/bytes-codec.ts +62 -0
  288. package/src/camera-authoring.ts +175 -0
  289. package/src/cancellation-reason.ts +58 -0
  290. package/src/canvas-preview-frames.ts +482 -0
  291. package/src/capture-camera-pose.ts +77 -0
  292. package/src/chrome-registry.ts +159 -0
  293. package/src/chrome-slot-registry.ts +91 -0
  294. package/src/collaboration-client.ts +264 -0
  295. package/src/collaboration-presence.ts +41 -0
  296. package/src/command-dispatch.ts +19 -0
  297. package/src/command-listener.ts +2743 -0
  298. package/src/command-registry.ts +70 -0
  299. package/src/component-board-registry.ts +205 -0
  300. package/src/component-states-registry.ts +200 -0
  301. package/src/components/AgentPresentationNotice.tsx +75 -0
  302. package/src/components/AlignToolbar.tsx +204 -0
  303. package/src/components/AppRoot.tsx +394 -0
  304. package/src/components/ApplicationMenus.tsx +415 -0
  305. package/src/components/AssetBrowser.tsx +2843 -0
  306. package/src/components/AssetEditorShell.tsx +216 -0
  307. package/src/components/AssetInspectorToolSection.tsx +124 -0
  308. package/src/components/BoardRulers.tsx +354 -0
  309. package/src/components/CameraInfo.tsx +81 -0
  310. package/src/components/CanvasSceneViewport.tsx +556 -0
  311. package/src/components/CapabilityCoverageSection.tsx +185 -0
  312. package/src/components/CenterDocuments.tsx +22 -0
  313. package/src/components/ChromeSlot.tsx +20 -0
  314. package/src/components/CodeView.tsx +470 -0
  315. package/src/components/CollaborationHeaderControl.css +74 -0
  316. package/src/components/CompactInspectorCard.tsx +190 -0
  317. package/src/components/CompactInspectorShell.tsx +39 -0
  318. package/src/components/ConsolePanel.css +55 -0
  319. package/src/components/ConsolePanel.tsx +270 -0
  320. package/src/components/DefaultEditorLayout.tsx +106 -0
  321. package/src/components/DocumentHeaderStrip.tsx +96 -0
  322. package/src/components/DocumentShelfRail.tsx +45 -0
  323. package/src/components/DocumentThumbnail.tsx +345 -0
  324. package/src/components/EditorLeaseGuard.tsx +372 -0
  325. package/src/components/ErrorBanner.tsx +123 -0
  326. package/src/components/FolderPreviewTile.tsx +159 -0
  327. package/src/components/GameHierarchy.tsx +3842 -0
  328. package/src/components/GameplaySessionTimeline.tsx +295 -0
  329. package/src/components/InspectionProjection.tsx +968 -0
  330. package/src/components/Inspector.tsx +233 -0
  331. package/src/components/InspectorCanvasPreview.tsx +35 -0
  332. package/src/components/InspectorFieldsSection.tsx +290 -0
  333. package/src/components/InspectorObjectPreview.tsx +57 -0
  334. package/src/components/InspectorStoriesSection.tsx +92 -0
  335. package/src/components/InspectorToolSection.tsx +96 -0
  336. package/src/components/InspectorTransformSection.tsx +245 -0
  337. package/src/components/LightExplorerPanel.tsx +433 -0
  338. package/src/components/MediaProperties.tsx +145 -0
  339. package/src/components/NonThreeAuthoringBootstrap.tsx +19 -0
  340. package/src/components/Object3DDocumentToolbar.css +100 -0
  341. package/src/components/Object3DDocumentToolbar.tsx +454 -0
  342. package/src/components/Object3DDocumentViewport.tsx +58 -0
  343. package/src/components/ProjectHeader.css +617 -0
  344. package/src/components/ProjectHeader.tsx +328 -0
  345. package/src/components/ProjectLayout.tsx +249 -0
  346. package/src/components/ReactCanvasControls.tsx +284 -0
  347. package/src/components/RootSelectionOverlay.tsx +3162 -0
  348. package/src/components/RootTextEditor.tsx +79 -0
  349. package/src/components/SaveStatus.tsx +70 -0
  350. package/src/components/StageHost.tsx +1954 -0
  351. package/src/components/StageOverlays.tsx +21 -0
  352. package/src/components/StartupErrorScreen.tsx +76 -0
  353. package/src/components/StartupLoadingScreen.tsx +65 -0
  354. package/src/components/StatsOverlay.tsx +78 -0
  355. package/src/components/SurfaceStateOverlay.tsx +24 -0
  356. package/src/components/ToolContributionSurfaces.tsx +65 -0
  357. package/src/components/ToolHost.tsx +370 -0
  358. package/src/components/ToolObject3DPreview.tsx +39 -0
  359. package/src/components/Toolbar.tsx +595 -0
  360. package/src/components/TransientHint.tsx +44 -0
  361. package/src/components/TransportStrip.tsx +174 -0
  362. package/src/components/VersionControlSection.tsx +470 -0
  363. package/src/components/VgaiLogo.css +83 -0
  364. package/src/components/VgaiLogo.tsx +35 -0
  365. package/src/components/ViewportControlsHint.tsx +60 -0
  366. package/src/components/ViewportFurniture.tsx +401 -0
  367. package/src/components/ViewportOverlay.tsx +145 -0
  368. package/src/components/ViewportOverlaysMenu.tsx +153 -0
  369. package/src/components/ViewportShadingMenu.tsx +300 -0
  370. package/src/components/ViewportViewMenu.tsx +101 -0
  371. package/src/components/WorkspaceDocumentSurface.tsx +204 -0
  372. package/src/components/WorkspaceUtilitySurface.tsx +22 -0
  373. package/src/components/WorktreeSwitcher.css +239 -0
  374. package/src/components/WorktreeSwitcher.tsx +890 -0
  375. package/src/components/account-documents.tsx +1162 -0
  376. package/src/components/asset-documents.tsx +812 -0
  377. package/src/components/asset-editor-persistence.ts +216 -0
  378. package/src/components/asset-selection-section.tsx +535 -0
  379. package/src/components/asset-thumbnails.tsx +312 -0
  380. package/src/components/asset-viewers/AudioViewer.tsx +201 -0
  381. package/src/components/asset-viewers/EntityModelDocument.tsx +122 -0
  382. package/src/components/asset-viewers/EnvironmentAssetDocument.tsx +440 -0
  383. package/src/components/asset-viewers/GenericJsonViewer.tsx +102 -0
  384. package/src/components/asset-viewers/ImageViewer.tsx +300 -0
  385. package/src/components/asset-viewers/JsonAssetDocument.tsx +93 -0
  386. package/src/components/asset-viewers/LiveModuleDocument.tsx +417 -0
  387. package/src/components/asset-viewers/LutAssetDocument.tsx +444 -0
  388. package/src/components/asset-viewers/ModelAssetDocument.tsx +105 -0
  389. package/src/components/asset-viewers/Object3DPreview.tsx +359 -0
  390. package/src/components/asset-viewers/OnlineAssetDetail.tsx +421 -0
  391. package/src/components/asset-viewers/PasteboardModuleDocument.tsx +67 -0
  392. package/src/components/asset-viewers/QuarksAssetDocument.tsx +526 -0
  393. package/src/components/asset-viewers/ShaderAssetDocument.tsx +743 -0
  394. package/src/components/asset-viewers/SourceAssetViewer.tsx +281 -0
  395. package/src/components/asset-viewers/SpritesheetSpriteView.tsx +102 -0
  396. package/src/components/asset-viewers/VideoViewer.tsx +101 -0
  397. package/src/components/asset-viewers/shader-source.ts +144 -0
  398. package/src/components/asset-workflow.css +731 -0
  399. package/src/components/board-guides.ts +150 -0
  400. package/src/components/compact-inspector.css +539 -0
  401. package/src/components/core-utilities.tsx +90 -0
  402. package/src/components/editor-notifications.css +40 -0
  403. package/src/components/engine-workspace.css +274 -0
  404. package/src/components/inspector-preview-section.tsx +238 -0
  405. package/src/components/inspector-property-grouping.ts +64 -0
  406. package/src/components/inspector-revert-label.ts +20 -0
  407. package/src/components/inspector-selection.ts +42 -0
  408. package/src/components/inspector-stories-gating.ts +171 -0
  409. package/src/components/inspector-transform-subject.ts +11 -0
  410. package/src/components/inspector-transform.ts +75 -0
  411. package/src/components/kind-documents.tsx +500 -0
  412. package/src/components/palette-action-publisher.tsx +140 -0
  413. package/src/components/primitives/DraftColorInput.tsx +74 -0
  414. package/src/components/product-shell.css +1829 -0
  415. package/src/components/project-tool-documents.tsx +410 -0
  416. package/src/components/scene-documents.tsx +223 -0
  417. package/src/components/stage-keyboard.tsx +37 -0
  418. package/src/components/stage-overlay-set.tsx +107 -0
  419. package/src/components/stage-presence-markers.ts +478 -0
  420. package/src/components/standard-viewport-dressing.ts +417 -0
  421. package/src/components/status-contributions.tsx +403 -0
  422. package/src/components/tool-documents.tsx +309 -0
  423. package/src/components/tool-schema-form.tsx +262 -0
  424. package/src/components/use-after-paint.ts +41 -0
  425. package/src/components/use-project-image-assets.ts +86 -0
  426. package/src/components/viewport-header-controls.css +90 -0
  427. package/src/components/viewport-surface-status.tsx +55 -0
  428. package/src/components/workspace-history.ts +32 -0
  429. package/src/components/workspace-static-panel-registry.tsx +152 -0
  430. package/src/components/workspace-surfaces.css +621 -0
  431. package/src/components/world-documents.tsx +586 -0
  432. package/src/components/world-overlay-gestures.ts +1694 -0
  433. package/src/composite-screenshot.ts +1641 -0
  434. package/src/console-sync.ts +131 -0
  435. package/src/constraint-helper.ts +338 -0
  436. package/src/content-entry-source-registry.ts +184 -0
  437. package/src/coverage/authoring-seam-evidence.ts +300 -0
  438. package/src/coverage/canvas-reveal.ts +192 -0
  439. package/src/coverage/design-time-surfaces.ts +101 -0
  440. package/src/coverage/live-seam-evidence.ts +11 -0
  441. package/src/coverage/ontology-invariants.ts +466 -0
  442. package/src/coverage/session-vitals.ts +501 -0
  443. package/src/coverage/system-seam-evidence.ts +72 -0
  444. package/src/crash-null-boundary.ts +36 -0
  445. package/src/creation-site-edit.ts +1479 -0
  446. package/src/creation-site-registry.ts +160 -0
  447. package/src/delegate-harness-registry.ts +143 -0
  448. package/src/document-context-registry.ts +177 -0
  449. package/src/document-open-registry.ts +200 -0
  450. package/src/document-preview-source.ts +20 -0
  451. package/src/document-renderer-session.ts +138 -0
  452. package/src/editor-api.ts +46 -0
  453. package/src/editor-chrome-capture.ts +139 -0
  454. package/src/editor-commands.ts +164 -0
  455. package/src/editor-console.ts +563 -0
  456. package/src/editor-current-view.ts +82 -0
  457. package/src/editor-document-probe.ts +881 -0
  458. package/src/editor-git-client.ts +115 -0
  459. package/src/editor-host-door.ts +462 -0
  460. package/src/editor-hotkeys.ts +842 -0
  461. package/src/editor-lease-view.ts +39 -0
  462. package/src/editor-lease.ts +415 -0
  463. package/src/editor-mode.ts +19 -0
  464. package/src/editor-notifications.ts +140 -0
  465. package/src/editor-presence.ts +563 -0
  466. package/src/editor-presentation-activity.ts +50 -0
  467. package/src/editor-presentation-notice.ts +42 -0
  468. package/src/editor-runtime.tsx +145 -0
  469. package/src/editor-server-response.ts +86 -0
  470. package/src/editor-session-attribution.ts +75 -0
  471. package/src/editor-session-mode.ts +54 -0
  472. package/src/editor-shell-store.ts +1304 -0
  473. package/src/editor-state-facets.ts +74 -0
  474. package/src/editor-styles.css +33 -0
  475. package/src/editor-view-presentation.ts +810 -0
  476. package/src/editor-viewport.ts +5302 -0
  477. package/src/entity-lod.ts +31 -0
  478. package/src/entity-object.ts +91 -0
  479. package/src/files/file-provider.ts +62 -0
  480. package/src/files/project-files.ts +264 -0
  481. package/src/finders/index.ts +136 -0
  482. package/src/finders/scenes-from-entrypoint-selection.ts +387 -0
  483. package/src/frame/bridge.tsx +1408 -0
  484. package/src/frame/product.ts +77 -0
  485. package/src/gameplay-dom-recording.ts +319 -0
  486. package/src/gameplay-export-state.ts +14 -0
  487. package/src/gameplay-replay.ts +417 -0
  488. package/src/gameplay-session-time.ts +9 -0
  489. package/src/gameplay-sessions.ts +204 -0
  490. package/src/harness-chat-types.ts +253 -0
  491. package/src/hierarchy-component-marks.ts +298 -0
  492. package/src/hierarchy-drop.ts +91 -0
  493. package/src/hierarchy-expansion-state.ts +80 -0
  494. package/src/hierarchy-header-slot.ts +52 -0
  495. package/src/hierarchy-internals.ts +197 -0
  496. package/src/hierarchy-kind-icon.ts +217 -0
  497. package/src/hierarchy-mark-reader.ts +73 -0
  498. package/src/hierarchy-menu-registry.ts +67 -0
  499. package/src/hierarchy-node-rows.ts +307 -0
  500. package/src/hierarchy-panel-view.ts +280 -0
  501. package/src/hierarchy-projection.ts +76 -0
  502. package/src/hierarchy-row-cache.ts +243 -0
  503. package/src/hierarchy-row-model.ts +308 -0
  504. package/src/hierarchy-rows.ts +11 -0
  505. package/src/hierarchy-walk.ts +86 -0
  506. package/src/history/editor-session.ts +25 -0
  507. package/src/history/history-commands.ts +147 -0
  508. package/src/history/history-delegate.ts +163 -0
  509. package/src/history/history-limit-notices.ts +43 -0
  510. package/src/history/history-service.ts +1173 -0
  511. package/src/history/persistence-coordinator.ts +35 -0
  512. package/src/history/project-file-history.ts +386 -0
  513. package/src/history/project-root-history-backends.ts +139 -0
  514. package/src/history/resource-registry.ts +209 -0
  515. package/src/history/snapshot-store.ts +103 -0
  516. package/src/history/source-history-backend.ts +546 -0
  517. package/src/history/types.ts +124 -0
  518. package/src/hmr-registration-group.ts +67 -0
  519. package/src/hmr-stable-react-context.ts +23 -0
  520. package/src/hotkeys.ts +188 -0
  521. package/src/inference-diagnostics.ts +69 -0
  522. package/src/initial-project.ts +80 -0
  523. package/src/inspection/active-subject.ts +578 -0
  524. package/src/inspection/active-surface.ts +142 -0
  525. package/src/inspection/compose.ts +1064 -0
  526. package/src/inspection/display.ts +170 -0
  527. package/src/inspection/document-subject.ts +109 -0
  528. package/src/inspection/game-subject.ts +85 -0
  529. package/src/inspection/model.ts +542 -0
  530. package/src/inspection/null-subject.ts +115 -0
  531. package/src/inspection/serialize.ts +357 -0
  532. package/src/inspection/use-active-inspection.ts +180 -0
  533. package/src/inspector-presentation.ts +201 -0
  534. package/src/inspector-section-registry.ts +221 -0
  535. package/src/instance-source-actions.ts +163 -0
  536. package/src/instanced-presentation.ts +164 -0
  537. package/src/js-heap.ts +71 -0
  538. package/src/key-actions.ts +91 -0
  539. package/src/keymap-presets.ts +401 -0
  540. package/src/layout-policy.ts +31 -0
  541. package/src/learn-links.ts +73 -0
  542. package/src/light-explorer-model.ts +134 -0
  543. package/src/live-canvas-frame.ts +55 -0
  544. package/src/live-document.ts +279 -0
  545. package/src/live-module-source.ts +230 -0
  546. package/src/live-session-registry.ts +220 -0
  547. package/src/live-transition.ts +633 -0
  548. package/src/manifest-project.ts +107 -0
  549. package/src/model-thumbnail.ts +523 -0
  550. package/src/native-selection-style.ts +202 -0
  551. package/src/object3d-document-write-policy.ts +137 -0
  552. package/src/packaged-runtime.ts +108 -0
  553. package/src/palettes/maya.palette.json +57 -0
  554. package/src/palettes/substance.palette.json +57 -0
  555. package/src/pasteboard-module.ts +81 -0
  556. package/src/performance-profiler.ts +367 -0
  557. package/src/performance-sources.ts +69 -0
  558. package/src/play-boot-phase.ts +145 -0
  559. package/src/presentation-surface.ts +248 -0
  560. package/src/project-adapter.ts +1143 -0
  561. package/src/project-asset-refresh.ts +26 -0
  562. package/src/project-declaration-refresh.ts +31 -0
  563. package/src/project-local-state.ts +118 -0
  564. package/src/project-manager.ts +243 -0
  565. package/src/project-module-changes.ts +163 -0
  566. package/src/project-module-split.ts +266 -0
  567. package/src/project-provenance.ts +115 -0
  568. package/src/project-ready.ts +42 -0
  569. package/src/project-session-reset.ts +67 -0
  570. package/src/project-shape.ts +68 -0
  571. package/src/project-tool-discovery.ts +66 -0
  572. package/src/project-tools.ts +107 -0
  573. package/src/project-work-types.ts +149 -0
  574. package/src/projection/three.ts +898 -0
  575. package/src/projection/types.ts +44 -0
  576. package/src/readiness.ts +113 -0
  577. package/src/reflection-probe-helper.ts +142 -0
  578. package/src/reported-play-state.ts +90 -0
  579. package/src/resolve-relative-specifier.ts +33 -0
  580. package/src/scene-document-plan.ts +315 -0
  581. package/src/scene-framing.ts +315 -0
  582. package/src/scene-live-open.ts +210 -0
  583. package/src/scene-view-fog.ts +89 -0
  584. package/src/scoped-game-css.ts +152 -0
  585. package/src/session-orphan-record.ts +193 -0
  586. package/src/session-tombstone.ts +126 -0
  587. package/src/settings/settings-provider.ts +82 -0
  588. package/src/settings-store.ts +345 -0
  589. package/src/shared-view-restore.ts +42 -0
  590. package/src/shell-store-door.ts +45 -0
  591. package/src/source-conflict.ts +122 -0
  592. package/src/spatial-handle-visuals.ts +332 -0
  593. package/src/stage-context.ts +341 -0
  594. package/src/stage-store-registry.ts +63 -0
  595. package/src/stale-chunk-recovery.ts +34 -0
  596. package/src/state-report-deferral.ts +73 -0
  597. package/src/storage/host-files-storage.ts +97 -0
  598. package/src/storage/http-storage.ts +174 -0
  599. package/src/storage/index.ts +75 -0
  600. package/src/storage/mem-storage.ts +149 -0
  601. package/src/storage/path-lock.ts +44 -0
  602. package/src/storage/paths.ts +26 -0
  603. package/src/storage/types.ts +116 -0
  604. package/src/stories/StoryComponentThumbnail.tsx +184 -0
  605. package/src/stories/StoryPreviewMount.tsx +306 -0
  606. package/src/stories/component-content-source.tsx +106 -0
  607. package/src/stories/component-states-source.ts +78 -0
  608. package/src/stories/compose-project-stories.ts +255 -0
  609. package/src/stories/pixi-story-model.ts +30 -0
  610. package/src/stories/prefabs-finder.ts +54 -0
  611. package/src/stories/prefabs-from-stories.ts +182 -0
  612. package/src/stories/project-story-discovery.ts +78 -0
  613. package/src/stories/project-story-regions.ts +24 -0
  614. package/src/stories/story-actions.ts +54 -0
  615. package/src/stories/story-capture-command.ts +124 -0
  616. package/src/stories/story-capture.ts +584 -0
  617. package/src/stories/story-declared-medium.ts +126 -0
  618. package/src/stories/story-discovery.ts +176 -0
  619. package/src/stories/story-document-openers.ts +36 -0
  620. package/src/stories/story-dom-runtime.ts +78 -0
  621. package/src/stories/story-grouping.ts +111 -0
  622. package/src/stories/story-lane.ts +88 -0
  623. package/src/stories/story-mount-turn.ts +27 -0
  624. package/src/stories/story-opener.ts +260 -0
  625. package/src/stories/story-pixi-preview.ts +408 -0
  626. package/src/stories/story-presentation.ts +215 -0
  627. package/src/stories/story-registry.ts +517 -0
  628. package/src/stories/story-three-preview.ts +807 -0
  629. package/src/stories/three-story-model.ts +96 -0
  630. package/src/story-three-preview-runtime.ts +56 -0
  631. package/src/surface-keyboard.ts +112 -0
  632. package/src/surface-state.ts +124 -0
  633. package/src/tab-bootstrap.js +628 -0
  634. package/src/tab-census.ts +198 -0
  635. package/src/tab-lifecycle-client.ts +196 -0
  636. package/src/theme-library.ts +844 -0
  637. package/src/theme-preference.ts +378 -0
  638. package/src/theme.css +3437 -0
  639. package/src/three-viewport/bone-selection-highlight.ts +119 -0
  640. package/src/three-viewport/camera-fit.ts +41 -0
  641. package/src/three-viewport/interactive-renderer.ts +132 -0
  642. package/src/three-viewport/selection-brackets.ts +310 -0
  643. package/src/three-viewport/selection-outline.ts +183 -0
  644. package/src/three-viewport/skeleton-helper.ts +61 -0
  645. package/src/three-viewport/source-color.ts +167 -0
  646. package/src/three-viewport/studio-environment.ts +96 -0
  647. package/src/three-viewport-presentation.ts +23 -0
  648. package/src/tool-contribution-play.ts +74 -0
  649. package/src/tool-loader.ts +1798 -0
  650. package/src/transform-mode-request.ts +57 -0
  651. package/src/transient-hint.ts +78 -0
  652. package/src/trigger-volume-helper.ts +116 -0
  653. package/src/ui-source/adapter-region-includes.ts +241 -0
  654. package/src/ui-source/ensure-import.ts +132 -0
  655. package/src/ui-source/file-region-resolver.ts +302 -0
  656. package/src/ui-source/inspect.ts +775 -0
  657. package/src/ui-source/oid-transform.ts +1845 -0
  658. package/src/ui-source/plan-csf-story.ts +196 -0
  659. package/src/ui-source/plan-extract-component.ts +421 -0
  660. package/src/ui-source/plan-fork-component.ts +621 -0
  661. package/src/ui-source/plan-named-style.ts +95 -0
  662. package/src/ui-source/plan-source-edit.ts +353 -0
  663. package/src/ui-source/r3f-contract-resolver.ts +327 -0
  664. package/src/ui-source/r3f-diagnostic-index.ts +165 -0
  665. package/src/ui-source/r3f-environment-binding.ts +133 -0
  666. package/src/ui-source/r3f-joint-binding.ts +251 -0
  667. package/src/ui-source/r3f-lod-binding.ts +91 -0
  668. package/src/ui-source/r3f-particle-binding.ts +235 -0
  669. package/src/ui-source/r3f-physics-binding.ts +483 -0
  670. package/src/ui-source/r3f-project-contracts.ts +444 -0
  671. package/src/ui-source/relative-import-specifier.ts +34 -0
  672. package/src/ui-source/reparent-guard.ts +544 -0
  673. package/src/ui-source/source-edit-request.ts +97 -0
  674. package/src/ui-source/source-write-backend.ts +618 -0
  675. package/src/ui-source/syntactic-prop-specs.ts +296 -0
  676. package/src/ui-source/tier-source-write-backend.ts +279 -0
  677. package/src/ui-source/ts-ast.ts +171 -0
  678. package/src/ui-source/utility-class-support.ts +169 -0
  679. package/src/ui-source/write-component-default.ts +133 -0
  680. package/src/ui-source/writer.ts +1989 -0
  681. package/src/viewport-activation-timings.ts +840 -0
  682. package/src/viewport-authoring-policy.ts +186 -0
  683. package/src/viewport-controls-hint.ts +57 -0
  684. package/src/viewport-door.ts +237 -0
  685. package/src/viewport-shading-boundary.ts +12 -0
  686. package/src/vite-error-surface.ts +141 -0
  687. package/src/wait-until.ts +37 -0
  688. package/src/workspace-areas.ts +156 -0
  689. package/src/workspace-aux-commands.ts +11 -0
  690. package/src/workspace-available-documents.ts +127 -0
  691. package/src/workspace-core-utilities.ts +31 -0
  692. package/src/workspace-document-ids.ts +59 -0
  693. package/src/workspace-document-registry.ts +612 -0
  694. package/src/workspace-document-restore.ts +145 -0
  695. package/src/workspace-host-commands.ts +141 -0
  696. package/src/workspace-persistence-gate.ts +40 -0
  697. package/src/workspace-play-utilities.ts +44 -0
  698. package/src/workspace-presets.ts +425 -0
  699. package/src/workspace-regions.ts +294 -0
  700. package/src/workspace-state-persistence.ts +536 -0
  701. package/src/workspace-static-panels.ts +73 -0
  702. package/src/workspace-status-registry.ts +121 -0
  703. package/src/workspace-style.ts +239 -0
  704. package/src/workspace-utility-commands.ts +74 -0
  705. package/src/workspace-utility-registry.ts +263 -0
  706. package/src/workspace-viewport-rect.ts +97 -0
  707. package/src/world-adoption.ts +115 -0
  708. package/src/world-document-routing.ts +104 -0
  709. package/vite-plugin-creation-site-write.ts +184 -0
  710. package/vite-plugin-creation-site.ts +80 -0
  711. package/vite-plugin-game-static.ts +303 -0
  712. package/vite-plugin-module-doorways.ts +336 -0
  713. package/vite-plugin-product-contributions.ts +197 -0
  714. package/vite-plugin-project-game-static.ts +125 -0
  715. package/vite-plugin-project-jsx-js.ts +65 -0
  716. package/vite-plugin-project-root-absolute-assets.ts +359 -0
  717. package/vite-plugin-shared-react.ts +420 -0
  718. package/vite-plugin-shared-three.ts +203 -0
  719. package/vite-plugin-ui-oid.ts +2106 -0
@@ -0,0 +1,679 @@
1
+ /**
2
+ * Atomic persistence boundary for files produced by project tools.
3
+ *
4
+ * Generators remain ordinary project/package code. They hand their completed
5
+ * bytes to this writer only when they are ready to commit; the editor host
6
+ * validates every path, stages the whole batch, and rolls the batch back if
7
+ * any rename fails. A half-generated output set must never become
8
+ * visible to the asset watcher.
9
+ */
10
+
11
+ import { createHash, randomUUID } from 'node:crypto';
12
+ import { createReadStream } from 'node:fs';
13
+ import { mkdir, readdir, readFile, rename, rm, stat, writeFile } from 'node:fs/promises';
14
+ import { dirname, extname, posix, relative, resolve, sep } from 'node:path';
15
+ import { isContainedRelativePath } from '@volter/editor-sdk/session/relative-path-guard';
16
+ import type { GenerationJob } from '@volter/editor-sdk/generations';
17
+ import { normalizeProjectOutputPath } from '@volter/editor-sdk/project/output-roots';
18
+ import {
19
+ emptyProjectProvenanceDocument,
20
+ PROJECT_ATTEST_OPERATION,
21
+ PROJECT_PROVENANCE_PATH,
22
+ ProjectProvenanceDocumentSchema,
23
+ type ProjectProvenanceExecution,
24
+ ProjectProvenanceOperationSchema,
25
+ } from './support/project/provenance';
26
+ import type {
27
+ ProjectGeneratedOutput,
28
+ ProjectGeneratedOutputFile,
29
+ ProjectOutputFile,
30
+ ProjectOutputProvenanceContext,
31
+ ProjectOutputWriter,
32
+ } from '@volter/editor-sdk/tools/types';
33
+ import { withExclusiveLock } from '../src/asset-workflow/ledger-write-lock';
34
+ import { ledgerLockIo } from './asset-ledger-store';
35
+ import { readGenerationJobs } from './generation-jobs';
36
+ import { consumeGenerativeExecutions } from './generative-execution-context';
37
+ import { sanitizeRecordedValue } from './redact-secrets';
38
+
39
+ type NormalizedOutputFile = ProjectOutputFile & { path: string };
40
+
41
+ interface HashedProjectFile extends ProjectGeneratedOutputFile {
42
+ sha256: string;
43
+ }
44
+
45
+ const projectCommitQueues = new Map<string, Promise<unknown>>();
46
+
47
+ function withCapturedExecutions(
48
+ provenanceContext: ProjectOutputProvenanceContext,
49
+ ): ProjectOutputProvenanceContext {
50
+ const captured = consumeGenerativeExecutions();
51
+ const explicit = provenanceContext.executions
52
+ ? [...provenanceContext.executions]
53
+ : provenanceContext.execution
54
+ ? [provenanceContext.execution]
55
+ : [];
56
+ if (
57
+ captured.length > 0 &&
58
+ explicit.length > 0 &&
59
+ JSON.stringify(captured) !== JSON.stringify(explicit)
60
+ ) {
61
+ throw new Error('Explicit and automatically captured provider execution facts disagree.');
62
+ }
63
+ const executions = captured.length > 0 ? captured : explicit;
64
+ const effective = { ...provenanceContext };
65
+ delete effective.execution;
66
+ delete effective.executions;
67
+ if (executions.length === 1) effective.execution = executions[0]!;
68
+ if (executions.length > 1) effective.executions = executions;
69
+ return effective;
70
+ }
71
+
72
+ async function withGenerationBilling(
73
+ projectRoot: string,
74
+ provenanceContext: ProjectOutputProvenanceContext,
75
+ ): Promise<ProjectOutputProvenanceContext> {
76
+ const executions = provenanceContext.executions
77
+ ? [...provenanceContext.executions]
78
+ : provenanceContext.execution
79
+ ? [provenanceContext.execution]
80
+ : [];
81
+ if (executions.length === 0) return provenanceContext;
82
+ let jobs: GenerationJob[];
83
+ try {
84
+ jobs = (await readGenerationJobs(projectRoot)).jobs;
85
+ } catch {
86
+ // A direct callable may never have registered a job, and a damaged
87
+ // operational ledger must not strand otherwise valid accepted bytes.
88
+ return provenanceContext;
89
+ }
90
+ const enriched = executions.map((execution) => {
91
+ const externalId = execution.requestId ?? execution.taskId;
92
+ if (!externalId) return execution;
93
+ const job = jobs.find(
94
+ (candidate) =>
95
+ candidate.provider === execution.provider && candidate.externalId === externalId,
96
+ );
97
+ return job ? { ...execution, billing: job.billing } : execution;
98
+ });
99
+ const effective = { ...provenanceContext };
100
+ delete effective.execution;
101
+ delete effective.executions;
102
+ if (enriched.length === 1) effective.execution = enriched[0]!;
103
+ if (enriched.length > 1) effective.executions = enriched;
104
+ return effective;
105
+ }
106
+
107
+ /**
108
+ * Project-relative, contained, and under one of the writable output roots —
109
+ * `public/` (shipped game assets) or `references/` (reference material the
110
+ * editor's Content panel indexes but no export copies). The root rule itself
111
+ * lives in `@vgai/sdk/output-roots` because provider boundaries enforce the
112
+ * same one; `isContainedRelativePath` stays here as the host's own escape
113
+ * check, which knows about absolute Windows paths and NUL bytes.
114
+ */
115
+ function normalizeOutputPath(path: string): string {
116
+ const slashPath = path.split(sep).join('/');
117
+ const normalized = posix.normalize(slashPath).replace(/^\.\//, '');
118
+ if (!isContainedRelativePath(normalized)) {
119
+ throw new Error(
120
+ `Generated output path ${JSON.stringify(path)} is invalid; outputs must be project-relative files.`,
121
+ );
122
+ }
123
+ return normalizeProjectOutputPath(normalized);
124
+ }
125
+
126
+ function byteLength(content: string | Uint8Array): number {
127
+ return typeof content === 'string' ? Buffer.byteLength(content) : content.byteLength;
128
+ }
129
+
130
+ function sha256(content: string | Uint8Array): string {
131
+ return createHash('sha256').update(content).digest('hex');
132
+ }
133
+
134
+ async function sha256File(path: string): Promise<string> {
135
+ const hash = createHash('sha256');
136
+ for await (const chunk of createReadStream(path)) hash.update(chunk as Buffer);
137
+ return hash.digest('hex');
138
+ }
139
+
140
+ async function existingFile(path: string): Promise<boolean> {
141
+ try {
142
+ const info = await stat(path);
143
+ if (!info.isFile()) throw new Error(`Generated output target is not a file: ${path}`);
144
+ return true;
145
+ } catch (error) {
146
+ if (error instanceof Error && 'code' in error && error.code === 'ENOENT') return false;
147
+ throw error;
148
+ }
149
+ }
150
+
151
+ function validateBatch(files: readonly ProjectOutputFile[]): {
152
+ normalized: NormalizedOutputFile[];
153
+ summaries: ProjectGeneratedOutputFile[];
154
+ totalBytes: number;
155
+ } {
156
+ if (files.length === 0) throw new Error('Generated output batch must contain at least one file.');
157
+ const normalized = files.map((file) => ({ ...file, path: normalizeOutputPath(file.path) }));
158
+ const paths = new Set<string>();
159
+ let totalBytes = 0;
160
+ for (const file of normalized) {
161
+ if (paths.has(file.path)) {
162
+ throw new Error(
163
+ `Generated output batch contains duplicate path ${JSON.stringify(file.path)}.`,
164
+ );
165
+ }
166
+ paths.add(file.path);
167
+ totalBytes += byteLength(file.content);
168
+ }
169
+ return {
170
+ normalized,
171
+ totalBytes,
172
+ summaries: normalized.map((file) => ({
173
+ path: file.path,
174
+ bytes: byteLength(file.content),
175
+ ...(file.mediaType ? { mediaType: file.mediaType } : {}),
176
+ ...(file.role ? { role: file.role } : {}),
177
+ })),
178
+ };
179
+ }
180
+
181
+ async function stageBatch(stagedRoot: string, files: readonly NormalizedOutputFile[]) {
182
+ for (const file of files) {
183
+ const staged = resolve(stagedRoot, file.path);
184
+ await mkdir(dirname(staged), { recursive: true });
185
+ await writeFile(staged, file.content);
186
+ }
187
+ }
188
+
189
+ async function commitBatch(
190
+ projectRoot: string,
191
+ stagedRoot: string,
192
+ backupRoot: string,
193
+ files: readonly NormalizedOutputFile[],
194
+ ): Promise<void> {
195
+ const committed: Array<{ target: string; backup: string | null }> = [];
196
+ try {
197
+ for (const file of files) {
198
+ const staged = resolve(stagedRoot, file.path);
199
+ const target = resolve(projectRoot, file.path);
200
+ const backup = resolve(backupRoot, file.path);
201
+ await mkdir(dirname(target), { recursive: true });
202
+ let prior: string | null = null;
203
+ if (await existingFile(target)) {
204
+ await mkdir(dirname(backup), { recursive: true });
205
+ await rename(target, backup);
206
+ prior = backup;
207
+ }
208
+ try {
209
+ await rename(staged, target);
210
+ } catch (error) {
211
+ if (prior) await rename(prior, target);
212
+ throw error;
213
+ }
214
+ committed.push({ target, backup: prior });
215
+ }
216
+ } catch (error) {
217
+ for (const entry of committed.reverse()) {
218
+ await rm(entry.target, { force: true });
219
+ if (entry.backup) await rename(entry.backup, entry.target);
220
+ }
221
+ throw error;
222
+ }
223
+ }
224
+
225
+ async function readProvenance(projectRoot: string) {
226
+ try {
227
+ const parsed: unknown = JSON.parse(
228
+ await readFile(resolve(projectRoot, PROJECT_PROVENANCE_PATH), 'utf8'),
229
+ );
230
+ return ProjectProvenanceDocumentSchema.parse(parsed);
231
+ } catch (error) {
232
+ if (!(error instanceof Error) || !('code' in error) || error.code !== 'ENOENT') throw error;
233
+ return emptyProjectProvenanceDocument();
234
+ }
235
+ }
236
+
237
+ function jsonSafeInput(input: unknown): unknown {
238
+ if (input === undefined) return undefined;
239
+ return sanitizeRecordedValue(input, new WeakSet());
240
+ }
241
+
242
+ function provenanceOperation(
243
+ provenanceContext: ProjectOutputProvenanceContext,
244
+ outputs: readonly HashedProjectFile[],
245
+ ) {
246
+ return ProjectProvenanceOperationSchema.parse({
247
+ createdAt: new Date().toISOString(),
248
+ operation: {
249
+ name: provenanceContext.operationName,
250
+ ...(provenanceContext.operationSource ? { source: provenanceContext.operationSource } : {}),
251
+ },
252
+ ...(provenanceContext.execution ? { execution: provenanceContext.execution } : {}),
253
+ ...(provenanceContext.executions ? { executions: provenanceContext.executions } : {}),
254
+ ...(provenanceContext.session ? { session: provenanceContext.session } : {}),
255
+ ...(provenanceContext.input === undefined
256
+ ? {}
257
+ : { input: jsonSafeInput(provenanceContext.input) }),
258
+ ...(provenanceContext.inputs && provenanceContext.inputs.length > 0
259
+ ? { inputs: [...provenanceContext.inputs] }
260
+ : {}),
261
+ outputs,
262
+ });
263
+ }
264
+
265
+ async function nextProvenanceFile(
266
+ projectRoot: string,
267
+ provenanceOperationId: string,
268
+ provenanceContext: ProjectOutputProvenanceContext,
269
+ outputs: readonly HashedProjectFile[],
270
+ ): Promise<NormalizedOutputFile> {
271
+ const provenance = await readProvenance(projectRoot);
272
+ const nextProvenance = ProjectProvenanceDocumentSchema.parse({
273
+ ...provenance,
274
+ operations: {
275
+ ...provenance.operations,
276
+ [provenanceOperationId]: provenanceOperation(provenanceContext, outputs),
277
+ },
278
+ });
279
+ return {
280
+ path: PROJECT_PROVENANCE_PATH,
281
+ content: `${JSON.stringify(nextProvenance, null, 2)}\n`,
282
+ mediaType: 'application/json',
283
+ role: 'provenance',
284
+ };
285
+ }
286
+
287
+ /**
288
+ * Both halves of "a read-modify-write of `.vgai/provenance.json` never loses a
289
+ * record", exactly as `asset-ledger-store.ts` holds them for `.vgai/assets.json`
290
+ * — the queue below is the in-process half, and it CANNOT see another process.
291
+ *
292
+ * The other process is ordinary now, not exotic: `vgai blender-mcp` mirrors a
293
+ * session's `public/` outputs in through this same writer while the editor
294
+ * server it is talking to may be committing a bake for the same project. Both
295
+ * read the whole document, add one operation, and write it back; interleaved,
296
+ * the later write wins and the earlier record is gone with no error anywhere.
297
+ */
298
+ async function serializeProjectCommit<T>(projectRoot: string, work: () => Promise<T>): Promise<T> {
299
+ const guarded = async () => {
300
+ const lockFile = `${resolve(projectRoot, PROJECT_PROVENANCE_PATH)}.lock`;
301
+ await mkdir(dirname(lockFile), { recursive: true });
302
+ return withExclusiveLock(ledgerLockIo(lockFile), work, { owner: `pid ${process.pid}` });
303
+ };
304
+ const previous = projectCommitQueues.get(projectRoot) ?? Promise.resolve();
305
+ const current = previous.catch(() => undefined).then(guarded);
306
+ projectCommitQueues.set(projectRoot, current);
307
+ try {
308
+ return await current;
309
+ } finally {
310
+ if (projectCommitQueues.get(projectRoot) === current) projectCommitQueues.delete(projectRoot);
311
+ }
312
+ }
313
+
314
+ export function createProjectOutputWriter(
315
+ projectRoot: string,
316
+ provenanceContext: ProjectOutputProvenanceContext = {
317
+ operationName: 'project.output.write',
318
+ },
319
+ ): ProjectOutputWriter {
320
+ return {
321
+ async write(files, options = {}): Promise<ProjectGeneratedOutput> {
322
+ const { normalized, summaries, totalBytes } = validateBatch(files);
323
+ if (options.dryRun === true) {
324
+ return { files: summaries, totalBytes, dryRun: true };
325
+ }
326
+
327
+ // Capture request-scoped execution facts synchronously, then enqueue
328
+ // before doing any filesystem-backed billing lookup. Otherwise two
329
+ // writes invoked in order can reach the commit queue in the opposite
330
+ // order when the first lookup yields longer than the second.
331
+ const capturedProvenanceContext = withCapturedExecutions(provenanceContext);
332
+
333
+ return serializeProjectCommit(projectRoot, async () => {
334
+ const effectiveProvenanceContext = await withGenerationBilling(
335
+ projectRoot,
336
+ capturedProvenanceContext,
337
+ );
338
+ const provenanceOperationId = randomUUID();
339
+ const hashedFiles: HashedProjectFile[] = normalized.map((file) => ({
340
+ path: file.path,
341
+ bytes: byteLength(file.content),
342
+ sha256: sha256(file.content),
343
+ ...(file.mediaType ? { mediaType: file.mediaType } : {}),
344
+ ...(file.role ? { role: file.role } : {}),
345
+ }));
346
+ const provenanceFile = await nextProvenanceFile(
347
+ projectRoot,
348
+ provenanceOperationId,
349
+ effectiveProvenanceContext,
350
+ hashedFiles,
351
+ );
352
+ const committedFiles = [...normalized, provenanceFile];
353
+ const transactionRoot = resolve(
354
+ projectRoot,
355
+ '.vgai',
356
+ 'tmp',
357
+ `project-output-${provenanceOperationId}`,
358
+ );
359
+ const stagedRoot = resolve(transactionRoot, 'staged');
360
+ const backupRoot = resolve(transactionRoot, 'backup');
361
+ try {
362
+ await stageBatch(stagedRoot, committedFiles);
363
+ await commitBatch(projectRoot, stagedRoot, backupRoot, committedFiles);
364
+ } finally {
365
+ await rm(transactionRoot, { recursive: true, force: true });
366
+ }
367
+
368
+ return {
369
+ files: summaries,
370
+ totalBytes,
371
+ dryRun: false,
372
+ provenanceOperationId,
373
+ };
374
+ });
375
+ },
376
+ };
377
+ }
378
+
379
+ /** Idempotently repairs the permanent billing snapshot after an accept tool
380
+ * returns its final settlement. Acceptance writes bytes before its provider
381
+ * mapper can update the operational job, so this second phase is also run by
382
+ * startup reconciliation to close the crash window between those commits. */
383
+ export async function reconcileAcceptedGenerationProvenance(
384
+ projectRoot: string,
385
+ job: GenerationJob,
386
+ ): Promise<boolean> {
387
+ if (!job.acceptedAt || !job.provenanceOperationId) return false;
388
+ const provenanceOperationId = job.provenanceOperationId;
389
+ return serializeProjectCommit(projectRoot, async () => {
390
+ const provenance = await readProvenance(projectRoot);
391
+ const operation = provenance.operations[provenanceOperationId];
392
+ if (!operation) return false;
393
+ const matches = (execution: ProjectProvenanceExecution) =>
394
+ execution.provider === job.provider &&
395
+ (execution.requestId === job.externalId || execution.taskId === job.externalId);
396
+ let changed = false;
397
+ let nextOperation = operation;
398
+ if (operation.execution && matches(operation.execution)) {
399
+ changed = JSON.stringify(operation.execution.billing) !== JSON.stringify(job.billing);
400
+ nextOperation = { ...operation, execution: { ...operation.execution, billing: job.billing } };
401
+ } else if (operation.executions) {
402
+ const executions = operation.executions.map((execution) => {
403
+ if (!matches(execution)) return execution;
404
+ if (JSON.stringify(execution.billing) !== JSON.stringify(job.billing)) changed = true;
405
+ return { ...execution, billing: job.billing };
406
+ });
407
+ nextOperation = { ...operation, executions };
408
+ }
409
+ if (!changed) return false;
410
+ const next = ProjectProvenanceDocumentSchema.parse({
411
+ ...provenance,
412
+ operations: { ...provenance.operations, [provenanceOperationId]: nextOperation },
413
+ });
414
+ const path = resolve(projectRoot, PROJECT_PROVENANCE_PATH);
415
+ const temporary = `${path}.${randomUUID()}.tmp`;
416
+ await writeFile(temporary, `${JSON.stringify(next, null, 2)}\n`);
417
+ try {
418
+ await rename(temporary, path);
419
+ } finally {
420
+ await rm(temporary, { force: true });
421
+ }
422
+ return true;
423
+ });
424
+ }
425
+
426
+ /** The `mediaType` an output's extension implies. Exported because every
427
+ * writer that commits bytes it did not choose the type of needs the same
428
+ * table — the CLI's Blender write-back door among them — and two tables
429
+ * drift. */
430
+ export function projectOutputMediaType(path: string): string | undefined {
431
+ switch (extname(path).toLowerCase()) {
432
+ case '.glb':
433
+ return 'model/gltf-binary';
434
+ case '.gltf':
435
+ return 'model/gltf+json';
436
+ case '.png':
437
+ return 'image/png';
438
+ case '.mp4':
439
+ return 'video/mp4';
440
+ case '.webm':
441
+ return 'video/webm';
442
+ case '.webp':
443
+ return 'image/webp';
444
+ case '.jpg':
445
+ case '.jpeg':
446
+ return 'image/jpeg';
447
+ case '.json':
448
+ return 'application/json';
449
+ case '.hdr':
450
+ return 'image/vnd.radiance';
451
+ default:
452
+ return undefined;
453
+ }
454
+ }
455
+
456
+ function stagedRole(path: string): ProjectOutputFile['role'] {
457
+ if (path.endsWith('/.vgai-thumbnail.webp')) return 'other';
458
+ return 'asset';
459
+ }
460
+
461
+ async function describeStagedDirectory(
462
+ stagedDirectory: string,
463
+ destinationProjectPath: string,
464
+ ): Promise<HashedProjectFile[]> {
465
+ const outputs: HashedProjectFile[] = [];
466
+ async function walk(directory: string): Promise<void> {
467
+ const entries = await readdir(directory, { withFileTypes: true });
468
+ for (const entry of entries) {
469
+ const absolute = resolve(directory, entry.name);
470
+ if (entry.isDirectory()) {
471
+ await walk(absolute);
472
+ continue;
473
+ }
474
+ if (!entry.isFile()) {
475
+ throw new Error(
476
+ `Staged project output contains an unsupported filesystem entry: ${absolute}`,
477
+ );
478
+ }
479
+ const relativeFile = relative(stagedDirectory, absolute).split(sep).join('/');
480
+ const path = posix.join(destinationProjectPath, relativeFile);
481
+ const info = await stat(absolute);
482
+ const mediaType = projectOutputMediaType(path);
483
+ outputs.push({
484
+ path,
485
+ bytes: info.size,
486
+ sha256: await sha256File(absolute),
487
+ ...(mediaType ? { mediaType } : {}),
488
+ role: stagedRole(path),
489
+ });
490
+ }
491
+ }
492
+ await walk(stagedDirectory);
493
+ outputs.sort((left, right) => left.path.localeCompare(right.path));
494
+ if (outputs.length === 0) throw new Error('Staged project output directory is empty.');
495
+ return outputs;
496
+ }
497
+
498
+ async function pathExists(path: string): Promise<boolean> {
499
+ try {
500
+ await stat(path);
501
+ return true;
502
+ } catch (error) {
503
+ if (error instanceof Error && 'code' in error && error.code === 'ENOENT') return false;
504
+ throw error;
505
+ }
506
+ }
507
+
508
+ /**
509
+ * RE-RECORD BYTES THAT ARE ALREADY ON DISK, against the door that builds them
510
+ * today — without touching a single one of them.
511
+ *
512
+ * Every other path here WRITES: it stages bytes a generator just produced and
513
+ * commits them with the record of the operation that produced them. This one
514
+ * writes nothing but the ledger. It hashes the files where they lie and
515
+ * appends ONE `project.provenance.attest` operation naming them.
516
+ *
517
+ * WHEN IT IS THE RIGHT ANSWER, and it is a narrow case: a project ships a
518
+ * binary whose ledger record names a tool that no longer exists (renamed,
519
+ * folded into another capability, deleted), so nothing tells a reader which
520
+ * door rebuilds it — and re-running the live door WOULD change the bytes the
521
+ * project ships. Re-baking is the better answer whenever the bytes may move;
522
+ * an attest is for when they may not. It never edits or removes the old
523
+ * record: that record is what happened.
524
+ *
525
+ * The claim it makes is deliberately weak, and `input.reason` is REQUIRED by
526
+ * `scripts/validate-project-provenance.mjs` to keep it honest — see
527
+ * {@link PROJECT_ATTEST_OPERATION}. `attests` names the live operation.
528
+ *
529
+ * Driven by `scripts/attest-project-output.ts`.
530
+ */
531
+ export async function attestExistingProjectOutputs(options: {
532
+ projectRoot: string;
533
+ /** Project-relative paths that must ALREADY exist. Nothing is written to them. */
534
+ paths: readonly string[];
535
+ /** Why the door was not simply re-run. Recorded verbatim as `input.reason`. */
536
+ reason: string;
537
+ /** The operation that produces these bytes today, and where it lives. */
538
+ attests: { operation: string; source?: string; input?: unknown };
539
+ }): Promise<{ provenanceOperationId: string; files: ProjectGeneratedOutputFile[] }> {
540
+ if (options.paths.length === 0) throw new Error('attest: no output paths given.');
541
+ if (options.reason.trim().length === 0) {
542
+ throw new Error(
543
+ 'attest: `reason` is required and must be non-empty — an attest is the weakest ' +
544
+ 'claim in the ledger and says in writing why the door was not re-run.',
545
+ );
546
+ }
547
+ const outputs: HashedProjectFile[] = [];
548
+ for (const raw of options.paths) {
549
+ const path = normalizeOutputPath(raw);
550
+ const absolute = resolve(options.projectRoot, path);
551
+ if (!(await existingFile(absolute))) {
552
+ throw new Error(
553
+ `attest: ${path} does not exist. An attest records bytes already on disk; ` +
554
+ 'it never creates them.',
555
+ );
556
+ }
557
+ const info = await stat(absolute);
558
+ const mediaType = projectOutputMediaType(path);
559
+ outputs.push({
560
+ path,
561
+ bytes: info.size,
562
+ sha256: await sha256File(absolute),
563
+ ...(mediaType ? { mediaType } : {}),
564
+ role: 'asset',
565
+ });
566
+ }
567
+ outputs.sort((left, right) => left.path.localeCompare(right.path));
568
+
569
+ return serializeProjectCommit(options.projectRoot, async () => {
570
+ const provenanceOperationId = randomUUID();
571
+ const provenanceFile = await nextProvenanceFile(
572
+ options.projectRoot,
573
+ provenanceOperationId,
574
+ {
575
+ operationName: PROJECT_ATTEST_OPERATION,
576
+ input: {
577
+ reason: options.reason,
578
+ attests: {
579
+ operation: options.attests.operation,
580
+ ...(options.attests.source ? { source: options.attests.source } : {}),
581
+ ...(options.attests.input === undefined ? {} : { input: options.attests.input }),
582
+ },
583
+ },
584
+ },
585
+ outputs,
586
+ );
587
+ const transactionRoot = resolve(
588
+ options.projectRoot,
589
+ '.vgai',
590
+ 'tmp',
591
+ `project-attest-${provenanceOperationId}`,
592
+ );
593
+ try {
594
+ await stageBatch(resolve(transactionRoot, 'staged'), [provenanceFile]);
595
+ await commitBatch(
596
+ options.projectRoot,
597
+ resolve(transactionRoot, 'staged'),
598
+ resolve(transactionRoot, 'backup'),
599
+ [provenanceFile],
600
+ );
601
+ } finally {
602
+ await rm(transactionRoot, { recursive: true, force: true });
603
+ }
604
+ return {
605
+ provenanceOperationId,
606
+ files: outputs.map(({ sha256: _sha256, ...file }) => file),
607
+ };
608
+ });
609
+ }
610
+
611
+ /**
612
+ * Commits an already-streamed directory and the central provenance rewrite as
613
+ * one rollback-safe project transaction. Catalog acquisition uses this path so
614
+ * large assets never need to be buffered into ProjectOutputFile.content.
615
+ */
616
+ export async function commitStagedProjectDirectory(options: {
617
+ projectRoot: string;
618
+ stagedDirectory: string;
619
+ destination: string;
620
+ provenance: ProjectOutputProvenanceContext;
621
+ }): Promise<ProjectGeneratedOutput> {
622
+ const destinationProjectPath = normalizeOutputPath(
623
+ relative(options.projectRoot, options.destination).split(sep).join('/'),
624
+ );
625
+ const outputs = await describeStagedDirectory(options.stagedDirectory, destinationProjectPath);
626
+ const summaries: ProjectGeneratedOutputFile[] = outputs.map(
627
+ ({ sha256: _sha256, ...file }) => file,
628
+ );
629
+ const totalBytes = summaries.reduce((total, file) => total + file.bytes, 0);
630
+
631
+ return serializeProjectCommit(options.projectRoot, async () => {
632
+ if (await pathExists(options.destination)) {
633
+ throw new Error(`Destination already exists and was not overwritten: ${options.destination}`);
634
+ }
635
+ const provenanceOperationId = randomUUID();
636
+ const provenanceFile = await nextProvenanceFile(
637
+ options.projectRoot,
638
+ provenanceOperationId,
639
+ options.provenance,
640
+ outputs,
641
+ );
642
+ const transactionRoot = resolve(
643
+ options.projectRoot,
644
+ '.vgai',
645
+ 'tmp',
646
+ `project-directory-${provenanceOperationId}`,
647
+ );
648
+ const stagedRoot = resolve(transactionRoot, 'staged');
649
+ const backupRoot = resolve(transactionRoot, 'backup');
650
+ let directoryCommitted = false;
651
+ try {
652
+ await stageBatch(stagedRoot, [provenanceFile]);
653
+ await mkdir(dirname(options.destination), { recursive: true });
654
+ await rename(options.stagedDirectory, options.destination);
655
+ directoryCommitted = true;
656
+ await commitBatch(options.projectRoot, stagedRoot, backupRoot, [provenanceFile]);
657
+ } catch (error) {
658
+ if (directoryCommitted) {
659
+ try {
660
+ await rename(options.destination, options.stagedDirectory);
661
+ } catch (rollbackError) {
662
+ throw new AggregateError(
663
+ [error, rollbackError],
664
+ 'Project directory transaction and its rollback both failed.',
665
+ );
666
+ }
667
+ }
668
+ throw error;
669
+ } finally {
670
+ await rm(transactionRoot, { recursive: true, force: true });
671
+ }
672
+ return {
673
+ files: summaries,
674
+ totalBytes,
675
+ dryRun: false,
676
+ provenanceOperationId,
677
+ };
678
+ });
679
+ }