1.先讲讲Claude code最近出来的/buddy小宠物,相信大家意见有很多玩家都生成了自己的小宠物 那先介绍一下这个宠物系统原理:

让 AI 分析了claude code泄露的源码(src/buddy/),整个系统分两层:
Bones(骨架) —— 外观、物种、稀有度、属性,全部由 hash(userID + SALT) 确定性生成,不存储在配置中,每次读取时实时计算。
Soul(灵魂) —— 名字和性格,由模型生成,存储在 ~/.claude.json (windows系统一般在C:\Users\用户名称.claude.json)的 companion 字段中。

// src/buddy/companion.ts
const SALT = 'friend-2026-401'

export function companionUserId(): string {
  const config = getGlobalConfig()
  return config.oauthAccount?.accountUuid ?? config.userID ?? 'anon'
}

一共有多少种?

18 个物种:
duck🦆,goose大鹅,blob泡泡,cat🐱,dragon🐉,octopus🐙,owl🦉,penguin🐧,turtle🐢,snail🐌,ghost👻,axolotl蝾螈,capybara水豚,cactus🌵,robot🤖,rabbit🐇mushroom🍄,chonk胖乎乎

5 个稀有度:

稀有度权重概率
★ common 60%
★★ uncommon 25%
★★★ rare 10%
★★★★ epic 4%
★★★★★ legendary 1%
还有 6 种眼睛(· ✦ × ◉ @ °)、8 种帽子、5 项属性(DEBUGGING / PATIENCE / CHAOS / WISDOM / SNARK),以及 1% 概率的 shiny 闪光版。

userID 是什么?

没登录 OAuth 账号的情况下,userID 是首次启动时随机生成的 32 字节 hex 字符串:

// src/utils/config.ts
const userID = randomBytes(32).toString('hex')
saveGlobalConfig(current => ({ ...current, userID }))

它只用于:遥测分析(匿名 device_id)、A/B 分桶、buddy 种子。跟对话历史、API key、本地配置完全无关。 换掉不影响任何东西。
如何重置
编辑 ~/.claude.json(或C:\Users\用户名称.claude.json),替换
2.先用powershell命令安装bun.exe或者node.js(node在上一篇文档中有教下载)

powershell -c "irm bun.sh/install.ps1 | iex"

2.使用buddy-reroll-top.js,用命令node或者bun去运行它,species代表物种,rarity代表稀有度,eye代表眼睛,shiny代表闪光,后面几个参数是找出top5个数值的宠物,然后将这些uid记录到自己的一个记事本或者任意文档中(值得注意的是你安装claude code用的是node安装的话就用node去找对应的宠物uid,不要用bun,不然找出的uid是对不上你这个宠物的,可能是解析字符串的算法不一样,博主亲测,切记)

#!/usr/bin/env node
// buddy-reroll-top.js
// 在原版基础上新增 --top-stats 模式:
//   扫描大量样本,按五项属性总分排序,输出最高的 N 个结果。
//   其余过滤条件(--species / --rarity / --eye / --hat / --shiny)照常生效。
//
// 新增选项:
//   --top-stats            启用 top 模式(按总分排序,替代原来的 --min-stats)
//   --top-count <n>        保留总分最高的前 N 个候选(默认 10)
//
// 推荐用法:
//   node buddy-reroll-top.js --species dragon --rarity legendary --eye ✦ --shiny --top-stats --max 5000000 --top-count 5
//
// 注意:Node.js 使用 FNV-1a hash,结果与真实 Claude Code (Bun.hash) 不同。

const crypto = require('crypto')

