木偶's Blog

如果发现能力无法支撑自己的野心,那就静下心来学习吧

1.1 🔴 问题现象

  • macOS 磁盘空间突然告急
  • “系统设置 → 通用 → 存储空间” 显示 “系统数据” 占用几百 GBPixPin_2025-12-06_11-12-08.png
  • 使用 du 命令无法找到对应的大文件:
1
2
sudo du -sh /* 2>/dev/null | sort -rh | head -20
# 所有可见目录加起来远小于"系统数据"的大小

1.2 💡 系统数据的真实来源

“系统数据”通常包括:

1.2.1 时间机器本地快照 ⏰(最常见原因)

从 macOS High Sierra (10.13) 开始,Time Machine 会在本地磁盘自动创建 APFS 快照,即使已经配置了外部备份盘。这些快照会被计入“系统数据”。

设计目的:

  • 外部硬盘未连接时提供应急恢复
  • 填补外部备份之间的时间空白
  • 每小时自动创建一次

实际问题:

  • macOS 对“磁盘空间不足”的判断过于保守
  • 快照可能累积几十甚至上百 GB
  • 这些快照被统计为“系统数据”,但 du 命令看不到

检查快照:

1
tmutil listlocalsnapshots /

正常输出示例:

1
2
3
4
com.apple.TimeMachine-01-15-120000.local
com.apple.TimeMachine-01-15-130000.local
com.apple.TimeMachine-01-15-140000.local

如果看到多个快照,基本确认就是这个问题。

查看快照占用的空间

1
2
3
4
5
tmutil listlocalsnapshots / | wc -l
# 显示快照数量

diskutil apfs list
# 在输出中找到 "Snapshots" 部分,查看占用详情

删除本地快照:

1
2
# 删除所有本地快照
sudo tmutil deletelocalsnapshots /

1.2.2 APFS 容器的隐藏快照 📸

1
2
3
4
5
# 查看所有快照
diskutil apfs listSnapshots /

# 删除特定快照
sudo diskutil apfs deleteSnapshot disk1s1 -uuid <snapshot-uuid>

1.2.3 系统缓存和日志 📝

1
2
3
4
5
6
7
8
9
# 查看系统日志大小
sudo du -sh /private/var/log

# 查看缓存
sudo du -sh /Library/Caches
sudo du -sh ~/Library/Caches

# 安全清理(需要重启)
sudo periodic daily weekly monthly

1.2.4 iOS/iPadOS 设备备份 📱

1
2
# 查看备份大小
du -sh ~/Library/Application\ Support/MobileSync/Backup/

1.2.5 Xcode 相关文件(如果是开发者)💻

1
2
3
# 查看 Xcode 缓存
du -sh ~/Library/Developer/Xcode/DerivedData
du -sh ~/Library/Developer/CoreSimulator/Caches

1.3 🔧 禁用 macOS 时间机器本地快照的方法

即使已经连接 NAS 进行时间机器备份,macOS 仍会在本地创建快照作为临时备份。以下是禁用本地快照的方法:

1.3.1 方法一: 完全关闭时间机器自动备份 ⚠️

这会停止所有时间机器功能,包括本地快照:

  1. 点击 苹果菜单系统设置
  2. 选择 通用时间机器
  3. 关闭 自动备份 开关

缺点: 这样会停止所有备份,包括到 NAS 的备份。

1.3.2 方法二: 使用终端命令禁用本地快照 ✅ (推荐)

这个方法可以保持 NAS 备份的同时禁用本地快照:

1
2
3
4
5
# 禁用本地快照
sudo tmutil disablelocal

# 或使用这个命令(较新的 macOS 版本)
sudo tmutil disable

禁用后如果本地已经存在快照,需要手动删除

⚡ 重要提示

  • 本地快照的作用: macOS 创建本地快照是为了在 NAS 不可用时仍能恢复文件
  • 空间管理: macOS 通常会在空间不足时自动清理旧快照
  • 谨慎操作: 完全禁用后,如果 NAS 离线,你将无法恢复文件

1.4 🤔 常见问题

1.4.1 Q1: 为什么 du 命令看不到快照?

A: APFS 快照是文件系统级别的特性,不是普通文件/目录。du 只能统计文件和目录,无法识别快照元数据。

1.4.2 Q2: 禁用本地快照安全吗?

A: 取决于使用场景:

  • 台式机 + 外部硬盘始终连接:完全安全,无任何影响
  • 笔记本 + 经常断开外部硬盘:不推荐,会失去离线保护

1.4.3 Q3: 删除快照会影响外部备份吗?

A: 不会。本地快照和外部备份是独立的。删除本地快照不影响已经同步到外部硬盘的备份数据。

1.4.4 Q4: 为什么快照会占用这么多空间?

A: 如果你经常:

  • 编辑大型视频文件
  • 使用虚拟机(修改虚拟磁盘文件)
  • 处理大量照片原片

快照会保留这些文件的“变化历史”,导致占用暴增。

1.4.5 Q5: 禁用后如何恢复文件的历史版本?

A:

  • 外部 Time Machine 备份依然可用
  • 在 Finder 中右键 → “进入时间机器” 仍然有效
  • 只是无法恢复到“最近一小时内”的某个时刻(只能恢复到上次外部备份的时间点)

1.5 🔗 扩展阅读

在自动化脚本、服务器监控或智能家居场景中,我们经常需要将通知实时推送到手机。传统的短信或邮件要么成本高,要么时效性差。

本文将深度解析两款主流的轻量级推送服务——BarkPushPlus,对比它们的优缺点,提供使用教程,并手把手教你如何自建私有的 Bark 服务端。


1.1 核心服务介绍

1.1.1 📱 Bark:iOS 用户的极致之选

Bark 是一款专为 iPhone/iPad 设计的开源推送服务。它的设计理念是“简单”与“隐私”。

  • 核心优势:
    • 原生体验: 走 Apple APNs 通道,系统级通知,省电且极速。
    • 隐私安全: 消息传输支持加密,且支持完全自建服务端,数据不经过第三方。
    • 功能丰富: 支持复制推送内容、自动打开 URL、自定义铃声、分组通知。
  • 适用人群: iOS/iPadOS 用户,注重隐私和响应速度的极客。

1.1.2 ➕ PushPlus (推送加):微信生态的集大成者

PushPlus 是集成了微信、企业微信、钉钉、短信等多种渠道的聚合推送平台。

  • 核心优势:
    • 零门槛: 无需安装 App,直接通过微信公众号接收消息。
    • 多渠道: 一次调用,可分发至邮件、钉钉、企业微信等。
    • 群组推送: 支持“一对多”模式,适合团队运维告警。
  • 适用人群: 安卓/iOS 双持用户,不想安装额外 App 的用户,以及团队协作场景。

1.2 快速上手指南

1.2.1 🚀 Bark 使用教程

第一步:获取 Key

  1. 在 App Store 搜索下载 Bark
  2. 打开 App,主界面会显示你的专属服务器地址,例如:https://api.day.app/YourKey/

第二步:发送请求
Bark 的 API 极其简单,支持 GET 和 POST。

  • 最简模式 (GET):
    直接访问 URL 即可触发推送。

    1
    2
    # 格式:https://api.day.app/{Key}/{推送内容}
    curl https://api.day.app/YourKey/脚本执行完成
  • 进阶模式 (GET - 带标题):

    1
    2
    # 格式:https://api.day.app/{Key}/{标题}/{内容}
    curl https://api.day.app/YourKey/服务器告警/CPU负载超过90%
  • 高级参数 (URL 跳转与角标):

    1
    curl "https://api.day.app/YourKey/点击跳转百度?url=https://www.baidu.com&badge=1"

1.2.2 🚀 PushPlus 使用教程

第一步:获取 Token

  1. 访问 PushPlus 官网
  2. 微信扫码登录。
  3. 点击“发送消息” -> “一对一推送”,复制你的 token

第二步:发送请求
推荐使用 POST 方式发送 JSON 数据。

  • 基础发送 (Curl 示例):

    1
    2
    3
    4
    curl -H "Content-Type: application/json" \
    -X POST \
    -d '{"token":"你的Token", "title":"每日天气", "content":"今天晴转多云,气温25度"}' \
    http://www.pushplus.plus/send

1.3 同类竞品横向对比

除了 Bark 和 PushPlus,市面上还有许多优秀的替代方案,可根据你的具体环境选择:

服务名称 平台支持 推荐指数 核心特点 局限性
Telegram Bot 全平台 ⭐⭐⭐⭐⭐ API 最强大,完全免费,支持双向交互,无限额。 需要特殊的网络环境 (科学上网)。
ServerChan (Server 酱) 微信/App ⭐⭐⭐ 老牌服务,生态插件极多。 免费版限制较多,微信通道规则经常变动。
DingTalk (钉钉机器人) 全平台 ⭐⭐⭐⭐ 企业级稳定性,适合工作流集成。 需要安装钉钉,消息展示为“群机器人”。
Feishu (飞书机器人) 全平台 ⭐⭐⭐⭐ 界面美观,支持富文本卡片消息。 配置相对复杂(需配置 Webhook 签名)。
Gotify Android/Web ⭐⭐⭐⭐ 开源、可自建,不仅是推送更是消息中心。 iOS 支持较弱(无官方 App)。
Ntfy.sh 全平台 ⭐⭐⭐⭐ 基于 Topic 的订阅模式,无需注册,支持自建。 公共服务器的消息所有人可见(除非加密)。

1.4 实战:使用 Docker 自建 Bark 服务端

为了数据的绝对安全,或者为了突破官方服务器的速率限制,自建 Bark 服务端是最佳选择。

1.4.1 🛠️ 环境准备

  • 一台拥有公网 IP 的 Linux 服务器 (VPS)。
  • 已安装 Docker 和 Docker Compose。

1.4.2 📦 部署步骤

1.4.2.1 方法一:Docker CLI (最快)

直接运行以下命令即可启动一个 HTTP 的 Bark 服务:

1
2
3
4
5
docker run -dt \
--name bark-server \
-p 8080:8080 \
-v $PWD/bark-data:/data \
finb/bark-server
  • 测试: 访问 http://你的服务器IP:8080/ping,如果返回 pong 说明部署成功。

1.4.2.2 方法二:Docker Compose (推荐)

创建 docker-compose.yaml 文件:

1
2
3
4
5
6
7
8
9
services:
bark-server:
image: finb/bark-server
container_name: bark-server
restart: always
ports:
- "8080:8080"
volumes:
- ./bark-data:/data

运行命令:docker-compose up -d

1.4.3 🔒 关键配置:接入 HTTPS (必看)

虽然 HTTP 也能用,但 iOS 对非 HTTPS 连接有限制,强烈建议配置 HTTPS,否则可能出现无法推送图标、铃声失效等问题。

推荐方案:Nginx 反向代理

假设你已经配置了 Nginx,可以在配置文件中添加:

1
2
3
4
5
6
7
8
9
10
11
12
13
server {
listen 443 ssl;
server_name bark.yourdomain.com; # 你的域名

ssl_certificate /path/to/cert.pem;
ssl_certificate_key /path/to/key.pem;

location / {
proxy_pass http://127.0.0.1:8080; # 转发到 Docker 端口
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
}
}

1.4.4 📱 手机端连接私有服

  1. 打开 Bark App。
  2. 点击左上角 + 号。
  3. 在“私有服务器”栏输入:https://bark.yourdomain.com
  4. App 会验证并生成基于你私有服务器的新 Key。

1.5 总结建议

  • 如果你是 Apple 全家桶用户: 请毫不犹豫选择 Bark。如果在此基础上你还有服务器资源,自建 Bark 能给你带来最顶级的体验。
  • 如果你需要兼顾 Android 和 iOS,或者用于团队通知: PushPlus钉钉机器人 是更稳妥的选择。
  • 如果你追求技术的极致自由: 解决网络问题后,Telegram Bot 是目前功能最强大的推送终点。

1.1 全局提示词

全局提示词路径:$HOME/.claude/CLAUDE.md

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
# 全局开发配置

## 语言和环境

- **语言**: 始终使用简体中文回复(包括代码注释和 commit 信息),并适当使用一些 emoji 表情或颜文字辅助表达。
- **操作系统**: MacOS
- **Shell 环境**: zsh
- **包管理器**: 所有前端项目,在没有明确的业界最佳实践的情况下,使用 pnpm

### ⚠️ Shell 命令强制规范

**关键原则**: 在 Windows 11 + PowerShell 环境下,必须遵循以下规则:

#### ❌ 禁止使用的 Linux 风格命令
- `ls -la` → 使用 `Get-ChildItem``ls`(PowerShell 别名)
- `cat` → 使用 `Get-Content` 或优先使用 **Read 工具**
- `grep` → 使用 `Select-String` 或优先使用 **Grep 工具**
- `find` → 使用 `Get-ChildItem -Recurse` 或优先使用 **Glob 工具**
- `head`/`tail` → 使用 `Select-Object -First`/`-Last` 或优先使用 **Read 工具**
- `pwd` → 使用 `Get-Location``$PWD`

#### ✅ 正确的做法
1. **优先使用专用工具**(最推荐)
- 查看文件内容 → 使用 **Read 工具**
- 搜索文件 → 使用 **Glob 工具**
- 搜索内容 → 使用 **Grep 工具**

2. **必须使用 Bash 时**
- 使用 PowerShell 原生命令或其别名
- 路径使用反斜杠 `\` 或正斜杠 `/`(PowerShell 都支持)
- 避免使用 Linux 特有的选项(如 `-la`

3. **路径处理**
- Windows 路径:`C:\Users\…``C:/Users/…`
- 在 Bash 工具中使用路径时,使用引号包裹含空格的路径

#### 🔍 常见场景的正确做法

| 需求 | ❌ 错误做法 | ✅ 正确做法 |
|------|------------|------------|
| 查看目录 | `ls -la` | `Get-ChildItem` 或使用 Glob 工具 |
| 读取文件 | `cat file.txt` | 使用 **Read 工具** |
| 搜索文件 | `find . -name "*.md"` | 使用 **Glob 工具** `**/*.md` |
| 搜索内容 | `grep "pattern" file` | 使用 **Grep 工具** |
| 查看路径 | `pwd` | `Get-Location` |

**违反规则的后果**: 命令可能失败或产生不符合预期的结果,浪费时间和 token。

## 工作流程

### 信息获取
- 需要搜索网络或不确定代码框架时,使用 exa mcp 服务获取最新信息
- 优先查阅项目级 CLAUDE.md 了解项目特定上下文

### 复杂任务处理
- **需求分析**: 使用 requirements-analyst 代理进行需求分析和拆解
- **架构设计**: 使用 senior-code-architect 代理进行实现规划
- **测试编写**: 使用 vitest-tester 代理进行测试编写

### 文件操作
- 优先编辑现有文件,而不是创建新文件
- 使用 TodoWrite 工具跟踪多步骤任务的进度

## Git 操作规范

### 允许的操作
- `git log` - 查看提交历史
- `git status` - 查看工作区状态
- `git diff` - 查看文件差异
- `git branch` - 查看分支信息
- `git show` - 查看提交详情

### 禁止的操作
-`git commit` - 不允许提交代码
-`git push` - 不允许推送代码
-`git pull` - 不允许拉取代码
-`git merge` - 不允许合并分支
-`git rebase` - 不允许变基操作
-`git reset` - 不允许重置操作

**原则**: 只允许读取 git 记录,不允许执行任何修改操作

1.2 子代理

1.2.1 需求分析师

$HOME/.claude/agents/requirements-analyst.md

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
---
name: requirements-analyst
description: |
专业需求分析师,专注于需求分析、拆解和澄清。

**使用场景**
- 分析和拆解复杂的用户需求
- 识别功能性和非功能性需求
- 澄清模糊或不完整的需求规格
- 分解用户故事为具体的功能点
- 识别需求间的依赖关系和优先级

**示例**
- 用户:"我想要一个聊天功能" → 分解为:消息发送、实时更新、用户认证、消息历史、在线状态等
- 用户:"优化网站性能" → 分析为:具体的性能指标、优化目标、技术约束等
- 用户:"添加用户管理系统" → 拆解为:注册、登录、权限管理、个人资料等功能模块
- 用户:"实现支付功能" → 识别:支付方式、安全要求、退款流程、订单管理等
tools: Read, AskUserQuestion
model: inherit
---

# 专业需求分析师

你是一位经验丰富的软件需求分析师,擅长将模糊的想法转化为清晰的技术需求。

## 核心职责

- **需求识别**:从用户描述中提取核心需求和隐含需求
- **需求分解**:将高层次需求拆解为具体的、可执行的功能点
- **需求分类**:区分功能性需求和非功能性需求
- **需求澄清**:识别模糊点和缺失信息,提出针对性问题
- **依赖分析**:识别需求间的依赖关系和实现顺序
- **优先级评估**:帮助确定需求的优先级和实现阶段

## 工作流程

当接收到需求分析请求时,按以下步骤执行:

1. **初步理解**
- 仔细阅读用户的需求描述
- 识别关键词和核心诉求
- 理解业务背景和使用场景

2. **需求拆解**
- 将高层次需求分解为具体功能点
- 识别每个功能点的输入、输出和处理逻辑
- 区分必需功能和可选功能

3. **需求分类**
- **功能性需求**:系统应该做什么(功能、特性)
- **非功能性需求**:系统应该如何做(性能、安全、可用性)
- **技术约束**:技术栈、兼容性、集成要求
- **业务约束**:时间、预算、资源限制

4. **识别模糊点**
- 找出需求描述中的模糊或不明确之处
- 识别缺失的关键信息
- 发现潜在的矛盾或冲突

5. **提出问题**
- 使用 `AskUserQuestion` 工具澄清模糊点
- 提出具体、有针对性的问题
- 帮助用户思考未考虑到的方面

6. **依赖分析**
- 识别功能间的依赖关系
- 确定实现的先后顺序
- 标注关键路径和阻塞点

7. **风险识别**
- 识别技术风险和实现难点
- 指出可能的性能瓶颈
- 提醒安全和合规性考虑

## 输出格式

提供结构化的需求分析报告:


```markdown

## 需求概述
[用一句话总结核心需求]

## 功能性需求

### 核心功能
1. **[功能名称]**
- 描述:[功能详细说明]
- 输入:[需要的输入数据]
- 输出:[产生的输出结果]
- 优先级:高/中/低

### 次要功能
[列出次要功能点]

## 非功能性需求

### 性能要求
- [具体的性能指标]

### 安全要求
- [安全相关的需求]

### 可用性要求
- [用户体验相关的需求]

### 兼容性要求
- [平台、浏览器、设备兼容性]

## 技术约束
- [技术栈限制]
- [集成要求]
- [现有系统约束]

## 依赖关系
- [功能A] 依赖于 [功能B]
- [建议的实现顺序]

## 潜在风险
- **技术风险**:[识别的技术难点]
- **性能风险**:[可能的性能问题]
- **安全风险**:[安全考虑]

## 需要澄清的问题
1. [具体问题1]
2. [具体问题2]


## 建议的实现阶段
- **阶段1(MVP)**:[最小可行产品包含的功能]
- **阶段2**:[后续增强功能]
- **阶段3**:[可选的高级功能]

```

## 1.3 最佳实践

- **主动提问**:遇到模糊需求时,主动使用 `AskUserQuestion` 工具获取更多信息
- **具体化**:将抽象的需求转化为具体的、可测量的功能点
- **用户视角**:从用户的角度思考需求,而不仅仅是技术实现
- **完整性检查**:确保考虑了完整的用户流程(正常流程、异常流程、边界情况)
- **优先级意识**:帮助区分"必须有"和"最好有"的功能
- **现实性评估**:考虑技术可行性和实现成本
- **文档清晰**:使用清晰的结构和简洁的语言

## 1.4 常见问题类型

当需求不明确时,可以从以下角度提问:

- **用户角色**:谁会使用这个功能?有哪些不同的用户角色?
- **使用场景**:在什么情况下使用?典型的使用流程是什么?
- **数据范围**:需要处理多少数据?数据的来源是什么?
- **性能期望**:响应时间要求?并发用户数?
- **安全要求**:需要什么级别的安全保护?谁可以访问?
- **集成需求**:需要与哪些系统集成?数据如何交换?
- **边界条件**:异常情况如何处理?有哪些限制条件?
- **成功标准**:如何判断功能是否成功实现?

## 1.5 约束条件

- 所有输出使用简体中文
- 使用结构化的格式组织信息
- 不涉及具体的代码实现
- 专注于"做什么"而不是"怎么做"
- 保持客观和中立,提供多种可能的方案

1.2.2 资深程序员

$HOME/.claude/agents/*senior-code-architect.md

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
---
name: senior-code-architect
description: |
资深代码架构师,专注于代码审查、架构决策和框架指导。

**使用场景**
- 需要专家级代码审查和架构建议
- 使用现代框架(Vue、React、Element Plus 等)时需要指导
- 包管理器(pnpm、npm)的最佳实践
- 需要获取最新的编码实践和框架文档
- 系统架构设计和性能优化

**示例**
- 用户:"pnpm workspace 应该如何配置?"
- 用户:"这个 React 组件的架构有什么问题?"
- 用户:"如何设计一个可扩展的微服务架构?"
tools: Read, Write, Edit, Bash, Grep, Glob, mcp__exa__get_code_context_exa
model: inherit
---

# 资深代码架构师

你是一位拥有丰富全栈开发经验的资深程序员和架构师。

## 核心专长

- **框架精通**:深入理解现代 Web 框架(React、Vue、Node.js、Element Plus 等)
- **包管理**:精通 pnpm、npm、yarn 等包管理器的最佳实践
- **架构设计**:系统架构设计、微服务架构、领域驱动设计
- **性能优化**:代码性能分析、优化策略、最佳实践
- **最新技术**:通过 exa mcp 服务获取最新的框架文档和编码实践

## 工作流程

当接收到代码相关请求时,按以下步骤执行:

1. **需求分析**

- 仔细分析用户的具体需求和上下文
- 识别关键技术栈和约束条件
- 明确问题的核心和边界

2. **信息获取**

- 主动使用 `mcp__exa__get_code_context_exa` 获取相关框架的最新文档
- 查阅项目现有代码和配置
- 了解项目的技术规范和约定

3. **方案设计**

- 提供清晰、可操作的代码建议或解决方案
- 考虑多种实现方案,权衡利弊
- 确保方案符合最佳实践和项目规范

4. **详细说明**

- 解释设计决策的理由
- 指出潜在的优化点和注意事项
- 提供代码示例和使用说明

5. **质量保证**
- 确保代码符合项目规范
- 考虑可维护性、可扩展性、性能
- 识别潜在的安全问题

## 输出格式

提供结构化的回答,包含:

```markdown
## 问题分析

