UNPKG

@dollhousemcp/mcp-server

Version:

DollhouseMCP - A Model Context Protocol (MCP) server that enables dynamic AI persona management from markdown files, allowing Claude and other compatible AI assistants to activate and switch between different behavioral personas.

318 lines 11.2 kB
/** * ElementCRUDHandler - Handles all generic element CRUD operations * * Provides create, edit, validate, and delete operations for all element types * (personas, skills, templates, agents, memories). * * Uses dependency injection for all services: * - InitializationService for setup tasks * - PersonaIndicatorService for persona indicator formatting * - Element managers (SkillManager, TemplateManager, AgentManager, MemoryManager) * - PersonaManager for persona operations * - PortfolioManager for portfolio operations * * FIX: DMCP-SEC-006 - Security audit suppression * This handler delegates all operations to specialized element managers. * Audit logging happens in the element managers themselves. * @security-audit-suppress DMCP-SEC-006 */ import { PortfolioManager } from '../portfolio/PortfolioManager.js'; import { SkillManager } from '../elements/skills/index.js'; import { TemplateManager } from '../elements/templates/TemplateManager.js'; import { TemplateRenderer } from '../utils/TemplateRenderer.js'; import { AgentManager } from '../elements/agents/AgentManager.js'; import { MemoryManager } from '../elements/memories/MemoryManager.js'; import { EnsembleManager } from '../elements/ensembles/EnsembleManager.js'; import { InitializationService } from '../services/InitializationService.js'; import { PersonaIndicatorService } from '../services/PersonaIndicatorService.js'; import { PersonaManager } from '../persona/PersonaManager.js'; import type { IFileOperationsService } from '../services/FileOperationsService.js'; import type { MCPResponse } from './strategies/index.js'; import { ElementQueryService } from '../services/query/ElementQueryService.js'; import { ValidationRegistry } from '../services/validation/ValidationRegistry.js'; import type { ActivationStore } from '../services/ActivationStore.js'; import type { BackupService } from '../services/BackupService.js'; import type { PolicyExportService } from '../services/PolicyExportService.js'; export declare class ElementCRUDHandler { private readonly skillManager; private readonly templateManager; private readonly templateRenderer; private readonly agentManager; private readonly memoryManager; private readonly ensembleManager; private readonly personaManager; private readonly portfolioManager; private readonly initService; private readonly indicatorService; private readonly fileOperations; private readonly elementQueryService; private readonly validationRegistry; private readonly activationStore?; private readonly backupService?; private readonly policyExportService?; private readonly strategies; constructor(skillManager: SkillManager, templateManager: TemplateManager, templateRenderer: TemplateRenderer, agentManager: AgentManager, memoryManager: MemoryManager, ensembleManager: EnsembleManager, personaManager: PersonaManager, portfolioManager: PortfolioManager, initService: InitializationService, indicatorService: PersonaIndicatorService, fileOperations: IFileOperationsService, elementQueryService: ElementQueryService, validationRegistry: ValidationRegistry, activationStore?: ActivationStore | undefined, backupService?: BackupService | undefined, policyExportService?: PolicyExportService | undefined); private ensureInitialized; private getPersonaIndicator; private getContext; /** * Find an element by name, supporting both exact display name and filename (slug) matching * Helper method extracted from index.ts:346-379 */ private findElementFlexibly; /** * Sanitize metadata object to prevent prototype pollution * Helper method extracted from index.ts:390-410 */ private sanitizeMetadata; private normalizeLookupValue; private hasGatekeeperPolicy; private toPolicyElementType; /** * Create a new element * Extracted from index.ts:1492-1631 (140 lines - exact copy) */ createElement(args: { name: string; type: string; description: string; content?: string; instructions?: string; metadata?: Record<string, any>; }): Promise<import("./element-crud/responseFormatter.js").McpToolResponse | { content: { type: string; text: string; }[]; }>; /** * Edit an existing element using GraphQL-aligned nested input objects. * * @example * await handler.editElement({ * name: 'my-skill', * type: 'skills', * input: { * description: 'Updated', * metadata: { triggers: ['code'] } * } * }); */ editElement(args: { name: string; type: string; input: Record<string, unknown>; }): Promise<{ content: { type: string; text: string; }[]; }>; /** * Upgrade element from v1 single-body to v2 dual-field format (instructions + content) */ upgradeElement(args: { name: string; type: string; dry_run?: boolean; instructions_override?: string; content_override?: string; }): Promise<{ content: { type: string; text: string; }[]; }>; /** * Validate an element * Extracted from index.ts:1941-2054 (114 lines - exact copy) */ validateElement(args: { name: string; type: string; strict?: boolean; }): Promise<{ content: { type: string; text: string; }[]; }>; /** * Delete an element * Extracted from index.ts:2056-2310 (255 lines - exact copy, split for readability) */ deleteElement(args: { name: string; type: string; deleteData?: boolean; }): Promise<{ content: { type: string; text: string; }[]; }>; normalizeElementType(type: string | undefined | null): string; listElements(type: string, options?: import('../services/query/types.js').QueryOptions): Promise<import("./element-crud/listElements.js").AggregationResult | import("./element-crud/listElements.js").ListElementsResult | import("./element-crud/listElements.js").StructuredError>; /** * Get raw elements array for a given type. * Unlike listElements which returns MCPResponse format, this returns raw element objects. * * @param type - Element type (persona, skill, template, agent, memory, ensemble) * @returns Array of raw element objects */ getElements(type: string): Promise<unknown[]>; activateElement(name: string, type: string, context?: Record<string, any>): Promise<MCPResponse>; getActiveElements(type?: string): Promise<MCPResponse>; /** * Get raw active elements for Gatekeeper policy evaluation. * Returns active personas, skills, and ensembles with their metadata * mapped to the shape expected by the Gatekeeper's ActiveElement interface. * * Issue #452: Provides active element context for enforce() policy checks. */ getActiveElementsForPolicy(): Promise<Array<{ type: string; name: string; metadata: Record<string, unknown>; }>>; getPolicyElementsForReport(sessionId?: string): Promise<Array<{ type: string; name: string; metadata: Record<string, unknown>; sessionIds?: string[]; }>>; releaseDeadlock(): Promise<{ sessionId?: string; activeBeforeReset: Array<{ type: string; name: string; }>; deactivated: Array<{ type: string; name: string; }>; failed: Array<{ type: string; name: string; error: string; }>; persistedStateCleared: boolean; likelyDeadlockCause: { sandboxingElement?: { type: string; name: string; }; advisoryElements: Array<{ type: string; name: string; }>; }; snapshotFile?: string; }>; private collectActiveElementsForDeadlockRelief; private writeDeadlockReliefSnapshot; private mergePersistedPolicyState; deactivateElement(name: string, type: string): Promise<MCPResponse>; /** * Issue #708: Get the element manager for a normalized type. * Used to check invalid element records when an element is "not found". */ private getManagerForType; getElementDetails(name: string, type: string): Promise<MCPResponse>; /** * Reload elements of a specific type from the filesystem * Extracted from index.ts:609-679 (exact copy, adapted for handler pattern) */ reloadElements(type: string): Promise<{ content: { type: string; text: string; }[]; }>; /** * Render a template with variables * Extracted from index.ts:682-701 (exact copy) * * @throws {ElementNotFoundError} When template does not exist * @see Issue #275 - Handlers return success=true for missing elements */ renderTemplate(name: string, variables: Record<string, any>): Promise<{ content: { type: string; text: string; }[]; }>; /** * Execute an agent with goal parameters * Returns context for LLM to drive the agentic loop */ executeAgent(name: string, parameters: Record<string, any>): Promise<{ content: { type: string; text: string; }[]; }>; /** * Record a step in agent execution */ recordAgentStep(args: { agentName: string; stepDescription: string; outcome: "success" | "failure" | "partial"; findings?: string; confidence?: number; nextActionHint?: string; riskScore?: number; }): Promise<{ content: { type: string; text: string; }[]; }>; /** * Complete an agent goal */ completeAgentGoal(args: { agentName: string; goalId?: string; outcome: "success" | "failure" | "partial"; summary: string; }): Promise<{ content: { type: string; text: string; }[]; }>; /** * Get agent state */ getAgentState(args: { agentName: string; includeDecisionHistory?: boolean; includeContext?: boolean; }): Promise<{ content: { type: string; text: string; }[]; }>; /** * Continue agent execution from previous state */ continueAgentExecution(args: { agentName: string; parameters?: Record<string, any>; previousStepResult?: string; }): Promise<{ content: { type: string; text: string; }[]; }>; /** * Aggregate active elements across all registered element types. * Issue #501: Called when get_active_elements is invoked without element_type. */ private aggregateActiveElements; } //# sourceMappingURL=ElementCRUDHandler.d.ts.map