// --- Constants ---
const SALT = 'friend-2026-401'
const SPECIES = ['duck','goose','blob','cat','dragon','octopus','owl','penguin','turtle','snail','ghost','axolotl','capybara','cactus','robot','rabbit','mushroom','chonk']
const RARITIES = ['common','uncommon','rare','epic','legendary']
const RARITY_WEIGHTS = { common:60, uncommon:25, rare:10, epic:4, legendary:1 }
const RARITY_RANK   = { common:0,  uncommon:1,  rare:2,  epic:3, legendary:4 }
const EYES = ['·','✦','×','◉','@','°']
const HATS = ['none','crown','tophat','propeller','halo','wizard','beanie','tinyduck']
const STAT_NAMES = ['DEBUGGING','PATIENCE','CHAOS','WISDOM','SNARK']
const RARITY_FLOOR = { common:5, uncommon:15, rare:25, epic:35, legendary:50 }
const RARITY_STARS = { common:'★', uncommon:'★★', rare:'★★★', epic:'★★★★', legendary:'★★★★★' }

// --- Hash ---
function hashFNV1a(s) {
  let h = 2166136261
  for (let i = 0; i < s.length; i++) {
    h ^= s.charCodeAt(i)
    h = Math.imul(h, 16777619)
  }
  return h >>> 0
}

// --- PRNG ---
function mulberry32(seed) {
  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
  }
}

function pick(rng, arr) { return arr[Math.floor(rng() * arr.length)] }

function rollRarity(rng) {
  let roll = rng() * 100
  for (const r of RARITIES) {
    roll -= RARITY_WEIGHTS[r]
    if (roll < 0) return r
  }
  return 'common'
}

function rollStats(rng, rarity) {
  const floor = RARITY_FLOOR[rarity]
  const peak = pick(rng, STAT_NAMES)
  let dump = pick(rng, STAT_NAMES)
  while (dump === peak) dump = pick(rng, STAT_NAMES)
  const stats = {}
  for (const name of STAT_NAMES) {
    if (name === peak)      stats[name] = Math.min(100, floor + 50 + Math.floor(rng() * 30))
    else if (name === dump) stats[name] = Math.max(1,   floor - 10 + Math.floor(rng() * 15))
    else                    stats[name] = floor + Math.floor(rng() * 40)
  }
  return stats
}

function rollFull(uid) {
  const rng = mulberry32(hashFNV1a(uid + SALT))
  const rarity  = rollRarity(rng)
  const species = pick(rng, SPECIES)
  const eye     = pick(rng, EYES)
  const hat     = rarity === 'common' ? 'none' : pick(rng, HATS)
  const shiny   = rng() < 0.01
  const stats   = rollStats(rng, rarity)
  return { rarity, species, eye, hat, shiny, stats }
}

// --- CLI ---
function parseArgs() {
  const args = process.argv.slice(2)
  const opts = { max: 5_000_000, count: 3, topCount: 10 }

  for (let i = 0; i < args.length; i++) {
    switch (args[i]) {
      case '--species':    opts.species   = args[++i]; break
      case '--rarity':     opts.rarity    = args[++i]; break
      case '--eye':        opts.eye       = args[++i]; break
      case '--hat':        opts.hat       = args[++i]; break
      case '--shiny':      opts.shiny     = true;      break
      case '--top-stats':  opts.topStats  = true;      break
      case '--top-count':  opts.topCount  = parseInt(args[++i]); break
      case '--max':        opts.max       = parseInt(args[++i]); break
      case '--count':      opts.count     = parseInt(args[++i]); break
      case '--check':      opts.check     = args[++i]; break
      case '--min-stats': {
        const next = args[i + 1]
        opts.minStatsVal = (next && !next.startsWith('--')) ? parseInt(args[++i]) : 90
        break
      }
      case '--help': case '-h':
        console.log(`Usage: node buddy-reroll-top.js [options]

过滤选项(先缩小范围):
  --species <name>     ${SPECIES.join(', ')}
  --rarity  <name>     ${RARITIES.join(', ')}(最低稀有度)
  --eye     <char>     ${EYES.join(' ')}
  --hat     <name>     ${HATS.join(', ')}
  --shiny              只要闪光

属性排序模式(推荐):
  --top-stats          按五项属性总分从高到低排序输出
  --top-count <n>      保留总分最高的前 N 个(默认 10)

原有模式:
  --min-stats [value]  要求全部属性 >= value(默认 90,legendary 下几乎不可达)
  --count <n>          找到 n 个即停止(默认 3)

其他:
  --max <n>            最大迭代次数(默认 5000000)
  --check <uid>        查看某个 userID 的 buddy

示例(推荐):
  node buddy-reroll-top.js --species dragon --rarity legendary --eye ✦ --shiny --top-stats --max 5000000 --top-count 5
`)
        process.exit(0)
    }
  }

  if (opts.species && !SPECIES.includes(opts.species)) {
    console.error(`未知 species: ${opts.species}\n可用: ${SPECIES.join(', ')}`); process.exit(1)
  }
  if (opts.rarity && !RARITIES.includes(opts.rarity)) {
    console.error(`未知 rarity: ${opts.rarity}\n可用: ${RARITIES.join(', ')}`); process.exit(1)
  }
  if (opts.eye && !EYES.includes(opts.eye)) {
    console.error(`未知 eye: ${opts.eye}\n可用: ${EYES.join(' ')}`); process.exit(1)
  }
  if (opts.hat && !HATS.includes(opts.hat)) {
    console.error(`未知 hat: ${opts.hat}\n可用: ${HATS.join(', ')}`); process.exit(1)
  }
  return opts
}