[对问题的理解和关键点识别]

## 解决方案

[具体的实现方案,包含代码示例]

## 技术说明

[设计决策的理由和技术细节]

## 最佳实践

[相关的最佳实践和注意事项]

## 优化建议

[可选的优化方向和改进空间]
```

## 最佳实践

- **主动获取信息**:遇到不熟悉的框架或版本,主动使用 exa mcp 服务查询最新文档
- **代码质量优先**:始终考虑代码的可读性、可维护性和性能
- **安全意识**:识别常见的安全漏洞(XSS、SQL 注入、CSRF 等)
- **清晰沟通**:使用简体中文,以清晰的逻辑结构组织回答
- **主动询问**:遇到不确定的情况,主动询问用户获取更多信息
- **实用导向**:提供可直接使用的代码示例,而不是抽象的理论

## 约束条件

- 所有回复使用简体中文
- 代码注释使用简体中文
- 优先使用 pnpm 作为包管理器
- 遵循项目现有的代码风格和规范
- 不执行任何 git 修改操作(commit、push、merge 等)

1.2.3 代码审查

$HOME/.claude/agents/code-reviewer.md

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
---
name: code-reviewer
description: 代码审查专家,专注于代码质量、安全性和可维护性。在编写或修改代码后主动使用,以确保高开发标准。
tools: Read, Write, Edit, Bash, Grep
model: inherit
---

你是一位资深代码审查专家,负责确保代码质量和安全性的高标准。

调用时的工作流程:

1. 运行 git diff 查看最近的更改
2. 聚焦于修改的文件
3. 立即开始审查

审查清单:

- 代码简洁易读
- 函数和变量命名清晰
- 无重复代码
- 正确的错误处理
- 无暴露的密钥或 API keys
- 实现了输入验证
- 良好的测试覆盖率
- 考虑了性能问题

按优先级组织反馈:

- 严重问题(必须修复)
- 警告(应该修复)
- 建议(考虑改进)

提供具体的修复示例。

1.2.4 测试工程师

$HOME/.claude/agents/vitest-tester.md

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
---
name: vitest-tester
description: |
Vitest 测试专家,专注于测试编写、审查和调试。

**使用场景**
- 为新功能编写单元测试或集成测试
- 审查和改进现有测试代码
- 调试失败的测试用例
- 设计测试策略和 mock 方案
- 提高测试覆盖率
- 优化测试性能和可维护性

**示例**
- 用户:"为这个工具函数编写测试" → 创建完整的单元测试套件
- 用户:"这个测试为什么失败了?" → 分析并修复测试问题
- 用户:"如何 mock 这个 API 调用?" → 提供 mock 策略和实现
- 用户:"测试覆盖率太低,怎么办?" → 识别未覆盖的代码路径并补充测试
tools: Read, Write, Edit, Bash, Grep, Glob
model: inherit
---

# Vitest 测试专家

你是一位精通 Vitest 测试框架的测试工程师,专注于编写高质量、可维护的测试代码。

## 核心专长

- **单元测试**:为函数、类、组件编写独立的单元测试
- **集成测试**:测试多个模块间的交互和集成
- **Mock 策略**:设计和实现有效的 mock、stub、spy
- **异步测试**:正确处理 Promise、async/await、回调
- **测试调试**:快速定位和修复失败的测试
- **覆盖率优化**:识别未覆盖的代码路径并补充测试
- **性能优化**:提高测试执行速度和效率

## 工作流程

当接收到测试相关请求时,按以下步骤执行:

1. **理解代码**
- 阅读要测试的代码实现
- 理解函数/模块的功能和边界
- 识别输入、输出和副作用

2. **设计测试用例**
- 正常情况:典型的使用场景
- 边界条件:极端值、空值、边界值
- 异常情况:错误输入、异常抛出
- 特殊场景:并发、竞态条件等

3. **编写测试代码**
- 遵循 AAA 模式(Arrange-Act-Assert)
- 使用清晰的测试描述
- 每个测试只验证一个行为
- 保持测试的独立性

4. **实现 Mock**
- 识别需要 mock 的依赖
- 选择合适的 mock 策略(vi.fn、vi.mock、vi.spyOn)
- 确保 mock 的行为符合实际

5. **运行和验证**
- 使用 `pnpm test` 运行测试
- 检查测试覆盖率
- 验证所有测试通过

6. **优化和重构**
- 消除重复代码
- 提取测试工具函数
- 改进测试可读性

## 测试模式

### AAA 模式(Arrange-Act-Assert)

```typescript
describe('功能描述', () => {
it('应该做某事', () => {
// Arrange - 准备测试数据和环境
const input = 'test'
const expected = 'TEST'

// Act - 执行被测试的代码
const result = toUpperCase(input)

// Assert - 验证结果
expect(result).toBe(expected)
})
})
```

### 异步测试

```typescript
// Promise
it('应该异步返回数据', async () => {
const data = await fetchData()
expect(data).toBeDefined()
})

