Claude Code 源码分析Claude Code 源码分析
首页
源码统计
系统架构
UML 图表
工具系统
CodeGraph
首页
源码统计
系统架构
UML 图表
工具系统
CodeGraph
  • 概览

    • Claude Code 源码分析
    • 源码统计
    • CodeGraph 图谱
  • 架构

    • 系统架构
    • UML 图表索引
    • 查询引擎
    • 核心流程
    • 消息系统
    • 状态管理
  • 功能模块

    • 工具系统
    • 斜杠命令
    • 服务层
    • MCP 协议
    • Skills 技能
    • 子代理系统
  • 分层深度

    • 入口层
    • UI / Ink 层
    • utils 基础设施
    • 桥接 / 远程
    • 上下文压缩
  • 原理与安全

    • 底层原理
    • 技术难点
    • 权限与安全
    • 内部机制
    • 遥测与分析
  • 深度专题

    • Hooks 系统
    • 插件系统
    • 记忆系统
    • API 通信层
    • Ink 终端 UI
    • 认证系统
    • 构建与发布
    • 术语表
  • 调用分析

    • 调用链分析
    • 核心文件索引
  • 模块详解

    • utils

      • 模块: utils
      • messages · 消息工厂与规范化
      • session-storage · JSONL 会话持久化
      • permissions · 工具权限决策
      • shell-hooks · 用户 Shell Hook 系统
    • components

      • 模块: components
      • REPL · 主屏编排
      • messages · 消息行渲染
      • PermissionRequest · 权限弹窗
      • PromptInput · 底部输入
    • services

      • 模块: services
      • api-claude · Anthropic API 流式与重试
      • mcp-client · MCP 连接与工具调用
      • compact · 上下文压缩与自动触发
      • analytics · GrowthBook、Datadog 与 1P 事件
    • tools

      • 模块: tools
      • tool-interface · Tool 契约与注册表
      • bash-tool · Shell 执行与权限
      • streaming-executor · 流式工具并发调度
      • agent-tool · 子 Agent 委派
    • commands

      • 模块: commands
      • command-registry · commands.ts 注册与分派
      • model-command · /model 模型选择
      • mcp-commands · /mcp 服务器管理
      • compact-memory-commands · /compact 与 /memory
    • ink

      • 模块: ink
      • Ink 渲染管线 · Screen 与终端输出
      • 终端事件 · resize、paste、stdin
      • Ink Hooks · 输入、搜索、终端状态
      • Ink 组件 · Box、Text、ScrollBox 原语
    • hooks

      • 模块: hooks
      • useCanUseTool · 权限 UI 接缝
      • 输入与快捷键 Hook
      • 合并态 Hook(MCP + 本地)
      • notifs 通知 Hook
    • bridge

      • 模块: bridge
      • repl-bridge · REPL 桥初始化与传输
      • bridge-messaging · 桥消息路由与入站处理
      • remote-bridge-core · env-less 核心与守护主循环
      • bridge-permissions-ui · 权限、API 与 TUI
    • cli

      • 模块: cli
      • Structured IO · NDJSON SDK 协议
      • CLI Transports · Session Ingress 传输层
      • CLI Handlers · 子命令懒加载实现
      • Update & Upload · 自更新与串行上传原语
    • screens

      • 模块: screens
      • REPL 屏 · Screen 类型与顶层路由
      • ResumeConversation · 会话恢复选择器
      • Doctor · 安装诊断全屏
    • entrypoints

      • 模块: entrypoints
      • cli-entrypoint · Bootstrap 与快路径
      • sdk-types · core / control / runtime 类型体系
      • mcp-entrypoint · MCP stdio 服务器
      • sandbox-types · 沙箱配置单一真相源
    • skills

      • 模块: skills
      • skills-loading · 磁盘加载与 bundled 注册表
      • bundled-skills · 内置 skill 与 initBundledSkills
      • mcp-skills · MCP prompt 转 skill
      • skill-tool-integration · SkillTool 与命令注册
    • types

      • 模块: types
      • message-types · Message 联合与 content blocks
      • tool-permission-types · Tool、Permission、Command 类型
      • api-sdk-types · API 与 Hooks 协议类型
      • misc-types · ids、plugin、generated 与其余类型
    • tasks

      • 模块: tasks
      • local-agent-task · 本地 Agent 与主会话后台化
      • remote-agent-task · 远程 CCR 与 In-Process Teammate
      • shell-workflow-tasks · Bash 后台、Workflow 与 stopTask
      • dream-monitor-tasks · Dream、Monitor MCP 与 pill 文案
    • keybindings

      • 模块: keybindings
      • keybinding-registry · 注册、Provider 与 useKeybinding
      • default-bindings · 默认键位表与平台差异
      • command-bindings · command:* 动态斜杠命令绑定
      • vim-bindings · Vim 模式与 keybindings 边界
    • memdir

      • 模块: memdir
      • memdir-core · 路径、加载与 MEMORY.md
      • memory-extraction · extractMemories 与 SessionMemory
      • memdir-commands · /memory、/remember 与命令集成
    • state

      • 模块: state
      • app-state-core · store、AppState 类型与 Provider
      • app-state-selectors · selectors 与 onChangeAppState
      • teammate-state · 队友视图与 swarm 状态
      • state-boundaries · bootstrap、sessionStorage、FileStateCache
    • query

      • 模块: query
      • query config 与 deps · 配置快照与依赖注入
      • query tokenBudget · +500k 自动续跑
      • query transitions · Continue / Terminal 状态机
      • query stopHooks · Stop 事件与 turn 结束编排
  • 模块详解(扩展)

    • messages · 消息工厂与规范化
    • session-storage · JSONL 会话持久化
    • permissions · 工具权限决策
    • shell-hooks · 用户 Shell Hook 系统
    • REPL · 主屏编排
    • messages · 消息行渲染
    • PermissionRequest · 权限弹窗
    • PromptInput · 底部输入
    • api-claude · Anthropic API 流式与重试
    • mcp-client · MCP 连接与工具调用
    • compact · 上下文压缩与自动触发
    • analytics · GrowthBook、Datadog 与 1P 事件
    • tool-interface · Tool 契约与注册表
    • bash-tool · Shell 执行与权限
    • streaming-executor · 流式工具并发调度
    • agent-tool · 子 Agent 委派
    • command-registry · commands.ts 注册与分派
    • model-command · /model 模型选择
    • mcp-commands · /mcp 服务器管理
    • compact-memory-commands · /compact 与 /memory
    • Ink 渲染管线 · Screen 与终端输出
    • 终端事件 · resize、paste、stdin
    • Ink Hooks · 输入、搜索、终端状态
    • Ink 组件 · Box、Text、ScrollBox 原语
    • useCanUseTool · 权限 UI 接缝
    • 输入与快捷键 Hook
    • 合并态 Hook(MCP + 本地)
    • notifs 通知 Hook
    • repl-bridge · REPL 桥初始化与传输
    • bridge-messaging · 桥消息路由与入站处理
    • remote-bridge-core · env-less 核心与守护主循环
    • bridge-permissions-ui · 权限、API 与 TUI
    • Structured IO · NDJSON SDK 协议
    • CLI Transports · Session Ingress 传输层
    • CLI Handlers · 子命令懒加载实现
    • Update & Upload · 自更新与串行上传原语
    • REPL 屏 · Screen 类型与顶层路由
    • ResumeConversation · 会话恢复选择器
    • Doctor · 安装诊断全屏
    • cli-entrypoint · Bootstrap 与快路径
    • sdk-types · core / control / runtime 类型体系
    • mcp-entrypoint · MCP stdio 服务器
    • sandbox-types · 沙箱配置单一真相源
    • skills-loading · 磁盘加载与 bundled 注册表
    • bundled-skills · 内置 skill 与 initBundledSkills
    • mcp-skills · MCP prompt 转 skill
    • skill-tool-integration · SkillTool 与命令注册
    • message-types · Message 联合与 content blocks
    • tool-permission-types · Tool、Permission、Command 类型
    • api-sdk-types · API 与 Hooks 协议类型
    • misc-types · ids、plugin、generated 与其余类型
    • local-agent-task · 本地 Agent 与主会话后台化
    • remote-agent-task · 远程 CCR 与 In-Process Teammate
    • shell-workflow-tasks · Bash 后台、Workflow 与 stopTask
    • dream-monitor-tasks · Dream、Monitor MCP 与 pill 文案
    • keybinding-registry · 注册、Provider 与 useKeybinding
    • default-bindings · 默认键位表与平台差异
    • command-bindings · command:* 动态斜杠命令绑定
    • vim-bindings · Vim 模式与 keybindings 边界
    • memdir-core · 路径、加载与 MEMORY.md
    • memory-extraction · extractMemories 与 SessionMemory
    • memdir-commands · /memory、/remember 与命令集成
    • app-state-core · store、AppState 类型与 Provider
    • app-state-selectors · selectors 与 onChangeAppState
    • teammate-state · 队友视图与 swarm 状态
    • state-boundaries · bootstrap、sessionStorage、FileStateCache
    • query config 与 deps · 配置快照与依赖注入
    • query tokenBudget · +500k 自动续跑
    • query transitions · Continue / Terminal 状态机
    • query stopHooks · Stop 事件与 turn 结束编排
  • 工具详解

    • tool-interface · Tool 契约与注册表
    • tool-permission-types · Tool、Permission、Command 类型
    • 工具: Bash
    • 工具: PowerShell
    • 工具: Agent
    • 工具: LSP
    • 工具: FileEdit
    • 工具: FileRead
    • 工具: Skill
    • 工具: WebFetch
    • 工具: MCP
    • 工具: SendMessage
    • 工具: FileWrite
    • 工具: Config
    • 工具: Grep
    • 工具: Brief
    • 工具: ExitPlanMode
    • 工具: ToolSearch
    • 工具: NotebookEdit
    • 工具: TaskOutput
    • 工具: WebSearch
    • 工具: ScheduleCron

本章总览

先建立地图:misc-types 负责承接核心主干之外的“边界约束类型”,保证 ID、插件、输入状态、生成代码与轻量工具类型不会互相污染。对应到源码,它把 ids.ts、plugin.ts、textInputTypes.ts、utils.ts 与 generated/ 这几类不同稳定性的类型分层组织。

学完本章你应该能

  • 使用 asSessionId / toAgentId 品牌类型防止 ID 混用
  • 理解 LoadedPlugin 与 PluginManifest 的字段分工
  • 知道 DeepImmutable 在 AppState 上的应用与例外
  • 阅读 textInputTypes 与 useVimInput 的模式状态
  • 区分 generated/ 手改禁止与消费方式
  • 能在 analytics 找到 claude_code_internal_event 用法

核心概念(先读懂这些)

Branded types 防呆

SessionId 与 AgentId 是 string & { __brand },编译期不可互换。toAgentId 用 AGENT_ID_PATTERN 校验 createAgentId 格式,teammate 名称等非 agent id 返回 null。运行时仍是一般的 string,品牌仅在 TS 层。

plugin.ts 桥接 marketplace 与 runtime

LoadedPlugin 聚合 manifest、path、commandsPaths、hooksConfig、mcpServers、lspServers。PluginError 判别联合区分 manifest 解析、git clone、版本冲突等。BuiltinPluginDefinition 描述内置插件默认启用与 isAvailable 门控。

