@alpsckr/unitycli 0.4.2 → 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 +35 -42
- 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
|
@@ -0,0 +1,672 @@
|
|
|
1
|
+
#if UNITY_EDITOR
|
|
2
|
+
using System;
|
|
3
|
+
using System.Collections.Generic;
|
|
4
|
+
using System.Linq;
|
|
5
|
+
using System.Threading;
|
|
6
|
+
|
|
7
|
+
namespace UnityCli
|
|
8
|
+
{
|
|
9
|
+
/// <summary>一次Bridge队列实例的全部可变状态;production与测试状态永不互换。</summary>
|
|
10
|
+
internal sealed class BridgeQueueState
|
|
11
|
+
{
|
|
12
|
+
internal readonly object QueueLock = new object();
|
|
13
|
+
private readonly object SettlementLock = new object();
|
|
14
|
+
internal readonly LinkedList<UnityCliBridge.BridgeWorkItem> WorkQueue = new LinkedList<UnityCliBridge.BridgeWorkItem>();
|
|
15
|
+
internal readonly LinkedList<UnityCliBridge.BridgeWorkItem> SafeStatusQueue = new LinkedList<UnityCliBridge.BridgeWorkItem>();
|
|
16
|
+
internal readonly LinkedList<UnityCliBridge.BridgeWorkItem> ControlQueue = new LinkedList<UnityCliBridge.BridgeWorkItem>();
|
|
17
|
+
internal LinkedListNode<UnityCliBridge.BridgeWorkItem> ControlScanCursor;
|
|
18
|
+
internal readonly HashSet<UnityCliBridge.BridgeWorkItem> RunningWork = new HashSet<UnityCliBridge.BridgeWorkItem>();
|
|
19
|
+
internal readonly HashSet<UnityCliBridge.BridgeWorkItem> PendingSettlementWork = new HashSet<UnityCliBridge.BridgeWorkItem>();
|
|
20
|
+
internal readonly Dictionary<string, UnityCliBridge.BridgeWorkItem> ActiveRequestWork = new Dictionary<string, UnityCliBridge.BridgeWorkItem>(StringComparer.Ordinal);
|
|
21
|
+
internal UnityCliAdmissionPool AdmissionPool;
|
|
22
|
+
internal bool QueuePublicationOpen;
|
|
23
|
+
internal bool QueueSessionStopping;
|
|
24
|
+
internal string ListenerId;
|
|
25
|
+
internal long ListenerGeneration;
|
|
26
|
+
internal bool AdmissionPoolShutdownPending;
|
|
27
|
+
internal readonly BridgeQueueSinks Sinks;
|
|
28
|
+
internal readonly BridgeQueueTestHooks TestHooks;
|
|
29
|
+
internal readonly BridgeIsolatedExecutionState IsolatedExecution;
|
|
30
|
+
private readonly Func<long> monotonicNowMs;
|
|
31
|
+
private readonly Func<bool> persistPoolState;
|
|
32
|
+
private readonly Func<UnityCliBridge.AdmissionOwnerIdentity, bool> persistCompletionIntent;
|
|
33
|
+
private readonly Func<UnityCliBridge.AdmissionOwnerIdentity, bool> hasCompletionIntent;
|
|
34
|
+
private readonly Func<UnityCliBridge.AdmissionOwnerIdentity, bool> clearCompletionIntent;
|
|
35
|
+
private readonly Dictionary<string, PendingCompletionIntent> pendingCompletionIntents = new Dictionary<string, PendingCompletionIntent>(StringComparer.Ordinal);
|
|
36
|
+
private int ioCallbackCount;
|
|
37
|
+
private int lastQueueNodesExamined;
|
|
38
|
+
private int lastFifoNodesExamined;
|
|
39
|
+
private int lastControlNodesExamined;
|
|
40
|
+
private int lastSafeStatusNodesExamined;
|
|
41
|
+
internal int IoCallbackCount { get { return Volatile.Read(ref ioCallbackCount); } }
|
|
42
|
+
internal int LastQueueNodesExamined { get { return Volatile.Read(ref lastQueueNodesExamined); } }
|
|
43
|
+
internal int LastFifoNodesExamined { get { return Volatile.Read(ref lastFifoNodesExamined); } }
|
|
44
|
+
internal int LastControlNodesExamined { get { return Volatile.Read(ref lastControlNodesExamined); } }
|
|
45
|
+
internal int LastSafeStatusNodesExamined { get { return Volatile.Read(ref lastSafeStatusNodesExamined); } }
|
|
46
|
+
|
|
47
|
+
internal BridgeQueueState(
|
|
48
|
+
UnityCliAdmissionPool admissionPool,
|
|
49
|
+
Func<long> monotonicNowMs,
|
|
50
|
+
BridgeQueueSinks sinks,
|
|
51
|
+
BridgeQueueTestHooks testHooks,
|
|
52
|
+
Func<bool> persistPoolState,
|
|
53
|
+
Func<UnityCliBridge.AdmissionOwnerIdentity, bool> persistCompletionIntent,
|
|
54
|
+
Func<UnityCliBridge.AdmissionOwnerIdentity, bool> hasCompletionIntent,
|
|
55
|
+
Func<UnityCliBridge.AdmissionOwnerIdentity, bool> clearCompletionIntent,
|
|
56
|
+
BridgeIsolatedExecutionState isolatedExecution)
|
|
57
|
+
{
|
|
58
|
+
if (sinks == null || testHooks == null || persistPoolState == null || persistCompletionIntent == null
|
|
59
|
+
|| hasCompletionIntent == null || clearCompletionIntent == null)
|
|
60
|
+
throw new ArgumentNullException("BridgeQueueState dependencies must be explicit.");
|
|
61
|
+
AdmissionPool = admissionPool;
|
|
62
|
+
this.monotonicNowMs = monotonicNowMs ?? DefaultMonotonicMilliseconds;
|
|
63
|
+
Sinks = sinks;
|
|
64
|
+
TestHooks = testHooks;
|
|
65
|
+
this.persistPoolState = persistPoolState;
|
|
66
|
+
this.persistCompletionIntent = persistCompletionIntent;
|
|
67
|
+
this.hasCompletionIntent = hasCompletionIntent;
|
|
68
|
+
this.clearCompletionIntent = clearCompletionIntent;
|
|
69
|
+
IsolatedExecution = isolatedExecution;
|
|
70
|
+
ListenerGeneration = 1;
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
internal long NowMs()
|
|
74
|
+
{
|
|
75
|
+
return monotonicNowMs();
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
internal bool PersistPool()
|
|
79
|
+
{
|
|
80
|
+
AssertIoOutsideQueueLock();
|
|
81
|
+
TestHooks.Hit("before-state-persist-pool");
|
|
82
|
+
Interlocked.Increment(ref ioCallbackCount);
|
|
83
|
+
return persistPoolState();
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
internal bool ClearMarkers(UnityCliBridge.AdmissionOwnerIdentity identity)
|
|
87
|
+
{
|
|
88
|
+
AssertIoOutsideQueueLock();
|
|
89
|
+
TestHooks.Hit("before-state-clear-markers");
|
|
90
|
+
Interlocked.Increment(ref ioCallbackCount);
|
|
91
|
+
return UnityCliBridge.ClearAdmissionOwnerMarkersForState(this, identity);
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
internal bool PersistIntent(UnityCliBridge.AdmissionOwnerIdentity identity)
|
|
95
|
+
{
|
|
96
|
+
AssertIoOutsideQueueLock();
|
|
97
|
+
if (!CanTrackCompletionIntent(identity)) return false;
|
|
98
|
+
TestHooks.Hit("before-state-persist-intent");
|
|
99
|
+
Interlocked.Increment(ref ioCallbackCount);
|
|
100
|
+
var persisted = persistCompletionIntent(identity);
|
|
101
|
+
if (persisted) TrackCompletionIntent(identity);
|
|
102
|
+
return persisted;
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
internal bool HasIntent(UnityCliBridge.AdmissionOwnerIdentity identity)
|
|
106
|
+
{
|
|
107
|
+
if (HasIntentInMemory(identity)) return true;
|
|
108
|
+
AssertIoOutsideQueueLock();
|
|
109
|
+
TestHooks.Hit("before-state-has-intent");
|
|
110
|
+
Interlocked.Increment(ref ioCallbackCount);
|
|
111
|
+
var exists = hasCompletionIntent(identity);
|
|
112
|
+
if (exists) TrackCompletionIntent(identity);
|
|
113
|
+
return exists;
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
internal bool HasIntentInMemory(UnityCliBridge.AdmissionOwnerIdentity identity)
|
|
117
|
+
{
|
|
118
|
+
if (identity == null) return false;
|
|
119
|
+
lock (SettlementLock)
|
|
120
|
+
{
|
|
121
|
+
PendingCompletionIntent pending;
|
|
122
|
+
return pendingCompletionIntents.TryGetValue(IntentKey(identity), out pending) && pending.IntentPersisted;
|
|
123
|
+
}
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
/// <summary>同一requestId与不可变请求字节在旧owner补偿完成前不得绑定到任何新WorkItem。</summary>
|
|
127
|
+
internal bool HasCompensationTombstone(string requestId, string requestDigest)
|
|
128
|
+
{
|
|
129
|
+
if (string.IsNullOrEmpty(requestId) || string.IsNullOrEmpty(requestDigest)) return false;
|
|
130
|
+
lock (SettlementLock)
|
|
131
|
+
{
|
|
132
|
+
return pendingCompletionIntents.Values.Any(pending => pending.Compensation
|
|
133
|
+
&& string.Equals(pending.Owner.RequestId, requestId, StringComparison.Ordinal)
|
|
134
|
+
&& string.Equals(pending.Owner.RequestDigest, requestDigest, StringComparison.Ordinal));
|
|
135
|
+
}
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
internal bool ClearIntent(UnityCliBridge.AdmissionOwnerIdentity identity)
|
|
139
|
+
{
|
|
140
|
+
AssertIoOutsideQueueLock();
|
|
141
|
+
TestHooks.Hit("before-state-clear-intent");
|
|
142
|
+
Interlocked.Increment(ref ioCallbackCount);
|
|
143
|
+
var cleared = clearCompletionIntent(identity);
|
|
144
|
+
if (cleared)
|
|
145
|
+
{
|
|
146
|
+
lock (SettlementLock) pendingCompletionIntents.Remove(IntentKey(identity));
|
|
147
|
+
}
|
|
148
|
+
return cleared;
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
private bool CanTrackCompletionIntent(UnityCliBridge.AdmissionOwnerIdentity identity)
|
|
152
|
+
{
|
|
153
|
+
if (identity == null) return false;
|
|
154
|
+
var key = IntentKey(identity);
|
|
155
|
+
lock (SettlementLock) return pendingCompletionIntents.ContainsKey(key) || pendingCompletionIntents.Count < 256;
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
internal void TrackCompletionIntent(UnityCliBridge.AdmissionOwnerIdentity identity)
|
|
159
|
+
{
|
|
160
|
+
TrackIntent(identity, false, true);
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
/// <summary>publication失败后先登记内存continuation,再尝试首次durable intent写入。</summary>
|
|
164
|
+
internal void TrackCompensationContinuation(UnityCliBridge.AdmissionOwnerIdentity identity)
|
|
165
|
+
{
|
|
166
|
+
TrackIntent(identity, true, false);
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
private void TrackIntent(UnityCliBridge.AdmissionOwnerIdentity identity, bool compensation, bool persisted)
|
|
170
|
+
{
|
|
171
|
+
if (identity == null) throw new ArgumentNullException("identity");
|
|
172
|
+
var key = IntentKey(identity);
|
|
173
|
+
lock (SettlementLock)
|
|
174
|
+
{
|
|
175
|
+
PendingCompletionIntent current;
|
|
176
|
+
if (pendingCompletionIntents.TryGetValue(key, out current))
|
|
177
|
+
{
|
|
178
|
+
if (compensation) current.Compensation = true;
|
|
179
|
+
if (persisted) current.IntentPersisted = true;
|
|
180
|
+
return;
|
|
181
|
+
}
|
|
182
|
+
if (pendingCompletionIntents.Count >= 256) throw new InvalidOperationException("Admission completion intent journal reached its fixed bound.");
|
|
183
|
+
pendingCompletionIntents.Add(key, new PendingCompletionIntent
|
|
184
|
+
{
|
|
185
|
+
Owner = CloneIdentity(identity), Compensation = compensation, IntentPersisted = persisted
|
|
186
|
+
});
|
|
187
|
+
}
|
|
188
|
+
}
|
|
189
|
+
|
|
190
|
+
internal PendingCompletionIntent[] DueCompletionIntents(long nowMs, int limit)
|
|
191
|
+
{
|
|
192
|
+
lock (SettlementLock)
|
|
193
|
+
{
|
|
194
|
+
return pendingCompletionIntents.Values.Where(value => value.NextRetryAtMs <= nowMs)
|
|
195
|
+
.OrderBy(value => value.Owner.RequestId, StringComparer.Ordinal).Take(Math.Max(0, limit)).ToArray();
|
|
196
|
+
}
|
|
197
|
+
}
|
|
198
|
+
|
|
199
|
+
internal void DeferCompletionIntent(PendingCompletionIntent intent, long nowMs)
|
|
200
|
+
{
|
|
201
|
+
if (intent == null) return;
|
|
202
|
+
lock (SettlementLock)
|
|
203
|
+
{
|
|
204
|
+
PendingCompletionIntent current;
|
|
205
|
+
if (!pendingCompletionIntents.TryGetValue(IntentKey(intent.Owner), out current) || !object.ReferenceEquals(current, intent)) return;
|
|
206
|
+
current.NextRetryAtMs = checked(nowMs + 100L);
|
|
207
|
+
}
|
|
208
|
+
}
|
|
209
|
+
|
|
210
|
+
internal void MarkCompletionIntentFailureLogged(PendingCompletionIntent intent)
|
|
211
|
+
{
|
|
212
|
+
if (intent == null) return;
|
|
213
|
+
lock (SettlementLock) intent.FailureLogged = true;
|
|
214
|
+
}
|
|
215
|
+
|
|
216
|
+
internal bool DeferTrackedCompletionIntent(UnityCliBridge.AdmissionOwnerIdentity identity, long nowMs)
|
|
217
|
+
{
|
|
218
|
+
if (identity == null) return false;
|
|
219
|
+
lock (SettlementLock)
|
|
220
|
+
{
|
|
221
|
+
PendingCompletionIntent pending;
|
|
222
|
+
if (!pendingCompletionIntents.TryGetValue(IntentKey(identity), out pending)) return false;
|
|
223
|
+
pending.NextRetryAtMs = checked(nowMs + 100L);
|
|
224
|
+
if (pending.FailureLogged) return false;
|
|
225
|
+
pending.FailureLogged = true;
|
|
226
|
+
return true;
|
|
227
|
+
}
|
|
228
|
+
}
|
|
229
|
+
|
|
230
|
+
internal int PendingCompletionIntentCount
|
|
231
|
+
{
|
|
232
|
+
get { lock (SettlementLock) return pendingCompletionIntents.Count; }
|
|
233
|
+
}
|
|
234
|
+
|
|
235
|
+
internal Dictionary<string, object> LoadOperation(string scope)
|
|
236
|
+
{
|
|
237
|
+
AssertIoOutsideQueueLock();
|
|
238
|
+
TestHooks.Hit("before-operation-load:" + scope);
|
|
239
|
+
Interlocked.Increment(ref ioCallbackCount);
|
|
240
|
+
return IsolatedExecution == null ? UnityCliActiveOperation.Load(scope) : IsolatedExecution.Load(scope);
|
|
241
|
+
}
|
|
242
|
+
|
|
243
|
+
internal void SaveOperation(string scope, Dictionary<string, object> value)
|
|
244
|
+
{
|
|
245
|
+
AssertIoOutsideQueueLock();
|
|
246
|
+
TestHooks.Hit("before-operation-save:" + scope);
|
|
247
|
+
Interlocked.Increment(ref ioCallbackCount);
|
|
248
|
+
if (IsolatedExecution == null) UnityCliActiveOperation.Save(scope, value);
|
|
249
|
+
else IsolatedExecution.Save(scope, value);
|
|
250
|
+
}
|
|
251
|
+
|
|
252
|
+
internal void ClearOperation(string scope)
|
|
253
|
+
{
|
|
254
|
+
AssertIoOutsideQueueLock();
|
|
255
|
+
TestHooks.Hit("before-operation-clear:" + scope);
|
|
256
|
+
Interlocked.Increment(ref ioCallbackCount);
|
|
257
|
+
if (IsolatedExecution == null) UnityCliActiveOperation.Clear(scope);
|
|
258
|
+
else IsolatedExecution.Clear(scope);
|
|
259
|
+
}
|
|
260
|
+
|
|
261
|
+
internal bool OperationExists(string scope)
|
|
262
|
+
{
|
|
263
|
+
AssertIoOutsideQueueLock();
|
|
264
|
+
Interlocked.Increment(ref ioCallbackCount);
|
|
265
|
+
return IsolatedExecution == null ? UnityCliActiveOperation.Exists(scope) : IsolatedExecution.Exists(scope);
|
|
266
|
+
}
|
|
267
|
+
|
|
268
|
+
internal bool TryGetTerminal(string scope, string requestId, string requestDigest, out object envelope)
|
|
269
|
+
{
|
|
270
|
+
AssertIoOutsideQueueLock();
|
|
271
|
+
Interlocked.Increment(ref ioCallbackCount);
|
|
272
|
+
return IsolatedExecution == null
|
|
273
|
+
? UnityCliActiveOperation.TryGetTerminal(scope, requestId, requestDigest, out envelope)
|
|
274
|
+
: IsolatedExecution.TryGetTerminal(scope, requestId, requestDigest, out envelope);
|
|
275
|
+
}
|
|
276
|
+
|
|
277
|
+
internal object StoreTerminalFirst(string scope, string requestId, string requestDigest, object envelope)
|
|
278
|
+
{
|
|
279
|
+
return StoreTerminalFirst(scope, requestId, requestDigest, null, envelope);
|
|
280
|
+
}
|
|
281
|
+
|
|
282
|
+
internal object StoreTerminalFirst(string scope, string requestId, string requestDigest, string selectorDigest, object envelope)
|
|
283
|
+
{
|
|
284
|
+
return StoreTerminalFirst(scope, requestId, requestDigest, selectorDigest, null, envelope);
|
|
285
|
+
}
|
|
286
|
+
|
|
287
|
+
internal object StoreTerminalFirst(string scope, string requestId, string requestDigest, string selectorDigest, string statusDomain, object envelope)
|
|
288
|
+
{
|
|
289
|
+
AssertIoOutsideQueueLock();
|
|
290
|
+
TestHooks.Hit("before-terminal-store:" + scope);
|
|
291
|
+
Interlocked.Increment(ref ioCallbackCount);
|
|
292
|
+
return IsolatedExecution == null
|
|
293
|
+
? UnityCliActiveOperation.StoreTerminalFirst(scope, requestId, requestDigest, selectorDigest, statusDomain, envelope)
|
|
294
|
+
: IsolatedExecution.StoreTerminalFirst(scope, requestId, requestDigest, selectorDigest, statusDomain, envelope);
|
|
295
|
+
}
|
|
296
|
+
|
|
297
|
+
internal bool TryGetTerminalBySelector(string scope, string requestId, string selectorDigest, out object envelope)
|
|
298
|
+
{
|
|
299
|
+
AssertIoOutsideQueueLock();
|
|
300
|
+
Interlocked.Increment(ref ioCallbackCount);
|
|
301
|
+
return IsolatedExecution == null
|
|
302
|
+
? UnityCliActiveOperation.TryGetTerminalBySelector(scope, requestId, selectorDigest, out envelope)
|
|
303
|
+
: IsolatedExecution.TryGetTerminalBySelector(scope, requestId, selectorDigest, out envelope);
|
|
304
|
+
}
|
|
305
|
+
|
|
306
|
+
internal bool TryAcquireLease(string requestId, string requestDigest, out bool newlyAcquired)
|
|
307
|
+
{
|
|
308
|
+
AssertIoOutsideQueueLock();
|
|
309
|
+
Interlocked.Increment(ref ioCallbackCount);
|
|
310
|
+
return IsolatedExecution == null
|
|
311
|
+
? UnityCliBridge.UnityCliSessionMutationLease.TryAcquire(requestId, requestDigest, out newlyAcquired)
|
|
312
|
+
: IsolatedExecution.TryAcquireLease(requestId, requestDigest, out newlyAcquired);
|
|
313
|
+
}
|
|
314
|
+
|
|
315
|
+
internal bool TryRecoverLease(string requestId, string requestDigest, out bool newlyAcquired)
|
|
316
|
+
{
|
|
317
|
+
AssertIoOutsideQueueLock();
|
|
318
|
+
Interlocked.Increment(ref ioCallbackCount);
|
|
319
|
+
return IsolatedExecution == null
|
|
320
|
+
? UnityCliBridge.UnityCliSessionMutationLease.TryRecoverExact(requestId, requestDigest, out newlyAcquired)
|
|
321
|
+
: IsolatedExecution.TryAcquireLease(requestId, requestDigest, out newlyAcquired);
|
|
322
|
+
}
|
|
323
|
+
|
|
324
|
+
internal void ReleaseLease(string requestId, string requestDigest)
|
|
325
|
+
{
|
|
326
|
+
AssertIoOutsideQueueLock();
|
|
327
|
+
Interlocked.Increment(ref ioCallbackCount);
|
|
328
|
+
if (IsolatedExecution == null) UnityCliBridge.UnityCliSessionMutationLease.Release(requestId, requestDigest);
|
|
329
|
+
else IsolatedExecution.ReleaseLease(requestId, requestDigest);
|
|
330
|
+
}
|
|
331
|
+
|
|
332
|
+
internal bool TryIsLeaseOwned(string requestId, string requestDigest, out bool isOwned)
|
|
333
|
+
{
|
|
334
|
+
AssertIoOutsideQueueLock();
|
|
335
|
+
Interlocked.Increment(ref ioCallbackCount);
|
|
336
|
+
return IsolatedExecution == null
|
|
337
|
+
? UnityCliBridge.UnityCliSessionMutationLease.TryIsOwnedBy(requestId, requestDigest, out isOwned)
|
|
338
|
+
: IsolatedExecution.TryIsLeaseOwned(requestId, requestDigest, out isOwned);
|
|
339
|
+
}
|
|
340
|
+
|
|
341
|
+
internal bool TryGetCurrentLeaseOwner(out string requestId, out string requestDigest)
|
|
342
|
+
{
|
|
343
|
+
AssertIoOutsideQueueLock();
|
|
344
|
+
Interlocked.Increment(ref ioCallbackCount);
|
|
345
|
+
return IsolatedExecution == null
|
|
346
|
+
? UnityCliBridge.UnityCliSessionMutationLease.TryGetCurrentOwner(out requestId, out requestDigest)
|
|
347
|
+
: IsolatedExecution.TryGetCurrentOwner(out requestId, out requestDigest);
|
|
348
|
+
}
|
|
349
|
+
|
|
350
|
+
internal void RecordQueueNodesExamined(int safeStatusCount, int controlCount, int fifoCount)
|
|
351
|
+
{
|
|
352
|
+
if (safeStatusCount < 0 || safeStatusCount > UnityCliBridgeQueuePolicy.MaxSafeStatusNodesExaminedPerTick
|
|
353
|
+
|| controlCount < 0 || controlCount > UnityCliBridgeQueuePolicy.MaxControlNodesExaminedPerTick
|
|
354
|
+
|| fifoCount < 0 || fifoCount > UnityCliBridgeQueuePolicy.MaxFifoNodesExaminedPerTick)
|
|
355
|
+
throw new InvalidOperationException("Bridge queue lane scan exceeded its fixed production bound.");
|
|
356
|
+
var total = checked(safeStatusCount + controlCount + fifoCount);
|
|
357
|
+
if (total > UnityCliBridgeQueuePolicy.MaxNodesExaminedPerTick)
|
|
358
|
+
throw new InvalidOperationException("Bridge queue scan exceeded its fixed total production bound.");
|
|
359
|
+
Volatile.Write(ref lastSafeStatusNodesExamined, safeStatusCount);
|
|
360
|
+
Volatile.Write(ref lastControlNodesExamined, controlCount);
|
|
361
|
+
Volatile.Write(ref lastFifoNodesExamined, fifoCount);
|
|
362
|
+
Volatile.Write(ref lastQueueNodesExamined, total);
|
|
363
|
+
}
|
|
364
|
+
|
|
365
|
+
internal void AssertEmptyForTests()
|
|
366
|
+
{
|
|
367
|
+
lock (QueueLock)
|
|
368
|
+
{
|
|
369
|
+
if (WorkQueue.Count != 0 || SafeStatusQueue.Count != 0 || ControlQueue.Count != 0 || ControlScanCursor != null
|
|
370
|
+
|| RunningWork.Count != 0 || PendingSettlementWork.Count != 0 || ActiveRequestWork.Count != 0)
|
|
371
|
+
throw new InvalidOperationException("Local BridgeQueueState still owns work.");
|
|
372
|
+
}
|
|
373
|
+
if (PendingCompletionIntentCount != 0)
|
|
374
|
+
throw new InvalidOperationException("Local BridgeQueueState still owns admission completion intents.");
|
|
375
|
+
if (IsolatedExecution != null) IsolatedExecution.AssertEmpty();
|
|
376
|
+
TestHooks.AssertDrained();
|
|
377
|
+
}
|
|
378
|
+
|
|
379
|
+
private void AssertIoOutsideQueueLock()
|
|
380
|
+
{
|
|
381
|
+
if (Monitor.IsEntered(QueueLock)) throw new InvalidOperationException("Bridge queue state I/O is forbidden while QueueLock is held.");
|
|
382
|
+
}
|
|
383
|
+
|
|
384
|
+
private static string IntentKey(UnityCliBridge.AdmissionOwnerIdentity identity)
|
|
385
|
+
{
|
|
386
|
+
return identity.RequestId + "\0" + identity.RequestDigest + "\0" + (identity.TopRequestDigest ?? string.Empty)
|
|
387
|
+
+ "\0" + identity.RootFingerprint + "\0" + identity.Token + "\0" + identity.SessionId
|
|
388
|
+
+ "\0" + identity.ListenerId + "\0" + identity.ListenerGeneration.ToString(System.Globalization.CultureInfo.InvariantCulture)
|
|
389
|
+
+ "\0" + identity.ExecutionDeadlineMs.ToString(System.Globalization.CultureInfo.InvariantCulture)
|
|
390
|
+
+ "\0" + ((int)identity.OwnerState).ToString(System.Globalization.CultureInfo.InvariantCulture);
|
|
391
|
+
}
|
|
392
|
+
|
|
393
|
+
private static UnityCliBridge.AdmissionOwnerIdentity CloneIdentity(UnityCliBridge.AdmissionOwnerIdentity identity)
|
|
394
|
+
{
|
|
395
|
+
return new UnityCliBridge.AdmissionOwnerIdentity
|
|
396
|
+
{
|
|
397
|
+
RequestId = identity.RequestId, RequestDigest = identity.RequestDigest, TopRequestDigest = identity.TopRequestDigest,
|
|
398
|
+
RootFingerprint = identity.RootFingerprint, Token = identity.Token, SessionId = identity.SessionId,
|
|
399
|
+
ListenerId = identity.ListenerId, ListenerGeneration = identity.ListenerGeneration,
|
|
400
|
+
ExecutionDeadlineMs = identity.ExecutionDeadlineMs, EditorSessionId = identity.EditorSessionId, OwnerState = identity.OwnerState
|
|
401
|
+
};
|
|
402
|
+
}
|
|
403
|
+
|
|
404
|
+
internal sealed class PendingCompletionIntent
|
|
405
|
+
{
|
|
406
|
+
internal UnityCliBridge.AdmissionOwnerIdentity Owner;
|
|
407
|
+
internal long NextRetryAtMs;
|
|
408
|
+
internal bool FailureLogged;
|
|
409
|
+
internal bool Compensation;
|
|
410
|
+
internal bool IntentPersisted;
|
|
411
|
+
}
|
|
412
|
+
|
|
413
|
+
private static long DefaultMonotonicMilliseconds()
|
|
414
|
+
{
|
|
415
|
+
return checked((long)(System.Diagnostics.Stopwatch.GetTimestamp() * (1000d / System.Diagnostics.Stopwatch.Frequency)));
|
|
416
|
+
}
|
|
417
|
+
}
|
|
418
|
+
|
|
419
|
+
/// <summary>每个queue state显式持有日志与transaction输出;测试sink不触碰Library/UnityCli。</summary>
|
|
420
|
+
internal sealed class BridgeQueueSinks
|
|
421
|
+
{
|
|
422
|
+
private readonly Action<string> log;
|
|
423
|
+
private readonly Action<string, string, string, string> appendTransaction;
|
|
424
|
+
internal bool Production { get; private set; }
|
|
425
|
+
private int logCount;
|
|
426
|
+
private int transactionCount;
|
|
427
|
+
internal int LogCount { get { return Volatile.Read(ref logCount); } }
|
|
428
|
+
internal int TransactionCount { get { return Volatile.Read(ref transactionCount); } }
|
|
429
|
+
|
|
430
|
+
internal BridgeQueueSinks(Action<string> log, Action<string, string, string, string> appendTransaction, bool production)
|
|
431
|
+
{
|
|
432
|
+
if (log == null || appendTransaction == null) throw new ArgumentNullException("Bridge queue sinks must be explicit.");
|
|
433
|
+
this.log = log;
|
|
434
|
+
this.appendTransaction = appendTransaction;
|
|
435
|
+
Production = production;
|
|
436
|
+
}
|
|
437
|
+
|
|
438
|
+
internal void WriteLog(string line)
|
|
439
|
+
{
|
|
440
|
+
log(line);
|
|
441
|
+
Interlocked.Increment(ref logCount);
|
|
442
|
+
}
|
|
443
|
+
|
|
444
|
+
internal void AppendTransaction(string requestId, string command, string request, string response)
|
|
445
|
+
{
|
|
446
|
+
appendTransaction(requestId, command, request, response);
|
|
447
|
+
Interlocked.Increment(ref transactionCount);
|
|
448
|
+
}
|
|
449
|
+
}
|
|
450
|
+
|
|
451
|
+
/// <summary>测试边界按名称注册且只消费一次;未消费的故障点在TearDown硬失败。</summary>
|
|
452
|
+
internal sealed class BridgeQueueTestHooks
|
|
453
|
+
{
|
|
454
|
+
private readonly object sync = new object();
|
|
455
|
+
private readonly Dictionary<string, Action> expected = new Dictionary<string, Action>(StringComparer.Ordinal);
|
|
456
|
+
private readonly bool enabled;
|
|
457
|
+
|
|
458
|
+
internal BridgeQueueTestHooks(bool enabled)
|
|
459
|
+
{
|
|
460
|
+
this.enabled = enabled;
|
|
461
|
+
}
|
|
462
|
+
|
|
463
|
+
internal void ExpectOnce(string name, Action action)
|
|
464
|
+
{
|
|
465
|
+
if (!enabled) throw new InvalidOperationException("Production queue state does not accept test hooks.");
|
|
466
|
+
if (string.IsNullOrWhiteSpace(name) || action == null) throw new ArgumentException("One-shot test hook is invalid.");
|
|
467
|
+
lock (sync)
|
|
468
|
+
{
|
|
469
|
+
if (expected.ContainsKey(name)) throw new InvalidOperationException("One-shot test hook is already registered: " + name);
|
|
470
|
+
expected.Add(name, action);
|
|
471
|
+
}
|
|
472
|
+
}
|
|
473
|
+
|
|
474
|
+
internal void Hit(string name)
|
|
475
|
+
{
|
|
476
|
+
Action action;
|
|
477
|
+
lock (sync)
|
|
478
|
+
{
|
|
479
|
+
if (!expected.TryGetValue(name, out action)) return;
|
|
480
|
+
expected.Remove(name);
|
|
481
|
+
}
|
|
482
|
+
action();
|
|
483
|
+
}
|
|
484
|
+
|
|
485
|
+
internal void AssertDrained()
|
|
486
|
+
{
|
|
487
|
+
lock (sync)
|
|
488
|
+
{
|
|
489
|
+
if (expected.Count != 0)
|
|
490
|
+
throw new InvalidOperationException("One-shot queue test hooks were not consumed: " + string.Join(",", expected.Keys));
|
|
491
|
+
}
|
|
492
|
+
}
|
|
493
|
+
}
|
|
494
|
+
|
|
495
|
+
/// <summary>显式测试state的内存journal;不读取或修改production固定文件与全局mutation lease。</summary>
|
|
496
|
+
internal sealed class BridgeIsolatedExecutionState
|
|
497
|
+
{
|
|
498
|
+
private readonly object sync = new object();
|
|
499
|
+
private readonly Dictionary<string, Dictionary<string, object>> operations = new Dictionary<string, Dictionary<string, object>>(StringComparer.Ordinal);
|
|
500
|
+
private readonly Dictionary<string, TerminalEntry> terminals = new Dictionary<string, TerminalEntry>(StringComparer.Ordinal);
|
|
501
|
+
private string leaseRequestId;
|
|
502
|
+
private string leaseRequestDigest;
|
|
503
|
+
|
|
504
|
+
internal Dictionary<string, object> Load(string scope)
|
|
505
|
+
{
|
|
506
|
+
lock (sync)
|
|
507
|
+
{
|
|
508
|
+
Dictionary<string, object> value;
|
|
509
|
+
return operations.TryGetValue(scope, out value) ? Clone(value) : null;
|
|
510
|
+
}
|
|
511
|
+
}
|
|
512
|
+
|
|
513
|
+
internal void Save(string scope, Dictionary<string, object> value)
|
|
514
|
+
{
|
|
515
|
+
if (string.IsNullOrEmpty(scope) || value == null) throw new ArgumentException("Isolated operation state is invalid.");
|
|
516
|
+
lock (sync) operations[scope] = Clone(value);
|
|
517
|
+
}
|
|
518
|
+
|
|
519
|
+
internal void Clear(string scope)
|
|
520
|
+
{
|
|
521
|
+
lock (sync) operations.Remove(scope);
|
|
522
|
+
}
|
|
523
|
+
|
|
524
|
+
internal bool Exists(string scope)
|
|
525
|
+
{
|
|
526
|
+
lock (sync) return operations.ContainsKey(scope);
|
|
527
|
+
}
|
|
528
|
+
|
|
529
|
+
internal bool TryGetTerminal(string scope, string requestId, string requestDigest, out object envelope)
|
|
530
|
+
{
|
|
531
|
+
lock (sync)
|
|
532
|
+
{
|
|
533
|
+
TerminalEntry value;
|
|
534
|
+
if (!terminals.TryGetValue(TerminalKey(scope, requestId, requestDigest), out value))
|
|
535
|
+
{
|
|
536
|
+
envelope = null;
|
|
537
|
+
return false;
|
|
538
|
+
}
|
|
539
|
+
envelope = CloneObject(value.Envelope);
|
|
540
|
+
return true;
|
|
541
|
+
}
|
|
542
|
+
}
|
|
543
|
+
|
|
544
|
+
internal bool TryGetTerminalBySelector(string scope, string requestId, string selectorDigest, out object envelope)
|
|
545
|
+
{
|
|
546
|
+
lock (sync)
|
|
547
|
+
{
|
|
548
|
+
var value = terminals.Values.FirstOrDefault(entry => string.Equals(entry.Scope, scope, StringComparison.Ordinal)
|
|
549
|
+
&& string.Equals(entry.RequestId, requestId, StringComparison.Ordinal));
|
|
550
|
+
if (value == null || !string.Equals(value.SelectorDigest, selectorDigest, StringComparison.Ordinal))
|
|
551
|
+
{
|
|
552
|
+
envelope = null;
|
|
553
|
+
return false;
|
|
554
|
+
}
|
|
555
|
+
envelope = CloneObject(value.Envelope);
|
|
556
|
+
return true;
|
|
557
|
+
}
|
|
558
|
+
}
|
|
559
|
+
|
|
560
|
+
internal object StoreTerminalFirst(string scope, string requestId, string requestDigest, string selectorDigest, object envelope)
|
|
561
|
+
{
|
|
562
|
+
return StoreTerminalFirst(scope, requestId, requestDigest, selectorDigest, null, envelope);
|
|
563
|
+
}
|
|
564
|
+
|
|
565
|
+
internal object StoreTerminalFirst(string scope, string requestId, string requestDigest, string selectorDigest, string statusDomain, object envelope)
|
|
566
|
+
{
|
|
567
|
+
lock (sync)
|
|
568
|
+
{
|
|
569
|
+
var key = TerminalKey(scope, requestId, requestDigest);
|
|
570
|
+
TerminalEntry current;
|
|
571
|
+
if (!terminals.TryGetValue(key, out current))
|
|
572
|
+
{
|
|
573
|
+
current = new TerminalEntry
|
|
574
|
+
{
|
|
575
|
+
Scope = scope,
|
|
576
|
+
RequestId = requestId,
|
|
577
|
+
SelectorDigest = selectorDigest,
|
|
578
|
+
StatusDomain = statusDomain,
|
|
579
|
+
Envelope = CloneObject(envelope)
|
|
580
|
+
};
|
|
581
|
+
terminals.Add(key, current);
|
|
582
|
+
}
|
|
583
|
+
else if (!string.Equals(current.SelectorDigest, selectorDigest, StringComparison.Ordinal)
|
|
584
|
+
|| !string.Equals(current.StatusDomain, statusDomain, StringComparison.Ordinal))
|
|
585
|
+
{
|
|
586
|
+
throw new InvalidOperationException("Isolated terminal selector identity changed.");
|
|
587
|
+
}
|
|
588
|
+
return CloneObject(current.Envelope);
|
|
589
|
+
}
|
|
590
|
+
}
|
|
591
|
+
|
|
592
|
+
internal bool TryAcquireLease(string requestId, string requestDigest, out bool newlyAcquired)
|
|
593
|
+
{
|
|
594
|
+
lock (sync)
|
|
595
|
+
{
|
|
596
|
+
newlyAcquired = false;
|
|
597
|
+
if (leaseRequestId != null)
|
|
598
|
+
return string.Equals(leaseRequestId, requestId, StringComparison.Ordinal)
|
|
599
|
+
&& string.Equals(leaseRequestDigest, requestDigest, StringComparison.Ordinal);
|
|
600
|
+
leaseRequestId = requestId;
|
|
601
|
+
leaseRequestDigest = requestDigest;
|
|
602
|
+
newlyAcquired = true;
|
|
603
|
+
return true;
|
|
604
|
+
}
|
|
605
|
+
}
|
|
606
|
+
|
|
607
|
+
internal void ReleaseLease(string requestId, string requestDigest)
|
|
608
|
+
{
|
|
609
|
+
lock (sync)
|
|
610
|
+
{
|
|
611
|
+
if (!string.Equals(leaseRequestId, requestId, StringComparison.Ordinal)
|
|
612
|
+
|| !string.Equals(leaseRequestDigest, requestDigest, StringComparison.Ordinal)) return;
|
|
613
|
+
leaseRequestId = null;
|
|
614
|
+
leaseRequestDigest = null;
|
|
615
|
+
}
|
|
616
|
+
}
|
|
617
|
+
|
|
618
|
+
internal bool TryIsLeaseOwned(string requestId, string requestDigest, out bool isOwned)
|
|
619
|
+
{
|
|
620
|
+
lock (sync)
|
|
621
|
+
{
|
|
622
|
+
isOwned = string.Equals(leaseRequestId, requestId, StringComparison.Ordinal)
|
|
623
|
+
&& string.Equals(leaseRequestDigest, requestDigest, StringComparison.Ordinal);
|
|
624
|
+
return true;
|
|
625
|
+
}
|
|
626
|
+
}
|
|
627
|
+
|
|
628
|
+
internal bool TryGetCurrentOwner(out string requestId, out string requestDigest)
|
|
629
|
+
{
|
|
630
|
+
lock (sync)
|
|
631
|
+
{
|
|
632
|
+
requestId = leaseRequestId;
|
|
633
|
+
requestDigest = leaseRequestDigest;
|
|
634
|
+
return true;
|
|
635
|
+
}
|
|
636
|
+
}
|
|
637
|
+
|
|
638
|
+
internal void AssertEmpty()
|
|
639
|
+
{
|
|
640
|
+
lock (sync)
|
|
641
|
+
{
|
|
642
|
+
if (operations.Count != 0 || leaseRequestId != null)
|
|
643
|
+
throw new InvalidOperationException("Isolated execution state still owns an operation or lease.");
|
|
644
|
+
}
|
|
645
|
+
}
|
|
646
|
+
|
|
647
|
+
private sealed class TerminalEntry
|
|
648
|
+
{
|
|
649
|
+
internal string Scope;
|
|
650
|
+
internal string RequestId;
|
|
651
|
+
internal string SelectorDigest;
|
|
652
|
+
internal string StatusDomain;
|
|
653
|
+
internal object Envelope;
|
|
654
|
+
}
|
|
655
|
+
|
|
656
|
+
private static string TerminalKey(string scope, string requestId, string requestDigest)
|
|
657
|
+
{
|
|
658
|
+
return (scope ?? string.Empty) + "\0" + (requestId ?? string.Empty) + "\0" + (requestDigest ?? string.Empty);
|
|
659
|
+
}
|
|
660
|
+
|
|
661
|
+
private static Dictionary<string, object> Clone(Dictionary<string, object> value)
|
|
662
|
+
{
|
|
663
|
+
return (Dictionary<string, object>)CloneObject(value);
|
|
664
|
+
}
|
|
665
|
+
|
|
666
|
+
private static object CloneObject(object value)
|
|
667
|
+
{
|
|
668
|
+
return value == null ? null : UnityCliSerializer.Parse(UnityCliSerializer.Serialize(value));
|
|
669
|
+
}
|
|
670
|
+
}
|
|
671
|
+
}
|
|
672
|
+
#endif
|