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

本章总览

先看整体:message-types 是 transcript 的类型地基,决定“每一行消息能长成什么样、渲染层如何分支、队列与桥接如何对齐”。在这个地基上,types/message.ts 定义判别联合与系统子类型,types/messageQueueTypes.ts 描述发送队列,utils/messages.ts 把类型收敛为可复用工厂。

学完本章你应该能

  • 列举 Message 联合的全部成员及其 type 字面量
  • 说明 MessageBase 扩展字段的设计意图
  • 区分 UserMessage.message.content 的 string 与 block 数组形态
  • 理解 SystemMessage subtype 家族(local_command、compact_boundary 等)
  • 知道 NormalizedMessage 与 Message 在渲染层的取舍
  • 能在 utils/messages.ts 找到 createUserMessage 等工厂与类型的对应关系

核心概念(先读懂这些)

Transcript 是一棵带 uuid 的消息树

每条 Message 可选 uuid、parentUuid,支持 fork/resume 与 compact 边界。isMeta 标记模型可见但 UI 折叠;isVirtual 用于 speculative 或合成消息。origin 保留 MessageOrigin 供 analytics 与 bridge 回放。类型层故意保留 [key: string]: unknown 以兼容历史 transcript JSON 而不阻塞新字段落地。

System 消息是 subtype 驱动的多态

SystemMessage 用 subtype 区分 local_command、bridge_status、thinking、memory_saved、compact_boundary 等。TypeScript 通过 SystemLocalCommandMessage、SystemCompactBoundaryMessage 等交叉类型给组件窄化——Ink 组件 switch(message.subtype) 时可获更好提示。level 字段(info/warning/error)服务横幅与 Doctor 展示。

Content blocks 与 SDK 对齐

UserMessage.message.content 可以是 string 或 { type: string; text?: string; ... }[],与 Anthropic Messages API ContentBlockParam 形态兼容。AssistantMessage.message.content 用 unknown,因 tool_use、thinking、redacted_thinking 等块形状随模型版本演进。工具层在读取前做运行时窄化而非在 types 层穷举每一种 block。

建议学习步骤

  1. 通读 message.ts 顶部 MessageBase 与 MessageOrigin
  2. 对照 UserMessage / AssistantMessage 的 message 嵌套结构
  3. 浏览 System* 别名列表,在 REPL 搜索 createSystemMessage 用法
  4. 阅读 ProgressMessage、HookResultMessage、TombstoneMessage 语义
  5. 打开 messageQueueTypes.ts 看 queued 与 in-flight 类型
  6. 在 utils/messages.ts 验证工厂函数返回类型

常见误区

注意

不要把 AttachmentMessage 与 user 侧 file block 混淆——attachment 是 transcript 行类型

注意

GroupedToolUseMessage 与 CollapsedReadSearchGroup 在 UI 层另有折叠逻辑

注意

StreamEvent 仅用于 streaming 解析,不应持久化进 transcript

注意

修改 Message 联合时需同步 bridge 序列化与 sessionStorage schema

Message 联合总览

Message 是 REPL、compact、bridge、SDK 共享的 transcript 行类型:

Message =
  | UserMessage          type: 'user'
  | AssistantMessage     type: 'assistant'
  | ProgressMessage      type: 'progress'
  | SystemMessage        type: 'system' (+ subtype)
  | AttachmentMessage    type: 'attachment'
  | HookResultMessage    type: 'hook_result'
  | ToolUseSummaryMessage type: 'tool_use_summary'
  | TombstoneMessage     type: 'tombstone'
  | GroupedToolUseMessage type: 'grouped_tool_use'

RenderableMessage 别名等于 Message,供组件 props 语义化。NormalizedMessage 是 user/assistant/progress/system/attachment 子集,用于需要排除 tombstone/grouped 的渲染路径。

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

   6| export type MessageBase = {
   7|   uuid?: string
   8|   parentUuid?: string
   9|   timestamp?: string
  10|   createdAt?: string
  11|   isMeta?: boolean
  12|   isVirtual?: boolean
  13|   isCompactSummary?: boolean
  14|   toolUseResult?: unknown
  15|   origin?: MessageOrigin
  16|   [key: string]: unknown
  17| }

源码引用: src/types/message.ts · 第 124–133 行(共 135 行)

 124| export type Message =
 125|   | UserMessage
 126|   | AssistantMessage
 127|   | ProgressMessage
 128|   | SystemMessage
 129|   | AttachmentMessage
 130|   | HookResultMessage
 131|   | ToolUseSummaryMessage
 132|   | TombstoneMessage
 133|   | GroupedToolUseMessage

