# bonus-plan-4-open-zcode **Repository Path**: wangwang668/bonus-plan-4-open-zcode ## Basic Information - **Project Name**: bonus-plan-4-open-zcode - **Description**: 在开源zcode中使用闭源版的免费赠送plan的插件。 - **Primary Language**: Unknown - **License**: Not specified - **Default Branch**: master - **Homepage**: None - **GVP Project**: No ## Statistics - **Stars**: 0 - **Forks**: 2 - **Created**: 2026-10-02 - **Last Updated**: 2026-10-02 ## Categories & Tags **Categories**: Uncategorized **Tags**: None ## README # zcode-bonus-plan 让**开源 ZCode**(zai-org/ZCode)用上**闭源客户端才有的赠送免费 plan** (`account:bigmodel-start-plan` → `zcode.z.ai/api/v1/zcode-plan/anthropic`)。 - ✅ **纯插件**:不改壳一行源码、不重新构建壳、不打补丁 - ✅ **静默 captcha(按需)**:以 ZCode 自己的 Electron 为载体(离屏隐藏 iframe),不碰 GUI、不建任务;上游不需要验证时**完全不产出** - ✅ **多账号池**:各账号独立凭据与额度,用尽自动切换 - ✅ **零运行时依赖**:只用 Node 内置模块 > 📦 **预编译的开源版 ZCode**(不用自己构建): > > —— 提供**安装程序**与 **portable** 两种形态(分卷 zip,需用 7-Zip 解 `.001`)。 > 一条命令装 portable:`pwsh -File scripts\install-portable-zcode.ps1 -Zip <...zcode-portable.zip.001>`; > 详见「[如何获得「开源版」宿主](#如何获得开源版宿主)」。 ## 灵感与实证来源 本项目的实现是独立编写的,但有几个**关键发现**直接受益于下面两个项目 —— 记录下来, 一是致谢,二是让后来者能顺着源头复核这些结论。 ### [dsh-free-glm](https://github.com/MYCF711/dsh-free-glm) 免费通道这件事上,它是最早把路走通并留下实证的项目。本项目从中受益的点: - **闭源版 captcha 的所在位置**:captcha 生产代码(阿里云 SDK 调用)在**闭源发行版** `app.asar` 打出的 renderer bundle 里,而**不在开源仓库**(`packages/ui/src/captcha` 在开源版里根本不存在)。本项目据此才敢下「只接受开源版」这个判断 —— 并用它反向 识别闭源发行版(见「宿主守卫」)。 - **开源 ZCode 的构建经验与坑**:必须跑**完整** `desktop build`;只跑 `build:no-runtime-assets` 会跳过内置 agent bundle,壳随后以 `unsupported_runtime` **静默失败**(构建退出码仍是 0)。这条被写进了 `setup-open-source-zcode.ps1` 的体检。 - **Electron 上的 CDP 硬限制**:`Target.createTarget` 返回 `Not supported`、 `PUT /json/new` 报 500 —— 所以「另开一个页面当载体」在 Electron 里走不通。本项目 因此改用**离屏 iframe**(见「为什么 captcha 跑在离屏 iframe 里」)。 - **环境变量约定**:`ZCODE_BRIDGE_APP_DIR` / `ZCODE_BRIDGE_ELECTRON_PATH`。本项目的 启动脚本探测兼容这两个变量(用它们反推检出根)。 - **复用而非重开**的方向:captcha 载体应当复用同一个 Electron 实例,而不是每次重开。 ## 它怎么工作 ``` ZCode(自定义 provider,一次性配置) │ baseURL = http://127.0.0.1: ▼ 本插件(壳 spawn 的 MCP server 子进程) ├─ /v1/messages Anthropic 兼容代理:选号 → 先不带 captcha 探(被 3007 拒才产出)→ 直发上游 → SSE 透传 ├─ /ui 管理面板(账号池 / 额度 / 领取 / 观测) └─ CDP ─────────► ZCode 自己的 Electron:在 renderer 里挂一个离屏隐藏 iframe (真实 https origin https://zcode.z.ai/)产出阿里云 captcha ▼ zcode.z.ai/api/v1/zcode-plan/anthropic(直发,不经壳的服务层) ``` ### 免费通道什么时候要 captcha(实测,2026-10-01) **它并非总是必需** —— 取决于 provider 的 `access.mode`。源码依据 (`apps/zcode-cli/packages/adapters/src/model/runner.ts:164`): ```ts const requestAuthRequired = options.providerConfig.access.type === "zhipu-account" && options.providerConfig.access.mode === "off-peak"; // ← 只有它才强制刷新运行时头 ``` | 情形 | 壳会不会索要验证头 | 结果 | |---|---|---| | `mode = normal`(默认/常见) | **不索要** | 官方通道**直连可用**,全程零验证 | | `mode = off-peak`(闲时排队协议,业务码 3105/3102) | **强制索要** | 开源壳的 renderer 没有 captcha 生产者 ⇒ `Provider runtime headers request timed out`,**180 秒超时** | 支撑数据: - **零验证的直接证据(抓包)**:一次完整的「打开壳 → 用官方 start plan 发一条 → 收到回答」 抓包(32 秒 / 4674 包)里,`captcha`、`aliyun`、`alicdn`、`verify`、`geetest`、`hcaptcha`、 `recaptcha` 相关包**全部为 0**;访问的域名只有 `zcode.z.ai`、`cdn-zcode.z.ai`、`bigmodel.cn` (其余是系统其他软件的流量)。 - **日志佐证**:同一次会话 14/14 条 start-plan 请求 `try=1` 成功,且**零**"索要运行时头"事件。 - **超时只出现在另一条路径上**:`off-peak` / 带桥接补丁的场景累计 222 次 `Provider runtime headers request timed out`(这也是"开源版不能用免费通道"这个说法的最初来源—— 它其实只对那条路径成立)。 - **开源侧确实没有生产者**:源码里 `captcha` 零命中;闭源发行版的 `initAliyunCaptcha` / `o.alicdn.com/captcha-frontend` / `AliyunCaptchaConfig` 在开源构建产物里 一个都没有;16MB 的 agent `zcode.cjs` 里**连 "captcha" 这个词都不存在**——它只实现了 "向宿主索要运行时头"这个协议,头名与内容完全由宿主 renderer 提供。 **本插件怎么处理**:走自己的本地代理直连上游,**先不带验证头探一次**,被 `3007 captcha verify failed` 拒了才产出("要了才取")。所以无论上游要不要验证都按最省的方式工作: 不需要时 captcha 耗时 **0ms**,需要时自动补上并记住 2 分钟(避免连续请求反复吃 3007)。 另一道门**始终存在**: 2. **请求体身份块**:`system` 必须以官方身份块结构开头,且首轮 user 消息要带 `` 日期块,否则 `3012 unusual activity` (**该错误有账号冷却惩罚,不要反复触发**)。 (**该错误有账号冷却惩罚,不要反复触发**)。 ### 为什么 captcha 跑在「离屏 iframe」里 Electron 不支持通过 CDP 新建页面(实测 `Target.createTarget` → `Not supported`、 `PUT /json/new` → 500),而壳 renderer 自身的 origin 是 `file://`(风控不接受)。 因此插件在壳的 renderer 里挂一个**离屏、不可见、不可点**的 iframe (`position:fixed;left:-99999px;opacity:0;pointer-events:none` + `aria-hidden`), 让它跨站加载 `https://zcode.z.ai/`(Chromium 会为它建独立进程目标), 再通过 CDP 只在该 iframe 内执行 captcha 动作。 **对 ZCode 的影响**:只增删插件自己的那个元素 —— 不碰界面(React 树)、 不调壳的 API、不建任务、不发 prompt;用完即 `remove()`。 > 本机实测(headless 静默实例):mint 成功 1716ms、param 长度 280、无感通过、 > 合法性校验通过;第二次热复用 690ms(param 仍是一次性、每次不同)。 > > **复用优化后**(移植自参考实现提交 2511113,见下):新建帧 1808ms / > 复用 421ms / **空闲 20 秒后仍是 473ms** —— 修复前该场景会因「预测式换帧」 > 白付 2600-3500ms(这正是「签到要等很久」的成因)。 ## 安装 ```powershell # 1. 构建(产出 lib/,插件运行需要它;.gitignore 里排除了 lib/,故必须自己构建) pnpm install pnpm build # 2. 把插件目录登记进 ZCode CLI 的用户配置(~/.zcode/cli/config.json) # { # "plugins": { # "enabled": true, # "dirs": ["<本仓库的绝对路径>"] # } # } ``` ZCode 会在启动时发现 `.zcode-plugin/plugin.json` 并 spawn 本插件的 MCP server, 代理与面板随之一并启动(每个会话一个实例,只有第一个是主实例)。发现文件 (端口 + token + 面板地址)写在: ``` <数据目录>/proxy.json ``` **设置页里可以改的**:ZCode「设置 → 插件 → zcode-bonus-plan」里有 `cdp_port` 选项(ZCode 桌面端的 CDP 调试端口,默认 9229)—— 它经 `${user_config.cdp_port}` 注入成 `BONUS_PLAN_CDP_PORT`,改完重启 ZCode 生效。 > ⚠ ZCode 必须**在运行**(它是 captcha 的载体)。想在没有 ZCode 会话时也保持 > 代理与面板可用,用 `pwsh -File scripts\start-proxy.ps1` 常驻一份(与壳 spawn 的 > 实例通过单实例判定共存)。 ### 启动脚本怎么找到开源 ZCode(**只接受开源版**) `scripts\start-zcode.ps1` 按顺序**多来源探测**并打印命中的来源。其中 PATH 也是来源之一 —— **portable 产物不写注册表、不留快捷方式,只有 PATH 能发现它**。 | 顺序 | 来源 | 说明 | |---|---|---| | ① | 参数 `-ZCodeRoot` / `-ZCodeExe` | 显式指定;无效或闭源时**直接失败、不回退**(避免你以为用的是它) | | ② | 环境变量 `BONUS_PLAN_ZCODE_ROOT` / `BONUS_PLAN_ZCODE_EXE` | 无效则记下并继续(可能是陈旧配置) | | ③ | **正在运行的安装版进程** | 最该用它 —— **插件就是它 spawn 的**,用它才自洽 | | ④ | **正在运行的源码构建进程** | 同上(用户此刻正在用) | | ⑤ | 注册表卸载项 | `DisplayIcon` / `UninstallString` 反推真实安装位置 | | ⑥ | 快捷方式(含 `Scoop Apps`) | 用户怎么装都会留快捷方式 | | ⑦ | **PATH(portable)** | 扫进程 PATH + 用户级/机器级注册表 Path 里的条目;`resources\app.asar`(或解包的 `resources\app\`)在同级才算命中 | | ⑧ | scoop | `$SCOOP` / `$SCOOP_GLOBAL` / `~\scoop` 下的 `apps\zcode\current` 与逐版本目录 | | ⑨ | 父目录一层通配(安装形态) | 覆盖装到任意子目录的绿色版 | | ⑩ | 常见安装位置 | `%LOCALAPPDATA%\Programs\ZCode`、`ZCode Preview` 等 | | ⑪ | **源码检出候选(兜底)** | 多盘符 × 常见父目录 × 常见名字,外加父目录一层通配 | **为什么安装版排在源码检出之前**:源码检出只是**开发形态**,常常是历史遗留 (free-glm 时代留下的旧检出)。把它排前面,磁盘扫描会抢在用户刚装的正式包之前命中 —— 变成「明明装了新包,脚本却去起三年前的旧检出」(实测踩过这个顺序错)。 **为什么「来源」不决定「结论」**:开源/闭源由**判据**决定(扫 `app.asar` 里有没有 captcha 生产代码),不看它是安装版还是源码版 —— 实测:官方安装包判 ✗ 闭源被拒, 而用开源仓库自建的 `ZCode Preview` 安装包判 ✓ 开源可用。 **主程序名不写死**:先看目录里的 `*ZCode*.exe`(取体积最大者,排除 `Uninstall*`/`elevate` 等); 若 `productName` 被改成完全无关的名字,则靠 `resources\glm\zcode.cjs`(ZCode 特有的内置 agent bundle) 这个**结构标记**兜底认出宿主 —— 比文件名可靠。 主程序名**不写死 `ZCode.exe`**:electron-builder 的 `productName` 可变(实测有 `ZCode Preview.exe`),所以按目录解析「体积最大的 `*ZCode*.exe`」,并排除 `Uninstall*` / `elevate` / `crashpad` / `helper` / `updater`。 > 探测不到时,`-List` 会把每个候选标成 ✓/✗ 并给出原因(如「闭源发行版…拒绝」)—— > 「你装的那个 ZCode 是闭源版,所以不能用」比「找不到 ZCode」有用得多。 #### ⚠ 为什么必须区分「开源版」与「闭源发行版」 实测(本机,两份官方安装包): | 形态 | renderer 是否有 captcha 生产能力 | 能否做宿主 | |---|---|---| | **源码构建**(github zai-org/ZCode) | **没有**(`packages/ui/src/captcha` 不存在,renderer 产物搜不到 `initAliyunCaptcha`) | ✅ 正是我们要的 | | **官方安装包 / scoop 安装** | **有**(`app.asar` 里同时命中 `initAliyunCaptcha`、`o.alicdn.com/captcha-frontend`、`AliyunCaptchaConfig`) | ❌ **拒绝** | 闭源发行版**自己会为免费通道刷 captcha**(这是它内置的能力);插件再刷一次就是 **双倍消耗** —— 同一账号的验证配额与设备信誉被吃两遍。所以脚本会扫描候选的 `app.asar`,把自带 captcha 的一律标为闭源并跳过(在 `-List` 里能看到原因)。 > 判定读不出来时**保守视为闭源**:误拒只让用户多设一个参数,误收会造成双倍消耗 —— > 两种错的代价不对称。 #### ⚠ 运行时保护(脚本层的拒绝不够) 实测:**闭源版同样会加载本插件**(它用官方的 `__zcode-plugin-host` spawn 我们的 MCP server)。所以直接双击桌面快捷方式启动闭源版时,插件照样会去 mint → 双倍消耗 依然发生。 因此插件在**运行时**自己也会判断:通过 `process.ppid` 向上遍历进程链找出宿主 (`ZCode.exe` = 打包版 / `node_modules\electron\dist\electron.exe` = 源码构建), 用与脚本相同的判据识别闭源版,命中就**拒绝产出 captcha** 并说明原因。判定结果: - 首次真的要去产 captcha 时才检测(懒执行),并按「宿主根目录」缓存到 `<数据目录>/host-scan.json`,所以 312MB 的 asar 不会每次请求都扫 - 面板「状态」与 `bonus_plan_status` 工具会显示宿主判定(开源版 / 闭源发行版 / 未确认) - 判定不出来时(拿不到进程信息等环境限制)**放行但告警** —— 不因环境限制让插件完全不可用 - 逃生口:`BONUS_PLAN_ALLOW_CLOSED_HOST=1` 强制放行(判定误伤时用,后果自负) ```powershell # 看有哪些候选、哪些是开源版(每份都标 ✓/✗ 与原因) pwsh -File scripts\start-zcode.ps1 -List # 只看探测过程与将要执行的命令(不启动) pwsh -File scripts\start-zcode.ps1 -WhatIfCommand # 换机器时指定源码检出 pwsh -File scripts\start-zcode.ps1 -ZCodeRoot "E:\ZCode-official" ``` 判定结果按「路径 + 大小 + 修改时间」缓存在 `%TEMP%\bonus-plan-captcha-scan.json`, 所以 300MB 的 asar 只在首次探测时扫一遍。 ## 接入 ZCode 1. **启动 ZCode 桌面端**(源码构建运行模式;调试端口默认 9229)。 端口不同时设环境变量 `BONUS_PLAN_CDP_PORT=<端口>`。 2. **打开管理面板**(`proxy.json` 里的 `panel` 字段,形如 `http://127.0.0.1:/ui`),点「添加账号」完成浏览器授权 (也可粘贴凭据 JSON)。 3. **在 ZCode 里添加自定义供应商**(设置里的实际文案): | 步骤 | 界面文案 | 填什么 | |---|---|---| | ① | 设置 → 模型 → **添加供应商** | — | | ② | 选 **自定义端点**(不是「供应商目录」) | — | | ③ | **Base URL** | `http://127.0.0.1:17899` | | ④ | **API Key** | 面板给出的 token | | ⑤ | **API 格式** | **Anthropic Messages**(我们只实现 `/v1/messages`) | | ⑥ | 模型 | 至少加一个:`GLM-5.3-Flash`(或 `GLM-5.3`) | 4. 在会话里选该供应商的 `GLM-5.3-Flash` 开始对话。 > ⚠ 第 ⑤ 步别选错:三个选项是 `Chat Completions (/v1/chat/completions)`、 > `Responses (/responses)`、`Anthropic Messages (/v1/messages)`。插件只实现最后 > 那条路径,选前两个会 404。 > ⚠ 关于「要不要切到我们的代理」——**取决于壳的模式**(细节见上文 > 「免费通道什么时候要 captcha」): > > - `access.mode = normal`(默认)时,壳自带的 `account:bigmodel-start-plan` > provider **可以直连成功**(实测 14/14、抓包零验证流量),此时不切也能用; > - `access.mode = off-peak` 时,壳会先向 renderer 索要一次性验证头,而开源壳 > **没有 captcha 生产者** ⇒ 请求会一直挂住到 **180 秒超时**(日志表现: > `Provider runtime headers request timed out`)。 > > **我们的代理对两种模式都成立**:它绕过壳直连上游,先不带验证头探一次, > 被 `3007` 拒了才产出 captcha("要了才取")。所以想要 > **不受壳的模式影响 + 多账号池 + 额度耗尽自动切号 + 每日自动领取**,就用它。 ### 代理端口是固定的(配一次长期有效) 默认 **17899**(可用环境变量 `BONUS_PLAN_PORT=<端口>` 覆盖,`0` 表示随机)。 端口的稳定性很要紧:ZCode 里配好的 provider baseUrl 指向它,**端口一变那份配置就失效**。 若 17899 被别的程序占用,插件会**自动回退随机端口**并在日志/面板里如实告知 —— 此时请用面板显示的新端口更新 provider 配置。 **访问 token 同样持久化**(初次生成后存到数据目录的 `proxy-token.txt`,进程重启不变)—— 否则你在供应商里填的 API Key 每次重启 ZCode 就失效(表现为 401)。可用环境变量 `BONUS_PLAN_TOKEN` 覆盖。 ## 在会话里使用(不需要打开面板) 插件注册了 7 个 MCP 工具与一个斜杠命令,日常操作可以直接在 ZCode 会话里完成: | 你说 | 调用的工具 | 效果 | |---|---|---| | 「免费额度还能用吗 / 插件正常吗」 | `bonus_plan_status` | 账号数、captcha(CDP)连通性、失败计数与冷却、自动领取状态 | | 「我有几个账号 / 哪个号还有额度」 | `bonus_plan_accounts` | 账号列表(含额度需说「看剩余额度」) | | 「帮我加一个 zcode 账号」 | `bonus_plan_add_account` | 返回授权链接 → 你在浏览器完成 → 再说一声即自动入池 | | 「停用/启用/删掉/把某号排到第一个/重置额度」 | `bonus_plan_account_action` | 改的是插件自己的账号池,不影响 ZCode 登录 | | 「现在就领一次额度」 | `bonus_plan_claim` | 补激活上报 → 查可领 → 逐个领取(每个 plan 单独 captcha) | | 「怀疑 captcha 坏了」 | `bonus_plan_captcha_test` | 手动产一次 captcha(诊断用,别反复调) | | 「怎么接入 / provider 怎么填」 | `bonus_plan_panel_url` | 面板地址 + 自定义 provider 配置 | 也有斜杠命令 `/bonus-plan`(等价入口,可带参数): ``` /bonus-plan # 看状态 /bonus-plan add # 添加账号(给授权链接) /bonus-plan panel # 面板地址 + provider 配置(可点击链接) /bonus-plan 打开面板 # ★ 用系统默认浏览器**真的把面板打开** /bonus-plan disable 尾号1234 # 停用某个账号 /bonus-plan up 尾号1234 # 调高优先级 /bonus-plan claim # 立刻领取额度 ``` ### 三种打开面板的方式 | 方式 | 怎么做 | 效果 | |---|---|---| | **会话内(说)** | 直接说「**打开**插件面板 / 帮我打开配置面板」 | agent 调 `bonus_plan_panel_url` 并带 `open=true` → 插件用系统默认浏览器**真的打开** | | **会话内(命令)** | 输入 `/` 选 `bonus-plan`,或 `/bonus-plan 打开面板` | 同上(斜杠命令会展开成一段指示,让 agent 调对应工具) | | **shell** | `pnpm panel`(或 `node scripts/open-panel.mjs`) | 读发现文件 → 校验可达 → 打开浏览器;`--print` 只打印地址 | > 只想看地址(不想弹浏览器)时:会话里说「**给我面板地址**」即可 —— 此时 `open` 不传, > 插件只返回可点击的 Markdown 链接与 provider 配置。shell 侧用 `pnpm panel:print`。 `/bonus-plan` 属于**插件提供的自定义斜杠命令**(GUI 通过 `useSlashCommands` + `pluginSlashCommandRefresh` 加载)。命令是新加的字段,**若输入 `/` 看不到 `bonus-plan`, 重启一次 ZCode**(壳启动时才读取插件清单),或直接用上面的自然语言方式。 > 为什么不做成「设置页里的面板」:开源 ZCode 的插件体系只支持 > `mcpServers / commands / skills / hooks / agents` 五类组件,**没有自定义 UI 组件** > (`PluginManifest.settings` 字段在契约里声明了但全仓无消费点)。所以设置页里能 > **看到并启用**这个插件(含它的 MCP 组件与配置项),但打不开我们的网页界面 —— > 因此把能力做进工具与命令,让日常操作不需要离开会话。 ## 如何获得「开源版」宿主 **官方发行的安装包(含 scoop 装的)是闭源发行版,不能用**(见上)—— 它自带 captcha, 插件再刷就是双倍消耗。开源版有两条路:**下载预编译产物**(最省事)或**自己构建**。 ### 路线 A|下载预编译的开源版(无需构建) 用开源代码预编译好的产物发布在 ****, 两种形态任选(都是**分卷 zip**,两卷都要下载): | 产物(分卷) | 里面装的是 | 怎么放 | 探测怎么找到它 | |---|---|---|---| | `ZCode Preview-3.14.3-win-x64_TEST.zip.001`
`…zip.002` | **安装程序**(解出 `ZCode Preview-3.14.3-win-x64_TEST.exe`) | 双击安装,默认装到 `%LOCALAPPDATA%\Programs\ZCode Preview\` | 注册表卸载项 / 快捷方式 / 常见安装位置 | | `zcode-portable.zip.001`
`zcode-portable.zip.002` | **portable 解压版**(解出 `zcode-portable\` 目录,等同 `dist\win-unpacked\`) | 解压到**固定目录**(如 `D:\Apps\ZCode-oss`),再把**该目录**加进 PATH | **PATH** 来源 | 下载地址(把 `.00N` 换成对应分卷): ``` https://gitee.com/iJetLi/zcode/releases/download/3.14.3/<上面的文件名> ``` > ⚠ **分卷必须按顺序合并解压**:Windows 资源管理器**不支持**分卷 zip,请用 > **7-Zip**(或 WinRAR)右键 `.001` 解压,它会自动续接 `.002`: > > ```powershell > 7z x "ZCode Preview-3.14.3-win-x64_TEST.zip.001" # 得到安装程序 > 7z x "zcode-portable.zip.001" -o"D:\Apps\ZCode-oss" # 得到 portable 目录 > ``` > 💡 **也可以一条命令做完**:`scripts\install-portable-zcode.ps1` 会「合并分卷解压 → 放到固定目录 → 加 PATH → 校验能被探测到」, > 并自动认出解压后多出来的 `zcode-portable\` 这一层(PATH 加错层是最常见的失败原因): > > ```powershell > pwsh -File scripts\install-portable-zcode.ps1 -Zip "$env:USERPROFILE\Downloads\zcode-portable.zip.001" > ``` > > 只需给**第一卷** `.001`,7-Zip 会自动续接 `.002`;`-NoPath` 可只解压、不动 PATH。 > ⚠ **portable 必须进 PATH**:它不写注册表、不留快捷方式,解压在哪系统无从得知。 > 加的是**exe 所在目录**(不是它的父目录): > > ```powershell > $dir = 'D:\Apps\ZCode-oss\zcode-portable' # 目录里就是 ZCode Preview.exe + resources\ > $p = [Environment]::GetEnvironmentVariable('Path', 'User') > if (($p -split ';') -notcontains $dir) { > [Environment]::SetEnvironmentVariable('Path', "$p;$dir", 'User') > } > ``` > > 不想动 PATH 也可以直接用 `scripts\start-zcode.ps1 -ZCodeExe "<解压目录>\ZCode Preview.exe"`。 > > 探测除了当前进程的 PATH,**也会读用户级/机器级注册表里的 Path**,所以刚设完 > 不必重开终端就能被发现。 > > portable 目录长这样(实测 `win-unpacked`): > > ``` > ZCode Preview.exe ← 主程序(名字随 productName 变,可能带空格) > resources\app.asar ← 应用本体(守卫扫它判开源/闭源) > resources\glm\zcode.cjs ← 内置 agent bundle(缺它壳会静默不服务) > resources\config\ resources\tools\ locales\ *.dll *.pak > ``` > > 识别**不依赖产品名**:先看 `*ZCode*.exe`;若你把 productName 改成完全无关的名字, > 则靠 `resources\glm\zcode.cjs` 这个 ZCode 特有结构标记兜底认(实测两种都通过)。 装好/解压好后启动(**打包态不自带 9229,所以不能只双击**): ```powershell pwsh -File scripts\start-zcode.ps1 # 自动探测(安装包与 PATH 里的 portable 都能找到) pwsh -File scripts\start-zcode.ps1 -List # 看发现了几份、每份的开源/闭源判定 ``` ### 路线 B|自己构建(clone → 打补丁 → 打包 → 安装) ### 第 1 步|clone 源码 ```powershell git clone --depth 1 https://github.com/zai-org/ZCode.git D:\ZCode-official # 国内直连不稳时走镜像: # git clone --depth 1 https://gh-proxy.com/https://github.com/zai-org/ZCode.git D:\ZCode-official ``` ### 第 2 步|打补丁(**必需**,否则 Windows 上根本打不出包) 上游 `packages/desktop/scripts/bundle.mjs` 的目标平台是**写死的 mac/arm64**(CI 契约, 上游不会改),所以在 Windows/Linux 上直接打包必然打错平台失败。本仓库带修好的补丁: ```powershell pwsh -File <本仓库>\scripts\patch-zcode.ps1 -ZCodeRoot D:\ZCode-official # 应用(默认 git am) pwsh -File <本仓库>\scripts\patch-zcode.ps1 -ZCodeRoot D:\ZCode-official -Action status # 只看状态 pwsh -File <本仓库>\scripts\patch-zcode.ps1 -ZCodeRoot D:\ZCode-official -Action apply -NoCommit # 只改工作区 ``` 补丁是 `patches/zcode-package-desktop.patch`(纯新增两个文件,可干净应用),做两件事: | 内容 | 为什么必须 | |---|---| | 新增 `scripts/package-desktop.mjs` + 根 `package.json` 的 `package:desktop` 脚本 | 解析**本机** OS/架构后显式传给 `bundle.mjs`,完整链路(prepare → build → electron-builder → 产物校验)全部复用上游,不绕过 CI 契约 | | Windows 上把 `%SystemRoot%\System32\tar.exe`(bsdtar,支持 xz)前置到**子进程** PATH | 机器上若有 GNU tar(scoop 那类),prepare 解压 `node-*.tar.xz` 会报 `tar.exe: invalid option -- J` 而整包失败;只影响本次子进程,不动你的系统 PATH | 支持 `--os/--arch/--clean/--dry-run`,也认 `ZCODE_TARGET_OS` / `ZCODE_TARGET_ARCH`。 ### 第 3 步|装依赖并打安装包 ```powershell cd D:\ZCode-official pnpm install # 约 2.8GB,耗时较久 pnpm package:desktop # 产物:packages\desktop\dist\*.exe(本机平台自动适配) ``` > ⚠ 别用 `build:no-runtime-assets`:它跳过内置 agent bundle,壳随后以 > `unsupported_runtime` **静默失败**(数据库起不来 → 插件根本不会被加载)。 > `package:desktop` 走完整链路,不用操心;不放心可体检: > `pwsh -File <本仓库>\scripts\setup-open-source-zcode.ps1 -VerifyOnly -Target D:\ZCode-official` ### 第 4 步|安装,并用脚本启动(**不能双击**) 装完主程序通常在 `%LOCALAPPDATA%\Programs\\`(实测 `productName` 是 `ZCode Preview`,**名字可变**): ```powershell pwsh -File <本仓库>\scripts\start-zcode.ps1 -ZCodeExe "$env:LOCALAPPDATA\Programs\ZCode Preview\ZCode Preview.exe" ``` 不带 `-ZCodeExe` 通常也能选中(注册表卸载项 / 快捷方式 / 运行中进程 / 常见位置都会探测)。 | 要点 | 实测结论 | |---|---| | 会被误判成闭源吗 | **不会**。守卫扫它的 `app.asar` 搜不到 captcha 生产代码 ⇒ 判开源、接受 ✓(判据看**内容**,不看形态) | | 为什么不能双击 | 打包态 `app.isPackaged=true` ⇒ 上游那段 `!app.isPackaged` 不生效 ⇒ **不自带 9229**,captcha 载体连不上。脚本会自动补 `--remote-debugging-port=9229`(日志出现 `DevTools listening on ws://127.0.0.1:9229/…` 即为成功)。想双击就得给快捷方式的「目标」加这个参数 | | 主程序名可变 | 探测不写死 `ZCode.exe`,而是按目录解析「体积最大的 `*ZCode*.exe`」,排除 `Uninstall*` / `elevate` / `crashpad` 等 | | 已知无害警告 | `Windows bundled runtime missing providers: glm` / `glm binary path: ` —— 本插件链路全通(代理、captcha、端到端请求),但可能影响壳自带的部分能力 | ### 备选|只跑源码检出(开发形态) 不想打包也可以: ```powershell pwsh -File <本仓库>\scripts\setup-open-source-zcode.ps1 # clone + 装依赖 + 完整构建 pwsh -File <本仓库>\scripts\start-zcode.ps1 -ZCodeRoot D:\ZCode-official ``` 源码构建态默认就开 9229(双击也能工作),但它始终是个「检出」而非系统里的应用 —— **推荐还是走上面的安装包路线**。 ## 数据目录 优先级:`PLUGIN_DATA`(壳注入)> `BONUS_PLAN_DATA_DIR`(调试)> `~/.zcode/cli/plugins/data/zcode-bonus-plan`。 凭据用 **AES-256-GCM** 加密,主密钥由系统机制保护: Windows = DPAPI;macOS = 登录钥匙串(`security`);Linux = Secret Service(`secret-tool`); 三者皆不可用时降级为同目录的明文密钥文件(权限 600),面板会明示安全水位。 ## 额度与切号 - 免费额度按**自然日**结算(UTC+8)。用尽的账号会被标记到当日 24:00 后自动恢复。 - 触发切号的形态(全部实测):HTTP `1005` / `1113`、HTTP 200 但**零内容**返回。 - 触发重试但**不换号**:`3009`(并发限流,退避 1.5s/3s 重试)。 - **不重试**:`3012`(风控,有冷却惩罚)、`401/1002`(凭据失效,需重新登录)。 - 需要验证时,每轮重试都会**重新 mint** captcha(param 一次性);不需要验证时完全不 mint (先不带验证头探一次,被 `3007` 拒才产出,见上文)。 ## 已知边界 - captcha 需要 ZCode 桌面端**在运行**(插件只连接它,不代管其生命周期; 连不上会明确报错并提示启动,不静默失败)。 - 不做独立浏览器回退 —— 保持零额外进程;如确需回退,属二期。 - 打包版壳的调试端口:源码构建运行模式默认开启 9229;打包态视壳配置而定。 - captcha 产出失败会进入指数退避(保护设备信誉):连续失败达阈值后冷却, 面板可见计数与剩余冷却时间。 ## 开发 ```powershell pnpm test # 单元测试(193 个用例) pnpm typecheck # 类型检查 pnpm build # 构建到 lib/ ``` 调研/验证脚本与设计文档不入库:脚本在 `tmp/`,文档在 `docs/`(均已在 `.gitignore`)。 ### [deepseek-harness-codearts](https://gitee.com/iJetLi/deepseek-harness-codearts) 账号池、额度判断与切号策略的参考实现。特别受益于其提交 `2511113db284374503709a4b376affca981c0267`: - **captcha 帧复用的正确姿势**(`prepared` 守卫):复用**不能重置 DOM** —— DOM 一旦被 重建,SDK 的全局实例仍然绑在已销毁的元素上,于是复用变成"更快地失败"。空闲时也**不要 预测式换帧**(那是纯粹的浪费)。本项目 `src/captcha/cdp-minter.ts` 里的 `prepareFrame` / `frameStillUsable` / `idleReuseMs` 就是按这个思路实现的(实测复用后 ~0.4s vs 新建 ~1.8s)。 - **额度耗尽与切号的判定表**:`1005` / `1113` / 200-但零内容 → 标记该账号×模型并切号; `3009` 退避不换号;`3007` 换 captcha 重试;`3012` 不重试(计冷却);`401` / `1002` 不重试。 ### 本项目与它们不同的地方 - **形态**:做成 ZCode 的**插件**(MCP 工具 + 斜杠命令 + 网页面板),**不侵入任务系统** —— captcha 在插件的进程/离屏 iframe 里静默产出,不产生壳里的可见任务。 - **载体**:复用**宿主自己的** Electron 通过 CDP 产出 captcha,**不需要另起浏览器或壳**。 - **宿主守卫**(本项目特有):闭源发行版也会加载本插件,所以运行时自检宿主 —— 是闭源版 就**拒绝产 captcha**,避免与它自带的 captcha 能力**双倍消耗**同一账号。 - **多账号池 + 自动切号 + 每日自动领取**,以及端口/token 持久化(配一次长期有效)。 - **零运行时依赖**:只用 Node 内置模块。