返回

Claude Code 源码分析 7:State 状态管理与持久化

深入分析 Claude Code 的 State 状态管理与持久化机制,包括应用状态、会话存储、任务状态、设置管理和数据持久化策略。

本章概述

系列目录:Claude Code 源码分析系列索引

State 管理是 Claude Code 的核心基础设施,负责会话状态、应用配置、任务数据的存储和持久化。

你将学到

  • ✅ 状态管理架构设计
  • ✅ 会话存储与恢复
  • ✅ 任务状态管理
  • ✅ 设置持久化
  • ✅ 数据备份策略

状态管理概览

flowchart TB
    subgraph StateTypes["状态类型"]
        A[AppState] --> B[会话状态]
        A --> C[工具权限]
        A --> D[UI 状态]
        E[持久化状态] --> F[会话存储]
        E --> G[设置配置]
        E --> H[任务列表]
    end
    
    subgraph Storage["存储层"]
        I[内存] --> J[磁盘 JSON]
        J --> K[Git Worktree]
    end
    
    subgraph Sync["同步机制"]
        L[自动保存] --> M[定期备份]
        N[事件触发] --> O[变化监听]
    end

核心文件结构

src/
├── state/                      # 状态管理
│   ├── AppState.tsx           # 应用状态 Provider
│   ├── AppStateStore.ts       # Store 定义
│   └── store.ts               # Store 实现
├── utils/sessionStorage.ts    # 会话存储
├── utils/settings/            # 设置管理
│   ├── settings.ts
│   └── settingsCache.ts
└── utils/tasks.ts             # 任务状态

应用状态(AppState)

状态定义

// state/AppStateStore.ts
export type AppState = {
  // 会话状态
  messages: Message[]
  sessionId: string
  isLoading: boolean
  
  // 工具权限上下文
  toolPermissionContext: ToolPermissionContext
  
  // UI 状态
  theme: ThemeName
  spinnerMode: SpinnerMode
  
  // 上下文信息
  context: ContextInfo
  
  // 成本追踪
  costTracker: CostTrackerState
}

export function getDefaultAppState(): AppState {
  return {
    messages: [],
    sessionId: generateSessionId(),
    isLoading: false,
    toolPermissionContext: getDefaultToolPermissionContext(),
    theme: 'default',
    spinnerMode: 'normal',
    context: getDefaultContext(),
    costTracker: getDefaultCostTracker()
  };
}

Store 实现

// state/store.ts
export type AppStateStore = {
  getState: () => AppState
  setState: (updater: (prev: AppState) => AppState) => void
  subscribe: (listener: () => void) => () => void
}

export function createStore(
  initialState: AppState,
  onChange?: OnChangeCallback
): AppStateStore {
  let state = initialState;
  const listeners = new Set<() => void>();
  
  return {
    getState: () => state,
    
    setState: (updater) => {
      const newState = updater(state);
      const oldState = state;
      state = newState;
      
      // 通知所有监听器
      listeners.forEach(listener => listener());
      
      // 触发变化回调
      onChange?.({ newState, oldState });
    },
    
    subscribe: (listener) => {
      listeners.add(listener);
      return () => listeners.delete(listener);
    }
  };
}

React 集成

// state/AppState.tsx
export const AppStoreContext = React.createContext<AppStateStore | null>(null);

export function AppStateProvider({ children, initialState }: Props) {
  const [store] = useState(() => 
    createStore(initialState ?? getDefaultAppState())
  );
  
  return (
    <AppStoreContext.Provider value={store}>
      {children}
    </AppStoreContext.Provider>
  );
}

export function useAppStore(): AppStateStore {
  const store = useContext(AppStoreContext);
  if (!store) {
    throw new Error('useAppStore must be used within AppStateProvider');
  }
  return store;
}

export function useAppState<T>(selector: (state: AppState) => T): T {
  const store = useAppStore();
  const [value, setValue] = useState(() => selector(store.getState()));
  
  useEffect(() => {
    return store.subscribe(() => {
      setValue(selector(store.getState()));
    });
  }, [store, selector]);
  
  return value;
}

会话存储

会话数据结构

// utils/sessionStorage.ts
export type SessionData = {
  sessionId: string
  title?: string
  messages: Message[]
  createdAt: number
  updatedAt: number
  metadata?: SessionMetadata
}

export type SessionMetadata = {
  workingDirectory: string
  gitBranch?: string
  gitCommit?: string
  agentSettings?: AgentSettings
}

会话存储实现

// utils/sessionStorage.ts
const SESSIONS_DIR = path.join(CLAUDE_DIR, 'sessions');

