mcpywrap-core 0.6.2__tar.gz → 0.6.4__tar.gz

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 (263) hide show
  1. {mcpywrap_core-0.6.2 → mcpywrap_core-0.6.4}/PKG-INFO +1 -1
  2. mcpywrap_core-0.6.4/mcpywrap_core/_version.py +1 -0
  3. {mcpywrap_core-0.6.2 → mcpywrap_core-0.6.4}/mcpywrap_core/api.py +6 -6
  4. {mcpywrap_core-0.6.2 → mcpywrap_core-0.6.4}/mcpywrap_core/builders/assembly.py +14 -0
  5. {mcpywrap_core-0.6.2 → mcpywrap_core-0.6.4}/mcpywrap_core/builders/dependency_manager.py +59 -6
  6. mcpywrap_core-0.6.4/mcpywrap_core/builders/output_lock.py +46 -0
  7. {mcpywrap_core-0.6.2 → mcpywrap_core-0.6.4}/mcpywrap_core/builders/project_builder.py +19 -4
  8. {mcpywrap_core-0.6.2 → mcpywrap_core-0.6.4}/mcpywrap_core/builders/watcher.py +7 -2
  9. {mcpywrap_core-0.6.2 → mcpywrap_core-0.6.4}/mcpywrap_core/cli.py +1 -1
  10. {mcpywrap_core-0.6.2 → mcpywrap_core-0.6.4}/mcpywrap_core/command_context.py +2 -2
  11. {mcpywrap_core-0.6.2 → mcpywrap_core-0.6.4}/mcpywrap_core/commands/add_cmd.py +26 -6
  12. {mcpywrap_core-0.6.2 → mcpywrap_core-0.6.4}/mcpywrap_core/commands/build_cmd.py +2 -0
  13. {mcpywrap_core-0.6.2 → mcpywrap_core-0.6.4}/mcpywrap_core/commands/dependency_prompt.py +2 -0
  14. mcpywrap_core-0.6.4/mcpywrap_core/commands/deps_cmd.py +27 -0
  15. {mcpywrap_core-0.6.2 → mcpywrap_core-0.6.4}/mcpywrap_core/commands/dev_cmd.py +36 -31
  16. {mcpywrap_core-0.6.2 → mcpywrap_core-0.6.4}/mcpywrap_core/commands/package_cmd.py +2 -0
  17. {mcpywrap_core-0.6.2 → mcpywrap_core-0.6.4}/mcpywrap_core/commands/remove_cmd.py +8 -2
  18. {mcpywrap_core-0.6.2 → mcpywrap_core-0.6.4}/mcpywrap_core/commands/run_cmd.py +12 -3
  19. {mcpywrap_core-0.6.2 → mcpywrap_core-0.6.4}/mcpywrap_core/commands/sync_cmd.py +5 -2
  20. {mcpywrap_core-0.6.2 → mcpywrap_core-0.6.4}/mcpywrap_core/consumer_prepare.py +7 -2
  21. {mcpywrap_core-0.6.2 → mcpywrap_core-0.6.4}/mcpywrap_core/dependencies.py +94 -15
  22. mcpywrap_core-0.6.4/mcpywrap_core/dependency_feedback.py +29 -0
  23. {mcpywrap_core-0.6.2 → mcpywrap_core-0.6.4}/mcpywrap_core/engines/install.py +1 -1
  24. {mcpywrap_core-0.6.2 → mcpywrap_core-0.6.4}/mcpywrap_core/engines/windows.py +49 -6
  25. {mcpywrap_core-0.6.2 → mcpywrap_core-0.6.4}/mcpywrap_core/frameworks.py +2 -1
  26. {mcpywrap_core-0.6.2 → mcpywrap_core-0.6.4}/mcpywrap_core/git_projects.py +103 -26
  27. mcpywrap_core-0.6.4/mcpywrap_core/mcstudio/lan_locator.py +94 -0
  28. mcpywrap_core-0.6.4/mcpywrap_core/mcstudio/lan_memory.py +142 -0
  29. mcpywrap_core-0.6.4/mcpywrap_core/mcstudio/lan_window.py +35 -0
  30. {mcpywrap_core-0.6.2 → mcpywrap_core-0.6.4}/mcpywrap_core/mcstudio/runtime_debug.py +7 -0
  31. {mcpywrap_core-0.6.2 → mcpywrap_core-0.6.4}/mcpywrap_core/mcstudio/sessions.py +6 -2
  32. {mcpywrap_core-0.6.2 → mcpywrap_core-0.6.4}/mcpywrap_core/mobile_host/client.py +2 -2
  33. {mcpywrap_core-0.6.2 → mcpywrap_core-0.6.4}/mcpywrap_core/mobile_host/intervention.py +2 -2
  34. {mcpywrap_core-0.6.2 → mcpywrap_core-0.6.4}/mcpywrap_core/mobile_host/routing.py +18 -0
  35. {mcpywrap_core-0.6.2 → mcpywrap_core-0.6.4}/mcpywrap_core/operations/build.py +18 -10
  36. {mcpywrap_core-0.6.2 → mcpywrap_core-0.6.4}/mcpywrap_core/operations/package.py +3 -3
  37. {mcpywrap_core-0.6.2 → mcpywrap_core-0.6.4}/mcpywrap_core/operations/project.py +13 -4
  38. {mcpywrap_core-0.6.2 → mcpywrap_core-0.6.4}/mcpywrap_core/operations/sync.py +10 -8
  39. {mcpywrap_core-0.6.2 → mcpywrap_core-0.6.4}/mcpywrap_core/project_dependencies.py +46 -5
  40. {mcpywrap_core-0.6.2 → mcpywrap_core-0.6.4}/mcpywrap_core/project_scripts.py +6 -4
  41. {mcpywrap_core-0.6.2 → mcpywrap_core-0.6.4}/mcpywrap_core/remote/service.py +1 -1
  42. {mcpywrap_core-0.6.2 → mcpywrap_core-0.6.4}/mcpywrap_core/runtime/deployment.py +1 -1
  43. {mcpywrap_core-0.6.2 → mcpywrap_core-0.6.4}/mcpywrap_core/runtime/groups.py +52 -9
  44. mcpywrap_core-0.6.4/mcpywrap_core/runtime/lan_menu.py +72 -0
  45. {mcpywrap_core-0.6.2 → mcpywrap_core-0.6.4}/mcpywrap_core/runtime/preparation.py +3 -1
  46. {mcpywrap_core-0.6.2 → mcpywrap_core-0.6.4}/mcpywrap_core/runtime/profiles.py +1 -1
  47. mcpywrap_core-0.6.4/mcpywrap_core/runtime/windows_join.py +193 -0
  48. {mcpywrap_core-0.6.2 → mcpywrap_core-0.6.4}/mcpywrap_core/skill/SKILL.md +2 -1
  49. {mcpywrap_core-0.6.2 → mcpywrap_core-0.6.4}/mcpywrap_core/skill/references/application-host.md +10 -6
  50. {mcpywrap_core-0.6.2 → mcpywrap_core-0.6.4}/mcpywrap_core/skill/references/consumer-prepare.md +2 -0
  51. {mcpywrap_core-0.6.2 → mcpywrap_core-0.6.4}/mcpywrap_core/skill/references/dual-clients.md +12 -4
  52. {mcpywrap_core-0.6.2 → mcpywrap_core-0.6.4}/mcpywrap_core/skill/references/macos-local.md +3 -2
  53. {mcpywrap_core-0.6.2 → mcpywrap_core-0.6.4}/mcpywrap_core/skill/references/project-dependencies.md +29 -1
  54. {mcpywrap_core-0.6.2 → mcpywrap_core-0.6.4}/mcpywrap_core/skill/references/project-workflow.md +2 -2
  55. {mcpywrap_core-0.6.2 → mcpywrap_core-0.6.4}/mcpywrap_core/skill/references/troubleshooting.md +3 -0
  56. {mcpywrap_core-0.6.2 → mcpywrap_core-0.6.4}/mcpywrap_core/skill/scripts/bootstrap.py +2 -0
  57. {mcpywrap_core-0.6.2 → mcpywrap_core-0.6.4}/mcpywrap_core/skill/scripts/smoke.py +1 -1
  58. {mcpywrap_core-0.6.2 → mcpywrap_core-0.6.4}/mcpywrap_core/ui/project_ui.py +86 -10
  59. {mcpywrap_core-0.6.2 → mcpywrap_core-0.6.4}/mcpywrap_core/ui/session_views.py +2 -0
  60. {mcpywrap_core-0.6.2 → mcpywrap_core-0.6.4}/mcpywrap_core.egg-info/PKG-INFO +1 -1
  61. {mcpywrap_core-0.6.2 → mcpywrap_core-0.6.4}/mcpywrap_core.egg-info/SOURCES.txt +8 -0
  62. mcpywrap_core-0.6.2/mcpywrap_core/_version.py +0 -1
  63. {mcpywrap_core-0.6.2 → mcpywrap_core-0.6.4}/LICENSE +0 -0
  64. {mcpywrap_core-0.6.2 → mcpywrap_core-0.6.4}/MANIFEST.in +0 -0
  65. {mcpywrap_core-0.6.2 → mcpywrap_core-0.6.4}/README.md +0 -0
  66. {mcpywrap_core-0.6.2 → mcpywrap_core-0.6.4}/THIRD_PARTY_NOTICES.md +0 -0
  67. {mcpywrap_core-0.6.2 → mcpywrap_core-0.6.4}/mcpywrap_core/__init__.py +0 -0
  68. {mcpywrap_core-0.6.2 → mcpywrap_core-0.6.4}/mcpywrap_core/__main__.py +0 -0
  69. {mcpywrap_core-0.6.2 → mcpywrap_core-0.6.4}/mcpywrap_core/_process_identity.py +0 -0
  70. {mcpywrap_core-0.6.2 → mcpywrap_core-0.6.4}/mcpywrap_core/_script_worker.py +0 -0
  71. {mcpywrap_core-0.6.2 → mcpywrap_core-0.6.4}/mcpywrap_core/builders/AddonsPack.py +0 -0
  72. {mcpywrap_core-0.6.2 → mcpywrap_core-0.6.4}/mcpywrap_core/builders/MapPack.py +0 -0
  73. {mcpywrap_core-0.6.2 → mcpywrap_core-0.6.4}/mcpywrap_core/builders/__init__.py +0 -0
  74. {mcpywrap_core-0.6.2 → mcpywrap_core-0.6.4}/mcpywrap_core/builders/file_merge.py +0 -0
  75. {mcpywrap_core-0.6.2 → mcpywrap_core-0.6.4}/mcpywrap_core/code_libraries.py +0 -0
  76. {mcpywrap_core-0.6.2 → mcpywrap_core-0.6.4}/mcpywrap_core/commands/__init__.py +0 -0
  77. {mcpywrap_core-0.6.2 → mcpywrap_core-0.6.4}/mcpywrap_core/commands/connect_cmd.py +0 -0
  78. {mcpywrap_core-0.6.2 → mcpywrap_core-0.6.4}/mcpywrap_core/commands/default_cmd.py +0 -0
  79. {mcpywrap_core-0.6.2 → mcpywrap_core-0.6.4}/mcpywrap_core/commands/deployment_cmd.py +0 -0
  80. {mcpywrap_core-0.6.2 → mcpywrap_core-0.6.4}/mcpywrap_core/commands/deployment_output.py +0 -0
  81. {mcpywrap_core-0.6.2 → mcpywrap_core-0.6.4}/mcpywrap_core/commands/desktop_cmd.py +0 -0
  82. {mcpywrap_core-0.6.2 → mcpywrap_core-0.6.4}/mcpywrap_core/commands/doctor_cmd.py +0 -0
  83. {mcpywrap_core-0.6.2 → mcpywrap_core-0.6.4}/mcpywrap_core/commands/edit_cmd.py +0 -0
  84. {mcpywrap_core-0.6.2 → mcpywrap_core-0.6.4}/mcpywrap_core/commands/engine_cmd.py +0 -0
  85. {mcpywrap_core-0.6.2 → mcpywrap_core-0.6.4}/mcpywrap_core/commands/host_cmd.py +0 -0
  86. {mcpywrap_core-0.6.2 → mcpywrap_core-0.6.4}/mcpywrap_core/commands/init_cmd.py +0 -0
  87. {mcpywrap_core-0.6.2 → mcpywrap_core-0.6.4}/mcpywrap_core/commands/mod_cmd.py +0 -0
  88. {mcpywrap_core-0.6.2 → mcpywrap_core-0.6.4}/mcpywrap_core/commands/modsdk_cmd.py +0 -0
  89. {mcpywrap_core-0.6.2 → mcpywrap_core-0.6.4}/mcpywrap_core/commands/publish_cmd.py +0 -0
  90. {mcpywrap_core-0.6.2 → mcpywrap_core-0.6.4}/mcpywrap_core/commands/record_cmd.py +0 -0
  91. {mcpywrap_core-0.6.2 → mcpywrap_core-0.6.4}/mcpywrap_core/commands/runtime_cmd.py +0 -0
  92. {mcpywrap_core-0.6.2 → mcpywrap_core-0.6.4}/mcpywrap_core/commands/runtime_input_cmd.py +0 -0
  93. {mcpywrap_core-0.6.2 → mcpywrap_core-0.6.4}/mcpywrap_core/commands/runtime_player_cmd.py +0 -0
  94. {mcpywrap_core-0.6.2 → mcpywrap_core-0.6.4}/mcpywrap_core/commands/runtime_ui_cmd.py +0 -0
  95. {mcpywrap_core-0.6.2 → mcpywrap_core-0.6.4}/mcpywrap_core/commands/script_cmd.py +0 -0
  96. {mcpywrap_core-0.6.2 → mcpywrap_core-0.6.4}/mcpywrap_core/commands/serve_cmd.py +0 -0
  97. {mcpywrap_core-0.6.2 → mcpywrap_core-0.6.4}/mcpywrap_core/commands/session_cmd.py +0 -0
  98. {mcpywrap_core-0.6.2 → mcpywrap_core-0.6.4}/mcpywrap_core/commands/skill_cmd.py +0 -0
  99. {mcpywrap_core-0.6.2 → mcpywrap_core-0.6.4}/mcpywrap_core/commands/ui_cmd.py +0 -0
  100. {mcpywrap_core-0.6.2 → mcpywrap_core-0.6.4}/mcpywrap_core/config.py +0 -0
  101. {mcpywrap_core-0.6.2 → mcpywrap_core-0.6.4}/mcpywrap_core/core-contract.json +0 -0
  102. {mcpywrap_core-0.6.2 → mcpywrap_core-0.6.4}/mcpywrap_core/custom_packaging.py +0 -0
  103. {mcpywrap_core-0.6.2 → mcpywrap_core-0.6.4}/mcpywrap_core/engines/__init__.py +0 -0
  104. {mcpywrap_core-0.6.2 → mcpywrap_core-0.6.4}/mcpywrap_core/engines/android_icon.py +0 -0
  105. {mcpywrap_core-0.6.2 → mcpywrap_core-0.6.4}/mcpywrap_core/engines/apk_profile.py +0 -0
  106. {mcpywrap_core-0.6.2 → mcpywrap_core-0.6.4}/mcpywrap_core/engines/backend.py +0 -0
  107. {mcpywrap_core-0.6.2 → mcpywrap_core-0.6.4}/mcpywrap_core/engines/host.py +0 -0
  108. {mcpywrap_core-0.6.2 → mcpywrap_core-0.6.4}/mcpywrap_core/engines/macos.py +0 -0
  109. {mcpywrap_core-0.6.2 → mcpywrap_core-0.6.4}/mcpywrap_core/engines/macos_icons.py +0 -0
  110. {mcpywrap_core-0.6.2 → mcpywrap_core-0.6.4}/mcpywrap_core/engines/macos_network.py +0 -0
  111. {mcpywrap_core-0.6.2 → mcpywrap_core-0.6.4}/mcpywrap_core/engines/official.py +0 -0
  112. {mcpywrap_core-0.6.2 → mcpywrap_core-0.6.4}/mcpywrap_core/engines/preferences.py +0 -0
  113. {mcpywrap_core-0.6.2 → mcpywrap_core-0.6.4}/mcpywrap_core/engines/tui.py +0 -0
  114. {mcpywrap_core-0.6.2 → mcpywrap_core-0.6.4}/mcpywrap_core/framework_presets.py +0 -0
  115. {mcpywrap_core-0.6.2 → mcpywrap_core-0.6.4}/mcpywrap_core/git_cache.py +0 -0
  116. {mcpywrap_core-0.6.2 → mcpywrap_core-0.6.4}/mcpywrap_core/host.py +0 -0
  117. {mcpywrap_core-0.6.2 → mcpywrap_core-0.6.4}/mcpywrap_core/host_assets.py +0 -0
  118. {mcpywrap_core-0.6.2 → mcpywrap_core-0.6.4}/mcpywrap_core/input_executor.py +0 -0
  119. {mcpywrap_core-0.6.2 → mcpywrap_core-0.6.4}/mcpywrap_core/input_plan.py +0 -0
  120. {mcpywrap_core-0.6.2 → mcpywrap_core-0.6.4}/mcpywrap_core/mcstudio/SimpleMonitor.py +0 -0
  121. {mcpywrap_core-0.6.2 → mcpywrap_core-0.6.4}/mcpywrap_core/mcstudio/__init__.py +0 -0
  122. {mcpywrap_core-0.6.2 → mcpywrap_core-0.6.4}/mcpywrap_core/mcstudio/auth_interaction.py +0 -0
  123. {mcpywrap_core-0.6.2 → mcpywrap_core-0.6.4}/mcpywrap_core/mcstudio/bridge_assets.py +0 -0
  124. {mcpywrap_core-0.6.2 → mcpywrap_core-0.6.4}/mcpywrap_core/mcstudio/deployment_links.py +0 -0
  125. {mcpywrap_core-0.6.2 → mcpywrap_core-0.6.4}/mcpywrap_core/mcstudio/diagnostics.py +0 -0
  126. {mcpywrap_core-0.6.2 → mcpywrap_core-0.6.4}/mcpywrap_core/mcstudio/discovery.py +0 -0
  127. {mcpywrap_core-0.6.2 → mcpywrap_core-0.6.4}/mcpywrap_core/mcstudio/editor.py +0 -0
  128. {mcpywrap_core-0.6.2 → mcpywrap_core-0.6.4}/mcpywrap_core/mcstudio/file_logs.py +0 -0
  129. {mcpywrap_core-0.6.2 → mcpywrap_core-0.6.4}/mcpywrap_core/mcstudio/game.py +0 -0
  130. {mcpywrap_core-0.6.2 → mcpywrap_core-0.6.4}/mcpywrap_core/mcstudio/host_input.py +0 -0
  131. {mcpywrap_core-0.6.2 → mcpywrap_core-0.6.4}/mcpywrap_core/mcstudio/hot_reload.py +0 -0
  132. {mcpywrap_core-0.6.2 → mcpywrap_core-0.6.4}/mcpywrap_core/mcstudio/image.py +0 -0
  133. {mcpywrap_core-0.6.2 → mcpywrap_core-0.6.4}/mcpywrap_core/mcstudio/input_sequence.py +0 -0
  134. {mcpywrap_core-0.6.2 → mcpywrap_core-0.6.4}/mcpywrap_core/mcstudio/launcher_control.py +0 -0
  135. {mcpywrap_core-0.6.2 → mcpywrap_core-0.6.4}/mcpywrap_core/mcstudio/launcher_python.py +0 -0
  136. {mcpywrap_core-0.6.2 → mcpywrap_core-0.6.4}/mcpywrap_core/mcstudio/log_colorizer.py +0 -0
  137. {mcpywrap_core-0.6.2 → mcpywrap_core-0.6.4}/mcpywrap_core/mcstudio/log_protocol.py +0 -0
  138. {mcpywrap_core-0.6.2 → mcpywrap_core-0.6.4}/mcpywrap_core/mcstudio/log_query.py +0 -0
  139. {mcpywrap_core-0.6.2 → mcpywrap_core-0.6.4}/mcpywrap_core/mcstudio/log_stream.py +0 -0
  140. {mcpywrap_core-0.6.2 → mcpywrap_core-0.6.4}/mcpywrap_core/mcstudio/mcs.py +0 -0
  141. {mcpywrap_core-0.6.2 → mcpywrap_core-0.6.4}/mcpywrap_core/mcstudio/mcs_auth.py +0 -0
  142. {mcpywrap_core-0.6.2 → mcpywrap_core-0.6.4}/mcpywrap_core/mcstudio/network.py +0 -0
  143. {mcpywrap_core-0.6.2 → mcpywrap_core-0.6.4}/mcpywrap_core/mcstudio/private_logs.py +0 -0
  144. {mcpywrap_core-0.6.2 → mcpywrap_core-0.6.4}/mcpywrap_core/mcstudio/processes.py +0 -0
  145. {mcpywrap_core-0.6.2 → mcpywrap_core-0.6.4}/mcpywrap_core/mcstudio/recording_worker.py +0 -0
  146. {mcpywrap_core-0.6.2 → mcpywrap_core-0.6.4}/mcpywrap_core/mcstudio/recordings.py +0 -0
  147. {mcpywrap_core-0.6.2 → mcpywrap_core-0.6.4}/mcpywrap_core/mcstudio/runtime_cppconfig.py +0 -0
  148. {mcpywrap_core-0.6.2 → mcpywrap_core-0.6.4}/mcpywrap_core/mcstudio/runtime_input_payload.py +0 -0
  149. {mcpywrap_core-0.6.2 → mcpywrap_core-0.6.4}/mcpywrap_core/mcstudio/runtime_key_timeline_payload.py +0 -0
  150. {mcpywrap_core-0.6.2 → mcpywrap_core-0.6.4}/mcpywrap_core/mcstudio/runtime_player_payload.py +0 -0
  151. {mcpywrap_core-0.6.2 → mcpywrap_core-0.6.4}/mcpywrap_core/mcstudio/runtime_ui.py +0 -0
  152. {mcpywrap_core-0.6.2 → mcpywrap_core-0.6.4}/mcpywrap_core/mcstudio/runtime_ui_outline.py +0 -0
  153. {mcpywrap_core-0.6.2 → mcpywrap_core-0.6.4}/mcpywrap_core/mcstudio/runtime_ui_payload.py +0 -0
  154. {mcpywrap_core-0.6.2 → mcpywrap_core-0.6.4}/mcpywrap_core/mcstudio/screenshot.py +0 -0
  155. {mcpywrap_core-0.6.2 → mcpywrap_core-0.6.4}/mcpywrap_core/mcstudio/session_capabilities.py +0 -0
  156. {mcpywrap_core-0.6.2 → mcpywrap_core-0.6.4}/mcpywrap_core/mcstudio/session_worker.py +0 -0
  157. {mcpywrap_core-0.6.2 → mcpywrap_core-0.6.4}/mcpywrap_core/mcstudio/studio_server.py +0 -0
  158. {mcpywrap_core-0.6.2 → mcpywrap_core-0.6.4}/mcpywrap_core/mcstudio/studio_server_ui.py +0 -0
  159. {mcpywrap_core-0.6.2 → mcpywrap_core-0.6.4}/mcpywrap_core/mcstudio/symlink_helper_global.py +0 -0
  160. {mcpywrap_core-0.6.2 → mcpywrap_core-0.6.4}/mcpywrap_core/mcstudio/symlink_helper_map.py +0 -0
  161. {mcpywrap_core-0.6.2 → mcpywrap_core-0.6.4}/mcpywrap_core/mcstudio/symlinks.py +0 -0
  162. {mcpywrap_core-0.6.2 → mcpywrap_core-0.6.4}/mcpywrap_core/mcstudio/unified_input.py +0 -0
  163. {mcpywrap_core-0.6.2 → mcpywrap_core-0.6.4}/mcpywrap_core/mcstudio/window.py +0 -0
  164. {mcpywrap_core-0.6.2 → mcpywrap_core-0.6.4}/mcpywrap_core/mcstudio/window_activation.py +0 -0
  165. {mcpywrap_core-0.6.2 → mcpywrap_core-0.6.4}/mcpywrap_core/minecraft/__init__.py +0 -0
  166. {mcpywrap_core-0.6.2 → mcpywrap_core-0.6.4}/mcpywrap_core/minecraft/addons.py +0 -0
  167. {mcpywrap_core-0.6.2 → mcpywrap_core-0.6.4}/mcpywrap_core/minecraft/level_dat.py +0 -0
  168. {mcpywrap_core-0.6.2 → mcpywrap_core-0.6.4}/mcpywrap_core/minecraft/map.py +0 -0
  169. {mcpywrap_core-0.6.2 → mcpywrap_core-0.6.4}/mcpywrap_core/minecraft/modsdk_environment.py +0 -0
  170. {mcpywrap_core-0.6.2 → mcpywrap_core-0.6.4}/mcpywrap_core/minecraft/modsdk_versions.py +0 -0
  171. {mcpywrap_core-0.6.2 → mcpywrap_core-0.6.4}/mcpywrap_core/minecraft/netease_modsdk.py +0 -0
  172. {mcpywrap_core-0.6.2 → mcpywrap_core-0.6.4}/mcpywrap_core/minecraft/template/generate_mod_files.py +0 -0
  173. {mcpywrap_core-0.6.2 → mcpywrap_core-0.6.4}/mcpywrap_core/minecraft/template/mod_template.py +0 -0
  174. {mcpywrap_core-0.6.2 → mcpywrap_core-0.6.4}/mcpywrap_core/mobile_host/__init__.py +0 -0
  175. {mcpywrap_core-0.6.2 → mcpywrap_core-0.6.4}/mcpywrap_core/mobile_host/options.py +0 -0
  176. {mcpywrap_core-0.6.2 → mcpywrap_core-0.6.4}/mcpywrap_core/mobile_host/preparation.py +0 -0
  177. {mcpywrap_core-0.6.2 → mcpywrap_core-0.6.4}/mcpywrap_core/mobile_host/profiles.py +0 -0
  178. {mcpywrap_core-0.6.2 → mcpywrap_core-0.6.4}/mcpywrap_core/mobile_host/receipts.py +0 -0
  179. {mcpywrap_core-0.6.2 → mcpywrap_core-0.6.4}/mcpywrap_core/mobile_host/streams.py +0 -0
  180. {mcpywrap_core-0.6.2 → mcpywrap_core-0.6.4}/mcpywrap_core/operations/__init__.py +0 -0
  181. {mcpywrap_core-0.6.2 → mcpywrap_core-0.6.4}/mcpywrap_core/operations/input_snapshot.py +0 -0
  182. {mcpywrap_core-0.6.2 → mcpywrap_core-0.6.4}/mcpywrap_core/prepare_environment.py +0 -0
  183. {mcpywrap_core-0.6.2 → mcpywrap_core-0.6.4}/mcpywrap_core/project_init.py +0 -0
  184. {mcpywrap_core-0.6.2 → mcpywrap_core-0.6.4}/mcpywrap_core/recording_io.py +0 -0
  185. {mcpywrap_core-0.6.2 → mcpywrap_core-0.6.4}/mcpywrap_core/remote/__init__.py +0 -0
  186. {mcpywrap_core-0.6.2 → mcpywrap_core-0.6.4}/mcpywrap_core/remote/client.py +0 -0
  187. {mcpywrap_core-0.6.2 → mcpywrap_core-0.6.4}/mcpywrap_core/remote/http_server.py +0 -0
  188. {mcpywrap_core-0.6.2 → mcpywrap_core-0.6.4}/mcpywrap_core/remote/protocol.py +0 -0
  189. {mcpywrap_core-0.6.2 → mcpywrap_core-0.6.4}/mcpywrap_core/runtime/__init__.py +0 -0
  190. {mcpywrap_core-0.6.2 → mcpywrap_core-0.6.4}/mcpywrap_core/runtime/deployment_inspection.py +0 -0
  191. {mcpywrap_core-0.6.2 → mcpywrap_core-0.6.4}/mcpywrap_core/runtime/deployment_service.py +0 -0
  192. {mcpywrap_core-0.6.2 → mcpywrap_core-0.6.4}/mcpywrap_core/runtime/diagnostics.py +0 -0
  193. {mcpywrap_core-0.6.2 → mcpywrap_core-0.6.4}/mcpywrap_core/runtime/instances.py +0 -0
  194. {mcpywrap_core-0.6.2 → mcpywrap_core-0.6.4}/mcpywrap_core/runtime/native.py +0 -0
  195. {mcpywrap_core-0.6.2 → mcpywrap_core-0.6.4}/mcpywrap_core/runtime/occupancy.py +0 -0
  196. {mcpywrap_core-0.6.2 → mcpywrap_core-0.6.4}/mcpywrap_core/runtime/storage.py +0 -0
  197. {mcpywrap_core-0.6.2 → mcpywrap_core-0.6.4}/mcpywrap_core/runtime/targets.py +0 -0
  198. {mcpywrap_core-0.6.2 → mcpywrap_core-0.6.4}/mcpywrap_core/runtime/watch.py +0 -0
  199. {mcpywrap_core-0.6.2 → mcpywrap_core-0.6.4}/mcpywrap_core/runtime/window_policy.py +0 -0
  200. {mcpywrap_core-0.6.2 → mcpywrap_core-0.6.4}/mcpywrap_core/runtime/windows.py +0 -0
  201. {mcpywrap_core-0.6.2 → mcpywrap_core-0.6.4}/mcpywrap_core/skill/agents/openai.yaml +0 -0
  202. {mcpywrap_core-0.6.2 → mcpywrap_core-0.6.4}/mcpywrap_core/skill/assets/consumer-prepare/framework/behavior_pack/CatalogRuntime/__init__.py +0 -0
  203. {mcpywrap_core-0.6.2 → mcpywrap_core-0.6.4}/mcpywrap_core/skill/assets/consumer-prepare/framework/behavior_pack/manifest.json +0 -0
  204. {mcpywrap_core-0.6.2 → mcpywrap_core-0.6.4}/mcpywrap_core/skill/assets/consumer-prepare/framework/build_tools/example.toml +0 -0
  205. {mcpywrap_core-0.6.2 → mcpywrap_core-0.6.4}/mcpywrap_core/skill/assets/consumer-prepare/framework/build_tools/prepare.py +0 -0
  206. {mcpywrap_core-0.6.2 → mcpywrap_core-0.6.4}/mcpywrap_core/skill/assets/consumer-prepare/framework/build_tools/schema.json +0 -0
  207. {mcpywrap_core-0.6.2 → mcpywrap_core-0.6.4}/mcpywrap_core/skill/assets/consumer-prepare/framework/pyproject.toml +0 -0
  208. {mcpywrap_core-0.6.2 → mcpywrap_core-0.6.4}/mcpywrap_core/skill/assets/consumer-prepare/game/.gitignore +0 -0
  209. {mcpywrap_core-0.6.2 → mcpywrap_core-0.6.4}/mcpywrap_core/skill/assets/consumer-prepare/game/behavior_pack/manifest.json +0 -0
  210. {mcpywrap_core-0.6.2 → mcpywrap_core-0.6.4}/mcpywrap_core/skill/assets/consumer-prepare/game/data/items.json +0 -0
  211. {mcpywrap_core-0.6.2 → mcpywrap_core-0.6.4}/mcpywrap_core/skill/assets/consumer-prepare/game/pyproject.toml +0 -0
  212. {mcpywrap_core-0.6.2 → mcpywrap_core-0.6.4}/mcpywrap_core/skill/assets/consumer-prepare/game/resource_pack/manifest.json +0 -0
  213. {mcpywrap_core-0.6.2 → mcpywrap_core-0.6.4}/mcpywrap_core/skill/references/capture.md +0 -0
  214. {mcpywrap_core-0.6.2 → mcpywrap_core-0.6.4}/mcpywrap_core/skill/references/consumer-prepare-author.md +0 -0
  215. {mcpywrap_core-0.6.2 → mcpywrap_core-0.6.4}/mcpywrap_core/skill/references/input-sequence.md +0 -0
  216. {mcpywrap_core-0.6.2 → mcpywrap_core-0.6.4}/mcpywrap_core/skill/references/input-writing.md +0 -0
  217. {mcpywrap_core-0.6.2 → mcpywrap_core-0.6.4}/mcpywrap_core/skill/references/instance-world-settings.md +0 -0
  218. {mcpywrap_core-0.6.2 → mcpywrap_core-0.6.4}/mcpywrap_core/skill/references/local-development.md +0 -0
  219. {mcpywrap_core-0.6.2 → mcpywrap_core-0.6.4}/mcpywrap_core/skill/references/network-sessions.md +0 -0
  220. {mcpywrap_core-0.6.2 → mcpywrap_core-0.6.4}/mcpywrap_core/skill/references/project-scripts.md +0 -0
  221. {mcpywrap_core-0.6.2 → mcpywrap_core-0.6.4}/mcpywrap_core/skill/references/remote-testing.md +0 -0
  222. {mcpywrap_core-0.6.2 → mcpywrap_core-0.6.4}/mcpywrap_core/skill/references/runtime-debug.md +0 -0
  223. {mcpywrap_core-0.6.2 → mcpywrap_core-0.6.4}/mcpywrap_core/skill/references/runtime-input.md +0 -0
  224. {mcpywrap_core-0.6.2 → mcpywrap_core-0.6.4}/mcpywrap_core/skill/references/runtime-key-timeline.md +0 -0
  225. {mcpywrap_core-0.6.2 → mcpywrap_core-0.6.4}/mcpywrap_core/skill/references/runtime-player.md +0 -0
  226. {mcpywrap_core-0.6.2 → mcpywrap_core-0.6.4}/mcpywrap_core/skill/references/runtime-ui.md +0 -0
  227. {mcpywrap_core-0.6.2 → mcpywrap_core-0.6.4}/mcpywrap_core/skill/references/script-example.md +0 -0
  228. {mcpywrap_core-0.6.2 → mcpywrap_core-0.6.4}/mcpywrap_core/skill/references/setup.md +0 -0
  229. {mcpywrap_core-0.6.2 → mcpywrap_core-0.6.4}/mcpywrap_core/skill/scripts/bootstrap.ps1 +0 -0
  230. {mcpywrap_core-0.6.2 → mcpywrap_core-0.6.4}/mcpywrap_core/skill/scripts/game_window.py +0 -0
  231. {mcpywrap_core-0.6.2 → mcpywrap_core-0.6.4}/mcpywrap_core/source_files.py +0 -0
  232. {mcpywrap_core-0.6.2 → mcpywrap_core-0.6.4}/mcpywrap_core/timeline.py +0 -0
  233. {mcpywrap_core-0.6.2 → mcpywrap_core-0.6.4}/mcpywrap_core/ui/__init__.py +0 -0
  234. {mcpywrap_core-0.6.2 → mcpywrap_core-0.6.4}/mcpywrap_core/ui/application.py +0 -0
  235. {mcpywrap_core-0.6.2 → mcpywrap_core-0.6.4}/mcpywrap_core/ui/assets/mcpy.icns +0 -0
  236. {mcpywrap_core-0.6.2 → mcpywrap_core-0.6.4}/mcpywrap_core/ui/assets/mcpy.icon/Assets/01-cube.svg +0 -0
  237. {mcpywrap_core-0.6.2 → mcpywrap_core-0.6.4}/mcpywrap_core/ui/assets/mcpy.icon/Assets/02-prompt.svg +0 -0
  238. {mcpywrap_core-0.6.2 → mcpywrap_core-0.6.4}/mcpywrap_core/ui/assets/mcpy.icon/icon.json +0 -0
  239. {mcpywrap_core-0.6.2 → mcpywrap_core-0.6.4}/mcpywrap_core/ui/assets/mcpy.png +0 -0
  240. {mcpywrap_core-0.6.2 → mcpywrap_core-0.6.4}/mcpywrap_core/ui/engine_setup.py +0 -0
  241. {mcpywrap_core-0.6.2 → mcpywrap_core-0.6.4}/mcpywrap_core/ui/log_view.py +0 -0
  242. {mcpywrap_core-0.6.2 → mcpywrap_core-0.6.4}/mcpywrap_core/ui/log_window.py +0 -0
  243. {mcpywrap_core-0.6.2 → mcpywrap_core-0.6.4}/mcpywrap_core/ui/run_session.py +0 -0
  244. {mcpywrap_core-0.6.2 → mcpywrap_core-0.6.4}/mcpywrap_core/ui/session_controller.py +0 -0
  245. {mcpywrap_core-0.6.2 → mcpywrap_core-0.6.4}/mcpywrap_core/ui/session_tools.py +0 -0
  246. {mcpywrap_core-0.6.2 → mcpywrap_core-0.6.4}/mcpywrap_core/ui/world_config.py +0 -0
  247. {mcpywrap_core-0.6.2 → mcpywrap_core-0.6.4}/mcpywrap_core/utils/__init__.py +0 -0
  248. {mcpywrap_core-0.6.2 → mcpywrap_core-0.6.4}/mcpywrap_core/utils/console.py +0 -0
  249. {mcpywrap_core-0.6.2 → mcpywrap_core-0.6.4}/mcpywrap_core/utils/link_snapshot.py +0 -0
  250. {mcpywrap_core-0.6.2 → mcpywrap_core-0.6.4}/mcpywrap_core/utils/locks.py +0 -0
  251. {mcpywrap_core-0.6.2 → mcpywrap_core-0.6.4}/mcpywrap_core/utils/paths.py +0 -0
  252. {mcpywrap_core-0.6.2 → mcpywrap_core-0.6.4}/mcpywrap_core/utils/pip_error_parser.py +0 -0
  253. {mcpywrap_core-0.6.2 → mcpywrap_core-0.6.4}/mcpywrap_core/utils/print_guide.py +0 -0
  254. {mcpywrap_core-0.6.2 → mcpywrap_core-0.6.4}/mcpywrap_core/utils/project_setup.py +0 -0
  255. {mcpywrap_core-0.6.2 → mcpywrap_core-0.6.4}/mcpywrap_core/utils/utils.py +0 -0
  256. {mcpywrap_core-0.6.2 → mcpywrap_core-0.6.4}/mcpywrap_core.egg-info/dependency_links.txt +0 -0
  257. {mcpywrap_core-0.6.2 → mcpywrap_core-0.6.4}/mcpywrap_core.egg-info/requires.txt +0 -0
  258. {mcpywrap_core-0.6.2 → mcpywrap_core-0.6.4}/mcpywrap_core.egg-info/top_level.txt +0 -0
  259. {mcpywrap_core-0.6.2 → mcpywrap_core-0.6.4}/mcpywrap_host/__init__.py +0 -0
  260. {mcpywrap_core-0.6.2 → mcpywrap_core-0.6.4}/mcpywrap_host/store.py +0 -0
  261. {mcpywrap_core-0.6.2 → mcpywrap_core-0.6.4}/pyproject.toml +0 -0
  262. {mcpywrap_core-0.6.2 → mcpywrap_core-0.6.4}/setup.cfg +0 -0
  263. {mcpywrap_core-0.6.2 → mcpywrap_core-0.6.4}/setup.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: mcpywrap-core