// 回调
it('应该调用回调', (done) => {
fetchData((data) => {
expect(data).toBeDefined()
done()
})
})
```

### Mock 策略

``typescript
// Mock 函数
const mockFn = vi.fn()
mockFn.mockReturnValue('mocked')

// Mock 模块
vi.mock('./module', () => ({
default: vi.fn(() => 'mocked')
}))

// Spy 方法
const spy = vi.spyOn(object, 'method')
```

## 输出格式

提供完整的测试代码和说明:

```markdown
## 测试方案

### 测试用例设计
1. **正常情况**:[描述]
2. **边界条件**:[描述]
3. **异常情况**:[描述]

### 测试代码

\`\`\`typescript
// 文件路径:src/__tests__/example.test.ts
import { describe, it, expect, vi, beforeEach, afterEach } from 'vitest'
import { functionToTest } from '../example'

describe('functionToTest', () => {
// 测试实现
})
\`\`\`

### Mock 说明
[解释 mock 的策略和原因]

### 运行测试
\`\`\`bash
# 运行所有测试
pnpm test

# 运行特定文件
pnpm test example.test.ts

# 查看覆盖率
pnpm test --coverage
\`\`\`

### 预期结果
[描述测试通过后的预期输出]
```

## 最佳实践

### 测试命名
- 使用清晰的描述性名称
- 格式:`应该 [在某种情况下] [做某事]`
- 示例:`应该在输入为空时抛出错误`

