Skip to content

Publish allium-lsp to npm on release#54

Closed
yavorpanayotov wants to merge 3 commits into
mainfrom
feat/publish-allium-lsp-npm
Closed

Publish allium-lsp to npm on release#54
yavorpanayotov wants to merge 3 commits into
mainfrom
feat/publish-allium-lsp-npm

Conversation

@yavorpanayotov

@yavorpanayotov yavorpanayotov commented Jun 19, 2026

Copy link
Copy Markdown
Collaborator

What

Makes allium-lsp installable with npm install -g allium-lsp, so editors and the Claude Code plugin (juxt/allium#39) can put the language server on PATH without the manual tarball/source dance.

Why

The plugin wires allium-lsp via lspServers, but there's currently no one-command way to get the binary onto PATH — the documented npm install -g allium-lsp path didn't exist (the name is unpublished). This adds the publish step.

Changes

  • .github/workflows/release-artifacts.yml — new publish-npm job: builds the WASM parser + LSP bundle and runs npm publish --workspace packages/allium-lsp on v* tags. Mirrors publish-crates; gated on tags and on build-and-release (lint + test) passing.
  • packages/allium-lsp/package.json — publish metadata (repository, homepage, bugs, keywords, engines: node >=20, publishConfig.access=public).
  • packages/allium-lsp/README.md + LICENSE — added; both were already listed in files but missing (npm would otherwise publish a bare page with no licence).
  • Docsnpm install -g allium-lsp documented as the recommended path in the README and the generic/Emacs LSP guides.

Why this is safe / self-contained

The package was already publish-ready. Its build copies allium_wasm.js + allium_wasm_bg.wasm into dist/, and the runtime loader resolves the parser via require(__dirname + "/allium_wasm.js") before falling back to the allium-parser-wasm workspace package — so the externalized dependency is a dev-only fallback and the published tarball is self-contained. npm pack --dry-run confirms the layout:

LICENSE  README.md  dist/bin.js  dist/allium_wasm.js  dist/allium_wasm_bg.wasm  package.json

The publish job builds via the exact same npm run --workspace packages/allium-lsp build already used to produce the release tarball, so it's the proven build path plus a publish step.

⚠️ Maintainer setup required (JUXT) — this is greenfield npm publishing

allium-lsp would be JUXT's first npm package. I verified there is no existing npm token to reuse: across the org, no workflow references NPM_TOKEN / NODE_AUTH_TOKEN and nothing runs npm publish (today JUXT ships to crates.io via CARGO_REGISTRY_TOKEN and to the Homebrew tap via HOMEBREW_TAP_TOKEN; the VS Code extension is distributed as a .vsix on Releases). The allium-lsp name is also still unregistered on npm. So someone from JUXT needs to do a one-time setup before the first tagged release — none of it is a code change:

  • Create / decide the npm org that will own the package (e.g. a juxt npm org), or confirm an existing npm account that should own allium-lsp. There is no JUXT npm org in use yet.
  • Claim the allium-lsp name — it's first-come-first-served and currently free. Claiming = publishing the first version (the release workflow does this automatically once the token is in place; or npm publish it once manually to reserve sooner).
  • Create an npm automation/granular token with publish rights for that org/package (automation tokens bypass 2FA, required for CI).
  • Add it as the NPM_TOKEN repo secret on juxt/allium-tools (or as a shared org-level secret). The workflow already references secrets.NPM_TOKEN.

Until the token exists, the publish-npm job fails only at the final publish step; every other job (crates, Homebrew, GitHub release) is unaffected, and the change is otherwise inert. Once set up, pushing a v* tag claims the name and publishes in one go, which then activates the LSP wiring in juxt/allium#48.

Refs juxt/allium#39

🤖 Generated with Claude Code

Add a `publish-npm` job to the release-artifacts workflow that builds the
WASM parser and the LSP bundle, then runs `npm publish` for
packages/allium-lsp on every `v*` tag — mirroring the existing
publish-crates job. Gated on tags and on build-and-release (lint + test)
passing first.

The package was already publish-ready: its build copies allium_wasm.js
and allium_wasm_bg.wasm into dist/, and the runtime loader resolves the
parser via `require(__dirname + "/allium_wasm.js")` before falling back to
the workspace package, so the published tarball is self-contained (Node
>= 20). Add publish metadata (repository, homepage, bugs, keywords,
engines, publishConfig) plus the README.md and LICENSE the `files` list
already referenced but were missing.

Document `npm install -g allium-lsp` as the recommended install path in
the README and the generic/Emacs editor guides.

Requires (maintainer): an NPM_TOKEN repo secret and ownership of the
`allium-lsp` name on npm before the first tagged release.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Skip the publish step when the version is already on the registry, so
re-running a release or pushing a tag without bumping the npm version
doesn't fail the workflow on "cannot publish over previously published
versions".

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@yavorpanayotov

Copy link
Copy Markdown
Collaborator Author

Self-review

Reviewed the diff. Docs and package.json metadata are clean; the publish job scopes the token to only the publish step and gates on build-and-release (lint + test). One operational fix applied, two notes left for discussion.

🔴 Fixed in latest commit — idempotent publish. npm publish exits non-zero if the version already exists, which would fail the entire release run on a re-run or on a tag pushed without bumping the npm version. Added a guard that checks npm view allium-lsp@<version> and skips if already published.

🟡 Optional — npm provenance. Adding permissions: id-token: write + --provenance would give verifiable build attestation for this public package. Happy to add if wanted; left out to keep the first publish simple.

🟢 Note — CI cost. The job recompiles the WASM parser rather than reusing build-and-release's output, because the uploaded artifact is a .tar.gz, not a publishable package layout. Rebuilding is the pragmatic choice (a few extra minutes per release).

Reminder of the two maintainer prerequisites before the first tagged release: add the NPM_TOKEN secret and own the allium-lsp name on npm.

Publish with --provenance and grant the job id-token: write so npm mints
a signed build attestation linking the package to this workflow run.
Set contents: read explicitly since job-level permissions override the
workflow default and checkout needs read access.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@yavorpanayotov

Copy link
Copy Markdown
Collaborator Author

Note: this is a non-blocking convenience PR.

The Claude Code plugin wiring (juxt/allium#48) and all editors already work with the existing release tarball / from-source install, which put allium-lsp on PATH. This PR only makes installation a one-command npm install -g allium-lsp.

It can land on its own timeline once JUXT completes the npm org/token setup described above — #48 does not need to wait for it.

@yavorpanayotov

Copy link
Copy Markdown
Collaborator Author

Closing as won't do for now — intentionally deferred, not rejected.

The motivation for this PR was to unblock the Claude Code plugin's LSP wiring (juxt/allium#48). That turned out to be unnecessary: the plugin only needs allium-lsp on PATH, which the existing release tarball / from-source install already provides. #48 has been merged and works today without npm.

So npm publishing is now a pure convenience (one-command npm install -g vs. unpacking a tarball), and it carries real one-time setup cost — JUXT has no npm org or token today, and allium-lsp would be its first npm package. Not worth taking on right now for the marginal install-UX gain.

If we want to revisit later, the work is captured here and the cleaner long-term direction is probably the standalone binary (#17) + Nix (#16), which would also give a no-Node-runtime install. Leaving the branch feat/publish-allium-lsp-npm in place for reference.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant