大家好,我又来了。
本来以为写完第七章的性能优化,这个系列就该画个句号了。但本着"贼不走空"的极客精神,我又在源码的 src 目录下瞎溜达了一圈。
结果,在一个叫 src/buddy/ 的隐秘角落里,我挖到了 Anthropic 工程师们藏的一个惊天大彩蛋------他们居然在一个硬核的 CLI 效率工具里,偷偷塞了个电子宠物(Buddy)系统!
你想啊,在这个枯燥的命令行世界里,当你每天被满屏的报错、跑不通的单测折磨得想砸键盘的时候,如果终端角落里能有一只专属于你的、独一无二的小鸭子或者小恐龙陪着你,是不是瞬间就觉得没那么烦躁了?
今天咱们就当个番外篇,不聊什么高深架构,纯粹用扒一扒代码的方式,看看牛啤工程师们的浪漫是怎么写进代码里的。
源码里藏着什么好玩的?
翻开 src/buddy/ 目录,你会发现他们不仅写了个彩蛋,还真把它当成个微型 RPG 游戏在做:
- 看看他们是怎么用伪随机数生成器(PRNG)来搞"抽卡"的。
- 看看为了防作弊(防止玩家改配置刷极品宠物),他们是怎么设计"骨肉分离"的数据结构的。
- 甚至为了躲开代码扫描工具的误伤,他们是怎么给宠物种类名字"加密"的。
1. 抽卡机制与 Mulberry32 算法
这只小宠物是怎么"生"出来的呢?如果你打开 src/buddy/companion.ts,你会看到一个叫 mulberry32 的函数。
为了保证你的宠物虽然属性是随机的,但只要"种子(Seed)"不变,你每次打开终端它都长得一模一样,他们专门手搓了这个轻量级的伪随机数算法。官方还在注释里调侃了一句:
typescript
// src/buddy/companion.ts
// Mulberry32 --- tiny seeded PRNG, good enough for picking ducks
// 翻译:"足够用来抽鸭子了" 😂
function mulberry32(seed: number): () => number {
let a = seed >>> 0
return function () {
a |= 0
a = (a + 0x6d2b79f5) | 0
let t = Math.imul(a ^ (a >>> 15), 1 | a)
t = (t + Math.imul(t ^ (t >>> 7), 61 | t)) ^ t
return ((t ^ (t >>> 14)) >>> 0) / 4294967296
}
}
他们把你的账号 ID 或者本地标识(userId + SALT)哈希处理后当做 Seed。这意味着什么?
这意味着从你用 Claude Code 的那一刻起,你的这台电脑、这个账号,注定只会孵化出那只命中注定的宠物。
2. 稀有度、属性与"闪光"设定
玩过抽卡手游的兄弟们都知道,SSR 有多难出。Anthropic 的工程师们把这套拿捏得死死的。
在 src/buddy/types.ts 里,我看到了完整的概率表(RARITY_WEIGHTS):
- Common(普通): 60%
- Uncommon(罕见): 25%
- Rare(稀有): 10%
- Epic(史诗): 4%
- Legendary(传说): 1%
宠物甚至有五维属性:DEBUGGING(调试)、PATIENCE(耐心)、CHAOS(混沌)、WISDOM(智慧)、SNARK(毒舌)。
稀有度越高,属性的保底值就越高。而且,每次生成必定有一个巅峰属性和一个拉胯的"下水道"属性。
最离谱的是,他们还加了个类似宝可梦的"闪光(shiny)"机制,只有可怜的 1% 概率触发:
typescript
// 只有不到百分之一的欧皇能拿到闪光宠物
shiny: rng() < 0.01,
3. 防作弊设计:骨肉分离的"灵魂"
既然属性这么难抽,那我直接去改本地配置文件(config.json),给自己捏个"闪光传说级"宠物不就行了?
抱歉,你想到的,工程师早想到了。
他们把宠物的数据拆成了两半:CompanionBones(骨架)和 CompanionSoul(灵魂)。
- 灵魂(名字、性格):是由大模型根据你的属性自动生成的,保存在你的本地配置里。
- 骨架(稀有度、种类、属性、外观) :从来不保存! 每次启动时,它都会严格根据你的
userId重新计算一遍。
源码里是这么写的:
typescript
// src/buddy/companion.ts
// What actually persists in config. Bones are regenerated from hash(userId)
// on every read so... users can't edit their way to a legendary.
// 翻译:骨架每次读取时从哈希重新生成,这样玩家就没法通过改配置来刷传说宠物了。
这波操作,直接把想作弊的黑客们按死在了起跑线上。
4. 为了躲避扫描,连物种名都加密了
在看物种列表时,我发现了一段极其诡异的代码。普通的数组定义不写,非要用 String.fromCharCode 把字母一个个拼出来:
typescript
// src/buddy/types.ts
const c = String.fromCharCode
export const duck = c(0x64,0x75,0x63,0x6b) as 'duck' // 鸭子
export const octopus = c(0x6f, 0x63, 0x74, 0x6f, 0x70, 0x75, 0x73) as 'octopus' // 章鱼
为什么要这么搞?注释里给出了答案:
- 原来他们内部有一个"敏感词扫描"工具,用来防止代码里泄露正在研发的 AI 模型代号(codename)。
- 结果很不巧,某个宠物的名字跟内部未发布的模型代号撞车了!
- 为了不让扫描工具天天报假警,工程师干脆把所有的宠物名字都在运行时动态拼装,绕过了静态扫描。
- 这真是一个被逼出来的机智操作啊!
最后:这才是工程师的浪漫
看完整个 src/buddy/ 模块,我确实被这帮老外圈粉了。
在一个承载着巨量代码、复杂的 AST 解析、深度的 MCP 协议的硬核效率工具里,在一个每天都在卷性能、卷大模型智商的环境下,他们依然愿意花时间写这么一套对核心功能毫无帮助、却趣味拉满的代码。
可能它只是终端里一只戴着高顶礼帽、长着星星眼的 ASCII 小鸭子,但它确实能在某个深夜,给那些对着屏幕抓头发的程序员们,带来一丝会心的微笑。
这,大概就是写代码最纯粹的乐趣吧。
开源
我自己也做了一个桌宠,还在迭代中:
CodeWalkers:让 AI 助手化身桌面宠物,陪你敲代码的赛博伙伴!
源码地址:github.com/you-want/Co... 欢迎给个 Star ✨。
