mcpywrap 0.4.3__tar.gz → 0.4.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 (270) hide show
  1. {mcpywrap-0.4.3 → mcpywrap-0.4.4}/CHANGELOG.md +8 -0
  2. {mcpywrap-0.4.3/mcpywrap.egg-info → mcpywrap-0.4.4}/PKG-INFO +1 -1
  3. {mcpywrap-0.4.3 → mcpywrap-0.4.4}/docs/git-dependencies.md +3 -3
  4. {mcpywrap-0.4.3 → mcpywrap-0.4.4}/mcpywrap/__init__.py +1 -1
  5. {mcpywrap-0.4.3 → mcpywrap-0.4.4}/mcpywrap/code_libraries.py +11 -7
  6. {mcpywrap-0.4.3 → mcpywrap-0.4.4}/mcpywrap/commands/sync_cmd.py +2 -6
  7. {mcpywrap-0.4.3 → mcpywrap-0.4.4}/mcpywrap/engines/windows.py +22 -16
  8. {mcpywrap-0.4.3 → mcpywrap-0.4.4}/mcpywrap/git_cache.py +8 -1
  9. {mcpywrap-0.4.3 → mcpywrap-0.4.4}/mcpywrap/git_projects.py +14 -44
  10. {mcpywrap-0.4.3 → mcpywrap-0.4.4}/mcpywrap/mcstudio/bridge_payload/Injector.exe +0 -0
  11. {mcpywrap-0.4.3 → mcpywrap-0.4.4}/mcpywrap/mcstudio/bridge_payload/Loader.dll +0 -0
  12. {mcpywrap-0.4.3 → mcpywrap-0.4.4}/mcpywrap/mcstudio/bridge_payload/McpyMcsAuth.dll +0 -0
  13. {mcpywrap-0.4.3 → mcpywrap-0.4.4}/mcpywrap/mcstudio/bridge_payload/manifest.json +3 -3
  14. {mcpywrap-0.4.3 → mcpywrap-0.4.4}/mcpywrap/mcstudio/window_capture/manifest.json +1 -1
  15. {mcpywrap-0.4.3 → mcpywrap-0.4.4}/mcpywrap/mcstudio/window_capture/mcpy-window-capture.exe +0 -0
  16. {mcpywrap-0.4.3 → mcpywrap-0.4.4}/mcpywrap/minecraft/template/mod_template.py +2 -0
  17. {mcpywrap-0.4.3 → mcpywrap-0.4.4}/mcpywrap/source_files.py +4 -1
  18. {mcpywrap-0.4.3 → mcpywrap-0.4.4/mcpywrap.egg-info}/PKG-INFO +1 -1
  19. {mcpywrap-0.4.3 → mcpywrap-0.4.4}/pyproject.toml +1 -1
  20. {mcpywrap-0.4.3 → mcpywrap-0.4.4}/skills/mcpywrap/SKILL.md +1 -1
  21. {mcpywrap-0.4.3 → mcpywrap-0.4.4}/skills/mcpywrap/references/project-dependencies.md +2 -1
  22. {mcpywrap-0.4.3 → mcpywrap-0.4.4}/tests/test_code_libraries.py +20 -0
  23. {mcpywrap-0.4.3 → mcpywrap-0.4.4}/tests/test_engine_backends.py +22 -0
  24. {mcpywrap-0.4.3 → mcpywrap-0.4.4}/tests/test_git_projects.py +105 -69
  25. {mcpywrap-0.4.3 → mcpywrap-0.4.4}/tests/test_qt_sessions.py +5 -1
  26. {mcpywrap-0.4.3 → mcpywrap-0.4.4}/LICENSE +0 -0
  27. {mcpywrap-0.4.3 → mcpywrap-0.4.4}/MANIFEST.in +0 -0
  28. {mcpywrap-0.4.3 → mcpywrap-0.4.4}/README.md +0 -0
  29. {mcpywrap-0.4.3 → mcpywrap-0.4.4}/THIRD_PARTY_NOTICES.md +0 -0
  30. {mcpywrap-0.4.3 → mcpywrap-0.4.4}/docs/code-libraries.md +0 -0
  31. {mcpywrap-0.4.3 → mcpywrap-0.4.4}/docs/development.md +0 -0
  32. {mcpywrap-0.4.3 → mcpywrap-0.4.4}/docs/engine-discovery.md +0 -0
  33. {mcpywrap-0.4.3 → mcpywrap-0.4.4}/docs/game-backends.md +0 -0
  34. {mcpywrap-0.4.3 → mcpywrap-0.4.4}/docs/input-sequence.md +0 -0
  35. {mcpywrap-0.4.3 → mcpywrap-0.4.4}/docs/launcher-client-python.md +0 -0
  36. {mcpywrap-0.4.3 → mcpywrap-0.4.4}/docs/local-dependencies.md +0 -0
  37. {mcpywrap-0.4.3 → mcpywrap-0.4.4}/docs/macos-resource-reload.md +0 -0
  38. {mcpywrap-0.4.3 → mcpywrap-0.4.4}/docs/mcs-auth.md +0 -0
  39. {mcpywrap-0.4.3 → mcpywrap-0.4.4}/docs/qt6-development.md +0 -0
  40. {mcpywrap-0.4.3 → mcpywrap-0.4.4}/docs/qumod.md +0 -0
  41. {mcpywrap-0.4.3 → mcpywrap-0.4.4}/docs/release-0.4.0.md +0 -0
  42. {mcpywrap-0.4.3 → mcpywrap-0.4.4}/docs/release-readiness-0.4.0.md +0 -0
  43. {mcpywrap-0.4.3 → mcpywrap-0.4.4}/docs/releasing.md +0 -0
  44. {mcpywrap-0.4.3 → mcpywrap-0.4.4}/docs/runtime-debug.md +0 -0
  45. {mcpywrap-0.4.3 → mcpywrap-0.4.4}/docs/runtime-input.md +0 -0
  46. {mcpywrap-0.4.3 → mcpywrap-0.4.4}/docs/runtime-player.md +0 -0
  47. {mcpywrap-0.4.3 → mcpywrap-0.4.4}/docs/runtime-ui.md +0 -0
  48. {mcpywrap-0.4.3 → mcpywrap-0.4.4}/docs/shared-log-ui.md +0 -0
  49. {mcpywrap-0.4.3 → mcpywrap-0.4.4}/mcpywrap/__main__.py +0 -0
  50. {mcpywrap-0.4.3 → mcpywrap-0.4.4}/mcpywrap/builders/AddonsPack.py +0 -0
  51. {mcpywrap-0.4.3 → mcpywrap-0.4.4}/mcpywrap/builders/MapPack.py +0 -0
  52. {mcpywrap-0.4.3 → mcpywrap-0.4.4}/mcpywrap/builders/__init__.py +0 -0
  53. {mcpywrap-0.4.3 → mcpywrap-0.4.4}/mcpywrap/builders/assembly.py +0 -0
  54. {mcpywrap-0.4.3 → mcpywrap-0.4.4}/mcpywrap/builders/dependency_manager.py +0 -0
  55. {mcpywrap-0.4.3 → mcpywrap-0.4.4}/mcpywrap/builders/file_merge.py +0 -0
  56. {mcpywrap-0.4.3 → mcpywrap-0.4.4}/mcpywrap/builders/project_builder.py +0 -0
  57. {mcpywrap-0.4.3 → mcpywrap-0.4.4}/mcpywrap/builders/watcher.py +0 -0
  58. {mcpywrap-0.4.3 → mcpywrap-0.4.4}/mcpywrap/cli.py +0 -0
  59. {mcpywrap-0.4.3 → mcpywrap-0.4.4}/mcpywrap/command_context.py +0 -0
  60. {mcpywrap-0.4.3 → mcpywrap-0.4.4}/mcpywrap/commands/__init__.py +0 -0
  61. {mcpywrap-0.4.3 → mcpywrap-0.4.4}/mcpywrap/commands/add_cmd.py +0 -0
  62. {mcpywrap-0.4.3 → mcpywrap-0.4.4}/mcpywrap/commands/build_cmd.py +0 -0
  63. {mcpywrap-0.4.3 → mcpywrap-0.4.4}/mcpywrap/commands/connect_cmd.py +0 -0
  64. {mcpywrap-0.4.3 → mcpywrap-0.4.4}/mcpywrap/commands/default_cmd.py +0 -0
  65. {mcpywrap-0.4.3 → mcpywrap-0.4.4}/mcpywrap/commands/dependency_prompt.py +0 -0
  66. {mcpywrap-0.4.3 → mcpywrap-0.4.4}/mcpywrap/commands/desktop_cmd.py +0 -0
  67. {mcpywrap-0.4.3 → mcpywrap-0.4.4}/mcpywrap/commands/dev_cmd.py +0 -0
  68. {mcpywrap-0.4.3 → mcpywrap-0.4.4}/mcpywrap/commands/doctor_cmd.py +0 -0
  69. {mcpywrap-0.4.3 → mcpywrap-0.4.4}/mcpywrap/commands/edit_cmd.py +0 -0
  70. {mcpywrap-0.4.3 → mcpywrap-0.4.4}/mcpywrap/commands/engine_cmd.py +0 -0
  71. {mcpywrap-0.4.3 → mcpywrap-0.4.4}/mcpywrap/commands/init_cmd.py +0 -0
  72. {mcpywrap-0.4.3 → mcpywrap-0.4.4}/mcpywrap/commands/mod_cmd.py +0 -0
  73. {mcpywrap-0.4.3 → mcpywrap-0.4.4}/mcpywrap/commands/modsdk_cmd.py +0 -0
  74. {mcpywrap-0.4.3 → mcpywrap-0.4.4}/mcpywrap/commands/package_cmd.py +0 -0
  75. {mcpywrap-0.4.3 → mcpywrap-0.4.4}/mcpywrap/commands/publish_cmd.py +0 -0
  76. {mcpywrap-0.4.3 → mcpywrap-0.4.4}/mcpywrap/commands/record_cmd.py +0 -0
  77. {mcpywrap-0.4.3 → mcpywrap-0.4.4}/mcpywrap/commands/remove_cmd.py +0 -0
  78. {mcpywrap-0.4.3 → mcpywrap-0.4.4}/mcpywrap/commands/run_cmd.py +0 -0
  79. {mcpywrap-0.4.3 → mcpywrap-0.4.4}/mcpywrap/commands/runtime_cmd.py +0 -0
  80. {mcpywrap-0.4.3 → mcpywrap-0.4.4}/mcpywrap/commands/runtime_input_cmd.py +0 -0
  81. {mcpywrap-0.4.3 → mcpywrap-0.4.4}/mcpywrap/commands/runtime_player_cmd.py +0 -0
  82. {mcpywrap-0.4.3 → mcpywrap-0.4.4}/mcpywrap/commands/runtime_ui_cmd.py +0 -0
  83. {mcpywrap-0.4.3 → mcpywrap-0.4.4}/mcpywrap/commands/serve_cmd.py +0 -0
  84. {mcpywrap-0.4.3 → mcpywrap-0.4.4}/mcpywrap/commands/session_cmd.py +0 -0
  85. {mcpywrap-0.4.3 → mcpywrap-0.4.4}/mcpywrap/commands/ui_cmd.py +0 -0
  86. {mcpywrap-0.4.3 → mcpywrap-0.4.4}/mcpywrap/config.py +0 -0
  87. {mcpywrap-0.4.3 → mcpywrap-0.4.4}/mcpywrap/custom_packaging.py +0 -0
  88. {mcpywrap-0.4.3 → mcpywrap-0.4.4}/mcpywrap/dependencies.py +0 -0
  89. {mcpywrap-0.4.3 → mcpywrap-0.4.4}/mcpywrap/engines/__init__.py +0 -0
  90. {mcpywrap-0.4.3 → mcpywrap-0.4.4}/mcpywrap/engines/apk_profile.py +0 -0
  91. {mcpywrap-0.4.3 → mcpywrap-0.4.4}/mcpywrap/engines/backend.py +0 -0
  92. {mcpywrap-0.4.3 → mcpywrap-0.4.4}/mcpywrap/engines/host.py +0 -0
  93. {mcpywrap-0.4.3 → mcpywrap-0.4.4}/mcpywrap/engines/install.py +0 -0
  94. {mcpywrap-0.4.3 → mcpywrap-0.4.4}/mcpywrap/engines/macos.py +0 -0
  95. {mcpywrap-0.4.3 → mcpywrap-0.4.4}/mcpywrap/engines/macos_network.py +0 -0
  96. {mcpywrap-0.4.3 → mcpywrap-0.4.4}/mcpywrap/engines/official.py +0 -0
  97. {mcpywrap-0.4.3 → mcpywrap-0.4.4}/mcpywrap/engines/preferences.py +0 -0
  98. {mcpywrap-0.4.3 → mcpywrap-0.4.4}/mcpywrap/engines/tui.py +0 -0
  99. {mcpywrap-0.4.3 → mcpywrap-0.4.4}/mcpywrap/framework_presets.py +0 -0
  100. {mcpywrap-0.4.3 → mcpywrap-0.4.4}/mcpywrap/frameworks.py +0 -0
  101. {mcpywrap-0.4.3 → mcpywrap-0.4.4}/mcpywrap/input_executor.py +0 -0
  102. {mcpywrap-0.4.3 → mcpywrap-0.4.4}/mcpywrap/input_plan.py +0 -0
  103. {mcpywrap-0.4.3 → mcpywrap-0.4.4}/mcpywrap/mcstudio/SimpleMonitor.py +0 -0
  104. {mcpywrap-0.4.3 → mcpywrap-0.4.4}/mcpywrap/mcstudio/__init__.py +0 -0
  105. {mcpywrap-0.4.3 → mcpywrap-0.4.4}/mcpywrap/mcstudio/auth_interaction.py +0 -0
  106. {mcpywrap-0.4.3 → mcpywrap-0.4.4}/mcpywrap/mcstudio/bridge_assets.py +0 -0
  107. {mcpywrap-0.4.3 → mcpywrap-0.4.4}/mcpywrap/mcstudio/bridge_payload/publisher.cer +0 -0
  108. {mcpywrap-0.4.3 → mcpywrap-0.4.4}/mcpywrap/mcstudio/diagnostics.py +0 -0
  109. {mcpywrap-0.4.3 → mcpywrap-0.4.4}/mcpywrap/mcstudio/discovery.py +0 -0
  110. {mcpywrap-0.4.3 → mcpywrap-0.4.4}/mcpywrap/mcstudio/editor.py +0 -0
  111. {mcpywrap-0.4.3 → mcpywrap-0.4.4}/mcpywrap/mcstudio/file_logs.py +0 -0
  112. {mcpywrap-0.4.3 → mcpywrap-0.4.4}/mcpywrap/mcstudio/game.py +0 -0
  113. {mcpywrap-0.4.3 → mcpywrap-0.4.4}/mcpywrap/mcstudio/host_input.py +0 -0
  114. {mcpywrap-0.4.3 → mcpywrap-0.4.4}/mcpywrap/mcstudio/hot_reload.py +0 -0
  115. {mcpywrap-0.4.3 → mcpywrap-0.4.4}/mcpywrap/mcstudio/input_sequence.py +0 -0
  116. {mcpywrap-0.4.3 → mcpywrap-0.4.4}/mcpywrap/mcstudio/launcher_python.py +0 -0
  117. {mcpywrap-0.4.3 → mcpywrap-0.4.4}/mcpywrap/mcstudio/log_colorizer.py +0 -0
  118. {mcpywrap-0.4.3 → mcpywrap-0.4.4}/mcpywrap/mcstudio/log_protocol.py +0 -0
  119. {mcpywrap-0.4.3 → mcpywrap-0.4.4}/mcpywrap/mcstudio/mcs.py +0 -0
  120. {mcpywrap-0.4.3 → mcpywrap-0.4.4}/mcpywrap/mcstudio/mcs_auth.py +0 -0
  121. {mcpywrap-0.4.3 → mcpywrap-0.4.4}/mcpywrap/mcstudio/network.py +0 -0
  122. {mcpywrap-0.4.3 → mcpywrap-0.4.4}/mcpywrap/mcstudio/private_logs.py +0 -0
  123. {mcpywrap-0.4.3 → mcpywrap-0.4.4}/mcpywrap/mcstudio/processes.py +0 -0
  124. {mcpywrap-0.4.3 → mcpywrap-0.4.4}/mcpywrap/mcstudio/recording_worker.py +0 -0
  125. {mcpywrap-0.4.3 → mcpywrap-0.4.4}/mcpywrap/mcstudio/recordings.py +0 -0
  126. {mcpywrap-0.4.3 → mcpywrap-0.4.4}/mcpywrap/mcstudio/runtime_cppconfig.py +0 -0
  127. {mcpywrap-0.4.3 → mcpywrap-0.4.4}/mcpywrap/mcstudio/runtime_debug.py +0 -0
  128. {mcpywrap-0.4.3 → mcpywrap-0.4.4}/mcpywrap/mcstudio/runtime_input_payload.py +0 -0
  129. {mcpywrap-0.4.3 → mcpywrap-0.4.4}/mcpywrap/mcstudio/runtime_key_timeline_payload.py +0 -0
  130. {mcpywrap-0.4.3 → mcpywrap-0.4.4}/mcpywrap/mcstudio/runtime_player_payload.py +0 -0
  131. {mcpywrap-0.4.3 → mcpywrap-0.4.4}/mcpywrap/mcstudio/runtime_ui.py +0 -0
  132. {mcpywrap-0.4.3 → mcpywrap-0.4.4}/mcpywrap/mcstudio/runtime_ui_outline.py +0 -0
  133. {mcpywrap-0.4.3 → mcpywrap-0.4.4}/mcpywrap/mcstudio/runtime_ui_payload.py +0 -0
  134. {mcpywrap-0.4.3 → mcpywrap-0.4.4}/mcpywrap/mcstudio/session_capabilities.py +0 -0
  135. {mcpywrap-0.4.3 → mcpywrap-0.4.4}/mcpywrap/mcstudio/session_worker.py +0 -0
  136. {mcpywrap-0.4.3 → mcpywrap-0.4.4}/mcpywrap/mcstudio/sessions.py +0 -0
  137. {mcpywrap-0.4.3 → mcpywrap-0.4.4}/mcpywrap/mcstudio/studio_server.py +0 -0
  138. {mcpywrap-0.4.3 → mcpywrap-0.4.4}/mcpywrap/mcstudio/studio_server_ui.py +0 -0
  139. {mcpywrap-0.4.3 → mcpywrap-0.4.4}/mcpywrap/mcstudio/symlink_helper_global.py +0 -0
  140. {mcpywrap-0.4.3 → mcpywrap-0.4.4}/mcpywrap/mcstudio/symlink_helper_map.py +0 -0
  141. {mcpywrap-0.4.3 → mcpywrap-0.4.4}/mcpywrap/mcstudio/symlinks.py +0 -0
  142. {mcpywrap-0.4.3 → mcpywrap-0.4.4}/mcpywrap/mcstudio/unified_input.py +0 -0
  143. {mcpywrap-0.4.3 → mcpywrap-0.4.4}/mcpywrap/mcstudio/window.py +0 -0
  144. {mcpywrap-0.4.3 → mcpywrap-0.4.4}/mcpywrap/minecraft/__init__.py +0 -0
  145. {mcpywrap-0.4.3 → mcpywrap-0.4.4}/mcpywrap/minecraft/addons.py +0 -0
  146. {mcpywrap-0.4.3 → mcpywrap-0.4.4}/mcpywrap/minecraft/level_dat.py +0 -0
  147. {mcpywrap-0.4.3 → mcpywrap-0.4.4}/mcpywrap/minecraft/map.py +0 -0
  148. {mcpywrap-0.4.3 → mcpywrap-0.4.4}/mcpywrap/minecraft/netease_modsdk.py +0 -0
  149. {mcpywrap-0.4.3 → mcpywrap-0.4.4}/mcpywrap/minecraft/template/generate_mod_files.py +0 -0
  150. {mcpywrap-0.4.3 → mcpywrap-0.4.4}/mcpywrap/project_dependencies.py +0 -0
  151. {mcpywrap-0.4.3 → mcpywrap-0.4.4}/mcpywrap/project_init.py +0 -0
  152. {mcpywrap-0.4.3 → mcpywrap-0.4.4}/mcpywrap/recording_io.py +0 -0
  153. {mcpywrap-0.4.3 → mcpywrap-0.4.4}/mcpywrap/remote/__init__.py +0 -0
  154. {mcpywrap-0.4.3 → mcpywrap-0.4.4}/mcpywrap/remote/client.py +0 -0
  155. {mcpywrap-0.4.3 → mcpywrap-0.4.4}/mcpywrap/remote/http_server.py +0 -0
  156. {mcpywrap-0.4.3 → mcpywrap-0.4.4}/mcpywrap/remote/service.py +0 -0
  157. {mcpywrap-0.4.3 → mcpywrap-0.4.4}/mcpywrap/timeline.py +0 -0
  158. {mcpywrap-0.4.3 → mcpywrap-0.4.4}/mcpywrap/ui/__init__.py +0 -0
  159. {mcpywrap-0.4.3 → mcpywrap-0.4.4}/mcpywrap/ui/engine_setup.py +0 -0
  160. {mcpywrap-0.4.3 → mcpywrap-0.4.4}/mcpywrap/ui/log_view.py +0 -0
  161. {mcpywrap-0.4.3 → mcpywrap-0.4.4}/mcpywrap/ui/log_window.py +0 -0
  162. {mcpywrap-0.4.3 → mcpywrap-0.4.4}/mcpywrap/ui/project_ui.py +0 -0
  163. {mcpywrap-0.4.3 → mcpywrap-0.4.4}/mcpywrap/ui/run_session.py +0 -0
  164. {mcpywrap-0.4.3 → mcpywrap-0.4.4}/mcpywrap/ui/session_controller.py +0 -0
  165. {mcpywrap-0.4.3 → mcpywrap-0.4.4}/mcpywrap/ui/session_tools.py +0 -0
  166. {mcpywrap-0.4.3 → mcpywrap-0.4.4}/mcpywrap/ui/session_views.py +0 -0
  167. {mcpywrap-0.4.3 → mcpywrap-0.4.4}/mcpywrap/ui/world_config.py +0 -0
  168. {mcpywrap-0.4.3 → mcpywrap-0.4.4}/mcpywrap/utils/__init__.py +0 -0
  169. {mcpywrap-0.4.3 → mcpywrap-0.4.4}/mcpywrap/utils/pip_error_parser.py +0 -0
  170. {mcpywrap-0.4.3 → mcpywrap-0.4.4}/mcpywrap/utils/print_guide.py +0 -0
  171. {mcpywrap-0.4.3 → mcpywrap-0.4.4}/mcpywrap/utils/project_setup.py +0 -0
  172. {mcpywrap-0.4.3 → mcpywrap-0.4.4}/mcpywrap/utils/utils.py +0 -0
  173. {mcpywrap-0.4.3 → mcpywrap-0.4.4}/mcpywrap.egg-info/SOURCES.txt +0 -0
  174. {mcpywrap-0.4.3 → mcpywrap-0.4.4}/mcpywrap.egg-info/dependency_links.txt +0 -0
  175. {mcpywrap-0.4.3 → mcpywrap-0.4.4}/mcpywrap.egg-info/entry_points.txt +0 -0
  176. {mcpywrap-0.4.3 → mcpywrap-0.4.4}/mcpywrap.egg-info/requires.txt +0 -0
  177. {mcpywrap-0.4.3 → mcpywrap-0.4.4}/mcpywrap.egg-info/top_level.txt +0 -0
  178. {mcpywrap-0.4.3 → mcpywrap-0.4.4}/native/mcs_auth/Bridge.cs +0 -0
  179. {mcpywrap-0.4.3 → mcpywrap-0.4.4}/native/mcs_auth/Injector.cs +0 -0
  180. {mcpywrap-0.4.3 → mcpywrap-0.4.4}/native/mcs_auth/Loader.c +0 -0
  181. {mcpywrap-0.4.3 → mcpywrap-0.4.4}/native/mcs_auth/publisher.cer +0 -0
  182. {mcpywrap-0.4.3 → mcpywrap-0.4.4}/native/mcs_auth/publisher.json +0 -0
  183. {mcpywrap-0.4.3 → mcpywrap-0.4.4}/native/runtime_input/README.md +0 -0
  184. {mcpywrap-0.4.3 → mcpywrap-0.4.4}/native/runtime_input/launcher-monotonic.patch +0 -0
  185. {mcpywrap-0.4.3 → mcpywrap-0.4.4}/native/runtime_input/steady_clock.h +0 -0
  186. {mcpywrap-0.4.3 → mcpywrap-0.4.4}/native/window_capture/video_capture.h +0 -0
  187. {mcpywrap-0.4.3 → mcpywrap-0.4.4}/native/window_capture/window_capture.cpp +0 -0
  188. {mcpywrap-0.4.3 → mcpywrap-0.4.4}/scripts/build_all_native.py +0 -0
  189. {mcpywrap-0.4.3 → mcpywrap-0.4.4}/scripts/build_mcs_auth_bridge.py +0 -0
  190. {mcpywrap-0.4.3 → mcpywrap-0.4.4}/scripts/build_window_capture.py +0 -0
  191. {mcpywrap-0.4.3 → mcpywrap-0.4.4}/scripts/check_mcs_auth_bridge.py +0 -0
  192. {mcpywrap-0.4.3 → mcpywrap-0.4.4}/scripts/check_release.py +0 -0
  193. {mcpywrap-0.4.3 → mcpywrap-0.4.4}/scripts/check_window_capture.py +0 -0
  194. {mcpywrap-0.4.3 → mcpywrap-0.4.4}/setup.cfg +0 -0
  195. {mcpywrap-0.4.3 → mcpywrap-0.4.4}/skills/mcpywrap/agents/openai.yaml +0 -0
  196. {mcpywrap-0.4.3 → mcpywrap-0.4.4}/skills/mcpywrap/references/input-sequence.md +0 -0
  197. {mcpywrap-0.4.3 → mcpywrap-0.4.4}/skills/mcpywrap/references/input-writing.md +0 -0
  198. {mcpywrap-0.4.3 → mcpywrap-0.4.4}/skills/mcpywrap/references/instance-world-settings.md +0 -0
  199. {mcpywrap-0.4.3 → mcpywrap-0.4.4}/skills/mcpywrap/references/local-development.md +0 -0
  200. {mcpywrap-0.4.3 → mcpywrap-0.4.4}/skills/mcpywrap/references/macos-local.md +0 -0
  201. {mcpywrap-0.4.3 → mcpywrap-0.4.4}/skills/mcpywrap/references/remote-testing.md +0 -0
  202. {mcpywrap-0.4.3 → mcpywrap-0.4.4}/skills/mcpywrap/references/runtime-input.md +0 -0
  203. {mcpywrap-0.4.3 → mcpywrap-0.4.4}/skills/mcpywrap/references/runtime-key-timeline.md +0 -0
  204. {mcpywrap-0.4.3 → mcpywrap-0.4.4}/skills/mcpywrap/references/runtime-player.md +0 -0
  205. {mcpywrap-0.4.3 → mcpywrap-0.4.4}/skills/mcpywrap/references/runtime-ui.md +0 -0
  206. {mcpywrap-0.4.3 → mcpywrap-0.4.4}/skills/mcpywrap/references/troubleshooting.md +0 -0
  207. {mcpywrap-0.4.3 → mcpywrap-0.4.4}/skills/mcpywrap/scripts/bootstrap.ps1 +0 -0
  208. {mcpywrap-0.4.3 → mcpywrap-0.4.4}/skills/mcpywrap/scripts/bootstrap.py +0 -0
  209. {mcpywrap-0.4.3 → mcpywrap-0.4.4}/skills/mcpywrap/scripts/game_window.py +0 -0
  210. {mcpywrap-0.4.3 → mcpywrap-0.4.4}/skills/mcpywrap/scripts/smoke.py +0 -0
  211. {mcpywrap-0.4.3 → mcpywrap-0.4.4}/tests/manual/runtime_controls/README.md +0 -0
  212. {mcpywrap-0.4.3 → mcpywrap-0.4.4}/tests/manual/runtime_controls/client_probe.py +0 -0
  213. {mcpywrap-0.4.3 → mcpywrap-0.4.4}/tests/manual/runtime_controls/input_probe.py +0 -0
  214. {mcpywrap-0.4.3 → mcpywrap-0.4.4}/tests/manual/runtime_controls/key_timeline_probe.py +0 -0
  215. {mcpywrap-0.4.3 → mcpywrap-0.4.4}/tests/manual/runtime_controls/movement.json +0 -0
  216. {mcpywrap-0.4.3 → mcpywrap-0.4.4}/tests/manual/runtime_controls/run.py +0 -0
  217. {mcpywrap-0.4.3 → mcpywrap-0.4.4}/tests/manual/runtime_controls/server_fixture.py +0 -0
  218. {mcpywrap-0.4.3 → mcpywrap-0.4.4}/tests/manual/runtime_controls/support.py +0 -0
  219. {mcpywrap-0.4.3 → mcpywrap-0.4.4}/tests/manual_dependency_boundaries.py +0 -0
  220. {mcpywrap-0.4.3 → mcpywrap-0.4.4}/tests/manual_input_window.py +0 -0
  221. {mcpywrap-0.4.3 → mcpywrap-0.4.4}/tests/manual_integration.py +0 -0
  222. {mcpywrap-0.4.3 → mcpywrap-0.4.4}/tests/manual_native_recording.py +0 -0
  223. {mcpywrap-0.4.3 → mcpywrap-0.4.4}/tests/manual_remote_recording.py +0 -0
  224. {mcpywrap-0.4.3 → mcpywrap-0.4.4}/tests/manual_runtime_input.py +0 -0
  225. {mcpywrap-0.4.3 → mcpywrap-0.4.4}/tests/manual_runtime_input_unified.py +0 -0
  226. {mcpywrap-0.4.3 → mcpywrap-0.4.4}/tests/manual_runtime_key_timeline.py +0 -0
  227. {mcpywrap-0.4.3 → mcpywrap-0.4.4}/tests/manual_runtime_player.py +0 -0
  228. {mcpywrap-0.4.3 → mcpywrap-0.4.4}/tests/manual_runtime_ui.py +0 -0
  229. {mcpywrap-0.4.3 → mcpywrap-0.4.4}/tests/test_auth_interaction.py +0 -0
  230. {mcpywrap-0.4.3 → mcpywrap-0.4.4}/tests/test_automation.py +0 -0
  231. {mcpywrap-0.4.3 → mcpywrap-0.4.4}/tests/test_build_replace_retry.py +0 -0
  232. {mcpywrap-0.4.3 → mcpywrap-0.4.4}/tests/test_dependency_boundaries.py +0 -0
  233. {mcpywrap-0.4.3 → mcpywrap-0.4.4}/tests/test_engine_compatibility.py +0 -0
  234. {mcpywrap-0.4.3 → mcpywrap-0.4.4}/tests/test_engine_discovery.py +0 -0
  235. {mcpywrap-0.4.3 → mcpywrap-0.4.4}/tests/test_engine_install.py +0 -0
  236. {mcpywrap-0.4.3 → mcpywrap-0.4.4}/tests/test_game_window_skill.py +0 -0
  237. {mcpywrap-0.4.3 → mcpywrap-0.4.4}/tests/test_host_input.py +0 -0
  238. {mcpywrap-0.4.3 → mcpywrap-0.4.4}/tests/test_input_sequence.py +0 -0
  239. {mcpywrap-0.4.3 → mcpywrap-0.4.4}/tests/test_instance_cppconfig.py +0 -0
  240. {mcpywrap-0.4.3 → mcpywrap-0.4.4}/tests/test_launch_encoding.py +0 -0
  241. {mcpywrap-0.4.3 → mcpywrap-0.4.4}/tests/test_launcher_python.py +0 -0
  242. {mcpywrap-0.4.3 → mcpywrap-0.4.4}/tests/test_local_auth_session.py +0 -0
  243. {mcpywrap-0.4.3 → mcpywrap-0.4.4}/tests/test_local_dependencies.py +0 -0
  244. {mcpywrap-0.4.3 → mcpywrap-0.4.4}/tests/test_macos_network.py +0 -0
  245. {mcpywrap-0.4.3 → mcpywrap-0.4.4}/tests/test_manual_runtime_controls.py +0 -0
  246. {mcpywrap-0.4.3 → mcpywrap-0.4.4}/tests/test_mcs_auth.py +0 -0
  247. {mcpywrap-0.4.3 → mcpywrap-0.4.4}/tests/test_mouse.py +0 -0
  248. {mcpywrap-0.4.3 → mcpywrap-0.4.4}/tests/test_native_input_sequence.py +0 -0
  249. {mcpywrap-0.4.3 → mcpywrap-0.4.4}/tests/test_native_preferences.py +0 -0
  250. {mcpywrap-0.4.3 → mcpywrap-0.4.4}/tests/test_native_recording.py +0 -0
  251. {mcpywrap-0.4.3 → mcpywrap-0.4.4}/tests/test_network.py +0 -0
  252. {mcpywrap-0.4.3 → mcpywrap-0.4.4}/tests/test_network_sessions.py +0 -0
  253. {mcpywrap-0.4.3 → mcpywrap-0.4.4}/tests/test_pack_uuid_conflicts.py +0 -0
  254. {mcpywrap-0.4.3 → mcpywrap-0.4.4}/tests/test_package.py +0 -0
  255. {mcpywrap-0.4.3 → mcpywrap-0.4.4}/tests/test_qumod_workflow.py +0 -0
  256. {mcpywrap-0.4.3 → mcpywrap-0.4.4}/tests/test_recordings.py +0 -0
  257. {mcpywrap-0.4.3 → mcpywrap-0.4.4}/tests/test_remote.py +0 -0
  258. {mcpywrap-0.4.3 → mcpywrap-0.4.4}/tests/test_remote_scripts.py +0 -0
  259. {mcpywrap-0.4.3 → mcpywrap-0.4.4}/tests/test_resource_reload.py +0 -0
  260. {mcpywrap-0.4.3 → mcpywrap-0.4.4}/tests/test_runtime_debug.py +0 -0
  261. {mcpywrap-0.4.3 → mcpywrap-0.4.4}/tests/test_runtime_input.py +0 -0
  262. {mcpywrap-0.4.3 → mcpywrap-0.4.4}/tests/test_runtime_key_timeline.py +0 -0
  263. {mcpywrap-0.4.3 → mcpywrap-0.4.4}/tests/test_runtime_player.py +0 -0
  264. {mcpywrap-0.4.3 → mcpywrap-0.4.4}/tests/test_runtime_ui.py +0 -0
  265. {mcpywrap-0.4.3 → mcpywrap-0.4.4}/tests/test_runtime_ui_outline.py +0 -0
  266. {mcpywrap-0.4.3 → mcpywrap-0.4.4}/tests/test_session_capabilities.py +0 -0
  267. {mcpywrap-0.4.3 → mcpywrap-0.4.4}/tests/test_shared_logs.py +0 -0
  268. {mcpywrap-0.4.3 → mcpywrap-0.4.4}/tests/test_skill_workflows.py +0 -0
  269. {mcpywrap-0.4.3 → mcpywrap-0.4.4}/tests/test_unified_skill_contract.py +0 -0
  270. {mcpywrap-0.4.3 → mcpywrap-0.4.4}/tests/test_window_focus.py +0 -0
