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.
- {mcpywrap_core-0.6.2 → mcpywrap_core-0.6.4}/PKG-INFO +1 -1
- mcpywrap_core-0.6.4/mcpywrap_core/_version.py +1 -0
- {mcpywrap_core-0.6.2 → mcpywrap_core-0.6.4}/mcpywrap_core/api.py +6 -6
- {mcpywrap_core-0.6.2 → mcpywrap_core-0.6.4}/mcpywrap_core/builders/assembly.py +14 -0
- {mcpywrap_core-0.6.2 → mcpywrap_core-0.6.4}/mcpywrap_core/builders/dependency_manager.py +59 -6
- mcpywrap_core-0.6.4/mcpywrap_core/builders/output_lock.py +46 -0
- {mcpywrap_core-0.6.2 → mcpywrap_core-0.6.4}/mcpywrap_core/builders/project_builder.py +19 -4
- {mcpywrap_core-0.6.2 → mcpywrap_core-0.6.4}/mcpywrap_core/builders/watcher.py +7 -2
- {mcpywrap_core-0.6.2 → mcpywrap_core-0.6.4}/mcpywrap_core/cli.py +1 -1
- {mcpywrap_core-0.6.2 → mcpywrap_core-0.6.4}/mcpywrap_core/command_context.py +2 -2
- {mcpywrap_core-0.6.2 → mcpywrap_core-0.6.4}/mcpywrap_core/commands/add_cmd.py +26 -6
- {mcpywrap_core-0.6.2 → mcpywrap_core-0.6.4}/mcpywrap_core/commands/build_cmd.py +2 -0
- {mcpywrap_core-0.6.2 → mcpywrap_core-0.6.4}/mcpywrap_core/commands/dependency_prompt.py +2 -0
- mcpywrap_core-0.6.4/mcpywrap_core/commands/deps_cmd.py +27 -0
- {mcpywrap_core-0.6.2 → mcpywrap_core-0.6.4}/mcpywrap_core/commands/dev_cmd.py +36 -31
- {mcpywrap_core-0.6.2 → mcpywrap_core-0.6.4}/mcpywrap_core/commands/package_cmd.py +2 -0
- {mcpywrap_core-0.6.2 → mcpywrap_core-0.6.4}/mcpywrap_core/commands/remove_cmd.py +8 -2
- {mcpywrap_core-0.6.2 → mcpywrap_core-0.6.4}/mcpywrap_core/commands/run_cmd.py +12 -3
- {mcpywrap_core-0.6.2 → mcpywrap_core-0.6.4}/mcpywrap_core/commands/sync_cmd.py +5 -2
- {mcpywrap_core-0.6.2 → mcpywrap_core-0.6.4}/mcpywrap_core/consumer_prepare.py +7 -2
- {mcpywrap_core-0.6.2 → mcpywrap_core-0.6.4}/mcpywrap_core/dependencies.py +94 -15
- mcpywrap_core-0.6.4/mcpywrap_core/dependency_feedback.py +29 -0
- {mcpywrap_core-0.6.2 → mcpywrap_core-0.6.4}/mcpywrap_core/engines/install.py +1 -1
- {mcpywrap_core-0.6.2 → mcpywrap_core-0.6.4}/mcpywrap_core/engines/windows.py +49 -6
- {mcpywrap_core-0.6.2 → mcpywrap_core-0.6.4}/mcpywrap_core/frameworks.py +2 -1
- {mcpywrap_core-0.6.2 → mcpywrap_core-0.6.4}/mcpywrap_core/git_projects.py +103 -26
- mcpywrap_core-0.6.4/mcpywrap_core/mcstudio/lan_locator.py +94 -0
- mcpywrap_core-0.6.4/mcpywrap_core/mcstudio/lan_memory.py +142 -0
- mcpywrap_core-0.6.4/mcpywrap_core/mcstudio/lan_window.py +35 -0
- {mcpywrap_core-0.6.2 → mcpywrap_core-0.6.4}/mcpywrap_core/mcstudio/runtime_debug.py +7 -0
- {mcpywrap_core-0.6.2 → mcpywrap_core-0.6.4}/mcpywrap_core/mcstudio/sessions.py +6 -2
- {mcpywrap_core-0.6.2 → mcpywrap_core-0.6.4}/mcpywrap_core/mobile_host/client.py +2 -2
- {mcpywrap_core-0.6.2 → mcpywrap_core-0.6.4}/mcpywrap_core/mobile_host/intervention.py +2 -2
- {mcpywrap_core-0.6.2 → mcpywrap_core-0.6.4}/mcpywrap_core/mobile_host/routing.py +18 -0
- {mcpywrap_core-0.6.2 → mcpywrap_core-0.6.4}/mcpywrap_core/operations/build.py +18 -10
- {mcpywrap_core-0.6.2 → mcpywrap_core-0.6.4}/mcpywrap_core/operations/package.py +3 -3
- {mcpywrap_core-0.6.2 → mcpywrap_core-0.6.4}/mcpywrap_core/operations/project.py +13 -4
- {mcpywrap_core-0.6.2 → mcpywrap_core-0.6.4}/mcpywrap_core/operations/sync.py +10 -8
- {mcpywrap_core-0.6.2 → mcpywrap_core-0.6.4}/mcpywrap_core/project_dependencies.py +46 -5
- {mcpywrap_core-0.6.2 → mcpywrap_core-0.6.4}/mcpywrap_core/project_scripts.py +6 -4
- {mcpywrap_core-0.6.2 → mcpywrap_core-0.6.4}/mcpywrap_core/remote/service.py +1 -1
- {mcpywrap_core-0.6.2 → mcpywrap_core-0.6.4}/mcpywrap_core/runtime/deployment.py +1 -1
- {mcpywrap_core-0.6.2 → mcpywrap_core-0.6.4}/mcpywrap_core/runtime/groups.py +52 -9
- mcpywrap_core-0.6.4/mcpywrap_core/runtime/lan_menu.py +72 -0
- {mcpywrap_core-0.6.2 → mcpywrap_core-0.6.4}/mcpywrap_core/runtime/preparation.py +3 -1
- {mcpywrap_core-0.6.2 → mcpywrap_core-0.6.4}/mcpywrap_core/runtime/profiles.py +1 -1
- mcpywrap_core-0.6.4/mcpywrap_core/runtime/windows_join.py +193 -0
- {mcpywrap_core-0.6.2 → mcpywrap_core-0.6.4}/mcpywrap_core/skill/SKILL.md +2 -1
- {mcpywrap_core-0.6.2 → mcpywrap_core-0.6.4}/mcpywrap_core/skill/references/application-host.md +10 -6
- {mcpywrap_core-0.6.2 → mcpywrap_core-0.6.4}/mcpywrap_core/skill/references/consumer-prepare.md +2 -0
- {mcpywrap_core-0.6.2 → mcpywrap_core-0.6.4}/mcpywrap_core/skill/references/dual-clients.md +12 -4
- {mcpywrap_core-0.6.2 → mcpywrap_core-0.6.4}/mcpywrap_core/skill/references/macos-local.md +3 -2
- {mcpywrap_core-0.6.2 → mcpywrap_core-0.6.4}/mcpywrap_core/skill/references/project-dependencies.md +29 -1
- {mcpywrap_core-0.6.2 → mcpywrap_core-0.6.4}/mcpywrap_core/skill/references/project-workflow.md +2 -2
- {mcpywrap_core-0.6.2 → mcpywrap_core-0.6.4}/mcpywrap_core/skill/references/troubleshooting.md +3 -0
- {mcpywrap_core-0.6.2 → mcpywrap_core-0.6.4}/mcpywrap_core/skill/scripts/bootstrap.py +2 -0
- {mcpywrap_core-0.6.2 → mcpywrap_core-0.6.4}/mcpywrap_core/skill/scripts/smoke.py +1 -1
- {mcpywrap_core-0.6.2 → mcpywrap_core-0.6.4}/mcpywrap_core/ui/project_ui.py +86 -10
- {mcpywrap_core-0.6.2 → mcpywrap_core-0.6.4}/mcpywrap_core/ui/session_views.py +2 -0
- {mcpywrap_core-0.6.2 → mcpywrap_core-0.6.4}/mcpywrap_core.egg-info/PKG-INFO +1 -1
- {mcpywrap_core-0.6.2 → mcpywrap_core-0.6.4}/mcpywrap_core.egg-info/SOURCES.txt +8 -0
- mcpywrap_core-0.6.2/mcpywrap_core/_version.py +0 -1
- {mcpywrap_core-0.6.2 → mcpywrap_core-0.6.4}/LICENSE +0 -0
- {mcpywrap_core-0.6.2 → mcpywrap_core-0.6.4}/MANIFEST.in +0 -0
- {mcpywrap_core-0.6.2 → mcpywrap_core-0.6.4}/README.md +0 -0
- {mcpywrap_core-0.6.2 → mcpywrap_core-0.6.4}/THIRD_PARTY_NOTICES.md +0 -0
- {mcpywrap_core-0.6.2 → mcpywrap_core-0.6.4}/mcpywrap_core/__init__.py +0 -0
- {mcpywrap_core-0.6.2 → mcpywrap_core-0.6.4}/mcpywrap_core/__main__.py +0 -0
- {mcpywrap_core-0.6.2 → mcpywrap_core-0.6.4}/mcpywrap_core/_process_identity.py +0 -0
- {mcpywrap_core-0.6.2 → mcpywrap_core-0.6.4}/mcpywrap_core/_script_worker.py +0 -0
- {mcpywrap_core-0.6.2 → mcpywrap_core-0.6.4}/mcpywrap_core/builders/AddonsPack.py +0 -0
- {mcpywrap_core-0.6.2 → mcpywrap_core-0.6.4}/mcpywrap_core/builders/MapPack.py +0 -0
- {mcpywrap_core-0.6.2 → mcpywrap_core-0.6.4}/mcpywrap_core/builders/__init__.py +0 -0
- {mcpywrap_core-0.6.2 → mcpywrap_core-0.6.4}/mcpywrap_core/builders/file_merge.py +0 -0
- {mcpywrap_core-0.6.2 → mcpywrap_core-0.6.4}/mcpywrap_core/code_libraries.py +0 -0
- {mcpywrap_core-0.6.2 → mcpywrap_core-0.6.4}/mcpywrap_core/commands/__init__.py +0 -0
- {mcpywrap_core-0.6.2 → mcpywrap_core-0.6.4}/mcpywrap_core/commands/connect_cmd.py +0 -0
- {mcpywrap_core-0.6.2 → mcpywrap_core-0.6.4}/mcpywrap_core/commands/default_cmd.py +0 -0
- {mcpywrap_core-0.6.2 → mcpywrap_core-0.6.4}/mcpywrap_core/commands/deployment_cmd.py +0 -0
- {mcpywrap_core-0.6.2 → mcpywrap_core-0.6.4}/mcpywrap_core/commands/deployment_output.py +0 -0
- {mcpywrap_core-0.6.2 → mcpywrap_core-0.6.4}/mcpywrap_core/commands/desktop_cmd.py +0 -0
- {mcpywrap_core-0.6.2 → mcpywrap_core-0.6.4}/mcpywrap_core/commands/doctor_cmd.py +0 -0
- {mcpywrap_core-0.6.2 → mcpywrap_core-0.6.4}/mcpywrap_core/commands/edit_cmd.py +0 -0
- {mcpywrap_core-0.6.2 → mcpywrap_core-0.6.4}/mcpywrap_core/commands/engine_cmd.py +0 -0
- {mcpywrap_core-0.6.2 → mcpywrap_core-0.6.4}/mcpywrap_core/commands/host_cmd.py +0 -0
- {mcpywrap_core-0.6.2 → mcpywrap_core-0.6.4}/mcpywrap_core/commands/init_cmd.py +0 -0
- {mcpywrap_core-0.6.2 → mcpywrap_core-0.6.4}/mcpywrap_core/commands/mod_cmd.py +0 -0
- {mcpywrap_core-0.6.2 → mcpywrap_core-0.6.4}/mcpywrap_core/commands/modsdk_cmd.py +0 -0
- {mcpywrap_core-0.6.2 → mcpywrap_core-0.6.4}/mcpywrap_core/commands/publish_cmd.py +0 -0
- {mcpywrap_core-0.6.2 → mcpywrap_core-0.6.4}/mcpywrap_core/commands/record_cmd.py +0 -0
- {mcpywrap_core-0.6.2 → mcpywrap_core-0.6.4}/mcpywrap_core/commands/runtime_cmd.py +0 -0
- {mcpywrap_core-0.6.2 → mcpywrap_core-0.6.4}/mcpywrap_core/commands/runtime_input_cmd.py +0 -0
- {mcpywrap_core-0.6.2 → mcpywrap_core-0.6.4}/mcpywrap_core/commands/runtime_player_cmd.py +0 -0
- {mcpywrap_core-0.6.2 → mcpywrap_core-0.6.4}/mcpywrap_core/commands/runtime_ui_cmd.py +0 -0
- {mcpywrap_core-0.6.2 → mcpywrap_core-0.6.4}/mcpywrap_core/commands/script_cmd.py +0 -0
- {mcpywrap_core-0.6.2 → mcpywrap_core-0.6.4}/mcpywrap_core/commands/serve_cmd.py +0 -0
- {mcpywrap_core-0.6.2 → mcpywrap_core-0.6.4}/mcpywrap_core/commands/session_cmd.py +0 -0
- {mcpywrap_core-0.6.2 → mcpywrap_core-0.6.4}/mcpywrap_core/commands/skill_cmd.py +0 -0
- {mcpywrap_core-0.6.2 → mcpywrap_core-0.6.4}/mcpywrap_core/commands/ui_cmd.py +0 -0
- {mcpywrap_core-0.6.2 → mcpywrap_core-0.6.4}/mcpywrap_core/config.py +0 -0
- {mcpywrap_core-0.6.2 → mcpywrap_core-0.6.4}/mcpywrap_core/core-contract.json +0 -0
- {mcpywrap_core-0.6.2 → mcpywrap_core-0.6.4}/mcpywrap_core/custom_packaging.py +0 -0
- {mcpywrap_core-0.6.2 → mcpywrap_core-0.6.4}/mcpywrap_core/engines/__init__.py +0 -0
- {mcpywrap_core-0.6.2 → mcpywrap_core-0.6.4}/mcpywrap_core/engines/android_icon.py +0 -0
- {mcpywrap_core-0.6.2 → mcpywrap_core-0.6.4}/mcpywrap_core/engines/apk_profile.py +0 -0
- {mcpywrap_core-0.6.2 → mcpywrap_core-0.6.4}/mcpywrap_core/engines/backend.py +0 -0
- {mcpywrap_core-0.6.2 → mcpywrap_core-0.6.4}/mcpywrap_core/engines/host.py +0 -0
- {mcpywrap_core-0.6.2 → mcpywrap_core-0.6.4}/mcpywrap_core/engines/macos.py +0 -0
- {mcpywrap_core-0.6.2 → mcpywrap_core-0.6.4}/mcpywrap_core/engines/macos_icons.py +0 -0
- {mcpywrap_core-0.6.2 → mcpywrap_core-0.6.4}/mcpywrap_core/engines/macos_network.py +0 -0
- {mcpywrap_core-0.6.2 → mcpywrap_core-0.6.4}/mcpywrap_core/engines/official.py +0 -0
- {mcpywrap_core-0.6.2 → mcpywrap_core-0.6.4}/mcpywrap_core/engines/preferences.py +0 -0
- {mcpywrap_core-0.6.2 → mcpywrap_core-0.6.4}/mcpywrap_core/engines/tui.py +0 -0
- {mcpywrap_core-0.6.2 → mcpywrap_core-0.6.4}/mcpywrap_core/framework_presets.py +0 -0
- {mcpywrap_core-0.6.2 → mcpywrap_core-0.6.4}/mcpywrap_core/git_cache.py +0 -0
- {mcpywrap_core-0.6.2 → mcpywrap_core-0.6.4}/mcpywrap_core/host.py +0 -0
- {mcpywrap_core-0.6.2 → mcpywrap_core-0.6.4}/mcpywrap_core/host_assets.py +0 -0
- {mcpywrap_core-0.6.2 → mcpywrap_core-0.6.4}/mcpywrap_core/input_executor.py +0 -0
- {mcpywrap_core-0.6.2 → mcpywrap_core-0.6.4}/mcpywrap_core/input_plan.py +0 -0
- {mcpywrap_core-0.6.2 → mcpywrap_core-0.6.4}/mcpywrap_core/mcstudio/SimpleMonitor.py +0 -0
- {mcpywrap_core-0.6.2 → mcpywrap_core-0.6.4}/mcpywrap_core/mcstudio/__init__.py +0 -0
- {mcpywrap_core-0.6.2 → mcpywrap_core-0.6.4}/mcpywrap_core/mcstudio/auth_interaction.py +0 -0
- {mcpywrap_core-0.6.2 → mcpywrap_core-0.6.4}/mcpywrap_core/mcstudio/bridge_assets.py +0 -0
- {mcpywrap_core-0.6.2 → mcpywrap_core-0.6.4}/mcpywrap_core/mcstudio/deployment_links.py +0 -0
- {mcpywrap_core-0.6.2 → mcpywrap_core-0.6.4}/mcpywrap_core/mcstudio/diagnostics.py +0 -0
- {mcpywrap_core-0.6.2 → mcpywrap_core-0.6.4}/mcpywrap_core/mcstudio/discovery.py +0 -0
- {mcpywrap_core-0.6.2 → mcpywrap_core-0.6.4}/mcpywrap_core/mcstudio/editor.py +0 -0
- {mcpywrap_core-0.6.2 → mcpywrap_core-0.6.4}/mcpywrap_core/mcstudio/file_logs.py +0 -0
- {mcpywrap_core-0.6.2 → mcpywrap_core-0.6.4}/mcpywrap_core/mcstudio/game.py +0 -0
- {mcpywrap_core-0.6.2 → mcpywrap_core-0.6.4}/mcpywrap_core/mcstudio/host_input.py +0 -0
- {mcpywrap_core-0.6.2 → mcpywrap_core-0.6.4}/mcpywrap_core/mcstudio/hot_reload.py +0 -0
- {mcpywrap_core-0.6.2 → mcpywrap_core-0.6.4}/mcpywrap_core/mcstudio/image.py +0 -0
- {mcpywrap_core-0.6.2 → mcpywrap_core-0.6.4}/mcpywrap_core/mcstudio/input_sequence.py +0 -0
- {mcpywrap_core-0.6.2 → mcpywrap_core-0.6.4}/mcpywrap_core/mcstudio/launcher_control.py +0 -0
- {mcpywrap_core-0.6.2 → mcpywrap_core-0.6.4}/mcpywrap_core/mcstudio/launcher_python.py +0 -0
- {mcpywrap_core-0.6.2 → mcpywrap_core-0.6.4}/mcpywrap_core/mcstudio/log_colorizer.py +0 -0
- {mcpywrap_core-0.6.2 → mcpywrap_core-0.6.4}/mcpywrap_core/mcstudio/log_protocol.py +0 -0
- {mcpywrap_core-0.6.2 → mcpywrap_core-0.6.4}/mcpywrap_core/mcstudio/log_query.py +0 -0
- {mcpywrap_core-0.6.2 → mcpywrap_core-0.6.4}/mcpywrap_core/mcstudio/log_stream.py +0 -0
- {mcpywrap_core-0.6.2 → mcpywrap_core-0.6.4}/mcpywrap_core/mcstudio/mcs.py +0 -0
- {mcpywrap_core-0.6.2 → mcpywrap_core-0.6.4}/mcpywrap_core/mcstudio/mcs_auth.py +0 -0
- {mcpywrap_core-0.6.2 → mcpywrap_core-0.6.4}/mcpywrap_core/mcstudio/network.py +0 -0
- {mcpywrap_core-0.6.2 → mcpywrap_core-0.6.4}/mcpywrap_core/mcstudio/private_logs.py +0 -0
- {mcpywrap_core-0.6.2 → mcpywrap_core-0.6.4}/mcpywrap_core/mcstudio/processes.py +0 -0
- {mcpywrap_core-0.6.2 → mcpywrap_core-0.6.4}/mcpywrap_core/mcstudio/recording_worker.py +0 -0
- {mcpywrap_core-0.6.2 → mcpywrap_core-0.6.4}/mcpywrap_core/mcstudio/recordings.py +0 -0
- {mcpywrap_core-0.6.2 → mcpywrap_core-0.6.4}/mcpywrap_core/mcstudio/runtime_cppconfig.py +0 -0
- {mcpywrap_core-0.6.2 → mcpywrap_core-0.6.4}/mcpywrap_core/mcstudio/runtime_input_payload.py +0 -0
- {mcpywrap_core-0.6.2 → mcpywrap_core-0.6.4}/mcpywrap_core/mcstudio/runtime_key_timeline_payload.py +0 -0
- {mcpywrap_core-0.6.2 → mcpywrap_core-0.6.4}/mcpywrap_core/mcstudio/runtime_player_payload.py +0 -0
- {mcpywrap_core-0.6.2 → mcpywrap_core-0.6.4}/mcpywrap_core/mcstudio/runtime_ui.py +0 -0
- {mcpywrap_core-0.6.2 → mcpywrap_core-0.6.4}/mcpywrap_core/mcstudio/runtime_ui_outline.py +0 -0
- {mcpywrap_core-0.6.2 → mcpywrap_core-0.6.4}/mcpywrap_core/mcstudio/runtime_ui_payload.py +0 -0
- {mcpywrap_core-0.6.2 → mcpywrap_core-0.6.4}/mcpywrap_core/mcstudio/screenshot.py +0 -0
- {mcpywrap_core-0.6.2 → mcpywrap_core-0.6.4}/mcpywrap_core/mcstudio/session_capabilities.py +0 -0
- {mcpywrap_core-0.6.2 → mcpywrap_core-0.6.4}/mcpywrap_core/mcstudio/session_worker.py +0 -0
- {mcpywrap_core-0.6.2 → mcpywrap_core-0.6.4}/mcpywrap_core/mcstudio/studio_server.py +0 -0
- {mcpywrap_core-0.6.2 → mcpywrap_core-0.6.4}/mcpywrap_core/mcstudio/studio_server_ui.py +0 -0
- {mcpywrap_core-0.6.2 → mcpywrap_core-0.6.4}/mcpywrap_core/mcstudio/symlink_helper_global.py +0 -0
- {mcpywrap_core-0.6.2 → mcpywrap_core-0.6.4}/mcpywrap_core/mcstudio/symlink_helper_map.py +0 -0
- {mcpywrap_core-0.6.2 → mcpywrap_core-0.6.4}/mcpywrap_core/mcstudio/symlinks.py +0 -0
- {mcpywrap_core-0.6.2 → mcpywrap_core-0.6.4}/mcpywrap_core/mcstudio/unified_input.py +0 -0
- {mcpywrap_core-0.6.2 → mcpywrap_core-0.6.4}/mcpywrap_core/mcstudio/window.py +0 -0
- {mcpywrap_core-0.6.2 → mcpywrap_core-0.6.4}/mcpywrap_core/mcstudio/window_activation.py +0 -0
- {mcpywrap_core-0.6.2 → mcpywrap_core-0.6.4}/mcpywrap_core/minecraft/__init__.py +0 -0
- {mcpywrap_core-0.6.2 → mcpywrap_core-0.6.4}/mcpywrap_core/minecraft/addons.py +0 -0
- {mcpywrap_core-0.6.2 → mcpywrap_core-0.6.4}/mcpywrap_core/minecraft/level_dat.py +0 -0
- {mcpywrap_core-0.6.2 → mcpywrap_core-0.6.4}/mcpywrap_core/minecraft/map.py +0 -0
- {mcpywrap_core-0.6.2 → mcpywrap_core-0.6.4}/mcpywrap_core/minecraft/modsdk_environment.py +0 -0
- {mcpywrap_core-0.6.2 → mcpywrap_core-0.6.4}/mcpywrap_core/minecraft/modsdk_versions.py +0 -0
- {mcpywrap_core-0.6.2 → mcpywrap_core-0.6.4}/mcpywrap_core/minecraft/netease_modsdk.py +0 -0
- {mcpywrap_core-0.6.2 → mcpywrap_core-0.6.4}/mcpywrap_core/minecraft/template/generate_mod_files.py +0 -0
- {mcpywrap_core-0.6.2 → mcpywrap_core-0.6.4}/mcpywrap_core/minecraft/template/mod_template.py +0 -0
- {mcpywrap_core-0.6.2 → mcpywrap_core-0.6.4}/mcpywrap_core/mobile_host/__init__.py +0 -0
- {mcpywrap_core-0.6.2 → mcpywrap_core-0.6.4}/mcpywrap_core/mobile_host/options.py +0 -0
- {mcpywrap_core-0.6.2 → mcpywrap_core-0.6.4}/mcpywrap_core/mobile_host/preparation.py +0 -0
- {mcpywrap_core-0.6.2 → mcpywrap_core-0.6.4}/mcpywrap_core/mobile_host/profiles.py +0 -0
- {mcpywrap_core-0.6.2 → mcpywrap_core-0.6.4}/mcpywrap_core/mobile_host/receipts.py +0 -0
- {mcpywrap_core-0.6.2 → mcpywrap_core-0.6.4}/mcpywrap_core/mobile_host/streams.py +0 -0
- {mcpywrap_core-0.6.2 → mcpywrap_core-0.6.4}/mcpywrap_core/operations/__init__.py +0 -0
- {mcpywrap_core-0.6.2 → mcpywrap_core-0.6.4}/mcpywrap_core/operations/input_snapshot.py +0 -0
- {mcpywrap_core-0.6.2 → mcpywrap_core-0.6.4}/mcpywrap_core/prepare_environment.py +0 -0
- {mcpywrap_core-0.6.2 → mcpywrap_core-0.6.4}/mcpywrap_core/project_init.py +0 -0
- {mcpywrap_core-0.6.2 → mcpywrap_core-0.6.4}/mcpywrap_core/recording_io.py +0 -0
- {mcpywrap_core-0.6.2 → mcpywrap_core-0.6.4}/mcpywrap_core/remote/__init__.py +0 -0
- {mcpywrap_core-0.6.2 → mcpywrap_core-0.6.4}/mcpywrap_core/remote/client.py +0 -0
- {mcpywrap_core-0.6.2 → mcpywrap_core-0.6.4}/mcpywrap_core/remote/http_server.py +0 -0
- {mcpywrap_core-0.6.2 → mcpywrap_core-0.6.4}/mcpywrap_core/remote/protocol.py +0 -0
- {mcpywrap_core-0.6.2 → mcpywrap_core-0.6.4}/mcpywrap_core/runtime/__init__.py +0 -0
- {mcpywrap_core-0.6.2 → mcpywrap_core-0.6.4}/mcpywrap_core/runtime/deployment_inspection.py +0 -0
- {mcpywrap_core-0.6.2 → mcpywrap_core-0.6.4}/mcpywrap_core/runtime/deployment_service.py +0 -0
- {mcpywrap_core-0.6.2 → mcpywrap_core-0.6.4}/mcpywrap_core/runtime/diagnostics.py +0 -0
- {mcpywrap_core-0.6.2 → mcpywrap_core-0.6.4}/mcpywrap_core/runtime/instances.py +0 -0
- {mcpywrap_core-0.6.2 → mcpywrap_core-0.6.4}/mcpywrap_core/runtime/native.py +0 -0
- {mcpywrap_core-0.6.2 → mcpywrap_core-0.6.4}/mcpywrap_core/runtime/occupancy.py +0 -0
- {mcpywrap_core-0.6.2 → mcpywrap_core-0.6.4}/mcpywrap_core/runtime/storage.py +0 -0
- {mcpywrap_core-0.6.2 → mcpywrap_core-0.6.4}/mcpywrap_core/runtime/targets.py +0 -0
- {mcpywrap_core-0.6.2 → mcpywrap_core-0.6.4}/mcpywrap_core/runtime/watch.py +0 -0
- {mcpywrap_core-0.6.2 → mcpywrap_core-0.6.4}/mcpywrap_core/runtime/window_policy.py +0 -0
- {mcpywrap_core-0.6.2 → mcpywrap_core-0.6.4}/mcpywrap_core/runtime/windows.py +0 -0
- {mcpywrap_core-0.6.2 → mcpywrap_core-0.6.4}/mcpywrap_core/skill/agents/openai.yaml +0 -0
- {mcpywrap_core-0.6.2 → mcpywrap_core-0.6.4}/mcpywrap_core/skill/assets/consumer-prepare/framework/behavior_pack/CatalogRuntime/__init__.py +0 -0
- {mcpywrap_core-0.6.2 → mcpywrap_core-0.6.4}/mcpywrap_core/skill/assets/consumer-prepare/framework/behavior_pack/manifest.json +0 -0
- {mcpywrap_core-0.6.2 → mcpywrap_core-0.6.4}/mcpywrap_core/skill/assets/consumer-prepare/framework/build_tools/example.toml +0 -0
- {mcpywrap_core-0.6.2 → mcpywrap_core-0.6.4}/mcpywrap_core/skill/assets/consumer-prepare/framework/build_tools/prepare.py +0 -0
- {mcpywrap_core-0.6.2 → mcpywrap_core-0.6.4}/mcpywrap_core/skill/assets/consumer-prepare/framework/build_tools/schema.json +0 -0
- {mcpywrap_core-0.6.2 → mcpywrap_core-0.6.4}/mcpywrap_core/skill/assets/consumer-prepare/framework/pyproject.toml +0 -0
- {mcpywrap_core-0.6.2 → mcpywrap_core-0.6.4}/mcpywrap_core/skill/assets/consumer-prepare/game/.gitignore +0 -0
- {mcpywrap_core-0.6.2 → mcpywrap_core-0.6.4}/mcpywrap_core/skill/assets/consumer-prepare/game/behavior_pack/manifest.json +0 -0
- {mcpywrap_core-0.6.2 → mcpywrap_core-0.6.4}/mcpywrap_core/skill/assets/consumer-prepare/game/data/items.json +0 -0
- {mcpywrap_core-0.6.2 → mcpywrap_core-0.6.4}/mcpywrap_core/skill/assets/consumer-prepare/game/pyproject.toml +0 -0
- {mcpywrap_core-0.6.2 → mcpywrap_core-0.6.4}/mcpywrap_core/skill/assets/consumer-prepare/game/resource_pack/manifest.json +0 -0
- {mcpywrap_core-0.6.2 → mcpywrap_core-0.6.4}/mcpywrap_core/skill/references/capture.md +0 -0
- {mcpywrap_core-0.6.2 → mcpywrap_core-0.6.4}/mcpywrap_core/skill/references/consumer-prepare-author.md +0 -0
- {mcpywrap_core-0.6.2 → mcpywrap_core-0.6.4}/mcpywrap_core/skill/references/input-sequence.md +0 -0
- {mcpywrap_core-0.6.2 → mcpywrap_core-0.6.4}/mcpywrap_core/skill/references/input-writing.md +0 -0
- {mcpywrap_core-0.6.2 → mcpywrap_core-0.6.4}/mcpywrap_core/skill/references/instance-world-settings.md +0 -0
- {mcpywrap_core-0.6.2 → mcpywrap_core-0.6.4}/mcpywrap_core/skill/references/local-development.md +0 -0
- {mcpywrap_core-0.6.2 → mcpywrap_core-0.6.4}/mcpywrap_core/skill/references/network-sessions.md +0 -0
- {mcpywrap_core-0.6.2 → mcpywrap_core-0.6.4}/mcpywrap_core/skill/references/project-scripts.md +0 -0
- {mcpywrap_core-0.6.2 → mcpywrap_core-0.6.4}/mcpywrap_core/skill/references/remote-testing.md +0 -0
- {mcpywrap_core-0.6.2 → mcpywrap_core-0.6.4}/mcpywrap_core/skill/references/runtime-debug.md +0 -0
- {mcpywrap_core-0.6.2 → mcpywrap_core-0.6.4}/mcpywrap_core/skill/references/runtime-input.md +0 -0
- {mcpywrap_core-0.6.2 → mcpywrap_core-0.6.4}/mcpywrap_core/skill/references/runtime-key-timeline.md +0 -0
- {mcpywrap_core-0.6.2 → mcpywrap_core-0.6.4}/mcpywrap_core/skill/references/runtime-player.md +0 -0
- {mcpywrap_core-0.6.2 → mcpywrap_core-0.6.4}/mcpywrap_core/skill/references/runtime-ui.md +0 -0
- {mcpywrap_core-0.6.2 → mcpywrap_core-0.6.4}/mcpywrap_core/skill/references/script-example.md +0 -0
- {mcpywrap_core-0.6.2 → mcpywrap_core-0.6.4}/mcpywrap_core/skill/references/setup.md +0 -0
- {mcpywrap_core-0.6.2 → mcpywrap_core-0.6.4}/mcpywrap_core/skill/scripts/bootstrap.ps1 +0 -0
- {mcpywrap_core-0.6.2 → mcpywrap_core-0.6.4}/mcpywrap_core/skill/scripts/game_window.py +0 -0
- {mcpywrap_core-0.6.2 → mcpywrap_core-0.6.4}/mcpywrap_core/source_files.py +0 -0
- {mcpywrap_core-0.6.2 → mcpywrap_core-0.6.4}/mcpywrap_core/timeline.py +0 -0
- {mcpywrap_core-0.6.2 → mcpywrap_core-0.6.4}/mcpywrap_core/ui/__init__.py +0 -0
- {mcpywrap_core-0.6.2 → mcpywrap_core-0.6.4}/mcpywrap_core/ui/application.py +0 -0
- {mcpywrap_core-0.6.2 → mcpywrap_core-0.6.4}/mcpywrap_core/ui/assets/mcpy.icns +0 -0
- {mcpywrap_core-0.6.2 → mcpywrap_core-0.6.4}/mcpywrap_core/ui/assets/mcpy.icon/Assets/01-cube.svg +0 -0
- {mcpywrap_core-0.6.2 → mcpywrap_core-0.6.4}/mcpywrap_core/ui/assets/mcpy.icon/Assets/02-prompt.svg +0 -0
- {mcpywrap_core-0.6.2 → mcpywrap_core-0.6.4}/mcpywrap_core/ui/assets/mcpy.icon/icon.json +0 -0
- {mcpywrap_core-0.6.2 → mcpywrap_core-0.6.4}/mcpywrap_core/ui/assets/mcpy.png +0 -0
- {mcpywrap_core-0.6.2 → mcpywrap_core-0.6.4}/mcpywrap_core/ui/engine_setup.py +0 -0
- {mcpywrap_core-0.6.2 → mcpywrap_core-0.6.4}/mcpywrap_core/ui/log_view.py +0 -0
- {mcpywrap_core-0.6.2 → mcpywrap_core-0.6.4}/mcpywrap_core/ui/log_window.py +0 -0
- {mcpywrap_core-0.6.2 → mcpywrap_core-0.6.4}/mcpywrap_core/ui/run_session.py +0 -0
- {mcpywrap_core-0.6.2 → mcpywrap_core-0.6.4}/mcpywrap_core/ui/session_controller.py +0 -0
- {mcpywrap_core-0.6.2 → mcpywrap_core-0.6.4}/mcpywrap_core/ui/session_tools.py +0 -0
- {mcpywrap_core-0.6.2 → mcpywrap_core-0.6.4}/mcpywrap_core/ui/world_config.py +0 -0
- {mcpywrap_core-0.6.2 → mcpywrap_core-0.6.4}/mcpywrap_core/utils/__init__.py +0 -0
- {mcpywrap_core-0.6.2 → mcpywrap_core-0.6.4}/mcpywrap_core/utils/console.py +0 -0
- {mcpywrap_core-0.6.2 → mcpywrap_core-0.6.4}/mcpywrap_core/utils/link_snapshot.py +0 -0
- {mcpywrap_core-0.6.2 → mcpywrap_core-0.6.4}/mcpywrap_core/utils/locks.py +0 -0
- {mcpywrap_core-0.6.2 → mcpywrap_core-0.6.4}/mcpywrap_core/utils/paths.py +0 -0
- {mcpywrap_core-0.6.2 → mcpywrap_core-0.6.4}/mcpywrap_core/utils/pip_error_parser.py +0 -0
- {mcpywrap_core-0.6.2 → mcpywrap_core-0.6.4}/mcpywrap_core/utils/print_guide.py +0 -0
- {mcpywrap_core-0.6.2 → mcpywrap_core-0.6.4}/mcpywrap_core/utils/project_setup.py +0 -0
- {mcpywrap_core-0.6.2 → mcpywrap_core-0.6.4}/mcpywrap_core/utils/utils.py +0 -0
- {mcpywrap_core-0.6.2 → mcpywrap_core-0.6.4}/mcpywrap_core.egg-info/dependency_links.txt +0 -0
- {mcpywrap_core-0.6.2 → mcpywrap_core-0.6.4}/mcpywrap_core.egg-info/requires.txt +0 -0
- {mcpywrap_core-0.6.2 → mcpywrap_core-0.6.4}/mcpywrap_core.egg-info/top_level.txt +0 -0
- {mcpywrap_core-0.6.2 → mcpywrap_core-0.6.4}/mcpywrap_host/__init__.py +0 -0
- {mcpywrap_core-0.6.2 → mcpywrap_core-0.6.4}/mcpywrap_host/store.py +0 -0
- {mcpywrap_core-0.6.2 → mcpywrap_core-0.6.4}/pyproject.toml +0 -0
- {mcpywrap_core-0.6.2 → mcpywrap_core-0.6.4}/setup.cfg +0 -0
- {mcpywrap_core-0.6.2 → mcpywrap_core-0.6.4}/setup.py +0 -0
|
@@ -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':
|
|
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
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
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
|
-
|
|
82
|
-
|
|
85
|
+
click.secho(f"🔍 开始监控代码变化,路径: ", fg="bright_blue", nl=False)
|
|
86
|
+
click.secho(f"{source_dir}", fg="bright_cyan")
|
|
83
87
|
|
|
84
|
-
|
|
85
|
-
|
|
88
|
+
if plan.enabled:
|
|
89
|
+
click.echo('初次资源准备已完成;dev 后续只同步包内文件,原始素材修改需要重新构建并应用。')
|
|
86
90
|
|
|
87
|
-
|
|
88
|
-
|
|
91
|
+
# 创建项目监视器
|
|
92
|
+
project_watcher = ProjectWatcher(source_dir, target_dir, file_change_callback, output_lease=lease)
|
|
89
93
|
|
|
90
|
-
|
|
91
|
-
|
|
94
|
+
# 设置监视器
|
|
95
|
+
dep_count = project_watcher.setup_from_config(project_name, dependencies_list)
|
|
92
96
|
|
|
93
|
-
|
|
94
|
-
|
|
97
|
+
if dep_count > 0:
|
|
98
|
+
click.secho(f"✅ 找到并监控 {dep_count} 个依赖包", fg="green")
|
|
95
99
|
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
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
|