export async function saveSession(session: SessionData): Promise<void> {
  const sessionPath = getSessionPath(session.sessionId);
  
  // 更新元数据
  const data: SessionData = {
    ...session,
    updatedAt: Date.now()
  };
  
  // 写入文件
  await writeFile(
    sessionPath,
    JSON.stringify(data, null, 2)
  );
  
  // 更新索引
  await updateSessionIndex(data);
}

export async function loadSession(
  sessionId: string
): Promise<SessionData | null> {
  const sessionPath = getSessionPath(sessionId);
  
  try {
    const content = await readFile(sessionPath, 'utf-8');
    return JSON.parse(content);
  } catch (error) {
    if (isFileNotFoundError(error)) {
      return null;
    }
    throw error;
  }
}

export async function listSessions(): Promise<SessionSummary[]> {
  const index = await loadSessionIndex();
  return index.sessions
    .sort((a, b) => b.updatedAt - a.updatedAt);
}

会话恢复

// utils/conversationRecovery.ts
export async function loadConversationForResume(
  sessionId: string
): Promise<ResumeData | null> {
  const session = await loadSession(sessionId);
  if (!session) {
    return null;
  }
  
  // 恢复应用状态
  const appState = getDefaultAppState();
  appState.messages = session.messages;
  appState.sessionId = sessionId;
  
  // 恢复上下文
  if (session.metadata) {
    await restoreContext(session.metadata);
  }
  
  return {
    appState,
    sessionId,
    title: session.title
  };
}

任务状态管理

任务定义

// utils/tasks.ts
export type Task = {
  id: string
  content: string
  status: TaskStatus
  owner?: AgentId
  createdAt: number
  updatedAt: number
  metadata?: TaskMetadata
}

export type TaskStatus = 
  | 'pending'
  | 'in_progress' 
  | 'completed'
  | 'blocked'
  | 'cancelled'

export type TaskList = {
  id: string
  tasks: Task[]
  updatedAt: number
}

export const DEFAULT_TASKS_MODE_TASK_LIST_ID = 'default';
export const TASK_STATUSES = {
  PENDING: 'pending',
  IN_PROGRESS: 'in_progress',
  COMPLETED: 'completed',
  BLOCKED: 'blocked',
  CANCELLED: 'cancelled'
} as const;

任务存储

// utils/tasks.ts
const TASKS_FILE = path.join(CLAUDE_DIR, 'tasks.json');

export async function loadTaskList(
  listId: string = DEFAULT_TASKS_MODE_TASK_LIST_ID
): Promise<TaskList> {
  try {
    const content = await readFile(TASKS_FILE, 'utf-8');
    const lists = JSON.parse(content);
    return lists[listId] || createDefaultTaskList(listId);
  } catch (error) {
    return createDefaultTaskList(listId);
  }
}

export async function saveTaskList(list: TaskList): Promise<void> {
  const lists = await loadAllTaskLists();
  lists[list.id] = {
    ...list,
    updatedAt: Date.now()
  };
  
  await writeFile(TASKS_FILE, JSON.stringify(lists, null, 2));
}

任务更新

// tools/TodoWriteTool/TodoWriteTool.ts
export async function updateTasks(
  listId: string,
  updates: TaskUpdate[]
): Promise<void> {
  const list = await loadTaskList(listId);
  
  for (const update of updates) {
    const index = list.tasks.findIndex(t => t.id === update.id);
    
    if (index >= 0) {
      // 更新现有任务
      list.tasks[index] = {
        ...list.tasks[index],
        ...update,
        updatedAt: Date.now()
      };
    } else {
      // 创建新任务
      list.tasks.push({
        id: update.id,
        content: update.content,
        status: update.status || 'pending',
        createdAt: Date.now(),
        updatedAt: Date.now()
      });
    }
  }
  
  await saveTaskList(list);
}

设置管理

设置定义

// utils/settings/types.ts
export type Settings = {
  // 编辑器设置
  editor: {
    theme: ThemeName
    fontSize: number
    tabSize: number
  }
  
  // 代理设置
  agent: {
    model: string
    effort: EffortValue
    permissionMode: PermissionMode
  }
  
  // MCP 设置
  mcp: {
    servers: Record<string, McpServerConfig>
    enabled: boolean
  }
  
  // 插件设置
  plugins: {
    enabled: string[]
    disabled: string[]
  }
}

export type SettingSource = 
  | 'default'
  | 'user'
  | 'project'
  | 'managed'
  | 'cli'

设置层级

设置优先级(从高到低):
1. CLI 参数
2. 项目设置 (.claude/settings.json)
3. 用户设置 (~/.claude/settings.json)
4. 管理设置 (远程配置)
5. 默认设置