UserMessage 与 AssistantMessage

UserMessage 结构:

字段类型说明
type'user'判别字段
message.contentstring | block[]用户输入或粘贴的多模态内容
message.*unknown 扩展与 API 请求体对齐

AssistantMessage 的 message 可选,content 为 unknown——streaming 过程中可能部分填充。toolUseResult 在 MessageBase 层,表示 tool 结果回写 transcript 时的附加 payload。

ProgressMessage 用于 tool streaming 中间态(bash 输出、MCP 进度),通常 isMeta 或 UI 特殊渲染。

源码引用: src/types/message.ts · 第 24–43 行(共 135 行)

  24| export type UserMessage = MessageBase & {
  25|   type: 'user'
  26|   message: {
  27|     content: string | Array<{ type: string; text?: string; [key: string]: unknown }>
  28|     [key: string]: unknown
  29|   }
  30| }
  31| 
  32| export type AssistantMessage = MessageBase & {
  33|   type: 'assistant'
  34|   message?: {
  35|     content?: unknown
  36|     [key: string]: unknown
  37|   }
  38| }
  39| 
  40| export type ProgressMessage = MessageBase & {
  41|   type: 'progress'
  42|   progress?: unknown
  43| }

源码引用: src/types/message.ts · 第 40–43 行(共 135 行)

  40| export type ProgressMessage = MessageBase & {
  41|   type: 'progress'
  42|   progress?: unknown
  43| }

System 消息 subtype 家族

SystemMessage 通过 subtype 承载本地命令、bridge、thinking、memory_saved、stop_hook_summary、compact_boundary、permission_retry 等语义。TypeScript 导出细粒度别名便于组件 narrow:

别名典型用途
SystemLocalCommandMessage/memory、/compact 等 slash 命令系统行
SystemMemorySavedMessageextractMemories 或 Write 后提示
SystemCompactBoundaryMessagecompact 前后边界标记
SystemThinkingMessageextended thinking UI
SystemAPIErrorMessageAPI 失败展示,含 error 字段

SystemMessageLevel 为 info | warning | error | string,允许未来扩展级别而不改联合。

源码引用: src/types/message.ts · 第 47–72 行(共 135 行)

  47| export type SystemMessage = MessageBase & {
  48|   type: 'system'
  49|   subtype?: string
  50|   level?: SystemMessageLevel
  51|   message?: string
  52| }
  53| 
  54| export type SystemLocalCommandMessage = SystemMessage & {
  55|   subtype: 'local_command'
  56| }
  57| 
  58| export type SystemBridgeStatusMessage = SystemMessage
  59| export type SystemTurnDurationMessage = SystemMessage
  60| export type SystemThinkingMessage = SystemMessage
  61| export type SystemMemorySavedMessage = SystemMessage
  62| export type SystemStopHookSummaryMessage = SystemMessage
  63| export type SystemInformationalMessage = SystemMessage
  64| export type SystemCompactBoundaryMessage = SystemMessage
  65| export type SystemMicrocompactBoundaryMessage = SystemMessage
  66| export type SystemPermissionRetryMessage = SystemMessage
  67| export type SystemScheduledTaskFireMessage = SystemMessage
  68| export type SystemAwaySummaryMessage = SystemMessage
  69| export type SystemAgentsKilledMessage = SystemMessage
  70| export type SystemApiMetricsMessage = SystemMessage
  71| export type SystemAPIErrorMessage = SystemMessage & { error?: string }
  72| export type SystemFileSnapshotMessage = SystemMessage

源码引用: src/types/message.ts · 第 74–84 行(共 135 行)

  74| export type HookResultMessage = MessageBase & {
  75|   type: 'hook_result'
  76| }
  77| 
  78| export type ToolUseSummaryMessage = MessageBase & {
  79|   type: 'tool_use_summary'
  80| }
  81| 
  82| export type TombstoneMessage = MessageBase & {
  83|   type: 'tombstone'
  84| }

StreamEvent 与 Compact 元数据

StreamEvent、RequestStartEvent 描述 SSE/stream 解析阶段的松散事件,使用 index signature 兼容未记录事件名。

CompactMetadata、PartialCompactDirection(older/newer/both)服务 compact 服务在 transcript 上打标。StopHookInfo 供 stopHooks 附加结构化信息。

这些类型 intentionally loose——compact 与 query 循环迭代快,严格 schema 会拖慢落地;运行时 zod 校验在 services 层完成。

