core-agent-ide/codex-rs/package-manager/README.md
2026-03-05 13:02:30 +00:00

3.3 KiB

codex-package-manager

codex-package-manager is the shared installer used for versioned runtime bundles and other cached artifacts in codex-rs.

It owns the generic parts of package installation:

  • current-platform detection
  • manifest and archive fetches
  • checksum and archive-size validation
  • archive extraction for .zip and .tar.gz
  • staging and promotion into a versioned cache directory
  • cross-process install locking

Package-specific code stays behind the ManagedPackage trait.

Model

The package manager is intentionally small:

  1. A ManagedPackage implementation describes how to fetch a manifest, choose an archive for a PackagePlatform, and load a validated installed package from disk.
  2. PackageManager::resolve_cached() returns a cached install for the current platform if load_installed() succeeds and the version matches.
  3. PackageManager::ensure_installed() acquires a per-install lock, downloads the archive into a staging directory, extracts it, validates the staged package, and promotes it into the cache.

The default cache root is:

<codex_home>/<default_cache_root_relative>

Callers can override that root with PackageManagerConfig::with_cache_root(...).

ManagedPackage Contract

The trait is small, but the invariants matter:

  • install_dir() should be unique per package version and platform. If two versions or two platforms share a directory, promotion and cleanup become unsafe.
  • load_installed() must fully validate the installed package, not just deserialize a manifest. resolve_cached() trusts a successful load as a valid cache hit.
  • The default detect_extracted_root() looks for manifest.json at the extraction root or inside a single top-level directory. Override it if your package layout differs.
  • archive_url() should be derived from manifest data, not recomputed from unrelated caller state, so manifest selection and download stay aligned.

Consumer Guidance

  • If your feature can install on demand, do not gate feature registration on a preinstalled-cache check alone. resolve_cached() only answers "is it already present?" while ensure_installed() is the bootstrap path.
  • Keep cache-root overrides inside your manager/config surface. Separate helpers that reconstruct install paths can drift from PackageManagerConfig.
  • Prefer surfacing package-specific validation failures from load_installed() when debugging. The generic manager treats failed cache loads as cache misses today.

Security and Extraction Rules

  • .zip extraction rejects entries that escape the extraction root and preserves Unix executable bits when the archive carries them.
  • .tar.gz extraction rejects symlinks, hard links, sparse files, device files, and FIFOs. Only regular files and directories are promoted.
  • The archive SHA-256 is always verified, and size_bytes is enforced when present in the manifest.

Extending It

Typical usage looks like this:

let config = PackageManagerConfig::new(codex_home, MyPackage::new(...));
let manager = PackageManager::new(config);

let package = manager.ensure_installed().await?;

In practice, most packages should expose their own small wrapper config/manager types over the generic crate so the rest of the codebase does not depend on ManagedPackage details directly.