乐于分享
好东西不私藏

Claude Code源码系列:7、数据流转与状态管理

Claude Code源码系列:7、数据流转与状态管理

Claude Code CLI 作为 Anthropic 官方的命令行工具,承载着与 AI 模型实时交互、工具调用、文件操作等复杂任务。其核心是一个精心设计的状态管理与数据流转系统——不同于传统的 Redux/MobX 方案,该项目采用了一种极简的 Zustand 风格设计:仅 34 行代码的 createStore 函数,配合 React 18 的 useSyncExternalStore,构建出一个支持 800KB 主入口文件、50+ 状态字段的巨型应用。

本文将从源码级别深入剖析其数据流转架构,揭示以下核心问题:

  • 如何用最小代码实现最大状态管理能力?
  • 消息队列如何与 React 渲染解耦?
  • 流式响应如何转化为状态更新?
  • 文件变更如何同步到运行时状态?

第一章:状态基元——createStore 的极简哲学

1.1 三接口设计模式

状态管理的核心在于「读」「写」「订阅」三个原子操作。Claude Code 的 createStore 函数将这三个操作封装为三个接口,构成最小可用的状态管理单元。

// src/state/store.ts:1-8type Listener = () =>void// 监听器类型:无参数回调type OnChange<T> = (args: { newState: T; oldState: T }) =>void// 变更回调类型exporttype Store<T> = {  getState: () => T; // 读取当前状态  setState: (updater: (prev: T) => T) =>void// 更新状态(通过 updater 函数)  subscribe: (listener: Listener) => () => void// 订阅变更(返回取消订阅函数)};

这是一个经典的「发布-订阅」模式的极简实现。与 Redux 的 reducer + action 模式不同,createStore 直接接受 updater 函数,省去了 action 创建和 dispatch 的中间层。与 Zustand 的实现几乎完全一致,但代码量更少——没有中间件系统,没有 devtools 集成,纯粹的原子状态管理

1.2 不可变更新与引用相等性判断

setState 的实现是整个系统的性能关键点。它采用「不可变更新」+「引用相等性判断」的双重策略:

// src/state/store.ts:10-27export functioncreateStore<T>(  initialState: T,  onChange?: OnChange<T>,): Store<T{let state = initialState; // 内部状态变量const listeners = new Set<Listener>(); // 监听器集合(自动去重)return {    getState: () => state,    setState: (updater: (prev: T) => T) => {const prev = state; // 保存旧状态const next = updater(prev); // 执行 updater 得到新状态if (Object.is(next, prev)) return// 【关键】浅比较阻断无效更新      state = next; // 更新内部状态      onChange?.({ newState: next, oldState: prev }); // 触发变更回调for (const listener of listeners) listener(); // 通知所有订阅者    },    subscribe: (listener: Listener) => {      listeners.add(listener); // 添加监听器return () => listeners.delete(listener); // 返回取消订阅函数    },  };}

Object.is(next, prev) 是性能优化的第一法则。这个浅比较在以下场景会阻断无效渲染:

  1. updater 返回原对象setState(prev => prev) —— 状态未改变,无需通知
  2. 状态切片相等setState(prev => ({ ...prev, unchanged: prev.unchanged })) —— 如果 unchanged 是原引用,整体对象不等但组件级可能相等

这种设计要求调用者必须遵循「不可变更新」原则:永远不要修改原状态对象,而是返回新对象。这与 React 的 setState 行为一致,是现代状态管理的基石。

1.3 与 Redux/Zustand 的对比

特性
Redux
Zustand
Claude Code createStore
代码行数
~300 (核心)
~100
34
中间件支持
是 (thunk/saga)
否(通过 onChange 回调)
异步处理
thunk/saga
内置 async
无(由外部 Generator 处理)
DevTools
Redux DevTools
内置 devtools
订阅机制
单一 listener
selector 支持
Set + 返回取消函数
更新模式
reducer + action
updater 函数
updater 函数 + Object.is

Claude Code 的选择体现了「极简主义」哲学:不需要中间件,不需要 devtools,只需要最纯粹的状态管理。复杂度被转移到外部——异步处理由 AsyncGenerator 处理,副作用由 onChange 回调处理,类型安全由 TypeScript 保证。


第二章:AppState 巨型状态的设计艺术

2.1 状态分片架构

Claude Code 的全局状态 AppState 是一个「巨型状态」,包含 50+ 字段,覆盖配置、运行、连接、UI 等多个维度。为了管理这个复杂度,状态被按照「功能域」分片:

// src/state/AppStateStore.ts:89-452 (简化展示)export type AppState = DeepImmutable<{// ==================== 配置类状态 ====================  settings: SettingsJson; // 用户/项目设置  verbose: boolean// 详细日志开关  mainLoopModel: ModelSetting; // 当前模型  toolPermissionContext: ToolPermissionContext; // 工具权限上下文// ==================== 运行类状态 ====================  tasks: { [taskId: string]: TaskState }; // 任务状态映射  agentNameRegistry: Map<string, AgentId>; // Agent 名称注册表  speculation: SpeculationState; // 预测执行状态  notifications: { current: Notification | null; queue: Notification[] }; // 通知队列// ==================== 连接类状态 ====================  mcp: {    clients: MCPServerConnection[]; // MCP 服务器连接    tools: Tool[]; // MCP 工具列表    commands: Command[]; // MCP 命令列表    pluginReconnectKey: number// 重连计数器  };  plugins: {    enabled: LoadedPlugin[]; // 已启用插件    disabled: LoadedPlugin[]; // 已禁用插件    errors: PluginError[]; // 插件错误列表    needsRefresh: boolean// 需刷新标记  };// ==================== Bridge 状态 ====================  replBridgeEnabled: boolean// Bridge 启用开关  replBridgeConnected: boolean// Bridge 连接状态  replBridgeSessionActive: boolean// Bridge 会话活跃// ==================== UI 状态 ====================  expandedView: "none" | "tasks" | "teammates"// 展开视图类型  statusLineText: string | undefined// 状态栏文本  isBriefOnly: boolean// 简洁模式  footerSelection: FooterItem | null// 底部选中项}> & {// 可变部分(函数类型无法 DeepImmutable)  tasks: { [taskId: string]: TaskState }; // TaskState 包含函数类型  agentNameRegistry: Map<string, AgentId>; // Map 类型需要可变操作};

状态分类设计哲学

类别
字段示例
特点
配置类
settings, verbose, mainLoopModel
持久化优先,生命周期跨越会话
运行类
tasks, speculation, notifications
会话生命周期,随进程销毁
连接类
mcp, plugins, replBridge*
外部系统状态,需要同步机制
UI 类
expandedView, statusLineText
纯展示状态,不持久化

2.2 DeepImmutable 类型约束

AppState 使用 DeepImmutable 类型包装,这是一种「深度不可变」的类型约束:

// src/state/AppStateStore.ts:89exporttype AppState = DeepImmutable<{ ... }> & { ... }

DeepImmutable 的作用是:

  1. 编译时阻止直接修改state.settings.verbose = true 会触发 TypeScript 错误
  2. 强制不可变更新模式:必须通过 setState(prev => ({ ...prev, ... })) 更新
  3. 允许例外:通过 & 交叉类型,将 tasks 和 agentNameRegistry 排除,因为它们包含函数类型或需要可变操作

这种设计在 Redux 中需要 Immutable.js 或手动 readonly 标记,而 Claude Code 通过 TypeScript 的类型系统直接实现。

2.3 默认状态工厂函数 getDefaultAppState()

默认状态通过工厂函数生成,确保每次初始化都获得完整、合法的状态对象:

// src/state/AppStateStore.ts:456-569export functiongetDefaultAppState(): AppState{// 确定初始权限模式const teammateUtils = require("../utils/teammate.js");const initialMode: PermissionMode =    teammateUtils.isTeammate() && teammateUtils.isPlanModeRequired()      ? "plan"      : "default";return {    settings: getInitialSettings(), // 从磁盘加载设置    tasks: {}, // 空任务映射    agentNameRegistry: new Map(), // 空 Agent 注册表    verbose: false// 默认不详细    mainLoopModel: null// 默认模型(由配置决定)    toolPermissionContext: {      ...getEmptyToolPermissionContext(),      mode: initialMode, // 权限模式    },    mcp: {      clients: [], // 空 MCP 连接      tools: [],      commands: [],      resources: {},      pluginReconnectKey: 0,    },    plugins: {      enabled: [], // 空插件列表      disabled: [],      commands: [],      errors: [],      installationStatus: { marketplaces: [], plugins: [] },      needsRefresh: false,    },    speculation: IDLE_SPECULATION_STATE, // 预测执行初始状态    notifications: { current: null, queue: [] },    inbox: { messages: [] },// ... 更多字段默认值  };}

工厂函数的关键设计:

  1. 懒加载依赖:通过 require() 避免循环依赖
  2. 动态初始值:根据运行环境(teammate、plan mode)决定初始值
  3. 完整覆盖:每个字段都有显式默认值,避免 undefined

第三章:React 集成——useSyncExternalStore 的精妙运用

3.1 AppStateProvider 单例约束

React 18 引入的 useSyncExternalStore 是连接外部状态与 React 渲染的关键桥梁。Claude Code 通过 AppStateProvider 封装这个集成:

// src/state/AppState.tsx:27-110export const AppStoreContext = React.createContext<AppStateStore | null>(null)const HasAppStateContext = React.createContext<boolean>(false)export functionAppStateProvider({ children, initialState, onChangeAppState }: Props{// 【关键】禁止嵌套 Provider —— 确保全局单例const hasAppStateContext = useContext(HasAppStateContext)if (hasAppStateContext) {throw new Error("AppStateProvider can not be nested within another AppStateProvider")  }// Store 只创建一次,永不重建 —— useState 传入工厂函数const [store] = useState(() =>    createStore<AppState>(initialState ?? getDefaultAppState(), onChangeAppState)  )// Mount 时检查 bypass permissions 模式  useEffect(() => {const { toolPermissionContext } = store.getState()if (toolPermissionContext.isBypassPermissionsModeAvailable && isBypassPermissionsModeDisabled()) {      store.setState(prev => ({        ...prev,        toolPermissionContext: createDisabledBypassPermissionsContext(prev.toolPermissionContext),      }))    }  }, [])// 监听设置变更并同步到 Storeconst onSettingsChange = useEffectEvent((source: SettingSource) =>    applySettingsChange(source, store.setState)  )  useSettingsChange(onSettingsChange)return (    <HasAppStateContext.Provider value={true}>      <AppStoreContext.Provider value={store}>        <MailboxProvider>          <VoiceProvider>{children}</VoiceProvider>        </MailboxProvider>      </AppStoreContext.Provider>    </HasAppStateContext.Provider>  )}

单例约束的设计理由

  • AppState 是全局状态,多实例会导致状态分叉
  • HasAppStateContext 作为「嵌套检测器」,在 render 阶段抛错
  • useState(() => createStore(...)) 确保 Store 只创建一次

3.2 选择器订阅模式 useAppState(selector)

组件订阅状态的唯一方式是通过 useAppState(selector)

// src/state/AppState.tsx:142-163export functionuseAppState<T>(selector: (state: AppState) => T): T{const store = useAppStore(); // 获取 Storeconst get = () => {const state = store.getState(); // 读取完整状态const selected = selector(state); // 执行选择器return selected; // 返回选中切片  };// 【关键】useSyncExternalStore 实现 React-外部状态同步return useSyncExternalStore(store.subscribe, getget);}

使用示例

