@@ -28,7 +28,7 @@ Root (blade-code)
2828│ ├── security/ # 安全管理
2929│ ├── services/ # 共享服务层
3030│ ├── slash-commands/ # 内置斜杠命令
31- │ ├── telemetry/ # 遥测和监控
31+ │ ├── telemetry/ # 遥测和监控(历史目录,当前实现中已不再使用)
3232│ ├── tools/ # 工具系统
3333│ │ ├── builtin/ # 内置工具(Read/Write/Bash等)
3434│ │ ├── execution/ # 执行管道
@@ -96,7 +96,7 @@ Root (blade-code)
9696 - 静态工厂方法 ` Agent.create() ` 用于创建和初始化实例
9797 - 每次命令可创建新 Agent 实例(用完即弃)
9898 - 通过 ` ExecutionEngine ` 处理工具执行流程
99- - 通过 ` LoopDetectionService ` 防止无限循环(三层检测机制 )
99+ - ** 安全保障 ** : 通过 ` maxTurns ` + 硬性轮次上限 ` SAFETY_LIMIT = 100 ` 控制循环(已移除 LoopDetectionService,避免与系统提示冲突 )
100100
101101- ** SessionContext** ([ src/ui/contexts/SessionContext.tsx] ( src/ui/contexts/SessionContext.tsx ) ): 会话状态管理
102102 - 维护全局唯一 ` sessionId `
@@ -129,12 +129,6 @@ Root (blade-code)
129129 - Discovery → Permission (Zod验证+默认值) → Confirmation → Execution → Formatting
130130 - 事件驱动架构,支持监听各阶段事件
131131 - 自动记录执行历史
132- - ** LoopDetectionService** ([ src/agent/LoopDetectionService.ts] ( src/agent/LoopDetectionService.ts ) ): 三层循环检测系统
133- - ** 层1** : 工具调用循环检测(MD5 哈希 + 动态阈值)
134- - ** 层2** : 内容循环检测(滑动窗口 + 动态相似度)
135- - ** 层3** : LLM 智能检测(认知循环分析)
136- - 支持白名单工具、Plan 模式跳过内容检测
137- - 详见: [ 循环检测系统文档] ( docs/development/implementation/loop-detection-system.md )
138132- ** PromptBuilder** ([ src/prompts/] ( src/prompts/ ) ): 提示模板管理和构建
139133- ** ContextManager** ([ src/context/ContextManager.ts] ( src/context/ContextManager.ts ) ): 上下文管理系统
140134 - ** JSONL 格式** : 追加式存储,每行一个 JSON 对象
@@ -192,6 +186,149 @@ Blade 提供完整的 Markdown 渲染支持,包含以下组件:
192186- 用户文档:[ docs/public/guides/markdown-support.md] ( docs/public/guides/markdown-support.md )
193187- 开发者文档:[ docs/development/implementation/markdown-renderer.md] ( docs/development/implementation/markdown-renderer.md )
194188
189+ ## State Management Architecture
190+
191+ ### Zustand Store 设计
192+
193+ Blade 使用 ** Zustand** 作为全局状态管理库,采用 ** 单一数据源 (SSOT)** 架构:
194+
195+ ** 核心原则** :
196+ - ** Store 是唯一读取源** - 所有组件和服务从 Store 读取状态
197+ - ** vanilla.ts actions 是唯一写入入口** - 自动同步内存 + 持久化
198+ - ** ConfigManager 仅用于 Bootstrap** - 初始化时加载配置文件
199+ - ** ConfigService 负责持久化** - 运行时写入配置文件
200+
201+ ** 架构图** :
202+ ```
203+ Bootstrap (启动时):
204+ ConfigManager.initialize() → 返回 BladeConfig → Store.setConfig()
205+
206+ Runtime (运行时):
207+ UI/Agent → vanilla.ts actions → Store (内存SSOT)
208+ ↓
209+ ConfigService (持久化到 config.json/settings.json)
210+ ```
211+
212+ ### 状态管理最佳实践
213+
214+ ** ✅ 推荐:从 Store 读取**
215+ ``` typescript
216+ import { getConfig , getCurrentModel } from ' ../store/vanilla.js' ;
217+
218+ const config = getConfig (); // 读取完整配置
219+ const model = getCurrentModel (); // 读取当前模型
220+ ```
221+
222+ ** ✅ 推荐:通过 actions 写入**
223+ ``` typescript
224+ import { configActions } from ' ../store/vanilla.js' ;
225+
226+ // 自动同步内存 + 持久化
227+ await configActions ().addModel ({... });
228+ await configActions ().setPermissionMode (' yolo' );
229+ ```
230+
231+ ** ❌ 避免:直接调用 ConfigManager**
232+ ``` typescript
233+ // ❌ 错误:绕过 Store,导致数据不一致
234+ const configManager = ConfigManager .getInstance ();
235+ await configManager .addModel ({... }); // Store 未更新!
236+ ```
237+
238+ ** React 组件订阅** :
239+ ``` typescript
240+ // ✅ 使用选择器(精准订阅)
241+ import { useCurrentModel , usePermissionMode } from ' ../store/selectors/index.js' ;
242+
243+ const model = useCurrentModel ();
244+ const mode = usePermissionMode ();
245+
246+ // ✅ 组合选择器使用 useShallow 优化
247+ import { useShallow } from ' zustand/react/shallow' ;
248+
249+ const { field1, field2 } = useBladeStore (
250+ useShallow ((state ) => ({
251+ field1: state .slice .field1 ,
252+ field2: state .slice .field2 ,
253+ }))
254+ );
255+ ```
256+
257+ ### Store 初始化规则
258+
259+ ** ⚠️ 关键规则** :任何调用 ` configActions() ` 或读取 ` getConfig() ` 的代码前,必须确保 Store 已初始化。
260+
261+ ** 统一防御点(推荐)** :
262+ ``` typescript
263+ import { ensureStoreInitialized } from ' ../store/vanilla.js' ;
264+
265+ // 在执行任何依赖 Store 的逻辑前
266+ await ensureStoreInitialized ();
267+ ```
268+
269+ ** ` ensureStoreInitialized() ` 特性** :
270+ - ✅ ** 幂等** :已初始化直接返回(性能无负担)
271+ - ✅ ** 并发安全** :同一时刻只初始化一次(共享 Promise)
272+ - ✅ ** 失败重试** :初始化失败后,下次调用会重新尝试
273+ - ✅ ** 明确报错** :初始化失败抛出详细错误信息
274+
275+ ** 已添加防御的路径** :
276+ | 路径 | 防御点 | 说明 |
277+ | ------| --------| ------|
278+ | CLI 命令 | ` middleware.ts ` | 初始化失败会退出并报错 |
279+ | Slash Commands | ` useCommandHandler.ts ` | 执行前统一调用 ` ensureStoreInitialized() ` |
280+ | Agent 创建 | ` Agent.create() ` | 内置防御性检查 |
281+ | Config Actions | 各方法内部 | 检查 ` if (!config) throw ` |
282+
283+ ** ⚠️ 竞态风险** :
284+ - UI 初始化过程中用户立即输入命令
285+ - 多个 slash command 并发执行
286+ - 非 UI 场景(测试/脚本/print mode)复用
287+
288+ ** ✅ 推荐模式** :
289+ ``` typescript
290+ // Slash command 执行前
291+ if (isSlashCommand (command )) {
292+ await ensureStoreInitialized (); // 统一防御点
293+ const result = await executeSlashCommand (command , context );
294+ }
295+
296+ // CLI 子命令执行前
297+ export const myCommand: CommandModule = {
298+ handler : async (argv ) => {
299+ await ensureStoreInitialized (); // 防御性检查
300+ const config = getConfig ();
301+ // ... 使用 config
302+ }
303+ };
304+ ```
305+
306+ ** ❌ 避免模式** :
307+ ``` typescript
308+ // ❌ 错误:假设已初始化
309+ const config = getConfig ();
310+ if (! config ) {
311+ // 太迟了,某些路径可能已经踩坑
312+ }
313+
314+ // ❌ 错误:静默吞掉初始化失败
315+ try {
316+ await ensureStoreInitialized ();
317+ } catch (error ) {
318+ console .warn (' 初始化失败,继续执行' ); // 危险!
319+ }
320+ ```
321+
322+ ### Store 初始化机制
323+
324+ 三层初始化防护:
325+
326+ 1 . ** UI 路径** :` App.tsx ` → useEffect 初始化 Store
327+ 2 . ** CLI 路径** :` middleware.ts ` → loadConfiguration 初始化 Store
328+ 3 . ** 防御路径** :` Agent.create() ` → ensureStoreInitialized() 兜底
329+
330+ 详见:[ Store 与 Config 架构统一文档] ( docs/development/implementation/store-config-unification.md )
331+
195332## Slash Commands
196333
197334Blade 提供内置的斜杠命令系统,用于执行特定的系统操作。所有 slash 命令实现位于 [ src/slash-commands/] ( src/slash-commands/ ) 。
0 commit comments