W
AI-Wiki
ENTITY

cleanup-hook.js

定义与身份

cleanup-hook.jsclaude-mem Hook 生命周期中对应 SessionEnd 阶段的脚本。

它在 hooks 配置中由 SessionEnd 生命周期事件调用,命令路径为 ${CLAUDE_PLUGIN_ROOT}/scripts/cleanup-hook.js

源码映射关系为:src/hooks/cleanup-hook.tsplugin/scripts/cleanup-hook.js

从角色上看,它不是负责摘要生成,也不是负责保存 observation,而是在会话退出阶段收尾:把当前 session 标记为完成,并为后续异步处理留下自然结束的机会。

hooks 配置位置

原始配置形式如下:

{
  "hooks": {
    "SessionEnd": [{
      "hooks": [{
        "type": "command",
        "command": "${CLAUDE_PLUGIN_ROOT}/scripts/cleanup-hook.js"
      }]
    }]
  }
}

这说明 cleanup-hook.js 是在 SessionEnd 阶段以 command hook 方式执行的,而不是在 SessionStartUserPromptSubmitPostToolUse 或 Stop 阶段执行。

角色职责

cleanup-hook.js 的职责有 3 项:

  1. 在数据库中把 session 标记为已完成。
  2. 允许 worker 把尚未完成的处理继续做完。
  3. 执行优雅清理(graceful cleanup),而不是粗暴中断。

这意味着它的目标不是“尽快杀掉后台工作”,而是“在会话结束后把状态收拢到正确终态,同时避免丢数据和竞争条件”。

触发时机与边界

触发时机是:Claude Code 会话结束时。

但有一个明确边界:不会在 /clear 时执行这类清理语义。原文明确说明 SessionEnd cleanup 是“Claude Code session ends (not on /clear)”。

因此,/clear 不应被当作真正的会话完成信号;cleanup-hook.js 的完成标记逻辑面向的是会话结束,而不是简单的上下文清空操作。

关键设计决策

与该脚本直接相关的关键决策包括:

  • ✅ 自 v4.1.0+ 起采用优雅完成(Graceful completion)。
  • ✅ 不再向 worker 发送 DELETE。
  • ✅ 对 /clear 跳过这类 cleanup 处理。
  • ✅ 保留仍在进行中的处理链路,避免误杀进行中的 session。

这里最重要的变化,是从“主动停止 worker”转向“把 session 标成完成,让 worker 自然收尾”。

为什么要做优雅清理

旧方案(v3)

旧方案是激进清理:

SessionEnd → DELETE /worker/session → Worker stops immediately

这个方案的问题被明确列出为:

  • 中断摘要生成。
  • 丢失待处理 observation。
  • 引发 race conditions(竞争条件)。

也就是说,只要 summary-hook.js 还没跑完、或 save-hook.js 先前排队的数据尚未处理完,直接删 worker / 直接停 worker 就会破坏流程完整性。

新方案(v4.1.0+)

新方案改为优雅完成:

SessionEnd → UPDATE sessions SET completed_at = NOW()
Worker sees completion → Finishes processing → Exits naturally

1 这说明 cleanup-hook.js 的核心动作首先是更新 session 完成状态,而不是直接终止工作进程。

worker 读取到 session 已完成后,会继续把手头重要操作执行完,再自然退出。

优雅清理带来的效果

新方案带来的收益原文列得很具体:

  • Worker 能完成重要操作。
  • 会话摘要可以成功完成。
  • 状态迁移更干净、更一致。

结合整个 Hook 流程来看,这尤其保护了两类工作:

因此,cleanup-hook.js 虽然名字叫 cleanup,但它实际上承担的是“完成态切换 + 异步收尾保护”的职责。

在执行流中的位置

在 Hook Timing 表中,SessionEnd 的执行特征是:

  • 触发时机:On exit
  • Blocking:No
  • Timeout:120s
  • Output Handling:Log only

这几个属性意味着:

  • 它发生在退出时,而不是会话处理中途。
  • 它不是阻塞式关键前置步骤。
  • 它的超时时间是 120 秒。
  • 它的输出只用于日志,不用于向用户上下文注入结构化内容。

summary-hook.js 不同,cleanup-hook.js 的结果不写成摘要结构;与 SessionStart 的 context hook 不同,它也不会通过 hookSpecificOutput.additionalContext 静默注入上下文。

细节与边界

它会做什么

  • 将 session 标记为 completed。
  • 给 worker 留出处理完成窗口。
  • 在退出链路上执行温和、可收敛的状态清理。

它不会做什么

  • 不再直接发送 DELETE 去强制停止 worker。
  • 不把 /clear 当作真正的 session end 来处理。
  • 不负责生成摘要正文;那是 summary-hook.js 的职责。
  • 不负责把工具使用记录排队;那是 save-hook.jsPostToolUse 阶段的职责。

版本边界

优雅清理方案明确是 v4.1.0+ 的设计。也就是说,如果对比更早版本,cleanup-hook.js 所代表的会话结束语义已经发生了架构变化:从“立即终止”迁移为“标记完成后自然退出”。

与相关条目的关系

  • SessionEndcleanup-hook.js 对应的生命周期阶段。
  • summary-hook.js:负责 Stop 阶段摘要生成;优雅清理会避免它的生成过程被提前打断。
  • save-hook.js:负责 PostToolUse 后 observation 排队;优雅清理会降低待处理 observation 丢失的风险。
  • Hooks architecture 摘要:用于理解它在五阶段 Hook 执行流中的位置。
  • Worker Service Architecture:用于理解“标记 completed 后由 worker 自然收尾退出”的架构意图。
  • Progressive Enhancement:如果该条目讨论系统如何在不破坏主流程的前提下逐步增强能力,那么 cleanup-hook.js 的非阻塞、优雅收尾方式与这种设计哲学相容。
  • version-check.js:同属 hook 脚本,但职责不同;前者偏会话结束收尾,后者偏开始前环境/版本提示。

结论

cleanup-hook.jsSessionEnd 阶段的收尾脚本,配置命令为 ${CLAUDE_PLUGIN_ROOT}/scripts/cleanup-hook.js,源码来自 src/hooks/cleanup-hook.ts 并构建到 plugin/scripts/cleanup-hook.js

它最核心的价值不只是“清理”,而是以 v4.1.0+ 引入的优雅完成机制,把 session 标记为完成,让 worker 自然处理完剩余任务,避免旧式强制终止带来的摘要中断、observation 丢失和竞争条件。