@alpsckr/unitycli 0.4.3 → 0.4.4

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (420) hide show
  1. package/README.md +5 -5
  2. package/contracts/command-contract.json +109 -217
  3. package/contracts/package-files.json +374 -294
  4. package/contracts/stable-session/direct-call-semantics.json +8 -2
  5. package/contracts/tool-completion-contract.json +148 -672
  6. package/dist/bridge/admission.d.ts +17 -1
  7. package/dist/bridge/admission.js +2 -0
  8. package/dist/bridge/admission.js.map +1 -1
  9. package/dist/bridge/domains/asset.js +3 -1
  10. package/dist/bridge/domains/asset.js.map +1 -1
  11. package/dist/bridge/domains/camera.js +39 -7
  12. package/dist/bridge/domains/camera.js.map +1 -1
  13. package/dist/bridge/domains/console.js +2 -1
  14. package/dist/bridge/domains/console.js.map +1 -1
  15. package/dist/bridge/domains/doctor.d.ts +3 -0
  16. package/dist/bridge/domains/doctor.js +8 -0
  17. package/dist/bridge/domains/doctor.js.map +1 -0
  18. package/dist/bridge/domains/editor.js +0 -4
  19. package/dist/bridge/domains/editor.js.map +1 -1
  20. package/dist/bridge/domains/game-object.js +4 -12
  21. package/dist/bridge/domains/game-object.js.map +1 -1
  22. package/dist/bridge/domains/graphics.js +1 -16
  23. package/dist/bridge/domains/graphics.js.map +1 -1
  24. package/dist/bridge/domains/object.js +3 -0
  25. package/dist/bridge/domains/object.js.map +1 -1
  26. package/dist/bridge/domains/physics.js +1 -2
  27. package/dist/bridge/domains/physics.js.map +1 -1
  28. package/dist/bridge/domains/profiler.js +18 -7
  29. package/dist/bridge/domains/profiler.js.map +1 -1
  30. package/dist/bridge/domains/project-tool.js +4 -0
  31. package/dist/bridge/domains/project-tool.js.map +1 -1
  32. package/dist/bridge/domains/reflection.js +10 -2
  33. package/dist/bridge/domains/reflection.js.map +1 -1
  34. package/dist/bridge/domains/runtime-tool.js +3 -0
  35. package/dist/bridge/domains/runtime-tool.js.map +1 -1
  36. package/dist/bridge/domains/scene.js +3 -8
  37. package/dist/bridge/domains/scene.js.map +1 -1
  38. package/dist/bridge/domains/screenshot.js +30 -6
  39. package/dist/bridge/domains/screenshot.js.map +1 -1
  40. package/dist/bridge/domains/ui.js +3 -1
  41. package/dist/bridge/domains/ui.js.map +1 -1
  42. package/dist/bridge/index.d.ts +5 -5
  43. package/dist/bridge/index.js +6 -9
  44. package/dist/bridge/index.js.map +1 -1
  45. package/dist/bridge/registry.js +3 -5
  46. package/dist/bridge/registry.js.map +1 -1
  47. package/dist/bridge/session-supervisor.d.ts +6 -3
  48. package/dist/bridge/session-supervisor.js +122 -34
  49. package/dist/bridge/session-supervisor.js.map +1 -1
  50. package/dist/bridge/types.d.ts +6 -5
  51. package/dist/bridge/types.js +16 -2
  52. package/dist/bridge/types.js.map +1 -1
  53. package/dist/catalog-protocol.d.ts +64 -0
  54. package/dist/catalog-protocol.js +460 -0
  55. package/dist/catalog-protocol.js.map +1 -0
  56. package/dist/cli-commands/command.js +84 -61
  57. package/dist/cli-commands/command.js.map +1 -1
  58. package/dist/cli-commands/extensions.js +70 -50
  59. package/dist/cli-commands/extensions.js.map +1 -1
  60. package/dist/cli-commands/instances.js +1 -1
  61. package/dist/cli-commands/instances.js.map +1 -1
  62. package/dist/cli-process-owners.d.ts +6 -0
  63. package/dist/cli-process-owners.js +27 -0
  64. package/dist/cli-process-owners.js.map +1 -0
  65. package/dist/cli.d.ts +1 -1
  66. package/dist/cli.js +20 -5
  67. package/dist/cli.js.map +1 -1
  68. package/dist/contracts/command-contract.js +14 -4
  69. package/dist/contracts/command-contract.js.map +1 -1
  70. package/dist/doctor.d.ts +4 -6
  71. package/dist/doctor.js +429 -398
  72. package/dist/doctor.js.map +1 -1
  73. package/dist/editor-blocker-observer.d.ts +2 -1
  74. package/dist/editor-blocker-observer.js +40 -13
  75. package/dist/editor-blocker-observer.js.map +1 -1
  76. package/dist/extension-availability.d.ts +27 -9
  77. package/dist/extension-availability.js +96 -56
  78. package/dist/extension-availability.js.map +1 -1
  79. package/dist/extensions/descriptor-loader.d.ts +2 -2
  80. package/dist/extensions/descriptor-loader.js +3 -4
  81. package/dist/extensions/descriptor-loader.js.map +1 -1
  82. package/dist/extensions/index.d.ts +1 -1
  83. package/dist/extensions/index.js +1 -1
  84. package/dist/extensions/index.js.map +1 -1
  85. package/dist/extensions/installer.d.ts +24 -7
  86. package/dist/extensions/installer.js +142 -66
  87. package/dist/extensions/installer.js.map +1 -1
  88. package/dist/extensions/registry.js +3 -5
  89. package/dist/extensions/registry.js.map +1 -1
  90. package/dist/extensions/state-contract.d.ts +11 -0
  91. package/dist/extensions/state-contract.js +50 -0
  92. package/dist/extensions/state-contract.js.map +1 -0
  93. package/dist/instances.d.ts +13 -1
  94. package/dist/instances.js +26 -0
  95. package/dist/instances.js.map +1 -1
  96. package/dist/package-manager.d.ts +0 -24
  97. package/dist/package-manager.js +5 -58
  98. package/dist/package-manager.js.map +1 -1
  99. package/dist/project-tool-discovery.d.ts +5 -2
  100. package/dist/project-tool-discovery.js +22 -18
  101. package/dist/project-tool-discovery.js.map +1 -1
  102. package/dist/runtime-code.js +1 -1
  103. package/dist/runtime-code.js.map +1 -1
  104. package/dist/tool-name.d.ts +4 -0
  105. package/dist/tool-name.js +15 -0
  106. package/dist/tool-name.js.map +1 -0
  107. package/dist/tools/.generated-completion-registry.d.ts +2 -0
  108. package/dist/tools/.generated-completion-registry.js +763 -325
  109. package/dist/tools/.generated-completion-registry.js.map +1 -1
  110. package/dist/tools/.generated-registry.d.ts +6 -11
  111. package/dist/tools/.generated-registry.js +6 -11
  112. package/dist/tools/.generated-registry.js.map +1 -1
  113. package/dist/tools/.generated-schemas.js +11 -16
  114. package/dist/tools/.generated-schemas.js.map +1 -1
  115. package/dist/tools/asset/refresh-status.d.ts +3 -0
  116. package/dist/tools/asset/refresh-status.js +12 -0
  117. package/dist/tools/asset/refresh-status.js.map +1 -0
  118. package/dist/tools/asset/refresh.js +7 -3
  119. package/dist/tools/asset/refresh.js.map +1 -1
  120. package/dist/tools/build/player-status.d.ts +3 -0
  121. package/dist/tools/build/player-status.js +12 -0
  122. package/dist/tools/build/player-status.js.map +1 -0
  123. package/dist/tools/build/run.js +1 -1
  124. package/dist/tools/build/run.js.map +1 -1
  125. package/dist/tools/catalog-control.d.ts +22 -0
  126. package/dist/tools/catalog-control.js +335 -0
  127. package/dist/tools/catalog-control.js.map +1 -0
  128. package/dist/tools/catalog.d.ts +7 -9
  129. package/dist/tools/catalog.js +66 -45
  130. package/dist/tools/catalog.js.map +1 -1
  131. package/dist/tools/commands.d.ts +1 -1
  132. package/dist/tools/commands.js +44 -11
  133. package/dist/tools/commands.js.map +1 -1
  134. package/dist/tools/define.js +3 -2
  135. package/dist/tools/define.js.map +1 -1
  136. package/dist/tools/dispatcher.d.ts +53 -6
  137. package/dist/tools/dispatcher.js +277 -108
  138. package/dist/tools/dispatcher.js.map +1 -1
  139. package/dist/tools/editor/compile.js +1 -1
  140. package/dist/tools/editor/compile.js.map +1 -1
  141. package/dist/tools/editor/play-mode-status.d.ts +3 -0
  142. package/dist/tools/editor/play-mode-status.js +12 -0
  143. package/dist/tools/editor/play-mode-status.js.map +1 -0
  144. package/dist/tools/editor/readiness.d.ts +0 -1
  145. package/dist/tools/editor/readiness.js +0 -1
  146. package/dist/tools/editor/readiness.js.map +1 -1
  147. package/dist/tools/editor/refresh.d.ts +7 -3
  148. package/dist/tools/editor/refresh.js +20 -15
  149. package/dist/tools/editor/refresh.js.map +1 -1
  150. package/dist/tools/editor/state.d.ts +2 -2
  151. package/dist/tools/editor/state.js +13 -12
  152. package/dist/tools/editor/state.js.map +1 -1
  153. package/dist/tools/metadata/derived.js +1 -7
  154. package/dist/tools/metadata/derived.js.map +1 -1
  155. package/dist/tools/metadata/status.js +1 -12
  156. package/dist/tools/metadata/status.js.map +1 -1
  157. package/dist/tools/metadata/types.d.ts +0 -2
  158. package/dist/tools/navmesh/live.js +1 -1
  159. package/dist/tools/navmesh/live.js.map +1 -1
  160. package/dist/tools/occlusion/live.js +1 -1
  161. package/dist/tools/occlusion/live.js.map +1 -1
  162. package/dist/tools/package/deploy.js +2 -2
  163. package/dist/tools/package/deploy.js.map +1 -1
  164. package/dist/tools/package/embed.js +1 -1
  165. package/dist/tools/package/embed.js.map +1 -1
  166. package/dist/tools/package/install-status.d.ts +3 -0
  167. package/dist/tools/package/install-status.js +12 -0
  168. package/dist/tools/package/install-status.js.map +1 -0
  169. package/dist/tools/package/install.js +3 -3
  170. package/dist/tools/package/install.js.map +1 -1
  171. package/dist/tools/package/live-resolve.js +45 -12
  172. package/dist/tools/package/live-resolve.js.map +1 -1
  173. package/dist/tools/package/registry-clear.js.map +1 -1
  174. package/dist/tools/package/registry-set.js.map +1 -1
  175. package/dist/tools/package/remove-status.d.ts +3 -0
  176. package/dist/tools/package/remove-status.js +12 -0
  177. package/dist/tools/package/remove-status.js.map +1 -0
  178. package/dist/tools/package/remove.js +3 -3
  179. package/dist/tools/package/remove.js.map +1 -1
  180. package/dist/tools/package/resolve.js +3 -3
  181. package/dist/tools/package/resolve.js.map +1 -1
  182. package/dist/tools/package/restore.js +2 -2
  183. package/dist/tools/package/restore.js.map +1 -1
  184. package/dist/tools/package/scoped-registry-add.js.map +1 -1
  185. package/dist/tools/status/support.d.ts +13 -0
  186. package/dist/tools/status/support.js +28 -0
  187. package/dist/tools/status/support.js.map +1 -0
  188. package/dist/tools/test/cancel.js +2 -2
  189. package/dist/tools/test/cancel.js.map +1 -1
  190. package/dist/tools/test/run-status.d.ts +3 -0
  191. package/dist/tools/test/run-status.js +12 -0
  192. package/dist/tools/test/run-status.js.map +1 -0
  193. package/dist/tools/test/run.js +7 -4
  194. package/dist/tools/test/run.js.map +1 -1
  195. package/dist/tools/tools/group-summaries.js +10 -14
  196. package/dist/tools/tools/group-summaries.js.map +1 -1
  197. package/docs/architecture.md +4 -4
  198. package/docs/availability-differences.md +4 -4
  199. package/docs/command-execution.md +4 -3
  200. package/docs/error-codes.md +13 -5
  201. package/docs/extensions.md +1 -7
  202. package/docs/risk-and-side-effects.md +4 -3
  203. package/docs/safety-boundaries.md +3 -1
  204. package/docs/target-and-instance.md +1 -1
  205. package/docs/tool-discovery.md +17 -10
  206. package/docs/tool-execution.md +18 -7
  207. package/extensions/cinemachine/unitypkg/Editor/UnityCliExtensionAssembly.cs +3 -0
  208. package/extensions/hdrp/unitypkg/Editor/UnityCliExtensionAssembly.cs +3 -0
  209. package/extensions/probuilder/unitypkg/Editor/UnityCliExtensionAssembly.cs +3 -0
  210. package/extensions/urp/unitypkg/Editor/UnityCliExtensionAssembly.cs +3 -0
  211. package/extensions/vfx-graph/unitypkg/Editor/UnityCliExtensionAssembly.cs +3 -0
  212. package/package.json +2 -4
  213. package/skills/unitycli/SKILL.md +11 -2
  214. package/skills/unitycli/manifest.json +1 -1
  215. package/skills/unitycli/references/operation-protocol.md +3 -3
  216. package/unitypkg/Editor/AssemblyInfo.cs +5 -0
  217. package/unitypkg/Editor/Bridge/BridgeCommandRegistry.cs +49 -14
  218. package/unitypkg/Editor/Bridge/BridgeHttpServer.cs +9 -35
  219. package/unitypkg/Editor/Bridge/BridgeQueueState.cs +672 -0
  220. package/unitypkg/Editor/Bridge/BridgeWorkQueue.cs +970 -120
  221. package/unitypkg/Editor/BridgeStartupStateMachine.cs +59 -1
  222. package/unitypkg/Editor/Commands/ProjectToolCommands.cs +4 -0
  223. package/unitypkg/Editor/Commands/RuntimeToolCommands.cs +3 -0
  224. package/unitypkg/Editor/Generated/UnityCliToolCompletionRegistry.g.cs +379 -14
  225. package/unitypkg/Editor/Infrastructure/CodeExecSupport.cs +28 -13
  226. package/unitypkg/Editor/Infrastructure/RegistryOwnershipResolver.cs +132 -105
  227. package/unitypkg/Editor/Infrastructure/UnityCliActiveOperation.cs +138 -29
  228. package/unitypkg/Editor/Infrastructure/UnityCliAdmission.cs +1856 -237
  229. package/unitypkg/Editor/Infrastructure/UnityCliDoctorDiagnostics.cs +220 -0
  230. package/unitypkg/Editor/Infrastructure/UnityCliDurableStatusCoordinator.cs +118 -0
  231. package/unitypkg/Editor/Infrastructure/UnityCliEditorStateSnapshot.cs +2 -1
  232. package/unitypkg/Editor/Infrastructure/UnityCliHierarchyPager.cs +203 -0
  233. package/unitypkg/Editor/Infrastructure/UnityCliInstanceCleanup.cs +2 -1
  234. package/unitypkg/Editor/Infrastructure/UnityCliInstanceRegistry.cs +201 -63
  235. package/unitypkg/Editor/Infrastructure/UnityCliJson.cs +2 -3
  236. package/unitypkg/Editor/Infrastructure/UnityCliLiveBuildCoordinator.cs +289 -46
  237. package/unitypkg/Editor/Infrastructure/UnityCliLiveRefreshCoordinator.cs +87 -53
  238. package/unitypkg/Editor/Infrastructure/UnityCliNavMeshBakeCoordinator.cs +4 -4
  239. package/unitypkg/Editor/Infrastructure/UnityCliObjectRef.cs +128 -25
  240. package/unitypkg/Editor/Infrastructure/UnityCliObjectSerializer.cs +435 -327
  241. package/unitypkg/Editor/Infrastructure/UnityCliOcclusionBakeCoordinator.cs +4 -4
  242. package/unitypkg/Editor/Infrastructure/UnityCliOperationCoordinator.cs +351 -53
  243. package/unitypkg/Editor/Infrastructure/UnityCliPackageResolveCoordinator.cs +118 -18
  244. package/unitypkg/Editor/Infrastructure/UnityCliPackageResolveState.cs +20 -1
  245. package/unitypkg/Editor/Infrastructure/UnityCliReadGeneration.cs +97 -0
  246. package/unitypkg/Editor/Infrastructure/UnityCliReflection.cs +644 -133
  247. package/unitypkg/Editor/Infrastructure/UnityCliReloadOperation.cs +128 -41
  248. package/unitypkg/Editor/Infrastructure/UnityCliRuntimeExecutor.cs +14 -84
  249. package/unitypkg/Editor/Infrastructure/UnityCliSerializer.cs +220 -0
  250. package/unitypkg/Editor/Infrastructure/UnityCliSessionMutationLease.cs +69 -29
  251. package/unitypkg/Editor/Infrastructure/UnityCliTestRunCoordinator.cs +440 -54
  252. package/unitypkg/Editor/Infrastructure/UnityCliWaiter.cs +128 -35
  253. package/unitypkg/Editor/ProjectTools/IUnityCliTool.cs +9 -1
  254. package/unitypkg/Editor/ProjectTools/OfficialAttributeToolRegistry.cs +32 -31
  255. package/unitypkg/Editor/ProjectTools/ProjectToolRegistry.cs +607 -458
  256. package/unitypkg/Editor/ProjectTools/ProjectToolSchemaValidator.cs +35 -7
  257. package/unitypkg/Editor/ProjectTools/RegisteredTool.cs +501 -60
  258. package/unitypkg/Editor/ProjectTools/UnityCliProjectToolContext.cs +21 -0
  259. package/unitypkg/Editor/ProjectTools/UnityCliSchemaDeriver.cs +36 -7
  260. package/unitypkg/Editor/ProjectTools/UnityCliToolName.cs +30 -0
  261. package/unitypkg/Editor/Properties/AssemblyInfo.cs +3 -0
  262. package/unitypkg/Editor/Tools/asset/get-data.cs +16 -7
  263. package/unitypkg/Editor/Tools/build/BuildSceneStateTool.cs +23 -3
  264. package/unitypkg/Editor/Tools/build/BuildToolDtos.cs +2 -1
  265. package/unitypkg/Editor/Tools/build/scene/add.cs +6 -3
  266. package/unitypkg/Editor/Tools/build/scene/disable.cs +1 -1
  267. package/unitypkg/Editor/Tools/build/scene/enable.cs +1 -1
  268. package/unitypkg/Editor/Tools/build/scene/list.cs +1 -1
  269. package/unitypkg/Editor/Tools/build/scene/remove.cs +13 -3
  270. package/unitypkg/Editor/Tools/camera/CameraToolSupport.cs +38 -38
  271. package/unitypkg/Editor/Tools/camera/multiview.cs +13 -6
  272. package/unitypkg/Editor/Tools/camera/screenshot.cs +14 -7
  273. package/unitypkg/Editor/Tools/component/get.cs +16 -9
  274. package/unitypkg/Editor/Tools/component/modify.cs +6 -4
  275. package/unitypkg/Editor/Tools/console/clear.cs +7 -6
  276. package/unitypkg/Editor/Tools/console/get.cs +48 -16
  277. package/unitypkg/Editor/Tools/editor/EditorToolSupport.cs +143 -28
  278. package/unitypkg/Editor/Tools/editor/menu-items.cs +1 -1
  279. package/unitypkg/Editor/Tools/editor/play.cs +2 -11
  280. package/unitypkg/Editor/Tools/editor/selection.cs +1 -1
  281. package/unitypkg/Editor/Tools/editor/stop.cs +2 -11
  282. package/unitypkg/Editor/Tools/editor/windows.cs +1 -1
  283. package/unitypkg/Editor/Tools/go/GameObjectToolSupport.cs +54 -4
  284. package/unitypkg/Editor/Tools/go/delete.cs +1 -1
  285. package/unitypkg/Editor/Tools/go/find.cs +167 -70
  286. package/unitypkg/Editor/Tools/graphics/GraphicsToolSupport.cs +25 -0
  287. package/unitypkg/Editor/Tools/graphics/light-probe-group.cs +9 -3
  288. package/unitypkg/Editor/Tools/graphics/pipeline-info.cs +1 -1
  289. package/unitypkg/Editor/Tools/graphics/pipeline-settings.cs +1 -1
  290. package/unitypkg/Editor/Tools/graphics/quality.cs +2 -2
  291. package/unitypkg/Editor/Tools/graphics/reflection-probe.cs +3 -3
  292. package/unitypkg/Editor/Tools/graphics/stats.cs +1 -1
  293. package/unitypkg/Editor/Tools/object/ObjectToolSupport.cs +4 -4
  294. package/unitypkg/Editor/Tools/object/get-data.cs +9 -7
  295. package/unitypkg/Editor/Tools/object/modify.cs +7 -5
  296. package/unitypkg/Editor/Tools/physics/raycast.cs +24 -6
  297. package/unitypkg/Editor/Tools/prefab/stage.cs +1 -1
  298. package/unitypkg/Editor/Tools/profiler/ProfilerFrameDebuggerSupport.cs +94 -21
  299. package/unitypkg/Editor/Tools/profiler/ProfilerMemorySnapshotSupport.cs +397 -10
  300. package/unitypkg/Editor/Tools/profiler/ProfilerToolSupport.cs +18 -4
  301. package/unitypkg/Editor/Tools/profiler/frame-debugger/enable.cs +1 -1
  302. package/unitypkg/Editor/Tools/profiler/frame-debugger/events.cs +88 -87
  303. package/unitypkg/Editor/Tools/profiler/hierarchy.cs +278 -112
  304. package/unitypkg/Editor/Tools/profiler/memory-snapshot/compare.cs +9 -5
  305. package/unitypkg/Editor/Tools/profiler/memory-snapshot/list.cs +37 -35
  306. package/unitypkg/Editor/Tools/profiler/memory-snapshot/take.cs +99 -97
  307. package/unitypkg/Editor/Tools/project/info.cs +1 -1
  308. package/unitypkg/Editor/Tools/project/layers.cs +1 -1
  309. package/unitypkg/Editor/Tools/project/tags.cs +1 -1
  310. package/unitypkg/Editor/Tools/reflection/method/call.cs +9 -7
  311. package/unitypkg/Editor/Tools/reflection/method/find.cs +27 -37
  312. package/unitypkg/Editor/Tools/reflection/type/schema.cs +24 -28
  313. package/unitypkg/Editor/Tools/scene/gameobject/component.cs +8 -5
  314. package/unitypkg/Editor/Tools/scene/gameobject/components.cs +10 -7
  315. package/unitypkg/Editor/Tools/scene/gameobject-support.cs +104 -8
  316. package/unitypkg/Editor/Tools/scene/gameobject.cs +37 -16
  317. package/unitypkg/Editor/Tools/scene/hierarchy.cs +146 -142
  318. package/unitypkg/Editor/Tools/screenshot/EditorElementCaptureToolSupport.cs +77 -25
  319. package/unitypkg/Editor/Tools/screenshot/ScreenshotToolSupport.cs +315 -95
  320. package/unitypkg/Editor/Tools/screenshot/editor-element.cs +7 -5
  321. package/unitypkg/Editor/Tools/screenshot/game-view.cs +35 -21
  322. package/unitypkg/Editor/Tools/screenshot/isolated-object.cs +29 -23
  323. package/unitypkg/Editor/Tools/screenshot/orbit.cs +37 -25
  324. package/unitypkg/Editor/Tools/screenshot/scene-view.cs +25 -18
  325. package/unitypkg/Editor/Tools/screenshot/screen.cs +177 -17
  326. package/unitypkg/Editor/Tools/screenshot/surround.cs +83 -79
  327. package/unitypkg/Editor/Tools/ui/render-preview.cs +16 -11
  328. package/unitypkg/Editor/UnityCliBridge.cs +97 -34
  329. package/unitypkg/Runtime/Infrastructure/UnityCliRuntimeBridge.cs +753 -122
  330. package/unitypkg/Runtime/Properties/AssemblyInfo.cs +5 -0
  331. package/unitypkg/Runtime/UnityCli.Runtime.asmdef +1 -1
  332. package/unitypkg/Shared/AssemblyInfo.cs +4 -0
  333. package/unitypkg/Shared/UnityCliAdmissionPool.cs +265 -75
  334. package/unitypkg/Shared/UnityCliBridgeQueuePolicy.cs +410 -0
  335. package/unitypkg/Shared/UnityCliBridgeWorkItemState.cs +47 -0
  336. package/unitypkg/Shared/UnityCliExceptionProjection.cs +151 -0
  337. package/unitypkg/Shared/UnityCliQueuePublication.cs +30 -0
  338. package/unitypkg/Shared/UnityCliRequestBudget.cs +352 -0
  339. package/unitypkg/Shared/UnityCliRuntimeRequestPublication.cs +107 -0
  340. package/unitypkg/Tests/Editor/UnityCli.Editor.Tests.asmdef +2 -2
  341. package/unitypkg/Tests/Editor/UnityCliAdmissionCoordinatorIntegrationTests.cs +1329 -0
  342. package/unitypkg/Tests/Editor/UnityCliAdmissionPoolTests.cs +311 -114
  343. package/unitypkg/Tests/Editor/UnityCliAdmissionRepairStateTests.cs +94 -0
  344. package/unitypkg/Tests/Editor/UnityCliBridgeAdmissionIntegrationTests.cs +1229 -0
  345. package/unitypkg/Tests/Editor/UnityCliBridgeQueuePolicyTests.cs +412 -0
  346. package/unitypkg/Tests/Editor/UnityCliContinuationIntegrationTests.cs +292 -0
  347. package/unitypkg/Tests/Editor/UnityCliDiagnosticBoundaryTests.cs +120 -0
  348. package/unitypkg/Tests/Editor/UnityCliDurableStatusTests.cs +84 -0
  349. package/unitypkg/Tests/Editor/UnityCliExceptionProjectionTests.cs +72 -0
  350. package/unitypkg/Tests/Editor/UnityCliInstancePublicationRetryTests.cs +180 -97
  351. package/unitypkg/Tests/Editor/UnityCliMemoryReflectionIntegrationTests.cs +434 -0
  352. package/unitypkg/Tests/Editor/UnityCliRequestBudgetTests.cs +615 -0
  353. package/unitypkg/Tests/Editor/UnityCliRuntimeBridgeIntegrationTests.cs +520 -0
  354. package/unitypkg/Tests/Editor/UnityCliToolCatalogTests.cs +562 -0
  355. package/unitypkg/Tests/Runtime/UnityCli.Runtime.Tests.asmdef +23 -0
  356. package/unitypkg/Tests/Runtime/UnityCliRuntimeCatalogValidationTests.cs +29 -0
  357. package/unitypkg/package.json +1 -1
  358. package/contracts/static-capability-catalog.json +0 -48226
  359. package/dist/bridge/domains/diagnose.d.ts +0 -2
  360. package/dist/bridge/domains/diagnose.js +0 -11
  361. package/dist/bridge/domains/diagnose.js.map +0 -1
  362. package/dist/bridge/domains/extension.d.ts +0 -8
  363. package/dist/bridge/domains/extension.js +0 -20
  364. package/dist/bridge/domains/extension.js.map +0 -1
  365. package/dist/capabilities.d.ts +0 -5
  366. package/dist/capabilities.js +0 -84
  367. package/dist/capabilities.js.map +0 -1
  368. package/dist/static-capability-catalog.d.ts +0 -13
  369. package/dist/static-capability-catalog.js +0 -41
  370. package/dist/static-capability-catalog.js.map +0 -1
  371. package/dist/tools/diagnose/capabilities.d.ts +0 -13
  372. package/dist/tools/diagnose/capabilities.js +0 -34
  373. package/dist/tools/diagnose/capabilities.js.map +0 -1
  374. package/dist/tools/package/info.d.ts +0 -19
  375. package/dist/tools/package/info.js +0 -27
  376. package/dist/tools/package/info.js.map +0 -1
  377. package/dist/tools/package/list.d.ts +0 -27
  378. package/dist/tools/package/list.js +0 -21
  379. package/dist/tools/package/list.js.map +0 -1
  380. package/dist/tools/package/registry-get.d.ts +0 -10
  381. package/dist/tools/package/registry-get.js +0 -22
  382. package/dist/tools/package/registry-get.js.map +0 -1
  383. package/dist/tools/package/scoped-registry-list.d.ts +0 -14
  384. package/dist/tools/package/scoped-registry-list.js +0 -22
  385. package/dist/tools/package/scoped-registry-list.js.map +0 -1
  386. package/dist/tools/package/search.d.ts +0 -17
  387. package/dist/tools/package/search.js +0 -39
  388. package/dist/tools/package/search.js.map +0 -1
  389. package/dist/tools/package/status.d.ts +0 -21
  390. package/dist/tools/package/status.js +0 -37
  391. package/dist/tools/package/status.js.map +0 -1
  392. package/dist/tools/tools/describe.d.ts +0 -27
  393. package/dist/tools/tools/describe.js +0 -35
  394. package/dist/tools/tools/describe.js.map +0 -1
  395. package/dist/tools/tools/group-list.d.ts +0 -16
  396. package/dist/tools/tools/group-list.js +0 -38
  397. package/dist/tools/tools/group-list.js.map +0 -1
  398. package/dist/tools/tools/group.d.ts +0 -13
  399. package/dist/tools/tools/group.js +0 -34
  400. package/dist/tools/tools/group.js.map +0 -1
  401. package/dist/tools/tools/pagination.d.ts +0 -17
  402. package/dist/tools/tools/pagination.js +0 -28
  403. package/dist/tools/tools/pagination.js.map +0 -1
  404. package/dist/tools/tools/search.d.ts +0 -15
  405. package/dist/tools/tools/search.js +0 -42
  406. package/dist/tools/tools/search.js.map +0 -1
  407. package/unitypkg/Editor/Tools/diagnose/preflight.cs +0 -269
  408. package/unitypkg/Editor/Tools/editor/console.cs +0 -26
  409. package/unitypkg/Editor/Tools/extension/status.cs +0 -87
  410. package/unitypkg/Editor/Tools/go/inspect.cs +0 -49
  411. package/unitypkg/Editor/Tools/graphics/pipeline-quality.cs +0 -24
  412. package/unitypkg/Editor/Tools/graphics/probe-positions.cs +0 -58
  413. package/unitypkg/Editor/Tools/graphics/settings.cs +0 -104
  414. package/unitypkg/Editor/Tools/graphics/stats-counters.cs +0 -28
  415. package/unitypkg/Editor/Tools/graphics/stats-memory.cs +0 -21
  416. package/unitypkg/Editor/Tools/instances/list.cs +0 -71
  417. package/unitypkg/Editor/Tools/physics/raycast-all.cs +0 -67
  418. package/unitypkg/Editor/Tools/scene/build-settings.cs +0 -69
  419. package/unitypkg/Editor/Tools/scene/data.cs +0 -125
  420. package/unitypkg/Editor/Tools/tests/list.cs +0 -98
