@alpsckr/unitycli 0.4.2 → 0.4.4

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (420) hide show
  1. package/README.md +5 -5
  2. package/contracts/command-contract.json +109 -217
  3. package/contracts/package-files.json +374 -294
  4. package/contracts/stable-session/direct-call-semantics.json +8 -2
  5. package/contracts/tool-completion-contract.json +148 -672
  6. package/dist/bridge/admission.d.ts +17 -1
  7. package/dist/bridge/admission.js +2 -0
  8. package/dist/bridge/admission.js.map +1 -1
  9. package/dist/bridge/domains/asset.js +3 -1
  10. package/dist/bridge/domains/asset.js.map +1 -1
  11. package/dist/bridge/domains/camera.js +39 -7
  12. package/dist/bridge/domains/camera.js.map +1 -1
  13. package/dist/bridge/domains/console.js +2 -1
  14. package/dist/bridge/domains/console.js.map +1 -1
  15. package/dist/bridge/domains/doctor.d.ts +3 -0
  16. package/dist/bridge/domains/doctor.js +8 -0
  17. package/dist/bridge/domains/doctor.js.map +1 -0
  18. package/dist/bridge/domains/editor.js +0 -4
  19. package/dist/bridge/domains/editor.js.map +1 -1
  20. package/dist/bridge/domains/game-object.js +4 -12
  21. package/dist/bridge/domains/game-object.js.map +1 -1
  22. package/dist/bridge/domains/graphics.js +1 -16
  23. package/dist/bridge/domains/graphics.js.map +1 -1
  24. package/dist/bridge/domains/object.js +3 -0
  25. package/dist/bridge/domains/object.js.map +1 -1
  26. package/dist/bridge/domains/physics.js +1 -2
  27. package/dist/bridge/domains/physics.js.map +1 -1
  28. package/dist/bridge/domains/profiler.js +18 -7
  29. package/dist/bridge/domains/profiler.js.map +1 -1
  30. package/dist/bridge/domains/project-tool.js +4 -0
  31. package/dist/bridge/domains/project-tool.js.map +1 -1
  32. package/dist/bridge/domains/reflection.js +10 -2
  33. package/dist/bridge/domains/reflection.js.map +1 -1
  34. package/dist/bridge/domains/runtime-tool.js +3 -0
  35. package/dist/bridge/domains/runtime-tool.js.map +1 -1
  36. package/dist/bridge/domains/scene.js +3 -8
  37. package/dist/bridge/domains/scene.js.map +1 -1
  38. package/dist/bridge/domains/screenshot.js +30 -6
  39. package/dist/bridge/domains/screenshot.js.map +1 -1
  40. package/dist/bridge/domains/ui.js +3 -1
  41. package/dist/bridge/domains/ui.js.map +1 -1
  42. package/dist/bridge/index.d.ts +5 -5
  43. package/dist/bridge/index.js +6 -9
  44. package/dist/bridge/index.js.map +1 -1
  45. package/dist/bridge/registry.js +3 -5
  46. package/dist/bridge/registry.js.map +1 -1
  47. package/dist/bridge/session-supervisor.d.ts +6 -3
  48. package/dist/bridge/session-supervisor.js +122 -34
  49. package/dist/bridge/session-supervisor.js.map +1 -1
  50. package/dist/bridge/types.d.ts +6 -5
  51. package/dist/bridge/types.js +16 -2
  52. package/dist/bridge/types.js.map +1 -1
  53. package/dist/catalog-protocol.d.ts +64 -0
  54. package/dist/catalog-protocol.js +460 -0
  55. package/dist/catalog-protocol.js.map +1 -0
  56. package/dist/cli-commands/command.js +84 -61
  57. package/dist/cli-commands/command.js.map +1 -1
  58. package/dist/cli-commands/extensions.js +70 -50
  59. package/dist/cli-commands/extensions.js.map +1 -1
  60. package/dist/cli-commands/instances.js +1 -1
  61. package/dist/cli-commands/instances.js.map +1 -1
  62. package/dist/cli-process-owners.d.ts +6 -0
  63. package/dist/cli-process-owners.js +27 -0
  64. package/dist/cli-process-owners.js.map +1 -0
  65. package/dist/cli.d.ts +1 -1
  66. package/dist/cli.js +20 -5
  67. package/dist/cli.js.map +1 -1
  68. package/dist/contracts/command-contract.js +14 -4
  69. package/dist/contracts/command-contract.js.map +1 -1
  70. package/dist/doctor.d.ts +4 -6
  71. package/dist/doctor.js +429 -398
  72. package/dist/doctor.js.map +1 -1
  73. package/dist/editor-blocker-observer.d.ts +2 -1
  74. package/dist/editor-blocker-observer.js +40 -13
  75. package/dist/editor-blocker-observer.js.map +1 -1
  76. package/dist/extension-availability.d.ts +27 -9
  77. package/dist/extension-availability.js +96 -56
  78. package/dist/extension-availability.js.map +1 -1
  79. package/dist/extensions/descriptor-loader.d.ts +2 -2
  80. package/dist/extensions/descriptor-loader.js +3 -4
  81. package/dist/extensions/descriptor-loader.js.map +1 -1
  82. package/dist/extensions/index.d.ts +1 -1
  83. package/dist/extensions/index.js +1 -1
  84. package/dist/extensions/index.js.map +1 -1
  85. package/dist/extensions/installer.d.ts +24 -7
  86. package/dist/extensions/installer.js +142 -66
  87. package/dist/extensions/installer.js.map +1 -1
  88. package/dist/extensions/registry.js +3 -5
  89. package/dist/extensions/registry.js.map +1 -1
  90. package/dist/extensions/state-contract.d.ts +11 -0
  91. package/dist/extensions/state-contract.js +50 -0
  92. package/dist/extensions/state-contract.js.map +1 -0
  93. package/dist/instances.d.ts +13 -1
  94. package/dist/instances.js +26 -0
  95. package/dist/instances.js.map +1 -1
  96. package/dist/package-manager.d.ts +0 -24
  97. package/dist/package-manager.js +5 -58
  98. package/dist/package-manager.js.map +1 -1
  99. package/dist/project-tool-discovery.d.ts +5 -2
  100. package/dist/project-tool-discovery.js +22 -18
  101. package/dist/project-tool-discovery.js.map +1 -1
  102. package/dist/runtime-code.js +1 -1
  103. package/dist/runtime-code.js.map +1 -1
  104. package/dist/tool-name.d.ts +4 -0
  105. package/dist/tool-name.js +15 -0
  106. package/dist/tool-name.js.map +1 -0
  107. package/dist/tools/.generated-completion-registry.d.ts +2 -0
  108. package/dist/tools/.generated-completion-registry.js +763 -325
  109. package/dist/tools/.generated-completion-registry.js.map +1 -1
  110. package/dist/tools/.generated-registry.d.ts +6 -11
  111. package/dist/tools/.generated-registry.js +6 -11
  112. package/dist/tools/.generated-registry.js.map +1 -1
  113. package/dist/tools/.generated-schemas.js +11 -16
  114. package/dist/tools/.generated-schemas.js.map +1 -1
  115. package/dist/tools/asset/refresh-status.d.ts +3 -0
  116. package/dist/tools/asset/refresh-status.js +12 -0
  117. package/dist/tools/asset/refresh-status.js.map +1 -0
  118. package/dist/tools/asset/refresh.js +7 -3
  119. package/dist/tools/asset/refresh.js.map +1 -1
  120. package/dist/tools/build/player-status.d.ts +3 -0
  121. package/dist/tools/build/player-status.js +12 -0
  122. package/dist/tools/build/player-status.js.map +1 -0
  123. package/dist/tools/build/run.js +1 -1
  124. package/dist/tools/build/run.js.map +1 -1
  125. package/dist/tools/catalog-control.d.ts +22 -0
  126. package/dist/tools/catalog-control.js +335 -0
  127. package/dist/tools/catalog-control.js.map +1 -0
  128. package/dist/tools/catalog.d.ts +7 -9
  129. package/dist/tools/catalog.js +66 -45
  130. package/dist/tools/catalog.js.map +1 -1
  131. package/dist/tools/commands.d.ts +1 -1
  132. package/dist/tools/commands.js +44 -11
  133. package/dist/tools/commands.js.map +1 -1
  134. package/dist/tools/define.js +3 -2
  135. package/dist/tools/define.js.map +1 -1
  136. package/dist/tools/dispatcher.d.ts +53 -6
  137. package/dist/tools/dispatcher.js +277 -108
  138. package/dist/tools/dispatcher.js.map +1 -1
  139. package/dist/tools/editor/compile.js +1 -1
  140. package/dist/tools/editor/compile.js.map +1 -1
  141. package/dist/tools/editor/play-mode-status.d.ts +3 -0
  142. package/dist/tools/editor/play-mode-status.js +12 -0
  143. package/dist/tools/editor/play-mode-status.js.map +1 -0
  144. package/dist/tools/editor/readiness.d.ts +0 -1
  145. package/dist/tools/editor/readiness.js +0 -1
  146. package/dist/tools/editor/readiness.js.map +1 -1
  147. package/dist/tools/editor/refresh.d.ts +7 -3
  148. package/dist/tools/editor/refresh.js +20 -15
  149. package/dist/tools/editor/refresh.js.map +1 -1
  150. package/dist/tools/editor/state.d.ts +2 -2
  151. package/dist/tools/editor/state.js +13 -12
  152. package/dist/tools/editor/state.js.map +1 -1
  153. package/dist/tools/metadata/derived.js +1 -7
  154. package/dist/tools/metadata/derived.js.map +1 -1
  155. package/dist/tools/metadata/status.js +1 -12
  156. package/dist/tools/metadata/status.js.map +1 -1
  157. package/dist/tools/metadata/types.d.ts +0 -2
  158. package/dist/tools/navmesh/live.js +1 -1
  159. package/dist/tools/navmesh/live.js.map +1 -1
  160. package/dist/tools/occlusion/live.js +1 -1
  161. package/dist/tools/occlusion/live.js.map +1 -1
  162. package/dist/tools/package/deploy.js +2 -2
  163. package/dist/tools/package/deploy.js.map +1 -1
  164. package/dist/tools/package/embed.js +1 -1
  165. package/dist/tools/package/embed.js.map +1 -1
  166. package/dist/tools/package/install-status.d.ts +3 -0
  167. package/dist/tools/package/install-status.js +12 -0
  168. package/dist/tools/package/install-status.js.map +1 -0
  169. package/dist/tools/package/install.js +3 -3
  170. package/dist/tools/package/install.js.map +1 -1
  171. package/dist/tools/package/live-resolve.js +45 -12
  172. package/dist/tools/package/live-resolve.js.map +1 -1
  173. package/dist/tools/package/registry-clear.js.map +1 -1
  174. package/dist/tools/package/registry-set.js.map +1 -1
  175. package/dist/tools/package/remove-status.d.ts +3 -0
  176. package/dist/tools/package/remove-status.js +12 -0
  177. package/dist/tools/package/remove-status.js.map +1 -0
  178. package/dist/tools/package/remove.js +3 -3
  179. package/dist/tools/package/remove.js.map +1 -1
  180. package/dist/tools/package/resolve.js +3 -3
  181. package/dist/tools/package/resolve.js.map +1 -1
  182. package/dist/tools/package/restore.js +2 -2
  183. package/dist/tools/package/restore.js.map +1 -1
  184. package/dist/tools/package/scoped-registry-add.js.map +1 -1
  185. package/dist/tools/status/support.d.ts +13 -0
  186. package/dist/tools/status/support.js +28 -0
  187. package/dist/tools/status/support.js.map +1 -0
  188. package/dist/tools/test/cancel.js +2 -2
  189. package/dist/tools/test/cancel.js.map +1 -1
  190. package/dist/tools/test/run-status.d.ts +3 -0
  191. package/dist/tools/test/run-status.js +12 -0
  192. package/dist/tools/test/run-status.js.map +1 -0
  193. package/dist/tools/test/run.js +7 -4
  194. package/dist/tools/test/run.js.map +1 -1
  195. package/dist/tools/tools/group-summaries.js +10 -14
  196. package/dist/tools/tools/group-summaries.js.map +1 -1
  197. package/docs/architecture.md +4 -4
  198. package/docs/availability-differences.md +4 -4
  199. package/docs/command-execution.md +4 -3
  200. package/docs/error-codes.md +13 -5
  201. package/docs/extensions.md +1 -7
  202. package/docs/risk-and-side-effects.md +4 -3
  203. package/docs/safety-boundaries.md +3 -1
  204. package/docs/target-and-instance.md +1 -1
  205. package/docs/tool-discovery.md +17 -10
  206. package/docs/tool-execution.md +18 -7
  207. package/extensions/cinemachine/unitypkg/Editor/UnityCliExtensionAssembly.cs +3 -0
  208. package/extensions/hdrp/unitypkg/Editor/UnityCliExtensionAssembly.cs +3 -0
  209. package/extensions/probuilder/unitypkg/Editor/UnityCliExtensionAssembly.cs +3 -0
  210. package/extensions/urp/unitypkg/Editor/UnityCliExtensionAssembly.cs +3 -0
  211. package/extensions/vfx-graph/unitypkg/Editor/UnityCliExtensionAssembly.cs +3 -0
  212. package/package.json +2 -4
  213. package/skills/unitycli/SKILL.md +35 -42
  214. package/skills/unitycli/manifest.json +1 -1
  215. package/skills/unitycli/references/operation-protocol.md +3 -3
  216. package/unitypkg/Editor/AssemblyInfo.cs +5 -0
  217. package/unitypkg/Editor/Bridge/BridgeCommandRegistry.cs +49 -14
  218. package/unitypkg/Editor/Bridge/BridgeHttpServer.cs +9 -35
  219. package/unitypkg/Editor/Bridge/BridgeQueueState.cs +672 -0
  220. package/unitypkg/Editor/Bridge/BridgeWorkQueue.cs +970 -120
  221. package/unitypkg/Editor/BridgeStartupStateMachine.cs +59 -1
  222. package/unitypkg/Editor/Commands/ProjectToolCommands.cs +4 -0
  223. package/unitypkg/Editor/Commands/RuntimeToolCommands.cs +3 -0
  224. package/unitypkg/Editor/Generated/UnityCliToolCompletionRegistry.g.cs +379 -14
  225. package/unitypkg/Editor/Infrastructure/CodeExecSupport.cs +28 -13
  226. package/unitypkg/Editor/Infrastructure/RegistryOwnershipResolver.cs +132 -105
  227. package/unitypkg/Editor/Infrastructure/UnityCliActiveOperation.cs +138 -29
  228. package/unitypkg/Editor/Infrastructure/UnityCliAdmission.cs +1856 -237
  229. package/unitypkg/Editor/Infrastructure/UnityCliDoctorDiagnostics.cs +220 -0
  230. package/unitypkg/Editor/Infrastructure/UnityCliDurableStatusCoordinator.cs +118 -0
  231. package/unitypkg/Editor/Infrastructure/UnityCliEditorStateSnapshot.cs +2 -1
  232. package/unitypkg/Editor/Infrastructure/UnityCliHierarchyPager.cs +203 -0
  233. package/unitypkg/Editor/Infrastructure/UnityCliInstanceCleanup.cs +2 -1
  234. package/unitypkg/Editor/Infrastructure/UnityCliInstanceRegistry.cs +201 -63
  235. package/unitypkg/Editor/Infrastructure/UnityCliJson.cs +2 -3
  236. package/unitypkg/Editor/Infrastructure/UnityCliLiveBuildCoordinator.cs +289 -46
  237. package/unitypkg/Editor/Infrastructure/UnityCliLiveRefreshCoordinator.cs +87 -53
  238. package/unitypkg/Editor/Infrastructure/UnityCliNavMeshBakeCoordinator.cs +4 -4
  239. package/unitypkg/Editor/Infrastructure/UnityCliObjectRef.cs +128 -25
  240. package/unitypkg/Editor/Infrastructure/UnityCliObjectSerializer.cs +435 -327
  241. package/unitypkg/Editor/Infrastructure/UnityCliOcclusionBakeCoordinator.cs +4 -4
  242. package/unitypkg/Editor/Infrastructure/UnityCliOperationCoordinator.cs +351 -53
  243. package/unitypkg/Editor/Infrastructure/UnityCliPackageResolveCoordinator.cs +118 -18
  244. package/unitypkg/Editor/Infrastructure/UnityCliPackageResolveState.cs +20 -1
  245. package/unitypkg/Editor/Infrastructure/UnityCliReadGeneration.cs +97 -0
  246. package/unitypkg/Editor/Infrastructure/UnityCliReflection.cs +644 -133
  247. package/unitypkg/Editor/Infrastructure/UnityCliReloadOperation.cs +128 -41
  248. package/unitypkg/Editor/Infrastructure/UnityCliRuntimeExecutor.cs +14 -84
  249. package/unitypkg/Editor/Infrastructure/UnityCliSerializer.cs +220 -0
  250. package/unitypkg/Editor/Infrastructure/UnityCliSessionMutationLease.cs +69 -29
  251. package/unitypkg/Editor/Infrastructure/UnityCliTestRunCoordinator.cs +440 -54
  252. package/unitypkg/Editor/Infrastructure/UnityCliWaiter.cs +128 -35
  253. package/unitypkg/Editor/ProjectTools/IUnityCliTool.cs +9 -1
  254. package/unitypkg/Editor/ProjectTools/OfficialAttributeToolRegistry.cs +32 -31
  255. package/unitypkg/Editor/ProjectTools/ProjectToolRegistry.cs +607 -458
  256. package/unitypkg/Editor/ProjectTools/ProjectToolSchemaValidator.cs +35 -7
  257. package/unitypkg/Editor/ProjectTools/RegisteredTool.cs +501 -60
  258. package/unitypkg/Editor/ProjectTools/UnityCliProjectToolContext.cs +21 -0
  259. package/unitypkg/Editor/ProjectTools/UnityCliSchemaDeriver.cs +36 -7
  260. package/unitypkg/Editor/ProjectTools/UnityCliToolName.cs +30 -0
  261. package/unitypkg/Editor/Properties/AssemblyInfo.cs +3 -0
  262. package/unitypkg/Editor/Tools/asset/get-data.cs +16 -7
  263. package/unitypkg/Editor/Tools/build/BuildSceneStateTool.cs +23 -3
  264. package/unitypkg/Editor/Tools/build/BuildToolDtos.cs +2 -1
  265. package/unitypkg/Editor/Tools/build/scene/add.cs +6 -3
  266. package/unitypkg/Editor/Tools/build/scene/disable.cs +1 -1
  267. package/unitypkg/Editor/Tools/build/scene/enable.cs +1 -1
  268. package/unitypkg/Editor/Tools/build/scene/list.cs +1 -1
  269. package/unitypkg/Editor/Tools/build/scene/remove.cs +13 -3
  270. package/unitypkg/Editor/Tools/camera/CameraToolSupport.cs +38 -38
  271. package/unitypkg/Editor/Tools/camera/multiview.cs +13 -6
  272. package/unitypkg/Editor/Tools/camera/screenshot.cs +14 -7
  273. package/unitypkg/Editor/Tools/component/get.cs +16 -9
  274. package/unitypkg/Editor/Tools/component/modify.cs +6 -4
  275. package/unitypkg/Editor/Tools/console/clear.cs +7 -6
  276. package/unitypkg/Editor/Tools/console/get.cs +48 -16
  277. package/unitypkg/Editor/Tools/editor/EditorToolSupport.cs +143 -28
  278. package/unitypkg/Editor/Tools/editor/menu-items.cs +1 -1
  279. package/unitypkg/Editor/Tools/editor/play.cs +2 -11
  280. package/unitypkg/Editor/Tools/editor/selection.cs +1 -1
  281. package/unitypkg/Editor/Tools/editor/stop.cs +2 -11
  282. package/unitypkg/Editor/Tools/editor/windows.cs +1 -1
  283. package/unitypkg/Editor/Tools/go/GameObjectToolSupport.cs +54 -4
  284. package/unitypkg/Editor/Tools/go/delete.cs +1 -1
  285. package/unitypkg/Editor/Tools/go/find.cs +167 -70
  286. package/unitypkg/Editor/Tools/graphics/GraphicsToolSupport.cs +25 -0
  287. package/unitypkg/Editor/Tools/graphics/light-probe-group.cs +9 -3
  288. package/unitypkg/Editor/Tools/graphics/pipeline-info.cs +1 -1
  289. package/unitypkg/Editor/Tools/graphics/pipeline-settings.cs +1 -1
  290. package/unitypkg/Editor/Tools/graphics/quality.cs +2 -2
  291. package/unitypkg/Editor/Tools/graphics/reflection-probe.cs +3 -3
  292. package/unitypkg/Editor/Tools/graphics/stats.cs +1 -1
  293. package/unitypkg/Editor/Tools/object/ObjectToolSupport.cs +4 -4
  294. package/unitypkg/Editor/Tools/object/get-data.cs +9 -7
  295. package/unitypkg/Editor/Tools/object/modify.cs +7 -5
  296. package/unitypkg/Editor/Tools/physics/raycast.cs +24 -6
  297. package/unitypkg/Editor/Tools/prefab/stage.cs +1 -1
  298. package/unitypkg/Editor/Tools/profiler/ProfilerFrameDebuggerSupport.cs +94 -21
  299. package/unitypkg/Editor/Tools/profiler/ProfilerMemorySnapshotSupport.cs +397 -10
  300. package/unitypkg/Editor/Tools/profiler/ProfilerToolSupport.cs +18 -4
  301. package/unitypkg/Editor/Tools/profiler/frame-debugger/enable.cs +1 -1
  302. package/unitypkg/Editor/Tools/profiler/frame-debugger/events.cs +88 -87
  303. package/unitypkg/Editor/Tools/profiler/hierarchy.cs +278 -112
  304. package/unitypkg/Editor/Tools/profiler/memory-snapshot/compare.cs +9 -5
  305. package/unitypkg/Editor/Tools/profiler/memory-snapshot/list.cs +37 -35
  306. package/unitypkg/Editor/Tools/profiler/memory-snapshot/take.cs +99 -97
  307. package/unitypkg/Editor/Tools/project/info.cs +1 -1
  308. package/unitypkg/Editor/Tools/project/layers.cs +1 -1
  309. package/unitypkg/Editor/Tools/project/tags.cs +1 -1
  310. package/unitypkg/Editor/Tools/reflection/method/call.cs +9 -7
  311. package/unitypkg/Editor/Tools/reflection/method/find.cs +27 -37
  312. package/unitypkg/Editor/Tools/reflection/type/schema.cs +24 -28
  313. package/unitypkg/Editor/Tools/scene/gameobject/component.cs +8 -5
  314. package/unitypkg/Editor/Tools/scene/gameobject/components.cs +10 -7
  315. package/unitypkg/Editor/Tools/scene/gameobject-support.cs +104 -8
  316. package/unitypkg/Editor/Tools/scene/gameobject.cs +37 -16
  317. package/unitypkg/Editor/Tools/scene/hierarchy.cs +146 -142
  318. package/unitypkg/Editor/Tools/screenshot/EditorElementCaptureToolSupport.cs +77 -25
  319. package/unitypkg/Editor/Tools/screenshot/ScreenshotToolSupport.cs +315 -95
  320. package/unitypkg/Editor/Tools/screenshot/editor-element.cs +7 -5
  321. package/unitypkg/Editor/Tools/screenshot/game-view.cs +35 -21
  322. package/unitypkg/Editor/Tools/screenshot/isolated-object.cs +29 -23
  323. package/unitypkg/Editor/Tools/screenshot/orbit.cs +37 -25
  324. package/unitypkg/Editor/Tools/screenshot/scene-view.cs +25 -18
  325. package/unitypkg/Editor/Tools/screenshot/screen.cs +177 -17
  326. package/unitypkg/Editor/Tools/screenshot/surround.cs +83 -79
  327. package/unitypkg/Editor/Tools/ui/render-preview.cs +16 -11
  328. package/unitypkg/Editor/UnityCliBridge.cs +97 -34
  329. package/unitypkg/Runtime/Infrastructure/UnityCliRuntimeBridge.cs +753 -122
  330. package/unitypkg/Runtime/Properties/AssemblyInfo.cs +5 -0
  331. package/unitypkg/Runtime/UnityCli.Runtime.asmdef +1 -1
  332. package/unitypkg/Shared/AssemblyInfo.cs +4 -0
  333. package/unitypkg/Shared/UnityCliAdmissionPool.cs +265 -75
  334. package/unitypkg/Shared/UnityCliBridgeQueuePolicy.cs +410 -0
  335. package/unitypkg/Shared/UnityCliBridgeWorkItemState.cs +47 -0
  336. package/unitypkg/Shared/UnityCliExceptionProjection.cs +151 -0
  337. package/unitypkg/Shared/UnityCliQueuePublication.cs +30 -0
  338. package/unitypkg/Shared/UnityCliRequestBudget.cs +352 -0
  339. package/unitypkg/Shared/UnityCliRuntimeRequestPublication.cs +107 -0
  340. package/unitypkg/Tests/Editor/UnityCli.Editor.Tests.asmdef +2 -2
  341. package/unitypkg/Tests/Editor/UnityCliAdmissionCoordinatorIntegrationTests.cs +1329 -0
  342. package/unitypkg/Tests/Editor/UnityCliAdmissionPoolTests.cs +311 -114
  343. package/unitypkg/Tests/Editor/UnityCliAdmissionRepairStateTests.cs +94 -0
  344. package/unitypkg/Tests/Editor/UnityCliBridgeAdmissionIntegrationTests.cs +1229 -0
  345. package/unitypkg/Tests/Editor/UnityCliBridgeQueuePolicyTests.cs +412 -0
  346. package/unitypkg/Tests/Editor/UnityCliContinuationIntegrationTests.cs +292 -0
  347. package/unitypkg/Tests/Editor/UnityCliDiagnosticBoundaryTests.cs +120 -0
  348. package/unitypkg/Tests/Editor/UnityCliDurableStatusTests.cs +84 -0
  349. package/unitypkg/Tests/Editor/UnityCliExceptionProjectionTests.cs +72 -0
  350. package/unitypkg/Tests/Editor/UnityCliInstancePublicationRetryTests.cs +180 -97
  351. package/unitypkg/Tests/Editor/UnityCliMemoryReflectionIntegrationTests.cs +434 -0
  352. package/unitypkg/Tests/Editor/UnityCliRequestBudgetTests.cs +615 -0
  353. package/unitypkg/Tests/Editor/UnityCliRuntimeBridgeIntegrationTests.cs +520 -0
  354. package/unitypkg/Tests/Editor/UnityCliToolCatalogTests.cs +562 -0
  355. package/unitypkg/Tests/Runtime/UnityCli.Runtime.Tests.asmdef +23 -0
  356. package/unitypkg/Tests/Runtime/UnityCliRuntimeCatalogValidationTests.cs +29 -0
  357. package/unitypkg/package.json +1 -1
  358. package/contracts/static-capability-catalog.json +0 -48226
  359. package/dist/bridge/domains/diagnose.d.ts +0 -2
  360. package/dist/bridge/domains/diagnose.js +0 -11
  361. package/dist/bridge/domains/diagnose.js.map +0 -1
  362. package/dist/bridge/domains/extension.d.ts +0 -8
  363. package/dist/bridge/domains/extension.js +0 -20
  364. package/dist/bridge/domains/extension.js.map +0 -1
  365. package/dist/capabilities.d.ts +0 -5
  366. package/dist/capabilities.js +0 -84
  367. package/dist/capabilities.js.map +0 -1
  368. package/dist/static-capability-catalog.d.ts +0 -13
  369. package/dist/static-capability-catalog.js +0 -41
  370. package/dist/static-capability-catalog.js.map +0 -1
  371. package/dist/tools/diagnose/capabilities.d.ts +0 -13
  372. package/dist/tools/diagnose/capabilities.js +0 -34
  373. package/dist/tools/diagnose/capabilities.js.map +0 -1
  374. package/dist/tools/package/info.d.ts +0 -19
  375. package/dist/tools/package/info.js +0 -27
  376. package/dist/tools/package/info.js.map +0 -1
  377. package/dist/tools/package/list.d.ts +0 -27
  378. package/dist/tools/package/list.js +0 -21
  379. package/dist/tools/package/list.js.map +0 -1
  380. package/dist/tools/package/registry-get.d.ts +0 -10
  381. package/dist/tools/package/registry-get.js +0 -22
  382. package/dist/tools/package/registry-get.js.map +0 -1
  383. package/dist/tools/package/scoped-registry-list.d.ts +0 -14
  384. package/dist/tools/package/scoped-registry-list.js +0 -22
  385. package/dist/tools/package/scoped-registry-list.js.map +0 -1
  386. package/dist/tools/package/search.d.ts +0 -17
  387. package/dist/tools/package/search.js +0 -39
  388. package/dist/tools/package/search.js.map +0 -1
  389. package/dist/tools/package/status.d.ts +0 -21
  390. package/dist/tools/package/status.js +0 -37
  391. package/dist/tools/package/status.js.map +0 -1
  392. package/dist/tools/tools/describe.d.ts +0 -27
  393. package/dist/tools/tools/describe.js +0 -35
  394. package/dist/tools/tools/describe.js.map +0 -1
  395. package/dist/tools/tools/group-list.d.ts +0 -16
  396. package/dist/tools/tools/group-list.js +0 -38
  397. package/dist/tools/tools/group-list.js.map +0 -1
  398. package/dist/tools/tools/group.d.ts +0 -13
  399. package/dist/tools/tools/group.js +0 -34
  400. package/dist/tools/tools/group.js.map +0 -1
  401. package/dist/tools/tools/pagination.d.ts +0 -17
  402. package/dist/tools/tools/pagination.js +0 -28
  403. package/dist/tools/tools/pagination.js.map +0 -1
  404. package/dist/tools/tools/search.d.ts +0 -15
  405. package/dist/tools/tools/search.js +0 -42
  406. package/dist/tools/tools/search.js.map +0 -1
  407. package/unitypkg/Editor/Tools/diagnose/preflight.cs +0 -269
  408. package/unitypkg/Editor/Tools/editor/console.cs +0 -26
  409. package/unitypkg/Editor/Tools/extension/status.cs +0 -87
  410. package/unitypkg/Editor/Tools/go/inspect.cs +0 -49
  411. package/unitypkg/Editor/Tools/graphics/pipeline-quality.cs +0 -24
  412. package/unitypkg/Editor/Tools/graphics/probe-positions.cs +0 -58
  413. package/unitypkg/Editor/Tools/graphics/settings.cs +0 -104
  414. package/unitypkg/Editor/Tools/graphics/stats-counters.cs +0 -28
  415. package/unitypkg/Editor/Tools/graphics/stats-memory.cs +0 -21
  416. package/unitypkg/Editor/Tools/instances/list.cs +0 -71
  417. package/unitypkg/Editor/Tools/physics/raycast-all.cs +0 -67
  418. package/unitypkg/Editor/Tools/scene/build-settings.cs +0 -69
  419. package/unitypkg/Editor/Tools/scene/data.cs +0 -125
  420. package/unitypkg/Editor/Tools/tests/list.cs +0 -98