3
- Version: 0.6.2
3
+ Version: 0.6.4
4
4
  Summary: Shared mcpy project dependency, build and runtime logic
5
5
  Author-email: boybook <boybook@easecation.net>
6
6
  License-Expression: MIT
@@ -0,0 +1 @@
1
+ __version__ = '0.6.4'
@@ -16,19 +16,19 @@ class Core:
16
16
 
17
17
  def describe(self):
18
18
  return {'core_api': CORE_API, 'host_api': HOST_API, 'version': __version__,
19
- 'operations': list(OPERATIONS), 'capabilities': self.host.capabilities()}
19
+ 'operations': list(OPERATIONS), 'capabilities': {**self.host.capabilities(), 'unbundled-dependencies': True}}
20
20
 
21
21
  def execute(self, operation, project, **options):
22
22
  """Execute or raise the original structured error; never invoke another core."""
23
23
  if operation not in OPERATIONS:
24
24
  raise ValueError('未知工程操作:' + str(operation))
25
- allowed = OPTIONS[operation] if operation in OPTIONS else {'resolve': set(), 'build': {'merge'}, 'package': {'merge'},
26
- 'sync': {'install', 'migrate_windows_lock'}}[operation]
25
+ allowed = OPTIONS[operation] if operation in OPTIONS else {'resolve': {'bundled_only'}, 'build': {'merge'}, 'package': {'merge'},
26
+ 'sync': {'install', 'migrate_windows_lock', 'bundled_only'}}[operation]
27
27
  if set(options) - allowed or (operation not in OPTIONS and any(type(value) is not bool for value in options.values())):
