84
return result as ChatRequestHooks;
85
}
87
>
/**
88
>
* Descriptions for hook command fields, used by both the JSON schema and the hover provider.
89
>
*/
90
>
export const HOOK_COMMAND_FIELD_DESCRIPTIONS: Record<string, string> = {
91
>
type: nls.localize('hook.type', 'Must be "command".'),
92
>
command: nls.localize('hook.command', 'The command to execute. This is the default cross-platform command.'),
93
>
windows: nls.localize('hook.windows', 'Windows-specific command. If specified and running on Windows, this overrides the "command" field.'),
94
>
linux: nls.localize('hook.linux', 'Linux-specific command. If specified and running on Linux, this overrides the "command" field.'),
95
>
osx: nls.localize('hook.osx', 'macOS-specific command. If specified and running on macOS, this overrides the "command" field.'),
96
>
bash: nls.localize('hook.bash', 'Bash command for Linux and macOS.'),
97
>
powershell: nls.localize('hook.powershell', 'PowerShell command for Windows.'),
98
>
cwd: nls.localize('hook.cwd', 'Working directory for the script (relative to repository root).'),
99
>
env: nls.localize('hook.env', 'Additional environment variables that are merged with the existing environment.'),
100
>
timeout: nls.localize('hook.timeout', 'Maximum execution time in seconds (default: 30).'),
101
>
timeoutSec: nls.localize('hook.timeoutSec', 'Maximum execution time in seconds (default: 10).'),
102
>
};
103
>
104
>
/**
105
>
* JSON Schema for GitHub Copilot hook configuration files.
106
>
* Hooks enable executing custom shell commands at strategic points in an agent's workflow.
107
>
*/
108
>
const vscodeHookCommandSchema: IJSONSchema = {
109
>
type: 'object',
110
>
additionalProperties: true,
111
>
required: ['type'],
112
>
anyOf: [
113
>
{ required: ['command'] },
114
>
{ required: ['windows'] },
115
>
{ required: ['linux'] },
116
>
{ required: ['osx'] },
117
>
{ required: ['bash'] },
118
>
{ required: ['powershell'] }
119
>
],
120
>
errorMessage: nls.localize('hook.commandRequired', 'At least one of "command", "windows", "linux", or "osx" must be specified.'),
121
>
properties: {
122
>
type: {
123
>
type: 'string',
124
>
enum: ['command'],
125
>
description: HOOK_COMMAND_FIELD_DESCRIPTIONS.type
126
>
},
127
>
command: {
128
>
type: 'string',
129
>
description: HOOK_COMMAND_FIELD_DESCRIPTIONS.command
130
>
},
131
>
windows: {
132
>
type: 'string',
133
>
description: HOOK_COMMAND_FIELD_DESCRIPTIONS.windows
134
>
},
135
>
linux: {
136
>
type: 'string',
137
>
description: HOOK_COMMAND_FIELD_DESCRIPTIONS.linux
138
>
},
139
>
osx: {
140
>
type: 'string',
141
>
description: HOOK_COMMAND_FIELD_DESCRIPTIONS.osx
142
>
},
143
>
cwd: {
144
>
type: 'string',
145
>
description: HOOK_COMMAND_FIELD_DESCRIPTIONS.cwd
146
>
},
147
>
env: {
148
>
type: 'object',
149
>
additionalProperties: { type: 'string' },
150
>
description: HOOK_COMMAND_FIELD_DESCRIPTIONS.env
151
>
},
152
>
timeout: {
153
>
type: 'number',
154
>
default: 30,
155
>
description: HOOK_COMMAND_FIELD_DESCRIPTIONS.timeout
156
>
}
157
>
}
158
>
};
159
>
160
>
const hookArraySchema: IJSONSchema = {
161
>
type: 'array',
162
>
items: vscodeHookCommandSchema
163
>
};
164
>
165
>
/**
166
>
* Builds JSON Schema hook properties for a given target by looking up
167
>
* the hook keys from HOOKS_BY_TARGET and descriptions from HOOK_METADATA.
168
>
*/
169
>
function buildHookProperties(target: Target, arraySchema: IJSONSchema): Record<string, IJSONSchema> {
170
>
return Object.fromEntries(
171
>
Object.entries(HOOKS_BY_TARGET[target]).map(([key, hookType]) => [
172
>
key,
173
>
{ ...arraySchema, description: HOOK_METADATA[hookType]?.description }
174
>
])
175
>
);
176
>
}
177
>
178
>
/**
179
>
* Hook properties for the VS Code format.
180
>
*/
181
>
const vscodeHookProperties: Record<string, IJSONSchema> = buildHookProperties(Target.VSCode, hookArraySchema);
182
>
183
>
/**
184
>
* Hook command schema for the Copilot CLI format.
185
>
* Adds `bash`, `powershell`, and `timeoutSec` fields alongside the standard ones.
186
>
*/
187
>
const copilotCliHookCommandSchema: IJSONSchema = {
188
>
type: 'object',
189
>
additionalProperties: true,
190
>
required: ['type'],
191
>
anyOf: [
192
>
{ required: ['bash'] },
193
>
{ required: ['powershell'] }
194
>
],
195
>
errorMessage: nls.localize('hook.cliCommandRequired', 'At least one of "bash" or "powershell" must be specified.'),
196
>
properties: {
197
>
type: {
198
>
type: 'string',
199
>
enum: ['command'],
200
>
description: HOOK_COMMAND_FIELD_DESCRIPTIONS.type
201
>
},
202
>
bash: {
203
>
type: 'string',
204
>
description: HOOK_COMMAND_FIELD_DESCRIPTIONS.bash
205
>
},
206
>
powershell: {
207
>
type: 'string',
208
>
description: HOOK_COMMAND_FIELD_DESCRIPTIONS.powershell
209
>
},
210
>
cwd: {
211
>
type: 'string',
212
>
description: HOOK_COMMAND_FIELD_DESCRIPTIONS.cwd
213
>
},
214
>
env: {
215
>
type: 'object',
216
>
additionalProperties: { type: 'string' },
217
>
description: HOOK_COMMAND_FIELD_DESCRIPTIONS.env
218
>
},
219
>
timeoutSec: {
220
>
type: 'number',
221
>
default: 10,
222
>
description: HOOK_COMMAND_FIELD_DESCRIPTIONS.timeoutSec
223
>
}
224
>
}
225
>
};
226
>
227
>
const copilotCliHookArraySchema: IJSONSchema = {
228
>
type: 'array',
229
>
items: copilotCliHookCommandSchema
230
>
};
231
>
232
>
/**
233
>
* Hook properties for the Copilot CLI format.
234
>
*/
235
>
const copilotCliHookProperties: Record<string, IJSONSchema> = buildHookProperties(Target.GitHubCopilot, copilotCliHookArraySchema);
236
>
237
>
export const hookFileSchema: IJSONSchema = {
238
>
$schema: 'http://json-schema.org/draft-07/schema#',
239
>
type: 'object',
240
>
description: nls.localize('hookFile.description', 'GitHub Copilot hook configuration file. Hooks enable executing custom shell commands at strategic points in an agent\'s workflow.'),
241
>
additionalProperties: true,
242
>
required: ['hooks'],
243
>
properties: {
244
>
hooks: {
245
>
type: 'object',
246
>
description: nls.localize('hookFile.hooks', 'Hook definitions organized by type.'),
247
>
additionalProperties: true,
248
>
}
249
>
},
250
>
// Conditionally apply PascalCase or camelCase hook properties based on
251
>
// whether the file uses the Copilot CLI format (detected by the "version" field).
252
>
if: {
253
>
required: ['version'],
254
>
properties: {
255
>
version: { type: 'number' }
256
>
}
257
>
},
258
>
then: {
259
>
// Copilot CLI format: camelCase hook names, bash/powershell/timeoutSec fields
260
>
properties: {
261
>
version: {
262
>
type: 'number',
263
>
description: nls.localize('hookFile.version', 'Hook configuration format version.'),
264
>
},
265
>
hooks: {
266
>
properties: copilotCliHookProperties
267
>
}
268
>
}
269
>
},
270
>
else: {
271
>
// VS Code / PascalCase format
272
>
properties: {
273
>
hooks: {
274
>
properties: vscodeHookProperties
275
>
}
276
>
}
277
>
},
278
>
defaultSnippets: [
279
>
{
280
>
label: nls.localize('hookFile.snippet.basic', 'Basic hook configuration'),
281
>
description: nls.localize('hookFile.snippet.basic.description', 'A basic hook configuration with common hooks'),
282
>
body: {
283
>
hooks: {
284
>
SessionStart: [
285
>
{
286
>
type: 'command',
287
>
command: '${1:echo "Session started" >> session.log}',
288
>
}
289
>
],
290
>
PreToolUse: [
291
>
{
292
>
type: 'command',
293
>
command: '${2:./scripts/validate.sh}',
294
>
timeout: 15
295
>
}
296
>
]
297
>
}
298
>
}
299
>
}
300
>
]
301
>
};
302
>
303
>
/**
304
>
* URI for the hook schema registration.
305
>
*/
306
>
export const HOOK_SCHEMA_URI = 'vscode://schemas/hooks';
307
>
308
>
/**
309
>
* Normalizes a raw hook type identifier to the canonical HookType enum value.
310
>
* Only matches exact enum values. For tool-specific naming conventions (e.g., Claude, Copilot CLI),
311
>
* use the corresponding compat module's resolver function.
312
>
*/
313
>
export function toHookType(rawHookTypeId: string): HookType | undefined {
314
if (Object.values(HookType).includes(rawHookTypeId as HookType)) {
315
return rawHookTypeId as HookType;