@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,47 @@
1
+ import path from 'node:path';
2
+
3
+ /** Scratch belongs to its project, not to the project a study may be opened in. */
4
+ export function isProjectScratchPath(filename: string, roots: Iterable<string>): boolean {
5
+ const file = path.resolve(filename);
6
+ let owner = '';
7
+ for (const candidate of roots) {
8
+ const root = path.resolve(candidate);
9
+ if (root.length > owner.length && (file === root || file.startsWith(root + path.sep))) {
10
+ owner = root;
11
+ }
12
+ }
13
+ if (!owner) return false;
14
+ const [directory, child] = path.relative(owner, file).split(path.sep);
15
+ return directory === '.vgai' && child === 'tmp';
16
+ }
17
+
18
+ /**
19
+ * An agent-workspace path that is NOT this server's own source.
20
+ *
21
+ * Agent/IDE worktrees and scratch live under `<checkout>/.claude/`, and Vite
22
+ * full-reloads every connected tab when a file under its root changes — so one
23
+ * agent's worktree churn was reloading every OTHER editor served from the
24
+ * checkout (a tab kicked mid-boot). Hence the ignore. But a server can also BE
25
+ * served FROM one of those worktrees, and the path-shaped ignore (`.claude/**`)
26
+ * could not tell the two apart: it swallowed the worktree's own source, so that
27
+ * editor silently stopped watching the very files it serves. MEASURED
28
+ * 2026-09-18: an edit to `editor-chrome-capture.ts` in an agent worktree never
29
+ * reached the page — the dev server transformed the new module on request while
30
+ * the tab kept running the old one, with nothing reporting a problem, and the
31
+ * only way to see a source edit was to restart the session.
32
+ *
33
+ * The discriminator is OWNERSHIP, not the path's shape: a file inside
34
+ * `serverRoot` whose path below that root holds no `.claude` segment is the
35
+ * server's own source and is watched. Everything else under a `.claude`
36
+ * directory — a sibling worktree, the checkout's own agent scratch, this
37
+ * worktree's `.claude/` — is ignored exactly as before, so a server rooted at
38
+ * the checkout itself keeps today's behaviour for every path.
39
+ */
40
+ export function isForeignAgentPath(filename: string, serverRoot: string): boolean {
41
+ const file = path.resolve(filename);
42
+ const segments = file.split(path.sep);
43
+ if (!segments.includes('.claude')) return false;
44
+ const root = path.resolve(serverRoot);
45
+ if (file !== root && !file.startsWith(root + path.sep)) return true;
46
+ return path.relative(root, file).split(path.sep).includes('.claude');
47
+ }
@@ -0,0 +1,619 @@
1
+ /**
2
+ * The editor's project-script HMR hook — ONE copy, shared by `dev.ts` and
3
+ * `packaged.ts` (both used to carry a hand-maintained "byte-identical" copy).
4
+ *
5
+ * IT RUNS ON VITE'S `hotUpdate`, NOT `handleHotUpdate`, AND THAT IS THE POINT
6
+ * -------------------------------------------------------------------------
7
+ * Vite calls the legacy `handleHotUpdate` hook for `type === 'update'` ONLY
8
+ * (`handleHMRUpdate`, vite 6.4.3). The watcher's `add`/`unlink` path emits
9
+ * `'create'`/`'delete'` instead, so for two years every delete and every
10
+ * create of a project file went past this seam entirely: the running game kept
11
+ * the vanished module, nothing set `restartRequired`, nothing was printed, and
12
+ * vite fanned a useless HMR update across every accumulated `?vgai-mount=N`
13
+ * variant of the project's modules (measured at 7 and 14 variants; the only
14
+ * trace was `[vite] Failed to reload` in the page console, and often not even
15
+ * that). The modern `hotUpdate` hook receives all three types, so the editor
16
+ * now owns the whole file-event vocabulary — see
17
+ * {@link handleProjectScriptHotUpdate}'s create/delete branch.
18
+ *
19
+ * WHY THIS MODULE EXISTS AT ALL: `vgai restart` served STALE CODE
20
+ * ---------------------------------------------------------------
21
+ * Measured 2026-08-02, live: editing `src/components/Dragon.tsx` (a component
22
+ * the R3F entry imports) and then running `vgai restart` + play left the edit
23
+ * UNAPPLIED, while an edit to `src/world.tsx` (the entry ITSELF) applied after
24
+ * the same restart. Only closing the session and re-running `npm run dev`
25
+ * picked the component edit up — i.e. the documented restart contract ("so
26
+ * setup and disposal rerun") was silently running the pre-edit module.
27
+ *
28
+ * The mechanism, end to end:
29
+ *
30
+ * 1. This hook classifies a project source change and, for the kinds the
31
+ * editor drives itself (`r3f-entry`/`component`/`restart`), sends its OWN
32
+ * custom websocket event and returns `[]` — deliberately swallowing
33
+ * Vite's stock HMR propagation, because stock HMR on an R3F-dialect
34
+ * module bubbles to a full page reload (W4).
35
+ * 2. Returning `[]` means Vite never calls `updateModules`. The only
36
+ * invalidation that ran is the watcher's `moduleGraph.onFileChange`,
37
+ * which calls `invalidateModule(mod, seen)` with `isHmr === false` — that
38
+ * branch sets `lastInvalidationTimestamp` and leaves `lastHMRTimestamp`
39
+ * at 0 (vite 6.4.1, `ModuleGraph.invalidateModule`).
40
+ * 3. Vite's import-analysis appends the `?t=<ts>` cache-busting query to a
41
+ * static import ONLY when `depModule.lastHMRTimestamp > 0` (both the full
42
+ * transform path and `handleModuleSoftInvalidation`'s rewrite path check
43
+ * exactly that field).
44
+ * 4. So when play remounts and the realm's entry loader
45
+ * (`src/realm-services.ts`) re-imports the ENTRY with
46
+ * its own `?vgai-play=<n>` buster, the freshly transformed entry still
47
+ * points at the BYTE-IDENTICAL `/@fs/.../Dragon.tsx` URL the browser
48
+ * already has in its ES module registry. Browser module identity is
49
+ * per-URL, so the browser reuses the pre-edit module. The entry is fresh;
50
+ * everything it imports is stale.
51
+ *
52
+ * THE FIX is one line of intent: when this hook swallows Vite's HMR, it must
53
+ * still do the half of `updateModules` that the module graph needs — stamp
54
+ * the changed file's modules as HMR-invalidated (`isHmr: true`), which
55
+ * propagates to their importers and gives every ancestor a fresh `?t=` for
56
+ * the changed module on its next transform. Cache-busting the entry then
57
+ * genuinely re-evaluates the whole edited subgraph, which is what "restart"
58
+ * always claimed to do.
59
+ *
60
+ * `stampHmrInvalidation` is deliberately defensive about the graph's shape:
61
+ * if a module graph ever stops offering the invalidation API, this hook says
62
+ * so LOUDLY and names the file, rather than swallowing HMR into silence and
63
+ * letting a restart remount old code again.
64
+ */
65
+
66
+ import { createHash } from 'node:crypto';
67
+ import { relative } from 'node:path';
68
+ import {
69
+ classifyProjectHotUpdate,
70
+ type ProjectHotUpdateKind,
71
+ reactRefreshBoundaryExports,
72
+ } from './project-hmr-files';
73
+ import {
74
+ importersFromModuleGraph,
75
+ type ModuleGraphLike,
76
+ resolveOidSurface,
77
+ } from './project-root-surface';
78
+
79
+ /** Structural stand-in for a Vite `ModuleNode` (never imported from `vite` —
80
+ * this file holds the same dependency-light bar as `project-root-surface`). */
81
+ export interface HmrModuleNodeLike {
82
+ readonly url?: string | undefined;
83
+ readonly id?: string | null | undefined;
84
+ readonly file?: string | null | undefined;
85
+ readonly isSelfAccepting?: boolean | undefined;
86
+ /** Vite's `ModuleNode.importers` — read by {@link stampHmrInvalidation}'s
87
+ * boundary pre-walk; optional so a bare graph stays acceptable. */
88
+ readonly importers?: Iterable<HmrModuleNodeLike> | undefined;
89
+ }
90
+
91
+ /** The slice of Vite's `ModuleGraph` this module needs, both members optional
92
+ * so a caller can hand over any graph-shaped object and get an honest
93
+ * `supported: false` rather than a crash.
94
+ *
95
+ * METHOD syntax, deliberately: TypeScript checks method parameters
96
+ * bivariantly and property-typed function parameters contravariantly, and
97
+ * the whole point of this interface is that Vite's REAL `ModuleGraph`
98
+ * (whose `ModuleNode` is far richer than `HmrModuleNodeLike`) satisfies it. */
99
+ export interface HmrInvalidationGraph {
100
+ getModulesByFile?(file: string): Iterable<HmrModuleNodeLike> | undefined;
101
+ invalidateModule?(
102
+ mod: HmrModuleNodeLike,
103
+ seen?: Set<HmrModuleNodeLike>,
104
+ timestamp?: number,
105
+ isHmr?: boolean,
106
+ softInvalidate?: boolean,
107
+ ): void;
108
+ }
109
+
110
+ export type ScriptHmrModuleGraph = ModuleGraphLike & HmrInvalidationGraph;
111
+
112
+ /** Project documents can import helpers without being React boundaries.
113
+ * Report actual dependent files so a Model reloads for its own dependencies,
114
+ * never for every unrelated save in the project. Include every loaded variant. */
115
+ export function affectedProjectFiles(
116
+ graph: HmrInvalidationGraph,
117
+ file: string,
118
+ projectRoot: string,
119
+ ): string[] {
120
+ const files = new Set([file.replaceAll('\\', '/')]);
121
+ const seen = new Set<HmrModuleNodeLike>();
122
+ const visit = (node: HmrModuleNodeLike): void => {
123
+ if (seen.has(node)) return;
124
+ seen.add(node);
125
+ if (node.file) {
126
+ const path = relative(projectRoot, node.file);
127
+ if (path === '..' || path.startsWith('../')) return;
128
+ files.add(node.file.replaceAll('\\', '/'));
129
+ }
130
+ for (const importer of node.importers ?? []) visit(importer);
131
+ };
132
+ for (const node of graph.getModulesByFile?.(file) ?? []) visit(node);
133
+ return [...files].sort();
134
+ }
135
+
136
+ /** The minimal dev-server shape this hook drives. */
137
+ export interface ScriptHmrServerLike {
138
+ ws: { send: (msg: unknown) => void };
139
+ moduleGraph: ScriptHmrModuleGraph;
140
+ }
141
+
142
+ /** The slice of vite's `HotUpdateOptions` the editor's plugin reads —
143
+ * structural, so neither host has to import `vite` to declare its hook. */
144
+ export interface ScriptHmrHostOptions {
145
+ readonly file: string;
146
+ readonly type: ProjectFileEventType;
147
+ readonly timestamp?: number;
148
+ readonly server: ScriptHmrServerLike;
149
+ }
150
+
151
+ /** The `this` vite binds on `hotUpdate` — the environment whose pass this is. */
152
+ export interface ScriptHmrHookContext {
153
+ readonly environment?: { readonly name?: string } | undefined;
154
+ }
155
+
156
+ /**
157
+ * Does this update kind SWALLOW Vite's own HMR propagation (return `[]`)?
158
+ *
159
+ * Stated as the complement on purpose: the three kinds below return EARLY, so
160
+ * stock Vite HMR runs `updateModules` and stamps the graph for us. Everything
161
+ * else — including `ignore` — reaches `return []`, and therefore has to be
162
+ * stamped by hand or an edit to it can survive a remount. Writing this as a
163
+ * positive list of "the kinds I remembered" is how `ignore` would quietly
164
+ * become a second hole.
165
+ */
166
+ export function swallowsViteHmr(kind: ProjectHotUpdateKind): boolean {
167
+ return kind !== 'outside' && kind !== 'stock-data' && kind !== 'react' && kind !== 'r3f-refresh';
168
+ }
169
+
170
+ /** What {@link stampHmrInvalidation} did, so the caller can report honestly. */
171
+ export interface HmrStampOutcome {
172
+ /** False when the graph does not expose the invalidation API at all — the
173
+ * ONE case where an edited module provably cannot be re-evaluated by a
174
+ * remount, and therefore the one case that must be shouted about. */
175
+ readonly supported: boolean;
176
+ /** Module urls/ids that were stamped. Empty with `supported: true` simply
177
+ * means the file has no module-graph node yet — it was never loaded, so
178
+ * it cannot be stale. */
179
+ readonly stamped: readonly string[];
180
+ }
181
+
182
+ /**
183
+ * Mark every module of `file` as HMR-invalidated, the way Vite's own
184
+ * `updateModules` would have, so import-analysis re-stamps `?t=` on it for
185
+ * every importer. Propagation to importers is `invalidateModule`'s own job
186
+ * (it walks `mod.importers` with the same `isHmr` flag).
187
+ *
188
+ * `stopAt` BOUNDS that propagation at the editor's own modules, and its
189
+ * absence was a live defect (measured on bubbo-bubbo, 2026-08-21): a
190
+ * creation-site write to the game's source stamped the changed module, and
191
+ * the importer walk climbed THROUGH the isolation-document's import edge into
192
+ * editor chrome — `play-mode.ts` among the ancestors. Editor chrome is full
193
+ * of lazy `await import('./x')` seams, and the next one to fire after the
194
+ * stamp fetched a SECOND `play-mode.ts?t=…` instance: `GamePanel` then
195
+ * reported its container to the new instance while the mount path read the
196
+ * old one, and every subsequent ▶ refused with "Game container not mounted"
197
+ * until a full page reload. A game edit re-evaluates the GAME's subgraph
198
+ * (the entry re-import's own cache-buster sees the fresh `?t=`); it must
199
+ * never re-instance editor-chrome singletons mid-session. The boundary works
200
+ * by pre-seeding `invalidateModule`'s `seen` set: a module already in `seen`
201
+ * is skipped AND its importers are not walked, which is exactly "stop here".
202
+ */
203
+ export function stampHmrInvalidation(
204
+ graph: HmrInvalidationGraph | undefined,
205
+ file: string,
206
+ timestamp: number = Date.now(),
207
+ stopAt?: (moduleFile: string) => boolean,
208
+ ): HmrStampOutcome {
209
+ if (!graph || typeof graph.getModulesByFile !== 'function')
210
+ return { supported: false, stamped: [] };
211
+ if (typeof graph.invalidateModule !== 'function') return { supported: false, stamped: [] };
212
+ const mods = graph.getModulesByFile(file);
213
+ if (!mods) return { supported: true, stamped: [] };
214
+ const stamped: string[] = [];
215
+ if (stopAt) {
216
+ // BOUNDED. Vite's `seen` is a CYCLE guard, not a fence: `invalidateModule`
217
+ // assigns `invalidationState` BEFORE its early-return check, and only
218
+ // returns for a seen module WHEN THAT ASSIGNMENT CHANGED NOTHING
219
+ // (`if (seen.has(mod) && prevInvalidationState === mod.invalidationState)
220
+ // return`, vite 6.4.3). A fresh module in `seen` therefore still gets
221
+ // stamped and walked through — measured on bubbo-bubbo: every seeding
222
+ // strategy shipped 33 editor-module stamps per write, identically. The
223
+ // fence that actually holds is PRE-ARMING each boundary module's
224
+ // `invalidationState` to the exact value both walk arms would assign:
225
+ // the hard arm re-assigns `'HARD_INVALIDATED'` (no change) and the soft
226
+ // arm's `??=` keeps it (no change), so the early return finally fires.
227
+ // Pre-arming is behaviorally free for the boundary module itself — its
228
+ // `transformResult` cache is untouched, and the soft-invalidation
229
+ // replay path only consumes `invalidationState` after an invalidation
230
+ // nulled that cache.
231
+ const boundary = new Set<HmrModuleNodeLike>();
232
+ const visited = new Set<HmrModuleNodeLike>([...mods]);
233
+ const queue = [...visited];
234
+ while (queue.length > 0) {
235
+ const mod = queue.pop() as HmrModuleNodeLike;
236
+ for (const importer of mod.importers ?? []) {
237
+ if (visited.has(importer)) continue;
238
+ visited.add(importer);
239
+ if (typeof importer.file === 'string' && stopAt(importer.file)) {
240
+ boundary.add(importer);
241
+ continue;
242
+ }
243
+ queue.push(importer);
244
+ }
245
+ }
246
+ for (const node of boundary) {
247
+ // The mixed backward-compat graph hands out WRAPPERS whose state lives
248
+ // on the per-environment halves; a plain environment graph's node holds
249
+ // the field itself. Write whichever exists.
250
+ const halves = node as {
251
+ _clientModule?: { invalidationState?: unknown };
252
+ _ssrModule?: { invalidationState?: unknown };
253
+ invalidationState?: unknown;
254
+ };
255
+ if (halves._clientModule) halves._clientModule.invalidationState = 'HARD_INVALIDATED';
256
+ if (halves._ssrModule) halves._ssrModule.invalidationState = 'HARD_INVALIDATED';
257
+ if (!halves._clientModule && !halves._ssrModule) {
258
+ halves.invalidationState = 'HARD_INVALIDATED';
259
+ }
260
+ }
261
+ const seen = new Set<HmrModuleNodeLike>(boundary);
262
+ for (const mod of mods) {
263
+ graph.invalidateModule(mod, seen, timestamp, true);
264
+ stamped.push(mod.url ?? mod.id ?? file);
265
+ }
266
+ return { supported: true, stamped };
267
+ }
268
+ const seen = new Set<HmrModuleNodeLike>();
269
+ for (const mod of mods) {
270
+ graph.invalidateModule(mod, seen, timestamp, true);
271
+ stamped.push(mod.url ?? mod.id ?? file);
272
+ }
273
+ return { supported: true, stamped };
274
+ }
275
+
276
+ /**
277
+ * The loud warning for the one genuinely-uninvalidatable case. Pure so the
278
+ * exact wording is a unit-testable contract rather than an inline string: a
279
+ * silent stale remount is the defect this whole module exists to prevent, so
280
+ * the failure to prevent it must NAME the module.
281
+ */
282
+ export function staleModuleWarning(file: string, outcome: HmrStampOutcome): string | null {
283
+ if (outcome.supported) return null;
284
+ return (
285
+ `vgai: ${file} changed, but this dev server's module graph does not support HMR ` +
286
+ 'invalidation — a play restart will re-run setup against the STALE copy of that ' +
287
+ 'module. Reload the editor page to pick the edit up.'
288
+ );
289
+ }
290
+
291
+ /** Vite's `HotUpdateOptions['type']`, restated so this module keeps its
292
+ * never-import-`vite` bar. */
293
+ export type ProjectFileEventType = 'create' | 'update' | 'delete';
294
+
295
+ /** Everything `handleProjectScriptHotUpdate` needs from its plugin host. */
296
+ export interface ProjectScriptHotUpdateArgs {
297
+ readonly file: string;
298
+ readonly projectRoot: string;
299
+ /** Which watcher event this is. Defaults to `'update'` so a caller that only
300
+ * ever had edits keeps its old meaning. */
301
+ readonly type?: ProjectFileEventType | undefined;
302
+ /** The changed file's source, or `''` when there is none to read — a
303
+ * non-script file, or a file that has just been DELETED (the caller reads
304
+ * it; this module does no I/O). */
305
+ readonly source: string;
306
+ readonly server: ScriptHmrServerLike;
307
+ /**
308
+ * Which of vite's environments this invocation is for. `hotUpdate` runs once
309
+ * per environment (client, then ssr), and the editor's side effects — the
310
+ * module-graph stamp and the custom websocket event — belong to the CLIENT
311
+ * pass alone: the ssr pass would double-send both. Non-client passes still
312
+ * return the same swallow/pass-through decision so vite's own propagation
313
+ * stays consistent across environments.
314
+ */
315
+ readonly environment?: string | undefined;
316
+ readonly timestamp?: number | undefined;
317
+ /** Defaults to `console.warn`; injected in tests. */
318
+ readonly warn?: ((message: string) => void) | undefined;
319
+ }
320
+
321
+ /**
322
+ * Fast Refresh boundary status of the LAST source this hook saw for a file.
323
+ *
324
+ * React Refresh validates a boundary by COMPARING the loaded module's exports
325
+ * with the incoming ones, so the hazard is a TRANSITION, not a state: the
326
+ * update that REMOVES a non-component export invalidates exactly as hard as
327
+ * the one that adds it (measured live — removing the `export` keyword again
328
+ * full-reloaded the editor even though the new source is a perfectly good
329
+ * boundary). Judging the incoming source alone therefore closes only half the
330
+ * hole; the previous source has to be remembered.
331
+ *
332
+ * The serving plugin records initial client transforms as well as updates,
333
+ * so the first edit after loading mixed exports cannot skip the transition.
334
+ */
335
+ const lastSeenBoundary = new Map<string, readonly string[] | null>();
336
+
337
+ /** Clears the memo above so a test can start from a known first-sight state. */
338
+ export function resetReactBoundaryMemoForTest(): void {
339
+ lastSeenBoundary.clear();
340
+ }
341
+
342
+ /** Record the source actually served, including the initial mixed-export case. */
343
+ export function recordReactBoundary(file: string, source: string): void {
344
+ if (/\.[jt]sx$/.test(file)) lastSeenBoundary.set(file, reactRefreshBoundaryExports(source));
345
+ }
346
+
347
+ /**
348
+ * Record this source's boundary status and downgrade a `react` classification
349
+ * to `restart` unless BOTH the previous and the incoming source are Fast
350
+ * Refresh boundaries. Runs for every `.tsx`/`.jsx` update, whatever its kind,
351
+ * so the memo also records the versions that never rode stock HMR.
352
+ */
353
+ function trackReactBoundary(
354
+ kind: ProjectHotUpdateKind,
355
+ file: string,
356
+ source: string,
357
+ ): ProjectHotUpdateKind {
358
+ if (!/\.(tsx|jsx)$/.test(file)) return kind;
359
+ const isBoundary = reactRefreshBoundaryExports(source);
360
+ const wasBoundary = lastSeenBoundary.has(file) ? lastSeenBoundary.get(file)! : isBoundary;
361
+ lastSeenBoundary.set(file, isBoundary);
362
+ if (kind !== 'react' && kind !== 'r3f-refresh') return kind;
363
+ return isBoundary && wasBoundary && isBoundary.join('\0') === wasBoundary.join('\0')
364
+ ? kind
365
+ : kind === 'r3f-refresh'
366
+ ? 'r3f-entry'
367
+ : 'restart';
368
+ }
369
+
370
+ /** A plain model/helper module may use Vite's dependency propagation only
371
+ * when EVERY loaded importer path ends at a proven R3F refresh boundary.
372
+ * Dead ends, cycles, mixed exports and paths into editor code retain the
373
+ * controlled fallback. The URLs are Vite's own, including mount variants.
374
+ */
375
+ export function r3fDependencyBoundaries(
376
+ graph: ScriptHmrModuleGraph,
377
+ file: string,
378
+ projectRoot: string,
379
+ ): readonly string[] | null {
380
+ const nodes = [...(graph.getModulesByFile?.(file) ?? [])];
381
+ if (!nodes.length) return null;
382
+ const boundaries = new Set<string>();
383
+ const root = `${projectRoot.replaceAll('\\', '/').replace(/\/$/, '')}/`;
384
+ const importersOf = importersFromModuleGraph(graph);
385
+ const proven = new Set<HmrModuleNodeLike>();
386
+ const visit = (node: HmrModuleNodeLike, ancestors: Set<HmrModuleNodeLike>): boolean => {
387
+ if (proven.has(node)) return true;
388
+ if (ancestors.has(node) || !node.file?.replaceAll('\\', '/').startsWith(root)) return false;
389
+ if (node.isSelfAccepting) {
390
+ if (
391
+ !node.url ||
392
+ !lastSeenBoundary.get(node.file) ||
393
+ resolveOidSurface(node.file, '', importersOf).attribute !== 'userData-oid'
394
+ )
395
+ return false;
396
+ boundaries.add(node.url);
397
+ proven.add(node);
398
+ return true;
399
+ }
400
+ const importers = [...(node.importers ?? [])];
401
+ if (!importers.length) return false;
402
+ const next = new Set(ancestors).add(node);
403
+ if (!importers.every((importer) => visit(importer, next))) return false;
404
+ proven.add(node);
405
+ return true;
406
+ };
407
+ return nodes.every((node) => visit(node, new Set())) && boundaries.size ? [...boundaries] : null;
408
+ }
409
+
410
+ /**
411
+ * Is a file APPEARING or VANISHING under this kind the editor's event to own?
412
+ *
413
+ * `outside` is not the project's, so vite keeps it. Everything else is —
414
+ * including `ignore`, whose files are swallowed silently exactly as an edit to
415
+ * them is. The kinds in between all name a module the running game may hold,
416
+ * and a module that no longer exists (or has just started existing beside the
417
+ * ones it does) cannot be reconciled by any hot update: only a remount can.
418
+ */
419
+ function appearanceIsOurs(kind: ProjectHotUpdateKind): boolean {
420
+ return kind !== 'outside';
421
+ }
422
+
423
+ /**
424
+ * A project file was CREATED or DELETED.
425
+ *
426
+ * There is exactly one honest answer for a runtime module: restart. Vite's own
427
+ * propagation is swallowed (`[]`) rather than allowed to run, because for a
428
+ * delete it has nothing to send that any client can apply — its only effect
429
+ * was pushing an unusable update at every `?vgai-mount=N` variant the session
430
+ * had accumulated, which is how this failure stayed invisible: the page logged
431
+ * `[vite] Failed to reload` and nothing else did anything at all.
432
+ */
433
+ /**
434
+ * The stamp's propagation boundary for a PROJECT file: the project's own
435
+ * modules re-evaluate on the next remount; any importer OUTSIDE the project
436
+ * tree is editor chrome (or an engine module the chrome shares) and must
437
+ * never be re-instanced by a game edit — see {@link stampHmrInvalidation}'s
438
+ * doc for the split-singleton failure this prevents.
439
+ */
440
+ function projectStampBoundary(projectRoot: string): (moduleFile: string) => boolean {
441
+ const root = `${projectRoot.replaceAll('\\', '/').replace(/\/+$/, '')}/`;
442
+ return (moduleFile) => !moduleFile.replaceAll('\\', '/').startsWith(root);
443
+ }
444
+
445
+ /**
446
+ * Pick the stamp boundary for ONE changed file. A file inside the project
447
+ * tree bounds at the project; a repo-VENDORED game file (classified
448
+ * `restart` by `classifyProjectHotUpdate` even though it sits outside the
449
+ * project folder) must keep propagating through the vendored subtree AND the
450
+ * project's own modules — only editor chrome stops it — so its boundary is
451
+ * the engine-root form, with the engine root read off the file's own
452
+ * `/vendor/games/` position.
453
+ */
454
+ function stampBoundaryFor(file: string, projectRoot: string): (moduleFile: string) => boolean {
455
+ const normalized = file.replaceAll('\\', '/');
456
+ const vendorIdx = normalized.indexOf('/vendor/games/');
457
+ if (vendorIdx !== -1) {
458
+ return editorChromeStampBoundary(normalized.slice(0, vendorIdx), () => projectRoot);
459
+ }
460
+ return projectStampBoundary(projectRoot);
461
+ }
462
+
463
+ /**
464
+ * The same boundary for a WRITE-ROUTE stamp, where the changed file can live
465
+ * OUTSIDE the project root (a repo-vendored game's source under
466
+ * `vendor/games/`): editor chrome is what must not re-instance, and here it
467
+ * is nameable directly — modules under the engine checkout's `packages/`
468
+ * that are not the open project's own tree. The project-root carve-out is
469
+ * load-bearing for in-tree fixture projects, which live inside
470
+ * `packages/editor/src/ingest/games/`. Vendored sources sit under `vendor/`
471
+ * (not `packages/`), so they propagate; engine modules the chrome shares sit
472
+ * under `packages/engine/`, so they stop. ONE spelling, exported so every
473
+ * write route stamps with the same boundary — a second inline copy is how
474
+ * one route shipped unbounded (see {@link stampHmrInvalidation}'s doc).
475
+ */
476
+ export function editorChromeStampBoundary(
477
+ engineRoot: string,
478
+ getProjectRoot: () => string | undefined,
479
+ ): (moduleFile: string) => boolean {
480
+ const packagesRoot = `${engineRoot.replaceAll('\\', '/').replace(/\/+$/, '')}/packages/`;
481
+ return (moduleFile) => {
482
+ const normalized = moduleFile.replaceAll('\\', '/');
483
+ if (!normalized.startsWith(packagesRoot)) return false;
484
+ const projectRoot = getProjectRoot();
485
+ if (!projectRoot) return true;
486
+ const projectPrefix = `${projectRoot.replaceAll('\\', '/').replace(/\/+$/, '')}/`;
487
+ return !normalized.startsWith(projectPrefix);
488
+ };
489
+ }
490
+
491
+ function handleProjectFileAppearance(
492
+ args: ProjectScriptHotUpdateArgs,
493
+ kind: ProjectHotUpdateKind,
494
+ isClient: boolean,
495
+ ): never[] | undefined {
496
+ if (!appearanceIsOurs(kind)) return undefined;
497
+ if (!isClient || kind === 'ignore') return [];
498
+ const { file, server } = args;
499
+ // A delete leaves the graph holding nodes for a file that is gone; stamping
500
+ // them HMR-invalid is what makes every importer re-transform (and therefore
501
+ // re-resolve, and therefore FAIL LOUDLY) instead of silently serving the
502
+ // cached transform that still points at the vanished module.
503
+ const outcome = stampHmrInvalidation(
504
+ server.moduleGraph,
505
+ file,
506
+ args.timestamp,
507
+ stampBoundaryFor(file, args.projectRoot),
508
+ );
509
+ const warning = staleModuleWarning(file, outcome);
510
+ if (warning) (args.warn ?? console.warn)(warning);
511
+ server.ws.send({
512
+ type: 'custom',
513
+ event: kind === 'tool' ? 'vgai:script-update' : 'vgai:restart-required',
514
+ data: { file: file.replaceAll('\\', '/') },
515
+ });
516
+ return [];
517
+ }
518
+
519
+ /**
520
+ * The shared `hotUpdate` body. Returns `[]` to swallow Vite's HMR
521
+ * propagation, or `undefined` to let it run — the same two-valued contract
522
+ * `dev.ts`/`packaged.ts` returned when each carried its own copy.
523
+ */
524
+ export function handleProjectScriptHotUpdate(
525
+ args: ProjectScriptHotUpdateArgs,
526
+ ): never[] | undefined {
527
+ const { file, projectRoot, source, server } = args;
528
+ const isClient = (args.environment ?? 'client') === 'client';
529
+ const classified = classifyProjectHotUpdate(
530
+ file,
531
+ projectRoot,
532
+ source,
533
+ // T43: reach a non-entry R3F component through the live import graph,
534
+ // same as `vite-plugin-ui-oid.ts`'s transform hook — see
535
+ // `project-hmr-files.ts`'s doc comment on why this is shared, not
536
+ // re-derived.
537
+ importersFromModuleGraph(server.moduleGraph),
538
+ );
539
+ if ((args.type ?? 'update') !== 'update') {
540
+ return handleProjectFileAppearance(args, classified, isClient);
541
+ }
542
+ const boundaries =
543
+ classified === 'restart' && /\.[cm]?[jt]s$/.test(file)
544
+ ? r3fDependencyBoundaries(server.moduleGraph, file, projectRoot)
545
+ : null;
546
+ const kind = boundaries
547
+ ? 'r3f-refresh'
548
+ : isClient
549
+ ? trackReactBoundary(classified, file, source)
550
+ : classified;
551
+ // `outside` / `stock-data` / `react` ride stock Vite HMR (a data handle's
552
+ // owning module live-tunes it through its own `import.meta.hot.accept`;
553
+ // a react module takes Fast Refresh) — and stock HMR does the module-graph
554
+ // stamping itself, which is why they leave here untouched.
555
+ if (!swallowsViteHmr(kind)) {
556
+ if (kind === 'r3f-refresh' && isClient) {
557
+ server.ws.send({
558
+ type: 'custom',
559
+ event: 'vgai:r3f-refresh-source',
560
+ data: {
561
+ file: file.replaceAll('\\', '/'),
562
+ path: relative(projectRoot, file).replaceAll('\\', '/'),
563
+ sha: createHash('sha256').update(source).digest('hex').slice(0, 16),
564
+ timestamp: args.timestamp,
565
+ affected: affectedProjectFiles(server.moduleGraph, file, projectRoot),
566
+ ...(boundaries ? { boundaries } : {}),
567
+ },
568
+ });
569
+ }
570
+ return undefined;
571
+ }
572
+ // The ssr pass owns no side effects — see `ProjectScriptHotUpdateArgs.environment`.
573
+ if (!isClient) return [];
574
+
575
+ // Swallowing Vite's HMR means taking on the module-graph bookkeeping it
576
+ // would have done. See this module's header for the full mechanism and the
577
+ // stale-restart incident that produced it.
578
+ const outcome = stampHmrInvalidation(
579
+ server.moduleGraph,
580
+ file,
581
+ args.timestamp,
582
+ stampBoundaryFor(file, args.projectRoot),
583
+ );
584
+ const warning = staleModuleWarning(file, outcome);
585
+ if (warning) (args.warn ?? console.warn)(warning);
586
+
587
+ // R3F-dialect modules are swallowed from stock HMR (their non-component)
588
+ // exports would force a full page reload) — the editor's R3F design
589
+ // session listens for this custom event and remounts the design world in
590
+ // place, re-resolving selection by oid.
591
+ if (kind === 'r3f-entry') {
592
+ server.ws.send({
593
+ type: 'custom',
594
+ event: 'vgai:r3f-entry-update',
595
+ data: { file, affected: affectedProjectFiles(server.moduleGraph, file, projectRoot) },
596
+ });
597
+ }
598
+ if (kind === 'tool') {
599
+ server.ws.send({
600
+ type: 'custom',
601
+ event: 'vgai:script-update',
602
+ data: {
603
+ file: file.replaceAll('\\', '/'),
604
+ affected: affectedProjectFiles(server.moduleGraph, file, projectRoot),
605
+ },
606
+ });
607
+ }
608
+ if (kind === 'restart') {
609
+ server.ws.send({
610
+ type: 'custom',
611
+ event: 'vgai:restart-required',
612
+ data: { file, affected: affectedProjectFiles(server.moduleGraph, file, projectRoot) },
613
+ });
614
+ }
615
+ // Other project changes (including scripts/, tests/, dist/) are not runtime
616
+ // modules. Swallow them; scene/asset changes are delivered through the
617
+ // editor's own SSE channel.
618
+ return [];
619
+ }