@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,352 @@
1
+ /**
2
+ * Shared event fan-out for editor tabs — ONE message vocabulary over TWO
3
+ * transports.
4
+ *
5
+ * A connected editor page is a `EditorEventClient` in this pool, and every
6
+ * caller (asset browser, Colyseus plugin, the command relay, the tab
7
+ * bijection) addresses it the same way regardless of how it got here:
8
+ *
9
+ * - `ServerResponse` — the classic `GET /__editor/events` SSE stream. Still
10
+ * the transport the share tunnel bridges through (TryCloudflare cannot do
11
+ * SSE to the browser, so its gateway consumes this and re-frames it), and
12
+ * still curl-debuggable.
13
+ * - `EditorSocketClient` — a WebSocket upgrade on that SAME path. Local tabs
14
+ * use this one: it carries the identical named events downstream AND the
15
+ * tab's control replies upstream, so receipts/results/state no longer
16
+ * compete with module loads for the browser's per-origin HTTP connection
17
+ * pool. It also answers protocol pings from the browser's network stack
18
+ * while the main thread is blocked, which is what lets the relay say
19
+ * "busy" instead of guessing "dead".
20
+ */
21
+
22
+ import type { ServerResponse } from 'node:http';
23
+ import type { CommandListenerFacts } from './server-utils';
24
+
25
+ /**
26
+ * What a tab last told the server about itself (`POST /__editor/state` or the
27
+ * equivalent control frame).
28
+ *
29
+ * It is EVIDENCE FOR A REFUSAL and nothing else now. It used to elect the tab
30
+ * that owned commands, and that election is what the tab table replaced: who
31
+ * owns the session is a presence question (`server/tab-presence.ts`), and
32
+ * answering it from a report the page is not obliged to send is how a live,
33
+ * blessed tab became unroutable and its commands came back "disconnected".
34
+ * What survives is the part that was always true — when a command goes
35
+ * unacknowledged, the refusal can say what that tab was showing and how long
36
+ * it has been quiet instead of guessing.
37
+ */
38
+ export interface ClientControlHealth {
39
+ /** `healthy` means the tab explicitly reported an empty pageErrors list. */
40
+ readonly errorState: 'healthy' | 'unknown' | 'errored';
41
+ readonly visible: boolean;
42
+ readonly focused: boolean;
43
+ readonly updatedAt: number;
44
+ }
45
+
46
+ /**
47
+ * A duplex control socket in the pool.
48
+ *
49
+ * Beyond delivery it exposes the two liveness facts an SSE response cannot:
50
+ * the age of the last protocol pong (answered by the browser's NETWORK stack,
51
+ * so it stays fresh through a blocked main thread) and a main-thread echo
52
+ * round trip (answered by the inline bootstrap in index.html, so an
53
+ * unanswered echo can only mean a blocked main thread).
54
+ */
55
+ export interface EditorSocketClient {
56
+ /** Structural discriminator against `ServerResponse`. */
57
+ readonly kind: 'socket';
58
+ /** Deliver one framed event; false when the socket can no longer take it. */
59
+ sendFrame(event: string, data: string, id?: string): boolean;
60
+ /** True once the socket is closing or closed. */
61
+ isClosed(): boolean;
62
+ /** Age in ms of the most recent protocol pong, or null before the first. */
63
+ lastPongAgeMs(): number | null;
64
+ /** Round-trip the page's inline main-thread echo responder. */
65
+ echo(timeoutMs: number): Promise<boolean>;
66
+ /** End this exact connection because a newer generation superseded it. */
67
+ close(code: number, reason: string): void;
68
+ }
69
+
70
+ /** Either transport, as held by the pool and by a pending command's owner. */
71
+ export type EditorEventClient = ServerResponse | EditorSocketClient;
72
+
73
+ const sseClients = new Set<EditorEventClient>();
74
+ const clientIds = new Map<EditorEventClient, string>();
75
+ const clientParticipantIds = new Map<EditorEventClient, string>();
76
+ const clientControlHealth = new Map<string, ClientControlHealth>();
77
+ /**
78
+ * Per-page-load command-listener facts (`server-utils.ts`'s
79
+ * `CommandListenerFacts`), keyed by client id — which IS the page-load id, so
80
+ * a reload starts from nothing rather than inheriting the dead page's verdict.
81
+ *
82
+ * OWNERSHIP: this map is written only by the three `note*` helpers below, and
83
+ * an entry is dropped only by `dropClient`, exactly where `clientControlHealth`
84
+ * beside it is dropped — one lifetime, one teardown path, no timer.
85
+ */
86
+ const clientListenerFacts = new Map<string, MutableCommandListenerFacts>();
87
+
88
+ interface MutableCommandListenerFacts {
89
+ attachedAt: number | null;
90
+ lastRelayAt: number | null;
91
+ lastReceiptAt: number | null;
92
+ }
93
+
94
+ function factsFor(clientId: string): MutableCommandListenerFacts {
95
+ const existing = clientListenerFacts.get(clientId);
96
+ if (existing) return existing;
97
+ const fresh: MutableCommandListenerFacts = {
98
+ attachedAt: null,
99
+ lastRelayAt: null,
100
+ lastReceiptAt: null,
101
+ };
102
+ clientListenerFacts.set(clientId, fresh);
103
+ return fresh;
104
+ }
105
+
106
+ const KEEPALIVE_MS = 15_000;
107
+ let keepaliveTimer: ReturnType<typeof setInterval> | null = null;
108
+
109
+ /** True for the WebSocket transport. */
110
+ export function isEditorSocketClient(client: EditorEventClient): client is EditorSocketClient {
111
+ return (client as Partial<EditorSocketClient>).kind === 'socket';
112
+ }
113
+
114
+ /**
115
+ * Whether this client's transport can still carry an event.
116
+ *
117
+ * Both flags are needed on the SSE side: `writableEnded` reports that the
118
+ * SERVER called `res.end()`, which nothing does for an SSE response, so a
119
+ * client abort leaves `writableEnded: false, destroyed: true` (measured).
120
+ */
121
+ export function isClientAlive(client: EditorEventClient): boolean {
122
+ if (isEditorSocketClient(client)) return !client.isClosed();
123
+ return !client.writableEnded && !client.destroyed;
124
+ }
125
+
126
+ /** End one exact event-stream generation. Its ordinary close handler owns all
127
+ * table and pending-command cleanup. */
128
+ export function closeClient(client: EditorEventClient, code: number, reason: string): void {
129
+ if (isEditorSocketClient(client)) {
130
+ client.close(code, reason);
131
+ return;
132
+ }
133
+ try {
134
+ client.end();
135
+ } catch {
136
+ /* The stream is already ending; its request close still owns cleanup. */
137
+ }
138
+ }
139
+
140
+ function dropClient(client: EditorEventClient): void {
141
+ const clientId = clientIds.get(client);
142
+ sseClients.delete(client);
143
+ clientIds.delete(client);
144
+ clientParticipantIds.delete(client);
145
+ if (clientId && ![...clientIds.values()].includes(clientId)) {
146
+ clientControlHealth.delete(clientId);
147
+ clientListenerFacts.delete(clientId);
148
+ }
149
+ }
150
+
151
+ /** Deliver one named event, removing the client from the pool if it is dead. */
152
+ function deliver(client: EditorEventClient, event: string, data: string, id?: string): boolean {
153
+ try {
154
+ if (isEditorSocketClient(client)) {
155
+ if (client.isClosed()) {
156
+ dropClient(client);
157
+ return false;
158
+ }
159
+ if (!client.sendFrame(event, data, id)) {
160
+ dropClient(client);
161
+ return false;
162
+ }
163
+ return true;
164
+ }
165
+ // `writableEnded` guards against writing to a closed stream.
166
+ if (client.writableEnded) {
167
+ dropClient(client);
168
+ return false;
169
+ }
170
+ client.write(`${id === undefined ? '' : `id: ${id}\n`}event: ${event}\ndata: ${data}\n\n`);
171
+ return true;
172
+ } catch {
173
+ // SC3: one dead client must not abort the broadcast loop.
174
+ dropClient(client);
175
+ return false;
176
+ }
177
+ }
178
+
179
+ /** Start the keepalive ticker once at least one client is connected. */
180
+ function ensureKeepalive(): void {
181
+ if (keepaliveTimer || sseClients.size === 0) return;
182
+ keepaliveTimer = setInterval(() => {
183
+ if (sseClients.size === 0) {
184
+ stopKeepalive();
185
+ return;
186
+ }
187
+ // Socket clients have the protocol ping instead (editor-control-socket.ts).
188
+ for (const client of [...sseClients]) {
189
+ if (isEditorSocketClient(client)) continue;
190
+ try {
191
+ if (client.writableEnded) dropClient(client);
192
+ else client.write(':keepalive\n\n');
193
+ } catch {
194
+ dropClient(client);
195
+ }
196
+ }
197
+ }, KEEPALIVE_MS);
198
+ // Don't keep the process alive solely for the heartbeat.
199
+ keepaliveTimer.unref?.();
200
+ }
201
+
202
+ function stopKeepalive(): void {
203
+ if (keepaliveTimer) {
204
+ clearInterval(keepaliveTimer);
205
+ keepaliveTimer = null;
206
+ }
207
+ }
208
+
209
+ /** Send an event to all connected editor clients. */
210
+ export function broadcast(event: string, data: unknown): void {
211
+ const sequence =
212
+ data &&
213
+ typeof data === 'object' &&
214
+ Number.isSafeInteger((data as { sequence?: unknown }).sequence)
215
+ ? Number((data as { sequence: number }).sequence)
216
+ : null;
217
+ const payload = JSON.stringify(data);
218
+ // Snapshot so deletions during iteration are safe.
219
+ for (const client of [...sseClients]) {
220
+ deliver(client, event, payload, sequence === null ? undefined : String(sequence));
221
+ }
222
+ }
223
+
224
+ /**
225
+ * Send an event to the connection(s) carrying one specific clientId
226
+ * (tab-bijection lifecycle: yield/refocus/close target exactly one tab).
227
+ * Returns true when at least one live connection received it.
228
+ */
229
+ export function sendToClient(clientId: string, event: string, data: unknown): boolean {
230
+ const payload = JSON.stringify(data);
231
+ let delivered = false;
232
+ for (const [client, id] of [...clientIds]) {
233
+ if (id !== clientId) continue;
234
+ if (deliver(client, event, payload)) delivered = true;
235
+ }
236
+ return delivered;
237
+ }
238
+
239
+ /**
240
+ * Send an event to the FIRST live connection carrying this clientId, and hand
241
+ * back the handle it went to.
242
+ *
243
+ * The command relay needs the handle, not a boolean: a command is owned by
244
+ * the connection that took it, so the disconnect settlement can find it
245
+ * again. `sendToClient` fans out to every connection of a client and can only
246
+ * answer "did anyone take it", which is the right shape for a lifecycle
247
+ * notification and the wrong one for a side effect that must happen once.
248
+ */
249
+ export function sendToClientHandle(
250
+ clientId: string,
251
+ event: string,
252
+ data: unknown,
253
+ ): EditorEventClient | null {
254
+ const payload = JSON.stringify(data);
255
+ for (const [client, id] of [...clientIds]) {
256
+ if (id !== clientId) continue;
257
+ if (deliver(client, event, payload)) return client;
258
+ }
259
+ return null;
260
+ }
261
+
262
+ /**
263
+ * Send an event to EVERY live connection, optionally scoped to one
264
+ * participant. Distinct from `broadcast` only in the scoping — session end is
265
+ * the caller: `tab-close` has to reach the extras and the launcher tabs too,
266
+ * not just the blessed one, or every other tab falls through to the generic
267
+ * "Editor disconnected" overlay when the process exits under it.
268
+ */
269
+ export function sendToAllClients(event: string, data: unknown, participantId?: string): number {
270
+ const payload = JSON.stringify(data);
271
+ let delivered = 0;
272
+ for (const client of [...sseClients]) {
273
+ if (participantId && clientParticipantIds.get(client) !== participantId) continue;
274
+ if (deliver(client, event, payload)) delivered++;
275
+ }
276
+ return delivered;
277
+ }
278
+
279
+ /** Add a client connection. Call from the /__editor/events handler. */
280
+ export function addClient(res: EditorEventClient, clientId?: string, participantId?: string): void {
281
+ sseClients.add(res);
282
+ if (clientId) clientIds.set(res, clientId);
283
+ if (participantId) clientParticipantIds.set(res, participantId);
284
+ ensureKeepalive();
285
+ }
286
+
287
+ /** Remove a client connection. Call on request/socket close. */
288
+ export function removeClient(res: EditorEventClient): void {
289
+ dropClient(res);
290
+ if (sseClients.size === 0) stopKeepalive();
291
+ }
292
+
293
+ /** Record what a tab last said about itself — read only by a refusal. */
294
+ export function updateClientControlHealth(clientId: string, health: ClientControlHealth): void {
295
+ clientControlHealth.set(clientId, health);
296
+ }
297
+
298
+ /** Clear project-specific health snapshots while keeping live sockets. */
299
+ export function clearClientControlHealth(): void {
300
+ clientControlHealth.clear();
301
+ }
302
+
303
+ /** The page said its command listener attached (a timestamp) or detached
304
+ * (`null`). See `src/editor-api.ts`'s `reportCommandListener`. */
305
+ export function noteCommandListenerAttached(clientId: string, at: number | null): void {
306
+ factsFor(clientId).attachedAt = at;
307
+ }
308
+
309
+ /** The relay handed this page a command. */
310
+ export function noteCommandRelay(clientId: string, at: number = Date.now()): void {
311
+ factsFor(clientId).lastRelayAt = at;
312
+ }
313
+
314
+ /** This page acknowledged receipt of a relayed command — the OTHER half of the
315
+ * verdict, and the one that needs no cooperation beyond the receipt the relay
316
+ * already depends on. */
317
+ export function noteCommandReceipt(clientId: string | undefined, at: number = Date.now()): void {
318
+ if (clientId === undefined) return;
319
+ factsFor(clientId).lastReceiptAt = at;
320
+ }
321
+
322
+ /** What is MEASURED about this page-load's command listener. A page-load that
323
+ * has never reported anything reads as all-null, which
324
+ * `commandListenerHealth` states as `'not attached'` — never as healthy. */
325
+ export function commandListenerFactsFor(clientId: string): CommandListenerFacts {
326
+ return (
327
+ clientListenerFacts.get(clientId) ?? {
328
+ attachedAt: null,
329
+ lastRelayAt: null,
330
+ lastReceiptAt: null,
331
+ }
332
+ );
333
+ }
334
+
335
+ /** Number of currently-connected clients (exposed for tests). */
336
+ export function clientCount(participantId?: string): number {
337
+ if (!participantId) return sseClients.size;
338
+ return [...clientParticipantIds.values()].filter((candidate) => candidate === participantId)
339
+ .length;
340
+ }
341
+
342
+ /** The last health a given tab reported, or `undefined` if it never has. Read
343
+ * when a relayed command goes unacknowledged, so the refusal can name what
344
+ * that tab was showing and how long it has been silent rather than guessing. */
345
+ export function clientControlHealthFor(clientId: string | null): ClientControlHealth | undefined {
346
+ return clientId === null ? undefined : clientControlHealth.get(clientId);
347
+ }
348
+
349
+ /** Client identity for a handle returned by `sendToClientHandle`. */
350
+ export function clientIdForResponse(response: EditorEventClient): string | null {
351
+ return clientIds.get(response) ?? null;
352
+ }
@@ -0,0 +1,169 @@
1
+ /**
2
+ * What code is this editor session actually serving?
3
+ *
4
+ * Measured defect (2026-08-09): a user's editor server came from an engine
5
+ * checkout parked on a dead feature branch, 162 commits behind `origin/main`.
6
+ * Three fixes that had already merged were simply absent from the running
7
+ * editor, and hours went into debugging their absence as live bugs — because
8
+ * NOTHING in the product reported which commit was being served. The URL, the
9
+ * project name, the session id and the engine's npm version were all correct
10
+ * and all useless for that question.
11
+ *
12
+ * So the server computes its own checkout's git provenance and reports it
13
+ * everywhere a human or an agent looks: the `/__editor/project` payload, the
14
+ * server's own startup banner, `vgai edit`'s ready line, and `vgai status`.
15
+ *
16
+ * Two rules this module exists to hold:
17
+ *
18
+ * - **Report, never refuse.** A stale checkout still serves. Nothing here
19
+ * gates, delays, or fails a boot; every field degrades to `null` on any
20
+ * error (no git, not a repo, no `origin/main` ref) and the line still
21
+ * prints.
22
+ * - **Never touch the network.** `behindOriginMain` is measured against the
23
+ * LOCAL `origin/main` ref only. A fetch here would make every editor boot
24
+ * depend on a remote being reachable, which is exactly the kind of
25
+ * always-on dependency a diagnostic must not introduce. The number is
26
+ * therefore "behind the last main you fetched", and that is still the
27
+ * number that would have caught the 162-commit case.
28
+ */
29
+
30
+ import { execFile } from 'node:child_process';
31
+ import { realpathSync } from 'node:fs';
32
+ import { resolve } from 'node:path';
33
+ import { promisify } from 'node:util';
34
+
35
+ const execFileAsync = promisify(execFile);
36
+
37
+ export interface EngineProvenance {
38
+ /** Current branch, or `null` when detached / unknown. */
39
+ branch: string | null;
40
+ /** Short HEAD commit, or `null` when unknown. */
41
+ commit: string | null;
42
+ /** Commits on the LOCAL `origin/main` ref that HEAD does not have. */
43
+ behindOriginMain: number | null;
44
+ /** Tracked-file modifications in the working tree. */
45
+ dirty: boolean | null;
46
+ }
47
+
48
+ export const UNKNOWN_ENGINE_PROVENANCE: EngineProvenance = {
49
+ branch: null,
50
+ commit: null,
51
+ behindOriginMain: null,
52
+ dirty: null,
53
+ };
54
+
55
+ /**
56
+ * Runs `git <args>` in the engine checkout. Returns trimmed stdout on success
57
+ * — `''` is a legitimate success (a clean `git status --porcelain`) and must
58
+ * stay distinguishable from failure, which is `null`.
59
+ */
60
+ export type GitRunner = (args: readonly string[]) => Promise<string | null>;
61
+
62
+ export function createGitRunner(cwd: string): GitRunner {
63
+ return async (args) => {
64
+ try {
65
+ const { stdout } = await execFileAsync('git', args, {
66
+ cwd,
67
+ encoding: 'utf8',
68
+ timeout: 5_000,
69
+ maxBuffer: 1024 * 1024,
70
+ });
71
+ return stdout.trim();
72
+ } catch {
73
+ return null;
74
+ }
75
+ };
76
+ }
77
+
78
+ function canonical(path: string): string {
79
+ try {
80
+ return realpathSync(path);
81
+ } catch {
82
+ return resolve(path);
83
+ }
84
+ }
85
+
86
+ /**
87
+ * `engineRoot` must BE the repository git discovers, not merely live inside
88
+ * one. A registry-installed editor sits at `<game>/node_modules/@vgai/editor`,
89
+ * where `rev-parse --show-toplevel` happily answers with the GAME's repo — and
90
+ * reporting the game's branch under the word "engine" is worse than reporting
91
+ * nothing. Mismatch therefore degrades to all-null, the same as no git at all.
92
+ */
93
+ export async function computeEngineProvenance(
94
+ engineRoot: string,
95
+ run: GitRunner,
96
+ ): Promise<EngineProvenance> {
97
+ const toplevel = await run(['rev-parse', '--show-toplevel']);
98
+ if (toplevel === null || toplevel === '') return UNKNOWN_ENGINE_PROVENANCE;
99
+ if (canonical(toplevel) !== canonical(engineRoot)) return UNKNOWN_ENGINE_PROVENANCE;
100
+
101
+ const [rawBranch, commit, rawBehind, rawStatus] = await Promise.all([
102
+ run(['rev-parse', '--abbrev-ref', 'HEAD']),
103
+ run(['rev-parse', '--short', 'HEAD']),
104
+ run(['rev-list', '--count', 'HEAD..origin/main']),
105
+ run(['status', '--porcelain', '--untracked-files=no']),
106
+ ]);
107
+
108
+ // Detached HEAD answers the literal string `HEAD`, which would print as
109
+ // `engine: HEAD @ abc1234`. That is a branch name nobody has.
110
+ const branch = rawBranch === null || rawBranch === '' || rawBranch === 'HEAD' ? null : rawBranch;
111
+ const behind = rawBehind === null ? Number.NaN : Number.parseInt(rawBehind, 10);
112
+
113
+ return {
114
+ branch,
115
+ commit: commit === null || commit === '' ? null : commit,
116
+ behindOriginMain: Number.isFinite(behind) ? behind : null,
117
+ dirty: rawStatus === null ? null : rawStatus !== '',
118
+ };
119
+ }
120
+
121
+ /**
122
+ * One provenance read per engine checkout per process. The value is stable for
123
+ * a server's lifetime: changing engine source restarts the server
124
+ * (`engine-source-restart.ts`), so there is nothing to invalidate. Keyed by
125
+ * root rather than module-global so a test — or a process hosting two roots —
126
+ * cannot poison another's answer.
127
+ */
128
+ const cache = new Map<string, Promise<EngineProvenance>>();
129
+
130
+ export function engineProvenance(engineRoot: string, run?: GitRunner): Promise<EngineProvenance> {
131
+ const key = canonical(engineRoot);
132
+ const cached = cache.get(key);
133
+ if (cached) return cached;
134
+ // Never let a rejection escape into a boot path or an HTTP handler.
135
+ const pending = computeEngineProvenance(engineRoot, run ?? createGitRunner(key)).catch(
136
+ () => UNKNOWN_ENGINE_PROVENANCE,
137
+ );
138
+ cache.set(key, pending);
139
+ return pending;
140
+ }
141
+
142
+ /**
143
+ * The ONE wording. The server banner, `vgai edit` and `vgai status` all print
144
+ * this exact string, so a reader comparing two surfaces is never left deciding
145
+ * whether they disagree or are merely phrased differently.
146
+ */
147
+ export function formatEngineProvenanceLine(provenance: EngineProvenance | null): string {
148
+ if (
149
+ provenance === null ||
150
+ (provenance.branch === null &&
151
+ provenance.commit === null &&
152
+ provenance.behindOriginMain === null &&
153
+ provenance.dirty === null)
154
+ ) {
155
+ return 'engine: provenance unavailable';
156
+ }
157
+ const branch = provenance.branch ?? 'detached';
158
+ const commit = provenance.commit ?? 'unknown commit';
159
+ const behind =
160
+ provenance.behindOriginMain === null
161
+ ? 'distance from origin/main unknown'
162
+ : `${provenance.behindOriginMain} behind origin/main`;
163
+ const dirty = provenance.dirty === true ? ' [dirty]' : '';
164
+ const stale =
165
+ provenance.behindOriginMain !== null && provenance.behindOriginMain > 0
166
+ ? ' — STALE: fixes merged to main are not running here'
167
+ : '';
168
+ return `engine: ${branch} @ ${commit} (${behind})${dirty}${stale}`;
169
+ }
@@ -0,0 +1,117 @@
1
+ /**
2
+ * Debounced, content-aware restart gate for the dev host's engine-source
3
+ * watcher (editor-session diagnosis cause 4). The watcher used to hand ANY
4
+ * chokidar event straight to the exit-75 restart handoff, which produced
5
+ * back-to-back restart storms for an actively-editing agent: a multi-file
6
+ * save burst restarted once per file (each relaunch caught the next event),
7
+ * and mtime-only touches / git branch switches restoring identical bytes
8
+ * restarted a process whose imported modules were not actually stale — the
9
+ * "zombie-tab reload loop". Two minimal suppressions, without changing what
10
+ * counts as watched:
11
+ *
12
+ * - **Content check**: each watched file's content hash is baselined during
13
+ * the watcher's initial scan and refreshed as events arrive; an event
14
+ * whose bytes match the last-seen hash is ignored entirely (only different
15
+ * bytes stale the Node process's imports). Unreadable/deleted paths hash
16
+ * to null and are treated as changed, so deletions still restart.
17
+ * - **Debounce**: a real change (re)arms a short quiet-window timer; the
18
+ * restart callback fires ONCE, after the burst goes quiet, reporting the
19
+ * burst's FIRST change (matching the old first-event-wins staleSource
20
+ * semantics). Once fired, the gate is latched — the process is exiting.
21
+ *
22
+ * Hashing and timers are injectable so the decision logic is unit-testable
23
+ * without filesystem or clock choreography (test-proportionality policy).
24
+ */
25
+
26
+ import { createHash } from 'node:crypto';
27
+ import { readFileSync } from 'node:fs';
28
+
29
+ export interface EngineSourceChange {
30
+ changedPath: string;
31
+ changedAt: string;
32
+ }
33
+
34
+ /** sha256 of a file's bytes, or null when unreadable (deleted, a directory,
35
+ * permission). Callers treat null as "changed" — a vanished source file
36
+ * stales imports exactly like different bytes do. */
37
+ export function hashFileContent(file: string): string | null {
38
+ try {
39
+ return createHash('sha256').update(readFileSync(file)).digest('hex');
40
+ } catch {
41
+ return null;
42
+ }
43
+ }
44
+
45
+ export interface EngineSourceRestartGate {
46
+ /** Record a file's boot-time content during the watcher's initial scan
47
+ * (chokidar's pre-`ready` add events) — served content IS boot content,
48
+ * since any earlier change already restarted the previous process. */
49
+ recordBaseline(file: string): void;
50
+ /** Handle a post-scan watcher event; arms/re-arms the quiet-window timer
51
+ * when the file's content actually differs from the last-seen bytes. */
52
+ handleEvent(event: string, file: string): void;
53
+ /** Cancel any pending restart (shutdown path). */
54
+ dispose(): void;
55
+ }
56
+
57
+ export function createEngineSourceRestartGate(options: {
58
+ onRestart: (change: EngineSourceChange) => void;
59
+ /** Quiet window a burst must go silent for before the single restart fires. */
60
+ quietMs?: number;
61
+ hashFile?: (file: string) => string | null;
62
+ /** Timer seam (opaque handle) so tests drive the quiet window directly. */
63
+ setTimer?: (fn: () => void, ms: number) => unknown;
64
+ clearTimer?: (timer: unknown) => void;
65
+ now?: () => Date;
66
+ }): EngineSourceRestartGate {
67
+ const quietMs = options.quietMs ?? 1000;
68
+ const hashFile = options.hashFile ?? hashFileContent;
69
+ const setTimer =
70
+ options.setTimer ?? ((fn: () => void, ms: number): unknown => setTimeout(fn, ms));
71
+ const clearTimer =
72
+ options.clearTimer ?? ((timer: unknown) => clearTimeout(timer as NodeJS.Timeout));
73
+ const now = options.now ?? (() => new Date());
74
+
75
+ /** file -> last-seen content hash (baseline scan, then refreshed per event). */
76
+ const lastSeen = new Map<string, string>();
77
+ let pending: EngineSourceChange | null = null;
78
+ let timer: unknown = null;
79
+ let fired = false;
80
+
81
+ const fire = (): void => {
82
+ timer = null;
83
+ if (fired || pending === null) return;
84
+ fired = true;
85
+ options.onRestart(pending);
86
+ };
87
+
88
+ return {
89
+ recordBaseline(file: string): void {
90
+ const hash = hashFile(file);
91
+ if (hash !== null) lastSeen.set(file, hash);
92
+ },
93
+ handleEvent(event: string, file: string): void {
94
+ if (fired) return;
95
+ if (event === 'unlink' || event === 'unlinkDir') {
96
+ // Deletions are always real changes (old any-event behavior kept);
97
+ // drop the hash so a later re-add with identical bytes still counts
98
+ // as a change relative to "the file was gone".
99
+ lastSeen.delete(file);
100
+ } else {
101
+ const hash = hashFile(file);
102
+ if (hash !== null && hash === lastSeen.get(file)) return; // mtime-only touch
103
+ if (hash !== null) lastSeen.set(file, hash);
104
+ else lastSeen.delete(file);
105
+ }
106
+ if (pending === null) {
107
+ pending = { changedPath: file, changedAt: now().toISOString() };
108
+ }
109
+ if (timer !== null) clearTimer(timer);
110
+ timer = setTimer(fire, quietMs);
111
+ },
112
+ dispose(): void {
113
+ if (timer !== null) clearTimer(timer);
114
+ timer = null;
115
+ },
116
+ };
117
+ }