13. 其他工具 - Skill/LSP/Sleep等
所属分组:工具系统
概述
Claude Code 的工具系统除了核心的文件操作、命令执行和网络工具外,还包含一组辅助工具,包括 SkillTool、LSPTool 和 SleepTool。这些工具虽然不是日常使用频率最高的,但它们在特定场景下发挥着重要作用:SkillTool 用于执行斜杠命令技能,LSPTool 提供代码智能分析能力,SleepTool 实现会话暂停功能。
本文将深入分析这三个辅助工具的实现机制、设计意图以及它们在整体工具系统中的定位。
源码位置
- SkillTool 核心实现:tools/SkillTool/SkillTool.ts(file:///e:/2026plan/AI_Lab/claude-code-sourcemap-main/restored-src/src/tools/SkillTool/SkillTool.ts)
- SkillTool UI 组件:tools/SkillTool/UI.tsx(file:///e:/2026plan/AI_Lab/claude-code-sourcemap-main/restored-src/src/tools/SkillTool/UI.tsx)
- SkillTool 提示词:tools/SkillTool/prompt.ts(file:///e:/2026plan/AI_Lab/claude-code-sourcemap-main/restored-src/src/tools/SkillTool/prompt.ts)
- SkillTool 常量:tools/SkillTool/constants.ts(file:///e:/2026plan/AI_Lab/claude-code-sourcemap-main/restored-src/src/tools/SkillTool/constants.ts)
- LSPTool 核心实现:tools/LSPTool/LSPTool.ts(file:///e:/2026plan/AI_Lab/claude-code-sourcemap-main/restored-src/src/tools/LSPTool/LSPTool.ts)
- LSPTool UI 组件:tools/LSPTool/UI.tsx(file:///e:/2026plan/AI_Lab/claude-code-sourcemap-main/restored-src/src/tools/LSPTool/UI.tsx)
- LSPTool 提示词:tools/LSPTool/prompt.ts(file:///e:/2026plan/AI_Lab/claude-code-sourcemap-main/restored-src/src/tools/LSPTool/prompt.ts)
- LSPTool 格式化器:tools/LSPTool/formatters.ts(file:///e:/2026plan/AI_Lab/claude-code-sourcemap-main/restored-src/src/tools/LSPTool/formatters.ts)
- LSPTool Schema:tools/LSPTool/schemas.ts(file:///e:/2026plan/AI_Lab/claude-code-sourcemap-main/restored-src/src/tools/LSPTool/schemas.ts)
- SleepTool 提示词:tools/SleepTool/prompt.ts(file:///e:/2026plan/AI_Lab/claude-code-sourcemap-main/restored-src/src/tools/SleepTool/prompt.ts)
核心实现分析
SkillTool - 斜杠命令技能执行器
SkillTool 是 Claude Code 中执行斜杠命令技能的核心工具,它允许模型通过工具调用的方式执行各种技能,如 /commit、/review、/plan 等。
基础结构
ts
export const SkillTool: Tool<InputSchema, Output, Progress> = buildTool({
name: SKILL_TOOL_NAME,
searchHint: 'invoke a slash-command skill',
maxResultSizeChars: 100_000,
get inputSchema(): InputSchema {
return inputSchema()
},
get outputSchema(): OutputSchema {
return outputSchema()
},
description: async ({ skill }) => `Execute skill: ${skill}`,
// ... 其他配置
} satisfies ToolDef<InputSchema, Output, Progress>)
输入输出 Schema
ts
export const inputSchema = lazySchema(() =>
z.object({
skill: z.string().describe('The skill name. E.g., "commit", "review-pr", or "pdf"'),
args: z.string().optional().describe('Optional arguments for the skill'),
}),
)
export const outputSchema = lazySchema(() => {
const inlineOutputSchema = z.object({
success: z.boolean(),
commandName: z.string(),
allowedTools: z.array(z.string()).optional(),
model: z.string().optional(),
status: z.literal('inline').optional(),
})
const forkedOutputSchema = z.object({
success: z.boolean(),
commandName: z.string(),
status: z.literal('forked'),
agentId: z.string(),
result: z.string(),
})
return z.union([inlineOutputSchema, forkedOutputSchema])
})
SkillTool 支持两种执行模式:inline(内联)模式 和 forked(分叉)模式。内联模式直接扩展技能提示词并注入到当前会话中,而分叉模式则创建一个独立的子代理来执行技能。
技能执行流程
call 方法实现了完整的技能执行流程:
- 技能验证:检查技能名称是否有效,是否存在于命令注册表中
- 远程技能处理 :如果是远程发现的技能,通过
executeRemoteSkill加载和执行 - 分叉模式判断:根据技能配置决定是否使用分叉模式
- 命令处理 :通过
processPromptSlashCommand处理斜杠命令,生成消息和上下文修改器
关键代码片段:
ts
async call({ skill, args }, context, canUseTool, parentMessage, onProgress?) {
const commandName = trimmed.startsWith('/') ? trimmed.substring(1) : trimmed
// 远程技能处理(实验性)
if (feature('EXPERIMENTAL_SKILL_SEARCH') && process.env.USER_TYPE === 'ant') {
const slug = remoteSkillModules!.stripCanonicalPrefix(commandName)
if (slug !== null) {
return executeRemoteSkill(slug, commandName, parentMessage, context)
}
}
// 分叉模式执行
if (command?.type === 'prompt' && command.context === 'fork') {
return executeForkedSkill(command, commandName, args, context, canUseTool, parentMessage, onProgress)
}
// 内联模式执行
const processedCommand = await processPromptSlashCommand(commandName, args || '', commands, context)
// ...
}
权限控制机制
SkillTool 实现了多层次的权限控制:
- 规则匹配 :根据
deny、allow规则进行权限判断,支持精确匹配和前缀匹配 - 安全属性检查 :通过
SAFE_SKILL_PROPERTIES白名单自动允许只包含安全属性的技能 - 远程技能自动授权:官方远程技能自动授予权限
关键代码片段:
ts
async checkPermissions({ skill, args }, context): Promise<PermissionDecision> {
// 检查 deny 规则
for (const [ruleContent, rule] of denyRules.entries()) {
if (ruleMatches(ruleContent)) {
return { behavior: 'deny', message: `Skill execution blocked by permission rules`, decisionReason: { type: 'rule', rule } }
}
}
// 自动允许安全技能
if (commandObj?.type === 'prompt' && skillHasOnlySafeProperties(commandObj)) {
return { behavior: 'allow', updatedInput: { skill, args }, decisionReason: undefined }
}
// 默认行为:询问用户
return { behavior: 'ask', message: `Execute skill: ${commandName}`, suggestions }
}
分叉模式执行
分叉模式通过 executeForkedSkill 函数实现,它创建一个独立的子代理来执行技能:
ts
async function executeForkedSkill(command, commandName, args, context, canUseTool, parentMessage, onProgress?) {
const agentId = createAgentId()
const { modifiedGetAppState, baseAgent, promptMessages, skillContent } =
await prepareForkedCommandContext(command, args || '', context)
// 运行子代理
for await (const message of runAgent({
agentDefinition,
promptMessages,
toolUseContext: { ...context, getAppState: modifiedGetAppState },
canUseTool,
isAsync: false,
querySource: 'agent:custom',
model: command.model as ModelAlias | undefined,
availableTools: context.options.tools,
override: { agentId },
})) {
agentMessages.push(message)
// 报告进度
if (onProgress) {
onProgress({ toolUseID: `skill_${parentMessage.message.id}`, data: { message, type: 'skill_progress', prompt: skillContent, agentId } })
}
}
const resultText = extractResultText(agentMessages, 'Skill execution completed')
return { data: { success: true, commandName, status: 'forked', agentId, result: resultText } }
}
LSPTool - 语言服务器协议工具
LSPTool 是 Claude Code 中实现代码智能分析的核心工具,它通过 Language Server Protocol (LSP) 与语言服务器交互,提供定义跳转、引用查找、符号搜索等代码分析能力。
基础结构
ts
export const LSPTool = buildTool({
name: LSP_TOOL_NAME,
searchHint: 'code intelligence (definitions, references, symbols, hover)',
maxResultSizeChars: 100_000,
isLsp: true,
isEnabled() {
return isLspConnected()
},
// ... 其他配置
} satisfies ToolDef<InputSchema, Output>)
支持的操作类型
ts
const inputSchema = lazySchema(() =>
z.strictObject({
operation: z.enum([
'goToDefinition',
'findReferences',
'hover',
'documentSymbol',
'workspaceSymbol',
'goToImplementation',
'prepareCallHierarchy',
'incomingCalls',
'outgoingCalls',
]),
filePath: z.string(),
line: z.number().int().positive(),
character: z.number().int().positive(),
}),
)
LSPTool 支持九种 LSP 操作,覆盖了代码导航和分析的主要场景。
LSP 调用流程
call 方法实现了完整的 LSP 调用流程:
- 初始化等待:如果 LSP 服务器正在初始化,等待初始化完成
- 文件打开:确保文件在 LSP 服务器中打开,以便进行分析
- 请求发送:根据操作类型发送相应的 LSP 请求
- 结果格式化:将 LSP 服务器返回的结果格式化为人类可读的文本
关键代码片段:
ts
async call(input: Input, _context) {
const absolutePath = expandPath(input.filePath)
// 等待初始化完成
const status = getInitializationStatus()
if (status.status === 'pending') {
await waitForInitialization()
}
// 获取 LSP 服务器管理器
const manager = getLspServerManager()
if (!manager) {
return { data: { operation: input.operation, result: 'LSP server manager not initialized.', filePath: input.filePath } }
}
// 发送请求
const { method, params } = getMethodAndParams(input, absolutePath)
let result = await manager.sendRequest(absolutePath, method, params)
// 格式化结果
const { formatted, resultCount, fileCount } = formatResult(input.operation, result, cwd)
return { data: { operation: input.operation, result: formatted, filePath: input.filePath, resultCount, fileCount } }
}
调用层级处理
对于 incomingCalls 和 outgoingCalls 操作,需要两步处理:
- 准备调用层级 :发送
textDocument/prepareCallHierarchy请求获取调用层级项 - 获取调用信息 :使用获取到的调用层级项发送
callHierarchy/incomingCalls或callHierarchy/outgoingCalls请求
ts
if (input.operation === 'incomingCalls' || input.operation === 'outgoingCalls') {
const callItems = result as CallHierarchyItem[]
if (!callItems || callItems.length === 0) {
return { data: { operation: input.operation, result: 'No call hierarchy item found at this position', filePath: input.filePath, resultCount: 0, fileCount: 0 } }
}
const callMethod = input.operation === 'incomingCalls' ? 'callHierarchy/incomingCalls' : 'callHierarchy/outgoingCalls'
result = await manager.sendRequest(absolutePath, callMethod, { item: callItems[0] })
}
Git 忽略过滤
LSPTool 会过滤掉被 .gitignore 忽略的文件,确保搜索结果的相关性:
ts
async function filterGitIgnoredLocations<T extends Location>(locations: T[], cwd: string): Promise<T[]> {
// 使用 git check-ignore 批量检查路径
const ignoredPaths = new Set<string>()
const BATCH_SIZE = 50
for (let i = 0; i < uniquePaths.length; i += BATCH_SIZE) {
const batch = uniquePaths.slice(i, i + BATCH_SIZE)
const result = await execFileNoThrowWithCwd('git', ['check-ignore', ...batch], { cwd, timeout: 5_000 })
if (result.code === 0 && result.stdout) {
for (const line of result.stdout.split('\n')) {
const trimmed = line.trim()
if (trimmed) {
ignoredPaths.add(trimmed)
}
}
}
}
return locations.filter(loc => {
const filePath = uriToPath.get(loc.uri)
return !filePath || !ignoredPaths.has(filePath)
})
}
SleepTool - 会话暂停工具
SleepTool 是一个简单但实用的工具,用于实现会话暂停功能,让 Claude 在指定时间内不执行任何操作。
工具定义
ts
export const SLEEP_TOOL_NAME = 'Sleep'
export const DESCRIPTION = 'Wait for a specified duration'
export const SLEEP_TOOL_PROMPT = `Wait for a specified duration. The user can interrupt the sleep at any time.
Use this when the user tells you to sleep or rest, when you have nothing to do, or when you're waiting for something.
You may receive <${TICK_TAG}> prompts --- these are periodic check-ins. Look for useful work to do before sleeping.
You can call this concurrently with other tools --- it won't interfere with them.
Prefer this over \`Bash(sleep ...)\` --- it doesn't hold a shell process.
Each wake-up costs an API call, but the prompt cache expires after 5 minutes of inactivity --- balance accordingly.`
SleepTool 的设计意图包括:
- 资源友好 :相比
Bash(sleep ...),SleepTool 不需要占用 shell 进程 - 可中断:用户可以随时中断暂停
- 并发安全:可以与其他工具并发执行,不会相互干扰
- 成本意识:提示词中明确提到 API 调用成本,帮助模型做出合理决策
关键设计要点
- 技能执行模式:SkillTool 支持内联和分叉两种执行模式,分叉模式提供了隔离的执行环境,适合需要独立上下文的复杂技能
- 权限白名单 :SkillTool 通过
SAFE_SKILL_PROPERTIES白名单实现自动授权,平衡安全性和可用性 - LSP 集成:LSPTool 通过 Language Server Protocol 提供代码智能分析能力,支持多种代码导航操作
- Git 集成 :LSPTool 自动过滤
.gitignore文件,确保搜索结果的相关性 - 资源优化:SleepTool 相比 shell 命令更资源友好,不需要占用额外进程
与其他模块的关系
- 工具系统:SkillTool、LSPTool 和 SleepTool 都是工具系统的组成部分,与其他工具并列使用
- 命令系统:SkillTool 依赖命令系统来查找和执行技能
- 权限系统:SkillTool 和 LSPTool 都依赖权限系统进行访问控制
- LSP 服务层 :LSPTool 依赖
services/lsp/manager.ts中的 LSP 服务器管理器 - Agent 系统:SkillTool 的分叉模式依赖 Agent 系统创建和管理子代理
- UI 层 :每个工具都有对应的
UI.tsx组件提供终端渲染
小结
SkillTool、LSPTool 和 SleepTool 虽然定位不同,但都在 Claude Code 的工具系统中扮演着重要角色。SkillTool 是斜杠命令技能的执行入口,支持内联和分叉两种模式;LSPTool 通过语言服务器协议提供代码智能分析能力;SleepTool 则实现了资源友好的会话暂停功能。这些工具共同构成了 Claude Code 丰富的工具生态,为用户提供了多样化的交互方式。