<?xml version="1.0" encoding="utf-8" standalone="yes"?><rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom"><channel><title>Codex on Bruce's 博客</title><link>https://www.huangqixuan.com/tags/codex/</link><description>Recent content in Codex on Bruce's 博客</description><generator>Hugo -- gohugo.io</generator><language>zh-cn</language><lastBuildDate>Tue, 22 Sep 2026 00:30:00 +0800</lastBuildDate><atom:link href="https://www.huangqixuan.com/tags/codex/index.xml" rel="self" type="application/rss+xml"/><item><title>我把 Qoder 接进了 Codex：OpenCodex 接入、提速与图片串题排查</title><link>https://www.huangqixuan.com/p/qoder-cn-opencodex-windows/</link><pubDate>Tue, 22 Sep 2026 00:30:00 +0800</pubDate><guid>https://www.huangqixuan.com/p/qoder-cn-opencodex-windows/</guid><description>&lt;img src="https://www.huangqixuan.com/site-images/qoder-opencodex/cover_hu_9ed2904526ce44cb.webp" alt="Featured image of post 我把 Qoder 接进了 Codex：OpenCodex 接入、提速与图片串题排查" /&gt;&lt;p&gt;我最开始只想做一件事：继续用 Codex 的界面和工具，但模型可以切到我的 Qoder CN 账号，最好连模型列表和额度也一起交给 OpenCodex 管。&lt;/p&gt;&#10;&lt;p&gt;登录并不难。真正花时间的是后面：先是 502，接着模型把 &lt;code&gt;&amp;lt;tool_call&amp;gt;&lt;/code&gt; 当正文发出来，好不容易能对话了，每次又弹一个黑框。修完这些，同样一句“你好”，两条 DeepSeek 路线的响应速度又差了好几秒。&lt;/p&gt;&#10;&lt;p&gt;最后还有一个很容易漏掉的问题：我这一轮明明没发图，它却说“你发的两张图我也看了”。这篇把整个过程连起来，也写清楚哪些已经验证，哪些不能下结论。&lt;/p&gt;&#10;&lt;p&gt;本文记录的是 2026 年 9 月 20 日至 22 日这台 Windows 电脑上的适配。OpenCodex 的本地修改按当时安装的 2.60.0 核对。它包含自定义桥接代码和本地补丁，&lt;strong&gt;不是装完官方软件就自动具备的功能，也不是一键安装教程&lt;/strong&gt;。升级软件后需要重新验收。&lt;/p&gt;&#10;&lt;p&gt;封面根据实际界面截图生成，标了“界面参考合成图”；正文使用真实的模型菜单和额度截图。登录链接、令牌等认证信息没有公开。&lt;/p&gt;&#10;&lt;h2 id="codexopencodex-和-qoder-各自做什么"&gt;&lt;a href="#codexopencodex-%e5%92%8c-qoder-%e5%90%84%e8%87%aa%e5%81%9a%e4%bb%80%e4%b9%88" class="header-anchor"&gt;&lt;/a&gt;Codex、OpenCodex 和 Qoder 各自做什么&#10;&lt;/h2&gt;&lt;p&gt;Codex 是聊天和执行任务的入口。OpenCodex 是本机的提供商代理与管理界面。Qoder CN 则是另一套账号、CLI 和模型服务。&lt;/p&gt;&#10;&lt;p&gt;这套方案连接的是 Qoder CLI，通过 SDK 交换消息，不涉及嵌入 Qoder IDE。&lt;a class="link" href="https://docs.qoder.com/cli/sdk/how-it-works" target="_blank" rel="noopener"&#10; &gt;Qoder 的 SDK 架构文档&lt;/a&gt;也明确区分了本地 CLI 进程和远端模型服务。&lt;/p&gt;&#10;&lt;p&gt;请求路径如下：&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-text" data-lang="text"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;Codex 界面、任务历史、工具执行与审批&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; ↓ Responses 请求&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;OpenCodex · 127.0.0.1:10100&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; ├─ deepseek → DeepSeek API&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; ├─ xiaomi → 小米 MiMo API&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; └─ qoder-cn → 本地桥接器 · 127.0.0.1:3000&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; ↓ Qoder Agent SDK&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; Qoder CN CLI&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; ↓&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; Qoder 模型服务&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;这里需要区分两种“代理”：OpenCodex 和桥接器是本机协议转发；&lt;code&gt;HTTP_PROXY&lt;/code&gt; 指向的则是网络出站代理。让国内接口直连，取消的是后者，不是把 OpenCodex 从链路中移除。&lt;/p&gt;&#10;&lt;p&gt;&lt;a class="link" href="https://github.com/lidge-jun/opencodex" target="_blank" rel="noopener"&#10; &gt;OpenCodex 项目&lt;/a&gt;提供多提供商接入和管理面板。本文里的 Qoder 会话桥接、启动联动等是这次本机适配的部分，不能据此认为上游发行版已经包含全部修改。&lt;/p&gt;&#10;&lt;h2 id="登录成功只是第一步"&gt;&lt;a href="#%e7%99%bb%e5%bd%95%e6%88%90%e5%8a%9f%e5%8f%aa%e6%98%af%e7%ac%ac%e4%b8%80%e6%ad%a5" class="header-anchor"&gt;&lt;/a&gt;登录成功，只是第一步&#10;&lt;/h2&gt;&lt;p&gt;先在 PowerShell 登录 CLI：&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-powershell" data-lang="powershell"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="n"&gt;qodercn&lt;/span&gt; &lt;span class="n"&gt;login&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;浏览器授权后，终端报告登录成功。但这只说明 CLI 拿到了账号状态，并不能证明 Codex 到模型服务的整条链路都通了。&lt;/p&gt;&#10;&lt;p&gt;当时 Codex 报过这样的错误：&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-text" data-lang="text"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;502 Bad Gateway: Provider unreachable: Unable to connect&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;url: http://127.0.0.1:10100/v1/responses&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;遇到这个错误，先确认本地服务是否启动、端口是否监听。本文使用了下面两个地址，其他环境应按实际配置替换：&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-powershell" data-lang="powershell"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nb"&gt;Invoke-RestMethod&lt;/span&gt; &lt;span class="n"&gt;http&lt;/span&gt;&lt;span class="err"&gt;:&lt;/span&gt;&lt;span class="p"&gt;//&lt;/span&gt;&lt;span class="mf"&gt;127.0&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="py"&gt;0&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="mf"&gt;1&lt;/span&gt;&lt;span class="err"&gt;:&lt;/span&gt;&lt;span class="mf"&gt;10100&lt;/span&gt;&lt;span class="p"&gt;/&lt;/span&gt;&lt;span class="n"&gt;healthz&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nb"&gt;Invoke-RestMethod&lt;/span&gt; &lt;span class="n"&gt;http&lt;/span&gt;&lt;span class="err"&gt;:&lt;/span&gt;&lt;span class="p"&gt;//&lt;/span&gt;&lt;span class="mf"&gt;127.0&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="py"&gt;0&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="mf"&gt;1&lt;/span&gt;&lt;span class="err"&gt;:&lt;/span&gt;&lt;span class="mf"&gt;3000&lt;/span&gt;&lt;span class="p"&gt;/&lt;/span&gt;&lt;span class="n"&gt;health&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nb"&gt;Get-NetTCPConnection&lt;/span&gt; &lt;span class="n"&gt;-LocalPort&lt;/span&gt; &lt;span class="mf"&gt;10100&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mf"&gt;3000&lt;/span&gt; &lt;span class="n"&gt;-State&lt;/span&gt; &lt;span class="n"&gt;Listen&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;健康检查只能确认服务是否响应。接下来还要发一条真实消息、调用一个简单工具，并检查工具结果回来后能否继续回答。&lt;/p&gt;&#10;&lt;h2 id="能说话以后为什么工具还是用不了"&gt;&lt;a href="#%e8%83%bd%e8%af%b4%e8%af%9d%e4%bb%a5%e5%90%8e%e4%b8%ba%e4%bb%80%e4%b9%88%e5%b7%a5%e5%85%b7%e8%bf%98%e6%98%af%e7%94%a8%e4%b8%8d%e4%ba%86" class="header-anchor"&gt;&lt;/a&gt;能说话以后，为什么工具还是用不了&#10;&lt;/h2&gt;&lt;p&gt;早期最明显的症状，是模型直接输出了一段像这样的文字：&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-text" data-lang="text"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&amp;lt;tool_call&amp;gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; {&amp;#34;name&amp;#34;:&amp;#34;read_file&amp;#34;,&amp;#34;arguments&amp;#34;:{&amp;#34;path&amp;#34;:&amp;#34;&amp;lt;临时提示词文件&amp;gt;&amp;#34;}}&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&amp;lt;/tool_call&amp;gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;界面没有真的读取文件，回答就在这里结束了。另一种表现是它说“我先读取这张图片”，然后没有下文。&lt;/p&gt;&#10;&lt;p&gt;这段文字没有触发工具执行。Codex 需要结构化的工具事件，还需要调用 ID、参数和结果能正确对应。只把普通文本接通，离完整的编程代理还差一段。&lt;/p&gt;&#10;&lt;p&gt;修复后，桥接器使用 SDK 的结构化消息：普通文字按流式片段转发，工具请求转换成客户端能识别的调用，Codex 执行和审批后，再把真实结果送回原会话。桥接层不伪造成功结果，也不在另一边偷偷执行一遍同名工具。&lt;/p&gt;&#10;&lt;p&gt;修复后，界面开始连续显示“已读取聊天”“运行了命令”“已读取技能”和文件读取记录。一次网站检查可以连续做下去，不必每次等它停住后再补一句“继续”。&lt;/p&gt;&#10;&lt;p&gt;图片也是同一个道理。把图片变成一句“用户上传了截图”，不能代替图片像素。桥接器需要传递实际图像内容；遇到不支持图片的模型，应明确报错，而不是让它猜。&lt;/p&gt;&#10;&lt;h2 id="每次弹出的黑框来自-cli-子进程"&gt;&lt;a href="#%e6%af%8f%e6%ac%a1%e5%bc%b9%e5%87%ba%e7%9a%84%e9%bb%91%e6%a1%86%e6%9d%a5%e8%87%aa-cli-%e5%ad%90%e8%bf%9b%e7%a8%8b" class="header-anchor"&gt;&lt;/a&gt;每次弹出的黑框，来自 CLI 子进程&#10;&lt;/h2&gt;&lt;p&gt;对话接通后，每发一条消息都会冒出一个黑色控制台。窗口标题指向 Qoder CN 的 CLI 可执行文件。&lt;/p&gt;&#10;&lt;p&gt;处理位置在启动子进程的代码里。下面是关键选项示意，不能单独替代整个桥接器：&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-js" data-lang="js"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nx"&gt;spawn&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;command&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;args&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nx"&gt;cwd&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nx"&gt;env&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nx"&gt;windowsHide&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nx"&gt;shell&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nx"&gt;stdio&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;pipe&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;pipe&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;pipe&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;});&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;这个改动只隐藏控制台窗口，输入输出管道、取消信号和进程清理都保留。SDK 请求、额度查询和其他 CLI 启动路径也要检查，否则很容易修好对话，却在刷新额度时又弹一次。&lt;/p&gt;&#10;&lt;h2 id="两条-deepseek-路线首字差了多久"&gt;&lt;a href="#%e4%b8%a4%e6%9d%a1-deepseek-%e8%b7%af%e7%ba%bf%e9%a6%96%e5%ad%97%e5%b7%ae%e4%ba%86%e5%a4%9a%e4%b9%85" class="header-anchor"&gt;&lt;/a&gt;两条 DeepSeek 路线，首字差了多久&#10;&lt;/h2&gt;&lt;p&gt;两条路线都输入“你好”，响应时间却不同。模型菜单里的名字相近，也不能据此认定请求完全一样。&lt;/p&gt;&#10;&lt;p&gt;这次对照让两条路线同时发出同样的短问候，使用相同的低推理设置和各自独立的任务 ID。每一对请求的发出时间相差约 1 毫秒，两边都返回了“你好！”。计时从请求发出开始，直到收到第一段非空答案文字。&lt;/p&gt;&#10;&lt;table&gt;&#10;&#9;&lt;thead&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;th&gt;请求&lt;/th&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;th style="text-align: right"&gt;DeepSeek API 路线首字&lt;/th&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;th style="text-align: right"&gt;Qoder DeepSeek 路线首字&lt;/th&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&lt;/thead&gt;&#10;&#9;&lt;tbody&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;首次使用&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td style="text-align: right"&gt;0.600 秒&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td style="text-align: right"&gt;6.714 秒&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;续聊一&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td style="text-align: right"&gt;1.016 秒&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td style="text-align: right"&gt;1.958 秒&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;续聊二&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td style="text-align: right"&gt;0.912 秒&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td style="text-align: right"&gt;2.240 秒&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&lt;/tbody&gt;&#10;&lt;/table&gt;&#10;&lt;p&gt;这只是三组本机样本，不是性能排名。直连路线当时配置的是 V4 Flash，Qoder 目录给出的标识是 &lt;code&gt;DeepSeek-Flash&lt;/code&gt;，目前无法确认它们是否使用完全相同的底层模型版本。提供商内部提示、排队和推理过程也可能不同。&lt;/p&gt;&#10;&lt;p&gt;进一步查看桥接内部的计时，三轮中，本地 HTTP 转发层相对 SDK 首段文字只多出约 24、20、18 毫秒。因此，当时剩下的几秒等待，不能再解释成“本地攒完答案才显示”。&lt;/p&gt;&#10;&lt;p&gt;计时按 &lt;a class="link" href="https://developers.openai.com/api/docs/guides/streaming-responses" target="_blank" rel="noopener"&#10; &gt;OpenAI 流式响应文档&lt;/a&gt;区分答案增量和其他事件：连接建立、心跳、思考状态都不算首字。也没有通过提前显示一句假话，让数字看起来更快。&lt;/p&gt;&#10;&lt;h2 id="续用会话减少重复初始化"&gt;&lt;a href="#%e7%bb%ad%e7%94%a8%e4%bc%9a%e8%af%9d%e5%87%8f%e5%b0%91%e9%87%8d%e5%a4%8d%e5%88%9d%e5%a7%8b%e5%8c%96" class="header-anchor"&gt;&lt;/a&gt;续用会话，减少重复初始化&#10;&lt;/h2&gt;&lt;p&gt;早期每轮新开 CLI 进程，都要重新初始化，还可能重发整段历史。界面虽然留在同一个聊天框，后端却又从头开始处理。&lt;/p&gt;&#10;&lt;p&gt;现在桥接器会把 Codex 任务与 Qoder 会话对应起来。匹配时续用现有会话，只补发新增消息；需要恢复时，使用对应的会话 ID，而不是随意接到“最近一次聊天”。&lt;/p&gt;&#10;&lt;p&gt;不同任务的会话保持隔离。账号、模型、工作目录、系统指令、工具定义和推理参数发生变化，都可能要求隔离或重建。省掉启动时间，不能以串任务、串账号为代价。&lt;/p&gt;&#10;&lt;p&gt;切换模型时保留 Codex 的可见历史，但不同模型的缓存不能视为通用。实测从 Kimi 切到 Qoder DeepSeek，需要给新会话初始历史；切回仍可复用的 Kimi 时，则补入中间新增的消息。历史被编辑或配置不匹配时，要安全重建。&lt;/p&gt;&#10;&lt;p&gt;这减少了重复传输，却不能直接换算成“省了多少计费 Token”。当时部分 SDK 用量字段返回零，无法据此计算可靠的计费节省比例。旧历史留在模型上下文里，也不意味着后续推理免费。&lt;/p&gt;&#10;&lt;h2 id="预启动空会话随-opencodex-一起退出"&gt;&lt;a href="#%e9%a2%84%e5%90%af%e5%8a%a8%e7%a9%ba%e4%bc%9a%e8%af%9d%e9%9a%8f-opencodex-%e4%b8%80%e8%b5%b7%e9%80%80%e5%87%ba" class="header-anchor"&gt;&lt;/a&gt;预启动空会话，随 OpenCodex 一起退出&#10;&lt;/h2&gt;&lt;p&gt;最终采用的办法是提前初始化一个空会话，等真正提问时再使用。它不发送“你好”之类的占位请求，也不为了测试连通性偷偷跑一次推理。&lt;/p&gt;&#10;&lt;p&gt;预启动只准备一个配置匹配的空会话，不会把所有模型一起打开。第一次安装使用的默认配置，未必匹配下一次任务；模型、工具或系统指令不一致时，仍需正常初始化。&lt;/p&gt;&#10;&lt;p&gt;启动和退出按以下规则处理：&lt;/p&gt;&#10;&lt;ul&gt;&#10;&lt;li&gt;启动 OpenCodex 服务，才启动和准备 Qoder 桥接。&lt;/li&gt;&#10;&lt;li&gt;普通 Codex 的启动方式不变，不因此额外启动 Qoder。&lt;/li&gt;&#10;&lt;li&gt;退出 OpenCodex 服务，关闭桥接器及它自己启动的 CLI 子进程。&lt;/li&gt;&#10;&lt;li&gt;只关闭管理网页，不等于停止后台 OpenCodex 服务。&lt;/li&gt;&#10;&lt;/ul&gt;&#10;&lt;p&gt;测试退出时还发现了一个 Windows 时序问题：SDK 的 &lt;code&gt;close()&lt;/code&gt; 返回，子进程未必已经完全退出。因此，清理流程增加了等待子进程退出的步骤。隔离测试用的是模拟服务进程，没有为了验收把正在用的 Codex 桌面强行关掉。&lt;/p&gt;&#10;&lt;p&gt;一次预启动命中的短问候，首字约 3 秒；模拟拥有者退出后，桥接器和 CLI 约 1.3 秒内结束。另一轮后续测试分别是 2.619 秒和 0.562 秒。这些是不同轮次的小样本，不能拿来承诺每次都一样。&lt;/p&gt;&#10;&lt;p&gt;空会话仍占内存，所以热会话数量有上限，空闲后也会回收。保留时间从 60 秒改到 5 分钟，减少读完回答再打字时触发冷启动的次数；代价是内存占用持续得更久。&lt;/p&gt;&#10;&lt;h2 id="配置国内直连继续排查其他等待"&gt;&lt;a href="#%e9%85%8d%e7%bd%ae%e5%9b%bd%e5%86%85%e7%9b%b4%e8%bf%9e%e7%bb%a7%e7%bb%ad%e6%8e%92%e6%9f%a5%e5%85%b6%e4%bb%96%e7%ad%89%e5%be%85" class="header-anchor"&gt;&lt;/a&gt;配置国内直连，继续排查其他等待&#10;&lt;/h2&gt;&lt;p&gt;排查时确实发现 OpenCodex 配了 &lt;code&gt;127.0.0.1:7897&lt;/code&gt;，却没有国内接口绕过列表。环境里也有 &lt;code&gt;HTTP_PROXY&lt;/code&gt;、&lt;code&gt;HTTPS_PROXY&lt;/code&gt; 和 &lt;code&gt;ALL_PROXY&lt;/code&gt;。&lt;/p&gt;&#10;&lt;p&gt;已配置的 DeepSeek、小米 MiMo 和本地接口加入了 &lt;code&gt;noProxy&lt;/code&gt;。下面是局部配置示意，应合并进原配置，别拿它覆盖账号和提供商内容：&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-json" data-lang="json"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;{&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nt"&gt;&amp;#34;noProxy&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="s2"&gt;&amp;#34;localhost&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;127.0.0.1&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;::1&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="s2"&gt;&amp;#34;api.deepseek.com&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;api.xiaomimimo.com&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="s2"&gt;&amp;#34;qoder.cn&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;.qoder.cn&amp;#34;&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;]&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;}&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Qoder CN 子进程则清除了继承的出站代理变量，并单独设置绕过环境；没有改整台电脑的代理，也没有改变国外接口的路由。用 OpenCodex 自己的路由解析器检查，国内配置地址返回 &lt;code&gt;direct&lt;/code&gt;，ChatGPT 地址仍返回 &lt;code&gt;proxy&lt;/code&gt;。&lt;/p&gt;&#10;&lt;p&gt;排查时曾把继承代理变量当成请求走代理的证据，这个判断不够严谨。&lt;a class="link" href="https://docs.qoder.cn/cli/sdk/references-typescript" target="_blank" rel="noopener"&#10; &gt;Qoder CN TypeScript SDK 文档&lt;/a&gt;写明：没有显式配置 &lt;code&gt;proxy&lt;/code&gt; 时，SDK 集成的 CLI 自身默认直连；继承的代理变量仍可能影响工具和子进程。不同版本还要以实际运行行为为准。&lt;/p&gt;&#10;&lt;p&gt;这次确认的是应用层路由策略已修正，真实请求也能成功；后续提速不能全归因于去掉代理。系统级 TUN/VPN 是否转发到代理节点，也不由这段 &lt;code&gt;noProxy&lt;/code&gt; 配置保证。&lt;/p&gt;&#10;&lt;p&gt;慢请求的日志里还出现过多轮工具调用，以及一次约 1.42 MB 的历史重传。任务总耗时、单轮首字时间、模型思考和工具运行，必须分开看。后面网站检查显示的 4 分 47 秒包含连续操作，不能拿它当一次纯聊天的首字延迟。&lt;/p&gt;&#10;&lt;h2 id="本轮没发图回答却提起旧截图"&gt;&lt;a href="#%e6%9c%ac%e8%bd%ae%e6%b2%a1%e5%8f%91%e5%9b%be%e5%9b%9e%e7%ad%94%e5%8d%b4%e6%8f%90%e8%b5%b7%e6%97%a7%e6%88%aa%e5%9b%be" class="header-anchor"&gt;&lt;/a&gt;本轮没发图，回答却提起旧截图&#10;&lt;/h2&gt;&lt;p&gt;还有一次，最后一条消息只问了功能和 UI 建议，没有附图，回答却又讨论起以前的截图。&lt;/p&gt;&#10;&lt;p&gt;检查记录显示，那一轮调用的是读取网站样式和模板的命令，没有调用读图工具。它说“我看了两张图”，不能作为本轮确实发生读图的证据。&lt;/p&gt;&#10;&lt;p&gt;桥接代码也存在歧义：重建会话时，会把历史消息中的图片收集起来，附在同一次 SDK 输入后面。正文虽然保留了引用，但模型看到的是同一批附件，容易把旧图误认为本轮刚上传的图。&lt;/p&gt;&#10;&lt;p&gt;直接丢掉历史图片会影响后续追问，例如“刚才那张图呢”。这次保留了图片，改为逐张标注来源：&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-text" data-lang="text"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;[Image m1:p2; source_role=user; scope=HISTORICAL_IMAGE]&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;[Image m5:p2; source_role=user; scope=CURRENT_USER_ATTACHMENT]&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;[Image m6:p1; source_role=tool; scope=TOOL_OUTPUT_IMAGE]&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;这里的编号对应原始消息和内容块。每张实际图片旁边都有同一份标签，历史正文也使用它。本轮没有附件时，输入会明确说明“本轮没有新图片”；历史图片仍然保留，但只有与当前问题相关时才应该分析。工具返回的图片也不能冒充用户新上传的附件。&lt;/p&gt;&#10;&lt;p&gt;同一个有效会话续聊时，沿用已有的增量输入机制，不重复发送旧像素；切换模型或重建会话时保留图片及其来源。完全没有图片历史的纯文字对话，不添加这段额外图片说明。&lt;/p&gt;&#10;&lt;p&gt;Kimi 的四轮实测结果如下：&lt;/p&gt;&#10;&lt;table&gt;&#10;&#9;&lt;thead&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;th&gt;操作&lt;/th&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;th&gt;实际回答&lt;/th&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&lt;/thead&gt;&#10;&#9;&lt;tbody&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;发一张模型菜单图，要求只回复收到&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;收到&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;同会话问本条是否附带新图片&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;没有&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;强制新建会话并带回历史，再问本条是否附带新图片&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;没有&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;追问最早那张图里的一个 Kimi 模型标识&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;code&gt;qoder-cn/kimi-k3&lt;/code&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&lt;/tbody&gt;&#10;&lt;/table&gt;&#10;&lt;p&gt;这次修改后，自动测试共 189 项通过，包含新旧图混合、工具图像、增量续聊和重建标记。四轮真实请求也通过，但它只是一次功能验收，不代表从此不会再跑题。&lt;/p&gt;&#10;&lt;p&gt;这样既能区分图片来源，也保留了追问旧图的能力，正常续聊无需重复传图。代价是桥接代码更复杂，有图片历史时多了一小段说明；重建仍可能需要传回旧图。尚未做足够的对照测试，暂时无法量化 Token 和耗时的变化。&lt;/p&gt;&#10;&lt;h2 id="模型列表和额度终于放到一起了"&gt;&lt;a href="#%e6%a8%a1%e5%9e%8b%e5%88%97%e8%a1%a8%e5%92%8c%e9%a2%9d%e5%ba%a6%e7%bb%88%e4%ba%8e%e6%94%be%e5%88%b0%e4%b8%80%e8%b5%b7%e4%ba%86" class="header-anchor"&gt;&lt;/a&gt;模型列表和额度终于放到一起了&#10;&lt;/h2&gt;&lt;p&gt;&lt;img alt="Codex 中实际显示的 Qoder CN 模型菜单" class="gallery-image" data-flex-basis="185px" data-flex-grow="77" height="639" loading="lazy" sizes="(max-width: 767px) calc(100vw - 30px), (max-width: 1023px) 700px, (max-width: 1279px) 950px, 1232px" src="https://www.huangqixuan.com/site-images/qoder-opencodex/model-menu_hu_6970619e71d680e3.webp" width="493"&gt;&lt;/p&gt;&#10;&lt;p&gt;&lt;em&gt;实际运行的模型菜单。目录能显示，不等于每个模型的文字、图片、工具调用都已逐项验收。&lt;/em&gt;&lt;/p&gt;&#10;&lt;p&gt;接入完成后，Codex 的模型菜单可以选择 Qoder CN 路线，OpenCodex 可以查看 Qoder 的套餐、组织资源包和其他提供商的用量。额度读取用到了 SDK 的 &lt;code&gt;getUsageInfo()&lt;/code&gt;，不是用本地对话 Token 估算账户余额。&lt;/p&gt;&#10;&lt;p&gt;&lt;img alt="OpenCodex 的 Qoder CN 提供方页面，显示连接状态、套餐额度和组织资源包" class="gallery-image" data-flex-basis="497px" data-flex-grow="207" height="927" loading="lazy" sizes="(max-width: 767px) calc(100vw - 30px), (max-width: 1023px) 700px, (max-width: 1279px) 950px, 1232px" src="https://www.huangqixuan.com/site-images/qoder-opencodex/quota_hu_23db81b4e3092c9d.webp" srcset="https://www.huangqixuan.com/site-images/qoder-opencodex/quota_hu_a74535b6d226f4ee.webp 800w, https://www.huangqixuan.com/site-images/qoder-opencodex/quota_hu_b77b459261dfe55b.webp 1600w, https://www.huangqixuan.com/site-images/qoder-opencodex/quota_hu_23db81b4e3092c9d.webp 1920w" width="1920"&gt;&lt;/p&gt;&#10;&lt;p&gt;&lt;em&gt;截图时的额度快照。右侧同时显示读取来源 &lt;code&gt;qoder-sdk · getUsageInfo&lt;/code&gt; 和配额更新时间，数值不代表当前余额。&lt;/em&gt;&lt;/p&gt;&#10;&lt;p&gt;查看额度时要留意“上次检查”的时间。界面显示两小时前检查，就代表缓存结果，不能把它当成实时账单。接口返回未知或不支持，也不应该画成“还剩零额度”。&lt;/p&gt;&#10;&lt;p&gt;当时不是每个模型都通过了验收：Kimi 的工具往返和续聊有真实测试；Qwen3.8 Flash 出现过超时，不能因为出现在菜单里就写成“全模型完美兼容”。图片能力也需要单独测试。&lt;/p&gt;&#10;&lt;h2 id="接入后的检查清单"&gt;&lt;a href="#%e6%8e%a5%e5%85%a5%e5%90%8e%e7%9a%84%e6%a3%80%e6%9f%a5%e6%b8%85%e5%8d%95" class="header-anchor"&gt;&lt;/a&gt;接入后的检查清单&#10;&lt;/h2&gt;&lt;p&gt;一句“你好”只能验证最基本的对话。完整接入还需要检查这些情况：&lt;/p&gt;&#10;&lt;ol&gt;&#10;&lt;li&gt;CLI 登录和模型请求分别测试，先确认账号与服务。&lt;/li&gt;&#10;&lt;li&gt;检查 OpenCodex 和桥接器的监听端口，再测整条路线。&lt;/li&gt;&#10;&lt;li&gt;先验证文字增量，再验证真实工具调用与结果续接。&lt;/li&gt;&#10;&lt;li&gt;单独测试图片，以及“这一轮没图、上一轮有图”。&lt;/li&gt;&#10;&lt;li&gt;测同任务续聊、切模型、切回、历史编辑和会话恢复。&lt;/li&gt;&#10;&lt;li&gt;分开记录冷启动、热会话首字、工具耗时和任务总时间。&lt;/li&gt;&#10;&lt;li&gt;检查应用层代理规则，不用“国内模型”四个字推断实际网络路径。&lt;/li&gt;&#10;&lt;li&gt;退出 OpenCodex 后检查子进程，升级后重新检查本地补丁。&lt;/li&gt;&#10;&lt;/ol&gt;&#10;&lt;p&gt;桥接器应只监听回环地址，不向外部网络开放；本机接口按需要配置认证。账号文件、令牌、完整请求历史和本地预启动配置都不应该跟着教程上传。使用远端模型时，任务所需的提示、文件片段和工具结果仍可能发往提供商，“本地桥接”不等于数据全在本机。&lt;/p&gt;&#10;&lt;p&gt;目前，这套接入已经能在 Codex 中使用 Qoder CN 模型，完成带工具和图片的连续任务。大历史重建的成本、不同模型的长任务稳定性，仍需要在实际使用中继续观察。&lt;/p&gt;&#10;</description></item><item><title>让 Codex 用灯光叫我回来（二）：从多会话分区到 Micro 原生状态</title><link>https://www.huangqixuan.com/p/codexlighthub-native-micro-part-2/</link><pubDate>Mon, 21 Sep 2026 00:00:00 +0800</pubDate><guid>https://www.huangqixuan.com/p/codexlighthub-native-micro-part-2/</guid><description>&lt;img src="https://www.huangqixuan.com/site-images/codexlighthub-native/cover_hu_eb280410d7c9c795.webp" alt="Featured image of post 让 Codex 用灯光叫我回来（二）：从多会话分区到 Micro 原生状态" /&gt;&lt;p&gt;在&lt;a class="link" href="https://www.huangqixuan.com/p/codexlighthub-windows-rgb/" &gt;上篇&lt;/a&gt;里，我已经让 ROG 键盘和 Yeelight 挂灯跟着 Codex 的状态变色：工作时蓝色，需要我回答时橙色，完成后绿色，过一会儿再回到平时的彩色灯效。&lt;/p&gt;&#10;&lt;p&gt;这个想法来自 Codex Micro 的指示灯。我希望不用一直盯着聊天窗口，也能知道任务有没有结束、是不是在等我。&lt;/p&gt;&#10;&lt;p&gt;但真正用起来以后，我又想加一点东西：如果同时开着两个、三个对话，能不能让键盘分别显示它们的状态？如果 Codex 本身就能给 Micro 发送状态，能不能不再依赖 hooks？&lt;/p&gt;&#10;&lt;p&gt;于是，我和 Codex 又折腾了几轮。最直观的变化是桌面版真的出现了 Micro 的欢迎向导；最费时间的部分，却发生在它已经显示“已连接”之后。&lt;/p&gt;&#10;&lt;p&gt;&lt;em&gt;封面是 AI 生成的概念插画，用来表达状态与灯光的连接关系，不是实机照片，也不作为灯效测试证据。下文的软件截图来自我的实际测试。&lt;/em&gt;&lt;/p&gt;&#10;&lt;h2 id="一块键盘能不能看几个对话"&gt;&lt;a href="#%e4%b8%80%e5%9d%97%e9%94%ae%e7%9b%98%e8%83%bd%e4%b8%8d%e8%83%bd%e7%9c%8b%e5%87%a0%e4%b8%aa%e5%af%b9%e8%af%9d" class="header-anchor"&gt;&lt;/a&gt;一块键盘，能不能看几个对话？&#10;&lt;/h2&gt;&lt;p&gt;原来的整块变色很直接，不过只能给出一个汇总结果。我说的多个对话，包括主窗口里的任务，也包括 Codex 右侧打开的另一个对话。&lt;/p&gt;&#10;&lt;p&gt;最开始的想法很朴素：两个就左右分，三个就左中右，再多一些也可以继续分，但要有上限。每个区域显示一个任务的状态。&lt;/p&gt;&#10;&lt;p&gt;第一次测试时，颜色确实出来了，边界却不太对。后来按这台 G615LR 的实际键盘布局重新校准，去掉不适用的数字小键盘布局假设，三色分区才变得正常。空格这样的大键也需要单独考虑：一个物理按键只能显示一种颜色，不能因为它跨过两个区域，就把它当成两颗灯处理。&lt;/p&gt;&#10;&lt;p&gt;紧接着又遇到了一个问题：两个相邻任务都在工作，两个区域都是蓝色，看起来又连成了一片。&lt;/p&gt;&#10;&lt;p&gt;我们试过白色分隔键，也试过熄灯隔离带。我反馈过“三色正常，但同色区分隔不清”。后来我举了个例子：一个蓝区向左流动，另一个向上流动，会不会更容易区分？&lt;/p&gt;&#10;&lt;p&gt;这把问题从分区带到了动画。区域越多，每块越窄，灯光本身也越难读。能把颜色写进去，离“我扫一眼就能看懂”还有距离。&lt;/p&gt;&#10;&lt;h2 id="我想用官方动画结果发现要分开看"&gt;&lt;a href="#%e6%88%91%e6%83%b3%e7%94%a8%e5%ae%98%e6%96%b9%e5%8a%a8%e7%94%bb%e7%bb%93%e6%9e%9c%e5%8f%91%e7%8e%b0%e8%a6%81%e5%88%86%e5%bc%80%e7%9c%8b" class="header-anchor"&gt;&lt;/a&gt;我想用官方动画，结果发现要分开看&#10;&lt;/h2&gt;&lt;p&gt;流动效果做出来之后，我的感觉是卡。既然 G-Helper 的灯效看着很顺，能不能直接用它的方式？&lt;/p&gt;&#10;&lt;p&gt;这里需要把两种控制方式分开。&lt;/p&gt;&#10;&lt;p&gt;整块键盘的常亮、呼吸，可以给键盘发送模式命令，让设备自己运行效果。任意分区里的独立波浪，则需要更细的逐键控制。目前这条实现路径还没有验证出“每个任意分区都能独立调用固件波浪”的能力，所以不能把整板原生动画当成多区动画的现成替代。&lt;/p&gt;&#10;&lt;p&gt;软件逐帧发送也做过优化。一次短测里，旧逻辑的实际提交频率约为 6.20 次/秒，调整调度后约为 29.71 次/秒。不过这测到的是程序提交灯光数据的节奏，不是相机测出的 LED 刷新率，更不能代替我的肉眼反馈。&lt;/p&gt;&#10;&lt;p&gt;我后来更在意的是颜色是否清楚。任务提示不一定要一直动，尤其不能为了波浪把蓝色压得很暗。动画保留为探索方向，日常显示先回到容易辨认的常亮。&lt;/p&gt;&#10;&lt;h2 id="让桌面版真正认出-micro"&gt;&lt;a href="#%e8%ae%a9%e6%a1%8c%e9%9d%a2%e7%89%88%e7%9c%9f%e6%ad%a3%e8%ae%a4%e5%87%ba-micro" class="header-anchor"&gt;&lt;/a&gt;让桌面版真正认出 Micro&#10;&lt;/h2&gt;&lt;p&gt;接下来，我提出了另一个要求：“我不想用钩子做这个。”&lt;/p&gt;&#10;&lt;p&gt;上篇的路线是读取 hooks 事件，再由 Hub 判断状态。这次尝试的是在 Windows 上提供一个兼容 Micro 通信的虚拟 HID 设备，让 Codex 桌面版本身发送灯光状态，再把它转给实际的 ROG 键盘和 Yeelight。&lt;/p&gt;&#10;&lt;p&gt;大致路径是：&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-text" data-lang="text"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;Codex 桌面版&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; ↓ Micro 灯光状态&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;虚拟 HID 设备与本地桥接程序&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; ├→ ASUS HID → ROG 键盘&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; └→ 本地 MIoT → Yeelight 氛围灯&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;起初 Windows 已经能看到设备，本地程序也能枚举到，Codex 却没有真正开始通信。继续检查后，发现还涉及桌面版筛选设备时使用的设备路径。调整虚拟设备的标识路径之后，欢迎向导终于弹了出来。&lt;/p&gt;&#10;&lt;p&gt;&lt;img alt="Codex Micro 欢迎向导" class="gallery-image" data-flex-basis="286px" data-flex-grow="119" height="671" loading="lazy" sizes="(max-width: 767px) calc(100vw - 30px), (max-width: 1023px) 700px, (max-width: 1279px) 950px, 1232px" src="https://www.huangqixuan.com/site-images/codexlighthub-native/welcome_hu_7c1b31f5be870dfb.webp" srcset="https://www.huangqixuan.com/site-images/codexlighthub-native/welcome_hu_824c3eb2f9c6ad86.webp 800w, https://www.huangqixuan.com/site-images/codexlighthub-native/welcome_hu_7c1b31f5be870dfb.webp 801w" width="801"&gt;&lt;/p&gt;&#10;&lt;p&gt;&lt;em&gt;桌面版出现了 Micro 的欢迎向导。这里连接的是本项目的虚拟兼容设备，不代表我购买或接入了一台实体 Micro。&lt;/em&gt;&lt;/p&gt;&#10;&lt;p&gt;这个时刻很有意思：最初只是受到它的指示灯启发，现在终于走到了桌面版原本为它准备的状态通道。&lt;/p&gt;&#10;&lt;p&gt;不过，“原生”这个词也容易把几件事混在一起。在这里，我说的是状态由 Codex 的 Micro 通道发出；接收和转译仍然靠本地桥接，键盘仍然是 ASUS 的设备。它不意味着 ROG 键盘变成了 Micro，也不意味着分区动画就由 ASUS 固件自动完成。&lt;/p&gt;&#10;&lt;p&gt;这条路线涉及虚拟驱动和本地证书信任，也不是拷贝一个脚本就结束的普通配置。我把它当作自己这台机器上的兼容性实验，而不是已经适合所有人安装的通用方案。&lt;/p&gt;&#10;&lt;h2 id="欢迎向导能打开不代表所有功能都实现了"&gt;&lt;a href="#%e6%ac%a2%e8%bf%8e%e5%90%91%e5%af%bc%e8%83%bd%e6%89%93%e5%bc%80%e4%b8%8d%e4%bb%a3%e8%a1%a8%e6%89%80%e6%9c%89%e5%8a%9f%e8%83%bd%e9%83%bd%e5%ae%9e%e7%8e%b0%e4%ba%86" class="header-anchor"&gt;&lt;/a&gt;欢迎向导能打开，不代表所有功能都实现了&#10;&lt;/h2&gt;&lt;p&gt;向导里的智能体按键很贴合我最初想要的体验：六个位置，各自显示状态。截图里的图例包括白色空闲、蓝色思考中、绿色已完成、琥珀色需要输入、红色错误，以及关闭表示未分配。&lt;/p&gt;&#10;&lt;p&gt;&lt;img alt="智能体按键向导：六个位置与状态颜色" class="gallery-image" data-flex-basis="229px" data-flex-grow="95" height="809" loading="lazy" sizes="(max-width: 767px) calc(100vw - 30px), (max-width: 1023px) 700px, (max-width: 1279px) 950px, 1232px" src="https://www.huangqixuan.com/site-images/codexlighthub-native/agent-keys_hu_244d9aeb715078e1.webp" width="772"&gt;&lt;/p&gt;&#10;&lt;p&gt;&lt;img alt="命令键向导：桌面版界面，不代表本项目已实现控制功能" class="gallery-image" data-flex-basis="203px" data-flex-grow="84" height="671" loading="lazy" sizes="(max-width: 767px) calc(100vw - 30px), (max-width: 1023px) 700px, (max-width: 1279px) 950px, 1232px" src="https://www.huangqixuan.com/site-images/codexlighthub-native/command-keys_hu_6f74d139eb3c0820.webp" width="569"&gt;&lt;/p&gt;&#10;&lt;p&gt;我目前接的是灯光状态。截图里介绍的命令键、旋钮、麦克风，以及点击按键切换任务，都不能因为欢迎向导出现了，就算成本项目的功能。桥接程序也不会替我点击批准按钮。&lt;/p&gt;&#10;&lt;p&gt;设置页同样需要这样看：它显示已连接，能看到亮度和自动调暗设置，是通信接入的证据。但虚拟设备报告的“电池 100%”只是兼容信息，不能当作笔记本电池读数。&lt;/p&gt;&#10;&lt;p&gt;&lt;img alt="Codex Micro 设置页" class="gallery-image" data-flex-basis="403px" data-flex-grow="168" height="1142" loading="lazy" sizes="(max-width: 767px) calc(100vw - 30px), (max-width: 1023px) 700px, (max-width: 1279px) 950px, 1232px" src="https://www.huangqixuan.com/site-images/codexlighthub-native/settings_hu_cd6690d4b9d471b.webp" srcset="https://www.huangqixuan.com/site-images/codexlighthub-native/settings_hu_53561592dc4ea876.webp 800w, https://www.huangqixuan.com/site-images/codexlighthub-native/settings_hu_807abd437203f76e.webp 1600w, https://www.huangqixuan.com/site-images/codexlighthub-native/settings_hu_cd6690d4b9d471b.webp 1920w" width="1920"&gt;&lt;/p&gt;&#10;&lt;p&gt;&lt;em&gt;测试时的设置页：亮度为 100%，自动调暗关闭。设置值正常，仍然不保证实际键盘颜色足够明显。&lt;/em&gt;&lt;/p&gt;&#10;&lt;p&gt;还有一个限制：这条实现接收的是六个原生槽位的灯光状态，不是读取所有聊天内容、任务标题或者百分比进度。它不能无上限地把所有打开的对话铺到键盘上，也不能承诺槽位始终对应屏幕上从左到右的窗口位置。&lt;/p&gt;&#10;&lt;h2 id="接通之后我看到的却是一整块淡蓝白色"&gt;&lt;a href="#%e6%8e%a5%e9%80%9a%e4%b9%8b%e5%90%8e%e6%88%91%e7%9c%8b%e5%88%b0%e7%9a%84%e5%8d%b4%e6%98%af%e4%b8%80%e6%95%b4%e5%9d%97%e6%b7%a1%e8%93%9d%e7%99%bd%e8%89%b2" class="header-anchor"&gt;&lt;/a&gt;接通之后，我看到的却是一整块淡蓝白色&#10;&lt;/h2&gt;&lt;p&gt;接入成功之后，实际效果仍让我不满意。我先反馈“整块蓝”，后来又觉得颜色很淡，基本看不清，甚至像白色。&lt;/p&gt;&#10;&lt;p&gt;这次没有继续只看日志里的“发送成功”。我们做了一轮独立的硬件测试：先整块红色，再左蓝右橙，最后左红中绿右蓝。我确认这三种都看到了。&lt;/p&gt;&#10;&lt;p&gt;这至少说明键盘能显示明显的颜色，也能接受分区数据。但它只验证了输出路径，不能证明真实聊天状态已经显示正确。接下来还得把状态选择、颜色映射和显示方式一起检查。&lt;/p&gt;&#10;&lt;p&gt;此前的显示会把原生槽位里的白色空闲状态也带进键盘，加上浅冰蓝和亮度变化，视觉上很容易变成一片偏白的光。后来的日常策略改得更直接：&lt;/p&gt;&#10;&lt;ul&gt;&#10;&lt;li&gt;白色和关闭的槽位不再挤占键盘上的活动区域。&lt;/li&gt;&#10;&lt;li&gt;只有一个有色状态时，用整块键盘显示。&lt;/li&gt;&#10;&lt;li&gt;多个有色状态时，再做分区。&lt;/li&gt;&#10;&lt;li&gt;工作蓝改成更饱和的蓝色，RGB 为 &lt;code&gt;35, 105, 255&lt;/code&gt;，先用常亮保证可见。&lt;/li&gt;&#10;&lt;/ul&gt;&#10;&lt;p&gt;原始槽位数据仍然保留，改变的是呈现方式。至于相邻同色区域，目前还不能说已经完美解决，尤其不能把两区、三区通过测试，推成所有分区数量都清楚可读。&lt;/p&gt;&#10;&lt;p&gt;后来我又提了一个更直接的改法：把分界处的一条按键都点亮，不要只在顶部放一个白色标记。调整后的实拍里，两个相邻绿区之间已经出现了纵向白色分隔键。键盘每一排的位置有错位，大键也不能切开，所以它是一串沿边界排列的亮键，不是一条连续的灯带。&lt;/p&gt;&#10;&lt;p&gt;&lt;img alt="最新分区实拍：相邻绿区之间的纵向白色分隔键" class="gallery-image" data-flex-basis="320px" data-flex-grow="133" height="1279" loading="lazy" sizes="(max-width: 767px) calc(100vw - 30px), (max-width: 1023px) 700px, (max-width: 1279px) 950px, 1232px" src="https://www.huangqixuan.com/site-images/codexlighthub-native/white-boundary-latest_hu_b8ec19d1a1186e9a.webp" srcset="https://www.huangqixuan.com/site-images/codexlighthub-native/white-boundary-latest_hu_654e775846e468d7.webp 800w, https://www.huangqixuan.com/site-images/codexlighthub-native/white-boundary-latest_hu_21a945b9b82ba7c3.webp 1600w, https://www.huangqixuan.com/site-images/codexlighthub-native/white-boundary-latest_hu_b8ec19d1a1186e9a.webp 1706w" width="1706"&gt;&lt;/p&gt;&#10;&lt;p&gt;&lt;em&gt;最新原图：左侧蓝色，中部与右侧绿色，白色按键标出两个相邻绿区的边界。这次改动后的代码测试为 110 项通过，照片记录实际显示效果。&lt;/em&gt;&lt;/p&gt;&#10;&lt;p&gt;写这篇时，我又拍了两张新版分区的效果。第一张能看到左右蓝色、中间绿色；第二张多了一块黄橙色，从左到右是蓝、黄橙、绿、蓝。和之前那种整块偏白的观感相比，这两张照片里已经能直接辨认出不同的颜色区域。&lt;/p&gt;&#10;&lt;p&gt;&lt;img alt="蓝绿双区：左侧蓝色，右侧绿色" class="gallery-image" data-flex-basis="320px" data-flex-grow="133" height="1279" loading="lazy" sizes="(max-width: 767px) calc(100vw - 30px), (max-width: 1023px) 700px, (max-width: 1279px) 950px, 1232px" src="https://www.huangqixuan.com/site-images/codexlighthub-native/zones-blue-green_hu_f5c344f3af53b35f.webp" srcset="https://www.huangqixuan.com/site-images/codexlighthub-native/zones-blue-green_hu_6f679957f32f6540.webp 800w, https://www.huangqixuan.com/site-images/codexlighthub-native/zones-blue-green_hu_a9cb9dfc49b4ac68.webp 1600w, https://www.huangqixuan.com/site-images/codexlighthub-native/zones-blue-green_hu_f5c344f3af53b35f.webp 1706w" width="1706"&gt;&lt;/p&gt;&#10;&lt;p&gt;&lt;img alt="三块区域：中间绿色，两侧蓝色" class="gallery-image" data-flex-basis="320px" data-flex-grow="133" height="1280" loading="lazy" sizes="(max-width: 767px) calc(100vw - 30px), (max-width: 1023px) 700px, (max-width: 1279px) 950px, 1232px" src="https://www.huangqixuan.com/site-images/codexlighthub-native/zones-blue-green-blue_hu_3c8efa2fc545db31.webp" srcset="https://www.huangqixuan.com/site-images/codexlighthub-native/zones-blue-green-blue_hu_99a69dfd4df8827c.webp 800w, https://www.huangqixuan.com/site-images/codexlighthub-native/zones-blue-green-blue_hu_3d43cbe3105e1848.webp 1600w, https://www.huangqixuan.com/site-images/codexlighthub-native/zones-blue-green-blue_hu_3c8efa2fc545db31.webp 1707w" width="1707"&gt;&lt;/p&gt;&#10;&lt;p&gt;&lt;img alt="新版分区实拍：蓝、黄橙、绿、蓝" class="gallery-image" data-flex-basis="320px" data-flex-grow="133" height="1280" loading="lazy" sizes="(max-width: 767px) calc(100vw - 30px), (max-width: 1023px) 700px, (max-width: 1279px) 950px, 1232px" src="https://www.huangqixuan.com/site-images/codexlighthub-native/zones-four-colors_hu_542aeedf63428255.webp" srcset="https://www.huangqixuan.com/site-images/codexlighthub-native/zones-four-colors_hu_393543bff41e51ca.webp 800w, https://www.huangqixuan.com/site-images/codexlighthub-native/zones-four-colors_hu_adb95f6023b584f7.webp 1600w, https://www.huangqixuan.com/site-images/codexlighthub-native/zones-four-colors_hu_542aeedf63428255.webp 1707w" width="1707"&gt;&lt;/p&gt;&#10;&lt;p&gt;&lt;em&gt;新版分区实拍之二：四块区域同时显示。照片里的黄橙色会受拍摄曝光和白平衡影响；两张静态照片只记录颜色与空间分区，不证明动画帧率，也不单独证明每个区域的任务对应关系。&lt;/em&gt;&lt;/p&gt;&#10;&lt;p&gt;真正询问时也单独试过。我在一次真实询问里确认键盘和挂灯都变成了橙色。这个反馈比手动发送一个橙色测试命令更有意义，因为它走的是实际交互链路。&lt;/p&gt;&#10;&lt;p&gt;&lt;img alt="黄橙色与蓝色分区近照" class="gallery-image" data-flex-basis="320px" data-flex-grow="133" height="1280" loading="lazy" sizes="(max-width: 767px) calc(100vw - 30px), (max-width: 1023px) 700px, (max-width: 1279px) 950px, 1232px" src="https://www.huangqixuan.com/site-images/codexlighthub-native/zones-amber-blue_hu_df2e7fbadbb89057.webp" srcset="https://www.huangqixuan.com/site-images/codexlighthub-native/zones-amber-blue_hu_69bfe536f407bd13.webp 800w, https://www.huangqixuan.com/site-images/codexlighthub-native/zones-amber-blue_hu_94c7774ad4742815.webp 1600w, https://www.huangqixuan.com/site-images/codexlighthub-native/zones-amber-blue_hu_df2e7fbadbb89057.webp 1707w" width="1707"&gt;&lt;/p&gt;&#10;&lt;p&gt;&lt;em&gt;另一组分区近照：左侧黄橙色，右侧蓝色。不同状态可以同时留在键盘上。&lt;/em&gt;&lt;/p&gt;&#10;&lt;p&gt;&lt;img alt="询问窗口、键盘分区和 Yeelight 挂灯同框" class="gallery-image" data-flex-basis="320px" data-flex-grow="133" height="1280" loading="lazy" sizes="(max-width: 767px) calc(100vw - 30px), (max-width: 1023px) 700px, (max-width: 1279px) 950px, 1232px" src="https://www.huangqixuan.com/site-images/codexlighthub-native/real-question-desk_hu_31a8945687873a73.webp" srcset="https://www.huangqixuan.com/site-images/codexlighthub-native/real-question-desk_hu_f3914854491d330.webp 800w, https://www.huangqixuan.com/site-images/codexlighthub-native/real-question-desk_hu_4a76a6125b5ca1f1.webp 1600w, https://www.huangqixuan.com/site-images/codexlighthub-native/real-question-desk_hu_31a8945687873a73.webp 1707w" width="1707"&gt;&lt;/p&gt;&#10;&lt;p&gt;&lt;em&gt;这张全景把询问窗口、键盘上的黄橙色区域和挂灯两端的橙光拍在了一起。比起只看设置页，我更想保留这种实际使用时的画面。&lt;/em&gt;&lt;/p&gt;&#10;&lt;h2 id="完成以后我还是想回到原来的彩色"&gt;&lt;a href="#%e5%ae%8c%e6%88%90%e4%bb%a5%e5%90%8e%e6%88%91%e8%bf%98%e6%98%af%e6%83%b3%e5%9b%9e%e5%88%b0%e5%8e%9f%e6%9d%a5%e7%9a%84%e5%bd%a9%e8%89%b2" class="header-anchor"&gt;&lt;/a&gt;完成以后，我还是想回到原来的彩色&#10;&lt;/h2&gt;&lt;p&gt;另一个让我直接要求改回去的地方，是任务结束后的灯。&lt;/p&gt;&#10;&lt;p&gt;我问：“运作完的灯为什么关了，还是和以前一样比较好。”&lt;/p&gt;&#10;&lt;p&gt;如果把原生槽位的关闭状态直接照搬到整个桌面，任务结束可能就把灯关掉了。但我平时用的就是彩色灯效，希望任务提示只是暂时覆盖它，而不是接管之后再把它熄灭。&lt;/p&gt;&#10;&lt;p&gt;后来的修正恢复了本地的完成保持：收到绿色完成状态后，保持三分钟，再恢复平时的灯效。键盘恢复 G-Helper 保存的灯效，Yeelight 恢复配置的空闲灯效。&lt;/p&gt;&#10;&lt;p&gt;&lt;img alt="平时的彩虹灯效实拍" class="gallery-image" data-flex-basis="320px" data-flex-grow="133" height="1350" loading="lazy" sizes="(max-width: 767px) calc(100vw - 30px), (max-width: 1023px) 700px, (max-width: 1279px) 950px, 1232px" src="https://www.huangqixuan.com/site-images/codexlighthub/idle-rainbow_hu_fd591344525db735.webp" srcset="https://www.huangqixuan.com/site-images/codexlighthub/idle-rainbow_hu_acde748662294c16.webp 800w, https://www.huangqixuan.com/site-images/codexlighthub/idle-rainbow_hu_7fe519b2d72f8cd2.webp 1600w, https://www.huangqixuan.com/site-images/codexlighthub/idle-rainbow_hu_fd591344525db735.webp 1800w" width="1800"&gt;&lt;/p&gt;&#10;&lt;p&gt;&lt;em&gt;沿用上篇的彩虹灯效实拍，展示我想保留的日常效果，不单独证明三分钟倒计时与自动恢复的全过程。&lt;/em&gt;&lt;/p&gt;&#10;&lt;p&gt;这三分钟也不能挡住新任务。同一位置如果又变成蓝色、橙色或红色，就立即显示新状态；重复收到同一轮绿色不会不断延长倒计时。保持期间收到白色或关闭，也不应立刻把完成提示切掉。&lt;/p&gt;&#10;&lt;p&gt;这里还有一个边界：如果根本没有收到绿色，只是从蓝色变成关闭，就不能擅自判断“任务完成了”，再编出一段绿色提示。&lt;/p&gt;&#10;&lt;p&gt;这一轮修改后的本地测试记录是 109 项通过。它验证了程序行为，但截至这篇记录，我还没有把完整三分钟的双设备实机保持、恢复过程当作已经验收的结果。长时间使用、重启后的恢复，以及多个真实任务同时变化，仍然需要继续观察。&lt;/p&gt;&#10;&lt;h2 id="我现在更想要一盏看得懂的灯"&gt;&lt;a href="#%e6%88%91%e7%8e%b0%e5%9c%a8%e6%9b%b4%e6%83%b3%e8%a6%81%e4%b8%80%e7%9b%8f%e7%9c%8b%e5%be%97%e6%87%82%e7%9a%84%e7%81%af" class="header-anchor"&gt;&lt;/a&gt;我现在更想要一盏看得懂的灯&#10;&lt;/h2&gt;&lt;p&gt;这一轮从分区开始，绕到了逐帧动画、虚拟 HID 和 Micro 状态，最后又回到了很简单的要求：蓝色得看得清，需要我回答时要提醒，完成后别马上消失，也别把我原来的灯效弄没了。&lt;/p&gt;&#10;&lt;p&gt;Micro 给我的启发一直没有变。我喜欢的是把任务状态放到视线边缘，不用频繁切回聊天窗口。至于是不是每个区域都在滚动、有没有复制出向导里的全部功能，反而没那么着急。&lt;/p&gt;&#10;&lt;p&gt;目前的版本已经能继续沿着原生状态接入这条路走，也保留了后续校准和回退的余地。我会先让它在自己的桌面上稳定工作，再决定哪些效果值得留下。&lt;/p&gt;&#10;&lt;p&gt;毕竟我想要的是它在需要的时候叫我回来，而不是让我一直盯着灯，猜它现在到底是什么意思。&lt;/p&gt;&#10;&lt;h2 id="留两张整理后的桌面照片"&gt;&lt;a href="#%e7%95%99%e4%b8%a4%e5%bc%a0%e6%95%b4%e7%90%86%e5%90%8e%e7%9a%84%e6%a1%8c%e9%9d%a2%e7%85%a7%e7%89%87" class="header-anchor"&gt;&lt;/a&gt;留两张整理后的桌面照片&#10;&lt;/h2&gt;&lt;p&gt;最后，我也给两张照片做了 AI 美化，整理曝光和背景，留作这篇的视觉记录。前面的原图仍然保留。美化版可能重绘按键字符、屏幕文字和局部细节，不用于核对按键映射、灯光亮度或软件界面。&lt;/p&gt;&#10;&lt;p&gt;&lt;img alt="四色分区近照 · AI 美化版，非测试证据" class="gallery-image" data-flex-basis="320px" data-flex-grow="133" height="1086" loading="lazy" sizes="(max-width: 767px) calc(100vw - 30px), (max-width: 1023px) 700px, (max-width: 1279px) 950px, 1232px" src="https://www.huangqixuan.com/site-images/codexlighthub-native/keyboard-retouched_hu_e2bcb3c44a66a163.webp" srcset="https://www.huangqixuan.com/site-images/codexlighthub-native/keyboard-retouched_hu_2e089d98af871631.webp 800w, https://www.huangqixuan.com/site-images/codexlighthub-native/keyboard-retouched_hu_e2bcb3c44a66a163.webp 1448w" width="1448"&gt;&lt;/p&gt;&#10;&lt;p&gt;&lt;img alt="桌面全景 · AI 美化版，非测试证据" class="gallery-image" data-flex-basis="320px" data-flex-grow="133" height="1086" loading="lazy" sizes="(max-width: 767px) calc(100vw - 30px), (max-width: 1023px) 700px, (max-width: 1279px) 950px, 1232px" src="https://www.huangqixuan.com/site-images/codexlighthub-native/desk-retouched_hu_6f057248d34de892.webp" srcset="https://www.huangqixuan.com/site-images/codexlighthub-native/desk-retouched_hu_9c9ee236db8e02ac.webp 800w, https://www.huangqixuan.com/site-images/codexlighthub-native/desk-retouched_hu_6f057248d34de892.webp 1448w" width="1448"&gt;&lt;/p&gt;&#10;</description></item><item><title>让 Codex 用灯光叫我回来：CodexLightHub 的 ROG 与 Yeelight 实机记录</title><link>https://www.huangqixuan.com/p/codexlighthub-windows-rgb/</link><pubDate>Tue, 08 Sep 2026 00:00:00 +0800</pubDate><guid>https://www.huangqixuan.com/p/codexlighthub-windows-rgb/</guid><description>&lt;img src="https://www.huangqixuan.com/site-images/codexlighthub/cover_hu_a0f28dc5a066aea9.webp" alt="Featured image of post 让 Codex 用灯光叫我回来：CodexLightHub 的 ROG 与 Yeelight 实机记录" /&gt;&lt;p&gt;Codex 在后台跑任务时，我不想一直盯着窗口。更需要提醒我的时刻，是它已经停下来，等我回答一个问题。既然桌上已经有 RGB 键盘和挂灯，能不能让这些灯直接表示任务状态？&lt;/p&gt;&#10;&lt;p&gt;这个想法来自 Codex Micro 的状态指示灯。它用颜色告诉我 Codex 正在工作、等待输入还是已经完成，我也想让整张桌面有同样直观的反馈。最后做出来的 CodexLightHub，是一个运行在 Windows 上的 Python 小程序。它接收 Codex 的生命周期事件，再把状态发给 ROG 笔记本灯光和 Yeelight 挂灯的后方氛围灯。&lt;/p&gt;&#10;&lt;p&gt;这篇记录整理到 &lt;code&gt;1.0.6&lt;/code&gt;。ASUS 和 Yeelight 两条链路已经接通，EZ80 仍停在只读探测阶段。本文中的灯光照片均来自实际运行效果，连接图只用于解释程序结构。&lt;/p&gt;&#10;&lt;h2 id="先确定灯光应该告诉我什么"&gt;&lt;a href="#%e5%85%88%e7%a1%ae%e5%ae%9a%e7%81%af%e5%85%89%e5%ba%94%e8%af%a5%e5%91%8a%e8%af%89%e6%88%91%e4%bb%80%e4%b9%88" class="header-anchor"&gt;&lt;/a&gt;先确定灯光应该告诉我什么&#10;&lt;/h2&gt;&lt;p&gt;最早的设想很直接：工作时蓝色，需要我时橙色，完成时绿色。真正用起来以后，才发现颜色背后的判断比变色本身更难。&lt;/p&gt;&#10;&lt;p&gt;例如，Codex 发起权限检查时，可能由自动审核处理，根本没有弹窗让我操作。如果每次都变橙色，我就会不断被叫回来，最后开始忽略它。&lt;/p&gt;&#10;&lt;p&gt;&lt;code&gt;1.0.6&lt;/code&gt; 把规则收紧到了下面这样：&lt;/p&gt;&#10;&lt;table&gt;&#10;&#9;&lt;thead&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;th&gt;状态&lt;/th&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;th&gt;当前行为&lt;/th&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&lt;/thead&gt;&#10;&#9;&lt;tbody&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;工作中&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;满亮蓝色；ROG 使用硬件呼吸形成动态起伏，Yeelight 保持静态蓝色&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;真实询问&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;code&gt;request_user_input&lt;/code&gt; 调用前变成满亮橙色，回答后恢复蓝色&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;自动审核或后台权限检查&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;保持蓝色，不触发橙色提醒&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;本轮完成&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;满亮绿色保持 180 秒，再恢复日常彩色灯效&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;收到中断事件&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;满亮红色短暂提示，默认保持 4 秒&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;空闲&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;ASUS 恢复 G-Helper 保存的灯效；Yeelight 按配置恢复彩虹&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&lt;/tbody&gt;&#10;&lt;/table&gt;&#10;&lt;div class="article-photo-grid"&gt;&lt;figure&gt;&#10; &lt;img src="https://www.huangqixuan.com/img/codexlighthub/working-blue.webp" alt="蓝色：Codex 正在工作" loading="lazy" decoding="async"&gt;&#10; &lt;figcaption&gt;蓝色：Codex 正在工作&lt;/figcaption&gt;&#10; &lt;/figure&gt;&lt;figure&gt;&#10; &lt;img src="https://www.huangqixuan.com/img/codexlighthub/waiting-orange.webp" alt="橙色：等待我回答问题" loading="lazy" decoding="async"&gt;&#10; &lt;figcaption&gt;橙色：等待我回答问题&lt;/figcaption&gt;&#10; &lt;/figure&gt;&lt;figure&gt;&#10; &lt;img src="https://www.huangqixuan.com/img/codexlighthub/completed-green.webp" alt="绿色：这一轮已经完成" loading="lazy" decoding="async"&gt;&#10; &lt;figcaption&gt;绿色：这一轮已经完成&lt;/figcaption&gt;&#10; &lt;/figure&gt;&lt;figure&gt;&#10; &lt;img src="https://www.huangqixuan.com/img/codexlighthub/idle-rainbow.webp" alt="彩色：恢复平时的桌面灯效" loading="lazy" decoding="async"&gt;&#10; &lt;figcaption&gt;彩色：恢复平时的桌面灯效&lt;/figcaption&gt;&#10; &lt;/figure&gt;&lt;/div&gt;&#10;&#10;&lt;p&gt;这里的“完成”指当前一轮结束，不代表整个项目已经做完。红色也不能覆盖所有错误：当前安装器没有注册通用错误事件，Hub 只是保留了 &lt;code&gt;Interrupt&lt;/code&gt; 的处理入口。&lt;/p&gt;&#10;&lt;p&gt;还有一个限制要单独说清楚。项目默认启用了 &lt;code&gt;plan_stop_is_waiting&lt;/code&gt;，当收到带有 &lt;code&gt;permission_mode=plan&lt;/code&gt; 的 &lt;code&gt;Stop&lt;/code&gt; 时，会保守地显示等待状态。它是为部分计划确认界面补的启发式判断，不能证明屏幕上一定有弹窗。普通询问使用的是实际工具事件，这两条路径不能混为一谈。&lt;/p&gt;&#10;&lt;h2 id="一条很短的事件链"&gt;&lt;a href="#%e4%b8%80%e6%9d%a1%e5%be%88%e7%9f%ad%e7%9a%84%e4%ba%8b%e4%bb%b6%e9%93%be" class="header-anchor"&gt;&lt;/a&gt;一条很短的事件链&#10;&lt;/h2&gt;&lt;p&gt;程序分成三层：Hook 接事件，Hub 判断状态，Adapter 控灯。&lt;/p&gt;&#10;&lt;p&gt;&lt;img alt="CodexLightHub 的事件、状态机和双设备输出示意" loading="lazy" sizes="(max-width: 767px) calc(100vw - 30px), (max-width: 1023px) 700px, (max-width: 1279px) 950px, 1232px" src="https://www.huangqixuan.com/site-images/codexlighthub/cover.svg"&gt;&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-text" data-lang="text"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;Codex lifecycle hooks&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; │&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;codex-light-hook.cmd → hook.py&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; │ UDP 127.0.0.1:17871&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; ▼&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;Hub：按会话保存状态、去重、决定当前灯色&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; ├── ASUS HID → ROG 键盘与机身灯光&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; └── 本地 MIoT → Yeelight 后方氛围灯&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;&lt;code&gt;hook.py&lt;/code&gt; 只挑出事件名、会话、轮次、工具名等少量字段，发送到本机回环地址后退出。提示词、工具参数、工具输出、回复正文和工作目录都不在转发白名单里。灯光程序也不输出允许或拒绝权限的决定。&lt;/p&gt;&#10;&lt;p&gt;硬件写入在 Hub 的工作线程里执行。挂灯连接慢了，或某个设备不可用，不应该让 Codex 的 Hook 一直等着。&lt;/p&gt;&#10;&lt;p&gt;&lt;img alt="Codex Desktop、ROG 键盘和 Yeelight 挂灯联动的桌面实拍" class="gallery-image" data-flex-basis="320px" data-flex-grow="133" height="1350" loading="lazy" sizes="(max-width: 767px) calc(100vw - 30px), (max-width: 1023px) 700px, (max-width: 1279px) 950px, 1232px" src="https://www.huangqixuan.com/site-images/codexlighthub/desktop-overview_hu_4bafa2bc26838238.webp" srcset="https://www.huangqixuan.com/site-images/codexlighthub/desktop-overview_hu_b720b52f4ea1c3c8.webp 800w, https://www.huangqixuan.com/site-images/codexlighthub/desktop-overview_hu_bc99cec487176054.webp 1600w, https://www.huangqixuan.com/site-images/codexlighthub/desktop-overview_hu_4bafa2bc26838238.webp 1800w" width="1800"&gt;&lt;/p&gt;&#10;&lt;p&gt;同一时间开多个任务时，Hub 按下面的顺序选择灯色：&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-text" data-lang="text"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;waiting &amp;gt; running &amp;gt; interrupted &amp;gt; completed &amp;gt; idle&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;因此，一个任务完成不会用绿色盖住另一个任务的橙色询问；只要还有任务在运行，整体也会优先显示蓝色。这意味着绿色的 3 分钟计时到了，不一定马上看到彩虹，还要看其他会话是否仍然活跃。&lt;/p&gt;&#10;&lt;h2 id="rog从没有设备的-rest-接口走到-asus-hid"&gt;&lt;a href="#rog%e4%bb%8e%e6%b2%a1%e6%9c%89%e8%ae%be%e5%a4%87%e7%9a%84-rest-%e6%8e%a5%e5%8f%a3%e8%b5%b0%e5%88%b0-asus-hid" class="header-anchor"&gt;&lt;/a&gt;ROG：从没有设备的 REST 接口，走到 ASUS HID&#10;&lt;/h2&gt;&lt;p&gt;这次使用的笔记本是 ROG Strix G16 G615LR，灯光由 G-Helper 0.279.0 管理。&lt;/p&gt;&#10;&lt;p&gt;最初的 Aura REST 探测没有枚举到设备，返回值是 &lt;code&gt;5&lt;/code&gt;。我们随后试过 Windows Dynamic Lighting，又遇到了 PyWinRT 枚举接口的参数问题。但确认平时由 G-Helper 控灯后，主线就转向了它使用的 ASUS HID 通道。&lt;/p&gt;&#10;&lt;p&gt;&lt;a class="link" href="https://github.com/seerge/g-helper" target="_blank" rel="noopener"&#10; &gt;G-Helper 的公开源码&lt;/a&gt;提供了实际设备控制实现。项目据此整理协议，再结合本机 G-Helper 日志确认目标设备，而不是只看到 ASUS 的厂商编号就发送数据。&lt;/p&gt;&#10;&lt;p&gt;本机核对到的参数是：&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-text" data-lang="text"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;VID: 0B05&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;PID: 19B6&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;Aura collection: col04&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;Report length: 64 bytes&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;桥接层会同时检查 PID 白名单、配置中的允许列表、日志里的完整 HID 路径、报告长度和 Aura Probe 结果。检查不通过时，拒绝写入。&lt;/p&gt;&#10;&lt;p&gt;灯效写入沿用了三段报告的顺序：&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-text" data-lang="text"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;5D-B3-00-{mode}-{R}-{G}-{B}-{speed}-...&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;5D-B5-00-00-00&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;5D-B4&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;上面是协议结构说明，不是可以直接复制发送的完整数据包。它也不代表所有 ASUS 设备都适用。当前配置默认只允许这次验证过的 &lt;code&gt;19B6&lt;/code&gt;，换型号后应重新探测。&lt;/p&gt;&#10;&lt;p&gt;&lt;code&gt;GHelperAuraBridge.py&lt;/code&gt; 提供 &lt;code&gt;blue&lt;/code&gt;、&lt;code&gt;waiting&lt;/code&gt;、&lt;code&gt;complete&lt;/code&gt;、&lt;code&gt;error&lt;/code&gt; 和 &lt;code&gt;restore&lt;/code&gt; 命令。ASUS 的运行、等待和错误效果使用硬件呼吸模式，不需要 Python 持续计算每一帧亮度。四种任务状态都按 100% 亮度发送。&lt;/p&gt;&#10;&lt;p&gt;恢复灯效时，程序读取 G-Helper 保存的 &lt;code&gt;aura_mode&lt;/code&gt;、&lt;code&gt;aura_color&lt;/code&gt; 和 &lt;code&gt;aura_speed&lt;/code&gt;，再发送对应模式。它不会修改 G-Helper 的配置。这恢复的是保存的日常设置，并不是对接管前任意瞬时灯光状态的完整快照。&lt;/p&gt;&#10;&lt;h2 id="yeelight55443-不通仍然可以走本地-miot"&gt;&lt;a href="#yeelight55443-%e4%b8%8d%e9%80%9a%e4%bb%8d%e7%84%b6%e5%8f%af%e4%bb%a5%e8%b5%b0%e6%9c%ac%e5%9c%b0-miot" class="header-anchor"&gt;&lt;/a&gt;Yeelight：55443 不通，仍然可以走本地 MIoT&#10;&lt;/h2&gt;&lt;p&gt;挂灯是 Yeelight 显示器挂灯 2 Pro，设备型号为 &lt;code&gt;yeelink.light.lamp42&lt;/code&gt;。这里控制的是背后的氛围灯。&lt;/p&gt;&#10;&lt;p&gt;最容易绕进去的地方，是把“Yeelight 设备”与“开放传统 Yeelight LAN Control”画上等号。本机测试中，传统局域网控制端口 &lt;code&gt;55443&lt;/code&gt; 没有开放。这只能说明那条路径没有跑通，不能据此判定设备没有其他本地接口。&lt;/p&gt;&#10;&lt;p&gt;另一个障碍是登录。早期 &lt;code&gt;python-miio/micloud&lt;/code&gt; 的密码登录在这次环境中失败，后面改用了 &lt;a class="link" href="https://pypi.org/project/mihome-ctl/" target="_blank" rel="noopener"&#10; &gt;mihome-ctl&lt;/a&gt; 的米家扫码登录，取得设备的本地 IP 和 Token。这个工具用于完成设备信息获取；日常灯色切换由 CodexLightHub 的本地 MIoT 后端处理。&lt;/p&gt;&#10;&lt;p&gt;所以最终链路是：扫码取得凭据，然后通过本地 MIoT 控灯。它不需要每变一次颜色就重新扫码，也没有把米家账号密码写进 Hub。&lt;/p&gt;&#10;&lt;p&gt;在这盏灯上，氛围灯属性已经按下面的映射完成实机验证：&lt;/p&gt;&#10;&lt;table&gt;&#10;&#9;&lt;thead&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;th&gt;属性&lt;/th&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;th&gt;SIID / PIID&lt;/th&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&lt;/thead&gt;&#10;&#9;&lt;tbody&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;开关&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;3 / 1&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;亮度&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;3 / 2&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;RGB 颜色&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;3 / 3&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;模式&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;3 / 4&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&lt;/tbody&gt;&#10;&lt;/table&gt;&#10;&lt;p&gt;颜色按 RGB 转成十进制值：&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-python" data-lang="python"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="n"&gt;color&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;r&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&amp;lt;&lt;/span&gt; &lt;span class="mi"&gt;16&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;g&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&amp;lt;&lt;/span&gt; &lt;span class="mi"&gt;8&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="n"&gt;b&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;正常变色时，后端依次写入静态模式、颜色、亮度和开关。恢复日常灯效时则把模式放到最后写，因为写颜色可能让设备回到静态模式。此次验证中，最后写入 &lt;code&gt;mode=1&lt;/code&gt; 可以恢复彩虹。&lt;/p&gt;&#10;&lt;p&gt;这里还有一个设备差异：ASUS 的蓝色运行和橙色等待灯效使用硬件呼吸，当前 Yeelight 后端则显示对应颜色的满亮静态灯效。两者表示同一个状态，动画并不完全一致。&lt;/p&gt;&#10;&lt;p&gt;&lt;img alt="Codex 完成后，Yeelight 挂灯显示绿色状态" class="gallery-image" data-flex-basis="320px" data-flex-grow="133" height="1350" loading="lazy" sizes="(max-width: 767px) calc(100vw - 30px), (max-width: 1023px) 700px, (max-width: 1279px) 950px, 1232px" src="https://www.huangqixuan.com/site-images/codexlighthub/yeelight-completed_hu_54f0cb2063c59573.webp" srcset="https://www.huangqixuan.com/site-images/codexlighthub/yeelight-completed_hu_d3664758feb739e.webp 800w, https://www.huangqixuan.com/site-images/codexlighthub/yeelight-completed_hu_5904de5a83dce505.webp 1600w, https://www.huangqixuan.com/site-images/codexlighthub/yeelight-completed_hu_54f0cb2063c59573.webp 1800w" width="1800"&gt;&lt;/p&gt;&#10;&lt;p&gt;Token 是设备控制密钥，只放在本地配置。文章没有附设备地址、Token、登录二维码或账号信息；如果分享工程，应使用 &lt;code&gt;config.example.json&lt;/code&gt;，不能打包自己的运行配置。&lt;/p&gt;&#10;&lt;h2 id="真正费时间的是状态细节"&gt;&lt;a href="#%e7%9c%9f%e6%ad%a3%e8%b4%b9%e6%97%b6%e9%97%b4%e7%9a%84%e6%98%af%e7%8a%b6%e6%80%81%e7%bb%86%e8%8a%82" class="header-anchor"&gt;&lt;/a&gt;真正费时间的是状态细节&#10;&lt;/h2&gt;&lt;h3 id="hook-显示完成不等于灯光脚本执行了"&gt;&lt;a href="#hook-%e6%98%be%e7%a4%ba%e5%ae%8c%e6%88%90%e4%b8%8d%e7%ad%89%e4%ba%8e%e7%81%af%e5%85%89%e8%84%9a%e6%9c%ac%e6%89%a7%e8%a1%8c%e4%ba%86" class="header-anchor"&gt;&lt;/a&gt;Hook 显示完成，不等于灯光脚本执行了&#10;&lt;/h3&gt;&lt;p&gt;Windows 包装命令曾是一个排查点。项目最后用 &lt;code&gt;.cmd&lt;/code&gt; 包装器承接 Python 调用，避免在 Hook 字符串里反复嵌套引号。&lt;/p&gt;&#10;&lt;p&gt;安装器会备份并合并已有的 &lt;code&gt;hooks.json&lt;/code&gt;，保留不属于本项目的处理器。最终版本还移除了本项目之前注册的 &lt;code&gt;PermissionRequest&lt;/code&gt; 处理器，让自动审核不再触发橙色。&lt;/p&gt;&#10;&lt;p&gt;这套安装方式是在本机路径和 Codex 版本下跑通的。包装命令依赖路径格式，迁移到包含空格的用户目录时仍应检查，不能把一次成功当成所有 Windows 环境的保证。&lt;/p&gt;&#10;&lt;h3 id="已完成和我已经看过不是一回事"&gt;&lt;a href="#%e5%b7%b2%e5%ae%8c%e6%88%90%e5%92%8c%e6%88%91%e5%b7%b2%e7%bb%8f%e7%9c%8b%e8%bf%87%e4%b8%8d%e6%98%af%e4%b8%80%e5%9b%9e%e4%ba%8b" class="header-anchor"&gt;&lt;/a&gt;“已完成”和“我已经看过”不是一回事&#10;&lt;/h3&gt;&lt;p&gt;开发中一度参考 Codex Micro 的“完成且未读”思路，让绿色一直保持到下一次交互。用了一下，我又把需求改成了“过几分钟切回彩色”。&lt;/p&gt;&#10;&lt;p&gt;最后的配置是：&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-json" data-lang="json"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;{&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nt"&gt;&amp;#34;completed_hold_seconds&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;180&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nt"&gt;&amp;#34;sticky_completed&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;false&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;}&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;新提示提交后立即回到蓝色，不必等计时结束。Hub 虽然保留了 &lt;code&gt;MarkRead&lt;/code&gt; 和 &lt;code&gt;Read&lt;/code&gt; 入口，但当前接入没有收到“用户已阅读回复”的事件，不能根据绿色是否消失判断我有没有看过结果。&lt;/p&gt;&#10;&lt;h3 id="橙色必须值得我回来"&gt;&lt;a href="#%e6%a9%99%e8%89%b2%e5%bf%85%e9%a1%bb%e5%80%bc%e5%be%97%e6%88%91%e5%9b%9e%e6%9d%a5" class="header-anchor"&gt;&lt;/a&gt;橙色必须值得我回来&#10;&lt;/h3&gt;&lt;p&gt;最后一次调整是把手工变橙色测试改成真正的询问弹窗测试。&lt;/p&gt;&#10;&lt;p&gt;先手工写入橙色，只能证明设备能接收颜色。真正调用 &lt;code&gt;request_user_input&lt;/code&gt;、出现问题、回答后恢复蓝色，才能检查从 Codex 到设备的整条链路。开发记录里最终确认了“弹窗且橙色”，随后完成 &lt;code&gt;1.0.6&lt;/code&gt;。&lt;/p&gt;&#10;&lt;p&gt;Hub 还处理了一个并行工具细节：已经在等我回答时，另一个工具先结束，不应把等待状态提前冲掉。只有匹配的询问结束，才应该回到运行状态。&lt;/p&gt;&#10;&lt;h2 id="目前完成到哪里"&gt;&lt;a href="#%e7%9b%ae%e5%89%8d%e5%ae%8c%e6%88%90%e5%88%b0%e5%93%aa%e9%87%8c" class="header-anchor"&gt;&lt;/a&gt;目前完成到哪里&#10;&lt;/h2&gt;&lt;p&gt;截至这次记录，已经完成 ASUS HID 写入、Yeelight 本地 MIoT 写入、双设备接入同一状态机、真实询问提醒，以及完成 3 分钟后的彩色恢复。最终开发记录报告 11 项自动测试通过，代码中的测试覆盖了状态变化、HID 构造与保护条件、MIoT 属性写入等部分。自动测试与实机变色是两类证据，不能互相替代。&lt;/p&gt;&#10;&lt;p&gt;EZ80 暂时只有只读 HID 探测器，没有写入灯光协议。当前项目也没有实现逐键显示多个任务、按某个键跳回会话，或者识别所有客户端弹窗。这些早期讨论过的想法，没有被写成已经完成的功能。&lt;/p&gt;&#10;&lt;p&gt;工程仍是围绕这台 G615LR 和这盏 lamp42 做的个人工具。设备断开、网络超时、G-Helper 与其他灯光控制器竞争，以及不同 Codex 版本的事件差异，都是后续使用时需要观察的地方。&lt;/p&gt;&#10;&lt;p&gt;对我来说，最有用的结果是：起伏的蓝色让我知道它还在工作，橙色提示有问题要回答，绿色短暂保留完成状态，然后桌面回到原来的彩色。这个小工具的价值，取决于这些提醒能不能对应真实情况。&lt;/p&gt;&#10;</description></item></channel></rss>