Hi, 我是 W10N

这里主要是我的日常记录——周记、工作复盘和一些随笔。另外我也收集整理了一些技术资料,可从顶部导航「转载」「整理过的」查看。

Switching Cursor Pro to The X Subscription: Cursor 老用户的首年折扣

我之前订阅的是 Cursor Pro,每月 20 美元。2026 年 10 月 12 日,X 推出了统一订阅(The X Subscription),把 X Premium、Grok(SuperGrok)和 Cursor 合到了一个订阅里。我把 Cursor Pro 转成了统一订阅的 Premium 档。 同样是 Premium 年付,从 Cursor 那边转过去,首年约 16 美元/月;直接在 X 或 grok.com 上订,是 25 美元/月。这是给 Cursor 老用户的首年折扣,从 X 那边看不到。 为什么要换 我想要 X 的蓝 V(Premium checkmark),用来推广自己的产品 ENX。 写代码我主要用 Claude 的订阅,Cursor 用得不多,所以统一订阅里 Cursor 不包含 Claude 用量这一点,对我影响不大。 原来 Cursor Pro 一年 240 美元,统一订阅 Premium 年付原价 300 美元,多 60 美元,多出来的是 SuperGrok 和 X Premium+ 的权益。 统一订阅的档位 X 页面(x.com/i/premium_sign_up)上的年付价格: ...

Created 16166-10-16 · Updated 16166-10-16 · 2 min · 321 words · -

Doubao IME Voice Input: 语音输入后自动切回英文输入法

问题 我平时在 macOS 上停在英文 ABC 输入法。豆包输入法 开了「跨输入法启用语音」后,在任何输入法下都能用快捷键唤起豆包的语音输入,我设置了两个键: 模式 快捷键 用途 按住说话,松开结束 Fn 短句 按一下开始,再按一下结束 右 Option 长段 唤起时豆包会把系统输入法切到豆包拼音,语音结束后不会切回来。接下来打字就是中文,每次都要再按一下切回 ABC。 我想要的效果是:语音输入结束后自动回到唤起前的输入法。豆包当前版本没有这个选项,所以用 Hammerspoon 补上。 第一版:监听按键(不成功) 最直接的思路是监听快捷键:按下时记下当前输入法,结束时切回去。 Fn 模式:松开即结束,不用记状态 右 Option 模式:数按键次数,按单数次记下输入法,按双数次切回 写好后按 Fn 测试,没有切回。在脚本里加了日志才看出两个问题。 Hammerspoon 没有辅助功能权限 日志里 hs.accessibilityState() 一直是 false。权限要在「系统设置 → 隐私与安全性 → 辅助功能」里开,不是左侧栏顶层那个「辅助功能」(那里是 VoiceOver、缩放这类功能)。 开了之后还是 false,原因是 macOS 的这个权限只在进程启动时生效。我在设置里关了再开、删掉再加回来都没用,Hammerspoon 一直是开权限之前启动的那个进程。退出 Hammerspoon 再打开后,权限才变成 true。 豆包把 Fn 吞掉了 权限正常以后,Control、Caps Lock、右 Option 都能在日志里看到,Fn 一次都没有出现。我又用 hs.eventtap.checkKeyboardModifiers() 轮询 Fn 的按下状态,按住 Fn 说话的整个过程中也一直读到未按下。 所以豆包在更底层把 Fn 拦截了,Hammerspoon 拿不到这个键的任何信息,靠按键判断的方案走不通。右 Option 倒是能收到,但切换模式要数按键次数,如果用 Esc 或鼠标结束语音,计数就会错位。 ...

Created 15156-10-15 · Updated 15156-10-15 · 3 min · 455 words · -

CNB: Cloud Native Buildpacks 与 Paketo

是什么 Cloud Native Buildpacks(常缩写 CNB)是一套把应用源码或编译产物自动打成 OCI 容器镜像的规范与工具生态,站点在 buildpacks.io。思路类似早年 Heroku、Cloud Foundry 上的 buildpack:平台检测你推上来的是什么(Java jar、Node 项目等),自动选运行时、装依赖、写好启动命令,不必为每种语言手写 Dockerfile。 Paketo(paketo.io)是 CNB 生态里常用的开源实现,提供现成的 builder 镜像和一系列 language buildpack(Java、Node.js、Go、Python 等)。它与 Spring 无隶属关系,但 Spring Boot 的 bootBuildImage / spring-boot:build-image 默认使用 Paketo 的 builder。 CNB ← 规范 + 生态(buildpack / builder / lifecycle) │ ├── Paketo ← 开源实现(Spring Boot 默认路径) ├── Heroku buildpacks └── Google Cloud buildpacks … 调用方: pack CLI、Spring Boot 插件、Tekton、CI … → 拉 builder → 跑 buildpack → 出 OCI 镜像 Spring Boot 侧如何把 fat jar、分层 JAR、jlink 与 Buildpack 串起来,见 Spring Boot Container Packaging。 ...

Created 21216-06-21 · Updated 12126-10-12 · 3 min · 589 words · -

ENX Mark Known: 从等待接口改为乐观更新

背景 enX 的 Chrome 扩展会给查过的生词画下划线。主窗口点一个词会弹出浮层,浮层里有 Mark Known(标为已认识)按钮,点了之后这个词的下划线消失。 后来侧边栏的整句翻译也加上了同样的下划线(ADR-053),于是有了一个新问题:在主窗口标为已认识之后,侧边栏里这个词的下划线也应该一起消失。 原来的做法 content script → background → POST /api/mark → enx-api 写库 ↓ 成功 content script 收到回复 → 去掉主窗口下划线 主窗口要等接口成功才去掉下划线,侧边栏完全不知道这件事。 改成什么样 content script:先去掉主窗口下划线 └─ runtime.sendMessage({ type: 'markAcquainted', word }) ├─ 侧边栏:收到后立即去掉下划线,不回复 └─ background:调 enx-api,完成后回复 content script 两点变化: 主窗口先改界面,再让 background 在后台调接口,也就是常说的乐观更新(optimistic update),和它相对的是原来那种等服务端确认再改界面的做法。 侧边栏不需要新的通道。chrome.runtime.sendMessage 从 content script 发出时,会投递给扩展里所有监听 runtime.onMessage 的页面,background 和侧边栏都能收到。侧边栏只需要多注册一个监听。 为什么可以先改界面 标为已认识失败的代价很低:服务端没记上,用户下次读别的文章时这个词还会带下划线,再标一次就行。为了这个小概率的失败让用户每次都等一个网络往返,不划算。 如果改成「background 调接口成功后再通知侧边栏」,状态会更严格一致,但侧边栏要多等一个接口的时间。对这个操作来说,一致性没有那么重要。 多个接收方只能有一个回复 runtime.sendMessage 允许多个页面监听,但发送方只会收到第一个调用 sendResponse 的回复,其余的被忽略。侧边栏如果也回复,会抢在 background 前面,content script 就看不到接口的真实结果了。 ...

Created 12126-10-12 · Updated 12126-10-12 · 1 min · 95 words · -

2026 W38-W41

临近国庆节,节奏有点乱。有四周没写周记了,W38 到 W41 合成一篇。这四周的主线还是 enx:给它取了个名字叫 Catglish,部署生产环境。最近在准备提交 Chrome Web Store,提交之前得再调整一轮 UI。 Catglish W37 里纠结的名字,最后用了 Catglish。网站和 Chrome 扩展上的名字都改成了 Catglish,仓库名还是 enx,等上线之前再找时间改。 W38 主要在调细节。跟 AI 一起重新做了一遍配色,统一了各个组件的颜色 token。在颜色这件事上,AI 比我专业多了。周五 Claude Code 赠送的 100 美元额度第二天就要过期,那两天开着 Opus 改了很多东西,也第一次往生产环境部署了一个版本。 W39 在补生产环境的链路。部署流水线从 GHCR 加 SSH 换成了 ECR 加 SSM,机器调整成 t3a.small。扩展的内容脚本改成按需注入,不再在每个页面上都注入。周五集中做了一次依赖版本升级:Next 16、Vite 8、TypeScript 6。E2E 测试改成用真实的登录流程跑。 W40 是国庆: 网站上加了 Beta 标记和 GitHub 链接 加了定价页;现在的配额都是内测阶段的数字,跑一段时间再定上线时各个等级的额度 除了按月订阅,也可以一次性付款购买 AI 积分 本地词典查不到的词,可以调用 AI 生成释义 收藏页面,以及按站点设置「在这个网站上自动开启」 另外加了 Prometheus 监控指标,homelab 和生产环境的监控面板都接上了。 W41 打好了 0.1.0 Beta 的扩展包,画了个 logo:一个带猫耳朵的 C。 ...

Created 9096-10-09 · Updated 9096-10-09 · 1 min · 173 words · -

IIT Filing: 企业法人个税申报

一人公司法人申报个人所得税的操作备忘。记录网页版扣缴端的零申报步骤。相关背景见 一人公司。 网页版 入口:国家税务总局电子税务局 → 自然人电子税务局。 打开上述网站,进入自然人电子税务局 用法人的个税 App 扫码登录 在菜单里找「单位办税」,选择公司,进入扣缴端 进入「综合所得申报」,选择税款所属月份(上一个月) 「收入及减除填写」→「正常工资薪金所得」→「填写」→ 添加法人本人,本期收入填 0,保存 「税款计算」→ 附表跳过 →「申报表报送」→「发送申报」 「获取反馈」,显示申报成功,应缴 0,不用缴款 在「扣缴申报 → 查询统计 → 单位申报记录查询」可以核对每个月的申报记录 公司没发工资、没有分红,也要每月零申报。征期是每月 15 日前,节假日顺延。 过程中的提示 未填写正常工资薪金所得:申报表一行数据都没有。上月的数据不会自动带过来,每个月都要在「正常工资薪金所得」里重新添加本人 未填写专项附加扣除,请确认是否漏填或确实不想享受:选确认。收入为 0,不影响税额,专项附加扣除可以在年度汇算时享受 未填写三险一金,请确认是否继续:选继续。公司没有代缴社保和公积金 全年一次性奖金、年金等其他所得项都不用填,只填正常工资薪金 Windows 版 (待补)

Created 2026-09-02 · Updated 8086-10-08 · 1 min · 37 words · -

2026 W37

这周主要在给 enx 取名字。另外 enx 接了 DeepSeek,HomeLab 的 CI/CD 加了缓存,在 YouTube 上新建了一个产品频道。 enx:取名字 enx 一直是开发代号,要做成产品发布,得有一个正式的名字。取名字是最不重要、也最纠结的一件事。 这一周一直在纠结叫什么。想了好多名字,一个个去查域名和商标,大部分都和现有的软件或者商标冲突:有的域名已经被人注册了,有的已经注册了商标,用了会有法律风险。 最后在仅有的几个不冲突的名字里来回纠结,周六选了一个,注册了域名。 enx:开发 新功能不多:Reader 页面,可以把一段英文粘贴进来阅读、查词;从浏览器扩展里发起登录,登录完会自动回到原来的页面。 另外还做了一些细节上的小调整和优化。 UI 和 API 的提示文案全部改成了英文。用这个工具的人本来就在学英文,UI 上简单的英文应该不是问题; MiniMax 的订阅过期了,DeepSeek 的账户里还有余额,所以给 enx 加了一个 DeepSeek 的 provider,HomeLab 上切到了 DeepSeek。HomeLab 是测试用的,对后端用哪个模型不是特别敏感。 HomeLab:CI/CD 提速 最近一直在测 enx,频繁调细节,也频繁往 HomeLab 上部署,CI/CD 跑的时间就成了一个比较明显的问题。 这周优化了一下:加了缓存,加了 Nexus 私有仓库。npm 和 Go 的依赖走 Nexus 代理,镜像构建的缓存也放在 Nexus 里,依赖没变的时候可以跳过安装依赖那一步。 YouTube:两个频道 打算拍一些东西放到 YouTube 上,比如 enx 的安装/使用演示, 宣传视频, 这周在准备拍摄方案,周六在自己的 YouTube 账号下新建了一个产品频道。 注册 YouTube 账号之后本来就会有一个默认的频道,每个注册用户都有,只是大多数人没有往里面发过视频。我的默认频道就当个人频道用。同一个账号下面还可以再新建别的频道,这一点我也是这周才知道的,算是一个新发现。 这样一个账号下面就有了两个频道。个人频道放我自己的内容,比如 HomeLab 的改造、有可能的未来的房车旅行,也许会有美食类的视频,主要是个人记录。产品频道只发产品相关的内容。个人频道是全集,跟 enx 相关的视频会同时发到两个频道。 ...