// 正确用法:选择单个字段(返回原始引用)const verbose = useAppState((s) => s.verbose);const model = useAppState((s) => s.mainLoopModel);// 正确用法:选择嵌套对象(返回原有引用)const { text, promptId } = useAppState((s) => s.promptSuggestion);// 错误用法:返回新对象(每次 render 都不等)const data = useAppState((s) => ({  verbose: s.verbose,  model: s.mainLoopModel,})); // ❌

为什么禁止返回新对象? 因为 useSyncExternalStore 通过 Object.is 判断 snapshot 是否变化。如果 selector 每次都返回新对象 { ... },即使状态没变,React 也认为变了,导致无限重渲染。

3.3 无订阅更新器 useSetAppState()

对于只需要更新状态、不需要订阅的组件,使用 useSetAppState

// src/state/AppState.tsx:170-172exportfunctionuseSetAppState(): (  updater: (prev: AppState) => AppState,) => void{return useAppStore().setState; // 返回稳定的 setState 函数}

关键特性:返回的 setState 函数是稳定引用——永远不会变化。这意味着:

const setAppState = useSetAppState();// 这个组件永远不会因为 AppState 变化而重渲染// 因为它没有订阅任何状态切片

这是性能优化的关键模式:「只写不读」组件不需要订阅,避免不必要的渲染


第四章:事件信号与消息队列——解耦通信的两种范式

4.1 Signal:无状态事件广播

当订阅者只需要知道「某事发生了」,而不需要「当前值是什么」时,使用 Signal

// src/utils/signal.ts:18-43export type Signal<Args extends unknown[] = []> = {  subscribe: (listener: (...args: Args) => void) => () => void// 订阅(返回取消)  emit: (...args: Args) => void// 发射事件  clear: () => void// 清除所有监听器};export functioncreateSignal<Argsextendsunknown[] = []>(): Signal<Args{const listeners = new Set<(...args: Args) =>void>();return {    subscribe(listener) {      listeners.add(listener);return () => {        listeners.delete(listener);      }; // 返回取消函数    },    emit(...args) {for (const listener of listeners) listener(...args); // 遍历调用    },    clear() {      listeners.clear();    },  };}

Signal 与 Store 的区别

特性
Store
Signal
存储状态
是 (getState)
获取当前值
通知时机
值改变时
emit() 调用时
参数传递
无(通过 getState 获取)
有(emit 参数)
适用场景
状态管理
纯事件通知

典型用途:设置文件变更通知

// src/utils/settings/changeDetector.ts:71const settingsChanged = createSignal<[source: SettingSource]>();// 订阅者exportconst subscribe = settingsChanged.subscribe;// 发射者functionfanOut(source: SettingSource): void{  resetSettingsCache();  settingsChanged.emit(source); // 通知所有订阅者}

4.2 命令队列优先级调度

用户输入、任务通知、系统消息都需要排队等待处理。messageQueueManager 实现了一个优先级队列:

// src/utils/messageQueueManager.ts:53-61const commandQueue: QueuedCommand[] = [];let snapshot: readonly QueuedCommand[] = Object.freeze([]); // 快照(供 React)const queueChanged = createSignal(); // 变更信号functionnotifySubscribers(): void{  snapshot = Object.freeze([...commandQueue]); // 更新快照  queueChanged.emit(); // 通知订阅者}// 优先级定义const PRIORITY_ORDER: Record<QueuePriority, number> = {  now: 0// 最高优先级 —— 立即处理  next: 1// 用户输入默认 —— 当前工具完成后  later: 2// 任务通知默认 —— 当前 turn 完成后};

入队操作

// src/utils/messageQueueManager.ts:128-135export functionenqueue(command: QueuedCommand): void{  commandQueue.push({ ...command, priority: command.priority ?? "next" }); // 默认 next  notifySubscribers();  logOperation("enqueue",typeof command.value === "string" ? command.value : undefined,  );}// 任务通知入队 —— 默认 laterexport functionenqueuePendingNotification(command: QueuedCommand): void{  commandQueue.push({ ...command, priority: command.priority ?? "later" }); // 默认 later  notifySubscribers();}

出队操作:按优先级取出,同优先级 FIFO:

// src/utils/messageQueueManager.ts:167-193export functiondequeue(  filter?: (cmd: QueuedCommand) => boolean,): QueuedCommand | undefined{if (commandQueue.length === 0return undefined;// 遍历找最高优先级let bestIdx = -1;let bestPriority = Infinity;for (let i = 0; i < commandQueue.length; i++) {const cmd = commandQueue[i]!;if (filter && !filter(cmd)) continue// 应用过滤器const priority = PRIORITY_ORDER[cmd.priority ?? "next"];if (priority < bestPriority) {      bestIdx = i;      bestPriority = priority;    }  }if (bestIdx === -1return undefined;const [dequeued] = commandQueue.splice(bestIdx, 1); // 移除  notifySubscribers();return dequeued;}

React 集成

// src/utils/messageQueueManager.ts:71-80exportconst subscribeToCommandQueue = queueChanged.subscribe;exportfunctiongetCommandQueueSnapshot(): readonlyQueuedCommand[] {return snapshot; // 返回不可变快照}// 在组件中使用const commands = useSyncExternalStore(  subscribeToCommandQueue,  getCommandQueueSnapshot,);

4.3 Mailbox:异步等待式消息传递

Mailbox 是一种「异步等待」模式的消息传递机制,用于进程间通信:

