@x12i/npm
v2.30.2
Published
CLI for automating npm and git workflows across one or more packages
Readme
xnpm
npm is the native package manager. xnpm is the x12i automation layer for npm packages and git workflows.
Install once with npm install -g @x12i/npm, then use xnpm from any package folder, packages root, monorepo root, or workspace root.
xnpm does not replace npm or git. It orchestrates them — discovering packages, mapping local dependencies, determining execution order, and running the right native commands in the right folders, safely.
You can also use xnpm as your only daily command: native npm and git subcommands pass through directly (for example xnpm run build, xnpm status), and xnpm ask resolves plain-English requests to xnpm automation, npm, or git.
Product naming
| | |
|---|---|
| Product name | xnpm |
| npm package | @x12i/npm |
| Daily command | xnpm |
| Compatibility alias | x12i-npm |
Install
Global install (recommended)
| Platform | Command |
|---|---|
| Windows | npm install -g @x12i/npm |
| macOS / Linux | sudo npm install -g @x12i/npm |
On macOS and Linux, sudo is needed because npm’s default global directory (/usr/local/lib/node_modules) is not writable by a normal user. On Windows, install without sudo.
After installation, xnpm is available from any folder (x12i-npm remains as a compatibility alias):
xnpm --versionGlobal installation is the primary workflow. You do not need to install @x12i/npm into every package you manage.
Troubleshooting (xnpm not recognized, PATH, Git Bash, EACCES cache, doctor hangs): see docs/troubleshooting.md or run:
xnpm troubleshooting
npx @x12i/npm doctorUpdate
| Platform | Command |
|---|---|
| Any | xnpm upgrade or xnpm --upgrade |
| Windows | npm install -g @x12i/npm@latest |
| macOS / Linux | sudo npm install -g @x12i/npm@latest |
xnpm upgrade checks npm for the latest release and runs npm install -g @x12i/npm@latest. On macOS/Linux you may still need sudo if the global folder is not writable — xnpm prints both sudo chown … and sudo npm install -g … fixes when that happens (exit code 3 = environment/permissions, not a package error).
One-off / CI usage
Without a global install:
npx @x12i/npm --build --test
npx @x12i/npm@latest --build --test --publish --pushOr:
npm exec @x12i/npm -- --build --testUseful for CI, temporary machines, or developers who prefer not to install globally.
Optional project-level install
Teams that want a pinned version per repository may install locally:
npm install --save-dev @x12i/npmThen expose scripts such as:
{
"scripts": {
"xnpm": "xnpm",
"release:packages": "xnpm --build --test --publish --push --report"
}
}This is optional. The global CLI remains the simplest path.
Requirements
The station must already have these tools installed:
- Node.js
>= 20 - npm — available in
PATH - git — required when using
--pushor--create-git
@x12i/npm does not install Node.js, npm, or git. It does not configure npm login or create tokens.
On startup, the CLI validates that npm is available. If --push is used, git must also be available. If --push is not used, a missing git produces a warning rather than a fatal error.
npm authentication
Installing the CLI itself requires no special handling when @x12i/npm is published publicly.
For publish operations, valid npm authentication must already be configured through npm’s normal mechanisms — usually via .npmrc at the repo root or ~/.npmrc.
xnpm automatically applies the repo root .npmrc to every package install and publish (package-local → invocation root → git root). You do not need to export NPM_CONFIG_USERCONFIG before running xnpm in a monorepo.
Example shape:
@x12i:registry=https://registry.npmjs.org/
//registry.npmjs.org/:_authToken=${NPM_TOKEN}
always-auth=trueThe CLI never asks for tokens, stores tokens, or prints tokens.
Simplest developer flow
# Install once (macOS / Linux — use sudo)
sudo npm install -g @x12i/npm
# Go to a package folder or packages root
cd /path/to/packages
# Fix dependency specs to npm latest, then install dependencies
xnpm install
# Or use xnpm for everyday npm/git in a single package folder
xnpm run build
xnpm status
# Full release flow
xnpm --full-flow
# Monorepo: install all packages, then tiered publish scripts
xnpm --all install
xnpm scripts init
xnpm scripts run all
# Update the CLI later
sudo npm install -g @x12i/npm@latestOn Windows, omit sudo from the install and update commands.
xnpm uses an isolated npm cache at ~/.cache/xnpm/npm so installs keep working when ~/.npm has permission issues. If the primary cache is root-owned (from a past sudo xnpm), xnpm automatically falls back to ~/.cache/xnpm/npm-clean and prints a one-line chown fix — you do not need wrapper scripts that export NPM_CONFIG_CACHE. See docs/troubleshooting.md for EACCES fixes, exit codes, and cache details.
Usage
xnpm [command] [flags]Compatibility alias: x12i-npm
xgit — git-first CLI (same package)
@x12i/npm also ships xgit / x12i-git — same engine, git-first ergonomics:
xgit status # natural git passthrough (no "git" prefix)
xgit pull --rebase origin main
xgit push # plain git push (+ rebase prompt when remote is ahead)
xgit ask "commit and push" # ask resolves git catalog first
# npm / monorepo cross-support (same commands as xnpm)
xgit install --all
xgit release --report
xgit validate --fix
xgit npm run build # explicit npm passthrough| | xnpm | xgit |
|---|----------|----------|
| Primary focus | npm install, publish, validate, release | git status, pull, push, commit |
| Natural passthrough | xnpm git status or xnpm status | xgit status |
| Ask catalog order | xnpm → npm → git | git → xnpm → npm |
| Monorepo lifecycle | full support | full support (cross-solve) |
Show help (default when run with no arguments):
xnpm
xnpm help
xnpm -h
xnpm --helpFix dependency specs to npm latest, then install dependencies:
xnpm i
xnpm installList packages, versions, and local dependency relationships:
xnpm list
xnpm ls
xnpm list --filter "@x12i/*"
xnpm ls --allValidate workspace integrity and npm registry versions:
xnpm validate
xnpm validate --build # also run npm run build smoke test
xnpm validate --fix # fix deps + overrides; major bumps run build unless --no-build
xnpm --validate --filter "@x12i/*"Optional: generate a machine-readable package graph, publish scripts, or agent instructions:
xnpm map # write xnpm.json (backs up existing to xnpm.json.bak)
xnpm scripts init # create scripts/publish-*.sh + package.json publish:* entries
xnpm map-to ./custom-graph.json # write to a custom file
xnpm map-out # print JSON to stdout
xnpm --instructions # writes xnpm-*.md files only when you run this
xnpm --instructions --instructions-dir ./docs
xnpm agent-deploy-guide # writes .xnpm/agent-monorepo-deploy.md for code agents
xnpm init agent-deploy # alias
xnpm agent-deploy-guide --dir docs --forceCheck environment and fix common setup issues:
xnpm doctor
xnpm troubleshooting
npx @x12i/npm doctorRun native npm or git in the current folder (passthrough):
xnpm run build
xnpm status
xnpm npm outdated
xnpm git log --oneline -5Commands
| Command | Description |
|---|---|
| (no command) | Show usage, flags, and examples |
| install, i | Fix dependency specs to npm latest, then install dependencies and requested lifecycle steps |
| list, ls | List discovered packages, versions, and local dependency relationships |
| validate | Check local dependency integrity and npm registry versions (read-only) |
| release | Full release playbook: fix → install → build → test → publish → push |
| map | Write inferred package graph to xnpm.json (backs up existing file to xnpm.json.bak) |
| map-to <path> | Write inferred package graph to a custom file |
| map-out | Print inferred package graph as JSON to stdout |
| scripts | Publish script helpers: init, list, run <name> [-- args] — see Publish scripts |
| upgrade | Install the latest @x12i/npm from npm globally (--upgrade alias) |
| upstream | CR/FR issue bridge: submit issues to upstream repos, pull-fix, verify — see Upstream CR/FR bridge and docs/upstream.md |
| cursor-init | Write Cursor, Codex, and Claude Code agent rules (optional --hooks) |
| agent-init | Alias for cursor-init |
| agent-deploy-guide | Write agent monorepo deploy guide (default: .xnpm/agent-monorepo-deploy.md) |
| init agent-deploy | Alias for agent-deploy-guide |
| doctor | Check Node/npm/git/xnpm setup; auto-fix common PATH issues on Windows |
| troubleshooting | Print install, PATH, cache, and platform troubleshooting guide |
| ask <text> | Resolve plain-English to xnpm, npm, or git (deterministic) |
| npm <args> | Run native npm in the current folder |
| git <args> | Run native git in the current folder |
| help, -h, --help | Same as running xnpm with no arguments |
xnpm i and xnpm install are equivalent for xnpm automation. Both align package.json dependency specs to npm latest before installing. Flags can be combined with install, e.g. xnpm install --build --test.
npm and git passthrough
xnpm can front almost all regular npm and git commands so you do not need separate binaries for day-to-day work.
Implicit passthrough — recognized npm/git subcommands run natively:
| You run | Equivalent |
|---|---|
| xnpm run build | npm run build |
| xnpm test | npm test |
| xnpm install lodash | npm install lodash |
| xnpm publish | npm publish |
| xnpm status | git status |
| xnpm push | git push |
| xnpm pull | git pull |
Explicit passthrough — always available:
xnpm npm run build
xnpm npm outdated
xnpm git status
xnpm git diffPassthrough npm commands use xnpm’s isolated cache at ~/.cache/xnpm/npm (same as xnpm automation).
Disambiguation — xnpm automation vs native tools:
| Input | Routed to |
|---|---|
| xnpm install | xnpm install only (refreshes @x12i/* / @exellix/* at latest; add --fix for in-house version fix) |
| xnpm install --fix-public | xnpm fix + install including public toolchain deps |
| xnpm install --build | xnpm automation |
| xnpm install lodash | npm install lodash |
| xnpm install -D typescript | npm install -D typescript |
| xnpm list / xnpm ls | xnpm package discovery |
| xnpm npm list | npm list |
| xnpm --publish | xnpm lifecycle publish |
| xnpm publish | npm publish |
| xnpm --push | xnpm lifecycle git push |
| xnpm push | git push |
| xnpm --test | xnpm lifecycle test |
| xnpm test | npm test |
Reserved xnpm commands (ask, doctor, help, list, ls, map, map-to, map-out, scripts, troubleshooting, validate) always stay on the xnpm side.
Natural-language commands (xnpm ask)
xnpm ask lets you describe what you want in plain English. The CLI resolves that text to a normal command — xnpm automation flags, or native npm/git — using the same execution path you would use directly.
This is not an LLM. There is no model dependency, no local AI setup, and no hallucinated shell commands. Resolution is deterministic: input is normalized and matched against phrase catalogs by @x12i/ask-cli, then turned into a structured plan that is validated before anything runs.
Resolution order: xnpm catalog first, then npm, then git. xnpm workflow phrases win when they match.
# xnpm automation
xnpm ask "install all packages"
xnpm ask "install, build and test all @x12i packages"
xnpm ask "publish all @x12i packages and push"
xnpm ask "create publishing scripts"
xnpm ask "run publish script all"
xnpm ask "create new private npm packages for @exellix packages"
# native npm
xnpm ask "run build"
xnpm ask "run tests"
xnpm ask "show outdated packages"
# native git
xnpm ask "show git status"
xnpm ask "pull latest changes"
xnpm ask "push to remote"How it works
When you run xnpm ask "<text>", the CLI:
- Normalizes the text (lowercase, trim, collapse spaces, normalize
&→and,everything→all packages, and similar shorthands). - Matches the normalized input against the phrase catalog (exact phrase first, then slot patterns).
- Extracts known variables such as scope (
@x12i,exellix), package name, repo mode, or git provider. - Builds a structured argv list (never executes the raw English string).
- Validates the plan using the same rules as normal commands (
buildOperations,createExecutionPlan, or npm/git passthrough). - Shows the resolved command, what it will do, and any risks.
- Asks for approval when the operation is dangerous.
- Executes only after validation (and approval, if required).
What you can say
The catalog covers common workflows. Phrasing can vary; many aliases resolve to the same command.
| You might say | Resolves to |
|---|---|
| install all packages | xnpm |
| install all / install everything | xnpm |
| build and test everything | xnpm --build --test |
| install, build and test all @x12i packages | xnpm --filter "@x12i/*" --build --test |
| install, build and test all @x12i and @exellix packages | xnpm --filter "@x12i/*" --filter "@exellix/*" --build --test |
| publish all packages | xnpm --build --test --publish --report |
| publish all @x12i packages and push | xnpm --filter "@x12i/*" --build --test --publish --push --report |
| create new private npm packages for @x12i packages | xnpm --filter "@x12i/*" --build --test --new-private --report |
| push all repos | xnpm --push --report |
| connect git repo to [email protected]:x12i/packages.git | xnpm --connect "[email protected]:x12i/packages.git" |
| link remote [email protected]:x12i/core.git and push | xnpm --connect "[email protected]:x12i/core.git" --push --report |
| create git and connect to [email protected]:x12i/demo.git | xnpm --create-git --connect "[email protected]:x12i/demo.git" |
| run build | xnpm npm run build |
| run tests | xnpm npm test |
| show outdated packages | xnpm npm outdated |
| show git status | xnpm git status |
| pull latest changes | xnpm git pull |
| push to remote | xnpm git push |
Scope names are flexible. All of these filter the same way:
@x12i
x12i
x12i packages
all @x12i packages
packages under @x12iApproval for dangerous operations
Safe operations (install, build, test, status, diff) run immediately after resolution.
Dangerous operations (publish, push, pull, commit, first-publish, git creation) show a confirmation prompt:
I understood this as:
xnpm --filter "@x12i/*" --build --test --publish --push --report
This will:
- Select packages matching the requested scope.
- Run install.
- Run build and test.
- Publish packages in dependency-aware order.
- Push git changes.
- Show a summarized report.
Risks:
- This may publish new npm versions.
- This may push commits to git remotes.
Execute? [y/N]Only y or yes proceeds. Anything else cancels.
Code-agent-safe ask (2.30.0+)
xnpm ask never blocks on stdin when the caller is a code agent or CI, and offers a plan-only mode for resolving intent without executing anything:
xnpm ask "release the stack" --plan --json # resolve only — argv, risks, explanation, suggested --yes command
xnpm ask "release the stack" --agent # never prompts; exits 4 if approval is required
XNPM_AGENT=1 xnpm ask "release the stack" # same, via env var
CI=true xnpm ask "release the stack" # same, detected automatically
xnpm ask "release the stack" --yes # explicit approval — executes--planresolves the request to a command, argv, risks, and explanation, and exits without running it.--jsonprints that resolution as machine-readable JSON instead of the human-readable summary.--agent,XNPM_AGENT=1,CI=true, or a non-TTY stdin all mean "never wait for an interactive answer."- In any of those non-interactive contexts, a dangerous operation without
--yesexits with code4(approval required) instead of hanging on a prompt that will never be answered. TTY behavior for humans is unchanged.
Unknown requests
If no catalog can match your text, xnpm ask fails safely and suggests known examples. It does not call an LLM or run arbitrary commands.
I could not match that request to a known xnpm, npm, or git command.
Try one of these:
xnpm ask "install all packages"
xnpm ask "run build"
xnpm ask "show git status"
xnpm ask "publish all @x12i packages and push"Phrase catalogs ship at:
src/catalog/xnpm-ask.catalog.json— multi-package workflowssrc/catalog/npm-ask.catalog.json— common npm commandssrc/catalog/git-ask.catalog.json— common git commands
(built to dist/catalog/). Matching and normalization come from @x12i/ask-cli; xnpm owns validation, approval, and execution. Covered by automated tests (npm test).
Flags
| Flag | Description |
|---|---|
| --build | Run npm run build after install |
| --test | Run npm test after build |
| --publish | Bump minor version and publish to npm |
| --publish-flow | Run fix, install, publish, and push with a final report |
| --full-flow | Run fix, install, build, test, publish, and push with a final report |
| --push | Commit and push via git |
| --report | Suppress noisy output, show high-level summary only |
| --validate | Check local dependency integrity and npm registry versions (read-only; same as validate command) |
| --fix | Refresh @x12i/* / @exellix/* (and workspace locals) to ^npm-latest |
| --fix-public | Also bump public/third-party deps (vite, react, tailwindcss, …) |
| --all-external | Alias for --fix-public |
| --force-engine | Allow fix when engines.node would block |
| --no-fix | Skip automatic fix on install, --publish, --publish-flow, and --full-flow |
| --no-install | Skip npm install steps (use after a local npm install) |
| --force-republish | Publish even when the version already exists on npm (default: skip with --no-version-bump) |
| --instructions | Write xnpm-package-graph-instructions.md and xnpm-package-graph-readme.md for agents (optional) |
| --instructions-dir <path> | Output directory for --instructions (default: current folder) |
| --dry-run | Show planned execution without modifying files |
| --no-version-bump | Publish the current version without bumping |
| --clean-local | Remove local file: overrides from package.json |
| --clean-all | Remove the entire overrides object from package.json |
| --force | Opt-in: npm cache clean --force once before install; on --push, retry with --force-with-lease after rebase recovery is declined or fails |
| --fast | Skip security and slow validation checks (tarball inspect, pack-check, gitignore, post-publish verify, install-health); see report for what was skipped |
| --stack <name> | Load release playbook from .xnpm/stacks/<name>.json or .yaml |
| --with-catalox | Run stack postRelease scripts when .env is present |
| --message <text> | Custom release summary for CHANGELOG and git commit ({name}, {version}, {shortName}) |
| --all | Discover all packages under cwd, including nested git repos |
| --package <name> | Select a specific package (repeatable) |
| --filter <glob> | Select packages matching a glob (e.g. @x12i/*) |
| --json | Machine-readable output where supported (xnpm ask --plan --json, xnpm history --json) |
| --plan | xnpm ask only: resolve to a command/argv/risk plan without executing it |
| --agent | xnpm ask only: never wait for interactive approval (also via XNPM_AGENT=1 or CI=true); exits 4 instead of prompting when approval is required |
| --yes | xnpm ask only: approve a matched dangerous operation non-interactively and execute it |
Creation flags (opt-in)
These flags initialize missing git/npm setup when explicitly requested. Normal commands assume packages and git repositories already exist.
| Flag | Description |
|---|---|
| --create-git | Create local git repository where needed (git init, initial commit) |
| --repo-mode <mode> | monorepo (one root repo) or multi-repo (one repo per package) |
| --connect <url> | Alias for --git-link — link folder to an existing remote |
| --git-link <url> | Link to an existing remote (monorepo or single package) |
| --git-link-template <tpl> | Link remotes by template in multi-repo mode |
| --git-map <path> | Link remotes via JSON map file in multi-repo mode (not the same as map / map-to / map-out) |
| --git-create-remote | Create a new remote repo via provider API |
| --git-provider <name> | github, gitlab, or bitbucket |
| --git-org <org> | Organization or user for remote creation |
| --git-visibility <vis> | private or public |
| --repo-name <name> | Remote repo name (monorepo) |
| --repo-name-template <tpl> | Remote repo name template (multi-repo) |
| --new-public | First-publish as a public npm package (no version bump) |
| --new-private | First-publish as a restricted npm package (scoped names only) |
Package selection
--package selects packages by exact package.json name (repeatable). --filter matches package names using glob syntax (not folder paths).
Examples:
--filter "@x12i/*" matches all packages under the @x12i scope
--filter "@exellix/*" matches all packages under the @exellix scope
--filter "@x12i/ai-*" matches only @x12i packages whose unscoped name starts with ai-
--filter "*gateway*" matches package names containing gatewayMultiple --filter values are OR-based:
xnpm --filter "@x12i/*" --filter "@exellix/*"matches packages from either scope.
--package and --filter are also OR-based when used together.
If no package matches a given --filter glob, the CLI fails with a clear error. A separate folder-path filter may be added later if needed — package-name and path matching are not mixed in one flag.
Examples
# Show help
xnpm
# Natural-language commands (deterministic resolver)
xnpm ask "install all packages"
xnpm ask "install, build and test all @x12i packages"
xnpm ask "publish all @x12i packages and push"
xnpm ask "run build"
xnpm ask "show git status"
xnpm ask "connect git repo to [email protected]:x12i/packages.git"
# Native npm/git passthrough
xnpm run build
xnpm test
xnpm status
xnpm npm outdated
xnpm git log --oneline -10
# Environment check and troubleshooting
xnpm doctor
xnpm troubleshooting
# Validate workspace and registry versions
xnpm validate
xnpm validate --build
xnpm --validate --filter "@x12i/*"
# Fix dependency versions against npm without installing
xnpm --fix
xnpm install --fix-public --dry-run # public bumps + rationale; blocked if Node engine gap
xnpm why-upgrade vite
xnpm validate --fix
# Dependency usage reports
xnpm deps unused --include-dev
xnpm deps usage react --format markdown
# Engine floor
xnpm engines sync
xnpm doctor
# Scaffold upstream CR/FR workspace
xnpm init upstream
# File upstream CR/FR to @x12i/npm (after: xnpm upstream auth login)
xnpm upstream submit --id FR-XNPM-1 --registry xnpm
xnpm upstream submit --file docs/upstream/my-fr.md --package @x12i/npm --repo x12i/npm
xnpm upstream auth status
# Install only (workspace-aware)
xnpm install
# Fix dependency versions against npm, then install
xnpm install --fix
# Optional: generate package graph and agent instructions (no effect until you add xnpm.json)
xnpm map
xnpm map-to ./custom-graph.json
xnpm map-out
xnpm --instructions
xnpm --instructions --instructions-dir ./docs
# Connect folder to an existing remote (--connect is alias for --git-link)
xnpm --connect [email protected]:x12i/packages.git --repo-mode monorepo --push
# Install only
xnpm install
# Install and build
xnpm install --build
# Install, build, and test
xnpm --build --test
# Publish flow — fix, install, publish, push, final report
xnpm --publish-flow
# Full flow — fix, install, build, test, publish, push, final report
xnpm --full-flow
# Release playbook (same as --full-flow; supports --stack for monorepo policies)
xnpm release
xnpm release --stack ai-tasks-line --with-catalox --message "Stack release."
xnpm release --package @x12i/core
# Fast mode — skip slow security checks (see report for skipped steps)
xnpm install --fast
xnpm release --stack ai-tasks-line --fast
# Dry run — show plan without executing
xnpm --full-flow --dry-run
# Publish without version bump
xnpm --build --test --publish --no-version-bump
# Remove local file: overrides and install
xnpm --clean-local
# Remove all overrides and install
xnpm --clean-all
# Scope-based package selection
xnpm --filter "@x12i/*"
xnpm --filter "@x12i/*" --filter "@exellix/*"
# Create local git repo at root (monorepo)
xnpm --create-git --repo-mode monorepo
# First-publish a scoped package as restricted
xnpm --package @x12i/core --build --test --new-private --report
# Create/publish new private packages
xnpm --build --test --new-private --push --report
# Create remote repo and publish
xnpm \
--package @x12i/core \
--create-git \
--repo-mode multi-repo \
--git-create-remote \
--git-provider github \
--git-org x12i \
--git-visibility private \
--repo-name-template "{repoName}" \
--build --test --new-private --push --report
# Create/link git and publish (monorepo)
xnpm \
--create-git \
--repo-mode monorepo \
--git-create-remote \
--git-provider github \
--git-org x12i \
--git-visibility private \
--repo-name packages \
--build \
--test \
--new-private \
--push \
--reportWhat it does
Package discovery
Run from a project folder. By default, xnpm scopes discovery so it does not crawl unrelated sibling repositories:
| Where you run it | Default scope |
|---|---|
| Inside a git repo | That repository's root |
| Inside an npm workspace | The workspace root |
| Anywhere else | Current folder only (nested .git directories are skipped) |
Pass --all to scan every package.json under the current folder recursively — including nested git repos. Use this from a shared parent folder that contains multiple independent projects.
cd xentra
xnpm install # only packages in the xentra repo
cd ~/projects/x12i
xnpm install # nothing (unless a package lives directly here)
xnpm install --all # every package under x12iGenerated and irrelevant folders are ignored automatically (node_modules, dist, build, .git, coverage, .next, .cache, etc.).
Supported layouts:
- Single package folder
- Root folder with nested packages
- Monorepo (shared git root)
- Multiple independent git repositories under one root
Package graph (xnpm.json) — optional
Nothing changes unless you opt in. xnpm works exactly as before when xnpm.json is absent. The file is optional — use it only when a repo benefits from explicit publish order, documented dev/test cycles, or tiered releases.
For those cases, add xnpm.json at the repo root. It is a machine-readable package graph — not a replacement for package.json, but a complement that documents discovery layout, publish sequences, local dependency edges, known cycles, and release profiles.
Generate a starter graph (only when you run a map command):
xnpm map # writes xnpm.json (backs up existing to xnpm.json.bak)
xnpm map-to ./custom-graph.json # writes a custom file
xnpm map-out # prints JSON to stdoutIf xnpm.json already exists, xnpm map renames it to xnpm.json.bak first. An existing .bak is overwritten.
Generate agent instructions (optional; only runs when you invoke it):
xnpm --instructionsThis writes:
xnpm-package-graph-instructions.md— step-by-step workflow for creating or updatingxnpm.jsonxnpm-package-graph-readme.md— short overview
Only after you place xnpm.json in the repo does xnpm pick it up. It searches from the current folder up to the git root and then uses it for list, validate, and lifecycle commands:
You do not need xnpm.json for discovery. xnpm finds packages from package.json files (use xnpm install --all to scan a tree without per-package git remotes). Add xnpm.json only when you want explicit publish order, release profiles, or documented dev cycles — generate a starter with xnpm map from the repo root.
- Publish order from
sequences(via the activereleaseProfilesentry forproject.layout.mode) - Relationships from each
package.jsonby default (operations.graphSourcedefaults topackage-json) - Private roots excluded via
operations.privatePackages - Documented dev cycles respected when
operations.allowDocumentedDevDependencyCyclesis set - Fix scope via
operations.autoFixandoperations.fix(disable devDependency bumps, exclude toolchain packages)
xnpm list and validate warn when xnpm.json dependency metadata is out of sync with package.json (run xnpm map from the repo root to refresh). Lifecycle runs show the loaded config path when xnpm.json is in use. Without xnpm.json, behavior is unchanged: xnpm infers relationships directly from each package.json.
Set operations.graphSource to "xnpm.json" only if you intentionally want relationships to follow the graph file instead of live package.json (legacy).
For npm workspace monorepos (workspaces in root package.json), xnpm runs npm install once at the repo root so local @scope/* siblings link correctly, then skips per-package installs under that root. This avoids registry lookups for unpublished workspace packages.
map / map-to / map-out and --git-map are different: the map commands export the package dependency graph; --git-map links git remotes in multi-repo creation mode.
Publish scripts (xnpm scripts)
Tiered publish scripts for monorepos — generate once, run by name, forward args to the underlying xnpm command.
Create scripts (writes scripts/publish-*.sh, wires root package.json, merges into xnpm.json if present):
xnpm scripts init # alias: xnpm scripts create| Script name | Shell file | Underlying command |
|---|---|---|
| preflight | scripts/publish-preflight.sh | xnpm validate |
| core | scripts/publish-core.sh | xnpm --build --test --publish --report |
| all | scripts/publish-all.sh | xnpm release --report |
Ordered publish runbook (for agents or manual npm publish — discovers packages, dependency order, verify loop):
xnpm scripts init runbook
xnpm scripts init runbook --filter "@x12i/memorix-*" # publish subset; verify all packages
xnpm scripts init runbook --dry-run # preview markdown
xnpm scripts init all # tiered scripts + runbookCreates:
| File | Purpose |
|---|---|
| scripts/publish-runbook.md | Step-by-step guide: npm preflight, build + npm publish per package, verify loop |
| scripts/publish-ordered.sh | Executable version of the same flow |
List and run:
xnpm scripts # list (same as xnpm scripts list)
xnpm scripts run preflight # validate before publish
xnpm scripts run core # build, test, publish in dependency order
xnpm scripts run all # full release playbook
xnpm scripts run all -- --dry-run # forward extra args after --Script definitions are read from xnpm.json → scripts (populated by xnpm map) or inferred from root package.json publish:* entries. Commands run from the git repo root with repo .npmrc applied automatically.
xnpm ask "publish everything in the right order" resolves to xnpm --build --test --publish --report — install, build, test, and publish each package in dependency order, refreshing dependents to @latest after each publish in the same run.
Typical monorepo flow:
xnpm map # optional: write xnpm.json graph
xnpm scripts init # create publish scripts
xnpm --all install # bootstrap all packages
xnpm scripts run preflight # validate
xnpm scripts run all # release when readyNo wrapper script is required for cache or npmrc — xnpm handles both. See npm cache and npmrc resolution.
Dependency-aware execution order
Local package relationships are mapped automatically. If @x12i/api depends on @x12i/core, then @x12i/core is installed, built, tested, and published first. Dependency cycles are detected and reported before any commands run.
Releasing from a subfolder: When you run lifecycle commands from sub-folder-b/ (install, build, test, publish, or release), xnpm walks to the git root, finds sibling packages (e.g. @scope/package-a in folder-of-package-a/), and compares their local package.json version to what you declared in package-b. If the sibling is ahead of your range or not published on npm yet, xnpm:
xnpm install/build/test— proactive alert (fast check; does not block). Usexnpm install --fixto bump declared ranges when appropriate.xnpm validate— reportssibling-release-first(error)xnpm release/publish— asks permission to release upstream packages first (default yes), or continue without changes (--yesskips prompts)
cd root-folder/sub-folder-b
xnpm install --package @scope/package-b # alerts if package-a is ahead / unpublished
xnpm validate --package @scope/package-b # check without publishing
xnpm release --package @scope/package-b # offers to release package-a firstUse xnpm release --package @scope/package-a from the repo root or that package's folder when prompted.
If you have added xnpm.json, publish order and release metadata come from the graph file; local dependency edges still follow each package.json unless you set operations.graphSource to "xnpm.json". Repos without xnpm.json are unaffected.
Operation order
For each package:
[fix] → install → build → test → publish → pushfix runs by default only for --publish-flow and --full-flow, or when --fix is passed (e.g. xnpm install --fix). Use --no-fix to skip it. Set operations.autoFix: false in xnpm.json to disable fix on flows unless --fix is explicit.
Default fix scope (CR-XNPM-1): --fix refreshes in-house @x12i/* and @exellix/* only. Public toolchain bumps require --fix-public (or name packages explicitly: xnpm install --fix vite). Prerequisites (Node engine, companion packages) are checked before writes; use --force-engine to override engine blocks.
Only the requested operations run.
By default, install runs npm install only. Pass --force to run npm cache clean --force once before all installs — useful when stale cache entries cause confusing npm resolution errors. If cache clean fails (for example root-owned files in ~/.npm), xnpm warns once and continues with install.
During every install, xnpm also runs npm install <pkg>@latest for scoped registry dependencies:
- always for
@x12i/*and@exellix/* - for any other scope that appears on a package being handled in the run (for example
@acme/*when@acme/appis selected)
Local sibling packages discovered in the same run are skipped (they stay linked locally). After a publish in the same run, dependents still refresh those published packages to @latest.
With --push, if git push fails because the remote has commits you don't have locally, xnpm shows the missing remote commits and asks to run git pull --rebase origin <branch> then push again (default yes). Pass --yes to approve rebase recovery non-interactively. --force still enables git push --force-with-lease only if rebase recovery is declined or fails. Missing upstream is fixed automatically with git push -u origin <branch>.
Git behavior
Monorepo — all npm lifecycle steps run across all packages first, then git add / commit / push runs once at the repository root.
Multi-repo — each package/repo completes its full lifecycle (including push) before moving to the next.
If there are no git changes to commit, the CLI reports it and continues rather than failing.
Publish behavior
With --no-version-bump, xnpm checks npm before publishing each package. If that version is already on the registry, the package is skipped (same as a shell npm view pkg@version guard). Use --force-republish to override.
Before publishing any package, the CLI:
- Validates
.gitignorecovers.env*and.npmrc(when--pushis also requested) - Validates
.npmignorecovers.env*and.npmrc(creates one if missing) - Runs
npm pack --dry-run --jsonand fails if any.envor.npmrcfile would be included - Bumps the minor version (
npm version minor --no-git-tag-version) unless--no-version-bumpis set - Runs a second
npm pack --dry-run --jsonon the final package state - Publishes (
npm publish --access public) - Updates dependent packages to
@latestfor dependencies published earlier in the same run (in addition to the scoped@latestrefresh that runs on every install — see Operation order)
The pack check is the real safety net — it runs even when ignore files appear correct, because the files field in package.json can override them.
Fix configuration (xnpm.json)
Pin toolchain versions or disable automatic fix for lifecycle flows:
{
"operations": {
"autoFix": false,
"fix": {
"dependencies": true,
"devDependencies": false,
"peerDependencies": false,
"exclude": ["typescript", "@types/node"]
}
}
}Recommended monorepo publish workflow
When versions are pre-aligned and local npm install / build / test already passed:
xnpm validate --filter "@x12i/*"
npm install && npm run build && npm test
xnpm --filter "@x12i/*" --no-fix --no-install --publish --no-version-bump --reportnpmrc resolution
For each package, xnpm picks one .npmrc in this order:
- If the package folder has
.npmrc, use it - Otherwise use the invocation root
.npmrc(the folder you ran xnpm from) - Otherwise use the git-root
.npmrcwhen the repo is a git checkout - Otherwise rely on the system npm configuration (
~/.npmrc)
Root .npmrc is passed via NPM_CONFIG_USERCONFIG — it is never copied into package folders and the token is never printed. In a monorepo, run xnpm install from the repo root (or rely on git-root fallback) so registry tokens in the root .npmrc apply to every package — a personal ~/.npmrc must not override repo auth.
You do not need to export NPM_CONFIG_USERCONFIG before xnpm when the repo root has .npmrc; xnpm sets it automatically per package.
npm cache
xnpm uses an isolated cache at ~/.cache/xnpm/npm for every npm subprocess (install, publish, passthrough xnpm npm …, upgrade checks, and so on).
| Situation | xnpm behavior |
|---|---|
| ~/.npm not writable (past sudo npm) | One-line notice; xnpm uses its own cache |
| ~/.cache/xnpm/npm root-owned | Auto-fallback to ~/.cache/xnpm/npm-clean + prints chown fix |
| NPM_CONFIG_CACHE set and writable | Respected (your explicit cache wins) |
| Both caches unusable | Exit 3 (environment) before install with clear fix steps |
You do not need shell wrappers that export NPM_CONFIG_CACHE for normal project work.
Clean modes
--clean-local removes only overrides that point to packages discovered in the current run (e.g. "@x12i/core": "file:../core"), leaving unrelated overrides intact.
--clean-all removes the entire overrides object.
If overrides are modified, a second npm install runs automatically so package-lock.json and node_modules reflect the change.
There is no --clean. Using it is an error. Using both --clean-local and --clean-all together is also an error.
Override / direct-dependency conflicts
xnpm runs npm install <pkg>@latest for scoped registry dependencies (@x12i/*, @exellix/*, and scopes from workspace package names). npm rejects root-level overrides on packages that are also direct dependencies unless the override uses the $ reference form or exactly matches the direct dependency spec after @latest refresh.
Detection: xnpm validate and xnpm doctor report override-latest-conflict, override-spec-mismatch, and override-redundant findings before npm is invoked.
Auto-fix: xnpm validate --fix or xnpm install --fix (and publish flows with fix enabled) remove redundant overrides by default, or convert them to $@scope/pkg when operations.overrideFix.prefer is use-reference or the key is listed in operations.overrideFix.keepPatterns.
Example xnpm.json:
{
"operations": {
"autoFixOverrides": true,
"overrideFix": {
"prefer": "remove-when-direct-dep",
"keepPatterns": ["nanoid"]
}
}
}| Key | Default | Meaning |
|---|---|---|
| autoFixOverrides | true when --fix / publish-flow; else false | Auto-apply on install pre-flight |
| overrideFix.prefer | remove-when-direct-dep | Default strategy when multiple apply |
| overrideFix.keepPatterns | [] | Override keys never auto-removed (exact match or * suffix glob) |
Manual fix for a conflicting override on a direct dependency:
"overrides": {
"@x12i/graphenix-core": "$@x12i/graphenix-core"
}Or remove the override entry when it matches the direct dependency spec.
Tarball inspection gate (pre-install)
Before npm install, xnpm inspects new registry dependency tarballs for Phantom Gyp–style attacks (malicious binding.gyp shell substitution, decoy root index.js, fake native addons). Inspection runs in memory — nothing is written to disk except the audit log and cleared cache.
| Check | Code | What it detects |
|---|---|---|
| A | PHANTOM_GYP | binding.gyp with <!(...) shell command substitution |
| B | OVERSIZED_DECOY | Root index.js > 1 MB and > 10× declared main size |
| C | PHANTOM_GYP_NO_NATIVE_SRC | binding.gyp with no .c/.cc/.h source files |
Skipped when: same version already in node_modules, package cleared in ~/.xnpm/inspected.json with matching integrity hash, name is in the bundled trusted catalog (~1000 common unscoped packages, built from npm’s top ~2000 by search popularity), scope is in the bundled trusted catalog (~200 vendor orgs including @x12i, @exellix, @types, @nestjs, @vitejs, …), or scope is user-configured in ~/.xnpm/config.json.
Unknown components only: scoped packages outside the bundled and user lists are still inspected (e.g. a new @acme-corp/* dependency).
Regenerate bundled lists: npm run generate:trusted-catalog (fetches top 2000 npm names, splits scoped → vendors / unscoped → packages; pins in scripts/trusted-catalog-pins.json are always kept).
Tradeoff: allowlisted packages skip inspection even if a mainstream name is compromised. Use --force to re-scan everything; integrity hash changes still trigger re-inspection.
Re-inspected when: version changes, --force, or tarball integrity hash differs from cache (republished package).
On warning, xnpm prompts [y/N]. In CI (CI=true or non-TTY), default is abort (exit 1). User overrides are logged to ~/.xnpm/audit.log.
xnpm install # inspect new deps, then install
xnpm install --inspect-only # inspect only (CI pre-flight)
xnpm install --skip-inspect # skip gate (debug; logs warning)
xnpm install --force # re-inspect all (including trusted scopes)
xnpm config trust-scope @mycompany
xnpm config untrust-scope @mycompany
xnpm config list-trusted-scopes
xnpm audit --log # full inspection audit log (NDJSON)
xnpm audit --log --overrides # user-overridden warnings onlyCleared cache schema (~/.xnpm/inspected.json):
{
"version": 1,
"entries": {
"[email protected]": {
"integrity": "sha512-…",
"clearedAt": "2026-06-13T10:00:00Z",
"userOverride": false
}
}
}Additional trusted scopes live in ~/.xnpm/config.json:
{ "trustedScopes": ["@mycompany"] }Background: Phantom Gyp and the CVE gap (June 2026)
In June 2026, the Miasma worm spread through npm using a technique researchers call Phantom Gyp: a malicious binding.gyp that triggers node-gyp rebuild during npm install — with no preinstall or postinstall entry in package.json. Snyk tracked the incident as Node-gyp Supply Chain Compromise — June 2026, covering 57 affected packages across hundreds of malicious versions, all classified as Embedded Malicious Code at Critical severity — Snyk's own advisory system, not a CVE.
There is no CVE for the technique itself, and that is fundamental to how CVEs work. A CVE describes a vulnerability in specific software — a bug in npm, a flaw in node-gyp, a bad default. Phantom Gyp does not exploit a bug. Attackers weaponized gyp's <!(...) command substitution, which is working as designed. There is nothing to patch in npm or node-gyp; the feature is intentional. The same pattern applies to most supply-chain attacks: individual compromised packages get npm security advisories, but the technique of using binding.gyp to execute code does not get a CVE because npm is not broken.
| Layer | What it catches | Phantom Gyp gap |
|---|---|---|
| npm security advisories | Known-bad package versions (after filing) | Reactive — misses the window before advisories exist |
| npm audit | Packages with published advisories | Same — no proactive structural check |
| --ignore-scripts | preinstall / postinstall / lifecycle hooks | Does not stop node-gyp rebuild triggered by binding.gyp (Snyk) |
| xnpm tarball inspection | <!( in binding.gyp, decoy payloads, fake native addons | Structural — catches the technique before install, even with no advisory yet |
The reliable defenses Snyk and others recommend are: pin to known-good versions, and scan tarballs before building. That is exactly what this gate does. It would have flagged these packages during the ~two-hour window when malicious versions were live but before any advisory existed — the gap no advisory database fills.
Run logs (.xnpm/logs/)
Every xnpm run writes a log under .xnpm/logs/ in the project (gitignored). On completion, stderr prints the path; with --report or --dry-run, the summary footer includes it too. On failure, the message points at the full log for debugging.
.xnpm/latest-log.json points at the most recent log. Lifecycle runs with transaction journaling reuse the transaction id as the log filename.
Release playbooks (.xnpm/stacks/)
For monorepos with per-package test commands, version policies, changelog templates, and post-release hooks, add stack files at .xnpm/stacks/<name>.json or .yaml, then:
xnpm release --stack <name>
xnpm ask "release stack <name>"Stack config can set per-package test, versionPolicy, publish, changelog, postRelease, and dependsOn ordering. See tests/fixtures/stacks/ for an example shape.
dependsOn is honored as the release order even when package.json does not contain every operational edge — publish order is a release contract, not just a runtime import graph:
{
"stack": "jobs-reliability",
"syncInternalDepsOnPublish": true,
"restoreFileDepsAfterRelease": true,
"packages": [
{ "path": "jobs-db", "name": "@exellix/jobs-db", "versionPolicy": "patch" },
{
"path": "jobs",
"name": "@exellix/jobs",
"dependsOn": ["@exellix/jobs-db"],
"versionPolicy": "patch"
}
]
}With syncInternalDepsOnPublish: true (2.30.0+), xnpm rewrites in-stack local dependency specs (file:, link:, workspace:) to ^<publishedVersion> immediately before a downstream package's publish step, using the version just published earlier in the same stack run — then restores the original local spec afterward (restoreFileDepsAfterRelease, defaults to true when sync is enabled). Local development keeps file: links; the published package only ever sees a real registry range. This only rewrites in-stack internal deps, not every file: dependency in the package.
Validate install health (post-upgrade checks)
When node_modules is present, xnpm validate also checks:
| Finding code | Meaning |
|---|---|
| engine-node-unsupported | Installed package engines.node not satisfied by current Node |
| engine-node-warn | Possible Node engine mismatch (e.g. Vite 8 on Node 22.11) |
| native-binding-missing | Platform native binding missing (e.g. Rolldown on Windows) |
| migration-config-stale | Known breaking upgrade config hint (Tailwind 4, Vite 8) |
| build-smoke-failed | npm run build failed during --build or post-fix smoke |
| dependency-patched | Consumer patch detected (patches/, pnpm.patchedDependencies, or patch-package script) |
xnpm validate --build # run npm run build and fail validate on error
xnpm validate --unused-deps # warn on unused direct dependencies
xnpm validate --report-patches # validate, then file upstream CRs for detected patches
xnpm validate --fix # after major dep bumps, runs build smoke by default
xnpm install --fix # in-house @x12i/* / @exellix/* only
xnpm install --fix-public # opt-in public toolchain bumps (prerequisite pass)
xnpm install --fix vite # explicit package list onlyConsumer dependency patches
xnpm validate warns on patches but never removes them. --fix and install flows are unchanged.
Detects patches/*.patch (patch-package), pnpm.patchedDependencies, and patch-package lifecycle scripts.
xnpm upstream report-patches # write CR drafts + file GitHub issues
xnpm upstream report-patches --dry-run
xnpm patches strip --dry-run # preview removal plan
xnpm patches strip --confirm # explicit opt-in strip onlyDependency intelligence
xnpm deps unused [--include-dev]
xnpm deps usage <name> [--field devDependencies] [--format table|markdown|json] [--out path]Upgrade rationale
xnpm why-upgrade vite
xnpm install --fix-public --dry-run # prints Why upgrade / Why wait per packagePrivate workspace packages still skip npm registry checks; install-health findings apply regardless.
Upstream CR/FR bridge
File structured change requests from consumer repos to upstream GitHub issues (x12i/npm, @x12i/funcx, etc.) and track fix → install → verify.
Auth (token from env, gh auth login, or ~/.xnpm/config.json):
xnpm upstream auth status
xnpm upstream auth loginIf GitHub access fails, xnpm prints why and options (gh auth login, PAT export, --relay).
Submit (markdown file, inline body, or stdin — no .xnpm-upstream.yaml required when using --repo):
xnpm upstream submit --id FR-XNPM-1 --registry xnpm
xnpm upstream submit --file docs/upstream/my-fr.md --package @x12i/npm --repo x12i/npm
cat issue.md | xnpm upstream submit --stdin --package @x12i/npm --repo x12i/npm
xnpm upstream submit --relay --file fr.md --id FR-XNPM-1 --package @x12i/npm # no local GitHub tokenConsumer loop: submit → status → pull-fix → verify --comment
Owner loop: inbox → fix code → fix-done
Cursor / Codex / Claude Code agents: run xnpm cursor-init in the consumer repo to write agent rules for upstream-first dependency issues and xnpm lifecycle workflows (--hooks for optional patch guardrails). Codex loads the AGENTS.md block; Claude Code uses .claude/rules/. Run xnpm agent-deploy-guide to add docs/agent-monorepo-deploy.md to the repo (default path: .xnpm/agent-monorepo-deploy.md; use --dir or --file to override).
Full reference: docs/upstream.md
Git and npm creation mode
Creation mode is opt-in. Use it when the local package folder exists but one or more of these are missing:
- Local git repository
- Git remote link
- Remote git repository
- First npm publication
package.jsonpublish metadata
@x12i/npm still does not replace git or npm. It automates commands such as git init, git remote add origin, git commit, git push -u origin main, and npm publish --access public|restricted.
Repo layout
The CLI does not guess whether multiple packages should become one monorepo or many separate repos. When multiple packages are discovered and no git repository exists, you must pass --repo-mode monorepo or --repo-mode multi-repo.
| Mode | Behavior |
|---|---|
| monorepo | One git repo at the invocation root; one push at the end |
| multi-repo | One git repo per selected package; push per package |
Git creation
--create-git runs git init, git add ., and git commit -m "initial commit by @x12i/npm" where needed. If --git-link or --git-create-remote is also set, the CLI connects the local repo to a remote and pushes when --push is used.
--connect <url> is an alias for --git-link <url>. Both add origin when linking. If origin already exists with a different URL, the CLI fails rather than overwriting it. Use --push when you also want to push after linking.
--git-create-remote creates a remote repository through a provider API. Requires --git-provider, --git-org, and --git-visibility. The CLI checks whether the remote already exists and fails if it does (use --git-link to attach to an existing remote).
For multi-repo linking, use either:
--git-link-template "[email protected]:x12i/{repoName}.git"or a map file:
--git-map ./x12i-npm.git-map.jsonMap file format:
{
"@x12i/core": {
"remoteUrl": "[email protected]:x12i/core.git"
}
}Template variables: {packageName}, {scope}, {unscopedName}, {repoName}.
Repo name derivation removes the npm scope, lowercases, and replaces invalid characters with -. For @x12i/core-utils, {repoName} is core-utils.
Provider authentication
The CLI never prompts for secrets. Remote creation uses environment variables:
| Provider | Environment variables |
|---|---|
| GitHub | GITHUB_TOKEN or GH_TOKEN |
| GitLab | GITLAB_TOKEN |
| Bitbucket | BITBUCKET_TOKEN |
Token values are redacted from all output and reports.
First npm publication
--new-public publishes with npm publish --access public and sets publishConfig.access to public.
--new-private publishes with npm publish --access restricted and sets publishConfig.access to restricted. Unscoped package names are rejected.
Both modes:
- Publish the current
package.jsonversion (no automatic minor bump) - Default missing
versionto0.1.0 - Fail if the package already exists on npm (
npm view <name> name) - Fail if
"private": trueis set inpackage.json
--new-public / --new-private cannot be combined with --publish.
When a git remote is linked or created, package.json repository fields are updated. Monorepo packages include a directory field relative to the git root.
Creation lifecycle order
discover → select packages → validate repo mode → ensure package.json
→ create/link git → install → build → test → pack validation
→ new npm publish → commit/push → reportFor monorepo creation with publish, all packages are processed first, repository fields are updated, then one commit and one push happen at the root.
For multi-repo creation, each package completes its full git/npm lifecycle before the next.
Common creation examples
# Local monorepo git only
xnpm --create-git --repo-mode monorepo
# Link monorepo to existing remote
xnpm --create-git --repo-mode monorepo \
--git-link [email protected]:x12i/packages.git --push
# Create remote monorepo
xnpm --create-git --repo-mode monorepo \
--git-create-remote --git-provider github --git-org x12i \
--git-visibility private --repo-name packages --push
# Local git per package
xnpm --create-git --repo-mode multi-repo
# Link each package by template
xnpm --create-git --repo-mode multi-repo \
--git-link-template "[email protected]:x12i/{repoName}.git" --push
# Publish selected packages as new private npm packages
xnpm --filter "@x12i/*" --build --test --new-private --reportInvalid combinations
| Command | Error |
|---|---|
| --create-git with multiple packages, no git, no --repo-mode | Must specify monorepo or multi-repo |
| --git-create-remote without provider/org/visibility | Missing required flags |
| --git-link with --repo-mode multi-repo and multiple packages | Use --git-link-template or --git-map |
| --new-public and --new-private | Use only one |
| --new-private and --publish | Use one or the other |
Report output
Without --report, the CLI streams native npm and git output directly — exactly as if you ran the commands yourself.
With --report (or --dry-run), it suppresses noisy output and prints a summary:
@x12i/npm report
Root:
/path/to/packages
Git mode:
monorepo
Packages discovered:
3
Execution order:
1. @x12i/core
2. @x12i/utils
3. @x12i/api
Install:
succeeded: 3
failed: 0
Build:
succeeded: 3
skipped: 0
failed: 0
Test:
succeeded: 2
skipped: 1
failed: 0
Publish:
published: 3
failed: 0
Published packages:
@x12i/core 1.4.2 -> 1.5.0
@x12i/utils 2.1.0 -> 2.2.0
@x12i/api 0.7.4 -> 0.8.0
Git:
repos detected: 1
commits created: 1
pushes succeeded: 1
pushes failed: 0
Security:
gitignore updated: yes
npmignore updated: 2 packages
pack validation passed: 3 packagesOn failure:
FAILED
Package:
@x12i/api
Folder:
/path/to/packages/api
Step:
publish
Command:
npm publish --access public
Exit code:
1
Reason:
npm publish failed.
Important output:
403 Forbidden - You do not have permission to publish this package.Security
The CLI enforces publish safety regardless of ignore file configuration:
.gitignoremust exclude.env*and.npmrc.npmignoremust exclude.env*and.npmrc(auto-created if missing)npm pack --dry-run --jsonis always run before publish — if any.envor.npmrcfile would be included in the package, publishing is blocked- Tokens and token-like values are redacted from all output and reports
Exit codes
| Code | Meaning |
|---|---|
| 0 | Success |
| 1 | Failed (package, registry, validation, or command error) |
| 2 | Partial success (warnings only — e.g. publish OK but git push failed) |
| 3 | Environment / permissions — root-owned cache, global install dir, or node_modules; not a package bug |
| 4 | Approval required — xnpm ask matched a command that needs confirmation but none was given in a non-interactive context (--agent, CI=true, non-TTY); the plan is printed, nothing executes |
On macOS/Linux, exit 3 messages state clearly that xnpm ran without sudo and name the root-owned path, with chown and (for global upgrade) sudo npm install -g options.
Failure behavior
The CLI stops on the first critical failure. A package will not be published if install, build, or test failed. In a dependency chain, if one package fails, its dependents are not processed.
On multi-package --all install runs, failures include an install summary: which packages succeeded, failed, were skipped, or were never attempted — so a partial run is obvious.
Permission errors (EACCES, root-owned cache) include actionable fix text, not raw npm output alone.
If publish succeeds but git push fails (and rebase recovery was declined or unavailable), the run is reported as partial success (exit code 2). npm publish cannot be rolled back — run git pull --rebase origin main && git push origin main, or retry with xnpm ... --push --yes.
What this tool does not do
- Replace the underlying
npmorgitbinaries (it orchestrates and passthroughs to them) - Implement its own package manager or dependency resolution
- Use an LLM for
xnpm ask(resolution is deterministic catalog matching only) - Cover every possible npm/git phrase in
xnpm ask(unknown input fails safely with suggestions) - Manage npm login or store credentials interactively
- Create git tags
- Run operations in parallel
- Support
--messagefor custom commit messages (release flows; templates:{name},{version},{shortName})
License
MIT — 100% free for personal and commercial use. See LICENSE.