Created 14146-09-14 · Updated 14146-09-14 · 1 min · 90 words · -

macos apps

macOS Apps 跨平台常用软件统一维护于 my apps,本文只记录 macOS 专属工具。 说明 brew — brew install <name> cask — brew install --cask <name> Essentials 跨平台工具见 my apps,以下为 macOS 专属推荐: app install notes iterm2 cask:iterm2 功能强大的 terminal stats cask:stats 任务栏系统资源监控 itsycal cask:itsycal 任务栏日历(显示周数) tunnelblick cask:tunnelblick OpenVPN GUI 客户端 Logi Options+ cask:logi-options-plus Logitech 键鼠配置工具 Ice cask:jordanbaird-ice@beta 菜单栏图标管理、隐藏与分组 KeepingYouAwake cask:keepingyouawake 菜单栏咖啡杯,防止系统休眠 Input Method app install notes 豆包输入法 — AI 语音输入,详见 豆包输入法 Squirrel(鼠须管) cask:squirrel RIME 引擎输入法,详见 Squirrel(鼠须管) brew install --cask doubao 安装的是豆包 AI 聊天客户端,不是输入法。 ...

Created 5056-05-05 · Updated 13136-09-13 · 2 min · 236 words · -

2026 W36

enx:认证从 Cognito 换成了 Clerk,单词高亮换成了浏览器原生的 Highlight API。 enx:认证从 Cognito 换到 Clerk 当初选 Cognito 的原因是,那会儿在聊一个职位,对方公司用 Java 技术栈,也用 AWS。我想让自己更熟悉 AWS 和 Java 一些,所以 enx 选型的时候选了 Cognito,还给 enx 加了一个 Java 后端。 那个职位后来没有 Offer,见 W33。 这周把认证换成了 Clerk。换的原因是 Clerk 和 Google 登录集成得更好一些,另外它同时支持 Google 和 GitHub 两种登录。网页端和扩展的会话也能同步。两端手写的 OAuth 客户端一起下线,Cognito 那套基础设施也删掉了。 enx:单词高亮换成浏览器原生的 Highlight API 有天晚上碰到思科的前同事 Roc,聊了一会儿,发现自己的前端知识实在太匮乏了。页面上点一下要查的词,其实可以用鼠标的坐标反查到点中的是哪个词,不需要像之前那样预先改 DOM、把所有词都拆开包起来,也不用挂那么多 onClick。 以前的做法就是把匹配到的单词用元素包起来,再给这个元素加样式。这样会改动页面的 DOM,在结构复杂或者会自己重绘的页面上容易出问题。 这周换成了 CSS Custom Highlight API:高亮范围用 Range 描述,交给浏览器渲染,不再往页面里插元素。点击查词改成在容器上做事件委托,用 caretPositionFromPoint 定位点到的是哪个词。 顺带把两件事拆开了:「阅读时高亮生词」和「点击查词」现在是两个独立的开关,可以只启用其中一个。X 上切换推文时正文是原地替换的,加了自动重建。Playwright 的用例按新的实现重写了一遍。 周六:大黑石 周六老婆公司团建,在大黑石的海边烧烤,她带着女儿去了。女儿下午有英语课,我中午开车去大黑石的沙滩接她们。 据说,小朋友到了沙滩就想去海边,饭都不吃了。一开始还在岸边挖沙子,后来看妈妈下水游泳,她也要下水。下水之后就不想走了,用老婆的话说是 “血脉觉醒”。 上次带她去海边是在广鹿岛,那时候她还只是在浅水里捡海星和贝壳。 路边为啥要栽这么多树… 开车去大黑石的路上,偶尔过桥的时候能看到远处的山,景色还不错。其余大部分时间视线都被路两边的树挡着,开多久,窗外都是一样的树。 ...

Created 7076-09-07 · Updated 7076-09-07 · 1 min · 82 words · -

2026 W35

这周主要是 enx 的开发:接入 Stripe,以及上线前的一些细节调整。 enx:接入 Stripe 订阅加积分这套方案是上周那份规划里定下来的,这周把它落进代码。 周三一天,enx 里多出了一整套计费:积分账本、Stripe 的 webhook、配额、结账和账单管理入口,网页端加了定价页和账单页,扩展这边加了积分不足和需要升级的提示。方案之前讨论过,这次是把方案细化,然后由 AI 生成代码。 同一批改动里还补了一组单元测试,账本、webhook、配额、结账处理各有一份。补测试的原因是接入 Stripe 之后要开始新一轮测试,而现有代码的单元测试覆盖太小,先把底子补上。 接下来是测试。 订阅之外加了一次性充值包 周四改了一次访问规则。 前一天定的是:AI 翻译必须有订阅才能用,不能靠单独充值绕过。第二天推翻了,改成账户里有积分就能用,不限来源,订阅发放的积分和一次性购买的积分包都算。 改的原因是有了一个新想法,可以开放一次性购买的充值包。按月订阅并不是所有人都愿意,月费也不好定太高,一次性的充值包是个补充。 代价是前一天已经写进代码的那条校验现在是错的,得删掉。项目还在开发中,随时都会有变化,这些变化都是正常的。 内网域名换成 wiloon.lab wiloon.com 是公网域名,homelab 内部之前也用它,只是在内网解析。但 DNS 分流上遇到了问题,所以内网改用 wiloon.lab,专门给 homelab 用。 这周把 enx 的内网访问切了过去。 公司账本:把方法固化成一个仓库 上周写过决定自己记账,用 beancount,AI 出数、人工复核。这周把它做成了一个仓库。 促成这件事的还有几点。找代账公司有沟通成本;在 twitter 上看到有人用 AI 处理公司的账目,我也想试试;另外公司现在没有业务,都是零申报,应该不复杂。有代账公司打电话过来,我跟他们说的也是自己先试试,实在不行再找专业人士。 仓库里放的是科目表模板、余额断言、季度增值税和年终结账两份 SOP,以及法定报表的字段映射。另外把几个常用动作做成了 Claude Code 的 skill:开票申请、季度报税、出报表、报税准备。 上周是决定自己记账,这周是把记账做成一套可以重复执行的流程。 homelab 杂项 kubectl 的 logs 和 exec 一度用不了,加了一个 ClusterRoleBinding 修回来,交给 ArgoCD 管理。 路由器那边把 IPv6 的 WAN 口改成了静态接口,之前记录过的前缀委派丢失问题走到了这一步。 监控补了一批采集配置。 blog 这周写了三篇:mktemp、DuckDB,以及微信扫码查看与下载 PDF。另外给 SQLite 那篇做了修订。 ...

