source dump of claude code
1import type { ContentBlockParam } from '@anthropic-ai/sdk/resources/index.mjs'
2import type { UUID } from 'crypto'
3import type { CanUseToolFn } from '../hooks/useCanUseTool.js'
4import type { CompactionResult } from '../services/compact/compact.js'
5import type { ScopedMcpServerConfig } from '../services/mcp/types.js'
6import type { ToolUseContext } from '../Tool.js'
7import type { EffortValue } from '../utils/effort.js'
8import type { IDEExtensionInstallationStatus, IdeType } from '../utils/ide.js'
9import type { SettingSource } from '../utils/settings/constants.js'
10import type { HooksSettings } from '../utils/settings/types.js'
11import type { ThemeName } from '../utils/theme.js'
12import type { LogOption } from './logs.js'
13import type { Message } from './message.js'
14import type { PluginManifest } from './plugin.js'
15
16export type LocalCommandResult =
17 | { type: 'text'; value: string }
18 | {
19 type: 'compact'
20 compactionResult: CompactionResult
21 displayText?: string
22 }
23 | { type: 'skip' } // Skip messages
24
25export type PromptCommand = {
26 type: 'prompt'
27 progressMessage: string
28 contentLength: number // Length of command content in characters (used for token estimation)
29 argNames?: string[]
30 allowedTools?: string[]
31 model?: string
32 source: SettingSource | 'builtin' | 'mcp' | 'plugin' | 'bundled'
33 pluginInfo?: {
34 pluginManifest: PluginManifest
35 repository: string
36 }
37 disableNonInteractive?: boolean
38 // Hooks to register when this skill is invoked
39 hooks?: HooksSettings
40 // Base directory for skill resources (used to set CLAUDE_PLUGIN_ROOT environment variable for skill hooks)
41 skillRoot?: string
42 // Execution context: 'inline' (default) or 'fork' (run as sub-agent)
43 // 'inline' = skill content expands into the current conversation
44 // 'fork' = skill runs in a sub-agent with separate context and token budget
45 context?: 'inline' | 'fork'
46 // Agent type to use when forked (e.g., 'Bash', 'general-purpose')
47 // Only applicable when context is 'fork'
48 agent?: string
49 effort?: EffortValue
50 // Glob patterns for file paths this skill applies to
51 // When set, the skill is only visible after the model touches matching files
52 paths?: string[]
53 getPromptForCommand(
54 args: string,
55 context: ToolUseContext,
56 ): Promise<ContentBlockParam[]>
57}
58
59/**
60 * The call signature for a local command implementation.
61 */
62export type LocalCommandCall = (
63 args: string,
64 context: LocalJSXCommandContext,
65) => Promise<LocalCommandResult>
66
67/**
68 * Module shape returned by load() for lazy-loaded local commands.
69 */
70export type LocalCommandModule = {
71 call: LocalCommandCall
72}
73
74type LocalCommand = {
75 type: 'local'
76 supportsNonInteractive: boolean
77 load: () => Promise<LocalCommandModule>
78}
79
80export type LocalJSXCommandContext = ToolUseContext & {
81 canUseTool?: CanUseToolFn
82 setMessages: (updater: (prev: Message[]) => Message[]) => void
83 options: {
84 dynamicMcpConfig?: Record<string, ScopedMcpServerConfig>
85 ideInstallationStatus: IDEExtensionInstallationStatus | null
86 theme: ThemeName
87 }
88 onChangeAPIKey: () => void
89 onChangeDynamicMcpConfig?: (
90 config: Record<string, ScopedMcpServerConfig>,
91 ) => void
92 onInstallIDEExtension?: (ide: IdeType) => void
93 resume?: (
94 sessionId: UUID,
95 log: LogOption,
96 entrypoint: ResumeEntrypoint,
97 ) => Promise<void>
98}
99
100export type ResumeEntrypoint =
101 | 'cli_flag'
102 | 'slash_command_picker'
103 | 'slash_command_session_id'
104 | 'slash_command_title'
105 | 'fork'
106
107export type CommandResultDisplay = 'skip' | 'system' | 'user'
108
109/**
110 * Callback when a command completes.
111 * @param result - Optional user-visible message to display
112 * @param options - Optional configuration for command completion
113 * @param options.display - How to display the result: 'skip' | 'system' | 'user' (default)
114 * @param options.shouldQuery - If true, send messages to the model after command completes
115 * @param options.metaMessages - Additional messages to insert as isMeta (model-visible but hidden)
116 */
117export type LocalJSXCommandOnDone = (
118 result?: string,
119 options?: {
120 display?: CommandResultDisplay
121 shouldQuery?: boolean
122 metaMessages?: string[]
123 nextInput?: string
124 submitNextInput?: boolean
125 },
126) => void
127
128/**
129 * The call signature for a local JSX command implementation.
130 */
131export type LocalJSXCommandCall = (
132 onDone: LocalJSXCommandOnDone,
133 context: ToolUseContext & LocalJSXCommandContext,
134 args: string,
135) => Promise<React.ReactNode>
136
137/**
138 * Module shape returned by load() for lazy-loaded commands.
139 */
140export type LocalJSXCommandModule = {
141 call: LocalJSXCommandCall
142}
143
144type LocalJSXCommand = {
145 type: 'local-jsx'
146 /**
147 * Lazy-load the command implementation.
148 * Returns a module with a call() function.
149 * This defers loading heavy dependencies until the command is invoked.
150 */
151 load: () => Promise<LocalJSXCommandModule>
152}
153
154/**
155 * Declares which auth/provider environments a command is available in.
156 *
157 * This is separate from `isEnabled()`:
158 * - `availability` = who can use this (auth/provider requirement, static)
159 * - `isEnabled()` = is this turned on right now (GrowthBook, platform, env vars)
160 *
161 * Commands without `availability` are available everywhere.
162 * Commands with `availability` are only shown if the user matches at least one
163 * of the listed auth types. See meetsAvailabilityRequirement() in commands.ts.
164 *
165 * Example: `availability: ['claude-ai', 'console']` shows the command to
166 * claude.ai subscribers and direct Console API key users (api.anthropic.com),
167 * but hides it from Bedrock/Vertex/Foundry users and custom base URL users.
168 */
169export type CommandAvailability =
170 // claude.ai OAuth subscriber (Pro/Max/Team/Enterprise via claude.ai)
171 | 'claude-ai'
172 // Console API key user (direct api.anthropic.com, not via claude.ai OAuth)
173 | 'console'
174
175export type CommandBase = {
176 availability?: CommandAvailability[]
177 description: string
178 hasUserSpecifiedDescription?: boolean
179 /** Defaults to true. Only set when the command has conditional enablement (feature flags, env checks, etc). */
180 isEnabled?: () => boolean
181 /** Defaults to false. Only set when the command should be hidden from typeahead/help. */
182 isHidden?: boolean
183 name: string
184 aliases?: string[]
185 isMcp?: boolean
186 argumentHint?: string // Hint text for command arguments (displayed in gray after command)
187 whenToUse?: string // From the "Skill" spec. Detailed usage scenarios for when to use this command
188 version?: string // Version of the command/skill
189 disableModelInvocation?: boolean // Whether to disable this command from being invoked by models
190 userInvocable?: boolean // Whether users can invoke this skill by typing /skill-name
191 loadedFrom?:
192 | 'commands_DEPRECATED'
193 | 'skills'
194 | 'plugin'
195 | 'managed'
196 | 'bundled'
197 | 'mcp' // Where the command was loaded from
198 kind?: 'workflow' // Distinguishes workflow-backed commands (badged in autocomplete)
199 immediate?: boolean // If true, command executes immediately without waiting for a stop point (bypasses queue)
200 isSensitive?: boolean // If true, args are redacted from the conversation history
201 /** Defaults to `name`. Only override when the displayed name differs (e.g. plugin prefix stripping). */
202 userFacingName?: () => string
203}
204
205export type Command = CommandBase &
206 (PromptCommand | LocalCommand | LocalJSXCommand)
207
208/** Resolves the user-visible name, falling back to `cmd.name` when not overridden. */
209export function getCommandName(cmd: CommandBase): string {
210 return cmd.userFacingName?.() ?? cmd.name
211}
212
213/** Resolves whether the command is enabled, defaulting to true. */
214export function isCommandEnabled(cmd: CommandBase): boolean {
215 return cmd.isEnabled?.() ?? true
216}