Files
claude-code-mirror/claude-code-中文Wiki/13-配置与迁移系统.md
2026-04-03 13:01:19 +08:00

9.2 KiB

配置与迁移系统

Claude Code 使用 Zod 进行配置模式验证,并通过迁移系统处理配置版本升级。

目录结构

src/
├── schemas/           # Zod 配置模式定义
├── migrations/        # 配置迁移脚本
└── utils/settings/   # 设置管理系统
    ├── settings.ts    # 设置管理核心
    ├── validation.ts  # 验证逻辑
    ├── changeDetector.ts  # 变更检测
    ├── applySettingsChange.ts  # 变更应用
    ├── permissionValidation.ts  # 权限规则验证
    ├── toolValidationConfig.ts  # 工具验证配置
    ├── types.ts      # 类型定义
    ├── constants.ts  # 常量
    ├── mdm/          # 移动设备管理
    └── settingsCache.ts  # 设置缓存

1. 配置模式 (schemas/)

1.1 主模式文件

文件: src/schemas/hooks.ts (7884行)

使用 Zod 定义所有配置项的验证模式。

1.2 核心模式示例

// 基础设置模式
const baseSettingsSchema = z.object({
  // 模型配置
  model: z.string(),
  maxTokens: z.number().optional(),

  // UI 设置
  theme: z.enum(['dark', 'light', 'system']),
  fontSize: z.number().min(8).max(24),

  // 权限设置
  allowPermissions: z.boolean(),
  permissionRules: z.array(permissionRuleSchema).optional(),
})

// MCP 服务器配置
const mcpServerSchema = z.object({
  name: z.string(),
  command: z.string(),
  args: z.array(z.string()).optional(),
  env: z.record(z.string()).optional(),
})

2. 设置管理 (utils/settings/)

2.1 设置核心 (settings.ts)

文件: src/utils/settings/settings.ts (~32KB)

主要函数:

函数 用途
getSettings() 获取当前设置
updateSettings(partial) 更新设置
resetSettings() 重置为默认值
loadManagedFileSettings() 加载托管配置文件
parseSettingsFile(path) 解析设置文件

