Skip to content

Commit 51bb7fc

Browse files
authored
Merge pull request #23 from lfglabs-dev/fricoben/npm-native-binaries
feat(cli): switch to npm optional dependencies for native binaries
2 parents e8c04b0 + 12cc809 commit 51bb7fc

6 files changed

Lines changed: 212 additions & 290 deletions

File tree

Lines changed: 86 additions & 92 deletions
Original file line numberDiff line numberDiff line change
@@ -1,162 +1,156 @@
11
---
22
name: publish-cli
33
description: >
4-
CLI publishing workflow using GitHub releases for binaries and local npm publish.
5-
Trigger terms: publish, release, npm, cli, version, tag, github actions,
6-
vibetracking, package, deploy cli.
4+
CLI publishing workflow using npm optional dependencies for native binaries.
5+
CI builds binaries, you publish locally via npm.
6+
Trigger terms: publish, release, npm, cli, version, tag, vibetracking, package, deploy cli.
77
---
88

99
## When to Use
1010

1111
- Publishing a new version of the CLI to npm
12-
- Checking the release workflow
13-
- Understanding the hybrid publishing model
12+
- Understanding the npm optional dependencies publishing model
13+
- Checking the build workflow
1414

15-
## Architecture: Hybrid Publishing
15+
## Architecture: npm Optional Dependencies
1616

17-
The CLI uses a hybrid publishing approach:
17+
The CLI uses the npm optional dependencies pattern (same as esbuild, swc, prisma):
1818

19-
| Component | Host | Description |
20-
|-----------|------|-------------|
21-
| `vibetracking` | npm | CLI JavaScript wrapper (you publish locally) |
22-
| Native binaries | GitHub Releases | `.node` files for each platform |
19+
| Component | Location | Description |
20+
|-----------|----------|-------------|
21+
| `vibetracking` | npm | CLI JavaScript package |
22+
| `@starknetid/vibetracking-core` | npm | Main core package with optional deps |
23+
| `@starknetid/vibetracking-core-*` | npm | 7 platform-specific binary packages |
2324

24-
**Why?** This simplifies publishing to 1 npm package instead of 9, avoiding npm OIDC/auth issues.
25+
**How it works**: When a user runs `npm install vibetracking`, npm automatically installs only the platform-specific binary package that matches their OS/arch.
2526

26-
**How it works**: On first run, the CLI downloads the correct native binary from GitHub releases to `~/.vibetracking/bin/{version}/`.
27+
## Existing npm Packages
28+
29+
These packages already exist on npm - we publish new versions to them:
30+
31+
- `@starknetid/vibetracking-core` - Main package
32+
- `@starknetid/vibetracking-core-darwin-arm64` - macOS ARM64
33+
- `@starknetid/vibetracking-core-darwin-x64` - macOS Intel
34+
- `@starknetid/vibetracking-core-darwin-universal` - macOS Universal
35+
- `@starknetid/vibetracking-core-linux-x64-gnu` - Linux x64
36+
- `@starknetid/vibetracking-core-linux-arm64-gnu` - Linux ARM64
37+
- `@starknetid/vibetracking-core-win32-x64-msvc` - Windows x64
38+
- `@starknetid/vibetracking-core-win32-arm64-msvc` - Windows ARM64
2739

2840
## Procedure: Publish a New Version
2941

3042
### Step 1: Update Version Numbers
3143

