@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
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
"name": "UnityCli.Runtime",
|
|
3
3
|
"rootNamespace": "UnityCli",
|
|
4
4
|
"references": ["UnityCli.Shared"],
|
|
5
|
-
"includePlatforms": ["WindowsStandalone32", "WindowsStandalone64"],
|
|
5
|
+
"includePlatforms": ["Editor", "WindowsStandalone32", "WindowsStandalone64"],
|
|
6
6
|
"excludePlatforms": [],
|
|
7
7
|
"allowUnsafeCode": false,
|
|
8
8
|
"overrideReferences": false,
|
|
@@ -7,13 +7,14 @@ using System.Text;
|
|
|
7
7
|
|
|
8
8
|
namespace UnityCli
|
|
9
9
|
{
|
|
10
|
-
/// <summary>每个Unity target session独占的有界原子准入池;
|
|
10
|
+
/// <summary>每个Unity target session独占的有界原子准入池;owner state是唯一生命周期真相。</summary>
|
|
11
11
|
public sealed class UnityCliAdmissionPool
|
|
12
12
|
{
|
|
13
|
-
public enum
|
|
14
|
-
public enum AdmissionOwnerKind { WorkItem, Coordinator, Recovery }
|
|
13
|
+
public enum AdmissionOwnerState { Granted, WorkItem, Coordinator, Continuation, Recovery, TerminalCleanup }
|
|
15
14
|
public enum AcquireOutcome { Granted, AlreadyConsumed, Closed, Invalid, IdentityMismatch, RecoveryBlocked }
|
|
16
|
-
public enum AuthorizeOutcome { Authorized, AlreadyConsumed, Missing,
|
|
15
|
+
public enum AuthorizeOutcome { Authorized, AlreadyConsumed, Missing, IdentityMismatch, Invalid, RecoveryBlocked }
|
|
16
|
+
public enum ExactIdentityOutcome { ExactCurrent, DefinitelyAbsent, IdentityMismatchOrBlocked }
|
|
17
|
+
public enum CompletionOutcome { ExactCurrentCompleted, DefinitelyAbsent, IdentityMismatchOrBlocked }
|
|
17
18
|
|
|
18
19
|
public sealed class AcquireResult
|
|
19
20
|
{
|
|
@@ -24,29 +25,52 @@ namespace UnityCli
|
|
|
24
25
|
public bool NewlyGranted { get; internal set; }
|
|
25
26
|
}
|
|
26
27
|
|
|
28
|
+
public sealed class AuthorizeResult
|
|
29
|
+
{
|
|
30
|
+
public AuthorizeOutcome Outcome { get; internal set; }
|
|
31
|
+
public ConsumedIdentity Identity { get; internal set; }
|
|
32
|
+
public bool NewlyConsumed { get; internal set; }
|
|
33
|
+
}
|
|
34
|
+
|
|
27
35
|
public sealed class AdmissionRecord
|
|
28
36
|
{
|
|
29
37
|
public string InstanceId { get; set; }
|
|
30
38
|
public string SessionId { get; set; }
|
|
31
39
|
public string RequestId { get; set; }
|
|
32
40
|
public string RootFingerprint { get; set; }
|
|
41
|
+
public string RequestDigest { get; set; }
|
|
33
42
|
public string Token { get; set; }
|
|
34
43
|
public string ListenerId { get; set; }
|
|
35
44
|
public long ListenerGeneration { get; set; }
|
|
36
45
|
public long GrantExpiresAtMs { get; set; }
|
|
37
46
|
public long ExecutionDeadlineMs { get; set; }
|
|
38
|
-
public
|
|
39
|
-
public
|
|
40
|
-
public bool
|
|
47
|
+
public AdmissionOwnerState OwnerState { get; set; }
|
|
48
|
+
public AdmissionOwnerState IntendedOwnerState { get; set; }
|
|
49
|
+
public bool TransferCommitted { get; set; }
|
|
50
|
+
public bool Consumed { get { return OwnerState != AdmissionOwnerState.Granted; } }
|
|
41
51
|
}
|
|
42
52
|
|
|
43
53
|
public sealed class ConsumedIdentity
|
|
44
54
|
{
|
|
45
55
|
public string RequestId { get; internal set; }
|
|
46
56
|
public string RootFingerprint { get; internal set; }
|
|
57
|
+
public string RequestDigest { get; internal set; }
|
|
47
58
|
public string Token { get; internal set; }
|
|
48
59
|
public string SessionId { get; internal set; }
|
|
49
|
-
public
|
|
60
|
+
public string ListenerId { get; internal set; }
|
|
61
|
+
public long ListenerGeneration { get; internal set; }
|
|
62
|
+
public long ExecutionDeadlineMs { get; internal set; }
|
|
63
|
+
public AdmissionOwnerState OwnerState { get; internal set; }
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
/// <summary>跨assembly owner只通过完整字段创建不可变transition identity。</summary>
|
|
67
|
+
public static ConsumedIdentity CreateConsumedIdentity(string requestId, string rootFingerprint, string requestDigest, string token, string ownerSessionId, AdmissionOwnerState ownerState, string listenerId, long listenerGeneration, long executionDeadlineMs)
|
|
68
|
+
{
|
|
69
|
+
if (!ValidRequestId(requestId) || !IsSha256(rootFingerprint) || !IsSha256(requestDigest) || !IsToken(token)
|
|
70
|
+
|| string.IsNullOrWhiteSpace(ownerSessionId) || !ValidListener(listenerId, listenerGeneration) || executionDeadlineMs <= 0
|
|
71
|
+
|| ownerState == AdmissionOwnerState.Granted || !Enum.IsDefined(typeof(AdmissionOwnerState), ownerState))
|
|
72
|
+
throw new ArgumentException("Admission consumed identity is invalid.");
|
|
73
|
+
return new ConsumedIdentity { RequestId = requestId, RootFingerprint = rootFingerprint, RequestDigest = requestDigest, Token = token, SessionId = ownerSessionId, ListenerId = listenerId, ListenerGeneration = listenerGeneration, ExecutionDeadlineMs = executionDeadlineMs, OwnerState = ownerState };
|
|
50
74
|
}
|
|
51
75
|
|
|
52
76
|
public sealed class Snapshot
|
|
@@ -104,12 +128,12 @@ namespace UnityCli
|
|
|
104
128
|
if (records.TryGetValue(requestId, out existing))
|
|
105
129
|
{
|
|
106
130
|
if (!string.Equals(existing.RootFingerprint, rootFingerprint, StringComparison.Ordinal)) return Result(AcquireOutcome.IdentityMismatch);
|
|
107
|
-
if (existing.
|
|
131
|
+
if (existing.OwnerState == AdmissionOwnerState.Granted && (!string.Equals(existing.ListenerId, listenerId, StringComparison.Ordinal) || existing.ListenerGeneration != listenerGeneration))
|
|
108
132
|
{
|
|
109
133
|
records.Remove(requestId);
|
|
110
134
|
UpdateGateAfterRemoval();
|
|
111
135
|
}
|
|
112
|
-
else if (existing.
|
|
136
|
+
else if (existing.Consumed) return Result(AcquireOutcome.AlreadyConsumed);
|
|
113
137
|
else return Result(AcquireOutcome.Granted, existing.Token, RemainingGrantMs(existing), false);
|
|
114
138
|
}
|
|
115
139
|
|
|
@@ -136,8 +160,9 @@ namespace UnityCli
|
|
|
136
160
|
ListenerGeneration = listenerGeneration,
|
|
137
161
|
GrantExpiresAtMs = checked(monotonicNowMs() + GrantTtlMs),
|
|
138
162
|
ExecutionDeadlineMs = 0,
|
|
139
|
-
|
|
140
|
-
|
|
163
|
+
OwnerState = AdmissionOwnerState.Granted,
|
|
164
|
+
IntendedOwnerState = AdmissionOwnerState.Granted,
|
|
165
|
+
TransferCommitted = true
|
|
141
166
|
});
|
|
142
167
|
if (records.Count == maxActive) gateClosed = true;
|
|
143
168
|
return Result(AcquireOutcome.Granted, token, GrantTtlMs, true);
|
|
@@ -151,38 +176,36 @@ namespace UnityCli
|
|
|
151
176
|
}
|
|
152
177
|
}
|
|
153
178
|
|
|
154
|
-
/// <summary
|
|
155
|
-
public
|
|
179
|
+
/// <summary>Granted→WorkItem与完整identity冻结共享一个线性化点。</summary>
|
|
180
|
+
public AuthorizeResult AuthorizeAndCapture(string requestId, string rootFingerprint, string requestDigest, string token, string listenerId, long listenerGeneration, long executionDeadlineMs)
|
|
156
181
|
{
|
|
157
182
|
lock (sync)
|
|
158
183
|
{
|
|
159
184
|
try
|
|
160
185
|
{
|
|
161
186
|
CleanupExpiredGrants();
|
|
162
|
-
if (recoveryBlocked) return AuthorizeOutcome.RecoveryBlocked;
|
|
163
|
-
if (!ValidRequestId(requestId) || !IsSha256(rootFingerprint) || !IsToken(token) || !ValidListener(listenerId, listenerGeneration) || executionDeadlineMs <= utcNowMs()) return AuthorizeOutcome.Invalid;
|
|
187
|
+
if (recoveryBlocked) return Authorized(AuthorizeOutcome.RecoveryBlocked);
|
|
188
|
+
if (!ValidRequestId(requestId) || !IsSha256(rootFingerprint) || !IsSha256(requestDigest) || !IsToken(token) || !ValidListener(listenerId, listenerGeneration) || executionDeadlineMs <= utcNowMs()) return Authorized(AuthorizeOutcome.Invalid);
|
|
164
189
|
AdmissionRecord entry;
|
|
165
|
-
if (!records.TryGetValue(requestId, out entry)) return AuthorizeOutcome.Missing;
|
|
166
|
-
if (!string.Equals(entry.RootFingerprint, rootFingerprint, StringComparison.Ordinal) || !FixedEquals(entry.Token, token)) return AuthorizeOutcome.IdentityMismatch;
|
|
167
|
-
if (entry.
|
|
168
|
-
return entry.ExecutionDeadlineMs == executionDeadlineMs
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
records.Remove(requestId);
|
|
172
|
-
UpdateGateAfterRemoval();
|
|
173
|
-
return AuthorizeOutcome.Expired;
|
|
174
|
-
}
|
|
190
|
+
if (!records.TryGetValue(requestId, out entry)) return Authorized(AuthorizeOutcome.Missing);
|
|
191
|
+
if (!string.Equals(entry.RootFingerprint, rootFingerprint, StringComparison.Ordinal) || !FixedEquals(entry.Token, token)) return Authorized(AuthorizeOutcome.IdentityMismatch);
|
|
192
|
+
if (entry.Consumed)
|
|
193
|
+
return entry.ExecutionDeadlineMs == executionDeadlineMs && string.Equals(entry.RequestDigest, requestDigest, StringComparison.Ordinal)
|
|
194
|
+
? Authorized(AuthorizeOutcome.AlreadyConsumed, Identity(entry))
|
|
195
|
+
: Authorized(AuthorizeOutcome.IdentityMismatch);
|
|
175
196
|
if (!string.Equals(entry.ListenerId, listenerId, StringComparison.Ordinal) || entry.ListenerGeneration != listenerGeneration)
|
|
176
197
|
{
|
|
177
198
|
records.Remove(requestId);
|
|
178
199
|
UpdateGateAfterRemoval();
|
|
179
|
-
return AuthorizeOutcome.IdentityMismatch;
|
|
200
|
+
return Authorized(AuthorizeOutcome.IdentityMismatch);
|
|
180
201
|
}
|
|
181
|
-
entry.
|
|
182
|
-
entry.
|
|
202
|
+
entry.RequestDigest = requestDigest;
|
|
203
|
+
entry.OwnerState = AdmissionOwnerState.WorkItem;
|
|
204
|
+
entry.IntendedOwnerState = AdmissionOwnerState.WorkItem;
|
|
205
|
+
entry.TransferCommitted = true;
|
|
183
206
|
entry.ExecutionDeadlineMs = executionDeadlineMs;
|
|
184
207
|
entry.GrantExpiresAtMs = 0;
|
|
185
|
-
return AuthorizeOutcome.Authorized;
|
|
208
|
+
return Authorized(AuthorizeOutcome.Authorized, Identity(entry), true);
|
|
186
209
|
}
|
|
187
210
|
catch
|
|
188
211
|
{
|
|
@@ -193,29 +216,46 @@ namespace UnityCli
|
|
|
193
216
|
}
|
|
194
217
|
}
|
|
195
218
|
|
|
219
|
+
/// <summary>仅撤销本次新消费且尚未发布的WorkItem;完整identity避免删除后继。</summary>
|
|
220
|
+
public bool CompensateAuthorization(ConsumedIdentity identity)
|
|
221
|
+
{
|
|
222
|
+
lock (sync)
|
|
223
|
+
{
|
|
224
|
+
AdmissionRecord entry;
|
|
225
|
+
if (identity == null || !records.TryGetValue(identity.RequestId, out entry)) return true;
|
|
226
|
+
if (!Matches(entry, identity) || entry.OwnerState != AdmissionOwnerState.WorkItem
|
|
227
|
+
|| entry.IntendedOwnerState != AdmissionOwnerState.WorkItem || !entry.TransferCommitted) return false;
|
|
228
|
+
records.Remove(identity.RequestId);
|
|
229
|
+
UpdateGateAfterRemoval();
|
|
230
|
+
return true;
|
|
231
|
+
}
|
|
232
|
+
}
|
|
233
|
+
|
|
196
234
|
/// <summary>同listener generation的已消费root只做attach检查,不再次消费token。</summary>
|
|
197
|
-
public bool AttachConsumed(string requestId, string rootFingerprint, string listenerId, long listenerGeneration, long executionDeadlineMs)
|
|
235
|
+
public bool AttachConsumed(string requestId, string rootFingerprint, string requestDigest, string listenerId, long listenerGeneration, long executionDeadlineMs)
|
|
198
236
|
{
|
|
199
237
|
lock (sync)
|
|
200
238
|
{
|
|
201
239
|
if (recoveryBlocked) return false;
|
|
202
240
|
AdmissionRecord entry;
|
|
203
|
-
return records.TryGetValue(requestId, out entry) && entry
|
|
241
|
+
return records.TryGetValue(requestId, out entry) && ValidConsumedRecord(entry)
|
|
204
242
|
&& string.Equals(entry.RootFingerprint, rootFingerprint, StringComparison.Ordinal)
|
|
243
|
+
&& string.Equals(entry.RequestDigest, requestDigest, StringComparison.Ordinal)
|
|
205
244
|
&& string.Equals(entry.ListenerId, listenerId, StringComparison.Ordinal) && entry.ListenerGeneration == listenerGeneration
|
|
206
245
|
&& entry.ExecutionDeadlineMs == executionDeadlineMs;
|
|
207
246
|
}
|
|
208
247
|
}
|
|
209
248
|
|
|
210
|
-
/// <summary>durable owner证明同root恢复后显式重绑listener generation,不改变
|
|
211
|
-
public bool RecoverConsumed(string requestId, string rootFingerprint, string listenerId, long listenerGeneration, long executionDeadlineMs)
|
|
249
|
+
/// <summary>durable owner证明同root恢复后显式重绑listener generation,不改变owner。</summary>
|
|
250
|
+
public bool RecoverConsumed(string requestId, string rootFingerprint, string requestDigest, string listenerId, long listenerGeneration, long executionDeadlineMs)
|
|
212
251
|
{
|
|
213
252
|
lock (sync)
|
|
214
253
|
{
|
|
215
254
|
if (recoveryBlocked || !ValidListener(listenerId, listenerGeneration)) return false;
|
|
216
255
|
AdmissionRecord entry;
|
|
217
|
-
if (!records.TryGetValue(requestId, out entry) || entry
|
|
256
|
+
if (!records.TryGetValue(requestId, out entry) || !ValidConsumedRecord(entry)
|
|
218
257
|
|| !string.Equals(entry.RootFingerprint, rootFingerprint, StringComparison.Ordinal)
|
|
258
|
+
|| !string.Equals(entry.RequestDigest, requestDigest, StringComparison.Ordinal)
|
|
219
259
|
|| entry.ExecutionDeadlineMs != executionDeadlineMs) return false;
|
|
220
260
|
entry.ListenerId = listenerId;
|
|
221
261
|
entry.ListenerGeneration = listenerGeneration;
|
|
@@ -223,7 +263,49 @@ namespace UnityCli
|
|
|
223
263
|
}
|
|
224
264
|
}
|
|
225
265
|
|
|
226
|
-
/// <summary>
|
|
266
|
+
/// <summary>marker与pool同时落在reload窗口时按完整identity重建唯一consumed record。</summary>
|
|
267
|
+
public bool RestoreConsumed(ConsumedIdentity identity, AdmissionOwnerState intendedOwner, bool transferCommitted)
|
|
268
|
+
{
|
|
269
|
+
lock (sync)
|
|
270
|
+
{
|
|
271
|
+
if (recoveryBlocked || identity == null || identity.OwnerState == AdmissionOwnerState.Granted
|
|
272
|
+
|| !Enum.IsDefined(typeof(AdmissionOwnerState), intendedOwner) || intendedOwner == AdmissionOwnerState.Granted
|
|
273
|
+
|| !ValidRequestId(identity.RequestId) || !IsSha256(identity.RootFingerprint) || !IsSha256(identity.RequestDigest)
|
|
274
|
+
|| !IsToken(identity.Token) || !string.Equals(identity.SessionId, sessionId, StringComparison.Ordinal)
|
|
275
|
+
|| !ValidListener(identity.ListenerId, identity.ListenerGeneration) || identity.ExecutionDeadlineMs <= 0
|
|
276
|
+
|| !IsLegalOwnerTransfer(identity.OwnerState, intendedOwner)) return false;
|
|
277
|
+
AdmissionRecord existing;
|
|
278
|
+
if (records.TryGetValue(identity.RequestId, out existing))
|
|
279
|
+
{
|
|
280
|
+
var expectedIntendedOwner = transferCommitted ? identity.OwnerState : intendedOwner;
|
|
281
|
+
return Matches(existing, identity)
|
|
282
|
+
&& existing.IntendedOwnerState == expectedIntendedOwner
|
|
283
|
+
&& existing.TransferCommitted == transferCommitted;
|
|
284
|
+
}
|
|
285
|
+
if (records.Count >= maxActive) { gateClosed = true; return false; }
|
|
286
|
+
records.Add(identity.RequestId, new AdmissionRecord
|
|
287
|
+
{
|
|
288
|
+
InstanceId = instanceId,
|
|
289
|
+
SessionId = sessionId,
|
|
290
|
+
RequestId = identity.RequestId,
|
|
291
|
+
RootFingerprint = identity.RootFingerprint,
|
|
292
|
+
RequestDigest = identity.RequestDigest,
|
|
293
|
+
Token = identity.Token,
|
|
294
|
+
ListenerId = identity.ListenerId,
|
|
295
|
+
ListenerGeneration = identity.ListenerGeneration,
|
|
296
|
+
GrantExpiresAtMs = 0,
|
|
297
|
+
ExecutionDeadlineMs = identity.ExecutionDeadlineMs,
|
|
298
|
+
OwnerState = identity.OwnerState,
|
|
299
|
+
IntendedOwnerState = transferCommitted ? identity.OwnerState : intendedOwner,
|
|
300
|
+
TransferCommitted = transferCommitted
|
|
301
|
+
});
|
|
302
|
+
effectiveMaxActive = Math.Max(effectiveMaxActive, records.Count);
|
|
303
|
+
if (records.Count >= maxActive) gateClosed = true;
|
|
304
|
+
return true;
|
|
305
|
+
}
|
|
306
|
+
}
|
|
307
|
+
|
|
308
|
+
/// <summary>冻结当前consumed identity;后续转移与完成仍必须提交全部字段和expected owner。</summary>
|
|
227
309
|
public bool TryGetConsumedIdentity(string requestId, out ConsumedIdentity identity)
|
|
228
310
|
{
|
|
229
311
|
lock (sync)
|
|
@@ -231,52 +313,114 @@ namespace UnityCli
|
|
|
231
313
|
identity = null;
|
|
232
314
|
AdmissionRecord entry;
|
|
233
315
|
if (!records.TryGetValue(requestId, out entry) || !ValidConsumedRecord(entry)) return false;
|
|
234
|
-
identity =
|
|
316
|
+
identity = Identity(entry);
|
|
235
317
|
return true;
|
|
236
318
|
}
|
|
237
319
|
}
|
|
238
320
|
|
|
239
|
-
/// <summary
|
|
240
|
-
public bool
|
|
321
|
+
/// <summary>持久化层写完intent后登记expected→intended;重复同一intent幂等。</summary>
|
|
322
|
+
public bool PrepareOwnerTransfer(ConsumedIdentity identity, AdmissionOwnerState intendedOwner)
|
|
241
323
|
{
|
|
242
324
|
lock (sync)
|
|
243
325
|
{
|
|
244
|
-
if (targetOwner == AdmissionOwnerKind.WorkItem) return false;
|
|
245
326
|
AdmissionRecord entry;
|
|
246
|
-
if (!records.TryGetValue(
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
if (entry.
|
|
250
|
-
|
|
251
|
-
entry.
|
|
327
|
+
if (identity == null || !records.TryGetValue(identity.RequestId, out entry) || !Matches(entry, identity)) return false;
|
|
328
|
+
if (entry.TransferCommitted && entry.OwnerState == intendedOwner && entry.IntendedOwnerState == intendedOwner) return true;
|
|
329
|
+
if (!entry.TransferCommitted) return entry.OwnerState == identity.OwnerState && entry.IntendedOwnerState == intendedOwner;
|
|
330
|
+
if (!LegalTransfer(entry.OwnerState, intendedOwner)) return false;
|
|
331
|
+
entry.IntendedOwnerState = intendedOwner;
|
|
332
|
+
entry.TransferCommitted = false;
|
|
252
333
|
return true;
|
|
253
334
|
}
|
|
254
335
|
}
|
|
255
336
|
|
|
256
|
-
/// <summary
|
|
257
|
-
public bool
|
|
337
|
+
/// <summary>只提交已登记的exact transfer;已提交同一target时幂等返回冻结后继identity。</summary>
|
|
338
|
+
public bool CommitOwnerTransfer(ConsumedIdentity identity, AdmissionOwnerState intendedOwner, out ConsumedIdentity successor)
|
|
258
339
|
{
|
|
259
340
|
lock (sync)
|
|
260
341
|
{
|
|
342
|
+
successor = null;
|
|
261
343
|
AdmissionRecord entry;
|
|
262
|
-
if (!records.TryGetValue(
|
|
263
|
-
if (
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
344
|
+
if (identity == null || !records.TryGetValue(identity.RequestId, out entry)) return false;
|
|
345
|
+
if (entry.TransferCommitted && entry.OwnerState == intendedOwner && entry.IntendedOwnerState == intendedOwner
|
|
346
|
+
&& MatchesIdentityFields(entry, identity) && (identity.OwnerState == intendedOwner || LegalTransfer(identity.OwnerState, intendedOwner)))
|
|
347
|
+
{
|
|
348
|
+
successor = Identity(entry);
|
|
349
|
+
return true;
|
|
350
|
+
}
|
|
351
|
+
if (!Matches(entry, identity) || entry.TransferCommitted || entry.IntendedOwnerState != intendedOwner
|
|
352
|
+
|| !LegalTransfer(entry.OwnerState, intendedOwner)) return false;
|
|
353
|
+
entry.OwnerState = intendedOwner;
|
|
354
|
+
entry.IntendedOwnerState = intendedOwner;
|
|
355
|
+
entry.TransferCommitted = true;
|
|
356
|
+
successor = Identity(entry);
|
|
268
357
|
return true;
|
|
269
358
|
}
|
|
270
359
|
}
|
|
271
360
|
|
|
272
|
-
/// <summary
|
|
361
|
+
/// <summary>transfer marker按冻结字段识别当前root;owner state由同一锁内的current record另行裁决。</summary>
|
|
362
|
+
public ExactIdentityOutcome InspectExactIdentityFields(ConsumedIdentity identity)
|
|
363
|
+
{
|
|
364
|
+
lock (sync)
|
|
365
|
+
{
|
|
366
|
+
if (identity == null || recoveryBlocked) return ExactIdentityOutcome.IdentityMismatchOrBlocked;
|
|
367
|
+
AdmissionRecord entry;
|
|
368
|
+
if (!records.TryGetValue(identity.RequestId, out entry)) return ExactIdentityOutcome.DefinitelyAbsent;
|
|
369
|
+
return ValidConsumedRecord(entry) && MatchesIdentityFields(entry, identity)
|
|
370
|
+
? ExactIdentityOutcome.ExactCurrent
|
|
371
|
+
: ExactIdentityOutcome.IdentityMismatchOrBlocked;
|
|
372
|
+
}
|
|
373
|
+
}
|
|
374
|
+
|
|
375
|
+
/// <summary>只有WorkItem、Continuation或TerminalCleanup可完成;返回值保留absent与mismatch差异。</summary>
|
|
376
|
+
public CompletionOutcome CompleteTrusted(ConsumedIdentity identity)
|
|
377
|
+
{
|
|
378
|
+
lock (sync)
|
|
379
|
+
{
|
|
380
|
+
if (identity == null || recoveryBlocked) return CompletionOutcome.IdentityMismatchOrBlocked;
|
|
381
|
+
AdmissionRecord entry;
|
|
382
|
+
if (!records.TryGetValue(identity.RequestId, out entry)) return CompletionOutcome.DefinitelyAbsent;
|
|
383
|
+
if (!ValidConsumedRecord(entry) || !Matches(entry, identity) || !CanComplete(entry.OwnerState)
|
|
384
|
+
|| !entry.TransferCommitted || entry.IntendedOwnerState != entry.OwnerState)
|
|
385
|
+
return CompletionOutcome.IdentityMismatchOrBlocked;
|
|
386
|
+
records.Remove(identity.RequestId);
|
|
387
|
+
UpdateGateAfterRemoval();
|
|
388
|
+
return CompletionOutcome.ExactCurrentCompleted;
|
|
389
|
+
}
|
|
390
|
+
}
|
|
391
|
+
|
|
392
|
+
/// <summary>session publication关闭后,shutdown可按完整WorkItem身份隔离回收,即使普通recovery已阻断。</summary>
|
|
393
|
+
public CompletionOutcome CompleteWorkItemForShutdown(ConsumedIdentity identity)
|
|
394
|
+
{
|
|
395
|
+
lock (sync)
|
|
396
|
+
{
|
|
397
|
+
if (identity == null) return CompletionOutcome.IdentityMismatchOrBlocked;
|
|
398
|
+
AdmissionRecord entry;
|
|
399
|
+
if (!records.TryGetValue(identity.RequestId, out entry)) return CompletionOutcome.DefinitelyAbsent;
|
|
400
|
+
if (!ValidConsumedRecord(entry) || !Matches(entry, identity)
|
|
401
|
+
|| entry.OwnerState != AdmissionOwnerState.WorkItem
|
|
402
|
+
|| !entry.TransferCommitted || entry.IntendedOwnerState != AdmissionOwnerState.WorkItem)
|
|
403
|
+
return CompletionOutcome.IdentityMismatchOrBlocked;
|
|
404
|
+
records.Remove(identity.RequestId);
|
|
405
|
+
UpdateGateAfterRemoval();
|
|
406
|
+
return CompletionOutcome.ExactCurrentCompleted;
|
|
407
|
+
}
|
|
408
|
+
}
|
|
409
|
+
|
|
410
|
+
public static bool IsLegalOwnerTransfer(AdmissionOwnerState source, AdmissionOwnerState target)
|
|
411
|
+
{
|
|
412
|
+
return source == target || LegalTransfer(source, target);
|
|
413
|
+
}
|
|
414
|
+
|
|
415
|
+
/// <summary>未消费grant只能按完整identity执行Granted→removed。</summary>
|
|
273
416
|
public bool Revoke(string requestId, string rootFingerprint, string token)
|
|
274
417
|
{
|
|
275
418
|
lock (sync)
|
|
276
419
|
{
|
|
277
420
|
AdmissionRecord entry;
|
|
278
421
|
if (!records.TryGetValue(requestId, out entry)) return true;
|
|
279
|
-
if (!RecordOwnedByPool(entry) || entry.
|
|
422
|
+
if (!RecordOwnedByPool(entry) || entry.OwnerState != AdmissionOwnerState.Granted
|
|
423
|
+
|| !string.Equals(entry.RootFingerprint, rootFingerprint, StringComparison.Ordinal) || !FixedEquals(entry.Token, token)) return false;
|
|
280
424
|
records.Remove(requestId);
|
|
281
425
|
UpdateGateAfterRemoval();
|
|
282
426
|
return true;
|
|
@@ -287,7 +431,7 @@ namespace UnityCli
|
|
|
287
431
|
{
|
|
288
432
|
lock (sync)
|
|
289
433
|
{
|
|
290
|
-
var remove = records.Values.Where(entry => entry.
|
|
434
|
+
var remove = records.Values.Where(entry => entry.OwnerState == AdmissionOwnerState.Granted && string.Equals(entry.ListenerId, listenerId, StringComparison.Ordinal) && entry.ListenerGeneration == listenerGeneration).Select(entry => entry.RequestId).ToArray();
|
|
291
435
|
foreach (var requestId in remove) records.Remove(requestId);
|
|
292
436
|
UpdateGateAfterRemoval();
|
|
293
437
|
}
|
|
@@ -298,22 +442,22 @@ namespace UnityCli
|
|
|
298
442
|
lock (sync)
|
|
299
443
|
{
|
|
300
444
|
CleanupExpiredGrants();
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
445
|
+
return SnapshotOf(records.Values.OrderBy(value => value.RequestId, StringComparer.Ordinal).Select(Clone).ToArray(), gateClosed, maxActive);
|
|
446
|
+
}
|
|
447
|
+
}
|
|
448
|
+
|
|
449
|
+
/// <summary>reload快照排除可撤销grant;digest与active count只覆盖durable consumed owner。</summary>
|
|
450
|
+
public Snapshot CaptureRecovery()
|
|
451
|
+
{
|
|
452
|
+
lock (sync)
|
|
453
|
+
{
|
|
454
|
+
CleanupExpiredGrants();
|
|
455
|
+
var values = records.Values.Where(value => value.Consumed).OrderBy(value => value.RequestId, StringComparer.Ordinal).Select(Clone).ToArray();
|
|
456
|
+
return SnapshotOf(values, values.Length >= maxActive || (gateClosed && values.Length > reopenAt), Math.Max(maxActive, values.Length));
|
|
313
457
|
}
|
|
314
458
|
}
|
|
315
459
|
|
|
316
|
-
/// <summary
|
|
460
|
+
/// <summary>只恢复当前启动的consumed owner;未提交transfer由durable marker reconciliation裁决。</summary>
|
|
317
461
|
public void Restore(IEnumerable<AdmissionRecord> values, int expectedActiveCount, bool wasClosed, string expectedRecoveryDigest, int sourceMaxActive, int sourceReopenAt)
|
|
318
462
|
{
|
|
319
463
|
lock (sync)
|
|
@@ -351,10 +495,25 @@ namespace UnityCli
|
|
|
351
495
|
public void BlockRecovery() { lock (sync) { recoveryBlocked = true; gateClosed = true; } }
|
|
352
496
|
public void Reset() { lock (sync) { records.Clear(); effectiveMaxActive = maxActive; gateClosed = false; recoveryBlocked = false; } }
|
|
353
497
|
|
|
498
|
+
private Snapshot SnapshotOf(AdmissionRecord[] values, bool closed, int digestMaxActive)
|
|
499
|
+
{
|
|
500
|
+
return new Snapshot
|
|
501
|
+
{
|
|
502
|
+
GateClosed = closed,
|
|
503
|
+
Active = values.Length,
|
|
504
|
+
MaxActive = effectiveMaxActive,
|
|
505
|
+
ConfiguredMaxActive = digestMaxActive,
|
|
506
|
+
ReopenAt = reopenAt,
|
|
507
|
+
RecoveryBlocked = recoveryBlocked,
|
|
508
|
+
Records = values,
|
|
509
|
+
RecoveryDigest = ComputeRecoveryDigest(values, values.Length, closed, digestMaxActive, reopenAt)
|
|
510
|
+
};
|
|
511
|
+
}
|
|
512
|
+
|
|
354
513
|
private void CleanupExpiredGrants()
|
|
355
514
|
{
|
|
356
515
|
var current = monotonicNowMs();
|
|
357
|
-
var remove = records.Values.Where(entry => entry.
|
|
516
|
+
var remove = records.Values.Where(entry => entry.OwnerState == AdmissionOwnerState.Granted && entry.GrantExpiresAtMs <= current).Select(entry => entry.RequestId).ToArray();
|
|
358
517
|
foreach (var requestId in remove) records.Remove(requestId);
|
|
359
518
|
if (remove.Length > 0) UpdateGateAfterRemoval();
|
|
360
519
|
}
|
|
@@ -372,9 +531,10 @@ namespace UnityCli
|
|
|
372
531
|
Append(builder, digestReopenAt.ToString(CultureInfo.InvariantCulture)); Append(builder, expectedActiveCount.ToString(CultureInfo.InvariantCulture)); Append(builder, wasClosed ? "1" : "0");
|
|
373
532
|
foreach (var value in values.OrderBy(item => item.RequestId, StringComparer.Ordinal))
|
|
374
533
|
{
|
|
375
|
-
Append(builder, value.InstanceId); Append(builder, value.SessionId); Append(builder, value.RequestId); Append(builder, value.RootFingerprint); Append(builder, value.Token);
|
|
534
|
+
Append(builder, value.InstanceId); Append(builder, value.SessionId); Append(builder, value.RequestId); Append(builder, value.RootFingerprint); Append(builder, value.RequestDigest); Append(builder, value.Token);
|
|
376
535
|
Append(builder, value.ListenerId); Append(builder, value.ListenerGeneration.ToString(CultureInfo.InvariantCulture)); Append(builder, value.GrantExpiresAtMs.ToString(CultureInfo.InvariantCulture));
|
|
377
|
-
Append(builder, value.ExecutionDeadlineMs.ToString(CultureInfo.InvariantCulture)); Append(builder, ((int)value.
|
|
536
|
+
Append(builder, value.ExecutionDeadlineMs.ToString(CultureInfo.InvariantCulture)); Append(builder, ((int)value.OwnerState).ToString(CultureInfo.InvariantCulture));
|
|
537
|
+
Append(builder, ((int)value.IntendedOwnerState).ToString(CultureInfo.InvariantCulture)); Append(builder, value.TransferCommitted ? "1" : "0");
|
|
378
538
|
}
|
|
379
539
|
using (var sha = SHA256.Create())
|
|
380
540
|
{
|
|
@@ -385,6 +545,21 @@ namespace UnityCli
|
|
|
385
545
|
}
|
|
386
546
|
}
|
|
387
547
|
|
|
548
|
+
private static bool LegalTransfer(AdmissionOwnerState source, AdmissionOwnerState target)
|
|
549
|
+
{
|
|
550
|
+
if (source == AdmissionOwnerState.WorkItem)
|
|
551
|
+
return target == AdmissionOwnerState.Coordinator || target == AdmissionOwnerState.Continuation
|
|
552
|
+
|| target == AdmissionOwnerState.Recovery || target == AdmissionOwnerState.TerminalCleanup;
|
|
553
|
+
if (source == AdmissionOwnerState.Coordinator || source == AdmissionOwnerState.Recovery)
|
|
554
|
+
return target == AdmissionOwnerState.TerminalCleanup;
|
|
555
|
+
return false;
|
|
556
|
+
}
|
|
557
|
+
|
|
558
|
+
private static bool CanComplete(AdmissionOwnerState state)
|
|
559
|
+
{
|
|
560
|
+
return state == AdmissionOwnerState.WorkItem || state == AdmissionOwnerState.Continuation || state == AdmissionOwnerState.TerminalCleanup;
|
|
561
|
+
}
|
|
562
|
+
|
|
388
563
|
private static void Append(StringBuilder builder, string value)
|
|
389
564
|
{
|
|
390
565
|
var item = value ?? string.Empty;
|
|
@@ -393,10 +568,25 @@ namespace UnityCli
|
|
|
393
568
|
|
|
394
569
|
private int RemainingGrantMs(AdmissionRecord value) { return checked((int)Math.Max(0, Math.Min(GrantTtlMs, value.GrantExpiresAtMs - monotonicNowMs()))); }
|
|
395
570
|
private static AcquireResult Result(AcquireOutcome outcome, string token = null, int grantExpiresInMs = 0, bool newlyGranted = false) { return new AcquireResult { Outcome = outcome, Token = token, RetryAfterMs = RetryAfterMs, GrantExpiresInMs = grantExpiresInMs, NewlyGranted = newlyGranted }; }
|
|
571
|
+
private static AuthorizeResult Authorized(AuthorizeOutcome outcome, ConsumedIdentity identity = null, bool newlyConsumed = false) { return new AuthorizeResult { Outcome = outcome, Identity = identity, NewlyConsumed = newlyConsumed }; }
|
|
396
572
|
private bool RecordOwnedByPool(AdmissionRecord value) { return value != null && string.Equals(value.InstanceId, instanceId, StringComparison.Ordinal) && string.Equals(value.SessionId, sessionId, StringComparison.Ordinal) && ValidRequestId(value.RequestId) && IsSha256(value.RootFingerprint) && IsToken(value.Token) && ValidListener(value.ListenerId, value.ListenerGeneration); }
|
|
397
|
-
private bool ValidConsumedRecord(AdmissionRecord value) { return RecordOwnedByPool(value) && value.
|
|
398
|
-
private AdmissionRecord Clone(AdmissionRecord value) { return new AdmissionRecord { InstanceId = value.InstanceId, SessionId = value.SessionId, RequestId = value.RequestId, RootFingerprint = value.RootFingerprint, Token = value.Token, ListenerId = value.ListenerId, ListenerGeneration = value.ListenerGeneration, GrantExpiresAtMs = value.GrantExpiresAtMs, ExecutionDeadlineMs = value.ExecutionDeadlineMs,
|
|
573
|
+
private bool ValidConsumedRecord(AdmissionRecord value) { return RecordOwnedByPool(value) && value.Consumed && IsSha256(value.RequestDigest) && Enum.IsDefined(typeof(AdmissionOwnerState), value.OwnerState) && Enum.IsDefined(typeof(AdmissionOwnerState), value.IntendedOwnerState) && value.GrantExpiresAtMs == 0 && value.ExecutionDeadlineMs > 0 && ((value.TransferCommitted && value.OwnerState == value.IntendedOwnerState) || (!value.TransferCommitted && LegalTransfer(value.OwnerState, value.IntendedOwnerState))); }
|
|
574
|
+
private AdmissionRecord Clone(AdmissionRecord value) { return new AdmissionRecord { InstanceId = value.InstanceId, SessionId = value.SessionId, RequestId = value.RequestId, RootFingerprint = value.RootFingerprint, RequestDigest = value.RequestDigest, Token = value.Token, ListenerId = value.ListenerId, ListenerGeneration = value.ListenerGeneration, GrantExpiresAtMs = value.GrantExpiresAtMs, ExecutionDeadlineMs = value.ExecutionDeadlineMs, OwnerState = value.OwnerState, IntendedOwnerState = value.IntendedOwnerState, TransferCommitted = value.TransferCommitted }; }
|
|
399
575
|
private bool ValidRestoredRecord(AdmissionRecord value) { return ValidConsumedRecord(value); }
|
|
576
|
+
private static ConsumedIdentity Identity(AdmissionRecord value) { return new ConsumedIdentity { RequestId = value.RequestId, RootFingerprint = value.RootFingerprint, RequestDigest = value.RequestDigest, Token = value.Token, SessionId = value.SessionId, ListenerId = value.ListenerId, ListenerGeneration = value.ListenerGeneration, ExecutionDeadlineMs = value.ExecutionDeadlineMs, OwnerState = value.OwnerState }; }
|
|
577
|
+
private static bool Matches(AdmissionRecord value, ConsumedIdentity identity) { return MatchesIdentityFields(value, identity) && value.OwnerState == identity.OwnerState; }
|
|
578
|
+
private static bool MatchesIdentityFields(AdmissionRecord value, ConsumedIdentity identity)
|
|
579
|
+
{
|
|
580
|
+
return value != null && identity != null
|
|
581
|
+
&& string.Equals(value.RequestId, identity.RequestId, StringComparison.Ordinal)
|
|
582
|
+
&& string.Equals(value.RootFingerprint, identity.RootFingerprint, StringComparison.Ordinal)
|
|
583
|
+
&& string.Equals(value.RequestDigest, identity.RequestDigest, StringComparison.Ordinal)
|
|
584
|
+
&& FixedEquals(value.Token, identity.Token)
|
|
585
|
+
&& string.Equals(value.SessionId, identity.SessionId, StringComparison.Ordinal)
|
|
586
|
+
&& string.Equals(value.ListenerId, identity.ListenerId, StringComparison.Ordinal)
|
|
587
|
+
&& value.ListenerGeneration == identity.ListenerGeneration
|
|
588
|
+
&& value.ExecutionDeadlineMs == identity.ExecutionDeadlineMs;
|
|
589
|
+
}
|
|
400
590
|
private static bool ValidListener(string listenerId, long generation) { return !string.IsNullOrWhiteSpace(listenerId) && listenerId.Length <= 200 && generation >= 1; }
|
|
401
591
|
|
|
402
592
|
private static string NewToken()
|