feat: preflight - prerequisites checked and tool paths recorded before wikitool runs; launcher refuses without it (#151, POSIX half)
CI / verify (push) Successful in 2m18s
Release / release (push) Successful in 36s

Files changed:
- .claude/settings.json
- .gitea/workflows/ci.yml
- .gitea/workflows/nightly.yml
- .gitea/workflows/release.yml
- .gitea/workflows/tracker-live.yml
- .github/hooks/wiki-trace.json
- .gitignore
- .vibe/hooks.toml
- AGENTS.md
- CHANGES.md
- EVALS.md
- INSTALL.md
- README.md
- VERSION
- instructions/bootstrap.md
- instructions/preflight.md
- instructions/setup-instance.md
- instructions/upgrade-instance.md
- tools/CONTRACT.md
- tools/README.md
- tools/chemenu/cli.py
- tools/chemenu/commands/dist_cmd.py
- tools/chemenu/commands/docs_verify.py
- tools/chemenu/commands/doctor.py
- tools/chemenu/commands/git_publish.py
- tools/chemenu/commands/migrate_cmd.py
- tools/chemenu/config.py
- tools/chemenu/corpus_cache.py
- tools/chemenu/prerequisites.py
- tools/chemenu/search/ripgrep.py
- tools/chemenu/tests/conftest.py
- tools/chemenu/tests/test_dist_upgrade.py
- tools/chemenu/tests/test_doctor.py
- tools/chemenu/tests/test_preflight.py
- tools/chemenu/toolpaths.py
- tools/preflight.sh
- tools/prerequisites.txt
- tools/run_wikitool.py
- tools/trace-hook
- tools/wikitool
This commit is contained in:
torben committed 2026-10-01 05:52:55 +02:00
1 parent 5a731729f6
commit e4b2b6d9b1
40 files changed
+1849 -125

No files matched your search

+24 -5
View File
@@ -18,26 +18,45 @@ file deliberately has none - and `docs verify` now enforces that.
## Setup
```bash
cd tools
python3 -m venv .venv
.venv/bin/pip install -r requirements.txt
tools/preflight.sh # from the repo root
```
The preflight is the one way a checkout gets its environment: it checks the
tools listed in `prerequisites.txt`, records their absolute paths in
`../.wikitool-tools.json`, creates `.venv` and installs `requirements.txt` into
it with `-m pip`. It is POSIX sh because it has to run before Python is known
to exist; exit 42 means the user has to act, and its output says how. The
procedure an agent follows around it is `instructions/preflight.md`.
`tools/wikitool` refuses to start (exit 42) until the preflight has written a
*complete* `.wikitool-tools.json` and the venv exists. Past that, every `git`
and `rg` the package starts goes through `chemenu/toolpaths.py`, which reads
the recorded path - or, with no file at all (the test suite, a bare
`python -m chemenu.cli`), falls back to the bare name. A file that is present
but names a path that has gone raises `ToolPathError`, which the CLI turns
into an `ERROR` line pointing at the preflight rather than a traceback.
`jsonschema` and `PyYAML` are hard dependencies, not optional extras: schema
validation is the tool's whole safety net, so `cli.py` fails loudly with the
install command rather than degrading silently.
fix rather than degrading silently.
## Layout
```
tools/
wikitool entry point
wikitool entry point (POSIX sh): stops with exit 42 until the preflight has passed
run_wikitool.py what the launcher runs with the venv's Python - puts chemenu on sys.path without PYTHONPATH
preflight.sh checks prerequisites.txt, records .wikitool-tools.json, creates .venv (POSIX sh)
prerequisites.txt what the machine needs, one `|`-separated line per tool - read by the preflight and `doctor`
trace-hook what the harness hooks call: trace_ingest.py under the venv's Python
chemenu/
cli.py Typer app: registers every command, runs the budget gate, renders `-h`/`--help` from cli_contract
cli_contract.py one data record per command (name, synopsis, properties, exit status) - the source `-h`, the index and CONTRACT.md's generated region render from
config.py repo layout: root resolution and every path under it
api.py the in-process entry point - point Chemenu at a corpus and read it
errors.py ChemenuError / ValidationError / BackendError
toolpaths.py where git and rg are started from: .wikitool-tools.json, bare name only without the file
prerequisites.py prerequisites.txt read from Python, plus the platform and long-path questions `doctor` asks
corpus_cache.py one parsed corpus per commit, never cached while the tree is dirty
kb_scan.py page iteration/loading over kb/
blocks.py generated regions in a page body, found by marker rather than by heading