read_snapshot.py file-level

at sha256:c · View file ↗ · Intel ↗

History
1 files
1 commits
0 hotspots
0 🧊 dead
0 💥 blast risk
sha256:c docs(KD-STAGING): sync governance after KD-6b DONE Mirror workspace go… · aaronrene · Jul 10, 2026
1 """muse plumbing read-snapshot — emit full snapshot metadata as JSON.
2
3 Reads a snapshot record by its SHA-256 ID and emits the complete JSON
4 representation including the file manifest.
5
6 Output::
7
8 {
9 "snapshot_id": "<sha256>",
10 "created_at": "2026-03-18T12:00:00+00:00",
11 "file_count": 3,
12 "manifest": {
13 "tracks/drums.mid": "<sha256>",
14 "tracks/bass.mid": "<sha256>",
15 "tracks/piano.mid": "<sha256>"
16 }
17 }
18
19 Plumbing contract
20 -----------------
21
22 - Exit 0: snapshot found and printed.
23 - Exit 1: snapshot not found or invalid snapshot ID format.
24
25 Agent use
26 ---------
27
28 Skip the manifest when you only need metadata::
29
30 muse plumbing read-snapshot <id> --no-manifest
31 # → {"snapshot_id": "...", "created_at": "...", "file_count": 3}
32
33 Filter to a path prefix to avoid pulling the full manifest::
34
35 muse plumbing read-snapshot <id> --path-prefix src/
36 """
37
38 from __future__ import annotations
39
40 import argparse
41 import json
42 import logging
43 import sys
44 from typing import TypedDict
45
46 from muse.core.errors import ExitCode
47 from muse.core.repo import require_repo
48 from muse.core.store import read_snapshot
49 from muse.core.validation import validate_object_id
50 from muse.core._types import Manifest
51
52 logger = logging.getLogger(__name__)
53
54 _FORMAT_CHOICES = ("json", "text")
55
56
57 class _SnapshotOutput(TypedDict, total=False):
58 snapshot_id: str
59 created_at: str
60 file_count: int
61 manifest: Manifest
62
63
64 def register(subparsers: "argparse._SubParsersAction[argparse.ArgumentParser]") -> None:
65 """Register the read-snapshot subcommand."""
66 parser = subparsers.add_parser(
67 "read-snapshot",
68 help="Emit full snapshot metadata and manifest as JSON.",
69 description=__doc__,
70 formatter_class=argparse.RawDescriptionHelpFormatter,
71 )
72 parser.add_argument(
73 "snapshot_id",
74 help="SHA-256 snapshot ID (64 hex chars).",
75 )
76 parser.add_argument(
77 "--no-manifest",
78 action="store_true",
79 dest="no_manifest",
80 help=(
81 "Omit the file manifest from JSON output. "
82 "Returns only snapshot_id, created_at, and file_count — "
83 "ideal for agents doing metadata-only queries."
84 ),
85 )
86 parser.add_argument(
87 "--path-prefix", "-p",
88 default=None,
89 dest="path_prefix",
90 metavar="PREFIX",
91 help="Filter manifest to paths starting with PREFIX.",
92 )
93 parser.add_argument(
94 "--format", "-f",
95 dest="fmt",
96 default="json",
97 metavar="FORMAT",
98 help="Output format: json (default) or text.",
99 )
100 parser.add_argument(
101 "--json", action="store_const", const="json", dest="fmt",
102 help="Shorthand for --format json.",
103 )
104 parser.set_defaults(func=run)
105
106
107 def run(args: argparse.Namespace) -> None:
108 """Emit full snapshot metadata as JSON (default) or a compact text summary.
109
110 A snapshot holds the complete file manifest (path → object_id mapping)
111 for a point in time. Every commit references exactly one snapshot.
112 Use ``muse plumbing ls-files --commit <id>`` if you want to look up a
113 snapshot from a commit ID rather than the snapshot ID directly.
114
115 Use ``--no-manifest`` for lightweight metadata queries.
116 Use ``--path-prefix`` to scope the manifest to a subtree.
117
118 Text format (``--format text``)::
119
120 <snapshot_id[:12]> <file_count> files <created_at>
121 """
122 fmt: str = args.fmt
123 snapshot_id: str = args.snapshot_id
124 no_manifest: bool = args.no_manifest
125 path_prefix: str | None = args.path_prefix
126
127 if fmt not in _FORMAT_CHOICES:
128 print(
129 json.dumps({"error": f"Unknown format {fmt!r}. Valid: {', '.join(_FORMAT_CHOICES)}"}),
130 file=sys.stderr,
131 )
132 raise SystemExit(ExitCode.USER_ERROR)
133
134 if no_manifest and fmt == "text":
135 print(
136 json.dumps({"error": "--no-manifest is only valid with --format json"}),
137 file=sys.stderr,
138 )
139 raise SystemExit(ExitCode.USER_ERROR)
140
141 if path_prefix is not None and fmt == "text":
142 print(
143 json.dumps({"error": "--path-prefix is only valid with --format json"}),
144 file=sys.stderr,
145 )
146 raise SystemExit(ExitCode.USER_ERROR)
147
148 try:
149 validate_object_id(snapshot_id)
150 except ValueError as exc:
151 print(json.dumps({"error": f"Invalid snapshot ID: {exc}"}), file=sys.stderr)
152 raise SystemExit(ExitCode.USER_ERROR)
153
154 root = require_repo()
155
156 record = read_snapshot(root, snapshot_id)
157 if record is None:
158 print(json.dumps({"error": f"Snapshot not found: {snapshot_id}"}), file=sys.stderr)
159 raise SystemExit(ExitCode.USER_ERROR)
160
161 if fmt == "text":
162 print(
163 f"{record.snapshot_id[:12]} {len(record.manifest)} files "
164 f"{record.created_at.isoformat()}"
165 )
166 return
167
168 manifest = record.manifest
169 if path_prefix is not None:
170 manifest = {p: oid for p, oid in manifest.items() if p.startswith(path_prefix)}
171
172 output: _SnapshotOutput = {
173 "snapshot_id": record.snapshot_id,
174 "created_at": record.created_at.isoformat(),
175 "file_count": len(manifest),
176 }
177 if not no_manifest:
178 output["manifest"] = manifest
179
180 print(json.dumps(output, indent=2))