源码引用: src/types/message.ts · 第 86–111 行(共 135 行)

  86| export type StreamEvent = {
  87|   type?: string
  88|   [key: string]: unknown
  89| }
  90| 
  91| export type RequestStartEvent = StreamEvent
  92| 
  93| export type StopHookInfo = {
  94|   [key: string]: unknown
  95| }
  96| 
  97| export type CompactMetadata = {
  98|   [key: string]: unknown
  99| }
 100| 
 101| export type PartialCompactDirection = 'older' | 'newer' | 'both' | string
 102| 
 103| export type CollapsedReadSearchGroup = {
 104|   [key: string]: unknown
 105| }
 106| 
 107| export type GroupedToolUseMessage = MessageBase & {
 108|   type: 'grouped_tool_use'
 109| }
 110| 
 111| export type CollapsibleMessage = MessageBase

messageQueueTypes 与发送队列

messageQueueTypes.ts 定义主循环外的消息队列条目:待发送 user 消息、重试、speculation 接受等。队列类型引用 Message 或 content block 子集,避免 queue 模块 import 整个 utils/messages。

设计意图:当 REPL 在 tool 执行或 permission dialog 阻塞时,用户仍可排队输入;队列 flush 时构造标准 UserMessage 入 transcript。读 QueryEngine 或 handlePromptSubmit 时可对照队列类型与 Message 工厂。

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

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

utils/messages 工厂与类型对齐

utils/messages.ts 的 createUserMessage、createAssistantMessage、createMemorySavedMessage 等返回 Message 联合成员。工厂集中默认值(timestamp、uuid 生成),保证 transcript 磁盘 JSON 与类型一致。

createSystemMessage 族函数设置 subtype/level/message 三元组。extractMemories 完成后调用 createMemorySavedMessage,对应 SystemMemorySavedMessage 形状。

改 message.ts 后,先让 messages.ts 编译通过,再修 components 与 bridge 的 switch 分支——TypeScript 判别联合会在遗漏分支时报错。

