Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
19 changes: 10 additions & 9 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
# Claude Code Best V3 (CCB)

牢 A (Anthropic) 官方 [Claude Code](https://docs.anthropic.com/en/docs/claude-code) CLI 工具的源码反编译/逆向还原项目。目标是将 Claude Code 大部分功能及工程化能力复现。虽然很难绷, 但是它叫做 CCB(踩踩背)...
牢 A (Anthropic) 官方 [Claude Code](https://docs.anthropic.com/en/docs/claude-code) CLI 工具的源码反编译/逆向还原项目。目标是将 Claude Code 大部分功能及工程化能力复现 (问就是老佛爷已经付过钱了)。虽然很难绷, 但是它叫做 CCB(踩踩背)...

[文档在这里, 支持投稿 PR](https://ccb.agent-aura.top/)

Expand All @@ -12,21 +12,22 @@
- [x] 构建流水线完成, 产物 Node/Bun 都可以运行
- [x] V3 会写大量文档, 完善文档站点
- [ ] V4 会完成大量的测试文件, 以提高稳定性
- [ ] V5 大规模重构石山代码, 全面模块分包
- [ ] V5 将会为全新分支, 届时 main 分支将会封存为历史版本

> 我不知道这个项目还会存在多久, Star + Fork + git clone + .zip 包最稳健;
> 我不知道这个项目还会存在多久, Star + Fork + git clone + .zip 包最稳健; 说白了就是扛旗项目, 看看能走多远
>
> 这个项目更新很快, 后台有 Opus 持续优化, 所以你可以提 issues, 但是 PR 暂时不会接受;
> 这个项目更新很快, 后台有 Opus 持续优化, 几乎几个小时就有新变化;
>
> Claude 已经烧了 800$ 以上, 如果你个人想赞助, 请随便找个机构捐款, 然后截图在 issues, 大家的力量是温暖的;
> Claude 已经烧了 1000$ 以上, 继续玩;
>
> 某些模型提供商想要赞助, 那么请私发一个 1w 额度以上的账号到 <claude-code-best@proton.me>; 我们会在赞助商栏直接给你最亮的位置

存活记录:

1. 开源后 24 小时: 突破 6k Star, 感谢各位支持. 完成 docs 文档的站点构建, 达到 v3 版本, 后续开始进行测试用例维护, 完成之后可以接受 PR; 看来牢 A 是不想理我们了;
2. 开源后 15 小时: 完成了构建产物的 node 支持, 现在是完全体了; star 快到 3k 了; 等待牢 A 的邮件
3. 开源后 12 小时: 愚人节, star 破 1k, 并且牢 A 没有发邮件搞这个项目
4. 如果你想要私人咨询服务, 那么可以发送邮件到 <claude-code-best@proton.me>, 备注咨询与联系方式即可; 由于后续工作非常多, 可能会忽略邮件, 半天没回复, 可以多发;
1. 开源后 48 小时: 突破 7k Star; 测试代码小有成效;
2. 开源后 24 小时: 突破 6k Star, 感谢各位支持. 完成 docs 文档的站点构建, 达到 v3 版本, 后续开始进行测试用例维护, 完成之后可以接受 PR; 看来牢 A 是不想理我们了;
3. 开源后 15 小时: 完成了构建产物的 node 支持, 现在是完全体了; star 快到 3k 了; 等待牢 A 的邮件
4. 开源后 12 小时: 愚人节, star 破 1k, 并且牢 A 没有发邮件搞这个项目

## 快速开始

Expand Down
147 changes: 147 additions & 0 deletions docs/test-plans/01-tool-system.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,147 @@
# Tool 系统测试计划

## 概述

Tool 系统是 Claude Code 的核心,负责工具的定义、注册、发现和过滤。本计划覆盖 `src/Tool.ts` 中的工具接口与工具函数、`src/tools.ts` 中的注册/过滤逻辑,以及各工具目录下可独立测试的纯函数。

## 被测文件

| 文件 | 关键导出 |
|------|----------|
| `src/Tool.ts` | `buildTool`, `toolMatchesName`, `findToolByName`, `getEmptyToolPermissionContext`, `filterToolProgressMessages` |
| `src/tools.ts` | `parseToolPreset`, `filterToolsByDenyRules`, `getAllBaseTools`, `getTools`, `assembleToolPool` |
| `src/tools/shared/gitOperationTracking.ts` | `parseGitCommitId`, `detectGitOperation` |
| `src/tools/shared/spawnMultiAgent.ts` | `resolveTeammateModel`, `generateUniqueTeammateName` |
| `src/tools/GrepTool/GrepTool.ts` | `applyHeadLimit`, `formatLimitInfo`(内部辅助函数) |
| `src/tools/FileEditTool/utils.ts` | 字符串匹配/补丁相关纯函数 |

---

## 测试用例

### src/Tool.ts

#### describe('buildTool')

- test('fills in default isEnabled as true') — 不传 isEnabled 时,构建的 tool.isEnabled() 应返回 true
- test('fills in default isConcurrencySafe as false') — 默认值应为 false(fail-closed)
- test('fills in default isReadOnly as false') — 默认假设有写操作
- test('fills in default isDestructive as false') — 默认非破坏性
- test('fills in default checkPermissions as allow') — 默认 checkPermissions 应返回 `{ behavior: 'allow', updatedInput }`
- test('fills in default userFacingName from tool name') — userFacingName 默认应返回 tool.name
- test('preserves explicitly provided methods') — 传入自定义 isEnabled 等方法时应覆盖默认值
- test('preserves all non-defaultable properties') — name, inputSchema, call, description 等属性原样保留

#### describe('toolMatchesName')

- test('returns true for exact name match') — `{ name: 'Bash' }` 匹配 'Bash'
- test('returns false for non-matching name') — `{ name: 'Bash' }` 不匹配 'Read'
- test('returns true when name matches an alias') — `{ name: 'Bash', aliases: ['BashTool'] }` 匹配 'BashTool'
- test('returns false when aliases is undefined') — `{ name: 'Bash' }` 不匹配 'BashTool'
- test('returns false when aliases is empty') — `{ name: 'Bash', aliases: [] }` 不匹配 'BashTool'

#### describe('findToolByName')

- test('finds tool by primary name') — 从 tools 列表中按 name 找到工具
- test('finds tool by alias') — 从 tools 列表中按 alias 找到工具
- test('returns undefined when no match') — 找不到时返回 undefined
- test('returns first match when duplicates exist') — 多个同名工具时返回第一个

#### describe('getEmptyToolPermissionContext')

- test('returns default permission mode') — mode 应为 'default'
- test('returns empty maps and arrays') — additionalWorkingDirectories 为空 Map,rules 为空对象
- test('returns isBypassPermissionsModeAvailable as false')

#### describe('filterToolProgressMessages')

- test('filters out hook_progress messages') — 移除 type 为 hook_progress 的消息
- test('keeps tool progress messages') — 保留非 hook_progress 的消息
- test('returns empty array for empty input')
- test('handles messages without type field') — data 不含 type 时应保留

---

### src/tools.ts

#### describe('parseToolPreset')

- test('returns "default" for "default" input') — 精确匹配
- test('returns "default" for "Default" input') — 大小写不敏感
- test('returns null for unknown preset') — 未知字符串返回 null
- test('returns null for empty string')

#### describe('filterToolsByDenyRules')

- test('returns all tools when no deny rules') — 空 deny 规则不过滤任何工具
- test('filters out tools matching blanket deny rule') — deny rule `{ toolName: 'Bash' }` 应移除 Bash
- test('does not filter tools with content-specific deny rules') — deny rule `{ toolName: 'Bash', ruleContent: 'rm -rf' }` 不移除 Bash(只在运行时阻止特定命令)
- test('filters MCP tools by server name prefix') — deny rule `mcp__server` 应移除该 server 下所有工具
- test('preserves tools not matching any deny rule')

#### describe('getAllBaseTools')

- test('returns a non-empty array of tools') — 至少包含核心工具
- test('each tool has required properties') — 每个工具应有 name, inputSchema, call 等属性
- test('includes BashTool, FileReadTool, FileEditTool') — 核心工具始终存在
- test('includes TestingPermissionTool when NODE_ENV is test') — 需设置 env

#### describe('getTools')

- test('returns filtered tools based on permission context') — 根据 deny rules 过滤
- test('returns simple tools in CLAUDE_CODE_SIMPLE mode') — 仅返回 Bash/Read/Edit
- test('filters disabled tools via isEnabled') — isEnabled 返回 false 的工具被排除

---

### src/tools/shared/gitOperationTracking.ts

#### describe('parseGitCommitId')

- test('extracts commit hash from git commit output') — 从 `[main abc1234] message` 中提取 `abc1234`
- test('returns null for non-commit output') — 无法解析时返回 null
- test('handles various branch name formats') — `[feature/foo abc1234]` 等

#### describe('detectGitOperation')

- test('detects git commit operation') — 命令含 `git commit` 时识别为 commit
- test('detects git push operation') — 命令含 `git push` 时识别
- test('returns null for non-git commands') — 非 git 命令返回 null
- test('detects git merge operation')
- test('detects git rebase operation')

---

### src/tools/shared/spawnMultiAgent.ts

#### describe('resolveTeammateModel')

- test('returns specified model when provided')
- test('falls back to default model when not specified')

#### describe('generateUniqueTeammateName')

- test('generates a name when no existing names') — 无冲突时返回基础名
- test('appends suffix when name conflicts') — 与已有名称冲突时添加后缀
- test('handles multiple conflicts') — 多次冲突时递增后缀

---

## Mock 需求

| 依赖 | Mock 方式 | 说明 |
|------|-----------|------|
| `bun:bundle` (feature) | 已 polyfill 为 `() => false` | 不需额外 mock |
| `process.env` | `bun:test` mock | 测试 `USER_TYPE`、`NODE_ENV`、`CLAUDE_CODE_SIMPLE` |
| `getDenyRuleForTool` | mock module | `filterToolsByDenyRules` 测试中需控制返回值 |
| `isToolSearchEnabledOptimistic` | mock module | `getAllBaseTools` 中条件加载 |

## 集成测试场景

放在 `tests/integration/tool-chain.test.ts`:

### describe('Tool registration and discovery')

- test('getAllBaseTools returns tools that can be found by findToolByName') — 注册 → 查找完整链路
- test('filterToolsByDenyRules + getTools produces consistent results') — 过滤管线一致性
- test('assembleToolPool deduplicates built-in and MCP tools') — 合并去重逻辑
Loading
Loading