01.3 启动期状态与上下文
关注源码
src/bootstrap/state.tssrc/context.tssrc/state/onChangeAppState.ts
两层状态模型
这套代码有两层不同职责的状态:
1. bootstrap/state.ts 管启动期和会话级全局事实
这层保存的是“整个进程/会话都要共享”的东西,例如:
originalCwd、projectRoot、sessionId- 当前模型、model strings、SDK betas
- 统计计数器、成本、API duration、tool duration
- prompt cache 相关 latch
- 计划模式/auto mode 的一次性状态
- session trust、session persistence、remote mode 等全局标记
这类状态不适合放进 React AppState,因为它们既服务 headless,也服务 TUI,还要在启动期早早可用。
2. AppState 管交互式前台会话状态
AppState 在 state/AppStateStore.ts 中定义,更多承载:
- 当前消息、任务、notifications、elicitation
- 当前 tools/commands/MCP/plugin 视图
- Prompt suggestion、speculation、footer、panel、selection
- 交互层正在展示什么、聚焦什么
入口层负责把 bootstrap 层结果折叠成初始 AppState。
上下文组装
getSystemContext()
context.ts 中的 system context 主要提供:
- git status 快照
- 当前分支与默认分支
- recent commits
- 某些调试/缓存打断注入
它是“会话开头的环境说明”,而不是每轮实时刷新状态。
getUserContext()
user context 主要提供:
CLAUDE.md及其递归 memory 文件内容- 当前日期
其中 CLAUDE.md 会被缓存到 bootstrap state,供权限分类器等无法直接依赖 claudemd.ts 的路径复用。
为什么上下文在入口层准备
因为它们直接影响:
- system prompt 组成
- prompt cache key
- 权限分类器输入
- 启动后的第一轮 query
如果把这些信息拖到运行时临时补,会让 prompt 组成、缓存命中、权限行为都变得不稳定。
onChangeAppState 的位置很关键
state/onChangeAppState.ts 不是普通监听器,它是“交互状态写回系统状态”的统一出口。当前它会处理:
- permission mode 变更时,向 CCR/SDK 同步 external metadata
- model 变更时,写回 settings 和 session override
- expanded view / verbose 等 UI 偏好持久化
- settings 变化时,清理认证缓存并重新应用环境变量
这意味着 AppState 不是孤立的前端 store,而是会反向驱动:
- session metadata
- settings 持久化
- 远端桥接元数据
这一层的设计意义
1. 启动期状态和前台状态被明确分层
如果把所有状态都塞进 React store,会让:
- headless 模式难以复用
- 启动前阶段无法访问关键状态
- 进程级 latch 与 UI 状态混在一起
当前分层把“运行时事实”和“界面表现”区分得比较清楚。
2. 上下文是缓存敏感数据,不是普通 helper
context.ts 的输出会直接影响模型输入,所以它被做成 memoized provider,而不是 UI 侧随手拼装的对象。
3. onChangeAppState 是跨层同步阀门
所有 setAppState 造成的重要副作用都尽量汇总到这里,而不是散在各组件和 hooks 里。这是避免模式同步失真的关键。