@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
package/dist/doctor.js
CHANGED
|
@@ -1,349 +1,377 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* CLI command: doctor
|
|
2
|
+
* CLI control command: doctor.
|
|
3
3
|
*
|
|
4
|
-
*
|
|
5
|
-
*
|
|
6
|
-
* Transport endpoint and listener identity remain internal to instance selection.
|
|
4
|
+
* Registry/Health identity, main-thread pulse, admitted business work, catalog
|
|
5
|
+
* integrity, compilation, and extension installation are independent owners.
|
|
7
6
|
*/
|
|
8
7
|
import { getString } from "./args.js";
|
|
8
|
+
import { Buffer } from "node:buffer";
|
|
9
9
|
import { access, stat } from "node:fs/promises";
|
|
10
|
-
import {
|
|
11
|
-
import {
|
|
12
|
-
import { executeBridgePayload } from "./bridge/index.js";
|
|
10
|
+
import { inspectInstanceHealth, instanceSelectionFailure, obsoleteLocalStatePaths, readInstancesWithRegistryDiagnostics, selectInstanceForFlags, } from "./instances.js";
|
|
11
|
+
import { executeBridgePayload, SessionSupervisor, SessionSupervisorError, } from "./bridge/index.js";
|
|
13
12
|
import { EDITOR_STATE_OBSERVATION_BUDGET_MS } from "./bridge/session-supervisor.js";
|
|
14
|
-
import {
|
|
15
|
-
import { builtinExtensionMetadata } from "./extensions/metadata/index.js";
|
|
16
|
-
import { ExtensionRegistry, extensionAvailabilitySummary } from "./extensions/index.js";
|
|
13
|
+
import { withObservationSelection } from "./bridge/types.js";
|
|
17
14
|
import { extensionAvailabilityFlags } from "./extension-availability.js";
|
|
18
|
-
import {
|
|
19
|
-
import {
|
|
15
|
+
import { readInstalledExtensions } from "./cli-commands/extensions.js";
|
|
16
|
+
import { checkExtensionBundles, readExtensionInstallManifest } from "./extensions/installer.js";
|
|
17
|
+
import { EXTENSION_DIAGNOSTIC_SAMPLE_LIMIT } from "./extensions/state-contract.js";
|
|
18
|
+
import { failure, success } from "./output.js";
|
|
19
|
+
const DOCTOR_BUSINESS_TIMEOUT_MS = 10_000;
|
|
20
|
+
const DOCTOR_BUSINESS_COMPLETION = "doctor-business-read-v1";
|
|
21
|
+
const DOCTOR_CATALOG_IDENTITY = "unity-cli-immutable-domain-catalog";
|
|
22
|
+
const MAX_DOCTOR_CATALOG_TOOLS = 10_000;
|
|
23
|
+
const MAX_DOCTOR_CATALOG_ASSEMBLIES = 100_000;
|
|
24
|
+
const MAX_DOCTOR_CATALOG_RESPONSE_BYTES = 64 * 1024;
|
|
20
25
|
export async function handleDoctorCommand(flags, runtime, requestId) {
|
|
21
26
|
const checks = [];
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
checks.
|
|
34
|
-
}
|
|
35
|
-
|
|
36
|
-
|
|
27
|
+
checks.push(await checkDataDirectory(runtime.dataDir));
|
|
28
|
+
checks.push(await checkObsoleteLocalState(runtime.dataDir));
|
|
29
|
+
const selected = await inspectSelectedHealth(flags, runtime, requestId);
|
|
30
|
+
checks.push(await checkRegistryHealthIdentity(runtime.dataDir, selected));
|
|
31
|
+
checks.push(checkMainThreadPulse(selected));
|
|
32
|
+
checks.push(await checkBusinessDiagnostic(flags, runtime, requestId, selected));
|
|
33
|
+
checks.push(await checkCatalogIntegrity(flags, runtime, requestId, selected));
|
|
34
|
+
checks.push(await checkCompile(flags, runtime, requestId, selected));
|
|
35
|
+
checks.push(await checkExtensions(flags, runtime));
|
|
36
|
+
const summary = checks.some((check) => check.status === "fail")
|
|
37
|
+
? "fail"
|
|
38
|
+
: checks.some((check) => check.status === "warn") ? "warn" : "pass";
|
|
39
|
+
return success(requestId, { summary, checks, suggestions: buildSuggestions(checks) });
|
|
40
|
+
}
|
|
41
|
+
/** selector 与严格 Health v3 只执行一次,后续 check 共享脱敏结果但不共享严重性。 */
|
|
42
|
+
async function inspectSelectedHealth(flags, runtime, requestId) {
|
|
37
43
|
try {
|
|
38
44
|
const selection = await (runtime.selectInstance ?? selectInstanceForFlags)(flags, runtime.dataDir);
|
|
39
|
-
|
|
40
|
-
checks.push(bridgeCheck);
|
|
41
|
-
bridgeReachable = bridgeCheck.status === "pass";
|
|
45
|
+
return { selection, health: await inspectInstanceHealth(selection.instance) };
|
|
42
46
|
}
|
|
43
47
|
catch (error) {
|
|
44
|
-
const
|
|
45
|
-
|
|
46
|
-
checks.push({
|
|
47
|
-
name: "bridge_connectivity",
|
|
48
|
-
status: "warn",
|
|
49
|
-
message: selectionError?.message ?? "No Unity project identity can be selected from --instance or CWD.",
|
|
50
|
-
details: selectionError ? { code: selectionError.code, details: selectionError.details } : undefined,
|
|
51
|
-
});
|
|
52
|
-
}
|
|
53
|
-
// Check 4: Data directory
|
|
54
|
-
checks.push(await checkDataDirectory(runtime.dataDir));
|
|
55
|
-
// Check 5: Configuration integrity and obsolete local state
|
|
56
|
-
checks.push(await checkConfigIntegrity(readyInstances));
|
|
57
|
-
checks.push(await checkObsoleteLocalState(runtime.dataDir));
|
|
58
|
-
const fingerprintCheck = checkBridgeFingerprintStatus(checks);
|
|
59
|
-
if (fingerprintCheck) {
|
|
60
|
-
checks.push(fingerprintCheck);
|
|
61
|
-
}
|
|
62
|
-
const compileCheck = checkCompileStatus(checks);
|
|
63
|
-
if (compileCheck) {
|
|
64
|
-
checks.push(compileCheck);
|
|
48
|
+
const projected = projectDoctorError(`${requestId}_identity`, error);
|
|
49
|
+
return { error: projected };
|
|
65
50
|
}
|
|
66
|
-
// Unified CLI/tools discovery surface
|
|
67
|
-
checks.push(await checkUnifiedDiscovery(flags, runtime, requestId, bridgeReachable));
|
|
68
|
-
// Extension package availability comes from physical project state.
|
|
69
|
-
checks.push(await checkExtensionAvailability(flags, runtime));
|
|
70
|
-
checks.push(checkExtensionRegistry());
|
|
71
|
-
const allPassed = checks.every((c) => c.status === "pass");
|
|
72
|
-
const hasWarnings = checks.some((c) => c.status === "warn");
|
|
73
|
-
const hasFailures = checks.some((c) => c.status === "fail");
|
|
74
|
-
const summary = hasFailures ? "fail" : hasWarnings ? "warn" : "pass";
|
|
75
|
-
const data = {
|
|
76
|
-
summary,
|
|
77
|
-
checks,
|
|
78
|
-
suggestions: buildSuggestions(checks)
|
|
79
|
-
};
|
|
80
|
-
return success(requestId, data);
|
|
81
51
|
}
|
|
82
|
-
async function
|
|
52
|
+
async function checkRegistryHealthIdentity(dataDir, selected) {
|
|
53
|
+
let instanceCount = 0;
|
|
54
|
+
let invalidRecordCount = 0;
|
|
83
55
|
try {
|
|
84
|
-
const
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
name: "instance_registry",
|
|
88
|
-
status: "warn",
|
|
89
|
-
message: `Instance registry contains ${instances.length} valid instance(s) and ignored ${invalidRecordCount} invalid or unreadable record(s).`,
|
|
90
|
-
details: { instanceCount: instances.length, invalidRecordCount },
|
|
91
|
-
};
|
|
92
|
-
}
|
|
93
|
-
if (instances.length === 0) {
|
|
94
|
-
return {
|
|
95
|
-
name: "instance_registry",
|
|
96
|
-
status: "warn",
|
|
97
|
-
message: "Instance registry is empty. No Unity instances registered.",
|
|
98
|
-
details: { instanceCount: 0 }
|
|
99
|
-
};
|
|
100
|
-
}
|
|
101
|
-
return {
|
|
102
|
-
name: "instance_registry",
|
|
103
|
-
status: "pass",
|
|
104
|
-
message: `Instance registry contains ${instances.length} instance(s).`,
|
|
105
|
-
details: { instanceCount: instances.length }
|
|
106
|
-
};
|
|
56
|
+
const registry = await readInstancesWithRegistryDiagnostics(dataDir);
|
|
57
|
+
instanceCount = registry.instances.length;
|
|
58
|
+
invalidRecordCount = registry.invalidRecordCount;
|
|
107
59
|
}
|
|
108
60
|
catch (error) {
|
|
109
61
|
return {
|
|
110
|
-
name: "
|
|
62
|
+
name: "registry_health_identity",
|
|
111
63
|
status: "fail",
|
|
112
|
-
message: `
|
|
64
|
+
message: `Instance registry could not be read: ${errorMessage(error)}`,
|
|
65
|
+
details: { code: "E_INSTANCE_REGISTRY_INVALID" },
|
|
113
66
|
};
|
|
114
67
|
}
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
const unverifiable = instances.filter((instance) => instance.status === "unverifiable");
|
|
119
|
-
const blocked = instances.filter((instance) => instance.status === "blocked");
|
|
120
|
-
if (conflicts.length > 0) {
|
|
68
|
+
if (!selected.selection) {
|
|
69
|
+
const error = selected.error;
|
|
70
|
+
const status = error?.code === "E_INSTANCE_CONFLICT" || error?.code === "E_INSTANCE_UNVERIFIABLE" ? "fail" : "warn";
|
|
121
71
|
return {
|
|
122
|
-
name: "
|
|
123
|
-
status
|
|
124
|
-
message:
|
|
125
|
-
details: {
|
|
72
|
+
name: "registry_health_identity",
|
|
73
|
+
status,
|
|
74
|
+
message: error?.message ?? "No exact Editor identity was selected from Registry v3.",
|
|
75
|
+
details: {
|
|
76
|
+
code: error?.code ?? "E_INSTANCE_REQUIRED",
|
|
77
|
+
instanceCount,
|
|
78
|
+
invalidRecordCount,
|
|
79
|
+
transportVerified: false,
|
|
80
|
+
},
|
|
126
81
|
};
|
|
127
82
|
}
|
|
128
|
-
|
|
83
|
+
const identity = selected.selection.instance;
|
|
84
|
+
if (!selected.health?.transportVerified) {
|
|
129
85
|
return {
|
|
130
|
-
name: "
|
|
86
|
+
name: "registry_health_identity",
|
|
131
87
|
status: "fail",
|
|
132
|
-
message:
|
|
133
|
-
details: {
|
|
88
|
+
message: `Registry v3 selected ${identity.instanceId}, but strict Health v3 transport identity was not verified.`,
|
|
89
|
+
details: {
|
|
90
|
+
code: "BRIDGE_CONNECTION_FAILED",
|
|
91
|
+
instanceId: identity.instanceId,
|
|
92
|
+
canonicalProjectPath: identity.canonicalProjectPath,
|
|
93
|
+
registryStatus: identity.status,
|
|
94
|
+
instanceCount,
|
|
95
|
+
invalidRecordCount,
|
|
96
|
+
transportVerified: false,
|
|
97
|
+
},
|
|
134
98
|
};
|
|
135
99
|
}
|
|
136
|
-
|
|
100
|
+
return {
|
|
101
|
+
name: "registry_health_identity",
|
|
102
|
+
status: invalidRecordCount > 0 ? "warn" : "pass",
|
|
103
|
+
message: invalidRecordCount > 0
|
|
104
|
+
? `Strict Registry/Health identity is verified; ${invalidRecordCount} unrelated invalid registry record(s) were ignored.`
|
|
105
|
+
: "Strict Registry v3 and Health v3 transport identity are verified.",
|
|
106
|
+
details: {
|
|
107
|
+
instanceId: identity.instanceId,
|
|
108
|
+
canonicalProjectPath: identity.canonicalProjectPath,
|
|
109
|
+
editorSessionId: identity.editorSessionId,
|
|
110
|
+
registryStatus: identity.status,
|
|
111
|
+
instanceCount,
|
|
112
|
+
invalidRecordCount,
|
|
113
|
+
transportVerified: true,
|
|
114
|
+
},
|
|
115
|
+
};
|
|
116
|
+
}
|
|
117
|
+
function checkMainThreadPulse(selected) {
|
|
118
|
+
const pulse = selected.health?.mainThread;
|
|
119
|
+
if (!selected.health?.transportVerified || !pulse) {
|
|
137
120
|
return {
|
|
138
|
-
name: "
|
|
121
|
+
name: "main_thread_pulse",
|
|
139
122
|
status: "warn",
|
|
140
|
-
message: "
|
|
141
|
-
details: {
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
123
|
+
message: "Main-thread pulse could not be evaluated independently of transport identity.",
|
|
124
|
+
details: { code: "E_MAIN_THREAD_PULSE_UNAVAILABLE", observed: false, fresh: false },
|
|
125
|
+
};
|
|
126
|
+
}
|
|
127
|
+
if (!pulse.fresh) {
|
|
128
|
+
return {
|
|
129
|
+
name: "main_thread_pulse",
|
|
130
|
+
status: "warn",
|
|
131
|
+
message: `Health v3 transport is reachable, but the Editor main-thread pulse is stale or absent (${pulse.lifecycle}).`,
|
|
132
|
+
details: { code: "E_MAIN_THREAD_UNRESPONSIVE", ...pulse },
|
|
148
133
|
};
|
|
149
134
|
}
|
|
150
135
|
return {
|
|
151
|
-
name: "
|
|
152
|
-
status: "pass",
|
|
153
|
-
message:
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
instanceId: instance.instanceId,
|
|
158
|
-
canonicalProjectPath: instance.canonicalProjectPath,
|
|
159
|
-
editorSessionId: instance.editorSessionId,
|
|
160
|
-
publishedAt: instance.publishedAt,
|
|
161
|
-
}))
|
|
162
|
-
}
|
|
136
|
+
name: "main_thread_pulse",
|
|
137
|
+
status: pulse.lifecycle === "ready" ? "pass" : "warn",
|
|
138
|
+
message: pulse.lifecycle === "ready"
|
|
139
|
+
? "The read-only Editor main-thread pulse is fresh."
|
|
140
|
+
: `The main-thread pulse is fresh while the Editor lifecycle is ${pulse.lifecycle}.`,
|
|
141
|
+
details: { ...pulse },
|
|
163
142
|
};
|
|
164
143
|
}
|
|
165
|
-
|
|
144
|
+
/** 此 check 独占 admission;其失败不得改写 Registry/Health check。 */
|
|
145
|
+
async function checkBusinessDiagnostic(flags, runtime, requestId, selected) {
|
|
146
|
+
if (!selected.selection || !selected.health?.transportVerified || !selected.health.mainThread?.fresh) {
|
|
147
|
+
return skippedLiveCheck("business_diagnostic", "E_BUSINESS_DIAGNOSTIC_SKIPPED", "Business diagnostic was skipped because an exact fresh Editor session was not available.");
|
|
148
|
+
}
|
|
149
|
+
const childRequestId = `${requestId}_doctor_business`;
|
|
150
|
+
const input = {};
|
|
151
|
+
const selectedFlags = { ...flags, instance: selected.selection.instance.instanceId };
|
|
152
|
+
const supervisor = new SessionSupervisor(selectedFlags, runtime);
|
|
153
|
+
let admission;
|
|
166
154
|
try {
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
155
|
+
admission = await supervisor.acquireRootAdmission({
|
|
156
|
+
requestId: childRequestId,
|
|
157
|
+
command: "internal.doctor.business",
|
|
158
|
+
input,
|
|
159
|
+
dryRun: false,
|
|
160
|
+
target: "editor",
|
|
161
|
+
completionContractIdentity: DOCTOR_BUSINESS_COMPLETION,
|
|
162
|
+
timeoutMs: DOCTOR_BUSINESS_TIMEOUT_MS,
|
|
163
|
+
admissionAbsoluteDeadlineMs: Date.now() + DOCTOR_BUSINESS_TIMEOUT_MS,
|
|
164
|
+
});
|
|
165
|
+
const result = await executeBridgePayload(childRequestId, "internal.doctor.business", input, selectedFlags, { ...runtime, rootAdmission: admission }, { mode: "read", mutation: false, absoluteDeadlineMs: admission.executionAbsoluteDeadlineMs });
|
|
166
|
+
if (!result.ok)
|
|
167
|
+
return failedLiveCheck("business_diagnostic", result.error);
|
|
168
|
+
const data = record(result.data);
|
|
169
|
+
if (data?.accepted !== true || typeof data.sceneLoaded !== "boolean" || typeof data.projectPath !== "string") {
|
|
170
|
+
return invalidLiveCheck("business_diagnostic", "Business diagnostic returned an invalid DTO.");
|
|
182
171
|
}
|
|
183
172
|
return {
|
|
184
|
-
name: "
|
|
185
|
-
status: "
|
|
186
|
-
message:
|
|
187
|
-
details: {
|
|
173
|
+
name: "business_diagnostic",
|
|
174
|
+
status: "pass",
|
|
175
|
+
message: "An admission-bound read reached the Editor business layer.",
|
|
176
|
+
details: {
|
|
177
|
+
accepted: true,
|
|
178
|
+
projectPath: data.projectPath,
|
|
179
|
+
sceneLoaded: data.sceneLoaded,
|
|
180
|
+
activeScenePath: typeof data.activeScenePath === "string" ? data.activeScenePath : "",
|
|
181
|
+
playMode: data.playMode === true,
|
|
182
|
+
},
|
|
188
183
|
};
|
|
189
184
|
}
|
|
190
185
|
catch (error) {
|
|
191
|
-
return
|
|
192
|
-
name: "bridge_connectivity",
|
|
193
|
-
status: "fail",
|
|
194
|
-
message: `Cannot reach bridge for ${instanceId}: ${error instanceof Error ? error.message : String(error)}`,
|
|
195
|
-
details: { instanceId, error: error instanceof Error ? error.message : String(error) }
|
|
196
|
-
};
|
|
186
|
+
return failedLiveCheck("business_diagnostic", projectDoctorError(childRequestId, error));
|
|
197
187
|
}
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
const bridgeResponse = bridgeCheck?.details?.bridgeResponse;
|
|
202
|
-
if (!bridgeResponse || typeof bridgeResponse !== "object") {
|
|
203
|
-
return undefined;
|
|
188
|
+
finally {
|
|
189
|
+
if (admission)
|
|
190
|
+
await supervisor.completeRootAdmission(admission);
|
|
204
191
|
}
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
192
|
+
}
|
|
193
|
+
async function checkCatalogIntegrity(flags, runtime, requestId, selected) {
|
|
194
|
+
const result = await privateDoctorRead("catalog_integrity", "internal.doctor.catalog", flags, runtime, requestId, selected);
|
|
195
|
+
if (isDoctorCheck(result)) {
|
|
196
|
+
return result.details?.code === "E_TOOL_REGISTRY_UNHEALTHY" ? { ...result, status: "fail" } : result;
|
|
209
197
|
}
|
|
210
|
-
const
|
|
211
|
-
|
|
212
|
-
|
|
198
|
+
const data = doctorCatalogData(result.data);
|
|
199
|
+
if (!data)
|
|
200
|
+
return invalidLiveCheck("catalog_integrity", "Catalog integrity read returned an invalid bounded DTO.");
|
|
213
201
|
return {
|
|
214
|
-
name: "
|
|
215
|
-
status,
|
|
216
|
-
message:
|
|
217
|
-
|
|
218
|
-
:
|
|
219
|
-
|
|
202
|
+
name: "catalog_integrity",
|
|
203
|
+
status: "pass",
|
|
204
|
+
message: `The immutable domain catalog contains ${data.toolCount} registered Tool(s).`,
|
|
205
|
+
details: {
|
|
206
|
+
identity: data.identity,
|
|
207
|
+
toolCount: data.toolCount,
|
|
208
|
+
providerCounts: data.providerCounts,
|
|
209
|
+
publicationDiagnostics: data.publicationDiagnostics,
|
|
210
|
+
},
|
|
220
211
|
};
|
|
221
212
|
}
|
|
222
|
-
function
|
|
223
|
-
const
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
213
|
+
async function checkCompile(flags, runtime, requestId, selected) {
|
|
214
|
+
const result = await privateDoctorRead("compile", "internal.doctor.compile", flags, runtime, requestId, selected);
|
|
215
|
+
if (isDoctorCheck(result))
|
|
216
|
+
return result;
|
|
217
|
+
const data = record(result.data);
|
|
218
|
+
const errors = Array.isArray(data?.compileErrors) && data.compileErrors.every((value) => typeof value === "string")
|
|
219
|
+
? data.compileErrors : undefined;
|
|
220
|
+
const nextActions = Array.isArray(data?.nextActions) && data.nextActions.every((value) => typeof value === "string")
|
|
221
|
+
? data.nextActions : undefined;
|
|
222
|
+
if (!data || typeof data.compiling !== "boolean" || typeof data.scanComplete !== "boolean"
|
|
223
|
+
|| typeof data.hasCompileErrors !== "boolean" || !isNonNegativeInteger(data.compileErrorCount)
|
|
224
|
+
|| typeof data.compileErrorsTruncated !== "boolean" || !errors || errors.length > 20 || !nextActions) {
|
|
225
|
+
return invalidLiveCheck("compile", "Compile diagnostic returned an invalid bounded DTO.");
|
|
231
226
|
}
|
|
232
|
-
const
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
const compiling = compile.compiling === true;
|
|
237
|
-
const hasErrors = compile.hasCompileErrors === true;
|
|
238
|
-
const errors = Array.isArray(compile.compileErrors) ? compile.compileErrors.filter((e) => typeof e === "string") : [];
|
|
239
|
-
const status = hasErrors ? "fail" : compiling ? "warn" : "pass";
|
|
240
|
-
const message = hasErrors
|
|
241
|
-
? `Unity has compile errors (${errors.length} shown). Often caused by a broken extension under Packages/com.alpsckr.unitycli/Extensions.`
|
|
242
|
-
: compiling
|
|
243
|
-
? "Unity is currently compiling scripts."
|
|
244
|
-
: "Unity scripts compiled cleanly.";
|
|
227
|
+
const status = data.hasCompileErrors ? "fail" : data.compiling || !data.scanComplete ? "warn" : "pass";
|
|
228
|
+
const code = data.hasCompileErrors ? "E_UNITY_COMPILE_FAILED"
|
|
229
|
+
: data.compiling ? "E_UNITY_COMPILING"
|
|
230
|
+
: !data.scanComplete ? "E_COMPILE_DIAGNOSTICS_INCOMPLETE" : undefined;
|
|
245
231
|
return {
|
|
246
|
-
name: "
|
|
232
|
+
name: "compile",
|
|
247
233
|
status,
|
|
248
|
-
message
|
|
249
|
-
|
|
234
|
+
message: data.hasCompileErrors
|
|
235
|
+
? `Unity reports ${data.compileErrorCount} compiler error(s).`
|
|
236
|
+
: data.compiling ? "Unity is compiling scripts."
|
|
237
|
+
: !data.scanComplete ? "Compile diagnostics were not scanned completely."
|
|
238
|
+
: "Unity scripts are not compiling and no compiler errors were found.",
|
|
239
|
+
details: {
|
|
240
|
+
...(code ? { code } : {}),
|
|
241
|
+
compiling: data.compiling,
|
|
242
|
+
scanComplete: data.scanComplete,
|
|
243
|
+
hasCompileErrors: data.hasCompileErrors,
|
|
244
|
+
compileErrorCount: data.compileErrorCount,
|
|
245
|
+
compileErrorsTruncated: data.compileErrorsTruncated,
|
|
246
|
+
compileErrors: errors,
|
|
247
|
+
nextActions,
|
|
248
|
+
},
|
|
250
249
|
};
|
|
251
250
|
}
|
|
252
|
-
function
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
}
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
return typeof raw === "string" ? raw : undefined;
|
|
251
|
+
async function privateDoctorRead(checkName, command, flags, runtime, requestId, selected) {
|
|
252
|
+
if (!selected.selection || !selected.health?.transportVerified || !selected.health.mainThread?.fresh) {
|
|
253
|
+
return skippedLiveCheck(checkName, "E_DOCTOR_READ_SKIPPED", `${checkName} was skipped because an exact fresh Editor session was not available.`);
|
|
254
|
+
}
|
|
255
|
+
const result = await executeBridgePayload(`${requestId}_${checkName}`, command, {}, { ...flags, instance: selected.selection.instance.instanceId }, runtime, withObservationSelection({ mode: "observeNow", mutation: false, defaultTimeoutMs: EDITOR_STATE_OBSERVATION_BUDGET_MS }, selected.selection));
|
|
256
|
+
return result.ok ? { data: result.data } : failedLiveCheck(checkName, result.error);
|
|
259
257
|
}
|
|
260
|
-
async function
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
if (!stats.isDirectory()) {
|
|
265
|
-
return { name: "data_directory", status: "fail", message: `Data path is not a directory: ${dataDir}` };
|
|
266
|
-
}
|
|
258
|
+
async function checkExtensions(flags, runtime) {
|
|
259
|
+
const resolvedFlags = await extensionAvailabilityFlags(flags, runtime);
|
|
260
|
+
const projectPath = getString(resolvedFlags, "project");
|
|
261
|
+
if (!projectPath) {
|
|
267
262
|
return {
|
|
268
|
-
name: "
|
|
269
|
-
status: "
|
|
270
|
-
message:
|
|
271
|
-
details: {
|
|
263
|
+
name: "extensions",
|
|
264
|
+
status: "warn",
|
|
265
|
+
message: "Extension installation state is unknown because no project path was resolved.",
|
|
266
|
+
details: { code: "PROJECT_PATH_REQUIRED", projectResolved: false },
|
|
272
267
|
};
|
|
273
268
|
}
|
|
274
|
-
|
|
275
|
-
const
|
|
276
|
-
|
|
269
|
+
try {
|
|
270
|
+
const [enabled, manifest, physical] = await Promise.all([
|
|
271
|
+
readInstalledExtensions(projectPath),
|
|
272
|
+
readExtensionInstallManifest(projectPath),
|
|
273
|
+
checkExtensionBundles(projectPath),
|
|
274
|
+
]);
|
|
275
|
+
const installedEntries = new Set(manifest.extensions.map((entry) => entry.extensionId));
|
|
276
|
+
const knownIds = new Set(physical.map((entry) => entry.extensionId));
|
|
277
|
+
const unknownInstalled = manifest.extensions.map((entry) => entry.extensionId).filter((id) => !knownIds.has(id));
|
|
278
|
+
const unknownEnabled = [...enabled].filter((id) => !knownIds.has(id));
|
|
279
|
+
const broken = physical.filter((entry) => (enabled.has(entry.extensionId) || installedEntries.has(entry.extensionId)) && !entry.installed);
|
|
280
|
+
const optional = physical.filter((entry) => !enabled.has(entry.extensionId) && !installedEntries.has(entry.extensionId));
|
|
281
|
+
const healthyInstalled = physical.filter((entry) => entry.installed).length;
|
|
282
|
+
if (unknownInstalled.length > 0 || unknownEnabled.length > 0 || broken.length > 0) {
|
|
283
|
+
const missingDependency = broken.some((entry) => entry.status === "missing_dependency");
|
|
284
|
+
const code = unknownInstalled.length > 0 ? "E_EXTENSION_UNKNOWN_INSTALLED"
|
|
285
|
+
: unknownEnabled.length > 0 ? "E_EXTENSION_STATE_INVALID"
|
|
286
|
+
: missingDependency ? "E_EXTENSION_DEPENDENCY_MISSING" : "E_EXTENSION_TARGET_PROJECTION_INVALID";
|
|
287
|
+
const nextActions = unknownInstalled.length > 0
|
|
288
|
+
? ["Inspect unitycli.extensions.manifest.json and the matching extension directories.", "Remove unknown installed entries only after auditing their projected files."]
|
|
289
|
+
: unknownEnabled.length > 0
|
|
290
|
+
? ["Inspect extensions.json and remove IDs that are not present in the CLI extension registry."]
|
|
291
|
+
: [...new Set(broken.flatMap((entry) => entry.nextActions))];
|
|
277
292
|
return {
|
|
278
|
-
name: "
|
|
293
|
+
name: "extensions",
|
|
294
|
+
status: "fail",
|
|
295
|
+
message: `${broken.length + unknownInstalled.length + unknownEnabled.length} installed or enabled extension state(s) are broken.`,
|
|
296
|
+
details: {
|
|
297
|
+
code,
|
|
298
|
+
projectPath,
|
|
299
|
+
healthyInstalled,
|
|
300
|
+
optionalUninstalled: optional.length,
|
|
301
|
+
unknownInstalledCount: unknownInstalled.length,
|
|
302
|
+
unknownInstalled: unknownInstalled.slice(0, EXTENSION_DIAGNOSTIC_SAMPLE_LIMIT),
|
|
303
|
+
unknownInstalledTruncated: unknownInstalled.length > EXTENSION_DIAGNOSTIC_SAMPLE_LIMIT,
|
|
304
|
+
unknownEnabledCount: unknownEnabled.length,
|
|
305
|
+
unknownEnabled: unknownEnabled.slice(0, EXTENSION_DIAGNOSTIC_SAMPLE_LIMIT),
|
|
306
|
+
unknownEnabledTruncated: unknownEnabled.length > EXTENSION_DIAGNOSTIC_SAMPLE_LIMIT,
|
|
307
|
+
brokenCount: broken.length,
|
|
308
|
+
broken: broken.slice(0, EXTENSION_DIAGNOSTIC_SAMPLE_LIMIT).map(extensionDiagnostic),
|
|
309
|
+
brokenTruncated: broken.length > EXTENSION_DIAGNOSTIC_SAMPLE_LIMIT,
|
|
310
|
+
nextActions,
|
|
311
|
+
},
|
|
312
|
+
};
|
|
313
|
+
}
|
|
314
|
+
if (optional.length > 0) {
|
|
315
|
+
return {
|
|
316
|
+
name: "extensions",
|
|
279
317
|
status: "warn",
|
|
280
|
-
message:
|
|
281
|
-
details: {
|
|
318
|
+
message: `${optional.length} optional extension(s) are not installed; no installed or enabled extension is broken.`,
|
|
319
|
+
details: {
|
|
320
|
+
projectPath,
|
|
321
|
+
healthyInstalled,
|
|
322
|
+
optionalUninstalled: optional.length,
|
|
323
|
+
optional: optional.slice(0, EXTENSION_DIAGNOSTIC_SAMPLE_LIMIT).map((entry) => ({
|
|
324
|
+
extensionId: entry.extensionId,
|
|
325
|
+
status: entry.status,
|
|
326
|
+
missingPackageIds: entry.missingPackageIds,
|
|
327
|
+
})),
|
|
328
|
+
optionalTruncated: optional.length > EXTENSION_DIAGNOSTIC_SAMPLE_LIMIT,
|
|
329
|
+
},
|
|
282
330
|
};
|
|
283
331
|
}
|
|
284
332
|
return {
|
|
285
|
-
name: "
|
|
286
|
-
status: "
|
|
287
|
-
message: `
|
|
288
|
-
|
|
289
|
-
}
|
|
290
|
-
}
|
|
291
|
-
async function checkUnifiedDiscovery(flags, runtime, requestId, bridgeReachable) {
|
|
292
|
-
if (!bridgeReachable && runtime.projectTools === undefined) {
|
|
293
|
-
return {
|
|
294
|
-
name: "unified_tool_discovery",
|
|
295
|
-
status: "warn",
|
|
296
|
-
message: "Tool discovery is unavailable because no Unity instance is connected.",
|
|
297
|
-
details: { mode: "unavailable", toolCount: 0 }
|
|
333
|
+
name: "extensions",
|
|
334
|
+
status: "pass",
|
|
335
|
+
message: `All ${healthyInstalled} installed extension(s) passed physical and dependency checks.`,
|
|
336
|
+
details: { projectPath, healthyInstalled, optionalUninstalled: 0 },
|
|
298
337
|
};
|
|
299
338
|
}
|
|
300
|
-
|
|
301
|
-
|
|
339
|
+
catch (error) {
|
|
340
|
+
const projected = projectDoctorError("doctor_extensions", error);
|
|
302
341
|
return {
|
|
303
|
-
name: "
|
|
304
|
-
status: "
|
|
305
|
-
message:
|
|
306
|
-
details: {
|
|
342
|
+
name: "extensions",
|
|
343
|
+
status: "fail",
|
|
344
|
+
message: projected.message,
|
|
345
|
+
details: { code: projected.code, projectPath, nextActions: projected.nextActions },
|
|
307
346
|
};
|
|
308
347
|
}
|
|
309
|
-
|
|
348
|
+
}
|
|
349
|
+
function extensionDiagnostic(entry) {
|
|
310
350
|
return {
|
|
311
|
-
|
|
312
|
-
status:
|
|
313
|
-
|
|
314
|
-
|
|
351
|
+
extensionId: entry.extensionId,
|
|
352
|
+
status: entry.status,
|
|
353
|
+
dependencyInstalled: entry.dependencyInstalled,
|
|
354
|
+
missingPackageIds: entry.missingPackageIds,
|
|
355
|
+
missingFileCount: entry.missingFiles.length,
|
|
356
|
+
changedFileCount: entry.changedFiles.length,
|
|
357
|
+
unknownFileCount: entry.unknownFiles.length,
|
|
358
|
+
nextActions: entry.nextActions,
|
|
315
359
|
};
|
|
316
360
|
}
|
|
317
|
-
async function
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
if (
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
if (!instance.canonicalProjectPath)
|
|
325
|
-
issues.push(`Instance ${instance.instanceId}: missing canonicalProjectPath.`);
|
|
326
|
-
if (!instance.editorSessionId)
|
|
327
|
-
issues.push(`Instance ${instance.instanceId}: missing editorSessionId.`);
|
|
328
|
-
if (!instance.publishedAt)
|
|
329
|
-
issues.push(`Instance ${instance.instanceId}: missing publishedAt.`);
|
|
361
|
+
async function checkDataDirectory(dataDir) {
|
|
362
|
+
try {
|
|
363
|
+
await access(dataDir);
|
|
364
|
+
if (!(await stat(dataDir)).isDirectory()) {
|
|
365
|
+
return { name: "data_directory", status: "fail", message: `Data path is not a directory: ${dataDir}`, details: { code: "E_DATA_DIRECTORY_INVALID" } };
|
|
366
|
+
}
|
|
367
|
+
return { name: "data_directory", status: "pass", message: `Data directory exists: ${dataDir}`, details: { dataDir } };
|
|
330
368
|
}
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
name: "
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
details: { issues }
|
|
337
|
-
};
|
|
369
|
+
catch (error) {
|
|
370
|
+
if (error.code === "ENOENT") {
|
|
371
|
+
return { name: "data_directory", status: "warn", message: `Data directory does not exist yet: ${dataDir}.`, details: { dataDir } };
|
|
372
|
+
}
|
|
373
|
+
return { name: "data_directory", status: "fail", message: `Cannot access data directory: ${errorMessage(error)}`, details: { code: "E_DATA_DIRECTORY_INVALID" } };
|
|
338
374
|
}
|
|
339
|
-
return {
|
|
340
|
-
name: "config_integrity",
|
|
341
|
-
status: "pass",
|
|
342
|
-
message: readyInstances.length > 0
|
|
343
|
-
? `${readyInstances.length} instance(s) passed v3 identity checks.`
|
|
344
|
-
: "No ready instances to check.",
|
|
345
|
-
details: { checkedInstances: readyInstances.length }
|
|
346
|
-
};
|
|
347
375
|
}
|
|
348
376
|
/** 旧 active-target/alias/aggregate 文件只报告,不解析、不迁移。 */
|
|
349
377
|
async function checkObsoleteLocalState(dataDir) {
|
|
@@ -357,142 +385,145 @@ async function checkObsoleteLocalState(dataDir) {
|
|
|
357
385
|
details: { code: "E_OBSOLETE_LOCAL_STATE", paths },
|
|
358
386
|
};
|
|
359
387
|
}
|
|
360
|
-
|
|
361
|
-
const
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
const registry = new ExtensionRegistry();
|
|
372
|
-
let installedPackages;
|
|
373
|
-
try {
|
|
374
|
-
installedPackages = await readInstalledUnityPackages(projectPath);
|
|
375
|
-
}
|
|
376
|
-
catch {
|
|
377
|
-
return {
|
|
378
|
-
name: "extension_availability",
|
|
379
|
-
status: "warn",
|
|
380
|
-
message: `Cannot read Unity packages from project: ${projectPath}.`,
|
|
381
|
-
details: { projectPath }
|
|
382
|
-
};
|
|
383
|
-
}
|
|
384
|
-
const summary = extensionAvailabilitySummary(registry, installedPackages);
|
|
385
|
-
const unavailableExtensions = summary.extensions.filter((e) => e.status === "unavailable");
|
|
386
|
-
const unknownExtensions = summary.extensions.filter((e) => e.status === "unknown");
|
|
387
|
-
if (unavailableExtensions.length > 0) {
|
|
388
|
-
return {
|
|
389
|
-
name: "extension_availability",
|
|
390
|
-
status: "fail",
|
|
391
|
-
message: `${unavailableExtensions.length} extension(s) have missing Unity package dependencies: ${unavailableExtensions.map((e) => e.name + " (missing: " + e.missingPackages.join(", ") + ")").join("; ")}.`,
|
|
392
|
-
details: {
|
|
393
|
-
projectPath,
|
|
394
|
-
projectResolved: true,
|
|
395
|
-
total: summary.total,
|
|
396
|
-
available: summary.available,
|
|
397
|
-
unavailable: summary.unavailable,
|
|
398
|
-
unknown: summary.unknown,
|
|
399
|
-
unavailableExtensions,
|
|
400
|
-
unknownExtensions
|
|
401
|
-
}
|
|
402
|
-
};
|
|
403
|
-
}
|
|
404
|
-
if (unknownExtensions.length > 0) {
|
|
405
|
-
return {
|
|
406
|
-
name: "extension_availability",
|
|
407
|
-
status: "warn",
|
|
408
|
-
message: `${unknownExtensions.length} extension(s) could not be resolved (no installed packages data): ${unknownExtensions.map((e) => e.name).join(", ")}.`,
|
|
409
|
-
details: {
|
|
410
|
-
projectPath,
|
|
411
|
-
projectResolved: true,
|
|
412
|
-
total: summary.total,
|
|
413
|
-
available: summary.available,
|
|
414
|
-
unavailable: summary.unavailable,
|
|
415
|
-
unknown: summary.unknown
|
|
416
|
-
}
|
|
417
|
-
};
|
|
388
|
+
function projectDoctorError(requestId, error) {
|
|
389
|
+
const selected = instanceSelectionFailure(requestId, error);
|
|
390
|
+
if (selected && !selected.ok)
|
|
391
|
+
return selected.error;
|
|
392
|
+
if (error instanceof SessionSupervisorError) {
|
|
393
|
+
const projected = failure(requestId, error.code, error.message, error.nextActions, undefined, {
|
|
394
|
+
transient: error.transient,
|
|
395
|
+
retryAfterMs: error.retryAfterMs,
|
|
396
|
+
});
|
|
397
|
+
if (!projected.ok)
|
|
398
|
+
return projected.error;
|
|
418
399
|
}
|
|
400
|
+
const code = typeof error === "object" && error !== null && "code" in error && typeof error.code === "string"
|
|
401
|
+
? error.code : "BRIDGE_CONNECTION_FAILED";
|
|
402
|
+
const nextActions = typeof error === "object" && error !== null && "nextActions" in error && Array.isArray(error.nextActions)
|
|
403
|
+
? error.nextActions : ["Run unitycli instances list and inspect the selected Editor session."];
|
|
404
|
+
const projected = failure(requestId, code, errorMessage(error), nextActions);
|
|
405
|
+
if (!projected.ok)
|
|
406
|
+
return projected.error;
|
|
407
|
+
throw new Error("Doctor error projection unexpectedly succeeded.");
|
|
408
|
+
}
|
|
409
|
+
function failedLiveCheck(name, error) {
|
|
419
410
|
return {
|
|
420
|
-
name
|
|
421
|
-
status: "
|
|
422
|
-
message:
|
|
411
|
+
name,
|
|
412
|
+
status: error.transient ? "warn" : "fail",
|
|
413
|
+
message: `${error.code}: ${error.message}`,
|
|
423
414
|
details: {
|
|
424
|
-
|
|
425
|
-
|
|
426
|
-
|
|
427
|
-
|
|
428
|
-
|
|
429
|
-
unknown: summary.unknown,
|
|
430
|
-
extensions: summary.extensions
|
|
431
|
-
}
|
|
415
|
+
code: error.code,
|
|
416
|
+
transient: error.transient,
|
|
417
|
+
retryAfterMs: error.retryAfterMs,
|
|
418
|
+
nextActions: error.nextActions,
|
|
419
|
+
},
|
|
432
420
|
};
|
|
433
421
|
}
|
|
434
|
-
function
|
|
435
|
-
|
|
436
|
-
|
|
437
|
-
|
|
422
|
+
function skippedLiveCheck(name, code, message) {
|
|
423
|
+
return { name, status: "warn", message, details: { code } };
|
|
424
|
+
}
|
|
425
|
+
function invalidLiveCheck(name, message) {
|
|
426
|
+
return { name, status: "fail", message, details: { code: "E_BRIDGE_RESPONSE_INVALID" } };
|
|
427
|
+
}
|
|
428
|
+
function isDoctorCheck(value) {
|
|
429
|
+
return "status" in value && "name" in value;
|
|
430
|
+
}
|
|
431
|
+
function isNonNegativeInteger(value) {
|
|
432
|
+
return typeof value === "number" && Number.isSafeInteger(value) && value >= 0;
|
|
433
|
+
}
|
|
434
|
+
/** catalog DTO 只接受唯一 published snapshot 的 aggregate,并校验 count parity 与固定 publication 边界。 */
|
|
435
|
+
function doctorCatalogData(value) {
|
|
436
|
+
const data = exactRecord(value, ["identity", "toolCount", "providerCounts", "publicationDiagnostics"]);
|
|
437
|
+
if (!data)
|
|
438
|
+
return undefined;
|
|
439
|
+
const providerCounts = exactRecord(data.providerCounts, ["builtIn", "extension", "projectInterface", "officialAttribute"]);
|
|
440
|
+
const publication = exactRecord(data.publicationDiagnostics, [
|
|
441
|
+
"assemblyCount", "providerAssemblyCount", "elapsedMilliseconds", "discoveryPassCount",
|
|
442
|
+
"providerMetadataReadCount", "aggregateSuccessLogCount",
|
|
443
|
+
]);
|
|
444
|
+
const serialized = JSON.stringify(data);
|
|
445
|
+
const toolCount = data.toolCount;
|
|
446
|
+
if (!providerCounts || !publication || serialized === undefined
|
|
447
|
+
|| Buffer.byteLength(serialized, "utf8") > MAX_DOCTOR_CATALOG_RESPONSE_BYTES
|
|
448
|
+
|| data.identity !== DOCTOR_CATALOG_IDENTITY
|
|
449
|
+
|| !isNonNegativeInteger(toolCount) || toolCount > MAX_DOCTOR_CATALOG_TOOLS)
|
|
450
|
+
return undefined;
|
|
451
|
+
if (!isNonNegativeInteger(providerCounts.builtIn) || !isNonNegativeInteger(providerCounts.extension)
|
|
452
|
+
|| !isNonNegativeInteger(providerCounts.projectInterface) || !isNonNegativeInteger(providerCounts.officialAttribute))
|
|
453
|
+
return undefined;
|
|
454
|
+
const typedProviderCounts = {
|
|
455
|
+
builtIn: providerCounts.builtIn,
|
|
456
|
+
extension: providerCounts.extension,
|
|
457
|
+
projectInterface: providerCounts.projectInterface,
|
|
458
|
+
officialAttribute: providerCounts.officialAttribute,
|
|
459
|
+
};
|
|
460
|
+
if (Object.values(typedProviderCounts).some((count) => count > toolCount)
|
|
461
|
+
|| Object.values(typedProviderCounts).reduce((sum, count) => sum + count, 0) !== toolCount
|
|
462
|
+
|| !isNonNegativeInteger(publication.assemblyCount) || publication.assemblyCount > MAX_DOCTOR_CATALOG_ASSEMBLIES
|
|
463
|
+
|| !isNonNegativeInteger(publication.providerAssemblyCount) || publication.providerAssemblyCount > publication.assemblyCount
|
|
464
|
+
|| !isNonNegativeInteger(publication.elapsedMilliseconds)
|
|
465
|
+
|| publication.discoveryPassCount !== 1
|
|
466
|
+
|| publication.providerMetadataReadCount !== publication.providerAssemblyCount
|
|
467
|
+
|| publication.aggregateSuccessLogCount !== 1)
|
|
468
|
+
return undefined;
|
|
469
|
+
const typedPublication = {
|
|
470
|
+
assemblyCount: publication.assemblyCount,
|
|
471
|
+
providerAssemblyCount: publication.providerAssemblyCount,
|
|
472
|
+
elapsedMilliseconds: publication.elapsedMilliseconds,
|
|
473
|
+
discoveryPassCount: publication.discoveryPassCount,
|
|
474
|
+
providerMetadataReadCount: publication.providerMetadataReadCount,
|
|
475
|
+
aggregateSuccessLogCount: publication.aggregateSuccessLogCount,
|
|
476
|
+
};
|
|
438
477
|
return {
|
|
439
|
-
|
|
440
|
-
|
|
441
|
-
|
|
442
|
-
|
|
478
|
+
identity: DOCTOR_CATALOG_IDENTITY,
|
|
479
|
+
toolCount,
|
|
480
|
+
providerCounts: typedProviderCounts,
|
|
481
|
+
publicationDiagnostics: typedPublication,
|
|
443
482
|
};
|
|
444
483
|
}
|
|
484
|
+
function exactRecord(value, fields) {
|
|
485
|
+
const item = record(value);
|
|
486
|
+
if (!item)
|
|
487
|
+
return undefined;
|
|
488
|
+
const allowed = new Set(fields);
|
|
489
|
+
const keys = Object.keys(item);
|
|
490
|
+
return keys.length === fields.length && keys.every((key) => allowed.has(key)) ? item : undefined;
|
|
491
|
+
}
|
|
492
|
+
function record(value) {
|
|
493
|
+
return value && typeof value === "object" && !Array.isArray(value) ? value : undefined;
|
|
494
|
+
}
|
|
495
|
+
function errorMessage(error) {
|
|
496
|
+
return error instanceof Error ? error.message : String(error);
|
|
497
|
+
}
|
|
445
498
|
function buildSuggestions(checks) {
|
|
446
499
|
const suggestions = [];
|
|
447
500
|
for (const check of checks) {
|
|
448
|
-
if (check.status === "
|
|
449
|
-
|
|
450
|
-
|
|
451
|
-
|
|
452
|
-
|
|
453
|
-
|
|
454
|
-
|
|
455
|
-
|
|
456
|
-
|
|
457
|
-
|
|
458
|
-
|
|
459
|
-
|
|
460
|
-
|
|
461
|
-
|
|
462
|
-
|
|
463
|
-
|
|
464
|
-
|
|
465
|
-
|
|
466
|
-
|
|
467
|
-
|
|
468
|
-
|
|
469
|
-
|
|
470
|
-
|
|
471
|
-
|
|
472
|
-
suggestions.push("Re-initialize the canonical registry claim by restarting Unity Editor.");
|
|
473
|
-
break;
|
|
474
|
-
case "obsolete_local_state":
|
|
475
|
-
suggestions.push("Delete only the reported obsolete config.json, aliases.json, or aggregate instances.json files after auditing them.");
|
|
476
|
-
break;
|
|
477
|
-
case "unified_tool_discovery":
|
|
478
|
-
suggestions.push("Run unitycli tools group to see tool groups.");
|
|
479
|
-
suggestions.push("Run unitycli tools group list <group> with a connected Unity instance to inspect its complete Tool descriptors.");
|
|
480
|
-
break;
|
|
481
|
-
case "extension_registry":
|
|
482
|
-
suggestions.push("Run unitycli extensions list to see available extensions.");
|
|
483
|
-
suggestions.push("Run unitycli extensions doctor to check extension status.");
|
|
484
|
-
break;
|
|
485
|
-
case "extension_availability":
|
|
486
|
-
suggestions.push("Run 'unitycli extensions doctor --project <path>' for detailed extension diagnostics.");
|
|
487
|
-
suggestions.push("Run 'unitycli extensions list --project <path>' to see all extensions and their status.");
|
|
488
|
-
suggestions.push("Install missing Unity packages manually via Unity Package Manager or Packages/manifest.json, then run the matching 'unitycli extensions install <id> --project <path>'.");
|
|
489
|
-
break;
|
|
490
|
-
}
|
|
501
|
+
if (check.status === "pass")
|
|
502
|
+
continue;
|
|
503
|
+
switch (check.name) {
|
|
504
|
+
case "registry_health_identity":
|
|
505
|
+
suggestions.push("Run unitycli instances list and select the exact canonical project identity.");
|
|
506
|
+
break;
|
|
507
|
+
case "main_thread_pulse":
|
|
508
|
+
suggestions.push("Run unitycli tools run editor.state and wait for a fresh ready Editor pulse.");
|
|
509
|
+
break;
|
|
510
|
+
case "business_diagnostic":
|
|
511
|
+
suggestions.push("Use the business diagnostic error code and nextActions without treating it as a transport failure.");
|
|
512
|
+
break;
|
|
513
|
+
case "catalog_integrity":
|
|
514
|
+
suggestions.push("Fix the catalog publication failure, then let Unity compile and reload the domain.");
|
|
515
|
+
break;
|
|
516
|
+
case "compile":
|
|
517
|
+
suggestions.push("Fix the bounded compiler diagnostics or wait for compilation to finish.");
|
|
518
|
+
break;
|
|
519
|
+
case "extensions":
|
|
520
|
+
suggestions.push("Run unitycli extensions doctor --project <path> for installed extension details.");
|
|
521
|
+
break;
|
|
522
|
+
case "obsolete_local_state":
|
|
523
|
+
suggestions.push("Delete only the explicitly reported obsolete files after auditing them.");
|
|
524
|
+
break;
|
|
491
525
|
}
|
|
492
526
|
}
|
|
493
|
-
|
|
494
|
-
suggestions.push("All checks passed. No action needed.");
|
|
495
|
-
}
|
|
496
|
-
return suggestions;
|
|
527
|
+
return suggestions.length > 0 ? [...new Set(suggestions)] : ["All checks passed. No action needed."];
|
|
497
528
|
}
|
|
498
529
|
//# sourceMappingURL=doctor.js.map
|