generated/ 是 analytics 与 GrowthBook 的 schema 源

claude_code_internal_event.ts、growthbook_experiment_event.ts、auth.ts、timestamp.ts 由 codegen 生成,types/ 手改类型与之并存。业务代码 import generated 类型发 tengu_* 事件,不在 generated 内加业务逻辑。

建议学习步骤

  1. 阅读 ids.ts 品牌函数与 AGENT_ID_PATTERN
  2. 浏览 plugin.ts LoadedPlugin 与 PluginError
  3. 打开 utils.ts DeepImmutable 定义
  4. 阅读 textInputTypes VimMode 与 VimInputState
  5. 扫一眼 generated/claude_code_internal_event 结构
  6. 在 services/analytics 搜索 import generated

常见误区

注意

plugin.ts re-export PluginManifest 自 utils/plugins/schemas——改 manifest 先改 schema

注意

statusLine.ts 极薄,StatusLineItem 用 Record 松散类型

注意

notebook.ts 与 Jupyter 导出相关,与 memdir 无关

注意

勿编辑 generated/ 文件,重新 codegen 会覆盖

ids.ts 品牌类型

类型含义工厂
SessionIdClaude Code 会话getSessionId(), asSessionId()
AgentId会话内 subagentcreateAgentId(), toAgentId()

AGENT_ID_PATTERN = ^a(?:.+-)?[0-9a-f]{16}$——可选 label 前缀 + 16 hex。teammate 寻址字符串不匹配则 toAgentId 返回 null,避免误当 subagent transcript 过滤。

源码引用: src/types/ids.ts · 第 6–17 行(共 45 行)

   6| /**
   7|  * A session ID uniquely identifies a Claude Code session.
   8|  * Returned by getSessionId().
   9|  */
  10| export type SessionId = string & { readonly __brand: 'SessionId' }
  11| 
  12| /**
  13|  * An agent ID uniquely identifies a subagent within a session.
  14|  * Returned by createAgentId().
  15|  * When present, indicates the context is a subagent (not the main session).
  16|  */
  17| export type AgentId = string & { readonly __brand: 'AgentId' }

源码引用: src/types/ids.ts · 第 35–44 行(共 45 行)

  35| const AGENT_ID_PATTERN = /^a(?:.+-)?[0-9a-f]{16}$/
  36| 
  37| /**
  38|  * Validate and brand a string as AgentId.
  39|  * Matches the format produced by createAgentId(): `a` + optional `<label>-` + 16 hex chars.
  40|  * Returns null if the string doesn't match (e.g. teammate names, team-addressing).
  41|  */
  42| export function toAgentId(s: string): AgentId | null {
  43|   return AGENT_ID_PATTERN.test(s) ? (s as AgentId) : null
  44| }

plugin.ts 插件类型族

BuiltinPluginDefinition:name、description、skills、hooks、mcpServers、defaultEnabled、isAvailable()。

LoadedPlugin:运行时实例,含 commandsPaths[]、agentsPaths[]、sha(marketplace pin)、isBuiltin。

PluginError 联合覆盖 manifestValidation、cloneFailed、incompatibleVersion 等,/plugin UI 与 Doctor 展示人类可读错误。

PluginComponent = commands | agents | skills | hooks | output-styles,用于按组件 reload。

源码引用: src/types/plugin.ts · 第 18–35 行(共 364 行)

  18| export type BuiltinPluginDefinition = {
  19|   /** Plugin name (used in `{name}@builtin` identifier) */
  20|   name: string
  21|   /** Description shown in the /plugin UI */
  22|   description: string
  23|   /** Optional version string */
  24|   version?: string
  25|   /** Skills provided by this plugin */
  26|   skills?: BundledSkillDefinition[]
  27|   /** Hooks provided by this plugin */
  28|   hooks?: HooksSettings
  29|   /** MCP servers provided by this plugin */
  30|   mcpServers?: Record<string, McpServerConfig>
  31|   /** Whether this plugin is available (e.g. based on system capabilities). Unavailable plugins are hidden entirely. */
  32|   isAvailable?: () => boolean
  33|   /** Default enabled state before the user sets a preference (defaults to true) */
  34|   defaultEnabled?: boolean
  35| }

源码引用: src/types/plugin.ts · 第 48–70 行(共 364 行)

  48| export type LoadedPlugin = {
  49|   name: string
  50|   manifest: PluginManifest
  51|   path: string
  52|   source: string
  53|   repository: string // Repository identifier, usually same as source
  54|   enabled?: boolean
  55|   isBuiltin?: boolean // true for built-in plugins that ship with the CLI
  56|   sha?: string // Git commit SHA for version pinning (from marketplace entry source)
  57|   commandsPath?: string
  58|   commandsPaths?: string[] // Additional command paths from manifest
  59|   commandsMetadata?: Record<string, CommandMetadata> // Metadata for named commands from object-mapping format
  60|   agentsPath?: string
  61|   agentsPaths?: string[] // Additional agent paths from manifest
  62|   skillsPath?: string
  63|   skillsPaths?: string[] // Additional skill paths from manifest
  64|   outputStylesPath?: string
  65|   outputStylesPaths?: string[] // Additional output style paths from manifest
  66|   hooksConfig?: HooksSettings
  67|   mcpServers?: Record<string, McpServerConfig>
  68|   lspServers?: Record<string, LspServerConfig>
  69|   settings?: Record<string, unknown>
  70| }

