@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
@@ -59,16 +59,23 @@ namespace UnityCli
59
59
 
60
60
  var result = ExecuteCodeSource(request, source, cancellationToken);
61
61
  WriteLog("code_exec requestId=" + request.RequestId + " ok=" + result.Ok + " exitState=" + result.ExitState);
62
- object envelope = result.Ok
63
- ? (object)UnityCli.Protocol.ProtocolEnvelopeFactory.Success(request.RequestId, result.Data)
64
- : UnityCli.Protocol.ProtocolEnvelopeFactory.Error(request.RequestId, result.ErrorCode, BoundedText(result.ErrorMessage, 4096), result.Details, result.NextActions);
65
- var serialized = UnityCliSerializer.Serialize(envelope);
66
- if (Encoding.UTF8.GetByteCount(serialized) > MaxCodeTerminalBytes)
67
- return UnityCliSerializer.Serialize(UnityCli.Protocol.ProtocolEnvelopeFactory.Error(request.RequestId, "E_EXECUTION_TIMEOUT", "Runtime Code completed, but its bounded terminal could not be represented safely.", null, new[] { "Inspect the affected business state before submitting another mutation." }));
62
+ var serialized = SerializeCodeExecutionResult(request.RequestId, result);
68
63
  if (result.Ok) RecordDirectCompletionEvidence(request.RequestId, "code.exec", ResolveRequestCompletionContract(request), result.Data);
69
64
  return serialized;
70
65
  }
71
66
 
67
+ /// <summary>所有 code.exec terminal 统一经过同一 Bridge envelope 与总 byte 上限。</summary>
68
+ private static string SerializeCodeExecutionResult(string requestId, CodeExecutionResult result)
69
+ {
70
+ object envelope = result.Ok
71
+ ? (object)UnityCli.Protocol.ProtocolEnvelopeFactory.Success(requestId, result.Data)
72
+ : UnityCli.Protocol.ProtocolEnvelopeFactory.Error(requestId, result.ErrorCode, BoundedText(result.ErrorMessage, 4096), result.Details, result.NextActions);
73
+ var serialized = UnityCliSerializer.Serialize(envelope);
74
+ return Encoding.UTF8.GetByteCount(serialized) <= MaxCodeTerminalBytes
75
+ ? serialized
76
+ : UnityCliSerializer.Serialize(UnityCli.Protocol.ProtocolEnvelopeFactory.Error(requestId, "E_EXECUTION_TIMEOUT", "Runtime Code completed, but its bounded terminal could not be represented safely.", null, new[] { "Inspect the affected business state before submitting another mutation." }));
77
+ }
78
+
72
79
  // 编译源码并执行约定的 Run 方法,收集编译诊断、输出和运行时异常。
73
80
  private static CodeExecutionResult ExecuteCodeSource(UnityCli.Protocol.BridgeRequest request, string source, CancellationToken cancellationToken)
74
81
  {
@@ -101,7 +108,7 @@ namespace UnityCli
101
108
  }
102
109
  catch (Exception exception)
103
110
  {
104
- return CodeExecutionResult.Fail("E_REFERENCE_RESOLUTION_FAILED", "Failed to compile Runtime Code: " + exception.Message, ExceptionDetails(exception, "", ""), "Check Unity/Editor/project assembly references and --refs.");
111
+ return ExceptionFailure("E_REFERENCE_RESOLUTION_FAILED", "Failed to compile Runtime Code: ", exception, "", "", "Check Unity/Editor/project assembly references and --refs.");
105
112
  }
106
113
 
107
114
  var compiledAssembly = Assembly.Load(assemblyBytes);
@@ -182,10 +189,10 @@ namespace UnityCli
182
189
  {
183
190
  if (ReferenceEquals(exception, effectBarrierException)
184
191
  || ReferenceEquals(exception, completionProbeException)) throw;
185
- return CodeExecutionResult.Fail("E_CODE_RUNTIME_EXCEPTION", BoundedText(exception.Message, 4096), ExceptionDetails(exception, stdout.ToString(), stderr.ToString()), "Inspect the bounded runtime exception and affected business state.");
192
+ return ExceptionFailure("E_CODE_RUNTIME_EXCEPTION", string.Empty, exception, stdout.ToString(), stderr.ToString(), "Inspect the bounded runtime exception cause chain and affected business state.");
186
193
  }
