diff --git a/.github/workflows/eval.yml b/.github/workflows/eval.yml index 4befd2b..949205c 100644 --- a/.github/workflows/eval.yml +++ b/.github/workflows/eval.yml @@ -31,11 +31,19 @@ jobs: timeout-minutes: 20 steps: - uses: actions/checkout@v4 + with: + # Full history so hatch-vcs sees the tags and stamps a truthful + # dev version into the installed engine (and every manifest's + # lc_version) instead of a 0.1.dev fallback + fetch-depth: 0 - name: Set up uv + # No python-version input: it would export an ambient UV_PYTHON, + # which lc's install-settings scrub then rightly warns about on + # every single invocation the agent makes. The interpreter is + # pinned per tool install below instead. uses: astral-sh/setup-uv@v6 with: - python-version: "3.12" enable-cache: true - name: Install lightcone-cli + astra (uv tools) @@ -49,8 +57,8 @@ jobs: # venv is activated: the agent's shell sees the tools exactly as # an end user's would. run: | - uv tool install "$GITHUB_WORKSPACE" - uv tool install "astra-tools==$(grep -oP 'astra-tools==\K[0-9][0-9.]*' pyproject.toml)" + uv tool install --python 3.12 "$GITHUB_WORKSPACE" + uv tool install --python 3.12 "astra-tools==$(grep -oP 'astra-tools==\K[0-9][0-9.]*' pyproject.toml)" echo "$HOME/.local/bin" >> "$GITHUB_PATH" - name: Install Claude Code + astra plugin diff --git a/docs/cli/run.md b/docs/cli/run.md index 594a18a..2171b98 100644 --- a/docs/cli/run.md +++ b/docs/cli/run.md @@ -13,7 +13,10 @@ lc run COMMAND... ``` Everything after `run` is the command, verbatim — flags included. -`lc run` takes no options of its own, so nothing needs escaping: +Argv, the `docker run` / `uv run` convention: a single quoted string +would be exec'd as one filename, so probe shell syntax through +`bash -c` instead. `lc run` takes no options of its own, so nothing +else needs escaping: ```bash lc run python -c "import numpy; print(numpy.__version__)" diff --git a/evals/prompt.md b/evals/prompt.md index c0f948f..aa05abc 100644 --- a/evals/prompt.md +++ b/evals/prompt.md @@ -26,7 +26,10 @@ This project is driven by two CLIs — use them rather than improvising: making. - `lc run ` runs an ad-hoc command in the project environment under the same isolation a recipe gets — useful for - probing why a recipe would fail. + probing why a recipe would fail. Argv style, like `docker run` or + `uv run`: `lc run python scripts/fit.py --output /tmp/x`, never a + single quoted shell string; for shell syntax use + `lc run bash -c '...'`. - Outputs land in `results/baseline//`, each with a `.lightcone-manifest.json` manifest written and committed by the engine. Never write into `results/` yourself: a hand-placed file diff --git a/src/lightcone/cli/commands.py b/src/lightcone/cli/commands.py index 75319b2..8fbf4ca 100644 --- a/src/lightcone/cli/commands.py +++ b/src/lightcone/cli/commands.py @@ -368,8 +368,8 @@ def status(as_json: bool) -> None: "unfetched": "content not in this clone — the next build or run fetches it", }[state] lines.append(f" image: {tag} — {described}") - lines.append(f" sandbox: {report.sandbox}") - lines.append(f" crate: {report.crate}") + lines.append(f" sandbox: {escape(report.sandbox)}") + lines.append(f" crate: {escape(report.crate)}") lines.append("") marks = {"current": "[dim]·[/dim]", "behind": "[cyan]·[/cyan]", "stale": "[yellow]![/yellow]"} width = max((len(o.output) for o in report.outputs), default=0) diff --git a/tests/test_cli.py b/tests/test_cli.py index 8970165..1f5bd9e 100644 --- a/tests/test_cli.py +++ b/tests/test_cli.py @@ -561,6 +561,23 @@ def test_status_headers_answer_mode_image_and_sandbox( assert "crate: up to date with the outputs" in output +def test_status_header_prose_is_not_markup( + runner: CliRunner, project: Path, monkeypatch: pytest.MonkeyPatch +) -> None: + """The crate line names `[project].license`, and rich would read the + brackets as a style tag and swallow the one word that names the fix.""" + from lightcone.engine.materialize import StatusReport + + report = _report() + assert isinstance(report, StatusReport) + report.crate = "not maintained — declare [project].license to enable it" + _status_stub(monkeypatch, report) + + output = runner.invoke(main, ["status"]).output + + assert "declare [project].license to enable it" in output + + def test_build_on_a_direct_project_is_an_explanatory_no_op( runner: CliRunner, project: Path ) -> None: