@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,57 @@
1
+ /**
2
+ * H2, third half — honest gizmo refusal.
3
+ *
4
+ * WHY THE TRIGGER IS TOOL ACTIVATION AND NOT DRAG-START. The design record
5
+ * says "attempting to drag a refused node shows a transient hint". Read
6
+ * against the code, a literal drag-start trigger is unreachable: a fully
7
+ * refused selection never gets a gizmo in the first place —
8
+ * `EditorViewport.syncFromStore` computes `selectedTransformWritable` and
9
+ * calls `this.detach()` (editor-viewport.ts, the `attach`/`detach` branch), so
10
+ * `TransformControls` fires no `dragging-changed`: there is nothing attached
11
+ * to drag. THAT detach is the exact spot where the silence lives.
12
+ *
13
+ * The earliest point at which the user has made a real, unambiguous attempt to
14
+ * transform — as opposed to merely selecting something — is therefore ARMING
15
+ * the move/rotate/scale tool (W/E/R, the toolbar's mode buttons, the command
16
+ * palette's Translate/Rotate/Scale Mode actions) while that refused selection
17
+ * is live. That is the second trigger the brief explicitly allows, and
18
+ * it is what this module implements. Every UI mode-switch call site routes
19
+ * through {@link requestTransformMode} instead of `store.setTransformMode`.
20
+ * (The programmatic `command-listener` path deliberately does not: an
21
+ * automated `set-transform-mode` command is not a user attempt, and a headless
22
+ * caller has no viewport to read a hint in.)
23
+ *
24
+ * The hint text is the adapter's own `reason`, verbatim — the same sentence
25
+ * the hierarchy lock tooltip and the inspector field show (doctrine rule 2).
26
+ * When an adapter refuses without giving a reason we show NOTHING rather than
27
+ * invent a sentence to paraphrase it with.
28
+ */
29
+
30
+ import { getActiveAuthoring } from './authoring/active-adapter';
31
+ import type { EditorShellStore, TransformMode } from './editor-shell-store';
32
+ import { transformLockSummary } from './hierarchy-row-model';
33
+ import { showTransientHint } from './transient-hint';
34
+
35
+ /** Set the transform mode, and NAME the refusal if the live selection is one
36
+ * the active adapter will not write. */
37
+ export function requestTransformMode(store: EditorShellStore, mode: TransformMode): void {
38
+ store.setTransformMode(mode);
39
+ // Arming SELECT is not an attempt to transform anything — it is the tool
40
+ // that transforms nothing (`TransformMode`'s own note) — so the refusal
41
+ // below, whose whole trigger is "a real, unambiguous attempt to transform",
42
+ // has nothing to report about it.
43
+ if (mode === 'select') return;
44
+ const ids = [...store.selectedEntityIds];
45
+ if (ids.length === 0) return;
46
+ const editability = getActiveAuthoring(store).transforms?.editability;
47
+ if (!editability) return;
48
+ let reason: string | undefined;
49
+ for (const id of ids) {
50
+ const summary = transformLockSummary((channel) => editability(id, channel));
51
+ // Anything movable in the selection means the gesture is not refused —
52
+ // the gizmo attaches and moves what it can.
53
+ if (!summary.locked) return;
54
+ reason ??= summary.reason;
55
+ }
56
+ if (reason) showTransientHint(reason);
57
+ }
@@ -0,0 +1,78 @@
1
+ /**
2
+ * The editor's one transient, non-blocking hint channel (H2).
3
+ *
4
+ * There was no toast/notification/status-message mechanism in the editor when
5
+ * this landed (grepped: `toast`, `notification`, `statusMessage`, `hint` —
6
+ * only unrelated hits), so this is the minimal one. Deliberately: one hint at
7
+ * a time (a new one replaces the old), auto-dismissing, carrying nothing but
8
+ * a string it did not write. Blocking dialogs (`window.alert`/`prompt`) are
9
+ * banned in editor UI.
10
+ *
11
+ * Publisher lives here (plain module state, no React) so non-React callers —
12
+ * hotkeys, the action registry — can raise a hint without importing the
13
+ * component. `components/TransientHint.tsx` renders it.
14
+ */
15
+
16
+ export const TRANSIENT_HINT_MS = 3000;
17
+
18
+ export interface TransientHint {
19
+ /** Monotonic — lets the renderer restart its animation on a repeat message. */
20
+ readonly id: number;
21
+ readonly message: string;
22
+ }
23
+
24
+ let current: TransientHint | null = null;
25
+ let timer: ReturnType<typeof setTimeout> | null = null;
26
+ let nextId = 1;
27
+ const listeners = new Set<() => void>();
28
+
29
+ function emit(): void {
30
+ for (const listener of listeners) listener();
31
+ }
32
+
33
+ /** Show `message` for {@link TRANSIENT_HINT_MS}, replacing any live hint. */
34
+ export function showTransientHint(message: string): void {
35
+ current = { id: nextId++, message };
36
+ if (timer) clearTimeout(timer);
37
+ timer = setTimeout(() => {
38
+ current = null;
39
+ timer = null;
40
+ emit();
41
+ }, TRANSIENT_HINT_MS);
42
+ emit();
43
+ }
44
+
45
+ export function dismissTransientHint(): void {
46
+ if (timer) clearTimeout(timer);
47
+ timer = null;
48
+ current = null;
49
+ emit();
50
+ }
51
+
52
+ export const subscribeTransientHint = (listener: () => void): (() => void) => {
53
+ listeners.add(listener);
54
+ return () => {
55
+ listeners.delete(listener);
56
+ };
57
+ };
58
+
59
+ export const transientHint = (): TransientHint | null => current;
60
+
61
+ /**
62
+ * A drag that ended with NOTHING accepting it says so.
63
+ *
64
+ * `dropEffect === 'none'` at `dragend` is the browser's own word that no drop
65
+ * target took the payload: the card was released over editor chrome (a tab
66
+ * strip, the toolbar, a console row) instead of the viewport or a hierarchy
67
+ * row. That used to be perfectly silent — no hint, no console line, nothing
68
+ * changed — and a verifier lost a whole round to it before checking
69
+ * `elementFromPoint` (2026-09-02). A human just sees "the drop did nothing".
70
+ */
71
+ export function reportUnacceptedAssetDrop(event: { dataTransfer: DataTransfer | null }): void {
72
+ if (event.dataTransfer?.dropEffect !== 'none') return;
73
+ // Surface-neutral on purpose: the source cannot know whether the scene is
74
+ // three or canvas, and a 2D tester told 'the 3D view' would be misled.
75
+ showTransientHint(
76
+ 'Nothing accepted that drop — release it over the scene view or a hierarchy row.',
77
+ );
78
+ }
@@ -0,0 +1,116 @@
1
+ import { EDITOR_LAYER } from '@volter/editor-threejs/viewport/editor-layers';
2
+ import { triggerVolumeOf } from '@volter/editor-threejs/adapter/trigger-volume';
3
+ import { setUserData } from '@volter/editor-threejs/ecs/user-data';
4
+ import * as THREE from 'three';
5
+
6
+ const RING = new THREE.Color(0x4fd1c5);
7
+ const RING_SELECTED = new THREE.Color(0x9ff0e8);
8
+ const SEGMENTS = 64;
9
+ /** How far the corner ticks rise off the ring, in world units. */
10
+ const TICK_HEIGHT = 0.6;
11
+
12
+ /**
13
+ * Editor-only visualization for a project-owned trigger volume — the group
14
+ * whose radius decides where a hazard fires or a quest arrives. The game's
15
+ * source says nothing about being authored; it just carries the radius in
16
+ * `userData`, and this helper draws it: a ground circle in the source's local
17
+ * XZ plane that extends upward at ±X/±Z, which is what such a volume tests.
18
+ *
19
+ * Same contract as `ReflectionProbeHelper`: it follows the live Object3D but
20
+ * owns every line and material it draws, sits on EDITOR_LAYER, and therefore
21
+ * never enters the game's tree or its runtime camera.
22
+ */
23
+ export class TriggerVolumeHelper extends THREE.Group {
24
+ private signature = '';
25
+ private selected = false;
26
+
27
+ constructor(readonly source: THREE.Object3D) {
28
+ super();
29
+ this.name = 'Trigger Volume Helper';
30
+ this.matrixAutoUpdate = false;
31
+ this.renderOrder = 998;
32
+ setUserData(this, 'editorHelper', true);
33
+ setUserData(this, 'editorHelperType', 'trigger-volumes');
34
+ this.layers.set(EDITOR_LAYER);
35
+ this.refresh(true);
36
+ }
37
+
38
+ setSelected(selected: boolean): void {
39
+ if (this.selected === selected) return;
40
+ this.selected = selected;
41
+ this.refresh(true);
42
+ }
43
+
44
+ update(): void {
45
+ this.refresh(false);
46
+ this.source.updateWorldMatrix(true, false);
47
+ this.matrix.copy(this.source.matrixWorld);
48
+ this.matrixWorldNeedsUpdate = true;
49
+ }
50
+
51
+ dispose(): void {
52
+ this.clearVisuals();
53
+ this.removeFromParent();
54
+ }
55
+
56
+ private refresh(force: boolean): void {
57
+ const volume = triggerVolumeOf(this.source);
58
+ if (!volume) return;
59
+ const radius = volume.radius;
60
+ const next = String(radius);
61
+ if (!force && next === this.signature) return;
62
+ this.signature = next;
63
+ this.clearVisuals();
64
+
65
+ const color = this.selected ? RING_SELECTED : RING;
66
+ const opacity = this.selected ? 1 : 0.62;
67
+
68
+ const ring: number[] = [];
69
+ for (let i = 0; i < SEGMENTS; i += 1) {
70
+ const angle = (i / SEGMENTS) * Math.PI * 2;
71
+ ring.push(Math.cos(angle) * radius, 0, Math.sin(angle) * radius);
72
+ }
73
+ const ringGeometry = new THREE.BufferGeometry();
74
+ ringGeometry.setAttribute('position', new THREE.Float32BufferAttribute(ring, 3));
75
+ const loop = new THREE.LineLoop(ringGeometry, this.lineMaterial(color, opacity));
76
+ loop.renderOrder = this.renderOrder;
77
+ this.add(loop);
78
+
79
+ const ticks: number[] = [];
80
+ for (const [x, z] of [
81
+ [radius, 0],
82
+ [-radius, 0],
83
+ [0, radius],
84
+ [0, -radius],
85
+ ] as const) {
86
+ ticks.push(x, 0, z, x, TICK_HEIGHT, z);
87
+ }
88
+ const tickGeometry = new THREE.BufferGeometry();
89
+ tickGeometry.setAttribute('position', new THREE.Float32BufferAttribute(ticks, 3));
90
+ const tickLines = new THREE.LineSegments(tickGeometry, this.lineMaterial(color, opacity));
91
+ tickLines.renderOrder = this.renderOrder;
92
+ this.add(tickLines);
93
+
94
+ this.traverse((object) => object.layers.set(EDITOR_LAYER));
95
+ }
96
+
97
+ private lineMaterial(color: THREE.Color, opacity: number): THREE.LineBasicMaterial {
98
+ return new THREE.LineBasicMaterial({
99
+ color,
100
+ depthTest: false,
101
+ transparent: true,
102
+ opacity,
103
+ toneMapped: false,
104
+ });
105
+ }
106
+
107
+ private clearVisuals(): void {
108
+ for (const child of [...this.children]) {
109
+ child.removeFromParent();
110
+ const line = child as THREE.LineSegments;
111
+ line.geometry?.dispose();
112
+ const materials = Array.isArray(line.material) ? line.material : [line.material];
113
+ for (const material of materials) material?.dispose();
114
+ }
115
+ }
116
+ }
@@ -0,0 +1,241 @@
1
+ import ts from 'typescript';
2
+
3
+ /**
4
+ * A SYNCHRONOUS, source-only read of what a project's `vgai.adapter.ts`
5
+ * declares about which files belong to which SURFACE: each region's `include`
6
+ * globs, and the additional surfaces it `mounts` — stated either as parameters
7
+ * layered onto the `'manifest-roots'` rule (`regionIncludes`, what every
8
+ * first-party project uses) or inside an explicit `regions` list (the
9
+ * full-replacement form). Pure — the dev server adds
10
+ * the filesystem and a cache (`server/adapter-region-includes.ts`); the
11
+ * browser-hosted Content index reads the same file through its storage backend.
12
+ *
13
+ * WHY A STATIC READ AND NOT AN IMPORT. The adapter module's contract
14
+ * (`@volter/editor-project/adapter/adapter-module`, ARCHITECTURE-CORE §The editor protocol) is
15
+ * that its TOP LEVEL is "a STATICALLY EVALUABLE BINDING TABLE, readable without
16
+ * booting the game" — plain data, closures only inside `observation[].answer`.
17
+ * This module takes the contract at its word for the one consumer that cannot
18
+ * take any other route: the OID stamping transform runs in a Vite `transform`
19
+ * hook, synchronously, per project `.tsx`, long before any browser-tier adapter
20
+ * load has happened (and in `vite build`, where none ever will). The same
21
+ * placement test ARCHITECTURE-CORE applies to manifest-vs-adapter fields —
22
+ * "readable WITHOUT EVALUATING ANY MODULE … e.g. Vite config time" — is what
23
+ * makes a static read of a statically-evaluable table the right instrument here
24
+ * rather than a second declaration home.
25
+ *
26
+ * It reads those properties and reads them literally. Anything it cannot read
27
+ * literally is reported as {@link AdapterRegionIncludes.unreadable} — never
28
+ * silently treated as "no includes", because a silently dropped declaration is
29
+ * indistinguishable from a declaration that worked, which is the whole failure
30
+ * class this rung exists to end. `packages/editor/src/project-adapter.ts` (the
31
+ * real loader, which IMPORTS the module) stays the validation authority: this
32
+ * read never accepts anything that loader would reject, it only declines to
33
+ * answer.
34
+ */
35
+
36
+ /** One ADDITIONAL mounted surface a region declares — see
37
+ * `@volter/editor-project/adapter/adapter-module`'s `AdapterRegion.mounts`. */
38
+ export interface AdapterRegionMountDeclaration {
39
+ readonly surface: 'three' | 'canvas' | 'dom';
40
+ readonly include: readonly string[];
41
+ }
42
+
43
+ /** Region id -> the `include` globs it declares, and the additional surfaces it
44
+ * mounts. */
45
+ export interface AdapterRegionIncludes {
46
+ readonly byRegionId: ReadonlyMap<string, readonly string[]>;
47
+ /** Region id -> the surfaces it mounts BESIDE its manifest root's own
48
+ * adapter, each with the files that render on it. Read here for the same
49
+ * reason `include` is: it is the one place a root's second surface can be
50
+ * stated, and every OID/HMR/Content reader answers from the same table. */
51
+ readonly mountsByRegionId: ReadonlyMap<string, readonly AdapterRegionMountDeclaration[]>;
52
+ /**
53
+ * `true` when the file HAS a `regions` binding this static read could not
54
+ * evaluate (a spread, an imported constant, a computed value). The caller
55
+ * reports it; it never reads as "declares nothing".
56
+ */
57
+ readonly unreadable: boolean;
58
+ }
59
+
60
+ export const EMPTY_REGION_INCLUDES: AdapterRegionIncludes = {
61
+ byRegionId: new Map(),
62
+ mountsByRegionId: new Map(),
63
+ unreadable: false,
64
+ };
65
+
66
+ const UNREADABLE_REGION_INCLUDES: AdapterRegionIncludes = {
67
+ byRegionId: new Map(),
68
+ mountsByRegionId: new Map(),
69
+ unreadable: true,
70
+ };
71
+
72
+ /** The game's adapter module lives beside `vgai.project.json`, by contract. */
73
+ export const ADAPTER_MODULE_FILENAME = 'vgai.adapter.ts';
74
+
75
+ function stringLiteralOf(node: ts.Node | undefined): string | undefined {
76
+ return node && ts.isStringLiteralLike(node) ? node.text : undefined;
77
+ }
78
+
79
+ function stringArrayOf(node: ts.Node | undefined): string[] | undefined {
80
+ if (!node || !ts.isArrayLiteralExpression(node)) return undefined;
81
+ const out: string[] = [];
82
+ for (const element of node.elements) {
83
+ const value = stringLiteralOf(element);
84
+ if (value === undefined) return undefined;
85
+ out.push(value);
86
+ }
87
+ return out;
88
+ }
89
+
90
+ function propertyOf(object: ts.ObjectLiteralExpression, name: string): ts.Expression | undefined {
91
+ for (const member of object.properties) {
92
+ if (!ts.isPropertyAssignment(member)) continue;
93
+ const key = ts.isIdentifier(member.name)
94
+ ? member.name.text
95
+ : (stringLiteralOf(member.name) ?? null);
96
+ if (key === name) return member.initializer;
97
+ }
98
+ return undefined;
99
+ }
100
+
101
+ /**
102
+ * What the module's default export gives this reader.
103
+ *
104
+ * The three outcomes are deliberately distinct, because two of them used to
105
+ * collapse into one and that collapse WAS a silent hole: `export default def`
106
+ * (a hoisted `const def = defineAdapter({…})`) and `defineAdapter(config)`
107
+ * both evaluate fine in `project-adapter.ts` — which validates the exported
108
+ * VALUE — while this reader saw "not a readable literal" and answered "no
109
+ * includes, nothing to report". The loader would honor an `include` this tier
110
+ * had silently dropped, which is exactly the disagreement the module docblock
111
+ * promises cannot happen. Both are now `'unreadable'`.
112
+ */
113
+ type DefinitionRead =
114
+ /** A statically readable argument object (possibly with no `regions`). */
115
+ | { readonly kind: 'literal'; readonly literal: ts.ObjectLiteralExpression }
116
+ /** A zero-argument call — `nativeAdapter()`. The legitimate empty. */
117
+ | { readonly kind: 'empty' }
118
+ /** No default export at all: nothing here worth flagging; the loader is the
119
+ * validation authority and an absent adapter is the native default. */
120
+ | { readonly kind: 'absent' }
121
+ /** A default export this reader cannot evaluate but the loader can. */
122
+ | { readonly kind: 'unreadable' };
123
+
124
+ function readDefinition(source: ts.SourceFile): DefinitionRead {
125
+ for (const statement of source.statements) {
126
+ if (!ts.isExportAssignment(statement) || statement.isExportEquals) continue;
127
+ const call = statement.expression;
128
+ if (!ts.isCallExpression(call)) return { kind: 'unreadable' };
129
+ const arg = call.arguments[0];
130
+ if (arg === undefined) return { kind: 'empty' };
131
+ return ts.isObjectLiteralExpression(arg)
132
+ ? { kind: 'literal', literal: arg }
133
+ : { kind: 'unreadable' };
134
+ }
135
+ return { kind: 'absent' };
136
+ }
137
+
138
+ /** Read `regions[].include` out of one adapter source. Pure — the fs half is
139
+ * `server/adapter-region-includes.ts`, so this is directly testable, and
140
+ * `adapter-region-includes-conformance.test.ts` pins it against what
141
+ * `parseAdapterDefinition` yields from EVALUATING the same source. */
142
+ export function parseAdapterRegionIncludes(code: string): AdapterRegionIncludes {
143
+ const source = ts.createSourceFile('vgai.adapter.ts', code, ts.ScriptTarget.Latest, true);
144
+ const definition = readDefinition(source);
145
+ if (definition.kind === 'unreadable') return UNREADABLE_REGION_INCLUDES;
146
+ if (definition.kind !== 'literal') return EMPTY_REGION_INCLUDES;
147
+ const regions = propertyOf(definition.literal, 'regions');
148
+ const overlay = propertyOf(definition.literal, 'regionIncludes');
149
+ const listed = regions !== undefined && !ts.isStringLiteralLike(regions);
150
+ // The two forms may not be combined — `defineAdapter` rejects that pairing by
151
+ // name, so the module never loads. This tier declines to answer rather than
152
+ // reporting half of an invalid table.
153
+ if (listed && overlay !== undefined) return UNREADABLE_REGION_INCLUDES;
154
+ // Absent, or the `'manifest-roots'` RULE: the derivation runs, and the
155
+ // declared PARAMETERS beside it are what a native project states (decision,
156
+ // 2026-08-17). Neither present is a real answer — pure reach — not a gap.
157
+ if (!listed) return overlay ? layeredIncludes(overlay) : EMPTY_REGION_INCLUDES;
158
+ if (!ts.isArrayLiteralExpression(regions)) return UNREADABLE_REGION_INCLUDES;
159
+
160
+ const byRegionId = new Map<string, readonly string[]>();
161
+ const mountsByRegionId = new Map<string, readonly AdapterRegionMountDeclaration[]>();
162
+ for (const element of regions.elements) {
163
+ if (!ts.isObjectLiteralExpression(element)) return UNREADABLE_REGION_INCLUDES;
164
+ const id = stringLiteralOf(propertyOf(element, 'id'));
165
+ if (id === undefined) return UNREADABLE_REGION_INCLUDES;
166
+ const include = propertyOf(element, 'include');
167
+ if (include !== undefined) {
168
+ const globs = stringArrayOf(include);
169
+ if (globs === undefined) return UNREADABLE_REGION_INCLUDES;
170
+ byRegionId.set(id, globs);
171
+ }
172
+ const mounts = propertyOf(element, 'mounts');
173
+ if (mounts === undefined) continue;
174
+ const declared = mountArrayOf(mounts);
175
+ if (declared === undefined) return UNREADABLE_REGION_INCLUDES;
176
+ mountsByRegionId.set(id, declared);
177
+ }
178
+ return { byRegionId, mountsByRegionId, unreadable: false };
179
+ }
180
+
181
+ /**
182
+ * Read the LAYERED form: `regionIncludes`, the per-region parameters the
183
+ * `'manifest-roots'` rule takes (`@volter/editor-project/adapter/adapter-module`'s
184
+ * {@link AdapterDefinition.regionIncludes}, decision 2026-08-17).
185
+ *
186
+ * Statically readable BY CONSTRUCTION — it is an object literal of object
187
+ * literals of string arrays, sitting beside the `regions` string in the same
188
+ * argument object — which is exactly why the decision put the parameters here
189
+ * rather than behind a builder call. Anything that is NOT that literal shape
190
+ * (a spread, an imported table, a computed key) is `unreadable`, on the same
191
+ * terms as every other shape this reader declines: the loader would honor it,
192
+ * so silence about it would be the drift this module exists to prevent.
193
+ */
194
+ function layeredIncludes(node: ts.Expression): AdapterRegionIncludes {
195
+ if (!ts.isObjectLiteralExpression(node)) return UNREADABLE_REGION_INCLUDES;
196
+ const byRegionId = new Map<string, readonly string[]>();
197
+ const mountsByRegionId = new Map<string, readonly AdapterRegionMountDeclaration[]>();
198
+ for (const member of node.properties) {
199
+ if (!ts.isPropertyAssignment(member)) return UNREADABLE_REGION_INCLUDES;
200
+ const id = ts.isIdentifier(member.name) ? member.name.text : stringLiteralOf(member.name);
201
+ const overlay = overlayOf(member.initializer);
202
+ if (id === undefined || overlay === undefined) return UNREADABLE_REGION_INCLUDES;
203
+ if (overlay.include) byRegionId.set(id, overlay.include);
204
+ if (overlay.mounts) mountsByRegionId.set(id, overlay.mounts);
205
+ }
206
+ return { byRegionId, mountsByRegionId, unreadable: false };
207
+ }
208
+
209
+ /** One `regionIncludes` entry, read literally. `undefined` for anything this
210
+ * reader cannot evaluate — never a partial answer. */
211
+ function overlayOf(
212
+ node: ts.Expression,
213
+ ): { include?: string[]; mounts?: AdapterRegionMountDeclaration[] } | undefined {
214
+ if (!ts.isObjectLiteralExpression(node)) return undefined;
215
+ const includeNode = propertyOf(node, 'include');
216
+ const include = includeNode === undefined ? undefined : stringArrayOf(includeNode);
217
+ if (includeNode !== undefined && include === undefined) return undefined;
218
+ const mountsNode = propertyOf(node, 'mounts');
219
+ const mounts = mountsNode === undefined ? undefined : mountArrayOf(mountsNode);
220
+ if (mountsNode !== undefined && mounts === undefined) return undefined;
221
+ return { ...(include ? { include } : {}), ...(mounts ? { mounts } : {}) };
222
+ }
223
+
224
+ /** Read a region's `mounts` array literally. `undefined` — not an empty list —
225
+ * for anything this reader cannot evaluate, so the caller reports it rather
226
+ * than silently dropping a surface the real loader will honor. */
227
+ function mountArrayOf(node: ts.Expression): AdapterRegionMountDeclaration[] | undefined {
228
+ if (!ts.isArrayLiteralExpression(node)) return undefined;
229
+ const out: AdapterRegionMountDeclaration[] = [];
230
+ for (const element of node.elements) {
231
+ if (!ts.isObjectLiteralExpression(element)) return undefined;
232
+ const surface = stringLiteralOf(propertyOf(element, 'surface'));
233
+ if (surface !== 'three' && surface !== 'canvas' && surface !== 'dom') return undefined;
234
+ const include = propertyOf(element, 'include');
235
+ if (include === undefined) return undefined;
236
+ const globs = stringArrayOf(include);
237
+ if (globs === undefined || globs.length === 0) return undefined;
238
+ out.push({ surface, include: globs });
239
+ }
240
+ return out;
241
+ }
@@ -0,0 +1,132 @@
1
+ /**
2
+ * `ensureNamedImport` — make a named import available in a module, idempotently.
3
+ *
4
+ * Why this is not in `writer.ts`: that file is deliberately parser-free ("pure
5
+ * string ops", see its header), and an import list is the one region of a source
6
+ * file where a scan-based guess is genuinely unsafe — a string, a comment, or a
7
+ * type-only clause all look like the thing being matched. This is a real parse.
8
+ *
9
+ * The one caller is the `create`/`create-sibling` struct op
10
+ * (`plan-source-edit.ts`): an inserted element whose tag is a COMPONENT is broken
11
+ * source until its import exists, so the import rides the same plan (and therefore
12
+ * the same single history transaction) as the insert itself.
13
+ */
14
+
15
+ import * as ts from 'typescript';
16
+ import { parseAuthoringTsx } from './ts-ast';
17
+ import type { StructEditResult } from './writer';
18
+
19
+ /** Insert `name` into the module's named imports from `moduleSpecifier`, adding
20
+ * the whole import statement when the module is not imported yet. Already
21
+ * present ⇒ `changed: false` with the code untouched (the idempotent case every
22
+ * drop after the first takes). */
23
+ export function ensureNamedImport(
24
+ code: string,
25
+ name: string,
26
+ moduleSpecifier: string,
27
+ ): StructEditResult {
28
+ const sf = parseAuthoringTsx('module.tsx', code);
29
+ const imports = sf.statements.filter(ts.isImportDeclaration);
30
+
31
+ for (const declaration of imports) {
32
+ if (!ts.isStringLiteral(declaration.moduleSpecifier)) continue;
33
+ if (declaration.moduleSpecifier.text !== moduleSpecifier) continue;
34
+ // A type-only import of the same module cannot host a VALUE import; leave it
35
+ // alone and let the new-statement path below add a separate one.
36
+ if (declaration.importClause?.isTypeOnly) continue;
37
+ const bindings = declaration.importClause?.namedBindings;
38
+ if (!bindings || !ts.isNamedImports(bindings)) continue;
39
+ if (bindings.elements.some((element) => element.name.text === name)) {
40
+ return { code, changed: false };
41
+ }
42
+ // Keep the clause alphabetical — the order every formatter in this repo's
43
+ // toolchain writes, so an inserted name does not read as a stray.
44
+ const after = bindings.elements.find((element) => element.name.text > name);
45
+ if (after) {
46
+ const at = after.getStart(sf);
47
+ return { code: `${code.slice(0, at)}${name}, ${code.slice(at)}`, changed: true };
48
+ }
49
+ const last = bindings.elements[bindings.elements.length - 1];
50
+ const at = last ? last.getEnd() : bindings.getEnd() - 1;
51
+ const separator = last ? ', ' : '';
52
+ return { code: `${code.slice(0, at)}${separator}${name}${code.slice(at)}`, changed: true };
53
+ }
54
+
55
+ const statement = `import { ${name} } from ${quoteOf(sf, code)}${moduleSpecifier}${quoteOf(sf, code)}${semicolonOf(imports, code)}`;
56
+ const lastImport = imports[imports.length - 1];
57
+ if (!lastImport) return { code: `${statement}\n${code}`, changed: true };
58
+ const at = lastImport.getEnd();
59
+ return { code: `${code.slice(0, at)}\n${statement}${code.slice(at)}`, changed: true };
60
+ }
61
+
62
+ /** Ensure either ecosystem-native import spelling. Component discovery knows
63
+ * whether a project component is a default or named export; preserving that
64
+ * fact avoids inventing a registry or wrapper merely to place it. */
65
+ export function ensureValueImport(
66
+ code: string,
67
+ name: string,
68
+ moduleSpecifier: string,
69
+ kind: 'default' | 'named' = 'named',
70
+ ): StructEditResult {
71
+ if (kind === 'named') return ensureNamedImport(code, name, moduleSpecifier);
72
+ const sf = parseAuthoringTsx('module.tsx', code);
73
+ const imports = sf.statements.filter(ts.isImportDeclaration);
74
+ for (const declaration of imports) {
75
+ if (!importsFrom(declaration, moduleSpecifier)) continue;
76
+ const defaultBinding = defaultBindingStatus(declaration.importClause, name);
77
+ if (defaultBinding === 'same') return { code, changed: false };
78
+ // A module may have only one default binding per import declaration. If
79
+ // this file already chose another local name, import the same ecosystem
80
+ // value through standard ESM's named-default spelling instead of emitting
81
+ // a second default clause.
82
+ if (defaultBinding === 'different') {
83
+ const statement = `import { default as ${name} } from ${quoteOf(sf, code)}${moduleSpecifier}${quoteOf(sf, code)}${semicolonOf(imports, code)}`;
84
+ const at = declaration.getEnd();
85
+ return { code: `${code.slice(0, at)}\n${statement}${code.slice(at)}`, changed: true };
86
+ }
87
+ }
88
+ const statement = `import ${name} from ${quoteOf(sf, code)}${moduleSpecifier}${quoteOf(sf, code)}${semicolonOf(imports, code)}`;
89
+ const lastImport = imports[imports.length - 1];
90
+ if (!lastImport) return { code: `${statement}\n${code}`, changed: true };
91
+ const at = lastImport.getEnd();
92
+ return { code: `${code.slice(0, at)}\n${statement}${code.slice(at)}`, changed: true };
93
+ }
94
+
95
+ function importsFrom(declaration: ts.ImportDeclaration, moduleSpecifier: string): boolean {
96
+ return (
97
+ ts.isStringLiteral(declaration.moduleSpecifier) &&
98
+ declaration.moduleSpecifier.text === moduleSpecifier
99
+ );
100
+ }
101
+
102
+ function defaultBindingStatus(
103
+ clause: ts.ImportClause | undefined,
104
+ name: string,
105
+ ): 'same' | 'different' | 'absent' {
106
+ if (!clause || clause.isTypeOnly) return 'absent';
107
+ if (clause.name?.text === name) return 'same';
108
+ const named = clause.namedBindings;
109
+ if (
110
+ named &&
111
+ ts.isNamedImports(named) &&
112
+ named.elements.some(
113
+ (element) => element.propertyName?.text === 'default' && element.name.text === name,
114
+ )
115
+ ) {
116
+ return 'same';
117
+ }
118
+ return clause.name ? 'different' : 'absent';
119
+ }
120
+
121
+ /** Match the file's own import spelling rather than imposing one. */
122
+ function quoteOf(sf: ts.SourceFile, code: string): string {
123
+ const first = sf.statements.find(ts.isImportDeclaration);
124
+ if (!first) return "'";
125
+ return code[first.moduleSpecifier.getStart(sf)] === '"' ? '"' : "'";
126
+ }
127
+
128
+ function semicolonOf(imports: readonly ts.ImportDeclaration[], code: string): string {
129
+ const last = imports[imports.length - 1];
130
+ if (!last) return ';';
131
+ return code.slice(0, last.getEnd()).trimEnd().endsWith(';') ? ';' : '';
132
+ }