@@ -1,5 +1,13 @@
1
1
  # 更新记录
2
2
 
3
+ ## 0.4.4
4
+
5
+ - 修复 Windows 与 macOS 之间同步 Git 依赖时的源码校验失败:获取源码时禁用宿主 Git 的换行、编码与过滤转换,统一保留固定提交中的文件字节。
6
+ - `mcpy sync` 按固定提交直接重新计算 lock 摘要,不改变依赖版本,不再创建锁备份或执行专门迁移;未被修改的旧安装副本自动重建,缓存损坏与手动修改仍会报错。
7
+ - Git 项目依赖和旧代码库使用独立的新源码缓存,首次同步重新获取固定提交,后续可离线复用。补充跨 Git 配置、旧 Windows 缓存、二进制文件与重复同步稳定性的回归测试。
8
+ - Windows 启动时增加原生 HUD 布局日志识别,避免 Python 启动日志异常导致世界就绪状态无法确认。
9
+ - 修复 Mod 模板窗口关闭后未释放对象、在新版 PySide6 下退出进程时可能崩溃的问题。
10
+
3
11
  ## 0.4.3
4
12
 
5
13
  - macOS 新增无认证服务器连接,复用 `mcpy connect` 与项目 `[tool.mcpywrap.server]` 的 `run` 入口、cppconfig、日志、偏好和退出机制,不装配本地 Mod 或创建本地世界实例。
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: mcpywrap
3
- Version: 0.4.3
3
+ Version: 0.4.4
4
4
  Summary: A wrapper for Minecraft China Edition Addons management