源码引用: src/types/plugin.ts · 第 72–120 行(共 364 行)

  72| export type PluginComponent =
  73|   | 'commands'
  74|   | 'agents'
  75|   | 'skills'
  76|   | 'hooks'
  77|   | 'output-styles'
  78| 
  79| /**
  80|  * Discriminated union of plugin error types.
  81|  * Each error type has specific contextual data for better debugging and user guidance.
  82|  *
  83|  * This replaces the previous string-based error matching approach with type-safe
  84|  * error handling that can't break when error messages change.
  85|  *
  86|  * IMPLEMENTATION STATUS:
  87|  * Currently used in production (2 types):
  88|  * - generic-error: Used for various plugin loading failures
  89|  * - plugin-not-found: Used when plugin not found in marketplace
  90|  *
  91|  * Planned for future use (10 types - see TODOs in pluginLoader.ts):
  92|  * - path-not-found, git-auth-failed, git-timeout, network-error
  93|  * - manifest-parse-error, manifest-validation-error
  94|  * - marketplace-not-found, marketplace-load-failed
  95|  * - mcp-config-invalid, hook-load-failed, component-load-failed
  96|  *
  97|  * These unused types support UI formatting and provide a clear roadmap for
  98|  * improving error specificity. They can be incrementally implemented as
  99|  * error creation sites are refactored.
 100|  */
 101| export type PluginError =
 102|   | {
 103|       type: 'path-not-found'
 104|       source: string
 105|       plugin?: string
 106|       path: string
 107|       component: PluginComponent
 108|     }
 109|   | {
 110|       type: 'git-auth-failed'
 111|       source: string
 112|       plugin?: string
 113|       gitUrl: string
 114|       authType: 'ssh' | 'https'
 115|     }
 116|   | {
 117|       type: 'git-timeout'
 118|       source: string
 119|       plugin?: string
 120|       gitUrl: string

utils.ts 与 textInputTypes.ts

DeepImmutable 递归 readonly,AppState 主体使用;Map/Set/含函数字段除外。

textInputTypes.ts 定义 VimMode = NORMAL | INSERT,VimInputState 暴露 mode、offset、handleVimInput 等给 VimTextInput。与 keybindings 模块分离——Esc 切 NORMAL 不走可配置 binding(见 vim-bindings 子章节)。

fileSuggestion.ts、connectorText.ts 服务 autocomplete 与连接器文案类型。

源码引用: src/types/utils.ts · 第 1–10 行(共 10 行)

   1| export type DeepImmutable<T> = T extends (...args: never[]) => unknown
   2|   ? T
   3|   : T extends readonly (infer U)[]
   4|     ? ReadonlyArray<DeepImmutable<U>>
   5|     : T extends object
   6|       ? { readonly [K in keyof T]: DeepImmutable<T[K]> }
   7|       : T
   8| 
   9| export type Permutations<T> = T
  10| 

源码引用: src/types/textInputTypes.ts · 第 1–50 行(共 388 行)

   1| import type { ContentBlockParam } from '@anthropic-ai/sdk/resources/messages.mjs'
   2| import type { UUID } from 'crypto'
   3| import type React from 'react'
   4| import type { PermissionResult } from '../entrypoints/agentSdkTypes.js'
   5| import type { Key } from '../ink.js'
   6| import type { PastedContent } from '../utils/config.js'
   7| import type { ImageDimensions } from '../utils/imageResizer.js'
   8| import type { TextHighlight } from '../utils/textHighlighting.js'
   9| import type { AgentId } from './ids.js'
  10| import type { AssistantMessage, MessageOrigin } from './message.js'
  11| 
  12| /**
  13|  * Inline ghost text for mid-input command autocomplete
  14|  */
  15| export type InlineGhostText = {
  16|   /** The ghost text to display (e.g., "mit" for /commit) */
  17|   readonly text: string
  18|   /** The full command name (e.g., "commit") */
  19|   readonly fullCommand: string
  20|   /** Position in the input where the ghost text should appear */
  21|   readonly insertPosition: number
  22| }
  23| 
  24| /**
  25|  * Base props for text input components
  26|  */
  27| export type BaseTextInputProps = {
  28|   /**
  29|    * Optional callback for handling history navigation on up arrow at start of input
  30|    */
  31|   readonly onHistoryUp?: () => void
  32| 
  33|   /**
  34|    * Optional callback for handling history navigation on down arrow at end of input
  35|    */
  36|   readonly onHistoryDown?: () => void
  37| 
  38|   /**
  39|    * Text to display when `value` is empty.
  40|    */
  41|   readonly placeholder?: string
  42| 
  43|   /**
  44|    * Allow multi-line input via line ending with backslash (default: `true`)
  45|    */
  46|   readonly multiline?: boolean
  47| 
  48|   /**
  49|    * Listen to user's input. Useful in case there are multiple input components
  50|    * at the same time and input must be "routed" to a specific component.

源码引用: src/types/fileSuggestion.ts · 第 1–2 行(共 2 行)

   1| export type FileSuggestion = Record<string, unknown>
   2| 

statusLine 与 notebook

StatusLineItem = Record<string, unknown>——statusline 插件 JSON 输出松散解析,避免每种 item 形状都进中央类型。

notebook.ts 定义 notebook 导出单元结构(cells、metadata),供特定 export 路径使用,与 REPL transcript 类型正交。

源码引用: src/types/statusLine.ts · 第 1–2 行(共 2 行)

   1| export type StatusLineItem = Record<string, unknown>
   2| 

源码引用: src/types/notebook.ts · 第 1–2 行(共 2 行)

   1| export type NotebookCell = Record<string, unknown>
   2| 

generated/ protobuf 事件

claude_code_internal_event.ts 定义 tengu 内部 analytics 事件 protobuf 消息类型,体积最大(数千行)。growthbook_experiment_event.ts 对接 GrowthBook experiment 上报。auth.ts、timestamp.ts 为公共子消息。

消费模式:

业务 logEvent('tengu_*', metadata)
  → metadata 类型与 generated 字段对齐
  → 批量上传 events pipeline

types/ 手写的 message、plugin 类型 不 import generated,保持 REPL 核心与 analytics codegen 解耦。

源码引用: src/types/generated/events_mono/claude_code/v1/claude_code_internal_event.ts · 第 1–60 行(共 866 行)

   1| // Code generated by protoc-gen-ts_proto. DO NOT EDIT.
   2| // versions:
   3| //   protoc-gen-ts_proto  v2.6.1
   4| //   protoc               unknown
   5| // source: events_mono/claude_code/v1/claude_code_internal_event.proto
   6| 
   7| /* eslint-disable */
   8| import { Timestamp } from '../../../google/protobuf/timestamp.js'
   9| import { PublicApiAuth } from '../../common/v1/auth.js'
  10| 
  11| /** GitHubActionsMetadata contains GitHub Actions-specific environment information */
  12| export interface GitHubActionsMetadata {
  13|   actor_id?: string | undefined
  14|   repository_id?: string | undefined
  15|   repository_owner_id?: string | undefined
  16| }
  17| 
  18| /**
  19|  * EnvironmentMetadata contains environment and runtime information
  20|  * See claude-cli-internal/src/services/statsig.ts for the source of these fields
  21|  */
  22| export interface EnvironmentMetadata {
  23|   platform?: string | undefined
  24|   node_version?: string | undefined
  25|   terminal?: string | undefined
  26|   package_managers?: string | undefined
  27|   runtimes?: string | undefined
  28|   is_running_with_bun?: boolean | undefined
  29|   is_ci?: boolean | undefined
  30|   is_claubbit?: boolean | undefined
  31|   is_github_action?: boolean | undefined
  32|   is_claude_code_action?: boolean | undefined
  33|   is_claude_ai_auth?: boolean | undefined
  34|   version?: string | undefined
  35|   /** GitHub Actions specific fields (only present when is_github_action is true) */
  36|   github_event_name?: string | undefined
  37|   github_actions_runner_environment?: string | undefined
  38|   github_actions_runner_os?: string | undefined
  39|   github_action_ref?: string | undefined
  40|   /** WSL specific field */
  41|   wsl_version?: string | undefined
  42|   /** GitHub metadata (only present when is_github_action is true) */
  43|   github_actions_metadata?: GitHubActionsMetadata | undefined
  44|   arch?: string | undefined
  45|   is_claude_code_remote?: boolean | undefined
  46|   remote_environment_type?: string | undefined
  47|   claude_code_container_id?: string | undefined
  48|   claude_code_remote_session_id?: string | undefined
  49|   tags?: string[] | undefined
  50|   deployment_environment?: string | undefined
  51|   is_conductor?: boolean | undefined
  52|   version_base?: string | undefined
  53|   coworker_type?: string | undefined
  54|   build_time?: string | undefined
  55|   is_local_agent_mode?: boolean | undefined
  56|   linux_distro_id?: string | undefined
  57|   linux_distro_version?: string | undefined
  58|   linux_kernel?: string | undefined
  59|   vcs?: string | undefined
  60|   platform_raw?: string | undefined

源码引用: src/types/generated/events_mono/growthbook/v1/growthbook_experiment_event.ts · 第 1–40 行(共 224 行)

   1| // Code generated by protoc-gen-ts_proto. DO NOT EDIT.
   2| // versions:
   3| //   protoc-gen-ts_proto  v2.6.1
   4| //   protoc               unknown
   5| // source: events_mono/growthbook/v1/growthbook_experiment_event.proto
   6| 
   7| /* eslint-disable */
   8| import { Timestamp } from '../../../google/protobuf/timestamp.js'
   9| import { PublicApiAuth } from '../../common/v1/auth.js'
  10| 
  11| /**
  12|  * GrowthBook experiment assignment event
  13|  * This event tracks when a user is exposed to an experiment variant
  14|  * See: https://docs.growthbook.io/guide/bigquery
  15|  */
  16| export interface GrowthbookExperimentEvent {
  17|   /** Unique event identifier (for deduplication) */
  18|   event_id?: string | undefined
  19|   /** When user was exposed to experiment (maps to GrowthBook's timestamp column) */
  20|   timestamp?: Date | undefined
  21|   /** Experiment tracking key (maps to GrowthBook's experiment_id column) */
  22|   experiment_id?: string | undefined
  23|   /** Variation index: 0=control, 1+=variants (maps to GrowthBook's variation_id column) */
  24|   variation_id?: number | undefined
  25|   /** Environment where assignment occurred */
  26|   environment?: string | undefined
  27|   /** User attributes at time of assignment */
  28|   user_attributes?: string | undefined
  29|   /** Experiment metadata */
  30|   experiment_metadata?: string | undefined
  31|   /** Device identifier for the client */
  32|   device_id?: string | undefined
  33|   /** Authentication context automatically injected by the API */
  34|   auth?: PublicApiAuth | undefined
  35|   /** Session identifier for tracking user sessions */
  36|   session_id?: string | undefined
  37|   /** Anonymous identifier for unauthenticated users */
  38|   anonymous_id?: string | undefined
  39|   /** Event metadata variables (automatically populated by internal-tools-common event_logging library) */
  40|   event_metadata_vars?: string | undefined

源码引用: src/types/generated/events_mono/common/v1/auth.ts · 第 1–30 行(共 101 行)

   1| // Code generated by protoc-gen-ts_proto. DO NOT EDIT.
   2| // versions:
   3| //   protoc-gen-ts_proto  v2.6.1
   4| //   protoc               unknown
   5| // source: events_mono/common/v1/auth.proto
   6| 
   7| /* eslint-disable */
   8| 
   9| /** PublicApiAuth contains authentication context automatically injected by the API */
  10| export interface PublicApiAuth {
  11|   account_id?: number | undefined
  12|   organization_uuid?: string | undefined
  13|   account_uuid?: string | undefined
  14| }
  15| 
  16| function createBasePublicApiAuth(): PublicApiAuth {
  17|   return { account_id: 0, organization_uuid: '', account_uuid: '' }
  18| }
  19| 
  20| export const PublicApiAuth: MessageFns<PublicApiAuth> = {
  21|   fromJSON(object: any): PublicApiAuth {
  22|     return {
  23|       account_id: isSet(object.account_id)
  24|         ? globalThis.Number(object.account_id)
  25|         : 0,
  26|       organization_uuid: isSet(object.organization_uuid)
  27|         ? globalThis.String(object.organization_uuid)
  28|         : '',
  29|       account_uuid: isSet(object.account_uuid)
  30|         ? globalThis.String(object.account_uuid)

connectorText 与 messageQueue 交叉引用

connectorText.ts 类型化 MCP connector 展示字符串,避免 UI 硬编码。

messageQueueTypes.ts(见 message-types 章)与 ids.ts 在 task/agent 寻址场景交汇——Background task UI 用 AgentId 过滤 transcript。

misc 文件虽小,grep import 'types/' 时高频出现,值得单独索引。

源码引用: src/types/connectorText.ts · 第 1–10 行(共 10 行)

   1| export type ConnectorTextBlock = {
   2|   type?: string
   3|   text?: string
   4|   [key: string]: unknown
   5| }
   6| 
   7| export function isConnectorTextBlock(value: unknown): value is ConnectorTextBlock {
   8|   return !!value && typeof value === 'object' && 'text' in (value as Record<string, unknown>)
   9| }
  10| 

源码引用: src/types/messageQueueTypes.ts · 第 1–2 行(共 2 行)

   1| export type MessageQueueEntry = Record<string, unknown>
   2| 

types/ 行数分布提示

19 文件中 generated/ 约占 70% 行数;手写类型以 message、permissions、command、hooks、plugin 为核心。读源码时优先手写文件,generated 当字典查阅。

升级 protobuf codegen 后跑 TypeScript build,analytics metadata 类型错误通常指向 generated 字段 rename。

长尾类型的共同模式

misc-types 里的文件看起来分散,但共同目标都是“让边界更难被误用”。ids.ts 用 branded string 区分 SessionId 与 AgentId,运行时仍是字符串,编译期却能防止把 subagent id 当成 session id 传入 transcript 或 analytics。plugin.ts 把 BuiltinPluginDefinition、LoadedPlugin、PluginComponent、PluginError 拆清楚:manifest 是外部声明,LoadedPlugin 是解析后的运行时实体,PluginError 是 UI/Doctor 能展示的结构化失败。textInputTypes.ts 则把 VimMode、VimInputState 放在纯类型层,让 hooks/useVimInput 和组件共享状态形状,却不让 types/ 反向 import React 组件。

阅读这些小文件时,可以按“来源、运行时形态、消费点”三步归类。来源可能是用户配置、插件 manifest、终端输入、protobuf codegen 或会话 id;运行时形态可能是品牌字符串、Record 松散对象、判别联合或只读工具类型;消费点则通常在 UI、analytics、commands 或 hooks。只要抓住这个模式,就不会因为文件短而忽略其约束作用。尤其 generated/ 不应手改,plugin manifest 字段应先改 schema,Vim 输入类型应先看 hooks/useVimInput 的实际返回值,再决定是否扩展 textInputTypes。

这些长尾类型还有一个共同特征:它们经常承担跨模块“薄适配层”。StatusLineItem 用 Record 接住插件输出,是因为 statusline 内容由外部脚本决定;connectorText 把连接器文案集中,避免多个组件手写同一展示结构;fileSuggestion 和 notebook 则服务特定 UI 或导出路径,不应被 message、permission、hooks 等核心类型反向依赖。把薄类型保留在 types/ 中,可以让消费方 import 一个稳定名字,而实现细节仍留在 utils、components 或 services。

维护时不要因为类型文件短就随手扩大范围。例如给 LoadedPlugin 增字段,要检查插件 loader、marketplace pin、/plugin UI 和 Doctor;给 AgentId 放宽 pattern,要确认 subagent transcript、teammate 寻址和 analytics 是否仍能区分;给 VimInputState 加方法,要确认 useVimInput、VimTextInput、PromptInput 三处都能提供同一语义。misc-types 的价值正是在这些边界处阻止“看似都是字符串或对象”的混用。

如果某个新增类型暂时只被一个实现使用,先放在实现相邻文件通常更清晰;只有当它成为多个模块的共享语言,才提升到 types/。这能避免 types/ 变成杂物桶,也能让读者根据目录推断稳定性。

源码引用: src/types/ids.ts · 第 1–44 行(共 45 行)

   1| /**
   2|  * Branded types for session and agent IDs.
   3|  * These prevent accidentally mixing up session IDs and agent IDs at compile time.
   4|  */
   5| 
   6| /**
   7|  * A session ID uniquely identifies a Claude Code session.
   8|  * Returned by getSessionId().
   9|  */
  10| export type SessionId = string & { readonly __brand: 'SessionId' }
  11| 
  12| /**
  13|  * An agent ID uniquely identifies a subagent within a session.
  14|  * Returned by createAgentId().
  15|  * When present, indicates the context is a subagent (not the main session).
  16|  */
  17| export type AgentId = string & { readonly __brand: 'AgentId' }
  18| 
  19| /**
  20|  * Cast a raw string to SessionId.
  21|  * Use sparingly - prefer getSessionId() when possible.
  22|  */
  23| export function asSessionId(id: string): SessionId {
  24|   return id as SessionId
  25| }
  26| 
  27| /**
  28|  * Cast a raw string to AgentId.
  29|  * Use sparingly - prefer createAgentId() when possible.
  30|  */
  31| export function asAgentId(id: string): AgentId {
  32|   return id as AgentId
  33| }
  34| 
  35| const AGENT_ID_PATTERN = /^a(?:.+-)?[0-9a-f]{16}$/
  36| 
  37| /**
  38|  * Validate and brand a string as AgentId.
  39|  * Matches the format produced by createAgentId(): `a` + optional `<label>-` + 16 hex chars.
  40|  * Returns null if the string doesn't match (e.g. teammate names, team-addressing).
  41|  */
  42| export function toAgentId(s: string): AgentId | null {
  43|   return AGENT_ID_PATTERN.test(s) ? (s as AgentId) : null
  44| }

源码引用: src/types/plugin.ts · 第 18–70 行(共 364 行)

  18| export type BuiltinPluginDefinition = {
  19|   /** Plugin name (used in `{name}@builtin` identifier) */
  20|   name: string
  21|   /** Description shown in the /plugin UI */
  22|   description: string
  23|   /** Optional version string */
  24|   version?: string
  25|   /** Skills provided by this plugin */
  26|   skills?: BundledSkillDefinition[]
  27|   /** Hooks provided by this plugin */
  28|   hooks?: HooksSettings
  29|   /** MCP servers provided by this plugin */
  30|   mcpServers?: Record<string, McpServerConfig>
  31|   /** Whether this plugin is available (e.g. based on system capabilities). Unavailable plugins are hidden entirely. */
  32|   isAvailable?: () => boolean
  33|   /** Default enabled state before the user sets a preference (defaults to true) */
  34|   defaultEnabled?: boolean
  35| }
  36| 
  37| export type PluginRepository = {
  38|   url: string
  39|   branch: string
  40|   lastUpdated?: string
  41|   commitSha?: string
  42| }
  43| 
  44| export type PluginConfig = {
  45|   repositories: Record<string, PluginRepository>
  46| }
  47| 
  48| export type LoadedPlugin = {
  49|   name: string
  50|   manifest: PluginManifest
  51|   path: string
  52|   source: string
  53|   repository: string // Repository identifier, usually same as source
  54|   enabled?: boolean
  55|   isBuiltin?: boolean // true for built-in plugins that ship with the CLI
  56|   sha?: string // Git commit SHA for version pinning (from marketplace entry source)
  57|   commandsPath?: string
  58|   commandsPaths?: string[] // Additional command paths from manifest
  59|   commandsMetadata?: Record<string, CommandMetadata> // Metadata for named commands from object-mapping format
  60|   agentsPath?: string
  61|   agentsPaths?: string[] // Additional agent paths from manifest
  62|   skillsPath?: string
  63|   skillsPaths?: string[] // Additional skill paths from manifest
  64|   outputStylesPath?: string
  65|   outputStylesPaths?: string[] // Additional output style paths from manifest
  66|   hooksConfig?: HooksSettings
  67|   mcpServers?: Record<string, McpServerConfig>
  68|   lspServers?: Record<string, LspServerConfig>
  69|   settings?: Record<string, unknown>
  70| }

源码引用: src/types/textInputTypes.ts · 第 208–260 行(共 388 行)

 208|   /**
 209|    * Initial vim mode to use
 210|    */
 211|   readonly initialMode?: VimMode
 212| 
 213|   /**
 214|    * Optional callback for mode changes
 215|    */
 216|   readonly onModeChange?: (mode: VimMode) => void
 217| }
 218| 
 219| /**
 220|  * Vim editor modes
 221|  */
 222| export type VimMode = 'INSERT' | 'NORMAL'
 223| 
 224| /**
 225|  * Common properties for input hook results
 226|  */
 227| export type BaseInputState = {
 228|   onInput: (input: string, key: Key) => void
 229|   renderedValue: string
 230|   offset: number
 231|   setOffset: (offset: number) => void
 232|   /** Cursor line (0-indexed) within the rendered text, accounting for wrapping. */
 233|   cursorLine: number
 234|   /** Cursor column (display-width) within the current line. */
 235|   cursorColumn: number
 236|   /** Character offset in the full text where the viewport starts (0 when no windowing). */
 237|   viewportCharOffset: number
 238|   /** Character offset in the full text where the viewport ends (text.length when no windowing). */
 239|   viewportCharEnd: number
 240| 
 241|   // For paste handling
 242|   isPasting?: boolean
 243|   pasteState?: {
 244|     chunks: string[]
 245|     timeoutId: ReturnType<typeof setTimeout> | null
 246|   }
 247| }
 248| 
 249| /**
 250|  * State for text input
 251|  */
 252| export type TextInputState = BaseInputState
 253| 
 254| /**
 255|  * State for vim input with mode
 256|  */
 257| export type VimInputState = BaseInputState & {
 258|   mode: VimMode
 259|   setMode: (mode: VimMode) => void
 260| }

何时把类型提升到 types/ 根目录

维护 misc 类型时,一个实用判断标准是“这个类型是否已经成为跨模块语言”。如果某类型只在单一实现内部使用,留在同目录最清晰;若它被 commands、hooks、services、components 多方共享,且字段名会进入文档、配置或外部接口,再提升到 types/ 会更稳妥。ids.ts 与 plugin.ts 都属于后者:它们的名字和字段会被多个子系统复用,改动需要跨模块评估。

另一个标准是“是否承担迁移与兼容”。generated/ 文件由 codegen 管理,不应手改;StatusLineItem、connectorText 这类松散类型则用于接外部输入并隔离不稳定结构。把这两类都放进 misc-types 的阅读路径,有助于新人建立同一心智:并不是所有类型都追求极致严格,很多类型的价值是把不稳定数据圈在边界里,让核心 message/permission/hook 体系保持可演进。

源码引用: src/types/ids.ts · 第 6–44 行(共 45 行)

   6| /**
   7|  * A session ID uniquely identifies a Claude Code session.
   8|  * Returned by getSessionId().
   9|  */
  10| export type SessionId = string & { readonly __brand: 'SessionId' }
  11| 
  12| /**
  13|  * An agent ID uniquely identifies a subagent within a session.
  14|  * Returned by createAgentId().
  15|  * When present, indicates the context is a subagent (not the main session).
  16|  */
  17| export type AgentId = string & { readonly __brand: 'AgentId' }
  18| 
  19| /**
  20|  * Cast a raw string to SessionId.
  21|  * Use sparingly - prefer getSessionId() when possible.
  22|  */
  23| export function asSessionId(id: string): SessionId {
  24|   return id as SessionId
  25| }
  26| 
  27| /**
  28|  * Cast a raw string to AgentId.
  29|  * Use sparingly - prefer createAgentId() when possible.
  30|  */
  31| export function asAgentId(id: string): AgentId {
  32|   return id as AgentId
  33| }
  34| 
  35| const AGENT_ID_PATTERN = /^a(?:.+-)?[0-9a-f]{16}$/
  36| 
  37| /**
  38|  * Validate and brand a string as AgentId.
  39|  * Matches the format produced by createAgentId(): `a` + optional `<label>-` + 16 hex chars.
  40|  * Returns null if the string doesn't match (e.g. teammate names, team-addressing).
  41|  */
  42| export function toAgentId(s: string): AgentId | null {
  43|   return AGENT_ID_PATTERN.test(s) ? (s as AgentId) : null
  44| }

源码引用: src/types/plugin.ts · 第 48–120 行(共 364 行)

  48| export type LoadedPlugin = {
  49|   name: string
  50|   manifest: PluginManifest
  51|   path: string
  52|   source: string
  53|   repository: string // Repository identifier, usually same as source
  54|   enabled?: boolean
  55|   isBuiltin?: boolean // true for built-in plugins that ship with the CLI
  56|   sha?: string // Git commit SHA for version pinning (from marketplace entry source)
  57|   commandsPath?: string
  58|   commandsPaths?: string[] // Additional command paths from manifest
  59|   commandsMetadata?: Record<string, CommandMetadata> // Metadata for named commands from object-mapping format
  60|   agentsPath?: string
  61|   agentsPaths?: string[] // Additional agent paths from manifest
  62|   skillsPath?: string
  63|   skillsPaths?: string[] // Additional skill paths from manifest
  64|   outputStylesPath?: string
  65|   outputStylesPaths?: string[] // Additional output style paths from manifest
  66|   hooksConfig?: HooksSettings
  67|   mcpServers?: Record<string, McpServerConfig>
  68|   lspServers?: Record<string, LspServerConfig>
  69|   settings?: Record<string, unknown>
  70| }
  71| 
  72| export type PluginComponent =
  73|   | 'commands'
  74|   | 'agents'
  75|   | 'skills'
  76|   | 'hooks'
  77|   | 'output-styles'
  78| 
  79| /**
  80|  * Discriminated union of plugin error types.
  81|  * Each error type has specific contextual data for better debugging and user guidance.
  82|  *
  83|  * This replaces the previous string-based error matching approach with type-safe
  84|  * error handling that can't break when error messages change.
  85|  *
  86|  * IMPLEMENTATION STATUS:
  87|  * Currently used in production (2 types):
  88|  * - generic-error: Used for various plugin loading failures
  89|  * - plugin-not-found: Used when plugin not found in marketplace
  90|  *
  91|  * Planned for future use (10 types - see TODOs in pluginLoader.ts):
  92|  * - path-not-found, git-auth-failed, git-timeout, network-error
  93|  * - manifest-parse-error, manifest-validation-error
  94|  * - marketplace-not-found, marketplace-load-failed
  95|  * - mcp-config-invalid, hook-load-failed, component-load-failed
  96|  *
  97|  * These unused types support UI formatting and provide a clear roadmap for
  98|  * improving error specificity. They can be incrementally implemented as
  99|  * error creation sites are refactored.
 100|  */
 101| export type PluginError =
 102|   | {
 103|       type: 'path-not-found'
 104|       source: string
 105|       plugin?: string
 106|       path: string
 107|       component: PluginComponent
 108|     }
 109|   | {
 110|       type: 'git-auth-failed'
 111|       source: string
 112|       plugin?: string
 113|       gitUrl: string
 114|       authType: 'ssh' | 'https'
 115|     }
 116|   | {
 117|       type: 'git-timeout'
 118|       source: string
 119|       plugin?: string
 120|       gitUrl: string

源码引用: src/types/statusLine.ts · 第 1–2 行(共 2 行)

   1| export type StatusLineItem = Record<string, unknown>
   2| 

本章小结与延伸

misc-types 补齐 types/ 长尾文件与 codegen 子树。回到 types 总览对照 19 文件全貌。 继续学习:

  • types 模块总览
  • api-sdk-types
Prev
api-sdk-types · API 与 Hooks 协议类型
Next
local-agent-task · 本地 Agent 与主会话后台化