📝 docs(tsl): clarify syntax constraints and enhance test infrastructure
- Add TSF file naming constraint to syntax/02_core_model.md - Clarify semicolon rules: syntax facts vs style preferences - Separate control flow end semicolon rules (syntax allows both) - Add function body semicolon requirements to syntax/05_functions_and_calls.md - Move style preferences to code_style.md (control flow end semicolons) - Remove cross-references from syntax docs to maintain independence - Enhance Gitea workflow emoji for better CI output readability - Fix CI test path from tests/ to test/ - Organize agent test results under test/agent/result/ directory - Add complete Chinese translation of test cases (test_cases_zh.md) - Clean up .gitignore to use unified test/agent/result/ directory - Remove obsolete agent test artifacts (REPORTS_LOCATION.md, old results) Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,290 @@
|
||||
import json
|
||||
import os
|
||||
import shutil
|
||||
import subprocess
|
||||
import tempfile
|
||||
import unittest
|
||||
from pathlib import Path
|
||||
|
||||
|
||||
ROOT = Path(__file__).resolve().parents[1]
|
||||
MANIFEST = ROOT / ".gitea" / "ci" / "thirdparty_skills.json"
|
||||
WORKFLOW = ROOT / ".gitea" / "workflows" / "update-thirdparty-skills.yml"
|
||||
LEGACY_WORKFLOW = ROOT / ".gitea" / "workflows" / "update-thirdparty-superpowers.yml"
|
||||
UPDATE_SCRIPT = ROOT / ".gitea" / "ci" / "update_thirdparty_skills.sh"
|
||||
SYNC_SCRIPT = ROOT / ".gitea" / "ci" / "sync_thirdparty_skills.sh"
|
||||
SKILLS_MD = ROOT / "SKILLS.md"
|
||||
SUPERPOWERS_LIST = ROOT / "skills" / "thirdparty" / ".sources" / "superpowers.list"
|
||||
UI_UX_PRO_MAX_LIST = ROOT / "skills" / "thirdparty" / ".sources" / "ui-ux-pro-max.list"
|
||||
UI_UX_PRO_MAX_DIR = ROOT / "skills" / "thirdparty" / "ui-ux-pro-max"
|
||||
BROOKS_LINT_LIST = ROOT / "skills" / "thirdparty" / ".sources" / "brooks-lint.list"
|
||||
CODEBASE_RECON_LIST = ROOT / "skills" / "thirdparty" / ".sources" / "codebase-recon.list"
|
||||
PATHFINDING_DIR = ROOT / "skills" / "thirdparty" / "pathfinding"
|
||||
|
||||
|
||||
def load_manifest() -> dict:
|
||||
return json.loads(MANIFEST.read_text(encoding="utf-8"))
|
||||
|
||||
|
||||
def bash_path(path: Path) -> str:
|
||||
resolved = path.resolve()
|
||||
if os.name != "nt":
|
||||
return resolved.as_posix()
|
||||
drive = resolved.drive.rstrip(":").lower()
|
||||
rest = resolved.as_posix()[2:]
|
||||
return f"/mnt/{drive}{rest}"
|
||||
|
||||
|
||||
def run_command(*args: str, cwd: Path | None = None) -> subprocess.CompletedProcess[str]:
|
||||
return subprocess.run(
|
||||
list(args),
|
||||
cwd=cwd,
|
||||
capture_output=True,
|
||||
text=True,
|
||||
)
|
||||
|
||||
|
||||
class ThirdpartySkillsPipelineTests(unittest.TestCase):
|
||||
def test_manifest_declares_all_thirdparty_sources(self):
|
||||
data = load_manifest()
|
||||
self.assertEqual(
|
||||
[entry["id"] for entry in data["sources"]],
|
||||
[
|
||||
"superpowers",
|
||||
"ui-ux-pro-max",
|
||||
"andrej-karpathy-skills",
|
||||
"brooks-lint",
|
||||
"codebase-recon",
|
||||
"codebase-migrate",
|
||||
"uncle-bob-craft",
|
||||
],
|
||||
)
|
||||
|
||||
def test_karpathy_manifest_uses_copy_skill_dirs_sync_mode(self):
|
||||
data = load_manifest()
|
||||
karpathy = next(
|
||||
item for item in data["sources"] if item["id"] == "andrej-karpathy-skills"
|
||||
)
|
||||
self.assertEqual(karpathy["sync_mode"], "copy_skill_dirs")
|
||||
self.assertEqual(karpathy["snapshot_dir"], "andrej-karpathy-skills")
|
||||
self.assertEqual(karpathy["skills_subdir"], "skills")
|
||||
self.assertEqual(
|
||||
karpathy["source_list"], "skills/thirdparty/.sources/andrej-karpathy-skills.list"
|
||||
)
|
||||
|
||||
def test_ui_ux_pro_max_uses_render_skill_sync_mode(self):
|
||||
data = load_manifest()
|
||||
ui_skill = next(item for item in data["sources"] if item["id"] == "ui-ux-pro-max")
|
||||
self.assertEqual(ui_skill["sync_mode"], "render_skill")
|
||||
self.assertEqual(ui_skill["snapshot_dir"], "ui-ux-pro-max")
|
||||
|
||||
def test_architecture_skill_sources_use_include_filters(self):
|
||||
data = load_manifest()
|
||||
brooks = next(item for item in data["sources"] if item["id"] == "brooks-lint")
|
||||
self.assertEqual(brooks["sync_mode"], "copy_skill_dirs")
|
||||
self.assertEqual(brooks["snapshot_dir"], "brooks-lint")
|
||||
self.assertEqual(brooks["skills_subdir"], "skills")
|
||||
self.assertEqual(
|
||||
brooks["source_list"], "skills/thirdparty/.sources/brooks-lint.list"
|
||||
)
|
||||
self.assertIn("brooks-audit", brooks["include_skill_dirs"])
|
||||
self.assertIn("brooks-review", brooks["include_skill_dirs"])
|
||||
self.assertIn("_shared", brooks["include_skill_dirs"])
|
||||
|
||||
recon = next(item for item in data["sources"] if item["id"] == "codebase-recon")
|
||||
self.assertEqual(recon["sync_mode"], "copy_skill_dirs")
|
||||
self.assertEqual(recon["snapshot_dir"], "outfitter-agents")
|
||||
self.assertEqual(recon["skills_subdir"], "plugins/outfitter/skills")
|
||||
self.assertEqual(
|
||||
recon["source_list"], "skills/thirdparty/.sources/codebase-recon.list"
|
||||
)
|
||||
self.assertEqual(recon["include_skill_dirs"], ["codebase-recon", "pathfinding"])
|
||||
|
||||
migrate = next(
|
||||
item for item in data["sources"] if item["id"] == "codebase-migrate"
|
||||
)
|
||||
self.assertEqual(
|
||||
migrate["upstream_repo"],
|
||||
"https://github.com/ComposioHQ/awesome-codex-skills.git",
|
||||
)
|
||||
self.assertEqual(migrate["upstream_ref"], "master")
|
||||
self.assertEqual(migrate["sync_mode"], "copy_skill_dirs")
|
||||
self.assertEqual(migrate["snapshot_dir"], "awesome-codex-skills")
|
||||
self.assertEqual(migrate["skills_subdir"], ".")
|
||||
self.assertEqual(
|
||||
migrate["source_list"], "skills/thirdparty/.sources/codebase-migrate.list"
|
||||
)
|
||||
self.assertEqual(migrate["include_skill_dirs"], ["codebase-migrate"])
|
||||
|
||||
craft = next(
|
||||
item for item in data["sources"] if item["id"] == "uncle-bob-craft"
|
||||
)
|
||||
self.assertEqual(
|
||||
craft["upstream_repo"],
|
||||
"https://github.com/sickn33/antigravity-awesome-skills.git",
|
||||
)
|
||||
self.assertEqual(craft["upstream_ref"], "main")
|
||||
self.assertEqual(craft["sync_mode"], "copy_skill_dirs")
|
||||
self.assertEqual(craft["snapshot_dir"], "antigravity-awesome-skills")
|
||||
self.assertEqual(craft["skills_subdir"], "skills")
|
||||
self.assertEqual(
|
||||
craft["source_list"], "skills/thirdparty/.sources/uncle-bob-craft.list"
|
||||
)
|
||||
self.assertEqual(craft["include_skill_dirs"], ["uncle-bob-craft"])
|
||||
|
||||
def test_superpowers_manifest_prunes_non_superpowers_paths(self):
|
||||
data = load_manifest()
|
||||
superpowers = next(item for item in data["sources"] if item["id"] == "superpowers")
|
||||
self.assertEqual(superpowers["remove_paths"], ["skills/ui-ux-pro-max"])
|
||||
|
||||
def test_workflow_uses_generic_scripts_and_single_serial_job(self):
|
||||
text = WORKFLOW.read_text(encoding="utf-8")
|
||||
self.assertFalse(LEGACY_WORKFLOW.exists())
|
||||
self.assertIn("update_and_sync:", text)
|
||||
self.assertNotIn("\n update:\n", text)
|
||||
self.assertNotIn("\n sync:\n", text)
|
||||
self.assertIn("bash .gitea/ci/update_thirdparty_skills.sh", text)
|
||||
self.assertIn("bash .gitea/ci/sync_thirdparty_skills.sh", text)
|
||||
self.assertNotIn("git merge", text)
|
||||
self.assertNotIn("git pull", text)
|
||||
|
||||
def test_workflow_has_serial_concurrency_and_literal_generic_paths(self):
|
||||
text = WORKFLOW.read_text(encoding="utf-8")
|
||||
self.assertIn("concurrency:", text)
|
||||
self.assertIn("update-thirdparty-${{ github.repository }}", text)
|
||||
self.assertIn('MANIFEST_PATH: ".gitea/ci/thirdparty_skills.json"', text)
|
||||
self.assertIn('TARGET_BRANCH="$THIRDPARTY_BRANCH" bash .gitea/ci/update_thirdparty_skills.sh', text)
|
||||
self.assertIn('TARGET_BRANCH="main" \\', text)
|
||||
self.assertIn('MANIFEST_PATH="$MANIFEST_PATH" \\', text)
|
||||
|
||||
def test_generic_scripts_exist_and_use_manifest(self):
|
||||
update_text = UPDATE_SCRIPT.read_text(encoding="utf-8")
|
||||
sync_text = SYNC_SCRIPT.read_text(encoding="utf-8")
|
||||
self.assertIn('MANIFEST_PATH="${MANIFEST_PATH:-.gitea/ci/thirdparty_skills.json}"', update_text)
|
||||
self.assertIn('MANIFEST_PATH="${MANIFEST_PATH:-.gitea/ci/thirdparty_skills.json}"', sync_text)
|
||||
self.assertIn('TARGET_BRANCH="${TARGET_BRANCH:-thirdparty/skill}"', update_text)
|
||||
self.assertIn('TARGET_BRANCH="${TARGET_BRANCH:-main}"', sync_text)
|
||||
self.assertIn(':package: deps(thirdparty): update snapshots', update_text)
|
||||
self.assertIn(':package: deps(skills): sync thirdparty skills', sync_text)
|
||||
|
||||
def test_skills_doc_points_to_generic_thirdparty_sources(self):
|
||||
text = SKILLS_MD.read_text(encoding="utf-8")
|
||||
self.assertIn("## 9. Third-party Skills", text)
|
||||
self.assertIn("来源:`skills/thirdparty/.sources/`(第三方来源清单目录)。", text)
|
||||
self.assertNotIn("Third-party Skills (superpowers)", text)
|
||||
|
||||
def test_superpowers_and_ui_ux_pro_max_source_lists_exist(self):
|
||||
self.assertTrue(SUPERPOWERS_LIST.is_file())
|
||||
self.assertTrue(UI_UX_PRO_MAX_LIST.is_file())
|
||||
self.assertTrue(CODEBASE_RECON_LIST.is_file())
|
||||
self.assertIn("using-superpowers", SUPERPOWERS_LIST.read_text(encoding="utf-8"))
|
||||
self.assertIn("ui-ux-pro-max", UI_UX_PRO_MAX_LIST.read_text(encoding="utf-8"))
|
||||
self.assertIn("pathfinding", CODEBASE_RECON_LIST.read_text(encoding="utf-8"))
|
||||
|
||||
def test_codebase_recon_pathfinding_dependency_is_synced(self):
|
||||
self.assertTrue((PATHFINDING_DIR / "SKILL.md").is_file())
|
||||
self.assertTrue(
|
||||
(PATHFINDING_DIR / "references" / "confidence.md").is_file()
|
||||
)
|
||||
|
||||
def test_ui_ux_pro_max_output_exists_with_data_and_scripts(self):
|
||||
self.assertTrue((UI_UX_PRO_MAX_DIR / "SKILL.md").is_file())
|
||||
self.assertTrue((UI_UX_PRO_MAX_DIR / "data").is_dir())
|
||||
self.assertTrue((UI_UX_PRO_MAX_DIR / "scripts").is_dir())
|
||||
|
||||
def test_update_script_materializes_manifest_before_target_checkout(self):
|
||||
text = UPDATE_SCRIPT.read_text(encoding="utf-8")
|
||||
self.assertIn('manifest_copy="$tmp_dir/thirdparty_skills.json"', text)
|
||||
self.assertIn('cp "$MANIFEST_PATH" "$manifest_copy"', text)
|
||||
self.assertIn('MANIFEST_PATH="$manifest_copy"', text)
|
||||
self.assertIn("remove_paths", text)
|
||||
self.assertIn('remove_snapshot_paths "$snapshot_dir" "$remove_paths"', text)
|
||||
self.assertIn("- Remove-Paths:", text)
|
||||
self.assertIn('if ! emit_sources_tsv > "$sources_file"; then', text)
|
||||
self.assertNotIn("done < <(emit_sources_tsv)", text)
|
||||
self.assertLess(
|
||||
text.index('cp "$MANIFEST_PATH" "$manifest_copy"'),
|
||||
text.index('git checkout -B "$TARGET_BRANCH" "origin/$TARGET_BRANCH"'),
|
||||
)
|
||||
|
||||
def test_sync_script_assumes_thirdparty_snapshot_is_already_clean(self):
|
||||
text = SYNC_SCRIPT.read_text(encoding="utf-8")
|
||||
self.assertIn('"\\x1f".join(', text)
|
||||
self.assertIn("while IFS=$'\\x1f' read -r", text)
|
||||
self.assertIn("include_skill_dirs", text)
|
||||
self.assertIn('skill_dir_included "$name" "$include_skill_dirs"', text)
|
||||
self.assertNotIn("while IFS=$'\\t' read -r", text)
|
||||
self.assertNotIn("exclude_skill_dirs", text)
|
||||
self.assertNotIn("is_excluded_skill_dir", text)
|
||||
|
||||
def test_sync_script_generates_karpathy_outputs_in_temp_repo(self):
|
||||
with tempfile.TemporaryDirectory() as tmp_dir:
|
||||
tmp_root = Path(tmp_dir)
|
||||
mirror = tmp_root / "origin.git"
|
||||
work = tmp_root / "work"
|
||||
|
||||
clone_mirror = run_command("git", "clone", "--mirror", str(ROOT), str(mirror))
|
||||
self.assertEqual(clone_mirror.returncode, 0, msg=clone_mirror.stderr)
|
||||
|
||||
thirdparty_ref = run_command(
|
||||
"git",
|
||||
f"--git-dir={mirror}",
|
||||
"rev-parse",
|
||||
"refs/remotes/origin/thirdparty/skill",
|
||||
)
|
||||
self.assertEqual(thirdparty_ref.returncode, 0, msg=thirdparty_ref.stderr)
|
||||
expose_thirdparty_branch = run_command(
|
||||
"git",
|
||||
f"--git-dir={mirror}",
|
||||
"update-ref",
|
||||
"refs/heads/thirdparty/skill",
|
||||
thirdparty_ref.stdout.strip(),
|
||||
)
|
||||
self.assertEqual(
|
||||
expose_thirdparty_branch.returncode,
|
||||
0,
|
||||
msg=expose_thirdparty_branch.stderr,
|
||||
)
|
||||
|
||||
clone_work = run_command("git", "clone", str(mirror), str(work))
|
||||
self.assertEqual(clone_work.returncode, 0, msg=clone_work.stderr)
|
||||
|
||||
set_remote = run_command(
|
||||
"git", "-C", str(work), "remote", "set-url", "origin", bash_path(mirror)
|
||||
)
|
||||
self.assertEqual(set_remote.returncode, 0, msg=set_remote.stderr)
|
||||
|
||||
manifest_data = load_manifest()
|
||||
manifest_data["sources"] = [
|
||||
entry
|
||||
for entry in manifest_data["sources"]
|
||||
if entry["id"] == "andrej-karpathy-skills"
|
||||
]
|
||||
(work / ".gitea" / "ci" / "thirdparty_skills.json").write_text(
|
||||
json.dumps(manifest_data, indent=2) + "\n",
|
||||
encoding="utf-8",
|
||||
)
|
||||
shutil.copy2(SYNC_SCRIPT, work / ".gitea" / "ci" / "sync_thirdparty_skills.sh")
|
||||
|
||||
sync_result = run_command("bash", ".gitea/ci/sync_thirdparty_skills.sh", cwd=work)
|
||||
self.assertEqual(
|
||||
sync_result.returncode,
|
||||
0,
|
||||
msg=sync_result.stdout + sync_result.stderr,
|
||||
)
|
||||
|
||||
generated_list = (
|
||||
work / "skills" / "thirdparty" / ".sources" / "andrej-karpathy-skills.list"
|
||||
)
|
||||
generated_skill = (
|
||||
work / "skills" / "thirdparty" / "karpathy-guidelines" / "SKILL.md"
|
||||
)
|
||||
self.assertTrue(generated_list.is_file())
|
||||
self.assertTrue(generated_skill.is_file())
|
||||
self.assertIn(
|
||||
"karpathy-guidelines", generated_list.read_text(encoding="utf-8")
|
||||
)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
unittest.main()
|
||||
Reference in New Issue
Block a user