@@ -1,6 +1,7 @@
1
1
  #if UNITY_EDITOR
2
2
  using System;
3
3
  using System.Collections.Generic;
4
+ using System.Diagnostics;
4
5
  using System.Globalization;
5
6
  using System.IO;
6
7
  using System.Threading;
@@ -9,6 +10,35 @@ using UnityCli.Protocol;
9
10
 
10
11
  namespace UnityCli
11
12
  {
13
+ /// <summary>每个reload operation独占的单调tick节流;绝对业务deadline仍由UTC判定。</summary>
14
+ internal sealed class UnityCliReloadTickSchedule
15
+ {
16
+ private readonly Func<long> monotonicNowMs;
17
+ private readonly Func<DateTimeOffset> utcNow;
18
+ private long nextTickAtMs;
19
+
20
+ internal UnityCliReloadTickSchedule(Func<long> monotonicNowMs = null, Func<DateTimeOffset> utcNow = null)
21
+ {
22
+ this.monotonicNowMs = monotonicNowMs ?? DefaultMonotonicMilliseconds;
23
+ this.utcNow = utcNow ?? (() => DateTimeOffset.UtcNow);
24
+ }
25
+
26
+ internal DateTimeOffset UtcNow { get { return utcNow(); } }
27
+
28
+ internal bool TryEnter()
29
+ {
30
+ var now = monotonicNowMs();
31
+ if (now < nextTickAtMs) return false;
32
+ nextTickAtMs = checked(now + 100L);
33
+ return true;
34
+ }
35
+
36
+ private static long DefaultMonotonicMilliseconds()
37
+ {
38
+ return checked((long)(Stopwatch.GetTimestamp() * (1000d / Stopwatch.Frequency)));
39
+ }
40
+ }
41
+
12
42
  public static partial class UnityCliBridge
13
43
  {
14
44
  /// <summary>跨 domain reload 的 dictionary journal 操作公共协调骨架。</summary>
@@ -84,8 +114,8 @@ namespace UnityCli
84
114
  || Array.IndexOf(phases ?? new string[0], Text(root, "phase")) < 0)
85
115
  throw new InvalidDataException("Active root common fields are invalid.");
86
116
  }
