本章总览
SkillTool 是模型 invocation skill 的入口 tool(SKILL_TOOL_NAME),串联 findCommand、权限(SkillPermissionRequest)、fork context(executeForkedSkill)与 prompt 注入。commands.ts 在启动时 merge bundled + disk skills。本章描述 SkillTool 与 skills 加载层的集成,以及 slash command 注册热重载。
学完本章你应该能
- 说明 SkillTool 与 getCommands 的能力差异(MCP merge)
- 解释 executeForkedSkill 与 context:fork frontmatter
- 描述 SkillPermissionRequest 与 getRuleByContentsForTool
- 理解 addInvokedSkill / recordSkillUsage telemetry
- 掌握 builtInCommandNames 与 bundled skill 命名
核心概念(先读懂这些)
SkillTool 是模型侧;slash 是用户侧
用户输入 /verify → processSlashCommand → findCommand。模型发 SkillTool tool_use → SkillTool.call → 同一 getPromptForCommand 路径。disableModelInvocation frontmatter 阻断后者保留前者。
fork context 隔离 token
executeForkedSkill 用 runAgent 在 subagent 跑 skill prompt,parent transcript 只收到摘要。loadSkillsDir frontmatter context:fork 与 bundled registerBundledSkill context 字段一致。
建议学习步骤
- 阅读 getAllCommands MCP merge(源码块 A)
- 阅读 executeForkedSkill 开头(源码块 B)
- 阅读 SkillTool buildTool / schema(源码块 C)
- 阅读 commands.ts skills import(源码块 D)
- 阅读 SkillPermissionRequest 接缝(源码块 E)
常见误区
注意
custom skill 名在 fork telemetry sanitizes 为 custom
注意
remote skill search 用 require gated by EXPERIMENTAL_SKILL_SEARCH
注意
SkillTool prompt.ts 描述可用 skill 列表给模型
SkillTool 在 tool 体系中的位置
getTools(toolPermissionContext)
└─ SkillTool (buildTool)
模型 tool_use: SkillTool { command: "verify", args: "..." }
→ getAllCommands(context) // local + mcp skills
→ findCommand(name)
→ permission: SkillPermissionRequest / getRuleByContentsForTool
→ inline: inject prompt blocks → continue query
→ fork: executeForkedSkill → runAgent → extractResultText
用户 /verify args
→ processSlashCommand (utils/processUserInput)
→ 同一 findCommand + getPromptForCommand
constants/tools.ts 注册 SKILL_TOOL_NAME;prompts 教模型何时用 Skill vs 直接工具。
源码引用: src/tools/SkillTool/SkillTool.ts · 第 1–75 行(共 1109 行)
1| import { feature } from 'bun:bundle'
2| import type { ToolResultBlockParam } from '@anthropic-ai/sdk/resources/index.mjs'
3| import uniqBy from 'lodash-es/uniqBy.js'
4| import { dirname } from 'path'
5| import { getProjectRoot } from 'src/bootstrap/state.js'
6| import {
7| builtInCommandNames,
8| findCommand,
9| getCommands,
10| type PromptCommand,
11| } from 'src/commands.js'
12| import type {
13| Tool,
14| ToolCallProgress,
15| ToolResult,
16| ToolUseContext,
17| ValidationResult,
18| } from 'src/Tool.js'
19| import { buildTool, type ToolDef } from 'src/Tool.js'
20| import type { Command } from 'src/types/command.js'
21| import type {
22| AssistantMessage,
23| AttachmentMessage,
24| Message,
25| SystemMessage,
26| UserMessage,
27| } from 'src/types/message.js'
28| import { logForDebugging } from 'src/utils/debug.js'
29| import type { PermissionDecision } from 'src/utils/permissions/PermissionResult.js'
30| import { getRuleByContentsForTool } from 'src/utils/permissions/permissions.js'
31| import {
32| isOfficialMarketplaceName,
33| parsePluginIdentifier,
34| } from 'src/utils/plugins/pluginIdentifier.js'
35| import { buildPluginCommandTelemetryFields } from 'src/utils/telemetry/pluginTelemetry.js'
36| import { z } from 'zod/v4'
37| import {
38| addInvokedSkill,
39| clearInvokedSkillsForAgent,
40| getSessionId,
41| } from '../../bootstrap/state.js'
42| import { COMMAND_MESSAGE_TAG } from '../../constants/xml.js'
43| import type { CanUseToolFn } from '../../hooks/useCanUseTool.js'
44| import {
45| type AnalyticsMetadata_I_VERIFIED_THIS_IS_NOT_CODE_OR_FILEPATHS,
46| type AnalyticsMetadata_I_VERIFIED_THIS_IS_PII_TAGGED,
47| logEvent,
48| } from '../../services/analytics/index.js'
49| import { getAgentContext } from '../../utils/agentContext.js'
50| import { errorMessage } from '../../utils/errors.js'
51| import {
52| extractResultText,
53| prepareForkedCommandContext,
54| } from '../../utils/forkedAgent.js'
55| import { parseFrontmatter } from '../../utils/frontmatterParser.js'
56| import { lazySchema } from '../../utils/lazySchema.js'
57| import { createUserMessage, normalizeMessages } from '../../utils/messages.js'
58| import type { ModelAlias } from '../../utils/model/aliases.js'
59| import { resolveSkillModelOverride } from '../../utils/model/model.js'
60| import { recordSkillUsage } from '../../utils/suggestions/skillUsageTracking.js'
61| import { createAgentId } from '../../utils/uuid.js'
62| import { runAgent } from '../AgentTool/runAgent.js'
63| import {
64| getToolUseIDFromParentMessage,
65| tagMessagesWithToolUseID,
66| } from '../utils.js'
67| import { SKILL_TOOL_NAME } from './constants.js'
68| import { getPrompt } from './prompt.js'
69| import {
70| renderToolResultMessage,
71| renderToolUseErrorMessage,
72| renderToolUseMessage,
73| renderToolUseProgressMessage,
74| renderToolUseRejectedMessage,
75| } from './UI.js'
源码缺失
File not found: c:\Users\123\Desktop\jd\Claude code源码\claude-code-complete\claude-code-complete\src-readable\tools\SkillTool\constants.js
getAllCommands:为何 SkillTool 不只用 getCommands
getCommands(projectRoot)(commands.ts)merge builtin + disk + bundled,不含 MCP AppState commands。
SkillTool getAllCommands 追加:
context.getAppState().mcp.commands.filter(
cmd => cmd.type === 'prompt' && cmd.loadedFrom === 'mcp',
)
uniqBy name 去重。注释说明防止模型猜测 mcp__server__prompt 名 invoke 非 skill 化 MCP prompt。
getCommands 供 PromptInput slash 补全;SkillTool 供模型发现完整 skill 集。
源码引用: src/tools/SkillTool/SkillTool.ts · 第 77–94 行(共 1109 行)
77| /**
78| * Gets all commands including MCP skills/prompts from AppState.
79| * SkillTool needs this because getCommands() only returns local/bundled skills.
80| */
81| async function getAllCommands(context: ToolUseContext): Promise<Command[]> {
82| // Only include MCP skills (loadedFrom === 'mcp'), not plain MCP prompts.
83| // Before this filter, the model could invoke MCP prompts via SkillTool
84| // if it guessed the mcp__server__prompt name — they weren't discoverable
85| // but were technically reachable.
86| const mcpSkills = context
87| .getAppState()
88| .mcp.commands.filter(
89| cmd => cmd.type === 'prompt' && cmd.loadedFrom === 'mcp',
90| )
91| if (mcpSkills.length === 0) return getCommands(getProjectRoot())
92| const localCommands = await getCommands(getProjectRoot())
93| return uniqBy([...localCommands, ...mcpSkills], 'name')
94| }
源码引用: src/commands.ts · 第 155–165 行(共 755 行)
155| import { logForDebugging } from './utils/debug.js'
156| import {
157| getSkillDirCommands,
158| clearSkillCaches,
159| getDynamicSkills,
160| } from './skills/loadSkillsDir.js'
161| import { getBundledSkills } from './skills/bundledSkills.js'
162| import { getBuiltinPluginSkillCommands } from './plugins/builtinPlugins.js'
163| import {
164| getPluginCommands,
165| clearPluginCommandCache,
executeForkedSkill
async function executeForkedSkill(command, commandName, args, context, canUseTool, ...)
要点:
createAgentId()新 subagentbuiltInCommandNames().has(commandName)→ telemetry sanitized nameisBundled = command.source === 'bundled'prepareForkedCommandContext组装 isolated messagesrunAgent执行 with separate token budgetextractResultText返回 parent-facing 摘要
onProgress 渲染 SkillTool UI progress(UI.tsx)。
frontmatter context: 'fork' 或 bundled definition context 字段触发此路径。
源码引用: src/tools/SkillTool/SkillTool.ts · 第 118–155 行(共 1109 行)
118| /**
119| * Executes a skill in a forked sub-agent context.
120| * This runs the skill prompt in an isolated agent with its own token budget.
121| */
122| async function executeForkedSkill(
123| command: Command & { type: 'prompt' },
124| commandName: string,
125| args: string | undefined,
126| context: ToolUseContext,
127| canUseTool: CanUseToolFn,
128| parentMessage: AssistantMessage,
129| onProgress?: ToolCallProgress<Progress>,
130| ): Promise<ToolResult<Output>> {
131| const startTime = Date.now()
132| const agentId = createAgentId()
133| const isBuiltIn = builtInCommandNames().has(commandName)
134| const isOfficialSkill = isOfficialMarketplaceSkill(command)
135| const isBundled = command.source === 'bundled'
136| const forkedSanitizedName =
137| isBuiltIn || isBundled || isOfficialSkill ? commandName : 'custom'
138|
139| const wasDiscoveredField =
140| feature('EXPERIMENTAL_SKILL_SEARCH') &&
141| remoteSkillModules!.isSkillSearchEnabled()
142| ? {
143| was_discovered:
144| context.discoveredSkillNames?.has(commandName) ?? false,
145| }
146| : {}
147| const pluginMarketplace = command.pluginInfo
148| ? parsePluginIdentifier(command.pluginInfo.repository).marketplace
149| : undefined
150| const queryDepth = context.queryTracking?.depth ?? 0
151| const parentAgentId = getAgentContext()?.agentId
152| logEvent('tengu_skill_tool_invocation', {
153| command_name:
154| forkedSanitizedName as AnalyticsMetadata_I_VERIFIED_THIS_IS_NOT_CODE_OR_FILEPATHS,
155| // _PROTO_skill_name routes to the privileged skill_name BQ column
源码引用: src/utils/forkedAgent.ts · 第 1–30 行(共 690 行)
1| /**
2| * Helper for running forked agent query loops with usage tracking.
3| *
4| * This utility ensures forked agents:
5| * 1. Share identical cache-critical params with the parent to guarantee prompt cache hits
6| * 2. Track full usage metrics across the entire query loop
7| * 3. Log metrics via the tengu_fork_agent_query event when complete
8| * 4. Isolate mutable state to prevent interference with the main agent loop
9| */
10|
11| import type { UUID } from 'crypto'
12| import { randomUUID } from 'crypto'
13| import type { PromptCommand } from '../commands.js'
14| import type { QuerySource } from '../constants/querySource.js'
15| import type { CanUseToolFn } from '../hooks/useCanUseTool.js'
16| import { query } from '../query.js'
17| import {
18| type AnalyticsMetadata_I_VERIFIED_THIS_IS_NOT_CODE_OR_FILEPATHS,
19| logEvent,
20| } from '../services/analytics/index.js'
21| import { accumulateUsage, updateUsage } from '../services/api/claude.js'
22| import { EMPTY_USAGE, type NonNullableUsage } from '../services/api/logging.js'
23| import type { ToolUseContext } from '../Tool.js'
24| import type { AgentDefinition } from '../tools/AgentTool/loadAgentsDir.js'
25| import type { AgentId } from '../types/ids.js'
26| import type { Message } from '../types/message.js'
27| import { createChildAbortController } from './abortController.js'
28| import { logForDebugging } from './debug.js'
29| import { cloneFileStateCache } from './fileStateCache.js'
30| import type { REPLHookContext } from './hooks/postSamplingHooks.js'
SkillTool 定义与 prompt
buildTool 包装 SkillTool 定义:
- input schema: command string + optional args(zod lazySchema)
- getPrompt(prompt.ts)— 系统 prompt 中列出 invocable skills
- renderToolUseMessage / Progress / Rejected UI(UI.tsx)
- call 主逻辑:findCommand → permission → inline/fork 分支
addInvokedSkill(getSessionId()) 记录 session 内已 invoke skill,防重复或 analytics。
resolveSkillModelOverride 应用 skill frontmatter model 字段。
源码引用: src/tools/SkillTool/SkillTool.ts · 第 67–75 行(共 1109 行)
67| import { SKILL_TOOL_NAME } from './constants.js'
68| import { getPrompt } from './prompt.js'
69| import {
70| renderToolResultMessage,
71| renderToolUseErrorMessage,
72| renderToolUseMessage,
73| renderToolUseProgressMessage,
74| renderToolUseRejectedMessage,
75| } from './UI.js'
源码引用: src/tools/SkillTool/prompt.ts · 第 1–40 行(共 242 行)
1| import { memoize } from 'lodash-es'
2| import type { Command } from 'src/commands.js'
3| import {
4| getCommandName,
5| getSkillToolCommands,
6| getSlashCommandToolSkills,
7| } from 'src/commands.js'
8| import { COMMAND_NAME_TAG } from '../../constants/xml.js'
9| import { stringWidth } from '../../ink/stringWidth.js'
10| import {
11| type AnalyticsMetadata_I_VERIFIED_THIS_IS_NOT_CODE_OR_FILEPATHS,
12| logEvent,
13| } from '../../services/analytics/index.js'
14| import { count } from '../../utils/array.js'
15| import { logForDebugging } from '../../utils/debug.js'
16| import { toError } from '../../utils/errors.js'
17| import { truncate } from '../../utils/format.js'
18| import { logError } from '../../utils/log.js'
19|
20| // Skill listing gets 1% of the context window (in characters)
21| export const SKILL_BUDGET_CONTEXT_PERCENT = 0.01
22| export const CHARS_PER_TOKEN = 4
23| export const DEFAULT_CHAR_BUDGET = 8_000 // Fallback: 1% of 200k × 4
24|
25| // Per-entry hard cap. The listing is for discovery only — the Skill tool loads
26| // full content on invoke, so verbose whenToUse strings waste turn-1 cache_creation
27| // tokens without improving match rate. Applies to all entries, including bundled,
28| // since the cap is generous enough to preserve the core use case.
29| export const MAX_LISTING_DESC_CHARS = 250
30|
31| export function getCharBudget(contextWindowTokens?: number): number {
32| if (Number(process.env.SLASH_COMMAND_TOOL_CHAR_BUDGET)) {
33| return Number(process.env.SLASH_COMMAND_TOOL_CHAR_BUDGET)
34| }
35| if (contextWindowTokens) {
36| return Math.floor(
37| contextWindowTokens * CHARS_PER_TOKEN * SKILL_BUDGET_CONTEXT_PERCENT,
38| )
39| }
40| return DEFAULT_CHAR_BUDGET
权限:SkillPermissionRequest
skill 可能触发 SkillPermissionRequest(components/permissions/SkillPermissionRequest):
- getRuleByContentsForTool 检查 permission rules 是否 allow skill content
- 与 bash/edit 权限并列,REPL focusedInputDialog 栈管理
disableModelInvocation — 仅允许用户 /slash,SkillTool.call 拒绝。
userInvocable: false — 仅模型 SkillTool 可调用,slash 补全隐藏。
bundled remember 设 userInvocable: true + isEnabled gate。
源码引用: src/components/permissions/SkillPermissionRequest/SkillPermissionRequest.tsx · 第 1–30 行(共 254 行)
1| import React, { useCallback, useMemo } from 'react'
2| import { logError } from 'src/utils/log.js'
3| import { getOriginalCwd } from '../../../bootstrap/state.js'
4| import { Box, Text } from '../../../ink.js'
5| import { sanitizeToolNameForAnalytics } from '../../../services/analytics/metadata.js'
6| import { SKILL_TOOL_NAME } from '../../../tools/SkillTool/constants.js'
7| import { SkillTool } from '../../../tools/SkillTool/SkillTool.js'
8| import { env } from '../../../utils/env.js'
9| import { shouldShowAlwaysAllowOptions } from '../../../utils/permissions/permissionsLoader.js'
10| import { logUnaryEvent } from '../../../utils/unaryLogging.js'
11| import { type UnaryEvent, usePermissionRequestLogging } from '../hooks.js'
12| import { PermissionDialog } from '../PermissionDialog.js'
13| import {
14| PermissionPrompt,
15| type PermissionPromptOption,
16| type ToolAnalyticsContext,
17| } from '../PermissionPrompt.js'
18| import type { PermissionRequestProps } from '../PermissionRequest.js'
19| import { PermissionRuleExplanation } from '../PermissionRuleExplanation.js'
20|
21| type SkillOptionValue = 'yes' | 'yes-exact' | 'yes-prefix' | 'no'
22|
23| export function SkillPermissionRequest(
24| props: PermissionRequestProps,
25| ): React.ReactNode {
26| const {
27| toolUseConfirm,
28| onDone,
29| onReject,
30| verbose: _verbose,
源码引用: src/tools/SkillTool/SkillTool.ts · 第 29–30 行(共 1109 行)
29| import type { PermissionDecision } from 'src/utils/permissions/PermissionResult.js'
30| import { getRuleByContentsForTool } from 'src/utils/permissions/permissions.js'
commands.ts 与启动注册
commands.ts import loadSkillsDir 函数 merge disk skills。
main.tsx 顺序:
init()
initBundledSkills()
...
getCommands(projectRoot) → 传入 REPL commands prop
REPL useSkillsChange — disk skill 变更 → setLocalCommands(refresh)
bundled skill 变更需新版本;MCP skill 随连接动态变化,SkillTool 每次 call 读 fresh AppState。
源码引用: src/main.tsx · 第 1920–1930 行(共 6604 行)
1920| // These replace the CLAUDE_CODE_* environment variables
1921| const teammateOpts = extractTeammateOptions(options)
1922| storedTeammateOpts = teammateOpts
1923|
1924| // If any teammate identity option is provided, all three required ones must be present
1925| const hasAnyTeammateOpt =
1926| teammateOpts.agentId ||
1927| teammateOpts.agentName ||
1928| teammateOpts.teamName
1929| const hasAllRequiredTeammateOpts =
1930| teammateOpts.agentId &&
源码引用: src/commands.ts · 第 160–160 行(共 755 行)
160| } from './skills/loadSkillsDir.js'
builtInCommandNames 与 official marketplace
builtInCommandNames() 返回内置 slash 名集合;SkillTool fork telemetry 对 builtIn/bundled/official 保留原名,custom skill sanitize 为 'custom'。
isOfficialMarketplaceSkill 检查 plugin 来源是否官方 marketplace,影响 telemetry 字段。
parsePluginIdentifier / isOfficialMarketplaceName 防混淆第三方 plugin skill。
源码引用: src/tools/SkillTool/SkillTool.ts · 第 130–145 行(共 1109 行)
130| ): Promise<ToolResult<Output>> {
131| const startTime = Date.now()
132| const agentId = createAgentId()
133| const isBuiltIn = builtInCommandNames().has(commandName)
134| const isOfficialSkill = isOfficialMarketplaceSkill(command)
135| const isBundled = command.source === 'bundled'
136| const forkedSanitizedName =
137| isBuiltIn || isBundled || isOfficialSkill ? commandName : 'custom'
138|
139| const wasDiscoveredField =
140| feature('EXPERIMENTAL_SKILL_SEARCH') &&
141| remoteSkillModules!.isSkillSearchEnabled()
142| ? {
143| was_discovered:
144| context.discoveredSkillNames?.has(commandName) ?? false,
145| }
inline skill 执行路径
非 fork skill 在 SkillTool.call 内:
- findCommand + type==='prompt' 校验
- getPromptForCommand(args, context) → ContentBlockParam[]
- 注入 messages 为 user/attachment 块(COMMAND_MESSAGE_TAG)
- 继续 parent query 循环
resolveSkillModelOverride 临时切换 model;recordSkillUsage 更新 suggestions。
disableModelInvocation 时 SkillTool.call early reject,用户 /slash 仍可用 processSlashCommand。
源码引用: src/tools/SkillTool/SkillTool.ts · 第 200–250 行(共 1109 行)
200| : 'third-party') as AnalyticsMetadata_I_VERIFIED_THIS_IS_NOT_CODE_OR_FILEPATHS,
201| ...buildPluginCommandTelemetryFields(command.pluginInfo),
202| }),
203| })
204|
205| const { modifiedGetAppState, baseAgent, promptMessages, skillContent } =
206| await prepareForkedCommandContext(command, args || '', context)
207|
208| // Merge skill's effort into the agent definition so runAgent applies it
209| const agentDefinition =
210| command.effort !== undefined
211| ? { ...baseAgent, effort: command.effort }
212| : baseAgent
213|
214| // Collect messages from the forked agent
215| const agentMessages: Message[] = []
216|
217| logForDebugging(
218| `SkillTool executing forked skill ${commandName} with agent ${agentDefinition.agentType}`,
219| )
220|
221| try {
222| // Run the sub-agent
223| for await (const message of runAgent({
224| agentDefinition,
225| promptMessages,
226| toolUseContext: {
227| ...context,
228| getAppState: modifiedGetAppState,
229| },
230| canUseTool,
231| isAsync: false,
232| querySource: 'agent:custom',
233| model: command.model as ModelAlias | undefined,
234| availableTools: context.options.tools,
235| override: { agentId },
236| })) {
237| agentMessages.push(message)
238|
239| // Report progress for tool uses (like AgentTool does)
240| if (
241| (message.type === 'assistant' || message.type === 'user') &&
242| onProgress
243| ) {
244| const normalizedNew = normalizeMessages([message])
245| for (const m of normalizedNew) {
246| const hasToolContent = m.message.content.some(
247| c => c.type === 'tool_use' || c.type === 'tool_result',
248| )
249| if (hasToolContent) {
250| onProgress({
UI 渲染与 progress
SkillTool 使用 UI.tsx 四个 render 函数:
- renderToolUseMessage — 模型发起 skill 时行内展示
- renderToolUseProgressMessage — fork 或长 prompt 进度
- renderToolUseRejectedMessage — 权限拒绝
- renderToolResultMessage — 完成后摘要
与 BashTool 等共用 Tool 渲染管线;MessageRow 按 tool name 分发。
源码引用: src/tools/SkillTool/UI.tsx · 第 1–40 行(共 182 行)
1| import type { ToolResultBlockParam } from '@anthropic-ai/sdk/resources/index.mjs'
2| import * as React from 'react'
3| import { SubAgentProvider } from 'src/components/CtrlOToExpand.js'
4| import { FallbackToolUseErrorMessage } from 'src/components/FallbackToolUseErrorMessage.js'
5| import { FallbackToolUseRejectedMessage } from 'src/components/FallbackToolUseRejectedMessage.js'
6| import type { z } from 'zod/v4'
7| import type { Command } from '../../commands.js'
8| import { Byline } from '../../components/design-system/Byline.js'
9| import { Message as MessageComponent } from '../../components/Message.js'
10| import { MessageResponse } from '../../components/MessageResponse.js'
11| import { Box, Text } from '../../ink.js'
12| import type { Tools } from '../../Tool.js'
13| import type { ProgressMessage } from '../../types/message.js'
14| import { buildSubagentLookups, EMPTY_LOOKUPS } from '../../utils/messages.js'
15| import { plural } from '../../utils/stringUtils.js'
16| import type { inputSchema, Output, Progress } from './SkillTool.js'
17|
18| type Input = z.infer<ReturnType<typeof inputSchema>>
19|
20| const MAX_PROGRESS_MESSAGES_TO_SHOW = 3
21| const INITIALIZING_TEXT = 'Initializing…'
22|
23| export function renderToolResultMessage(output: Output): React.ReactNode {
24| // Handle forked skill result
25| if ('status' in output && output.status === 'forked') {
26| return (
27| <MessageResponse height={1}>
28| <Text>
29| <Byline>{['Done']}</Byline>
30| </Text>
31| </MessageResponse>
32| )
33| }
34|
35| const parts: string[] = ['Successfully loaded skill']
36|
37| // Show tools count (only for inline skills)
38| if (
39| 'allowedTools' in output &&
40| output.allowedTools &&
telemetry 与 invoked skill 跟踪
SkillTool 集成:
- recordSkillUsage — suggestions/skillUsageTracking
- buildPluginCommandTelemetryFields — plugin 来源 skill
- logEvent skill invoke success/failure
- addInvokedSkill / clearInvokedSkillsForAgent — bootstrap state
pluginTelemetry 与 skillLoadedEvent 在 load 阶段 vs invoke 阶段分别打点。
官方 marketplace skill 用 isOfficialMarketplaceSkill 识别 telemetry 字段。
源码引用: src/tools/SkillTool/SkillTool.ts · 第 38–60 行(共 1109 行)
38| addInvokedSkill,
39| clearInvokedSkillsForAgent,
40| getSessionId,
41| } from '../../bootstrap/state.js'
42| import { COMMAND_MESSAGE_TAG } from '../../constants/xml.js'
43| import type { CanUseToolFn } from '../../hooks/useCanUseTool.js'
44| import {
45| type AnalyticsMetadata_I_VERIFIED_THIS_IS_NOT_CODE_OR_FILEPATHS,
46| type AnalyticsMetadata_I_VERIFIED_THIS_IS_PII_TAGGED,
47| logEvent,
48| } from '../../services/analytics/index.js'
49| import { getAgentContext } from '../../utils/agentContext.js'
50| import { errorMessage } from '../../utils/errors.js'
51| import {
52| extractResultText,
53| prepareForkedCommandContext,
54| } from '../../utils/forkedAgent.js'
55| import { parseFrontmatter } from '../../utils/frontmatterParser.js'
56| import { lazySchema } from '../../utils/lazySchema.js'
57| import { createUserMessage, normalizeMessages } from '../../utils/messages.js'
58| import type { ModelAlias } from '../../utils/model/aliases.js'
59| import { resolveSkillModelOverride } from '../../utils/model/model.js'
60| import { recordSkillUsage } from '../../utils/suggestions/skillUsageTracking.js'
源码缺失
File not found: c:\Users\123\Desktop\jd\Claude code源码\claude-code-complete\claude-code-complete\src-readable\bootstrap\state.js
本章小结与延伸
SkillTool = skills 系统的模型入口。加载见 skills-loading;内置见 bundled-skills。用户 /slash 与模型 SkillTool 共用 findCommand,disableModelInvocation 仅阻断后者。 继续学习: