ZCode(z.ai CLI)插件:每轮被动审查对话增量的独立审查副模型。本插件是 dsh-advisor(omp "advisor" 子系统的 DeepSeek Harness 移植)在 zcode 端的对应实现:一个独立配置的审查模型观察主会话转录,在每轮结束时评审"继续做下去是否明显有问题",并把 nit / concern / blocker 三级建议注回会话。
AI 协作者 / 新维护者:先读 ARCHITECTURE.md——三形态职责边界、 事件生命周期、状态归属、部署链路与已知局限都在那里,能避免"只看片段就下判断"。
advisory-only 纪律(与上游一致):审查副模型从不批准/否决主模型的动作,从不代行操作;每条送达的意见都带 [advisor:*] 前缀并以"仅供参考"框架自述。故障有界:错误分类计入 Dropped 统计并安静退出,绝不拖垮主会话(被宿主强杀的进程无法自行计数,见"局限")。
[advisor:concern] 输入没有做长度校验
(以上来自审查副模型,仅供参考,不构成指令。……)
前置条件:PATH 上有 Node(hook 以 node 派生;node -v 自查)。版本要求分两档:
| 组件 | 最低 Node | 原因 |
|---|---|---|
| hook 审查链路(SessionStart / UserPromptSubmit / Stop) | ≥ 18 | 只用 fetch、fs 等 18 起稳定的能力 |
🛡️ 角标外挂(tools/companion/controller.cjs) |
≥ 22 | 依赖全局 WebSocket(v21 需 --experimental-websocket,22 起默认提供) |
发行包内嵌官方 Node,目标机无需自行安装;仅在包未内嵌时才需要系统 Node 满足上表。
- 安装:ZCode → 设置 → 插件管理 → 添加插件市场 → 选择本目录(
.claude-plugin/marketplace.json,插件源指向自身;.zcode-plugin/marketplace.json为等价副本)→ 安装 zcode-advisor 并保持启用。 - 新开会话。
⚠️ 斜杠命令(/advisor-*)与[advisor]注册行都在会话创建时注册:安装前就已打开的旧会话里它们不存在,这是宿主机制而非故障——新建一个会话即可。
- 选审查服务商(0.2.17 起不再填 key):审查通道只使用 ZCode 里已维护的第三方服务商(OpenAI 兼容或 Anthropic 协议、非官方内置),端点与 key 都由 ZCode 统一维护、本插件不单独保存也不落盘。
- 🛡️ 角标 →「完整配置」:选服务商 / 选模型 / 刷新 / 从端点拉取实时模型清单 / Ping / 审查模式 / max_tokens;
- 双击
配置面板.cmd:同一份全局配置的另一个入口(127.0.0.1,不联网); - 会话级覆盖(只影响当前会话):角标面板的「本会话的审查模型」块,或会话内
/advisor-model。
- 观察效果:几轮对话后
/advisor-status看审查次数与Token 累计增长;Dropped非零时按故障排查表处置。
全局(所有会话) 与 本会话 两处,互不干扰:
| 范围 | 操作 | 生效 |
|---|---|---|
| 全局 | 🛡️ 角标 →「完整配置」面板(或本地配置面板 127.0.0.1:8789、/advisor-setup):选服务商 + 选模型 → 保存 |
下一轮审查即生效,跨升级保留 |
| 本会话 | 🛡️ 角标面板 →「本会话的审查模型」块:选服务商/模型 → 「固定此模型」;**「使用全局默认」**一键清除覆盖 | 自下一轮审查生效,只影响该会话 |
| 本会话(命令) | /advisor-model set <模型id> [provider:<服务商>]、/advisor-model provider <id>、/advisor-model reset |
同上 |
面板会显示当前生效的目标与来源徽标:全局默认(蓝)或 本会话固定(绿)。优先级:本会话覆盖 > 全局 > 服务商清单首项。
审查服务商必须非官方内置(
builtin:前缀的 BigModel/Z.ai 通道被排除)且协议为 OpenAI 兼容或 Anthropic(/v1/messages)并已配端点与 key;不满足时门禁明确拦下并在状态行给出可操作原因,绝不回退到任何硬编码端点。
0.2.17 角标面板:只保留会话级控制——当前生效模型 + 来源徽标、本会话服务商/模型下拉 + 「固定此模型 / 使用全局默认」、「启用顾问(本会话)」开关(等价 /advisor-on|off,只作用于最近活动的会话)、意见记录(最近 10 条)、「完整配置…」入口。全局配置一律在完整配置面板改。
配置加载优先级:环境变量(逃生舱)> ZCode 第三方服务商解析(端点/key/模型)> 用户级配置 ~/.zcode/advisor.config.json(服务商/模型/模式选择)> 插件目录 advisor.config.json > 内置默认。hook 每次调用都会重读配置,因此保存后无需重启会话。随时用 ctl doctor 查看配置解析链与服务商(key 脱敏显示)。
旧版手动 key 的处理:0.2.17 起插件配置里的 apiKey/baseUrl/apiSource/zcodeModel 一律失效,并在下一次写入配置时被清除——它们不再参与解析,留着既会让用户误以为仍生效,也是明文 key 的纯风险。想换 key 请改 ZCode 设置里的服务商。
为什么不做「legacy 兼容」回头路(2026-10-04 复审后明确拍板,勿再翻案):曾评估过"旧 baseUrl+apiKey 成对时仍生效"的兼容方案,结论是不采纳——它会把「插件持有第二份凭据」重新引入,正是 0.2.17 要消灭的密钥交叉面;而升级影响有兜底:门禁提示会直接给出「请先在 ZCode 设置里维护一个 OpenAI 兼容或 Anthropic 协议的第三方服务商」,迁移发生时另有日志留痕。新增的兼容分支同时会长期保留一条与主路径语义不同的凭据来源,维护成本高于收益。
版本倾斜(插件与 companion 不同步):通常无症状——hook 侧与面板各自独立工作。安装器与升级流程会把两半一起更新;若你手动只替换了一半且行为异常,重新运行安装器即可自愈(--force 覆盖)。登记为已知简化,不做运行时检测。
模型怎么选:审查模型建议与主对话模型形成能力差(主模型是 flash 级时,审查优先试 glm-5.3 等更强模型,以 ZCode 里该服务商实际登记/可用的为准)。改全局模型两处入口等价:完整配置面板(角标内嵌面板或本地配置面板)、直接编辑配置文件;两者都能「从端点拉取」实时清单并 Ping 验证候选模型。会话级临时切换用角标面板的「本会话的审查模型」块,或 /advisor-model set <model-id> [provider:<服务商>](自下一轮审查生效,仅当前会话,优先级高于全局;/advisor-model reset 恢复全局)。maxTokens 默认即 4096(有实证支撑的下限:768 会把预算耗在思考上导致空转,有实测);越界值会被钳到 64–16384 并在 /advisor-status 的「配置问题」行登记。
构建零第三方依赖,macOS 与 Windows 均可运行:
npm run build # 默认:win 全套 + 当前架构 mac 全套
node tools/companion/build-installer.cjs --mac-arch=both # 同时产出 mac x64 与 arm64
node tools/companion/build-installer.cjs --skip-win # 只出 mac
node tools/companion/build-installer.cjs --no-installer # 只出绿色包(跳过 exe/dmg)| 产物 | 平台 | 形态 | 安装方式 |
|---|---|---|---|
ZCodeAdvisor-<v>-win-x64-setup.exe |
Windows x64 | NSIS 安装器 | 双击 → 向导安装 → 桌面/开始菜单快捷方式 + 控制面板卸载项 |
ZCodeAdvisor-<v>-win-x64.zip |
Windows x64 | 绿色包 | 解压 → 双击 install.cmd(明文脚本) |
ZCodeAdvisor-<v>-macos-<arch>.dmg |
macOS | DMG 安装包 | 打开 → 把 ZCode Advisor.app 拖入 Applications |
ZCodeAdvisor-<v>-macos-<arch>.tar.gz |
macOS | 绿色包 | 解压 → ./install.sh |
两种形态的差异:安装器(exe/dmg)提供标准安装体验;绿色包全程明文脚本、可先审阅。
两者都内嵌官方 Node 运行时(Windows bin\node.exe 保留原始签名;macOS 内嵌官方二进制),
目标机无需安装 Node。DMG 内的 .app 是自包含的(运行时与控制器都在包内,不依赖 ~/Library)。
受限网络注意:nodejs.org 在部分网络下直连不通,需走代理,例如
export https_proxy=http://127.0.0.1:7897后以NODE_USE_ENV_PROXY=1运行构建(Node ≥ 22); 或设NODE_DIST_MIRROR指向可达镜像。内嵌运行时获取失败时,构建不静默:会给出警告并产出 「回退到系统 Node」的包,包内 README 与install.sh都会明确提示需要系统 Node(角标外挂需 ≥ 22,见上方版本表)。
构建完成后脚本做三层校验,任一层失败即非零退出:
- 依赖闭包:从源码
require链自动推导运行时文件清单,逐个确认已进包 (这道防线是必需的——早期硬编码清单曾漏掉zcode-path.cjs,产物装完即崩); - 系统工具交叉验证:
unzip/tar/hdiutil verify实际校验产物(工具不存在时跳过并提示; 注意unzip不是 Windows 自带,需 Git for Windows 的 CmdTools 才有); - require 冒烟:把包内 JS 释放到临时目录并真实
require一次入口,确认依赖可解析。
工具可用性(缺失时明确跳过并提示,不算构建失败):
| 产物 | 依赖工具 | 说明 |
|---|---|---|
| setup.exe | makensis |
Windows 上 choco install nsis;CI 用 windows-2022(预装 NSIS 3.10) |
| dmg | hdiutil |
仅 macOS 可构建 |
实测记录:本机(Hackintosh x86_64)的 Homebrew
makensis 3.12连最简 NSIS 脚本都std::bad_alloc崩溃(与该二进制自身有关,非脚本问题),且其 SIGABRT 会干扰同进程内随后的hdiutil调用——因此 NSIS 构建在独立子进程中执行,二者互不影响。macOS 上产出 setup.exe 因此不可靠,建议在 Windows/CI 上构建。
杀软友好形态(刻意保持,不得回退):不做自解压 dropper、不改进程名、不做隐藏启动——
NSIS 是业界标准安装器(非 IExpress 自解压),快捷方式直接指向原始 node.exe 且以最小化窗口运行。
若你的环境仍有误报,自行斟酌是否加白。
与 zcode-plus 共存:本外挂的 controller 先扫描调试端口段(9333-9350), 发现已有调试实例就直接附着(不抢占、不重复拉起 ZCode);因此与 zcode+ 谁先启动都行, ✨ 与 🛡️ 可在同一页面共存。
.github/workflows/build-installers.yml:
- 打 tag 即自动发布:
git tag v0.2.2 && git push origin v0.2.2→ 三平台并行构建 → 安装包自动挂到 Release; - 手动触发:Actions 页面
Run workflow,只上传 artifact 供验证,不发 Release。
发版前先升版本号:node tools/companion/bump-version.cjs 0.2.21
(版本号在四处,必须同值——只改一处会装出「版本号新、内容旧」的插件,见 ARCHITECTURE.md)。
流程包含一道确定性门禁:Linux 上先跑全量测试(npm test),通过后才进入打包;
macOS 侧在打包后额外做 DMG 挂载冒烟(确认 .app 与启动器存在),Windows 侧确认 makensis 可用。
为何固定
windows-2022:查证actions/runner-images得知 NSIS 3.10 预装在该镜像, 而windows-2025未预装 NSIS(只有 InnoSetup)——换镜像会导致 setup.exe 静默跳过。
ZCode 桌面版没有官方 UI 扩展机制,因此在界面内提供设置入口依赖 CDP 注入:
- 双击
启动-Advisor-ZCode.cmd(Windows)或运行node tools/companion/controller.cjs: 以调试模式拉起 ZCode(或在已有调试实例时直接附着),保持一个控制台窗口(使用期间别关); macOS 装好 DMG 后无需此步——.app会自动配置 LaunchAgent,登录即就绪(见上节); - ZCode 输入框区域右下角出现 🛡️ 顾问角标,点开即设置面板:
- 启用顾问(本会话):面板首行的独立开关(只作用于最近活动的会话,等价
/advisor-on|off); - 本会话的审查模型:当前生效目标 + 来源徽标(
全局默认/本会话固定)、服务商与模型下拉、**「固定此模型」/「使用全局默认」**两个动作; - 完整配置…:打开全局配置面板(选服务商 / 选模型 / 刷新 / 从端点拉取 / Ping / 审查模式 / max_tokens);
- 意见记录(最近 10 条)与健康图例收在折叠区,面板默认占地更小。
- 启用顾问(本会话):面板首行的独立开关(只作用于最近活动的会话,等价
- 健康状态灯(角标上的小圆点):角标带一个状态灯,由图外的 companion 每 5s 轮询本机
/api/health着色——绿=正常、黄=降级、红=审查未成功返回、灰=未知(未运行或数据过期)。只有明确成功才显绿:取不到数据一律灰,避免"灯坏了"被误读成"顾问健康"。悬停角标可看上次成功/尝试时间与失败原因。 - 注入采用
Page.addScriptToEvaluateOnNewDocument+ 当前文档补注入双通道, 页面刷新/导航后角标自动恢复;原版方式启动的 ZCode 不会有角标(无调试通道)。
macOS 用户:若自动探测不到 ZCode,在 ~/.zcode/advisor-companion.json 填
{ "zcodePath": "/Applications/ZCode.app" }(支持直接填 .app 包路径,会自动解析到内部可执行文件)。
DMG 安装的 .app 首次打开时会自动装上 LaunchAgent(~/Library/LaunchAgents/local.zcode.advisor.plist),
此后登录即自动就绪——不必再用启动器打开,直接双击 ZCode 也会有角标:
RunAtLoad:登录时自动拉起;KeepAlive{SuccessfulExit:false}:崩溃后自动重启;ThrottleInterval=30:重试间隔 30s(不会重启风暴)。- 由 launchd 监督时,controller 的退出码语义会切换:暂不可用(ZCode 正以非调试模式运行、
端口占用等)退
3让 launchd 稍后重试;永久性失败(Node 版本过低、zcodePath不可执行) 退0停止重启,避免每 30s 空转刷日志。 - 若你习惯直接打开 ZCode:那个实例没有调试端口,注入无法后补——受监督的外挂会每 30s 重试, 你**完全退出 ZCode(含菜单栏图标)**后它会自动接管并重新以调试模式拉起,无需手动操作。
管理命令(用包内 Node 运行,<app> = ZCode Advisor.app/Contents/Resources):
"<app>/node" "<app>/app/launchd.cjs" status # 查看是否已加载
"<app>/node" "<app>/app/launchd.cjs" install --now # 安装并立即加载(幂等)
"<app>/node" "<app>/app/launchd.cjs" uninstall # 卸载自启动(可逆)也可直接删掉该 plist 并执行
launchctl bootout gui/$UID/local.zcode.advisor完成卸载。
关于插件设置表单(
userConfig)的如实说明:本项目在.zcode-plugin/plugin.json中声明了userConfig设置表单(沿用 Claude Code 契约)。但 ZCode 官方插件规范 (plugin-creator的plugin-json-spec.md)只声明skills/commands/hooks/mcpServers, 未定义userConfig;在 ZCode 3.14.4 的app.asar中也未检索到插件系统处理该字段的逻辑。 因此不要依赖该表单单作为配置入口——请优先使用 🛡️ 角标 或本地配置面板。 若你的 ZCode 版本确实渲染了该表单:0.2.17 起表单只剩服务商 / 模型 / 审查模式 / max_tokens (端点与 key 已不再由本插件维护),桥接进程以「只兜底填补缺失项」语义写入用户级配置—— 表单值仅在对应键缺失/为空时落盘,已有的非空配置不被表单覆盖 (model 字段例外:非空即覆盖,作为全局审查模型生效)。
原理与限制(如实声明):ZCode 桌面版是 Electron 应用且无官方 UI 扩展机制,本外挂经 Chrome DevTools Protocol 注入页面脚本——依赖 ZCode 的非公开接口,ZCode 大版本更新可能导致角标失效(重新适配即可,hook 审查功能不受影响);调试端口仅监听 127.0.0.1;面板 API 使用随注入下发的共享令牌,本机其他网页无法调用;不承诺官方兼容性,介意者只用前文的命令/面板方式。
SessionStart ──── 创建会话状态(幂等);resume/compact 后重发注册行;清理过期状态文件
UserPromptSubmit ─ 送达积压意见(additionalContext)或注册行;无 key/已停用时控制面提示照常可达
Stop ──────────── 每轮结束时触发审查(按 reviewMode 分两条路径)
- async 模式(默认):Stop 立即返回、固定开销为亚秒级(每轮 hook 冷启动 + 一次后台进程派生)。后台
review-worker(detached 子进程,同会话互斥锁 + 全局并发上限 + 陈旧锁过滤)读取转录增量、调用审查模型、把意见写入顺延队列;你下一条消息提交时意见以additionalContext送达。代价:concern/blocker 失去"当轮打断"时机(blocker 顺延时保留[advisor:blocker]前缀可辨识)。 - sync 模式:Stop 内联审查。concern/blocker 经
{"decision":"block","reason":"…"}立即送达(宿主强制续跑,最多 3 连续轮),nit 仍顺延。代价:每轮收尾等待审查完成;reviewTimeoutMs自动钳制到 300s 且 429/5xx 重试与单次尝试共享同一截止时间(总时长不超 Stop hook 硬限 320s,避免"强杀→指针不推进→每轮重审"的停滞循环);送达前还会复查会话启停状态。
增量机制:转录按 byte offset 增量读取(按字节切行,非法 UTF-8 只污染单行内容、不影响指针),文件首部指纹(headHash)变化或体积变小(compaction/resume 重写)时全量回退;回读量超过 backfillLimitBytes(默认 2MB)时只从尾部回读。窗口默认最近 60 条实质消息、总量 48K 字符封顶(长消息场景实际生效的是字符帽),并保底保留最早的用户指令(该注入不受字符帽约束);思考链不送审;advisor 自身注入的内容按 [advisor: 前缀过滤;"有完整行但零解析产率"会计 parse_empty(转录格式异常的可观测信号)。
状态写纪律:所有写路径(UPS/ctl/Stop 父进程/worker 落盘)经由跨进程短临界区(.wrlock,写前后双重属主校验)重读最新状态后做字段级合并——审查在飞期间执行的 /advisor-off、/advisor-model set、意见投递不会被 worker 的落盘覆盖(有真实子进程 + 挂起 TCP 服务的并发回归测试保障);UPS 只清除自己已投递的意见,不吞并发入队的新意见。
| dsh-advisor | 本插件 | 说明 |
|---|---|---|
agent.inject(nit) |
UserPromptSubmit additionalContext |
语义一致:不唤醒、下个边界消费 |
agent.steer(concern/blocker) |
sync:Stop block;async:顺延队列 | async 是宿主约束下的选择(见上),非被迫 |
| 每步审查(step boundary) | Stop 时点审查 | zcode 无逐步注入通道,粒度为整轮 |
immuneTurns / maxDeltaMessages / maxTokens / systemPrompt |
同名配置 | 语义一致;冷却设点差异见下 |
proseFallback |
同名配置,本移植默认 true | 上游默认 false;对齐 dsh 端本地补丁 v2.2 的生效状态。守门规则见下 |
enabled 配置键(已废弃) |
同样没有 | 插件管理里的启用开关即主开关;会话级用 /advisor-on /advisor-off |
/advisor status|on|off|model |
/advisor-status /advisor-setup /advisor-on /advisor-off /advisor-model |
会话级命令经注册行里的状态文件路径精确定位本会话;多会话并存时裸 ctl 会被拒绝,防误伤 |
| provider + model 硬门禁 | 第三方服务商 + model + key 硬门禁 | 缺任一项绝不发起调用;门禁失败时注册行照常投递(含可操作原因),命令通道不失联 |
冷却(immuneTurns)口径如实声明:sync 在 block 真正发出时进入冷却;async 在入队成功时进入冷却(无投递回执下的近似,间隔至多一个 UPS 边界)——入队后若会话终止未送达,冷却已消耗。冷却期内的 deferred concern 不算送达、不进冷却。maxBlocksPerTurn 是纵深防御,正常流程下主防护是 stop_hook_active 跳过续跑轮。status 中的 steer 计数:sync=实际送达数,async=入队数。
dsh 端教训(ADVISOR-GUARD-REPORT.md,issue #102)的吸收情况:
- 散文救回三条守门:只剥离成对 markdown 标记(
**粗体**、行内反引号、围栏行),绝不全局删* _ >(否则破坏snake_case_var、x => y、*.ts);以{/[开头、括号不配平、含note:键特征的回复不救回(避免注入半截 JSON);救回的 severity 一律 nit,按 Unicode 码点截断(不劈开 emoji)。默认开启。 - 多帧解析:模型输出中混杂伪码
{a:1}不会杀死后面的真帧(扫描全部配平块,取最后一个合法帧——模型自我纠正语义;不用 max-of-N,避免放大转录注入面)。 - 可见性:
/advisor-status输出Dropped分类计数与 Token 累计(usage 解析入账),杜绝"看似在运行、实际不产出"。
配置加载优先级:环境变量(逃生舱)> ZCode 第三方服务商解析 > 用户级 ~/.zcode/advisor.config.json > 插件目录 advisor.config.json > 内置默认(损坏的层自动跳过并把 config_invalid 挂到"配置问题"行展示)。环境变量逐项覆盖,命名 camelCase → ZCODE_ADVISOR_SNAKE_CASE:
0.2.17 起端点与 key 不再由本插件维护:审查通道的唯一来源是 ZCode 里已维护的第三方服务商 (
~/.zcode/v2/config.json的provider.*,排除builtin:官方内置通道)。 旧配置里的apiKey/baseUrl/apiSource/zcodeModel一律失效并在下次写入时被清除。
| 键 | 默认 | 说明 |
|---|---|---|
zcodeProvider |
空 | 全局审查服务商(ZCode provider 的 id,容忍写名称)。留空 = 自动选择(优先含所填模型的可用第三方服务商,否则第一个可用的)。必须是非官方内置 + 协议受支持(OpenAI 兼容或 Anthropic)+ 端点/key 齐备,否则门禁拦下并在「配置问题」行给出原因 |
model |
空 | 全局审查模型;留空取所选服务商登记清单首项。建议与主模型形成能力差,思考型模型配 maxTokens: 4096。会话级覆盖见 /advisor-model 与角标面板 |
protocol |
自动 | 审查协议(只读展示,不是可落盘的配置键):openai(chat/completions)或 anthropic(/v1/messages)。一律由所选服务商的协议自动推导;唯一的显式覆盖入口是环境变量 ZCODE_ADVISOR_PROTOCOL(必须与 ZCODE_ADVISOR_BASE_URL+ZCODE_ADVISOR_API_KEY 同时给)。刻意不开放为配置键:协议与端点/凭据是一个三元组,分开配会让 key 以错误的鉴权方案发出 |
apiKeyEnv |
见文件 | 仅环境变量逃生舱:ZCODE_ADVISOR_API_KEY 等(CI/特殊部署)。占位符样式值(REPLACE_*、test*、含中文的模板文案等)视为未配置。共享 env key 发往非签发方端点会触发警告 |
reviewMode |
async |
async(亚秒级固定税,意见下条消息送达)或 sync(立即打断,超时自动钳制 ≤300s) |
immuneTurns |
3 | steer 后的冷却轮数;冷却期内 concern 降级顺延(blocker 不受限) |
maxDeltaMessages / maxContextChars |
60 / 48000 | 送审窗口(条数 / 总字符)。两者同时生效,长消息下字符帽先到 |
maxTokens |
4096 | 单次审查输出预算;接受字符串数字,越界钳到 64–16384 并登记「配置问题」 |
fallbackModel |
空(关闭) | 降级备用模型:主模型遇白名单错误(llm_empty_response/unparsed/llm_http_404)时临时换用它,端点/key 不变。仅 async 生效(sync 下会砍半 primary 预算,已禁用)。建议配快模型/非思考型——它要在主模型烧剩的预算里跑完。降级成功会写 history 的 degraded 事件并触发独立降级告警(不掩盖主模型劣化) |
temperature |
0.2 | 审查调用温度 |
proseFallback / maxNoteChars |
true / 768 | 无 JSON 帧时把清洗后的散文救回为 nit;JSON 帧与散文的 note 统一按码点截断到该上限 |
systemPrompt |
内置 | 完全替换内置审查提示词(含 advisory-only 纪律)。注意:插件目录可被会话内的工具写入,不建议设置——保持内置纪律不可被改写 |
startEnabled |
true | 新会话是否自动启用(会话级仍可 /advisor-off) |
maxBlocksPerTurn |
2 | sync 单轮 steer 上限(纵深防御,正常流程不触达) |
reviewTimeoutMs |
240000 | 单次审查超时(含重试共享截止);<1000 回退默认,sync 钳制 ≤300000,async 钳制 ≤600000(async 单轮总预算为其 2×,仍小于 worker 锁过期窗 2×+60s) |
maxGlobalWorkers |
4 | 全局同时在飞审查上限(跨会话,只计新鲜锁),超限计 global_busy |
backfillLimitBytes |
2097152 | offset 大幅落后时的尾部回读上限 |
pendingNotesCap |
5 | 顺延队列上限,溢出计 queue_overflow |
stateDir |
插件数据目录 state/(无则退回插件目录内) |
会话状态目录。默认优先使用宿主插件数据目录(ZCODE_ADVISOR_PLUGIN_DATA,跨版本升级保留——待真机确认);需确保跨升级时显式配置到插件目录外 |
调试环境变量:ZCODE_ADVISOR_DEBUG=1(hook 异常栈写 stderr,见宿主 hook 运行记录)、ZCODE_ADVISOR_DRY_RUN=1(sync 演练,不真正 block、不虚增计数)、ZCODE_ADVISOR_MOCK=1 + ZCODE_ADVISOR_MOCK_FRAME='{"severity":"concern","note":"…"}'(免 key 联调;需同时在 state 目录放 .mock-allowed 空文件,否则静默滑入真实调用并给出注册行警告;mock 帧与生产同口径校验)。
| 命令 | 作用 |
|---|---|
/advisor-setup |
交互式配置:选择审查服务商与模型 → 写入用户级配置 → ctl doctor --probe 当场验证能力(--n 5 采样、--model <id> 逐个测候选);只想看连通性用 --ping。端点与 key 由 ZCode 服务商维护,本命令不收集 |
/advisor-status |
状态:启用/门禁/模式/服务商与模型及来源/审查与 steer 计数/Token 累计/顺延队列/Dropped 分类/配置问题与警告 |
/advisor-on /advisor-off |
当前会话启停(临时覆盖;审查在飞时执行也不会被回滚;停用会话仍可用注册行自救) |
/advisor-model |
查看审查服务商/模型及来源(全局默认 or 本会话覆盖);set <模型id> [provider:<服务商>] 本会话固定、provider <id> 只换服务商、reset 回落全局默认(下一轮生效) |
/advisor-api |
0.2.17 已移除:审查凭据一律来自 ZCode 第三方服务商,不再支持会话级端点/key 覆盖 |
命令通过首条消息注入的 [advisor] 注册行定位(含脚本与状态文件两个绝对路径;门禁失败/会话停用时也会投递或重发)。ctl doctor 可随时做无会话体检:配置解析链、服务商与 key 来源(脱敏)、门禁;ctl doctor --probe 用生产参数跑 N 次能力探针并输出通过率与耗时分布(不做「可用/不可用」判决——可用性是概率属性),--ping 则是最小连通性检查。ctl providers [--all] 列出 ZCode 里可用的第三方服务商(--all 含被排除项与原因)。
npm test # 全量测试(用例数随开发增长,不在此写死;实际数量见命令输出)
# 覆盖:配置分层/状态临界区/转录增量与指纹/帧解析与散文救回/路由/端到端(含 P0 并发回归)
# + 归档读写(ZIP/TAR 字节结构与系统工具交叉校验)
# + ZCode 路径探测(macOS .app 解析 / Windows 候选链 / 降级链)
# + 安装模板、图标生成(ICO/ICNS 经系统工具校验)、运行时依赖闭包
# + 页面注入脚本行为(样式注入、令牌版本、模型下拉、403 提示)
npm run build # 构建发行包(构建后自动做三层产物校验)mock 链路验证(以下命令需 Git Bash 和含 test/fixtures 的源码仓库;安装缓存不含测试 fixture。PowerShell 用户请用等价写法,注意 JSON 内路径需用正斜杠或双反斜杠):
cd "<仓库根目录>"
mock_home="$(mktemp -d)"
mkdir -p "$mock_home/state" "$mock_home/.zcode"
touch "$mock_home/state/.mock-allowed"
printf '{"enabled":true}\n' > "$mock_home/.zcode/advisor.config.json"
HOME="$mock_home" USERPROFILE="$mock_home" ZCODE_ADVISOR_STATE_DIR="$mock_home/state" \
ZCODE_ADVISOR_MOCK=1 ZCODE_ADVISOR_MOCK_FRAME='{"severity":"blocker","note":"演示"}' \
ZCODE_ADVISOR_BASE_URL=http://127.0.0.1:9/v1/chat/completions \
ZCODE_ADVISOR_API_KEY=e2e-key ZCODE_ADVISOR_MODEL=mock-model ZCODE_ADVISOR_REVIEW_MODE=sync \
node hooks/advisor-hook.js stop <<< '{"session_id":"demo","transcript_path":"test/fixtures/transcript-basic.jsonl","stop_hook_active":false}'
# 期望 stdout:{"decision":"block","reason":"[advisor:blocker] 演示(以上来自审查副模型……)"}
printf '隔离目录(验证后可手动删除):%s\n' "$mock_home"端点和 key 必须成对覆盖;上例回环端点仅用于安全 mock,不是真实服务。.mock-allowed 与 ZCODE_ADVISOR_STATE_DIR 必须指向同一状态目录。
接真实模型:在 ZCode 设置里配好一个 OpenAI 兼容(或 Anthropic 协议)的第三方服务商 → 🛡️ 角标「完整配置」里选中它并 Ping OK(或 /advisor-setup 引导选择)→ 新开会话 → 首条消息出现 [advisor] 注册行 → 几轮后 /advisor-status 看 审查次数 与 Token 累计 增长。
/advisor-status 的 Dropped 行按类别定位(config_invalid/config_out_of_range 属于"配置问题"行,不在 Dropped 内):
| 类别 | 含义 | 处置 |
|---|---|---|
llm_empty_response |
模型把输出预算耗在思考上,正文为空 | maxTokens 提到 4096 |
unparsed |
无合法 JSON 帧且救回被守门拒绝 | 确认 proseFallback: true;换格式稳定的模型 |
llm_timeout |
审查超时(含重试共享截止) | 提高 reviewTimeoutMs(sync 已自动钳制 ≤300s)或缩小 maxDeltaMessages(20~30) |
| 面板保存 503 | 配置文件正被其他进程写入(跨进程锁在保护它) | 等几秒重试;持续出现则删除 ~/.zcode/advisor.config.json.lock(进程崩溃残留,锁协议会自动接管死主的锁,正常无需手动) |
llm_http_4xx/5xx |
端点/认证/限流错误 | 检查 key 与模型 id;429/5xx 已内置一次共享截止的退避重试 |
llm_error |
网络层失败(DNS/连接) | 检查端点可达性 |
no_transcript |
转录文件缺失 | 宿主契约问题,带 ZCODE_ADVISOR_DEBUG=1 反馈 |
parse_empty |
转录有完整行但全部无法解析 | 转录格式与预期不符,带样例反馈 |
busy / global_busy |
同会话在审 / 全局并发达上限(只计新鲜锁) | 正常现象;高频出现说明审查耗时超过交互节奏,缩小窗口 |
queue_overflow |
顺延队列满(cap 5) | 意见产出快于消费,属正常丢弃 |
spawn_failed / worker_error |
后台派生失败 / worker 内部异常 | 带调试日志反馈 |
其他:无 key/停用状态下不会全哑——控制面提示照常可达;每轮收尾变慢 → 确认在 async;长会话后命令失联 → resume/compact 会重发注册行。
- 注入链残余风险(如实声明):本插件向主会话新增两条自动注入通道(sync 的 Stop block、async 的 additionalContext)。能影响转录内容的一方(被 Read 的网页/代码注释/工具输出)理论上可经审查模型植入 note 影响主模型;缓解是 note 码点截断(768)、帧校验(多帧取末帧而非最高severity)、advisory 前缀与"仅供参考"框架、内置提示词禁止 note 携带可执行指令——但对蓄意注入无硬性防线。选型提示拆开说:担心注入链 → 用 async(无强制续跑);担心 blocker 迟到 → 用 sync(当轮打断),两个维度独立决策。
- 敏感数据外发(如实声明):转录增量(代码、路径、可能的密钥)不做脱敏直接发送到
baseUrl;主模型 Read.env后其内容会进入转录并外发。当前无可配置脱敏规则——请自行权衡端点可信度;插件目录(含本配置文件)可被会话内工具改写,"独立审查"对被审查者不设防,/advisor-status的配置警告行可辅助发现端点篡改。 - key 落盘:用户级配置(
~/.zcode/advisor.config.json)不在任何 git 仓库内、跨升级保留;插件目录的advisor.config.json已被 gitignore(模板见 example)。共享 env key(ZAI_API_KEY等)发往非官方端点会在状态中警告;http://非本机端点会警告明文传输。 - 成本可观测:每次调用的 usage 解析入账(
/advisor-status的 Token 累计;数字来自端点自报,恶意端点可伪造);单次调用输入上限 48K 字符 +maxTokens输出,单轮(含空响应重试)最多 3 次调用、总耗时 ≤ 预算上界(sync=1×、async=2×reviewTimeoutMs)。空转(有调用无产出)在Dropped:llm_empty_response可见。
- async 模式下 concern/blocker 没有"当轮打断";blocker 顺延送达时任务可能已完成(时效损失未完全缓解,仅有前缀可辨识)。
- sync 模式受 Stop hook 硬超时 320s 约束(配置与重试已联动钳制),且宿主"最多 3 连续续跑"为文档声明、未实测。
- 被宿主强杀/会话释放杀掉的 worker 无法自我计数:该轮意见丢失且不计入任何 Dropped 类别;其残留锁在
staleMs(约 9 分钟)内会让该会话计busy(全局额度只计新鲜锁,不受影响)。 - resume/compact 后全量回读(窗口截断保护)可能对最近的旧事重提一条意见。
- 转录按 Claude Code 同构 JSONL 容错解析,尚未在真实 zcode 转录上验证过;宿主格式差异的表现为
parse_empty信号 + 审查无产出,不崩溃。 - headHash 指纹取文件头 64 字节:若真实转录前 64 字节为纯样板(跨重写恒定),重写检测退化为"仅变小才重置"——真机验证项。
- 单 advisor、单模型;无会话内面板、无转录持久化。逐步(step-boundary)审查未实现,粒度为整轮。
- 降级(fallback)仅 async:sync 下单轮受 Stop 硬超时约束,切预算会复活"强杀→指针不推进→每轮重审"停滞循环,故禁用。且只在"换模型能治"的白名单错误上切换(401/403/429/5xx/timeout 都不切——那是 key/端点问题)。
- 配置面板的 Ping 仍按旧口径(
max_tokens=1,思考型模型会误报 OK);能力探针ctl doctor --probe是 CLI 入口,面板用户暂不受益。三处 ping 的统一是后续项。 - 健康状态灯依赖 CDP 角标:controller 未运行时角标不存在,也就没有灯(不是"灯变灰",是"没有灯")。此时用
/advisor-status或ctl doctor兜底。
zcode-advisor/
├─ .zcode-plugin/ plugin.json + marketplace.json(含展示元数据)
├─ .claude-plugin/ marketplace.json(Claude Code 兼容副本)
├─ hooks/hooks.json SessionStart / UserPromptSubmit / Stop 三个 process 型 hook
├─ hooks/advisor-hook.js 入口:事件分发 + review-worker + ctl(含 doctor)
├─ hooks/lib/ config(分层加载)/ state(临界区写)/ transcript(字节级增量)/ reviewer / route
├─ commands/ /advisor-setup /advisor-status /advisor-on /advisor-off /advisor-model
├─ tools/ config-bridge.js(设置表单桥)+ setup-server.js(本地网页面板)
├─ tools/companion/ 输入框角标外挂与打包:
│ ├─ controller.cjs CDP 注入 + 本机 API(macOS/Windows 双平台探测)
│ ├─ inject.js 页面角标 + 设置面板
│ ├─ lib.cjs 模型端点推导(纯函数)
│ ├─ zcode-path.cjs ZCode 可执行文件探测(含 .app 解析)
│ ├─ archive.cjs 零依赖 ZIP/TAR 读写
│ ├─ icon.cjs 零依赖 ICO/ICNS/PNG 生成
│ ├─ install-templates.cjs 明文安装脚本模板
│ ├─ build-meta.cjs 版本号单一来源
│ └─ build-installer.cjs 发行包构建(跨平台)
├─ 配置面板.cmd 双击打开本地网页配置面板
├─ 启动-Advisor-ZCode.cmd 双击以角标模式启动 ZCode(CDP 注入)
├─ advisor.config.json 插件目录兜底配置(gitignore;模板见 advisor.config.example.json)
├─ test/ node:test 单测 + mock 端到端 + P0 并发回归 + 面板/桥接/companion/归档/路径测试
└─ state/ 兜底状态目录(默认优先宿主插件数据目录)
MIT