32-
Update version in `packages/cli/package.json`:
33-
```json
34-
{
35-
"version": "X.Y.Z"
36-
}
44+
Use the napi version command to sync all package versions:
45+
46+
```bash
47+
cd packages/core
48+
pnpm napi version -p X.Y.Z
3749
```
3850

39-
Update `BINARY_VERSION` constant in:
40-
- `packages/cli/src/native.ts`
41-
- `packages/cli/src/native-runner.ts`
51+
This updates:
52+
- `packages/core/package.json`
53+
- All `packages/core/npm/*/package.json` files
4254

43-
```typescript
44-
const BINARY_VERSION = "X.Y.Z";
55+
Also update CLI version manually:
56+
```bash
57+
# Edit packages/cli/package.json
58+
# Change "version": "X.Y.Z"
4559
```
4660

47-
### Step 2: Commit and Push
61+
### Step 2: Commit and Push Tag
4862

4963
```bash
50-
git add packages/cli/
51-
git commit -m "chore: bump CLI version to X.Y.Z"
64+
git add .
65+
git commit -m "chore: bump version to X.Y.Z"
5266
git push origin main
67+
68+
# Create and push tag to trigger CI build
69+
git tag cli-vX.Y.Z
70+
git push origin cli-vX.Y.Z
5371
```
5472

55-
### Step 3: Create and Push Tag
73+
### Step 3: Wait for CI Build
5674

57-
**IMPORTANT**: Create the tag AFTER pushing the version bump to main. The tag must point to the commit with the updated version and workflow.
75+
GitHub Actions will build native binaries for all 7 platforms (~10-15 minutes).
5876

77+
Monitor progress:
5978
```bash
60-
git tag cli-vX.Y.Z
61-
git push origin cli-vX.Y.Z
79+
gh run watch --exit-status
6280
```
6381

64-
### Step 4: Wait for CI and Verify Release
65-
66-
GitHub Actions will:
67-
1. Build native binaries for all 6 platforms
68-
2. Create universal macOS binary
69-
3. Upload all binaries to GitHub Release
82+
### Step 4: Download Artifacts
7083

71-
Monitor progress: `gh run watch <RUN_ID> --exit-status`
84+
Once CI completes, download the built binaries:
7285

73-
**Before proceeding**: Verify binaries were uploaded:
7486
```bash
75-
gh release view cli-vX.Y.Z --json assets --jq '.assets[].name'
87+
# Get the run ID from the CLI or GitHub UI
88+
gh run download <RUN_ID> -D ./artifacts
7689
```
7790

78-
You should see 7 `.node` files (6 platforms + 1 universal macOS).
91+
### Step 5: Publish All Packages
7992

80-
### Step 5: Publish CLI to npm (Locally)
81-
82-
Once CI completes and binaries are verified, publish from your local machine:
93+
Run the publish script:
8394

8495
```bash
85-
cd packages/cli
86-
pnpm build
87-
npm publish --access public
96+
./scripts/publish-all.sh
8897
```
8998

90-
**Note**: npm will prompt for OTP (one-time password) from your authenticator app.
99+
This script:
100+
1. Copies binaries to their package directories
101+
2. Publishes all 7 platform packages
102+
3. Publishes the main core package
103+
4. Builds and publishes the CLI package
104+
105+
**Note**: You'll be prompted for npm OTP if 2FA is enabled on your account.
91106

92107
### Step 6: Verify
93108

94109
```bash
95-
# Check npm
110+
# Check npm registry
96111
npm view vibetracking versions
97112

98-
# Test fresh install (should download binary)
99-
rm -rf ~/.vibetracking/bin
113+
# Test fresh install
100114
bunx vibetracking@X.Y.Z --version
101115
```
102116

103117
## Workflow Configuration
104118

105119
- **File**: `.github/workflows/release.yml`
106-
- **Trigger**: Push tags matching `cli-v*`
107-
- **Output**: Native binaries uploaded to GitHub Release
120+
- **Trigger**: Push tags matching `cli-v*` or manual dispatch
121+
- **Output**: Build artifacts (downloaded locally for publishing)
122+
123+
## Version Synchronization
108124

109-
### Manual Trigger (Dry Run)
125+
All these must match:
126+
- `packages/cli/package.json` version
127+
- `packages/core/package.json` version
128+
- All `packages/core/npm/*/package.json` versions
110129

111-
Test the build without uploading:
112-
1. Go to Actions > Release CLI
113-
2. Click "Run workflow"
114-
3. Check "Dry run" option
130+
The `napi version` command syncs the core packages automatically.
115131

116-
## Native Binary Locations
132+
## Troubleshooting
117133

118-
Binaries are downloaded to `~/.vibetracking/bin/{version}/`:
134+
### CI Build Failed
119135

120-
| Platform | Binary Name |
121-
|----------|-------------|
122-
| macOS Intel | `vibetracking-core.darwin-x64.node` |
123-
| macOS ARM | `vibetracking-core.darwin-arm64.node` |
124-
| Linux x64 | `vibetracking-core.linux-x64-gnu.node` |
125-
| Linux ARM64 | `vibetracking-core.linux-arm64-gnu.node` |
126-
| Windows x64 | `vibetracking-core.win32-x64-msvc.node` |
127-
| Windows ARM64 | `vibetracking-core.win32-arm64-msvc.node` |
136+
Check the GitHub Actions logs. Common issues:
137+
- Rust toolchain version
138+
- Cross-compilation toolchain missing
128139

129-
## User Installation
140+
### npm Publish Failed
130141

131-
After publishing, users can install with:
142+
If a version already exists on npm:
132143
```bash
133-
bunx vibetracking # One-off execution (downloads binary on first run)
134-
bun add -g vibetracking # Global install
144+
npm view @starknetid/vibetracking-core versions
135145
```
136146

137-
## Troubleshooting
138-
139-
### CI Failed / Tag Points to Old Workflow
147+
Bump to the next version if needed.
140148

141-
If the release workflow fails or you need to recreate a tag:
149+
### Binary Not Loading
142150

151+
Check that the correct platform package was installed:
143152
```bash
144-
# Delete tag locally and remotely
145-
git tag -d cli-vX.Y.Z
146-
git push origin :refs/tags/cli-vX.Y.Z
147-
148-
# Create new tag on current main
149-
git tag cli-vX.Y.Z origin/main
150-
git push origin cli-vX.Y.Z
153+
npm ls @starknetid/vibetracking-core
151154
```
152155

153-
### npm Version Already Exists but Tarball is 404
154-
155-
If `npm view vibetracking versions` shows a version but `bunx vibetracking@X.Y.Z` fails with 404, the version was corrupted. Bump to next patch version (e.g., 0.2.0 → 0.2.1).
156-
157-
### Binary Download Fails
158-
159-
Check that:
160-
1. GitHub release exists: `gh release view cli-vX.Y.Z`
161-
2. Repo is public (private repos require auth for release downloads)
162-
3. `GITHUB_REPO` in `native.ts` matches the actual repo name
156+
Should show the platform-specific package as an optional dependency.

.github/workflows/release.yml

Lines changed: 27 additions & 71 deletions
Original file line numberDiff line numberDiff line change
@@ -1,25 +1,10 @@
1-
name: Release CLI
1+
name: Build CLI Binaries
22

33
on:
44
push:
55
tags:
66
- 'cli-v*'
77
workflow_dispatch:
8-
inputs:
9-
dry_run:
10-
description: 'Dry run (skip GitHub release upload)'
11-
required: false
12-
default: false
13-
type: boolean
14-
skip_build:
15-
description: 'Skip build (reuse artifacts from previous run)'
16-
required: false
17-
default: false
18-
type: boolean
19-
run_id:
20-
description: 'Run ID to download artifacts from (required if skip_build is true)'
21-
required: false
22-
type: string
238

249
env:
2510
DEBUG: napi:*
@@ -31,7 +16,6 @@ permissions:
3116

3217
jobs:
3318
build:
34-
if: ${{ github.event.inputs.skip_build != 'true' }}
3519
strategy:
3620
fail-fast: false
3721
matrix:
@@ -94,7 +78,6 @@ jobs:
9478
if-no-files-found: error
9579

9680
build-universal-macos:
97-
if: ${{ github.event.inputs.skip_build != 'true' }}
9881
name: Build - universal-apple-darwin
9982
needs: build
10083
runs-on: macos-latest
@@ -133,71 +116,44 @@ jobs:
133116
path: packages/core/*.node
134117
if-no-files-found: error
135118

136-
upload-release:
137-
name: Upload to GitHub Release
119+
summary:
120+
name: Build Summary
138121
runs-on: ubuntu-latest
139122
needs:
140123
- build
141124
- build-universal-macos
142-
if: ${{ always() && (github.event.inputs.skip_build == 'true' || (needs.build.result == 'success' && needs.build-universal-macos.result == 'success')) }}
125+
if: ${{ needs.build.result == 'success' && needs.build-universal-macos.result == 'success' }}
143126

144127
steps:
145128
- uses: actions/checkout@v4
146129

147-
- name: Download artifacts from current run
148-
if: ${{ github.event.inputs.skip_build != 'true' }}
149-
uses: actions/download-artifact@v4
150-
with:
151-
path: artifacts
152-
pattern: bindings-*
153-
merge-multiple: true
154-
155-
- name: Download artifacts from previous run
156-
if: ${{ github.event.inputs.skip_build == 'true' }}
157-
uses: actions/download-artifact@v4
158-
with:
159-
path: artifacts
160-
pattern: bindings-*
161-
merge-multiple: true
162-
github-token: ${{ secrets.GITHUB_TOKEN }}
163-
run-id: ${{ github.event.inputs.run_id }}
164-
165-
- name: List artifacts
166-
run: ls -la artifacts/
167-
168-
- name: Get tag name
169-
id: tag
130+
- name: Get version
131+
id: version
170132
run: |
171-
if [[ "${{ github.ref_type }}" == "tag" ]]; then
172-
echo "name=${{ github.ref_name }}" >> $GITHUB_OUTPUT
173-
else
174-
# For manual runs, use the version from package.json
175-
VERSION=$(jq -r .version packages/cli/package.json)
176-
echo "name=cli-v${VERSION}" >> $GITHUB_OUTPUT
177-
fi
178-
179-
- name: Create or update GitHub Release
180-
if: ${{ github.event.inputs.dry_run != 'true' }}
181-
uses: softprops/action-gh-release@v2
182-
with:
183-
tag_name: ${{ steps.tag.outputs.name }}
184-
name: CLI ${{ steps.tag.outputs.name }}
185-
files: artifacts/*.node
186-
fail_on_unmatched_files: true
187-
generate_release_notes: true
188-
env:
189-
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
133+
VERSION=$(jq -r .version packages/cli/package.json)
134+
echo "version=${VERSION}" >> $GITHUB_OUTPUT
190135
191136
- name: Summary
192137
run: |
193-
echo "## Release ${{ steps.tag.outputs.name }}" >> $GITHUB_STEP_SUMMARY
138+
echo "## Build Complete - v${{ steps.version.outputs.version }}" >> $GITHUB_STEP_SUMMARY
139+
echo "" >> $GITHUB_STEP_SUMMARY
140+
echo "### Artifacts Ready for Download" >> $GITHUB_STEP_SUMMARY
141+
echo "" >> $GITHUB_STEP_SUMMARY
142+
echo "All platform binaries have been built and uploaded as artifacts." >> $GITHUB_STEP_SUMMARY
143+
echo "" >> $GITHUB_STEP_SUMMARY
144+
echo "### Next Steps (Local Publishing)" >> $GITHUB_STEP_SUMMARY
194145
echo "" >> $GITHUB_STEP_SUMMARY
195-
echo "### Binaries uploaded to GitHub Release" >> $GITHUB_STEP_SUMMARY
146+
echo "1. Download artifacts:" >> $GITHUB_STEP_SUMMARY
147+
echo " \`\`\`bash" >> $GITHUB_STEP_SUMMARY
148+
echo " gh run download ${{ github.run_id }} -D ./artifacts" >> $GITHUB_STEP_SUMMARY
149+
echo " \`\`\`" >> $GITHUB_STEP_SUMMARY
196150
echo "" >> $GITHUB_STEP_SUMMARY
197-
ls -1 artifacts/*.node | while read f; do
198-
echo "- $(basename $f)" >> $GITHUB_STEP_SUMMARY
199-
done
151+
echo "2. Run publish script:" >> $GITHUB_STEP_SUMMARY
152+
echo " \`\`\`bash" >> $GITHUB_STEP_SUMMARY
153+
echo " ./scripts/publish-all.sh" >> $GITHUB_STEP_SUMMARY
154+
echo " \`\`\`" >> $GITHUB_STEP_SUMMARY
200155
echo "" >> $GITHUB_STEP_SUMMARY
201-
echo "### Next Steps" >> $GITHUB_STEP_SUMMARY
202-
echo "1. Publish CLI to npm locally: \`cd packages/cli && npm publish --access public\`" >> $GITHUB_STEP_SUMMARY
203-
echo "2. Verify: \`bunx vibetracking@latest --version\`" >> $GITHUB_STEP_SUMMARY
156+
echo "3. Verify installation:" >> $GITHUB_STEP_SUMMARY
157+
echo " \`\`\`bash" >> $GITHUB_STEP_SUMMARY
158+
echo " bunx vibetracking@${{ steps.version.outputs.version }} --version" >> $GITHUB_STEP_SUMMARY
159+
echo " \`\`\`" >> $GITHUB_STEP_SUMMARY

packages/cli/package.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,7 @@
3232
"prepublishOnly": "bun run build"
3333
},
3434
"dependencies": {
35+
"@starknetid/vibetracking-core": "0.2.0",
3536
"clipboardy": "^5.0.2",
3637
"commander": "^14.0.2",
3738
"csv-parse": "^5.6.0",

0 commit comments

Comments
 (0)