@@ -2,15 +2,13 @@
2
2
  using System;
3
3
  using System.Collections.Generic;
4
4
  using System.Globalization;
5
- using System.Linq;
5
+ using UnityEditor;
6
6
  using UnityEngine;
7
7
  using UnityEngine.SceneManagement;
8
8
 
9
9
  namespace UnityCli
10
10
  {
11
- /// <summary>
12
- /// go.find — 按名称/标签/层/组件/层级路径/实例ID 搜索 GameObject,可选优先 Prefab Stage。
13
- /// </summary>
11
+ /// <summary>go.find — exact selector 直达,其他 selector 按 raw hierarchy position 有界续页。</summary>
14
12
  public class GameObjectFindTool : IUnityCliTool<GameObjectFindTool.Request, GameObjectFindTool.Result>
15
13
  {
16
14
  public sealed class Request
@@ -24,26 +22,52 @@ namespace UnityCli
24
22
  public string Component { get; set; }
25
23
  public string Path { get; set; }
26
24
  public string Id { get; set; }
25
+ [UnityCliStringEnum("by_name", "by_tag", "by_layer", "by_component", "by_path", "by_id")]
27
26
  public string SearchMethod { get; set; }
28
27
  public bool IncludeInactive { get; set; }
29
28
  public bool PreferPrefabStage { get; set; }
30
- public int? PageSize { get; set; }
31
- public int? Cursor { get; set; }
29
+ [UnityCliRange(1L, 500L)] public int? PageSize { get; set; }
30
+ public string Cursor { get; set; }
31
+ public UnityCliReadBudgetInput Budget { get; set; }
32
32
  }
33
33
 
34
34
  public sealed class Result
35
35
  {
36
36
  public bool PrefabStageOpen { get; set; }
37
- public long MatchCount { get; set; }
38
- public List<GoFindItem> Items { get; set; }
39
- public GoPageInfo PageInfo { get; set; }
37
+ public long ReturnedCount { get; set; }
38
+ [UnityCliItemsRange(0, 500)] public List<Item> Items { get; set; }
39
+ public PageInfo PageInfo { get; set; }
40
+ public UnityCliRequestBudgetUsage Budget { get; set; }
41
+ }
42
+
43
+ public sealed class Item
44
+ {
45
+ public long Id { get; set; }
46
+ public string Name { get; set; }
47
+ public string Path { get; set; }
48
+ public bool Active { get; set; }
49
+ public bool ActiveInHierarchy { get; set; }
50
+ public string Tag { get; set; }
51
+ public long Layer { get; set; }
52
+ public long ChildCount { get; set; }
53
+ public bool ChildrenTruncated { get; set; }
54
+ }
55
+
56
+ public sealed class PageInfo
57
+ {
58
+ public long PageSize { get; set; }
59
+ public string Cursor { get; set; }
60
+ public string NextCursor { get; set; }
61
+ public bool Complete { get; set; }
62
+ public bool Truncated { get; set; }
63
+ public string Generation { get; set; }
40
64
  }
41
65
 
42
66
  public ToolDescriptor Describe() => new()
43
67
  {
44
68
  Name = "go.find",
45
- Summary = "Search GameObjects by name, tag, layer, component, hierarchy path, or instance id; optionally prefer an open Prefab Stage.",
46
- Description = "Search GameObjects by name, tag, layer, component, hierarchy path, or instance id. Results are lightweight and paged. Pass preferPrefabStage=true to first match inside an open Prefab Stage (prefabContentsRoot), then merge scene matches.",
69
+ Summary = "Resolve exact GameObject ids/paths directly or page filtered hierarchy matches from stable raw positions.",
70
+ Description = "Search loaded GameObjects by exact name, tag, layer or component. by_id uses direct instance resolution and by_path walks only the exact case-sensitive path; neither materializes the scene tree. Other selectors stream Unity hierarchy order with pageSize 1..500 (default 50). All work shares budget defaults of 10000 scans, 4096 nodes, 2048 getters, 4096 reflection calls, 250 main-thread ms and 1 MiB UTF-8; maxima are 100000/20000/10000/20000/2000 ms/8 MiB. No filtered total is fabricated: pageInfo.complete/truncated and nextCursor identify the next raw object. preferPrefabStage scans the open Prefab Stage first. Read-only in Edit and Play Mode.",
47
71
  Group = "go",
48
72
  DestructiveHint = false,
49
73
  Target = "editor",
@@ -52,47 +76,116 @@ namespace UnityCli
52
76
  MaxTimeoutMs = 600000,
53
77
  Examples = new[]
54
78
  {
55
- new ToolExample { Description = "Find by name", Input = new Request { SearchTerm = "Player", SearchMethod = "by_name", PageSize = 25 } },
56
- new ToolExample { Description = "Find objects with Camera component", Input = new Request { SearchTerm = "Camera", SearchMethod = "by_component", PageSize = 10 } }
79
+ new ToolExample { Description = "Find an exact object name", Input = new Request { SearchTerm = "Player", SearchMethod = "by_name", PageSize = 25 } },
80
+ new ToolExample { Description = "Resolve a full hierarchy path directly", Input = new Request { SearchTerm = "World/Player", SearchMethod = "by_path" } }
57
81
  }
58
82
  };
59
83
 
60
84
  public System.Threading.Tasks.ValueTask<Result> ExecuteAsync(Request request, UnityCliProjectToolContext ctx, System.Threading.CancellationToken ct = default)
61
85
  {
86
+ request = request ?? new Request();
62
87
  var searchTerm = request.SearchTerm ?? request.Query ?? request.Target ?? request.Name ?? request.Tag ?? request.Layer ?? request.Component ?? request.Path ?? request.Id;
63
- if (string.IsNullOrEmpty(searchTerm))
88
+ if (string.IsNullOrEmpty(searchTerm)) throw new UnityCliBridge.BridgeCommandException("E_TARGET_NOT_FOUND", "GameObject find requires a search term.", "Pass searchTerm and one documented searchMethod.");
89
+ var method = request.SearchMethod ?? InferSearchMethod(request);
90
+ var budget = ctx.UseReadBudget(request.Budget);
91
+ var pageSize = request.PageSize ?? 50;
92
+ if ((method == "by_id" || method == "by_path") && !string.IsNullOrEmpty(request.Cursor))
93
+ throw new UnityCliBridge.BridgeCommandException("E_CONTINUATION_INVALID", "Exact by_id/by_path resolution does not accept cursor.", "Remove cursor for exact resolution.");
94
+
95
+ if (!budget.TryConsumeGetter()) throw new UnityCliRequestBudgetExceededException(budget.ExhaustedDimension);
96
+ var prefabStage = UnityEditor.SceneManagement.PrefabStageUtility.GetCurrentPrefabStage();
97
+ GameObject prefabRoot = null;
98
+ var prefabStageIdentity = string.Empty;
99
+ if (request.PreferPrefabStage && prefabStage != null)
64
100
  {
65
- throw new UnityCliBridge.BridgeCommandException("E_TARGET_NOT_FOUND", "GameObject find requires a search term.", "Pass --input '{\"searchTerm\":\"Player\",\"searchMethod\":\"by_name\"}'.");
101
+ if (!budget.TryConsumeGetters(3)) throw new UnityCliRequestBudgetExceededException(budget.ExhaustedDimension);
102
+ prefabRoot = prefabStage.prefabContentsRoot;
103
+ if (prefabRoot != null)
104
+ prefabStageIdentity = prefabStage.scene.handle.ToString(CultureInfo.InvariantCulture) + "\0" + prefabStage.assetPath;
105
+ }
106
+ var prefabOpen = prefabRoot != null;
107
+ var generation = UnityCliContinuationToken.Fingerprint(
108
+ UnityCliReadGeneration.Hierarchy(SceneManager.GetActiveScene()) + "\0" + method + "\0" + searchTerm + "\0" + request.IncludeInactive
109
+ + "\0" + prefabOpen + "\0" + prefabStageIdentity);
110
+ if (method == "by_id" || method == "by_path")
111
+ {
112
+ var exact = ResolveExact(method, searchTerm, budget);
113
+ var exactItems = new List<Item>();
114
+ if (exact != null)
115
+ {
116
+ if (!budget.TryConsumeGetter()) throw new UnityCliRequestBudgetExceededException(budget.ExhaustedDimension);
117
+ if (request.IncludeInactive || exact.activeInHierarchy) exactItems.Add(BuildItem(exact, budget));
118
+ }
119
+ return new System.Threading.Tasks.ValueTask<Result>(ResultPage(exactItems, pageSize, request.Cursor, null, generation, prefabOpen, budget));
66
120
  }
67
- var searchMethod = request.SearchMethod ?? InferSearchMethod(request);
68
- var includeInactive = request.IncludeInactive;
69
- var preferPrefabStage = request.PreferPrefabStage;
70
- var pageSize = Math.Max(1, Math.Min(request.PageSize ?? 50, 500));
71
- var cursor = Math.Max(0, request.Cursor ?? 0);
72
121
 
73
- // Prefab Stage 优先:preferPrefabStage=true 且有打开的 Prefab Stage 时,先在 prefab 内容里匹配,再合并场景匹配
74
- var prefabStage = UnityEditor.SceneManagement.PrefabStageUtility.GetCurrentPrefabStage();
75
- var prefabStageMatches = new List<GameObject>();
76
- var prefabStageOpen = preferPrefabStage && prefabStage != null && prefabStage.prefabContentsRoot != null;
77
- if (prefabStageOpen)
122
+ Type componentType = null;
123
+ int? layer = null;
124
+ if (method == "by_component") componentType = GameObjectToolSupport.ResolveComponentType(searchTerm, budget);
125
+ if (method == "by_layer") layer = GameObjectToolSupport.ParseLayer(searchTerm);
126
+ var prefabTraversal = prefabOpen ? new UnityCliHierarchyPager.Traversal(prefabStage.scene, prefabRoot, int.MaxValue, budget) : null;
127
+ var sceneTraversal = new UnityCliHierarchyPager.LoadedSceneTraversal(budget, prefabOpen ? prefabStage.scene.handle : 0);
128
+ GameObject current;
129
+ var phase = prefabOpen ? "prefab" : "scene";
130
+ if (string.IsNullOrEmpty(request.Cursor)) current = prefabOpen ? prefabRoot : sceneTraversal.First(budget);
131
+ else
132
+ {
133
+ current = UnityCliHierarchyPager.ResolveCursor(request.Cursor, "go.find", generation, budget, out phase);
134
+ if (phase != "scene" && phase != "prefab") throw UnityCliHierarchyPager.Stale();
135
+ if (phase == "prefab" && (!prefabOpen || !IsDescendantOrSelf(current.transform, prefabRoot.transform, budget))) throw UnityCliHierarchyPager.Stale();
136
+ if (phase == "scene" && prefabOpen && current.scene.handle == prefabStage.scene.handle) throw UnityCliHierarchyPager.Stale();
137
+ }
138
+
139
+ var items = new List<Item>();
140
+ while (current != null && items.Count < pageSize)
78
141
  {
79
- foreach (var t in prefabStage.prefabContentsRoot.GetComponentsInChildren<Transform>(includeInactive))
142
+ var candidate = current;
143
+ if (!budget.TryConsumeScannedRecord()) break;
144
+ try
145
+ {
146
+ var nextPhase = phase;
147
+ var next = phase == "prefab" ? prefabTraversal.Next(candidate, budget) : sceneTraversal.Next(candidate, budget);
148
+ if (phase == "prefab" && next == null) { nextPhase = "scene"; next = sceneTraversal.First(budget); }
149
+ if (Matches(candidate, method, searchTerm, request.IncludeInactive, componentType, layer, budget))
150
+ items.Add(BuildItem(candidate, budget));
151
+ phase = nextPhase;
152
+ current = next;
153
+ }
154
+ catch (UnityCliRequestBudgetExceededException)
80
155
  {
81
- if (MatchesGameObject(t.gameObject, searchMethod, searchTerm)) prefabStageMatches.Add(t.gameObject);
156
+ current = candidate;
157
+ break;
82
158
  }
83
159
  }
84
- var sceneMatches = SearchGameObjects(searchMethod, searchTerm, includeInactive);
85
- var matches = prefabStageOpen ? prefabStageMatches.Concat(sceneMatches).ToList() : sceneMatches;
86
- var total = matches.Count;
87
- var page = matches.Skip(cursor).Take(pageSize).ToList();
88
- long? nextCursor = cursor + page.Count < total ? (long?)(cursor + page.Count) : null;
89
- return new System.Threading.Tasks.ValueTask<Result>(new Result
160
+
161
+ if (items.Count == 0 && current != null) throw new UnityCliRequestBudgetExceededException(budget.ExhaustedDimension ?? "scannedRecords");
162
+ var nextCursor = UnityCliHierarchyPager.Cursor("go.find", generation, phase, current, budget);
163
+ return new System.Threading.Tasks.ValueTask<Result>(ResultPage(items, pageSize, request.Cursor, nextCursor, generation, prefabOpen, budget));
164
+ }
165
+
166
+ private static Result ResultPage(List<Item> items, int pageSize, string cursor, string nextCursor, string generation, bool prefabOpen, UnityCliRequestBudget budget)
167
+ {
168
+ return new Result
90
169
  {
91
- PrefabStageOpen = prefabStageOpen,
92
- MatchCount = total,
93
- Items = page.ConvertAll(BuildItem),
94
- PageInfo = new GoPageInfo { PageSize = pageSize, Cursor = cursor, NextCursor = nextCursor, Total = total }
95
- });
170
+ PrefabStageOpen = prefabOpen,
171
+ ReturnedCount = items.Count,
172
+ Items = items,
173
+ PageInfo = new PageInfo
174
+ {
175
+ PageSize = pageSize, Cursor = cursor, NextCursor = nextCursor,
176
+ Complete = nextCursor == null, Truncated = nextCursor != null, Generation = generation
177
+ },
178
+ Budget = budget.Usage()
179
+ };
180
+ }
181
+
182
+ private static GameObject ResolveExact(string method, string value, UnityCliRequestBudget budget)
183
+ {
184
+ if (method == "by_path") return UnityCliBridge.ObjectRefResolver.FindGameObjectByExactPath(value, budget);
185
+ int instanceId;
186
+ if (!int.TryParse(value, NumberStyles.Integer, CultureInfo.InvariantCulture, out instanceId)) return null;
187
+ if (!budget.TryConsumeGetter()) throw new UnityCliRequestBudgetExceededException(budget.ExhaustedDimension);
188
+ return EditorUtility.InstanceIDToObject(instanceId) as GameObject;
96
189
  }
