tasq/node_modules/@claude-flow/mcp/dist/prompt-registry.js

209 lines
5.5 KiB
JavaScript

/**
* @claude-flow/mcp - Prompt Registry
*
* MCP 2025-11-25 compliant prompt management
* Supports: list, get, arguments, templates, embedded resources
*/
import { EventEmitter } from 'events';
export class PromptRegistry extends EventEmitter {
logger;
prompts = new Map();
options;
constructor(logger, options = {}) {
super();
this.logger = logger;
this.options = {
maxPrompts: options.maxPrompts ?? 1000,
validateArguments: options.validateArguments ?? true,
};
}
/**
* Register a prompt
*/
register(prompt) {
if (this.prompts.size >= this.options.maxPrompts) {
this.logger.error('Maximum prompts reached', { max: this.options.maxPrompts });
return false;
}
if (this.prompts.has(prompt.name)) {
this.logger.warn('Prompt already registered', { name: prompt.name });
return false;
}
this.prompts.set(prompt.name, prompt);
this.logger.debug('Prompt registered', { name: prompt.name });
this.emit('prompt:registered', { name: prompt.name });
this.emitListChanged();
return true;
}
/**
* Unregister a prompt
*/
unregister(name) {
if (!this.prompts.has(name)) {
return false;
}
this.prompts.delete(name);
this.logger.debug('Prompt unregistered', { name });
this.emit('prompt:unregistered', { name });
this.emitListChanged();
return true;
}
/**
* List prompts with pagination
*/
list(cursor, pageSize = 50) {
const allPrompts = Array.from(this.prompts.values()).map((p) => ({
name: p.name,
title: p.title,
description: p.description,
arguments: p.arguments,
}));
let startIndex = 0;
if (cursor) {
const decoded = this.decodeCursor(cursor);
startIndex = decoded.offset;
}
const endIndex = Math.min(startIndex + pageSize, allPrompts.length);
const prompts = allPrompts.slice(startIndex, endIndex);
const result = { prompts };
if (endIndex < allPrompts.length) {
result.nextCursor = this.encodeCursor({ offset: endIndex });
}
return result;
}
/**
* Get a prompt with arguments
*/
async get(name, args = {}) {
const prompt = this.prompts.get(name);
if (!prompt) {
throw new Error(`Prompt not found: ${name}`);
}
// Validate required arguments
if (this.options.validateArguments && prompt.arguments) {
for (const arg of prompt.arguments) {
if (arg.required && !(arg.name in args)) {
throw new Error(`Missing required argument: ${arg.name}`);
}
}
}
const messages = await prompt.handler(args);
this.emit('prompt:get', { name, argCount: Object.keys(args).length });
return {
description: prompt.description,
messages,
};
}
/**
* Get prompt by name
*/
getPrompt(name) {
const prompt = this.prompts.get(name);
if (!prompt)
return undefined;
return {
name: prompt.name,
title: prompt.title,
description: prompt.description,
arguments: prompt.arguments,
};
}
/**
* Check if prompt exists
*/
hasPrompt(name) {
return this.prompts.has(name);
}
/**
* Get prompt count
*/
getPromptCount() {
return this.prompts.size;
}
/**
* Get stats
*/
getStats() {
let promptsWithArgs = 0;
for (const prompt of this.prompts.values()) {
if (prompt.arguments && prompt.arguments.length > 0) {
promptsWithArgs++;
}
}
return {
totalPrompts: this.prompts.size,
promptsWithArgs,
};
}
/**
* Encode cursor for pagination
*/
encodeCursor(data) {
return Buffer.from(JSON.stringify(data)).toString('base64');
}
/**
* Decode cursor for pagination
*/
decodeCursor(cursor) {
try {
return JSON.parse(Buffer.from(cursor, 'base64').toString('utf-8'));
}
catch {
return { offset: 0 };
}
}
/**
* Emit listChanged notification
*/
emitListChanged() {
this.emit('prompts:listChanged');
}
}
export function createPromptRegistry(logger, options) {
return new PromptRegistry(logger, options);
}
/**
* Helper to define a prompt
*/
export function definePrompt(name, description, handler, options) {
return {
name,
description,
title: options?.title,
arguments: options?.arguments,
handler,
};
}
/**
* Helper to create a text message
*/
export function textMessage(role, text) {
return {
role,
content: {
type: 'text',
text,
},
};
}
/**
* Helper to create a message with embedded resource
*/
export function resourceMessage(role, resource) {
return {
role,
content: {
type: 'resource',
resource,
},
};
}
/**
* Template string interpolation for prompts
*/
export function interpolate(template, args) {
return template.replace(/\{(\w+)\}/g, (match, key) => {
return args[key] ?? match;
});
}
//# sourceMappingURL=prompt-registry.js.map