comfygit 0.6.0__tar.gz → 0.7.0__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-0.6.0 → comfygit-0.7.0}/PKG-INFO +19 -9
- {comfygit-0.6.0 → comfygit-0.7.0}/README.md +15 -5
- {comfygit-0.6.0 → comfygit-0.7.0}/comfygit_cli/cli.py +81 -10
- {comfygit-0.6.0 → comfygit-0.7.0}/comfygit_cli/env_commands.py +69 -6
- {comfygit-0.6.0 → comfygit-0.7.0}/comfygit_cli/global_commands.py +278 -235
- {comfygit-0.6.0 → comfygit-0.7.0}/comfygit_cli/logging/compressed_handler.py +9 -0
- {comfygit-0.6.0 → comfygit-0.7.0}/comfygit_cli/logging/environment_logger.py +21 -13
- {comfygit-0.6.0 → comfygit-0.7.0}/comfygit_cli/logging/logging_config.py +6 -5
- comfygit-0.7.0/comfygit_cli/logging/security.py +41 -0
- {comfygit-0.6.0 → comfygit-0.7.0}/comfygit_cli/utils/civitai_errors.py +1 -1
- comfygit-0.7.0/comfygit_cli/utils/runtime_client.py +66 -0
- comfygit-0.7.0/comfygit_cli/utils/workflow_result.py +40 -0
- {comfygit-0.6.0 → comfygit-0.7.0}/pyproject.toml +3 -3
- {comfygit-0.6.0 → comfygit-0.7.0}/.gitignore +0 -0
- {comfygit-0.6.0 → comfygit-0.7.0}/LICENSE.txt +0 -0
- {comfygit-0.6.0 → comfygit-0.7.0}/comfygit_cli/__init__.py +0 -0
- {comfygit-0.6.0 → comfygit-0.7.0}/comfygit_cli/__main__.py +0 -0
- {comfygit-0.6.0 → comfygit-0.7.0}/comfygit_cli/cli_utils.py +0 -0
- {comfygit-0.6.0 → comfygit-0.7.0}/comfygit_cli/completers.py +0 -0
- {comfygit-0.6.0 → comfygit-0.7.0}/comfygit_cli/completion_commands.py +0 -0
- {comfygit-0.6.0 → comfygit-0.7.0}/comfygit_cli/formatters/__init__.py +0 -0
- {comfygit-0.6.0 → comfygit-0.7.0}/comfygit_cli/formatters/error_formatter.py +0 -0
- {comfygit-0.6.0 → comfygit-0.7.0}/comfygit_cli/interactive/__init__.py +0 -0
- {comfygit-0.6.0 → comfygit-0.7.0}/comfygit_cli/logging/log_compressor.py +0 -0
- {comfygit-0.6.0 → comfygit-0.7.0}/comfygit_cli/resolution_strategies.py +0 -0
- {comfygit-0.6.0 → comfygit-0.7.0}/comfygit_cli/strategies/__init__.py +0 -0
- {comfygit-0.6.0 → comfygit-0.7.0}/comfygit_cli/strategies/confirmation.py +0 -0
- {comfygit-0.6.0 → comfygit-0.7.0}/comfygit_cli/strategies/conflict_resolver.py +0 -0
- {comfygit-0.6.0 → comfygit-0.7.0}/comfygit_cli/strategies/interactive.py +0 -0
- {comfygit-0.6.0 → comfygit-0.7.0}/comfygit_cli/strategies/rollback.py +0 -0
- {comfygit-0.6.0 → comfygit-0.7.0}/comfygit_cli/update_commands.py +0 -0
- {comfygit-0.6.0 → comfygit-0.7.0}/comfygit_cli/utils/__init__.py +0 -0
- {comfygit-0.6.0 → comfygit-0.7.0}/comfygit_cli/utils/formatting.py +0 -0
- {comfygit-0.6.0 → comfygit-0.7.0}/comfygit_cli/utils/orchestrator.py +0 -0
- {comfygit-0.6.0 → comfygit-0.7.0}/comfygit_cli/utils/pagination.py +0 -0
- {comfygit-0.6.0 → comfygit-0.7.0}/comfygit_cli/utils/progress.py +0 -0
- {comfygit-0.6.0 → comfygit-0.7.0}/comfygit_cli/utils/update_checker.py +0 -0
- {comfygit-0.6.0 → comfygit-0.7.0}/comfygit_cli/utils/update_notice.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
Metadata-Version: 2.
|
|
1
|
+
Metadata-Version: 2.5
|
|
2
2
|
Name: comfygit
|
|
3
|
-
Version: 0.
|
|
3
|
+
Version: 0.7.0
|
|
4
4
|
Summary: ComfyGit - Git-based environment management for ComfyUI
|
|
5
5
|
Project-URL: Documentation, https://docs.comfygit.org/
|
|
6
6
|
Project-URL: Repository, https://github.com/comfygit-ai/comfygit
|
|
@@ -8,8 +8,8 @@ Project-URL: Issues, https://github.com/comfygit-ai/comfygit/issues
|
|
|
8
8
|
License-File: LICENSE.txt
|
|
9
9
|
Requires-Python: >=3.10
|
|
10
10
|
Requires-Dist: argcomplete>=3.5.0
|
|
11
|
-
Requires-Dist: comfygit-core==0.
|
|
12
|
-
Requires-Dist: comfygit-studio==0.
|
|
11
|
+
Requires-Dist: comfygit-core[keyring]==0.7.0
|
|
12
|
+
Requires-Dist: comfygit-studio==0.7.0
|
|
13
13
|
Requires-Dist: requests>=2.32.4
|
|
14
14
|
Description-Content-Type: text/markdown
|
|
15
15
|
|
|
@@ -201,10 +201,17 @@ cg import [PATH|URL]
|
|
|
201
201
|
cg export [PATH]
|
|
202
202
|
--allow-issues Skip confirmation if models lack source URLs
|
|
203
203
|
|
|
204
|
-
#
|
|
205
|
-
cg
|
|
206
|
-
|
|
207
|
-
|
|
204
|
+
# Provider authentication (secrets never go in argv)
|
|
205
|
+
cg auth status
|
|
206
|
+
cg auth set civitai
|
|
207
|
+
cg auth set huggingface
|
|
208
|
+
cg auth set github
|
|
209
|
+
cg auth login huggingface
|
|
210
|
+
cg auth migrate
|
|
211
|
+
cg auth clear PROVIDER
|
|
212
|
+
|
|
213
|
+
# Nonsecret configuration
|
|
214
|
+
cg config --show
|
|
208
215
|
|
|
209
216
|
# Registry management
|
|
210
217
|
cg registry status # Show registry cache status
|
|
@@ -243,6 +250,7 @@ cg create NAME
|
|
|
243
250
|
--template PATH Template manifest
|
|
244
251
|
--python VERSION Python version (default: 3.11)
|
|
245
252
|
--comfyui VERSION ComfyUI version
|
|
253
|
+
--comfyui-repository URL ComfyUI Git repository (canonical by default)
|
|
246
254
|
--torch-backend BACKEND PyTorch backend (auto/cpu/cu128/rocm6.3/xpu)
|
|
247
255
|
--use Set as active environment
|
|
248
256
|
|
|
@@ -633,7 +641,9 @@ source ~/.bashrc # or ~/.zshrc
|
|
|
633
641
|
|
|
634
642
|
- `COMFYGIT_HOME` - Override default workspace location (`~/comfygit`)
|
|
635
643
|
- `COMFYGIT_DEV_COMPRESS_LOGS` - Enable compressed logging (dev feature: `true`/`1`/`yes`)
|
|
636
|
-
- `CIVITAI_API_KEY` - CivitAI
|
|
644
|
+
- `CIVITAI_API_TOKEN` / `CIVITAI_API_KEY` - CivitAI credential override
|
|
645
|
+
- `HF_TOKEN` / `HUGGING_FACE_HUB_TOKEN` - Hugging Face credential override
|
|
646
|
+
- `GITHUB_TOKEN` / `GH_TOKEN` - GitHub credential override
|
|
637
647
|
|
|
638
648
|
Example:
|
|
639
649
|
```bash
|
|
@@ -186,10 +186,17 @@ cg import [PATH|URL]
|
|
|
186
186
|
cg export [PATH]
|
|
187
187
|
--allow-issues Skip confirmation if models lack source URLs
|
|
188
188
|
|
|
189
|
-
#
|
|
190
|
-
cg
|
|
191
|
-
|
|
192
|
-
|
|
189
|
+
# Provider authentication (secrets never go in argv)
|
|
190
|
+
cg auth status
|
|
191
|
+
cg auth set civitai
|
|
192
|
+
cg auth set huggingface
|
|
193
|
+
cg auth set github
|
|
194
|
+
cg auth login huggingface
|
|
195
|
+
cg auth migrate
|
|
196
|
+
cg auth clear PROVIDER
|
|
197
|
+
|
|
198
|
+
# Nonsecret configuration
|
|
199
|
+
cg config --show
|
|
193
200
|
|
|
194
201
|
# Registry management
|
|
195
202
|
cg registry status # Show registry cache status
|
|
@@ -228,6 +235,7 @@ cg create NAME
|
|
|
228
235
|
--template PATH Template manifest
|
|
229
236
|
--python VERSION Python version (default: 3.11)
|
|
230
237
|
--comfyui VERSION ComfyUI version
|
|
238
|
+
--comfyui-repository URL ComfyUI Git repository (canonical by default)
|
|
231
239
|
--torch-backend BACKEND PyTorch backend (auto/cpu/cu128/rocm6.3/xpu)
|
|
232
240
|
--use Set as active environment
|
|
233
241
|
|
|
@@ -618,7 +626,9 @@ source ~/.bashrc # or ~/.zshrc
|
|
|
618
626
|
|
|
619
627
|
- `COMFYGIT_HOME` - Override default workspace location (`~/comfygit`)
|
|
620
628
|
- `COMFYGIT_DEV_COMPRESS_LOGS` - Enable compressed logging (dev feature: `true`/`1`/`yes`)
|
|
621
|
-
- `CIVITAI_API_KEY` - CivitAI
|
|
629
|
+
- `CIVITAI_API_TOKEN` / `CIVITAI_API_KEY` - CivitAI credential override
|
|
630
|
+
- `HF_TOKEN` / `HUGGING_FACE_HUB_TOKEN` - Hugging Face credential override
|
|
631
|
+
- `GITHUB_TOKEN` / `GH_TOKEN` - GitHub credential override
|
|
622
632
|
|
|
623
633
|
Example:
|
|
624
634
|
```bash
|
|
@@ -233,6 +233,14 @@ def _add_global_commands(subparsers: argparse._SubParsersAction) -> None:
|
|
|
233
233
|
)
|
|
234
234
|
analyze_parser.set_defaults(func=global_cmds.analyze)
|
|
235
235
|
|
|
236
|
+
inventory_parser = subparsers.add_parser(
|
|
237
|
+
"inventory",
|
|
238
|
+
help="Report typed workspace model, environment, and storage inventory",
|
|
239
|
+
)
|
|
240
|
+
inventory_parser.add_argument("--json", action="store_true", dest="json_output", help="Emit machine-readable JSON")
|
|
241
|
+
inventory_parser.add_argument("--storage", action="store_true", help="Measure environment, cache, input/output, and model storage")
|
|
242
|
+
inventory_parser.set_defaults(func=global_cmds.inventory)
|
|
243
|
+
|
|
236
244
|
# update - Update ComfyGit CLI (self-update)
|
|
237
245
|
update_parser = subparsers.add_parser("update", help="Update ComfyGit CLI")
|
|
238
246
|
update_parser.add_argument("--check", action="store_true", help="Check for updates without upgrading")
|
|
@@ -333,6 +341,7 @@ def _add_global_commands(subparsers: argparse._SubParsersAction) -> None:
|
|
|
333
341
|
# model index list
|
|
334
342
|
model_index_list_parser = model_index_subparsers.add_parser("list", help="List all indexed models")
|
|
335
343
|
model_index_list_parser.add_argument("--duplicates", action="store_true", help="Show only models with multiple locations")
|
|
344
|
+
model_index_list_parser.add_argument("--json", action="store_true", dest="json_output", help="Emit machine-readable JSON")
|
|
336
345
|
model_index_list_parser.set_defaults(func=global_cmds.model_index_list)
|
|
337
346
|
|
|
338
347
|
# model index show
|
|
@@ -370,7 +379,14 @@ def _add_global_commands(subparsers: argparse._SubParsersAction) -> None:
|
|
|
370
379
|
# model delete
|
|
371
380
|
model_delete_parser = model_subparsers.add_parser("delete", help="Delete model files and clean index entries")
|
|
372
381
|
model_delete_parser.add_argument("identifier", help="Model hash, hash prefix, filename, or path")
|
|
373
|
-
model_delete_parser.
|
|
382
|
+
deletion_target = model_delete_parser.add_mutually_exclusive_group()
|
|
383
|
+
deletion_target.add_argument("--location-id", type=int, help="Delete one indexed location id")
|
|
384
|
+
deletion_target.add_argument("--all-locations", action="store_true", help="Explicitly target every indexed location")
|
|
385
|
+
model_delete_parser.add_argument("--apply", action="store_true", help="Apply the deletion plan; default is dry-run")
|
|
386
|
+
model_delete_parser.add_argument("--allow-referenced", action="store_true", help="Allow deletion despite ComfyGit environment references")
|
|
387
|
+
model_delete_parser.add_argument("--allow-incomplete-recovery", action="store_true", help="Allow final-copy deletion without source/hash recovery proof")
|
|
388
|
+
model_delete_parser.add_argument("--json", action="store_true", dest="json_output", help="Emit machine-readable JSON")
|
|
389
|
+
model_delete_parser.add_argument("-y", "--yes", action="store_true", help="Compatibility alias for --apply --all-locations")
|
|
374
390
|
model_delete_parser.set_defaults(func=global_cmds.model_delete)
|
|
375
391
|
|
|
376
392
|
# Registry management subcommands
|
|
@@ -386,14 +402,46 @@ def _add_global_commands(subparsers: argparse._SubParsersAction) -> None:
|
|
|
386
402
|
registry_update_parser = registry_subparsers.add_parser("update", help="Update registry data from GitHub")
|
|
387
403
|
registry_update_parser.set_defaults(func=global_cmds.registry_update)
|
|
388
404
|
|
|
389
|
-
#
|
|
405
|
+
# Provider authentication. Secret values are read from a hidden prompt or stdin,
|
|
406
|
+
# never from argv.
|
|
407
|
+
auth_parser = subparsers.add_parser("auth", help="Manage provider authentication")
|
|
408
|
+
auth_subparsers = auth_parser.add_subparsers(dest="auth_command", help="Authentication commands")
|
|
409
|
+
auth_parser.set_defaults(func=_make_help_func(auth_parser))
|
|
410
|
+
|
|
411
|
+
auth_status_parser = auth_subparsers.add_parser("status", help="Show provider authentication status")
|
|
412
|
+
auth_status_parser.set_defaults(func=global_cmds.auth_status)
|
|
413
|
+
|
|
414
|
+
auth_set_parser = auth_subparsers.add_parser("set", help="Save a provider credential")
|
|
415
|
+
auth_set_parser.add_argument("provider", choices=("civitai", "huggingface", "github"))
|
|
416
|
+
auth_set_parser.add_argument(
|
|
417
|
+
"--token-stdin",
|
|
418
|
+
action="store_true",
|
|
419
|
+
help="Read the credential from one line on standard input instead of a hidden prompt",
|
|
420
|
+
)
|
|
421
|
+
auth_set_parser.set_defaults(func=global_cmds.auth_set)
|
|
422
|
+
|
|
423
|
+
auth_clear_parser = auth_subparsers.add_parser("clear", help="Clear a saved provider credential")
|
|
424
|
+
auth_clear_parser.add_argument("provider", choices=("civitai", "huggingface", "github"))
|
|
425
|
+
auth_clear_parser.set_defaults(func=global_cmds.auth_clear)
|
|
426
|
+
|
|
427
|
+
auth_login_parser = auth_subparsers.add_parser(
|
|
428
|
+
"login",
|
|
429
|
+
help="Authenticate through a provider-native login flow",
|
|
430
|
+
)
|
|
431
|
+
auth_login_parser.add_argument("provider", choices=("huggingface",))
|
|
432
|
+
auth_login_parser.add_argument("--force", action="store_true", help="Force a new provider login")
|
|
433
|
+
auth_login_parser.set_defaults(func=global_cmds.auth_login)
|
|
434
|
+
|
|
435
|
+
auth_migrate_parser = auth_subparsers.add_parser(
|
|
436
|
+
"migrate",
|
|
437
|
+
help="Migrate verified legacy plaintext credentials into secure storage",
|
|
438
|
+
)
|
|
439
|
+
auth_migrate_parser.set_defaults(func=global_cmds.auth_migrate)
|
|
440
|
+
|
|
441
|
+
# Nonsecret workspace configuration.
|
|
390
442
|
config_parser = subparsers.add_parser("config", help="Manage configuration settings")
|
|
391
443
|
config_parser.add_subparsers(dest="config_command", help="Configuration commands")
|
|
392
444
|
|
|
393
|
-
# Legacy flags - still supported at root level for backward compatibility
|
|
394
|
-
config_parser.add_argument("--civitai-key", type=str, help="Set Civitai API key (use empty string to clear)")
|
|
395
|
-
config_parser.add_argument("--huggingface-token", type=str, help="Set Hugging Face token for gated model downloads (use empty string to clear)")
|
|
396
|
-
config_parser.add_argument("--github-token", type=str, help="Set GitHub token for private git repository access (use empty string to clear)")
|
|
397
445
|
config_parser.add_argument("--uv-cache", type=str, help="Set external UV cache path (use empty string to clear)")
|
|
398
446
|
config_parser.add_argument("--show", action="store_true", help="Show current configuration")
|
|
399
447
|
config_parser.set_defaults(func=global_cmds.config)
|
|
@@ -437,22 +485,24 @@ def _add_global_commands(subparsers: argparse._SubParsersAction) -> None:
|
|
|
437
485
|
orch_parser.set_defaults(func=_make_help_func(orch_parser))
|
|
438
486
|
|
|
439
487
|
# orch status
|
|
440
|
-
orch_status_parser = orch_subparsers.add_parser("status", help="Show orchestrator
|
|
488
|
+
orch_status_parser = orch_subparsers.add_parser("status", help="Show environment runtime status (legacy orchestrator fallback)")
|
|
441
489
|
orch_status_parser.add_argument("--json", action="store_true", help="Output as JSON")
|
|
442
490
|
orch_status_parser.set_defaults(func=global_cmds.orch_status)
|
|
443
491
|
|
|
444
492
|
# orch restart
|
|
445
|
-
orch_restart_parser = orch_subparsers.add_parser("restart", help="Restart ComfyUI")
|
|
493
|
+
orch_restart_parser = orch_subparsers.add_parser("restart", help="Restart idle ComfyUI through its cg run supervisor")
|
|
446
494
|
orch_restart_parser.add_argument("--wait", action="store_true", help="Wait for restart to complete")
|
|
495
|
+
orch_restart_parser.add_argument("--timeout", type=float, default=180, help="Maximum readiness wait in seconds")
|
|
496
|
+
orch_restart_parser.add_argument("--json", action="store_true", help="Output acknowledgement or verified readiness as JSON")
|
|
447
497
|
orch_restart_parser.set_defaults(func=global_cmds.orch_restart)
|
|
448
498
|
|
|
449
499
|
# orch kill
|
|
450
|
-
orch_kill_parser = orch_subparsers.add_parser("kill", help="Shutdown orchestrator")
|
|
500
|
+
orch_kill_parser = orch_subparsers.add_parser("kill", help="Shutdown the legacy orchestrator (not cg run)")
|
|
451
501
|
orch_kill_parser.add_argument("--force", action="store_true", help="Force kill (bypass command queue)")
|
|
452
502
|
orch_kill_parser.set_defaults(func=global_cmds.orch_kill)
|
|
453
503
|
|
|
454
504
|
# orch clean
|
|
455
|
-
orch_clean_parser = orch_subparsers.add_parser("clean", help="Clean orchestrator state")
|
|
505
|
+
orch_clean_parser = orch_subparsers.add_parser("clean", help="Clean legacy orchestrator state")
|
|
456
506
|
orch_clean_parser.add_argument("--dry-run", action="store_true", help="Show what would be deleted")
|
|
457
507
|
orch_clean_parser.add_argument("--force", action="store_true", help="Skip confirmation")
|
|
458
508
|
orch_clean_parser.add_argument("--kill", action="store_true", help="Also kill orchestrator process")
|
|
@@ -497,6 +547,13 @@ def _add_env_commands(subparsers: argparse._SubParsersAction) -> None:
|
|
|
497
547
|
create_parser.add_argument("--template", type=Path, help="Template manifest")
|
|
498
548
|
create_parser.add_argument("--python", default="3.11", help="Python version")
|
|
499
549
|
create_parser.add_argument("--comfyui", help="ComfyUI version")
|
|
550
|
+
create_parser.add_argument(
|
|
551
|
+
"--comfyui-repository",
|
|
552
|
+
help=(
|
|
553
|
+
"ComfyUI Git repository URL. Use with --comfyui to pin a fork "
|
|
554
|
+
"or alternate upstream; defaults to canonical ComfyUI."
|
|
555
|
+
),
|
|
556
|
+
)
|
|
500
557
|
create_parser.add_argument(
|
|
501
558
|
"--torch-backend",
|
|
502
559
|
default="auto",
|
|
@@ -1065,10 +1122,24 @@ def _add_env_commands(subparsers: argparse._SubParsersAction) -> None:
|
|
|
1065
1122
|
workflow_resolve_parser = workflow_subparsers.add_parser("resolve", help="Resolve workflow dependencies (nodes & models)")
|
|
1066
1123
|
workflow_resolve_parser.add_argument("name", help="Workflow name to resolve").completer = workflow_completer # type: ignore[attr-defined]
|
|
1067
1124
|
workflow_resolve_parser.add_argument("--auto", action="store_true", help="Auto-resolve without interaction")
|
|
1125
|
+
workflow_resolve_parser.add_argument("--json", action="store_true", help="JSON result on stdout; requires --auto and --install/--no-install")
|
|
1126
|
+
workflow_resolve_parser.add_argument("--strict", action="store_true", help="Exit 1 when dependencies remain unresolved or uninstalled")
|
|
1068
1127
|
workflow_resolve_parser.add_argument("--install", action="store_true", help="Auto-install missing nodes without prompting")
|
|
1069
1128
|
workflow_resolve_parser.add_argument("--no-install", action="store_true", help="Skip node installation prompt")
|
|
1070
1129
|
workflow_resolve_parser.set_defaults(func=env_cmds.workflow_resolve)
|
|
1071
1130
|
|
|
1131
|
+
workflow_node_parser = workflow_subparsers.add_parser("node", help="Manage explicit node ownership mappings")
|
|
1132
|
+
mapping_parsers = workflow_node_parser.add_subparsers(dest="mapping_command", required=True)
|
|
1133
|
+
for operation in ("map", "unmap", "list"):
|
|
1134
|
+
mapping_parser = mapping_parsers.add_parser(operation)
|
|
1135
|
+
mapping_parser.add_argument("name", help="Workflow name")
|
|
1136
|
+
if operation != "list":
|
|
1137
|
+
mapping_parser.add_argument("node_type", help="ComfyUI registered node class name")
|
|
1138
|
+
if operation == "map":
|
|
1139
|
+
mapping_parser.add_argument("package", help="Tracked node package identifier")
|
|
1140
|
+
mapping_parser.add_argument("--json", action="store_true")
|
|
1141
|
+
mapping_parser.set_defaults(func=env_cmds.workflow_node_mapping)
|
|
1142
|
+
|
|
1072
1143
|
# workflow model importance
|
|
1073
1144
|
workflow_importance_parser = workflow_subparsers.add_parser(
|
|
1074
1145
|
"model",
|
|
@@ -20,8 +20,8 @@ from comfygit_core.models import (
|
|
|
20
20
|
)
|
|
21
21
|
from comfygit_core.runtime import (
|
|
22
22
|
ACTIVE_TORCH_BACKEND_OVERRIDE_ENV,
|
|
23
|
+
ManagedRuntimeController,
|
|
23
24
|
SwitchObserverServer,
|
|
24
|
-
cleanup_supervisor_advertisement,
|
|
25
25
|
cleanup_switch_status,
|
|
26
26
|
read_switch_status,
|
|
27
27
|
resolve_comfyui_endpoint,
|
|
@@ -259,6 +259,7 @@ class EnvironmentCommands:
|
|
|
259
259
|
workspace.create_environment(
|
|
260
260
|
name=args.name,
|
|
261
261
|
comfyui_version=args.comfyui,
|
|
262
|
+
comfyui_repository=getattr(args, "comfyui_repository", None),
|
|
262
263
|
python_version=args.python,
|
|
263
264
|
template_path=args.template,
|
|
264
265
|
torch_backend=args.torch_backend,
|
|
@@ -595,6 +596,9 @@ class EnvironmentCommands:
|
|
|
595
596
|
extras = getattr(args, 'extra', None) or []
|
|
596
597
|
all_extras = getattr(args, 'all_extras', False)
|
|
597
598
|
overlay_names = getattr(args, 'overlay', None) or []
|
|
599
|
+
self._managed_runtime = ManagedRuntimeController(
|
|
600
|
+
env.name, resolve_comfyui_endpoint(base_comfyui_args), self.workspace.path,
|
|
601
|
+
)
|
|
598
602
|
supervisor_control = self._start_supervisor_control(base_comfyui_args)
|
|
599
603
|
if supervisor_control:
|
|
600
604
|
atexit.register(supervisor_control.stop)
|
|
@@ -611,6 +615,9 @@ class EnvironmentCommands:
|
|
|
611
615
|
# replacing `env`, so derive backend-specific launch args per target.
|
|
612
616
|
torch_backend, was_probed = self._get_or_probe_backend(env, torch_backend_override)
|
|
613
617
|
comfyui_args = self._comfyui_args_for_backend(base_comfyui_args, torch_backend)
|
|
618
|
+
self._managed_runtime.configure(env.name, resolve_comfyui_endpoint(comfyui_args))
|
|
619
|
+
if supervisor_control:
|
|
620
|
+
supervisor_control.advertise_runtime()
|
|
614
621
|
|
|
615
622
|
if torch_backend_override:
|
|
616
623
|
print(f"🔧 Using PyTorch backend override: {torch_backend}")
|
|
@@ -653,6 +660,7 @@ class EnvironmentCommands:
|
|
|
653
660
|
if comfyui_args:
|
|
654
661
|
print(f" Arguments: {' '.join(comfyui_args)}")
|
|
655
662
|
|
|
663
|
+
self._managed_runtime.launching()
|
|
656
664
|
if switch_source_env:
|
|
657
665
|
result = self._run_switched_comfyui(
|
|
658
666
|
env,
|
|
@@ -668,6 +676,7 @@ class EnvironmentCommands:
|
|
|
668
676
|
backend_override=torch_backend_override,
|
|
669
677
|
)
|
|
670
678
|
|
|
679
|
+
self._managed_runtime.exited()
|
|
671
680
|
if result.returncode == RESTART_EXIT_CODE:
|
|
672
681
|
print("\n🔄 Restart requested, syncing dependencies...\n")
|
|
673
682
|
no_sync = False # Ensure sync runs on restart
|
|
@@ -696,7 +705,6 @@ class EnvironmentCommands:
|
|
|
696
705
|
explicit_port = port_text is not None
|
|
697
706
|
|
|
698
707
|
if port_text and port_text.lower() in {"0", "off", "false", "disabled"}:
|
|
699
|
-
cleanup_supervisor_advertisement(self.workspace.path)
|
|
700
708
|
return None
|
|
701
709
|
|
|
702
710
|
if port_text:
|
|
@@ -704,7 +712,6 @@ class EnvironmentCommands:
|
|
|
704
712
|
candidate_ports = [int(port_text)]
|
|
705
713
|
except ValueError:
|
|
706
714
|
print(f"⚠️ Invalid COMFYGIT_SUPERVISOR_CONTROL_PORT={port_text!r}; supervisor control disabled")
|
|
707
|
-
cleanup_supervisor_advertisement(self.workspace.path)
|
|
708
715
|
return None
|
|
709
716
|
else:
|
|
710
717
|
start_port = min(max(endpoint.port + 1, 1), 65535)
|
|
@@ -720,6 +727,7 @@ class EnvironmentCommands:
|
|
|
720
727
|
host,
|
|
721
728
|
port,
|
|
722
729
|
public_origin=public_origin,
|
|
730
|
+
runtime_controller=getattr(self, "_managed_runtime", None),
|
|
723
731
|
)
|
|
724
732
|
try:
|
|
725
733
|
control.start()
|
|
@@ -738,7 +746,6 @@ class EnvironmentCommands:
|
|
|
738
746
|
"⚠️ Could not start supervisor control server on "
|
|
739
747
|
f"{host}:{candidate_ports[0]}-{candidate_ports[-1]}: {last_error}"
|
|
740
748
|
)
|
|
741
|
-
cleanup_supervisor_advertisement(self.workspace.path)
|
|
742
749
|
return None
|
|
743
750
|
|
|
744
751
|
def _append_switch_log(
|
|
@@ -3732,8 +3739,64 @@ class EnvironmentCommands:
|
|
|
3732
3739
|
print(f"✗ Invalid selection: {choice}")
|
|
3733
3740
|
return None
|
|
3734
3741
|
|
|
3735
|
-
@with_env_logging("workflow resolve", get_env_name=lambda self, args: self._get_env(args).name)
|
|
3736
3742
|
def workflow_resolve(self, args: argparse.Namespace, logger=None) -> None:
|
|
3743
|
+
"""Resolve with optional machine-readable, strict completion reporting."""
|
|
3744
|
+
import contextlib
|
|
3745
|
+
import json
|
|
3746
|
+
|
|
3747
|
+
json_output = getattr(args, "json", False)
|
|
3748
|
+
strict = getattr(args, "strict", False)
|
|
3749
|
+
if json_output and not args.auto:
|
|
3750
|
+
print("--json requires --auto (use explicit mappings for unknown nodes)", file=sys.stderr)
|
|
3751
|
+
raise SystemExit(2)
|
|
3752
|
+
if json_output and not (args.install or args.no_install):
|
|
3753
|
+
print("--json requires --install or --no-install", file=sys.stderr)
|
|
3754
|
+
raise SystemExit(2)
|
|
3755
|
+
|
|
3756
|
+
try:
|
|
3757
|
+
with contextlib.redirect_stdout(sys.stderr) if json_output else contextlib.nullcontext():
|
|
3758
|
+
self._workflow_resolve(args)
|
|
3759
|
+
if not (json_output or strict):
|
|
3760
|
+
return
|
|
3761
|
+
# Re-analyze AFTER downloads/installs, rather than reporting the stale plan.
|
|
3762
|
+
env = self._get_env(args)
|
|
3763
|
+
_, result = env.analyze_workflow_dependencies(args.name)
|
|
3764
|
+
missing = env.get_uninstalled_nodes(workflow_name=args.name)
|
|
3765
|
+
failed = env.get_workflow_failed_downloads(args.name)
|
|
3766
|
+
from .utils.workflow_result import resolution_report
|
|
3767
|
+
report = resolution_report(result, missing, failed)
|
|
3768
|
+
except (Exception, SystemExit) as exc:
|
|
3769
|
+
if json_output:
|
|
3770
|
+
print(json.dumps({"schema_version": 1, "workflow": args.name,
|
|
3771
|
+
"complete": False, "error": "resolution_failed"}))
|
|
3772
|
+
raise exc
|
|
3773
|
+
if json_output:
|
|
3774
|
+
print(json.dumps(report, indent=2))
|
|
3775
|
+
if strict and not report["complete"]:
|
|
3776
|
+
raise SystemExit(1)
|
|
3777
|
+
|
|
3778
|
+
def workflow_node_mapping(self, args: argparse.Namespace) -> None:
|
|
3779
|
+
"""Explicit ownership edits through the public Environment facade."""
|
|
3780
|
+
import json
|
|
3781
|
+
|
|
3782
|
+
env = self._get_env(args)
|
|
3783
|
+
if not env.get_workflow_path(args.name).is_file():
|
|
3784
|
+
raise ValueError(f"Workflow not found: {args.name}")
|
|
3785
|
+
if args.mapping_command == "map":
|
|
3786
|
+
if env.get_manifest_node(args.package) is None:
|
|
3787
|
+
raise ValueError(f"Package is not tracked: {args.package}. Add or dev-link it first.")
|
|
3788
|
+
env.set_workflow_custom_node_mapping(args.name, args.node_type, args.package)
|
|
3789
|
+
elif args.mapping_command == "unmap":
|
|
3790
|
+
env.remove_workflow_custom_node_mapping(args.name, args.node_type)
|
|
3791
|
+
mappings = dict(env.get_workflow_custom_node_map(args.name))
|
|
3792
|
+
if args.json:
|
|
3793
|
+
print(json.dumps({"workflow": args.name, "custom_node_map": mappings}, indent=2))
|
|
3794
|
+
else:
|
|
3795
|
+
for node_type, package in sorted(mappings.items()):
|
|
3796
|
+
print(f"{node_type}: {package}")
|
|
3797
|
+
|
|
3798
|
+
@with_env_logging("workflow resolve", get_env_name=lambda self, args: self._get_env(args).name)
|
|
3799
|
+
def _workflow_resolve(self, args: argparse.Namespace, logger=None) -> None:
|
|
3737
3800
|
"""Resolve workflow dependencies interactively."""
|
|
3738
3801
|
env = self._get_env(args)
|
|
3739
3802
|
|
|
@@ -3923,7 +3986,7 @@ class EnvironmentCommands:
|
|
|
3923
3986
|
print(f" • {m.filename}")
|
|
3924
3987
|
|
|
3925
3988
|
print("\n💡 Next:")
|
|
3926
|
-
print(" Add Civitai API key: cg
|
|
3989
|
+
print(" Add Civitai API key: cg auth set civitai")
|
|
3927
3990
|
print(f" Try again: cg workflow resolve \"{args.name}\"")
|
|
3928
3991
|
print(" Or commit anyway: cg commit -m \"...\" --allow-issues")
|
|
3929
3992
|
else:
|