@@ -31,6 +31,7 @@ import { IChatModeInstructions, IVariableReference } from '../../chatModes.js';
3131import { dirname , isEqual } from '../../../../../../base/common/resources.js' ;
3232import { IExtensionDescription } from '../../../../../../platform/extensions/common/extensions.js' ;
3333import { Delayer } from '../../../../../../base/common/async.js' ;
34+ import { IFilesConfigurationService } from '../../../../../services/filesConfiguration/common/filesConfigurationService.js' ;
3435
3536/**
3637 * Provides prompt services.
@@ -55,9 +56,9 @@ export class PromptsService extends Disposable implements IPromptsService {
5556 * Contributed files from extensions keyed by prompt type then name.
5657 */
5758 private readonly contributedFiles = {
58- [ PromptsType . prompt ] : new ResourceMap < IExtensionPromptPath > ( ) ,
59- [ PromptsType . instructions ] : new ResourceMap < IExtensionPromptPath > ( ) ,
60- [ PromptsType . mode ] : new ResourceMap < IExtensionPromptPath > ( ) ,
59+ [ PromptsType . prompt ] : new ResourceMap < Promise < IExtensionPromptPath > > ( ) ,
60+ [ PromptsType . instructions ] : new ResourceMap < Promise < IExtensionPromptPath > > ( ) ,
61+ [ PromptsType . mode ] : new ResourceMap < Promise < IExtensionPromptPath > > ( ) ,
6162 } ;
6263
6364 /**
@@ -73,7 +74,8 @@ export class PromptsService extends Disposable implements IPromptsService {
7374 @IUserDataProfileService private readonly userDataService : IUserDataProfileService ,
7475 @ILanguageService private readonly languageService : ILanguageService ,
7576 @IConfigurationService private readonly configurationService : IConfigurationService ,
76- @IFileService private readonly fileService : IFileService
77+ @IFileService private readonly fileService : IFileService ,
78+ @IFilesConfigurationService private readonly filesConfigService : IFilesConfigurationService
7779 ) {
7880 super ( ) ;
7981
@@ -125,10 +127,11 @@ export class PromptsService extends Disposable implements IPromptsService {
125127
126128 const prompts = await Promise . all ( [
127129 this . fileLocator . listFiles ( type , PromptsStorage . user , token ) . then ( uris => uris . map ( uri => ( { uri, storage : PromptsStorage . user , type } satisfies IUserPromptPath ) ) ) ,
128- this . fileLocator . listFiles ( type , PromptsStorage . local , token ) . then ( uris => uris . map ( uri => ( { uri, storage : PromptsStorage . local , type } satisfies ILocalPromptPath ) ) )
130+ this . fileLocator . listFiles ( type , PromptsStorage . local , token ) . then ( uris => uris . map ( uri => ( { uri, storage : PromptsStorage . local , type } satisfies ILocalPromptPath ) ) ) ,
131+ this . getExtensionContributions ( type )
129132 ] ) ;
130133
131- return [ ...prompts . flat ( ) , ... this . contributedFiles [ type ] . values ( ) ] ;
134+ return [ ...prompts . flat ( ) ] ;
132135 }
133136
134137 public async listPromptFilesForStorage ( type : PromptsType , storage : PromptsStorage , token : CancellationToken ) : Promise < readonly IPromptPath [ ] > {
@@ -138,7 +141,7 @@ export class PromptsService extends Disposable implements IPromptsService {
138141
139142 switch ( storage ) {
140143 case PromptsStorage . extension :
141- return Promise . resolve ( Array . from ( this . contributedFiles [ type ] . values ( ) ) ) ;
144+ return this . getExtensionContributions ( type ) ;
142145 case PromptsStorage . local :
143146 return this . fileLocator . listFiles ( type , PromptsStorage . local , token ) . then ( uris => uris . map ( uri => ( { uri, storage : PromptsStorage . local , type } satisfies ILocalPromptPath ) ) ) ;
144147 case PromptsStorage . user :
@@ -148,6 +151,10 @@ export class PromptsService extends Disposable implements IPromptsService {
148151 }
149152 }
150153
154+ private async getExtensionContributions ( type : PromptsType ) : Promise < IPromptPath [ ] > {
155+ return Promise . all ( this . contributedFiles [ type ] . values ( ) ) ;
156+ }
157+
151158 public getSourceFolders ( type : PromptsType ) : readonly IPromptPath [ ] {
152159 if ( ! PromptsConfig . enabled ( this . configurationService ) ) {
153160 return [ ] ;
@@ -301,7 +308,16 @@ export class PromptsService extends Disposable implements IPromptsService {
301308 // keep first registration per extension (handler filters duplicates per extension already)
302309 return Disposable . None ;
303310 }
304- bucket . set ( uri , { uri, name, description, storage : PromptsStorage . extension , type, extension } satisfies IExtensionPromptPath ) ;
311+ const entryPromise = ( async ( ) => {
312+ try {
313+ await this . filesConfigService . updateReadonly ( uri , true ) ;
314+ } catch ( e ) {
315+ const msg = e instanceof Error ? e . message : String ( e ) ;
316+ this . logger . error ( `[registerContributedFile] Failed to make prompt file readonly: ${ uri } ` , msg ) ;
317+ }
318+ return { uri, name, description, storage : PromptsStorage . extension , type, extension } satisfies IExtensionPromptPath ;
319+ } ) ( ) ;
320+ bucket . set ( uri , entryPromise ) ;
305321
306322 const updateModesIfRequired = ( ) => {
307323 if ( type === PromptsType . mode ) {
0 commit comments