Skip to main content

knowledge-runtime-state-bootstrap-and-observability

覆盖 Blade 的进程启动目录状态、跨异步上下文 cwd 隔离、共享 Vanilla Store、日志与运行环境观测、运行时包信息、Session ID、原生目录选择和项目注册。 使用时机:调整 CLI 启动顺序、排查多 workspace 状态串扰、从 React 外访问 Store、增加运行态观测、修改版本识别、Session 标识或项目选择/绑定流程。 不包含:配置层级与持久化路由见 layered-configuration-and-runtime-settings,事件日志与持久投影见 durable-transcript-and-event-projection,容量和关闭编排见 capacity-lifecycle-and-egress。 关键词:bootstrap state, getCwd, runWithCwdOverride, vanillaStore, ensureStoreInitialized, Logger, streamDebug, getEnvironmentContext, getVersion, createSessionId, NativeDirectoryPicker, ProjectRegistry。

معلومات المصدر

المستودع
echoVic/blade-code
آخر نشاط في المصدر
٢٦ أغسطس ٢٠٢٦ في ١٩:٥٧
لغة SKILL.md المكتشفة
الصينية
النجوم
١٨١
التفرعات
٢٨

خيارات التثبيت

يُحدَّد Prompt الذي يراجع المصدر أولًا بشكل افتراضي. يمكنك التبديل إلى أمر مباشر أو تنزيل نسخة محلية.

مراجعة ملفات المصدر

اقرأ SKILL.md وأي ملفات مرافقة يعرضها SkillsMP قبل أن تقرر التثبيت.

عرض SKILL.md

