跳转到内容

Claude Code 插件与 Hooks 架构

Claude Code 插件与 Hooks 架构:Claude-Mem 的具体实现

学习目标

本章聚焦 Claude-Mem 如何作为 Claude Code 插件,通过 6 个生命周期 Hook 实现持久记忆。建议先阅读前置知识,下文直接聚焦具体落地方案。

前置知识

本章涉及 Hook 系统和插件系统的通用架构,建议先阅读:

项目实践

插件目录结构

plugin/
├── hooks/
│ ├── hooks.json # Hook 配置 DSL
│ └── codex-hooks.json # Codex 平台专用 Hook 配置
├── scripts/
│ ├── bun-runner.js # Bun 启动器,桥接 Node.js Hook 到 Bun Worker
│ ├── worker-service.cjs # Worker Service 入口(CJS 格式)
│ └── version-check.js # 版本检查脚本(Setup Hook,独立于统一 Worker)
├── skills/ # 17 个 Skill 定义
│ ├── mem-search/ # 记忆搜索 Skill
│ ├── make-plan/ # 计划编排 Skill
│ ├── do/ # 执行 Skill
│ └── ...
├── ui/
│ └── viewer.html # Web Viewer UI(React 构建产物)
└── modes/ # 工作模式定义
├── code/ # 英文模式
├── code--zh/ # 中文模式
└── code--ja/ # 日文模式

6 个生命周期 Hook

统一 Worker 模式

version-check.js(Setup Hook)外,所有 Hook 通过统一路径执行:

node bun-runner.js worker-service.cjs hook <子命令>

bun-runner.js 的作用:

  1. 检测 Bun 是否可用,不可用时自动安装
  2. 通过 Bun 执行 worker-service.cjshook 子命令
  3. 将 Hook 参数(来自 Claude Code 的 stdin)转发给 Worker

这种模式的好处是:

  • 代码复用:所有 Hook 共享同一个 Worker 实例的逻辑
  • 热启动:Worker Service 常驻内存,Hook 只需 HTTP 调用
  • 统一错误处理:所有 Hook 使用相同的退出码策略

Hook 退出码策略

Exit 0 — 成功或优雅关闭
Exit 1 — 非阻塞错误(stderr 展示给用户,继续执行)
Exit 2 — 阻塞错误(stderr 传给 Claude 处理)

设计哲学:Worker/Hook 的错误默认 Exit 0,防止 Windows Terminal 标签页累积。包装层/插件层处理重启逻辑,ERROR 级别的日志保留用于诊断。

Hooks 配置 DSL

hooks.json 使用声明式语法定义每个 Hook 的行为:

字段说明
matcher正则匹配,决定 Hook 何时触发(* 表示总是触发)
typeHook 类型(command 表示执行 shell 命令)
shell使用的 shell(bash
command要执行的 shell 命令
timeout超时时间(毫秒)

问题与规避

PATH 传播

问题:Hook 在 Claude Code 的受限环境中执行,可能找不到 Node.js、Bun 等工具。

规避:每个 Hook 命令都以 export PATH=... 开头,通过 $SHELL -lc 'echo $PATH' 获取登录 shell 的 PATH。在 Cygwin/MSYS 环境下还通过 cygpath -w 转换路径。

插件禁用检测

问题:用户可能在 Claude Code 设置中禁用了插件,但 Hook 仍然被触发。

规避src/shared/plugin-state.ts 提供 isPluginDisabledInClaudeSettings() 函数,Worker Service 启动时检查该状态,禁用时优雅退出。

设计取舍

为什么 version-check.js 独立于统一 Worker?

Setup Hook 的 version-check.js 是唯一的独立脚本,不调用统一 Worker:

  • 原因:Setup Hook 在 Worker 可能尚未安装或版本不兼容时执行,需要独立的版本检查
  • 优势:即使 Worker 损坏,版本检查仍能运行,可以提示用户修复
  • 代价:需要维护额外的独立脚本

参考来源