Skip to main content
The public npm package is factrove. It installs two commands, factrove and ftrv. They run the same program. npm rejected a separate ftrv package name, so ftrv is only a bin alias. The workspace package stays @factrove/cli and private. The repository root is also named factrove, and pnpm will not accept a second workspace package with that name. node scripts/pack-cli.mjs writes apps/cli/npm/ with the public manifest, bundles @factrove/api-client and @factrove/contracts into dist/cli.js, and leaves NestJS, reflect-metadata, rxjs, and zod as normal dependencies. That directory is gitignored. npm publish runs there, not in apps/cli. Publishing happens only when someone runs the Publish CLI workflow by hand from main. The workflow file is .github/workflows/publish-cli.yml. It has no push or tag trigger. A dispatch from any other branch is skipped, so it cannot publish.

Add NPM_TOKEN

The workflow reads the NPM_TOKEN repository secret. It does not publish without that secret, and a dry run does not need it. Create a granular access token on the npm account that owns factrove (npm user tommagni):
  1. Open npm Access Tokens and generate a Granular Access Token.
  2. Name it for GitHub Actions, and set an expiration you will rotate.
  3. Under packages, grant read and write only for the factrove package. Do not grant access to every package on the account.
  4. Tick Bypass two-factor authentication. It is off by default. CI cannot publish until that box is ticked. The token is still a granular access token, scoped to read and write on factrove only.
  5. In the GitHub repository, open Settings → Secrets and variables → Actions → New repository secret. Name it NPM_TOKEN and paste the token.
Do not commit the token, and do not put it in the workflow file. The workflow writes it to ~/.npmrc only for the publish step. The publish command is npm publish --access public. It does not pass --provenance. The publish step sets NPM_CONFIG_PROVENANCE to the opposite of github.event.repository.private. While this repository is private, that value is false and npm publishes without provenance, which is what npm accepts from a private repository. When the repository is later made public, the same workflow turns provenance on without a workflow edit. id-token: write is already set so a public repository can sign it. You do not need to make the repository public before the first publish.

Cut a release

1

Set the version

The version in apps/cli/package.json is what gets published when the version input is empty. Bump that version in a commit on main before a real publish. The input overrides the tarball version without changing the file. Pass a semver such as 0.1.0, with no leading v.npm already has the placeholder factrove@0.0.1. Do not republish 0.0.1. The first release from this repository is the version in apps/cli/package.json (0.1.0 until that file changes).
2

Dry-run

Open Actions → Publish CLI → Run workflow on main. Leave Dry-run checked. That is the default. Leave Version empty to use package.json, or type a version to pack that version instead.The job installs dependencies, builds the CLI, runs the CLI tests, writes the publish directory, prints npm pack --dry-run, and fails if that version is already on npm. It then installs the tarball into a clean prefix and runs factrove --help and ftrv --help. It does not publish.
3

Publish

Run the workflow again from main with Dry-run unchecked. The same checks run, then npm publish --access public. Provenance stays off while the repository is private and turns on automatically once the repository is public. A missing NPM_TOKEN fails this step. A version that already exists fails before the smoke test, with an error that names the version.
pnpm cli:pack from a checkout writes the same apps/cli/npm/ directory. It does not publish. Contributors still run pnpm factrove from the repository root. That launcher is not the published package. Install instructions for the published commands are in CLI and CLI overview.