// --- 打印单个结果 ---
function printResult(rank, uid, r) {
  const total = Object.values(r.stats).reduce((a, b) => a + b, 0)
  const avg   = (total / STAT_NAMES.length).toFixed(1)
  console.log(`#${rank}  [${r.rarity}${RARITY_STARS[r.rarity]}] ${r.species}  eye=${r.eye}  hat=${r.hat}  shiny=${r.shiny}`)
  console.log(`   总分: ${total}  均值: ${avg}`)
  for (const name of STAT_NAMES) {
    const val = r.stats[name]
    const bar = '█'.repeat(Math.floor(val / 5)) + '░'.repeat(20 - Math.floor(val / 5))
    console.log(`   ${name.padEnd(10)} ${bar} ${val}`)
  }
  console.log(`   uid: ${uid}`)
  console.log('')
}

// --- Main ---
const opts = parseArgs()

// Check 模式
if (opts.check) {
  console.log(`[Node.js / FNV-1a — 仅供参考,与真实 Claude Code 不同]\n`)
  const r = rollFull(opts.check)
  printResult('?', opts.check, r)
  process.exit(0)
}

const filters = []
if (opts.species)     filters.push(`species=${opts.species}`)
if (opts.rarity)      filters.push(`rarity>=${opts.rarity}`)
if (opts.eye)         filters.push(`eye=${opts.eye}`)
if (opts.hat)         filters.push(`hat=${opts.hat}`)
if (opts.shiny)       filters.push('shiny=true')
if (opts.topStats)    filters.push(`top-${opts.topCount}(按总分排序)`)
else if (opts.minStatsVal) filters.push(`all stats>=${opts.minStatsVal}`)

console.log(`[Node.js / FNV-1a — 结果与真实 Claude Code 不匹配]`)
console.log(`搜索条件: ${filters.join(', ') || '任意'}`)
console.log(`迭代上限: ${opts.max.toLocaleString()}`)
console.log('')

const minRarityRank = opts.rarity ? RARITY_RANK[opts.rarity] : 0
const startTime = Date.now()