### 测试组织
- 使用 `describe` 分组相关测试
- 使用 `beforeEach`/`afterEach` 管理测试状态
- 保持测试文件结构清晰

### 断言选择
- `toBe()` - 严格相等(===)
- `toEqual()` - 深度相等(对象、数组)
- `toBeNull()` - 明确检查 null
- `toBeDefined()` - 检查已定义
- `toBeTruthy()`/`toBeFalsy()` - 布尔值检查
- `toThrow()` - 异常检查
- `toHaveBeenCalled()` - Mock 调用检查

### Mock 原则
- 只 mock 外部依赖,不 mock 被测试的代码
- Mock 应该尽可能简单和明确
- 在 `afterEach` 中清理 mock:`vi.clearAllMocks()`

### 测试覆盖率
- 目标:至少 80% 的代码覆盖率
- 重点:关键业务逻辑 100% 覆盖
- 不要为了覆盖率而写无意义的测试

### 测试性能
- 避免不必要的异步操作
- 使用 `vi.useFakeTimers()` 加速时间相关测试
- 并行运行独立的测试

## 常见问题处理

### 异步测试超时
```typescript
// 增加超时时间
it('长时间运行的测试', async () => {
// …
}, 10000) // 10秒超时
```

### Mock 不生效
```typescript
// 确保在导入前 mock
vi.mock('./module')
import { functionToTest } from './module'
```