87
- /// <summary>供带有私有控制面的操作注册 start/status 之外的命令。</summary>
88
- protected virtual IEnumerable<(string name, bool destructive)> AdditionalCommands { get { yield break; } }
117
+ /// <summary>供带有私有控制面的操作注册 start/status 之外的命令与唯一queue分类。</summary>
118
+ protected virtual IEnumerable<(string name, bool destructive, UnityCliBridgeQueuePolicy.WorkClass queueClass)> AdditionalCommands { get { yield break; } }
89
119
  protected virtual object ExecuteAdditionalCommand(BridgeRequest request)
90
120
  {
91
121
  throw new BridgeCommandException("E_REQUEST_NOT_FOUND", OperationDisplayName + " command was not found.");
@@ -115,6 +145,74 @@ namespace UnityCli
115
145
  protected virtual TerminalCleanupDecision EvaluateTerminalCleanupRoot(Dictionary<string, object> root, string requestId, string requestDigest) { return TerminalCleanupDecision.Cleanup; }
116
146
  /// <summary>root不可读时,业务必须仅凭独立durable terminal决定清理、重试或拒绝。</summary>
117
147
  protected virtual TerminalCleanupDecision EvaluateUnreadableTerminalCleanup(string requestId, string requestDigest) { return TerminalCleanupDecision.Cleanup; }
148
+
149
+ /// <summary>每tick先消费scope准入marker;只有root与lease的exact状态都可证明时才推进或清理owner。</summary>
150
+ protected bool RetryAdmissionOwnerRecoveryMarker()
151
+ {
152
+ return RetryAdmissionOwnerRecoveryMarker(ProductionQueueState, Scope, OperationDisplayName);
153
+ }
154
+
155
+ /// <summary>production与隔离测试共用同一root-missing保守终态算法,任何写入失败都保留原marker。</summary>
156
+ private static bool RetryAdmissionOwnerRecoveryMarker(BridgeQueueState state, string scope, string displayName)
157
+ {
158
+ var markerScope = scope + "-admission-owner";
159
+ if (state.OperationExists(scope + "-terminal-cleanup"))
160
+ {
161
+ try
162
+ {
163
+ if (UnityCliActiveOperation.RetryExactTerminalCleanup(scope, state)) return true;
164
+ }
165
+ catch { return true; }
166
+ }
167
+ if (!state.OperationExists(markerScope)) return false;
168
+ Dictionary<string, object> marker;
169
+ try { marker = state.LoadOperation(markerScope); }
170
+ catch { return true; }
171
+ if (marker == null) return true;
172
+ var requestId = Text(marker, "requestId");
173
+ var ownerRequestDigest = Text(marker, "admissionRequestDigest");
174
+ var topRequestDigest = Text(marker, "requestDigest");
175
+ if (!IsSafeId(requestId) || !IsSha256(ownerRequestDigest) || !IsSha256(topRequestDigest)) return true;
176
+ AdmissionOwnerIdentity owner;
177
+ try { owner = ReconcileAdmissionTransferForLiveMarker(state, markerScope, marker, requestId, ownerRequestDigest); }
178
+ catch { return true; }
179
+ if (owner == null || !string.Equals(owner.TopRequestDigest, topRequestDigest, StringComparison.Ordinal)) return true;
180
+
181
+ Dictionary<string, object> root;
182
+ try { root = state.LoadOperation(scope); }
183
+ catch { return true; }
184
+ if (root != null)
185
+ {
186
+ var rootMatches = string.Equals(Text(root, "editorSessionId"), EditorSessionId(), StringComparison.Ordinal)
187
+ && string.Equals(Text(root, "requestId"), requestId, StringComparison.Ordinal)
188
+ && string.Equals(Text(root, "requestDigest"), topRequestDigest, StringComparison.Ordinal);
189
+ return !rootMatches;
190
+ }
191
+
192
+ bool leaseOwned;
193
+ if (!state.TryIsLeaseOwned(owner.RequestId, owner.RequestDigest, out leaseOwned)) return true;
194
+ try
195
+ {
196
+ object first;
197
+ if (!state.TryGetTerminal(scope, requestId, topRequestDigest, out first))
198
+ {
199
+ var terminal = ProtocolEnvelopeFactory.Error(requestId, "E_EXECUTION_TIMEOUT", displayName + (leaseOwned ? " active root disappeared while its exact lease was retained; outcome is unknown." : " active root disappeared after its exact lease was released; outcome is unknown."), null, new[] { "Inspect the affected business state before submitting another mutation." });
200
+ first = state.StoreTerminalFirst(scope, requestId, topRequestDigest, terminal);
201
+ }
202
+ object confirmed;
203
+ if (!state.TryGetTerminal(scope, requestId, topRequestDigest, out confirmed)
204
+ || !string.Equals(UnityCliSerializer.Serialize(first), UnityCliSerializer.Serialize(confirmed), StringComparison.Ordinal)) return true;
205
+ UnityCliActiveOperation.BeginExactTerminalCleanup(scope, requestId, topRequestDigest, state);
206
+ }
207
+ catch { return true; }
208
+ return true;
209
+ }
210
+
211
+ internal static bool RetryAdmissionOwnerRecoveryMarkerForTests(BridgeQueueState state, string scope, string displayName)
212
+ {
213
+ if (state == null || state.IsolatedExecution == null) throw new ArgumentException("Reload recovery test state must be isolated.", "state");
214
+ return RetryAdmissionOwnerRecoveryMarker(state, scope, displayName);
215
+ }
118
216
  /// <summary>effect前放弃只能清理同identity且由业务证明从未越过effect barrier的root。</summary>
119
217
  protected virtual bool CanCleanupAbandonedPreEffectRoot(Dictionary<string, object> root, string requestId, string requestDigest) { return false; }
120
218
  /// <summary>root删除后、lease释放前,业务可清理同identity且未dispatch的附属status;失败必须重试。</summary>
@@ -134,7 +232,7 @@ namespace UnityCli
134
232
 
135
233
  private string TerminalCleanupScope { get { return Scope + "-terminal-cleanup"; } }
136
234
  private string PreEffectCleanupScope { get { return Scope + "-pre-effect-cleanup"; } }
137
- private DateTime nextTickUtc;
235
+ private readonly UnityCliReloadTickSchedule tickSchedule = new UnityCliReloadTickSchedule();
138
236
  private string lastTerminalRequestId;
139
237
  private string lastTerminalRequestDigest;
140
238
  private object lastTerminalEnvelope;
@@ -157,10 +255,10 @@ namespace UnityCli
157
255
  }
