headroom/scripts/version-sync.py

Ignoring revisions in .git-blame-ignore-revs. Click here to bypass and see the normal blame view.

222 lines
7.5 KiB
Python
Raw Normal View History

#!/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_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:
chore(release): harden local artifact smokes (#1824) ## Description Harden the release artifact workflow so maintainers can reproduce npm and Python release checks locally and so OpenClaw packaging does not depend on a not-yet-published SDK version. This follow-up also keeps the OpenClaw loader export contract explicit and updates the PR after the branch was merged with current `headroomlabs/main`. ## Type of Change - [x] Bug fix (non-breaking change that fixes an issue) - [x] New feature (non-breaking change that adds functionality) - [x] Documentation update ## Changes Made - Added reusable local release smoke scripts for npm assets, Python wheel/sdist artifacts, and the combined release gate. - Switched the release workflow npm asset build to the reusable npm builder. - Made OpenClaw release asset building install against the just-built local SDK tarball before rewriting packed metadata to the release dependency range. - Kept the OpenClaw source dependency registry-installable at `headroom-ai@^0.22.3` while the packed artifact still ships `^<release-version>`. - Added `registerHeadroomPlugin` as a named export while preserving the default `{ register }` OpenClaw loader contract. - Added Windows development bootstrap docs/script and regression tests for version sync, npm asset ordering, OpenClaw source installability, and Python wheel smoke import isolation. ## Testing - [x] Unit tests pass (`pytest`) - [x] New tests added for new functionality - [x] Manual testing performed ### Test Output ```text uv run --with pytest python -m pytest tests/test_release_workflows.py scripts/tests/test_version_sync.py -q 44 passed, 1 warning node --check scripts/build_npm_release_assets.mjs node --check scripts/verify_npm_release_assets.mjs python -m py_compile scripts/build_python_release_smoke.py scripts/release_smoke_all.py scripts/version-sync.py python scripts/verify-versions.py All versions aligned at 0.31.0 npm ci (plugins/openclaw) added 88 packages, audited 89 packages, found 0 vulnerabilities python scripts/release_smoke_all.py --out release-assets-local/all-pr1824-postmerge-fixed-20260710-104739 Verified npm release assets for 0.31.0 wheel metadata OK: headroom_ai-0.31.0-cp310-abi3-win_amd64.whl contains headroom/_core.pyd sdist License-File metadata OK: ['LICENSE', 'NOTICE'] smoke-import OK: version=0.31.0 hello=headroom-core ``` ## Real Behavior Proof - Environment: Windows 11, Python 3.14.3, Node v24.14.0, npm 11.9.0, uv 0.11.15, Rust/Cargo already installed in the local development environment. - Exact command / steps: Ran `python scripts/release_smoke_all.py --out release-assets-local/all-pr1824-postmerge-fixed-20260710-104739` after syncing this branch with current `headroomlabs/main`. - Observed result: The command built `headroom-ai-0.31.0.tgz`, `headroom-openclaw-0.31.0.tgz`, `headroom_ai-0.31.0-cp310-abi3-win_amd64.whl`, and `headroom_ai-0.31.0.tar.gz`; npm verifier passed; the wheel installed into a fresh venv and imported `headroom._core`. - Not tested: Full GitHub Actions release matrix and publish jobs with real PyPI/npm/GitHub Packages credentials. ## Review Readiness - [x] I have performed a self-review - [x] This PR is ready for human review ## Checklist - [x] My code follows the project's style guidelines - [x] I have performed a self-review of my code - [ ] I have commented my code, particularly in hard-to-understand areas - [x] I have made corresponding changes to the documentation - [x] My changes generate no new warnings - [x] I have added tests that prove my fix is effective or that my feature works - [x] New and existing unit tests pass locally with my changes - [ ] I have updated the CHANGELOG.md if applicable ## Screenshots (if applicable) N/A. ## Additional Notes The post-merge full smoke initially failed because the OpenClaw source package depended on `headroom-ai@^0.31.0`, which is not available on public npm yet. The builder now installs OpenClaw against the just-built local SDK tarball before build/pack, and then rewrites packed metadata to `^0.31.0`. --------- Co-authored-by: JerrettDavis <mxjerrett@gmail.com> Co-authored-by: Tejas Chopra <chopratejas@gmail.com>
2026-07-14 22:07:34 +02:00
json.dump(data, f, indent=2, ensure_ascii=False)
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:
chore(release): harden local artifact smokes (#1824) ## Description Harden the release artifact workflow so maintainers can reproduce npm and Python release checks locally and so OpenClaw packaging does not depend on a not-yet-published SDK version. This follow-up also keeps the OpenClaw loader export contract explicit and updates the PR after the branch was merged with current `headroomlabs/main`. ## Type of Change - [x] Bug fix (non-breaking change that fixes an issue) - [x] New feature (non-breaking change that adds functionality) - [x] Documentation update ## Changes Made - Added reusable local release smoke scripts for npm assets, Python wheel/sdist artifacts, and the combined release gate. - Switched the release workflow npm asset build to the reusable npm builder. - Made OpenClaw release asset building install against the just-built local SDK tarball before rewriting packed metadata to the release dependency range. - Kept the OpenClaw source dependency registry-installable at `headroom-ai@^0.22.3` while the packed artifact still ships `^<release-version>`. - Added `registerHeadroomPlugin` as a named export while preserving the default `{ register }` OpenClaw loader contract. - Added Windows development bootstrap docs/script and regression tests for version sync, npm asset ordering, OpenClaw source installability, and Python wheel smoke import isolation. ## Testing - [x] Unit tests pass (`pytest`) - [x] New tests added for new functionality - [x] Manual testing performed ### Test Output ```text uv run --with pytest python -m pytest tests/test_release_workflows.py scripts/tests/test_version_sync.py -q 44 passed, 1 warning node --check scripts/build_npm_release_assets.mjs node --check scripts/verify_npm_release_assets.mjs python -m py_compile scripts/build_python_release_smoke.py scripts/release_smoke_all.py scripts/version-sync.py python scripts/verify-versions.py All versions aligned at 0.31.0 npm ci (plugins/openclaw) added 88 packages, audited 89 packages, found 0 vulnerabilities python scripts/release_smoke_all.py --out release-assets-local/all-pr1824-postmerge-fixed-20260710-104739 Verified npm release assets for 0.31.0 wheel metadata OK: headroom_ai-0.31.0-cp310-abi3-win_amd64.whl contains headroom/_core.pyd sdist License-File metadata OK: ['LICENSE', 'NOTICE'] smoke-import OK: version=0.31.0 hello=headroom-core ``` ## Real Behavior Proof - Environment: Windows 11, Python 3.14.3, Node v24.14.0, npm 11.9.0, uv 0.11.15, Rust/Cargo already installed in the local development environment. - Exact command / steps: Ran `python scripts/release_smoke_all.py --out release-assets-local/all-pr1824-postmerge-fixed-20260710-104739` after syncing this branch with current `headroomlabs/main`. - Observed result: The command built `headroom-ai-0.31.0.tgz`, `headroom-openclaw-0.31.0.tgz`, `headroom_ai-0.31.0-cp310-abi3-win_amd64.whl`, and `headroom_ai-0.31.0.tar.gz`; npm verifier passed; the wheel installed into a fresh venv and imported `headroom._core`. - Not tested: Full GitHub Actions release matrix and publish jobs with real PyPI/npm/GitHub Packages credentials. ## Review Readiness - [x] I have performed a self-review - [x] This PR is ready for human review ## Checklist - [x] My code follows the project's style guidelines - [x] I have performed a self-review of my code - [ ] I have commented my code, particularly in hard-to-understand areas - [x] I have made corresponding changes to the documentation - [x] My changes generate no new warnings - [x] I have added tests that prove my fix is effective or that my feature works - [x] New and existing unit tests pass locally with my changes - [ ] I have updated the CHANGELOG.md if applicable ## Screenshots (if applicable) N/A. ## Additional Notes The post-merge full smoke initially failed because the OpenClaw source package depended on `headroom-ai@^0.31.0`, which is not available on public npm yet. The builder now installs OpenClaw against the just-built local SDK tarball before build/pack, and then rewrites packed metadata to `^0.31.0`. --------- Co-authored-by: JerrettDavis <mxjerrett@gmail.com> Co-authored-by: Tejas Chopra <chopratejas@gmail.com>
2026-07-14 22:07:34 +02:00
json.dump(data, f, indent=2, ensure_ascii=False)
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:
chore(release): harden local artifact smokes (#1824) ## Description Harden the release artifact workflow so maintainers can reproduce npm and Python release checks locally and so OpenClaw packaging does not depend on a not-yet-published SDK version. This follow-up also keeps the OpenClaw loader export contract explicit and updates the PR after the branch was merged with current `headroomlabs/main`. ## Type of Change - [x] Bug fix (non-breaking change that fixes an issue) - [x] New feature (non-breaking change that adds functionality) - [x] Documentation update ## Changes Made - Added reusable local release smoke scripts for npm assets, Python wheel/sdist artifacts, and the combined release gate. - Switched the release workflow npm asset build to the reusable npm builder. - Made OpenClaw release asset building install against the just-built local SDK tarball before rewriting packed metadata to the release dependency range. - Kept the OpenClaw source dependency registry-installable at `headroom-ai@^0.22.3` while the packed artifact still ships `^<release-version>`. - Added `registerHeadroomPlugin` as a named export while preserving the default `{ register }` OpenClaw loader contract. - Added Windows development bootstrap docs/script and regression tests for version sync, npm asset ordering, OpenClaw source installability, and Python wheel smoke import isolation. ## Testing - [x] Unit tests pass (`pytest`) - [x] New tests added for new functionality - [x] Manual testing performed ### Test Output ```text uv run --with pytest python -m pytest tests/test_release_workflows.py scripts/tests/test_version_sync.py -q 44 passed, 1 warning node --check scripts/build_npm_release_assets.mjs node --check scripts/verify_npm_release_assets.mjs python -m py_compile scripts/build_python_release_smoke.py scripts/release_smoke_all.py scripts/version-sync.py python scripts/verify-versions.py All versions aligned at 0.31.0 npm ci (plugins/openclaw) added 88 packages, audited 89 packages, found 0 vulnerabilities python scripts/release_smoke_all.py --out release-assets-local/all-pr1824-postmerge-fixed-20260710-104739 Verified npm release assets for 0.31.0 wheel metadata OK: headroom_ai-0.31.0-cp310-abi3-win_amd64.whl contains headroom/_core.pyd sdist License-File metadata OK: ['LICENSE', 'NOTICE'] smoke-import OK: version=0.31.0 hello=headroom-core ``` ## Real Behavior Proof - Environment: Windows 11, Python 3.14.3, Node v24.14.0, npm 11.9.0, uv 0.11.15, Rust/Cargo already installed in the local development environment. - Exact command / steps: Ran `python scripts/release_smoke_all.py --out release-assets-local/all-pr1824-postmerge-fixed-20260710-104739` after syncing this branch with current `headroomlabs/main`. - Observed result: The command built `headroom-ai-0.31.0.tgz`, `headroom-openclaw-0.31.0.tgz`, `headroom_ai-0.31.0-cp310-abi3-win_amd64.whl`, and `headroom_ai-0.31.0.tar.gz`; npm verifier passed; the wheel installed into a fresh venv and imported `headroom._core`. - Not tested: Full GitHub Actions release matrix and publish jobs with real PyPI/npm/GitHub Packages credentials. ## Review Readiness - [x] I have performed a self-review - [x] This PR is ready for human review ## Checklist - [x] My code follows the project's style guidelines - [x] I have performed a self-review of my code - [ ] I have commented my code, particularly in hard-to-understand areas - [x] I have made corresponding changes to the documentation - [x] My changes generate no new warnings - [x] I have added tests that prove my fix is effective or that my feature works - [x] New and existing unit tests pass locally with my changes - [ ] I have updated the CHANGELOG.md if applicable ## Screenshots (if applicable) N/A. ## Additional Notes The post-merge full smoke initially failed because the OpenClaw source package depended on `headroom-ai@^0.31.0`, which is not available on public npm yet. The builder now installs OpenClaw against the just-built local SDK tarball before build/pack, and then rewrites packed metadata to `^0.31.0`. --------- Co-authored-by: JerrettDavis <mxjerrett@gmail.com> Co-authored-by: Tejas Chopra <chopratejas@gmail.com>
2026-07-14 22:07:34 +02:00
json.dump(data, f, indent=2, ensure_ascii=False)
f.write("\n")
fix(release): sync generated version metadata on the release branch (#2659) ## Description The 0.33.0 release PR (#2339) has sat in `changes-requested` since 2026-07-17. Root cause: **release-please only rewrites `pyproject.toml` and its configured `extra-files`**, but other tracked files also carry the version — and `server.json` is asserted byte-for-byte against `render_server_json()`, which derives its version from `pyproject.toml`. So the bump alone fails `tests/test_mcp_registry/test_server_json.py::test_root_server_json_matches_builder` (the `test (2)` shard) on every regenerated release PR. Nothing in the repo regenerated `server.json` at all, so it fell behind every release. Unblocks #2339. ### Why the release *build* passes but the release PR does not `release.yml` already runs `scripts/version-sync.py` immediately before its own `verify-versions.py` gate (lines 145 and 278). That is why `build` and `build-wheels` are green on #2339 despite the drift — it syncs in the workspace, uncommitted. The regular CI test job does **not** sync, so the fix has to be committed to the branch. This also explains why reviewers kept seeing `verify-versions.py` fail locally while CI's build jobs passed: the verifier is never run un-synced inside `release.yml`. ## Type of Change - [x] Bug fix (non-breaking change that fixes an issue) - [ ] New feature (non-breaking change that adds functionality) - [ ] Breaking change (fix or feature that would cause existing functionality to change) - [ ] Documentation update - [ ] Performance improvement - [ ] Code refactoring (no functional changes) ## Changes Made - **`scripts/version-sync.py`**: also write `server.json`. It was the one version-carrying file with no writer anywhere. Values are rewritten in place so key order and formatting keep matching the builder's byte-for-byte output (verified: the file is pure ASCII and round-trips exactly through `json.dumps(..., indent=2) + "\n"`). - **`.github/workflows/release-metadata-sync.yml`** (new): on a push to `release-please--branches--**`, run version-sync → gate on verify-versions → commit if changed. - **Keyed off the branch push** because release-please force-regenerates that branch on every merge to main. That is precisely what wiped the hand-pushed metadata fixes on #2339 (`2a86c8ff`, `d5ea4dc5`) — a push trigger re-heals after every regeneration instead of being lost. - **Uses the same PAT as `release-please.yml`**: a `GITHUB_TOKEN` push does not trigger workflows, so the release PR's checks would never re-run against the synced commit and would stay red. - **Idempotent**: the self-triggered rerun finds no diff and exits before pushing, so the loop terminates after one no-op run. - **Corrected pre-existing drift on `main`**: the agent-hooks plugin manifests, both marketplace manifests, and `.releasemetadata` were stranded at **0.31.0** — never bumped for 0.32.0 either. `verify-versions.py` now passes on `main`. ### Why not more `extra-files` entries That would need ~13 jsonpath entries restating what `version-sync.py` already knows, and a jsonpath that fails to match **fails silently** — the same class of failure this PR removes, discoverable only after a real release PR regenerates. There is also no precedent for nested jsonpath (`$.packages[0].version`, `$.metadata.version`) in the config today; both existing entries are plain `$.version`. Running the script keeps one source of truth, and files added to it later are covered with no change here. ## Testing - [x] Unit tests pass (`pytest`) - [x] Linting passes (`ruff check .`) - [ ] Type checking passes (`mypy headroom`) — no `headroom/` sources touched - [x] New tests added for new functionality - [x] Manual testing performed ### Test Output ```text $ python -m pytest scripts/tests/ tests/test_release_workflows.py tests/test_mcp_registry/ -q 207 passed in 2.69s $ ruff check scripts/version-sync.py scripts/tests/test_version_sync.py tests/test_release_workflows.py All checks passed! $ ruff format --check <same> 3 files already formatted $ actionlint .github/workflows/release-metadata-sync.yml (clean) ``` New tests: - `test_server_json_version_is_synchronized` — version-sync moves both `server.json` version fields and preserves the other keys. - `test_release_metadata_sync_runs_on_release_please_branch` — asserts the trigger, the sync→verify→commit ordering, the no-op guard, and the PAT. - `test_version_sync_covers_every_file_the_verifier_gates` — guards `version-sync.py` and `verify-versions.py` against drifting apart again, which is the root cause here. ## Real Behavior Proof - **Environment:** macOS (Darwin arm64), Python 3.12, repo venv. - **Exact command / steps:** reproduced the CI failure locally by simulating release-please's partial bump, then applying the fix. **Reproducing the exact `test (2)` failure** — set `pyproject` to 0.33.0 while `server.json` stays at 0.32.0, as release-please leaves it: ```text $ python -m pytest tests/test_mcp_registry/test_server_json.py -q FAILED tests/test_mcp_registry/test_server_json.py::test_root_server_json_matches_builder 1 failed, 3 passed ``` **After `version-sync.py`:** ```text $ python scripts/version-sync.py && python -m pytest tests/test_mcp_registry/test_server_json.py -q 4 passed ``` **Both gates green on a simulated 0.33.0 bump:** ```text $ python scripts/version-sync.py --version 0.33.0 Version synchronized to 0.33.0 $ python scripts/verify-versions.py All versions aligned at 0.33.0 $ python -m pytest tests/test_mcp_registry/test_server_json.py -q 4 passed ``` **Idempotency** (the property the workflow's loop-termination relies on): re-running against an already-synced tree leaves `pyproject.toml`, `server.json`, `openclaw`, and `sdk/typescript` untouched. - **Not tested:** the workflow has not executed on a real release-please branch regeneration — that can only be exercised once this is on `main` and release-please next updates #2339. The PAT push path and the self-trigger no-op are reasoned from `release-please.yml`'s existing token comment and from local idempotency, not observed in CI. ## Review Readiness - [x] I have performed a self-review - [x] This PR is ready for human review ## Checklist - [x] My code follows the project's style guidelines - [x] I have performed a self-review of my code - [x] I have commented my code, particularly in hard-to-understand areas - [ ] I have made corresponding changes to the documentation - [x] My changes generate no new warnings - [x] I have added tests that prove my fix is effective or that my feature works - [x] New and existing unit tests pass locally with my changes - [x] I did **not** edit `CHANGELOG.md` ## Additional Notes **Context on the v0.32.0 release failure, since it is easy to misread as "images never build".** Every artifact built for v0.32.0 — all 5 wheel platforms including Windows, all 16 Docker builds + 8 manifests + `promote-latest`, npm, and GitHub Packages. Only `publish-pypi` failed (PyPI attestations, already fixed by `f9cbdd6e` / #2405), and `create-release` was skipped because it depends on it. That is why the release looked like it produced nothing. **Separate, approaching blocker — not addressed here.** PyPI is at **9.69 GB of its 10 GB project cap (96.9%)**, leaving ~305 MB against ~68 MB per release, so roughly 4 more releases fit. The `0.21.x` series alone holds **6.58 GB across 31 releases**, from the old every-push-is-a-release era; pruning it would reclaim two thirds of the quota. Worth a separate issue. **`.releasemetadata` is written but never read** by anything outside `version-sync.py` and its test. It is kept in sync here for internal consistency, but it may be a deletion candidate.
2026-07-29 15:12:04 -07:00
def update_server_json(file_path: Path, version: str) -> None:
"""Update the MCP registry descriptor's version fields.
``server.json`` is asserted byte-for-byte against ``render_server_json()``
(tests/test_mcp_registry/test_server_json.py), which derives the version from
``pyproject.toml``. Nothing regenerated this file, so it silently fell behind
every release and failed that test on the release PR. Values are rewritten in
place so key order and formatting keep matching the builder's output.
"""
with open(file_path, encoding="utf-8") as f:
data = json.load(f)
data["version"] = version
packages = data.get("packages")
if isinstance(packages, list):
for package in packages:
if isinstance(package, dict):
package["version"] = version
with open(file_path, "w", encoding="utf-8") as f:
json.dump(data, f, indent=2, ensure_ascii=False)
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,
)
chore(release): harden local artifact smokes (#1824) ## Description Harden the release artifact workflow so maintainers can reproduce npm and Python release checks locally and so OpenClaw packaging does not depend on a not-yet-published SDK version. This follow-up also keeps the OpenClaw loader export contract explicit and updates the PR after the branch was merged with current `headroomlabs/main`. ## Type of Change - [x] Bug fix (non-breaking change that fixes an issue) - [x] New feature (non-breaking change that adds functionality) - [x] Documentation update ## Changes Made - Added reusable local release smoke scripts for npm assets, Python wheel/sdist artifacts, and the combined release gate. - Switched the release workflow npm asset build to the reusable npm builder. - Made OpenClaw release asset building install against the just-built local SDK tarball before rewriting packed metadata to the release dependency range. - Kept the OpenClaw source dependency registry-installable at `headroom-ai@^0.22.3` while the packed artifact still ships `^<release-version>`. - Added `registerHeadroomPlugin` as a named export while preserving the default `{ register }` OpenClaw loader contract. - Added Windows development bootstrap docs/script and regression tests for version sync, npm asset ordering, OpenClaw source installability, and Python wheel smoke import isolation. ## Testing - [x] Unit tests pass (`pytest`) - [x] New tests added for new functionality - [x] Manual testing performed ### Test Output ```text uv run --with pytest python -m pytest tests/test_release_workflows.py scripts/tests/test_version_sync.py -q 44 passed, 1 warning node --check scripts/build_npm_release_assets.mjs node --check scripts/verify_npm_release_assets.mjs python -m py_compile scripts/build_python_release_smoke.py scripts/release_smoke_all.py scripts/version-sync.py python scripts/verify-versions.py All versions aligned at 0.31.0 npm ci (plugins/openclaw) added 88 packages, audited 89 packages, found 0 vulnerabilities python scripts/release_smoke_all.py --out release-assets-local/all-pr1824-postmerge-fixed-20260710-104739 Verified npm release assets for 0.31.0 wheel metadata OK: headroom_ai-0.31.0-cp310-abi3-win_amd64.whl contains headroom/_core.pyd sdist License-File metadata OK: ['LICENSE', 'NOTICE'] smoke-import OK: version=0.31.0 hello=headroom-core ``` ## Real Behavior Proof - Environment: Windows 11, Python 3.14.3, Node v24.14.0, npm 11.9.0, uv 0.11.15, Rust/Cargo already installed in the local development environment. - Exact command / steps: Ran `python scripts/release_smoke_all.py --out release-assets-local/all-pr1824-postmerge-fixed-20260710-104739` after syncing this branch with current `headroomlabs/main`. - Observed result: The command built `headroom-ai-0.31.0.tgz`, `headroom-openclaw-0.31.0.tgz`, `headroom_ai-0.31.0-cp310-abi3-win_amd64.whl`, and `headroom_ai-0.31.0.tar.gz`; npm verifier passed; the wheel installed into a fresh venv and imported `headroom._core`. - Not tested: Full GitHub Actions release matrix and publish jobs with real PyPI/npm/GitHub Packages credentials. ## Review Readiness - [x] I have performed a self-review - [x] This PR is ready for human review ## Checklist - [x] My code follows the project's style guidelines - [x] I have performed a self-review of my code - [ ] I have commented my code, particularly in hard-to-understand areas - [x] I have made corresponding changes to the documentation - [x] My changes generate no new warnings - [x] I have added tests that prove my fix is effective or that my feature works - [x] New and existing unit tests pass locally with my changes - [ ] I have updated the CHANGELOG.md if applicable ## Screenshots (if applicable) N/A. ## Additional Notes The post-merge full smoke initially failed because the OpenClaw source package depended on `headroom-ai@^0.31.0`, which is not available on public npm yet. The builder now installs OpenClaw against the just-built local SDK tarball before build/pack, and then rewrites packed metadata to `^0.31.0`. --------- Co-authored-by: JerrettDavis <mxjerrett@gmail.com> Co-authored-by: Tejas Chopra <chopratejas@gmail.com>
2026-07-14 22:07:34 +02:00
def update_openclaw_package_json(file_path: Path, version: str) -> None:
"""Update openclaw package.json version.
Keep the source `headroom-ai` dependency registry-installable. The release
workflow rewrites the packed tgz dependency to the exact release range after
the local SDK tarball is available.
"""
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:
chore(release): harden local artifact smokes (#1824) ## Description Harden the release artifact workflow so maintainers can reproduce npm and Python release checks locally and so OpenClaw packaging does not depend on a not-yet-published SDK version. This follow-up also keeps the OpenClaw loader export contract explicit and updates the PR after the branch was merged with current `headroomlabs/main`. ## Type of Change - [x] Bug fix (non-breaking change that fixes an issue) - [x] New feature (non-breaking change that adds functionality) - [x] Documentation update ## Changes Made - Added reusable local release smoke scripts for npm assets, Python wheel/sdist artifacts, and the combined release gate. - Switched the release workflow npm asset build to the reusable npm builder. - Made OpenClaw release asset building install against the just-built local SDK tarball before rewriting packed metadata to the release dependency range. - Kept the OpenClaw source dependency registry-installable at `headroom-ai@^0.22.3` while the packed artifact still ships `^<release-version>`. - Added `registerHeadroomPlugin` as a named export while preserving the default `{ register }` OpenClaw loader contract. - Added Windows development bootstrap docs/script and regression tests for version sync, npm asset ordering, OpenClaw source installability, and Python wheel smoke import isolation. ## Testing - [x] Unit tests pass (`pytest`) - [x] New tests added for new functionality - [x] Manual testing performed ### Test Output ```text uv run --with pytest python -m pytest tests/test_release_workflows.py scripts/tests/test_version_sync.py -q 44 passed, 1 warning node --check scripts/build_npm_release_assets.mjs node --check scripts/verify_npm_release_assets.mjs python -m py_compile scripts/build_python_release_smoke.py scripts/release_smoke_all.py scripts/version-sync.py python scripts/verify-versions.py All versions aligned at 0.31.0 npm ci (plugins/openclaw) added 88 packages, audited 89 packages, found 0 vulnerabilities python scripts/release_smoke_all.py --out release-assets-local/all-pr1824-postmerge-fixed-20260710-104739 Verified npm release assets for 0.31.0 wheel metadata OK: headroom_ai-0.31.0-cp310-abi3-win_amd64.whl contains headroom/_core.pyd sdist License-File metadata OK: ['LICENSE', 'NOTICE'] smoke-import OK: version=0.31.0 hello=headroom-core ``` ## Real Behavior Proof - Environment: Windows 11, Python 3.14.3, Node v24.14.0, npm 11.9.0, uv 0.11.15, Rust/Cargo already installed in the local development environment. - Exact command / steps: Ran `python scripts/release_smoke_all.py --out release-assets-local/all-pr1824-postmerge-fixed-20260710-104739` after syncing this branch with current `headroomlabs/main`. - Observed result: The command built `headroom-ai-0.31.0.tgz`, `headroom-openclaw-0.31.0.tgz`, `headroom_ai-0.31.0-cp310-abi3-win_amd64.whl`, and `headroom_ai-0.31.0.tar.gz`; npm verifier passed; the wheel installed into a fresh venv and imported `headroom._core`. - Not tested: Full GitHub Actions release matrix and publish jobs with real PyPI/npm/GitHub Packages credentials. ## Review Readiness - [x] I have performed a self-review - [x] This PR is ready for human review ## Checklist - [x] My code follows the project's style guidelines - [x] I have performed a self-review of my code - [ ] I have commented my code, particularly in hard-to-understand areas - [x] I have made corresponding changes to the documentation - [x] My changes generate no new warnings - [x] I have added tests that prove my fix is effective or that my feature works - [x] New and existing unit tests pass locally with my changes - [ ] I have updated the CHANGELOG.md if applicable ## Screenshots (if applicable) N/A. ## Additional Notes The post-merge full smoke initially failed because the OpenClaw source package depended on `headroom-ai@^0.31.0`, which is not available on public npm yet. The builder now installs OpenClaw against the just-built local SDK tarball before build/pack, and then rewrites packed metadata to `^0.31.0`. --------- Co-authored-by: JerrettDavis <mxjerrett@gmail.com> Co-authored-by: Tejas Chopra <chopratejas@gmail.com>
2026-07-14 22:07:34 +02:00
json.dump(data, f, indent=2, ensure_ascii=False)
f.write("\n")
fix: publish headroom-opencode in release workflow (#2372) ## Description `headroom-opencode` is documented as an npm package, but the release workflow never published it, so installs failed with a registry 404 even though the plugin source already lived under `plugins/opencode`. This wires the existing package into the npm release path, keeps its version synced with root releases, and adds release guards for the new package. Closes #76. ## Type of Change - [x] Bug fix (non-breaking change that fixes an issue) - [ ] New feature (non-breaking change that adds functionality) - [ ] Breaking change (fix or feature that would cause existing functionality to change) - [x] Documentation update - [ ] Performance improvement - [ ] Code refactoring (no functional changes) ## Changes Made - added `headroom-opencode` to the npm release workflow, including release-version stamping and `headroom-ai` dependency rewrite before publish - added `plugins/opencode/package.json` to release-please and local version-sync guards - synced the source opencode package version to the current release line and documented the new npm package in the release docs - added focused release workflow and version-sync tests for the opencode package - aligned the two failing dashboard Playwright tests with the current Session/Lifetime split and `/stats-lifetime` fixture contract ## Testing - [x] Unit tests pass (`uv run pytest scripts/tests/test_version_sync.py -q`, `uv run pytest tests/test_release_workflows.py -q -k 'publish_npm_rewrites_opencode_dependency_after_version_and_before_publish or opencode_source_dependency_matches_lockfile_registry_range or release_please_manifest_config_consistency'`) - [x] Unit tests pass (`uv run pytest tests/test_dashboard_cache_lifetime_playwright.py tests/test_dashboard_cache_ttl_playwright.py -q`) - [x] Linting passes (`uv run ruff check scripts/verify-versions.py scripts/version-sync.py scripts/tests/test_version_sync.py tests/test_release_workflows.py`) - [ ] Type checking passes (`uv run mypy headroom`) - [x] New tests added for new functionality when applicable - [x] Manual testing performed ### Test Output ```text $ uv run pytest scripts/tests/test_version_sync.py -q 8 passed, 1 warning in 0.51s $ uv run pytest tests/test_release_workflows.py -q -k 'publish_npm_rewrites_opencode_dependency_after_version_and_before_publish or opencode_source_dependency_matches_lockfile_registry_range or release_please_manifest_config_consistency' 2 passed, 38 deselected, 1 warning in 0.07s $ uv run pytest tests/test_dashboard_cache_lifetime_playwright.py tests/test_dashboard_cache_ttl_playwright.py -q 4 passed, 1 warning in 4.04s $ uv run ruff check scripts/verify-versions.py scripts/version-sync.py scripts/tests/test_version_sync.py tests/test_release_workflows.py All checks passed! $ npm ci && npm run build (plugins/opencode) Build success; dist/index.js, dist/entry.opencode.js, and DTS outputs emitted ``` ## Real Behavior Proof - Environment: Windows, Python 3.11.15, Node v24.15.0, npm 11.16.0 - Exact command / steps: inspected `.github/workflows/release.yml`, updated the npm publish path for `plugins/opencode`, aligned the two failing dashboard Playwright tests with the current Session/Lifetime split, then ran the focused pytest commands above plus `npm ci && npm run build` in `plugins/opencode` - Observed result: the release workflow now versions and publishes `headroom-opencode`, release-please and version-sync track `plugins/opencode/package.json`, the dashboard tests now fetch durable cache and setup-url data from the Lifetime view, and the opencode package still builds locally from source - Not tested: GitHub Package Registry publish ## Review Readiness - [x] I have performed a self-review - [x] This PR is ready for human review ## Checklist - [x] My code follows the project's style guidelines - [x] I have performed a self-review of my code - [x] I have commented my code, particularly in hard-to-understand areas - [x] I have made corresponding changes to the documentation - [x] My changes generate no new warnings - [x] I have added tests that prove my fix is effective or that my feature works - [x] New and existing unit tests pass locally with my changes - [x] I have updated the CHANGELOG.md if applicable ## Additional Notes `CHANGELOG.md` is unchanged because release-please owns changelog generation here. --------- Co-authored-by: JD Davis <mxjerrett@gmail.com>
2026-08-12 00:56:40 -04:00
def update_opencode_package_json(file_path: Path, version: str) -> None:
"""Update opencode package.json version.
Keep the source `headroom-ai` dependency registry-installable. The release
workflow rewrites the packed dependency to the exact release range right
before npm publication.
"""
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, ensure_ascii=False)
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:
fix(scripts): rename .releaseetadata to .releasemetadata (#1246) ## Description Fixes a typo in the release metadata filename written by `scripts/version-sync.py`. The file was being created as `.releaseetadata` (double `e`) instead of `.releasemetadata`. Any downstream tooling or developer looking for the artifact by its correct name would not find it. Closes # ## Type of Change - [x] Bug fix (non-breaking change that fixes an issue) - [ ] New feature (non-breaking change that adds functionality) - [ ] Breaking change (fix or feature that would cause existing functionality to change) - [ ] Documentation update - [ ] Performance improvement - [ ] Code refactoring (no functional changes) ## Changes Made - `scripts/version-sync.py`: corrected the filename in `write_release_metadata()` — both the docstring and the `metadata_path` assignment. - `scripts/tests/test_version_sync.py`: updated 3 test assertions to reference `.releasemetadata`. ## Testing - [x] Unit tests pass (`pytest`) - [ ] Linting passes (`ruff check .`) - [ ] Type checking passes (`mypy headroom`) - [ ] New tests added for new functionality - [ ] Manual testing performed ### Test Output ```text $ uv run python -m pytest scripts/tests/test_version_sync.py -q ============================= test session starts ============================== platform linux -- Python 3.14.0, pytest-9.1.1, pluggy-1.6.0 rootdir: /home/sepurisaikrishna/Documents/calude-here/headroom configfile: pyproject.toml collected 6 items scripts/tests/test_version_sync.py ...... [100%] =============================== warnings summary =============================== PytestConfigWarning: Unknown config option: asyncio_mode -- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html ========================= 6 passed, 1 warning in 1.00s ========================= $ git diff --check origin/main..HEAD # no output; command exited 0 ``` ## Real Behavior Proof - Environment: Linux, Python 3.14.0, uv-managed .venv, branch based on current origin/main. - Exact command / steps: grep -r "releaseetadata" scripts/ before the fix returns hits; after the fix returns nothing. Confirmed .releasemetadata is written correctly by test_release_metadata_written. - Observed result: all 6 test_version_sync.py tests pass with the corrected filename. - Not tested: full repository pytest, ruff, and mypy — this is a one-line spelling fix with no logic changes. ## Review Readiness - [x] I have performed a self-review - [x] This PR is ready for human review ## Checklist - [x] My code follows the project's style guidelines - [x] I have performed a self-review of my code - [ ] I have commented my code, particularly in hard-to-understand areas - [ ] I have made corresponding changes to the documentation - [x] My changes generate no new warnings - [ ] I have added tests that prove my fix is effective or that my feature works - [x] New and existing unit tests pass locally with my changes - [ ] I have updated the CHANGELOG.md if applicable ## Screenshots (if applicable) N/A. ## Additional Notes - The typo was consistent across implementation and tests, so all tests passed before this fix with the wrong name. The fix corrects both the code and the test expectations together. - No production behaviour changes the file is written but not yet consumed by any workflow step.
2026-07-10 03:59:17 +05:30
"""Write .releasemetadata JSON file."""
metadata = {
"version": version,
"packages": {
"pypi": version,
"npm-sdk": version,
"npm-openclaw": version,
fix: publish headroom-opencode in release workflow (#2372) ## Description `headroom-opencode` is documented as an npm package, but the release workflow never published it, so installs failed with a registry 404 even though the plugin source already lived under `plugins/opencode`. This wires the existing package into the npm release path, keeps its version synced with root releases, and adds release guards for the new package. Closes #76. ## Type of Change - [x] Bug fix (non-breaking change that fixes an issue) - [ ] New feature (non-breaking change that adds functionality) - [ ] Breaking change (fix or feature that would cause existing functionality to change) - [x] Documentation update - [ ] Performance improvement - [ ] Code refactoring (no functional changes) ## Changes Made - added `headroom-opencode` to the npm release workflow, including release-version stamping and `headroom-ai` dependency rewrite before publish - added `plugins/opencode/package.json` to release-please and local version-sync guards - synced the source opencode package version to the current release line and documented the new npm package in the release docs - added focused release workflow and version-sync tests for the opencode package - aligned the two failing dashboard Playwright tests with the current Session/Lifetime split and `/stats-lifetime` fixture contract ## Testing - [x] Unit tests pass (`uv run pytest scripts/tests/test_version_sync.py -q`, `uv run pytest tests/test_release_workflows.py -q -k 'publish_npm_rewrites_opencode_dependency_after_version_and_before_publish or opencode_source_dependency_matches_lockfile_registry_range or release_please_manifest_config_consistency'`) - [x] Unit tests pass (`uv run pytest tests/test_dashboard_cache_lifetime_playwright.py tests/test_dashboard_cache_ttl_playwright.py -q`) - [x] Linting passes (`uv run ruff check scripts/verify-versions.py scripts/version-sync.py scripts/tests/test_version_sync.py tests/test_release_workflows.py`) - [ ] Type checking passes (`uv run mypy headroom`) - [x] New tests added for new functionality when applicable - [x] Manual testing performed ### Test Output ```text $ uv run pytest scripts/tests/test_version_sync.py -q 8 passed, 1 warning in 0.51s $ uv run pytest tests/test_release_workflows.py -q -k 'publish_npm_rewrites_opencode_dependency_after_version_and_before_publish or opencode_source_dependency_matches_lockfile_registry_range or release_please_manifest_config_consistency' 2 passed, 38 deselected, 1 warning in 0.07s $ uv run pytest tests/test_dashboard_cache_lifetime_playwright.py tests/test_dashboard_cache_ttl_playwright.py -q 4 passed, 1 warning in 4.04s $ uv run ruff check scripts/verify-versions.py scripts/version-sync.py scripts/tests/test_version_sync.py tests/test_release_workflows.py All checks passed! $ npm ci && npm run build (plugins/opencode) Build success; dist/index.js, dist/entry.opencode.js, and DTS outputs emitted ``` ## Real Behavior Proof - Environment: Windows, Python 3.11.15, Node v24.15.0, npm 11.16.0 - Exact command / steps: inspected `.github/workflows/release.yml`, updated the npm publish path for `plugins/opencode`, aligned the two failing dashboard Playwright tests with the current Session/Lifetime split, then ran the focused pytest commands above plus `npm ci && npm run build` in `plugins/opencode` - Observed result: the release workflow now versions and publishes `headroom-opencode`, release-please and version-sync track `plugins/opencode/package.json`, the dashboard tests now fetch durable cache and setup-url data from the Lifetime view, and the opencode package still builds locally from source - Not tested: GitHub Package Registry publish ## Review Readiness - [x] I have performed a self-review - [x] This PR is ready for human review ## Checklist - [x] My code follows the project's style guidelines - [x] I have performed a self-review of my code - [x] I have commented my code, particularly in hard-to-understand areas - [x] I have made corresponding changes to the documentation - [x] My changes generate no new warnings - [x] I have added tests that prove my fix is effective or that my feature works - [x] New and existing unit tests pass locally with my changes - [x] I have updated the CHANGELOG.md if applicable ## Additional Notes `CHANGELOG.md` is unchanged because release-please owns changelog generation here. --------- Co-authored-by: JD Davis <mxjerrett@gmail.com>
2026-08-12 00:56:40 -04:00
"npm-opencode": version,
"agent-hooks-plugin": version,
},
}
fix(scripts): rename .releaseetadata to .releasemetadata (#1246) ## Description Fixes a typo in the release metadata filename written by `scripts/version-sync.py`. The file was being created as `.releaseetadata` (double `e`) instead of `.releasemetadata`. Any downstream tooling or developer looking for the artifact by its correct name would not find it. Closes # ## Type of Change - [x] Bug fix (non-breaking change that fixes an issue) - [ ] New feature (non-breaking change that adds functionality) - [ ] Breaking change (fix or feature that would cause existing functionality to change) - [ ] Documentation update - [ ] Performance improvement - [ ] Code refactoring (no functional changes) ## Changes Made - `scripts/version-sync.py`: corrected the filename in `write_release_metadata()` — both the docstring and the `metadata_path` assignment. - `scripts/tests/test_version_sync.py`: updated 3 test assertions to reference `.releasemetadata`. ## Testing - [x] Unit tests pass (`pytest`) - [ ] Linting passes (`ruff check .`) - [ ] Type checking passes (`mypy headroom`) - [ ] New tests added for new functionality - [ ] Manual testing performed ### Test Output ```text $ uv run python -m pytest scripts/tests/test_version_sync.py -q ============================= test session starts ============================== platform linux -- Python 3.14.0, pytest-9.1.1, pluggy-1.6.0 rootdir: /home/sepurisaikrishna/Documents/calude-here/headroom configfile: pyproject.toml collected 6 items scripts/tests/test_version_sync.py ...... [100%] =============================== warnings summary =============================== PytestConfigWarning: Unknown config option: asyncio_mode -- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html ========================= 6 passed, 1 warning in 1.00s ========================= $ git diff --check origin/main..HEAD # no output; command exited 0 ``` ## Real Behavior Proof - Environment: Linux, Python 3.14.0, uv-managed .venv, branch based on current origin/main. - Exact command / steps: grep -r "releaseetadata" scripts/ before the fix returns hits; after the fix returns nothing. Confirmed .releasemetadata is written correctly by test_release_metadata_written. - Observed result: all 6 test_version_sync.py tests pass with the corrected filename. - Not tested: full repository pytest, ruff, and mypy — this is a one-line spelling fix with no logic changes. ## Review Readiness - [x] I have performed a self-review - [x] This PR is ready for human review ## Checklist - [x] My code follows the project's style guidelines - [x] I have performed a self-review of my code - [ ] I have commented my code, particularly in hard-to-understand areas - [ ] I have made corresponding changes to the documentation - [x] My changes generate no new warnings - [ ] I have added tests that prove my fix is effective or that my feature works - [x] New and existing unit tests pass locally with my changes - [ ] I have updated the CHANGELOG.md if applicable ## Screenshots (if applicable) N/A. ## Additional Notes - The typo was consistent across implementation and tests, so all tests passed before this fix with the wrong name. The fix corrects both the code and the test expectations together. - No production behaviour changes the file is written but not yet consumed by any workflow step.
2026-07-10 03:59:17 +05:30
metadata_path = root / ".releasemetadata"
with open(metadata_path, "w", encoding="utf-8") as f:
chore(release): harden local artifact smokes (#1824) ## Description Harden the release artifact workflow so maintainers can reproduce npm and Python release checks locally and so OpenClaw packaging does not depend on a not-yet-published SDK version. This follow-up also keeps the OpenClaw loader export contract explicit and updates the PR after the branch was merged with current `headroomlabs/main`. ## Type of Change - [x] Bug fix (non-breaking change that fixes an issue) - [x] New feature (non-breaking change that adds functionality) - [x] Documentation update ## Changes Made - Added reusable local release smoke scripts for npm assets, Python wheel/sdist artifacts, and the combined release gate. - Switched the release workflow npm asset build to the reusable npm builder. - Made OpenClaw release asset building install against the just-built local SDK tarball before rewriting packed metadata to the release dependency range. - Kept the OpenClaw source dependency registry-installable at `headroom-ai@^0.22.3` while the packed artifact still ships `^<release-version>`. - Added `registerHeadroomPlugin` as a named export while preserving the default `{ register }` OpenClaw loader contract. - Added Windows development bootstrap docs/script and regression tests for version sync, npm asset ordering, OpenClaw source installability, and Python wheel smoke import isolation. ## Testing - [x] Unit tests pass (`pytest`) - [x] New tests added for new functionality - [x] Manual testing performed ### Test Output ```text uv run --with pytest python -m pytest tests/test_release_workflows.py scripts/tests/test_version_sync.py -q 44 passed, 1 warning node --check scripts/build_npm_release_assets.mjs node --check scripts/verify_npm_release_assets.mjs python -m py_compile scripts/build_python_release_smoke.py scripts/release_smoke_all.py scripts/version-sync.py python scripts/verify-versions.py All versions aligned at 0.31.0 npm ci (plugins/openclaw) added 88 packages, audited 89 packages, found 0 vulnerabilities python scripts/release_smoke_all.py --out release-assets-local/all-pr1824-postmerge-fixed-20260710-104739 Verified npm release assets for 0.31.0 wheel metadata OK: headroom_ai-0.31.0-cp310-abi3-win_amd64.whl contains headroom/_core.pyd sdist License-File metadata OK: ['LICENSE', 'NOTICE'] smoke-import OK: version=0.31.0 hello=headroom-core ``` ## Real Behavior Proof - Environment: Windows 11, Python 3.14.3, Node v24.14.0, npm 11.9.0, uv 0.11.15, Rust/Cargo already installed in the local development environment. - Exact command / steps: Ran `python scripts/release_smoke_all.py --out release-assets-local/all-pr1824-postmerge-fixed-20260710-104739` after syncing this branch with current `headroomlabs/main`. - Observed result: The command built `headroom-ai-0.31.0.tgz`, `headroom-openclaw-0.31.0.tgz`, `headroom_ai-0.31.0-cp310-abi3-win_amd64.whl`, and `headroom_ai-0.31.0.tar.gz`; npm verifier passed; the wheel installed into a fresh venv and imported `headroom._core`. - Not tested: Full GitHub Actions release matrix and publish jobs with real PyPI/npm/GitHub Packages credentials. ## Review Readiness - [x] I have performed a self-review - [x] This PR is ready for human review ## Checklist - [x] My code follows the project's style guidelines - [x] I have performed a self-review of my code - [ ] I have commented my code, particularly in hard-to-understand areas - [x] I have made corresponding changes to the documentation - [x] My changes generate no new warnings - [x] I have added tests that prove my fix is effective or that my feature works - [x] New and existing unit tests pass locally with my changes - [ ] I have updated the CHANGELOG.md if applicable ## Screenshots (if applicable) N/A. ## Additional Notes The post-merge full smoke initially failed because the OpenClaw source package depended on `headroom-ai@^0.31.0`, which is not available on public npm yet. The builder now installs OpenClaw against the just-built local SDK tarball before build/pack, and then rewrites packed metadata to `^0.31.0`. --------- Co-authored-by: JerrettDavis <mxjerrett@gmail.com> Co-authored-by: Tejas Chopra <chopratejas@gmail.com>
2026-07-14 22:07:34 +02:00
json.dump(metadata, f, indent=2, ensure_ascii=False)
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)
chore(release): harden local artifact smokes (#1824) ## Description Harden the release artifact workflow so maintainers can reproduce npm and Python release checks locally and so OpenClaw packaging does not depend on a not-yet-published SDK version. This follow-up also keeps the OpenClaw loader export contract explicit and updates the PR after the branch was merged with current `headroomlabs/main`. ## Type of Change - [x] Bug fix (non-breaking change that fixes an issue) - [x] New feature (non-breaking change that adds functionality) - [x] Documentation update ## Changes Made - Added reusable local release smoke scripts for npm assets, Python wheel/sdist artifacts, and the combined release gate. - Switched the release workflow npm asset build to the reusable npm builder. - Made OpenClaw release asset building install against the just-built local SDK tarball before rewriting packed metadata to the release dependency range. - Kept the OpenClaw source dependency registry-installable at `headroom-ai@^0.22.3` while the packed artifact still ships `^<release-version>`. - Added `registerHeadroomPlugin` as a named export while preserving the default `{ register }` OpenClaw loader contract. - Added Windows development bootstrap docs/script and regression tests for version sync, npm asset ordering, OpenClaw source installability, and Python wheel smoke import isolation. ## Testing - [x] Unit tests pass (`pytest`) - [x] New tests added for new functionality - [x] Manual testing performed ### Test Output ```text uv run --with pytest python -m pytest tests/test_release_workflows.py scripts/tests/test_version_sync.py -q 44 passed, 1 warning node --check scripts/build_npm_release_assets.mjs node --check scripts/verify_npm_release_assets.mjs python -m py_compile scripts/build_python_release_smoke.py scripts/release_smoke_all.py scripts/version-sync.py python scripts/verify-versions.py All versions aligned at 0.31.0 npm ci (plugins/openclaw) added 88 packages, audited 89 packages, found 0 vulnerabilities python scripts/release_smoke_all.py --out release-assets-local/all-pr1824-postmerge-fixed-20260710-104739 Verified npm release assets for 0.31.0 wheel metadata OK: headroom_ai-0.31.0-cp310-abi3-win_amd64.whl contains headroom/_core.pyd sdist License-File metadata OK: ['LICENSE', 'NOTICE'] smoke-import OK: version=0.31.0 hello=headroom-core ``` ## Real Behavior Proof - Environment: Windows 11, Python 3.14.3, Node v24.14.0, npm 11.9.0, uv 0.11.15, Rust/Cargo already installed in the local development environment. - Exact command / steps: Ran `python scripts/release_smoke_all.py --out release-assets-local/all-pr1824-postmerge-fixed-20260710-104739` after syncing this branch with current `headroomlabs/main`. - Observed result: The command built `headroom-ai-0.31.0.tgz`, `headroom-openclaw-0.31.0.tgz`, `headroom_ai-0.31.0-cp310-abi3-win_amd64.whl`, and `headroom_ai-0.31.0.tar.gz`; npm verifier passed; the wheel installed into a fresh venv and imported `headroom._core`. - Not tested: Full GitHub Actions release matrix and publish jobs with real PyPI/npm/GitHub Packages credentials. ## Review Readiness - [x] I have performed a self-review - [x] This PR is ready for human review ## Checklist - [x] My code follows the project's style guidelines - [x] I have performed a self-review of my code - [ ] I have commented my code, particularly in hard-to-understand areas - [x] I have made corresponding changes to the documentation - [x] My changes generate no new warnings - [x] I have added tests that prove my fix is effective or that my feature works - [x] New and existing unit tests pass locally with my changes - [ ] I have updated the CHANGELOG.md if applicable ## Screenshots (if applicable) N/A. ## Additional Notes The post-merge full smoke initially failed because the OpenClaw source package depended on `headroom-ai@^0.31.0`, which is not available on public npm yet. The builder now installs OpenClaw against the just-built local SDK tarball before build/pack, and then rewrites packed metadata to `^0.31.0`. --------- Co-authored-by: JerrettDavis <mxjerrett@gmail.com> Co-authored-by: Tejas Chopra <chopratejas@gmail.com>
2026-07-14 22:07:34 +02:00
update_openclaw_package_json(args.root / "plugins" / "openclaw" / "package.json", version)
fix: publish headroom-opencode in release workflow (#2372) ## Description `headroom-opencode` is documented as an npm package, but the release workflow never published it, so installs failed with a registry 404 even though the plugin source already lived under `plugins/opencode`. This wires the existing package into the npm release path, keeps its version synced with root releases, and adds release guards for the new package. Closes #76. ## Type of Change - [x] Bug fix (non-breaking change that fixes an issue) - [ ] New feature (non-breaking change that adds functionality) - [ ] Breaking change (fix or feature that would cause existing functionality to change) - [x] Documentation update - [ ] Performance improvement - [ ] Code refactoring (no functional changes) ## Changes Made - added `headroom-opencode` to the npm release workflow, including release-version stamping and `headroom-ai` dependency rewrite before publish - added `plugins/opencode/package.json` to release-please and local version-sync guards - synced the source opencode package version to the current release line and documented the new npm package in the release docs - added focused release workflow and version-sync tests for the opencode package - aligned the two failing dashboard Playwright tests with the current Session/Lifetime split and `/stats-lifetime` fixture contract ## Testing - [x] Unit tests pass (`uv run pytest scripts/tests/test_version_sync.py -q`, `uv run pytest tests/test_release_workflows.py -q -k 'publish_npm_rewrites_opencode_dependency_after_version_and_before_publish or opencode_source_dependency_matches_lockfile_registry_range or release_please_manifest_config_consistency'`) - [x] Unit tests pass (`uv run pytest tests/test_dashboard_cache_lifetime_playwright.py tests/test_dashboard_cache_ttl_playwright.py -q`) - [x] Linting passes (`uv run ruff check scripts/verify-versions.py scripts/version-sync.py scripts/tests/test_version_sync.py tests/test_release_workflows.py`) - [ ] Type checking passes (`uv run mypy headroom`) - [x] New tests added for new functionality when applicable - [x] Manual testing performed ### Test Output ```text $ uv run pytest scripts/tests/test_version_sync.py -q 8 passed, 1 warning in 0.51s $ uv run pytest tests/test_release_workflows.py -q -k 'publish_npm_rewrites_opencode_dependency_after_version_and_before_publish or opencode_source_dependency_matches_lockfile_registry_range or release_please_manifest_config_consistency' 2 passed, 38 deselected, 1 warning in 0.07s $ uv run pytest tests/test_dashboard_cache_lifetime_playwright.py tests/test_dashboard_cache_ttl_playwright.py -q 4 passed, 1 warning in 4.04s $ uv run ruff check scripts/verify-versions.py scripts/version-sync.py scripts/tests/test_version_sync.py tests/test_release_workflows.py All checks passed! $ npm ci && npm run build (plugins/opencode) Build success; dist/index.js, dist/entry.opencode.js, and DTS outputs emitted ``` ## Real Behavior Proof - Environment: Windows, Python 3.11.15, Node v24.15.0, npm 11.16.0 - Exact command / steps: inspected `.github/workflows/release.yml`, updated the npm publish path for `plugins/opencode`, aligned the two failing dashboard Playwright tests with the current Session/Lifetime split, then ran the focused pytest commands above plus `npm ci && npm run build` in `plugins/opencode` - Observed result: the release workflow now versions and publishes `headroom-opencode`, release-please and version-sync track `plugins/opencode/package.json`, the dashboard tests now fetch durable cache and setup-url data from the Lifetime view, and the opencode package still builds locally from source - Not tested: GitHub Package Registry publish ## Review Readiness - [x] I have performed a self-review - [x] This PR is ready for human review ## Checklist - [x] My code follows the project's style guidelines - [x] I have performed a self-review of my code - [x] I have commented my code, particularly in hard-to-understand areas - [x] I have made corresponding changes to the documentation - [x] My changes generate no new warnings - [x] I have added tests that prove my fix is effective or that my feature works - [x] New and existing unit tests pass locally with my changes - [x] I have updated the CHANGELOG.md if applicable ## Additional Notes `CHANGELOG.md` is unchanged because release-please owns changelog generation here. --------- Co-authored-by: JD Davis <mxjerrett@gmail.com>
2026-08-12 00:56:40 -04:00
update_opencode_package_json(args.root / "plugins" / "opencode" / "package.json", version)
update_package_json(args.root / "sdk" / "typescript" / "package.json", version)
update_plugin_versions(args.root, version)
fix(release): sync generated version metadata on the release branch (#2659) ## Description The 0.33.0 release PR (#2339) has sat in `changes-requested` since 2026-07-17. Root cause: **release-please only rewrites `pyproject.toml` and its configured `extra-files`**, but other tracked files also carry the version — and `server.json` is asserted byte-for-byte against `render_server_json()`, which derives its version from `pyproject.toml`. So the bump alone fails `tests/test_mcp_registry/test_server_json.py::test_root_server_json_matches_builder` (the `test (2)` shard) on every regenerated release PR. Nothing in the repo regenerated `server.json` at all, so it fell behind every release. Unblocks #2339. ### Why the release *build* passes but the release PR does not `release.yml` already runs `scripts/version-sync.py` immediately before its own `verify-versions.py` gate (lines 145 and 278). That is why `build` and `build-wheels` are green on #2339 despite the drift — it syncs in the workspace, uncommitted. The regular CI test job does **not** sync, so the fix has to be committed to the branch. This also explains why reviewers kept seeing `verify-versions.py` fail locally while CI's build jobs passed: the verifier is never run un-synced inside `release.yml`. ## Type of Change - [x] Bug fix (non-breaking change that fixes an issue) - [ ] New feature (non-breaking change that adds functionality) - [ ] Breaking change (fix or feature that would cause existing functionality to change) - [ ] Documentation update - [ ] Performance improvement - [ ] Code refactoring (no functional changes) ## Changes Made - **`scripts/version-sync.py`**: also write `server.json`. It was the one version-carrying file with no writer anywhere. Values are rewritten in place so key order and formatting keep matching the builder's byte-for-byte output (verified: the file is pure ASCII and round-trips exactly through `json.dumps(..., indent=2) + "\n"`). - **`.github/workflows/release-metadata-sync.yml`** (new): on a push to `release-please--branches--**`, run version-sync → gate on verify-versions → commit if changed. - **Keyed off the branch push** because release-please force-regenerates that branch on every merge to main. That is precisely what wiped the hand-pushed metadata fixes on #2339 (`2a86c8ff`, `d5ea4dc5`) — a push trigger re-heals after every regeneration instead of being lost. - **Uses the same PAT as `release-please.yml`**: a `GITHUB_TOKEN` push does not trigger workflows, so the release PR's checks would never re-run against the synced commit and would stay red. - **Idempotent**: the self-triggered rerun finds no diff and exits before pushing, so the loop terminates after one no-op run. - **Corrected pre-existing drift on `main`**: the agent-hooks plugin manifests, both marketplace manifests, and `.releasemetadata` were stranded at **0.31.0** — never bumped for 0.32.0 either. `verify-versions.py` now passes on `main`. ### Why not more `extra-files` entries That would need ~13 jsonpath entries restating what `version-sync.py` already knows, and a jsonpath that fails to match **fails silently** — the same class of failure this PR removes, discoverable only after a real release PR regenerates. There is also no precedent for nested jsonpath (`$.packages[0].version`, `$.metadata.version`) in the config today; both existing entries are plain `$.version`. Running the script keeps one source of truth, and files added to it later are covered with no change here. ## Testing - [x] Unit tests pass (`pytest`) - [x] Linting passes (`ruff check .`) - [ ] Type checking passes (`mypy headroom`) — no `headroom/` sources touched - [x] New tests added for new functionality - [x] Manual testing performed ### Test Output ```text $ python -m pytest scripts/tests/ tests/test_release_workflows.py tests/test_mcp_registry/ -q 207 passed in 2.69s $ ruff check scripts/version-sync.py scripts/tests/test_version_sync.py tests/test_release_workflows.py All checks passed! $ ruff format --check <same> 3 files already formatted $ actionlint .github/workflows/release-metadata-sync.yml (clean) ``` New tests: - `test_server_json_version_is_synchronized` — version-sync moves both `server.json` version fields and preserves the other keys. - `test_release_metadata_sync_runs_on_release_please_branch` — asserts the trigger, the sync→verify→commit ordering, the no-op guard, and the PAT. - `test_version_sync_covers_every_file_the_verifier_gates` — guards `version-sync.py` and `verify-versions.py` against drifting apart again, which is the root cause here. ## Real Behavior Proof - **Environment:** macOS (Darwin arm64), Python 3.12, repo venv. - **Exact command / steps:** reproduced the CI failure locally by simulating release-please's partial bump, then applying the fix. **Reproducing the exact `test (2)` failure** — set `pyproject` to 0.33.0 while `server.json` stays at 0.32.0, as release-please leaves it: ```text $ python -m pytest tests/test_mcp_registry/test_server_json.py -q FAILED tests/test_mcp_registry/test_server_json.py::test_root_server_json_matches_builder 1 failed, 3 passed ``` **After `version-sync.py`:** ```text $ python scripts/version-sync.py && python -m pytest tests/test_mcp_registry/test_server_json.py -q 4 passed ``` **Both gates green on a simulated 0.33.0 bump:** ```text $ python scripts/version-sync.py --version 0.33.0 Version synchronized to 0.33.0 $ python scripts/verify-versions.py All versions aligned at 0.33.0 $ python -m pytest tests/test_mcp_registry/test_server_json.py -q 4 passed ``` **Idempotency** (the property the workflow's loop-termination relies on): re-running against an already-synced tree leaves `pyproject.toml`, `server.json`, `openclaw`, and `sdk/typescript` untouched. - **Not tested:** the workflow has not executed on a real release-please branch regeneration — that can only be exercised once this is on `main` and release-please next updates #2339. The PAT push path and the self-trigger no-op are reasoned from `release-please.yml`'s existing token comment and from local idempotency, not observed in CI. ## Review Readiness - [x] I have performed a self-review - [x] This PR is ready for human review ## Checklist - [x] My code follows the project's style guidelines - [x] I have performed a self-review of my code - [x] I have commented my code, particularly in hard-to-understand areas - [ ] I have made corresponding changes to the documentation - [x] My changes generate no new warnings - [x] I have added tests that prove my fix is effective or that my feature works - [x] New and existing unit tests pass locally with my changes - [x] I did **not** edit `CHANGELOG.md` ## Additional Notes **Context on the v0.32.0 release failure, since it is easy to misread as "images never build".** Every artifact built for v0.32.0 — all 5 wheel platforms including Windows, all 16 Docker builds + 8 manifests + `promote-latest`, npm, and GitHub Packages. Only `publish-pypi` failed (PyPI attestations, already fixed by `f9cbdd6e` / #2405), and `create-release` was skipped because it depends on it. That is why the release looked like it produced nothing. **Separate, approaching blocker — not addressed here.** PyPI is at **9.69 GB of its 10 GB project cap (96.9%)**, leaving ~305 MB against ~68 MB per release, so roughly 4 more releases fit. The `0.21.x` series alone holds **6.58 GB across 31 releases**, from the old every-push-is-a-release era; pruning it would reclaim two thirds of the quota. Worth a separate issue. **`.releasemetadata` is written but never read** by anything outside `version-sync.py` and its test. It is kept in sync here for internal consistency, but it may be a deletion candidate.
2026-07-29 15:12:04 -07:00
update_server_json(args.root / "server.json", version)
write_release_metadata(args.root, version)
print(f"Version synchronized to {version}")
if __name__ == "__main__":
main()