Created 30306-08-30 · Updated 30306-08-30 · 1 min · 83 words · -

2026 W34

这一周几乎没碰键盘。带娃在老家待了五天,只有她午睡和晚上睡了之后,才有一点时间做自己的事。 从鞍山到老四平 上周从大连出发,在鞍山住了一晚,周一走下半程。 去程走的是国道,这天改走高速。四岁的娃也感觉出来国道太慢了,是她要求走高速的,条件是全程系安全带,她答应了。 到老四平已经是下午,太阳落了山。她还是要去菜园子,非开着手电筒去摘菜。 奶奶家在一个小镇上,房子前后都有菜园子,房子后面是一条铁路,经常有火车轰隆隆地开过去。从小在城市里长大的娃,对这里的一切都新奇。 周二天一亮她又冲进菜园子,拉着奶奶东看西看,摘各种蔬菜,收获满满。 小公园 周三去了老家附近的一个小公园。 爷爷奶奶本来打算当个景点看一眼就回家,中午外面太热。没想到娃对什么都新奇,跟小树小草玩起来就不肯走了。有荷花池,有草地,有树林。 亲戚家的动物 周四去亲戚家看小动物。 老姨家养了羊,还有鸡、鹅和鸽子。娃见了鸽子,就掏出车上的玉米去喂。家里养的鸽子和城市里的广场鸽不一样,星海公园的鸽子只要见了玉米就成群结队地下来吃,家里的鸽子完全没有这个概念。据说每天下午五点才是它们觅食的时间。 又去了二舅家,二舅妈刚卖菜回来。他们也有菜园子,平时吃不掉的菜拿到市场上卖。暖棚里有葡萄,也有各种菜。临走时二舅从鸡窝里掏了一些鸡蛋,给我们带上。 娃拿到鸡蛋,第一个问题是:这个鸡蛋能孵小鸡吗? 我们解释了好一会儿,得有鸡爸爸和鸡妈妈,蛋才能孵出小鸡。她大概是因为亲眼看见鸡蛋是从鸡窝里掏出来的,才会觉得它能孵小鸡。平时从市场买回来的鸡蛋,看不到母鸡的影子,也就不会有这样的联想。 早上跑步 我每天早上跑步。老家在内陆,中午三十几度,早晚凉快,跑步只能放在早上。 小镇上很少有人把跑步当成锻炼。老年人有打太极的,有做操的,有跳广场舞的,跑步的很少。所以 Keep 的地图上,老四平一条跑步路线都没有。上次回来我开发了一条 2 公里的,这次又开发了一条 4 公里的。路上车不多,早上跑起来很舒服。 不方便的是跑完一身汗,洗澡不方便。家里没有独立的卫生间,厕所是旱厕,只能用湿毛巾擦一擦。 回大连 周五开车带娃和奶奶一起回大连。 在大连是姥姥姥爷和爷爷奶奶轮班过来帮忙带娃,这次刚好赶上换班的周期,带娃回老家,顺便把奶奶接过来。 她自己编的一个故事 周六上完英语课,我们坐在外面的长凳上休息,娃自己编了一个故事。 有一只小象,在大森林里走着走着,遇到一张蜘蛛网。网上有两只蜘蛛,一只蜘蛛国王,一只蜘蛛王后。蜘蛛王后会变成老奶奶的模样,骗小象进蜘蛛网,没有成功。后来小象打败了蜘蛛国王和蜘蛛王后,把它们装进了垃圾袋。 正讲到这里,飞过来一只麻雀,落在附近的地上。她接着说:后来来了一只鸟,把垃圾袋叼走了,用嘴啄那个蜘蛛国王和王后。 这个故事的来源能对上。上周回老四平,路上无聊的时候给她讲过孙悟空三打白骨精,白骨精先变成一个姑娘,再变成老奶奶,最后变成老爷爷。另外最近买了 Switch 2 上的《世界游戏大全 51》,和她玩过里面的国际象棋,国际象棋有国王和王后。她把三打白骨精的情节、国际象棋的棋子,还有当时飞过来的那只鸟,编进了同一个故事。 我帮她把这个故事做成了连环画,下次再找时间生成一个动画片。 还是要多带她去看不同的东西,接触各种各样的事物。她会把见过的、经历过的重新排列组合,变成自己的认知。 项目 这周项目上基本没有进展,只有她午睡和晚上睡了之后才有一点点时间。 在老家这几天不碰键盘,倒是想清楚了一件事。enx 这个项目我断断续续做了很久,一直是自己在用。做了这么久,如果最后没有真正上线,我会有遗憾。所以暂时不找工作,接下来一段时间集中精力把它部署上线。 2026 W34,老四平 — 大连。

Created 30306-08-30 · Updated 30306-08-30 · 1 min · 48 words · -

2026 W33

