深入拆解 Claude Code 源码(四):77 个斜杠命令背后的三种设计模式与插件迁移之路

深入拆解 Claude Code 源码(四):77 个斜杠命令背后的三种设计模式与插件迁移之路

系列:深入拆解 Claude Code 源码 | 第 4 篇 / 共 8 篇
关键词:Claude Code, 斜杠命令, Command 接口, prompt 命令, local 命令, 插件系统


开篇:一个命令,三种命运

在 Claude Code 里输入 /commit,AI 会帮你写一个 commit message 并提交代码。输入 /vim,终端会切换到 Vim 编辑模式。输入 /help,会弹出一个漂亮的 React 帮助面板。

这三个命令看起来都是"斜杠命令",但它们的内部实现完全不同:

  • /commitprompt 类型 —— 它生成一段 AI 提示词,交给对话引擎处理
  • /vimlocal 类型 —— 它直接在本地执行 JavaScript 逻辑
  • /helplocal-jsx 类型 —— 它渲染一个 React/Ink 组件到终端

这三种类型,就是 Claude Code 命令系统的核心设计模式。今天我们就来拆解这 77 个命令背后的架构。


一、Command 接口:12 个字段的精密设计

所有命令都实现同一个接口,定义在 src/commands.ts 中。这个接口有 12 个字段,每一个都有其存在的理由:

// src/types/command.ts → src/commands.ts
interface Command {
  // ─── 身份标识 ───
  name: string              // 命令名称(不含 /),如 'commit', 'clear'
  type: 'prompt' | 'local' | 'local-jsx'  // 命令类型,决定执行路径
  description: string       // 命令描述,显示在 /help 面板中
  aliases: string[]         // 别名列表,如 /reset → /clear, /continue → /resume

  // ─── 生命周期控制 ───
  isEnabled: () => boolean  // 动态判断是否启用(运行时检查环境变量、Feature Flag 等)
  isHidden: boolean         // 是否在帮助面板中隐藏(如 /heapdump、/thinkback-play)
  immediate: boolean        // 是否立即执行,不等用户确认(如 /rename、/mcp、/status)

  // ─── 运行环境 ───
  supportsNonInteractive: boolean  // 是否支持 SDK/CLI 非交互模式(如 /compact、/advisor)
  availability: string[]    // 可用环境限制:'claude-ai'(订阅用户)、'console'(API 用户)
  source: 'builtin' | 'plugin'  // 来源:内置 or 插件

  // ─── 实现 ───
  argumentHint: string      // 参数提示,显示在命令名后面,如 '<model>|off'
  load: () => Promise       // 延迟加载工厂函数,返回命令的实际实现
}

关键设计:load() 是延迟加载的核心。每个命令的实际实现被封装在一个返回 Promise 的工厂函数中。只有当用户真正输入某个命令时,对应的代码才会被 import() 动态加载到内存中。/insights 命令的实现文件有 3201 行(113KB),如果没有延迟加载,它会在启动时白白占用内存。

availability 字段是一个精巧的访问控制机制。在 src/commands.ts 中,meetsAvailabilityRequirement() 函数会根据用户的认证状态过滤命令:

// src/commands.ts
export function meetsAvailabilityRequirement(cmd: Command): boolean {
  if (!cmd.availability) return true  // 无限制 = 所有人可用
  for (const a of cmd.availability) {
    switch (a) {
      case 'claude-ai':
        if (isClaudeAISubscriber()) return true  // claude.ai 订阅用户
        break
      case 'console':
        // Console API 用户 = 第一方 API 客户端(排除 Bedrock/Vertex/Foundry)
        if (!isClaudeAISubscriber() && !isUsing3PServices()
            && isFirstPartyAnthropicBaseUrl())
          return true
        break
    }
  }
  return false
}

这就是为什么 /usage/upgrade/chrome 等命令在使用第三方 API 时不会出现 —— 它们的 availability 设置了 'claude-ai' 限制。


二、三种命令类型详解

类型一:prompt 命令 —— AI 的"剧本"

prompt 命令不直接执行任何操作,它只是生成一段精心构造的提示词,交给 AI 处理。这是 Claude Code 命令系统中最巧妙的设计 —— 把人类的意图转化为 AI 能理解的"剧本"

/commit:93 行代码的 Git 提交自动化

/commit 命令看起来简单,但它的 getPromptContent() 函数包含了一整套精心设计的"安全协议":

// src/commands/commit.ts (93 行)
const ALLOWED_TOOLS = [
  'Bash(git add:*)',
  'Bash(git status:*)',
  'Bash(git commit:*)',
]