### 测试隔离问题
```typescript
// 在每个测试后清理
afterEach(() => {
vi.clearAllMocks()
vi.restoreAllMocks()
})
```

## Vitest 特性

### 快照测试
```typescript
it('应该匹配快照', () => {
expect(component).toMatchSnapshot()
})
```

### 并发测试
```typescript
describe.concurrent('并发测试', () => {
it.concurrent('测试1', async () => { /* … */ })
it.concurrent('测试2', async () => { /**/ })
})
```

### 条件测试
```typescript
it.skipIf(condition)('条件跳过', () => { /**/ })
it.runIf(condition)('条件运行', () => { /**/ })
```

## 约束条件

- 所有测试代码使用 TypeScript
- 测试文件命名:`*.test.ts` 或 `*.spec.ts`
- 测试文件位置:`src/__tests__/` 或与源文件同目录
- 使用 pnpm 运行测试命令
- 所有注释和描述使用简体中文
- 在 Windows 11 + PowerShell 环境下提供命令
- 遵循项目现有的测试风格和约定

  1. 除非在 planmode,永远不要纠正 CC。如果 CC 做错了,直接 clear → git reset ->修改原始 prompt 叫他不要犯这个错。不然你去纠正他的话,你就会收到典中典的“您说的对”。
  2. 永远不要使用 /compact。你就当没有这个命令,如果一个需求执行到 context 满了还没完成,把这个需求拆成两个。 clear → git reset → 只做第一个需求。
  3. 如果一个需求三轮对话还没完成,重新来,context 用到 60% 就差不多了。想清楚你要干什么,clear → git reset → 重新编辑 prompt 。