158
256
  internal void Register(BridgeCommandRegistry registry)
159
257
  {
160
- registry.Register<BridgeRequest>(StartCommand, "internal", true, CommandTimeoutMs, (r, c) => { throw new InvalidOperationException(OperationDisplayName + " is coordinator-owned."); });
161
- registry.Register<BridgeRequest>(StatusCommand, "internal", false, CommandTimeoutMs, (r, c) => { throw new InvalidOperationException(OperationDisplayName + " is coordinator-owned."); });
258
+ registry.Register<BridgeRequest>(StartCommand, "internal", true, CommandTimeoutMs, (r, c) => { throw new InvalidOperationException(OperationDisplayName + " is coordinator-owned."); }, UnityCliBridgeQueuePolicy.WorkClass.Mutation);
259
+ registry.Register<BridgeRequest>(StatusCommand, "internal", false, CommandTimeoutMs, (r, c) => { throw new InvalidOperationException(OperationDisplayName + " is coordinator-owned."); }, UnityCliBridgeQueuePolicy.WorkClass.SafeStatus);
162
260
  foreach (var additional in AdditionalCommands)
163
- registry.Register<BridgeRequest>(additional.name, "internal", additional.destructive, CommandTimeoutMs, (r, c) => { throw new InvalidOperationException(OperationDisplayName + " is coordinator-owned."); });
261
+ registry.Register<BridgeRequest>(additional.name, "internal", additional.destructive, CommandTimeoutMs, (r, c) => { throw new InvalidOperationException(OperationDisplayName + " is coordinator-owned."); }, additional.queueClass);
164
262
  }