28
28
  raise ValueError('无效的工程操作参数')
29
29
  if operation in OPTIONS:
30
30
  for name,value in options.items():
31
- valid = (type(value) is bool if name=='effective' else
31
+ valid = (type(value) is bool if name in ('effective', 'unbundled') else
32
32
  isinstance(value,(list,tuple)) and all(isinstance(item,str) for item in value) if name=='args' else
33
33
  value is None or isinstance(value,str))
34
34
  if not valid: raise ValueError('无效的工程操作参数:'+name)
@@ -45,10 +45,10 @@ class Core:
45
45
  result = execute(operation, project, options)
46
46
  elif operation == 'resolve':
47
47
  from .dependencies import DependencyService
48
- manager = DependencyService(project).resolve()
48
+ manager = DependencyService(project).resolve(purpose="release" if options.get("bundled_only") else "runtime")
49
49
  result = {'project': str(project), 'dependencies': [
50
50
  {'name': pack.pkg_name, 'path': str(pack.path)}
51
- for pack in manager.get_all_dependencies().values()], 'warnings': manager.warnings}
51
+ for pack in manager.get_all_dependencies().values()], 'warnings': manager.warnings, 'dependency_selection': manager.selection()}
52
52
  elif operation == 'build':
53
53
  from .operations.build import build_project
