Skip to content

Give the lilbee npm package the lilbee release version - #1242

Open
tobocop2 wants to merge 12 commits into
feat/agent-npm-pluginfrom
feat/npm-version-follows-lilbee
Open

tobocop2 wants to merge 12 commits into
feat/agent-npm-pluginfrom
feat/npm-version-follows-lilbee

Conversation

@tobocop2

@tobocop2 tobocop2 commented Nov 4, 2026

Copy link
Copy Markdown
Owner

Problem

The npm package lilbee has a version that is not related to lilbee. npm shows 0.6.102, while the lilbee release is 0.6.90b691. The launcher downloads the latest GitHub release at run time, so the npm version does not tell you which lilbee runs. The package now also ships the opencode and pi plugin and the skills, which change with each lilbee release.

One version

Each release now writes the lilbee version into the npm package in semver form: 0.6.90b691 becomes 0.6.90-beta.691. The .N form makes npm compare the beta number as a number, so beta.1000 sorts above beta.691. One script holds this mapping. The release script, the promote script, the promotion check, the publish job and the tests all use it.

The launcher runs the release it pins

With no override, the launcher runs exactly the release in lilbee.release. It no longer looks up the latest release. LILBEE_BIN, LILBEE_RELEASE and npx lilbee prepare <tag> still choose a different binary.

Publishing

The npm job publishes with --tag latest, because npm orders a prerelease below the old 0.6.102. The job stops when the package version does not match the release it publishes. Dev builds do not publish to npm.

Notes

  • Merge after Install lilbee into opencode and pi from the lilbee npm package #1237.
  • The old 0.6.95 to 0.6.102 versions stay on npm. To mark them deprecated: npm deprecate lilbee@"0.6.95 - 0.6.102" "lilbee npm versions now match lilbee releases; install lilbee@latest".
  • The first promotion of a dev tag cut before this change gets new release notes instead of copied ones, because that tag carries the old promotion check.

Both skills now live under plugins/lilbee/skills, the only copy of each.
The wheel maps the lilbee-mcp skill to lilbee/skills/lilbee_mcp with a
hatch force-include, and the single-file binary build copies it from the
same place.

A source checkout does not apply force-include to an editable install,
so the launcher skill copy looks in the installed location first and in
the checkout's plugin directory second. It raises an error that names
both paths when neither holds the skill.
The plugin bundles both skills, the lilbee-worker agent and an MCP entry
that runs lilbee mcp. The marketplace points at plugins/lilbee, so the
install cache holds that directory and not the repository. CI validates
both paths with claude plugin validate --strict.
The lilbee-mcp skill text named the old docs/agent-skills path for the
wiki skill. It now names the plugin directory.
Tie the launcher's installed-skill path, the wheel force-include
destination and the Nuitka data-dir destination to one value in a
test. Read the skill from the frozen binary in the release smoke
test, which the executable check also runs on pull requests that
touch the build tooling.

Pin the Claude Code CLI in the claude-plugin CI job to 2.1.317.

The plugin cache keys on the manifest version. Strict validation
rejects a manifest with no version, so the version stays and
release.sh now sets it to the lilbee release version, with a test
that the two match.
The smoke-step skill check now runs against a fake binary that carries
the skill and three that do not, so removing its exit or changing a
grep pattern turns a test red.

The skill-destination test reads the build script without comments, so
a wrong real flag with the right pair in a comment turns it red.

Two bats tests pin promotion detection: two releases in a row are not a
promotion, and a promoted tag is.
The plugin lives inside the existing npm package lilbee instead of a
second package. opencode loads it from the ./server export and pi reads
the pi key; import "lilbee" still gives the API and the bins are
unchanged. The plugin code under plugin/ and the API under lib/ share
no module.

The skills stay in plugins/lilbee/skills. A copy step runs before pack
and before test and puts them in the ignored skills/ directory of the
package, so no second tracked copy can drift.

The npm version of the package is bumped by a pull request, so the
release and promote scripts stop stamping a plugin package.json. The
separate plugin test job, make target and version-order script go
away; the launcher job runs the plugin tests.

With the plugin package.json gone, a release commit changes only the
files a promotion changes, so two releases in a row looked like a
promotion. The promote script now commits "Promote <v>", and the
promotion check also requires that subject.
The launcher looked up the latest GitHub release at run time and kept
the package's own release only as a fallback. The npm version therefore
said nothing about the lilbee that ran.

With no override the launcher now runs exactly lilbee.release. It reuses
a cached binary only when that binary is of this release, and downloads
the release otherwise. The latest-release lookup, its fallback and the
LILBEE_CHANNEL variable are gone from the launcher. LILBEE_BIN,
LILBEE_RELEASE and an explicit prepare tag still override the pin.

The library API keeps latestRelease, listReleases and ensureBinary for
embedders that have no pinned release.
The npm version was bumped by hand and drifted from lilbee: npm 0.6.102
ran lilbee 0.6.90b691.

One script, scripts/release_version.sh, now owns the mapping from the
PEP 440 version to semver (0.6.90b691 becomes 0.6.90-beta.691, so
semver orders beta.1000 after beta.691) and the list of version files.
release.sh and promote_release.sh stamp package.json, lilbee.release and
package-lock.json with the other version files, and restore the tree if
a file does not take the version. A version with no mapping stops the
release. The promotion detector reads the same file list.

The npm publish job checks out the tag, fails when package.json is not
the npm form of that tag, publishes with --tag latest, and skips dev
builds. The package now carries 0.6.90-beta.691 and v0.6.90b691.
The publish job refuses a package.json that is not the npm form of
the tag. The test runs the job's own script against a scratch
package.json, so a guard that never fails or tests the wrong way
turns the test red. The subprocess calls name utf-8.
A promotion changes every file that release_version.sh lists, not
three. The launcher runs the release that matches the package
version. The manual dispatch example uses a placeholder tag.
The release scripts run on the Linux and macOS runners only. On a Windows
runner, `bash` starts the WSL launcher, which has no distribution
installed, so every call to the version script exits 1. The tests that run
the script now skip on win32, as the publish guard tests already do.
@tobocop2
tobocop2 marked this pull request as ready for review November 4, 2026 23:20
@tobocop2
tobocop2 force-pushed the feat/agent-npm-plugin branch 2 times, most recently from 642b4e4 to b698383 Compare November 5, 2026 10:28

This branch has not been deployed

No deployments
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