// src/utils/mailbox.ts:19-73export class Mailbox {private queue: Message[] = []; // 消息队列private waiters: Waiter[] = []; // 等待者列表(Promise)private changed = createSignal(); // 变更信号private _revision = 0// 版本号  send(msg: Message): void {this._revision++;// 检查是否有等待者匹配const idx = this.waiters.findIndex((w) => w.fn(msg));if (idx !== -1) {const waiter = this.waiters.splice(idx, 1)[0];      waiter.resolve(msg); // 直接 resolve 等待的 Promisethis.notify();return;    }this.queue.push(msg); // 否则推入队列this.notify();  }  receive(fn = () => true): Promise<Message> {// 先检查队列const idx = this.queue.findIndex(fn);if (idx !== -1) {const msg = this.queue.splice(idx, 1)[0];this.notify();return Promise.resolve(msg);    }// 无匹配消息,创建等待 Promisereturn new Promise<Message>((resolve) => {this.waiters.push({ fn, resolve }); // 注册等待者    });  }poll(fn = () => true): Message | undefined {constidx = this.queue.findIndex(fn);if (idx === -1returnundefined;returnthis.queue.splice(idx, 1)[0]; // 非阻塞取消息  }subscribe = this.changed.subscribe;}

Mailbox 与命令队列的区别

特性
命令队列 (messageQueueManager)
Mailbox
级别
模块级(单例)
实例级(可创建多个)
消费者
React 组件 + 主循环
异步等待者(Promise)
等待模式
主动 dequeue
被动 receive
用途
用户输入/任务通知
进程间消息(team 模式)

典型场景:Team 模式下的 Agent 消息传递

// Agent A 发送消息mailbox.send({ id: "msg-1"from"agent-A", text: "task completed" });// Agent B 等待特定消息const msg = await mailbox.receive((m) => m.from === "agent-A");

第五章:流式处理与工具执行器——并发控制的艺术

5.1 Stream 类:AsyncIterator 封装

流式 API 响应需要一种「生产者-消费者」模式的数据结构。Claude Code 的 Stream 类封装了 AsyncIterator:

// src/utils/stream.ts:1-76export class Stream<T> implements AsyncIterator<T> {private readonly queue: T[] = []; // 数据队列private readResolve?: (value: IteratorResult<T>) => void// 等待 resolveprivate readReject?: (error: unknown) => void// 错误 rejectprivate isDone: boolean = false// 结束标记private hasError: unknown | undefined// 错误标记private started = false// 启动标记constructor(private readonly returned?: () => void) {}  [Symbol.asyncIterator](): AsyncIterableIterator<T> {if (this.started) throw new Error("Stream can only be iterated once");this.started = true;return this;  }  next(): Promise<IteratorResult<T>> {// 队列有数据,立即返回if (this.queue.length > 0) {return Promise.resolve({ done: false, value: this.queue.shift()! });    }// 已结束,返回 doneif (this.isDone) return Promise.resolve({ done: true, value: undefined });// 有错误,抛出if (this.hasError) return Promise.reject(this.hasError);// 【关键】无数据未结束,创建等待 Promisereturn new Promise<IteratorResult<T>>((resolve, reject) => {this.readResolve = resolve;this.readReject = reject;    });  }enqueue(value: T): void {    // 如果有等待者,直接 resolveif (this.readResolve) {this.readResolve({ done: false, value });this.readResolve = undefined;this.readReject = undefined;    } else {this.queue.push(value); // 否则推入队列    }  }done() {this.isDone = true;if (this.readResolve) {this.readResolve({ done: true, value: undefined });    }  }error(error: unknown) {this.hasError = error;if (this.readRejectthis.readReject(error);  }}

Stream 的设计精髓

  1. 消费者驱动next() 被调用时才触发数据流动
  2. Promise 等待:无数据时消费者挂起,数据到达时唤醒
  3. 单向流动:只能迭代一次(started 标记)
  4. 错误穿透error() 立即 reject 所有等待者

5.2 StreamingToolExecutor 并发控制模型

当 AI 模型流式输出多个工具调用时,需要并发执行但保持结果顺序。StreamingToolExecutor 实现了一个四状态并发控制模型:

// src/services/tools/StreamingToolExecutor.ts:19-32type ToolStatus = "queued" | "executing" | "completed" | "yielded";type TrackedTool = {  id: string;  block: ToolUseBlock;  assistantMessage: AssistantMessage;  status: ToolStatus; // 状态机  isConcurrencySafe: boolean// 是否可并发  promise?: Promise<void>; // 执行 Promise  results?: Message[]; // 执行结果  pendingProgress: Message[]; // 进度消息(立即 yield)  contextModifiers?: Array<(context: ToolUseContext) => ToolUseContext>;};

状态流转

addTool() → queued → canExecuteTool()? → executing → completed → yielded                         ↓ 否                 ↓              ↓                      等待...           收集结果        getCompletedResults()

并发控制逻辑

// src/services/tools/StreamingToolExecutor.ts:129-135private canExecuteTool(isConcurrencySafe: boolean): boolean {const executingTools = this.tools.filter(t => t.status === 'executing')return (    executingTools.length === 0 ||                   // 无执行中的工具,可开始    (isConcurrencySafe && executingTools.every(t => t.isConcurrencySafe))  // 全并发安全,可并行  )}

关键规则

  1. 并发安全工具可并行:Read、WebFetch 等不修改状态的工具
  2. 非并发工具独占执行:Edit、Write 等修改状态的工具必须串行
  3. 结果顺序保持:按工具添加顺序 yield,不按完成顺序

5.3 Bash 错误级联取消机制

Bash 工具执行失败时,需要取消所有正在执行的并行工具:

// src/services/tools/StreamingToolExecutor.ts:265-405private async executeTool(tool: TrackedTool): Promise<void> {  tool.status = 'executing'// 子 AbortController —— Bash 错误时可被级联取消const toolAbortController = createChildAbortController(this.siblingAbortController)// 监听取消信号,向上传播  toolAbortController.signal.addEventListener('abort'() => {if (toolAbortController.signal.reason !== 'sibling_error' &&        !this.toolUseContext.abortController.signal.aborted) {this.toolUseContext.abortController.abort(toolAbortController.signal.reason)    }  }, { once: true })const generator = runToolUse(tool.block, tool.assistantMessage, this.canUseTool, { ...this.toolUseContext, abortController: toolAbortController })for await (const update of generator) {// 检查是否被取消const abortReason = this.getAbortReason(tool)if (abortReason && !thisToolErrored) {      messages.push(this.createSyntheticErrorMessage(tool.id, abortReason, tool.assistantMessage))break    }// 检查错误结果const isErrorResult = update.message.type === 'user' &&      update.message.message.content.some(_ => _.type === 'tool_result' && _.is_error === true)if (isErrorResult) {      thisToolErrored = true// 【关键】只有 Bash 错误触发级联取消if (tool.block.name === BASH_TOOL_NAME) {this.hasErrored = truethis.siblingAbortController.abort('sibling_error')  // 取消所有兄弟工具      }    }// ...  }}