54
54
  result = build_project(project, **options)
@@ -84,6 +84,20 @@ def rebuild_file(packs, kind, relative, destination):
84
84
  shutil.copy2(source, destination)
85
85
 
86
86
 
87
+ def validate_unbundled_overrides(packs):
88
+ owners = {}
89
+ for pack in packs:
90
+ for relative in pack_files(pack, 'behavior'):
91
+ if not relative.endswith('.py'):
92
+ continue
93
+ module = relative[:-len('/__init__.py')] if relative.endswith('/__init__.py') else relative[:-3]
94
+ key = module.casefold()
95
+ for previous in owners.get(key, []):
96
+ if getattr(previous, 'unbundled', False) != getattr(pack, 'unbundled', False):
97
+ raise DependencyError('unbundled 依赖不能覆盖随发布的 Python 模块: ' + relative + '\n来源: ' + str(previous.path) + ' / ' + str(pack.path))
98
+ owners.setdefault(key, []).append(pack)
99
+
100
+
87
101
  def assemble_addon(packs, target_pack):
88
102
  for kind in ('behavior', 'resource'):
89
103
  target = getattr(target_pack, kind + '_pack_dir')
@@ -71,6 +71,9 @@ class DependencyManager:
71
71
  self._git_sources = {}
72
72
  self.collect_errors = False
