评估日期:2026-03-31 基于 7 份架构文档 + 源码静态分析 项目规模:1,886 源文件,512,670 行 TypeScript/TSX
| 文件 | 行数 | 被引用数 | 导出数 | 问题 |
|---|---|---|---|---|
bootstrap/state.ts |
1,758 | 251 | 215 | 经典 God Module — 全局状态容器,session/cost/duration/cwd 全塞一个文件 |
utils/messages.ts |
5,512 | 108 | 80+ | 消息常量 + 工具函数混杂,5500 行纯工具文件 |
utils/sessionStorage.ts |
5,105 | — | — | 会话存储逻辑臃肿 |
utils/hooks.ts |
5,022 | — | — | 与 React hooks 概念冲突(在 utils/ 下) |
utils/attachments.ts |
3,997 | — | — | 附件处理逻辑过于集中 |
Tool.js |
~792 | 259 | — | 工具接口定义被 259 个文件引用,变更成本极高 |
state/AppState.ts |
1,190 | 171 | — | 应用状态类型 + store 混合 |
utils/config.ts |
1,817 | 129 | — | 配置读写 + 全局缓存混杂 |
关键判断: bootstrap/state.ts 是最严重的耦合瓶颈。215 个导出、251 个消费者,任何修改都可能波及半个代码库。它本质上是一个伪装成模块的全局变量空间。
| 文件 | 行数 | 职责 | 问题 |
|---|---|---|---|
cli/print.ts |
5,594 | 非交互输出模式 | 单文件 5500+ 行,职责不清 |
screens/REPL.tsx |
5,005 | 主交互循环 | 244 个 import,是项目中 import 最多的文件 |
main.tsx |
4,683 | CLI 入口 | 164 个 import,初始化 + 参数解析 + 会话管理全混 |
utils/bash/bashParser.ts |
4,436 | Bash 解析 | 单一职责但体积过大 |
services/api/claude.ts |
3,419 | API 客户端 | API 调用 + 流处理 + 重试 + token 管理 |
services/mcp/client.ts |
3,348 | MCP 客户端 | 协议 + 连接 + 工具发现 + 资源管理 |
utils/plugins/pluginLoader.ts |
3,302 | 插件加载 | 安装 + 验证 + 加载 + 版本管理 |
commands/insights.ts |
3,200 | Insights 命令 | 单命令文件过大 |
bridge/bridgeMain.ts |
2,999 | Bridge 主循环 | IDE 集成核心,耦合多协议 |
bootstrap/state.ts ←——→ 251 个文件(星型拓扑,所有东西都连它)
↑
├── REPL.tsx (直接引用多个 state getter/setter)
├── main.tsx (直接引用多个 state getter/setter)
├── QueryEngine.ts
├── 几乎所有 commands/
├── 几乎所有 tools/
└── 大部分 hooks/
tools.ts↔commands.ts:tools.ts 不直接引用 commands.ts,但 QueryEngine.ts 同时引用两者,形成三角耦合REPL.tsx↔ 多个 hooks:REPL 导入 244 个模块,多个 hooks 又依赖 REPL 暴露的 context,形成隐式循环permissions/跨层耦合:权限逻辑分散在utils/permissions/(24 文件)、tools/BashTool/bashPermissions.ts、components/permissions/(77 文件)、hooks/toolPermission/四个位置
bootstrap/state.ts ████████████████████████████ 251 文件
Tool.js ██████████████████████████ 259 文件
utils/config.ts ████████████████ 129 文件
AppState ████████████████████ 171 文件
utils/messages.ts ████████████ 108 文件
高可行性 ─────────────────── 低可行性
┌─────────────────┬──────────────────┐
│ │ │
高 │ ★ P0 立即做 │ ★ P1 规划做 │
影 │ │ │
响 │ ① 拆分 bootstrap │ ④ REPL.tsx 拆分 │
度 │ /state.ts │ (5005 行) │
│ │ │
│ ② 提取权限模块 │ ⑤ main.tsx 拆分 │
│ (跨 4 层) │ (4683 行) │
│ │ │
│ ③ utils/ 整理 │ ⑥ 工具系统重构 │
│ (清理巨型文件) │ (42 工具统一) │
│ │ │
├─────────────────┼──────────────────┤
│ │ │
低 │ ★ P2 随时做 │ ★ P3 长期目标 │
影 │ │ │
响 │ ⑦ BashTool/PS │ ⑧ Bridge/Remote │
度 │ 代码去重 │ 解耦 │
│ │ │
│ ⑨ 组件层 >800行 │ ⑩ 插件系统重构 │
│ 文件拆分 │ (3302 行加载器) │
│ │ │
└─────────────────┴──────────────────┘
| # | 项目 | 影响 | 可行 | 理由 |
|---|---|---|---|---|
| ① | 拆分 bootstrap/state.ts |
🔴 极高 | 🟢 高 | 按领域拆成 6-8 个子模块(session, cost, cwd, duration, tools, hooks),251 个引用点可通过 barrel export 过渡 |
| ② | 提取权限模块 | 🔴 高 | 🟡 中 | 当前跨 4 个目录,需要先统一接口,再迁移,逐步替换 |
| ③ | 清理 utils/ 巨型文件 | 🟡 中 | 🟢 高 | messages.ts / sessionStorage.ts / hooks.ts 各 5000+ 行,按职责拆分 |
| ④ | REPL.tsx 拆分 | 🔴 高 | 🔴 低 | 244 个 import,高度耦合 UI + 业务逻辑,需要先抽取业务逻辑层 |
| ⑤ | main.tsx 拆分 | 🔴 高 | 🔴 低 | 4683 行初始化 + CLI 解析混杂,Commander.js 定义可提取 |
| ⑥ | 工具系统统一 | 🟡 中 | 🔴 低 | 42 个工具接口已统一,但权限检查链分散 |
| ⑦ | BashTool/PS 去重 | 🟢 低 | 🟢 高 | 5706 行 readOnlyValidation 有明显重复,可提取共享层 |
| ⑧ | Bridge/Remote 解耦 | 🟡 中 | 🔴 低 | 涉及 WebSocket/JSON-RPC 协议层,需谨慎 |
| ⑨ | 大组件拆分 | 🟢 低 | 🟢 高 | PromptInput(2338), Config(1821) 等可直接拆 |
| ⑩ | 插件系统重构 | 🟡 中 | 🔴 低 | 3302 行加载器 + 2643 行市场管理器,复杂度高 |
现状: 1 文件,215 导出,251 个引用者
目标拆分:
bootstrap/
├── state.ts ← barrel re-export(保持兼容)
├── session/
│ └── sessionState.ts ← getSessionId, switchSession, parent session
├── cost/
│ └── costState.ts ← totalCost, totalDuration, API duration
├── cwd/
│ └── cwdState.ts ← getOriginalCwd, setProjectRoot, getCwdState
├── tools/
│ └── toolState.ts ← turnToolDuration, turnHookDuration, counters
├── tokens/
│ └── tokenState.ts ← token budget, turn output tokens
└── runtime/
└── runtimeState.ts ← session hooks, direct connect, speculation
策略:
- 创建子模块,从 state.ts 导出
- state.ts 变为 barrel file(
export * from './session/sessionState.js') - 逐步将消费者迁移到直接导入子模块
- 最终废弃 barrel file
风险: 低。barrel re-export 保证向后兼容。
现状: 4 个位置分散实现
当前:
utils/permissions/ (24 files) — 引擎核心
tools/BashTool/bashPermissions.ts — Bash 专用
tools/PowerShellTool/powershellPermissions.ts — PS 专用
components/permissions/ (77 files) — UI 组件
hooks/toolPermission/ (4 files) — React hooks
目标:
core/permissions/
├── engine.ts ← 统一权限判断引擎
├── rules.ts ← 规则匹配
├── modes.ts ← 模式管理
├── classifiers.ts ← AI 分类器
└── types.ts ← 统一类型
tools/*/ ← 各工具只保留 tool-specific 逻辑
components/permissions/ ← 不变,依赖 core/permissions
hooks/toolPermission/ ← 不变,依赖 core/permissions
原则: 先抽业务逻辑,再动 UI 组件
当前: screens/REPL.tsx (5005 行, 244 imports)
目标:
screens/
├── REPL.tsx ← 纯 UI 组合 (~1500 行)
├── useReplSession.ts ← 会话生命周期管理
├── useReplInput.ts ← 输入处理(从 244 import 中抽取)
├── useReplCommands.ts ← 命令调度
└── useReplQuery.ts ← 查询执行编排
services/repl/
├── queryOrchestrator.ts ← 查询编排(当前 REPL 中的 query 逻辑)
├── sessionManager.ts ← 会话管理
└── inputProcessor.ts ← 输入分类处理
关键前置条件: ① 已完成(bootstrap/state 拆分减少直接状态操作)
当前: main.tsx (4683 行)
目标:
main.tsx ← 入口 + 路由分发 (~800 行)
cli/
├── commanderSetup.ts ← Commander.js 配置 (~1500 行)
├── initialization.ts ← init 流程 (~800 行)
├── sessionLauncher.ts ← 会话启动分支 (~600 行)
└── urlHandlers.ts ← URL/deep link 处理 (~500 行)
| 异味 | 严重度 | 位置 | 说明 |
|---|---|---|---|
| God Module | 🔴 严重 | bootstrap/state.ts |
215 导出,251 消费者,全局状态倾倒场 |
| Blob | 🔴 严重 | REPL.tsx, main.tsx |
5000+ 行单文件,违反 SRP |
| Feature Envy | 🟡 中等 | utils/hooks.ts |
5022 行工具函数文件名为 "hooks",但不是 React hooks |
| Shotgun Surgery | 🔴 严重 | 权限系统 | 改一个权限逻辑要改 4 个目录 |
| Divergent Change | 🟡 中等 | utils/messages.ts |
5512 行,每次修改可能触及不同职责 |
| Data Clumps | 🟡 中等 | Tool.ts + AppState |
session/cwd/model 经常一起传递但没有组合类型 |
| 反模式 | 位置 | 说明 |
|---|---|---|
| 全局状态滥用 | bootstrap/state.ts |
215 个 getter/setter 实质是全局变量,无依赖注入,不可测试 |
| 隐式依赖 | REPL.tsx |
244 个 import 使得组件无法独立测试或复用 |
| 跨层耦合 | 权限系统 | 业务逻辑(utils/permissions)、UI(components/permissions)、Hooks(hooks/toolPermission)、工具级(tools/BashTool/bashPermissions)四层互相引用 |
| 重复实现 | BashTool ↔ PowerShellTool | readOnlyValidation 两个文件各 ~1900 行,逻辑高度相似但独立实现 |
| 命名混淆 | utils/hooks.ts |
不是 React hooks,是通用工具函数,与 hooks/ 目录产生歧义 |
当前状态: 302 个 await import() + 277 个 require() + 960 个 feature() 调用
评估: 动态导入使用已较充分,但存在不一致:
- ✅
main.tsx中重型模块(OpenTelemetry, gRPC, print.ts)已做延迟加载 - ✅
feature('...')用于构建时死码消除,覆盖 12+ feature flags ⚠️ REPL.tsx仅 4 处动态 import,大部分依赖是静态的⚠️ commands.ts静态导入所有 60+ 命令,应改为动态加载- ❌
tools.ts静态导入 42 个工具,启动时全部加载
建议: commands.ts 和 tools.ts 应按需动态导入,可减少初始 bundle ~30%。
| 问题 | 位置 | 说明 |
|---|---|---|
any 类型 |
多处 | permission result、tool output 等处有 any 残留 |
| 状态类型弱 | bootstrap/state.ts |
使用 module-level 变量而非 typed store,缺少变更追踪 |
| 条件类型分支 | Command 联合类型 |
prompt/local/local-jsx 三种分支,模式匹配不完整 |
Phase 1 (1-2 周) Phase 2 (2-4 周) Phase 3 (4-8 周)
┌──────────────┐ ┌──────────────┐ ┌──────────────┐
│ bootstrap/ │ │ 权限系统统一 │ │ REPL.tsx │
│ state.ts 拆分 │ ──────→ │ │ ──────→ │ 业务逻辑抽取 │
│ │ │ 核心引擎提取 │ │ │
└──────────────┘ └──────────────┘ └──────────────┘
│ │ │
▼ ▼ ▼
Phase 4 (6-10 周) Phase 5 (8-12 周) Phase 6 (持续)
┌──────────────┐ ┌──────────────┐ ┌──────────────┐
│ main.tsx 拆分 │ │ commands.ts │ │ 工具系统优化 │
│ │ ──────→ │ tools.ts │ ──────→ │ 组件层拆分 │
│ CLI 解析分离 │ │ 动态加载改造 │ │ 测试覆盖补全 │
└──────────────┘ └──────────────┘ └──────────────┘
-
创建子模块目录结构(30 分钟)
mkdir -p bootstrap/{session,cost,cwd,tools,tokens,runtime} -
提取
sessionState.ts(2 小时)- 移动
getSessionId,switchSession,parentSession*等 ~25 个导出 - 在
state.ts中添加export * from './session/sessionState.js'
- 移动
-
提取
costState.ts(2 小时)- 移动 cost/duration 相关 ~30 个导出
-
提取
cwdState.ts(1 小时)- 移动 cwd/project 相关 ~15 个导出
-
提取
toolState.ts(2 小时)- 移动 tool duration/counter 相关 ~40 个导出
-
提取
tokenState.ts(1 小时)- 移动 token budget 相关 ~20 个导出
-
提取
runtimeState.ts(2 小时)- 移动 hooks/speculation/directConnect 等 ~85 个导出
-
验证 barrel file 兼容性(1 小时)
- 确保所有 251 个消费者的 import 路径不变
- 运行类型检查 + 单元测试
前置条件: Phase 1 完成
- 定义
core/permissions/types.ts— 统一 PermissionResult, PermissionMode 等类型 - 实现
core/permissions/engine.ts— 通用权限判断引擎 - 将
utils/permissions/(24 文件) 迁移到core/permissions/ - 创建 adapter 层让 BashTool/PowerShellTool 使用统一引擎
- 迁移
components/permissions/依赖到core/permissions/ - 迁移
hooks/toolPermission/依赖到core/permissions/
每个 Phase 完成后必须验证:
- ✅ TypeScript 编译无新增错误
- ✅ 现有单元测试全部通过
- ✅ 启动时间无回退(
main.tsx的 profileCheckpoint 可用于测量) - ✅ Bundle 大小无显著增长
| 风险 | 概率 | 影响 | 缓解 |
|---|---|---|---|
| barrel file 过渡期引入循环依赖 | 中 | 中 | 严格使用 export * from,不引入新逻辑 |
| REPL 拆分破坏流式渲染 | 高 | 高 | 以 hook 边界拆分,不动渲染层 |
| 权限系统迁移遗漏 | 中 | 极高 | 端到端测试覆盖 + 灰度 |
| 动态加载改造影响启动时间 | 低 | 中 | 保留 profileCheckpoint 监控 |
| 多 provider(Bedrock/Vertex)兼容性 | 低 | 高 | 每个 provider 独立测试 |
Claude Code 的架构在工具系统(buildTool() 接口统一)和延迟加载(960 个 feature flag)方面做得不错。但有三个结构性债务需要优先处理:
-
bootstrap/state.ts是全局耦合的核心节点。215 个导出被 251 个文件引用,修改任何状态逻辑都可能产生级联影响。拆分它是最高 ROI 的重构动作。 -
权限系统跨四层分散是维护噩梦的根源。统一权限引擎能同时提升可维护性和安全性。
-
REPL.tsx 和 main.tsx 的体积使新人上手和 bug 定位变得困难。但拆分它们是 Phase 3+ 的工作,需要先解决底层耦合。
Phase 1(bootstrap/state 拆分)可在 1-2 周内完成,零风险,立即可启动。