@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
@@ -1,10 +1,7 @@
1
1
  #if UNITY_EDITOR
2
2
  using System;
3
3
  using System.Collections.Generic;
4
- using System.Globalization;
5
4
  using System.IO;
6
- using System.Linq;
7
- using System.Text;
8
5
  using System.Threading;
9
6
  using System.Threading.Tasks;
10
7
  using UnityEditor;
@@ -14,7 +11,7 @@ namespace UnityCli
14
11
  {
15
12
  public static partial class UnityCliBridge
16
13
  {
17
- /// <summary>editor.refresh 的单 scope 进行中操作协调器(统一骨架收编)。</summary>
14
+ /// <summary>editor.refresh 的单 scope durable operation;proof 只使用 Unity-owned artifact generations。</summary>
18
15
  internal static class UnityCliLiveRefreshCoordinator
19
16
  {
20
17
  private static readonly Coordinator Instance = new Coordinator();
@@ -24,7 +21,7 @@ namespace UnityCli
24
21
  internal static Task<string> Execute(BridgeRequest request, byte[] raw, Func<bool> accept, CancellationToken ct) { return Instance.Execute(request, raw, accept, ct); }
25
22
  internal static void Initialize() { }
26
23
  internal static void Shutdown() { }
27
- internal static void BeforeReload() { Instance.Update(x => x["reloadObserved"] = true); }
24
+ internal static void BeforeReload() { Instance.Update(root => root["reloadObserved"] = true); }
28
25
  internal static void Tick() { Instance.Tick(); }
29
26
 
30
27
  private sealed class Coordinator : UnityCliReloadOperation
@@ -34,9 +31,10 @@ namespace UnityCli
34
31
  protected override string StatusCommand { get { return "internal.editor.refresh.status"; } }
35
32
  protected override string OperationDisplayName { get { return "Refresh"; } }
36
33
  protected override bool IncludeAcceptedInStatus { get { return true; } }
37
- protected override string SessionChangedMessage { get { return "Refresh result cannot be confirmed after the Editor session changed; check the business state."; } }
38
- protected override string DeadlineMessage { get { return "Refresh did not reach a confirmed terminal state before the deadline; check the business state."; } }
34
+ protected override string SessionChangedMessage { get { return "Refresh result cannot be confirmed after the Editor session changed; inspect editor.state and asset state."; } }
35
+ protected override string DeadlineMessage { get { return "Refresh did not reach a confirmed terminal state before the shared deadline; inspect editor.state and asset state."; } }
39
36
  protected override object DeserializeStartArgs(BridgeRequest request) { return request.DeserializeArgs<Args>(); }
37
+
40
38
  protected override void ValidateStart(object value)
41
39
  {
42
40
  var args = (Args)value;
@@ -44,37 +42,39 @@ namespace UnityCli
44
42
  if (!string.Equals(args.ExpectedEditorSessionId, EditorSessionId(), StringComparison.Ordinal)) throw new BridgeCommandException("E_EDITOR_SESSION_REPLACED", "The selected Editor session changed before refresh execution.");
45
43
  if (EditorApplication.isPlaying || IsPlayModeChanging()) throw new BridgeCommandException("E_TOOL_PLAYMODE_UNAVAILABLE", "editor.refresh is editor-only and requires stable Edit Mode.");
46
44
  }
45
+
47
46
  protected override void ValidateLoadedRoot(Dictionary<string, object> root)
48
47
  {
49
- ValidateRootContract(root, new[] { "compile", "compilationRequested", "compilationObserved", "compilePhase", "compileDispatchSequence", "compileStartedSequence", "compileFinishedSequence", "compileStartedCycle", "compileDiagnostics", "compileErrorCount", "compileWarningCount", "compileInfoCount", "compileDiagnosticsTruncated", "stableFrames", "beforeSourceFingerprint", "beforeDependencyVersion", "reloadObserved", "rootContractDigest" },
50
- "queued", "prepared", "dispatching", "refresh_returned", "waiting_stable");
48
+ ValidateRootContract(root, new[]
49
+ {
50
+ "compile", "compilationRequested", "compilationObserved", "compilePhase", "compileDispatchSequence", "compileStartedSequence", "compileFinishedSequence", "compileStartedCycle",
51
+ "compileDiagnostics", "compileErrorCount", "compileWarningCount", "compileInfoCount", "compileDiagnosticsTruncated", "stableFrames",
52
+ "beforeDependencyGeneration", "beforeProcessedGeneration", "importObserved", "reloadObserved", "rootContractDigest"
53
+ }, "queued", "prepared", "dispatching", "refresh_returned", "waiting_stable");
51
54
  object compile; object requested; object observed; object diagnostics; object errorCount; object warningCount; object infoCount; object truncated; object stableFrames;
52
55
  if (!root.TryGetValue("compile", out compile) || !(compile is bool)
53
56
  || !root.TryGetValue("compilationRequested", out requested) || !(requested is bool)
54
57
  || !root.TryGetValue("compilationObserved", out observed) || !(observed is bool)
55
58
  || !root.TryGetValue("compileDiagnostics", out diagnostics) || !(diagnostics is List<object>)
56
- || !root.TryGetValue("compileErrorCount", out errorCount) || !(errorCount is long) || (long)errorCount < 0 || (long)errorCount > 1000000
57
- || !root.TryGetValue("compileWarningCount", out warningCount) || !(warningCount is long) || (long)warningCount < 0 || (long)warningCount > 1000000
58
- || !root.TryGetValue("compileInfoCount", out infoCount) || !(infoCount is long) || (long)infoCount < 0 || (long)infoCount > 1000000
59
- || !root.TryGetValue("compileDiagnosticsTruncated", out truncated) || !(truncated is long) || (long)truncated < 0 || (long)truncated > 1000000
60
- || !root.TryGetValue("stableFrames", out stableFrames) || !(stableFrames is long) || (long)stableFrames < 0
61
- || !IsSha256(Text(root, "beforeSourceFingerprint")) || !IsSha256(Text(root, "beforeDependencyVersion")))
59
+ || !root.TryGetValue("compileErrorCount", out errorCount) || !(errorCount is long) || (long)errorCount < 0L || (long)errorCount > 1000000L
60
+ || !root.TryGetValue("compileWarningCount", out warningCount) || !(warningCount is long) || (long)warningCount < 0L || (long)warningCount > 1000000L
61
+ || !root.TryGetValue("compileInfoCount", out infoCount) || !(infoCount is long) || (long)infoCount < 0L || (long)infoCount > 1000000L
62
+ || !root.TryGetValue("compileDiagnosticsTruncated", out truncated) || !(truncated is long) || (long)truncated < 0L || (long)truncated > 1000000L
63
+ || !root.TryGetValue("stableFrames", out stableFrames) || !(stableFrames is long) || (long)stableFrames < 0L
64
+ || !(root["beforeDependencyGeneration"] is long) || (long)root["beforeDependencyGeneration"] < 0L
65
+ || !(root["beforeProcessedGeneration"] is long) || (long)root["beforeProcessedGeneration"] < 0L
66
+ || !(root["importObserved"] is bool))
62
67
  throw new InvalidDataException("Refresh active root fields are invalid.");
63
- if (!string.Equals(Text(root, "rootContractDigest"), RefreshRootContractDigest(root), StringComparison.Ordinal))
64
- throw new InvalidDataException("Refresh immutable root contract changed.");
68
+ if (!string.Equals(Text(root, "rootContractDigest"), RefreshRootContractDigest(root), StringComparison.Ordinal)) throw new InvalidDataException("Refresh immutable root contract changed.");
65
69
  UnityCliCompileCoordinator.ValidateBoundedDiagnostics(root, "compileDiagnostics", "compileErrorCount", "compileWarningCount", "compileInfoCount", "compileDiagnosticsTruncated", true);
66
70
  var compilePhase = Text(root, "compilePhase");
67
- if (Array.IndexOf(new[] { "idle", "dispatching", "awaiting_started", "compiling", "cycle_finished" }, compilePhase) < 0)
68
- throw new InvalidDataException("Refresh compile phase is invalid.");
71
+ if (Array.IndexOf(new[] { "idle", "dispatching", "awaiting_started", "compiling", "cycle_finished" }, compilePhase) < 0) throw new InvalidDataException("Refresh compile phase is invalid.");
69
72
  var refreshFenced = HasExactEffectFence("refresh", root, "refresh-dispatch");
70
73
  var phase = Text(root, "phase");
71
- if ((phase == "queued" || phase == "prepared") == refreshFenced)
72
- throw new InvalidDataException("Refresh effect fence is inconsistent with phase.");
74
+ if ((phase == "queued" || phase == "prepared") == refreshFenced) throw new InvalidDataException("Refresh effect fence is inconsistent with phase.");
73
75
  var compileFenced = HasExactEffectFence("refresh", root, "compile-dispatch");
74
- if ((compilePhase == "idle") == compileFenced)
75
- throw new InvalidDataException("Refresh compile fence is inconsistent with phase.");
76
- if (Bool(root, "compilationObserved")
77
- && (Long(root, "compileStartedCycle") <= 0 || Long(root, "compileStartedSequence") <= Long(root, "compileDispatchSequence")))
76
+ if ((compilePhase == "idle") == compileFenced) throw new InvalidDataException("Refresh compile fence is inconsistent with phase.");
77
+ if (Bool(root, "compilationObserved") && (Long(root, "compileStartedCycle") <= 0L || Long(root, "compileStartedSequence") <= Long(root, "compileDispatchSequence")))
78
78
  throw new InvalidDataException("Refresh compile attribution is invalid.");
79
79
  }
80
80
 
@@ -82,7 +82,7 @@ namespace UnityCli
82
82
  {
83
83
  return UnityCliSerializer.Sha256Canonical(new Dictionary<string, object>
84
84
  {
85
- { "compile", root["compile"] }, { "beforeSourceFingerprint", root["beforeSourceFingerprint"] }, { "beforeDependencyVersion", root["beforeDependencyVersion"] }
85
+ { "compile", root["compile"] }, { "beforeDependencyGeneration", root["beforeDependencyGeneration"] }, { "beforeProcessedGeneration", root["beforeProcessedGeneration"] }
86
86
  });
87
87
  }
88
88
 
@@ -93,69 +93,103 @@ namespace UnityCli
93
93
  if (args.Compile) effects.Add(new Dictionary<string, object> { { "type", "script-compile" } });
94
94
  return new Dictionary<string, object> { { "dryRun", true }, { "plannedEffects", effects } };
95
95
  }
96
+
96
97
  protected override Dictionary<string, object> CreateRoot(BridgeRequest request, string digest, object value)
97
98
  {
98
99
  var args = (Args)value;
99
100
  var before = CaptureProof();
100
- var root = new Dictionary<string, object> { { "requestId", request.RequestId }, { "editorSessionId", EditorSessionId() }, { "requestDigest", digest }, { "deadline", request.Execution.AbsoluteDeadlineUtc }, { "phase", "queued" }, { "compile", args.Compile }, { "compilationRequested", false }, { "compilationObserved", false }, { "compilePhase", "idle" }, { "compileDispatchSequence", 0L }, { "compileStartedSequence", 0L }, { "compileFinishedSequence", 0L }, { "compileStartedCycle", 0L }, { "compileDiagnostics", new List<object>() }, { "compileErrorCount", 0L }, { "compileWarningCount", 0L }, { "compileInfoCount", 0L }, { "compileDiagnosticsTruncated", 0L }, { "stableFrames", 0L }, { "beforeSourceFingerprint", before.SourceFingerprint }, { "beforeDependencyVersion", before.DependencyVersion } };
101
+ var root = new Dictionary<string, object>
102
+ {
103
+ { "requestId", request.RequestId }, { "editorSessionId", EditorSessionId() }, { "requestDigest", digest }, { "deadline", request.Execution.AbsoluteDeadlineUtc },
104
+ { "phase", "queued" }, { "compile", args.Compile }, { "compilationRequested", false }, { "compilationObserved", false }, { "compilePhase", "idle" },
105
+ { "compileDispatchSequence", 0L }, { "compileStartedSequence", 0L }, { "compileFinishedSequence", 0L }, { "compileStartedCycle", 0L },
106
+ { "compileDiagnostics", new List<object>() }, { "compileErrorCount", 0L }, { "compileWarningCount", 0L }, { "compileInfoCount", 0L }, { "compileDiagnosticsTruncated", 0L },
107
+ { "stableFrames", 0L }, { "beforeDependencyGeneration", before.DependencyGeneration }, { "beforeProcessedGeneration", before.ProcessedGeneration },
108
+ { "importObserved", false }, { "reloadObserved", false }
109
+ };
101
110
  root["rootContractDigest"] = RefreshRootContractDigest(root);
102
111
  return root;
103
112
  }
113
+
104
114
  protected override void OnTick(Dictionary<string, object> root)
105
115
  {
106
116
  if (UnityCliCompilationEventBroker.SequenceCorrupt && Bool(root, "compile")) { Fail(root, "E_EXECUTION_TIMEOUT", "Refresh compilation event sequence is corrupt; attributed outcome is unknown."); return; }
107
117
  var phase = Text(root, "phase");
108
- if (phase == "queued") { if (BusyEditor()) return; Update(x => x["phase"] = "prepared"); return; }
109
- if (phase == "prepared") { root = CrossEffectFence(root, "refresh-dispatch", "dispatching"); try { AssetDatabase.Refresh(); Update(x => x["phase"] = "refresh_returned"); } catch (Exception e) { Fail(root, "E_EXECUTION_TIMEOUT", "Refresh result cannot be confirmed: " + e.Message + "; check the business state."); } return; }
118
+ if (phase != "queued" && phase != "prepared") ObserveImport(root);
119
+ if (phase == "queued") { if (BusyEditor()) return; Update(value => value["phase"] = "prepared"); return; }
120
+ if (phase == "prepared")
121
+ {
122
+ root = CrossEffectFence(root, "refresh-dispatch", "dispatching");
123
+ try { AssetDatabase.Refresh(); Update(value => value["phase"] = "refresh_returned"); }
124
+ catch (Exception exception) { Fail(root, "E_EXECUTION_TIMEOUT", "Refresh result cannot be confirmed: " + exception.Message + "; inspect asset state."); }
125
+ return;
126
+ }
110
127
  if (phase == "refresh_returned")
111
128
  {
112
- if (Bool(root, "compile") && !Bool(root, "compilationObserved") && !Bool(root, "compilationRequested")) { if (BusyEditor()) return; UnityCliCompileCoordinator.RequestRefreshCompilation(Text(root, "requestId"), Text(root, "requestDigest")); return; }
113
- Update(x => x["phase"] = "waiting_stable"); return;
129
+ if (Bool(root, "compile") && !Bool(root, "compilationObserved") && !Bool(root, "compilationRequested"))
130
+ {
131
+ if (BusyEditor()) return;
132
+ UnityCliCompileCoordinator.RequestRefreshCompilation(Text(root, "requestId"), Text(root, "requestDigest"));
133
+ return;
134
+ }
135
+ Update(value => value["phase"] = "waiting_stable");
136
+ return;
114
137
  }
115
138
  if (phase != "waiting_stable" || BusyEditor()) return;
116
- if (Bool(root, "compile") && (!Bool(root, "compilationObserved") || Text(root, "compilePhase") != "cycle_finished")) { Fail(root, "E_EXECUTION_TIMEOUT", "Refresh compilation result cannot be confirmed; check the business state."); return; }
117
- if (Long(root, "compileErrorCount") > 0)
139
+ if (Bool(root, "compile") && (!Bool(root, "compilationObserved") || Text(root, "compilePhase") != "cycle_finished"))
140
+ {
141
+ Fail(root, "E_EXECUTION_TIMEOUT", "Refresh compilation result cannot be confirmed; inspect editor.state and compile diagnostics.");
142
+ return;
143
+ }
144
+ if (Long(root, "compileErrorCount") > 0L)
118
145
  {
119
146
  var details = new Dictionary<string, object>
120
147
  {
121
148
  { "compile", new Dictionary<string, object> { { "completed", true }, { "errorCount", Long(root, "compileErrorCount") }, { "warningCount", Long(root, "compileWarningCount") }, { "status", "errors" }, { "diagnosticsTruncated", Long(root, "compileDiagnosticsTruncated") } } },
122
149
  { "diagnostics", root["compileDiagnostics"] }
123
150
  };
124
- Fail(root, "E_UNITY_COMPILE_FAILED", "Refresh compilation reported compiler errors.", details, new[] { "Fix the listed compiler diagnostics before retrying refresh." }); return;
151
+ Fail(root, "E_UNITY_COMPILE_FAILED", "Refresh compilation reported compiler errors.", details, new[] { "Fix the listed compiler diagnostics before retrying refresh." });
152
+ return;
125
153
  }
126
- var frames = Long(root, "stableFrames") + 1; Update(x => x["stableFrames"] = frames); if (frames >= 3) Succeed(root);
154
+ var frames = Long(root, "stableFrames") + 1L;
155
+ Update(value => value["stableFrames"] = frames);
156
+ if (frames >= 3L) Succeed(root);
127
157
  }
158
+
128
159
  protected override object BuildSuccessData(Dictionary<string, object> root)
129
160
  {
130
161
  var after = CaptureProof();
131
- var changed = !Same(Text(root, "beforeSourceFingerprint"), after.SourceFingerprint) || !Same(Text(root, "beforeDependencyVersion"), after.DependencyVersion);
162
+ var changed = Long(root, "beforeDependencyGeneration") != after.DependencyGeneration || Long(root, "beforeProcessedGeneration") != after.ProcessedGeneration;
132
163
  return new Dictionary<string, object>
133
164
  {
134
- { "changed", changed }, { "compilationTriggered", Bool(root, "compilationObserved") },
135
- { "sourceFileCount", (long)after.Paths.Count }, { "sourceFingerprint", after.SourceFingerprint }, { "dependencyVersion", after.DependencyVersion },
165
+ { "changed", changed }, { "importObserved", Bool(root, "importObserved") || changed }, { "compilationTriggered", Bool(root, "compilationObserved") },
166
+ { "generation", new Dictionary<string, object> { { "dependencyBefore", Long(root, "beforeDependencyGeneration") }, { "dependencyAfter", after.DependencyGeneration }, { "processedBefore", Long(root, "beforeProcessedGeneration") }, { "processedAfter", after.ProcessedGeneration } } },
136
167
  { "editorState", new Dictionary<string, object> { { "status", "ready" }, { "compile", false }, { "import", false } } }
137
168
  };
138
169
  }
139
- private sealed class Proof { internal List<string> Paths; internal string SourceFingerprint; internal string DependencyVersion; }
140
- /// <summary>Refresh 的业务证明:Assets 全量文件指纹 + AssetDatabase 依赖哈希版本。</summary>
170
+
171
+ private void ObserveImport(Dictionary<string, object> root)
172
+ {
173
+ if (Bool(root, "importObserved")) return;
174
+ var current = CaptureProof();
175
+ if (!EditorApplication.isUpdating && Long(root, "beforeDependencyGeneration") == current.DependencyGeneration && Long(root, "beforeProcessedGeneration") == current.ProcessedGeneration) return;
176
+ root["importObserved"] = true;
177
+ Update(value => value["importObserved"] = true);
178
+ }
179
+
180
+ private sealed class Proof { internal long DependencyGeneration; internal long ProcessedGeneration; }
181
+
182
+ /// <summary>O(1) Unity-owned generation proof;不读取 Assets 文件,不计算 per-file dependency hash。</summary>
141
183
  private static Proof CaptureProof()
142
184
  {
143
- var rootPath = Path.Combine(ProjectRoot(), "Assets");
144
- var files = Directory.Exists(rootPath) ? Directory.GetFiles(rootPath, "*", SearchOption.AllDirectories).OrderBy(path => path, StringComparer.Ordinal).ToArray() : new string[0];
145
- var lines = new List<string>(); var paths = new List<string>(); var dependencies = new List<string>();
146
- foreach (var file in files)
185
+ return new Proof
147
186
  {
148
- var relative = "Assets/" + Path.GetRelativePath(rootPath, file).Replace('\\', '/');
149
- var info = new FileInfo(file);
150
- paths.Add(relative);
151
- lines.Add(relative + "\0" + info.Length.ToString(CultureInfo.InvariantCulture) + "\0" + info.LastWriteTimeUtc.Ticks.ToString(CultureInfo.InvariantCulture) + "\0" + HashFile(file));
152
- if (!relative.EndsWith(".meta", StringComparison.OrdinalIgnoreCase)) dependencies.Add(relative + "\0" + AssetDatabase.GetAssetDependencyHash(relative).ToString());
153
- }
154
- return new Proof { Paths = paths, SourceFingerprint = Sha256Hex(Encoding.UTF8.GetBytes(string.Join("\n", lines))), DependencyVersion = Sha256Hex(Encoding.UTF8.GetBytes(string.Join("\n", dependencies))) };
187
+ DependencyGeneration = Math.Max(0L, (long)AssetDatabase.GlobalArtifactDependencyVersion),
188
+ ProcessedGeneration = Math.Max(0L, (long)AssetDatabase.GlobalArtifactProcessedVersion)
189
+ };
155
190
  }
