0.19.0

Released 2026-09-29

Added

  • viv php install [VERSION] downloads a self-contained PHP build from static-php-cli's bulk bundle (Linux and macOS, x86_64 and aarch64, intl included) into the store and pins it as config.platform.php; viv php list shows the builds in the cache. Upstream publishes no checksums, so viv records its own sha256 on first download and refuses plain-http downloads (#337, #339)
  • viv run <name> falls through from a scripts entry to vendor/bin/<name> to a command on PATH, with the pinned PHP's directory first on PATH for run, exec and every script the runner spawns, so @php and a plain php hit the pinned build. A pinned build that is not in the cache is installed on first use, with one line on stderr; --offline keeps the error (#338)

Changed

  • viv run, viv exec and viv x take one trailing command: everything after the name belongs to the tool, so viv run php -v no longer loses -v to viv's own --verbose. viv's flags go before the name (viv run -d ../app phpunit); one leading -- after the name is dropped, as Composer's run-script test -- --filter idiom expects (#338)
  • The composer/installers, johnpbloch/wordpress-core-installer, roots/wordpress-core-installer, drupal/core-composer-scaffold and cweagans/composer-patches adapters read their rules from TOML files embedded in the binary (src/plugins/data/), parsed once per process; the mechanics stay in Rust and the output is unchanged. docs/plugin-strategy.md says when a plugin is a data file and when it needs an adapter (#340, #341, #342)

Fixed

  • The solve uses the same root version as Composer's RootPackageLoader: an explicit version, then COMPOSER_ROOT_VERSION, then the git guess (a tag at HEAD, else dev-<branch>), then 1.0.0; before, only installed.php guessed and the solve always took 1.0.0, so a self.version require resolved differently (#312)

Research

  • Generation 3, five candidates measured (#329 to #333); docs/research.md "Generation 3". 3.1 managed PHP toolchain: holds, built (above). 3.2 per-plugin isolation: 46 of the 100 most popular WordPress.org plugins bundle vendor/, 5% of bundled copies are prefixed, and the real collisions (Guzzle 6 against 7, Monolog 1 against 2, php-jwt 5 against 6) sit in plugin zips; not built until a count on Composer-managed sites says how often the site's own copy meets a bundled one (#330). 3.4 installs that run no code: 25 of the 40 most-downloaded Composer plugins are declarable as data, 16 of 20 corpus projects run code at install; holds, built as the adapters-as-data change above (#332). 3.5 simpler resolution rules: the unused features caused no bugs and the bug-prone ones (repositories, replace, branch-alias) are used by most projects; not built (#333). 3.3 a lock that pins commits: over the 52 client merges chapter 1 left to a person, pinning dev-* records by commit with the later commit winning finishes 37 of 52 with no person (21 of them with no network), leaves 1 real conflict and 14 that the registry no longer serves at all; chapter 1's floor of 51 unfinished merges falls to 15; holds, build decision open (#331)