import subprocess, sys, json, re from pathlib import Path from typer.testing import CliRunner from jof250.cli import app from jof250.provenance import ROOT def test_cli_help_lists_commands(): r = CliRunner().invoke(app, ["--help"]); assert r.exit_code == 0 for c in ["corpus", "profiles", "index", "retrieve", "write", "review", "audit", "evidence", "benchmark", "status", "install-claude-code"]: assert c in r.output def test_status_runs(): r = CliRunner().invoke(app, ["status"]); assert r.exit_code == 0 and "JoF-250 status" in r.output def test_claude_code_files_reference_cli(): cdir = ROOT / ".claude" cmds = list((cdir / "commands").glob("jof-*.md")); agents = list((cdir / "agents").glob("jof-*.md")); skill = cdir / "skills" / "jof250" / "SKILL.md" assert len(cmds) == 10 and len(agents) == 7 and skill.exists() for p in cmds: t = p.read_text(); assert t.startswith("---") and "description:" in t and "/.venv/bin/jof250" in t for p in agents: t = p.read_text(); assert re.search(r"^name: jof-", t, re.M) and "model:" in t def test_provenance_stamp(): from jof250.provenance import stamp, Ledger s = stamp(); assert s["timestamp"].endswith("+00:00") and s["code_version"] def test_ledger_append_only(tmp_path): from jof250.provenance import Ledger l = Ledger(tmp_path / "l.jsonl"); l.append({"a": 1}); l.append({"a": 2}); assert [r["a"] for r in l.read()] == [1, 2] def test_budget_cap_blocks_calls(monkeypatch): from jof250 import llm, config monkeypatch.setattr(llm, "spent_usd", lambda: 1e9) import pytest with pytest.raises(llm.BudgetExceeded): llm.call("s", "u", use_cache=False) def test_extract_json_tolerates_fences(): from jof250.llm import extract_json assert extract_json('```json\n{"a": 1}\n```') == {"a": 1} and extract_json('text {"b": 2} more') == {"b": 2} and extract_json("no json") is None