面试结果 上周那场第二轮面试,周二有了结果:职位不匹配。 从 4 月离职到现在同事/朋友帮推过三家公司。一家给了 offer,薪资太低,拒了;一家没有下文;这一家前后聊了四个月,两个岗位都进了二面,都没有 offer. 这一家前后接触了一位 HR 和八位面试官。感觉得出来,有的是希望我加入的,也有的对我有疑虑。anyway,最终的结论是职位不匹配。 接下来先测试 enx 独立商业化的可行性:把功能做完、部署到 AWS、接上 Stripe 订阅,先在 YouTube 和 X 上推(因为只做了 google 账号登录),看能不能有几个付费订阅用户;跑不通的话就再找工作。 enx: 划词翻译 之前选中一个短语会走词典查询,而后端判定"包含空格就是句子",直接返回一句"句子翻译功能暂未开放",短语永远拿不到释义。现在改成:选中的如果是句子中间的几个词,侧边栏显示这个短语在整句里的含义。像 “hunt down emails”,三个词单看都认识,放进上下文里是什么意思才是要查的。 另外给三个翻译 provider 各补了单测。 enx:上线还差什么 周三花了一天,把 enx 距离上线还差哪些事情列了一遍,写成两份文档,一份是商业化设计,一份是任务清单。 先定义什么叫"上线":在生产环境上,真实用户可以注册、登录、订阅、使用 AI 翻译、被限流、退订,这条链路全部跑通,才谈得上开始推广。 顺序定成三步。先在现在这套 homelab 环境里把订阅功能做完、测通,不用等基础设施迁移——然后把跑通的功能迁到 AWS。最后在生产环境完整跑一遍端到端冒烟测试,作为发布门禁。 几条已经定下来的: 计算平台继续用 EC2,不上 ECS 或 EKS。EKS 控制面每月的固定成本,在验证付费意愿这个阶段不划算 上线时数据库继续用 SQLite,先不迁 PostgreSQL。现有链路已经跑过,上线门槛越低越好,数据库迁移不是订阅功能的前置依赖 域名不换。Cognito 的 callback、CORS、证书、扩展权限都已经围绕现在这个域名配好了 全部开源,包括计费规则,继续用 AGPL-3.0 最后一条想得比较久。最初担心闭源可以防止别人用 AI 抄产品,后来推翻了:闭源只能防直接复制代码,防不了照着功能用 AI 重写一遍,而后者才是真正的风险,源码可不可见对它基本无效。定价和免费额度这些数字,用户用一遍产品就能观察到,藏代码也藏不住。真正让我决定开源的是另一件事——找工作这条退路还在,一个有真实用户、有测试和 ADR 的开源项目本身就是求职作品集,这个价值闭源换不来,而闭源换来的那点"防护"本来就是假的。 局域网域名的一秒延迟 周五在准备 enx 的测试环境,发现局域网里的域名访问都带着一段很规律的延迟。查下来是 IPv6 的 DNS 问题。 ...

Created 16166-08-16 · Updated 16166-08-16 · 1 min · 176 words · -

2026 W32

广鹿岛:彩虹滩赶海 上周末坐船去了广鹿岛。 周一换了个海滩,去彩虹滩赶海。这次出来玩时间赶得不错,退潮都在傍晚 6 点左右,太阳快落山,正好是一天里凉快下来的时候。海滩很浅,可以往前走很远,靠岸这一段脚下都是细沙,沙滩上有很多海葵,寄居蟹更是数不过来。再往深处走,细沙变成礁石,海草也多起来,水到膝盖左右。 四岁的女儿一路捡,寄居蟹、螃蟹、各种贝壳,把整个桶底铺满了。后来我们在海草附近捡到一只海星,她立刻把桶里的螃蟹和寄居蟹全倒回海里,整个桶只装这一只海星。 海星带回了民宿。到晚上它大概是缺氧,开始往桶外爬。我们商量了一下,还是放回去吧,不然会死掉。于是又把海星送到离住处最近的海里。 赶海的时候一边拍照一边让 AI 识别,认识了海葵和鱿鱼的卵鞘。海葵挺有意思,拿铲子碰一下,它整个身体缩进沙子里,同时喷出一股海水。鱿鱼的卵鞘在滩上到处都是,半透明、软软的、圆圆的一团。 周三从广鹿岛回大连。在杏树港下船之后是我开车,女儿自己坐安全座椅,全程走国道没上高速——小朋友随时可能需要我,国道方便停车。过几周我要单独带她去爷爷奶奶家,这次算是一次 dry run。 enx:遮阳伞下的 side panel 周二在岛上找了家有泳池的酒店,女儿和妈妈在泳池里泡了一下午。我没带泳衣,就在遮阳伞下写码。 这周 enx 主要在开发句子翻译的 side panel。 后端给三个翻译 provider 都加上了「按句子上下文翻译单词」的能力,配了对应的 handler 和路由,每个 provider 补了单测。前端这边,侧边栏里点击单词后的展示从单行文字改成了卡片。 卡片这块反复改了几版。一开始词、音标、上下文含义、查询次数分四行堆着,太占纵向空间,改成一行内排列、放不下才折行;有道词典的外链也删掉了,侧边栏就这么宽;「Query Count」几个字重复出现太啰嗦,换成一个放大镜图标,原文字挪到 title 属性里做悬浮提示。 加载方式也调了。以前是词典查询和 AI 上下文翻译两个请求都回来才一起渲染,现在点击的时候就先插入一张骨架卡片,两个请求各自返回后只更新自己那部分。词典那边通常更快,音标和释义会先显示出来。列表按点击时间倒序排,重复点同一个词不再发请求,只把已有的卡片挪到最前面。 第二轮面试 周三从广鹿岛回来,在杏树港排队驶出停车场的时候接到了 HR 的电话。是第二轮面试的邀请,安排在周五下午,30 分钟,听起来会是全英文。 当天下午要带娃上课,距离面试还有一天多准备时间。上一次面试因为一直在看 Spring 的资料,没准备自我介绍,英文的自我介绍讲得不太好,这次得准备一下;剩下的主要是怎么用英语把简历上的经历说清楚。周四一整天和面试当天的白天,基本都在准备这些。 周五当天出了个小插曲。我之前很少用 zoom,16:20 就打开了,输会议号、输密码、调整摄像头和麦克风,然后等面试官上线。等到 16:27 还没看见人,才注意到窗口右下角有一个 join 按钮——原来我一直在会议外面 -_- 赶紧点了 join,发现两位面试官已经在线了。 面试过程还算顺利。我的英文不是特别好,中间有问题没听清楚就麻烦面试官再讲一遍,对方会很友好地放慢语速重复。有些问题答得还好,也有因为准备不够没能表达清楚的。面试官也问到了个人项目,我讲了 enx,说计划部署到 AWS 上,或许能帮到其他人。 快结束的时候我还纠结了一下,要不要解释一句我其实一直在会议外面等着。但这么复杂的句子,我的英文暂时还撑不住,就直接 say goodbye 了。

