@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,1408 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* THE EDITOR'S ENTRY POINT UNDER THE CODE-OSS FRAME — the vgai editor's own app
|
|
3
|
+
* with a VS Code-backed LAYOUT HOST.
|
|
4
|
+
*
|
|
5
|
+
* THIS IS THE EDITOR'S MODULE, IN THE EDITOR'S TREE — forty of its imports are
|
|
6
|
+
* this package's and none is the workbench's, so it is an editor module that
|
|
7
|
+
* happens to mount inside a workbench. The Code-OSS contribution imports
|
|
8
|
+
* whatever `/__editor/served-modules` hands back, and what the session serves
|
|
9
|
+
* is this file (`packages/editor/server/routes/served-modules.ts`).
|
|
10
|
+
*
|
|
11
|
+
* Everything below is the real editor: AppRoot → EditorProvider →
|
|
12
|
+
* DefaultEditorLayout → ProjectLayout → the project's ModelLayout, unchanged. The
|
|
13
|
+
* one thing swapped is `@volter/editor-sdk/layouts`' LayoutHost: the adapter's
|
|
14
|
+
* `<EditorHeader/>`, `<Workspace/>` and `<EditorFooter/>` render through THIS host,
|
|
15
|
+
* which portals ProjectHeader and the active document surface + hierarchy + inspector
|
|
16
|
+
* into the VS Code parts the contribution hands over (title bar, editor pane, two
|
|
17
|
+
* sidebar views). The FOOTER portals nothing: the status bar is the workbench's own
|
|
18
|
+
* and every vgai status item is a real entry in it (see `Footer` below).
|
|
19
|
+
*
|
|
20
|
+
* IT IS THE KIT'S MOUNT, AND IT IS NOT THE SERVED MODULE. A PRODUCT is what the
|
|
21
|
+
* session serves (`packages/game-editor/src/index.ts`,
|
|
22
|
+
* `packages/model-editor/src/index.ts`): it composes its packages, its look and
|
|
23
|
+
* its workspace in code and re-exports this function as `mountVgai`, which is
|
|
24
|
+
* the name the fork's contribution reads off whatever module
|
|
25
|
+
* `/__editor/served-modules` hands it. So this file is product-neutral — it
|
|
26
|
+
* names no package and no product (ARCHITECTURE-CORE §The target shape, rule 1)
|
|
27
|
+
* — and `frame/product.ts` is the door a product calls.
|
|
28
|
+
*
|
|
29
|
+
* The runbook is docs/CODE-OSS.md; the `mountEditor` return value is the frame's
|
|
30
|
+
* half of every host door, and each handle's own comment names the contribution
|
|
31
|
+
* that consumes it.
|
|
32
|
+
*/
|
|
33
|
+
import '../editor-styles.css';
|
|
34
|
+
import '../authoring/instance-source-menu-register';
|
|
35
|
+
import { activeProduct } from '../active-product';
|
|
36
|
+
import '../authoring/prefab-instance-inspector-section';
|
|
37
|
+
import '../authoring/null-inspection-subjects';
|
|
38
|
+
import { editorHost } from '@volter/editor-sdk/host';
|
|
39
|
+
import {
|
|
40
|
+
type LayoutFrameProps,
|
|
41
|
+
registerLayoutHost,
|
|
42
|
+
type WorkspaceProps,
|
|
43
|
+
} from '@volter/editor-sdk/layouts';
|
|
44
|
+
import { invokeViewVerb, subscribeViewVerbs, viewVerbContributions } from '@volter/editor-sdk/views';
|
|
45
|
+
import {
|
|
46
|
+
Fragment,
|
|
47
|
+
type ReactNode,
|
|
48
|
+
useEffect,
|
|
49
|
+
useLayoutEffect,
|
|
50
|
+
useRef,
|
|
51
|
+
useState,
|
|
52
|
+
useSyncExternalStore,
|
|
53
|
+
} from 'react';
|
|
54
|
+
import { createPortal } from 'react-dom';
|
|
55
|
+
import { createRoot } from 'react-dom/client';
|
|
56
|
+
import { subscribeAdapterEditorConfiguration } from '../adapter-editor-config';
|
|
57
|
+
import { AppRoot } from '../components/AppRoot';
|
|
58
|
+
import { CompactInspectorCard } from '../components/CompactInspectorCard';
|
|
59
|
+
import { GameHierarchy } from '../components/GameHierarchy';
|
|
60
|
+
import { Inspector } from '../components/Inspector';
|
|
61
|
+
import { ProjectHeader } from '../components/ProjectHeader';
|
|
62
|
+
import { DocumentView } from '../components/ProjectLayout';
|
|
63
|
+
import { WorkspaceDocumentSurface } from '../components/WorkspaceDocumentSurface';
|
|
64
|
+
import { WorkspaceUtilitySurface } from '../components/WorkspaceUtilitySurface';
|
|
65
|
+
import { WorkspaceStaticPanelSurface } from '../components/workspace-static-panel-registry';
|
|
66
|
+
import { installEditorConsoleReporting } from '../console-sync';
|
|
67
|
+
import { installSessionVitals } from '../coverage/session-vitals';
|
|
68
|
+
import {
|
|
69
|
+
invokePaletteAction,
|
|
70
|
+
paletteActions,
|
|
71
|
+
setCommandExecutor,
|
|
72
|
+
setPaletteOpener,
|
|
73
|
+
subscribePaletteActions,
|
|
74
|
+
} from '../editor-commands';
|
|
75
|
+
import { editorConsole } from '../editor-console';
|
|
76
|
+
import { installEditorHostDoor, setOutputProvider } from '../editor-host-door';
|
|
77
|
+
import { getProjectDefinePath } from '../editor-mode';
|
|
78
|
+
import { type EditorNotification, setNotificationDelegate } from '../editor-notifications';
|
|
79
|
+
import { useEditorStore } from '../editor-runtime';
|
|
80
|
+
import { clearHierarchyHeaderSlot, setHierarchyHeaderSlot } from '../hierarchy-header-slot';
|
|
81
|
+
import { useActiveInspection } from '../inspection/use-active-inspection';
|
|
82
|
+
import { installLayoutPolicy } from '../layout-policy';
|
|
83
|
+
import {
|
|
84
|
+
installPlayTransitionDock,
|
|
85
|
+
reconcilePlayPresentationPolicy,
|
|
86
|
+
usesImmersivePlayPresentation,
|
|
87
|
+
} from '../live-transition';
|
|
88
|
+
import { getCurrentProject } from '../project-manager';
|
|
89
|
+
import {
|
|
90
|
+
describeSessionOrphan,
|
|
91
|
+
sessionOrphanIsWorthReporting,
|
|
92
|
+
takeSessionOrphanRecord,
|
|
93
|
+
} from '../session-orphan-record';
|
|
94
|
+
import {
|
|
95
|
+
declaredAdapterSettingEntries,
|
|
96
|
+
effectiveSettings,
|
|
97
|
+
preloadSettings,
|
|
98
|
+
subscribeSettings,
|
|
99
|
+
} from '../settings-store';
|
|
100
|
+
import { useSharedViewRestore } from '../shared-view-restore';
|
|
101
|
+
import { installStaleChunkRecovery } from '../stale-chunk-recovery';
|
|
102
|
+
import { installStoryLane } from '../stories/story-lane';
|
|
103
|
+
import { notifySurfaceKeyboard, setSurfaceKeyboardProbe } from '../surface-keyboard';
|
|
104
|
+
import { preloadEditorThemeLibrary } from '../theme-library';
|
|
105
|
+
import {
|
|
106
|
+
editorPaletteSnapshot,
|
|
107
|
+
installEditorTheme,
|
|
108
|
+
subscribeEditorTheme,
|
|
109
|
+
} from '../theme-preference';
|
|
110
|
+
import { primeSourceWriteRuntime } from '../ui-source/tier-source-write-backend';
|
|
111
|
+
import { installViteErrorSurface } from '../vite-error-surface';
|
|
112
|
+
import { activeWorkspaceAreas, subscribeWorkspaceAreas } from '../workspace-areas';
|
|
113
|
+
import {
|
|
114
|
+
activateWorkspaceDocument,
|
|
115
|
+
activeWorkspaceDocument,
|
|
116
|
+
activeWorkspaceDocumentViewId,
|
|
117
|
+
closeWorkspaceDocument,
|
|
118
|
+
openWorkspaceDocuments,
|
|
119
|
+
setActiveWorkspaceDocumentView,
|
|
120
|
+
subscribeWorkspaceDocuments,
|
|
121
|
+
type WorkspaceDocumentDescriptor,
|
|
122
|
+
workspaceDocumentRegistryVersion,
|
|
123
|
+
} from '../workspace-document-registry';
|
|
124
|
+
import {
|
|
125
|
+
installWorkspaceHostCommands,
|
|
126
|
+
setActiveWorkspaceStaticPanel,
|
|
127
|
+
} from '../workspace-host-commands';
|
|
128
|
+
import { notifyEditorWorkspaceApplied, setEditorWorkspace } from '../workspace-presets';
|
|
129
|
+
import {
|
|
130
|
+
installWorkspaceStatePersistence,
|
|
131
|
+
waitForWorkspaceStateRestore,
|
|
132
|
+
} from '../workspace-state-persistence';
|
|
133
|
+
import { WORKSPACE_STATIC_PANELS } from '../workspace-static-panels';
|
|
134
|
+
import {
|
|
135
|
+
subscribeWorkspaceStatus,
|
|
136
|
+
workspaceStatusContributions,
|
|
137
|
+
workspaceStatusRegistryVersion,
|
|
138
|
+
} from '../workspace-status-registry';
|
|
139
|
+
import {
|
|
140
|
+
availableUtilityFingerprint,
|
|
141
|
+
availableWorkspaceUtilities,
|
|
142
|
+
subscribeWorkspaceUtilities,
|
|
143
|
+
} from '../workspace-utility-registry';
|
|
144
|
+
import { setWorkspaceViewportRect } from '../workspace-viewport-rect';
|
|
145
|
+
|
|
146
|
+
/**
|
|
147
|
+
* WHAT THE FRAME GETS OF THE KEYBOARD — the editor's own door
|
|
148
|
+
* (`@volter/editor-sdk/host`'s `keyboard`) reshaped into exactly the facts the
|
|
149
|
+
* contribution's context keys need, so no file under `src/vs/` imports an
|
|
150
|
+
* editor module. Its counterpart is `vgaiKeyboard.ts`'s `VgaiKeyboardBridge`.
|
|
151
|
+
*
|
|
152
|
+
* The CHORDS are deliberately not among them (U6b): they are package data
|
|
153
|
+
* known at build time, generated into `extensions/vgai-keymaps`'s
|
|
154
|
+
* `contributes.keybindings` by `scripts/workbench/generate-keymaps.mjs` from the same
|
|
155
|
+
* `keymap-presets.ts`/`*.keymap.ts` tables this door would have read. What is
|
|
156
|
+
* dynamic — WHICH keymap the project chose — is `activeKeymap()` below, and
|
|
157
|
+
* the frame publishes it as the `vgai.keymap` context key each generated set
|
|
158
|
+
* is gated on. The door's own `keymaps()`/`actions()` members stay the
|
|
159
|
+
* editor's published API; the frame reads neither.
|
|
160
|
+
*/
|
|
161
|
+
export interface VgaiKeyboardHandle {
|
|
162
|
+
activeKeymap(): string;
|
|
163
|
+
invoke(id: string): boolean;
|
|
164
|
+
subscribe(listener: () => void): () => void;
|
|
165
|
+
facts(): {
|
|
166
|
+
surface: string | null;
|
|
167
|
+
mode: string | null;
|
|
168
|
+
documentKind: string | null;
|
|
169
|
+
play: string;
|
|
170
|
+
};
|
|
171
|
+
report(level: 'warn' | 'error', message: string): void;
|
|
172
|
+
}
|
|
173
|
+
|
|
174
|
+
/**
|
|
175
|
+
* WHAT THE FRAME GETS OF THE OPEN DOCUMENTS — its counterpart is the
|
|
176
|
+
* contribution's own `VgaiDocumentsBridge`, declared there so that no file
|
|
177
|
+
* under `src/vs/` imports an editor module.
|
|
178
|
+
*
|
|
179
|
+
* ONE fact, because one command needs it: which file on disk the active
|
|
180
|
+
* document IS. `VGAI: Show Explorer and Open Model Source Beside` opens the
|
|
181
|
+
* active model's source beside the Model document, and before this it opened
|
|
182
|
+
* the literal string `src/models/cube.ts` — a path the models template stopped
|
|
183
|
+
* shipping when a model became a `.blend` plus the bpy that authored it
|
|
184
|
+
* (`src/models/cube.py`). The frame cannot know that path; the editor does,
|
|
185
|
+
* because a `model` document's id IS `model:<project-relative .blend>`
|
|
186
|
+
* (`@volter/editor-blender`'s `models.finder.ts`), and this door is where that stops
|
|
187
|
+
* being an id-parsing trick anyone else has to repeat.
|
|
188
|
+
*/
|
|
189
|
+
/**
|
|
190
|
+
* WHAT THE FRAME GETS OF THE EDITOR'S HISTORY — the editor's own door
|
|
191
|
+
* (`@volter/editor-sdk/host`'s `history`) reshaped into exactly what the
|
|
192
|
+
* contribution needs, so no file under `src/vs/` imports an editor module. Its
|
|
193
|
+
* counterpart is `vgaiHistory.ts`'s `VgaiHistoryBridge`.
|
|
194
|
+
*
|
|
195
|
+
* The elements carry PROJECT-RELATIVE paths and the frame resolves them
|
|
196
|
+
* against the open workspace folder — that is what puts a gizmo drag on
|
|
197
|
+
* `cube.ts`'s model and a keystroke in `cube.ts`'s text editor on ONE
|
|
198
|
+
* resource's stack.
|
|
199
|
+
*/
|
|
200
|
+
export interface VgaiHistoryHandle {
|
|
201
|
+
elements(): readonly VgaiHistoryElementHandle[];
|
|
202
|
+
onElement(listener: (element: VgaiHistoryElementHandle) => void): () => void;
|
|
203
|
+
focusedResource(): string | null;
|
|
204
|
+
focusedDocument(): { id: string; label: string } | null;
|
|
205
|
+
/** Hand the frame's OWN undo to the editor, so its Edit menu, palette and
|
|
206
|
+
* `vgai eval` reach the one stack instead of a cursor nobody drives. */
|
|
207
|
+
setDelegate(delegate: {
|
|
208
|
+
undo(): void;
|
|
209
|
+
redo(): void;
|
|
210
|
+
canUndo(): boolean;
|
|
211
|
+
canRedo(): boolean;
|
|
212
|
+
}): void;
|
|
213
|
+
report(level: 'warn' | 'error', message: string): void;
|
|
214
|
+
}
|
|
215
|
+
|
|
216
|
+
export interface VgaiHistoryElementHandle {
|
|
217
|
+
readonly id: string;
|
|
218
|
+
readonly label: string;
|
|
219
|
+
readonly resources: readonly string[];
|
|
220
|
+
readonly document: string | null;
|
|
221
|
+
undo(): Promise<boolean>;
|
|
222
|
+
redo(): Promise<boolean>;
|
|
223
|
+
}
|
|
224
|
+
|
|
225
|
+
/**
|
|
226
|
+
* WHAT THE FRAME GETS OF THE PROJECT'S FILES — the editor's own door
|
|
227
|
+
* (`@volter/editor-sdk/host`'s `files`) in the one direction the frame drives
|
|
228
|
+
* it: the frame INSTALLS a provider, and from then on every vgai read and
|
|
229
|
+
* write of the project's files is the workbench's own `IFileService` /
|
|
230
|
+
* `ITextFileService` call. Its counterpart is `vgaiFiles.ts`'s
|
|
231
|
+
* `VgaiFilesBridge`, declared there so that no file under `src/vs/` imports an
|
|
232
|
+
* editor module.
|
|
233
|
+
*
|
|
234
|
+
* It arrives LATER than the ownership does, and that is deliberate:
|
|
235
|
+
* `setFilesOwner('frame')` runs before the editor mounts, so nothing can be
|
|
236
|
+
* written behind the workbench's back, while the provider needs services a
|
|
237
|
+
* `ServicesAccessor` only yields inside the command's synchronous part. The
|
|
238
|
+
* door falls back to the session's transports in that window — a write there
|
|
239
|
+
* is a real write with nowhere else to go.
|
|
240
|
+
*/
|
|
241
|
+
export interface VgaiFilesHandle {
|
|
242
|
+
setProvider(provider: {
|
|
243
|
+
read(path: string): Promise<string>;
|
|
244
|
+
readBytes(path: string): Promise<Uint8Array>;
|
|
245
|
+
write(path: string, data: string | Uint8Array): Promise<void>;
|
|
246
|
+
exists(path: string): Promise<boolean>;
|
|
247
|
+
}): void;
|
|
248
|
+
report(level: 'warn' | 'error', message: string): void;
|
|
249
|
+
}
|
|
250
|
+
|
|
251
|
+
/**
|
|
252
|
+
* WHAT THE FRAME GETS OF THE SETTINGS — the editor's own door
|
|
253
|
+
* (`@volter/editor-sdk/host`'s `settings`) in the one direction the frame drives
|
|
254
|
+
* it, plus the ONE fact only the editor knows: what the open project's
|
|
255
|
+
* `vgai.adapter.ts` DECLARES. Its counterpart is `vgaiSettings.ts`'s
|
|
256
|
+
* `VgaiSettingsBridge`, declared there so that no file under `src/vs/` imports
|
|
257
|
+
* an editor module.
|
|
258
|
+
*
|
|
259
|
+
* The adapter's declaration is CODE — an imported `blenderStyle` object, not a
|
|
260
|
+
* file the host parses (ARCHITECTURE-CORE §Adapters and contributions are
|
|
261
|
+
* code) — so the frame cannot read it and must be handed it. It arrives as
|
|
262
|
+
* dotted `vgai.*` keys, the same spelling the configuration service takes, and
|
|
263
|
+
* the frame writes exactly those to its MEMORY target under the inspect gate.
|
|
264
|
+
*/
|
|
265
|
+
export interface VgaiSettingsHandle {
|
|
266
|
+
setProvider(provider: {
|
|
267
|
+
get(key: string): unknown;
|
|
268
|
+
inspect(key: string): {
|
|
269
|
+
default: unknown;
|
|
270
|
+
user: unknown;
|
|
271
|
+
adapter: unknown;
|
|
272
|
+
project: unknown;
|
|
273
|
+
effective: unknown;
|
|
274
|
+
};
|
|
275
|
+
set(key: string, value: unknown, target: 'user' | 'project'): void;
|
|
276
|
+
subscribe(listener: () => void): () => void;
|
|
277
|
+
}): void;
|
|
278
|
+
adapterValues(): readonly (readonly [string, unknown])[];
|
|
279
|
+
/** VS CODE'S OWN keys the active LOOK answers, and today that is exactly one: the top
|
|
280
|
+
* bar's height (`window.titleBarHeight`, WORK.md U9). The frame writes it on the same
|
|
281
|
+
* MEMORY layer under the same inspect gate, and its own core edit 1 reads it in
|
|
282
|
+
* `BrowserTitlebarPart.minimumHeight`. See `vgaiTitleBar.ts` for why that edit exists and
|
|
283
|
+
* for the four routes measured before it was made. */
|
|
284
|
+
workbenchValues(): readonly (readonly [string, unknown])[];
|
|
285
|
+
/** The ACTIVE LOOK's own id — the editor's palette id. The frame maps it to the colour
|
|
286
|
+
* theme and product icon theme IT ships (`vgaiSettings.ts`'s `LOOK_THEMES`) and writes
|
|
287
|
+
* them on the same MEMORY layer, under the same inspect gate, as the top bar's height.
|
|
288
|
+
* The editor hands over the look and never a theme NAME: `Blender` and `blender-icons`
|
|
289
|
+
* are artifacts of the fork, and a panel naming one would be the inversion rule 2
|
|
290
|
+
* forbids. */
|
|
291
|
+
lookId(): string;
|
|
292
|
+
subscribe(listener: () => void): () => void;
|
|
293
|
+
report(level: 'warn' | 'error', message: string): void;
|
|
294
|
+
/** ONE event-shaped message to the PERSON, through `EditorHost.notify` — which under this
|
|
295
|
+
* frame is `INotificationService` (`vgaiNotifications.ts`). The frame uses it for the one
|
|
296
|
+
* thing the Settings editor cannot draw: a user value on an adapter-declared key, visible
|
|
297
|
+
* there and ineffective in this project. */
|
|
298
|
+
notify(notification: {
|
|
299
|
+
id: string;
|
|
300
|
+
tone: 'info' | 'warning' | 'error';
|
|
301
|
+
title: string;
|
|
302
|
+
detail?: string;
|
|
303
|
+
}): void;
|
|
304
|
+
}
|
|
305
|
+
|
|
306
|
+
/**
|
|
307
|
+
* WHAT THE FRAME GETS OF THE OPEN DOCUMENTS — its counterpart is
|
|
308
|
+
* `vgaiDocuments.ts`'s `VgaiDocumentsBridge`, declared there so that no file
|
|
309
|
+
* under `src/vs/` imports an editor module.
|
|
310
|
+
*
|
|
311
|
+
* `activeSource` answers ONE fact for `VGAI: Show Explorer and Open Model
|
|
312
|
+
* Source Beside`: which file on disk the active document IS.
|
|
313
|
+
*
|
|
314
|
+
* The other four are the open SET, and they arrived with walk 3's beat 19
|
|
315
|
+
* (2026-09-20). The frame used to have exactly one editor whatever this
|
|
316
|
+
* registry held, so an open-but-not-active document — an ingest root's Game,
|
|
317
|
+
* which is where its pixels are — could not be reached by any workbench
|
|
318
|
+
* gesture. `list`/`activeId`/`subscribe` are the read, `activate` is the
|
|
319
|
+
* write, and the write is deliberately the registry's OWN activation rather
|
|
320
|
+
* than a second notion of "which document is in front": activating fires the
|
|
321
|
+
* descriptor's `onActivate`, which is what moves the store's viewport tab.
|
|
322
|
+
*/
|
|
323
|
+
export interface VgaiDocumentsHandle {
|
|
324
|
+
whenRestored(): Promise<void>;
|
|
325
|
+
/** The active document's kind and the project-relative file it is, or null
|
|
326
|
+
* when nothing is open or the active document is not a file on disk. */
|
|
327
|
+
activeSource(): { kind: string; path: string } | null;
|
|
328
|
+
/**
|
|
329
|
+
* Every OPEN workspace document, in the registry's own order.
|
|
330
|
+
*
|
|
331
|
+
* `area` arrived with WORK.md's Timeline item 1 (2026-09-20). A workspace
|
|
332
|
+
* AREA is an editor GROUP (orchestrator ruling, 2026-09-19), and the two
|
|
333
|
+
* halves of the fact live in two places on this side: the registry
|
|
334
|
+
* descriptor holds the area's ID (`WorkspaceDocumentDescriptor.area`,
|
|
335
|
+
* written only by the workspace that opened it) and the ACTIVE workspace's
|
|
336
|
+
* own `areas` entry holds its `place` and `ratio`
|
|
337
|
+
* (`WorkspaceAreaContribution`, the same list the dock sizes its group
|
|
338
|
+
* from). They are joined here so that nothing under `src/vs/` has to know
|
|
339
|
+
* either module.
|
|
340
|
+
*/
|
|
341
|
+
list(): readonly {
|
|
342
|
+
readonly id: string;
|
|
343
|
+
readonly title: string;
|
|
344
|
+
readonly area?: {
|
|
345
|
+
readonly id: string;
|
|
346
|
+
readonly place: 'left' | 'right' | 'above' | 'below';
|
|
347
|
+
readonly ratio: number;
|
|
348
|
+
};
|
|
349
|
+
}[];
|
|
350
|
+
/** The registry's active document id, or null. */
|
|
351
|
+
activeId(): string | null;
|
|
352
|
+
/** Fires when the open set, the titles or the active document change. */
|
|
353
|
+
subscribe(listener: () => void): () => void;
|
|
354
|
+
/** Activate one open document — the frame's half of a tab click. */
|
|
355
|
+
activate(id: string, viewId?: string): void;
|
|
356
|
+
/**
|
|
357
|
+
* CLOSE one open document — the frame's half of `View: Close Editor`.
|
|
358
|
+
*
|
|
359
|
+
* A person closing a vgai editor is closing the DOCUMENT; without this the
|
|
360
|
+
* registry kept reporting it open and active while the workbench had no
|
|
361
|
+
* editor for it, so `vgai status` disagreed with the screen and reopening it
|
|
362
|
+
* was a no-op against a registry that never noticed (walk 4, W12). The
|
|
363
|
+
* contribution calls this only for a close it did NOT make itself.
|
|
364
|
+
*/
|
|
365
|
+
close(id: string): void;
|
|
366
|
+
/** Native occurrence lifetime and attachment. A null element hides a view;
|
|
367
|
+
* only `closed` releases its content. */
|
|
368
|
+
setView(view: NativeDocumentView, closed: boolean): void;
|
|
369
|
+
}
|
|
370
|
+
|
|
371
|
+
export interface VscodeParts {
|
|
372
|
+
/** The element that carries the vgai theme variables: `.monaco-workbench`. */
|
|
373
|
+
chromeRoot: HTMLElement;
|
|
374
|
+
header: HTMLElement;
|
|
375
|
+
center: HTMLElement;
|
|
376
|
+
outliner?: HTMLElement | undefined;
|
|
377
|
+
properties?: HTMLElement | undefined;
|
|
378
|
+
content?: HTMLElement;
|
|
379
|
+
}
|
|
380
|
+
|
|
381
|
+
let parts: VscodeParts | null = null;
|
|
382
|
+
let partsVersion = 0;
|
|
383
|
+
const partsListeners = new Set<() => void>();
|
|
384
|
+
function subscribeParts(listener: () => void): () => void {
|
|
385
|
+
partsListeners.add(listener);
|
|
386
|
+
return () => partsListeners.delete(listener);
|
|
387
|
+
}
|
|
388
|
+
function partsSnapshot(): number {
|
|
389
|
+
return partsVersion;
|
|
390
|
+
}
|
|
391
|
+
|
|
392
|
+
/**
|
|
393
|
+
* RE-OFFER OR WITHDRAW ONE HANDED-OVER PART, after the mount.
|
|
394
|
+
*
|
|
395
|
+
* The mount's parts used to be captured once, which was true for exactly as
|
|
396
|
+
* long as the pane that owned the centre lived. `View: Close Editor` on the
|
|
397
|
+
* only vgai document disposes that pane AND its group, and the element this
|
|
398
|
+
* module portals into goes with it — measured 2026-09-20 (walk 4, W12): the
|
|
399
|
+
* workspace came back with the Timeline alone and reopening the document drew
|
|
400
|
+
* into a detached node. So the contribution withdraws a dead part (`null`) and
|
|
401
|
+
* offers the next pane's container under the same id, and the portal below
|
|
402
|
+
* re-targets on the re-render that arrival causes.
|
|
403
|
+
*/
|
|
404
|
+
export function offerVgaiPart(id: keyof VscodeParts, element: HTMLElement | null): void {
|
|
405
|
+
if (!parts) return;
|
|
406
|
+
if (element === null) {
|
|
407
|
+
// A WITHDRAWAL IS ONLY THE OWNER'S. Panes are built and disposed in any
|
|
408
|
+
// order (a group split builds the area's pane before the main one goes),
|
|
409
|
+
// so a late `clearInput` from a pane that no longer holds the part must
|
|
410
|
+
// not delete the part its successor already offered.
|
|
411
|
+
if (parts[id]?.isConnected) return;
|
|
412
|
+
} else if (parts[id] === element) {
|
|
413
|
+
return;
|
|
414
|
+
}
|
|
415
|
+
if (element === null && (id === 'outliner' || id === 'properties' || id === 'content')) {
|
|
416
|
+
const next = { ...parts };
|
|
417
|
+
delete next[id];
|
|
418
|
+
parts = next;
|
|
419
|
+
} else if (element !== null) {
|
|
420
|
+
parts = { ...parts, [id]: element };
|
|
421
|
+
}
|
|
422
|
+
if (element !== null) stampPart(id, element);
|
|
423
|
+
partsVersion += 1;
|
|
424
|
+
for (const listener of partsListeners) listener();
|
|
425
|
+
}
|
|
426
|
+
|
|
427
|
+
/**
|
|
428
|
+
* THE PART'S OWN NAME, ON THE PART — written at the moment of the handover,
|
|
429
|
+
* which is the only moment anything knows that THIS element is the Properties
|
|
430
|
+
* view's body and that one is the Outliner's.
|
|
431
|
+
*
|
|
432
|
+
* It is here because the product door onto editor chrome
|
|
433
|
+
* (`editor-document-probe.ts`, scopes `rail` and `outliner`) has to find a
|
|
434
|
+
* view's live root, and these views are VS Code panes holding React portals:
|
|
435
|
+
* there is no path down from the document's box to them, and no class name
|
|
436
|
+
* that means "the Properties view" rather than "a panel". Reading the id the
|
|
437
|
+
* workbench registered is the honest answer; a class guess is not. A disposed
|
|
438
|
+
* pane takes its stamped element out of the document with it, so a closed view
|
|
439
|
+
* answers "not open" instead of matching a stale node.
|
|
440
|
+
*
|
|
441
|
+
* Costs nothing to draw: a `data-` attribute on a container that already
|
|
442
|
+
* exists.
|
|
443
|
+
*/
|
|
444
|
+
function stampPart(id: keyof VscodeParts, element: HTMLElement): void {
|
|
445
|
+
element.dataset['vgaiPart'] = id;
|
|
446
|
+
}
|
|
447
|
+
|
|
448
|
+
/** Native occurrences survive pane detach/move; React keys follow their IDs. */
|
|
449
|
+
interface NativeDocumentView {
|
|
450
|
+
readonly id: string;
|
|
451
|
+
readonly documentId: string;
|
|
452
|
+
readonly element: HTMLElement | null;
|
|
453
|
+
}
|
|
454
|
+
const documentViews = new Map<string, NativeDocumentView>();
|
|
455
|
+
let documentSlotsVersion = 0;
|
|
456
|
+
const documentSlotListeners = new Set<() => void>();
|
|
457
|
+
function setDocumentView(view: NativeDocumentView, closed: boolean): void {
|
|
458
|
+
if (closed) {
|
|
459
|
+
if (!documentViews.delete(view.id)) return;
|
|
460
|
+
} else {
|
|
461
|
+
const previous = documentViews.get(view.id);
|
|
462
|
+
if (previous?.element === view.element && previous.documentId === view.documentId) return;
|
|
463
|
+
documentViews.set(view.id, { ...view });
|
|
464
|
+
}
|
|
465
|
+
documentSlotsVersion += 1;
|
|
466
|
+
for (const listener of [...documentSlotListeners]) listener();
|
|
467
|
+
}
|
|
468
|
+
function subscribeDocumentSlots(listener: () => void): () => void {
|
|
469
|
+
documentSlotListeners.add(listener);
|
|
470
|
+
return () => {
|
|
471
|
+
documentSlotListeners.delete(listener);
|
|
472
|
+
};
|
|
473
|
+
}
|
|
474
|
+
function documentSlotsSnapshot(): number {
|
|
475
|
+
return documentSlotsVersion;
|
|
476
|
+
}
|
|
477
|
+
|
|
478
|
+
/** The shell's frame styling, per part (EditorShellFrame minus the absolute box). */
|
|
479
|
+
function PartShell({
|
|
480
|
+
children,
|
|
481
|
+
row = false,
|
|
482
|
+
center = false,
|
|
483
|
+
}: {
|
|
484
|
+
children: ReactNode;
|
|
485
|
+
row?: boolean;
|
|
486
|
+
center?: boolean;
|
|
487
|
+
}) {
|
|
488
|
+
return (
|
|
489
|
+
<div
|
|
490
|
+
className="vgai-editor-shell vgai-part"
|
|
491
|
+
// Code-OSS cancels wheel events at the workbench root. Our panels use
|
|
492
|
+
// native overflow scrolling, so retain its default action inside this host.
|
|
493
|
+
onWheel={(event) => event.stopPropagation()}
|
|
494
|
+
data-editor-hotkey-scope="workspace"
|
|
495
|
+
data-editor-hotkey-fallback
|
|
496
|
+
style={{
|
|
497
|
+
display: 'flex',
|
|
498
|
+
flexDirection: row ? 'row' : 'column',
|
|
499
|
+
justifyContent: center ? 'center' : undefined,
|
|
500
|
+
width: '100%',
|
|
501
|
+
height: '100%',
|
|
502
|
+
minHeight: 0,
|
|
503
|
+
minWidth: 0,
|
|
504
|
+
position: 'relative',
|
|
505
|
+
// THE LOOK'S OWN FACE, and it is RESTATED here on purpose. `theme.css`
|
|
506
|
+
// declares it on the theme root and every ordinary surface inherits it
|
|
507
|
+
// — but under the frame the theme root IS `.monaco-workbench`, and the
|
|
508
|
+
// parts we portal into are the workbench's own elements, several of
|
|
509
|
+
// which declare a font of their own. Inheritance from the root loses to
|
|
510
|
+
// a declaration on the part.
|
|
511
|
+
// It read `var(--vgai-typography-sans, 'Inter', system-ui, sans-serif)`
|
|
512
|
+
// while it lived in the fork: that variable is published by nothing, so
|
|
513
|
+
// the frame wore the hard-coded fallback and never the look's face.
|
|
514
|
+
fontFamily: 'var(--vgai-font-sans)',
|
|
515
|
+
fontSize: 'var(--vgai-font-base)',
|
|
516
|
+
color: 'var(--vgai-content-primary)',
|
|
517
|
+
}}
|
|
518
|
+
>
|
|
519
|
+
{children}
|
|
520
|
+
</div>
|
|
521
|
+
);
|
|
522
|
+
}
|
|
523
|
+
|
|
524
|
+
function Frame({ children }: LayoutFrameProps) {
|
|
525
|
+
return <>{children}</>;
|
|
526
|
+
}
|
|
527
|
+
|
|
528
|
+
function Header() {
|
|
529
|
+
if (!parts) return null;
|
|
530
|
+
return createPortal(
|
|
531
|
+
<PartShell center>
|
|
532
|
+
<ProjectHeader />
|
|
533
|
+
</PartShell>,
|
|
534
|
+
parts.header,
|
|
535
|
+
);
|
|
536
|
+
}
|
|
537
|
+
|
|
538
|
+
/**
|
|
539
|
+
* THE FOOTER IS NOT HOSTED — the status bar is the WORKBENCH'S (U8 step 7).
|
|
540
|
+
*
|
|
541
|
+
* The spike portalled `EditorBottomBar` into `.part.statusbar` and the skin hid the bar's own
|
|
542
|
+
* `.items-container` to make room for it. U8 replaced that whole for-the-look arrangement with
|
|
543
|
+
* the real thing: one `IStatusbarService` entry per `workspace.status` contribution, each
|
|
544
|
+
* carrying our own element as its `content` (`vgaiStatus.ts`), and `StatusBar.tsx` drawing
|
|
545
|
+
* nothing under frame ownership. The portal that stayed behind was then an EMPTY 1440x22 blob
|
|
546
|
+
* covering every one of those entries — walk 2 measured them all at 0x0 with no `Hide <item>`
|
|
547
|
+
* reachable, which is exactly what a second rendering of one part costs.
|
|
548
|
+
*
|
|
549
|
+
* WHAT THIS DROPS, named rather than silently degraded: `EditorBottomBar` is the status line
|
|
550
|
+
* plus the `bottom-bar` CHROME SLOT, whose one filler is `@vgai/agents`' minimized conversation
|
|
551
|
+
* tray. That tray has no frame home yet — neither does the `panel:agent` slot beside it, because
|
|
552
|
+
* the agents surface is a dock PANEL and the dock is U10's to retire. It renders nothing in a
|
|
553
|
+
* scaffolded project today (measured: the hosted slot's `innerText` was empty), and the two
|
|
554
|
+
* halves of that surface move together when they move. docs/CODE-OSS.md §Views, colours, marks
|
|
555
|
+
* and status carries the note.
|
|
556
|
+
*/
|
|
557
|
+
function Footer() {
|
|
558
|
+
return null;
|
|
559
|
+
}
|
|
560
|
+
|
|
561
|
+
function OutlinerPart() {
|
|
562
|
+
const slot = useRef<HTMLDivElement>(null);
|
|
563
|
+
useEffect(() => {
|
|
564
|
+
const element = slot.current;
|
|
565
|
+
if (!element) return;
|
|
566
|
+
setHierarchyHeaderSlot(element);
|
|
567
|
+
return () => clearHierarchyHeaderSlot(element);
|
|
568
|
+
}, []);
|
|
569
|
+
return (
|
|
570
|
+
<div style={{ display: 'flex', flexDirection: 'column', height: '100%', minHeight: 0 }}>
|
|
571
|
+
<div ref={slot} className="vgai-vscode-outliner-header" />
|
|
572
|
+
<div style={{ flex: 1, minHeight: 0, display: 'flex', flexDirection: 'column' }}>
|
|
573
|
+
<GameHierarchy />
|
|
574
|
+
</div>
|
|
575
|
+
</div>
|
|
576
|
+
);
|
|
577
|
+
}
|
|
578
|
+
|
|
579
|
+
/**
|
|
580
|
+
* THE VIEW BODIES the frame has handed over, by utility id. A module-scope store with its own
|
|
581
|
+
* subscription for the reason `parts` is one: the workbench constructs a view pane when it
|
|
582
|
+
* pleases (the panel is collapsed until someone opens it), so the element arrives long after
|
|
583
|
+
* the bridge mounted and the React tree has to re-render when it does.
|
|
584
|
+
*/
|
|
585
|
+
const utilityBodies = new Map<string, HTMLElement>();
|
|
586
|
+
const utilityBodyListeners = new Set<() => void>();
|
|
587
|
+
let utilityBodyVersion = 0;
|
|
588
|
+
function setUtilityBody(id: string, element: HTMLElement | null): void {
|
|
589
|
+
if (element) {
|
|
590
|
+
if (utilityBodies.get(id) === element) return;
|
|
591
|
+
utilityBodies.set(id, element);
|
|
592
|
+
} else if (!utilityBodies.delete(id)) {
|
|
593
|
+
return;
|
|
594
|
+
}
|
|
595
|
+
utilityBodyVersion++;
|
|
596
|
+
for (const listener of utilityBodyListeners) listener();
|
|
597
|
+
}
|
|
598
|
+
|
|
599
|
+
const statusBodies = new Map<string, HTMLElement>();
|
|
600
|
+
const statusBodyListeners = new Set<() => void>();
|
|
601
|
+
let statusBodyVersion = 0;
|
|
602
|
+
function setStatusBody(id: string, element: HTMLElement | null): void {
|
|
603
|
+
if (element) {
|
|
604
|
+
if (statusBodies.get(id) === element) return;
|
|
605
|
+
statusBodies.set(id, element);
|
|
606
|
+
} else if (!statusBodies.delete(id)) {
|
|
607
|
+
return;
|
|
608
|
+
}
|
|
609
|
+
statusBodyVersion++;
|
|
610
|
+
for (const listener of statusBodyListeners) listener();
|
|
611
|
+
}
|
|
612
|
+
|
|
613
|
+
/** Our status items, each portalled into the real status bar ENTRY the frame made for it (U8).
|
|
614
|
+
* No `PartShell` here: a status entry is already the workbench's own chrome, and wrapping it in
|
|
615
|
+
* our shell frame would put a second border inside one item. */
|
|
616
|
+
function StatusPortals() {
|
|
617
|
+
useSyncExternalStore(
|
|
618
|
+
subscribeWorkspaceStatus,
|
|
619
|
+
workspaceStatusRegistryVersion,
|
|
620
|
+
workspaceStatusRegistryVersion,
|
|
621
|
+
);
|
|
622
|
+
useSyncExternalStore(
|
|
623
|
+
(listener: () => void) => {
|
|
624
|
+
statusBodyListeners.add(listener);
|
|
625
|
+
return () => statusBodyListeners.delete(listener);
|
|
626
|
+
},
|
|
627
|
+
() => statusBodyVersion,
|
|
628
|
+
() => statusBodyVersion,
|
|
629
|
+
);
|
|
630
|
+
return (
|
|
631
|
+
<>
|
|
632
|
+
{[...workspaceStatusContributions('left'), ...workspaceStatusContributions('right')].map(
|
|
633
|
+
(contribution) => {
|
|
634
|
+
const body = statusBodies.get(contribution.id);
|
|
635
|
+
if (!body) return null;
|
|
636
|
+
const Content = contribution.Content;
|
|
637
|
+
return <Fragment key={contribution.id}>{createPortal(<Content />, body)}</Fragment>;
|
|
638
|
+
},
|
|
639
|
+
)}
|
|
640
|
+
</>
|
|
641
|
+
);
|
|
642
|
+
}
|
|
643
|
+
|
|
644
|
+
/** Our utilities, each portalled into the VS Code view the frame made for it (U8). */
|
|
645
|
+
function UtilityPortals() {
|
|
646
|
+
useSyncExternalStore(
|
|
647
|
+
subscribeWorkspaceUtilities,
|
|
648
|
+
availableUtilityFingerprint,
|
|
649
|
+
availableUtilityFingerprint,
|
|
650
|
+
);
|
|
651
|
+
useSyncExternalStore(
|
|
652
|
+
(listener: () => void) => {
|
|
653
|
+
utilityBodyListeners.add(listener);
|
|
654
|
+
return () => utilityBodyListeners.delete(listener);
|
|
655
|
+
},
|
|
656
|
+
() => utilityBodyVersion,
|
|
657
|
+
() => utilityBodyVersion,
|
|
658
|
+
);
|
|
659
|
+
return (
|
|
660
|
+
<>
|
|
661
|
+
{availableWorkspaceUtilities().map((utility) => {
|
|
662
|
+
const body = utilityBodies.get(utility.id);
|
|
663
|
+
if (!body) return null;
|
|
664
|
+
return (
|
|
665
|
+
<Fragment key={utility.id}>
|
|
666
|
+
{createPortal(
|
|
667
|
+
<PartShell>
|
|
668
|
+
<WorkspaceUtilitySurface utility={utility} />
|
|
669
|
+
</PartShell>,
|
|
670
|
+
body,
|
|
671
|
+
)}
|
|
672
|
+
</Fragment>
|
|
673
|
+
);
|
|
674
|
+
})}
|
|
675
|
+
</>
|
|
676
|
+
);
|
|
677
|
+
}
|
|
678
|
+
|
|
679
|
+
/** Keep the React portal target for a document stable across native tab moves.
|
|
680
|
+
* Moving the host element preserves the mounted game's container and renderer. */
|
|
681
|
+
function NativeDocumentPortal({
|
|
682
|
+
descriptor,
|
|
683
|
+
viewId,
|
|
684
|
+
slot,
|
|
685
|
+
parking,
|
|
686
|
+
visible,
|
|
687
|
+
inspector,
|
|
688
|
+
}: {
|
|
689
|
+
descriptor: WorkspaceDocumentDescriptor;
|
|
690
|
+
viewId: string;
|
|
691
|
+
slot: HTMLElement | undefined;
|
|
692
|
+
parking: HTMLElement;
|
|
693
|
+
visible: boolean;
|
|
694
|
+
inspector: boolean;
|
|
695
|
+
}) {
|
|
696
|
+
const [host] = useState(() => document.createElement('div'));
|
|
697
|
+
useLayoutEffect(() => {
|
|
698
|
+
host.className = 'vgai-vscode-document-slot';
|
|
699
|
+
host.dataset['vgaiDocument'] = descriptor.id;
|
|
700
|
+
host.dataset['vgaiArea'] = descriptor.area ?? '';
|
|
701
|
+
host.style.cssText = `display:${visible ? 'flex' : 'none'};flex-direction:column;width:100%;height:100%;min-width:0;min-height:0;position:relative;`;
|
|
702
|
+
}, [host, descriptor.id, descriptor.area, visible]);
|
|
703
|
+
useLayoutEffect(() => {
|
|
704
|
+
(slot ?? parking).appendChild(host);
|
|
705
|
+
return () => host.remove();
|
|
706
|
+
}, [host, slot, parking]);
|
|
707
|
+
return createPortal(
|
|
708
|
+
<PartShell>
|
|
709
|
+
<WorkspaceDocumentSurface
|
|
710
|
+
descriptor={descriptor}
|
|
711
|
+
viewId={viewId}
|
|
712
|
+
active={visible}
|
|
713
|
+
chrome={!descriptor.area}
|
|
714
|
+
/>
|
|
715
|
+
{inspector && <CompactInspectorCard />}
|
|
716
|
+
</PartShell>,
|
|
717
|
+
host,
|
|
718
|
+
);
|
|
719
|
+
}
|
|
720
|
+
|
|
721
|
+
let inspectorColumn = true;
|
|
722
|
+
|
|
723
|
+
function Workspace({ arrangement, immersivePlay }: WorkspaceProps) {
|
|
724
|
+
const store = useEditorStore();
|
|
725
|
+
useSharedViewRestore(store);
|
|
726
|
+
const inspection = useActiveInspection(store);
|
|
727
|
+
useLayoutEffect(() => {
|
|
728
|
+
inspectorColumn = inspection.column;
|
|
729
|
+
}, [inspection.column]);
|
|
730
|
+
const centerPart =
|
|
731
|
+
documentViews.get(activeWorkspaceDocumentViewId() ?? '')?.element ?? parts?.center;
|
|
732
|
+
useLayoutEffect(() => {
|
|
733
|
+
if (!centerPart) return;
|
|
734
|
+
const update = () =>
|
|
735
|
+
setWorkspaceViewportRect({
|
|
736
|
+
x: 0,
|
|
737
|
+
y: 0,
|
|
738
|
+
width: centerPart.clientWidth,
|
|
739
|
+
height: centerPart.clientHeight,
|
|
740
|
+
});
|
|
741
|
+
const observer = new ResizeObserver(update);
|
|
742
|
+
observer.observe(centerPart);
|
|
743
|
+
update();
|
|
744
|
+
return () => {
|
|
745
|
+
observer.disconnect();
|
|
746
|
+
setWorkspaceViewportRect(null);
|
|
747
|
+
};
|
|
748
|
+
}, [centerPart]);
|
|
749
|
+
useSyncExternalStore(store.subscribe, store.getShellSnapshot ?? store.getSnapshot);
|
|
750
|
+
useSyncExternalStore(
|
|
751
|
+
subscribeWorkspaceDocuments,
|
|
752
|
+
workspaceDocumentRegistryVersion,
|
|
753
|
+
workspaceDocumentRegistryVersion,
|
|
754
|
+
);
|
|
755
|
+
// THE FRAME'S PER-DOCUMENT SLOTS (WORK.md's Timeline item 1): an area's pane is built after
|
|
756
|
+
// this component first rendered, so its arrival has to be a re-render.
|
|
757
|
+
useSyncExternalStore(subscribeDocumentSlots, documentSlotsSnapshot, documentSlotsSnapshot);
|
|
758
|
+
// …and so does a re-offered PART: the centre's pane is disposed with its group when a person
|
|
759
|
+
// closes the last vgai editor, and the next one hands over a different element (W12).
|
|
760
|
+
useSyncExternalStore(subscribeParts, partsSnapshot, partsSnapshot);
|
|
761
|
+
useLayoutEffect(() => {
|
|
762
|
+
const stop = installLayoutPolicy({
|
|
763
|
+
...(arrangement ? { arrangement } : {}),
|
|
764
|
+
...(immersivePlay === undefined ? {} : { immersivePlay }),
|
|
765
|
+
playUtilities: [],
|
|
766
|
+
});
|
|
767
|
+
if (arrangement) setEditorWorkspace(arrangement.id);
|
|
768
|
+
// THE ACK a scripted caller waits on (`editor.workspace(id)`): this commit
|
|
769
|
+
// IS the workspace being applied on our side, and the frame sizes its
|
|
770
|
+
// editor groups from the same registry change in the same beat. Without a
|
|
771
|
+
// caller here `whenEditorWorkspaceApplied()` never resolves and the verb
|
|
772
|
+
// hangs on a switch that already happened.
|
|
773
|
+
notifyEditorWorkspaceApplied();
|
|
774
|
+
return stop;
|
|
775
|
+
}, [arrangement, immersivePlay]);
|
|
776
|
+
// WHAT THE DOCK DOES ON EVERY PLAY EDGE, minus the dock (U2). `endPlayTransition` is what
|
|
777
|
+
// puts the chrome back, and it must run when play stops AND when a layout that is not
|
|
778
|
+
// immersive starts something — the dock calls this from the same place for the same reason.
|
|
779
|
+
// It is here rather than in the game handle because only a component sees the store's edges.
|
|
780
|
+
const playing = store.playState !== 'stopped';
|
|
781
|
+
const keepPanelsVisible = useSyncExternalStore(subscribeSettings, effectiveSettings).play
|
|
782
|
+
?.keepPanelsVisible;
|
|
783
|
+
useEffect(() => {
|
|
784
|
+
reconcilePlayPresentationPolicy(playing, usesImmersivePlayPresentation());
|
|
785
|
+
}, [playing, immersivePlay, keepPanelsVisible]);
|
|
786
|
+
// WORKSPACE-STATE PERSISTENCE: which named workspace this project was left
|
|
787
|
+
// in, which documents were open and which was in front. It is installed HERE
|
|
788
|
+
// because this component is the editor's one workspace — the same place the
|
|
789
|
+
// dock used to install it from, for the same reason: the restore must not
|
|
790
|
+
// run before a workspace exists to restore into, and the write-through must
|
|
791
|
+
// stop when it goes.
|
|
792
|
+
useEffect(() => installWorkspaceStatePersistence(store), [store]);
|
|
793
|
+
if (!parts) return null;
|
|
794
|
+
const parking = parts.center;
|
|
795
|
+
const docs = openWorkspaceDocuments();
|
|
796
|
+
const active = activeWorkspaceDocument() ?? docs[0] ?? null;
|
|
797
|
+
(globalThis as unknown as { __vgaiBridge?: unknown }).__vgaiBridge = {
|
|
798
|
+
documents: docs.map((d) => d.descriptor.id),
|
|
799
|
+
active: active?.descriptor.id ?? null,
|
|
800
|
+
workspace: arrangement?.id ?? null,
|
|
801
|
+
areas: docs.flatMap((d) =>
|
|
802
|
+
d.descriptor.area ? [{ id: d.descriptor.id, area: d.descriptor.area }] : [],
|
|
803
|
+
),
|
|
804
|
+
slots: [...documentViews.values()].map(({ id, documentId, element }) => ({
|
|
805
|
+
id,
|
|
806
|
+
documentId,
|
|
807
|
+
visible: !!element,
|
|
808
|
+
})),
|
|
809
|
+
};
|
|
810
|
+
return (
|
|
811
|
+
<>
|
|
812
|
+
{[...documentViews.values()].map((view) => {
|
|
813
|
+
const descriptor = docs.find((doc) => doc.descriptor.id === view.documentId)?.descriptor;
|
|
814
|
+
if (!descriptor) return null;
|
|
815
|
+
return (
|
|
816
|
+
<NativeDocumentPortal
|
|
817
|
+
key={view.id}
|
|
818
|
+
descriptor={descriptor}
|
|
819
|
+
viewId={view.id}
|
|
820
|
+
slot={view.element ?? undefined}
|
|
821
|
+
parking={parking}
|
|
822
|
+
visible={!!view.element}
|
|
823
|
+
inspector={inspection.card && descriptor.id === active?.descriptor.id}
|
|
824
|
+
/>
|
|
825
|
+
);
|
|
826
|
+
})}
|
|
827
|
+
{docs.length === 0 &&
|
|
828
|
+
createPortal(
|
|
829
|
+
<PartShell>
|
|
830
|
+
<div className="vgai-vscode-empty">No document open</div>
|
|
831
|
+
</PartShell>,
|
|
832
|
+
parts.center,
|
|
833
|
+
)}
|
|
834
|
+
{parts.outliner &&
|
|
835
|
+
createPortal(
|
|
836
|
+
<PartShell>
|
|
837
|
+
<OutlinerPart />
|
|
838
|
+
</PartShell>,
|
|
839
|
+
parts.outliner,
|
|
840
|
+
)}
|
|
841
|
+
{parts.properties &&
|
|
842
|
+
inspection.column &&
|
|
843
|
+
createPortal(
|
|
844
|
+
<PartShell>
|
|
845
|
+
<Inspector />
|
|
846
|
+
</PartShell>,
|
|
847
|
+
parts.properties,
|
|
848
|
+
)}
|
|
849
|
+
{parts.content &&
|
|
850
|
+
createPortal(
|
|
851
|
+
<PartShell>
|
|
852
|
+
<WorkspaceStaticPanelSurface kind="assets" />
|
|
853
|
+
</PartShell>,
|
|
854
|
+
parts.content,
|
|
855
|
+
)}
|
|
856
|
+
<UtilityPortals />
|
|
857
|
+
<StatusPortals />
|
|
858
|
+
</>
|
|
859
|
+
);
|
|
860
|
+
}
|
|
861
|
+
|
|
862
|
+
/**
|
|
863
|
+
* WHAT THE FRAME GETS OF OUR STATUS ITEMS (U8) — the editor's `workspace.status` registry, plus
|
|
864
|
+
* the element each real status bar entry hands back. Its counterpart is `vgaiStatus.ts`'s
|
|
865
|
+
* `VgaiStatusBridge`. The item's pixels never change: the same `Content` the bottom bar renders
|
|
866
|
+
* is portalled into the entry the workbench made for it.
|
|
867
|
+
*/
|
|
868
|
+
export interface VgaiStatusHandle {
|
|
869
|
+
list(): readonly {
|
|
870
|
+
readonly id: string;
|
|
871
|
+
readonly title: string;
|
|
872
|
+
readonly align: 'left' | 'right';
|
|
873
|
+
readonly order: number;
|
|
874
|
+
}[];
|
|
875
|
+
subscribe(listener: () => void): () => void;
|
|
876
|
+
offerBody(itemId: string, element: HTMLElement | null): void;
|
|
877
|
+
}
|
|
878
|
+
|
|
879
|
+
/**
|
|
880
|
+
* WHAT THE FRAME GETS OF OUR DRAWER UTILITIES (U8, ruling 1's other half) — the editor's live
|
|
881
|
+
* `workspace.utility` registry, plus the door the frame hands each VIEW's body back through.
|
|
882
|
+
* Its counterpart is `vgaiUtilityViews.ts`'s `VgaiUtilitiesBridge`.
|
|
883
|
+
*
|
|
884
|
+
* A utility's CONTENT never moves: `WorkspaceUtilitySurface` renders the same registration the
|
|
885
|
+
* dock renders, portalled into the view's body. What changes is only where the body is.
|
|
886
|
+
*/
|
|
887
|
+
export interface VgaiUtilitiesHandle {
|
|
888
|
+
list(): readonly { readonly id: string; readonly title: string; readonly order: number }[];
|
|
889
|
+
subscribe(listener: () => void): () => void;
|
|
890
|
+
offerBody(utilityId: string, element: HTMLElement | null): void;
|
|
891
|
+
}
|
|
892
|
+
|
|
893
|
+
/**
|
|
894
|
+
* WHAT THE FRAME GETS OF OUR VIEWS (U8, ruling 1) — the SDK's view-verb registry, reshaped
|
|
895
|
+
* into what a `vgai.<view>.<verb>` command needs. Its counterpart is `vgaiViews.ts`'s
|
|
896
|
+
* `VgaiViewsBridge`. Arguments pass straight through and a refusal is the view's own thrown
|
|
897
|
+
* sentence: what an argument means belongs to the view.
|
|
898
|
+
*/
|
|
899
|
+
export interface VgaiViewsHandle {
|
|
900
|
+
list(): readonly {
|
|
901
|
+
readonly view: string;
|
|
902
|
+
readonly title: string;
|
|
903
|
+
readonly verbs: readonly { readonly id: string; readonly title?: string }[];
|
|
904
|
+
}[];
|
|
905
|
+
invoke(view: string, verb: string, args?: Record<string, unknown>): unknown;
|
|
906
|
+
subscribe(listener: () => void): () => void;
|
|
907
|
+
}
|
|
908
|
+
|
|
909
|
+
/**
|
|
910
|
+
* WHAT THE FRAME GETS OF NOTIFICATIONS (U8) — one installer, because a notification is a
|
|
911
|
+
* one-way message and there is nothing for the frame to read back. `null` hands them back to
|
|
912
|
+
* the editor's own tray. Its counterpart is `vgaiNotifications.ts`'s
|
|
913
|
+
* `VgaiNotificationsBridge`.
|
|
914
|
+
*/
|
|
915
|
+
export interface VgaiNotificationsHandle {
|
|
916
|
+
setDelegate(show: ((notification: EditorNotification) => () => void) | null): void;
|
|
917
|
+
}
|
|
918
|
+
|
|
919
|
+
/**
|
|
920
|
+
* WHAT THE FRAME GETS OF THE PALETTE (U8) — the editor's live action table, reshaped into
|
|
921
|
+
* exactly the facts a `MenuId.CommandPalette` item needs, so no file under `src/vs/` imports an
|
|
922
|
+
* editor module. Its counterpart is `vgaiCommands.ts`'s `VgaiCommandsBridge`.
|
|
923
|
+
*
|
|
924
|
+
* Deliberately NOT here: the relay's verbs. `vgai <verb>` stays the SESSION's vocabulary (the
|
|
925
|
+
* one-name table gives commands to VS Code in the same row that keeps relay verbs ours); this
|
|
926
|
+
* is only the palette a PERSON opens.
|
|
927
|
+
*/
|
|
928
|
+
export interface VgaiCommandsHandle {
|
|
929
|
+
list(): readonly { readonly id: string; readonly label: string; readonly category: string }[];
|
|
930
|
+
invoke(id: string): boolean;
|
|
931
|
+
subscribe(listener: () => void): () => void;
|
|
932
|
+
setPaletteOpener(open: () => void): void;
|
|
933
|
+
/** The frame's `ICommandService`, behind `editor.command(id, args)` — the editor's one door
|
|
934
|
+
* to a command BY ID, and the only way the product can drive a drawer VIEW (U8 ruling 1).
|
|
935
|
+
* Standalone the same door answers a `vgai.<view>.<verb>` id off the views registry, so this
|
|
936
|
+
* is the second implementation of one table, never a second table. */
|
|
937
|
+
setCommandExecutor(run: ((id: string, args?: unknown) => Promise<unknown>) | null): void;
|
|
938
|
+
report(level: 'warn' | 'error', message: string): void;
|
|
939
|
+
}
|
|
940
|
+
|
|
941
|
+
/**
|
|
942
|
+
* WHAT THE FRAME ANSWERS FOR THE GAME SKEW (U2) — the three things the workspace
|
|
943
|
+
* host must install for a game layout, answered by the workbench.
|
|
944
|
+
*
|
|
945
|
+
* Everything else of the Game layout needed nothing: `GameLayout` is the same three
|
|
946
|
+
* layout-host members `ModelLayout` renders, the header carries the workspace tabs AND the
|
|
947
|
+
* Play transport, and the Game document is an ordinary workspace document the active-document
|
|
948
|
+
* portal already draws. Its counterpart is `vgaiGameSkew.ts`'s `VgaiGameBridge`.
|
|
949
|
+
*/
|
|
950
|
+
export interface VgaiGameHandle {
|
|
951
|
+
setActiveStaticPanel(kind: string | null): void;
|
|
952
|
+
focusCompactInspector(): boolean;
|
|
953
|
+
setPaneActive(active: boolean): void;
|
|
954
|
+
setImmersive(act: { enter(): void; exit(): void } | null): void;
|
|
955
|
+
setDockCommands(
|
|
956
|
+
commands: {
|
|
957
|
+
showUtility(id: string): void;
|
|
958
|
+
toggleUtility(id: string): void;
|
|
959
|
+
ensureUtility(id: string): void;
|
|
960
|
+
closeUtility(id: string): void;
|
|
961
|
+
showStaticPanel(kind: string): void;
|
|
962
|
+
setFocus(focused: boolean): void;
|
|
963
|
+
toggleFocus(): void;
|
|
964
|
+
} | null,
|
|
965
|
+
): void;
|
|
966
|
+
report(level: 'warn' | 'error', message: string): void;
|
|
967
|
+
}
|
|
968
|
+
|
|
969
|
+
export async function mountEditor(next: VscodeParts): Promise<{
|
|
970
|
+
host: HTMLElement;
|
|
971
|
+
keyboard: VgaiKeyboardHandle;
|
|
972
|
+
documents: VgaiDocumentsHandle;
|
|
973
|
+
history: VgaiHistoryHandle;
|
|
974
|
+
files: VgaiFilesHandle;
|
|
975
|
+
settings: VgaiSettingsHandle;
|
|
976
|
+
commands: VgaiCommandsHandle;
|
|
977
|
+
notifications: VgaiNotificationsHandle;
|
|
978
|
+
views: VgaiViewsHandle;
|
|
979
|
+
utilities: VgaiUtilitiesHandle;
|
|
980
|
+
output: { setProvider: typeof setOutputProvider };
|
|
981
|
+
status: VgaiStatusHandle;
|
|
982
|
+
game: VgaiGameHandle;
|
|
983
|
+
/** Re-offer or withdraw one handed-over part after the mount — see
|
|
984
|
+
* {@link offerVgaiPart}. */
|
|
985
|
+
offerPart(id: keyof VscodeParts, element: HTMLElement | null): void;
|
|
986
|
+
}> {
|
|
987
|
+
parts = next;
|
|
988
|
+
// The parts the mount was handed get the same stamp a re-offered one gets
|
|
989
|
+
// ({@link stampPart}) — one rule, both arrival paths.
|
|
990
|
+
for (const [id, element] of Object.entries(next)) {
|
|
991
|
+
if (element) stampPart(id as keyof VscodeParts, element);
|
|
992
|
+
}
|
|
993
|
+
// EVERY HOST DOOR'S FRAME HALF ARRIVES FROM THE CONTRIBUTION, which is the
|
|
994
|
+
// only side that has the services — and it arrives AFTER this, because a
|
|
995
|
+
// `ServicesAccessor` is valid only for the synchronous part of a command.
|
|
996
|
+
// Each door falls back to the editor's own answer in that window rather than
|
|
997
|
+
// refusing a real gesture; see the handles at the bottom of this file, and
|
|
998
|
+
// each door's own module for what the fallback costs.
|
|
999
|
+
// The theme scope is `#editor-chrome-root` and nothing else (index.html, the
|
|
1000
|
+
// appearance composer, the viewport's overlays) — so the workbench IS it.
|
|
1001
|
+
next.chromeRoot.id = 'editor-chrome-root';
|
|
1002
|
+
// THE ONE LAYOUT HOST. `DocumentView` is the editor's own document mount
|
|
1003
|
+
// (`components/ProjectLayout.tsx`); the other four are this file's, because
|
|
1004
|
+
// this file IS where the editor meets the workbench's parts.
|
|
1005
|
+
registerLayoutHost({ Frame, Header, Footer, Workspace, Document: DocumentView });
|
|
1006
|
+
// CAPTURE **AND** REPORT. This used to be `installEditorConsoleCapture()`
|
|
1007
|
+
// alone, copied out of the editor's `main.tsx` without the
|
|
1008
|
+
// `installConsoleSync()` line beside it — so this page's errors filled the
|
|
1009
|
+
// editor console and its bottom-bar counter and never reached the session
|
|
1010
|
+
// ledger `vgai console` reads. U6b's walk spent 44 React duplicate-key errors
|
|
1011
|
+
// inside that gap with a CLI calling the session clean. The editor now
|
|
1012
|
+
// publishes the two as one door that cannot be half-called.
|
|
1013
|
+
installEditorConsoleReporting();
|
|
1014
|
+
// SECOND: the editor starts watching its OWN vitals. Every live ontology
|
|
1015
|
+
// invariant (Edit is static, a scene has one root, the viewport canvas is
|
|
1016
|
+
// revealed, a visible tab renders, play draws) is checked on a timer and
|
|
1017
|
+
// reported as a session warning through the ledger the line above wired — so
|
|
1018
|
+
// a doctrine violation is loud on every `vgai` command instead of sitting in
|
|
1019
|
+
// a doc as a named, therefore licensed, "known problem".
|
|
1020
|
+
installSessionVitals();
|
|
1021
|
+
// THE NOTE THE LAST WINDOW AT THIS ADDRESS LEFT when it lost its server
|
|
1022
|
+
// (`session-orphan-record.ts`). Said right after the console pipe is wired,
|
|
1023
|
+
// because the server that would have recorded it is exactly the one that
|
|
1024
|
+
// died — this boot is the first moment the fact can reach `vgai console` and
|
|
1025
|
+
// the session journal at all. Taken, not peeked: one episode, said once.
|
|
1026
|
+
const orphaned = takeSessionOrphanRecord();
|
|
1027
|
+
if (orphaned && sessionOrphanIsWorthReporting(orphaned, Date.now())) {
|
|
1028
|
+
editorConsole.warn(describeSessionOrphan(orphaned, Date.now()), 'editor');
|
|
1029
|
+
}
|
|
1030
|
+
// A LAZY CHUNK THAT NO LONGER EXISTS reloads the page once, rather than
|
|
1031
|
+
// showing a crash whose Retry can never succeed.
|
|
1032
|
+
installStaleChunkRecovery();
|
|
1033
|
+
// The session turns Vite's full-screen error overlay OFF (a game that does
|
|
1034
|
+
// not compile must not brick the editor), so the `vite:error` payload is
|
|
1035
|
+
// routed to the editor's own error home instead. `import.meta.hot` exists
|
|
1036
|
+
// only while the session serves this module from source; a production build
|
|
1037
|
+
// has no HMR client and the failure arrives as an ordinary captured
|
|
1038
|
+
// `console.error` from Vite's own client.
|
|
1039
|
+
if (import.meta.hot) {
|
|
1040
|
+
installViteErrorSurface(
|
|
1041
|
+
import.meta.hot,
|
|
1042
|
+
() => getCurrentProject()?.rootPath ?? getProjectDefinePath(),
|
|
1043
|
+
);
|
|
1044
|
+
}
|
|
1045
|
+
primeSourceWriteRuntime();
|
|
1046
|
+
installEditorHostDoor();
|
|
1047
|
+
// PORTABLE CSF, the kit's own design-time state: the Content scope's
|
|
1048
|
+
// story-backed entries, a component's named states, the addresses a story
|
|
1049
|
+
// opens under, the palette's per-story action, `capture-story-variants` and
|
|
1050
|
+
// the discovery scan. The kit's own CSF needs no contribution to exist, so
|
|
1051
|
+
// the registrations are direct (`stories/story-lane.ts`).
|
|
1052
|
+
installStoryLane();
|
|
1053
|
+
await Promise.all([preloadSettings(), preloadEditorThemeLibrary()]);
|
|
1054
|
+
installEditorTheme(next.chromeRoot);
|
|
1055
|
+
next.chromeRoot.classList.toggle('vgai-native-menus', activeProduct()?.nativeMenus === true);
|
|
1056
|
+
// AppRoot's own overlays (startup screens, notifications, the palette) render
|
|
1057
|
+
// here, over the workbench, exactly as index.html's #editor-root does.
|
|
1058
|
+
const host = document.createElement('div');
|
|
1059
|
+
host.id = 'editor-root';
|
|
1060
|
+
host.className = 'vgai-part';
|
|
1061
|
+
host.style.cssText = 'position:absolute;inset:0;pointer-events:none;z-index:10;';
|
|
1062
|
+
next.chromeRoot.appendChild(host);
|
|
1063
|
+
createRoot(host).render(<AppRoot />);
|
|
1064
|
+
const keyboard: VgaiKeyboardHandle = {
|
|
1065
|
+
activeKeymap: () => editorHost().keyboard.activeKeymap(),
|
|
1066
|
+
invoke: (id) => editorHost().keyboard.invoke(id),
|
|
1067
|
+
subscribe: (listener) => editorHost().keyboard.subscribe(listener),
|
|
1068
|
+
facts: () => {
|
|
1069
|
+
const door = editorHost();
|
|
1070
|
+
const stage = door.keyboard.stage();
|
|
1071
|
+
return {
|
|
1072
|
+
surface: stage.surface,
|
|
1073
|
+
mode: stage.mode,
|
|
1074
|
+
documentKind: door.documents.active()?.kind ?? null,
|
|
1075
|
+
play: door.session.playState(),
|
|
1076
|
+
};
|
|
1077
|
+
},
|
|
1078
|
+
// EVERY FRAME-SIDE REFUSAL COMES THROUGH HERE — `vgaiFiles`' dirty-model
|
|
1079
|
+
// refusal, `vgaiHistory`' "Nothing to undo in …", `vgaiSettings`' unknown
|
|
1080
|
+
// key, the game skew's "undo history has no panel under the frame" — so
|
|
1081
|
+
// this one function IS the frame's whole refusal channel, and what it
|
|
1082
|
+
// calls decides whether a refusal exists for anyone but the person
|
|
1083
|
+
// watching the screen. Measured 2026-09-19, a write refused under this
|
|
1084
|
+
// frame produced `sessionWarnings: {count: 0}`, no toast, and a ledger
|
|
1085
|
+
// carrying only the history layer's generic `Source write rolled back:
|
|
1086
|
+
// Failed to apply "…" (apply-failed)` — a channel with no reader.
|
|
1087
|
+
//
|
|
1088
|
+
// IT CALLS THE HOST DOOR, and it keeps doing so now that this file is the
|
|
1089
|
+
// editor's own. `editor-console.ts` is a module-level ring buffer, and the
|
|
1090
|
+
// page that runs this bridge also runs the fork's contribution — a second
|
|
1091
|
+
// realm with its own module instances, which is exactly the bet the SDK's
|
|
1092
|
+
// host registry exists to retire ("two module instances, so plain module
|
|
1093
|
+
// state would be an empty registry on the contribution's side", measured
|
|
1094
|
+
// 2026-09-17 and answered with a `Symbol.for` key). `EditorHost.console`
|
|
1095
|
+
// is the published door for precisely this — *"a contribution's
|
|
1096
|
+
// diagnostics go here, never to `console.*`, so they reach every door
|
|
1097
|
+
// whether or not anyone looks at the tab"* — and it is what the editor's
|
|
1098
|
+
// boot fills. Nothing under the frame should reach past it into the
|
|
1099
|
+
// editor's internals to say something.
|
|
1100
|
+
//
|
|
1101
|
+
// THE LEDGER AND NOT THE TRAY, which is this file's own standing split
|
|
1102
|
+
// (`VgaiSettingsHandle.notify`: *"Not `report`: the console is the record
|
|
1103
|
+
// an agent reads back"*). A refusal reaches the person anyway — it rolls
|
|
1104
|
+
// the write back, and `workspace-utility-commands.ts` reveals the Console
|
|
1105
|
+
// with the rollback line, which now CARRIES the refusing sentence rather
|
|
1106
|
+
// than restating "failed to apply" (`history-service.ts`'s
|
|
1107
|
+
// `causeSentence`). A notification per refusal would also fire on every
|
|
1108
|
+
// Cmd+Z at the bottom of a stack, which VS Code itself is silent about.
|
|
1109
|
+
report: (level, message) => {
|
|
1110
|
+
const door = editorHost();
|
|
1111
|
+
if (level === 'error') door.console.error(message, 'editor');
|
|
1112
|
+
else door.console.warn(message, 'editor');
|
|
1113
|
+
},
|
|
1114
|
+
};
|
|
1115
|
+
const documents: VgaiDocumentsHandle = {
|
|
1116
|
+
whenRestored: waitForWorkspaceStateRestore,
|
|
1117
|
+
activeSource: () => {
|
|
1118
|
+
const active = editorHost().documents.active();
|
|
1119
|
+
if (!active) return null;
|
|
1120
|
+
// Only a kind whose id CARRIES its file answers with one. `model` is the
|
|
1121
|
+
// one that does today (`model:<project-relative .blend>`); any other kind
|
|
1122
|
+
// answers with its name and an empty path, which is what lets the
|
|
1123
|
+
// command's refusal say WHICH document was open instead of just "none".
|
|
1124
|
+
const path =
|
|
1125
|
+
active.kind === 'model' && active.id.startsWith('model:')
|
|
1126
|
+
? active.id.slice('model:'.length)
|
|
1127
|
+
: '';
|
|
1128
|
+
return { kind: active.kind, path };
|
|
1129
|
+
},
|
|
1130
|
+
// THE AREA IS JOINED FROM THE TWO PLACES THAT HOLD IT: the descriptor says WHICH area
|
|
1131
|
+
// this document fills (the workspace that opened it wrote the id), and the active
|
|
1132
|
+
// workspace's own `areas` entry says WHERE that area sits and how big it starts. An id
|
|
1133
|
+
// the active workspace no longer declares carries no area, which is the same answer
|
|
1134
|
+
// `workspace-areas.ts` gives a moment later when it closes the document.
|
|
1135
|
+
list: () =>
|
|
1136
|
+
openWorkspaceDocuments().map((open) => {
|
|
1137
|
+
const area = open.descriptor.area
|
|
1138
|
+
? activeWorkspaceAreas().find((candidate) => candidate.id === open.descriptor.area)
|
|
1139
|
+
: undefined;
|
|
1140
|
+
return {
|
|
1141
|
+
id: open.descriptor.id,
|
|
1142
|
+
title: open.title,
|
|
1143
|
+
...(area ? { area: { id: area.id, place: area.place, ratio: area.ratio } } : {}),
|
|
1144
|
+
};
|
|
1145
|
+
}),
|
|
1146
|
+
activeId: () => activeWorkspaceDocument()?.descriptor.id ?? null,
|
|
1147
|
+
subscribe: (listener) => {
|
|
1148
|
+
const registry = subscribeWorkspaceDocuments(listener);
|
|
1149
|
+
// The AREAS move on a workspace switch, and the registry is silent about that: the
|
|
1150
|
+
// documents it holds are the same objects, only the list that gives them a place and a
|
|
1151
|
+
// ratio has changed. The frame needs both edges.
|
|
1152
|
+
const areas = subscribeWorkspaceAreas(listener);
|
|
1153
|
+
return () => {
|
|
1154
|
+
registry();
|
|
1155
|
+
areas();
|
|
1156
|
+
};
|
|
1157
|
+
},
|
|
1158
|
+
activate: (id, viewId) => {
|
|
1159
|
+
if (viewId) setActiveWorkspaceDocumentView(id, viewId);
|
|
1160
|
+
else activateWorkspaceDocument(id);
|
|
1161
|
+
},
|
|
1162
|
+
// The registry's own close, which runs the descriptor's `onClose` and
|
|
1163
|
+
// activates whatever is left — the same door the dock's tab × used.
|
|
1164
|
+
//
|
|
1165
|
+
// IT CAN REFUSE, and the one reason it does is an unsaved draft: the
|
|
1166
|
+
// registry will not discard authored work on a close gesture. Our editor
|
|
1167
|
+
// input is Readonly, so the workbench asked nothing before closing it —
|
|
1168
|
+
// the next reconcile therefore re-opens the editor, and this says why
|
|
1169
|
+
// rather than letting the tab reappear on its own.
|
|
1170
|
+
close: (id) => {
|
|
1171
|
+
if (closeWorkspaceDocument(id)) return;
|
|
1172
|
+
const open = openWorkspaceDocuments().find((doc) => doc.descriptor.id === id);
|
|
1173
|
+
if (!open) return;
|
|
1174
|
+
keyboard.report(
|
|
1175
|
+
'warn',
|
|
1176
|
+
`“${open.title}” has unsaved changes, so it stayed open. Save it (⌘S) and close it again.`,
|
|
1177
|
+
);
|
|
1178
|
+
},
|
|
1179
|
+
setView: (view, closed) => setDocumentView(view, closed),
|
|
1180
|
+
};
|
|
1181
|
+
const history: VgaiHistoryHandle = {
|
|
1182
|
+
elements: () => editorHost().history.elements(),
|
|
1183
|
+
onElement: (listener) => editorHost().history.onElement(listener),
|
|
1184
|
+
focusedResource: () => editorHost().history.focusedResource(),
|
|
1185
|
+
// The document's TITLE is what a refusal should say ("Nothing to undo in
|
|
1186
|
+
// MainScene"), and the id is what scopes the stack; both come from the
|
|
1187
|
+
// door's own `documents.active()` rather than a second notion here.
|
|
1188
|
+
focusedDocument: () => {
|
|
1189
|
+
const active = editorHost().documents.active();
|
|
1190
|
+
return active ? { id: active.id, label: active.title } : null;
|
|
1191
|
+
},
|
|
1192
|
+
setDelegate: (delegate) => editorHost().history.setDelegate(delegate),
|
|
1193
|
+
report: keyboard.report,
|
|
1194
|
+
};
|
|
1195
|
+
const files: VgaiFilesHandle = {
|
|
1196
|
+
setProvider: (provider) => editorHost().files.setProvider(provider),
|
|
1197
|
+
report: keyboard.report,
|
|
1198
|
+
};
|
|
1199
|
+
const settings: VgaiSettingsHandle = {
|
|
1200
|
+
setProvider: (provider) => editorHost().settings.setProvider(provider),
|
|
1201
|
+
// The DECLARATION, not the layer in force: what the frame writes to its
|
|
1202
|
+
// MEMORY target. Reading the layer would be circular — the layer in force
|
|
1203
|
+
// is what the frame just wrote.
|
|
1204
|
+
adapterValues: () => [...declaredAdapterSettingEntries()],
|
|
1205
|
+
// The ADAPTER's own stream, not the settings store's: the store notifies for
|
|
1206
|
+
// every layer including the memory values the frame itself just wrote, and
|
|
1207
|
+
// waking the frame's apply pass with its own writes is the re-entrancy
|
|
1208
|
+
// `vgaiSettings.ts`'s header names. This fires when a project opens or its
|
|
1209
|
+
// adapter module loads or unloads, which is the only time the declaration
|
|
1210
|
+
// can move.
|
|
1211
|
+
// THE LOOK'S TOP BAR, resolved rather than declared (U9). `--vgai-command-bar-height` is
|
|
1212
|
+
// what `.vgai-project-header`'s own `height` reads, so the title bar becomes exactly the
|
|
1213
|
+
// band our stylesheet would have drawn: Classic's 36 (`theme.ts`'s `chromeSize.commandBar`),
|
|
1214
|
+
// Blender's 26 (`blender.style.ts`'s `chrome.commandBar`, traced at 1x). Reading the
|
|
1215
|
+
// COMPUTED property rather than the style declaration is deliberate — the value is set on
|
|
1216
|
+
// `#editor-chrome-root` by the theme installer, and a look that declares no chrome density
|
|
1217
|
+
// inherits the editor's own, which only the computed value shows.
|
|
1218
|
+
workbenchValues: () => {
|
|
1219
|
+
const root = parts?.chromeRoot;
|
|
1220
|
+
if (!root) return [];
|
|
1221
|
+
const raw = getComputedStyle(root).getPropertyValue('--vgai-command-bar-height').trim();
|
|
1222
|
+
const height = Number.parseFloat(raw);
|
|
1223
|
+
// A property that has not been painted yet reads '' and parses NaN. Hand back NOTHING
|
|
1224
|
+
// rather than a guess: the frame then clears the key and the title bar keeps its own
|
|
1225
|
+
// 30/35 until the theme lands, which is a correct top bar rather than a wrong one.
|
|
1226
|
+
if (!Number.isFinite(height) || height <= 0) return [];
|
|
1227
|
+
return [['window.titleBarHeight', Math.round(height)]];
|
|
1228
|
+
},
|
|
1229
|
+
// THE LOOK ITSELF, so the frame can choose its own colour theme for it. `theme-blender`
|
|
1230
|
+
// used to set `workbench.colorTheme` as a blanket `configurationDefaults`, which is why
|
|
1231
|
+
// Classic still carried Blender's `--vscode-vgai-*` colours (the walk's beat 6). The
|
|
1232
|
+
// palette id IS the look — `subscribe` below already watches the theme stream, so a
|
|
1233
|
+
// person switching style re-runs the frame's apply pass with no extra wiring.
|
|
1234
|
+
lookId: () => editorPaletteSnapshot(),
|
|
1235
|
+
// `EditorHost.notify`, which under this frame IS `INotificationService` — the frame's
|
|
1236
|
+
// settings layer uses it for the one fact the Settings editor cannot draw: a user value
|
|
1237
|
+
// on an adapter-declared key, shown there and ineffective in this project.
|
|
1238
|
+
notify: (notification) => {
|
|
1239
|
+
editorHost().notify(notification);
|
|
1240
|
+
},
|
|
1241
|
+
subscribe: (listener) => {
|
|
1242
|
+
// BOTH streams, because the two answers move independently: the adapter's declaration
|
|
1243
|
+
// changes when a project or its adapter module loads, and the resolved chrome changes
|
|
1244
|
+
// when a person switches palette/material inside one project.
|
|
1245
|
+
const stopAdapter = subscribeAdapterEditorConfiguration(listener);
|
|
1246
|
+
const stopTheme = subscribeEditorTheme(listener);
|
|
1247
|
+
return () => {
|
|
1248
|
+
stopAdapter();
|
|
1249
|
+
stopTheme();
|
|
1250
|
+
};
|
|
1251
|
+
},
|
|
1252
|
+
report: keyboard.report,
|
|
1253
|
+
};
|
|
1254
|
+
const commands: VgaiCommandsHandle = {
|
|
1255
|
+
list: () =>
|
|
1256
|
+
paletteActions().map((entry) => ({
|
|
1257
|
+
id: entry.id,
|
|
1258
|
+
label: entry.label,
|
|
1259
|
+
category: entry.category,
|
|
1260
|
+
})),
|
|
1261
|
+
invoke: (id) => invokePaletteAction(id),
|
|
1262
|
+
subscribe: (listener) => subscribePaletteActions(listener),
|
|
1263
|
+
setPaletteOpener: (open) => setPaletteOpener(open),
|
|
1264
|
+
setCommandExecutor: (run) => setCommandExecutor(run),
|
|
1265
|
+
report: keyboard.report,
|
|
1266
|
+
};
|
|
1267
|
+
const notifications: VgaiNotificationsHandle = {
|
|
1268
|
+
// The DELEGATE arrives from the contribution, which is the only side that
|
|
1269
|
+
// has `INotificationService` — later than the mount, because a
|
|
1270
|
+
// `ServicesAccessor` is valid only for a command's synchronous part.
|
|
1271
|
+
// Anything `notify()`-ed in that window is queued and shown on arrival
|
|
1272
|
+
// (`editor-notifications.ts`).
|
|
1273
|
+
setDelegate: (show) => setNotificationDelegate(show ? { show } : null),
|
|
1274
|
+
};
|
|
1275
|
+
const views: VgaiViewsHandle = {
|
|
1276
|
+
list: () =>
|
|
1277
|
+
viewVerbContributions().map((contribution) => ({
|
|
1278
|
+
view: contribution.view,
|
|
1279
|
+
title: contribution.title,
|
|
1280
|
+
verbs: contribution.verbs.map((verb) => ({
|
|
1281
|
+
id: verb.id,
|
|
1282
|
+
...(verb.title ? { title: verb.title } : {}),
|
|
1283
|
+
})),
|
|
1284
|
+
})),
|
|
1285
|
+
invoke: (view, verb, args) => invokeViewVerb(view, verb, args),
|
|
1286
|
+
subscribe: (listener) => subscribeViewVerbs(listener),
|
|
1287
|
+
};
|
|
1288
|
+
const utilities: VgaiUtilitiesHandle = {
|
|
1289
|
+
list: () =>
|
|
1290
|
+
availableWorkspaceUtilities().map((utility, index) => ({
|
|
1291
|
+
id: utility.id,
|
|
1292
|
+
title: utility.title,
|
|
1293
|
+
order: utility.order ?? index,
|
|
1294
|
+
})),
|
|
1295
|
+
subscribe: (listener) => subscribeWorkspaceUtilities(listener),
|
|
1296
|
+
offerBody: (id, element) => setUtilityBody(id, element),
|
|
1297
|
+
};
|
|
1298
|
+
// ---- THE GAME SKEW'S THREE FRAME ANSWERS (U2). See `vgaiGameSkew.ts` for why each exists.
|
|
1299
|
+
//
|
|
1300
|
+
// The pane's active state is held here rather than re-asked, because the probe is read on
|
|
1301
|
+
// EVERY gated DOM event (`gated-globals.ts`'s `gateFor`) and must not cross the bridge to
|
|
1302
|
+
// answer. `notifySurfaceKeyboard()` is the edge the engine's latched `InputManager` needs.
|
|
1303
|
+
let paneActive = true;
|
|
1304
|
+
let stopImmersive: (() => void) | null = null;
|
|
1305
|
+
let stopDockCommands: (() => void) | null = null;
|
|
1306
|
+
setSurfaceKeyboardProbe(() => paneActive);
|
|
1307
|
+
const game: VgaiGameHandle = {
|
|
1308
|
+
setActiveStaticPanel: (kind) =>
|
|
1309
|
+
setActiveWorkspaceStaticPanel(
|
|
1310
|
+
WORKSPACE_STATIC_PANELS.find((p) => p.kind === kind)?.kind ?? null,
|
|
1311
|
+
),
|
|
1312
|
+
focusCompactInspector: () => {
|
|
1313
|
+
if (inspectorColumn) return false;
|
|
1314
|
+
const card = parts?.center.querySelector<HTMLElement>(
|
|
1315
|
+
'[data-testid="compact-inspector-card"]',
|
|
1316
|
+
);
|
|
1317
|
+
if (!card) return false;
|
|
1318
|
+
card.tabIndex = -1;
|
|
1319
|
+
card.focus();
|
|
1320
|
+
setActiveWorkspaceStaticPanel('inspector');
|
|
1321
|
+
return true;
|
|
1322
|
+
},
|
|
1323
|
+
setPaneActive: (active) => {
|
|
1324
|
+
if (paneActive === active) return;
|
|
1325
|
+
paneActive = active;
|
|
1326
|
+
notifySurfaceKeyboard();
|
|
1327
|
+
},
|
|
1328
|
+
// IMMERSIVE PLAY RIDES THE EDITOR'S EXISTING SEAM. `live-transition.ts` owns the timing and
|
|
1329
|
+
// the camera flight and never touches a dock; what the dock registered here as a chrome
|
|
1330
|
+
// dissolve, the frame registers as a layout act. `root` is the element the transition's own
|
|
1331
|
+
// CSS classes land on, which under the frame is the workbench itself.
|
|
1332
|
+
setImmersive: (act) => {
|
|
1333
|
+
stopImmersive?.();
|
|
1334
|
+
stopImmersive = null;
|
|
1335
|
+
if (!act || !parts) return;
|
|
1336
|
+
stopImmersive = installPlayTransitionDock({
|
|
1337
|
+
root: parts.chromeRoot,
|
|
1338
|
+
hideChrome: () => act.enter(),
|
|
1339
|
+
showChrome: () => act.exit(),
|
|
1340
|
+
});
|
|
1341
|
+
},
|
|
1342
|
+
setDockCommands: (commands) => {
|
|
1343
|
+
stopDockCommands?.();
|
|
1344
|
+
stopDockCommands = null;
|
|
1345
|
+
if (!commands) return;
|
|
1346
|
+
stopDockCommands = installWorkspaceHostCommands({
|
|
1347
|
+
showUtility: (id) => commands.showUtility(id),
|
|
1348
|
+
toggleUtility: (id) => commands.toggleUtility(id),
|
|
1349
|
+
ensureUtility: (id) => commands.ensureUtility(id),
|
|
1350
|
+
closeUtility: (id) => commands.closeUtility(id),
|
|
1351
|
+
showStaticPanel: (kind) => commands.showStaticPanel(kind),
|
|
1352
|
+
setFocus: (focused) => commands.setFocus(focused),
|
|
1353
|
+
toggleFocus: () => commands.toggleFocus(),
|
|
1354
|
+
// `captureUtilities` is what a layout's `playUtilities` uses to show a set for the
|
|
1355
|
+
// duration of play and put the drawer back afterwards. The frame's version is the
|
|
1356
|
+
// views service: open each, and on release close exactly the ones this call opened.
|
|
1357
|
+
captureUtilities: (ids) => {
|
|
1358
|
+
for (const id of ids) commands.showUtility(id);
|
|
1359
|
+
return () => {
|
|
1360
|
+
for (const id of ids) commands.closeUtility(id);
|
|
1361
|
+
};
|
|
1362
|
+
},
|
|
1363
|
+
// UNDO HISTORY HAS NO FRAME HOME, and saying so is the honest answer: under the frame
|
|
1364
|
+
// the stack is VS Code's `IUndoRedoService` (U4), so a vgai "undo history" panel would
|
|
1365
|
+
// be a second, partial view of a stack the workbench already owns.
|
|
1366
|
+
showAuxiliary: () =>
|
|
1367
|
+
game.report(
|
|
1368
|
+
'warn',
|
|
1369
|
+
"Undo history has no panel under the VS Code frame: the stack is the workbench's own (U4), reached through Edit → Undo/Redo and the Timeline.",
|
|
1370
|
+
),
|
|
1371
|
+
});
|
|
1372
|
+
},
|
|
1373
|
+
report: (level, message) => keyboard.report(level, message),
|
|
1374
|
+
};
|
|
1375
|
+
const statusItems: VgaiStatusHandle = {
|
|
1376
|
+
list: () =>
|
|
1377
|
+
(['left', 'right'] as const).flatMap((align) =>
|
|
1378
|
+
workspaceStatusContributions(align).map((contribution, index) => ({
|
|
1379
|
+
id: contribution.id,
|
|
1380
|
+
// THE NAME A PERSON READS, not the id. `vgaiStatus.ts` passes it as
|
|
1381
|
+
// the entry's `name` and `ariaLabel`, which is what the status bar's
|
|
1382
|
+
// own right-click menu says — `Hide Console errors`, never
|
|
1383
|
+
// `Hide console-counts`.
|
|
1384
|
+
title: contribution.name,
|
|
1385
|
+
align,
|
|
1386
|
+
order: contribution.order ?? index,
|
|
1387
|
+
})),
|
|
1388
|
+
),
|
|
1389
|
+
subscribe: (listener) => subscribeWorkspaceStatus(listener),
|
|
1390
|
+
offerBody: (id, element) => setStatusBody(id, element),
|
|
1391
|
+
};
|
|
1392
|
+
return {
|
|
1393
|
+
host,
|
|
1394
|
+
keyboard,
|
|
1395
|
+
documents,
|
|
1396
|
+
history,
|
|
1397
|
+
files,
|
|
1398
|
+
commands,
|
|
1399
|
+
notifications,
|
|
1400
|
+
views,
|
|
1401
|
+
utilities,
|
|
1402
|
+
output: { setProvider: setOutputProvider },
|
|
1403
|
+
settings,
|
|
1404
|
+
status: statusItems,
|
|
1405
|
+
game,
|
|
1406
|
+
offerPart: offerVgaiPart,
|
|
1407
|
+
};
|
|
1408
|
+
}
|