156
- private static string HashFile(string path) { using (var sha = System.Security.Cryptography.SHA256.Create()) using (var stream = File.OpenRead(path)) return BitConverter.ToString(sha.ComputeHash(stream)).Replace("-", "").ToLowerInvariant(); }
191
+
157
192
  private static bool BusyEditor() { return EditorApplication.isUpdating || EditorApplication.isCompiling || BuildPipeline.isBuildingPlayer || IsPlayModeChanging(); }
158
- private static bool Same(string left, string right) { return !string.IsNullOrEmpty(left) && string.Equals(left, right, StringComparison.Ordinal); }
159
193
  private sealed class Args { public bool Compile { get; set; } public string ExpectedEditorSessionId { get; set; } }
160
194
  }
161
195
  }
@@ -77,13 +77,13 @@ namespace UnityCli
77
77
  protected override string OperationDisplayName { get { return "NavMesh bake"; } }
78
78
  protected override int CommandTimeoutMs { get { return 600000; } }
79
79
  protected override bool IncludeAcceptedInStatus { get { return true; } }
80
- protected override IEnumerable<(string name, bool destructive)> AdditionalCommands
80
+ protected override IEnumerable<(string name, bool destructive, UnityCliBridgeQueuePolicy.WorkClass queueClass)> AdditionalCommands
81
81
  {
82
82
  get
83
83
  {
84
- yield return (PlanCommand, false);
85
- yield return (SnapshotCommand, false);
86
- yield return (CancelCommand, true);
84
+ yield return (PlanCommand, false, UnityCliBridgeQueuePolicy.WorkClass.Mutation);
85
+ yield return (SnapshotCommand, false, UnityCliBridgeQueuePolicy.WorkClass.OrdinaryRead);
86
+ yield return (CancelCommand, true, UnityCliBridgeQueuePolicy.WorkClass.Control);
87
87
  }
88
88
  }