Created 9096-08-09 · Updated 9096-08-09 · 1 min · 62 words · -

2026 W30-W31

这两周的周记合成一篇。 enx:先把功能做完,上线再说 enx 是我自己的项目,一个查词加翻译的 Chrome 扩展。这两周它是主线。 前一周主要在部署链路上:调查词性能(SQLite 相关的调整、给 words 表加索引的 migration),构建时把 version 注入镜像,Go API、Java API 和 UI 三条镜像链路陆续跑通,部署到 homelab。 后一周是功能推进: 合入本地 ECDICT 词典,查词路径不再依赖外部接口 单词弹窗迁到 React + Shadow DOM,样式不会再被宿主页面污染 加了句子翻译的 Side Panel,翻译后端做成多 provider(MiniMax、Bedrock、Kimi),用 factory 加 handler 分派 修扩展的 session 超时问题,Cognito 那边改成手写刷新逻辑 周六在岛上想清楚一件事:微信登录先不做了。现在已经有 Google 登录,把 Stripe 接上就可以上线部署。把基本功能做完先上线,不需要等到完美。 一个朋友的文档校验工具 之前写过的、给一位朋友做的文档校验工具,这两周继续往前走。 前一周主要是仓库骨架落地:架构 ADR、几个模块的 Spec、测试,周末开始写 Web UI 的 SDD 和 lint 配置。后一周把它部署进了测试环境。 另外这个项目按正常的需求分析、报价流程走一遍。因为如果以后真的在线接单,报价是绕不开的问题,正好拿它测试一下。 starlabrys 官网 公司官网这两周加了历史项目展示页,还有一个 Site Advisor 的雏形,包括意图识别、知识库、tools 和对话几个部分。ew8 帮我改的那部分周五合并进来了。 w_dashboard:一个玩具级的仓库看板 周末起了个新项目 w_dashboard,Linux 端用 Rust 加 Slint,macOS 端用 Swift 加 SwiftUI,两端各写了一版初版。 ...

Created 2026-08-02 · Updated 2026-08-02 · 1 min · 130 words · -

linux apps

Linux Apps 跨平台常用软件统一维护于 my apps,本文只记录 Linux 专属工具。 说明 pacman — sudo pacman -S aur — yay -S apt — sudo apt install Essentials 跨平台工具详见 my apps,以下是 Linux 上的安装命令速查: app source notes kitty pacman terminal neovim pacman 编辑器 flameshot pacman 截图+标注 bitwarden pacman 密码管理 btop pacman top 替代 wechat aur visual-studio-code-bin aur VSCode 官方二进制版 Browser Ubuntu install Chrome curl -O https://dl.google.com/linux/direct/google-chrome-stable_current_amd64.deb sudo apt install ./google-chrome-stable_current_amd64.deb Terminal app source notes termite pacman 支持 32 位色 Text Editor app source notes mousepad pacman 轻量文本编辑器 nixnote2-git aur Evernote Linux 客户端 Screenshot / Recording app source notes spectacle pacman KDE 原生截图 simplescreenrecorder pacman 录屏 gtk-recordmydesktop aur 录屏 shutter aur 截图,需配合 perl-goo-canvas System Monitor app source notes ncdu pacman/apt 命令行磁盘空间分析 netdata pacman 系统资源监控 indicator-sysmonitor apt 任务栏系统资源监控 nethogs pacman 网络流量监控 dstat pacman 查看系统性能 dstat -cdlmnpsy slurm aur 网络监控 hardinfo-git aur 硬件信息查看 System Info app source notes fastfetch pacman 打印发行版 logo neofetch pacman/apt 系统信息(已停止维护) stress pacman 压力测试 hdparm pacman 磁盘参数查看 procmon aur 微软的进程监控工具 File Management app source notes filelight pacman 图形化磁盘空间管理 baobab apt 硬盘占用分析工具 catfish pacman 文件搜索 tree apt 树形目录显示 tree -L N nautilus apt Ubuntu 默认文件管理器 Archive / Compression app source notes ark pacman KDE 压缩包管理器 file-roller pacman zip/7z/rar 支持 rar/unrar apt Media / Graphics app source notes digikam pacman KDE 最佳图片管理 gwenview pacman KDE 图片查看 eog apt Eye of Gnome 图片查看 okular pacman PDF reader gpick pacman 颜色拾取工具 Remote Desktop app source notes chrome-remote-desktop aur Google 远程桌面主机 remmina pacman GTK 远程桌面客户端 freerdp pacman remmina RDP 支持包 rdesktop pacman Development Tools app source notes base-devel pacman 编译工具链 lsof pacman hexyl pacman 彩色 hex 编辑器 lrzsz pacman zmodem binutils pacman 二进制文件处理工具集 inetutils pacman telnet 等网络工具 kotlin pacman glow pacman 命令行 markdown 预览 Fonts app source notes ttf-wqy-microhei apt 文泉驿-微米黑 ttf-wqy-zenhei apt 文泉驿-正黑 xfonts-wqy apt 文泉驿-点阵宋体 ttf-consolas-with-yahei-powerline-git aur Consolas+雅黑 ttf-wps-fonts aur WPS 字体依赖 KDE sudo pacman -S powerdevil kmix kscreen ark gwenview kcolorchooser app source notes powerdevil pacman 电源管理,休眠按钮 kmix pacman 音量调节 kscreen pacman 多显示器管理 kcolorchooser pacman 颜色拾取 KDE Widget name notes netspeed widget 网络监控 resources monitor CPU/内存监控 Plasma Week Number 显示周数 Virtualization app source notes kvm pacman wine pacman 需开启 Multilib 仓库 playonlinux pacman Wine 图形前端 podlet aur podman 辅助工具 Utilities app source notes rsibreak pacman 番茄钟 gnome-shell-pomodoro apt Pomodoro pavucontrol apt Chrome 音频输出设置 sl pacman 小火车 x11-apps apt xclock, xserver 测试用 pamac-aur aur 图形界面的 pacman libiconv aur 编码转换 Ventoy — 各种 ISO 安装盘引导工具 References Arch Linux List of Applications 维护记录 时间 修改内容 原因 2026-07-28 Development Tools 表格补充 glow(命令行 markdown 预览工具) 新增常用软件