源码引用: src/utils/messages.ts · 第 1–50 行(共 5513 行)

   1| import { feature } from 'bun:bundle'
   2| import type { BetaUsage as Usage } from '@anthropic-ai/sdk/resources/beta/messages/messages.mjs'
   3| import type {
   4|   ContentBlock,
   5|   ContentBlockParam,
   6|   RedactedThinkingBlock,
   7|   RedactedThinkingBlockParam,
   8|   TextBlockParam,
   9|   ThinkingBlock,
  10|   ThinkingBlockParam,
  11|   ToolResultBlockParam,
  12|   ToolUseBlock,
  13|   ToolUseBlockParam,
  14| } from '@anthropic-ai/sdk/resources/index.mjs'
  15| import { randomUUID, type UUID } from 'crypto'
  16| import isObject from 'lodash-es/isObject.js'
  17| import last from 'lodash-es/last.js'
  18| import {
  19|   type AnalyticsMetadata_I_VERIFIED_THIS_IS_NOT_CODE_OR_FILEPATHS,
  20|   logEvent,
  21| } from 'src/services/analytics/index.js'
  22| import { sanitizeToolNameForAnalytics } from 'src/services/analytics/metadata.js'
  23| import type { AgentId } from 'src/types/ids.js'
  24| import { companionIntroText } from '../buddy/prompt.js'
  25| import { NO_CONTENT_MESSAGE } from '../constants/messages.js'
  26| import { OUTPUT_STYLE_CONFIG } from '../constants/outputStyles.js'
  27| import { isAutoMemoryEnabled } from '../memdir/paths.js'
  28| import {
  29|   checkStatsigFeatureGate_CACHED_MAY_BE_STALE,
  30|   getFeatureValue_CACHED_MAY_BE_STALE,
  31| } from '../services/analytics/growthbook.js'
  32| import {
  33|   getImageTooLargeErrorMessage,
  34|   getPdfInvalidErrorMessage,
  35|   getPdfPasswordProtectedErrorMessage,
  36|   getPdfTooLargeErrorMessage,
  37|   getRequestTooLargeErrorMessage,
  38| } from '../services/api/errors.js'
  39| import type { AnyObject, Progress } from '../Tool.js'
  40| import { isConnectorTextBlock } from '../types/connectorText.js'
  41| import type {
  42|   AssistantMessage,
  43|   AttachmentMessage,
  44|   Message,
  45|   MessageOrigin,
  46|   NormalizedAssistantMessage,
  47|   NormalizedMessage,
  48|   NormalizedUserMessage,
  49|   PartialCompactDirection,
  50|   ProgressMessage,

源码引用: src/utils/messages.ts · 第 200–240 行(共 5513 行)

 200| export function deriveShortMessageId(uuid: string): string {
 201|   // Take first 10 hex chars from the UUID (skipping dashes)
 202|   const hex = uuid.replace(/-/g, '').slice(0, 10)
 203|   // Convert to base36 for shorter representation, take 6 chars
 204|   return parseInt(hex, 16).toString(36).slice(0, 6)
 205| }
 206| 
 207| export const INTERRUPT_MESSAGE = '[Request interrupted by user]'
 208| export const INTERRUPT_MESSAGE_FOR_TOOL_USE =
 209|   '[Request interrupted by user for tool use]'
 210| export const CANCEL_MESSAGE =
 211|   "The user doesn't want to take this action right now. STOP what you are doing and wait for the user to tell you how to proceed."
 212| export const REJECT_MESSAGE =
 213|   "The user doesn't want to proceed with this tool use. The tool use was rejected (eg. if it was a file edit, the new_string was NOT written to the file). STOP what you are doing and wait for the user to tell you how to proceed."
 214| export const REJECT_MESSAGE_WITH_REASON_PREFIX =
 215|   "The user doesn't want to proceed with this tool use. The tool use was rejected (eg. if it was a file edit, the new_string was NOT written to the file). To tell you how to proceed, the user said:\n"
 216| export const SUBAGENT_REJECT_MESSAGE =
 217|   'Permission for this tool use was denied. The tool use was rejected (eg. if it was a file edit, the new_string was NOT written to the file). Try a different approach or report the limitation to complete your task.'
 218| export const SUBAGENT_REJECT_MESSAGE_WITH_REASON_PREFIX =
 219|   'Permission for this tool use was denied. The tool use was rejected (eg. if it was a file edit, the new_string was NOT written to the file). The user said:\n'
 220| export const PLAN_REJECTION_PREFIX =
 221|   'The agent proposed a plan that was rejected by the user. The user chose to stay in plan mode rather than proceed with implementation.\n\nRejected plan:\n'
 222| 
 223| /**
 224|  * Shared guidance for permission denials, instructing the model on appropriate workarounds.
 225|  */
 226| export const DENIAL_WORKAROUND_GUIDANCE =
 227|   `IMPORTANT: You *may* attempt to accomplish this action using other tools that might naturally be used to accomplish this goal, ` +
 228|   `e.g. using head instead of cat. But you *should not* attempt to work around this denial in malicious ways, ` +
 229|   `e.g. do not use your ability to run tests to execute non-test actions. ` +
 230|   `You should only try to work around this restriction in reasonable ways that do not attempt to bypass the intent behind this denial. ` +
 231|   `If you believe this capability is essential to complete the user's request, STOP and explain to the user ` +
 232|   `what you were trying to do and why you need this permission. Let the user decide how to proceed.`
 233| 
 234| export function AUTO_REJECT_MESSAGE(toolName: string): string {
 235|   return `Permission to use ${toolName} has been denied. ${DENIAL_WORKAROUND_GUIDANCE}`
 236| }
 237| export function DONT_ASK_REJECT_MESSAGE(toolName: string): string {
 238|   return `Permission to use ${toolName} has been denied because Claude Code is running in don't ask mode. ${DENIAL_WORKAROUND_GUIDANCE}`
 239| }
 240| export const NO_RESPONSE_REQUESTED = 'No response requested.'

渲染与 bridge 消费模式

Ink 组件(MessageComponents、Transcript)对 Message 做 type switch:

message.type === 'user'     → UserMessageBlock
message.type === 'assistant' → AssistantMessageBlock + tool blocks
message.type === 'system'   → switch(subtype) 横幅/本地命令
message.type === 'progress' → ToolProgressRenderer

Bridge 出站可能 strip isMeta 或折叠 grouped_tool_use。NormalizedUserMessage 等别名供仅需文本内容的 API 适配层使用,避免误传 tombstone 进模型上下文。

宽松字段的阅读边界

读 Message 类型时要把“判别字段稳定”和“payload 宽松”分开理解。type、subtype、uuid、parentUuid 这些字段承担 transcript 树、渲染分支、compact 边界和 hook 回放的稳定契约;而 message.content、progress、toolUseResult、origin、CompactMetadata 等位置保留 unknown 或索引签名,是为了让 streaming、工具结果、外部 SDK 与历史 JSON 可以先落盘再由消费点做运行时窄化。这样新增一种 tool_use block 或 hook 附加字段时,不必立刻修改中央 Message 联合,也不会让旧 transcript 因多一个字段无法加载。

实践上应遵守两条规则:第一,新增 transcript 行种类才改 Message 联合,并同步 utils/messages 的工厂和所有渲染 switch;第二,若只是某个 assistant content block、progress payload 或系统消息附加信息变化,优先在对应工具、组件或 hook 解析处定义局部类型。SystemMemorySavedMessage 这类别名看似只是 SystemMessage,但它给组件和文档留下语义锚点:调用 createMemorySavedMessage 后,UI 可以通过 subtype=memory_saved 识别通知,而模型上下文仍只把它当系统元数据处理。

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

   6| export type MessageBase = {
   7|   uuid?: string
   8|   parentUuid?: string
   9|   timestamp?: string
  10|   createdAt?: string
  11|   isMeta?: boolean
  12|   isVirtual?: boolean
  13|   isCompactSummary?: boolean
  14|   toolUseResult?: unknown
  15|   origin?: MessageOrigin
  16|   [key: string]: unknown
  17| }

源码引用: src/types/message.ts · 第 47–72 行(共 135 行)

  47| export type SystemMessage = MessageBase & {
  48|   type: 'system'
  49|   subtype?: string
  50|   level?: SystemMessageLevel
  51|   message?: string
  52| }
  53| 
  54| export type SystemLocalCommandMessage = SystemMessage & {
  55|   subtype: 'local_command'
  56| }
  57| 
  58| export type SystemBridgeStatusMessage = SystemMessage
  59| export type SystemTurnDurationMessage = SystemMessage
  60| export type SystemThinkingMessage = SystemMessage
  61| export type SystemMemorySavedMessage = SystemMessage
  62| export type SystemStopHookSummaryMessage = SystemMessage
  63| export type SystemInformationalMessage = SystemMessage
  64| export type SystemCompactBoundaryMessage = SystemMessage
  65| export type SystemMicrocompactBoundaryMessage = SystemMessage
  66| export type SystemPermissionRetryMessage = SystemMessage
  67| export type SystemScheduledTaskFireMessage = SystemMessage
  68| export type SystemAwaySummaryMessage = SystemMessage
  69| export type SystemAgentsKilledMessage = SystemMessage
  70| export type SystemApiMetricsMessage = SystemMessage
  71| export type SystemAPIErrorMessage = SystemMessage & { error?: string }
  72| export type SystemFileSnapshotMessage = SystemMessage

源码引用: src/utils/messages.ts · 第 223–247 行(共 5513 行)

 223| /**
 224|  * Shared guidance for permission denials, instructing the model on appropriate workarounds.
 225|  */
 226| export const DENIAL_WORKAROUND_GUIDANCE =
 227|   `IMPORTANT: You *may* attempt to accomplish this action using other tools that might naturally be used to accomplish this goal, ` +
 228|   `e.g. using head instead of cat. But you *should not* attempt to work around this denial in malicious ways, ` +
 229|   `e.g. do not use your ability to run tests to execute non-test actions. ` +
 230|   `You should only try to work around this restriction in reasonable ways that do not attempt to bypass the intent behind this denial. ` +
 231|   `If you believe this capability is essential to complete the user's request, STOP and explain to the user ` +
 232|   `what you were trying to do and why you need this permission. Let the user decide how to proceed.`
 233| 
 234| export function AUTO_REJECT_MESSAGE(toolName: string): string {
 235|   return `Permission to use ${toolName} has been denied. ${DENIAL_WORKAROUND_GUIDANCE}`
 236| }
 237| export function DONT_ASK_REJECT_MESSAGE(toolName: string): string {
 238|   return `Permission to use ${toolName} has been denied because Claude Code is running in don't ask mode. ${DENIAL_WORKAROUND_GUIDANCE}`
 239| }
 240| export const NO_RESPONSE_REQUESTED = 'No response requested.'
 241| 
 242| // Synthetic tool_result content inserted by ensureToolResultPairing when a
 243| // tool_use block has no matching tool_result. Exported so HFI submission can
 244| // reject any payload containing it — placeholder satisfies pairing structurally
 245| // but the content is fake, which poisons training data if submitted.
 246| export const SYNTHETIC_TOOL_RESULT_PLACEHOLDER =
 247|   '[Tool result missing due to internal error]'

本章小结与延伸

message-types = transcript 的 TypeScript 真相源。下一章 tool-permission-types,读 Tool 进度类型与 Permission/Command 契约。 继续学习:

  • tool-permission-types
  • types 模块总览
Prev
模块: types
Next
tool-permission-types · Tool、Permission、Command 类型