@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,562 @@
1
+ #if UNITY_EDITOR
2
+ using System;
3
+ using System.Collections;
4
+ using System.CodeDom.Compiler;
5
+ using System.Collections.Generic;
6
+ using System.Linq;
7
+ using System.Reflection;
8
+ using System.Text;
9
+ using System.Threading;
10
+ using System.Threading.Tasks;
11
+ using Microsoft.CSharp;
12
+ using NUnit.Framework;
13
+
14
+ namespace UnityCli.Tests
15
+ {
16
+ public static class UnityCliToolCatalogFixtureProbe
17
+ {
18
+ private static readonly object Sync = new object();
19
+ private static readonly Dictionary<string, int> DescribeCounts = new Dictionary<string, int>(StringComparer.Ordinal);
20
+
21
+ public static void Reset()
22
+ {
23
+ lock (Sync)
24
+ {
25
+ DescribeCounts.Clear();
26
+ }
27
+ }
28
+
29
+ public static void RecordDescribe(string providerName)
30
+ {
31
+ lock (Sync)
32
+ {
33
+ int current;
34
+ DescribeCounts.TryGetValue(providerName, out current);
35
+ DescribeCounts[providerName] = current + 1;
36
+ }
37
+ }
38
+
39
+ public static Dictionary<string, int> Snapshot()
40
+ {
41
+ lock (Sync)
42
+ {
43
+ return new Dictionary<string, int>(DescribeCounts, StringComparer.Ordinal);
44
+ }
45
+ }
46
+ }
47
+
48
+ public sealed class UnityCliToolCatalogTests
49
+ {
50
+ private static Assembly[] compiledProjectToolProviderAssemblies;
51
+ private Type bridgeType;
52
+ private Type builderType;
53
+ private Type providerKindType;
54
+ private Type registeredToolType;
55
+ private Type ownershipType;
56
+ private FieldInfo publishedField;
57
+ private FieldInfo healthField;
58
+ private object publishedTemplate;
59
+
60
+ [SetUp]
61
+ public void SetUp()
62
+ {
63
+ bridgeType = Type.GetType("UnityCli.UnityCliBridge, UnityCli.Editor", true);
64
+ builderType = Type.GetType("UnityCli.UnityCliToolCatalogBuilder, UnityCli.Editor", true);
65
+ providerKindType = Type.GetType("UnityCli.UnityCliToolProviderKind, UnityCli.Editor", true);
66
+ registeredToolType = Type.GetType("UnityCli.RegisteredTool, UnityCli.Editor", true);
67
+ ownershipType = Type.GetType("UnityCli.RegistryToolOwnership, UnityCli.Editor", true);
68
+ publishedField = Field("publishedProjectToolCatalog");
69
+ healthField = Field("projectToolCatalogHealth");
70
+ publishedTemplate = FirstValue(Property(publishedField.GetValue(null), "ExecutableTools").GetValue(publishedField.GetValue(null)));
71
+ }
72
+
73
+ [Test]
74
+ public void StaticConstructorPublishesOneImmutableDescriptorSnapshotAndLaterReadsDoNoDiscoveryWork()
75
+ {
76
+ var first = ReadPublishedSnapshot();
77
+ var second = ReadPublishedSnapshot();
78
+ Assert.That(second, Is.SameAs(first));
79
+ Assert.That((int)Field("projectToolCatalogConstructionCount").GetValue(null), Is.EqualTo(1));
80
+ Assert.That(Int(first, "DiscoveryPassCount"), Is.EqualTo(1));
81
+ Assert.That(Int(first, "ProviderMetadataReadCount"), Is.EqualTo(Int(first, "ProviderAssemblyCount")));
82
+ Assert.That(Int(first, "AggregateSuccessLogCount"), Is.EqualTo(1));
83
+
84
+ var descriptor = FirstTool(first);
85
+ foreach (var privateExecutionMember in new[] { "InvokeAsync", "RequestType", "ResultType", "OfficialAttributeBinding", "OwnerIdentity" })
86
+ Assert.That(descriptor.GetType().GetProperty(privateExecutionMember, BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance), Is.Null, privateExecutionMember);
87
+ Assert.That(descriptor.GetType().GetProperties().Where(property => property.SetMethod != null), Is.Empty);
88
+
89
+ var firstExamples = (IList)Invoke(descriptor, "CloneExamples");
90
+ var firstExample = (IDictionary<string, object>)firstExamples[0];
91
+ firstExample["description"] = "mutated test copy";
92
+ var secondExamples = (IList)Invoke(descriptor, "CloneExamples");
93
+ Assert.That(((IDictionary<string, object>)secondExamples[0])["description"], Is.Not.EqualTo("mutated test copy"));
94
+ }
95
+
96
+ [Test]
97
+ public void CatalogFingerprintIsCachedStableAndBindsPublishedDescriptorContent()
98
+ {
99
+ var previousCatalog = publishedField.GetValue(null);
100
+ var previousHealth = healthField.GetValue(null);
101
+ try
102
+ {
103
+ var firstBuilder = NewBuilder(1, 1);
104
+ Add(firstBuilder, Definition("fixture.fingerprint", "project", "native", "fixture"), "ProjectInterface");
105
+ var firstSnapshot = PublishThroughProductionSlot(firstBuilder, 1L);
106
+ var firstFingerprint = (string)Property(firstSnapshot, "ToolCatalogFingerprint").GetValue(firstSnapshot);
107
+
108
+ var sameBuilder = NewBuilder(1, 1);
109
+ Add(sameBuilder, Definition("fixture.fingerprint", "project", "native", "fixture"), "ProjectInterface");
110
+ var sameSnapshot = PublishThroughProductionSlot(sameBuilder, 999L);
111
+ var sameFingerprint = (string)Property(sameSnapshot, "ToolCatalogFingerprint").GetValue(sameSnapshot);
112
+
113
+ var changedBuilder = NewBuilder(1, 1);
114
+ Add(changedBuilder, Definition("fixture.fingerprint", "project", "native", "fixture", "Changed fixture summary."), "ProjectInterface");
115
+ var changedSnapshot = PublishThroughProductionSlot(changedBuilder, 1L);
116
+ var changedFingerprint = (string)Property(changedSnapshot, "ToolCatalogFingerprint").GetValue(changedSnapshot);
117
+
118
+ Assert.That(firstFingerprint, Does.Match("^[0-9a-f]{64}$"));
119
+ Assert.That(Property(firstSnapshot, "ToolCatalogFingerprint").GetValue(firstSnapshot), Is.SameAs(firstFingerprint));
120
+ Assert.That(sameFingerprint, Is.EqualTo(firstFingerprint));
121
+ Assert.That(changedFingerprint, Is.Not.EqualTo(firstFingerprint));
122
+ }
123
+ finally
124
+ {
125
+ publishedField.SetValue(null, previousCatalog);
126
+ healthField.SetValue(null, previousHealth);
127
+ }
128
+ }
129
+
130
+ [Test]
131
+ public void ProviderMetadataCountersAndThreeHundredOneEntriesFlowThroughProductionPublication()
132
+ {
133
+ var previousCatalog = publishedField.GetValue(null);
134
+ var previousHealth = healthField.GetValue(null);
135
+ try
136
+ {
137
+ UnityCliToolCatalogFixtureProbe.Reset();
138
+ var fixtureAssemblies = CompileProjectToolProviderAssemblies(301);
139
+ var builder = Activator.CreateInstance(builderType, true);
140
+ var collect = bridgeType.GetMethod("CollectProjectToolCatalog", BindingFlags.NonPublic | BindingFlags.Static);
141
+ collect.Invoke(null, new object[] { AppDomain.CurrentDomain.GetAssemblies(), builder });
142
+ var snapshot = PublishThroughProductionSlot(builder, 12L);
143
+ Assert.That(ReadPublishedSnapshot(), Is.SameAs(snapshot));
144
+ Assert.That(Int(snapshot, "ProviderAssemblyCount"), Is.GreaterThanOrEqualTo(302));
145
+ Assert.That(Int(snapshot, "ProjectInterfaceToolCount"), Is.GreaterThanOrEqualTo(301));
146
+ Assert.That(Int(snapshot, "ToolCount"), Is.GreaterThanOrEqualTo(301));
147
+
148
+ var descriptors = ((IEnumerable)Property(snapshot, "Descriptors").GetValue(snapshot)).Cast<object>().ToList();
149
+ var fixtureDescriptorNames = descriptors
150
+ .Select(item => (string)Property(item, "Name").GetValue(item))
151
+ .Where(name => name.StartsWith("fixture.generated.", StringComparison.Ordinal))
152
+ .ToList();
153
+ var describeCounts = UnityCliToolCatalogFixtureProbe.Snapshot();
154
+
155
+ Assert.That(fixtureAssemblies.Length, Is.EqualTo(301));
156
+ Assert.That(fixtureAssemblies.All(assembly => assembly.GetTypes().Count(type => !type.IsAbstract && type.Name.StartsWith("GeneratedTool", StringComparison.Ordinal)) == 1), Is.True);
157
+ Assert.That(fixtureDescriptorNames.Count, Is.EqualTo(301));
158
+ Assert.That(fixtureDescriptorNames.Distinct(StringComparer.Ordinal).Count(), Is.EqualTo(301));
159
+ Assert.That(describeCounts.Count, Is.EqualTo(301));
160
+ Assert.That(describeCounts.Values.All(count => count == 1), Is.True);
161
+ Assert.That(fixtureDescriptorNames, Is.EquivalentTo(describeCounts.Keys));
162
+ }
163
+ finally
164
+ {
165
+ publishedField.SetValue(null, previousCatalog);
166
+ healthField.SetValue(null, previousHealth);
167
+ UnityCliToolCatalogFixtureProbe.Reset();
168
+ }
169
+ }
170
+
171
+ [Test]
172
+ public void NthEntryFailureCannotReplaceThePublishedSlot()
173
+ {
174
+ var previousCatalog = publishedField.GetValue(null);
175
+ var previousHealth = healthField.GetValue(null);
176
+ try
177
+ {
178
+ var candidate = NewBuilder(1, 1);
179
+ Add(candidate, Definition("fixture.published", "project", "native", "fixture"), "ProjectInterface");
180
+ PublishThroughProductionSlot(candidate, 1L);
181
+ var publishedCandidate = publishedField.GetValue(null);
182
+
183
+ var failed = NewBuilder(1, 1);
184
+ Add(failed, Definition("fixture.first", "project", "native", "fixture"), "ProjectInterface");
185
+ Assert.That(() => Add(failed, Definition("fixture.first", "project", "native", "fixture"), "ProjectInterface"), Throws.TypeOf<TargetInvocationException>());
186
+ Assert.That(() => PublishThroughProductionSlot(failed, 1L), Throws.TypeOf<TargetInvocationException>());
187
+ Assert.That(publishedField.GetValue(null), Is.SameAs(publishedCandidate));
188
+ Assert.That(ReadPublishedSnapshot(), Is.SameAs(Property(publishedCandidate, "Snapshot").GetValue(publishedCandidate)));
189
+ }
190
+ finally
191
+ {
192
+ publishedField.SetValue(null, previousCatalog);
193
+ healthField.SetValue(null, previousHealth);
194
+ }
195
+ }
196
+
197
+ [Test]
198
+ public void UnhealthyHealthSnapshotRemainsReadableWhileCatalogReaderFailsClosed()
199
+ {
200
+ var previousCatalog = publishedField.GetValue(null);
201
+ var previousHealth = healthField.GetValue(null);
202
+ try
203
+ {
204
+ var healthType = Type.GetType("UnityCli.UnityCliToolCatalogHealthSnapshot, UnityCli.Editor", true);
205
+ var health = Activator.CreateInstance(healthType, BindingFlags.Instance | BindingFlags.NonPublic, null,
206
+ new object[] { false, 0, "bounded failure", "reload domain" }, null);
207
+ publishedField.SetValue(null, null);
208
+ healthField.SetValue(null, health);
209
+
210
+ var healthReader = bridgeType.GetProperty("ProjectToolCatalogHealthSnapshotReader", BindingFlags.NonPublic | BindingFlags.Static).GetValue(null);
211
+ var observed = healthReader.GetType().GetMethod("Read", BindingFlags.Public | BindingFlags.Instance).Invoke(healthReader, null);
212
+ Assert.That((bool)Property(observed, "Ready").GetValue(observed), Is.False);
213
+ Assert.That((string)Property(observed, "Failure").GetValue(observed), Is.EqualTo("bounded failure"));
214
+ var exception = Assert.Throws<TargetInvocationException>(() => ReadPublishedSnapshot());
215
+ Assert.That(((UnityCliBridge.BridgeCommandException)exception.InnerException).Code, Is.EqualTo("E_TOOL_REGISTRY_UNHEALTHY"));
216
+ }
217
+ finally
218
+ {
219
+ publishedField.SetValue(null, previousCatalog);
220
+ healthField.SetValue(null, previousHealth);
221
+ }
222
+ }
223
+
224
+ [Test]
225
+ public void DuplicateInvalidOrOversizedDescriptorFaultsBuilderWithoutPublication()
226
+ {
227
+ var duplicate = NewBuilder(1, 1);
228
+ Add(duplicate, Definition("fixture.duplicate", "project", "native", "fixture"), "ProjectInterface");
229
+ Assert.That(() => Add(duplicate, Definition("fixture.duplicate", "project", "native", "fixture"), "ProjectInterface"), Throws.TypeOf<TargetInvocationException>());
230
+ Assert.That(() => PublishThroughProductionSlot(duplicate, 1L), Throws.TypeOf<TargetInvocationException>());
231
+
232
+ var oversized = NewBuilder(1, 1);
233
+ Assert.That(() => Add(oversized, Definition("fixture." + new string('n', 249), "project", "native", "fixture"), "ProjectInterface"), Throws.TypeOf<TargetInvocationException>());
234
+ Assert.That(() => PublishThroughProductionSlot(oversized, 1L), Throws.TypeOf<TargetInvocationException>());
235
+ }
236
+
237
+ [Test]
238
+ public void MultibyteDescriptorBoundsAndCompleteCatalogEnvelopesUseUtf8Bytes()
239
+ {
240
+ var accepted = NewBuilder(1, 1);
241
+ Assert.That(() => Add(accepted, Definition("fixture.utf8.accepted", "project", "native", new string('组', 85), new string('界', 170) + "ab"), "ProjectInterface"), Throws.Nothing);
242
+
243
+ var rejected = NewBuilder(1, 1);
244
+ Assert.That(() => Add(rejected, Definition("fixture.utf8.too-long", "project", "native", new string('组', 85), new string('界', 170) + "abc"), "ProjectInterface"),
245
+ Throws.TypeOf<TargetInvocationException>());
246
+ var rejectedGroup = NewBuilder(1, 1);
247
+ Assert.That(() => Add(rejectedGroup, Definition("fixture.utf8.group-too-long", "project", "native", new string('组', 86)), "ProjectInterface"),
248
+ Throws.TypeOf<TargetInvocationException>());
249
+
250
+ var previousCatalog = publishedField.GetValue(null);
251
+ var previousHealth = healthField.GetValue(null);
252
+ try
253
+ {
254
+ var builder = NewBuilder(4096, 1);
255
+ for (var index = 0; index < 4096; index++)
256
+ Add(builder, Definition("fixture.bound." + index.ToString("D4"), "project", "native", "g" + index.ToString("D4"), new string('界', 170)), "ProjectInterface");
257
+ PublishThroughProductionSlot(builder, 1L);
258
+ var summaryRequest = CursorSummaryRequest(null, null);
259
+ ((IDictionary<string, object>)summaryRequest.Input)["limit"] = 101;
260
+ var summary = bridgeType.GetMethod("ProjectToolCatalogSummary", BindingFlags.NonPublic | BindingFlags.Static)
261
+ .Invoke(null, new object[] { summaryRequest, false });
262
+ Assert.That(Encoding.UTF8.GetByteCount(UnityCliSerializer.Serialize(summary)), Is.LessThanOrEqualTo(256 * 1024));
263
+ Assert.That(((IList)((IDictionary<string, object>)summary)["tools"]).Count, Is.EqualTo(101));
264
+ Assert.That((bool)((IDictionary<string, object>)summary)["hasMore"], Is.True);
265
+
266
+ var groupsRequest = new UnityCli.Protocol.BridgeRequest
267
+ {
268
+ Input = new Dictionary<string, object> { { "reservedNames", new List<object>() } }
269
+ };
270
+ var groups = bridgeType.GetMethod("ProjectToolCatalogGroups", BindingFlags.NonPublic | BindingFlags.Static)
271
+ .Invoke(null, new object[] { groupsRequest, false });
272
+ Assert.That(Encoding.UTF8.GetByteCount(UnityCliSerializer.Serialize(groups)), Is.LessThanOrEqualTo(2 * 1024 * 1024));
273
+ Assert.That(((IList)((IDictionary<string, object>)groups)["groups"]).Count, Is.EqualTo(4096));
274
+ }
275
+ finally
276
+ {
277
+ publishedField.SetValue(null, previousCatalog);
278
+ healthField.SetValue(null, previousHealth);
279
+ }
280
+ }
281
+
282
+ [Test]
283
+ public void SerializedSummaryBudgetTruncatesWithAnAccurateSignedBoundary()
284
+ {
285
+ var names = Enumerable.Range(0, 101).Select(index => "fixture.bytes." + index.ToString("D3")).ToList();
286
+ var pageNames = names.ToList();
287
+ var tools = names.Select(name => (object)new Dictionary<string, object>
288
+ {
289
+ { "name", name }, { "summary", new string('界', 170) + "ab" }, { "group", "fixture" },
290
+ { "target", "editor" }, { "contractProfile", "native" }, { "commandName", name },
291
+ { "available", false }, { "unavailableReason", new string('界', 682) }
292
+ }).ToList();
293
+ var bounded = (IDictionary<string, object>)bridgeType.GetMethod("BoundSignedCatalogSummaryData", BindingFlags.NonPublic | BindingFlags.Static)
294
+ .Invoke(null, new object[] { new string('g', 64), 101, names, 0, pageNames, tools, new string('s', 64) });
295
+ Assert.That(Encoding.UTF8.GetByteCount(UnityCliSerializer.Serialize(bounded)), Is.LessThanOrEqualTo(256 * 1024));
296
+ var emittedNames = ((IEnumerable)bounded["pageNames"]).Cast<object>().Select(Convert.ToString).ToList();
297
+ Assert.That(emittedNames.Count, Is.InRange(1, 100));
298
+ Assert.That((bool)bounded["hasMore"], Is.True);
299
+ var tokenFields = Encoding.UTF8.GetString(FromBase64Url(((string)bounded["continuationToken"]).Split('.')[0])).Split('\n');
300
+ Assert.That(Encoding.UTF8.GetString(Convert.FromBase64String(tokenFields[2])), Is.EqualTo(emittedNames.Last()));
301
+ }
302
+
303
+ [Test]
304
+ public void EditorContinuationRejectsAlteredExistingAndUnknownBoundariesInSameGeneration()
305
+ {
306
+ var previousCatalog = publishedField.GetValue(null);
307
+ var previousHealth = healthField.GetValue(null);
308
+ try
309
+ {
310
+ var builder = NewBuilder(1, 1);
311
+ foreach (var name in new[] { "fixture.cursor.a", "fixture.cursor.b", "fixture.cursor.c" })
312
+ Add(builder, Definition(name, "project", "native", "fixture"), "ProjectInterface");
313
+ PublishThroughProductionSlot(builder, 1L);
314
+ var summary = bridgeType.GetMethod("ProjectToolCatalogSummary", BindingFlags.NonPublic | BindingFlags.Static);
315
+ var firstRequest = CursorSummaryRequest(null, null);
316
+ var first = (IDictionary<string, object>)summary.Invoke(null, new object[] { firstRequest, false });
317
+ var token = (string)first["continuationToken"];
318
+ var generation = (string)first["catalogGeneration"];
319
+ foreach (var boundary in new[] { "fixture.cursor.c", "fixture.cursor.unknown" })
320
+ {
321
+ var request = CursorSummaryRequest(generation, AlterCursorBoundary(token, boundary));
322
+ var exception = Assert.Throws<TargetInvocationException>(() => summary.Invoke(null, new object[] { request, false }));
323
+ Assert.That(((UnityCliBridge.BridgeCommandException)exception.InnerException).Code, Is.EqualTo("E_DISCOVERY_CURSOR_INVALID"), boundary);
324
+ }
325
+ }
326
+ finally
327
+ {
328
+ publishedField.SetValue(null, previousCatalog);
329
+ healthField.SetValue(null, previousHealth);
330
+ }
331
+ }
332
+
333
+ [Test]
334
+ public void EditorDescribeAcceptsOneExactFallbackWhileRuntimeDescribeRejectsIt()
335
+ {
336
+ var describe = bridgeType.GetMethod("ProjectToolCatalogDescribe", BindingFlags.NonPublic | BindingFlags.Static);
337
+ var request = new UnityCli.Protocol.BridgeRequest
338
+ {
339
+ Input = new Dictionary<string, object> { { "name", "fixture.missing" }, { "fallbackName", "fixture.also-missing" } }
340
+ };
341
+ Assert.That(() => describe.Invoke(null, new object[] { request, false }), Throws.Nothing);
342
+ var exception = Assert.Throws<TargetInvocationException>(() => describe.Invoke(null, new object[] { request, true }));
343
+ Assert.That(((UnityCliBridge.BridgeCommandException)exception.InnerException).Code, Is.EqualTo("E_SCHEMA_INVALID"));
344
+ }
345
+
346
+ [Test]
347
+ public void PrivateCatalogReadersRejectUnknownInputBeforeSnapshotProjection()
348
+ {
349
+ var request = new UnityCli.Protocol.BridgeRequest
350
+ {
351
+ Input = new Dictionary<string, object> { { "limit", 20L }, { "unknown", true } }
352
+ };
353
+ var summary = bridgeType.GetMethod("ProjectToolCatalogSummary", BindingFlags.NonPublic | BindingFlags.Static);
354
+ var exception = Assert.Throws<TargetInvocationException>(() => summary.Invoke(null, new object[] { request, false }));
355
+ Assert.That(((UnityCliBridge.BridgeCommandException)exception.InnerException).Code, Is.EqualTo("E_SCHEMA_INVALID"));
356
+ }
357
+
358
+ [Test]
359
+ public void UnsupportedOfficialSignatureOrReturnTypeCannotPublishPendingTable()
360
+ {
361
+ var validate = bridgeType.GetMethod("ValidateOfficialMethodSignature", BindingFlags.NonPublic | BindingFlags.Static);
362
+ var invalidMethod = GetType().GetMethod("InstanceOfficialMethod", BindingFlags.NonPublic | BindingFlags.Instance);
363
+ Assert.That(() => validate.Invoke(null, new object[] { invalidMethod }), Throws.TypeOf<TargetInvocationException>());
364
+
365
+ var output = bridgeType.GetMethod("BuildOfficialOutputContract", BindingFlags.NonPublic | BindingFlags.Static);
366
+ Assert.That(() => output.Invoke(null, new object[] { typeof(ValueTask<int>) }), Throws.TypeOf<TargetInvocationException>());
367
+ }
368
+
369
+ private void InstanceOfficialMethod() { }
370
+ private static UnityCli.Protocol.BridgeRequest CursorSummaryRequest(string generation, string token)
371
+ {
372
+ var input = new Dictionary<string, object>
373
+ {
374
+ { "limit", 1L }, { "reservedNames", new List<object>() }, { "localNames", new List<object>() },
375
+ { "cursorContext", new string('a', 64) }
376
+ };
377
+ if (generation != null) input["expectedCatalogGeneration"] = generation;
378
+ if (token != null) input["cursorToken"] = token;
379
+ return new UnityCli.Protocol.BridgeRequest { Input = input };
380
+ }
381
+
382
+ private static string AlterCursorBoundary(string token, string boundary)
383
+ {
384
+ var parts = token.Split('.');
385
+ var payload = Encoding.UTF8.GetString(FromBase64Url(parts[0])).Split('\n');
386
+ payload[2] = Convert.ToBase64String(Encoding.UTF8.GetBytes(boundary));
387
+ return ToBase64Url(Encoding.UTF8.GetBytes(string.Join("\n", payload))) + "." + parts[1];
388
+ }
389
+
390
+ private static string ToBase64Url(byte[] value)
391
+ {
392
+ return Convert.ToBase64String(value).TrimEnd('=').Replace('+', '-').Replace('/', '_');
393
+ }
394
+
395
+ private static byte[] FromBase64Url(string value)
396
+ {
397
+ var normalized = value.Replace('-', '+').Replace('_', '/');
398
+ normalized = normalized.PadRight(normalized.Length + (4 - normalized.Length % 4) % 4, '=');
399
+ return Convert.FromBase64String(normalized);
400
+ }
401
+
402
+ private static void StaticOfficialMethod() { }
403
+
404
+ private object ReadPublishedSnapshot()
405
+ {
406
+ var reader = bridgeType.GetProperty("ProjectToolCatalogSnapshotReader", BindingFlags.NonPublic | BindingFlags.Static).GetValue(null);
407
+ return reader.GetType().GetMethod("Read", BindingFlags.Public | BindingFlags.Instance).Invoke(reader, null);
408
+ }
409
+
410
+ private static object FirstTool(object snapshot)
411
+ {
412
+ var descriptors = Property(snapshot, "Descriptors").GetValue(snapshot) as IEnumerable;
413
+ return descriptors.Cast<object>().First();
414
+ }
415
+
416
+ private static object FirstValue(object dictionary)
417
+ {
418
+ var values = Property(dictionary, "Values").GetValue(dictionary) as IEnumerable;
419
+ return values.Cast<object>().First();
420
+ }
421
+
422
+ private object NewBuilder(int assemblies, int providers)
423
+ {
424
+ var builder = Activator.CreateInstance(builderType, true);
425
+ Invoke(builder, "BeginDiscovery", assemblies, providers);
426
+ for (var index = 0; index < providers; index++) Invoke(builder, "RecordProviderMetadata", "fixture.provider." + index);
427
+ return builder;
428
+ }
429
+
430
+ private object Definition(string name, string source, string profile, string group, string summary = "Fixture summary.")
431
+ {
432
+ var descriptor = new ToolDescriptor
433
+ {
434
+ Name = name,
435
+ Summary = summary,
436
+ Description = "Fixture descriptor for production catalog publication validation.",
437
+ Group = group,
438
+ DestructiveHint = false,
439
+ SideEffects = new string[0],
440
+ SupportsDryRun = false,
441
+ Permissions = new string[0],
442
+ RequiresPackages = new string[0],
443
+ Examples = new[] { new ToolExample { Description = "Fixture", Input = new Dictionary<string, object>() } },
444
+ Target = "editor",
445
+ PlayModeSupport = profile == "official-attribute" ? "unknown" : "supported",
446
+ DefaultTimeoutMs = 30000,
447
+ MaxTimeoutMs = 60000
448
+ };
449
+ var implementationType = source == "built-in" ? bridgeType : GetType();
450
+ var extensionId = source == "extension" ? "fixture" : null;
451
+ var ownership = Activator.CreateInstance(ownershipType, BindingFlags.Instance | BindingFlags.NonPublic, null,
452
+ new object[] { source, extensionId, implementationType.Assembly, implementationType }, null);
453
+ object binding = null;
454
+ if (profile == "official-attribute")
455
+ {
456
+ var bindingType = Type.GetType("UnityCli.OfficialAttributeToolBinding, UnityCli.Editor", true);
457
+ var parameterType = Type.GetType("UnityCli.OfficialAttributeParameterBinding, UnityCli.Editor", true);
458
+ binding = Activator.CreateInstance(bindingType, true);
459
+ Property(binding, "Method").SetValue(binding, GetType().GetMethod("StaticOfficialMethod", BindingFlags.NonPublic | BindingFlags.Static));
460
+ Property(binding, "DeclaredResultType").SetValue(binding, typeof(void));
461
+ Property(binding, "Parameters").SetValue(binding, Activator.CreateInstance(typeof(List<>).MakeGenericType(parameterType)));
462
+ }
463
+ var invoke = Property(publishedTemplate, "InvokeAsync").GetValue(publishedTemplate);
464
+ var constructor = registeredToolType.GetConstructors(BindingFlags.NonPublic | BindingFlags.Instance).Single();
465
+ return constructor.Invoke(new[]
466
+ {
467
+ descriptor, ownership, "{}", "{}", "editorSession", profile,
468
+ typeof(Dictionary<string, object>), typeof(Dictionary<string, object>), Completion(name, source), binding, invoke
469
+ });
470
+ }
471
+
472
+ private static Assembly[] CompileProjectToolProviderAssemblies(int count)
473
+ {
474
+ if (compiledProjectToolProviderAssemblies != null && compiledProjectToolProviderAssemblies.Length == count)
475
+ return compiledProjectToolProviderAssemblies;
476
+
477
+ var assemblies = new List<Assembly>(count);
478
+ for (var index = 0; index < count; index++)
479
+ assemblies.Add(CompileProjectToolProviderAssembly(index));
480
+
481
+ compiledProjectToolProviderAssemblies = assemblies.ToArray();
482
+ return compiledProjectToolProviderAssemblies;
483
+ }
484
+
485
+ private static Assembly CompileProjectToolProviderAssembly(int index)
486
+ {
487
+ var suffix = index.ToString("D3");
488
+ var source = new StringBuilder();
489
+ source.AppendLine("using System.Collections.Generic; using System.Threading; using System.Threading.Tasks; using UnityCli;");
490
+ source.AppendLine("namespace UnityCli.GeneratedCatalogFixture" + suffix + " {");
491
+ source.AppendLine("public sealed class FixtureRequest {} public sealed class FixtureResult {}");
492
+ source.AppendLine("public sealed class GeneratedTool" + suffix + " : IUnityCliTool<FixtureRequest, FixtureResult> {");
493
+ source.AppendLine("public ToolDescriptor Describe() { global::UnityCli.Tests.UnityCliToolCatalogFixtureProbe.RecordDescribe(\"fixture.generated." + suffix + "\"); return new ToolDescriptor { Name=\"fixture.generated." + suffix
494
+ + "\", Summary=\"Generated fixture.\", Description=\"Production collector fixture.\", Group=\"fixture\", Examples=new[]{new ToolExample{Description=\"Fixture\", Input=new Dictionary<string, object>()}}, Completion=new ToolCompletionDescriptor{ExecutionClass=\"atomic\", CompletionPredicate=\"typed-business-terminal\", ProofSource=\"typed-result-and-effect-readback\", ReloadPolicy=\"caller-responsibility\", TimeoutError=\"E_EXECUTION_TIMEOUT\", OutcomeUnknownPolicy=\"caller-responsibility\", CompletionDriverId=\"atomic-typed-result-v1\"} }; }");
495
+ source.AppendLine("public ValueTask<FixtureResult> ExecuteAsync(FixtureRequest request, UnityCliProjectToolContext ctx, CancellationToken ct) { return new ValueTask<FixtureResult>(new FixtureResult()); }}");
496
+ source.AppendLine("}");
497
+ using (var provider = new CSharpCodeProvider())
498
+ {
499
+ var parameters = new CompilerParameters
500
+ {
501
+ GenerateExecutable = false,
502
+ GenerateInMemory = true,
503
+ CompilerOptions = "/langversion:latest",
504
+ OutputAssembly = "UnityCli.GeneratedCatalogFixture" + suffix + ".dll"
505
+ };
506
+ parameters.ReferencedAssemblies.Add("System.dll");
507
+ parameters.ReferencedAssemblies.Add("System.Core.dll");
508
+ parameters.ReferencedAssemblies.Add(typeof(IUnityCliTool<,>).Assembly.Location);
509
+ parameters.ReferencedAssemblies.Add(typeof(UnityCliToolCatalogFixtureProbe).Assembly.Location);
510
+ var result = provider.CompileAssemblyFromSource(parameters, source.ToString());
511
+ var failures = result.Errors.Cast<CompilerError>().Where(error => !error.IsWarning).Select(error => error.ToString()).ToArray();
512
+ Assert.That(failures, Is.Empty, string.Join(Environment.NewLine, failures));
513
+ return result.CompiledAssembly;
514
+ }
515
+ }
516
+
517
+ private object Completion(string name, string source)
518
+ {
519
+ var type = Type.GetType("UnityCli.UnityCliToolCompletionContract, UnityCli.Editor", true);
520
+ var constructor = type.GetConstructors(BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance).Single();
521
+ var owner = source == "extension" ? "extension:fixture" : source;
522
+ return constructor.Invoke(new object[]
523
+ {
524
+ name, owner, "direct-terminal", "atomic", "typed-result-schema-v1", "typed-handler-result",
525
+ "fail-before-effect", "E_EXECUTION_TIMEOUT", "not-applicable-read-only", "direct-typed-result-v1", "none", false
526
+ });
527
+ }
528
+
529
+ private object PublishThroughProductionSlot(object builder, long elapsedMilliseconds)
530
+ {
531
+ var method = bridgeType.GetMethod("PublishProjectToolCatalog", BindingFlags.NonPublic | BindingFlags.Static);
532
+ return method.Invoke(null, new[] { builder, (object)elapsedMilliseconds });
533
+ }
534
+
535
+ private void Add(object builder, object definition, string providerKind)
536
+ {
537
+ Invoke(builder, "Add", definition, Enum.Parse(providerKindType, providerKind));
538
+ }
539
+
540
+ private static object Invoke(object target, string name, params object[] args)
541
+ {
542
+ var method = target.GetType().GetMethod(name, BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance);
543
+ return method.Invoke(target, args);
544
+ }
545
+
546
+ private FieldInfo Field(string name)
547
+ {
548
+ return bridgeType.GetField(name, BindingFlags.NonPublic | BindingFlags.Static) ?? throw new MissingFieldException(name);
549
+ }
550
+
551
+ private static PropertyInfo Property(object target, string name)
552
+ {
553
+ return target.GetType().GetProperty(name, BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance) ?? throw new MissingMemberException(name);
554
+ }
555
+
556
+ private static int Int(object target, string name)
557
+ {
558
+ return Convert.ToInt32(Property(target, name).GetValue(target));
559
+ }
560
+ }
561
+ }
562
+ #endif
@@ -0,0 +1,23 @@
1
+ {
2
+ "name": "UnityCli.Runtime.Tests",
3
+ "rootNamespace": "UnityCli.Tests",
4
+ "references": [
5
+ "UnityCli.Runtime"
6
+ ],
7
+ "includePlatforms": [
8
+ "Editor"
9
+ ],
10
+ "excludePlatforms": [],
11
+ "allowUnsafeCode": false,
12
+ "overrideReferences": false,
13
+ "precompiledReferences": [],
14
+ "autoReferenced": false,
15
+ "defineConstraints": [
16
+ "UNITY_INCLUDE_TESTS"
17
+ ],
18
+ "versionDefines": [],
19
+ "noEngineReferences": false,
20
+ "optionalUnityReferences": [
21
+ "TestAssemblies"
22
+ ]
23
+ }
@@ -0,0 +1,29 @@
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 UnityCliRuntimeCatalogValidationTests
9
+ {
10
+ [Test]
11
+ public void RuntimeDescribeAcceptsOnlyTheExactNamePayload()
12
+ {
13
+ var bridge = Type.GetType("UnityCli.UnityCliRuntimeBridge, UnityCli.Runtime", true);
14
+ var validate = bridge.GetMethod("ValidateRuntimeCatalogInput", BindingFlags.NonPublic | BindingFlags.Static);
15
+ var exact = new Dictionary<string, object> { { "name", "runtime.state" } };
16
+ Assert.That(() => validate.Invoke(null, new object[] { "runtime-tool.describe", exact }), Throws.Nothing);
17
+
18
+ var fallback = new Dictionary<string, object>
19
+ {
20
+ { "name", "runtime.state" },
21
+ { "fallbackName", "UnityPipeline_runtime.state" }
22
+ };
23
+ var exception = Assert.Throws<TargetInvocationException>(() =>
24
+ validate.Invoke(null, new object[] { "runtime-tool.describe", fallback }));
25
+ Assert.That(exception.InnerException, Is.TypeOf<FormatException>());
26
+ Assert.That(exception.InnerException.Message, Does.Contain("unknown field"));
27
+ }
28
+ }
29
+ }
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "com.alpsckr.unitycli",
3
- "version": "0.4.3",
3
+ "version": "0.4.4",
4
4
  "displayName": "UnityCLI",
5
5
  "description": "Editor package used by UnityCLI commands.",
6
6
  "unity": "2022.3",