Summary
A `--watch` flag that keeps `llmstxt-gen` running and automatically regenerates output whenever a tracked source file changes.
Depends on
Desired behaviour
- `llmstxt-gen generate . --watch` enters a loop, watching the files matched by the current config.
- On any change, run an incremental rebuild (using the hash cache) and overwrite the output files.
- Print a timestamped line like `[14:02:31] Rebuilt in 0.4s (3 files changed)` on each trigger.
- Gracefully handle `SIGINT` / Ctrl-C — exit cleanly with a `Watching stopped.` message.
- `--watch` combined with `--diff` is explicitly unsupported — raise a clear error early.
Implementation plan
1. pyproject.toml
Add an optional extras group:
```toml
[project.optional-dependencies]
watch = ["watchfiles>=0.21"]
```
2. src/llmstxt_gen/watcher.py (new file)
Thin wrapper around `watchfiles.watch()`:
```python
from pathlib import Path
from watchfiles import watch
def iter_changes(root: Path):
"""Yield on each batch of file changes under root."""
for changes in watch(root):
yield {str(Path(c[1]).relative_to(root)) for c in changes}
```
3. src/llmstxt_gen/cli.py
- Add `--watch` boolean flag to the `generate` command.
- Guard: if `--watch` and `--diff` both set, print error and exit 1.
- After initial generation, enter the watch loop:
- Call `iter_changes(root)`
- On each yield, re-collect only changed modules (cache handles skipping unchanged)
- Re-render and re-write output files
- Print `[HH:MM:SS] Rebuilt in Xs (N files changed)`
- Catch `KeyboardInterrupt` → print `Watching stopped.` and exit 0.
4. tests/test_watcher.py (new file)
- Mock `watchfiles.watch` to yield one synthetic change event then stop.
- Assert rebuild is triggered and output updated.
- Use `threading.Event` or `itertools.islice` to bound the loop in tests.
Acceptance criteria
Summary
A `--watch` flag that keeps `llmstxt-gen` running and automatically regenerates output whenever a tracked source file changes.
Depends on
Desired behaviour
Implementation plan
1.
pyproject.tomlAdd an optional extras group:
```toml
[project.optional-dependencies]
watch = ["watchfiles>=0.21"]
```
2.
src/llmstxt_gen/watcher.py(new file)Thin wrapper around `watchfiles.watch()`:
```python
from pathlib import Path
from watchfiles import watch
def iter_changes(root: Path):
"""Yield on each batch of file changes under root."""
for changes in watch(root):
yield {str(Path(c[1]).relative_to(root)) for c in changes}
```
3.
src/llmstxt_gen/cli.py4.
tests/test_watcher.py(new file)Acceptance criteria