@alpsckr/unitycli 0.4.2 → 0.4.4

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