安装
需要 Node.js ≥ 18.18(execa 的真实下限),以及至少装一个包管理器。
git clone https://github.com/hanqindylan/x-pm.git
cd x-pm
npm install
npm run build
npm link
npm i -g github:hanqindylan/x-pm
装完会有两个命令:x 和 xgo。卸载用 npm unlink -g x-pm。
npm run build 再 npm link。
dist/ 在 .gitignore 里,不会进仓库,别人 clone 后要自己构建。
命令总览
| 命令 | 作用 |
|---|---|
x i | 安装依赖 |
x a <pkg> | 添加依赖,-D 走 devDependencies |
x r <pkg> | 移除依赖 |
x up | 更新依赖 |
x ls | 列出顶层依赖 |
x run <script> / x <script> | 运行 package.json 脚本 |
x exec <cmd> | 执行本地可执行文件 |
x search <kw> | 远程搜索包(默认国内源) |
x find <kw> | 本地搜索已安装的包 |
x where <pkg> | 精确定位包目录和可执行文件 |
xgo <cmd> | 统一 npx / pnpm dlx / bun x / yarn dlx |
x use <pm> | 写入 packageManager 字段并切换 |
别名:i=install、a=add、r=remove、
up=update、ls=list、s=search、f=find。
还可以用 .xrc.json 的 aliases 加自己的。
全局选项(任何命令都能带):
x dev --port 3000、x i --legacy-peer-deps、
x a axios -- --registry 内网源 都不会丢参数。
包管理
$ x i
$ x i --frozen-lockfile
别名 install / in。对应 <pm> install。
$ x a axios lodash # 一次加多个
$ x a -D typescript # 开发依赖
$ x a axios --save-exact # 原样透传
选项会被自动排到包名之前,所以 x a axios -D 也会变成规范的 -D axios。
$ x r lodash
别名 remove / rm / uninstall。
对应 npm / pnpm / bun 的 update;yarn 用的是
upgrade,x 会自动翻译,不用你记。
对应 <pm> ls --depth=0,只列出直接依赖,不展开依赖树。
$ x run dev
$ x dev --port 3000 # 简写,参数透传
简写规则:任何没被识别成 x 命令的词,都当作 package.json 脚本去跑。
所以 x dev ≡ x run dev。
$ x exec eslint .
和 xgo 的区别:exec 只走包管理器自带的
exec,强制使用项目本地环境,不会去 PATH 或 dlx 找。
$ x use pnpm
✔ 已切换到 pnpm
packageManager: (无) → pnpm@10.14.0
! 目录里还残留其他包管理器的锁文件:package-lock.json
提示: packageManager 字段优先级最高,不删也不影响使用
x 会写完整版本号(通过执行 <pm> --version 获取);拿不到时只写包名。
发现其它锁文件时只提示不删除——删文件这种事不替你做主。
搜索与查找
$ x search react
源: registry.npmmirror.com 当前项目: npm
┌───────────┬────────┬────────────────────────────┬──────────────┐
│ 包名 │ 版本 │ 描述 │ 发布者 │
├───────────┼────────┼────────────────────────────┼──────────────┤
│ react │ 19.3.1 │ React is a JavaScript li… │ GitHub Actions│
└───────────┴────────┴────────────────────────────┴──────────────┘
安装:x a react
底层接口是 GET {registry}/-/v1/search?text=…&size=…,
npmmirror 和官方源格式一致。
$ x find eslint --local
┌────────────┬────────┬──────┬────────────┬──────────────────────────┐
│ 包名 │ 版本 │ 位置 │ 类型 │ 路径 │
├────────────┼────────┼──────┼────────────┼──────────────────────────┤
│ eslint │ 9.17.0 │ 本地 │ dependency │ ~/proj/node_modules/… │
└────────────┴────────┴──────┴────────────┴──────────────────────────┘
共 1 个包
扫描范围:当前项目 node_modules、monorepo workspace 里的 node_modules、以及全局目录。
@scope 一层,不递归,大仓库也是毫秒级。
结果按 node_modules 的 mtime 缓存——你装了新包,缓存自动失效。
只有 --deep 才会递归进入每个包自己的 node_modules。
$ x where eslint
eslint (来源: pnpm-lock.yaml)
├─ 包目录
本地: /repo/node_modules/eslint
│
├─ 可执行文件
本地: /repo/node_modules/.bin/eslint
PATH: /usr/local/bin/eslint
│
└─ 元信息
版本: 9.17.0
来源: pnpm
主页: https://eslint.org
$ x where eslint --bin | head -1
/repo/node_modules/.bin/eslint
跨平台:内部封装 which,Windows 自动处理 .cmd / .exe 后缀和 PATHEXT。
xgo 统一 npx
xgo 顶替 npx / pnpm dlx /
yarn dlx / bun x。x go <cmd> 是等价的写法。
$ xgo cowsay hi
提示: 本地与 PATH 都没有 cowsay,使用 pnpm dlx 执行
$ xgo --pm pnpm vite --host
执行顺序
sudo 规则
x 永远不会自动加 sudo。只有两条路径会提权:
- 你显式传了
--sudo -
执行失败、报错里有
EACCES/EPERM/permission denied,并且你在提示里回答了y
配置 .xrc.json
放在项目根目录,也可以放在上层目录——x 会用 find-up 向上找。
{
"registry": "https://registry.npmmirror.com",
"defaultPM": "pnpm",
"searchLimit": 10,
"aliases": {
"s": "search",
"f": "find"
}
}
| 字段 | 说明 |
|---|---|
registry | 搜索用的源地址 |
defaultPM | 锁文件缺失时的兜底包管理器 |
searchLimit | x search 默认返回条数 |
aliases | 自定义命令别名 |
包管理器检测规则
从高到低逐级判断,命中即停:
支持 packageManager 的各种写法:
pnpm、pnpm@9.15.0、
yarn@4.1.0+sha512.xxx 都认。
每次执行都会在 stderr 打印一行说明:
[x] 检测到 pnpm-lock.yaml,使用 pnpm。
国内源说明
x search 默认走国内源 registry.npmmirror.com,因为官方源在国内经常超时。
优先级从高到低:
$ x search react --source npm # 临时用官方源
$ export X_REGISTRY=https://registry.npmmirror.com
常见问题
它会替代包管理器吗?
不会。x 只是翻译命令,真正的活还是 npm / pnpm / bun / yarn 在干。 所有参数原样透传,所以包管理器的任何特性你都用得上。
为什么有 stderr 上的那行 [x] 检测到…
这是检测提示,说明 x 为什么选了某个包管理器。它走 stderr,
所以不会污染 --json 等需要管道消费的 stdout 输出。
x dev 会和某个包重名吗?
有理论上的可能。比如你的脚本叫 i 或 search,
那 x i 会被解析成安装命令。规避办法:给这类脚本起个不冲突的名字,
或者改用完整的 x run i。
monorepo 里怎么用?
在任意子目录执行 x 都会向上找到项目根再检测。
x find 也会把 workspace 包里的
node_modules 一起扫,位置标为 workspace。
改了代码怎么生效?
npm run build && x --help。
因为是 npm link 装的软链,不用重装。
记住顺序是 build 在前、link 在后。
开发
npm install # 装依赖
npm run dev # tsx 直接跑 src/index.ts
npm run lint # tsc --noEmit 类型检查
npm test # vitest
npm run build # tsup 打包到 dist/
技术栈:TypeScript 5(严格模式)+ 全 ESM,
cac 生成帮助、execa 执行子进程、
picocolors 着色、find-up 找配置、
which 跨平台定位、tsup 打包、vitest 测试。
GitHub 源码 → MIT