5
5
  Author-email: boybook <boybook@easecation.net>
6
6
  License-Expression: MIT
@@ -76,11 +76,11 @@ Python的project.dependencies继续表示工具Python依赖,不变成游戏代
76
76
 
77
77
  两端提交并使用同一份 `mcpy-git.lock.json`,无需维护平台分支。锁定的是 Git 提交、源码和依赖关系;本机安装目录位于 `.mcpy/`,不提交到 Git。当前依赖都是游戏源码,没有需要分别锁定的 Windows/macOS 原生包。
78
78
 
79
- v2 锁使用相同的大小写敏感路径排序;源码由 Git archive 提取,保留仓库内的原始字节,工具生成的文件统一使用 LF。切换操作系统不会改变依赖摘要。新机器或克隆项目后运行一次 `mcpy sync`,随后正常 `mcpy run`。
79
+ v2 锁使用相同的大小写敏感路径排序;源码由 Git archive 提取,禁用宿主 Git 的换行、编码、ident 和 filter 转换及全局 attributes,保留提交中的文件字节(包括二进制和原本的 CRLF)。工具生成的文件统一使用 LF。新机器或克隆项目后运行一次 `mcpy sync`,随后正常 `mcpy run`。
80
80
 
81
- 普通 `mcpy sync` 会验证旧 v1 锁的源码,再自动更新跨平台格式,不再需要迁移参数。旧锁备份于 `.mcpy/lock-backups/`;需要重建的旧平台安装副本保留于 `.mcpy/registration-backups/`。提交新锁后,团队两端应使用支持 v2 的新版 mcpy。旧源码校验失败、或已安装文件出现无法解释的修改时仍会报错,不自动丢弃用户修改。
81
+ `mcpy sync` 依据声明中固定的完整 Git 提交重新计算源码和安装内容摘要,直接写回锁文件;不更新依赖版本、不创建备份或执行专门的锁迁移。旧 v1/v2 锁都可通过一次 sync 刷新。新快照使用独立的 `git-archive-v2` 缓存,首次同步会重新获取固定提交,之后可离线复用;旧缓存不参与新摘要计算。已安装副本与旧锁一致时可重建,手动改动或缓存损坏仍会报错。`build/package/run` 继续严格验证锁文件,不隐式重算。
82
82
 
