@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,292 @@
1
+ using System;
2
+ using System.Collections.Generic;
3
+ using System.Globalization;
4
+ using System.Linq;
5
+ using System.Threading;
6
+ using System.Threading.Tasks;
7
+ using NUnit.Framework;
8
+ using UnityEditor;
9
+ using UnityEditor.SceneManagement;
10
+ using UnityEngine;
11
+ using UnityEngine.SceneManagement;
12
+
13
+ namespace UnityCli.Tests
14
+ {
15
+ public sealed class UnityCliContinuationIntegrationTests
16
+ {
17
+ private const string PrefabFolder = "Assets/UnityCliTests";
18
+ private const string PrefabPath = PrefabFolder + "/issue-042-continuation.prefab";
19
+
20
+ [TearDown]
21
+ public void TearDown()
22
+ {
23
+ FrameDebuggerReflection.ResetTestOverrides();
24
+ var stage = PrefabStageUtility.GetCurrentPrefabStage();
25
+ if (stage != null && string.Equals(PrefabToolSupport.StageAssetPath(stage), PrefabPath, StringComparison.OrdinalIgnoreCase))
26
+ {
27
+ PrefabToolSupport.SavePrefabStage(stage);
28
+ PrefabToolSupport.ClosePrefabStage();
29
+ }
30
+ AssetDatabase.DeleteAsset(PrefabPath);
31
+ if (AssetDatabase.IsValidFolder(PrefabFolder) && AssetDatabase.FindAssets(string.Empty, new[] { PrefabFolder }).Length == 0)
32
+ AssetDatabase.DeleteAsset(PrefabFolder);
33
+ }
34
+
35
+ [Test]
36
+ public void FrameDebuggerPagesEntireControlledCaptureAndRejectsChangedDeletedOrUnknownPositions()
37
+ {
38
+ const int eventCount = 1203;
39
+ var capture = "capture-a";
40
+ var currentCount = eventCount;
41
+ FrameDebuggerReflection.AvailableOverrideForTests = true;
42
+ FrameDebuggerReflection.EnabledOverrideForTests = () => true;
43
+ FrameDebuggerReflection.EventCountOverrideForTests = () => currentCount;
44
+ FrameDebuggerReflection.EventNameOverrideForTests = index => "event-" + index.ToString("D4", CultureInfo.InvariantCulture);
45
+ FrameDebuggerReflection.EventDataOverrideForTests = index => null;
46
+ FrameDebuggerReflection.GenerationOverrideForTests = () => capture;
47
+
48
+ var tool = new ProfilerFrameDebuggerEventsTool();
49
+ var indices = new List<long>();
50
+ string cursor = null;
51
+ string firstCursor = null;
52
+ string generation = null;
53
+ var pageCount = 0;
54
+ do
55
+ {
56
+ var page = tool.ExecuteAsync(
57
+ new ProfilerFrameDebuggerEventsTool.Request { PageSize = 500, Cursor = cursor },
58
+ Context("issue-042-frame-" + pageCount.ToString(CultureInfo.InvariantCulture))).GetAwaiter().GetResult();
59
+ pageCount++;
60
+ Assert.That(page.TotalEvents, Is.EqualTo(eventCount));
61
+ Assert.That(page.PageInfo.Cursor, Is.EqualTo(cursor));
62
+ Assert.That(page.PageInfo.ReturnedCount, Is.EqualTo(page.Events.Count));
63
+ Assert.That(page.Budget.ScannedRecords, Is.LessThanOrEqualTo(500));
64
+ Assert.That(page.Budget.Nodes, Is.LessThanOrEqualTo(500));
65
+ if (generation == null) generation = page.PageInfo.Generation;
66
+ else Assert.That(page.PageInfo.Generation, Is.EqualTo(generation));
67
+ indices.AddRange(page.Events.Select(item => item.Index));
68
+ cursor = page.PageInfo.NextCursor;
69
+ if (firstCursor == null) firstCursor = cursor;
70
+ } while (cursor != null);
71
+
72
+ CollectionAssert.AreEqual(Enumerable.Range(0, eventCount).Select(index => (long)index).ToArray(), indices.ToArray());
73
+ Assert.That(pageCount, Is.EqualTo(3));
74
+ Assert.That(indices.Distinct().Count(), Is.EqualTo(eventCount));
75
+
76
+ capture = "capture-b";
77
+ AssertStale(tool, firstCursor, "issue-042-frame-generation");
78
+ capture = "capture-a";
79
+ currentCount--;
80
+ AssertStale(tool, firstCursor, "issue-042-frame-deleted");
81
+ currentCount = eventCount;
82
+ var unknown = UnityCliContinuationToken.Create("profiler.frame-debugger.events", generation, "unknown");
83
+ AssertStale(tool, unknown, "issue-042-frame-unknown");
84
+ }
85
+
86
+ [Test]
87
+ public void FrameDebuggerHonorsDeadlineAndCancellationBeforePublishingPartialEvents()
88
+ {
89
+ var clock = new ManualClock();
90
+ FrameDebuggerReflection.AvailableOverrideForTests = true;
91
+ FrameDebuggerReflection.EventCountOverrideForTests = () => 10;
92
+ FrameDebuggerReflection.GenerationOverrideForTests = () => "capture-deadline";
93
+ FrameDebuggerReflection.EventNameOverrideForTests = index =>
94
+ {
95
+ clock.Advance(2);
96
+ return "event-" + index.ToString(CultureInfo.InvariantCulture);
97
+ };
98
+ FrameDebuggerReflection.EventDataOverrideForTests = index => null;
99
+ var budget = new UnityCliRequestBudget(
100
+ new UnityCliReadBudgetInput { MaxMainThreadMilliseconds = 1 },
101
+ 30000,
102
+ CancellationToken.None,
103
+ clock);
104
+ var deadline = Assert.Throws<UnityCliRequestBudgetExceededException>(() => ProfilerFrameDebuggerEventsTool.ReadPage(
105
+ new ProfilerFrameDebuggerEventsTool.Request { PageSize = 5 }, budget));
106
+ Assert.That(deadline.Dimension, Is.EqualTo("mainThreadMilliseconds"));
107
+
108
+ var cancellation = new CancellationTokenSource();
109
+ cancellation.Cancel();
110
+ Assert.Throws<OperationCanceledException>(() => new ProfilerFrameDebuggerEventsTool().ExecuteAsync(
111
+ new ProfilerFrameDebuggerEventsTool.Request { PageSize = 5 },
112
+ Context("issue-042-frame-cancel", cancellation.Token)).GetAwaiter().GetResult());
113
+ }
114
+
115
+ [Test]
116
+ public void ConcurrentFramePagesUseIndependentBudgetsAndRetainNoSnapshotState()
117
+ {
118
+ FrameDebuggerReflection.AvailableOverrideForTests = true;
119
+ FrameDebuggerReflection.EventCountOverrideForTests = () => 64;
120
+ FrameDebuggerReflection.EventNameOverrideForTests = index => "event-" + index.ToString(CultureInfo.InvariantCulture);
121
+ FrameDebuggerReflection.EventDataOverrideForTests = index => null;
122
+ FrameDebuggerReflection.GenerationOverrideForTests = () => "capture-concurrent";
123
+ var pages = new ProfilerFrameDebuggerEventsTool.Result[8];
124
+
125
+ Parallel.For(0, pages.Length, index =>
126
+ {
127
+ var budget = new UnityCliRequestBudget(null, 30000, CancellationToken.None);
128
+ pages[index] = ProfilerFrameDebuggerEventsTool.ReadPage(
129
+ new ProfilerFrameDebuggerEventsTool.Request { PageSize = 7 }, budget);
130
+ });
131
+
132
+ Assert.That(pages.All(page => page.Events.Count == 7), Is.True);
133
+ Assert.That(pages.All(page => page.Events.Select(item => item.Index).SequenceEqual(Enumerable.Range(0, 7).Select(value => (long)value))), Is.True);
134
+ Assert.That(pages.Select(page => page.PageInfo.NextCursor).Distinct().Count(), Is.EqualTo(1));
135
+ Assert.That(pages.All(page => page.Budget.ScannedRecords == 7 && page.Budget.Nodes == 7), Is.True);
136
+ }
137
+
138
+ [Test]
139
+ public void PrefabStagePagesWithoutDuplicatesAndRejectsGenerationOrDeletedBoundary()
140
+ {
141
+ CreatePrefabFixture(17);
142
+ Assert.That(PrefabToolSupport.OpenPrefabStage(PrefabPath), Is.True);
143
+ var stage = PrefabStageUtility.GetCurrentPrefabStage();
144
+ Assert.That(stage, Is.Not.Null);
145
+ Assert.That(stage.prefabContentsRoot, Is.Not.Null);
146
+
147
+ var tool = new GameObjectFindTool();
148
+ var ids = new List<long>();
149
+ string cursor = null;
150
+ string firstCursor = null;
151
+ do
152
+ {
153
+ var page = tool.ExecuteAsync(new GameObjectFindTool.Request
154
+ {
155
+ SearchTerm = "issue-042-match",
156
+ SearchMethod = "by_name",
157
+ IncludeInactive = true,
158
+ PreferPrefabStage = true,
159
+ PageSize = 4,
160
+ Cursor = cursor
161
+ }, Context("issue-042-prefab-page")).GetAwaiter().GetResult();
162
+ Assert.That(page.PrefabStageOpen, Is.True);
163
+ Assert.That(page.PageInfo.Cursor, Is.EqualTo(cursor));
164
+ ids.AddRange(page.Items.Select(item => item.Id));
165
+ cursor = page.PageInfo.NextCursor;
166
+ if (firstCursor == null) firstCursor = cursor;
167
+ } while (cursor != null);
168
+
169
+ Assert.That(ids.Count, Is.EqualTo(17));
170
+ Assert.That(ids.Distinct().Count(), Is.EqualTo(17));
171
+
172
+ UnityCliReadGeneration.InvalidateHierarchy();
173
+ AssertGoFindStale(tool, firstCursor, "issue-042-prefab-generation");
174
+
175
+ var fresh = tool.ExecuteAsync(new GameObjectFindTool.Request
176
+ {
177
+ SearchTerm = "issue-042-match",
178
+ SearchMethod = "by_name",
179
+ IncludeInactive = true,
180
+ PreferPrefabStage = true,
181
+ PageSize = 1
182
+ }, Context("issue-042-prefab-deleted-first")).GetAwaiter().GetResult();
183
+ string position;
184
+ Assert.That(UnityCliContinuationToken.TryParse(
185
+ fresh.PageInfo.NextCursor, "go.find", fresh.PageInfo.Generation, out position), Is.True);
186
+ var separator = position.IndexOf(':');
187
+ int instanceId;
188
+ Assert.That(separator, Is.GreaterThan(0));
189
+ Assert.That(int.TryParse(position.Substring(separator + 1), NumberStyles.Integer, CultureInfo.InvariantCulture, out instanceId), Is.True);
190
+ var deletedBoundary = EditorUtility.InstanceIDToObject(instanceId);
191
+ Assert.That(deletedBoundary, Is.Not.Null);
192
+ UnityEngine.Object.DestroyImmediate(deletedBoundary);
193
+ AssertGoFindStale(tool, fresh.PageInfo.NextCursor, "issue-042-prefab-deleted");
194
+ }
195
+
196
+ [Test]
197
+ public void ExactIdSelectorDoesNotScanLargeSceneAndUnknownIdsReturnEmpty()
198
+ {
199
+ var scene = EditorSceneManager.NewPreviewScene();
200
+ try
201
+ {
202
+ GameObject target = null;
203
+ for (var index = 0; index < 1000; index++)
204
+ {
205
+ var value = new GameObject("issue-042-exact-" + index.ToString("D4", CultureInfo.InvariantCulture));
206
+ SceneManager.MoveGameObjectToScene(value, scene);
207
+ if (index == 777) target = value;
208
+ }
209
+ var tool = new GameObjectFindTool();
210
+ var found = tool.ExecuteAsync(new GameObjectFindTool.Request
211
+ {
212
+ SearchTerm = target.GetInstanceID().ToString(CultureInfo.InvariantCulture),
213
+ SearchMethod = "by_id",
214
+ IncludeInactive = true,
215
+ Budget = new UnityCliReadBudgetInput { MaxScannedRecords = 1 }
216
+ }, Context("issue-042-exact-found")).GetAwaiter().GetResult();
217
+ Assert.That(found.ReturnedCount, Is.EqualTo(1));
218
+ Assert.That(found.Items.Single().Id, Is.EqualTo(target.GetInstanceID()));
219
+ Assert.That(found.Budget.ScannedRecords, Is.Zero);
220
+
221
+ var missing = tool.ExecuteAsync(new GameObjectFindTool.Request
222
+ {
223
+ SearchTerm = int.MaxValue.ToString(CultureInfo.InvariantCulture),
224
+ SearchMethod = "by_id",
225
+ IncludeInactive = true,
226
+ Budget = new UnityCliReadBudgetInput { MaxScannedRecords = 1 }
227
+ }, Context("issue-042-exact-missing")).GetAwaiter().GetResult();
228
+ Assert.That(missing.ReturnedCount, Is.Zero);
229
+ Assert.That(missing.PageInfo.Complete, Is.True);
230
+ Assert.That(missing.Budget.ScannedRecords, Is.Zero);
231
+ }
232
+ finally
233
+ {
234
+ Assert.That(EditorSceneManager.ClosePreviewScene(scene), Is.True);
235
+ }
236
+ }
237
+
238
+ private static void AssertStale(ProfilerFrameDebuggerEventsTool tool, string cursor, string requestId)
239
+ {
240
+ var exception = Assert.Throws<UnityCliBridge.BridgeCommandException>(() => tool.ExecuteAsync(
241
+ new ProfilerFrameDebuggerEventsTool.Request { PageSize = 500, Cursor = cursor }, Context(requestId)).GetAwaiter().GetResult());
242
+ Assert.That(exception.Code, Is.EqualTo("E_CONTINUATION_STALE"));
243
+ }
244
+
245
+ private static void AssertGoFindStale(GameObjectFindTool tool, string cursor, string requestId)
246
+ {
247
+ var exception = Assert.Throws<UnityCliBridge.BridgeCommandException>(() => tool.ExecuteAsync(new GameObjectFindTool.Request
248
+ {
249
+ SearchTerm = "issue-042-match",
250
+ SearchMethod = "by_name",
251
+ IncludeInactive = true,
252
+ PreferPrefabStage = true,
253
+ PageSize = 4,
254
+ Cursor = cursor
255
+ }, Context(requestId)).GetAwaiter().GetResult());
256
+ Assert.That(exception.Code, Is.EqualTo("E_CONTINUATION_STALE"));
257
+ }
258
+
259
+ private static UnityCliProjectToolContext Context(string requestId, CancellationToken cancellationToken = default)
260
+ {
261
+ return new UnityCliProjectToolContext { RequestId = requestId, TimeoutMs = 30000, CancellationToken = cancellationToken };
262
+ }
263
+
264
+ private static void CreatePrefabFixture(int childCount)
265
+ {
266
+ if (!AssetDatabase.IsValidFolder(PrefabFolder)) AssetDatabase.CreateFolder("Assets", "UnityCliTests");
267
+ AssetDatabase.DeleteAsset(PrefabPath);
268
+ var root = new GameObject("issue-042-prefab-root");
269
+ try
270
+ {
271
+ for (var index = 0; index < childCount; index++)
272
+ {
273
+ var child = new GameObject("issue-042-match");
274
+ child.transform.SetParent(root.transform, false);
275
+ child.SetActive(index % 3 != 0);
276
+ }
277
+ Assert.That(PrefabUtility.SaveAsPrefabAsset(root, PrefabPath), Is.Not.Null);
278
+ AssetDatabase.SaveAssets();
279
+ }
280
+ finally
281
+ {
282
+ UnityEngine.Object.DestroyImmediate(root);
283
+ }
284
+ }
285
+
286
+ private sealed class ManualClock : IUnityCliMonotonicClock
287
+ {
288
+ public long ElapsedMilliseconds { get; private set; }
289
+ internal void Advance(long milliseconds) { ElapsedMilliseconds += milliseconds; }
290
+ }
291
+ }
292
+ }
@@ -0,0 +1,120 @@
1
+ #if UNITY_EDITOR
2
+ using System;
3
+ using System.Collections;
4
+ using System.Collections.Generic;
5
+ using System.Reflection;
6
+ using System.Text;
7
+ using System.Threading;
8
+ using System.Threading.Tasks;
9
+ using NUnit.Framework;
10
+
11
+ namespace UnityCli.Tests
12
+ {
13
+ public sealed class UnityCliDiagnosticBoundaryTests
14
+ {
15
+ private static readonly Type BridgeType = Type.GetType("UnityCli.UnityCliBridge, UnityCli.Editor", true);
16
+
17
+ [Test]
18
+ public void DoctorCatalogHandlerReadsThePublishedSnapshotWithoutAnotherConstruction()
19
+ {
20
+ var constructionCounter = Field("projectToolCatalogConstructionCount");
21
+ var reader = BridgeType.GetProperty("ProjectToolCatalogSnapshotReader", BindingFlags.NonPublic | BindingFlags.Static).GetValue(null, null);
22
+ var snapshot = reader.GetType().GetMethod("Read", BindingFlags.Public | BindingFlags.Instance).Invoke(reader, null);
23
+ var expectedToolCount = Convert.ToInt64(snapshot.GetType().GetProperty("ToolCount").GetValue(snapshot, null));
24
+ var registry = Method("CreateCommandRegistry").Invoke(null, null);
25
+ var requestType = Type.GetType("UnityCli.Protocol.BridgeRequest, UnityCli.Editor", true);
26
+ var request = Activator.CreateInstance(requestType);
27
+ requestType.GetProperty("Command").SetValue(request, "internal.doctor.catalog", null);
28
+ requestType.GetProperty("RequestId").SetValue(request, "doctor-catalog-owner", null);
29
+ requestType.GetProperty("Input").SetValue(request, new Dictionary<string, object>(), null);
30
+
31
+ var before = Convert.ToInt64(constructionCounter.GetValue(null));
32
+ var pending = (ValueTask<object>)registry.GetType().GetMethod("ExecuteAsync").Invoke(registry, new[] { request, (object)CancellationToken.None });
33
+ var result = (IDictionary<string, object>)pending.AsTask().GetAwaiter().GetResult();
34
+ var after = Convert.ToInt64(constructionCounter.GetValue(null));
35
+
36
+ Assert.That(after, Is.EqualTo(before));
37
+ Assert.That(result["identity"], Is.EqualTo("unity-cli-immutable-domain-catalog"));
38
+ Assert.That(Convert.ToInt64(result["toolCount"]), Is.EqualTo(expectedToolCount));
39
+ Assert.That(result["providerCounts"], Is.InstanceOf<IDictionary<string, object>>());
40
+ Assert.That(result["publicationDiagnostics"], Is.InstanceOf<IDictionary<string, object>>());
41
+ var serialized = UnityCli.UnityCliSerializer.Serialize(result);
42
+ Assert.That(Encoding.UTF8.GetByteCount(serialized), Is.LessThanOrEqualTo(64 * 1024));
43
+ Assert.That(serialized, Does.Not.Contain("fingerprint").IgnoreCase);
44
+ Assert.That(serialized, Does.Not.Contain("rePinValue"));
45
+ }
46
+
47
+ [Test]
48
+ public void ProjectToolNamesUseProfileAwareGrammarAndOneUtf8Budget()
49
+ {
50
+ var validator = Type.GetType("UnityCli.UnityCliToolName, UnityCli.Editor", true);
51
+ var validate = validator.GetMethod("Validate", BindingFlags.NonPublic | BindingFlags.Static);
52
+ Assert.DoesNotThrow(() => validate.Invoke(null, new object[] { "scene.hierarchy", "native" }));
53
+ Assert.DoesNotThrow(() => validate.Invoke(null, new object[] { new string('a', 128), "native" }));
54
+ Assert.DoesNotThrow(() => validate.Invoke(null, new object[] { "UnityPipeline_hotfix_container_inspect", "official-attribute" }));
55
+ Assert.DoesNotThrow(() => validate.Invoke(null, new object[] { "UnityPipeline_project_reload_data", "official-attribute" }));
56
+
57
+ AssertInvalidName(validate, "UnityPipeline_project_reload_data", "native");
58
+ AssertInvalidName(validate, "project_reload_data", "official-attribute");
59
+ AssertInvalidName(validate, "Scene.Data", "native");
60
+ AssertInvalidName(validate, "scene..data", "native");
61
+ AssertInvalidName(validate, "scene.数据", "native");
62
+ AssertInvalidName(validate, new string('a', 129), "native");
63
+ AssertInvalidName(validate, "scene.hierarchy\n", "native");
64
+ AssertInvalidName(validate, "scene.hierarchy\r\n", "native");
65
+ AssertInvalidName(validate, "scene.hierarchy ", "native");
66
+ AssertInvalidName(validate, "UnityPipeline_project_reload_data\n", "official-attribute");
67
+ AssertInvalidName(validate, "UnityPipeline_project_reload_data\r\n", "official-attribute");
68
+ AssertInvalidName(validate, "UnityPipeline_project_reload_data\t", "official-attribute");
69
+ }
70
+
71
+ [Test]
72
+ public void CodeExecBridgeEnvelopeUsesTerminalCauseBeyondEightLevels()
73
+ {
74
+ const string terminalMessage = "terminal-actionable-cause";
75
+ Exception exception = new InvalidOperationException(terminalMessage);
76
+ for (var index = 0; index < 12; index++) exception = new TargetInvocationException("wrapper-" + index, exception);
77
+
78
+ var result = Method("ExceptionFailure").Invoke(null, new object[]
79
+ {
80
+ "E_CODE_RUNTIME_EXCEPTION", string.Empty, exception, string.Empty, string.Empty,
81
+ "Inspect the bounded runtime exception cause chain and affected business state."
82
+ });
83
+ var envelope = (string)Method("SerializeCodeExecutionResult").Invoke(null, new[] { "code-exec-deep-cause", result });
84
+ var serializer = Type.GetType("UnityCli.UnityCliSerializer, UnityCli.Editor", true);
85
+ var root = (IDictionary<string, object>)serializer.GetMethod("Parse", BindingFlags.Public | BindingFlags.Static).Invoke(null, new object[] { envelope });
86
+ var error = (IDictionary<string, object>)root["error"];
87
+ var details = (IDictionary<string, object>)error["details"];
88
+ var causes = (IList)details["causes"];
89
+ var terminal = (IDictionary<string, object>)causes[causes.Count - 1];
90
+
91
+ Assert.That(error["code"], Is.EqualTo("E_CODE_RUNTIME_EXCEPTION"));
92
+ Assert.That(error["message"], Is.EqualTo(terminalMessage));
93
+ Assert.That(details["message"], Is.EqualTo(terminalMessage));
94
+ Assert.That(details["exceptionType"], Is.EqualTo(typeof(InvalidOperationException).FullName));
95
+ Assert.That(details["causeChainTruncated"], Is.EqualTo(true));
96
+ Assert.That(causes.Count, Is.EqualTo(8));
97
+ Assert.That(terminal["depth"], Is.EqualTo(12L));
98
+ Assert.That(terminal["message"], Is.EqualTo(terminalMessage));
99
+ Assert.That(Encoding.UTF8.GetByteCount(envelope), Is.LessThanOrEqualTo(1536 * 1024));
100
+ }
101
+
102
+ private static void AssertInvalidName(MethodInfo validate, string name, string contractProfile)
103
+ {
104
+ var exception = Assert.Throws<TargetInvocationException>(() => validate.Invoke(null, new object[] { name, contractProfile }));
105
+ Assert.That(exception.InnerException, Is.TypeOf<InvalidOperationException>());
106
+ Assert.That(exception.InnerException.Message, Is.EqualTo("Tool name must use the registered Tool syntax and fit 128 UTF-8 bytes."));
107
+ }
108
+
109
+ private static FieldInfo Field(string name)
110
+ {
111
+ return BridgeType.GetField(name, BindingFlags.Static | BindingFlags.NonPublic) ?? throw new MissingFieldException(name);
112
+ }
113
+
114
+ private static MethodInfo Method(string name)
115
+ {
116
+ return BridgeType.GetMethod(name, BindingFlags.Static | BindingFlags.NonPublic) ?? throw new MissingMethodException(name);
117
+ }
118
+ }
119
+ }
120
+ #endif
@@ -0,0 +1,84 @@
1
+ #if UNITY_EDITOR
2
+ using System;
3
+ using System.Collections.Generic;
4
+ using NUnit.Framework;
5
+
6
+ namespace UnityCli.Tests
7
+ {
8
+ public sealed class UnityCliDurableStatusTests
9
+ {
10
+ private string _scope;
11
+ private string _runningRequestId;
12
+ private string _terminalRequestId;
13
+ private static readonly string Digest = new string('a', 64);
14
+
15
+ [SetUp]
16
+ public void SetUp()
17
+ {
18
+ // terminal identity在Editor session内有意持久化,增量重复执行必须使用新identity。
19
+ var runId = Guid.NewGuid().ToString("N");
20
+ _scope = "durable-status-test-" + runId;
21
+ _runningRequestId = "durable-status-running-root-" + runId;
22
+ _terminalRequestId = "durable-status-terminal-root-" + runId;
23
+ UnityCliActiveOperation.Clear(_scope);
24
+ }
25
+
26
+ [TearDown]
27
+ public void TearDown()
28
+ {
29
+ UnityCliActiveOperation.Clear(_scope);
30
+ }
31
+
32
+ [Test]
33
+ public void ReadScope_ReturnsRunningPhaseWithoutDigest()
34
+ {
35
+ UnityCliActiveOperation.Save(_scope, new Dictionary<string, object>
36
+ {
37
+ { "requestId", _runningRequestId }, { "requestDigest", Digest }, { "phase", "effect_started" }
38
+ });
39
+
40
+ var result = (Dictionary<string, object>)UnityCliBridge.UnityCliDurableStatusCoordinator.ReadScope(_scope, _runningRequestId);
41
+
42
+ Assert.That(result["requestId"], Is.EqualTo(_runningRequestId));
43
+ Assert.That(result["state"], Is.EqualTo("running"));
44
+ Assert.That(result["phase"], Is.EqualTo("effect_started"));
45
+ Assert.That(result.ContainsKey("requestDigest"), Is.False);
46
+ Assert.That(result.ContainsKey("terminalEnvelope"), Is.False);
47
+ }
48
+
49
+ [Test]
50
+ public void ReadScope_ReturnsFirstTerminalWithoutReplayingEffect()
51
+ {
52
+ var terminal = new Dictionary<string, object>
53
+ {
54
+ { "ok", true }, { "requestId", _terminalRequestId }, { "data", new Dictionary<string, object> { { "value", 1L } } }
55
+ };
56
+ var first = UnityCliActiveOperation.StoreTerminalFirst(_scope, _terminalRequestId, Digest, null, "test.run", terminal);
57
+
58
+ var result = (Dictionary<string, object>)UnityCliBridge.UnityCliDurableStatusCoordinator.ReadScope(_scope, _terminalRequestId);
59
+ Assert.That(UnityCliActiveOperation.TryGetTerminalByRequestId(_scope, _terminalRequestId, out var internalDigest, out var statusDomain, out var selected), Is.True);
60
+
61
+ Assert.That(result["state"], Is.EqualTo("completed"));
62
+ Assert.That(result["terminalEnvelope"], Is.EqualTo(first));
63
+ Assert.That(internalDigest, Is.EqualTo(Digest));
64
+ Assert.That(statusDomain, Is.EqualTo("test.run"));
65
+ Assert.That(selected, Is.EqualTo(first));
66
+ Assert.That(result.ContainsKey("requestDigest"), Is.False);
67
+ }
68
+
69
+ [Test]
70
+ public void SafeStatusAllowlist_ContainsEveryDomainCommand()
71
+ {
72
+ var commands = new[]
73
+ {
74
+ "internal.asset.refresh.public-status", "internal.build.player.public-status",
75
+ "internal.editor.play-mode.public-status", "internal.package.install.public-status",
76
+ "internal.package.remove.public-status", "internal.test.run.public-status"
77
+ };
78
+ foreach (var command in commands)
79
+ Assert.That(UnityCliBridgeQueuePolicy.IsSafeStatusCommand(command), Is.True, command);
80
+ Assert.That(UnityCliBridgeQueuePolicy.IsSafeStatusCommand("internal.operation.public-status"), Is.False);
81
+ }
82
+ }
83
+ }
84
+ #endif
@@ -0,0 +1,72 @@
1
+ using System;
2
+ using System.Collections.Generic;
3
+ using System.Reflection;
4
+ using NUnit.Framework;
5
+
6
+ namespace UnityCli.Tests
7
+ {
8
+ public sealed class UnityCliExceptionProjectionTests
9
+ {
10
+ [Test]
11
+ public void NestedReflectionAndNUnitFailureUsesDeepestActionableCause()
12
+ {
13
+ var assertion = new AssertionException("Expected health check to pass, but it failed.");
14
+ var wrapper = new InvalidOperationException("NUnit invocation failed.", assertion);
15
+ var reflection = new TargetInvocationException("Reflected method failed.", wrapper);
16
+
17
+ var result = UnityCliExceptionProjection.Project(reflection);
18
+
19
+ Assert.That(result.PublicMessage, Is.EqualTo(assertion.Message));
20
+ Assert.That(result.DeepestExceptionType, Is.EqualTo(typeof(AssertionException).FullName));
21
+ Assert.That(result.Causes, Has.Count.EqualTo(3));
22
+ Assert.That(result.Causes[0]["exceptionType"], Is.EqualTo(typeof(TargetInvocationException).FullName));
23
+ Assert.That(result.Causes[2]["message"], Is.EqualTo(assertion.Message));
24
+ Assert.That(result.Truncated, Is.False);
25
+ }
26
+
27
+ [Test]
28
+ public void CauseChainStopsAtCyclesAndStaysDepthAndByteBounded()
29
+ {
30
+ Exception deep = new Exception(new string('z', 100000));
31
+ for (var index = 0; index < UnityCliExceptionProjection.MaxCauseDepth + 4; index++)
32
+ deep = new InvalidOperationException(new string((char)('a' + index), 100000), deep);
33
+ var deepResult = UnityCliExceptionProjection.Project(deep);
34
+ Assert.That(deepResult.Causes, Has.Count.EqualTo(UnityCliExceptionProjection.MaxCauseDepth));
35
+ Assert.That(deepResult.CauseTextBytes, Is.LessThanOrEqualTo(UnityCliExceptionProjection.MaxCauseTextBytes));
36
+ Assert.That(deepResult.CauseTraversalCount, Is.EqualTo(UnityCliExceptionProjection.MaxCauseDepth + 5));
37
+ Assert.That(deepResult.PublicMessage, Is.EqualTo(new string('z', 4096)));
38
+ Assert.That(deepResult.DeepestMessage, Is.EqualTo(new string('z', 4096)));
39
+ Assert.That(deepResult.Causes[UnityCliExceptionProjection.MaxCauseDepth - 1]["depth"], Is.EqualTo((long)(UnityCliExceptionProjection.MaxCauseDepth + 4)));
40
+ Assert.That(deepResult.Causes[UnityCliExceptionProjection.MaxCauseDepth - 1]["message"], Is.EqualTo(new string('z', 4096)));
41
+ Assert.That(deepResult.Truncated, Is.True);
42
+
43
+ var first = new InvalidOperationException("first");
44
+ var second = new Exception("second");
45
+ var next = new Dictionary<Exception, Exception>
46
+ {
47
+ { first, second },
48
+ { second, first }
49
+ };
50
+ var cycleResult = UnityCliExceptionProjection.Project(first, value => next[value]);
51
+ Assert.That(cycleResult.Causes, Has.Count.EqualTo(2));
52
+ Assert.That(cycleResult.Truncated, Is.True);
53
+ Assert.That(cycleResult.PublicMessage, Is.EqualTo("second"));
54
+ Assert.That(cycleResult.CauseTraversalCount, Is.EqualTo(2));
55
+ }
56
+
57
+ [Test]
58
+ public void TraversalWorkRemainsHardBoundedBeyondThePublishedCauseDepth()
59
+ {
60
+ Exception deep = new Exception("terminal-beyond-traversal-budget");
61
+ for (var index = 0; index < UnityCliExceptionProjection.MaxCauseTraversal + 20; index++)
62
+ deep = new InvalidOperationException("wrapper-" + index, deep);
63
+
64
+ var result = UnityCliExceptionProjection.Project(deep);
65
+
66
+ Assert.That(result.CauseTraversalCount, Is.EqualTo(UnityCliExceptionProjection.MaxCauseTraversal));
67
+ Assert.That(result.Causes, Has.Count.EqualTo(UnityCliExceptionProjection.MaxCauseDepth));
68
+ Assert.That(result.CauseTextBytes, Is.LessThanOrEqualTo(UnityCliExceptionProjection.MaxCauseTextBytes));
69
+ Assert.That(result.Truncated, Is.True);
70
+ }
71
+ }
72
+ }