Created 5056-05-05 · Updated 28286-07-28 · 2 min · 404 words · w10n

2026 W29

从 HashMap 关联到的 上周说面试复盘整理了一部分,这周继续。blog 里 Java 相关的文档以前记得有些零散,重新整理一下。 HashMap 关联的东西其实挺多的… 先是解决哈希冲突主要的两条路:开链法和开放地址法。链表长到一定程度会转成红黑树,于是又去看了红黑树。哈希值怎么来的又牵出随机数——xorshift、LCG。再往下是 CPU 层面的事:加法/乘法/除法消耗的时钟周期不一样,缓存的空间局部性会直接影响这类数据结构的实际性能。横向看,Python 的 dict、Go 的 map 用的 Swiss Table,思路各不相同。 Swiss Table 这条又牵出 SIMD,还挺有意思的。1997 年的 Pentium MMX 就带了 MMX 指令集,不过只能做整数;AMD 1998 年 K6-2 上的 3DNow! 把单精度浮点加了进来;到 1999 年 Pentium III 的 SSE,才有了独立的 128 位寄存器。早年这套指令主要是拿来做多媒体和图形的。 而 Swiss Table 用 SIMD 一次比对一组控制字节来定位槽位,Go 的 map 后来换成了这个结构——中间隔了二十多年。一个 90 年代末为了跑多媒体加进来的特性,现在被用来加速哈希表的查找。 JVM 这边也一并整理了:HotSpot 的 GC 和 JIT。中间还跑偏去看了下 Linux 的进程调度。 starlabrys:把公司的壳先搭起来 和朋友聊天,有人找到了工作但不太理想,有人还在面试。我之前注册了营业执照,就在想我们是不是可以一起做点什么。 有人建议建一个 GitHub organization,这样想贡献代码的人可以加进来。公司暂时没业务,但有件事是现在就能做的——把官网建起来。 于是注册了域名 starlabrys.com,建了 GitHub org,把仓库和权限用 OpenTofu 管起来,后来又把这部分 IaC 从我自己的配置仓库拆出去,单独放进了 starlabrys-infra。 ...

Created 19196-07-19 · Updated 19196-07-19 · 1 min · 126 words · -

2026 W28

魔法线路的一次重建 我有三条魔法线路,这周状态都不太好:炸掉了一条,另外一条流量超了配额,还有一条延迟很大。索性新建了一条顶上。 配置新线路的过程中,顺带发现之前配的延迟检测不准,干脆一起修了。这一修就牵出一串:kube-prometheus-stack 里 additionalScrapeConfigs 字段名写错了;把 R 线路上的 X 从 split-updown 架构切回了普通方案,本想验证问题是不是出在这个架构上,结果发现并不是;J 线路也重新调了一遍,接进了 Grafana 监控。 本来只是想补一条线路,结果顺手把观测这块积了一阵子的旧账清了一遍。 重新拾起 QuantDinger 重新研究 QuantDinger,顺带整理自己的 enx 项目。 隔了一段时间没跟,上游已经升了很多个版本,还有一次大版本更新——MT5 整个模块被删掉了,看代码仓库,主线现在主要在更新数字货币和股票相关的模块。我跟着更新了指标(indicator)相关的一批代码。 也跑了一单测试,赚了 0.02866,差不多两毛钱——这也算是有正向现金流了 -_-。 面试复盘 上一次面试还没有后续 比起纠结结果,我更想把遇到的问题梳理清楚。已经整理了一部分,下周找时间继续,从 blog 里挖了一些相关的文档再整理一遍,下周接着弄。 女儿的一支舞,和被传染的一家 上周提到女儿在排练一支舞,这周演出了。 她上的是小班,周五这场是幼儿园大班的毕业典礼,小班出了几个小朋友排练了一支舞蹈,去典礼上表演。表演当天她的状态不错——一周前感冒过,到那天体温已经正常一两天,算是在恢复中,只剩一点点咳嗽,不影响跳舞,整支舞完整跳完了。 感冒倒是在家里转了一圈。她把病毒传给了妈妈,周六晚上老婆开始发烧。那天我全天带娃在外面上课、玩,回到家就成了半个病房。我目前还好,没有中招的迹象——但也不敢太乐观。 周日的三件不相干的小事 周日修了三件事,彼此没什么关联,凑巧都在这天: 蓝牙:偶然发现开机后蓝牙不能自动启用,是 Linux 启动过程中的时序问题,调了一下。 时区:为了能在这台机器上用 Claude Code,把时区问题处理了。 tekton-pipelines:把 PodSecurity 放宽到 baseline,是为了能在 homelab 上部署 enx 的 Java API。 两个小工具上的调整 Running page 换了数据源:Strava 的 API 改成了订阅模式,就把数据源换成了 Keep。 装了 Squirrel(鼠须管):macOS 自带的五笔输入法没有造词功能,换成了 Squirrel。

Created 12126-07-12 · Updated 12126-07-12 · 1 min · 66 words · -

COSMIC 桌面环境与 cosmic-greeter

