lcode-cli 0.38.0__tar.gz → 0.40.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.38.0 → lcode_cli-0.40.0}/CHANGELOG.md +52 -1
- {lcode_cli-0.38.0 → lcode_cli-0.40.0}/PKG-INFO +4 -1
- {lcode_cli-0.38.0 → lcode_cli-0.40.0}/README.md +3 -0
- {lcode_cli-0.38.0 → lcode_cli-0.40.0}/docs/configuration.md +4 -0
- {lcode_cli-0.38.0 → lcode_cli-0.40.0}/docs/mcp.md +5 -81
- lcode_cli-0.40.0/docs/modes.md +109 -0
- {lcode_cli-0.38.0 → lcode_cli-0.40.0}/docs/quickstart.md +1 -1
- {lcode_cli-0.38.0 → lcode_cli-0.40.0}/docs/usage.md +4 -3
- {lcode_cli-0.38.0 → lcode_cli-0.40.0}/mkdocs.yml +1 -0
- {lcode_cli-0.38.0 → lcode_cli-0.40.0}/src/lcode/__init__.py +1 -1
- {lcode_cli-0.38.0 → lcode_cli-0.40.0}/src/lcode/agent.py +9 -0
- {lcode_cli-0.38.0 → lcode_cli-0.40.0}/src/lcode/api.py +43 -11
- {lcode_cli-0.38.0 → lcode_cli-0.40.0}/src/lcode/cli.py +85 -0
- lcode_cli-0.40.0/src/lcode/comfy.py +658 -0
- {lcode_cli-0.38.0 → lcode_cli-0.40.0}/src/lcode/config.py +7 -0
- {lcode_cli-0.38.0 → lcode_cli-0.40.0}/src/lcode/mcp/catalog.toml +0 -48
- {lcode_cli-0.38.0 → lcode_cli-0.40.0}/src/lcode/mcp/commands.py +6 -0
- lcode_cli-0.40.0/src/lcode/media.py +262 -0
- lcode_cli-0.40.0/src/lcode/modes.py +124 -0
- {lcode_cli-0.38.0 → lcode_cli-0.40.0}/src/lcode/repl.py +116 -19
- lcode_cli-0.40.0/src/lcode/workflows/__init__.py +0 -0
- lcode_cli-0.40.0/src/lcode/workflows/flux2-klein-4b-t2i.json +38 -0
- lcode_cli-0.40.0/tests/comfy_standin.py +231 -0
- {lcode_cli-0.38.0 → lcode_cli-0.40.0}/tests/conftest.py +12 -1
- lcode_cli-0.40.0/tests/test_comfy.py +499 -0
- lcode_cli-0.40.0/tests/test_modes.py +165 -0
- {lcode_cli-0.38.0 → lcode_cli-0.40.0}/tests/test_xai.py +0 -11
- {lcode_cli-0.38.0 → lcode_cli-0.40.0}/.editorconfig +0 -0
- {lcode_cli-0.38.0 → lcode_cli-0.40.0}/.github/CODEOWNERS +0 -0
- {lcode_cli-0.38.0 → lcode_cli-0.40.0}/.github/ISSUE_TEMPLATE/bug_report.yml +0 -0
- {lcode_cli-0.38.0 → lcode_cli-0.40.0}/.github/ISSUE_TEMPLATE/config.yml +0 -0
- {lcode_cli-0.38.0 → lcode_cli-0.40.0}/.github/ISSUE_TEMPLATE/feature_request.yml +0 -0
- {lcode_cli-0.38.0 → lcode_cli-0.40.0}/.github/ISSUE_TEMPLATE/model_request.yml +0 -0
- {lcode_cli-0.38.0 → lcode_cli-0.40.0}/.github/PULL_REQUEST_TEMPLATE.md +0 -0
- {lcode_cli-0.38.0 → lcode_cli-0.40.0}/.github/dependabot.yml +0 -0
- {lcode_cli-0.38.0 → lcode_cli-0.40.0}/.github/workflows/ci.yml +0 -0
- {lcode_cli-0.38.0 → lcode_cli-0.40.0}/.github/workflows/docs.yml +0 -0
- {lcode_cli-0.38.0 → lcode_cli-0.40.0}/.github/workflows/release.yml +0 -0
- {lcode_cli-0.38.0 → lcode_cli-0.40.0}/.gitignore +0 -0
- {lcode_cli-0.38.0 → lcode_cli-0.40.0}/.pre-commit-config.yaml +0 -0
- {lcode_cli-0.38.0 → lcode_cli-0.40.0}/AGENTS.md +0 -0
- {lcode_cli-0.38.0 → lcode_cli-0.40.0}/CODE_OF_CONDUCT.md +0 -0
- {lcode_cli-0.38.0 → lcode_cli-0.40.0}/CONTRIBUTING.md +0 -0
- {lcode_cli-0.38.0 → lcode_cli-0.40.0}/LICENSE +0 -0
- {lcode_cli-0.38.0 → lcode_cli-0.40.0}/SECURITY.md +0 -0
- {lcode_cli-0.38.0 → lcode_cli-0.40.0}/action.yml +0 -0
- {lcode_cli-0.38.0 → lcode_cli-0.40.0}/docs/agents.md +0 -0
- {lcode_cli-0.38.0 → lcode_cli-0.40.0}/docs/assets/demo.svg +0 -0
- {lcode_cli-0.38.0 → lcode_cli-0.40.0}/docs/assets/extra.css +0 -0
- {lcode_cli-0.38.0 → lcode_cli-0.40.0}/docs/automation.md +0 -0
- {lcode_cli-0.38.0 → lcode_cli-0.40.0}/docs/bench.md +0 -0
- {lcode_cli-0.38.0 → lcode_cli-0.40.0}/docs/changelog.md +0 -0
- {lcode_cli-0.38.0 → lcode_cli-0.40.0}/docs/commands.md +0 -0
- {lcode_cli-0.38.0 → lcode_cli-0.40.0}/docs/contributing.md +0 -0
- {lcode_cli-0.38.0 → lcode_cli-0.40.0}/docs/editors.md +0 -0
- {lcode_cli-0.38.0 → lcode_cli-0.40.0}/docs/git.md +0 -0
- {lcode_cli-0.38.0 → lcode_cli-0.40.0}/docs/hooks.md +0 -0
- {lcode_cli-0.38.0 → lcode_cli-0.40.0}/docs/how-it-works.md +0 -0
- {lcode_cli-0.38.0 → lcode_cli-0.40.0}/docs/index.md +0 -0
- {lcode_cli-0.38.0 → lcode_cli-0.40.0}/docs/installation.md +0 -0
- {lcode_cli-0.38.0 → lcode_cli-0.40.0}/docs/lsp.md +0 -0
- {lcode_cli-0.38.0 → lcode_cli-0.40.0}/docs/memory.md +0 -0
- {lcode_cli-0.38.0 → lcode_cli-0.40.0}/docs/models.md +0 -0
- {lcode_cli-0.38.0 → lcode_cli-0.40.0}/docs/sandbox.md +0 -0
- {lcode_cli-0.38.0 → lcode_cli-0.40.0}/docs/search.md +0 -0
- {lcode_cli-0.38.0 → lcode_cli-0.40.0}/docs/servers.md +0 -0
- {lcode_cli-0.38.0 → lcode_cli-0.40.0}/docs/troubleshooting.md +0 -0
- {lcode_cli-0.38.0 → lcode_cli-0.40.0}/examples/README.md +0 -0
- {lcode_cli-0.38.0 → lcode_cli-0.40.0}/examples/api/fix_tests.py +0 -0
- {lcode_cli-0.38.0 → lcode_cli-0.40.0}/examples/commands/review.md +0 -0
- {lcode_cli-0.38.0 → lcode_cli-0.40.0}/examples/skills/commit-message/SKILL.md +0 -0
- {lcode_cli-0.38.0 → lcode_cli-0.40.0}/examples/skills/commit-message/scripts/staged.sh +0 -0
- {lcode_cli-0.38.0 → lcode_cli-0.40.0}/install.sh +0 -0
- {lcode_cli-0.38.0 → lcode_cli-0.40.0}/overrides/main.html +0 -0
- {lcode_cli-0.38.0 → lcode_cli-0.40.0}/pyproject.toml +0 -0
- {lcode_cli-0.38.0 → lcode_cli-0.40.0}/scripts/make_logos.py +0 -0
- {lcode_cli-0.38.0 → lcode_cli-0.40.0}/scripts/record_demo.py +0 -0
- {lcode_cli-0.38.0 → lcode_cli-0.40.0}/scripts/social-preview.html +0 -0
- {lcode_cli-0.38.0 → lcode_cli-0.40.0}/src/lcode/__main__.py +0 -0
- {lcode_cli-0.38.0 → lcode_cli-0.40.0}/src/lcode/acp.py +0 -0
- {lcode_cli-0.38.0 → lcode_cli-0.40.0}/src/lcode/action.py +0 -0
- {lcode_cli-0.38.0 → lcode_cli-0.40.0}/src/lcode/backends.py +0 -0
- {lcode_cli-0.38.0 → lcode_cli-0.40.0}/src/lcode/bench.py +0 -0
- {lcode_cli-0.38.0 → lcode_cli-0.40.0}/src/lcode/bench_backend.py +0 -0
- {lcode_cli-0.38.0 → lcode_cli-0.40.0}/src/lcode/bench_runtime.py +0 -0
- {lcode_cli-0.38.0 → lcode_cli-0.40.0}/src/lcode/catalog.py +0 -0
- {lcode_cli-0.38.0 → lcode_cli-0.40.0}/src/lcode/checkpoints.py +0 -0
- {lcode_cli-0.38.0 → lcode_cli-0.40.0}/src/lcode/checks.py +0 -0
- {lcode_cli-0.38.0 → lcode_cli-0.40.0}/src/lcode/clipboard.py +0 -0
- {lcode_cli-0.38.0 → lcode_cli-0.40.0}/src/lcode/cloud.py +0 -0
- {lcode_cli-0.38.0 → lcode_cli-0.40.0}/src/lcode/codesearch.py +0 -0
- {lcode_cli-0.38.0 → lcode_cli-0.40.0}/src/lcode/context.py +0 -0
- {lcode_cli-0.38.0 → lcode_cli-0.40.0}/src/lcode/escalate.py +0 -0
- {lcode_cli-0.38.0 → lcode_cli-0.40.0}/src/lcode/extensions.py +0 -0
- {lcode_cli-0.38.0 → lcode_cli-0.40.0}/src/lcode/frontmatter.py +0 -0
- {lcode_cli-0.38.0 → lcode_cli-0.40.0}/src/lcode/gitflow.py +0 -0
- {lcode_cli-0.38.0 → lcode_cli-0.40.0}/src/lcode/hardware.py +0 -0
- {lcode_cli-0.38.0 → lcode_cli-0.40.0}/src/lcode/hooks.py +0 -0
- {lcode_cli-0.38.0 → lcode_cli-0.40.0}/src/lcode/jobs.py +0 -0
- {lcode_cli-0.38.0 → lcode_cli-0.40.0}/src/lcode/limits.py +0 -0
- {lcode_cli-0.38.0 → lcode_cli-0.40.0}/src/lcode/lsp.py +0 -0
- {lcode_cli-0.38.0 → lcode_cli-0.40.0}/src/lcode/matching.py +0 -0
- {lcode_cli-0.38.0 → lcode_cli-0.40.0}/src/lcode/mcp/__init__.py +0 -0
- {lcode_cli-0.38.0 → lcode_cli-0.40.0}/src/lcode/mcp/auth.py +0 -0
- {lcode_cli-0.38.0 → lcode_cli-0.40.0}/src/lcode/mcp/catalog.py +0 -0
- {lcode_cli-0.38.0 → lcode_cli-0.40.0}/src/lcode/mcp/client.py +0 -0
- {lcode_cli-0.38.0 → lcode_cli-0.40.0}/src/lcode/mcp/config.py +0 -0
- {lcode_cli-0.38.0 → lcode_cli-0.40.0}/src/lcode/mcp/http.py +0 -0
- {lcode_cli-0.38.0 → lcode_cli-0.40.0}/src/lcode/mcp/manager.py +0 -0
- {lcode_cli-0.38.0 → lcode_cli-0.40.0}/src/lcode/mcp/protocol.py +0 -0
- {lcode_cli-0.38.0 → lcode_cli-0.40.0}/src/lcode/mcp/server.py +0 -0
- {lcode_cli-0.38.0 → lcode_cli-0.40.0}/src/lcode/mcp/stdio.py +0 -0
- {lcode_cli-0.38.0 → lcode_cli-0.40.0}/src/lcode/memory.py +0 -0
- {lcode_cli-0.38.0 → lcode_cli-0.40.0}/src/lcode/models.toml +0 -0
- {lcode_cli-0.38.0 → lcode_cli-0.40.0}/src/lcode/notify.py +0 -0
- {lcode_cli-0.38.0 → lcode_cli-0.40.0}/src/lcode/ollama.py +0 -0
- {lcode_cli-0.38.0 → lcode_cli-0.40.0}/src/lcode/permissions.py +0 -0
- {lcode_cli-0.38.0 → lcode_cli-0.40.0}/src/lcode/planning.py +0 -0
- {lcode_cli-0.38.0 → lcode_cli-0.40.0}/src/lcode/render.py +0 -0
- {lcode_cli-0.38.0 → lcode_cli-0.40.0}/src/lcode/repeats.py +0 -0
- {lcode_cli-0.38.0 → lcode_cli-0.40.0}/src/lcode/repomap.py +0 -0
- {lcode_cli-0.38.0 → lcode_cli-0.40.0}/src/lcode/residency.py +0 -0
- {lcode_cli-0.38.0 → lcode_cli-0.40.0}/src/lcode/review.py +0 -0
- {lcode_cli-0.38.0 → lcode_cli-0.40.0}/src/lcode/sandbox.py +0 -0
- {lcode_cli-0.38.0 → lcode_cli-0.40.0}/src/lcode/screenshots.py +0 -0
- {lcode_cli-0.38.0 → lcode_cli-0.40.0}/src/lcode/secretscan.py +0 -0
- {lcode_cli-0.38.0 → lcode_cli-0.40.0}/src/lcode/servers/__init__.py +0 -0
- {lcode_cli-0.38.0 → lcode_cli-0.40.0}/src/lcode/servers/encord.py +0 -0
- {lcode_cli-0.38.0 → lcode_cli-0.40.0}/src/lcode/servers/valohai.py +0 -0
- {lcode_cli-0.38.0 → lcode_cli-0.40.0}/src/lcode/servers/xai.py +0 -0
- {lcode_cli-0.38.0 → lcode_cli-0.40.0}/src/lcode/sessions.py +0 -0
- {lcode_cli-0.38.0 → lcode_cli-0.40.0}/src/lcode/steer.py +0 -0
- {lcode_cli-0.38.0 → lcode_cli-0.40.0}/src/lcode/subagents.py +0 -0
- {lcode_cli-0.38.0 → lcode_cli-0.40.0}/src/lcode/tools.py +0 -0
- {lcode_cli-0.38.0 → lcode_cli-0.40.0}/src/lcode/unreachable.py +0 -0
- {lcode_cli-0.38.0 → lcode_cli-0.40.0}/src/lcode/update.py +0 -0
- {lcode_cli-0.38.0 → lcode_cli-0.40.0}/src/lcode/vision.py +0 -0
- {lcode_cli-0.38.0 → lcode_cli-0.40.0}/src/lcode/web.py +0 -0
- {lcode_cli-0.38.0 → lcode_cli-0.40.0}/tests/fake_lsp_server.py +0 -0
- {lcode_cli-0.38.0 → lcode_cli-0.40.0}/tests/fake_mcp_server.py +0 -0
- {lcode_cli-0.38.0 → lcode_cli-0.40.0}/tests/test_acp.py +0 -0
- {lcode_cli-0.38.0 → lcode_cli-0.40.0}/tests/test_action.py +0 -0
- {lcode_cli-0.38.0 → lcode_cli-0.40.0}/tests/test_agent.py +0 -0
- {lcode_cli-0.38.0 → lcode_cli-0.40.0}/tests/test_api.py +0 -0
- {lcode_cli-0.38.0 → lcode_cli-0.40.0}/tests/test_backends.py +0 -0
- {lcode_cli-0.38.0 → lcode_cli-0.40.0}/tests/test_bench.py +0 -0
- {lcode_cli-0.38.0 → lcode_cli-0.40.0}/tests/test_catalog.py +0 -0
- {lcode_cli-0.38.0 → lcode_cli-0.40.0}/tests/test_checkpoints.py +0 -0
- {lcode_cli-0.38.0 → lcode_cli-0.40.0}/tests/test_checks.py +0 -0
- {lcode_cli-0.38.0 → lcode_cli-0.40.0}/tests/test_cli.py +0 -0
- {lcode_cli-0.38.0 → lcode_cli-0.40.0}/tests/test_clipboard.py +0 -0
- {lcode_cli-0.38.0 → lcode_cli-0.40.0}/tests/test_cloud.py +0 -0
- {lcode_cli-0.38.0 → lcode_cli-0.40.0}/tests/test_codesearch.py +0 -0
- {lcode_cli-0.38.0 → lcode_cli-0.40.0}/tests/test_config.py +0 -0
- {lcode_cli-0.38.0 → lcode_cli-0.40.0}/tests/test_context.py +0 -0
- {lcode_cli-0.38.0 → lcode_cli-0.40.0}/tests/test_context_picker.py +0 -0
- {lcode_cli-0.38.0 → lcode_cli-0.40.0}/tests/test_escalate.py +0 -0
- {lcode_cli-0.38.0 → lcode_cli-0.40.0}/tests/test_extensions.py +0 -0
- {lcode_cli-0.38.0 → lcode_cli-0.40.0}/tests/test_gitflow.py +0 -0
- {lcode_cli-0.38.0 → lcode_cli-0.40.0}/tests/test_hooks.py +0 -0
- {lcode_cli-0.38.0 → lcode_cli-0.40.0}/tests/test_jobs.py +0 -0
- {lcode_cli-0.38.0 → lcode_cli-0.40.0}/tests/test_look.py +0 -0
- {lcode_cli-0.38.0 → lcode_cli-0.40.0}/tests/test_lsp.py +0 -0
- {lcode_cli-0.38.0 → lcode_cli-0.40.0}/tests/test_matching.py +0 -0
- {lcode_cli-0.38.0 → lcode_cli-0.40.0}/tests/test_mcp.py +0 -0
- {lcode_cli-0.38.0 → lcode_cli-0.40.0}/tests/test_memory.py +0 -0
- {lcode_cli-0.38.0 → lcode_cli-0.40.0}/tests/test_model_picker.py +0 -0
- {lcode_cli-0.38.0 → lcode_cli-0.40.0}/tests/test_permissions.py +0 -0
- {lcode_cli-0.38.0 → lcode_cli-0.40.0}/tests/test_plan_mode.py +0 -0
- {lcode_cli-0.38.0 → lcode_cli-0.40.0}/tests/test_repeats.py +0 -0
- {lcode_cli-0.38.0 → lcode_cli-0.40.0}/tests/test_repomap.py +0 -0
- {lcode_cli-0.38.0 → lcode_cli-0.40.0}/tests/test_residency.py +0 -0
- {lcode_cli-0.38.0 → lcode_cli-0.40.0}/tests/test_review.py +0 -0
- {lcode_cli-0.38.0 → lcode_cli-0.40.0}/tests/test_robustness.py +0 -0
- {lcode_cli-0.38.0 → lcode_cli-0.40.0}/tests/test_sandbox.py +0 -0
- {lcode_cli-0.38.0 → lcode_cli-0.40.0}/tests/test_screenshots.py +0 -0
- {lcode_cli-0.38.0 → lcode_cli-0.40.0}/tests/test_secretscan.py +0 -0
- {lcode_cli-0.38.0 → lcode_cli-0.40.0}/tests/test_servers.py +0 -0
- {lcode_cli-0.38.0 → lcode_cli-0.40.0}/tests/test_sessions.py +0 -0
- {lcode_cli-0.38.0 → lcode_cli-0.40.0}/tests/test_steer.py +0 -0
- {lcode_cli-0.38.0 → lcode_cli-0.40.0}/tests/test_stuck.py +0 -0
- {lcode_cli-0.38.0 → lcode_cli-0.40.0}/tests/test_subagents.py +0 -0
- {lcode_cli-0.38.0 → lcode_cli-0.40.0}/tests/test_tools.py +0 -0
- {lcode_cli-0.38.0 → lcode_cli-0.40.0}/tests/test_update.py +0 -0
- {lcode_cli-0.38.0 → lcode_cli-0.40.0}/tests/test_vision.py +0 -0
- {lcode_cli-0.38.0 → lcode_cli-0.40.0}/tests/test_web.py +0 -0
- {lcode_cli-0.38.0 → lcode_cli-0.40.0}/uv.lock +0 -0
|
@@ -6,6 +6,55 @@ All notable changes to lcode are documented here. The format follows
|
|
|
6
6
|
|
|
7
7
|
## [Unreleased]
|
|
8
8
|
|
|
9
|
+
## [0.40.0] - 2026-10-23
|
|
10
|
+
|
|
11
|
+
### Added
|
|
12
|
+
|
|
13
|
+
- **Image mode makes images** (#149). In image mode, what you type becomes a picture, made by
|
|
14
|
+
FLUX.2 klein 4B on your GPU in about 8 seconds, with no language model involved. lcode drives
|
|
15
|
+
ComfyUI itself. See [Modes](https://nasser1941.github.io/lcode/modes/#image-mode).
|
|
16
|
+
- **ComfyUI is found or started:** lcode uses a running ComfyUI as it is. Otherwise it starts
|
|
17
|
+
yours in the background when you enter image mode (`comfyui_path`, the `comfy` CLI's folder or
|
|
18
|
+
a usual one). It stops that ComfyUI when you quit, go back to code mode or close the terminal.
|
|
19
|
+
With none, it offers to install ComfyUI with comfy-cli.
|
|
20
|
+
- **Progress, cancel and type-ahead:** the status line shows the step, the time left and your
|
|
21
|
+
place in ComfyUI's queue. Esc or Ctrl+C cancels the job in ComfyUI too. What you type
|
|
22
|
+
meanwhile waits in the next prompt.
|
|
23
|
+
- **Files with their settings:** images go to `.lcode/media/` (the `media_dir` setting), each
|
|
24
|
+
with a JSON file of its prompt, model, seed and size, also stored in the PNG itself. Images
|
|
25
|
+
that finish after a crash are saved the next time.
|
|
26
|
+
- `lcode --mode image -p "…"` makes an image from a script, and `--output json` gives the paths.
|
|
27
|
+
`lcode doctor` reports ComfyUI and the image model.
|
|
28
|
+
- **No Ollama needed for images:** lcode starts in image mode without Ollama or the coding
|
|
29
|
+
model; `/mode code` says what's missing.
|
|
30
|
+
|
|
31
|
+
### Fixed
|
|
32
|
+
|
|
33
|
+
- **lcode cleans up when its terminal closes.** A closed terminal or a `kill` used to end lcode
|
|
34
|
+
without stopping what it had started. Now it saves the session and stops its background jobs and
|
|
35
|
+
servers. On Linux, a ComfyUI lcode started also stops if lcode is killed outright.
|
|
36
|
+
|
|
37
|
+
## [0.39.0] - 2026-10-23
|
|
38
|
+
|
|
39
|
+
### Added
|
|
40
|
+
|
|
41
|
+
- **Modes: code, image and video** (#148). `/mode image`, `/mode video` and `/mode code` switch
|
|
42
|
+
what lcode makes. `lcode --mode` starts in one, and the `mode` setting is the default. The
|
|
43
|
+
banner, status bar and prompt show the mode, and sessions keep theirs.
|
|
44
|
+
- **The GPU goes to one model at a time:** switching to image or video mode unloads the coding
|
|
45
|
+
model, and switching back asks ComfyUI to free its memory.
|
|
46
|
+
- **Image and video mode don't generate yet:** they say what's coming (#149–#157) instead of
|
|
47
|
+
sending your words to the coding model. See [Modes](https://nasser1941.github.io/lcode/modes/).
|
|
48
|
+
|
|
49
|
+
### Changed
|
|
50
|
+
|
|
51
|
+
- **Code mode makes code only.** The MCP servers that generated images and videos (`comfyui`,
|
|
52
|
+
`xai`) are out of the MCP catalog, and lcode doesn't load them in code mode even if they're
|
|
53
|
+
still in `mcp.json` (it says so once). Image and video generation are moving to their own modes.
|
|
54
|
+
- **`/mode` switches code, image and video.** The permission mode is set with `/permissions` now;
|
|
55
|
+
`/mode yolo` and the like still work, with a note. Shift+Tab cycles the permission mode as
|
|
56
|
+
before.
|
|
57
|
+
|
|
9
58
|
## [0.38.0] - 2026-10-21
|
|
10
59
|
|
|
11
60
|
### Added
|
|
@@ -855,7 +904,9 @@ First public release.
|
|
|
855
904
|
- `AGENTS.md` project instructions and `/init` to generate them.
|
|
856
905
|
- One-line installer for Linux and macOS.
|
|
857
906
|
|
|
858
|
-
[Unreleased]: https://github.com/nasser1941/lcode/compare/v0.
|
|
907
|
+
[Unreleased]: https://github.com/nasser1941/lcode/compare/v0.40.0...HEAD
|
|
908
|
+
[0.40.0]: https://github.com/nasser1941/lcode/compare/v0.39.0...v0.40.0
|
|
909
|
+
[0.39.0]: https://github.com/nasser1941/lcode/compare/v0.38.0...v0.39.0
|
|
859
910
|
[0.38.0]: https://github.com/nasser1941/lcode/compare/v0.37.0...v0.38.0
|
|
860
911
|
[0.37.0]: https://github.com/nasser1941/lcode/compare/v0.36.0...v0.37.0
|
|
861
912
|
[0.36.0]: https://github.com/nasser1941/lcode/compare/v0.35.1...v0.36.0
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.5
|
|
2
2
|
Name: lcode-cli
|
|
3
|
-
Version: 0.
|
|
3
|
+
Version: 0.40.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,6 +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 mode.** `/mode image`, describe a picture, and FLUX.2 klein 4B makes it on your GPU in
|
|
111
|
+
seconds through ComfyUI, which lcode starts, follows and stops itself. Video mode is next
|
|
112
|
+
([modes](https://nasser1941.github.io/lcode/modes/)).
|
|
110
113
|
- **Automation.** `lcode -p --output json` for scripts and CI, a Python API (`from lcode import
|
|
111
114
|
Session`), and a GitHub Action that answers `@lcode` in issues and pull requests on your own
|
|
112
115
|
self-hosted runner.
|
|
@@ -71,6 +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 mode.** `/mode image`, describe a picture, and FLUX.2 klein 4B makes it on your GPU in
|
|
75
|
+
seconds through ComfyUI, which lcode starts, follows and stops itself. Video mode is next
|
|
76
|
+
([modes](https://nasser1941.github.io/lcode/modes/)).
|
|
74
77
|
- **Automation.** `lcode -p --output json` for scripts and CI, a Python API (`from lcode import
|
|
75
78
|
Session`), and a GitHub Action that answers `@lcode` in issues and pull requests on your own
|
|
76
79
|
self-hosted runner.
|
|
@@ -23,6 +23,10 @@ lcode config path # print the file location
|
|
|
23
23
|
| `backend` | `ollama` | The model server: `ollama`, `lmstudio`, `llama.cpp`, `vllm`, `mlx` or `openai` (any OpenAI-compatible API); see [Other model servers](servers.md) |
|
|
24
24
|
| `base_url` | the backend's | The server's OpenAI-compatible address, e.g. `http://localhost:1234/v1` |
|
|
25
25
|
| `permission_mode` | `ask` | `ask`, `plan`, `auto-edit` or `yolo` |
|
|
26
|
+
| `mode` | `code` | What lcode makes when it starts: `code`, `image` or `video` ([modes](modes.md)) |
|
|
27
|
+
| `comfyui_url` | `http://127.0.0.1:8188` | ComfyUI's address, for image and video mode |
|
|
28
|
+
| `comfyui_path` | (found) | Your ComfyUI folder, if lcode doesn't find it; lcode starts it when needed ([ComfyUI](modes.md#comfyui)) |
|
|
29
|
+
| `media_dir` | `.lcode/media` | Where images and videos go: a folder in the project, or an absolute path |
|
|
26
30
|
| `think` | `true` | Let the model reason before answering |
|
|
27
31
|
| `web` | `on` | Web search and page fetching: `on`, `ask` (before each search/website) or `off` |
|
|
28
32
|
| `search_backend` | `auto` | `auto`, `ollama`, `brave`, `tavily` or `searxng`; `auto` uses the first one configured |
|
|
@@ -28,8 +28,6 @@ and find the code for the top one."*
|
|
|
28
28
|
| `gcp` | `gcloud` commands on your Google Cloud projects | `npx` and the `gcloud` CLI, signed in |
|
|
29
29
|
| `github` | Repositories, issues, pull requests, Actions | a GitHub token (or the GitHub CLI) |
|
|
30
30
|
| `playwright` | A real (headless) browser: open pages, click, fill forms | `npx` |
|
|
31
|
-
| `comfyui` | Generate and edit images with local models (FLUX, SDXL, SD 1.5, Qwen-Image) | `uvx` and [ComfyUI](#images-with-comfyui) running locally |
|
|
32
|
-
| `xai` | Generate and edit images, and generate videos and speech, with xAI's Grok Imagine (paid, in the cloud) | `uvx`, an xAI API key ([below](#images-videos-and-speech-with-xai)) |
|
|
33
31
|
| `context7` | Up-to-date docs and examples for thousands of libraries | nothing (an API key is optional) |
|
|
34
32
|
| `sentry` | Errors, issues, traces and releases | a Sentry account (browser sign-in) |
|
|
35
33
|
| `postgres` | Schemas, read-only queries, query performance | `uvx`, a connection URL |
|
|
@@ -87,86 +85,12 @@ Google Cloud project:
|
|
|
87
85
|
See [Google's guide](https://developers.google.com/workspace/guides/configure-mcp-servers) for
|
|
88
86
|
details.
|
|
89
87
|
|
|
90
|
-
### Images
|
|
88
|
+
### Images and videos
|
|
91
89
|
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
```bash
|
|
97
|
-
uv tool install comfy-cli && comfy install # ComfyUI, once
|
|
98
|
-
comfy launch --background -- --disable-smart-memory # start it (http://127.0.0.1:8188)
|
|
99
|
-
lcode mcp add comfyui
|
|
100
|
-
```
|
|
101
|
-
|
|
102
|
-
Then add models in ComfyUI (its model manager, or ask lcode: *"download FLUX.2 Klein 4B in
|
|
103
|
-
ComfyUI"*), and ask for images: *"make a 512×512 app icon of a paper plane and save it in
|
|
104
|
-
assets/"*. To edit an image, ask lcode to upload it and run an editing workflow (Kontext or
|
|
105
|
-
Qwen-Image-Edit).
|
|
106
|
-
|
|
107
|
-
| Model | Good for | On a 12 GB GPU |
|
|
108
|
-
|---|---|---|
|
|
109
|
-
| FLUX.2 Klein 4B | Generation and editing, fast | Fits (about 8 GB) |
|
|
110
|
-
| SDXL and its community models | Generation, inpainting | Fits |
|
|
111
|
-
| Stable Diffusion 1.5 and its community models | Light generation, inpainting | Fits easily |
|
|
112
|
-
| FLUX.1 Dev and finetunes | High-quality generation | Needs an fp8 or GGUF version; slower |
|
|
113
|
-
| FLUX.1 Kontext Dev | Editing an image from instructions | Needs an fp8 or GGUF version; slower |
|
|
114
|
-
| Qwen-Image / Qwen-Image-Edit | Generation and editing, good text in images | Heavy: a GGUF version and RAM offloading |
|
|
115
|
-
|
|
116
|
-
Only ComfyUI's local tools are turned on; Comfy Cloud's partner tools are left out, so prompts and
|
|
117
|
-
images stay on your machine.
|
|
118
|
-
|
|
119
|
-
**Sharing one GPU.** A GPU rarely holds a coding model and an image model at the same time, so the
|
|
120
|
-
two take turns: before ComfyUI generates, lcode unloads its own model (the `free_gpu` setting), and
|
|
121
|
-
ComfyUI started with `--disable-smart-memory` gives the GPU back after each image. lcode's model
|
|
122
|
-
then reloads for the next step, which adds a few seconds to half a minute per image request. With
|
|
123
|
-
enough GPU memory for both (or on a Mac with plenty of memory), remove `free_gpu` from the server's
|
|
124
|
-
settings in `mcp.json`. lcode can also look at the results ([Images](usage.md#images)).
|
|
125
|
-
|
|
126
|
-
Measured on an RTX 4080 Laptop GPU (12 GB) with qwen3.6-35b at 64K context and FLUX.2 Klein Base 4B
|
|
127
|
-
(fp8, 512×512, 20 steps):
|
|
128
|
-
|
|
129
|
-
| | |
|
|
130
|
-
|---|---|
|
|
131
|
-
| Generating while lcode's model is loaded | Fails: ComfyUI runs out of GPU memory |
|
|
132
|
-
| Freeing the GPU (lcode unloads its model) | 0.2 s |
|
|
133
|
-
| Generating one image | about 12 s |
|
|
134
|
-
| Reloading lcode's model afterwards | about 20 s |
|
|
135
|
-
|
|
136
|
-
The first time, the model has to find the right template and fill in its settings (model file names,
|
|
137
|
-
size, prompt), which can take several minutes of trial and error. Once an image comes out right, ask
|
|
138
|
-
lcode to save that workflow in your project (for example `assets/icon.workflow.json`) and reuse it:
|
|
139
|
-
later images are a single `run_workflow` call.
|
|
140
|
-
|
|
141
|
-
### Images, videos and speech with xAI
|
|
142
|
-
|
|
143
|
-
xAI's [Grok Imagine](https://docs.x.ai/developers/model-capabilities/imagine) and
|
|
144
|
-
[text to speech](https://docs.x.ai/developers/models/text-to-speech) APIs make images, videos and
|
|
145
|
-
speech in the cloud: no GPU needed, but each call is billed to your xAI account. lcode ships an MCP
|
|
146
|
-
server for them, `lcode-mcp-xai`.
|
|
147
|
-
|
|
148
|
-
```bash
|
|
149
|
-
lcode mcp add xai # asks for your xAI API key (create one at https://console.x.ai)
|
|
150
|
-
```
|
|
151
|
-
|
|
152
|
-
The key is typed hidden and kept in `~/.config/lcode/mcp.json`, readable only by you. If
|
|
153
|
-
`XAI_API_KEY` is already set in your environment, lcode uses that and doesn't store the key.
|
|
154
|
-
|
|
155
|
-
| Tool | | Costs |
|
|
156
|
-
|---|---|---|
|
|
157
|
-
| `generate_image` | Images from a description: 1–10 at a time, aspect ratio, 1k or 2k | $0.02–0.05 an image |
|
|
158
|
-
| `edit_image` | Change a local image as described | the same |
|
|
159
|
-
| `generate_video` | A 1–15 second MP4 from a description, optionally starting from a local image, up to 1080p. Waits for it (a minute or more) | $0.02–0.08 a second |
|
|
160
|
-
| `video_status` | Fetch a video that wasn't ready within 10 minutes | |
|
|
161
|
-
| `text_to_speech` | Speech in one of 26 voices and 20 languages, as MP3 or WAV | per character |
|
|
162
|
-
|
|
163
|
-
Files are saved in `generated/` in the project, or where you ask (*"generate an app icon and save
|
|
164
|
-
it as assets/icon.png"*). xAI has no music generation API.
|
|
165
|
-
|
|
166
|
-
Your prompts, and the images you edit or animate, go to xAI. lcode asks before each call, since each
|
|
167
|
-
one costs money. To stop asking for some tools, list them under `"allow"` for the server in
|
|
168
|
-
`mcp.json`, for example `"allow": ["generate_image", "text_to_speech"]`. xAI applies its own usage
|
|
169
|
-
policies to what it generates; when it refuses a prompt, lcode passes its message to the model.
|
|
90
|
+
Code mode makes code only, so the servers that generated images and videos in earlier versions
|
|
91
|
+
(`comfyui`, `xai`) aren't in the catalog any more, and lcode doesn't load them in code mode if
|
|
92
|
+
they're still in your `mcp.json`. Image and video generation get their own [modes](modes.md),
|
|
93
|
+
with their own models and controls.
|
|
170
94
|
|
|
171
95
|
### Metabase
|
|
172
96
|
|
|
@@ -0,0 +1,109 @@
|
|
|
1
|
+
# Modes: code, image and video
|
|
2
|
+
|
|
3
|
+
lcode makes three kinds of things, each in its own mode with its own models:
|
|
4
|
+
|
|
5
|
+
| Mode | What it makes | The model doing the work |
|
|
6
|
+
|---|---|---|
|
|
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 and reference images | An image model, run by ComfyUI on your GPU |
|
|
9
|
+
| **video** | Videos from a description, a start image or references | A video model, run by ComfyUI on your GPU |
|
|
10
|
+
|
|
11
|
+
```text
|
|
12
|
+
❯ /mode image
|
|
13
|
+
Mode: image (local image generation).
|
|
14
|
+
Unloaded qwen3.6-35b to free the GPU for images.
|
|
15
|
+
Starting ComfyUI (~/comfy/ComfyUI) in the background.
|
|
16
|
+
Describe an image and press Enter: FLUX.2 klein 4B makes it on your GPU, into .lcode/media.
|
|
17
|
+
image ❯ a red fox sitting in fresh snow at dusk
|
|
18
|
+
◆ .lcode/media/20261023-184531-a-red-fox-sitting-in-fresh-snow-at-dusk-1.png 1024×1024 · FLUX.2 klein 4B · seed 3714779554 · 8.0 s
|
|
19
|
+
```
|
|
20
|
+
|
|
21
|
+
- **Switching:** `/mode code`, `/mode image` and `/mode video` switch in a session. `lcode --mode image`
|
|
22
|
+
starts in one, and `lcode config set mode video` makes it the default. `/mode` alone shows
|
|
23
|
+
the current one.
|
|
24
|
+
- **Where it shows:** the banner, the status bar and the prompt (`image ❯`) show the mode.
|
|
25
|
+
- **Sessions:** a session keeps the mode it was made in, and resuming it brings that mode back.
|
|
26
|
+
|
|
27
|
+
## Code mode makes code only
|
|
28
|
+
|
|
29
|
+
Code mode is the coding agent, as before, and it no longer generates images or videos. The MCP
|
|
30
|
+
servers that did (`comfyui` and `xai`) are gone from the MCP catalog, and lcode doesn't load them
|
|
31
|
+
in code mode even if they're still in your `mcp.json`. It says so once.
|
|
32
|
+
|
|
33
|
+
## Image mode
|
|
34
|
+
|
|
35
|
+
In image mode, what you type is a description, and lcode makes the picture. No language model is
|
|
36
|
+
involved: lcode fills in its own ComfyUI workflow for the image model and follows the job itself.
|
|
37
|
+
For now that's one image per request, 1024×1024, with **FLUX.2 klein 4B** (4 steps, about 8 seconds
|
|
38
|
+
on a 12 GB laptop GPU; a 4B model that fits in 8 GB). Choosing models, sizes, seeds and variations
|
|
39
|
+
comes next (#150, #151).
|
|
40
|
+
|
|
41
|
+
- **Progress:** the status line says what ComfyUI is doing (loading the model, reading the
|
|
42
|
+
prompt, drawing, decoding), the step, the time left and the time so far. If other jobs are ahead
|
|
43
|
+
in ComfyUI's queue, it says how many.
|
|
44
|
+
- **Cancel** with Esc or Ctrl+C: lcode cancels the job in ComfyUI too, so it stops using the GPU.
|
|
45
|
+
- **Type ahead:** what you type while an image is being made waits in the next prompt.
|
|
46
|
+
- **Files:** each image goes to `.lcode/media/` in the project (the `media_dir` setting), named
|
|
47
|
+
after the time and the prompt, with a `.json` next to it holding the prompt, model, seed, size and
|
|
48
|
+
steps. PNGs carry the same in their own metadata (an `lcode` text chunk), and ComfyUI's workflow
|
|
49
|
+
as well. `.lcode/media/` keeps itself out of git; a folder of your own (`lcode config set
|
|
50
|
+
media_dir assets/generated`) doesn't.
|
|
51
|
+
- **Nothing is lost:** lcode writes each job down while it runs. If lcode crashes or the terminal
|
|
52
|
+
closes before an image arrives, the next request in image mode saves it.
|
|
53
|
+
- **From scripts:** `lcode --mode image -p "a red fox in the snow"` makes one image and exits;
|
|
54
|
+
with `--output json` it prints a result with the file paths, model, seed, size and time.
|
|
55
|
+
- **No Ollama needed:** `lcode --mode image` starts even when Ollama isn't running or the coding
|
|
56
|
+
model isn't installed; `/mode code` then says what's missing.
|
|
57
|
+
|
|
58
|
+
## ComfyUI
|
|
59
|
+
|
|
60
|
+
ComfyUI runs the image and video models; lcode drives it through its API.
|
|
61
|
+
|
|
62
|
+
- **One that's running** at `comfyui_url` (by default `http://127.0.0.1:8188`) is used as it is.
|
|
63
|
+
- **Otherwise lcode starts one** in the background when you switch to image mode, so the first
|
|
64
|
+
image waits less, and stops it when you quit or go back to code mode, or when the terminal
|
|
65
|
+
closes. It looks in the `comfyui_path` setting, then the folder the `comfy` CLI uses, then
|
|
66
|
+
`~/comfy/ComfyUI`, `~/ComfyUI`, `~/comfyui` and `~/Documents/ComfyUI`. It uses that install's
|
|
67
|
+
own Python (its `.venv` or `venv`), and logs to `comfyui.log` in lcode's state folder.
|
|
68
|
+
- **With none,** your first image request offers to install ComfyUI into lcode's state folder with
|
|
69
|
+
[comfy-cli](https://github.com/Comfy-Org/comfy-cli) and the PyTorch build for your GPU (NVIDIA,
|
|
70
|
+
Apple Silicon or CPU). That downloads several GB. To install it yourself:
|
|
71
|
+
|
|
72
|
+
```bash
|
|
73
|
+
uvx --from comfy-cli comfy install
|
|
74
|
+
```
|
|
75
|
+
|
|
76
|
+
- **The image model** has to be in ComfyUI's model folders for now: for FLUX.2 klein 4B,
|
|
77
|
+
`diffusion_models/flux-2-klein-4b-fp8.safetensors`, `text_encoders/qwen_3_4b.safetensors` and
|
|
78
|
+
`vae/flux2-vae.safetensors` (from ComfyUI's FLUX.2 klein template). lcode names any that are
|
|
79
|
+
missing. Installing models from lcode comes with #150.
|
|
80
|
+
- **`lcode doctor`** shows whether ComfyUI is running or found, and whether the image model is
|
|
81
|
+
there.
|
|
82
|
+
|
|
83
|
+
## One model on the GPU at a time
|
|
84
|
+
|
|
85
|
+
Image and video modes don't need the big coding model: the image or video model does the work. A
|
|
86
|
+
small optional model will help with prompts later. Image and video models need the GPU to
|
|
87
|
+
themselves:
|
|
88
|
+
|
|
89
|
+
- **Into image or video mode:** lcode unloads its coding model from Ollama, and checks again
|
|
90
|
+
before each image.
|
|
91
|
+
- **Back to code mode:** lcode stops the ComfyUI it started, or asks yours to free its memory,
|
|
92
|
+
then loads the coding model again in the background.
|
|
93
|
+
|
|
94
|
+
## Coming next
|
|
95
|
+
|
|
96
|
+
Video mode doesn't generate yet: a request there says what's coming instead of going anywhere.
|
|
97
|
+
|
|
98
|
+
- **#150 Media model catalog:** image and video models that fit your machine, installed on
|
|
99
|
+
demand.
|
|
100
|
+
- **#151, #152 Image mode:** generating, variations, sizes and seeds, a gallery, editing,
|
|
101
|
+
references, inpainting, upscaling.
|
|
102
|
+
- **#153, #154 Video mode:** from text or a start image, first and last frames, several
|
|
103
|
+
references, camera moves, longer clips, sound.
|
|
104
|
+
- **#155 Movies:** storyboards with a consistent cast, shots stitched into one film.
|
|
105
|
+
- **#156 Prompt assistant:** a small local model for prompts and follow-ups.
|
|
106
|
+
- **#157 Cloud generation**, with costs shown (Grok Imagine first).
|
|
107
|
+
|
|
108
|
+
The permission mode (`ask`, `plan`, `auto-edit`, `yolo`) is a different setting: `/permissions`
|
|
109
|
+
sets it, and Shift+Tab cycles it as before.
|
|
@@ -79,7 +79,8 @@ reasoning is on.
|
|
|
79
79
|
| `/models`, `/model [number or name]` | List the models and how they fit this machine, numbered: type a number to switch, or `/model 2`, `/model qwen3.5-9b` |
|
|
80
80
|
| `/think [on\|off]` | Toggle reasoning |
|
|
81
81
|
| `/verbose` | Toggle showing the reasoning text |
|
|
82
|
-
| `/mode [
|
|
82
|
+
| `/mode [code\|image\|video]` | Switch what lcode makes: [code, images or videos](modes.md) |
|
|
83
|
+
| `/permissions [ask\|plan\|auto-edit\|yolo]` | Set the permission mode |
|
|
83
84
|
| `/cd DIR` | Change the working directory |
|
|
84
85
|
| `/todos` | Show the model's task list |
|
|
85
86
|
| `/status` | The task sheet: your latest requests, the plan and the model's notes, files changed, the last check |
|
|
@@ -315,7 +316,7 @@ stays loaded:
|
|
|
315
316
|
| The model was loaded | `◆ Loaded qwen3.6-35b in 15s: 22.3 GB, 45% on the GPU and the rest in system RAM.`, and a warning when less of it is on the GPU than usual, because another program or model is using GPU memory |
|
|
316
317
|
| A dense model doesn't fit on the GPU (at startup and on `/model`) | `⚠ qwen3.8-27b is a dense model: all 27B parameters work on every token. It's capable, but slow here. Only about 61% of it fits in the 12 GB of GPU memory…`, with what to do instead |
|
|
317
318
|
| The model that looks at images needs the memory | `Loading the vision model … to look at bug.png; qwen3.6-35b makes room and reloads afterwards`, then `◆ qwen3.6-35b was unloaded to make room…`, and the next step says `Reloading qwen3.6-35b into memory (it made room for the vision model …)` |
|
|
318
|
-
| A tool needs the GPU to itself
|
|
319
|
+
| A tool needs the GPU to itself (an MCP server with `free_gpu`) | `◆ Unloaded qwen3.6-35b so the server can use the GPU; it reloads afterwards.` |
|
|
319
320
|
| Ollama ran out of memory | `⚠` what ran out (the prompt batch, or the context next to the model), what lcode retries with, and what it remembers for next time |
|
|
320
321
|
|
|
321
322
|
While the model loads in the background at startup, the status bar says
|
|
@@ -470,7 +471,7 @@ a screen and sees what you would, measured:
|
|
|
470
471
|
| `auto-edit` | automatic | ask, except read-only commands |
|
|
471
472
|
| `yolo` | automatic | automatic |
|
|
472
473
|
|
|
473
|
-
++shift+tab++ cycles through them in this order, `/
|
|
474
|
+
++shift+tab++ cycles through them in this order, `/permissions` sets one, and `--plan`, `--auto-edit` and
|
|
474
475
|
`--yolo` start in one.
|
|
475
476
|
|
|
476
477
|
Read-only commands run without asking: `ls`, `cat`, `head`, `tail`, `grep`, `rg`, `find`, `tree`,
|
|
@@ -304,6 +304,10 @@ class Progress:
|
|
|
304
304
|
class Settings:
|
|
305
305
|
model: str # Ollama model name to call
|
|
306
306
|
context: int
|
|
307
|
+
mode: str = "code" # what lcode makes: code, image or video (lcode.modes)
|
|
308
|
+
comfyui_url: str = "http://127.0.0.1:8188"
|
|
309
|
+
comfyui_path: str | None = None # a ComfyUI install lcode doesn't find by itself (lcode.comfy)
|
|
310
|
+
media_dir: str = ".lcode/media" # where image and video mode save their files (lcode.media)
|
|
307
311
|
num_batch: int | None = None
|
|
308
312
|
keep_alive: str = "30m"
|
|
309
313
|
think: bool = True
|
|
@@ -368,6 +372,8 @@ class Agent:
|
|
|
368
372
|
self.session_name = ""
|
|
369
373
|
self.session_title = ""
|
|
370
374
|
self.interactive = True # False for `lcode -p`: no end-of-session questions
|
|
375
|
+
self.comfy_process = None # the ComfyUI lcode started for image and video mode, stopped when it exits
|
|
376
|
+
self.no_coding_model = "" # why there's no coding model, when lcode started in image or video mode without
|
|
371
377
|
self.reflected = 0 # messages before this index were already checked for notes to remember
|
|
372
378
|
self._memory: memory_notes.Memory | None = None
|
|
373
379
|
self._agent_types: tuple[Path, dict[str, subagents.AgentType], list[str]] | None = None
|
|
@@ -680,6 +686,7 @@ class Agent:
|
|
|
680
686
|
data = {
|
|
681
687
|
"cwd": str(self.workspace), # where `lcode -c` there finds it, wherever the shell moved
|
|
682
688
|
"model": self.settings.model,
|
|
689
|
+
"mode": self.settings.mode,
|
|
683
690
|
"name": self.session_name,
|
|
684
691
|
"title": self.session_title,
|
|
685
692
|
"messages": self.messages,
|
|
@@ -726,6 +733,8 @@ class Agent:
|
|
|
726
733
|
self.session_id = info.id
|
|
727
734
|
self.checkpoints.load(info.id, data.get("checkpoints") or [])
|
|
728
735
|
self.session_name = data.get("name", "")
|
|
736
|
+
if data.get("mode") in ("code", "image", "video"):
|
|
737
|
+
self.settings.mode = data["mode"] # a session belongs to the mode it was made in
|
|
729
738
|
self.session_title = data.get("title") or sessions.title_from(self.messages)
|
|
730
739
|
self.tools.read_mtimes.clear() # files may have changed since; the model must read them again
|
|
731
740
|
self.tools.todos = list(data.get("todos") or [])
|
|
@@ -15,6 +15,7 @@ A session is one conversation: each `run` continues it. `stream` yields the same
|
|
|
15
15
|
|
|
16
16
|
from __future__ import annotations
|
|
17
17
|
|
|
18
|
+
import contextlib
|
|
18
19
|
import io
|
|
19
20
|
import queue
|
|
20
21
|
import threading
|
|
@@ -54,6 +55,7 @@ class Options:
|
|
|
54
55
|
model: str | None = None
|
|
55
56
|
context: int | str | None = None
|
|
56
57
|
permission_mode: str | None = None # ask, plan, auto-edit or yolo
|
|
58
|
+
mode: str | None = None # code, image or video
|
|
57
59
|
allowed_tools: list[str] | None = None # only these tools (default: all)
|
|
58
60
|
max_steps: int | None = None # model steps per request
|
|
59
61
|
think: bool | None = None
|
|
@@ -129,6 +131,24 @@ def switch(wanted: bool | None, configured: str, default_on: str) -> str:
|
|
|
129
131
|
return configured if configured != "off" else default_on
|
|
130
132
|
|
|
131
133
|
|
|
134
|
+
def coding_model(ollama, options: Options, cfg: dict, requested: int | None, hw: Hardware, console: Console):
|
|
135
|
+
"""The coding model to use, its catalog entry and the context window; SetupError when there's none."""
|
|
136
|
+
from lcode import cli
|
|
137
|
+
|
|
138
|
+
check_server(ollama, hw)
|
|
139
|
+
try:
|
|
140
|
+
model, spec = cli.resolve_model(ollama, options.model or cfg["model"])
|
|
141
|
+
except cli.NotInstalled as e:
|
|
142
|
+
first_run = not options.model and cfg["model"] == config.DEFAULT_MODEL and not config.CONFIG_PATH.exists()
|
|
143
|
+
if first_run and not backends.is_openai(ollama):
|
|
144
|
+
raise SetupError("lcode isn't set up yet. Run: lcode setup") from e
|
|
145
|
+
raise SetupError(str(e)) from e
|
|
146
|
+
context, note = cli.choose_context(ollama, model, spec, requested, hw)
|
|
147
|
+
if note:
|
|
148
|
+
console.print(f"[yellow]Context {config.format_tokens(context)}: {note}[/]")
|
|
149
|
+
return model, spec, context
|
|
150
|
+
|
|
151
|
+
|
|
132
152
|
def open_agent(cwd: Path, options: Options, console: Console, hw: Hardware | None = None) -> Agent:
|
|
133
153
|
"""An agent set up the way `lcode` sets up a session: model, context, hooks, language servers, MCP."""
|
|
134
154
|
from lcode import catalog, cli, extensions, hooks
|
|
@@ -152,17 +172,14 @@ def open_agent(cwd: Path, options: Options, console: Console, hw: Hardware | Non
|
|
|
152
172
|
except OllamaError as e:
|
|
153
173
|
raise SetupError(str(e)) from e
|
|
154
174
|
hw = hw or detect()
|
|
155
|
-
|
|
175
|
+
no_coding_model = "" # why, when image or video mode starts without one
|
|
156
176
|
try:
|
|
157
|
-
model, spec =
|
|
158
|
-
except
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
context, note = cli.choose_context(ollama, model, spec, requested, hw)
|
|
164
|
-
if note:
|
|
165
|
-
console.print(f"[yellow]Context {config.format_tokens(context)}: {note}[/]")
|
|
177
|
+
model, spec, context = coding_model(ollama, options, cfg, requested, hw, console)
|
|
178
|
+
except SetupError as e:
|
|
179
|
+
if (options.mode or cfg["mode"]) == "code":
|
|
180
|
+
raise
|
|
181
|
+
# Image and video mode don't need the coding model: start without it, and say so on /mode code.
|
|
182
|
+
model, spec, context, no_coding_model = options.model or cfg["model"], None, requested or 32768, str(e)
|
|
166
183
|
num_batch = cfg["num_batch"]
|
|
167
184
|
if num_batch is None and spec and spec.num_batch:
|
|
168
185
|
if model == spec.local_name:
|
|
@@ -179,6 +196,10 @@ def open_agent(cwd: Path, options: Options, console: Console, hw: Hardware | Non
|
|
|
179
196
|
think=cfg["think"] if options.think is None else options.think,
|
|
180
197
|
show_thinking=options.show_thinking,
|
|
181
198
|
permission_mode=options.permission_mode or cfg["permission_mode"],
|
|
199
|
+
mode=options.mode or cfg["mode"],
|
|
200
|
+
comfyui_url=cfg["comfyui_url"],
|
|
201
|
+
comfyui_path=cfg["comfyui_path"],
|
|
202
|
+
media_dir=cfg["media_dir"],
|
|
182
203
|
web=switch(options.web, cfg["web"], "on"),
|
|
183
204
|
search_backend=cfg["search_backend"],
|
|
184
205
|
searxng_url=cfg["searxng_url"],
|
|
@@ -208,6 +229,7 @@ def open_agent(cwd: Path, options: Options, console: Console, hw: Hardware | Non
|
|
|
208
229
|
)
|
|
209
230
|
agent = Agent(ollama, settings, cwd, console=console)
|
|
210
231
|
agent.hardware = hw
|
|
232
|
+
agent.no_coding_model = no_coding_model
|
|
211
233
|
agent.autosave = True
|
|
212
234
|
agent.interactive = options.interactive
|
|
213
235
|
if options.max_steps:
|
|
@@ -247,15 +269,25 @@ def open_agent(cwd: Path, options: Options, console: Console, hw: Hardware | Non
|
|
|
247
269
|
|
|
248
270
|
|
|
249
271
|
def close_agent(agent: Agent) -> None:
|
|
272
|
+
"""Stop what lcode started (background jobs, servers, the sandbox, ComfyUI), then say so: the terminal may be
|
|
273
|
+
gone already (closed), and saying it then fails."""
|
|
274
|
+
from lcode import media
|
|
275
|
+
|
|
276
|
+
said = []
|
|
250
277
|
stopped = agent.jobs.stop_all()
|
|
251
278
|
if stopped:
|
|
252
|
-
|
|
279
|
+
said.append(f"Stopped {stopped} background job(s).")
|
|
280
|
+
if media.stop_engine(agent):
|
|
281
|
+
said.append("Stopped ComfyUI.")
|
|
253
282
|
if agent.lsp is not None:
|
|
254
283
|
agent.lsp.close()
|
|
255
284
|
if agent.mcp:
|
|
256
285
|
agent.mcp.close()
|
|
257
286
|
if agent.sandbox:
|
|
258
287
|
agent.sandbox.stop()
|
|
288
|
+
for line in said:
|
|
289
|
+
with contextlib.suppress(OSError):
|
|
290
|
+
agent.console.print(f"[dim]{line}[/]")
|
|
259
291
|
|
|
260
292
|
|
|
261
293
|
# ----------------------------------------------------------------------------- running
|