// ---- top-stats 模式:维护一个最小堆(用数组模拟) ----
if (opts.topStats) {
  // 简单做法:维护一个长度为 topCount 的数组,记录最高总分
  // 每次新候选比堆顶大就替换,最后排序输出
  const heap = []   // { total, uid, r }
  let scanned = 0
  let passed  = 0

  // 进度打点
  const REPORT_INTERVAL = 500_000
  let nextReport = REPORT_INTERVAL

  for (let i = 0; i < opts.max; i++) {
    const uid = crypto.randomBytes(32).toString('hex')
    const r   = rollFull(uid)

    // 过滤
    if (opts.rarity  && RARITY_RANK[r.rarity] < minRarityRank) continue
    if (opts.species && r.species !== opts.species) continue
    if (opts.eye     && r.eye     !== opts.eye)     continue
    if (opts.hat     && r.hat     !== opts.hat)     continue
    if (opts.shiny   && !r.shiny)                   continue

    passed++
    const total = Object.values(r.stats).reduce((a, b) => a + b, 0)

    if (heap.length < opts.topCount) {
      heap.push({ total, uid, r })
      heap.sort((a, b) => a.total - b.total)   // 升序,堆顶最小
    } else if (total > heap[0].total) {
      heap[0] = { total, uid, r }
      heap.sort((a, b) => a.total - b.total)
    }

    scanned++
    if (i + 1 >= nextReport) {
      const elapsed = ((Date.now() - startTime) / 1000).toFixed(1)
      process.stdout.write(`\r  已扫描 ${(i+1).toLocaleString()} 次  命中过滤 ${passed}  当前最低总分 ${heap.length > 0 ? heap[0].total : '-'}  用时 ${elapsed}s   `)
      nextReport += REPORT_INTERVAL
    }
  }

  process.stdout.write('\n\n')
  const elapsed = ((Date.now() - startTime) / 1000).toFixed(1)
  console.log(`扫描完成:共 ${opts.max.toLocaleString()} 次,命中 ${passed} 个,用时 ${elapsed}s`)
  console.log(`输出总分最高的 ${heap.length} 个结果:\n`)

  // 降序输出
  heap.sort((a, b) => b.total - a.total)
  heap.forEach((entry, idx) => printResult(idx + 1, entry.uid, entry.r))

  process.exit(0)
}

// ---- 原有模式(找到 count 个即停) ----
let found = 0
for (let i = 0; i < opts.max; i++) {
  const uid = crypto.randomBytes(32).toString('hex')
  const r   = rollFull(uid)

  if (opts.rarity  && RARITY_RANK[r.rarity] < minRarityRank) continue
  if (opts.species && r.species !== opts.species) continue
  if (opts.eye     && r.eye     !== opts.eye)     continue
  if (opts.hat     && r.hat     !== opts.hat)     continue
  if (opts.shiny   && !r.shiny)                   continue
  if (opts.minStatsVal && !Object.values(r.stats).every(v => v >= opts.minStatsVal)) continue

  found++
  printResult(found, uid, r)
  if (found >= opts.count) break
}

const elapsed = ((Date.now() - startTime) / 1000).toFixed(1)
if (found === 0) {
  console.log(`在 ${opts.max.toLocaleString()} 次内未找到匹配结果(${elapsed}s)`)
} else {
  console.log(`找到 ${found} 个结果,用时 ${elapsed}s`)
}
node buddy-reroll-top.js --species dragon --rarity legendary --eye ✦ --shiny --top-stats --max 5000000 --top-count 5
 bun buddy-reroll-top.js --species dragon --rarity legendary --eye ✦ --shiny --top-stats --max 5000000 --top-count 5

3.打开自己电脑对应的.claude.json文件,找到useID、name、personality这三个字符串对应的值,把上一步得到的任意你满意数值的uid换到useID里面,name和personality你可以取任意名称和个性签名。
在这里插入图片描述
在这里插入图片描述

4.最后重启你的claude code,就可以得到对应数值拉满的传说级闪光宠物!!!
在这里插入图片描述
在这里插入图片描述
(结语:博主也是从common的Octopus变成了传说级闪光Dragon,当时出现智慧为1,我人都傻掉了,怎么能数值这么低感觉像是小时候玩洛克王国的感觉)

Logo

AtomGit 是由开放原子开源基金会联合 CSDN 等生态伙伴共同推出的新一代开源与人工智能协作平台。平台坚持“开放、中立、公益”的理念,把代码托管、模型共享、数据集托管、智能体开发体验和算力服务整合在一起,为开发者提供从开发、训练到部署的一站式体验。

更多推荐