什么是 COSMIC COSMIC(“Computer Operating System Main Interface Components”)是 System76(Pop!_OS 的厂商)用 Rust + iced 从零重写的新一代桌面环境,用来替代 Pop!_OS 之前基于 GNOME Shell 深度定制的 Pop Shell。 Compositor:cosmic-comp,基于 Smithay(Rust 的 Wayland compositor 库),只支持 Wayland,不支持 X11。 UI 工具包:iced(Rust 原生 GUI 库),不依赖 GTK 或 Qt。 特点:内置类似平铺窗口管理器的窗口平铺/浮动切换,风格上介于 GNOME 的简洁与传统桌面(面板 + 应用列表 + 系统托盘)之间。 现状(2026-07):Arch extra 仓库已提供稳定打包(当前 1.2.0-1),可通过包组 cosmic 一次性安装。 KDE Plasma 对比 COSMIC 维度 KDE Plasma COSMIC 实现语言/工具包 C++ / Qt + QML Rust / iced 显示协议 X11 + Wayland 双支持 仅 Wayland(cosmic-comp 基于 Smithay) 项目历史 1996 年至今,成熟度极高 2022 年立项,2024~2025 年逐步稳定,仍在快速迭代 窗口管理风格 浮动窗口为主,插件式支持平铺(如 KWin 脚本、Bismuth) 原生内置平铺/浮动切换,无需插件 可定制程度 极高:几乎每个组件(面板、快捷键、主题、特效)都可深度配置 目前较克制,配置项比 Plasma 少很多,走"够用即可"路线 默认发行版 Kubuntu、openSUSE、Arch 等(无绑定) Pop!_OS(System76 主推,未来默认桌面) 资源占用 中等,特效多时略高 更轻量,Rust 实现 + 无 Qt/GTK 依赖 应用生态 庞大(KDE Applications 套件:Dolphin、Kate、Okular、Konsole 等) 尚在建设中(cosmic-files、cosmic-terminal、cosmic-text-editor 等基础应用刚起步) 主题/外观定制 支持第三方主题、图标包、Global Theme 一键换肤 目前主题选择有限,风格由官方统一把控(类似 GNOME 的"少即是多"哲学) 登录界面集成 SDDM(KWallet 自动解锁等深度集成) cosmic-greeter(greetd),风格与桌面统一,但生态集成不如 SDDM 成熟 适合人群 想要高度自定义、功能全面、多年验证的稳定桌面 想尝鲜 Rust 生态新桌面、偏好简洁一致设计、愿意接受少数功能还不完善 一句话总结:Plasma 是"功能全面、可深度定制"的成熟老牌桌面;COSMIC 是"简洁统一、技术栈新颖"的年轻桌面,目前更适合尝鲜和轻量使用,还不建议完全替代 Plasma 作为主力日常桌面。 ...

Created 12126-07-12 · Updated 12126-07-12 · 3 min · 447 words · -

Hugo + Cloudflare Pages 搭建个人博客

本文记录这个博客的搭建方式,从买域名到发布一个静态站点。技术选型和步骤与本站的实现保持一致。 这套技术栈长什么样 一句话概览:用 Hugo 把 Markdown 编译成静态页面,源码在 GitHub,Cloudflare Pages 连接 GitHub 仓库并在 Cloudflare 侧构建、托管,域名解析和 CDN 也在 Cloudflare。 各部分的分工: 组件 作用 Hugo 静态站点生成器,把 content/ 下的 Markdown 编译成 HTML GitHub 存放源码,作为部署的触发源 Cloudflare Pages 连接 GitHub 仓库,执行 hugo --minify 构建并托管产物 Cloudflare DNS 域名解析,把自定义域名指向 Pages 项目 Cloudflare CDN 边缘缓存与加速,Pages 默认自带 整个流程没有用 GitHub Actions,也没有容器化构建,构建这一步完全由 Cloudflare Pages 在它自己的环境里完成。基础站点的构建命令就是一句 hugo --minify;本站为了顺带生成搜索索引,把它包成了一个很短的脚本(见下文进阶模块),思路一样。 基础模块 这一部分从 0 到「能访问」。 买域名 域名可以在任意注册商购买,我最早是在 GoDaddy 买的。以 GoDaddy 为例: 打开 godaddy.com,在搜索框里输入想要的域名,看是否可注册。 选一个后缀(.com、.dev 等),加入购物车,结账。注意第一年常有促销价,续费价通常更高,下单前看清续费价格。 结账时可关掉 GoDaddy 自家的一堆增值服务(邮箱、隐私保护等),后面把 DNS 切到 Cloudflare 后这些大多用不上。 Cloudflare 自己也能直接注册域名(Cloudflare Registrar,按批发价、免费 WHOIS 隐私保护),但支持的后缀有限。如果想要的后缀在它的列表里,直接在 Cloudflare 买、省去后面改 Nameserver 的步骤也可以;后缀不在列表里就按上面的思路在别的注册商买,再把 DNS 切过来。 ...

Created 9096-07-09 · Updated 9096-07-09 · 3 min · 452 words · -

Cloudflare Pages with OpenTofu: 用 IaC 管理 Pages 项目

在 Cloudflare 后台点几下就能建好一个 Pages 项目、绑好域名。想把这些配置变成可版本化、可复现的代码,就用 OpenTofu 来管理。本文只讲 Cloudflare 场景的具体写法,Provider、Resource、State 这些基础概念见 OpenTofu 入门。 目标 用 OpenTofu 声明式地管理三样东西: 一个连接 GitHub 仓库的 Cloudflare Pages 项目(含构建命令、产物目录、环境变量) 项目绑定的自定义域名 指向 Pages 的 DNS 记录 准备 需要两个 Cloudflare 侧的标识和一个 API Token: 变量 从哪来 Account ID Cloudflare 后台任意页面右侧栏,或 Workers & Pages 概览页 Zone ID 域名的 Overview 页面右侧栏 API Token My Profile → API Tokens → Create Token,授予 Pages 编辑和 DNS 编辑权限 Token 属于机密,不要写进代码,用环境变量注入: export TF_VAR_cloudflare_api_token="your-token-here" Provider 配置 terraform { required_providers { cloudflare = { source = "cloudflare/cloudflare" version = "~> 4" } } } variable "cloudflare_api_token" { type = string sensitive = true } variable "account_id" { type = string } variable "zone_id" { type = string } provider "cloudflare" { api_token = var.cloudflare_api_token } Pages 项目 cloudflare_pages_project 对应后台的一个 Pages 项目,source 块声明连接哪个 GitHub 仓库,build_config 对应构建命令和产物目录,deployment_configs 里可以设环境变量(例如 HUGO_VERSION)。 ...

Created 9096-07-09 · Updated 9096-07-09 · 2 min · 272 words · -