function getPromptContent(): string {
  const { commit: commitAttribution } = getAttributionTexts()

  // undercover 模式:Anthropic 内部使用的特殊指令前缀
  let prefix = ''
  if (process.env.USER_TYPE === 'ant' && isUndercover()) {
    prefix = getUndercoverInstructions() + '\n'
  }

  return `${prefix}## Context
- Current git status: !\`git status\`
- Current git diff (staged and unstaged changes): !\`git diff HEAD\`
- Current branch: !\`git branch --show-current\`
- Recent commits: !\`git log --oneline -10\`

## Git Safety Protocol
- NEVER update the git config
- NEVER skip hooks (--no-verify, --no-gpg-sign, etc)
- CRITICAL: ALWAYS create NEW commits. NEVER use git commit --amend
- Do not commit files that likely contain secrets (.env, credentials.json, etc)
- If there are no changes to commit, do not create an empty commit
- Never use git commands with the -i flag (interactive input not supported)

## Your task
Based on the above changes, create a single git commit:
1. Analyze all staged changes, draft a concise commit message (1-2 sentences, focus on "why")
2. Stage relevant files and create the commit using HEREDOC syntax
   (commitAttribution 自动附加到 commit message 末尾)
`
}

注意那个 !\``git status\`` 语法 —— 这是 Claude Code 的 内联 Shell 执行 机制。executeShellCommandsInPrompt() 函数会在发送给 AI 之前,先在本地执行这些命令,把结果替换到提示词中。AI 看到的不是 !\git status``,而是真实的 git 状态输出。

还有一个细节:getAttributionTexts() 会返回类似 Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com> 的归因文本,自动附加到 commit message 中。

/commit-push-pr:159 行的全流程自动化

如果说 /commit 是"一键提交",那 /commit-push-pr 就是"一键发 PR"。它的工作量大得多:

// src/commands/commit-push-pr.ts (159 行)
const ALLOWED_TOOLS = [
  'Bash(git checkout --branch:*)',
  'Bash(git checkout -b:*)',
  'Bash(git add:*)',
  'Bash(git status:*)',
  'Bash(git push:*)',
  'Bash(git commit:*)',
  'Bash(gh pr create:*)',
  'Bash(gh pr edit:*)',
  'Bash(gh pr view:*)',
  'Bash(gh pr merge:*)',
  'ToolSearch',                              // 搜索可用工具
  'mcp__slack__send_message',               // Slack MCP 集成
  'mcp__claude_ai_Slack__slack_send_message', // claude.ai Slack 集成
]

getPromptContent() 函数的核心逻辑:

function getPromptContent(defaultBranch: string, prAttribution?: string): string {
  const safeUser = process.env.SAFEUSER || ''
  const username = process.env.USER || ''

  // undercover 模式下:移除 reviewer 和 Slack 步骤
  let reviewerArg = ' and `--reviewer anthropics/claude-code`'
  let slackStep = `5. After creating PR, check CLAUDE.md for Slack channels...`
  if (process.env.USER_TYPE === 'ant' && isUndercover()) {
    reviewerArg = ''; slackStep = ''
  }

  return `## Context
- SAFEUSER: ${safeUser}, whoami: ${username}
- git status/diff/branch: !\`git status\` !\`git diff HEAD\` !\`git branch --show-current\`
- diff from ${defaultBranch}: !\`git diff ${defaultBranch}...HEAD\`

## Your task
1. Create new branch if on ${defaultBranch} (use SAFEUSER for prefix, fallback to whoami)
2. Commit with heredoc syntax (include commitAttribution)
3. Push to origin
4. Create or update PR (title < 70 chars)${reviewerArg}
   ...${slackStep}`
}

关键设计点:

  • 分支命名:使用 SAFEUSER 环境变量(而非直接用 USER),回退到 whoami。这是为了避免在共享环境中泄露用户名。
  • 并行解析getPromptForCommand() 中用 Promise.all() 并行获取 defaultBranchprAttribution
  • Slack 集成:通过 ToolSearch 动态搜索 Slack 工具,而非硬编码依赖。找到后询问用户是否发送,找不到则静默跳过。
  • PR 归因getEnhancedPRAttribution() 会生成比 commit 更详细的 PR 归因文本,包含 PR body 的 footer 部分。
/security-review:196 行安全审查提示词

/security-review 是整个命令系统中提示词最长的 prompt 命令。它的核心是 SECURITY_REVIEW_MARKDOWN —— 一个 196 行的 Markdown 模板,定义了完整的安全审查流程。

