feat(skills): store immutable plugin upstream snapshots

This commit is contained in:
2026-06-16 11:42:46 +08:00
parent 41b45e0423
commit 094dde0b81
5 changed files with 386 additions and 4 deletions

View File

@ -0,0 +1,48 @@
"""Same-filesystem staging for plugin skill writes."""
from __future__ import annotations
import filecmp
import os
from pathlib import Path
import shutil
from uuid import uuid4
class PluginSkillTransaction:
def __init__(self, workspace: str | Path) -> None:
self.workspace = Path(workspace)
self.transaction_id = uuid4().hex
self.root = self.workspace / ".beaver" / "staging" / "plugin-skills" / self.transaction_id
self.root.mkdir(parents=True, exist_ok=True)
def stage_upstream_snapshot(self, skill_name: str, source_id: str, tree_hash: str) -> Path:
path = self.root / "upstreams" / skill_name / source_id / tree_hash
path.mkdir(parents=True, exist_ok=True)
return path
def stage_skill_version(self, skill_name: str, version: str) -> Path:
path = self.root / "versions" / skill_name / version
path.mkdir(parents=True, exist_ok=True)
return path
def promote_directory(self, staged: Path, final: Path) -> None:
if final.exists():
if _directories_identical(staged, final):
return
raise ValueError(f"Immutable directory already exists with different content: {final}")
final.parent.mkdir(parents=True, exist_ok=True)
os.replace(staged, final)
def cleanup(self) -> None:
shutil.rmtree(self.root, ignore_errors=True)
def _directories_identical(left: Path, right: Path) -> bool:
comparison = filecmp.dircmp(left, right)
if comparison.left_only or comparison.right_only or comparison.funny_files:
return False
for filename in comparison.common_files:
if not filecmp.cmp(left / filename, right / filename, shallow=False):
return False
return all(_directories_identical(left / name, right / name) for name in comparison.common_dirs)