165
263
 
166
264
  /// <summary>HTTP 接受后建立或续接唯一 journal;lease 成功后任意异常都必须释放它。</summary>
@@ -248,15 +346,15 @@ namespace UnityCli
248
346
  /// <summary>每帧只推进当前 lease owner;session/deadline 不可确认时先持久化失败终态。</summary>
249
347
  internal virtual void Tick()
250
348
  {
251
- if (DateTime.UtcNow < nextTickUtc) return;
252
- nextTickUtc = DateTime.UtcNow.AddMilliseconds(100);
349
+ if (RetryAdmissionOwnerRecoveryMarker()) return;
350
+ if (!tickSchedule.TryEnter()) return;
253
351
  if (RetryPreEffectCleanup()) return;
254
352
  if (RetryTerminalCleanup()) return;
255
353
  var root = Load();
256
354
  if (root == null || !UnityCliSessionMutationLease.IsOwnedBy(Text(root, "requestId"), Text(root, "requestDigest"))) return;
257
355
  if (TryResumePublishedTerminal(root)) return;
258
356
  if (!string.Equals(Text(root, "editorSessionId"), EditorSessionId(), StringComparison.Ordinal)) { Fail(root, "E_EXECUTION_TIMEOUT", SessionChangedMessage); return; }
259
- if (DateTimeOffset.UtcNow >= Time(root, "deadline")) { Fail(root, "E_EXECUTION_TIMEOUT", DeadlineMessage); return; }
357
+ if (tickSchedule.UtcNow >= Time(root, "deadline")) { Fail(root, "E_EXECUTION_TIMEOUT", DeadlineMessage); return; }
260
358
  OnTick(root);
261
359
  }