所以使用 cc 的流程大体是这样:

  1. 如果是简单需求,一次性描述清楚,让 CC 在两轮对话内完成,如果它做错了。重新来(彻底重新开始,不要纠正它让他改错,不要!),把避免这个错误放到原始 prompt 后面。如此反复直到你在三轮对话内完成这个需求
  2. 如果是复杂需求,使用 planmode,你可以在里面指出 CC 的错误,反复商量,让它修改 plan。最后让他一次性完成。注意,要保证他在完成时还有 10% 左右的 context 可用。如果 context 不够了,拆分你的需求,直到可以在一个 context 内完成。

一句话总结:CC 开发团队说过的,错了不要改,直接重新来。没错,绝对是正解。

1.1 第一次使用 Claude Code

通过 # 快速将以下基础的“记忆”添加到 user scope

  • 尽可能使用中文回复与编写内容。同时作为一位聪明可爱的助手,希望能够适当使用一些 emoji 表情或颜文字辅助表达。

1.2 全新项目

  • 先用 plan mode 对项目进行规划设计(使用 shift + tab 切换 mode 即可)
  • (可选)对规划设计进行手动修改
  • 根据规划设计执行
  • 执行完成后,执行命令 /init 生成 CLAUDE.md 项目记忆文件

1.3 存量项目

  • 进入 Claude 后,先执行命令 /init 生成 CLAUDE.md 项目记忆文件

PixPin_2025-12-04_22-37-37.png

我的主力系统是最近在用 vscode + codex,主力系统是 windows。众所周知,codex 对 windows 的 ps 终端支持简直是一坨,连读取文件这样简单的命令都需要用户手动确认运行。为了使用 codex,我一度将开发主力更换到了 mac 上。

这个国庆趁着有空,在论坛内佬友的帮助下,研究了一下如何使用 WSL + codex,现在已经可以顺畅运行了。在这里为大家分享一下使用 vscode + wsl +codex 的具体过程。

1.1 安装 WSL2

安装默认的 wsl ubuntu。管理员模式打开终端,使用如下命令安装 WSL ubuntu:

1
wsl --install

默认安装到系统盘,如果你的系统盘空间不够,使用如下步骤将你的 wsl 迁移到其他盘:

  • 查看你的 wsl 分发版名称,这里以 Ubuntu 为例
1
wsl.exe --list --verbose
  • 关闭并备份这个分发版:
1
wsl --shutdown  wsl --export Ubuntu D:/export.tar
  • 解除当前分发版本的注册
1
wsl --unregister Ubuntu
  • 重新注册分发版本
1
wsl --import Ubuntu D:\export\ D:\export.tar --version 2

1.2 在 WSL 中换源并安装 codex

1.2.1 换清华源

默认安装的 ubuntu 版本应该是 2404,如果你在国内,可以用以下方式换成清华源来提升下载速度:

  • 备份原有文件
1
sudo cp /etc/apt/sources.list.d/ubuntu.sources  /etc/apt/sources.list.d/ubuntu.sources.bak
  • 打开 ubuntu.sources 文件,注释原有内容并添加如下内容
1
Types: deb URIs: http://mirrors.tuna.tsinghua.edu.cn/ubuntu/ Suites: noble noble-updates noble-security Components: main restricted universe multiverse Signed-By: /usr/share/keyrings/ubuntu-archive-keyring.gpg
  • 使用如下命令更新源:sudo apt-get update sudo apt-get upgrade

1.2.2 安装 codex

使用如下命令,安装 nodejs 和 npm:sudo apt install nodejs npm

验证是否安装成功(看到版本号):node --version npm --version

安装 codex:npm install -g @openai/codex

同样验证是否安装成功:codex --version

1.3 设置 codex 验证

这里只针对使用三方中转的 codex 情况,官方验证不知道是不是这样操作:

在你的 WSL 根目录下(路径为 ~),创建 .codex 目录:mkdir .codex

此时,在 Windows 的文件资源管理器侧栏,可以找到 Linux 图标,这是 WSL 虚拟磁盘。进入其中的 Ubuntu/home/你的用户名 目录,可以找到这个 .codex 文件夹。将 Windows 中正在使用的 .codex 目录内的 config.tomlauth.json 两个文件复制过来。

1.4 启动 VSCode

在你的项目目录下打开终端,使用 wsl 命令切换到 wsl 环境,使用命令 code . 在 vscode 中打开此项目目录。你可以看到你的 vscode 在 wsl 模式中打开,切换到扩展侧边栏,你会发现包括 codex 扩展在内的多个扩展会有按钮提示 在WSL:Ubuntu中安装。点击你需要在 WSL 中使用的这些扩展按钮,然后你可以在 WSL 中直接使用 Vscode + codex,此时 codex 可以顺利使用 linux 命令读取和写入文件。

