Spaces:
Running
Running
| #!/usr/bin/env python3 | |
| """Synchronize version across all headroom packages.""" | |
| from __future__ import annotations | |
| import argparse | |
| import json | |
| import re | |
| from pathlib import Path | |
| try: | |
| import tomllib | |
| except ImportError: # pragma: no cover - Python 3.10 fallback | |
| import tomli as tomllib | |
| def get_version_from_pyproject(root: Path) -> str: | |
| """Read version from pyproject.toml.""" | |
| pyproject_path = root / "pyproject.toml" | |
| with open(pyproject_path, "rb") as f: | |
| data = tomllib.load(f) | |
| return data["project"]["version"] | |
| def bump_version(version: str, bump_type: str) -> str: | |
| """Bump version according to bump_type (major, minor, patch).""" | |
| major, minor, patch = map(int, version.split(".")) | |
| if bump_type == "major": | |
| major += 1 | |
| minor = 0 | |
| patch = 0 | |
| elif bump_type == "minor": | |
| minor += 1 | |
| patch = 0 | |
| elif bump_type == "patch": | |
| patch += 1 | |
| return f"{major}.{minor}.{patch}" | |
| def update_version_py(root: Path, version: str) -> None: | |
| """Update headroom/_version.py with new version.""" | |
| version_py_path = root / "headroom" / "_version.py" | |
| content = version_py_path.read_text(encoding="utf-8") | |
| updated = re.sub( | |
| r'__version__ = "[^"]+"', | |
| f'__version__ = "{version}"', | |
| content, | |
| ) | |
| version_py_path.write_text(updated, encoding="utf-8") | |
| def update_package_json(file_path: Path, version: str) -> None: | |
| """Update a package.json version field.""" | |
| with open(file_path, encoding="utf-8") as f: | |
| data = json.load(f) | |
| data["version"] = version | |
| with open(file_path, "w", encoding="utf-8") as f: | |
| json.dump(data, f, indent=2) | |
| f.write("\n") | |
| def update_plugin_manifest(file_path: Path, version: str) -> None: | |
| """Update a plugin.json version field.""" | |
| with open(file_path, encoding="utf-8") as f: | |
| data = json.load(f) | |
| data["version"] = version | |
| with open(file_path, "w", encoding="utf-8") as f: | |
| json.dump(data, f, indent=2) | |
| f.write("\n") | |
| def update_marketplace_manifest(file_path: Path, version: str) -> None: | |
| """Update marketplace metadata and plugin entry versions.""" | |
| with open(file_path, encoding="utf-8") as f: | |
| data = json.load(f) | |
| metadata = data.get("metadata") | |
| if isinstance(metadata, dict): | |
| metadata["version"] = version | |
| plugins = data.get("plugins") | |
| if isinstance(plugins, list): | |
| for plugin in plugins: | |
| if isinstance(plugin, dict): | |
| plugin["version"] = version | |
| with open(file_path, "w", encoding="utf-8") as f: | |
| json.dump(data, f, indent=2) | |
| f.write("\n") | |
| def update_plugin_versions(root: Path, version: str) -> None: | |
| """Update marketplace and plugin manifest versions.""" | |
| update_marketplace_manifest(root / ".claude-plugin" / "marketplace.json", version) | |
| update_marketplace_manifest(root / ".github" / "plugin" / "marketplace.json", version) | |
| update_plugin_manifest( | |
| root / "plugins" / "headroom-agent-hooks" / ".claude-plugin" / "plugin.json", version | |
| ) | |
| update_plugin_manifest( | |
| root / "plugins" / "headroom-agent-hooks" / ".github" / "plugin" / "plugin.json", | |
| version, | |
| ) | |
| def update_openclaw_package_json(file_path: Path, version: str, sdk_version: str) -> None: | |
| """Update openclaw package.json version and headroom-ai dependency range.""" | |
| with open(file_path, encoding="utf-8") as f: | |
| data = json.load(f) | |
| data["version"] = version | |
| if "dependencies" in data and "headroom-ai" in data["dependencies"]: | |
| data["dependencies"]["headroom-ai"] = f"^{sdk_version}" | |
| with open(file_path, "w", encoding="utf-8") as f: | |
| json.dump(data, f, indent=2) | |
| f.write("\n") | |
| def update_pyproject_version(root: Path, version: str) -> None: | |
| """Update pyproject.toml version.""" | |
| pyproject_path = root / "pyproject.toml" | |
| content = pyproject_path.read_text(encoding="utf-8") | |
| updated = re.sub( | |
| r'^version = "[^"]+"', | |
| f'version = "{version}"', | |
| content, | |
| flags=re.MULTILINE, | |
| ) | |
| pyproject_path.write_text(updated, encoding="utf-8") | |
| def write_release_metadata(root: Path, version: str) -> None: | |
| """Write .releaseetadata JSON file.""" | |
| metadata = { | |
| "version": version, | |
| "packages": { | |
| "pypi": version, | |
| "npm-sdk": version, | |
| "npm-openclaw": version, | |
| "agent-hooks-plugin": version, | |
| }, | |
| } | |
| metadata_path = root / ".releaseetadata" | |
| with open(metadata_path, "w", encoding="utf-8") as f: | |
| json.dump(metadata, f, indent=2) | |
| f.write("\n") | |
| def main() -> None: | |
| parser = argparse.ArgumentParser(description="Synchronize version across headroom packages") | |
| parser.add_argument( | |
| "--root", | |
| type=Path, | |
| default=Path(__file__).parent.parent, | |
| help="Root directory of the project", | |
| ) | |
| group = parser.add_mutually_exclusive_group() | |
| group.add_argument("--version", help="Explicit version to set (e.g., 0.6.0)") | |
| group.add_argument( | |
| "--bump", | |
| choices=["major", "minor", "patch"], | |
| help="Bump version from pyproject.toml", | |
| ) | |
| parser.add_argument( | |
| "--plugin-manifests-only", | |
| action="store_true", | |
| help="Only update marketplace/plugin manifest versions", | |
| ) | |
| args = parser.parse_args() | |
| if args.version: | |
| version = args.version | |
| elif args.bump: | |
| base_version = get_version_from_pyproject(args.root) | |
| version = bump_version(base_version, args.bump) | |
| else: | |
| version = get_version_from_pyproject(args.root) | |
| if args.plugin_manifests_only: | |
| update_plugin_versions(args.root, version) | |
| print(f"Plugin versions synchronized to {version}") | |
| return | |
| # Update all versioned files | |
| update_pyproject_version(args.root, version) | |
| update_version_py(args.root, version) | |
| update_openclaw_package_json( | |
| args.root / "plugins" / "openclaw" / "package.json", version, version | |
| ) | |
| update_package_json(args.root / "sdk" / "typescript" / "package.json", version) | |
| update_plugin_versions(args.root, version) | |
| write_release_metadata(args.root, version) | |
| print(f"Version synchronized to {version}") | |
| if __name__ == "__main__": | |
| main() | |