Skip to content

Commit bb17be7

Browse files
author
Bot
committed
feat: 添加 Exa AI 搜索适配器
新增 ExaSearchAdapter,基于 MCP 协议调用 Exa 搜索 API。 WebSearchTool 支持 num_results、livecrawl、search_type 等高级选项。 非官方 base URL 时默认使用 Exa 适配器。
1 parent 173ebfb commit bb17be7

8 files changed

Lines changed: 773 additions & 8 deletions

File tree

BUILD_GUIDE.md

Lines changed: 223 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,223 @@
1+
# Claude Code 编译指南
2+
3+
## 环境要求
4+
5+
- **Bun** >= 1.3.x(必须,Node.js 不支持 `bun build --compile`
6+
- **Git**(用于下载依赖和源码管理)
7+
- **Windows/Linux/macOS**(本仓库已在 Windows 下验证)
8+
9+
安装 Bun:
10+
```powershell
11+
powershell -ExecutionPolicy Bypass -c "irm bun.sh/install.ps1 | iex"
12+
```
13+
14+
---
15+
16+
## 快速开始
17+
18+
### 1. 克隆仓库
19+
20+
```bash
21+
git clone https://github.com/claude-code-best/claude-code.git
22+
cd claude-code
23+
```
24+
25+
### 2. 安装依赖
26+
27+
```bash
28+
bun install
29+
```
30+
31+
> 安装时会自动运行 `postinstall` 脚本,下载 ripgrep 二进制文件(`scripts/postinstall.cjs`)。
32+
33+
### 3. 编译
34+
35+
#### 方式一:编译为可分发的 JS 包(输出 `dist/`
36+
37+
```bash
38+
bun run build
39+
```
40+
41+
产物:`dist/` 目录下多个 `.js` chunk 文件,需要配合 Bun 或 Node.js 运行。
42+
43+
#### 方式二:编译为独立可执行文件(输出 `claude.exe`
44+
45+
```bash
46+
bun run compile
47+
```
48+
49+
产物:`claude.exe`(Windows)或 `claude`(Linux/macOS),约 143 MB,可独立运行,无需安装 Bun。
50+
51+
#### 方式三:开发模式(热重载)
52+
53+
```bash
54+
bun run dev
55+
```
56+
57+
---
58+
59+
## 构建产物说明
60+
61+
| 产物 | 命令 | 用途 | 大小 |
62+
|------|------|------|------|
63+
| `dist/` | `bun run build` | JS 分发包,配合 Bun/Node 运行 | ~35 MB |
64+
| `claude.exe` | `bun run compile` | 独立可执行文件,无需运行时 | ~143 MB |
65+
66+
---
67+
68+
## 编译脚本详解
69+
70+
### `build.ts` — JS 版本
71+
72+
Bun bundler 将 TypeScript/TSX 源码打包为可在 Bun/Node 运行的 JS。
73+
74+
**默认启用的 Feature Flags:**
75+
76+
```
77+
AGENT_TRIGGERS_REMOTE — 远程 Agent 触发
78+
CHICAGO_MCP — Computer Use MCP
79+
VOICE_MODE — 语音模式
80+
SHOT_STATS — 截图统计
81+
PROMPT_CACHE_BREAK_DETECTION — Prompt 缓存检测
82+
TOKEN_BUDGET — Token 预算
83+
AGENT_TRIGGERS — P0 本地功能
84+
ULTRATHINK — 深度思考
85+
BUILTIN_EXPLORE_PLAN_AGENTS — 内置探索计划 Agent
86+
LODESTONE — LODESTONE 功能
87+
EXTRACT_MEMORIES — P1 API 相关
88+
VERIFICATION_AGENT — 验证 Agent
89+
KAIROS_BRIEF — KAIROS 摘要
90+
AWAY_SUMMARY — 离开摘要
91+
ULTRAPLAN — 超计划
92+
DAEMON — P2 守护进程 + 远程控制
93+
```
94+
95+
启用额外功能(通过环境变量):
96+
97+
```bash
98+
FEATURE_MY_FEATURE=1 bun run build
99+
```
100+
101+
**构建步骤:**
102+
1. 清理 `dist/` 目录
103+
2. `Bun.build` 打包为 bun target,启用代码分割
104+
3. 后处理:替换 `import.meta.require` 为 Node.js 兼容版本
105+
4. 复制 `vendor/audio-capture/` 原生模块到 `dist/`
106+
5. 打包 `scripts/download-ripgrep.ts` 为独立 JS
107+
108+
---
109+
110+
### `compile.ts` — Native 版本
111+
112+
通过 `bun build --compile` 生成独立的可执行文件。
113+
114+
**构建步骤:**
115+
116+
1. **生成 ripgrep base64** — 将 ripgrep 二进制 base64 编码为 TypeScript 字符串,写入 `src/utils/ripgrepAssetBase64.ts`。只嵌入当前平台,减少 exe 体积。
117+
118+
2. **Patch SDK cli.js** — 修补 `@anthropic-ai/claude-agent-sdk` 中的 ripgrep 路径逻辑,将 `import.meta.url` 替换为 `process.execPath`(在编译后 `import.meta.url` 不可用)。
119+
120+
3. **执行 `bun build --compile`** — 传入以下参数:
121+
- `--define BUNDLED_MODE:"true"` — 告知运行时处于编译模式
122+
- `--feature CHICAGO_MCP` — 强制启用 MCP(否则 native 模块会被 tree-shake)
123+
- 原生模块路径通过环境变量注入(让 Bun 将 `.node` 文件嵌入为 asset)
124+
125+
4. **原生模块嵌入**(通过 `XXX_NODE_PATH` 环境变量):
126+
127+
```
128+
AUDIO_CAPTURE_NODE_PATH → vendor/audio-capture/x64-win32/audio-capture.node
129+
IMAGE_PROCESSOR_NODE_PATH → vendor/image-processor/x64-win32/image-processor.node
130+
MODIFIERS_NODE_PATH → vendor/modifiers-napi/x64-darwin/modifiers.node
131+
URL_HANDLER_NODE_PATH → vendor/url-handler/x64-darwin/url-handler.node
132+
```
133+
134+
> macOS-only 的 `.node` 文件仍会被打包(即使在 Windows 下),运行时检测平台后跳过。
135+
136+
---
137+
138+
## 常见问题
139+
140+
### 1. `Could not resolve: @anthropic/ink`
141+
142+
```bash
143+
bun install
144+
```
145+
146+
需要先安装依赖,`@anthropic/ink` 是 workspace 包,`bun install` 会自动 link。
147+
148+
### 2. `Warning: SDK patch did not match`
149+
150+
正常,不影响运行。SDK 的内部结构可能有细微变化,但 ripgrep 在编译后走 base64 解码路径,不依赖 SDK 的这个文件。
151+
152+
### 3. 编译速度慢
153+
154+
- 首次编译慢(需下载 SDK 和 ripgrep)
155+
- 后续编译通过 `bun install` 复用缓存
156+
- ripgrep base64 每次编译都会重新生成(正常)
157+
158+
### 4. Windows 下 `claude.exe` 生成到错误目录
159+
160+
`compile.ts` 已通过 `Bun.spawn` 解决此问题,直接用 `bun build --compile` 在 Windows 上可能有此 bug。
161+
162+
### 5. 缺少某些工具/技能
163+
164+
这是**反编译版本的固有限制**,以下模块在编译时被 strip 或 tree-shake 掉了,无法通过重新编译补回:
165+
- `skills/bundled/` 目录
166+
- `commands/torch.js`
167+
- `commands/subscribe-pr.js`
168+
- 部分 PushNotification / CtxInspect / ListPeers 工具
169+
170+
---
171+
172+
## monorepo 结构
173+
174+
```
175+
claude-code/
176+
├── src/ # 主源码
177+
│ ├── entrypoints/cli.tsx # CLI 入口
178+
│ ├── commands/ # 斜杠命令实现
179+
│ ├── tools/ # 工具实现
180+
│ └── utils/ # 工具函数
181+
├── packages/@ant/ # 子包
182+
│ ├── ink/ # Ink 终端 UI 组件库(核心)
183+
│ ├── computer-use-mcp/ # Computer Use MCP
184+
│ ├── computer-use-swift/ # macOS Swift 集成
185+
│ └── computer-use-input/ # 输入处理
186+
├── vendor/ # 原生模块(.node)
187+
│ ├── audio-capture/
188+
│ ├── image-processor/
189+
│ └── modifiers-napi/
190+
├── scripts/ # 构建/维护脚本
191+
│ ├── dev.ts # 开发启动
192+
│ ├── dev-debug.ts # 带调试的启动
193+
│ ├── download-ripgrep.ts # ripgrep 下载(TS 版)
194+
│ ├── postinstall.cjs # postinstall(CJS 版,bun install 用)
195+
│ └── defines.ts # 宏定义
196+
├── dist/ # JS 版本构建产物
197+
├── build.ts # JS 版本构建脚本
198+
└── compile.ts # Native 版本构建脚本
199+
```
200+
201+
---
202+
203+
## 一键完整构建
204+
205+
```bash
206+
# 清理 + 安装 + 构建 JS + 编译 native
207+
rm -rf dist && bun install && bun run build && bun run compile
208+
209+
# 验证 exe 可运行(显示帮助)
210+
./claude.exe --help
211+
```
212+
213+
---
214+
215+
## 自动化构建(定时更新)
216+
217+
参考以下 cron 任务配置(每 2 小时):
218+
219+
```
220+
0 */2 * * * bun install && bun run build && bun run compile
221+
```
222+
223+
> 注意:需确保 ripgrep 下载网络畅通,国内可通过设置 `RIPGREP_DOWNLOAD_BASE` 环境变量指向镜像。

package.json

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,7 @@
4242
],
4343
"scripts": {
4444
"build": "bun run build.ts",
45+
"compile": "bun run compile.ts",
4546
"build:vite": "vite build && bun run scripts/post-build.ts",
4647
"build:vite:only": "vite build",
4748
"build:bun": "bun run build.ts",
@@ -65,6 +66,7 @@
6566
"dependencies": {
6667
"@agentclientprotocol/sdk": "^0.19.0",
6768
"@claude-code-best/mcp-chrome-bridge": "^3.0.1",
69+
"cli-highlight": "^2.1.11",
6870
"highlight.js": "^11.11.1",
6971
"ws": "^8.20.0"
7072
},

packages/builtin-tools/src/tools/WebSearchTool/WebSearchTool.ts

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,26 @@ const inputSchema = lazySchema(() =>
2323
.array(z.string())
2424
.optional()
2525
.describe('Never include search results from these domains'),
26+
num_results: z
27+
.number()
28+
.optional()
29+
.describe('Number of search results to return (default: 8)'),
30+
livecrawl: z
31+
.enum(['fallback', 'preferred'])
32+
.optional()
33+
.describe(
34+
"Live crawl mode - 'fallback': use live crawling as backup if cached content unavailable, 'preferred': prioritize live crawling (default: 'fallback')",
35+
),
36+
search_type: z
37+
.enum(['auto', 'fast', 'deep'])
38+
.optional()
39+
.describe(
40+
"Search type - 'auto': balanced search (default), 'fast': quick results, 'deep': comprehensive search",
41+
),
42+
context_max_characters: z
43+
.number()
44+
.optional()
45+
.describe('Maximum characters for context string optimized for LLMs (default: 10000)'),
2646
}),
2747
)
2848
type InputSchema = ReturnType<typeof inputSchema>
@@ -148,6 +168,10 @@ export const WebSearchTool = buildTool({
148168
const adapterResults = await adapter.search(query, {
149169
allowedDomains: input.allowed_domains,
150170
blockedDomains: input.blocked_domains,
171+
numResults: input.num_results,
172+
livecrawl: input.livecrawl,
173+
searchType: input.search_type,
174+
contextMaxCharacters: input.context_max_characters,
151175
signal: context.abortController.signal,
152176
onProgress(progress) {
153177
if (onProgress) {

packages/builtin-tools/src/tools/WebSearchTool/__tests__/adapterFactory.test.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -52,10 +52,10 @@ describe('createAdapter', () => {
5252
expect(createAdapter().constructor.name).toBe('ApiSearchAdapter')
5353
})
5454

55-
test('selects the Bing adapter for third-party Anthropic base URLs', () => {
55+
test('selects the Exa adapter for third-party Anthropic base URLs', () => {
5656
delete process.env.WEB_SEARCH_ADAPTER
5757
isFirstPartyBaseUrl = false
5858

59-
expect(createAdapter().constructor.name).toBe('BingSearchAdapter')
59+
expect(createAdapter().constructor.name).toBe('ExaSearchAdapter')
6060
})
6161
})

0 commit comments

Comments
 (0)