// src/commands/security-review.ts (244 行)
const SECURITY_REVIEW_MARKDOWN = `---
allowed-tools: Bash(git diff:*), Bash(git status:*), Bash(git log:*),
  Bash(git show:*), Bash(git remote show:*), Read, Glob, Grep, LS, Task
---

You are a senior security engineer conducting a focused security review.
...(自动注入 git status、diff、commit 日志)

OBJECTIVE: Identify HIGH-CONFIDENCE security vulnerabilities.
CRITICAL: Only flag issues where you're >80% confident of actual exploitability.

ANALYSIS METHODOLOGY:
Phase 1 - Repository Context Research: 识别安全框架、编码模式、消毒/验证模式
Phase 2 - Comparative Analysis: 对比新代码与现有安全模式,识别偏差
Phase 3 - Vulnerability Assessment: 追踪数据流,检查注入点和不安全反序列化

START ANALYSIS (3 steps):
1. Use a sub-task to identify vulnerabilities
2. For each vulnerability, create a parallel sub-task to filter false-positives
3. Filter out any vulnerabilities where confidence < 8`

安全检查 5 大类

类别检查项
输入验证SQL 注入、命令注入、XXE、模板注入、NoSQL 注入、路径遍历
认证授权认证绕过、提权路径、会话管理、JWT 漏洞、授权逻辑绕过
加密密钥硬编码密钥、弱算法、密钥存储不当、随机数问题、证书验证绕过
注入执行RCE(反序列化)、Pickle 注入、YAML 反序列化、Eval 注入、XSS
数据暴露敏感数据日志、PII 处理、API 数据泄露、调试信息暴露

误报过滤 17+ 条硬排除规则 + 12 条先例规则:这是安全审查中最实用的部分。Claude Code 的工程师们把常见的误报模式硬编码进了提示词。挑几条最有代表性的:

HARD EXCLUSIONS(自动排除):
- DOS 漏洞、磁盘密钥存储、速率限制、内存安全(Rust 等内存安全语言不报告)
- 单元测试文件、日志欺骗、仅控制路径的 SSRF、正则注入/DOS
- GitHub Action 工作流中的输入消毒(除非明确可通过不可信输入触发)
- React/Angular 中的 XSS(除非使用了 dangerouslySetInnerHTML)
- 客户端 JS/TS 中缺少权限检查(服务端负责,不是漏洞)

PRECEDENTS(先例判定):
- 记录高价值密钥明文是漏洞,记录 URL 不是
- UUID 可假定为不可猜测,无需验证
- 环境变量和 CLI 标志是可信值,依赖控制环境变量的攻击无效
- ipython notebook 中的漏洞通常不可实际利用,除非有明确攻击路径

注意最终的 3 步分析流程:子任务识别漏洞 → 并行子任务过滤误报 → 过滤置信度 < 8 的结果。这意味着每个发现的漏洞都会被一个独立的 AI 子任务重新审查一遍,大幅降低了误报率。

/init:NEW_INIT 的 8 阶段交互式设置

/init 命令有两个版本,由 feature('NEW_INIT') 控制。旧版本(OLD_INIT_PROMPT)只是一个简单的"帮我创建 CLAUDE.md"提示词。新版本(NEW_INIT_PROMPT,约 200 行)是一个完整的 8 阶段交互式流程。命令入口根据 USER_TYPE === 'ant' 和环境变量 CLAUDE_CODE_NEW_INIT 决定使用哪个版本,执行时调用 maybeMarkProjectOnboardingComplete() 标记 onboarding 完成。

NEW_INIT 的 8 个阶段

阶段名称做什么
Phase 1询问偏好AskUserQuestion 问用户:要设置哪个 CLAUDE.md?要设置 skills 和 hooks 吗?
Phase 2探索代码库启动子 Agent 扫描:package.json、README、CI 配置、现有 CLAUDE.md、.cursor/rules、.copilot-instructions.md 等
Phase 3填补空白AskUserQuestion 补充代码无法回答的问题:团队规范、分支策略、测试怪癖等
Phase 4写入 CLAUDE.md在项目根目录写入精简的 CLAUDE.md,每行都通过"删掉它 Claude 会犯错吗?"测试
Phase 5写入 CLAUDE.local.md写入个人偏好文件(自动加入 .gitignore),包含角色、沙箱 URL、沟通偏好等
Phase 6建议技能根据 Phase 3 的偏好队列创建 .claude/skills/<name>/SKILL.md,并建议额外技能
Phase 7建议优化检查 GitHub CLI、lint 配置、formatter hook 等,逐项询问用户是否需要
Phase 8摘要回顾设置内容,提供后续优化建议(如安装插件、设置测试框架等)

NEW_INIT 的设计哲学是"只写 Claude 会犯错的东西"。Phase 4 的 CLAUDE.md 写入规则非常严格:

  • 包含:非标准的构建/测试/lint 命令、与语言默认不同的代码风格、测试怪癖、环境变量要求
  • 排除:文件结构列表(Claude 可以自己读)、标准语言惯例、通用建议、频繁变化的信息(用 @path 引用代替)

prompt 命令的代表清单