83
- 终端只显示同步进度、结果和必要操作;`mcpy sync --json` 保留备份位置、完整摘要等诊断信息,供脚本和 AI 使用。`--migrate-windows-lock` 暂留作旧脚本兼容参数。
83
+ 终端只显示同步进度、结果和必要操作;`mcpy sync --json` 返回结构化结果。`--migrate-windows-lock` 和 JSON 中始终为空的 `git_lock_migrations` 仅保留旧脚本兼容。团队各设备应使用包含此修复的版本,并提交 sync 更新后的锁文件。
84
84
 
85
85
  ## 验证范围
86
86
 
@@ -1,4 +1,4 @@
1
1
  # -*- coding: utf-8 -*-
2
2
  """mcpywrap - 我的世界中国版 Addon 开发依赖、构建与游戏测试工具。"""
3
3
 
4
- __version__ = '0.4.3'
4
+ __version__ = '0.4.4'
@@ -64,9 +64,6 @@ def prepare_sync(root, config=None):
64
64
  for entry in entries:
65
65
  key = identity(entry)
66
66
  installed = cache / key
67
- if installed.is_dir() and key in expected and expected[key] in (digest(installed), windows_checkout_digest(installed, crlf=False)):
68
- lock['libraries'].append({'declaration': entry, 'sha256': digest(installed)})
69
- continue
70
67
  # 临时仓库不检出文件、不运行依赖代码、hooks 或安装脚本。
