<?xml version="1.0" encoding="utf-8"?>
<?xml-stylesheet href="/feeds/rss-style.xsl" type="text/xsl"?>
<rss version="2.0" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:atom="http://www.w3.org/2005/Atom">
    <channel>
        <title>Aurora</title>
        <link>https://blog.auroramaple.com/</link>
        <description>Aurora 的个人博客, 记录技术与生活.</description>
        <lastBuildDate>Sat, 19 Sep 2026 15:49:01 GMT</lastBuildDate>
        <docs>https://validator.w3.org/feed/docs/rss2.html</docs>
        <generator>Astro-Theme-Retypeset with Feed for Node.js</generator>
        <language>zh</language>
        <copyright>Copyright © 2026 Aurora</copyright>
        <atom:link href="https://blog.auroramaple.com/rss.xml" rel="self" type="application/rss+xml"/>
        <item>
            <title><![CDATA[我合上电脑以后, 还有一台机器醒着]]></title>
            <link>https://blog.auroramaple.com/posts/a-machine-stays-awake/</link>
            <guid isPermaLink="false">https://blog.auroramaple.com/posts/a-machine-stays-awake/</guid>
            <pubDate>Sat, 19 Sep 2026 00:00:00 GMT</pubDate>
            <description><![CDATA[知识库, AI 助手, 开发环境, 住宅出口, 还有一盏台灯. 我把一些需要继续的事情交给 Mini, 也慢慢学着照看它.]]></description>
            <content:encoded><![CDATA[<p>我合上 MacBook 的时候, 通常觉得今天的事情差不多了.</p>
<p>可有些事还得继续. 消息可能晚一点来, 手机上还会用到那些笔记, 刚配好的服务也不能跟着电脑一起睡下. 后来, 我把这些事情陆续交给了 Mini.</p>
<p>起初只是给它安排一点活. 多放一份资料, 多跑一个服务, 好像都不费什么事. 等到有一次连不上它, 我才开始逐项想: 哪些东西还在那里等着? 哪些事情也会跟着停下来?</p>
<p>一台机器在日子里的分量, 有时要等它没了回应, 才掂得出来.</p>
<h2>把需要继续的事情留下</h2>
<p>MacBook 跟着我走. 开发, 查资料, 看页面, 大部分看得见的工作都在它上面发生. 用完合起来, 放进包里, 很自然.</p>
<p>服务却不太懂这种自然. 它们需要进程继续运行, 网络保持连接, 文件待在约好的位置. 我可以换一个地方坐下, 一个等待消息的入口却不能每次都跟着重新安顿.</p>
<p>Mini 接过的, 就是这一部分.</p>
<p>我在上面部署过 AI 助手的消息入口, 配过后台任务, 放过需要远程访问的开发环境. 它们各有自己的服务和目录, 有些一直保留, 有些后来换了做法, 也有一些已经停掉. 比如早先的 CLI Remote 常驻服务, 后来就退役了, 没有为了凑一个功能清单继续挂在那里.</p>
<p>这也让我逐渐养成一种习惯: 想留一个服务之前, 先想想明天还用不用得上. 真要留下, 就把启动方式、日志位置和停止办法一并安顿好. 否则今天少敲的几条命令, 过一阵总会变成自己都认不出的后台进程.</p>
<p>我愿意让它常开, 是因为有些工作确实需要一个固定的去处. 至于我自己, 可以暂时离开屏幕.</p>
<h2>我的笔记, 在那里另有一份</h2>
<p>Mini 上最让我踏实的东西, 是知识库.</p>
<p>主要的整理仍然在 MacBook 上完成. 项目做到了哪里, 为什么没有采用另一个方案, 某次部署留下什么问题, 我们把它们写进 Markdown. 普通笔记通过私有 Git 同步, 需要单独保管的原始资料则走另一条私有传输路径.</p>
<p>Mini 保存已经同步过去的副本, 再通过一个独立的只读入口, 让 ChatGPT 能够搜索和查阅.</p>
<p>于是, 手机上问起一个旧项目时, 就有机会找到当时留下的记录. 不必先把 MacBook 打开, 再去翻某个文件夹, 把一段背景复制进聊天框. 前提当然是资料已经同步过去, Mini 和查询服务也都在线.</p>
<p>这个入口没有写文件和执行命令的能力. 它能翻阅允许范围内的资料, 不能顺便去改项目. 真正要维护知识库, 仍然走编辑、检查和同步的流程. 我喜欢这种安排带来的清楚: 查一条记录, 不必连同改动整台机器的能力一起交出去.</p>
<p>同步也有没完成的时候. 曾经 Mac 端已经推送, Mini 的 SSH 却连不上. 那次只能确认资料到了远端仓库, 不能替 Mini 说一句已经收到了. 再从手机查询, 读到的就可能还是之前的版本.</p>
<p>所以, 我不把常驻副本当成一句万无一失的保证. 更新有没有过去, 仍然要核对. 只是核对过后, 我知道那些费心整理的东西, 在笔记本之外还有一个可以找到的地方.</p>
<p>关于这套记录如何积累, 之前写过<a href="/posts/anchor-and-memory/">个人 Wiki</a>; 至于 ChatGPT 怎样走到这个入口, 则放在<a href="/posts/chatgpt-beyond-the-chat-window/">对话之外, 是我的整个工作现场</a>里. 这次再回头看, 才发现那两篇背后, 都站着这台小主机.</p>
<h2>留一张没有收起的工作台</h2>
<p>Mini 也承接了一部分开发环境.</p>
<p>代码放好, 依赖装好, 需要的服务按项目启动. 经由已经配置的远程通道, 可以访问对应的开发页面和后端. 这样换到另一台设备时, 至少不用先把整套环境从头搬一遍.</p>
<p>这里让我觉得方便的, 是事情可以停在一个能认出来的位置. 上一次在哪个分支, 环境用了什么版本, 哪个进程负责眼前的页面, 都有地方查. 接着做之前核对一遍, 比凭印象重新拼装从容得多.</p>
<p>早先还遇到过一个很小、很磨人的问题: 手机上的远程目录选择器能看见入口, 却进不去. 那时候才发现, 路径在终端里能用, 到另一个入口未必就一样. 后来把目录挂载的方式理顺, 手机上才真正走得进去.</p>
<p>这些麻烦不会出现在一张漂亮的配置表上, 却决定了我下次愿不愿意再用它.</p>
<p>当然, 开发环境留在 Mini, 也不意味着所有工作都适合挪过去. Mac 上的真机调试仍然需要 Mac, 某些界面也得在实际使用的设备上看. 我只把适合留在那里的部分留下, 不强求一台机器替所有设备过日子.</p>
<h2>还有一些流量, 要从它那里出去</h2>
<p>在<a href="/posts/my-proxy-network/">那套折腾了很久的代理网络</a>里, Mini 还承担着住宅出口的一部分工作.</p>
<p>需要走这条路径的流量, 经由隧道到达它, 再从住宅网络出去. 平时查资料、使用 AI 时, 我很少专门想到这一步. 页面打开, 请求返回, 注意力便回到正在做的事情上.</p>
<p>只有出问题的时候, 那段平日看不见的路才会重新显出来.</p>
<p>主机在线, 不代表隧道一定通; 隧道通了, 也还要看真正的请求能不能出去. 同一台设备上的两种连接方式, 更不能算成两套完全独立的保障. 主机断电或者住宅网络断了, 它们仍然可能一起失效.</p>
<p>把这些关系看清以后, 我对备用路径也就少了些想当然. 配置里多写一个名字, 并不能替我完成一次故障切换. 该试的时候, 还是得真的试.</p>
<p>Mini 在这里承担的责任挺重. 但我不愿意因此把它写成整套网络唯一的支点. 哪些流量依赖它, 出问题后怎样处理, 应该是明白的, 不能等到需要的时候才猜.</p>
<h2>最后, 事情落到一盏灯上</h2>
<p>如果一直说服务、隧道和副本, Mini 很容易显得离生活很远.</p>
<p>其实它也替我管过一盏台灯.</p>
<p>我们为自己的台灯做了独立控制程序, 又把相应的 Skill 放进 Mini 上的 Hermes. 查询状态、开关灯、调亮度和白光色温, 都有了具体的调用办法. Mini 通过厂商的云端协议与设备通信, 并不要求主机和灯待在同一个局域网里.</p>
<p>这件事也没有接上就成. 有一次新 Skill 已经装好, 旧会话却还不知道它的存在, 仍然往另一套工具上找. 换了新会话, 才真正读到新能力. 那一刻很能说明这些东西的脾气: 文件已经在磁盘上, 不代表正在和我说话的助手已经见过它.</p>
<p>后来查询和控制走通, 我也确认可以使用. 灯仍然是原来那盏灯, 桌面也没多出什么. 只是想调一下亮度的时候, 多了一种顺手的办法.</p>
<p>我很喜欢这样的结果. 前面花了不少时间读协议、试参数, 最后得到的便利却轻得很, 一句话就说完了.</p>
<p>至于没有弄清的功能, 就先留着. 这盏灯的白光档位已经确认, 任意 RGB 的控制方式没有足够证据, 我们便没有拿猜来的命令去试. 能把自己真正需要的几件事做好, 已经很够用.</p>
<h2>它需要有人照看</h2>
<p>写到这里, 容易把 Mini 想成一台永远安静工作的小机器. 实际上, 我们也查过它的掉线.</p>
<p>有一次翻启动记录和上一轮日志, 看到的是一次非正常关机留下的痕迹. 日志突然结束, 找不到对应的正常关机过程. 这些证据让供电中断、硬关机或强制复位成为可能的解释, 却不足以指认某一个外部原因.</p>
<p>那次让我记住, 远程能看到的东西终究有限. 有时可以确认机器发生过什么, 却还不知道机器旁边发生了什么.</p>
<p>所以, 给它安排工作, 也要给自己留下一点收拾局面的余地. 改之前保存旧配置, 更新后看实际服务, 同步失败就留下失败, 不让一个定时任务悄悄替我宣布成功. 暂时不用的服务停掉, 已经退役的入口清理掉. 下一次排障时, 少一个来历不明的进程, 就少一份猜测.</p>
<p>这些维护谈不上有趣. 相比装好一个新东西, 它们很少带来立刻可见的兴奋. 可我越来越觉得, 愿意做这些, 才算真正准备好长期使用一台常驻主机.</p>
<p>它替我留住工作现场, 我也得记得它需要电、网络、磁盘空间, 以及偶尔的一点耐心.</p>
<h2>电脑可以合上了</h2>
<p>现在回头看, Mini 的工作是慢慢添上去的.</p>
<p>先是一份资料, 后来是一个入口, 再后来, 连一盏灯也与它有了关系. 每一件单独拿出来, 似乎都不值得写一篇文章. 放在一起, 才看出它替我省掉了多少重新打开、重新连接、重新找一遍的动作.</p>
<p>我仍然会合上 MacBook. 有些事情留到明天, 有些念头过几天再说. 不是所有工作都该在夜里继续, 我也不想把每一点空闲都交给自动化.</p>
<p>只是那些已经安排好、确实需要继续的事情, 可以留在那里.</p>
<p>下一次拿起手机, 如果需要翻一页旧笔记, 那个入口还在. 如果想接着做一个项目, 工作台上也还留着上次放下的东西.</p>
<p>我便不用急着把电脑从包里拿出来.</p>
<hr />
<p>本文根据截至 2026-09-19 的个人部署与使用记录整理, 不代表写作时对所有服务做了在线巡检. 私有地址、账户标识和凭据已省略.</p>
]]></content:encoded>
            <author>Aurora</author>
        </item>
        <item>
            <title><![CDATA[把走过的路, 留给下一次出发]]></title>
            <link>https://blog.auroramaple.com/posts/anchor-and-memory/</link>
            <guid isPermaLink="false">https://blog.auroramaple.com/posts/anchor-and-memory/</guid>
            <pubDate>Sat, 19 Sep 2026 00:00:00 GMT</pubDate>
            <description><![CDATA[写下第一篇博客时, 我才发觉, 那些随手留下的项目记录, 已经替我保存了几个月的来路. 关于我的个人 Wiki, 以及如何与 AI 一起, 让经验慢慢留下来.]]></description>
            <content:encoded><![CDATA[<p>写上一篇代理网络的文章时, 我发现, 最难的竟不是落笔.</p>
<p>那套网络已经用了许久. 每天打开电脑, 接通, 查资料, 和 AI 说话, 事情便往前走. 真要回头写它是怎样搭起来的, 脑子里最先浮现的, 却只有一句模糊的话: 折腾了很久.</p>
<p>多久, 折腾了什么, 又为什么非得那样改, 需要慢慢找回来.</p>
<p>我和 AI 翻回以前留下的记录. 有些故障查明了原因, 有些只是恢复了连接; 有些备用路径早就写在配置里, 后来才真正验过它能不能接管. 当时觉得不会忘的细节, 到了今天, 已经不能只凭印象分辨.</p>
<p>好在, 它们还有地方可找.</p>
<p>那是我的个人 Wiki. 一些 Markdown 文件, 几页索引, 按项目归拢的事实, 以及一条条并不起眼的维护记录. 平日里看着很寻常, 直到要写这篇文章, 我才发觉, 那些零碎的字已经替我保存了几个月的来路.</p>
<h2>我不想每次都做一个重新介绍自己的人</h2>
<p>和 AI 一起做事久了, 会发现, 把问题说清楚也是一份工作.</p>
<p>一个项目为什么这样安排, 哪个方案已经试过, 哪一步只是编译通过, 哪一步确实用起来了. 这些事情在当时的对话里都很清楚. 可是换一次任务, 隔一段时间, 又得把它们从头铺开.</p>
<p>重讲一遍也未必能讲全. 人往往记得结论, 却忘了结论成立的条件. 记得那天说过可以, 却未必记得后面还有半句: 在这个环境里可以, 另一端还没有验证.</p>
<p>我渐渐舍不得花在这里的时间. 一个问题已经认真想过, 一条路已经亲自走过, 下一次再遇见, 总该比第一次从容一点.</p>
<p>于是, 我开始把这些东西往固定的地方放. 不再任由它们留在不同的聊天窗口, 等到需要时再凭几个关键词翻找.</p>
<p>项目有项目的页, 做事的方法有工作流的页. 某个决定写下缘由, 某次验证留下边界. 下次接着做, 先读相关记录, 再去看眼前的文件和实际环境.</p>
<p>这样的开始让我舒服许多. 不必急着开工, 也不必重新交代一遍所有背景. 先把上一次放下的事情认出来, 再往前走.</p>
<h2>让记录成为做事的一部分</h2>
<p>有一个文件夹, 还不够.</p>
<p>文件可以越积越多, 经验却未必更容易找到. 一份笔记写在这里, 另一份留在那里, 内容相近, 日期不同. 到最后, 连自己也说不准该信哪一份.</p>
<p>所以我给这套知识库配了一个 <code>wiki</code> skill. 它是一份交给 AI 的查阅与维护规则: 从哪里找, 先读什么, 哪些内容值得写下, 写到哪里, 又有哪些东西不该放进去.</p>
<p>需要接续项目时, 先看索引, 找到对应的页面, 只读与眼前这件事有关的部分. 完成了有用的工作, 再把新的事实和决定整理回去. 页面确实属于哪个项目, 就写回哪个项目; 归属还拿不准, 先留下待整理的记录.</p>
<p>知识库的位置是固定的. 我可以在不同项目之间来回切换, 记录仍回到同一个地方. 这条规则看着朴素, 却省掉了日后寻找许多个副本的麻烦.</p>
<p>我也希望整理发生在事情刚刚弄清楚的时候. 那时还知道为什么要改, 什么已经验证, 哪个疑问尚未解决. 若等到很久以后再补, 写下的常常只剩一个结果, 过程里的分寸已经丢了.</p>
<p>一次值得保留的收尾, 因而多了几件小事: 更新相关页面, 写清验过什么, 留下尚未完成的部分, 在维护记录里添上日期和简短说明.</p>
<p>不必把每一次操作都记下来. 没有新结论的检查, 不用反复抄写; 已经说清的事情, 也不用换个措辞再存一遍. 我想让后来读到它的人省些力气, 其中当然也包括未来的自己.</p>
<h2>真正做起项目, 它省下了什么</h2>
<p>这些规矩的用处, 要放回具体的事情里看.</p>
<p>比如这个博客. 第一次上线, 要弄清内容放在哪里, 怎样构建, 怎样部署, 又怎样确认外面的人确实能打开. 这些做完以后, 知识库里便留下了维护记录. 到第二篇文章要发布, 不用再把服务器和目录重新摸一遍. 先找到那份记录, 核对仓库里的发布脚本, 就能沿用已经走通过的流程.</p>
<p>省下来的不只是几条命令. 我们知道这套站点不需要数据库, 知道发布前该做哪些检查, 也知道旧版本留在哪里. 真出了问题, 至少不用一边着急, 一边重新寻找退路.</p>
<p>代理网络的记录则更像一份有日期的病历. 软路由上曾经有一条为内网互联工具准备的 UDP 直连规则, 后来发现范围太宽, 会让普通的 STUN 请求也直接出去. 后续记录写下了怎样收窄它, 怎样重新验证. 只翻到早先那一页, 很容易把已经改掉的做法当成答案; 把前后缘由一并留下, 才知道为什么今天的配置长这样.</p>
<p>这让排障少了一种很消耗人的循环: 好不容易修过的地方, 隔了一阵, 又被自己当作新办法改回去.</p>
<p>还有跨设备接着做事的时候. 某一端同步成功, 不等于另一端也拿到了最新内容. 把已确认和待确认的部分分别记清, 下次开始就知道该先检查哪一端, 不必把整套流程再跑一遍, 也不会把旧副本误当成新的起点.</p>
<p>有时, 最有用的甚至是一个没有采用的决定. 当时为什么觉得某个方案收益不大, 为什么暂时保留简单的做法, 如果只留下最后的配置, 这些考虑是看不出来的. 记下理由, 再遇到相似建议时, 就可以先问条件有没有改变, 而不必重新争论一遍.</p>
<p>我喜欢这些很具体的便利. 少找一份文件, 少走一次回头路, 接手时少猜一个环节. 每次省下的都不多, 但项目做得久了, 人会明显轻松些. 精力终于可以用在眼前真正没解决的事情上.</p>
<h2>比记得更多更要紧的事</h2>
<p>整理旧记录时, 我最看重的是其中的区别.</p>
<p>怀疑一个原因, 和查明一个原因, 要分开写. 在本地打开页面, 和线上已经可以访问, 要分开写. 一端的文件更新了, 另一端尚未核对, 就把那一端留在那里, 不急着替整件事画上句号.</p>
<p>这些句子不够漂亮. 有时一页读下来, 尽是限制和未完成. 但接着做事的时候, 它们很有用. 我知道哪里可以放心沿用, 哪里还需要停下来看看.</p>
<p>我不愿意让一份总结, 把过程修饰得比实际更圆满.</p>
<p>因此, 确认的事实放进项目页, 暂时的线索另行留下. 原始材料也保留自己的位置, 不因为后来有了新的理解, 就回头把旧材料改成新结论. 真要追问一件事, 仍然有来处可以核对.</p>
<p>还有些内容, 本来就不该出现在普通笔记里. 密码, 令牌和密钥, 不会因为一句顺手的总结, 就被带进项目页或维护日志. 需要知道它们在哪里, 和需要把它们写在这里, 是两回事.</p>
<p>知识库要便于翻阅, 就更该在写入时有所取舍.</p>
<p>同样, 旧笔记也会老去. 曾经运行正常的服务, 今天未必还正常; 上一次使用的配置, 此刻可能已经变了. Wiki 告诉我过去确认过什么, 也帮助我找到这次应当复查的地方. 至于现在, 还是要到现在去看.</p>
<p>有了这样的分寸, 我才敢逐渐依赖这些记录.</p>
<h2>一张书签, 和书架上的那些书</h2>
<p>与 Wiki 一起用的, 还有 Task Anchor.</p>
<p>它负责的事情更近一些: 一项长任务还没做完, 先留住目标, 约定, 已经确认的进度和下一步. 对话中断, 或者上下文经过压缩, 接着做的时候, 有一张短笺可读.</p>
<p>比如, 文章写好了, 但我还没审稿. 那么眼下该做的是本地预览, 而不是发布. 这类约定, 就适合留在任务锚点里.</p>
<p>等这项工作完成, 锚点可以收起来. 工作中形成的, 以后仍有用的经验, 则整理进 Wiki. 前者照看眼下尚未合上的一页, 后者慢慢收存已经读过, 还会再翻的内容.</p>
<p>两者都不需要事事启用. 简单的问题, 直接回答就好. 我不想为了防止遗忘, 让每一件小事都先经过一套仪式.</p>
<p>真正需要它们的时候, 是那些投入过时间, 隔天还要继续, 或者日后值得重访的事情.</p>
<h2>留下来的, 也是我自己</h2>
<p>最初整理 Wiki, 我想的多半是实用: 少找几次文件, 少解释几遍背景, 少重复一段已经走过的弯路.</p>
<p>后来读旧页面, 才发现里面还有别的东西.</p>
<p>为什么宁可多验一次, 也不愿意把尚未确定的事说成完成. 为什么一个看上去更先进的方案, 最后没有采用. 为什么有的东西拆掉了, 有的东西明明简单, 却一直留着.</p>
<p>这些选择分散在不同项目里. 单看每一次, 都是很小的决定; 放在一起, 慢慢就看出了自己的习惯. 我在意什么, 愿意为什么花时间, 又从什么时候开始, 不再急着给每个问题找一个漂亮的答案.</p>
<p>AI 可以帮我查阅, 帮我归纳, 帮我把零散的内容整理得更清楚. 但那些取舍仍然来自一次次实际的合作, 来自我说过的可以, 不行, 先等等, 再看一眼.</p>
<p>我希望它下次读到这些的时候, 能更明白我们为什么这样做. 我也希望自己隔了很久再看, 还能认出当时的心思.</p>
<p>于是, 写上一篇博客的时候, Wiki 又有了一个我起初没有特别安排的用处: 它让回忆有了细节.</p>
<p>几个月不再只剩下一句折腾很久. 哪次恢复了连接, 哪次推翻了猜测, 哪条备用路径终于经过验证, 都还留着痕迹. 文章里的底气, 有一部分就来自这里.</p>
<p>我并不想把生活里所有的事都存下来. 只是那些认真做过的, 好不容易弄明白的, 若能留下几行字, 往后再遇见, 就不至于全然陌生.</p>
<p>事情做完了, 屏幕会暗下去. 下一次打开, 又是新的一天.</p>
<p>而索引里的那几行字还在. 顺着它们翻过去, 我能找到上一次的自己, 接过他留下的东西, 继续往前做一点.</p>
]]></content:encoded>
            <author>Aurora</author>
        </item>
        <item>
            <title><![CDATA[对话之外, 是我的整个工作现场]]></title>
            <link>https://blog.auroramaple.com/posts/chatgpt-beyond-the-chat-window/</link>
            <guid isPermaLink="false">https://blog.auroramaple.com/posts/chatgpt-beyond-the-chat-window/</guid>
            <pubDate>Sat, 19 Sep 2026 00:00:00 GMT</pubDate>
            <description><![CDATA[把本机文件, 已打开的浏览器和 Mini 上的知识库接到 ChatGPT 之后, 我终于可以少搬运一些上下文. 也记下这些连接怎样建立, 以及知识如何在不同设备之间接续.]]></description>
            <content:encoded><![CDATA[<p>有时, 我已经把问题说得很清楚, 却还没法开始.</p>
<p>文件在电脑里, 报错在终端里, 正在看的页面留在浏览器里. 上一次为什么这样改, 则写在另一份项目笔记中. 我知道它们彼此有关, 但隔着一个聊天窗口, 还得逐件搬过去.</p>
<p>复制一段代码, 补一张截图, 再解释这份文件放在哪里. 聊到一半, 本地内容变了, 刚才贴进去的又成了旧版本. 有时真正消耗耐心的, 就是这一来一回的搬运.</p>
<p>上一篇写 Wiki, 写的是怎样把做过的事留下来. 这一篇, 想再往前走一步: 留下来的东西, 能不能在需要时直接找到? 正在做的事情, 能不能让 ChatGPT 看到现场, 也在授权范围内动手?</p>
<p>我后来搭了几条连接. 一条通向本机的开发工作区, 一条延伸到已打开的 Chrome, 还有一条通向常驻 Mini 主机上的知识库.</p>
<p>后来, 我开始让它做一些很日常的事: 帮我申请想试的新 AI 服务, 去京东找我需要的东西, 或者读一读电脑里正在改的文件.</p>
<p>这些事情让我比看到一串测试通过更高兴. 原先要自己在几个窗口之间来回跑的小事, 终于有一部分可以在谈话中往前推进.</p>
<h2>先让它看见真正的文件</h2>
<p>这套本地连接, 我用的是 DevSpace.</p>
<p>它在 Mac 上运行一个 MCP 服务, 把打开工作区, 读取与搜索文件, 编辑与写入等能力交给经过认证的 ChatGPT 调用. MCP 可以理解为双方约定好的工具接口: ChatGPT 提出调用, 本地服务执行, 再把结果送回对话.</p>
<p>执行文件操作的, 始终是本机的程序. 单独打开一个聊天窗口, 并不会自动获得我的磁盘访问权. 我日常使用的 Codex 又是另一套工作入口; 这里记录的是给 ChatGPT 另行接上的连接, 两者不能因为都能写代码, 就混成一回事.</p>
<p>我们搭过的 DevSpace 链路, 从 ChatGPT 经认证入口和 Cloudflare Tunnel, 到达本机服务, 再进入允许的工作目录. 本地服务监听回环地址, 对外连通由隧道承担. Cloudflare 是这条链路中的中转方, 文件被读取回对话时, 内容也确实离开了本机, 不能把这种用法称作完全离线.</p>
<p>用起来, 先选定一个工作区, 之后围绕这个工作区读文件, 查内容, 做修改. 它看见的是磁盘上当时的版本, 写下的也是实际文件, 不必由我在聊天回答与编辑器之间再誊抄一次.</p>
<p>第一次验这条链路, 我们做的事情很小: 从 ChatGPT 读取目录, 创建一个测试文件, 再把它读回来, 最后到本机核对. 只有那份文件真的出现, 内容也一致, 才能说读写走通了. 一个服务进程显示运行中, 还不足以回答这个问题.</p>
<p>在项目里, 这样的连接适合一些很具体的请求. 比如先读现有配置再解释某个行为, 找到实际调用位置再讨论怎么改, 或者把确认过的改动直接写回文件. 对话终于可以贴着正在工作的那份材料展开.</p>
<p>DevSpace 还提供 shell 能力, 可以运行检查和构建. 这也意味着, 不能把工作目录白名单误当作整个操作系统的沙箱. 文件工具的路径限制, 与命令进程在宿主机上的权限, 是不同层面的事. 对我来说, 接通之后仍然要看清调用会做什么, 改完仍然要检查 diff 和运行结果.</p>
<p><a href="https://developers.openai.com/api/docs/guides/developer-mode">ChatGPT Developer mode 的官方文档</a>支持通过 MCP 接入读写工具, 同时说明了写操作的确认机制. 真正能做哪些事, 还取决于服务公布的工具与相应权限, 并不是接上一个地址就什么都能做.</p>
<h2>浏览器里, 有我已经打开的上下文</h2>
<p>文件之外, 浏览器里也放着许多正在进行的事.</p>
<p>有些页面已经登录, 有些内容刚刚展开, 有些问题只有在当前页面里才看得明白. 把网址发过去, 不一定能重现同一个现场. 截图可以保留画面, 却不总适合阅读长段文字, 更不能代替页面上的实际操作.</p>
<p>于是, 我们又给 DevSpace 接了 Chrome.</p>
<p>其中一条路径专门读页面. 它通过 macOS 的 Apple Events 取得已打开页面里加载出来的文字, 链接和部分媒体信息. 对长页面, 可以分段读取. 这样, 我说看一下这个页面, 就不必先把整段内容复制出来.</p>
<p>不过, 页面没有加载的部分, 没有展开的回复, 跨域框架里的内容, 都不能假装已经读过. 读到图片的说明或地址, 也不等于看过图片本身. 这个区别, 在一篇很长的讨论里尤其容易被忽略.</p>
<p>需要动手时, 则由接入的 Chrome DevTools MCP 提供页面列表, 导航, 快照, 点击和输入等工具. 它连接的是已有的 Chrome 会话. 找到正确的标签页, 读取当前快照, 再根据里面的元素操作, 做完重新看结果.</p>
<p>我喜欢这一步带来的变化: 同一个页面, 不再需要我一边念给它听, 一边替它点按钮. 至少在已支持的操作里, 它可以看着页面做事, 我们也有实际结果可核对.</p>
<p>这部分接入曾被一个很具体的问题绊住. 终端里能连接 Chrome, 换到后台服务却读不到需要的文件. 排查后发现, macOS 对运行进程的权限归属才是关键. 后来让有明确身份的 DevSpace Bridge App 持有后端进程, 再为这个 App 授权, 才把这层关系理顺.</p>
<p>连接已有浏览器, 也意味着操作可能带着现有登录态. 所以我保留了有限的工具集合, 没有把任意 JavaScript 执行和文件上传一起开放. 页面上的文字是要处理的材料, 不能因为它写着一句命令, 就变成我对助手的授权.</p>
<p>当时的验证覆盖了测试页面上的读取, 输入, 点击与截图返回. 它说明这些环节已经走通过, 不能因此推论每一个网站都能照常操作. 网站会变, 页面状态也会变, 具体任务仍要看当次结果.</p>
<h2>从想试一个 AI, 到申请真的递出去</h2>
<p>最近申请一个新 AI 服务的体验资格, 就是一件很合适的小事.</p>
<p>我对它好奇, 想用, 却还没把申请流程摸清. 过去遇到这种情况, 往往要自己找入口, 看英文说明, 填表, 再把不确定的问题复制到对话里问. 如今可以让 ChatGPT 陪着往下走, 读当前页面, 理清字段, 在我给出信息以后填入对应的位置.</p>
<p>那次申请里, 有一道题问从哪里知道这个产品. 我说, 推特. 它便填入 X (Twitter). 还有一个让人放松下来的小问题, 问有没有喜欢的 meme, 可以留个链接. 表单走到这里, 已经不像一项需要专门腾出时间的琐事, 更像一边聊, 一边把它办完.</p>
<p>后来, 申请补充信息提交了. 当时的对话记录写下了页面反馈: 对方会审核, 有访问资格再邮件通知.</p>
<p>我喜欢这个过程里的具体感. 不再只是告诉我应该点哪个按钮, 而是事情确实推进了一步. 但这一步也有自己的终点: 申请递出去, 还没有获得资格, 更没有开始调用模型.</p>
<p>后面我又想让它帮忙留意邀请邮件, 却遇到了另一层限制. 那个自动任务环境不能实际读取邮箱, 检查没有走通, 监控随后停了下来. 浏览器里办完申请, 和之后能否在后台持续等邮件, 原来是两项不同的能力.</p>
<p>这段不完全顺利的后续, 我也愿意留下. 它让我更清楚自动化到底走到了哪里. 下次再安排类似的事, 就会先确认后续任务有没有所需的连接与权限, 不只听一句已经替你盯上了.</p>
<h2>去京东找东西, 把来回比较交出去一点</h2>
<p>我也让它去京东搜索过想要的物品.</p>
<p>买东西时, 很多精力其实花在筛选上. 搜索词稍微换一下, 出来的东西就不同; 标题看着相近, 点进去才发现是另一个规格. 看过几个标签页, 又得回头确认刚才那一件到底哪里合适.</p>
<p>浏览器接进来以后, 这段过程就有了可以协作的空间. 我说需求, 它在页面上找, 我再根据结果补充偏好. 原先完全由自己承担的搜索与翻页, 可以交出去一部分.</p>
<p>下面用一个示意需求说明这种用法, 不对应某笔真实订单:</p>
<blockquote>
<p>帮我在京东找一个桌面用的扩展坞. 先看接口够不够, 再看供电和体积. 把几款合适的放在一起比较, 先不用买.</p>
</blockquote>
<p>这个请求真正有用的地方, 是把搜索变成了有条件的阅读. 找到商品以后, 还得核对页面选中的型号, 不能把同一链接下另一个规格的参数抄过来. 写着券后价, 也要弄清它附带什么条件. 看不见的运费和优惠, 就留着, 不凭标题凑一个到手价.</p>
<p>沿着这个示例, 还可以把比较结果整理到本地笔记里. 两条连接便有了配合的机会: 浏览器负责看, 文件工具负责留下结果. 以后再挑, 可以从已经筛过的几项继续, 不必重开一轮标签页.</p>
<p>至于最后选哪一个, 要不要下单, 仍然可以等我看过再说. 我希望省下的是重复翻找的力气, 好把注意力留给真正需要自己决定的地方.</p>
<h2>文件读写, 也可以落在一件小事上</h2>
<p>读写本机文件听着像开发者才需要的能力, 实际上也可以很朴素.</p>
<p>比如把一份已有的 Markdown 文档读出来, 找到要补充的段落, 将确认过的文字写回原文件. 修改之后再读一次, 看内容有没有落到正确的位置. 这里不必另起一个复杂系统, 重要的是正在谈论的那份材料, 与电脑上留下的那份材料终于是同一个东西.</p>
<p>放到开发里, 则可以先搜索某个配置项, 读清它周围的内容, 做一处有范围的修改, 然后运行对应检查. 这样的步骤是工作流示例; 真正的一次改动是否成功, 仍以文件差异和检查结果为准.</p>
<p>我开始在意这种很小的闭合. 说要改的地方, 真正改到了; 说要保留的东西, 还在那里. 对话结束以后, 桌面上的工作也往前走了一点.</p>
<h2>合上笔记本以后, 知识库仍有一处入口</h2>
<p>本地连接解决了一半问题: Mac 开着, 服务运行着, ChatGPT 就有机会走到工作现场.</p>
<p>可是, 如果只是想问一句上次那个项目做到哪里了, 我不希望答案总要等这台笔记本开机.</p>
<p>所以, 我把知识库的一个副本放在常驻的 Mini 上, 又为它准备了独立的 MCP 服务. 它的职责很窄: 搜索笔记, 列出文件, 读取文本, 读取允许范围内的证据图片.</p>
<p>这条入口只读. 没有写入, 删除或 shell 工具, 也不能顺着路径走到任意项目目录. 文件访问在服务端检查, 系统层面也对相关目录加了只读约束. 一个工具叫作只读, 和它确实没有写入能力, 我希望两件事能对得上.</p>
<p>Mini 使用的是 <a href="https://developers.openai.com/api/docs/guides/secure-mcp-tunnels">OpenAI Secure MCP Tunnel</a>. 隧道客户端从主机内部发起向外的 HTTPS 连接, 接收并转交 MCP 请求, 因而不需要为这项知识库服务开放公网入站端口. 它仍然需要正确的账户关联与授权, 服务和隧道也都要保持运行.</p>
<p>两条连接的用途便很清楚了:</p>
<table>
<thead>
<tr>
<th>入口</th>
<th>连接的内容</th>
<th>在我的方案里负责什么</th>
</tr>
</thead>
<tbody>
<tr>
<td>Mac 上的 DevSpace</td>
<td>本机工作区与已打开的 Chrome</td>
<td>授权范围内的文件读写和浏览器操作</td>
</tr>
<tr>
<td>Mini 上的 Wiki MCP</td>
<td>已同步的知识库副本</td>
<td>查询资料, 返回文字与证据图片</td>
</tr>
</tbody>
</table>
<p>Mac 合上以后, 第一条连接自然不能照常替它做事. 第二条不依赖 Mac 当时在线, 但只能看到 Mini 已经收到的内容. 这也使同步成了整个安排里不可省略的一部分.</p>
<h2>多台设备, 怎样读到同一段经历</h2>
<p>我的知识库以 MacBook 为主要编辑源, 普通 Markdown 通过私有 Git 仓库同步到 Mini. 其他需要参与的终端, 也可以沿用同一套版本交接规则. 手机或另一台电脑上的 ChatGPT, 则通过配置好的知识库入口查询 Mini 上的副本, 不要求每台阅读设备都克隆一份仓库.</p>
<p>这里有两件不同的事: 编辑端负责让文件版本一致, 查询端负责找到已经同步的资料. 从手机发出一个问题, 不代表手机正在和 Mac 实时同步整个文件夹.</p>
<p>多端编辑最容易出问题的地方, 往往发生在写入之前. 一台机器忙了一会儿, 另一台也留了几处修改, 如果都只顾着把自己的版本推上去, 那些更晚发生的事情未必就能自然合到一起.</p>
<p>我的顺序因此是先接住别处的变化, 再交出这一端的改动. 接手前确认设备与目录, 保护尚未提交的内容, 拉取远端更新, 再恢复并审查本地修改. 提交之前检查差异, 推送之前再看一次远端. 遇到无法明确处理的冲突, 就停下来, 保留现场.</p>
<p>Git 在这里留下的, 除了副本, 还有一次次修改的来历. 某个结论是什么时候补上的, 为什么后来又变了, 可以回头查. 它不替人判断哪句话正确, 但能保住判断发生过的过程.</p>
<p>原始私有资料另走一条路. 我没有把它们顺手塞进 Git, 而是通过 SSH 加密传输, 单向增量复制到 Mini 的独立私有目录, 不使用删除目标文件的同步选项. 普通笔记同步成功, 不能顺带说这一部分也完成了, 两条链路要分别核对.</p>
<p>在我的私有配置里, 少量明确授权的原始资料也可以从只读入口查询. 这不意味着整台主机的文件都向 ChatGPT 开放, 更不意味着资料仍只留在主机上: 被工具返回的内容会进入对话. 因此, 查询和文章里都不应附带无关的敏感内容.</p>
<p>定时同步只是兜底. 本机关了, 从本机发起的任务就不能照常执行; 网络没通, 也不能把等待误写成完成. 重要变更需要及时同步, 再核对两端的版本或文件结果.</p>
<p>有过一次, Mac 这一端已经推送, Mini 的 SSH 却没有连上. 那次能确认的, 就只能到推送为止. 后来再查询 Mini, 不能因为我记得本机已经改过, 就认定它一定读到了新内容.</p>
<p>同步这件事, 值得的就是这份不含糊.</p>
<h2>于是, 一次工作可以怎样接着往前走</h2>
<p>把这些关系连起来, 实际的便利就具体了.</p>
<p>准备接着做一个旧项目, 可以先让 ChatGPT 从 Mini 的 Wiki 找到上次的决定和未完成项. 回到 Mac 上, 再通过本地工作区读取眼前的代码, 看笔记与现状是否一致. 涉及页面的问题, 则去已有的 Chrome 会话里查看, 或在授权下操作并核对结果.</p>
<p>它们是几段可以配合的工作, 不会仅凭写在一张图上就自动完成. 是否调用了正确的工具, 是否读到正确的文件, 是否确实完成了修改, 都要有结果来回答.</p>
<p>收尾时, 我通常让 Codex 按 Wiki 的维护规则整理新的事实. 审查修改, 提交普通笔记, 同步到 Mini, 再从查询入口确认能找到更新. Mini 的只读工具本身不会替我写回这些内容.</p>
<p>这样, 一次对话里弄清楚的事情, 就有机会成为下一次开工的依据.</p>
<p>少复制一段文件, 少补一张截图, 少解释一次历史. 每一处都不算惊天动地, 合起来却让我更愿意把 AI 放进日常工作. 因为它接触到的材料, 开始与我手边的东西对应起来了.</p>
<h2>窗口仍然很小, 来路却清楚了</h2>
<p>这些连接搭完以后, 我反而更在意一个回答是从哪里来的.</p>
<p>是刚刚读过的文件, 还是旧笔记里的记录? 是浏览器上已经显示的内容, 还是一个没有展开的部分? 是 Mac 上的新版本, 还是 Mini 尚未更新的副本?</p>
<p>看上去只是几个追问. 但能把它们分清, 对话就有了可以落脚的地方. 我们可以检查, 可以更正, 也可以在下一次继续.</p>
<p>屏幕上的聊天窗口仍然不大. 窗口之外, 文件在原来的目录里, 浏览器留着正在看的页面, Mini 上存着慢慢积累的笔记.</p>
<p>我没有把整个工作现场搬进一段对话. 只是为那些需要相遇的东西, 留好了可以找到彼此的路.</p>
<hr />
<p>本文依据截至 2026-09-19 的个人实现与既有验收记录整理, 不代表写作时重新检查了所有主机的在线状态. 私有入口, 账户标识, 具体路径与凭据均已省略. 文中的读写能力指分别授权的工具, Mini 知识库入口保持只读.</p>
]]></content:encoded>
            <author>Aurora</author>
        </item>
        <item>
            <title><![CDATA[我转过头去, 屏幕便起了一层雾]]></title>
            <link>https://blog.auroramaple.com/posts/glance-guard/</link>
            <guid isPermaLink="false">https://blog.auroramaple.com/posts/glance-guard/</guid>
            <pubDate>Sat, 19 Sep 2026 00:00:00 GMT</pubDate>
            <description><![CDATA[给 AirPods 找了一件听歌之外的小事. 从一个让人心动的点子, 到真正跟着转头变化的屏幕, 记下 Glance Guard 的诞生, 校准与那些不肯轻易过去的细节.]]></description>
            <content:encoded><![CDATA[<p>耳机戴在耳朵上, 通常是为了把声音送进来.</p>
<p>有一天, 我却想借它告诉电脑一件事: 我已经转过头去了.</p>
<p>这个念头来自别人分享的一个创意. 看过以后, 我很想在自己的 Mac 上也试一试: 正对屏幕时, 眼前的内容保持清晰; 头慢慢偏开, 离开朝向范围的部分便模糊起来; 再转回来, 画面重新清楚.</p>
<p>不需要另找一个开关. 一个原本就会发生的小动作, 成了电脑能够接住的信号.</p>
<p>后来, 我把自己的实现叫作 Glance Guard, 也把源码放到了 <a href="https://github.com/AuroraNest/Glance-Guard">GitHub</a>. 灵感来自 <a href="https://x.com/bryllim_/status/2099049704822907277">@bryllim_ 的分享</a>, 项目由我独立实现, 仓库里保留了致谢.</p>
<h2>先把一个小念头做出来</h2>
<p>我喜欢这种尺度的项目.</p>
<p>它不必先回答能服务多少人, 也不必给自己安排一个庞大的未来. 只要那个画面确实发生, 我就已经很高兴: 戴着耳机, 转一下头, 屏幕跟着有了变化.</p>
<p>当然, 想象里只是一瞬间的事, 真做起来, 中间还有好几层.</p>
<p>Glance Guard 从兼容 AirPods 的运动数据里取得头部姿态, 再把相对校准方向的偏转, 映射到屏幕上的清晰区域. 它知道的是头朝哪里偏, 并不知道眼睛正盯着哪一个字. 只动眼球, 头没有转, 就不能指望它像眼动追踪那样理解视线.</p>
<p>我没有给它接摄像头. 第一版就围绕头部姿态做, 左右转, 抬头, 低头, 再回到正前方. 先让这几件事有一个清楚的对应关系.</p>
<p>为了不用每改一行代码就戴上耳机重试, 控制面板里还做了模拟模式. 拖动角度, 看屏幕范围怎样移动. 等规则大致走通, 再把它交回真实的动作.</p>
<p>但也正是在这里, 我逐渐发现, 模拟图里看着合理, 和坐在电脑前觉得自然, 还有一段距离.</p>
<h2>我都转开了, 怎么还有一半是清楚的</h2>
<p>最有记忆的一次反馈, 就这么直接.</p>
<p>头已经转开, 人都不再看着那块屏幕了, 它却还留着一片清晰区域. 最初在多屏环境里发现这个问题, 容易以为是屏幕排列出了差错. 后来只用笔记本内屏再试, 同样会发生.</p>
<p>问题便不能再交给副屏解释了.</p>
<p>早先的做法, 是假定一个视距与视野角度, 把头部朝向投影到连续的桌面上. 数学上可以画出一个范围, 可那并不意味着它知道我坐在哪里, 离屏幕多远, 又在什么时候已经完全转开.</p>
<p>系统能告诉程序屏幕的逻辑尺寸和排列. 桌上两块显示器之间真实的夹角, 我的坐姿, 耳机的佩戴偏差, 却不在那张排列图里.</p>
<p>后来, 我们把固定视距的估算拿掉, 换成了更贴近使用感受的校准: 正视参考屏幕, 记住正前方; 转到希望整屏模糊的位置, 再记下这个角度. 达到设定阈值时, 参考屏幕就完整模糊.</p>
<p>左右与上下分别有可调的阈值, 也给自然的小幅晃动留了一点余地. 换了坐姿, 移动了电脑, 就重新校准.</p>
<p>这次修改让我很喜欢. 程序终于不必假装知道一个标准的人应该怎样坐着. 它可以先问问眼前这个人, 再按他的动作来.</p>
<p>多屏仍然更复杂. 同一个清晰区域沿系统排列移动, 并不等于精确识别我正在看哪块副屏. 我把这部分保留为需要继续体验和验证的地方, 没有因为两块屏幕能显示出来, 就把所有摆放方式都算作解决了.</p>
<h2>那层雾, 也不能随便起</h2>
<p>最初的遮罩效果, 我并不满意.</p>
<p>屏幕像被盖了一层灰白的纸, 底下的内容固然不那么清楚了, 颜色和光也一并闷住. 我想要的高斯模糊, 应当还能看出原来画面的色调, 只是细节柔和地散开.</p>
<p>于是又回去改显示方式. 用 ScreenCaptureKit 取得屏幕画面, 交给 Core Image 做高斯模糊, 再让模糊图像与真实桌面沿边缘渐变衔接. 控制面板上的 Liquid Glass 是另一回事, 我没有拿它来代替桌面本身的模糊.</p>
<p>这里还有一个很容易忽略的小圈套: 如果把 App 自己的遮罩也截进去, 它就会不断处理自己的上一层结果. 所以捕获时要把自己的窗口排除, 让屏幕画面与覆盖在上面的那层雾各归各位.</p>
<p>为了这个效果, App 需要屏幕录制权限. 图像在本机内存里处理, 不保存, 不上传, 也不采集音频. 暂停以后, 停止捕获并清除图像.</p>
<p>我想做的只是桌面上的一个小变化. 它没有理由顺便替我攒下一份屏幕录像.</p>
<h2>有时, 卡住的是系统对你的认识</h2>
<p>做到这一步, 又碰到一个让人困惑的状况: 设置里的录屏权限明明开着, 程序却仍然被拒绝.</p>
<p>重启过, 开关也切过, 问题没有跟着消失. 后来对照日志与签名, 才发现旧的 ad-hoc 签名会随重新构建的可执行文件变化. 系统保存的授权, 与眼前这一版 App 的身份没有对上.</p>
<p>最后固定安装位置, 使用稳定的 Apple Development 签名, 再单独迁移这个 App 的录屏授权, 捕获才重新正常工作.</p>
<p>写功能的时候, 很容易把注意力都放在屏幕上发生了什么. 真正把一个 App 留在电脑里使用, 才会遇到这些不显眼的事: 它从哪里启动, 更新以后还是不是系统认识的那个程序, 授权还认不认它.</p>
<p>它们不在效果图里, 却决定了第二天还能不能照常打开.</p>
<p>后来那次安装和授权调整完成, 我终于说, 可以了. 那句话很短, 前面却跟着不少次构建, 检查与重试.</p>
<h2>好玩之外, 还得留一条退出的路</h2>
<p>我不希望耳机断连以后, 自己反而对着一块无法恢复的模糊屏幕.</p>
<p>所以数据中断, 手动暂停, 或显示器配置变化时, 都要恢复清晰. 运动数据超过一秒没有更新, 也不继续拿旧姿态维持遮罩. 重新开始, 则需要有效数据与校准.</p>
<p>控制面板和菜单栏里留着暂停入口. 不管正在试什么效果, 总要能把电脑交还给原来的使用方式.</p>
<p>这也决定了它的边界. Glance Guard 是一个跟随头部姿态变化的视觉工具, 模糊不能代替锁屏. 大字和图像仍可能被辨认, 它也不阻止其他程序截屏. 真要离开座位, 我还是会锁上电脑.</p>
<p>后来, 我们还试着减少捕获画面的尺寸和刷新频率, 降低图像处理的负担. 那部分先留在本地迭代里, 没有拿理论上的像素减少比例当作 CPU 实测成绩, 也没有把它写成公开版本已经兑现的性能承诺.</p>
<p>一个效果能出现, 是第一步. 愿不愿意让它一直开着, 还要留给更长一点的日常来回答.</p>
<h2>把它放出来, 让别人也能试试</h2>
<p>源码已经公开, 使用 MIT License:</p>
<p><strong><a href="https://github.com/AuroraNest/Glance-Guard">AuroraNest / Glance-Guard</a></strong></p>
<p>它目前仍是一个原型, 适合愿意自己构建和调试的人. 构建条件与使用步骤以仓库 README 为准, 目前也不是已经公证、下载后即可面向所有人分发的成品安装包.</p>
<p>我尤其想知道, 换一副兼容耳机, 换一种坐姿, 换一套显示器摆法, 它会怎样. 这些真实的差异, 比我继续在自己的桌前猜测更有用. 若愿意尝试, 可以在仓库留下反馈, 分享时记得避开屏幕里的私人内容.</p>
<p>把一个小项目公开, 于我也有一份很朴素的快乐. 一个原本只在自己电脑上发生的动作, 从此有机会出现在别人的桌面上.</p>
<p>耳机仍然用来听歌. 只是偶尔, 当我转过头去, 它还会替我捎一句话给屏幕.</p>
<p>而屏幕轻轻起雾, 等我回来.</p>
]]></content:encoded>
            <author>Aurora</author>
        </item>
        <item>
            <title><![CDATA[为了好好上个网, 我折腾了一整套代理网络]]></title>
            <link>https://blog.auroramaple.com/posts/my-proxy-network/</link>
            <guid isPermaLink="false">https://blog.auroramaple.com/posts/my-proxy-network/</guid>
            <pubDate>Sat, 19 Sep 2026 00:00:00 GMT</pubDate>
            <description><![CDATA[起初只是想好好上网, 看看世界, 安稳地用 AI. 后来, 从手机里的一串节点到家里的软路由, 我花了几个月, 才让这件日常的小事慢慢安静下来.]]></description>
            <content:encoded><![CDATA[<p>我希望打开电脑的时候, 可以直接去做想做的事.</p>
<p>读一篇文章, 查一份资料, 看看别处的人正在关心什么. 或者把手头卡住的问题拿去和 AI 商量, 话说到一半, 不必停下来研究那个迟迟不动的加载圆圈.</p>
<p>好好上网, 看看世界, 再稳定、安全地用 AI. 最初想要的, 大致就是这些. 后来 AI 渐渐成了每天要用的工具, 我对网络也就多了一份认真: 住宅 IP, 稳定的出口, 还有大家常说的"不降智", 都在我的考虑里. 一个 IP 无法保证模型每次都聪明, 我能做的, 是先把自己这段连接照料好.</p>
<p>谁知, 为了省下日后打开电脑时的那一点麻烦, 我先花了几个月.</p>
<p>手机里的节点, 家里的软路由, 公网网关, 远端的住宅出口, 一样样接起来, 又一样样检查. 当时做的时候只觉得琐碎, 现在回头看, 才发现自己已经走了这么远.</p>
<h2>那些看上去都像网络不好的日子</h2>
<p>最初, 我很自然地把问题归给线路. 这条不稳, 再添一条; 那个服务不好用, 给它单独加几条规则. 手机用 Shadowrocket, 电脑用 Clash/Mihomo, 路由器上还有自己的配置.</p>
<p>每次改动都有理由. 日子一长, 却越来越难说清它们合在一起, 究竟怎样工作.</p>
<p>同一个服务, 手机上正常, 电脑上不正常, 得先确认两边是不是同一份规则. 一台设备更新了订阅, 另一台还在用旧配置. 列表里有一个节点, 不代表自动模式真的会选它. 看见一个延迟数字, 也不能说明业务请求走的是自己以为的出口.</p>
<p>这类问题最烦的地方, 是看上去都像网络不好.</p>
<p>有一次, 客户端把线路测成了 timeout, 实际请求却能通. 查下来, 测速使用的探测地址并不能可靠代表那条线路的可用性. 换掉探测地址后, 那个红色的 timeout 才消失.</p>
<p>还有一次, 服务端和订阅都核对过了, 手机仍然表现不对. 最后重启了一下客户端, 恢复了. 具体是哪一层旧状态没有刷新, 当时没有继续拆, 但至少不用再去改服务器.</p>
<p>类似的小事多了, 我才发觉, 真正磨人的还有那份不确定. 一次请求没有回来, 面前却摆着那么多可能. 我需要知道它经过了哪里, 而不是再凭运气换一个节点.</p>
<h2>先把去向理清</h2>
<p>于是, 我开始把主要的出口选择收回到服务端. 频繁变化的部分, 尽量在一个地方维护.</p>
<p>客户端保留自己该处理的直连和拒绝规则, 比如局域网, 内网互联, 以及明确不需要代理的请求. 需要进入代理的部分, 尽量交给统一网关. 网关再决定普通流量从哪里出去, 哪些请求必须进入指定出口链.</p>
<p>下面把实际机器和线路名称都换掉了, 只保留关系:</p>
<pre><code>手机 / 电脑 / 路由器
  ├─ 直连规则 → 设备所在网络
  ├─ 拒绝规则 → 停止连接
  └─ 代理规则 → 公网网关
      ├─ 普通流量 → 网关出口
      └─ 指定流量 → 住宅出口候选链
          ├─ 可用 → 出口 A / B
          └─ 全部不可用 → 停止连接
</code></pre>
<p>这里的住宅出口, 就是流量最终从住宅网络出去. 它只是我选择的一种出口条件, 不代表某个服务一定放行, 也不能替代账号本身的安全措施.</p>
<p>理清这一层以后, 修改服务端的出口规则, 终于不用再往手机, 电脑和路由器里各抄一遍. 客户端仍然各有要做的事, 但最容易变化的那部分, 总算有了确定的归处.</p>
<p>手动选出口的入口我也留了. 自动模式负责平时用, 固定出口负责排查. 出问题时能够钉住某一条路径, 比反复点一个含糊的 Auto 有用得多.</p>
<p>改造没有直接拿原来的服务开刀. 我们先起了独立的试验入口, 验证请求能走通, 再逐步切换. 即便如此, 还是踩到了很朴素的坑: 新入口的防火墙没放行, 客户端当然怎么测都是 timeout. 另一次是配置文件权限收得太紧, 检查时用的用户能读, 实际运行服务的用户读不了.</p>
<p>看过许多协议的说明, 最后仍要回来检查一条防火墙规则, 一个文件权限. 做网络的耐心, 有一部分就是这样练出来的.</p>
<h2>接上家里的 Wi-Fi, 就能继续</h2>
<p>软路由是这套网络里离日常最近的一环.</p>
<p>公网网关负责后面的出口选择, 家里的这台设备则站在更前面. OpenWrt 上运行 Mihomo, 通过透明代理接住需要处理的流量, 按规则决定直连还是送入代理. 接到这张 Wi-Fi 的设备, 可以把这一部分工作交给它, 不用每台都先打开客户端, 再各自选一遍节点.</p>
<p>我想要的便利很小: 手里从电脑换成平板, 注意力还留在正在读的东西上. 网络在后面接着做它的事, 不必每次都出来打招呼.</p>
<p>但让它不打扰人, 需要先做不少细活.</p>
<p>曾经查到, 平板的云同步被兜底规则送进了代理. 还有一次排查音乐跳歌, 发现相关请求缺少直连规则, 连 DNS 得到的 CDN 去向也与直连路径不协调. 这时只改一个代理开关不够, 得把域名分流与解析策略一起理顺, 再看新连接实际去了哪里.</p>
<p>后来, 国内域名的直连规则也在软路由上补齐, 对应的 DNS 策略一并对齐. AI 的指定出口规则保留在前面, 需要直连的日常服务各走自己的路. 那些看似不起眼的先后顺序, 决定了接入这张 Wi-Fi 以后, 每一次请求怎样离开家里.</p>
<p>改动时, 我们先检查配置, 再热加载, 必要时清理受影响的旧连接, 最后核对新请求命中的规则. 没有动不动就重启整台路由器. 这样处理, 才能分清变化来自刚才的修正, 还是旧连接恰好断了.</p>
<p>软路由替设备省下了操作, 也把更多责任集中到了自己身上. 一条写得太宽的规则, 影响的就不止一个客户端. 所以我对它的要求, 渐渐从能用, 变成了能解释清楚为什么这样用.</p>
<h2>两台设备, 四条路</h2>
<p>家里这一端理顺了, 请求还得走到远端. 那里的连接, 也有自己的脾气.</p>
<p>我先用了 Tailscale, 后来又加上独立的 WireGuard 隧道, 把主要的数据传输放到 WireGuard 上, 同时保留 Tailscale 这条路. 当时做过同一对机器之间的对照测试, WireGuard 在其中一个单流方向上更有优势. 这个结果足够支持我调整自己的链路, 但也只说明那次测试的情况.</p>
<p>真正让我重新考虑备用路径的, 是一次 WireGuard 握手长时间不再更新.</p>
<p>机器没重启, 没找到内存耗尽, 网卡掉线或者代理进程崩溃的证据. 两端重启隧道后, 连接又恢复了. 当时也不是忘了配 keepalive, 它本来就在.</p>
<p>这很像 UDP 会话或 NAT 状态出了问题, 但没有足够证据把原因钉死在路由器或运营商身上. 我能确定的只有: 主机还在, 服务还在, 这条路径却已经不能正常用了.</p>
<p>那次故障还暴露了另一件事: 我以为已经留好的后路, 没有如期接住连接.</p>
<p>回头查配置, 才重新弄清探测列表, 候选集合与 fallback 的关系. 健康检查观察到一条线路, 并不代表当前选择器会使用它. 我曾经把出现在文件里的名字, 当成了已经备好的退路.</p>
<p>后来整理出来的顺序是这样的:</p>
<table>
<thead>
<tr>
<th>优先级</th>
<th>候选路径</th>
</tr>
</thead>
<tbody>
<tr>
<td>1</td>
<td>出口设备 A, 经独立 WireGuard 隧道</td>
</tr>
<tr>
<td>2</td>
<td>出口设备 A, 经 Tailscale 网络</td>
</tr>
<tr>
<td>3</td>
<td>出口设备 B, 经独立 WireGuard 隧道</td>
</tr>
<tr>
<td>4</td>
<td>出口设备 B, 经 Tailscale 网络</td>
</tr>
<tr>
<td>最后</td>
<td>全部不可用时停止连接</td>
</tr>
</tbody>
</table>
<p>四条路径并不是四条完全独立的宽带. 前两条仍然依赖同一台设备和它所在的网络, 后两条也是. 同一台机器断电, 换一条隧道救不了它; 整个住宅网络断了, 也一样. 我保留两种连接方式, 是想覆盖一部分路径故障, 再用另一台出口设备覆盖另一部分故障.</p>
<p>Tailscale 这条路径也不等于每次都经过中继, 它可能直接连接, 也可能借助 relay. 我关心的是它能不能提供一条可用的替代路径, 以及最后有没有从指定的出口出去.</p>
<p>最后做逐级故障注入时, 我们用的是隔离的 Xray 实例. 依次让前面的候选不可用, 核对 TCP, UDP 的路由标签和响应, 直到最后的阻断. 正式入口还分别验证了各条路径, 自动模式也确认命中了主路径.</p>
<p>测试的最后一步, 是确认所有候选失效以后, 连接会停下来. 对于明确要求住宅出口的请求, 我宁愿看见一次失败, 也不希望它悄悄换个出口, 留给我一张仿佛正常的页面.</p>
<p>做到这一步, 我才对备用路径多了一点底气. 隔离测试当然还不能代替日后真实的断电与断网, 但至少那条写在配置里的顺序, 已经逐级走过了.</p>
<h2>也有亲手搭起, 又亲手拆掉的东西</h2>
<p>中间我还自建过 Tailscale 的 DERP.</p>
<p>当时觉得这很顺手: 既然已经有自己的服务器, 中继也由自己维护, 整套东西应该更可控. 后来碰到跨 tailnet 分享设备的场景, 才发现这里有一条很具体的限制.</p>
<p><a href="https://tailscale.com/docs/reference/derp-servers">Tailscale 官方文档</a>写明, 自定义 DERP 不支持 device sharing 等跨 tailnet 功能. 我当时又移除了默认的官方 DERP 候选, 相当于在这个场景下把本来能用的选择也拿走了.</p>
<p>最后删除了自定义中继映射, 恢复官方中继候选, 设备重新连通. 自建服务, 证书同步和相关规则也一起清理了.</p>
<p>拆的时候, 难免想起搭它花过的时间. 但留下来, 也不能替当初的投入多挣回什么. 清理完服务与规则, 重新确认连接, 这件事就算过去了. 后来再看, 少维护一处, 也是那段折腾留给我的收获.</p>
<h2>页面之外, 还有没有走完的检查</h2>
<p>TCP 好测. 打开一个页面, 发一个请求, 看看响应就有了直观感觉. UDP 比较容易被漏掉, 尤其是 WebRTC 用到的 STUN 流量.</p>
<p>有一次检测页上的出口结果不一致, 我们继续查真实连接, 发现不同 STUN 请求没有走同一类出口: 一部分进了住宅路径, 另一部分从网关直接出去了.</p>
<p>看到两个地址的时候, 不能直接认定本地真实地址泄露了. 那次查到的是代理链内部的出口不一致. 对我的规则要求来说, 它依然需要修, 只是不能把两件事混在一起.</p>
<p>后来把相关 STUN/TURN 请求也收进了指定出口策略, 再用实际 UDP 请求确认路由. 那条四级候选链, 因此也必须把 UDP 单独测一遍.</p>
<p>备用设备的 Tailscale 路径还遇到过一个更细的坑: SOCKS 的 UDP 返回地址, 在分享设备的场景里并不适合另一侧直接使用. TCP 能通, 掩盖不了这个问题. 最后给这条路径换了适合当时条件的承载方式, 再把 TCP 和 UDP 各自验过, 才把它算作可用候选.</p>
<p>现在写下来, 不过几句话. 当时却要在不同机器之间来回核对, 把一个请求送出去, 再去另一端找它的踪迹. 许多所谓稳定, 就藏在这些不太好讲得有趣的检查里.</p>
<h2>账单记得的事, 日志未必记得</h2>
<p>另一类很有记忆点的问题, 是流量突然涨得特别快.</p>
<p>前面提到的平板云同步, 就是在查实时连接时找出来的. 后来还发现, 内网互联工具自己的部分通信也绕进了代理, 平白多走一层. 改好规则, 再观察连接与流量的变化, 这类问题尚有清楚的来回可看.</p>
<p>但不是每次都能查清楚.</p>
<p>有一段流量增长, 等开始调查时, 大流量连接已经结束了. 当时的日志没有留下足够的字节记录. 能看到某台设备开过什么程序, 也能看到某些连接, 但没办法据此把过去那一大段用量准确算到某个下载头上.</p>
<p>这段时间, 我也补上了持续的用量统计, 按使用主体归并, 把不同协议的计数收进来. 同一个人换出口, 不应该在账上凭空变成另一个人. 进程重启导致计数归零, 也不能把之前累计的用量一起抹掉.</p>
<p>这件事让我对那些漂亮的用量图表多了一点耐心. 账要从有可靠记录的那一刻算起. 过去没有留下的字节, 不会因为今天画出一条曲线, 就重新有了去处.</p>
<h2>后来, 网络慢慢安静下来</h2>
<p>这套东西里面确实用了不少组件: Xray, sing-box, WireGuard, Tailscale, 再加上手机, 电脑和路由器上的客户端. 真正省心的部分, 是后来一点点理清的关系.</p>
<p>哪份配置是源文件, 哪份是发布出来的订阅. 首页节点列表和路由规则分别从哪里来. 自动模式选哪些候选, 手动模式又固定到哪里. 服务端更新之后, 客户端究竟有没有加载到新内容.</p>
<p>早先节点列表和规则文件混在一起, 刷新一下就可能又冒出一组重复节点. 后来把这两部分拆开, 分别维护. 发布时也开始核对本地文件, 服务器文件和实际订阅响应, 而不只看上传命令有没有报错.</p>
<p>把这些关系一点点理清以后, 日常反而没有那么多值得说的事了. 接上 Wi-Fi, 打开文档, 继续和 AI 讨论手里的问题. 那些忙过许久的配置, 终于退到了注意力之外.</p>
<p>我现在依然会看新版本, 也会惦记还能怎么改. 只是不会看到更新就马上替换正在用的核心组件. 真要升级, 得把自己的客户端和 TCP, UDP 路径再跑一遍, 还得确认出口切换和统计没有退回去. 好不容易折腾到能日常用, 不太舍得随手把它弄坏.</p>
<p>偶尔我还是会打开控制台看看. 看请求走在安排好的路径上, 看软路由替家里的设备分清去向. 说实话, 是有一点得意的.</p>
<p>规模不大, 也还有没完全解释清楚的故障. 可从起初对着节点列表挨个尝试, 到现在能够说清一次请求经过哪里, 为什么走这条路, 中断以后又怎样处理, 这段变化是实实在在的.</p>
<p>我把面板关掉, 回到原来想读的文章.</p>
<p>折腾这么久, 想要的无非就是这一刻: 世界在页面那头, 我可以把心思放回它身上.</p>
<hr />
<p>本文依据这几个月的实际配置, 排障和验证记录整理. 机器名称, 地点, 地址, 端口, 账号及访问入口均已省略或替换, 图中只保留架构关系. 文中的测试结果指当时的记录, 不代表持续在线监测.</p>
]]></content:encoded>
            <author>Aurora</author>
        </item>
        <item>
            <title><![CDATA[工作微信在小米上, 我想用 iPhone 回一句]]></title>
            <link>https://blog.auroramaple.com/posts/wechat-between-two-phones/</link>
            <guid isPermaLink="false">https://blog.auroramaple.com/posts/wechat-between-two-phones/</guid>
            <pubDate>Sat, 19 Sep 2026 00:00:00 GMT</pubDate>
            <description><![CDATA[不想为了看一条消息, 总去拿另一部手机. 从通知中继到锁屏回复, 再到语音转文字, 记一次小米工作微信与 iPhone 之间的折腾.]]></description>
            <content:encoded><![CDATA[<p>工作微信放在小米手机上, 平时更常拿在手里的却是 iPhone.</p>
<p>事情不大, 麻烦也很具体: 想知道工作微信有没有新消息, 就得再看一部手机. 要是只是回一句收到, 也要把它拿过来, 解锁, 找到会话, 输入, 再放回去.</p>
<p>两部手机各有各的用途, 我并不想把它们合成一部. 只是那些短短的消息, 如果能在手边先看见, 能回的顺手回掉, 应该会省心不少.</p>
<p>于是有了 WeChat Relay.</p>
<p>名字很直白, 就是一段中继. 工作微信仍然留在小米上, iPhone 上另有一个接收和回复的入口. 这里说的工作微信, 是我用来处理工作的普通个人微信, 不是企业微信; iPhone 上的入口也是独立的 PWA, 不会把这些消息写进 iPhone 自己的微信聊天列表.</p>
<p>这个区别从一开始就得说清楚. 我想解决的是手边能不能接住一条消息, 没打算再造一个完整的微信.</p>
<h2>先让消息过来</h2>
<p>最早做的事情, 是在 Android 上监听微信通知.</p>
<p>消息来了, Relay 取得系统通知里可以读取的内容, 在手机端加密, 经过自托管服务转交, 再由 iPhone 端解密显示. iPhone 的网页入口添加到主屏幕后, 像一个单独的小应用那样打开, 会话和消息都放在里面.</p>
<p>这条路不用 Root, 也不是把微信的整个聊天数据库搬到另一台手机上. 它从通知出发, 因而也带着通知本身的限制. 微信没有发出通知的内容, 不能指望这边凭空知道; 过去没有接到的历史, 也不会因为今天配对好了就自动补齐.</p>
<p>我给它的第一份期待很低: 来一条, 能看见一条, 知道是谁说的.</p>
<p>真正做起来才发现, 提醒响了, 和正文出现在眼前, 居然是两件事.</p>
<p>有一阵子, iPhone 已经收到提醒, 打开页面却不见新内容. 后来又碰到另一种情形: 人就停在会话详情里, 新消息仍然不往下追加, 得再点一次系统通知.</p>
<p>我当然不愿意一直这样用. 都已经打开聊天页了, 还要绕出去点个提醒, 总觉得差了一口气.</p>
<p>排查过程中, 有一次问题出在我们自己的限流上. 页面同步, Android 上传与回复查询, 几种正常请求挤进同一个过紧的限额里, 反而把自己挡住了. 后来把流量的用途分开, 配合前台会话的更新机制与重试处理, 提醒和正文才逐渐接上.</p>
<p>这些事在架构图里只占一根箭头. 在手机上, 却是一次次发消息, 等待, 点开, 再问一句: 这回到了没有?</p>
<h2>看见以后, 总想顺手回一句</h2>
<p>能看消息以后, 回复就成了最自然的下一步.</p>
<p>iPhone 上写下的文字同样先加密, 经过服务端交给小米. Android 优先借用原始微信通知仍然有效的快捷回复能力, 把内容送回微信. 原来的通知还在, 这条路就比较直接.</p>
<p>可手机日常不会永远停在最配合的状态. 通知可能失效, 屏幕可能锁着, 微信界面也可能与刚才不同. 代码里写了发送, 不代表对面的人真的收到了.</p>
<p>为了自己的这台小米, 我们又做过一段明确开启才会使用的辅助功能实验: 在限定条件下操作手机上的微信, 完成回复, 再把设备恢复到原来的锁屏状态.</p>
<p>这段花了不少工夫. 曾经卡在系统锁屏控件的识别上, 也曾经把文字写进输入框, 却没等界面状态跟上就急着往下走. 修这些问题, 靠的不是多点几次发送, 而是把每一步真正完成的条件弄清楚.</p>
<p>那次最终验收, 我们看了两次锁屏回复的过程, 也确认了实际收件. 消息出去以后, 手机重新锁回去, 屏幕熄下来. 到这里, 才觉得一句简单的回复终于走完了它该走的路.</p>
<p>但这条实验路径仍有我不愿省略的一处风险: 当时的微信版本没有暴露可用的会话标题文字, 标题复核未能保留, 因而存在误发到错误会话的可能. 我的设备上试通了, 不代表适合让别人不加判断地照搬, 更不适合把重要消息放心交给它盲发.</p>
<p>日常能用与到处都能用, 中间还隔着许多不同的手机和界面.</p>
<h2>语音过来了, 可我想知道它说了什么</h2>
<p>文字之后, 自然就遇到了语音.</p>
<p>如果 iPhone 只显示一个语音提示, 我仍然得去拿小米听. 于是又想往前挪一点: 能不能借微信自己已有的转文字, 把结果带过来?</p>
<p>我们最后走的就是这条路. 新语音进入队列, Android 找到对应的那条消息, 调用微信原生转文字. PWA 先收到语音提示, 有了结果以后, 再把文字补到原来的会话里. 传过来的是转写文本, 不是录音文件.</p>
<p>其中有一段很绕. 微信明明已经把字显示在屏幕上, 辅助功能却拿不到文字节点. 后来增加了受限的复制读取过程, 只接收这一次操作刚产生的文字, 不拿旧剪贴板里的东西凑结果.</p>
<p>可第一次能复制, 还没算结束. 转写如果被放进一个新会话, 我仍然要猜它来自谁; 同一条通知短时间重复上报, 就可能冒出两份消息; 列表一滚动, 还得确认正在处理的依然是原来那条语音.</p>
<p>于是又一项项收拾: 去重, 保住发送方和原任务的关系, 等列表稳定, 等长按完成, 再去找复制按钮. 文字很长, 就分段同步. 微信自己转文字失败, 就如实显示失败.</p>
<p>最后, 单条语音的这条路跑通了, 我也确认过可以使用. 连续很快地发多条, 仍然可能卡住, 这个限制没有被一句已经完成抹掉. 目前我接受它作为一个自用工具的不足, 没把它当成语音原样同步的替代品.</p>
<h2>图片和聊天记录, 各有各的过法</h2>
<p>图片也试过几条路.</p>
<p>最初能看到的是聊天气泡的截图预览, 清晰度不够. 后来尝试打开大图再截图传过去. 这里得到的仍然是手机画面的截图, 不能因为点过查看原图, 就把传出的截图叫作原始文件. 长图与不同页面状态, 也还有各自的限制.</p>
<p>旧预览在手机上看到了, 后来的大图方案还没走完从小米到 iPhone 的确认过程. 所以眼下想认真看一张图, 尤其是图里有小字的时候, 我还是会回到原来的微信里打开.</p>
<p>别人合并转发过来的聊天记录, 又是另一回事. 只收到聊天记录四个字, 和真正看见里面的内容, 差得很远.</p>
<p>最后这类卡片借用微信原生转发, 送到事先准备、接收端账号也在其中的中继群里. 普通消息继续在 PWA 看, 完整聊天记录去接收端微信的那个群里看. 这条路径已经有过真机成功反馈.</p>
<p>听起来不够统一, 但它保留了内容原本适合的查看方式. 我宁愿多一个明确的入口, 也不想在 PWA 里放一张看似完整、实际点不开的卡片.</p>
<h2>消息经过服务器, 正文不留在那里</h2>
<p>既然是工作消息, 我不愿意为了少拿一部手机, 就在服务器上多攒一份明文聊天.</p>
<p>消息和回复在两端用 AES-256-GCM 加密. 服务端负责保存密文, 必要的路由信息与推送订阅, 再把它们送到对应设备. 解密后用来阅读的缓存留在接收端, 这一点也要与服务端的密文存储分开理解.</p>
<p>做这种中继, 最重要的几件事都不太显眼: 这条消息属于哪个配对, 回复要回到哪一条原通知, 处理失败以后能不能再试, 结果不明时会不会重复发送.</p>
<p>尤其是最后一件. 对方没有回话, 并不能据此断言刚才的消息没发出去. 所以发送结果不明的任务, 不能为了追求一个绿色的完成标记就自动重发.</p>
<p>人每天使用聊天软件, 几乎不会专门想这些问题. 自己做一小段以后, 才知道一句话在两台设备之间来回, 有多少地方需要认真对待.</p>
<h2>也给工作消息留一个暂停键</h2>
<p>把工作微信接到 iPhone 上, 是为了少些来回操作. 我并不想因此把工作消息接进每一个时刻.</p>
<p>后来, 设置页加了手动暂停和每周重复的暂停时段, 按中国标准时间计算. 服务端负责最后的转发门禁, Android 收到规则后, 也会在入口停止相关处理.</p>
<p>这套设计里, 暂停期间的新消息不会在恢复后补发. 如果只是把它们攒起来, 到点再一股脑送过来, 那份清静也就只借来了一会儿. 原来的微信仍然在小米上, 真要查看, 可以回到那里.</p>
<p>这套规则已经部署, 不过 iPhone 上的手动切换, 以及暂停时真有消息进来会怎样, 还留着几项真机检查. 在它们逐一确认以前, 这个暂停键还算不上完全收工.</p>
<p>对我来说, 能够接过来, 和能够暂时不接, 都属于这件工具该有的分寸.</p>
<h2>现在, 两部手机之间少了一点距离</h2>
<p>项目已经开源: <strong><a href="https://github.com/AuroraNest/wechat-relay">AuroraNest / wechat-relay</a></strong>.</p>
<p>它仍然是自托管原型, 配置和使用限制都在 README 里. 不同手机系统, 微信版本, 通知样式和锁屏状态会影响结果. 特别是辅助功能实验, 不能把我这一台设备上的成功当作通用保证.</p>
<p>但回到最初那件小事, 它已经带来了很具体的方便: 工作微信还放在小米上, 我却可以在手边的 iPhone 查看同步过来的文字, 在可用的路径里回复, 也能接住一部分语音转写.</p>
<p>两部手机没有变成一部. 只是原来横在中间的那些动作, 少了一些.</p>
<p>为了少拿几次手机, 我写了一个项目, 又花了好些时间处理通知, 队列, 锁屏和微信界面. 算起来大概不划算.</p>
<p>可当一条消息在 iPhone 上出现, 我顺手回完, 不用再去找另一部手机的时候, 还是会觉得, 嗯, 就是想要这个.</p>
]]></content:encoded>
            <author>Aurora</author>
        </item>
    </channel>
</rss>