97
190
 
98
191
  private static string InferSearchMethod(Request request)
@@ -105,47 +198,51 @@ namespace UnityCli
105
198
  return "by_name";
106
199
  }
107
200
 
108
- private static List<GameObject> SearchGameObjects(string searchMethod, string searchTerm, bool includeInactive)
201
+ private static bool Matches(GameObject gameObject, string method, string value, bool includeInactive, Type componentType, int? layer, UnityCliRequestBudget budget)
109
202
  {
110
- var allObjects = UnityEngine.Object.FindObjectsOfType<GameObject>(includeInactive)
111
- .OrderBy(GameObjectToolSupport.HierarchyPath, StringComparer.Ordinal).ToList();
112
- return allObjects.Where(go => MatchesGameObject(go, searchMethod, searchTerm)).ToList();
203
+ if (!budget.TryConsumeGetter()) throw new UnityCliRequestBudgetExceededException(budget.ExhaustedDimension);
204
+ if (!includeInactive && !gameObject.activeInHierarchy) return false;
205
+ if (method == "by_component")
206
+ {
207
+ if (!budget.TryConsumeGetter()) throw new UnityCliRequestBudgetExceededException(budget.ExhaustedDimension);
208
+ return gameObject.GetComponent(componentType) != null;
209
+ }
210
+ if (!budget.TryConsumeGetter()) throw new UnityCliRequestBudgetExceededException(budget.ExhaustedDimension);
211
+ if (method == "by_tag") return string.Equals(gameObject.tag, value, StringComparison.Ordinal);
212
+ if (method == "by_layer") return gameObject.layer == layer;
213
+ if (method != "by_name") throw new UnityCliBridge.BridgeCommandException("E_SEARCH_METHOD_INVALID", "Unsupported GameObject searchMethod: " + method, "Use by_name, by_tag, by_layer, by_component, by_path, or by_id.");
214
+ return string.Equals(gameObject.name, value, StringComparison.Ordinal);
113
215
  }