71
68
  with tempfile.TemporaryDirectory(prefix='fetch-', dir=cache) as temporary:
72
69
  temp = Path(temporary)
@@ -83,12 +80,19 @@ def prepare_sync(root, config=None):
83
80
  (content / ('MCPY_UPSTREAM_' + file.name)).write_bytes(file.read_bytes())
84
81
  validate_game_files(root, [content])
85
82
  value = digest(content)
86
- if key in expected and expected[key] not in (value, windows_checkout_digest(content, crlf=False)):
87
- raise DependencyError('固定提交的代码库内容与锁文件摘要不符')
88
83
  if installed.exists():
89
- # 回退到旧提交:用重新获取的内容验证旧缓存,而不是逐文件覆盖。
84
+ # Rebuild unchanged old installations from canonical source.
90
85
  if digest(installed) != value:
91
- raise DependencyError(f'代码库缓存已损坏,请移走后重新 sync: {installed}')
86
+ if key not in expected or expected[key] not in (
87
+ digest(installed), windows_checkout_digest(installed, crlf=False)):
88
+ raise DependencyError(f'代码库缓存已损坏,请移走后重新 sync: {installed}')
89
+ old = temp / 'old'
90
+ os.replace(installed, old)
91
+ try:
92
+ os.replace(content, installed)
93
+ except BaseException:
94
+ os.replace(old, installed)
95
+ raise
92
96
  else:
