UNPKG

story-weaver-ai

Version:

A narrative development system for AI-driven storytelling with Jungian psychology

148 lines (135 loc) 4.81 kB
/** * Story Weaver MCP Server - Analyze Story Tool * * @author Sean Pavlak * @github https://github.com/seanpavlak/cursor-story-master * * Tool for analyzing stories through a Jungian psychological lens. */ import fs from 'fs/promises'; import path from 'path'; import { spawnSync } from 'child_process'; import { fileURLToPath } from 'url'; import logger from '../logger.js'; // Get the directory path for the module const __filename = fileURLToPath(import.meta.url); const __dirname = path.dirname(__filename); const rootDir = path.resolve(__dirname, '../../..'); /** * Analyze a story with Jungian psychological principles */ export const analyzeStoryTool = { name: 'analyze_story', description: 'Analyze a story for plot structure, character development, themes, and psychological depth.', parameters: { type: 'object', properties: { input_file: { type: 'string', description: 'Path to the story file to analyze' }, output_file: { type: 'string', description: 'Path to save the analysis results (default: analysis_results.md)' }, deep_analysis: { type: 'boolean', description: 'Whether to perform deep psychological analysis' }, format: { type: 'string', description: 'Output format (markdown, json, yaml)', enum: ['markdown', 'json', 'yaml'] } }, required: ['input_file'] }, async handler(params) { try { logger.info(`Analyzing story file: ${params.input_file}`); // Default output file and format if not specified const outputFile = params.output_file || 'analysis_results.md'; const format = params.format || 'markdown'; // Set up command arguments const args = [ path.join(rootDir, 'bin/story-weaver.js'), 'analyze-story', '-i', params.input_file, '-o', outputFile, '-f', format ]; // Add deep analysis flag if requested if (params.deep_analysis) { args.push('-d'); } // Execute the command logger.debug(`Executing command: ${args.join(' ')}`); const result = spawnSync('node', args, { encoding: 'utf8', cwd: process.cwd() }); if (result.error) { throw new Error(`Failed to execute: ${result.error.message}`); } if (result.status !== 0) { throw new Error(`Command failed with status ${result.status}: ${result.stderr}`); } // Read the analysis file if it was successfully created const analysisContent = await fs.readFile(outputFile, 'utf8'); // Return the analysis results return { status: 'success', message: `Story analysis complete. Results saved to ${outputFile}`, file_path: outputFile, format: format, summary: extractSummary(analysisContent, format) }; } catch (error) { logger.error(`Story analysis failed: ${error.message}`); return { status: 'error', message: `Failed to analyze story: ${error.message}` }; } } }; /** * Extract a brief summary from the analysis content * @param {string} content - Analysis content * @param {string} format - Content format (markdown, json, yaml) * @returns {Object} Brief summary object */ function extractSummary(content, format) { // Extract basic summary data depending on format try { if (format === 'json') { const data = JSON.parse(content); return { structure_type: data.structure?.type || 'Unknown', structure_rating: data.structure?.effectiveness || 0, character_count: data.characters?.length || 0, themes: data.themes?.primary || [], has_recommendations: Boolean(data.recommendations?.length) }; } else if (format === 'yaml') { // Basic YAML parsing to extract summary // In a real implementation, you'd use a YAML parser return { note: 'YAML summary extraction is simplified in this version' }; } else { // For markdown, extract basic info from headings const structureMatch = content.match(/## Plot Structure\s+\*\*Type\*\*: (.*)\s+\*\*Effectiveness\*\*: (\d+)/); const charactersMatch = content.match(/## Characters/g); const themesMatch = content.match(/### Primary Themes\s+((?:- .*\s+)+)/); return { structure_type: structureMatch ? structureMatch[1] : 'Unknown', structure_rating: structureMatch ? parseInt(structureMatch[2]) : 0, has_recommendations: content.includes('## Recommendations') }; } } catch (error) { logger.warn(`Failed to extract summary: ${error.message}`); return { note: 'Summary extraction failed' }; } }