73
73
  self.has_git_projects = False
74
+ self.purpose = "runtime"
75
+ self.edges = []
76
+ self.excluded = []
74
77
 
75
78
  def find_dependency_path(self, package_name):
76
79
  try:
@@ -80,8 +83,10 @@ class DependencyManager:
80
83
  direct = dist.read_text('direct_url.json')
81
84
  return _local_url(json.loads(direct).get('url', '')) if direct else None
82
85
 
83
- def build_dependency_tree(self, project_name, project_path, dependencies=None, *, config=None, allow_missing=False, git_lock=None, collect_errors=False):
86
+ def build_dependency_tree(self, project_name, project_path, dependencies=None, *, config=None, allow_missing=False, git_lock=None, collect_errors=False, purpose="runtime"):
84
87
  self.__init__()
88
+ from ..dependencies import validate_purpose
89
+ self.purpose = validate_purpose(purpose)
85
90
  self.collect_errors = collect_errors
86
91
  project_path = str(Path(project_path).resolve())
87
92
  if git_lock is not None:
@@ -101,18 +106,39 @@ class DependencyManager:
101
106
  self._active.append(key)
102
107
  self._process(root, config)
103
108
  self._active.pop()
109
+ self.bundled_nodes = {id(root)}
110
+ pending = [root]
111
+ while pending:
112
+ current = pending.pop()
113
+ for owner, child, unbundled in self.edges:
114
+ if owner is current and not unbundled and id(child) not in self.bundled_nodes:
115
+ self.bundled_nodes.add(id(child))
116
+ pending.append(child)
117
+ for node in self._ordered:
118
+ node.unbundled = id(node) not in self.bundled_nodes
119
+ node.addon_pack.unbundled = node.unbundled
104
120
  self.dependency_map = {canonical_path(n.addon_pack.path): n.addon_pack for n in self._ordered}
105
121
  if self.errors and not (allow_missing or collect_errors):
106
122
  raise DependencyError('\n'.join(self.errors))
107
123
  return root
108
124
 
109
125
  def _process(self, parent, config):
126
+ local_paths = {}
110
127
  for entry in declarations(config):
111
128
  source = parent.addon_pack.path
129
+ if entry.unbundled and (parent is not self.root_node or self.purpose == 'release'):
130
+ self.excluded.append({'source': str(source), 'dependency': entry.value, 'unbundled': True,
131
+ 'reason': 'unbundled' if parent is self.root_node else 'dependency_unbundled'})
132
+ self._status(source, entry, 'excluded', 'unbundled 依赖不进入 build/package,也不向消费者传递')
133
+ continue
112
134
  try:
113
135
  if entry.kind == 'local':
114
136
  path = str(resolve_path(source, entry.value))
115
- self._visit(parent, path, Path(path).name)
137
+ key = canonical_path(path)
138
+ if key in local_paths and local_paths[key] != entry.unbundled:
139
+ raise DependencyError('同一目录的 unbundled 设置冲突: ' + entry.value)
140
+ local_paths[key] = entry.unbundled
141
+ self._visit(parent, path, Path(path).name, unbundled=entry.unbundled)
116
142
  self._status(source, entry, 'addon')
117
143
  continue
118
144
  try:
@@ -153,14 +179,18 @@ class DependencyManager:
153
179
  if not self.collect_errors:
154
180
  raise DependencyError(message) from exc
155
181
  self.errors.append(message)
156
- from ..git_projects import resolve_projects
182
+ from ..git_projects import resolve_projects, declarations as git_declarations
183
+ for entry in git_declarations(parent.addon_pack.path, config):
184
+ if entry.get('unbundled', False) and (parent is not self.root_node or self.purpose == 'release'):
185
+ self.excluded.append({'source': str(parent.addon_pack.path), 'dependency': entry['name'], 'unbundled': True,
186
+ 'reason': 'unbundled' if parent is self.root_node else 'dependency_unbundled'})
157
187
  try:
