lcode-cli 0.42.0__tar.gz → 0.44.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.
- {lcode_cli-0.42.0 → lcode_cli-0.44.0}/CHANGELOG.md +32 -1
- {lcode_cli-0.42.0 → lcode_cli-0.44.0}/PKG-INFO +4 -3
- {lcode_cli-0.42.0 → lcode_cli-0.44.0}/README.md +3 -2
- {lcode_cli-0.42.0 → lcode_cli-0.44.0}/docs/configuration.md +1 -0
- {lcode_cli-0.42.0 → lcode_cli-0.44.0}/docs/modes.md +75 -10
- {lcode_cli-0.42.0 → lcode_cli-0.44.0}/docs/quickstart.md +1 -1
- {lcode_cli-0.42.0 → lcode_cli-0.44.0}/docs/usage.md +2 -0
- {lcode_cli-0.42.0 → lcode_cli-0.44.0}/src/lcode/__init__.py +1 -1
- {lcode_cli-0.42.0 → lcode_cli-0.44.0}/src/lcode/agent.py +8 -2
- {lcode_cli-0.42.0 → lcode_cli-0.44.0}/src/lcode/api.py +1 -0
- {lcode_cli-0.42.0 → lcode_cli-0.44.0}/src/lcode/cli.py +9 -13
- {lcode_cli-0.42.0 → lcode_cli-0.44.0}/src/lcode/comfy.py +3 -2
- {lcode_cli-0.42.0 → lcode_cli-0.44.0}/src/lcode/config.py +4 -3
- lcode_cli-0.44.0/src/lcode/edits.py +283 -0
- {lcode_cli-0.42.0 → lcode_cli-0.44.0}/src/lcode/imageopts.py +21 -2
- lcode_cli-0.44.0/src/lcode/media.py +767 -0
- {lcode_cli-0.42.0 → lcode_cli-0.44.0}/src/lcode/media.toml +70 -2
- {lcode_cli-0.42.0 → lcode_cli-0.44.0}/src/lcode/media_catalog.py +13 -0
- {lcode_cli-0.42.0 → lcode_cli-0.44.0}/src/lcode/modes.py +9 -9
- {lcode_cli-0.42.0 → lcode_cli-0.44.0}/src/lcode/repl.py +137 -52
- lcode_cli-0.44.0/src/lcode/workflows/remove-background.json +13 -0
- lcode_cli-0.44.0/src/lcode/workflows/upscale-esrgan.json +12 -0
- lcode_cli-0.44.0/src/lcode/workflows/wan22-ti2v-5b.json +152 -0
- {lcode_cli-0.42.0 → lcode_cli-0.44.0}/tests/comfy_standin.py +22 -1
- {lcode_cli-0.42.0 → lcode_cli-0.44.0}/tests/test_comfy.py +1 -1
- lcode_cli-0.44.0/tests/test_image_edit.py +214 -0
- {lcode_cli-0.42.0 → lcode_cli-0.44.0}/tests/test_media_catalog.py +14 -4
- {lcode_cli-0.42.0 → lcode_cli-0.44.0}/tests/test_modes.py +12 -16
- lcode_cli-0.44.0/tests/test_video.py +145 -0
- lcode_cli-0.42.0/src/lcode/media.py +0 -473
- {lcode_cli-0.42.0 → lcode_cli-0.44.0}/.editorconfig +0 -0
- {lcode_cli-0.42.0 → lcode_cli-0.44.0}/.github/CODEOWNERS +0 -0
- {lcode_cli-0.42.0 → lcode_cli-0.44.0}/.github/ISSUE_TEMPLATE/bug_report.yml +0 -0
- {lcode_cli-0.42.0 → lcode_cli-0.44.0}/.github/ISSUE_TEMPLATE/config.yml +0 -0
- {lcode_cli-0.42.0 → lcode_cli-0.44.0}/.github/ISSUE_TEMPLATE/feature_request.yml +0 -0
- {lcode_cli-0.42.0 → lcode_cli-0.44.0}/.github/ISSUE_TEMPLATE/model_request.yml +0 -0
- {lcode_cli-0.42.0 → lcode_cli-0.44.0}/.github/PULL_REQUEST_TEMPLATE.md +0 -0
- {lcode_cli-0.42.0 → lcode_cli-0.44.0}/.github/dependabot.yml +0 -0
- {lcode_cli-0.42.0 → lcode_cli-0.44.0}/.github/workflows/ci.yml +0 -0
- {lcode_cli-0.42.0 → lcode_cli-0.44.0}/.github/workflows/docs.yml +0 -0
- {lcode_cli-0.42.0 → lcode_cli-0.44.0}/.github/workflows/release.yml +0 -0
- {lcode_cli-0.42.0 → lcode_cli-0.44.0}/.gitignore +0 -0
- {lcode_cli-0.42.0 → lcode_cli-0.44.0}/.pre-commit-config.yaml +0 -0
- {lcode_cli-0.42.0 → lcode_cli-0.44.0}/AGENTS.md +0 -0
- {lcode_cli-0.42.0 → lcode_cli-0.44.0}/CODE_OF_CONDUCT.md +0 -0
- {lcode_cli-0.42.0 → lcode_cli-0.44.0}/CONTRIBUTING.md +0 -0
- {lcode_cli-0.42.0 → lcode_cli-0.44.0}/LICENSE +0 -0
- {lcode_cli-0.42.0 → lcode_cli-0.44.0}/SECURITY.md +0 -0
- {lcode_cli-0.42.0 → lcode_cli-0.44.0}/action.yml +0 -0
- {lcode_cli-0.42.0 → lcode_cli-0.44.0}/docs/agents.md +0 -0
- {lcode_cli-0.42.0 → lcode_cli-0.44.0}/docs/assets/demo.svg +0 -0
- {lcode_cli-0.42.0 → lcode_cli-0.44.0}/docs/assets/extra.css +0 -0
- {lcode_cli-0.42.0 → lcode_cli-0.44.0}/docs/automation.md +0 -0
- {lcode_cli-0.42.0 → lcode_cli-0.44.0}/docs/bench.md +0 -0
- {lcode_cli-0.42.0 → lcode_cli-0.44.0}/docs/changelog.md +0 -0
- {lcode_cli-0.42.0 → lcode_cli-0.44.0}/docs/commands.md +0 -0
- {lcode_cli-0.42.0 → lcode_cli-0.44.0}/docs/contributing.md +0 -0
- {lcode_cli-0.42.0 → lcode_cli-0.44.0}/docs/editors.md +0 -0
- {lcode_cli-0.42.0 → lcode_cli-0.44.0}/docs/git.md +0 -0
- {lcode_cli-0.42.0 → lcode_cli-0.44.0}/docs/hooks.md +0 -0
- {lcode_cli-0.42.0 → lcode_cli-0.44.0}/docs/how-it-works.md +0 -0
- {lcode_cli-0.42.0 → lcode_cli-0.44.0}/docs/index.md +0 -0
- {lcode_cli-0.42.0 → lcode_cli-0.44.0}/docs/installation.md +0 -0
- {lcode_cli-0.42.0 → lcode_cli-0.44.0}/docs/lsp.md +0 -0
- {lcode_cli-0.42.0 → lcode_cli-0.44.0}/docs/mcp.md +0 -0
- {lcode_cli-0.42.0 → lcode_cli-0.44.0}/docs/memory.md +0 -0
- {lcode_cli-0.42.0 → lcode_cli-0.44.0}/docs/models.md +0 -0
- {lcode_cli-0.42.0 → lcode_cli-0.44.0}/docs/sandbox.md +0 -0
- {lcode_cli-0.42.0 → lcode_cli-0.44.0}/docs/search.md +0 -0
- {lcode_cli-0.42.0 → lcode_cli-0.44.0}/docs/servers.md +0 -0
- {lcode_cli-0.42.0 → lcode_cli-0.44.0}/docs/troubleshooting.md +0 -0
- {lcode_cli-0.42.0 → lcode_cli-0.44.0}/examples/README.md +0 -0
- {lcode_cli-0.42.0 → lcode_cli-0.44.0}/examples/api/fix_tests.py +0 -0
- {lcode_cli-0.42.0 → lcode_cli-0.44.0}/examples/commands/review.md +0 -0
- {lcode_cli-0.42.0 → lcode_cli-0.44.0}/examples/skills/commit-message/SKILL.md +0 -0
- {lcode_cli-0.42.0 → lcode_cli-0.44.0}/examples/skills/commit-message/scripts/staged.sh +0 -0
- {lcode_cli-0.42.0 → lcode_cli-0.44.0}/install.sh +0 -0
- {lcode_cli-0.42.0 → lcode_cli-0.44.0}/mkdocs.yml +0 -0
- {lcode_cli-0.42.0 → lcode_cli-0.44.0}/overrides/main.html +0 -0
- {lcode_cli-0.42.0 → lcode_cli-0.44.0}/pyproject.toml +0 -0
- {lcode_cli-0.42.0 → lcode_cli-0.44.0}/scripts/make_logos.py +0 -0
- {lcode_cli-0.42.0 → lcode_cli-0.44.0}/scripts/record_demo.py +0 -0
- {lcode_cli-0.42.0 → lcode_cli-0.44.0}/scripts/social-preview.html +0 -0
- {lcode_cli-0.42.0 → lcode_cli-0.44.0}/src/lcode/__main__.py +0 -0
- {lcode_cli-0.42.0 → lcode_cli-0.44.0}/src/lcode/acp.py +0 -0
- {lcode_cli-0.42.0 → lcode_cli-0.44.0}/src/lcode/action.py +0 -0
- {lcode_cli-0.42.0 → lcode_cli-0.44.0}/src/lcode/backends.py +0 -0
- {lcode_cli-0.42.0 → lcode_cli-0.44.0}/src/lcode/bench.py +0 -0
- {lcode_cli-0.42.0 → lcode_cli-0.44.0}/src/lcode/bench_backend.py +0 -0
- {lcode_cli-0.42.0 → lcode_cli-0.44.0}/src/lcode/bench_runtime.py +0 -0
- {lcode_cli-0.42.0 → lcode_cli-0.44.0}/src/lcode/catalog.py +0 -0
- {lcode_cli-0.42.0 → lcode_cli-0.44.0}/src/lcode/checkpoints.py +0 -0
- {lcode_cli-0.42.0 → lcode_cli-0.44.0}/src/lcode/checks.py +0 -0
- {lcode_cli-0.42.0 → lcode_cli-0.44.0}/src/lcode/clipboard.py +0 -0
- {lcode_cli-0.42.0 → lcode_cli-0.44.0}/src/lcode/cloud.py +0 -0
- {lcode_cli-0.42.0 → lcode_cli-0.44.0}/src/lcode/codesearch.py +0 -0
- {lcode_cli-0.42.0 → lcode_cli-0.44.0}/src/lcode/context.py +0 -0
- {lcode_cli-0.42.0 → lcode_cli-0.44.0}/src/lcode/escalate.py +0 -0
- {lcode_cli-0.42.0 → lcode_cli-0.44.0}/src/lcode/extensions.py +0 -0
- {lcode_cli-0.42.0 → lcode_cli-0.44.0}/src/lcode/frontmatter.py +0 -0
- {lcode_cli-0.42.0 → lcode_cli-0.44.0}/src/lcode/gitflow.py +0 -0
- {lcode_cli-0.42.0 → lcode_cli-0.44.0}/src/lcode/hardware.py +0 -0
- {lcode_cli-0.42.0 → lcode_cli-0.44.0}/src/lcode/hooks.py +0 -0
- {lcode_cli-0.42.0 → lcode_cli-0.44.0}/src/lcode/jobs.py +0 -0
- {lcode_cli-0.42.0 → lcode_cli-0.44.0}/src/lcode/limits.py +0 -0
- {lcode_cli-0.42.0 → lcode_cli-0.44.0}/src/lcode/lsp.py +0 -0
- {lcode_cli-0.42.0 → lcode_cli-0.44.0}/src/lcode/matching.py +0 -0
- {lcode_cli-0.42.0 → lcode_cli-0.44.0}/src/lcode/mcp/__init__.py +0 -0
- {lcode_cli-0.42.0 → lcode_cli-0.44.0}/src/lcode/mcp/auth.py +0 -0
- {lcode_cli-0.42.0 → lcode_cli-0.44.0}/src/lcode/mcp/catalog.py +0 -0
- {lcode_cli-0.42.0 → lcode_cli-0.44.0}/src/lcode/mcp/catalog.toml +0 -0
- {lcode_cli-0.42.0 → lcode_cli-0.44.0}/src/lcode/mcp/client.py +0 -0
- {lcode_cli-0.42.0 → lcode_cli-0.44.0}/src/lcode/mcp/commands.py +0 -0
- {lcode_cli-0.42.0 → lcode_cli-0.44.0}/src/lcode/mcp/config.py +0 -0
- {lcode_cli-0.42.0 → lcode_cli-0.44.0}/src/lcode/mcp/http.py +0 -0
- {lcode_cli-0.42.0 → lcode_cli-0.44.0}/src/lcode/mcp/manager.py +0 -0
- {lcode_cli-0.42.0 → lcode_cli-0.44.0}/src/lcode/mcp/protocol.py +0 -0
- {lcode_cli-0.42.0 → lcode_cli-0.44.0}/src/lcode/mcp/server.py +0 -0
- {lcode_cli-0.42.0 → lcode_cli-0.44.0}/src/lcode/mcp/stdio.py +0 -0
- {lcode_cli-0.42.0 → lcode_cli-0.44.0}/src/lcode/memory.py +0 -0
- {lcode_cli-0.42.0 → lcode_cli-0.44.0}/src/lcode/models.toml +0 -0
- {lcode_cli-0.42.0 → lcode_cli-0.44.0}/src/lcode/notify.py +0 -0
- {lcode_cli-0.42.0 → lcode_cli-0.44.0}/src/lcode/ollama.py +0 -0
- {lcode_cli-0.42.0 → lcode_cli-0.44.0}/src/lcode/permissions.py +0 -0
- {lcode_cli-0.42.0 → lcode_cli-0.44.0}/src/lcode/planning.py +0 -0
- {lcode_cli-0.42.0 → lcode_cli-0.44.0}/src/lcode/preview.py +0 -0
- {lcode_cli-0.42.0 → lcode_cli-0.44.0}/src/lcode/render.py +0 -0
- {lcode_cli-0.42.0 → lcode_cli-0.44.0}/src/lcode/repeats.py +0 -0
- {lcode_cli-0.42.0 → lcode_cli-0.44.0}/src/lcode/repomap.py +0 -0
- {lcode_cli-0.42.0 → lcode_cli-0.44.0}/src/lcode/residency.py +0 -0
- {lcode_cli-0.42.0 → lcode_cli-0.44.0}/src/lcode/review.py +0 -0
- {lcode_cli-0.42.0 → lcode_cli-0.44.0}/src/lcode/sandbox.py +0 -0
- {lcode_cli-0.42.0 → lcode_cli-0.44.0}/src/lcode/screenshots.py +0 -0
- {lcode_cli-0.42.0 → lcode_cli-0.44.0}/src/lcode/secretscan.py +0 -0
- {lcode_cli-0.42.0 → lcode_cli-0.44.0}/src/lcode/servers/__init__.py +0 -0
- {lcode_cli-0.42.0 → lcode_cli-0.44.0}/src/lcode/servers/encord.py +0 -0
- {lcode_cli-0.42.0 → lcode_cli-0.44.0}/src/lcode/servers/valohai.py +0 -0
- {lcode_cli-0.42.0 → lcode_cli-0.44.0}/src/lcode/servers/xai.py +0 -0
- {lcode_cli-0.42.0 → lcode_cli-0.44.0}/src/lcode/sessions.py +0 -0
- {lcode_cli-0.42.0 → lcode_cli-0.44.0}/src/lcode/steer.py +0 -0
- {lcode_cli-0.42.0 → lcode_cli-0.44.0}/src/lcode/subagents.py +0 -0
- {lcode_cli-0.42.0 → lcode_cli-0.44.0}/src/lcode/tools.py +0 -0
- {lcode_cli-0.42.0 → lcode_cli-0.44.0}/src/lcode/unreachable.py +0 -0
- {lcode_cli-0.42.0 → lcode_cli-0.44.0}/src/lcode/update.py +0 -0
- {lcode_cli-0.42.0 → lcode_cli-0.44.0}/src/lcode/vision.py +0 -0
- {lcode_cli-0.42.0 → lcode_cli-0.44.0}/src/lcode/web.py +0 -0
- {lcode_cli-0.42.0 → lcode_cli-0.44.0}/src/lcode/workflows/__init__.py +0 -0
- {lcode_cli-0.42.0 → lcode_cli-0.44.0}/src/lcode/workflows/flux2-klein-4b-t2i.json +0 -0
- {lcode_cli-0.42.0 → lcode_cli-0.44.0}/src/lcode/workflows/z-image-turbo-t2i.json +0 -0
- {lcode_cli-0.42.0 → lcode_cli-0.44.0}/tests/conftest.py +0 -0
- {lcode_cli-0.42.0 → lcode_cli-0.44.0}/tests/fake_lsp_server.py +0 -0
- {lcode_cli-0.42.0 → lcode_cli-0.44.0}/tests/fake_mcp_server.py +0 -0
- {lcode_cli-0.42.0 → lcode_cli-0.44.0}/tests/test_acp.py +0 -0
- {lcode_cli-0.42.0 → lcode_cli-0.44.0}/tests/test_action.py +0 -0
- {lcode_cli-0.42.0 → lcode_cli-0.44.0}/tests/test_agent.py +0 -0
- {lcode_cli-0.42.0 → lcode_cli-0.44.0}/tests/test_api.py +0 -0
- {lcode_cli-0.42.0 → lcode_cli-0.44.0}/tests/test_backends.py +0 -0
- {lcode_cli-0.42.0 → lcode_cli-0.44.0}/tests/test_bench.py +0 -0
- {lcode_cli-0.42.0 → lcode_cli-0.44.0}/tests/test_catalog.py +0 -0
- {lcode_cli-0.42.0 → lcode_cli-0.44.0}/tests/test_checkpoints.py +0 -0
- {lcode_cli-0.42.0 → lcode_cli-0.44.0}/tests/test_checks.py +0 -0
- {lcode_cli-0.42.0 → lcode_cli-0.44.0}/tests/test_cli.py +0 -0
- {lcode_cli-0.42.0 → lcode_cli-0.44.0}/tests/test_clipboard.py +0 -0
- {lcode_cli-0.42.0 → lcode_cli-0.44.0}/tests/test_cloud.py +0 -0
- {lcode_cli-0.42.0 → lcode_cli-0.44.0}/tests/test_codesearch.py +0 -0
- {lcode_cli-0.42.0 → lcode_cli-0.44.0}/tests/test_config.py +0 -0
- {lcode_cli-0.42.0 → lcode_cli-0.44.0}/tests/test_context.py +0 -0
- {lcode_cli-0.42.0 → lcode_cli-0.44.0}/tests/test_context_picker.py +0 -0
- {lcode_cli-0.42.0 → lcode_cli-0.44.0}/tests/test_escalate.py +0 -0
- {lcode_cli-0.42.0 → lcode_cli-0.44.0}/tests/test_extensions.py +0 -0
- {lcode_cli-0.42.0 → lcode_cli-0.44.0}/tests/test_gitflow.py +0 -0
- {lcode_cli-0.42.0 → lcode_cli-0.44.0}/tests/test_hooks.py +0 -0
- {lcode_cli-0.42.0 → lcode_cli-0.44.0}/tests/test_image_generate.py +0 -0
- {lcode_cli-0.42.0 → lcode_cli-0.44.0}/tests/test_jobs.py +0 -0
- {lcode_cli-0.42.0 → lcode_cli-0.44.0}/tests/test_look.py +0 -0
- {lcode_cli-0.42.0 → lcode_cli-0.44.0}/tests/test_lsp.py +0 -0
- {lcode_cli-0.42.0 → lcode_cli-0.44.0}/tests/test_matching.py +0 -0
- {lcode_cli-0.42.0 → lcode_cli-0.44.0}/tests/test_mcp.py +0 -0
- {lcode_cli-0.42.0 → lcode_cli-0.44.0}/tests/test_memory.py +0 -0
- {lcode_cli-0.42.0 → lcode_cli-0.44.0}/tests/test_model_picker.py +0 -0
- {lcode_cli-0.42.0 → lcode_cli-0.44.0}/tests/test_permissions.py +0 -0
- {lcode_cli-0.42.0 → lcode_cli-0.44.0}/tests/test_plan_mode.py +0 -0
- {lcode_cli-0.42.0 → lcode_cli-0.44.0}/tests/test_repeats.py +0 -0
- {lcode_cli-0.42.0 → lcode_cli-0.44.0}/tests/test_repomap.py +0 -0
- {lcode_cli-0.42.0 → lcode_cli-0.44.0}/tests/test_residency.py +0 -0
- {lcode_cli-0.42.0 → lcode_cli-0.44.0}/tests/test_review.py +0 -0
- {lcode_cli-0.42.0 → lcode_cli-0.44.0}/tests/test_robustness.py +0 -0
- {lcode_cli-0.42.0 → lcode_cli-0.44.0}/tests/test_sandbox.py +0 -0
- {lcode_cli-0.42.0 → lcode_cli-0.44.0}/tests/test_screenshots.py +0 -0
- {lcode_cli-0.42.0 → lcode_cli-0.44.0}/tests/test_secretscan.py +0 -0
- {lcode_cli-0.42.0 → lcode_cli-0.44.0}/tests/test_servers.py +0 -0
- {lcode_cli-0.42.0 → lcode_cli-0.44.0}/tests/test_sessions.py +0 -0
- {lcode_cli-0.42.0 → lcode_cli-0.44.0}/tests/test_steer.py +0 -0
- {lcode_cli-0.42.0 → lcode_cli-0.44.0}/tests/test_stuck.py +0 -0
- {lcode_cli-0.42.0 → lcode_cli-0.44.0}/tests/test_subagents.py +0 -0
- {lcode_cli-0.42.0 → lcode_cli-0.44.0}/tests/test_tools.py +0 -0
- {lcode_cli-0.42.0 → lcode_cli-0.44.0}/tests/test_update.py +0 -0
- {lcode_cli-0.42.0 → lcode_cli-0.44.0}/tests/test_vision.py +0 -0
- {lcode_cli-0.42.0 → lcode_cli-0.44.0}/tests/test_web.py +0 -0
- {lcode_cli-0.42.0 → lcode_cli-0.44.0}/tests/test_xai.py +0 -0
- {lcode_cli-0.42.0 → lcode_cli-0.44.0}/uv.lock +0 -0
|
@@ -6,6 +6,35 @@ All notable changes to lcode are documented here. The format follows
|
|
|
6
6
|
|
|
7
7
|
## [Unreleased]
|
|
8
8
|
|
|
9
|
+
## [0.44.0] - 2026-10-24
|
|
10
|
+
|
|
11
|
+
### Added
|
|
12
|
+
|
|
13
|
+
- **Video mode makes videos** (#153). Describe a clip, or start it from a picture (`@photo.png`),
|
|
14
|
+
and Wan 2.2 TI2V 5B makes it on your GPU. See [Video mode](https://nasser1941.github.io/lcode/modes/#video-mode).
|
|
15
|
+
- **Options:** `--seconds` (1 to 8, 5 by default, 24 fps) plus the image options. Quality
|
|
16
|
+
presets: 864×480 in 12 or 20 steps, or 1280×704 in 30. A 5-second clip takes 100 to 150 s on a
|
|
17
|
+
12 GB laptop GPU. Clips are 16:9 (9:16 from an upright start image) unless you give a shape.
|
|
18
|
+
- **Results:** an MP4 with its settings in a JSON file next to it, in the session's gallery; the
|
|
19
|
+
first frame shows in the terminal, `/play` opens it, and `/vary`/`/again` make new clips.
|
|
20
|
+
- **`/animate 3`** in image mode makes a clip from image #3. `lcode media` lists video models, and
|
|
21
|
+
`/models` in video mode picks one (the `video_model` setting).
|
|
22
|
+
- With `notify` on, a long render ends with a desktop notification.
|
|
23
|
+
|
|
24
|
+
## [0.43.0] - 2026-10-24
|
|
25
|
+
|
|
26
|
+
### Added
|
|
27
|
+
|
|
28
|
+
- **Image mode edits pictures** (#152). See [Editing](https://nasser1941.github.io/lcode/modes/#editing).
|
|
29
|
+
- **Edit by instruction** (`/edit 3 make the sky purple`, or `@photo.png make the sky purple`)
|
|
30
|
+
and **references** (`@photo.png @#3 put the mug from image 1 on the table in image 2`), with
|
|
31
|
+
FLUX.2 klein 4B. `/use 3` makes every next request follow an image until `/use off`.
|
|
32
|
+
- **Inpainting** (`--mask mask.png`: only the white part changes) and **outpainting** (`/extend 3
|
|
33
|
+
--ar 16:9`, or by sides: only the new border is painted, the original stays as it was).
|
|
34
|
+
- **`/upscale 3`** (Real-ESRGAN, 2× or 4×) and **`/nobg 3`** (BiRefNet, a transparent PNG), installed
|
|
35
|
+
on first use. `/vary` on an edit makes new edits of the same images.
|
|
36
|
+
- ComfyUI's reasons for refusing a workflow now include its explanation, not just the input's name.
|
|
37
|
+
|
|
9
38
|
## [0.42.0] - 2026-10-24
|
|
10
39
|
|
|
11
40
|
### Added
|
|
@@ -940,7 +969,9 @@ First public release.
|
|
|
940
969
|
- `AGENTS.md` project instructions and `/init` to generate them.
|
|
941
970
|
- One-line installer for Linux and macOS.
|
|
942
971
|
|
|
943
|
-
[Unreleased]: https://github.com/nasser1941/lcode/compare/v0.
|
|
972
|
+
[Unreleased]: https://github.com/nasser1941/lcode/compare/v0.44.0...HEAD
|
|
973
|
+
[0.44.0]: https://github.com/nasser1941/lcode/compare/v0.43.0...v0.44.0
|
|
974
|
+
[0.43.0]: https://github.com/nasser1941/lcode/compare/v0.42.0...v0.43.0
|
|
944
975
|
[0.42.0]: https://github.com/nasser1941/lcode/compare/v0.41.0...v0.42.0
|
|
945
976
|
[0.41.0]: https://github.com/nasser1941/lcode/compare/v0.40.0...v0.41.0
|
|
946
977
|
[0.40.0]: https://github.com/nasser1941/lcode/compare/v0.39.0...v0.40.0
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.5
|
|
2
2
|
Name: lcode-cli
|
|
3
|
-
Version: 0.
|
|
3
|
+
Version: 0.44.0
|
|
4
4
|
Summary: A local-first terminal coding agent powered by open-weight models on your own GPU or Mac, via Ollama.
|
|
5
5
|
Project-URL: Homepage, https://nasser1941.github.io/lcode/
|
|
6
6
|
Project-URL: Documentation, https://nasser1941.github.io/lcode/
|
|
@@ -107,8 +107,9 @@ through [Ollama](https://ollama.com), and when it needs current information it c
|
|
|
107
107
|
`lcode --worktree` runs parallel sessions on one repository.
|
|
108
108
|
- **In your editor.** Zed, JetBrains IDEs, Neovim and other editors that speak the Agent Client
|
|
109
109
|
Protocol run lcode with `lcode acp`, with diffs and approvals in the editor.
|
|
110
|
-
- **Image
|
|
111
|
-
seconds
|
|
110
|
+
- **Image and video modes.** `/mode image`, describe a picture, and FLUX.2 klein 4B makes it on your
|
|
111
|
+
GPU in seconds; edit it, extend it, upscale it or cut it out. `/mode video` makes clips with
|
|
112
|
+
Wan 2.2, from a description or a start image. lcode drives ComfyUI itself
|
|
112
113
|
([modes](https://nasser1941.github.io/lcode/modes/)).
|
|
113
114
|
- **Automation.** `lcode -p --output json` for scripts and CI, a Python API (`from lcode import
|
|
114
115
|
Session`), and a GitHub Action that answers `@lcode` in issues and pull requests on your own
|
|
@@ -71,8 +71,9 @@ through [Ollama](https://ollama.com), and when it needs current information it c
|
|
|
71
71
|
`lcode --worktree` runs parallel sessions on one repository.
|
|
72
72
|
- **In your editor.** Zed, JetBrains IDEs, Neovim and other editors that speak the Agent Client
|
|
73
73
|
Protocol run lcode with `lcode acp`, with diffs and approvals in the editor.
|
|
74
|
-
- **Image
|
|
75
|
-
seconds
|
|
74
|
+
- **Image and video modes.** `/mode image`, describe a picture, and FLUX.2 klein 4B makes it on your
|
|
75
|
+
GPU in seconds; edit it, extend it, upscale it or cut it out. `/mode video` makes clips with
|
|
76
|
+
Wan 2.2, from a description or a start image. lcode drives ComfyUI itself
|
|
76
77
|
([modes](https://nasser1941.github.io/lcode/modes/)).
|
|
77
78
|
- **Automation.** `lcode -p --output json` for scripts and CI, a Python API (`from lcode import
|
|
78
79
|
Session`), and a GitHub Action that answers `@lcode` in issues and pull requests on your own
|
|
@@ -28,6 +28,7 @@ lcode config path # print the file location
|
|
|
28
28
|
| `comfyui_path` | (found) | Your ComfyUI folder, if lcode doesn't find it; lcode starts it when needed ([ComfyUI](modes.md#comfyui)) |
|
|
29
29
|
| `media_dir` | `.lcode/media` | Where images and videos go: a folder in the project, or an absolute path |
|
|
30
30
|
| `preview` | `auto` | Images in the terminal: `auto`, `kitty`, `iterm`, `blocks` (colour text) or `off` ([results](modes.md#results)) |
|
|
31
|
+
| `video_model` | `wan22-ti2v-5b` | The model video mode uses: a key from `lcode media` ([video mode](modes.md#video-mode)) |
|
|
31
32
|
| `image_model` | `flux2-klein-4b` | The model image mode uses: a key from `lcode media` ([image models](modes.md#image-models)) |
|
|
32
33
|
| `think` | `true` | Let the model reason before answering |
|
|
33
34
|
| `web` | `on` | Web search and page fetching: `on`, `ask` (before each search/website) or `off` |
|
|
@@ -5,8 +5,8 @@ lcode makes three kinds of things, each in its own mode with its own models:
|
|
|
5
5
|
| Mode | What it makes | The model doing the work |
|
|
6
6
|
|---|---|---|
|
|
7
7
|
| **code** (default) | Code: it reads, writes, runs and checks your project | A coding language model in Ollama (or another server) |
|
|
8
|
-
| **image** | Images from a description
|
|
9
|
-
| **video** |
|
|
8
|
+
| **image** | Images from a description, edits of your images (references, inpainting, outpainting), upscales and cut-outs | An image model, run by ComfyUI on your GPU |
|
|
9
|
+
| **video** | Video clips from a description or a start image | A video model, run by ComfyUI on your GPU |
|
|
10
10
|
|
|
11
11
|
```text
|
|
12
12
|
❯ /mode image
|
|
@@ -81,6 +81,8 @@ alone shows them.
|
|
|
81
81
|
- **Sessions:** the gallery and `/options` are saved with the session, so `lcode -c` or `/resume`
|
|
82
82
|
brings them back. An image session is listed under its first prompt.
|
|
83
83
|
|
|
84
|
+
### While it works
|
|
85
|
+
|
|
84
86
|
- **Progress:** the status line says what ComfyUI is doing (loading the model, reading the
|
|
85
87
|
prompt, drawing, decoding), the step, the time left and the time so far. If other jobs are ahead
|
|
86
88
|
in ComfyUI's queue, it says how many.
|
|
@@ -99,7 +101,75 @@ alone shows them.
|
|
|
99
101
|
- **No Ollama needed:** `lcode --mode image` starts even when Ollama isn't running or the coding
|
|
100
102
|
model isn't installed; `/mode code` then says what's missing.
|
|
101
103
|
|
|
102
|
-
|
|
104
|
+
### Editing
|
|
105
|
+
|
|
106
|
+
FLUX.2 klein 4B edits pictures as well as making them: it takes images as references and an
|
|
107
|
+
instruction as the prompt. When the chosen model can't edit (Z-Image Turbo), lcode hands edits to
|
|
108
|
+
FLUX.2 klein and says so.
|
|
109
|
+
|
|
110
|
+
```text
|
|
111
|
+
image ❯ /edit 1 make the mug matte black with a small gold star
|
|
112
|
+
◆ #2 .lcode/media/20261024-100504-make-the-mug-matte-black-with-a-small-go.png 1024×1024 · FLUX.2 klein 4B · seed 1798225303 · 6.1 s
|
|
113
|
+
image ❯ /extend 1 --ar 16:9
|
|
114
|
+
Extending #1 from 1024×1024 to 1824×1024 before scaling.
|
|
115
|
+
◆ #4 .lcode/media/…-extended.png 1360×768 · FLUX.2 klein 4B · seed 2994584653 · 6.4 s
|
|
116
|
+
image ❯ /nobg 2
|
|
117
|
+
◆ #6 .lcode/media/…-nobg.png 1024×1024 · BiRefNet · 0.7 s
|
|
118
|
+
```
|
|
119
|
+
|
|
120
|
+
| What | How | What happens |
|
|
121
|
+
|---|---|---|
|
|
122
|
+
| **Edit by instruction** | `/edit 3 make the sky purple` (the last image without a number), or `@photo.png make the sky purple` | The image goes in as a reference, the instruction is the prompt. The result keeps the image's shape unless you give one (`--ar`). |
|
|
123
|
+
| **References** | `@photo.png @#3 put the mug from image 1 on the table in image 2`, or `/edit 3 … @style.png` | Several images, in order ("image 1", "image 2" in the instruction): a subject, a style, a place. `@"a file with spaces.png"` works too. |
|
|
124
|
+
| **Keep following an image** | `/use 3` (or `/use photo.png`), then plain requests; `/use off` | Every request is an edit of those images until you stop it: handy for one subject in many scenes. |
|
|
125
|
+
| **Inpaint** | `@photo.png --mask mask.png make the sky purple` | Only where the mask image is white changes (with a soft edge); the rest stays exactly as it was. |
|
|
126
|
+
| **Outpaint** | `/extend 3 --ar 16:9`, or `/extend 3 --left 256 --top 128`, plus words about the new part | The canvas grows, the model paints only the new border, and the original is pasted back as it was. |
|
|
127
|
+
| **Upscale** | `/upscale 3` (2×) or `/upscale 3 4` | Real-ESRGAN, a few seconds: a 1024×1024 image becomes 2048×2048. |
|
|
128
|
+
| **Remove the background** | `/nobg 3` | BiRefNet cuts out the subject: a PNG with a transparent background. |
|
|
129
|
+
|
|
130
|
+
- **Follow-ups work on edits too:** `/vary` on an edit makes new edits of the same images with the
|
|
131
|
+
same instruction, and `/again` repeats the last request, edit or not.
|
|
132
|
+
- **The tools install on first use,** after you agree: Real-ESRGAN (0.07 GB) and BiRefNet (0.44 GB).
|
|
133
|
+
`lcode media` lists them under "Tools for images".
|
|
134
|
+
- **Text in images:** FLUX.2 klein and Z-Image Turbo write short text you put in quotes
|
|
135
|
+
(`a café sign that says "OPEN"`).
|
|
136
|
+
- **Measured** on the RTX 4080 Laptop GPU (12 GB): an edit takes 5 to 7 s, two references 10 s,
|
|
137
|
+
inpainting and outpainting 6 to 12 s, a 2× upscale 6 s, and a background cut-out under a second
|
|
138
|
+
once the tools are loaded.
|
|
139
|
+
|
|
140
|
+
## Video mode
|
|
141
|
+
|
|
142
|
+
Video mode works like image mode: what you type describes a clip, and **Wan 2.2 TI2V 5B** makes it on
|
|
143
|
+
your GPU. Start it from a picture with `@photo.png` (or `@#3`, an image from this session), and the
|
|
144
|
+
clip begins with that frame. From image mode, `/animate 3 the waves roll in` switches to video mode
|
|
145
|
+
and animates image #3.
|
|
146
|
+
|
|
147
|
+
```text
|
|
148
|
+
video ❯ waves rolling onto a beach at sunset --seconds 5
|
|
149
|
+
◆ #1 .lcode/media/20261024-….mp4 864×480 · Wan 2.2 TI2V 5B · seed 1234 · …
|
|
150
|
+
video ❯ /play
|
|
151
|
+
```
|
|
152
|
+
|
|
153
|
+
- **Options:** the image options work here too (`--n`, `--ar`, `--seed`, `--quality`, `--style`,
|
|
154
|
+
`--no`, and `/options`), plus `--seconds` (1 to 8; 5 by default, at 24 frames per second).
|
|
155
|
+
Clips are 16:9, or 9:16 from an upright start picture (cropped to it), unless you give a shape:
|
|
156
|
+
Wan 2.2 knows those two shapes best, and a square or small clip can break up into streaks.
|
|
157
|
+
- **Quality:** `fast` makes 864×480 in 12 steps, `balanced` (the default) 864×480 in 20 steps, and
|
|
158
|
+
`best` the model's own 1280×704 in 30 steps. Smaller than 864×480 breaks this model up into
|
|
159
|
+
streaks, so lcode doesn't go lower.
|
|
160
|
+
- **Camera moves:** describe them as shots ("slow zoom in", "dolly shot along the shore", "pan
|
|
161
|
+
left"). "The camera moves in" can put a camera in the picture.
|
|
162
|
+
- **Negative prompt:** Wan uses one. lcode passes Wan's own default (it avoids static, blurry,
|
|
163
|
+
over-exposed clips) unless you give `--no "…"`.
|
|
164
|
+
- **Results:** an MP4 with a JSON file next to it (prompt, seed, size, frames, fps, start image),
|
|
165
|
+
numbered in the session's gallery with the images. The first frame shows in the terminal.
|
|
166
|
+
`/play 4` opens a clip in your player, and `/vary` and `/again` make new clips from the same
|
|
167
|
+
description and start image.
|
|
168
|
+
- **Measured** on the RTX 4080 Laptop GPU (12 GB), a 5-second clip (121 frames): `fast` 100 s,
|
|
169
|
+
`balanced` 150 s (the same from a start image), `best` 10.5 minutes.
|
|
170
|
+
- **Long renders:** progress shows the step and the time left. With `notify` on, lcode sends a
|
|
171
|
+
desktop notification when a clip that took longer than `notify_after` seconds is done.
|
|
172
|
+
|
|
103
173
|
|
|
104
174
|
ComfyUI runs the image and video models; lcode drives it through its API.
|
|
105
175
|
|
|
@@ -196,13 +266,8 @@ themselves:
|
|
|
196
266
|
|
|
197
267
|
## Coming next
|
|
198
268
|
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
- **#150 Media model catalog** (image models done; video models come with video generation).
|
|
202
|
-
- **#151, #152 Image mode:** generating, variations, sizes and seeds, a gallery, editing,
|
|
203
|
-
references, inpainting, upscaling.
|
|
204
|
-
- **#153, #154 Video mode:** from text or a start image, first and last frames, several
|
|
205
|
-
references, camera moves, longer clips, sound.
|
|
269
|
+
- **#154 More video:** first and last frames, several references, camera moves, longer clips,
|
|
270
|
+
sound, and more video models in the catalog.
|
|
206
271
|
- **#155 Movies:** storyboards with a consistent cast, shots stitched into one film.
|
|
207
272
|
- **#156 Prompt assistant:** a small local model for prompts and follow-ups.
|
|
208
273
|
- **#157 Cloud generation**, with costs shown (Grok Imagine first).
|
|
@@ -82,6 +82,8 @@ reasoning is on.
|
|
|
82
82
|
| `/verbose` | Toggle showing the reasoning text |
|
|
83
83
|
| `/mode [code\|image\|video]` | Switch what lcode makes: [code, images or videos](modes.md) |
|
|
84
84
|
| `/options`, `/again`, `/vary N`, `/gallery`, `/open N` | Image mode: [options for the session, follow-ups on results](modes.md#results) |
|
|
85
|
+
| `/edit N`, `/use N`, `/extend N`, `/upscale N`, `/nobg N` | Image mode: [edit, follow, outpaint, upscale, cut out](modes.md#editing) |
|
|
86
|
+
| `/animate N`, `/play N` | [Video mode](modes.md#video-mode): animate image N; play a clip |
|
|
85
87
|
| `/permissions [ask\|plan\|auto-edit\|yolo]` | Set the permission mode |
|
|
86
88
|
| `/cd DIR` | Change the working directory |
|
|
87
89
|
| `/todos` | Show the model's task list |
|
|
@@ -309,6 +309,7 @@ class Settings:
|
|
|
309
309
|
comfyui_path: str | None = None # a ComfyUI install lcode doesn't find by itself (lcode.comfy)
|
|
310
310
|
media_dir: str = ".lcode/media" # where image and video mode save their files (lcode.media)
|
|
311
311
|
image_model: str = "flux2-klein-4b" # the media catalog's model image mode uses (lcode.media_catalog)
|
|
312
|
+
video_model: str = "wan22-ti2v-5b" # and video mode's
|
|
312
313
|
preview: str = "auto" # images in the terminal: auto, kitty, iterm, blocks or off (lcode.preview)
|
|
313
314
|
num_batch: int | None = None
|
|
314
315
|
keep_alive: str = "30m"
|
|
@@ -380,7 +381,8 @@ class Agent:
|
|
|
380
381
|
|
|
381
382
|
self.image_options = ImageOptions() # image mode's defaults for this session (/options)
|
|
382
383
|
self.media_results: list[dict] = [] # the session's images, numbered (/gallery, /vary, /open)
|
|
383
|
-
self.last_request:
|
|
384
|
+
self.last_request: dict | None = None # what /again repeats (lcode.media.redo)
|
|
385
|
+
self.image_refs: list[str] = [] # images every next request follows (/use)
|
|
384
386
|
self.reflected = 0 # messages before this index were already checked for notes to remember
|
|
385
387
|
self._memory: memory_notes.Memory | None = None
|
|
386
388
|
self._agent_types: tuple[Path, dict[str, subagents.AgentType], list[str]] | None = None
|
|
@@ -697,7 +699,8 @@ class Agent:
|
|
|
697
699
|
"model": self.settings.model,
|
|
698
700
|
"mode": self.settings.mode,
|
|
699
701
|
"image_model": self.settings.image_model,
|
|
700
|
-
"
|
|
702
|
+
"video_model": self.settings.video_model,
|
|
703
|
+
"media": {"results": self.media_results, "options": self.image_options.to_json(), "refs": self.image_refs},
|
|
701
704
|
"name": self.session_name,
|
|
702
705
|
"title": self.session_title,
|
|
703
706
|
"messages": self.messages,
|
|
@@ -748,9 +751,12 @@ class Agent:
|
|
|
748
751
|
self.settings.mode = data["mode"] # a session belongs to the mode it was made in
|
|
749
752
|
if isinstance(data.get("image_model"), str):
|
|
750
753
|
self.settings.image_model = data["image_model"]
|
|
754
|
+
if isinstance(data.get("video_model"), str):
|
|
755
|
+
self.settings.video_model = data["video_model"]
|
|
751
756
|
media = data.get("media") or {}
|
|
752
757
|
self.media_results = [r for r in media.get("results") or [] if isinstance(r, dict) and "path" in r]
|
|
753
758
|
self.image_options = type(self.image_options).from_json(media.get("options") or {})
|
|
759
|
+
self.image_refs = [r for r in media.get("refs") or [] if isinstance(r, str)]
|
|
754
760
|
self.session_title = data.get("title") or sessions.title_from(self.messages)
|
|
755
761
|
self.tools.read_mtimes.clear() # files may have changed since; the model must read them again
|
|
756
762
|
self.tools.todos = list(data.get("todos") or [])
|
|
@@ -201,6 +201,7 @@ def open_agent(cwd: Path, options: Options, console: Console, hw: Hardware | Non
|
|
|
201
201
|
comfyui_path=cfg["comfyui_path"],
|
|
202
202
|
media_dir=cfg["media_dir"],
|
|
203
203
|
image_model=cfg["image_model"],
|
|
204
|
+
video_model=cfg["video_model"],
|
|
204
205
|
preview=cfg["preview"],
|
|
205
206
|
web=switch(options.web, cfg["web"], "on"),
|
|
206
207
|
search_backend=cfg["search_backend"],
|
|
@@ -801,16 +801,8 @@ def media_request(agent, prompt: str, out: Console, quiet: bool) -> None:
|
|
|
801
801
|
"""`lcode --mode image -p "…"`: make the image, say where it went (or, with --output json, a result object)."""
|
|
802
802
|
import json
|
|
803
803
|
|
|
804
|
-
from lcode import api, media
|
|
804
|
+
from lcode import api, media
|
|
805
805
|
|
|
806
|
-
if agent.settings.mode == "video":
|
|
807
|
-
message = modes.COMING["video"]
|
|
808
|
-
if quiet:
|
|
809
|
-
print(json.dumps({"type": "result", "status": "error", "error": message}), flush=True)
|
|
810
|
-
else:
|
|
811
|
-
out.print(f"[yellow]{escape(message)}[/]")
|
|
812
|
-
api.close_agent(agent)
|
|
813
|
-
sys.exit(2)
|
|
814
806
|
try:
|
|
815
807
|
made = media.request(agent, prompt)
|
|
816
808
|
except (media.MediaError, KeyboardInterrupt) as e:
|
|
@@ -825,7 +817,7 @@ def media_request(agent, prompt: str, out: Console, quiet: bool) -> None:
|
|
|
825
817
|
result = {
|
|
826
818
|
"type": "result",
|
|
827
819
|
"status": "success",
|
|
828
|
-
"mode":
|
|
820
|
+
"mode": agent.settings.mode,
|
|
829
821
|
"files": [str(path) for one in made for path in one.files],
|
|
830
822
|
"model": made[0].model,
|
|
831
823
|
"seed": made[0].seed,
|
|
@@ -1106,10 +1098,14 @@ def cmd_media(args) -> None:
|
|
|
1106
1098
|
where = (
|
|
1107
1099
|
f"ComfyUI at {server.url}" if running else (f"{install.path} (not running)" if install else "no ComfyUI found")
|
|
1108
1100
|
)
|
|
1109
|
-
console.print(f"[dim]{hw.describe()} · {where} · image
|
|
1110
|
-
for mode in ("image", "video"):
|
|
1101
|
+
console.print(f"[dim]{hw.describe()} · {where} · image: {cfg['image_model']} · video: {cfg['video_model']}[/]\n")
|
|
1102
|
+
for mode in ("image", "video", "tool"):
|
|
1111
1103
|
models = cat.for_mode(mode)
|
|
1112
|
-
console.print(
|
|
1104
|
+
console.print(
|
|
1105
|
+
"[bold]Tools for images[/] [dim](/upscale, /nobg)[/]"
|
|
1106
|
+
if mode == "tool"
|
|
1107
|
+
else f"[bold]{mode.capitalize()} models[/]"
|
|
1108
|
+
)
|
|
1113
1109
|
if not models:
|
|
1114
1110
|
console.print(f" [dim]{media.SOON[mode]}[/]\n")
|
|
1115
1111
|
continue
|
|
@@ -336,8 +336,9 @@ def describe_rejection(r: requests.Response) -> str:
|
|
|
336
336
|
lines = [str((data.get("error") or {}).get("message") or "ComfyUI refused the workflow")]
|
|
337
337
|
for node, info in (data.get("node_errors") or {}).items():
|
|
338
338
|
for err in info.get("errors", [])[:3]:
|
|
339
|
-
detail = err.get("
|
|
340
|
-
|
|
339
|
+
message, detail = err.get("message") or "", err.get("details") or ""
|
|
340
|
+
why = f"{message}: {detail}" if message and detail and detail not in message else (detail or message)
|
|
341
|
+
lines.append(f"{info.get('class_type', 'node')} ({node}): {why}")
|
|
341
342
|
return "; ".join(lines)
|
|
342
343
|
|
|
343
344
|
|
|
@@ -46,6 +46,7 @@ SETTINGS: dict[str, tuple[object, type, str]] = {
|
|
|
46
46
|
"comfyui_path": (None, str, "your ComfyUI folder, if lcode doesn't find it (lcode starts it when needed)"),
|
|
47
47
|
"media_dir": (".lcode/media", str, "where images and videos go: a folder in the project, or an absolute path"),
|
|
48
48
|
"image_model": ("flux2-klein-4b", str, "the model image mode uses: a key from `lcode media`"),
|
|
49
|
+
"video_model": ("wan22-ti2v-5b", str, "the model video mode uses: a key from `lcode media`"),
|
|
49
50
|
"preview": ("auto", str, "images in the terminal: auto | kitty | iterm | blocks (colour text) | off"),
|
|
50
51
|
"think": (True, bool, "let the model reason before answering (slower, better)"),
|
|
51
52
|
"web": ("on", str, "web search and page fetching for the model: on | ask | off"),
|
|
@@ -217,12 +218,12 @@ def coerce(key: str, value: object) -> object:
|
|
|
217
218
|
|
|
218
219
|
if value not in PROTOCOLS:
|
|
219
220
|
raise ConfigError(f"preview must be one of {', '.join(PROTOCOLS)}")
|
|
220
|
-
if key
|
|
221
|
+
if key in ("image_model", "video_model"):
|
|
221
222
|
from lcode import media_catalog
|
|
222
223
|
|
|
223
|
-
keys = [m.key for m in media_catalog.load().for_mode("
|
|
224
|
+
keys = [m.key for m in media_catalog.load().for_mode(key.removesuffix("_model"))]
|
|
224
225
|
if value not in keys:
|
|
225
|
-
raise ConfigError(f"
|
|
226
|
+
raise ConfigError(f"{key} must be one of {', '.join(keys)} (see lcode media)")
|
|
226
227
|
if typ is bool and isinstance(value, str):
|
|
227
228
|
if value.lower() not in ("true", "false", "1", "0", "yes", "no", "on", "off"):
|
|
228
229
|
raise ConfigError(f"{key} must be true or false")
|