89
89
 
@@ -2,8 +2,6 @@
2
2
  using System;
3
3
  using System.Collections.Generic;
4
4
  using System.Globalization;
5
- using System.Linq;
6
- using System.Reflection;
7
5
  using UnityEditor;
8
6
  using UnityEngine;
9
7
  using UnityEngine.SceneManagement;
@@ -34,6 +32,7 @@ namespace UnityCli
34
32
  List<string> Paths { get; }
35
33
  object ViewQuery { get; }
36
34
  string NamePattern { get; }
35
+ UnityCliReadBudgetInput Budget { get; }
37
36
  }
38
37
 
39
38
  public static partial class UnityCliBridge
@@ -45,13 +44,21 @@ namespace UnityCli
45
44
  /// </summary>
46
45
  internal static class ObjectRefResolver
47
46
  {
47
+ internal const int AbsoluteMaxBatchItems = 4096;
48
+ private const int MaximumRootSnapshotItems = AbsoluteMaxBatchItems;
49
+ private const int MaximumComponentSnapshotItems = AbsoluteMaxBatchItems;
50
+ private const int MaximumRootSnapshotGenerations = 64;
51
+ private static readonly Dictionary<string, GameObject[]> RootSnapshots = new Dictionary<string, GameObject[]>(StringComparer.Ordinal);
52
+
48
53
  /// <summary>解析任意 UnityEngine.Object 引用。</summary>
49
- public static UnityEngine.Object ResolveObject(IUnityCliObjectReferenceInput request)
54
+ public static UnityEngine.Object ResolveObject(IUnityCliObjectReferenceInput request, UnityCliRequestBudget budget)
50
55
  {
51
- // 优先级:instanceId > assetPath/guid > name(path)
56
+ if (budget == null) throw new ArgumentNullException("budget");
57
+ // 优先级:instanceId > assetPath/guid > exact hierarchy path/name
52
58
  var instanceId = request.InstanceId;
53
59
  if (instanceId.HasValue && instanceId.Value != 0)
54
60
  {
61
+ if (!budget.TryConsumeGetter()) throw new UnityCliRequestBudgetExceededException(budget.ExhaustedDimension);
55
62
  var obj = EditorUtility.InstanceIDToObject(instanceId.Value);
56
63
  if (obj == null)
57
64
  {
@@ -66,11 +73,13 @@ namespace UnityCli
66
73
  var guid = request.Guid;
67
74
  if (!string.IsNullOrEmpty(guid))
68
75
  {
76
+ if (!budget.TryConsumeGetter()) throw new UnityCliRequestBudgetExceededException(budget.ExhaustedDimension);
69
77
  var pathByGuid = AssetDatabase.GUIDToAssetPath(guid);
70
78
  if (!string.IsNullOrEmpty(pathByGuid)) assetPath = pathByGuid;
71
79
  }
72
80
  if (!string.IsNullOrEmpty(assetPath))
73
81
  {
82
+ if (!budget.TryConsumeGetter()) throw new UnityCliRequestBudgetExceededException(budget.ExhaustedDimension);
74
83
  var asset = AssetDatabase.LoadMainAssetAtPath(assetPath);
75
84
  if (asset == null)
76
85
  {
@@ -81,19 +90,11 @@ namespace UnityCli
81
90
  return asset;
82
91
  }
83
92
 
84
- // 名称/路径解析:优先在活动场景中找 GameObject,再回退资产
85
93
  var path = request.Path ?? request.Name ?? request.Target;
86
94
  if (!string.IsNullOrEmpty(path))
87
95
  {
88
- var go = FindGameObjectByPath(path);
89
- if (go != null) return go;
90
-
91
- var assetByName = AssetDatabase.FindAssets(path);
92
- if (assetByName != null && assetByName.Length > 0)
93
- {
94
- var resolved = AssetDatabase.LoadMainAssetAtPath(AssetDatabase.GUIDToAssetPath(assetByName[0]));
95
- if (resolved != null) return resolved;
96
- }
96
+ var gameObject = FindGameObjectByExactPath(path, budget);
97
+ if (gameObject != null) return gameObject;
97
98
  }
98
99
 
99
100
  throw new BridgeCommandException("E_OBJECTREF_REQUIRED",
@@ -102,11 +103,13 @@ namespace UnityCli
102
103
  }
103
104
 
104
105
  /// <summary>解析 GameObject 引用。</summary>
105
- public static GameObject ResolveGameObject(IUnityCliObjectReferenceInput request)
106
+ public static GameObject ResolveGameObject(IUnityCliObjectReferenceInput request, UnityCliRequestBudget budget)
106
107
  {
108
+ if (budget == null) throw new ArgumentNullException("budget");
107
109
  var instanceId = request.InstanceId;
108
110
  if (instanceId.HasValue && instanceId.Value != 0)
109
111
  {
112
+ if (!budget.TryConsumeGetter()) throw new UnityCliRequestBudgetExceededException(budget.ExhaustedDimension);
110
113
  var obj = EditorUtility.InstanceIDToObject(instanceId.Value) as GameObject;
111
114
  if (obj == null)
112
115
  {
@@ -120,7 +123,7 @@ namespace UnityCli
120
123
  var path = request.Path ?? request.Target ?? request.Name;
121
124
  if (!string.IsNullOrEmpty(path))
122
125
  {
123
- var go = FindGameObjectByPath(path);
126
+ var go = FindGameObjectByExactPath(path, budget);
124
127
  if (go != null) return go;
125
128
  throw new BridgeCommandException("E_OBJECTREF_GAMEOBJECT_REQUIRED",
126
129
  "No GameObject matched path/name '" + path + "' in any loaded scene.",
@@ -138,11 +141,13 @@ namespace UnityCli
138
141
  /// 2) GameObject + component index
139
142
  /// 3) GameObject + component typeName
140
143
  /// </summary>
141
- public static Component ResolveComponent(IUnityCliObjectReferenceInput request)
144
+ public static Component ResolveComponent(IUnityCliObjectReferenceInput request, UnityCliRequestBudget budget)
142
145
  {
146
+ if (budget == null) throw new ArgumentNullException("budget");
143
147
  var componentInstanceId = request.ComponentInstanceId;
144
148
  if (componentInstanceId.HasValue && componentInstanceId.Value != 0)
145
149
  {
150
+ if (!budget.TryConsumeGetter()) throw new UnityCliRequestBudgetExceededException(budget.ExhaustedDimension);
146
151
  var obj = EditorUtility.InstanceIDToObject(componentInstanceId.Value) as Component;
147
152
  if (obj == null)
148
153
  {
@@ -153,11 +158,11 @@ namespace UnityCli
153
158
  return obj;
154
159
  }
155
160
 
156
- var gameObject = ResolveGameObject(request);
161
+ var gameObject = ResolveGameObject(request, budget);
157
162
  var componentIndex = request.ComponentIndex;
158
163
  if (componentIndex.HasValue)
159
164
  {
160
- var components = gameObject.GetComponents<Component>();
165
+ var components = BoundedComponents(gameObject, budget);
161
166
  if (componentIndex.Value < 0 || componentIndex.Value >= components.Length)
162
167
  {
163
168
  throw new BridgeCommandException("E_OBJECTREF_COMPONENT_INDEX_OUT_OF_RANGE",
@@ -170,7 +175,8 @@ namespace UnityCli
170
175
  var componentType = request.Component ?? request.ComponentType;
171
176
  if (!string.IsNullOrEmpty(componentType))
172
177
  {
173
- var type = ResolveComponentType(componentType);
178
+ var type = GameObjectToolSupport.ResolveComponentType(componentType, budget);
179
+ if (!budget.TryConsumeGetter()) throw new UnityCliRequestBudgetExceededException(budget.ExhaustedDimension);
174
180
  var component = gameObject.GetComponent(type);
175
181
  if (component == null)
176
182
  {
@@ -186,6 +192,99 @@ namespace UnityCli
186
192
  "Run component.get --input '{\"instanceId\":123,\"component\":\"Transform\"}'.");
187
193
  }
188
194
 
195
+ /// <summary>按完整大小写敏感路径直接逐段解析;不会在失败时扫描整棵层级树。</summary>
196
+ public static GameObject FindGameObjectByExactPath(string path, UnityCliRequestBudget budget)
197
+ {
198
+ if (string.IsNullOrEmpty(path)) return null;
199
+ if (budget == null) throw new ArgumentNullException("budget");
200
+ if (path.Length > 8192) throw new BridgeCommandException("E_OBJECTREF_PATH_INVALID", "Exact hierarchy paths are limited to 8192 characters.", "Pass a shorter full case-sensitive hierarchy path or an instance id.");
201
+ var segments = path.Split(new[] { '/' }, StringSplitOptions.RemoveEmptyEntries);
202
+ if (segments.Length == 0) return null;
203
+ if (segments.Length > 256) throw new BridgeCommandException("E_OBJECTREF_PATH_INVALID", "Exact hierarchy paths are limited to 256 segments.", "Pass an instance id for deeper objects.");
204
+ GameObject match = null;
205
+ if (!budget.TryConsumeGetter()) throw new UnityCliRequestBudgetExceededException(budget.ExhaustedDimension);
206
+ var sceneCount = SceneManager.sceneCount;
207
+ for (var sceneIndex = 0; sceneIndex < sceneCount; sceneIndex++)
208
+ {
209
+ if (!budget.TryConsumeGetter()) throw new UnityCliRequestBudgetExceededException(budget.ExhaustedDimension);
210
+ var scene = SceneManager.GetSceneAt(sceneIndex);
211
+ if (!budget.TryConsumeGetter()) throw new UnityCliRequestBudgetExceededException(budget.ExhaustedDimension);
212
+ if (!scene.isLoaded) continue;
213
+ foreach (var root in BoundedSceneRoots(scene, budget))
214
+ {
215
+ if (!budget.TryConsumeGetter()) throw new UnityCliRequestBudgetExceededException(budget.ExhaustedDimension);
216
+ if (!string.Equals(root.name, segments[0], StringComparison.Ordinal)) continue;
217
+ var current = root.transform;
218
+ var resolved = true;
219
+ for (var segmentIndex = 1; segmentIndex < segments.Length; segmentIndex++)
220
+ {
221
+ Transform childMatch = null;
222
+ if (!budget.TryConsumeGetter()) throw new UnityCliRequestBudgetExceededException(budget.ExhaustedDimension);
223
+ var childCount = current.childCount;
224
+ for (var childIndex = 0; childIndex < childCount; childIndex++)
225
+ {
226
+ if (!budget.TryConsumeScannedRecord() || !budget.TryConsumeGetter() || !budget.TryConsumeGetter()) throw new UnityCliRequestBudgetExceededException(budget.ExhaustedDimension);
227
+ var child = current.GetChild(childIndex);
228
+ if (!string.Equals(child.name, segments[segmentIndex], StringComparison.Ordinal)) continue;
229
+ if (childMatch != null) ThrowExactAmbiguousPath(path, childMatch.gameObject, child.gameObject, budget);
230
+ childMatch = child;
231
+ }
232
+ if (childMatch == null) { resolved = false; break; }
233
+ current = childMatch;
234
+ }
235
+ if (!resolved) continue;
236
+ if (match != null) ThrowExactAmbiguousPath(path, match, current.gameObject, budget);
237
+ match = current.gameObject;
238
+ }
239
+ }
240
+ return match;
241
+ }
242
+
243
+ /// <summary>批量根对象 getter 只在已验证 cardinality 后调用,并在同一层级 generation 复用有限快照。</summary>
244
+ internal static GameObject[] BoundedSceneRoots(Scene scene, UnityCliRequestBudget budget)
245
+ {
246
+ if (!budget.TryConsumeGetter()) throw new UnityCliRequestBudgetExceededException(budget.ExhaustedDimension);
247
+ var rootCount = scene.rootCount;
248
+ if (rootCount < 0 || rootCount > MaximumRootSnapshotItems || !budget.TryConsumeScannedRecords(rootCount))
249
+ throw new UnityCliRequestBudgetExceededException(rootCount > MaximumRootSnapshotItems ? "rootSnapshotItems" : budget.ExhaustedDimension);
250
+ if (!budget.TryConsumeGetter()) throw new UnityCliRequestBudgetExceededException(budget.ExhaustedDimension);
251
+ var generation = UnityCliReadGeneration.Hierarchy(scene);
252
+ GameObject[] cached;
253
+ if (RootSnapshots.TryGetValue(generation, out cached))
254
+ {
255
+ if (cached.Length != rootCount) throw new BridgeCommandException("E_READ_GENERATION_CHANGED", "Scene roots changed while resolving the exact path.", "Retry the read from the beginning.");
256
+ return cached;
257
+ }
258
+ if (!budget.TryConsumeGetter()) throw new UnityCliRequestBudgetExceededException(budget.ExhaustedDimension);
259
+ var roots = scene.GetRootGameObjects();
260
+ if (roots.Length != rootCount) throw new BridgeCommandException("E_READ_GENERATION_CHANGED", "Scene roots changed while building the bounded snapshot.", "Retry the read from the beginning.");
261
+ if (RootSnapshots.Count >= MaximumRootSnapshotGenerations) RootSnapshots.Clear();
262
+ RootSnapshots[generation] = roots;
263
+ return roots;
264
+ }
265
+
266
+ /// <summary>组件数组在 materialize 前验证数量并一次性占用扫描预算。</summary>
267
+ internal static Component[] BoundedComponents(GameObject gameObject, UnityCliRequestBudget budget)
268
+ {
269
+ if (!budget.TryConsumeGetter()) throw new UnityCliRequestBudgetExceededException(budget.ExhaustedDimension);
270
+ var componentCount = gameObject.GetComponentCount();
271
+ if (componentCount < 0 || componentCount > MaximumComponentSnapshotItems || !budget.TryConsumeScannedRecords(componentCount))
272
+ throw new UnityCliRequestBudgetExceededException(componentCount > MaximumComponentSnapshotItems ? "componentSnapshotItems" : budget.ExhaustedDimension);
273
+ if (!budget.TryConsumeGetter()) throw new UnityCliRequestBudgetExceededException(budget.ExhaustedDimension);
274
+ var components = gameObject.GetComponents<Component>();
275
+ if (components.Length != componentCount) throw new BridgeCommandException("E_READ_GENERATION_CHANGED", "GameObject components changed while building the bounded snapshot.", "Retry the read from the beginning.");
276
+ return components;
277
+ }
278
+
279
+ private static void ThrowExactAmbiguousPath(string path, GameObject first, GameObject second, UnityCliRequestBudget budget)
280
+ {
281
+ var firstPath = UnityCliHierarchyPager.Path(first, budget);
282
+ var secondPath = UnityCliHierarchyPager.Path(second, budget);
283
+ throw new BridgeCommandException("E_OBJECTREF_AMBIGUOUS",
284
+ "Path '" + path + "' matches multiple GameObjects: " + firstPath + ", " + secondPath,
285
+ "Pass the instanceId from go.find to disambiguate objects in different loaded scenes.");
286
+ }
287
+
189
288
  /// <summary>
190
289
  /// 按路径或名称查找 GameObject,分层匹配:
191
290
  /// 层1 精确匹配(从场景顶层起、大小写敏感)→ 层2 放宽匹配(任意层级起点、路径后缀、忽略大小写)。
@@ -263,11 +362,15 @@ namespace UnityCli
263
362
  // 多命中时抛歧义错误,列候选完整路径(从顶层起),不静默取错。
264
363
  private static void ThrowAmbiguousPath(string path, List<GameObject> matches)
265
364
  {
266
- var candidates = matches
267
- .Select(m => FullPath(m.transform))
268
- .Distinct()
269
- .Take(10)
270
- .ToList();
365
+ var candidates = new List<string>();
366
+ var seen = new HashSet<string>(StringComparer.Ordinal);
367
+ foreach (var match in matches)
368
+ {
369
+ var candidate = FullPath(match.transform);
370
+ if (!seen.Add(candidate)) continue;
371
+ candidates.Add(candidate);
372
+ if (candidates.Count == 10) break;
373
+ }
271
374
  throw new BridgeCommandException("E_OBJECTREF_AMBIGUOUS",
272
375
  "Path '" + path + "' matches " + matches.Count + " GameObjects: " + string.Join(", ", candidates),
273
376
  "Pass the full hierarchy path from a scene root, or use go.find to obtain the instanceId.");