114
216
 
115
- private static bool MatchesGameObject(GameObject gameObject, string searchMethod, string searchTerm)
217
+ private static Item BuildItem(GameObject gameObject, UnityCliRequestBudget budget)
116
218
  {
117
- var normalized = (searchMethod ?? "by_name").Trim().ToLowerInvariant();
118
- if (normalized == "by_id") return gameObject.GetInstanceID().ToString(CultureInfo.InvariantCulture) == searchTerm;
119
- if (normalized == "by_path") return string.Equals(GameObjectToolSupport.HierarchyPath(gameObject), searchTerm, StringComparison.Ordinal);
120
- if (normalized == "by_tag") return string.Equals(gameObject.tag, searchTerm, StringComparison.Ordinal);
121
- if (normalized == "by_layer") return gameObject.layer == GameObjectToolSupport.ParseLayer(searchTerm);
122
- if (normalized == "by_component") { var type = GameObjectToolSupport.ResolveComponentType(searchTerm); return type != null && gameObject.GetComponent(type) != null; }
123
- if (normalized != "by_name") throw new UnityCliBridge.BridgeCommandException("E_SEARCH_METHOD_INVALID", "Unsupported GameObject searchMethod: " + searchMethod, "Use by_name, by_tag, by_layer, by_component, by_path, or by_id.");
124
- return string.Equals(gameObject.name, searchTerm, StringComparison.Ordinal);
219
+ if (!budget.TryConsumeNode() || !budget.TryConsumeGetter()) throw new UnityCliRequestBudgetExceededException(budget.ExhaustedDimension);
220
+ var path = UnityCliHierarchyPager.Path(gameObject, budget);
221
+ var name = gameObject.name;
222
+ if (!budget.TryConsumeGetter() || !budget.TryConsumeGetter() || !budget.TryConsumeGetter()
223
+ || !budget.TryConsumeGetter() || !budget.TryConsumeGetter()) throw new UnityCliRequestBudgetExceededException(budget.ExhaustedDimension);
224
+ var tag = gameObject.tag;
225
+ var childCount = gameObject.transform.childCount;
226
+ if (!budget.TryReserveSerializedUtf8(name) || !budget.TryReserveSerializedUtf8(path) || !budget.TryReserveSerializedUtf8(tag))
227
+ throw new UnityCliRequestBudgetExceededException(budget.ExhaustedDimension);
228
+ return new Item
229
+ {
230
+ Id = gameObject.GetInstanceID(), Name = name, Path = path,
231
+ Active = gameObject.activeSelf, ActiveInHierarchy = gameObject.activeInHierarchy,
232
+ Tag = tag, Layer = gameObject.layer,
233
+ ChildCount = childCount, ChildrenTruncated = childCount > 0
234
+ };
125
235
  }
