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.
Files changed (457) hide show
  1. comfygit_core-0.7.1/PKG-INFO +131 -0
  2. comfygit_core-0.7.1/README.md +109 -0
  3. {comfygit_core-0.7.0 → comfygit_core-0.7.1}/pyproject.toml +1 -1
  4. {comfygit_core-0.7.0 → comfygit_core-0.7.1}/src/comfygit_core/core/environment.py +16 -4
  5. {comfygit_core-0.7.0 → comfygit_core-0.7.1}/src/comfygit_core/lifecycle/runtime_control.py +2 -0
  6. {comfygit_core-0.7.0 → comfygit_core-0.7.1}/src/comfygit_core/lifecycle/switch_observer.py +1 -0
  7. {comfygit_core-0.7.0 → comfygit_core-0.7.1}/src/comfygit_core/models/__init__.py +2 -0
  8. {comfygit_core-0.7.0 → comfygit_core-0.7.1}/src/comfygit_core/models/exceptions.py +22 -0
  9. {comfygit_core-0.7.0 → comfygit_core-0.7.1}/src/comfygit_core/models/manifest.py +7 -0
  10. {comfygit_core-0.7.0 → comfygit_core-0.7.1}/src/comfygit_core/services/credential_service.py +1 -0
  11. comfygit_core-0.7.1/src/comfygit_core/utils/environment_lock.py +196 -0
  12. {comfygit_core-0.7.0 → comfygit_core-0.7.1}/tests/unit/core/test_environment_operation_locking.py +8 -1
  13. comfygit_core-0.7.1/tests/unit/core/test_environment_shared_reads.py +85 -0
  14. comfygit_core-0.7.0/PKG-INFO +0 -521
  15. comfygit_core-0.7.0/README.md +0 -499
  16. comfygit_core-0.7.0/src/comfygit_core/utils/environment_lock.py +0 -111
  17. {comfygit_core-0.7.0 → comfygit_core-0.7.1}/.gitignore +0 -0
  18. {comfygit_core-0.7.0 → comfygit_core-0.7.1}/.python-version +0 -0
  19. {comfygit_core-0.7.0 → comfygit_core-0.7.1}/AGENTS.md +0 -0
  20. {comfygit_core-0.7.0 → comfygit_core-0.7.1}/CLAUDE.md +0 -0
  21. {comfygit_core-0.7.0 → comfygit_core-0.7.1}/LICENSE.txt +0 -0
  22. {comfygit_core-0.7.0 → comfygit_core-0.7.1}/docs/architecture-deep-dive.md +0 -0
  23. {comfygit_core-0.7.0 → comfygit_core-0.7.1}/docs/architecture.md +0 -0
  24. {comfygit_core-0.7.0 → comfygit_core-0.7.1}/docs/knowledge/comfyui-node-loader-base-directories.md +0 -0
  25. {comfygit_core-0.7.0 → comfygit_core-0.7.1}/docs/knowledge/model-tracking-system.md +0 -0
  26. {comfygit_core-0.7.0 → comfygit_core-0.7.1}/docs/knowledge/node-resolution-behavior.md +0 -0
  27. {comfygit_core-0.7.0 → comfygit_core-0.7.1}/docs/layer-hierarchy.md +0 -0
  28. {comfygit_core-0.7.0 → comfygit_core-0.7.1}/docs/plans/uv-overlay-system.md +0 -0
  29. {comfygit_core-0.7.0 → comfygit_core-0.7.1}/src/comfygit_core/__init__.py +0 -0
  30. {comfygit_core-0.7.0 → comfygit_core-0.7.1}/src/comfygit_core/analyzers/__init__.py +0 -0
  31. {comfygit_core-0.7.0 → comfygit_core-0.7.1}/src/comfygit_core/analyzers/config_comparison.py +0 -0
  32. {comfygit_core-0.7.0 → comfygit_core-0.7.1}/src/comfygit_core/analyzers/custom_node_scanner.py +0 -0
  33. {comfygit_core-0.7.0 → comfygit_core-0.7.1}/src/comfygit_core/analyzers/git_change_parser.py +0 -0
  34. {comfygit_core-0.7.0 → comfygit_core-0.7.1}/src/comfygit_core/analyzers/model_scanner.py +0 -0
  35. {comfygit_core-0.7.0 → comfygit_core-0.7.1}/src/comfygit_core/analyzers/node_classifier.py +0 -0
  36. {comfygit_core-0.7.0 → comfygit_core-0.7.1}/src/comfygit_core/analyzers/node_git_analyzer.py +0 -0
  37. {comfygit_core-0.7.0 → comfygit_core-0.7.1}/src/comfygit_core/analyzers/ref_diff_analyzer.py +0 -0
  38. {comfygit_core-0.7.0 → comfygit_core-0.7.1}/src/comfygit_core/analyzers/status_scanner.py +0 -0
  39. {comfygit_core-0.7.0 → comfygit_core-0.7.1}/src/comfygit_core/analyzers/unmanaged_comfyui_analyzer.py +0 -0
  40. {comfygit_core-0.7.0 → comfygit_core-0.7.1}/src/comfygit_core/analyzers/workflow_dependency_parser.py +0 -0
  41. {comfygit_core-0.7.0 → comfygit_core-0.7.1}/src/comfygit_core/assets.py +0 -0
  42. {comfygit_core-0.7.0 → comfygit_core-0.7.1}/src/comfygit_core/build_readiness.py +0 -0
  43. {comfygit_core-0.7.0 → comfygit_core-0.7.1}/src/comfygit_core/caching/__init__.py +0 -0
  44. {comfygit_core-0.7.0 → comfygit_core-0.7.1}/src/comfygit_core/caching/api_cache.py +0 -0
  45. {comfygit_core-0.7.0 → comfygit_core-0.7.1}/src/comfygit_core/caching/base.py +0 -0
  46. {comfygit_core-0.7.0 → comfygit_core-0.7.1}/src/comfygit_core/caching/comfyui_cache.py +0 -0
  47. {comfygit_core-0.7.0 → comfygit_core-0.7.1}/src/comfygit_core/caching/custom_node_cache.py +0 -0
  48. {comfygit_core-0.7.0 → comfygit_core-0.7.1}/src/comfygit_core/caching/workflow_cache.py +0 -0
  49. {comfygit_core-0.7.0 → comfygit_core-0.7.1}/src/comfygit_core/clients/__init__.py +0 -0
  50. {comfygit_core-0.7.0 → comfygit_core-0.7.1}/src/comfygit_core/clients/civitai_client.py +0 -0
  51. {comfygit_core-0.7.0 → comfygit_core-0.7.1}/src/comfygit_core/clients/github_client.py +0 -0
  52. {comfygit_core-0.7.0 → comfygit_core-0.7.1}/src/comfygit_core/clients/registry_client.py +0 -0
  53. {comfygit_core-0.7.0 → comfygit_core-0.7.1}/src/comfygit_core/configs/__init__.py +0 -0
  54. {comfygit_core-0.7.0 → comfygit_core-0.7.1}/src/comfygit_core/configs/comfyui_builtin_nodes.py +0 -0
  55. {comfygit_core-0.7.0 → comfygit_core-0.7.1}/src/comfygit_core/configs/comfyui_models.py +0 -0
  56. {comfygit_core-0.7.0 → comfygit_core-0.7.1}/src/comfygit_core/configs/model_config.py +0 -0
  57. {comfygit_core-0.7.0 → comfygit_core-0.7.1}/src/comfygit_core/configs/package_config.py +0 -0
  58. {comfygit_core-0.7.0 → comfygit_core-0.7.1}/src/comfygit_core/confirmation.py +0 -0
  59. {comfygit_core-0.7.0 → comfygit_core-0.7.1}/src/comfygit_core/constants.py +0 -0
  60. {comfygit_core-0.7.0 → comfygit_core-0.7.1}/src/comfygit_core/core/__init__.py +0 -0
  61. {comfygit_core-0.7.0 → comfygit_core-0.7.1}/src/comfygit_core/core/workspace.py +0 -0
  62. {comfygit_core-0.7.0 → comfygit_core-0.7.1}/src/comfygit_core/data/overlays/stock/sageattention.toml +0 -0
  63. {comfygit_core-0.7.0 → comfygit_core-0.7.1}/src/comfygit_core/data/overlays/stock/triton.toml +0 -0
  64. {comfygit_core-0.7.0 → comfygit_core-0.7.1}/src/comfygit_core/data/overlays/stock/xformers.toml +0 -0
  65. {comfygit_core-0.7.0 → comfygit_core-0.7.1}/src/comfygit_core/factories/__init__.py +0 -0
  66. {comfygit_core-0.7.0 → comfygit_core-0.7.1}/src/comfygit_core/factories/environment_factory.py +0 -0
  67. {comfygit_core-0.7.0 → comfygit_core-0.7.1}/src/comfygit_core/factories/uv_factory.py +0 -0
  68. {comfygit_core-0.7.0 → comfygit_core-0.7.1}/src/comfygit_core/factories/workspace_factory.py +0 -0
  69. {comfygit_core-0.7.0 → comfygit_core-0.7.1}/src/comfygit_core/git.py +0 -0
  70. {comfygit_core-0.7.0 → comfygit_core-0.7.1}/src/comfygit_core/imports.py +0 -0
  71. {comfygit_core-0.7.0 → comfygit_core-0.7.1}/src/comfygit_core/infrastructure/__init__.py +0 -0
  72. {comfygit_core-0.7.0 → comfygit_core-0.7.1}/src/comfygit_core/infrastructure/sqlite_manager.py +0 -0
  73. {comfygit_core-0.7.0 → comfygit_core-0.7.1}/src/comfygit_core/integrations/__init__.py +0 -0
  74. {comfygit_core-0.7.0 → comfygit_core-0.7.1}/src/comfygit_core/integrations/uv_command.py +0 -0
  75. {comfygit_core-0.7.0 → comfygit_core-0.7.1}/src/comfygit_core/lifecycle/__init__.py +0 -0
  76. {comfygit_core-0.7.0 → comfygit_core-0.7.1}/src/comfygit_core/lifecycle/comfyui_readiness.py +0 -0
  77. {comfygit_core-0.7.0 → comfygit_core-0.7.1}/src/comfygit_core/logging/__init__.py +0 -0
  78. {comfygit_core-0.7.0 → comfygit_core-0.7.1}/src/comfygit_core/logging/logging_config.py +0 -0
  79. {comfygit_core-0.7.0 → comfygit_core-0.7.1}/src/comfygit_core/managers/__init__.py +0 -0
  80. {comfygit_core-0.7.0 → comfygit_core-0.7.1}/src/comfygit_core/managers/environment_git_orchestrator.py +0 -0
  81. {comfygit_core-0.7.0 → comfygit_core-0.7.1}/src/comfygit_core/managers/environment_model_manager.py +0 -0
  82. {comfygit_core-0.7.0 → comfygit_core-0.7.1}/src/comfygit_core/managers/export_import_manager.py +0 -0
  83. {comfygit_core-0.7.0 → comfygit_core-0.7.1}/src/comfygit_core/managers/git_manager.py +0 -0
  84. {comfygit_core-0.7.0 → comfygit_core-0.7.1}/src/comfygit_core/managers/model_symlink_manager.py +0 -0
  85. {comfygit_core-0.7.0 → comfygit_core-0.7.1}/src/comfygit_core/managers/node_manager.py +0 -0
  86. {comfygit_core-0.7.0 → comfygit_core-0.7.1}/src/comfygit_core/managers/overlay_manager.py +0 -0
  87. {comfygit_core-0.7.0 → comfygit_core-0.7.1}/src/comfygit_core/managers/pyproject_manager.py +0 -0
  88. {comfygit_core-0.7.0 → comfygit_core-0.7.1}/src/comfygit_core/managers/pytorch_backend_manager.py +0 -0
  89. {comfygit_core-0.7.0 → comfygit_core-0.7.1}/src/comfygit_core/managers/system_node_symlink_manager.py +0 -0
  90. {comfygit_core-0.7.0 → comfygit_core-0.7.1}/src/comfygit_core/managers/user_content_symlink_manager.py +0 -0
  91. {comfygit_core-0.7.0 → comfygit_core-0.7.1}/src/comfygit_core/managers/uv_project_manager.py +0 -0
  92. {comfygit_core-0.7.0 → comfygit_core-0.7.1}/src/comfygit_core/managers/workflow_manager.py +0 -0
  93. {comfygit_core-0.7.0 → comfygit_core-0.7.1}/src/comfygit_core/manifest/__init__.py +0 -0
  94. {comfygit_core-0.7.0 → comfygit_core-0.7.1}/src/comfygit_core/manifest/base.py +0 -0
  95. {comfygit_core-0.7.0 → comfygit_core-0.7.1}/src/comfygit_core/manifest/dependencies.py +0 -0
  96. {comfygit_core-0.7.0 → comfygit_core-0.7.1}/src/comfygit_core/manifest/disposable_project.py +0 -0
  97. {comfygit_core-0.7.0 → comfygit_core-0.7.1}/src/comfygit_core/manifest/migrations.py +0 -0
  98. {comfygit_core-0.7.0 → comfygit_core-0.7.1}/src/comfygit_core/manifest/models.py +0 -0
  99. {comfygit_core-0.7.0 → comfygit_core-0.7.1}/src/comfygit_core/manifest/nodes.py +0 -0
  100. {comfygit_core-0.7.0 → comfygit_core-0.7.1}/src/comfygit_core/manifest/overlays.py +0 -0
  101. {comfygit_core-0.7.0 → comfygit_core-0.7.1}/src/comfygit_core/manifest/pyproject_manifest.py +0 -0
  102. {comfygit_core-0.7.0 → comfygit_core-0.7.1}/src/comfygit_core/manifest/store.py +0 -0
  103. {comfygit_core-0.7.0 → comfygit_core-0.7.1}/src/comfygit_core/manifest/sync_config.py +0 -0
  104. {comfygit_core-0.7.0 → comfygit_core-0.7.1}/src/comfygit_core/manifest/uv_config.py +0 -0
  105. {comfygit_core-0.7.0 → comfygit_core-0.7.1}/src/comfygit_core/manifest/workflows.py +0 -0
  106. {comfygit_core-0.7.0 → comfygit_core-0.7.1}/src/comfygit_core/merging/__init__.py +0 -0
  107. {comfygit_core-0.7.0 → comfygit_core-0.7.1}/src/comfygit_core/merging/atomic_executor.py +0 -0
  108. {comfygit_core-0.7.0 → comfygit_core-0.7.1}/src/comfygit_core/merging/merge_validator.py +0 -0
  109. {comfygit_core-0.7.0 → comfygit_core-0.7.1}/src/comfygit_core/merging/semantic_merger.py +0 -0
  110. {comfygit_core-0.7.0 → comfygit_core-0.7.1}/src/comfygit_core/models/build_readiness.py +0 -0
  111. {comfygit_core-0.7.0 → comfygit_core-0.7.1}/src/comfygit_core/models/civitai.py +0 -0
  112. {comfygit_core-0.7.0 → comfygit_core-0.7.1}/src/comfygit_core/models/comfyui_builtin_versions.py +0 -0
  113. {comfygit_core-0.7.0 → comfygit_core-0.7.1}/src/comfygit_core/models/commit.py +0 -0
  114. {comfygit_core-0.7.0 → comfygit_core-0.7.1}/src/comfygit_core/models/credentials.py +0 -0
  115. {comfygit_core-0.7.0 → comfygit_core-0.7.1}/src/comfygit_core/models/dependency_resolution.py +0 -0
  116. {comfygit_core-0.7.0 → comfygit_core-0.7.1}/src/comfygit_core/models/environment.py +0 -0
  117. {comfygit_core-0.7.0 → comfygit_core-0.7.1}/src/comfygit_core/models/git.py +0 -0
  118. {comfygit_core-0.7.0 → comfygit_core-0.7.1}/src/comfygit_core/models/lifecycle.py +0 -0
  119. {comfygit_core-0.7.0 → comfygit_core-0.7.1}/src/comfygit_core/models/materialization.py +0 -0
  120. {comfygit_core-0.7.0 → comfygit_core-0.7.1}/src/comfygit_core/models/merge_plan.py +0 -0
  121. {comfygit_core-0.7.0 → comfygit_core-0.7.1}/src/comfygit_core/models/model_scan.py +0 -0
  122. {comfygit_core-0.7.0 → comfygit_core-0.7.1}/src/comfygit_core/models/node_mapping.py +0 -0
  123. {comfygit_core-0.7.0 → comfygit_core-0.7.1}/src/comfygit_core/models/overlay.py +0 -0
  124. {comfygit_core-0.7.0 → comfygit_core-0.7.1}/src/comfygit_core/models/protocols.py +0 -0
  125. {comfygit_core-0.7.0 → comfygit_core-0.7.1}/src/comfygit_core/models/readiness.py +0 -0
  126. {comfygit_core-0.7.0 → comfygit_core-0.7.1}/src/comfygit_core/models/ref_diff.py +0 -0
  127. {comfygit_core-0.7.0 → comfygit_core-0.7.1}/src/comfygit_core/models/registry.py +0 -0
  128. {comfygit_core-0.7.0 → comfygit_core-0.7.1}/src/comfygit_core/models/resource_inventory.py +0 -0
  129. {comfygit_core-0.7.0 → comfygit_core-0.7.1}/src/comfygit_core/models/runtime_config.py +0 -0
  130. {comfygit_core-0.7.0 → comfygit_core-0.7.1}/src/comfygit_core/models/shared.py +0 -0
  131. {comfygit_core-0.7.0 → comfygit_core-0.7.1}/src/comfygit_core/models/sync.py +0 -0
  132. {comfygit_core-0.7.0 → comfygit_core-0.7.1}/src/comfygit_core/models/system.py +0 -0
  133. {comfygit_core-0.7.0 → comfygit_core-0.7.1}/src/comfygit_core/models/unmanaged_import.py +0 -0
  134. {comfygit_core-0.7.0 → comfygit_core-0.7.1}/src/comfygit_core/models/workflow.py +0 -0
  135. {comfygit_core-0.7.0 → comfygit_core-0.7.1}/src/comfygit_core/models/workflow_contract.py +0 -0
  136. {comfygit_core-0.7.0 → comfygit_core-0.7.1}/src/comfygit_core/models/workflow_execution.py +0 -0
  137. {comfygit_core-0.7.0 → comfygit_core-0.7.1}/src/comfygit_core/models/workspace_config.py +0 -0
  138. {comfygit_core-0.7.0 → comfygit_core-0.7.1}/src/comfygit_core/py.typed +0 -0
  139. {comfygit_core-0.7.0 → comfygit_core-0.7.1}/src/comfygit_core/readiness.py +0 -0
  140. {comfygit_core-0.7.0 → comfygit_core-0.7.1}/src/comfygit_core/repositories/__init__.py +0 -0
  141. {comfygit_core-0.7.0 → comfygit_core-0.7.1}/src/comfygit_core/repositories/comfyui_builtin_versions_repository.py +0 -0
  142. {comfygit_core-0.7.0 → comfygit_core-0.7.1}/src/comfygit_core/repositories/credential_store.py +0 -0
  143. {comfygit_core-0.7.0 → comfygit_core-0.7.1}/src/comfygit_core/repositories/migrate_paths.py +0 -0
  144. {comfygit_core-0.7.0 → comfygit_core-0.7.1}/src/comfygit_core/repositories/model_repository.py +0 -0
  145. {comfygit_core-0.7.0 → comfygit_core-0.7.1}/src/comfygit_core/repositories/node_mappings_repository.py +0 -0
  146. {comfygit_core-0.7.0 → comfygit_core-0.7.1}/src/comfygit_core/repositories/workflow_repository.py +0 -0
  147. {comfygit_core-0.7.0 → comfygit_core-0.7.1}/src/comfygit_core/repositories/workspace_config_repository.py +0 -0
  148. {comfygit_core-0.7.0 → comfygit_core-0.7.1}/src/comfygit_core/resolvers/__init__.py +0 -0
  149. {comfygit_core-0.7.0 → comfygit_core-0.7.1}/src/comfygit_core/resolvers/global_node_resolver.py +0 -0
  150. {comfygit_core-0.7.0 → comfygit_core-0.7.1}/src/comfygit_core/resolvers/model_resolver.py +0 -0
  151. {comfygit_core-0.7.0 → comfygit_core-0.7.1}/src/comfygit_core/runtime.py +0 -0
  152. {comfygit_core-0.7.0 → comfygit_core-0.7.1}/src/comfygit_core/security.py +0 -0
  153. {comfygit_core-0.7.0 → comfygit_core-0.7.1}/src/comfygit_core/services/__init__.py +0 -0
  154. {comfygit_core-0.7.0 → comfygit_core-0.7.1}/src/comfygit_core/services/build_readiness.py +0 -0
  155. {comfygit_core-0.7.0 → comfygit_core-0.7.1}/src/comfygit_core/services/dependency_resolution_preview.py +0 -0
  156. {comfygit_core-0.7.0 → comfygit_core-0.7.1}/src/comfygit_core/services/environment_lifecycle.py +0 -0
  157. {comfygit_core-0.7.0 → comfygit_core-0.7.1}/src/comfygit_core/services/environment_readiness.py +0 -0
  158. {comfygit_core-0.7.0 → comfygit_core-0.7.1}/src/comfygit_core/services/environment_sync_coordinator.py +0 -0
  159. {comfygit_core-0.7.0 → comfygit_core-0.7.1}/src/comfygit_core/services/huggingface_url.py +0 -0
  160. {comfygit_core-0.7.0 → comfygit_core-0.7.1}/src/comfygit_core/services/import_analyzer.py +0 -0
  161. {comfygit_core-0.7.0 → comfygit_core-0.7.1}/src/comfygit_core/services/model_downloader.py +0 -0
  162. {comfygit_core-0.7.0 → comfygit_core-0.7.1}/src/comfygit_core/services/model_source_lookup.py +0 -0
  163. {comfygit_core-0.7.0 → comfygit_core-0.7.1}/src/comfygit_core/services/node_lookup_service.py +0 -0
  164. {comfygit_core-0.7.0 → comfygit_core-0.7.1}/src/comfygit_core/services/registry_data_manager.py +0 -0
  165. {comfygit_core-0.7.0 → comfygit_core-0.7.1}/src/comfygit_core/services/resource_inventory.py +0 -0
  166. {comfygit_core-0.7.0 → comfygit_core-0.7.1}/src/comfygit_core/services/unmanaged_environment_import.py +0 -0
  167. {comfygit_core-0.7.0 → comfygit_core-0.7.1}/src/comfygit_core/services/workflow_analysis_cache.py +0 -0
  168. {comfygit_core-0.7.0 → comfygit_core-0.7.1}/src/comfygit_core/services/workflow_analysis_service.py +0 -0
  169. {comfygit_core-0.7.0 → comfygit_core-0.7.1}/src/comfygit_core/services/workflow_execution.py +0 -0
  170. {comfygit_core-0.7.0 → comfygit_core-0.7.1}/src/comfygit_core/services/workflow_file_store.py +0 -0
  171. {comfygit_core-0.7.0 → comfygit_core-0.7.1}/src/comfygit_core/services/workflow_input.py +0 -0
  172. {comfygit_core-0.7.0 → comfygit_core-0.7.1}/src/comfygit_core/services/workflow_manifest_reconciler.py +0 -0
  173. {comfygit_core-0.7.0 → comfygit_core-0.7.1}/src/comfygit_core/services/workflow_manual_model_policy.py +0 -0
  174. {comfygit_core-0.7.0 → comfygit_core-0.7.1}/src/comfygit_core/services/workflow_model_dependency_service.py +0 -0
  175. {comfygit_core-0.7.0 → comfygit_core-0.7.1}/src/comfygit_core/services/workflow_model_download_coordinator.py +0 -0
  176. {comfygit_core-0.7.0 → comfygit_core-0.7.1}/src/comfygit_core/services/workflow_model_path_policy.py +0 -0
  177. {comfygit_core-0.7.0 → comfygit_core-0.7.1}/src/comfygit_core/services/workflow_node_package_policy.py +0 -0
  178. {comfygit_core-0.7.0 → comfygit_core-0.7.1}/src/comfygit_core/services/workflow_resolution_context_builder.py +0 -0
  179. {comfygit_core-0.7.0 → comfygit_core-0.7.1}/src/comfygit_core/services/workflow_resolution_fixer.py +0 -0
  180. {comfygit_core-0.7.0 → comfygit_core-0.7.1}/src/comfygit_core/services/workflow_resolution_service.py +0 -0
  181. {comfygit_core-0.7.0 → comfygit_core-0.7.1}/src/comfygit_core/services/workflow_state_cleanup.py +0 -0
  182. {comfygit_core-0.7.0 → comfygit_core-0.7.1}/src/comfygit_core/strategies/__init__.py +0 -0
  183. {comfygit_core-0.7.0 → comfygit_core-0.7.1}/src/comfygit_core/strategies/auto.py +0 -0
  184. {comfygit_core-0.7.0 → comfygit_core-0.7.1}/src/comfygit_core/strategies/confirmation.py +0 -0
  185. {comfygit_core-0.7.0 → comfygit_core-0.7.1}/src/comfygit_core/utils/__init__.py +0 -0
  186. {comfygit_core-0.7.0 → comfygit_core-0.7.1}/src/comfygit_core/utils/builtin_extractor.py +0 -0
  187. {comfygit_core-0.7.0 → comfygit_core-0.7.1}/src/comfygit_core/utils/comfyui_ops.py +0 -0
  188. {comfygit_core-0.7.0 → comfygit_core-0.7.1}/src/comfygit_core/utils/common.py +0 -0
  189. {comfygit_core-0.7.0 → comfygit_core-0.7.1}/src/comfygit_core/utils/conflict_analyzer.py +0 -0
  190. {comfygit_core-0.7.0 → comfygit_core-0.7.1}/src/comfygit_core/utils/conflict_parser.py +0 -0
  191. {comfygit_core-0.7.0 → comfygit_core-0.7.1}/src/comfygit_core/utils/dependency_parser.py +0 -0
  192. {comfygit_core-0.7.0 → comfygit_core-0.7.1}/src/comfygit_core/utils/dependency_probe.py +0 -0
  193. {comfygit_core-0.7.0 → comfygit_core-0.7.1}/src/comfygit_core/utils/download.py +0 -0
  194. {comfygit_core-0.7.0 → comfygit_core-0.7.1}/src/comfygit_core/utils/environment_cleanup.py +0 -0
  195. {comfygit_core-0.7.0 → comfygit_core-0.7.1}/src/comfygit_core/utils/filesystem.py +0 -0
  196. {comfygit_core-0.7.0 → comfygit_core-0.7.1}/src/comfygit_core/utils/folder_paths_extractor.py +0 -0
  197. {comfygit_core-0.7.0 → comfygit_core-0.7.1}/src/comfygit_core/utils/git.py +0 -0
  198. {comfygit_core-0.7.0 → comfygit_core-0.7.1}/src/comfygit_core/utils/input_signature.py +0 -0
  199. {comfygit_core-0.7.0 → comfygit_core-0.7.1}/src/comfygit_core/utils/model_categories.py +0 -0
  200. {comfygit_core-0.7.0 → comfygit_core-0.7.1}/src/comfygit_core/utils/model_loader_extractor.py +0 -0
  201. {comfygit_core-0.7.0 → comfygit_core-0.7.1}/src/comfygit_core/utils/node_identity.py +0 -0
  202. {comfygit_core-0.7.0 → comfygit_core-0.7.1}/src/comfygit_core/utils/provider_urls.py +0 -0
  203. {comfygit_core-0.7.0 → comfygit_core-0.7.1}/src/comfygit_core/utils/pytorch.py +0 -0
  204. {comfygit_core-0.7.0 → comfygit_core-0.7.1}/src/comfygit_core/utils/pytorch_prober.py +0 -0
  205. {comfygit_core-0.7.0 → comfygit_core-0.7.1}/src/comfygit_core/utils/redaction.py +0 -0
  206. {comfygit_core-0.7.0 → comfygit_core-0.7.1}/src/comfygit_core/utils/requirements.py +0 -0
  207. {comfygit_core-0.7.0 → comfygit_core-0.7.1}/src/comfygit_core/utils/retry.py +0 -0
  208. {comfygit_core-0.7.0 → comfygit_core-0.7.1}/src/comfygit_core/utils/symlink_utils.py +0 -0
  209. {comfygit_core-0.7.0 → comfygit_core-0.7.1}/src/comfygit_core/utils/system_detector.py +0 -0
  210. {comfygit_core-0.7.0 → comfygit_core-0.7.1}/src/comfygit_core/utils/toml_compat.py +0 -0
  211. {comfygit_core-0.7.0 → comfygit_core-0.7.1}/src/comfygit_core/utils/uuid.py +0 -0
  212. {comfygit_core-0.7.0 → comfygit_core-0.7.1}/src/comfygit_core/utils/uv_error_handler.py +0 -0
  213. {comfygit_core-0.7.0 → comfygit_core-0.7.1}/src/comfygit_core/utils/version.py +0 -0
  214. {comfygit_core-0.7.0 → comfygit_core-0.7.1}/src/comfygit_core/utils/workflow_hash.py +0 -0
  215. {comfygit_core-0.7.0 → comfygit_core-0.7.1}/src/comfygit_core/validation/__init__.py +0 -0
  216. {comfygit_core-0.7.0 → comfygit_core-0.7.1}/src/comfygit_core/validation/resolution_tester.py +0 -0
  217. {comfygit_core-0.7.0 → comfygit_core-0.7.1}/src/comfygit_core/workflow.py +0 -0
  218. {comfygit_core-0.7.0 → comfygit_core-0.7.1}/tests/README.md +0 -0
  219. {comfygit_core-0.7.0 → comfygit_core-0.7.1}/tests/caching/TEST_REDUCTION_SUMMARY.md +0 -0
  220. {comfygit_core-0.7.0 → comfygit_core-0.7.1}/tests/caching/__init__.py +0 -0
  221. {comfygit_core-0.7.0 → comfygit_core-0.7.1}/tests/caching/test_workflow_cache.py +0 -0
  222. {comfygit_core-0.7.0 → comfygit_core-0.7.1}/tests/caching/test_workflow_cache_context_hash.py +0 -0
  223. {comfygit_core-0.7.0 → comfygit_core-0.7.1}/tests/conftest.py +0 -0
  224. {comfygit_core-0.7.0 → comfygit_core-0.7.1}/tests/fixtures/models/test_models.json +0 -0
  225. {comfygit_core-0.7.0 → comfygit_core-0.7.1}/tests/fixtures/workflows/checkpoint_loader_with_missing_model.json +0 -0
  226. {comfygit_core-0.7.0 → comfygit_core-0.7.1}/tests/fixtures/workflows/kjnodes_workflow.json +0 -0
  227. {comfygit_core-0.7.0 → comfygit_core-0.7.1}/tests/fixtures/workflows/simple_txt2img.json +0 -0
  228. {comfygit_core-0.7.0 → comfygit_core-0.7.1}/tests/fixtures/workflows/with_custom_node.json +0 -0
  229. {comfygit_core-0.7.0 → comfygit_core-0.7.1}/tests/fixtures/workflows/with_missing_model.json +0 -0
  230. {comfygit_core-0.7.0 → comfygit_core-0.7.1}/tests/fixtures/workflows/workflow_with_duplicates.json +0 -0
  231. {comfygit_core-0.7.0 → comfygit_core-0.7.1}/tests/fixtures/workflows/workflow_with_properties.json +0 -0
  232. {comfygit_core-0.7.0 → comfygit_core-0.7.1}/tests/fixtures/workflows/workflow_without_properties.json +0 -0
  233. {comfygit_core-0.7.0 → comfygit_core-0.7.1}/tests/helpers/__init__.py +0 -0
  234. {comfygit_core-0.7.0 → comfygit_core-0.7.1}/tests/helpers/model_index_builder.py +0 -0
  235. {comfygit_core-0.7.0 → comfygit_core-0.7.1}/tests/helpers/pyproject_assertions.py +0 -0
  236. {comfygit_core-0.7.0 → comfygit_core-0.7.1}/tests/helpers/workflow_builder.py +0 -0
  237. {comfygit_core-0.7.0 → comfygit_core-0.7.1}/tests/integration/test_atomic_semantic_merge.py +0 -0
  238. {comfygit_core-0.7.0 → comfygit_core-0.7.1}/tests/integration/test_auto_model_index_sync.py +0 -0
  239. {comfygit_core-0.7.0 → comfygit_core-0.7.1}/tests/integration/test_branch_workflow_preservation.py +0 -0
  240. {comfygit_core-0.7.0 → comfygit_core-0.7.1}/tests/integration/test_cache_invalidation_on_model_deletion.py +0 -0
  241. {comfygit_core-0.7.0 → comfygit_core-0.7.1}/tests/integration/test_cache_node_version_invalidation.py +0 -0
  242. {comfygit_core-0.7.0 → comfygit_core-0.7.1}/tests/integration/test_checkout_b_with_modified_workflow.py +0 -0
  243. {comfygit_core-0.7.0 → comfygit_core-0.7.1}/tests/integration/test_commit_git_changes.py +0 -0
  244. {comfygit_core-0.7.0 → comfygit_core-0.7.1}/tests/integration/test_commit_git_changes_SUMMARY.md +0 -0
  245. {comfygit_core-0.7.0 → comfygit_core-0.7.1}/tests/integration/test_commit_history.py +0 -0
  246. {comfygit_core-0.7.0 → comfygit_core-0.7.1}/tests/integration/test_context_aware_node_resolution.py +0 -0
  247. {comfygit_core-0.7.0 → comfygit_core-0.7.1}/tests/integration/test_create_with_version_spec.py +0 -0
  248. {comfygit_core-0.7.0 → comfygit_core-0.7.1}/tests/integration/test_custom_node_path_preservation.py +0 -0
  249. {comfygit_core-0.7.0 → comfygit_core-0.7.1}/tests/integration/test_deferred_model_downloads.py +0 -0
  250. {comfygit_core-0.7.0 → comfygit_core-0.7.1}/tests/integration/test_deleted_model_download_intent.py +0 -0
  251. {comfygit_core-0.7.0 → comfygit_core-0.7.1}/tests/integration/test_dependency_group_removal.py +0 -0
  252. {comfygit_core-0.7.0 → comfygit_core-0.7.1}/tests/integration/test_dev_node_git_references.py +0 -0
  253. {comfygit_core-0.7.0 → comfygit_core-0.7.1}/tests/integration/test_dev_node_improvements.py +0 -0
  254. {comfygit_core-0.7.0 → comfygit_core-0.7.1}/tests/integration/test_download_cleanup.py +0 -0
  255. {comfygit_core-0.7.0 → comfygit_core-0.7.1}/tests/integration/test_download_intent_cache_invalidation.py +0 -0
  256. {comfygit_core-0.7.0 → comfygit_core-0.7.1}/tests/integration/test_environment_basic.py +0 -0
  257. {comfygit_core-0.7.0 → comfygit_core-0.7.1}/tests/integration/test_environment_branching.py +0 -0
  258. {comfygit_core-0.7.0 → comfygit_core-0.7.1}/tests/integration/test_environment_create_progress.py +0 -0
  259. {comfygit_core-0.7.0 → comfygit_core-0.7.1}/tests/integration/test_export_import.py +0 -0
  260. {comfygit_core-0.7.0 → comfygit_core-0.7.1}/tests/integration/test_git_branching.py +0 -0
  261. {comfygit_core-0.7.0 → comfygit_core-0.7.1}/tests/integration/test_git_import.py +0 -0
  262. {comfygit_core-0.7.0 → comfygit_core-0.7.1}/tests/integration/test_git_pull_push.py +0 -0
  263. {comfygit_core-0.7.0 → comfygit_core-0.7.1}/tests/integration/test_git_remote.py +0 -0
  264. {comfygit_core-0.7.0 → comfygit_core-0.7.1}/tests/integration/test_git_subdirectory_import.py +0 -0
  265. {comfygit_core-0.7.0 → comfygit_core-0.7.1}/tests/integration/test_import_auto_remote.py +0 -0
  266. {comfygit_core-0.7.0 → comfygit_core-0.7.1}/tests/integration/test_import_comfyui_version_bug.py +0 -0
  267. {comfygit_core-0.7.0 → comfygit_core-0.7.1}/tests/integration/test_import_preview.py +0 -0
  268. {comfygit_core-0.7.0 → comfygit_core-0.7.1}/tests/integration/test_lifecycle_status.py +0 -0
  269. {comfygit_core-0.7.0 → comfygit_core-0.7.1}/tests/integration/test_model_category_mismatch_detection.py +0 -0
  270. {comfygit_core-0.7.0 → comfygit_core-0.7.1}/tests/integration/test_model_directory_switch.py +0 -0
  271. {comfygit_core-0.7.0 → comfygit_core-0.7.1}/tests/integration/test_model_download_integration.py +0 -0
  272. {comfygit_core-0.7.0 → comfygit_core-0.7.1}/tests/integration/test_model_index_mismatch_bug_SUMMARY.md +0 -0
  273. {comfygit_core-0.7.0 → comfygit_core-0.7.1}/tests/integration/test_model_path_sync_detection.py +0 -0
  274. {comfygit_core-0.7.0 → comfygit_core-0.7.1}/tests/integration/test_model_resolution_stale_directory.py +0 -0
  275. {comfygit_core-0.7.0 → comfygit_core-0.7.1}/tests/integration/test_model_show_command.py +0 -0
  276. {comfygit_core-0.7.0 → comfygit_core-0.7.1}/tests/integration/test_model_source_management.py +0 -0
  277. {comfygit_core-0.7.0 → comfygit_core-0.7.1}/tests/integration/test_model_source_preservation.py +0 -0
  278. {comfygit_core-0.7.0 → comfygit_core-0.7.1}/tests/integration/test_model_source_preservation_SUMMARY.md +0 -0
  279. {comfygit_core-0.7.0 → comfygit_core-0.7.1}/tests/integration/test_model_source_removal.py +0 -0
  280. {comfygit_core-0.7.0 → comfygit_core-0.7.1}/tests/integration/test_multiple_optional_group_failures.py +0 -0
  281. {comfygit_core-0.7.0 → comfygit_core-0.7.1}/tests/integration/test_node_prune.py +0 -0
  282. {comfygit_core-0.7.0 → comfygit_core-0.7.1}/tests/integration/test_node_version_replacement.py +0 -0
  283. {comfygit_core-0.7.0 → comfygit_core-0.7.1}/tests/integration/test_opencv_conflict_resolution.py +0 -0
  284. {comfygit_core-0.7.0 → comfygit_core-0.7.1}/tests/integration/test_optional_dependency_groups.py +0 -0
  285. {comfygit_core-0.7.0 → comfygit_core-0.7.1}/tests/integration/test_overlay_e2e.py +0 -0
  286. {comfygit_core-0.7.0 → comfygit_core-0.7.1}/tests/integration/test_overlay_git_integration.py +0 -0
  287. {comfygit_core-0.7.0 → comfygit_core-0.7.1}/tests/integration/test_overlay_system_integration.py +0 -0
  288. {comfygit_core-0.7.0 → comfygit_core-0.7.1}/tests/integration/test_package_config.py +0 -0
  289. {comfygit_core-0.7.0 → comfygit_core-0.7.1}/tests/integration/test_per_environment_manager.py +0 -0
  290. {comfygit_core-0.7.0 → comfygit_core-0.7.1}/tests/integration/test_pyproject_batch_writes.py +0 -0
  291. {comfygit_core-0.7.0 → comfygit_core-0.7.1}/tests/integration/test_pytorch_reconfiguration.py +0 -0
  292. {comfygit_core-0.7.0 → comfygit_core-0.7.1}/tests/integration/test_registry_git_fallback.py +0 -0
  293. {comfygit_core-0.7.0 → comfygit_core-0.7.1}/tests/integration/test_registry_node_update_empty_download_url.py +0 -0
  294. {comfygit_core-0.7.0 → comfygit_core-0.7.1}/tests/integration/test_repair_completion_marker.py +0 -0
  295. {comfygit_core-0.7.0 → comfygit_core-0.7.1}/tests/integration/test_repair_model_download.py +0 -0
  296. {comfygit_core-0.7.0 → comfygit_core-0.7.1}/tests/integration/test_repair_node_removal.py +0 -0
  297. {comfygit_core-0.7.0 → comfygit_core-0.7.1}/tests/integration/test_repair_workflow.py +0 -0
  298. {comfygit_core-0.7.0 → comfygit_core-0.7.1}/tests/integration/test_requirements_inline_comments_bug.py +0 -0
  299. {comfygit_core-0.7.0 → comfygit_core-0.7.1}/tests/integration/test_runtime_restart_workflow_preservation.py +0 -0
  300. {comfygit_core-0.7.0 → comfygit_core-0.7.1}/tests/integration/test_status_abstraction.py +0 -0
  301. {comfygit_core-0.7.0 → comfygit_core-0.7.1}/tests/integration/test_status_uninstalled_nodes.py +0 -0
  302. {comfygit_core-0.7.0 → comfygit_core-0.7.1}/tests/integration/test_workflow_cache_metadata_invalidation.py +0 -0
  303. {comfygit_core-0.7.0 → comfygit_core-0.7.1}/tests/integration/test_workflow_caching_integration.py +0 -0
  304. {comfygit_core-0.7.0 → comfygit_core-0.7.1}/tests/integration/test_workflow_commit_flow.py +0 -0
  305. {comfygit_core-0.7.0 → comfygit_core-0.7.1}/tests/integration/test_workflow_deletion_cleanup.py +0 -0
  306. {comfygit_core-0.7.0 → comfygit_core-0.7.1}/tests/integration/test_workflow_model_criticality_update.py +0 -0
  307. {comfygit_core-0.7.0 → comfygit_core-0.7.1}/tests/integration/test_workflow_path_update_after_interactive_resolution.py +0 -0
  308. {comfygit_core-0.7.0 → comfygit_core-0.7.1}/tests/integration/test_workflow_resolution_cleanup.py +0 -0
  309. {comfygit_core-0.7.0 → comfygit_core-0.7.1}/tests/integration/test_workflow_resolution_pipeline.py +0 -0
  310. {comfygit_core-0.7.0 → comfygit_core-0.7.1}/tests/integration/test_workflow_resolve_install.py +0 -0
  311. {comfygit_core-0.7.0 → comfygit_core-0.7.1}/tests/integration/test_workflow_subgraph_resolution.py +0 -0
  312. {comfygit_core-0.7.0 → comfygit_core-0.7.1}/tests/test_architecture_boundaries.py +0 -0
  313. {comfygit_core-0.7.0 → comfygit_core-0.7.1}/tests/test_public_api.py +0 -0
  314. {comfygit_core-0.7.0 → comfygit_core-0.7.1}/tests/unit/analyzers/test_config_comparison.py +0 -0
  315. {comfygit_core-0.7.0 → comfygit_core-0.7.1}/tests/unit/analyzers/test_custom_node_scanner.py +0 -0
  316. {comfygit_core-0.7.0 → comfygit_core-0.7.1}/tests/unit/analyzers/test_model_scanner_symlinks.py +0 -0
  317. {comfygit_core-0.7.0 → comfygit_core-0.7.1}/tests/unit/analyzers/test_node_git_analyzer.py +0 -0
  318. {comfygit_core-0.7.0 → comfygit_core-0.7.1}/tests/unit/analyzers/test_ref_diff_analyzer.py +0 -0
  319. {comfygit_core-0.7.0 → comfygit_core-0.7.1}/tests/unit/analyzers/test_status_scanner.py +0 -0
  320. {comfygit_core-0.7.0 → comfygit_core-0.7.1}/tests/unit/analyzers/test_status_scanner_disabled_nodes.py +0 -0
  321. {comfygit_core-0.7.0 → comfygit_core-0.7.1}/tests/unit/analyzers/test_status_scanner_package_sync.py +0 -0
  322. {comfygit_core-0.7.0 → comfygit_core-0.7.1}/tests/unit/analyzers/test_workflow_dependency_parser.py +0 -0
  323. {comfygit_core-0.7.0 → comfygit_core-0.7.1}/tests/unit/caching/test_cache_base.py +0 -0
  324. {comfygit_core-0.7.0 → comfygit_core-0.7.1}/tests/unit/caching/test_comfyui_cache.py +0 -0
  325. {comfygit_core-0.7.0 → comfygit_core-0.7.1}/tests/unit/caching/test_custom_node_cache_refactor.py +0 -0
  326. {comfygit_core-0.7.0 → comfygit_core-0.7.1}/tests/unit/caching/test_workspace_relative_caching.py +0 -0
  327. {comfygit_core-0.7.0 → comfygit_core-0.7.1}/tests/unit/clients/test_civitai_client.py +0 -0
  328. {comfygit_core-0.7.0 → comfygit_core-0.7.1}/tests/unit/clients/test_civitai_parsing.py +0 -0
  329. {comfygit_core-0.7.0 → comfygit_core-0.7.1}/tests/unit/clients/test_github_releases.py +0 -0
  330. {comfygit_core-0.7.0 → comfygit_core-0.7.1}/tests/unit/configs/__init__.py +0 -0
  331. {comfygit_core-0.7.0 → comfygit_core-0.7.1}/tests/unit/configs/test_package_config.py +0 -0
  332. {comfygit_core-0.7.0 → comfygit_core-0.7.1}/tests/unit/core/test_environment_facades.py +0 -0
  333. {comfygit_core-0.7.0 → comfygit_core-0.7.1}/tests/unit/core/test_environment_run.py +0 -0
  334. {comfygit_core-0.7.0 → comfygit_core-0.7.1}/tests/unit/core/test_environment_sync.py +0 -0
  335. {comfygit_core-0.7.0 → comfygit_core-0.7.1}/tests/unit/core/test_environment_uninstalled_nodes.py +0 -0
  336. {comfygit_core-0.7.0 → comfygit_core-0.7.1}/tests/unit/core/test_import_download_failures.py +0 -0
  337. {comfygit_core-0.7.0 → comfygit_core-0.7.1}/tests/unit/core/test_import_no_manager.py +0 -0
  338. {comfygit_core-0.7.0 → comfygit_core-0.7.1}/tests/unit/core/test_reserved_environment_names.py +0 -0
  339. {comfygit_core-0.7.0 → comfygit_core-0.7.1}/tests/unit/core/test_sync_node_dependency_provisioning.py +0 -0
  340. {comfygit_core-0.7.0 → comfygit_core-0.7.1}/tests/unit/core/test_workflow_contract_access.py +0 -0
  341. {comfygit_core-0.7.0 → comfygit_core-0.7.1}/tests/unit/core/test_workspace_environment_creation.py +0 -0
  342. {comfygit_core-0.7.0 → comfygit_core-0.7.1}/tests/unit/core/test_workspace_model_delete.py +0 -0
  343. {comfygit_core-0.7.0 → comfygit_core-0.7.1}/tests/unit/factories/test_environment_factory_manager_install.py +0 -0
  344. {comfygit_core-0.7.0 → comfygit_core-0.7.1}/tests/unit/lifecycle/test_comfyui_readiness.py +0 -0
  345. {comfygit_core-0.7.0 → comfygit_core-0.7.1}/tests/unit/managers/test_environment_model_manager.py +0 -0
  346. {comfygit_core-0.7.0 → comfygit_core-0.7.1}/tests/unit/managers/test_export_import_overlays.py +0 -0
  347. {comfygit_core-0.7.0 → comfygit_core-0.7.1}/tests/unit/managers/test_git_manager_gitignore.py +0 -0
  348. {comfygit_core-0.7.0 → comfygit_core-0.7.1}/tests/unit/managers/test_git_manager_log_refs.py +0 -0
  349. {comfygit_core-0.7.0 → comfygit_core-0.7.1}/tests/unit/managers/test_model_index_manager.py +0 -0
  350. {comfygit_core-0.7.0 → comfygit_core-0.7.1}/tests/unit/managers/test_model_short_hash.py +0 -0
  351. {comfygit_core-0.7.0 → comfygit_core-0.7.1}/tests/unit/managers/test_node_conflict_detection.py +0 -0
  352. {comfygit_core-0.7.0 → comfygit_core-0.7.1}/tests/unit/managers/test_node_manager.py +0 -0
  353. {comfygit_core-0.7.0 → comfygit_core-0.7.1}/tests/unit/managers/test_overlay_fuzz.py +0 -0
  354. {comfygit_core-0.7.0 → comfygit_core-0.7.1}/tests/unit/managers/test_overlay_manager.py +0 -0
  355. {comfygit_core-0.7.0 → comfygit_core-0.7.1}/tests/unit/managers/test_overlay_materialization.py +0 -0
  356. {comfygit_core-0.7.0 → comfygit_core-0.7.1}/tests/unit/managers/test_pyproject_manager.py +0 -0
  357. {comfygit_core-0.7.0 → comfygit_core-0.7.1}/tests/unit/managers/test_pyproject_schema_version.py +0 -0
  358. {comfygit_core-0.7.0 → comfygit_core-0.7.1}/tests/unit/managers/test_pytorch_backend_manager.py +0 -0
  359. {comfygit_core-0.7.0 → comfygit_core-0.7.1}/tests/unit/managers/test_pytorch_overlay_materialization.py +0 -0
  360. {comfygit_core-0.7.0 → comfygit_core-0.7.1}/tests/unit/managers/test_pytorch_stripping.py +0 -0
  361. {comfygit_core-0.7.0 → comfygit_core-0.7.1}/tests/unit/managers/test_sqlite_manager.py +0 -0
  362. {comfygit_core-0.7.0 → comfygit_core-0.7.1}/tests/unit/managers/test_uv_no_build_isolation.py +0 -0
  363. {comfygit_core-0.7.0 → comfygit_core-0.7.1}/tests/unit/managers/test_workflow_manager.py +0 -0
  364. {comfygit_core-0.7.0 → comfygit_core-0.7.1}/tests/unit/managers/test_workflow_node_cleanup.py +0 -0
  365. {comfygit_core-0.7.0 → comfygit_core-0.7.1}/tests/unit/managers/test_workflow_status.py +0 -0
  366. {comfygit_core-0.7.0 → comfygit_core-0.7.1}/tests/unit/merging/__init__.py +0 -0
  367. {comfygit_core-0.7.0 → comfygit_core-0.7.1}/tests/unit/merging/test_atomic_executor.py +0 -0
  368. {comfygit_core-0.7.0 → comfygit_core-0.7.1}/tests/unit/merging/test_merge_validator.py +0 -0
  369. {comfygit_core-0.7.0 → comfygit_core-0.7.1}/tests/unit/merging/test_semantic_merger.py +0 -0
  370. {comfygit_core-0.7.0 → comfygit_core-0.7.1}/tests/unit/models/test_comfyui_builtin_versions.py +0 -0
  371. {comfygit_core-0.7.0 → comfygit_core-0.7.1}/tests/unit/models/test_lifecycle.py +0 -0
  372. {comfygit_core-0.7.0 → comfygit_core-0.7.1}/tests/unit/models/test_overlay.py +0 -0
  373. {comfygit_core-0.7.0 → comfygit_core-0.7.1}/tests/unit/models/test_ref_diff.py +0 -0
  374. {comfygit_core-0.7.0 → comfygit_core-0.7.1}/tests/unit/models/test_workflow_contract.py +0 -0
  375. {comfygit_core-0.7.0 → comfygit_core-0.7.1}/tests/unit/models/test_workflow_dependencies.py +0 -0
  376. {comfygit_core-0.7.0 → comfygit_core-0.7.1}/tests/unit/models/test_workflow_roundtrip.py +0 -0
  377. {comfygit_core-0.7.0 → comfygit_core-0.7.1}/tests/unit/models/test_workflow_subgraph.py +0 -0
  378. {comfygit_core-0.7.0 → comfygit_core-0.7.1}/tests/unit/repositories/test_credential_store.py +0 -0
  379. {comfygit_core-0.7.0 → comfygit_core-0.7.1}/tests/unit/resolvers/test_global_node_resolver_v2.py +0 -0
  380. {comfygit_core-0.7.0 → comfygit_core-0.7.1}/tests/unit/resolvers/test_model_resolver.py +0 -0
  381. {comfygit_core-0.7.0 → comfygit_core-0.7.1}/tests/unit/services/test_build_readiness.py +0 -0
  382. {comfygit_core-0.7.0 → comfygit_core-0.7.1}/tests/unit/services/test_credential_service.py +0 -0
  383. {comfygit_core-0.7.0 → comfygit_core-0.7.1}/tests/unit/services/test_dependency_resolution_preview.py +0 -0
  384. {comfygit_core-0.7.0 → comfygit_core-0.7.1}/tests/unit/services/test_environment_lifecycle.py +0 -0
  385. {comfygit_core-0.7.0 → comfygit_core-0.7.1}/tests/unit/services/test_environment_model_requirements.py +0 -0
  386. {comfygit_core-0.7.0 → comfygit_core-0.7.1}/tests/unit/services/test_environment_readiness.py +0 -0
  387. {comfygit_core-0.7.0 → comfygit_core-0.7.1}/tests/unit/services/test_global_node_resolver.py +0 -0
  388. {comfygit_core-0.7.0 → comfygit_core-0.7.1}/tests/unit/services/test_huggingface_url.py +0 -0
  389. {comfygit_core-0.7.0 → comfygit_core-0.7.1}/tests/unit/services/test_import_analyzer.py +0 -0
  390. {comfygit_core-0.7.0 → comfygit_core-0.7.1}/tests/unit/services/test_model_downloader.py +0 -0
  391. {comfygit_core-0.7.0 → comfygit_core-0.7.1}/tests/unit/services/test_model_source_lookup.py +0 -0
  392. {comfygit_core-0.7.0 → comfygit_core-0.7.1}/tests/unit/services/test_node_lookup_api_first.py +0 -0
  393. {comfygit_core-0.7.0 → comfygit_core-0.7.1}/tests/unit/services/test_node_lookup_version_fallback.py +0 -0
  394. {comfygit_core-0.7.0 → comfygit_core-0.7.1}/tests/unit/services/test_registry_data_manager.py +0 -0
  395. {comfygit_core-0.7.0 → comfygit_core-0.7.1}/tests/unit/services/test_resource_inventory.py +0 -0
  396. {comfygit_core-0.7.0 → comfygit_core-0.7.1}/tests/unit/services/test_scan_requirements_substitution.py +0 -0
  397. {comfygit_core-0.7.0 → comfygit_core-0.7.1}/tests/unit/services/test_unmanaged_environment_import.py +0 -0
  398. {comfygit_core-0.7.0 → comfygit_core-0.7.1}/tests/unit/services/test_workflow_analysis_cache.py +0 -0
  399. {comfygit_core-0.7.0 → comfygit_core-0.7.1}/tests/unit/services/test_workflow_analysis_service.py +0 -0
  400. {comfygit_core-0.7.0 → comfygit_core-0.7.1}/tests/unit/services/test_workflow_execution.py +0 -0
  401. {comfygit_core-0.7.0 → comfygit_core-0.7.1}/tests/unit/services/test_workflow_file_store.py +0 -0
  402. {comfygit_core-0.7.0 → comfygit_core-0.7.1}/tests/unit/services/test_workflow_input.py +0 -0
  403. {comfygit_core-0.7.0 → comfygit_core-0.7.1}/tests/unit/services/test_workflow_model_dependency_service.py +0 -0
  404. {comfygit_core-0.7.0 → comfygit_core-0.7.1}/tests/unit/services/test_workflow_model_download_coordinator.py +0 -0
  405. {comfygit_core-0.7.0 → comfygit_core-0.7.1}/tests/unit/services/test_workflow_model_path_policy.py +0 -0
  406. {comfygit_core-0.7.0 → comfygit_core-0.7.1}/tests/unit/services/test_workflow_resolution_context_builder.py +0 -0
  407. {comfygit_core-0.7.0 → comfygit_core-0.7.1}/tests/unit/services/test_workflow_resolution_fixer.py +0 -0
  408. {comfygit_core-0.7.0 → comfygit_core-0.7.1}/tests/unit/services/test_workflow_resolution_service.py +0 -0
  409. {comfygit_core-0.7.0 → comfygit_core-0.7.1}/tests/unit/services/test_workflow_state_cleanup.py +0 -0
  410. {comfygit_core-0.7.0 → comfygit_core-0.7.1}/tests/unit/test_add_dependencies_substitution.py +0 -0
  411. {comfygit_core-0.7.0 → comfygit_core-0.7.1}/tests/unit/test_auto_strategies.py +0 -0
  412. {comfygit_core-0.7.0 → comfygit_core-0.7.1}/tests/unit/test_builtin_extractor.py +0 -0
  413. {comfygit_core-0.7.0 → comfygit_core-0.7.1}/tests/unit/test_dev_node_rename_detection.py +0 -0
  414. {comfygit_core-0.7.0 → comfygit_core-0.7.1}/tests/unit/test_environment_py_dependencies.py +0 -0
  415. {comfygit_core-0.7.0 → comfygit_core-0.7.1}/tests/unit/test_external_uv_cache.py +0 -0
  416. {comfygit_core-0.7.0 → comfygit_core-0.7.1}/tests/unit/test_folder_paths_extractor.py +0 -0
  417. {comfygit_core-0.7.0 → comfygit_core-0.7.1}/tests/unit/test_github_auth_config.py +0 -0
  418. {comfygit_core-0.7.0 → comfygit_core-0.7.1}/tests/unit/test_github_url_installation.py +0 -0
  419. {comfygit_core-0.7.0 → comfygit_core-0.7.1}/tests/unit/test_headless_import.py +0 -0
  420. {comfygit_core-0.7.0 → comfygit_core-0.7.1}/tests/unit/test_materialization.py +0 -0
  421. {comfygit_core-0.7.0 → comfygit_core-0.7.1}/tests/unit/test_minimal_schema_compatibility.py +0 -0
  422. {comfygit_core-0.7.0 → comfygit_core-0.7.1}/tests/unit/test_model_config_dynamic_loading.py +0 -0
  423. {comfygit_core-0.7.0 → comfygit_core-0.7.1}/tests/unit/test_model_downloader_errors.py +0 -0
  424. {comfygit_core-0.7.0 → comfygit_core-0.7.1}/tests/unit/test_model_loader_extractor.py +0 -0
  425. {comfygit_core-0.7.0 → comfygit_core-0.7.1}/tests/unit/test_model_repository_cleanup.py +0 -0
  426. {comfygit_core-0.7.0 → comfygit_core-0.7.1}/tests/unit/test_model_symlink_manager.py +0 -0
  427. {comfygit_core-0.7.0 → comfygit_core-0.7.1}/tests/unit/test_node_callbacks.py +0 -0
  428. {comfygit_core-0.7.0 → comfygit_core-0.7.1}/tests/unit/test_node_conflict_context.py +0 -0
  429. {comfygit_core-0.7.0 → comfygit_core-0.7.1}/tests/unit/test_node_mappings_repository.py +0 -0
  430. {comfygit_core-0.7.0 → comfygit_core-0.7.1}/tests/unit/test_node_resolution_context.py +0 -0
  431. {comfygit_core-0.7.0 → comfygit_core-0.7.1}/tests/unit/test_unified_node_search.py +0 -0
  432. {comfygit_core-0.7.0 → comfygit_core-0.7.1}/tests/unit/test_user_content_symlink_manager.py +0 -0
  433. {comfygit_core-0.7.0 → comfygit_core-0.7.1}/tests/unit/test_uv_error_handling.py +0 -0
  434. {comfygit_core-0.7.0 → comfygit_core-0.7.1}/tests/unit/test_uv_error_parser.py +0 -0
  435. {comfygit_core-0.7.0 → comfygit_core-0.7.1}/tests/unit/test_workflow_manager_deduplication.py +0 -0
  436. {comfygit_core-0.7.0 → comfygit_core-0.7.1}/tests/unit/test_workspace_config_facade.py +0 -0
  437. {comfygit_core-0.7.0 → comfygit_core-0.7.1}/tests/unit/test_workspace_config_resilience.py +0 -0
  438. {comfygit_core-0.7.0 → comfygit_core-0.7.1}/tests/unit/test_workspace_credential_overrides.py +0 -0
  439. {comfygit_core-0.7.0 → comfygit_core-0.7.1}/tests/unit/utils/test_comfyui_ops_source.py +0 -0
  440. {comfygit_core-0.7.0 → comfygit_core-0.7.1}/tests/unit/utils/test_conflict_analyzer.py +0 -0
  441. {comfygit_core-0.7.0 → comfygit_core-0.7.1}/tests/unit/utils/test_conflict_parser.py +0 -0
  442. {comfygit_core-0.7.0 → comfygit_core-0.7.1}/tests/unit/utils/test_dependency_parser.py +0 -0
  443. {comfygit_core-0.7.0 → comfygit_core-0.7.1}/tests/unit/utils/test_dependency_probe.py +0 -0
  444. {comfygit_core-0.7.0 → comfygit_core-0.7.1}/tests/unit/utils/test_environment_cleanup.py +0 -0
  445. {comfygit_core-0.7.0 → comfygit_core-0.7.1}/tests/unit/utils/test_filesystem.py +0 -0
  446. {comfygit_core-0.7.0 → comfygit_core-0.7.1}/tests/unit/utils/test_git.py +0 -0
  447. {comfygit_core-0.7.0 → comfygit_core-0.7.1}/tests/unit/utils/test_input_signature.py +0 -0
  448. {comfygit_core-0.7.0 → comfygit_core-0.7.1}/tests/unit/utils/test_node_identity.py +0 -0
  449. {comfygit_core-0.7.0 → comfygit_core-0.7.1}/tests/unit/utils/test_provider_auth_hardening.py +0 -0
  450. {comfygit_core-0.7.0 → comfygit_core-0.7.1}/tests/unit/utils/test_pytorch.py +0 -0
  451. {comfygit_core-0.7.0 → comfygit_core-0.7.1}/tests/unit/utils/test_pytorch_prober.py +0 -0
  452. {comfygit_core-0.7.0 → comfygit_core-0.7.1}/tests/unit/utils/test_requirements.py +0 -0
  453. {comfygit_core-0.7.0 → comfygit_core-0.7.1}/tests/unit/utils/test_symlink_utils.py +0 -0
  454. {comfygit_core-0.7.0 → comfygit_core-0.7.1}/tests/unit/utils/test_uuid.py +0 -0
  455. {comfygit_core-0.7.0 → comfygit_core-0.7.1}/tests/unit/utils/test_version.py +0 -0
  456. {comfygit_core-0.7.0 → comfygit_core-0.7.1}/tests/utils/__init__.py +0 -0
  457. {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.
@@ -1,6 +1,6 @@
1
1
  [project]
2
2
  name = "comfygit-core"
3
- version = "0.7.0"
3
+ version = "0.7.1"
4
4
  description = "ComfyGit Core - Git-based ComfyUI environment manager"
5
5
  readme = "README.md"
6
6
  requires-python = ">=3.10"
@@ -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
- return self.pyproject.get_manifest_snapshot()
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=(
@@ -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())
@@ -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
- assert lock_path.read_text(encoding="utf-8").strip()
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") == ""