@precisa-saude/worktree-cli
v1.8.0
Published
Shared git-worktree lifecycle CLI for Precisa Saúde repositories — creates/dev-runs/tears-down feature worktrees with per-repo port allocation. Drop-in replacement for each repo's `scripts/worktree.sh`.
Maintainers
Readme
@precisa-saude/worktree-cli
Shared git worktree lifecycle CLI for the Precisa Saúde ecosystem.
Drop-in replacement for each repo's hand-rolled scripts/worktree.sh.
- One codebase, one behavior across fhir-brasil, medbench-brasil, datasus-brasil, and platform.
- Per-repo config declared in
package.json— no code fork. - Single-service and multi-service repos supported uniformly (platform runs API + Web + Landing in one worktree; medbench/fhir run just the site).
- Atomic port allocation via a JSON registry on
/tmp/, guarded by amkdir-based lock portable to macOS and Linux.
Install
pnpm add -D @precisa-saude/worktree-cliConfigure
Add a worktree field to the repo's root package.json:
{
"worktree": {
"directoryPrefix": "medbench-brasil",
"portRegistry": "/tmp/medbench-worktree-ports.json",
"buildCommand": "pnpm turbo run build --filter=./packages/*",
"services": [
{
"name": "site",
"mainPort": 4321,
"featureBase": 4331,
"increment": 10,
"pnpmFilter": "@medbench-brasil/site",
"logPrefix": "medbench-site"
}
]
}
}Multi-service example (platform)
{
"worktree": {
"directoryPrefix": "platform",
"portRegistry": "/tmp/precisa-worktree-ports.json",
"services": [
{
"name": "api",
"mainPort": 3000,
"featureBase": 3010,
"increment": 10,
"pnpmFilter": "@precisasaude/api",
"logPrefix": "precisa-api",
"env": { "PORT": "{port}" }
},
{
"name": "web",
"mainPort": 5173,
"featureBase": 5180,
"increment": 10,
"pnpmFilter": "@precisasaude/web",
"logPrefix": "precisa-web",
"env": { "VITE_API_URL": "http://localhost:{api_port}/api" }
}
]
}
}Usage
precisa-worktree setup feat/my-work # create worktree, install, allocate ports
cd ../<prefix>-feat-my-work
precisa-worktree dev # start dev servers (foreground)
precisa-worktree dev --detach # detached (writes to log files)
precisa-worktree dev --force # kill processes on conflicting ports
precisa-worktree stop # kill this worktree's dev servers
precisa-worktree logs --service=api # tail a specific service log
precisa-worktree list # show all worktrees + ports + status
precisa-worktree teardown feat/my-work # stop, remove, delete branch, free ports
precisa-worktree teardown --keep-branch X # preserve the local branchCommands that take [branch] auto-detect from the working directory
when invoked inside a linked worktree. In the main worktree, pass the
branch explicitly.
Drop-in migration from scripts/worktree.sh
Old:
./scripts/worktree.sh setup feat/my-work
./scripts/worktree.sh dev
./scripts/worktree.sh teardown feat/my-workNew:
pnpm exec precisa-worktree setup feat/my-work
pnpm exec precisa-worktree dev
pnpm exec precisa-worktree teardown feat/my-workOr add a shim at scripts/worktree.sh:
#!/usr/bin/env bash
exec pnpm exec precisa-worktree "$@"How port allocation works
- Main worktree always uses
mainPort(never allocated — reserved by convention). - Feature worktrees get a slot starting at 1. Slot N allocates
featureBase + (N-1) * incrementfor each service. - Slots are recycled after teardown, so long-lived repos don't drift into high port numbers.
- The registry is a JSON file on
/tmp/(survives across sessions, wiped by the OS between boots — safe default). - A
mkdir-based lock serializes concurrent setup/teardown across parallel agent sessions without requiringflock(macOS-compatible).
Design goals
- No surprise behavior change relative to the hand-rolled scripts: same port allocation algorithm, same worktree directory naming, same log file paths.
- Fail loudly on misconfiguration: missing config field → immediate error with field name.
- Cross-platform: macOS (lsof) and Linux (ss, fuser) port probing; POSIX-atomic locking; no GNU-specific flags.