187
194
  try { return CodeExecutionResult.Success(CodeSuccessData(stdout.ToString(), stderr.ToString(), stdout.Truncated, stderr.Truncated, returnValue, completion)); }
188
- catch (Exception exception) { return CodeExecutionResult.Fail("E_CODE_RUNTIME_EXCEPTION", BoundedText(exception.Message, 4096), ExceptionDetails(exception, stdout.ToString(), stderr.ToString()), "Inspect the bounded return-value conversion failure and affected business state."); }
195
+ catch (Exception exception) { return ExceptionFailure("E_CODE_RUNTIME_EXCEPTION", string.Empty, exception, stdout.ToString(), stderr.ToString(), "Inspect the bounded return-value conversion cause chain and affected business state."); }
189
196
  }
190
197
 
191
198
  /// <summary>caller effect紧前同时重验immutable deadline、cancel token与exact direct lease。</summary>
@@ -531,13 +538,21 @@ namespace UnityCli
531
538
  };
532
539
  }
533
540
 
534
- // 构造包含诊断、输出和堆栈的运行时异常详情。
535
- private static Dictionary<string, object> ExceptionDetails(Exception exception, string stdout, string stderr)
541
+ /// <summary>错误 code 保持稳定,公开 message 与兼容字段统一指向最深可操作 cause。</summary>
542
+ private static CodeExecutionResult ExceptionFailure(string code, string prefix, Exception exception, string stdout, string stderr, string nextAction)
543
+ {
544
+ var projection = UnityCliExceptionProjection.Project(exception);
545
+ return CodeExecutionResult.Fail(code, prefix + projection.PublicMessage, ExceptionDetails(projection, stdout, stderr), nextAction);
546
+ }
547
+
548
+ // cause chain 由 Shared helper 统一执行循环、深度和 UTF-8 byte 上限。
549
+ private static Dictionary<string, object> ExceptionDetails(UnityCliExceptionProjection.Result projection, string stdout, string stderr)
536
550
  {
537
551
  return new Dictionary<string, object>
538
552
  {
539
- { "diagnostics", Array.Empty<object>() }, { "exceptionType", BoundedText(exception.GetType().FullName, 512) },
540
- { "message", BoundedText(exception.Message, 4096) }, { "stackTrace", BoundedText(exception.StackTrace, 16384) },
553
+ { "diagnostics", Array.Empty<object>() }, { "exceptionType", projection.DeepestExceptionType },
554
+ { "message", projection.DeepestMessage }, { "stackTrace", projection.DeepestStackTrace },
555
+ { "causes", projection.Causes }, { "causeChainTruncated", projection.Truncated },
541
556
  { "stdout", stdout }, { "stderr", stderr }
542
557
  };
543
558
  }
@@ -1,147 +1,174 @@
1
1
  #if UNITY_EDITOR
2
2
  using System;
3
- using System.Collections;
4
3
  using System.Collections.Generic;
5
- using System.IO;
4
+ using System.Linq;
6
5
  using System.Reflection;
7
- using UnityEngine;
8
6
 
9
7
  namespace UnityCli
