Fix skill delete behaviour (#298814)

This commit is contained in:
Paul
2026-03-02 14:36:19 -08:00
committed by GitHub
parent b072e8231a
commit 2bddfa571a
2 changed files with 35 additions and 9 deletions

View File

@@ -35,7 +35,7 @@ import { ContextKeyExpr } from '../../../../../platform/contextkey/common/contex
import { ChatConfiguration } from '../../common/constants.js';
import { IFileService } from '../../../../../platform/files/common/files.js';
import { IDialogService } from '../../../../../platform/dialogs/common/dialogs.js';
import { basename } from '../../../../../base/common/resources.js';
import { basename, dirname } from '../../../../../base/common/resources.js';
import { Schemas } from '../../../../../base/common/network.js';
import { isWindows, isMacintosh } from '../../../../../base/common/platform.js';
@@ -119,6 +119,16 @@ function extractStorage(context: AICustomizationContext): PromptsStorage | undef
return context.storage;
}
/**
* Extracts prompt type from context.
*/
function extractPromptType(context: AICustomizationContext): PromptsType | undefined {
if (URI.isUri(context) || typeof context === 'string') {
return undefined;
}
return context.promptType;
}
// Open file action
const OPEN_AI_CUSTOMIZATION_MGMT_FILE_ID = 'aiCustomizationManagement.openFile';
registerAction2(class extends Action2 {
@@ -193,8 +203,11 @@ registerAction2(class extends Action2 {
const dialogService = accessor.get(IDialogService);
const uri = extractURI(context);
const fileName = basename(uri);
const storage = extractStorage(context);
const promptType = extractPromptType(context);
const isSkill = promptType === PromptsType.skill;
// For skills, use the parent folder name since skills are structured as <skillname>/SKILL.md.
const fileName = isSkill ? basename(dirname(uri)) : basename(uri);
// Extension and plugin files cannot be deleted
if (storage === PromptsStorage.extension || storage === PromptsStorage.plugin) {
@@ -206,15 +219,21 @@ registerAction2(class extends Action2 {
}
// Confirm deletion
const message = isSkill
? localize('confirmDeleteSkill', "Are you sure you want to delete skill '{0}' and its folder?", fileName)
: localize('confirmDelete', "Are you sure you want to delete '{0}'?", fileName);
const confirmation = await dialogService.confirm({
message: localize('confirmDelete', "Are you sure you want to delete '{0}'?", fileName),
message,
detail: localize('confirmDeleteDetail', "This action cannot be undone."),
primaryButton: localize('delete', "Delete"),
type: 'warning',
});
if (confirmation.confirmed) {
await fileService.del(uri, { useTrash: true });
// For skills, delete the parent folder (e.g. .github/skills/my-skill/)
// since each skill is a folder containing SKILL.md.
const deleteTarget = isSkill ? dirname(uri) : uri;
await fileService.del(deleteTarget, { useTrash: true, recursive: isSkill });
}
}
});

View File

@@ -8,7 +8,7 @@ import { URI } from '../../../../../../base/common/uri.js';
import { Codicon } from '../../../../../../base/common/codicons.js';
import { ThemeIcon } from '../../../../../../base/common/themables.js';
import { AgentFileType, IExtensionPromptPath, IPromptPath, IPromptsService, PromptsStorage } from '../../../common/promptSyntax/service/promptsService.js';
import { dirname, extUri, joinPath } from '../../../../../../base/common/resources.js';
import { basename, dirname, extUri, joinPath } from '../../../../../../base/common/resources.js';
import { DisposableStore } from '../../../../../../base/common/lifecycle.js';
import { IFileService } from '../../../../../../platform/files/common/files.js';
import { IOpenerService } from '../../../../../../platform/opener/common/opener.js';
@@ -651,16 +651,23 @@ export class PromptFilePickers {
// don't close the main prompt selection dialog by the confirmation dialog
return await this.keepQuickPickOpen(quickPick, async () => {
const filename = getCleanPromptName(value);
const message = localize('commands.prompts.use.select-dialog.delete-prompt.confirm.message', "Are you sure you want to delete '{0}'?", filename);
const isSkill = options.type === PromptsType.skill;
// For skills, use the parent folder name as the display name
// since skills are structured as <skillname>/SKILL.md.
const filename = isSkill ? basename(dirname(value)) : item.label;
const message = isSkill
? localize('commands.prompts.use.select-dialog.delete-skill.confirm.message', "Are you sure you want to delete skill '{0}' and its folder?", filename)
: localize('commands.prompts.use.select-dialog.delete-prompt.confirm.message', "Are you sure you want to delete '{0}'?", filename);
const { confirmed } = await this._dialogService.confirm({ message });
// if prompt deletion was not confirmed, nothing to do
if (!confirmed) {
return false;
}
// prompt deletion was confirmed so delete the prompt file
await this._fileService.del(value);
// For skills, delete the parent folder (e.g. .github/skills/my-skill/)
// since each skill is a folder containing SKILL.md.
const deleteTarget = isSkill ? dirname(value) : value;
await this._fileService.del(deleteTarget, { recursive: isSkill, useTrash: true });
return true;
});