@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.
- package/BUNDLED_NOTICES +1527 -0
- package/LICENSE +686 -0
- package/LICENSE-APACHE +202 -0
- package/NOTICE +18 -0
- package/README.md +24 -0
- package/dist/build/chunk-JS4D4XZ3.js +175 -0
- package/dist/build/chunk-JS4D4XZ3.js.map +7 -0
- package/dist/build/vite-plugin-product-contributions.js +100 -0
- package/dist/build/vite-plugin-product-contributions.js.map +7 -0
- package/dist/build/vite-plugin-shared-react.js +25 -0
- package/dist/build/vite-plugin-shared-react.js.map +7 -0
- package/dist/build/vite-plugin-shared-three.js +86 -0
- package/dist/build/vite-plugin-shared-three.js.map +7 -0
- package/dist/server/chunk-KMJC7AGO.js +98 -0
- package/dist/server/chunk-KMJC7AGO.js.map +7 -0
- package/dist/server/chunk-PSILUMGS.js +46 -0
- package/dist/server/chunk-PSILUMGS.js.map +7 -0
- package/dist/server/frame-proxy.js +255 -0
- package/dist/server/frame-proxy.js.map +7 -0
- package/dist/server/open-browser.js +53 -0
- package/dist/server/open-browser.js.map +7 -0
- package/dist/server/process-shutdown.js +127 -0
- package/dist/server/process-shutdown.js.map +7 -0
- package/dist/server/session-registry.js +141 -0
- package/dist/server/session-registry.js.map +7 -0
- package/dist/server/spawn-opener.js +11 -0
- package/dist/server/spawn-opener.js.map +7 -0
- package/dist/server/worktree-identity.js +11 -0
- package/dist/server/worktree-identity.js.map +7 -0
- package/dist-server/packaged.mjs +88816 -0
- package/package.json +118 -0
- package/scripts/build-plugins.mjs +14 -0
- package/scripts/build-server.mjs +26 -0
- package/scripts/build-session.mjs +9 -0
- package/server/account-credentials.ts +60 -0
- package/server/account-service.ts +1434 -0
- package/server/adapter-region-includes.ts +47 -0
- package/server/asset-catalog-v2.ts +175 -0
- package/server/asset-history-snapshots.ts +196 -0
- package/server/asset-ledger-store.ts +195 -0
- package/server/asset-library-routes.ts +1595 -0
- package/server/blender-wasm-artifact.ts +430 -0
- package/server/boot-timings.ts +106 -0
- package/server/canonical-path.ts +50 -0
- package/server/checkout-workspace-preflight.ts +349 -0
- package/server/cloud-asset-catalog.ts +158 -0
- package/server/coding-inference-launch.ts +237 -0
- package/server/collaboration-account-client.ts +202 -0
- package/server/collaboration-attribution.ts +122 -0
- package/server/collaboration-session.ts +934 -0
- package/server/comfyui-bridge.ts +248 -0
- package/server/console-ledger.ts +499 -0
- package/server/creation-site-transform.ts +304 -0
- package/server/creation-site-write.ts +648 -0
- package/server/data-file-serialize.ts +158 -0
- package/server/editor-brand-html.ts +72 -0
- package/server/editor-control-socket.ts +366 -0
- package/server/editor-server-options.ts +190 -0
- package/server/editor-server.ts +1483 -0
- package/server/editor-sse.ts +352 -0
- package/server/engine-provenance.ts +169 -0
- package/server/engine-source-restart.ts +117 -0
- package/server/frame-bridge.ts +115 -0
- package/server/frame-proxy.ts +490 -0
- package/server/frame-workbench.ts +259 -0
- package/server/frontend-handoff.ts +229 -0
- package/server/game-globals-shadow.ts +113 -0
- package/server/gameplay-session-retention.ts +149 -0
- package/server/gameplay-sessions.ts +123 -0
- package/server/generation-jobs.ts +201 -0
- package/server/generation-reconciler.ts +137 -0
- package/server/generative-execution-context.ts +59 -0
- package/server/git-workflow.ts +612 -0
- package/server/harness-chat-caller.ts +36 -0
- package/server/harness-chat-service.ts +1681 -0
- package/server/idle-shutdown.ts +170 -0
- package/server/js-profiling-policy.ts +52 -0
- package/server/launcher-settings.ts +84 -0
- package/server/local-asset-catalog.ts +410 -0
- package/server/managed-account-defaults.ts +22 -0
- package/server/mock-control-plane.ts +540 -0
- package/server/model-import-conversion.ts +345 -0
- package/server/native-credential-store.ts +162 -0
- package/server/open-browser.ts +118 -0
- package/server/packaged.ts +1192 -0
- package/server/play-stall.ts +126 -0
- package/server/process-shutdown.ts +218 -0
- package/server/product-presets.ts +55 -0
- package/server/project-build-artifact.ts +95 -0
- package/server/project-components.ts +100 -0
- package/server/project-dependency-invalidation.ts +114 -0
- package/server/project-file-scan.ts +235 -0
- package/server/project-hmr-files.ts +215 -0
- package/server/project-install-roots.ts +210 -0
- package/server/project-kinds.ts +71 -0
- package/server/project-mcp-servers.ts +82 -0
- package/server/project-module-freshness.ts +109 -0
- package/server/project-module-instance.ts +375 -0
- package/server/project-optimize-deps-entries.ts +827 -0
- package/server/project-output-writer.ts +679 -0
- package/server/project-package-origin.ts +63 -0
- package/server/project-root-surface.ts +831 -0
- package/server/project-scratch-path.ts +47 -0
- package/server/project-script-hmr.ts +619 -0
- package/server/project-serving-plugins.ts +236 -0
- package/server/project-tools.ts +653 -0
- package/server/project-validation.ts +250 -0
- package/server/project-verbs.ts +127 -0
- package/server/project-view.ts +52 -0
- package/server/project-watch.ts +1134 -0
- package/server/project-work-coordinator.ts +288 -0
- package/server/provider-credentials.ts +331 -0
- package/server/recent-projects-store.ts +98 -0
- package/server/redact-secrets.ts +71 -0
- package/server/repository-presence.ts +267 -0
- package/server/routes/account.ts +357 -0
- package/server/routes/agents.ts +60 -0
- package/server/routes/assets.ts +154 -0
- package/server/routes/build.ts +13 -0
- package/server/routes/collaboration.ts +595 -0
- package/server/routes/configurations.ts +419 -0
- package/server/routes/context.ts +264 -0
- package/server/routes/control-plane.ts +1811 -0
- package/server/routes/logs.ts +272 -0
- package/server/routes/project-identity.ts +302 -0
- package/server/routes/project-open.ts +429 -0
- package/server/routes/project-source.ts +686 -0
- package/server/routes/project-state.ts +383 -0
- package/server/routes/relay.ts +1029 -0
- package/server/routes/route-helpers.ts +29 -0
- package/server/routes/served-modules.ts +138 -0
- package/server/routes/session-tabs.ts +196 -0
- package/server/routes/settings.ts +121 -0
- package/server/routes/share-control.ts +486 -0
- package/server/routes/themes.ts +116 -0
- package/server/routes/tools.ts +230 -0
- package/server/routes/worktrees.ts +595 -0
- package/server/scoped-game-css.ts +461 -0
- package/server/server-utils.ts +1194 -0
- package/server/session-product.ts +112 -0
- package/server/session-registry.ts +230 -0
- package/server/share-claims.ts +138 -0
- package/server/share-host.ts +526 -0
- package/server/share-session-gateway.ts +1362 -0
- package/server/share-tunnel.ts +123 -0
- package/server/spawn-opener.ts +74 -0
- package/server/support/play/log-format.ts +76 -0
- package/server/support/play/session-record.ts +199 -0
- package/server/support/project/build-discipline.ts +718 -0
- package/server/support/project/inspection-node.ts +119 -0
- package/server/support/project/log-naming.ts +54 -0
- package/server/support/project/provenance.ts +290 -0
- package/server/support/project/run-name.ts +18 -0
- package/server/support/project/session-journal.ts +830 -0
- package/server/support/project/shared.ts +327 -0
- package/server/tab-bootstrap.ts +62 -0
- package/server/tab-heartbeat.ts +477 -0
- package/server/tab-lifecycle.ts +550 -0
- package/server/tab-presence.ts +1508 -0
- package/server/team-agent-mirror.ts +95 -0
- package/server/twin-auth.ts +138 -0
- package/server/vendored-lock-recorder.ts +968 -0
- package/server/worktree-identity.ts +121 -0
- package/server/worktree-management.ts +398 -0
- package/server/worktree-retention.d.mts +13 -0
- package/server/worktree-retention.mjs +205 -0
- package/src/EditorContext.tsx +169 -0
- package/src/account.ts +333 -0
- package/src/action-registry.ts +532 -0
- package/src/active-product.ts +74 -0
- package/src/active-project.ts +155 -0
- package/src/adapter-editor-config.ts +25 -0
- package/src/adapter-observation.ts +49 -0
- package/src/animation/stage-transport.ts +379 -0
- package/src/animation/three-clips-subject.ts +172 -0
- package/src/api/asset-library-wire.ts +45 -0
- package/src/api/assets.ts +365 -0
- package/src/api/base.ts +10 -0
- package/src/api/build.ts +99 -0
- package/src/api/git-wire.ts +56 -0
- package/src/api/logs.ts +92 -0
- package/src/api/project-identity.ts +74 -0
- package/src/api/project-open.ts +355 -0
- package/src/api/project-source.ts +162 -0
- package/src/api/project-state.ts +107 -0
- package/src/api/relay.ts +268 -0
- package/src/api/settings.ts +36 -0
- package/src/api/themes.ts +45 -0
- package/src/api/worktrees.ts +257 -0
- package/src/asset-compare-core.ts +171 -0
- package/src/asset-compare.ts +294 -0
- package/src/asset-editor-context.tsx +100 -0
- package/src/asset-events.ts +97 -0
- package/src/asset-inspector-actions.ts +87 -0
- package/src/asset-preview-framing.ts +357 -0
- package/src/asset-preview.ts +2802 -0
- package/src/asset-selection-viewer-registry.ts +113 -0
- package/src/asset-selection.ts +133 -0
- package/src/asset-workflow/asset-capabilities.ts +344 -0
- package/src/asset-workflow/asset-import-jobs.ts +106 -0
- package/src/asset-workflow/asset-ledger-backend.ts +126 -0
- package/src/asset-workflow/asset-ledger.ts +156 -0
- package/src/asset-workflow/asset-materialization-report.ts +140 -0
- package/src/asset-workflow/asset-pack-manifest.ts +320 -0
- package/src/asset-workflow/asset-types.ts +142 -0
- package/src/asset-workflow/asset-workflow-quality.ts +61 -0
- package/src/asset-workflow/audio-preview-player.ts +193 -0
- package/src/asset-workflow/audio-waveform.ts +22 -0
- package/src/asset-workflow/cloud-asset-client.ts +263 -0
- package/src/asset-workflow/folder-preview.ts +345 -0
- package/src/asset-workflow/hosted-asset-materialization.ts +236 -0
- package/src/asset-workflow/image-view-scale.ts +32 -0
- package/src/asset-workflow/import-contract.ts +124 -0
- package/src/asset-workflow/ledger-write-lock.ts +244 -0
- package/src/asset-workflow/model-inspection.ts +818 -0
- package/src/asset-workflow/pixi-spritesheet.ts +197 -0
- package/src/asset-workflow/preview-resource-lifetime.ts +44 -0
- package/src/asset-workflow/project-asset-commands.ts +23 -0
- package/src/asset-workflow/project-asset-health.ts +139 -0
- package/src/asset-workflow/project-asset-operations.ts +154 -0
- package/src/asset-workflow/project-asset-roots.ts +68 -0
- package/src/asset-workflow/project-content.ts +288 -0
- package/src/asset-workflow/project-source-index.ts +550 -0
- package/src/asset-workflow/thumbnail-system.ts +256 -0
- package/src/authoring/active-adapter.ts +199 -0
- package/src/authoring/active-systems.ts +422 -0
- package/src/authoring/adapter-key.ts +18 -0
- package/src/authoring/authoring-asset-url.ts +27 -0
- package/src/authoring/bootstrap-state.ts +49 -0
- package/src/authoring/boundary-authoring-adapter.ts +184 -0
- package/src/authoring/breakpoint-state.ts +43 -0
- package/src/authoring/canvas-scene-guides.ts +76 -0
- package/src/authoring/component-instance-root.ts +171 -0
- package/src/authoring/composite-authoring-adapter.ts +2110 -0
- package/src/authoring/consumer-actions.ts +520 -0
- package/src/authoring/css-numeric-style.ts +97 -0
- package/src/authoring/design-time-layers.ts +849 -0
- package/src/authoring/design-time-mount-registry.ts +235 -0
- package/src/authoring/design-time-settle.ts +343 -0
- package/src/authoring/edit-mode-authoring.ts +619 -0
- package/src/authoring/eyedropper-session.ts +60 -0
- package/src/authoring/instance-source-menu-register.ts +13 -0
- package/src/authoring/instance-source-menu.ts +135 -0
- package/src/authoring/layered-pick.ts +183 -0
- package/src/authoring/live-gesture-lock.ts +50 -0
- package/src/authoring/live-object-transform.ts +62 -0
- package/src/authoring/mount-failure-report.ts +154 -0
- package/src/authoring/mounted-root-subjects.ts +144 -0
- package/src/authoring/no-authoring-adapter.ts +55 -0
- package/src/authoring/null-inspection-subjects.tsx +75 -0
- package/src/authoring/object3d-document-persistence.ts +106 -0
- package/src/authoring/object3d-document-session-registry.ts +120 -0
- package/src/authoring/object3d-document-session.ts +1326 -0
- package/src/authoring/object3d-gesture-controller.ts +113 -0
- package/src/authoring/panel-authoring.ts +121 -0
- package/src/authoring/prefab-instance-inspector-section.tsx +237 -0
- package/src/authoring/prefab-instance-section-model.ts +55 -0
- package/src/authoring/project-authoring-session.ts +105 -0
- package/src/authoring/provenance.ts +99 -0
- package/src/authoring/quarks-particle-systems.ts +19 -0
- package/src/authoring/react-canvas-navigation.ts +255 -0
- package/src/authoring/react-design-canvas-style.ts +20 -0
- package/src/authoring/react-story-board.ts +937 -0
- package/src/authoring/selection-scope.ts +195 -0
- package/src/authoring/shell-document-ops.ts +169 -0
- package/src/authoring/shell-object3d-document-write-policy.ts +108 -0
- package/src/authoring/shell-viewport-policy.ts +48 -0
- package/src/authoring/source-object3d-authoring-adapter.ts +526 -0
- package/src/authoring/stories-scope.ts +35 -0
- package/src/authoring/story-board-chrome-fit.ts +107 -0
- package/src/authoring/story-board-presentation.ts +111 -0
- package/src/authoring/three-projection-core.ts +226 -0
- package/src/authoring/viewport-pick-context.ts +40 -0
- package/src/authoring/viewport-raycast.ts +240 -0
- package/src/authoring/viewport-tool-context.ts +73 -0
- package/src/authoring/world-canvas-viewport-state.ts +35 -0
- package/src/authoring/world-hidden-viewport.ts +152 -0
- package/src/authoring/world-pan-state.ts +198 -0
- package/src/authoring/world-session-state.ts +101 -0
- package/src/authoring/write-pipe.ts +173 -0
- package/src/availability-tick.ts +66 -0
- package/src/bitmap-label.ts +120 -0
- package/src/blender-tab-metrics.ts +161 -0
- package/src/board-open-actions.ts +20 -0
- package/src/boot-routing.ts +391 -0
- package/src/build-identity.ts +15 -0
- package/src/bytes-codec.ts +62 -0
- package/src/camera-authoring.ts +175 -0
- package/src/cancellation-reason.ts +58 -0
- package/src/canvas-preview-frames.ts +482 -0
- package/src/capture-camera-pose.ts +77 -0
- package/src/chrome-registry.ts +159 -0
- package/src/chrome-slot-registry.ts +91 -0
- package/src/collaboration-client.ts +264 -0
- package/src/collaboration-presence.ts +41 -0
- package/src/command-dispatch.ts +19 -0
- package/src/command-listener.ts +2743 -0
- package/src/command-registry.ts +70 -0
- package/src/component-board-registry.ts +205 -0
- package/src/component-states-registry.ts +200 -0
- package/src/components/AgentPresentationNotice.tsx +75 -0
- package/src/components/AlignToolbar.tsx +204 -0
- package/src/components/AppRoot.tsx +394 -0
- package/src/components/ApplicationMenus.tsx +415 -0
- package/src/components/AssetBrowser.tsx +2843 -0
- package/src/components/AssetEditorShell.tsx +216 -0
- package/src/components/AssetInspectorToolSection.tsx +124 -0
- package/src/components/BoardRulers.tsx +354 -0
- package/src/components/CameraInfo.tsx +81 -0
- package/src/components/CanvasSceneViewport.tsx +556 -0
- package/src/components/CapabilityCoverageSection.tsx +185 -0
- package/src/components/CenterDocuments.tsx +22 -0
- package/src/components/ChromeSlot.tsx +20 -0
- package/src/components/CodeView.tsx +470 -0
- package/src/components/CollaborationHeaderControl.css +74 -0
- package/src/components/CompactInspectorCard.tsx +190 -0
- package/src/components/CompactInspectorShell.tsx +39 -0
- package/src/components/ConsolePanel.css +55 -0
- package/src/components/ConsolePanel.tsx +270 -0
- package/src/components/DefaultEditorLayout.tsx +106 -0
- package/src/components/DocumentHeaderStrip.tsx +96 -0
- package/src/components/DocumentShelfRail.tsx +45 -0
- package/src/components/DocumentThumbnail.tsx +345 -0
- package/src/components/EditorLeaseGuard.tsx +372 -0
- package/src/components/ErrorBanner.tsx +123 -0
- package/src/components/FolderPreviewTile.tsx +159 -0
- package/src/components/GameHierarchy.tsx +3842 -0
- package/src/components/GameplaySessionTimeline.tsx +295 -0
- package/src/components/InspectionProjection.tsx +968 -0
- package/src/components/Inspector.tsx +233 -0
- package/src/components/InspectorCanvasPreview.tsx +35 -0
- package/src/components/InspectorFieldsSection.tsx +290 -0
- package/src/components/InspectorObjectPreview.tsx +57 -0
- package/src/components/InspectorStoriesSection.tsx +92 -0
- package/src/components/InspectorToolSection.tsx +96 -0
- package/src/components/InspectorTransformSection.tsx +245 -0
- package/src/components/LightExplorerPanel.tsx +433 -0
- package/src/components/MediaProperties.tsx +145 -0
- package/src/components/NonThreeAuthoringBootstrap.tsx +19 -0
- package/src/components/Object3DDocumentToolbar.css +100 -0
- package/src/components/Object3DDocumentToolbar.tsx +454 -0
- package/src/components/Object3DDocumentViewport.tsx +58 -0
- package/src/components/ProjectHeader.css +617 -0
- package/src/components/ProjectHeader.tsx +328 -0
- package/src/components/ProjectLayout.tsx +249 -0
- package/src/components/ReactCanvasControls.tsx +284 -0
- package/src/components/RootSelectionOverlay.tsx +3162 -0
- package/src/components/RootTextEditor.tsx +79 -0
- package/src/components/SaveStatus.tsx +70 -0
- package/src/components/StageHost.tsx +1954 -0
- package/src/components/StageOverlays.tsx +21 -0
- package/src/components/StartupErrorScreen.tsx +76 -0
- package/src/components/StartupLoadingScreen.tsx +65 -0
- package/src/components/StatsOverlay.tsx +78 -0
- package/src/components/SurfaceStateOverlay.tsx +24 -0
- package/src/components/ToolContributionSurfaces.tsx +65 -0
- package/src/components/ToolHost.tsx +370 -0
- package/src/components/ToolObject3DPreview.tsx +39 -0
- package/src/components/Toolbar.tsx +595 -0
- package/src/components/TransientHint.tsx +44 -0
- package/src/components/TransportStrip.tsx +174 -0
- package/src/components/VersionControlSection.tsx +470 -0
- package/src/components/VgaiLogo.css +83 -0
- package/src/components/VgaiLogo.tsx +35 -0
- package/src/components/ViewportControlsHint.tsx +60 -0
- package/src/components/ViewportFurniture.tsx +401 -0
- package/src/components/ViewportOverlay.tsx +145 -0
- package/src/components/ViewportOverlaysMenu.tsx +153 -0
- package/src/components/ViewportShadingMenu.tsx +300 -0
- package/src/components/ViewportViewMenu.tsx +101 -0
- package/src/components/WorkspaceDocumentSurface.tsx +204 -0
- package/src/components/WorkspaceUtilitySurface.tsx +22 -0
- package/src/components/WorktreeSwitcher.css +239 -0
- package/src/components/WorktreeSwitcher.tsx +890 -0
- package/src/components/account-documents.tsx +1162 -0
- package/src/components/asset-documents.tsx +812 -0
- package/src/components/asset-editor-persistence.ts +216 -0
- package/src/components/asset-selection-section.tsx +535 -0
- package/src/components/asset-thumbnails.tsx +312 -0
- package/src/components/asset-viewers/AudioViewer.tsx +201 -0
- package/src/components/asset-viewers/EntityModelDocument.tsx +122 -0
- package/src/components/asset-viewers/EnvironmentAssetDocument.tsx +440 -0
- package/src/components/asset-viewers/GenericJsonViewer.tsx +102 -0
- package/src/components/asset-viewers/ImageViewer.tsx +300 -0
- package/src/components/asset-viewers/JsonAssetDocument.tsx +93 -0
- package/src/components/asset-viewers/LiveModuleDocument.tsx +417 -0
- package/src/components/asset-viewers/LutAssetDocument.tsx +444 -0
- package/src/components/asset-viewers/ModelAssetDocument.tsx +105 -0
- package/src/components/asset-viewers/Object3DPreview.tsx +359 -0
- package/src/components/asset-viewers/OnlineAssetDetail.tsx +421 -0
- package/src/components/asset-viewers/PasteboardModuleDocument.tsx +67 -0
- package/src/components/asset-viewers/QuarksAssetDocument.tsx +526 -0
- package/src/components/asset-viewers/ShaderAssetDocument.tsx +743 -0
- package/src/components/asset-viewers/SourceAssetViewer.tsx +281 -0
- package/src/components/asset-viewers/SpritesheetSpriteView.tsx +102 -0
- package/src/components/asset-viewers/VideoViewer.tsx +101 -0
- package/src/components/asset-viewers/shader-source.ts +144 -0
- package/src/components/asset-workflow.css +731 -0
- package/src/components/board-guides.ts +150 -0
- package/src/components/compact-inspector.css +539 -0
- package/src/components/core-utilities.tsx +90 -0
- package/src/components/editor-notifications.css +40 -0
- package/src/components/engine-workspace.css +274 -0
- package/src/components/inspector-preview-section.tsx +238 -0
- package/src/components/inspector-property-grouping.ts +64 -0
- package/src/components/inspector-revert-label.ts +20 -0
- package/src/components/inspector-selection.ts +42 -0
- package/src/components/inspector-stories-gating.ts +171 -0
- package/src/components/inspector-transform-subject.ts +11 -0
- package/src/components/inspector-transform.ts +75 -0
- package/src/components/kind-documents.tsx +500 -0
- package/src/components/palette-action-publisher.tsx +140 -0
- package/src/components/primitives/DraftColorInput.tsx +74 -0
- package/src/components/product-shell.css +1829 -0
- package/src/components/project-tool-documents.tsx +410 -0
- package/src/components/scene-documents.tsx +223 -0
- package/src/components/stage-keyboard.tsx +37 -0
- package/src/components/stage-overlay-set.tsx +107 -0
- package/src/components/stage-presence-markers.ts +478 -0
- package/src/components/standard-viewport-dressing.ts +417 -0
- package/src/components/status-contributions.tsx +403 -0
- package/src/components/tool-documents.tsx +309 -0
- package/src/components/tool-schema-form.tsx +262 -0
- package/src/components/use-after-paint.ts +41 -0
- package/src/components/use-project-image-assets.ts +86 -0
- package/src/components/viewport-header-controls.css +90 -0
- package/src/components/viewport-surface-status.tsx +55 -0
- package/src/components/workspace-history.ts +32 -0
- package/src/components/workspace-static-panel-registry.tsx +152 -0
- package/src/components/workspace-surfaces.css +621 -0
- package/src/components/world-documents.tsx +586 -0
- package/src/components/world-overlay-gestures.ts +1694 -0
- package/src/composite-screenshot.ts +1641 -0
- package/src/console-sync.ts +131 -0
- package/src/constraint-helper.ts +338 -0
- package/src/content-entry-source-registry.ts +184 -0
- package/src/coverage/authoring-seam-evidence.ts +300 -0
- package/src/coverage/canvas-reveal.ts +192 -0
- package/src/coverage/design-time-surfaces.ts +101 -0
- package/src/coverage/live-seam-evidence.ts +11 -0
- package/src/coverage/ontology-invariants.ts +466 -0
- package/src/coverage/session-vitals.ts +501 -0
- package/src/coverage/system-seam-evidence.ts +72 -0
- package/src/crash-null-boundary.ts +36 -0
- package/src/creation-site-edit.ts +1479 -0
- package/src/creation-site-registry.ts +160 -0
- package/src/delegate-harness-registry.ts +143 -0
- package/src/document-context-registry.ts +177 -0
- package/src/document-open-registry.ts +200 -0
- package/src/document-preview-source.ts +20 -0
- package/src/document-renderer-session.ts +138 -0
- package/src/editor-api.ts +46 -0
- package/src/editor-chrome-capture.ts +139 -0
- package/src/editor-commands.ts +164 -0
- package/src/editor-console.ts +563 -0
- package/src/editor-current-view.ts +82 -0
- package/src/editor-document-probe.ts +881 -0
- package/src/editor-git-client.ts +115 -0
- package/src/editor-host-door.ts +462 -0
- package/src/editor-hotkeys.ts +842 -0
- package/src/editor-lease-view.ts +39 -0
- package/src/editor-lease.ts +415 -0
- package/src/editor-mode.ts +19 -0
- package/src/editor-notifications.ts +140 -0
- package/src/editor-presence.ts +563 -0
- package/src/editor-presentation-activity.ts +50 -0
- package/src/editor-presentation-notice.ts +42 -0
- package/src/editor-runtime.tsx +145 -0
- package/src/editor-server-response.ts +86 -0
- package/src/editor-session-attribution.ts +75 -0
- package/src/editor-session-mode.ts +54 -0
- package/src/editor-shell-store.ts +1304 -0
- package/src/editor-state-facets.ts +74 -0
- package/src/editor-styles.css +33 -0
- package/src/editor-view-presentation.ts +810 -0
- package/src/editor-viewport.ts +5302 -0
- package/src/entity-lod.ts +31 -0
- package/src/entity-object.ts +91 -0
- package/src/files/file-provider.ts +62 -0
- package/src/files/project-files.ts +264 -0
- package/src/finders/index.ts +136 -0
- package/src/finders/scenes-from-entrypoint-selection.ts +387 -0
- package/src/frame/bridge.tsx +1408 -0
- package/src/frame/product.ts +77 -0
- package/src/gameplay-dom-recording.ts +319 -0
- package/src/gameplay-export-state.ts +14 -0
- package/src/gameplay-replay.ts +417 -0
- package/src/gameplay-session-time.ts +9 -0
- package/src/gameplay-sessions.ts +204 -0
- package/src/harness-chat-types.ts +253 -0
- package/src/hierarchy-component-marks.ts +298 -0
- package/src/hierarchy-drop.ts +91 -0
- package/src/hierarchy-expansion-state.ts +80 -0
- package/src/hierarchy-header-slot.ts +52 -0
- package/src/hierarchy-internals.ts +197 -0
- package/src/hierarchy-kind-icon.ts +217 -0
- package/src/hierarchy-mark-reader.ts +73 -0
- package/src/hierarchy-menu-registry.ts +67 -0
- package/src/hierarchy-node-rows.ts +307 -0
- package/src/hierarchy-panel-view.ts +280 -0
- package/src/hierarchy-projection.ts +76 -0
- package/src/hierarchy-row-cache.ts +243 -0
- package/src/hierarchy-row-model.ts +308 -0
- package/src/hierarchy-rows.ts +11 -0
- package/src/hierarchy-walk.ts +86 -0
- package/src/history/editor-session.ts +25 -0
- package/src/history/history-commands.ts +147 -0
- package/src/history/history-delegate.ts +163 -0
- package/src/history/history-limit-notices.ts +43 -0
- package/src/history/history-service.ts +1173 -0
- package/src/history/persistence-coordinator.ts +35 -0
- package/src/history/project-file-history.ts +386 -0
- package/src/history/project-root-history-backends.ts +139 -0
- package/src/history/resource-registry.ts +209 -0
- package/src/history/snapshot-store.ts +103 -0
- package/src/history/source-history-backend.ts +546 -0
- package/src/history/types.ts +124 -0
- package/src/hmr-registration-group.ts +67 -0
- package/src/hmr-stable-react-context.ts +23 -0
- package/src/hotkeys.ts +188 -0
- package/src/inference-diagnostics.ts +69 -0
- package/src/initial-project.ts +80 -0
- package/src/inspection/active-subject.ts +578 -0
- package/src/inspection/active-surface.ts +142 -0
- package/src/inspection/compose.ts +1064 -0
- package/src/inspection/display.ts +170 -0
- package/src/inspection/document-subject.ts +109 -0
- package/src/inspection/game-subject.ts +85 -0
- package/src/inspection/model.ts +542 -0
- package/src/inspection/null-subject.ts +115 -0
- package/src/inspection/serialize.ts +357 -0
- package/src/inspection/use-active-inspection.ts +180 -0
- package/src/inspector-presentation.ts +201 -0
- package/src/inspector-section-registry.ts +221 -0
- package/src/instance-source-actions.ts +163 -0
- package/src/instanced-presentation.ts +164 -0
- package/src/js-heap.ts +71 -0
- package/src/key-actions.ts +91 -0
- package/src/keymap-presets.ts +401 -0
- package/src/layout-policy.ts +31 -0
- package/src/learn-links.ts +73 -0
- package/src/light-explorer-model.ts +134 -0
- package/src/live-canvas-frame.ts +55 -0
- package/src/live-document.ts +279 -0
- package/src/live-module-source.ts +230 -0
- package/src/live-session-registry.ts +220 -0
- package/src/live-transition.ts +633 -0
- package/src/manifest-project.ts +107 -0
- package/src/model-thumbnail.ts +523 -0
- package/src/native-selection-style.ts +202 -0
- package/src/object3d-document-write-policy.ts +137 -0
- package/src/packaged-runtime.ts +108 -0
- package/src/palettes/maya.palette.json +57 -0
- package/src/palettes/substance.palette.json +57 -0
- package/src/pasteboard-module.ts +81 -0
- package/src/performance-profiler.ts +367 -0
- package/src/performance-sources.ts +69 -0
- package/src/play-boot-phase.ts +145 -0
- package/src/presentation-surface.ts +248 -0
- package/src/project-adapter.ts +1143 -0
- package/src/project-asset-refresh.ts +26 -0
- package/src/project-declaration-refresh.ts +31 -0
- package/src/project-local-state.ts +118 -0
- package/src/project-manager.ts +243 -0
- package/src/project-module-changes.ts +163 -0
- package/src/project-module-split.ts +266 -0
- package/src/project-provenance.ts +115 -0
- package/src/project-ready.ts +42 -0
- package/src/project-session-reset.ts +67 -0
- package/src/project-shape.ts +68 -0
- package/src/project-tool-discovery.ts +66 -0
- package/src/project-tools.ts +107 -0
- package/src/project-work-types.ts +149 -0
- package/src/projection/three.ts +898 -0
- package/src/projection/types.ts +44 -0
- package/src/readiness.ts +113 -0
- package/src/reflection-probe-helper.ts +142 -0
- package/src/reported-play-state.ts +90 -0
- package/src/resolve-relative-specifier.ts +33 -0
- package/src/scene-document-plan.ts +315 -0
- package/src/scene-framing.ts +315 -0
- package/src/scene-live-open.ts +210 -0
- package/src/scene-view-fog.ts +89 -0
- package/src/scoped-game-css.ts +152 -0
- package/src/session-orphan-record.ts +193 -0
- package/src/session-tombstone.ts +126 -0
- package/src/settings/settings-provider.ts +82 -0
- package/src/settings-store.ts +345 -0
- package/src/shared-view-restore.ts +42 -0
- package/src/shell-store-door.ts +45 -0
- package/src/source-conflict.ts +122 -0
- package/src/spatial-handle-visuals.ts +332 -0
- package/src/stage-context.ts +341 -0
- package/src/stage-store-registry.ts +63 -0
- package/src/stale-chunk-recovery.ts +34 -0
- package/src/state-report-deferral.ts +73 -0
- package/src/storage/host-files-storage.ts +97 -0
- package/src/storage/http-storage.ts +174 -0
- package/src/storage/index.ts +75 -0
- package/src/storage/mem-storage.ts +149 -0
- package/src/storage/path-lock.ts +44 -0
- package/src/storage/paths.ts +26 -0
- package/src/storage/types.ts +116 -0
- package/src/stories/StoryComponentThumbnail.tsx +184 -0
- package/src/stories/StoryPreviewMount.tsx +306 -0
- package/src/stories/component-content-source.tsx +106 -0
- package/src/stories/component-states-source.ts +78 -0
- package/src/stories/compose-project-stories.ts +255 -0
- package/src/stories/pixi-story-model.ts +30 -0
- package/src/stories/prefabs-finder.ts +54 -0
- package/src/stories/prefabs-from-stories.ts +182 -0
- package/src/stories/project-story-discovery.ts +78 -0
- package/src/stories/project-story-regions.ts +24 -0
- package/src/stories/story-actions.ts +54 -0
- package/src/stories/story-capture-command.ts +124 -0
- package/src/stories/story-capture.ts +584 -0
- package/src/stories/story-declared-medium.ts +126 -0
- package/src/stories/story-discovery.ts +176 -0
- package/src/stories/story-document-openers.ts +36 -0
- package/src/stories/story-dom-runtime.ts +78 -0
- package/src/stories/story-grouping.ts +111 -0
- package/src/stories/story-lane.ts +88 -0
- package/src/stories/story-mount-turn.ts +27 -0
- package/src/stories/story-opener.ts +260 -0
- package/src/stories/story-pixi-preview.ts +408 -0
- package/src/stories/story-presentation.ts +215 -0
- package/src/stories/story-registry.ts +517 -0
- package/src/stories/story-three-preview.ts +807 -0
- package/src/stories/three-story-model.ts +96 -0
- package/src/story-three-preview-runtime.ts +56 -0
- package/src/surface-keyboard.ts +112 -0
- package/src/surface-state.ts +124 -0
- package/src/tab-bootstrap.js +628 -0
- package/src/tab-census.ts +198 -0
- package/src/tab-lifecycle-client.ts +196 -0
- package/src/theme-library.ts +844 -0
- package/src/theme-preference.ts +378 -0
- package/src/theme.css +3437 -0
- package/src/three-viewport/bone-selection-highlight.ts +119 -0
- package/src/three-viewport/camera-fit.ts +41 -0
- package/src/three-viewport/interactive-renderer.ts +132 -0
- package/src/three-viewport/selection-brackets.ts +310 -0
- package/src/three-viewport/selection-outline.ts +183 -0
- package/src/three-viewport/skeleton-helper.ts +61 -0
- package/src/three-viewport/source-color.ts +167 -0
- package/src/three-viewport/studio-environment.ts +96 -0
- package/src/three-viewport-presentation.ts +23 -0
- package/src/tool-contribution-play.ts +74 -0
- package/src/tool-loader.ts +1798 -0
- package/src/transform-mode-request.ts +57 -0
- package/src/transient-hint.ts +78 -0
- package/src/trigger-volume-helper.ts +116 -0
- package/src/ui-source/adapter-region-includes.ts +241 -0
- package/src/ui-source/ensure-import.ts +132 -0
- package/src/ui-source/file-region-resolver.ts +302 -0
- package/src/ui-source/inspect.ts +775 -0
- package/src/ui-source/oid-transform.ts +1845 -0
- package/src/ui-source/plan-csf-story.ts +196 -0
- package/src/ui-source/plan-extract-component.ts +421 -0
- package/src/ui-source/plan-fork-component.ts +621 -0
- package/src/ui-source/plan-named-style.ts +95 -0
- package/src/ui-source/plan-source-edit.ts +353 -0
- package/src/ui-source/r3f-contract-resolver.ts +327 -0
- package/src/ui-source/r3f-diagnostic-index.ts +165 -0
- package/src/ui-source/r3f-environment-binding.ts +133 -0
- package/src/ui-source/r3f-joint-binding.ts +251 -0
- package/src/ui-source/r3f-lod-binding.ts +91 -0
- package/src/ui-source/r3f-particle-binding.ts +235 -0
- package/src/ui-source/r3f-physics-binding.ts +483 -0
- package/src/ui-source/r3f-project-contracts.ts +444 -0
- package/src/ui-source/relative-import-specifier.ts +34 -0
- package/src/ui-source/reparent-guard.ts +544 -0
- package/src/ui-source/source-edit-request.ts +97 -0
- package/src/ui-source/source-write-backend.ts +618 -0
- package/src/ui-source/syntactic-prop-specs.ts +296 -0
- package/src/ui-source/tier-source-write-backend.ts +279 -0
- package/src/ui-source/ts-ast.ts +171 -0
- package/src/ui-source/utility-class-support.ts +169 -0
- package/src/ui-source/write-component-default.ts +133 -0
- package/src/ui-source/writer.ts +1989 -0
- package/src/viewport-activation-timings.ts +840 -0
- package/src/viewport-authoring-policy.ts +186 -0
- package/src/viewport-controls-hint.ts +57 -0
- package/src/viewport-door.ts +237 -0
- package/src/viewport-shading-boundary.ts +12 -0
- package/src/vite-error-surface.ts +141 -0
- package/src/wait-until.ts +37 -0
- package/src/workspace-areas.ts +156 -0
- package/src/workspace-aux-commands.ts +11 -0
- package/src/workspace-available-documents.ts +127 -0
- package/src/workspace-core-utilities.ts +31 -0
- package/src/workspace-document-ids.ts +59 -0
- package/src/workspace-document-registry.ts +612 -0
- package/src/workspace-document-restore.ts +145 -0
- package/src/workspace-host-commands.ts +141 -0
- package/src/workspace-persistence-gate.ts +40 -0
- package/src/workspace-play-utilities.ts +44 -0
- package/src/workspace-presets.ts +425 -0
- package/src/workspace-regions.ts +294 -0
- package/src/workspace-state-persistence.ts +536 -0
- package/src/workspace-static-panels.ts +73 -0
- package/src/workspace-status-registry.ts +121 -0
- package/src/workspace-style.ts +239 -0
- package/src/workspace-utility-commands.ts +74 -0
- package/src/workspace-utility-registry.ts +263 -0
- package/src/workspace-viewport-rect.ts +97 -0
- package/src/world-adoption.ts +115 -0
- package/src/world-document-routing.ts +104 -0
- package/vite-plugin-creation-site-write.ts +184 -0
- package/vite-plugin-creation-site.ts +80 -0
- package/vite-plugin-game-static.ts +303 -0
- package/vite-plugin-module-doorways.ts +336 -0
- package/vite-plugin-product-contributions.ts +197 -0
- package/vite-plugin-project-game-static.ts +125 -0
- package/vite-plugin-project-jsx-js.ts +65 -0
- package/vite-plugin-project-root-absolute-assets.ts +359 -0
- package/vite-plugin-shared-react.ts +420 -0
- package/vite-plugin-shared-three.ts +203 -0
- package/vite-plugin-ui-oid.ts +2106 -0
|
@@ -0,0 +1,160 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The creation-site registry — the host-side half of the index whose
|
|
3
|
+
* source half is `server/creation-site-transform.ts`.
|
|
4
|
+
*
|
|
5
|
+
* ANTI-SHIM: the record NEVER touches the object. A `WeakMap` keyed by the
|
|
6
|
+
* constructed object is the whole storage, so an ingested game cannot see that
|
|
7
|
+
* it is being indexed — no new property, no symbol, no `userData` key, nothing
|
|
8
|
+
* enumerable, nothing a `for…in`/`Object.keys`/JSON round-trip can pick up.
|
|
9
|
+
* (This is the same rule the ingest adapter follows for its structural ids'
|
|
10
|
+
* sole exception, `userData.entityId`, which is a deliberate, documented
|
|
11
|
+
* identity tag; a provenance record has no such justification.)
|
|
12
|
+
*
|
|
13
|
+
* RESOURCE OWNERSHIP (brief-rule 4).
|
|
14
|
+
* - THE MAP is owned by this module and scoped to the editor page's realm.
|
|
15
|
+
* Every same-realm mount in the page shares it, which is correct: the
|
|
16
|
+
* stamped modules are ordinary modules in that one realm and their `new`
|
|
17
|
+
* expressions have exactly one place to report to.
|
|
18
|
+
* - IT IS NEVER CLEARED, deliberately. A `WeakMap` holds no strong reference,
|
|
19
|
+
* so a record dies with the object it describes — a game teardown that
|
|
20
|
+
* dropped its scene has already emptied the registry of everything that
|
|
21
|
+
* mattered. An explicit `clear()` on teardown would be a no-op dressed as
|
|
22
|
+
* cleanup, and it would be WRONG for the upgrade path, where a late-captured
|
|
23
|
+
* mount reuses objects constructed before the capture.
|
|
24
|
+
* - THE INSTALLED GLOBAL is the ownable resource, and it has one owner:
|
|
25
|
+
* `installGatedGameGlobals` (`gated-globals.ts`) installs it alongside the
|
|
26
|
+
* other `__vgai*` game-realm globals, once, at the same point in the
|
|
27
|
+
* lifecycle. {@link installCreationSiteRecorder} returns an uninstall for
|
|
28
|
+
* tests, which is the only caller that needs to take it back down.
|
|
29
|
+
*/
|
|
30
|
+
|
|
31
|
+
/** A source location a stamped `new` expression reported. */
|
|
32
|
+
export interface CreationSite {
|
|
33
|
+
/** Project-root-RELATIVE path, POSIX separators (e.g. `src/scripts/sim/city.js`). */
|
|
34
|
+
file: string;
|
|
35
|
+
/** 1-based. */
|
|
36
|
+
line: number;
|
|
37
|
+
/** 0-based character offset. */
|
|
38
|
+
col: number;
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
/**
|
|
42
|
+
* What the read surfaces show for one object: either the anchor, or a NAMED
|
|
43
|
+
* reason there is none. There is no third, blank state — an unanchored object
|
|
44
|
+
* says why (the honest-floor rule).
|
|
45
|
+
*/
|
|
46
|
+
export type CreationSiteAnchor =
|
|
47
|
+
| ({ anchored: true; kind: 'source'; display: string } & CreationSite)
|
|
48
|
+
| { anchored: false; reason: string };
|
|
49
|
+
|
|
50
|
+
/** The reason for an object that exists but was not constructed by a `new`
|
|
51
|
+
* expression in a served project module — a three.js internal, a GLTF
|
|
52
|
+
* loader's mesh, anything from a bundled dependency. The anchoring does not
|
|
53
|
+
* reach these, so this is what the surfaces say, verbatim. */
|
|
54
|
+
export const UNANCHORED_REASON =
|
|
55
|
+
'constructed outside project source (library internals or loader output)';
|
|
56
|
+
|
|
57
|
+
/** The reason for a selection with no live object behind it at all. */
|
|
58
|
+
export const NO_OBJECT_REASON = 'no live object for this selection';
|
|
59
|
+
|
|
60
|
+
const sites = new WeakMap<object, CreationSite>();
|
|
61
|
+
|
|
62
|
+
/**
|
|
63
|
+
* How many objects each anchor has constructed — the MULTIPLICITY signal.
|
|
64
|
+
*
|
|
65
|
+
* SimCity builds all 256 tiles from one line (`const tile = new Tile(x, y)`,
|
|
66
|
+
* `src/scripts/sim/city.js:59`), so "can this edit be written at its creation
|
|
67
|
+
* site?" has a second answer beyond "is there a literal there": writing that
|
|
68
|
+
* line would move every tile, and writing it for one tile is a lie about what
|
|
69
|
+
* the source says. Nothing else in the system knows the count — the WeakMap
|
|
70
|
+
* above is deliberately un-enumerable — so it is counted here, at the one place
|
|
71
|
+
* every construction reports to.
|
|
72
|
+
*
|
|
73
|
+
* A PLAIN `Map`, not a WeakMap, and never decremented: the count is over
|
|
74
|
+
* CONSTRUCTIONS, not live objects. That is the conservative direction — a site
|
|
75
|
+
* that built and dropped a hundred objects still refuses, which costs a refusal
|
|
76
|
+
* the user can read, where a count that forgot its history would eventually let
|
|
77
|
+
* a shared site be written as if it were unique. It is keyed by the site string,
|
|
78
|
+
* so it holds no reference to anything the game owns and cannot leak an object.
|
|
79
|
+
*/
|
|
80
|
+
const instances = new Map<string, number>();
|
|
81
|
+
|
|
82
|
+
function siteKey(site: CreationSite): string {
|
|
83
|
+
return `${site.file}:${site.line}:${site.col}`;
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
/** The global name the served prelude calls through (must match
|
|
87
|
+
* `CREATION_SITE_GLOBAL` in `server/creation-site-transform.ts`; the pairing is
|
|
88
|
+
* asserted by `creation-site-registry.test.ts`). */
|
|
89
|
+
export const CREATION_SITE_GLOBAL = '__vgaiRecordCreationSite';
|
|
90
|
+
|
|
91
|
+
type Recorder = (o: unknown, file: string, line: number, col: number) => void;
|
|
92
|
+
|
|
93
|
+
/**
|
|
94
|
+
* Record one construction. FIRST WRITE WINS: a constructor that returns an
|
|
95
|
+
* already-registered object (a cache, a singleton, an interned value) must not
|
|
96
|
+
* have its true creation site overwritten by the call site that merely asked
|
|
97
|
+
* for it again.
|
|
98
|
+
*/
|
|
99
|
+
export function recordCreationSite(o: unknown, file: string, line: number, col: number): void {
|
|
100
|
+
if (o === null || (typeof o !== 'object' && typeof o !== 'function')) return;
|
|
101
|
+
if (sites.has(o as object)) return;
|
|
102
|
+
const site: CreationSite = { file, line, col };
|
|
103
|
+
sites.set(o as object, site);
|
|
104
|
+
const key = siteKey(site);
|
|
105
|
+
instances.set(key, (instances.get(key) ?? 0) + 1);
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
/**
|
|
109
|
+
* How many objects this anchor has constructed. `0` for a site nothing was ever
|
|
110
|
+
* recorded at. Only `1` may be written by a single-object edit; a deliberate
|
|
111
|
+
* creation-site-default edit may address the full count after naming it — see
|
|
112
|
+
* `creation-site-edit.ts`'s `CreationSiteWriteScope`.
|
|
113
|
+
*/
|
|
114
|
+
export function instancesAtSite(site: CreationSite): number {
|
|
115
|
+
return instances.get(siteKey(site)) ?? 0;
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
/** Test-only: forget every recorded construction count. The WeakMap needs no
|
|
119
|
+
* equivalent (it is collected with its keys) and deliberately has none. */
|
|
120
|
+
export function resetCreationSiteCountsForTest(): void {
|
|
121
|
+
instances.clear();
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
/** The raw record for an object, or `null`. */
|
|
125
|
+
export function creationSiteOf(o: unknown): CreationSite | null {
|
|
126
|
+
if (o === null || (typeof o !== 'object' && typeof o !== 'function')) return null;
|
|
127
|
+
return sites.get(o as object) ?? null;
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
/** `src/scripts/sim/city.js:59` — the text the inspector shows and `vgai eval` reads. */
|
|
131
|
+
export function formatCreationSite(site: CreationSite): string {
|
|
132
|
+
return `${site.file}:${site.line}`;
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
/**
|
|
136
|
+
* The read-surface answer for one object: the anchor, or the named reason there
|
|
137
|
+
* isn't one. `null`/a non-object means the caller had no live object to ask
|
|
138
|
+
* about, which is a DIFFERENT honest answer from "the library built it".
|
|
139
|
+
*/
|
|
140
|
+
export function creationSiteAnchor(o: unknown): CreationSiteAnchor {
|
|
141
|
+
if (o === null || o === undefined) return { anchored: false, reason: NO_OBJECT_REASON };
|
|
142
|
+
const site = creationSiteOf(o);
|
|
143
|
+
if (!site) return { anchored: false, reason: UNANCHORED_REASON };
|
|
144
|
+
return { anchored: true, kind: 'source', ...site, display: formatCreationSite(site) };
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
/**
|
|
148
|
+
* Publish {@link recordCreationSite} on `globalThis` for the served prelude.
|
|
149
|
+
* Idempotent. Returns an uninstall — see the module header for who owns this.
|
|
150
|
+
*/
|
|
151
|
+
export function installCreationSiteRecorder(): () => void {
|
|
152
|
+
const g = globalThis as unknown as Record<string, unknown>;
|
|
153
|
+
const existing = g[CREATION_SITE_GLOBAL];
|
|
154
|
+
if (typeof existing === 'function') return () => {};
|
|
155
|
+
const recorder: Recorder = recordCreationSite;
|
|
156
|
+
g[CREATION_SITE_GLOBAL] = recorder;
|
|
157
|
+
return () => {
|
|
158
|
+
if (g[CREATION_SITE_GLOBAL] === recorder) delete g[CREATION_SITE_GLOBAL];
|
|
159
|
+
};
|
|
160
|
+
}
|
|
@@ -0,0 +1,143 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* WHICH CODING HARNESSES CAN BE DELEGATED TO — the eleventh registry in the
|
|
3
|
+
* family of `workspace-document-restore.ts` (a kind owns its persisted state),
|
|
4
|
+
* `document-open-registry.ts` (a kind owns how it opens), `chrome-slot-registry
|
|
5
|
+
* .ts` (the host owns the place, a package owns what sits there),
|
|
6
|
+
* `content-entry-source-registry.ts` (the host owns the Content scope, a
|
|
7
|
+
* package owns why a component is content) and the seven since. Here: the host
|
|
8
|
+
* owns the DELEGATE FORM — the task text, the isolation choice, the branch
|
|
9
|
+
* name, the button, the notice line and `delegateEditorTask` itself — and a
|
|
10
|
+
* package owns WHICH AGENTS EXIST.
|
|
11
|
+
*
|
|
12
|
+
* WHY IT EXISTS. `components/WorktreeSwitcher.tsx`'s Delegate form was the
|
|
13
|
+
* single edge holding `api/agents.ts` and its three wire modules in the
|
|
14
|
+
* editor's eager import closure (WORK.md §The open-source launch, the four
|
|
15
|
+
* that remained of the harness bucket): it called `getHarnessChatSnapshot()`
|
|
16
|
+
* to list which harnesses are installed, and it named two of them by hand
|
|
17
|
+
* (`claude`, `codex`) for its container isolation. A base library for making
|
|
18
|
+
* IDEs should not know the name of a coding agent.
|
|
19
|
+
*
|
|
20
|
+
* THE DOOR THE RECORD NAMED WAS A BIGGER ONE, AND THE CODE DID NOT WANT IT.
|
|
21
|
+
* Unit 21 specified "a chrome slot that can hand its filler a dismiss/refresh
|
|
22
|
+
* callback", i.e. the whole form becoming `@vgai/agents`' surface. Measured
|
|
23
|
+
* against the form: of its ~120 lines, everything but the harness `<Select>`
|
|
24
|
+
* is the worktree board's own vocabulary — the branch slug, the three
|
|
25
|
+
* isolations, the copy about sibling checkouts and bounded containers, and
|
|
26
|
+
* `delegateEditorTask` (`api/worktrees.ts`, a `keep`-bucket module whose wire
|
|
27
|
+
* already takes a `harness` string). Moving it would have put the board's
|
|
28
|
+
* delegation UI inside the agents package AND changed `ChromeSlotFiller` —
|
|
29
|
+
* whose whole claim is that a slot is a PLACE, rendered `<filler.Content />`
|
|
30
|
+
* with no props — for every existing filler. What the host actually cannot
|
|
31
|
+
* answer is one question, so one question is what it asks.
|
|
32
|
+
*
|
|
33
|
+
* ASKED PER ISOLATION, because the answer differs and only the source knows
|
|
34
|
+
* how: a worktree or in-place delegation needs a harness that is INSTALLED and
|
|
35
|
+
* can start, while a bounded container authenticates the harness inside its
|
|
36
|
+
* own temporary home, so "installed here" is not the question. The host passes
|
|
37
|
+
* the isolation and reads a list; which of its harnesses satisfies which is
|
|
38
|
+
* the package's to decide.
|
|
39
|
+
*
|
|
40
|
+
* NOTHING REGISTERED IS A REAL ANSWER. With no source, the picker says "No
|
|
41
|
+
* harness ready" and Delegate stays disabled — the same honest emptiness a
|
|
42
|
+
* document kind with no registered opener gives. That is not a regression
|
|
43
|
+
* risk for any shipped build: `WorktreeSwitcher` renders only in `server`
|
|
44
|
+
* editor mode, and every dev session loads `@vgai/agents` through
|
|
45
|
+
* `SESSION_PACKAGES` (`server/project-tools.ts`), while a build with no
|
|
46
|
+
* session has no board at all.
|
|
47
|
+
*/
|
|
48
|
+
|
|
49
|
+
/** How a delegated task is isolated from the caller's checkout — the board's
|
|
50
|
+
* own vocabulary, passed to a source as the question's context. */
|
|
51
|
+
export type DelegateIsolation = 'worktree' | 'current' | 'container';
|
|
52
|
+
|
|
53
|
+
export interface DelegateHarness {
|
|
54
|
+
/** The value `delegateEditorTask({ harness })` takes. */
|
|
55
|
+
readonly id: string;
|
|
56
|
+
/** What the picker shows. */
|
|
57
|
+
readonly label: string;
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
export interface DelegateHarnessSource {
|
|
61
|
+
/** Which module registered it. Re-registering the same owner REPLACES, so
|
|
62
|
+
* an HMR re-evaluation leaves one source, not two. */
|
|
63
|
+
readonly owner: string;
|
|
64
|
+
/** Ascending; ties keep registration order. */
|
|
65
|
+
readonly order?: number;
|
|
66
|
+
/** Asking is a fetch, so this is async; the form re-asks whenever the
|
|
67
|
+
* isolation or the registry version changes. */
|
|
68
|
+
readonly harnesses: (isolation: DelegateIsolation) => Promise<readonly DelegateHarness[]>;
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
const _sources: DelegateHarnessSource[] = [];
|
|
72
|
+
const listeners = new Set<() => void>();
|
|
73
|
+
let version = 0;
|
|
74
|
+
|
|
75
|
+
function publish(): void {
|
|
76
|
+
version++;
|
|
77
|
+
for (const listener of listeners) listener();
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
/** Install a source. Returns the teardown. */
|
|
81
|
+
export function registerDelegateHarnessSource(source: DelegateHarnessSource): () => void {
|
|
82
|
+
const stale = _sources.findIndex((item) => item.owner === source.owner);
|
|
83
|
+
if (stale >= 0) _sources.splice(stale, 1);
|
|
84
|
+
_sources.push(source);
|
|
85
|
+
_sources.sort((a, b) => (a.order ?? 0) - (b.order ?? 0));
|
|
86
|
+
publish();
|
|
87
|
+
return () => {
|
|
88
|
+
const at = _sources.indexOf(source);
|
|
89
|
+
if (at < 0) return;
|
|
90
|
+
_sources.splice(at, 1);
|
|
91
|
+
publish();
|
|
92
|
+
};
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
/**
|
|
96
|
+
* THE HOST'S ONE QUESTION. Every source's answer, in registration order, with
|
|
97
|
+
* the first claim on an id winning — two packages offering the same harness is
|
|
98
|
+
* one harness, and the one that registered earlier named it.
|
|
99
|
+
*
|
|
100
|
+
* A source that throws is skipped rather than taking the form down with it:
|
|
101
|
+
* the picker degrades to the harnesses that did answer, which is the same
|
|
102
|
+
* shape as no source at all.
|
|
103
|
+
*/
|
|
104
|
+
export async function delegateHarnesses(
|
|
105
|
+
isolation: DelegateIsolation,
|
|
106
|
+
): Promise<readonly DelegateHarness[]> {
|
|
107
|
+
const seen = new Set<string>();
|
|
108
|
+
const out: DelegateHarness[] = [];
|
|
109
|
+
for (const source of _sources) {
|
|
110
|
+
let answered: readonly DelegateHarness[];
|
|
111
|
+
try {
|
|
112
|
+
answered = await source.harnesses(isolation);
|
|
113
|
+
} catch {
|
|
114
|
+
continue;
|
|
115
|
+
}
|
|
116
|
+
for (const harness of answered) {
|
|
117
|
+
if (seen.has(harness.id)) continue;
|
|
118
|
+
seen.add(harness.id);
|
|
119
|
+
out.push(harness);
|
|
120
|
+
}
|
|
121
|
+
}
|
|
122
|
+
return out;
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
/** The form's `useSyncExternalStore` subscription: a source arriving with a
|
|
126
|
+
* contribution pass re-asks the question. */
|
|
127
|
+
export function subscribeDelegateHarnessSources(listener: () => void): () => void {
|
|
128
|
+
listeners.add(listener);
|
|
129
|
+
return () => {
|
|
130
|
+
listeners.delete(listener);
|
|
131
|
+
};
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
export function delegateHarnessRegistryVersion(): number {
|
|
135
|
+
return version;
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
/** Test-only reset (mirrors the restore, open, chrome-slot and content-entry
|
|
139
|
+
* registries'). */
|
|
140
|
+
export function __resetDelegateHarnessSourcesForTest(): void {
|
|
141
|
+
_sources.length = 0;
|
|
142
|
+
publish();
|
|
143
|
+
}
|
|
@@ -0,0 +1,177 @@
|
|
|
1
|
+
import {
|
|
2
|
+
object3DDocumentSession,
|
|
3
|
+
object3DDocumentStageAnnounced,
|
|
4
|
+
} from './authoring/object3d-document-session-registry';
|
|
5
|
+
import { DOCUMENT_REGISTRATION_TIMEOUT_MS, waitUntil } from './wait-until';
|
|
6
|
+
|
|
7
|
+
/**
|
|
8
|
+
* THE OPEN DOCUMENT'S OWN CONTEXT, published for the REPL door.
|
|
9
|
+
*
|
|
10
|
+
* A tool document (`workspace.document`) may hand the host ONE object — the
|
|
11
|
+
* live session it edits through — and `editor.document.run(ctx => …)`
|
|
12
|
+
* (`vgai eval`) runs a wire-carried step against it, in Edit mode, without
|
|
13
|
+
* play. This is the "explore in the REPL, commit as source" half of the
|
|
14
|
+
* parity program's one spine (docs/BLENDER-PARITY.md §Execution model): the
|
|
15
|
+
* mesh document publishes its `MeshEditSession`, whose `ctx` is the
|
|
16
|
+
* bpy-shaped edit context, so an agent phrases a modeling step the way the
|
|
17
|
+
* corpus does — context + selection + op — and reads the result back.
|
|
18
|
+
*
|
|
19
|
+
* Keyed by workspace document id; the door resolves the ACTIVE document and
|
|
20
|
+
* refuses by name when it published nothing (a data sheet, a story). A
|
|
21
|
+
* document re-publishes whenever its session object changes (a reload swaps
|
|
22
|
+
* it); publishing returns the unpublish.
|
|
23
|
+
*
|
|
24
|
+
* ITS SIBLING FACT, and the reason they share a module: whether a contributed
|
|
25
|
+
* document has MOUNTED AT ALL. Both are things a contribution's own React root
|
|
26
|
+
* tells the host about itself, and both exist because `ToolHost.tsx` renders
|
|
27
|
+
* that contribution into a SEPARATE root (`createEditorRoot(...).render(...)`),
|
|
28
|
+
* which React schedules — so nothing in the host's own commit can say whether
|
|
29
|
+
* the contribution has rendered yet. Every door that must not read a document
|
|
30
|
+
* "before it decided what it is" waits on one of these two.
|
|
31
|
+
*/
|
|
32
|
+
|
|
33
|
+
const _contexts = new Map<string, unknown>();
|
|
34
|
+
const _listeners = new Set<() => void>();
|
|
35
|
+
const _mounted = new Set<string>();
|
|
36
|
+
const _mountListeners = new Set<() => void>();
|
|
37
|
+
|
|
38
|
+
let _version = 0;
|
|
39
|
+
|
|
40
|
+
function _notifyContexts(): void {
|
|
41
|
+
_version += 1;
|
|
42
|
+
for (const listener of [..._listeners]) listener();
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
export function publishDocumentContext(documentId: string, context: unknown): () => void {
|
|
46
|
+
_contexts.set(documentId, context);
|
|
47
|
+
_notifyContexts();
|
|
48
|
+
return () => {
|
|
49
|
+
if (_contexts.get(documentId) === context) _contexts.delete(documentId);
|
|
50
|
+
};
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
/**
|
|
54
|
+
* THE PUBLISHED CONTEXT HAS MOVED — said by the package that DRIVES the
|
|
55
|
+
* document, not by the one that published it.
|
|
56
|
+
*
|
|
57
|
+
* The context object is a live handle, so a package can change what it answers
|
|
58
|
+
* without ever republishing: `@volter/editor-blender` reads the engine through its RNA
|
|
59
|
+
* door and the answer decides which Properties TABS exist for the selected
|
|
60
|
+
* datablock (an armature has a Bone tab, a cube does not). Nothing in the
|
|
61
|
+
* host's own stores moves when that answer arrives, so before this existed the
|
|
62
|
+
* inspector had no reason to re-compose and the rail stayed at whatever the
|
|
63
|
+
* first render could see.
|
|
64
|
+
*
|
|
65
|
+
* `use-active-inspection.ts` subscribes to {@link documentContextVersion}, so
|
|
66
|
+
* this makes the whole inspection re-derive — matches included.
|
|
67
|
+
*/
|
|
68
|
+
export function notifyDocumentContextChanged(documentId: string): void {
|
|
69
|
+
if (!_contexts.has(documentId)) return;
|
|
70
|
+
_notifyContexts();
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
export function subscribeDocumentContexts(listener: () => void): () => void {
|
|
74
|
+
_listeners.add(listener);
|
|
75
|
+
return () => {
|
|
76
|
+
_listeners.delete(listener);
|
|
77
|
+
};
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
export function documentContextVersion(): number {
|
|
81
|
+
return _version;
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
export function documentContextFor(documentId: string): unknown {
|
|
85
|
+
return _contexts.get(documentId);
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
/** Opening a document activates its tab before an async model import can
|
|
89
|
+
* publish its context. The REPL waits for that publication; it never executes
|
|
90
|
+
* against a placeholder or mistakes a loading document for an unsupported one. */
|
|
91
|
+
export function waitForDocumentContext(documentId: string, timeoutMs = 10_000): Promise<unknown> {
|
|
92
|
+
const current = documentContextFor(documentId);
|
|
93
|
+
if (current !== undefined) return Promise.resolve(current);
|
|
94
|
+
return new Promise((resolve) => {
|
|
95
|
+
const onPublish = () => {
|
|
96
|
+
const context = documentContextFor(documentId);
|
|
97
|
+
if (context === undefined) return;
|
|
98
|
+
clearTimeout(timeout);
|
|
99
|
+
_listeners.delete(onPublish);
|
|
100
|
+
resolve(context);
|
|
101
|
+
};
|
|
102
|
+
const timeout = setTimeout(() => {
|
|
103
|
+
_listeners.delete(onPublish);
|
|
104
|
+
resolve(undefined);
|
|
105
|
+
}, timeoutMs);
|
|
106
|
+
_listeners.add(onPublish);
|
|
107
|
+
});
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
export function __resetDocumentContextsForTest(): void {
|
|
111
|
+
_contexts.clear();
|
|
112
|
+
_mounted.clear();
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
/**
|
|
116
|
+
* A CONTRIBUTED DOCUMENT'S REACT ROOT HAS COMMITTED — published by the host's
|
|
117
|
+
* own wrapper INSIDE that root (`ToolHost.tsx`), so every child effect has run
|
|
118
|
+
* by the time it fires. That ordering is the whole point: it is what lets an
|
|
119
|
+
* opener's `ready` read an absent stage announcement as "this document has no
|
|
120
|
+
* stage" rather than "the stage has not rendered yet"
|
|
121
|
+
* (`authoring/object3d-document-session-registry.ts`).
|
|
122
|
+
*/
|
|
123
|
+
export function markContributedDocumentMounted(documentId: string): () => void {
|
|
124
|
+
_mounted.add(documentId);
|
|
125
|
+
for (const listener of [..._mountListeners]) listener();
|
|
126
|
+
return () => {
|
|
127
|
+
_mounted.delete(documentId);
|
|
128
|
+
};
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
/** Resolves once this document's contribution has committed, `false` if the
|
|
132
|
+
* bounded window elapses first — the same shape and reason as
|
|
133
|
+
* {@link waitForDocumentContext} above. */
|
|
134
|
+
export function waitForContributedDocumentMount(
|
|
135
|
+
documentId: string,
|
|
136
|
+
timeoutMs = 10_000,
|
|
137
|
+
): Promise<boolean> {
|
|
138
|
+
if (_mounted.has(documentId)) return Promise.resolve(true);
|
|
139
|
+
return new Promise((resolve) => {
|
|
140
|
+
const onMount = () => {
|
|
141
|
+
if (!_mounted.has(documentId)) return;
|
|
142
|
+
clearTimeout(timeout);
|
|
143
|
+
_mountListeners.delete(onMount);
|
|
144
|
+
resolve(true);
|
|
145
|
+
};
|
|
146
|
+
const timeout = setTimeout(() => {
|
|
147
|
+
_mountListeners.delete(onMount);
|
|
148
|
+
resolve(false);
|
|
149
|
+
}, timeoutMs);
|
|
150
|
+
_mountListeners.add(onMount);
|
|
151
|
+
});
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
/**
|
|
155
|
+
* THE SHARED HALF OF EVERY OPENER'S `ready` (`document-open-registry.ts`): a
|
|
156
|
+
* document whose stage announced itself
|
|
157
|
+
* (`authoring/object3d-document-session-registry.ts`) is not ready to be
|
|
158
|
+
* driven until that stage has registered its session, and one that announced
|
|
159
|
+
* nothing is ready already. Each caller has already waited for its own MOUNT
|
|
160
|
+
* to settle — the asset family for its Inspector, a contributed document for
|
|
161
|
+
* the React root above — which is what makes an absent announcement mean
|
|
162
|
+
* "this document has no stage" rather than "the stage has not rendered yet".
|
|
163
|
+
*
|
|
164
|
+
* The refusal sentence is the one `editor-view-presentation.ts` used to throw,
|
|
165
|
+
* moved to the kinds' own side unchanged.
|
|
166
|
+
*/
|
|
167
|
+
export async function awaitAnnouncedObject3DDocumentSession(documentId: string): Promise<void> {
|
|
168
|
+
if (!object3DDocumentStageAnnounced(documentId)) return;
|
|
169
|
+
if (
|
|
170
|
+
await waitUntil(
|
|
171
|
+
() => object3DDocumentSession(documentId) !== null,
|
|
172
|
+
DOCUMENT_REGISTRATION_TIMEOUT_MS,
|
|
173
|
+
)
|
|
174
|
+
)
|
|
175
|
+
return;
|
|
176
|
+
throw new Error(`The requested Object3D view did not mount for document: ${documentId}`);
|
|
177
|
+
}
|
|
@@ -0,0 +1,200 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* A DOCUMENT KIND OWNS HOW IT OPENS — the forward half of the seam whose
|
|
3
|
+
* backward half is `workspace-document-restore.ts` (docs/WORKBENCH.md §host
|
|
4
|
+
* versus package).
|
|
5
|
+
*
|
|
6
|
+
* THE RULE. The host ADDRESSES a document (a story on a module, an asset at a
|
|
7
|
+
* path); it does not construct one. A module that can open a kind registers an
|
|
8
|
+
* opener under a named id, and every host call site — the palette, the
|
|
9
|
+
* hierarchy's double-click, the Edit tab row, the layout restore, the view
|
|
10
|
+
* protocol, the SDK's `host.workspace` door — asks for that id instead of
|
|
11
|
+
* importing the document module. When nothing has registered the id (a build
|
|
12
|
+
* whose package list does not carry that kind, a contribution that has not
|
|
13
|
+
* loaded yet) the answer is `null`, and the caller does what it already did
|
|
14
|
+
* for a document it could not open.
|
|
15
|
+
*
|
|
16
|
+
* WHY IT EXISTS. `workspace-document-restore.ts` fixed the PERSISTENCE half:
|
|
17
|
+
* the host no longer names a document module to reopen one. The opening half
|
|
18
|
+
* was still `import { openThreeStoryDocument } from './components/…'` in ten
|
|
19
|
+
* host files, which is the same serialization defect one rung earlier — a
|
|
20
|
+
* document cannot leave for a package while the shell calls its constructor by
|
|
21
|
+
* name. Measured 2026-09-18 (WORK.md §The open-source launch, phase 1 unit 4).
|
|
22
|
+
*
|
|
23
|
+
* WHAT AN ID IS. A string in the host's own vocabulary, declared beside the
|
|
24
|
+
* kind's other host-side contracts (`stories/story-document-openers.ts` is the
|
|
25
|
+
* first), with a request type declared in the SAME place so both sides of the
|
|
26
|
+
* seam are typed against one declaration rather than against each other.
|
|
27
|
+
* Several modules may register one id; they are tried in registration order
|
|
28
|
+
* until one returns a document id.
|
|
29
|
+
*/
|
|
30
|
+
|
|
31
|
+
import type { WorkspaceStateStore } from './workspace-document-restore';
|
|
32
|
+
|
|
33
|
+
export interface DocumentOpener<Request> {
|
|
34
|
+
/** The opener id — the address vocabulary, not a module name. */
|
|
35
|
+
readonly id: string;
|
|
36
|
+
/** Which module registered it. Re-registering the same owner+id REPLACES,
|
|
37
|
+
* so an HMR re-evaluation leaves one opener, not two. */
|
|
38
|
+
readonly owner: string;
|
|
39
|
+
/**
|
|
40
|
+
* Open (or activate) the document this request addresses, and answer its
|
|
41
|
+
* document id. `null` = this opener cannot serve THIS request (an
|
|
42
|
+
* undeclared medium, a story that is no longer exported); the next
|
|
43
|
+
* registered opener is tried.
|
|
44
|
+
*
|
|
45
|
+
* THROWING is the third answer, and it is different from `null`: "this
|
|
46
|
+
* address is MINE and it is broken" — a table that lists no such entry, a
|
|
47
|
+
* contribution whose module threw on import. The throw reaches the caller
|
|
48
|
+
* with the kind's own sentence instead of the host's generic "nothing can
|
|
49
|
+
* open this", which is the only way a reader learns which of the two
|
|
50
|
+
* happened. Only an opener that OWNS the id may throw; one of several
|
|
51
|
+
* openers sharing an id answers `null` so its siblings still get their turn.
|
|
52
|
+
*/
|
|
53
|
+
readonly open: (store: WorkspaceStateStore, request: Request) => string | null;
|
|
54
|
+
/**
|
|
55
|
+
* The kind's own async settling step, awaited by
|
|
56
|
+
* {@link openRegisteredDocumentAsync} ONLY after a first synchronous attempt
|
|
57
|
+
* answered `null` — refresh the ledger this kind opens documents out of, then
|
|
58
|
+
* the attempt is made once more.
|
|
59
|
+
*
|
|
60
|
+
* It mirrors `WorkspaceDocumentRestorer.prepare` deliberately: a kind is the
|
|
61
|
+
* only thing that knows what "I might be able to open this once I have looked
|
|
62
|
+
* again" means, and the host must not hold that knowledge to address a
|
|
63
|
+
* document. Absent means one attempt is the whole answer.
|
|
64
|
+
*
|
|
65
|
+
* IT RECEIVES THE REQUEST, because settling is per-address: waiting for THIS
|
|
66
|
+
* table entry, loading THIS module, refreshing the contribution that would
|
|
67
|
+
* carry THIS id. `stories/story-opener.ts:92` is the evidence —
|
|
68
|
+
* it keeps two module-level `unsettled*` sets whose only job is to carry the
|
|
69
|
+
* failed request across to a settle that could not see it. (Existing openers
|
|
70
|
+
* that ignore the argument are unaffected; the dedupe below is by function
|
|
71
|
+
* identity, so one settle still runs once per attempt.) Like `open`, it may
|
|
72
|
+
* THROW to refuse the address with the kind's own sentence.
|
|
73
|
+
*/
|
|
74
|
+
readonly settle?: (request: Request) => Promise<void>;
|
|
75
|
+
/**
|
|
76
|
+
* The kind's own POST-open readiness — `settle`'s mirror on the other side of
|
|
77
|
+
* the answer, awaited by {@link openRegisteredDocumentAsync} once an opener
|
|
78
|
+
* has produced a document id, before the caller is told the view is present.
|
|
79
|
+
*
|
|
80
|
+
* It exists because "opened" and "ready to be driven" are different instants
|
|
81
|
+
* for some kinds and the host cannot know which: an asset document answers
|
|
82
|
+
* its id the moment the tab is registered, while an immediate
|
|
83
|
+
* inspect/setField against it needs the Inspector mounted and (for a model)
|
|
84
|
+
* its live adapter installed — `waitForAssetDocumentInspector`, which the
|
|
85
|
+
* presenter used to await by hand because it knew the asset family's rule.
|
|
86
|
+
* Absent means the id IS the whole answer. May THROW to refuse.
|
|
87
|
+
*
|
|
88
|
+
* A synchronous caller ({@link openRegisteredDocument}) cannot await it, the
|
|
89
|
+
* same way it cannot settle — it gets the id and the kind's own doors are
|
|
90
|
+
* what it waits on.
|
|
91
|
+
*/
|
|
92
|
+
readonly ready?: (documentId: string, request: Request) => Promise<void>;
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
// The registry is heterogeneous by construction — one id, one request type,
|
|
96
|
+
// checked at both ends by the shared declaration the id comes from.
|
|
97
|
+
// biome-ignore lint/suspicious/noExplicitAny: the map is keyed by id, not by type.
|
|
98
|
+
const _openers = new Map<string, DocumentOpener<any>[]>();
|
|
99
|
+
|
|
100
|
+
/** Install an opener. Returns the teardown. */
|
|
101
|
+
export function registerDocumentOpener<Request>(opener: DocumentOpener<Request>): () => void {
|
|
102
|
+
const existing = _openers.get(opener.id) ?? [];
|
|
103
|
+
const next = existing.filter((item) => item.owner !== opener.owner);
|
|
104
|
+
next.push(opener);
|
|
105
|
+
_openers.set(opener.id, next);
|
|
106
|
+
return () => {
|
|
107
|
+
const current = _openers.get(opener.id);
|
|
108
|
+
if (!current) return;
|
|
109
|
+
const remaining = current.filter((item) => item !== opener);
|
|
110
|
+
if (remaining.length === 0) _openers.delete(opener.id);
|
|
111
|
+
else _openers.set(opener.id, remaining);
|
|
112
|
+
};
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
/** Whether anything can open this id in THIS session — what a palette asks
|
|
116
|
+
* before offering an action that would otherwise do nothing. */
|
|
117
|
+
export function hasDocumentOpener(id: string): boolean {
|
|
118
|
+
return (_openers.get(id)?.length ?? 0) > 0;
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
/**
|
|
122
|
+
* Every address this session can open, sorted. The generic answer to "what
|
|
123
|
+
* DOES this editor open?", which is what a refusal owes its reader: a build
|
|
124
|
+
* whose package list carries no opener for the kind is a configuration fact,
|
|
125
|
+
* and naming the addresses that ARE registered is the difference between
|
|
126
|
+
* "this is broken" and "this editor is not that editor".
|
|
127
|
+
*/
|
|
128
|
+
export function registeredDocumentOpenerIds(): readonly string[] {
|
|
129
|
+
return [..._openers.keys()].sort();
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
/**
|
|
133
|
+
* Open the document this request addresses, through whichever registered
|
|
134
|
+
* opener claims it. `null` = nothing here can open it, which is the same
|
|
135
|
+
* answer the host already gives for a story with no declared medium.
|
|
136
|
+
*/
|
|
137
|
+
export function openRegisteredDocument<Request>(
|
|
138
|
+
id: string,
|
|
139
|
+
store: WorkspaceStateStore,
|
|
140
|
+
request: Request,
|
|
141
|
+
): string | null {
|
|
142
|
+
for (const opener of _openers.get(id) ?? []) {
|
|
143
|
+
const opened = opener.open(store, request);
|
|
144
|
+
if (opened !== null) return opened;
|
|
145
|
+
}
|
|
146
|
+
return null;
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
/**
|
|
150
|
+
* The same question, asked where the caller can wait: try the registered
|
|
151
|
+
* openers once; if none claimed the request, let each kind SETTLE (refresh the
|
|
152
|
+
* ledger it opens out of) and try once more. Used by the VIEW PROTOCOL, which
|
|
153
|
+
* is already async and is the one caller that addresses a document by a name a
|
|
154
|
+
* person or an agent typed — the subject may simply not have been fetched yet.
|
|
155
|
+
*/
|
|
156
|
+
export async function openRegisteredDocumentAsync<Request>(
|
|
157
|
+
id: string,
|
|
158
|
+
store: WorkspaceStateStore,
|
|
159
|
+
request: Request,
|
|
160
|
+
): Promise<string | null> {
|
|
161
|
+
const openers = _openers.get(id) ?? [];
|
|
162
|
+
const direct = claim(openers, store, request);
|
|
163
|
+
if (direct) return settleReady(direct, request);
|
|
164
|
+
if (openers.length === 0) return null;
|
|
165
|
+
const settled = new Set<(request: Request) => Promise<void>>();
|
|
166
|
+
for (const opener of openers) if (opener.settle) settled.add(opener.settle);
|
|
167
|
+
for (const settle of settled) await settle(request);
|
|
168
|
+
if (settled.size === 0) return null;
|
|
169
|
+
const retried = claim(openers, store, request);
|
|
170
|
+
return retried === null ? null : settleReady(retried, request);
|
|
171
|
+
}
|
|
172
|
+
|
|
173
|
+
/** The first opener that answers a document id, and WHICH one — the async door
|
|
174
|
+
* needs the identity because `ready` belongs to the opener that claimed, not
|
|
175
|
+
* to every opener sharing the address. */
|
|
176
|
+
function claim<Request>(
|
|
177
|
+
// biome-ignore lint/suspicious/noExplicitAny: the map is keyed by id, not by type.
|
|
178
|
+
openers: readonly DocumentOpener<any>[],
|
|
179
|
+
store: WorkspaceStateStore,
|
|
180
|
+
request: Request,
|
|
181
|
+
): { opener: DocumentOpener<Request>; documentId: string } | null {
|
|
182
|
+
for (const opener of openers) {
|
|
183
|
+
const documentId = opener.open(store, request);
|
|
184
|
+
if (documentId !== null) return { opener, documentId };
|
|
185
|
+
}
|
|
186
|
+
return null;
|
|
187
|
+
}
|
|
188
|
+
|
|
189
|
+
async function settleReady<Request>(
|
|
190
|
+
claimed: { opener: DocumentOpener<Request>; documentId: string },
|
|
191
|
+
request: Request,
|
|
192
|
+
): Promise<string> {
|
|
193
|
+
await claimed.opener.ready?.(claimed.documentId, request);
|
|
194
|
+
return claimed.documentId;
|
|
195
|
+
}
|
|
196
|
+
|
|
197
|
+
/** Test-only reset (mirrors the restore registry's own). */
|
|
198
|
+
export function __resetDocumentOpenersForTest(): void {
|
|
199
|
+
_openers.clear();
|
|
200
|
+
}
|