feat(apps): add extension registry source

This commit is contained in:
Xubin Ren
2026-05-29 17:26:58 +08:00
parent 232df45126
commit c1357e86de
4 changed files with 147 additions and 26 deletions
+103
View File
@@ -121,6 +121,7 @@ def _seed_catalog(manager: CliAppManager) -> None:
}
_write_cache(manager._cache_path("harness"), harness)
_write_cache(manager._cache_path("public"), public)
_write_cache(manager._cache_path("extensions"), {"meta": {}, "clis": []})
def test_payload_merges_catalog_and_marks_unsupported_installs(tmp_path: Path) -> None:
@@ -187,6 +188,7 @@ def test_payload_uses_anygen_official_domain_for_logo(tmp_path: Path) -> None:
],
},
)
_write_cache(manager._cache_path("extensions"), {"meta": {}, "clis": []})
payload = manager.payload()
@@ -195,6 +197,75 @@ def test_payload_uses_anygen_official_domain_for_logo(tmp_path: Path) -> None:
assert app["logo_url"] == "https://www.google.com/s2/favicons?domain=anygen.io&sz=64"
def test_payload_includes_nanobot_extension_registry(tmp_path: Path) -> None:
manager = _manager(tmp_path)
_write_cache(manager._cache_path("harness"), {"meta": {"updated": "2026-04-16"}, "clis": []})
_write_cache(manager._cache_path("public"), {"meta": {"updated": "2026-04-18"}, "clis": []})
_write_cache(
manager._cache_path("extensions"),
{
"meta": {"updated": "2026-05-29"},
"clis": [
{
"name": "hyperframes",
"display_name": "HyperFrames",
"version": "latest",
"description": "HTML-to-MP4 motion graphics CLI",
"category": "video",
"package_manager": "npm",
"npm_package": "hyperframes",
"install_cmd": "npm install -g hyperframes",
"entry_point": "hyperframes",
"skill_md": "skills/hyperframes/SKILL.md",
}
],
},
)
payload = manager.payload()
assert payload["catalog_updated_at"] == "2026-05-29"
app = payload["apps"][0]
assert app["name"] == "hyperframes"
assert app["source"] == "extensions"
assert app["install_supported"] is True
assert app["manifest"]["source"] == "nanobot-extension"
assert app["manifest"]["trust"]["registry"] == "nanobot-extension"
def test_optional_extension_registry_failure_does_not_break_payload(
tmp_path: Path,
monkeypatch: pytest.MonkeyPatch,
) -> None:
manager = _manager(tmp_path)
_write_cache(
manager._cache_path("harness"),
{
"meta": {"updated": "2026-04-16"},
"clis": [
{
"name": "gimp",
"display_name": "GIMP",
"description": "Image editing",
"install_cmd": "pip install cli-anything-gimp",
"entry_point": "cli-anything-gimp",
}
],
},
)
_write_cache(manager._cache_path("public"), {"meta": {"updated": "2026-04-18"}, "clis": []})
def fail_get(*args, **kwargs):
raise RuntimeError("network unavailable")
monkeypatch.setattr("nanobot.apps.cli.service.httpx.get", fail_get)
payload = manager.payload()
assert payload["catalog_updated_at"] == "2026-04-18"
assert [app["name"] for app in payload["apps"]] == ["gimp"]
def test_install_dispatches_safe_pip_and_installs_skill(
tmp_path: Path,
monkeypatch: pytest.MonkeyPatch,
@@ -333,6 +404,38 @@ def test_fetch_skill_content_allows_cli_anything_raw_skill_url(
]
def test_fetch_skill_content_uses_extension_raw_base_for_relative_skills(
tmp_path: Path,
monkeypatch: pytest.MonkeyPatch,
) -> None:
manager = _manager(tmp_path)
seen: list[str] = []
class Response:
text = "---\nname: hyperframes\ndescription: HyperFrames\n---\n# HyperFrames\n"
@staticmethod
def raise_for_status() -> None:
return None
def fake_get(url: str, **kwargs):
seen.append(url)
return Response()
monkeypatch.setattr("nanobot.apps.cli.service.httpx.get", fake_get)
content = manager._fetch_skill_content({
"name": "hyperframes",
"skill_md": "skills/hyperframes/SKILL.md",
"_raw_base": "https://raw.githubusercontent.com/Re-bin/nanobot-extension/main",
})
assert content and "# HyperFrames" in content
assert seen == [
"https://raw.githubusercontent.com/Re-bin/nanobot-extension/main/skills/hyperframes/SKILL.md"
]
def test_uninstall_removes_installed_state_and_generated_skill(
tmp_path: Path,
monkeypatch: pytest.MonkeyPatch,
+2
View File
@@ -41,6 +41,7 @@ def test_run_cli_app_uses_installed_registry_app(
}
_write_cache(data_dir / "harness_registry_cache.json", registry)
_write_cache(data_dir / "public_registry_cache.json", {"meta": {}, "clis": []})
_write_cache(data_dir / "extensions_registry_cache.json", {"meta": {}, "clis": []})
CliAppManager(workspace=workspace, data_dir=data_dir)._save_installed(
{"gimp": {"entry_point": "cli-anything-gimp"}}
)
@@ -102,6 +103,7 @@ def test_run_cli_app_rejects_uninstalled_app(tmp_path: Path, monkeypatch) -> Non
}
_write_cache(data_dir / "harness_registry_cache.json", registry)
_write_cache(data_dir / "public_registry_cache.json", {"meta": {}, "clis": []})
_write_cache(data_dir / "extensions_registry_cache.json", {"meta": {}, "clis": []})
monkeypatch.setattr("nanobot.apps.cli.service.get_runtime_subdir", lambda _name: data_dir)
tool = CliAppsTool(workspace=workspace, restrict_to_workspace=True)