为什么只对 Bash 错误级联取消?

"Bash commands often have implicit dependency chains (e.g. mkdir fails → subsequent commands pointless). Read/WebFetch/etc are independent — one failure shouldn't nuke the rest."

这是一个务实的设计决策:Bash 命令之间通常有隐式依赖(如先 mkdir 再 cd),失败后继续执行其他 Bash 是无意义的;而 Read/WebFetch 是独立操作,失败不应影响其他。


第六章:设置同步——文件变更到运行时的闭环

6.1 chokidar 文件监听配置

设置文件(settings.json)变更需要实时同步到运行时状态。Claude Code 使用 chokidar 监听文件变更:

// src/utils/settings/changeDetector.ts:31-51const FILE_STABILITY_THRESHOLD_MS = 1000// 文件稳定性阈值const FILE_STABILITY_POLL_INTERVAL_MS = 500// 轮询间隔const INTERNAL_WRITE_WINDOW_MS = 5000// 内部写入窗口(抑制自己写的变更)const DELETION_GRACE_MS =  FILE_STABILITY_THRESHOLD_MS + FILE_STABILITY_POLL_INTERVAL_MS + 200// 删除宽限期export async functioninitialize(): Promise<void{// ...  watcher = chokidar.watch(dirs, {    persistent: true,    ignoreInitial: true// 忽略初始扫描    depth: 0// 只监听直接子文件    awaitWriteFinish: {      stabilityThreshold: FILE_STABILITY_THRESHOLD_MS, // 等待文件稳定      pollInterval: FILE_STABILITY_POLL_INTERVAL_MS,    },    atomic: true// 处理原子写入    ignored: (path, stats) => {// 忽略 .git 目录、非文件类型if (stats && !stats.isFile() && !stats.isDirectory()) return true;if (path.split(platformPath.sep).some((dir) => dir === ".git"))return true;// 只监听已知设置文件const normalized = platformPath.normalize(path);if (settingsFiles.has(normalized)) return false;return true;    },  });  watcher.on("change", handleChange);  watcher.on("unlink", handleDelete);  watcher.on("add", handleAdd);}

稳定性阈值设计awaitWriteFinish 确保文件写入完成后再触发事件。这解决了「写入中途触发多次 change」的问题:

用户编辑 settings.json → 写入开始 → chokidar 检测 → 等待 1000ms → 确认稳定 → 触发 change

6.2 内部写入抑制机制

当 Claude Code 自己写入设置文件时(如 /config 命令),不应该触发文件监听通知。这是通过「内部写入标记」机制实现的:

// src/utils/settings/changeDetector.ts:268-301functionhandleChange(path: string): void{const source = getSourceForPath(path);if (!source) return;// 【关键】检查是否是内部写入if (consumeInternalWrite(path, INTERNAL_WRITE_WINDOW_MS)) {return// 抑制,不触发通知  }// 执行 ConfigChange hook —— hook 可以阻止变更void executeConfigChangeHooks(    settingSourceToConfigChangeSource(source),    path,  ).then((results) => {if (hasBlockingResult(results)) {return// hook 阻止变更    }    fanOut(source); // 广播变更  });}

内部写入标记流程

1. Claude Code 写入 settings.json2. markInternalWrite(path) 记录写入时间3. chokidar 检测到变更,触发 handleChange4. consumeInternalWrite(path, 5000ms) 检查是否在 5s 内有标记5. 如果是内部写入 → return(不触发 fanOut)6. 如果是外部写入 → fanOut(通知订阅者)

6.3 applySettingsChange 状态同步

文件变更通知到达后,需要将新设置同步到 AppState:

// src/utils/settings/applySettingsChange.ts:33-92export functionapplySettingsChange(  source: SettingSource,  setAppState: (f: (prev: AppState) => AppState) => void,): void{const newSettings = getInitialSettings(); // 【关键】重读磁盘设置  logForDebugging(`Settings changed from ${source}, updating app state`);const updatedRules = loadAllPermissionRulesFromDisk(); // 重新加载权限规则  updateHooksConfigSnapshot(); // 更新 hooks 配置快照  setAppState((prev) => {// 同步权限规则let newContext = syncPermissionRulesFromDisk(      prev.toolPermissionContext,      updatedRules,    );// Ant-only:剥离过度宽泛的 Bash 权限if (      process.env.USER_TYPE === "ant" &&      process.env.CLAUDE_CODE_ENTRYPOINT !== "local-agent"    ) {const overlyBroad = findOverlyBroadBashPermissions(updatedRules, []);if (overlyBroad.length > 0) {        newContext = removeDangerousPermissions(newContext, overlyBroad);      }    }// 处理 bypass permissions 模式if (      newContext.isBypassPermissionsModeAvailable &&      isBypassPermissionsModeDisabled()    ) {      newContext = createDisabledBypassPermissionsContext(newContext);    }// 处理 effort 同步const prevEffort = prev.settings.effortLevel;const newEffort = newSettings.effortLevel;const effortChanged = prevEffort !== newEffort;return {      ...prev,      settings: newSettings, // 新设置      toolPermissionContext: newContext, // 新权限上下文      ...(effortChanged && newEffort !== undefined        ? { effortValue: newEffort }        : {}),    };  });}

同步闭环设计

