Beads 启动钩子实战:用 bd-version-check.sh 让 AI Agent 自动感知 bd 升级
2026/9/13 12:29:02 网站建设 项目流程

Beads 启动钩子实战:用 bd-version-check.sh 让 AI Agent 自动感知 bd 升级

【免费下载链接】beadsBeads - A memory upgrade for your coding agent项目地址: https://gitcode.com/GitHub_Trending/beads1/beads

Beads 仓库中的examples/startup-hooks/目录提供了一个开箱即用的启动钩子脚本bd-version-check.sh,用于解决一个真实痛点:当 bd(beads 命令行工具)升级后,AI 编码 Agent 无法自动得知"发生了什么变化",从而可能继续沿用旧工作流。本文以该脚本为主体,结合bd info --whats-newbd hooks list/install的源码实现,讲解如何把"升级感知"能力挂载到 Claude Code、GitHub Copilot、Cursor 等任意支持启动脚本的 Agent 环境中,并逐段剖析脚本原理与边界情况处理。

背景:为什么 Agent 需要"升级感知"

bd 作为 beads 项目的 CLI 工具,其迭代速度较快,bd info --whats-new命令专门为 Agent 提供了"最近 3 个版本的变更摘要"(见 cmd/bd/info.go)。但问题是:Agent 无法自己发现 bd 已经升级。它只有在被明确告知、或手动执行相关命令时才会看到变更,而这通常发生在用户介入之后,导致 Agent 的工作流与新版 bd 的能力脱节。

bd-version-check.sh的思路非常直接:把版本检测做成一个幂等、零侵入的启动钩子,在每次 AI 会话(或进入 beads 项目时)自动比对"上次见过的版本"与"当前版本",一旦发现升级就打印变更横幅,同时顺带检查并自动更新过期的 git hooks——全程无需修改 bd 本身的任何代码(README 中明确标注 "Works today - no bd code changes required!",见 examples/startup-hooks/README.md)。

脚本功能总览

bd-version-check.sh(完整实现见 examples/startup-hooks/bd-version-check.sh)提供的核心能力:

  • 自动检测两次会话之间 bd 版本是否变化;
  • 版本变化时自动展示bd info --whats-new的输出;
  • 自动检查并更新过期的 git hooks(即使版本未变化也会执行);
  • 将"上次见过的版本"持久化在项目级文件.beads/metadata.json中;
  • 在非 beads 项目、bd 未安装等场景下静默退出,可安全地放入全局 shell 初始化文件。

脚本刻意保持"轻量 + 静默失败"的设计哲学:它不会在任何无关环境下产生噪音,也绝不阻断 Agent 的会话启动流程。

前置要求

依赖说明缺失时的行为
bd(beads)必须已安装且位于 PATH 中静默退出(command -v bd检测失败即 return)
jq用于读取/写入.beads/metadata.json,macOS 用brew install jq,Ubuntu 用apt-get install jq打印警告⚠️ jq not found...后静默退出
.beads目录必须存在于当前项目根目录静默退出([ ! -d ".beads" ]直接返回)

其中.beads目录是 beads 项目的核心标记:它存放数据库文件beads.db、JSONL 导出文件beads.jsonl以及本脚本使用的metadata.json。判断"当前是否处于 beads 项目"完全依赖该目录的存在性,这也是脚本能被安全放进全局~/.bashrc/~/.zshrc的前提——非 beads 项目里它一行输出都不会有。

安装与两种运行方式

脚本支持两种调用方式,README 推荐优先使用source(见 examples/startup-hooks/README.md):

# 方式一:source 执行(推荐,可被 .bashrc 复用环境) source examples/startup-hooks/bd-version-check.sh # 方式二:直接以子进程执行 bash examples/startup-hooks/bd-version-check.sh

两种方式的差异在于:source将脚本内容直接注入当前 shell,脚本末尾的return 0 2>/dev/null || exit 0在这种场景下走return分支,不会把整个会话 shell 关掉;而以bash script.sh方式执行时,脚本运行在自己的子进程中,return会失败、exit 0兜底退出,效果相同但无法影响父 shell 环境。脚本中多次出现return 0 2>/dev/null || exit 0正是为了同时兼容这两种调用方式。

集成到各 AI 编码环境

Claude Code

如果 Claude Code 支持启动钩子,将脚本挂到会话启动时:

# 添加至 .claude/hooks/session-start source examples/startup-hooks/bd-version-check.sh

如果当前环境不支持该钩子机制,退而求其次:在每个编码会话开始时手动执行一次source即可(README 也给出了这一备选方案)。

GitHub Copilot

Copilot 通常没有独立的会话启动钩子,更稳妥的做法是挂在 shell 初始化文件里,并仅在进入 beads 项目时触发:

# ~/.bashrc 或 ~/.zshrc # 进入 beads 项目时自动执行 bd 版本检查 if [ -d ".beads" ]; then source /path/to/beads/examples/startup-hooks/bd-version-check.sh fi

Cursor

