pacm

pacm

C++ package manager for distributing native extensions, model files, and binary assets. Async downloads, SHA-256 verification, SDK version locking, atomic installation.

C++20libuvHTTPSHA-256ZIP

Pacm is a C++ package manager for distributing native extensions, model files, and binary assets to applications at runtime. Remote package querying, versioned downloads with mirror fallback, SHA-256 checksum verification, atomic multi-phase installation, SDK version locking, and install-time extension metadata. Built on libuv for async IO, so installations don’t block your application.

How it works

The package lifecycle has three phases and a state machine that prevents partial-write disasters:

  Remote Index                Local State              Filesystem
       |                          |                        |
  queryRemotePackages()     loadLocalPackages()            |
       |                          |                        |
       v                          v                        |
  RemotePackage[]           LocalPackage[]                 |
       |                          |                        |
       +--- getPackagePairs() ----+                        |
       |                                                   |
       v                                                   |
  InstallTask                                              |
    Downloading -----> tmp/package-1.0.0.zip               |
    Extracting  -----> tmp/extracted/                      |
    Finalizing  -----> install/package-name/      <-- atomic move
    Installed   -----> data/package-name.json     <-- manifest

Downloading fetches the archive from remote mirrors with progress callbacks. Extracting decompresses to a staging directory with path traversal protection; no zip bomb can write outside the target. Finalizing atomically moves files to the install directory. If any phase fails, previous phases are still intact. No partial installations, no corrupted state.

Package definitions

Packages live as JSON on any HTTP server; your own CDN, GitHub releases, S3. Each package declares versioned assets with platform-specific binaries:

{
    "id": "vision-plugin",
    "name": "Vision Plugin",
    "type": "Plugin",
    "author": "0state",
    "description": "OpenCV-based image processing plugin",
    "assets": [
        {
            "version": "2.1.0",
            "sdk-version": "3.0.0",
            "platform": "linux",
            "file-name": "vision-2.1.0-linux.zip",
            "file-size": 4521984,
            "checksum": "a1b2c3...",
            "mirrors": [
                {"url": "https://cdn.example.com/vision-2.1.0-linux.zip"},
                {"url": "https://backup.example.com/vision-2.1.0-linux.zip"}
            ]
        }
    ]
}

Platform detection is automatic. Asset selection picks the right binary for the OS. Mirror fallback means a CDN outage doesn’t break installations.

Manifests can also describe how an installed payload should be used after it lands on disk: loader (graft), runtime (native or worker), entrypoint path, ABI version, and capability tags. That keeps delivery concerns in Pacm while still giving the host enough metadata to bind the installed extension cleanly.

Version intelligence

  • SDK version locking - latestSDKAsset(sdkVersion) returns the newest asset compatible with the running application’s SDK version
  • Version pinning - setVersionLock(version) freezes a package at a specific release, ignoring newer versions
  • Update detection - hasAvailableUpdates() compares local manifests against remote, respecting both locks

A plugin compiled against SDK 2.x might crash with SDK 3.x internals. Pacm checks this before replacing a working plugin with an incompatible one.

PackageManager pm(options);
pm.initialize();
pm.queryRemotePackages();

// Only install what's compatible
auto pairs = pm.getUpdatablePackagePairs();
pm.updatePackages(ids, &monitor);

monitor.Complete += [](LocalPackageVec& packages) {
    for (auto& pkg : packages)
        loadPlugin(pkg->getInstalledFilePath("lib/plugin.so"));
};

Batch operations

The InstallMonitor coordinates multiple concurrent installations with aggregate progress:

InstallMonitor monitor;
pm.installPackages({"plugin-a", "plugin-b", "model-data"}, &monitor);

monitor.Progress += [](int& percent) {
    updateProgressBar(percent);  // 0-100 across all tasks
};

monitor.InstallStateChange += [](auto& task, auto& from, auto& to) {
    log("Package {} moved from {} to {}", task.name(), from, to);
};

monitor.Complete += [](auto& packages) {
    // All done - load plugins, apply models
};

Individual tasks emit their own progress. The monitor aggregates. Your UI gets a single percentage without tracking individual downloads.

Security

Every installation verifies before finalizing:

  • Checksum validation - SHA-256 (or MD5 for legacy) against the declared hash. Mismatch aborts the install
  • Path traversal protection - validatePathComponent() rejects .., absolute paths, and path separators in archive entries. No zip file can write outside its target directory
  • Manifest verification - after extraction, every declared file is checked for existence. Missing files fail the install
  • Authentication - OAuth bearer tokens or HTTP basic auth for private repositories
  • TLS - all HTTP traffic over SSL with certificate verification

With Graft

Pacm and Graft form a complete native-extension delivery path. Pacm handles the logistics: query, download, verify, extract, install. Graft handles the runtime boundary: open the shared library, validate the manifest, bind the typed entrypoint.

  1. Host your compiled plugins as versioned ZIP archives on any HTTP server
  2. Pacm queries the index, downloads the right platform binary, verifies the checksum
  3. Application resolves the installed extension.entrypoint and loads it through Graft
  4. Manifest and ABI validation catch mismatches before they become segfaults
  5. Updates check SDK compatibility before replacing a working plugin with an incompatible one

The same pipeline works for any binary asset; machine learning models, shader files, data bundles, configuration packages. Versioned distribution with integrity verification.