lemming-cli 0.4.0__tar.gz → 0.4.2__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.
- lemming_cli-0.4.2/.dockerignore +30 -0
- {lemming_cli-0.4.0 → lemming_cli-0.4.2}/.github/workflows/ci.yml +1 -1
- {lemming_cli-0.4.0 → lemming_cli-0.4.2}/Dockerfile +8 -2
- {lemming_cli-0.4.0 → lemming_cli-0.4.2}/PKG-INFO +18 -8
- {lemming_cli-0.4.0 → lemming_cli-0.4.2}/README.md +17 -7
- lemming_cli-0.4.2/SKILL.md +120 -0
- {lemming_cli-0.4.0 → lemming_cli-0.4.2}/pyproject.toml +1 -1
- {lemming_cli-0.4.0 → lemming_cli-0.4.2}/src/lemming/cli/exec_cli.py +6 -0
- {lemming_cli-0.4.0 → lemming_cli-0.4.2}/src/lemming/cli/exec_cli_test.py +18 -0
- {lemming_cli-0.4.0 → lemming_cli-0.4.2}/src/lemming/evals/cli.py +4 -0
- {lemming_cli-0.4.0 → lemming_cli-0.4.2}/src/lemming/evals/container.py +35 -1
- {lemming_cli-0.4.0 → lemming_cli-0.4.2}/src/lemming/evals/container_test.py +31 -0
- {lemming_cli-0.4.0 → lemming_cli-0.4.2}/src/lemming/runner.py +14 -3
- {lemming_cli-0.4.0 → lemming_cli-0.4.2}/src/lemming/runner_test.py +4 -2
- {lemming_cli-0.4.0 → lemming_cli-0.4.2}/uv.lock +1 -1
- lemming_cli-0.4.0/SKILL.md +0 -86
- {lemming_cli-0.4.0 → lemming_cli-0.4.2}/.github/workflows/publish.yml +0 -0
- {lemming_cli-0.4.0 → lemming_cli-0.4.2}/.github/workflows/screenshots.yml +0 -0
- {lemming_cli-0.4.0 → lemming_cli-0.4.2}/.gitignore +0 -0
- {lemming_cli-0.4.0 → lemming_cli-0.4.2}/.prettierignore +0 -0
- {lemming_cli-0.4.0 → lemming_cli-0.4.2}/.prettierrc +0 -0
- {lemming_cli-0.4.0 → lemming_cli-0.4.2}/LICENSE +0 -0
- {lemming_cli-0.4.0 → lemming_cli-0.4.2}/biome.json +0 -0
- {lemming_cli-0.4.0 → lemming_cli-0.4.2}/docker-compose.yml +0 -0
- {lemming_cli-0.4.0 → lemming_cli-0.4.2}/docs/EVALS.md +0 -0
- {lemming_cli-0.4.0 → lemming_cli-0.4.2}/docs/HOOKS.md +0 -0
- {lemming_cli-0.4.0 → lemming_cli-0.4.2}/docs/screenshots/dashboard-desktop.png +0 -0
- {lemming_cli-0.4.0 → lemming_cli-0.4.2}/docs/screenshots/dashboard-mobile.png +0 -0
- {lemming_cli-0.4.0 → lemming_cli-0.4.2}/docs/screenshots/task-log-desktop.png +0 -0
- {lemming_cli-0.4.0 → lemming_cli-0.4.2}/docs/screenshots/task-log-mobile.png +0 -0
- {lemming_cli-0.4.0 → lemming_cli-0.4.2}/package-lock.json +0 -0
- {lemming_cli-0.4.0 → lemming_cli-0.4.2}/package.json +0 -0
- {lemming_cli-0.4.0 → lemming_cli-0.4.2}/playwright.config.js +0 -0
- {lemming_cli-0.4.0 → lemming_cli-0.4.2}/src/lemming/__init__.py +0 -0
- {lemming_cli-0.4.0 → lemming_cli-0.4.2}/src/lemming/api/__init__.py +0 -0
- {lemming_cli-0.4.0 → lemming_cli-0.4.2}/src/lemming/api/auth.py +0 -0
- {lemming_cli-0.4.0 → lemming_cli-0.4.2}/src/lemming/api/auth_test.py +0 -0
- {lemming_cli-0.4.0 → lemming_cli-0.4.2}/src/lemming/api/config.py +0 -0
- {lemming_cli-0.4.0 → lemming_cli-0.4.2}/src/lemming/api/config_test.py +0 -0
- {lemming_cli-0.4.0 → lemming_cli-0.4.2}/src/lemming/api/conftest.py +0 -0
- {lemming_cli-0.4.0 → lemming_cli-0.4.2}/src/lemming/api/context.py +0 -0
- {lemming_cli-0.4.0 → lemming_cli-0.4.2}/src/lemming/api/context_test.py +0 -0
- {lemming_cli-0.4.0 → lemming_cli-0.4.2}/src/lemming/api/directories.py +0 -0
- {lemming_cli-0.4.0 → lemming_cli-0.4.2}/src/lemming/api/directories_test.py +0 -0
- {lemming_cli-0.4.0 → lemming_cli-0.4.2}/src/lemming/api/files.py +0 -0
- {lemming_cli-0.4.0 → lemming_cli-0.4.2}/src/lemming/api/files_test.py +0 -0
- {lemming_cli-0.4.0 → lemming_cli-0.4.2}/src/lemming/api/hooks.py +0 -0
- {lemming_cli-0.4.0 → lemming_cli-0.4.2}/src/lemming/api/hooks_test.py +0 -0
- {lemming_cli-0.4.0 → lemming_cli-0.4.2}/src/lemming/api/logging.py +0 -0
- {lemming_cli-0.4.0 → lemming_cli-0.4.2}/src/lemming/api/logging_test.py +0 -0
- {lemming_cli-0.4.0 → lemming_cli-0.4.2}/src/lemming/api/loop.py +0 -0
- {lemming_cli-0.4.0 → lemming_cli-0.4.2}/src/lemming/api/loop_test.py +0 -0
- {lemming_cli-0.4.0 → lemming_cli-0.4.2}/src/lemming/api/main.py +0 -0
- {lemming_cli-0.4.0 → lemming_cli-0.4.2}/src/lemming/api/main_test.py +0 -0
- {lemming_cli-0.4.0 → lemming_cli-0.4.2}/src/lemming/api/tasks.py +0 -0
- {lemming_cli-0.4.0 → lemming_cli-0.4.2}/src/lemming/api/tasks_test.py +0 -0
- {lemming_cli-0.4.0 → lemming_cli-0.4.2}/src/lemming/api_test.py +0 -0
- {lemming_cli-0.4.0 → lemming_cli-0.4.2}/src/lemming/brief_test.py +0 -0
- {lemming_cli-0.4.0 → lemming_cli-0.4.2}/src/lemming/cli/__init__.py +0 -0
- {lemming_cli-0.4.0 → lemming_cli-0.4.2}/src/lemming/cli/brief.py +0 -0
- {lemming_cli-0.4.0 → lemming_cli-0.4.2}/src/lemming/cli/config.py +0 -0
- {lemming_cli-0.4.0 → lemming_cli-0.4.2}/src/lemming/cli/config_test.py +0 -0
- {lemming_cli-0.4.0 → lemming_cli-0.4.2}/src/lemming/cli/goal.py +0 -0
- {lemming_cli-0.4.0 → lemming_cli-0.4.2}/src/lemming/cli/goal_test.py +0 -0
- {lemming_cli-0.4.0 → lemming_cli-0.4.2}/src/lemming/cli/hooks.py +0 -0
- {lemming_cli-0.4.0 → lemming_cli-0.4.2}/src/lemming/cli/hooks_test.py +0 -0
- {lemming_cli-0.4.0 → lemming_cli-0.4.2}/src/lemming/cli/machine_output_test.py +0 -0
- {lemming_cli-0.4.0 → lemming_cli-0.4.2}/src/lemming/cli/main.py +0 -0
- {lemming_cli-0.4.0 → lemming_cli-0.4.2}/src/lemming/cli/main_test.py +0 -0
- {lemming_cli-0.4.0 → lemming_cli-0.4.2}/src/lemming/cli/operations.py +0 -0
- {lemming_cli-0.4.0 → lemming_cli-0.4.2}/src/lemming/cli/operations_test.py +0 -0
- {lemming_cli-0.4.0 → lemming_cli-0.4.2}/src/lemming/cli/progress.py +0 -0
- {lemming_cli-0.4.0 → lemming_cli-0.4.2}/src/lemming/cli/progress_test.py +0 -0
- {lemming_cli-0.4.0 → lemming_cli-0.4.2}/src/lemming/cli/readability_cli.py +0 -0
- {lemming_cli-0.4.0 → lemming_cli-0.4.2}/src/lemming/cli/readability_cli_test.py +0 -0
- {lemming_cli-0.4.0 → lemming_cli-0.4.2}/src/lemming/cli/skill.py +0 -0
- {lemming_cli-0.4.0 → lemming_cli-0.4.2}/src/lemming/cli/skill_test.py +0 -0
- {lemming_cli-0.4.0 → lemming_cli-0.4.2}/src/lemming/cli/stop_test.py +0 -0
- {lemming_cli-0.4.0 → lemming_cli-0.4.2}/src/lemming/cli/tasks.py +0 -0
- {lemming_cli-0.4.0 → lemming_cli-0.4.2}/src/lemming/cli/tasks_test.py +0 -0
- {lemming_cli-0.4.0 → lemming_cli-0.4.2}/src/lemming/cli_test.py +0 -0
- {lemming_cli-0.4.0 → lemming_cli-0.4.2}/src/lemming/conftest.py +0 -0
- {lemming_cli-0.4.0 → lemming_cli-0.4.2}/src/lemming/evals/__init__.py +0 -0
- {lemming_cli-0.4.0 → lemming_cli-0.4.2}/src/lemming/evals/__main__.py +0 -0
- {lemming_cli-0.4.0 → lemming_cli-0.4.2}/src/lemming/evals/cli_test.py +0 -0
- {lemming_cli-0.4.0 → lemming_cli-0.4.2}/src/lemming/evals/fixtures.py +0 -0
- {lemming_cli-0.4.0 → lemming_cli-0.4.2}/src/lemming/evals/fixtures_test.py +0 -0
- {lemming_cli-0.4.0 → lemming_cli-0.4.2}/src/lemming/evals/harness.py +0 -0
- {lemming_cli-0.4.0 → lemming_cli-0.4.2}/src/lemming/evals/harness_test.py +0 -0
- {lemming_cli-0.4.0 → lemming_cli-0.4.2}/src/lemming/evals/readability.py +0 -0
- {lemming_cli-0.4.0 → lemming_cli-0.4.2}/src/lemming/evals/readability_test.py +0 -0
- {lemming_cli-0.4.0 → lemming_cli-0.4.2}/src/lemming/evals/roadmap.py +0 -0
- {lemming_cli-0.4.0 → lemming_cli-0.4.2}/src/lemming/evals/roadmap_test.py +0 -0
- {lemming_cli-0.4.0 → lemming_cli-0.4.2}/src/lemming/evals/scenarios.py +0 -0
- {lemming_cli-0.4.0 → lemming_cli-0.4.2}/src/lemming/evals/scenarios_test.py +0 -0
- {lemming_cli-0.4.0 → lemming_cli-0.4.2}/src/lemming/evals/suites.py +0 -0
- {lemming_cli-0.4.0 → lemming_cli-0.4.2}/src/lemming/evals/trial.py +0 -0
- {lemming_cli-0.4.0 → lemming_cli-0.4.2}/src/lemming/evals/trial_test.py +0 -0
- {lemming_cli-0.4.0 → lemming_cli-0.4.2}/src/lemming/hooks.py +0 -0
- {lemming_cli-0.4.0 → lemming_cli-0.4.2}/src/lemming/hooks_test.py +0 -0
- {lemming_cli-0.4.0 → lemming_cli-0.4.2}/src/lemming/integration_test.py +0 -0
- {lemming_cli-0.4.0 → lemming_cli-0.4.2}/src/lemming/main.py +0 -0
- {lemming_cli-0.4.0 → lemming_cli-0.4.2}/src/lemming/main_test.py +0 -0
- {lemming_cli-0.4.0 → lemming_cli-0.4.2}/src/lemming/models.py +0 -0
- {lemming_cli-0.4.0 → lemming_cli-0.4.2}/src/lemming/models_test.py +0 -0
- {lemming_cli-0.4.0 → lemming_cli-0.4.2}/src/lemming/orchestrator.py +0 -0
- {lemming_cli-0.4.0 → lemming_cli-0.4.2}/src/lemming/orchestrator_test.py +0 -0
- {lemming_cli-0.4.0 → lemming_cli-0.4.2}/src/lemming/paths.py +0 -0
- {lemming_cli-0.4.0 → lemming_cli-0.4.2}/src/lemming/paths_test.py +0 -0
- {lemming_cli-0.4.0 → lemming_cli-0.4.2}/src/lemming/persistence.py +0 -0
- {lemming_cli-0.4.0 → lemming_cli-0.4.2}/src/lemming/persistence_test.py +0 -0
- {lemming_cli-0.4.0 → lemming_cli-0.4.2}/src/lemming/prompts/hooks/50-readability.md +0 -0
- {lemming_cli-0.4.0 → lemming_cli-0.4.2}/src/lemming/prompts/hooks/60-testing.md +0 -0
- {lemming_cli-0.4.0 → lemming_cli-0.4.2}/src/lemming/prompts/hooks/70-ux.md +0 -0
- {lemming_cli-0.4.0 → lemming_cli-0.4.2}/src/lemming/prompts/hooks/90-roadmap.md +0 -0
- {lemming_cli-0.4.0 → lemming_cli-0.4.2}/src/lemming/prompts/taskrunner.md +0 -0
- {lemming_cli-0.4.0 → lemming_cli-0.4.2}/src/lemming/prompts.py +0 -0
- {lemming_cli-0.4.0 → lemming_cli-0.4.2}/src/lemming/prompts_test.py +0 -0
- {lemming_cli-0.4.0 → lemming_cli-0.4.2}/src/lemming/providers.py +0 -0
- {lemming_cli-0.4.0 → lemming_cli-0.4.2}/src/lemming/providers_test.py +0 -0
- {lemming_cli-0.4.0 → lemming_cli-0.4.2}/src/lemming/scope.py +0 -0
- {lemming_cli-0.4.0 → lemming_cli-0.4.2}/src/lemming/scope_test.py +0 -0
- {lemming_cli-0.4.0 → lemming_cli-0.4.2}/src/lemming/shutdown.py +0 -0
- {lemming_cli-0.4.0 → lemming_cli-0.4.2}/src/lemming/shutdown_integration_test.py +0 -0
- {lemming_cli-0.4.0 → lemming_cli-0.4.2}/src/lemming/shutdown_test.py +0 -0
- {lemming_cli-0.4.0 → lemming_cli-0.4.2}/src/lemming/tasks/__init__.py +0 -0
- {lemming_cli-0.4.0 → lemming_cli-0.4.2}/src/lemming/tasks/lifecycle.py +0 -0
- {lemming_cli-0.4.0 → lemming_cli-0.4.2}/src/lemming/tasks/lifecycle_test.py +0 -0
- {lemming_cli-0.4.0 → lemming_cli-0.4.2}/src/lemming/tasks/limits.py +0 -0
- {lemming_cli-0.4.0 → lemming_cli-0.4.2}/src/lemming/tasks/operations.py +0 -0
- {lemming_cli-0.4.0 → lemming_cli-0.4.2}/src/lemming/tasks/operations_test.py +0 -0
- {lemming_cli-0.4.0 → lemming_cli-0.4.2}/src/lemming/tasks/progress.py +0 -0
- {lemming_cli-0.4.0 → lemming_cli-0.4.2}/src/lemming/tasks/progress_test.py +0 -0
- {lemming_cli-0.4.0 → lemming_cli-0.4.2}/src/lemming/tasks/queries.py +0 -0
- {lemming_cli-0.4.0 → lemming_cli-0.4.2}/src/lemming/tasks/queries_test.py +0 -0
- {lemming_cli-0.4.0 → lemming_cli-0.4.2}/src/lemming/web/dashboard.spec.js +0 -0
- {lemming_cli-0.4.0 → lemming_cli-0.4.2}/src/lemming/web/dashboard.test.js +0 -0
- {lemming_cli-0.4.0 → lemming_cli-0.4.2}/src/lemming/web/favicon.js +0 -0
- {lemming_cli-0.4.0 → lemming_cli-0.4.2}/src/lemming/web/favicon.spec.js +0 -0
- {lemming_cli-0.4.0 → lemming_cli-0.4.2}/src/lemming/web/files.html +0 -0
- {lemming_cli-0.4.0 → lemming_cli-0.4.2}/src/lemming/web/files.spec.js +0 -0
- {lemming_cli-0.4.0 → lemming_cli-0.4.2}/src/lemming/web/index.html +0 -0
- {lemming_cli-0.4.0 → lemming_cli-0.4.2}/src/lemming/web/index.js +0 -0
- {lemming_cli-0.4.0 → lemming_cli-0.4.2}/src/lemming/web/logs.html +0 -0
- {lemming_cli-0.4.0 → lemming_cli-0.4.2}/src/lemming/web/logs.test.js +0 -0
- {lemming_cli-0.4.0 → lemming_cli-0.4.2}/src/lemming/web/mancha.js +0 -0
- {lemming_cli-0.4.0 → lemming_cli-0.4.2}/src/lemming/web/screenshots.spec.js +0 -0
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
# The image builds its own environments, so host-built ones are not just
|
|
2
|
+
# wasted bytes in the context — they are the wrong platform's binaries
|
|
3
|
+
# landing on top of what `uv sync` and `npm install` are about to create.
|
|
4
|
+
.venv
|
|
5
|
+
node_modules
|
|
6
|
+
|
|
7
|
+
# History and build products the image never reads.
|
|
8
|
+
.git
|
|
9
|
+
.github
|
|
10
|
+
dist
|
|
11
|
+
test-results
|
|
12
|
+
docs/screenshots
|
|
13
|
+
|
|
14
|
+
# Agent worktrees are whole checkouts of this repo, each with its own
|
|
15
|
+
# dependencies installed, and they dwarf the source they sit beside.
|
|
16
|
+
.claude
|
|
17
|
+
|
|
18
|
+
# Local state and caches.
|
|
19
|
+
.pytest_cache
|
|
20
|
+
.ruff_cache
|
|
21
|
+
__pycache__
|
|
22
|
+
*.pyc
|
|
23
|
+
.DS_Store
|
|
24
|
+
|
|
25
|
+
# Roadmaps and their locks belong to whoever is running lemming, not to
|
|
26
|
+
# the image; a stale one baked in would be read as that project's state.
|
|
27
|
+
tasks.yml
|
|
28
|
+
*.lock
|
|
29
|
+
!uv.lock
|
|
30
|
+
!package-lock.json
|
|
@@ -22,8 +22,14 @@ WORKDIR /opt/lemming
|
|
|
22
22
|
COPY . .
|
|
23
23
|
RUN uv sync --no-dev --frozen
|
|
24
24
|
|
|
25
|
-
#
|
|
26
|
-
|
|
25
|
+
# Frontend dependencies are always needed: postinstall vendors mancha into
|
|
26
|
+
# the web assets. The browsers are not, and they are more than half the
|
|
27
|
+
# image, so anything that will never drive one builds without them.
|
|
28
|
+
ARG INSTALL_BROWSERS=true
|
|
29
|
+
RUN npm install \
|
|
30
|
+
&& if [ "$INSTALL_BROWSERS" = "true" ]; then \
|
|
31
|
+
npx playwright install --with-deps; \
|
|
32
|
+
fi
|
|
27
33
|
|
|
28
34
|
# Pre-create the lemming home directory so users can bind-mount a .env file into it
|
|
29
35
|
RUN mkdir -p /root/.local/lemming
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.5
|
|
2
2
|
Name: lemming-cli
|
|
3
|
-
Version: 0.4.
|
|
3
|
+
Version: 0.4.2
|
|
4
4
|
Summary: An autonomous, iterative task runner for AI coding agents.
|
|
5
5
|
Project-URL: Homepage, https://github.com/owahltinez/lemming
|
|
6
6
|
Project-URL: Repository, https://github.com/owahltinez/lemming
|
|
@@ -140,7 +140,10 @@ removed unless it failed — in which case it is kept, and its path printed, so
|
|
|
140
140
|
the log can be read. Kept directories live in `~/.local/lemming/exec-*` and
|
|
141
141
|
are retired automatically a week later, so a recent failure is always still
|
|
142
142
|
there to inspect. Stdout carries the agent's message alone and everything
|
|
143
|
-
else goes to stderr, so the output can be consumed directly.
|
|
143
|
+
else goes to stderr, so the output can be consumed directly. Stderr reports
|
|
144
|
+
the ephemeral tasks file and task ID at startup; pass those to `lemming
|
|
145
|
+
--tasks-file <path> status <id>` or `logs <id>` to inspect an active run. Use
|
|
146
|
+
the global verbose flag (`lemming -v exec ...`) to stream runner activity.
|
|
144
147
|
|
|
145
148
|
Note that the agent runs unattended (`--yolo` by default), so it does not
|
|
146
149
|
inherit the permission prompts of whatever launched it.
|
|
@@ -395,8 +398,9 @@ These come before the subcommand and apply to all of them.
|
|
|
395
398
|
per-task `--runner`/`--model` overrides anything passed here.
|
|
396
399
|
- **`exec [<description>]`**: Run one task, or one set of reviews, outside any
|
|
397
400
|
roadmap. Prints the agent's closing message to stdout and everything else to
|
|
398
|
-
stderr
|
|
399
|
-
|
|
401
|
+
stderr, including its tasks file and task ID at startup. Use `lemming -v
|
|
402
|
+
exec ...` to stream runner activity. Exits non-zero if the task did not
|
|
403
|
+
complete. See [One-off tasks](#one-off-tasks-without-a-roadmap).
|
|
400
404
|
- `-f/--file`: Read the description from a file, or `-` for stdin. Unlike
|
|
401
405
|
`add`, there is no length cap.
|
|
402
406
|
- `--review <names>`: Reviews to run after the task, comma-separated or
|
|
@@ -533,10 +537,16 @@ pushing a `v*` tag triggers the `publish.yml` GitHub Actions workflow, which
|
|
|
533
537
|
builds the package with `uv build` and uploads it.
|
|
534
538
|
|
|
535
539
|
```bash
|
|
536
|
-
# 1. Bump
|
|
537
|
-
|
|
538
|
-
|
|
539
|
-
git
|
|
540
|
+
# 1. Bump pyproject.toml and uv.lock together, commit, and push
|
|
541
|
+
uv version --bump patch --no-sync
|
|
542
|
+
version="$(uv version --short)"
|
|
543
|
+
git add pyproject.toml uv.lock
|
|
544
|
+
git commit -m "Bump version to $version"
|
|
545
|
+
git push origin main
|
|
546
|
+
|
|
547
|
+
# 2. After CI passes, tag the release and push the tag
|
|
548
|
+
git tag "v$version"
|
|
549
|
+
git push origin "v$version"
|
|
540
550
|
```
|
|
541
551
|
|
|
542
552
|
---
|
|
@@ -118,7 +118,10 @@ removed unless it failed — in which case it is kept, and its path printed, so
|
|
|
118
118
|
the log can be read. Kept directories live in `~/.local/lemming/exec-*` and
|
|
119
119
|
are retired automatically a week later, so a recent failure is always still
|
|
120
120
|
there to inspect. Stdout carries the agent's message alone and everything
|
|
121
|
-
else goes to stderr, so the output can be consumed directly.
|
|
121
|
+
else goes to stderr, so the output can be consumed directly. Stderr reports
|
|
122
|
+
the ephemeral tasks file and task ID at startup; pass those to `lemming
|
|
123
|
+
--tasks-file <path> status <id>` or `logs <id>` to inspect an active run. Use
|
|
124
|
+
the global verbose flag (`lemming -v exec ...`) to stream runner activity.
|
|
122
125
|
|
|
123
126
|
Note that the agent runs unattended (`--yolo` by default), so it does not
|
|
124
127
|
inherit the permission prompts of whatever launched it.
|
|
@@ -373,8 +376,9 @@ These come before the subcommand and apply to all of them.
|
|
|
373
376
|
per-task `--runner`/`--model` overrides anything passed here.
|
|
374
377
|
- **`exec [<description>]`**: Run one task, or one set of reviews, outside any
|
|
375
378
|
roadmap. Prints the agent's closing message to stdout and everything else to
|
|
376
|
-
stderr
|
|
377
|
-
|
|
379
|
+
stderr, including its tasks file and task ID at startup. Use `lemming -v
|
|
380
|
+
exec ...` to stream runner activity. Exits non-zero if the task did not
|
|
381
|
+
complete. See [One-off tasks](#one-off-tasks-without-a-roadmap).
|
|
378
382
|
- `-f/--file`: Read the description from a file, or `-` for stdin. Unlike
|
|
379
383
|
`add`, there is no length cap.
|
|
380
384
|
- `--review <names>`: Reviews to run after the task, comma-separated or
|
|
@@ -511,10 +515,16 @@ pushing a `v*` tag triggers the `publish.yml` GitHub Actions workflow, which
|
|
|
511
515
|
builds the package with `uv build` and uploads it.
|
|
512
516
|
|
|
513
517
|
```bash
|
|
514
|
-
# 1. Bump
|
|
515
|
-
|
|
516
|
-
|
|
517
|
-
git
|
|
518
|
+
# 1. Bump pyproject.toml and uv.lock together, commit, and push
|
|
519
|
+
uv version --bump patch --no-sync
|
|
520
|
+
version="$(uv version --short)"
|
|
521
|
+
git add pyproject.toml uv.lock
|
|
522
|
+
git commit -m "Bump version to $version"
|
|
523
|
+
git push origin main
|
|
524
|
+
|
|
525
|
+
# 2. After CI passes, tag the release and push the tag
|
|
526
|
+
git tag "v$version"
|
|
527
|
+
git push origin "v$version"
|
|
518
528
|
```
|
|
519
529
|
|
|
520
530
|
---
|
|
@@ -0,0 +1,120 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: lemming
|
|
3
|
+
description: One interface over the AI coding agent CLIs (agy, claude, codex). Delegate a single task to another agent to spare a quota or play to its strengths; run a readability, testing, or UX review over changed files, a branch, or a path; or drive a multi-task project through a roadmap that survives context limits. Use whenever work should run under a different agent than the current one, when reviewing a diff before opening a pull request, or when a job is too large for one agent run.
|
|
4
|
+
license: MIT
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
# lemming
|
|
8
|
+
|
|
9
|
+
One interface over several agent CLIs. You do not need to know how `agy`,
|
|
10
|
+
`claude`, or `codex` spell their flags — only `lemming`.
|
|
11
|
+
|
|
12
|
+
Use `exec` for one unit of work, and a roadmap for anything larger than a
|
|
13
|
+
single agent run can hold.
|
|
14
|
+
|
|
15
|
+
## Delegate one task
|
|
16
|
+
|
|
17
|
+
```sh
|
|
18
|
+
lemming -v exec "Fix the flaky heartbeat test in src/runner_test.py" --runner codex
|
|
19
|
+
|
|
20
|
+
# Pipe a longer handoff rather than fighting shell quoting; no length limit
|
|
21
|
+
cat handoff.md | lemming -v exec -f - --runner agy
|
|
22
|
+
```
|
|
23
|
+
|
|
24
|
+
The agent's closing message comes back on **stdout**, everything else on
|
|
25
|
+
stderr, and the exit code is 0 only if the task completed. Read that message
|
|
26
|
+
instead of hunting through logs.
|
|
27
|
+
|
|
28
|
+
When you launch `exec` as a subprocess, use the global `-v` flag (before
|
|
29
|
+
`exec`) and continue monitoring its output until it exits. Verbose mode streams
|
|
30
|
+
the runner's activity on stderr. At startup, stderr also reports the exact
|
|
31
|
+
`Tasks file` and `Task ID`; use them from another process to inspect the
|
|
32
|
+
agent's durable findings or full log without guessing which `exec-*` directory
|
|
33
|
+
belongs to the run:
|
|
34
|
+
|
|
35
|
+
```sh
|
|
36
|
+
lemming --tasks-file <reported-path> status <reported-task-id>
|
|
37
|
+
lemming --tasks-file <reported-path> logs <reported-task-id>
|
|
38
|
+
```
|
|
39
|
+
|
|
40
|
+
The task runner is required to record its approach first and concise findings
|
|
41
|
+
as it works. These entries are checkpoints rather than a continuous trace, so
|
|
42
|
+
use verbose output or the log to tell whether it is actively making progress.
|
|
43
|
+
|
|
44
|
+
The task starts with an empty context and sees nothing of your conversation,
|
|
45
|
+
so give it everything it needs.
|
|
46
|
+
|
|
47
|
+
## Run a review
|
|
48
|
+
|
|
49
|
+
With no description there is nothing for a task runner to do, so only the
|
|
50
|
+
reviews run — against work that already exists.
|
|
51
|
+
|
|
52
|
+
```sh
|
|
53
|
+
lemming exec --review readability # uncommitted work
|
|
54
|
+
lemming exec --review testing --scope main...HEAD
|
|
55
|
+
lemming exec --review all --scope src/api/
|
|
56
|
+
lemming exec "Add pagination" --review all # do the work, then gate it
|
|
57
|
+
|
|
58
|
+
# Someone else's branch, in a worktree so your own tree is untouched
|
|
59
|
+
git worktree add /tmp/pr-123 && (cd /tmp/pr-123 && gh pr checkout 123)
|
|
60
|
+
lemming -C /tmp/pr-123 exec --review testing --scope main...HEAD
|
|
61
|
+
```
|
|
62
|
+
|
|
63
|
+
`--scope` takes paths, which pass through untouched, or a git revision range,
|
|
64
|
+
which is resolved to the files it changed. It defaults to uncommitted work,
|
|
65
|
+
and a clean tree stops the run rather than reviewing everything.
|
|
66
|
+
|
|
67
|
+
Reviews **edit the workspace** — readability applies fixes and reruns checks.
|
|
68
|
+
That is the point, but it means a review is not read-only.
|
|
69
|
+
|
|
70
|
+
## Drive a roadmap
|
|
71
|
+
|
|
72
|
+
For work that outlasts one agent run — a migration, a multi-step feature —
|
|
73
|
+
break it into tasks. Each runs with a fresh context seeded only by the goal
|
|
74
|
+
and recorded progress, so the project survives context limits.
|
|
75
|
+
|
|
76
|
+
```sh
|
|
77
|
+
lemming goal "Add offline support with a service worker and a sync queue"
|
|
78
|
+
lemming add "Register the service worker and cache the app shell"
|
|
79
|
+
lemming add "Queue writes in IndexedDB while offline"
|
|
80
|
+
lemming run # runs until the queue drains
|
|
81
|
+
```
|
|
82
|
+
|
|
83
|
+
Check on it, and read what an agent actually did:
|
|
84
|
+
|
|
85
|
+
```sh
|
|
86
|
+
lemming status # queue, attempts, and recorded progress
|
|
87
|
+
lemming status <id> # one task in detail, including its runner command
|
|
88
|
+
lemming logs # the active task's log, or logs <id> for one task
|
|
89
|
+
```
|
|
90
|
+
|
|
91
|
+
Adjust it while it runs — new tasks are picked up automatically:
|
|
92
|
+
|
|
93
|
+
```sh
|
|
94
|
+
lemming add "Add a retry backoff to the sync queue" --index 0 # jump the queue
|
|
95
|
+
lemming stop --after-current-task # drain, then stop
|
|
96
|
+
```
|
|
97
|
+
|
|
98
|
+
After each task, review hooks run automatically and a roadmap hook may revise
|
|
99
|
+
the queue. `lemming hooks list` shows them; `lemming hooks disable <name>`
|
|
100
|
+
turns one off for the project.
|
|
101
|
+
|
|
102
|
+
## What to know before running any of it
|
|
103
|
+
|
|
104
|
+
- **The agent runs unattended.** `--yolo` is the default, so it does not
|
|
105
|
+
inherit the permission prompts of whatever launched it. Treat this as
|
|
106
|
+
granting an agent unsupervised write access to the working directory.
|
|
107
|
+
- **`exec` makes one attempt, no retry.** A failure is final. A roadmap task
|
|
108
|
+
retries (3 by default) with its progress carried forward.
|
|
109
|
+
- **Interrupting leaves partial edits.** Nothing is restored, so there is no
|
|
110
|
+
atomicity to rely on.
|
|
111
|
+
- **Concurrent runs in one checkout interleave their edits.** Give each
|
|
112
|
+
writing run its own worktree and address it with `-C`.
|
|
113
|
+
- **Every run reports its state.** The tasks file and task ID are printed on
|
|
114
|
+
stderr at startup. Successful state is removed on exit unless `--keep` is
|
|
115
|
+
used; failures keep their directory and print it again for recovery. Kept
|
|
116
|
+
failure state is retired automatically after a week.
|
|
117
|
+
- **`--tasks-file` and `-C` are group options.** They go before the
|
|
118
|
+
subcommand — `lemming -C ../other exec ...`, never `exec -C ../other`.
|
|
119
|
+
|
|
120
|
+
`lemming --help`, or `--help` on any subcommand, has the full flag list.
|
|
@@ -324,6 +324,12 @@ def exec_command(
|
|
|
324
324
|
else _create_review_task(exec_dir, reviews, config)
|
|
325
325
|
)
|
|
326
326
|
|
|
327
|
+
# A supervising process needs an exact, race-free handle to the ephemeral
|
|
328
|
+
# roadmap while the run is active. Keep it on stderr so stdout remains the
|
|
329
|
+
# agent's closing-message interface.
|
|
330
|
+
click.echo(f"Tasks file: {tasks_file}", err=True)
|
|
331
|
+
click.echo(f"Task ID: {task_id}", err=True)
|
|
332
|
+
|
|
327
333
|
shutdown.clear_drain()
|
|
328
334
|
shutdown.install_handlers()
|
|
329
335
|
|
|
@@ -80,6 +80,24 @@ def test_exec_keeps_progress_chatter_off_stdout(workspace):
|
|
|
80
80
|
assert "Attempt" in result.stderr
|
|
81
81
|
|
|
82
82
|
|
|
83
|
+
def test_exec_announces_monitoring_coordinates_on_stderr(workspace):
|
|
84
|
+
"""A supervisor can inspect an active exec without guessing its state."""
|
|
85
|
+
seen = {}
|
|
86
|
+
|
|
87
|
+
def finish(cmd, tasks_file, task_id, *args, **kwargs):
|
|
88
|
+
seen["tasks_file"] = tasks_file
|
|
89
|
+
seen["task_id"] = task_id
|
|
90
|
+
return _finish("Done.")(cmd, tasks_file, task_id, *args, **kwargs)
|
|
91
|
+
|
|
92
|
+
with mock.patch("lemming.runner.run_with_heartbeat", finish):
|
|
93
|
+
result = CliRunner().invoke(cli, ["exec", "Fix the flaky test"])
|
|
94
|
+
|
|
95
|
+
assert result.exit_code == 0, result.stderr
|
|
96
|
+
assert result.stdout.strip() == "Done."
|
|
97
|
+
assert f"Tasks file: {seen['tasks_file']}" in result.stderr
|
|
98
|
+
assert f"Task ID: {seen['task_id']}" in result.stderr
|
|
99
|
+
|
|
100
|
+
|
|
83
101
|
def test_exec_removes_its_state_directory_on_success(workspace):
|
|
84
102
|
"""A one-shot leaves nothing behind when it worked."""
|
|
85
103
|
with mock.patch("lemming.runner.run_with_heartbeat", _finish("Done.")):
|
|
@@ -178,6 +178,10 @@ def run(
|
|
|
178
178
|
)
|
|
179
179
|
click.echo(f"Building eval image '{image}'...")
|
|
180
180
|
container.build_image(context, image=image, docker=docker)
|
|
181
|
+
# The image is what the trials need; the cache that produced it is
|
|
182
|
+
# dead weight, and it outgrows the image several times over across
|
|
183
|
+
# repeated runs.
|
|
184
|
+
container.prune_build_cache(docker=docker)
|
|
181
185
|
|
|
182
186
|
if run_dir is None:
|
|
183
187
|
run_dir = pathlib.Path(tempfile.mkdtemp(prefix="lemming-evals-"))
|
|
@@ -41,7 +41,41 @@ def build_image(
|
|
|
41
41
|
image: Tag for the built image.
|
|
42
42
|
docker: Docker-compatible CLI binary to invoke.
|
|
43
43
|
"""
|
|
44
|
-
|
|
44
|
+
# No scenario drives a browser, and they are more than half the image.
|
|
45
|
+
subprocess.run(
|
|
46
|
+
[
|
|
47
|
+
docker,
|
|
48
|
+
"build",
|
|
49
|
+
"--build-arg",
|
|
50
|
+
"INSTALL_BROWSERS=false",
|
|
51
|
+
"--tag",
|
|
52
|
+
image,
|
|
53
|
+
str(context),
|
|
54
|
+
],
|
|
55
|
+
check=True,
|
|
56
|
+
)
|
|
57
|
+
|
|
58
|
+
|
|
59
|
+
def prune_build_cache(docker: str = "docker") -> None:
|
|
60
|
+
"""Discards the build cache left behind by an eval image build.
|
|
61
|
+
|
|
62
|
+
Cache accumulates faster than images do — a run rebuilding this image a
|
|
63
|
+
few times leaves tens of gigabytes behind — and nothing reuses it once
|
|
64
|
+
the trials have finished.
|
|
65
|
+
|
|
66
|
+
Args:
|
|
67
|
+
docker: Docker-compatible CLI binary to invoke.
|
|
68
|
+
"""
|
|
69
|
+
try:
|
|
70
|
+
subprocess.run(
|
|
71
|
+
[docker, "builder", "prune", "--force", "--all"],
|
|
72
|
+
check=False,
|
|
73
|
+
capture_output=True,
|
|
74
|
+
)
|
|
75
|
+
except OSError:
|
|
76
|
+
# This runs after the results are in; failing to tidy up must never
|
|
77
|
+
# be the reason a completed eval run reports an error.
|
|
78
|
+
pass
|
|
45
79
|
|
|
46
80
|
|
|
47
81
|
def trial_command(
|
|
@@ -84,3 +84,34 @@ class TestRunTrial(unittest.TestCase):
|
|
|
84
84
|
|
|
85
85
|
if __name__ == "__main__":
|
|
86
86
|
unittest.main()
|
|
87
|
+
|
|
88
|
+
|
|
89
|
+
class BuildImageTest(unittest.TestCase):
|
|
90
|
+
"""The build must not carry what the eval trials never use."""
|
|
91
|
+
|
|
92
|
+
@unittest.mock.patch("subprocess.run")
|
|
93
|
+
def test_builds_without_browsers(
|
|
94
|
+
self, run: unittest.mock.MagicMock
|
|
95
|
+
) -> None:
|
|
96
|
+
"""Browsers are over half the image and no trial drives one."""
|
|
97
|
+
container.build_image(pathlib.Path("/repo"))
|
|
98
|
+
|
|
99
|
+
argv = run.call_args[0][0]
|
|
100
|
+
self.assertIn("--build-arg", argv)
|
|
101
|
+
self.assertIn("INSTALL_BROWSERS=false", argv)
|
|
102
|
+
|
|
103
|
+
@unittest.mock.patch("subprocess.run")
|
|
104
|
+
def test_prunes_the_build_cache(self, run: unittest.mock.MagicMock) -> None:
|
|
105
|
+
"""Repeated eval runs accumulate cache faster than images."""
|
|
106
|
+
container.prune_build_cache()
|
|
107
|
+
|
|
108
|
+
argv = run.call_args[0][0]
|
|
109
|
+
self.assertEqual(argv[:3], ["docker", "builder", "prune"])
|
|
110
|
+
self.assertIn("--force", argv)
|
|
111
|
+
|
|
112
|
+
@unittest.mock.patch("subprocess.run", side_effect=OSError("no docker"))
|
|
113
|
+
def test_pruning_never_fails_a_run(
|
|
114
|
+
self, run: unittest.mock.MagicMock
|
|
115
|
+
) -> None:
|
|
116
|
+
"""Cleanup runs after the results are in; it must not lose them."""
|
|
117
|
+
container.prune_build_cache()
|
|
@@ -29,6 +29,10 @@ KILL_GRACE_SECONDS = 5
|
|
|
29
29
|
# inherit the pipe and hold it open indefinitely.
|
|
30
30
|
OUTPUT_DRAIN_SECONDS = 5
|
|
31
31
|
|
|
32
|
+
# Headroom between the task time limit and a runner's own print-mode timeout,
|
|
33
|
+
# so the two never race to end the same run.
|
|
34
|
+
PRINT_TIMEOUT_GRACE_MINUTES = 5
|
|
35
|
+
|
|
32
36
|
|
|
33
37
|
def _pretty_quote(s: str) -> str:
|
|
34
38
|
"""Quotes a string for shell execution, preferring readable quoting.
|
|
@@ -234,9 +238,16 @@ def build_runner_command(
|
|
|
234
238
|
# payload, with none of claude's top-level "type".
|
|
235
239
|
cmd.extend(["--output-format", "stream-json"])
|
|
236
240
|
|
|
237
|
-
# agy caps print mode at 5 minutes by default; extend it
|
|
238
|
-
# task time limit (or effectively unlimited when there is
|
|
239
|
-
|
|
241
|
+
# agy caps print mode at 5 minutes by default; extend it past the
|
|
242
|
+
# task time limit (or make it effectively unlimited when there is
|
|
243
|
+
# none). The headroom leaves Lemming's own kill to end an
|
|
244
|
+
# overrunning task, which records why it stopped; agy's expiry
|
|
245
|
+
# reports an empty response instead, losing the run's outcome.
|
|
246
|
+
print_timeout = (
|
|
247
|
+
f"{time_limit + PRINT_TIMEOUT_GRACE_MINUTES}m"
|
|
248
|
+
if time_limit > 0
|
|
249
|
+
else "24h"
|
|
250
|
+
)
|
|
240
251
|
cmd.extend(["--print-timeout", print_timeout])
|
|
241
252
|
|
|
242
253
|
prompt_arg = "--prompt"
|
|
@@ -48,11 +48,13 @@ def test_build_runner_command_agy_streams_json_events():
|
|
|
48
48
|
assert "--log-file" not in cmd
|
|
49
49
|
|
|
50
50
|
|
|
51
|
-
def
|
|
51
|
+
def test_build_runner_command_agy_print_timeout_clears_time_limit():
|
|
52
|
+
# The runner's own timeout must not race Lemming's kill: Lemming records
|
|
53
|
+
# why it stopped the task, whereas agy's expiry yields an empty response.
|
|
52
54
|
cmd = runner.build_runner_command(
|
|
53
55
|
"agy", "my prompt", yolo=True, time_limit=45
|
|
54
56
|
)
|
|
55
|
-
assert cmd[cmd.index("--print-timeout") + 1] == "
|
|
57
|
+
assert cmd[cmd.index("--print-timeout") + 1] == "50m"
|
|
56
58
|
|
|
57
59
|
|
|
58
60
|
def test_build_runner_command_agy_print_timeout_without_time_limit():
|
lemming_cli-0.4.0/SKILL.md
DELETED
|
@@ -1,86 +0,0 @@
|
|
|
1
|
-
---
|
|
2
|
-
name: lemming
|
|
3
|
-
description: Delegate a single coding task to another AI agent CLI (agy, claude, codex) through one interface, or run a code review — readability, testing, UX — over changed files, a PR branch, or a path. Use when handing work to a different agent to spare a quota or play to its strengths, or when reviewing a diff before opening a pull request. Not for driving a multi-task project; that is a roadmap.
|
|
4
|
-
license: MIT
|
|
5
|
-
---
|
|
6
|
-
|
|
7
|
-
# lemming
|
|
8
|
-
|
|
9
|
-
One interface over several agent CLIs. You do not need to know how `agy`,
|
|
10
|
-
`claude`, or `codex` spell their flags — only `lemming exec`.
|
|
11
|
-
|
|
12
|
-
## Delegate one task
|
|
13
|
-
|
|
14
|
-
```sh
|
|
15
|
-
lemming exec "Fix the flaky heartbeat test in src/runner_test.py" --runner codex
|
|
16
|
-
```
|
|
17
|
-
|
|
18
|
-
The agent's closing message comes back on **stdout**; progress and the event
|
|
19
|
-
trace go to stderr. Exit code is 0 only if the task completed. That message is
|
|
20
|
-
the return value — read it instead of hunting through logs.
|
|
21
|
-
|
|
22
|
-
Pipe a longer handoff rather than fighting shell quoting. There is no length
|
|
23
|
-
limit, unlike a roadmap task description:
|
|
24
|
-
|
|
25
|
-
```sh
|
|
26
|
-
cat handoff.md | lemming exec -f - --runner agy
|
|
27
|
-
```
|
|
28
|
-
|
|
29
|
-
Delegate when another agent's quota, price, or strengths suit the work better
|
|
30
|
-
than yours. Give the task everything it needs: it starts with an empty context
|
|
31
|
-
and sees nothing of your conversation.
|
|
32
|
-
|
|
33
|
-
## Run a review
|
|
34
|
-
|
|
35
|
-
With no description there is nothing for a task runner to do, so only the
|
|
36
|
-
reviews run — against work that already exists.
|
|
37
|
-
|
|
38
|
-
```sh
|
|
39
|
-
lemming exec --review readability # uncommitted work
|
|
40
|
-
lemming exec --review testing --scope main...HEAD
|
|
41
|
-
lemming exec --review all --scope src/api/
|
|
42
|
-
lemming exec "Add pagination" --review all # do the work, then gate it
|
|
43
|
-
```
|
|
44
|
-
|
|
45
|
-
`--scope` takes paths, which pass through untouched, or a git revision range,
|
|
46
|
-
which is resolved to the files it changed. It defaults to uncommitted work.
|
|
47
|
-
A clean tree stops the run rather than reviewing everything.
|
|
48
|
-
|
|
49
|
-
Reviews **edit the workspace**: readability applies fixes and reruns checks.
|
|
50
|
-
That is the point — but it means a review is not read-only.
|
|
51
|
-
|
|
52
|
-
## Reviewing someone else's branch
|
|
53
|
-
|
|
54
|
-
Check it out in a worktree so your own tree is untouched, and point `-C` at it:
|
|
55
|
-
|
|
56
|
-
```sh
|
|
57
|
-
git worktree add /tmp/pr-123 && (cd /tmp/pr-123 && gh pr checkout 123)
|
|
58
|
-
lemming -C /tmp/pr-123 exec --review testing --scope main...HEAD
|
|
59
|
-
```
|
|
60
|
-
|
|
61
|
-
## What to know before running it
|
|
62
|
-
|
|
63
|
-
- **The agent runs unattended.** `--yolo` is the default, so it does not
|
|
64
|
-
inherit the permission prompts of whatever launched it. Treat `lemming exec`
|
|
65
|
-
as granting an agent unsupervised write access to the working directory.
|
|
66
|
-
- **One agent run, no retry.** A failure is final; it does not silently try
|
|
67
|
-
again. `--time-limit` caps the wall clock (default 60 minutes).
|
|
68
|
-
- **Interrupting leaves partial edits.** The workspace is not restored, so
|
|
69
|
-
there is no atomicity to rely on.
|
|
70
|
-
- **Failures keep their log.** The state directory path is printed on stderr;
|
|
71
|
-
read it with `lemming logs` pointed at that tasks file.
|
|
72
|
-
|
|
73
|
-
## Running several at once
|
|
74
|
-
|
|
75
|
-
Concurrent runs in one checkout will interleave their edits. Give each write
|
|
76
|
-
task its own worktree and address it with `-C`. Read-only work parallelizes
|
|
77
|
-
safely as-is.
|
|
78
|
-
|
|
79
|
-
## When not to use it
|
|
80
|
-
|
|
81
|
-
`exec` is for one unit of work. Anything needing more context than a single
|
|
82
|
-
agent run can hold — a migration across a large codebase, a multi-step feature
|
|
83
|
-
— belongs on a roadmap: `lemming add`, then `lemming run`. In particular,
|
|
84
|
-
`--scope .` over a large repository *samples*; it does not cover.
|
|
85
|
-
|
|
86
|
-
Run `lemming exec --help` for the full flag list.
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|