story-weaver-ai
Version:
A narrative development system for AI-driven storytelling with Jungian psychology
148 lines (135 loc) • 4.81 kB
JavaScript
/**
* 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' };
}
}