comfygit 0.3.6__py3-none-any.whl → 0.3.10__py3-none-any.whl
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-0.3.6.dist-info → comfygit-0.3.10.dist-info}/METADATA +123 -120
- {comfygit-0.3.6.dist-info → comfygit-0.3.10.dist-info}/RECORD +12 -12
- comfygit_cli/cli.py +135 -9
- comfygit_cli/cli_utils.py +1 -0
- comfygit_cli/completers.py +6 -6
- comfygit_cli/env_commands.py +379 -40
- comfygit_cli/global_commands.py +43 -65
- comfygit_cli/logging/environment_logger.py +7 -7
- comfygit_cli/utils/civitai_errors.py +1 -1
- {comfygit-0.3.6.dist-info → comfygit-0.3.10.dist-info}/WHEEL +0 -0
- {comfygit-0.3.6.dist-info → comfygit-0.3.10.dist-info}/entry_points.txt +0 -0
- {comfygit-0.3.6.dist-info → comfygit-0.3.10.dist-info}/licenses/LICENSE.txt +0 -0
comfygit_cli/global_commands.py
CHANGED
|
@@ -16,15 +16,6 @@ from .utils import create_progress_callback, paginate, show_civitai_auth_help, s
|
|
|
16
16
|
|
|
17
17
|
logger = get_logger(__name__)
|
|
18
18
|
|
|
19
|
-
# Default system nodes to install with new workspaces.
|
|
20
|
-
# These are infrastructure custom nodes that provide management capabilities.
|
|
21
|
-
# Use `cg init --bare` to skip installation.
|
|
22
|
-
DEFAULT_SYSTEM_NODES = {
|
|
23
|
-
"comfygit-manager": {
|
|
24
|
-
"url": "https://github.com/comfyhub-org/comfygit-manager.git",
|
|
25
|
-
"description": "ComfyGit management panel for ComfyUI",
|
|
26
|
-
},
|
|
27
|
-
}
|
|
28
19
|
|
|
29
20
|
|
|
30
21
|
class GlobalCommands:
|
|
@@ -94,7 +85,6 @@ class GlobalCommands:
|
|
|
94
85
|
- uv_cache/ for package management
|
|
95
86
|
- environments/ for ComfyUI environments
|
|
96
87
|
"""
|
|
97
|
-
from pathlib import Path
|
|
98
88
|
|
|
99
89
|
# Validate models directory if provided (before creating workspace)
|
|
100
90
|
explicit_models_dir = getattr(args, 'models_dir', None)
|
|
@@ -142,12 +132,6 @@ class GlobalCommands:
|
|
|
142
132
|
|
|
143
133
|
print(f"✓ Workspace initialized at {workspace.path}")
|
|
144
134
|
|
|
145
|
-
# Install default system nodes (unless --bare)
|
|
146
|
-
if not getattr(args, 'bare', False):
|
|
147
|
-
self._install_system_nodes(workspace)
|
|
148
|
-
else:
|
|
149
|
-
print("📦 Skipping system node installation (--bare flag)")
|
|
150
|
-
|
|
151
135
|
# Handle models directory setup
|
|
152
136
|
self._setup_models_directory(workspace, args)
|
|
153
137
|
|
|
@@ -163,39 +147,6 @@ class GlobalCommands:
|
|
|
163
147
|
print(f"✗ Failed to initialize workspace: {e}", file=sys.stderr)
|
|
164
148
|
sys.exit(1)
|
|
165
149
|
|
|
166
|
-
def _install_system_nodes(self, workspace: Workspace) -> None:
|
|
167
|
-
"""Install default system nodes (comfygit-manager) into workspace.
|
|
168
|
-
|
|
169
|
-
System nodes are infrastructure custom nodes that:
|
|
170
|
-
- Live at workspace level (.metadata/system_nodes/)
|
|
171
|
-
- Are symlinked into every environment
|
|
172
|
-
- Are never tracked in pyproject.toml
|
|
173
|
-
"""
|
|
174
|
-
from comfygit_core.utils.git import git_clone
|
|
175
|
-
|
|
176
|
-
system_nodes_path = workspace.paths.system_nodes
|
|
177
|
-
|
|
178
|
-
for node_name, node_config in DEFAULT_SYSTEM_NODES.items():
|
|
179
|
-
target_path = system_nodes_path / node_name
|
|
180
|
-
|
|
181
|
-
if target_path.exists():
|
|
182
|
-
logger.debug(f"System node '{node_name}' already exists, skipping")
|
|
183
|
-
continue
|
|
184
|
-
|
|
185
|
-
print(f"📦 Installing system node: {node_name}")
|
|
186
|
-
try:
|
|
187
|
-
git_clone(
|
|
188
|
-
url=node_config["url"],
|
|
189
|
-
target_path=target_path,
|
|
190
|
-
depth=1 # Shallow clone for speed
|
|
191
|
-
)
|
|
192
|
-
print(f" ✓ Installed {node_name}")
|
|
193
|
-
logger.info(f"Installed system node: {node_name}")
|
|
194
|
-
except Exception as e:
|
|
195
|
-
print(f" ⚠️ Failed to install {node_name}: {e}")
|
|
196
|
-
print(f" You can install it manually later")
|
|
197
|
-
logger.warning(f"Failed to install system node {node_name}: {e}")
|
|
198
|
-
|
|
199
150
|
def _show_workspace_env_setup(self, workspace_path: Path) -> None:
|
|
200
151
|
"""Show instructions for setting COMFYGIT_HOME for custom workspace location."""
|
|
201
152
|
import os
|
|
@@ -231,8 +182,7 @@ class GlobalCommands:
|
|
|
231
182
|
args: CLI arguments containing models_dir and yes flags
|
|
232
183
|
"""
|
|
233
184
|
from pathlib import Path
|
|
234
|
-
|
|
235
|
-
from comfygit_core.utils.common import format_size
|
|
185
|
+
|
|
236
186
|
|
|
237
187
|
# Check for explicit flags
|
|
238
188
|
use_interactive = not getattr(args, 'yes', False)
|
|
@@ -256,7 +206,7 @@ class GlobalCommands:
|
|
|
256
206
|
print("\nOptions:")
|
|
257
207
|
print(" 1. Point to an existing ComfyUI models directory (recommended)")
|
|
258
208
|
print(" → Access all your existing models immediately")
|
|
259
|
-
print(
|
|
209
|
+
print(" → Example: ~/ComfyUI/models")
|
|
260
210
|
print("\n 2. Use the default empty directory")
|
|
261
211
|
print(f" → ComfyGit created: {workspace.paths.models}")
|
|
262
212
|
print(" → Download models as needed later")
|
|
@@ -296,7 +246,7 @@ class GlobalCommands:
|
|
|
296
246
|
# Auto-detect if they entered ComfyUI root instead of models subdir
|
|
297
247
|
if (models_path / "models").exists() and models_path.name != "models":
|
|
298
248
|
print(f"\n⚠️ Detected ComfyUI installation at: {models_path}")
|
|
299
|
-
use_subdir = input(
|
|
249
|
+
use_subdir = input("Use models/ subdirectory instead? (Y/n): ").strip().lower()
|
|
300
250
|
if use_subdir != 'n':
|
|
301
251
|
models_path = models_path / "models"
|
|
302
252
|
print(f"Using: {models_path}")
|
|
@@ -322,9 +272,10 @@ class GlobalCommands:
|
|
|
322
272
|
workspace: The workspace instance
|
|
323
273
|
models_path: Path to the models directory to scan
|
|
324
274
|
"""
|
|
325
|
-
from comfygit_cli.utils.progress import create_model_sync_progress
|
|
326
275
|
from comfygit_core.utils.common import format_size
|
|
327
276
|
|
|
277
|
+
from comfygit_cli.utils.progress import create_model_sync_progress
|
|
278
|
+
|
|
328
279
|
try:
|
|
329
280
|
progress = create_model_sync_progress()
|
|
330
281
|
workspace.set_models_directory(models_path, progress=progress)
|
|
@@ -404,7 +355,7 @@ class GlobalCommands:
|
|
|
404
355
|
|
|
405
356
|
# Read log lines
|
|
406
357
|
try:
|
|
407
|
-
with open(log_file,
|
|
358
|
+
with open(log_file, encoding='utf-8') as f:
|
|
408
359
|
lines = f.readlines()
|
|
409
360
|
except Exception as e:
|
|
410
361
|
print(f"✗ Failed to read log file: {e}", file=sys.stderr)
|
|
@@ -453,9 +404,9 @@ class GlobalCommands:
|
|
|
453
404
|
for line in record:
|
|
454
405
|
print(line.rstrip())
|
|
455
406
|
|
|
456
|
-
print(
|
|
407
|
+
print("\n=== End of logs ===")
|
|
457
408
|
if not args.full and len(records) == args.lines:
|
|
458
|
-
print(
|
|
409
|
+
print("Tip: Use --full to see all logs, or increase --lines to see more")
|
|
459
410
|
|
|
460
411
|
@with_workspace_logging("migrate")
|
|
461
412
|
def migrate(self, args: argparse.Namespace) -> None:
|
|
@@ -749,7 +700,7 @@ class GlobalCommands:
|
|
|
749
700
|
callbacks = CLIExportCallbacks()
|
|
750
701
|
|
|
751
702
|
try:
|
|
752
|
-
tarball_path = env.export_environment(output_path, callbacks=callbacks)
|
|
703
|
+
tarball_path = env.export_environment(output_path, callbacks=callbacks, allow_issues=args.allow_issues)
|
|
753
704
|
|
|
754
705
|
# Check if we need user confirmation
|
|
755
706
|
if callbacks.models_without_sources and not args.allow_issues:
|
|
@@ -1519,10 +1470,10 @@ class GlobalCommands:
|
|
|
1519
1470
|
def orch_status(self, args: argparse.Namespace) -> None:
|
|
1520
1471
|
"""Show orchestrator status."""
|
|
1521
1472
|
from .utils.orchestrator import (
|
|
1473
|
+
format_uptime,
|
|
1474
|
+
get_orchestrator_uptime,
|
|
1522
1475
|
is_orchestrator_running,
|
|
1523
1476
|
read_switch_status,
|
|
1524
|
-
get_orchestrator_uptime,
|
|
1525
|
-
format_uptime
|
|
1526
1477
|
)
|
|
1527
1478
|
|
|
1528
1479
|
metadata_dir = self.workspace.path / ".metadata"
|
|
@@ -1578,7 +1529,7 @@ class GlobalCommands:
|
|
|
1578
1529
|
try:
|
|
1579
1530
|
port = control_port_file.read_text().strip()
|
|
1580
1531
|
print(f"Control Port: {port}")
|
|
1581
|
-
except
|
|
1532
|
+
except OSError:
|
|
1582
1533
|
pass
|
|
1583
1534
|
|
|
1584
1535
|
# Check switch status
|
|
@@ -1605,6 +1556,7 @@ class GlobalCommands:
|
|
|
1605
1556
|
def orch_restart(self, args: argparse.Namespace) -> None:
|
|
1606
1557
|
"""Request orchestrator to restart ComfyUI."""
|
|
1607
1558
|
import time
|
|
1559
|
+
|
|
1608
1560
|
from .utils.orchestrator import is_orchestrator_running, safe_write_command
|
|
1609
1561
|
|
|
1610
1562
|
metadata_dir = self.workspace.path / ".metadata"
|
|
@@ -1643,11 +1595,12 @@ class GlobalCommands:
|
|
|
1643
1595
|
def orch_kill(self, args: argparse.Namespace) -> None:
|
|
1644
1596
|
"""Shutdown orchestrator."""
|
|
1645
1597
|
import time
|
|
1598
|
+
|
|
1646
1599
|
from .utils.orchestrator import (
|
|
1647
1600
|
is_orchestrator_running,
|
|
1648
|
-
safe_write_command,
|
|
1649
1601
|
kill_orchestrator_process,
|
|
1650
|
-
read_switch_status
|
|
1602
|
+
read_switch_status,
|
|
1603
|
+
safe_write_command,
|
|
1651
1604
|
)
|
|
1652
1605
|
|
|
1653
1606
|
metadata_dir = self.workspace.path / ".metadata"
|
|
@@ -1701,9 +1654,9 @@ class GlobalCommands:
|
|
|
1701
1654
|
def orch_clean(self, args: argparse.Namespace) -> None:
|
|
1702
1655
|
"""Clean orchestrator state files."""
|
|
1703
1656
|
from .utils.orchestrator import (
|
|
1657
|
+
cleanup_orchestrator_state,
|
|
1704
1658
|
is_orchestrator_running,
|
|
1705
1659
|
kill_orchestrator_process,
|
|
1706
|
-
cleanup_orchestrator_state
|
|
1707
1660
|
)
|
|
1708
1661
|
|
|
1709
1662
|
metadata_dir = self.workspace.path / ".metadata"
|
|
@@ -1742,7 +1695,7 @@ class GlobalCommands:
|
|
|
1742
1695
|
print("\nNote: workspace_config.json will be preserved")
|
|
1743
1696
|
|
|
1744
1697
|
if args.kill:
|
|
1745
|
-
print(
|
|
1698
|
+
print("\n⚠️ --kill flag: Will also terminate orchestrator process")
|
|
1746
1699
|
|
|
1747
1700
|
response = input("\nContinue? [y/N]: ").strip().lower()
|
|
1748
1701
|
if response not in ['y', 'yes']:
|
|
@@ -1784,6 +1737,7 @@ class GlobalCommands:
|
|
|
1784
1737
|
def orch_logs(self, args: argparse.Namespace) -> None:
|
|
1785
1738
|
"""Show orchestrator logs."""
|
|
1786
1739
|
import subprocess
|
|
1740
|
+
|
|
1787
1741
|
from .utils.orchestrator import tail_log_file
|
|
1788
1742
|
|
|
1789
1743
|
metadata_dir = self.workspace.path / ".metadata"
|
|
@@ -1808,3 +1762,27 @@ class GlobalCommands:
|
|
|
1808
1762
|
print("".join(lines))
|
|
1809
1763
|
else:
|
|
1810
1764
|
print("(empty log file)")
|
|
1765
|
+
|
|
1766
|
+
# === Workspace Management ===
|
|
1767
|
+
|
|
1768
|
+
@with_workspace_logging("workspace cleanup")
|
|
1769
|
+
def workspace_cleanup(self, args: argparse.Namespace) -> None:
|
|
1770
|
+
"""Clean up legacy workspace artifacts.
|
|
1771
|
+
|
|
1772
|
+
Removes .metadata/system_nodes/ directory if no environments
|
|
1773
|
+
still use legacy symlinked manager.
|
|
1774
|
+
"""
|
|
1775
|
+
force = getattr(args, 'force', False)
|
|
1776
|
+
|
|
1777
|
+
result = self.workspace.cleanup_legacy_system_nodes(force=force)
|
|
1778
|
+
|
|
1779
|
+
if result.success:
|
|
1780
|
+
print(f"Removed {result.removed_path}")
|
|
1781
|
+
else:
|
|
1782
|
+
if result.legacy_environments:
|
|
1783
|
+
print("Cannot cleanup: Some environments still use legacy manager")
|
|
1784
|
+
for env in result.legacy_environments:
|
|
1785
|
+
print(f" {env}")
|
|
1786
|
+
print("\nRun 'cg -e <ENV> manager update' to migrate, then retry.")
|
|
1787
|
+
else:
|
|
1788
|
+
print(f"{result.message}")
|
|
@@ -408,21 +408,21 @@ def with_env_logging(command_name: str, get_env_name: Callable | None = None, lo
|
|
|
408
408
|
"""Decorator for environment commands that automatically sets up logging.
|
|
409
409
|
|
|
410
410
|
Args:
|
|
411
|
-
command_name: Name of the command for logging (e.g., "
|
|
411
|
+
command_name: Name of the command for logging (e.g., "create", "node add")
|
|
412
412
|
get_env_name: Optional function to extract env name from args.
|
|
413
|
-
If None, tries args.name, then args.env_name,
|
|
413
|
+
If None, tries args.name, then args.env_name,
|
|
414
414
|
then calls self._get_env_name(args) if available.
|
|
415
415
|
log_args: If True, automatically logs all args attributes (default: True)
|
|
416
416
|
**log_context: Additional static context to log
|
|
417
|
-
|
|
417
|
+
|
|
418
418
|
Example:
|
|
419
|
-
@with_env_logging("
|
|
419
|
+
@with_env_logging("create") # Automatically logs all args
|
|
420
420
|
def create(self, args):
|
|
421
421
|
# All logging automatically goes to environment log
|
|
422
422
|
result = self.env_mgr.create_environment(...)
|
|
423
|
-
|
|
424
|
-
@with_env_logging("
|
|
425
|
-
def
|
|
423
|
+
|
|
424
|
+
@with_env_logging("repair", log_args=False, custom_field="value")
|
|
425
|
+
def repair(self, args):
|
|
426
426
|
# Only logs custom_field, not args
|
|
427
427
|
"""
|
|
428
428
|
def decorator(func: Callable) -> Callable:
|
|
@@ -5,5 +5,5 @@ def show_civitai_auth_help() -> None:
|
|
|
5
5
|
"""Display helpful message for Civitai authentication errors."""
|
|
6
6
|
print("\n💡 Civitai API key required")
|
|
7
7
|
print(" 1. Get your API key from: https://civitai.com/user/account")
|
|
8
|
-
print(" 2. Add it to ComfyGit:
|
|
8
|
+
print(" 2. Add it to ComfyGit: cg config --civitai-key <your-key>")
|
|
9
9
|
print(" 3. Try downloading again")
|
|
File without changes
|
|
File without changes
|
|
File without changes
|