158
188
  projects = resolve_projects(parent.addon_pack.path, config,
159
189
  self._git_locks.get(str(Path(parent.addon_pack.path).resolve())),
160
- source_records=self._git_sources)
190
+ source_records=self._git_sources, purpose=self.purpose if parent is self.root_node else "release")
161
191
  for entry, path, info in projects:
162
192
  self.has_git_projects = True
163
- self._visit(parent, str(path), entry['name'])
193
+ self._visit(parent, str(path), entry['name'], unbundled=entry.get('unbundled', False))
164
194
  except (DependencyError, OSError, ValueError) as exc:
165
195
  if not self.collect_errors:
166
196
  raise
@@ -185,7 +215,7 @@ class DependencyManager:
185
215
  self.warnings.append(message)
186
216
  self._status(source, entry, 'development_only', message)
187
217
 
188
- def _visit(self, parent, path, name, source_kind='local'):
218
+ def _visit(self, parent, path, name, source_kind='local', unbundled=False):
189
219
  key = canonical_path(path)
190
220
  if key in self._active:
191
221
  raise DependencyError('循环依赖: ' + ' -> '.join(self._active + [key]))
@@ -193,6 +223,7 @@ class DependencyManager:
193
223
  if source_kind == 'local' and self._nodes[key].source['kind'] == 'package':
194
224
  self._nodes[key].source['kind'] = 'local'
195
225
  parent.add_child(self._nodes[key])
226
+ self.edges.append((parent, self._nodes[key], unbundled))
196
227
  return
197
228
  config = read_project(path)
198
229
  if config.get('tool', {}).get('mcpywrap', {}).get('project_type', 'addon') != 'addon':
@@ -211,6 +242,7 @@ class DependencyManager:
211
242
  node = DependencyNode(name, addon, parent, source=source)
212
243
  self._nodes[key] = node
213
244
  parent.add_child(node)
245
+ self.edges.append((parent, node, unbundled))
214
246
  self._active.append(key)
215
247
  config = read_project(path)
216
248
  try:
@@ -220,6 +252,27 @@ class DependencyManager:
220
252
  self._active.pop()
221
253
  self._ordered.append(node)
222
254
 
255
+ def selection(self):
256
+ from collections import deque
257
+ paths = {(id(self.root_node), False): [self.root_node.name]}
258
+ pending = deque([(self.root_node, False)])
259
+ outgoing = {}
260
+ for parent, child, unbundled in self.edges:
261
+ outgoing.setdefault(id(parent), []).append((child, unbundled))
262
+ while pending:
263
+ parent, inherited = pending.popleft()
264
+ for child, unbundled in outgoing.get(id(parent), []):
265
+ effective = inherited or unbundled
266
+ key = (id(child), effective)
267
+ if key not in paths:
268
+ paths[key] = paths[(id(parent), inherited)] + [child.name]
269
+ pending.append((child, effective))
270
+ return {'purpose': self.purpose, 'includes_unbundled': self.purpose == 'runtime',
271
+ 'dependencies': [{'name': node.name, 'path': str(node.addon_pack.path),
272
+ 'unbundled': node.unbundled, 'included_in_release': not node.unbundled,
273
+ 'via': [paths[(id(node), value)] for value in (False, True) if (id(node), value) in paths]} for node in self._ordered],
274
+ 'excluded': self.excluded}
275
+
223
276
  def get_all_dependencies(self):
224
277
  return self.dependency_map
225
278
 
@@ -0,0 +1,46 @@
1
+ """A dev watcher owns its output until stopped; builds cannot overwrite it."""
2
+ from contextlib import contextmanager
3
+ from functools import wraps
4
+ from pathlib import Path
5
+ import hashlib
6
+ import tempfile
7
+
8
+ from ..dependencies import canonical_path, DependencyError
9
+ from ..utils.locks import directory_lock
10
+
11
+
12
+ class OutputLease:
13
+ def __init__(self, target):
14
+ self.target = canonical_path(target)
15
+ self.active = True
16
+
17
+ @contextmanager
18
+ def use(self, target):
19
+ if not self.active or canonical_path(target) != self.target:
20
+ raise DependencyError('构建输出占用凭据无效,请重启 dev')
21
+ yield self
22
+
23
+
24
+ @contextmanager
25
+ def output_lease(target):
26
+ key = hashlib.sha256(canonical_path(target).encode('utf-8')).hexdigest()
27
+ with directory_lock(Path(tempfile.gettempdir())/'mcpy-output-locks'/key, reentrant=True):
28
+ lease = OutputLease(target)
29
+ try:
30
+ yield lease
31
+ finally:
32
+ lease.active = False
33
+
34
+
35
+ def locked_output(method):
36
+ @wraps(method)
37
+ def wrapped(self):
38
+ try:
39
+ if self.target_dir is None:
40
+ return method(self)
41
+ lease = getattr(self, 'output_lease', None)
42
+ with lease.use(self.target_dir) if lease else output_lease(self.target_dir):
43
+ return method(self)
44
+ except (ValueError, OSError) as exc:
45
+ return False, str(exc)
46
+ return wrapped
@@ -11,6 +11,7 @@ from .MapPack import MapPack
11
11
  from .assembly import assemble_addon, validate_target, is_within, pack_files, rebuild_file
12
12
  from ..code_libraries import prepare_libraries
13
13
  from ..utils.paths import is_link
14
+ from .output_lock import locked_output
14
15
 
15
16
 
16
17
  def _replace_with_retry(source, target):
@@ -39,7 +40,7 @@ def _clear_directory(directory):
39
40
 
40
41
 
41
42
  class AddonProjectBuilder:
42
- def __init__(self, source_dir, target_dir, include_dependencies=True, *, resolved=None, stable_layout=False):
43
+ def __init__(self, source_dir, target_dir, include_dependencies=True, *, resolved=None, stable_layout=False, purpose="release", output_lease=None):
43
44
  self.source_dir = str(Path(source_dir).resolve())
44
45
  self.requested_target = Path(target_dir).absolute() if target_dir else None
45
46
  self.target_dir = str(Path(target_dir).resolve()) if target_dir else None
@@ -47,6 +48,9 @@ class AddonProjectBuilder:
47
48
  self.project_name = self.config.get('project', {}).get('name', 'current_project')
48
49
  self.include_dependencies = include_dependencies
49
50
  self.resolved = resolved
51
+ from ..dependencies import validate_purpose
52
+ self.purpose = validate_purpose(purpose)
53
+ self.output_lease = output_lease
50
54
  self.stable_layout = stable_layout
51
55
 
52
56
  def initialize(self):
@@ -60,12 +64,16 @@ class AddonProjectBuilder:
60
64
  config.setdefault('project', {})['dependencies'] = []
61
65
  config.setdefault('tool', {}).setdefault('mcpywrap', {})['local_dependencies'] = []
62
66
  config['tool']['mcpywrap']['git_dependencies'] = []
63
- self.dependency_manager = self.resolved or DependencyService(self.source_dir).resolve(config)
67
+ self.dependency_manager = self.resolved or DependencyService(self.source_dir).resolve(config, purpose=self.purpose)
68
+ from ..dependencies import require_resolution
69
+ require_resolution(self.dependency_manager, self.source_dir, self.purpose)
64
70
  report_dependency_warnings(self.dependency_manager)
65
71
  self.dependency_tree = self.dependency_manager.root_node
66
72
  self.origin_addon = self.dependency_tree.addon_pack
67
73
  self.packs = list(self.dependency_manager.get_all_dependencies().values()) + [self.origin_addon]
68
74
  prepare_libraries(self.packs)
75
+ from .assembly import validate_unbundled_overrides
76
+ validate_unbundled_overrides(self.packs)
69
77
  validate_target(self.target_dir, self.source_dir, self.packs)
70
78
  if is_link(self.target_dir):
71
79
  raise DependencyError('构建目标不能是目录链接')
@@ -77,6 +85,7 @@ class AddonProjectBuilder:
77
85
  setattr(self.target_addon, kind + '_pack_dir', str(Path(self.target_dir) / name))
78
86
  return True
79
87
 
88
+ @locked_output
80
89
  def build(self):
81
90
  try:
82
91
  from ..runtime.deployment import check_build_target
@@ -125,19 +134,25 @@ class AddonProjectBuilder:
125
134
 
126
135
 
127
136
  class MapProjectBuilder:
128
- def __init__(self, source_dir, target_dir, merge=False):
137
+ def __init__(self, source_dir, target_dir, merge=False, *, purpose="release", resolved=None, output_lease=None):
129
138
  self.source_dir = str(Path(source_dir).resolve())
130
139
  self.requested_target = Path(target_dir).absolute() if target_dir else None
131
140
  self.target_dir = str(Path(target_dir).resolve()) if target_dir else None
132
141
  self.merge = merge
142
+ self.purpose, self.resolved = purpose, resolved
143
+ self.output_lease = output_lease
133
144
 
145
+ @locked_output
134
146
  def build(self):
135
147
  try:
136
148
  if self.requested_target is not None and is_link(self.requested_target):
137
149
  raise DependencyError('构建目标不能是目录链接')
138
150
  from ..runtime.deployment import check_build_target
139
151
  check_build_target(self.source_dir, self.target_dir)