SKILL.md
تعليمات المصدر · معاينة للقراءة فقط
name
knowledge-runtime-state-bootstrap-and-observability
description
覆盖 Blade 的进程启动目录状态、跨异步上下文 cwd 隔离、共享 Vanilla Store、日志与运行环境观测、运行时包信息、Session ID、原生目录选择和项目注册。 使用时机:调整 CLI 启动顺序、排查多 workspace 状态串扰、从 React 外访问 Store、增加运行态观测、修改版本识别、Session 标识或项目选择/绑定流程。 不包含:配置层级与持久化路由见 layered-configuration-and-runtime-settings,事件日志与持久投影见 durable-transcript-and-event-projection,容量和关闭编排见 capacity-lifecycle-and-egress。 关键词:bootstrap state, getCwd, runWithCwdOverride, vanillaStore, ensureStoreInitialized, Logger, streamDebug, getEnvironmentContext, getVersion, createSessionId, NativeDirectoryPicker, ProjectRegistry。
## Module Structure 该组件提供各运行表面共享的进程级基础状态与观测入口;它区分启动目录、当前工作区和稳定项目根,并把 UI 状态、日志、环境探测及项目发现收敛到可被 Agent、CLI、Server、工具和扩展复用的 API。 ### Directory Layout - `packages/cli/src/bootstrap/state.ts` — 惰性初始化的 cwd、originalCwd 与 projectRoot 三态 - `packages/cli/src/store/` — React 与非 React 共用的 Zustand Store、切片、类型和细粒度选择器 - `packages/cli/src/logging/` — 分类 JSONL 日志与独立流式调试日志 - `packages/cli/src/utils/cwd.ts` — 基于 AsyncLocalStorage 的并发 cwd 覆写 - `packages/cli/src/utils/environment.ts` — 项目根发现、环境提示和目录概览 - `packages/cli/src/utils/packageInfo.ts` — 源码与打包布局兼容的运行时包信息 - `packages/cli/src/utils/sessionId.ts` — 可安全用于存储路径的 Session ID - `packages/cli/src/services/DirectoryPicker.ts` — macOS、Windows 与 Linux 原生目录选择 - `packages/cli/src/services/ProjectRegistry.ts` — 规范化项目路径的持久绑定注册表 ### Key Entry Points - `getCwd()` / `runWithCwdOverride()` — 获取当前执行上下文的 workspace,或为异步调用链临时覆写 - `vanillaStore` / `useBladeStore()` / `ensureStoreInitialized()` — 共享状态实例、React 订阅与幂等配置初始化 - `createLogger()` / `setLoggerSessionId()` / `streamDebug()` — 分类日志、会话日志路由与流式专项诊断 - `getEnvironmentContext()` / `getVersion()` / `createSessionId()` — 构造环境上下文、读取运行版本和生成存储安全标识 - `NativeDirectoryPicker.pick()` / `ProjectRegistry.list()` — 选择本机目录并读取规范化项目集合 ## API Surface ### Workspace Location - `getCwd()` — 优先返回当前 AsyncLocalStorage 覆写,否则返回进程级 cwd - `runWithCwdOverride(cwd, fn)` — 在同步及后续异步调用链内隔离 workspace - `getOriginalCwd()` — 返回 CLI 被调用时的原始目录,用于解析用户传入的相对路径 - `getProjectRoot()` — 返回启动后保持稳定的项目标识根 - `findProjectRoot(startDir)` / `setCwd(newPath, relativeTo?)` — 发现工作区根并更新规范化的全局 cwd ### Shared Store - `useBladeStore(selector)` — React 对共享 Vanilla Store 的细粒度订阅入口 - `getState()` — Agent、服务与命令读取当前 Store 快照 - `sessionActions()` / `appActions()` / `configActions()` — 面向不同状态域的动作入口 - `ensureStoreInitialized()` — 以共享 Promise 合并并发配置初始化 - `useCurrentStreamingBuffer()` — 以浅比较订阅流式行缓冲、尾部、计数和版本 ### Observability - `createLogger(category, options?)` — 创建分类日志器,文件输出与终端调试过滤相互独立 - `Logger.setGlobalDebug(config)` — 动态设置全局终端日志开关或分类过滤 - `setLoggerSessionId(sessionId)` — 切换后续 JSONL 日志的文件名 - `streamDebug(source, message, data?)` — 向独立流式诊断文件追加记录且不向调用方抛错 - `getEnvironmentContext(options?)` — 组装系统、Git、脚本和目录信息供系统提示使用 ### Runtime Identity And Project Discovery - `getPackageInfo()` / `getVersion()` — 从运行时邻近 package.json 读取并缓存实际发布信息 - `createSessionId(prefix?, size?)` — 校验前缀后生成可用于文件名的 ID - `NativeDirectoryPicker.pick()` — 跨平台打开至多一个并发原生目录选择器 - `ProjectRegistry.bind()` / `list()` / `unbind()` — 规范化、持久化并查询项目绑定 ## Usage Examples ### CLI 启动时固定项目根 ```typescript const invocationCwd = process.cwd(); const detectedRoot = findProjectRoot(invocationCwd); setCwd(detectedRoot); setProjectRoot(getCwd()); ``` ### 启动 Server 前确保共享 Store 可用 ```typescript await ensureStoreInitialized(); const server = await BladeServer.listenAsync(opts); ``` ### TUI 初始化完成后绑定会话日志 ```typescript const state = getState(); const sessionId = state.session.sessionId; setLoggerSessionId(sessionId); ``` ## Gotchas - `originalCwd`、`cwd` 与 `projectRoot` 不能互换:CLI 相对参数以调用目录解析,运行工具使用可变 cwd,历史、Skill 和 Session 等项目身份使用启动后固定的 projectRoot (`packages/cli/src/bootstrap/state.ts`, `packages/cli/src/blade.tsx`, `packages/cli/src/cli/settings.ts`, `packages/cli/src/mcp/loadMcpConfig.ts`) - CLI 必须先执行 `findProjectRoot()`、`setCwd()` 和 `setProjectRoot()` 再启动依赖 workspace 的流程,否则配置、信任与资源发现会以调用子目录为根 (`packages/cli/src/blade.tsx`, `packages/cli/src/utils/environment.ts`) - 并发 Session 或子代理不能用全局 `setCwd()` 做临时切换;应使用 `runWithCwdOverride()`,其 AsyncLocalStorage 覆写会沿异步调用链传播且不污染其他执行上下文 (`packages/cli/src/utils/cwd.ts`, `git:4543542b`) - `setCwd()` 解析相对路径时默认基于真实 `process.cwd()` 而不是当前 AsyncLocalStorage 覆写;在隔离上下文内传相对路径必须显式提供 `relativeTo` (`packages/cli/src/utils/environment.ts`, `packages/cli/src/utils/cwd.ts`) - Store 是否初始化仅以 `config.config !== null` 判断;CLI、Server、ACP 和 Hook 等非 React 入口在读取配置前都必须等待 `ensureStoreInitialized()`,并发调用会共享同一个初始化 Promise (`packages/cli/src/store/vanilla.ts`, `packages/cli/src/commands/serve.ts`, `packages/cli/src/acp/BladeAgent.ts`) - `resetSession()` 只重置 Zustand 内的 Session 字段并保留 sessionId,不会隐式清空模块级 `conversationProjection`;切换事件流时还要显式调用 `resetConversationProjection()` (`packages/cli/src/store/slices/sessionSlice.ts`) - `Logger` 的 debug 开关只控制终端输出,所有级别仍同步追加到 JSONL;不要通过关闭 debug 假设磁盘日志已停用 (`packages/cli/src/logging/Logger.ts`) - 日志文件路由使用进程级 `currentSessionId` 而非异步上下文;TUI 绑定 Session 前的记录进入 `blade-default.jsonl`,该机制也不能区分并发 Server Session (`packages/cli/src/logging/Logger.ts`, `packages/cli/src/ui/App.tsx`) - 日志目录初始化只尝试一次;权限或创建失败后会缓存不可用状态,当前进程内即使外部修复目录也不会自动重试 (`packages/cli/src/logging/Logger.ts`) - `streamDebug()` 不受 `Logger.setGlobalDebug()` 控制,并会在每个 storage root 的首次调用时重写 `stream-debug.log`;它是临时专项诊断通道,不是普通分类日志 (`packages/cli/src/logging/StreamDebugLogger.ts`, `packages/cli/src/ui/utils/loopEventHandler.ts`) - `ProjectRegistry` 遇到缺失、损坏或版本不匹配的注册表会按空集合继续,并始终临时注入当前项目;因此列表只剩当前项目不代表绑定从未存在 (`packages/cli/src/services/ProjectRegistry.ts`, `packages/cli/tests/unit/services/project-registry.test.ts`) - 原生目录选择服务本身不校验请求来源,只有 Server 路由拒绝非本机 Origin;新增调用表面时必须复用同等访问边界 (`packages/cli/src/services/DirectoryPicker.ts`, `packages/cli/src/server/routes/projects.ts`) - Linux 目录选择仅在命令不存在时从 `zenity` 回退到 `kdialog`;已安装选择器返回真实错误时会立即失败,而空输出的退出码 1 被视为用户取消 (`packages/cli/src/services/DirectoryPicker.ts`, `packages/cli/tests/unit/platform/services/directory-picker.test.ts`) ## Architecture - `bootstrap/state.ts` 保存进程级三态,`cwd.ts` 只在其上增加异步上下文覆盖;绝大多数业务代码应依赖 `getCwd()`,只有启动和测试夹具直接操作底层状态 (`packages/cli/src/bootstrap/state.ts`, `packages/cli/src/utils/cwd.ts`) - 单一 `vanillaStore` 同时服务 Ink React 订阅和 Agent、服务、命令的命令式访问;Store 不使用 persist 中间件,配置和会话持久化分别交给 ConfigService 与 Context/JSONL (`packages/cli/src/store/index.ts`, `packages/cli/src/store/vanilla.ts`) - Session Store 同时投影持久消息、临时流式缓冲和 Provider/停滞/重试等观测事件;命令结束或取消会集中清除易过期的运行态诊断,避免下一轮展示旧状态 (`packages/cli/src/store/slices/sessionSlice.ts`, `packages/cli/src/store/slices/commandSlice.ts`, `git:2aa2b22b`, `git:e6bd4e15`) - `getEnvironmentContext()` 默认采集 Git 分支、工作树、最近提交、根目录清单和常用脚本;单项命令失败只省略对应片段,不会阻断提示构建 (`packages/cli/src/utils/environment.ts`, `packages/cli/tests/unit/platform/utils/environment.test.ts`, `git:7680e3eb`) - 项目根发现会继续向上寻找 `.git`、`.blade` 或 `.claude`,仅在没有这些标记时回退到最近的 package.json,因此 monorepo 子包默认归属仓库根 (`packages/cli/src/utils/environment.ts`, `packages/cli/tests/unit/platform/utils/environment.test.ts`) - 项目注册表以 realpath 作为去重身份,保留已失联项目供用户修复或解绑,并把当前项目固定排在名称排序之前 (`packages/cli/src/services/ProjectRegistry.ts`, `packages/cli/tests/unit/services/project-registry.test.ts`) ## Decisions - cwd 隔离采用 AsyncLocalStorage 而不是 `process.chdir()`,使并行子代理、ACP 和真实 API 驱动可在同一进程内保持各自 workspace (`packages/cli/src/utils/cwd.ts`, `packages/cli/tests/support/browserToolAcpDriver.ts`) - Zustand 只承担当前进程读模型,不承担磁盘权威状态;这一边界允许 Session 事件日志和配置服务独立处理恢复、原子写与版本迁移 (`packages/cli/src/store/vanilla.ts`, `packages/cli/src/store/types.ts`) - 包版本改为从源码或 bundle 邻近目录向上搜索名称匹配的 package.json,避免发布包仍报告构建时导入的旧版本;找不到时才使用导入值或 `BLADE_VERSION` (`packages/cli/src/utils/packageInfo.ts`, `git:092d356b`) - Session ID 统一由带受限前缀的 nanoid 生成,替代可能包含路径非法字符的临时标识,使 TUI、Web、ACP、任务和子代理共享存储安全格式 (`packages/cli/src/utils/sessionId.ts`, `packages/cli/src/store/slices/sessionSlice.ts`, `git:d148a8fa`) ## Patterns - React 消费者通过专用 selector 订阅最小状态片段,对对象组合使用 `useShallow`,空模型列表复用常量引用;非 React 消费者通过 `getState()` 和动作访问器共享同一实例 (`packages/cli/src/store/index.ts`, `packages/cli/src/store/selectors/index.ts`, `packages/cli/src/store/vanilla.ts`) - Store action 在并发清理时使用身份或请求 ID 防止迟到回调覆盖新状态,例如 `clearAbortController(expectedController)` 和旁路对话完成动作都先核对当前所有者 (`packages/cli/src/store/slices/commandSlice.ts`, `packages/cli/src/store/slices/appSlice.ts`) - 项目绑定写入遵循 mutex 内 read-modify-write、原子替换和 `0600` 文件权限;目录本身同步收紧到 `0700` (`packages/cli/src/services/ProjectRegistry.ts`) - `NativeDirectoryPicker.pick()` 缓存进行中的 Promise,并在 settle 后清空,多个并发 Web 请求只会打开一个系统对话框 (`packages/cli/src/services/DirectoryPicker.ts`, `packages/cli/tests/unit/platform/services/directory-picker.test.ts`) ## Dependencies - 原生目录选择分别依赖 macOS `osascript`、Windows PowerShell Forms、Linux `zenity` 或 `kdialog`,统一受 15 分钟超时和 64 KiB 输出上限约束 (`packages/cli/src/services/DirectoryPicker.ts`) - 日志和项目注册都从 Blade storage root 派生文件位置;前者容忍写入失败,后者使用 `write-file-atomic` 并向调用方传播非 ENOENT/语法错误 (`packages/cli/src/logging/Logger.ts`, `packages/cli/src/services/ProjectRegistry.ts`) ## Consumer Analysis - TUI 是共享 Store 的最高频消费者,通过 selector 渲染消息、焦点和运行态,并通过动作协调初始化、模型、权限和日志 Session 绑定 (`packages/cli/src/ui/App.tsx`, `packages/cli/src/ui/hooks/useAgent.ts`, `packages/cli/src/store/selectors/index.ts`) - Server 与 CLI 命令在无 React 环境调用 `ensureStoreInitialized()`、配置动作、环境版本和项目注册服务,启动顺序错误会直接影响 Web/Headless 可用性 (`packages/cli/src/commands/serve.ts`, `packages/cli/src/server/server.ts`, `packages/cli/src/server/routes/projects.ts`) - Agent、SessionRuntime 与子代理使用共享 Store 投影运行状态,并以 `getCwd()` 或 AsyncLocalStorage 覆写确定每次执行的 workspace (`packages/cli/src/agent/Agent.ts`, `packages/cli/src/agent/runtime/SessionRuntime.ts`, `packages/cli/src/agent/subagents/BackgroundAgentManager.ts`) - 工具、Hooks、MCP、Plugins 和 LSP 广泛依赖 `getCwd()` 与分类 Logger;这些扩展必须优先使用显式 `context.workspaceRoot`,缺失时才回退进程上下文 (`packages/cli/src/tools/execution/ToolExecutor.ts`, `packages/cli/src/hooks/HookManager.ts`, `packages/cli/src/plugins/PluginRegistry.ts`, `packages/cli/src/lsp/LspSessionManager.ts`) - SessionService、PersistentStore 和协议适配层消费运行版本与存储安全 ID,把同一身份格式写入会话元数据、JSONL 路径、ACP 握手和 MCP 客户端信息 (`packages/cli/src/services/SessionService.ts`, `packages/cli/src/context/storage/PersistentStore.ts`, `packages/cli/src/acp/BladeAgent.ts`, `packages/cli/src/mcp/McpClient.ts`)
عرض على GitHub