命令功能允许的工具
/commitGit 提交git add, git status, git commit
/commit-push-pr提交+推送+创建 PRgit + gh pr create/edit/view/merge + Slack MCP
/reviewPR 审查gh pr 命令
/init项目初始化文件读写
/insights使用分析报告文件读取
/security-review安全审查git diff/status/log/show, Read, Glob, Grep, LS, Task

类型二:local 命令 —— 本地的"快速反应"

local 命令直接执行 JavaScript 逻辑,不经过 AI。适合不需要 AI 参与的纯操作。

// 示例:/version 命令
{
  name: 'version',
  type: 'local',
  async load() {
    return () => {
      console.log(MACRO.VERSION)
      if (MACRO.BUILD_TIME) {
        console.log(`Build: ${MACRO.BUILD_TIME}`)
      }
    }
  }
}
/compact:对话压缩的核心机制

/compact 是 local 命令中最复杂的一个。它不只是"清除历史",而是一套精心设计的对话压缩系统。命令定义很简单:isEnabledDISABLE_COMPACT 环境变量门控,支持非交互模式,支持自定义摘要指令作为参数。

compact.ts 的实现(约 100+ 行)包含多层压缩策略:

  1. 会话记忆压缩trySessionMemoryCompaction):优先尝试,不支持自定义指令
  2. 标准压缩compactConversation):调用 AI 生成对话摘要
  3. 微压缩microcompactMessages):对消息进行细粒度裁剪
  4. 响应式压缩reactiveCompact):Feature Flag REACTIVE_COMPACT 门控的实验性方案

压缩完成后还会执行一系列清理操作:清除用户上下文缓存、运行后压缩 hooks(runPostCompactCleanup)、通知缓存断裂检测(notifyCompaction)、标记压缩状态(markPostCompaction)、抑制压缩警告(suppressCompactWarning)。

/rewind:回到过去

/rewind(别名 checkpoint)支持恢复代码和/或对话到之前的状态。checkpoint 别名暗示了它的用途 —— 在关键时刻创建检查点,方便回溯。supportsNonInteractive: false,不支持 SDK 模式。

/clear:一键清空

/clear 有三个入口:/clear/reset/new。实现分为两层:clearSessionCaches(清除会话缓存)和 clearConversation(清除对话)。注意 supportsNonInteractive: false —— 在 SDK 非交互模式下,/clear 不会清除当前会话,而是应该创建一个全新的会话。

/advisor:模型顾问的三层验证
// src/commands/advisor.ts (110 行)
const advisor = {
  type: 'local',
  name: 'advisor',
  description: 'Configure the advisor model',
  argumentHint: '[<model>|off]',
  isEnabled: () => canUserConfigureAdvisor(),  // GrowthBook 配置门控
  get isHidden() {
    return !canUserConfigureAdvisor()  // 未启用时隐藏
  },
  supportsNonInteractive: true,
  load: () => Promise.resolve({ call }),  // 直接返回,无需动态导入
}

/advisor 支持三种操作:show(显示当前配置)、set <model>(设置模型)、unset/off(关闭)。设置模型时有三层验证:parseUserSpecifiedModel() 解析名称 → validateModel() 验证 API 有效性 → isValidAdvisorModel() 验证业务适配性。通过后持久化到用户设置,并检查当前主模型是否兼容 advisor 角色。

local 命令的代表清单

命令功能别名
/clear清除对话历史reset, new
/compact压缩对话(保留摘要)
/rewind恢复到之前状态checkpoint
/vim切换 Vim 模式
/cost显示当前费用
/version显示版本号
/advisor配置 advisor 模型

类型三:local-jsx 命令 —— 终端里的"UI 组件"

local-jsx 命令渲染 React/Ink 组件,提供丰富的交互式界面。

// 示例:/help 命令
{
  name: 'help',
  type: 'local-jsx',
  async load() {
    return ({ onExit }) => (
      <Dialog title="Help" onCancel={onExit}>
        <Box flexDirection="column">
          <Text bold>Available Commands:</Text>
          {commands.map(cmd => (
            <ListItem key={cmd.name}>
              <Text color="blue">/{cmd.name}</Text>
              <Text dimColor>{cmd.description}</Text>
            </ListItem>
          ))}
        </Box>
      </Dialog>
    )
  }
}
/resume:恢复对话

/resume(别名 continue)渲染一个对话选择器 UI,让用户从历史会话列表中选择要恢复的会话。continue 别名的设计很贴心 —— 用户可以自然地说"继续上次的对话"。支持通过参数 [conversation id or search term] 直接指定会话。

/branch:对话分叉

/branch 在当前对话点创建一个分支。它的别名设计很有趣:当 FORK_SUBAGENT Feature Flag 开启时,fork 别名会被移除(aliases: feature('FORK_SUBAGENT') ? [] : ['fork']),因为此时存在一个独立的 /fork 命令(用于创建子 Agent)。这是一个别名冲突避免的典型案例。

