Skip to content

Latest commit

 

History

History
110 lines (92 loc) · 12.1 KB

File metadata and controls

110 lines (92 loc) · 12.1 KB

codeeraser plugin

被动 guard 四钩(全部 fail-open,内部失败一律放行)+ 一个主动 skill + 一条命令:

hook 命令 行为
SessionStart ce health --hook 健康行(版本/guard 档/索引/daemon)+ daemon 预热;有新版本时另起一行更新通知(检查结果缓存一天,CE_UPDATE_CHECK=0 关闭,无网络即无此行)
PreToolUse (Write|Edit) ce probe --hook 对将写入的内容做 T1/T2 重复探针 + 硬预算(写后行数超本文件那条硬线)两类,按 ce.toml [guard] mode 决策;未超硬线而落在软线与硬线之间的写入由分级区观察器记账,[guard] zone_tiers 开启后才按落点出声;墓碑类按自己的 [tombstone] tier 与 budget 在核里判,只在核答 over 时出声;函数内死代码类按自己的 [flow] tier(出厂 observe)只在这次写入带来新的被判决发现时出声
PostToolUse (Write|Edit) ce settle --hook 只记不说:本会话的 PreToolUse 对同一次工具调用(同一 tool_use_id)答过 ask、而工具真跑完了,就往观察账本追加一行 settled——人放行了这次写入;拒绝不触发任何钩子,所以没有这一行就是拒绝的记录
Stop ce audit --hook 净 LOC + 涉改重复块,仅 deny 档拦停;墓碑腿同样在核里按 [tombstone] tier 与 budget 判、也只有 deny 档拦停。四分类汇总(跨文件搬迁 / 堆叠嫌疑)只记不判,账本见 docs/FPR-L2.md;同角色顾问行(本会话新增的单元其 top-1 带角色位时)只落进 observe 账本,永不拦停

拒写理由与 Stop / precommit / commitmsg 的每一行都由核按当时的语言写出(钩子经 daemon 的核链、审计经自己的核链问一次);核说不出时决定照旧,句子换成一句英文兜底 ce: rule … fired; the core could not phrase the reason: …——只点名触发的规则、不说决定,各档位同一拼写(审计面是 ce <面>: rule … fired; the core could not phrase the verdict: …,本地规则不拦时没有 rule … fired; 这一段)。

skill:skills/erase/,把 dedup/deadcode/join 的发现引导成安全删除(先读全文、查引用、小批删、重跑门证收敛), 用户说"清理重复/死码"时由 Claude 自动调用。

命令:/codeeraser:update,跑 ce update 并转述判定 (退出码 0 最新 / 1 有更新 / 2 未知)。插件绑定的副本由清单 pin 决定, 所以它的更新动作永远是 /plugin update codeeraser(新清单带新 pin,下一会话 启动器重验重下载);ce update --yes 只替换手工放置或安装包随附的副本。

MCP:.mcp.json 注册只读报告面(ce mcp),二十一个工具随插件 一起到位:装插件 = 钩子与报告一起装,不需要另外 claude mcp add。工具名 由 Claude Code 自动命名空间化为 mcp__plugin_codeeraser_reports__<tool>。 erase 工具只到计划为止、erase_log 只读它的审计轨迹:apply 没有 face、也不会有,因为一个能凭自己 的权限删文件的机器面,是橡皮擦唯一不能出的东西;update_check 同理只到检查; similar_units 是同角色顾问(ce similar 的同一份文档),只当顾问不判决; query / rules 是代码查询家族(ce query / ce rules 的同一份文档,问题或规则文件在核的 query/1 上判决),这里只出报告,退出码是 CLI 自己读 counts.violations 的事; merge_suggestions 是克隆合并建议(ce merge 的同一份文档:每个克隆组合并成一个函数要几个参数、保留哪个成员、 省几行、可不可行及原因,在核的 merge/1 上判决),只当顾问; architecture 是架构分析(ce arch 的同一份文档:分层、拆环切边、簇与错位文件、目录度量,impact 给出一处改动波及的文件,在核的 arch/1 上判决),只当顾问。

安装

公开 marketplace 一键装(清单在仓根 .claude-plugin/marketplace.json;注册的是 release 分支,verify-publish 每次 publish 后把它快进到 tag 提交,装机跟发布不跟 main):

  1. /plugin marketplace add skymanbp/CodeEraser@release
  2. /plugin install codeeraser@codeeraser

v1.7.0 起 ce setup 就是这两步,任何平台同一具身体(cli/src/setup/):找到 Claude Code → 已注册则保留、否则注册 → 安装并刷新 → 只在本次注册时写 claude-plugin-wired 标记 → 报告本二进制所在目录是否在 PATH 上;运行账户 ≠ 登录用户时按名拒绝、退 13 什么都不接; --unwire 以标记为凭只拆它自己接的。Windows 安装包装机 / 卸载时各调一次 (gui/src-tauri/windows/hooks.nsh 只印退出码图例,失败一律降级为提示行),AppImage / dmg / 纯 CLI 底座自己跑一次。本地开发 clone 则注册仓根目录为 marketplace (claude plugin marketplace add <repo根>);注册 plugin/ 子目录是 9f86d58 之前的旧位, 清单已不在那里,会以 cache-miss 静默掉钩。

ce 与判决核 ce-core 两个真身均由 bin/ce.sh 三级解析(ADR-007): 已验证本地副本 → 按 bin/manifest.env 的 SHA256 pin(清单每目标钉三枚:ce / ce-core / GUI 安装包, 共五目标十五枚;启动器只取前两枚,v1.7.0 前的清单只钉前三个目标)从 GitHub Releases 下载并校验 → PATH 兜底。校验按会话一次:验证过的 路径记在 CLAUDE_PLUGIN_DATA/bound-<清单版本>.env,同会话后续 hook 直接 exec; 清单或二进制更新即重验,SessionStart 的 health 每会话必验。手放到 CLAUDE_PLUGIN_DATA/ce-<清单版本>-<平台> 的副本走同一道 pin:相符即按已验证执行并落戳, 不相符具名拒绝、不执行(CE_AIRGAPPED=1 永不下载,只在手放副本与 PATH 之间选)。 源码安装(cargo install codeeraser 或 --path cli)依然可用。

Windows 前置:sh 要在 Windows PATH 上。 四个钩子与 .mcp.json 都以裸 sh 起头去跑 bin/ce.sh,而 Claude Code 是原生 Windows 进程,按 Windows PATH 找第一个 token。Git for Windows 默认只把 Git\cmd 放进 PATH,那里有 git.exe 没有 sh.exe; sh.exe 在 Git\bin 与 Git\usr\bin。PATH 上没有 sh 时钩子与 MCP 面都起不来, 且这个失败不出声:起不来的正是本该报错的那个脚本,症状是没有健康行、没有 .ce/、 /mcp 里那条 server 连不上。把 Git\bin 追加到用户 PATH 即可(只有 bash.exe / git.exe / sh.exe 三个文件,不会遮蔽 find / sort 这些同名 Windows 工具,那些在 Git\usr\bin);追加而非前置,则 bash 仍解析到 system32 的 WSL 那只。 改完 PATH 要重启 Claude Code:钩子配置在会话启动时读取。

配置

项目里可选 ce.toml:

[guard]
mode = "observe"   # 全局覆盖(可选):observe | warn | ask | deny
                   # 不写 = 计划 §4.2 路线默认(见下)

[[rules.class]]    # 可选:路径类分参(计划 v2.13)——声明序首中,无命中 = 全局表
name  = "generated"
globs = ["gen/**"]
[rules.class.knobs]
file_lines_fail = 900   # 该类自己的硬预算——PreToolUse 按这条拒;至多 64 类,类名与 glob 永不过线

默认档位 = §4.2 路线第 3 级(2026-08-17 1.0 档位切换生效,依据见根目录 CHANGELOG.md):T1/T2 精确重复写入与**硬预算超限 (写后文件超过其硬线:默认 750,或其 [[rules.class]] 声明的那条;hook 经 guard::budget::lines_for、ce scan 直呼,两面同读 scan::classes::Classes::thresholds_for 那张类尺)**两类 PreToolUse 规则默认 deny;Stop 审计 / precommit 不在晋升类,默认仍 observe。显式 mode 统一覆盖全部规则类。 分级区档位映射(软线→硬线之间按位置 <25 % observe / 25–75 % warn / >75 % ask)走 [guard] zone_tiers 这一个开关;首测自仓 28/5196 = 0.5388 %、requests 11/448 = 2.4553 %,后者超 1 %,采用变体 B,默认仍为 false。完整台账在 docs/FPR-REPLAY.md「分级区档位映射」节。 观察档数据在 <project>/.ce/observe.ndjson(已被 .ce/ gitignore 规则覆盖), 每行带 schema(单一来源 cli/src/hookio.rs::OBSERVE_SCHEMA,版本号以那一处为准,此处不再抄写;M5 收口审计抓获抄本 0.3.0 陈旧于实际 0.4.0)、session_id 与 ts_ms; tombstone 事件行(PreToolUse 一次写入删掉了名字、或它的标题 / 标识符 / 散文把本会话删掉的名字 写回成「无 X」时才落一行,只记名字的哈希)、settled 事件行(PostToolUse 腿:PreToolUse 答 ask 后工具真跑了才落一行,只带 file 与 tool_use_id;同一次工具调用的各行都带 tool_use_id,probe 行另带钩子对这次事件的决定 decision,墓碑行的 applied 为 null 时按有无对应的 settled 行读)与 Stop / precommit / commitmsg 行上的 tombstone 对象 (本次改动集的度量:删掉的名字数、候选面数 rows、changelog 定位豁免(整文件按路径、台账形或 [tombstone] ledger 声明,或只豁免一段而段条目带起始 line)与核的判决 judged:前几处站点 file:line kind、标签 / 散文分账、over) 按类自己的 [tombstone] tier(默认 observe)出声,且只在核答 over(站点数超过 [tombstone] budget)时;observe 只记不拦,FPR 账本见 docs/FPR-TOMBSTONE.md; fourclass 对象(跨文件搬迁与堆叠嫌疑)永不出声:它不属于任何档位,其改动集级 FPR 账本见 docs/FPR-L2.md:821 事件零跳过,严格 0/125、宽读法 0/820;唯一 copy 正例 1035f6b1 漏过(召回 0/1),本批无默认档位变更; similar 对象(本会话新增的单元逐个问过同角色顾问:rev、new_units、queried,以及核的 top-1 带角色位时的 rows 行 {unit,twin,score};无核或读不到索引时只记 degraded)同样永不出声:顾问不判决,评估台账见 docs/EVAL-SET-SIMILAR.md; flow 事件行(PreToolUse 一次写入的前后两侧各降表经核 flow/1 判一次,后侧有发现才落一行:before / after 发现数、按 (单元名, 种类, 变量名) 多重集相减得的 novel、按种类计数的 kinds、语言是否在判决掩码 judged;mode 是类自己的 [flow] tier,出厂 observe)与 Stop / precommit / commitmsg 行上的 flow 对象(改动集里有单元的文件数、单元数、发现数、kinds、被判决的条数)自 feed 0.12.0 起加性出现;Stop 腿在任何档位都不拦停,站点清单在 ce flow 里; 核的定义包读不到(没有核、核早于 7.7.0)时钩子不度量、退 0、从不拒写,但每个钩子各落一行(PreToolUse probe、PostToolUse settle、Stop stop_audit、SessionStart health):degraded 为真、reason 是 CLI 拒绝时的同一句,PreToolUse / PostToolUse 行另带 file 与 tool_use_id,自 feed 0.13.0 起加性出现;ce doctor 的降级计数把它们算进去,SessionStart 那一行写「tables: unavailable — <原因>」,每个会话说一次; session_id 为 null 表示该条不属于任何会话;ce precommit / ce commitmsg(后者把提交说明也当一个面,站点记 COMMIT_EDITMSG:行 prose)跑在终端里、 不是 hook,是仅有的会出现 null 的来源。按会话切分是 M4 评估集的前置 (计划 D2-1 样本纯净度 / D2-2 观察档会话计数)。

hooks 配置在会话启动时加载,安装/改档后重启会话生效 (2026-08-07 hook payload 实采会话的实测结论)。