codex-preserve 0.1.0__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,11 @@
1
+ """codex-preserve: export Codex sessions to durable files and verify them.
2
+
3
+ The export/verify core lives in :mod:`codex_preserve.exporter`; the installed
4
+ ``codex-preserve`` console command is :func:`codex_preserve.cli.main`.
5
+
6
+ This project is not affiliated with, endorsed by, or certified by OpenAI.
7
+ """
8
+
9
+ __all__ = ["__version__"]
10
+
11
+ __version__ = "0.1.0"
@@ -0,0 +1,8 @@
1
+ """``python -m codex_preserve`` runs the same command as ``codex-preserve``."""
2
+
3
+ import sys
4
+
5
+ from .cli import main
6
+
7
+ if __name__ == "__main__":
8
+ sys.exit(main())
codex_preserve/cli.py ADDED
@@ -0,0 +1,103 @@
1
+ """The ``codex-preserve`` console command.
2
+
3
+ A deliberately thin dispatcher. It owns no parser state: ``export`` hands the
4
+ remaining arguments straight to the existing exporter parser, and ``verify``
5
+ runs one small argparse over the existing integrity primitives.
6
+
7
+ Naming boundary: this command is never installed as ``codex``, and it never
8
+ offers an ``archive`` verb. ``codex archive`` is a different, built-in Codex
9
+ command that changes a saved session's lifecycle state inside Codex.
10
+ """
11
+
12
+ from __future__ import annotations
13
+
14
+ import argparse
15
+ import json
16
+ import sys
17
+ from pathlib import Path
18
+ from typing import List, Optional, Sequence
19
+
20
+ from . import __version__, exporter, verify
21
+
22
+ USAGE = """\
23
+ codex-preserve — export Codex sessions to durable files and verify them.
24
+
25
+ usage:
26
+ codex-preserve [EXPORT OPTIONS] export a session (default surface)
27
+ codex-preserve export [EXPORT OPTIONS] the same export surface, named
28
+ codex-preserve verify PACKAGE_DIR verify one exported package
29
+ codex-preserve --help | --version
30
+
31
+ Export reads one already-persisted local Codex rollout and writes a
32
+ human-readable conversation file, a machine receipt and a manifest into a
33
+ per-session package. The rollout is never modified.
34
+
35
+ Verify re-checks every manifest-attested member of an exported package.
36
+ exit 0 package is intact
37
+ exit 1 a manifest-attested member is missing or altered
38
+ exit 2 the package could not be verified at all (fails closed)
39
+
40
+ Run `codex-preserve export --help` for the full export option list.
41
+
42
+ This is not `codex archive`. This project is not affiliated with, endorsed by,
43
+ or certified by OpenAI.
44
+ """
45
+
46
+ _ARCHIVE_REFUSAL = """\
47
+ codex-preserve has no `%s` command, deliberately.
48
+
49
+ `codex archive` / `codex unarchive` are built-in Codex commands that change a
50
+ saved session's lifecycle state inside Codex. codex-preserve only exports a
51
+ durable copy outside Codex and verifies it.
52
+
53
+ Did you mean `codex-preserve export` or `codex-preserve verify`?
54
+ """
55
+
56
+
57
+ def _verify_main(argv: Sequence[str]) -> int:
58
+ parser = argparse.ArgumentParser(
59
+ prog="codex-preserve verify",
60
+ description="Verify one exported package against its manifest.",
61
+ )
62
+ parser.add_argument("package_dir",
63
+ help="the exported package directory to verify")
64
+ parser.add_argument("--json", action="store_true",
65
+ help="print the machine-readable receipt instead")
66
+ options = parser.parse_args(argv)
67
+
68
+ receipt = verify.verify_package(Path(options.package_dir))
69
+ stream = sys.stdout if receipt["verdict"] == verify.VERDICT_PASS \
70
+ else sys.stderr
71
+ if options.json:
72
+ print(json.dumps(receipt, indent=2, sort_keys=True,
73
+ ensure_ascii=False), file=stream)
74
+ else:
75
+ print(verify.render_human(receipt), file=stream)
76
+ return int(receipt["exit_code"])
77
+
78
+
79
+ def main(argv: Optional[Sequence[str]] = None) -> int:
80
+ args: List[str] = list(sys.argv[1:] if argv is None else argv)
81
+
82
+ if not args or args[0] in ("-h", "--help", "help"):
83
+ sys.stdout.write(USAGE)
84
+ return 0
85
+ if args[0] in ("-V", "--version", "version"):
86
+ print("codex-preserve %s (conversation package schema %s, export "
87
+ "core %s)" % (__version__, exporter.PACKAGE_SCHEMA_VERSION,
88
+ exporter.EXPORTER_VERSION))
89
+ return 0
90
+ if args[0] in ("archive", "unarchive"):
91
+ sys.stderr.write(_ARCHIVE_REFUSAL % args[0])
92
+ return 2
93
+ if args[0] == "verify":
94
+ return _verify_main(args[1:])
95
+ if args[0] == "export":
96
+ return exporter.main(args[1:])
97
+ # Unprefixed invocation stays the export surface, so existing export
98
+ # command lines keep working unchanged.
99
+ return exporter.main(args)
100
+
101
+
102
+ if __name__ == "__main__":
103
+ sys.exit(main())