@ranger1/dx
v0.1.91
Published
一个可安装的 Node.js CLI,用于管理符合约定的 pnpm + nx monorepo 项目的构建/启动/数据库/部署等流程。
Downloads
3,330
Readme
dx
一个可安装的 Node.js CLI,用于管理符合约定的 pnpm + nx monorepo 项目的构建/启动/数据库/部署等流程。
本工具通过项目内的 dx/config/* 配置文件来驱动命令执行:你可以把它理解成「带环境变量分层 + 校验 + 命令编排能力的脚本系统」。
安装
必须全局安装,并始终使用最新版本:
pnpm add -g @ranger1/dx@latest安装后即可在任意目录使用:
dx --help
dx status升级到最新版本:
pnpm update -g @ranger1/dx使用条件(必须满足)
- Node.js:>= 20
- 包管理器:pnpm(dx 内部会调用
pnpm) - 构建系统:Nx(dx 默认命令配置里大量使用
npx nx ...) - 环境加载:建议项目依赖
dotenv-cli(dx 会用pnpm exec dotenv ...包裹命令来注入.env.*) - 项目结构:推荐按
apps/backend/apps/front/apps/admin-front这类布局组织;如有自定义目录结构,请通过dx/config/commands.json适配
如果你的 monorepo 不完全一致,也能用:关键是你在 dx/config/commands.json 里把命令写成适配你项目的形式。
项目配置(必须)
dx 会从当前目录向上查找 dx/config/commands.json 来定位项目根目录。
你需要在项目根目录提供:
dx/
config/
commands.json
env-layers.json
env-policy.jsonc可选覆盖:
- 环境变量:
DX_CONFIG_DIR=/abs/path/to/config - 参数:
dx --config-dir /abs/path/to/config ...
全局安装场景下,如果你不在项目目录内执行,也可以通过 DX_CONFIG_DIR / --config-dir 显式指定配置目录(目录下需要存在 commands.json)。
示例:
# 在任意目录执行
dx --config-dir /path/to/your-repo/dx/config status
# 或
DX_CONFIG_DIR=/path/to/your-repo/dx/config dx status配置文件写法
1) dx/config/commands.json
这是核心文件,定义了 dx 各命令要执行的 shell 命令,支持:
- 单命令:
{ "command": "..." } - 并发:
{ "concurrent": true, "commands": ["build.front.dev", "build.admin.dev"] } - 串行:
{ "sequential": true, "commands": ["build.backend.prod", "build.sdk"] } - 环境分支:如
build.backend.dev/build.backend.prod(dx 会根据--dev/--prod/--staging/...选择) - dotenv 包裹:配置里带
"app": "backend"时,dx 会按env-layers.json拼出 dotenv 层并用pnpm exec dotenv ... -- <command>执行
常见字段(单命令配置):
{
"command": "npx nx build backend --configuration=production",
"app": "backend", // 可选:用于选择 dotenv 层,并决定需要校验的 env 变量组
"ports": [3000], // 可选:用于 start 类命令,冲突时自动清理
"description": "构建后端(生产环境)",
"dangerous": true, // 可选:危险操作需要确认
"skipEnvValidation": true, // 可选:跳过 env 校验(仍可加载 dotenv 层)
"env": { "NX_CACHE": "false" } // 可选:注入额外环境变量
}命令路径引用(并发/串行的 commands 数组)使用点号字符串,例如:
{ "concurrent": true, "commands": ["build.shared", "build.front.dev"] }2) dx/config/env-layers.json
用于定义不同环境下加载哪些 .env.* 文件(顺序 = 覆盖优先级)。格式:
{
"development": [".env.development", ".env.development.local"],
"staging": [".env.staging", ".env.staging.local"],
"production": [".env.production", ".env.production.local"],
"test": [".env.test", ".env.test.local"],
"e2e": [".env.e2e", ".env.e2e.local"]
}3) dx/config/env-policy.jsonc
统一的 env 策略配置(jsonc),同时覆盖:
- env 文件布局约束(禁用
.env/.env.local;禁止子目录散落.env*,仅允许少数特例路径) - 机密键策略:机密 key 只能在
.env.<env>.local放真实值;对应的.env.<env>必须存在同名 key 且为占位符__SET_IN_env.local__ - 必填校验:按环境 + 按 target(端)定义 required keys,执行命令前校验是否缺失/仍为占位符
target(端)不写死,由 env-policy.jsonc.targets 定义;commands.json 里的 app 通过 env-policy.jsonc.appToTarget 映射到某个 target。
注:env-policy.jsonc 为必需配置;未提供时 dx 将直接报错。
示例工程
查看 example/:包含一个最小可读的 dx/config 配置示例,以及如何在一个 pnpm+nx monorepo 中接入 dx。
PR Review Loop(自动评审-修复闭环)
仓库内提供了基于 Codex Skill 的 PR 评审自动化工作流:并行评审 -> 聚合结论 -> 生成修复清单 -> 自动修复 -> 再评审,最多循环 3 轮,用于让 PR 更快收敛。
什么时候用
- PR 变更较大、想要更系统地覆盖安全/性能/可维护性问题
- 希望在 CI 通过前提下,把评审建议落成可执行修复清单(fixFile)
- 希望避免同一个问题在不同轮次被反复提出(Decision Log)
如何运行
在 Codex 会话中触发该技能:
使用 $pr-review-loop 对 PR #<PR_NUMBER> 执行审核闭环技能入口与说明见:
codex/skills/pr-review-loop/SKILL.mdcodex/skills/pr-review-loop/references/agents/*.md
工作流概览
- 预检(
pr-precheck):先做编译/基础 gate,不通过则终止流程 - 获取上下文(
pr-context):生成本轮上下文缓存contextFile与runId - 并行评审(reviewers):按
./reviewer/*-reviewer.md并行审查并产出 reviewFile - 聚合(
pr-review-aggregate模式 A):合并评审结果、去重、发布 Review Summary、生成fixFile - 修复(
fixer):按fixFile执行修复并产出fixReportFile - 发布修复报告(
pr-review-aggregate模式 B)
缓存文件(项目内 ./.cache/)
该流程中间产物写入 ./.cache/,并在各阶段传递相对路径:
./.cache/pr-context-pr<PR>-r<ROUND>-<RUN_ID>.md(contextFile)./.cache/review-<ROLE_CODE>-pr<PR>-r<ROUND>-<RUN_ID>.md(reviewFile)./.cache/fix-pr<PR>-r<ROUND>-<RUN_ID>.md(fixFile)./.cache/fix-report-pr<PR>-r<ROUND>-<RUN_ID>.md(fixReportFile)
Decision Log(跨轮次决策日志)
- 文件:
./.cache/decision-log-pr<PR_NUMBER>.md - 作用:记录每轮 Fixed/Rejected 结论,后续轮次用于过滤重复问题
- 规则:默认 append-only,保留历史决策用于收敛
命令
dx 的命令由 dx/config/commands.json 驱动,并且内置了一些 internal runner(避免项目侧依赖任何 scripts/lib/*.js):
internal: sdk-build:SDK 生成/构建internal: backend-package:后端打包internal: backend-artifact-deploy:后端制品构建、上传与远端部署internal: start-dev:开发环境一键启动internal: pm2-stack:PM2 交互式服务栈(支持端口清理/缓存清理配置)
常用示例:
dx start backend --dev
dx start all --dev
dx build backend --prod
dx build sdk --dev
dx db generate
dx db migrate --dev --name init
dx db deploy --prod -Y
dx deploy front --staging
dx deploy backend --prod
dx lint
dx test e2e backend apps/backend/e2e/auth
dx test e2e quantify apps/quantify/e2e/health/health.e2e-spec.ts命令约束摘要:
- 对声明了
requiresPath: true的 E2E target,dx test e2e <target>必须提供文件或目录路径,禁止无路径或all全量执行 dx test e2e all不受支持,必须显式指定 target 和路径dx db migrate仅允许在--dev环境创建迁移;非开发环境请使用dx db deploydx start未指定服务时默认是开发套件,仅允许--devdx start下的单层目标(如stagewise-front)默认仅支持--devdx build显式传入环境标志时,必须是该 target 实际支持的环境
dx start stack 配置详解(PM2 交互式服务栈)
从 0.1.78 起,dx start stack 推荐完全由 dx/config/commands.json 配置驱动,不再依赖硬编码服务列表。
最小可用配置:
{
"start": {
"stack": {
"internal": "pm2-stack",
"interactive": true,
"description": "PM2 交互式服务栈",
"stack": {
"ecosystemConfig": "ecosystem.config.cjs",
"services": ["backend", "front", "admin"],
"preflight": {
"killPorts": [3000, 3001, 3500],
"pm2Reset": true
}
}
}
}
}完整字段说明:
start.stack.internal- 固定为
pm2-stack,表示启用内置 PM2 交互式 runner。
- 固定为
start.stack.interactive- 建议设为
true,用于标记这是交互式命令(便于团队识别)。
- 建议设为
start.stack.stack.ecosystemConfig- PM2 配置文件路径;支持相对路径(相对项目根目录)或绝对路径。
- 默认值:
ecosystem.config.cjs。
start.stack.stack.pm2Bin- PM2 命令前缀,默认
pnpm pm2。如果团队使用全局 pm2,可改为pm2。
- PM2 命令前缀,默认
start.stack.stack.services- 交互命令(
r/l/s)可操作的服务名单。 - 示例:
["backend", "front", "admin"]。
- 交互命令(
start.stack.stack.preflight.killPorts- 启动前自动清理占用端口列表。
- 这就是“某些端口被占用时自动处理”的核心配置。
start.stack.stack.preflight.forcePortCleanup- 是否强制清理端口占用,默认
true。
- 是否强制清理端口占用,默认
start.stack.stack.preflight.pm2Reset- 启动前是否执行 PM2 状态重置(
delete all/kill/ 状态文件清理),默认true。
- 启动前是否执行 PM2 状态重置(
start.stack.stack.preflight.cleanPaths- 启动前需要删除的缓存路径列表(相对项目根目录)。
- 适合清理
.next、dist、.vite等缓存,避免脏状态。
start.stack.stack.preflight.cleanTsBuildInfo- 是否清理
*.tsbuildinfo,默认true。
- 是否清理
start.stack.stack.preflight.cleanTsBuildInfoDirs- 扫描
*.tsbuildinfo的目录列表。
- 扫描
交互命令保持不变:
r <service>重启服务l <service>查看日志s <service>停止服务list查看状态monit打开 PM2 监控q停止所有服务并退出
推荐实践:
- 将
services与ecosystem.config.cjs里的 app 名保持一致,避免交互命令找不到服务。 killPorts只配置开发态常驻端口,避免误杀不相关进程。- 如果项目不是
apps/front/apps/admin-front结构,请按实际目录改cleanPaths与cleanTsBuildInfoDirs。
deploy 行为说明
从 0.1.9 起,dx deploy <target> 不再在 dx 内部硬编码执行任何 nx build/sdk build 等前置步骤。
- 需要的前置构建(例如
shared、api-contracts、OpenAPI 导出、后端构建等)应由项目自己的 Nx 依赖图(dependsOn/项目依赖)或 Vercel 的buildCommand负责。 - 这样 dx deploy 不会强依赖
apps/sdk等目录结构,更容易适配不同 monorepo。
backend 制品发布
当 dx/config/commands.json 的 deploy.backend.internal 配置为 backend-artifact-deploy 时,dx deploy backend 走内置的后端制品发布流程,而不是 Vercel 部署。
常用命令:
dx deploy backend --prod
dx deploy backend --build-only
dx deploy backend --prod --skip-migration最小示例配置:
{
"deploy": {
"backend": {
"internal": "backend-artifact-deploy",
"backendDeploy": {
"build": {
"app": "backend",
"distDir": "dist/backend",
"versionFile": "apps/backend/package.json",
"commands": {
"development": "npx nx build backend --configuration=development",
"staging": "npx nx build backend --configuration=production",
"production": "npx nx build backend --configuration=production"
}
},
"runtime": {
"appPackage": "apps/backend/package.json",
"rootPackage": "package.json",
"lockfile": "pnpm-lock.yaml",
"prismaSchemaDir": "apps/backend/prisma/schema",
"prismaConfig": "apps/backend/prisma.config.ts",
"ecosystemConfig": "ecosystem.config.cjs"
},
"artifact": {
"outputDir": "release/backend",
"bundleName": "backend-bundle"
},
"remote": {
"host": "deploy.example.com",
"port": 22,
"user": "deploy",
"baseDir": "/srv/example-app"
},
"startup": {
"mode": "pm2",
"serviceName": "backend"
},
"deploy": {
"keepReleases": 5,
"installCommand": "pnpm install --prod --no-frozen-lockfile --ignore-workspace",
"prismaGenerate": true,
"prismaMigrateDeploy": true
},
"verify": {
"healthCheck": {
"url": "http://127.0.0.1:3005/api/v1/health",
"timeoutSeconds": 10,
"maxWaitSeconds": 24,
"retryIntervalSeconds": 2
}
}
}
}
}
}固定远端目录协议:
<baseDir>/releases/<version-name><baseDir>/current<baseDir>/shared/.env.<environment><baseDir>/shared/.env.<environment>.local<baseDir>/uploads/<bundle-file>
运行时制品约束:
- 生成的 release
package.json默认只保留运行时依赖;如果应用把prisma放在devDependencies,dx 会自动把它提升进 release 依赖,保证远端prisma generate/prisma migrate deploy可执行。 - 打包前会递归扫描整个 staged payload;任意层级出现
.env*文件都会直接失败,避免把环境文件误打进制品。 - 所有本地路径字段都会被解析为相对项目根目录,并且必须留在项目根目录内;例如
build.distDir、runtime.prismaSchemaDir、artifact.outputDir不能通过../逃逸到仓库外。 remote.baseDir必须是绝对路径,并且只能包含/、字母、数字、.、_、-;不要使用空格或 shell 特殊字符。
部署后验活与成功摘要:
dx deploy backend在远端启动完成后,会继续校验current软链接是否切到本次 release。- 如果
startup.mode是pm2,还会校验 PM2 进程是否存在,以及 PM2 中的APP_ENV/NODE_ENV是否与部署环境一致。 - 如果配置了
verify.healthCheck,dx 会在远端对健康检查地址做重试探测;适合处理不同项目启动时间不一致的问题。 - 成功后,dx 会在本地 CLI 回显一段摘要,默认包含:
- release 版本名
- current 当前指向的 release 目录
- service/status
- APP_ENV / NODE_ENV
- health 地址
示例成功输出:
✅ 后端部署成功: backend-v0.0.24-20260313-174425
🚀 [deploy-summary] current=/opt/work/noveai/releases/backend-v0.0.24-20260313-174425
🚀 [deploy-summary] service=noveai-backend status=online
🚀 [deploy-summary] APP_ENV=staging NODE_ENV=production
🚀 [deploy-summary] health=http://127.0.0.1:3005/api/v1/healthverify.healthCheck 配置说明:
url:健康检查地址。未配置时,dx 会跳过 health check,但仍会执行current/ PM2 验活。timeoutSeconds:单次curl请求超时。maxWaitSeconds:从启动后开始,health check 最长等待多久;超过这个时间仍未成功则失败。retryIntervalSeconds:两次 health check 之间的等待间隔。
推荐配置:
{
"verify": {
"healthCheck": {
"url": "http://127.0.0.1:3005/api/v1/health",
"timeoutSeconds": 10,
"maxWaitSeconds": 24,
"retryIntervalSeconds": 2
}
}
}说明:
timeoutSeconds控制“单次请求能等多久”。maxWaitSeconds控制“服务从启动到 ready 最多允许多久”。retryIntervalSeconds越小,ready 后越快通过;越大,请求频率越低。
SSH 认证说明:
dx deploy backend当前直接调用系统ssh/scp,不会单独解析sshKey、identityFile之类的 dx 配置项。- 因此,发布使用哪把私钥,取决于本机 OpenSSH 的默认认证行为,例如
ssh-agent、~/.ssh/config、默认私钥文件等。 - 如果你已经在
~/.ssh/config中配置了主机别名(例如Host ai-staging),推荐直接把backendDeploy.remote.host写成这个别名,让 OpenSSH 自动匹配对应的HostName、User、Port、IdentityFile。
例如本机 ~/.ssh/config:
Host ai-staging
HostName 1.2.3.4
User deploy
Port 22
IdentityFile ~/.ssh/your_staging_key对应的 dx/config/commands.json:
{
"deploy": {
"backend": {
"internal": "backend-artifact-deploy",
"backendDeploy": {
"remote": {
"host": "ai-staging",
"port": 22,
"user": "deploy",
"baseDir": "/srv/example-app"
}
}
}
}
}注意:
remote.host写成别名后,dx 仍会显式传入remote.user和remote.port;如果这两个值与~/.ssh/config中的User/Port不一致,命令行参数会覆盖 SSH config。- 最稳妥的做法是让
remote.user、remote.port与~/.ssh/config保持一致,或者都统一以 SSH config 中的值为准后再同步到 dx 配置。
依赖关系约定
dx 不负责管理「工程之间的构建依赖关系」。如果多个工程之间存在依赖(例如 front/admin 依赖 shared 或 api-contracts),必须由 Nx 的依赖图来表达并自动拉起:
- 使用 Nx 的项目依赖(基于 import graph 或
implicitDependencies) - 使用
nx.json的targetDefaults.dependsOn/targetDependencies
dx 只会执行你在 dx/config/commands.json 中配置的命令,不会在执行过程中额外硬编码插入依赖构建。
给 Nx target 注入版本信息(可选)
本包提供 dx-with-version-env,用于在 nx:run-commands 中注入版本/sha/构建时间等环境变量:
{
"command": "dx-with-version-env --app front -- next build"
}支持的 app:backend / front / admin。
约束与假设
当前版本面向 pnpm + nx 的 monorepo,默认假设:
- 使用 pnpm + nx
- 项目布局包含
apps/backend、apps/front、apps/admin-front(如有差异,通过dx/config/commands.json适配) - 版本注入脚本
dx-with-version-env默认支持 app:backend/front/admin
发布到 npm(准备工作)
如果你准备公开发布:
- 注意:npm 上的包名
dx很可能已被占用;更稳妥的是使用 scope(例如@ranger1/dx)。 - 发布前需要把
package.json里的private: true去掉,并补全version/license/repository等字段。 - 发布命令(公开包):
npm publish --access public --registry=https://registry.npmjs.org