93
97
  os.replace(content, installed)
94
98
  lock['libraries'].append({'declaration': entry, 'sha256': value})
@@ -19,8 +19,6 @@ def sync_cmd(install, migrate_windows_lock=False):
19
19
  result = sync_project(project_dir(), install, migrate_windows_lock=migrate_windows_lock)
20
20
  if json_output():
21
21
  return result
22
- if result['git_lock_migrations']:
23
- click.echo('已更新跨平台依赖记录,旧文件已备份。')
24
22
  count = result['git_projects'] + result['code_libraries']
25
23
  click.secho('完成 · %d 个源码依赖已就绪 · %.1fs' % (count, time.monotonic()-started), fg='green')
26
24
  if install:
@@ -38,7 +36,6 @@ def sync_project(path, install=False, migrate_windows_lock=False):
38
36
  from ..builders.dependency_manager import DependencyManager
39
37
  visited, active = set(), set()
40
38
  git_count = 0
41
- migrations = []
42
39
  def sync_sources(directory):
43
40
  nonlocal git_count
44
41
  key = canonical_path(directory)
@@ -57,8 +54,7 @@ def sync_project(path, install=False, migrate_windows_lock=False):
57
54
  if target and 'mcpywrap' in read_project(target).get('tool', {}):
58
55
  sync_sources(target)
59
56
  if git_declarations(directory, source_config) or Path(directory, GIT_LOCK_FILE).exists():
60
- git_count += sync_projects(directory, source_config, migrate_windows_lock=migrate_windows_lock,
61
- migration_report=migrations)
57
+ git_count += sync_projects(directory, source_config)
62
58
  active.remove(key)
63
59
  visited.add(key)
64
60
  sync_sources(path)
@@ -78,4 +74,4 @@ def sync_project(path, install=False, migrate_windows_lock=False):
78
74
  if proc.returncode:
79
75
  raise click.ClickException(proc.stderr or proc.stdout or '项目安装失败')
80
76
  return {'project': str(path), 'installed': install, 'code_libraries': library_count,
81
- 'git_projects': git_count, 'git_lock_migrations': migrations}
77
+ 'git_projects': git_count, 'git_lock_migrations': []}
@@ -13,28 +13,34 @@ class WindowsBackend(GameBackend):
13
13
  def debug_channel(self, data, write_log):
14
14
  from ..mcstudio.runtime_debug import SafaiaChannel
15
15
  self._world_ready = data.get('mode') != 'local'
16
- self._log_offset, self._log_pending = 0, b''
16
+ self._ready_log_cursors = {}
17
17
  if data.get('mode') == 'local': data['world_ready'] = False
18
18
  return SafaiaChannel(write_log, ready=lambda: self._world_ready)
19
19
 
20
20
  def refresh(self, data, channel):
21
21
  if self._world_ready: return False
22
22
  from pathlib import Path
23
- path = Path(data['log_path'])
24
- try:
25
- with path.open('rb') as stream:
26
- stream.seek(self._log_offset)
27
- chunk = stream.read(65536)
28
- self._log_offset = stream.tell()
29
- except FileNotFoundError:
30
- return False
31
- text = self._log_pending + chunk
32
- # This engine log is emitted after client/server Python system creation.
33
- if b'OnHandlePushScreen hud_screen' in text:
34
- self._world_ready = data['world_ready'] = True
35
- self._log_pending = b''
36
- return True
37
- self._log_pending = text[-64:]
23
+ import re
24
+ for name in ('log_path', 'engine_log_path'):
25
+ if not data.get(name): continue
26
+ path = Path(data[name])
27
+ offset, pending = self._ready_log_cursors.get(name, (0, b''))
28
+ try:
29
+ with path.open('rb') as stream:
30
+ stream.seek(offset)
31
+ chunk = stream.read(65536)
32
+ offset = stream.tell()
33
+ except FileNotFoundError:
34
+ continue
35
+ text = pending + chunk
36
+ # Both markers require a created gameplay HUD. The native layout
37
+ # marker also works if the Python launch logging handler raises.
38
+ hud = (b'OnHandlePushScreen hud_screen' in text if name == 'log_path' else
39
+ re.search(rb"\bINFO GUI [^\r\n]*\] Layout main thread: [^\r\n]*controls completed [^\r\n]*for screen 'hud\.hud_screen'\.", text))
40
+ self._ready_log_cursors[name] = (offset, text[-1024:])
41
+ if hud:
42
+ self._world_ready = data['world_ready'] = True
43
+ return True
38
44
  return False
39
45
 
40
46
  def reload_restriction(self, data, kind):
@@ -89,7 +89,9 @@ def fetch_snapshot(url, ref):
89
89
  raise DependencyError('无效Git引用')
90
90
  origin = hashlib.sha256(url.encode('utf-8')).hexdigest()
91
91
  base = cache_root()
92
- snapshots = base / 'git' / origin
92
+ # Old archives may contain bytes converted by the host's Git settings.
93
+ # Keep them separate so even a verified old cache cannot reintroduce CRLF.
94
+ snapshots = base / 'git-archive-v2' / origin
93
95
  snapshots.mkdir(parents=True, exist_ok=True)
94
96
  with _source_lock(base / 'locks' / (origin + '.lock')):
95
97
  if re.fullmatch('[0-9a-f]{40}', ref) and (snapshots / ref).exists():
@@ -99,6 +101,11 @@ def fetch_snapshot(url, ref):
99
101
  repo, package = stage / 'repo', stage / 'snapshot'
100
102
  content = package / 'content'
101
103
  _git('init', '--bare', repo)
104
+ # Archive applies checkout conversions too. Preserve blob bytes,
105
+ # including binary/intentional CRLF files, on every host.
106
+ (repo / 'info').mkdir(exist_ok=True)
107
+ (repo / 'info' / 'attributes').write_bytes(
108
+ b'* -text -eol -filter -ident -working-tree-encoding\n')
102
109
  _git('-C', repo, 'fetch', '--depth=1', '--no-tags', url, ref)
103
110
  commit = _git('-C', repo, 'rev-parse', 'FETCH_HEAD^{commit}').decode().strip()
104
111
  if not re.fullmatch('[0-9a-f]{40}', commit) or (re.fullmatch('[0-9a-f]{40}', ref) and commit != ref):
@@ -108,11 +108,10 @@ def prepare_graph(root, config=None, migrate_windows_lock=False):
108
108
  root = Path(root).resolve()
109
109
  config = read_project(root) if config is None else config
110
110
  roots = declarations(root, config)
111
- expected, legacy = {}, False
111
+ expected = {}
112
112
  if (root / LOCK_FILE).exists():
