first usable curator UI

This commit is contained in:
2026-04-25 23:04:15 +02:00
parent 8f94c38309
commit aa18dfc8f2
10 changed files with 677 additions and 10 deletions

View File

@@ -66,6 +66,7 @@ def test_search_matches_approved_abilities_and_capabilities(tmp_path):
repository = service.register_repository(
name="MailRouter",
url="https://example.com/mail-router.git",
description="Manual test repository.",
)
ability_id = service.add_ability(
repository.id,
@@ -87,10 +88,34 @@ def test_search_matches_approved_abilities_and_capabilities(tmp_path):
assert results[0].match_name == "Classify Incoming Email"
def test_register_repository_imports_metadata_when_name_is_omitted(tmp_path):
source = tmp_path / "metadata-source"
source.mkdir()
(source / "pyproject.toml").write_text(
'[project]\nname = "metadata-source"\ndescription = "Imported description."\n',
encoding="utf-8",
)
service = make_service(tmp_path)
repository = service.register_repository(url=str(source))
assert repository.name == "metadata-source"
assert repository.description == "Imported description."
def test_capability_must_belong_to_repository(tmp_path):
service = make_service(tmp_path)
first = service.register_repository(name="First", url="https://example.com/first.git")
second = service.register_repository(name="Second", url="https://example.com/second.git")
first = service.register_repository(
name="First",
url="https://example.com/first.git",
description="Manual first repository.",
)
second = service.register_repository(
name="Second",
url="https://example.com/second.git",
description="Manual second repository.",
)
ability_id = service.add_ability(first.id, name="Document Classification")
try:
@@ -186,6 +211,7 @@ def test_analyze_repository_failure_is_recorded(tmp_path):
repository = service.register_repository(
name="Missing",
url=str(tmp_path / "does-not-exist"),
description="Manual missing repository.",
)
summary = service.analyze_repository(repository.id)

View File

@@ -0,0 +1,43 @@
from repo_registry.repo_ingestion.metadata import RepositoryMetadataExtractor
def test_metadata_prefers_pyproject(tmp_path):
repo = tmp_path / "repo"
repo.mkdir()
(repo / "pyproject.toml").write_text(
'[project]\nname = "invoice-tools"\ndescription = "Extract invoice data."\n',
encoding="utf-8",
)
metadata = RepositoryMetadataExtractor().extract(repo, str(repo))
assert metadata.name == "invoice-tools"
assert metadata.description == "Extract invoice data."
def test_metadata_uses_package_json(tmp_path):
repo = tmp_path / "repo"
repo.mkdir()
(repo / "package.json").write_text(
'{"name":"frontend-registry","description":"Browse repository abilities."}',
encoding="utf-8",
)
metadata = RepositoryMetadataExtractor().extract(repo, str(repo))
assert metadata.name == "frontend-registry"
assert metadata.description == "Browse repository abilities."
def test_metadata_falls_back_to_readme_title(tmp_path):
repo = tmp_path / "repo-name"
repo.mkdir()
(repo / "README.md").write_text(
"# Useful Registry\n\nExtra details follow.\n",
encoding="utf-8",
)
metadata = RepositoryMetadataExtractor().extract(repo, str(repo))
assert metadata.name == "Useful Registry"
assert metadata.description == "Extra details follow."

View File

@@ -72,6 +72,33 @@ def test_api_manual_registry_loop(tmp_path):
app.dependency_overrides.clear()
def test_api_registers_repository_from_url_metadata(tmp_path):
source = tmp_path / "metadata-api"
source.mkdir()
(source / "package.json").write_text(
'{"name":"metadata-api","description":"Imported through the API."}',
encoding="utf-8",
)
def override_settings():
return Settings(
database_path=str(tmp_path / "metadata-api.sqlite3"),
checkout_root=str(tmp_path / "metadata-api-checkouts"),
)
app.dependency_overrides[get_settings] = override_settings
client = TestClient(app)
try:
response = client.post("/repos", json={"url": str(source)})
assert response.status_code == 201
repository = response.json()
assert repository["name"] == "metadata-api"
assert repository["description"] == "Imported through the API."
finally:
app.dependency_overrides.clear()
def test_api_analysis_run_loop(tmp_path):
source = tmp_path / "repo"
source.mkdir()
@@ -139,3 +166,70 @@ def test_api_analysis_run_loop(tmp_path):
assert ("framework", "Vite", "package.json") in fact_names
finally:
app.dependency_overrides.clear()
def test_ui_register_analyze_and_approve_loop(tmp_path):
source = tmp_path / "repo"
source.mkdir()
(source / "README.md").write_text("# UI Repo\n", encoding="utf-8")
(source / "app.py").write_text(
"from fastapi import FastAPI\n"
"app = FastAPI()\n"
'@app.get("/status")\n'
"def status():\n"
" return {}\n",
encoding="utf-8",
)
def override_settings():
return Settings(
database_path=str(tmp_path / "ui.sqlite3"),
checkout_root=str(tmp_path / "ui-checkouts"),
)
app.dependency_overrides[get_settings] = override_settings
client = TestClient(app)
try:
index_response = client.get("/ui")
assert index_response.status_code == 200
assert "Register Repository" in index_response.text
create_response = client.post(
"/ui/repos",
data={
"url": str(source),
"branch": "main",
},
follow_redirects=False,
)
assert create_response.status_code == 303
repository_path = create_response.headers["location"]
detail_response = client.get(repository_path)
assert detail_response.status_code == 200
assert "Run Analysis" in detail_response.text
run_response = client.post(
f"{repository_path}/analysis-runs",
data={"source_path": ""},
follow_redirects=False,
)
assert run_response.status_code == 303
run_path = run_response.headers["location"]
run_detail = client.get(run_path)
assert run_detail.status_code == 200
assert "Candidate Graph" in run_detail.text
approve_response = client.post(
f"{run_path}/candidate-graph/approve",
follow_redirects=False,
)
assert approve_response.status_code == 303
approved_detail = client.get(approve_response.headers["location"])
assert approved_detail.status_code == 200
assert "Approved Ability Map" in approved_detail.text
assert "Review UI Repo Repository Usefulness" in approved_detail.text
finally:
app.dependency_overrides.clear()