外部编辑 settings.json    ↓chokidar 检测 → handleChange    ↓executeConfigChangeHooks (可阻止)    ↓fanOut(source) → settingsChanged.emit(source)    ↓useSettingsChange 回调 → applySettingsChange    ↓getInitialSettings() → 重读磁盘    ↓setAppState(prev => { ...prev, settings: newSettings })    ↓React 组件重新渲染

全链路数据流流程图

┌─────────────────────────────────────────────────────────────────────┐│                        用户输入层                                    ││  PromptInput → enqueue(command) → messageQueueManager               ││                                ↓                                    ││                    getCommandQueueSnapshot() ← React 订阅           │└─────────────────────────────────────────────────────────────────────┘                                  │                                  ▼ dequeue(filter)┌─────────────────────────────────────────────────────────────────────┐│                        Query 入口层                                  ││  query.ts / QueryEngine.ts → processUserInput()                    ││  → normalizeMessagesForAPI() → 构建 API 请求                        │└─────────────────────────────────────────────────────────────────────┘                                  │                                  ▼ Anthropic API Stream┌─────────────────────────────────────────────────────────────────────┐│                        流式处理层                                    ││  Stream<T> ← API AsyncGenerator                                     ││  → StreamingToolExecutor.addTool()                                  ││  → canExecuteTool(isConcurrencySafe)?                               ││      ├─ 是 → executeTool() → 收集结果                               ││      └─ 否 → 等待 executing 工具完成                                ││  → getCompletedResults() / getRemainingResults()                    │└─────────────────────────────────────────────────────────────────────┘                                  │                                  ▼ yield Message┌─────────────────────────────────────────────────────────────────────┐│                        状态更新层                                    ││  setAppState(prev => ({                                             ││    ...prev,                                                         ││    messages: [...prev.messages, newMessage],                        ││  }))                                                                ││  → listeners.forEach(listener())                                    ││  → React useSyncExternalStore 触发重渲染                            │└─────────────────────────────────────────────────────────────────────┘                                  │                                  ▼┌─────────────────────────────────────────────────────────────────────┐│                        UI 渲染层                                     ││  useAppState(selector) → selector(store.getState())                ││  → useSyncExternalStore(subscribe, getSnapshot)                    ││  → React 组件更新                                                   │└─────────────────────────────────────────────────────────────────────┘【并行分支:设置同步】┌─────────────────────────────────────────────────────────────────────┐│ settings.json 变更                                                  ││    ↓                                                                ││ chokidar.watch → handleChange(path)                                ││    ↓                                                                ││ consumeInternalWrite(path, 5000ms)?                                ││    ├─ 是 → return (抑制)                                            ││    └─ 否 → executeConfigChangeHooks → fanOut(source)              ││              ↓                                                      ││         settingsChanged.emit(source)                                ││              ↓                                                      ││         useSettingsChange 回调 → applySettingsChange()             ││              ↓                                                      ││         setAppState(prev => ({ ...prev, settings: newSettings }))  │└─────────────────────────────────────────────────────────────────────┘

小结:架构设计的核心结论

  1. 极简主义获胜:34 行 createStore 实现全量状态管理,证明复杂度来自业务而非框架。去掉中间件、去掉 devtools,只保留最原子化的「读」「写」「订阅」,足够构建 800KB 级别应用。

  2. 引用相等性优先Object.is(prev, next) 阻断无效更新,是性能优化的第一法则。这要求状态更新必须是不可变的,也与 React 18 的 useSyncExternalStore 语义完全匹配。

  3. 双队列解耦设计:messageQueueManager(模块级)与 Mailbox(实例级)分离,前者对接 React(useSyncExternalStore),后者处理异步等待。优先级调度(now/next/later)确保用户输入永不被系统消息饥饿。

  4. Signal 与 Store 正交:无状态事件广播与有状态订阅互补。当订阅者只需要「发生了某事」而非「当前值是什么」时,Signal 比 Store 更轻量、更合适。

  5. 流式即迭代器:Stream 类将 AsyncIterator 模式封装为「生产者-消费者」队列。让 for await...of 成为流式处理的自然表达,消费者驱动数据流动,无数据时自动挂起。

  6. 并发控制的状态机:StreamingToolExecutor 用 queued/executing/completed/yielded 四状态管理工具执行。比锁/信号量更直观,也比 Promise.all 更可控——结果按添加顺序 yield,不按完成顺序。

  7. 文件监听的闭环抑制:内部写入检测(5s 窗口)+ ConfigChange hook(可阻止)+ 缓存重置(fanOut 集中处理),构成完整的「磁盘→运行时」同步机制。避免自己写入触发回环通知,也允许 hook 拦截非法变更。