262
360
 
@@ -394,15 +492,14 @@ namespace UnityCli
394
492
  }
395
493
  pendingPreEffectCleanupRequestId = requestId;
396
494
  pendingPreEffectCleanupRequestDigest = requestDigest;
397
- try { pendingPreEffectAdmissionOwner = CaptureAdmissionOwner(requestId); }
495
+ try { pendingPreEffectAdmissionOwner = CaptureAdmissionOwner(requestId, requestDigest); }
398
496
  catch (Exception exception) { WriteLog(Scope + " pre-effect admission owner freeze failed: " + exception.Message); return; }
399
497
  var marker = new Dictionary<string, object>
400
498
  {
401
499
  { "requestId", requestId }, { "requestDigest", requestDigest }, { "editorSessionId", EditorSessionId() }
402
500
  };
403
- AddAdmissionOwnerFields(marker, pendingPreEffectAdmissionOwner);
404
- try { UnityCliActiveOperation.Save(PreEffectCleanupScope, marker); }
405
- catch (Exception exception) { WriteLog(Scope + " pre-effect cleanup marker write failed: " + exception.Message); }
501
+ try { pendingPreEffectAdmissionOwner = PersistAdmissionOwnerTransfer(PreEffectCleanupScope, marker, pendingPreEffectAdmissionOwner, UnityCliAdmissionPool.AdmissionOwnerState.TerminalCleanup); }
502
+ catch (Exception exception) { WriteLog(Scope + " pre-effect cleanup owner transfer failed: " + exception.Message); return; }
406
503
  RetryPreEffectCleanup();
407
504
  }
408
505
 
@@ -430,7 +527,7 @@ namespace UnityCli
430
527
  { "requestDigest", pendingPreEffectCleanupRequestDigest },
431
528
  { "editorSessionId", EditorSessionId() }
432
529
  };
433
- AddAdmissionOwnerFields(cleanup, pendingPreEffectAdmissionOwner);
530
+ AddAdmissionOwnerFields(cleanup, pendingPreEffectAdmissionOwner, UnityCliAdmissionPool.AdmissionOwnerState.TerminalCleanup);
434
531
  }
435
532
  if (cleanup == null) return markerReadFailed;
436
533
  if (markerReadFailed || !UnityCliActiveOperation.Exists(PreEffectCleanupScope))
@@ -447,8 +544,10 @@ namespace UnityCli
447
544
  return true;
448
545
  }
449
546
  if (string.IsNullOrEmpty(requestId) || string.IsNullOrEmpty(requestDigest)) return true;
450
- var admissionOwner = ReadAdmissionOwnerFields(cleanup, requestId);
451
- if (admissionOwner == null) return true;
547
+ AdmissionOwnerIdentity admissionOwner;
548
+ try { admissionOwner = ReconcileAdmissionTransferForLiveMarker(PreEffectCleanupScope, cleanup, requestId, requestDigest); }
549
+ catch (Exception exception) { WriteLog(Scope + " pre-effect admission transfer retry failed: " + exception.Message); return true; }
550
+ if (admissionOwner == null) { ClearPendingPreEffectCleanup(requestId, requestDigest); return true; }
452
551
 
453
552
  Dictionary<string, object> active = null;
454
553
  if (UnityCliActiveOperation.Exists(Scope))
@@ -507,15 +606,14 @@ namespace UnityCli
507
606
  }
508
607
  pendingTerminalCleanupRequestId = requestId;
509
608
  pendingTerminalCleanupRequestDigest = requestDigest;
510
- try { pendingTerminalAdmissionOwner = CaptureAdmissionOwner(requestId); }
609
+ try { pendingTerminalAdmissionOwner = CaptureAdmissionOwner(requestId, requestDigest); }
511
610
  catch (Exception exception) { WriteLog(Scope + " terminal admission owner freeze failed: " + exception.Message); return; }
512
611
  var marker = new Dictionary<string, object>
513
612
  {
514
613
  { "requestId", requestId }, { "requestDigest", requestDigest }, { "editorSessionId", EditorSessionId() }
515
614
  };
516
- AddAdmissionOwnerFields(marker, pendingTerminalAdmissionOwner);
517
- try { UnityCliActiveOperation.Save(TerminalCleanupScope, marker); }
518
- catch (Exception exception) { WriteLog(Scope + " terminal cleanup marker write failed: " + exception.Message); }
615
+ try { pendingTerminalAdmissionOwner = PersistAdmissionOwnerTransfer(TerminalCleanupScope, marker, pendingTerminalAdmissionOwner, UnityCliAdmissionPool.AdmissionOwnerState.TerminalCleanup); }
616
+ catch (Exception exception) { WriteLog(Scope + " terminal cleanup owner transfer failed: " + exception.Message); return; }
519
617
  RetryTerminalCleanup();
520
618
  }
521
619
 
@@ -540,7 +638,7 @@ namespace UnityCli
540
638
  { "requestDigest", pendingTerminalCleanupRequestDigest },
541
639
  { "editorSessionId", EditorSessionId() }
542
640
  };