140
- manager = DependencyService(self.source_dir).resolve()
152
+ manager = self.resolved or DependencyService(self.source_dir).resolve(purpose=self.purpose)
153
+ from ..dependencies import require_resolution
154
+ require_resolution(manager, self.source_dir, self.purpose)
155
+ self.manager = manager
141
156
  report_dependency_warnings(manager)
142
157
  packs = list(manager.get_all_dependencies().values())
143
158
  root = manager.root_node.addon_pack
@@ -94,17 +94,20 @@ class MultiWatcher:
94
94
 
95
95
 
96
96
  class ProjectWatcher:
97
- def __init__(self, source_dir, target_dir, callback=None):
97
+ def __init__(self, source_dir, target_dir, callback=None, *, output_lease=None):
98
98
  self.source_dir, self.target_dir = os.path.abspath(source_dir), os.path.abspath(target_dir)
99
99
  self.callback = callback
100
100
  self.multi_watcher = MultiWatcher()
101
101
  self.lock = threading.RLock()
102
102
  self.known_files = set()
103
+ self.output_lease = output_lease
103
104
 
104
105
  def setup_from_config(self, project_name, dependencies=None):
105
106
  self.dependency_manager = DependencyService(self.source_dir).resolve()
106
107
  self.main_addon_pack = self.dependency_manager.root_node.addon_pack
107
108
  self.packs = list(self.dependency_manager.get_all_dependencies().values()) + [self.main_addon_pack]
109
+ from .assembly import validate_unbundled_overrides
110
+ validate_unbundled_overrides(self.packs)
108
111
  self.has_libraries = prepare_libraries(self.packs)
109
112
  self.has_libraries = self.has_libraries or self.dependency_manager.has_git_projects
110
113
  validate_target(self.target_dir, self.source_dir, self.packs)
@@ -147,11 +150,13 @@ class ProjectWatcher:
147
150
  def _build_libraries(self):
148
151
  # 带固定代码库的项目使用原子完整组装,不能绕过摘要或目标冲突校验。
149
152
  from .project_builder import AddonProjectBuilder
150
- success, error = AddonProjectBuilder(self.source_dir, self.target_dir).build()
153
+ success, error = AddonProjectBuilder(self.source_dir, self.target_dir, purpose="runtime", output_lease=self.output_lease).build()
151
154
  if not success:
152
155
  raise ValueError(error)
153
156
 
154
157
  def validate_sources(self):
158
+ from .assembly import validate_unbundled_overrides
159
+ validate_unbundled_overrides(self.packs)
155
160
  for pack in self.packs:
156
161
  validate_game_files(pack.path, [pack.behavior_pack_dir, pack.resource_pack_dir])
157
162
 
@@ -8,7 +8,7 @@ from .command_context import OperationGroup, configure_context
8
8
  COMMANDS = {
9
9
  name: (name + '_cmd', name + '_cmd') for name in
10
10
  ('host', 'skill', 'modsdk', 'init', 'add', 'remove', 'build', 'dev', 'package', 'publish',
11
- 'mod', 'run', 'connect', 'edit', 'ui', 'doctor', 'engine', 'sync', 'serve', 'record', 'script', 'deployment')
11
+ 'mod', 'run', 'deps', 'connect', 'edit', 'ui', 'doctor', 'engine', 'sync', 'serve', 'record', 'script', 'deployment')
12
12
  }
13
13
  COMMANDS.update({name: ('session_cmd', name + '_cmd') for name in ('status', 'logs', 'stop', 'restart')})
14
14
  COMMANDS.update({name: ('runtime_cmd', name + '_cmd') for name in ('runtime', 'py', 'reload')})
@@ -88,7 +88,7 @@ def require_project():
88
88
 
89
89
  def restart_handoff(result, previous):
90
90
  if not isinstance(result,dict) or not previous: return result
91
- current=result.get('session')
91
+ current=result.get('replacement_session',result.get('session'))
92
92
  if current and current!=previous:
93
93
  result=dict(result,previous_session=previous,session_changed=True)
94
94
  message='会话已更换;后续日志、截图和调试请使用 --session '+current+'。旧会话记录仍保留。'
@@ -226,7 +226,7 @@ class OperationGroup(click.Group):
226
226
  if result.get('hint'):
227
227
  click.echo(result['hint'])
228
228
  for key, value in result.items():
229
- if key not in ('ok', 'error', 'hint') and value is not None:
229
+ if key not in ('ok', 'error', 'hint', 'dependency_selection') and value is not None:
230
230
  click.echo(f'{key}: {value}')
231
231
  finally:
232
232
  _context.reset(token)
@@ -1,13 +1,15 @@
1
1
  """添加 Python 包或本地 Addon 目录依赖。"""
2
2
  import click
3
3
  from ..command_context import OperationCommand, project_dir as current_project, report_dependency_warnings
4
- from ..dependencies import DependencyDeclaration, DependencyError, DependencyService
4
+ from ..dependencies import DependencyDeclaration, DependencyError, DependencyService, canonical_path, resolve_path, included_in_release
5
5
  from .dependency_prompt import prompt_dependency, require_interactive, PromptDependency
6
6
  from ..framework_presets import FRAMEWORK_PRESETS
7
+ from ..dependency_feedback import report_unbundled
7
8
 
8
9
 
9
10
  @click.command(cls=OperationCommand)
10
11
  @click.argument('package', required=False)
12
+ @click.option('--unbundled/--bundled', default=None, help='不随 build/package 打包;新依赖默认打包,重复添加时省略则保留原设置')
11
13
  @click.option('--path', 'local_path', help='直接引用本地 Addon 根目录,不安装目录')
12
14
  @click.option('--qumod', is_flag=True, help='添加并同步已验证版本的 QuMod 外部代码库')
13
15
  @click.option('--framework', type=click.Choice(list(FRAMEWORK_PRESETS)), help='添加已注册框架预设')
@@ -19,11 +21,15 @@ from ..framework_presets import FRAMEWORK_PRESETS
19
21
  @click.option('--target', help='代码依赖在行为包内的安装目录')
20
22
  @click.option('--script-dir', help='框架所属脚本目录;唯一入口自动识别,无入口默认 MyScript')
21
23
  @click.option('--source', '--qumod-source', 'preset_source', help='预设源码来源名称,例如 github/gitee')
22
- def add_cmd(package, local_path, qumod, framework, git_url, git_ref, dep_name, subdir, kind, target, script_dir, preset_source):
24
+ def add_cmd(package, local_path, qumod, framework, git_url, git_ref, dep_name, subdir, kind, target, script_dir, preset_source, unbundled=None):
23
25
  """添加依赖;包安装到 mcpy 工具环境,不安装到游戏。无参数进入向导。"""
24
26
  if sum((package is not None, local_path is not None, qumod, framework is not None, git_url is not None)) > 1:
25
27
  raise click.UsageError('请选择一种依赖来源:包名、--path、--git、--framework 或 --qumod')
28
+ if unbundled is not None and package is not None:
29
+ raise click.UsageError('--unbundled/--bundled 只用于游戏依赖;Python 包仍安装在工具环境')
26
30
  preset = 'qumod' if qumod else framework
31
+ if unbundled is True and preset:
32
+ raise click.UsageError('框架快捷入口保持正式依赖;开发辅助代码请使用 add --git --unbundled')
27
33
  if (script_dir or preset_source) and not preset:
28
34
  raise click.UsageError('--script-dir/--source 需要框架预设')
29
35
  if (git_ref or dep_name or subdir is not None or kind is not None or target) and not git_url:
