first commit
This commit is contained in:
441
claude-code-中文Wiki/01-架构总览.md
Normal file
441
claude-code-中文Wiki/01-架构总览.md
Normal file
@@ -0,0 +1,441 @@
|
||||
# Claude Code 架构总览
|
||||
|
||||
本文件说明:介绍 Claude Code 的整体架构设计、技术栈、核心设计模式。
|
||||
|
||||
## 1. 项目背景
|
||||
|
||||
Claude Code 是 Anthropic 官方开发的 CLI(命令行界面)工具,旨在为开发者提供一个在终端环境中与 Claude 交互的途径,完成各种软件工程任务。
|
||||
|
||||
### 核心定位
|
||||
|
||||
- **终端优先**:专为命令行环境设计,使用 Ink(React for CLIs)渲染 Terminal UI
|
||||
- **软件工程助手**:专注于代码编写、文件操作、Git 管理、任务执行等开发任务
|
||||
- **安全可控**:提供细粒度的权限控制,用户可精确控制工具访问范围
|
||||
|
||||
### 源码泄露事件
|
||||
|
||||
2026 年 3 月 31 日,通过 npm source map 泄露了大量 Claude Code 源码,引起了安全研究社区的关注。这次泄露使外界得以深入了解 Claude Code 的内部实现机制。
|
||||
|
||||
## 2. 技术栈详解
|
||||
|
||||
### 2.1 运行时环境:Bun
|
||||
|
||||
Claude Code 使用 [Bun](https://bun.sh/) 作为 JavaScript/TypeScript 运行时:
|
||||
|
||||
```typescript
|
||||
// 使用 bun:bundle feature flag 进行条件编译
|
||||
import { feature } from 'bun:bundle'
|
||||
|
||||
// Dead code elimination 示例
|
||||
const REPLTool = feature('REPL_MODE')
|
||||
? require('./tools/REPLTool/REPLTool.js').REPLTool
|
||||
: null
|
||||
```
|
||||
|
||||
**Bun 的优势**:
|
||||
- 启动速度快
|
||||
- 内置 bundler 功能,支持条件导入(Dead code elimination)
|
||||
- 原生支持 TypeScript
|
||||
- 高效的 I/O 操作
|
||||
|
||||
### 2.2 语言:TypeScript
|
||||
|
||||
全项目使用 TypeScript 开发,具有:
|
||||
- 完整的类型系统
|
||||
- 严格的参数校验(基于 Zod v4)
|
||||
- 模块化的接口设计
|
||||
|
||||
### 2.3 终端 UI:React + Ink
|
||||
|
||||
Claude Code 使用 [Ink](https://github.com/vadimdemedes/ink) 库来实现 React 风格的终端界面:
|
||||
|
||||
```typescript
|
||||
// Ink 组件示例
|
||||
import { Box, Text } from 'ink'
|
||||
|
||||
const MyComponent = () => (
|
||||
<Box>
|
||||
<Text>Hello, Terminal!</Text>
|
||||
</Box>
|
||||
)
|
||||
```
|
||||
|
||||
**UI 组件特点**:
|
||||
- 支持颜色、布局、边框等终端视觉效果
|
||||
- 兼容 React 生态系统(hooks、context)
|
||||
- 用于渲染消息、进度条、选择器等 UI 元素
|
||||
|
||||
### 2.4 CLI 框架:Commander.js
|
||||
|
||||
使用 Commander.js 处理命令行参数和子命令:
|
||||
|
||||
```typescript
|
||||
import { Command } from '@commander-js/extra-typings'
|
||||
|
||||
const program = new Command()
|
||||
program
|
||||
.name('claude')
|
||||
.description('Anthropic 的 CLI 工具')
|
||||
.version('1.0.0')
|
||||
```
|
||||
|
||||
### 2.5 参数校验:Zod v4
|
||||
|
||||
使用 Zod v4 进行运行时参数校验:
|
||||
|
||||
```typescript
|
||||
import { z } from 'zod/v4'
|
||||
|
||||
const inputSchema = z.object({
|
||||
file_path: z.string(),
|
||||
offset: z.number().int().nonnegative().optional(),
|
||||
limit: z.number().int().positive().optional(),
|
||||
})
|
||||
```
|
||||
|
||||
### 2.6 代码搜索:ripgrep
|
||||
|
||||
内置集成了 ripgrep (`rg`) 用于高效的代码搜索:
|
||||
|
||||
```typescript
|
||||
// 在 GrepTool 等工具中使用
|
||||
import { execFile } from 'child_process'
|
||||
execFile('rg', ['--json', pattern, directory], callback)
|
||||
```
|
||||
|
||||
## 3. 核心架构设计
|
||||
|
||||
### 3.1 整体架构图
|
||||
|
||||
```
|
||||
┌─────────────────────────────────────────────────────────────┐
|
||||
│ main.tsx │
|
||||
│ (CLI 入口点) │
|
||||
└─────────────────────┬───────────────────────────────────────────┘
|
||||
│
|
||||
▼
|
||||
┌─────────────────────────────────────────────────────────────┐
|
||||
│ QueryEngine │
|
||||
│ (查询引擎核心) │
|
||||
│ ┌──────────────────────────────────────────────────────┐ │
|
||||
│ │ - submitMessage(): 处理用户输入 │ │
|
||||
│ │ - query(): 执行 API 调用循环 │ │
|
||||
│ │ - 流式响应处理 │ │
|
||||
│ │ - 工具调用编排 │ │
|
||||
│ └──────────────────────────────────────────────────────┘ │
|
||||
└─────────────────────┬───────────────────────────────────────────┘
|
||||
│
|
||||
┌─────────────┼─────────────┐
|
||||
▼ ▼ ▼
|
||||
┌─────────────┐ ┌─────────────┐ ┌─────────────┐
|
||||
│ Tools │ │ Commands │ │ Context │
|
||||
│ (工具系统) │ │ (命令系统) │ │ (上下文系统) │
|
||||
└─────────────┘ └─────────────┘ └─────────────┘
|
||||
```
|
||||
|
||||
### 3.2 工具系统架构
|
||||
|
||||
工具系统是 Claude Code 最核心的扩展机制:
|
||||
|
||||
```
|
||||
┌─────────────────────────────────────────────────────────────┐
|
||||
│ Tool.ts │
|
||||
│ (工具基类定义) │
|
||||
│ - inputSchema: Zod 输入校验 │
|
||||
│ - call(): 工具执行入口 │
|
||||
│ - checkPermissions(): 权限检查 │
|
||||
│ - render*: UI 渲染方法 │
|
||||
└─────────────────────────────────────────────────────────────┘
|
||||
│
|
||||
┌────────────────────┼────────────────────┐
|
||||
▼ ▼ ▼
|
||||
┌─────────────┐ ┌─────────────┐ ┌─────────────┐
|
||||
│ BashTool │ │ FileReadTool │ │ AgentTool │
|
||||
│ (Shell命令) │ │ (文件读取) │ │ (子Agent) │
|
||||
└─────────────┘ └─────────────┘ └─────────────┘
|
||||
│ │ │
|
||||
└────────────────────┼────────────────────┘
|
||||
▼
|
||||
┌───────────────────────────────────┐
|
||||
│ ToolRegistry (tools.ts) │
|
||||
│ - getAllBaseTools(): 获取所有工具 │
|
||||
│ - getTools(): 按权限过滤工具 │
|
||||
│ - assembleToolPool(): 合并 MCP │
|
||||
└───────────────────────────────────┘
|
||||
```
|
||||
|
||||
### 3.3 命令系统架构
|
||||
|
||||
命令系统支持三种类型的命令:
|
||||
|
||||
```typescript
|
||||
type CommandType =
|
||||
| 'prompt' // 展开为提示发送给模型
|
||||
| 'local' // 本地执行,返回文本结果
|
||||
| 'local-jsx' // 本地执行,渲染 Ink UI
|
||||
```
|
||||
|
||||
**命令注册流程**:
|
||||
1. 在 `commands.ts` 中定义命令
|
||||
2. 使用条件编译控制命令可见性
|
||||
3. 通过 `getCommands()` 获取可用命令列表
|
||||
|
||||
### 3.4 查询管道架构
|
||||
|
||||
```
|
||||
用户输入 ──► processUserInput() ──► query() ──► API 调用
|
||||
│ │
|
||||
│ ▼
|
||||
│ 工具执行循环
|
||||
│ │
|
||||
│ ┌─────────┼─────────┐
|
||||
│ ▼ ▼ ▼
|
||||
│ Tool 1 Tool 2 Tool N
|
||||
│ │ │ │
|
||||
│ └─────────┼─────────┘
|
||||
│ ▼
|
||||
│ 结果处理 ◄──────┐
|
||||
│ │ │
|
||||
│ ▼ │
|
||||
└──────► 结果返回 ───────────┘
|
||||
```
|
||||
|
||||
## 4. 关键设计模式
|
||||
|
||||
### 4.1 工厂模式 (Factory Pattern)
|
||||
|
||||
使用 `buildTool()` 工厂函数创建工具实例:
|
||||
|
||||
```typescript
|
||||
export function buildTool<D extends AnyToolDef>(def: D): BuiltTool<D> {
|
||||
return {
|
||||
...TOOL_DEFAULTS, // 填充默认实现
|
||||
userFacingName: () => def.name,
|
||||
...def,
|
||||
} as BuiltTool<D>
|
||||
}
|
||||
```
|
||||
|
||||
### 4.2 策略模式 (Strategy Pattern)
|
||||
|
||||
权限检查使用策略模式:
|
||||
|
||||
```typescript
|
||||
async checkPermissions(
|
||||
input: z.infer<Input>,
|
||||
context: ToolUseContext,
|
||||
): Promise<PermissionResult> {
|
||||
// 根据权限模式选择不同的检查策略
|
||||
switch (context.mode) {
|
||||
case 'auto': return autoCheck(input, context)
|
||||
case 'bypass': return allowAll(input)
|
||||
case 'default': return defaultCheck(input, context)
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### 4.3 装饰器模式 (Decorator Pattern)
|
||||
|
||||
`backfillObservableInput()` 允许在工具执行前修改输入:
|
||||
|
||||
```typescript
|
||||
backfillObservableInput?(input: Record<string, unknown>): void {
|
||||
// 在观察者看到输入之前修改它
|
||||
// 必须幂等
|
||||
}
|
||||
```
|
||||
|
||||
### 4.4 生成器模式 (Generator Pattern)
|
||||
|
||||
查询管道使用 AsyncGenerator 实现流式处理:
|
||||
|
||||
```typescript
|
||||
async *query(params: QueryParams): AsyncGenerator<
|
||||
| StreamEvent
|
||||
| RequestStartEvent
|
||||
| Message
|
||||
| TombstoneMessage
|
||||
| ToolUseSummaryMessage,
|
||||
Terminal
|
||||
> {
|
||||
// 流式 yield 消息
|
||||
}
|
||||
```
|
||||
|
||||
## 5. 状态管理
|
||||
|
||||
### 5.1 全局状态 (AppState)
|
||||
|
||||
```typescript
|
||||
interface AppState {
|
||||
toolPermissionContext: ToolPermissionContext
|
||||
fastMode: boolean
|
||||
fileHistory: FileHistoryState
|
||||
mcp: MCPState
|
||||
// ...其他状态
|
||||
}
|
||||
```
|
||||
|
||||
### 5.2 会话状态
|
||||
|
||||
- **Session ID**:唯一标识每次会话
|
||||
- **Message 列表**:维护对话历史
|
||||
- **Token 使用**:追踪 API 调用成本
|
||||
- **文件缓存**:readFileState 缓存已读文件内容
|
||||
|
||||
## 6. 安全机制
|
||||
|
||||
### 6.1 权限模式 (Permission Modes)
|
||||
|
||||
| 模式 | 描述 |
|
||||
|------|------|
|
||||
| `default` | 执行危险操作前询问用户 |
|
||||
| `auto` | 基于规则自动允许/拒绝 |
|
||||
| `bypass` | 允许所有操作(仅供可信环境) |
|
||||
| `plan` | 计划模式,限制更严格 |
|
||||
|
||||
### 6.2 工具沙箱
|
||||
|
||||
BashTool 支持使用沙箱执行命令:
|
||||
|
||||
```typescript
|
||||
const shouldUseSandbox = await shouldUseSandbox(command)
|
||||
if (shouldUseSandbox) {
|
||||
// 使用沙箱执行
|
||||
} else {
|
||||
// 直接执行
|
||||
}
|
||||
```
|
||||
|
||||
## 7. 扩展机制
|
||||
|
||||
### 7.1 MCP (Model Context Protocol)
|
||||
|
||||
支持通过 MCP 协议扩展工具:
|
||||
|
||||
```typescript
|
||||
interface MCPServerConnection {
|
||||
name: string
|
||||
type: 'stdio' | 'http'
|
||||
command?: string
|
||||
args?: string[]
|
||||
env?: Record<string, string>
|
||||
}
|
||||
```
|
||||
|
||||
### 7.2 插件系统
|
||||
|
||||
```typescript
|
||||
// 插件加载
|
||||
const plugins = await loadAllPluginsCacheOnly()
|
||||
|
||||
// 插件命令注册
|
||||
export function getPluginCommands(): Promise<Command[]>
|
||||
```
|
||||
|
||||
### 7.3 技能系统 (Skills)
|
||||
|
||||
技能是保存在本地目录中的可执行脚本:
|
||||
|
||||
```typescript
|
||||
// 技能目录结构
|
||||
~/.claude/skills/
|
||||
├── skill-name/
|
||||
│ ├── skill.md # 技能定义
|
||||
│ └── script.sh # 执行脚本
|
||||
```
|
||||
|
||||
## 8. 性能优化
|
||||
|
||||
### 8.1 记忆化 (Memoization)
|
||||
|
||||
使用 lodash 的 `memoize` 缓存昂贵计算:
|
||||
|
||||
```typescript
|
||||
export const getGitStatus = memoize(async (): Promise<string | null> => {
|
||||
// Git 状态获取(只计算一次)
|
||||
})
|
||||
```
|
||||
|
||||
### 8.2 条件编译 (Dead Code Elimination)
|
||||
|
||||
通过 Bun 的 `feature()` 实现条件编译:
|
||||
|
||||
```typescript
|
||||
const SleepTool = feature('PROACTIVE') || feature('KAIROS')
|
||||
? require('./tools/SleepTool/SleepTool.js').SleepTool
|
||||
: null
|
||||
```
|
||||
|
||||
### 8.3 自动压缩 (Auto-compact)
|
||||
|
||||
当上下文接近 Token 限制时自动压缩历史:
|
||||
|
||||
```typescript
|
||||
const { compactionResult } = await deps.autocompact(
|
||||
messagesForQuery,
|
||||
toolUseContext,
|
||||
{ systemPrompt, userContext, systemContext, toolUseContext },
|
||||
querySource,
|
||||
tracking,
|
||||
snipTokensFreed,
|
||||
)
|
||||
```
|
||||
|
||||
## 9. 源码目录结构
|
||||
|
||||
```
|
||||
claude-code/
|
||||
├── src/
|
||||
│ ├── main.tsx # CLI 入口
|
||||
│ ├── QueryEngine.ts # 查询引擎
|
||||
│ ├── Tool.ts # 工具基类
|
||||
│ ├── tools.ts # 工具注册表
|
||||
│ ├── commands.ts # 命令注册
|
||||
│ ├── context.ts # 上下文收集
|
||||
│ ├── cost-tracker.ts # 成本追踪
|
||||
│ ├── query.ts # 查询管道
|
||||
│ │
|
||||
│ ├── tools/ # 工具实现
|
||||
│ │ ├── BashTool/ # Shell 命令执行
|
||||
│ │ ├── FileReadTool/ # 文件读取
|
||||
│ │ ├── FileEditTool/ # 文件编辑
|
||||
│ │ ├── FileWriteTool/ # 文件写入
|
||||
│ │ ├── GlobTool/ # 文件模式匹配
|
||||
│ │ ├── GrepTool/ # 代码搜索
|
||||
│ │ ├── AgentTool/ # 子 Agent
|
||||
│ │ ├── WebFetchTool/ # 网页获取
|
||||
│ │ ├── WebSearchTool/ # 网络搜索
|
||||
│ │ ├── Task*/ # 任务管理系列
|
||||
│ │ └── ...
|
||||
│ │
|
||||
│ ├── services/ # 服务层
|
||||
│ │ ├── api/ # API 调用
|
||||
│ │ ├── mcp/ # MCP 协议
|
||||
│ │ ├── compact/ # 上下文压缩
|
||||
│ │ └── analytics/ # 分析服务
|
||||
│ │
|
||||
│ ├── state/ # 状态管理
|
||||
│ │ ├── AppState.ts
|
||||
│ │ └── store.ts
|
||||
│ │
|
||||
│ └── utils/ # 工具函数
|
||||
│ ├── permissions/ # 权限系统
|
||||
│ ├── model/ # 模型配置
|
||||
│ └── ...
|
||||
│
|
||||
├── package.json
|
||||
└── tsconfig.json
|
||||
```
|
||||
|
||||
## 10. 总结
|
||||
|
||||
Claude Code 的架构设计体现了以下原则:
|
||||
|
||||
1. **模块化**:清晰的分层和模块划分
|
||||
2. **可扩展性**:工具系统、命令系统、插件系统三位一体
|
||||
3. **类型安全**:TypeScript + Zod 双重保障
|
||||
4. **性能优先**:记忆化、条件编译、流式处理
|
||||
5. **安全可控**:细粒度的权限控制系统
|
||||
|
||||
这套架构使得 Claude Code 能够有效地在终端环境中执行复杂的软件工程任务,同时保持高度的可配置性和安全性。
|
||||
813
claude-code-中文Wiki/02-核心模块详解.md
Normal file
813
claude-code-中文Wiki/02-核心模块详解.md
Normal file
@@ -0,0 +1,813 @@
|
||||
# 核心模块详解
|
||||
|
||||
本文件说明:详细分析 Claude Code 的核心源文件,理解其实现原理。
|
||||
|
||||
## 1. main.tsx - CLI 入口点
|
||||
|
||||
### 1.1 功能概述
|
||||
|
||||
`main.tsx` 是 Claude Code 应用程序的入口点,负责:
|
||||
|
||||
- CLI 参数解析
|
||||
- 应用程序初始化
|
||||
- REPL(Read-Eval-Print Loop)启动
|
||||
- 各种启动前检查和配置
|
||||
|
||||
### 1.2 启动流程
|
||||
|
||||
```typescript
|
||||
// 1. 启动性能分析
|
||||
profileCheckpoint('main_tsx_entry')
|
||||
|
||||
// 2. MDM 设置预读取(并行)
|
||||
startMdmRawRead()
|
||||
|
||||
// 3. Keychain 凭据预读取(并行)
|
||||
startKeychainPrefetch()
|
||||
|
||||
// 4. 初始化遥测
|
||||
initializeTelemetryAfterTrust()
|
||||
|
||||
// 5. 获取引导数据
|
||||
const bootstrapData = await fetchBootstrapData()
|
||||
|
||||
// 6. 启动 REPL
|
||||
launchRepl()
|
||||
```
|
||||
|
||||
### 1.3 关键导入
|
||||
|
||||
```typescript
|
||||
import { Command as CommanderCommand } from '@commander-js/extra-typings'
|
||||
import React from 'react'
|
||||
import chalk from 'chalk'
|
||||
import { getTools } from './tools.js'
|
||||
import { getCommands, filterCommandsForRemoteMode } from './commands.js'
|
||||
import { getSystemContext, getUserContext } from './context.js'
|
||||
```
|
||||
|
||||
### 1.4 核心配置初始化
|
||||
|
||||
```typescript
|
||||
// 权限模式设置
|
||||
const initialPermissionMode = await initialPermissionModeFromCLI()
|
||||
|
||||
// 工具权限上下文初始化
|
||||
initializeToolPermissionContext({
|
||||
mode: initialPermissionMode,
|
||||
additionalWorkingDirectories: new Map(),
|
||||
alwaysAllowRules: {},
|
||||
alwaysDenyRules: {},
|
||||
alwaysAskRules: {},
|
||||
isBypassPermissionsModeAvailable: false,
|
||||
})
|
||||
|
||||
// 获取工具列表
|
||||
const tools = getTools(appState.toolPermissionContext)
|
||||
|
||||
// 获取命令列表
|
||||
const commands = await getCommands(cwd)
|
||||
```
|
||||
|
||||
## 2. QueryEngine.ts - LLM 查询引擎核心
|
||||
|
||||
### 2.1 功能概述
|
||||
|
||||
`QueryEngine` 是 Claude Code 的核心查询处理类,负责:
|
||||
|
||||
- 管理对话生命周期(每个对话一个 QueryEngine 实例)
|
||||
- 处理用户消息提交
|
||||
- 执行 API 调用循环
|
||||
- 处理流式响应
|
||||
- 编排工具执行
|
||||
- 管理会话状态(消息、Token 使用等)
|
||||
|
||||
### 2.2 类结构
|
||||
|
||||
```typescript
|
||||
export class QueryEngine {
|
||||
private config: QueryEngineConfig
|
||||
private mutableMessages: Message[] // 对话消息列表
|
||||
private abortController: AbortController // 中断控制器
|
||||
private permissionDenials: SDKPermissionDenial[] // 权限拒绝记录
|
||||
private totalUsage: NonNullableUsage // 累计 Token 使用
|
||||
private hasHandledOrphanedPermission = false
|
||||
private readFileState: FileStateCache // 文件读取缓存
|
||||
private discoveredSkillNames = new Set<string>()
|
||||
private loadedNestedMemoryPaths = new Set<string>()
|
||||
}
|
||||
```
|
||||
|
||||
### 2.3 核心方法:submitMessage()
|
||||
|
||||
这是处理用户输入的主要方法:
|
||||
|
||||
```typescript
|
||||
async *submitMessage(
|
||||
prompt: string | ContentBlockParam[],
|
||||
options?: { uuid?: string; isMeta?: boolean },
|
||||
): AsyncGenerator<SDKMessage, void, unknown>
|
||||
```
|
||||
|
||||
**执行流程**:
|
||||
|
||||
1. **初始化阶段**
|
||||
```typescript
|
||||
this.discoveredSkillNames.clear()
|
||||
setCwd(cwd)
|
||||
|
||||
// 获取系统提示词
|
||||
const { defaultSystemPrompt, userContext, systemContext } =
|
||||
await fetchSystemPromptParts({ tools, mainLoopModel, ... })
|
||||
```
|
||||
|
||||
2. **处理用户输入**
|
||||
```typescript
|
||||
const { messages, shouldQuery, allowedTools, model, resultText } =
|
||||
await processUserInput({
|
||||
input: prompt,
|
||||
mode: 'prompt',
|
||||
context: processUserInputContext,
|
||||
})
|
||||
|
||||
// 更新权限规则
|
||||
setAppState(prev => ({
|
||||
...prev,
|
||||
toolPermissionContext: {
|
||||
...prev.toolPermissionContext,
|
||||
alwaysAllowRules: { command: allowedTools }
|
||||
}
|
||||
}))
|
||||
```
|
||||
|
||||
3. **构建系统提示**
|
||||
```typescript
|
||||
const systemPrompt = asSystemPrompt([
|
||||
...(customPrompt ?? defaultSystemPrompt),
|
||||
...(memoryMechanicsPrompt ?? []), // 记忆机制提示
|
||||
...(appendSystemPrompt ?? [])
|
||||
])
|
||||
```
|
||||
|
||||
4. **查询循环**
|
||||
```typescript
|
||||
for await (const message of query({
|
||||
messages,
|
||||
systemPrompt,
|
||||
userContext,
|
||||
systemContext,
|
||||
canUseTool: wrappedCanUseTool,
|
||||
})) {
|
||||
// 处理各种消息类型
|
||||
switch (message.type) {
|
||||
case 'assistant': /* 记录助手消息 */ break
|
||||
case 'progress': /* 进度更新 */ break
|
||||
case 'user': /* 用户消息 */ break
|
||||
case 'stream_event': /* 流式事件 */ break
|
||||
case 'attachment': /* 附件处理 */ break
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### 2.4 流式响应处理
|
||||
|
||||
QueryEngine 处理多种流式事件:
|
||||
|
||||
```typescript
|
||||
if (message.type === 'stream_event') {
|
||||
// message_start: 新消息开始
|
||||
if (message.event.type === 'message_start') {
|
||||
currentMessageUsage = EMPTY_USAGE
|
||||
currentMessageUsage = updateUsage(currentMessageUsage, message.event.message.usage)
|
||||
}
|
||||
|
||||
// message_delta: 消息增量更新
|
||||
if (message.event.type === 'message_delta') {
|
||||
currentMessageUsage = updateUsage(currentMessageUsage, message.event.usage)
|
||||
if (message.event.delta.stop_reason != null) {
|
||||
lastStopReason = message.event.delta.stop_reason
|
||||
}
|
||||
}
|
||||
|
||||
// message_stop: 消息结束
|
||||
if (message.event.type === 'message_stop') {
|
||||
this.totalUsage = accumulateUsage(this.totalUsage, currentMessageUsage)
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### 2.5 思考模式 (Thinking Mode)
|
||||
|
||||
Claude Code 支持 Claude 的思考模式:
|
||||
|
||||
```typescript
|
||||
const initialThinkingConfig: ThinkingConfig = thinkingConfig
|
||||
? thinkingConfig
|
||||
: shouldEnableThinkingByDefault() !== false
|
||||
? { type: 'adaptive' } // 自适应思考
|
||||
: { type: 'disabled' } // 禁用
|
||||
```
|
||||
|
||||
思考规则(注释中的说明):
|
||||
1. 包含思考或编辑块的消息必须在 `max_thinking_length > 0` 的查询中
|
||||
2. 思考块不能是消息块中的最后一个
|
||||
3. 思考块必须在整个助手轨迹中保留
|
||||
|
||||
### 2.6 错误恢复机制
|
||||
|
||||
```typescript
|
||||
// USD 预算超限检查
|
||||
if (maxBudgetUsd !== undefined && getTotalCost() >= maxBudgetUsd) {
|
||||
yield {
|
||||
type: 'result',
|
||||
subtype: 'error_max_budget_usd',
|
||||
...
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// 最大轮次检查
|
||||
if (maxTurns && nextTurnCount > maxTurns) {
|
||||
yield { type: 'result', subtype: 'error_max_turns', ... }
|
||||
return
|
||||
}
|
||||
|
||||
// 结构化输出重试限制
|
||||
if (callsThisQuery >= maxRetries) {
|
||||
yield { type: 'result', subtype: 'error_max_structured_output_retries', ... }
|
||||
return
|
||||
}
|
||||
```
|
||||
|
||||
## 3. Tool.ts - 工具基类和接口定义
|
||||
|
||||
### 3.1 工具接口定义
|
||||
|
||||
```typescript
|
||||
export type Tool<
|
||||
Input extends AnyObject = AnyObject,
|
||||
Output = unknown,
|
||||
P extends ToolProgressData = ToolProgressData,
|
||||
> = {
|
||||
// 工具名称
|
||||
readonly name: string
|
||||
|
||||
// 可选别名(用于工具重命名后的向后兼容)
|
||||
aliases?: string[]
|
||||
|
||||
// 工具搜索提示词
|
||||
searchHint?: string
|
||||
|
||||
// 核心执行方法
|
||||
call(
|
||||
args: z.infer<Input>,
|
||||
context: ToolUseContext,
|
||||
canUseTool: CanUseToolFn,
|
||||
parentMessage: AssistantMessage,
|
||||
onProgress?: ToolCallProgress<P>,
|
||||
): Promise<ToolResult<Output>>
|
||||
|
||||
// 获取工具描述
|
||||
description(
|
||||
input: z.infer<Input>,
|
||||
options: {...}
|
||||
): Promise<string>
|
||||
|
||||
// 输入 Schema
|
||||
readonly inputSchema: Input
|
||||
|
||||
// 输入 JSON Schema(用于 MCP 工具)
|
||||
readonly inputJSONSchema?: ToolInputJSONSchema
|
||||
|
||||
// 输出 Schema
|
||||
outputSchema?: z.ZodType<unknown>
|
||||
}
|
||||
```
|
||||
|
||||
### 3.2 工具权限方法
|
||||
|
||||
```typescript
|
||||
// 验证输入是否有效
|
||||
validateInput?(
|
||||
input: z.infer<Input>,
|
||||
context: ToolUseContext,
|
||||
): Promise<ValidationResult>
|
||||
|
||||
// 检查权限
|
||||
checkPermissions(
|
||||
input: z.infer<Input>,
|
||||
context: ToolUseContext,
|
||||
): Promise<PermissionResult>
|
||||
|
||||
// 准备权限匹配器
|
||||
preparePermissionMatcher?(
|
||||
input: z.infer<Input>,
|
||||
): Promise<(pattern: string) => boolean>
|
||||
```
|
||||
|
||||
### 3.3 工具渲染方法
|
||||
|
||||
```typescript
|
||||
// 渲染工具使用消息
|
||||
renderToolUseMessage(
|
||||
input: Partial<z.infer<Input>>,
|
||||
options: { theme: ThemeName; verbose: boolean; commands?: Command[] }
|
||||
): React.ReactNode
|
||||
|
||||
// 渲染工具结果消息
|
||||
renderToolResultMessage?(
|
||||
content: Output,
|
||||
progressMessagesForMessage: ProgressMessage<P>[],
|
||||
options: {...}
|
||||
): React.ReactNode
|
||||
|
||||
// 渲染工具使用标签
|
||||
renderToolUseTag?(input: Partial<z.infer<Input>>): React.ReactNode
|
||||
|
||||
// 渲染进度消息
|
||||
renderToolUseProgressMessage?(
|
||||
progressMessagesForMessage: ProgressMessage<P>[],
|
||||
options: {...}
|
||||
): React.ReactNode
|
||||
```
|
||||
|
||||
### 3.4 buildTool 工厂函数
|
||||
|
||||
```typescript
|
||||
const TOOL_DEFAULTS = {
|
||||
isEnabled: () => true,
|
||||
isConcurrencySafe: (_input?: unknown) => false,
|
||||
isReadOnly: (_input?: unknown) => false,
|
||||
isDestructive: (_input?: unknown) => false,
|
||||
checkPermissions: async () => ({ behavior: 'allow', updatedInput: input }),
|
||||
toAutoClassifierInput: (_input?: unknown) => '',
|
||||
userFacingName: (_input?: unknown) => '',
|
||||
}
|
||||
|
||||
export function buildTool<D extends AnyToolDef>(def: D): BuiltTool<D> {
|
||||
return {
|
||||
...TOOL_DEFAULTS,
|
||||
userFacingName: () => def.name,
|
||||
...def,
|
||||
} as BuiltTool<D>
|
||||
}
|
||||
```
|
||||
|
||||
### 3.5 工具权限上下文
|
||||
|
||||
```typescript
|
||||
export type ToolPermissionContext = {
|
||||
mode: PermissionMode // 'default' | 'auto' | 'bypass' | 'plan'
|
||||
additionalWorkingDirectories: Map<string, AdditionalWorkingDirectory>
|
||||
alwaysAllowRules: ToolPermissionRulesBySource
|
||||
alwaysDenyRules: ToolPermissionRulesBySource
|
||||
alwaysAskRules: ToolPermissionRulesBySource
|
||||
isBypassPermissionsModeAvailable: boolean
|
||||
isAutoModeAvailable?: boolean
|
||||
strippedDangerousRules?: ToolPermissionRulesBySource
|
||||
shouldAvoidPermissionPrompts?: boolean
|
||||
awaitAutomatedChecksBeforeDialog?: boolean
|
||||
prePlanMode?: PermissionMode
|
||||
}
|
||||
```
|
||||
|
||||
## 4. commands.ts - 命令注册中心
|
||||
|
||||
### 4.1 功能概述
|
||||
|
||||
`commands.ts` 是 Claude Code 的命令注册中心,管理所有 slash commands(以 `/` 开头的命令)。
|
||||
|
||||
### 4.2 命令类型
|
||||
|
||||
```typescript
|
||||
type CommandType =
|
||||
| 'prompt' // 展开为提示发送给模型
|
||||
| 'local' // 本地执行,返回文本
|
||||
| 'local-jsx' // 本地执行,渲染 Ink UI
|
||||
```
|
||||
|
||||
### 4.3 命令定义结构
|
||||
|
||||
```typescript
|
||||
interface Command {
|
||||
type: CommandType
|
||||
name: string
|
||||
aliases?: string[]
|
||||
description: string
|
||||
contentLength: number
|
||||
source: 'builtin' | 'plugin' | 'bundled' | 'mcp' | ...
|
||||
availability?: ('claude-ai' | 'console')[]
|
||||
// ...
|
||||
}
|
||||
```
|
||||
|
||||
### 4.4 命令加载流程
|
||||
|
||||
```typescript
|
||||
// 1. 获取技能目录命令
|
||||
const skillDirCommands = await getSkillDirCommands(cwd)
|
||||
|
||||
// 2. 获取插件命令
|
||||
const pluginCommands = await getPluginCommands()
|
||||
|
||||
// 3. 获取内置命令
|
||||
const builtinCommands = COMMANDS()
|
||||
|
||||
// 4. 合并并过滤
|
||||
const allCommands = [
|
||||
...bundledSkills,
|
||||
...builtinPluginSkills,
|
||||
...skillDirCommands,
|
||||
...workflowCommands,
|
||||
...pluginCommands,
|
||||
...pluginSkills,
|
||||
...COMMANDS(),
|
||||
]
|
||||
|
||||
// 5. 检查可用性要求
|
||||
const filteredCommands = allCommands.filter(cmd =>
|
||||
meetsAvailabilityRequirement(cmd)
|
||||
)
|
||||
|
||||
// 6. 检查是否启用
|
||||
.filter(cmd => isCommandEnabled(cmd))
|
||||
```
|
||||
|
||||
### 4.5 远程安全命令
|
||||
|
||||
```typescript
|
||||
export const REMOTE_SAFE_COMMANDS: Set<Command> = new Set([
|
||||
session, exit, clear, help, theme, color, vim,
|
||||
cost, usage, copy, btw, feedback, plan,
|
||||
keybindings, statusline, stickers, mobile,
|
||||
])
|
||||
```
|
||||
|
||||
### 4.6 命令查找
|
||||
|
||||
```typescript
|
||||
export function findCommand(
|
||||
commandName: string,
|
||||
commands: Command[],
|
||||
): Command | undefined {
|
||||
return commands.find(
|
||||
_ =>
|
||||
_.name === commandName ||
|
||||
getCommandName(_) === commandName ||
|
||||
_.aliases?.includes(commandName)
|
||||
)
|
||||
}
|
||||
```
|
||||
|
||||
## 5. context.ts - 系统/用户上下文收集
|
||||
|
||||
### 5.1 功能概述
|
||||
|
||||
`context.ts` 负责收集系统上下文和用户上下文,这些上下文会被预置到每个对话的开头。
|
||||
|
||||
### 5.2 Git 状态收集
|
||||
|
||||
```typescript
|
||||
export const getGitStatus = memoize(async (): Promise<string | null> => {
|
||||
// 检查是否是 Git 仓库
|
||||
const isGit = await getIsGit()
|
||||
if (!isGit) return null
|
||||
|
||||
// 并行获取多个 Git 信息
|
||||
const [branch, mainBranch, status, log, userName] = await Promise.all([
|
||||
getBranch(),
|
||||
getDefaultBranch(),
|
||||
execFileNoThrow(gitExe(), ['status', '--short'], ...),
|
||||
execFileNoThrow(gitExe(), ['log', '--oneline', '-n', '5'], ...),
|
||||
execFileNoThrow(gitExe(), ['config', 'user.name'], ...),
|
||||
])
|
||||
|
||||
return [
|
||||
`Current branch: ${branch}`,
|
||||
`Main branch: ${mainBranch}`,
|
||||
`Git user: ${userName}`,
|
||||
`Status:\n${truncatedStatus}`,
|
||||
`Recent commits:\n${log}`,
|
||||
].join('\n\n')
|
||||
})
|
||||
```
|
||||
|
||||
### 5.3 系统上下文
|
||||
|
||||
```typescript
|
||||
export const getSystemContext = memoize(async () => {
|
||||
const gitStatus = await getGitStatus()
|
||||
|
||||
// 缓存破坏注入(仅用于调试)
|
||||
const injection = feature('BREAK_CACHE_COMMAND')
|
||||
? getSystemPromptInjection()
|
||||
: null
|
||||
|
||||
return {
|
||||
...(gitStatus && { gitStatus }),
|
||||
...(injection && { cacheBreaker: `[CACHE_BREAKER: ${injection}]` }),
|
||||
}
|
||||
})
|
||||
```
|
||||
|
||||
### 5.4 用户上下文
|
||||
|
||||
```typescript
|
||||
export const getUserContext = memoize(async () => {
|
||||
// 获取 CLAUDE.md 文件内容
|
||||
const shouldDisableClaudeMd = isEnvTruthy(process.env.CLAUDE_CODE_DISABLE_CLAUDE_MDS)
|
||||
|| (isBareMode() && getAdditionalDirectoriesForClaudeMd().length === 0)
|
||||
|
||||
const claudeMd = shouldDisableClaudeMd
|
||||
? null
|
||||
: getClaudeMds(filterInjectedMemoryFiles(await getMemoryFiles()))
|
||||
|
||||
// 缓存 CLAUDE.md 内容供自动模式分类器使用
|
||||
setCachedClaudeMdContent(claudeMd || null)
|
||||
|
||||
return {
|
||||
...(claudeMd && { claudeMd }),
|
||||
currentDate: `Today's date is ${getLocalISODate()}.`,
|
||||
}
|
||||
})
|
||||
```
|
||||
|
||||
### 5.5 上下文缓存
|
||||
|
||||
所有上下文函数都使用 `memoize` 进行缓存,确保在一次对话中只计算一次:
|
||||
|
||||
```typescript
|
||||
export const getSystemContext = memoize(async () => {...})
|
||||
export const getUserContext = memoize(async () => {...})
|
||||
export const getGitStatus = memoize(async () => {...})
|
||||
```
|
||||
|
||||
## 6. cost-tracker.ts - Token 成本追踪
|
||||
|
||||
### 6.1 功能概述
|
||||
|
||||
`cost-tracker.ts` 负责追踪和计算 API 调用的 Token 使用量和成本。
|
||||
|
||||
### 6.2 核心数据结构
|
||||
|
||||
```typescript
|
||||
type StoredCostState = {
|
||||
totalCostUSD: number
|
||||
totalAPIDuration: number
|
||||
totalAPIDurationWithoutRetries: number
|
||||
totalToolDuration: number
|
||||
totalLinesAdded: number
|
||||
totalLinesRemoved: number
|
||||
lastDuration: number | undefined
|
||||
modelUsage: { [modelName: string]: ModelUsage }
|
||||
}
|
||||
|
||||
type ModelUsage = {
|
||||
inputTokens: number
|
||||
outputTokens: number
|
||||
cacheReadInputTokens: number
|
||||
cacheCreationInputTokens: number
|
||||
webSearchRequests: number
|
||||
costUSD: number
|
||||
contextWindow: number
|
||||
maxOutputTokens: number
|
||||
}
|
||||
```
|
||||
|
||||
### 6.3 成本计算
|
||||
|
||||
```typescript
|
||||
export function addToTotalSessionCost(
|
||||
cost: number,
|
||||
usage: Usage,
|
||||
model: string,
|
||||
): number {
|
||||
const modelUsage = addToTotalModelUsage(cost, usage, model)
|
||||
addToTotalCostState(cost, modelUsage, model)
|
||||
|
||||
// 发送到 Statsig 计数器
|
||||
getCostCounter()?.add(cost, { model })
|
||||
getTokenCounter()?.add(usage.input_tokens, { ...attrs, type: 'input' })
|
||||
getTokenCounter()?.add(usage.output_tokens, { ...attrs, type: 'output' })
|
||||
|
||||
// 处理 Advisor 使用量
|
||||
for (const advisorUsage of getAdvisorUsage(usage)) {
|
||||
const advisorCost = calculateUSDCost(advisorUsage.model, advisorUsage)
|
||||
totalCost += addToTotalSessionCost(advisorCost, advisorUsage, advisorUsage.model)
|
||||
}
|
||||
return totalCost
|
||||
}
|
||||
```
|
||||
|
||||
### 6.4 成本格式化
|
||||
|
||||
```typescript
|
||||
export function formatTotalCost(): string {
|
||||
const costDisplay = formatCost(getTotalCostUSD())
|
||||
|
||||
return chalk.dim(`
|
||||
Total cost: ${costDisplay}
|
||||
Total duration (API): ${formatDuration(getTotalAPIDuration())}
|
||||
Total duration (wall): ${formatDuration(getTotalDuration())}
|
||||
Total code changes: ${linesAdded} lines added, ${linesRemoved} lines removed
|
||||
${formatModelUsage()}
|
||||
`)
|
||||
}
|
||||
```
|
||||
|
||||
### 6.5 会话成本保存/恢复
|
||||
|
||||
```typescript
|
||||
// 保存当前会话成本到项目配置
|
||||
export function saveCurrentSessionCosts(fpsMetrics?: FpsMetrics): void {
|
||||
saveCurrentProjectConfig(current => ({
|
||||
...current,
|
||||
lastCost: getTotalCostUSD(),
|
||||
lastAPIDuration: getTotalAPIDuration(),
|
||||
lastLinesAdded: getTotalLinesAdded(),
|
||||
lastLinesRemoved: getTotalLinesRemoved(),
|
||||
lastModelUsage: Object.fromEntries(...),
|
||||
lastSessionId: getSessionId(),
|
||||
}))
|
||||
}
|
||||
|
||||
// 恢复会话成本
|
||||
export function restoreCostStateForSession(sessionId: string): boolean {
|
||||
const data = getStoredSessionCosts(sessionId)
|
||||
if (!data) return false
|
||||
setCostStateForRestore(data)
|
||||
return true
|
||||
}
|
||||
```
|
||||
|
||||
## 7. query.ts - 查询管道
|
||||
|
||||
### 7.1 功能概述
|
||||
|
||||
`query.ts` 是核心的查询处理管道,负责:
|
||||
|
||||
- 消息流式 API 调用
|
||||
- 工具调用编排
|
||||
- 自动压缩
|
||||
- 错误恢复
|
||||
|
||||
### 7.2 主查询循环
|
||||
|
||||
```typescript
|
||||
export async function* query(
|
||||
params: QueryParams,
|
||||
): AsyncGenerator<...> {
|
||||
const consumedCommandUuids: string[] = []
|
||||
const terminal = yield* queryLoop(params, consumedCommandUuids)
|
||||
return terminal
|
||||
}
|
||||
|
||||
async function* queryLoop(
|
||||
params: QueryParams,
|
||||
consumedCommandUuids: string[],
|
||||
): AsyncGenerator<...> {
|
||||
let state: State = {
|
||||
messages: params.messages,
|
||||
toolUseContext: params.toolUseContext,
|
||||
autoCompactTracking: undefined,
|
||||
maxOutputTokensRecoveryCount: 0,
|
||||
// ...
|
||||
}
|
||||
|
||||
while (true) {
|
||||
// 1. 上下文压缩
|
||||
const { compactionResult } = await deps.autocompact(...)
|
||||
|
||||
// 2. API 调用循环
|
||||
for await (const message of deps.callModel({...})) {
|
||||
if (message.type === 'assistant') {
|
||||
assistantMessages.push(message)
|
||||
// 处理工具调用块
|
||||
}
|
||||
}
|
||||
|
||||
// 3. 工具执行
|
||||
if (needsFollowUp) {
|
||||
const toolUpdates = runTools(toolUseBlocks, ...)
|
||||
for await (const update of toolUpdates) {
|
||||
// 处理工具结果
|
||||
}
|
||||
}
|
||||
|
||||
// 4. 递归继续
|
||||
state = { ...state, messages: [...messages, ...assistantMessages, ...toolResults] }
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### 7.3 工具执行编排
|
||||
|
||||
```typescript
|
||||
// 两种工具执行模式
|
||||
if (streamingToolExecutor) {
|
||||
// 流式工具执行:在模型流式输出的同时执行工具
|
||||
logEvent('tengu_streaming_tool_execution_used', {...})
|
||||
} else {
|
||||
// 批量工具执行:等待模型完全响应后执行
|
||||
logEvent('tengu_streaming_tool_execution_not_used', {...})
|
||||
}
|
||||
|
||||
const toolUpdates = streamingToolExecutor
|
||||
? streamingToolExecutor.getRemainingResults()
|
||||
: runTools(toolUseBlocks, assistantMessages, canUseTool, toolUseContext)
|
||||
```
|
||||
|
||||
### 7.4 错误恢复机制
|
||||
|
||||
```typescript
|
||||
// 1. 模型回退
|
||||
if (innerError instanceof FallbackTriggeredError && fallbackModel) {
|
||||
currentModel = fallbackModel
|
||||
attemptWithFallback = true
|
||||
continue
|
||||
}
|
||||
|
||||
// 2. Prompt Too Long 恢复
|
||||
if (isWithheld413) {
|
||||
// 尝试排空上下文折叠
|
||||
const drained = contextCollapse.recoverFromOverflow(...)
|
||||
if (drained.committed > 0) {
|
||||
state = { ...state, messages: drained.messages }
|
||||
continue
|
||||
}
|
||||
|
||||
// 尝试响应式压缩
|
||||
const compacted = await reactiveCompact.tryReactiveCompact(...)
|
||||
if (compacted) {
|
||||
// ...
|
||||
}
|
||||
}
|
||||
|
||||
// 3. Max Output Tokens 恢复
|
||||
if (maxOutputTokensRecoveryCount < MAX_OUTPUT_TOKENS_RECOVERY_LIMIT) {
|
||||
const recoveryMessage = createUserMessage({
|
||||
content: `Output token limit hit. Resume directly...`
|
||||
})
|
||||
state = { ...state, messages: [...messages, recoveryMessage] }
|
||||
continue
|
||||
}
|
||||
```
|
||||
|
||||
### 7.5 上下文压缩
|
||||
|
||||
```typescript
|
||||
// Snip(去除)压缩
|
||||
if (feature('HISTORY_SNIP')) {
|
||||
const snipResult = snipModule!.snipCompactIfNeeded(messagesForQuery)
|
||||
messagesForQuery = snipResult.messages
|
||||
snipTokensFreed = snipResult.tokensFreed
|
||||
}
|
||||
|
||||
// 微压缩
|
||||
const microcompactResult = await deps.microcompact(messagesForQuery, ...)
|
||||
messagesForQuery = microcompactResult.messages
|
||||
|
||||
// 自动压缩
|
||||
const { compactionResult } = await deps.autocompact(
|
||||
messagesForQuery,
|
||||
toolUseContext,
|
||||
{ systemPrompt, userContext, systemContext, toolUseContext },
|
||||
querySource,
|
||||
tracking,
|
||||
snipTokensFreed,
|
||||
)
|
||||
```
|
||||
|
||||
### 7.6 工具使用摘要
|
||||
|
||||
```typescript
|
||||
// 为耗时的 Haiku 调用生成工具使用摘要
|
||||
if (config.gates.emitToolUseSummaries && toolUseBlocks.length > 0) {
|
||||
const summary = await generateToolUseSummary({
|
||||
tools: toolInfoForSummary,
|
||||
signal: toolUseContext.abortController.signal,
|
||||
lastAssistantText,
|
||||
})
|
||||
|
||||
// 异步生成,不阻塞下一个 API 调用
|
||||
nextPendingToolUseSummary = summary.then(s =>
|
||||
s ? createToolUseSummaryMessage(summary, toolUseIds) : null
|
||||
)
|
||||
}
|
||||
```
|
||||
|
||||
## 8. 总结
|
||||
|
||||
这七个核心文件共同构成了 Claude Code 的核心架构:
|
||||
|
||||
| 文件 | 职责 |
|
||||
|------|------|
|
||||
| `main.tsx` | CLI 入口,应用程序初始化 |
|
||||
| `QueryEngine.ts` | 对话生命周期管理,消息处理 |
|
||||
| `Tool.ts` | 工具基类和接口定义 |
|
||||
| `commands.ts` | Slash 命令注册和管理 |
|
||||
| `context.ts` | 系统/用户上下文收集 |
|
||||
| `cost-tracker.ts` | Token 成本追踪 |
|
||||
| `query.ts` | API 调用管道,工具编排 |
|
||||
|
||||
理解这些核心模块是深入研究 Claude Code 源码的基础。
|
||||
949
claude-code-中文Wiki/03-工具系统.md
Normal file
949
claude-code-中文Wiki/03-工具系统.md
Normal file
@@ -0,0 +1,949 @@
|
||||
# 工具系统详解
|
||||
|
||||
本文件说明:详细介绍 Claude Code 的工具系统,包括所有内置工具的功能、输入 schema、权限模型和核心逻辑。
|
||||
|
||||
## 1. 工具系统架构
|
||||
|
||||
### 1.1 工具注册表
|
||||
|
||||
所有内置工具在 `tools.ts` 中注册:
|
||||
|
||||
```typescript
|
||||
export function getAllBaseTools(): Tools {
|
||||
return [
|
||||
AgentTool,
|
||||
TaskOutputTool,
|
||||
BashTool,
|
||||
GlobTool,
|
||||
GrepTool,
|
||||
ExitPlanModeV2Tool,
|
||||
FileReadTool,
|
||||
FileEditTool,
|
||||
FileWriteTool,
|
||||
NotebookEditTool,
|
||||
WebFetchTool,
|
||||
TodoWriteTool,
|
||||
WebSearchTool,
|
||||
TaskStopTool,
|
||||
AskUserQuestionTool,
|
||||
SkillTool,
|
||||
EnterPlanModeTool,
|
||||
// ... 更多工具
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
### 1.2 工具调用流程
|
||||
|
||||
```
|
||||
用户输入/模型决策
|
||||
│
|
||||
▼
|
||||
checkPermissions() ────► 权限检查
|
||||
│
|
||||
▼
|
||||
validateInput() ────► 输入验证
|
||||
│
|
||||
▼
|
||||
call() ───────────► 工具执行
|
||||
│
|
||||
▼
|
||||
renderToolResultMessage() ────► 结果渲染
|
||||
```
|
||||
|
||||
### 1.3 工具基类接口
|
||||
|
||||
所有工具都实现以下核心方法:
|
||||
|
||||
| 方法 | 描述 |
|
||||
|------|------|
|
||||
| `call(args, context, canUseTool, parentMessage)` | 工具执行入口 |
|
||||
| `description(input, options)` | 获取工具描述 |
|
||||
| `inputSchema` | 输入参数 Zod Schema |
|
||||
| `checkPermissions(input, context)` | 权限检查 |
|
||||
| `validateInput(input, context)` | 输入验证 |
|
||||
| `renderToolUseMessage(input, options)` | 渲染工具调用消息 |
|
||||
| `renderToolResultMessage(content, options)` | 渲染工具结果 |
|
||||
|
||||
## 2. BashTool - Shell 命令执行
|
||||
|
||||
### 2.1 功能描述
|
||||
|
||||
BashTool 是 Claude Code 最核心的工具之一,负责在用户授权下执行 Shell 命令。
|
||||
|
||||
### 2.2 输入 Schema
|
||||
|
||||
```typescript
|
||||
const inputSchema = z.object({
|
||||
command: z.string().describe('要执行的命令'),
|
||||
cwd: z.string().optional().describe('工作目录'),
|
||||
timeout: z.number().optional().describe('超时时间(毫秒)'),
|
||||
})
|
||||
```
|
||||
|
||||
### 2.3 权限模型
|
||||
|
||||
**权限检查规则**:
|
||||
1. 检查命令是否匹配 `alwaysAllowRules`
|
||||
2. 检查命令是否匹配 `alwaysDenyRules`
|
||||
3. 检查命令是否属于危险命令(如 `rm -rf`)
|
||||
4. 用户确认后执行
|
||||
|
||||
**危险命令警告**:
|
||||
- `rm -rf` 类删除命令
|
||||
- 格式化命令(如 `mkfs`)
|
||||
- 覆盖系统文件
|
||||
|
||||
### 2.4 核心逻辑
|
||||
|
||||
```typescript
|
||||
async call({ command, cwd, timeout }, context) {
|
||||
// 1. 展开路径
|
||||
const fullCommand = expandPath(command)
|
||||
|
||||
// 2. 权限检查
|
||||
const decision = await checkBashPermission(fullCommand, context)
|
||||
|
||||
// 3. 决定是否使用沙箱
|
||||
const shouldSandbox = await shouldUseSandbox(fullCommand)
|
||||
|
||||
// 4. 执行命令
|
||||
if (shouldSandbox) {
|
||||
return executeInSandbox(fullCommand, cwd, timeout)
|
||||
} else {
|
||||
return executeDirect(fullCommand, cwd, timeout)
|
||||
}
|
||||
|
||||
// 5. 追踪文件变更
|
||||
if (result.modifiedFiles) {
|
||||
for (const file of result.modifiedFiles) {
|
||||
updateFileHistory(file, 'modified')
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### 2.5 沙箱执行
|
||||
|
||||
Claude Code 支持使用沙箱执行危险命令:
|
||||
|
||||
```typescript
|
||||
async function shouldUseSandbox(command: string): Promise<boolean> {
|
||||
// 检测命令是否危险
|
||||
const isDangerous = detectDangerousCommand(command)
|
||||
|
||||
// 检查用户是否设置了沙箱偏好
|
||||
const sandboxPreference = getSandboxPreference()
|
||||
|
||||
return isDangerous || sandboxPreference === 'always'
|
||||
}
|
||||
```
|
||||
|
||||
## 3. FileReadTool - 文件读取
|
||||
|
||||
### 3.1 功能描述
|
||||
|
||||
FileReadTool 用于读取文件内容,支持多种文件类型:
|
||||
|
||||
- 纯文本文件
|
||||
- 图片文件(PNG, JPG, GIF, WebP)
|
||||
- PDF 文档
|
||||
- Jupyter Notebooks
|
||||
|
||||
### 3.2 输入 Schema
|
||||
|
||||
```typescript
|
||||
const inputSchema = z.object({
|
||||
file_path: z.string().describe('要读取的文件绝对路径'),
|
||||
offset: z.number().int().nonnegative().optional().describe('起始行号'),
|
||||
limit: z.number().int().positive().optional().describe('读取行数'),
|
||||
pages: z.string().optional().describe('PDF 页码范围(如 "1-5")'),
|
||||
})
|
||||
```
|
||||
|
||||
### 3.3 权限模型
|
||||
|
||||
- 检查文件路径是否在允许目录下
|
||||
- 检查是否匹配 deny rules
|
||||
- 检查是否为会话相关文件(特殊处理)
|
||||
|
||||
### 3.4 核心逻辑
|
||||
|
||||
```typescript
|
||||
async call({ file_path, offset = 1, limit, pages }, context) {
|
||||
const ext = path.extname(file_path).toLowerCase()
|
||||
|
||||
// 根据文件类型处理
|
||||
if (ext === '.ipynb') {
|
||||
return readNotebook(file_path)
|
||||
} else if (IMAGE_EXTENSIONS.has(ext)) {
|
||||
return readImage(file_path)
|
||||
} else if (ext === '.pdf') {
|
||||
return readPDF(file_path, pages)
|
||||
} else {
|
||||
return readTextFile(file_path, offset, limit)
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### 3.5 特殊处理
|
||||
|
||||
**Deduplication(去重)**:
|
||||
- 如果文件未修改且读取范围相同,返回 `file_unchanged` stub
|
||||
- 避免重复发送相同内容浪费 Token
|
||||
|
||||
**内存新鲜度提示**:
|
||||
```typescript
|
||||
function memoryFileFreshnessNote(mtimeMs: number): string {
|
||||
const age = Date.now() - mtimeMs
|
||||
if (age < 60000) return '(updated seconds ago)'
|
||||
if (age < 3600000) return `(updated ${Math.floor(age/60000)}m ago)`
|
||||
// ...
|
||||
}
|
||||
```
|
||||
|
||||
## 4. FileWriteTool - 文件写入
|
||||
|
||||
### 4.1 功能描述
|
||||
|
||||
FileWriteTool 用于创建或覆盖文件内容。
|
||||
|
||||
### 4.2 输入 Schema
|
||||
|
||||
```typescript
|
||||
const inputSchema = z.object({
|
||||
file_path: z.string().describe('文件路径'),
|
||||
content: z.string().describe('文件内容'),
|
||||
})
|
||||
```
|
||||
|
||||
### 4.3 权限模型
|
||||
|
||||
- 写入权限检查
|
||||
- 目录创建权限
|
||||
- 危险路径保护(如 `/etc`、`/System`)
|
||||
|
||||
### 4.4 核心逻辑
|
||||
|
||||
```typescript
|
||||
async call({ file_path, content }, context) {
|
||||
// 1. 验证路径
|
||||
const fullPath = expandPath(file_path)
|
||||
|
||||
// 2. 安全检查
|
||||
if (isDangerousPath(fullPath)) {
|
||||
throw new Error('Cannot write to protected path')
|
||||
}
|
||||
|
||||
// 3. 确保目录存在
|
||||
const dir = path.dirname(fullPath)
|
||||
await ensureDirExists(dir)
|
||||
|
||||
// 4. 写入文件
|
||||
await writeFile(fullPath, content)
|
||||
|
||||
// 5. 更新文件状态缓存
|
||||
context.readFileState.set(fullPath, {
|
||||
content,
|
||||
timestamp: Date.now(),
|
||||
})
|
||||
|
||||
return { success: true, path: fullPath }
|
||||
}
|
||||
```
|
||||
|
||||
## 5. FileEditTool - 文件编辑
|
||||
|
||||
### 5.1 功能描述
|
||||
|
||||
FileEditTool 支持两种编辑模式:
|
||||
|
||||
1. **Search/Replace 模式**:通过 old_string 和 new_string 进行替换
|
||||
2. **Edit 模式**:直接编辑文件内容
|
||||
|
||||
### 5.2 输入 Schema
|
||||
|
||||
```typescript
|
||||
const inputSchema = z.object({
|
||||
file_path: z.string().describe('文件路径'),
|
||||
old_string: z.string().optional().describe('要替换的文本(精确匹配)'),
|
||||
new_string: z.string().optional().describe('替换后的文本'),
|
||||
// 或者使用 partial_diff
|
||||
partial_diff: z.object({
|
||||
replacements: z.array(z.object({
|
||||
old_string: z.string(),
|
||||
new_string: z.string(),
|
||||
}))
|
||||
}).optional()
|
||||
})
|
||||
```
|
||||
|
||||
### 5.3 权限模型
|
||||
|
||||
- 需要有效的 old_string(防止意外覆盖)
|
||||
- 不能用于删除整个文件
|
||||
- 禁止编辑二进制文件
|
||||
|
||||
### 5.4 核心逻辑
|
||||
|
||||
```typescript
|
||||
async call({ file_path, old_string, new_string, partial_diff }, context) {
|
||||
// 1. 读取当前文件内容
|
||||
const content = await readFile(file_path)
|
||||
|
||||
// 2. 执行替换
|
||||
let newContent: string
|
||||
|
||||
if (partial_diff) {
|
||||
// 批量替换
|
||||
newContent = content
|
||||
for (const { old_string, new_string } of partial_diff.replacements) {
|
||||
newContent = applyReplacement(newContent, old_string, new_string)
|
||||
}
|
||||
} else {
|
||||
// 单次替换
|
||||
newContent = applyReplacement(content, old_string, new_string)
|
||||
}
|
||||
|
||||
// 3. 验证 old_string 存在且唯一
|
||||
const occurrences = countOccurrences(content, old_string)
|
||||
if (occurrences === 0) {
|
||||
throw new Error('old_string not found in file')
|
||||
}
|
||||
if (occurrences > 1) {
|
||||
throw new Error('old_string appears multiple times, be more specific')
|
||||
}
|
||||
|
||||
// 4. 写入文件
|
||||
await writeFile(file_path, newContent)
|
||||
|
||||
// 5. 更新缓存
|
||||
context.readFileState.set(file_path, {
|
||||
content: newContent,
|
||||
timestamp: Date.now(),
|
||||
})
|
||||
}
|
||||
```
|
||||
|
||||
## 6. GlobTool - 文件模式匹配
|
||||
|
||||
### 6.1 功能描述
|
||||
|
||||
使用 glob 模式查找文件。
|
||||
|
||||
### 6.2 输入 Schema
|
||||
|
||||
```typescript
|
||||
const inputSchema = z.object({
|
||||
pattern: z.string().describe('Glob 模式(如 "**/*.ts")'),
|
||||
cwd: z.string().optional().describe('搜索根目录'),
|
||||
})
|
||||
```
|
||||
|
||||
### 6.3 核心逻辑
|
||||
|
||||
```typescript
|
||||
async call({ pattern, cwd }, context) {
|
||||
// 使用 ripgrep 的 glob 功能实现高性能搜索
|
||||
const results = await execFile('rg', [
|
||||
'--files-with-matches',
|
||||
'--glob', pattern,
|
||||
cwd || process.cwd()
|
||||
])
|
||||
|
||||
return {
|
||||
files: results.split('\n').filter(Boolean)
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## 7. GrepTool - 代码搜索
|
||||
|
||||
### 7.1 功能描述
|
||||
|
||||
在代码库中搜索匹配文本。
|
||||
|
||||
### 7.2 输入 Schema
|
||||
|
||||
```typescript
|
||||
const inputSchema = z.object({
|
||||
pattern: z.string().describe('搜索模式(支持正则)'),
|
||||
cwd: z.string().optional().describe('搜索目录'),
|
||||
context: z.number().optional().describe('上下文行数'),
|
||||
file_pattern: z.string().optional().describe('文件过滤模式'),
|
||||
})
|
||||
```
|
||||
|
||||
### 7.3 核心逻辑
|
||||
|
||||
```typescript
|
||||
async call({ pattern, cwd, context = 3, file_pattern }, context) {
|
||||
const args = [
|
||||
'--json',
|
||||
'-C', context.toString(),
|
||||
pattern,
|
||||
]
|
||||
|
||||
if (file_pattern) {
|
||||
args.push('--glob', file_pattern)
|
||||
}
|
||||
|
||||
args.push(cwd || '.')
|
||||
|
||||
const results = await execFile('rg', args)
|
||||
|
||||
// 解析 JSON 输出
|
||||
const matches = JSON.parse(results)
|
||||
|
||||
return {
|
||||
matches: matches.map(parseMatch),
|
||||
count: matches.length
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## 8. WebFetchTool - 网页获取
|
||||
|
||||
### 8.1 功能描述
|
||||
|
||||
获取网页内容。
|
||||
|
||||
### 8.2 输入 Schema
|
||||
|
||||
```typescript
|
||||
const inputSchema = z.object({
|
||||
url: z.string().url().describe('网页 URL'),
|
||||
})
|
||||
```
|
||||
|
||||
### 8.3 权限模型
|
||||
|
||||
**预批准域名列表**:
|
||||
- anthropic.com
|
||||
- claude.ai
|
||||
- github.com
|
||||
- 主要新闻和文档站点
|
||||
|
||||
### 8.4 核心逻辑
|
||||
|
||||
```typescript
|
||||
async call({ url }, context) {
|
||||
// 1. URL 安全检查
|
||||
if (!isPreapprovedUrl(url)) {
|
||||
const decision = await context.requestPrompt('web_fetch', url)
|
||||
if (!decision.approved) {
|
||||
throw new Error('URL not approved')
|
||||
}
|
||||
}
|
||||
|
||||
// 2. 获取网页
|
||||
const response = await fetch(url)
|
||||
|
||||
// 3. 解析 HTML
|
||||
const text = await extractText(response)
|
||||
|
||||
// 4. 清理和格式化
|
||||
return {
|
||||
content: cleanHtml(text),
|
||||
title: extractTitle(response),
|
||||
url,
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## 9. WebSearchTool - 网络搜索
|
||||
|
||||
### 9.1 功能描述
|
||||
|
||||
执行网络搜索。
|
||||
|
||||
### 9.2 输入 Schema
|
||||
|
||||
```typescript
|
||||
const inputSchema = z.object({
|
||||
query: z.string().describe('搜索查询'),
|
||||
})
|
||||
```
|
||||
|
||||
### 9.3 核心逻辑
|
||||
|
||||
```typescript
|
||||
async call({ query }, context) {
|
||||
// 使用搜索引擎 API
|
||||
const results = await searchEngine.query(query)
|
||||
|
||||
return {
|
||||
results: results.map(r => ({
|
||||
title: r.title,
|
||||
url: r.url,
|
||||
snippet: r.snippet,
|
||||
})),
|
||||
total: results.length,
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## 10. AgentTool - 子 Agent
|
||||
|
||||
### 10.1 功能描述
|
||||
|
||||
AgentTool 允许 Claude 创建和管理子 Agent 来并行执行任务。
|
||||
|
||||
### 10.2 输入 Schema
|
||||
|
||||
```typescript
|
||||
const inputSchema = z.object({
|
||||
agent: z.enum(['general', 'plan', 'explore', ...]).describe('Agent 类型'),
|
||||
prompt: z.string().describe('给 Agent 的指令'),
|
||||
agentId: z.string().optional().describe('现有 Agent ID(用于恢复)'),
|
||||
maxTurns: z.number().optional().describe('最大轮次'),
|
||||
})
|
||||
```
|
||||
|
||||
### 10.3 Agent 类型
|
||||
|
||||
| 类型 | 描述 |
|
||||
|------|------|
|
||||
| `general` | 通用任务执行 |
|
||||
| `plan` | 计划制定 |
|
||||
| `explore` | 代码探索 |
|
||||
| `verification` | 验证检查 |
|
||||
|
||||
### 10.4 核心逻辑
|
||||
|
||||
```typescript
|
||||
async call({ agent, prompt, maxTurns }, context) {
|
||||
// 1. 创建或恢复 Agent
|
||||
const agentId = await createSubAgent({
|
||||
type: agent,
|
||||
prompt,
|
||||
maxTurns,
|
||||
})
|
||||
|
||||
// 2. 执行 Agent
|
||||
const result = await runAgent(agentId, context)
|
||||
|
||||
// 3. 返回结果
|
||||
return {
|
||||
output: result.output,
|
||||
agentId,
|
||||
turns: result.turns,
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## 11. SkillTool - 技能执行
|
||||
|
||||
### 11.1 功能描述
|
||||
|
||||
SkillTool 用于执行用户定义的技能(Skills),这些技能以 Markdown 文件形式保存在本地目录中。
|
||||
|
||||
### 11.2 输入 Schema
|
||||
|
||||
```typescript
|
||||
const inputSchema = z.object({
|
||||
name: z.string().describe('技能名称'),
|
||||
args: z.string().optional().describe('传递给技能的参数'),
|
||||
})
|
||||
```
|
||||
|
||||
### 11.3 技能定义格式
|
||||
|
||||
技能目录结构:
|
||||
```
|
||||
~/.claude/skills/my-skill/
|
||||
└── skill.md
|
||||
```
|
||||
|
||||
skill.md 格式:
|
||||
```markdown
|
||||
---
|
||||
name: my-skill
|
||||
description: 这个技能做什么
|
||||
---
|
||||
|
||||
# My Skill
|
||||
|
||||
这个技能用于执行特定任务...
|
||||
|
||||
## 使用方法
|
||||
|
||||
执行时会运行以下脚本...
|
||||
```
|
||||
|
||||
### 11.4 核心逻辑
|
||||
|
||||
```typescript
|
||||
async call({ name, args }, context) {
|
||||
// 1. 查找技能定义
|
||||
const skill = await findSkill(name)
|
||||
|
||||
if (!skill) {
|
||||
throw new Error(`Skill not found: ${name}`)
|
||||
}
|
||||
|
||||
// 2. 解析技能定义
|
||||
const { prompt, script } = parseSkillDefinition(skill)
|
||||
|
||||
// 3. 执行脚本
|
||||
const output = await executeScript(script, { args })
|
||||
|
||||
return {
|
||||
output,
|
||||
skillName: name,
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## 12. MCPTool - Model Context Protocol
|
||||
|
||||
### 12.1 功能描述
|
||||
|
||||
MCPTool 是 MCP(Model Context Protocol)协议的工具包装器,允许调用 MCP 服务器提供的工具。
|
||||
|
||||
### 12.2 输入 Schema
|
||||
|
||||
```typescript
|
||||
const inputSchema = z.object({
|
||||
server: z.string().describe('MCP 服务器名称'),
|
||||
tool: z.string().describe('工具名称'),
|
||||
arguments: z.record(z.string(), z.unknown()).optional().describe('工具参数'),
|
||||
})
|
||||
```
|
||||
|
||||
### 12.3 核心逻辑
|
||||
|
||||
```typescript
|
||||
async call({ server, tool, arguments }, context) {
|
||||
// 1. 获取 MCP 客户端
|
||||
const client = context.mcpClients.find(c => c.name === server)
|
||||
|
||||
if (!client) {
|
||||
throw new Error(`MCP server not found: ${server}`)
|
||||
}
|
||||
|
||||
// 2. 发送工具调用请求
|
||||
const result = await client.callTool(tool, arguments)
|
||||
|
||||
// 3. 返回结果
|
||||
return result
|
||||
}
|
||||
```
|
||||
|
||||
## 13. LSPTool - 语言服务器协议
|
||||
|
||||
### 13.1 功能描述
|
||||
|
||||
LSPTool 提供对 Language Server Protocol 的访问,用于代码导航、诊断等。
|
||||
|
||||
### 13.2 核心功能
|
||||
|
||||
- 跳转到定义 (Go to Definition)
|
||||
- 查找引用 (Find References)
|
||||
- 代码补全 (Completions)
|
||||
- 诊断信息 (Diagnostics)
|
||||
|
||||
## 14. NotebookEditTool - Jupyter Notebook 编辑
|
||||
|
||||
### 14.1 功能描述
|
||||
|
||||
NotebookEditTool 专门用于编辑 Jupyter Notebook 文件。
|
||||
|
||||
### 14.2 输入 Schema
|
||||
|
||||
```typescript
|
||||
const inputSchema = z.object({
|
||||
file_path: z.string().describe('Notebook 文件路径'),
|
||||
cell_id: z.string().optional().describe('要编辑的单元格 ID'),
|
||||
new_source: z.string().optional().describe('新单元格内容'),
|
||||
action: z.enum(['insert', 'delete', 'move']).optional().describe('操作类型'),
|
||||
})
|
||||
```
|
||||
|
||||
## 15. Task 系列工具
|
||||
|
||||
### 15.1 概述
|
||||
|
||||
Task 系列工具提供完整的任务管理功能:
|
||||
|
||||
| 工具 | 描述 |
|
||||
|------|------|
|
||||
| `TaskCreateTool` | 创建新任务 |
|
||||
| `TaskGetTool` | 获取任务详情 |
|
||||
| `TaskUpdateTool` | 更新任务状态 |
|
||||
| `TaskListTool` | 列出任务 |
|
||||
| `TaskStopTool` | 停止任务 |
|
||||
| `TaskOutputTool` | 获取任务输出 |
|
||||
|
||||
### 15.2 TaskCreateTool 输入 Schema
|
||||
|
||||
```typescript
|
||||
const inputSchema = z.object({
|
||||
description: z.string().describe('任务描述'),
|
||||
status: z.enum(['pending', 'in_progress', 'completed']).optional(),
|
||||
priority: z.enum(['low', 'medium', 'high']).optional(),
|
||||
})
|
||||
```
|
||||
|
||||
### 15.3 任务状态流转
|
||||
|
||||
```
|
||||
pending ──► in_progress ──► completed
|
||||
│ │
|
||||
└──────► failed
|
||||
```
|
||||
|
||||
## 16. SendMessageTool - 团队消息
|
||||
|
||||
### 16.1 功能描述
|
||||
|
||||
SendMessageTool 用于向团队成员发送消息。
|
||||
|
||||
### 16.2 输入 Schema
|
||||
|
||||
```typescript
|
||||
const inputSchema = z.object({
|
||||
recipient: z.string().describe('收件人标识'),
|
||||
message: z.string().describe('消息内容'),
|
||||
})
|
||||
```
|
||||
|
||||
## 17. TeamCreateTool - 创建团队
|
||||
|
||||
### 17.1 功能描述
|
||||
|
||||
TeamCreateTool 创建一个 Agent 团队,团队成员可以协作完成任务。
|
||||
|
||||
### 17.2 输入 Schema
|
||||
|
||||
```typescript
|
||||
const inputSchema = z.object({
|
||||
name: z.string().describe('团队名称'),
|
||||
members: z.array(z.object({
|
||||
name: z.string(),
|
||||
role: z.enum(['coordinator', 'worker', 'reviewer']),
|
||||
agentType: z.string().optional(),
|
||||
})).describe('团队成员'),
|
||||
})
|
||||
```
|
||||
|
||||
### 17.3 团队角色
|
||||
|
||||
| 角色 | 描述 |
|
||||
|------|------|
|
||||
| `coordinator` | 协调者,负责分配任务 |
|
||||
| `worker` | 执行者,负责完成任务 |
|
||||
| `reviewer` | 审核者,负责检查结果 |
|
||||
|
||||
## 18. EnterPlanModeTool / ExitPlanModeTool
|
||||
|
||||
### 18.1 功能描述
|
||||
|
||||
计划模式允许 Claude 在执行前先制定计划,用户确认后再执行。
|
||||
|
||||
### 18.2 输入 Schema
|
||||
|
||||
```typescript
|
||||
// EnterPlanModeTool
|
||||
const inputSchema = z.object({
|
||||
prompt: z.string().optional().describe('计划提示'),
|
||||
})
|
||||
|
||||
// ExitPlanModeTool
|
||||
// 无需参数
|
||||
```
|
||||
|
||||
## 19. EnterWorktreeTool / ExitWorktreeTool
|
||||
|
||||
### 19.1 功能描述
|
||||
|
||||
用于创建和切换 Git Worktree,便于在多个分支上同时工作。
|
||||
|
||||
### 19.2 输入 Schema
|
||||
|
||||
```typescript
|
||||
// EnterWorktreeTool
|
||||
const inputSchema = z.object({
|
||||
branch: z.string().describe('分支名'),
|
||||
path: z.string().optional().describe('Worktree 路径'),
|
||||
})
|
||||
|
||||
// ExitWorktreeTool
|
||||
const inputSchema = z.object({
|
||||
path: z.string().optional().describe('要删除的 Worktree 路径'),
|
||||
})
|
||||
```
|
||||
|
||||
## 20. ToolSearchTool - 工具搜索
|
||||
|
||||
### 20.1 功能描述
|
||||
|
||||
ToolSearchTool 允许模型在运行时搜索可用工具,当工具过多时会延迟加载。
|
||||
|
||||
### 20.2 输入 Schema
|
||||
|
||||
```typescript
|
||||
const inputSchema = z.object({
|
||||
query: z.string().describe('搜索查询'),
|
||||
})
|
||||
```
|
||||
|
||||
### 20.3 延迟加载机制
|
||||
|
||||
```typescript
|
||||
// 当工具数量超过阈值时启用延迟加载
|
||||
const TOOL_SEARCH_THRESHOLD = 50
|
||||
|
||||
if (totalTools > TOOL_SEARCH_THRESHOLD) {
|
||||
// 工具标记为 shouldDefer: true
|
||||
// 首次调用时需要通过 ToolSearchTool 激活
|
||||
}
|
||||
```
|
||||
|
||||
## 21. CronCreateTool - 定时任务
|
||||
|
||||
### 21.1 功能描述
|
||||
|
||||
CronCreateTool 创建定时执行的任务。
|
||||
|
||||
### 21.2 输入 Schema
|
||||
|
||||
```typescript
|
||||
const inputSchema = z.object({
|
||||
schedule: z.string().describe('Cron 表达式'),
|
||||
command: z.string().describe('要执行的命令'),
|
||||
name: z.string().optional().describe('任务名称'),
|
||||
})
|
||||
```
|
||||
|
||||
## 22. RemoteTriggerTool - 远程触发
|
||||
|
||||
### 22.1 功能描述
|
||||
|
||||
RemoteTriggerTool 允许从远程触发任务执行。
|
||||
|
||||
### 22.2 输入 Schema
|
||||
|
||||
```typescript
|
||||
const inputSchema = z.object({
|
||||
trigger_id: z.string().describe('触发器 ID'),
|
||||
payload: z.record(z.string(), z.unknown()).optional().describe('传递的数据'),
|
||||
})
|
||||
```
|
||||
|
||||
## 23. SleepTool - 延迟执行
|
||||
|
||||
### 23.1 功能描述
|
||||
|
||||
SleepTool 用于在任务执行中引入延迟。
|
||||
|
||||
### 23.2 输入 Schema
|
||||
|
||||
```typescript
|
||||
const inputSchema = z.object({
|
||||
duration: z.number().describe('延迟时间(秒)'),
|
||||
})
|
||||
```
|
||||
|
||||
## 24. SyntheticOutputTool - 结构化输出
|
||||
|
||||
### 24.1 功能描述
|
||||
|
||||
SyntheticOutputTool 用于提供符合 JSON Schema 的结构化输出。
|
||||
|
||||
### 24.2 输入 Schema
|
||||
|
||||
```typescript
|
||||
const inputSchema = z.object({
|
||||
schema: z.record(z.string(), z.unknown()).describe('JSON Schema'),
|
||||
data: z.record(z.string(), z.unknown()).describe('输出数据'),
|
||||
})
|
||||
```
|
||||
|
||||
### 24.3 验证机制
|
||||
|
||||
```typescript
|
||||
async call({ schema, data }, context) {
|
||||
// 使用 Zod 验证数据
|
||||
const validator = z.object(schema)
|
||||
const result = validator.safeParse(data)
|
||||
|
||||
if (!result.success) {
|
||||
throw new Error(`Invalid output: ${result.error.message}`)
|
||||
}
|
||||
|
||||
return { validated: result.data }
|
||||
}
|
||||
```
|
||||
|
||||
## 25. 工具权限系统总结
|
||||
|
||||
### 25.1 权限模式
|
||||
|
||||
| 模式 | 描述 | 行为 |
|
||||
|------|------|------|
|
||||
| `default` | 默认模式 | 询问危险操作 |
|
||||
| `auto` | 自动模式 | 基于规则自动决定 |
|
||||
| `bypass` | 绕过模式 | 允许所有操作 |
|
||||
| `plan` | 计划模式 | 强制计划模式 |
|
||||
|
||||
### 25.2 权限检查流程
|
||||
|
||||
```
|
||||
1. validateInput() - 验证输入有效性
|
||||
│
|
||||
▼
|
||||
2. checkPermissions() - 检查权限规则
|
||||
│
|
||||
├──► alwaysAllow → 返回允许
|
||||
│
|
||||
├──► alwaysDeny → 返回拒绝
|
||||
│
|
||||
└──► 需要询问 → 等待用户确认
|
||||
```
|
||||
|
||||
### 25.3 权限规则匹配
|
||||
|
||||
```typescript
|
||||
// 权限规则支持通配符模式
|
||||
const rules = {
|
||||
'Bash(rm *)': 'deny', // 拒绝所有 rm 命令
|
||||
'Bash(git *)': 'allow', // 允许所有 git 命令
|
||||
'Read(/home/user/src/*)': 'allow', // 允许读取特定目录
|
||||
}
|
||||
```
|
||||
|
||||
## 26. 工具渲染系统
|
||||
|
||||
### 26.1 渲染方法
|
||||
|
||||
| 方法 | 用途 |
|
||||
|------|------|
|
||||
| `renderToolUseMessage` | 渲染工具调用消息 |
|
||||
| `renderToolUseTag` | 渲染工具标签(如超时标记) |
|
||||
| `renderToolUseProgressMessage` | 渲染进度消息 |
|
||||
| `renderToolResultMessage` | 渲染工具结果 |
|
||||
| `renderToolUseErrorMessage` | 渲染错误消息 |
|
||||
| `renderToolUseRejectedMessage` | 渲染拒绝消息 |
|
||||
|
||||
### 26.2 渲染选项
|
||||
|
||||
```typescript
|
||||
interface RenderOptions {
|
||||
style?: 'condensed' | 'full'
|
||||
theme?: ThemeName
|
||||
verbose?: boolean
|
||||
isTranscriptMode?: boolean
|
||||
terminalSize?: { columns: number; rows: number }
|
||||
}
|
||||
```
|
||||
|
||||
## 27. 总结
|
||||
|
||||
Claude Code 的工具系统设计遵循以下原则:
|
||||
|
||||
1. **一致性**:所有工具实现统一的 Tool 接口
|
||||
2. **安全性**:细粒度的权限控制和验证
|
||||
3. **可扩展性**:支持 MCP、插件、技能等多种扩展机制
|
||||
4. **用户控制**:用户可精确控制每个工具的使用权限
|
||||
5. **高性能**:支持流式执行、缓存、去重等优化
|
||||
569
claude-code-中文Wiki/04-命令系统.md
Normal file
569
claude-code-中文Wiki/04-命令系统.md
Normal file
@@ -0,0 +1,569 @@
|
||||
# Claude Code 命令系统详解
|
||||
|
||||
## 概述
|
||||
|
||||
Claude Code 的命令系统是用户与 CLI 交互的核心方式。每个斜杠命令(slash command)都是一个独立的模块,支持懒加载以提高启动性能。命令定义遵循统一的 `Command` 接口,包含元数据和执行逻辑。
|
||||
|
||||
## 命令类型
|
||||
|
||||
### 1. prompt 类型命令
|
||||
生成提示词发送给 AI 模型处理。
|
||||
|
||||
```typescript
|
||||
type Command = {
|
||||
type: 'prompt'
|
||||
name: string
|
||||
description: string
|
||||
contentLength: number
|
||||
source: 'builtin'
|
||||
async getPromptForCommand(args): Promise<ContentBlockParam[]>
|
||||
}
|
||||
```
|
||||
|
||||
### 2. local-jsx 类型命令
|
||||
渲染本地 React 组件的交互式命令。
|
||||
|
||||
```typescript
|
||||
type Command = {
|
||||
type: 'local-jsx'
|
||||
name: string
|
||||
description: string
|
||||
load: () => import('./xxx.js')
|
||||
}
|
||||
```
|
||||
|
||||
### 3. local 类型命令
|
||||
执行本地逻辑的命令,不涉及 AI 模型。
|
||||
|
||||
```typescript
|
||||
type Command = {
|
||||
type: 'local'
|
||||
name: string
|
||||
description: string
|
||||
supportsNonInteractive: boolean
|
||||
load: () => import('./xxx.js')
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 命令详解
|
||||
|
||||
### /commit - 创建 Git 提交
|
||||
|
||||
**文件位置**: `src/commands/commit.ts`
|
||||
|
||||
**功能描述**: 分析当前 Git 状态,生成符合项目规范的提交信息,创建新的 Git 提交。
|
||||
|
||||
**触发条件**: 用户输入 `/commit`
|
||||
|
||||
**核心逻辑**:
|
||||
1. 获取当前 Git 状态(`git status`、`git diff HEAD`、`git branch --show-current`)
|
||||
2. 获取最近 10 条提交记录以了解项目提交风格
|
||||
3. 根据变更内容生成提交信息
|
||||
4. 使用 HEREDOC 语法执行 `git commit`
|
||||
|
||||
**安全协议**:
|
||||
- 禁止更新 git config
|
||||
- 禁止跳过 hooks(除非用户明确要求)
|
||||
- 必须创建新提交,禁止使用 `--amend`
|
||||
- 禁止提交包含密钥的文件(.env 等)
|
||||
- 禁止使用需要交互输入的 git 命令(如 `git rebase -i`)
|
||||
|
||||
**相关文件**:
|
||||
- `src/commands/commit.ts` - 命令入口
|
||||
- `src/utils/attribution.js` - 获取归属文本
|
||||
|
||||
---
|
||||
|
||||
### /review - 代码审查
|
||||
|
||||
**文件位置**: `src/commands/review.ts`
|
||||
|
||||
**功能描述**: 审查 GitHub Pull Request 的代码变更。
|
||||
|
||||
**触发条件**: 用户输入 `/review [PR编号]`
|
||||
|
||||
**核心逻辑**:
|
||||
1. 若未提供 PR 编号,执行 `gh pr list` 显示打开的 PR 列表
|
||||
2. 若提供 PR 编号,执行 `gh pr view <number>` 获取详情
|
||||
3. 执行 `gh pr diff <number>` 获取代码差异
|
||||
4. 分析代码质量、风格、潜在问题、安全性等
|
||||
5. 提供改进建议
|
||||
|
||||
**本地审查提示词** (`LOCAL_REVIEW_PROMPT`):
|
||||
```
|
||||
You are an expert code reviewer. Follow these steps:
|
||||
1. If no PR number is provided, run `gh pr list`
|
||||
2. Analyze the changes and provide a thorough code review
|
||||
...
|
||||
```
|
||||
|
||||
**ultrareview 命令**:
|
||||
- 唯一入口:通过 `/ultrareview` 触发远程 Bug Hunter 路径
|
||||
- 使用 `~10-20 min` 执行深度 bug 查找
|
||||
- 需要在 Claude Code 网页版运行
|
||||
|
||||
**相关文件**:
|
||||
- `src/commands/review.ts` - 包含本地 review 和 ultrareview 命令
|
||||
- `src/commands/review/ultrareviewEnabled.ts` - ultrareview 功能开关
|
||||
|
||||
---
|
||||
|
||||
### /compact - 对话压缩
|
||||
|
||||
**文件位置**: `src/commands/compact/index.ts`, `src/commands/compact/compact.ts`
|
||||
|
||||
**功能描述**: 清除对话历史但保留摘要,保持在上下文中。
|
||||
|
||||
**触发条件**: 用户输入 `/compact [自定义摘要指令]`
|
||||
|
||||
**核心逻辑**:
|
||||
1. 首先尝试会话内存压缩(无自定义指令时)
|
||||
2. 若有自定义指令或会话内存压缩不适用,执行传统的压缩流程:
|
||||
- 执行 PreCompact hooks
|
||||
- 运行 microcompact 减少 token 数量
|
||||
- 调用 `compactConversation` 生成摘要
|
||||
- 执行 PostCompact hooks
|
||||
3. 重置文件状态缓存
|
||||
4. 生成压缩边界标记和摘要消息
|
||||
|
||||
**压缩类型**:
|
||||
- **完整压缩**: 总结整个对话历史
|
||||
- **部分压缩**: 围绕选定消息索引进行压缩
|
||||
- `from`: 总结索引之后的消息,保留早期消息
|
||||
- `up_to`: 总结索引之前的消息,保留后续消息
|
||||
|
||||
**相关服务**:
|
||||
- `src/services/compact/compact.ts` - 核心压缩逻辑
|
||||
- `src/services/compact/microCompact.ts` - 微压缩
|
||||
- `src/services/compact/sessionMemoryCompact.ts` - 会话内存压缩
|
||||
- `src/services/compact/postCompactCleanup.ts` - 压缩后清理
|
||||
|
||||
---
|
||||
|
||||
### /mcp - MCP 服务器管理
|
||||
|
||||
**文件位置**: `src/commands/mcp/index.ts`
|
||||
|
||||
**功能描述**: 管理 MCP(Model Context Protocol)服务器连接。
|
||||
|
||||
**触发条件**: 用户输入 `/mcp [enable|disable [服务器名称]]`
|
||||
|
||||
**核心逻辑**:
|
||||
1. 懒加载 MCP 管理界面组件
|
||||
2. 支持启用/禁用特定 MCP 服务器
|
||||
3. 管理 MCP 服务器配置
|
||||
|
||||
**MCP 配置类型** (`Transport`):
|
||||
- `stdio` - 标准 I/O 传输
|
||||
- `sse` - Server-Sent Events
|
||||
- `http` - HTTP 传输
|
||||
- `ws` - WebSocket
|
||||
- `sdk` - SDK 传输
|
||||
|
||||
**相关服务**:
|
||||
- `src/services/mcp/useManageMCPConnections.ts` - MCP 连接管理 Hook
|
||||
- `src/services/mcp/types.ts` - MCP 类型定义
|
||||
- `src/services/mcp/client.ts` - MCP 客户端实现
|
||||
|
||||
---
|
||||
|
||||
### /config - 配置面板
|
||||
|
||||
**文件位置**: `src/commands/config/index.ts`
|
||||
|
||||
**功能描述**: 打开配置面板,管理 Claude Code 设置。
|
||||
|
||||
**别名**: `/settings`
|
||||
|
||||
**触发条件**: 用户输入 `/config`
|
||||
|
||||
**核心逻辑**:
|
||||
- 懒加载配置面板 React 组件
|
||||
- 支持用户偏好设置、项目设置等
|
||||
|
||||
---
|
||||
|
||||
### /doctor - 诊断检查
|
||||
|
||||
**文件位置**: `src/commands/doctor/index.ts`
|
||||
|
||||
**功能描述**: 诊断和验证 Claude Code 安装状态和设置。
|
||||
|
||||
**触发条件**: 用户输入 `/doctor`
|
||||
|
||||
**核心逻辑**:
|
||||
1. 检查环境变量 `DISABLE_DOCTOR_COMMAND` 确认是否启用
|
||||
2. 懒加载诊断组件
|
||||
3. 执行多项检查:安装完整性、配置正确性、认证状态等
|
||||
|
||||
---
|
||||
|
||||
### /login - 登录
|
||||
|
||||
**文件位置**: `src/commands/login/index.ts`
|
||||
|
||||
**功能描述**: 使用 Anthropic 账户登录或切换账户。
|
||||
|
||||
**触发条件**: 用户输入 `/login`
|
||||
|
||||
**核心逻辑**:
|
||||
1. 检测是否已有 API Key 认证(`hasAnthropicApiKeyAuth()`)
|
||||
2. 根据认证状态显示不同描述
|
||||
3. 检查环境变量 `DISABLE_LOGIN_COMMAND`
|
||||
4. 懒加载登录组件
|
||||
|
||||
---
|
||||
|
||||
### /logout - 登出
|
||||
|
||||
**文件位置**: `src/commands/logout/index.ts`
|
||||
|
||||
**功能描述**: 从 Anthropic 账户登出。
|
||||
|
||||
**触发条件**: 用户输入 `/logout`
|
||||
|
||||
**核心逻辑**:
|
||||
1. 检查环境变量 `DISABLE_LOGOUT_COMMAND`
|
||||
2. 执行登出逻辑,清除认证信息
|
||||
|
||||
---
|
||||
|
||||
### /memory - 记忆文件编辑
|
||||
|
||||
**文件位置**: `src/commands/memory/index.ts`
|
||||
|
||||
**功能描述**: 编辑 Claude 记忆文件。
|
||||
|
||||
**触发条件**: 用户输入 `/memory`
|
||||
|
||||
**核心逻辑**:
|
||||
- 懒加载记忆编辑器组件
|
||||
|
||||
---
|
||||
|
||||
### /skills - 技能列表
|
||||
|
||||
**文件位置**: `src/commands/skills/index.ts`
|
||||
|
||||
**功能描述**: 列出可用的技能(Skills)。
|
||||
|
||||
**触发条件**: 用户输入 `/skills`
|
||||
|
||||
**核心逻辑**:
|
||||
- 懒加载技能列表组件
|
||||
- 显示所有已安装和可用的技能
|
||||
|
||||
---
|
||||
|
||||
### /tasks - 后台任务管理
|
||||
|
||||
**文件位置**: `src/commands/tasks/index.ts`
|
||||
|
||||
**功能描述**: 列出和管理后台任务。
|
||||
|
||||
**别名**: `/bashes`
|
||||
|
||||
**触发条件**: 用户输入 `/tasks`
|
||||
|
||||
**核心逻辑**:
|
||||
- 懒加载任务管理界面
|
||||
- 显示正在运行、完成、失败的任务
|
||||
|
||||
---
|
||||
|
||||
### /vim - Vim 模式切换
|
||||
|
||||
**文件位置**: `src/commands/vim/index.ts`, `src/commands/vim/vim.ts`
|
||||
|
||||
**功能描述**: 在 Vim 和 Normal 编辑模式之间切换。
|
||||
|
||||
**触发条件**: 用户输入 `/vim`
|
||||
|
||||
**核心逻辑**:
|
||||
- 切换 REPL 的编辑模式
|
||||
- 仅在交互式会话中可用
|
||||
|
||||
---
|
||||
|
||||
### /diff - 变更查看
|
||||
|
||||
**文件位置**: `src/commands/diff/index.ts`
|
||||
|
||||
**功能描述**: 查看未提交的变更和每轮对话的差异。
|
||||
|
||||
**触发条件**: 用户输入 `/diff`
|
||||
|
||||
**核心逻辑**:
|
||||
- 懒加载差异查看组件
|
||||
- 显示工作区与上次提交的差异
|
||||
|
||||
---
|
||||
|
||||
### /cost - 成本显示
|
||||
|
||||
**文件位置**: `src/commands/cost/index.ts`, `src/commands/cost/cost.ts`
|
||||
|
||||
**功能描述**: 显示当前会话的总成本和持续时间。
|
||||
|
||||
**触发条件**: 用户输入 `/cost`
|
||||
|
||||
**隐藏条件**:
|
||||
- Claude.ai 订阅用户(Ants 除外)默认隐藏
|
||||
- 订阅用户可看到成本明细
|
||||
|
||||
---
|
||||
|
||||
### /theme - 主题切换
|
||||
|
||||
**文件位置**: `src/commands/theme/index.ts`
|
||||
|
||||
**功能描述**: 更改终端主题。
|
||||
|
||||
**触发条件**: 用户输入 `/theme`
|
||||
|
||||
**核心逻辑**:
|
||||
- 懒加载主题选择组件
|
||||
|
||||
---
|
||||
|
||||
### /context - 上下文可视化
|
||||
|
||||
**文件位置**: `src/commands/context/index.ts`
|
||||
|
||||
**功能描述**: 将当前上下文使用情况可视化为彩色网格。
|
||||
|
||||
**触发条件**: 用户输入 `/context`
|
||||
|
||||
**交互模式变体**:
|
||||
- `context` - 交互式彩色网格(仅交互式会话)
|
||||
- `context` (非交互式) - 纯文本上下文使用情况
|
||||
|
||||
---
|
||||
|
||||
### /pr_comments - PR 评论获取
|
||||
|
||||
**文件位置**: `src/commands/pr_comments/index.ts`
|
||||
|
||||
**功能描述**: 获取 GitHub Pull Request 的评论。
|
||||
|
||||
**触发条件**: 用户输入 `/pr-comments [参数]`
|
||||
|
||||
**核心逻辑**:
|
||||
1. 使用 `gh pr view` 获取 PR 信息
|
||||
2. 使用 `gh api` 获取 PR 级评论
|
||||
3. 使用 `gh api` 获取代码审查评论
|
||||
4. 格式化显示评论列表
|
||||
|
||||
**备用方案**: 若市场不可用,使用内置提示词直接调用 GitHub CLI
|
||||
|
||||
---
|
||||
|
||||
### /resume - 恢复对话
|
||||
|
||||
**文件位置**: `src/commands/resume/index.ts`
|
||||
|
||||
**功能描述**: 恢复之前的对话。
|
||||
|
||||
**别名**: `/continue`
|
||||
|
||||
**触发条件**: 用户输入 `/resume [对话ID或搜索词]`
|
||||
|
||||
**核心逻辑**:
|
||||
- 懒加载恢复界面
|
||||
- 支持按 ID 或关键词搜索历史对话
|
||||
|
||||
---
|
||||
|
||||
### /share - 分享会话
|
||||
|
||||
**文件位置**: `src/commands/share/index.ts`
|
||||
|
||||
**功能描述**: 分享当前会话。
|
||||
|
||||
**触发条件**: 用户输入 `/share`
|
||||
|
||||
**核心逻辑**:
|
||||
- 生成分享链接或会话导出
|
||||
|
||||
---
|
||||
|
||||
### /desktop - 桌面客户端
|
||||
|
||||
**文件位置**: `src/commands/desktop/index.ts`
|
||||
|
||||
**功能描述**: 在 Claude Desktop 中继续当前会话。
|
||||
|
||||
**别名**: `/app`
|
||||
|
||||
**触发条件**: 用户输入 `/desktop`
|
||||
|
||||
**平台限制**:
|
||||
- macOS: 完全支持
|
||||
- Windows (x64): 支持
|
||||
- 其他平台: 隐藏
|
||||
|
||||
---
|
||||
|
||||
### /mobile - 移动应用
|
||||
|
||||
**文件位置**: `src/commands/mobile/index.ts`
|
||||
|
||||
**功能描述**: 显示下载 Claude 移动应用的二维码。
|
||||
|
||||
**别名**: `/ios`, `/android`
|
||||
|
||||
**触发条件**: 用户输入 `/mobile`
|
||||
|
||||
**核心逻辑**:
|
||||
- 懒加载移动应用下载界面组件
|
||||
- 显示 iOS 和 Android 的下载选项
|
||||
|
||||
---
|
||||
|
||||
### /permissions - 权限管理
|
||||
|
||||
**文件位置**: `src/commands/permissions/index.ts`
|
||||
|
||||
**功能描述**: 管理允许和拒绝的工具权限规则。
|
||||
|
||||
**别名**: `/allowed-tools`
|
||||
|
||||
**触发条件**: 用户输入 `/permissions`
|
||||
|
||||
**核心逻辑**:
|
||||
- 懒加载权限管理界面
|
||||
- 配置 `alwaysAllowRules` 等权限规则
|
||||
|
||||
---
|
||||
|
||||
### /agents - Agent 配置管理
|
||||
|
||||
**文件位置**: `src/commands/agents/index.ts`
|
||||
|
||||
**功能描述**: 管理 Agent 配置。
|
||||
|
||||
**触发条件**: 用户输入 `/agents`
|
||||
|
||||
**核心逻辑**:
|
||||
- 懒加载 Agent 管理界面
|
||||
- 支持多 Agent 配置
|
||||
|
||||
---
|
||||
|
||||
### /exit - 退出 REPL
|
||||
|
||||
**文件位置**: `src/commands/exit/index.ts`
|
||||
|
||||
**功能描述**: 退出 REPL 会话。
|
||||
|
||||
**别名**: `/quit`
|
||||
|
||||
**触发条件**: 用户输入 `/exit`
|
||||
|
||||
**特性**:
|
||||
- `immediate: true` - 立即执行,不等待 AI 响应
|
||||
|
||||
---
|
||||
|
||||
### /bridge - 远程控制
|
||||
|
||||
**文件位置**: `src/commands/bridge/index.ts`
|
||||
|
||||
**功能描述**: 连接此终端进行远程控制会话。
|
||||
|
||||
**别名**: `/rc`
|
||||
|
||||
**触发条件**: 用户输入 `/remote-control [名称]`
|
||||
|
||||
**条件限制**:
|
||||
- 需要启用 `BRIDGE_MODE` 功能
|
||||
- 需要 `isBridgeEnabled()` 返回 true
|
||||
|
||||
**核心逻辑**:
|
||||
- 建立与 Claude Code 网页版的桥接连接
|
||||
- 支持远程会话控制
|
||||
|
||||
---
|
||||
|
||||
## 命令注册机制
|
||||
|
||||
命令通过 `src/commands.js` 统一注册和管理:
|
||||
|
||||
```typescript
|
||||
export interface Command {
|
||||
type: 'prompt' | 'local-jsx' | 'local'
|
||||
name: string
|
||||
description: string
|
||||
aliases?: string[]
|
||||
load?: () => Promise<any>
|
||||
getPromptForCommand?: (args: string, context: CommandContext) => Promise<ContentBlockParam[]>
|
||||
allowedTools?: string[]
|
||||
contentLength?: number
|
||||
progressMessage?: string
|
||||
source?: 'builtin'
|
||||
isEnabled?: () => boolean
|
||||
isHidden?: boolean
|
||||
supportsNonInteractive?: boolean
|
||||
argumentHint?: string
|
||||
}
|
||||
```
|
||||
|
||||
## 懒加载机制
|
||||
|
||||
大多数命令使用懒加载模式:
|
||||
|
||||
```typescript
|
||||
const command = {
|
||||
type: 'local-jsx',
|
||||
name: 'example',
|
||||
load: () => import('./example.js'),
|
||||
}
|
||||
```
|
||||
|
||||
这确保只有实际使用的命令才会加载其代码,优化启动性能。
|
||||
|
||||
## 权限控制
|
||||
|
||||
某些命令支持 `isEnabled()` 方法动态控制可用性:
|
||||
|
||||
```typescript
|
||||
const command = {
|
||||
type: 'local',
|
||||
name: 'doctor',
|
||||
isEnabled: () => !isEnvTruthy(process.env.DISABLE_DOCTOR_COMMAND),
|
||||
load: () => import('./doctor.js'),
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 相关源码文件
|
||||
|
||||
| 命令 | 源码路径 |
|
||||
|------|---------|
|
||||
| commit | `src/commands/commit.ts` |
|
||||
| review | `src/commands/review.ts` |
|
||||
| compact | `src/commands/compact/` |
|
||||
| mcp | `src/commands/mcp/` |
|
||||
| config | `src/commands/config/` |
|
||||
| doctor | `src/commands/doctor/` |
|
||||
| login | `src/commands/login/` |
|
||||
| logout | `src/commands/logout/` |
|
||||
| memory | `src/commands/memory/` |
|
||||
| skills | `src/commands/skills/` |
|
||||
| tasks | `src/commands/tasks/` |
|
||||
| vim | `src/commands/vim/` |
|
||||
| diff | `src/commands/diff/` |
|
||||
| cost | `src/commands/cost/` |
|
||||
| theme | `src/commands/theme/` |
|
||||
| context | `src/commands/context/` |
|
||||
| resume | `src/commands/resume/` |
|
||||
| share | `src/commands/share/` |
|
||||
| desktop | `src/commands/desktop/` |
|
||||
| mobile | `src/commands/mobile/` |
|
||||
| permissions | `src/commands/permissions/` |
|
||||
| agents | `src/commands/agents/` |
|
||||
| exit | `src/commands/exit/` |
|
||||
| bridge | `src/commands/bridge/` |
|
||||
772
claude-code-中文Wiki/05-服务层详解.md
Normal file
772
claude-code-中文Wiki/05-服务层详解.md
Normal file
@@ -0,0 +1,772 @@
|
||||
# Claude Code 服务层详解
|
||||
|
||||
## 概述
|
||||
|
||||
服务层(services/)是 Claude Code 的核心业务逻辑层,提供 API 通信、协议管理、数据处理等功能。本文档详细介绍各服务的职责、实现和协作关系。
|
||||
|
||||
---
|
||||
|
||||
## 1. services/api/ - Anthropic API 客户端
|
||||
|
||||
### client.ts - API 客户端工厂
|
||||
|
||||
**文件位置**: `src/services/api/client.ts`
|
||||
|
||||
**核心功能**: 创建配置好的 Anthropic API 客户端实例。
|
||||
|
||||
**支持的认证方式**:
|
||||
|
||||
#### 1. 直接 API 访问
|
||||
```typescript
|
||||
// 环境变量: ANTHROPIC_API_KEY
|
||||
```
|
||||
|
||||
#### 2. AWS Bedrock
|
||||
```typescript
|
||||
// 环境变量配置
|
||||
AWS_REGION 或 AWS_DEFAULT_REGION
|
||||
ANTHROPIC_SMALL_FAST_MODEL_AWS_REGION (可选,用于 Haiku 模型)
|
||||
```
|
||||
- 支持 `AWS_BEARER_TOKEN_BEDROCK` 进行 API Key 认证
|
||||
- 支持自动凭证刷新
|
||||
|
||||
#### 3. Azure Foundry
|
||||
```typescript
|
||||
// 环境变量
|
||||
ANTHROPIC_FOUNDRY_RESOURCE 或 ANTHROPIC_FOUNDRY_BASE_URL
|
||||
ANTHROPIC_FOUNDRY_API_KEY (可选)
|
||||
```
|
||||
- 支持 Azure AD 认证(`DefaultAzureCredential`)
|
||||
- 支持自定义回调端口
|
||||
|
||||
#### 4. Google Vertex AI
|
||||
```typescript
|
||||
// 环境变量
|
||||
VERTEX_REGION_* (模型特定区域)
|
||||
CLOUD_ML_REGION (默认区域)
|
||||
ANTHROPIC_VERTEX_PROJECT_ID
|
||||
```
|
||||
- 支持 `google-auth-library` 凭证系统
|
||||
- 防止元数据服务器超时
|
||||
|
||||
**关键函数**:
|
||||
|
||||
```typescript
|
||||
export async function getAnthropicClient({
|
||||
apiKey,
|
||||
maxRetries,
|
||||
model,
|
||||
fetchOverride,
|
||||
source,
|
||||
}: {
|
||||
apiKey?: string
|
||||
maxRetries: number
|
||||
model?: string
|
||||
fetchOverride?: ClientOptions['fetch']
|
||||
source?: string
|
||||
}): Promise<Anthropic>
|
||||
```
|
||||
|
||||
**请求拦截**:
|
||||
- 注入自定义头:`x-app: cli`, `User-Agent`, `X-Claude-Code-Session-Id`
|
||||
- 支持 `ANTHROPIC_CUSTOM_HEADERS` 环境变量自定义头
|
||||
- 支持 `x-anthropic-additional-protection` 头
|
||||
- 生成客户端请求 ID (`x-client-request-id`) 用于追踪
|
||||
|
||||
**代理支持**:
|
||||
```typescript
|
||||
fetchOptions: getProxyFetchOptions({ forAnthropicAPI: true })
|
||||
```
|
||||
|
||||
### claude.ts - API 调用封装
|
||||
|
||||
**文件位置**: `src/services/api/claude.ts`
|
||||
|
||||
**核心功能**:
|
||||
- `queryModelWithStreaming()` - 流式查询模型
|
||||
- `getMaxOutputTokensForModel()` - 获取模型最大输出 token
|
||||
- `getPromptTooLongTokenGap()` - 解析 prompt 太长错误
|
||||
- `PROMPT_TOO_LONG_ERROR_MESSAGE` - 错误消息常量
|
||||
|
||||
### filesApi.ts - 文件 API
|
||||
|
||||
**功能**: 处理文件上传到 Claude API。
|
||||
|
||||
### errors.ts - 错误处理
|
||||
|
||||
**核心类型**:
|
||||
```typescript
|
||||
export const PROMPT_TOO_LONG_ERROR_MESSAGE =
|
||||
'Conversation too long. Press esc twice to go up a few messages and try again.'
|
||||
|
||||
export function startsWithApiErrorPrefix(text: string | null): boolean
|
||||
export function isPromptTooLongError(error: Error): boolean
|
||||
```
|
||||
|
||||
### withRetry.ts - 重试逻辑
|
||||
|
||||
**功能**: 提供指数退避重试机制。
|
||||
|
||||
```typescript
|
||||
export async function withRetry<T>(
|
||||
fn: () => Promise<T>,
|
||||
options: {
|
||||
maxRetries?: number
|
||||
initialDelayMs?: number
|
||||
maxDelayMs?: number
|
||||
}
|
||||
): Promise<T>
|
||||
```
|
||||
|
||||
### usage.ts - 使用量追踪
|
||||
|
||||
**功能**: 追踪 API 调用使用量(输入/输出 token)。
|
||||
|
||||
---
|
||||
|
||||
## 2. services/mcp/ - Model Context Protocol
|
||||
|
||||
### 类型系统 (types.ts)
|
||||
|
||||
**配置作用域** (`ConfigScope`):
|
||||
```typescript
|
||||
z.enum(['local', 'user', 'project', 'dynamic', 'enterprise', 'claudeai', 'managed'])
|
||||
```
|
||||
|
||||
**传输类型** (`Transport`):
|
||||
```typescript
|
||||
z.enum(['stdio', 'sse', 'sse-ide', 'http', 'ws', 'sdk'])
|
||||
```
|
||||
|
||||
**服务器配置**:
|
||||
```typescript
|
||||
// Stdio 配置
|
||||
McpStdioServerConfigSchema = z.object({
|
||||
type: z.literal('stdio'),
|
||||
command: z.string(),
|
||||
args: z.array(z.string()),
|
||||
env: z.record(z.string()),
|
||||
})
|
||||
|
||||
// SSE 配置
|
||||
McpSSEServerConfigSchema = z.object({
|
||||
type: z.literal('sse'),
|
||||
url: z.string(),
|
||||
headers: z.record(z.string()),
|
||||
oauth: McpOAuthConfigSchema,
|
||||
})
|
||||
|
||||
// WebSocket 配置
|
||||
McpWebSocketServerConfigSchema = z.object({
|
||||
type: z.literal('ws'),
|
||||
url: z.string(),
|
||||
headers: z.record(z.string()),
|
||||
})
|
||||
```
|
||||
|
||||
**连接状态类型**:
|
||||
```typescript
|
||||
ConnectedMCPServer = { client, name, type: 'connected', capabilities, serverInfo, cleanup }
|
||||
FailedMCPServer = { name, type: 'failed', error }
|
||||
NeedsAuthMCPServer = { name, type: 'needs-auth' }
|
||||
PendingMCPServer = { name, type: 'pending', reconnectAttempt }
|
||||
DisabledMCPServer = { name, type: 'disabled' }
|
||||
```
|
||||
|
||||
### useManageMCPConnections.ts - 连接管理 Hook
|
||||
|
||||
**文件位置**: `src/services/mcp/useManageMCPConnections.ts`
|
||||
|
||||
**核心职责**:
|
||||
1. 初始化 MCP 客户端连接
|
||||
2. 设置连接生命周期处理器
|
||||
3. 管理自动重连(SSE 连接)
|
||||
4. 同步 appState
|
||||
|
||||
**关键特性**:
|
||||
|
||||
#### 自动重连
|
||||
- 最大重试次数: 5
|
||||
- 初始退避: 1000ms
|
||||
- 最大退避: 30000ms
|
||||
- 指数退避策略
|
||||
|
||||
#### 通知处理器
|
||||
```typescript
|
||||
// 工具列表变更
|
||||
client.client.setNotificationHandler(ToolListChangedNotificationSchema, ...)
|
||||
|
||||
// 提示列表变更
|
||||
client.client.setNotificationHandler(PromptListChangedNotificationSchema, ...)
|
||||
|
||||
// 资源列表变更
|
||||
client.client.setNotificationHandler(ResourceListChangedNotificationSchema, ...)
|
||||
```
|
||||
|
||||
#### 通道推送 (KAIROS 特性)
|
||||
```typescript
|
||||
// 注册通道通知处理器
|
||||
client.client.setNotificationHandler(ChannelMessageNotificationSchema, async notification => {
|
||||
enqueue({
|
||||
mode: 'prompt',
|
||||
value: wrapChannelMessage(client.name, content, meta),
|
||||
priority: 'next',
|
||||
isMeta: true,
|
||||
})
|
||||
})
|
||||
```
|
||||
|
||||
### channelNotification.ts - 通道通知
|
||||
|
||||
**功能**: 处理 MCP 服务器的通道消息通知。
|
||||
|
||||
### channelPermissions.ts - 通道权限
|
||||
|
||||
**功能**: 管理通道权限回调。
|
||||
|
||||
### auth.ts - MCP 认证
|
||||
|
||||
**功能**: 处理 MCP 服务器的 OAuth 认证流程。
|
||||
|
||||
### oauthPort.ts - OAuth 端口管理
|
||||
|
||||
**功能**: 管理 OAuth 回调端口。
|
||||
|
||||
### elicitationHandler.ts - 信息请求处理
|
||||
|
||||
**功能**: 处理 MCP 服务器的信息请求(elicitation)。
|
||||
|
||||
### normalization.ts - 工具名称规范化
|
||||
|
||||
**功能**: 规范化 MCP 工具名称,避免命名冲突。
|
||||
|
||||
---
|
||||
|
||||
## 3. services/oauth/ - OAuth 2.0 认证
|
||||
|
||||
**文件位置**: `src/services/oauth/index.ts`
|
||||
|
||||
### OAuthService 类
|
||||
|
||||
**核心功能**: 实现 OAuth 2.0 授权码流程(支持 PKCE)。
|
||||
|
||||
```typescript
|
||||
export class OAuthService {
|
||||
async startOAuthFlow(
|
||||
authURLHandler: (url: string, automaticUrl?: string) => Promise<void>,
|
||||
options?: {
|
||||
loginWithClaudeAi?: boolean
|
||||
inferenceOnly?: boolean
|
||||
expiresIn?: number
|
||||
orgUUID?: string
|
||||
loginHint?: string
|
||||
loginMethod?: string
|
||||
skipBrowserOpen?: boolean
|
||||
}
|
||||
): Promise<OAuthTokens>
|
||||
}
|
||||
```
|
||||
|
||||
**两种授权流程**:
|
||||
|
||||
#### 1. 自动流程
|
||||
- 打开浏览器,跳转到授权页面
|
||||
- 用户在浏览器中完成授权
|
||||
- 回调到本地监听服务器
|
||||
|
||||
#### 2. 手动流程
|
||||
- 显示手动授权 URL
|
||||
- 用户复制 URL 到浏览器
|
||||
- 用户复制授权码回来
|
||||
|
||||
**核心步骤**:
|
||||
1. 创建本地授权码监听器 (`AuthCodeListener`)
|
||||
2. 生成 PKCE 值(`code_verifier`, `code_challenge`)
|
||||
3. 构建授权 URL
|
||||
4. 等待授权码
|
||||
5. 交换令牌
|
||||
|
||||
### client.ts - OAuth 客户端
|
||||
|
||||
**功能**: 与 OAuth 服务器通信。
|
||||
|
||||
```typescript
|
||||
export async function exchangeCodeForTokens(
|
||||
code: string,
|
||||
state: string,
|
||||
codeVerifier: string,
|
||||
port: number,
|
||||
isManual: boolean,
|
||||
expiresIn?: number
|
||||
): Promise<OAuthTokenExchangeResponse>
|
||||
|
||||
export function buildAuthUrl(opts: {
|
||||
codeChallenge: string
|
||||
state: string
|
||||
port: number
|
||||
isManual: boolean
|
||||
loginWithClaudeAi?: boolean
|
||||
inferenceOnly?: boolean
|
||||
orgUUID?: string
|
||||
loginHint?: string
|
||||
loginMethod?: string
|
||||
}): string
|
||||
```
|
||||
|
||||
### crypto.ts - 加密工具
|
||||
|
||||
**功能**: PKCE 加密操作。
|
||||
|
||||
```typescript
|
||||
export function generateCodeVerifier(): string
|
||||
export function generateCodeChallenge(verifier: string): string
|
||||
export function generateState(): string
|
||||
```
|
||||
|
||||
### auth-code-listener.ts - 授权码监听
|
||||
|
||||
**功能**: 启动本地 HTTP 服务器监听 OAuth 回调。
|
||||
|
||||
```typescript
|
||||
export class AuthCodeListener {
|
||||
async start(): Promise<number> // 返回监听端口
|
||||
waitForAuthorization(state: string, onReady: () => Promise<void>): Promise<string>
|
||||
handleSuccessRedirect(scopes: string[]): void
|
||||
handleErrorRedirect(): void
|
||||
close(): void
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 4. services/lsp/ - Language Server Protocol
|
||||
|
||||
### manager.ts - LSP 管理器
|
||||
|
||||
**文件位置**: `src/services/lsp/manager.ts`
|
||||
|
||||
**核心接口**:
|
||||
|
||||
```typescript
|
||||
export interface LSPServerManager {
|
||||
getAllServers(): Map<string, LSPServerInstance>
|
||||
getServer(name: string): LSPServerInstance | undefined
|
||||
getServerCapabilities(name: string): ServerCapabilities | undefined
|
||||
initialize(): Promise<void>
|
||||
shutdown(): Promise<void>
|
||||
}
|
||||
```
|
||||
|
||||
**初始化流程**:
|
||||
1. `initializeLspServerManager()` - 初始化管理器单例
|
||||
2. `createLSPServerManager()` - 创建管理器实例
|
||||
3. `registerLSPNotificationHandlers()` - 注册通知处理器
|
||||
|
||||
**状态管理**:
|
||||
```typescript
|
||||
type InitializationState = 'not-started' | 'pending' | 'success' | 'failed'
|
||||
```
|
||||
|
||||
**关键函数**:
|
||||
```typescript
|
||||
export function getLspServerManager(): LSPServerManager | undefined
|
||||
export function isLspConnected(): boolean
|
||||
export async function waitForInitialization(): Promise<void>
|
||||
export function reinitializeLspServerManager(): void // 用于 /reload-plugins
|
||||
export async function shutdownLspServerManager(): Promise<void>
|
||||
```
|
||||
|
||||
### LSPServerInstance.ts - 服务器实例
|
||||
|
||||
**功能**: 管理单个 LSP 服务器实例。
|
||||
|
||||
### LSPClient.ts - LSP 客户端
|
||||
|
||||
**功能**: 实现 LSP 协议客户端逻辑。
|
||||
|
||||
### LSPDiagnosticRegistry.ts - 诊断注册
|
||||
|
||||
**功能**: 注册和管理 LSP 诊断信息。
|
||||
|
||||
### passiveFeedback.ts - 被动反馈
|
||||
|
||||
**功能**: 处理 LSP 的被动反馈(如悬停信息、定义跳转)。
|
||||
|
||||
---
|
||||
|
||||
## 5. services/analytics/ - 分析服务
|
||||
|
||||
### index.ts - 分析服务入口
|
||||
|
||||
**文件位置**: `src/services/analytics/index.ts`
|
||||
|
||||
**核心功能**:
|
||||
- 事件日志记录
|
||||
- GrowthBook 特性开关
|
||||
- 事件队列管理
|
||||
|
||||
**事件日志**:
|
||||
|
||||
```typescript
|
||||
export function logEvent(
|
||||
eventName: string,
|
||||
metadata: Record<string, boolean | number | undefined>
|
||||
): void
|
||||
|
||||
export async function logEventAsync(
|
||||
eventName: string,
|
||||
metadata: Record<string, boolean | number | undefined>
|
||||
): Promise<void>
|
||||
```
|
||||
|
||||
**设计原则**:
|
||||
- 无依赖设计,避免导入循环
|
||||
- 事件在 sink 连接前进入队列
|
||||
- 支持同步/异步事件记录
|
||||
|
||||
**GrowthBook 集成**:
|
||||
```typescript
|
||||
export function getFeatureValue_CACHED_MAY_BE_STALE(
|
||||
featureName: string,
|
||||
defaultValue: T
|
||||
): T
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 6. services/plugins/ - 插件系统
|
||||
|
||||
### pluginOperations.ts - 插件操作
|
||||
|
||||
**文件位置**: `src/services/plugins/pluginOperations.ts`
|
||||
|
||||
**核心操作**:
|
||||
|
||||
```typescript
|
||||
export async function installPluginOp(
|
||||
plugin: string,
|
||||
scope: InstallableScope = 'user'
|
||||
): Promise<PluginOperationResult>
|
||||
|
||||
export async function uninstallPluginOp(
|
||||
plugin: string,
|
||||
scope: InstallableScope = 'user',
|
||||
deleteDataDir = true
|
||||
): Promise<PluginOperationResult>
|
||||
|
||||
export async function setPluginEnabledOp(
|
||||
plugin: string,
|
||||
enabled: boolean,
|
||||
scope?: InstallableScope
|
||||
): Promise<PluginOperationResult>
|
||||
|
||||
export async function updatePluginOp(
|
||||
plugin: string,
|
||||
scope: PluginScope
|
||||
): Promise<PluginUpdateResult>
|
||||
```
|
||||
|
||||
**安装作用域**:
|
||||
```typescript
|
||||
export const VALID_INSTALLABLE_SCOPES = ['user', 'project', 'local'] as const
|
||||
```
|
||||
|
||||
**操作原则**:
|
||||
1. 搜索市场获取插件信息
|
||||
2. 写入设置(声明意图)
|
||||
3. 缓存插件并记录版本
|
||||
|
||||
### PluginInstallationManager.ts - 安装管理
|
||||
|
||||
**功能**: 管理插件的下载、安装、更新。
|
||||
|
||||
---
|
||||
|
||||
## 7. services/compact/ - 对话压缩
|
||||
|
||||
### compact.ts - 核心压缩逻辑
|
||||
|
||||
**文件位置**: `src/services/compact/compact.ts`
|
||||
|
||||
**核心接口**:
|
||||
|
||||
```typescript
|
||||
export interface CompactionResult {
|
||||
boundaryMarker: SystemMessage
|
||||
summaryMessages: UserMessage[]
|
||||
attachments: AttachmentMessage[]
|
||||
hookResults: HookResultMessage[]
|
||||
messagesToKeep?: Message[]
|
||||
userDisplayMessage?: string
|
||||
preCompactTokenCount?: number
|
||||
postCompactTokenCount?: number
|
||||
truePostCompactTokenCount?: number
|
||||
compactionUsage?: ReturnType<typeof getTokenUsage>
|
||||
}
|
||||
```
|
||||
|
||||
**压缩类型**:
|
||||
|
||||
#### 完整压缩 (`compactConversation`)
|
||||
```typescript
|
||||
export async function compactConversation(
|
||||
messages: Message[],
|
||||
context: ToolUseContext,
|
||||
cacheSafeParams: CacheSafeParams,
|
||||
suppressFollowUpQuestions: boolean,
|
||||
customInstructions?: string,
|
||||
isAutoCompact: boolean = false,
|
||||
recompactionInfo?: RecompactionInfo
|
||||
): Promise<CompactionResult>
|
||||
```
|
||||
|
||||
#### 部分压缩 (`partialCompactConversation`)
|
||||
```typescript
|
||||
export async function partialCompactConversation(
|
||||
allMessages: Message[],
|
||||
pivotIndex: number,
|
||||
context: ToolUseContext,
|
||||
cacheSafeParams: CacheSafeParams,
|
||||
userFeedback?: string,
|
||||
direction: PartialCompactDirection = 'from'
|
||||
): Promise<CompactionResult>
|
||||
```
|
||||
|
||||
**核心流程**:
|
||||
1. 执行 PreCompact hooks
|
||||
2. 剥离图片/文档(节省 token)
|
||||
3. 调用 AI 生成摘要
|
||||
4. 创建压缩边界标记
|
||||
5. 执行 SessionStart hooks
|
||||
6. 清理缓存
|
||||
|
||||
### microCompact.ts - 微压缩
|
||||
|
||||
**功能**: 在调用压缩 API 前减少消息 token 数量。
|
||||
|
||||
```typescript
|
||||
export async function microcompactMessages(
|
||||
messages: Message[],
|
||||
context: ToolUseContext
|
||||
): Promise<{ messages: Message[] }>
|
||||
```
|
||||
|
||||
### sessionMemoryCompact.ts - 会话内存压缩
|
||||
|
||||
**功能**: 快速压缩,无需调用 AI。
|
||||
|
||||
### autoCompact.ts - 自动压缩
|
||||
|
||||
**功能**: 当上下文即将达到限制时自动触发压缩。
|
||||
|
||||
---
|
||||
|
||||
## 8. services/policyLimits/ - 组织策略限制
|
||||
|
||||
**文件位置**: `src/services/policyLimits/index.ts`
|
||||
|
||||
**功能**: 获取并应用组织级别的策略限制。
|
||||
|
||||
**资格条件**:
|
||||
- Console 用户(API Key): 全部符合
|
||||
- OAuth 用户(Claude.ai): 仅 Team 和 Enterprise 订阅
|
||||
|
||||
**核心函数**:
|
||||
|
||||
```typescript
|
||||
export function isPolicyLimitsEligible(): boolean
|
||||
export async function waitForPolicyLimitsToLoad(): Promise<void>
|
||||
export function isPolicyAllowed(policy: string): boolean
|
||||
export async function loadPolicyLimits(): Promise<void>
|
||||
export async function refreshPolicyLimits(): Promise<void>
|
||||
export async function clearPolicyLimitsCache(): Promise<void>
|
||||
```
|
||||
|
||||
**缓存策略**:
|
||||
- 文件缓存: `~/.claude/policy-limits.json`
|
||||
- ETag 校验
|
||||
- 后台轮询(每小时)
|
||||
|
||||
**失败处理**: 失败时继续运行(fail open)
|
||||
|
||||
---
|
||||
|
||||
## 9. services/remoteManagedSettings/ - 远程托管设置
|
||||
|
||||
**文件位置**: `src/services/remoteManagedSettings/index.ts`
|
||||
|
||||
**功能**: 为企业客户获取和管理远程托管设置。
|
||||
|
||||
**核心函数**:
|
||||
|
||||
```typescript
|
||||
export function isEligibleForRemoteManagedSettings(): boolean
|
||||
export async function waitForRemoteManagedSettingsToLoad(): Promise<void>
|
||||
export async function loadRemoteManagedSettings(): Promise<void>
|
||||
export async function refreshRemoteManagedSettings(): Promise<void>
|
||||
export async function clearRemoteManagedSettingsCache(): Promise<void>
|
||||
```
|
||||
|
||||
**安全检查**:
|
||||
```typescript
|
||||
export async function checkManagedSettingsSecurity(
|
||||
cachedSettings: SettingsJson,
|
||||
newSettings: SettingsJson
|
||||
): Promise<SecurityCheckResult>
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 10. services/extractMemories/ - 自动记忆提取
|
||||
|
||||
**文件位置**: `src/services/extractMemories/extractMemories.ts`
|
||||
|
||||
**功能**: 从当前会话中提取持久记忆并写入自动记忆目录。
|
||||
|
||||
**触发时机**: 在查询循环结束时(模型生成最终响应后)
|
||||
|
||||
**核心接口**:
|
||||
|
||||
```typescript
|
||||
export function initExtractMemories(): void
|
||||
export async function executeExtractMemories(
|
||||
context: REPLHookContext,
|
||||
appendSystemMessage?: AppendSystemMessageFn
|
||||
): Promise<void>
|
||||
export async function drainPendingExtraction(timeoutMs?: number): Promise<void>
|
||||
```
|
||||
|
||||
**工具权限**:
|
||||
```typescript
|
||||
export function createAutoMemCanUseTool(memoryDir: string): CanUseToolFn
|
||||
// 允许: Read, Grep, Glob, 只读 Bash
|
||||
// 允许: Edit, Write 仅限 auto-memory 路径
|
||||
```
|
||||
|
||||
**特性开关**:
|
||||
- `tengu_passport_quail` - 启用/禁用记忆提取
|
||||
- `tengu_bramble_lintel` - 提取频率控制
|
||||
- `TEAMMEM` - 团队记忆支持
|
||||
|
||||
---
|
||||
|
||||
## 11. services/tokenEstimation.ts - Token 估算
|
||||
|
||||
**文件位置**: `src/services/tokenEstimation.ts`
|
||||
|
||||
**核心功能**: 估算文本和消息的 token 数量。
|
||||
|
||||
**主要函数**:
|
||||
|
||||
```typescript
|
||||
export async function countTokensWithAPI(content: string): Promise<number | null>
|
||||
export async function countMessagesTokensWithAPI(
|
||||
messages: Anthropic.Beta.Messages.BetaMessageParam[],
|
||||
tools: Anthropic.Beta.Messages.BetaToolUnion[]
|
||||
): Promise<number | null>
|
||||
|
||||
export function roughTokenCountEstimation(
|
||||
content: string,
|
||||
bytesPerToken: number = 4
|
||||
): number
|
||||
|
||||
export async function countTokensViaHaikuFallback(
|
||||
messages: Anthropic.Beta.Messages.BetaMessageParam[],
|
||||
tools: Anthropic.Beta.Messages.BetaToolUnion[]
|
||||
): Promise<number | null>
|
||||
```
|
||||
|
||||
**文件类型估算**:
|
||||
|
||||
```typescript
|
||||
export function bytesPerTokenForFileType(fileExtension: string): number {
|
||||
switch (fileExtension) {
|
||||
case 'json':
|
||||
case 'jsonl':
|
||||
case 'jsonc':
|
||||
return 2 // JSON 更密集
|
||||
default:
|
||||
return 4
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
**图像 token 估算**:
|
||||
```typescript
|
||||
// tokens = (width px * height px) / 750
|
||||
// 最大 2000x2000 (约 5333 tokens)
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 12. services/teamMemorySync/ - 团队记忆同步
|
||||
|
||||
(参见 `extractMemories/` 中的 `TEAMMEM` 特性)
|
||||
|
||||
**功能**: 在团队成员之间同步记忆文件。
|
||||
|
||||
---
|
||||
|
||||
## 服务层架构图
|
||||
|
||||
```
|
||||
┌─────────────────────────────────────────────────────────────┐
|
||||
│ CLI 入口 │
|
||||
└─────────────────────────────────────────────────────────────┘
|
||||
│
|
||||
▼
|
||||
┌─────────────────────────────────────────────────────────────┐
|
||||
│ 命令层 (commands/) │
|
||||
│ /commit /review /compact /mcp /config /doctor 等 │
|
||||
└─────────────────────────────────────────────────────────────┘
|
||||
│
|
||||
▼
|
||||
┌─────────────────────────────────────────────────────────────┐
|
||||
│ 服务层 (services/) │
|
||||
│ │
|
||||
│ ┌─────────────┐ ┌─────────────┐ ┌─────────────┐ │
|
||||
│ │ api/ │ │ mcp/ │ │ lsp/ │ │
|
||||
│ │ Anthropic │ │ Model Context│ │ Language │ │
|
||||
│ │ API 客户端 │ │ Protocol │ │ Server │ │
|
||||
│ └─────────────┘ └─────────────┘ └─────────────┘ │
|
||||
│ │
|
||||
│ ┌─────────────┐ ┌─────────────┐ ┌─────────────┐ │
|
||||
│ │ oauth/ │ │ analytics/ │ │ plugins/ │ │
|
||||
│ │ OAuth 2.0 │ │ GrowthBook │ │ 插件系统 │ │
|
||||
│ └─────────────┘ └─────────────┘ └─────────────┘ │
|
||||
│ │
|
||||
│ ┌─────────────┐ ┌─────────────┐ ┌─────────────┐ │
|
||||
│ │ compact/ │ │policyLimits/│ │remoteManage │ │
|
||||
│ │ 对话压缩 │ │ 策略限制 │ │ dSettings/ │ │
|
||||
│ └─────────────┘ └─────────────┘ └─────────────┘ │
|
||||
│ │
|
||||
│ ┌─────────────┐ ┌─────────────┐ │
|
||||
│ │extractMemories│ │tokenEstim ation│ │
|
||||
│ │ 自动记忆提取 │ │ Token 估算 │ │
|
||||
│ └─────────────┘ └─────────────┘ │
|
||||
└─────────────────────────────────────────────────────────────┘
|
||||
│
|
||||
▼
|
||||
┌─────────────────────────────────────────────────────────────┐
|
||||
│ 工具层 (tools/) │
|
||||
│ Read / Write / Edit / Bash / Grep / Glob 等 │
|
||||
└─────────────────────────────────────────────────────────────┘
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 相关源码文件索引
|
||||
|
||||
| 服务 | 主要文件 |
|
||||
|------|---------|
|
||||
| API Client | `src/services/api/client.ts`, `claude.ts` |
|
||||
| MCP | `src/services/mcp/` |
|
||||
| OAuth | `src/services/oauth/` |
|
||||
| LSP | `src/services/lsp/` |
|
||||
| Analytics | `src/services/analytics/` |
|
||||
| Plugins | `src/services/plugins/` |
|
||||
| Compact | `src/services/compact/` |
|
||||
| Policy Limits | `src/services/policyLimits/` |
|
||||
| Remote Settings | `src/services/remoteManagedSettings/` |
|
||||
| Extract Memories | `src/services/extractMemories/` |
|
||||
| Token Estimation | `src/services/tokenEstimation.ts` |
|
||||
659
claude-code-中文Wiki/06-桥接系统.md
Normal file
659
claude-code-中文Wiki/06-桥接系统.md
Normal file
@@ -0,0 +1,659 @@
|
||||
# Claude Code 桥接系统详解
|
||||
|
||||
## 概述
|
||||
|
||||
桥接系统(Bridge)是 Claude Code CLI 与 IDE 扩展(VS Code, JetBrains)之间的双向通信层。它使 IDE 能够:
|
||||
1. 在远程设备上启动 Claude Code 会话
|
||||
2. 将用户输入转发到 Claude Code
|
||||
3. 显示 Claude Code 的输出和工具执行结果
|
||||
4. 处理权限请求和响应
|
||||
|
||||
---
|
||||
|
||||
## 核心架构
|
||||
|
||||
```
|
||||
┌──────────────────────────────────────────────────────────────┐
|
||||
│ IDE Extension (VS Code / JetBrains) │
|
||||
│ - 用户界面 │
|
||||
│ - 输入处理 │
|
||||
│ - 输出展示 │
|
||||
└──────────────────────────────────────────────────────────────┘
|
||||
│
|
||||
│ WebSocket / HTTP
|
||||
▼
|
||||
┌──────────────────────────────────────────────────────────────┐
|
||||
│ Bridge Layer │
|
||||
│ │
|
||||
│ ┌────────────────────────────────────────────────────────┐ │
|
||||
│ │ bridgeMain.ts │ │
|
||||
│ │ 入口点,管理桥接生命周期 │ │
|
||||
│ └────────────────────────────────────────────────────────┘ │
|
||||
│ │
|
||||
│ ┌────────────────────────────────────────────────────────┐ │
|
||||
│ │ bridgeMessaging.ts │ │
|
||||
│ │ 消息处理、入口路由、流量控制 │ │
|
||||
│ └────────────────────────────────────────────────────────┘ │
|
||||
│ │
|
||||
│ ┌────────────────────────────────────────────────────────┐ │
|
||||
│ │ replBridge.ts │ │
|
||||
│ │ REPL 会话桥接 │ │
|
||||
│ └────────────────────────────────────────────────────────┘ │
|
||||
│ │
|
||||
│ ┌────────────────────────────────────────────────────────┐ │
|
||||
│ │ sessionRunner.ts │ │
|
||||
│ │ 会话执行管理 │ │
|
||||
│ └────────────────────────────────────────────────────────┘ │
|
||||
│ │
|
||||
│ ┌────────────────────────────────────────────────────────┐ │
|
||||
│ │ jwtUtils.ts │ │
|
||||
│ │ JWT 认证工具 │ │
|
||||
│ └────────────────────────────────────────────────────────┘ │
|
||||
│ │
|
||||
│ ┌────────────────────────────────────────────────────────┐ │
|
||||
│ │ bridgePermissionCallbacks.ts │ │
|
||||
│ │ 权限回调处理 │ │
|
||||
│ └────────────────────────────────────────────────────────┘ │
|
||||
└──────────────────────────────────────────────────────────────┘
|
||||
│
|
||||
▼
|
||||
┌──────────────────────────────────────────────────────────────┐
|
||||
│ Claude Code CLI (子进程) │
|
||||
│ - 命令处理 │
|
||||
│ - 工具执行 │
|
||||
│ - API 调用 │
|
||||
└──────────────────────────────────────────────────────────────┘
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 1. bridgeMain.ts - 桥接主入口
|
||||
|
||||
**文件位置**: `src/bridge/bridgeMain.ts`
|
||||
|
||||
### 核心类型
|
||||
|
||||
```typescript
|
||||
export type BridgeState = 'ready' | 'connected' | 'reconnecting' | 'failed'
|
||||
|
||||
export type ReplBridgeHandle = {
|
||||
bridgeSessionId: string
|
||||
environmentId: string
|
||||
sessionIngressUrl: string
|
||||
writeMessages(messages: Message[]): void
|
||||
writeSdkMessages(messages: SDKMessage[]): void
|
||||
sendControlRequest(request: SDKControlRequest): void
|
||||
sendControlResponse(response: SDKControlResponse): void
|
||||
sendControlCancelRequest(requestId: string): void
|
||||
sendResult(): void
|
||||
teardown(): Promise<void>
|
||||
}
|
||||
```
|
||||
|
||||
### 核心函数
|
||||
|
||||
```typescript
|
||||
export async function initBridgeCore(
|
||||
params: BridgeCoreParams
|
||||
): Promise<BridgeCoreHandle | null>
|
||||
```
|
||||
|
||||
**BridgeCoreParams 输入参数**:
|
||||
|
||||
```typescript
|
||||
type BridgeCoreParams = {
|
||||
dir: string // 工作目录
|
||||
machineName: string // 机器名称
|
||||
branch: string // Git 分支
|
||||
gitRepoUrl: string | null // Git 仓库 URL
|
||||
title: string // 会话标题
|
||||
baseUrl: string // API 基础 URL
|
||||
sessionIngressUrl: string // 会话入口 URL
|
||||
workerType: string // 工作器类型
|
||||
getAccessToken: () => string | undefined
|
||||
createSession: (opts: {...}) => Promise<string | null>
|
||||
archiveSession: (sessionId: string) => Promise<void>
|
||||
toSDKMessages?: (messages: Message[]) => SDKMessage[]
|
||||
onAuth401?: (staleAccessToken: string) => Promise<boolean>
|
||||
getPollIntervalConfig?: () => PollIntervalConfig
|
||||
initialMessages?: Message[]
|
||||
previouslyFlushedUUIDs?: Set<string>
|
||||
onInboundMessage?: (msg: SDKMessage) => void
|
||||
onPermissionResponse?: (response: SDKControlResponse) => void
|
||||
onInterrupt?: () => void
|
||||
onSetModel?: (model: string | undefined) => void
|
||||
onSetMaxThinkingTokens?: (maxTokens: number | null) => void
|
||||
onSetPermissionMode?: (mode: PermissionMode) => {...}
|
||||
onStateChange?: (state: BridgeState, detail?: string) => void
|
||||
onUserMessage?: (text: string, sessionId: string) => boolean
|
||||
perpetual?: boolean
|
||||
initialSSESequenceNum?: number
|
||||
}
|
||||
```
|
||||
|
||||
### 桥接生命周期
|
||||
|
||||
1. **注册桥接环境**
|
||||
```typescript
|
||||
const reg = await api.registerBridgeEnvironment(bridgeConfig)
|
||||
environmentId = reg.environment_id
|
||||
environmentSecret = reg.environment_secret
|
||||
```
|
||||
|
||||
2. **创建会话**
|
||||
```typescript
|
||||
const createdSessionId = await createSession({...})
|
||||
currentSessionId = createdSessionId
|
||||
```
|
||||
|
||||
3. **启动工作轮询循环**
|
||||
```typescript
|
||||
void startWorkPollLoop(pollOpts)
|
||||
```
|
||||
|
||||
4. **处理入口消息**
|
||||
```typescript
|
||||
transport.onData(data => {
|
||||
handleIngressMessage(data, recentPostedUUIDs, recentInboundUUIDs, ...)
|
||||
})
|
||||
```
|
||||
|
||||
5. **清理**
|
||||
```typescript
|
||||
await doTeardownImpl()
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 2. bridgeMessaging.ts - 消息处理
|
||||
|
||||
**文件位置**: `src/bridge/bridgeMessaging.ts`
|
||||
|
||||
### 消息入口处理
|
||||
|
||||
```typescript
|
||||
export function handleIngressMessage(
|
||||
data: string,
|
||||
recentPostedUUIDs: BoundedUUIDSet,
|
||||
recentInboundUUIDs: BoundedUUIDSet,
|
||||
onInboundMessage: ((msg: SDKMessage) => void | Promise<void>) | undefined,
|
||||
onPermissionResponse?: ((response: SDKControlResponse) => void) | undefined,
|
||||
onControlRequest?: ((request: SDKControlRequest) => void) | undefined,
|
||||
): void
|
||||
```
|
||||
|
||||
**消息类型判断**:
|
||||
|
||||
```typescript
|
||||
export function isSDKMessage(value: unknown): value is SDKMessage
|
||||
export function isSDKControlResponse(value: unknown): value is SDKControlResponse
|
||||
export function isSDKControlRequest(value: unknown): value is SDKControlRequest
|
||||
```
|
||||
|
||||
### 可桥接消息过滤
|
||||
|
||||
```typescript
|
||||
export function isEligibleBridgeMessage(m: Message): boolean {
|
||||
// 排除虚拟消息
|
||||
if ((m.type === 'user' || m.type === 'assistant') && m.isVirtual) {
|
||||
return false
|
||||
}
|
||||
return (
|
||||
m.type === 'user' ||
|
||||
m.type === 'assistant' ||
|
||||
(m.type === 'system' && m.subtype === 'local_command')
|
||||
)
|
||||
}
|
||||
```
|
||||
|
||||
### 服务器控制请求处理
|
||||
|
||||
```typescript
|
||||
export function handleServerControlRequest(
|
||||
request: SDKControlRequest,
|
||||
handlers: ServerControlRequestHandlers,
|
||||
): void
|
||||
```
|
||||
|
||||
**支持的请求类型**:
|
||||
- `initialize` - 初始化
|
||||
- `set_model` - 设置模型
|
||||
- `set_max_thinking_tokens` - 设置最大思考 token
|
||||
- `set_permission_mode` - 设置权限模式
|
||||
- `interrupt` - 中断
|
||||
|
||||
### 标题文本提取
|
||||
|
||||
```typescript
|
||||
export function extractTitleText(m: Message): string | undefined
|
||||
// 从用户消息中提取标题
|
||||
```
|
||||
|
||||
### BoundedUUIDSet - UUID 环形缓冲区
|
||||
|
||||
```typescript
|
||||
export class BoundedUUIDSet {
|
||||
constructor(capacity: number)
|
||||
add(uuid: string): void
|
||||
has(uuid: string): boolean
|
||||
clear(): void
|
||||
}
|
||||
```
|
||||
|
||||
**用途**:
|
||||
- 消息回音过滤
|
||||
- 重复消息去重
|
||||
|
||||
---
|
||||
|
||||
## 3. replBridge.ts - REPL 会话桥接
|
||||
|
||||
**文件位置**: `src/bridge/replBridge.ts`
|
||||
|
||||
### 核心接口
|
||||
|
||||
```typescript
|
||||
export type ReplBridgeTransport = {
|
||||
setOnConnect(callback: () => void): void
|
||||
setOnData(callback: (data: string) => void): void
|
||||
setOnClose(callback: (code: number | undefined) => void): void
|
||||
connect(): void
|
||||
write(message: object): Promise<void>
|
||||
writeBatch(messages: object[]): Promise<void>
|
||||
close(): void
|
||||
getStateLabel(): string
|
||||
getLastSequenceNum(): number
|
||||
isConnectedStatus(): boolean
|
||||
}
|
||||
```
|
||||
|
||||
### 传输类型
|
||||
|
||||
#### 1. HybridTransport (v1)
|
||||
- WebSocket 读取
|
||||
- HTTP POST 写入
|
||||
- 目标: Session-Ingress
|
||||
|
||||
#### 2. SSETransport (v2)
|
||||
- Server-Sent Events 读取
|
||||
- HTTP POST 写入
|
||||
- 目标: CCR (/worker/*)
|
||||
|
||||
### 初始化流程
|
||||
|
||||
```typescript
|
||||
export async function initReplBridge(
|
||||
params: InitBridgeOptions
|
||||
): Promise<ReplBridgeHandle | null>
|
||||
```
|
||||
|
||||
### 消息写入
|
||||
|
||||
```typescript
|
||||
writeMessages(messages: Message[]) {
|
||||
// 过滤可桥接消息
|
||||
const filtered = messages.filter(m =>
|
||||
isEligibleBridgeMessage(m) &&
|
||||
!initialMessageUUIDs.has(m.uuid) &&
|
||||
!recentPostedUUIDs.has(m.uuid)
|
||||
)
|
||||
|
||||
// 转换并发送
|
||||
const sdkMessages = toSDKMessages(filtered)
|
||||
void transport.writeBatch(events)
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 4. jwtUtils.ts - JWT 认证
|
||||
|
||||
**文件位置**: `src/bridge/jwtUtils.ts`
|
||||
|
||||
### JWT 解析
|
||||
|
||||
```typescript
|
||||
export function decodeJwtPayload(token: string): unknown | null {
|
||||
// 剥离 sk-ant-si- 前缀
|
||||
const jwt = token.startsWith('sk-ant-si-')
|
||||
? token.slice('sk-ant-si-'.length)
|
||||
: token
|
||||
|
||||
// 解析 payload (不验证签名)
|
||||
const parts = jwt.split('.')
|
||||
if (parts.length !== 3 || !parts[1]) return null
|
||||
return jsonParse(Buffer.from(parts[1], 'base64url').toString('utf8'))
|
||||
}
|
||||
```
|
||||
|
||||
### Token 刷新调度器
|
||||
|
||||
```typescript
|
||||
export function createTokenRefreshScheduler({
|
||||
getAccessToken,
|
||||
onRefresh,
|
||||
label,
|
||||
refreshBufferMs = 5 * 60 * 1000, // 5 分钟
|
||||
}): {
|
||||
schedule: (sessionId: string, token: string) => void
|
||||
scheduleFromExpiresIn: (sessionId: string, expiresInSeconds: number) => void
|
||||
cancel: (sessionId: string) => void
|
||||
cancelAll: () => void
|
||||
}
|
||||
```
|
||||
|
||||
**刷新策略**:
|
||||
- 过期前 5 分钟刷新(默认)
|
||||
- 指数退避重试
|
||||
- 最多 3 次连续失败
|
||||
|
||||
---
|
||||
|
||||
## 5. sessionRunner.ts - 会话执行管理
|
||||
|
||||
**文件位置**: `src/bridge/sessionRunner.ts`
|
||||
|
||||
### 核心类型
|
||||
|
||||
```typescript
|
||||
type SessionSpawnerDeps = {
|
||||
execPath: string
|
||||
scriptArgs: string[]
|
||||
env: NodeJS.ProcessEnv
|
||||
verbose: boolean
|
||||
sandbox: boolean
|
||||
debugFile?: string
|
||||
permissionMode?: string
|
||||
onDebug: (msg: string) => void
|
||||
onActivity?: (sessionId: string, activity: SessionActivity) => void
|
||||
onPermissionRequest?: (sessionId: string, request: PermissionRequest, accessToken: string) => void
|
||||
}
|
||||
|
||||
export function createSessionSpawner(deps: SessionSpawnerDeps): SessionSpawner
|
||||
```
|
||||
|
||||
### 会话句柄
|
||||
|
||||
```typescript
|
||||
export type SessionHandle = {
|
||||
sessionId: string
|
||||
done: Promise<SessionDoneStatus>
|
||||
activities: SessionActivity[]
|
||||
accessToken: string
|
||||
lastStderr: string[]
|
||||
currentActivity: SessionActivity | null
|
||||
kill(): void
|
||||
forceKill(): void
|
||||
writeStdin(data: string): void
|
||||
updateAccessToken(token: string): void
|
||||
}
|
||||
```
|
||||
|
||||
### 活动提取
|
||||
|
||||
```typescript
|
||||
function extractActivities(
|
||||
line: string,
|
||||
sessionId: string,
|
||||
onDebug: (msg: string) => void
|
||||
): SessionActivity[]
|
||||
```
|
||||
|
||||
**活动类型**:
|
||||
```typescript
|
||||
type SessionActivity =
|
||||
| { type: 'tool_start'; summary: string; timestamp: number }
|
||||
| { type: 'text'; summary: string; timestamp: number }
|
||||
| { type: 'result'; summary: string; timestamp: number }
|
||||
| { type: 'error'; summary: string; timestamp: number }
|
||||
```
|
||||
|
||||
### 子进程管理
|
||||
|
||||
```typescript
|
||||
const child: ChildProcess = spawn(deps.execPath, args, {
|
||||
cwd: dir,
|
||||
stdio: ['pipe', 'pipe', 'pipe'],
|
||||
env,
|
||||
windowsHide: true,
|
||||
})
|
||||
```
|
||||
|
||||
**环境变量设置**:
|
||||
```typescript
|
||||
const env: NodeJS.ProcessEnv = {
|
||||
...deps.env,
|
||||
CLAUDE_CODE_OAUTH_TOKEN: undefined,
|
||||
CLAUDE_CODE_ENVIRONMENT_KIND: 'bridge',
|
||||
CLAUDE_CODE_SESSION_ACCESS_TOKEN: opts.accessToken,
|
||||
CLAUDE_CODE_USE_CCR_V2: opts.useCcrV2 ? '1' : undefined,
|
||||
CLAUDE_CODE_WORKER_EPOCH: String(opts.workerEpoch),
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 6. bridgePermissionCallbacks.ts - 权限回调
|
||||
|
||||
**文件位置**: `src/bridge/bridgePermissionCallbacks.ts`
|
||||
|
||||
### 权限响应类型
|
||||
|
||||
```typescript
|
||||
type BridgePermissionResponse = {
|
||||
behavior: 'allow' | 'deny'
|
||||
updatedInput?: Record<string, unknown>
|
||||
updatedPermissions?: PermissionUpdate[]
|
||||
message?: string
|
||||
}
|
||||
```
|
||||
|
||||
### 回调接口
|
||||
|
||||
```typescript
|
||||
type BridgePermissionCallbacks = {
|
||||
sendRequest(
|
||||
requestId: string,
|
||||
toolName: string,
|
||||
input: Record<string, unknown>,
|
||||
toolUseId: string,
|
||||
description: string,
|
||||
permissionSuggestions?: PermissionUpdate[],
|
||||
blockedPath?: string
|
||||
): void
|
||||
|
||||
sendResponse(requestId: string, response: BridgePermissionResponse): void
|
||||
|
||||
cancelRequest(requestId: string): void
|
||||
|
||||
onResponse(
|
||||
requestId: string,
|
||||
handler: (response: BridgePermissionResponse) => void
|
||||
): () => void // 返回取消订阅函数
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 7. replBridgeHandle.ts - REPL 桥接句柄
|
||||
|
||||
**文件位置**: `src/bridge/replBridgeHandle.ts`
|
||||
|
||||
### 句柄类型
|
||||
|
||||
```typescript
|
||||
export type ReplBridgeHandle = {
|
||||
bridgeSessionId: string
|
||||
environmentId: string
|
||||
sessionIngressUrl: string
|
||||
writeMessages(messages: Message[]): void
|
||||
writeSdkMessages(messages: SDKMessage[]): void
|
||||
sendControlRequest(request: SDKControlRequest): void
|
||||
sendControlResponse(response: SDKControlResponse): void
|
||||
sendControlCancelRequest(requestId: string): void
|
||||
sendResult(): void
|
||||
teardown(): Promise<void>
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 8. replBridgeTransport.ts - 传输层实现
|
||||
|
||||
**文件位置**: `src/bridge/replBridgeTransport.ts`
|
||||
|
||||
### 工厂函数
|
||||
|
||||
```typescript
|
||||
export function createV1ReplTransport(
|
||||
transport: HybridTransport
|
||||
): ReplBridgeTransport
|
||||
|
||||
export function createV2ReplTransport(opts: {
|
||||
sessionUrl: string
|
||||
ingressToken: string
|
||||
sessionId: string
|
||||
initialSequenceNum: number
|
||||
}): Promise<ReplBridgeTransport>
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 9. 入口消息处理流程
|
||||
|
||||
```
|
||||
IDE Extension
|
||||
│
|
||||
│ 1. 用户输入
|
||||
▼
|
||||
┌─────────────────┐
|
||||
│ WS 连接 │
|
||||
└─────────────────┘
|
||||
│
|
||||
▼
|
||||
┌─────────────────────────────────────────┐
|
||||
│ handleIngressMessage() │
|
||||
│ │
|
||||
│ 1. 解析 JSON │
|
||||
│ 2. 检查 UUID (回音/重复过滤) │
|
||||
│ 3. 分发消息类型 │
|
||||
│ - user → onInboundMessage │
|
||||
│ - control_response → onPermission │
|
||||
│ - control_request → onControlRequest │
|
||||
└─────────────────────────────────────────┘
|
||||
│
|
||||
▼
|
||||
┌─────────────────────────────────────────┐
|
||||
│ Claude Code CLI (子进程) │
|
||||
│ │
|
||||
│ - 执行工具 │
|
||||
│ - AI 推理 │
|
||||
│ - 返回结果 │
|
||||
└─────────────────────────────────────────┘
|
||||
│
|
||||
▼
|
||||
┌─────────────────────────────────────────┐
|
||||
│ writeMessages() / writeSdkMessages() │
|
||||
│ │
|
||||
│ 1. 过滤消息 │
|
||||
│ 2. 转换为 SDK 格式 │
|
||||
│ 3. 通过 transport.writeBatch() 发送 │
|
||||
└─────────────────────────────────────────┘
|
||||
│
|
||||
▼
|
||||
IDE Extension (WebSocket 订阅)
|
||||
│
|
||||
▼
|
||||
显示输出
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 10. 权限请求流程
|
||||
|
||||
```
|
||||
Claude Code CLI
|
||||
│
|
||||
▼ (can_use_tool 请求)
|
||||
┌─────────────────────────────────────────┐
|
||||
│ BridgePermissionCallbacks │
|
||||
│ │
|
||||
│ sendRequest(requestId, toolName, input) │
|
||||
└─────────────────────────────────────────┘
|
||||
│
|
||||
│ WebSocket / HTTP
|
||||
▼
|
||||
┌─────────────────────────────────────────┐
|
||||
│ IDE Extension │
|
||||
│ │
|
||||
│ 显示权限对话框 │
|
||||
│ 用户允许/拒绝 │
|
||||
└─────────────────────────────────────────┘
|
||||
│
|
||||
▼
|
||||
┌─────────────────────────────────────────┐
|
||||
│ sendResponse(requestId, response) │
|
||||
│ │
|
||||
│ response: { │
|
||||
│ behavior: 'allow' | 'deny', │
|
||||
│ updatedInput?, │
|
||||
│ updatedPermissions? │
|
||||
│ } │
|
||||
└─────────────────────────────────────────┘
|
||||
│
|
||||
▼
|
||||
onResponse() 回调
|
||||
│
|
||||
▼
|
||||
CLI 继续执行或中止
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 11. 关键配置
|
||||
|
||||
### 轮询配置
|
||||
|
||||
```typescript
|
||||
const DEFAULT_POLL_CONFIG = {
|
||||
poll_interval_ms_not_at_capacity: 5000, // 5 秒
|
||||
poll_interval_ms_at_capacity: 120000, // 2 分钟
|
||||
reclaim_older_than_ms: 5 * 60 * 1000, // 5 分钟
|
||||
non_exclusive_heartbeat_interval_ms: 30000, // 30 秒
|
||||
session_keepalive_interval_v2_ms: 120000, // 2 分钟
|
||||
}
|
||||
```
|
||||
|
||||
### 重连策略
|
||||
|
||||
```typescript
|
||||
const MAX_RECONNECT_ATTEMPTS = 5
|
||||
const INITIAL_BACKOFF_MS = 1000
|
||||
const MAX_BACKOFF_MS = 30000
|
||||
```
|
||||
|
||||
### UUID 缓冲区容量
|
||||
|
||||
```typescript
|
||||
const recentPostedUUIDs = new BoundedUUIDSet(2000)
|
||||
const recentInboundUUIDs = new BoundedUUIDSet(2000)
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 相关源码文件
|
||||
|
||||
| 文件 | 功能 |
|
||||
|------|------|
|
||||
| `bridgeMain.ts` | 桥接主入口和生命周期管理 |
|
||||
| `bridgeMessaging.ts` | 消息处理、路由、流量控制 |
|
||||
| `replBridge.ts` | REPL 会话桥接 |
|
||||
| `replBridgeTransport.ts` | 传输层实现 |
|
||||
| `sessionRunner.ts` | 子进程会话管理 |
|
||||
| `jwtUtils.ts` | JWT 解析和刷新调度 |
|
||||
| `bridgePermissionCallbacks.ts` | 权限回调接口 |
|
||||
| `replBridgeHandle.ts` | 句柄类型定义 |
|
||||
| `bridgeApi.ts` | 桥接 API 客户端 |
|
||||
| `pollConfig.ts` | 轮询配置 |
|
||||
| `flushGate.ts` | 刷新门控 |
|
||||
| `capacityWake.ts` | 容量唤醒机制 |
|
||||
655
claude-code-中文Wiki/07-权限系统.md
Normal file
655
claude-code-中文Wiki/07-权限系统.md
Normal file
@@ -0,0 +1,655 @@
|
||||
# Claude Code 权限系统详解
|
||||
|
||||
## 概述
|
||||
|
||||
Claude Code 的权限系统管理工具调用的授权流程。当 Claude 尝试执行危险操作(如运行 Bash 命令、写入文件)时,系统会请求用户确认。权限系统支持多种授权模式和来源,确保用户对工具执行有完全控制。
|
||||
|
||||
---
|
||||
|
||||
## 核心架构
|
||||
|
||||
```
|
||||
┌─────────────────────────────────────────────────────────────────┐
|
||||
│ 权限请求入口 │
|
||||
│ │
|
||||
│ hasPermissionsToUseTool(tool, input, context, message, id) │
|
||||
└─────────────────────────────────────────────────────────────────┘
|
||||
│
|
||||
▼
|
||||
┌─────────────────────────────────────────────────────────────────┐
|
||||
│ 权限模式检查 (PermissionMode) │
|
||||
│ │
|
||||
│ default | plan | bypassPermissions | auto | localAssistant │
|
||||
└─────────────────────────────────────────────────────────────────┘
|
||||
│
|
||||
┌───────────────┼───────────────┐
|
||||
▼ ▼ ▼
|
||||
┌──────────────┐ ┌──────────────┐ ┌──────────────┐
|
||||
│ Coordinator │ │ Interactive │ │ Swarm Worker │
|
||||
│ Handler │ │ Handler │ │ Handler │
|
||||
└──────────────┘ └──────────────┘ └──────────────┘
|
||||
│ │ │
|
||||
└───────────────┼───────────────┘
|
||||
▼
|
||||
┌──────────────────────────────────────┐
|
||||
│ 权限决策结果 │
|
||||
│ │
|
||||
│ allow | deny | ask | skip │
|
||||
└──────────────────────────────────────┘
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 1. 权限模式 (PermissionMode)
|
||||
|
||||
**文件位置**: `src/utils/permissions/PermissionMode.ts`
|
||||
|
||||
### 模式类型
|
||||
|
||||
```typescript
|
||||
type PermissionMode =
|
||||
| 'default' // 标准交互式权限确认
|
||||
| 'plan' // 计划模式,只读操作
|
||||
| 'bypassPermissions' // 跳过所有权限检查
|
||||
| 'auto' // 自动批准基于分类器
|
||||
| 'localAssistant' // 本地助手模式
|
||||
```
|
||||
|
||||
### 模式转换
|
||||
|
||||
```typescript
|
||||
export function transitionPermissionMode(
|
||||
from: PermissionMode,
|
||||
to: PermissionMode,
|
||||
options?: { skipAutoGate?: boolean }
|
||||
): { ok: true } | { ok: false; error: string }
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 2. PermissionContext - 权限上下文
|
||||
|
||||
**文件位置**: `src/hooks/toolPermission/PermissionContext.ts`
|
||||
|
||||
### 创建权限上下文
|
||||
|
||||
```typescript
|
||||
function createPermissionContext(
|
||||
tool: ToolType,
|
||||
input: Record<string, unknown>,
|
||||
toolUseContext: ToolUseContext,
|
||||
assistantMessage: AssistantMessage,
|
||||
toolUseID: string,
|
||||
setToolPermissionContext: (context: ToolPermissionContext) => void,
|
||||
queueOps?: PermissionQueueOps,
|
||||
)
|
||||
```
|
||||
|
||||
### 上下文方法
|
||||
|
||||
```typescript
|
||||
type PermissionContext = {
|
||||
// 工具信息
|
||||
tool: ToolType
|
||||
input: Record<string, unknown>
|
||||
toolUseContext: ToolUseContext
|
||||
assistantMessage: AssistantMessage
|
||||
messageId: string
|
||||
toolUseID: string
|
||||
|
||||
// 日志记录
|
||||
logDecision(args: PermissionDecisionArgs, opts?: {...}): void
|
||||
logCancelled(): void
|
||||
|
||||
// 权限持久化
|
||||
async persistPermissions(updates: PermissionUpdate[]): Promise<boolean>
|
||||
|
||||
// 决策构建
|
||||
buildAllow(
|
||||
updatedInput: Record<string, unknown>,
|
||||
opts?: {...}
|
||||
): PermissionAllowDecision
|
||||
|
||||
buildDeny(
|
||||
message: string,
|
||||
decisionReason: PermissionDecisionReason
|
||||
): PermissionDenyDecision
|
||||
|
||||
// 用户处理
|
||||
async handleUserAllow(
|
||||
updatedInput: Record<string, unknown>,
|
||||
permissionUpdates: PermissionUpdate[],
|
||||
feedback?: string,
|
||||
...
|
||||
): Promise<PermissionAllowDecision>
|
||||
|
||||
// Hook 执行
|
||||
async runHooks(
|
||||
permissionMode: string | undefined,
|
||||
suggestions: PermissionUpdate[] | undefined,
|
||||
updatedInput?: Record<string, unknown>,
|
||||
...
|
||||
): Promise<PermissionDecision | null>
|
||||
|
||||
// 分类器尝试
|
||||
async tryClassifier(
|
||||
pendingClassifierCheck: PendingClassifierCheck | undefined,
|
||||
updatedInput: Record<string, unknown> | undefined
|
||||
): Promise<PermissionDecision | null>
|
||||
|
||||
// 队列操作
|
||||
pushToQueue(item: ToolUseConfirm): void
|
||||
removeFromQueue(): void
|
||||
updateQueueItem(patch: Partial<ToolUseConfirm>): void
|
||||
|
||||
// 中止处理
|
||||
resolveIfAbort(resolve: (decision: PermissionDecision) => void): boolean
|
||||
cancelAndAbort(
|
||||
feedback?: string,
|
||||
isAbort?: boolean,
|
||||
contentBlocks?: ContentBlockParam[]
|
||||
): PermissionDecision
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 3. 权限决策类型
|
||||
|
||||
**文件位置**: `src/types/permissions.ts`
|
||||
|
||||
### 决策类型
|
||||
|
||||
```typescript
|
||||
type PermissionDecision =
|
||||
| { behavior: 'allow'; updatedInput?: Record<string, unknown>; ... }
|
||||
| { behavior: 'deny'; message: string; ... }
|
||||
| { behavior: 'ask' }
|
||||
| { behavior: 'skip' }
|
||||
```
|
||||
|
||||
### 决策来源
|
||||
|
||||
```typescript
|
||||
type PermissionDecisionSource =
|
||||
| { type: 'hook'; permanent?: boolean }
|
||||
| { type: 'user'; permanent: boolean }
|
||||
| { type: 'classifier' }
|
||||
| 'config' // 配置自动允许
|
||||
```
|
||||
|
||||
### 待处理分类器检查
|
||||
|
||||
```typescript
|
||||
type PendingClassifierCheck = {
|
||||
input: Record<string, unknown>
|
||||
command: string
|
||||
// ...
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 4. 权限处理器
|
||||
|
||||
### 4.1 Coordinator Handler
|
||||
|
||||
**文件位置**: `src/hooks/toolPermission/handlers/coordinatorHandler.ts`
|
||||
|
||||
用于协调者工作进程(coordinator worker)的权限处理流程。
|
||||
|
||||
```typescript
|
||||
async function handleCoordinatorPermission(
|
||||
params: CoordinatorPermissionParams
|
||||
): Promise<PermissionDecision | null>
|
||||
```
|
||||
|
||||
**处理流程**:
|
||||
|
||||
1. **尝试权限 Hooks**(快速,本地)
|
||||
```typescript
|
||||
const hookResult = await ctx.runHooks(
|
||||
permissionMode,
|
||||
suggestions,
|
||||
updatedInput
|
||||
)
|
||||
if (hookResult) return hookResult
|
||||
```
|
||||
|
||||
2. **尝试分类器**(慢速,推理)
|
||||
```typescript
|
||||
const classifierResult = feature('BASH_CLASSIFIER')
|
||||
? await ctx.tryClassifier?.(pendingClassifierCheck, updatedInput)
|
||||
: null
|
||||
if (classifierResult) return classifierResult
|
||||
```
|
||||
|
||||
3. **降级到交互式对话框**
|
||||
```typescript
|
||||
return null // 交给交互式处理
|
||||
```
|
||||
|
||||
### 4.2 Interactive Handler
|
||||
|
||||
**文件位置**: `src/hooks/toolPermission/handlers/interactiveHandler.ts`
|
||||
|
||||
用于主代理的交互式权限处理。
|
||||
|
||||
```typescript
|
||||
function handleInteractivePermission(
|
||||
params: InteractivePermissionParams,
|
||||
resolve: (decision: PermissionDecision) => void,
|
||||
): void
|
||||
```
|
||||
|
||||
**处理流程**:
|
||||
|
||||
1. **推送确认队列项**
|
||||
```typescript
|
||||
ctx.pushToQueue({
|
||||
assistantMessage,
|
||||
tool,
|
||||
description,
|
||||
input: displayInput,
|
||||
toolUseID,
|
||||
permissionResult: result,
|
||||
permissionPromptStartTimeMs,
|
||||
onUserInteraction: () => { ... },
|
||||
onAbort: () => { ... },
|
||||
onAllow: () => { ... },
|
||||
onReject: () => { ... },
|
||||
recheckPermission: () => { ... },
|
||||
})
|
||||
```
|
||||
|
||||
2. **桥接权限转发**(远程控制)
|
||||
```typescript
|
||||
if (bridgeCallbacks && bridgeRequestId) {
|
||||
bridgeCallbacks.sendRequest(
|
||||
bridgeRequestId,
|
||||
ctx.tool.name,
|
||||
displayInput,
|
||||
ctx.toolUseID,
|
||||
description,
|
||||
result.suggestions,
|
||||
result.blockedPath
|
||||
)
|
||||
}
|
||||
```
|
||||
|
||||
3. **通道权限转发**(KAIROS)
|
||||
```typescript
|
||||
if (channelCallbacks && !ctx.tool.requiresUserInteraction?.()) {
|
||||
// 发送到通道(Telegram, iMessage 等)
|
||||
client.notification({
|
||||
method: CHANNEL_PERMISSION_REQUEST_METHOD,
|
||||
params
|
||||
})
|
||||
}
|
||||
```
|
||||
|
||||
4. **异步 Hook 执行**
|
||||
```typescript
|
||||
void (async () => {
|
||||
const hookDecision = await ctx.runHooks(...)
|
||||
if (hookDecision && claim()) {
|
||||
resolveOnce(hookDecision)
|
||||
}
|
||||
})()
|
||||
```
|
||||
|
||||
5. **异步分类器执行**
|
||||
```typescript
|
||||
if (feature('BASH_CLASSIFIER') && result.pendingClassifierCheck) {
|
||||
setClassifierChecking(ctx.toolUseID)
|
||||
void executeAsyncClassifierCheck(...)
|
||||
}
|
||||
```
|
||||
|
||||
### 4.3 Swarm Worker Handler
|
||||
|
||||
**文件位置**: `src/hooks/toolPermission/handlers/swarmWorkerHandler.ts`
|
||||
|
||||
用于 Swarm Worker 的权限处理(简化的仅拒绝处理)。
|
||||
|
||||
---
|
||||
|
||||
## 5. 权限回调 (Bridge Permission Callbacks)
|
||||
|
||||
**文件位置**: `src/bridge/bridgePermissionCallbacks.ts`
|
||||
|
||||
### 回调接口
|
||||
|
||||
```typescript
|
||||
type BridgePermissionCallbacks = {
|
||||
sendRequest(
|
||||
requestId: string,
|
||||
toolName: string,
|
||||
input: Record<string, unknown>,
|
||||
toolUseId: string,
|
||||
description: string,
|
||||
permissionSuggestions?: PermissionUpdate[],
|
||||
blockedPath?: string,
|
||||
): void
|
||||
|
||||
sendResponse(requestId: string, response: BridgePermissionResponse): void
|
||||
|
||||
cancelRequest(requestId: string): void
|
||||
|
||||
onResponse(
|
||||
requestId: string,
|
||||
handler: (response: BridgePermissionResponse) => void,
|
||||
): () => void
|
||||
}
|
||||
```
|
||||
|
||||
### 权限响应
|
||||
|
||||
```typescript
|
||||
type BridgePermissionResponse = {
|
||||
behavior: 'allow' | 'deny'
|
||||
updatedInput?: Record<string, unknown>
|
||||
updatedPermissions?: PermissionUpdate[]
|
||||
message?: string
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 6. 权限规则管理
|
||||
|
||||
### 6.1 PermissionUpdate
|
||||
|
||||
**文件位置**: `src/utils/permissions/PermissionUpdateSchema.ts`
|
||||
|
||||
```typescript
|
||||
type PermissionUpdate = {
|
||||
destination: 'alwaysAllowRules' | 'alwaysDenyRules' | 'command'
|
||||
rule: {
|
||||
tool: string
|
||||
input?: Record<string, unknown>
|
||||
matchers?: InputMatcher[]
|
||||
}
|
||||
Permanente: boolean
|
||||
}
|
||||
```
|
||||
|
||||
### 6.2 规则应用
|
||||
|
||||
```typescript
|
||||
export function applyPermissionUpdates(
|
||||
context: ToolPermissionContext,
|
||||
updates: PermissionUpdate[]
|
||||
): ToolPermissionContext
|
||||
```
|
||||
|
||||
### 6.3 规则持久化
|
||||
|
||||
```typescript
|
||||
export function persistPermissionUpdates(updates: PermissionUpdate[]): void
|
||||
export function supportsPersistence(
|
||||
destination: 'alwaysAllowRules' | 'alwaysDenyRules' | 'command'
|
||||
): boolean
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 7. Bash 分类器
|
||||
|
||||
**文件位置**: `src/tools/BashTool/bashPermissions.ts`
|
||||
|
||||
### 分类器决策
|
||||
|
||||
```typescript
|
||||
type ClassifierDecision =
|
||||
| { type: 'classifier'; classifier: 'auto-mode'; reason: string }
|
||||
| { type: 'classifier'; classifier: 'pattern-match'; reason: string }
|
||||
| { type: 'user-defined'; reason: string }
|
||||
| { type: 'deny'; reason: string }
|
||||
```
|
||||
|
||||
### 分类器检查
|
||||
|
||||
```typescript
|
||||
export async function awaitClassifierAutoApproval(
|
||||
pendingClassifierCheck: PendingClassifierCheck,
|
||||
signal: AbortSignal,
|
||||
isNonInteractiveSession: boolean,
|
||||
): Promise<ClassifierDecision | null>
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 8. 权限日志
|
||||
|
||||
**文件位置**: `src/hooks/toolPermission/permissionLogging.ts`
|
||||
|
||||
### 日志函数
|
||||
|
||||
```typescript
|
||||
export function logPermissionDecision(
|
||||
args: PermissionDecisionArgs,
|
||||
decision: {
|
||||
decision: 'accept' | 'reject'
|
||||
source: PermissionApprovalSource | PermissionRejectionSource
|
||||
},
|
||||
permissionPromptStartTimeMs?: number
|
||||
): void
|
||||
```
|
||||
|
||||
### 事件类型
|
||||
|
||||
```typescript
|
||||
// 接受
|
||||
logEvent('tengu_tool_permission_accepted', {...})
|
||||
logEvent('tengu_tool_permission_auto_approved', {...})
|
||||
|
||||
// 拒绝
|
||||
logEvent('tengu_tool_permission_rejected', {...})
|
||||
logEvent('tengu_tool_use_cancelled', {...})
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 9. 权限检查入口
|
||||
|
||||
**文件位置**: `src/utils/permissions/permissions.ts`
|
||||
|
||||
### 主检查函数
|
||||
|
||||
```typescript
|
||||
export async function hasPermissionsToUseTool(
|
||||
tool: Tool,
|
||||
input: Record<string, unknown>,
|
||||
toolUseContext: ToolUseContext,
|
||||
assistantMessage: AssistantMessage,
|
||||
toolUseID: string,
|
||||
): Promise<PermissionDecision>
|
||||
```
|
||||
|
||||
**决策流程**:
|
||||
|
||||
1. **模式检查**
|
||||
- `bypassPermissions`: 直接允许
|
||||
- `plan`: 计划模式规则
|
||||
- `auto`: 分类器自动决策
|
||||
|
||||
2. **规则匹配**
|
||||
- `alwaysAllowRules`: 匹配则允许
|
||||
- `alwaysDenyRules`: 匹配则拒绝
|
||||
|
||||
3. **会话状态**
|
||||
- 非交互式会话可能有不同行为
|
||||
|
||||
4. **分类器检查**
|
||||
- 仅 Bash 工具支持
|
||||
- 异步执行
|
||||
|
||||
5. **Hook 检查**
|
||||
- 执行 PermissionRequest hooks
|
||||
|
||||
6. **降级到交互式**
|
||||
- 返回 `{ behavior: 'ask' }`
|
||||
|
||||
---
|
||||
|
||||
## 10. 权限队列
|
||||
|
||||
### ToolUseConfirm
|
||||
|
||||
```typescript
|
||||
type ToolUseConfirm = {
|
||||
assistantMessage: AssistantMessage
|
||||
tool: Tool
|
||||
description: string
|
||||
input: Record<string, unknown>
|
||||
toolUseContext: ToolUseContext
|
||||
toolUseID: string
|
||||
permissionResult: PermissionDecision & { behavior: 'ask' }
|
||||
permissionPromptStartTimeMs: number
|
||||
classifierCheckInProgress?: boolean
|
||||
classifierAutoApproved?: boolean
|
||||
classifierMatchedRule?: string
|
||||
|
||||
onUserInteraction(): void
|
||||
onDismissCheckmark(): void
|
||||
onAbort(): void
|
||||
onAllow(
|
||||
updatedInput: Record<string, unknown>,
|
||||
permissionUpdates: PermissionUpdate[],
|
||||
feedback?: string,
|
||||
contentBlocks?: ContentBlockParam[]
|
||||
): Promise<void>
|
||||
onReject(feedback?: string, contentBlocks?: ContentBlockParam[]): void
|
||||
recheckPermission(): Promise<void>
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 11. 权限处理流程图
|
||||
|
||||
```
|
||||
用户执行工具
|
||||
│
|
||||
▼
|
||||
hasPermissionsToUseTool()
|
||||
│
|
||||
▼
|
||||
┌─────────────────────┐
|
||||
│ 权限模式检查 │
|
||||
│ bypassPermissions? │ ───是──▶ 直接允许
|
||||
└─────────────────────┘
|
||||
│否
|
||||
▼
|
||||
┌─────────────────────┐
|
||||
│ 规则检查 │
|
||||
│ alwaysAllowRules? │ ───是──▶ 直接允许
|
||||
│ alwaysDenyRules? │ ───是──▶ 直接拒绝
|
||||
└─────────────────────┘
|
||||
│
|
||||
▼
|
||||
┌─────────────────────┐
|
||||
│ 分类器检查 │
|
||||
│ BASH_CLASSIFIER? │ ───是──▶ 异步推理
|
||||
└─────────────────────┘
|
||||
│
|
||||
▼
|
||||
┌─────────────────────┐
|
||||
│ Hook 检查 │
|
||||
│ executePermission │ ───允许──▶ 返回允许
|
||||
│ RequestHooks │ ───拒绝──▶ 返回拒绝
|
||||
└─────────────────────┘
|
||||
│
|
||||
▼
|
||||
交互式确认对话框
|
||||
│
|
||||
├─── 用户允许 ───▶ handleUserAllow()
|
||||
│ │
|
||||
│ ▼
|
||||
│ persistPermissions()
|
||||
│ │
|
||||
│ ▼
|
||||
│ logPermissionDecision()
|
||||
│ │
|
||||
│ ▼
|
||||
│ 返回 PermissionAllowDecision
|
||||
│
|
||||
├─── 用户拒绝 ───▶ onReject()
|
||||
│ │
|
||||
│ ▼
|
||||
│ cancelAndAbort()
|
||||
│ │
|
||||
│ ▼
|
||||
│ 返回 PermissionDenyDecision
|
||||
│
|
||||
└─── 用户中断 ───▶ Esc 按键
|
||||
│
|
||||
▼
|
||||
abortController.abort()
|
||||
│
|
||||
▼
|
||||
返回 PermissionDenyDecision
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 12. 远程权限流程
|
||||
|
||||
```
|
||||
CLI 端 (handleInteractivePermission)
|
||||
│
|
||||
▼
|
||||
bridgeCallbacks.sendRequest(bridgeRequestId, ...)
|
||||
│
|
||||
│ WebSocket / HTTP
|
||||
▼
|
||||
IDE Extension / Web UI
|
||||
│
|
||||
▼
|
||||
显示权限对话框
|
||||
│
|
||||
▼
|
||||
用户允许/拒绝
|
||||
│
|
||||
▼
|
||||
bridgeCallbacks.sendResponse(bridgeRequestId, response)
|
||||
│
|
||||
│ WebSocket / HTTP
|
||||
▼
|
||||
CLI 端 (onResponse 回调)
|
||||
│
|
||||
▼
|
||||
resolveOnce(decision)
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 13. 关键常量
|
||||
|
||||
```typescript
|
||||
// 200ms 宽限期后用户交互取消分类器
|
||||
const GRACE_PERIOD_MS = 200
|
||||
|
||||
// 分类器自动批准后显示 ✓ 的时间
|
||||
const CHECKMARK_DISPLAY_MS = 3000 // 终端聚焦时
|
||||
const CHECKMARK_DISPLAY_MS = 1000 // 终端未聚焦时
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 相关源码文件
|
||||
|
||||
| 文件 | 功能 |
|
||||
|------|------|
|
||||
| `PermissionContext.ts` | 权限上下文创建和管理 |
|
||||
| `handlers/coordinatorHandler.ts` | 协调者处理器 |
|
||||
| `handlers/interactiveHandler.ts` | 交互式处理器 |
|
||||
| `handlers/swarmWorkerHandler.ts` | Swarm Worker 处理器 |
|
||||
| `permissionLogging.ts` | 权限日志记录 |
|
||||
| `src/utils/permissions/permissions.ts` | 权限检查入口 |
|
||||
| `src/utils/permissions/PermissionUpdate.ts` | 权限更新管理 |
|
||||
| `src/utils/permissions/PermissionMode.ts` | 权限模式定义 |
|
||||
| `src/bridge/bridgePermissionCallbacks.ts` | 桥接权限回调 |
|
||||
| `src/tools/BashTool/bashPermissions.ts` | Bash 分类器 |
|
||||
| `src/types/permissions.ts` | 权限类型定义 |
|
||||
279
claude-code-中文Wiki/08-插件与技能系统.md
Normal file
279
claude-code-中文Wiki/08-插件与技能系统.md
Normal file
@@ -0,0 +1,279 @@
|
||||
# 插件与技能系统
|
||||
|
||||
Claude Code 提供了强大的插件系统和技能系统来扩展功能。本文档详细介绍这两个系统的架构和实现。
|
||||
|
||||
## 1. 插件系统 (plugins/)
|
||||
|
||||
### 1.1 插件加载机制
|
||||
|
||||
Claude Code 的插件系统支持内置插件和第三方插件。
|
||||
|
||||
**关键文件:**
|
||||
- `/src/plugins/builtinPlugins.ts` - 内置插件注册表
|
||||
- `/src/utils/plugins/pluginLoader.ts` - 插件加载器
|
||||
- `/src/utils/plugins/loadPluginHooks.ts` - 插件钩子加载
|
||||
|
||||
**插件结构:**
|
||||
```typescript
|
||||
interface LoadedPlugin {
|
||||
name: string // 插件名称
|
||||
manifest: { // 插件清单
|
||||
name: string
|
||||
description: string
|
||||
version: string
|
||||
}
|
||||
path: string // 插件路径
|
||||
source: string // 来源标识
|
||||
repository: string // 仓库地址
|
||||
enabled: boolean // 是否启用
|
||||
isBuiltin: boolean // 是否为内置插件
|
||||
hooksConfig?: HooksSettings // 钩子配置
|
||||
mcpServers?: MCPServer[] // MCP 服务器配置
|
||||
}
|
||||
```
|
||||
|
||||
### 1.2 内置插件 (builtinPlugins.ts)
|
||||
|
||||
内置插件是与 Claude Code CLI 一起打包的插件,可以通过 `/plugin` UI 启用/禁用。
|
||||
|
||||
**与 Bundled Skills 的区别:**
|
||||
| 特性 | 内置插件 | Bundled Skills |
|
||||
|------|----------|----------------|
|
||||
| 出现位置 | `/plugin` UI 的 "Built-in" 部分 | `/skills` 列表 |
|
||||
| 用户控制 | 可启用/禁用(持久化到用户设置) | 始终可用 |
|
||||
| 组件类型 | 可提供多种组件(skills, hooks, MCP servers) | 仅 skills |
|
||||
|
||||
**插件 ID 格式:**
|
||||
- 内置插件:`{name}@builtin`
|
||||
- 市场插件:`{name}@{marketplace}`
|
||||
|
||||
**核心函数:**
|
||||
```typescript
|
||||
// 注册内置插件
|
||||
registerBuiltinPlugin(definition: BuiltinPluginDefinition): void
|
||||
|
||||
// 检查是否为内置插件
|
||||
isBuiltinPluginId(pluginId: string): boolean
|
||||
|
||||
// 获取所有内置插件(分启用/禁用)
|
||||
getBuiltinPlugins(): { enabled: LoadedPlugin[]; disabled: LoadedPlugin[] }
|
||||
|
||||
// 获取内置插件提供的技能命令
|
||||
getBuiltinPluginSkillCommands(): Command[]
|
||||
```
|
||||
|
||||
### 1.3 插件注册和执行流程
|
||||
|
||||
**注册流程:**
|
||||
1. 在启动时调用 `initBuiltinPlugins()` 注册所有内置插件
|
||||
2. 插件定义包含:`name`, `description`, `version`, `isAvailable()`, `defaultEnabled`, `skills`, `hooks`, `mcpServers`
|
||||
|
||||
**加载流程 (loadPluginHooks.ts):**
|
||||
```typescript
|
||||
export const loadPluginHooks = memoize(async (): Promise<void> => {
|
||||
const { enabled } = await loadAllPluginsCacheOnly()
|
||||
// 转换插件钩子配置为匹配器
|
||||
const pluginMatchers = convertPluginHooksToMatchers(plugin)
|
||||
// 清除旧钩子并注册新钩子(原子操作)
|
||||
clearRegisteredPluginHooks()
|
||||
registerHookCallbacks(allPluginHooks)
|
||||
})
|
||||
```
|
||||
|
||||
**钩子事件类型:**
|
||||
- `PreToolUse` - 工具执行前
|
||||
- `PostToolUse` - 工具执行后
|
||||
- `PermissionDenied` - 权限被拒绝
|
||||
- `SessionStart/SessionEnd` - 会话开始/结束
|
||||
- `SubagentStart/SubagentStop` - 子智能体启动/停止
|
||||
- `TaskCreated/TaskCompleted` - 任务创建/完成
|
||||
|
||||
### 1.4 第三方插件支持
|
||||
|
||||
第三方插件通过市场安装,支持以下功能:
|
||||
- 自定义 skills
|
||||
- 钩子系统
|
||||
- MCP 服务器
|
||||
|
||||
## 2. 技能系统 (skills/)
|
||||
|
||||
### 2.1 技能定义和格式
|
||||
|
||||
**技能定义结构 (BundledSkillDefinition):**
|
||||
```typescript
|
||||
type BundledSkillDefinition = {
|
||||
name: string // 技能名称
|
||||
description: string // 技能描述
|
||||
aliases?: string[] // 别名
|
||||
whenToUse?: string // 使用建议
|
||||
argumentHint?: string // 参数提示
|
||||
allowedTools?: string[] // 允许的工具
|
||||
model?: string // 模型覆盖
|
||||
disableModelInvocation?: boolean // 禁用模型调用
|
||||
userInvocable?: boolean // 用户可调用
|
||||
isEnabled?: () => boolean // 启用检查函数
|
||||
hooks?: HooksSettings // 钩子设置
|
||||
context?: 'inline' | 'fork' // 执行上下文
|
||||
agent?: string // 代理类型
|
||||
files?: Record<string, string> // 参考文件
|
||||
getPromptForCommand: (args: string, context: ToolUseContext) => Promise<ContentBlockParam[]>
|
||||
}
|
||||
```
|
||||
|
||||
### 2.2 技能执行机制 (SkillTool)
|
||||
|
||||
**关键文件:** `/src/tools/SkillTool/SkillTool.ts`
|
||||
|
||||
**执行模式:**
|
||||
|
||||
1. **Inline 模式(内联执行)**
|
||||
- 技能内容直接注入对话
|
||||
- 使用 `processPromptSlashCommand` 处理
|
||||
- 支持 `!command` 和 `$ARGUMENTS` 扩展
|
||||
|
||||
2. **Fork 模式(分叉执行)**
|
||||
- 在独立子智能体中运行技能
|
||||
- 拥有独立 token 预算
|
||||
- 通过 `executeForkedSkill` 实现
|
||||
|
||||
**SkillTool 输入/输出:**
|
||||
```typescript
|
||||
// 输入
|
||||
input: {
|
||||
skill: string // 技能名称,如 "commit", "review-pr"
|
||||
args?: string // 可选参数
|
||||
}
|
||||
|
||||
// 输出
|
||||
output: {
|
||||
success: boolean
|
||||
commandName: string
|
||||
status: 'inline' | 'forked'
|
||||
agentId?: string // fork 模式下的子智能体 ID
|
||||
result?: string // fork 模式下的执行结果
|
||||
}
|
||||
```
|
||||
|
||||
**权限检查:**
|
||||
- 技能执行需要权限检查
|
||||
- 支持规则匹配(前缀匹配如 `review:*`)
|
||||
- 自动允许安全属性的技能
|
||||
|
||||
### 2.3 内置技能
|
||||
|
||||
**位置:** `/src/skills/bundled/`
|
||||
|
||||
**内置技能列表:**
|
||||
| 技能名 | 描述 |
|
||||
|--------|------|
|
||||
| `remember` | 记忆技能 |
|
||||
| `loremIpsum` | 生成占位文本 |
|
||||
| `verify` | 验证技能 |
|
||||
| `loop` | 循环执行技能 |
|
||||
| `claudeApi` | Claude API 相关 |
|
||||
| `debug` | 调试技能 |
|
||||
| `stuck` | 处理卡住情况 |
|
||||
| `batch` | 批量处理 |
|
||||
| `updateConfig` | 更新配置 |
|
||||
| `keybindings` | 快捷键 |
|
||||
| `simplify` | 简化代码 |
|
||||
| `skillify` | 技能化 |
|
||||
|
||||
### 2.4 用户自定义技能
|
||||
|
||||
用户可以在 `~/.claude/skills/` 目录下创建自定义技能。
|
||||
|
||||
**技能文件结构:**
|
||||
```
|
||||
~/.claude/skills/
|
||||
└── my-skill/
|
||||
└── SKILL.md # 技能定义文件
|
||||
```
|
||||
|
||||
**注册流程:**
|
||||
```typescript
|
||||
// 注册技能
|
||||
registerBundledSkill(definition: BundledSkillDefinition): void
|
||||
|
||||
// 获取所有已注册技能
|
||||
getBundledSkills(): Command[]
|
||||
|
||||
// 技能文件提取(用于有参考文件的技能)
|
||||
async function extractBundledSkillFiles(
|
||||
skillName: string,
|
||||
files: Record<string, string>
|
||||
): Promise<string | null>
|
||||
```
|
||||
|
||||
### 2.5 技能与命令的转换
|
||||
|
||||
技能在内部被转换为 `Command` 对象:
|
||||
|
||||
```typescript
|
||||
function skillDefinitionToCommand(definition: BundledSkillDefinition): Command {
|
||||
return {
|
||||
type: 'prompt',
|
||||
name: definition.name,
|
||||
description: definition.description,
|
||||
source: 'bundled',
|
||||
loadedFrom: 'bundled',
|
||||
hooks: definition.hooks,
|
||||
context: definition.context,
|
||||
agent: definition.agent,
|
||||
// ...
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## 3. 插件与技能的协同
|
||||
|
||||
### 3.1 插件提供技能
|
||||
|
||||
插件可以通过内置技能机制提供技能:
|
||||
```typescript
|
||||
// 插件定义
|
||||
const myPlugin: BuiltinPluginDefinition = {
|
||||
name: 'my-plugin',
|
||||
description: 'My custom plugin',
|
||||
skills: [skill1, skill2],
|
||||
// ...
|
||||
}
|
||||
```
|
||||
|
||||
### 3.2 钩子在技能执行中的应用
|
||||
|
||||
技能执行时会触发各种钩子:
|
||||
- `PreToolUse` - 检查技能是否允许使用特定工具
|
||||
- `PostToolUse` - 记录技能执行结果
|
||||
- `Stop` - 技能执行完成
|
||||
|
||||
## 4. MCP 集成
|
||||
|
||||
技能系统支持 MCP (Model Context Protocol) 技能构建器:
|
||||
|
||||
```typescript
|
||||
// 位置:/src/skills/mcpSkillBuilders.ts
|
||||
export function createMcpSkill(
|
||||
serverName: string,
|
||||
toolName: string
|
||||
): BundledSkillDefinition
|
||||
```
|
||||
|
||||
## 5. 权限与安全
|
||||
|
||||
### 5.1 技能白名单
|
||||
|
||||
`SAFE_SKILL_PROPERTIES` 定义了安全属性列表,只包含以下属性的技能会自动获得权限:
|
||||
- `type`, `progressMessage`, `contentLength`, `argNames`, `model`, `effort`
|
||||
- `source`, `pluginInfo`, `disableNonInteractive`, `skillRoot`, `context`, `agent`
|
||||
- `getPromptForCommand`, `frontmatterKeys`
|
||||
- `name`, `description`, `hasUserSpecifiedDescription`, `isEnabled`, `isHidden`
|
||||
- `aliases`, `isMcp`, `argumentHint`, `whenToUse`, `paths`, `version`
|
||||
- `disableModelInvocation`, `userInvocable`, `loadedFrom`, `immediate`, `userFacingName`
|
||||
|
||||
### 5.2 远程技能 (实验性)
|
||||
|
||||
启用 `EXPERIMENTAL_SKILL_SEARCH` 后支持远程技能:
|
||||
- 技能定义存储在远程服务器
|
||||
- 通过 `_canonical_<slug>` 格式引用
|
||||
- 支持 GCS、HTTP/HTTPS、S3 等协议
|
||||
390
claude-code-中文Wiki/09-状态与任务管理.md
Normal file
390
claude-code-中文Wiki/09-状态与任务管理.md
Normal file
@@ -0,0 +1,390 @@
|
||||
# 状态与任务管理
|
||||
|
||||
Claude Code 提供了强大的状态管理和任务管理系统来协调复杂的操作流程。
|
||||
|
||||
## 1. 状态管理 (state/)
|
||||
|
||||
### 1.1 状态存储机制
|
||||
|
||||
**核心文件:**
|
||||
- `/src/state/store.ts` - 状态存储基础实现
|
||||
- `/src/state/AppStateStore.ts` - 应用状态存储
|
||||
- `/src/state/onChangeAppState.ts` - 状态变更处理
|
||||
- `/src/state/selectors.ts` - 状态选择器
|
||||
|
||||
**Store 模式实现:**
|
||||
```typescript
|
||||
// 位置:/src/state/store.ts
|
||||
export type Store<T> = {
|
||||
getState: () => T // 获取当前状态
|
||||
setState: (updater: (prev: T) => T) => void // 更新状态
|
||||
subscribe: (listener: Listener) => () => void // 订阅变更
|
||||
}
|
||||
|
||||
export function createStore<T>(
|
||||
initialState: T,
|
||||
onChange?: OnChange<T>
|
||||
): Store<T>
|
||||
```
|
||||
|
||||
**特性:**
|
||||
- 不可变性(Immutability):状态更新采用函数式风格
|
||||
- 订阅机制:支持多个监听器,变更时自动通知
|
||||
- 变更回调:`onChange` 回调在状态变更后执行
|
||||
|
||||
### 1.2 AppState 结构
|
||||
|
||||
**位置:** `/src/state/AppStateStore.ts`
|
||||
|
||||
`AppState` 是全局状态的核心结构,包含以下主要部分:
|
||||
|
||||
```typescript
|
||||
export type AppState = {
|
||||
// 设置与配置
|
||||
settings: SettingsJson
|
||||
verbose: boolean
|
||||
mainLoopModel: ModelSetting
|
||||
|
||||
// 任务管理
|
||||
tasks: { [taskId: string]: TaskState }
|
||||
agentNameRegistry: Map<string, AgentId>
|
||||
foregroundedTaskId?: string
|
||||
viewingAgentTaskId?: string
|
||||
|
||||
// MCP 状态
|
||||
mcp: {
|
||||
clients: MCPServerConnection[]
|
||||
tools: Tool[]
|
||||
commands: Command[]
|
||||
resources: Record<string, ServerResource[]>
|
||||
pluginReconnectKey: number
|
||||
}
|
||||
|
||||
// 插件状态
|
||||
plugins: {
|
||||
enabled: LoadedPlugin[]
|
||||
disabled: LoadedPlugin[]
|
||||
commands: Command[]
|
||||
errors: PluginError[]
|
||||
installationStatus: {...}
|
||||
needsRefresh: boolean
|
||||
}
|
||||
|
||||
// Agent 定义
|
||||
agentDefinitions: AgentDefinitionsResult
|
||||
|
||||
// 团队上下文
|
||||
teamContext?: {
|
||||
teamName: string
|
||||
teamFilePath: string
|
||||
leadAgentId: string
|
||||
selfAgentId?: string
|
||||
selfAgentName?: string
|
||||
isLeader?: boolean
|
||||
selfAgentColor?: string
|
||||
teammates: {...}
|
||||
}
|
||||
|
||||
// 推理状态
|
||||
speculation: SpeculationState
|
||||
thinkingEnabled: boolean | undefined
|
||||
}
|
||||
```
|
||||
|
||||
### 1.3 状态持久化
|
||||
|
||||
**持久化策略:**
|
||||
- 设置存储在 `~/.claude/settings.json`
|
||||
- 任务状态存储在 `~/.claude/tasks/{taskListId}/`
|
||||
- 团队配置存储在 `~/.claude/teams/{team-name}/`
|
||||
|
||||
**状态恢复:**
|
||||
- 应用启动时从磁盘加载设置
|
||||
- 团队成员重新连接时恢复上下文
|
||||
- 任务队列在会话间持久化
|
||||
|
||||
### 1.4 状态变更处理
|
||||
|
||||
**onChangeAppState.ts:**
|
||||
```typescript
|
||||
// 状态变更时的处理逻辑
|
||||
- 任务创建时自动展开任务列表
|
||||
- 插件状态变更时触发热重载
|
||||
- 团队上下文变更时更新 UI
|
||||
```
|
||||
|
||||
## 2. 任务管理 (tasks/)
|
||||
|
||||
### 2.1 任务类型
|
||||
|
||||
**位置:** `/src/tasks/types.ts`
|
||||
|
||||
Claude Code 支持多种任务类型:
|
||||
|
||||
```typescript
|
||||
export type TaskState =
|
||||
| LocalShellTaskState // 本地 Shell 任务
|
||||
| LocalAgentTaskState // 本地 Agent 任务
|
||||
| RemoteAgentTaskState // 远程 Agent 任务
|
||||
| InProcessTeammateTaskState // 进程中队友任务
|
||||
| LocalWorkflowTaskState // 本地工作流任务
|
||||
| MonitorMcpTaskState // MCP 监控任务
|
||||
| DreamTaskState // 异步任务
|
||||
```
|
||||
|
||||
### 2.2 任务状态机
|
||||
|
||||
**任务状态流转:**
|
||||
|
||||
```
|
||||
pending → in_progress → completed
|
||||
↓ ↓ ↓
|
||||
blocked blocked blocked
|
||||
↓ ↓
|
||||
cancelled cancelled
|
||||
```
|
||||
|
||||
**状态定义:**
|
||||
```typescript
|
||||
type TaskStatus = 'pending' | 'in_progress' | 'completed' | 'cancelled' | 'blocked'
|
||||
|
||||
interface TaskState {
|
||||
id: string
|
||||
status: TaskStatus
|
||||
subject: string
|
||||
description?: string
|
||||
activeForm?: string // 进行中的操作描述
|
||||
owner?: string // 任务负责人
|
||||
blocks: string[] // 此任务阻止的任务
|
||||
blockedBy: string[] // 阻止此任务的任务
|
||||
metadata?: Record<string, unknown>
|
||||
}
|
||||
```
|
||||
|
||||
### 2.3 任务工具
|
||||
|
||||
Claude Code 提供四个主要任务工具:
|
||||
|
||||
#### TaskCreateTool
|
||||
|
||||
**位置:** `/src/tools/TaskCreateTool/TaskCreateTool.ts`
|
||||
|
||||
```typescript
|
||||
input: {
|
||||
subject: string // 任务标题
|
||||
description: string // 任务描述
|
||||
activeForm?: string // 进行中显示文本
|
||||
metadata?: Record<string, unknown> // 元数据
|
||||
}
|
||||
|
||||
output: {
|
||||
task: {
|
||||
id: string
|
||||
subject: string
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
**特性:**
|
||||
- 创建任务后自动展开任务列表
|
||||
- 支持任务创建钩子 (`TaskCreated` hooks)
|
||||
- 阻止错误的钩子可取消创建
|
||||
|
||||
#### TaskUpdateTool
|
||||
|
||||
**位置:** `/src/tools/TaskUpdateTool/TaskUpdateTool.ts`
|
||||
|
||||
```typescript
|
||||
input: {
|
||||
taskId: string
|
||||
subject?: string
|
||||
description?: string
|
||||
activeForm?: string
|
||||
status?: TaskStatus | 'deleted'
|
||||
addBlocks?: string[] // 此任务阻止的任务
|
||||
addBlockedBy?: string[] // 阻止此任务的任务
|
||||
owner?: string
|
||||
metadata?: Record<string, unknown>
|
||||
}
|
||||
|
||||
output: {
|
||||
success: boolean
|
||||
taskId: string
|
||||
updatedFields: string[]
|
||||
statusChange?: { from: string; to: string }
|
||||
verificationNudgeNeeded?: boolean
|
||||
}
|
||||
```
|
||||
|
||||
**特性:**
|
||||
- 支持原子字段更新
|
||||
- 任务完成时触发 `TaskCompleted` 钩子
|
||||
- 所有权变更时通知新负责人
|
||||
- 阻止依赖任务处理
|
||||
|
||||
#### TaskListTool
|
||||
|
||||
列出所有任务,支持过滤和排序。
|
||||
|
||||
#### TaskStopTool
|
||||
|
||||
停止正在运行的任务。
|
||||
|
||||
### 2.4 任务间依赖
|
||||
|
||||
**依赖管理:**
|
||||
```typescript
|
||||
// 阻止关系
|
||||
task.blocks = ['task-id-1', 'task-id-2'] // 此任务阻止这些任务
|
||||
task.blockedBy = ['task-id-3'] // 此任务被这些任务阻止
|
||||
|
||||
// 依赖检查
|
||||
function canStartTask(task: TaskState): boolean {
|
||||
return task.blockedBy.every(id => isTaskCompleted(id))
|
||||
}
|
||||
```
|
||||
|
||||
### 2.5 任务输出 (TaskOutputTool)
|
||||
|
||||
**位置:** `/src/tools/TaskOutputTool/`
|
||||
|
||||
用于检索任务的执行输出和结果。
|
||||
|
||||
## 3. 任务与状态的集成
|
||||
|
||||
### 3.1 AppState 中的任务管理
|
||||
|
||||
```typescript
|
||||
// 任务存储在 AppState.tasks 中
|
||||
tasks: { [taskId: string]: TaskState }
|
||||
|
||||
// 任务 ID 注册表(用于按名称查找)
|
||||
agentNameRegistry: Map<string, AgentId>
|
||||
|
||||
// 前台任务 ID
|
||||
foregroundedTaskId?: string
|
||||
|
||||
// 查看中的 Agent 任务 ID
|
||||
viewingAgentTaskId?: string
|
||||
```
|
||||
|
||||
### 3.2 任务状态变更与 UI 更新
|
||||
|
||||
```typescript
|
||||
// TaskCreateTool 和 TaskUpdateTool 自动更新 expandedView
|
||||
context.setAppState(prev => {
|
||||
if (prev.expandedView === 'tasks') return prev
|
||||
return { ...prev, expandedView: 'tasks' as const }
|
||||
})
|
||||
```
|
||||
|
||||
## 4. 后台任务管理
|
||||
|
||||
### 4.1 背景任务识别
|
||||
|
||||
```typescript
|
||||
export function isBackgroundTask(task: TaskState): boolean {
|
||||
if (task.status !== 'running' && task.status !== 'pending') {
|
||||
return false
|
||||
}
|
||||
// 前台任务(isBackgrounded === false)不是后台任务
|
||||
if ('isBackgrounded' in task && task.isBackgrounded === false) {
|
||||
return false
|
||||
}
|
||||
return true
|
||||
}
|
||||
```
|
||||
|
||||
### 4.2 任务清理
|
||||
|
||||
**Shell 任务清理:**
|
||||
```typescript
|
||||
// 位置:/src/tasks/LocalShellTask/killShellTasks.ts
|
||||
export function killShellTasksForAgent(
|
||||
agentId: AgentId,
|
||||
getAppState: () => AppState,
|
||||
setAppState: (updater: (prev: AppState) => AppState) => void
|
||||
): void
|
||||
```
|
||||
|
||||
### 4.3 任务与 Hooks 的集成
|
||||
|
||||
```typescript
|
||||
// 任务创建钩子
|
||||
executeTaskCreatedHooks(
|
||||
taskId: string,
|
||||
subject: string,
|
||||
description: string,
|
||||
agentName: string | undefined,
|
||||
teamName: string | undefined,
|
||||
// ...
|
||||
)
|
||||
|
||||
// 任务完成钩子
|
||||
executeTaskCompletedHooks(
|
||||
taskId: string,
|
||||
subject: string,
|
||||
description: string,
|
||||
agentName: string | undefined,
|
||||
teamName: string | undefined,
|
||||
// ...
|
||||
)
|
||||
```
|
||||
|
||||
## 5. 工作流集成
|
||||
|
||||
### 5.1 DreamTask
|
||||
|
||||
用于异步长时间运行的任务:
|
||||
```typescript
|
||||
// 位置:/src/tasks/DreamTask/DreamTask.ts
|
||||
export type DreamTaskState = {
|
||||
// 异步任务状态
|
||||
}
|
||||
```
|
||||
|
||||
### 5.2 InProcessTeammateTask
|
||||
|
||||
用于进程中队友通信的任务类型:
|
||||
```typescript
|
||||
// 位置:/src/tasks/InProcessTeammateTask/types.ts
|
||||
export type InProcessTeammateTaskState = {
|
||||
identity: TeammateIdentity
|
||||
abortController?: AbortController
|
||||
shutdownRequested?: boolean
|
||||
// ...
|
||||
}
|
||||
```
|
||||
|
||||
## 6. 任务列表管理
|
||||
|
||||
### 6.1 任务列表 ID
|
||||
|
||||
```typescript
|
||||
function getTaskListId(): string {
|
||||
// 基于团队名称或会话 ID
|
||||
}
|
||||
```
|
||||
|
||||
### 6.2 任务通知
|
||||
|
||||
```typescript
|
||||
// 任务更新通知
|
||||
notifyTasksUpdated()
|
||||
|
||||
// 任务目录
|
||||
getTasksDir(taskListId: string): string
|
||||
```
|
||||
|
||||
## 7. 验证与提醒
|
||||
|
||||
当完成任务列表时,系统会检查是否需要进行验证:
|
||||
|
||||
```typescript
|
||||
// 在 TaskUpdateTool 中
|
||||
if (allTasks.length >= 3 && !allTasks.some(t => /verif/i.test(t.subject))) {
|
||||
verificationNudgeNeeded = true
|
||||
}
|
||||
```
|
||||
|
||||
这提醒主线程 Agent 在没有验证步骤的情况下关闭了 3+ 个任务列表。
|
||||
437
claude-code-中文Wiki/10-多智能体协作.md
Normal file
437
claude-code-中文Wiki/10-多智能体协作.md
Normal file
@@ -0,0 +1,437 @@
|
||||
# 多智能体协作
|
||||
|
||||
Claude Code 的多智能体系统允许创建和协调多个 AI 代理协同工作。本文档详细介绍 AgentTool 和相关协作机制。
|
||||
|
||||
## 1. AgentTool 概述
|
||||
|
||||
### 1.1 核心文件
|
||||
|
||||
**位置:** `/src/tools/AgentTool/`
|
||||
|
||||
**主要文件:**
|
||||
- `runAgent.ts` - Agent 运行核心逻辑
|
||||
- `builtInAgents.ts` - 内置 Agent 定义
|
||||
- `loadAgentsDir.ts` - Agent 目录加载
|
||||
- `agentMemory.ts` - Agent 内存管理
|
||||
- `built-in/` - 内置 Agent 实现
|
||||
|
||||
### 1.2 Agent 定义结构
|
||||
|
||||
```typescript
|
||||
export type AgentDefinition = {
|
||||
agentType: string // Agent 类型标识
|
||||
whenToUse?: string // 使用建议
|
||||
disallowedTools?: string[] // 禁用工具列表
|
||||
tools?: string[] | '*' // 允许的工具
|
||||
source?: string // 来源
|
||||
baseDir?: string // 基础目录
|
||||
model?: string // 模型设置
|
||||
permissionMode?: PermissionMode // 权限模式
|
||||
maxTurns?: number // 最大轮次
|
||||
getSystemPrompt?: () => string // 系统提示
|
||||
hooks?: HooksSettings // 钩子设置
|
||||
skills?: string[] // 预加载技能
|
||||
mcpServers?: MCPServerSpec[] // MCP 服务器
|
||||
omitClaudeMd?: boolean // 是否省略 CLAUDE.md
|
||||
effort?: EffortValue // 努力值
|
||||
callback?: () => void // 完成回调
|
||||
}
|
||||
```
|
||||
|
||||
## 2. 子智能体生成
|
||||
|
||||
### 2.1 runAgent 函数
|
||||
|
||||
**位置:** `/src/tools/AgentTool/runAgent.ts`
|
||||
|
||||
`runAgent` 是创建和运行子智能体的核心函数:
|
||||
|
||||
```typescript
|
||||
export async function* runAgent({
|
||||
agentDefinition, // Agent 定义
|
||||
promptMessages, // 提示消息
|
||||
toolUseContext, // 工具使用上下文
|
||||
canUseTool, // 工具使用权限检查
|
||||
isAsync, // 是否异步执行
|
||||
querySource, // 查询来源
|
||||
model, // 模型覆盖
|
||||
maxTurns, // 最大轮次
|
||||
allowedTools, // 允许的工具列表
|
||||
// ...
|
||||
}): AsyncGenerator<Message, void>
|
||||
```
|
||||
|
||||
### 2.2 消息过滤
|
||||
|
||||
```typescript
|
||||
// 过滤不完整的工具调用
|
||||
export function filterIncompleteToolCalls(messages: Message[]): Message[] {
|
||||
// 移除有工具调用但没有结果的助手消息
|
||||
}
|
||||
```
|
||||
|
||||
### 2.3 上下文隔离
|
||||
|
||||
```typescript
|
||||
// 为子智能体创建隔离的上下文
|
||||
const agentToolUseContext = createSubagentContext(toolUseContext, {
|
||||
options: agentOptions,
|
||||
agentId,
|
||||
agentType: agentDefinition.agentType,
|
||||
messages: initialMessages,
|
||||
readFileState: agentReadFileState,
|
||||
abortController: agentAbortController,
|
||||
getAppState: agentGetAppState,
|
||||
shareSetAppState: !isAsync, // 同步 Agent 共享状态
|
||||
})
|
||||
```
|
||||
|
||||
## 3. 智能体生命周期管理
|
||||
|
||||
### 3.1 生命周期阶段
|
||||
|
||||
1. **初始化阶段**
|
||||
- 创建 Agent ID
|
||||
- 设置上下文
|
||||
- 初始化 MCP 服务器
|
||||
- 注册 Hooks
|
||||
|
||||
2. **执行阶段**
|
||||
- 运行查询循环
|
||||
- 处理工具调用
|
||||
- 管理会话
|
||||
|
||||
3. **清理阶段**
|
||||
- 清理 MCP 服务器
|
||||
- 清除会话 Hooks
|
||||
- 释放内存
|
||||
- 杀死后台任务
|
||||
|
||||
### 3.2 生命周期钩子
|
||||
|
||||
```typescript
|
||||
// SubagentStart 钩子
|
||||
for await (const hookResult of executeSubagentStartHooks(
|
||||
agentId,
|
||||
agentDefinition.agentType,
|
||||
agentAbortController.signal,
|
||||
)) {
|
||||
// 收集额外上下文
|
||||
}
|
||||
|
||||
// SubagentStop 钩子
|
||||
if (agentDefinition.hooks) {
|
||||
clearSessionHooks(rootSetAppState, agentId)
|
||||
}
|
||||
```
|
||||
|
||||
## 4. 内置智能体 (built-in/)
|
||||
|
||||
### 4.1 generalPurposeAgent
|
||||
|
||||
**位置:** `/src/tools/AgentTool/built-in/generalPurposeAgent.ts`
|
||||
|
||||
通用目的 Agent,适用于复杂研究和多步骤任务执行:
|
||||
|
||||
```typescript
|
||||
export const GENERAL_PURPOSE_AGENT: BuiltInAgentDefinition = {
|
||||
agentType: 'general-purpose',
|
||||
whenToUse: 'General-purpose agent for researching complex questions...',
|
||||
tools: ['*'], // 允许所有工具
|
||||
source: 'built-in',
|
||||
getSystemPrompt: getGeneralPurposeSystemPrompt,
|
||||
}
|
||||
```
|
||||
|
||||
### 4.2 planAgent
|
||||
|
||||
**位置:** `/src/tools/AgentTool/built-in/planAgent.ts`
|
||||
|
||||
软件架构师 Agent,用于设计实现计划:
|
||||
|
||||
**关键特性:**
|
||||
- **只读模式**:禁止任何文件修改操作
|
||||
- 严格禁用工具:`Edit`, `Write`, `NotebookEdit`, `Agent`
|
||||
- 允许工具:`Read`, `Glob`, `Grep`, `Bash`(仅限只读操作)
|
||||
|
||||
**系统提示片段:**
|
||||
```
|
||||
=== CRITICAL: READ-ONLY MODE - NO FILE MODIFICATIONS ===
|
||||
This is a READ-ONLY planning task. You are STRICTLY PROHIBITED from:
|
||||
- Creating new files (no Write, touch, or file creation of any kind)
|
||||
- Modifying existing files (no Edit operations)
|
||||
- Deleting files (no rm or deletion)
|
||||
...
|
||||
```
|
||||
|
||||
### 4.3 verificationAgent
|
||||
|
||||
验证 Agent,用于验证任务完成情况:
|
||||
|
||||
```typescript
|
||||
// 在 TaskUpdateTool 中引用
|
||||
const VERIFICATION_AGENT_TYPE = 'verification'
|
||||
|
||||
// 当满足条件时提示验证
|
||||
if (allTasks.length >= 3 && !allTasks.some(t => /verif/i.test(t.subject))) {
|
||||
verificationNudgeNeeded = true
|
||||
}
|
||||
```
|
||||
|
||||
### 4.4 exploreAgent
|
||||
|
||||
探索 Agent,用于代码库探索和搜索:
|
||||
|
||||
**特性:**
|
||||
- 只读操作
|
||||
- 使用 `find`/`grep` 或 `Glob`/`Grep` 进行搜索
|
||||
- 不加载 CLAUDE.md(节省 token)
|
||||
|
||||
### 4.5 statuslineSetup
|
||||
|
||||
状态栏设置 Agent,用于配置状态行显示。
|
||||
|
||||
### 4.6 claudeCodeGuideAgent
|
||||
|
||||
Claude Code 指南 Agent,帮助用户学习使用 Claude Code。
|
||||
|
||||
## 5. Agent 内存管理
|
||||
|
||||
### 5.1 Agent 内存结构
|
||||
|
||||
**位置:** `/src/tools/AgentTool/agentMemory.ts`
|
||||
|
||||
```typescript
|
||||
export type AgentMemory = {
|
||||
sessionId: string
|
||||
agentId: string
|
||||
messages: Message[]
|
||||
toolUseResults: Map<string, ToolResult>
|
||||
fileState: FileStateCache
|
||||
}
|
||||
```
|
||||
|
||||
### 5.2 文件状态缓存
|
||||
|
||||
```typescript
|
||||
// 克隆文件状态缓存
|
||||
const agentReadFileState = forkContextMessages !== undefined
|
||||
? cloneFileStateCache(toolUseContext.readFileState)
|
||||
: createFileStateCacheWithSizeLimit(READ_FILE_STATE_CACHE_SIZE)
|
||||
|
||||
// 清理时释放
|
||||
agentToolUseContext.readFileState.clear()
|
||||
```
|
||||
|
||||
### 5.3 转录记录
|
||||
|
||||
```typescript
|
||||
// 记录初始消息
|
||||
await recordSidechainTranscript(initialMessages, agentId)
|
||||
|
||||
// 记录新消息
|
||||
await recordSidechainTranscript([message], agentId, lastRecordedUuid)
|
||||
```
|
||||
|
||||
## 6. 团队协调器 (coordinator/)
|
||||
|
||||
### 6.1 协调器模式
|
||||
|
||||
**位置:** `/src/coordinator/coordinatorMode.ts`
|
||||
|
||||
协调器模式允许多个 Agent 在团队中协作。
|
||||
|
||||
### 6.2 协调器 Agent
|
||||
|
||||
```typescript
|
||||
// 获取协调器 Agent
|
||||
function getCoordinatorAgents(): AgentDefinition[]
|
||||
```
|
||||
|
||||
## 7. 团队管理工具
|
||||
|
||||
### 7.1 TeamCreateTool
|
||||
|
||||
**位置:** `/src/tools/TeamCreateTool/TeamCreateTool.ts`
|
||||
|
||||
创建团队,管理团队配置。
|
||||
|
||||
### 7.2 TeamDeleteTool
|
||||
|
||||
**位置:** `/src/tools/TeamDeleteTool/TeamDeleteTool.ts`
|
||||
|
||||
删除团队,清理团队资源。
|
||||
|
||||
### 7.3 团队文件结构
|
||||
|
||||
**位置:** `/src/utils/swarm/teamHelpers.ts`
|
||||
|
||||
```typescript
|
||||
export type TeamFile = {
|
||||
name: string
|
||||
description?: string
|
||||
createdAt: number
|
||||
leadAgentId: string
|
||||
leadSessionId?: string
|
||||
hiddenPaneIds?: string[]
|
||||
teamAllowedPaths?: TeamAllowedPath[]
|
||||
members: Array<{
|
||||
agentId: string
|
||||
name: string
|
||||
agentType?: string
|
||||
model?: string
|
||||
prompt?: string
|
||||
color?: string
|
||||
planModeRequired?: boolean
|
||||
joinedAt: number
|
||||
tmuxPaneId: string
|
||||
cwd: string
|
||||
worktreePath?: string
|
||||
sessionId?: string
|
||||
subscriptions: string[]
|
||||
backendType?: BackendType
|
||||
isActive?: boolean
|
||||
mode?: PermissionMode
|
||||
}>
|
||||
}
|
||||
```
|
||||
|
||||
## 8. Agent 与技能的集成
|
||||
|
||||
### 8.1 技能预加载
|
||||
|
||||
Agent 可以预加载技能:
|
||||
|
||||
```typescript
|
||||
const skillsToPreload = agentDefinition.skills ?? []
|
||||
if (skillsToPreload.length > 0) {
|
||||
const allSkills = await getSkillToolCommands(getProjectRoot())
|
||||
// 加载并注入技能内容
|
||||
}
|
||||
```
|
||||
|
||||
### 8.2 技能名称解析
|
||||
|
||||
```typescript
|
||||
function resolveSkillName(
|
||||
skillName: string,
|
||||
allSkills: Command[],
|
||||
agentDefinition: AgentDefinition
|
||||
): string | null {
|
||||
// 1. 精确匹配
|
||||
if (hasCommand(skillName, allSkills)) return skillName
|
||||
|
||||
// 2. 前缀匹配 (e.g., "my-skill" → "my-plugin:my-skill")
|
||||
const qualifiedName = `${pluginPrefix}:${skillName}`
|
||||
if (hasCommand(qualifiedName, allSkills)) return qualifiedName
|
||||
|
||||
// 3. 后缀匹配 (e.g., ":my-skill")
|
||||
// ...
|
||||
}
|
||||
```
|
||||
|
||||
## 9. MCP 服务器集成
|
||||
|
||||
### 9.1 Agent 专用 MCP 服务器
|
||||
|
||||
Agent 可以定义自己的 MCP 服务器:
|
||||
|
||||
```typescript
|
||||
async function initializeAgentMcpServers(
|
||||
agentDefinition: AgentDefinition,
|
||||
parentClients: MCPServerConnection[]
|
||||
): Promise<{
|
||||
clients: MCPServerConnection[]
|
||||
tools: Tools
|
||||
cleanup: () => Promise<void>
|
||||
}>
|
||||
```
|
||||
|
||||
### 9.2 服务器合并
|
||||
|
||||
```typescript
|
||||
// 合并父级和 Agent 专用的 MCP 客户端
|
||||
const allTools = uniqBy([...resolvedTools, ...agentMcpTools], 'name')
|
||||
```
|
||||
|
||||
## 10. 权限与隔离
|
||||
|
||||
### 10.1 权限模式
|
||||
|
||||
```typescript
|
||||
const agentPermissionMode = agentDefinition.permissionMode
|
||||
|
||||
if (agentPermissionMode &&
|
||||
state.toolPermissionContext.mode !== 'bypassPermissions' &&
|
||||
state.toolPermissionContext.mode !== 'acceptEdits') {
|
||||
toolPermissionContext = {
|
||||
...toolPermissionContext,
|
||||
mode: agentPermissionMode
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### 10.2 工具过滤
|
||||
|
||||
```typescript
|
||||
const resolvedTools = resolveAgentTools(
|
||||
agentDefinition,
|
||||
availableTools,
|
||||
isAsync
|
||||
).resolvedTools
|
||||
```
|
||||
|
||||
## 11. 性能优化
|
||||
|
||||
### 11.1 CLAUDE.md 省略
|
||||
|
||||
```typescript
|
||||
const shouldOmitClaudeMd = agentDefinition.omitClaudeMd &&
|
||||
!override?.userContext &&
|
||||
getFeatureValue_CACHED_MAY_BE_STALE('tengu_slim_subagent_claudemd', true)
|
||||
```
|
||||
|
||||
### 11.2 Git 状态省略
|
||||
|
||||
```typescript
|
||||
const resolvedSystemContext =
|
||||
agentDefinition.agentType === 'Explore' ||
|
||||
agentDefinition.agentType === 'Plan'
|
||||
? systemContextNoGit // 省略 gitStatus
|
||||
: baseSystemContext
|
||||
```
|
||||
|
||||
### 11.3 推理配置
|
||||
|
||||
```typescript
|
||||
thinkingConfig: useExactTools
|
||||
? toolUseContext.options.thinkingConfig // 继承父级
|
||||
: { type: 'disabled' as const } // 禁用
|
||||
```
|
||||
|
||||
## 12. Telemetry 与追踪
|
||||
|
||||
### 12.1 Perfetto 追踪
|
||||
|
||||
```typescript
|
||||
if (isPerfettoTracingEnabled()) {
|
||||
registerPerfettoAgent(agentId, agentDefinition.agentType, parentId)
|
||||
}
|
||||
|
||||
// 清理时注销
|
||||
unregisterPerfettoAgent(agentId)
|
||||
```
|
||||
|
||||
### 12.2 转录存储
|
||||
|
||||
```typescript
|
||||
// 边链转录
|
||||
await recordSidechainTranscript(initialMessages, agentId)
|
||||
|
||||
// Agent 元数据
|
||||
await writeAgentMetadata(agentId, {
|
||||
agentType: agentDefinition.agentType,
|
||||
worktreePath,
|
||||
description
|
||||
})
|
||||
```
|
||||
691
claude-code-中文Wiki/11-Swarm系统.md
Normal file
691
claude-code-中文Wiki/11-Swarm系统.md
Normal file
@@ -0,0 +1,691 @@
|
||||
# Swarm 系统
|
||||
|
||||
Claude Code 的 Swarm 系统是一个多智能体协作框架,支持团队模式、进程内队友和多种终端后端实现。
|
||||
|
||||
## 1. Swarm 系统概述
|
||||
|
||||
### 1.1 核心目录结构
|
||||
|
||||
**位置:** `/src/utils/swarm/`
|
||||
|
||||
```
|
||||
swarm/
|
||||
├── backends/
|
||||
│ ├── types.ts # 后端类型定义
|
||||
│ ├── registry.ts # 后端注册表
|
||||
│ ├── detection.ts # 环境检测
|
||||
│ ├── TmuxBackend.ts # Tmux 后端
|
||||
│ ├── ITermBackend.ts # iTerm2 后端
|
||||
│ ├── InProcessBackend.ts # 进程内后端
|
||||
│ ├── PaneBackendExecutor.ts # 面板执行器
|
||||
│ └── teammateModeSnapshot.ts # 团队模式快照
|
||||
├── teamHelpers.ts # 团队辅助函数
|
||||
├── teammateInit.ts # 队友初始化
|
||||
├── teammateLayoutManager.ts # 布局管理
|
||||
├── teammateModel.ts # 队友模型
|
||||
├── teammatePromptAddendum.ts # 提示补充
|
||||
├── permissionSync.ts # 权限同步
|
||||
├── reconnection.ts # 重连机制
|
||||
├── spawnUtils.ts # 生成工具
|
||||
├── spawnInProcess.ts # 进程内生成
|
||||
├── inProcessRunner.ts # 进程内运行器
|
||||
├── constants.ts # 常量定义
|
||||
└── leaderPermissionBridge.ts # 权限桥接
|
||||
```
|
||||
|
||||
## 2. 团队模式快照 (teammateModeSnapshot.ts)
|
||||
|
||||
### 2.1 快照机制
|
||||
|
||||
```typescript
|
||||
// 位置:/src/utils/swarm/backends/teammateModeSnapshot.ts
|
||||
|
||||
export type TeammateMode = 'auto' | 'tmux' | 'in-process'
|
||||
|
||||
// CLI 覆盖
|
||||
let cliTeammateModeOverride: TeammateMode | null = null
|
||||
|
||||
// 捕获启动时的团队模式
|
||||
export function captureTeammateModeSnapshot(): void {
|
||||
if (cliTeammateModeOverride) {
|
||||
initialTeammateMode = cliTeammateModeOverride
|
||||
} else {
|
||||
const config = getGlobalConfig()
|
||||
initialTeammateMode = config.teammateMode ?? 'auto'
|
||||
}
|
||||
}
|
||||
|
||||
// 获取快照模式
|
||||
export function getTeammateModeFromSnapshot(): TeammateMode
|
||||
```
|
||||
|
||||
### 2.2 模式类型
|
||||
|
||||
| 模式 | 描述 |
|
||||
|------|------|
|
||||
| `auto` | 自动检测可用后端 |
|
||||
| `tmux` | 强制使用 Tmux 后端 |
|
||||
| `in-process` | 使用进程内后端 |
|
||||
|
||||
## 3. 团队辅助函数 (teamHelpers.ts)
|
||||
|
||||
### 3.1 团队文件操作
|
||||
|
||||
```typescript
|
||||
// 获取团队目录
|
||||
export function getTeamDir(teamName: string): string
|
||||
|
||||
// 获取团队配置文件路径
|
||||
export function getTeamFilePath(teamName: string): string
|
||||
|
||||
// 读取团队文件(同步)
|
||||
export function readTeamFile(teamName: string): TeamFile | null
|
||||
|
||||
// 读取团队文件(异步)
|
||||
export async function readTeamFileAsync(teamName: string): Promise<TeamFile | null>
|
||||
|
||||
// 写入团队文件(同步)
|
||||
function writeTeamFile(teamName: string, teamFile: TeamFile): void
|
||||
|
||||
// 写入团队文件(异步)
|
||||
export async function writeTeamFileAsync(teamName: string, teamFile: TeamFile): Promise<void>
|
||||
```
|
||||
|
||||
### 3.2 团队成员管理
|
||||
|
||||
```typescript
|
||||
// 从团队文件移除队友
|
||||
export function removeTeammateFromTeamFile(
|
||||
teamName: string,
|
||||
identifier: { agentId?: string; name?: string }
|
||||
): boolean
|
||||
|
||||
// 移除成员
|
||||
export function removeMemberFromTeam(
|
||||
teamName: string,
|
||||
tmuxPaneId: string
|
||||
): boolean
|
||||
|
||||
// 按 Agent ID 移除成员
|
||||
export function removeMemberByAgentId(
|
||||
teamName: string,
|
||||
agentId: string
|
||||
): boolean
|
||||
|
||||
// 设置成员权限模式
|
||||
export function setMemberMode(
|
||||
teamName: string,
|
||||
memberName: string,
|
||||
mode: PermissionMode
|
||||
): boolean
|
||||
|
||||
// 同步队友模式
|
||||
export function syncTeammateMode(mode: PermissionMode, teamNameOverride?: string): void
|
||||
|
||||
// 设置成员活跃状态
|
||||
export async function setMemberActive(
|
||||
teamName: string,
|
||||
memberName: string,
|
||||
isActive: boolean
|
||||
): Promise<void>
|
||||
```
|
||||
|
||||
### 3.3 团队清理
|
||||
|
||||
```typescript
|
||||
// 清理会话团队
|
||||
export async function cleanupSessionTeams(): Promise<void>
|
||||
|
||||
// 清理团队目录
|
||||
export async function cleanupTeamDirectories(teamName: string): Promise<void>
|
||||
|
||||
// 注册团队会话清理
|
||||
export function registerTeamForSessionCleanup(teamName: string): void
|
||||
|
||||
// 注销团队会话清理
|
||||
export function unregisterTeamForSessionCleanup(teamName: string): void
|
||||
```
|
||||
|
||||
## 4. 队友初始化 (teammateInit.ts)
|
||||
|
||||
### 4.1 初始化流程
|
||||
|
||||
```typescript
|
||||
// 位置:/src/utils/swarm/teammateInit.ts
|
||||
|
||||
export function initializeTeammateHooks(
|
||||
setAppState: (updater: (prev: AppState) => AppState) => void,
|
||||
sessionId: string,
|
||||
teamInfo: { teamName: string; agentId: string; agentName: string }
|
||||
): void
|
||||
```
|
||||
|
||||
### 4.2 团队权限应用
|
||||
|
||||
```typescript
|
||||
// 应用团队范围的允许路径
|
||||
if (teamFile.teamAllowedPaths && teamFile.teamAllowedPaths.length > 0) {
|
||||
for (const allowedPath of teamFile.teamAllowedPaths) {
|
||||
setAppState(prev => ({
|
||||
...prev,
|
||||
toolPermissionContext: applyPermissionUpdate(
|
||||
prev.toolPermissionContext,
|
||||
{
|
||||
type: 'addRules',
|
||||
rules: [{ toolName: allowedPath.toolName, ruleContent }],
|
||||
behavior: 'allow',
|
||||
destination: 'session'
|
||||
}
|
||||
)
|
||||
}))
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### 4.3 停止钩子注册
|
||||
|
||||
```typescript
|
||||
// 注册停止钩子以通知团队领导
|
||||
addFunctionHook(
|
||||
setAppState,
|
||||
sessionId,
|
||||
'Stop',
|
||||
'',
|
||||
async (messages, _signal) => {
|
||||
// 标记为空闲
|
||||
void setMemberActive(teamName, agentName, false)
|
||||
|
||||
// 发送空闲通知
|
||||
const notification = createIdleNotification(agentName, {...})
|
||||
await writeToMailbox(leadAgentName, {...})
|
||||
|
||||
return true
|
||||
}
|
||||
)
|
||||
```
|
||||
|
||||
## 5. 布局管理 (teammateLayoutManager.ts)
|
||||
|
||||
### 5.1 队友颜色分配
|
||||
|
||||
```typescript
|
||||
// 分配队友颜色
|
||||
export function assignTeammateColor(teammateId: string): AgentColorName
|
||||
|
||||
// 获取队友颜色
|
||||
export function getTeammateColor(teammateId: string): AgentColorName | undefined
|
||||
|
||||
// 清除所有颜色分配
|
||||
export function clearTeammateColors(): void
|
||||
```
|
||||
|
||||
### 5.2 后端选择
|
||||
|
||||
```typescript
|
||||
async function getBackend(): Promise<PaneBackend> {
|
||||
return (await detectAndGetBackend()).backend
|
||||
}
|
||||
```
|
||||
|
||||
### 5.3 面板操作
|
||||
|
||||
```typescript
|
||||
// 在 Swarm 视图中创建队友面板
|
||||
export async function createTeammatePaneInSwarmView(
|
||||
teammateName: string,
|
||||
teammateColor: AgentColorName
|
||||
): Promise<{ paneId: string; isFirstTeammate: boolean }>
|
||||
|
||||
// 启用面板边框状态
|
||||
export async function enablePaneBorderStatus(
|
||||
windowTarget?: string,
|
||||
useSwarmSocket?: boolean
|
||||
): Promise<void>
|
||||
|
||||
// 发送命令到面板
|
||||
export async function sendCommandToPane(
|
||||
paneId: string,
|
||||
command: string,
|
||||
useSwarmSocket?: boolean
|
||||
): Promise<void>
|
||||
```
|
||||
|
||||
## 6. 后端系统 (backends/)
|
||||
|
||||
### 6.1 后端类型
|
||||
|
||||
**位置:** `/src/utils/swarm/backends/types.ts`
|
||||
|
||||
```typescript
|
||||
export type BackendType = 'tmux' | 'iterm2' | 'in-process'
|
||||
|
||||
export type PaneBackendType = 'tmux' | 'iterm2'
|
||||
|
||||
export type PaneId = string
|
||||
|
||||
export type CreatePaneResult = {
|
||||
paneId: PaneId
|
||||
isFirstTeammate: boolean
|
||||
}
|
||||
```
|
||||
|
||||
### 6.2 PaneBackend 接口
|
||||
|
||||
```typescript
|
||||
export type PaneBackend = {
|
||||
readonly type: BackendType
|
||||
readonly displayName: string
|
||||
readonly supportsHideShow: boolean
|
||||
|
||||
isAvailable(): Promise<boolean>
|
||||
isRunningInside(): Promise<boolean>
|
||||
|
||||
createTeammatePaneInSwarmView(
|
||||
name: string,
|
||||
color: AgentColorName
|
||||
): Promise<CreatePaneResult>
|
||||
|
||||
sendCommandToPane(
|
||||
paneId: PaneId,
|
||||
command: string,
|
||||
useExternalSession?: boolean
|
||||
): Promise<void>
|
||||
|
||||
setPaneBorderColor(
|
||||
paneId: PaneId,
|
||||
color: AgentColorName,
|
||||
useExternalSession?: boolean
|
||||
): Promise<void>
|
||||
|
||||
setPaneTitle(
|
||||
paneId: PaneId,
|
||||
name: string,
|
||||
color: AgentColorName,
|
||||
useExternalSession?: boolean
|
||||
): Promise<void>
|
||||
|
||||
enablePaneBorderStatus(
|
||||
windowTarget?: string,
|
||||
useExternalSession?: boolean
|
||||
): Promise<void>
|
||||
|
||||
rebalancePanes(windowTarget: string, hasLeader: boolean): Promise<void>
|
||||
|
||||
killPane(paneId: PaneId, useExternalSession?: boolean): Promise<boolean>
|
||||
|
||||
hidePane(paneId: PaneId, useExternalSession?: boolean): Promise<boolean>
|
||||
|
||||
showPane(
|
||||
paneId: PaneId,
|
||||
targetWindowOrPane: string,
|
||||
useExternalSession?: boolean
|
||||
): Promise<boolean>
|
||||
}
|
||||
```
|
||||
|
||||
### 6.3 TmuxBackend
|
||||
|
||||
**位置:** `/src/utils/swarm/backends/TmuxBackend.ts`
|
||||
|
||||
使用 tmux 进行面板管理的后端实现。
|
||||
|
||||
**功能:**
|
||||
- 创建 tmux 窗口和面板
|
||||
- 发送命令到指定面板
|
||||
- 设置面板颜色和标题
|
||||
- 管理面板布局
|
||||
|
||||
### 6.4 ITermBackend
|
||||
|
||||
**位置:** `/src/utils/swarm/backends/ITermBackend.ts`
|
||||
|
||||
使用 iTerm2 原生分割面板的后端实现。
|
||||
|
||||
**功能:**
|
||||
- 通过 it2 CLI 与 iTerm2 通信
|
||||
- 创建垂直/水平分割
|
||||
- 设置 profile 和颜色
|
||||
|
||||
### 6.5 InProcessBackend
|
||||
|
||||
**位置:** `/src/utils/swarm/backends/InProcessBackend.ts`
|
||||
|
||||
在当前 Node.js 进程中运行队友的后端。
|
||||
|
||||
**特性:**
|
||||
- 共享 API 客户端和 MCP 连接
|
||||
- 通过文件邮箱通信
|
||||
- 使用 AbortController 终止
|
||||
- 始终可用(无外部依赖)
|
||||
|
||||
```typescript
|
||||
export class InProcessBackend implements TeammateExecutor {
|
||||
readonly type = 'in-process' as const
|
||||
|
||||
async spawn(config: TeammateSpawnConfig): Promise<TeammateSpawnResult>
|
||||
async sendMessage(agentId: string, message: TeammateMessage): Promise<void>
|
||||
async terminate(agentId: string, reason?: string): Promise<boolean>
|
||||
async kill(agentId: string): Promise<boolean>
|
||||
async isActive(agentId: string): Promise<boolean>
|
||||
}
|
||||
```
|
||||
|
||||
### 6.6 后端注册表
|
||||
|
||||
**位置:** `/src/utils/swarm/backends/registry.ts`
|
||||
|
||||
```typescript
|
||||
// 检测并获取合适的后端
|
||||
export async function detectAndGetBackend(): Promise<BackendDetectionResult>
|
||||
|
||||
// 注册所有后端
|
||||
export async function ensureBackendsRegistered(): Promise<void>
|
||||
|
||||
// 按类型获取后端
|
||||
export async function getBackendByType(type: BackendType): Promise<PaneBackend>
|
||||
```
|
||||
|
||||
## 7. 权限同步 (permissionSync.ts)
|
||||
|
||||
### 7.1 权限请求流程
|
||||
|
||||
```
|
||||
Worker Agent → 权限请求 → Leader Mailbox
|
||||
Leader Agent ← 轮询 ← 权限队列
|
||||
↓
|
||||
用户批准/拒绝
|
||||
↓
|
||||
Leader → 权限响应 → Worker Mailbox
|
||||
Worker ← 处理响应 ←
|
||||
```
|
||||
|
||||
### 7.2 权限请求结构
|
||||
|
||||
```typescript
|
||||
export type SwarmPermissionRequest = {
|
||||
id: string
|
||||
workerId: string
|
||||
workerName: string
|
||||
workerColor?: string
|
||||
teamName: string
|
||||
toolName: string
|
||||
toolUseId: string
|
||||
description: string
|
||||
input: Record<string, unknown>
|
||||
permissionSuggestions: unknown[]
|
||||
status: 'pending' | 'approved' | 'rejected'
|
||||
resolvedBy?: 'worker' | 'leader'
|
||||
resolvedAt?: number
|
||||
feedback?: string
|
||||
updatedInput?: Record<string, unknown>
|
||||
permissionUpdates?: PermissionUpdate[]
|
||||
createdAt: number
|
||||
}
|
||||
```
|
||||
|
||||
### 7.3 权限操作
|
||||
|
||||
```typescript
|
||||
// 创建权限请求
|
||||
export function createPermissionRequest(params: {...}): SwarmPermissionRequest
|
||||
|
||||
// 写入待处理权限请求
|
||||
export async function writePermissionRequest(
|
||||
request: SwarmPermissionRequest
|
||||
): Promise<SwarmPermissionRequest>
|
||||
|
||||
// 读取待处理权限
|
||||
export async function readPendingPermissions(
|
||||
teamName?: string
|
||||
): Promise<SwarmPermissionRequest[]>
|
||||
|
||||
// 解决权限请求
|
||||
export async function resolvePermission(
|
||||
requestId: string,
|
||||
resolution: PermissionResolution,
|
||||
teamName?: string
|
||||
): Promise<boolean>
|
||||
|
||||
// 通过邮箱发送权限请求
|
||||
export async function sendPermissionRequestViaMailbox(
|
||||
request: SwarmPermissionRequest
|
||||
): Promise<boolean>
|
||||
|
||||
// 通过邮箱发送权限响应
|
||||
export async function sendPermissionResponseViaMailbox(
|
||||
workerName: string,
|
||||
resolution: PermissionResolution,
|
||||
requestId: string,
|
||||
teamName?: string
|
||||
): Promise<boolean>
|
||||
```
|
||||
|
||||
### 7.4 沙箱权限
|
||||
|
||||
```typescript
|
||||
// 发送沙箱权限请求
|
||||
export async function sendSandboxPermissionRequestViaMailbox(
|
||||
host: string,
|
||||
requestId: string,
|
||||
teamName?: string
|
||||
): Promise<boolean>
|
||||
|
||||
// 发送沙箱权限响应
|
||||
export async function sendSandboxPermissionResponseViaMailbox(
|
||||
workerName: string,
|
||||
requestId: string,
|
||||
host: string,
|
||||
allow: boolean,
|
||||
teamName?: string
|
||||
): Promise<boolean>
|
||||
```
|
||||
|
||||
### 7.5 团队领导检查
|
||||
|
||||
```typescript
|
||||
// 检查是否为团队领导
|
||||
export function isTeamLeader(teamName?: string): boolean
|
||||
|
||||
// 检查是否为 Swarm Worker
|
||||
export function isSwarmWorker(): boolean
|
||||
```
|
||||
|
||||
## 8. 重连机制 (reconnection.ts)
|
||||
|
||||
### 8.1 初始团队上下文计算
|
||||
|
||||
```typescript
|
||||
export function computeInitialTeamContext():
|
||||
| AppState['teamContext']
|
||||
| undefined {
|
||||
// 从 CLI 参数获取动态团队上下文
|
||||
const context = getDynamicTeamContext()
|
||||
|
||||
if (!context?.teamName || !context?.agentName) {
|
||||
return undefined
|
||||
}
|
||||
|
||||
// 读取团队文件获取领导 Agent ID
|
||||
const teamFile = readTeamFile(teamName)
|
||||
|
||||
return {
|
||||
teamName,
|
||||
teamFilePath,
|
||||
leadAgentId: teamFile.leadAgentId,
|
||||
selfAgentId: agentId,
|
||||
selfAgentName: agentName,
|
||||
isLeader,
|
||||
teammates: {}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### 8.2 从会话恢复团队上下文
|
||||
|
||||
```typescript
|
||||
export function initializeTeammateContextFromSession(
|
||||
setAppState: (updater: (prev: AppState) => AppState) => void,
|
||||
teamName: string,
|
||||
agentName: string
|
||||
): void {
|
||||
// 从团队文件读取成员信息
|
||||
const teamFile = readTeamFile(teamName)
|
||||
const member = teamFile.members.find(m => m.name === agentName)
|
||||
const agentId = member?.agentId
|
||||
|
||||
// 设置 AppState 中的团队上下文
|
||||
setAppState(prev => ({
|
||||
...prev,
|
||||
teamContext: {
|
||||
teamName,
|
||||
teamFilePath,
|
||||
leadAgentId: teamFile.leadAgentId,
|
||||
selfAgentId: agentId,
|
||||
selfAgentName: agentName,
|
||||
isLeader: false,
|
||||
teammates: {}
|
||||
}
|
||||
}))
|
||||
}
|
||||
```
|
||||
|
||||
## 9. 队友生成 (spawnUtils.ts, spawnInProcess.ts)
|
||||
|
||||
### 9.1 进程内队友生成
|
||||
|
||||
```typescript
|
||||
// 位置:/src/utils/swarm/spawnInProcess.ts
|
||||
|
||||
export async function spawnInProcessTeammate(
|
||||
identity: TeammateIdentity,
|
||||
context: ToolUseContext
|
||||
): Promise<{
|
||||
success: boolean
|
||||
agentId: string
|
||||
taskId?: string
|
||||
teammateContext?: TeammateContext
|
||||
abortController?: AbortController
|
||||
error?: string
|
||||
}>
|
||||
|
||||
export function killInProcessTeammate(
|
||||
taskId: string,
|
||||
setAppState: (updater: (prev: AppState) => AppState) => void
|
||||
): boolean
|
||||
```
|
||||
|
||||
### 9.2 进程内运行器
|
||||
|
||||
```typescript
|
||||
// 位置:/src/utils/swarm/inProcessRunner.ts
|
||||
|
||||
export async function startInProcessTeammate(params: {
|
||||
identity: TeammateIdentity
|
||||
taskId: string
|
||||
prompt: string
|
||||
teammateContext: TeammateContext
|
||||
toolUseContext: ToolUseContext
|
||||
abortController: AbortController
|
||||
model?: string
|
||||
systemPrompt?: string
|
||||
systemPromptMode?: 'default' | 'replace' | 'append'
|
||||
allowedTools?: string[]
|
||||
allowPermissionPrompts?: boolean
|
||||
}): Promise<void>
|
||||
```
|
||||
|
||||
## 10. TeammateExecutor 接口
|
||||
|
||||
### 10.1 接口定义
|
||||
|
||||
```typescript
|
||||
export type TeammateExecutor = {
|
||||
readonly type: BackendType
|
||||
|
||||
isAvailable(): Promise<boolean>
|
||||
spawn(config: TeammateSpawnConfig): Promise<TeammateSpawnResult>
|
||||
sendMessage(agentId: string, message: TeammateMessage): Promise<void>
|
||||
terminate(agentId: string, reason?: string): Promise<boolean>
|
||||
kill(agentId: string): Promise<boolean>
|
||||
isActive(agentId: string): Promise<boolean>
|
||||
}
|
||||
```
|
||||
|
||||
### 10.2 TeammateSpawnConfig
|
||||
|
||||
```typescript
|
||||
export type TeammateSpawnConfig = TeammateIdentity & {
|
||||
prompt: string
|
||||
cwd: string
|
||||
model?: string
|
||||
systemPrompt?: string
|
||||
systemPromptMode?: 'default' | 'replace' | 'append'
|
||||
worktreePath?: string
|
||||
parentSessionId: string
|
||||
permissions?: string[]
|
||||
allowPermissionPrompts?: boolean
|
||||
}
|
||||
```
|
||||
|
||||
### 10.3 TeammateSpawnResult
|
||||
|
||||
```typescript
|
||||
export type TeammateSpawnResult = {
|
||||
success: boolean
|
||||
agentId: string // 格式: agentName@teamName
|
||||
error?: string
|
||||
abortController?: AbortController // 进程内队友使用
|
||||
taskId?: string // AppState.tasks 中的任务 ID
|
||||
paneId?: PaneId // 基于面板的后端使用
|
||||
}
|
||||
```
|
||||
|
||||
## 11. 消息类型
|
||||
|
||||
### 11.1 TeammateMessage
|
||||
|
||||
```typescript
|
||||
export type TeammateMessage = {
|
||||
text: string
|
||||
from: string
|
||||
color?: string
|
||||
timestamp?: string
|
||||
summary?: string // 5-10 字预览
|
||||
}
|
||||
```
|
||||
|
||||
## 12. 类型守卫
|
||||
|
||||
### 12.1 面板后端检查
|
||||
|
||||
```typescript
|
||||
export function isPaneBackend(type: BackendType): type is 'tmux' | 'iterm2' {
|
||||
return type === 'tmux' || type === 'iterm2'
|
||||
}
|
||||
```
|
||||
|
||||
## 13. 环境检测
|
||||
|
||||
### 13.1 tmux 检测
|
||||
|
||||
```typescript
|
||||
// 检测是否在 tmux 会话内运行
|
||||
export async function isInsideTmux(): Promise<boolean>
|
||||
```
|
||||
|
||||
### 13.2 iTerm2 检测
|
||||
|
||||
```typescript
|
||||
// 检测 iTerm2 是否可用
|
||||
export async function isITerm2Available(): Promise<boolean>
|
||||
```
|
||||
|
||||
## 14. 团队常量
|
||||
|
||||
**位置:** `/src/utils/swarm/constants.ts`
|
||||
|
||||
```typescript
|
||||
export const TEAM_LEAD_NAME = 'team-lead'
|
||||
export const DEFAULT_TEAM_PANE_WIDTH = '30%'
|
||||
export const DEFAULT_TEAM_PANE_HEIGHT = '50%'
|
||||
```
|
||||
317
claude-code-中文Wiki/12-UI组件系统.md
Normal file
317
claude-code-中文Wiki/12-UI组件系统.md
Normal file
@@ -0,0 +1,317 @@
|
||||
# UI 组件系统
|
||||
|
||||
Claude Code 的 UI 组件系统是一个复杂的多层架构,结合了 React 组件、Ink 渲染器和终端 UI 技术。本文档详细介绍各层组件的设计和实现。
|
||||
|
||||
## 目录结构
|
||||
|
||||
```
|
||||
src/
|
||||
├── components/ # React 业务组件 (~140个)
|
||||
├── ink/ # Ink 渲染器封装
|
||||
│ ├── ink.tsx # 主渲染器 (1722行)
|
||||
│ ├── components/ # Ink 基础 UI 组件
|
||||
│ ├── events/ # 事件系统
|
||||
│ ├── hooks/ # React Hooks
|
||||
│ ├── layout/ # Yoga 布局引擎封装
|
||||
│ ├── termio/ # 终端 IO 处理
|
||||
│ └── screen.ts # 屏幕缓冲区管理
|
||||
├── screens/ # 全屏 UI 屏幕
|
||||
│ ├── Doctor.tsx # 诊断屏幕
|
||||
│ ├── REPL.tsx # REPL 屏幕
|
||||
│ └── ResumeConversation.tsx # 恢复对话屏幕
|
||||
└── outputStyles/ # 输出样式管理
|
||||
```
|
||||
|
||||
## 1. Ink 渲染器 (ink/)
|
||||
|
||||
Ink 是一个用于构建终端 UI 的 React 渲染器。Claude Code 对其进行了深度定制。
|
||||
|
||||
### 1.1 主渲染器 (ink.tsx)
|
||||
|
||||
**文件路径**: `src/ink/ink.tsx` (1722行)
|
||||
|
||||
**核心类**: `Ink`
|
||||
|
||||
**主要职责**:
|
||||
- 管理 React Fiber 树和渲染生命周期
|
||||
- 处理终端输入/输出
|
||||
- 管理帧缓冲区和屏幕更新
|
||||
- 处理鼠标跟踪和焦点管理
|
||||
|
||||
**关键属性**:
|
||||
```typescript
|
||||
class Ink {
|
||||
private readonly log: LogUpdate // 日志更新器
|
||||
private readonly terminal: Terminal // 终端连接
|
||||
private scheduleRender: () => void // 渲染调度
|
||||
private container: FiberRoot // React 容器
|
||||
private rootNode: dom.DOMElement // 根 DOM 节点
|
||||
readonly focusManager: FocusManager // 焦点管理器
|
||||
private renderer: Renderer // 渲染器
|
||||
private stylePool: StylePool // 样式池
|
||||
private charPool: CharPool // 字符池
|
||||
private hyperlinkPool: HyperlinkPool // 超链接池
|
||||
readonly selection: SelectionState // 文本选择状态
|
||||
private searchHighlightQuery: string // 搜索高亮查询
|
||||
}
|
||||
```
|
||||
|
||||
**渲染流程**:
|
||||
1. 接收 React 组件树
|
||||
2. 通过 React Reconciler 计算布局 (使用 Yoga 引擎)
|
||||
3. 将布局结果渲染到屏幕缓冲区
|
||||
4. 通过终端 IO 输出到终端
|
||||
|
||||
### 1.2 Ink 组件 (ink/components/)
|
||||
|
||||
#### Box 组件
|
||||
**文件**: `ink/components/Box.tsx`
|
||||
|
||||
Box 是 Ink 的核心布局组件,类似于 Web 的 `div` 和 Flexbox 的结合。
|
||||
|
||||
**主要属性**:
|
||||
```typescript
|
||||
type Props = {
|
||||
flexDirection?: 'row' | 'column' // 布局方向
|
||||
flexGrow?: number // 增长系数
|
||||
flexShrink?: number // 收缩系数
|
||||
flexWrap?: 'nowrap' | 'wrap' // 换行策略
|
||||
gap?: number // 间距
|
||||
overflowX?: 'visible' | 'hidden' | 'scroll' // 水平溢出
|
||||
overflowY?: 'visible' | 'hidden' | 'scroll' // 垂直溢出
|
||||
// 边距
|
||||
margin?: number
|
||||
marginX?: number
|
||||
marginY?: number
|
||||
padding?: number
|
||||
// ... 边框、背景等样式
|
||||
}
|
||||
```
|
||||
|
||||
**使用示例**:
|
||||
```tsx
|
||||
<Box flexDirection="column" gap={1} padding={2}>
|
||||
<Text>Hello</Text>
|
||||
<Box flexGrow={1}>Content</Box>
|
||||
</Box>
|
||||
```
|
||||
|
||||
#### Button 组件
|
||||
**文件**: `ink/components/Button.tsx`
|
||||
|
||||
Button 提供交互式按钮组件,支持焦点、悬停和激活状态。
|
||||
|
||||
**状态类型**:
|
||||
```typescript
|
||||
type ButtonState = {
|
||||
focused: boolean // 是否获得焦点
|
||||
hovered: boolean // 是否悬停
|
||||
active: boolean // 是否激活
|
||||
}
|
||||
```
|
||||
|
||||
**主要属性**:
|
||||
```typescript
|
||||
type Props = {
|
||||
onAction: () => void // 点击/回车/空格触发
|
||||
tabIndex?: number // Tab 顺序
|
||||
autoFocus?: boolean // 自动聚焦
|
||||
children: ((state: ButtonState) => React.ReactNode) | React.ReactNode
|
||||
}
|
||||
```
|
||||
|
||||
#### ScrollBox 组件
|
||||
**文件**: `ink/components/ScrollBox.tsx`
|
||||
|
||||
ScrollBox 是支持滚动的容器组件,提供虚拟滚动功能。
|
||||
|
||||
**句柄接口**:
|
||||
```typescript
|
||||
interface ScrollBoxHandle {
|
||||
scrollTo(y: number): void // 滚动到指定位置
|
||||
scrollBy(dy: number): void // 相对滚动
|
||||
scrollToElement(el: DOMElement, offset?: number): void // 滚动到元素
|
||||
scrollToBottom(): void // 滚动到底部
|
||||
getScrollTop(): number // 获取滚动位置
|
||||
getScrollHeight(): number // 获取内容高度
|
||||
getViewportHeight(): number // 获取视口高度
|
||||
isSticky(): boolean // 是否吸附底部
|
||||
subscribe(listener: () => void): () => void // 订阅滚动变化
|
||||
setClampBounds(min: number, max: number): void // 设置边界
|
||||
}
|
||||
```
|
||||
|
||||
**特性**:
|
||||
- Viewport Culling: 只渲染可见区域内的子元素
|
||||
- Sticky Scroll: 新内容自动滚动到底部
|
||||
- 节流渲染: 滚动事件节流,避免过度渲染
|
||||
|
||||
#### TerminalFocusContext
|
||||
**文件**: `ink/components/TerminalFocusContext.tsx`
|
||||
|
||||
提供终端焦点状态的 React Context。
|
||||
|
||||
#### Other Components
|
||||
| 组件 | 文件 | 用途 |
|
||||
|------|------|------|
|
||||
| Text | Text.tsx | 文本显示,支持颜色、样式 |
|
||||
| Link | Link.tsx | 超链接渲染 |
|
||||
| Newline | Newline.tsx | 换行符 |
|
||||
| Spacer | Spacer.tsx | 空白间距 |
|
||||
| RawAnsi | RawAnsi.tsx | 原始 ANSI 转义序列 |
|
||||
| NoSelect | NoSelect.tsx | 禁用选择 |
|
||||
| ErrorOverview | ErrorOverview.tsx | 错误概览 |
|
||||
| AlternateScreen | AlternateScreen.tsx | 替代屏幕 |
|
||||
| App | App.tsx | 根应用组件 |
|
||||
|
||||
### 1.3 ANSI 处理 (Ansi.tsx)
|
||||
|
||||
**文件**: `src/ink/Ansi.tsx`
|
||||
|
||||
Ansi 组件解析并渲染包含 ANSI 转义序列的字符串。
|
||||
|
||||
**功能**:
|
||||
- 解析 SGR (Select Graphic Rendition) 参数
|
||||
- 支持颜色、背景色、粗体、斜体、下划线等样式
|
||||
- 支持超链接
|
||||
- Memoized 防止不必要的重渲染
|
||||
|
||||
**属性**:
|
||||
```typescript
|
||||
type Props = {
|
||||
children: string // ANSI 字符串
|
||||
dimColor?: boolean // 是否淡化颜色
|
||||
}
|
||||
```
|
||||
|
||||
### 1.4 事件系统 (ink/events/)
|
||||
|
||||
```
|
||||
events/
|
||||
├── click-event.ts # 点击事件
|
||||
├── focus-event.ts # 焦点事件
|
||||
├── keyboard-event.ts # 键盘事件
|
||||
├── input-event.ts # 输入事件
|
||||
├── terminal-focus-event.ts # 终端焦点事件
|
||||
├── terminal-event.ts # 终端事件
|
||||
├── emitter.ts # 事件发射器
|
||||
├── dispatcher.ts # 事件分发器
|
||||
└── event.ts # 事件基类
|
||||
```
|
||||
|
||||
**键盘事件结构**:
|
||||
```typescript
|
||||
interface KeyboardEvent {
|
||||
key: string // 按键名称
|
||||
ctrl: boolean // Ctrl 修饰键
|
||||
shift: boolean // Shift 修饰键
|
||||
alt: boolean // Alt 修饰键
|
||||
meta: boolean // Meta 修饰键
|
||||
}
|
||||
```
|
||||
|
||||
### 1.5 布局系统 (ink/layout/)
|
||||
|
||||
使用 Facebook Yoga 布局引擎进行 Flexbox 布局计算。
|
||||
|
||||
```
|
||||
layout/
|
||||
├── yoga.ts # Yoga 引擎封装
|
||||
├── engine.ts # 布局引擎
|
||||
├── node.ts # 布局节点
|
||||
└── geometry.ts # 几何计算
|
||||
```
|
||||
|
||||
### 1.6 终端 IO (ink/termio/)
|
||||
|
||||
```
|
||||
termio/
|
||||
├── ansi.ts # ANSI 转义序列解析
|
||||
├── parser.ts # 终端输出解析
|
||||
├── dec.ts # DEC 私有模式
|
||||
├── osc.ts # Operating System Commands
|
||||
├── types.ts # 类型定义
|
||||
└── tokenize.ts # 标记化
|
||||
```
|
||||
|
||||
## 2. React 业务组件 (components/)
|
||||
|
||||
components 目录包含约 140 个 React 组件,提供高级 UI 功能。
|
||||
|
||||
### 2.1 主要分类
|
||||
|
||||
| 类别 | 示例组件 | 用途 |
|
||||
|------|----------|------|
|
||||
| 消息 | Message.tsx, MessageRow.tsx, Messages.tsx | 消息显示 |
|
||||
| 对话 | ChatInput.tsx, PromptInput/* | 用户输入 |
|
||||
| 设置 | Settings/*, ThemePicker.tsx | 设置界面 |
|
||||
| 诊断 | DiagnosticsDisplay.tsx, Doctor.tsx | 问题诊断 |
|
||||
| 权限 | permissions/* | 权限管理 |
|
||||
| MCP | MCPServerApprovalDialog.tsx, mcp/* | MCP 服务器 |
|
||||
| 差分 | StructuredDiff.tsx, FileEditToolDiff.tsx | 差异显示 |
|
||||
| 搜索 | GlobalSearchDialog.tsx, HistorySearchDialog.tsx | 搜索功能 |
|
||||
| 任务 | TaskListV2.tsx, tasks/* | 任务管理 |
|
||||
|
||||
### 2.2 设计系统 (components/design-system/)
|
||||
|
||||
```
|
||||
design-system/
|
||||
├── ThemedBox.tsx # 主题化 Box
|
||||
├── ThemedText.tsx # 主题化 Text
|
||||
├── ThemeProvider.tsx # 主题提供者
|
||||
└── color.ts # 颜色工具
|
||||
```
|
||||
|
||||
### 2.3 核心组件示例
|
||||
|
||||
#### Message.tsx (~79KB)
|
||||
消息行组件,处理 Assistant 和 User 消息的渲染。
|
||||
|
||||
#### Spinner.tsx (~88KB)
|
||||
丰富的旋转指示器组件,支持多种变体。
|
||||
|
||||
#### Stats.tsx (~153KB)
|
||||
统计信息显示面板。
|
||||
|
||||
## 3. 全屏屏幕 (screens/)
|
||||
|
||||
### 3.1 Doctor.tsx (73KB)
|
||||
诊断屏幕,显示系统健康状态和问题检测。
|
||||
|
||||
### 3.2 REPL.tsx (896KB)
|
||||
最大的组件,REPL 交互界面,包含完整的命令行编辑功能。
|
||||
|
||||
### 3.3 ResumeConversation.tsx (60KB)
|
||||
对话恢复屏幕,允许用户恢复之前的会话。
|
||||
|
||||
## 4. 输出样式 (outputStyles/)
|
||||
|
||||
```
|
||||
outputStyles/
|
||||
└── loadOutputStylesDir.ts
|
||||
```
|
||||
|
||||
负责加载和管理输出样式目录。
|
||||
|
||||
## 5. 核心概念
|
||||
|
||||
### 5.1 帧缓冲区 (Frame)
|
||||
每帧包含完整的屏幕内容,由 Ink 渲染器管理双缓冲:
|
||||
- `frontFrame`: 当前显示帧
|
||||
- `backFrame`: 下一帧(渲染中)
|
||||
|
||||
### 5.2 样式池 (StylePool)
|
||||
重用样式对象,减少内存分配。
|
||||
|
||||
### 5.3 Yoga 布局
|
||||
使用 Yoga 引擎计算 Flexbox 布局,支持:
|
||||
- flexDirection, justifyContent, alignItems
|
||||
- flexGrow, flexShrink
|
||||
- margin, padding, gap
|
||||
- overflow 处理
|
||||
|
||||
### 5.4 虚拟滚动
|
||||
ScrollBox 通过只渲染可见内容实现虚拟滚动,提升大列表性能。
|
||||
|
||||
### 5.5 焦点管理
|
||||
FocusManager 跟踪键盘焦点,支持 Tab/Shift+Tab 导航。
|
||||
401
claude-code-中文Wiki/13-配置与迁移系统.md
Normal file
401
claude-code-中文Wiki/13-配置与迁移系统.md
Normal file
@@ -0,0 +1,401 @@
|
||||
# 配置与迁移系统
|
||||
|
||||
Claude Code 使用 Zod 进行配置模式验证,并通过迁移系统处理配置版本升级。
|
||||
|
||||
## 目录结构
|
||||
|
||||
```
|
||||
src/
|
||||
├── schemas/ # Zod 配置模式定义
|
||||
├── migrations/ # 配置迁移脚本
|
||||
└── utils/settings/ # 设置管理系统
|
||||
├── settings.ts # 设置管理核心
|
||||
├── validation.ts # 验证逻辑
|
||||
├── changeDetector.ts # 变更检测
|
||||
├── applySettingsChange.ts # 变更应用
|
||||
├── permissionValidation.ts # 权限规则验证
|
||||
├── toolValidationConfig.ts # 工具验证配置
|
||||
├── types.ts # 类型定义
|
||||
├── constants.ts # 常量
|
||||
├── mdm/ # 移动设备管理
|
||||
└── settingsCache.ts # 设置缓存
|
||||
```
|
||||
|
||||
## 1. 配置模式 (schemas/)
|
||||
|
||||
### 1.1 主模式文件
|
||||
**文件**: `src/schemas/hooks.ts` (7884行)
|
||||
|
||||
使用 Zod 定义所有配置项的验证模式。
|
||||
|
||||
### 1.2 核心模式示例
|
||||
|
||||
```typescript
|
||||
// 基础设置模式
|
||||
const baseSettingsSchema = z.object({
|
||||
// 模型配置
|
||||
model: z.string(),
|
||||
maxTokens: z.number().optional(),
|
||||
|
||||
// UI 设置
|
||||
theme: z.enum(['dark', 'light', 'system']),
|
||||
fontSize: z.number().min(8).max(24),
|
||||
|
||||
// 权限设置
|
||||
allowPermissions: z.boolean(),
|
||||
permissionRules: z.array(permissionRuleSchema).optional(),
|
||||
})
|
||||
|
||||
// MCP 服务器配置
|
||||
const mcpServerSchema = z.object({
|
||||
name: z.string(),
|
||||
command: z.string(),
|
||||
args: z.array(z.string()).optional(),
|
||||
env: z.record(z.string()).optional(),
|
||||
})
|
||||
```
|
||||
|
||||
## 2. 设置管理 (utils/settings/)
|
||||
|
||||
### 2.1 设置核心 (settings.ts)
|
||||
|
||||
**文件**: `src/utils/settings/settings.ts` (~32KB)
|
||||
|
||||
**主要函数**:
|
||||
|
||||
| 函数 | 用途 |
|
||||
|------|------|
|
||||
| `getSettings()` | 获取当前设置 |
|
||||
| `updateSettings(partial)` | 更新设置 |
|
||||
| `resetSettings()` | 重置为默认值 |
|
||||
| `loadManagedFileSettings()` | 加载托管配置文件 |
|
||||
| `parseSettingsFile(path)` | 解析设置文件 |
|
||||
|
||||
**设置加载优先级** (从低到高):
|
||||
1. 默认值
|
||||
2. 托管设置文件 (`managed-settings.json`)
|
||||
3. 托管设置 Drop-in 目录 (`managed-settings.d/*.json`)
|
||||
4. 用户设置文件 (`~/.claude/settings.json`)
|
||||
|
||||
**托管设置系统**:
|
||||
```typescript
|
||||
// 加载托管文件设置
|
||||
export function loadManagedFileSettings(): {
|
||||
settings: SettingsJson | null
|
||||
errors: ValidationError[]
|
||||
} {
|
||||
// 1. 加载 managed-settings.json (基础)
|
||||
// 2. 按字母顺序加载 managed-settings.d/*.json (覆盖)
|
||||
}
|
||||
```
|
||||
|
||||
### 2.2 变更检测 (changeDetector.ts)
|
||||
|
||||
**文件**: `src/utils/settings/changeDetector.ts` (~16KB)
|
||||
|
||||
检测设置变更并触发相应的处理逻辑。
|
||||
|
||||
**主要功能**:
|
||||
- 检测设置项的变化
|
||||
- 生成变更事件
|
||||
- 防止循环依赖
|
||||
|
||||
### 2.3 变更应用 (applySettingsChange.ts)
|
||||
|
||||
**文件**: `src/utils/settings/applySettingsChange.ts`
|
||||
|
||||
应用设置变更到运行时系统。
|
||||
|
||||
```typescript
|
||||
// 示例:应用主题变更
|
||||
async function applyThemeChange(theme: Theme): Promise<void> {
|
||||
// 1. 更新渲染器主题
|
||||
// 2. 通知所有订阅者
|
||||
// 3. 持久化到磁盘
|
||||
}
|
||||
```
|
||||
|
||||
### 2.4 验证 (validation.ts)
|
||||
|
||||
**文件**: `src/utils/settings/validation.ts` (~8KB)
|
||||
|
||||
**主要函数**:
|
||||
|
||||
| 函数 | 用途 |
|
||||
|------|------|
|
||||
| `validateSettings(settings)` | 验证完整设置 |
|
||||
| `validateSetting(key, value)` | 验证单个设置 |
|
||||
| `formatZodError(error)` | 格式化 Zod 错误 |
|
||||
| `filterInvalidPermissionRules(rules)` | 过滤无效权限规则 |
|
||||
|
||||
**验证流程**:
|
||||
```typescript
|
||||
export function validateSettings(
|
||||
settings: unknown
|
||||
): SettingsWithErrors {
|
||||
const result = SettingsSchema.safeParse(settings)
|
||||
|
||||
if (result.success) {
|
||||
return { settings: result.data, errors: [] }
|
||||
}
|
||||
|
||||
// 转换 Zod 错误为友好格式
|
||||
return {
|
||||
settings: null,
|
||||
errors: formatZodError(result.error)
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### 2.5 权限验证 (permissionValidation.ts)
|
||||
|
||||
**文件**: `src/utils/settings/permissionValidation.ts` (~8.5KB)
|
||||
|
||||
验证权限规则的有效性。
|
||||
|
||||
**权限规则结构**:
|
||||
```typescript
|
||||
interface PermissionRule {
|
||||
tool: string // 工具名称
|
||||
path?: string // 路径模式
|
||||
deny?: boolean // 拒绝还是允许
|
||||
reason?: string // 原因说明
|
||||
}
|
||||
```
|
||||
|
||||
**验证规则**:
|
||||
1. 工具名称必须有效
|
||||
2. 路径模式必须是有效的 glob 或正则
|
||||
3. 冲突规则被拒绝
|
||||
|
||||
### 2.6 工具验证配置 (toolValidationConfig.ts)
|
||||
|
||||
**文件**: `src/utils/settings/toolValidationConfig.ts`
|
||||
|
||||
配置哪些工具需要验证或可以直接执行。
|
||||
|
||||
```typescript
|
||||
// 免验证工具
|
||||
const bypassValidationTools = [
|
||||
'Read',
|
||||
'BackgroundRead',
|
||||
'TodoWrite',
|
||||
'NotebookEdit',
|
||||
]
|
||||
|
||||
// 需要路径验证的工具
|
||||
const pathValidationTools = [
|
||||
'Bash',
|
||||
'Write',
|
||||
'Edit',
|
||||
'Read',
|
||||
]
|
||||
```
|
||||
|
||||
### 2.7 MDM 配置 (mdm/)
|
||||
|
||||
**目录**: `src/utils/settings/mdm/`
|
||||
|
||||
支持移动设备管理 (Mobile Device Management) 配置。
|
||||
|
||||
```
|
||||
mdm/
|
||||
└── settings.ts # MDM 设置加载
|
||||
```
|
||||
|
||||
### 2.8 类型定义 (types.ts)
|
||||
|
||||
**文件**: `src/utils/settings/types.ts` (~43KB)
|
||||
|
||||
定义所有设置相关的类型。
|
||||
|
||||
```typescript
|
||||
// 设置 JSON 结构
|
||||
type SettingsJson = {
|
||||
// 基本设置
|
||||
model?: string
|
||||
theme?: 'dark' | 'light' | 'system'
|
||||
|
||||
// MCP
|
||||
mcpServers?: Record<string, McpServerConfig>
|
||||
|
||||
// 权限
|
||||
permissionRules?: PermissionRule[]
|
||||
|
||||
// 实验性功能
|
||||
experimental?: Record<string, boolean>
|
||||
}
|
||||
|
||||
// 设置来源
|
||||
type SettingSource =
|
||||
| 'default'
|
||||
| 'managed'
|
||||
| 'user'
|
||||
|
||||
// 可编辑的设置源
|
||||
type EditableSettingSource = 'user'
|
||||
```
|
||||
|
||||
## 3. 迁移系统 (migrations/)
|
||||
|
||||
### 3.1 迁移文件列表
|
||||
|
||||
| 文件 | 用途 |
|
||||
|------|------|
|
||||
| `migrateAutoUpdatesToSettings.ts` | 自动更新迁移 |
|
||||
| `migrateBypassPermissionsAcceptedToSettings.ts` | 绕过权限迁移 |
|
||||
| `migrateEnableAllProjectMcpServersToSettings.ts` | MCP 服务器迁移 |
|
||||
| `migrateFennecToOpus.ts` | Fennec → Opus 模型迁移 |
|
||||
| `migrateLegacyOpusToCurrent.ts` | Legacy Opus 迁移 |
|
||||
| `migrateOpusToOpus1m.ts` | Opus → Opus 1M 迁移 |
|
||||
| `migrateReplBridgeEnabledToRemoteControlAtStartup.ts` | REPL 桥接迁移 |
|
||||
| `migrateSonnet1mToSonnet45.ts` | Sonnet 1M → 4.5 迁移 |
|
||||
| `migrateSonnet45ToSonnet46.ts` | Sonnet 4.5 → 4.6 迁移 |
|
||||
| `resetAutoModeOptInForDefaultOffer.ts` | 自动模式重置 |
|
||||
| `resetProToOpusDefault.ts` | Pro → Opus 默认重置 |
|
||||
|
||||
### 3.2 迁移示例
|
||||
|
||||
**migrateOpusToOpus1m.ts**:
|
||||
```typescript
|
||||
export function migrateOpusToOpus1m(
|
||||
oldSettings: LegacySettings
|
||||
): NewSettings {
|
||||
return {
|
||||
...oldSettings,
|
||||
model: oldSettings.model === 'opus' ? 'opus-3-5-20241120' : oldSettings.model,
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### 3.3 迁移执行时机
|
||||
|
||||
迁移在以下时机执行:
|
||||
1. 应用启动时
|
||||
2. 设置加载前
|
||||
3. 版本检测后
|
||||
|
||||
## 4. 常量 (constants.ts)
|
||||
|
||||
**文件**: `src/utils/settings/constants.ts` (~5.5KB)
|
||||
|
||||
```typescript
|
||||
// 设置源优先级
|
||||
const SETTING_SOURCE_PRIORITY: Record<SettingSource, number> = {
|
||||
default: 0,
|
||||
managed: 50,
|
||||
user: 100,
|
||||
}
|
||||
|
||||
// 设置路径
|
||||
const SETTINGS_DIR = 'settings'
|
||||
const SETTINGS_FILE = 'settings.json'
|
||||
const MANAGED_SETTINGS_FILE = 'managed-settings.json'
|
||||
const MANAGED_SETTINGS_DROPIN_DIR = 'managed-settings.d'
|
||||
|
||||
// 默认值
|
||||
const DEFAULT_MODEL = 'claude-opus-4-5'
|
||||
const DEFAULT_THEME = 'dark'
|
||||
const DEFAULT_MAX_TOKENS = 8192
|
||||
```
|
||||
|
||||
## 5. 缓存管理 (settingsCache.ts)
|
||||
|
||||
**文件**: `src/utils/settings/settingsCache.ts` (~2.4KB)
|
||||
|
||||
```typescript
|
||||
// 缓存接口
|
||||
interface SettingsCache {
|
||||
get(key: string): SettingsJson | null
|
||||
set(key: string, value: SettingsJson): void
|
||||
invalidate(key: string): void
|
||||
clear(): void
|
||||
}
|
||||
|
||||
// 缓存策略
|
||||
const CACHE_TTL = 5 * 60 * 1000 // 5 分钟
|
||||
const MAX_CACHE_SIZE = 10
|
||||
```
|
||||
|
||||
## 6. 托管设置系统详解
|
||||
|
||||
### 6.1 Drop-in 机制
|
||||
|
||||
托管设置支持 Drop-in 目录机制,允许多个配置文件按优先级合并:
|
||||
|
||||
```
|
||||
~/.claude/settings.json # 用户设置
|
||||
/etc/claude/managed-settings.json # 系统托管基础
|
||||
/etc/claude/managed-settings.d/
|
||||
├── 10-base.json # 优先级 10
|
||||
├── 20-security.json # 优先级 20
|
||||
└── 30-otel.json # 优先级 30
|
||||
```
|
||||
|
||||
### 6.2 合并规则
|
||||
|
||||
1. 基础文件先加载
|
||||
2. Drop-in 文件按文件名排序后加载
|
||||
3. 后加载的文件优先级更高
|
||||
4. 数组字段替换,非数组字段合并
|
||||
|
||||
## 7. 配置验证规则
|
||||
|
||||
### 7.1 路径验证
|
||||
|
||||
```typescript
|
||||
function validatePath(path: string): boolean {
|
||||
// 禁止危险路径
|
||||
if (path.includes('..')) return false
|
||||
if (path.startsWith('/etc/')) return false
|
||||
if (path.startsWith('/sys/')) return false
|
||||
|
||||
// 检查权限
|
||||
if (!canAccessPath(path)) return false
|
||||
|
||||
return true
|
||||
}
|
||||
```
|
||||
|
||||
### 7.2 命令验证
|
||||
|
||||
```typescript
|
||||
function validateCommand(command: string): boolean {
|
||||
// 白名单检查
|
||||
const allowedCommands = ['read', 'edit', 'bash']
|
||||
return allowedCommands.includes(command)
|
||||
}
|
||||
```
|
||||
|
||||
### 7.3 模型名称验证
|
||||
|
||||
```typescript
|
||||
const VALID_MODELS = [
|
||||
'claude-opus-4-5',
|
||||
'claude-sonnet-4-6',
|
||||
'claude-opus-3-5-20241120',
|
||||
// ...
|
||||
]
|
||||
|
||||
function validateModel(model: string): boolean {
|
||||
return VALID_MODELS.includes(model)
|
||||
}
|
||||
```
|
||||
|
||||
## 8. 内部写入标识 (internalWrites.ts)
|
||||
|
||||
**文件**: `src/utils/settings/internalWrites.ts`
|
||||
|
||||
标识由系统内部触发的设置写入,防止来自用户配置文件的覆盖。
|
||||
|
||||
```typescript
|
||||
// 标记内部写入
|
||||
export function markInternalWrite(key: string): void {
|
||||
internalWrites.add(key)
|
||||
}
|
||||
|
||||
// 检查是否为内部写入
|
||||
export function isInternalWrite(key: string): boolean {
|
||||
return internalWrites.has(key)
|
||||
}
|
||||
```
|
||||
387
claude-code-中文Wiki/14-网络与代理.md
Normal file
387
claude-code-中文Wiki/14-网络与代理.md
Normal file
@@ -0,0 +1,387 @@
|
||||
# 网络与代理
|
||||
|
||||
Claude Code 的网络系统处理代理配置、远程会话管理和服务器模式。
|
||||
|
||||
## 目录结构
|
||||
|
||||
```
|
||||
src/
|
||||
├── upstreamproxy/ # 上游代理配置
|
||||
│ ├── upstreamproxy.ts # 代理核心
|
||||
│ └── relay.ts # 代理中继
|
||||
├── remote/ # 远程会话
|
||||
│ ├── RemoteSessionManager.ts # 会话管理
|
||||
│ ├── SessionsWebSocket.ts # WebSocket 会话
|
||||
│ ├── remotePermissionBridge.ts # 权限桥接
|
||||
│ └── sdkMessageAdapter.ts # SDK 消息适配
|
||||
└── server/ # 服务器模式
|
||||
├── createDirectConnectSession.ts # 直连会话
|
||||
├── directConnectManager.ts # 直连管理
|
||||
└── types.ts # 类型定义
|
||||
```
|
||||
|
||||
## 1. 上游代理 (upstreamproxy/)
|
||||
|
||||
### 1.1 代理核心 (upstreamproxy.ts)
|
||||
|
||||
**文件**: `src/upstreamproxy/upstreamproxy.ts` (~10KB)
|
||||
|
||||
管理 Claude Code 与上游服务之间的 HTTP/SOCKS 代理连接。
|
||||
|
||||
**核心功能**:
|
||||
- 代理协议支持 (HTTP, HTTPS, SOCKS4, SOCKS5)
|
||||
- 代理认证 (Basic,NTLM, Negotiate)
|
||||
- 连接池管理
|
||||
- 自动重试和故障转移
|
||||
|
||||
**主要类**: `UpstreamProxy`
|
||||
|
||||
```typescript
|
||||
class UpstreamProxy {
|
||||
// 代理配置
|
||||
readonly type: 'http' | 'https' | 'socks4' | 'socks5'
|
||||
readonly host: string
|
||||
readonly port: number
|
||||
readonly auth?: ProxyAuth
|
||||
|
||||
// 连接池
|
||||
private pool: ConnectionPool
|
||||
|
||||
// 方法
|
||||
async getConnection(url: URL): Promise<Connection>
|
||||
async request(req: Request): Promise<Response>
|
||||
close(): void
|
||||
}
|
||||
```
|
||||
|
||||
**代理认证**:
|
||||
```typescript
|
||||
interface ProxyAuth {
|
||||
type: 'basic' | 'ntlm' | 'negotiate'
|
||||
username: string
|
||||
password?: string
|
||||
domain?: string // NTLM 专用
|
||||
}
|
||||
```
|
||||
|
||||
### 1.2 代理中继 (relay.ts)
|
||||
|
||||
**文件**: `src/upstreamproxy/relay.ts` (~15KB)
|
||||
|
||||
在代理链中转发请求,支持多层代理。
|
||||
|
||||
**功能**:
|
||||
- 代理链构建
|
||||
- 请求/响应转发
|
||||
- 头部处理
|
||||
- 连接复用
|
||||
|
||||
```typescript
|
||||
class ProxyRelay {
|
||||
// 上游代理链
|
||||
private relays: UpstreamProxy[]
|
||||
|
||||
// 添加跳点
|
||||
addHop(proxy: UpstreamProxy): void
|
||||
|
||||
// 转发请求
|
||||
async relayRequest(req: Request): Promise<Response>
|
||||
}
|
||||
```
|
||||
|
||||
## 2. 远程会话 (remote/)
|
||||
|
||||
### 2.1 会话管理器 (RemoteSessionManager.ts)
|
||||
|
||||
**文件**: `src/remote/RemoteSessionManager.ts` (~9KB)
|
||||
|
||||
管理远程 Claude Code 实例的会话。
|
||||
|
||||
**核心功能**:
|
||||
- 会话生命周期管理
|
||||
- 连接状态监控
|
||||
- 消息路由
|
||||
- 断开重连
|
||||
|
||||
**主要接口**:
|
||||
|
||||
```typescript
|
||||
interface RemoteSession {
|
||||
id: string
|
||||
remoteId: string
|
||||
status: 'connecting' | 'connected' | 'disconnected'
|
||||
createdAt: number
|
||||
lastActivity: number
|
||||
}
|
||||
|
||||
class RemoteSessionManager {
|
||||
// 创建会话
|
||||
async createSession(config: RemoteConfig): Promise<RemoteSession>
|
||||
|
||||
// 获取会话
|
||||
getSession(id: string): RemoteSession | null
|
||||
|
||||
// 列出所有会话
|
||||
listSessions(): RemoteSession[]
|
||||
|
||||
// 终止会话
|
||||
async terminateSession(id: string): Promise<void>
|
||||
|
||||
// 事件
|
||||
onSessionCreated: Event<RemoteSession>
|
||||
onSessionClosed: Event<string>
|
||||
onSessionError: Event<{ id: string; error: Error }>
|
||||
}
|
||||
```
|
||||
|
||||
### 2.2 WebSocket 会话 (SessionsWebSocket.ts)
|
||||
|
||||
**文件**: `src/remote/SessionsWebSocket.ts` (~12.5KB)
|
||||
|
||||
通过 WebSocket 管理远程会话的实时通信。
|
||||
|
||||
**功能**:
|
||||
- WebSocket 连接建立
|
||||
- 心跳检测
|
||||
- 消息序列化/反序列化
|
||||
- 重连逻辑
|
||||
|
||||
```typescript
|
||||
class SessionsWebSocket {
|
||||
// 连接 URL
|
||||
readonly url: string
|
||||
|
||||
// WebSocket 实例
|
||||
private ws: WebSocket
|
||||
|
||||
// 状态
|
||||
get status(): 'connecting' | 'open' | 'closing' | 'closed'
|
||||
|
||||
// 发送消息
|
||||
send(message: SessionMessage): void
|
||||
|
||||
// 接收消息
|
||||
onMessage: (message: SessionMessage) => void
|
||||
|
||||
// 重连
|
||||
async reconnect(): Promise<void>
|
||||
}
|
||||
```
|
||||
|
||||
### 2.3 权限桥接 (remotePermissionBridge.ts)
|
||||
|
||||
**文件**: `src/remote/remotePermissionBridge.ts` (~2.4KB)
|
||||
|
||||
在远程会话中桥接权限检查。
|
||||
|
||||
```typescript
|
||||
// 本地权限检查
|
||||
const localCheck = await checkPermission(tool, args)
|
||||
|
||||
// 远程权限请求
|
||||
const remoteGrant = await remoteSession.requestPermission({
|
||||
tool,
|
||||
args,
|
||||
reason: 'Remote session requested'
|
||||
})
|
||||
|
||||
// 合并结果
|
||||
return localCheck || remoteGrant
|
||||
```
|
||||
|
||||
### 2.4 SDK 消息适配器 (sdkMessageAdapter.ts)
|
||||
|
||||
**文件**: `src/remote/sdkMessageAdapter.ts` (~9KB)
|
||||
|
||||
适配 Claude SDK 消息格式与内部消息格式。
|
||||
|
||||
```typescript
|
||||
// SDK 消息 -> 内部消息
|
||||
function adaptFromSDK(sdkMessage: SDKMessage): InternalMessage
|
||||
|
||||
// 内部消息 -> SDK 消息
|
||||
function adaptToSDK(internalMessage: InternalMessage): SDKMessage
|
||||
|
||||
// 工具结果适配
|
||||
function adaptToolResult(result: ToolResult): ToolResultBlockParam
|
||||
```
|
||||
|
||||
## 3. 服务器模式 (server/)
|
||||
|
||||
### 3.1 直连会话 (createDirectConnectSession.ts)
|
||||
|
||||
**文件**: `src/server/createDirectConnectSession.ts` (~2.2KB)
|
||||
|
||||
创建直接的点对点连接会话。
|
||||
|
||||
```typescript
|
||||
interface DirectConnectConfig {
|
||||
remoteId: string
|
||||
authToken: string
|
||||
endpoint: URL
|
||||
}
|
||||
|
||||
async function createDirectConnectSession(
|
||||
config: DirectConnectConfig
|
||||
): Promise<DirectSession> {
|
||||
// 1. 验证配置
|
||||
validateConfig(config)
|
||||
|
||||
// 2. 建立连接
|
||||
const connection = await establishConnection(config)
|
||||
|
||||
// 3. 创建会话
|
||||
return new DirectSession(connection)
|
||||
}
|
||||
```
|
||||
|
||||
### 3.2 直连管理器 (directConnectManager.ts)
|
||||
|
||||
**文件**: `src/server/directConnectManager.ts` (~6KB)
|
||||
|
||||
管理所有直连会话。
|
||||
|
||||
**功能**:
|
||||
- 会话注册/注销
|
||||
- 连接状态跟踪
|
||||
- 资源清理
|
||||
- 并发控制
|
||||
|
||||
```typescript
|
||||
class DirectConnectManager {
|
||||
// 注册新会话
|
||||
register(session: DirectSession): void
|
||||
|
||||
// 注销会话
|
||||
unregister(sessionId: string): void
|
||||
|
||||
// 获取活跃会话
|
||||
getActiveSessions(): DirectSession[]
|
||||
|
||||
// 广播消息
|
||||
broadcast(message: Message): void
|
||||
|
||||
// 清理闲置会话
|
||||
cleanupIdleSessions(): void
|
||||
}
|
||||
```
|
||||
|
||||
### 3.3 类型定义 (types.ts)
|
||||
|
||||
**文件**: `src/server/types.ts`
|
||||
|
||||
```typescript
|
||||
// 服务器模式配置
|
||||
interface ServerConfig {
|
||||
host: string
|
||||
port: number
|
||||
tls: boolean
|
||||
cert?: string
|
||||
key?: string
|
||||
}
|
||||
|
||||
// 直连配置
|
||||
interface DirectConnectConfig {
|
||||
remoteId: string
|
||||
authToken: string
|
||||
endpoint: string
|
||||
}
|
||||
|
||||
// 会话消息
|
||||
interface SessionMessage {
|
||||
type: 'query' | 'result' | 'error' | 'heartbeat'
|
||||
sessionId: string
|
||||
payload: unknown
|
||||
timestamp: number
|
||||
}
|
||||
```
|
||||
|
||||
## 4. 连接流程
|
||||
|
||||
### 4.1 远程会话建立
|
||||
|
||||
```
|
||||
Client Server
|
||||
| |
|
||||
|--- WebSocket Connect --------->|
|
||||
| |
|
||||
|<-- Handshake Challenge -------|
|
||||
| |
|
||||
|--- Handshake Response ------->|
|
||||
| |
|
||||
|<-- Session Created ----------|
|
||||
| |
|
||||
|<====== Session Active =======>|
|
||||
| |
|
||||
|<-- Session Terminated --------|
|
||||
```
|
||||
|
||||
### 4.2 代理请求流程
|
||||
|
||||
```
|
||||
Claude Code
|
||||
|
|
||||
v
|
||||
UpstreamProxy
|
||||
|
|
||||
+---> HTTP Proxy
|
||||
|
|
||||
+---> SOCKS5 Proxy
|
||||
|
|
||||
v
|
||||
Anthropic API
|
||||
```
|
||||
|
||||
## 5. 安全考虑
|
||||
|
||||
### 5.1 TLS/SSL
|
||||
|
||||
- 服务器模式支持 TLS 终止
|
||||
- 证书验证可选
|
||||
- 支持自签名证书 (开发模式)
|
||||
|
||||
### 5.2 认证
|
||||
|
||||
- Token-based 认证
|
||||
- 定期心跳检测
|
||||
- 会话超时控制
|
||||
|
||||
### 5.3 网络隔离
|
||||
|
||||
- 敏感数据加密传输
|
||||
- 代理链逐跳认证
|
||||
- 审计日志记录
|
||||
|
||||
## 6. 配置示例
|
||||
|
||||
### 6.1 代理配置 (settings.json)
|
||||
|
||||
```json
|
||||
{
|
||||
"proxy": {
|
||||
"type": "socks5",
|
||||
"host": "proxy.example.com",
|
||||
"port": 1080,
|
||||
"auth": {
|
||||
"type": "basic",
|
||||
"username": "user",
|
||||
"password": "pass"
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### 6.2 服务器模式配置
|
||||
|
||||
```json
|
||||
{
|
||||
"server": {
|
||||
"enabled": true,
|
||||
"host": "0.0.0.0",
|
||||
"port": 8080,
|
||||
"tls": true,
|
||||
"cert": "/path/to/cert.pem",
|
||||
"key": "/path/to/key.pem"
|
||||
}
|
||||
}
|
||||
```
|
||||
496
claude-code-中文Wiki/15-其他重要模块.md
Normal file
496
claude-code-中文Wiki/15-其他重要模块.md
Normal file
@@ -0,0 +1,496 @@
|
||||
# 其他重要模块
|
||||
|
||||
本文档介绍 Claude Code 中不属于前几章的重要模块。
|
||||
|
||||
## 目录结构
|
||||
|
||||
```
|
||||
src/
|
||||
├── bootstrap/ # 启动引导
|
||||
├── memdir/ # 持久化内存目录
|
||||
├── native-ts/ # 原生 TypeScript 工具
|
||||
│ ├── yoga-layout/ # Yoga 布局引擎
|
||||
│ ├── file-index/ # 文件索引
|
||||
│ └── color-diff/ # 颜色差异计算
|
||||
├── voice/ # 语音输入
|
||||
├── vim/ # Vim 模式
|
||||
├── keybindings/ # 快捷键配置
|
||||
├── moreright/ # 权限扩展 UI
|
||||
├── outputStyles/ # 输出样式管理
|
||||
└── query/ # 查询管道
|
||||
├── tokenBudget.ts # Token 预算管理
|
||||
├── stopHooks.ts # 停止钩子
|
||||
└── config.ts # 查询配置
|
||||
```
|
||||
|
||||
## 1. 启动引导 (bootstrap/)
|
||||
|
||||
### 1.1 引导状态 (state.ts)
|
||||
|
||||
**文件**: `src/bootstrap/state.ts` (~56KB)
|
||||
|
||||
管理应用启动状态和全局状态。
|
||||
|
||||
**主要功能**:
|
||||
- 启动时间跟踪
|
||||
- 交互时间统计
|
||||
- 功能开关状态
|
||||
- 工作目录管理
|
||||
|
||||
**关键函数**:
|
||||
|
||||
| 函数 | 用途 |
|
||||
|------|------|
|
||||
| `getOriginalCwd()` | 获取原始工作目录 |
|
||||
| `getKairosActive()` | 获取 Kairos 状态 |
|
||||
| `flushInteractionTime()` | 刷新交互时间 |
|
||||
| `markScrollActivity()` | 标记滚动活动 |
|
||||
|
||||
## 2. 持久化内存 (memdir/)
|
||||
|
||||
### 2.1 内存目录核心 (memdir.ts)
|
||||
|
||||
**文件**: `src/memdir/memdir.ts` (~21KB)
|
||||
|
||||
管理 MEMORY.md 文件和自动记忆系统。
|
||||
|
||||
**主要功能**:
|
||||
- 内存文件读写
|
||||
- 记忆检索
|
||||
- 入口点截断
|
||||
- 团队记忆管理
|
||||
|
||||
**关键常量**:
|
||||
```typescript
|
||||
export const ENTRYPOINT_NAME = 'MEMORY.md'
|
||||
export const MAX_ENTRYPOINT_LINES = 200
|
||||
export const MAX_ENTRYPOINT_BYTES = 25_000
|
||||
```
|
||||
|
||||
**截断函数**:
|
||||
```typescript
|
||||
export function truncateEntrypointContent(
|
||||
raw: string
|
||||
): EntrypointTruncation {
|
||||
// 1. 按行截断 (最多200行)
|
||||
// 2. 按字节截断 (最多25KB)
|
||||
// 3. 返回截断结果和警告信息
|
||||
}
|
||||
```
|
||||
|
||||
### 2.2 记忆类型 (memoryTypes.ts)
|
||||
|
||||
**文件**: `src/memdir/memoryTypes.ts` (~23KB)
|
||||
|
||||
定义记忆相关的数据结构和常量。
|
||||
|
||||
```typescript
|
||||
// 记忆入口
|
||||
interface MemoryEntry {
|
||||
id: string
|
||||
type: 'individual' | 'team'
|
||||
keywords: string[]
|
||||
content: string
|
||||
createdAt: number
|
||||
accessedAt: number
|
||||
}
|
||||
|
||||
// 记忆类型
|
||||
const TYPES_SECTION_INDIVIDUAL = ...
|
||||
const TRUSTING_RECALL_SECTION = ...
|
||||
const WHAT_NOT_TO_SAVE_SECTION = ...
|
||||
```
|
||||
|
||||
### 2.3 路径管理 (paths.ts)
|
||||
|
||||
**文件**: `src/memdir/paths.ts` (~11KB)
|
||||
|
||||
管理内存目录的路径计算。
|
||||
|
||||
```typescript
|
||||
export function getMemoryDir(): string {
|
||||
return join(getProjectDir(), '.claude', 'memory')
|
||||
}
|
||||
|
||||
export function getAutoMemPath(): string {
|
||||
return join(getMemoryDir(), 'auto', 'MEMORY.md')
|
||||
}
|
||||
```
|
||||
|
||||
### 2.4 相关文件
|
||||
|
||||
| 文件 | 用途 |
|
||||
|------|------|
|
||||
| `findRelevantMemories.ts` | 查找相关记忆 |
|
||||
| `memoryAge.ts` | 记忆老化计算 |
|
||||
| `memoryScan.ts` | 记忆扫描 |
|
||||
| `teamMemPaths.ts` | 团队记忆路径 |
|
||||
| `teamMemPrompts.ts` | 团队记忆提示词 |
|
||||
|
||||
## 3. 原生 TypeScript 工具 (native-ts/)
|
||||
|
||||
### 3.1 Yoga 布局引擎 (yoga-layout/)
|
||||
|
||||
封装 Facebook Yoga 布局引擎。
|
||||
|
||||
**注意**: Yoga 是用 C++ 编写的,通过原生绑定调用。
|
||||
|
||||
```typescript
|
||||
// 获取 Yoga 计数器
|
||||
export function getYogaCounters(): {
|
||||
ms: number
|
||||
visited: number
|
||||
measured: number
|
||||
cacheHits: number
|
||||
live: number
|
||||
}
|
||||
```
|
||||
|
||||
### 3.2 文件索引 (file-index/)
|
||||
|
||||
文件内容的快速索引系统。
|
||||
|
||||
**用途**:
|
||||
- 代码搜索加速
|
||||
- 上下文构建
|
||||
- 记忆检索
|
||||
|
||||
### 3.3 颜色差异 (color-diff/)
|
||||
|
||||
计算颜色之间的视觉差异。
|
||||
|
||||
```typescript
|
||||
// Delta E (CIE2000) 计算
|
||||
export function colorDistance(
|
||||
color1: RGB,
|
||||
color2: RGB
|
||||
): number {
|
||||
// 返回 Delta E 值
|
||||
// < 1: 几乎不可察觉
|
||||
// 1-2: 轻微差异
|
||||
// 2-5: 有感差异
|
||||
// > 5: 明显差异
|
||||
}
|
||||
```
|
||||
|
||||
## 4. 语音输入 (voice/)
|
||||
|
||||
### 4.1 语音模式启用 (voiceModeEnabled.ts)
|
||||
|
||||
**文件**: `src/voice/voiceModeEnabled.ts`
|
||||
|
||||
检查语音输入模式是否启用。
|
||||
|
||||
```typescript
|
||||
export function isVoiceModeEnabled(): boolean {
|
||||
return isEnvTruthy('VOICE_MODE_ENABLED')
|
||||
}
|
||||
```
|
||||
|
||||
## 5. Vim 模式 (vim/)
|
||||
|
||||
### 5.1 模块结构
|
||||
|
||||
```
|
||||
vim/
|
||||
├── motions.ts # 动作 (h/j/k/l/w/b/e/...)
|
||||
├── operators.ts # 操作符 (d/y/c/s/r)
|
||||
├── textObjects.ts # 文本对象 (iw/aW/is/as/...)
|
||||
├── transitions.ts # 状态转换
|
||||
└── types.ts # 类型定义
|
||||
```
|
||||
|
||||
### 5.2 核心概念
|
||||
|
||||
**动作 (Motions)**:
|
||||
```typescript
|
||||
// 基础动作
|
||||
type Motion =
|
||||
| { type: 'char'; direction: 'left' | 'right' }
|
||||
| { type: 'word'; direction: 'forward' | 'backward' }
|
||||
| { type: 'line'; direction: 'up' | 'down' }
|
||||
| { type: 'lineStart' }
|
||||
| { type: 'lineEnd' }
|
||||
```
|
||||
|
||||
**操作符 (Operators)**:
|
||||
```typescript
|
||||
type Operator =
|
||||
| { type: 'delete' }
|
||||
| { type: 'yank' }
|
||||
| { type: 'change' }
|
||||
| { type: 'replace' }
|
||||
| { type: 'swapCase' }
|
||||
```
|
||||
|
||||
**状态机**:
|
||||
```typescript
|
||||
type VimState =
|
||||
| 'normal' // 普通模式
|
||||
| 'insert' // 插入模式
|
||||
| 'visual' // 可视模式
|
||||
| 'operator' // 操作符等待
|
||||
```
|
||||
|
||||
### 5.3 状态转换 (transitions.ts)
|
||||
|
||||
**文件**: `src/vim/transitions.ts` (~12KB)
|
||||
|
||||
管理 Vim 模式的状态转换。
|
||||
|
||||
```typescript
|
||||
// 转换函数
|
||||
function transition(
|
||||
state: VimState,
|
||||
input: VimInput
|
||||
): VimState
|
||||
|
||||
// 示例: Normal -> Insert
|
||||
// i -> Insert
|
||||
// a -> Insert (after cursor)
|
||||
// o -> Insert (new line below)
|
||||
|
||||
// 示例: Normal -> Visual
|
||||
// v -> Visual (character-wise)
|
||||
// V -> Visual (line-wise)
|
||||
```
|
||||
|
||||
## 6. 快捷键配置 (keybindings/)
|
||||
|
||||
### 6.1 模块结构
|
||||
|
||||
```
|
||||
keybindings/
|
||||
├── defaultBindings.ts # 默认绑定
|
||||
├── KeybindingContext.tsx # 快捷键上下文
|
||||
├── KeybindingProviderSetup.tsx # 提供者设置
|
||||
├── loadUserBindings.ts # 加载用户绑定
|
||||
├── match.ts # 匹配逻辑
|
||||
├── parser.ts # 解析器
|
||||
├── resolver.ts # 解析器
|
||||
├── schema.ts # 模式定义
|
||||
├── useKeybinding.ts # Hook
|
||||
├── validate.ts # 验证
|
||||
└── template.ts # 模板
|
||||
```
|
||||
|
||||
### 6.2 默认绑定 (defaultBindings.ts)
|
||||
|
||||
**文件**: `src/keybindings/defaultBindings.ts` (~12KB)
|
||||
|
||||
定义默认键盘快捷键。
|
||||
|
||||
```typescript
|
||||
export const DEFAULT_BINDINGS: KeyBinding[] = [
|
||||
// 编辑
|
||||
{ key: 'ctrl+c', action: 'copy' },
|
||||
{ key: 'ctrl+v', action: 'paste' },
|
||||
{ key: 'ctrl+z', action: 'undo' },
|
||||
|
||||
// 导航
|
||||
{ key: 'ctrl+p', action: 'previousItem' },
|
||||
{ key: 'ctrl+n', action: 'nextItem' },
|
||||
|
||||
// 特定
|
||||
{ key: 'ctrl+o', action: 'expand' },
|
||||
{ key: 'escape', action: 'dismiss' },
|
||||
]
|
||||
```
|
||||
|
||||
### 6.3 快捷键解析 (parser.ts)
|
||||
|
||||
解析用户定义的快捷键字符串。
|
||||
|
||||
```typescript
|
||||
// 解析 "ctrl+shift+k"
|
||||
parseKeybinding("ctrl+shift+k")
|
||||
// -> {
|
||||
// ctrl: true,
|
||||
// shift: true,
|
||||
// key: 'k'
|
||||
// }
|
||||
```
|
||||
|
||||
### 6.4 快捷键验证 (validate.ts)
|
||||
|
||||
验证快捷键定义的有效性。
|
||||
|
||||
```typescript
|
||||
export function validateBinding(
|
||||
binding: KeyBinding
|
||||
): ValidationResult {
|
||||
// 1. 检查修饰键组合
|
||||
// 2. 检查冲突
|
||||
// 3. 检查保留键
|
||||
}
|
||||
```
|
||||
|
||||
### 6.5 使用 Hook (useKeybinding.ts)
|
||||
|
||||
React Hook 用于在组件中使用快捷键。
|
||||
|
||||
```typescript
|
||||
function useKeybinding(
|
||||
key: string,
|
||||
handler: () => void,
|
||||
options?: {
|
||||
enabled?: boolean
|
||||
scope?: 'global' | 'local'
|
||||
}
|
||||
): void
|
||||
```
|
||||
|
||||
## 7. 权限扩展 UI (moreright/)
|
||||
|
||||
### 7.1 权限扩展组件 (useMoreRight.tsx)
|
||||
|
||||
**文件**: `src/moreright/useMoreRight.tsx`
|
||||
|
||||
提供额外的权限扩展 UI。
|
||||
|
||||
```typescript
|
||||
function useMoreRight(): {
|
||||
// 权限请求
|
||||
requestPermission: (
|
||||
tool: string,
|
||||
args: unknown
|
||||
) => Promise<boolean>
|
||||
|
||||
// 权限状态
|
||||
hasPermission: (tool: string) => boolean
|
||||
|
||||
// 打开权限面板
|
||||
openPermissionPanel: () => void
|
||||
}
|
||||
```
|
||||
|
||||
## 8. 输出样式管理 (outputStyles/)
|
||||
|
||||
### 8.1 样式加载 (loadOutputStylesDir.ts)
|
||||
|
||||
**文件**: `src/outputStyles/loadOutputStylesDir.ts`
|
||||
|
||||
加载输出样式目录中的自定义样式。
|
||||
|
||||
```typescript
|
||||
export function loadOutputStylesDir(
|
||||
dirPath: string
|
||||
): OutputStyle[] {
|
||||
// 1. 扫描目录
|
||||
// 2. 解析样式文件
|
||||
// 3. 验证样式
|
||||
// 4. 返回样式列表
|
||||
}
|
||||
```
|
||||
|
||||
## 9. 查询管道 (query/)
|
||||
|
||||
### 9.1 Token 预算管理 (tokenBudget.ts)
|
||||
|
||||
**文件**: `src/query/tokenBudget.ts`
|
||||
|
||||
管理查询的 Token 预算。
|
||||
|
||||
```typescript
|
||||
export interface TokenBudget {
|
||||
total: number // 总预算
|
||||
used: number // 已使用
|
||||
reserved: number // 预留
|
||||
remaining: number // 剩余
|
||||
}
|
||||
|
||||
// 预算检查
|
||||
export function checkBudget(budget: TokenBudget): boolean {
|
||||
return budget.remaining > 0
|
||||
}
|
||||
|
||||
// 预算分配
|
||||
export function allocateBudget(
|
||||
budget: TokenBudget,
|
||||
amount: number
|
||||
): TokenBudget {
|
||||
return {
|
||||
...budget,
|
||||
used: budget.used + amount,
|
||||
remaining: budget.total - budget.used - amount
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### 9.2 停止钩子 (stopHooks.ts)
|
||||
|
||||
**文件**: `src/query/stopHooks.ts` (~17KB)
|
||||
|
||||
定义查询停止时的回调钩子。
|
||||
|
||||
```typescript
|
||||
export type StopHook = {
|
||||
id: string
|
||||
name: string
|
||||
priority: number
|
||||
execute: (context: StopContext) => Promise<void>
|
||||
}
|
||||
|
||||
export interface StopContext {
|
||||
queryId: string
|
||||
reason: 'complete' | 'error' | 'user_cancel'
|
||||
tokensUsed: number
|
||||
duration: number
|
||||
}
|
||||
|
||||
// 注册钩子
|
||||
export function registerStopHook(hook: StopHook): void
|
||||
|
||||
// 执行钩子
|
||||
export async function executeStopHooks(
|
||||
context: StopContext
|
||||
): Promise<void> {
|
||||
const hooks = getHooks()
|
||||
.sort((a, b) => b.priority - a.priority)
|
||||
|
||||
for (const hook of hooks) {
|
||||
await hook.execute(context)
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### 9.3 查询配置 (config.ts)
|
||||
|
||||
**文件**: `src/query/config.ts`
|
||||
|
||||
```typescript
|
||||
export interface QueryConfig {
|
||||
// 模型
|
||||
model: string
|
||||
maxTokens: number
|
||||
|
||||
// 预算
|
||||
tokenBudget: number
|
||||
|
||||
// 停止条件
|
||||
stopHooks: string[]
|
||||
|
||||
// 工具配置
|
||||
tools: ToolConfig[]
|
||||
|
||||
// 上下文
|
||||
systemPrompt?: string
|
||||
contextFiles?: string[]
|
||||
}
|
||||
```
|
||||
|
||||
## 10. 总结
|
||||
|
||||
这些模块提供了 Claude Code 的重要辅助功能:
|
||||
|
||||
| 模块 | 核心功能 |
|
||||
|------|----------|
|
||||
| bootstrap | 应用启动和状态管理 |
|
||||
| memdir | 持久化记忆系统 |
|
||||
| native-ts | 性能关键原生工具 |
|
||||
| voice | 语音输入支持 |
|
||||
| vim | Vim 模式编辑 |
|
||||
| keybindings | 快捷键系统 |
|
||||
| moreright | 权限扩展 |
|
||||
| outputStyles | 输出样式 |
|
||||
| query | 查询管道 |
|
||||
171
claude-code-中文Wiki/README.md
Normal file
171
claude-code-中文Wiki/README.md
Normal file
@@ -0,0 +1,171 @@
|
||||
# Claude Code 源码中文 Wiki
|
||||
|
||||
本文件说明:总索引文档,介绍整个 Wiki 的结构和各部分内容。
|
||||
|
||||
## 概述
|
||||
|
||||
Claude Code 是 Anthropic 开发的 CLI 工具,用于在终端环境中与 Claude 交互完成软件工程任务。本 Wiki 基于 2026-03-31 通过 npm source map 泄露的源码进行详细分析。
|
||||
|
||||
## 项目规模
|
||||
|
||||
- **文件数量**:约 1900 个文件
|
||||
- **代码规模**:512K+ 行代码
|
||||
- **源码泄露时间**:2026-03-31(通过 npm source map)
|
||||
|
||||
## 技术栈
|
||||
|
||||
| 组件 | 技术 |
|
||||
|------|------|
|
||||
| 运行时 | Bun |
|
||||
| 语言 | TypeScript |
|
||||
| 终端 UI | React + Ink |
|
||||
| CLI 框架 | Commander.js |
|
||||
| 参数校验 | Zod v4 |
|
||||
| 代码搜索 | ripgrep |
|
||||
| 构建工具 | Bun bundle |
|
||||
|
||||
## Wiki 结构
|
||||
|
||||
### 1. 架构总览 (`01-架构总览.md`)
|
||||
|
||||
介绍 Claude Code 的整体架构设计,包括:
|
||||
- 项目背景与定位
|
||||
- 技术栈详解
|
||||
- 核心架构设计
|
||||
- 源码泄露事件
|
||||
|
||||
### 2. 核心模块详解 (`02-核心模块详解.md`)
|
||||
|
||||
详细分析以下核心文件的实现原理:
|
||||
|
||||
| 文件 | 功能 |
|
||||
|------|------|
|
||||
| `src/main.tsx` | CLI 入口点,应用程序初始化 |
|
||||
| `src/QueryEngine.ts` | LLM 查询引擎核心,处理流式响应、工具调用循环、思考模式、重试逻辑、token 计数 |
|
||||
| `src/Tool.ts` | 工具基类和接口定义,工具注册表核心 |
|
||||
| `src/commands.ts` | 命令注册中心,所有 slash command 的注册和管理 |
|
||||
| `src/context.ts` | 系统/用户上下文收集,Git 状态、CLAUDE.md 处理 |
|
||||
| `src/cost-tracker.ts` | Token 成本追踪,费用计算 |
|
||||
| `src/query.ts` | 查询管道,消息处理循环 |
|
||||
|
||||
### 3. 工具系统 (`03-工具系统.md`)
|
||||
|
||||
详细介绍所有内置工具的实现:
|
||||
|
||||
**文件操作工具**
|
||||
- `BashTool` - 执行 Shell 命令
|
||||
- `FileReadTool` - 读取文件(支持文本、图片、PDF、Jupyter Notebook)
|
||||
- `FileWriteTool` - 写入文件
|
||||
- `FileEditTool` - 编辑文件(支持 Search/Replace 模式)
|
||||
- `GlobTool` - 文件模式匹配
|
||||
- `GrepTool` - 代码搜索
|
||||
- `NotebookEditTool` - Jupyter Notebook 编辑
|
||||
|
||||
**Web 工具**
|
||||
- `WebFetchTool` - 获取网页内容
|
||||
- `WebSearchTool` - 网络搜索
|
||||
|
||||
**Agent 与团队工具**
|
||||
- `AgentTool` - 创建和管理子 Agent
|
||||
- `TeamCreateTool` - 创建 Agent 团队
|
||||
- `TeamDeleteTool` - 删除团队
|
||||
- `SendMessageTool` - 向团队成员发送消息
|
||||
|
||||
**任务管理工具**
|
||||
- `TaskCreateTool` - 创建任务
|
||||
- `TaskGetTool` - 获取任务详情
|
||||
- `TaskUpdateTool` - 更新任务状态
|
||||
- `TaskListTool` - 列出任务
|
||||
- `TaskStopTool` - 停止任务
|
||||
- `TaskOutputTool` - 获取任务输出
|
||||
- `TodoWriteTool` - 待办事项管理
|
||||
|
||||
**模式与工作流工具**
|
||||
- `EnterPlanModeTool` - 进入计划模式
|
||||
- `ExitPlanModeTool` - 退出计划模式
|
||||
- `EnterWorktreeTool` - 进入 Git Worktree
|
||||
- `ExitWorktreeTool` - 退出 Git Worktree
|
||||
|
||||
**搜索与技能工具**
|
||||
- `ToolSearchTool` - 工具搜索
|
||||
- `SkillTool` - 技能执行
|
||||
- `MCPTool` - Model Context Protocol 工具
|
||||
|
||||
**其他工具**
|
||||
- `LSPTool` - 语言服务器协议工具
|
||||
- `CronCreateTool` - 创建定时任务
|
||||
- `RemoteTriggerTool` - 远程触发器
|
||||
- `SleepTool` - 延迟执行
|
||||
- `SyntheticOutputTool` - 结构化输出
|
||||
|
||||
## 核心概念
|
||||
|
||||
### 1. 工具系统 (Tool System)
|
||||
|
||||
Claude Code 的工具系统基于 `Tool` 基类构建,每个工具实现:
|
||||
- `call()` - 工具执行逻辑
|
||||
- `description()` - 工具描述
|
||||
- `inputSchema` - 输入参数校验
|
||||
- `checkPermissions()` - 权限检查
|
||||
- `renderToolUseMessage()` - 渲染工具使用消息
|
||||
- `renderToolResultMessage()` - 渲染工具结果消息
|
||||
|
||||
### 2. 查询引擎 (Query Engine)
|
||||
|
||||
QueryEngine 是核心查询处理组件:
|
||||
- 管理对话生命周期
|
||||
- 处理流式 API 响应
|
||||
- 执行工具调用循环
|
||||
- 支持思考模式 (Thinking Mode)
|
||||
- 实现自动压缩 (Auto-compact) 机制
|
||||
|
||||
### 3. 命令系统 (Command System)
|
||||
|
||||
命令系统支持多种命令类型:
|
||||
- `prompt` - 展开为提示文本发送给模型
|
||||
- `local` - 本地执行的命令
|
||||
- `local-jsx` - 本地执行并渲染 Ink UI
|
||||
|
||||
### 4. 上下文管理 (Context Management)
|
||||
|
||||
上下文系统收集:
|
||||
- Git 状态信息
|
||||
- CLAUDE.md 文件内容
|
||||
- 用户上下文
|
||||
- 系统上下文
|
||||
|
||||
### 5. 成本追踪 (Cost Tracking)
|
||||
|
||||
成本追踪系统记录:
|
||||
- 输入/输出 Token 数量
|
||||
- 缓存读写 Token
|
||||
- Web 搜索请求次数
|
||||
- API 调用时长
|
||||
|
||||
## 目录结构
|
||||
|
||||
```
|
||||
claude-code-源码/
|
||||
├── src/
|
||||
│ ├── main.tsx # CLI 入口
|
||||
│ ├── QueryEngine.ts # 查询引擎
|
||||
│ ├── Tool.ts # 工具基类
|
||||
│ ├── commands.ts # 命令注册
|
||||
│ ├── context.ts # 上下文收集
|
||||
│ ├── cost-tracker.ts # 成本追踪
|
||||
│ ├── query.ts # 查询管道
|
||||
│ ├── tools/ # 工具实现
|
||||
│ │ ├── BashTool/
|
||||
│ │ ├── FileReadTool/
|
||||
│ │ ├── FileEditTool/
|
||||
│ │ ├── AgentTool/
|
||||
│ │ └── ...(其他工具)
|
||||
│ └── ...(其他模块)
|
||||
└── package.json
|
||||
```
|
||||
|
||||
## 扩展阅读
|
||||
|
||||
- 深入理解工具系统请阅读 `03-工具系统.md`
|
||||
- 深入理解核心模块请阅读 `02-核心模块详解.md`
|
||||
- 架构概览请阅读 `01-架构总览.md`
|
||||
Reference in New Issue
Block a user