126
236
 
127
- private static GoFindItem BuildItem(GameObject gameObject)
237
+ private static bool IsDescendantOrSelf(Transform value, Transform root, UnityCliRequestBudget budget)
128
238
  {
129
- var componentNames = new List<string>();
130
- foreach (var component in gameObject.GetComponents<Component>())
239
+ while (value != null)
131
240
  {
132
- componentNames.Add(component != null ? component.GetType().Name : "MissingScript");
241
+ if (value == root) return true;
242
+ if (!budget.TryConsumeGetter()) throw new UnityCliRequestBudgetExceededException(budget.ExhaustedDimension);
243
+ value = value.parent;
133
244
  }
134
- return new GoFindItem
135
- {
136
- Id = gameObject.GetInstanceID(),
137
- Name = gameObject.name,
138
- Path = GameObjectToolSupport.HierarchyPath(gameObject),
139
- Active = gameObject.activeSelf,
140
- ActiveInHierarchy = gameObject.activeInHierarchy,
141
- Tag = gameObject.tag,
142
- Layer = gameObject.layer,
143
- ChildCount = gameObject.transform.childCount,
144
- ChildrenTruncated = gameObject.transform.childCount > 0,
145
- ComponentCount = componentNames.Count,
146
- ComponentTypes = componentNames,
147
- Components = componentNames
148
- };
245
+ return false;
149
246
  }