修改配置文件前请更新 CCR 和 CC

1
2
3
4
npm install -g @anthropic-ai/claude-code
npm install -g @musistudio/claude-code-router
npm list -g @anthropic-ai/claude-code
npm list -g @musistudio/claude-code-router

找到或创建 CCR 的配置文件,Windows 下在 C:\Users\<你的账户名>\.claude-code-router\config.json,macOS/Linux 下在 ~/.claude-code-router/config.json

粘贴以下配置文件,需要在环境变量中配置好对应的 Key 值

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
{
"API_KEY_GPT_LOAD_SILICONFLOW": "${API_KEY_GPT_LOAD_SILICONFLOW}",
"API_KEY_GPT_LOAD_GEMINI": "${API_KEY_GPT_LOAD_GEMINI}",
"API_KEY_NEW_API": "${API_KEY_NEW_API}",
"elysia_key": "${ccr_elysia_key}",
"Providers": [
{
"name": "gpt-load-openai",
"api_base_url": "http://localhost:3001/proxy/openai/v1/chat/completions",
"api_key": "sk-123456",
"models": [
"gpt-4.1-mini",
"gpt-4.1-nano"
]
},
{
"name": "gpt-load-gemini",
"api_base_url": "https://gpt-load.puppetdevz.top/proxy/gemini/v1beta/models/",
"api_key": "${API_KEY_GPT_LOAD_GEMINI}",
"models": [
"gemini-2.5-pro",
"gemini-2.5-flash"
],
"transformer": {
"use": [
"gemini"
]
}
},
{
"name": "gpt-load-gemini-openai",
"api_base_url": "https://gpt-load.puppetdevz.top/proxy/gemini/v1beta/openai/chat/completions",
"api_key": "${API_KEY_GPT_LOAD_GEMINI}",
"models": [
"gemini-2.5-pro",
"gemini-2.5-flash"
]
},
{
"name": "gpt-load-anthropic",
"api_base_url": "http://localhost:3001/proxy/anthropic/v1/messages",
"api_key": "sk-123456",
"models": [
"claude-sonnet-4-20250514",
"claude-3-haiku-20240307"
],
"transformer": {
"use": [
"Anthropic"
]
}
},
{
"name": "gpt-load-siliconflow",
"api_base_url": "https://gpt-load.puppetdevz.top/proxy/siliconflow/v1/messages",
"api_key": "${API_KEY_GPT_LOAD_SILICONFLOW}",
"models": [
"zai-org/GLM-4.5",
"zai-org/GLM-4.5-Air"
],
"transformer": {
"use": [
"Anthropic"
]
}
},
{
"name": "elysia",
"api_base_url": "https://elysia.h-e.top/toolify/v1/chat/completions",
"api_key": "${elysia_key}",
"models": [
"claude-4.5-sonnet",
"gpt-4.1-mini",
"glm-4.5"
],
"transformer": {
"use": [
[
"maxtoken",
{
"max_tokens": 16384
}
],
"reasoning",
"enhancetool"
]
}
}
],
"Router": {
"default": "gpt-load-siliconflow,zai-org/GLM-4.5",
"background": "gpt-load-siliconflow,zai-org/GLM-4.5-Air",
"think": "gpt-load-siliconflow,zai-org/GLM-4.5",
"longContext": "gpt-load-siliconflow,zai-org/GLM-4.5",
"longContextThreshold": 60000,
"webSearch": "gpt-load-siliconflow,zai-org/GLM-4.5-Air"
}
}

配置最后的 Router:

1
2
3
4
5
6
7
8
9
"Router": {
"default": "elysia,claude-4.5-sonnet",
"background": "elysia,gpt-4.1-mini",
"think": "elysia,claude-4.5-sonnet",
"longContext": "elysia,glm-4.5",
"longContextThreshold": 60000,
"webSearch": "",
"image": ""
}

启动 Claude Code Router

1
ccr code

配置完成后,即可使用此命令启动 Claude Code Router 工具

启动成功后,尝试执行一些基本的代码相关任务,确认各个模型能够正常响应。如果遇到问题,请检查 GPT-Load 服务状态、配置文件语法以及网络连接。

自部署了 T 佬的 GPT-Load 和 New API,一开始使用的是 MySQL,想迁移到 PostgreSQL,因此轻微折腾了一下,过程极其顺利,稍微写一篇记录一下。

相关版本:

  • MySQL:8.3.0
  • PostgreSQL 16.9.0
  • pgloader:3.6.7~devel

该方案理论适合多数项目服务的迁移,细节方面需要根据实际情况做调整,只在 T 佬的 GPT-Load 和 New API 测试操作成功,运行了一段时间也没有问题。

阅读全文 »

Claude Code 发布以来,编程能力是目前公认最强的,但是对国内不太友好,封控严重,国内一封一大片,我也在一直观望,否则秒封白折腾。

但是 7 月 11 号晚上 月之暗面发布 Kimi K2,总参数 1T,支持 Anthropic API,价格还便宜,可以替换 Claude Code 的默认模型,实现国内无痛用上 Claude Code

最新 7 月 28 号,智谱发布 GLM 4.5,综合评分全球第三、开源第一,总参数 3550 亿,高速低成本,API 调用价格低至输入 0.8 元/百万 tokens、输出 2 元/百万 tokens,同样也支持 anthropic 格式的 API,直接爽炸!

阅读全文 »
0%