@alpsckr/unitycli 0.4.3 → 0.4.5

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 (425) 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 +145 -39
  49. package/dist/bridge/session-supervisor.js.map +1 -1
  50. package/dist/bridge/start-diagnostics.d.ts +19 -0
  51. package/dist/bridge/start-diagnostics.js +96 -0
  52. package/dist/bridge/start-diagnostics.js.map +1 -0
  53. package/dist/bridge/types.d.ts +6 -5
  54. package/dist/bridge/types.js +16 -2
  55. package/dist/bridge/types.js.map +1 -1
  56. package/dist/catalog-protocol.d.ts +64 -0
  57. package/dist/catalog-protocol.js +460 -0
  58. package/dist/catalog-protocol.js.map +1 -0
  59. package/dist/cli-commands/command.js +84 -61
  60. package/dist/cli-commands/command.js.map +1 -1
  61. package/dist/cli-commands/extensions.js +70 -50
  62. package/dist/cli-commands/extensions.js.map +1 -1
  63. package/dist/cli-commands/instances.js +1 -1
  64. package/dist/cli-commands/instances.js.map +1 -1
  65. package/dist/cli-commands/package.js +10 -2
  66. package/dist/cli-commands/package.js.map +1 -1
  67. package/dist/cli-process-owners.d.ts +6 -0
  68. package/dist/cli-process-owners.js +27 -0
  69. package/dist/cli-process-owners.js.map +1 -0
  70. package/dist/cli.d.ts +1 -1
  71. package/dist/cli.js +20 -5
  72. package/dist/cli.js.map +1 -1
  73. package/dist/contracts/command-contract.js +14 -4
  74. package/dist/contracts/command-contract.js.map +1 -1
  75. package/dist/doctor.d.ts +4 -6
  76. package/dist/doctor.js +451 -398
  77. package/dist/doctor.js.map +1 -1
  78. package/dist/editor-blocker-observer.d.ts +2 -1
  79. package/dist/editor-blocker-observer.js +40 -13
  80. package/dist/editor-blocker-observer.js.map +1 -1
  81. package/dist/extension-availability.d.ts +27 -9
  82. package/dist/extension-availability.js +96 -56
  83. package/dist/extension-availability.js.map +1 -1
  84. package/dist/extensions/descriptor-loader.d.ts +2 -2
  85. package/dist/extensions/descriptor-loader.js +3 -4
  86. package/dist/extensions/descriptor-loader.js.map +1 -1
  87. package/dist/extensions/index.d.ts +1 -1
  88. package/dist/extensions/index.js +1 -1
  89. package/dist/extensions/index.js.map +1 -1
  90. package/dist/extensions/installer.d.ts +57 -5
  91. package/dist/extensions/installer.js +263 -64
  92. package/dist/extensions/installer.js.map +1 -1
  93. package/dist/extensions/registry.js +3 -5
  94. package/dist/extensions/registry.js.map +1 -1
  95. package/dist/extensions/state-contract.d.ts +11 -0
  96. package/dist/extensions/state-contract.js +50 -0
  97. package/dist/extensions/state-contract.js.map +1 -0
  98. package/dist/instances.d.ts +19 -1
  99. package/dist/instances.js +39 -0
  100. package/dist/instances.js.map +1 -1
  101. package/dist/package-manager.d.ts +0 -24
  102. package/dist/package-manager.js +5 -58
  103. package/dist/package-manager.js.map +1 -1
  104. package/dist/project-tool-discovery.d.ts +5 -2
  105. package/dist/project-tool-discovery.js +22 -18
  106. package/dist/project-tool-discovery.js.map +1 -1
  107. package/dist/runtime-code.js +1 -1
  108. package/dist/runtime-code.js.map +1 -1
  109. package/dist/tool-name.d.ts +4 -0
  110. package/dist/tool-name.js +15 -0
  111. package/dist/tool-name.js.map +1 -0
  112. package/dist/tools/.generated-completion-registry.d.ts +2 -0
  113. package/dist/tools/.generated-completion-registry.js +763 -325
  114. package/dist/tools/.generated-completion-registry.js.map +1 -1
  115. package/dist/tools/.generated-registry.d.ts +6 -11
  116. package/dist/tools/.generated-registry.js +6 -11
  117. package/dist/tools/.generated-registry.js.map +1 -1
  118. package/dist/tools/.generated-schemas.js +11 -16
  119. package/dist/tools/.generated-schemas.js.map +1 -1
  120. package/dist/tools/asset/refresh-status.d.ts +3 -0
  121. package/dist/tools/asset/refresh-status.js +12 -0
  122. package/dist/tools/asset/refresh-status.js.map +1 -0
  123. package/dist/tools/asset/refresh.js +7 -3
  124. package/dist/tools/asset/refresh.js.map +1 -1
  125. package/dist/tools/build/player-status.d.ts +3 -0
  126. package/dist/tools/build/player-status.js +12 -0
  127. package/dist/tools/build/player-status.js.map +1 -0
  128. package/dist/tools/build/run.js +1 -1
  129. package/dist/tools/build/run.js.map +1 -1
  130. package/dist/tools/catalog-control.d.ts +22 -0
  131. package/dist/tools/catalog-control.js +335 -0
  132. package/dist/tools/catalog-control.js.map +1 -0
  133. package/dist/tools/catalog.d.ts +7 -9
  134. package/dist/tools/catalog.js +66 -45
  135. package/dist/tools/catalog.js.map +1 -1
  136. package/dist/tools/commands.d.ts +1 -1
  137. package/dist/tools/commands.js +44 -11
  138. package/dist/tools/commands.js.map +1 -1
  139. package/dist/tools/define.js +3 -2
  140. package/dist/tools/define.js.map +1 -1
  141. package/dist/tools/dispatcher.d.ts +53 -6
  142. package/dist/tools/dispatcher.js +277 -108
  143. package/dist/tools/dispatcher.js.map +1 -1
  144. package/dist/tools/editor/compile.js +1 -1
  145. package/dist/tools/editor/compile.js.map +1 -1
  146. package/dist/tools/editor/play-mode-status.d.ts +3 -0
  147. package/dist/tools/editor/play-mode-status.js +12 -0
  148. package/dist/tools/editor/play-mode-status.js.map +1 -0
  149. package/dist/tools/editor/readiness.d.ts +0 -1
  150. package/dist/tools/editor/readiness.js +0 -1
  151. package/dist/tools/editor/readiness.js.map +1 -1
  152. package/dist/tools/editor/refresh.d.ts +7 -3
  153. package/dist/tools/editor/refresh.js +20 -15
  154. package/dist/tools/editor/refresh.js.map +1 -1
  155. package/dist/tools/editor/state.d.ts +2 -2
  156. package/dist/tools/editor/state.js +13 -12
  157. package/dist/tools/editor/state.js.map +1 -1
  158. package/dist/tools/metadata/derived.js +1 -7
  159. package/dist/tools/metadata/derived.js.map +1 -1
  160. package/dist/tools/metadata/status.js +1 -12
  161. package/dist/tools/metadata/status.js.map +1 -1
  162. package/dist/tools/metadata/types.d.ts +0 -2
  163. package/dist/tools/navmesh/live.js +1 -1
  164. package/dist/tools/navmesh/live.js.map +1 -1
  165. package/dist/tools/occlusion/live.js +1 -1
  166. package/dist/tools/occlusion/live.js.map +1 -1
  167. package/dist/tools/package/deploy.js +2 -2
  168. package/dist/tools/package/deploy.js.map +1 -1
  169. package/dist/tools/package/embed.js +1 -1
  170. package/dist/tools/package/embed.js.map +1 -1
  171. package/dist/tools/package/install-status.d.ts +3 -0
  172. package/dist/tools/package/install-status.js +12 -0
  173. package/dist/tools/package/install-status.js.map +1 -0
  174. package/dist/tools/package/install.js +3 -3
  175. package/dist/tools/package/install.js.map +1 -1
  176. package/dist/tools/package/live-resolve.js +45 -12
  177. package/dist/tools/package/live-resolve.js.map +1 -1
  178. package/dist/tools/package/registry-clear.js.map +1 -1
  179. package/dist/tools/package/registry-set.js.map +1 -1
  180. package/dist/tools/package/remove-status.d.ts +3 -0
  181. package/dist/tools/package/remove-status.js +12 -0
  182. package/dist/tools/package/remove-status.js.map +1 -0
  183. package/dist/tools/package/remove.js +3 -3
  184. package/dist/tools/package/remove.js.map +1 -1
  185. package/dist/tools/package/resolve.js +3 -3
  186. package/dist/tools/package/resolve.js.map +1 -1
  187. package/dist/tools/package/restore.js +2 -2
  188. package/dist/tools/package/restore.js.map +1 -1
  189. package/dist/tools/package/scoped-registry-add.js.map +1 -1
  190. package/dist/tools/status/support.d.ts +13 -0
  191. package/dist/tools/status/support.js +28 -0
  192. package/dist/tools/status/support.js.map +1 -0
  193. package/dist/tools/test/cancel.js +2 -2
  194. package/dist/tools/test/cancel.js.map +1 -1
  195. package/dist/tools/test/run-status.d.ts +3 -0
  196. package/dist/tools/test/run-status.js +12 -0
  197. package/dist/tools/test/run-status.js.map +1 -0
  198. package/dist/tools/test/run.js +7 -4
  199. package/dist/tools/test/run.js.map +1 -1
  200. package/dist/tools/tools/group-summaries.js +10 -14
  201. package/dist/tools/tools/group-summaries.js.map +1 -1
  202. package/docs/architecture.md +4 -4
  203. package/docs/availability-differences.md +4 -4
  204. package/docs/command-execution.md +4 -3
  205. package/docs/error-codes.md +13 -5
  206. package/docs/extensions.md +1 -7
  207. package/docs/risk-and-side-effects.md +4 -3
  208. package/docs/safety-boundaries.md +3 -1
  209. package/docs/target-and-instance.md +1 -1
  210. package/docs/tool-discovery.md +17 -10
  211. package/docs/tool-execution.md +18 -7
  212. package/extensions/cinemachine/unitypkg/Editor/UnityCliExtensionAssembly.cs +3 -0
  213. package/extensions/hdrp/unitypkg/Editor/UnityCliExtensionAssembly.cs +3 -0
  214. package/extensions/probuilder/unitypkg/Editor/UnityCliExtensionAssembly.cs +3 -0
  215. package/extensions/urp/unitypkg/Editor/UnityCliExtensionAssembly.cs +3 -0
  216. package/extensions/vfx-graph/unitypkg/Editor/UnityCliExtensionAssembly.cs +3 -0
  217. package/package.json +2 -4
  218. package/skills/unitycli/SKILL.md +11 -2
  219. package/skills/unitycli/manifest.json +1 -1
  220. package/skills/unitycli/references/operation-protocol.md +3 -3
  221. package/unitypkg/Editor/AssemblyInfo.cs +5 -0
  222. package/unitypkg/Editor/Bridge/BridgeCommandRegistry.cs +49 -14
  223. package/unitypkg/Editor/Bridge/BridgeHttpServer.cs +9 -35
  224. package/unitypkg/Editor/Bridge/BridgeQueueState.cs +672 -0
  225. package/unitypkg/Editor/Bridge/BridgeWorkQueue.cs +970 -120
  226. package/unitypkg/Editor/BridgeStartupStateMachine.cs +59 -1
  227. package/unitypkg/Editor/Commands/ProjectToolCommands.cs +4 -0
  228. package/unitypkg/Editor/Commands/RuntimeToolCommands.cs +3 -0
  229. package/unitypkg/Editor/Generated/UnityCliToolCompletionRegistry.g.cs +379 -14
  230. package/unitypkg/Editor/Infrastructure/CodeExecSupport.cs +28 -13
  231. package/unitypkg/Editor/Infrastructure/RegistryOwnershipResolver.cs +132 -105
  232. package/unitypkg/Editor/Infrastructure/UnityCliActiveOperation.cs +138 -29
  233. package/unitypkg/Editor/Infrastructure/UnityCliAdmission.cs +1856 -237
  234. package/unitypkg/Editor/Infrastructure/UnityCliDoctorDiagnostics.cs +220 -0
  235. package/unitypkg/Editor/Infrastructure/UnityCliDurableStatusCoordinator.cs +118 -0
  236. package/unitypkg/Editor/Infrastructure/UnityCliEditorStateSnapshot.cs +2 -1
  237. package/unitypkg/Editor/Infrastructure/UnityCliHierarchyPager.cs +203 -0
  238. package/unitypkg/Editor/Infrastructure/UnityCliInstanceCleanup.cs +2 -1
  239. package/unitypkg/Editor/Infrastructure/UnityCliInstanceRegistry.cs +201 -63
  240. package/unitypkg/Editor/Infrastructure/UnityCliJson.cs +2 -3
  241. package/unitypkg/Editor/Infrastructure/UnityCliLiveBuildCoordinator.cs +289 -46
  242. package/unitypkg/Editor/Infrastructure/UnityCliLiveRefreshCoordinator.cs +87 -53
  243. package/unitypkg/Editor/Infrastructure/UnityCliNavMeshBakeCoordinator.cs +4 -4
  244. package/unitypkg/Editor/Infrastructure/UnityCliObjectRef.cs +128 -25
  245. package/unitypkg/Editor/Infrastructure/UnityCliObjectSerializer.cs +435 -327
  246. package/unitypkg/Editor/Infrastructure/UnityCliOcclusionBakeCoordinator.cs +4 -4
  247. package/unitypkg/Editor/Infrastructure/UnityCliOperationCoordinator.cs +351 -53
  248. package/unitypkg/Editor/Infrastructure/UnityCliPackageResolveCoordinator.cs +118 -18
  249. package/unitypkg/Editor/Infrastructure/UnityCliPackageResolveState.cs +20 -1
  250. package/unitypkg/Editor/Infrastructure/UnityCliReadGeneration.cs +97 -0
  251. package/unitypkg/Editor/Infrastructure/UnityCliReflection.cs +644 -133
  252. package/unitypkg/Editor/Infrastructure/UnityCliReloadOperation.cs +128 -41
  253. package/unitypkg/Editor/Infrastructure/UnityCliRuntimeExecutor.cs +14 -84
  254. package/unitypkg/Editor/Infrastructure/UnityCliSerializer.cs +220 -0
  255. package/unitypkg/Editor/Infrastructure/UnityCliSessionMutationLease.cs +69 -29
  256. package/unitypkg/Editor/Infrastructure/UnityCliTestRunCoordinator.cs +440 -54
  257. package/unitypkg/Editor/Infrastructure/UnityCliWaiter.cs +128 -35
  258. package/unitypkg/Editor/ProjectTools/IUnityCliTool.cs +9 -1
  259. package/unitypkg/Editor/ProjectTools/OfficialAttributeToolRegistry.cs +32 -31
  260. package/unitypkg/Editor/ProjectTools/ProjectToolRegistry.cs +607 -458
  261. package/unitypkg/Editor/ProjectTools/ProjectToolSchemaValidator.cs +35 -7
  262. package/unitypkg/Editor/ProjectTools/RegisteredTool.cs +501 -60
  263. package/unitypkg/Editor/ProjectTools/UnityCliProjectToolContext.cs +21 -0
  264. package/unitypkg/Editor/ProjectTools/UnityCliSchemaDeriver.cs +36 -7
  265. package/unitypkg/Editor/ProjectTools/UnityCliToolName.cs +30 -0
  266. package/unitypkg/Editor/Properties/AssemblyInfo.cs +3 -0
  267. package/unitypkg/Editor/Tools/asset/get-data.cs +16 -7
  268. package/unitypkg/Editor/Tools/build/BuildSceneStateTool.cs +23 -3
  269. package/unitypkg/Editor/Tools/build/BuildToolDtos.cs +2 -1
  270. package/unitypkg/Editor/Tools/build/scene/add.cs +6 -3
  271. package/unitypkg/Editor/Tools/build/scene/disable.cs +1 -1
  272. package/unitypkg/Editor/Tools/build/scene/enable.cs +1 -1
  273. package/unitypkg/Editor/Tools/build/scene/list.cs +1 -1
  274. package/unitypkg/Editor/Tools/build/scene/remove.cs +13 -3
  275. package/unitypkg/Editor/Tools/camera/CameraToolSupport.cs +38 -38
  276. package/unitypkg/Editor/Tools/camera/multiview.cs +13 -6
  277. package/unitypkg/Editor/Tools/camera/screenshot.cs +14 -7
  278. package/unitypkg/Editor/Tools/component/get.cs +16 -9
  279. package/unitypkg/Editor/Tools/component/modify.cs +6 -4
  280. package/unitypkg/Editor/Tools/console/clear.cs +7 -6
  281. package/unitypkg/Editor/Tools/console/get.cs +48 -16
  282. package/unitypkg/Editor/Tools/editor/EditorToolSupport.cs +143 -28
  283. package/unitypkg/Editor/Tools/editor/menu-items.cs +1 -1
  284. package/unitypkg/Editor/Tools/editor/play.cs +2 -11
  285. package/unitypkg/Editor/Tools/editor/selection.cs +1 -1
  286. package/unitypkg/Editor/Tools/editor/stop.cs +2 -11
  287. package/unitypkg/Editor/Tools/editor/windows.cs +1 -1
  288. package/unitypkg/Editor/Tools/go/GameObjectToolSupport.cs +54 -4
  289. package/unitypkg/Editor/Tools/go/delete.cs +1 -1
  290. package/unitypkg/Editor/Tools/go/find.cs +167 -70
  291. package/unitypkg/Editor/Tools/graphics/GraphicsToolSupport.cs +25 -0
  292. package/unitypkg/Editor/Tools/graphics/light-probe-group.cs +9 -3
  293. package/unitypkg/Editor/Tools/graphics/pipeline-info.cs +1 -1
  294. package/unitypkg/Editor/Tools/graphics/pipeline-settings.cs +1 -1
  295. package/unitypkg/Editor/Tools/graphics/quality.cs +2 -2
  296. package/unitypkg/Editor/Tools/graphics/reflection-probe.cs +3 -3
  297. package/unitypkg/Editor/Tools/graphics/stats.cs +1 -1
  298. package/unitypkg/Editor/Tools/object/ObjectToolSupport.cs +4 -4
  299. package/unitypkg/Editor/Tools/object/get-data.cs +9 -7
  300. package/unitypkg/Editor/Tools/object/modify.cs +7 -5
  301. package/unitypkg/Editor/Tools/physics/raycast.cs +24 -6
  302. package/unitypkg/Editor/Tools/prefab/stage.cs +1 -1
  303. package/unitypkg/Editor/Tools/profiler/ProfilerFrameDebuggerSupport.cs +94 -21
  304. package/unitypkg/Editor/Tools/profiler/ProfilerMemorySnapshotSupport.cs +397 -10
  305. package/unitypkg/Editor/Tools/profiler/ProfilerToolSupport.cs +18 -4
  306. package/unitypkg/Editor/Tools/profiler/frame-debugger/enable.cs +1 -1
  307. package/unitypkg/Editor/Tools/profiler/frame-debugger/events.cs +88 -87
  308. package/unitypkg/Editor/Tools/profiler/hierarchy.cs +278 -112
  309. package/unitypkg/Editor/Tools/profiler/memory-snapshot/compare.cs +9 -5
  310. package/unitypkg/Editor/Tools/profiler/memory-snapshot/list.cs +37 -35
  311. package/unitypkg/Editor/Tools/profiler/memory-snapshot/take.cs +99 -97
  312. package/unitypkg/Editor/Tools/project/info.cs +1 -1
  313. package/unitypkg/Editor/Tools/project/layers.cs +1 -1
  314. package/unitypkg/Editor/Tools/project/tags.cs +1 -1
  315. package/unitypkg/Editor/Tools/reflection/method/call.cs +9 -7
  316. package/unitypkg/Editor/Tools/reflection/method/find.cs +27 -37
  317. package/unitypkg/Editor/Tools/reflection/type/schema.cs +24 -28
  318. package/unitypkg/Editor/Tools/scene/gameobject/component.cs +8 -5
  319. package/unitypkg/Editor/Tools/scene/gameobject/components.cs +10 -7
  320. package/unitypkg/Editor/Tools/scene/gameobject-support.cs +104 -8
  321. package/unitypkg/Editor/Tools/scene/gameobject.cs +37 -16
  322. package/unitypkg/Editor/Tools/scene/hierarchy.cs +146 -142
  323. package/unitypkg/Editor/Tools/screenshot/EditorElementCaptureToolSupport.cs +77 -25
  324. package/unitypkg/Editor/Tools/screenshot/ScreenshotToolSupport.cs +315 -95
  325. package/unitypkg/Editor/Tools/screenshot/editor-element.cs +7 -5
  326. package/unitypkg/Editor/Tools/screenshot/game-view.cs +35 -21
  327. package/unitypkg/Editor/Tools/screenshot/isolated-object.cs +29 -23
  328. package/unitypkg/Editor/Tools/screenshot/orbit.cs +37 -25
  329. package/unitypkg/Editor/Tools/screenshot/scene-view.cs +25 -18
  330. package/unitypkg/Editor/Tools/screenshot/screen.cs +177 -17
  331. package/unitypkg/Editor/Tools/screenshot/surround.cs +83 -79
  332. package/unitypkg/Editor/Tools/ui/render-preview.cs +16 -11
  333. package/unitypkg/Editor/UnityCliBridge.cs +97 -34
  334. package/unitypkg/Runtime/Infrastructure/UnityCliRuntimeBridge.cs +753 -122
  335. package/unitypkg/Runtime/Properties/AssemblyInfo.cs +5 -0
  336. package/unitypkg/Runtime/UnityCli.Runtime.asmdef +1 -1
  337. package/unitypkg/Shared/AssemblyInfo.cs +4 -0
  338. package/unitypkg/Shared/UnityCliAdmissionPool.cs +265 -75
  339. package/unitypkg/Shared/UnityCliBridgeQueuePolicy.cs +410 -0
  340. package/unitypkg/Shared/UnityCliBridgeWorkItemState.cs +47 -0
  341. package/unitypkg/Shared/UnityCliExceptionProjection.cs +151 -0
  342. package/unitypkg/Shared/UnityCliQueuePublication.cs +30 -0
  343. package/unitypkg/Shared/UnityCliRequestBudget.cs +352 -0
  344. package/unitypkg/Shared/UnityCliRuntimeRequestPublication.cs +107 -0
  345. package/unitypkg/Tests/Editor/UnityCli.Editor.Tests.asmdef +2 -2
  346. package/unitypkg/Tests/Editor/UnityCliAdmissionCoordinatorIntegrationTests.cs +1329 -0
  347. package/unitypkg/Tests/Editor/UnityCliAdmissionPoolTests.cs +311 -114
  348. package/unitypkg/Tests/Editor/UnityCliAdmissionRepairStateTests.cs +94 -0
  349. package/unitypkg/Tests/Editor/UnityCliBridgeAdmissionIntegrationTests.cs +1229 -0
  350. package/unitypkg/Tests/Editor/UnityCliBridgeQueuePolicyTests.cs +412 -0
  351. package/unitypkg/Tests/Editor/UnityCliContinuationIntegrationTests.cs +292 -0
  352. package/unitypkg/Tests/Editor/UnityCliDiagnosticBoundaryTests.cs +120 -0
  353. package/unitypkg/Tests/Editor/UnityCliDurableStatusTests.cs +84 -0
  354. package/unitypkg/Tests/Editor/UnityCliExceptionProjectionTests.cs +72 -0
  355. package/unitypkg/Tests/Editor/UnityCliInstancePublicationRetryTests.cs +180 -97
  356. package/unitypkg/Tests/Editor/UnityCliMemoryReflectionIntegrationTests.cs +434 -0
  357. package/unitypkg/Tests/Editor/UnityCliRequestBudgetTests.cs +615 -0
  358. package/unitypkg/Tests/Editor/UnityCliRuntimeBridgeIntegrationTests.cs +520 -0
  359. package/unitypkg/Tests/Editor/UnityCliToolCatalogTests.cs +562 -0
  360. package/unitypkg/Tests/Runtime/UnityCli.Runtime.Tests.asmdef +23 -0
  361. package/unitypkg/Tests/Runtime/UnityCliRuntimeCatalogValidationTests.cs +29 -0
  362. package/unitypkg/package.json +1 -1
  363. package/contracts/static-capability-catalog.json +0 -48226
  364. package/dist/bridge/domains/diagnose.d.ts +0 -2
  365. package/dist/bridge/domains/diagnose.js +0 -11
  366. package/dist/bridge/domains/diagnose.js.map +0 -1
  367. package/dist/bridge/domains/extension.d.ts +0 -8
  368. package/dist/bridge/domains/extension.js +0 -20
  369. package/dist/bridge/domains/extension.js.map +0 -1
  370. package/dist/capabilities.d.ts +0 -5
  371. package/dist/capabilities.js +0 -84
  372. package/dist/capabilities.js.map +0 -1
  373. package/dist/static-capability-catalog.d.ts +0 -13
  374. package/dist/static-capability-catalog.js +0 -41
  375. package/dist/static-capability-catalog.js.map +0 -1
  376. package/dist/tools/diagnose/capabilities.d.ts +0 -13
  377. package/dist/tools/diagnose/capabilities.js +0 -34
  378. package/dist/tools/diagnose/capabilities.js.map +0 -1
  379. package/dist/tools/package/info.d.ts +0 -19
  380. package/dist/tools/package/info.js +0 -27
  381. package/dist/tools/package/info.js.map +0 -1
  382. package/dist/tools/package/list.d.ts +0 -27
  383. package/dist/tools/package/list.js +0 -21
  384. package/dist/tools/package/list.js.map +0 -1
  385. package/dist/tools/package/registry-get.d.ts +0 -10
  386. package/dist/tools/package/registry-get.js +0 -22
  387. package/dist/tools/package/registry-get.js.map +0 -1
  388. package/dist/tools/package/scoped-registry-list.d.ts +0 -14
  389. package/dist/tools/package/scoped-registry-list.js +0 -22
  390. package/dist/tools/package/scoped-registry-list.js.map +0 -1
  391. package/dist/tools/package/search.d.ts +0 -17
  392. package/dist/tools/package/search.js +0 -39
  393. package/dist/tools/package/search.js.map +0 -1
  394. package/dist/tools/package/status.d.ts +0 -21
  395. package/dist/tools/package/status.js +0 -37
  396. package/dist/tools/package/status.js.map +0 -1
  397. package/dist/tools/tools/describe.d.ts +0 -27
  398. package/dist/tools/tools/describe.js +0 -35
  399. package/dist/tools/tools/describe.js.map +0 -1
  400. package/dist/tools/tools/group-list.d.ts +0 -16
  401. package/dist/tools/tools/group-list.js +0 -38
  402. package/dist/tools/tools/group-list.js.map +0 -1
  403. package/dist/tools/tools/group.d.ts +0 -13
  404. package/dist/tools/tools/group.js +0 -34
  405. package/dist/tools/tools/group.js.map +0 -1
  406. package/dist/tools/tools/pagination.d.ts +0 -17
  407. package/dist/tools/tools/pagination.js +0 -28
  408. package/dist/tools/tools/pagination.js.map +0 -1
  409. package/dist/tools/tools/search.d.ts +0 -15
  410. package/dist/tools/tools/search.js +0 -42
  411. package/dist/tools/tools/search.js.map +0 -1
  412. package/unitypkg/Editor/Tools/diagnose/preflight.cs +0 -269
  413. package/unitypkg/Editor/Tools/editor/console.cs +0 -26
  414. package/unitypkg/Editor/Tools/extension/status.cs +0 -87
  415. package/unitypkg/Editor/Tools/go/inspect.cs +0 -49
  416. package/unitypkg/Editor/Tools/graphics/pipeline-quality.cs +0 -24
  417. package/unitypkg/Editor/Tools/graphics/probe-positions.cs +0 -58
  418. package/unitypkg/Editor/Tools/graphics/settings.cs +0 -104
  419. package/unitypkg/Editor/Tools/graphics/stats-counters.cs +0 -28
  420. package/unitypkg/Editor/Tools/graphics/stats-memory.cs +0 -21
  421. package/unitypkg/Editor/Tools/instances/list.cs +0 -71
  422. package/unitypkg/Editor/Tools/physics/raycast-all.cs +0 -67
  423. package/unitypkg/Editor/Tools/scene/build-settings.cs +0 -69
  424. package/unitypkg/Editor/Tools/scene/data.cs +0 -125
  425. package/unitypkg/Editor/Tools/tests/list.cs +0 -98
