feat: botmux update 支持本地 checkout 走 git pull + 构建 + 重启(CLI 与 Dashboard) - #930
Conversation
复审修复已推(commit 072d5f5)按复审意见收敛 4 处边界:
已知语义(本 PR 不扩范围):restart intent 仍按 version 判 update/manual,同 tag 不同 SHA 会落 manual intent,只影响 owner「已更新到 vX」DM 的措辞,不影响更新/build/lease/实际重启。 测试: |
514bb3c to
dec2745
Compare
|
建议合并前再收口一处本地 checkout 的事务边界:
建议把成功构建的绝对 checkout(最好连同 build 后 HEAD)作为 server-side update plan 固定下来, 另一个相关边界是 这是自动评审的初步意见,最终以维护者审阅为准。 |
已收口两处并发边界(commit 9c2a21b)A. run→restart 之间 wrapper 漂移(TOCTOU)
无 pending plan 的纯手动重启仍按 wrapper 实时解析(cli.js 不存在则回退 running root)。决策逻辑抽成纯函数 B. CLI 本地更新未进共享锁 测试: 已知语义(不扩范围):restart intent 仍按 version 判 update/manual,同 tag 不同 SHA 落 manual intent,只影响通知措辞。 |
自动评审补充(初步意见,最终以维护者审阅为准)感谢新一轮的
代码层这两点我们没有新增阻断性意见。 合并前有一个前置项(不是纯机械解冲突,建议一并处理):本分支现落后 master 较多, 因此 rebase 时除了删掉本地的 CLI 侧的 再次说明这是自动评审的初步意见,最终以维护者审阅为准。 |
9c2a21b to
afb9c22
Compare
本地开发从源码运行(有 .git/src)现也能一键更新:定位 checkout → git pull --ff-only → pnpm build → 从本 checkout 重启,CLI 与 Dashboard 都支持。 定位/干净检查/更新步骤/重启目标决策抽进 src/utils/local-dev-update.ts 共用。 关键不变量与边界: - 脏工作区 fail closed(不自动 stash);git pull --ff-only(分叉/冲突报错停下); dist/ 被 gitignore,故 build 步不可省。 - run→restart 目标一致性:/api/update/run 成功后把本次构建的 checkout 绝对路径 + 构建后 HEAD 固定为 server 端 pendingLocalDevRestart;/api/update/restart 经纯函数 resolveLocalDevRestartTarget 复验(cli.js 缺失→update_target_unavailable、HEAD 漂移→update_target_drifted),且都在 claim restart lease 之前 fail closed,杜绝 并发 use:here 改指 wrapper 导致的“更新 B 却重启 C/A”。 - CLI cmdUpgradeLocalDev 的 clean-check + pull + build 进与 Dashboard 同一把跨进程 update 锁(withFileLockSync(globalInstallUpdateLockTarget())),restart 走各自 lease。 安全:Dashboard 派生的 git/pnpm 子进程走 managed-spawn.ts 的 runLocalDevStep, env 用 redactChildEnv(process.env)——与 start-bot/stop-bot/runGlobalInstall 同一条 不变量,杜绝 dashboard 的飞书 H5 凭证(APP_SECRET 等)随子进程外泄;denylist 仍保留 PATH/HOME,git/pnpm 正常解析。dashboard.ts 不再直接 import node:child_process (由结构性测试 test/dashboard-managed-spawn.test.ts 守护)。 测试:local-dev-update(含真实 git 仓库集成 + resolveLocalDevRestartTarget 5 例覆盖 B→C 漂移回归)、dashboard-managed-spawn 结构测试、cli-update-alias、 dashboard-update-action 全绿;pnpm build + tsc --noEmit 通过。 Co-authored-by: Claude <noreply@anthropic.com>
afb9c22 to
6359e3a
Compare
|
🚀 Released in v3.16.0 |
背景 / 为什么
原来
botmux update(=upgrade别名)只认 npm/pnpm/bun 全局安装。跑在本地checkout(有
.git/src)时:pull + 构建后重启」。
本 PR 给「本地开发从源码运行」这种部署补上一键更新:定位 checkout → git pull
--ff-only → 构建 → 重启,CLI 与 Dashboard 都支持。
改了什么
共享层
src/utils/local-dev-update.ts把 checkout 定位、git 干净检查、HEAD 读取、更新步骤定义抽成共享纯/薄函数,CLI 与
Dashboard 共用,避免逻辑漂移:
~/.botmux/bin/botmux里指向的dist/cli.js→ 往上两级得 checkout 根(那才是用户实际敲
botmux跑的目录),拿不到回退到本进程安装根,再校验是 git 工作树;
localDevUpdateSteps():git pull --ff-only→pnpm build(重启单独由各调用方施加)。CLI(
src/cli.ts)cmdUpgrade检测到本地 checkout 走新分支cmdUpgradeLocalDev:git status --porcelain有未提交改动 → fail closed 中止并列出改动(不自动 stash);git pull --ff-only(分叉/冲突直接报错停下,不自动 merge);pnpm build(关键:dist/被 gitignore,只 pull 不 build 重启后跑的还是旧代码);node <checkout>/dist/cli.js restart从本 checkout 重启(不走 PATH,避免被更靠前的全局 botmux 抢先)。Dashboard 后端(
src/dashboard.ts)POST /api/update/run:local-dev 分支不再拒绝,改为在既有 install 锁内执行git 干净检查(脏工作区返回
dirty_worktree+ 文件列表,不 stash)→git pull --ff-only→pnpm build(300s 超时、捕获输出);用 HEAD 前后 sha 判断changed;版本走
resolveCurrentVersion(git describe)。复用既有updateInFlight/ 跨进程锁 / restart-lease 门禁;GET /api/update/status:新增localDevUpdatable(本地开发且定位到 git 工作树才为 true);POST /api/update/restart:local-dev 从resolveLocalDevCheckoutDir()重启,与 CLI 一致;rollback对 local-dev 仍拒绝(本地开发无回滚语义)。Dashboard 前端(
settings-page.tsx/i18n.ts)localDevUpdatable时按钮启用,文案「本地更新(git pull + 构建 + 重启)」,走既有run→restart 两步流;
dirty_worktree错误在 UI 回显改动文件列表;影响面
改动集中在版本更新链路:CLI
cmdUpgrade+ Dashboard/api/update/*+ 更新卡片 UI。git/pnpm子进程在 win32 走shell:true解析.cmdshim;daemon 实际跑在 Linux,路径/进程调用两边都已考虑。
测试
pnpm build+pnpm exec tsc --noEmit通过;test/local-dev-update.test.ts(11 例):wrapper 文本解析 + 目录推导 + 更新步骤定义,并用真实 git 仓库验证
isGitWorktree/gitPorcelainStatus(干净/脏)/gitHeadSha(跨 commit 变化);test/cli-update-alias.test.ts:按新本地分支行为更新断言(update==upgrade别名契约不变);test/dashboard-update-action.test.ts现有 8 例仍通过(响应字段形状未变);distbundle;git pull --ff-only快进(隔离仓库验证)、wrapper 定位到正确 checkout。
待 live 验证
Dashboard「本地更新」按钮的端到端点击需要一个「从本 checkout 跑起来的 dashboard」,
部署会重启 daemon,留到 review 后 live 验证并补 UI 截图。