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

本章总览

loadSkillsDir.ts(约 1087 行)扫描 .claude/skills、managed、plugin 路径下的 SKILL.md,解析 frontmatter 为 PromptCommand。bundledSkills.ts 提供 registerBundledSkill 编程式注册,供 bundled/*.ts 在 init 时写入。本章讲解 LoadedFrom 来源、createSkillCommand、files 提取与 registerMCPSkillBuilders 循环打破。loadSkillsDir 是 commands.ts 与 SkillTool 的共同上游。

学完本章你应该能

  • 说明 getSkillsPath(source, dir) 路径规则
  • 解释 createSkillCommand frontmatter 字段映射
  • 描述 registerBundledSkill 的 files 提取与 prependBaseDir
  • 理解 registerMCPSkillBuilders 在 loadSkillsDir 模块 init 注册
  • 掌握 clearDynamicSkills 与 /clear caches 衔接

核心概念(先读懂这些)

LoadedFrom 五源 + deprecated commands

LoadedFrom = commands_DEPRECATED | skills | plugin | managed | bundled | mcp。disk skill 与旧 commands 目录并存;frontmatter 决定 model、allowed-tools、context:fork 等。plugin-only policy 可限制非 plugin skill。

mcpSkillBuilders 打破循环依赖

loadSkillsDir 静态 import mcpSkillBuilders 并在文件末尾 registerMCPSkillBuilders({ createSkillCommand, parseSkillFrontmatterFields })。mcpSkills.ts 通过 getMCPSkillBuilders() 延迟获取,避免 client.ts → mcpSkills → loadSkillsDir → client 环。

建议学习步骤

  1. 阅读 LoadedFrom 与 getSkillsPath(源码块 A)
  2. 阅读 createSkillCommand 入口(源码块 B)
  3. 阅读 registerBundledSkill 与 files 提取(源码块 C、D)
  4. 阅读 registerMCPSkillBuilders 末尾注册(源码块 E)
  5. 阅读 frontmatter 与 HooksSchema(源码块 F)

常见误区

注意

executeShellCommandsInPrompt 在 load 时执行 shell 片段——安全敏感

注意

isBareMode 可能跳过部分目录扫描

注意

disk IO 失败 isENOENT / isFsInaccessible 区分 skip vs error log

注意

plugin-only policy 下非 plugin skill 静默 skip

注意

memoize cache 需在 plugin install 后 clearDynamicSkills

skills 加载在架构中的位置

main.tsx initBundledSkills()
commands.ts getCommands(projectRoot)
  ├─ builtIn slash commands
  ├─ loadSkillsFromDir (loadSkillsDir.ts)
  ├─ getBundledSkills() (bundledSkills.ts 内部数组)
  └─ MCP commands (AppState.mcp.commands, loadedFrom==='mcp')

REPL useSkillsChange(projectRoot, setLocalCommands)
  → skill 文件变更 → getCommands 全量 refresh

SkillsMenu.tsx 用 getSkillsPath、estimateSkillFrontmatterTokens 展示菜单。

FileRead/Write/EditTool import loadSkillsDir 辅助函数解析 skill 路径边界。

源码引用: src/commands.ts · 第 160–160 行(共 755 行)

 160| } from './skills/loadSkillsDir.js'

源码引用: src/screens/REPL.tsx · 第 683–684 行(共 7050 行)

 683|           <Box flexGrow={1} />
 684|           <Text dimColor>

LoadedFrom 与 getSkillsPath

export type LoadedFrom = 'commands_DEPRECATED' | 'skills' | 'plugin' | 'managed' | 'bundled' | 'mcp'

getSkillsPath(source, dir) 返回 claude config 下 skills 或 commands 目录:

  • user / project / local / managed / plugin 源
  • 与 settings constants isSettingSourceEnabled 联动
  • managed 路径经 getManagedFilePath

扫描使用 loadMarkdownFilesForSubdir、parseFrontmatter、parseSlashCommandToolsFromFrontmatter。

isPathGitignored / ignore 包排除 gitignore 目录内 skill。

源码引用: src/skills/loadSkillsDir.ts · 第 67–80 行(共 1087 行)

  67| export type LoadedFrom =
  68|   | 'commands_DEPRECATED'
  69|   | 'skills'
  70|   | 'plugin'
  71|   | 'managed'
  72|   | 'bundled'
  73|   | 'mcp'
  74| 
  75| /**
  76|  * Returns a claude config directory path for a given source.
  77|  */
  78| export function getSkillsPath(
  79|   source: SettingSource | 'plugin',
  80|   dir: 'skills' | 'commands',

源码引用: src/skills/loadSkillsDir.ts · 第 78–95 行(共 1087 行)

  78| export function getSkillsPath(
  79|   source: SettingSource | 'plugin',
  80|   dir: 'skills' | 'commands',
  81| ): string {
  82|   switch (source) {
  83|     case 'policySettings':
  84|       return join(getManagedFilePath(), '.claude', dir)
  85|     case 'userSettings':
  86|       return join(getClaudeConfigHomeDir(), dir)
  87|     case 'projectSettings':
  88|       return `.claude/${dir}`
  89|     case 'plugin':
  90|       return 'plugin'
  91|     default:
  92|       return ''
  93|   }
  94| }
  95| 

createSkillCommand

createSkillCommand({...}) 把 MarkdownFile + frontmatter 转为 PromptCommand:

关键 frontmatter 字段:

  • description / argument-hint / allowed-tools
  • model / effort / disable-model-invocation
  • context: inline | fork → SkillTool executeForkedSkill
  • agent → 指定 subagent type
  • hooks → HooksSchema 校验

getPromptForCommand 闭包:

  • substituteArguments 替换 $ARGUMENTS
  • executeShellCommandsInPrompt 执行 inline shell
  • roughTokenCountEstimation 记录 analytics

parseSkillFrontmatterFields 供 MCP skill builders 复用同一解析逻辑。

源码引用: src/skills/loadSkillsDir.ts · 第 270–310 行(共 1087 行)

 270| export function createSkillCommand({
 271|   skillName,
 272|   displayName,
 273|   description,
 274|   hasUserSpecifiedDescription,
 275|   markdownContent,
 276|   allowedTools,
 277|   argumentHint,
 278|   argumentNames,
 279|   whenToUse,
 280|   version,
 281|   model,
 282|   disableModelInvocation,
 283|   userInvocable,
 284|   source,
 285|   baseDir,
 286|   loadedFrom,
 287|   hooks,
 288|   executionContext,
 289|   agent,
 290|   paths,
 291|   effort,
 292|   shell,
 293| }: {
 294|   skillName: string
 295|   displayName: string | undefined
 296|   description: string
 297|   hasUserSpecifiedDescription: boolean
 298|   markdownContent: string
 299|   allowedTools: string[]
 300|   argumentHint: string | undefined
 301|   argumentNames: string[]
 302|   whenToUse: string | undefined
 303|   version: string | undefined
 304|   model: string | undefined
 305|   disableModelInvocation: boolean
 306|   userInvocable: boolean
 307|   source: PromptCommand['source']
 308|   baseDir: string | undefined
 309|   loadedFrom: LoadedFrom
 310|   hooks: HooksSettings | undefined

源码引用: src/utils/frontmatterParser.ts · 第 36–36 行(共 371 行)

  36|   // Validated by HooksSchema in loadSkillsDir.ts

registerBundledSkill 注册表

BundledSkillDefinition 字段:

  • name, description, aliases, whenToUse
  • allowedTools, model, disableModelInvocation, userInvocable
  • isEnabled() 动态 gate(feature / env)
  • hooks, context, agent
  • files — 首次调用时 extract 到磁盘,prepend "Base directory for this skill"

内部 bundledSkills: Command[] 数组;getBundledSkills() 返回副本供 getCommands merge。

registerBundledSkill 包装 getPromptForCommand:files 存在时 memoize extractionPromise 防并发 race。

源码引用: src/skills/bundledSkills.ts · 第 15–41 行(共 221 行)

  15| export type BundledSkillDefinition = {
  16|   name: string
  17|   description: string
  18|   aliases?: string[]
  19|   whenToUse?: string
  20|   argumentHint?: string
  21|   allowedTools?: string[]
  22|   model?: string
  23|   disableModelInvocation?: boolean
  24|   userInvocable?: boolean
  25|   isEnabled?: () => boolean
  26|   hooks?: HooksSettings
  27|   context?: 'inline' | 'fork'
  28|   agent?: string
  29|   /**
  30|    * Additional reference files to extract to disk on first invocation.
  31|    * Keys are relative paths (forward slashes, no `..`), values are content.
  32|    * When set, the skill prompt is prefixed with a "Base directory for this
  33|    * skill: <dir>" line so the model can Read/Grep these files on demand —
  34|    * same contract as disk-based skills.
  35|    */
  36|   files?: Record<string, string>
  37|   getPromptForCommand: (
  38|     args: string,
  39|     context: ToolUseContext,
  40|   ) => Promise<ContentBlockParam[]>
  41| }

源码引用: src/skills/bundledSkills.ts · 第 53–80 行(共 221 行)

  53| export function registerBundledSkill(definition: BundledSkillDefinition): void {
  54|   const { files } = definition
  55| 
  56|   let skillRoot: string | undefined
  57|   let getPromptForCommand = definition.getPromptForCommand
  58| 
  59|   if (files && Object.keys(files).length > 0) {
  60|     skillRoot = getBundledSkillExtractDir(definition.name)
  61|     // Closure-local memoization: extract once per process.
  62|     // Memoize the promise (not the result) so concurrent callers await
  63|     // the same extraction instead of racing into separate writes.
  64|     let extractionPromise: Promise<string | null> | undefined
  65|     const inner = definition.getPromptForCommand
  66|     getPromptForCommand = async (args, ctx) => {
  67|       extractionPromise ??= extractBundledSkillFiles(definition.name, files)
  68|       const extractedDir = await extractionPromise
  69|       const blocks = await inner(args, ctx)
  70|       if (extractedDir === null) return blocks
  71|       return prependBaseDir(blocks, extractedDir)
  72|     }
  73|   }
  74| 
  75|   const command: Command = {
  76|     type: 'prompt',
  77|     name: definition.name,
  78|     description: definition.description,
  79|     aliases: definition.aliases,
  80|     hasUserSpecifiedDescription: true,

files 提取与 prependBaseDir

当 definition.files 非空:

  1. skillRoot = getBundledSkillExtractDir(name)
  2. extractBundledSkillFiles(name, files) 写入 forward-slash 相对路径
  3. getPromptForCommand wrapper prepend base dir 行到 ContentBlockParam[]

模型收到 prompt 后可 Read/Grep 提取目录内 reference md——与磁盘 skill 相同契约。

getBundledSkillsRoot 来自 utils/permissions/filesystem.js,权限系统知悉 extract 根路径。

源码引用: src/skills/bundledSkills.ts · 第 59–73 行(共 221 行)

  59|   if (files && Object.keys(files).length > 0) {
  60|     skillRoot = getBundledSkillExtractDir(definition.name)
  61|     // Closure-local memoization: extract once per process.
  62|     // Memoize the promise (not the result) so concurrent callers await
  63|     // the same extraction instead of racing into separate writes.
  64|     let extractionPromise: Promise<string | null> | undefined
  65|     const inner = definition.getPromptForCommand
  66|     getPromptForCommand = async (args, ctx) => {
  67|       extractionPromise ??= extractBundledSkillFiles(definition.name, files)
  68|       const extractedDir = await extractionPromise
  69|       const blocks = await inner(args, ctx)
  70|       if (extractedDir === null) return blocks
  71|       return prependBaseDir(blocks, extractedDir)
  72|     }
  73|   }

源码引用: src/skills/bundledSkills.ts · 第 43–52 行(共 221 行)

  43| // Internal registry for bundled skills
  44| const bundledSkills: Command[] = []
  45| 
  46| /**
  47|  * Register a bundled skill that will be available to the model.
  48|  * Call this at module initialization or in an init function.
  49|  *
  50|  * Bundled skills are compiled into the CLI binary and available to all users.
  51|  * They follow the same pattern as registerPostSamplingHook() for internal features.
  52|  */

registerMCPSkillBuilders 模块 init

loadSkillsDir.ts 文件末尾:

registerMCPSkillBuilders({
  createSkillCommand,
  parseSkillFrontmatterFields,
})

mcpSkillBuilders.ts 注释解释:

  • 动态 import 非字面量在 Bun bunfs 失败
  • 静态 import 导致 dependency-cruiser 环
  • write-once registry 在 loadSkillsDir eval 时注册(commands.ts 静态 import 保证 startup 前完成)

getMCPSkillBuilders() 未注册时 throw,表明 load order bug。

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

   6| /**
   7|  * Write-once registry for the two loadSkillsDir functions that MCP skill
   8|  * discovery needs. This module is a dependency-graph leaf: it imports nothing
   9|  * but types, so both mcpSkills.ts and loadSkillsDir.ts can depend on it
  10|  * without forming a cycle (client.ts → mcpSkills.ts → loadSkillsDir.ts → …
  11|  * → client.ts).
  12|  *
  13|  * The non-literal dynamic-import approach ("await import(variable)") fails at
  14|  * runtime in Bun-bundled binaries — the specifier is resolved against the
  15|  * chunk's /$bunfs/root/… path, not the original source tree, yielding "Cannot
  16|  * find module './loadSkillsDir.js'". A literal dynamic import works in bunfs
  17|  * but dependency-cruiser tracks it, and because loadSkillsDir transitively
  18|  * reaches almost everything, the single new edge fans out into many new cycle
  19|  * violations in the diff check.
  20|  *
  21|  * Registration happens at loadSkillsDir.ts module init, which is eagerly
  22|  * evaluated at startup via the static import from commands.ts — long before
  23|  * any MCP server connects.
  24|  */
  25| 
  26| export type MCPSkillBuilders = {
  27|   createSkillCommand: typeof createSkillCommand
  28|   parseSkillFrontmatterFields: typeof parseSkillFrontmatterFields
  29| }
  30| 
  31| let builders: MCPSkillBuilders | null = null
  32| 
  33| export function registerMCPSkillBuilders(b: MCPSkillBuilders): void {
  34|   builders = b
  35| }
  36| 
  37| export function getMCPSkillBuilders(): MCPSkillBuilders {
  38|   if (!builders) {
  39|     throw new Error(
  40|       'MCP skill builders not registered — loadSkillsDir.ts has not been evaluated yet',
  41|     )
  42|   }
  43|   return builders
  44| }

源码引用: src/skills/loadSkillsDir.ts · 第 65–65 行(共 1087 行)

  65| import { registerMCPSkillBuilders } from './mcpSkillBuilders.js'

frontmatter 解析与 HooksSchema

loadSkillsDir 使用 parseFrontmatter、parseBooleanFrontmatter、parseShellFrontmatter、splitPathInFrontmatter 处理 SKILL.md YAML。

HooksSchema(utils/settings/types.js)校验 skill hooks 块——与 settings hooks 同 schema,避免两套规则。

parseSlashCommandToolsFromFrontmatter 限制 skill 可调用 tool 子集;与 allowed-tools 字段协同。

isRestrictedToPluginOnly 企业策略下拒绝非 plugin skill 加载,log 并 skip。

源码引用: src/skills/loadSkillsDir.ts · 第 38–56 行(共 1087 行)

  38| import {
  39|   coerceDescriptionToString,
  40|   type FrontmatterData,
  41|   type FrontmatterShell,
  42|   parseBooleanFrontmatter,
  43|   parseFrontmatter,
  44|   parseShellFrontmatter,
  45|   splitPathInFrontmatter,
  46| } from '../utils/frontmatterParser.js'
  47| import { getFsImplementation } from '../utils/fsOperations.js'
  48| import { isPathGitignored } from '../utils/git/gitignore.js'
  49| import { logError } from '../utils/log.js'
  50| import {
  51|   extractDescriptionFromMarkdown,
  52|   getProjectDirsUpToHome,
  53|   loadMarkdownFilesForSubdir,
  54|   type MarkdownFile,
  55|   parseSlashCommandToolsFromFrontmatter,
  56| } from '../utils/markdownConfigLoader.js'

memoize 与并发加载

loadSkillsDir 使用 lodash memoize 缓存目录扫描结果;plugin 安装或 /clear 时 clearDynamicSkills bust cache。

createSignal 与 skillChangeDetector 配合 REPL useSkillsChange 热重载。

logEvent skill 加载带 LoadedFrom 维度 analytics;失败文件收集到 warnings 而非 crash 全表。

getProjectDirsUpToHome 限定扫描深度,避免 HOME 以上越界。

缓存失效与 telemetry

clearDynamicSkills(loadSkillsDir export)在 /clear caches 命令调用,丢弃 memoized 扫描结果。

skillChangeDetector / skillLoadedEvent telemetry 在 skill 加载时 logEvent。

estimateSkillFrontmatterTokens 供 SkillsMenu、analyzeContext 估算 skill 占用 context。

disk skill 变更 → useSkillsChange → REPL setLocalCommands → 无需重启进程。

源码引用: src/commands/clear/caches.ts · 第 26–26 行(共 145 行)

  26| import { clearDynamicSkills } from '../../skills/loadSkillsDir.js'

源码引用: src/components/skills/SkillsMenu.tsx · 第 7–7 行(共 206 行)

   7|   type CommandResultDisplay,

本章小结与延伸

loadSkillsDir = 磁盘 skill 扫描器;bundledSkills = 内存注册表。MCP 构建见 mcp-skills 章。扫描路径含 user/project/managed/plugin 四层 settings 源。 继续学习:

  • bundled-skills
  • mcp-skills
Prev
模块: skills
Next
bundled-skills · 内置 skill 与 initBundledSkills