按 README 的建议,Cursor 可参照 GitHub Copilot 的模式:加入工作区设置或 shell 初始化文件中。由于脚本自带.beads目录探测与静默退出逻辑,这种方式不会在非 beads 工作区产生任何干扰。

通用集成

任何允许自定义启动脚本的 AI 编码环境,都可以通过source一行接入。脚本对运行环境几乎零假设,唯一的硬性前提是执行时的当前工作目录就是 beads 项目根目录(.beads在此目录下)。

工作原理:脚本逐段源码剖析

将脚本拆开来看,其执行流程分为四个阶段(与 README 中 "How It Works" 的四步一一对应,见 examples/startup-hooks/README.md)。

第 1 步:环境守卫与版本探测

# Exit early if not in a beads project if [ ! -d ".beads" ]; then return 0 2>/dev/null || exit 0 fi # Check if bd is installed if ! command -v bd &> /dev/null; then return 0 2>/dev/null || exit 0 fi

脚本先做两道"静默守卫":不在 beads 项目、或 bd 不在 PATH 中,都直接返回成功。接下来探测当前版本:

CURRENT_VERSION=$(bd --version 2>/dev/null | grep -oE '[0-9]+\.[0-9]+\.[0-9]+' | head -1) if [ -z "$CURRENT_VERSION" ]; then return 0 2>/dev/null || exit 0 fi

bd --version的输出中用正则[0-9]+\.[0-9]+\.[0-9]+提取语义化版本号;若命令失败导致取不到版本,同样静默退出。这里的head -1保证即使输出包含 commit hash 等多行信息,也只取第一个标准版本号。

第 2 步:metadata.json 的初始化与上次版本读取

METADATA_FILE=".beads/metadata.json" # Initialize metadata.json if it doesn't exist if [ ! -f "$METADATA_FILE" ]; then echo '{"database": "beads.db", "jsonl_export": "beads.jsonl"}' > "$METADATA_FILE" fi LAST_VERSION=$(jq -r '.last_bd_version // "unknown"' "$METADATA_FILE" 2>/dev/null)

文件不存在时自动创建,初始内容包含 beads 项目的基本元数据字段(databasejsonl_export),随后脚本追加写入last_bd_version字段。读取时用 jq 的// "unknown"缺省运算符处理字段缺失的情况——这对应 README 中 "First run: Sets version without showing upgrade message" 的边界处理:首次运行时last_bd_version为 "unknown",与当前版本必然不等,但升级横幅的触发条件要求LAST_VERSION != "unknown",因此首次运行只记录版本、不打印横幅。

第 3 步:版本变化检测与变更展示

if [ "$CURRENT_VERSION" != "$LAST_VERSION" ] && [ "$LAST_VERSION" != "unknown" ]; then echo "" echo "🔄 bd upgraded: $LAST_VERSION → $CURRENT_VERSION" echo "" echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━" bd info --whats-new 2>/dev/null || echo "⚠️ Could not fetch what's new (run 'bd info --whats-new' manually)" echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━" echo "💡 Review changes above and adapt your workflow accordingly" echo "" fi

检测到升级后,脚本打印分隔横幅并调用bd info --whats-new。这条命令的实现位于 cmd/bd/info.go 的showWhatsNew()函数:它以Version常量为当前版本、遍历内嵌的versionChanges结构(包含版本号、日期与变更列表),输出形如## v0.24.2 (2025-11-23)的摘要,并为与当前版本一致的条目标注← current。从versionChanges数据看(cmd/bd/info.go),它记录的正是 Agent 视角的高价值变更,例如bd doctor --fix自动修复、bd hooks install内嵌 git hooks 命令、bd new别名、bd list每行一条的默认格式等。

值得注意:bd info --whats-new还支持--json标志(见 cmd/bd/info.go 与 cmd/bd/info.go),输出{"current_version": ..., "recent_changes": ...}机器可读结构。如果未来需要让 Agent 程序化解析变更,可以在脚本中改用bd info --whats-new --json并配合 jq 消费。

第 4 步:git hooks 过期检查与自动更新

# Check for outdated git hooks (works even if version didn't change) if bd hooks list 2>&1 | grep -q "outdated"; then echo "🔧 Git hooks outdated. Updating to match bd v$CURRENT_VERSION..." if bd hooks install 2>/dev/null; then echo "✓ Git hooks updated successfully" else echo "⚠️ Failed to update git hooks. Run 'bd hooks install' manually." fi echo "" fi

这一步不依赖版本是否变化,每次会话启动都会执行——因为 hooks 过期与否由 bd 版本与已安装 hook 版本共同决定,即使本次会话没有升级也可能存在历史遗留的过期状态。bd hooks list的输出中,过期的 hook 会带有 "outdated" 标记:从 cmd/bd/hooks.go 的FormatHookWarnings实现可以看到,过期检测会比较每个 hook 的已安装版本与当前 bd 版本,统计过期数量并提示Run: bd hooks install;而 cmd/bd/hooks.go 的注释则说明"thin shims 永远不会过期"(因为它们会委托给 bd 本体),因此实际被标记为过期的通常是内联了旧版本逻辑的传统 hook。bd hooks install成功时输出✓ Git hooks installed successfully(见 cmd/bd/hooks.go)。