543
- AddAdmissionOwnerFields(cleanup, pendingTerminalAdmissionOwner);
641
+ AddAdmissionOwnerFields(cleanup, pendingTerminalAdmissionOwner, UnityCliAdmissionPool.AdmissionOwnerState.TerminalCleanup);
544
642
  }
545
643
  if (cleanup == null) return false;
546
644
  if (!UnityCliActiveOperation.Exists(TerminalCleanupScope))
@@ -557,14 +655,11 @@ namespace UnityCli
557
655
  }
558
656
  var requestId = Text(cleanup, "requestId");
559
657
  var requestDigest = Text(cleanup, "requestDigest");
560
- if (string.IsNullOrEmpty(requestId) || string.IsNullOrEmpty(requestDigest))
561
- {
562
- try { UnityCliActiveOperation.Clear(TerminalCleanupScope); } catch { return true; }
563
- ClearPendingTerminalCleanup(requestId, requestDigest);
564
- return true;
565
- }
566
- var admissionOwner = ReadAdmissionOwnerFields(cleanup, requestId);
567
- if (admissionOwner == null) return true;
658
+ if (string.IsNullOrEmpty(requestId) || string.IsNullOrEmpty(requestDigest)) return true;
659
+ AdmissionOwnerIdentity admissionOwner;
660
+ try { admissionOwner = ReconcileAdmissionTransferForLiveMarker(TerminalCleanupScope, cleanup, requestId, requestDigest); }
661
+ catch (Exception exception) { WriteLog(Scope + " terminal admission transfer retry failed: " + exception.Message); return true; }
662
+ if (admissionOwner == null) { ClearPendingTerminalCleanup(requestId, requestDigest); return true; }
568
663
 
569
664
  Dictionary<string, object> active = null;
570
665
  if (UnityCliActiveOperation.Exists(Scope))
@@ -575,18 +670,14 @@ namespace UnityCli
575
670
  WriteLog(Scope + " terminal active root read failed: " + exception.Message);
576
671
  if (!UnityCliSessionMutationLease.IsOwnedBy(requestId, requestDigest))
577
672
  {
673
+ if (!CompleteAdmissionRoot(admissionOwner)) return true;
578
674
  try { UnityCliActiveOperation.Clear(TerminalCleanupScope); } catch { return true; }
579
675
  ClearPendingTerminalCleanup(requestId, requestDigest);
580
676
  return true;
581
677
  }
582
678
  var unreadableDecision = EvaluateUnreadableTerminalCleanup(requestId, requestDigest);
583
679
  if (unreadableDecision == TerminalCleanupDecision.Retry) return true;
584
- if (unreadableDecision == TerminalCleanupDecision.Reject)
585
- {
586
- try { UnityCliActiveOperation.Clear(TerminalCleanupScope); } catch { return true; }
587
- ClearPendingTerminalCleanup(requestId, requestDigest);
588
- return true;
589
- }
680
+ if (unreadableDecision == TerminalCleanupDecision.Reject) return true;
590
681
  try { UnityCliActiveOperation.Clear(Scope); }
591
682
  catch (Exception clearException) { WriteLog(Scope + " corrupt terminal root cleanup failed: " + clearException.Message); return true; }
592
683
  if (UnityCliActiveOperation.Exists(Scope)) return true;
@@ -601,18 +692,14 @@ namespace UnityCli
601
692
  if (!markerMatchesActive)
602
693
  {
603
694
  if (!LeaseDefinitelyNotOwned(requestId, requestDigest)) return true;
695
+ if (!CompleteAdmissionRoot(admissionOwner)) return true;
604
696
  try { UnityCliActiveOperation.Clear(TerminalCleanupScope); } catch { return true; }
605
697
  ClearPendingTerminalCleanup(requestId, requestDigest);
606
698
  return true;
607
699
  }
608
700
  var cleanupDecision = EvaluateTerminalCleanupRoot(active, requestId, requestDigest);
609
701
  if (cleanupDecision == TerminalCleanupDecision.Retry) return true;
610
- if (cleanupDecision == TerminalCleanupDecision.Reject)
611
- {
612
- try { UnityCliActiveOperation.Clear(TerminalCleanupScope); } catch { return true; }
613
- ClearPendingTerminalCleanup(requestId, requestDigest);
614
- return true;
615
- }
702
+ if (cleanupDecision == TerminalCleanupDecision.Reject) return true;
616
703
  try { UnityCliActiveOperation.Clear(Scope); }
617
704
  catch (Exception exception) { WriteLog(Scope + " terminal active root cleanup failed: " + exception.Message); return true; }
618
705
  if (UnityCliActiveOperation.Exists(Scope)) return true;
@@ -5,7 +5,6 @@ using System.Collections.Generic;
5
5
  using System.Globalization;
6
6
  using System.Linq;
7
7
  using System.Reflection;
8
- using System.Text;
9
8
  using System.Threading;
10
9
  using System.Threading.Tasks;
11
10
  using UnityEditor;
@@ -24,48 +23,25 @@ namespace UnityCli
24
23
  // Play Mode session tracking
25
24
  private static string currentPlayModeSessionId = null;
26
25
  private static bool playModeReady = false;
27
- private static int runtimeRegistryVersion = 0;
28
- private static string runtimeToolCatalogFingerprint = null;
29
26
  private static bool runtimeExecutorInitialized = false;
30
27
 
31
- /// <summary>
32
- /// Initialize the Runtime Executor: subscribe to Play Mode state change
33
- /// events and compute the initial tool catalog fingerprint.
34
- /// </summary>
28
+ /// <summary>订阅当前domain的PlayMode状态;只验证已发布catalog,不触发发现或重建。</summary>
35
29
  private static void InitializeRuntimeExecutor()
36
30
  {
37
31
  if (runtimeExecutorInitialized) return;
32
+ ReadPublishedProjectToolCatalogSnapshot();
38
33
  runtimeExecutorInitialized = true;
39
34
  EditorApplication.playModeStateChanged += OnRuntimePlayModeStateChanged;
40
- RefreshRuntimeToolCatalog();
41
35
  WriteLog("runtime_executor_initialized");
42
36
 
43
- // If we are already in Play Mode at initialization time (e.g. after domain reload),
44
- // immediately establish the session as ready.
45
37
  if (EditorApplication.isPlaying)
46
38
  {
47
39
  currentPlayModeSessionId = GeneratePlayModeSessionId();
48
40
  playModeReady = true;
49
- runtimeRegistryVersion++;
50
- RefreshRuntimeToolCatalog();
51
- WriteLog("runtime_session_ready_after_domain_reload sessionId=" + currentPlayModeSessionId + " registryVersion=" + runtimeRegistryVersion.ToString(CultureInfo.InvariantCulture) + " fingerprint=" + (runtimeToolCatalogFingerprint ?? "none"));
41
+ WriteLog("runtime_session_ready_after_domain_reload sessionId=" + currentPlayModeSessionId);
52
42
  }
53
43
  }
54
44
 
55
- /// <summary>
56
- /// Called after domain reload to reinitialize the Runtime Executor.
57
- /// Domain reload resets all static fields, so the event subscription
58
- /// and session state are lost. This method re-subscribes to Play Mode
59
- /// state change events and restores the session state if already in
60
- /// Play Mode.
61
- /// </summary>
62
- private static void ReinitializeRuntimeExecutorAfterDomainReload()
63
- {
64
- // Reset the guard so InitializeRuntimeExecutor runs again
65
- runtimeExecutorInitialized = false;
66
- InitializeRuntimeExecutor();
67
- }
68
-
69
45
  /// <summary>
70
46
  /// Handle Play Mode state transitions. Generate a new session ID when
71
47
  /// entering Play Mode, mark ready, and invalidate the session when
@@ -83,11 +59,8 @@ namespace UnityCli
83
59
  break;
84
60
 
85
61
  case PlayModeStateChange.ExitingEditMode:
86
- // About to enter Play Mode: pre-generate session ID
87
62
  currentPlayModeSessionId = GeneratePlayModeSessionId();
88
63
  playModeReady = false;
89
- runtimeRegistryVersion++;
90
- RefreshRuntimeToolCatalog();
91
64
  WriteLog("runtime_session_entering sessionId=" + currentPlayModeSessionId);
92
65
  break;