/export:导出对话

/export 支持两种导出目标:文件(指定文件名参数)或剪贴板(不指定文件名)。

/brief:Kairos 的简要模式
// src/commands/brief.ts (131 行)
const brief = {
  type: 'local-jsx',
  name: 'brief',
  description: 'Toggle brief-only mode',
  isEnabled: () => {
    if (feature('KAIROS') || feature('KAIROS_BRIEF')) {
      return getBriefConfig().enable_slash_command  // GrowthBook 配置
    }
    return false
  },
  immediate: true,
  // load 直接返回 Promise.resolve,无需动态导入
}

/brief 是 Kairos 系统的一部分,它切换"简要模式"—— 在这个模式下,AI 只能通过特定的 Brief 工具输出内容,普通文本输出会被隐藏。它的实现有 131 行,包含几个精妙的设计:

  • Zod schema 验证:GrowthBook 推送的配置通过 z.object({ enable_slack_command: z.boolean() }) 验证,防止错误配置
  • 权益检查只在开启时生效:关闭 brief 模式总是允许的 —— 如果 GrowthBook 门控中途翻转,已开启 brief 模式的用户不会被卡住
  • userMsgOptIn 双向同步:确保 Brief 工具可用性与 brief 模式状态一致,但这会导致 prompt cache 失效
  • 系统提醒注入:工具列表变化不足以让模型"改习惯",所以显式注入 <system-reminder> 告诉模型行为切换
  • Kairos 活跃时跳过提醒getKairosActive() 时 Kairos 系统提示词已经强制使用 SendUserMessage,无需额外提醒

local-jsx 命令的代表清单

命令功能别名
/help帮助信息
/config配置管理settings
/model模型选择
/mcpMCP 管理
/permissions权限管理allowed-tools
/resume恢复对话continue
/branch对话分叉fork(条件)
/export导出对话
/brief简要模式
/diff查看差异
/agentsAgent 管理
/skills技能列表

三、命令注册表:754 行的中央调度

src/commands.ts 是命令的集中注册表,754 行代码,管理着所有命令的生命周期。

注册结构

// src/commands.ts — 命令注册表(简化版)
const COMMANDS = memoize((): Command[] => [
  // ─── 会话管理 ───
  clear, compact, resume, session, exportCommand,
  rename, branch, rewind,

  // ─── 配置 ───
  config, color, theme, vim, keybindings, permissions,
  outputStyle, sandboxToggle, terminalSetup,

  // ─── 认证 ───
  login(), logout, usage, upgrade, extraUsage, passes, privacySettings,

  // ─── MCP 与集成 ───
  mcp, ide, chrome, desktop, mobile, installGitHubApp, installSlackApp,

  // ─── 代码审查与 Git ───
  review, ultrareview, securityReview, pr_comments, diff,

  // ─── 任务/Agent ───
  tasks, agents, plan, skills, memory,

  // ─── 信息 ───
  help, status, cost, stats, context, doctor, files, releaseNotes,

  // ─── AI 功能 ───
  usageReport, thinkback, thinkbackPlay, btw,

  // ─── 开发工具 ───
  hooks, heapDump, copy, reloadPlugins,

  // ─── 其他 ───
  exit, feedback, stickers, tag, statusline,

  // ─── 条件命令(Feature Flag 门控)───
  ...(webCmd ? [webCmd] : []),
  ...(forkCmd ? [forkCmd] : []),
  ...(buddy ? [buddy] : []),
  ...(proactive ? [proactive] : []),
  ...(briefCommand ? [briefCommand] : []),
  ...(assistantCommand ? [assistantCommand] : []),
  ...(bridge ? [bridge] : []),
  ...(remoteControlServerCommand ? [remoteControlServerCommand] : []),
  ...(voiceCommand ? [voiceCommand] : []),
  ...(peersCmd ? [peersCmd] : []),
  ...(workflowsCmd ? [workflowsCmd] : []),
  ...(torch ? [torch] : []),

  // ─── 内部命令(ant-only)───
  ...(process.env.USER_TYPE === 'ant' && !process.env.IS_DEMO
    ? INTERNAL_ONLY_COMMANDS : []),
])

动态命令加载

COMMANDS() 只是基础命令列表。完整的命令列表还需要合并来自四个来源的动态命令:

// src/commands.ts
const loadAllCommands = memoize(async (cwd: string): Promise<Command[]> => {
  const [
    { skillDirCommands, pluginSkills, bundledSkills, builtinPluginSkills },
    pluginCommands,
    workflowCommands,
  ] = await Promise.all([
    getSkills(cwd),           // .claude/skills/ 目录下的技能命令
    getPluginCommands(),      // 插件提供的命令
    getWorkflowCommands(cwd), // 工作流脚本命令
  ])

  return [
    ...bundledSkills,         // 内置技能
    ...builtinPluginSkills,   // 内置插件技能
    ...skillDirCommands,      // 用户自定义技能
    ...workflowCommands,      // 工作流命令
    ...pluginCommands,        // 插件命令
    ...pluginSkills,          // 插件技能
    ...COMMANDS(),            // 基础命令(最后,优先级最低)
  ]
})

