@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
@@ -0,0 +1,520 @@
1
+ #if UNITY_EDITOR
2
+ using System;
3
+ using System.Collections.Generic;
4
+ using System.Reflection;
5
+ using System.Security.Cryptography;
6
+ using System.Text;
7
+ using System.Threading;
8
+ using System.Threading.Tasks;
9
+ using NUnit.Framework;
10
+ using UnityEngine;
11
+
12
+ namespace UnityCli.Tests
13
+ {
14
+ public sealed class UnityCliRuntimeBridgeIntegrationTests
15
+ {
16
+ private const string ListenerId = "runtime-test-listener";
17
+ private const string Fingerprint = "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa";
18
+ private GameObject host;
19
+ private UnityCliRuntimeBridge bridge;
20
+ private UnityCliAdmissionPool pool;
21
+ private long utcNowMs;
22
+ private long monotonicNowMs;
23
+
24
+ [SetUp]
25
+ public void SetUp()
26
+ {
27
+ host = new GameObject("UnityCli.RuntimeBridge.Test");
28
+ bridge = host.AddComponent<UnityCliRuntimeBridge>();
29
+ bridge.enabled = false;
30
+ utcNowMs = 1000000L;
31
+ monotonicNowMs = 5000L;
32
+ bridge.InjectUtcNowProviderForTests(() => utcNowMs);
33
+ bridge.InjectMonotonicNowProviderForTests(() => monotonicNowMs);
34
+ pool = new UnityCliAdmissionPool("runtime-test-instance", "runtime-test-session", 256, 64, null, () => utcNowMs);
35
+ SetField("admissionPool", pool);
36
+ SetField("listenerId", ListenerId);
37
+ SetField("sessionId", "runtime-test-session");
38
+ }
39
+
40
+ [TearDown]
41
+ public void TearDown()
42
+ {
43
+ if (bridge != null)
44
+ {
45
+ bridge.StopRuntimeRequestsLocked();
46
+ bridge.AssertRuntimeBoundariesDrainedForTests();
47
+ bridge.ResetClockProvidersForTests();
48
+ }
49
+ if (host != null) UnityEngine.Object.DestroyImmediate(host);
50
+ bridge = null;
51
+ host = null;
52
+ pool = null;
53
+ }
54
+
55
+ [Test]
56
+ public void PublicationAndShutdownShareOneProductionBoundary()
57
+ {
58
+ var entered = new ManualResetEventSlim(false);
59
+ var release = new ManualResetEventSlim(false);
60
+ bridge.ExpectRuntimeBoundaryForTests("before-runtime-publish", () =>
61
+ {
62
+ entered.Set();
63
+ release.Wait();
64
+ });
65
+ UnityCliRuntimeBridge.RuntimePublicationResult publication = null;
66
+ var publishTask = Task.Run(() => publication = PublishBypass("runtime-race"));
67
+ Task stopTask = null;
68
+ try
69
+ {
70
+ Assert.That(entered.Wait(5000), Is.True);
71
+ stopTask = Task.Run(() => bridge.StopRuntimeRequestsLocked());
72
+ }
73
+ finally { release.Set(); }
74
+
75
+ Assert.That(publishTask.Wait(5000), Is.True);
76
+ Assert.That(stopTask.Wait(5000), Is.True);
77
+ Assert.That(publication.Outcome, Is.EqualTo(UnityCliRuntimeBridge.RuntimePublicationOutcome.Published));
78
+ Assert.That(publication.Work.Completion.Task.Wait(1000), Is.True);
79
+ Assert.That(publication.Work.Completion.Task.Result, Does.Contain("E_RUNTIME_SESSION_STALE"));
80
+ Assert.That(PublishBypass("runtime-after-stop").Outcome, Is.EqualTo(UnityCliRuntimeBridge.RuntimePublicationOutcome.Stopping));
81
+ }
82
+
83
+ [Test]
84
+ public void RuntimeAdmissionAcquireAndStopShareThePublicationBoundary()
85
+ {
86
+ var entered = new ManualResetEventSlim(false);
87
+ var release = new ManualResetEventSlim(false);
88
+ bridge.ExpectRuntimeBoundaryForTests("before-runtime-admission-acquire", () =>
89
+ {
90
+ entered.Set();
91
+ release.Wait();
92
+ });
93
+ UnityCliAdmissionPool.AcquireResult acquired = null;
94
+ var acquireResult = false;
95
+ var acquireTask = Task.Run(() =>
96
+ {
97
+ UnityCliAdmissionPool.AcquireResult local;
98
+ acquireResult = bridge.TryAcquireRuntimeAdmissionForTests("runtime-admission-stop", Fingerprint, out local);
99
+ acquired = local;
100
+ });
101
+ Task stopTask = null;
102
+ try
103
+ {
104
+ Assert.That(entered.Wait(5000), Is.True);
105
+ stopTask = Task.Run(() => bridge.StopRuntimeRequestsLocked());
106
+ }
107
+ finally { release.Set(); }
108
+
109
+ Assert.That(acquireTask.Wait(5000), Is.True);
110
+ Assert.That(stopTask.Wait(5000), Is.True);
111
+ Assert.That(acquireResult, Is.True);
112
+ Assert.That(acquired.Outcome, Is.EqualTo(UnityCliAdmissionPool.AcquireOutcome.Granted));
113
+ Assert.That(pool.Capture().Active, Is.EqualTo(0));
114
+ Assert.That(bridge.TryAcquireRuntimeAdmissionForTests("runtime-admission-after-stop", Fingerprint, out acquired), Is.False);
115
+ Assert.That(acquired, Is.Null);
116
+ }
117
+
118
+ [Test]
119
+ public void RuntimeStopWinningAdmissionRaceReturnsOnlySessionStale()
120
+ {
121
+ var entered = new ManualResetEventSlim(false);
122
+ var release = new ManualResetEventSlim(false);
123
+ bridge.ExpectRuntimeBoundaryForTests("before-runtime-stop", () =>
124
+ {
125
+ entered.Set();
126
+ release.Wait();
127
+ });
128
+ var stopTask = Task.Run(() => bridge.StopRuntimeRequestsLocked());
129
+ var acquireResult = true;
130
+ UnityCliAdmissionPool.AcquireResult acquired = null;
131
+ Task acquireTask = null;
132
+ try
133
+ {
134
+ Assert.That(entered.Wait(5000), Is.True);
135
+ acquireTask = Task.Run(() =>
136
+ {
137
+ UnityCliAdmissionPool.AcquireResult local;
138
+ acquireResult = bridge.TryAcquireRuntimeAdmissionForTests("runtime-stop-wins", Fingerprint, out local);
139
+ acquired = local;
140
+ });
141
+ }
142
+ finally { release.Set(); }
143
+
144
+ Assert.That(stopTask.Wait(5000), Is.True);
145
+ Assert.That(acquireTask.Wait(5000), Is.True);
146
+ Assert.That(acquireResult, Is.False);
147
+ Assert.That(acquired, Is.Null);
148
+ Assert.That(pool.Capture().Active, Is.EqualTo(0));
149
+ }
150
+
151
+ [Test]
152
+ public void RecoveryBlockedAuthorizationRevokesItsExactUnconsumedGrant()
153
+ {
154
+ var requestId = "runtime-blocked-authorization";
155
+ var request = Request(requestId, "runtime-tool.run");
156
+ var digest = Digest('2');
157
+ var deadline = Deadline();
158
+ var admission = Admission(requestId, digest, deadline);
159
+ pool.BlockRecovery();
160
+
161
+ var publication = bridge.PublishRuntimeRequest(request, deadline, digest, admission);
162
+
163
+ Assert.That(publication.Outcome, Is.EqualTo(UnityCliRuntimeBridge.RuntimePublicationOutcome.Rejected));
164
+ Assert.That(publication.Error, Does.Contain("E_ADMISSION_IDENTITY_MISMATCH"));
165
+ Assert.That(pool.Capture().Active, Is.EqualTo(0));
166
+ }
167
+
168
+ [Test]
169
+ public void UnauthorizedCapacityAndPublicationFaultDoNotLeakAdmissionOrLoseExistingCache()
170
+ {
171
+ var first = PublishBypass("runtime-first");
172
+ Assert.That(first.Outcome, Is.EqualTo(UnityCliRuntimeBridge.RuntimePublicationOutcome.Published));
173
+
174
+ var unauthorizedRequest = Request("runtime-unauthorized", "runtime-tool.run");
175
+ var unauthorized = bridge.PublishRuntimeRequest(unauthorizedRequest, Deadline(), Digest('b'), new UnityCliRuntimeBridge.RuntimeAdmissionInput());
176
+ Assert.That(unauthorized.Outcome, Is.EqualTo(UnityCliRuntimeBridge.RuntimePublicationOutcome.Rejected));
177
+ Assert.That(unauthorized.Error, Does.Contain("E_ADMISSION_REQUIRED"));
178
+ Assert.That(PublishBypass("runtime-first").Outcome, Is.EqualTo(UnityCliRuntimeBridge.RuntimePublicationOutcome.Existing));
179
+
180
+ var faultRequest = Request("runtime-publication-fault", "runtime-tool.run");
181
+ var faultDigest = Digest('c');
182
+ var faultAdmission = Admission(faultRequest["requestId"] as string, faultDigest, Deadline());
183
+ bridge.ExpectRuntimeBoundaryForTests("before-runtime-publish", () => { throw new InvalidOperationException("injected publication fault"); });
184
+ Assert.Throws<InvalidOperationException>(() => bridge.PublishRuntimeRequest(faultRequest, Deadline(), faultDigest, faultAdmission));
185
+ Assert.That(pool.Capture().Active, Is.EqualTo(0));
186
+ Assert.That(PublishBypass("runtime-first").Outcome, Is.EqualTo(UnityCliRuntimeBridge.RuntimePublicationOutcome.Existing));
187
+
188
+ for (var index = 1; index < 128; index++)
189
+ Assert.That(PublishBypass("runtime-capacity-" + index).Outcome, Is.EqualTo(UnityCliRuntimeBridge.RuntimePublicationOutcome.Published));
190
+ var fullRequest = Request("runtime-capacity-rejected", "runtime-tool.run");
191
+ var fullDigest = Digest('d');
192
+ var full = bridge.PublishRuntimeRequest(fullRequest, Deadline(), fullDigest, Admission("runtime-capacity-rejected", fullDigest, Deadline()));
193
+ Assert.That(full.Outcome, Is.EqualTo(UnityCliRuntimeBridge.RuntimePublicationOutcome.QueueFull));
194
+ Assert.That(pool.Capture().Active, Is.EqualTo(0));
195
+ Assert.That(PublishBypass("runtime-first").Outcome, Is.EqualTo(UnityCliRuntimeBridge.RuntimePublicationOutcome.Existing));
196
+ }
197
+
198
+ [Test]
199
+ public void CompensationFaultRetainsExactOwnerUntilBoundedOnlineRecovery()
200
+ {
201
+ var requestId = "runtime-compensation-fault";
202
+ var request = Request(requestId, "runtime-tool.run");
203
+ var digest = Digest('7');
204
+ var deadline = Deadline();
205
+ var admission = Admission(requestId, digest, deadline);
206
+ bridge.ExpectRuntimeBoundaryForTests("before-runtime-publish", () => { throw new InvalidOperationException("injected publication fault"); });
207
+ bridge.ExpectRuntimeBoundaryForTests("before-runtime-compensation", () =>
208
+ {
209
+ pool.BlockRecovery();
210
+ throw new InvalidOperationException("injected compensation fault");
211
+ });
212
+
213
+ var publication = bridge.PublishRuntimeRequest(request, deadline, digest, admission);
214
+
215
+ Assert.That(publication.Outcome, Is.EqualTo(UnityCliRuntimeBridge.RuntimePublicationOutcome.Rejected));
216
+ Assert.That(publication.Work, Is.Not.Null);
217
+ Assert.That(publication.Work.Completion.Task.IsCompleted, Is.False);
218
+ Assert.That(bridge.PendingRuntimeSettlementCountForTests(), Is.EqualTo(1));
219
+ var duplicate = bridge.PublishRuntimeRequest(request, deadline, digest, new UnityCliRuntimeBridge.RuntimeAdmissionInput());
220
+ Assert.That(duplicate.Outcome, Is.EqualTo(UnityCliRuntimeBridge.RuntimePublicationOutcome.Existing));
221
+ Assert.That(duplicate.Work, Is.SameAs(publication.Work));
222
+
223
+ pool.Reset();
224
+ monotonicNowMs += 100L;
225
+ bridge.RetryPendingRuntimeSettlementsForTests();
226
+
227
+ Assert.That(publication.Work.Completion.Task.IsCompleted, Is.True);
228
+ Assert.That(publication.Work.Completion.Task.Result, Does.Contain("E_RUNTIME_BRIDGE_FAILED"));
229
+ Assert.That(bridge.PendingRuntimeSettlementCountForTests(), Is.EqualTo(0));
230
+ Assert.That(pool.Capture().Active, Is.EqualTo(0));
231
+ }
232
+
233
+ [Test]
234
+ public void CompletedCacheEvictionCommitsOnlyAfterProductionEnqueue()
235
+ {
236
+ for (var index = 0; index < 160; index++)
237
+ {
238
+ var publication = PublishBypass("runtime-cache-" + index);
239
+ Assert.That(publication.Outcome, Is.EqualTo(UnityCliRuntimeBridge.RuntimePublicationOutcome.Published));
240
+ var running = TakeNext();
241
+ Assert.That(running, Is.SameAs(publication.Work));
242
+ Assert.That(Finalize(running, "terminal-" + index, 1), Is.True);
243
+ }
244
+ bridge.ExpectRuntimeBoundaryForTests("before-runtime-publish", () => { throw new InvalidOperationException("injected eviction publication fault"); });
245
+ Assert.Throws<InvalidOperationException>(() => PublishBypass("runtime-cache-new"));
246
+ Assert.That(PublishBypass("runtime-cache-0").Outcome, Is.EqualTo(UnityCliRuntimeBridge.RuntimePublicationOutcome.Existing));
247
+
248
+ Assert.That(PublishBypass("runtime-cache-new").Outcome, Is.EqualTo(UnityCliRuntimeBridge.RuntimePublicationOutcome.Published));
249
+ Assert.That(PublishBypass("runtime-cache-0").Outcome, Is.EqualTo(UnityCliRuntimeBridge.RuntimePublicationOutcome.Published));
250
+ }
251
+
252
+ [Test]
253
+ public void ExpiredReplayIsLinearizedBeforeCacheMissFreshness()
254
+ {
255
+ var requestId = "runtime-expired-replay";
256
+ var digest = DigestFor(requestId);
257
+ var originalDeadline = utcNowMs + 500L;
258
+ var originalRequest = Request(requestId, "runtime-tool.list", originalDeadline);
259
+ var seeded = bridge.PublishRuntimeRequest(originalRequest, originalDeadline, digest, new UnityCliRuntimeBridge.RuntimeAdmissionInput());
260
+ Assert.That(seeded.Outcome, Is.EqualTo(UnityCliRuntimeBridge.RuntimePublicationOutcome.Published));
261
+ var terminalWork = TakeNext();
262
+ Assert.That(terminalWork, Is.SameAs(seeded.Work));
263
+ Assert.That(Finalize(terminalWork, "expired-existing-terminal", 1), Is.True);
264
+ utcNowMs = originalDeadline + 1L;
265
+ Assert.That(utcNowMs, Is.GreaterThanOrEqualTo(originalDeadline));
266
+
267
+ var exactTask = Task.Run(() => bridge.PublishRuntimeRequest(originalRequest, originalDeadline, digest, new UnityCliRuntimeBridge.RuntimeAdmissionInput()));
268
+ var mismatchTask = Task.Run(() => bridge.PublishRuntimeRequest(originalRequest, originalDeadline, Digest('f'), new UnityCliRuntimeBridge.RuntimeAdmissionInput()));
269
+
270
+ Assert.That(Task.WaitAll(new Task[] { exactTask, mismatchTask }, 5000), Is.True);
271
+ Assert.That(exactTask.Result.Outcome, Is.EqualTo(UnityCliRuntimeBridge.RuntimePublicationOutcome.Existing));
272
+ Assert.That(exactTask.Result.Work, Is.SameAs(seeded.Work));
273
+ Assert.That(exactTask.Result.Work.Completion.Task.Result, Is.EqualTo("expired-existing-terminal"));
274
+ Assert.That(mismatchTask.Result.Outcome, Is.EqualTo(UnityCliRuntimeBridge.RuntimePublicationOutcome.Rejected));
275
+ Assert.That(mismatchTask.Result.Error, Does.Contain("E_REQUEST_REPLAY_MISMATCH"));
276
+
277
+ var expired = utcNowMs - 1L;
278
+ var miss = bridge.PublishRuntimeRequest(Request("runtime-expired-miss", "runtime-tool.list", expired), expired, DigestFor("runtime-expired-miss"), new UnityCliRuntimeBridge.RuntimeAdmissionInput());
279
+ Assert.That(miss.Outcome, Is.EqualTo(UnityCliRuntimeBridge.RuntimePublicationOutcome.Rejected));
280
+ Assert.That(miss.Error, Does.Contain("E_SCHEMA_INVALID"));
281
+ Assert.That(bridge.PublishRuntimeRequest(originalRequest, originalDeadline, digest, new UnityCliRuntimeBridge.RuntimeAdmissionInput()).Outcome,
282
+ Is.EqualTo(UnityCliRuntimeBridge.RuntimePublicationOutcome.Existing));
283
+ }
284
+
285
+ [Test]
286
+ public void RunningRequestDeadlineReturnsTimeoutWithoutWaitingForTerminalOwner()
287
+ {
288
+ var deadline = utcNowMs + 10L;
289
+ var request = Request("runtime-running-deadline", "runtime-tool.run", deadline);
290
+ var digest = Digest('9');
291
+ var publication = bridge.PublishRuntimeRequest(request, deadline, digest, Admission("runtime-running-deadline", digest, deadline));
292
+ Assert.That(publication.Outcome, Is.EqualTo(UnityCliRuntimeBridge.RuntimePublicationOutcome.Published));
293
+ var running = TakeNext();
294
+ var waits = 0;
295
+ var response = bridge.AwaitRuntimeResponseForTests(running, new UnityCliRuntimeBridge.RuntimeWaitDependencies(
296
+ () => utcNowMs,
297
+ (completion, timeoutMs) => { waits++; utcNowMs = deadline + 1L; return false; },
298
+ () => false));
299
+
300
+ Assert.That(response, Does.Contain("E_EXECUTION_TIMEOUT"));
301
+ Assert.That(waits, Is.EqualTo(1));
302
+ Assert.That(running.Completion.Task.IsCompleted, Is.False);
303
+ Assert.That(pool.Capture().Active, Is.EqualTo(1));
304
+ Assert.That(Finalize(running, "running-deadline-terminal", 1), Is.True);
305
+ Assert.That(running.Completion.Task.Result, Is.EqualTo("running-deadline-terminal"));
306
+ Assert.That(pool.Capture().Active, Is.EqualTo(0));
307
+ }
308
+
309
+ [Test]
310
+ public void BlockedCompletionRetainsTerminalAndExactDuplicateUntilOwnerIsDefinitelyAbsent()
311
+ {
312
+ var requestId = "runtime-blocked-completion";
313
+ var request = Request(requestId, "runtime-tool.run");
314
+ var digest = Digest('8');
315
+ var deadline = Deadline();
316
+ var publication = bridge.PublishRuntimeRequest(request, deadline, digest, Admission(requestId, digest, deadline));
317
+ var running = TakeNext();
318
+ pool.BlockRecovery();
319
+
320
+ Assert.That(Finalize(running, "blocked-terminal", 1), Is.False);
321
+ Assert.That(running.Completion.Task.IsCompleted, Is.False);
322
+ Assert.That(bridge.PendingRuntimeSettlementCountForTests(), Is.EqualTo(1));
323
+ var duplicate = bridge.PublishRuntimeRequest(request, deadline, digest, new UnityCliRuntimeBridge.RuntimeAdmissionInput());
324
+ Assert.That(duplicate.Outcome, Is.EqualTo(UnityCliRuntimeBridge.RuntimePublicationOutcome.Existing));
325
+ Assert.That(duplicate.Work, Is.SameAs(running));
326
+
327
+ pool.Reset();
328
+ monotonicNowMs += 100L;
329
+ bridge.RetryPendingRuntimeSettlementsForTests();
330
+
331
+ Assert.That(running.Completion.Task.Result, Is.EqualTo("blocked-terminal"));
332
+ Assert.That(bridge.PendingRuntimeSettlementCountForTests(), Is.EqualTo(0));
333
+ }
334
+
335
+ [Test]
336
+ public void RecoveryBlockedFrozenTerminalSettlesDuringShutdownWithoutAPump()
337
+ {
338
+ var requestId = "runtime-blocked-frozen-shutdown";
339
+ var request = Request(requestId, "runtime-tool.run");
340
+ var digest = Digest('3');
341
+ var deadline = Deadline();
342
+ var publication = bridge.PublishRuntimeRequest(request, deadline, digest, Admission(requestId, digest, deadline));
343
+ var running = TakeNext();
344
+ pool.BlockRecovery();
345
+ Assert.That(Finalize(running, "frozen-shutdown-terminal", 1), Is.False);
346
+ Assert.That(bridge.PendingRuntimeSettlementCountForTests(), Is.EqualTo(1));
347
+
348
+ bridge.StopRuntimeRequestsLocked();
349
+
350
+ Assert.That(publication.Work.Completion.Task.IsCompleted, Is.True);
351
+ Assert.That(publication.Work.Completion.Task.Result, Is.EqualTo("frozen-shutdown-terminal"));
352
+ Assert.That(pool.Capture().Active, Is.EqualTo(0));
353
+ Assert.That(bridge.PendingRuntimeSettlementCountForTests(), Is.EqualTo(0));
354
+ }
355
+
356
+ [Test]
357
+ public void ShutdownFinalizesQueuedAdmissionOwnerBeforeAnyDequeueEffectOwnership()
358
+ {
359
+ var requestId = "runtime-queued-shutdown";
360
+ var request = Request(requestId, "runtime-tool.run");
361
+ var digest = Digest('6');
362
+ var deadline = Deadline();
363
+ var publication = bridge.PublishRuntimeRequest(request, deadline, digest, Admission(requestId, digest, deadline));
364
+ Assert.That(publication.Outcome, Is.EqualTo(UnityCliRuntimeBridge.RuntimePublicationOutcome.Published));
365
+ Assert.That(pool.Capture().Active, Is.EqualTo(1));
366
+
367
+ bridge.StopRuntimeRequestsLocked();
368
+
369
+ Assert.That(publication.Work.Completion.Task.IsCompleted, Is.True);
370
+ Assert.That(publication.Work.Completion.Task.Result, Does.Contain("E_RUNTIME_SESSION_STALE"));
371
+ Assert.That(pool.Capture().Active, Is.EqualTo(0));
372
+ Assert.That(bridge.PendingRuntimeSettlementCountForTests(), Is.EqualTo(0));
373
+ UnityCliRuntimeBridge.PendingRequest ignored;
374
+ Assert.That(TryTake(out ignored), Is.False);
375
+ Assert.That(ignored, Is.Null);
376
+ }
377
+
378
+ [Test]
379
+ public void RecoveryBlockedShutdownSettlesQueuedAndRunningAgainstCapturedPoolExactlyOnce()
380
+ {
381
+ var runningRequest = Request("runtime-running-shutdown", "runtime-tool.run");
382
+ var runningDigest = Digest('e');
383
+ var runningPublication = bridge.PublishRuntimeRequest(runningRequest, Deadline(), runningDigest,
384
+ Admission("runtime-running-shutdown", runningDigest, Deadline()));
385
+ Assert.That(runningPublication.Outcome, Is.EqualTo(UnityCliRuntimeBridge.RuntimePublicationOutcome.Published));
386
+ var running = TakeNext();
387
+ var queuedRequest = Request("runtime-blocked-queued-shutdown", "runtime-tool.run");
388
+ var queuedDigest = Digest('5');
389
+ var queuedPublication = bridge.PublishRuntimeRequest(queuedRequest, Deadline(), queuedDigest,
390
+ Admission("runtime-blocked-queued-shutdown", queuedDigest, Deadline()));
391
+ Assert.That(queuedPublication.Outcome, Is.EqualTo(UnityCliRuntimeBridge.RuntimePublicationOutcome.Published));
392
+ pool.BlockRecovery();
393
+ Assert.That(pool.Capture().Active, Is.EqualTo(2));
394
+
395
+ bridge.StopRuntimeRequestsLocked();
396
+
397
+ Assert.That(running.Completion.Task.IsCompleted, Is.True);
398
+ Assert.That(running.Completion.Task.Result, Does.Contain("E_EXECUTION_TIMEOUT"));
399
+ Assert.That(queuedPublication.Work.Completion.Task.IsCompleted, Is.True);
400
+ Assert.That(queuedPublication.Work.Completion.Task.Result, Does.Contain("E_RUNTIME_SESSION_STALE"));
401
+ Assert.That(pool.Capture().Active, Is.EqualTo(0));
402
+ Assert.That(bridge.PendingRuntimeSettlementCountForTests(), Is.EqualTo(0));
403
+ Assert.That(Finalize(running, "late-running-terminal", 1), Is.False);
404
+ Assert.That(Finalize(queuedPublication.Work, "late-queued-terminal", 0), Is.False);
405
+ Assert.That(running.Completion.Task.Result, Does.Contain("E_EXECUTION_TIMEOUT"));
406
+ Assert.That(queuedPublication.Work.Completion.Task.Result, Does.Contain("E_RUNTIME_SESSION_STALE"));
407
+ Assert.That(PublishBypass("runtime-after-running-stop").Outcome, Is.EqualTo(UnityCliRuntimeBridge.RuntimePublicationOutcome.Stopping));
408
+ }
409
+
410
+ [Test]
411
+ public void SettlementBackoffUsesMonotonicClockAcrossUtcJumps()
412
+ {
413
+ var requestId = "runtime-monotonic-settlement";
414
+ var request = Request(requestId, "runtime-tool.run");
415
+ var digest = Digest('4');
416
+ var deadline = Deadline();
417
+ var publication = bridge.PublishRuntimeRequest(request, deadline, digest, Admission(requestId, digest, deadline));
418
+ var running = TakeNext();
419
+ pool.BlockRecovery();
420
+ Assert.That(Finalize(running, "monotonic-terminal", 1), Is.False);
421
+ pool.Reset();
422
+
423
+ utcNowMs += 86400000L;
424
+ bridge.RetryPendingRuntimeSettlementsForTests();
425
+ Assert.That(publication.Work.Completion.Task.IsCompleted, Is.False);
426
+ utcNowMs -= 172800000L;
427
+ bridge.RetryPendingRuntimeSettlementsForTests();
428
+ Assert.That(publication.Work.Completion.Task.IsCompleted, Is.False);
429
+ monotonicNowMs += 99L;
430
+ bridge.RetryPendingRuntimeSettlementsForTests();
431
+ Assert.That(publication.Work.Completion.Task.IsCompleted, Is.False);
432
+ monotonicNowMs += 1L;
433
+ bridge.RetryPendingRuntimeSettlementsForTests();
434
+
435
+ Assert.That(publication.Work.Completion.Task.Result, Is.EqualTo("monotonic-terminal"));
436
+ Assert.That(bridge.PendingRuntimeSettlementCountForTests(), Is.EqualTo(0));
437
+ }
438
+
439
+ private UnityCliRuntimeBridge.RuntimePublicationResult PublishBypass(string requestId)
440
+ {
441
+ return bridge.PublishRuntimeRequest(Request(requestId, "runtime-tool.list"), Deadline(), DigestFor(requestId), new UnityCliRuntimeBridge.RuntimeAdmissionInput());
442
+ }
443
+
444
+ private UnityCliRuntimeBridge.RuntimeAdmissionInput Admission(string requestId, string digest, long deadline)
445
+ {
446
+ var grant = pool.Acquire(requestId, Fingerprint, ListenerId, 1L);
447
+ Assert.That(grant.Outcome, Is.EqualTo(UnityCliAdmissionPool.AcquireOutcome.Granted));
448
+ return new UnityCliRuntimeBridge.RuntimeAdmissionInput
449
+ {
450
+ RootId = requestId,
451
+ Fingerprint = Fingerprint,
452
+ Token = grant.Token,
453
+ DeadlineUtc = DateTimeOffset.FromUnixTimeMilliseconds(deadline).ToString("O")
454
+ };
455
+ }
456
+
457
+ private UnityCliRuntimeBridge.PendingRequest TakeNext()
458
+ {
459
+ UnityCliRuntimeBridge.PendingRequest request;
460
+ Assert.That(TryTake(out request), Is.True);
461
+ return request;
462
+ }
463
+
464
+ private bool TryTake(out UnityCliRuntimeBridge.PendingRequest request)
465
+ {
466
+ var method = typeof(UnityCliRuntimeBridge).GetMethod("TryTakeNextRuntimeRequest", BindingFlags.Instance | BindingFlags.NonPublic);
467
+ Assert.That(method, Is.Not.Null);
468
+ var arguments = new object[] { null };
469
+ var result = (bool)method.Invoke(bridge, arguments);
470
+ request = (UnityCliRuntimeBridge.PendingRequest)arguments[0];
471
+ return result;
472
+ }
473
+
474
+ private bool Finalize(UnityCliRuntimeBridge.PendingRequest request, string terminal, int expectedState)
475
+ {
476
+ var method = typeof(UnityCliRuntimeBridge).GetMethod("FinalizeRuntimeRequest", BindingFlags.Instance | BindingFlags.NonPublic);
477
+ Assert.That(method, Is.Not.Null);
478
+ return (bool)method.Invoke(bridge, new object[] { request, terminal, expectedState });
479
+ }
480
+
481
+ private void SetField(string name, object value)
482
+ {
483
+ var field = typeof(UnityCliRuntimeBridge).GetField(name, BindingFlags.Instance | BindingFlags.NonPublic);
484
+ Assert.That(field, Is.Not.Null, name);
485
+ field.SetValue(bridge, value);
486
+ }
487
+
488
+ private Dictionary<string, object> Request(string requestId, string command)
489
+ {
490
+ return Request(requestId, command, Deadline());
491
+ }
492
+
493
+ private static Dictionary<string, object> Request(string requestId, string command, long absoluteDeadlineMs)
494
+ {
495
+ return new Dictionary<string, object>
496
+ {
497
+ { "protocolVersion", (long)2 }, { "instanceId", "runtime-test-instance" }, { "command", command },
498
+ { "requestId", requestId }, { "input", new Dictionary<string, object>() },
499
+ { "execution", new Dictionary<string, object>
500
+ {
501
+ { "absoluteDeadlineUtc", DateTimeOffset.FromUnixTimeMilliseconds(absoluteDeadlineMs).ToString("O") },
502
+ { "completionContractVersion", (long)1 }, { "requestDigestVersion", (long)1 }
503
+ }
504
+ }
505
+ };
506
+ }
507
+
508
+ private long Deadline() { return utcNowMs + 60000L; }
509
+ private static string Digest(char value) { return new string(value, 64); }
510
+ private static string DigestFor(string requestId)
511
+ {
512
+ using (var sha = SHA256.Create())
513
+ {
514
+ var bytes = sha.ComputeHash(Encoding.UTF8.GetBytes(requestId));
515
+ return BitConverter.ToString(bytes).Replace("-", string.Empty).ToLowerInvariant();
516
+ }
517
+ }
518
+ }
519
+ }
520
+ #endif