10
8
  {
9
+ /// <summary>Tool name、extension id、assembly identity 与 implementation Type 的一次性编译身份。</summary>
10
+ internal sealed class RegistryToolOwnership
11
+ {
12
+ internal RegistryToolOwnership(string source, string extensionId, Assembly assembly, Type implementationType)
13
+ {
14
+ Source = source;
15
+ ExtensionId = extensionId;
16
+ Assembly = assembly ?? throw new ArgumentNullException("assembly");
17
+ AssemblyIdentity = assembly.GetName().FullName;
18
+ ImplementationType = implementationType ?? throw new ArgumentNullException("implementationType");
19
+ }
20
+
21
+ public string Source { get; }
22
+ public string ExtensionId { get; }
23
+ public Assembly Assembly { get; }
24
+ public string AssemblyIdentity { get; }
25
+ public Type ImplementationType { get; }
26
+ }
27
+
28
+ /// <summary>generated exact inventory 决定 Extension owner;名称前缀和项目 assembly 名称不参与冒充。</summary>
11
29
  internal sealed class RegistryOwnershipResolver
12
30
  {
13
- private readonly Dictionary<Type, string> extensionClaims;
31
+ private readonly HashSet<Assembly> candidateAssemblies;
32
+ private readonly Dictionary<Assembly, string> loadedExtensionAssemblies;
33
+ private readonly Dictionary<string, RegistryToolOwnership> actualPackageInventory = new Dictionary<string, RegistryToolOwnership>(StringComparer.Ordinal);
14
34
 
15
- private RegistryOwnershipResolver(Dictionary<Type, string> extensionClaims)
35
+ private RegistryOwnershipResolver(HashSet<Assembly> candidateAssemblies, Dictionary<Assembly, string> loadedExtensionAssemblies)
16
36
  {
17
- this.extensionClaims = extensionClaims;
37
+ this.candidateAssemblies = candidateAssemblies;
38
+ this.loadedExtensionAssemblies = loadedExtensionAssemblies;
18
39
  }
19
40
 
20
- /// <summary>只在已证明可能贡献Tool的程序集内解析Extension类型owner。</summary>
21
- public static RegistryOwnershipResolver Load(IEnumerable<Assembly> candidateAssemblies)
41
+ public static RegistryOwnershipResolver Load(IEnumerable<Assembly> candidates)
22
42
  {
23
- if (candidateAssemblies == null) throw new ArgumentNullException("candidateAssemblies");
24
- var claims = new Dictionary<string, string>(StringComparer.Ordinal);
25
- var packageRoot = Path.Combine(Directory.GetParent(Application.dataPath).FullName, "Packages", "com.alpsckr.unitycli");
26
- var extensionRoot = Path.Combine(packageRoot, "Extensions");
27
- var installedIds = ReadInstalledExtensionIds(Path.Combine(packageRoot, "unitycli.extensions.manifest.json"));
28
- if (!Directory.Exists(extensionRoot))
43
+ if (candidates == null) throw new ArgumentNullException("candidates");
44
+ var assemblies = new HashSet<Assembly>(candidates.Where(assembly => assembly != null));
45
+ var bridgeAssembly = typeof(UnityCliBridge).Assembly;
46
+ if (assemblies.Count == 0 || !assemblies.Contains(bridgeAssembly))
47
+ throw new InvalidOperationException("Tool provider metadata does not contain the UnityCLI Editor assembly.");
48
+
49
+ var expectedExtensions = InventoryEntries()
50
+ .Where(entry => entry.DescriptorOwner.StartsWith("extension:", StringComparison.Ordinal))
51
+ .GroupBy(entry => entry.DescriptorOwner.Substring("extension:".Length), StringComparer.Ordinal)
52
+ .ToDictionary(
53
+ group => group.Key,
54
+ group => group.Select(entry => entry.AssemblyName).Distinct(StringComparer.Ordinal).ToArray(),
55
+ StringComparer.Ordinal);
56
+ foreach (var expected in expectedExtensions)
29
57
  {
30
- if (installedIds.Count > 0) throw new InvalidOperationException("Extension registry has installed entries but no Extensions directory.");
31
- return new RegistryOwnershipResolver(new Dictionary<Type, string>());
58
+ if (string.IsNullOrWhiteSpace(expected.Key) || expected.Value.Length != 1 || string.IsNullOrWhiteSpace(expected.Value[0]))
59
+ throw new InvalidOperationException("Generated Extension inventory must map each extension id to one exact assembly identity: " + expected.Key + ".");
32
60
  }
33
61
 
34
- var manifestIds = new HashSet<string>(StringComparer.Ordinal);
35
- foreach (var manifestPath in Directory.GetFiles(extensionRoot, "extension.json", SearchOption.AllDirectories))
62
+ var loadedExtensions = new Dictionary<Assembly, string>();
63
+ var loadedExtensionIds = new HashSet<string>(StringComparer.Ordinal);
64
+ foreach (var assembly in assemblies)
36
65
  {
37
- IDictionary<string, object> manifest;
38
- try
39
- {
40
- manifest = UnityCliSerializer.Parse(File.ReadAllText(manifestPath)) as IDictionary<string, object>;
41
- }
42
- catch (Exception exception)
66
+ var markers = assembly.GetCustomAttributes(typeof(UnityCliExtensionAssemblyAttribute), false)
67
+ .Cast<UnityCliExtensionAssemblyAttribute>()
68
+ .ToArray();
69
+ if (markers.Length > 1)
70
+ throw new InvalidOperationException("Compiled assembly declares multiple UnityCLI Extension owners: " + assembly.GetName().Name + ".");
71
+ if (markers.Length == 0)
43
72
  {
44
- throw new InvalidOperationException("Extension registry manifest is unreadable: " + manifestPath, exception);
73
+ if (expectedExtensions.Any(pair => string.Equals(pair.Value[0], assembly.GetName().Name, StringComparison.Ordinal)))
74
+ throw new InvalidOperationException("Generated Extension assembly is loaded without its exact UnityCliExtensionAssembly marker: " + assembly.GetName().Name + ".");
75
+ continue;
45
76
  }
46
- if (manifest == null) throw new InvalidOperationException("Extension registry manifest must be a JSON object: " + manifestPath);
77
+ if (assembly == bridgeAssembly)
78
+ throw new InvalidOperationException("The UnityCLI Editor assembly cannot declare an Extension owner.");
47
79
 
48
- var extensionId = StringValue(manifest, "id");
49
- var contributions = ObjectValue(manifest, "contributions");
50
- var entries = contributions == null ? null : ArrayValue(contributions, "csharpEntries");
51
- if (string.IsNullOrWhiteSpace(extensionId) || entries == null)
52
- {
53
- throw new InvalidOperationException("Extension registry manifest has no id or contributions.csharpEntries: " + manifestPath);
54
- }
55
- if (!manifestIds.Add(extensionId)) throw new InvalidOperationException("Duplicate extension registry manifest id: " + extensionId);
56
- if (!installedIds.Contains(extensionId)) throw new InvalidOperationException("Extension manifest is not claimed by the install manifest: " + extensionId);
57
-
58
- foreach (var value in entries)
59
- {
60
- var entry = value as IDictionary<string, object>;
61
- var typeName = entry == null ? null : StringValue(entry, "type");
62
- if (string.IsNullOrWhiteSpace(typeName)) throw new InvalidOperationException("Extension registry contains an empty C# type claim: " + manifestPath);
63
- string owner;
64
- if (claims.TryGetValue(typeName, out owner) && !string.Equals(owner, extensionId, StringComparison.Ordinal))
65
- {
66
- throw new InvalidOperationException("Extension registry type claim conflict for " + typeName + ": " + owner + " and " + extensionId + ".");
67
- }
68
- claims[typeName] = extensionId;
69
- }
80
+ var extensionId = markers[0].ExtensionId;
81
+ string[] expectedAssemblyNames;
82
+ if (string.IsNullOrWhiteSpace(extensionId) || !expectedExtensions.TryGetValue(extensionId, out expectedAssemblyNames))
83
+ throw new InvalidOperationException("Compiled assembly declares an unknown UnityCLI Extension owner: " + extensionId + ".");
84
+ if (!string.Equals(expectedAssemblyNames[0], assembly.GetName().Name, StringComparison.Ordinal))
85
+ throw new InvalidOperationException("Extension assembly marker does not match generated exact assembly identity: " + extensionId + ".");
86
+ if (!loadedExtensionIds.Add(extensionId))
87
+ throw new InvalidOperationException("Multiple compiled assemblies declare the same UnityCLI Extension owner: " + extensionId + ".");
88
+ loadedExtensions.Add(assembly, extensionId);
70
89
  }
90
+ return new RegistryOwnershipResolver(assemblies, loadedExtensions);
91
+ }
92
+
93
+ /// <summary>每个 package Tool 在注册前绑定 generated owner、exact assembly 与 compiled Type。</summary>
94
+ public RegistryToolOwnership Resolve(Type implementationType, string toolName)
95
+ {
96
+ if (implementationType == null) throw new ArgumentNullException("implementationType");
97
+ if (string.IsNullOrWhiteSpace(toolName)) throw new ArgumentException("Tool name is required.", "toolName");
98
+ var assembly = implementationType.Assembly;
99
+ if (!candidateAssemblies.Contains(assembly))
100
+ throw new InvalidOperationException("Tool implementation assembly is outside the provider metadata set: " + implementationType.FullName + ".");
71
101
 
72
- foreach (var extensionId in installedIds)
102
+ UnityCliToolInventoryEntry expected;
103
+ if (!UnityCliToolCompletionRegistry.TryGetInventory(toolName, out expected))
73
104
  {
74
- if (!manifestIds.Contains(extensionId)) throw new InvalidOperationException("Extension install manifest has an orphan entry: " + extensionId);
105
+ if (assembly == typeof(UnityCliBridge).Assembly || loadedExtensionAssemblies.ContainsKey(assembly))
106
+ throw new InvalidOperationException("Package Tool has no generated exact inventory entry: " + toolName + ".");
107
+ return new RegistryToolOwnership("project", null, assembly, implementationType);
75
108
  }
76
109
 
77
- var loadedTypes = new Dictionary<string, List<Type>>(StringComparer.Ordinal);
78
- foreach (var assembly in candidateAssemblies)
110
+ if (string.IsNullOrWhiteSpace(expected.AssemblyName) || string.IsNullOrWhiteSpace(expected.ImplementationType)
111
+ || !string.Equals(expected.AssemblyName, assembly.GetName().Name, StringComparison.Ordinal)
112
+ || !string.Equals(expected.ImplementationType, implementationType.FullName, StringComparison.Ordinal))
113
+ throw new InvalidOperationException("Tool owner does not match the generated exact assembly identity and implementation type: " + toolName + ".");
114
+
115
+ RegistryToolOwnership ownership;
116
+ if (string.Equals(expected.DescriptorOwner, "built-in", StringComparison.Ordinal))
79
117
  {
80
- Type[] types;
81
- try { types = assembly.GetTypes(); }
82
- catch (ReflectionTypeLoadException exception) { throw new InvalidOperationException("Unable to inspect every type in Tool provider assembly " + assembly.FullName + ".", exception); }
83
- catch (Exception exception) { throw new InvalidOperationException("Unable to inspect Tool provider assembly " + assembly.FullName + ".", exception); }
84
- foreach (var type in types)
85
- {
86
- if (type == null || type.FullName == null) continue;
87
- List<Type> matches;
88
- if (!loadedTypes.TryGetValue(type.FullName, out matches)) loadedTypes[type.FullName] = matches = new List<Type>();
89
- matches.Add(type);
90
- }
118
+ if (assembly != typeof(UnityCliBridge).Assembly)
119
+ throw new InvalidOperationException("Built-in Tool owner does not match its exact compiled assembly: " + toolName + ".");
120
+ ownership = new RegistryToolOwnership("built-in", null, assembly, implementationType);
91
121
  }
92
-
93
- var resolvedClaims = new Dictionary<Type, string>();
94
- foreach (var claim in claims)
122
+ else if (expected.DescriptorOwner.StartsWith("extension:", StringComparison.Ordinal))
95
123
  {
96
- List<Type> matches;
97
- if (!loadedTypes.TryGetValue(claim.Key, out matches)) throw new InvalidOperationException("Extension registry has an orphan C# type claim: " + claim.Key + " (" + claim.Value + ").");
98
- if (matches.Count != 1) throw new InvalidOperationException("Extension registry C# type claim is ambiguous: " + claim.Key + " (" + claim.Value + ").");
99
- resolvedClaims.Add(matches[0], claim.Value);
124
+ var extensionId = expected.DescriptorOwner.Substring("extension:".Length);
125
+ string loadedExtensionId;
126
+ if (!loadedExtensionAssemblies.TryGetValue(assembly, out loadedExtensionId)
127
+ || !string.Equals(loadedExtensionId, extensionId, StringComparison.Ordinal))
128
+ throw new InvalidOperationException("Extension Tool owner does not match its generated extension and exact compiled assembly: " + toolName + ".");
129
+ ownership = new RegistryToolOwnership("extension", extensionId, assembly, implementationType);
100
130
  }
101
- return new RegistryOwnershipResolver(resolvedClaims);
102
- }
103
-
104
- public string Resolve(Type implementationType)
105
- {
106
- if (implementationType == null) throw new ArgumentNullException("implementationType");
107
- string extensionId;
108
- if (extensionClaims.TryGetValue(implementationType, out extensionId)) return "extension";
109
- return implementationType.Assembly == typeof(UnityCliBridge).Assembly ? "built-in" : "project";
110
- }
111
-
112
- private static HashSet<string> ReadInstalledExtensionIds(string path)
113
- {
114
- var result = new HashSet<string>(StringComparer.Ordinal);
115
- if (!File.Exists(path)) return result;
116
- var manifest = UnityCliSerializer.Parse(File.ReadAllText(path)) as IDictionary<string, object>;
117
- var entries = manifest == null ? null : ArrayValue(manifest, "extensions");
118
- if (entries == null) throw new InvalidOperationException("Extension install manifest is invalid: " + path);
119
- foreach (var value in entries)
131
+ else
120
132
  {
121
- var entry = value as IDictionary<string, object>;
122
- var extensionId = entry == null ? null : StringValue(entry, "extensionId");
123
- if (string.IsNullOrWhiteSpace(extensionId) || !result.Add(extensionId))
124
- throw new InvalidOperationException("Extension install manifest contains an invalid or duplicate entry: " + path);
133
+ throw new InvalidOperationException("Live package Tool has a non-package generated owner: " + toolName + ".");
125
134
  }
126
- return result;
127
- }
128
135
 
129
- private static string StringValue(IDictionary<string, object> value, string key)
130
- {
131
- object result;
132
- return value.TryGetValue(key, out result) ? result as string : null;
136
+ if (actualPackageInventory.ContainsKey(toolName))
137
+ throw new InvalidOperationException("Generated Tool inventory contains duplicate actual implementation: " + toolName + ".");
138
+ actualPackageInventory.Add(toolName, ownership);
139
+ return ownership;
133
140
  }
134
141
 
135
- private static IDictionary<string, object> ObjectValue(IDictionary<string, object> value, string key)
142
+ /// <summary>publication 前按已加载 compiled assembly 验证 expected/actual 全集,缺项、多项和跨 Extension 全部失败。</summary>
143
+ public void ValidateComplete()
136
144
  {
137
- object result;
138
- return value.TryGetValue(key, out result) ? result as IDictionary<string, object> : null;
145
+ var bridgeAssemblyName = typeof(UnityCliBridge).Assembly.GetName().Name;
146
+ var expected = InventoryEntries()
147
+ .Where(entry => string.Equals(entry.AssemblyName, bridgeAssemblyName, StringComparison.Ordinal)
148
+ || loadedExtensionAssemblies.Any(pair => string.Equals(pair.Key.GetName().Name, entry.AssemblyName, StringComparison.Ordinal)
149
+ && string.Equals(pair.Value, entry.DescriptorOwner.StartsWith("extension:", StringComparison.Ordinal) ? entry.DescriptorOwner.Substring("extension:".Length) : string.Empty, StringComparison.Ordinal)))
150
+ .ToDictionary(entry => entry.ToolName, entry => entry, StringComparer.Ordinal);
151
+
152
+ var missing = expected.Keys.Where(name => !actualPackageInventory.ContainsKey(name)).OrderBy(name => name, StringComparer.Ordinal).ToArray();
153
+ var extra = actualPackageInventory.Keys.Where(name => !expected.ContainsKey(name)).OrderBy(name => name, StringComparer.Ordinal).ToArray();
154
+ if (missing.Length > 0 || extra.Length > 0)
155
+ throw new InvalidOperationException("Generated Tool inventory expected/actual set mismatch; missing=" + string.Join(",", missing) + "; extra=" + string.Join(",", extra) + ".");
156
+
157
+ foreach (var pair in expected)
158
+ {
159
+ var actual = actualPackageInventory[pair.Key];
160
+ var expectedOwner = pair.Value.DescriptorOwner;
161
+ var actualOwner = actual.Source == "extension" ? "extension:" + actual.ExtensionId : actual.Source;
162
+ if (!string.Equals(expectedOwner, actualOwner, StringComparison.Ordinal)
163
+ || !string.Equals(pair.Value.AssemblyName, actual.Assembly.GetName().Name, StringComparison.Ordinal)
164
+ || !string.Equals(pair.Value.ImplementationType, actual.ImplementationType.FullName, StringComparison.Ordinal))
165
+ throw new InvalidOperationException("Generated Tool inventory actual identity differs from expected identity: " + pair.Key + ".");
166
+ }
139
167
  }
140
168
 
141
- private static IEnumerable ArrayValue(IDictionary<string, object> value, string key)
169
+ private static IEnumerable<UnityCliToolInventoryEntry> InventoryEntries()
142
170
  {
143
- object result;
144
- return value.TryGetValue(key, out result) ? result as IEnumerable : null;
171
+ return UnityCliToolCompletionRegistry.InventoryEntries();
145
172
  }
146
173
  }
147
174
  }