详解Claude Code的状态管理轻量引擎Zustand
Hook用途订阅状态?重渲染?读取并订阅特定字段✅ 是仅当 selector 返回值变化时获取更新函数❌ 否从不(稳定引用)直接访问 store 实例❌ 否从不(稳定引用)精准订阅 = 性能useAppState(s => s.specificField) // 只关心这个字段避免过度订阅 = 性能❌ useAppState(s => s) // 订阅整个状态树✅ 用 useSetAppState
Claude Code 并没有套用流行的第三方状态管理库(如 Zustand、Jotai、Recoil 或 MobX),而是实现了一个自研的轻量级状态管理引擎。这是一个自定义的 Zustand 风格的状态管理方案,特别适合Claude Code 这种长会话、高吞吐、多代理协作的 CLI 应用。
Claude Code 的状态管理基于三个核心文件:
- [`src/state/store.ts`](src/state/store.ts) - 核心状态存储引擎
- [`src/state/AppStateStore.ts`](src/state/AppStateStore.ts) - 应用状态类型定义
- [`src/state/AppState.tsx`](src/state/AppState.tsx) - React 上下文提供者和 hooks
核心架构
概览

其余相关文件为
src/state/onChangeAppState.ts - 状态变更处理器
src/state/teammateViewHelpers.ts - 团队视图状态管理
src/state/selectors.ts - 状态选择器
Claude Code 只用 30 行代码就实现一个完整的状态管理系统,其内核 createStore(状态存储引擎)如下:
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> {
let state = initialState // ← 第1行:闭包状态
const listeners = new Set<Listener>() // ← 第2行:订阅者集合
return {
getState: () => state, // ← 第3行:读取
setState: (updater) => { // ← 第4-12行:写入
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) => { // ← 第13-16行:订阅
listeners.add(listener)
return () => listeners.delete(listener)
},
}
}
没有中间件、没有 devtools、没有异步——只有状态、订阅、通知三个核心概念,
- 状态是数据的存储中心,包含所有应用数据
- 订阅是数据流向的控制机制,决定谁需要知道数据变化
- 通知是数据变化的传播机制,确保所有相关方都能及时响应变化
先看src/state/store.ts核心状态存储引擎状态(State) 的作用
// src/state/store.ts
let state = initialState // 内部可变状态
第 1 行 闭包状态的代码影响着的(src/state/AppStateStore.ts) - 应用状态类型定义中的400+字段,学过c++泛型的应该可以理解,let state = initialState 只是一个泛型变量,可以是任何类型 ,运行时:state 实际上等于 AppState 对象,包含所有字段 , 但代码层面:这里只看到 T,看不到具体字段而store.ts - 不知道也不关心 T 是什么。
400+字段例如:
// src/state/AppStateStore.ts
export type AppState = DeepImmutable<{
settings: SettingsJson // 应用设置
tasks: { [taskId: string]: TaskState } // 任务系统
plugins: { enabled: LoadedPlugin[] } // 插件系统
mcp: { clients: MCPServerConnection[] } // MCP 协议
teamContext?: { teamName: string } // 团队协作
// ... 更多字段
}>
如何理解呢?let state = initialState 是容器(装水的瓶子),400+ 字段是内容物(水)。瓶子不知道里面装的是什么液体,只知道它能装东西;而类型定义描述了液体的具体成分,它们在内存中的关系如下:
内存中的实际状态对象(运行时):
state 变量指向的内存区域:
┌─────────────────────────────────────────────────────────┐
│ AppState 对象(由 getDefaultAppState() 创建) │
├─────────────────────────────────────────────────────────┤
│ settings: ──────► { theme: 'dark', ... } │
│ tasks: ─────────► { "task-1": TaskState, ... } │
│ mcp: ───────────► { clients: [...], tools: [...] } │
│ teamContext: ───► undefined(初始未启用) │
│ // ... 其他 400+ 字段各自有值 │
└─────────────────────────────────────────────────────────┘
▲
│
let state = initialState // 这个变量指向上述对象
Claude Code中更为具体的状态变更触发流程如下:

在具体的代码层面,
为什么用 let 而不是 const?
因为需要可变引用才能实现更新
let state = initialState // ✅ 可以重新赋值
state = next // 原子替换
const state = initialState // ❌ 无法替换
// 如果 state 是对象,只能 mutate:Object.assign(state, next)
// 这会破坏不可变性,导致 bug
┌────────────────────────────────
│ createStore 调用
│ ┌─────────────────────────────┐
│ │ 闭包作用域 (Closure)
│ │
│ │ let state = { count: 0 } │◄────┼── 私有变量,外部无法直接访问
│ │ ↑
│ │ ┌────┴────┐
│ │ │ getState │───► 读取 state
│ │ │ setState │───► 修改 state
│ │ │subscribe │───► 监听变化
│ │ └─────────┘
│ │
│ └─────────────────────────────┘
│ ↑
│ 返回这三个函数
└─────────────────────────────────
核心状态存储引擎第 2 行:const listeners = new Set<Listener>()