第 5 步:版本持久化与安全退出

TEMP_FILE=$(mktemp) if jq --arg v "$CURRENT_VERSION" '.last_bd_version = $v' "$METADATA_FILE" > "$TEMP_FILE" 2>/dev/null; then mv "$TEMP_FILE" "$METADATA_FILE" else rm -f "$TEMP_FILE" fi return 0 2>/dev/null || exit 0

持久化采用"临时文件 + 原子替换"策略:先用mktemp创建临时文件,jq 写入新版本成功后用mv覆盖原文件,避免直接写入中途失败导致metadata.json损坏;jq 失败则清理临时文件并继续。这与 README 中 "Use a temp file to avoid corruption if jq fails" 的注释一致。最后return 0 2>/dev/null || exit 0保证无论以 source 还是子进程方式执行,脚本都以成功状态退出。

完整示例输出

当 bd 从 0.23.0 升级到 0.24.2 时,脚本在会话启动时会打印类似如下的横幅(见 examples/startup-hooks/README.md):

🔄 bd upgraded: 0.23.0 → 0.24.2 ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 🆕 What's New in bd (Current: v0.24.2) ============================================================= ## v0.24.2 (2025-11-23) • New feature X • Bug fix Y • Performance improvement Z [... rest of what's new output ...] ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 💡 Review changes above and adapt your workflow accordingly 🔧 Git hooks outdated. Updating to match bd v0.24.2... ✓ Git hooks updated successfully

横幅结构清晰地区分了"升级通知区"与"后续动作区":前者告诉 Agent 版本变化并展示变更摘要,后者提示 Agent 应当审查变更并调整自己的工作流,同时对 git hooks 的自动修复给出成功/失败反馈。

边界情况与设计决策

脚本对以下场景均做了明确处理(见 examples/startup-hooks/README.md):

场景行为
不在 beads 项目静默退出,可安全放入全局 shell 初始化文件
bd 未安装静默退出
jq 未安装打印警告但不中断(提示安装命令后退出)
metadata.json缺失自动创建
首次运行只记录版本,不展示升级横幅
bd命令执行失败静默退出

这些决策的共同原则是"失败降级、不产生噪音":任何前置条件不满足都不阻断 Agent 会话,任何错误都优先静默而非抛出异常。唯一主动暴露的是 jq 缺失警告,因为它直接影响脚本核心的 JSON 读写功能。

故障排查

README 提供了三组高频问题的速查(见 examples/startup-hooks/README.md):

Q: 脚本检测不到版本变化?A: 检查.beads/metadata.json是否存在且包含last_bd_version字段。注意字段缺失时 jq 的// "unknown"会让脚本在首次运行只记录版本而不提示,这是预期行为;若已运行过多次仍无提示,再检查bd --version输出中的版本号格式是否匹配正则[0-9]+\.[0-9]+\.[0-9]+

Q: 出现 "jq not found" 警告?A: 安装 jq 即可:macOS 执行brew install jq,Ubuntu 执行apt-get install jq。安装前脚本会持续以警告方式降级运行,不会报错。

Q: git hooks 没有自动更新?A: 确认对.git/hooks/目录有写权限。权限不足时脚本会打印⚠️ Failed to update git hooks. Run 'bd hooks install' manually.,此时可手动执行bd hooks install

相关资源与延伸阅读

  • 脚本本体:examples/startup-hooks/bd-version-check.sh(本文所有分段源码均出自此文件)
  • 使用说明:examples/startup-hooks/README.md
  • bd info --whats-new命令实现:cmd/bd/info.go,--whats-new标志在 cmd/bd/info.go 注册,其 v0.23.0 引入记录见 cmd/bd/info.go
  • bd hooks list/bd hooks install实现:cmd/bd/hooks.go(过期检测)、cmd/bd/hooks.go(安装成功输出)、cmd/bd/hooks.go(hooks list 命令描述)
  • 仓库根目录的 AGENTS.md 中提供了 "After Upgrading bd" 的手动工作流指引,本文介绍的脚本即该手动流程的自动化替代方案

适用前提与限制

需要说明的是:本方案的有效性依赖几个前提——脚本必须在当前工作目录为 beads 项目根目录时执行(.beads目录探测机制决定了这一点);bd info --whats-new展示的是 bd 内置的versionChanges列表,其详细程度取决于各版本发布时是否补充了 Agent 视角的变更条目;此外脚本为纯 bash 实现,未做跨平台适配(Windows 环境需借助 WSL 或 Git Bash)。若你的 Agent 环境支持真正的会话启动钩子(如 Claude Code 的session-start),优先挂在钩子里;否则退化为 shell 初始化文件中的目录条件判断,依然是安全且无副作用的方案。

【免费下载链接】beadsBeads - A memory upgrade for your coding agent项目地址: https://gitcode.com/GitHub_Trending/beads1/beads

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询