150
247
  }
151
248
  }
@@ -2,6 +2,7 @@
2
2
  using System;
3
3
  using System.Collections.Generic;
4
4
  using System.Globalization;
5
+ using System.Linq;
5
6
  using System.Reflection;
6
7
  using System.Security.Cryptography;
7
8
  using UnityEditor;
@@ -181,6 +182,23 @@ namespace UnityCli
181
182
  return null;
182
183
  }
183
184
 
185
+ /// <summary>构造探针所属 GameObject 的 fresh identity。</summary>
186
+ public static GraphicsProbeTarget BuildProbeTarget(GameObject gameObject)
187
+ {
188
+ return new GraphicsProbeTarget
189
+ {
190
+ Id = gameObject.GetInstanceID(),
191
+ Name = gameObject.name,
192
+ Path = GameObjectToolSupport.HierarchyPath(gameObject)
193
+ };
194
+ }
195
+
196
+ /// <summary>将探针位置投影为 typed DTO,避免返回请求字符串。</summary>
197
+ public static List<Vector3Data> BuildProbePositions(IEnumerable<Vector3> positions)
198
+ {
199
+ return (positions ?? Enumerable.Empty<Vector3>()).Select(position => new Vector3Data(position)).ToList();
200
+ }
201
+
184
202
  /// <summary>构造 ReflectionProbe 摘要 DTO。</summary>
185
203
  public static ReflectionProbeInfo BuildReflectionProbeInfo(ReflectionProbe probe)
186
204
  {
@@ -326,6 +344,13 @@ namespace UnityCli
326
344
  public long GiWorkflowMode { get; set; }
327
345
  }
328
346
 
347
+ public sealed class GraphicsProbeTarget
348
+ {
349
+ public long Id { get; set; }
350
+ public string Name { get; set; }
351
+ public string Path { get; set; }
352
+ }
353
+
329
354
  public sealed class ReflectionProbeInfo
