diff --git a/agents/qa-market-publish-agent-20260823/entry.json b/agents/qa-market-publish-agent-20260823/entry.json new file mode 100644 index 0000000..9aa2062 --- /dev/null +++ b/agents/qa-market-publish-agent-20260823/entry.json @@ -0,0 +1,37 @@ +{ + "id": "qa-market-publish-agent-20260823", + "name": "QA Market Publish Agent 20260823", + "category": "development", + "tags": ["qa", "market", "lifecycle"], + "icon": "", + "latestVersion": "1.0.0", + "i18n": { + "en-US": { + "name": "QA Market Publish Agent 20260823", + "shortDesc": "Temporary Agent for verifying the real publish, install, and delist lifecycle." + }, + "zh-CN": { + "name": "QA 市场发布测试 Agent 20260823", + "shortDesc": "用于验证真实上架、安装与下架闭环的一次性 Agent。" + } + }, + "maintainer": { + "name": "yi-ge", + "verified": false, + "account": "yi-ge", + "url": "https://github.com/yi-ge/qa-market-publish-agent-20260823" + }, + "stewardship": "community", + "license": "MIT", + "redistribution": "allowed", + "source": { + "kind": "git", + "repoUrl": "https://github.com/yi-ge/qa-market-publish-agent-20260823.git", + "repoBranch": "main", + "ref": "dd4abbe342f25d0569dba152ce1be3fb867c3474" + }, + "avatar": { + "t": "QA", + "bg": "linear-gradient(135deg, #FF9500, #FF6B00)" + } +} diff --git a/manifest.json b/manifest.json index 7924cd8..f881efa 100644 --- a/manifest.json +++ b/manifest.json @@ -1,6 +1,6 @@ { "name": "DesireCore Official Market", - "version": "1.2.26", + "version": "1.2.27", "schemaVersion": "1.1.0", "supportedLocales": ["zh-CN", "en-US"], "defaultLocale": "en-US", @@ -26,9 +26,9 @@ "url": "https://github.com/desirecore/market.git" }, "stats": { - "totalAgents": 1, + "totalAgents": 2, "totalSkills": 60, - "lastUpdated": "2026-08-09" + "lastUpdated": "2026-08-23" }, "features": [ "curated-index", diff --git a/scripts/i18n/test_validate_i18n.py b/scripts/i18n/test_validate_i18n.py index 92586a5..a9fd839 100644 --- a/scripts/i18n/test_validate_i18n.py +++ b/scripts/i18n/test_validate_i18n.py @@ -9,8 +9,10 @@ from __future__ import annotations import importlib.util import sys +import tempfile import unittest from pathlib import Path +from unittest.mock import patch VALIDATOR_PATH = Path(__file__).with_name("validate-i18n.py") @@ -84,5 +86,21 @@ class BuiltinSkillManifestTests(unittest.TestCase): self.assertEqual(1, len(sort_issues)) +class PublishableAgentCatalogTests(unittest.TestCase): + def test_counts_inline_and_pointer_agents(self) -> None: + with tempfile.TemporaryDirectory() as tmp: + root = Path(tmp) + (root / "agents" / "inline-agent").mkdir(parents=True) + (root / "agents" / "inline-agent" / "agent.json").write_text("{}") + (root / "agents" / "pointer-agent").mkdir(parents=True) + (root / "agents" / "pointer-agent" / "entry.json").write_text("{}") + + with patch.object(VALIDATOR, "REPO_ROOT", root): + inline, pointers = VALIDATOR.count_publishable_agents() + + self.assertEqual(["inline-agent"], inline) + self.assertEqual(["pointer-agent"], pointers) + + if __name__ == "__main__": unittest.main() diff --git a/scripts/i18n/validate-i18n.py b/scripts/i18n/validate-i18n.py index 1471fd0..38b2e48 100755 --- a/scripts/i18n/validate-i18n.py +++ b/scripts/i18n/validate-i18n.py @@ -348,6 +348,13 @@ def count_publishable_skills() -> tuple[list[str], list[str]]: return skill_md_names, entry_names +def count_publishable_agents() -> tuple[list[str], list[str]]: + """Return inline and pointer Agent IDs represented by the Market catalog.""" + agent_json_names = sorted(p.parent.name for p in (REPO_ROOT / "agents").glob("*/agent.json")) + entry_names = sorted(p.parent.name for p in (REPO_ROOT / "agents").glob("*/entry.json")) + return agent_json_names, entry_names + + def validate_builtin_skills(report: Report, skill_md_names: list[str]) -> None: builtin_path = REPO_ROOT / "builtin-skills.json" builtin = load_json(builtin_path, report, "builtin-skills") @@ -513,14 +520,17 @@ def validate_url(report: Report, path: str, url: str) -> None: def validate_market_catalog(report: Report, manifest: dict[str, Any], category_ids: set[str], online: bool) -> None: - agent_files = sorted((REPO_ROOT / "agents").glob("*/agent.json")) + agent_json_names, agent_entry_names = count_publishable_agents() + agent_files = [REPO_ROOT / "agents" / name / "agent.json" for name in agent_json_names] + agent_entry_files = [REPO_ROOT / "agents" / name / "entry.json" for name in agent_entry_names] skill_md_names, entry_names = count_publishable_skills() + skill_entry_files = sorted((REPO_ROOT / "skills").glob("*/entry.json")) stats = manifest.get("stats") if not isinstance(stats, dict): report.add(Issue("manifest.json", "market-stats", "stats must be an object")) else: - expected_agents = len(agent_files) + expected_agents = len(agent_json_names) + len(agent_entry_names) expected_skills = len(skill_md_names) + len(entry_names) if stats.get("totalAgents") != expected_agents: report.add(Issue( @@ -535,7 +545,7 @@ def validate_market_catalog(report: Report, manifest: dict[str, Any], category_i features = manifest.get("features") or [] if isinstance(features, list) and "verified-only" in features: - for entry_file in sorted((REPO_ROOT / "skills").glob("*/entry.json")): + for entry_file in [*agent_entry_files, *skill_entry_files]: entry = load_json(entry_file, report, "entry-json") maintainer = entry.get("maintainer") if isinstance(entry, dict) else None verified = maintainer.get("verified") if isinstance(maintainer, dict) else None @@ -549,7 +559,7 @@ def validate_market_catalog(report: Report, manifest: dict[str, Any], category_i validate_builtin_skills(report, skill_md_names) for agent_file in agent_files: validate_agent_json(report, agent_file, category_ids) - for entry_file in sorted((REPO_ROOT / "skills").glob("*/entry.json")): + for entry_file in [*agent_entry_files, *skill_entry_files]: validate_entry_json(report, entry_file, category_ids, online)