📦 deps(thirdparty): update snapshots
This commit is contained in:
@@ -655,6 +655,238 @@ def _materialize_plugin_skills(root: Path, destination_root: Path, skill_ids: li
|
||||
_copy_skill_directory(root, skill_id, destination_root)
|
||||
|
||||
|
||||
def _skill_tree_files(root: Path, skill_ids: list[str]) -> dict[str, Path]:
|
||||
files: dict[str, Path] = {}
|
||||
skills_root = root / "skills"
|
||||
resolved_skills_root = skills_root.resolve()
|
||||
|
||||
def collect(source_path: Path, relative_path: Path) -> None:
|
||||
resolved_source = source_path.resolve(strict=True)
|
||||
resolved_source.relative_to(resolved_skills_root)
|
||||
if resolved_source.is_dir():
|
||||
for child in resolved_source.iterdir():
|
||||
collect(child, relative_path / child.name)
|
||||
return
|
||||
files[relative_path.as_posix()] = resolved_source
|
||||
|
||||
for skill_id in skill_ids:
|
||||
source_root = skills_root / skill_id
|
||||
if not source_root.is_dir():
|
||||
raise ValueError(f"Expected canonical skill directory is missing: {skill_id}")
|
||||
for child in source_root.iterdir():
|
||||
collect(child, Path(skill_id) / child.name)
|
||||
|
||||
return files
|
||||
|
||||
|
||||
def _assert_skill_mirror_matches(
|
||||
root: Path,
|
||||
destination_root: Path,
|
||||
skill_ids: list[str],
|
||||
label: str,
|
||||
) -> None:
|
||||
if destination_root.is_symlink():
|
||||
raise ValueError(f"{label} skills directory must not be a symlink: {destination_root}")
|
||||
if not destination_root.is_dir():
|
||||
raise ValueError(f"{label} skills directory is missing: {destination_root}")
|
||||
|
||||
expected_files = _skill_tree_files(root, skill_ids)
|
||||
actual_files = {
|
||||
path.relative_to(destination_root).as_posix(): path
|
||||
for path in destination_root.rglob("*")
|
||||
if path.is_file()
|
||||
}
|
||||
mirrored_symlinks = sorted(
|
||||
path.relative_to(destination_root).as_posix()
|
||||
for path in destination_root.rglob("*")
|
||||
if path.is_symlink()
|
||||
)
|
||||
if mirrored_symlinks:
|
||||
raise ValueError(f"{label} contains unexpected symlink: {mirrored_symlinks[0]}")
|
||||
expected_paths = set(expected_files)
|
||||
actual_paths = set(actual_files)
|
||||
|
||||
missing = sorted(expected_paths - actual_paths)
|
||||
if missing:
|
||||
raise ValueError(f"{label} is missing mirrored file: {missing[0]}")
|
||||
|
||||
unexpected = sorted(actual_paths - expected_paths)
|
||||
if unexpected:
|
||||
raise ValueError(f"{label} contains unexpected mirrored file: {unexpected[0]}")
|
||||
|
||||
for relative_path in sorted(expected_paths):
|
||||
if expected_files[relative_path].read_bytes() != actual_files[relative_path].read_bytes():
|
||||
raise ValueError(f"{label} contains stale mirrored file: {relative_path}")
|
||||
|
||||
|
||||
def _assert_json_matches(
|
||||
path: Path,
|
||||
expected: dict[str, Any],
|
||||
label: str,
|
||||
allowed_root: Path,
|
||||
) -> None:
|
||||
relative_path = path.relative_to(allowed_root)
|
||||
current_path = allowed_root
|
||||
for part in relative_path.parts:
|
||||
current_path /= part
|
||||
if current_path.is_symlink():
|
||||
raise ValueError(f"{label} path must not contain a symlink: {current_path}")
|
||||
if not path.is_file():
|
||||
raise ValueError(f"{label} is missing: {path}")
|
||||
expected_content = (json.dumps(expected, indent=2, ensure_ascii=False) + "\n").encode("utf-8")
|
||||
if path.read_bytes() != expected_content:
|
||||
raise ValueError(f"{label} is out of sync: {path}")
|
||||
|
||||
|
||||
def _assert_plugin_metadata_layout(
|
||||
plugin_root: Path,
|
||||
expected_relative_paths: set[str],
|
||||
label: str,
|
||||
) -> None:
|
||||
if plugin_root.is_symlink():
|
||||
raise ValueError(f"{label} root must not be a symlink: {plugin_root}")
|
||||
if not plugin_root.is_dir():
|
||||
raise ValueError(f"{label} root is missing: {plugin_root}")
|
||||
actual_relative_paths = {
|
||||
path.relative_to(plugin_root).as_posix()
|
||||
for path in plugin_root.rglob("*")
|
||||
if path.is_file() and "skills" not in path.relative_to(plugin_root).parts[:1]
|
||||
}
|
||||
unexpected_symlinks = sorted(
|
||||
path.relative_to(plugin_root).as_posix()
|
||||
for path in plugin_root.rglob("*")
|
||||
if path.is_symlink() and "skills" not in path.relative_to(plugin_root).parts[:1]
|
||||
)
|
||||
if unexpected_symlinks:
|
||||
raise ValueError(f"{label} contains unexpected metadata symlink: {unexpected_symlinks[0]}")
|
||||
if actual_relative_paths != expected_relative_paths:
|
||||
missing = sorted(expected_relative_paths - actual_relative_paths)
|
||||
unexpected = sorted(actual_relative_paths - expected_relative_paths)
|
||||
detail = f"missing {missing[0]}" if missing else f"unexpected {unexpected[0]}"
|
||||
raise ValueError(f"{label} metadata layout is out of sync: {detail}")
|
||||
|
||||
|
||||
def check_editorial_bundle_plugins(
|
||||
root: Path,
|
||||
metadata: dict[str, Any],
|
||||
bundles: list[dict[str, Any]],
|
||||
compatibility: dict[str, dict[str, Any]],
|
||||
) -> None:
|
||||
bundle_support = {
|
||||
bundle["id"]: _bundle_target_status(bundle, compatibility)
|
||||
for bundle in bundles
|
||||
}
|
||||
codex_skill_ids = _supported_skill_ids(compatibility, "codex")
|
||||
claude_skill_ids = _supported_skill_ids(compatibility, "claude")
|
||||
|
||||
_assert_json_matches(
|
||||
root / CODEX_MARKETPLACE_PATH,
|
||||
_render_codex_marketplace(bundles, bundle_support),
|
||||
"Codex marketplace",
|
||||
root,
|
||||
)
|
||||
_assert_json_matches(
|
||||
root / CLAUDE_MARKETPLACE_PATH,
|
||||
_render_claude_marketplace(metadata, bundles, bundle_support),
|
||||
"Claude marketplace",
|
||||
root,
|
||||
)
|
||||
_assert_json_matches(
|
||||
root / CLAUDE_PLUGIN_PATH,
|
||||
_root_claude_plugin_manifest(metadata, len(claude_skill_ids)),
|
||||
"root Claude plugin manifest",
|
||||
root,
|
||||
)
|
||||
|
||||
codex_root = root / "plugins" / ROOT_CODEX_PLUGIN_NAME
|
||||
claude_root = root / "plugins" / ROOT_CLAUDE_PLUGIN_DIRNAME
|
||||
_assert_json_matches(
|
||||
codex_root / ".codex-plugin" / "plugin.json",
|
||||
_root_codex_plugin_manifest(metadata, len(codex_skill_ids)),
|
||||
"root Codex plugin manifest",
|
||||
root,
|
||||
)
|
||||
_assert_json_matches(
|
||||
claude_root / ".claude-plugin" / "plugin.json",
|
||||
_root_claude_plugin_manifest(metadata, len(claude_skill_ids)),
|
||||
"root Claude plugin manifest",
|
||||
root,
|
||||
)
|
||||
_assert_plugin_metadata_layout(
|
||||
codex_root,
|
||||
{".codex-plugin/plugin.json"},
|
||||
"root Codex plugin",
|
||||
)
|
||||
_assert_plugin_metadata_layout(
|
||||
claude_root,
|
||||
{".claude-plugin/plugin.json"},
|
||||
"root Claude plugin",
|
||||
)
|
||||
_assert_skill_mirror_matches(root, codex_root / "skills", codex_skill_ids, "root Codex plugin")
|
||||
_assert_skill_mirror_matches(root, claude_root / "skills", claude_skill_ids, "root Claude plugin")
|
||||
|
||||
expected_bundle_names = {
|
||||
_bundle_plugin_name(bundle["id"])
|
||||
for bundle in bundles
|
||||
if bundle_support[bundle["id"]]["codex"] or bundle_support[bundle["id"]]["claude"]
|
||||
}
|
||||
actual_bundle_names = {
|
||||
path.name
|
||||
for path in (root / "plugins").glob("agentic-bundle-*")
|
||||
if path.is_dir()
|
||||
}
|
||||
if actual_bundle_names != expected_bundle_names:
|
||||
missing = sorted(expected_bundle_names - actual_bundle_names)
|
||||
unexpected = sorted(actual_bundle_names - expected_bundle_names)
|
||||
detail = f"missing {missing[0]}" if missing else f"unexpected {unexpected[0]}"
|
||||
raise ValueError(f"Generated bundle plugin directories are out of sync: {detail}")
|
||||
|
||||
for bundle in bundles:
|
||||
support = bundle_support[bundle["id"]]
|
||||
if not support["codex"] and not support["claude"]:
|
||||
continue
|
||||
plugin_root = root / "plugins" / _bundle_plugin_name(bundle["id"])
|
||||
skill_ids = [skill["id"] for skill in bundle["skills"]]
|
||||
_assert_skill_mirror_matches(
|
||||
root,
|
||||
plugin_root / "skills",
|
||||
skill_ids,
|
||||
f'bundle plugin {bundle["id"]}',
|
||||
)
|
||||
|
||||
manifest_specs = (
|
||||
(
|
||||
"codex",
|
||||
plugin_root / ".codex-plugin" / "plugin.json",
|
||||
_bundle_codex_plugin_manifest(metadata, bundle),
|
||||
),
|
||||
(
|
||||
"claude",
|
||||
plugin_root / ".claude-plugin" / "plugin.json",
|
||||
_bundle_claude_plugin_manifest(metadata, bundle),
|
||||
),
|
||||
)
|
||||
expected_manifest_paths: set[str] = set()
|
||||
for target, manifest_path, expected_manifest in manifest_specs:
|
||||
if support[target]:
|
||||
expected_manifest_paths.add(manifest_path.relative_to(plugin_root).as_posix())
|
||||
_assert_json_matches(
|
||||
manifest_path,
|
||||
expected_manifest,
|
||||
f'bundle {bundle["id"]} {target} manifest',
|
||||
root,
|
||||
)
|
||||
elif manifest_path.exists():
|
||||
raise ValueError(
|
||||
f'Bundle {bundle["id"]} contains an unsupported {target} manifest: {manifest_path}'
|
||||
)
|
||||
_assert_plugin_metadata_layout(
|
||||
plugin_root,
|
||||
expected_manifest_paths,
|
||||
f'bundle plugin {bundle["id"]}',
|
||||
)
|
||||
|
||||
|
||||
def _remove_path(path: Path) -> None:
|
||||
if path.is_symlink() or path.is_file():
|
||||
path.unlink()
|
||||
@@ -860,7 +1092,11 @@ def main() -> int:
|
||||
current_doc = (root / "docs" / "users" / "bundles.md").read_text(encoding="utf-8")
|
||||
if current_doc != expected_doc:
|
||||
raise SystemExit("docs/users/bundles.md is out of sync with data/editorial-bundles.json")
|
||||
print("✅ Editorial bundles manifest and generated doc are in sync.")
|
||||
try:
|
||||
check_editorial_bundle_plugins(root, metadata, bundles, compatibility)
|
||||
except ValueError as exc:
|
||||
raise SystemExit(str(exc)) from exc
|
||||
print("✅ Editorial bundles, marketplaces, manifests, and plugin mirrors are in sync.")
|
||||
return 0
|
||||
sync_editorial_bundles(root)
|
||||
print("✅ Editorial bundles synced.")
|
||||
|
||||
Reference in New Issue
Block a user