@@ -0,0 +1,410 @@
1
+ using System;
2
+ using System.Collections.Generic;
3
+ using System.Collections.ObjectModel;
4
+
5
+ namespace UnityCli
6
+ {
7
+ /// <summary>Bridge主线程队列的纯分类、容量与启动选择策略。</summary>
8
+ public static class UnityCliBridgeQueuePolicy
9
+ {
10
+ public const int MaxBypassIdentities = 128;
11
+ public const int MaxFifoNodesExaminedPerTick = 128;
12
+ public const int MaxControlNodesExaminedPerTick = 128;
13
+ public const int MaxSafeStatusNodesExaminedPerTick = 4;
14
+ public const int MaxNodesExaminedPerTick = MaxFifoNodesExaminedPerTick
15
+ + MaxControlNodesExaminedPerTick + MaxSafeStatusNodesExaminedPerTick;
16
+ public const int MaxStartsPerTick = 16;
17
+ public const int MaxSafeStatusStartsPerTick = 4;
18
+
19
+ public enum WorkClass
20
+ {
21
+ Mutation,
22
+ OrdinaryRead,
23
+ SafeStatus,
24
+ Control
25
+ }
26
+
27
+ public enum DurableMutationBarrier
28
+ {
29
+ Clear,
30
+ Held,
31
+ Unreadable
32
+ }
33
+
34
+ public enum ControlDisposition
35
+ {
36
+ Pending,
37
+ Authorized,
38
+ RejectParentUnavailable,
39
+ RejectIdentityMismatch,
40
+ ExpireDeadline
41
+ }
42
+
43
+ public enum BypassAdmissionOutcome
44
+ {
45
+ Enqueue,
46
+ Attach,
47
+ RejectCapacity,
48
+ RejectIdentityMismatch
49
+ }
50
+
51
+ public sealed class QueueNode
52
+ {
53
+ public QueueNode(string nodeId, string command, WorkClass workClass)
54
+ : this(nodeId, command, workClass, ControlDisposition.Pending) { }
55
+
56
+ private QueueNode(string nodeId, string command, WorkClass workClass, ControlDisposition controlDisposition)
57
+ {
58
+ ValidateNodeId(nodeId);
59
+ ValidateEnum(controlDisposition, "controlDisposition");
60
+ NodeId = nodeId;
61
+ Command = command;
62
+ Class = Classify(command, workClass);
63
+ if (Class != WorkClass.Control && controlDisposition != ControlDisposition.Pending)
64
+ throw new InvalidOperationException("Only a durable control node can receive a control disposition.");
65
+ ControlDecision = Class == WorkClass.Control ? controlDisposition : ControlDisposition.Pending;
66
+ }
67
+
68
+ public string NodeId { get; }
69
+ public string Command { get; }
70
+ public WorkClass Class { get; }
71
+ public ControlDisposition ControlDecision { get; }
72
+ public bool ControlAuthorized { get { return ControlDecision == ControlDisposition.Authorized; } }
73
+
74
+ public QueueNode WithControlAuthorization(bool authorized)
75
+ {
76
+ return WithControlDisposition(authorized ? ControlDisposition.Authorized : ControlDisposition.Pending);
77
+ }
78
+
79
+ public QueueNode WithControlDisposition(ControlDisposition disposition)
80
+ {
81
+ if (Class != WorkClass.Control && disposition != ControlDisposition.Pending)
82
+ throw new InvalidOperationException("Only a durable control node can receive a control disposition.");
83
+ return new QueueNode(NodeId, Command, Class, disposition);
84
+ }
85
+ }
86
+
87
+ public sealed class BypassIdentity
88
+ {
89
+ public BypassIdentity(string requestId, string requestDigest)
90
+ {
91
+ ValidateRequestId(requestId);
92
+ ValidateDigest(requestDigest);
93
+ RequestId = requestId;
94
+ RequestDigest = requestDigest;
95
+ }
96
+
97
+ public string RequestId { get; }
98
+ public string RequestDigest { get; }
99
+ }
100
+
101
+ public sealed class BypassAdmissionDecision
102
+ {
103
+ internal BypassAdmissionDecision(BypassAdmissionOutcome outcome, int existingIndex)
104
+ {
105
+ Outcome = outcome;
106
+ ExistingIndex = existingIndex;
107
+ }
108
+
109
+ public BypassAdmissionOutcome Outcome { get; }
110
+ public int ExistingIndex { get; }
111
+ }
112
+
113
+ public sealed class StartDecision
114
+ {
115
+ internal StartDecision(string nodeId, int queueIndex, WorkClass workClass)
116
+ {
117
+ NodeId = nodeId;
118
+ QueueIndex = queueIndex;
119
+ Class = workClass;
120
+ }
121
+
122
+ public string NodeId { get; }
123
+ public int QueueIndex { get; }
124
+ public WorkClass Class { get; }
125
+ }
126
+
127
+ public sealed class RejectDecision
128
+ {
129
+ internal RejectDecision(string nodeId, int queueIndex, ControlDisposition disposition)
130
+ {
131
+ NodeId = nodeId;
132
+ QueueIndex = queueIndex;
133
+ Disposition = disposition;
134
+ }
135
+
136
+ public string NodeId { get; }
137
+ public int QueueIndex { get; }
138
+ public ControlDisposition Disposition { get; }
139
+ }
140
+
141
+ public sealed class TickSelection
142
+ {
143
+ internal TickSelection(List<StartDecision> starts, List<RejectDecision> rejects, int nodesExamined)
144
+ {
145
+ Starts = new ReadOnlyCollection<StartDecision>(starts.ToArray());
146
+ Rejects = new ReadOnlyCollection<RejectDecision>(rejects.ToArray());
147
+ NodesExamined = nodesExamined;
148
+ }
149
+
150
+ public IReadOnlyList<StartDecision> Starts { get; }
151
+ public IReadOnlyList<RejectDecision> Rejects { get; }
152
+ public int NodesExamined { get; }
153
+ }
154
+
155
+ /// <summary>只接受生产注册表裁决的闭集分类;SafeStatus命令不能被降级为普通读取。</summary>
156
+ public static WorkClass Classify(string command, WorkClass workClass)
157
+ {
158
+ ValidateCommand(command);
159
+ ValidateEnum(workClass, "workClass");
160
+ var safeStatus = IsSafeStatusCommand(command);
161
+ var durableControl = IsDurableControlCommand(command);
162
+ if (safeStatus && workClass != WorkClass.SafeStatus)
163
+ throw new ArgumentException("SafeStatus command must use SafeStatus classification.", "workClass");
164
+ if (!safeStatus && workClass == WorkClass.SafeStatus)
165
+ throw new ArgumentException("Only the exact SafeStatus allowlist may use SafeStatus classification.", "workClass");
166
+ if (durableControl && workClass != WorkClass.Control)
167
+ throw new ArgumentException("Durable control command must use Control classification.", "workClass");
168
+ if (!durableControl && workClass == WorkClass.Control)
169
+ throw new ArgumentException("Only the exact durable control allowlist may use Control classification.", "workClass");
170
+ return workClass;
171
+ }
172
+
173
+ /// <summary>精确白名单不接受后缀、大小写或project-tool间接名称。</summary>
174
+ public static bool IsSafeStatusCommand(string command)
175
+ {
176
+ switch (command)
177
+ {
178
+ case "internal.editor.compile.status":
179
+ case "internal.editor.refresh.status":
180
+ case "internal.editor.state.snapshot":
181
+ case "internal.asset.refresh.status":
182
+ case "internal.asset.refresh.public-status":
183
+ case "internal.build.player.public-status":
184
+ case "internal.editor.play-mode.public-status":
185
+ case "internal.package.install.public-status":
186
+ case "internal.package.remove.public-status":
187
+ case "internal.test.run.public-status":
188
+ case "internal.package.embed.status":
189
+ case "internal.package.resolve.status":
190
+ case "internal.test.run.status":
191
+ case "internal.test.run.cancel.status":
192
+ case "internal.navmesh.bake.status":
193
+ case "internal.occlusion.bake.status":
194
+ return true;
195
+ default:
196
+ return false;
197
+ }
198
+ }
199
+
200
+ /// <summary>只有绑定当前durable parent的私有命令可进入受限control lane。</summary>
201
+ public static bool IsDurableControlCommand(string command)
202
+ {
203
+ switch (command)
204
+ {
205
+ case "internal.test.run.cancel.plan":
206
+ case "internal.test.run.cancel":
207
+ case "internal.package.files.claim":
208
+ case "internal.package.files.commit":
209
+ case "internal.package.files.prove":
210
+ case "internal.package.files.fail":
211
+ case "internal.navmesh.bake.cancel":
212
+ case "internal.occlusion.bake.cancel":
213
+ return true;
214
+ default:
215
+ return false;
216
+ }
217
+ }
218
+
219
+ /// <summary>internal普通读取只允许不触发plan、cancel或writer控制的精确观察命令。</summary>
220
+ public static bool IsOrdinaryReadInternalCommand(string command)
221
+ {
222
+ return string.Equals(command, "internal.navmesh.bake.snapshot", StringComparison.Ordinal)
223
+ || string.Equals(command, "internal.occlusion.bake.snapshot", StringComparison.Ordinal);
224
+ }
225
+
226
+ /// <summary>同requestId同digest只attach;新identity达到固定上限时拒绝。</summary>
227
+ public static BypassAdmissionDecision DecideBypassAdmission(IReadOnlyList<BypassIdentity> activeAndQueued, BypassIdentity candidate)
228
+ {
229
+ if (activeAndQueued == null) throw new ArgumentNullException("activeAndQueued");
230
+ if (candidate == null) throw new ArgumentNullException("candidate");
231
+ if (activeAndQueued.Count > MaxBypassIdentities) throw new ArgumentException("Bypass identity snapshot exceeds its fixed bound.", "activeAndQueued");
232
+
233
+ var requestIds = new HashSet<string>(StringComparer.Ordinal);
234
+ var existingIndex = -1;
235
+ var exactMatch = false;
236
+ for (var index = 0; index < activeAndQueued.Count; index++)
237
+ {
238
+ var existing = activeAndQueued[index];
239
+ if (existing == null) throw new ArgumentException("Bypass identity snapshot contains null.", "activeAndQueued");
240
+ if (!requestIds.Add(existing.RequestId)) throw new ArgumentException("Bypass identity snapshot contains duplicate requestId.", "activeAndQueued");
241
+ if (!string.Equals(existing.RequestId, candidate.RequestId, StringComparison.Ordinal)) continue;
242
+ existingIndex = index;
243
+ exactMatch = string.Equals(existing.RequestDigest, candidate.RequestDigest, StringComparison.Ordinal);
244
+ }
245
+
246
+ if (existingIndex >= 0)
247
+ return new BypassAdmissionDecision(exactMatch ? BypassAdmissionOutcome.Attach : BypassAdmissionOutcome.RejectIdentityMismatch, existingIndex);
248
+ return activeAndQueued.Count == MaxBypassIdentities
249
+ ? new BypassAdmissionDecision(BypassAdmissionOutcome.RejectCapacity, -1)
250
+ : new BypassAdmissionDecision(BypassAdmissionOutcome.Enqueue, -1);
251
+ }
252
+
253
+ /// <summary>lane遍历每访问一个唯一节点就完成一次policy检查,避免production再次扫描候选集合。</summary>
254
+ public sealed class TickSelectionAccumulator
255
+ {
256
+ private readonly int runningOrdinaryReads;
257
+ private readonly bool mutationRunning;
258
+ private readonly DurableMutationBarrier durableMutationBarrier;
259
+ private readonly List<QueueNode> examinedNodes = new List<QueueNode>(MaxNodesExaminedPerTick);
260
+ private readonly List<int> earlierOrdinaryReadIndices = new List<int>();
261
+ private readonly List<int> safeStatusIndices = new List<int>(MaxSafeStatusStartsPerTick);
262
+ private readonly List<RejectDecision> rejects = new List<RejectDecision>();
263
+ private readonly HashSet<string> nodeIds = new HashSet<string>(StringComparer.Ordinal);
264
+ private int firstMutationIndex = -1;
265
+ private int firstAuthorizedControlIndex = -1;
266
+ private bool completed;
267
+
268
+ internal TickSelectionAccumulator(int runningOrdinaryReads, bool mutationRunning, DurableMutationBarrier durableMutationBarrier)
269
+ {
270
+ if (runningOrdinaryReads < 0) throw new ArgumentOutOfRangeException("runningOrdinaryReads");
271
+ ValidateEnum(durableMutationBarrier, "durableMutationBarrier");
272
+ this.runningOrdinaryReads = runningOrdinaryReads;
273
+ this.mutationRunning = mutationRunning;
274
+ this.durableMutationBarrier = durableMutationBarrier;
275
+ }
276
+
277
+ private bool HasCapacity { get { return examinedNodes.Count < MaxNodesExaminedPerTick; } }
278
+
279
+ /// <summary>调用方已访问lane节点时同步记录唯一候选及其完整eligibility。</summary>
280
+ public void Examine(QueueNode node)
281
+ {
282
+ if (completed) throw new InvalidOperationException("Tick selection is already complete.");
283
+ if (!HasCapacity) throw new InvalidOperationException("Tick selection exceeded its fixed node bound.");
284
+ if (node == null) throw new ArgumentException("Examined queue prefix contains null.", "node");
285
+ if (!nodeIds.Add(node.NodeId)) throw new ArgumentException("Examined queue prefix contains duplicate nodeId.", "node");
286
+ var index = examinedNodes.Count;
287
+ examinedNodes.Add(node);
288
+ if (node.Class == WorkClass.Control && IsTerminalControlDisposition(node.ControlDecision))
289
+ {
290
+ rejects.Add(new RejectDecision(node.NodeId, index, node.ControlDecision));
291
+ return;
292
+ }
293
+ if (firstAuthorizedControlIndex < 0 && node.Class == WorkClass.Control && node.ControlAuthorized)
294
+ firstAuthorizedControlIndex = index;
295
+ if (firstMutationIndex < 0 && (node.Class == WorkClass.Mutation || node.Class == WorkClass.Control))
296
+ firstMutationIndex = index;
297
+ if (node.Class == WorkClass.SafeStatus && safeStatusIndices.Count < MaxSafeStatusStartsPerTick)
298
+ safeStatusIndices.Add(index);
299
+ if (firstMutationIndex < 0 && node.Class == WorkClass.OrdinaryRead)
300
+ earlierOrdinaryReadIndices.Add(index);
301
+ }
302
+
303
+ /// <summary>基于已检查节点完成本tick的唯一启动与拒绝裁决。</summary>
304
+ public TickSelection Complete()
305
+ {
306
+ if (completed) throw new InvalidOperationException("Tick selection is already complete.");
307
+ completed = true;
308
+ var selectedIndices = new List<int>(MaxStartsPerTick);
309
+ selectedIndices.AddRange(safeStatusIndices);
310
+ var remainingStarts = MaxStartsPerTick - selectedIndices.Count;
311
+ var regularBarrierClear = !mutationRunning && durableMutationBarrier == DurableMutationBarrier.Clear;
312
+ if (!mutationRunning && durableMutationBarrier == DurableMutationBarrier.Held
313
+ && remainingStarts > 0 && firstAuthorizedControlIndex >= 0)
314
+ {
315
+ selectedIndices.Add(firstAuthorizedControlIndex);
316
+ remainingStarts -= 1;
317
+ }
318
+
319
+ if (regularBarrierClear && remainingStarts > 0)
320
+ {
321
+ if (firstMutationIndex < 0 || earlierOrdinaryReadIndices.Count > 0)
322
+ {
323
+ foreach (var index in earlierOrdinaryReadIndices)
324
+ {
325
+ if (remainingStarts == 0) break;
326
+ selectedIndices.Add(index);
327
+ remainingStarts -= 1;
328
+ }
329
+ }
330
+ else if (runningOrdinaryReads == 0 && examinedNodes[firstMutationIndex].Class == WorkClass.Mutation)
331
+ {
332
+ selectedIndices.Add(firstMutationIndex);
333
+ remainingStarts -= 1;
334
+ }
335
+ }
336
+
337
+ selectedIndices.Sort();
338
+ var starts = new List<StartDecision>(selectedIndices.Count);
339
+ foreach (var index in selectedIndices)
340
+ {
341
+ var node = examinedNodes[index];
342
+ starts.Add(new StartDecision(node.NodeId, index, node.Class));
343
+ }
344
+ return new TickSelection(starts, rejects, examinedNodes.Count);
345
+ }
346
+ }
347
+
348
+ /// <summary>创建与一次production lane遍历同生命周期的增量选择器。</summary>
349
+ public static TickSelectionAccumulator BeginSelection(
350
+ int runningOrdinaryReads,
351
+ bool mutationRunning,
352
+ DurableMutationBarrier durableMutationBarrier)
353
+ {
354
+ return new TickSelectionAccumulator(runningOrdinaryReads, mutationRunning, durableMutationBarrier);
355
+ }
356
+
357
+ /// <summary>按队列顺序选择本tick唯一可移除并尝试启动的节点,不修改调用方集合。</summary>
358
+ public static TickSelection SelectStarts(
359
+ IReadOnlyList<QueueNode> queued,
360
+ int runningOrdinaryReads,
361
+ bool mutationRunning,
362
+ DurableMutationBarrier durableMutationBarrier)
363
+ {
364
+ if (queued == null) throw new ArgumentNullException("queued");
365
+ var accumulator = BeginSelection(runningOrdinaryReads, mutationRunning, durableMutationBarrier);
366
+ var examined = Math.Min(queued.Count, MaxNodesExaminedPerTick);
367
+ for (var index = 0; index < examined; index++) accumulator.Examine(queued[index]);
368
+ return accumulator.Complete();
369
+ }
370
+
371
+ private static bool IsTerminalControlDisposition(ControlDisposition disposition)
372
+ {
373
+ return disposition == ControlDisposition.RejectParentUnavailable
374
+ || disposition == ControlDisposition.RejectIdentityMismatch
375
+ || disposition == ControlDisposition.ExpireDeadline;
376
+ }
377
+
378
+ private static void ValidateCommand(string command)
379
+ {
380
+ if (string.IsNullOrWhiteSpace(command) || command.Length > 256 || !string.Equals(command, command.Trim(), StringComparison.Ordinal))
381
+ throw new ArgumentException("Bridge command must be a non-empty exact value of at most 256 characters.", "command");
382
+ }
383
+
384
+ private static void ValidateNodeId(string nodeId)
385
+ {
386
+ if (string.IsNullOrWhiteSpace(nodeId) || nodeId.Length > 200)
387
+ throw new ArgumentException("Queue nodeId is required and must be at most 200 characters.", "nodeId");
388
+ }
389
+
390
+ private static void ValidateRequestId(string requestId)
391
+ {
392
+ if (string.IsNullOrWhiteSpace(requestId) || requestId.Length > 200)
393
+ throw new ArgumentException("Bypass requestId is required and must be at most 200 characters.", "requestId");
394
+ }
395
+
396
+ private static void ValidateDigest(string digest)
397
+ {
398
+ if (string.IsNullOrEmpty(digest) || digest.Length != 64)
399
+ throw new ArgumentException("Bypass requestDigest must be a lowercase SHA-256 value.", "requestDigest");
400
+ foreach (var character in digest)
401
+ if (!((character >= '0' && character <= '9') || (character >= 'a' && character <= 'f')))
402
+ throw new ArgumentException("Bypass requestDigest must be a lowercase SHA-256 value.", "requestDigest");
403
+ }
404
+
405
+ private static void ValidateEnum<T>(T value, string parameterName) where T : struct
406
+ {
407
+ if (!Enum.IsDefined(typeof(T), value)) throw new ArgumentOutOfRangeException(parameterName);
408
+ }
409
+ }
410
+ }
@@ -0,0 +1,47 @@
1
+ using System;
2
+
3
+ namespace UnityCli
4
+ {
5
+ /// <summary>Bridge WorkItem准入、启动与HTTP取消的纯状态裁决。</summary>
6
+ public sealed class UnityCliBridgeWorkItemState
7
+ {
8
+ public enum StartOutcome { Started, Cancelled, ListenerChanged, DeadlineElapsed }
9
+
10
+ private bool cancelled;
11
+ private bool accepted;
12
+ private bool started;
13
+
14
+ public bool Started { get { return started; } }
15
+ public bool Accepted { get { return accepted; } }
16
+
17
+ public StartOutcome TryStart(bool listenerMatches, int remainingMs)
18
+ {
19
+ if (cancelled) return StartOutcome.Cancelled;
20
+ if (!listenerMatches) { cancelled = true; return StartOutcome.ListenerChanged; }
21
+ if (remainingMs <= 0) { cancelled = true; return StartOutcome.DeadlineElapsed; }
22
+ started = true;
23
+ return StartOutcome.Started;
24
+ }
25
+
26
+ public bool TryAccept()
27
+ {
28
+ if (cancelled || accepted) return false;
29
+ accepted = true;
30
+ return true;
31
+ }
32
+
33
+ public bool CancelBeforeAcceptance()
34
+ {
35
+ if (accepted) return false;
36
+ cancelled = true;
37
+ return true;
38
+ }
39
+
40
+ public bool CancelBeforeStart()
41
+ {
42
+ if (started) return false;
43
+ cancelled = true;
44
+ return true;
45
+ }
46
+ }
47
+ }
@@ -0,0 +1,151 @@
1
+ using System;
2
+ using System.Collections.Generic;
3
+ using System.Runtime.CompilerServices;
4
+ using System.Text;
5
+
6
+ namespace UnityCli
7
+ {
8
+ /// <summary>将嵌套异常归一化为有界、可循环终止的公开 cause chain。</summary>
9
+ internal static class UnityCliExceptionProjection
10
+ {
11
+ internal const int MaxCauseDepth = 8;
12
+ internal const int MaxCauseTraversal = 256;
13
+ internal const int MaxCauseTextBytes = 64 * 1024;
14
+ private const int MaxTypeBytes = 512;
15
+ private const int MaxMessageBytes = 4096;
16
+ private const int MaxStackTraceBytes = 16384;
17
+
18
+ internal sealed class Result
19
+ {
20
+ internal string PublicMessage;
21
+ internal string DeepestExceptionType;
22
+ internal string DeepestMessage;
23
+ internal string DeepestStackTrace;
24
+ internal List<Dictionary<string, object>> Causes;
25
+ internal bool Truncated;
26
+ internal int CauseTextBytes;
27
+ internal int CauseTraversalCount;
28
+ }
29
+
30
+ internal static Result Project(Exception exception)
31
+ {
32
+ return Project(exception, value => value == null ? null : value.InnerException);
33
+ }
34
+
35
+ /// <summary>selector 仅供隔离测试构造循环;生产路径始终读取 Exception.InnerException。</summary>
36
+ internal static Result Project(Exception exception, Func<Exception, Exception> selector)
37
+ {
38
+ if (exception == null) throw new ArgumentNullException("exception");
39
+ if (selector == null) throw new ArgumentNullException("selector");
40
+
41
+ var retained = new List<CauseReference>(MaxCauseDepth);
42
+ var visited = new HashSet<Exception>(ReferenceComparer.Instance);
43
+ var truncated = false;
44
+ var current = exception;
45
+ Exception deepest = null;
46
+ var deepestDepth = -1;
47
+ var traversed = 0;
48
+ while (current != null && traversed < MaxCauseTraversal)
49
+ {
50
+ if (!visited.Add(current))
51
+ {
52
+ truncated = true;
53
+ break;
54
+ }
55
+ if (retained.Count < MaxCauseDepth - 1) retained.Add(new CauseReference(current, traversed));
56
+ deepest = current;
57
+ deepestDepth = traversed;
58
+ traversed++;
59
+ current = selector(current);
60
+ }
61
+ if (current != null || traversed > MaxCauseDepth) truncated = true;
62
+ if (deepestDepth >= MaxCauseDepth - 1) retained.Add(new CauseReference(deepest, deepestDepth));
63
+
64
+ var remaining = MaxCauseTextBytes;
65
+ var types = new string[retained.Count];
66
+ var messages = new string[retained.Count];
67
+ var stacks = new string[retained.Count];
68
+
69
+ // 只投影前七层与真实终端槽,并优先为终端 cause 分配 type/message bytes。
70
+ for (var index = retained.Count - 1; index >= 0; index--)
71
+ {
72
+ messages[index] = TakeUtf8(retained[index].Exception.Message, Math.Min(MaxMessageBytes, remaining), ref remaining, ref truncated);
73
+ types[index] = TakeUtf8(retained[index].Exception.GetType().FullName, Math.Min(MaxTypeBytes, remaining), ref remaining, ref truncated);
74
+ }
75
+ for (var index = retained.Count - 1; index >= 0; index--)
76
+ {
77
+ stacks[index] = TakeUtf8(retained[index].Exception.StackTrace, Math.Min(MaxStackTraceBytes, remaining), ref remaining, ref truncated);
78
+ }
79
+
80
+ var causes = new List<Dictionary<string, object>>(retained.Count);
81
+ for (var index = 0; index < retained.Count; index++)
82
+ {
83
+ causes.Add(new Dictionary<string, object>
84
+ {
85
+ { "depth", (long)retained[index].Depth },
86
+ { "exceptionType", types[index] },
87
+ { "message", messages[index] },
88
+ { "stackTrace", stacks[index] }
89
+ });
90
+ }
91
+
92
+ var deepestIndex = retained.Count - 1;
93
+ var deepestMessage = messages[deepestIndex];
94
+ if (string.IsNullOrWhiteSpace(deepestMessage)) deepestMessage = string.IsNullOrWhiteSpace(types[deepestIndex]) ? "Exception" : types[deepestIndex];
95
+ return new Result
96
+ {
97
+ PublicMessage = deepestMessage,
98
+ DeepestExceptionType = types[deepestIndex],
99
+ DeepestMessage = messages[deepestIndex],
100
+ DeepestStackTrace = stacks[deepestIndex],
101
+ Causes = causes,
102
+ Truncated = truncated,
103
+ CauseTextBytes = MaxCauseTextBytes - remaining,
104
+ CauseTraversalCount = traversed
105
+ };
106
+ }
107
+
108
+ private sealed class CauseReference
109
+ {
110
+ internal CauseReference(Exception exception, int depth) { Exception = exception; Depth = depth; }
111
+ internal readonly Exception Exception;
112
+ internal readonly int Depth;
113
+ }
114
+
115
+ private static string TakeUtf8(string value, int allowedBytes, ref int remaining, ref bool truncated)
116
+ {
117
+ value = value ?? string.Empty;
118
+ if (allowedBytes <= 0)
119
+ {
120
+ if (value.Length > 0) truncated = true;
121
+ return string.Empty;
122
+ }
123
+
124
+ var low = 0;
125
+ var high = Math.Min(value.Length, allowedBytes);
126
+ while (low < high)
127
+ {
128
+ var middle = low + (high - low + 1) / 2;
129
+ if (Encoding.UTF8.GetByteCount(value, 0, middle) <= allowedBytes) low = middle;
130
+ else high = middle - 1;
131
+ }
132
+ if (low > 0 && low < value.Length && char.IsHighSurrogate(value[low - 1]) && char.IsLowSurrogate(value[low])) low--;
133
+ if (low < value.Length) truncated = true;
134
+ if (low == value.Length)
135
+ {
136
+ remaining -= Encoding.UTF8.GetByteCount(value, 0, low);
137
+ return value;
138
+ }
139
+ var bounded = value.Substring(0, low);
140
+ remaining -= Encoding.UTF8.GetByteCount(bounded, 0, bounded.Length);
141
+ return bounded;
142
+ }
143
+
144
+ private sealed class ReferenceComparer : IEqualityComparer<Exception>
145
+ {
146
+ internal static readonly ReferenceComparer Instance = new ReferenceComparer();
147
+ public bool Equals(Exception left, Exception right) { return ReferenceEquals(left, right); }
148
+ public int GetHashCode(Exception value) { return RuntimeHelpers.GetHashCode(value); }
149
+ }
150
+ }
151
+ }
@@ -0,0 +1,30 @@
1
+ using System;
2
+
3
+ namespace UnityCli
4
+ {
5
+ /// <summary>队列map与队列节点的原子publication骨架;任一阶段失败都回滚已发布部分。</summary>
6
+ public static class UnityCliQueuePublication
7
+ {
8
+ public static void Publish(Action addMap, Action addQueue, Action removeMap, Action removeQueue, Action markPublished)
9
+ {
10
+ if (addMap == null || addQueue == null || removeMap == null || removeQueue == null || markPublished == null)
11
+ throw new ArgumentNullException("publication action");
12
+ var mapAdded = false;
13
+ var queueAdded = false;
14
+ try
15
+ {
16
+ addMap();
17
+ mapAdded = true;
18
+ addQueue();
19
+ queueAdded = true;
20
+ markPublished();
21
+ }
22
+ catch
23
+ {
24
+ if (queueAdded) { try { removeQueue(); } catch { } }
25
+ if (mapAdded) { try { removeMap(); } catch { } }
26
+ throw;
27
+ }
28
+ }
29
+ }
30
+ }