目录
  1. 1. 一、状态分层架构
  2. 2. 二、Layer 1: 进程级全局状态 (bootstrap/state.ts)
    1. 2.1. 2.1 为什么需要进程级状态?
    2. 2.2. 2.2 核心字段
    3. 2.3. 2.3 访问模式
  3. 3. 三、Layer 2: AppState Store
    1. 3.1. 3.1 Store 实现
    2. 3.2. 3.2 状态变更监听
    3. 3.3. 3.3 选择器 (Selectors)
  4. 4. 四、Layer 3: React Hooks
    1. 4.1. 4.1 常用 hooks 分类
    2. 4.2. 4.2 useCanUseTool — 权限检查 Hook
  5. 5. 五、数据流图
  6. 6. 六、信号系统 (utils/signal.ts)
  7. 7. 七、配置系统 (utils/config.ts)
  8. 8. 八、文件状态缓存
  9. 9. 涉及源文件
【Claude Code源码剖析】07-状态管理系统

⚠️ 学习声明:本文档基于 Claude Code 2.1.88 源码分析整理,仅供个人学习研究使用,不做任何商业用途。

Claude Code 采用三层状态管理:进程级全局 → Store → React Hooks。


一、状态分层架构

┌─────────────────────────────────────────┐
│ Layer 3: React Hooks (组件级) │
│ useState, useEffect, custom hooks │
│ ↕ 单向数据流 │
│ │
│ Layer 2: AppState Store (应用级) │
│ createStore<AppState>() │
│ ↕ 发布/订阅 │
│ │
│ Layer 1: bootstrap/state.ts (进程级) │
│ 模块闭包中的全局单例 │
│ getter/setter 函数 │
└─────────────────────────────────────────┘

二、Layer 1: 进程级全局状态 (bootstrap/state.ts)

2.1 为什么需要进程级状态?

多个场景需要在 React 组件树 外部 访问状态:

  • SDK 模式(无 React)
  • 子 Agent 进程
  • API 调用层
  • 工具执行层
  • OpenTelemetry 遥测

2.2 核心字段

type State = {
// 会话标识
sessionId: SessionId;
originalCwd: string;
projectRoot: string;

// 成本统计
totalCostUSD: number;
totalAPIDuration: number;
totalInputTokens: number;
totalOutputTokens: number;
modelUsage: { [modelName: string]: ModelUsage };

// 模型配置
mainLoopModelOverride: ModelSetting | undefined;
initialMainLoopModel: ModelSetting;

// 运行模式
isInteractive: boolean;
kairosActive: boolean; // Assistant 模式
clientType: string; // 'cli' | 'sdk' | ...
sessionSource: string; // 触发来源

// 遥测
meter: Meter | null; // OpenTelemetry
sessionCounter: AttributedCounter | null;
costCounter: AttributedCounter | null;

// 功能开关
sdkBetas: string[];
allowedChannels: ChannelEntry[];

// Hook 系统
registeredHooks: Map<string, RegisteredHookMatcher[]>;
}

2.3 访问模式

// 只通过导出的 getter/setter 访问,不暴露 state 对象本身
export function getSessionId(): SessionId { return state.sessionId; }
export function getTotalCostUSD(): number { return state.totalCostUSD; }

export function addToTotalCostState(amount: number): void {
state.totalCostUSD += amount;
}

// 复合操作
export function switchSession(newSessionId: SessionId): void {
state.sessionId = newSessionId;
resetSettingsCache(); // 切换会话时重置缓存
}

三、Layer 2: AppState Store

3.1 Store 实现

// state/store.ts
export function createStore<T>(
initialState: T,
onChange?: OnChange<T>,
): Store<T> {
let state = initialState;
const listeners = new Set<Listener>();

return {
getState: () => state,

setState: (updater: (prev: T) => T) => {
const prev = state;
const next = updater(prev);
if (Object.is(next, prev)) return; // 性能优化:引用相等时跳过
state = next;
onChange?.({ newState: next, oldState: prev });
for (const listener of listeners) listener();
},

subscribe: (listener: Listener) => {
listeners.add(listener);
return () => listeners.delete(listener);
},
};
}

3.2 状态变更监听

// state/onChangeAppState.ts
export function onChangeAppState({
newState,
oldState,
}: { newState: AppState; oldState: AppState }): void {
// 当特定字段变化时触发副作用

// 权限模式变化 → 更新全局配置
if (newState.toolPermissionContext.mode !== oldState.toolPermissionContext.mode) {
updatePermissionModeInConfig(newState.toolPermissionContext.mode);
}

// 模型变化 → 更新遥测属性
if (newState.mainLoopModel !== oldState.mainLoopModel) {
updateTelemetryModel(newState.mainLoopModel);
}

// 任务状态变化 → 通知系统
if (newState.tasks !== oldState.tasks) {
checkForCompletedTasks(newState.tasks, oldState.tasks);
}
}

3.3 选择器 (Selectors)

// state/selectors.ts
// 从 AppState 中提取派生数据