330
355
  {
331
356
  public string Mode { get; set; }
@@ -11,8 +11,8 @@ namespace UnityCli
11
11
  public class GraphicsLightProbeGroupTool : IUnityCliTool<GraphicsLightProbeGroupTool.Request, GraphicsLightProbeGroupTool.Result>
12
12
  {
13
13
  public sealed class Request { public string Target { get; set; } public bool? Create { get; set; } public string Positions { get; set; } }
14
- public sealed class Result { public long ProbeCount { get; set; } public List<GraphicsPlannedEffect> PlannedEffects { get; set; } }
15
- public ToolDescriptor Describe() => new() { Name = "graphics.light-probe-group", Summary = "Add, configure, or read a LightProbeGroup component on a target.", Description = "Resolve a target GameObject, optionally create a LightProbeGroup, and set probe positions from a space-separated vector array.", Group = "graphics",DestructiveHint = false, SideEffects = new[] { "scene-modify" }, Target = "editor", PlayModeSupport = "supported", DefaultTimeoutMs = 30000, MaxTimeoutMs = 600000, Examples = new[] { new ToolExample { Description = "Read light probe group", Input = new Request { Target = "LightProbes" } } } };
14
+ public sealed class Result { public GraphicsProbeTarget Target { get; set; } public long ProbeCount { get; set; } public List<Vector3Data> Positions { get; set; } public List<GraphicsPlannedEffect> PlannedEffects { get; set; } }
15
+ public ToolDescriptor Describe() => new() { Name = "graphics.light-probe-group", Summary = "Read, create, or set one LightProbeGroup's probe positions.", Description = "Dedicated LightProbeGroup Tool for Edit and Play mode. Resolve one target, set create=true to add the object/component when missing, and pass positions as space-separated x,y,z vectors to replace the array. Success re-resolves the component and returns fresh target identity, probe count, and positions.", Group = "graphics",DestructiveHint = false, SideEffects = new[] { "scene-modify" }, Target = "editor", PlayModeSupport = "supported", DefaultTimeoutMs = 30000, MaxTimeoutMs = 600000, Examples = new[] { new ToolExample { Description = "Read light probe positions", Input = new Request { Target = "LightProbes" } }, new ToolExample { Description = "Set two light probe positions", Input = new Request { Target = "LightProbes", Positions = "0,0,0 0,2,0" } } } };
16
16
  public System.Threading.Tasks.ValueTask<Result> ExecuteAsync(Request r, UnityCliProjectToolContext ctx, System.Threading.CancellationToken ct = default)
17
17
  {
18
18
  var createdObject = string.IsNullOrEmpty(r.Target);
@@ -43,7 +43,13 @@ namespace UnityCli
43
43
  var observedProbe = observedObject.GetComponent<LightProbeGroup>();
44
44
  var observedPositions = observedProbe == null ? null : observedProbe.probePositions;
45
45
  if (observedProbe == null || (positions != null && !SamePositions(observedPositions, positions))) throw new UnityCliBridge.BridgeCommandException("E_LIGHT_PROBE_GROUP_STATE_MISMATCH", "LightProbeGroup probe positions did not retain the request.", "Retry after the editor is idle.");
46
- return new System.Threading.Tasks.ValueTask<Result>(new Result { ProbeCount = observedPositions == null ? 0 : observedPositions.Length, PlannedEffects = effects });
46
+ return new System.Threading.Tasks.ValueTask<Result>(new Result
47
+ {
48
+ Target = GraphicsToolSupport.BuildProbeTarget(observedObject),
49
+ ProbeCount = observedPositions == null ? 0 : observedPositions.Length,
50
+ Positions = GraphicsToolSupport.BuildProbePositions(observedPositions),
51
+ PlannedEffects = effects
52
+ });
47
53
  }
48
54
  private static bool SamePositions(Vector3[] actual, Vector3[] expected)
49
55
  {
@@ -12,7 +12,7 @@ namespace UnityCli
12
12
  {
13
13
  public sealed class Request { }
14
14
  public sealed class Result { public GraphicsSummary Graphics { get; set; } public QualitySettingsInfo QualitySettings { get; set; } }
15
- public ToolDescriptor Describe() => new() { Name = "graphics.pipeline-info", Summary = "Read the active render pipeline asset and quality settings.", Description = "Read-only: returns render pipeline summary and current QualitySettings.", Group = "graphics",DestructiveHint = false, Target = "editor", PlayModeSupport = "supported", DefaultTimeoutMs = 30000, MaxTimeoutMs = 600000, Examples = new[] { new ToolExample { Description = "Read pipeline info", Input = new Request { } } } };
15
+ public ToolDescriptor Describe() => new() { Name = "graphics.pipeline-info", Summary = "Read active/default render pipeline identity and current quality settings.", Description = "Read-only in Edit and Play mode. Returns the active/default render pipeline identity plus current QualitySettings; use graphics.pipeline-settings for default pipeline writes and graphics.quality for quality writes.", Group = "graphics",DestructiveHint = false, Target = "editor", PlayModeSupport = "supported", DefaultTimeoutMs = 30000, MaxTimeoutMs = 600000, Examples = new[] { new ToolExample { Description = "Read pipeline info", Input = new Request { } } } };
16
16
  public System.Threading.Tasks.ValueTask<Result> ExecuteAsync(Request r, UnityCliProjectToolContext ctx, System.Threading.CancellationToken ct = default) => new System.Threading.Tasks.ValueTask<Result>(new Result { Graphics = GraphicsToolSupport.BuildGraphicsSummary(), QualitySettings = GraphicsToolSupport.BuildQualitySettings() });
17
17
  }
18
18
  }
@@ -13,7 +13,7 @@ namespace UnityCli
13
13
  {
14
14
  public sealed class Request { public string RenderPipeline { get; set; } }
15
15
  public sealed class Result { public GraphicsSummary Graphics { get; set; } public List<GraphicsPlannedEffect> PlannedEffects { get; set; } }
16
- public ToolDescriptor Describe() => new() { Name = "graphics.pipeline-settings", Summary = "Set the default render pipeline asset for the project.", Description = "Set GraphicsSettings.defaultRenderPipeline. Pass 'built-in' or 'null' to reset to built-in.", Group = "graphics",DestructiveHint = true, SideEffects = new[] { "settings-write" }, Target = "editor", PlayModeSupport = "editor-only", DefaultTimeoutMs = 30000, MaxTimeoutMs = 600000, Examples = new[] { new ToolExample { Description = "Set URP pipeline", Input = new Request { RenderPipeline = "Assets/Settings/URP.asset" } } } };
16
+ public ToolDescriptor Describe() => new() { Name = "graphics.pipeline-settings", Summary = "Read or set the project's default render pipeline asset.", Description = "Dedicated GraphicsSettings.defaultRenderPipeline reader/writer for Edit and Play mode. Omit renderPipeline for a pure read; pass one imported Assets/*.asset RenderPipelineAsset, or built-in/null to reset. Success re-resolves the asset by path and GUID before returning the fresh pipeline summary; QualitySettings belong to graphics.quality.", Group = "graphics",DestructiveHint = true, SideEffects = new[] { "settings-write", "asset-import", "session-affecting" }, Target = "editor", PlayModeSupport = "session-affecting", DefaultTimeoutMs = 30000, MaxTimeoutMs = 600000, Examples = new[] { new ToolExample { Description = "Set URP pipeline", Input = new Request { RenderPipeline = "Assets/Settings/URP.asset" } } } };
17
17
  public System.Threading.Tasks.ValueTask<Result> ExecuteAsync(Request r, UnityCliProjectToolContext ctx, System.Threading.CancellationToken ct = default)
18
18
  {
19
19
  var effects = new List<GraphicsPlannedEffect>();
@@ -37,9 +37,9 @@ namespace UnityCli
37
37
  public ToolDescriptor Describe() => new()
38
38
  {
39
39
  Name = "graphics.quality", Summary = "Read and update Unity QualitySettings (quality level, vSync, anti-aliasing, shadows, LOD).",
40
- Description = "Read or update QualitySettings. Pass qualityLevel (name or index) and individual settings to update; omit all to read current values.",
40
+ Description = "Dedicated QualitySettings reader/writer for Edit and Play mode. Pass qualityLevel (name or index) and individual quality fields to update; omit every field for a pure read. Success returns a fresh QualitySettings snapshot and the applied effects; render-pipeline assignment belongs to graphics.pipeline-settings.",
41
41
  Group = "graphics",DestructiveHint = true, SideEffects = new[] { "settings-write" },
42
- Target = "editor", PlayModeSupport = "editor-only",
42
+ Target = "editor", PlayModeSupport = "session-affecting",
43
43
  DefaultTimeoutMs = 30000, MaxTimeoutMs = 600000,
44
44
  Examples = new[] { new ToolExample { Description = "Read quality settings", Input = new Request { } } }
45
45
  };
@@ -12,8 +12,8 @@ namespace UnityCli
12
12
  public class GraphicsReflectionProbeTool : IUnityCliTool<GraphicsReflectionProbeTool.Request, GraphicsReflectionProbeTool.Result>
13
13
  {
14
14
  public sealed class Request { public string Target { get; set; } public bool? Create { get; set; } public string Mode { get; set; } public int? Resolution { get; set; } public int? Bounces { get; set; } public bool? Hdr { get; set; } public string BoxSize { get; set; } public string BoxOffset { get; set; } }
15
- public sealed class Result { public ReflectionProbeInfo Probe { get; set; } public List<GraphicsPlannedEffect> PlannedEffects { get; set; } }
16
- public ToolDescriptor Describe() => new() { Name = "graphics.reflection-probe", Summary = "Add, configure, or read a ReflectionProbe component on a target.", Description = "Resolve a target GameObject, optionally create a ReflectionProbe, and configure mode/resolution/bounces/hdr/boxSize/boxOffset.", Group = "graphics",DestructiveHint = false, SideEffects = new[] { "scene-modify" }, Target = "editor", PlayModeSupport = "supported", DefaultTimeoutMs = 30000, MaxTimeoutMs = 600000, Examples = new[] { new ToolExample { Description = "Read reflection probe", Input = new Request { Target = "ReflectionProbe" } } } };
15
+ public sealed class Result { public GraphicsProbeTarget Target { get; set; } public ReflectionProbeInfo Probe { get; set; } public List<GraphicsPlannedEffect> PlannedEffects { get; set; } }
16
+ public ToolDescriptor Describe() => new() { Name = "graphics.reflection-probe", Summary = "Read, create, or configure one ReflectionProbe component.", Description = "Dedicated ReflectionProbe Tool for Edit and Play mode. Resolve one target, set create=true to add the object/component when missing, and configure mode, resolution, bounces, hdr, boxSize, or boxOffset. Success re-resolves the component and returns fresh target identity and probe state.", Group = "graphics",DestructiveHint = false, SideEffects = new[] { "scene-modify" }, Target = "editor", PlayModeSupport = "supported", DefaultTimeoutMs = 30000, MaxTimeoutMs = 600000, Examples = new[] { new ToolExample { Description = "Read reflection probe", Input = new Request { Target = "ReflectionProbe" } } } };
17
17
  public System.Threading.Tasks.ValueTask<Result> ExecuteAsync(Request r, UnityCliProjectToolContext ctx, System.Threading.CancellationToken ct = default)
18
18
  {
19
19
  var createdObject = string.IsNullOrEmpty(r.Target);
@@ -58,7 +58,7 @@ namespace UnityCli
58
58
  if (observedProbe == null) throw new UnityCliBridge.BridgeCommandException("E_REFLECTION_PROBE_STATE_MISMATCH", "ReflectionProbe could not be read after mutation.", "Retry after the editor is idle.");
59
59
  var observed = GraphicsToolSupport.BuildReflectionProbeInfo(observedProbe);
60
60
  if ((hasMode && observedProbe.mode != mode) || (r.Resolution.HasValue && observedProbe.resolution != r.Resolution.Value) || (r.Bounces.HasValue && observed.Bounces != r.Bounces.Value) || (r.Hdr.HasValue && observedProbe.hdr != r.Hdr.Value) || (boxSize.HasValue && observedProbe.size != boxSize.Value) || (boxOffset.HasValue && observedProbe.center != boxOffset.Value)) throw new UnityCliBridge.BridgeCommandException("E_REFLECTION_PROBE_STATE_MISMATCH", "ReflectionProbe readback did not match the request.", "Retry after the editor is idle.");
61
- return new System.Threading.Tasks.ValueTask<Result>(new Result { Probe = observed, PlannedEffects = effects });
61
+ return new System.Threading.Tasks.ValueTask<Result>(new Result { Target = GraphicsToolSupport.BuildProbeTarget(observedObject), Probe = observed, PlannedEffects = effects });
62
62
  }
63
63
  private static void SetBounces(ReflectionProbe p, int v)
64
64
  {
@@ -10,7 +10,7 @@ namespace UnityCli
10
10
  {
11
11
  public sealed class Request { }
12
12
  public sealed class Result { public RenderStatsInfo Stats { get; set; } }
13
- public ToolDescriptor Describe() => new() { Name = "graphics.stats", Summary = "Read current render statistics (draw calls, batches, triangles, vertices, memory).", Description = "Read-only: returns a unified render stats snapshot from RenderStats (Unity 6) or UnityStats (2022.3).", Group = "graphics",DestructiveHint = false, Target = "editor", PlayModeSupport = "supported", DefaultTimeoutMs = 30000, MaxTimeoutMs = 600000, Examples = new[] { new ToolExample { Description = "Read render stats", Input = new Request { } } } };
13
+ public ToolDescriptor Describe() => new() { Name = "graphics.stats", Summary = "Read one unified render counter and memory snapshot.", Description = "Read-only in Edit and Play mode. Returns one bounded snapshot containing draw calls, batches, set-pass calls, triangles, vertices, screen resolution, texture/render-texture memory, and vertex-buffer memory from RenderStats (Unity 6) or UnityStats (2022.3).", Group = "graphics",DestructiveHint = false, Target = "editor", PlayModeSupport = "supported", DefaultTimeoutMs = 30000, MaxTimeoutMs = 600000, Examples = new[] { new ToolExample { Description = "Read render stats", Input = new Request { } } } };
14
14
  public System.Threading.Tasks.ValueTask<Result> ExecuteAsync(Request r, UnityCliProjectToolContext ctx, System.Threading.CancellationToken ct = default) => new System.Threading.Tasks.ValueTask<Result>(new Result { Stats = GraphicsToolSupport.BuildRenderStats() });
15
15
  }
16
16
  }
@@ -49,8 +49,8 @@ namespace UnityCli
49
49
  {
50
50
  var options = new UnityCliBridge.ObjectSerializer.Options
51
51
  {
52
- MaxDepth = request.MaxDepth ?? 4,
53
- MaxArrayItems = System.Math.Max(0, System.Math.Min(request.MaxArrayItems ?? 50, 1000)),
52
+ MaxDepth = request.MaxDepth ?? UnityCliBridge.ObjectSerializer.DefaultMaxDepth,
53
+ MaxArrayItems = request.MaxArrayItems ?? UnityCliBridge.ObjectSerializer.DefaultMaxArrayItems,
54
54
  IncludeFields = request.IncludeFields ?? true,
55
55
  IncludeProperties = request.IncludeProperties ?? true,
56
56
  DeepSerialization = request.DeepSerialization ?? true
@@ -61,7 +61,7 @@ namespace UnityCli
61
61
  }
62
62
  if (request.Paths != null)
63
63
  {
64
- options.Paths = new HashSet<string>(request.Paths.Where(path => !string.IsNullOrWhiteSpace(path)).Select(path => path.Trim()));
64
+ options.Paths = request.Paths.Where(path => !string.IsNullOrWhiteSpace(path)).Select(path => path.Trim()).ToList();
65
65
  }
66
66
  var query = request.ViewQuery as Dictionary<string, object>;
67
67
  if (query != null)
@@ -72,7 +72,7 @@ namespace UnityCli
72
72
  object maxDepth;
73
73
  if (query.TryGetValue("maxDepth", out maxDepth) && maxDepth != null)
74
74
  {
75
- options.MaxDepth = System.Math.Max(0, System.Convert.ToInt32(maxDepth, CultureInfo.InvariantCulture));
75
+ options.MaxDepth = UnityCliBridge.ObjectSerializer.ParseMaxDepth(maxDepth);
76
76
  }
77
77
  }
78
78
  if (!string.IsNullOrEmpty(request.NamePattern))
@@ -17,17 +17,18 @@ namespace UnityCli
17
17
  public string Name { get; set; }
18
18
  public string Target { get; set; }
19
19
  public int? ComponentInstanceId { get; set; }
20
- public int? ComponentIndex { get; set; }
20
+ [UnityCliRange(0L, int.MaxValue)] public int? ComponentIndex { get; set; }
21
21
  public string Component { get; set; }
22
22
  public string ComponentType { get; set; }
23
- public int? MaxDepth { get; set; }
24
- public int? MaxArrayItems { get; set; }
23
+ [UnityCliRange(0L, 16L)] public int? MaxDepth { get; set; }
24
+ [UnityCliRange(1L, 1000L)] public int? MaxArrayItems { get; set; }
25
25
  public bool? IncludeFields { get; set; }
26
26
  public bool? IncludeProperties { get; set; }
27
27
  public bool? DeepSerialization { get; set; }
28
- public List<string> Paths { get; set; }
28
+ [UnityCliItemsRange(0, 128)] public List<string> Paths { get; set; }
29
29
  [UnityCliAnyJson] public object ViewQuery { get; set; }
30
30
  public string NamePattern { get; set; }
31
+ public UnityCliReadBudgetInput Budget { get; set; }
31
32
  }
32
33
 
33
34
  public sealed class Result
@@ -40,7 +41,7 @@ namespace UnityCli
40
41
  {
41
42
  Name = "object.get-data",
42
43
  Summary = "Read deep serialized data from any Unity Object by instanceId, assetPath, guid or path.",
43
- Description = "Read deep serialized data from any UnityEngine.Object. Resolves the target by instanceId, assetPath/guid, or path/name. Supports maxDepth, maxArrayItems, includeFields, includeProperties, deepSerialization, paths (exact member reads) and viewQuery (filtered subtree). Read-only.",
44
+ Description = "Read deep serialized data from any UnityEngine.Object. maxDepth is 0..16 and maxArrayItems is 1..1000. paths accepts at most 128 ordered exact reads; all paths and recursive branches share one budget (10000 scans, 4096 nodes, 2048 getters, 4096 reflection calls, 250 main-thread ms, 1 MiB UTF-8 by default; public maxima are 100000/20000/10000/20000/2000 ms/8 MiB). Truncated nodes return nextPath. Read-only in Edit and Play Mode.",
44
45
  Group = "object",
45
46
  DestructiveHint = false,
46
47
  Target = "editor",
@@ -55,9 +56,10 @@ namespace UnityCli
55
56
 
56
57
  public System.Threading.Tasks.ValueTask<Result> ExecuteAsync(Request request, UnityCliProjectToolContext ctx, System.Threading.CancellationToken ct = default)
57
58
  {
58
- var target = UnityCliBridge.ObjectRefResolver.ResolveObject(request);
59
+ var budget = ctx.UseReadBudget(request.Budget);
60
+ var target = UnityCliBridge.ObjectRefResolver.ResolveObject(request, budget);
59
61
  var options = ObjectToolSupport.BuildSerializerOptions(request);
60
- var data = UnityCliBridge.ObjectSerializer.Serialize(target, options);
62
+ var data = UnityCliBridge.ObjectSerializer.Serialize(target, options, budget);
61
63
  return new System.Threading.Tasks.ValueTask<Result>(new Result
62
64
  {
63
65
  TypeName = target.GetType().FullName,
@@ -23,14 +23,15 @@ namespace UnityCli
23
23
  public string Component { get; set; }
24
24
  public string ComponentType { get; set; }
25
25
  [UnityCliAnyJson] public List<object> PathPatches { get; set; }
26
- public int? MaxDepth { get; set; }
27
- public int? MaxArrayItems { get; set; }
26
+ [UnityCliRange(0L, 16L)] public int? MaxDepth { get; set; }
27
+ [UnityCliRange(1L, 1000L)] public int? MaxArrayItems { get; set; }
28
28
  public bool? IncludeFields { get; set; }
29
29
  public bool? IncludeProperties { get; set; }
30
30
  public bool? DeepSerialization { get; set; }
31
- public List<string> Paths { get; set; }
31
+ [UnityCliItemsRange(0, 128)] public List<string> Paths { get; set; }
32
32
  [UnityCliAnyJson] public object ViewQuery { get; set; }
33
33
  public string NamePattern { get; set; }
34
+ public UnityCliReadBudgetInput Budget { get; set; }
34
35
  }
35
36
 
36
37
  public sealed class Result
@@ -71,7 +72,8 @@ namespace UnityCli
71
72
  public System.Threading.Tasks.ValueTask<Result> ExecuteAsync(Request request, UnityCliProjectToolContext ctx, System.Threading.CancellationToken ct = default)
72
73
  {
73
74
  ObjectToolSupport.EnsureEditorNotBusy("object.modify");
74
- var target = UnityCliBridge.ObjectRefResolver.ResolveObject(request);
75
+ var readBudget = ctx.UseReadBudget(request.Budget);
76
+ var target = UnityCliBridge.ObjectRefResolver.ResolveObject(request, readBudget);
75
77
  if (EditorApplication.isPlaying && EditorUtility.IsPersistent(target))
76
78
  {
77
79
  throw new UnityCliBridge.BridgeCommandException("E_TOOL_PLAYMODE_UNAVAILABLE", "object.modify cannot modify persistent assets during Play Mode.", "Target a scene object or exit Play Mode before modifying an asset.");
@@ -112,7 +114,7 @@ namespace UnityCli
112
114
  if (observedTarget == null) throw new UnityCliBridge.BridgeCommandException("E_OBJECT_MODIFY_STATE_MISMATCH", "Target could not be fresh-resolved after patch.", "Retry after the Editor is idle.");
113
115
  UnityCliBridge.ObjectPatch.VerifyFreshSerializedProperties(observedTarget, request.PathPatches);
114
116
  var options = ObjectToolSupport.BuildSerializerOptions(request);
115
- var updatedData = UnityCliBridge.ObjectSerializer.Serialize(observedTarget, options);
117
+ var updatedData = UnityCliBridge.ObjectSerializer.Serialize(observedTarget, options, readBudget);
116
118
 
117
119
  return new System.Threading.Tasks.ValueTask<Result>(new Result
118
120
  {