基本 文件 流程 错误 SQL 调试
  1. 请求信息 : 2026-05-15 08:32:59 HTTP/1.1 GET : https://www.yeyulingfeng.com/a/628221.html
  2. 运行时间 : 0.098921s [ 吞吐率:10.11req/s ] 内存消耗:4,788.76kb 文件加载:145
  3. 缓存信息 : 0 reads,0 writes
  4. 会话信息 : SESSION_ID=d674b2949928e7925d63ea24a1257862
  1. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/public/index.php ( 0.79 KB )
  2. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/autoload.php ( 0.17 KB )
  3. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/composer/autoload_real.php ( 2.49 KB )
  4. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/composer/platform_check.php ( 0.90 KB )
  5. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/composer/ClassLoader.php ( 14.03 KB )
  6. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/composer/autoload_static.php ( 6.05 KB )
  7. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/think-helper/src/helper.php ( 8.34 KB )
  8. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/think-validate/src/helper.php ( 2.19 KB )
  9. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/ralouphie/getallheaders/src/getallheaders.php ( 1.60 KB )
  10. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/think-orm/src/helper.php ( 1.47 KB )
  11. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/think-orm/stubs/load_stubs.php ( 0.16 KB )
  12. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/framework/src/think/Exception.php ( 1.69 KB )
  13. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/think-container/src/Facade.php ( 2.71 KB )
  14. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/symfony/deprecation-contracts/function.php ( 0.99 KB )
  15. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/symfony/polyfill-mbstring/bootstrap.php ( 8.26 KB )
  16. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/symfony/polyfill-mbstring/bootstrap80.php ( 9.78 KB )
  17. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/symfony/var-dumper/Resources/functions/dump.php ( 1.49 KB )
  18. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/think-dumper/src/helper.php ( 0.18 KB )
  19. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/symfony/var-dumper/VarDumper.php ( 4.30 KB )
  20. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/guzzlehttp/guzzle/src/functions_include.php ( 0.16 KB )
  21. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/guzzlehttp/guzzle/src/functions.php ( 5.54 KB )
  22. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/framework/src/think/App.php ( 15.30 KB )
  23. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/think-container/src/Container.php ( 15.76 KB )
  24. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/psr/container/src/ContainerInterface.php ( 1.02 KB )
  25. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/app/provider.php ( 0.19 KB )
  26. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/framework/src/think/Http.php ( 6.04 KB )
  27. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/think-helper/src/helper/Str.php ( 7.29 KB )
  28. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/framework/src/think/Env.php ( 4.68 KB )
  29. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/app/common.php ( 0.03 KB )
  30. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/framework/src/helper.php ( 18.78 KB )
  31. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/framework/src/think/Config.php ( 5.54 KB )
  32. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/config/alipay.php ( 3.59 KB )
  33. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/framework/src/think/facade/Env.php ( 1.67 KB )
  34. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/config/app.php ( 0.95 KB )
  35. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/config/cache.php ( 0.78 KB )
  36. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/config/console.php ( 0.23 KB )
  37. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/config/cookie.php ( 0.56 KB )
  38. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/config/database.php ( 2.48 KB )
  39. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/config/filesystem.php ( 0.61 KB )
  40. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/config/lang.php ( 0.91 KB )
  41. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/config/log.php ( 1.35 KB )
  42. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/config/middleware.php ( 0.19 KB )
  43. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/config/route.php ( 1.89 KB )
  44. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/config/session.php ( 0.57 KB )
  45. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/config/trace.php ( 0.34 KB )
  46. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/config/view.php ( 0.82 KB )
  47. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/app/event.php ( 0.25 KB )
  48. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/framework/src/think/Event.php ( 7.67 KB )
  49. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/app/service.php ( 0.13 KB )
  50. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/app/AppService.php ( 0.26 KB )
  51. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/framework/src/think/Service.php ( 1.64 KB )
  52. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/framework/src/think/Lang.php ( 7.35 KB )
  53. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/framework/src/lang/zh-cn.php ( 13.70 KB )
  54. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/framework/src/think/initializer/Error.php ( 3.31 KB )
  55. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/framework/src/think/initializer/RegisterService.php ( 1.33 KB )
  56. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/services.php ( 0.14 KB )
  57. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/framework/src/think/service/PaginatorService.php ( 1.52 KB )
  58. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/framework/src/think/service/ValidateService.php ( 0.99 KB )
  59. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/framework/src/think/service/ModelService.php ( 2.04 KB )
  60. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/think-trace/src/Service.php ( 0.77 KB )
  61. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/framework/src/think/Middleware.php ( 6.72 KB )
  62. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/framework/src/think/initializer/BootService.php ( 0.77 KB )
  63. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/think-orm/src/Paginator.php ( 11.86 KB )
  64. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/think-validate/src/Validate.php ( 63.20 KB )
  65. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/think-orm/src/Model.php ( 23.55 KB )
  66. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/think-orm/src/model/concern/Attribute.php ( 21.05 KB )
  67. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/think-orm/src/model/concern/AutoWriteData.php ( 4.21 KB )
  68. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/think-orm/src/model/concern/Conversion.php ( 6.44 KB )
  69. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/think-orm/src/model/concern/DbConnect.php ( 5.16 KB )
  70. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/think-orm/src/model/concern/ModelEvent.php ( 2.33 KB )
  71. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/think-orm/src/model/concern/RelationShip.php ( 28.29 KB )
  72. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/think-helper/src/contract/Arrayable.php ( 0.09 KB )
  73. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/think-helper/src/contract/Jsonable.php ( 0.13 KB )
  74. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/think-orm/src/model/contract/Modelable.php ( 0.09 KB )
  75. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/framework/src/think/Db.php ( 2.88 KB )
  76. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/think-orm/src/DbManager.php ( 8.52 KB )
  77. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/framework/src/think/Log.php ( 6.28 KB )
  78. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/framework/src/think/Manager.php ( 3.92 KB )
  79. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/psr/log/src/LoggerTrait.php ( 2.69 KB )
  80. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/psr/log/src/LoggerInterface.php ( 2.71 KB )
  81. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/framework/src/think/Cache.php ( 4.92 KB )
  82. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/psr/simple-cache/src/CacheInterface.php ( 4.71 KB )
  83. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/think-helper/src/helper/Arr.php ( 16.63 KB )
  84. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/framework/src/think/cache/driver/File.php ( 7.84 KB )
  85. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/framework/src/think/cache/Driver.php ( 9.03 KB )
  86. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/framework/src/think/contract/CacheHandlerInterface.php ( 1.99 KB )
  87. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/app/Request.php ( 0.09 KB )
  88. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/framework/src/think/Request.php ( 55.78 KB )
  89. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/app/middleware.php ( 0.25 KB )
  90. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/framework/src/think/Pipeline.php ( 2.61 KB )
  91. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/think-trace/src/TraceDebug.php ( 3.40 KB )
  92. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/framework/src/think/middleware/SessionInit.php ( 1.94 KB )
  93. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/framework/src/think/Session.php ( 1.80 KB )
  94. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/framework/src/think/session/driver/File.php ( 6.27 KB )
  95. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/framework/src/think/contract/SessionHandlerInterface.php ( 0.87 KB )
  96. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/framework/src/think/session/Store.php ( 7.12 KB )
  97. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/framework/src/think/Route.php ( 23.73 KB )
  98. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/framework/src/think/route/RuleName.php ( 5.75 KB )
  99. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/framework/src/think/route/Domain.php ( 2.53 KB )
  100. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/framework/src/think/route/RuleGroup.php ( 22.43 KB )
  101. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/framework/src/think/route/Rule.php ( 26.95 KB )
  102. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/framework/src/think/route/RuleItem.php ( 9.78 KB )
  103. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/route/app.php ( 3.94 KB )
  104. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/framework/src/think/facade/Route.php ( 4.70 KB )
  105. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/framework/src/think/route/dispatch/Controller.php ( 4.74 KB )
  106. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/framework/src/think/route/Dispatch.php ( 10.44 KB )
  107. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/app/controller/Index.php ( 9.87 KB )
  108. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/app/BaseController.php ( 2.05 KB )
  109. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/think-orm/src/facade/Db.php ( 0.93 KB )
  110. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/think-orm/src/db/connector/Mysql.php ( 5.44 KB )
  111. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/think-orm/src/db/PDOConnection.php ( 52.47 KB )
  112. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/think-orm/src/db/Connection.php ( 8.39 KB )
  113. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/think-orm/src/db/ConnectionInterface.php ( 4.57 KB )
  114. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/think-orm/src/db/builder/Mysql.php ( 16.58 KB )
  115. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/think-orm/src/db/Builder.php ( 24.06 KB )
  116. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/think-orm/src/db/BaseBuilder.php ( 27.50 KB )
  117. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/think-orm/src/db/Query.php ( 15.71 KB )
  118. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/think-orm/src/db/BaseQuery.php ( 45.13 KB )
  119. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/think-orm/src/db/concern/TimeFieldQuery.php ( 7.43 KB )
  120. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/think-orm/src/db/concern/AggregateQuery.php ( 3.26 KB )
  121. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/think-orm/src/db/concern/ModelRelationQuery.php ( 20.07 KB )
  122. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/think-orm/src/db/concern/ParamsBind.php ( 3.66 KB )
  123. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/think-orm/src/db/concern/ResultOperation.php ( 7.01 KB )
  124. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/think-orm/src/db/concern/WhereQuery.php ( 19.37 KB )
  125. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/think-orm/src/db/concern/JoinAndViewQuery.php ( 7.11 KB )
  126. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/think-orm/src/db/concern/TableFieldInfo.php ( 2.63 KB )
  127. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/think-orm/src/db/concern/Transaction.php ( 2.77 KB )
  128. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/framework/src/think/log/driver/File.php ( 5.96 KB )
  129. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/framework/src/think/contract/LogHandlerInterface.php ( 0.86 KB )
  130. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/framework/src/think/log/Channel.php ( 3.89 KB )
  131. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/framework/src/think/event/LogRecord.php ( 1.02 KB )
  132. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/think-helper/src/Collection.php ( 16.47 KB )
  133. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/framework/src/think/facade/View.php ( 1.70 KB )
  134. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/framework/src/think/View.php ( 4.39 KB )
  135. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/app/controller/Es.php ( 3.30 KB )
  136. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/framework/src/think/Response.php ( 8.81 KB )
  137. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/framework/src/think/response/View.php ( 3.29 KB )
  138. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/framework/src/think/Cookie.php ( 6.06 KB )
  139. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/think-view/src/Think.php ( 8.38 KB )
  140. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/framework/src/think/contract/TemplateHandlerInterface.php ( 1.60 KB )
  141. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/think-template/src/Template.php ( 46.61 KB )
  142. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/think-template/src/template/driver/File.php ( 2.41 KB )
  143. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/think-template/src/template/contract/DriverInterface.php ( 0.86 KB )
  144. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/runtime/temp/c935550e3e8a3a4c27dd94e439343fdf.php ( 31.50 KB )
  145. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/think-trace/src/Html.php ( 4.42 KB )
  1. CONNECT:[ UseTime:0.000524s ] mysql:host=127.0.0.1;port=3306;dbname=wenku;charset=utf8mb4
  2. SHOW FULL COLUMNS FROM `fenlei` [ RunTime:0.000904s ]
  3. SELECT * FROM `fenlei` WHERE `fid` = 0 [ RunTime:0.000360s ]
  4. SELECT * FROM `fenlei` WHERE `fid` = 63 [ RunTime:0.000234s ]
  5. SHOW FULL COLUMNS FROM `set` [ RunTime:0.000608s ]
  6. SELECT * FROM `set` [ RunTime:0.000214s ]
  7. SHOW FULL COLUMNS FROM `article` [ RunTime:0.000705s ]
  8. SELECT * FROM `article` WHERE `id` = 628221 LIMIT 1 [ RunTime:0.001514s ]
  9. UPDATE `article` SET `lasttime` = 1778805179 WHERE `id` = 628221 [ RunTime:0.008392s ]
  10. SELECT * FROM `fenlei` WHERE `id` = 64 LIMIT 1 [ RunTime:0.000266s ]
  11. SELECT * FROM `article` WHERE `id` < 628221 ORDER BY `id` DESC LIMIT 1 [ RunTime:0.000531s ]
  12. SELECT * FROM `article` WHERE `id` > 628221 ORDER BY `id` ASC LIMIT 1 [ RunTime:0.000946s ]
  13. SELECT * FROM `article` WHERE `id` < 628221 ORDER BY `id` DESC LIMIT 10 [ RunTime:0.000906s ]
  14. SELECT * FROM `article` WHERE `id` < 628221 ORDER BY `id` DESC LIMIT 10,10 [ RunTime:0.001975s ]
  15. SELECT * FROM `article` WHERE `id` < 628221 ORDER BY `id` DESC LIMIT 20,10 [ RunTime:0.002097s ]
0.101677s