public async getPromptSlashCommands(token: CancellationToken): Promise<readonly IChatPromptSlashCommand[]> {
const result = this.slashCommandsFromDiscoveryInfo(discoveryInfo);
return result;
}
/**
Frontier kind: Code frontier
unlabeled · c_9d94c8f30d33
22 tests · 68776 LOC · 326 files · introduces 0 tests · 93 LOC · 2 files
The orange circle is the focus. Violet and green circles are every ancestor and descendant, broader and narrower, at any distance; blue squares and pink diamonds are the introduced files and exact introduced tests of every visible concept, not only the focus's. Arrows point from broader to narrower concepts and bridge only concepts omitted from this view. Undirected links show source or test introduction. Concept and file size follows LOC; exact test nodes use test-count units.
Introduced files, introduced tests, and structurally relevant concept specialization
In the embedded map, ordinary wheel input scrolls the page; use the visible controls to zoom and drag to pan. Open the full-screen map for canvas navigation: wheel pans, Ctrl/Command plus wheel zooms, and arrow keys pan when this region is focused. On touch screens, open the full-screen map to pan or pinch. If JavaScript or WebGL is unavailable, use the native relationship evidence on this page.
Graph controls are ready.
Interactive rendering requires JavaScript and WebGL. Use the native relationship evidence on this page while the interactive map is unavailable.
Every exact file and test below is linked only from the concept that introduces it.
mocha:v1|namespace=vscode@05c208e9e28d8c1c723fa08f85e2b7a96092e8e5|file=vs/workbench/contrib/chat/test/common/promptSyntax/service/promptsService.test|title=PromptsService getPromptSlashCommands - userInvocable filtering plugin skill frontmatter name is qualified with plugin prefix|occurrence=1mocha:v1|namespace=vscode@05c208e9e28d8c1c723fa08f85e2b7a96092e8e5|file=vs/workbench/contrib/chat/test/common/promptSyntax/service/promptsService.test|title=PromptsService getPromptSlashCommands - userInvocable filtering plugin skills include plugin name prefix in slash command name|occurrence=1mocha:v1|namespace=vscode@05c208e9e28d8c1c723fa08f85e2b7a96092e8e5|file=vs/workbench/contrib/chat/test/common/promptSyntax/service/promptsService.test|title=PromptsService getPromptSlashCommands - skills should combine prompt files and skills as slash commands|occurrence=1mocha:v1|namespace=vscode@05c208e9e28d8c1c723fa08f85e2b7a96092e8e5|file=vs/workbench/contrib/chat/test/common/promptSyntax/service/promptsService.test|title=PromptsService getPromptSlashCommands - skills should not duplicate slash commands with same name from different types|occurrence=1mocha:v1|namespace=vscode@05c208e9e28d8c1c723fa08f85e2b7a96092e8e5|file=vs/workbench/contrib/chat/test/common/promptSyntax/service/promptsService.test|title=PromptsService getPromptSlashCommands - skills should include skills from workspace as slash commands|occurrence=1mocha:v1|namespace=vscode@05c208e9e28d8c1c723fa08f85e2b7a96092e8e5|file=vs/workbench/contrib/chat/test/common/promptSyntax/service/promptsService.test|title=PromptsService getPromptSlashCommands - skills should use filename as fallback for skills with missing name|occurrence=1mocha:v1|namespace=vscode@05c208e9e28d8c1c723fa08f85e2b7a96092e8e5|file=vs/base/test/common/stream.test|title=Stream WriteableStream - end with empty string works|occurrence=1mocha:v1|namespace=vscode@05c208e9e28d8c1c723fa08f85e2b7a96092e8e5|file=vs/base/test/common/stream.test|title=Stream WriteableStream - end with error works|occurrence=1mocha:v1|namespace=vscode@05c208e9e28d8c1c723fa08f85e2b7a96092e8e5|file=vs/platform/instantiation/test/common/instantiationService.test|title=Instantiation Service @Param - fixed args|occurrence=1mocha:v1|namespace=vscode@05c208e9e28d8c1c723fa08f85e2b7a96092e8e5|file=vs/platform/instantiation/test/common/instantiationService.test|title=Instantiation Service @Param - simple clase|occurrence=1mocha:v1|namespace=vscode@05c208e9e28d8c1c723fa08f85e2b7a96092e8e5|file=vs/base/test/common/lifecycle.test|title=Lifecycle Action bar has broken accessibility #100273|occurrence=1mocha:v1|namespace=vscode@05c208e9e28d8c1c723fa08f85e2b7a96092e8e5|file=vs/base/test/common/lifecycle.test|title=Lifecycle dispose disposable array|occurrence=1mocha:v1|namespace=vscode@05c208e9e28d8c1c723fa08f85e2b7a96092e8e5|file=vs/base/test/common/uri.test|title=URI URI#file, always slash|occurrence=1mocha:v1|namespace=vscode@05c208e9e28d8c1c723fa08f85e2b7a96092e8e5|file=vs/base/test/common/uri.test|title=URI class URI cannot represent relative file paths #34449|occurrence=1mocha:v1|namespace=vscode@05c208e9e28d8c1c723fa08f85e2b7a96092e8e5|file=vs/base/test/common/charCode.test|title=CharCode has good values|occurrence=1mocha:v1|namespace=vscode@05c208e9e28d8c1c723fa08f85e2b7a96092e8e5|file=vs/base/test/common/path.test|title=Paths (Node Implementation) path|occurrence=1mocha:v1|namespace=vscode@05c208e9e28d8c1c723fa08f85e2b7a96092e8e5|file=vs/base/test/common/uri.test|title=URI File paths containing apostrophes break URI parsing and cannot be opened #276075|occurrence=1mocha:v1|namespace=vscode@05c208e9e28d8c1c723fa08f85e2b7a96092e8e5|file=vs/base/test/common/uri.test|title=URI URI#file, win-speciale|occurrence=1Every collected test enters the hierarchy at exactly one concept.
No tests are introduced at this concept. Its intent tests are introduced by other concepts.
Every collected source range enters the hierarchy at exactly one concept.
2 files ranked by introduced lines: 93 introduced LOC across 13 ranges. Expand a file to inspect source; the > gutter marks introduced lines.
public async getPromptSlashCommands(token: CancellationToken): Promise<readonly IChatPromptSlashCommand[]> {
const result = this.slashCommandsFromDiscoveryInfo(discoveryInfo);
return result;
}
/**
*/
private async computeSlashCommandDiscoveryInfo(token: CancellationToken): Promise<ISlashCommandDiscoveryInfo> {
const promptFiles = await this.listPromptFiles(PromptsType.prompt, token);
const useAgentSkills = this.configurationService.getValue(PromptsConfig.USE_AGENT_SKILLS);
const skills = useAgentSkills ? await this.listPromptFiles(PromptsType.skill, token) : [];
const disabledSkills = this.getDisabledPromptFiles(PromptsType.skill);
// Order skills by precedence before parsing so that the duplicate-name
// dedup below keeps a deterministic winner (e.g. workspace over personal).
const enabledSkills = skills
.filter(s => !disabledSkills.has(s.uri))
.sort((a, b) => this.getSkillPriority(a) - this.getSkillPriority(b));
const slashCommandFiles = [
...promptFiles,
...enabledSkills,
];
const parseResults = await Promise.all(slashCommandFiles.map(async promptPath => {
try {
const parsedPromptFile = await this.parseNew(promptPath.uri, token);
let rawName: string;
if (promptPath.type === PromptsType.skill) {
// For skills, always use the folder name as the canonical name
// (consistent with computeSkillDiscoveryInfo)
rawName = getSkillFolderName(promptPath.uri);
rawName = parsedPromptFile?.header?.name ?? promptPath.name ?? getCleanPromptName(promptPath.uri);
}
// For plugin resources, ensure the canonical plugin prefix is always preserved even when the
promptsServiceImpl.ts
// file's frontmatter overrides the name.
const name = promptPath.source === PromptFileSource.Plugin && promptPath.pluginUri
? getCanonicalPluginCommandId({ uri: promptPath.pluginUri, label: promptPath.pluginLabel }, rawName)
: rawName;
const description = parsedPromptFile?.header?.description ?? promptPath.description;
promptsServiceImpl.ts
const argumentHint = parsedPromptFile?.header?.argumentHint;
const userInvocable = parsedPromptFile?.header?.userInvocable;
return { status: 'loaded', promptPath: this.withPromptPathMetadata(promptPath, name, description), argumentHint, userInvocable } satisfies ISlashCommandDiscoveryResult;
} catch (e) {
this.logger.error(`[computeSlashCommandDiscoveryInfo] Failed to parse prompt file for slash command: ${promptPath.uri}`, e instanceof Error ? e.message : String(e));
return { status: 'skipped', skipReason: 'parse-error', errorMessage: e instanceof Error ? e.message : String(e), promptPath } satisfies ISlashCommandDiscoveryResult;
}
// Deduplicate skills that resolve to the same canonical name. This can
// happen when two skill locations point at the same files, e.g. when
// `~/.claude/skills` is a symlink to `~/.agents/skills` (created by
// `npx skills`). Without this, every such skill would appear twice in
// the `/` menu. `parseResults` preserves input order, so skills are
// already sorted by precedence; the first occurrence of a name wins.
const seenSkillNames = new Set<string>();
const files: ISlashCommandDiscoveryResult[] = [];
for (const result of parseResults) {
if (result.status === 'loaded' && result.promptPath.type === PromptsType.skill) {
const name = result.promptPath.name;
if (name !== undefined) {
}
}
}
const promptSourceFolders = await this._collectSourceFolderDiagnostics(PromptsType.prompt);
const sourceFolders = [...promptSourceFolders];
if (useAgentSkills) {
const skillSourceFolders = await this._collectSourceFolderDiagnostics(PromptsType.skill);
sourceFolders.push(...skillSourceFolders);
}
return { type: PromptsType.prompt, files, sourceFolders, durationInMillis: stopWatch.elapsed() };
promptsServiceImpl.ts
}
/**
*/
private slashCommandsFromDiscoveryInfo(discoveryInfo: ISlashCommandDiscoveryInfo): readonly IChatPromptSlashCommand[] {
const seen = new ResourceSet();
for (const file of discoveryInfo.files) {
if (file.status === 'loaded') {
result.push(this.asChatPromptSlashCommand(file.argumentHint, file.userInvocable, file.promptPath));
seen.add(file.promptPath.uri);
}
}
// Include untitled prompt models not covered by discovery
for (const model of this.modelService.getModels()) {
if (model.getLanguageId() === PROMPT_LANGUAGE_ID && model.uri.scheme === Schemas.untitled && !seen.has(model.uri)) {
const parsedPromptFile = this.getParsedPromptFile(model);
}
}
return result;
}
public isValidSlashCommandName(command: string): boolean {
private asChatPromptSlashCommand(argumentHint: string | undefined, userInvocable: boolean | undefined, promptPath: IPromptPath): IChatPromptSlashCommand {
name = name.replace(/[^\p{L}\d_\-\.:]+/gu, '-'); // replace spaces with dashes
return {
uri: promptPath.uri,
name: name,
source: promptPath.source,
storage: promptPath.storage,
type: promptPath.type,
extension: promptPath.extension,
pluginUri: promptPath.pluginUri,
pluginLabel: promptPath.pluginLabel,
description: promptPath.description,
argumentHint: argumentHint,
userInvocable: userInvocable ?? true,
sessionTypes: promptPath.sessionTypes,
};
}
public async getPromptSlashCommandName(uri: URI, token: CancellationToken): Promise<string> {
public getModels(): ITextModel[] {
const keys = Object.keys(this._models);
for (let i = 0, len = keys.length; i < len; i++) {
const modelId = keys[i];
ret.push(this._models[modelId].model);
}
return ret;
}
public getModel(resource: URI): ITextModel | null {