设置加载

// utils/settings/settings.ts
export async function getInitialSettings(): Promise<Settings> {
  // 从各层级加载设置
  const defaultSettings = getDefaultSettings();
  const userSettings = await loadUserSettings();
  const projectSettings = await loadProjectSettings();
  const managedSettings = await loadManagedSettings();
  
  // 合并设置(高优先级覆盖低优先级)
  return mergeSettings(
    defaultSettings,
    userSettings,
    projectSettings,
    managedSettings
  );
}

export async function loadUserSettings(): Promise<Partial<Settings>> {
  const settingsPath = path.join(CLAUDE_HOME, 'settings.json');
  
  try {
    const content = await readFile(settingsPath, 'utf-8');
    return JSON.parse(content);
  } catch {
    return {};
  }
}

export async function loadProjectSettings(): Promise<Partial<Settings>> {
  const settingsPath = path.join(process.cwd(), '.claude', 'settings.json');
  
  try {
    const content = await readFile(settingsPath, 'utf-8');
    return JSON.parse(content);
  } catch {
    return {};
  }
}

设置变更

// utils/settings/applySettingsChange.ts
export async function applySettingsChange(
  source: SettingSource,
  updater: (settings: Settings) => Settings
): Promise<void> {
  // 获取当前设置
  const current = await getSettings();
  
  // 应用变更
  const updated = updater(current);
  
  // 验证设置
  const validation = validateSettings(updated);
  if (!validation.valid) {
    throw new SettingsValidationError(validation.errors);
  }
  
  // 保存到对应层级
  await saveSettings(source, updated);
  
  // 触发变更事件
  emitSettingsChange(source, current, updated);
}

数据备份策略

自动备份

// utils/backup.ts
const BACKUP_DIR = path.join(CLAUDE_DIR, 'backups');
const MAX_BACKUPS = 10;

export async function createBackup(): Promise<string> {
  const timestamp = new Date().toISOString();
  const backupPath = path.join(BACKUP_DIR, timestamp);
  
  // 备份会话
  await backupSessions(backupPath);
  
  // 备份设置
  await backupSettings(backupPath);
  
  // 清理旧备份
  await cleanupOldBackups();
  
  return backupPath;
}

async function cleanupOldBackups(): Promise<void> {
  const backups = await listBackups();
  
  if (backups.length > MAX_BACKUPS) {
    const toDelete = backups
      .sort((a, b) => a.createdAt - b.createdAt)
      .slice(0, backups.length - MAX_BACKUPS);
    
    for (const backup of toDelete) {
      await removeDirectory(backup.path);
    }
  }
}

会话归档

// utils/sessionStorage.ts
export async function archiveOldSessions(
  maxAgeDays: number = 30
): Promise<number> {
  const sessions = await listSessions();
  const cutoff = Date.now() - maxAgeDays * 24 * 60 * 60 * 1000;
  
  let archived = 0;
  for (const session of sessions) {
    if (session.updatedAt < cutoff) {
      await archiveSession(session.sessionId);
      archived++;
    }
  }
  
  return archived;
}

最佳实践

1. 状态更新模式

// ✅ 使用函数式更新
store.setState(prev => ({
  ...prev,
  messages: [...prev.messages, newMessage]
}));

// ❌ 避免直接修改
const state = store.getState();
state.messages.push(newMessage); // 错误!

2. 选择性订阅

// ✅ 只订阅需要的部分
const messages = useAppState(state => state.messages);

// ❌ 避免订阅整个状态
const state = useAppState(state => state); // 性能差

3. 错误处理

// ✅ 健壮的状态加载
try {
  const session = await loadSession(sessionId);
  if (!session) {
    return createNewSession();
  }
  return session;
} catch (error) {
  logError('Failed to load session', error);
  return createNewSession();
}

小结

本章分析了 Claude Code 的 State 状态管理:

核心概念

概念 说明 应用场景
Store 状态容器 应用状态管理
Session 会话数据 对话持久化
Tasks 任务列表 任务追踪
Settings 设置配置 用户偏好
Backup 备份策略 数据安全

架构优势

  1. 集中管理 - Store 模式统一状态
  2. 类型安全 - TypeScript 保障
  3. 持久化 - 自动保存到磁盘
  4. 可恢复 - 会话恢复机制

学习收获

  • 📦 状态管理 - Store 模式实践
  • 💾 持久化 - 数据存储策略
  • 🔄 状态同步 - 自动保存机制
  • 🛡️ 数据安全 - 备份与恢复

系列导航

参考资源