最终的 getCommands() 函数会过滤掉不满足 availability 要求和 isEnabled() 返回 false 的命令,并合并运行时动态发现的技能。


四、条件加载与 Feature Flag

Claude Code 大量使用 bun:bundlefeature() 宏进行编译时死代码消除。以下是所有受 Feature Flag 控制的命令:

// src/commands.ts — 条件导入(编译时消除),共 15 个 Flag 门控命令
// 模式:feature('FLAG') ? require('./commands/xxx.js').default : null

// 单 Flag 门控
const voiceCommand = feature('VOICE_MODE')
  ? require('./commands/voice/index.js').default : null
const bridge = feature('BRIDGE_MODE')
  ? require('./commands/bridge/index.js').default : null

// OR 组合(任一 Flag 开启即可)
const proactive = feature('PROACTIVE') || feature('KAIROS')
  ? require('./commands/proactive.js').default : null
const briefCommand = feature('KAIROS') || feature('KAIROS_BRIEF')
  ? require('./commands/brief.js').default : null

// AND 组合(两个 Flag 都需开启)
const remoteControlServerCommand =
  feature('DAEMON') && feature('BRIDGE_MODE')
    ? require('./commands/remoteControlServer/index.js').default : null

// 其他 Flag:FORK_SUBAGENT, BUDDY, WORKFLOW_SCRIPTS, CCR_REMOTE_SETUP,
// KAIROS_GITHUB_WEBHOOKS, ULTRAPLAN, TORCH, UDS_INBOX, HISTORY_SNIP ...

完整的 Feature Flag 命令对照表

命令Feature Flag(s)说明
/proactivePROACTIVE OR KAIROS主动模式
/briefKAIROS OR KAIROS_BRIEF简要模式
/assistantKAIROS助手模式
/remote-controlBRIDGE_MODE远程控制
/remote-control-serverDAEMON AND BRIDGE_MODE远程控制服务端
/voiceVOICE_MODE语音模式
/forkFORK_SUBAGENT子 Agent 分叉
/buddyBUDDY伙伴模式
/workflowsWORKFLOW_SCRIPTS工作流脚本
/web-setupCCR_REMOTE_SETUPWeb 远程设置
/subscribe-prKAIROS_GITHUB_WEBHOOKSPR 订阅
/ultraplanULTRAPLAN超级计划模式
/torchTORCHTorch 模式
/peersUDS_INBOX同行消息
force-snipHISTORY_SNIP历史裁剪(内部)

注意 remoteControlServerCommand 需要两个 Flag 同时开启(DAEMON AND BRIDGE_MODE),这体现了它对运行环境的严格要求。


五、环境变量控制:企业级的命令禁用机制

除了 Feature Flag,Claude Code 还支持通过环境变量在运行时禁用特定命令。这主要用于企业部署场景 —— 企业管理员不希望员工使用某些命令(如登录、反馈、升级)。每个被禁用的命令都有一个对应的 isEnabled 检查:isEnabled: () => !isEnvTruthy(process.env.DISABLE_XXX)

完整的环境变量控制表

环境变量影响的命令说明
DISABLE_COMPACT/compact禁用压缩命令
DISABLE_DOCTOR_COMMAND/doctor禁用诊断命令
DISABLE_LOGIN_COMMAND/login禁用登录命令
DISABLE_LOGOUT_COMMAND/logout禁用登出命令
DISABLE_FEEDBACK_COMMAND/feedback禁用反馈命令
DISABLE_BUG_COMMAND/feedback禁用 bug 命令(别名)
DISABLE_EXTRA_USAGE_COMMAND/extra-usage禁用超额使用命令
DISABLE_UPGRADE_COMMAND/upgrade禁用升级命令
DISABLE_INSTALL_GITHUB_APP_COMMAND/install-github-app禁用 GitHub App 安装
CLAUDE_CODE_USE_BEDROCK/feedbackBedrock 模式自动禁用反馈
CLAUDE_CODE_USE_VERTEX/feedbackVertex 模式自动禁用反馈
CLAUDE_CODE_USE_FOUNDRY/feedbackFoundry 模式自动禁用反馈
USER_TYPE多个ant 时启用内部命令和 undercover 模式

注意 /feedback 命令的禁用逻辑最复杂 —— 它同时被 6 个环境变量控制。这是因为第三方服务提供商(Bedrock/Vertex/Foundry)不支持 Anthropic 的反馈通道,所以需要自动禁用。


