comfygit-core 0.7.0__tar.gz → 0.7.1__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.
- comfygit_core-0.7.1/PKG-INFO +131 -0
- comfygit_core-0.7.1/README.md +109 -0
- {comfygit_core-0.7.0 → comfygit_core-0.7.1}/pyproject.toml +1 -1
- {comfygit_core-0.7.0 → comfygit_core-0.7.1}/src/comfygit_core/core/environment.py +16 -4
- {comfygit_core-0.7.0 → comfygit_core-0.7.1}/src/comfygit_core/lifecycle/runtime_control.py +2 -0
- {comfygit_core-0.7.0 → comfygit_core-0.7.1}/src/comfygit_core/lifecycle/switch_observer.py +1 -0
- {comfygit_core-0.7.0 → comfygit_core-0.7.1}/src/comfygit_core/models/__init__.py +2 -0
- {comfygit_core-0.7.0 → comfygit_core-0.7.1}/src/comfygit_core/models/exceptions.py +22 -0
- {comfygit_core-0.7.0 → comfygit_core-0.7.1}/src/comfygit_core/models/manifest.py +7 -0
- {comfygit_core-0.7.0 → comfygit_core-0.7.1}/src/comfygit_core/services/credential_service.py +1 -0
- comfygit_core-0.7.1/src/comfygit_core/utils/environment_lock.py +196 -0
- {comfygit_core-0.7.0 → comfygit_core-0.7.1}/tests/unit/core/test_environment_operation_locking.py +8 -1
- comfygit_core-0.7.1/tests/unit/core/test_environment_shared_reads.py +85 -0
- comfygit_core-0.7.0/PKG-INFO +0 -521
- comfygit_core-0.7.0/README.md +0 -499
- comfygit_core-0.7.0/src/comfygit_core/utils/environment_lock.py +0 -111
- {comfygit_core-0.7.0 → comfygit_core-0.7.1}/.gitignore +0 -0
- {comfygit_core-0.7.0 → comfygit_core-0.7.1}/.python-version +0 -0
- {comfygit_core-0.7.0 → comfygit_core-0.7.1}/AGENTS.md +0 -0
- {comfygit_core-0.7.0 → comfygit_core-0.7.1}/CLAUDE.md +0 -0
- {comfygit_core-0.7.0 → comfygit_core-0.7.1}/LICENSE.txt +0 -0
- {comfygit_core-0.7.0 → comfygit_core-0.7.1}/docs/architecture-deep-dive.md +0 -0
- {comfygit_core-0.7.0 → comfygit_core-0.7.1}/docs/architecture.md +0 -0
- {comfygit_core-0.7.0 → comfygit_core-0.7.1}/docs/knowledge/comfyui-node-loader-base-directories.md +0 -0
- {comfygit_core-0.7.0 → comfygit_core-0.7.1}/docs/knowledge/model-tracking-system.md +0 -0
- {comfygit_core-0.7.0 → comfygit_core-0.7.1}/docs/knowledge/node-resolution-behavior.md +0 -0
- {comfygit_core-0.7.0 → comfygit_core-0.7.1}/docs/layer-hierarchy.md +0 -0
- {comfygit_core-0.7.0 → comfygit_core-0.7.1}/docs/plans/uv-overlay-system.md +0 -0
- {comfygit_core-0.7.0 → comfygit_core-0.7.1}/src/comfygit_core/__init__.py +0 -0
- {comfygit_core-0.7.0 → comfygit_core-0.7.1}/src/comfygit_core/analyzers/__init__.py +0 -0
- {comfygit_core-0.7.0 → comfygit_core-0.7.1}/src/comfygit_core/analyzers/config_comparison.py +0 -0
- {comfygit_core-0.7.0 → comfygit_core-0.7.1}/src/comfygit_core/analyzers/custom_node_scanner.py +0 -0
- {comfygit_core-0.7.0 → comfygit_core-0.7.1}/src/comfygit_core/analyzers/git_change_parser.py +0 -0
- {comfygit_core-0.7.0 → comfygit_core-0.7.1}/src/comfygit_core/analyzers/model_scanner.py +0 -0
- {comfygit_core-0.7.0 → comfygit_core-0.7.1}/src/comfygit_core/analyzers/node_classifier.py +0 -0
- {comfygit_core-0.7.0 → comfygit_core-0.7.1}/src/comfygit_core/analyzers/node_git_analyzer.py +0 -0
- {comfygit_core-0.7.0 → comfygit_core-0.7.1}/src/comfygit_core/analyzers/ref_diff_analyzer.py +0 -0
- {comfygit_core-0.7.0 → comfygit_core-0.7.1}/src/comfygit_core/analyzers/status_scanner.py +0 -0
- {comfygit_core-0.7.0 → comfygit_core-0.7.1}/src/comfygit_core/analyzers/unmanaged_comfyui_analyzer.py +0 -0
- {comfygit_core-0.7.0 → comfygit_core-0.7.1}/src/comfygit_core/analyzers/workflow_dependency_parser.py +0 -0
- {comfygit_core-0.7.0 → comfygit_core-0.7.1}/src/comfygit_core/assets.py +0 -0
- {comfygit_core-0.7.0 → comfygit_core-0.7.1}/src/comfygit_core/build_readiness.py +0 -0
- {comfygit_core-0.7.0 → comfygit_core-0.7.1}/src/comfygit_core/caching/__init__.py +0 -0
- {comfygit_core-0.7.0 → comfygit_core-0.7.1}/src/comfygit_core/caching/api_cache.py +0 -0
- {comfygit_core-0.7.0 → comfygit_core-0.7.1}/src/comfygit_core/caching/base.py +0 -0
- {comfygit_core-0.7.0 → comfygit_core-0.7.1}/src/comfygit_core/caching/comfyui_cache.py +0 -0
- {comfygit_core-0.7.0 → comfygit_core-0.7.1}/src/comfygit_core/caching/custom_node_cache.py +0 -0
- {comfygit_core-0.7.0 → comfygit_core-0.7.1}/src/comfygit_core/caching/workflow_cache.py +0 -0
- {comfygit_core-0.7.0 → comfygit_core-0.7.1}/src/comfygit_core/clients/__init__.py +0 -0
- {comfygit_core-0.7.0 → comfygit_core-0.7.1}/src/comfygit_core/clients/civitai_client.py +0 -0
- {comfygit_core-0.7.0 → comfygit_core-0.7.1}/src/comfygit_core/clients/github_client.py +0 -0
- {comfygit_core-0.7.0 → comfygit_core-0.7.1}/src/comfygit_core/clients/registry_client.py +0 -0
- {comfygit_core-0.7.0 → comfygit_core-0.7.1}/src/comfygit_core/configs/__init__.py +0 -0
- {comfygit_core-0.7.0 → comfygit_core-0.7.1}/src/comfygit_core/configs/comfyui_builtin_nodes.py +0 -0
- {comfygit_core-0.7.0 → comfygit_core-0.7.1}/src/comfygit_core/configs/comfyui_models.py +0 -0
- {comfygit_core-0.7.0 → comfygit_core-0.7.1}/src/comfygit_core/configs/model_config.py +0 -0
- {comfygit_core-0.7.0 → comfygit_core-0.7.1}/src/comfygit_core/configs/package_config.py +0 -0
- {comfygit_core-0.7.0 → comfygit_core-0.7.1}/src/comfygit_core/confirmation.py +0 -0
- {comfygit_core-0.7.0 → comfygit_core-0.7.1}/src/comfygit_core/constants.py +0 -0
- {comfygit_core-0.7.0 → comfygit_core-0.7.1}/src/comfygit_core/core/__init__.py +0 -0
- {comfygit_core-0.7.0 → comfygit_core-0.7.1}/src/comfygit_core/core/workspace.py +0 -0
- {comfygit_core-0.7.0 → comfygit_core-0.7.1}/src/comfygit_core/data/overlays/stock/sageattention.toml +0 -0
- {comfygit_core-0.7.0 → comfygit_core-0.7.1}/src/comfygit_core/data/overlays/stock/triton.toml +0 -0
- {comfygit_core-0.7.0 → comfygit_core-0.7.1}/src/comfygit_core/data/overlays/stock/xformers.toml +0 -0
- {comfygit_core-0.7.0 → comfygit_core-0.7.1}/src/comfygit_core/factories/__init__.py +0 -0
- {comfygit_core-0.7.0 → comfygit_core-0.7.1}/src/comfygit_core/factories/environment_factory.py +0 -0
- {comfygit_core-0.7.0 → comfygit_core-0.7.1}/src/comfygit_core/factories/uv_factory.py +0 -0
- {comfygit_core-0.7.0 → comfygit_core-0.7.1}/src/comfygit_core/factories/workspace_factory.py +0 -0
- {comfygit_core-0.7.0 → comfygit_core-0.7.1}/src/comfygit_core/git.py +0 -0
- {comfygit_core-0.7.0 → comfygit_core-0.7.1}/src/comfygit_core/imports.py +0 -0
- {comfygit_core-0.7.0 → comfygit_core-0.7.1}/src/comfygit_core/infrastructure/__init__.py +0 -0
- {comfygit_core-0.7.0 → comfygit_core-0.7.1}/src/comfygit_core/infrastructure/sqlite_manager.py +0 -0
- {comfygit_core-0.7.0 → comfygit_core-0.7.1}/src/comfygit_core/integrations/__init__.py +0 -0
- {comfygit_core-0.7.0 → comfygit_core-0.7.1}/src/comfygit_core/integrations/uv_command.py +0 -0
- {comfygit_core-0.7.0 → comfygit_core-0.7.1}/src/comfygit_core/lifecycle/__init__.py +0 -0
- {comfygit_core-0.7.0 → comfygit_core-0.7.1}/src/comfygit_core/lifecycle/comfyui_readiness.py +0 -0
- {comfygit_core-0.7.0 → comfygit_core-0.7.1}/src/comfygit_core/logging/__init__.py +0 -0
- {comfygit_core-0.7.0 → comfygit_core-0.7.1}/src/comfygit_core/logging/logging_config.py +0 -0
- {comfygit_core-0.7.0 → comfygit_core-0.7.1}/src/comfygit_core/managers/__init__.py +0 -0
- {comfygit_core-0.7.0 → comfygit_core-0.7.1}/src/comfygit_core/managers/environment_git_orchestrator.py +0 -0
- {comfygit_core-0.7.0 → comfygit_core-0.7.1}/src/comfygit_core/managers/environment_model_manager.py +0 -0
- {comfygit_core-0.7.0 → comfygit_core-0.7.1}/src/comfygit_core/managers/export_import_manager.py +0 -0
- {comfygit_core-0.7.0 → comfygit_core-0.7.1}/src/comfygit_core/managers/git_manager.py +0 -0
- {comfygit_core-0.7.0 → comfygit_core-0.7.1}/src/comfygit_core/managers/model_symlink_manager.py +0 -0
- {comfygit_core-0.7.0 → comfygit_core-0.7.1}/src/comfygit_core/managers/node_manager.py +0 -0
- {comfygit_core-0.7.0 → comfygit_core-0.7.1}/src/comfygit_core/managers/overlay_manager.py +0 -0
- {comfygit_core-0.7.0 → comfygit_core-0.7.1}/src/comfygit_core/managers/pyproject_manager.py +0 -0
- {comfygit_core-0.7.0 → comfygit_core-0.7.1}/src/comfygit_core/managers/pytorch_backend_manager.py +0 -0
- {comfygit_core-0.7.0 → comfygit_core-0.7.1}/src/comfygit_core/managers/system_node_symlink_manager.py +0 -0
- {comfygit_core-0.7.0 → comfygit_core-0.7.1}/src/comfygit_core/managers/user_content_symlink_manager.py +0 -0
- {comfygit_core-0.7.0 → comfygit_core-0.7.1}/src/comfygit_core/managers/uv_project_manager.py +0 -0
- {comfygit_core-0.7.0 → comfygit_core-0.7.1}/src/comfygit_core/managers/workflow_manager.py +0 -0
- {comfygit_core-0.7.0 → comfygit_core-0.7.1}/src/comfygit_core/manifest/__init__.py +0 -0
- {comfygit_core-0.7.0 → comfygit_core-0.7.1}/src/comfygit_core/manifest/base.py +0 -0
- {comfygit_core-0.7.0 → comfygit_core-0.7.1}/src/comfygit_core/manifest/dependencies.py +0 -0
- {comfygit_core-0.7.0 → comfygit_core-0.7.1}/src/comfygit_core/manifest/disposable_project.py +0 -0
- {comfygit_core-0.7.0 → comfygit_core-0.7.1}/src/comfygit_core/manifest/migrations.py +0 -0
- {comfygit_core-0.7.0 → comfygit_core-0.7.1}/src/comfygit_core/manifest/models.py +0 -0
- {comfygit_core-0.7.0 → comfygit_core-0.7.1}/src/comfygit_core/manifest/nodes.py +0 -0
- {comfygit_core-0.7.0 → comfygit_core-0.7.1}/src/comfygit_core/manifest/overlays.py +0 -0
- {comfygit_core-0.7.0 → comfygit_core-0.7.1}/src/comfygit_core/manifest/pyproject_manifest.py +0 -0
- {comfygit_core-0.7.0 → comfygit_core-0.7.1}/src/comfygit_core/manifest/store.py +0 -0
- {comfygit_core-0.7.0 → comfygit_core-0.7.1}/src/comfygit_core/manifest/sync_config.py +0 -0
- {comfygit_core-0.7.0 → comfygit_core-0.7.1}/src/comfygit_core/manifest/uv_config.py +0 -0
- {comfygit_core-0.7.0 → comfygit_core-0.7.1}/src/comfygit_core/manifest/workflows.py +0 -0
- {comfygit_core-0.7.0 → comfygit_core-0.7.1}/src/comfygit_core/merging/__init__.py +0 -0
- {comfygit_core-0.7.0 → comfygit_core-0.7.1}/src/comfygit_core/merging/atomic_executor.py +0 -0
- {comfygit_core-0.7.0 → comfygit_core-0.7.1}/src/comfygit_core/merging/merge_validator.py +0 -0
- {comfygit_core-0.7.0 → comfygit_core-0.7.1}/src/comfygit_core/merging/semantic_merger.py +0 -0
- {comfygit_core-0.7.0 → comfygit_core-0.7.1}/src/comfygit_core/models/build_readiness.py +0 -0
- {comfygit_core-0.7.0 → comfygit_core-0.7.1}/src/comfygit_core/models/civitai.py +0 -0
- {comfygit_core-0.7.0 → comfygit_core-0.7.1}/src/comfygit_core/models/comfyui_builtin_versions.py +0 -0
- {comfygit_core-0.7.0 → comfygit_core-0.7.1}/src/comfygit_core/models/commit.py +0 -0
- {comfygit_core-0.7.0 → comfygit_core-0.7.1}/src/comfygit_core/models/credentials.py +0 -0
- {comfygit_core-0.7.0 → comfygit_core-0.7.1}/src/comfygit_core/models/dependency_resolution.py +0 -0
- {comfygit_core-0.7.0 → comfygit_core-0.7.1}/src/comfygit_core/models/environment.py +0 -0
- {comfygit_core-0.7.0 → comfygit_core-0.7.1}/src/comfygit_core/models/git.py +0 -0
- {comfygit_core-0.7.0 → comfygit_core-0.7.1}/src/comfygit_core/models/lifecycle.py +0 -0
- {comfygit_core-0.7.0 → comfygit_core-0.7.1}/src/comfygit_core/models/materialization.py +0 -0
- {comfygit_core-0.7.0 → comfygit_core-0.7.1}/src/comfygit_core/models/merge_plan.py +0 -0
- {comfygit_core-0.7.0 → comfygit_core-0.7.1}/src/comfygit_core/models/model_scan.py +0 -0
- {comfygit_core-0.7.0 → comfygit_core-0.7.1}/src/comfygit_core/models/node_mapping.py +0 -0
- {comfygit_core-0.7.0 → comfygit_core-0.7.1}/src/comfygit_core/models/overlay.py +0 -0
- {comfygit_core-0.7.0 → comfygit_core-0.7.1}/src/comfygit_core/models/protocols.py +0 -0
- {comfygit_core-0.7.0 → comfygit_core-0.7.1}/src/comfygit_core/models/readiness.py +0 -0
- {comfygit_core-0.7.0 → comfygit_core-0.7.1}/src/comfygit_core/models/ref_diff.py +0 -0
- {comfygit_core-0.7.0 → comfygit_core-0.7.1}/src/comfygit_core/models/registry.py +0 -0
- {comfygit_core-0.7.0 → comfygit_core-0.7.1}/src/comfygit_core/models/resource_inventory.py +0 -0
- {comfygit_core-0.7.0 → comfygit_core-0.7.1}/src/comfygit_core/models/runtime_config.py +0 -0
- {comfygit_core-0.7.0 → comfygit_core-0.7.1}/src/comfygit_core/models/shared.py +0 -0
- {comfygit_core-0.7.0 → comfygit_core-0.7.1}/src/comfygit_core/models/sync.py +0 -0
- {comfygit_core-0.7.0 → comfygit_core-0.7.1}/src/comfygit_core/models/system.py +0 -0
- {comfygit_core-0.7.0 → comfygit_core-0.7.1}/src/comfygit_core/models/unmanaged_import.py +0 -0
- {comfygit_core-0.7.0 → comfygit_core-0.7.1}/src/comfygit_core/models/workflow.py +0 -0
- {comfygit_core-0.7.0 → comfygit_core-0.7.1}/src/comfygit_core/models/workflow_contract.py +0 -0
- {comfygit_core-0.7.0 → comfygit_core-0.7.1}/src/comfygit_core/models/workflow_execution.py +0 -0
- {comfygit_core-0.7.0 → comfygit_core-0.7.1}/src/comfygit_core/models/workspace_config.py +0 -0
- {comfygit_core-0.7.0 → comfygit_core-0.7.1}/src/comfygit_core/py.typed +0 -0
- {comfygit_core-0.7.0 → comfygit_core-0.7.1}/src/comfygit_core/readiness.py +0 -0
- {comfygit_core-0.7.0 → comfygit_core-0.7.1}/src/comfygit_core/repositories/__init__.py +0 -0
- {comfygit_core-0.7.0 → comfygit_core-0.7.1}/src/comfygit_core/repositories/comfyui_builtin_versions_repository.py +0 -0
- {comfygit_core-0.7.0 → comfygit_core-0.7.1}/src/comfygit_core/repositories/credential_store.py +0 -0
- {comfygit_core-0.7.0 → comfygit_core-0.7.1}/src/comfygit_core/repositories/migrate_paths.py +0 -0
- {comfygit_core-0.7.0 → comfygit_core-0.7.1}/src/comfygit_core/repositories/model_repository.py +0 -0
- {comfygit_core-0.7.0 → comfygit_core-0.7.1}/src/comfygit_core/repositories/node_mappings_repository.py +0 -0
- {comfygit_core-0.7.0 → comfygit_core-0.7.1}/src/comfygit_core/repositories/workflow_repository.py +0 -0
- {comfygit_core-0.7.0 → comfygit_core-0.7.1}/src/comfygit_core/repositories/workspace_config_repository.py +0 -0
- {comfygit_core-0.7.0 → comfygit_core-0.7.1}/src/comfygit_core/resolvers/__init__.py +0 -0
- {comfygit_core-0.7.0 → comfygit_core-0.7.1}/src/comfygit_core/resolvers/global_node_resolver.py +0 -0
- {comfygit_core-0.7.0 → comfygit_core-0.7.1}/src/comfygit_core/resolvers/model_resolver.py +0 -0
- {comfygit_core-0.7.0 → comfygit_core-0.7.1}/src/comfygit_core/runtime.py +0 -0
- {comfygit_core-0.7.0 → comfygit_core-0.7.1}/src/comfygit_core/security.py +0 -0
- {comfygit_core-0.7.0 → comfygit_core-0.7.1}/src/comfygit_core/services/__init__.py +0 -0
- {comfygit_core-0.7.0 → comfygit_core-0.7.1}/src/comfygit_core/services/build_readiness.py +0 -0
- {comfygit_core-0.7.0 → comfygit_core-0.7.1}/src/comfygit_core/services/dependency_resolution_preview.py +0 -0
- {comfygit_core-0.7.0 → comfygit_core-0.7.1}/src/comfygit_core/services/environment_lifecycle.py +0 -0
- {comfygit_core-0.7.0 → comfygit_core-0.7.1}/src/comfygit_core/services/environment_readiness.py +0 -0
- {comfygit_core-0.7.0 → comfygit_core-0.7.1}/src/comfygit_core/services/environment_sync_coordinator.py +0 -0
- {comfygit_core-0.7.0 → comfygit_core-0.7.1}/src/comfygit_core/services/huggingface_url.py +0 -0
- {comfygit_core-0.7.0 → comfygit_core-0.7.1}/src/comfygit_core/services/import_analyzer.py +0 -0
- {comfygit_core-0.7.0 → comfygit_core-0.7.1}/src/comfygit_core/services/model_downloader.py +0 -0
- {comfygit_core-0.7.0 → comfygit_core-0.7.1}/src/comfygit_core/services/model_source_lookup.py +0 -0
- {comfygit_core-0.7.0 → comfygit_core-0.7.1}/src/comfygit_core/services/node_lookup_service.py +0 -0
- {comfygit_core-0.7.0 → comfygit_core-0.7.1}/src/comfygit_core/services/registry_data_manager.py +0 -0
- {comfygit_core-0.7.0 → comfygit_core-0.7.1}/src/comfygit_core/services/resource_inventory.py +0 -0
- {comfygit_core-0.7.0 → comfygit_core-0.7.1}/src/comfygit_core/services/unmanaged_environment_import.py +0 -0
- {comfygit_core-0.7.0 → comfygit_core-0.7.1}/src/comfygit_core/services/workflow_analysis_cache.py +0 -0
- {comfygit_core-0.7.0 → comfygit_core-0.7.1}/src/comfygit_core/services/workflow_analysis_service.py +0 -0
- {comfygit_core-0.7.0 → comfygit_core-0.7.1}/src/comfygit_core/services/workflow_execution.py +0 -0
- {comfygit_core-0.7.0 → comfygit_core-0.7.1}/src/comfygit_core/services/workflow_file_store.py +0 -0
- {comfygit_core-0.7.0 → comfygit_core-0.7.1}/src/comfygit_core/services/workflow_input.py +0 -0
- {comfygit_core-0.7.0 → comfygit_core-0.7.1}/src/comfygit_core/services/workflow_manifest_reconciler.py +0 -0
- {comfygit_core-0.7.0 → comfygit_core-0.7.1}/src/comfygit_core/services/workflow_manual_model_policy.py +0 -0
- {comfygit_core-0.7.0 → comfygit_core-0.7.1}/src/comfygit_core/services/workflow_model_dependency_service.py +0 -0
- {comfygit_core-0.7.0 → comfygit_core-0.7.1}/src/comfygit_core/services/workflow_model_download_coordinator.py +0 -0
- {comfygit_core-0.7.0 → comfygit_core-0.7.1}/src/comfygit_core/services/workflow_model_path_policy.py +0 -0
- {comfygit_core-0.7.0 → comfygit_core-0.7.1}/src/comfygit_core/services/workflow_node_package_policy.py +0 -0
- {comfygit_core-0.7.0 → comfygit_core-0.7.1}/src/comfygit_core/services/workflow_resolution_context_builder.py +0 -0
- {comfygit_core-0.7.0 → comfygit_core-0.7.1}/src/comfygit_core/services/workflow_resolution_fixer.py +0 -0
- {comfygit_core-0.7.0 → comfygit_core-0.7.1}/src/comfygit_core/services/workflow_resolution_service.py +0 -0
- {comfygit_core-0.7.0 → comfygit_core-0.7.1}/src/comfygit_core/services/workflow_state_cleanup.py +0 -0
- {comfygit_core-0.7.0 → comfygit_core-0.7.1}/src/comfygit_core/strategies/__init__.py +0 -0
- {comfygit_core-0.7.0 → comfygit_core-0.7.1}/src/comfygit_core/strategies/auto.py +0 -0
- {comfygit_core-0.7.0 → comfygit_core-0.7.1}/src/comfygit_core/strategies/confirmation.py +0 -0
- {comfygit_core-0.7.0 → comfygit_core-0.7.1}/src/comfygit_core/utils/__init__.py +0 -0
- {comfygit_core-0.7.0 → comfygit_core-0.7.1}/src/comfygit_core/utils/builtin_extractor.py +0 -0
- {comfygit_core-0.7.0 → comfygit_core-0.7.1}/src/comfygit_core/utils/comfyui_ops.py +0 -0
- {comfygit_core-0.7.0 → comfygit_core-0.7.1}/src/comfygit_core/utils/common.py +0 -0
- {comfygit_core-0.7.0 → comfygit_core-0.7.1}/src/comfygit_core/utils/conflict_analyzer.py +0 -0
- {comfygit_core-0.7.0 → comfygit_core-0.7.1}/src/comfygit_core/utils/conflict_parser.py +0 -0
- {comfygit_core-0.7.0 → comfygit_core-0.7.1}/src/comfygit_core/utils/dependency_parser.py +0 -0
- {comfygit_core-0.7.0 → comfygit_core-0.7.1}/src/comfygit_core/utils/dependency_probe.py +0 -0
- {comfygit_core-0.7.0 → comfygit_core-0.7.1}/src/comfygit_core/utils/download.py +0 -0
- {comfygit_core-0.7.0 → comfygit_core-0.7.1}/src/comfygit_core/utils/environment_cleanup.py +0 -0
- {comfygit_core-0.7.0 → comfygit_core-0.7.1}/src/comfygit_core/utils/filesystem.py +0 -0
- {comfygit_core-0.7.0 → comfygit_core-0.7.1}/src/comfygit_core/utils/folder_paths_extractor.py +0 -0
- {comfygit_core-0.7.0 → comfygit_core-0.7.1}/src/comfygit_core/utils/git.py +0 -0
- {comfygit_core-0.7.0 → comfygit_core-0.7.1}/src/comfygit_core/utils/input_signature.py +0 -0
- {comfygit_core-0.7.0 → comfygit_core-0.7.1}/src/comfygit_core/utils/model_categories.py +0 -0
- {comfygit_core-0.7.0 → comfygit_core-0.7.1}/src/comfygit_core/utils/model_loader_extractor.py +0 -0
- {comfygit_core-0.7.0 → comfygit_core-0.7.1}/src/comfygit_core/utils/node_identity.py +0 -0
- {comfygit_core-0.7.0 → comfygit_core-0.7.1}/src/comfygit_core/utils/provider_urls.py +0 -0
- {comfygit_core-0.7.0 → comfygit_core-0.7.1}/src/comfygit_core/utils/pytorch.py +0 -0
- {comfygit_core-0.7.0 → comfygit_core-0.7.1}/src/comfygit_core/utils/pytorch_prober.py +0 -0
- {comfygit_core-0.7.0 → comfygit_core-0.7.1}/src/comfygit_core/utils/redaction.py +0 -0
- {comfygit_core-0.7.0 → comfygit_core-0.7.1}/src/comfygit_core/utils/requirements.py +0 -0
- {comfygit_core-0.7.0 → comfygit_core-0.7.1}/src/comfygit_core/utils/retry.py +0 -0
- {comfygit_core-0.7.0 → comfygit_core-0.7.1}/src/comfygit_core/utils/symlink_utils.py +0 -0
- {comfygit_core-0.7.0 → comfygit_core-0.7.1}/src/comfygit_core/utils/system_detector.py +0 -0
- {comfygit_core-0.7.0 → comfygit_core-0.7.1}/src/comfygit_core/utils/toml_compat.py +0 -0
- {comfygit_core-0.7.0 → comfygit_core-0.7.1}/src/comfygit_core/utils/uuid.py +0 -0
- {comfygit_core-0.7.0 → comfygit_core-0.7.1}/src/comfygit_core/utils/uv_error_handler.py +0 -0
- {comfygit_core-0.7.0 → comfygit_core-0.7.1}/src/comfygit_core/utils/version.py +0 -0
- {comfygit_core-0.7.0 → comfygit_core-0.7.1}/src/comfygit_core/utils/workflow_hash.py +0 -0
- {comfygit_core-0.7.0 → comfygit_core-0.7.1}/src/comfygit_core/validation/__init__.py +0 -0
- {comfygit_core-0.7.0 → comfygit_core-0.7.1}/src/comfygit_core/validation/resolution_tester.py +0 -0
- {comfygit_core-0.7.0 → comfygit_core-0.7.1}/src/comfygit_core/workflow.py +0 -0
- {comfygit_core-0.7.0 → comfygit_core-0.7.1}/tests/README.md +0 -0
- {comfygit_core-0.7.0 → comfygit_core-0.7.1}/tests/caching/TEST_REDUCTION_SUMMARY.md +0 -0
- {comfygit_core-0.7.0 → comfygit_core-0.7.1}/tests/caching/__init__.py +0 -0
- {comfygit_core-0.7.0 → comfygit_core-0.7.1}/tests/caching/test_workflow_cache.py +0 -0
- {comfygit_core-0.7.0 → comfygit_core-0.7.1}/tests/caching/test_workflow_cache_context_hash.py +0 -0
- {comfygit_core-0.7.0 → comfygit_core-0.7.1}/tests/conftest.py +0 -0
- {comfygit_core-0.7.0 → comfygit_core-0.7.1}/tests/fixtures/models/test_models.json +0 -0
- {comfygit_core-0.7.0 → comfygit_core-0.7.1}/tests/fixtures/workflows/checkpoint_loader_with_missing_model.json +0 -0
- {comfygit_core-0.7.0 → comfygit_core-0.7.1}/tests/fixtures/workflows/kjnodes_workflow.json +0 -0
- {comfygit_core-0.7.0 → comfygit_core-0.7.1}/tests/fixtures/workflows/simple_txt2img.json +0 -0
- {comfygit_core-0.7.0 → comfygit_core-0.7.1}/tests/fixtures/workflows/with_custom_node.json +0 -0
- {comfygit_core-0.7.0 → comfygit_core-0.7.1}/tests/fixtures/workflows/with_missing_model.json +0 -0
- {comfygit_core-0.7.0 → comfygit_core-0.7.1}/tests/fixtures/workflows/workflow_with_duplicates.json +0 -0
- {comfygit_core-0.7.0 → comfygit_core-0.7.1}/tests/fixtures/workflows/workflow_with_properties.json +0 -0
- {comfygit_core-0.7.0 → comfygit_core-0.7.1}/tests/fixtures/workflows/workflow_without_properties.json +0 -0
- {comfygit_core-0.7.0 → comfygit_core-0.7.1}/tests/helpers/__init__.py +0 -0
- {comfygit_core-0.7.0 → comfygit_core-0.7.1}/tests/helpers/model_index_builder.py +0 -0
- {comfygit_core-0.7.0 → comfygit_core-0.7.1}/tests/helpers/pyproject_assertions.py +0 -0
- {comfygit_core-0.7.0 → comfygit_core-0.7.1}/tests/helpers/workflow_builder.py +0 -0
- {comfygit_core-0.7.0 → comfygit_core-0.7.1}/tests/integration/test_atomic_semantic_merge.py +0 -0
- {comfygit_core-0.7.0 → comfygit_core-0.7.1}/tests/integration/test_auto_model_index_sync.py +0 -0
- {comfygit_core-0.7.0 → comfygit_core-0.7.1}/tests/integration/test_branch_workflow_preservation.py +0 -0
- {comfygit_core-0.7.0 → comfygit_core-0.7.1}/tests/integration/test_cache_invalidation_on_model_deletion.py +0 -0
- {comfygit_core-0.7.0 → comfygit_core-0.7.1}/tests/integration/test_cache_node_version_invalidation.py +0 -0
- {comfygit_core-0.7.0 → comfygit_core-0.7.1}/tests/integration/test_checkout_b_with_modified_workflow.py +0 -0
- {comfygit_core-0.7.0 → comfygit_core-0.7.1}/tests/integration/test_commit_git_changes.py +0 -0
- {comfygit_core-0.7.0 → comfygit_core-0.7.1}/tests/integration/test_commit_git_changes_SUMMARY.md +0 -0
- {comfygit_core-0.7.0 → comfygit_core-0.7.1}/tests/integration/test_commit_history.py +0 -0
- {comfygit_core-0.7.0 → comfygit_core-0.7.1}/tests/integration/test_context_aware_node_resolution.py +0 -0
- {comfygit_core-0.7.0 → comfygit_core-0.7.1}/tests/integration/test_create_with_version_spec.py +0 -0
- {comfygit_core-0.7.0 → comfygit_core-0.7.1}/tests/integration/test_custom_node_path_preservation.py +0 -0
- {comfygit_core-0.7.0 → comfygit_core-0.7.1}/tests/integration/test_deferred_model_downloads.py +0 -0
- {comfygit_core-0.7.0 → comfygit_core-0.7.1}/tests/integration/test_deleted_model_download_intent.py +0 -0
- {comfygit_core-0.7.0 → comfygit_core-0.7.1}/tests/integration/test_dependency_group_removal.py +0 -0
- {comfygit_core-0.7.0 → comfygit_core-0.7.1}/tests/integration/test_dev_node_git_references.py +0 -0
- {comfygit_core-0.7.0 → comfygit_core-0.7.1}/tests/integration/test_dev_node_improvements.py +0 -0
- {comfygit_core-0.7.0 → comfygit_core-0.7.1}/tests/integration/test_download_cleanup.py +0 -0
- {comfygit_core-0.7.0 → comfygit_core-0.7.1}/tests/integration/test_download_intent_cache_invalidation.py +0 -0
- {comfygit_core-0.7.0 → comfygit_core-0.7.1}/tests/integration/test_environment_basic.py +0 -0
- {comfygit_core-0.7.0 → comfygit_core-0.7.1}/tests/integration/test_environment_branching.py +0 -0
- {comfygit_core-0.7.0 → comfygit_core-0.7.1}/tests/integration/test_environment_create_progress.py +0 -0
- {comfygit_core-0.7.0 → comfygit_core-0.7.1}/tests/integration/test_export_import.py +0 -0
- {comfygit_core-0.7.0 → comfygit_core-0.7.1}/tests/integration/test_git_branching.py +0 -0
- {comfygit_core-0.7.0 → comfygit_core-0.7.1}/tests/integration/test_git_import.py +0 -0
- {comfygit_core-0.7.0 → comfygit_core-0.7.1}/tests/integration/test_git_pull_push.py +0 -0
- {comfygit_core-0.7.0 → comfygit_core-0.7.1}/tests/integration/test_git_remote.py +0 -0
- {comfygit_core-0.7.0 → comfygit_core-0.7.1}/tests/integration/test_git_subdirectory_import.py +0 -0
- {comfygit_core-0.7.0 → comfygit_core-0.7.1}/tests/integration/test_import_auto_remote.py +0 -0
- {comfygit_core-0.7.0 → comfygit_core-0.7.1}/tests/integration/test_import_comfyui_version_bug.py +0 -0
- {comfygit_core-0.7.0 → comfygit_core-0.7.1}/tests/integration/test_import_preview.py +0 -0
- {comfygit_core-0.7.0 → comfygit_core-0.7.1}/tests/integration/test_lifecycle_status.py +0 -0
- {comfygit_core-0.7.0 → comfygit_core-0.7.1}/tests/integration/test_model_category_mismatch_detection.py +0 -0
- {comfygit_core-0.7.0 → comfygit_core-0.7.1}/tests/integration/test_model_directory_switch.py +0 -0
- {comfygit_core-0.7.0 → comfygit_core-0.7.1}/tests/integration/test_model_download_integration.py +0 -0
- {comfygit_core-0.7.0 → comfygit_core-0.7.1}/tests/integration/test_model_index_mismatch_bug_SUMMARY.md +0 -0
- {comfygit_core-0.7.0 → comfygit_core-0.7.1}/tests/integration/test_model_path_sync_detection.py +0 -0
- {comfygit_core-0.7.0 → comfygit_core-0.7.1}/tests/integration/test_model_resolution_stale_directory.py +0 -0
- {comfygit_core-0.7.0 → comfygit_core-0.7.1}/tests/integration/test_model_show_command.py +0 -0
- {comfygit_core-0.7.0 → comfygit_core-0.7.1}/tests/integration/test_model_source_management.py +0 -0
- {comfygit_core-0.7.0 → comfygit_core-0.7.1}/tests/integration/test_model_source_preservation.py +0 -0
- {comfygit_core-0.7.0 → comfygit_core-0.7.1}/tests/integration/test_model_source_preservation_SUMMARY.md +0 -0
- {comfygit_core-0.7.0 → comfygit_core-0.7.1}/tests/integration/test_model_source_removal.py +0 -0
- {comfygit_core-0.7.0 → comfygit_core-0.7.1}/tests/integration/test_multiple_optional_group_failures.py +0 -0
- {comfygit_core-0.7.0 → comfygit_core-0.7.1}/tests/integration/test_node_prune.py +0 -0
- {comfygit_core-0.7.0 → comfygit_core-0.7.1}/tests/integration/test_node_version_replacement.py +0 -0
- {comfygit_core-0.7.0 → comfygit_core-0.7.1}/tests/integration/test_opencv_conflict_resolution.py +0 -0
- {comfygit_core-0.7.0 → comfygit_core-0.7.1}/tests/integration/test_optional_dependency_groups.py +0 -0
- {comfygit_core-0.7.0 → comfygit_core-0.7.1}/tests/integration/test_overlay_e2e.py +0 -0
- {comfygit_core-0.7.0 → comfygit_core-0.7.1}/tests/integration/test_overlay_git_integration.py +0 -0
- {comfygit_core-0.7.0 → comfygit_core-0.7.1}/tests/integration/test_overlay_system_integration.py +0 -0
- {comfygit_core-0.7.0 → comfygit_core-0.7.1}/tests/integration/test_package_config.py +0 -0
- {comfygit_core-0.7.0 → comfygit_core-0.7.1}/tests/integration/test_per_environment_manager.py +0 -0
- {comfygit_core-0.7.0 → comfygit_core-0.7.1}/tests/integration/test_pyproject_batch_writes.py +0 -0
- {comfygit_core-0.7.0 → comfygit_core-0.7.1}/tests/integration/test_pytorch_reconfiguration.py +0 -0
- {comfygit_core-0.7.0 → comfygit_core-0.7.1}/tests/integration/test_registry_git_fallback.py +0 -0
- {comfygit_core-0.7.0 → comfygit_core-0.7.1}/tests/integration/test_registry_node_update_empty_download_url.py +0 -0
- {comfygit_core-0.7.0 → comfygit_core-0.7.1}/tests/integration/test_repair_completion_marker.py +0 -0
- {comfygit_core-0.7.0 → comfygit_core-0.7.1}/tests/integration/test_repair_model_download.py +0 -0
- {comfygit_core-0.7.0 → comfygit_core-0.7.1}/tests/integration/test_repair_node_removal.py +0 -0
- {comfygit_core-0.7.0 → comfygit_core-0.7.1}/tests/integration/test_repair_workflow.py +0 -0
- {comfygit_core-0.7.0 → comfygit_core-0.7.1}/tests/integration/test_requirements_inline_comments_bug.py +0 -0
- {comfygit_core-0.7.0 → comfygit_core-0.7.1}/tests/integration/test_runtime_restart_workflow_preservation.py +0 -0
- {comfygit_core-0.7.0 → comfygit_core-0.7.1}/tests/integration/test_status_abstraction.py +0 -0
- {comfygit_core-0.7.0 → comfygit_core-0.7.1}/tests/integration/test_status_uninstalled_nodes.py +0 -0
- {comfygit_core-0.7.0 → comfygit_core-0.7.1}/tests/integration/test_workflow_cache_metadata_invalidation.py +0 -0
- {comfygit_core-0.7.0 → comfygit_core-0.7.1}/tests/integration/test_workflow_caching_integration.py +0 -0
- {comfygit_core-0.7.0 → comfygit_core-0.7.1}/tests/integration/test_workflow_commit_flow.py +0 -0
- {comfygit_core-0.7.0 → comfygit_core-0.7.1}/tests/integration/test_workflow_deletion_cleanup.py +0 -0
- {comfygit_core-0.7.0 → comfygit_core-0.7.1}/tests/integration/test_workflow_model_criticality_update.py +0 -0
- {comfygit_core-0.7.0 → comfygit_core-0.7.1}/tests/integration/test_workflow_path_update_after_interactive_resolution.py +0 -0
- {comfygit_core-0.7.0 → comfygit_core-0.7.1}/tests/integration/test_workflow_resolution_cleanup.py +0 -0
- {comfygit_core-0.7.0 → comfygit_core-0.7.1}/tests/integration/test_workflow_resolution_pipeline.py +0 -0
- {comfygit_core-0.7.0 → comfygit_core-0.7.1}/tests/integration/test_workflow_resolve_install.py +0 -0
- {comfygit_core-0.7.0 → comfygit_core-0.7.1}/tests/integration/test_workflow_subgraph_resolution.py +0 -0
- {comfygit_core-0.7.0 → comfygit_core-0.7.1}/tests/test_architecture_boundaries.py +0 -0
- {comfygit_core-0.7.0 → comfygit_core-0.7.1}/tests/test_public_api.py +0 -0
- {comfygit_core-0.7.0 → comfygit_core-0.7.1}/tests/unit/analyzers/test_config_comparison.py +0 -0
- {comfygit_core-0.7.0 → comfygit_core-0.7.1}/tests/unit/analyzers/test_custom_node_scanner.py +0 -0
- {comfygit_core-0.7.0 → comfygit_core-0.7.1}/tests/unit/analyzers/test_model_scanner_symlinks.py +0 -0
- {comfygit_core-0.7.0 → comfygit_core-0.7.1}/tests/unit/analyzers/test_node_git_analyzer.py +0 -0
- {comfygit_core-0.7.0 → comfygit_core-0.7.1}/tests/unit/analyzers/test_ref_diff_analyzer.py +0 -0
- {comfygit_core-0.7.0 → comfygit_core-0.7.1}/tests/unit/analyzers/test_status_scanner.py +0 -0
- {comfygit_core-0.7.0 → comfygit_core-0.7.1}/tests/unit/analyzers/test_status_scanner_disabled_nodes.py +0 -0
- {comfygit_core-0.7.0 → comfygit_core-0.7.1}/tests/unit/analyzers/test_status_scanner_package_sync.py +0 -0
- {comfygit_core-0.7.0 → comfygit_core-0.7.1}/tests/unit/analyzers/test_workflow_dependency_parser.py +0 -0
- {comfygit_core-0.7.0 → comfygit_core-0.7.1}/tests/unit/caching/test_cache_base.py +0 -0
- {comfygit_core-0.7.0 → comfygit_core-0.7.1}/tests/unit/caching/test_comfyui_cache.py +0 -0
- {comfygit_core-0.7.0 → comfygit_core-0.7.1}/tests/unit/caching/test_custom_node_cache_refactor.py +0 -0
- {comfygit_core-0.7.0 → comfygit_core-0.7.1}/tests/unit/caching/test_workspace_relative_caching.py +0 -0
- {comfygit_core-0.7.0 → comfygit_core-0.7.1}/tests/unit/clients/test_civitai_client.py +0 -0
- {comfygit_core-0.7.0 → comfygit_core-0.7.1}/tests/unit/clients/test_civitai_parsing.py +0 -0
- {comfygit_core-0.7.0 → comfygit_core-0.7.1}/tests/unit/clients/test_github_releases.py +0 -0
- {comfygit_core-0.7.0 → comfygit_core-0.7.1}/tests/unit/configs/__init__.py +0 -0
- {comfygit_core-0.7.0 → comfygit_core-0.7.1}/tests/unit/configs/test_package_config.py +0 -0
- {comfygit_core-0.7.0 → comfygit_core-0.7.1}/tests/unit/core/test_environment_facades.py +0 -0
- {comfygit_core-0.7.0 → comfygit_core-0.7.1}/tests/unit/core/test_environment_run.py +0 -0
- {comfygit_core-0.7.0 → comfygit_core-0.7.1}/tests/unit/core/test_environment_sync.py +0 -0
- {comfygit_core-0.7.0 → comfygit_core-0.7.1}/tests/unit/core/test_environment_uninstalled_nodes.py +0 -0
- {comfygit_core-0.7.0 → comfygit_core-0.7.1}/tests/unit/core/test_import_download_failures.py +0 -0
- {comfygit_core-0.7.0 → comfygit_core-0.7.1}/tests/unit/core/test_import_no_manager.py +0 -0
- {comfygit_core-0.7.0 → comfygit_core-0.7.1}/tests/unit/core/test_reserved_environment_names.py +0 -0
- {comfygit_core-0.7.0 → comfygit_core-0.7.1}/tests/unit/core/test_sync_node_dependency_provisioning.py +0 -0
- {comfygit_core-0.7.0 → comfygit_core-0.7.1}/tests/unit/core/test_workflow_contract_access.py +0 -0
- {comfygit_core-0.7.0 → comfygit_core-0.7.1}/tests/unit/core/test_workspace_environment_creation.py +0 -0
- {comfygit_core-0.7.0 → comfygit_core-0.7.1}/tests/unit/core/test_workspace_model_delete.py +0 -0
- {comfygit_core-0.7.0 → comfygit_core-0.7.1}/tests/unit/factories/test_environment_factory_manager_install.py +0 -0
- {comfygit_core-0.7.0 → comfygit_core-0.7.1}/tests/unit/lifecycle/test_comfyui_readiness.py +0 -0
- {comfygit_core-0.7.0 → comfygit_core-0.7.1}/tests/unit/managers/test_environment_model_manager.py +0 -0
- {comfygit_core-0.7.0 → comfygit_core-0.7.1}/tests/unit/managers/test_export_import_overlays.py +0 -0
- {comfygit_core-0.7.0 → comfygit_core-0.7.1}/tests/unit/managers/test_git_manager_gitignore.py +0 -0
- {comfygit_core-0.7.0 → comfygit_core-0.7.1}/tests/unit/managers/test_git_manager_log_refs.py +0 -0
- {comfygit_core-0.7.0 → comfygit_core-0.7.1}/tests/unit/managers/test_model_index_manager.py +0 -0
- {comfygit_core-0.7.0 → comfygit_core-0.7.1}/tests/unit/managers/test_model_short_hash.py +0 -0
- {comfygit_core-0.7.0 → comfygit_core-0.7.1}/tests/unit/managers/test_node_conflict_detection.py +0 -0
- {comfygit_core-0.7.0 → comfygit_core-0.7.1}/tests/unit/managers/test_node_manager.py +0 -0
- {comfygit_core-0.7.0 → comfygit_core-0.7.1}/tests/unit/managers/test_overlay_fuzz.py +0 -0
- {comfygit_core-0.7.0 → comfygit_core-0.7.1}/tests/unit/managers/test_overlay_manager.py +0 -0
- {comfygit_core-0.7.0 → comfygit_core-0.7.1}/tests/unit/managers/test_overlay_materialization.py +0 -0
- {comfygit_core-0.7.0 → comfygit_core-0.7.1}/tests/unit/managers/test_pyproject_manager.py +0 -0
- {comfygit_core-0.7.0 → comfygit_core-0.7.1}/tests/unit/managers/test_pyproject_schema_version.py +0 -0
- {comfygit_core-0.7.0 → comfygit_core-0.7.1}/tests/unit/managers/test_pytorch_backend_manager.py +0 -0
- {comfygit_core-0.7.0 → comfygit_core-0.7.1}/tests/unit/managers/test_pytorch_overlay_materialization.py +0 -0
- {comfygit_core-0.7.0 → comfygit_core-0.7.1}/tests/unit/managers/test_pytorch_stripping.py +0 -0
- {comfygit_core-0.7.0 → comfygit_core-0.7.1}/tests/unit/managers/test_sqlite_manager.py +0 -0
- {comfygit_core-0.7.0 → comfygit_core-0.7.1}/tests/unit/managers/test_uv_no_build_isolation.py +0 -0
- {comfygit_core-0.7.0 → comfygit_core-0.7.1}/tests/unit/managers/test_workflow_manager.py +0 -0
- {comfygit_core-0.7.0 → comfygit_core-0.7.1}/tests/unit/managers/test_workflow_node_cleanup.py +0 -0
- {comfygit_core-0.7.0 → comfygit_core-0.7.1}/tests/unit/managers/test_workflow_status.py +0 -0
- {comfygit_core-0.7.0 → comfygit_core-0.7.1}/tests/unit/merging/__init__.py +0 -0
- {comfygit_core-0.7.0 → comfygit_core-0.7.1}/tests/unit/merging/test_atomic_executor.py +0 -0
- {comfygit_core-0.7.0 → comfygit_core-0.7.1}/tests/unit/merging/test_merge_validator.py +0 -0
- {comfygit_core-0.7.0 → comfygit_core-0.7.1}/tests/unit/merging/test_semantic_merger.py +0 -0
- {comfygit_core-0.7.0 → comfygit_core-0.7.1}/tests/unit/models/test_comfyui_builtin_versions.py +0 -0
- {comfygit_core-0.7.0 → comfygit_core-0.7.1}/tests/unit/models/test_lifecycle.py +0 -0
- {comfygit_core-0.7.0 → comfygit_core-0.7.1}/tests/unit/models/test_overlay.py +0 -0
- {comfygit_core-0.7.0 → comfygit_core-0.7.1}/tests/unit/models/test_ref_diff.py +0 -0
- {comfygit_core-0.7.0 → comfygit_core-0.7.1}/tests/unit/models/test_workflow_contract.py +0 -0
- {comfygit_core-0.7.0 → comfygit_core-0.7.1}/tests/unit/models/test_workflow_dependencies.py +0 -0
- {comfygit_core-0.7.0 → comfygit_core-0.7.1}/tests/unit/models/test_workflow_roundtrip.py +0 -0
- {comfygit_core-0.7.0 → comfygit_core-0.7.1}/tests/unit/models/test_workflow_subgraph.py +0 -0
- {comfygit_core-0.7.0 → comfygit_core-0.7.1}/tests/unit/repositories/test_credential_store.py +0 -0
- {comfygit_core-0.7.0 → comfygit_core-0.7.1}/tests/unit/resolvers/test_global_node_resolver_v2.py +0 -0
- {comfygit_core-0.7.0 → comfygit_core-0.7.1}/tests/unit/resolvers/test_model_resolver.py +0 -0
- {comfygit_core-0.7.0 → comfygit_core-0.7.1}/tests/unit/services/test_build_readiness.py +0 -0
- {comfygit_core-0.7.0 → comfygit_core-0.7.1}/tests/unit/services/test_credential_service.py +0 -0
- {comfygit_core-0.7.0 → comfygit_core-0.7.1}/tests/unit/services/test_dependency_resolution_preview.py +0 -0
- {comfygit_core-0.7.0 → comfygit_core-0.7.1}/tests/unit/services/test_environment_lifecycle.py +0 -0
- {comfygit_core-0.7.0 → comfygit_core-0.7.1}/tests/unit/services/test_environment_model_requirements.py +0 -0
- {comfygit_core-0.7.0 → comfygit_core-0.7.1}/tests/unit/services/test_environment_readiness.py +0 -0
- {comfygit_core-0.7.0 → comfygit_core-0.7.1}/tests/unit/services/test_global_node_resolver.py +0 -0
- {comfygit_core-0.7.0 → comfygit_core-0.7.1}/tests/unit/services/test_huggingface_url.py +0 -0
- {comfygit_core-0.7.0 → comfygit_core-0.7.1}/tests/unit/services/test_import_analyzer.py +0 -0
- {comfygit_core-0.7.0 → comfygit_core-0.7.1}/tests/unit/services/test_model_downloader.py +0 -0
- {comfygit_core-0.7.0 → comfygit_core-0.7.1}/tests/unit/services/test_model_source_lookup.py +0 -0
- {comfygit_core-0.7.0 → comfygit_core-0.7.1}/tests/unit/services/test_node_lookup_api_first.py +0 -0
- {comfygit_core-0.7.0 → comfygit_core-0.7.1}/tests/unit/services/test_node_lookup_version_fallback.py +0 -0
- {comfygit_core-0.7.0 → comfygit_core-0.7.1}/tests/unit/services/test_registry_data_manager.py +0 -0
- {comfygit_core-0.7.0 → comfygit_core-0.7.1}/tests/unit/services/test_resource_inventory.py +0 -0
- {comfygit_core-0.7.0 → comfygit_core-0.7.1}/tests/unit/services/test_scan_requirements_substitution.py +0 -0
- {comfygit_core-0.7.0 → comfygit_core-0.7.1}/tests/unit/services/test_unmanaged_environment_import.py +0 -0
- {comfygit_core-0.7.0 → comfygit_core-0.7.1}/tests/unit/services/test_workflow_analysis_cache.py +0 -0
- {comfygit_core-0.7.0 → comfygit_core-0.7.1}/tests/unit/services/test_workflow_analysis_service.py +0 -0
- {comfygit_core-0.7.0 → comfygit_core-0.7.1}/tests/unit/services/test_workflow_execution.py +0 -0
- {comfygit_core-0.7.0 → comfygit_core-0.7.1}/tests/unit/services/test_workflow_file_store.py +0 -0
- {comfygit_core-0.7.0 → comfygit_core-0.7.1}/tests/unit/services/test_workflow_input.py +0 -0
- {comfygit_core-0.7.0 → comfygit_core-0.7.1}/tests/unit/services/test_workflow_model_dependency_service.py +0 -0
- {comfygit_core-0.7.0 → comfygit_core-0.7.1}/tests/unit/services/test_workflow_model_download_coordinator.py +0 -0
- {comfygit_core-0.7.0 → comfygit_core-0.7.1}/tests/unit/services/test_workflow_model_path_policy.py +0 -0
- {comfygit_core-0.7.0 → comfygit_core-0.7.1}/tests/unit/services/test_workflow_resolution_context_builder.py +0 -0
- {comfygit_core-0.7.0 → comfygit_core-0.7.1}/tests/unit/services/test_workflow_resolution_fixer.py +0 -0
- {comfygit_core-0.7.0 → comfygit_core-0.7.1}/tests/unit/services/test_workflow_resolution_service.py +0 -0
- {comfygit_core-0.7.0 → comfygit_core-0.7.1}/tests/unit/services/test_workflow_state_cleanup.py +0 -0
- {comfygit_core-0.7.0 → comfygit_core-0.7.1}/tests/unit/test_add_dependencies_substitution.py +0 -0
- {comfygit_core-0.7.0 → comfygit_core-0.7.1}/tests/unit/test_auto_strategies.py +0 -0
- {comfygit_core-0.7.0 → comfygit_core-0.7.1}/tests/unit/test_builtin_extractor.py +0 -0
- {comfygit_core-0.7.0 → comfygit_core-0.7.1}/tests/unit/test_dev_node_rename_detection.py +0 -0
- {comfygit_core-0.7.0 → comfygit_core-0.7.1}/tests/unit/test_environment_py_dependencies.py +0 -0
- {comfygit_core-0.7.0 → comfygit_core-0.7.1}/tests/unit/test_external_uv_cache.py +0 -0
- {comfygit_core-0.7.0 → comfygit_core-0.7.1}/tests/unit/test_folder_paths_extractor.py +0 -0
- {comfygit_core-0.7.0 → comfygit_core-0.7.1}/tests/unit/test_github_auth_config.py +0 -0
- {comfygit_core-0.7.0 → comfygit_core-0.7.1}/tests/unit/test_github_url_installation.py +0 -0
- {comfygit_core-0.7.0 → comfygit_core-0.7.1}/tests/unit/test_headless_import.py +0 -0
- {comfygit_core-0.7.0 → comfygit_core-0.7.1}/tests/unit/test_materialization.py +0 -0
- {comfygit_core-0.7.0 → comfygit_core-0.7.1}/tests/unit/test_minimal_schema_compatibility.py +0 -0
- {comfygit_core-0.7.0 → comfygit_core-0.7.1}/tests/unit/test_model_config_dynamic_loading.py +0 -0
- {comfygit_core-0.7.0 → comfygit_core-0.7.1}/tests/unit/test_model_downloader_errors.py +0 -0
- {comfygit_core-0.7.0 → comfygit_core-0.7.1}/tests/unit/test_model_loader_extractor.py +0 -0
- {comfygit_core-0.7.0 → comfygit_core-0.7.1}/tests/unit/test_model_repository_cleanup.py +0 -0
- {comfygit_core-0.7.0 → comfygit_core-0.7.1}/tests/unit/test_model_symlink_manager.py +0 -0
- {comfygit_core-0.7.0 → comfygit_core-0.7.1}/tests/unit/test_node_callbacks.py +0 -0
- {comfygit_core-0.7.0 → comfygit_core-0.7.1}/tests/unit/test_node_conflict_context.py +0 -0
- {comfygit_core-0.7.0 → comfygit_core-0.7.1}/tests/unit/test_node_mappings_repository.py +0 -0
- {comfygit_core-0.7.0 → comfygit_core-0.7.1}/tests/unit/test_node_resolution_context.py +0 -0
- {comfygit_core-0.7.0 → comfygit_core-0.7.1}/tests/unit/test_unified_node_search.py +0 -0
- {comfygit_core-0.7.0 → comfygit_core-0.7.1}/tests/unit/test_user_content_symlink_manager.py +0 -0
- {comfygit_core-0.7.0 → comfygit_core-0.7.1}/tests/unit/test_uv_error_handling.py +0 -0
- {comfygit_core-0.7.0 → comfygit_core-0.7.1}/tests/unit/test_uv_error_parser.py +0 -0
- {comfygit_core-0.7.0 → comfygit_core-0.7.1}/tests/unit/test_workflow_manager_deduplication.py +0 -0
- {comfygit_core-0.7.0 → comfygit_core-0.7.1}/tests/unit/test_workspace_config_facade.py +0 -0
- {comfygit_core-0.7.0 → comfygit_core-0.7.1}/tests/unit/test_workspace_config_resilience.py +0 -0
- {comfygit_core-0.7.0 → comfygit_core-0.7.1}/tests/unit/test_workspace_credential_overrides.py +0 -0
- {comfygit_core-0.7.0 → comfygit_core-0.7.1}/tests/unit/utils/test_comfyui_ops_source.py +0 -0
- {comfygit_core-0.7.0 → comfygit_core-0.7.1}/tests/unit/utils/test_conflict_analyzer.py +0 -0
- {comfygit_core-0.7.0 → comfygit_core-0.7.1}/tests/unit/utils/test_conflict_parser.py +0 -0
- {comfygit_core-0.7.0 → comfygit_core-0.7.1}/tests/unit/utils/test_dependency_parser.py +0 -0
- {comfygit_core-0.7.0 → comfygit_core-0.7.1}/tests/unit/utils/test_dependency_probe.py +0 -0
- {comfygit_core-0.7.0 → comfygit_core-0.7.1}/tests/unit/utils/test_environment_cleanup.py +0 -0
- {comfygit_core-0.7.0 → comfygit_core-0.7.1}/tests/unit/utils/test_filesystem.py +0 -0
- {comfygit_core-0.7.0 → comfygit_core-0.7.1}/tests/unit/utils/test_git.py +0 -0
- {comfygit_core-0.7.0 → comfygit_core-0.7.1}/tests/unit/utils/test_input_signature.py +0 -0
- {comfygit_core-0.7.0 → comfygit_core-0.7.1}/tests/unit/utils/test_node_identity.py +0 -0
- {comfygit_core-0.7.0 → comfygit_core-0.7.1}/tests/unit/utils/test_provider_auth_hardening.py +0 -0
- {comfygit_core-0.7.0 → comfygit_core-0.7.1}/tests/unit/utils/test_pytorch.py +0 -0
- {comfygit_core-0.7.0 → comfygit_core-0.7.1}/tests/unit/utils/test_pytorch_prober.py +0 -0
- {comfygit_core-0.7.0 → comfygit_core-0.7.1}/tests/unit/utils/test_requirements.py +0 -0
- {comfygit_core-0.7.0 → comfygit_core-0.7.1}/tests/unit/utils/test_symlink_utils.py +0 -0
- {comfygit_core-0.7.0 → comfygit_core-0.7.1}/tests/unit/utils/test_uuid.py +0 -0
- {comfygit_core-0.7.0 → comfygit_core-0.7.1}/tests/unit/utils/test_version.py +0 -0
- {comfygit_core-0.7.0 → comfygit_core-0.7.1}/tests/utils/__init__.py +0 -0
- {comfygit_core-0.7.0 → comfygit_core-0.7.1}/tests/utils/test_workflow_hash.py +0 -0
|
@@ -0,0 +1,131 @@
|
|
|
1
|
+
Metadata-Version: 2.5
|
|
2
|
+
Name: comfygit-core
|
|
3
|
+
Version: 0.7.1
|
|
4
|
+
Summary: ComfyGit Core - Git-based ComfyUI environment manager
|
|
5
|
+
Project-URL: Documentation, https://docs.comfygit.org/
|
|
6
|
+
Project-URL: Repository, https://github.com/comfygit-ai/comfygit
|
|
7
|
+
Project-URL: Issues, https://github.com/comfygit-ai/comfygit/issues
|
|
8
|
+
License-File: LICENSE.txt
|
|
9
|
+
Requires-Python: >=3.10
|
|
10
|
+
Requires-Dist: blake3>=0.3.3
|
|
11
|
+
Requires-Dist: huggingface-hub>=0.15.1
|
|
12
|
+
Requires-Dist: packaging>=16.2
|
|
13
|
+
Requires-Dist: requests>=2.32.4
|
|
14
|
+
Requires-Dist: requirements-parser>=0.11.0
|
|
15
|
+
Requires-Dist: tomli>=2.0.1; python_version < '3.11'
|
|
16
|
+
Requires-Dist: tomlkit>=0.11.0
|
|
17
|
+
Requires-Dist: uv>=0.11.15
|
|
18
|
+
Requires-Dist: xxhash>=2.0.0
|
|
19
|
+
Provides-Extra: keyring
|
|
20
|
+
Requires-Dist: keyring>=25.7.0; extra == 'keyring'
|
|
21
|
+
Description-Content-Type: text/markdown
|
|
22
|
+
|
|
23
|
+
# ComfyGit Core
|
|
24
|
+
|
|
25
|
+
`comfygit-core` is the UI-independent library behind ComfyGit's CLI and runtime
|
|
26
|
+
adapters. It owns workspace discovery, environment manifests, custom nodes,
|
|
27
|
+
model metadata, dependency resolution, sync, import/export and materialization.
|
|
28
|
+
APIs are still evolving; integrations should pin a tested release.
|
|
29
|
+
|
|
30
|
+
## Installation
|
|
31
|
+
|
|
32
|
+
```bash
|
|
33
|
+
uv add 'comfygit-core==0.7.0'
|
|
34
|
+
```
|
|
35
|
+
|
|
36
|
+
Core does not require desktop keyring. For OS-backed credential persistence,
|
|
37
|
+
install the optional `comfygit-core[keyring]==0.7.0` extra. The CLI includes that
|
|
38
|
+
extra; headless library users can use environment credentials or inject their
|
|
39
|
+
own store instead.
|
|
40
|
+
|
|
41
|
+
## Open a workspace
|
|
42
|
+
|
|
43
|
+
```python
|
|
44
|
+
from pathlib import Path
|
|
45
|
+
from comfygit_core import Workspace
|
|
46
|
+
|
|
47
|
+
workspace = Workspace.open(Path.home() / "comfygit")
|
|
48
|
+
env = workspace.get_environment("my-project", auto_sync=False)
|
|
49
|
+
status = env.status()
|
|
50
|
+
```
|
|
51
|
+
|
|
52
|
+
`Workspace.create(path)` creates a workspace; `Workspace.open_or_create(path)`
|
|
53
|
+
handles either case. Opening with `auto_sync=False` above avoids reconciling the
|
|
54
|
+
environment just to inspect it.
|
|
55
|
+
|
|
56
|
+
## Create and reconcile an environment
|
|
57
|
+
|
|
58
|
+
```python
|
|
59
|
+
env = workspace.create_environment(
|
|
60
|
+
name="experiment",
|
|
61
|
+
python_version="3.12",
|
|
62
|
+
torch_backend="auto",
|
|
63
|
+
no_manager=True,
|
|
64
|
+
)
|
|
65
|
+
env.add_node("rgthree-comfy")
|
|
66
|
+
result = env.sync(model_strategy="required")
|
|
67
|
+
```
|
|
68
|
+
|
|
69
|
+
Creation and sync can download code and packages. Resolve an existing saved
|
|
70
|
+
workflow by its name, not an arbitrary JSON path:
|
|
71
|
+
|
|
72
|
+
```python
|
|
73
|
+
result = env.resolve_workflow("my-workflow")
|
|
74
|
+
```
|
|
75
|
+
|
|
76
|
+
For ambiguous resolution, supply implementations of the protocols in
|
|
77
|
+
[`models/protocols.py`](src/comfygit_core/models/protocols.py). Do not put prompts,
|
|
78
|
+
printing or CLI policy into Core. A successful dependency resolution is not proof
|
|
79
|
+
that a ComfyUI inference job succeeds.
|
|
80
|
+
|
|
81
|
+
## Credentials
|
|
82
|
+
|
|
83
|
+
Workspace entry points accept process-local `credential_overrides`, keyed by
|
|
84
|
+
`CredentialProvider`. A token overrides all discovery for that provider; `None`
|
|
85
|
+
explicitly selects anonymous access. Omitted providers use normal discovery.
|
|
86
|
+
|
|
87
|
+
```python
|
|
88
|
+
from comfygit_core.models.credentials import CredentialProvider
|
|
89
|
+
|
|
90
|
+
workspace = Workspace.open(
|
|
91
|
+
Path.home() / "comfygit",
|
|
92
|
+
credential_overrides={CredentialProvider.HUGGINGFACE: None},
|
|
93
|
+
)
|
|
94
|
+
```
|
|
95
|
+
|
|
96
|
+
Normal resolution uses provider environment variables, workspace secure storage,
|
|
97
|
+
provider-native credentials when available, then legacy workspace values during
|
|
98
|
+
migration. An unavailable keyring backend does not prevent environment/native
|
|
99
|
+
credentials from working. Saving a new credential requires a working secure store;
|
|
100
|
+
there is no new plaintext fallback. Callers may inject a `CredentialStore` through
|
|
101
|
+
the `credential_store` parameter.
|
|
102
|
+
|
|
103
|
+
## Portable and local state
|
|
104
|
+
|
|
105
|
+
The tracked `pyproject.toml`, `workflows/`, `workflow_api/`, shared overlays and
|
|
106
|
+
source metadata form the portable environment. Model bytes stay in the shared
|
|
107
|
+
model directory. ComfyUI/node checkouts, virtualenvs, `.cec/`, local overlays,
|
|
108
|
+
credentials and backend choices are derived or machine-local state.
|
|
109
|
+
|
|
110
|
+
Use ComfyGit operations to change the recipe; manual runtime edits may be
|
|
111
|
+
replaced on sync. For a headless recreation, use the materialization API or
|
|
112
|
+
[`cg materialize`](https://docs.comfygit.org/user-guide/collaboration/materialize/).
|
|
113
|
+
|
|
114
|
+
## API and development references
|
|
115
|
+
|
|
116
|
+
- [Workspace entry points](src/comfygit_core/core/workspace.py)
|
|
117
|
+
- [Environment operations](src/comfygit_core/core/environment.py)
|
|
118
|
+
- [Architecture](docs/architecture.md)
|
|
119
|
+
- [Normative contracts](../../docs/contracts/) and [specifications](../../docs/specs/)
|
|
120
|
+
- [Contributing](../../CONTRIBUTING.md)
|
|
121
|
+
|
|
122
|
+
From the monorepo root:
|
|
123
|
+
|
|
124
|
+
```bash
|
|
125
|
+
uv sync --frozen --all-packages
|
|
126
|
+
uv run pytest packages/core/tests -q
|
|
127
|
+
make lint
|
|
128
|
+
```
|
|
129
|
+
|
|
130
|
+
Core, Studio runtime and CLI releases use matched versions. See the root
|
|
131
|
+
[agent guide](../../AGENTS.md) for release ordering and package boundaries.
|
|
@@ -0,0 +1,109 @@
|
|
|
1
|
+
# ComfyGit Core
|
|
2
|
+
|
|
3
|
+
`comfygit-core` is the UI-independent library behind ComfyGit's CLI and runtime
|
|
4
|
+
adapters. It owns workspace discovery, environment manifests, custom nodes,
|
|
5
|
+
model metadata, dependency resolution, sync, import/export and materialization.
|
|
6
|
+
APIs are still evolving; integrations should pin a tested release.
|
|
7
|
+
|
|
8
|
+
## Installation
|
|
9
|
+
|
|
10
|
+
```bash
|
|
11
|
+
uv add 'comfygit-core==0.7.0'
|
|
12
|
+
```
|
|
13
|
+
|
|
14
|
+
Core does not require desktop keyring. For OS-backed credential persistence,
|
|
15
|
+
install the optional `comfygit-core[keyring]==0.7.0` extra. The CLI includes that
|
|
16
|
+
extra; headless library users can use environment credentials or inject their
|
|
17
|
+
own store instead.
|
|
18
|
+
|
|
19
|
+
## Open a workspace
|
|
20
|
+
|
|
21
|
+
```python
|
|
22
|
+
from pathlib import Path
|
|
23
|
+
from comfygit_core import Workspace
|
|
24
|
+
|
|
25
|
+
workspace = Workspace.open(Path.home() / "comfygit")
|
|
26
|
+
env = workspace.get_environment("my-project", auto_sync=False)
|
|
27
|
+
status = env.status()
|
|
28
|
+
```
|
|
29
|
+
|
|
30
|
+
`Workspace.create(path)` creates a workspace; `Workspace.open_or_create(path)`
|
|
31
|
+
handles either case. Opening with `auto_sync=False` above avoids reconciling the
|
|
32
|
+
environment just to inspect it.
|
|
33
|
+
|
|
34
|
+
## Create and reconcile an environment
|
|
35
|
+
|
|
36
|
+
```python
|
|
37
|
+
env = workspace.create_environment(
|
|
38
|
+
name="experiment",
|
|
39
|
+
python_version="3.12",
|
|
40
|
+
torch_backend="auto",
|
|
41
|
+
no_manager=True,
|
|
42
|
+
)
|
|
43
|
+
env.add_node("rgthree-comfy")
|
|
44
|
+
result = env.sync(model_strategy="required")
|
|
45
|
+
```
|
|
46
|
+
|
|
47
|
+
Creation and sync can download code and packages. Resolve an existing saved
|
|
48
|
+
workflow by its name, not an arbitrary JSON path:
|
|
49
|
+
|
|
50
|
+
```python
|
|
51
|
+
result = env.resolve_workflow("my-workflow")
|
|
52
|
+
```
|
|
53
|
+
|
|
54
|
+
For ambiguous resolution, supply implementations of the protocols in
|
|
55
|
+
[`models/protocols.py`](src/comfygit_core/models/protocols.py). Do not put prompts,
|
|
56
|
+
printing or CLI policy into Core. A successful dependency resolution is not proof
|
|
57
|
+
that a ComfyUI inference job succeeds.
|
|
58
|
+
|
|
59
|
+
## Credentials
|
|
60
|
+
|
|
61
|
+
Workspace entry points accept process-local `credential_overrides`, keyed by
|
|
62
|
+
`CredentialProvider`. A token overrides all discovery for that provider; `None`
|
|
63
|
+
explicitly selects anonymous access. Omitted providers use normal discovery.
|
|
64
|
+
|
|
65
|
+
```python
|
|
66
|
+
from comfygit_core.models.credentials import CredentialProvider
|
|
67
|
+
|
|
68
|
+
workspace = Workspace.open(
|
|
69
|
+
Path.home() / "comfygit",
|
|
70
|
+
credential_overrides={CredentialProvider.HUGGINGFACE: None},
|
|
71
|
+
)
|
|
72
|
+
```
|
|
73
|
+
|
|
74
|
+
Normal resolution uses provider environment variables, workspace secure storage,
|
|
75
|
+
provider-native credentials when available, then legacy workspace values during
|
|
76
|
+
migration. An unavailable keyring backend does not prevent environment/native
|
|
77
|
+
credentials from working. Saving a new credential requires a working secure store;
|
|
78
|
+
there is no new plaintext fallback. Callers may inject a `CredentialStore` through
|
|
79
|
+
the `credential_store` parameter.
|
|
80
|
+
|
|
81
|
+
## Portable and local state
|
|
82
|
+
|
|
83
|
+
The tracked `pyproject.toml`, `workflows/`, `workflow_api/`, shared overlays and
|
|
84
|
+
source metadata form the portable environment. Model bytes stay in the shared
|
|
85
|
+
model directory. ComfyUI/node checkouts, virtualenvs, `.cec/`, local overlays,
|
|
86
|
+
credentials and backend choices are derived or machine-local state.
|
|
87
|
+
|
|
88
|
+
Use ComfyGit operations to change the recipe; manual runtime edits may be
|
|
89
|
+
replaced on sync. For a headless recreation, use the materialization API or
|
|
90
|
+
[`cg materialize`](https://docs.comfygit.org/user-guide/collaboration/materialize/).
|
|
91
|
+
|
|
92
|
+
## API and development references
|
|
93
|
+
|
|
94
|
+
- [Workspace entry points](src/comfygit_core/core/workspace.py)
|
|
95
|
+
- [Environment operations](src/comfygit_core/core/environment.py)
|
|
96
|
+
- [Architecture](docs/architecture.md)
|
|
97
|
+
- [Normative contracts](../../docs/contracts/) and [specifications](../../docs/specs/)
|
|
98
|
+
- [Contributing](../../CONTRIBUTING.md)
|
|
99
|
+
|
|
100
|
+
From the monorepo root:
|
|
101
|
+
|
|
102
|
+
```bash
|
|
103
|
+
uv sync --frozen --all-packages
|
|
104
|
+
uv run pytest packages/core/tests -q
|
|
105
|
+
make lint
|
|
106
|
+
```
|
|
107
|
+
|
|
108
|
+
Core, Studio runtime and CLI releases use matched versions. See the root
|
|
109
|
+
[agent guide](../../AGENTS.md) for release ordering and package boundaries.
|
|
@@ -6,7 +6,8 @@ import os
|
|
|
6
6
|
import re
|
|
7
7
|
import shutil
|
|
8
8
|
import subprocess
|
|
9
|
-
from collections.abc import Mapping, Sequence
|
|
9
|
+
from collections.abc import Iterator, Mapping, Sequence
|
|
10
|
+
from contextlib import contextmanager
|
|
10
11
|
from datetime import datetime, timezone
|
|
11
12
|
from functools import cached_property, wraps
|
|
12
13
|
from pathlib import Path
|
|
@@ -125,7 +126,7 @@ def _workflow_api_prompt_relpath(workflow_name: str) -> Path:
|
|
|
125
126
|
def _requires_env_lock(method):
|
|
126
127
|
@wraps(method)
|
|
127
128
|
def wrapper(self, *args, **kwargs):
|
|
128
|
-
with self._operation_lock:
|
|
129
|
+
with self._operation_lock.named(method.__name__):
|
|
129
130
|
return method(self, *args, **kwargs)
|
|
130
131
|
return wrapper
|
|
131
132
|
|
|
@@ -2532,10 +2533,21 @@ class Environment:
|
|
|
2532
2533
|
# Public Snapshots and Readiness
|
|
2533
2534
|
# =====================================================
|
|
2534
2535
|
|
|
2535
|
-
@_requires_env_lock
|
|
2536
2536
|
def get_manifest_snapshot(self) -> EnvironmentManifestSnapshot:
|
|
2537
2537
|
"""Return a typed read-only projection of the current manifest."""
|
|
2538
|
-
|
|
2538
|
+
with self.read_manifest_snapshot() as snapshot:
|
|
2539
|
+
return snapshot
|
|
2540
|
+
|
|
2541
|
+
@contextmanager
|
|
2542
|
+
def read_manifest_snapshot(self) -> Iterator[EnvironmentManifestSnapshot]:
|
|
2543
|
+
"""Capture manifest and related artifacts under a short shared lock.
|
|
2544
|
+
|
|
2545
|
+
Do not await, mutate the environment, or execute a prompt in this scope.
|
|
2546
|
+
A new detached snapshot is loaded each time; no stale-cache fallback is
|
|
2547
|
+
used when a writer is active.
|
|
2548
|
+
"""
|
|
2549
|
+
with self._operation_lock.read():
|
|
2550
|
+
yield self.pyproject.get_manifest_snapshot(force_reload=True)
|
|
2539
2551
|
|
|
2540
2552
|
def list_manifest_nodes(self) -> Mapping[str, NodeInfo]:
|
|
2541
2553
|
"""Return tracked manifest nodes without exposing the manifest manager."""
|
|
@@ -61,6 +61,7 @@ def read_runtime_advertisement(workspace: Path, environment: str) -> dict | None
|
|
|
61
61
|
if isinstance(data, dict) and data.get("environment") == environment:
|
|
62
62
|
return data
|
|
63
63
|
except (OSError, ValueError):
|
|
64
|
+
# Missing or malformed advertisements cannot establish runtime ownership.
|
|
64
65
|
pass
|
|
65
66
|
return None
|
|
66
67
|
|
|
@@ -123,6 +124,7 @@ class ManagedRuntimeController:
|
|
|
123
124
|
and isinstance(data.get("queue_pending"), list)):
|
|
124
125
|
running, pending = len(data["queue_running"]), len(data["queue_pending"])
|
|
125
126
|
except (requests.RequestException, ValueError):
|
|
127
|
+
# Keep unavailable probes unknown; restart refuses an unverified queue.
|
|
126
128
|
pass
|
|
127
129
|
return ManagedRuntimeStatus(
|
|
128
130
|
environment=self.environment, instance_id=self.instance_id,
|
|
@@ -229,6 +229,7 @@ class SwitchObserverServer:
|
|
|
229
229
|
if self.runtime_controller and data.get("instance_id") == self.runtime_controller.instance_id:
|
|
230
230
|
path.unlink(missing_ok=True)
|
|
231
231
|
except (OSError, ValueError):
|
|
232
|
+
# Cleanup is best effort; never remove an advertisement without ownership proof.
|
|
232
233
|
pass
|
|
233
234
|
|
|
234
235
|
def append_log(self, message: str, level: str = "info") -> None:
|
|
@@ -11,6 +11,8 @@ _EXPORTS: dict[str, str] = {
|
|
|
11
11
|
"CDWorkspaceExistsError": "exceptions",
|
|
12
12
|
"CDCredentialStoreError": "exceptions",
|
|
13
13
|
"CDEnvironmentError": "exceptions",
|
|
14
|
+
"CDEnvironmentBusyError": "exceptions",
|
|
15
|
+
"EnvironmentLockOwner": "exceptions",
|
|
14
16
|
"CDEnvironmentNotFoundError": "exceptions",
|
|
15
17
|
"CDEnvironmentExistsError": "exceptions",
|
|
16
18
|
"CDDependencyPreviewStaleError": "exceptions",
|
|
@@ -41,6 +41,28 @@ class CDEnvironmentError(ComfyDockError):
|
|
|
41
41
|
"""Environment-related errors."""
|
|
42
42
|
pass
|
|
43
43
|
|
|
44
|
+
|
|
45
|
+
@dataclass(frozen=True)
|
|
46
|
+
class EnvironmentLockOwner:
|
|
47
|
+
"""Best-effort diagnostics, never authority to delete or steal a lock."""
|
|
48
|
+
|
|
49
|
+
pid: int | None = None
|
|
50
|
+
operation: str | None = None
|
|
51
|
+
acquired_at: str | None = None
|
|
52
|
+
|
|
53
|
+
|
|
54
|
+
class CDEnvironmentBusyError(CDEnvironmentError):
|
|
55
|
+
"""An environment lock is held; the requested operation has not begun."""
|
|
56
|
+
|
|
57
|
+
def __init__(self, lock_path: str, owner: EnvironmentLockOwner):
|
|
58
|
+
self.lock_path = lock_path
|
|
59
|
+
self.owner = owner
|
|
60
|
+
super().__init__(
|
|
61
|
+
"Another ComfyGit operation is running on this environment. "
|
|
62
|
+
f"Wait for it to complete (owner PID: {owner.pid}, operation: {owner.operation}). "
|
|
63
|
+
"Do not delete the lock file while an operation may be running."
|
|
64
|
+
)
|
|
65
|
+
|
|
44
66
|
class CDEnvironmentNotFoundError(ComfyDockError):
|
|
45
67
|
"""Environment doesn't exist."""
|
|
46
68
|
pass
|
|
@@ -1,5 +1,8 @@
|
|
|
1
1
|
# models/manifest.py
|
|
2
|
+
import hashlib
|
|
3
|
+
import json
|
|
2
4
|
from collections.abc import Mapping
|
|
5
|
+
from copy import deepcopy
|
|
3
6
|
from dataclasses import dataclass, field
|
|
4
7
|
from types import MappingProxyType
|
|
5
8
|
from typing import Any, Literal
|
|
@@ -304,6 +307,7 @@ class EnvironmentManifestSnapshot:
|
|
|
304
307
|
nodes: Mapping[str, NodeInfo]
|
|
305
308
|
workflows: Mapping[str, ManifestWorkflowEntry]
|
|
306
309
|
models: Mapping[str, ManifestModel]
|
|
310
|
+
revision: str = ""
|
|
307
311
|
|
|
308
312
|
def get_node(self, identifier: str) -> NodeInfo | None:
|
|
309
313
|
"""Return one manifest node by package identifier."""
|
|
@@ -331,6 +335,8 @@ class EnvironmentManifestSnapshot:
|
|
|
331
335
|
|
|
332
336
|
@classmethod
|
|
333
337
|
def from_toml_dict(cls, data: dict[str, Any]) -> "EnvironmentManifestSnapshot":
|
|
338
|
+
# Detached from the manager's mutable document, including nested defaults.
|
|
339
|
+
data = deepcopy(data)
|
|
334
340
|
tool = _plain_mapping(data.get("tool", {}))
|
|
335
341
|
comfygit = _plain_mapping(tool.get("comfygit", {}))
|
|
336
342
|
|
|
@@ -362,6 +368,7 @@ class EnvironmentManifestSnapshot:
|
|
|
362
368
|
normalized_schema_version = 1
|
|
363
369
|
|
|
364
370
|
return cls(
|
|
371
|
+
revision=hashlib.sha256(json.dumps(data, sort_keys=True, default=str).encode()).hexdigest(),
|
|
365
372
|
project=ManifestProjectSnapshot.from_toml_dict(data),
|
|
366
373
|
schema_version=normalized_schema_version,
|
|
367
374
|
comfyui_version=(
|
{comfygit_core-0.7.0 → comfygit_core-0.7.1}/src/comfygit_core/services/credential_service.py
RENAMED
|
@@ -70,6 +70,7 @@ class CredentialService:
|
|
|
70
70
|
if value := self.credential_store.get(workspace_id, provider):
|
|
71
71
|
return value
|
|
72
72
|
except CDCredentialStoreError:
|
|
73
|
+
# An unavailable desktop store must not block native/headless credentials.
|
|
73
74
|
pass
|
|
74
75
|
|
|
75
76
|
if value := self._native_value(provider):
|
|
@@ -0,0 +1,196 @@
|
|
|
1
|
+
"""Environment operation lock utilities."""
|
|
2
|
+
|
|
3
|
+
from __future__ import annotations
|
|
4
|
+
|
|
5
|
+
import errno
|
|
6
|
+
import json
|
|
7
|
+
import os
|
|
8
|
+
import sys
|
|
9
|
+
import threading
|
|
10
|
+
from collections.abc import Iterator
|
|
11
|
+
from contextlib import contextmanager
|
|
12
|
+
from datetime import datetime, timezone
|
|
13
|
+
from pathlib import Path
|
|
14
|
+
from typing import IO
|
|
15
|
+
|
|
16
|
+
from ..models.exceptions import CDEnvironmentBusyError, EnvironmentLockOwner
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
class EnvironmentOperationLock:
|
|
20
|
+
"""Cross-process, cross-thread lock for environment mutations."""
|
|
21
|
+
|
|
22
|
+
def __init__(self, lock_path: Path, *, shared: bool = False, operation: str = "environment operation"):
|
|
23
|
+
self.lock_path = lock_path
|
|
24
|
+
self.shared = shared
|
|
25
|
+
self.operation = operation
|
|
26
|
+
self._thread_lock = threading.Lock()
|
|
27
|
+
self._depth = 0
|
|
28
|
+
self._file: IO[str] | None = None
|
|
29
|
+
self._owner_thread: int | None = None
|
|
30
|
+
|
|
31
|
+
def __enter__(self) -> EnvironmentOperationLock:
|
|
32
|
+
return self._enter()
|
|
33
|
+
|
|
34
|
+
def _enter(self, operation: str | None = None) -> EnvironmentOperationLock:
|
|
35
|
+
current_thread = threading.get_ident()
|
|
36
|
+
with self._thread_lock:
|
|
37
|
+
if self._depth > 0 and self._owner_thread != current_thread:
|
|
38
|
+
raise self._busy_error()
|
|
39
|
+
if self._depth == 0:
|
|
40
|
+
if operation is not None:
|
|
41
|
+
self.operation = operation
|
|
42
|
+
self._acquire_file_lock()
|
|
43
|
+
self._owner_thread = current_thread
|
|
44
|
+
self._depth += 1
|
|
45
|
+
return self
|
|
46
|
+
|
|
47
|
+
def __exit__(self, exc_type, exc, tb) -> bool:
|
|
48
|
+
with self._thread_lock:
|
|
49
|
+
self._depth -= 1
|
|
50
|
+
if self._depth == 0:
|
|
51
|
+
self._owner_thread = None
|
|
52
|
+
self._release_file_lock()
|
|
53
|
+
return False
|
|
54
|
+
|
|
55
|
+
@contextmanager
|
|
56
|
+
def read(self) -> Iterator[None]:
|
|
57
|
+
"""Short shared read scope; never hold across await or upgrade to a write."""
|
|
58
|
+
with self._thread_lock:
|
|
59
|
+
owns_write = self._depth > 0 and self._owner_thread == threading.get_ident()
|
|
60
|
+
if owns_write:
|
|
61
|
+
# Synchronous reads nested inside a mutation already have protection.
|
|
62
|
+
yield
|
|
63
|
+
return
|
|
64
|
+
with EnvironmentOperationLock(self.lock_path, shared=True, operation="snapshot read"):
|
|
65
|
+
yield
|
|
66
|
+
|
|
67
|
+
@contextmanager
|
|
68
|
+
def named(self, operation: str) -> Iterator[None]:
|
|
69
|
+
"""Label the outer mutation, retaining its label across nested calls."""
|
|
70
|
+
self._enter(operation)
|
|
71
|
+
try:
|
|
72
|
+
yield
|
|
73
|
+
finally:
|
|
74
|
+
self.__exit__(None, None, None)
|
|
75
|
+
|
|
76
|
+
def _busy_error(self) -> CDEnvironmentBusyError:
|
|
77
|
+
owner = EnvironmentLockOwner()
|
|
78
|
+
try:
|
|
79
|
+
with self.lock_path.open(encoding="utf-8") as source:
|
|
80
|
+
# Win32 locks byte zero against even diagnostic reads. New
|
|
81
|
+
# writers reserve that byte and put their JSON after it.
|
|
82
|
+
if sys.platform == "win32":
|
|
83
|
+
source.seek(1)
|
|
84
|
+
data = json.loads(source.read(4096))
|
|
85
|
+
if isinstance(data, int) and sys.platform != "win32": # Legacy PID-only writer.
|
|
86
|
+
owner = EnvironmentLockOwner(pid=data)
|
|
87
|
+
elif isinstance(data, dict):
|
|
88
|
+
owner = EnvironmentLockOwner(
|
|
89
|
+
pid=data.get("pid") if type(data.get("pid")) is int else None,
|
|
90
|
+
operation=str(data["operation"])[:160] if data.get("operation") else None,
|
|
91
|
+
acquired_at=str(data["acquired_at"])[:64] if data.get("acquired_at") else None,
|
|
92
|
+
)
|
|
93
|
+
except (OSError, ValueError):
|
|
94
|
+
pass
|
|
95
|
+
return CDEnvironmentBusyError(str(self.lock_path), owner)
|
|
96
|
+
|
|
97
|
+
def _acquire_file_lock(self) -> None:
|
|
98
|
+
self.lock_path.parent.mkdir(parents=True, exist_ok=True)
|
|
99
|
+
self._file = open(self.lock_path, "a+")
|
|
100
|
+
|
|
101
|
+
try:
|
|
102
|
+
self._file.seek(0)
|
|
103
|
+
if sys.platform == "win32":
|
|
104
|
+
try:
|
|
105
|
+
_windows_lock(self._file.fileno(), shared=self.shared)
|
|
106
|
+
except OSError as e:
|
|
107
|
+
if e.winerror == 33: # ERROR_LOCK_VIOLATION
|
|
108
|
+
raise self._busy_error() from e
|
|
109
|
+
raise
|
|
110
|
+
else:
|
|
111
|
+
import fcntl
|
|
112
|
+
|
|
113
|
+
try:
|
|
114
|
+
mode = fcntl.LOCK_SH if self.shared else fcntl.LOCK_EX
|
|
115
|
+
fcntl.flock(self._file.fileno(), mode | fcntl.LOCK_NB)
|
|
116
|
+
except OSError as e:
|
|
117
|
+
if e.errno in {errno.EAGAIN, errno.EACCES}:
|
|
118
|
+
raise self._busy_error() from e
|
|
119
|
+
raise
|
|
120
|
+
|
|
121
|
+
if self.shared:
|
|
122
|
+
return # Readers must not overwrite or clear writer diagnostics.
|
|
123
|
+
|
|
124
|
+
try:
|
|
125
|
+
self._file.seek(0)
|
|
126
|
+
self._file.truncate()
|
|
127
|
+
self._file.write(" ")
|
|
128
|
+
json.dump({"pid": os.getpid(), "operation": self.operation,
|
|
129
|
+
"acquired_at": datetime.now(timezone.utc).isoformat()}, self._file)
|
|
130
|
+
self._file.flush()
|
|
131
|
+
except OSError:
|
|
132
|
+
pass
|
|
133
|
+
except Exception:
|
|
134
|
+
self._file.close()
|
|
135
|
+
self._file = None
|
|
136
|
+
raise
|
|
137
|
+
|
|
138
|
+
def _release_file_lock(self) -> None:
|
|
139
|
+
if not self._file:
|
|
140
|
+
return
|
|
141
|
+
|
|
142
|
+
try:
|
|
143
|
+
self._file.seek(0)
|
|
144
|
+
try:
|
|
145
|
+
if not self.shared:
|
|
146
|
+
self._file.truncate()
|
|
147
|
+
self._file.flush()
|
|
148
|
+
except OSError:
|
|
149
|
+
pass
|
|
150
|
+
|
|
151
|
+
if sys.platform == "win32":
|
|
152
|
+
try:
|
|
153
|
+
_windows_lock(self._file.fileno(), shared=self.shared, unlock=True)
|
|
154
|
+
except OSError:
|
|
155
|
+
pass
|
|
156
|
+
else:
|
|
157
|
+
import fcntl
|
|
158
|
+
|
|
159
|
+
try:
|
|
160
|
+
fcntl.flock(self._file.fileno(), fcntl.LOCK_UN)
|
|
161
|
+
except OSError:
|
|
162
|
+
pass
|
|
163
|
+
finally:
|
|
164
|
+
self._file.close()
|
|
165
|
+
self._file = None
|
|
166
|
+
|
|
167
|
+
|
|
168
|
+
def _windows_lock(fd: int, *, shared: bool, unlock: bool = False) -> None:
|
|
169
|
+
"""Lock byte zero with Win32 shared/exclusive semantics (msvcrt lacks shared locks)."""
|
|
170
|
+
if sys.platform != "win32":
|
|
171
|
+
raise RuntimeError("Win32 locking is only available on Windows")
|
|
172
|
+
import ctypes
|
|
173
|
+
import msvcrt
|
|
174
|
+
from ctypes import wintypes
|
|
175
|
+
|
|
176
|
+
class Overlapped(ctypes.Structure):
|
|
177
|
+
_fields_ = [("Internal", ctypes.c_size_t), ("InternalHigh", ctypes.c_size_t),
|
|
178
|
+
("Offset", wintypes.DWORD), ("OffsetHigh", wintypes.DWORD),
|
|
179
|
+
("hEvent", wintypes.HANDLE)]
|
|
180
|
+
|
|
181
|
+
kernel = ctypes.WinDLL("kernel32", use_last_error=True)
|
|
182
|
+
handle = wintypes.HANDLE(msvcrt.get_osfhandle(fd))
|
|
183
|
+
overlap = Overlapped()
|
|
184
|
+
if unlock:
|
|
185
|
+
fn = kernel.UnlockFileEx
|
|
186
|
+
fn.argtypes = [wintypes.HANDLE, wintypes.DWORD, wintypes.DWORD,
|
|
187
|
+
wintypes.DWORD, ctypes.POINTER(Overlapped)]
|
|
188
|
+
args = (handle, 0, 1, 0, ctypes.byref(overlap))
|
|
189
|
+
else:
|
|
190
|
+
fn = kernel.LockFileEx
|
|
191
|
+
fn.argtypes = [wintypes.HANDLE, wintypes.DWORD, wintypes.DWORD,
|
|
192
|
+
wintypes.DWORD, wintypes.DWORD, ctypes.POINTER(Overlapped)]
|
|
193
|
+
args = (handle, 1 | (0 if shared else 2), 0, 1, 0, ctypes.byref(overlap))
|
|
194
|
+
fn.restype = wintypes.BOOL
|
|
195
|
+
if not fn(*args):
|
|
196
|
+
raise ctypes.WinError(ctypes.get_last_error())
|
{comfygit_core-0.7.0 → comfygit_core-0.7.1}/tests/unit/core/test_environment_operation_locking.py
RENAMED
|
@@ -1,5 +1,7 @@
|
|
|
1
1
|
"""Tests for environment operation lock decorators."""
|
|
2
2
|
|
|
3
|
+
import os
|
|
4
|
+
|
|
3
5
|
from comfygit_core.core.environment import Environment
|
|
4
6
|
from comfygit_core.utils.environment_lock import EnvironmentOperationLock
|
|
5
7
|
|
|
@@ -13,6 +15,9 @@ class _FakeLock:
|
|
|
13
15
|
self.entered = True
|
|
14
16
|
return self
|
|
15
17
|
|
|
18
|
+
def named(self, operation):
|
|
19
|
+
return self
|
|
20
|
+
|
|
16
21
|
def __exit__(self, exc_type, exc, tb) -> bool:
|
|
17
22
|
self.exited = True
|
|
18
23
|
return False
|
|
@@ -50,6 +55,8 @@ def test_environment_operation_lock_clears_owner_file_on_release(tmp_path):
|
|
|
50
55
|
lock_path = tmp_path / ".comfygit.lock"
|
|
51
56
|
|
|
52
57
|
with EnvironmentOperationLock(lock_path):
|
|
53
|
-
|
|
58
|
+
# Windows reserves byte zero for the mandatory OS lock. Read owner
|
|
59
|
+
# diagnostics through the same portable path used by contending callers.
|
|
60
|
+
assert EnvironmentOperationLock(lock_path)._busy_error().owner.pid == os.getpid()
|
|
54
61
|
|
|
55
62
|
assert lock_path.read_text(encoding="utf-8") == ""
|