adapter.py python
115 lines 3.7 KB
Raw
sha256:a78e7e5a8740e03315f325d19edeb3aa1b306b3337d04abbaa9a9e0f3bbeb7a1 docs: MuseHub-first before ISR #74 — staging solidify NEXT Human 2 days ago
1 """Git-only VCS adapter backend (§4)."""
2
3 from __future__ import annotations
4
5 from adapters.base import BaseAdapter
6 from adapters.errors import ReadError, WriteError
7 from adapters.runner import CommandResult
8 from adapters.types import (
9 AnchorResult,
10 CommitResult,
11 HeadResult,
12 MirrorResult,
13 RealignResult,
14 StatusResult,
15 )
16
17
18 class GitOnlyAdapter(BaseAdapter):
19 """Single-history Git backend for external developers."""
20
21 def status(self) -> StatusResult | ReadError:
22 branch_result = self._git("rev-parse", "--abbrev-ref", "HEAD")
23 if isinstance(branch_result, ReadError):
24 return branch_result
25 dirty_result = self._git("status", "--porcelain")
26 if isinstance(dirty_result, ReadError):
27 return dirty_result
28 git_is_dirty = bool(dirty_result.stdout.strip())
29 return StatusResult(
30 regime=self.regime,
31 dirty=git_is_dirty,
32 branch=branch_result.stdout,
33 notes=["canonical=git", "single-history"],
34 muse_dirty=None,
35 git_dirty=git_is_dirty,
36 )
37
38 def read_head(self, ref: str) -> HeadResult | ReadError:
39 if ref.startswith("muse:"):
40 return ReadError(
41 "read_head",
42 "muse refs forbidden in git-only regime",
43 )
44 result = self._git("rev-parse", ref)
45 if isinstance(result, ReadError):
46 return result
47 sha = result.stdout.splitlines()[-1].strip()
48 if not sha:
49 return ReadError(f"git rev-parse {ref}", "empty sha")
50 return HeadResult(sha=sha, kind="git")
51
52 def read_canonical_anchor(self) -> AnchorResult | ReadError:
53 remote = self.config.vcs.git.remote
54 main = self.config.vcs.git.main_branch
55 ref = f"{remote}/{main}"
56 head = self.read_head(ref)
57 if isinstance(head, ReadError):
58 return head
59 return AnchorResult(anchor_sha=head.sha, source=ref)
60
61 def realign(self, *, dry_run: bool, max_commits: int) -> RealignResult:
62 return RealignResult(
63 would_import=0,
64 applied=False,
65 from_ref=None,
66 to_ref=None,
67 reason="single-history",
68 )
69
70 def commit_feature(
71 self,
72 *,
73 branch: str,
74 message: str,
75 paths: list[str],
76 ) -> CommitResult | ReadError | WriteError:
77 unsafe = self._validate_paths(paths)
78 if unsafe:
79 return unsafe
80 if self._is_protected_branch(branch):
81 return WriteError(
82 "commit_feature",
83 f"refused protected branch {branch!r}",
84 )
85
86 # §GSW.6.1: skip checkout when HEAD is already on the branch — the
87 # engine switches before writing docs, so a dirty tree here is normal.
88 current = self._git("rev-parse", "--abbrev-ref", "HEAD")
89 if isinstance(current, ReadError):
90 return current
91 if current.stdout.strip() != branch:
92 checkout = self._git("checkout", branch)
93 if isinstance(checkout, ReadError):
94 return checkout
95
96 if paths:
97 add = self._git("add", "--", *paths)
98 if isinstance(add, ReadError):
99 return add
100
101 commit = self._git("commit", "-m", message)
102 if isinstance(commit, ReadError):
103 return commit
104
105 head = self._git("rev-parse", "HEAD")
106 if isinstance(head, ReadError):
107 return head
108 return CommitResult(committed=True, sha=head.stdout.strip())
109
110 def mirror(self, *, dry_run: bool) -> MirrorResult:
111 return MirrorResult(
112 diff_summary="",
113 pushed=False,
114 reason="single-history",
115 )
File History 2 commits
sha256:a78e7e5a8740e03315f325d19edeb3aa1b306b3337d04abbaa9a9e0f3bbeb7a1 docs: MuseHub-first before ISR #74 — staging solidify NEXT Human 2 days ago
sha256:4671b7f787ddbe63ced31c895b688c77ab495653b65a730b423329f26b3c1439 feat: K1-P1 complete — agent provenance, build-verification… Sonnet 4.6 patch 54 days ago