@lema-ufpb/ds-sync
v1.3.0
Published
CLI to manage LEMA Design System components in consuming projects
Readme
@lema-ufpb/ds-sync
CLI for managing LEMA Design System components in consumer projects.
Replaces npx shadcn@latest add in UFPB projects with auth, lockfile, drift detection, and CI.
Installation
npm install -D @lema-ufpb/ds-syncConfigure in .env.local:
LEMA_DS_TOKEN=<your-token>
LEMA_DS_REGISTRY=https://ds.lema.ufpb.brToken provided by LEMA's NOC. Default registry points to production.
Commands
npx ds list # List available
npx ds list --installed # Only installed
npx ds add dashbox bar-chart # Install (resolves registryDeps)
npx ds add --all # Install everything
npx ds update dashbox # Update component(s)
npx ds update --all # Update everything
npx ds verify # Check local drift vs lock
npx ds info dashbox # Component details
npx ds whoami # Validate token
npx ds diff dashbox # Diff local vs remote
npx ds diff --all # Diff all
npx ds sync # Sync (interactive)
npx ds sync --all --yes # CI mode
npx ds sync-tokens # Force refetch CSS tokensGlobal flags
| Flag | Description |
| ----------------------------- | ----------------------------- |
| --registry <url> | Registry URL |
| --token <token> | Auth token |
| --cwd <path> | Project directory |
| --lock <path> | Lockfile path |
| --pm <npm\|pnpm\|yarn\|bun> | Force package manager |
| --no-install | Skip npm install |
| -y, --yes | Skip confirmations |
| --silent | Errors only |
| --verbose | Detailed log |
| --json | JSON output (machine-readable)|
JSON output
npx ds add dashbox --json
# {"command":"add","success":true,"components":["dashbox"],...}
npx ds verify --json
# {"command":"verify","ok":true,"drifted":[]}
npx ds whoami --json
# {"command":"whoami","authenticated":true,"registry":"LEMA-UFPB Design System",...}Exit codes
| Code | Meaning |
| ---- | ----------------------------- |
| 0 | Success |
| 1 | Generic error |
| 2 | Auth (invalid/missing token) |
| 3 | Config (components.json) |
| 4 | Drift detected |
| 5 | Registry/network |
Lockfile
ds.lock is generated automatically and must be committed — it is the source of truth for reproducibility and drift detection.
Development
make install # Install deps
make dev # Watch mode
make build # Production build
make test # Run tests
make lint # ESLint
make format # Prettier
make typecheck # TypeScript
make pack # Generate tarball for local install
make clean # Clean artifacts
make fresh # Clean + install + build
make help # List all targetsArchitecture
src/
├── cli.ts # Entrypoint (commander)
├── commands/ # add, list, update, verify, info, whoami, diff, sync, sync-tokens
├── core/ # registry, resolver, writer, lockfile, hasher, pm, tokens, config, differ
└── lib/ # errors, uiDependencies: commander, picocolors, @clack/prompts. Bundle < 35KB.
Release & Deploy
The project uses a GitFlow workflow with automatic versioning via release-please and continuous deployment to GitHub Packages.
Branches
| Branch | Purpose |
| :-------- | :------------------------------------------------------------------- |
| develop | Integration branch — every feature/fix PR goes here |
| main | Release branch — receives merge from develop when ready to ship |
Full workflow (commit to deploy)
feature/* ──PR──▶ develop ──PR──▶ main ──┐
│ (release-please watches)
▼
chore(release): vX.Y.Z (PR opened by bot)
│
▼ merge
tag vX.Y.Z + GitHub Release created
│
▼ (release.published)
CD: npm build → npm publish (GitHub Packages)CI (.github/workflows/ci.yml)
Triggers only on PRs against develop — the only stage where new code is introduced. PRs develop → main and release-please PRs do not run CI. Sequential pipeline with fail-fast (3 chained jobs) on a self-hosted runner:
lint → test → build
- Lint:
npm run format:check,npm run lintandnpm run typecheck - Test:
npm testusing Vitest - Build:
npm run build(tsup) and strict bundle size check (< 200KB)
Branch protection is mandatory on
developandmain. CI only attests quality if direct pushes are blocked.
Automated Release (.github/workflows/release-please.yml)
Triggers on push to main. The release-please bot:
- Reads commits since the last tag and calculates the next version (Conventional Commits)
- Opens/updates a
chore(release): vX.Y.ZPR containing updates topackage.json,.release-please-manifest.jsonandCHANGELOG.md - When the PR is merged → creates the
vX.Y.Ztag + GitHub Release automatically
Post-release sync (.github/workflows/post-release-sync.yml)
After each release, develop must be updated with the new manifest, version, and changelog from main. This workflow triggers on release: published and copies only .release-please-manifest.json, package.json, and CHANGELOG.md from main to develop — without merging branches.
Why this is necessary: release-please only updates these three files on main (via its release PR). Since the project uses GitFlow (develop → main, never main → develop), develop would otherwise keep stale version info. On the next develop → main PR, the stale files would overwrite the correct values on main, causing release-please to miscalculate the next version or open duplicate release PRs.
If the workflow fails, run manually:
git checkout develop && git fetch origin main && \
git checkout origin/main -- .release-please-manifest.json package.json CHANGELOG.md && \
git commit -m "chore(release): sync develop after vX.Y.Z" && git push origin developCD (.github/workflows/cd.yml)
Triggers on release: published.
The workflow checks out the release tag, builds the CLI (npm run build), and publishes to GitHub Packages (npm publish) under the @lema-ufpb/ds-sync scope.
Quality guarantee: the tag is only born from a release-please PR merged into
main. CI has already validated all code indevelop. CD trusts this upstream validation.
Recovery when CD fails
Default path (90% of cases): roll-forward (new fix in develop → merge to main → new tag and release).
Note:
npm publishis more permanent than Docker images. Published packages cannot be easily deleted after 72h, requiringnpm deprecate.
For complex scenarios (tag created but publish failed, package published with critical bug, release-please calculating wrong version, release-please CI blocked), refer to the .github/RELEASE_RUNBOOK.md. The runbook details all strategies and exact commands for each scenario.
Contributing
Conventional Commits (required)
For release-please to correctly calculate the next version and generate CHANGELOG.md, all commits must follow the Conventional Commits standard:
| Prefix | Bump (semver) | Appears in CHANGELOG |
| :--------------------------------------- | :------------------------------- | :------------------- |
| feat: | minor (X.1.0) | Features |
| fix: | patch (X.X.1) | Bug Fixes |
| perf: | patch | Performance |
| refactor: | patch | Refactor |
| docs: | patch | Documentation |
| revert: | patch | Reverts |
| feat!: / BREAKING CHANGE: | major (2.0.0) | Breaking |
| chore: style: test: build: ci: | — (no bump) | hidden |
Pull Request
- Create a branch from
develop:git checkout -b feature/my-feature - Push and open a PR against
develop— CI will trigger automatically - After merge into
develop, promote tomainby opening another PR - release-please bot will manage the release from
main
