mirror of
https://github.com/microsoft/vscode.git
synced 2026-04-17 23:35:54 +01:00
Remove await in discovery phase (#300537)
This commit is contained in:
@@ -493,14 +493,6 @@ export interface IPromptsService extends IDisposable {
|
||||
*/
|
||||
readonly onDidChangeSkills: Event<void>;
|
||||
|
||||
/**
|
||||
* Gets detailed discovery information for a prompt type.
|
||||
* This includes all files found and their load/skip status with reasons.
|
||||
* Used for diagnostics and config-info displays.
|
||||
* @param sessionResource Optional session resource to scope debug logging to a specific session.
|
||||
*/
|
||||
getPromptDiscoveryInfo(type: PromptsType, token: CancellationToken, sessionResource?: URI): Promise<IPromptDiscoveryInfo>;
|
||||
|
||||
/**
|
||||
* Gets all hooks collected from hooks.json files.
|
||||
* The result is cached and invalidated when hook files change.
|
||||
|
||||
@@ -559,7 +559,24 @@ export class PromptsService extends Disposable implements IPromptsService {
|
||||
}
|
||||
|
||||
public async getPromptSlashCommands(token: CancellationToken, sessionResource?: URI): Promise<readonly IChatPromptSlashCommand[]> {
|
||||
return await this.cachedSlashCommands.get(token);
|
||||
const sw = StopWatch.create();
|
||||
const result = await this.cachedSlashCommands.get(token);
|
||||
if (sessionResource) {
|
||||
const elapsed = sw.elapsed();
|
||||
void this.getPromptSlashCommandDiscoveryInfo(token).catch(() => undefined).then(discoveryInfo => {
|
||||
const details = result.length === 1
|
||||
? localize("promptsService.resolvedSlashCommand", "Resolved {0} slash command in {1}ms", result.length, elapsed.toFixed(1))
|
||||
: localize("promptsService.resolvedSlashCommands", "Resolved {0} slash commands in {1}ms", result.length, elapsed.toFixed(1));
|
||||
this._onDidLogDiscovery.fire({
|
||||
sessionResource,
|
||||
name: localize("promptsService.loadSlashCommands", "Load Slash Commands"),
|
||||
details,
|
||||
discoveryInfo,
|
||||
category: 'discovery',
|
||||
});
|
||||
});
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
private async computePromptSlashCommands(token: CancellationToken): Promise<readonly IChatPromptSlashCommand[]> {
|
||||
@@ -645,16 +662,17 @@ export class PromptsService extends Disposable implements IPromptsService {
|
||||
const result = await this.cachedCustomAgents.get(token);
|
||||
if (sessionResource) {
|
||||
const elapsed = sw.elapsed();
|
||||
const discoveryInfo = await this.getAgentDiscoveryInfo(token);
|
||||
const details = result.length === 1
|
||||
? localize("promptsService.resolvedAgent", "Resolved {0} agent in {1}ms", result.length, elapsed.toFixed(1))
|
||||
: localize("promptsService.resolvedAgents", "Resolved {0} agents in {1}ms", result.length, elapsed.toFixed(1));
|
||||
this._onDidLogDiscovery.fire({
|
||||
sessionResource,
|
||||
name: localize("promptsService.loadAgents", "Load Agents"),
|
||||
details,
|
||||
discoveryInfo,
|
||||
category: 'discovery',
|
||||
void this.getAgentDiscoveryInfo(token).catch(() => undefined).then(discoveryInfo => {
|
||||
const details = result.length === 1
|
||||
? localize("promptsService.resolvedAgent", "Resolved {0} agent in {1}ms", result.length, elapsed.toFixed(1))
|
||||
: localize("promptsService.resolvedAgents", "Resolved {0} agents in {1}ms", result.length, elapsed.toFixed(1));
|
||||
this._onDidLogDiscovery.fire({
|
||||
sessionResource,
|
||||
name: localize("promptsService.loadAgents", "Load Agents"),
|
||||
details,
|
||||
discoveryInfo,
|
||||
category: 'discovery',
|
||||
});
|
||||
});
|
||||
}
|
||||
return result;
|
||||
@@ -1061,16 +1079,17 @@ export class PromptsService extends Disposable implements IPromptsService {
|
||||
const result = await this.cachedSkills.get(token);
|
||||
if (sessionResource) {
|
||||
const elapsed = sw.elapsed();
|
||||
const discoveryInfo = await this.getSkillDiscoveryInfo(token);
|
||||
const details = result.length === 1
|
||||
? localize("promptsService.resolvedSkill", "Resolved {0} skill in {1}ms", result.length, elapsed.toFixed(1))
|
||||
: localize("promptsService.resolvedSkills", "Resolved {0} skills in {1}ms", result.length, elapsed.toFixed(1));
|
||||
this._onDidLogDiscovery.fire({
|
||||
sessionResource,
|
||||
name: localize("promptsService.loadSkills", "Load Skills"),
|
||||
details,
|
||||
discoveryInfo,
|
||||
category: 'discovery',
|
||||
void this.getSkillDiscoveryInfo(token).catch(() => undefined).then(discoveryInfo => {
|
||||
const details = result.length === 1
|
||||
? localize("promptsService.resolvedSkill", "Resolved {0} skill in {1}ms", result.length, elapsed.toFixed(1))
|
||||
: localize("promptsService.resolvedSkills", "Resolved {0} skills in {1}ms", result.length, elapsed.toFixed(1));
|
||||
this._onDidLogDiscovery.fire({
|
||||
sessionResource,
|
||||
name: localize("promptsService.loadSkills", "Load Skills"),
|
||||
details,
|
||||
discoveryInfo,
|
||||
category: 'discovery',
|
||||
});
|
||||
});
|
||||
}
|
||||
return result;
|
||||
@@ -1184,17 +1203,18 @@ export class PromptsService extends Disposable implements IPromptsService {
|
||||
const result = await this.cachedHooks.get(token);
|
||||
if (sessionResource) {
|
||||
const elapsed = sw.elapsed();
|
||||
const hookCount = result ? Object.values(result.hooks).reduce((sum, arr) => sum + arr.length, 0) : 0;
|
||||
const discoveryInfo = await this.getHookDiscoveryInfo(token);
|
||||
const details = hookCount === 1
|
||||
? localize("promptsService.resolvedHook", "Resolved {0} hook in {1}ms", hookCount, elapsed.toFixed(1))
|
||||
: localize("promptsService.resolvedHooks", "Resolved {0} hooks in {1}ms", hookCount, elapsed.toFixed(1));
|
||||
this._onDidLogDiscovery.fire({
|
||||
sessionResource,
|
||||
name: localize("promptsService.loadHooks", "Load Hooks"),
|
||||
details,
|
||||
discoveryInfo,
|
||||
category: 'discovery',
|
||||
void this.getHookDiscoveryInfo(token).catch(() => undefined).then(discoveryInfo => {
|
||||
const hookCount = result ? Object.values(result.hooks).reduce((sum, arr) => sum + arr.length, 0) : 0;
|
||||
const details = hookCount === 1
|
||||
? localize("promptsService.resolvedHook", "Resolved {0} hook in {1}ms", hookCount, elapsed.toFixed(1))
|
||||
: localize("promptsService.resolvedHooks", "Resolved {0} hooks in {1}ms", hookCount, elapsed.toFixed(1));
|
||||
this._onDidLogDiscovery.fire({
|
||||
sessionResource,
|
||||
name: localize("promptsService.loadHooks", "Load Hooks"),
|
||||
details,
|
||||
discoveryInfo,
|
||||
category: 'discovery',
|
||||
});
|
||||
});
|
||||
}
|
||||
return result;
|
||||
@@ -1205,16 +1225,17 @@ export class PromptsService extends Disposable implements IPromptsService {
|
||||
const result = await this.listPromptFiles(PromptsType.instructions, token);
|
||||
if (sessionResource) {
|
||||
const elapsed = sw.elapsed();
|
||||
const discoveryInfo = await this.getInstructionsDiscoveryInfo(token);
|
||||
const details = result.length === 1
|
||||
? localize("promptsService.resolvedInstruction", "Resolved {0} instruction in {1}ms", result.length, elapsed.toFixed(1))
|
||||
: localize("promptsService.resolvedInstructions", "Resolved {0} instructions in {1}ms", result.length, elapsed.toFixed(1));
|
||||
this._onDidLogDiscovery.fire({
|
||||
sessionResource,
|
||||
name: localize("promptsService.loadInstructions", "Load Instructions"),
|
||||
details,
|
||||
discoveryInfo,
|
||||
category: 'discovery',
|
||||
void this.getInstructionsDiscoveryInfo(token).catch(() => undefined).then(discoveryInfo => {
|
||||
const details = result.length === 1
|
||||
? localize("promptsService.resolvedInstruction", "Resolved {0} instruction in {1}ms", result.length, elapsed.toFixed(1))
|
||||
: localize("promptsService.resolvedInstructions", "Resolved {0} instructions in {1}ms", result.length, elapsed.toFixed(1));
|
||||
this._onDidLogDiscovery.fire({
|
||||
sessionResource,
|
||||
name: localize("promptsService.loadInstructions", "Load Instructions"),
|
||||
details,
|
||||
discoveryInfo,
|
||||
category: 'discovery',
|
||||
});
|
||||
});
|
||||
}
|
||||
return result;
|
||||
@@ -1318,58 +1339,6 @@ export class PromptsService extends Disposable implements IPromptsService {
|
||||
return { hooks: result, hasDisabledClaudeHooks };
|
||||
}
|
||||
|
||||
public async getPromptDiscoveryInfo(type: PromptsType, token: CancellationToken, sessionResource?: URI): Promise<IPromptDiscoveryInfo> {
|
||||
if (sessionResource) {
|
||||
this._onDidLogDiscovery.fire({
|
||||
sessionResource,
|
||||
name: localize("promptsService.discoveryStart", "Discovery {0} (Start)", type),
|
||||
category: 'discovery',
|
||||
});
|
||||
}
|
||||
const files: IPromptFileDiscoveryResult[] = [];
|
||||
|
||||
let result: IPromptDiscoveryInfo;
|
||||
if (type === PromptsType.skill) {
|
||||
result = await this.getSkillDiscoveryInfo(token);
|
||||
} else if (type === PromptsType.agent) {
|
||||
result = await this.getAgentDiscoveryInfo(token);
|
||||
} else if (type === PromptsType.prompt) {
|
||||
result = await this.getPromptSlashCommandDiscoveryInfo(token);
|
||||
} else if (type === PromptsType.instructions) {
|
||||
result = await this.getInstructionsDiscoveryInfo(token);
|
||||
} else if (type === PromptsType.hook) {
|
||||
result = await this.getHookDiscoveryInfo(token);
|
||||
} else {
|
||||
result = { type, files };
|
||||
}
|
||||
|
||||
const loadedCount = result.files.filter(f => f.status === 'loaded').length;
|
||||
const skippedCount = result.files.filter(f => f.status === 'skipped').length;
|
||||
|
||||
// Add source folder diagnostics if not already present
|
||||
if (!result.sourceFolders) {
|
||||
const sourceFolders = await this._collectSourceFolderDiagnostics(type);
|
||||
result = { ...result, sourceFolders };
|
||||
}
|
||||
|
||||
if (sessionResource) {
|
||||
const details = localize(
|
||||
"promptsService.discoveryResult",
|
||||
"{0} loaded, {1} skipped",
|
||||
loadedCount,
|
||||
skippedCount,
|
||||
);
|
||||
this._onDidLogDiscovery.fire({
|
||||
sessionResource,
|
||||
name: localize("promptsService.discoveryEnd", "Discovery {0} (End)", type),
|
||||
details,
|
||||
discoveryInfo: result,
|
||||
category: 'discovery',
|
||||
});
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
private async getSkillDiscoveryInfo(token: CancellationToken): Promise<IPromptDiscoveryInfo> {
|
||||
const useAgentSkills = this.configurationService.getValue(PromptsConfig.USE_AGENT_SKILLS);
|
||||
|
||||
|
||||
@@ -67,8 +67,6 @@ export class MockPromptsService implements IPromptsService {
|
||||
registerPromptFileProvider(extension: IExtensionDescription, type: PromptsType, provider: { providePromptFiles: (context: IPromptFileContext, token: CancellationToken) => Promise<IPromptFileResource[] | undefined> }): IDisposable { throw new Error('Method not implemented.'); }
|
||||
findAgentSkills(token: CancellationToken, sessionResource?: URI): Promise<IAgentSkill[] | undefined> { throw new Error('Method not implemented.'); }
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||
getPromptDiscoveryInfo(_type: any, _token: CancellationToken, _sessionResource?: URI): Promise<any> { throw new Error('Method not implemented.'); }
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||
getHooks(_token: CancellationToken, _sessionResource?: URI): Promise<any> { throw new Error('Method not implemented.'); }
|
||||
getInstructionFiles(_token: CancellationToken, _sessionResource?: URI): Promise<readonly IPromptPath[]> { throw new Error('Method not implemented.'); }
|
||||
dispose(): void { }
|
||||
|
||||
@@ -3670,33 +3670,6 @@ suite('PromptsService', () => {
|
||||
assert.strictEqual(reTrustedResult.hooks[HookType.PreToolUse]?.length, 1);
|
||||
});
|
||||
|
||||
test('discovery info marks hooks as skipped when workspace is untrusted', async function () {
|
||||
workspaceContextService.setWorkspace(testWorkspace(URI.file('/test-workspace')));
|
||||
testConfigService.setUserConfiguration(PromptsConfig.USE_CHAT_HOOKS, true);
|
||||
testConfigService.setUserConfiguration(PromptsConfig.HOOKS_LOCATION_KEY, { [HOOKS_SOURCE_FOLDER]: true });
|
||||
|
||||
await mockFiles(fileService, [
|
||||
{
|
||||
path: '/test-workspace/.github/hooks/my-hook.json',
|
||||
contents: [
|
||||
JSON.stringify({
|
||||
hooks: {
|
||||
[HookType.PreToolUse]: [
|
||||
{ type: 'command', command: 'echo test' },
|
||||
],
|
||||
},
|
||||
}),
|
||||
],
|
||||
},
|
||||
]);
|
||||
|
||||
await workspaceTrustService.setWorkspaceTrust(false);
|
||||
const discoveryInfo = await service.getPromptDiscoveryInfo(PromptsType.hook, CancellationToken.None);
|
||||
assert.strictEqual(discoveryInfo.files.length, 1, 'Expected one discovery result');
|
||||
assert.strictEqual(discoveryInfo.files[0].status, 'skipped');
|
||||
assert.strictEqual(discoveryInfo.files[0].skipReason, 'workspace-untrusted');
|
||||
});
|
||||
|
||||
test('suppresses plugin hooks when workspace is untrusted', async function () {
|
||||
testConfigService.setUserConfiguration(PromptsConfig.USE_CHAT_HOOKS, true);
|
||||
testConfigService.setUserConfiguration(PromptsConfig.HOOKS_LOCATION_KEY, {});
|
||||
|
||||
Reference in New Issue
Block a user