93
66
 
@@ -96,13 +69,9 @@ namespace UnityCli
96
69
  // After domain reload, currentPlayModeSessionId is reset to null.
97
70
  // Generate a new session ID if the pre-generated one was lost.
98
71
  if (currentPlayModeSessionId == null)
99
- {
100
72
  currentPlayModeSessionId = GeneratePlayModeSessionId();
101
- runtimeRegistryVersion++;
102
- RefreshRuntimeToolCatalog();
103
- }
104
73
  playModeReady = true;
105
- WriteLog("runtime_session_ready sessionId=" + currentPlayModeSessionId + " registryVersion=" + runtimeRegistryVersion.ToString(CultureInfo.InvariantCulture) + " fingerprint=" + (runtimeToolCatalogFingerprint ?? "none"));
74
+ WriteLog("runtime_session_ready sessionId=" + currentPlayModeSessionId);
106
75
  break;
107
76
 
108
77
  case PlayModeStateChange.ExitingPlayMode:
@@ -118,44 +87,26 @@ namespace UnityCli
118
87
  return "pms-" + DateTime.UtcNow.ToString("yyyyMMddHHmmss", CultureInfo.InvariantCulture) + "-" + Guid.NewGuid().ToString("N").Substring(0, 8);
119
88
  }
120
89
 
121
- private static void RefreshRuntimeToolCatalog()
122
- {
123
- DiscoverProjectTools();
124
- var count = 0;
125
- var material = new StringBuilder();
126
- foreach (var pair in ProjectTools)
127
- {
128
- var def = pair.Value;
129
- if (def.Target == "runtime" || def.Target == "both")
130
- {
131
- count++;
132
- material.Append(def.Name).Append('\n')
133
- .Append(def.Fingerprint ?? "").Append('\n');
134
- }
135
- }
136
- runtimeToolCatalogFingerprint = Sha256Hex("unity-cli-runtime-tool-catalog-v1\ncount=" + count.ToString(CultureInfo.InvariantCulture) + "\n" + material.ToString());
137
- }
138
-
139
90
  /// <summary>
140
91
  /// Runtime session readiness report, included in instance registration
141
92
  /// and available via editor.state.
142
93
  /// </summary>
143
94
  private static Dictionary<string, object> RuntimeSessionData()
144
95
  {
96
+ var catalog = ReadPublishedProjectToolCatalogSnapshot();
145
97
  var availableTools = new List<object>();
146
- foreach (var pair in ProjectTools)
98
+ foreach (var descriptor in catalog.Descriptors)
147
99
  {
148
- if (pair.Value.Target != "runtime" && pair.Value.Target != "both") continue;
100
+ if (descriptor.Target != "runtime" && descriptor.Target != "both") continue;
149
101
  availableTools.Add(new Dictionary<string, object>
150
102
  {
151
- { "name", pair.Value.Name }, { "target", pair.Value.Target }, { "availabilityScope", pair.Value.AvailabilityScope }, { "available", playModeReady }
103
+ { "name", descriptor.Name }, { "target", descriptor.Target }, { "availabilityScope", descriptor.AvailabilityScope }, { "available", playModeReady }
152
104
  });
153
105
  }
154
106
  // 会话数据直接嵌入最终 response,禁止序列化后重新解析为 object。
155
107
  return new Dictionary<string, object>
156
108
  {
157
- { "playModeSessionId", currentPlayModeSessionId }, { "ready", playModeReady }, { "registryVersion", runtimeRegistryVersion },
158
- { "toolCatalogFingerprint", runtimeToolCatalogFingerprint }, { "availableRuntimeTools", availableTools }
109
+ { "playModeSessionId", currentPlayModeSessionId }, { "ready", playModeReady }, { "availableRuntimeTools", availableTools }
159
110
  };
160
111
  }
161
112
 
@@ -165,10 +116,10 @@ namespace UnityCli
165
116
  /// </summary>
166
117
  private static object RuntimeToolList(UnityCli.Protocol.BridgeRequest request)
167
118
  {
168
- DiscoverProjectTools();
119
+ var catalog = ReadPublishedProjectToolCatalogSnapshot();
169
120
  InitializeRuntimeExecutor();
170
121
  var tools = new System.Collections.Generic.List<object>();
171
- foreach (var definition in ProjectTools.Values.OrderBy(tool => tool.Name, StringComparer.Ordinal))
122
+ foreach (var definition in catalog.Descriptors.OrderBy(tool => tool.Name, StringComparer.Ordinal))
172
123
  {
173
124
  if (definition.Target != "runtime" && definition.Target != "both") continue;
174
125
  var descriptor = ProjectToolDescriptorData(definition);
@@ -192,14 +143,13 @@ namespace UnityCli
192
143
  {
193
144
  public string Name { get; set; }
194
145
  [UnityCliAnyJson] public object Input { get; set; }
195
- public string ExpectedDescriptorFingerprint { get; set; }
196
146
  public string ArtifactDir { get; set; }
197
147
  public string ProjectPath { get; set; }
198
148
  }
199
149
 
200
150
  private static async ValueTask<object> RuntimeToolRun(UnityCli.Protocol.BridgeRequest request, CancellationToken cancellationToken)
201
151
  {
202
- DiscoverProjectTools();
152
+ var catalog = ReadPublishedProjectToolCatalog();
203
153
  InitializeRuntimeExecutor();
204
154
 
205
155
  var args = request.DeserializeArgs<RuntimeToolRunArgs>();
@@ -220,13 +170,13 @@ namespace UnityCli
220
170
  }
221
171
 
222
172
  // Validate the tool exists and is a runtime tool
223
- if (!ProjectTools.ContainsKey(name))
173
+ if (!catalog.ExecutableTools.ContainsKey(name))
224
174
  {
225
175
  throw new BridgeCommandException("E_TOOL_NOT_FOUND", "Tool not found: " + name,
226
176
  "Run unitycli tools group --instance <id|projectPath|alias> or tools search <keyword> to inspect the connected instance catalog.");
227
177
  }
228
178
 
229
- var definition = ProjectTools[name];
179
+ var definition = catalog.ExecutableTools[name];
230
180
  if (definition.Target != "runtime" && definition.Target != "both")
231
181
  {
232
182
  throw new BridgeCommandException("E_RUNTIME_TOOL_TARGET_MISMATCH",
@@ -236,26 +186,6 @@ namespace UnityCli
236
186
  }
237
187
  var dryRun = request.Execution != null && request.Execution.DryRun == true;
238
188
 
239
- // runtime-tool.run 是内部包装命令;门禁前刷新 live 指纹,防止跨 PlayMode/domain reload 重放旧 proof。
240
- var fingerprintCheck = RefreshProjectToolFingerprint(definition);
241
- if (!string.IsNullOrEmpty(args.ExpectedDescriptorFingerprint)
242
- && !string.Equals(args.ExpectedDescriptorFingerprint, definition.Fingerprint, StringComparison.Ordinal))
243
- {
244
- throw new BridgeCommandException(
245
- "E_TOOL_DESCRIPTOR_CHANGED",
246
- "The runtime Tool descriptor changed after discovery: " + name,
247
- new Dictionary<string, object> { { "toolName", name }, { "expectedFingerprint", args.ExpectedDescriptorFingerprint }, { "actualFingerprint", definition.Fingerprint } },
248
- new[] { "Run tools describe again in the current Play Mode generation before constructing a new request." });
249
- }
250
- // Fingerprint policy 使用同一次 live refresh 结果。
251
- if (fingerprintCheck.Blocked)
252
- {
253
- WriteLog("runtime_tool_fingerprint_blocked requestId=" + request.RequestId + " name=" + name);
254
- throw new BridgeCommandException("E_TOOL_FINGERPRINT_MISMATCH", fingerprintCheck.Message,
255
- ProjectToolFingerprintDetails(definition),
256
- ProjectToolFingerprintRePinSteps(definition));
257
- }
258
-
259
189
  // timeout 仅来自顶层 execution,业务 input 不参与执行策略。
260
190
  var timeoutMs = request.ExecutionTimeoutMs(definition.DefaultTimeoutMs, definition.MaxTimeoutMs);
261
191