为什么用 Set 而不是 Array?
| 特性 | Set |
Array |
|---|---|---|
| 去重 | 自动去重 | 需手动检查 |
| 删除 | O(1) delete |
O(n) splice |
| 查找 | O(1) has |
O(n) indexOf |
| 遍历 | for...of |
for...of |
// 取消订阅时 O(1) 删除
return () => listeners.delete(listener) // Set: 直接删除引用
// 如果是 Array:
return () => {
const idx = listeners.indexOf(listener) // O(n) 查找
if (idx > -1) listeners.splice(idx, 1) // O(n) 移动元素
}
下面是订阅 (Subscribe)
const listeners = new Set<Listener>() // 订阅者集合
subscribe: (listener: Listener) => () => void // 订阅方法

第3 行:getState: () => state
getState: () => state
简单的读取接口
const store = createStore({ count: 0 })
// 直接访问闭包变量
console.log(store.getState()) // { count: 0 }
// 非 React 代码也能用
function logState() {
console.log(store.getState())
}
第 4-12 行:setState —— 核心写入逻辑
setState: (updater) => {
const prev = state // 保存引用用于比较和回调
const next = updater(prev) // 函数式更新:基于 prev 计算 next
if (Object.is(next, prev)) return // 性能优化:无变化短路
state = next // 原子替换引用
onChange?.({ newState: next, oldState: prev }) // 副作用钩子
for (const listener of listeners) listener() // 通知所有订阅者
}
第 4-12 行代码的通知顺序
state = next // 1. 先更新状态
onChange?.({ newState: next, oldState: prev }) // 2. 副作用(同步)
for (const listener of listeners) listener() // 3. 通知 UI(同步)
为什么是同步而非异步?
// Redux 的异步通知(中间件/批处理)
dispatch(action)
→ reducer
→ 加入通知队列
→ 微任务刷新
→ 组件更新
// Zustand 风格同步通知
setState(updater)
→ 立即更新 state
→ 立即执行 onChange
→ 立即遍历 listeners
→ 同步触发 React 的 setState(在事件处理函数内)
优势:可预测、无 stale closure、支持同步读取最新值
第 13-16 行:subscribe —— 订阅系统
subscribe: (listener) => {
listeners.add(listener)
return () => listeners.delete(listener) // 清理函数
}
使用模式:
// React 集成(useSyncExternalStore)
function useAppState<T>(selector: (state: AppState) => T): T {
const store = useContext(AppStoreContext)
return useSyncExternalStore(
store.subscribe, // 直接传入
() => selector(store.getState()), // 获取快照
() => selector(store.getState()) // SSR 快照
)
}
// 非 React 代码
const unsub = store.subscribe(() => {
console.log('State changed:', store.getState())
})
// 稍后...
unsub() // 取消订阅
三者协同工作流程
1. 状态更新流程
// 1. 组件触发状态更新
setAppState(prev => ({
...prev,
statusLineText: 'Processing...'
}))
// 2. store.setState 执行
setState: (updater: (prev: T) => T) => {
const prev = state
const next = updater(prev)
// 3. 检查是否真的变化
if (Object.is(next, prev)) return
// 4. 更新内部状态
state = next
// 5. 触发 onChange 回调(通知外部系统)
onChange?.({ newState: next, oldState: prev })
// 6. 通知所有订阅者
for (const listener of listeners) listener()
}
2. 订阅者响应流程
// React 组件接收到通知
function MyComponent() {
const someValue = useAppState(s => s.someField)
// 当 someField 变化时,useSyncExternalStore 会触发组件重新渲染
useEffect(() => {
// 处理状态变化
}, [someValue])
}
3. 通知链式反应
// 状态变更 → 订阅者更新 → 外部系统同步
1. 用户切换权限模式
2. store.setState 更新状态
3. onChangeAppState 检测到变化
4. 通知 CCR/SDK 同步权限模式
5. 通知设置系统持久化变更
6. 所有订阅该字段的组件重新渲染
7. UI 立即反映最新状态
以上就是核心状态存储引擎的分析,可见有4个特点
┌─────────────────────────────────────────────────────────┐
│ createStore 实现 │
├─────────────────────────────────────────────────────────┤
│ 特点1: 不可变数据更新 │
│ ├── 第4行: updater: (prev: T) => T 类型定义 │
│ └── 第18-19行: const next = updater(prev) 实现 │
├─────────────────────────────────────────────────────────┤
│ 特点2: Object.is 深度相等性检查 │
│ └── 第20行: if (Object.is(next, prev)) return │
├─────────────────────────────────────────────────────────┤
│ 特点3: 状态变更回调 │
│ ├── 第8行: onChange?: OnChange<T> 参数定义 │
│ └── 第22行: onChange?.({ newState, oldState }) 调用 │
├─────────────────────────────────────────────────────────┤
│ 特点4: 内存管理优化(Set存储监听器) │
│ ├── 第11行: new Set<Listener>() 初始化 │
│ ├── 第24行: listeners.add(listener) O(1)添加 │
│ └── 第26行: listeners.delete(listener) O(1)清理 │
└─────────────────────────────────────────────────────────┘
首先就是基于不可变数据更新模式
// 第4行:API设计强制不可变
setState: (updater: (prev: T) => T) => void
// 第18-19行:实现不可变更新
const prev = state // 保存旧引用
const next = updater(prev) // 基于旧状态计算新状态
state = next // 原子替换引用(不是mutate)
使用 `Object.is` 进行深度相等性检查
// 第20行:精确相等判断
if (Object.is(next, prev)) return
状态变更回调
// 第8行:可选回调参数
onChange?: OnChange<T>
// 第22行:状态变更后同步触发
onChange?.({ newState: next, oldState: prev })
Claude Code中的实际使用:
createStore(initialState, ({ newState, oldState }) => {
// 权限模式同步到服务端
if (newState.toolPermissionContext.mode !== oldState.toolPermissionContext.mode) {
notifySessionMetadataChanged({ permission_mode: newMode })
}
// 设置持久化到磁盘
if (newState.settings !== oldState.settings) {
saveSettings(newState.settings)
}
})
内存管理优化(Set存储监听器)
// 第11行:Set存储(自动去重)
const listeners = new Set<Listener>()
// 第24行:O(1)添加
listeners.add(listener)
// 第26行:O(1)删除(自动清理,防止内存泄漏)
return () => listeners.delete(listener)
完整数据流图解
┌─────────────┐ setState(updater) ┌─────────────┐
│ 用户交互 │ ──────────────────────────► │ │
│ (点击/输入) │ │ 闭包状态 │
└─────────────┘ │ (state) │
│ │
┌─────────────┐ getState() │ │
│ 外部系统 │ ◄─────────────────────────│ │
│ (API/定时器)│ └──────┬──────┘
└─────────────┘ │
│
┌────────────────────────┘
│
▼
┌─────────────────────┐
│ const prev = state │
│ const next = updater(prev) │
│ if (Object.is(next, prev)) return │
│ state = next ◄── 原子替换 │
└─────────────────────┘
│
┌─────────────┼─────────────┐
▼ ▼ ▼
┌─────────┐ ┌─────────┐ ┌──────────┐
│ onChange │ │listeners│ │ 其他逻辑 │
│ (副作用) │ │ (Set) │ │ │
└────┬────┘ └───┬─────┘ └──────────┘
│ │
▼ ▼
┌────────────┐ ┌────────────┐
│持久化到磁盘 │ │ 遍历执行 │
│同步到服务端 │ │ for...of │
│日志记录 │ │ │
└────────────┘ └─────┬──────┘
│
┌───────────┼───────────┐
▼ ▼ ▼
┌───────┐ ┌───────┐ ┌───────┐
│组件 A │ │组件 B │ │组件 C │
│重渲染 │ │重渲染 │ │重渲染 │
└───────┘ └───────┘ └───────┘
2. React 集成层详解
- [`src/state/AppState.tsx`](src/state/AppState.tsx) - React 上下文提供者和 hooks
- 提供
AppStateProvider上下文提供者 - 三个核心 hooks:
useAppState(选择性订阅)、useSetAppState(状态更新)、useAppStateStore(直接访问 store) - 使用
useSyncExternalStore实现高效的订阅机制
用最直观的方式解释 AppState.tsx 中的 React 集成层。这个文件是连接"存储引擎"和"React 组件"的桥梁。
完整体架构图解
┌─────────────────────────────────────────────────────────────────┐
│ React 应用层 │
│ ┌─────────────┐ ┌─────────────┐ ┌─────────────────────────┐ │
│ │ ComponentA │ │ ComponentB │ │ ComponentC │ │
│ │ │ │ │ │ │ │
│ │ const text = │ │ const mode =│ │ const update = │ │
│ │ useAppState( │ │ useAppState│ │ useSetAppState() │ │
│ │ s=>s.text) │ │(s=>s.mode) │ │ │ │
│ │ ↓ │ │ ↓ │ │ ↓ │ │
│ │ 自动重渲染 │ │ 自动重渲染 │ │ 获取更新函数,不监听 │ │
│ └─────────────┘ └─────────────┘ └─────────────────────────┘ │
│ │ │ │ │
│ └──────────────┼──────────────────────┘ │
│ ▼ │
│ ╔═══════════════════════════════════════════════════════════╗ │
│ ║ AppState.tsx (本文件) ║ │
│ ║ ┌─────────────────────────────────────────────────────┐ ║ │
│ ║ │ 1. AppStateProvider: 创建 store 并提供给子树 │ ║ │
│ ║ │ 2. useAppState: 选择性订阅特定状态字段 │ ║ │
│ ║ │ 3. useSetAppState: 只获取更新函数,不订阅 │ ║ │
│ ║ │ 4. useAppStateStore: 直接获取 store 实例 │ ║ │
│ ║ └─────────────────────────────────────────────────────┘ ║ │
│ ╚═══════════════════════════════════════════════════════════╝ │
│ │ │
│ ▼ 使用 createStore() │
│ ┌───────────────────────────────────────────────────────────┐ │
│ │ store.ts (存储引擎) │ │
│ │ let state = initialState │ │
│ │ const listeners = new Set() │ │
│ │ getState / setState / subscribe │ │
│ └───────────────────────────────────────────────────────────┘ │
└─────────────────────────────────────────────────────────────────┘
三个核心 Hook 详解
1. useAppState —— 选择性订阅(最常用)
// 使用方式
const statusLineText = useAppState(s => s.statusLineText)
const permissionMode = useAppState(s => s.toolPermissionContext.mode)
内部实现原理:
export function useAppState<T>(selector: (state: AppState) => T): T {
const store = useAppStore() // 从 Context 获取 store 实例
// 创建 getSnapshot 函数:获取当前选中的状态片段
const get = () => {
const state = store.getState() // 获取完整状态
const selected = selector(state) // 执行选择器,提取需要的字段
return selected
}
// 🔑 核心:useSyncExternalStore 处理订阅和优化
return useSyncExternalStore(
store.subscribe, // 订阅函数:状态变化时通知 React
get, // 客户端获取快照
get // SSR 获取快照(这里相同)
)
}
useSyncExternalStore 的作用:
传统 useState + useEffect 的问题:
┌─────────────────────────────────────────┐
│ useEffect(() => { │
│ const unsub = store.subscribe(() => { │
│ setState(store.getState()) // ❌ 获取完整状态,不精准 │
│ }) │
│ return unsub │
│ }, []) │
│ │
│ 问题1: 任何字段变化都触发重渲染 │
│ 问题2: 订阅建立有延迟(useEffect 在渲染后)│
│ 问题3: 并发渲染可能出现 tearing(状态不一致)│
└─────────────────────────────────────────┘
useSyncExternalStore 的优势:
┌─────────────────────────────────────────┐
│ return useSyncExternalStore( │
│ store.subscribe, │
│ () => selector(store.getState()) │
│ ) │
│ │
│ 解决1: React 自动对比 selector 返回值 │
│ Object.is(prev, next) 不同才重渲染 │
│ │
│ 解决2: 订阅在渲染阶段同步建立 │
│ 无延迟,立即可用 │
│ │
│ 解决3: 内置 tearing 保护 │
│ 并发渲染时保证状态一致性 │
└─────────────────────────────────────────┘
精准订阅的工作流程:
状态对象:
{
statusLineText: "Ready", // ← ComponentA 订阅
toolPermissionContext: {
mode: "default" // ← ComponentB 订阅
},
tasks: {...} // ← 无人订阅
}
状态变化:tasks 更新了
│
▼
store.setState(prev => ({...prev, tasks: newTasks}))
│
▼
触发所有 listeners(包括 A 和 B 的)
│
├─────────────────┬─────────────────┐
▼ ▼ ▼
ComponentA ComponentB ComponentC
(订阅 statusLine) (订阅 mode) (无订阅)
│ │ │
▼ ▼ ▼
get() 执行 get() 执行 不执行
selector(s=>s. selector(s=>s.
statusLineText) toolPermissionContext.mode)
│ │
▼ ▼
返回 "Ready" 返回 "default"
(和上次相同) (和上次相同)
│ │
▼ ▼
Object.is("Ready", Object.is("default",
"Ready") === true "default") === true
│ │
▼ ▼
React 跳过重渲染 React 跳过重渲染
✅ 只有真正使用 tasks 的组件会重渲染(如果有的话)
2. useSetAppState —— 只更新,不订阅
// 使用方式
const setAppState = useSetAppState()
// 在事件处理中使用
const handleClick = () => {
setAppState(prev => ({...prev, count: prev.count + 1}))
}
为什么需要这个 Hook?
export function useSetAppState() {
return useAppStore().setState // 直接返回 setState 函数
}
// 关键特性:不调用 useSyncExternalStore
// 所以这个组件不会因为状态变化而重渲染!
使用场景对比:
❌ 错误:用 useAppState 获取更新函数
const setAppState = useAppState(s => s.setState) // 不存在!
// 而且这会订阅整个状态树,任何变化都重渲染
✅ 正确:useSetAppState
const setAppState = useSetAppState()
// 只获取函数,不建立订阅
// 组件永远不因状态变化重渲染
典型应用场景:
// 按钮组件:只需要发送命令,不需要显示状态
function IncrementButton() {
const setAppState = useSetAppState() // 稳定引用,永不变化
return (
<button onClick={() => setAppState(prev => ({
...prev,
count: prev.count + 1
}))}>
+1
</button>
)
}
// 这个组件只渲染一次,之后永远不重渲染(因为没订阅任何状态)
3. useAppStateStore —— 直接访问 store
// 使用方式
const store = useAppStateStore()
// 可以在非 React 代码中使用
useEffect(() => {
const timer = setInterval(() => {
const currentState = store.getState() // 直接读取
console.log(currentState.statusLineText)
}, 1000)
return () => clearInterval(timer)
}, [store])
用途:
1. 传递给非 React 代码(工具函数、类实例)
const api = new ApiClient(store)
2. 在 useEffect 中读取最新状态(不订阅)
useEffect(() => {
const state = store.getState()
// 基于当前状态执行副作用
}, [dependency])
3. 手动控制订阅(高级场景)
useEffect(() => {
return store.subscribe(() => {
// 自定义逻辑,不触发 React 重渲染
})
}, [store])
AppStateProvider 详解
export function AppStateProvider({
children,
initialState,
onChangeAppState
}) {
// 🔒 防止嵌套(一个应用只能有一个 store)
const hasAppStateContext = useContext(HasAppStateContext)
if (hasAppStateContext) {
throw new Error("AppStateProvider can not be nested...")
}
// 🏭 创建 store(只执行一次)
const [store] = useState(() =>
createStore(initialState ?? getDefaultAppState(), onChangeAppState)
)
// 🎧 设置变更监听(文件监视器等)
useEffect(() => {
const { toolPermissionContext } = store.getState()
if (shouldDisableBypassMode(toolPermissionContext)) {
store.setState(prev => /* 禁用 bypass 模式 */)
}
}, [])
// 🌳 提供上下文
return (
<HasAppStateContext.Provider value={true}>
<AppStoreContext.Provider value={store}>
<MailboxProvider>
<VoiceProvider>{children}</VoiceProvider>
</MailboxProvider>
</AppStoreContext.Provider>
</HasAppStateContext.Provider>
)
}
Context 嵌套结构:
<HasAppStateContext.Provider value={true}> ← 标记"已有 Provider"
<AppStoreContext.Provider value={store}> ← 实际 store 实例
<MailboxProvider> ← 邮件上下文
<VoiceProvider> ← 语音上下文(可选)
{children} ← 你的应用组件
</VoiceProvider>
</MailboxProvider>
</AppStoreContext.Provider>
</HasAppStateContext.Provider>
完整使用示例
// 1. 在应用入口包裹 Provider
function App() {
return (
<AppStateProvider>
<MainLayout />
</AppStateProvider>
)
}
// 2. 在组件中订阅状态
function StatusBar() {
// ✅ 精准订阅:只监听这两个字段
const statusText = useAppState(s => s.statusLineText)
const isConnected = useAppState(s => s.replBridgeConnected)
return (
<div className={isConnected ? 'green' : 'red'}>
{statusText}
</div>
)
}
// 3. 只更新不订阅的组件
function RefreshButton() {
// ✅ 稳定引用,不触发重渲染
const setAppState = useSetAppState()
return (
<button onClick={() => setAppState(prev => ({
...prev,
lastRefresh: Date.now()
}))}>
Refresh
</button>
)
}
// 4. 直接操作 store(高级)
function AutoSave() {
const store = useAppStateStore()
useEffect(() => {
const interval = setInterval(() => {
const state = store.getState()
localStorage.setItem('draft', JSON.stringify(state.draft))
}, 5000)
return () => clearInterval(interval)
}, [store])
return null
}
总结:三个 Hook 的选择指南
| Hook | 用途 | 订阅状态? | 重渲染? |
|---|---|---|---|
useAppState(selector) |
读取并订阅特定字段 | ✅ 是 | 仅当 selector 返回值变化时 |
useSetAppState() |
获取更新函数 | ❌ 否 | 从不(稳定引用) |
useAppStateStore() |
直接访问 store 实例 | ❌ 否 | 从不(稳定引用) |
核心设计原则:
精准订阅 = 性能
useAppState(s => s.specificField) // 只关心这个字段
避免过度订阅 = 性能
❌ useAppState(s => s) // 订阅整个状态树
✅ 用 useSetAppState 获取更新函数
useSyncExternalStore = 安全
处理并发渲染、SSR、状态一致性
参考相关资料阅读1
- [`src/state/AppStateStore.ts`](src/state/AppStateStore.ts) - 应用状态类型定义
Claude Code 的状态类型非常复杂,包含400+字段:
┌─────────────────────────────────────────────────────────────────────────┐
│ AppState 核心架构 │
├─────────────────────────────────────────────────────────────────────────┤
│ 1. 模型与设置 (Model & Settings) │
│ ├── settings: SettingsJson # 用户配置 │
│ ├── mainLoopModel: ModelSetting # 当前主模型 │
│ ├── mainLoopModelForSession: ModelSetting # 会话级模型覆盖 │
│ ├── thinkingEnabled: boolean # 深度思考模式 │
│ ├── effortValue: EffortValue # 工作量/复杂度设置 │
│ └── kairosEnabled: boolean # AI助手模式开关 │
├─────────────────────────────────────────────────────────────────────────┤
│ 2. 任务系统 (Task System) │
│ ├── tasks: { [taskId: string]: TaskState } # 所有任务字典 │
│ ├── foregroundedTaskId: string # 前台显示的任务 │
│ ├── viewingAgentTaskId: string # 正在查看的队友任务 │
│ ├── coordinatorTaskIndex: number # 协调器面板选择索引 │
│ ├── agentNameRegistry: Map<string, AgentId> # 代理名称映射 │
│ └── agentDefinitions: AgentDefinitionsResult # 代理定义列表 │
├─────────────────────────────────────────────────────────────────────────┤
│ 3. 权限与安全 (Permissions & Security) │
│ ├── toolPermissionContext: ToolPermissionContext # 工具权限上下文 │
│ ├── denialTracking: DenialTrackingState # 拒绝追踪(YOLO模式) │
│ ├── workerSandboxPermissions.queue # 沙箱权限请求队列 │
│ ├── pendingWorkerRequest # 待处理的工具权限请求 │
│ └── pendingSandboxRequest # 待处理的沙箱权限请求 │
├─────────────────────────────────────────────────────────────────────────┤
│ 4. 远程与会话 (Remote & Session) │
│ ├── remoteSessionUrl: string # 远程会话URL │
│ ├── remoteConnectionStatus # 连接状态 │
│ ├── remoteBackgroundTaskCount: number # 远程后台任务数 │
│ ├── replBridgeEnabled: boolean # 桥接模式开关 │
│ ├── replBridgeConnected: boolean # 桥接连接状态 │
│ ├── replBridgeSessionActive: boolean # 会话激活状态 │
│ ├── replBridgeSessionUrl: string # claude.ai 会话URL │
│ ├── ultraplanSessionUrl: string # Ultraplan 会话URL │
│ ├── ultraplanLaunching: boolean # 是否正在启动 │
│ └── isUltraplanMode: boolean # 是否处于Ultraplan模式 │
├─────────────────────────────────────────────────────────────────────────┤
│ 5. MCP/插件系统 (MCP & Plugins) │
│ ├── mcp.clients: MCPServerConnection[] # MCP服务器连接 │
│ ├── mcp.tools: Tool[] # 可用工具列表 │
│ ├── mcp.commands: Command[] # MCP命令 │
│ ├── mcp.resources # 服务器资源 │
│ ├── plugins.enabled: LoadedPlugin[] # 已启用插件 │
│ ├── plugins.disabled: LoadedPlugin[] # 已禁用插件 │
│ ├── plugins.errors: PluginError[] # 插件错误 │
│ └── plugins.needsRefresh: boolean # 需要刷新标记 │
├─────────────────────────────────────────────────────────────────────────┤
│ 6. UI/视图状态 (UI & View State) │
│ ├── expandedView # 展开视图(tasks/teammates) │
│ ├── viewSelectionMode # 视图选择模式 │
│ ├── footerSelection # 底部栏选中项 │
│ ├── isBriefOnly: boolean # 简洁模式 │
│ ├── statusLineText: string # 状态栏文本 │
│ ├── spinnerTip: string # 加载提示 │
│ ├── activeOverlays # 活跃弹窗集合(Esc键协调) │
│ ├── verbose: boolean # 详细日志模式 │
│ └── showTeammateMessagePreview # 队友消息预览 │
├─────────────────────────────────────────────────────────────────────────┤
│ 7. 团队/多代理 (Team & Multi-Agent) │
│ ├── teamContext # 团队上下文(swarm模式) │
│ │ ├── teamName # 团队名称 │
│ │ ├── leadAgentId # 队长ID │
│ │ ├── selfAgentId # 自身ID(队员) │
│ │ ├── isLeader: boolean # 是否为队长 │
│ │ └── teammates # 队友列表 │
│ └── standaloneAgentContext # 独立代理上下文(非swarm) │
├─────────────────────────────────────────────────────────────────────────┤
│ 8. 终端/Tmux集成 (Terminal Integration) │
│ ├── tungstenActiveSession # 当前tmux会话 │
│ ├── tungstenLastCapturedTime # 最后截图时间 │
│ ├── tungstenLastCommand # 最后发送的命令 │
│ ├── tungstenPanelVisible # 面板可见性 │
│ └── tungstenPanelAutoHidden # 自动隐藏标记 │
├─────────────────────────────────────────────────────────────────────────┤
│ 9. 浏览器工具 (WebBrowser Tool - "Bagel") │
│ ├── bagelActive: boolean # 浏览器是否活跃 │
│ ├── bagelUrl: string # 当前页面URL │
│ └── bagelPanelVisible: boolean # 浏览器面板可见性 │
├─────────────────────────────────────────────────────────────────────────┤
│ 10. 计算机使用MCP (Computer Use MCP - "Chicago") │
│ └── computerUseMcpState # 屏幕控制状态 │
│ ├── allowedApps # 允许的应用列表 │
│ ├── grantFlags # 剪贴板/系统键权限 │
│ ├── lastScreenshotDims # 最后截图尺寸 │
│ └── selectedDisplayId # 选中的显示器 │
├─────────────────────────────────────────────────────────────────────────┤
│ 11. 输入与建议 (Input & Suggestions) │
│ ├── promptSuggestion # 输入建议状态 │
│ │ ├── text # 建议文本 │
│ │ ├── promptId # 建议类型 │
│ │ ├── shownAt # 显示时间戳 │
│ │ └── acceptedAt # 接受时间戳 │
│ ├── speculation # 推测执行状态 │
│ │ ├── status # idle/active │
│ │ ├── messagesRef # 消息引用(可变优化) │
│ │ └── abort # 取消函数 │
│ └── speculationSessionTimeSavedMs # 节省时间统计 │
├─────────────────────────────────────────────────────────────────────────┤
│ 12. 通知与消息 (Notifications & Messaging) │
│ ├── notifications.current # 当前通知 │
│ ├── notifications.queue # 通知队列 │
│ ├── inbox.messages # 收件箱消息 │
│ └── elicitation.queue # 请求澄清队列 │
├─────────────────────────────────────────────────────────────────────────┤
│ 13. 文件与历史 (File & History) │
│ ├── fileHistory # 文件历史快照 │
│ └── attribution # 代码归属状态 │
├─────────────────────────────────────────────────────────────────────────┤
│ 14. 待办事项 (Todos) │
│ └── todos: { [agentId: string]: TodoList } # 各代理的待办列表 │
├─────────────────────────────────────────────────────────────────────────┤
│ 15. 会话生命周期 (Session Lifecycle) │
│ ├── initialMessage # 初始消息(CLI参数) │
│ ├── pendingPlanVerification # 待验证的计划 │
│ ├── sessionHooks # 会话钩子 │
│ ├── authVersion: number # 认证版本(触发重取) │
│ ├── fastMode: boolean # 快速模式 │
│ └── advisorModel: string # 顾问模型 │
├─────────────────────────────────────────────────────────────────────────┤
│ 16. 其他/辅助 (Misc) │
│ ├── agent: string # CLI指定的代理名称 │
│ ├── companionReaction # 伙伴表情反应 │
│ ├── companionPetAt # 最后互动时间 │
│ ├── skillImprovement # 技能改进建议 │
│ └── remoteAgentTaskSuggestions # 远程任务建议 │
└─────────────────────────────────────────────────────────────────────────┘
主要字段统计
总字段数: ~400+
核心类别: 16个
主要字段: ~60个(上表列出)
关键状态对象: 8个(tasks, mcp, plugins, teamContext, notifications,
speculation, promptSuggestion, computerUseMcpState)
这个设计支持:
-
单用户会话:所有状态集中管理
-
多代理协作:
teamContext+tasks字典 -
远程控制:
replBridge*+remote*字段群 -
工具生态:
mcp+plugins双系统 -
AI功能:
speculation+thinkingEnabled+promptSuggestion
参考阅读2
核心架构全
┌─────────────────────────────────────────────────────────┐
│ createStore<T> │
│ ┌─────────────┐ ┌─────────────┐ ┌─────────────────┐ │
│ │ state │ │ listeners │ │ onChange │ │
│ │ (mutable) │ │ (Set) │ │ (callback) │ │
│ └─────────────┘ └─────────────┘ └─────────────────┘ │
│ │
│ ┌─────────────┐ ┌─────────────┐ ┌─────────────────┐ │
│ │ getState() │ │ setState() │ │ subscribe() │ │
│ │ (read) │ │ (write) │ │ (subscribe) │ │
│ └─────────────┘ └─────────────┘ └─────────────────┘ │
└─────────────────────────────────────────────────────────┘
│
▼
┌─────────────────┐
│ AppStateStore │
│ (全局单例) │
└─────────────────┘
│
▼
┌─────────────────────────────────────┐
│ React 集成层 (AppState.tsx) │
│ ┌─────────────┐ ┌─────────────┐ │
│ │useAppState │ │useSetAppState│ │
│ │ (订阅) │ │ (仅写入) │ │
│ └─────────────┘ └─────────────┘ │
│ ┌─────────────┐ ┌─────────────┐ │
│ │useAppStateStore│ │useAppStateMaybe│ │
│ │ (原始store) │ │ (安全访问) │ │
│ └─────────────┘ └─────────────┘ │
└─────────────────────────────────────┘
│
▼
┌─────────────────────────────────────────────────────────┐
│ AppState │
│ ┌─────────────┐ ┌─────────────┐ ┌─────────────┐ │
│ │ 核心设置 │ │ 任务系统 │ │ 插件系统 │ │
│ │ (settings) │ │ (tasks) │ │ (plugins) │ │
│ └─────────────┘ └─────────────┘ └─────────────┘ │
│ ┌─────────────┐ ┌─────────────┐ ┌─────────────┐ │
│ │ MCP系统 │ │ 团队协作 │ │ 桥接系统 │ │
│ │ (mcp) │ │ (team) │ │ (bridge) │ │
│ └─────────────┘ └─────────────┘ └─────────────┘ │
│ ┌─────────────┐ ┌─────────────┐ ┌─────────────┐ │
│ │ UI状态 │ │ 权限系统 │ │ 超级计划 │ │
│ │ (ui) │ │ (perms) │ │ (ultra) │ │
│ └─────────────┘ └─────────────┘ └─────────────┘ │
└─────────────────────────────────────────────────────────┘
│
▼
┌─────────────────────────────────────────────────────────┐
│ 状态变更处理器 │
│ ┌─────────────┐ ┌─────────────┐ ┌─────────────┐ │
│ │onChangeAppState││团队视图助手 │ │ 状态选择器 │ │
│ │(全局变更) │ │(teammateView)│ │(selectors) │ │
│ └─────────────┘ └─────────────┘ └─────────────┘ │
└─────────────────────────────────────────────────────────┘
│
▼
┌─────────────────────────────────────────────────────────┐
│ 组件层 (React) │
│ ┌─────────────┐ ┌─────────────┐ ┌─────────────┐ │
│ │UI组件 │ │权限组件 │ │任务组件 │ │
│ │(Messages) │ │(Permissions)│ │(Tasks) │ │
│ └─────────────┘ └─────────────┘ └─────────────┘ │
│ ┌─────────────┐ ┌─────────────┐ ┌─────────────┐ │
│ │设置组件 │ │MCP组件 │ │桥接组件 │ │
│ │(Settings) │ │(MCP) │ │(Bridge) │ │
│ └─────────────┘ └─────────────┘ └─────────────┘ │
└─────────────────────────────────────────────────────────┘
参考阅读3
订阅在Claude Code React 中的具体实现
const listeners = new Set<Listener>() // 订阅者集合
subscribe: (listener: Listener) => () => void // 订阅方法
React 上下文订阅
// src/state/AppState.tsx
export function useAppState<T>(selector: (state: AppState) => T): T {
const store = useAppStore()
const get = React.useMemo(() => () => {
const state = store.getState()
const selected = selector(state)
return selected
}, [selector, store])
// 关键:使用 store.subscribe 实现订阅
return useSyncExternalStore(store.subscribe, get, get)
}
组件订阅示例
// src/components/StatusLine.tsx
function StatusLine() {
// 订阅特定状态字段
const statusLineText = useAppState(s => s.statusLineText)
const permissionMode = useAppState(s => s.toolPermissionContext.mode)
const isConnected = useAppState(s => s.replBridgeConnected)
// 只有当这些字段变化时组件才会重新渲染
return (
<div>Status: {statusLineText} | Mode: {permissionMode} | Connected: {isConnected}</div>
)
}
团队视图订阅
// src/state/teammateViewHelpers.ts
export function enterTeammateView(taskId: string, setAppState: any): void {
setAppState(prev => {
// 更新状态会触发所有订阅者的重新渲染
return {
...prev,
viewingAgentTaskId: taskId,
viewSelectionMode: 'viewing-agent'
}
})
}
参考阅读4
通知 (Notification) 的作用
核心概念
onChange?: OnChange<T> // 状态变更回调
for (const listener of listeners) listener() // 通知所有订阅者
全局状态变更通知
权限模式变更通知
// src/state/onChangeAppState.ts
export function onChangeAppState({ newState, oldState }: {
newState: AppState
oldState: AppState
}) {
// 检测权限模式变化
const prevMode = oldState.toolPermissionContext.mode
const newMode = newState.toolPermissionContext.mode
if (prevMode !== newMode) {
// 通知外部系统(CCR/SDK)
notifySessionMetadataChanged({
permission_mode: newExternal,
is_ultraplan_mode: isUltraplan ? true : null,
})
// 通知内部监听器
notifyPermissionModeChanged(newMode)
}
}
模型设置变更通知
// 模型变更时通知设置系统
if (newState.mainLoopModel !== oldState.mainLoopModel) {
if (newState.mainLoopModel === null) {
updateSettingsForSource('userSettings', { model: undefined })
setMainLoopModelOverride(null)
} else {
updateSettingsForSource('userSettings', { model: newState.mainLoopModel })
setMainLoopModelOverride(newState.mainLoopModel)
}
}
UI 设置持久化通知
// UI 状态变更时持久化到磁盘
if (newState.expandedView !== oldState.expandedView) {
const showExpandedTodos = newState.expandedView === 'tasks'
const showSpinnerTree = newState.expandedView === 'teammates'
saveGlobalConfig(current => ({
...current,
showExpandedTodos,
showSpinnerTree,
}))
}
参考阅读5
实际应用场景
实时协作场景
// 多个组件订阅同一个状态
const TeammateView = () => {
const viewingAgent = useAppState(s => s.viewingAgentTaskId)
// 当 viewingAgent 变化时,团队视图组件会立即更新
}
const TaskList = () => {
const tasks = useAppState(s => s.tasks)
// 当 tasks 变化时,任务列表会立即更新
}
const StatusIndicator = () => {
const connectionStatus = useAppState(s => s.replBridgeConnected)
// 当连接状态变化时,状态指示器会立即更新
}
性能优化
// 选择性订阅避免不必要的重渲染
const MyComponent = () => {
// 只订阅需要的字段,其他状态变化不会触发重渲染
const isBrief = useAppState(s => s.isBriefOnly)
const model = useAppState(s => s.mainLoopModel)
// 这两个字段的变化才会触发组件重渲染
return <div>{isBrief ? 'Brief mode' : 'Normal mode'} - {model}</div>
}
更多推荐



所有评论(0)