lcode-cli 0.17.0__tar.gz → 0.19.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.17.0 → lcode_cli-0.19.0}/CHANGELOG.md +34 -1
- {lcode_cli-0.17.0 → lcode_cli-0.19.0}/PKG-INFO +7 -3
- {lcode_cli-0.17.0 → lcode_cli-0.19.0}/README.md +6 -2
- lcode_cli-0.19.0/action.yml +79 -0
- lcode_cli-0.19.0/docs/automation.md +193 -0
- lcode_cli-0.19.0/docs/editors.md +85 -0
- {lcode_cli-0.17.0 → lcode_cli-0.19.0}/docs/quickstart.md +1 -1
- {lcode_cli-0.17.0 → lcode_cli-0.19.0}/docs/usage.md +4 -0
- {lcode_cli-0.17.0 → lcode_cli-0.19.0}/examples/README.md +1 -0
- lcode_cli-0.19.0/examples/api/fix_tests.py +37 -0
- {lcode_cli-0.17.0 → lcode_cli-0.19.0}/mkdocs.yml +2 -0
- {lcode_cli-0.17.0 → lcode_cli-0.19.0}/pyproject.toml +2 -0
- lcode_cli-0.19.0/src/lcode/__init__.py +16 -0
- lcode_cli-0.19.0/src/lcode/acp.py +635 -0
- lcode_cli-0.19.0/src/lcode/action.py +358 -0
- {lcode_cli-0.17.0 → lcode_cli-0.19.0}/src/lcode/agent.py +56 -4
- lcode_cli-0.19.0/src/lcode/api.py +383 -0
- {lcode_cli-0.17.0 → lcode_cli-0.19.0}/src/lcode/cli.py +85 -109
- {lcode_cli-0.17.0 → lcode_cli-0.19.0}/src/lcode/permissions.py +15 -0
- {lcode_cli-0.17.0 → lcode_cli-0.19.0}/src/lcode/planning.py +5 -0
- {lcode_cli-0.17.0 → lcode_cli-0.19.0}/src/lcode/subagents.py +2 -1
- {lcode_cli-0.17.0 → lcode_cli-0.19.0}/src/lcode/tools.py +20 -5
- lcode_cli-0.19.0/tests/test_acp.py +267 -0
- lcode_cli-0.19.0/tests/test_action.py +234 -0
- lcode_cli-0.19.0/tests/test_api.py +141 -0
- {lcode_cli-0.17.0 → lcode_cli-0.19.0}/tests/test_cli.py +1 -1
- lcode_cli-0.17.0/src/lcode/__init__.py +0 -3
- {lcode_cli-0.17.0 → lcode_cli-0.19.0}/.editorconfig +0 -0
- {lcode_cli-0.17.0 → lcode_cli-0.19.0}/.github/CODEOWNERS +0 -0
- {lcode_cli-0.17.0 → lcode_cli-0.19.0}/.github/ISSUE_TEMPLATE/bug_report.yml +0 -0
- {lcode_cli-0.17.0 → lcode_cli-0.19.0}/.github/ISSUE_TEMPLATE/config.yml +0 -0
- {lcode_cli-0.17.0 → lcode_cli-0.19.0}/.github/ISSUE_TEMPLATE/feature_request.yml +0 -0
- {lcode_cli-0.17.0 → lcode_cli-0.19.0}/.github/ISSUE_TEMPLATE/model_request.yml +0 -0
- {lcode_cli-0.17.0 → lcode_cli-0.19.0}/.github/PULL_REQUEST_TEMPLATE.md +0 -0
- {lcode_cli-0.17.0 → lcode_cli-0.19.0}/.github/dependabot.yml +0 -0
- {lcode_cli-0.17.0 → lcode_cli-0.19.0}/.github/workflows/ci.yml +0 -0
- {lcode_cli-0.17.0 → lcode_cli-0.19.0}/.github/workflows/docs.yml +0 -0
- {lcode_cli-0.17.0 → lcode_cli-0.19.0}/.github/workflows/release.yml +0 -0
- {lcode_cli-0.17.0 → lcode_cli-0.19.0}/.gitignore +0 -0
- {lcode_cli-0.17.0 → lcode_cli-0.19.0}/.pre-commit-config.yaml +0 -0
- {lcode_cli-0.17.0 → lcode_cli-0.19.0}/AGENTS.md +0 -0
- {lcode_cli-0.17.0 → lcode_cli-0.19.0}/CODE_OF_CONDUCT.md +0 -0
- {lcode_cli-0.17.0 → lcode_cli-0.19.0}/CONTRIBUTING.md +0 -0
- {lcode_cli-0.17.0 → lcode_cli-0.19.0}/LICENSE +0 -0
- {lcode_cli-0.17.0 → lcode_cli-0.19.0}/SECURITY.md +0 -0
- {lcode_cli-0.17.0 → lcode_cli-0.19.0}/docs/agents.md +0 -0
- {lcode_cli-0.17.0 → lcode_cli-0.19.0}/docs/assets/demo.svg +0 -0
- {lcode_cli-0.17.0 → lcode_cli-0.19.0}/docs/assets/extra.css +0 -0
- {lcode_cli-0.17.0 → lcode_cli-0.19.0}/docs/assets/logo.svg +0 -0
- {lcode_cli-0.17.0 → lcode_cli-0.19.0}/docs/assets/social-preview.png +0 -0
- {lcode_cli-0.17.0 → lcode_cli-0.19.0}/docs/bench.md +0 -0
- {lcode_cli-0.17.0 → lcode_cli-0.19.0}/docs/changelog.md +0 -0
- {lcode_cli-0.17.0 → lcode_cli-0.19.0}/docs/commands.md +0 -0
- {lcode_cli-0.17.0 → lcode_cli-0.19.0}/docs/configuration.md +0 -0
- {lcode_cli-0.17.0 → lcode_cli-0.19.0}/docs/contributing.md +0 -0
- {lcode_cli-0.17.0 → lcode_cli-0.19.0}/docs/git.md +0 -0
- {lcode_cli-0.17.0 → lcode_cli-0.19.0}/docs/hooks.md +0 -0
- {lcode_cli-0.17.0 → lcode_cli-0.19.0}/docs/how-it-works.md +0 -0
- {lcode_cli-0.17.0 → lcode_cli-0.19.0}/docs/index.md +0 -0
- {lcode_cli-0.17.0 → lcode_cli-0.19.0}/docs/installation.md +0 -0
- {lcode_cli-0.17.0 → lcode_cli-0.19.0}/docs/lsp.md +0 -0
- {lcode_cli-0.17.0 → lcode_cli-0.19.0}/docs/mcp.md +0 -0
- {lcode_cli-0.17.0 → lcode_cli-0.19.0}/docs/memory.md +0 -0
- {lcode_cli-0.17.0 → lcode_cli-0.19.0}/docs/models.md +0 -0
- {lcode_cli-0.17.0 → lcode_cli-0.19.0}/docs/sandbox.md +0 -0
- {lcode_cli-0.17.0 → lcode_cli-0.19.0}/docs/search.md +0 -0
- {lcode_cli-0.17.0 → lcode_cli-0.19.0}/docs/servers.md +0 -0
- {lcode_cli-0.17.0 → lcode_cli-0.19.0}/docs/troubleshooting.md +0 -0
- {lcode_cli-0.17.0 → lcode_cli-0.19.0}/examples/commands/review.md +0 -0
- {lcode_cli-0.17.0 → lcode_cli-0.19.0}/examples/skills/commit-message/SKILL.md +0 -0
- {lcode_cli-0.17.0 → lcode_cli-0.19.0}/examples/skills/commit-message/scripts/staged.sh +0 -0
- {lcode_cli-0.17.0 → lcode_cli-0.19.0}/install.sh +0 -0
- {lcode_cli-0.17.0 → lcode_cli-0.19.0}/overrides/main.html +0 -0
- {lcode_cli-0.17.0 → lcode_cli-0.19.0}/scripts/record_demo.py +0 -0
- {lcode_cli-0.17.0 → lcode_cli-0.19.0}/scripts/social-preview.html +0 -0
- {lcode_cli-0.17.0 → lcode_cli-0.19.0}/src/lcode/__main__.py +0 -0
- {lcode_cli-0.17.0 → lcode_cli-0.19.0}/src/lcode/backends.py +0 -0
- {lcode_cli-0.17.0 → lcode_cli-0.19.0}/src/lcode/bench.py +0 -0
- {lcode_cli-0.17.0 → lcode_cli-0.19.0}/src/lcode/bench_backend.py +0 -0
- {lcode_cli-0.17.0 → lcode_cli-0.19.0}/src/lcode/catalog.py +0 -0
- {lcode_cli-0.17.0 → lcode_cli-0.19.0}/src/lcode/checkpoints.py +0 -0
- {lcode_cli-0.17.0 → lcode_cli-0.19.0}/src/lcode/codesearch.py +0 -0
- {lcode_cli-0.17.0 → lcode_cli-0.19.0}/src/lcode/config.py +0 -0
- {lcode_cli-0.17.0 → lcode_cli-0.19.0}/src/lcode/context.py +0 -0
- {lcode_cli-0.17.0 → lcode_cli-0.19.0}/src/lcode/extensions.py +0 -0
- {lcode_cli-0.17.0 → lcode_cli-0.19.0}/src/lcode/frontmatter.py +0 -0
- {lcode_cli-0.17.0 → lcode_cli-0.19.0}/src/lcode/gitflow.py +0 -0
- {lcode_cli-0.17.0 → lcode_cli-0.19.0}/src/lcode/hardware.py +0 -0
- {lcode_cli-0.17.0 → lcode_cli-0.19.0}/src/lcode/hooks.py +0 -0
- {lcode_cli-0.17.0 → lcode_cli-0.19.0}/src/lcode/limits.py +0 -0
- {lcode_cli-0.17.0 → lcode_cli-0.19.0}/src/lcode/lsp.py +0 -0
- {lcode_cli-0.17.0 → lcode_cli-0.19.0}/src/lcode/mcp/__init__.py +0 -0
- {lcode_cli-0.17.0 → lcode_cli-0.19.0}/src/lcode/mcp/auth.py +0 -0
- {lcode_cli-0.17.0 → lcode_cli-0.19.0}/src/lcode/mcp/catalog.py +0 -0
- {lcode_cli-0.17.0 → lcode_cli-0.19.0}/src/lcode/mcp/catalog.toml +0 -0
- {lcode_cli-0.17.0 → lcode_cli-0.19.0}/src/lcode/mcp/client.py +0 -0
- {lcode_cli-0.17.0 → lcode_cli-0.19.0}/src/lcode/mcp/commands.py +0 -0
- {lcode_cli-0.17.0 → lcode_cli-0.19.0}/src/lcode/mcp/config.py +0 -0
- {lcode_cli-0.17.0 → lcode_cli-0.19.0}/src/lcode/mcp/http.py +0 -0
- {lcode_cli-0.17.0 → lcode_cli-0.19.0}/src/lcode/mcp/manager.py +0 -0
- {lcode_cli-0.17.0 → lcode_cli-0.19.0}/src/lcode/mcp/protocol.py +0 -0
- {lcode_cli-0.17.0 → lcode_cli-0.19.0}/src/lcode/mcp/server.py +0 -0
- {lcode_cli-0.17.0 → lcode_cli-0.19.0}/src/lcode/mcp/stdio.py +0 -0
- {lcode_cli-0.17.0 → lcode_cli-0.19.0}/src/lcode/memory.py +0 -0
- {lcode_cli-0.17.0 → lcode_cli-0.19.0}/src/lcode/models.toml +0 -0
- {lcode_cli-0.17.0 → lcode_cli-0.19.0}/src/lcode/ollama.py +0 -0
- {lcode_cli-0.17.0 → lcode_cli-0.19.0}/src/lcode/render.py +0 -0
- {lcode_cli-0.17.0 → lcode_cli-0.19.0}/src/lcode/repl.py +0 -0
- {lcode_cli-0.17.0 → lcode_cli-0.19.0}/src/lcode/repomap.py +0 -0
- {lcode_cli-0.17.0 → lcode_cli-0.19.0}/src/lcode/sandbox.py +0 -0
- {lcode_cli-0.17.0 → lcode_cli-0.19.0}/src/lcode/servers/__init__.py +0 -0
- {lcode_cli-0.17.0 → lcode_cli-0.19.0}/src/lcode/servers/encord.py +0 -0
- {lcode_cli-0.17.0 → lcode_cli-0.19.0}/src/lcode/servers/valohai.py +0 -0
- {lcode_cli-0.17.0 → lcode_cli-0.19.0}/src/lcode/sessions.py +0 -0
- {lcode_cli-0.17.0 → lcode_cli-0.19.0}/src/lcode/vision.py +0 -0
- {lcode_cli-0.17.0 → lcode_cli-0.19.0}/src/lcode/web.py +0 -0
- {lcode_cli-0.17.0 → lcode_cli-0.19.0}/tests/conftest.py +0 -0
- {lcode_cli-0.17.0 → lcode_cli-0.19.0}/tests/fake_lsp_server.py +0 -0
- {lcode_cli-0.17.0 → lcode_cli-0.19.0}/tests/fake_mcp_server.py +0 -0
- {lcode_cli-0.17.0 → lcode_cli-0.19.0}/tests/test_agent.py +0 -0
- {lcode_cli-0.17.0 → lcode_cli-0.19.0}/tests/test_backends.py +0 -0
- {lcode_cli-0.17.0 → lcode_cli-0.19.0}/tests/test_bench.py +0 -0
- {lcode_cli-0.17.0 → lcode_cli-0.19.0}/tests/test_catalog.py +0 -0
- {lcode_cli-0.17.0 → lcode_cli-0.19.0}/tests/test_checkpoints.py +0 -0
- {lcode_cli-0.17.0 → lcode_cli-0.19.0}/tests/test_codesearch.py +0 -0
- {lcode_cli-0.17.0 → lcode_cli-0.19.0}/tests/test_config.py +0 -0
- {lcode_cli-0.17.0 → lcode_cli-0.19.0}/tests/test_context.py +0 -0
- {lcode_cli-0.17.0 → lcode_cli-0.19.0}/tests/test_context_picker.py +0 -0
- {lcode_cli-0.17.0 → lcode_cli-0.19.0}/tests/test_extensions.py +0 -0
- {lcode_cli-0.17.0 → lcode_cli-0.19.0}/tests/test_gitflow.py +0 -0
- {lcode_cli-0.17.0 → lcode_cli-0.19.0}/tests/test_hooks.py +0 -0
- {lcode_cli-0.17.0 → lcode_cli-0.19.0}/tests/test_lsp.py +0 -0
- {lcode_cli-0.17.0 → lcode_cli-0.19.0}/tests/test_mcp.py +0 -0
- {lcode_cli-0.17.0 → lcode_cli-0.19.0}/tests/test_memory.py +0 -0
- {lcode_cli-0.17.0 → lcode_cli-0.19.0}/tests/test_permissions.py +0 -0
- {lcode_cli-0.17.0 → lcode_cli-0.19.0}/tests/test_plan_mode.py +0 -0
- {lcode_cli-0.17.0 → lcode_cli-0.19.0}/tests/test_repomap.py +0 -0
- {lcode_cli-0.17.0 → lcode_cli-0.19.0}/tests/test_sandbox.py +0 -0
- {lcode_cli-0.17.0 → lcode_cli-0.19.0}/tests/test_servers.py +0 -0
- {lcode_cli-0.17.0 → lcode_cli-0.19.0}/tests/test_sessions.py +0 -0
- {lcode_cli-0.17.0 → lcode_cli-0.19.0}/tests/test_subagents.py +0 -0
- {lcode_cli-0.17.0 → lcode_cli-0.19.0}/tests/test_tools.py +0 -0
- {lcode_cli-0.17.0 → lcode_cli-0.19.0}/tests/test_vision.py +0 -0
- {lcode_cli-0.17.0 → lcode_cli-0.19.0}/tests/test_web.py +0 -0
- {lcode_cli-0.17.0 → lcode_cli-0.19.0}/uv.lock +0 -0
|
@@ -6,6 +6,37 @@ All notable changes to lcode are documented here. The format follows
|
|
|
6
6
|
|
|
7
7
|
## [Unreleased]
|
|
8
8
|
|
|
9
|
+
## [0.19.0] - 2026-10-06
|
|
10
|
+
|
|
11
|
+
### Added
|
|
12
|
+
|
|
13
|
+
- `lcode acp`: lcode inside editors that speak the Agent Client Protocol (Zed, JetBrains IDEs,
|
|
14
|
+
Neovim, Emacs and others). The editor shows the answers and thinking as they stream, each tool
|
|
15
|
+
call with the files it touches and a diff for edits, and asks permission questions and plan
|
|
16
|
+
approvals in its own dialog. lcode's permission modes are the session's modes, the todo list is
|
|
17
|
+
the editor's plan, and saved sessions reopen with their conversation. The model reads the
|
|
18
|
+
editor's buffers (unsaved changes included) and edits through them, and MCP servers the editor
|
|
19
|
+
passes join lcode's own. See [Editors](https://nasser1941.github.io/lcode/editors/) for setup.
|
|
20
|
+
|
|
21
|
+
### Fixed
|
|
22
|
+
|
|
23
|
+
- Cancelling a request whose answer was cut off mid-stream no longer ends it as if it were done.
|
|
24
|
+
|
|
25
|
+
## [0.18.0] - 2026-10-06
|
|
26
|
+
|
|
27
|
+
### Added
|
|
28
|
+
|
|
29
|
+
- `lcode -p "…" --output json` prints one result object (status, answer, tool calls, files
|
|
30
|
+
changed, token usage); `--output stream-json` prints an event per model step and tool result,
|
|
31
|
+
then the result. `--max-steps` and `--allowed-tools` limit a run, and the exit code says how it
|
|
32
|
+
ended. Without a person to ask, anything that needs permission is refused.
|
|
33
|
+
- A Python API: `from lcode import Session`, with `run()`, `stream()` and an `approve` callback
|
|
34
|
+
for permission requests. See `examples/api/fix_tests.py`.
|
|
35
|
+
- A GitHub Action for self-hosted runners (`uses: nasser1941/lcode@v0.18.0`). It answers `@lcode`
|
|
36
|
+
in issues and pull requests from the repository's owners, members and collaborators, proposes
|
|
37
|
+
changes as a pull request (or pushes them to the pull request's branch), and can review pull
|
|
38
|
+
requests. See [Automation](https://nasser1941.github.io/lcode/automation/).
|
|
39
|
+
|
|
9
40
|
## [0.17.0] - 2026-10-06
|
|
10
41
|
|
|
11
42
|
### Added
|
|
@@ -419,7 +450,9 @@ First public release.
|
|
|
419
450
|
- `AGENTS.md` project instructions and `/init` to generate them.
|
|
420
451
|
- One-line installer for Linux and macOS.
|
|
421
452
|
|
|
422
|
-
[Unreleased]: https://github.com/nasser1941/lcode/compare/v0.
|
|
453
|
+
[Unreleased]: https://github.com/nasser1941/lcode/compare/v0.19.0...HEAD
|
|
454
|
+
[0.19.0]: https://github.com/nasser1941/lcode/compare/v0.18.0...v0.19.0
|
|
455
|
+
[0.18.0]: https://github.com/nasser1941/lcode/compare/v0.17.0...v0.18.0
|
|
423
456
|
[0.17.0]: https://github.com/nasser1941/lcode/compare/v0.16.0...v0.17.0
|
|
424
457
|
[0.16.0]: https://github.com/nasser1941/lcode/compare/v0.15.0...v0.16.0
|
|
425
458
|
[0.15.0]: https://github.com/nasser1941/lcode/compare/v0.14.0...v0.15.0
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.5
|
|
2
2
|
Name: lcode-cli
|
|
3
|
-
Version: 0.
|
|
3
|
+
Version: 0.19.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/
|
|
@@ -104,6 +104,11 @@ through [Ollama](https://ollama.com), and when it needs current information it c
|
|
|
104
104
|
- **Git workflow.** `/commit` writes messages in your repository's style, `/review` checks the
|
|
105
105
|
changes with `file:line` findings, `/pr` opens the pull request, each after you approve it, and
|
|
106
106
|
`lcode --worktree` runs parallel sessions on one repository.
|
|
107
|
+
- **In your editor.** Zed, JetBrains IDEs, Neovim and other editors that speak the Agent Client
|
|
108
|
+
Protocol run lcode with `lcode acp`, with diffs and approvals in the editor.
|
|
109
|
+
- **Automation.** `lcode -p --output json` for scripts and CI, a Python API (`from lcode import
|
|
110
|
+
Session`), and a GitHub Action that answers `@lcode` in issues and pull requests on your own
|
|
111
|
+
self-hosted runner.
|
|
107
112
|
- **Bring your own model.** Eight curated open-weight models, all tested end to end, or any Ollama model
|
|
108
113
|
with tool calling. Or use LM Studio, llama.cpp, vLLM or MLX instead of Ollama.
|
|
109
114
|
- **MCP servers, ready to go.** Connect Jira and Confluence, GitHub, AWS, Google Drive, Grafana,
|
|
@@ -211,8 +216,7 @@ fills up. Details: [How it works](https://nasser1941.github.io/lcode/how-it-work
|
|
|
211
216
|
|
|
212
217
|
See the pinned [Roadmap issue](https://github.com/nasser1941/lcode/issues/10). Next up:
|
|
213
218
|
|
|
214
|
-
- [
|
|
215
|
-
- [Editor integration through the Agent Client Protocol](https://github.com/nasser1941/lcode/issues/49)
|
|
219
|
+
- [Long-running work: finish notifications and background commands](https://github.com/nasser1941/lcode/issues/51)
|
|
216
220
|
- More models in the catalog, and test reports from your hardware ([report one](https://github.com/nasser1941/lcode/issues/new?template=model_request.yml))
|
|
217
221
|
|
|
218
222
|
## Contributing
|
|
@@ -68,6 +68,11 @@ through [Ollama](https://ollama.com), and when it needs current information it c
|
|
|
68
68
|
- **Git workflow.** `/commit` writes messages in your repository's style, `/review` checks the
|
|
69
69
|
changes with `file:line` findings, `/pr` opens the pull request, each after you approve it, and
|
|
70
70
|
`lcode --worktree` runs parallel sessions on one repository.
|
|
71
|
+
- **In your editor.** Zed, JetBrains IDEs, Neovim and other editors that speak the Agent Client
|
|
72
|
+
Protocol run lcode with `lcode acp`, with diffs and approvals in the editor.
|
|
73
|
+
- **Automation.** `lcode -p --output json` for scripts and CI, a Python API (`from lcode import
|
|
74
|
+
Session`), and a GitHub Action that answers `@lcode` in issues and pull requests on your own
|
|
75
|
+
self-hosted runner.
|
|
71
76
|
- **Bring your own model.** Eight curated open-weight models, all tested end to end, or any Ollama model
|
|
72
77
|
with tool calling. Or use LM Studio, llama.cpp, vLLM or MLX instead of Ollama.
|
|
73
78
|
- **MCP servers, ready to go.** Connect Jira and Confluence, GitHub, AWS, Google Drive, Grafana,
|
|
@@ -175,8 +180,7 @@ fills up. Details: [How it works](https://nasser1941.github.io/lcode/how-it-work
|
|
|
175
180
|
|
|
176
181
|
See the pinned [Roadmap issue](https://github.com/nasser1941/lcode/issues/10). Next up:
|
|
177
182
|
|
|
178
|
-
- [
|
|
179
|
-
- [Editor integration through the Agent Client Protocol](https://github.com/nasser1941/lcode/issues/49)
|
|
183
|
+
- [Long-running work: finish notifications and background commands](https://github.com/nasser1941/lcode/issues/51)
|
|
180
184
|
- More models in the catalog, and test reports from your hardware ([report one](https://github.com/nasser1941/lcode/issues/new?template=model_request.yml))
|
|
181
185
|
|
|
182
186
|
## Contributing
|
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
name: lcode
|
|
2
|
+
description: Answer @lcode in issues and pull requests, propose changes and review pull requests, with an open-weight model on your own self-hosted runner.
|
|
3
|
+
author: nasser1941
|
|
4
|
+
branding:
|
|
5
|
+
icon: terminal
|
|
6
|
+
color: gray-dark
|
|
7
|
+
|
|
8
|
+
inputs:
|
|
9
|
+
model:
|
|
10
|
+
description: The model to use (default, the runner's lcode configuration)
|
|
11
|
+
required: false
|
|
12
|
+
default: ""
|
|
13
|
+
trigger:
|
|
14
|
+
description: The word that calls lcode in a comment
|
|
15
|
+
required: false
|
|
16
|
+
default: "@lcode"
|
|
17
|
+
review:
|
|
18
|
+
description: Review pull requests when they're opened or updated ("true" or "false")
|
|
19
|
+
required: false
|
|
20
|
+
default: "false"
|
|
21
|
+
review-forks:
|
|
22
|
+
description: Also review pull requests from forks; their code runs through lcode's tools on your runner
|
|
23
|
+
required: false
|
|
24
|
+
default: "false"
|
|
25
|
+
author-associations:
|
|
26
|
+
description: Who can call lcode, by their association with the repository
|
|
27
|
+
required: false
|
|
28
|
+
default: "OWNER,MEMBER,COLLABORATOR"
|
|
29
|
+
permission-mode:
|
|
30
|
+
description: auto-edit (file changes, no shell commands except allow-commands) or yolo (anything; only on an isolated runner)
|
|
31
|
+
required: false
|
|
32
|
+
default: "auto-edit"
|
|
33
|
+
allow-commands:
|
|
34
|
+
description: Shell commands the model may run, one per line or comma-separated, with * wildcards (e.g. "pytest*, npm test")
|
|
35
|
+
required: false
|
|
36
|
+
default: ""
|
|
37
|
+
max-steps:
|
|
38
|
+
description: Model steps per request before lcode stops
|
|
39
|
+
required: false
|
|
40
|
+
default: "60"
|
|
41
|
+
lcode-version:
|
|
42
|
+
description: The lcode version to run (default, the one matching this action's tag)
|
|
43
|
+
required: false
|
|
44
|
+
default: ""
|
|
45
|
+
github-token:
|
|
46
|
+
description: Token for comments, pull requests and pushes
|
|
47
|
+
required: false
|
|
48
|
+
default: ${{ github.token }}
|
|
49
|
+
|
|
50
|
+
runs:
|
|
51
|
+
using: composite
|
|
52
|
+
steps:
|
|
53
|
+
- name: Run lcode
|
|
54
|
+
shell: bash
|
|
55
|
+
env:
|
|
56
|
+
GITHUB_TOKEN: ${{ inputs.github-token }}
|
|
57
|
+
LCODE_MODEL: ${{ inputs.model }}
|
|
58
|
+
LCODE_TRIGGER: ${{ inputs.trigger }}
|
|
59
|
+
LCODE_REVIEW: ${{ inputs.review }}
|
|
60
|
+
LCODE_REVIEW_FORKS: ${{ inputs.review-forks }}
|
|
61
|
+
LCODE_ASSOCIATIONS: ${{ inputs.author-associations }}
|
|
62
|
+
LCODE_PERMISSION_MODE: ${{ inputs.permission-mode }}
|
|
63
|
+
LCODE_ALLOW_COMMANDS: ${{ inputs.allow-commands }}
|
|
64
|
+
LCODE_MAX_STEPS: ${{ inputs.max-steps }}
|
|
65
|
+
LCODE_VERSION: ${{ inputs.lcode-version }}
|
|
66
|
+
ACTION_REF: ${{ github.action_ref }}
|
|
67
|
+
run: |
|
|
68
|
+
version="${LCODE_VERSION:-${ACTION_REF#v}}"
|
|
69
|
+
spec="lcode-cli"
|
|
70
|
+
if [[ "$version" =~ ^[0-9]+\.[0-9]+\.[0-9]+$ ]]; then spec="lcode-cli==$version"; fi
|
|
71
|
+
if command -v uvx > /dev/null; then
|
|
72
|
+
uvx --from "$spec" lcode action
|
|
73
|
+
elif command -v lcode > /dev/null; then
|
|
74
|
+
lcode action
|
|
75
|
+
else
|
|
76
|
+
python3 -m venv "$RUNNER_TEMP/lcode-venv"
|
|
77
|
+
"$RUNNER_TEMP/lcode-venv/bin/pip" install --quiet "$spec"
|
|
78
|
+
"$RUNNER_TEMP/lcode-venv/bin/lcode" action
|
|
79
|
+
fi
|
|
@@ -0,0 +1,193 @@
|
|
|
1
|
+
# Automation
|
|
2
|
+
|
|
3
|
+
lcode can also run without a person at the keyboard:
|
|
4
|
+
- **Scripts and CI** get structured results from `lcode -p`.
|
|
5
|
+
- **Programs** use it from Python.
|
|
6
|
+
- **A GitHub Action** answers `@lcode` in issues and pull requests on your own GPU machine.
|
|
7
|
+
|
|
8
|
+
In all three, nothing waits for an answer: anything that would need your permission is refused,
|
|
9
|
+
unless the permission mode, a [permission rule](hooks.md#permission-rules) or your program allows it.
|
|
10
|
+
|
|
11
|
+
## Structured output
|
|
12
|
+
|
|
13
|
+
```bash
|
|
14
|
+
lcode -p "Fix the failing test in tests/test_parser.py" --auto-edit --output json
|
|
15
|
+
lcode -p "Explain the retry logic" --output stream-json --max-steps 20
|
|
16
|
+
```
|
|
17
|
+
|
|
18
|
+
| Option | |
|
|
19
|
+
|---|---|
|
|
20
|
+
| `--output json` | One JSON object when the request is done |
|
|
21
|
+
| `--output stream-json` | One JSON event per line as the request runs, ending with the same result object |
|
|
22
|
+
| `--max-steps N` | Stop after N model steps (status `max_steps`) |
|
|
23
|
+
| `--allowed-tools LIST` | Only these tools, e.g. `"read_file,grep,glob,bash"` |
|
|
24
|
+
|
|
25
|
+
lcode's usual output goes to stderr, so stdout holds only the JSON. The exit code says how it
|
|
26
|
+
went: `0` success, `1` an error, `3` stopped at `--max-steps`, `130` interrupted.
|
|
27
|
+
|
|
28
|
+
### The result
|
|
29
|
+
|
|
30
|
+
```json
|
|
31
|
+
{
|
|
32
|
+
"type": "result",
|
|
33
|
+
"schema": 1,
|
|
34
|
+
"lcode": "0.18.0",
|
|
35
|
+
"status": "success",
|
|
36
|
+
"text": "Two bugs fixed in `calc.py`: …",
|
|
37
|
+
"session_id": "20261006-101503-7f3a",
|
|
38
|
+
"model": "lcode-qwen3.6-35b",
|
|
39
|
+
"tool_calls": [
|
|
40
|
+
{"id": "call_ab9fmzq1", "name": "read_file", "arguments": {"path": "calc.py"}, "error": false, "output": "…"},
|
|
41
|
+
{"id": "call_lhhyt2jn", "name": "bash", "arguments": {"command": "pytest -q"}, "error": true, "output": "This needs the user's permission, …"}
|
|
42
|
+
],
|
|
43
|
+
"files_changed": [{"status": "M", "path": "calc.py"}],
|
|
44
|
+
"usage": {"requests": 6, "prompt_tokens": 35092, "output_tokens": 942},
|
|
45
|
+
"seconds": 30.67,
|
|
46
|
+
"error": ""
|
|
47
|
+
}
|
|
48
|
+
```
|
|
49
|
+
|
|
50
|
+
| Field | |
|
|
51
|
+
|---|---|
|
|
52
|
+
| `status` | `success`, `error`, `max_steps` or `interrupted` |
|
|
53
|
+
| `text` | The model's final answer |
|
|
54
|
+
| `tool_calls` | Every tool call, with its arguments and output (the first 4,000 characters). `error` is true when the call failed or wasn't allowed |
|
|
55
|
+
| `files_changed` | Files the request added (`A`), modified (`M`) or deleted (`D`), shell commands included |
|
|
56
|
+
| `usage` | Model requests and tokens; `prompt_tokens` includes tokens served from the prompt cache |
|
|
57
|
+
| `error` | What went wrong, when `status` is `error` |
|
|
58
|
+
| `session_id` | Continue the conversation later with `lcode --resume <id>` |
|
|
59
|
+
|
|
60
|
+
A failure before the request starts (no model server, an unknown model) prints
|
|
61
|
+
`{"type": "result", "status": "error", "error": "…"}` and exits with `1`.
|
|
62
|
+
|
|
63
|
+
### The events (stream-json)
|
|
64
|
+
|
|
65
|
+
```json
|
|
66
|
+
{"type": "start", "schema": 1, "lcode": "0.18.0", "session_id": "…", "model": "lcode-qwen3.6-35b", "cwd": "/src/app"}
|
|
67
|
+
{"type": "assistant", "text": "", "tool_calls": [{"id": "call_1", "name": "read_file", "arguments": {"path": "calc.py"}}]}
|
|
68
|
+
{"type": "tool_result", "id": "call_1", "name": "read_file", "error": false, "output": "…"}
|
|
69
|
+
{"type": "assistant", "text": "The bug is in clamp(): …", "tool_calls": []}
|
|
70
|
+
{"type": "result", "status": "success", …}
|
|
71
|
+
```
|
|
72
|
+
|
|
73
|
+
An `assistant` event comes after each model step; a `tool_result` follows each of its calls, with
|
|
74
|
+
the same `id`.
|
|
75
|
+
|
|
76
|
+
## Python
|
|
77
|
+
|
|
78
|
+
```python
|
|
79
|
+
from lcode import Session
|
|
80
|
+
|
|
81
|
+
with Session("path/to/repo", permission_mode="auto-edit") as session:
|
|
82
|
+
result = session.run("Fix the failing test in tests/test_parser.py")
|
|
83
|
+
print(result.status, result.text)
|
|
84
|
+
for change in result.files_changed:
|
|
85
|
+
print(change["status"], change["path"])
|
|
86
|
+
```
|
|
87
|
+
|
|
88
|
+
- **A session is one conversation:** each `run` continues it.
|
|
89
|
+
- **Events while it runs:** `session.stream(prompt)` yields the events above, ending with the result.
|
|
90
|
+
- **Permissions:** pass `approve` to decide permission requests. It gets
|
|
91
|
+
`{"kind": "bash", "title": "…", "target": "pytest -q"}`; without it, every request is refused.
|
|
92
|
+
- **Options:** `model`, `context`, `permission_mode`, `allowed_tools`, `max_steps`, `think`,
|
|
93
|
+
`web`, `memory`, `mcp` and `sandbox`. Leave one out to use your
|
|
94
|
+
[configuration](configuration.md).
|
|
95
|
+
- **lcode's own output:** `verbose=True` shows it on stderr.
|
|
96
|
+
- **When lcode can't start** (no model server, a missing model): `lcode.SetupError`.
|
|
97
|
+
|
|
98
|
+
[`examples/api/fix_tests.py`](https://github.com/nasser1941/lcode/blob/main/examples/api/fix_tests.py)
|
|
99
|
+
runs a repository's tests, lets the model fix what fails and approves only the test command:
|
|
100
|
+
|
|
101
|
+
```text
|
|
102
|
+
$ python examples/api/fix_tests.py ~/src/calc
|
|
103
|
+
✓ read_file: 1 def average(values):
|
|
104
|
+
✓ bash: ============================= test session starts ==============================
|
|
105
|
+
✓ edit_file: Edited calc.py (1 replacement(s)). Result:
|
|
106
|
+
✓ edit_file: Edited calc.py (1 replacement(s)). Result:
|
|
107
|
+
✓ bash: ============================= test session starts ==============================
|
|
108
|
+
|
|
109
|
+
success in 22s, 5 model requests
|
|
110
|
+
M calc.py
|
|
111
|
+
```
|
|
112
|
+
|
|
113
|
+
## GitHub Action
|
|
114
|
+
|
|
115
|
+
The action runs lcode on a **self-hosted runner**, a machine of yours with a GPU and Ollama (or
|
|
116
|
+
[another model server](servers.md)). The code and the model stay on that machine; only the
|
|
117
|
+
replies and the commits go to GitHub.
|
|
118
|
+
|
|
119
|
+
- **Someone comments `@lcode …`** on an issue or a pull request. lcode reacts with 👀, does what
|
|
120
|
+
they ask and replies.
|
|
121
|
+
- When it changed files on an **issue**, it commits them to a new branch and opens a pull
|
|
122
|
+
request that closes the issue.
|
|
123
|
+
- On a **pull request**, it pushes the commit to that pull request's branch.
|
|
124
|
+
- **With `review: true`**, every new or updated pull request gets a review as a comment.
|
|
125
|
+
|
|
126
|
+
```yaml
|
|
127
|
+
# .github/workflows/lcode.yml
|
|
128
|
+
name: lcode
|
|
129
|
+
on:
|
|
130
|
+
issue_comment:
|
|
131
|
+
types: [created]
|
|
132
|
+
pull_request:
|
|
133
|
+
types: [opened, synchronize]
|
|
134
|
+
|
|
135
|
+
permissions:
|
|
136
|
+
contents: write
|
|
137
|
+
issues: write
|
|
138
|
+
pull-requests: write
|
|
139
|
+
|
|
140
|
+
jobs:
|
|
141
|
+
lcode:
|
|
142
|
+
if: github.event_name == 'pull_request' || contains(github.event.comment.body, '@lcode')
|
|
143
|
+
runs-on: [self-hosted, gpu]
|
|
144
|
+
steps:
|
|
145
|
+
- uses: actions/checkout@v5
|
|
146
|
+
with:
|
|
147
|
+
fetch-depth: 0
|
|
148
|
+
- uses: nasser1941/lcode@v0.18.0
|
|
149
|
+
with:
|
|
150
|
+
review: true
|
|
151
|
+
allow-commands: "pytest*, npm test"
|
|
152
|
+
```
|
|
153
|
+
|
|
154
|
+
| Input | Default | |
|
|
155
|
+
|---|---|---|
|
|
156
|
+
| `model` | the runner's config | The model to use |
|
|
157
|
+
| `trigger` | `@lcode` | The word that calls lcode in a comment |
|
|
158
|
+
| `review` | `false` | Review pull requests when they're opened or updated |
|
|
159
|
+
| `review-forks` | `false` | Also review pull requests from forks |
|
|
160
|
+
| `author-associations` | `OWNER,MEMBER,COLLABORATOR` | Who can call lcode |
|
|
161
|
+
| `permission-mode` | `auto-edit` | `auto-edit`: file changes, and only the shell commands in `allow-commands`. `yolo`: anything |
|
|
162
|
+
| `allow-commands` | | Shell commands the model may run, with `*` wildcards |
|
|
163
|
+
| `max-steps` | `60` | Model steps per request |
|
|
164
|
+
| `lcode-version` | the action's | The lcode version to run |
|
|
165
|
+
|
|
166
|
+
### Setting up the runner
|
|
167
|
+
|
|
168
|
+
1. [Add a self-hosted runner](https://docs.github.com/en/actions/hosting-your-own-runners/managing-self-hosted-runners/adding-self-hosted-runners)
|
|
169
|
+
to the repository, and give it a label such as `gpu`.
|
|
170
|
+
2. On that machine, as the runner's user, install lcode and a model:
|
|
171
|
+
`curl -fsSL https://nasser1941.github.io/lcode/install.sh | bash`. The action runs lcode with
|
|
172
|
+
[uv](https://docs.astral.sh/uv/) when it's there, otherwise with the `lcode` it finds, otherwise
|
|
173
|
+
it installs lcode with pip.
|
|
174
|
+
3. Settings and [permission rules](hooks.md#permission-rules) for the action go in that user's
|
|
175
|
+
`~/.config/lcode/config.toml`. A repository's own `.lcode/settings.toml` isn't used, because
|
|
176
|
+
nobody approved it on the runner.
|
|
177
|
+
|
|
178
|
+
### Safety
|
|
179
|
+
|
|
180
|
+
- **Who can trigger it.** Only people with an owner, member or collaborator association, and
|
|
181
|
+
never bots.
|
|
182
|
+
- **Other people's text.** The issue's description and the code may have been written by anyone.
|
|
183
|
+
lcode tells the model to treat instructions in them as information, but a model can still be
|
|
184
|
+
talked into things. Keep `permission-mode: auto-edit` with a short `allow-commands` list,
|
|
185
|
+
unless the runner is isolated and disposable.
|
|
186
|
+
- **Forks.** Pull requests from forks aren't reviewed unless you set `review-forks`: their code
|
|
187
|
+
would run through lcode's tools on your machine.
|
|
188
|
+
- **Git.** lcode does the git steps itself: the model can't commit, push or switch branches, and
|
|
189
|
+
commits are made as `lcode`.
|
|
190
|
+
- **Public repositories.** GitHub
|
|
191
|
+
[advises against](https://docs.github.com/en/actions/security-for-github-actions/security-guides/security-hardening-for-github-actions#hardening-for-self-hosted-runners)
|
|
192
|
+
self-hosted runners for public repositories, since anyone can open a pull request. Use the
|
|
193
|
+
action on private repositories, or on a runner you can afford to lose.
|
|
@@ -0,0 +1,85 @@
|
|
|
1
|
+
# Editors
|
|
2
|
+
|
|
3
|
+
lcode also works inside editors that support the
|
|
4
|
+
[Agent Client Protocol](https://agentclientprotocol.com) (ACP), such as Zed, JetBrains IDEs,
|
|
5
|
+
Neovim and Emacs. The editor starts `lcode acp` and shows lcode's work in its own UI: answers,
|
|
6
|
+
tool calls, a diff for each edit, and permission questions.
|
|
7
|
+
|
|
8
|
+
## Zed
|
|
9
|
+
|
|
10
|
+
Add lcode to Zed's `settings.json`:
|
|
11
|
+
|
|
12
|
+
```json
|
|
13
|
+
{
|
|
14
|
+
"agent_servers": {
|
|
15
|
+
"lcode": {
|
|
16
|
+
"type": "custom",
|
|
17
|
+
"command": "lcode",
|
|
18
|
+
"args": ["acp"],
|
|
19
|
+
"env": {}
|
|
20
|
+
}
|
|
21
|
+
}
|
|
22
|
+
}
|
|
23
|
+
```
|
|
24
|
+
|
|
25
|
+
Then open the Agent Panel and start a new thread with **lcode** from the new-thread menu.
|
|
26
|
+
|
|
27
|
+
- **Zed can't start lcode:** use the full path in `command`, from `which lcode` (usually
|
|
28
|
+
`~/.local/bin/lcode`). An editor started from the desktop may not see your shell's `PATH`.
|
|
29
|
+
- **Something goes wrong:** run **dev: open acp logs** in Zed's command palette to see the
|
|
30
|
+
messages lcode and Zed exchange.
|
|
31
|
+
|
|
32
|
+
## JetBrains IDEs
|
|
33
|
+
|
|
34
|
+
Add lcode to `~/.jetbrains/acp.json`, with the full path from `which lcode`:
|
|
35
|
+
|
|
36
|
+
```json
|
|
37
|
+
{
|
|
38
|
+
"agent_servers": {
|
|
39
|
+
"lcode": {
|
|
40
|
+
"command": "/home/you/.local/bin/lcode",
|
|
41
|
+
"args": ["acp"]
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
```
|
|
46
|
+
|
|
47
|
+
Then pick lcode in the AI Chat tool window.
|
|
48
|
+
|
|
49
|
+
## Other editors
|
|
50
|
+
|
|
51
|
+
Any [ACP client](https://agentclientprotocol.com/overview/clients) works the same way: tell it
|
|
52
|
+
to run `lcode acp`. That includes Neovim (CodeCompanion, avante.nvim), Emacs (agent-shell),
|
|
53
|
+
VS Code extensions and more.
|
|
54
|
+
|
|
55
|
+
## What the editor shows
|
|
56
|
+
|
|
57
|
+
| In the editor | From lcode |
|
|
58
|
+
|---|---|
|
|
59
|
+
| The conversation | lcode's answers and its thinking, as they stream |
|
|
60
|
+
| Tool calls | Each tool call, with its kind (read, search, edit, run, fetch) and the files it touches |
|
|
61
|
+
| Edits | A diff of the whole file for each edit |
|
|
62
|
+
| Open files | Edits go through the editor, so open files update right away. The model reads what's in the editor, unsaved changes included |
|
|
63
|
+
| Permission questions | **Allow**, **Always allow** (for this session) or **Reject**, in the editor's own dialog |
|
|
64
|
+
| Modes | lcode's [permission modes](usage.md#permissions): Ask, Auto-edit, Plan and Yolo |
|
|
65
|
+
| Plans | In Plan mode, the plan is approved in the editor, which then switches to Ask or Auto-edit |
|
|
66
|
+
| The plan list | The model's todo list |
|
|
67
|
+
| Context | How much of the context window is in use |
|
|
68
|
+
| Commands | `/review` and [your own commands](commands.md) |
|
|
69
|
+
| Past threads | lcode's saved sessions: an editor that reopens a thread gets its conversation back |
|
|
70
|
+
|
|
71
|
+
[Checkpoints](usage.md#undo-and-checkpoints), [hooks and permission rules](hooks.md),
|
|
72
|
+
[memory](memory.md), [subagents](agents.md) and [MCP servers](mcp.md) work as in the terminal.
|
|
73
|
+
MCP servers the editor passes to its agents are added to lcode's own.
|
|
74
|
+
|
|
75
|
+
## Settings
|
|
76
|
+
|
|
77
|
+
lcode uses your [configuration](configuration.md): the model, the context window, the
|
|
78
|
+
[model server](servers.md) and the default permission mode. To use different settings in an
|
|
79
|
+
editor, set them in the agent's `env`, for example `"env": {"LCODE_MODEL": "qwen3.5-9b"}`.
|
|
80
|
+
|
|
81
|
+
A repository's own commands, skills, agents and hooks are used only after you
|
|
82
|
+
[approve them](commands.md#approving-a-repositorys-commands-skills-and-agents). An editor can't
|
|
83
|
+
ask, so run `lcode` in the repository once and approve them there.
|
|
84
|
+
|
|
85
|
+
To see lcode's own output while it runs in an editor, set `LCODE_ACP_LOG` to a file in `env`.
|
|
@@ -10,11 +10,15 @@ lcode doctor # check the installation (include this in bug repor
|
|
|
10
10
|
lcode config [set|unset] # show or change settings
|
|
11
11
|
lcode bench [models] # score models on small coding tasks on this machine
|
|
12
12
|
lcode mcp [catalog|add|list] # connect MCP servers: Jira, GitHub, AWS, databases… (see MCP servers)
|
|
13
|
+
lcode acp # run inside an editor over the Agent Client Protocol (see Editors)
|
|
13
14
|
```
|
|
14
15
|
|
|
15
16
|
| Option | Meaning |
|
|
16
17
|
|---|---|
|
|
17
18
|
| `-p, --prompt TEXT` | Run one request non-interactively, print the result and exit |
|
|
19
|
+
| `--output json\|stream-json` | With `-p`: print a JSON result, or a JSON event per line ([Automation](automation.md)) |
|
|
20
|
+
| `--max-steps N` | Stop a request after N model steps |
|
|
21
|
+
| `--allowed-tools LIST` | Only these tools, e.g. `"read_file,grep,glob,bash"` |
|
|
18
22
|
| `-m, --model NAME` | Catalog key (see `lcode models`) or any installed Ollama model |
|
|
19
23
|
| `--context SIZE` | Context window, e.g. `65536`, `128k`, `1m` |
|
|
20
24
|
| `-r, --repo DIR` | Work in another directory |
|
|
@@ -7,6 +7,7 @@ them everywhere):
|
|
|
7
7
|
|---|---|---|
|
|
8
8
|
| [`commands/review.md`](commands/review.md) | `.lcode/commands/review.md` | `/review` or `/review the parser` |
|
|
9
9
|
| [`skills/commit-message/`](skills/commit-message/) | `.lcode/skills/commit-message/` | ask for a commit message, or `/commit-message` |
|
|
10
|
+
| [`api/fix_tests.py`](api/fix_tests.py) | anywhere | `python fix_tests.py path/to/repo`: lcode from Python ([Automation](https://nasser1941.github.io/lcode/automation/)) |
|
|
10
11
|
|
|
11
12
|
```bash
|
|
12
13
|
mkdir -p .lcode/commands .lcode/skills
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
"""Fix a repository's failing tests with lcode, from Python.
|
|
2
|
+
|
|
3
|
+
python fix_tests.py path/to/repo
|
|
4
|
+
|
|
5
|
+
lcode may edit files, and run the test command only: every other shell command is refused,
|
|
6
|
+
because nobody is there to ask.
|
|
7
|
+
"""
|
|
8
|
+
|
|
9
|
+
import sys
|
|
10
|
+
|
|
11
|
+
from lcode import Session
|
|
12
|
+
|
|
13
|
+
TEST_COMMANDS = ("pytest", "python -m pytest", "python3 -m pytest")
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
def approve(request: dict) -> bool:
|
|
17
|
+
return request["kind"] == "bash" and request["target"].startswith(TEST_COMMANDS)
|
|
18
|
+
|
|
19
|
+
|
|
20
|
+
def main() -> int:
|
|
21
|
+
repo = sys.argv[1] if len(sys.argv) > 1 else "."
|
|
22
|
+
with Session(repo, permission_mode="auto-edit", approve=approve, max_steps=40) as session:
|
|
23
|
+
for event in session.stream("Run the tests, fix the code until they pass, and run them again."):
|
|
24
|
+
if event["type"] == "tool_result":
|
|
25
|
+
mark = "✗" if event["error"] else "✓"
|
|
26
|
+
print(f"{mark} {event['name']}: {event['output'].splitlines()[0][:80] if event['output'] else ''}")
|
|
27
|
+
elif event["type"] == "result":
|
|
28
|
+
print(f"\n{event['status']} in {event['seconds']:.0f}s, {event['usage']['requests']} model requests")
|
|
29
|
+
for change in event["files_changed"]:
|
|
30
|
+
print(f" {change['status']} {change['path']}")
|
|
31
|
+
print(f"\n{event['text']}")
|
|
32
|
+
return 0 if event["status"] == "success" else 1
|
|
33
|
+
return 1
|
|
34
|
+
|
|
35
|
+
|
|
36
|
+
if __name__ == "__main__":
|
|
37
|
+
sys.exit(main())
|
|
@@ -96,6 +96,8 @@ nav:
|
|
|
96
96
|
- Subagents: agents.md
|
|
97
97
|
- Commands and skills: commands.md
|
|
98
98
|
- Git workflow: git.md
|
|
99
|
+
- Automation: automation.md
|
|
100
|
+
- Editors: editors.md
|
|
99
101
|
- Code intelligence: lsp.md
|
|
100
102
|
- Repository map and code search: search.md
|
|
101
103
|
- Models & context windows: models.md
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
"""lcode — a local-first terminal coding agent powered by open-weight models via Ollama.
|
|
2
|
+
|
|
3
|
+
From a program: `from lcode import Session` (see lcode.api).
|
|
4
|
+
"""
|
|
5
|
+
|
|
6
|
+
__version__ = "0.19.0"
|
|
7
|
+
|
|
8
|
+
API = ("Session", "Result", "Options", "SetupError")
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
def __getattr__(name: str):
|
|
12
|
+
if name in API: # loaded on first use, so `import lcode` stays fast
|
|
13
|
+
from lcode import api
|
|
14
|
+
|
|
15
|
+
return getattr(api, name)
|
|
16
|
+
raise AttributeError(f"module 'lcode' has no attribute {name!r}")
|