@@ -33,9 +39,10 @@ def add_cmd(package, local_path, qumod, framework, git_url, git_ref, dep_name, s
33
39
  try:
34
40
  service = DependencyService(str(current_project()))
35
41
  if git_url:
36
- result = service.add_git(git_url, ref=git_ref, name=dep_name, subdir=subdir, kind=kind, target=target)
42
+ result = service.add_git(git_url, ref=git_ref, name=dep_name, subdir=subdir, kind=kind, target=target, unbundled=unbundled)
37
43
  from ..consumer_prepare import guidance
38
44
  result['preparation'] = guidance(current_project())
45
+ report_unbundled(result)
39
46
  return result
40
47
  if preset:
41
48
  entry = PromptDependency('framework', preset, {'script_dir': script_dir, 'source': preset_source})
@@ -46,11 +53,14 @@ def add_cmd(package, local_path, qumod, framework, git_url, git_ref, dep_name, s
46
53
  entry = DependencyDeclaration('local' if local_path is not None else 'package', local_path if local_path is not None else package)
47
54
  service = DependencyService(str(current_project()))
48
55
  if entry.kind == 'git':
49
- result = service.add_git(entry.value, **entry.options)
56
+ result = service.add_git(entry.value, **entry.options, unbundled=unbundled)
50
57
  from ..consumer_prepare import guidance
51
58
  result['preparation'] = guidance(current_project())
59
+ report_unbundled(result)
52
60
  return result
53
61
  if entry.kind == 'framework':
62
+ if unbundled is True:
63
+ raise click.UsageError('框架快捷入口保持正式依赖;开发辅助代码请使用 add --git --unbundled')
54
64
  click.echo('正在准备框架外部依赖(固定提交,不安装到工具 Python 环境)...')
55
65
  result = service.add_framework(entry.value, **entry.options)
56
66
  for warning in result['warnings']:
@@ -58,10 +68,17 @@ def add_cmd(package, local_path, qumod, framework, git_url, git_ref, dep_name, s
58
68
  click.secho('框架已准备;其他开发者克隆后执行 mcpy sync 即可恢复。', fg='green')
59
69
  from ..consumer_prepare import guidance
60
70
  result['preparation'] = guidance(current_project())
71
+ report_unbundled(result)
61
72
  return result
73
+ previous_unbundled = None
62
74
  if entry.kind == 'local':
63
- changed, _ = service.add_local(entry.value)
75
+ previous = next((item for item in service.list() if item.kind == 'local' and canonical_path(resolve_path(current_project(), item.value)) == canonical_path(resolve_path(current_project(), entry.value))), None)
76
+ previous_unbundled = previous.unbundled if previous else None
77
+ changed, _ = service.add_local(entry.value, unbundled=unbundled)
78
+ entry = next(item for item in service.list() if item.kind == "local" and canonical_path(resolve_path(current_project(), item.value)) == canonical_path(resolve_path(current_project(), entry.value)))
64
79
  else:
80
+ if unbundled is not None:
81
+ raise click.UsageError('--unbundled/--bundled 只用于游戏依赖')
65
82
  click.echo(f'正在向 mcpy 工具环境安装 {entry.value}(非游戏环境)...')
66
83
  changed = service.add_package(entry.value)
67
84
  manager = service.last_resolution
@@ -69,7 +86,10 @@ def add_cmd(package, local_path, qumod, framework, git_url, git_ref, dep_name, s
69
86
  click.secho('依赖已添加' if changed else '依赖已存在', fg='green')
70
87
  from ..consumer_prepare import guidance
71
88
  preparation = guidance(current_project(), resolved=manager)
72
- return {'changed': changed, 'dependency': entry.value, 'source': entry.kind, 'preparation': preparation,
89
+ release_inclusion = included_in_release(manager, resolve_path(current_project(), entry.value)) if entry.kind == 'local' else None
90
+ if entry.kind == 'local':
91
+ report_unbundled({'unbundled': entry.unbundled, 'previous_unbundled': previous_unbundled, 'included_in_release': release_inclusion})
92
+ return {'unbundled': entry.unbundled if entry.kind == 'local' else None, 'previous_unbundled': previous_unbundled, 'included_in_release': release_inclusion, 'changed': changed, 'dependency': entry.value, 'source': entry.kind, 'preparation': preparation,
73
93
  'classification': 'addon' if entry.kind == 'local' else manager.status_for(current_project(), entry).state,
74
94
  'warnings': manager.warnings}
75
95
  except (DependencyError, OSError) as exc:
@@ -11,5 +11,7 @@ def build_cmd(merge):
11
11
  """构建为 MCStudio 工程"""
12
12
  require_project()
13
13
  result = Core().execute('build', project_dir(), merge=merge)
14
+ from ..dependency_feedback import report_selection
15
+ report_selection(result.get('dependency_selection'))
14
16
  click.secho('✅ 构建成功!项目已生成到目标目录。', fg='green')
15
17
  return result
@@ -36,6 +36,8 @@ def prompt_dependency():
36
36
  options['subdir'] = click.prompt('源码子目录', default='.').strip()
37
37
  options['target'] = click.prompt('行为包内安装目录').strip()
38
38
  return PromptDependency('git', url, options)
39
+ if kind == '2':
40
+ click.echo('默认添加正式依赖,随 build/package 发布;仅本地开发使用可执行 add --path <目录> --unbundled。')
39
41
  value = click.prompt('包名/版本约束' if kind == '1' else 'Addon 目录').strip()
40
42
  if kind == '1':
41
43
  try:
@@ -0,0 +1,27 @@
1
+ """Inspect the selected dependency graph without installing or running hooks."""
2
+ import click
3
+ from ..command_context import OperationCommand, project_dir, require_project, json_output, report_dependency_warnings
4
+ from ..dependencies import DependencyService
5
+ from ..dependency_feedback import report_selection
6
+ from ..utils.console import echo
7
+
8
+
9
+ @click.command(cls=OperationCommand)
10
+ @click.option('--bundled-only', is_flag=True, help='预览 build/package 的正式依赖图;默认预览 dev/run')
11
+ def deps_cmd(bundled_only):
12
+ """只读查看依赖用途、发布状态和引用链;不执行准备或安装。"""
13
+ require_project()
14
+ manager = DependencyService(project_dir()).resolve(purpose='release' if bundled_only else 'runtime')
15
+ report_dependency_warnings(manager)
16
+ return present_selection(manager.selection())
17
+
18
+
19
+ def present_selection(result):
20
+ report_selection(result)
21
+ for item in result['dependencies']:
22
+ echo('%s [unbundled=%s / %s]' % (item['name'], str(item['unbundled']).lower(), '随发布' if item['included_in_release'] else '不随发布'))
23
+ for chain in item['via']:
24
+ echo(' ' + ' → '.join(chain))
25
+ for item in result['excluded']:
26
+ echo('%s [已排除:%s]' % (item['dependency'], '不进入发布' if item['reason'] == 'unbundled' else '依赖自身的 unbundled 引用不传递'))
27
+ return result if json_output() else None
@@ -66,43 +66,48 @@ def dev_cmd(reload_session):
66
66
  project_name = config.get('project', {}).get('name', 'current_project')
67
67
  dependencies_list = config.get('project', {}).get('dependencies', [])
68
68
 
69
- # 实际构建
70
- from ..project_scripts import before, configured, validate_build
71
- from ..consumer_prepare import PreparationPlan
72
- plan = PreparationPlan(source_dir)
73
- if configured(source_dir):
74
- validate_build(source_dir, target_dir, resolved=plan.manager)
75
- with before(source_dir, 'before_build', plan=plan):
76
- suc = build(source_dir, target_dir, resolved=plan.manager)
77
- if not suc:
78
- click.secho("❌ 初始构建失败", fg="red")
79
- raise click.ClickException('无法启动开发监控')
69
+ from ..builders.output_lock import output_lease
70
+ with output_lease(target_dir) as lease:
71
+ # 实际构建
72
+ from ..project_scripts import before, configured, validate_build
73
+ from ..consumer_prepare import PreparationPlan
74
+ plan = PreparationPlan(source_dir)
75
+ from ..dependency_feedback import report_selection
76
+ report_selection(plan.manager.selection())
77
+ if configured(source_dir):
78
+ validate_build(source_dir, target_dir, resolved=plan.manager, purpose="runtime")
79
+ with before(source_dir, 'before_build', plan=plan):
80
+ suc = build(source_dir, target_dir, resolved=plan.manager, purpose="runtime", output_lease=lease)
81
+ if not suc:
82
+ click.secho("❌ 初始构建失败", fg="red")
83
+ raise click.ClickException('无法启动开发监控')
80
84
 
81
- click.secho(f"🔍 开始监控代码变化,路径: ", fg="bright_blue", nl=False)
82
- click.secho(f"{source_dir}", fg="bright_cyan")
85
+ click.secho(f"🔍 开始监控代码变化,路径: ", fg="bright_blue", nl=False)
86
+ click.secho(f"{source_dir}", fg="bright_cyan")
83
87
 
84
- if plan.enabled:
85
- click.echo('初次资源准备已完成;dev 后续只同步包内文件,原始素材修改需要重新构建并应用。')
88
+ if plan.enabled:
89
+ click.echo('初次资源准备已完成;dev 后续只同步包内文件,原始素材修改需要重新构建并应用。')
86
90
 
87
- # 创建项目监视器
88
- project_watcher = ProjectWatcher(source_dir, target_dir, file_change_callback)
91
+ # 创建项目监视器
92
+ project_watcher = ProjectWatcher(source_dir, target_dir, file_change_callback, output_lease=lease)
89
93
 
90
- # 设置监视器
91
- dep_count = project_watcher.setup_from_config(project_name, dependencies_list)
94
+ # 设置监视器
95
+ dep_count = project_watcher.setup_from_config(project_name, dependencies_list)
92
96
 
93
- if dep_count > 0:
94
- click.secho(f"✅ 找到并监控 {dep_count} 个依赖包", fg="green")
97
+ if dep_count > 0:
98
+ click.secho(f"✅ 找到并监控 {dep_count} 个依赖包", fg="green")
95
99
 
96
- # 启动监视
97
- project_watcher.start()
98
- try:
99
- click.secho("👀 监控中... 按 Ctrl+C 停止", fg="bright_magenta")
100
- while True:
101
- time.sleep(1)
102
- except KeyboardInterrupt:
103
- project_watcher.stop()
104
- click.secho("🛑 监控已停止", fg="bright_yellow")
105
- raise
100
+ # 启动监视
101
+ project_watcher.start()
102
+ try:
103
+ click.secho("👀 监控中... 按 Ctrl+C 停止", fg="bright_magenta")
104
+ while True:
105
+ time.sleep(1)
106
+ except KeyboardInterrupt:
107
+ click.secho("🛑 监控已停止", fg="bright_yellow")
108
+ raise
109
+ finally:
110
+ project_watcher.stop()
106
111
  else:
107
112
  click.secho('❌ 暂未支持: 当前仅支持Addons项目的构建', fg="red")
108
113
  raise click.ClickException('无法启动开发监控')
@@ -12,5 +12,7 @@ def package_cmd(merge):
12
12
  """组装 Addon/地图并生成分发 ZIP;游戏兼容性需实际测试。"""
13
13
  require_project()
14
14
  result = Core().execute('package', project_dir(), merge=merge)
15
+ from ..dependency_feedback import report_selection
16
+ report_selection(result.get('dependency_selection'))
15
17
  click.secho('✅ 打包成功!分发文件路径: ' + result['artifact'], fg='green')
16
18
  return result