113
113
  try:
114
114
  prior = json.loads((root / LOCK_FILE).read_text('utf-8'))
115
- legacy = prior['version'] == 1
116
115
  expected = {record['id']: record for record in prior['nodes']}
117
116
  except (ValueError, KeyError, TypeError) as exc:
118
117
  raise DependencyError('无法读取依赖锁文件 mcpy-git.lock.json。\n请从版本控制恢复该文件后运行 mcpy sync。') from exc
@@ -120,7 +119,7 @@ def prepare_graph(root, config=None, migrate_windows_lock=False):
120
119
  raise DependencyError('此项目需要较新版本的 mcpy,请先升级 mcpywrap。')
121
120
  registered = long_path(root / '.mcpy/git-projects')
122
121
  registered.mkdir(parents=True, exist_ok=True)
123
- nodes, active, migrations = {}, [], []
122
+ nodes, active = {}, []
124
123
  def visit(entry, supplied_source=None):
125
124
  source, commit = supplied_source or fetch_source(root, entry['git'], entry['rev'])
126
125
  project, payload, project_config, kind, target = _layout(source, entry)
@@ -138,11 +137,8 @@ def prepare_graph(root, config=None, migrate_windows_lock=False):
138
137
  active.append(key)
139
138
  source_hash = digest(source)
140
139
  previous = expected.get(key)
141
- migrating = legacy and previous is not None
142
- if previous and previous['source_sha256'] != source_hash:
143
- if not migrating or previous['source_sha256'] not in (
144
- windows_checkout_digest(source), windows_checkout_digest(source, crlf=False)):
145
- raise DependencyError(f"依赖 {entry['name']} 的源码校验失败。\n请保留 mcpy-git.lock.json,并重新获取该依赖的固定版本。")
140
+ # sync derives checksums from the pinned commit's verified snapshot.
141
+ # Old host-dependent checksums are outputs, not version constraints.
146
142
  children = []
147
143
  for child in declarations(project, project_config):
148
144
  children.append(visit(child))
@@ -197,65 +193,39 @@ def prepare_graph(root, config=None, migrate_windows_lock=False):
197
193
  from .dependencies import validate_game_files
198
194
  validate_game_files(stage, addon_directories(stage).values())
199
195
  content_hash = digest(stage)
200
- if previous and previous['sha256'] != content_hash and not migrating:
201
- raise DependencyError(f"依赖 {entry['name']} 的安装内容与锁文件不一致。\n请确认团队使用相同版本的 mcpywrap;不要删除锁文件。")
202
196
  final = registered / key
203
197
  if final.exists():
204
198
  if digest(final) != content_hash:
205
- # Old generated files may contain Windows line endings. Only
206
- # replace a verified old registration; preserve it for recovery.
207
- if not migrating or previous['sha256'] not in (
199
+ # Only replace an unchanged installation of the old lock.
200
+ if not previous or previous['sha256'] not in (
208
201
  digest(final), windows_checkout_digest(final, crlf=False)):
209
202
  raise DependencyError(f"依赖 {entry['name']} 的本地文件已修改。\n请将 {final} 移到项目外备份,再运行 mcpy sync。")
210
- backups = root/'.mcpy/registration-backups'
211
- backups.mkdir(parents=True, exist_ok=True)
212
- backup = Path(tempfile.mkdtemp(prefix=key[:12]+'-', dir=backups))/'project'
213
- os.replace(final, backup)
203
+ old = Path(temporary) / 'old'
204
+ os.replace(final, old)
214
205
  try:
215
206
  os.replace(stage, final)
216
207
  except BaseException:
217
- os.replace(backup, final)
208
+ os.replace(old, final)
218
209
  raise
219
210
  else:
220
211
  os.replace(stage, final)
221
212
  record = {'id': key, 'source': identity, 'source_sha256': source_hash, 'sha256': content_hash,
222
213
  'kind': kind, 'target': target, 'children': list(dict.fromkeys(children))}
223
- if migrating:
224
- migrations.append({'node': key, 'name': entry['name'], 'git': entry['git'], 'rev': commit,
225
- 'old_source_sha256': previous['source_sha256'], 'source_sha256': source_hash,
226
- 'old_registered_sha256': previous['sha256'], 'registered_sha256': content_hash})
227
214
  nodes[key] = record
228
215
  active.pop()
229
216
  return key
230
217
  root_ids = [visit(entry) for entry in roots]
231
- lock = {'version': 2, 'declarations': roots, 'roots': root_ids, 'nodes': list(nodes.values())}
232
- if migrations:
233
- lock['_lock_migrations'] = migrations
234
- return lock
218
+ return {'version': 2, 'declarations': roots, 'roots': root_ids, 'nodes': list(nodes.values())}
235
219
 
236
220
 
237
221
  def write_lock(root, lock):
238
- data = dict(lock)
239
- migrations = data.pop('_lock_migrations', [])
240
- report = []
241
- if migrations and (Path(root)/LOCK_FILE).exists():
242
- old = (Path(root)/LOCK_FILE).read_bytes()
243
- backup = Path(root)/'.mcpy/lock-backups'/(hashlib.sha256(old).hexdigest()+'.json')
244
- backup.parent.mkdir(parents=True, exist_ok=True)
245
- if backup.exists() and backup.read_bytes() != old:
246
- raise DependencyError('无法备份旧依赖记录,原锁文件未修改。')
247
- backup.write_bytes(old)
248
- report.append({'project': str(root), 'backup': str(backup), 'nodes': migrations})
249
- _write_json(Path(root) / LOCK_FILE, data)
250
- return report
222
+ _write_json(Path(root) / LOCK_FILE, lock)
251
223
 
252
224
 
253
225
  def sync_projects(root, config=None, migrate_windows_lock=False, migration_report=None):
254
- # Kept for older callers; recognized legacy locks now migrate automatically.
255
- lock = prepare_graph(root, config, migrate_windows_lock=migrate_windows_lock)
256
- report = write_lock(root, lock)
257
- if migration_report is not None:
258
- migration_report.extend(report)
226
+ # Legacy arguments are retained for callers; sync simply recalculates the lock.
227
+ lock = prepare_graph(root, config)
228
+ write_lock(root, lock)
259
229
  return len(lock['nodes'])
260
230
 
261
231
 
@@ -11,9 +11,9 @@
11
11
  "Loader.c": "f2f1f781ce82fc30c62a6ce22bb048d3b023f6ff500e6ec8228da28b4dbf1b4a"
12
12
  },
13
13
  "files": {
14
- "Injector.exe": "376bbefafdab254e413e6a6d9cb1b880e1e94fd259bae55c8a882e17a383892e",
15
- "Loader.dll": "a4f4da0a3d65dfd94802ac2dd30e5edea81d34659df451c961de15e44a87f6ac",
16
- "McpyMcsAuth.dll": "c5f105f2e8bd821aa8a0bc1435cc42bac2ca690343a63f8c773eb593971a5ffb",
14
+ "Injector.exe": "aa185d69f11e138df90f446c239d075ef6ab4e5c5e0457981a6c09f52e04b7b9",
15
+ "Loader.dll": "03956417da34f569dd6e794076f2252ff05cb286fd1a8dc6ce966dc78911330e",
16
+ "McpyMcsAuth.dll": "b1270f169319e8acebca7d49be966d54c769590d708157c3984e33f9a943c1d7",
17
17
  "publisher.cer": "e5aa2ac39df40804ed8b08fe8e43c4a2b8923f0d02a360708486b2db5b6303d7"
18
18
  }
19
19
  }
