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.
- codex_preserve/__init__.py +11 -0
- codex_preserve/__main__.py +8 -0
- codex_preserve/cli.py +103 -0
- codex_preserve/exporter.py +6239 -0
- codex_preserve/verify.py +502 -0
- codex_preserve-0.1.0.dist-info/METADATA +241 -0
- codex_preserve-0.1.0.dist-info/RECORD +11 -0
- codex_preserve-0.1.0.dist-info/WHEEL +5 -0
- codex_preserve-0.1.0.dist-info/entry_points.txt +2 -0
- codex_preserve-0.1.0.dist-info/licenses/LICENSE +202 -0
- codex_preserve-0.1.0.dist-info/top_level.txt +1 -0
|
@@ -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"
|
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())
|