@alpsckr/unitycli 0.4.3 → 0.4.5
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/README.md +5 -5
- package/contracts/command-contract.json +109 -217
- package/contracts/package-files.json +374 -294
- package/contracts/stable-session/direct-call-semantics.json +8 -2
- package/contracts/tool-completion-contract.json +148 -672
- package/dist/bridge/admission.d.ts +17 -1
- package/dist/bridge/admission.js +2 -0
- package/dist/bridge/admission.js.map +1 -1
- package/dist/bridge/domains/asset.js +3 -1
- package/dist/bridge/domains/asset.js.map +1 -1
- package/dist/bridge/domains/camera.js +39 -7
- package/dist/bridge/domains/camera.js.map +1 -1
- package/dist/bridge/domains/console.js +2 -1
- package/dist/bridge/domains/console.js.map +1 -1
- package/dist/bridge/domains/doctor.d.ts +3 -0
- package/dist/bridge/domains/doctor.js +8 -0
- package/dist/bridge/domains/doctor.js.map +1 -0
- package/dist/bridge/domains/editor.js +0 -4
- package/dist/bridge/domains/editor.js.map +1 -1
- package/dist/bridge/domains/game-object.js +4 -12
- package/dist/bridge/domains/game-object.js.map +1 -1
- package/dist/bridge/domains/graphics.js +1 -16
- package/dist/bridge/domains/graphics.js.map +1 -1
- package/dist/bridge/domains/object.js +3 -0
- package/dist/bridge/domains/object.js.map +1 -1
- package/dist/bridge/domains/physics.js +1 -2
- package/dist/bridge/domains/physics.js.map +1 -1
- package/dist/bridge/domains/profiler.js +18 -7
- package/dist/bridge/domains/profiler.js.map +1 -1
- package/dist/bridge/domains/project-tool.js +4 -0
- package/dist/bridge/domains/project-tool.js.map +1 -1
- package/dist/bridge/domains/reflection.js +10 -2
- package/dist/bridge/domains/reflection.js.map +1 -1
- package/dist/bridge/domains/runtime-tool.js +3 -0
- package/dist/bridge/domains/runtime-tool.js.map +1 -1
- package/dist/bridge/domains/scene.js +3 -8
- package/dist/bridge/domains/scene.js.map +1 -1
- package/dist/bridge/domains/screenshot.js +30 -6
- package/dist/bridge/domains/screenshot.js.map +1 -1
- package/dist/bridge/domains/ui.js +3 -1
- package/dist/bridge/domains/ui.js.map +1 -1
- package/dist/bridge/index.d.ts +5 -5
- package/dist/bridge/index.js +6 -9
- package/dist/bridge/index.js.map +1 -1
- package/dist/bridge/registry.js +3 -5
- package/dist/bridge/registry.js.map +1 -1
- package/dist/bridge/session-supervisor.d.ts +6 -3
- package/dist/bridge/session-supervisor.js +145 -39
- package/dist/bridge/session-supervisor.js.map +1 -1
- package/dist/bridge/start-diagnostics.d.ts +19 -0
- package/dist/bridge/start-diagnostics.js +96 -0
- package/dist/bridge/start-diagnostics.js.map +1 -0
- package/dist/bridge/types.d.ts +6 -5
- package/dist/bridge/types.js +16 -2
- package/dist/bridge/types.js.map +1 -1
- package/dist/catalog-protocol.d.ts +64 -0
- package/dist/catalog-protocol.js +460 -0
- package/dist/catalog-protocol.js.map +1 -0
- package/dist/cli-commands/command.js +84 -61
- package/dist/cli-commands/command.js.map +1 -1
- package/dist/cli-commands/extensions.js +70 -50
- package/dist/cli-commands/extensions.js.map +1 -1
- package/dist/cli-commands/instances.js +1 -1
- package/dist/cli-commands/instances.js.map +1 -1
- package/dist/cli-commands/package.js +10 -2
- package/dist/cli-commands/package.js.map +1 -1
- package/dist/cli-process-owners.d.ts +6 -0
- package/dist/cli-process-owners.js +27 -0
- package/dist/cli-process-owners.js.map +1 -0
- package/dist/cli.d.ts +1 -1
- package/dist/cli.js +20 -5
- package/dist/cli.js.map +1 -1
- package/dist/contracts/command-contract.js +14 -4
- package/dist/contracts/command-contract.js.map +1 -1
- package/dist/doctor.d.ts +4 -6
- package/dist/doctor.js +451 -398
- package/dist/doctor.js.map +1 -1
- package/dist/editor-blocker-observer.d.ts +2 -1
- package/dist/editor-blocker-observer.js +40 -13
- package/dist/editor-blocker-observer.js.map +1 -1
- package/dist/extension-availability.d.ts +27 -9
- package/dist/extension-availability.js +96 -56
- package/dist/extension-availability.js.map +1 -1
- package/dist/extensions/descriptor-loader.d.ts +2 -2
- package/dist/extensions/descriptor-loader.js +3 -4
- package/dist/extensions/descriptor-loader.js.map +1 -1
- package/dist/extensions/index.d.ts +1 -1
- package/dist/extensions/index.js +1 -1
- package/dist/extensions/index.js.map +1 -1
- package/dist/extensions/installer.d.ts +57 -5
- package/dist/extensions/installer.js +263 -64
- package/dist/extensions/installer.js.map +1 -1
- package/dist/extensions/registry.js +3 -5
- package/dist/extensions/registry.js.map +1 -1
- package/dist/extensions/state-contract.d.ts +11 -0
- package/dist/extensions/state-contract.js +50 -0
- package/dist/extensions/state-contract.js.map +1 -0
- package/dist/instances.d.ts +19 -1
- package/dist/instances.js +39 -0
- package/dist/instances.js.map +1 -1
- package/dist/package-manager.d.ts +0 -24
- package/dist/package-manager.js +5 -58
- package/dist/package-manager.js.map +1 -1
- package/dist/project-tool-discovery.d.ts +5 -2
- package/dist/project-tool-discovery.js +22 -18
- package/dist/project-tool-discovery.js.map +1 -1
- package/dist/runtime-code.js +1 -1
- package/dist/runtime-code.js.map +1 -1
- package/dist/tool-name.d.ts +4 -0
- package/dist/tool-name.js +15 -0
- package/dist/tool-name.js.map +1 -0
- package/dist/tools/.generated-completion-registry.d.ts +2 -0
- package/dist/tools/.generated-completion-registry.js +763 -325
- package/dist/tools/.generated-completion-registry.js.map +1 -1
- package/dist/tools/.generated-registry.d.ts +6 -11
- package/dist/tools/.generated-registry.js +6 -11
- package/dist/tools/.generated-registry.js.map +1 -1
- package/dist/tools/.generated-schemas.js +11 -16
- package/dist/tools/.generated-schemas.js.map +1 -1
- package/dist/tools/asset/refresh-status.d.ts +3 -0
- package/dist/tools/asset/refresh-status.js +12 -0
- package/dist/tools/asset/refresh-status.js.map +1 -0
- package/dist/tools/asset/refresh.js +7 -3
- package/dist/tools/asset/refresh.js.map +1 -1
- package/dist/tools/build/player-status.d.ts +3 -0
- package/dist/tools/build/player-status.js +12 -0
- package/dist/tools/build/player-status.js.map +1 -0
- package/dist/tools/build/run.js +1 -1
- package/dist/tools/build/run.js.map +1 -1
- package/dist/tools/catalog-control.d.ts +22 -0
- package/dist/tools/catalog-control.js +335 -0
- package/dist/tools/catalog-control.js.map +1 -0
- package/dist/tools/catalog.d.ts +7 -9
- package/dist/tools/catalog.js +66 -45
- package/dist/tools/catalog.js.map +1 -1
- package/dist/tools/commands.d.ts +1 -1
- package/dist/tools/commands.js +44 -11
- package/dist/tools/commands.js.map +1 -1
- package/dist/tools/define.js +3 -2
- package/dist/tools/define.js.map +1 -1
- package/dist/tools/dispatcher.d.ts +53 -6
- package/dist/tools/dispatcher.js +277 -108
- package/dist/tools/dispatcher.js.map +1 -1
- package/dist/tools/editor/compile.js +1 -1
- package/dist/tools/editor/compile.js.map +1 -1
- package/dist/tools/editor/play-mode-status.d.ts +3 -0
- package/dist/tools/editor/play-mode-status.js +12 -0
- package/dist/tools/editor/play-mode-status.js.map +1 -0
- package/dist/tools/editor/readiness.d.ts +0 -1
- package/dist/tools/editor/readiness.js +0 -1
- package/dist/tools/editor/readiness.js.map +1 -1
- package/dist/tools/editor/refresh.d.ts +7 -3
- package/dist/tools/editor/refresh.js +20 -15
- package/dist/tools/editor/refresh.js.map +1 -1
- package/dist/tools/editor/state.d.ts +2 -2
- package/dist/tools/editor/state.js +13 -12
- package/dist/tools/editor/state.js.map +1 -1
- package/dist/tools/metadata/derived.js +1 -7
- package/dist/tools/metadata/derived.js.map +1 -1
- package/dist/tools/metadata/status.js +1 -12
- package/dist/tools/metadata/status.js.map +1 -1
- package/dist/tools/metadata/types.d.ts +0 -2
- package/dist/tools/navmesh/live.js +1 -1
- package/dist/tools/navmesh/live.js.map +1 -1
- package/dist/tools/occlusion/live.js +1 -1
- package/dist/tools/occlusion/live.js.map +1 -1
- package/dist/tools/package/deploy.js +2 -2
- package/dist/tools/package/deploy.js.map +1 -1
- package/dist/tools/package/embed.js +1 -1
- package/dist/tools/package/embed.js.map +1 -1
- package/dist/tools/package/install-status.d.ts +3 -0
- package/dist/tools/package/install-status.js +12 -0
- package/dist/tools/package/install-status.js.map +1 -0
- package/dist/tools/package/install.js +3 -3
- package/dist/tools/package/install.js.map +1 -1
- package/dist/tools/package/live-resolve.js +45 -12
- package/dist/tools/package/live-resolve.js.map +1 -1
- package/dist/tools/package/registry-clear.js.map +1 -1
- package/dist/tools/package/registry-set.js.map +1 -1
- package/dist/tools/package/remove-status.d.ts +3 -0
- package/dist/tools/package/remove-status.js +12 -0
- package/dist/tools/package/remove-status.js.map +1 -0
- package/dist/tools/package/remove.js +3 -3
- package/dist/tools/package/remove.js.map +1 -1
- package/dist/tools/package/resolve.js +3 -3
- package/dist/tools/package/resolve.js.map +1 -1
- package/dist/tools/package/restore.js +2 -2
- package/dist/tools/package/restore.js.map +1 -1
- package/dist/tools/package/scoped-registry-add.js.map +1 -1
- package/dist/tools/status/support.d.ts +13 -0
- package/dist/tools/status/support.js +28 -0
- package/dist/tools/status/support.js.map +1 -0
- package/dist/tools/test/cancel.js +2 -2
- package/dist/tools/test/cancel.js.map +1 -1
- package/dist/tools/test/run-status.d.ts +3 -0
- package/dist/tools/test/run-status.js +12 -0
- package/dist/tools/test/run-status.js.map +1 -0
- package/dist/tools/test/run.js +7 -4
- package/dist/tools/test/run.js.map +1 -1
- package/dist/tools/tools/group-summaries.js +10 -14
- package/dist/tools/tools/group-summaries.js.map +1 -1
- package/docs/architecture.md +4 -4
- package/docs/availability-differences.md +4 -4
- package/docs/command-execution.md +4 -3
- package/docs/error-codes.md +13 -5
- package/docs/extensions.md +1 -7
- package/docs/risk-and-side-effects.md +4 -3
- package/docs/safety-boundaries.md +3 -1
- package/docs/target-and-instance.md +1 -1
- package/docs/tool-discovery.md +17 -10
- package/docs/tool-execution.md +18 -7
- package/extensions/cinemachine/unitypkg/Editor/UnityCliExtensionAssembly.cs +3 -0
- package/extensions/hdrp/unitypkg/Editor/UnityCliExtensionAssembly.cs +3 -0
- package/extensions/probuilder/unitypkg/Editor/UnityCliExtensionAssembly.cs +3 -0
- package/extensions/urp/unitypkg/Editor/UnityCliExtensionAssembly.cs +3 -0
- package/extensions/vfx-graph/unitypkg/Editor/UnityCliExtensionAssembly.cs +3 -0
- package/package.json +2 -4
- package/skills/unitycli/SKILL.md +11 -2
- package/skills/unitycli/manifest.json +1 -1
- package/skills/unitycli/references/operation-protocol.md +3 -3
- package/unitypkg/Editor/AssemblyInfo.cs +5 -0
- package/unitypkg/Editor/Bridge/BridgeCommandRegistry.cs +49 -14
- package/unitypkg/Editor/Bridge/BridgeHttpServer.cs +9 -35
- package/unitypkg/Editor/Bridge/BridgeQueueState.cs +672 -0
- package/unitypkg/Editor/Bridge/BridgeWorkQueue.cs +970 -120
- package/unitypkg/Editor/BridgeStartupStateMachine.cs +59 -1
- package/unitypkg/Editor/Commands/ProjectToolCommands.cs +4 -0
- package/unitypkg/Editor/Commands/RuntimeToolCommands.cs +3 -0
- package/unitypkg/Editor/Generated/UnityCliToolCompletionRegistry.g.cs +379 -14
- package/unitypkg/Editor/Infrastructure/CodeExecSupport.cs +28 -13
- package/unitypkg/Editor/Infrastructure/RegistryOwnershipResolver.cs +132 -105
- package/unitypkg/Editor/Infrastructure/UnityCliActiveOperation.cs +138 -29
- package/unitypkg/Editor/Infrastructure/UnityCliAdmission.cs +1856 -237
- package/unitypkg/Editor/Infrastructure/UnityCliDoctorDiagnostics.cs +220 -0
- package/unitypkg/Editor/Infrastructure/UnityCliDurableStatusCoordinator.cs +118 -0
- package/unitypkg/Editor/Infrastructure/UnityCliEditorStateSnapshot.cs +2 -1
- package/unitypkg/Editor/Infrastructure/UnityCliHierarchyPager.cs +203 -0
- package/unitypkg/Editor/Infrastructure/UnityCliInstanceCleanup.cs +2 -1
- package/unitypkg/Editor/Infrastructure/UnityCliInstanceRegistry.cs +201 -63
- package/unitypkg/Editor/Infrastructure/UnityCliJson.cs +2 -3
- package/unitypkg/Editor/Infrastructure/UnityCliLiveBuildCoordinator.cs +289 -46
- package/unitypkg/Editor/Infrastructure/UnityCliLiveRefreshCoordinator.cs +87 -53
- package/unitypkg/Editor/Infrastructure/UnityCliNavMeshBakeCoordinator.cs +4 -4
- package/unitypkg/Editor/Infrastructure/UnityCliObjectRef.cs +128 -25
- package/unitypkg/Editor/Infrastructure/UnityCliObjectSerializer.cs +435 -327
- package/unitypkg/Editor/Infrastructure/UnityCliOcclusionBakeCoordinator.cs +4 -4
- package/unitypkg/Editor/Infrastructure/UnityCliOperationCoordinator.cs +351 -53
- package/unitypkg/Editor/Infrastructure/UnityCliPackageResolveCoordinator.cs +118 -18
- package/unitypkg/Editor/Infrastructure/UnityCliPackageResolveState.cs +20 -1
- package/unitypkg/Editor/Infrastructure/UnityCliReadGeneration.cs +97 -0
- package/unitypkg/Editor/Infrastructure/UnityCliReflection.cs +644 -133
- package/unitypkg/Editor/Infrastructure/UnityCliReloadOperation.cs +128 -41
- package/unitypkg/Editor/Infrastructure/UnityCliRuntimeExecutor.cs +14 -84
- package/unitypkg/Editor/Infrastructure/UnityCliSerializer.cs +220 -0
- package/unitypkg/Editor/Infrastructure/UnityCliSessionMutationLease.cs +69 -29
- package/unitypkg/Editor/Infrastructure/UnityCliTestRunCoordinator.cs +440 -54
- package/unitypkg/Editor/Infrastructure/UnityCliWaiter.cs +128 -35
- package/unitypkg/Editor/ProjectTools/IUnityCliTool.cs +9 -1
- package/unitypkg/Editor/ProjectTools/OfficialAttributeToolRegistry.cs +32 -31
- package/unitypkg/Editor/ProjectTools/ProjectToolRegistry.cs +607 -458
- package/unitypkg/Editor/ProjectTools/ProjectToolSchemaValidator.cs +35 -7
- package/unitypkg/Editor/ProjectTools/RegisteredTool.cs +501 -60
- package/unitypkg/Editor/ProjectTools/UnityCliProjectToolContext.cs +21 -0
- package/unitypkg/Editor/ProjectTools/UnityCliSchemaDeriver.cs +36 -7
- package/unitypkg/Editor/ProjectTools/UnityCliToolName.cs +30 -0
- package/unitypkg/Editor/Properties/AssemblyInfo.cs +3 -0
- package/unitypkg/Editor/Tools/asset/get-data.cs +16 -7
- package/unitypkg/Editor/Tools/build/BuildSceneStateTool.cs +23 -3
- package/unitypkg/Editor/Tools/build/BuildToolDtos.cs +2 -1
- package/unitypkg/Editor/Tools/build/scene/add.cs +6 -3
- package/unitypkg/Editor/Tools/build/scene/disable.cs +1 -1
- package/unitypkg/Editor/Tools/build/scene/enable.cs +1 -1
- package/unitypkg/Editor/Tools/build/scene/list.cs +1 -1
- package/unitypkg/Editor/Tools/build/scene/remove.cs +13 -3
- package/unitypkg/Editor/Tools/camera/CameraToolSupport.cs +38 -38
- package/unitypkg/Editor/Tools/camera/multiview.cs +13 -6
- package/unitypkg/Editor/Tools/camera/screenshot.cs +14 -7
- package/unitypkg/Editor/Tools/component/get.cs +16 -9
- package/unitypkg/Editor/Tools/component/modify.cs +6 -4
- package/unitypkg/Editor/Tools/console/clear.cs +7 -6
- package/unitypkg/Editor/Tools/console/get.cs +48 -16
- package/unitypkg/Editor/Tools/editor/EditorToolSupport.cs +143 -28
- package/unitypkg/Editor/Tools/editor/menu-items.cs +1 -1
- package/unitypkg/Editor/Tools/editor/play.cs +2 -11
- package/unitypkg/Editor/Tools/editor/selection.cs +1 -1
- package/unitypkg/Editor/Tools/editor/stop.cs +2 -11
- package/unitypkg/Editor/Tools/editor/windows.cs +1 -1
- package/unitypkg/Editor/Tools/go/GameObjectToolSupport.cs +54 -4
- package/unitypkg/Editor/Tools/go/delete.cs +1 -1
- package/unitypkg/Editor/Tools/go/find.cs +167 -70
- package/unitypkg/Editor/Tools/graphics/GraphicsToolSupport.cs +25 -0
- package/unitypkg/Editor/Tools/graphics/light-probe-group.cs +9 -3
- package/unitypkg/Editor/Tools/graphics/pipeline-info.cs +1 -1
- package/unitypkg/Editor/Tools/graphics/pipeline-settings.cs +1 -1
- package/unitypkg/Editor/Tools/graphics/quality.cs +2 -2
- package/unitypkg/Editor/Tools/graphics/reflection-probe.cs +3 -3
- package/unitypkg/Editor/Tools/graphics/stats.cs +1 -1
- package/unitypkg/Editor/Tools/object/ObjectToolSupport.cs +4 -4
- package/unitypkg/Editor/Tools/object/get-data.cs +9 -7
- package/unitypkg/Editor/Tools/object/modify.cs +7 -5
- package/unitypkg/Editor/Tools/physics/raycast.cs +24 -6
- package/unitypkg/Editor/Tools/prefab/stage.cs +1 -1
- package/unitypkg/Editor/Tools/profiler/ProfilerFrameDebuggerSupport.cs +94 -21
- package/unitypkg/Editor/Tools/profiler/ProfilerMemorySnapshotSupport.cs +397 -10
- package/unitypkg/Editor/Tools/profiler/ProfilerToolSupport.cs +18 -4
- package/unitypkg/Editor/Tools/profiler/frame-debugger/enable.cs +1 -1
- package/unitypkg/Editor/Tools/profiler/frame-debugger/events.cs +88 -87
- package/unitypkg/Editor/Tools/profiler/hierarchy.cs +278 -112
- package/unitypkg/Editor/Tools/profiler/memory-snapshot/compare.cs +9 -5
- package/unitypkg/Editor/Tools/profiler/memory-snapshot/list.cs +37 -35
- package/unitypkg/Editor/Tools/profiler/memory-snapshot/take.cs +99 -97
- package/unitypkg/Editor/Tools/project/info.cs +1 -1
- package/unitypkg/Editor/Tools/project/layers.cs +1 -1
- package/unitypkg/Editor/Tools/project/tags.cs +1 -1
- package/unitypkg/Editor/Tools/reflection/method/call.cs +9 -7
- package/unitypkg/Editor/Tools/reflection/method/find.cs +27 -37
- package/unitypkg/Editor/Tools/reflection/type/schema.cs +24 -28
- package/unitypkg/Editor/Tools/scene/gameobject/component.cs +8 -5
- package/unitypkg/Editor/Tools/scene/gameobject/components.cs +10 -7
- package/unitypkg/Editor/Tools/scene/gameobject-support.cs +104 -8
- package/unitypkg/Editor/Tools/scene/gameobject.cs +37 -16
- package/unitypkg/Editor/Tools/scene/hierarchy.cs +146 -142
- package/unitypkg/Editor/Tools/screenshot/EditorElementCaptureToolSupport.cs +77 -25
- package/unitypkg/Editor/Tools/screenshot/ScreenshotToolSupport.cs +315 -95
- package/unitypkg/Editor/Tools/screenshot/editor-element.cs +7 -5
- package/unitypkg/Editor/Tools/screenshot/game-view.cs +35 -21
- package/unitypkg/Editor/Tools/screenshot/isolated-object.cs +29 -23
- package/unitypkg/Editor/Tools/screenshot/orbit.cs +37 -25
- package/unitypkg/Editor/Tools/screenshot/scene-view.cs +25 -18
- package/unitypkg/Editor/Tools/screenshot/screen.cs +177 -17
- package/unitypkg/Editor/Tools/screenshot/surround.cs +83 -79
- package/unitypkg/Editor/Tools/ui/render-preview.cs +16 -11
- package/unitypkg/Editor/UnityCliBridge.cs +97 -34
- package/unitypkg/Runtime/Infrastructure/UnityCliRuntimeBridge.cs +753 -122
- package/unitypkg/Runtime/Properties/AssemblyInfo.cs +5 -0
- package/unitypkg/Runtime/UnityCli.Runtime.asmdef +1 -1
- package/unitypkg/Shared/AssemblyInfo.cs +4 -0
- package/unitypkg/Shared/UnityCliAdmissionPool.cs +265 -75
- package/unitypkg/Shared/UnityCliBridgeQueuePolicy.cs +410 -0
- package/unitypkg/Shared/UnityCliBridgeWorkItemState.cs +47 -0
- package/unitypkg/Shared/UnityCliExceptionProjection.cs +151 -0
- package/unitypkg/Shared/UnityCliQueuePublication.cs +30 -0
- package/unitypkg/Shared/UnityCliRequestBudget.cs +352 -0
- package/unitypkg/Shared/UnityCliRuntimeRequestPublication.cs +107 -0
- package/unitypkg/Tests/Editor/UnityCli.Editor.Tests.asmdef +2 -2
- package/unitypkg/Tests/Editor/UnityCliAdmissionCoordinatorIntegrationTests.cs +1329 -0
- package/unitypkg/Tests/Editor/UnityCliAdmissionPoolTests.cs +311 -114
- package/unitypkg/Tests/Editor/UnityCliAdmissionRepairStateTests.cs +94 -0
- package/unitypkg/Tests/Editor/UnityCliBridgeAdmissionIntegrationTests.cs +1229 -0
- package/unitypkg/Tests/Editor/UnityCliBridgeQueuePolicyTests.cs +412 -0
- package/unitypkg/Tests/Editor/UnityCliContinuationIntegrationTests.cs +292 -0
- package/unitypkg/Tests/Editor/UnityCliDiagnosticBoundaryTests.cs +120 -0
- package/unitypkg/Tests/Editor/UnityCliDurableStatusTests.cs +84 -0
- package/unitypkg/Tests/Editor/UnityCliExceptionProjectionTests.cs +72 -0
- package/unitypkg/Tests/Editor/UnityCliInstancePublicationRetryTests.cs +180 -97
- package/unitypkg/Tests/Editor/UnityCliMemoryReflectionIntegrationTests.cs +434 -0
- package/unitypkg/Tests/Editor/UnityCliRequestBudgetTests.cs +615 -0
- package/unitypkg/Tests/Editor/UnityCliRuntimeBridgeIntegrationTests.cs +520 -0
- package/unitypkg/Tests/Editor/UnityCliToolCatalogTests.cs +562 -0
- package/unitypkg/Tests/Runtime/UnityCli.Runtime.Tests.asmdef +23 -0
- package/unitypkg/Tests/Runtime/UnityCliRuntimeCatalogValidationTests.cs +29 -0
- package/unitypkg/package.json +1 -1
- package/contracts/static-capability-catalog.json +0 -48226
- package/dist/bridge/domains/diagnose.d.ts +0 -2
- package/dist/bridge/domains/diagnose.js +0 -11
- package/dist/bridge/domains/diagnose.js.map +0 -1
- package/dist/bridge/domains/extension.d.ts +0 -8
- package/dist/bridge/domains/extension.js +0 -20
- package/dist/bridge/domains/extension.js.map +0 -1
- package/dist/capabilities.d.ts +0 -5
- package/dist/capabilities.js +0 -84
- package/dist/capabilities.js.map +0 -1
- package/dist/static-capability-catalog.d.ts +0 -13
- package/dist/static-capability-catalog.js +0 -41
- package/dist/static-capability-catalog.js.map +0 -1
- package/dist/tools/diagnose/capabilities.d.ts +0 -13
- package/dist/tools/diagnose/capabilities.js +0 -34
- package/dist/tools/diagnose/capabilities.js.map +0 -1
- package/dist/tools/package/info.d.ts +0 -19
- package/dist/tools/package/info.js +0 -27
- package/dist/tools/package/info.js.map +0 -1
- package/dist/tools/package/list.d.ts +0 -27
- package/dist/tools/package/list.js +0 -21
- package/dist/tools/package/list.js.map +0 -1
- package/dist/tools/package/registry-get.d.ts +0 -10
- package/dist/tools/package/registry-get.js +0 -22
- package/dist/tools/package/registry-get.js.map +0 -1
- package/dist/tools/package/scoped-registry-list.d.ts +0 -14
- package/dist/tools/package/scoped-registry-list.js +0 -22
- package/dist/tools/package/scoped-registry-list.js.map +0 -1
- package/dist/tools/package/search.d.ts +0 -17
- package/dist/tools/package/search.js +0 -39
- package/dist/tools/package/search.js.map +0 -1
- package/dist/tools/package/status.d.ts +0 -21
- package/dist/tools/package/status.js +0 -37
- package/dist/tools/package/status.js.map +0 -1
- package/dist/tools/tools/describe.d.ts +0 -27
- package/dist/tools/tools/describe.js +0 -35
- package/dist/tools/tools/describe.js.map +0 -1
- package/dist/tools/tools/group-list.d.ts +0 -16
- package/dist/tools/tools/group-list.js +0 -38
- package/dist/tools/tools/group-list.js.map +0 -1
- package/dist/tools/tools/group.d.ts +0 -13
- package/dist/tools/tools/group.js +0 -34
- package/dist/tools/tools/group.js.map +0 -1
- package/dist/tools/tools/pagination.d.ts +0 -17
- package/dist/tools/tools/pagination.js +0 -28
- package/dist/tools/tools/pagination.js.map +0 -1
- package/dist/tools/tools/search.d.ts +0 -15
- package/dist/tools/tools/search.js +0 -42
- package/dist/tools/tools/search.js.map +0 -1
- package/unitypkg/Editor/Tools/diagnose/preflight.cs +0 -269
- package/unitypkg/Editor/Tools/editor/console.cs +0 -26
- package/unitypkg/Editor/Tools/extension/status.cs +0 -87
- package/unitypkg/Editor/Tools/go/inspect.cs +0 -49
- package/unitypkg/Editor/Tools/graphics/pipeline-quality.cs +0 -24
- package/unitypkg/Editor/Tools/graphics/probe-positions.cs +0 -58
- package/unitypkg/Editor/Tools/graphics/settings.cs +0 -104
- package/unitypkg/Editor/Tools/graphics/stats-counters.cs +0 -28
- package/unitypkg/Editor/Tools/graphics/stats-memory.cs +0 -21
- package/unitypkg/Editor/Tools/instances/list.cs +0 -71
- package/unitypkg/Editor/Tools/physics/raycast-all.cs +0 -67
- package/unitypkg/Editor/Tools/scene/build-settings.cs +0 -69
- package/unitypkg/Editor/Tools/scene/data.cs +0 -125
- package/unitypkg/Editor/Tools/tests/list.cs +0 -98
|
@@ -23,14 +23,80 @@ namespace UnityCli
|
|
|
23
23
|
private const string Scope = "build";
|
|
24
24
|
private static bool reloadRecoveryPending;
|
|
25
25
|
internal static bool IsCommand(string command) { return command == Command; }
|
|
26
|
+
|
|
27
|
+
/// <summary>production固定真实prepare/effect;测试仅按单次Execute显式注入,不写全局hook。</summary>
|
|
28
|
+
internal sealed class BuildExecutionDependencies
|
|
29
|
+
{
|
|
30
|
+
internal Func<string, string, List<string>, Prepared> PrepareTarget;
|
|
31
|
+
internal Func<Prepared, BuildEffectResult> RunEffect;
|
|
32
|
+
internal readonly BuildTestBoundary Boundary;
|
|
33
|
+
|
|
34
|
+
internal BuildExecutionDependencies(bool testMode)
|
|
35
|
+
{
|
|
36
|
+
Boundary = new BuildTestBoundary(testMode);
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
internal static BuildExecutionDependencies Production()
|
|
40
|
+
{
|
|
41
|
+
var dependencies = new BuildExecutionDependencies(false)
|
|
42
|
+
{
|
|
43
|
+
PrepareTarget = (target, outputPath, options) => Prepare(new TargetArgs { Target = target, OutputPath = outputPath, Options = options }),
|
|
44
|
+
RunEffect = RunBuildEffect
|
|
45
|
+
};
|
|
46
|
+
return dependencies;
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
internal void Hit(string name)
|
|
50
|
+
{
|
|
51
|
+
Boundary.Hit(name);
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
internal sealed class BuildTestBoundary
|
|
55
|
+
{
|
|
56
|
+
private readonly object sync = new object();
|
|
57
|
+
private readonly Dictionary<string, Action> expected = new Dictionary<string, Action>(StringComparer.Ordinal);
|
|
58
|
+
private readonly bool enabled;
|
|
59
|
+
|
|
60
|
+
internal BuildTestBoundary(bool enabled) { this.enabled = enabled; }
|
|
61
|
+
internal void ExpectOnce(string name, Action action)
|
|
62
|
+
{
|
|
63
|
+
if (!enabled) throw new InvalidOperationException("Production build dependencies do not accept test boundaries.");
|
|
64
|
+
if (string.IsNullOrWhiteSpace(name) || action == null) throw new ArgumentException("Build test boundary is invalid.");
|
|
65
|
+
lock (sync)
|
|
66
|
+
{
|
|
67
|
+
if (expected.ContainsKey(name)) throw new InvalidOperationException("Build test boundary is already registered: " + name);
|
|
68
|
+
expected.Add(name, action);
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
internal void Hit(string name)
|
|
72
|
+
{
|
|
73
|
+
Action action;
|
|
74
|
+
lock (sync)
|
|
75
|
+
{
|
|
76
|
+
if (!expected.TryGetValue(name, out action)) return;
|
|
77
|
+
expected.Remove(name);
|
|
78
|
+
}
|
|
79
|
+
action();
|
|
80
|
+
}
|
|
81
|
+
internal void AssertDrained()
|
|
82
|
+
{
|
|
83
|
+
lock (sync)
|
|
84
|
+
{
|
|
85
|
+
if (expected.Count != 0) throw new InvalidOperationException("Build test boundaries were not consumed: " + string.Join(",", expected.Keys));
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
|
|
26
91
|
internal static void Register(BridgeCommandRegistry registry)
|
|
27
92
|
{
|
|
28
|
-
registry.Register<BridgeRequest>(Command, "internal", true, 600000, (r, c) => { throw new InvalidOperationException("Build is coordinator-owned."); });
|
|
93
|
+
registry.Register<BridgeRequest>(Command, "internal", true, 600000, (r, c) => { throw new InvalidOperationException("Build is coordinator-owned."); }, UnityCliBridgeQueuePolicy.WorkClass.Mutation);
|
|
29
94
|
}
|
|
30
95
|
|
|
31
96
|
/// <summary>reload后先持久化outcome-unknown标记,再释放已终止旧domain的exact lease。</summary>
|
|
32
|
-
internal static void Initialize() { RecoverTerminalCleanup(); reloadRecoveryPending = true; MarkReloadOutcomeUnknownAndRelease(); }
|
|
33
|
-
internal static void Tick() {
|
|
97
|
+
internal static void Initialize() { RecoverTerminalCleanup(ProductionQueueState); reloadRecoveryPending = true; MarkReloadOutcomeUnknownAndRelease(); }
|
|
98
|
+
internal static void Tick() { Tick(ProductionQueueState); }
|
|
99
|
+
internal static void Tick(BridgeQueueState state) { RecoverTerminalCleanup(state); if (object.ReferenceEquals(state, ProductionQueueState) && reloadRecoveryPending) MarkReloadOutcomeUnknownAndRelease(); }
|
|
34
100
|
|
|
35
101
|
private static void MarkReloadOutcomeUnknownAndRelease()
|
|
36
102
|
{
|
|
@@ -65,6 +131,24 @@ namespace UnityCli
|
|
|
65
131
|
|
|
66
132
|
internal static async Task<string> Execute(BridgeRequest request, byte[] rawRequestBytes, Func<bool> tryAccept, CancellationToken cancellationToken)
|
|
67
133
|
{
|
|
134
|
+
try
|
|
135
|
+
{
|
|
136
|
+
return await Execute(ProductionQueueState, request, rawRequestBytes, tryAccept, cancellationToken, BuildExecutionDependencies.Production());
|
|
137
|
+
}
|
|
138
|
+
catch (Exception exception)
|
|
139
|
+
{
|
|
140
|
+
WriteLog("build_entry_failed requestId=" + request.RequestId + " exception=" + exception);
|
|
141
|
+
return SerializeBridgeExceptionEnvelope(request.RequestId, new BridgeCommandException(
|
|
142
|
+
"E_EXECUTION_FAILED",
|
|
143
|
+
"Build request preparation failed before a trusted coordinator terminal was available.",
|
|
144
|
+
"Inspect UnityCliBridge.log and Build Settings before retrying build.run."));
|
|
145
|
+
}
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
internal static async Task<string> Execute(BridgeQueueState queueState, BridgeRequest request, byte[] rawRequestBytes, Func<bool> tryAccept, CancellationToken cancellationToken, BuildExecutionDependencies dependencies)
|
|
149
|
+
{
|
|
150
|
+
if (queueState == null) throw new ArgumentNullException("queueState");
|
|
151
|
+
if (dependencies == null || dependencies.PrepareTarget == null || dependencies.RunEffect == null) throw new ArgumentNullException("dependencies");
|
|
68
152
|
var args = request.DeserializeArgs<Args>();
|
|
69
153
|
if (request.Execution != null && request.Execution.DryRun == true)
|
|
70
154
|
{
|
|
@@ -73,13 +157,13 @@ namespace UnityCli
|
|
|
73
157
|
}
|
|
74
158
|
var digest = UnityCliRequestDigest.Compute(rawRequestBytes, request.InstanceId);
|
|
75
159
|
object recoveredTerminal;
|
|
76
|
-
if (
|
|
160
|
+
if (queueState.TryGetTerminal(Scope, request.RequestId, digest, out recoveredTerminal))
|
|
77
161
|
{
|
|
78
|
-
try { UnityCliActiveOperation.BeginExactTerminalCleanup(Scope, request.RequestId, digest); } catch { }
|
|
162
|
+
try { UnityCliActiveOperation.BeginExactTerminalCleanup(Scope, request.RequestId, digest, queueState); } catch { }
|
|
79
163
|
return Terminal(request.RequestId, recoveredTerminal);
|
|
80
164
|
}
|
|
81
165
|
Dictionary<string, object> active;
|
|
82
|
-
try { active =
|
|
166
|
+
try { active = queueState.LoadOperation(Scope); }
|
|
83
167
|
catch (Exception) { return SerializeBridgeExceptionEnvelope(request.RequestId, new BridgeCommandException("E_EXECUTION_TIMEOUT", "Build active state cannot be read; outcome is unknown.")); }
|
|
84
168
|
if (active != null)
|
|
85
169
|
{
|
|
@@ -90,55 +174,72 @@ namespace UnityCli
|
|
|
90
174
|
if (!active.TryGetValue("reloadOutcomeUnknown", out reloadUnknown) || !(reloadUnknown is bool) || !(bool)reloadUnknown)
|
|
91
175
|
return Busy(request.RequestId);
|
|
92
176
|
var unknown = ProtocolEnvelopeFactory.Error(request.RequestId, "E_EXECUTION_TIMEOUT", "A previous build did not reach a terminal result before reload or timeout.", null, new[] { "Inspect build output and editor.state before retrying." });
|
|
93
|
-
return FinishTerminal(request.RequestId, digest, unknown);
|
|
177
|
+
return FinishTerminal(queueState, request.RequestId, digest, unknown, dependencies);
|
|
94
178
|
}
|
|
95
179
|
bool newlyAcquiredLease;
|
|
96
|
-
if (!
|
|
180
|
+
if (!queueState.TryAcquireLease(request.RequestId, digest, out newlyAcquiredLease) || !newlyAcquiredLease) return Busy(request.RequestId);
|
|
181
|
+
AdmissionOwnerIdentity queueAdmissionOwner;
|
|
182
|
+
try { queueAdmissionOwner = CaptureAdmissionOwner(queueState, request.RequestId, digest); }
|
|
183
|
+
catch (Exception exception)
|
|
184
|
+
{
|
|
185
|
+
return FinishBuildPreRootFault(queueState, request.RequestId, digest, new BridgeCommandException("E_EXECUTION_TIMEOUT", "Build queue admission identity could not be frozen: " + exception.GetType().Name + "."));
|
|
186
|
+
}
|
|
187
|
+
var activeRootCreated = false;
|
|
97
188
|
try
|
|
98
189
|
{
|
|
99
190
|
if (tryAccept == null || !tryAccept()) throw new OperationCanceledException();
|
|
100
191
|
Validate(args);
|
|
101
|
-
var prepared = args.Targets.Select(
|
|
192
|
+
var prepared = args.Targets.Select(item => dependencies.PrepareTarget(item.Target, item.OutputPath, item.Options)).ToList();
|
|
102
193
|
active = NewActive(request, digest, args);
|
|
103
|
-
|
|
194
|
+
queueState.SaveOperation(Scope, active);
|
|
195
|
+
activeRootCreated = true;
|
|
104
196
|
cancellationToken.ThrowIfCancellationRequested();
|
|
105
197
|
active["phase"] = "running";
|
|
106
|
-
|
|
198
|
+
queueState.SaveOperation(Scope, active);
|
|
107
199
|
var reports = new List<object>();
|
|
108
200
|
foreach (var item in prepared)
|
|
109
201
|
{
|
|
110
202
|
bool ownedBefore;
|
|
111
|
-
if (!
|
|
112
|
-
return FinishTerminal(request.RequestId, digest, UnknownLeaseTerminal(request.RequestId));
|
|
113
|
-
reports.Add(Build(item));
|
|
203
|
+
if (!queueState.TryIsLeaseOwned(request.RequestId, digest, out ownedBefore) || !ownedBefore)
|
|
204
|
+
return FinishTerminal(queueState, request.RequestId, digest, UnknownLeaseTerminal(request.RequestId), dependencies);
|
|
205
|
+
reports.Add(Build(item, dependencies));
|
|
114
206
|
bool ownedAfter;
|
|
115
|
-
if (!
|
|
116
|
-
return FinishTerminal(request.RequestId, digest, UnknownLeaseTerminal(request.RequestId));
|
|
207
|
+
if (!queueState.TryIsLeaseOwned(request.RequestId, digest, out ownedAfter) || !ownedAfter)
|
|
208
|
+
return FinishTerminal(queueState, request.RequestId, digest, UnknownLeaseTerminal(request.RequestId), dependencies);
|
|
117
209
|
}
|
|
118
210
|
var data = new Dictionary<string, object> { { "targets", reports } };
|
|
119
211
|
var failed = reports.Cast<Dictionary<string, object>>().Any(x => !string.Equals(x["result"] as string, "Succeeded", StringComparison.Ordinal));
|
|
120
212
|
object envelope = failed ? (object)ProtocolEnvelopeFactory.Error(request.RequestId, "E_BUILD_FAILED", "One or more BuildPlayer reports were not successful.", data, new[] { "Inspect the returned BuildReport summaries and Unity Console." }) : ProtocolEnvelopeFactory.Success(request.RequestId, data);
|
|
121
|
-
return FinishTerminal(request.RequestId, digest, envelope);
|
|
213
|
+
return FinishTerminal(queueState, request.RequestId, digest, envelope, dependencies);
|
|
122
214
|
}
|
|
123
215
|
catch (OperationCanceledException)
|
|
124
216
|
{
|
|
125
|
-
|
|
217
|
+
var error = new BridgeCommandException("E_EXECUTION_TIMEOUT", "Build did not begin before the request deadline.");
|
|
218
|
+
if (!activeRootCreated && ActiveRootDefinitelyAbsent(queueState, request.RequestId, digest))
|
|
219
|
+
return FinishBuildPreRootFault(queueState, request.RequestId, digest, error);
|
|
220
|
+
return FinishBuildTerminalAfterRootFault(queueState, request.RequestId, digest, ProtocolEnvelopeFactory.Error(request.RequestId, "E_EXECUTION_TIMEOUT", "Build did not complete before the request deadline.", null, new[] { "Inspect editor.state and retry." }), queueAdmissionOwner, dependencies);
|
|
126
221
|
}
|
|
127
222
|
catch (BridgeCommandException ex)
|
|
128
223
|
{
|
|
129
|
-
|
|
224
|
+
if (!activeRootCreated && ActiveRootDefinitelyAbsent(queueState, request.RequestId, digest))
|
|
225
|
+
return FinishBuildPreRootFault(queueState, request.RequestId, digest, ex);
|
|
226
|
+
return FinishBuildTerminalAfterRootFault(queueState, request.RequestId, digest, BridgeExceptionTerminal(request.RequestId, ex), queueAdmissionOwner, dependencies);
|
|
130
227
|
}
|
|
131
228
|
catch (Exception ex)
|
|
132
229
|
{
|
|
133
|
-
|
|
230
|
+
WriteLog("build_unhandled_exception requestId=" + request.RequestId + " activeRootCreated=" + activeRootCreated + " exception=" + ex);
|
|
231
|
+
var error = new BridgeCommandException("E_EXECUTION_FAILED", "Build preparation failed before BuildPlayer could start.", "Inspect UnityCliBridge.log and Build Settings before retrying build.run.");
|
|
232
|
+
if (!activeRootCreated && ActiveRootDefinitelyAbsent(queueState, request.RequestId, digest))
|
|
233
|
+
return FinishBuildPreRootFault(queueState, request.RequestId, digest, error);
|
|
234
|
+
return FinishBuildTerminalAfterRootFault(queueState, request.RequestId, digest, SerializeException(request.RequestId, ex), queueAdmissionOwner, dependencies);
|
|
134
235
|
}
|
|
135
236
|
finally
|
|
136
237
|
{
|
|
137
238
|
try
|
|
138
239
|
{
|
|
139
|
-
UnityCliActiveOperation.RetryExactTerminalCleanup(Scope);
|
|
140
|
-
if (!
|
|
141
|
-
|
|
240
|
+
UnityCliActiveOperation.RetryExactTerminalCleanup(Scope, queueState);
|
|
241
|
+
if (!queueState.OperationExists(Scope) && !queueState.OperationExists(Scope + "-terminal-cleanup"))
|
|
242
|
+
queueState.ReleaseLease(request.RequestId, digest);
|
|
142
243
|
}
|
|
143
244
|
catch { }
|
|
144
245
|
await Task.FromResult(0);
|
|
@@ -148,11 +249,83 @@ namespace UnityCli
|
|
|
148
249
|
private static Dictionary<string, object> NewActive(BridgeRequest request, string digest, Args args) { return new Dictionary<string, object> { { "requestId", request.RequestId }, { "requestDigest", digest }, { "editorSessionId", EditorSessionId() }, { "phase", "accepted" }, { "startedAt", DateTimeOffset.UtcNow.ToString("O", CultureInfo.InvariantCulture) }, { "targets", args.Targets.Select(x => (object)new Dictionary<string, object> { { "target", x.Target }, { "outputPath", x.OutputPath } }).ToList() } }; }
|
|
149
250
|
private static string Value(IDictionary<string, object> value, string key) { object item; return value != null && value.TryGetValue(key, out item) ? item as string : null; }
|
|
150
251
|
private static string Busy(string id) { return UnityCliSerializer.Serialize(ProtocolEnvelopeFactory.Error(id, "E_UNITY_BUSY", "Another mutation owns the selected Unity instance.", null, new[] { "Wait for the current mutation to reach its terminal result, then retry." }, true, 250)); }
|
|
151
|
-
private static
|
|
252
|
+
private static bool ActiveRootDefinitelyAbsent(BridgeQueueState state, string id, string digest)
|
|
152
253
|
{
|
|
254
|
+
try
|
|
255
|
+
{
|
|
256
|
+
var root = state.LoadOperation(Scope);
|
|
257
|
+
if (root != null) return false;
|
|
258
|
+
return !state.OperationExists(Scope);
|
|
259
|
+
}
|
|
260
|
+
catch { return false; }
|
|
261
|
+
}
|
|
262
|
+
|
|
263
|
+
private static string FinishBuildPreRootFault(BridgeQueueState state, string id, string digest, BridgeCommandException error)
|
|
264
|
+
{
|
|
265
|
+
try { state.ReleaseLease(id, digest); } catch { }
|
|
153
266
|
bool isOwned;
|
|
154
|
-
if (
|
|
155
|
-
|
|
267
|
+
if (state.TryIsLeaseOwned(id, digest, out isOwned) && !isOwned)
|
|
268
|
+
return SerializeBridgeExceptionEnvelope(id, error);
|
|
269
|
+
try { UnityCliActiveOperation.BeginExactTerminalCleanup(Scope, id, digest, state); } catch { }
|
|
270
|
+
return SerializeBridgeExceptionEnvelope(id, new BridgeCommandException("E_EXECUTION_TIMEOUT", "Build was rejected before its durable root, but exact lease cleanup remains pending."));
|
|
271
|
+
}
|
|
272
|
+
|
|
273
|
+
private static string FinishBuildTerminalAfterRootFault(BridgeQueueState queueState, string id, string digest, object envelope, AdmissionOwnerIdentity queueAdmissionOwner, BuildExecutionDependencies dependencies)
|
|
274
|
+
{
|
|
275
|
+
try { return FinishTerminal(queueState, id, digest, envelope, dependencies); }
|
|
276
|
+
catch (Exception exception)
|
|
277
|
+
{
|
|
278
|
+
var unknown = ProtocolEnvelopeFactory.Error(id, "E_EXECUTION_TIMEOUT", "Build active state or terminal publication failed after effect; outcome is unknown.", null, new[] { "Inspect build artifacts and editor.state before submitting another mutation." });
|
|
279
|
+
try
|
|
280
|
+
{
|
|
281
|
+
var owner = queueAdmissionOwner ?? CaptureAdmissionOwner(queueState, id, digest);
|
|
282
|
+
owner.TopRequestDigest = digest;
|
|
283
|
+
PersistAdmissionOwnerTransfer(queueState, Scope + "-admission-owner", new Dictionary<string, object>
|
|
284
|
+
{
|
|
285
|
+
{ "requestId", id }, { "requestDigest", digest }, { "editorSessionId", EditorSessionId() }
|
|
286
|
+
}, owner, UnityCliAdmissionPool.AdmissionOwnerState.Recovery);
|
|
287
|
+
}
|
|
288
|
+
catch (Exception markerException)
|
|
289
|
+
{
|
|
290
|
+
return SerializeBridgeExceptionEnvelope(id, new BridgeCommandException("E_EXECUTION_TIMEOUT", "Build recovery marker remains pending after a post-root failure: " + markerException.GetType().Name + "."));
|
|
291
|
+
}
|
|
292
|
+
try
|
|
293
|
+
{
|
|
294
|
+
try
|
|
295
|
+
{
|
|
296
|
+
var recoveryRoot = queueState.LoadOperation(Scope);
|
|
297
|
+
if (recoveryRoot != null && string.Equals(Value(recoveryRoot, "requestId"), id, StringComparison.Ordinal)
|
|
298
|
+
&& string.Equals(Value(recoveryRoot, "requestDigest"), digest, StringComparison.Ordinal))
|
|
299
|
+
{
|
|
300
|
+
recoveryRoot["phase"] = "terminal_pending";
|
|
301
|
+
recoveryRoot["terminalEnvelope"] = unknown;
|
|
302
|
+
queueState.SaveOperation(Scope, recoveryRoot);
|
|
303
|
+
}
|
|
304
|
+
}
|
|
305
|
+
catch { }
|
|
306
|
+
dependencies.Hit("before-build-terminal-store");
|
|
307
|
+
var first = queueState.StoreTerminalFirst(Scope, id, digest, unknown);
|
|
308
|
+
try { UnityCliActiveOperation.BeginExactTerminalCleanup(Scope, id, digest, queueState); } catch { }
|
|
309
|
+
return Terminal(id, first);
|
|
310
|
+
}
|
|
311
|
+
catch
|
|
312
|
+
{
|
|
313
|
+
return SerializeBridgeExceptionEnvelope(id, new BridgeCommandException("E_EXECUTION_TIMEOUT", "Build conservative terminal remains pending after a post-root failure: " + exception.GetType().Name + "."));
|
|
314
|
+
}
|
|
315
|
+
}
|
|
316
|
+
}
|
|
317
|
+
|
|
318
|
+
private static object BridgeExceptionTerminal(string id, BridgeCommandException exception)
|
|
319
|
+
{
|
|
320
|
+
return UnityCliSerializer.Parse(SerializeBridgeExceptionEnvelope(id, exception));
|
|
321
|
+
}
|
|
322
|
+
|
|
323
|
+
private static string FinishTerminal(BridgeQueueState queueState, string id, string digest, object envelope, BuildExecutionDependencies dependencies)
|
|
324
|
+
{
|
|
325
|
+
bool isOwned;
|
|
326
|
+
if (!queueState.TryIsLeaseOwned(id, digest, out isOwned) || !isOwned) envelope = UnknownLeaseTerminal(id);
|
|
327
|
+
dependencies.Hit("before-build-terminal-root-read");
|
|
328
|
+
var active = queueState.LoadOperation(Scope);
|
|
156
329
|
if (active != null)
|
|
157
330
|
{
|
|
158
331
|
if (!string.Equals(Value(active, "requestId"), id, StringComparison.Ordinal)
|
|
@@ -160,24 +333,25 @@ namespace UnityCli
|
|
|
160
333
|
throw new BridgeCommandException("E_EXECUTION_TIMEOUT", "Build terminal active identity cannot be proven.");
|
|
161
334
|
active["phase"] = "terminal_pending";
|
|
162
335
|
active["terminalEnvelope"] = envelope;
|
|
163
|
-
|
|
336
|
+
queueState.SaveOperation(Scope, active);
|
|
164
337
|
}
|
|
165
|
-
|
|
166
|
-
|
|
338
|
+
dependencies.Hit("before-build-terminal-store");
|
|
339
|
+
var first = queueState.StoreTerminalFirst(Scope, id, digest, envelope);
|
|
340
|
+
UnityCliActiveOperation.BeginExactTerminalCleanup(Scope, id, digest, queueState);
|
|
167
341
|
return Terminal(id, first);
|
|
168
342
|
}
|
|
169
|
-
private static void RecoverTerminalCleanup()
|
|
343
|
+
private static void RecoverTerminalCleanup(BridgeQueueState state)
|
|
170
344
|
{
|
|
171
345
|
try
|
|
172
346
|
{
|
|
173
|
-
if (UnityCliActiveOperation.RetryExactTerminalCleanup(Scope)) return;
|
|
174
|
-
var active =
|
|
175
|
-
if (active == null) return;
|
|
347
|
+
if (UnityCliActiveOperation.RetryExactTerminalCleanup(Scope, state)) return;
|
|
348
|
+
var active = state.LoadOperation(Scope);
|
|
349
|
+
if (active == null) { RecoverFromBuildAdmissionMarker(state); return; }
|
|
176
350
|
var requestId = Value(active, "requestId");
|
|
177
351
|
var requestDigest = Value(active, "requestDigest");
|
|
178
352
|
object terminal = null;
|
|
179
353
|
var hasTerminal = IsSafeId(requestId) && IsSha256(requestDigest)
|
|
180
|
-
&&
|
|
354
|
+
&& state.TryGetTerminal(Scope, requestId, requestDigest, out terminal);
|
|
181
355
|
if (!hasTerminal)
|
|
182
356
|
{
|
|
183
357
|
object pending;
|
|
@@ -187,43 +361,112 @@ namespace UnityCli
|
|
|
187
361
|
pending = UnknownLeaseTerminal(requestId);
|
|
188
362
|
active["phase"] = "terminal_pending";
|
|
189
363
|
active["terminalEnvelope"] = pending;
|
|
190
|
-
|
|
364
|
+
state.SaveOperation(Scope, active);
|
|
191
365
|
}
|
|
192
|
-
terminal =
|
|
366
|
+
terminal = state.StoreTerminalFirst(Scope, requestId, requestDigest, pending);
|
|
367
|
+
}
|
|
368
|
+
if (terminal != null) UnityCliActiveOperation.BeginExactTerminalCleanup(Scope, requestId, requestDigest, state);
|
|
369
|
+
}
|
|
370
|
+
catch { RecoverFromBuildAdmissionMarker(state); }
|
|
371
|
+
}
|
|
372
|
+
|
|
373
|
+
/// <summary>root缺失时按完整Recovery marker与exact lease决定保守终态或无root清理。</summary>
|
|
374
|
+
private static void RecoverFromBuildAdmissionMarker(BridgeQueueState state)
|
|
375
|
+
{
|
|
376
|
+
try
|
|
377
|
+
{
|
|
378
|
+
var markerScope = Scope + "-admission-owner";
|
|
379
|
+
var marker = state.LoadOperation(markerScope);
|
|
380
|
+
if (marker == null || (UnityCliAdmissionPool.AdmissionOwnerState)AdmissionLong(marker, "admissionIntendedOwnerState") != UnityCliAdmissionPool.AdmissionOwnerState.Recovery) return;
|
|
381
|
+
var requestId = Value(marker, "requestId");
|
|
382
|
+
var topRequestDigest = Value(marker, "requestDigest");
|
|
383
|
+
var ownerRequestDigest = Value(marker, "admissionRequestDigest");
|
|
384
|
+
if (!IsSafeId(requestId) || !IsSha256(topRequestDigest) || !IsSha256(ownerRequestDigest)) return;
|
|
385
|
+
var owner = ReconcileAdmissionTransferForLiveMarker(state, markerScope, marker, requestId, ownerRequestDigest);
|
|
386
|
+
if (owner == null || !string.Equals(owner.TopRequestDigest, topRequestDigest, StringComparison.Ordinal)) return;
|
|
387
|
+
bool leaseOwned;
|
|
388
|
+
if (!state.TryIsLeaseOwned(owner.RequestId, owner.RequestDigest, out leaseOwned)) return;
|
|
389
|
+
object terminal;
|
|
390
|
+
if (!state.TryGetTerminal(Scope, requestId, topRequestDigest, out terminal))
|
|
391
|
+
{
|
|
392
|
+
var recoveryTerminal = leaseOwned
|
|
393
|
+
? ProtocolEnvelopeFactory.Error(requestId, "E_EXECUTION_TIMEOUT", "Build active root disappeared while its exact lease was retained; outcome is unknown.", null, new[] { "Inspect build artifacts before submitting another mutation." })
|
|
394
|
+
: UnknownLeaseTerminal(requestId);
|
|
395
|
+
terminal = state.StoreTerminalFirst(Scope, requestId, topRequestDigest, recoveryTerminal);
|
|
193
396
|
}
|
|
194
|
-
|
|
397
|
+
object confirmed;
|
|
398
|
+
if (terminal == null || !state.TryGetTerminal(Scope, requestId, topRequestDigest, out confirmed)
|
|
399
|
+
|| !string.Equals(UnityCliSerializer.Serialize(terminal), UnityCliSerializer.Serialize(confirmed), StringComparison.Ordinal)) return;
|
|
400
|
+
UnityCliActiveOperation.BeginExactTerminalCleanup(Scope, requestId, topRequestDigest, state);
|
|
195
401
|
}
|
|
196
402
|
catch { }
|
|
197
403
|
}
|
|
404
|
+
|
|
198
405
|
private static object UnknownLeaseTerminal(string id) { return ProtocolEnvelopeFactory.Error(id, "E_EXECUTION_TIMEOUT", "Build lost its exact mutation lease after BuildPlayer; outcome is unknown.", null, new[] { "Inspect build artifacts before submitting another mutation." }); }
|
|
199
406
|
private static string Terminal(string id, object envelope) { return UnityCliSerializer.Serialize(ProtocolEnvelopeFactory.Success(id, new Dictionary<string, object> { { "terminal", true }, { "rootEnvelope", envelope } })); }
|
|
200
407
|
private static object SerializeException(string id, Exception ex) { return ProtocolEnvelopeFactory.Error(id, "E_BRIDGE_COMMAND_FAILED", ex.Message, null, new[] { "Check Unity Console and UnityCliBridge.log." }); }
|
|
408
|
+
internal sealed class BuildEffectResult
|
|
409
|
+
{
|
|
410
|
+
internal string Result;
|
|
411
|
+
internal long TotalSize;
|
|
412
|
+
internal long TotalErrors;
|
|
413
|
+
internal long TotalWarnings;
|
|
414
|
+
internal Dictionary<string, object> Artifact;
|
|
415
|
+
internal List<object> Messages;
|
|
416
|
+
}
|
|
417
|
+
|
|
201
418
|
private static Prepared Prepare(TargetArgs input)
|
|
202
419
|
{
|
|
203
420
|
if (input == null || string.IsNullOrWhiteSpace(input.Target) || string.IsNullOrWhiteSpace(input.OutputPath)) throw new BridgeCommandException("E_SCHEMA_INVALID", "Each build target requires target and outputPath.");
|
|
204
421
|
BuildTarget target; if (!Enum.TryParse(input.Target, false, out target)) throw new BridgeCommandException("E_SCHEMA_INVALID", "Unsupported Unity BuildTarget: " + input.Target);
|
|
205
|
-
var
|
|
422
|
+
var configuredScenes = EditorBuildSettings.scenes ?? Array.Empty<EditorBuildSettingsScene>();
|
|
423
|
+
var scenes = configuredScenes.Where(x => x != null && x.enabled && File.Exists(x.path)).Select(x => x.path).ToArray();
|
|
424
|
+
if (scenes.Length == 0) throw new BridgeCommandException("E_BUILD_SCENES_EMPTY", "No enabled existing build scenes are available.");
|
|
206
425
|
var publicPath = input.OutputPath.Replace('\\', '/'); if (Path.IsPathRooted(input.OutputPath) || publicPath.Split('/').Any(x => x == "..")) throw new BridgeCommandException("E_SCHEMA_INVALID", "Build outputPath must be project-relative.");
|
|
207
426
|
var projectRoot = Path.GetFullPath(ProjectRoot()); var outputPath = Path.GetFullPath(Path.Combine(projectRoot, input.OutputPath)); if (!outputPath.StartsWith(projectRoot + Path.DirectorySeparatorChar, StringComparison.Ordinal) && !string.Equals(outputPath, projectRoot, StringComparison.Ordinal)) throw new BridgeCommandException("E_SCHEMA_INVALID", "Build outputPath escapes the project.");
|
|
208
427
|
return new Prepared { Target = target, TargetName = input.Target, OutputPath = outputPath, PublicOutputPath = publicPath, Scenes = scenes, Options = ParseOptions(input.Options) };
|
|
209
428
|
}
|
|
210
429
|
private static BuildOptions ParseOptions(List<string> values) { var result = BuildOptions.None; foreach (var value in values ?? new List<string>()) { BuildOptions option; if (string.IsNullOrWhiteSpace(value) || !Enum.TryParse(value, false, out option)) throw new BridgeCommandException("E_SCHEMA_INVALID", "Unsupported BuildOptions value: " + value); result |= option; } return result; }
|
|
211
|
-
private static Dictionary<string, object> Build(Prepared p)
|
|
430
|
+
private static Dictionary<string, object> Build(Prepared p, BuildExecutionDependencies dependencies)
|
|
431
|
+
{
|
|
432
|
+
var started = DateTimeOffset.UtcNow;
|
|
433
|
+
var parent = Path.GetDirectoryName(p.OutputPath);
|
|
434
|
+
if (!string.IsNullOrEmpty(parent)) Directory.CreateDirectory(parent);
|
|
435
|
+
var effect = dependencies.RunEffect(p);
|
|
436
|
+
return BuildResultData(p, effect, started, DateTimeOffset.UtcNow);
|
|
437
|
+
}
|
|
438
|
+
|
|
439
|
+
private static Dictionary<string, object> BuildResultData(Prepared prepared, BuildEffectResult effect, DateTimeOffset started, DateTimeOffset finished)
|
|
440
|
+
{
|
|
441
|
+
if (effect == null) throw new InvalidOperationException("Build effect returned no result.");
|
|
442
|
+
if (effect.Result == BuildResult.Succeeded.ToString() && !SuccessfulArtifactProof(effect.Artifact))
|
|
443
|
+
throw new BridgeCommandException("E_BUILD_ARTIFACT_MISSING", "BuildReport succeeded but its fresh output artifact has no non-empty SHA-256 proof.");
|
|
444
|
+
return new Dictionary<string, object>
|
|
445
|
+
{
|
|
446
|
+
{ "target", prepared.TargetName }, { "result", effect.Result }, { "outputPath", prepared.PublicOutputPath },
|
|
447
|
+
{ "totalSize", effect.TotalSize }, { "totalErrors", effect.TotalErrors }, { "totalWarnings", effect.TotalWarnings },
|
|
448
|
+
{ "startedAt", started.ToString("O", CultureInfo.InvariantCulture) }, { "finishedAt", finished.ToString("O", CultureInfo.InvariantCulture) },
|
|
449
|
+
{ "durationMs", (long)(finished - started).TotalMilliseconds }, { "messages", effect.Messages ?? new List<object>() }, { "artifact", effect.Artifact }
|
|
450
|
+
};
|
|
451
|
+
}
|
|
452
|
+
|
|
453
|
+
private static BuildEffectResult RunBuildEffect(Prepared p)
|
|
212
454
|
{
|
|
213
|
-
var
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
var
|
|
217
|
-
|
|
455
|
+
var report = BuildPipeline.BuildPlayer(p.Scenes, p.OutputPath, p.Target, p.Options);
|
|
456
|
+
if (report == null) throw new BridgeCommandException("E_BUILD_FAILED", "BuildPlayer returned no BuildReport.");
|
|
457
|
+
var artifact = ReadArtifact(p.OutputPath, p.PublicOutputPath);
|
|
458
|
+
var steps = report.steps ?? Array.Empty<BuildStep>();
|
|
459
|
+
var messages = steps.SelectMany(step => step.messages ?? Array.Empty<BuildStepMessage>()).Where(message => !string.IsNullOrWhiteSpace(message.content)).Select(message => (object)new Dictionary<string, object> { { "type", message.type.ToString() }, { "message", message.content } }).Take(100).ToList();
|
|
460
|
+
return new BuildEffectResult { Result = report.summary.result.ToString(), TotalSize = checked((long)report.summary.totalSize), TotalErrors = report.summary.totalErrors, TotalWarnings = report.summary.totalWarnings, Artifact = artifact, Messages = messages };
|
|
218
461
|
}
|
|
219
462
|
private static Dictionary<string, object> ReadArtifact(string path, string publicPath) { var roots = new List<string>(); if (File.Exists(path)) roots.Add(path); if (Directory.Exists(path)) roots.Add(path); var sidecar = Path.Combine(Path.GetDirectoryName(path) ?? string.Empty, Path.GetFileNameWithoutExtension(path) + "_Data"); if (Directory.Exists(sidecar)) roots.Add(sidecar); var files = roots.SelectMany(root => File.Exists(root) ? new[] { root } : Directory.GetFiles(root, "*", SearchOption.AllDirectories)).Distinct(StringComparer.Ordinal).OrderBy(x => x, StringComparer.Ordinal).ToArray(); var size = files.Sum(x => new FileInfo(x).Length); var treeRoot = Path.GetDirectoryName(path) ?? path; return new Dictionary<string, object> { { "outputPath", publicPath }, { "exists", files.Length > 0 }, { "hash", File.Exists(path) ? HashFile(path) : null }, { "treeHash", files.Length > 0 ? HashTree(files, treeRoot) : null }, { "fileCount", (long)files.Length }, { "size", size } }; }
|
|
220
|
-
private static bool SuccessfulArtifactProof(Dictionary<string, object> artifact) { object exists; object count; object size; object hash; object treeHash; artifact.TryGetValue("exists", out exists)
|
|
463
|
+
private static bool SuccessfulArtifactProof(Dictionary<string, object> artifact) { object exists; object count; object size; object hash; object treeHash; return artifact != null && artifact.TryGetValue("exists", out exists) && artifact.TryGetValue("fileCount", out count) && artifact.TryGetValue("size", out size) && artifact.TryGetValue("hash", out hash) && artifact.TryGetValue("treeHash", out treeHash) && exists is bool && (bool)exists && count is long && (long)count > 0 && size is long && (long)size > 0 && (IsSha256(hash as string) || IsSha256(treeHash as string)); }
|
|
221
464
|
private static string HashFile(string path) { using (var sha = SHA256.Create()) using (var stream = File.OpenRead(path)) return BitConverter.ToString(sha.ComputeHash(stream)).Replace("-", "").ToLowerInvariant(); }
|
|
222
465
|
private static string HashTree(IEnumerable<string> files, string root) { using (var sha = SHA256.Create()) return BitConverter.ToString(sha.ComputeHash(Encoding.UTF8.GetBytes(string.Join("\n", files.Select(x => Path.GetRelativePath(root, x).Replace('\\', '/') + "\0" + HashFile(x)))))).Replace("-", "").ToLowerInvariant(); }
|
|
223
466
|
private static void Validate(Args args) { if (args == null || string.IsNullOrWhiteSpace(args.ExpectedEditorSessionId) || args.Targets == null || args.Targets.Count == 0) throw new BridgeCommandException("E_SCHEMA_INVALID", "Build targets and expectedEditorSessionId are required."); if (args.Targets.Any(x => x == null || string.IsNullOrWhiteSpace(x.Target) || string.IsNullOrWhiteSpace(x.OutputPath))) throw new BridgeCommandException("E_SCHEMA_INVALID", "Each build target requires target and outputPath."); if (args.Targets.Select(x => x.Target).Distinct(StringComparer.Ordinal).Count() != args.Targets.Count) throw new BridgeCommandException("E_SCHEMA_INVALID", "Build targets must not contain duplicates."); if (args.Targets.Select(x => x.OutputPath.Replace('\\', '/')).Distinct(StringComparer.OrdinalIgnoreCase).Count() != args.Targets.Count) throw new BridgeCommandException("E_SCHEMA_INVALID", "Build output paths must not conflict."); if (!string.Equals(args.ExpectedEditorSessionId, EditorSessionId(), StringComparison.Ordinal)) throw new BridgeCommandException("E_EDITOR_SESSION_REPLACED", "The selected Editor session changed before build execution."); if (EditorApplication.isPlaying || IsPlayModeChanging()) throw new BridgeCommandException("E_TOOL_PLAYMODE_UNAVAILABLE", "build.run is editor-only and requires stable Edit Mode.", new Dictionary<string, object> { { "toolName", "build.run" }, { "playModeSupport", "editor-only" } }, new[] { "Exit Play Mode before running build.run." }); if (EditorUtility.scriptCompilationFailed) throw new BridgeCommandException("E_UNITY_COMPILE_FAILED", "Unity has unresolved script compilation errors and cannot start BuildPlayer.", "Run editor.compile and fix all diagnostics before retrying build.run."); }
|
|
224
467
|
private sealed class Args { public List<TargetArgs> Targets { get; set; } public string ExpectedEditorSessionId { get; set; } }
|
|
225
468
|
private sealed class TargetArgs { public string Target { get; set; } public string OutputPath { get; set; } public List<string> Options { get; set; } }
|
|
226
|
-
|
|
469
|
+
internal sealed class Prepared { internal BuildTarget Target; internal string TargetName; internal string OutputPath; internal string PublicOutputPath; internal string[] Scenes; internal BuildOptions Options; }
|
|
227
470
|
}
|
|
228
471
|
}
|
|
229
472
|
}
|