@@ -1,5 +1,5 @@
1
1
  {
2
- "executable_sha256": "81642e2d7c9c5097cd86b139f41f75a6f3ca12cb5b2bddbc0427cb2aee92bb64",
2
+ "executable_sha256": "4f4f8b0a8eae4b8d409ae90e222886623c4b53ed66525d8267ffaadc1db65442",
3
3
  "source_sha256": "0c0b2a02bfecea68b824a486ac1d88cde6bd9fc8ee8e4c9a6939870bd8e710d1",
4
4
  "sources": {
5
5
  "video_capture.h": "8daee1b8c1c8273bc8d19d39f0559f82c30d7ff900894bcc2cc197d3881532d7",
@@ -144,6 +144,8 @@ def open_ui_crate_mod(behavior_pack_path, run_event_loop=True):
144
144
 
145
145
  # 主窗口
146
146
  window = QWidget()
147
+ # Closed embedded editors must release their signal closures before Qt exits.
148
+ window.setAttribute(Qt.WidgetAttribute.WA_DeleteOnClose)
147
149
  window.setWindowTitle("Minecraft Mod 创建工具")
148
150
  window.setMinimumWidth(900) # 增加窗口宽度以适应目录树
149
151
  window.setMinimumHeight(600) # 设置窗口最小高度
@@ -68,7 +68,10 @@ def _git(*args):
68
68
  return value[4:]
69
69
  return value
70
70
  try:
71
- result = subprocess.run(['git', '-c', 'core.hooksPath=', '-c', 'core.longpaths=true', *map(argument, args)],
71
+ result = subprocess.run(['git', '-c', 'core.hooksPath=', '-c', 'core.longpaths=true',
72
+ '-c', 'core.autocrlf=false', '-c', 'core.eol=lf',
73
+ '-c', 'core.attributesFile=' + os.devnull, *map(argument, args)],
74
+ env=dict(os.environ, GIT_ATTR_NOSYSTEM='1'),
72
75
  capture_output=True, timeout=180)
73
76
  except (OSError, subprocess.TimeoutExpired) as exc:
74
77
  raise DependencyError(f'无法获取代码库: {exc}') from exc
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: mcpywrap
3
- Version: 0.4.3
3
+ Version: 0.4.4
4
4
  Summary: A wrapper for Minecraft China Edition Addons management
5
5
  Author-email: boybook <boybook@easecation.net>
6
6
  License-Expression: MIT
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
4
4
 
5
5
  [project]
6
6
  name = "mcpywrap"
7
- version = "0.4.3"
7
+ version = "0.4.4"
8
8
  description = "A wrapper for Minecraft China Edition Addons management"
9
9
  readme = "README.md"
10
10
  authors = [{name = "boybook", email = "boybook@easecation.net"}]
@@ -63,7 +63,7 @@ description: 使用 mcpywrap 管理《我的世界》中国版 Addon/地图、
63
63
  `--project` 必须是调用端路径且目录已存在;纯连接不需要 init。远程实际会话保存在 Windows 的 serve 数据目录。
64
64
  远程结果中的 `project/image` 是调用端路径;`remote_project/executable/log_path/engine_log_path` 是 Windows 信息。读取远程日志用 logs,不在 macOS 打开 Windows 路径。
65
65
 
66
- Windows/macOS 共用依赖锁;克隆后用 `sync --json` 恢复,旧平台格式自动验证和备份。向用户说明依赖名称与下一步命令,完整迁移信息保留在 JSON 中。
66
+ Windows/macOS 共用依赖锁;克隆后用 `sync --json` 恢复。sync 按固定 Git 提交重新计算跨平台摘要并写回锁,不改变依赖版本,也不创建备份或要求迁移。两端 CLI 都应包含此修复;首次使用新的源码缓存需联网获取固定提交。
67
67
 
68
68
  ## 项目工作流
69
69
 
@@ -116,7 +116,8 @@ export.path相对该项目描述。没有export时工具可识别符合既有目
116
116
  | 新克隆缺少缓存 | 执行sync,保留现有锁定提交 |
117
117
  | 布局无法识别 | 查上游export/目录,再传明确subdir、kind、target;不猜安装位置 |
118
118
  | 目标已有手工框架或另一依赖 | 核对归属并制定明确迁移;不直接覆盖或删业务目录 |
119
- | 源码摘要不符 | 定位具体缓存条目,保留锁的预期内容;不删锁或清空全部缓存来掩盖差异 |
119
+ | 旧平台锁摘要不符 | 更新两端 CLI 后运行 sync,按固定提交直接重算锁;不必删除锁或更改依赖版本 |
120
+ | 共享源码缓存损坏 | 定位具体缓存条目并重新获取;不清空全部缓存,不把手动改动写入锁 |
120
121
  | 获取来源失败 | 保留失败信息及现有声明,不静默换镜像、更新版本或转为pip安装 |
121
122
  | 构建成功但游戏导入失败 | 检查产物路径、入口、端侧与游戏日志;不是工具Python缺包的充分证据 |
122
123
 
@@ -87,6 +87,26 @@ class CodeLibraries(unittest.TestCase):
87
87
  self.build()
88
88
  self.assertFalse((self.out / 'behavior_pack/MyMod/Library').exists())
89
89
 
90
+ def test_windows_lock_and_installation_are_recalculated_from_pinned_source(self):
91
+ from mcpywrap.source_files import digest
92
+ sync_libraries(self.main)
93
+ path = self.main / LOCK_FILE
94
+ canonical = path.read_bytes()
95
+ installed = resolve_libraries(self.main)[0]['source']
96
+ for file in installed.rglob('*'):
97
+ if file.is_file():
98
+ file.write_bytes(file.read_bytes().replace(b'\r\n', b'\n').replace(b'\n', b'\r\n'))
99
+ lock = json.loads(canonical)
100
+ lock['libraries'][0]['sha256'] = digest(installed)
101
+ self.assertNotEqual(lock['libraries'][0]['sha256'], json.loads(canonical)['libraries'][0]['sha256'])
102
+ path.write_text(json.dumps(lock))
103
+ clone = self.root / 'clone'
104
+ shutil.copytree(self.main, clone, ignore=shutil.ignore_patterns('.mcpy'))
105
+ for project in (self.main, clone):
106
+ sync_libraries(project)
107
+ resolve_libraries(project)
108
+ self.assertEqual((project / LOCK_FILE).read_bytes(), canonical)
109
+
90
110
  def test_tamper_failed_fetch_and_handwritten_conflicts_preserve_output(self):
91
111
  sync_libraries(self.main)
92
112
  self.build()
@@ -18,6 +18,28 @@ from mcpywrap.engines.windows import WindowsBackend
18
18
 
19
19
 
20
20
  class BackendTests(unittest.TestCase):
21
+ def test_windows_native_hud_layout_when_python_launch_log_is_missing(self):
22
+ backend=WindowsBackend()
23
+ game=self.root/'game.log';engine=self.root/'engine.log'
24
+ data={'mode':'local','log_path':str(game),'engine_log_path':str(engine)}
25
+ channel=backend.debug_channel(data,lambda text:None);self.addCleanup(channel.close)
26
+ game.write_bytes(b'UI registered\n')
27
+ engine.write_bytes(b"[INFO GUI 1 2] Destroyed 'world_loading_progress_screen'\n[INFO GUI 1 2] Layout main thread: Full re-layout of 364 controls completed in 3ms for screen 'pause.pause_screen'.\n")
28
+ self.assertFalse(backend.refresh(data,channel));self.assertFalse(channel.ready())
29
+ marker=b"[2026-10-10 16:54:45:664 INFO GUI 90568 80348] Layout main thread: Full re-layout of 364 controls completed in 3.714000ms for screen 'hud.hud_screen'."
30
+ with engine.open('ab') as stream:stream.write(marker[:120])
31
+ self.assertFalse(backend.refresh(data,channel))
32
+ with engine.open('ab') as stream:stream.write(marker[120:]+b'\n')
33
+ self.assertTrue(backend.refresh(data,channel));self.assertTrue(data['world_ready']);self.assertTrue(channel.ready())
34
+ self.assertFalse(backend.refresh(data,channel))
35
+
36
+ def test_windows_native_hud_requires_engine_log_not_arbitrary_python_text(self):
37
+ backend=WindowsBackend();game=self.root/'game.log'
38
+ data={'mode':'local','log_path':str(game),'engine_log_path':str(self.root/'missing.log')}
39
+ channel=backend.debug_channel(data,lambda text:None);self.addCleanup(channel.close)
40
+ game.write_bytes(b"[INFO GUI 1 2] Layout main thread: 10 controls completed for screen 'hud.hud_screen'.\n")
41
+ self.assertFalse(backend.refresh(data,channel));self.assertFalse(channel.ready())
42
+
21
43
  def test_windows_world_readiness_waits_for_client_system_initialization(self):
22
44
  backend = WindowsBackend()
23
45
  path = self.root/'game.log'