六、insights.ts:3201 行的巨型命令

/insights 是整个命令系统中最大的单文件(3201 行,113KB),它生成一个完整的 HTML 使用分析报告。正因为它太大,commands.ts 中专门用了一个延迟加载 shim:

// src/commands.ts — 延迟加载 shim
const usageReport: Command = {
  type: 'prompt',
  name: 'insights',
  description: 'Generate a report analyzing your Claude Code sessions',
  contentLength: 0,
  progressMessage: 'analyzing your sessions',
  source: 'builtin',
  async getPromptForCommand(args, context) {
    const real = (await import('./commands/insights.js')).default
    if (real.type !== 'prompt') throw new Error('unreachable')
    return real.getPromptForCommand(args, context)
  },
}

6 阶段报告生成流程

Phase 1: Lite Scan
  → scanAllSessions() 扫描文件系统元数据(无 JSONL 解析)
  → 仅读取目录结构和文件大小,快速估算工作量

Phase 2: SessionMeta 加载
  → loadCachedSessionMeta() 尝试从缓存加载
  → logToSessionMeta() 解析未缓存的 JSONL 会话日志
  → deduplicateSessionBranches() 去重会话分支(同一会话的不同分支)

Phase 3: 特征提取
  → loadCachedFacets() 尝试从缓存加载
  → extractFacetsFromAPI() 对未缓存会话调用 API 提取特征
  → formatTranscriptForFacets() 格式化转录用于特征提取
  → saveFacets() 缓存提取结果

Phase 4: 聚合
  → aggregateData() 聚合所有会话数据
  → detectMultiClauding() 检测并行会话使用(多开 Claude Code)

Phase 5: 洞察生成
  → generateParallelInsights() 并行调用 Claude 生成 6+ 个洞察部分
  → 每个洞察部分独立生成,互不依赖

Phase 6: HTML 生成
  → generateHtmlReport() 生成完整 HTML 报告(~800 行 HTML)
  → generateBarChart() 生成柱状图
  → generateResponseTimeHistogram() 生成响应时间分布图
  → generateTimeOfDayChart() 生成时段使用图
  → buildExportData() 构建导出数据结构

核心数据结构

// 会话元数据 —— 从 JSONL 日志中提取
type SessionMeta = {
  session_id: string
  start_time: string
  end_time: string
  user_message_count: number
  assistant_message_count: number
  duration_minutes: number
  lines_added: number
  lines_removed: number
  files_modified: string[]
  git_commits: number
  language_counts: Record<string, number>  // 如 {"TypeScript": 42, "Python": 10}
  tool_counts: Record<string, number>      // 如 {"Bash": 15, "Read": 30}
}

// 会话特征 —— 通过 API 从转录中提取
type SessionFacets = {
  underlying_goal: string           // 用户的根本目标
  outcome: string                   // 会话结果
  brief_summary: string             // 简要摘要
  goal_categories: string[]         // 目标分类
  user_satisfaction_counts: Record<string, number>  // 满意度统计
  friction_counts: Record<string, number>           // 摩擦点统计
}

// 聚合数据 —— 所有会话的汇总
type AggregatedData = {
  total_messages: number
  total_sessions: number
  date_range: { start: string, end: string }
  languages: Record<string, number>
  tool_counts: Record<string, number>
  goal_categories: Record<string, number>
  outcomes: Record<string, number>
  satisfaction: Record<string, number>
  friction: Record<string, number>
  message_hours: Record<string, number>       // 按小时分布
  tool_error_categories: Record<string, number>
  multi_clauding: { sessions: number, peak: number }
}

// AI 生成的洞察结果
type InsightResults = {
  at_a_glance: string          // 一目了然的总结
  project_areas: string        // 项目区域分析
  interaction_style: string    // 交互风格分析
  what_works: string           // 什么有效
  friction_analysis: string    // 摩擦点分析
  suggestions: string          // 改进建议
  on_the_horizon: string       // 展望
}

关键函数一览

函数说明
extractToolStats(log)从会话日志提取工具使用统计
logToSessionMeta(log)会话日志转元数据(解析消息数、修改文件、语言分布等)
deduplicateSessionBranches(metas)去重会话分支(同一会话的不同 fork)
formatTranscriptForFacets(log)格式化转录用于 API 特征提取
extractFacetsFromAPI(log, sessionId)调用 Claude API 从转录中提取会话特征
detectMultiClauding(metas)检测并行会话使用(多开 Claude Code)
aggregateData(metas, facets)聚合所有会话数据
generateParallelInsights(data, facets)并行调用 Claude 生成 6+ 个洞察部分
generateHtmlReport(data, insights)生成完整 HTML 报告(~800 行)
generateBarChart / generateResponseTimeHistogram / generateTimeOfDayChart各类图表生成
buildExportData(data, insights, facets, remoteStats?)构建导出数据结构
scanAllSessions()扫描所有项目目录(仅文件系统元数据)
generateUsageReport(options?)主入口函数

