From ee179cdf287eab900d9292e1468c357d6669be27 Mon Sep 17 00:00:00 2001 From: Max Ghenis Date: Wed, 22 Jul 2026 10:56:12 -0400 Subject: [PATCH] Repin integrity shims to receipt 0.2.0 --- .github/workflows/ci.yml | 2 +- .github/workflows/thesis-facts-append.yml | 4 +- README.md | 4 +- pyproject.toml | 2 +- scripts/canonical_json.py | 6 +- scripts/check_thesis_facts_append.py | 40 ++++----- scripts/{vidimus_pins.py => receipt_pins.py} | 6 +- scripts/verify_release_chain.py | 90 +++++++++---------- ...y.py => test_receipt_shim_transparency.py} | 4 +- tests/test_thesis_append_adversarial.py | 2 +- uv.lock | 28 +++--- 11 files changed, 94 insertions(+), 94 deletions(-) rename scripts/{vidimus_pins.py => receipt_pins.py} (94%) rename tests/{test_vidimus_shim_transparency.py => test_receipt_shim_transparency.py} (98%) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index f86c6ab..665b004 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -21,7 +21,7 @@ jobs: github.event_name == 'push' && github.ref == 'refs/heads/codex/thesis-ledger-facts' # Runs in the repo's hash-locked env: the verifier may import - # packaged dependencies (vidimus) once the consumption shims land. + # packaged dependencies (receipt) once the consumption shims land. run: | uv sync --locked --no-dev uv run --locked --no-dev python scripts/verify_release_chain.py --full diff --git a/.github/workflows/thesis-facts-append.yml b/.github/workflows/thesis-facts-append.yml index 35bdc5e..81cdac2 100644 --- a/.github/workflows/thesis-facts-append.yml +++ b/.github/workflows/thesis-facts-append.yml @@ -97,7 +97,7 @@ jobs: # Provision the BASE commit's own hash-locked environment and run # the base gate with it: the gate scripts may import packaged - # dependencies (vidimus), and installing from the base's uv.lock + # dependencies, and installing from the base's uv.lock # keeps the PR unable to influence what code judges it. uv sync --locked --no-dev --project "$base_gate" @@ -139,7 +139,7 @@ jobs: test "$(git -C "$base_gate" rev-parse HEAD)" = "$base_sha" # Base gate runs from the BASE commit's own hash-locked env so - # gate imports (vidimus) resolve without the PR influencing them. + # gate dependencies resolve without the PR influencing them. uv sync --locked --no-dev --project "$base_gate" cd "$RUNNER_TEMP" diff --git a/README.md b/README.md index 6e7b8da..d65fb10 100644 --- a/README.md +++ b/README.md @@ -567,8 +567,8 @@ The `codex/thesis-ledger-facts` branch carries an append-only, externally witnessed observation ledger: every append lands with a chained release manifest, dual RFC 3161 receipts, and an Ed25519 producer signature, verified by a gate that runs from the base commit's hash-locked -environment. Verification machinery is consumed from the `vidimus` +environment. Verification machinery is consumed from the `receipt` package with this repository's trust pins committed in -`scripts/vidimus_pins.py`; see `releases/README.md` (immutable +`scripts/receipt_pins.py`; see `releases/README.md` (immutable post-genesis, like everything under `releases/`) for the schema, offline verification procedure, and security limits. diff --git a/pyproject.toml b/pyproject.toml index 65dd055..cfd606c 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -24,7 +24,7 @@ dependencies = [ "odfpy>=1.4.1", "xlrd>=2.0.1", "pypdf>=6.0.0", - "vidimus==0.1.2", + "receipt==0.2.0", ] [project.optional-dependencies] diff --git a/scripts/canonical_json.py b/scripts/canonical_json.py index 259a4e3..064aa6a 100644 --- a/scripts/canonical_json.py +++ b/scripts/canonical_json.py @@ -1,10 +1,10 @@ #!/usr/bin/env python3 -# Thin shim over vidimus==0.1.2 (hash-pinned in uv.lock). Any vidimus upgrade +# Thin shim over receipt==0.2.0 (hash-pinned in uv.lock). Any receipt upgrade # requires a fresh byte-equivalence proof at this repo's then-current pin BEFORE # the bump. -"""Canonical JSON compatibility surface backed by vidimus.""" +"""Canonical JSON compatibility surface backed by receipt.""" -from vidimus.canonical import ( +from receipt.canonical import ( canonical_bytes, canonical_sha256, canonical_stringify, diff --git a/scripts/check_thesis_facts_append.py b/scripts/check_thesis_facts_append.py index 773bbfd..ee1dd3c 100644 --- a/scripts/check_thesis_facts_append.py +++ b/scripts/check_thesis_facts_append.py @@ -1,5 +1,5 @@ #!/usr/bin/env python3 -# Thin shim over vidimus==0.1.2 (hash-pinned in uv.lock). Any vidimus upgrade +# Thin shim over receipt==0.2.0 (hash-pinned in uv.lock). Any receipt upgrade # requires a fresh byte-equivalence proof at this repo's then-current pin BEFORE # the bump. """Gate every change to the thesis-facts observation ledger.""" @@ -11,17 +11,17 @@ import sys from typing import Any -import vidimus.append_gate as _vidimus -from vidimus.release_chain import MANIFEST_RE, ReleaseChainError +import receipt.append_gate as _receipt +from receipt.release_chain import MANIFEST_RE, ReleaseChainError try: - from vidimus_pins import APPEND_GATE_SPEC, LEDGER_SPEC + from receipt_pins import APPEND_GATE_SPEC, LEDGER_SPEC except ModuleNotFoundError as exc: - if exc.name != "vidimus_pins": + if exc.name != "receipt_pins": raise # The test suite copies the legacy three-script surface into temporary # repositories. The editable consumer tree remains the sole pin owner. - from scripts.vidimus_pins import APPEND_GATE_SPEC, LEDGER_SPEC + from scripts.receipt_pins import APPEND_GATE_SPEC, LEDGER_SPEC CODE_ROOT = pathlib.Path(__file__).resolve().parents[1] @@ -34,9 +34,9 @@ DATA_SURFACE = APPEND_GATE_SPEC.data_surface ASSERTION_CONTENT_KEYS = APPEND_GATE_SPEC.assertion_content_keys -AppendError = _vidimus.AppendError -AppendGateSpec = _vidimus.AppendGateSpec -reject_non_append_bytes = _vidimus.reject_non_append_bytes +AppendError = _receipt.AppendError +AppendGateSpec = _receipt.AppendGateSpec +reject_non_append_bytes = _receipt.reject_non_append_bytes def _set_root(root: pathlib.Path) -> None: @@ -49,39 +49,39 @@ def _set_root(root: pathlib.Path) -> None: def _candidate() -> Any: - return _vidimus._set_root(ROOT, APPEND_GATE_SPEC) + return _receipt._set_root(ROOT, APPEND_GATE_SPEC) def check_surface_separation(base_ref: str) -> tuple[set[str], set[str]]: - return _vidimus.check_surface_separation(base_ref, _candidate()) + return _receipt.check_surface_separation(base_ref, _candidate()) def expected_assertion_version_id(row: dict[str, Any]) -> str: - return _vidimus.expected_assertion_version_id(row, APPEND_GATE_SPEC) + return _receipt.expected_assertion_version_id(row, APPEND_GATE_SPEC) def effective_current_rows( rows: list[dict[str, Any]], ) -> list[dict[str, Any]]: - return _vidimus.effective_current_rows(rows, APPEND_GATE_SPEC) + return _receipt.effective_current_rows(rows, APPEND_GATE_SPEC) def check_prefix(lines: list[str]) -> dict[str, Any]: - return _vidimus.check_prefix(lines, _candidate()) + return _receipt.check_prefix(lines, _candidate()) def check_rows(lines: list[str], prefix_count: int) -> None: - return _vidimus.check_rows(lines, prefix_count, APPEND_GATE_SPEC) + return _receipt.check_rows(lines, prefix_count, APPEND_GATE_SPEC) def check_append_only(base_ref: str, lines: list[str]) -> int: - return _vidimus.check_append_only(base_ref, lines, _candidate()) + return _receipt.check_append_only(base_ref, lines, _candidate()) def check_prefix_anchored_to_base( base_ref: str, candidate_prefix: dict[str, Any] ) -> int: - return _vidimus.check_prefix_anchored_to_base( + return _receipt.check_prefix_anchored_to_base( base_ref, candidate_prefix, _candidate(), @@ -94,7 +94,7 @@ def check_release_proposal( anchor_dir: pathlib.Path | None = None, enforce_production_pins: bool | None = None, ) -> int | None: - return _vidimus.check_release_proposal( + return _receipt.check_release_proposal( base_ref, candidate=_candidate(), anchor_dir=anchor_dir, @@ -107,7 +107,7 @@ def check_release_chain_without_base( anchor_dir: pathlib.Path | None = None, enforce_production_pins: bool | None = None, ) -> int | None: - return _vidimus.check_release_chain_without_base( + return _receipt.check_release_chain_without_base( candidate=_candidate(), anchor_dir=anchor_dir, enforce_production_pins=enforce_production_pins, @@ -121,7 +121,7 @@ def verify_append_gate( trusted_code_root: pathlib.Path = CODE_ROOT, release_anchor_dir: pathlib.Path | None = None, ) -> str: - return _vidimus.verify_append_gate( + return _receipt.verify_append_gate( root, spec=APPEND_GATE_SPEC, base_ref=base_ref, diff --git a/scripts/vidimus_pins.py b/scripts/receipt_pins.py similarity index 94% rename from scripts/vidimus_pins.py rename to scripts/receipt_pins.py index 49ee590..83d24b6 100644 --- a/scripts/vidimus_pins.py +++ b/scripts/receipt_pins.py @@ -1,11 +1,11 @@ -"""Consumer-owned trust and append-gate configuration for vidimus.""" +"""Consumer-owned trust and append-gate configuration for receipt.""" from __future__ import annotations import pathlib -from vidimus.append_gate import AppendGateSpec -from vidimus.release_chain import AnchorSpec, ChainSpec +from receipt.append_gate import AppendGateSpec +from receipt.release_chain import AnchorSpec, ChainSpec LEDGER_SPEC = ChainSpec( diff --git a/scripts/verify_release_chain.py b/scripts/verify_release_chain.py index fd182ab..2b45afc 100644 --- a/scripts/verify_release_chain.py +++ b/scripts/verify_release_chain.py @@ -1,5 +1,5 @@ #!/usr/bin/env python3 -# Thin shim over vidimus==0.1.2 (hash-pinned in uv.lock). Any vidimus upgrade +# Thin shim over receipt==0.2.0 (hash-pinned in uv.lock). Any receipt upgrade # requires a fresh byte-equivalence proof at this repo's then-current pin BEFORE # the bump. """Offline verification for the witnessed thesis-ledger release chain.""" @@ -12,16 +12,16 @@ from datetime import datetime from typing import Any -import vidimus.release_chain as _vidimus +import receipt.release_chain as _receipt try: - from vidimus_pins import LEDGER_SPEC + from receipt_pins import LEDGER_SPEC except ModuleNotFoundError as exc: - if exc.name != "vidimus_pins": + if exc.name != "receipt_pins": raise # The test suite copies the legacy three-script surface into temporary # repositories. The editable consumer tree remains the sole pin owner. - from scripts.vidimus_pins import LEDGER_SPEC + from scripts.receipt_pins import LEDGER_SPEC ROOT = pathlib.Path(__file__).resolve().parents[1] @@ -34,46 +34,46 @@ PRODUCER_PUBLIC_KEY_FILENAME = LEDGER_SPEC.producer_public_key_filename PRODUCER_SPKI_SHA256 = LEDGER_SPEC.producer_spki_sha256 -CRYPTOGRAPHY_AVAILABLE = _vidimus.CRYPTOGRAPHY_AVAILABLE -DEFAULT_CLOCK_SKEW_SECONDS = _vidimus.DEFAULT_CLOCK_SKEW_SECONDS -MAX_FUTURE_SECONDS = _vidimus.MAX_FUTURE_SECONDS -MAX_RELEASE_INDEX = _vidimus.MAX_RELEASE_INDEX -MANIFEST_RE = _vidimus.MANIFEST_RE -PRODUCER_SIGNATURE_BYTES = _vidimus.PRODUCER_SIGNATURE_BYTES -PRODUCER_SIGNATURE_RE = _vidimus.PRODUCER_SIGNATURE_RE -RECEIPT_RE = _vidimus._receipt_re(LEDGER_SPEC) -SHA256_RE = _vidimus.SHA256_RE -STRICT_UTC_RE = _vidimus.STRICT_UTC_RE -TIME_STAMP_RE = _vidimus.TIME_STAMP_RE - -AnchorSpec = _vidimus.AnchorSpec -ChainSpec = _vidimus.ChainSpec -ChainVerification = _vidimus.ChainVerification -GitEntry = _vidimus.GitEntry -ReleaseChainError = _vidimus.ReleaseChainError -ReleaseRecord = _vidimus.ReleaseRecord - -git_blob_bytes = _vidimus.git_blob_bytes -git_file_entry = _vidimus.git_file_entry -git_tree_entries = _vidimus.git_tree_entries -jsonl_line_offsets = _vidimus.jsonl_line_offsets -manifest_filename = _vidimus.manifest_filename -parse_created_at = _vidimus.parse_created_at -producer_signature_path_for_manifest = _vidimus.producer_signature_path_for_manifest -resolve_base_commit = _vidimus.resolve_base_commit -sha256_bytes = _vidimus.sha256_bytes +CRYPTOGRAPHY_AVAILABLE = _receipt.CRYPTOGRAPHY_AVAILABLE +DEFAULT_CLOCK_SKEW_SECONDS = _receipt.DEFAULT_CLOCK_SKEW_SECONDS +MAX_FUTURE_SECONDS = _receipt.MAX_FUTURE_SECONDS +MAX_RELEASE_INDEX = _receipt.MAX_RELEASE_INDEX +MANIFEST_RE = _receipt.MANIFEST_RE +PRODUCER_SIGNATURE_BYTES = _receipt.PRODUCER_SIGNATURE_BYTES +PRODUCER_SIGNATURE_RE = _receipt.PRODUCER_SIGNATURE_RE +RECEIPT_RE = _receipt._receipt_re(LEDGER_SPEC) +SHA256_RE = _receipt.SHA256_RE +STRICT_UTC_RE = _receipt.STRICT_UTC_RE +TIME_STAMP_RE = _receipt.TIME_STAMP_RE + +AnchorSpec = _receipt.AnchorSpec +ChainSpec = _receipt.ChainSpec +ChainVerification = _receipt.ChainVerification +GitEntry = _receipt.GitEntry +ReleaseChainError = _receipt.ReleaseChainError +ReleaseRecord = _receipt.ReleaseRecord + +git_blob_bytes = _receipt.git_blob_bytes +git_file_entry = _receipt.git_file_entry +git_tree_entries = _receipt.git_tree_entries +jsonl_line_offsets = _receipt.jsonl_line_offsets +manifest_filename = _receipt.manifest_filename +parse_created_at = _receipt.parse_created_at +producer_signature_path_for_manifest = _receipt.producer_signature_path_for_manifest +resolve_base_commit = _receipt.resolve_base_commit +sha256_bytes = _receipt.sha256_bytes def validate_manifest_schema(manifest: Any) -> dict[str, Any]: - return _vidimus.validate_manifest_schema(manifest, LEDGER_SPEC) + return _receipt.validate_manifest_schema(manifest, LEDGER_SPEC) def load_manifest(path: pathlib.Path) -> tuple[dict[str, Any], bytes, str]: - return _vidimus.load_manifest(path, LEDGER_SPEC) + return _receipt.load_manifest(path, LEDGER_SPEC) def receipt_paths_for_manifest(path: pathlib.Path) -> dict[str, pathlib.Path]: - return _vidimus.receipt_paths_for_manifest(path, LEDGER_SPEC) + return _receipt.receipt_paths_for_manifest(path, LEDGER_SPEC) def verify_producer_signature_bytes( @@ -84,7 +84,7 @@ def verify_producer_signature_bytes( enforce_production_pin: bool, label: str, ) -> None: - return _vidimus.verify_producer_signature_bytes( + return _receipt.verify_producer_signature_bytes( manifest, signature, spec=LEDGER_SPEC, @@ -101,7 +101,7 @@ def verify_producer_signature( anchor_dir: pathlib.Path, enforce_production_pin: bool, ) -> None: - return _vidimus.verify_producer_signature( + return _receipt.verify_producer_signature( manifest, signature_path, spec=LEDGER_SPEC, @@ -119,7 +119,7 @@ def verify_receipt( enforce_production_pins: bool, now: datetime | None = None, ) -> datetime: - return _vidimus.verify_receipt( + return _receipt.verify_receipt( manifest_digest, receipt, tsa, @@ -141,7 +141,7 @@ def verify_release_receipts( previous_times: dict[str, datetime] | None = None, now: datetime | None = None, ) -> dict[str, datetime]: - return _vidimus.verify_release_receipts( + return _receipt.verify_release_receipts( manifest, manifest_digest, receipt_paths, @@ -165,7 +165,7 @@ def verify_release_chain( clock_skew_seconds: int = DEFAULT_CLOCK_SKEW_SECONDS, now: datetime | None = None, ) -> ChainVerification: - return _vidimus.verify_release_chain( + return _receipt.verify_release_chain( root, spec=LEDGER_SPEC, anchor_dir=anchor_dir, @@ -181,7 +181,7 @@ def verify_release_chain( def verify_release_history_immutable( root: pathlib.Path, base_ref: str ) -> tuple[str, set[str], dict[str, GitEntry]]: - return _vidimus.verify_release_history_immutable(root, base_ref, LEDGER_SPEC) + return _receipt.verify_release_history_immutable(root, base_ref, LEDGER_SPEC) def materialize_base_tree( @@ -190,7 +190,7 @@ def materialize_base_tree( destination: pathlib.Path, release_entries: dict[str, GitEntry], ) -> None: - return _vidimus.materialize_base_tree( + return _receipt.materialize_base_tree( root, commit, destination, @@ -208,7 +208,7 @@ def verify_base_release_chain( enforce_production_pins: bool = True, clock_skew_seconds: int = DEFAULT_CLOCK_SKEW_SECONDS, ) -> ChainVerification: - return _vidimus.verify_base_release_chain( + return _receipt.verify_base_release_chain( root, commit, release_entries, @@ -272,7 +272,7 @@ def main() -> int: return 0 head = verification.releases[-1] receipt_summary = ", ".join( - f"{tsa}={_vidimus._format_time(value)}" + f"{tsa}={_receipt._format_time(value)}" for tsa, value in sorted(head.receipt_times.items()) ) print( diff --git a/tests/test_vidimus_shim_transparency.py b/tests/test_receipt_shim_transparency.py similarity index 98% rename from tests/test_vidimus_shim_transparency.py rename to tests/test_receipt_shim_transparency.py index 468d0c0..e5b6b27 100644 --- a/tests/test_vidimus_shim_transparency.py +++ b/tests/test_receipt_shim_transparency.py @@ -1,4 +1,4 @@ -"""Byte-level differential tests for the vidimus consumer shims.""" +"""Byte-level differential tests for the receipt consumer shims.""" from __future__ import annotations @@ -57,7 +57,7 @@ def test_original_oracle_fixtures_are_authenticated(name: str) -> None: def original_oracle(tmp_path_factory: pytest.TempPathFactory) -> pathlib.Path: """Copy the authenticated original scripts into one executable tree.""" - oracle = tmp_path_factory.mktemp("vidimus-original-oracle") + oracle = tmp_path_factory.mktemp("receipt-original-oracle") scripts = oracle / "scripts" scripts.mkdir() for name, expected in ORIGINAL_HASHES.items(): diff --git a/tests/test_thesis_append_adversarial.py b/tests/test_thesis_append_adversarial.py index e97406b..c91aa6e 100644 --- a/tests/test_thesis_append_adversarial.py +++ b/tests/test_thesis_append_adversarial.py @@ -656,7 +656,7 @@ def test_manifest_extension_cannot_grandfather_an_unbound_append(tmp_path): def test_binding_pair_presence_and_shape_are_enforced( tmp_path, mutation, expected_error ): - # Found during the vidimus extraction review: bool(row.get(...)) treated + # Found during the package extraction review: bool(row.get(...)) treated # falsy-but-present binding values as absent, silently waiving the # contract binding for a row that claims to grade a registered target. lines = _read_lines() diff --git a/uv.lock b/uv.lock index 214f9e6..2c5e1de 100644 --- a/uv.lock +++ b/uv.lock @@ -1652,10 +1652,10 @@ dependencies = [ { name = "pyarrow" }, { name = "pypdf" }, { name = "pyyaml" }, + { name = "receipt" }, { name = "scipy" }, { name = "sqlmodel" }, { name = "supabase" }, - { name = "vidimus" }, { name = "xlrd" }, ] @@ -1687,11 +1687,11 @@ requires-dist = [ { name = "pypdf", specifier = ">=6.0.0" }, { name = "pytest", marker = "extra == 'dev'", specifier = ">=8.0.0,<9" }, { name = "pyyaml", specifier = ">=6.0" }, + { name = "receipt", specifier = "==0.2.0" }, { name = "ruff", marker = "extra == 'dev'", specifier = ">=0.5.0" }, { name = "scipy", specifier = ">=1.11.0" }, { name = "sqlmodel", specifier = ">=0.0.22" }, { name = "supabase", specifier = ">=2.0.0" }, - { name = "vidimus", specifier = "==0.1.2" }, { name = "xlrd", specifier = ">=2.0.1" }, ] provides-extras = ["dev", "policyengine"] @@ -2325,6 +2325,18 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/c1/35/e9d9c8b7aa4a11df18bb0e4e5d135d5d1236eb500e922bf68f41da30bdef/realtime-2.27.0-py3-none-any.whl", hash = "sha256:3a7444116ebed9b6a497d00acc51a3175bbf9819cfcc5c929a2b25ad9b7ddba6", size = 22139, upload-time = "2025-12-16T14:48:34.838Z" }, ] +[[package]] +name = "receipt" +version = "0.2.0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "cryptography" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/9e/d5/ee2efdb0903a37ecd389d344e4822e0ff03b0fda79bc3a801a83dd84d777/receipt-0.2.0.tar.gz", hash = "sha256:41ef973355cf0cc18fdb1f5f78e116a3b95b5b7b27f67f48cb4fcbdd1561448d", size = 65898, upload-time = "2026-07-21T12:45:54.407Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/53/71/9efb03a89f382e5bdf33588bfe38ce04ce992d9c08c46c9c02ac4fc3b9d9/receipt-0.2.0-py3-none-any.whl", hash = "sha256:365b680ebec7e27de108cf990c807f8f45a8e9ccb40801a570c451afdd4aaf7a", size = 32646, upload-time = "2026-07-21T12:45:53.346Z" }, +] + [[package]] name = "requests" version = "2.32.5" @@ -2866,18 +2878,6 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/65/a8/1791660a87f03d10a3bce00401a66035999c91f5a9a6987569b84df5719d/us-3.2.0-py3-none-any.whl", hash = "sha256:571714ad6d473c72bbd2058a53404cdf4ecc0129e4f19adfcbeb4e2d7e3dc3e7", size = 13775, upload-time = "2024-07-22T01:09:41.432Z" }, ] -[[package]] -name = "vidimus" -version = "0.1.2" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "cryptography" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/e9/4b/83079ebfa8a96e47e73743b7a7f7d18ca6e7d41b8ef99d94a57e6da44cab/vidimus-0.1.2.tar.gz", hash = "sha256:ef0f798ecea994ce8796358442c046ddd77a9f7fc5608ca1bf35f9aa73a05b3f", size = 58045, upload-time = "2026-07-20T17:17:16.793Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/b8/0d/fa474cfbd58439eacd8268d2d956c7440667b1b67252188c20454f17607c/vidimus-0.1.2-py3-none-any.whl", hash = "sha256:f6662a73b31bb7c67b038b7179680c48de93c368ad2d9fd0bcde34fd3f6841ba", size = 28938, upload-time = "2026-07-20T17:17:15.392Z" }, -] - [[package]] name = "wcwidth" version = "0.6.0"