GitHub仓库发布——ZCode 会话管理器(Python CLI 版)

GitHub仓库发布——ZCode 会话管理器(Python CLI 版)

仓库地址:SinonJZH/zsm-for-python(当前版本 V1.0.1,MIT 协议)。

上一篇《GitHub仓库发布——增强版Qdrant MCP服务器》的结尾说,给知识库补上“改得动、删得掉”的句柄,这件事算是了了。结果话音落下没多久,我发现另一个只进不出的角落——而且这次里面装的东西更私人:我和 AI 的全部聊天记录。

一、做这个工具的背景

ZCode 的会话界面上有个删除按钮,我用得很放心,直到有一天我打开了它的数据库。

真相是:这个按钮有两种历史语义,但都只是标记,不清数据。旧版把 tasks 表的 archived 置 1,学名叫归档;新版(2026 年 9 月起)把 deleted 置 1,学名叫删除。无论哪种,会话正文都原封不动地躺在 cli/db/db.sqlite 里,磁盘上的伴生文件——命令输出、模型的原始输入输出记录(rollout)、执行缓存、产物缓存——也一个不少。

换句话说,删除按钮按下去,会话只是从花名册上消失了;档案室里,整卷档案原封不动。

上回对付知识库时我说过,“重复写入即永久冗余”;这回得换个说法:所谓删除,只是把书从架上取下来塞进床底,并没有烧掉。 对隐私有点洁癖的人,迟早会想去床底下看一眼——看完迟早想烧。这个仓库就是那把火,以及烧之前的一整套消防流程。

二、已有工具的局限

在网上搜索彻底删除Zcode聊天记录的工具,发现了一个已有仓库:woooooooooolf/zcode-session-manager(Tauri/Rust 桌面应用,MIT)在 2026 年 9 月 13 日就已经出现,把“浏览全部会话 + 彻底删除”这件事做得很到位——本项目的安全模型就是照着它学的,README 里专门鸣谢了一行。

然而仓库只有Windows版,WSL里根本用不了。Rust我不熟,既然这样,干脆把功能移植到python上,加上webui,什么平台都能用。

此外,现有的这个工具并没有对新增的deleted进行判断,无法区分归档与删除,我想要工具进一步能够区分开删除和归档。

三、移植了什么:总览

原版(Tauri/Rust) 本项目(Python CLI)
形态 桌面 GUI 应用 命令行 + 本地 Web 界面
依赖 Rust 工具链构建 Python 3.10+,仅 psutil、rich(可选)
分发 桌面安装包 单文件可执行(PyInstaller),或源码直接跑
跨端 — 支持从 WSL 经 /mnt/... 管理 Windows 侧数据
自动化 — --json 机器可读输出,clean 支持编号批量选择
隐私清理选项卡 有 未移植

原版的一切安全设计都原样保留,外面换了一层可以在终端里、脚本里、WSL 里跑的壳。至于 Web 界面——原版有桌面 GUI,移植版总得有个对应的坐镇,后文细说。

四、核心:删除的完整闭环

数据无价,删除必须谨慎。这个工具把删除做成了闭环:计划 → 确认 → 备份 → 删除 → 校验 →(失败)还原 → VACUUM。

先看计划。plan 子命令是纯 dry-run,不动任何数据,把级联范围摊开给你看:主会话连同子会话、逐表删除行数、磁盘能释放多少。会话 ID 支持唯一前缀匹配,有歧义就报错并列出候选——宁可让你多敲几个字符,不替你猜。

再看真实战报。第一次用它清理时留下的执行报告(JSON)长这样:

{
  "deleted": [
    { "table": "message", "rows": 124 },
    { "table": "part", "rows": 465 },
    { "table": "tool_usage", "rows": 103 },
    { "table": "model_usage", "rows": 101 },
    { "table": "session", "rows": 4 }
  ],
  "disk": { "files": 21, "bytes": 3871052, "errors": [] },
  "integrity": { "passed": true, "restored": false }
}

4 个会话,880 行数据库记录加 21 个磁盘文件,3.69 MB——界面上一干二净的“已删除”会话,底下一口气挖出来这么多。(上面有删节,完整报告是 13 张表逐条列明。)删了什么,有据可查,这份报告本身就存档在 out/ 目录里。

然后是四道防线,这是全工具的心脏:

  1. 先备份。删除前把两个数据库(连同 -wal)和全部会话磁盘文件拷到 <zcode>/zsm-backups/<时间戳>/,附 manifest.json 记录每个文件的原始路径——不依赖本工具也能手工还原;
  2. 后校验。删除完成后对两个库自动跑 PRAGMA integrity_check,一旦异常,自动从本次备份整体还原并明确提示,不留半个“删了一半”的现场;
  3. 运行保护。检测到 ZCode 正在运行时默认拒绝删除——数据库还被人握着写句柄呢。WSL 里操作 Windows 侧数据时,psutil 看不见 Windows 进程,就自动换 tasklist.exe 探测;两条路全都不通怎么办?拒绝执行。探测不出结果,不等于没在运行——这个设计原则写在 probe 模块 docstring 的第一行:None 等同于拒绝。确有需要时 --limited 受限模式只放行「已从界面移除 + 闲置超阈值 + 未被自动化引用」的会话;
  4. 格式兼容检查。ZCode 升级后表结构变了怎么办?compat 检查发现结构与预期不符,就拒绝一切破坏性操作——工具可以过时,但不能带着旧地图去开新船。