设置加载优先级 (从低到高):

  1. 默认值
  2. 托管设置文件 (managed-settings.json)
  3. 托管设置 Drop-in 目录 (managed-settings.d/*.json)
  4. 用户设置文件 (~/.claude/settings.json)

托管设置系统:

// 加载托管文件设置
export function loadManagedFileSettings(): {
  settings: SettingsJson | null
  errors: ValidationError[]
} {
  // 1. 加载 managed-settings.json (基础)
  // 2. 按字母顺序加载 managed-settings.d/*.json (覆盖)
}

2.2 变更检测 (changeDetector.ts)

文件: src/utils/settings/changeDetector.ts (~16KB)

检测设置变更并触发相应的处理逻辑。

主要功能:

  • 检测设置项的变化
  • 生成变更事件
  • 防止循环依赖

2.3 变更应用 (applySettingsChange.ts)

文件: src/utils/settings/applySettingsChange.ts

应用设置变更到运行时系统。

// 示例:应用主题变更
async function applyThemeChange(theme: Theme): Promise<void> {
  // 1. 更新渲染器主题
  // 2. 通知所有订阅者
  // 3. 持久化到磁盘
}

2.4 验证 (validation.ts)

文件: src/utils/settings/validation.ts (~8KB)

主要函数:

函数 用途
validateSettings(settings) 验证完整设置
validateSetting(key, value) 验证单个设置
formatZodError(error) 格式化 Zod 错误
filterInvalidPermissionRules(rules) 过滤无效权限规则

验证流程:

export function validateSettings(
  settings: unknown
): SettingsWithErrors {
  const result = SettingsSchema.safeParse(settings)

  if (result.success) {
    return { settings: result.data, errors: [] }
  }

  // 转换 Zod 错误为友好格式
  return {
    settings: null,
    errors: formatZodError(result.error)
  }
}

2.5 权限验证 (permissionValidation.ts)

文件: src/utils/settings/permissionValidation.ts (~8.5KB)

验证权限规则的有效性。

权限规则结构:

interface PermissionRule {
  tool: string              // 工具名称
  path?: string             // 路径模式
  deny?: boolean            // 拒绝还是允许
  reason?: string           // 原因说明
}

验证规则:

  1. 工具名称必须有效
  2. 路径模式必须是有效的 glob 或正则
  3. 冲突规则被拒绝

2.6 工具验证配置 (toolValidationConfig.ts)

文件: src/utils/settings/toolValidationConfig.ts

配置哪些工具需要验证或可以直接执行。

// 免验证工具
const bypassValidationTools = [
  'Read',
  'BackgroundRead',
  'TodoWrite',
  'NotebookEdit',
]

// 需要路径验证的工具
const pathValidationTools = [
  'Bash',
  'Write',
  'Edit',
  'Read',
]

2.7 MDM 配置 (mdm/)

目录: src/utils/settings/mdm/

支持移动设备管理 (Mobile Device Management) 配置。

mdm/
└── settings.ts    # MDM 设置加载

2.8 类型定义 (types.ts)

文件: src/utils/settings/types.ts (~43KB)

定义所有设置相关的类型。

// 设置 JSON 结构
type SettingsJson = {
  // 基本设置
  model?: string
  theme?: 'dark' | 'light' | 'system'

  // MCP
  mcpServers?: Record<string, McpServerConfig>

  // 权限
  permissionRules?: PermissionRule[]

  // 实验性功能
  experimental?: Record<string, boolean>
}

// 设置来源
type SettingSource =
  | 'default'
  | 'managed'
  | 'user'

// 可编辑的设置源
type EditableSettingSource = 'user'

3. 迁移系统 (migrations/)

3.1 迁移文件列表

文件 用途
migrateAutoUpdatesToSettings.ts 自动更新迁移
migrateBypassPermissionsAcceptedToSettings.ts 绕过权限迁移
migrateEnableAllProjectMcpServersToSettings.ts MCP 服务器迁移
migrateFennecToOpus.ts Fennec → Opus 模型迁移
migrateLegacyOpusToCurrent.ts Legacy Opus 迁移
migrateOpusToOpus1m.ts Opus → Opus 1M 迁移
migrateReplBridgeEnabledToRemoteControlAtStartup.ts REPL 桥接迁移
migrateSonnet1mToSonnet45.ts Sonnet 1M → 4.5 迁移
migrateSonnet45ToSonnet46.ts Sonnet 4.5 → 4.6 迁移
resetAutoModeOptInForDefaultOffer.ts 自动模式重置
resetProToOpusDefault.ts Pro → Opus 默认重置

3.2 迁移示例

migrateOpusToOpus1m.ts:

export function migrateOpusToOpus1m(
  oldSettings: LegacySettings
): NewSettings {
  return {
    ...oldSettings,
    model: oldSettings.model === 'opus' ? 'opus-3-5-20241120' : oldSettings.model,
  }
}

3.3 迁移执行时机

迁移在以下时机执行:

  1. 应用启动时
  2. 设置加载前
  3. 版本检测后

4. 常量 (constants.ts)

文件: src/utils/settings/constants.ts (~5.5KB)

// 设置源优先级
const SETTING_SOURCE_PRIORITY: Record<SettingSource, number> = {
  default: 0,
  managed: 50,
  user: 100,
}

// 设置路径
const SETTINGS_DIR = 'settings'
const SETTINGS_FILE = 'settings.json'
const MANAGED_SETTINGS_FILE = 'managed-settings.json'
const MANAGED_SETTINGS_DROPIN_DIR = 'managed-settings.d'

// 默认值
const DEFAULT_MODEL = 'claude-opus-4-5'
const DEFAULT_THEME = 'dark'
const DEFAULT_MAX_TOKENS = 8192

5. 缓存管理 (settingsCache.ts)

文件: src/utils/settings/settingsCache.ts (~2.4KB)

// 缓存接口
interface SettingsCache {
  get(key: string): SettingsJson | null
  set(key: string, value: SettingsJson): void
  invalidate(key: string): void
  clear(): void
}

// 缓存策略
const CACHE_TTL = 5 * 60 * 1000  // 5 分钟
const MAX_CACHE_SIZE = 10

6. 托管设置系统详解

6.1 Drop-in 机制

托管设置支持 Drop-in 目录机制,允许多个配置文件按优先级合并:

~/.claude/settings.json           # 用户设置
/etc/claude/managed-settings.json  # 系统托管基础
/etc/claude/managed-settings.d/
  ├── 10-base.json               # 优先级 10
  ├── 20-security.json           # 优先级 20
  └── 30-otel.json               # 优先级 30

6.2 合并规则

  1. 基础文件先加载
  2. Drop-in 文件按文件名排序后加载
  3. 后加载的文件优先级更高
  4. 数组字段替换,非数组字段合并

7. 配置验证规则

7.1 路径验证

function validatePath(path: string): boolean {
  // 禁止危险路径
  if (path.includes('..')) return false
  if (path.startsWith('/etc/')) return false
  if (path.startsWith('/sys/')) return false

  // 检查权限
  if (!canAccessPath(path)) return false

  return true
}

7.2 命令验证

function validateCommand(command: string): boolean {
  // 白名单检查
  const allowedCommands = ['read', 'edit', 'bash']
  return allowedCommands.includes(command)
}

7.3 模型名称验证

const VALID_MODELS = [
  'claude-opus-4-5',
  'claude-sonnet-4-6',
  'claude-opus-3-5-20241120',
  // ...
]

function validateModel(model: string): boolean {
  return VALID_MODELS.includes(model)
}

8. 内部写入标识 (internalWrites.ts)

文件: src/utils/settings/internalWrites.ts

标识由系统内部触发的设置写入,防止来自用户配置文件的覆盖。

// 标记内部写入
export function markInternalWrite(key: string): void {
  internalWrites.add(key)
}

// 检查是否为内部写入
export function isInternalWrite(key: string): boolean {
  return internalWrites.has(key)
}