远程主机数据采集(ant-only)

对于 Anthropic 内部用户,/insights 还支持从远程开发主机收集数据:

// 远程主机数据采集
getRunningRemoteHosts()              // 获取运行中的远程主机列表
getRemoteHostSessionCount(host)      // 获取单个主机的会话数
collectFromRemoteHost(host, destDir) // 从单个主机收集数据到本地目录
collectAllRemoteHostData(destDir)    // 从所有主机批量收集

这些远程主机通常是 Anthropic 内部的云开发环境,工程师可能同时在多个环境中使用 Claude Code。


七、插件迁移模式:从内置到插件的无缝过渡

这是命令系统中最有趣的设计之一。部分内置命令正在从"编译进二进制"迁移到"插件安装"。

createMovedToPluginCommand 工厂(66 行)

// src/commands/createMovedToPluginCommand.ts (66 行)
export function createMovedToPluginCommand({
  name, description, progressMessage,
  pluginName, pluginCommand,
  getPromptWhileMarketplaceIsPrivate,  // 市场未公开时的回退逻辑
}: Options): Command {
  return {
    type: 'prompt',
    name,
    description,
    progressMessage,
    contentLength: 0,
    source: 'builtin',
    async getPromptForCommand(args, context): Promise<ContentBlockParam[]> {
      // ─── Ant 用户:显示插件安装指引 ───
      if (process.env.USER_TYPE === 'ant') {
        return [{
          type: 'text',
          text: `This command has been moved to a plugin. Tell the user:
1. Install: claude plugin install ${pluginName}@claude-code-marketplace
2. Use: /${pluginName}:${pluginCommand}
3. Docs: https://github.com/anthropics/claude-code-marketplace/blob/main/${pluginName}/README.md`,
        }]
      }
      // ─── 其他用户:保留原始 prompt 逻辑 ───
      return getPromptWhileMarketplaceIsPrivate(args, context)
    },
  }
}

这个工厂函数的核心是一个两阶段迁移策略

  1. Ant 用户(Anthropic 内部员工):获得插件安装指引,告诉他们去 marketplace 安装
  2. 其他用户(外部用户):获得原始的 prompt 逻辑,体验完全不变

使用此模式的命令

命令插件名插件命令原始逻辑
/security-reviewsecurity-reviewsecurity-review196 行安全审查提示词
/pr-commentspr-commentspr-commentsPR 评论获取逻辑

这个模式的巧妙之处在于:对用户完全透明。无论命令是内置还是插件,用户输入 /security-review 的体验是一样的。内部员工提前体验插件版本,外部用户继续使用内置版本,直到 marketplace 公开后统一切换。

迁移状态在代码中的体现是 getPromptWhileMarketplaceIsPrivate 这个参数名 —— 它明确告诉未来的维护者:“这个回退逻辑只在 marketplace 是私有的时候需要,公开后可以删除。”


八、设计亮点总结

设计决策价值
三种命令类型职责分离:prompt 走 AI,local 走本地,jsx 走 UI
延迟加载 load()命令代码按需加载,/insights 的 113KB 不影响启动速度
别名系统/reset/clear/continue/resume,降低记忆负担
条件别名/fork 别名在 FORK_SUBAGENT 开启时自动移除,避免冲突
插件迁移工厂内置命令无缝迁移到插件,内外用户体验一致
Feature Flag 门控15+ 个实验性命令渐进发布,编译时死代码消除
环境变量禁用企业环境可禁用 10+ 个敏感命令
availability 访问控制按认证状态过滤命令(claude-ai vs console)
安全审查误报过滤17+ 条硬排除规则 + 12 条先例规则,大幅降低噪声
/init 8 阶段设置交互式引导,只写 Claude 会犯错的东西
/compact 多层压缩会话记忆 → 标准 → 微 → 响应式,四层压缩策略
undercover 模式Anthropic 内部特殊指令,自动移除 reviewer/Slack 等敏感步骤

下篇预告

第五篇:35 个内置工具的瑞士军刀

命令是面向用户的入口,工具才是 AI 真正的"手脚"。Claude Code 内置了 35+ 工具,从文件读写到 Shell 执行,从网页搜索到 Agent 调度。所有工具都通过一个统一的 buildTool() 工厂函数构建,支持输入验证、权限检查、并发安全标记和 UI 渲染。

下一篇,我们将深入工具系统的架构,看看 AI 是如何通过这些"瑞士军刀"操作你的电脑的。


标签: Claude Code 斜杠命令 Command接口 prompt命令 插件系统 TypeScript 源码分析 Feature Flag 安全审查 insights

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值