删除成功后还有个收尾:自动 VACUUM,把数据库文件真正缩小——不然行删了、页还在,磁盘占用纹丝不动,删除就成了行为艺术。

五、WebUI:多一层界面,不多一层风险

CLI 对程序友好,对人未必。所以移植版里加了个 zsm webui:纯标准库 http.server 加一个单文件页面,零第三方依赖,浏览器里筛选、勾选、只读浏览消息流、生成删除计划、确认执行。

但浏览器里点按钮,天然比终端里敲命令危险——你防的不是自己,是同一个局域网里的别人和浏览器里其他标签页的恶意网页。所以 WebUI 额外加了四层防护:

  • 只监听 127.0.0.1,局域网里根本看不到这个服务;
  • 校验 Host 头,防 DNS rebinding——否则一个精心构造的域名就能把你的本地服务变成公网可访问;
  • 每次启动生成随机 token,所有删除类 POST 必须携带。这同时让浏览器跨站请求的 CORS 预检必然失败,恶意网页的 CSRF 到此为止;
  • 会话 ID 严格校验字符集,防路径穿越。

即便如此,页面内的删除仍要输入 yes 二次确认,服务端复用与 CLI 完全相同的安全轨——备份、校验、还原,一道不少。界面可以换,闸门不能减。

六、工程化:能跑和能发布是两回事

看一眼提交历史,这个项目的一生浓缩在一个下午里:9 月 19 日 12:26 初始提交,14:00 拆分模块加交互式批量删除,15:08 追加 WebUI,15:36 配好 CI 打出 RC 标签,16:03 V1.0.0,17:48 V1.0.1。从“一个脚本”到“带 CI 的正式发布”,不到五个半小时。

流水线本身不复杂,但每一步都是踩出来的:

  • 推送 V* 标签触发,Linux 和 Windows 双平台矩阵构建;
  • 源码先跑一遍 selftest——在临时目录构造伪数据目录做全流程断言,根本不碰真实数据;
  • PyInstaller 打成单文件,然后对打包产物再跑一遍 selftest,最后起一个真的 WebUI 服务,GET / 拿到 200 才算过;
  • 全部通过后生成 SHA256SUMS.txt,连同两个平台的可执行文件挂上 Release。

其中三个坑值得一提:

  1. Windows runner 的 stdout 是 cp1252,构建日志里一点中文就 UnicodeEncodeError,全局环境变量 PYTHONUTF8: "1" 才摁住;
  2. --add-data 的分隔符是个平台陷阱:Windows 用分号、其他系统用冒号。webui.html 是运行时按包路径读取的数据文件,忘了这一行,打包照样成功——产物是一个“功能残废但毫无异样”的包。这也是为什么打包后必须拿产物做自检加冒烟,那两步不是仪式感;
  3. Linux 固定在 ubuntu-22.04 上构建:产物依赖构建机的 glibc,构建机越老,能跑的发行版越多。

七、怎么用

装 Python 的:

pip install psutil rich        # rich 可选,缺失时降级为纯文本输出

python zsm.py list             # 列出全部会话(含已删除/已归档/ghost)
python zsm.py show <id前缀>    # 只读浏览某会话完整消息流
python zsm.py plan <id...>     # 删除计划(dry-run,不动任何数据)
python zsm.py clean            # 交互式批量删除:编号选择 1,3,5-8 / all / q
python zsm.py webui            # 本地 Web 界面(http://127.0.0.1:8765)
python zsm.py selftest         # 不放心的话,先跑自检(临时目录,不碰真实数据)

不装 Python 的,去 Releases 下载对应平台的单文件直接运行,无需任何依赖。

一句必须照抄的提醒,来自 README 也来自我:正式使用前,先创建一个无意义的测试会话并对它执行删除,确认行为符合预期后再处理真实数据。 任何删除工具的多重防护,都不能替代你自己的备份习惯。

八、写在最后

上一篇的结尾说,知识库要“检得到,还得改得动、删得掉”。这一篇算是把同一个主张往前又推了半步:AI 的记忆要有完整的删除闭环,AI 的日记——那些记录着你每一次提问、它每一次思考的会话档案——同样要有。界面给你一个删除按钮很容易,难的是按钮背后那一整套:删得掉、验得了、还能反悔。

“把私有的纪律固化成公共的工具”,上次是这么说的,这次照做了一遍——只不过这次是站在前人的肩膀上做的:安全模型归于 wooooooooolf 的原项目,MIT 的版权声明原样保留在 LICENSE 里。至于上游没移植的隐私清理,做不做看需求,不强求大而全。

工具是用来被挑毛病的。欢迎来 issue 里骂,PR 更好——当然,最欢迎的是你用 selftest 先验一遍自己的环境。

最后的最后,把那句老话留在结尾:备份是作者的事,我已做满四道防线;备份习惯是你的事,这没人替得了。