export function getActiveAgentCount(state: AppState): number {
return Array.from(state.tasks.values())
.filter(t => t.type === 'local_agent' && t.status === 'running')
.length;
}

export function getTotalRunningTasks(state: AppState): number {
return Array.from(state.tasks.values())
.filter(t => t.status === 'running')
.length;
}

四、Layer 3: React Hooks

4.1 常用 hooks 分类

数据获取类:

useSettings()               // 获取当前设置
useMainLoopModel() // 获取当前模型
useCostSummary() // 获取费用摘要
useTerminalSize() // 获取终端尺寸
useIdeConnectionStatus() // IDE 连接状态

交互类:

useTextInput()              // 文本输入处理
useVimInput() // Vim 模式输入
useSearchInput() // 搜索输入
useArrowKeyHistory() // 历史导航
useCopyOnSelect() // 选择复制
usePasteHandler() // 粘贴处理

生命周期类:

useExitOnCtrlCD()           // Ctrl+C/D 退出
useCancelRequest() // 取消当前请求
useAfterFirstRender() // 首次渲染后执行
useMinDisplayTime() // 最小显示时间(防闪烁)

集成类:

useReplBridge()             // 远程桥接
useIDEIntegration() // IDE 集成
useMergedClients() // 合并 MCP 客户端
useMergedTools() // 合并工具列表
useManagePlugins() // 插件管理

4.2 useCanUseTool — 权限检查 Hook

// hooks/useCanUseTool.tsx
export default function useCanUseTool(
toolPermissionContext: ToolPermissionContext,
setToolPermissionContext: (updater) => void,
): CanUseToolFn {
return useCallback(async (tool, input, assistantMessage) => {
// 1. 匹配权限规则
const ruleMatch = matchPermissionRules(tool, input, toolPermissionContext);
if (ruleMatch) return ruleMatch;

// 2. 根据权限模式决策
switch (toolPermissionContext.mode) {
case 'bypass': return { behavior: 'allow' };
case 'plan': return tool.isReadOnly() ? { behavior: 'allow' } : { behavior: 'deny' };
case 'auto': return await classifierDecision(tool, input);
case 'default': return { behavior: 'ask' };
}
}, [toolPermissionContext]);
}

五、数据流图

用户操作 (键盘/鼠标)


React Event Handler (REPL.tsx)

├─→ setAppState(prev => ...) → Store 更新
│ │
│ ├─→ onChange() → 副作用
│ └─→ listeners → React 重渲染

├─→ setMessages(prev => ...) → 消息列表更新

└─→ query() → Agentic Loop

├─→ 更新 bootstrap/state (成本/token)
├─→ yield events → 更新 messages
└─→ 工具执行 → 可能修改 AppState

六、信号系统 (utils/signal.ts)

// 轻量级的响应式信号(比 Store 更轻量)
export function createSignal<T>(initialValue: T) {
let value = initialValue;
const subscribers = new Set<(value: T) => void>();

return {
get: () => value,
set: (newValue: T) => {
value = newValue;
for (const sub of subscribers) sub(newValue);
},
subscribe: (fn: (value: T) => void) => {
subscribers.add(fn);
return () => subscribers.delete(fn);
},
};
}

用于不需要 React 重渲染的简单状态(如内部计数器、标志位)。


七、配置系统 (utils/config.ts)

配置来源 (优先级从高到低):
├─ 1. CLI 参数 (--model, --permission-mode, ...)
├─ 2. 环境变量 (ANTHROPIC_API_KEY, CLAUDE_CODE_*)
├─ 3. 项目配置 (.claude/settings.json)
├─ 4. 用户配置 (~/.claude/settings.json)
├─ 5. 企业策略 (MDM / 远程管理)
└─ 6. 默认值
// 配置读取示例
export function getGlobalConfig(): GlobalConfig {
return readJsonSync(GLOBAL_CONFIG_PATH);
}

export function getCurrentProjectConfig(): ProjectConfig {
return readJsonSync(join(cwd, '.claude/settings.json'));
}

// 配置写入
export function saveGlobalConfig(config: GlobalConfig): void {
writeJsonSync(GLOBAL_CONFIG_PATH, config);
}

八、文件状态缓存

// utils/fileStateCache.ts
// 缓存工具读取的文件内容,避免重复读取

type FileStateCache = Map<string, {
content: string;
modifiedTime: number;
encoding: string;
}>;

// 带大小限制的缓存
export function createFileStateCacheWithSizeLimit(
maxSize: number = READ_FILE_STATE_CACHE_SIZE // 默认 1000 个文件
): FileStateCache {
// LRU 策略:满了就淘汰最早的条目
}

// 跨 Agent 的缓存共享
export function mergeFileStateCaches(
parent: FileStateCache,
child: FileStateCache,
): FileStateCache {
// 子 Agent 的缓存合并回父级
}

涉及源文件

  • bootstrap/state.ts
  • utils/config.ts
  • utils/signal.ts
打赏
  • 微信
  • 支付宝

评论