@@ -38,7 +38,7 @@ import { TestContextService, TestUserDataProfileService } from '../../../../../.
3838import { ChatRequestVariableSet , isPromptFileVariableEntry , toFileVariableEntry } from '../../../../common/attachments/chatVariableEntries.js' ;
3939import { ComputeAutomaticInstructions , newInstructionsCollectionEvent } from '../../../../common/promptSyntax/computeAutomaticInstructions.js' ;
4040import { PromptsConfig } from '../../../../common/promptSyntax/config/config.js' ;
41- import { AGENTS_SOURCE_FOLDER , CLAUDE_CONFIG_FOLDER , INSTRUCTION_FILE_EXTENSION , INSTRUCTIONS_DEFAULT_SOURCE_FOLDER , LEGACY_MODE_DEFAULT_SOURCE_FOLDER , PROMPT_DEFAULT_SOURCE_FOLDER , PROMPT_FILE_EXTENSION } from '../../../../common/promptSyntax/config/promptFileLocations.js' ;
41+ import { AGENTS_SOURCE_FOLDER , CLAUDE_CONFIG_FOLDER , HOOKS_SOURCE_FOLDER , INSTRUCTION_FILE_EXTENSION , INSTRUCTIONS_DEFAULT_SOURCE_FOLDER , LEGACY_MODE_DEFAULT_SOURCE_FOLDER , PROMPT_DEFAULT_SOURCE_FOLDER , PROMPT_FILE_EXTENSION } from '../../../../common/promptSyntax/config/promptFileLocations.js' ;
4242import { INSTRUCTIONS_LANGUAGE_ID , PROMPT_LANGUAGE_ID , PromptsType } from '../../../../common/promptSyntax/promptTypes.js' ;
4343import { ExtensionAgentSourceType , ICustomAgent , IPromptFileContext , IPromptsService , PromptsStorage , Target } from '../../../../common/promptSyntax/service/promptsService.js' ;
4444import { PromptsService } from '../../../../common/promptSyntax/service/promptsServiceImpl.js' ;
@@ -48,6 +48,7 @@ import { IPathService } from '../../../../../../services/path/common/pathService
4848import { IFileMatch , IFileQuery , ISearchService } from '../../../../../../services/search/common/search.js' ;
4949import { IExtensionService } from '../../../../../../services/extensions/common/extensions.js' ;
5050import { ChatModeKind } from '../../../../common/constants.js' ;
51+ import { HookType } from '../../../../common/promptSyntax/hookSchema.js' ;
5152
5253suite ( 'PromptsService' , ( ) => {
5354 const disposables = ensureNoDisposablesAreLeakedInTestSuite ( ) ;
@@ -3370,4 +3371,57 @@ suite('PromptsService', () => {
33703371 'Skill without header should be included when applying userInvocable filter (defaults to true)' ) ;
33713372 } ) ;
33723373 } ) ;
3374+
3375+ suite ( 'hooks' , ( ) => {
3376+ test ( 'multi-root workspace resolves cwd to per-hook-file workspace folder' , async function ( ) {
3377+ const folder1Uri = URI . file ( '/workspace-a' ) ;
3378+ const folder2Uri = URI . file ( '/workspace-b' ) ;
3379+
3380+ workspaceContextService . setWorkspace ( testWorkspace ( folder1Uri , folder2Uri ) ) ;
3381+ testConfigService . setUserConfiguration ( PromptsConfig . USE_CHAT_HOOKS , true ) ;
3382+ testConfigService . setUserConfiguration ( PromptsConfig . HOOKS_LOCATION_KEY , { [ HOOKS_SOURCE_FOLDER ] : true } ) ;
3383+
3384+ await mockFiles ( fileService , [
3385+ {
3386+ path : '/workspace-a/.github/hooks/my-hook.json' ,
3387+ contents : [
3388+ JSON . stringify ( {
3389+ hooks : {
3390+ [ HookType . PreToolUse ] : [
3391+ { type : 'command' , command : 'echo folder-a' } ,
3392+ ] ,
3393+ } ,
3394+ } ) ,
3395+ ] ,
3396+ } ,
3397+ {
3398+ path : '/workspace-b/.github/hooks/my-hook.json' ,
3399+ contents : [
3400+ JSON . stringify ( {
3401+ hooks : {
3402+ [ HookType . PreToolUse ] : [
3403+ { type : 'command' , command : 'echo folder-b' } ,
3404+ ] ,
3405+ } ,
3406+ } ) ,
3407+ ] ,
3408+ } ,
3409+ ] ) ;
3410+
3411+ const result = await service . getHooks ( CancellationToken . None ) ;
3412+ assert . ok ( result , 'Expected hooks result' ) ;
3413+
3414+ const preToolUseHooks = result . hooks [ HookType . PreToolUse ] ;
3415+ assert . ok ( preToolUseHooks , 'Expected PreToolUse hooks' ) ;
3416+ assert . strictEqual ( preToolUseHooks . length , 2 , 'Expected two PreToolUse hooks' ) ;
3417+
3418+ const hookA = preToolUseHooks . find ( h => h . command === 'echo folder-a' ) ;
3419+ const hookB = preToolUseHooks . find ( h => h . command === 'echo folder-b' ) ;
3420+ assert . ok ( hookA , 'Expected hook from folder-a' ) ;
3421+ assert . ok ( hookB , 'Expected hook from folder-b' ) ;
3422+
3423+ assert . strictEqual ( hookA . cwd ?. path , folder1Uri . path , 'Hook from folder-a should have cwd pointing to workspace-a' ) ;
3424+ assert . strictEqual ( hookB . cwd ?. path , folder2Uri . path , 'Hook from folder-b should have cwd pointing to workspace-b' ) ;
3425+ } ) ;
3426+ } ) ;
33733427} ) ;
0 commit comments