arti-pack

A Neovim plugin manager that installs plugins from an artifact repository instead of git. It downloads tagged upstream source archives over HTTP and unpacks them into Neovim's native package path — see :h packages.

It works with any HTTP artifact repository that serves an upstream tag archive at a stable URL — a JFrog Artifactory remote GitHub repository, or any caching proxy with the same path shape. Nothing is cloned, no git binary is needed, and the editor never has to reach GitHub: every plugin arrives as a cached, immutable, versioned artifact from the same store your builds already pull from.

Requirements

  • Neovim 0.10+
  • curl, and unzip (or tar when using ext = 'tar.gz')

Install

Each tag is published as a source zip under the same tag-archive path shape arti-pack expects, so it installs the same way as everything it manages — mirror it into your own artifact repository and fetch it from there:

curl -fsSL -o /tmp/arti-pack.zip \
  https://artifacts.example.com/artifactory/nvim-plugins/unkin/arti-pack/archive/refs/tags/v0.1.0.zip
mkdir -p "${XDG_DATA_HOME:-$HOME/.local/share}/nvim/site/pack/arti-pack/start"
unzip -q /tmp/arti-pack.zip -d /tmp/arti-pack
mv /tmp/arti-pack/arti-pack-0.1.0 \
  "${XDG_DATA_HOME:-$HOME/.local/share}/nvim/site/pack/arti-pack/start/arti-pack"

Once installed it can carry itself, since url bypasses the registry:

{
  'unkin/arti-pack',
  tag = 'v0.1.0',
  url = 'https://artifacts.example.com/artifactory/nvim-plugins/unkin/arti-pack/archive/refs/tags/v0.1.0.zip',
}

Usage

require('arti-pack').setup({
  registry = 'https://artifacts.example.com/artifactory/github-remote',
  plugins = {
    { 'nvim-lua/plenary.nvim', tag = 'v0.1.4' },
    { 'folke/which-key.nvim',  tag = 'v3.13.3', opt = true },
    { 'folke/tokyonight.nvim', tag = 'v4.10.0', as = 'tokyonight' },
    { 'tpope/vim-fugitive',    tag = 'v3.7',    ext = 'tar.gz' },
  },
})

registry is required and has no default: it is the URL prefix your own artifact repository serves upstream tag archives under, so there is no sensible value to ship. It must be an http:// or https:// URL; surrounding whitespace is trimmed and anything else is rejected. Until you set it, :ArtiPackSync refuses to run and says so:

[arti-pack] registry is not configured; set it in require('arti-pack').setup{ registry = 'https://artifacts.example.com/artifactory/github-remote' }

:ArtiPackClean and :ArtiPackList never resolve a URL, so they work without it, as do plugins that carry an explicit url.

Every plugin needs an explicit tag — that is the point. Plugins install to stdpath('data')/site/pack/arti-pack/start/<name>, or .../opt/<name> when opt = true.

Spec fields

Field Default Meaning
[1] required owner/repo
tag required Upstream tag, used verbatim in the archive path
opt false Install under opt/ for :packadd instead of start/
as repo name Directory name to install as
ext 'zip' zip or tar.gz
url — Full archive URL, bypassing the registry (no whitespace)

Options

Option Default Meaning
registry required Archive URL prefix placed in front of owner/repo
auto_sync true Sync missing and changed plugins on startup
concurrency 4 Plugins downloaded in parallel
timeout 120 Per-download timeout in seconds

Commands

Command Effect
:ArtiPackSync Install missing plugins and update ones whose tag changed
:ArtiPackSync! Reinstall everything, ignoring recorded state
:ArtiPackClean Remove installed plugins no longer in the spec
:ArtiPackList Show every configured plugin and its state

How it resolves an archive

<registry>/<owner>/<repo>/archive/refs/tags/<tag>.<ext>

which for the example above is

https://artifacts.example.com/artifactory/github-remote/nvim-lua/plenary.nvim/archive/refs/tags/v0.1.4.zip

That is GitHub's own tag-archive path shape, so a remote repository proxying github.com resolves it unchanged.

Archives are cached under stdpath('cache')/arti-pack, checked for a real zip or gzip magic header before being trusted, and unpacked into a staging directory. Tag archives wrap their contents in a single <repo>-<version> directory, which is stripped on the way in. Installed tags are recorded in stdpath('data')/arti-pack/lock.json, so a sync with nothing to do costs nothing. Helptags are regenerated per plugin after install.

A failed plugin is reported and skipped; the rest of the run continues.

Tests

make test
S
Description
Neovim plugin manager that installs plugins from tagged archives in an HTTP artifact repository into nvim's native package path
Readme 256 KiB
Languages
Lua 97.7%
Makefile 2.3%