@alpsckr/unitycli 0.4.3 → 0.4.4
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 +122 -34
- package/dist/bridge/session-supervisor.js.map +1 -1
- 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-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 +429 -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 +24 -7
- package/dist/extensions/installer.js +142 -66
- 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 +13 -1
- package/dist/instances.js +26 -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
|
@@ -53,15 +53,20 @@ namespace UnityCli
|
|
|
53
53
|
protected override Dictionary<string, object> CreateRoot(BridgeRequest request, string digest, object args) { return null; }
|
|
54
54
|
protected override void OnTick(Dictionary<string, object> root) { }
|
|
55
55
|
protected override object BuildSuccessData(Dictionary<string, object> root) { return null; }
|
|
56
|
-
protected override IEnumerable<(string name, bool destructive)> AdditionalCommands
|
|
56
|
+
protected override IEnumerable<(string name, bool destructive, UnityCliBridgeQueuePolicy.WorkClass queueClass)> AdditionalCommands
|
|
57
57
|
{
|
|
58
|
-
get
|
|
58
|
+
get
|
|
59
|
+
{
|
|
60
|
+
yield return (CancelPlanCommand, false, UnityCliBridgeQueuePolicy.WorkClass.Control);
|
|
61
|
+
yield return (CancelCommand, true, UnityCliBridgeQueuePolicy.WorkClass.Control);
|
|
62
|
+
yield return (CancelStatusCommand, false, UnityCliBridgeQueuePolicy.WorkClass.SafeStatus);
|
|
63
|
+
}
|
|
59
64
|
}
|
|
60
65
|
internal void Initialize() { InitializeLegacy(); }
|
|
61
66
|
internal void Shutdown() { ShutdownLegacy(); }
|
|
62
67
|
internal void BeforeReload() { BeforeReloadLegacy(); }
|
|
63
68
|
internal override Task<string> Execute(BridgeRequest request, byte[] raw, Func<bool> accept, CancellationToken ct) { return LegacyExecute(request, raw, accept, ct); }
|
|
64
|
-
internal override void Tick() { LegacyTick(); }
|
|
69
|
+
internal override void Tick() { if (RetryAdmissionOwnerRecoveryMarker() || RetryCancelAdmissionOwnerMarker()) return; LegacyTick(); }
|
|
65
70
|
}
|
|
66
71
|
|
|
67
72
|
private sealed class Root { internal string RequestId; internal string RequestDigest; internal string EditorSessionId; internal DateTimeOffset AbsoluteDeadlineUtc; internal Dictionary<string, object> TestOperation; }
|
|
@@ -69,6 +74,8 @@ namespace UnityCli
|
|
|
69
74
|
{
|
|
70
75
|
internal string RootRequestId; internal string RootRequestDigest; internal string EditorSessionId; internal DateTimeOffset AbsoluteDeadlineUtc;
|
|
71
76
|
internal string RunId; internal string CancelRequestId; internal string CancelRequestDigest;
|
|
77
|
+
internal AdmissionOwnerIdentity AdmissionOwner;
|
|
78
|
+
internal BridgeQueueState QueueState;
|
|
72
79
|
}
|
|
73
80
|
private enum CancelDispatchOutcome { NotInvoked, Returned, OutcomeUnknown }
|
|
74
81
|
internal static bool IsCommand(string command) { return operation.IsCommand(command); }
|
|
@@ -195,8 +202,9 @@ namespace UnityCli
|
|
|
195
202
|
{
|
|
196
203
|
if (acceptedCancel)
|
|
197
204
|
{
|
|
198
|
-
|
|
199
|
-
|
|
205
|
+
var dispatch = ReadCancelDispatch(root);
|
|
206
|
+
if (dispatch == null || !FinalizeCancelTerminal(dispatch, ProtocolEnvelopeFactory.Error(dispatch.CancelRequestId, "E_EXECUTION_TIMEOUT", "Test cancellation outcome is unknown after the Editor session changed.", null, new[] { "Inspect test.run before starting another run or cancellation." }), "outcome_unknown")) return;
|
|
207
|
+
return;
|
|
200
208
|
}
|
|
201
209
|
Fail(root, "E_EDITOR_SESSION_REPLACED", "The selected Editor session changed before tests began."); return;
|
|
202
210
|
}
|
|
@@ -207,8 +215,9 @@ namespace UnityCli
|
|
|
207
215
|
TickCancel(root);
|
|
208
216
|
try { root = Load(); } catch { return; }
|
|
209
217
|
if (root == null) return;
|
|
210
|
-
|
|
211
|
-
|
|
218
|
+
var dispatch = ReadCancelDispatch(root);
|
|
219
|
+
if (dispatch == null || !FinalizeCancelTerminal(dispatch, ProtocolEnvelopeFactory.Error(dispatch.CancelRequestId, "E_EXECUTION_TIMEOUT", "Test cancellation did not reach a proven terminal before the deadline; outcome is unknown.", null, new[] { "Inspect test.run before starting another run or cancellation." }), "outcome_unknown")) return;
|
|
220
|
+
return;
|
|
212
221
|
}
|
|
213
222
|
RecoverAfterDeadline(root); return;
|
|
214
223
|
}
|
|
@@ -269,9 +278,9 @@ namespace UnityCli
|
|
|
269
278
|
throw new BridgeCommandException("E_REQUEST_ID_REUSED", "Test cancellation identity changed after acceptance.");
|
|
270
279
|
return CancelAcceptedData(root, runId);
|
|
271
280
|
}
|
|
272
|
-
var dispatch = new CancelDispatchIdentity { RootRequestId = root.RequestId, RootRequestDigest = root.RequestDigest, EditorSessionId = root.EditorSessionId, AbsoluteDeadlineUtc = root.AbsoluteDeadlineUtc, RunId = runId, CancelRequestId = request.RequestId, CancelRequestDigest = cancelDigest };
|
|
273
281
|
var cancelAdmissionOwner = CaptureAdmissionOwner(request.RequestId);
|
|
274
|
-
|
|
282
|
+
var dispatch = new CancelDispatchIdentity { RootRequestId = root.RequestId, RootRequestDigest = root.RequestDigest, EditorSessionId = root.EditorSessionId, AbsoluteDeadlineUtc = root.AbsoluteDeadlineUtc, RunId = runId, CancelRequestId = request.RequestId, CancelRequestDigest = cancelDigest, AdmissionOwner = cancelAdmissionOwner, QueueState = ProductionQueueState };
|
|
283
|
+
Update(root, value => { AddAdmissionOwnerFields(value.TestOperation, cancelAdmissionOwner); value.TestOperation["cancelRequested"] = true; value.TestOperation["cancelRequestId"] = dispatch.CancelRequestId; value.TestOperation["cancelRequestDigest"] = dispatch.CancelRequestDigest; value.TestOperation["cancelRootRequestDigest"] = dispatch.RootRequestDigest; value.TestOperation["cancelRunId"] = dispatch.RunId; value.TestOperation["cancelPhaseBefore"] = Text(value.TestOperation, "phase"); value.TestOperation["cancelEffectState"] = "dispatching"; value.TestOperation["cancelNeedsContinuation"] = false; });
|
|
275
284
|
bool isOwned;
|
|
276
285
|
try
|
|
277
286
|
{
|
|
@@ -282,7 +291,7 @@ namespace UnityCli
|
|
|
282
291
|
}
|
|
283
292
|
catch
|
|
284
293
|
{
|
|
285
|
-
|
|
294
|
+
FinalizeCancelTerminal(dispatch, ProtocolEnvelopeFactory.Error(dispatch.CancelRequestId, "E_EXECUTION_TIMEOUT", "Test cancellation dispatch authorization became uncertain before OnRunCancel; cancellation was not invoked.", null, new[] { "Inspect test.run before submitting another cancellation." }), "not_invoked");
|
|
286
295
|
throw new BridgeCommandException("E_EXECUTION_TIMEOUT", "Test cancellation authorization expired before its effect.", "Inspect test.run before submitting another cancellation.");
|
|
287
296
|
}
|
|
288
297
|
string reason;
|
|
@@ -292,18 +301,18 @@ namespace UnityCli
|
|
|
292
301
|
var message = outcome == CancelDispatchOutcome.OutcomeUnknown
|
|
293
302
|
? "Exact Unity Test Runner cancellation may have occurred but its return state is unknown."
|
|
294
303
|
: "Exact Unity Test Runner cancellation was not invoked: " + reason + ".";
|
|
295
|
-
|
|
304
|
+
FinalizeCancelTerminal(dispatch, ProtocolEnvelopeFactory.Error(dispatch.CancelRequestId, "E_EXECUTION_TIMEOUT", message, null, new[] { "Inspect test.run state before deciding whether to submit another cancellation." }), outcome == CancelDispatchOutcome.OutcomeUnknown ? "outcome_unknown" : "not_invoked");
|
|
296
305
|
throw new BridgeCommandException("E_EXECUTION_TIMEOUT", message, "Inspect test.run state before deciding whether to submit another cancellation.");
|
|
297
306
|
}
|
|
298
307
|
try
|
|
299
308
|
{
|
|
300
309
|
root = Required();
|
|
301
310
|
if (!MatchesCancelDispatch(root, dispatch)) throw new BridgeCommandException("E_EXECUTION_TIMEOUT", "Test cancellation root changed after OnRunCancel.");
|
|
302
|
-
Update(root, value => value.TestOperation["cancelEffectState"] = "dispatched");
|
|
311
|
+
Update(root, value => { value.TestOperation["cancelEffectState"] = "dispatched"; value.TestOperation["cancelNeedsContinuation"] = true; });
|
|
303
312
|
}
|
|
304
313
|
catch
|
|
305
314
|
{
|
|
306
|
-
|
|
315
|
+
FinalizeCancelTerminal(dispatch, ProtocolEnvelopeFactory.Error(dispatch.CancelRequestId, "E_EXECUTION_TIMEOUT", "Test cancellation occurred but its dispatched state could not be durably proven.", null, new[] { "Inspect test.run before submitting another cancellation." }), "outcome_unknown");
|
|
307
316
|
throw new BridgeCommandException("E_EXECUTION_TIMEOUT", "Test cancellation outcome is unknown after OnRunCancel.", "Inspect test.run before submitting another cancellation.");
|
|
308
317
|
}
|
|
309
318
|
return CancelAcceptedData(root, runId);
|
|
@@ -346,9 +355,24 @@ namespace UnityCli
|
|
|
346
355
|
private static void TickCancel(Root root)
|
|
347
356
|
{
|
|
348
357
|
var effectState = Text(root.TestOperation, "cancelEffectState");
|
|
358
|
+
if (Same(effectState, "cancelled"))
|
|
359
|
+
{
|
|
360
|
+
var dispatch = ReadCancelDispatch(root);
|
|
361
|
+
object terminal;
|
|
362
|
+
if (dispatch != null && TryReadCancelTerminalProof(ProductionQueueState, dispatch.CancelRequestId, dispatch.CancelRequestDigest, dispatch.RootRequestDigest, out terminal))
|
|
363
|
+
FinalizeCancelTerminal(dispatch, terminal, "cancelled");
|
|
364
|
+
return;
|
|
365
|
+
}
|
|
349
366
|
if (Same(effectState, "dispatching"))
|
|
350
367
|
{
|
|
351
|
-
|
|
368
|
+
var dispatch = ReadCancelDispatch(root);
|
|
369
|
+
if (dispatch != null) FinalizeCancelTerminal(dispatch, ProtocolEnvelopeFactory.Error(dispatch.CancelRequestId, "E_EXECUTION_TIMEOUT", "Test cancellation return state could not be durably confirmed; the cancellation effect may have occurred.", null, new[] { "Inspect test.run before starting another run or cancellation." }), "outcome_unknown");
|
|
370
|
+
return;
|
|
371
|
+
}
|
|
372
|
+
if (Same(effectState, "outcome_unknown"))
|
|
373
|
+
{
|
|
374
|
+
var dispatch = ReadCancelDispatch(root);
|
|
375
|
+
if (dispatch != null) FinalizeCancelTerminal(dispatch, ProtocolEnvelopeFactory.Error(dispatch.CancelRequestId, "E_EXECUTION_TIMEOUT", "Test cancellation outcome is unknown after dispatch.", null, new[] { "Inspect test.run before starting another run or cancellation." }), "outcome_unknown");
|
|
352
376
|
return;
|
|
353
377
|
}
|
|
354
378
|
if (!Same(effectState, "dispatched")) return;
|
|
@@ -359,71 +383,425 @@ namespace UnityCli
|
|
|
359
383
|
|
|
360
384
|
/// <summary>校验dispatch后重读root仍与effect前冻结的完整身份和selector一致。</summary>
|
|
361
385
|
private static bool MatchesCancelDispatch(Root root, CancelDispatchIdentity dispatch)
|
|
386
|
+
{
|
|
387
|
+
return MatchesCancelIdentity(root, dispatch)
|
|
388
|
+
&& Same(Text(root.TestOperation, "cancelEffectState"), "dispatching");
|
|
389
|
+
}
|
|
390
|
+
|
|
391
|
+
private static bool MatchesCancelIdentity(Root root, CancelDispatchIdentity dispatch)
|
|
362
392
|
{
|
|
363
393
|
return root != null && Same(root.RequestId, dispatch.RootRequestId) && Same(root.RequestDigest, dispatch.RootRequestDigest)
|
|
364
394
|
&& Same(root.EditorSessionId, dispatch.EditorSessionId) && root.AbsoluteDeadlineUtc == dispatch.AbsoluteDeadlineUtc
|
|
365
395
|
&& Same(Text(root.TestOperation, "runId"), dispatch.RunId) && Same(Text(root.TestOperation, "cancelRunId"), dispatch.RunId)
|
|
366
396
|
&& Same(Text(root.TestOperation, "cancelRequestId"), dispatch.CancelRequestId)
|
|
367
397
|
&& Same(Text(root.TestOperation, "cancelRequestDigest"), dispatch.CancelRequestDigest)
|
|
368
|
-
&& Same(Text(root.TestOperation, "cancelRootRequestDigest"), dispatch.RootRequestDigest)
|
|
369
|
-
&& Same(Text(root.TestOperation, "cancelEffectState"), "dispatching");
|
|
398
|
+
&& Same(Text(root.TestOperation, "cancelRootRequestDigest"), dispatch.RootRequestDigest);
|
|
370
399
|
}
|
|
371
400
|
|
|
372
|
-
/// <summary>
|
|
373
|
-
private static bool
|
|
401
|
+
/// <summary>child terminal与完整恢复marker先于parent Finish持久化,避免父cleanup删除唯一重建身份。</summary>
|
|
402
|
+
private static bool FinalizeCancelTerminal(CancelDispatchIdentity dispatch, object envelope, string effectState)
|
|
374
403
|
{
|
|
375
|
-
|
|
404
|
+
if (dispatch == null || dispatch.AdmissionOwner == null) return false;
|
|
405
|
+
var queueState = dispatch.QueueState ?? ProductionQueueState;
|
|
406
|
+
if (!FreezeCancelRecoveryCandidate(queueState, dispatch, envelope, effectState)) return false;
|
|
407
|
+
object first;
|
|
408
|
+
try { first = queueState.StoreTerminalFirst(CancelTerminalScope, dispatch.CancelRequestId, dispatch.CancelRequestDigest, dispatch.RootRequestDigest, envelope); }
|
|
409
|
+
catch { RetainCancelAdmissionForRecovery(dispatch, envelope, effectState); return false; }
|
|
410
|
+
// parent Finish可能同步删除test-run root;此前必须已有完整Recovery/Continuation marker。
|
|
411
|
+
if (!RetainCancelAdmissionForRecovery(dispatch, first, effectState)) return false;
|
|
412
|
+
Root root;
|
|
413
|
+
try { root = Load(queueState); }
|
|
414
|
+
catch { return false; }
|
|
415
|
+
var parentAlreadyFinalized = root == null && CancelParentTerminalMatches(dispatch.RootRequestId, dispatch.RootRequestDigest, effectState, queueState);
|
|
416
|
+
if (!parentAlreadyFinalized && !MatchesCancelIdentity(root, dispatch)) return false;
|
|
417
|
+
if (!parentAlreadyFinalized)
|
|
376
418
|
{
|
|
377
|
-
var terminal = ProtocolEnvelopeFactory.Error(dispatch.CancelRequestId, "E_EXECUTION_TIMEOUT", message, null, new[] { "Inspect the exact test.run business state before starting another run or cancellation." });
|
|
378
|
-
UnityCliActiveOperation.StoreTerminalFirst(CancelTerminalScope, dispatch.CancelRequestId, dispatch.CancelRequestDigest, dispatch.RootRequestDigest, terminal);
|
|
379
419
|
try
|
|
380
420
|
{
|
|
381
|
-
|
|
382
|
-
|
|
421
|
+
ApplyCancelParentTerminal(root.TestOperation, effectState, first);
|
|
422
|
+
Save(queueState, root);
|
|
423
|
+
FinishCancelParentIfRequired(queueState, root, effectState, first);
|
|
424
|
+
}
|
|
425
|
+
catch
|
|
426
|
+
{
|
|
427
|
+
if (!CancelParentTerminalMatches(dispatch.RootRequestId, dispatch.RootRequestDigest, effectState, queueState)) return false;
|
|
428
|
+
}
|
|
429
|
+
}
|
|
430
|
+
if (!CancelParentTerminalMatches(dispatch.RootRequestId, dispatch.RootRequestDigest, effectState, queueState)
|
|
431
|
+
&& (effectState == "cancelled" || effectState == "outcome_unknown")) return false;
|
|
432
|
+
try
|
|
433
|
+
{
|
|
434
|
+
var owner = CaptureAdmissionOwner(queueState, dispatch.CancelRequestId, dispatch.CancelRequestDigest);
|
|
435
|
+
owner.TopRequestDigest = dispatch.RootRequestDigest;
|
|
436
|
+
if (owner.OwnerState != UnityCliAdmissionPool.AdmissionOwnerState.WorkItem
|
|
437
|
+
&& owner.OwnerState != UnityCliAdmissionPool.AdmissionOwnerState.Recovery
|
|
438
|
+
&& owner.OwnerState != UnityCliAdmissionPool.AdmissionOwnerState.Continuation
|
|
439
|
+
&& owner.OwnerState != UnityCliAdmissionPool.AdmissionOwnerState.TerminalCleanup) return false;
|
|
440
|
+
var completionMarker = CancelAdmissionMarker(dispatch, owner, first, effectState, false);
|
|
441
|
+
if (owner.OwnerState == UnityCliAdmissionPool.AdmissionOwnerState.WorkItem
|
|
442
|
+
|| owner.OwnerState == UnityCliAdmissionPool.AdmissionOwnerState.Recovery)
|
|
443
|
+
owner = PersistAdmissionOwnerTransfer(
|
|
444
|
+
queueState,
|
|
445
|
+
CancelTerminalScope + "-admission-owner",
|
|
446
|
+
completionMarker,
|
|
447
|
+
owner,
|
|
448
|
+
UnityCliAdmissionPool.AdmissionOwnerState.TerminalCleanup);
|
|
449
|
+
else
|
|
450
|
+
{
|
|
451
|
+
var existingMarker = queueState.LoadOperation(CancelTerminalScope + "-admission-owner");
|
|
452
|
+
if (!CopyCommittedAdmissionOwnerFields(existingMarker, completionMarker, owner, dispatch.RootRequestDigest)) return false;
|
|
453
|
+
queueState.SaveOperation(CancelTerminalScope + "-admission-owner", completionMarker);
|
|
454
|
+
if (!queueState.PersistPool()) return false;
|
|
455
|
+
}
|
|
456
|
+
// Continuation本身是legal terminal owner;completion失败时保留exact marker与intent供Tick重试。
|
|
457
|
+
if (!CompleteAdmissionRoot(queueState, owner)) return false;
|
|
458
|
+
return true;
|
|
459
|
+
}
|
|
460
|
+
catch { return false; }
|
|
461
|
+
}
|
|
462
|
+
|
|
463
|
+
internal static bool FinalizeCancelTerminalForTests(BridgeQueueState state, string rootRequestId, string rootRequestDigest, string runId, string cancelRequestId, string cancelRequestDigest, object envelope, string effectState)
|
|
464
|
+
{
|
|
465
|
+
if (state == null || state.IsolatedExecution == null) throw new ArgumentException("Cancel finalization test state must be isolated.", "state");
|
|
466
|
+
var root = Load(state);
|
|
467
|
+
if (root == null) throw new InvalidOperationException("Cancel finalization test root is missing.");
|
|
468
|
+
var owner = CaptureAdmissionOwner(state, cancelRequestId, cancelRequestDigest);
|
|
469
|
+
return FinalizeCancelTerminal(new CancelDispatchIdentity
|
|
470
|
+
{
|
|
471
|
+
RootRequestId = rootRequestId,
|
|
472
|
+
RootRequestDigest = rootRequestDigest,
|
|
473
|
+
EditorSessionId = root.EditorSessionId,
|
|
474
|
+
AbsoluteDeadlineUtc = root.AbsoluteDeadlineUtc,
|
|
475
|
+
RunId = runId,
|
|
476
|
+
CancelRequestId = cancelRequestId,
|
|
477
|
+
CancelRequestDigest = cancelRequestDigest,
|
|
478
|
+
AdmissionOwner = owner,
|
|
479
|
+
QueueState = state
|
|
480
|
+
}, envelope, effectState);
|
|
481
|
+
}
|
|
482
|
+
|
|
483
|
+
/// <summary>仍存活的WorkItem冻结双持久化失败所需候选;已转移owner无需本地副本。</summary>
|
|
484
|
+
private static bool FreezeCancelRecoveryCandidate(BridgeQueueState state, CancelDispatchIdentity dispatch, object envelope, string effectState)
|
|
485
|
+
{
|
|
486
|
+
if (!CancelTerminalEffectState(effectState) || !CancelTerminalCandidateIsValid(envelope, dispatch.CancelRequestId)) return false;
|
|
487
|
+
BridgeWorkItem item;
|
|
488
|
+
lock (state.QueueLock)
|
|
489
|
+
{
|
|
490
|
+
if (!state.ActiveRequestWork.TryGetValue(dispatch.CancelRequestId, out item)) return true;
|
|
491
|
+
if (!string.Equals(item.RequestDigest, dispatch.CancelRequestDigest, StringComparison.Ordinal)) return false;
|
|
492
|
+
}
|
|
493
|
+
try
|
|
494
|
+
{
|
|
495
|
+
item.FreezeCancelRecoveryCandidate(dispatch.RootRequestId, dispatch.RootRequestDigest, dispatch.RunId, effectState, envelope);
|
|
496
|
+
return true;
|
|
497
|
+
}
|
|
498
|
+
catch { return false; }
|
|
499
|
+
}
|
|
500
|
+
|
|
501
|
+
/// <summary>parent Finish前持久化完整候选并推进Recovery,任何后续失败都禁止queue误完成cancel owner。</summary>
|
|
502
|
+
private static bool RetainCancelAdmissionForRecovery(CancelDispatchIdentity dispatch, object envelope, string effectState)
|
|
503
|
+
{
|
|
504
|
+
try
|
|
505
|
+
{
|
|
506
|
+
var owner = CaptureAdmissionOwner(dispatch.QueueState ?? ProductionQueueState, dispatch.CancelRequestId, dispatch.CancelRequestDigest);
|
|
507
|
+
owner.TopRequestDigest = dispatch.RootRequestDigest;
|
|
508
|
+
if (owner.OwnerState != UnityCliAdmissionPool.AdmissionOwnerState.WorkItem
|
|
509
|
+
&& owner.OwnerState != UnityCliAdmissionPool.AdmissionOwnerState.Recovery
|
|
510
|
+
&& owner.OwnerState != UnityCliAdmissionPool.AdmissionOwnerState.Continuation
|
|
511
|
+
&& owner.OwnerState != UnityCliAdmissionPool.AdmissionOwnerState.TerminalCleanup) return false;
|
|
512
|
+
var state = dispatch.QueueState ?? ProductionQueueState;
|
|
513
|
+
var marker = CancelAdmissionMarker(dispatch, owner, envelope, effectState, true);
|
|
514
|
+
if (owner.OwnerState == UnityCliAdmissionPool.AdmissionOwnerState.WorkItem)
|
|
515
|
+
PersistAdmissionOwnerTransfer(state, CancelTerminalScope + "-admission-owner", marker, owner,
|
|
516
|
+
UnityCliAdmissionPool.AdmissionOwnerState.Recovery);
|
|
517
|
+
else
|
|
518
|
+
{
|
|
519
|
+
var existingMarker = state.LoadOperation(CancelTerminalScope + "-admission-owner");
|
|
520
|
+
if (!CopyCommittedAdmissionOwnerFields(existingMarker, marker, owner, dispatch.RootRequestDigest)) return false;
|
|
521
|
+
state.SaveOperation(CancelTerminalScope + "-admission-owner", marker);
|
|
522
|
+
if (!state.PersistPool()) return false;
|
|
523
|
+
}
|
|
524
|
+
return true;
|
|
525
|
+
}
|
|
526
|
+
catch { return false; }
|
|
527
|
+
}
|
|
528
|
+
|
|
529
|
+
private static Dictionary<string, object> CancelAdmissionMarker(CancelDispatchIdentity dispatch, AdmissionOwnerIdentity owner, object envelope, string effectState, bool parentRepairPending)
|
|
530
|
+
{
|
|
531
|
+
if (!CancelTerminalEffectState(effectState) || !CancelTerminalCandidateIsValid(envelope, dispatch.CancelRequestId))
|
|
532
|
+
throw new BridgeCommandException("E_EXECUTION_TIMEOUT", "Cancel recovery marker terminal candidate is invalid.");
|
|
533
|
+
return new Dictionary<string, object>
|
|
534
|
+
{
|
|
535
|
+
{ "requestId", owner.RequestId }, { "requestDigest", dispatch.RootRequestDigest },
|
|
536
|
+
{ "rootRequestId", dispatch.RootRequestId }, { "rootRequestDigest", dispatch.RootRequestDigest },
|
|
537
|
+
{ "runId", dispatch.RunId }, { "editorSessionId", dispatch.EditorSessionId },
|
|
538
|
+
{ "cancelRequestId", dispatch.CancelRequestId }, { "cancelRequestDigest", dispatch.CancelRequestDigest },
|
|
539
|
+
{ "cancelContinuationState", "continuation_pending" }, { "cancelTerminalEnvelope", envelope },
|
|
540
|
+
{ "parentRepairEffectState", effectState }, { "parentRepairPending", parentRepairPending }
|
|
541
|
+
};
|
|
542
|
+
}
|
|
543
|
+
|
|
544
|
+
private static void ApplyCancelParentTerminal(Dictionary<string, object> operation, string effectState, object terminal)
|
|
545
|
+
{
|
|
546
|
+
operation["cancelEffectState"] = effectState;
|
|
547
|
+
operation["cancelNeedsContinuation"] = effectState != "not_invoked";
|
|
548
|
+
operation["cancelRequested"] = effectState != "not_invoked";
|
|
549
|
+
operation["cancelTerminalEnvelope"] = terminal;
|
|
550
|
+
if (effectState != "not_invoked") return;
|
|
551
|
+
foreach (var key in new[] { "cancelRequestId", "cancelRequestDigest", "cancelRootRequestDigest", "cancelRunId", "cancelNeedsContinuation", "admissionRootFingerprint", "admissionToken", "admissionSessionId", "admissionListenerId", "admissionListenerGeneration", "admissionExecutionDeadlineMs", "admissionRequestDigest", "admissionOwnerState", "admissionIntendedOwnerState", "admissionTransferCommitted" })
|
|
552
|
+
operation.Remove(key);
|
|
553
|
+
}
|
|
554
|
+
|
|
555
|
+
/// <summary>cancel恢复分别校验父root/lease与cancel terminal;任何mismatch只保留marker,不阻塞整个pool。</summary>
|
|
556
|
+
private static bool RetryCancelAdmissionOwnerMarker()
|
|
557
|
+
{
|
|
558
|
+
return RetryCancelAdmissionOwnerMarker(ProductionQueueState);
|
|
559
|
+
}
|
|
560
|
+
|
|
561
|
+
internal static bool RetryCancelAdmissionOwnerMarkerForTests(BridgeQueueState state)
|
|
562
|
+
{
|
|
563
|
+
if (state == null || state.IsolatedExecution == null) throw new ArgumentException("Cancel recovery test state must be isolated.", "state");
|
|
564
|
+
return RetryCancelAdmissionOwnerMarker(state);
|
|
565
|
+
}
|
|
566
|
+
|
|
567
|
+
private static bool RetryCancelAdmissionOwnerMarker(BridgeQueueState state)
|
|
568
|
+
{
|
|
569
|
+
var markerScope = CancelTerminalScope + "-admission-owner";
|
|
570
|
+
Dictionary<string, object> marker;
|
|
571
|
+
try { marker = state.LoadOperation(markerScope); }
|
|
572
|
+
catch { return true; }
|
|
573
|
+
if (marker == null) return false;
|
|
574
|
+
var cancelRequestId = Text(marker, "requestId");
|
|
575
|
+
var cancelRequestDigest = Text(marker, "admissionRequestDigest");
|
|
576
|
+
var rootRequestId = Text(marker, "rootRequestId");
|
|
577
|
+
var rootRequestDigest = Text(marker, "rootRequestDigest");
|
|
578
|
+
var runId = Text(marker, "runId");
|
|
579
|
+
string continuationState;
|
|
580
|
+
string repairEffectState;
|
|
581
|
+
object candidateEnvelope;
|
|
582
|
+
if (!IsSafeId(cancelRequestId) || !IsSha256(cancelRequestDigest)
|
|
583
|
+
|| !IsSafeId(rootRequestId) || !IsSha256(rootRequestDigest) || !Guid.TryParse(runId, out _)
|
|
584
|
+
|| !Same(Text(marker, "requestDigest"), rootRequestDigest)
|
|
585
|
+
|| !Same(Text(marker, "editorSessionId"), EditorSessionId())
|
|
586
|
+
|| !TryReadCancelAdmissionMarkerState(marker, cancelRequestId, cancelRequestDigest, rootRequestDigest, runId,
|
|
587
|
+
out continuationState, out repairEffectState, out _, out candidateEnvelope)) return true;
|
|
588
|
+
AdmissionOwnerIdentity markerOwner;
|
|
589
|
+
try { markerOwner = ReadAdmissionOwnerFields(marker, cancelRequestId); }
|
|
590
|
+
catch { return true; }
|
|
591
|
+
if (!AdmissionMarkerHasImmutableIdentity(marker, markerOwner, rootRequestDigest)) return true;
|
|
592
|
+
markerOwner.TopRequestDigest = rootRequestDigest;
|
|
593
|
+
var pool = state.AdmissionPool;
|
|
594
|
+
if (pool == null) return true;
|
|
595
|
+
|
|
596
|
+
object cancelTerminal = null;
|
|
597
|
+
if (Same(continuationState, "continuation_pending"))
|
|
598
|
+
{
|
|
599
|
+
if (!TryReadCancelTerminalProof(state, cancelRequestId, cancelRequestDigest, rootRequestDigest, out cancelTerminal))
|
|
600
|
+
{
|
|
601
|
+
try
|
|
383
602
|
{
|
|
384
|
-
|
|
385
|
-
current.TestOperation["cancelEffectState"] = effectState;
|
|
386
|
-
Save(current);
|
|
603
|
+
state.StoreTerminalFirst(CancelTerminalScope, cancelRequestId, cancelRequestDigest, rootRequestDigest, candidateEnvelope);
|
|
387
604
|
}
|
|
605
|
+
catch { return true; }
|
|
606
|
+
if (!TryReadCancelTerminalProof(state, cancelRequestId, cancelRequestDigest, rootRequestDigest, out cancelTerminal)) return true;
|
|
388
607
|
}
|
|
389
|
-
|
|
608
|
+
if (!RepairCancelParentFromMarker(state, rootRequestId, rootRequestDigest, cancelRequestId,
|
|
609
|
+
cancelRequestDigest, runId, repairEffectState, cancelTerminal)) return true;
|
|
610
|
+
marker["parentRepairPending"] = false;
|
|
611
|
+
}
|
|
612
|
+
else if (!DispatchedCancelParentMatches(state, rootRequestId, rootRequestDigest, cancelRequestId, cancelRequestDigest, runId))
|
|
613
|
+
{
|
|
390
614
|
return true;
|
|
391
615
|
}
|
|
616
|
+
|
|
617
|
+
var exact = pool.InspectExactIdentityFields(ToPoolIdentity(markerOwner));
|
|
618
|
+
if (exact == UnityCliAdmissionPool.ExactIdentityOutcome.IdentityMismatchOrBlocked) return true;
|
|
619
|
+
if (exact == UnityCliAdmissionPool.ExactIdentityOutcome.DefinitelyAbsent)
|
|
620
|
+
{
|
|
621
|
+
if (HasAdmissionCompletionIntent(state, markerOwner))
|
|
622
|
+
{
|
|
623
|
+
if (!Same(continuationState, "continuation_pending")) return true;
|
|
624
|
+
try
|
|
625
|
+
{
|
|
626
|
+
if (!state.PersistPool() || !state.ClearMarkers(markerOwner)
|
|
627
|
+
|| !ClearAdmissionCompletionIntent(state, markerOwner)) return true;
|
|
628
|
+
return false;
|
|
629
|
+
}
|
|
630
|
+
catch { return true; }
|
|
631
|
+
}
|
|
632
|
+
var intendedRestore = (UnityCliAdmissionPool.AdmissionOwnerState)AdmissionLong(marker, "admissionIntendedOwnerState");
|
|
633
|
+
if (!pool.RestoreConsumed(ToPoolIdentity(markerOwner), intendedRestore, AdmissionBool(marker, "admissionTransferCommitted"))) return true;
|
|
634
|
+
try { if (!state.PersistPool()) return true; }
|
|
635
|
+
catch { return true; }
|
|
636
|
+
}
|
|
637
|
+
AdmissionOwnerIdentity owner;
|
|
638
|
+
try
|
|
639
|
+
{
|
|
640
|
+
owner = CaptureAdmissionOwner(state, cancelRequestId, cancelRequestDigest);
|
|
641
|
+
owner.TopRequestDigest = rootRequestDigest;
|
|
642
|
+
var intended = (UnityCliAdmissionPool.AdmissionOwnerState)AdmissionLong(marker, "admissionIntendedOwnerState");
|
|
643
|
+
if (owner.OwnerState != intended)
|
|
644
|
+
owner = PersistAdmissionOwnerTransfer(state, markerScope, marker, owner, intended);
|
|
645
|
+
else
|
|
646
|
+
{
|
|
647
|
+
marker["admissionTransferCommitted"] = true;
|
|
648
|
+
state.SaveOperation(markerScope, marker);
|
|
649
|
+
if (!state.PersistPool()) return true;
|
|
650
|
+
}
|
|
651
|
+
if (Same(continuationState, "dispatched"))
|
|
652
|
+
return owner.OwnerState != UnityCliAdmissionPool.AdmissionOwnerState.Continuation;
|
|
653
|
+
if (owner.OwnerState == UnityCliAdmissionPool.AdmissionOwnerState.WorkItem
|
|
654
|
+
|| owner.OwnerState == UnityCliAdmissionPool.AdmissionOwnerState.Recovery)
|
|
655
|
+
owner = PersistAdmissionOwnerTransfer(state, markerScope, marker, owner, UnityCliAdmissionPool.AdmissionOwnerState.TerminalCleanup);
|
|
656
|
+
if (owner.OwnerState != UnityCliAdmissionPool.AdmissionOwnerState.Continuation
|
|
657
|
+
&& owner.OwnerState != UnityCliAdmissionPool.AdmissionOwnerState.TerminalCleanup) return true;
|
|
658
|
+
return !CompleteAdmissionRoot(state, owner);
|
|
659
|
+
}
|
|
660
|
+
catch { return true; }
|
|
661
|
+
}
|
|
662
|
+
|
|
663
|
+
/// <summary>dispatched marker只恢复owner,不要求尚未生成的terminal;LegacyTick继续观察TestRunner。</summary>
|
|
664
|
+
private static bool DispatchedCancelParentMatches(BridgeQueueState state, string rootRequestId, string rootRequestDigest, string cancelRequestId, string cancelRequestDigest, string runId)
|
|
665
|
+
{
|
|
666
|
+
bool leaseOwned;
|
|
667
|
+
if (!state.TryIsLeaseOwned(rootRequestId, rootRequestDigest, out leaseOwned) || !leaseOwned) return false;
|
|
668
|
+
Root root;
|
|
669
|
+
try { root = Load(state); }
|
|
392
670
|
catch { return false; }
|
|
671
|
+
return root != null && Same(root.RequestId, rootRequestId) && Same(root.RequestDigest, rootRequestDigest)
|
|
672
|
+
&& Same(root.EditorSessionId, EditorSessionId()) && Same(Text(root.TestOperation, "runId"), runId)
|
|
673
|
+
&& Same(Text(root.TestOperation, "cancelRunId"), runId)
|
|
674
|
+
&& Same(Text(root.TestOperation, "cancelRequestId"), cancelRequestId)
|
|
675
|
+
&& Same(Text(root.TestOperation, "cancelRequestDigest"), cancelRequestDigest)
|
|
676
|
+
&& Same(Text(root.TestOperation, "cancelRootRequestDigest"), rootRequestDigest)
|
|
677
|
+
&& Same(Text(root.TestOperation, "cancelEffectState"), "dispatched")
|
|
678
|
+
&& Bool(root.TestOperation, "cancelRequested") && Bool(root.TestOperation, "cancelNeedsContinuation");
|
|
393
679
|
}
|
|
394
680
|
|
|
395
|
-
|
|
396
|
-
private static bool TryFreezeCancelOutcomeUnknown(Root root, string message)
|
|
681
|
+
private static bool TryReadCancelTerminalProof(BridgeQueueState state, string cancelRequestId, string cancelRequestDigest, string rootRequestDigest, out object terminal)
|
|
397
682
|
{
|
|
398
|
-
|
|
399
|
-
var cancelDigest = Text(root.TestOperation, "cancelRequestDigest");
|
|
400
|
-
if (!IsSafeId(cancelRequestId) || !IsSha256(cancelDigest) || !Same(Text(root.TestOperation, "cancelRootRequestDigest"), root.RequestDigest))
|
|
401
|
-
return false;
|
|
683
|
+
terminal = null;
|
|
402
684
|
try
|
|
403
685
|
{
|
|
404
|
-
|
|
405
|
-
|
|
406
|
-
|
|
686
|
+
object exact;
|
|
687
|
+
object selected;
|
|
688
|
+
if (!state.TryGetTerminal(CancelTerminalScope, cancelRequestId, cancelRequestDigest, out exact)
|
|
689
|
+
|| !state.TryGetTerminalBySelector(CancelTerminalScope, cancelRequestId, rootRequestDigest, out selected)
|
|
690
|
+
|| !string.Equals(UnityCliSerializer.Serialize(exact), UnityCliSerializer.Serialize(selected), StringComparison.Ordinal)) return false;
|
|
691
|
+
terminal = exact;
|
|
407
692
|
return true;
|
|
408
693
|
}
|
|
409
694
|
catch { return false; }
|
|
410
695
|
}
|
|
411
696
|
|
|
697
|
+
/// <summary>cancel terminal存在后先幂等修复父root;重读未证明目标state前绝不释放cancel owner。</summary>
|
|
698
|
+
private static bool RepairCancelParentFromMarker(BridgeQueueState state, string rootRequestId, string rootRequestDigest, string cancelRequestId, string cancelRequestDigest, string runId, string effectState, object cancelTerminal)
|
|
699
|
+
{
|
|
700
|
+
bool parentLeaseOwned;
|
|
701
|
+
if (!state.TryIsLeaseOwned(rootRequestId, rootRequestDigest, out parentLeaseOwned)) return false;
|
|
702
|
+
Root root;
|
|
703
|
+
try { root = Load(state); }
|
|
704
|
+
catch { return false; }
|
|
705
|
+
object parentTerminal;
|
|
706
|
+
var parentTerminalExists = false;
|
|
707
|
+
try { parentTerminalExists = state.TryGetTerminal(Scope, rootRequestId, rootRequestDigest, out parentTerminal); }
|
|
708
|
+
catch { return false; }
|
|
709
|
+
if (root == null) return CancelParentTerminalMatches(rootRequestId, rootRequestDigest, effectState, state);
|
|
710
|
+
if (!Same(root.RequestId, rootRequestId) || !Same(root.RequestDigest, rootRequestDigest)
|
|
711
|
+
|| !Same(root.EditorSessionId, EditorSessionId()) || (!parentLeaseOwned && !parentTerminalExists)
|
|
712
|
+
|| !Same(Text(root.TestOperation, "runId"), runId)) return false;
|
|
713
|
+
if (CancelParentRepairMatches(root, cancelRequestId, cancelRequestDigest, rootRequestDigest, runId, effectState, cancelTerminal))
|
|
714
|
+
{
|
|
715
|
+
if (effectState != "cancelled" && effectState != "outcome_unknown") return true;
|
|
716
|
+
if (CancelParentTerminalMatches(rootRequestId, rootRequestDigest, effectState, state)) return true;
|
|
717
|
+
try { FinishCancelParentIfRequired(state, root, effectState, cancelTerminal); }
|
|
718
|
+
catch { }
|
|
719
|
+
return CancelParentTerminalMatches(rootRequestId, rootRequestDigest, effectState, state);
|
|
720
|
+
}
|
|
721
|
+
if (!Same(Text(root.TestOperation, "cancelRequestId"), cancelRequestId)
|
|
722
|
+
|| !Same(Text(root.TestOperation, "cancelRequestDigest"), cancelRequestDigest)
|
|
723
|
+
|| !Same(Text(root.TestOperation, "cancelRootRequestDigest"), rootRequestDigest)
|
|
724
|
+
|| !Same(Text(root.TestOperation, "cancelRunId"), runId)) return false;
|
|
725
|
+
try
|
|
726
|
+
{
|
|
727
|
+
ApplyCancelParentTerminal(root.TestOperation, effectState, cancelTerminal);
|
|
728
|
+
Save(state, root);
|
|
729
|
+
FinishCancelParentIfRequired(state, root, effectState, cancelTerminal);
|
|
730
|
+
root = Load(state);
|
|
731
|
+
if (root == null) return CancelParentTerminalMatches(rootRequestId, rootRequestDigest, effectState, state);
|
|
732
|
+
return CancelParentRepairMatches(root, cancelRequestId, cancelRequestDigest, rootRequestDigest, runId, effectState, cancelTerminal)
|
|
733
|
+
&& ((effectState != "cancelled" && effectState != "outcome_unknown")
|
|
734
|
+
|| CancelParentTerminalMatches(rootRequestId, rootRequestDigest, effectState, state));
|
|
735
|
+
}
|
|
736
|
+
catch { return CancelParentTerminalMatches(rootRequestId, rootRequestDigest, effectState, state); }
|
|
737
|
+
}
|
|
738
|
+
|
|
739
|
+
private static bool CancelParentRepairMatches(Root root, string cancelRequestId, string cancelRequestDigest, string rootRequestDigest, string runId, string effectState, object cancelTerminal)
|
|
740
|
+
{
|
|
741
|
+
object storedTerminal;
|
|
742
|
+
if (root == null || !Same(Text(root.TestOperation, "cancelEffectState"), effectState)
|
|
743
|
+
|| Bool(root.TestOperation, "cancelRequested") != (effectState != "not_invoked")
|
|
744
|
+
|| !root.TestOperation.TryGetValue("cancelTerminalEnvelope", out storedTerminal)
|
|
745
|
+
|| !string.Equals(UnityCliSerializer.Serialize(storedTerminal), UnityCliSerializer.Serialize(cancelTerminal), StringComparison.Ordinal)) return false;
|
|
746
|
+
if (effectState == "not_invoked") return string.IsNullOrEmpty(Text(root.TestOperation, "cancelRequestId"));
|
|
747
|
+
return Same(Text(root.TestOperation, "cancelRequestId"), cancelRequestId)
|
|
748
|
+
&& Same(Text(root.TestOperation, "cancelRequestDigest"), cancelRequestDigest)
|
|
749
|
+
&& Same(Text(root.TestOperation, "cancelRootRequestDigest"), rootRequestDigest)
|
|
750
|
+
&& Same(Text(root.TestOperation, "cancelRunId"), runId);
|
|
751
|
+
}
|
|
752
|
+
|
|
753
|
+
private static void FinishCancelParentIfRequired(BridgeQueueState state, Root root, string effectState, object cancelTerminal)
|
|
754
|
+
{
|
|
755
|
+
if (effectState == "outcome_unknown")
|
|
756
|
+
{
|
|
757
|
+
Finish(state, root, ProtocolEnvelopeFactory.Error(root.RequestId, "E_EXECUTION_TIMEOUT", "Test cancellation may have occurred but its exact effect could not be proven.", null, new[] { "Inspect the Unity Test Runner before submitting another mutation." }));
|
|
758
|
+
return;
|
|
759
|
+
}
|
|
760
|
+
if (effectState == "cancelled")
|
|
761
|
+
Finish(state, root, ProtocolEnvelopeFactory.Error(root.RequestId, "E_TEST_RUN_CANCELLED", "The exact tracked Unity test run was cancelled.", CancelTerminalData(cancelTerminal), new[] { "Inspect the test.cancel proof before starting another test run." }));
|
|
762
|
+
}
|
|
763
|
+
|
|
764
|
+
private static bool CancelParentTerminalMatches(string rootRequestId, string rootRequestDigest, string effectState, BridgeQueueState state)
|
|
765
|
+
{
|
|
766
|
+
if (effectState != "cancelled" && effectState != "outcome_unknown") return true;
|
|
767
|
+
try
|
|
768
|
+
{
|
|
769
|
+
object terminal;
|
|
770
|
+
if (!state.TryGetTerminal(Scope, rootRequestId, rootRequestDigest, out terminal)) return false;
|
|
771
|
+
var parsed = UnityCliSerializer.Parse(UnityCliSerializer.Serialize(terminal)) as Dictionary<string, object>;
|
|
772
|
+
object okValue;
|
|
773
|
+
object errorValue;
|
|
774
|
+
var error = parsed != null && parsed.TryGetValue("error", out errorValue) ? errorValue as Dictionary<string, object> : null;
|
|
775
|
+
return parsed != null && parsed.TryGetValue("ok", out okValue) && okValue is bool && !(bool)okValue
|
|
776
|
+
&& error != null && Same(Text(error, "code"), effectState == "cancelled" ? "E_TEST_RUN_CANCELLED" : "E_EXECUTION_TIMEOUT");
|
|
777
|
+
}
|
|
778
|
+
catch { return false; }
|
|
779
|
+
}
|
|
780
|
+
|
|
781
|
+
private static CancelDispatchIdentity ReadCancelDispatch(Root root)
|
|
782
|
+
{
|
|
783
|
+
if (root == null || root.TestOperation == null) return null;
|
|
784
|
+
var id = Text(root.TestOperation, "cancelRequestId");
|
|
785
|
+
var digest = Text(root.TestOperation, "cancelRequestDigest");
|
|
786
|
+
var runId = Text(root.TestOperation, "cancelRunId");
|
|
787
|
+
if (!IsSafeId(id) || !IsSha256(digest) || !Guid.TryParse(runId, out _)
|
|
788
|
+
|| !Same(Text(root.TestOperation, "cancelRootRequestDigest"), root.RequestDigest)) return null;
|
|
789
|
+
AdmissionOwnerIdentity owner;
|
|
790
|
+
try { owner = CaptureAdmissionOwner(id, digest); } catch { return null; }
|
|
791
|
+
return new CancelDispatchIdentity { RootRequestId = root.RequestId, RootRequestDigest = root.RequestDigest, EditorSessionId = root.EditorSessionId, AbsoluteDeadlineUtc = root.AbsoluteDeadlineUtc, RunId = runId, CancelRequestId = id, CancelRequestDigest = digest, AdmissionOwner = owner };
|
|
792
|
+
}
|
|
793
|
+
|
|
412
794
|
private static void FinishCancelled(Root root)
|
|
413
795
|
{
|
|
414
796
|
string[] ids; string reason;
|
|
415
797
|
if (!TryReadActiveRunIds(out ids, out reason)) ids = new string[0];
|
|
416
798
|
var data = CancelData(root, true, false, ids);
|
|
417
|
-
|
|
418
|
-
|
|
419
|
-
if (!
|
|
420
|
-
|
|
421
|
-
|
|
422
|
-
var cancelEnvelope = ProtocolEnvelopeFactory.Success(cancelTerminalRequestId, data);
|
|
423
|
-
UnityCliActiveOperation.StoreTerminalFirst(CancelTerminalScope, cancelTerminalRequestId, cancelDigest, root.RequestDigest, cancelEnvelope);
|
|
424
|
-
CompleteAdmissionRoot(ReadAdmissionOwnerFields(root.TestOperation, cancelTerminalRequestId));
|
|
799
|
+
var dispatch = ReadCancelDispatch(root);
|
|
800
|
+
if (dispatch == null) throw new BridgeCommandException("E_EXECUTION_TIMEOUT", "Test cancellation terminal identity is incomplete; outcome is unknown.");
|
|
801
|
+
if (!FinalizeCancelTerminal(dispatch, ProtocolEnvelopeFactory.Success(dispatch.CancelRequestId, data), "cancelled"))
|
|
802
|
+
throw new BridgeCommandException("E_EXECUTION_TIMEOUT", "Test cancellation continuation owner could not be finalized.");
|
|
803
|
+
cancelTerminalRequestId = dispatch.CancelRequestId;
|
|
425
804
|
cancelTerminalData = data;
|
|
426
|
-
Finish(root, ProtocolEnvelopeFactory.Error(root.RequestId, "E_TEST_RUN_CANCELLED", "The exact tracked Unity test run was cancelled.", data, new[] { "Inspect the test.cancel proof before starting another test run." }));
|
|
427
805
|
}
|
|
428
806
|
|
|
429
807
|
private static Dictionary<string, object> CancelAcceptedData(Root root, string runId)
|
|
@@ -511,13 +889,15 @@ namespace UnityCli
|
|
|
511
889
|
private static object ResultEnvelope(Root root, ITestResultAdaptor result) { var data = CaptureResultData(root, result); object artifactFailed; if (data.TryGetValue("artifactWriteFailed", out artifactFailed) && artifactFailed is bool && (bool)artifactFailed) { data.Remove("artifactWriteFailed"); return ProtocolEnvelopeFactory.Error(root.RequestId, "E_TEST_ARTIFACT_WRITE_FAILED", "RunFinished was proven but its NUnit XML artifact could not be written.", data, new[] { "Inspect the returned test summary and verify the UnityCli data directory is writable." }); } var failed = result.FailCount; var count = result.PassCount + result.FailCount + result.SkipCount + result.InconclusiveCount; return count == 0 ? (object)ProtocolEnvelopeFactory.Error(root.RequestId, "E_TESTS_NOT_FOUND", "The requested filters matched no Unity tests.", data, new[] { "Inspect the available test names and relax the test filters." }) : failed > 0 ? (object)ProtocolEnvelopeFactory.Error(root.RequestId, "E_TESTS_FAILED", "One or more Unity tests failed.", data, new[] { "Inspect failures and the optional NUnit XML artifact." }) : ProtocolEnvelopeFactory.Success(root.RequestId, data); }
|
|
512
890
|
private static Dictionary<string, object> CaptureResultData(Root root, ITestResultAdaptor result) { var summary = new Dictionary<string, object> { { "platform", Text(root.TestOperation, "platform") }, { "status", result.FailCount == 0 ? "passed" : "failed" }, { "testCount", (long)(result.PassCount + result.FailCount + result.SkipCount + result.InconclusiveCount) }, { "passed", (long)result.PassCount }, { "failed", (long)result.FailCount }, { "skipped", (long)result.SkipCount }, { "inconclusive", (long)result.InconclusiveCount }, { "duration", result.Duration }, { "startedAt", result.StartTime.ToUniversalTime().ToString("O", CultureInfo.InvariantCulture) }, { "finishedAt", result.EndTime.ToUniversalTime().ToString("O", CultureInfo.InvariantCulture) } }; var data = new Dictionary<string, object> { { "summary", summary }, { "failures", Failures(result).Cast<object>().ToList() } }; if (Bool(root.TestOperation, "xml")) { try { data["xml"] = WriteXml(root, result); } catch { data["artifactWriteFailed"] = true; } } return data; }
|
|
513
891
|
private static Root Required() { var root = Load(); if (root == null) throw new BridgeCommandException("E_REQUEST_NOT_FOUND", "Test active operation was not found."); return root; }
|
|
514
|
-
private static Root Load()
|
|
892
|
+
private static Root Load() { return Load(ProductionQueueState); }
|
|
893
|
+
private static Root Load(BridgeQueueState state)
|
|
515
894
|
{
|
|
516
|
-
try { var
|
|
895
|
+
try { var value = state.LoadOperation(Scope); return value == null ? null : Parse(value); }
|
|
517
896
|
catch (BridgeCommandException) { throw; }
|
|
518
897
|
catch (Exception exception) { throw new BridgeCommandException("E_EXECUTION_TIMEOUT", "Test active state cannot be read; outcome is unknown: " + exception.GetType().Name + "."); }
|
|
519
898
|
}
|
|
520
|
-
private static void Save(Root root) {
|
|
899
|
+
private static void Save(Root root) { Save(ProductionQueueState, root); }
|
|
900
|
+
private static void Save(BridgeQueueState state, Root root) { state.SaveOperation(Scope, Data(root)); }
|
|
521
901
|
private static void Update(Root root, Action<Root> change)
|
|
522
902
|
{
|
|
523
903
|
var current = Required();
|
|
@@ -527,17 +907,23 @@ namespace UnityCli
|
|
|
527
907
|
change(current);
|
|
528
908
|
Save(current);
|
|
529
909
|
}
|
|
530
|
-
private static void Finish(Root root, object envelope)
|
|
910
|
+
private static void Finish(Root root, object envelope) { Finish(ProductionQueueState, root, envelope); }
|
|
911
|
+
private static void Finish(BridgeQueueState state, Root root, object envelope)
|
|
531
912
|
{
|
|
532
913
|
bool isOwned;
|
|
533
|
-
if (!
|
|
914
|
+
if (!state.TryIsLeaseOwned(root.RequestId, root.RequestDigest, out isOwned) || !isOwned)
|
|
534
915
|
envelope = ProtocolEnvelopeFactory.Error(root.RequestId, "E_EXECUTION_TIMEOUT", "Test run lost its exact mutation lease after effect; outcome is unknown.", null, new[] { "Inspect the Unity Test Runner before submitting another mutation." });
|
|
535
916
|
root.TestOperation["phase"] = "terminal_pending";
|
|
536
917
|
root.TestOperation["terminalEnvelope"] = envelope;
|
|
537
|
-
Save(root);
|
|
538
|
-
var first =
|
|
539
|
-
|
|
540
|
-
|
|
918
|
+
Save(state, root);
|
|
919
|
+
var first = state.StoreTerminalFirst(Scope, root.RequestId, root.RequestDigest, envelope);
|
|
920
|
+
if (object.ReferenceEquals(state, ProductionQueueState))
|
|
921
|
+
{
|
|
922
|
+
terminalRequestId = root.RequestId;
|
|
923
|
+
terminalRequestDigest = root.RequestDigest;
|
|
924
|
+
terminalEnvelope = first;
|
|
925
|
+
}
|
|
926
|
+
UnityCliActiveOperation.BeginExactTerminalCleanup(Scope, root.RequestId, root.RequestDigest, state);
|
|
541
927
|
}
|
|
542
928
|
private static void RecoverTerminalCleanup()
|
|
543
929
|
{
|