tarot-mcp-server
Version:
Model Context Protocol server for Rider-Waite tarot card readings
1,031 lines • 51.4 kB
JavaScript
import { getAllSpreads, getSpread, isValidSpreadType } from "./spreads.js";
import { getSecureRandom } from "./utils.js";
/**
* Manages tarot readings and interpretations
*/
export class TarotReadingManager {
cardManager;
sessionManager;
constructor(cardManager, sessionManager) {
this.cardManager = cardManager;
this.sessionManager = sessionManager;
}
/**
* Perform a tarot reading
*/
performReading(spreadType, question, sessionId) {
if (!isValidSpreadType(spreadType)) {
return `Invalid spread type: ${spreadType}. Use list_available_spreads to see valid options.`;
}
const spread = getSpread(spreadType);
// Use cryptographically secure random card drawing
const cards = this.cardManager.getRandomCards(spread.cardCount);
// Generate random orientations for each card using secure randomness
const drawnCards = cards.map((card, index) => ({
card,
orientation: this.getSecureRandomOrientation(), // Cryptographically secure orientation
position: spread.positions[index].name,
positionMeaning: spread.positions[index].meaning
}));
// Create the reading
const reading = {
id: this.generateReadingId(),
spreadType,
question,
cards: drawnCards,
interpretation: this.generateInterpretation(drawnCards, question, spread.name),
timestamp: new Date(),
sessionId
};
// Add to session if provided
if (sessionId) {
this.sessionManager.addReadingToSession(sessionId, reading);
}
return this.formatReading(reading, spread.name, spread.description);
}
/**
* List all available spreads
*/
listAvailableSpreads() {
const spreads = getAllSpreads();
let result = "# Available Tarot Spreads\n\n";
spreads.forEach(spread => {
result += `## ${spread.name} (${spread.cardCount} cards)\n\n`;
result += `${spread.description}\n\n`;
result += "**Positions:**\n";
spread.positions.forEach((position, index) => {
result += `${index + 1}. **${position.name}**: ${position.meaning}\n`;
});
result += "\n";
});
result += "Use the `perform_reading` tool with one of these spread types to get a reading.";
return result;
}
/**
* Perform a custom tarot reading with user-defined spread
*/
performCustomReading(spreadName, description, positions, question, sessionId) {
// Create a custom spread object
const customSpread = {
name: spreadName,
description: description,
positions: positions,
cardCount: positions.length
};
// Use cryptographically secure random card drawing
const cards = this.cardManager.getRandomCards(customSpread.cardCount);
// Generate random orientations for each card using secure randomness
const drawnCards = cards.map((card, index) => ({
card,
orientation: this.getSecureRandomOrientation(), // Cryptographically secure orientation
position: customSpread.positions[index].name,
positionMeaning: customSpread.positions[index].meaning
}));
// Create the reading
const reading = {
id: this.generateReadingId(),
spreadType: `custom_${spreadName.toLowerCase().replace(/\s+/g, '_')}`,
question,
cards: drawnCards,
interpretation: this.generateInterpretation(drawnCards, question, customSpread.name),
timestamp: new Date(),
sessionId
};
// Add to session if provided
if (sessionId) {
this.sessionManager.addReadingToSession(sessionId, reading);
}
return this.formatReading(reading, customSpread.name, customSpread.description);
}
/**
* Interpret a combination of cards
*/
interpretCardCombination(cards, context) {
const drawnCards = [];
for (const cardInput of cards) {
const card = this.cardManager.findCard(cardInput.name);
if (!card) {
return `Card "${cardInput.name}" not found. Use list_all_cards to see available cards.`;
}
drawnCards.push({
card,
orientation: cardInput.orientation || "upright"
});
}
let result = `# Card Combination Interpretation\n\n`;
result += `**Context:** ${context}\n\n`;
result += `## Cards in This Reading\n\n`;
drawnCards.forEach((drawnCard, index) => {
result += `${index + 1}. **${drawnCard.card.name}** (${drawnCard.orientation})\n`;
const keywords = drawnCard.orientation === "upright"
? drawnCard.card.keywords.upright
: drawnCard.card.keywords.reversed;
result += ` *Keywords: ${keywords.join(", ")}*\n\n`;
});
result += `## Interpretation\n\n`;
result += this.generateCombinationInterpretation(drawnCards, context);
return result;
}
/**
* Generate interpretation for a reading
*/
generateInterpretation(drawnCards, question, spreadName) {
let interpretation = `This ${spreadName} reading addresses your question: "${question}"\n\n`;
// Individual card interpretations with context
drawnCards.forEach((drawnCard, index) => {
const meanings = drawnCard.orientation === "upright"
? drawnCard.card.meanings.upright
: drawnCard.card.meanings.reversed;
interpretation += `**${drawnCard.position}**: ${drawnCard.card.name} (${drawnCard.orientation})\n`;
// Choose the most relevant meaning based on position
const relevantMeaning = this.selectRelevantMeaning(meanings, drawnCard.position || "General", question);
interpretation += `${relevantMeaning}\n\n`;
});
// Add spread-specific analysis
if (spreadName.toLowerCase().includes("celtic cross")) {
interpretation += this.generateCelticCrossAnalysis(drawnCards);
}
else if (spreadName.toLowerCase().includes("three card")) {
interpretation += this.generateThreeCardAnalysis(drawnCards);
}
else if (spreadName.toLowerCase().includes("relationship")) {
interpretation += this.generateRelationshipAnalysis(drawnCards);
}
else if (spreadName.toLowerCase().includes("career")) {
interpretation += this.generateCareerAnalysis(drawnCards);
}
else if (spreadName.toLowerCase().includes("spiritual")) {
interpretation += this.generateSpiritualAnalysis(drawnCards);
}
else if (spreadName.toLowerCase().includes("chakra")) {
interpretation += this.generateChakraAnalysis(drawnCards);
}
else if (spreadName.toLowerCase().includes("year ahead")) {
interpretation += this.generateYearAheadAnalysis(drawnCards);
}
else if (spreadName.toLowerCase().includes("venus") || spreadName.toLowerCase().includes("love")) {
interpretation += this.generateVenusLoveAnalysis(drawnCards);
}
else if (spreadName.toLowerCase().includes("tree of life")) {
interpretation += this.generateTreeOfLifeAnalysis(drawnCards);
}
else if (spreadName.toLowerCase().includes("astrological")) {
interpretation += this.generateAstrologicalAnalysis(drawnCards);
}
else if (spreadName.toLowerCase().includes("mandala")) {
interpretation += this.generateMandalaAnalysis(drawnCards);
}
else if (spreadName.toLowerCase().includes("pentagram")) {
interpretation += this.generatePentagramAnalysis(drawnCards);
}
else if (spreadName.toLowerCase().includes("mirror of truth")) {
interpretation += this.generateMirrorOfTruthAnalysis(drawnCards);
}
// Overall interpretation
interpretation += this.generateOverallInterpretation(drawnCards, question);
return interpretation;
}
/**
* Select the most relevant meaning based on position and question
*/
selectRelevantMeaning(meanings, position, question) {
const questionLower = question.toLowerCase();
const positionLower = position.toLowerCase();
// Determine the most relevant aspect based on question content
if (questionLower.includes("love") || questionLower.includes("relationship") || questionLower.includes("romance")) {
return meanings.love;
}
else if (questionLower.includes("career") || questionLower.includes("job") || questionLower.includes("work") || questionLower.includes("money")) {
return meanings.career;
}
else if (questionLower.includes("health") || questionLower.includes("wellness") || questionLower.includes("body")) {
return meanings.health;
}
else if (questionLower.includes("spiritual") || questionLower.includes("purpose") || questionLower.includes("meaning")) {
return meanings.spirituality;
}
// Default to general meaning, but consider position context
if (positionLower.includes("love") || positionLower.includes("relationship")) {
return meanings.love;
}
else if (positionLower.includes("career") || positionLower.includes("work")) {
return meanings.career;
}
return meanings.general;
}
/**
* Generate Celtic Cross specific analysis
*/
generateCelticCrossAnalysis(drawnCards) {
if (drawnCards.length !== 10)
return "";
let analysis = "**Celtic Cross Analysis:**\n\n";
// Analyze key relationships between positions
const present = drawnCards[0];
const challenge = drawnCards[1];
const past = drawnCards[2];
const future = drawnCards[3];
const above = drawnCards[4];
const below = drawnCards[5];
const advice = drawnCards[6];
const external = drawnCards[7];
const hopesFearsCard = drawnCards[8];
const outcome = drawnCards[9];
// Above vs Below analysis
analysis += `**Conscious vs Subconscious:** The ${above.card.name} above represents your conscious goals, while the ${below.card.name} below reveals your subconscious drives. `;
if (above.orientation === below.orientation) {
analysis += "These are aligned, suggesting harmony between your conscious desires and unconscious motivations. ";
}
else {
analysis += "The different orientations suggest some tension between what you consciously want and what unconsciously drives you. ";
}
// Above vs Outcome analysis
analysis += `**Goal vs Outcome:** Your conscious goal (${above.card.name}) `;
if (this.cardsHaveSimilarEnergy(above, outcome)) {
analysis += "aligns well with the likely outcome, suggesting you're on the right path. ";
}
else {
analysis += "differs from the projected outcome, indicating you may need to adjust your approach. ";
}
// Future vs Outcome analysis
analysis += `**Near Future Impact:** The ${future.card.name} in your near future will `;
if (future.orientation === "upright") {
analysis += "support your journey toward the final outcome. ";
}
else {
analysis += "present challenges that need to be navigated carefully to reach your desired outcome. ";
}
analysis += "\n";
return analysis;
}
/**
* Generate Three Card specific analysis
*/
generateThreeCardAnalysis(drawnCards) {
if (drawnCards.length !== 3)
return "";
let analysis = "**Three Card Flow Analysis:**\n\n";
const [past, present, future] = drawnCards;
analysis += `**The Journey:** From ${past.card.name} in the past, through ${present.card.name} in the present, to ${future.card.name} in the future, `;
// Analyze the progression
const pastEnergy = past.orientation === "upright" ? "positive" : "challenging";
const presentEnergy = present.orientation === "upright" ? "positive" : "challenging";
const futureEnergy = future.orientation === "upright" ? "positive" : "challenging";
if (pastEnergy === "challenging" && presentEnergy === "positive" && futureEnergy === "positive") {
analysis += "shows a clear progression from difficulty to resolution and success. ";
}
else if (pastEnergy === "positive" && presentEnergy === "challenging" && futureEnergy === "positive") {
analysis += "indicates a temporary setback that will resolve positively. ";
}
else if (pastEnergy === "positive" && presentEnergy === "positive" && futureEnergy === "positive") {
analysis += "reveals a consistently positive trajectory with continued growth. ";
}
else {
analysis += "shows a complex journey requiring careful attention to the lessons each phase offers. ";
}
analysis += "\n";
return analysis;
}
/**
* Generate Relationship spread specific analysis
*/
generateRelationshipAnalysis(drawnCards) {
if (drawnCards.length !== 7)
return "";
let analysis = "**Relationship Dynamics Analysis:**\n\n";
const you = drawnCards[0];
const partner = drawnCards[1];
const relationship = drawnCards[2];
const unites = drawnCards[3];
const divides = drawnCards[4];
// Analyze compatibility
analysis += `**Compatibility Assessment:** `;
if (you.orientation === partner.orientation) {
analysis += "You and your partner are currently in similar emotional states, which can create harmony. ";
}
else {
analysis += "You and your partner are in different emotional phases, which requires understanding and patience. ";
}
// Analyze relationship balance
const positiveCards = [you, partner, relationship, unites].filter(c => c.orientation === "upright").length;
if (positiveCards >= 3) {
analysis += "The overall energy of the relationship is positive and supportive. ";
}
else {
analysis += "The relationship may need attention and conscious effort to improve dynamics. ";
}
analysis += "\n";
return analysis;
}
/**
* Generate Career spread specific analysis
*/
generateCareerAnalysis(drawnCards) {
if (drawnCards.length !== 6)
return "";
let analysis = "**Career Path Analysis:**\n\n";
const current = drawnCards[0];
const skills = drawnCards[1];
const challenges = drawnCards[2];
const opportunities = drawnCards[3];
// Analyze career readiness
analysis += `**Career Readiness:** `;
if (skills.orientation === "upright" && opportunities.orientation === "upright") {
analysis += "You have strong skills and good opportunities ahead. This is a favorable time for career advancement. ";
}
else if (challenges.orientation === "reversed") {
analysis += "Previous obstacles are clearing, making way for new professional growth. ";
}
else {
analysis += "Focus on developing your skills and overcoming current challenges before pursuing new opportunities. ";
}
analysis += "\n";
return analysis;
}
/**
* Generate Spiritual Guidance spread analysis
*/
generateSpiritualAnalysis(drawnCards) {
if (drawnCards.length !== 6)
return "";
let analysis = "**Spiritual Development Analysis:**\n\n";
const spiritualState = drawnCards[0];
const lessons = drawnCards[1];
const blocks = drawnCards[2];
const gifts = drawnCards[3];
// Analyze spiritual progress
analysis += `**Spiritual Progress:** `;
if (spiritualState.orientation === "upright") {
analysis += "You are in a positive phase of spiritual growth and awareness. ";
}
else {
analysis += "You may be experiencing spiritual challenges or confusion that require inner work. ";
}
if (blocks.orientation === "reversed") {
analysis += "Previous spiritual blocks are dissolving, allowing for greater growth. ";
}
analysis += "\n";
return analysis;
}
/**
* Generate Chakra Alignment spread analysis
*/
generateChakraAnalysis(drawnCards) {
if (drawnCards.length !== 7)
return "";
let analysis = "**Chakra Energy Analysis:**\n\n";
const uprightChakras = drawnCards.filter(c => c.orientation === "upright").length;
const balancePercentage = (uprightChakras / 7) * 100;
analysis += `**Overall Energy Balance:** `;
if (balancePercentage >= 70) {
analysis += "Your chakras are well-balanced with strong energy flow. ";
}
else if (balancePercentage >= 50) {
analysis += "Your energy centers have moderate balance with some areas needing attention. ";
}
else {
analysis += "Several chakras need healing and rebalancing for optimal energy flow. ";
}
// Identify energy patterns
const lowerChakras = drawnCards.slice(0, 3).filter(c => c.orientation === "upright").length;
const upperChakras = drawnCards.slice(4, 7).filter(c => c.orientation === "upright").length;
if (lowerChakras > upperChakras) {
analysis += "Your grounding and physical energy centers are stronger than your spiritual centers. ";
}
else if (upperChakras > lowerChakras) {
analysis += "Your spiritual and intuitive centers are more active than your grounding centers. ";
}
analysis += "\n";
return analysis;
}
/**
* Generate Year Ahead spread analysis
*/
generateYearAheadAnalysis(drawnCards) {
if (drawnCards.length !== 13)
return "";
let analysis = "**Year Ahead Overview:**\n\n";
const overallTheme = drawnCards[0];
const monthlyCards = drawnCards.slice(1);
// Analyze overall year energy
analysis += `**Year Theme:** The ${overallTheme.card.name} sets the tone for your year, `;
if (overallTheme.orientation === "upright") {
analysis += "indicating a positive and growth-oriented period ahead. ";
}
else {
analysis += "suggesting a year of inner work and overcoming challenges. ";
}
// Analyze seasonal patterns
const quarters = [
monthlyCards.slice(0, 3), // Q1: Jan-Mar
monthlyCards.slice(3, 6), // Q2: Apr-Jun
monthlyCards.slice(6, 9), // Q3: Jul-Sep
monthlyCards.slice(9, 12) // Q4: Oct-Dec
];
quarters.forEach((quarter, index) => {
const uprightCount = quarter.filter(c => c.orientation === "upright").length;
const quarterNames = ["First Quarter", "Second Quarter", "Third Quarter", "Fourth Quarter"];
analysis += `**${quarterNames[index]}:** `;
if (uprightCount >= 2) {
analysis += "A positive and productive period. ";
}
else {
analysis += "A time for patience and inner work. ";
}
});
analysis += "\n";
return analysis;
}
/**
* Generate Venus Love spread analysis
*/
generateVenusLoveAnalysis(drawnCards) {
if (drawnCards.length !== 7)
return "";
let analysis = "**Venus Love Energy Analysis:**\n\n";
const [currentEnergy, selfLove, attraction, blocks, enhancement, desires, future] = drawnCards;
// Analyze love energy flow
analysis += `**Love Energy Flow:** Your current relationship energy (${currentEnergy.card.name}) `;
if (currentEnergy.orientation === "upright") {
analysis += "shows positive romantic vibrations and openness to love. ";
}
else {
analysis += "suggests some healing or inner work is needed before fully opening to love. ";
}
// Self-love foundation
analysis += `Your self-love foundation (${selfLove.card.name}) `;
if (selfLove.orientation === "upright") {
analysis += "indicates healthy self-worth that attracts genuine love. ";
}
else {
analysis += "reveals areas where self-compassion and self-acceptance need attention. ";
}
// Attraction and blocks
analysis += `What attracts love to you (${attraction.card.name}) works in harmony with `;
analysis += `overcoming blocks (${blocks.card.name}) to create a path forward. `;
// Future potential
analysis += `The future potential (${future.card.name}) `;
if (future.orientation === "upright") {
analysis += "promises beautiful developments in your love life. ";
}
else {
analysis += "suggests patience and continued inner work will lead to love. ";
}
analysis += "\n";
return analysis;
}
/**
* Generate Tree of Life spread analysis
*/
generateTreeOfLifeAnalysis(drawnCards) {
if (drawnCards.length !== 10)
return "";
let analysis = "**Tree of Life Spiritual Analysis:**\n\n";
const [kether, chokmah, binah, chesed, geburah, tiphareth, netzach, hod, yesod, malkuth] = drawnCards;
// Analyze the three pillars
const leftPillar = [binah, geburah, hod]; // Severity
const rightPillar = [chokmah, chesed, netzach]; // Mercy
const middlePillar = [kether, tiphareth, yesod, malkuth]; // Balance
// Pillar analysis
const leftUprightCount = leftPillar.filter(c => c.orientation === "upright").length;
const rightUprightCount = rightPillar.filter(c => c.orientation === "upright").length;
const middleUprightCount = middlePillar.filter(c => c.orientation === "upright").length;
analysis += `**Pillar Balance:** `;
if (rightUprightCount > leftUprightCount) {
analysis += "The Pillar of Mercy dominates, indicating expansion, growth, and positive energy. ";
}
else if (leftUprightCount > rightUprightCount) {
analysis += "The Pillar of Severity is prominent, suggesting discipline, boundaries, and necessary restrictions. ";
}
else {
analysis += "The pillars are balanced, showing harmony between expansion and contraction. ";
}
// Crown to Kingdom flow
analysis += `**Divine Flow:** From Kether (${kether.card.name}) to Malkuth (${malkuth.card.name}), `;
if (kether.orientation === malkuth.orientation) {
analysis += "there's alignment between your highest purpose and material manifestation. ";
}
else {
analysis += "there's a need to bridge the gap between spiritual ideals and earthly reality. ";
}
analysis += "\n";
return analysis;
}
/**
* Generate Astrological Houses spread analysis
*/
generateAstrologicalAnalysis(drawnCards) {
if (drawnCards.length !== 12)
return "";
let analysis = "**Astrological Houses Analysis:**\n\n";
// Group houses by element
const fireHouses = [drawnCards[0], drawnCards[4], drawnCards[8]]; // 1st, 5th, 9th
const earthHouses = [drawnCards[1], drawnCards[5], drawnCards[9]]; // 2nd, 6th, 10th
const airHouses = [drawnCards[2], drawnCards[6], drawnCards[10]]; // 3rd, 7th, 11th
const waterHouses = [drawnCards[3], drawnCards[7], drawnCards[11]]; // 4th, 8th, 12th
// Analyze elemental balance
const fireUpright = fireHouses.filter(c => c.orientation === "upright").length;
const earthUpright = earthHouses.filter(c => c.orientation === "upright").length;
const airUpright = airHouses.filter(c => c.orientation === "upright").length;
const waterUpright = waterHouses.filter(c => c.orientation === "upright").length;
analysis += `**Elemental Balance:** `;
const elements = [
{ name: "Fire (Identity/Creativity/Philosophy)", count: fireUpright },
{ name: "Earth (Resources/Work/Career)", count: earthUpright },
{ name: "Air (Communication/Partnerships/Community)", count: airUpright },
{ name: "Water (Home/Transformation/Spirituality)", count: waterUpright }
];
const strongestElement = elements.reduce((max, current) => current.count > max.count ? current : max);
analysis += `${strongestElement.name} energy is strongest in your chart, `;
analysis += `indicating focus in these life areas. `;
// Angular houses analysis (1st, 4th, 7th, 10th)
const angularHouses = [drawnCards[0], drawnCards[3], drawnCards[6], drawnCards[9]];
const angularUpright = angularHouses.filter(c => c.orientation === "upright").length;
analysis += `**Life Direction:** With ${angularUpright} out of 4 angular houses upright, `;
if (angularUpright >= 3) {
analysis += "you have strong momentum and clear direction in major life areas. ";
}
else if (angularUpright >= 2) {
analysis += "you have moderate stability with some areas needing attention. ";
}
else {
analysis += "focus on building stronger foundations in key life areas. ";
}
analysis += "\n";
return analysis;
}
/**
* Generate Mandala spread analysis
*/
generateMandalaAnalysis(drawnCards) {
if (drawnCards.length !== 9)
return "";
let analysis = "**Mandala Wholeness Analysis:**\n\n";
const [center, north, northeast, east, southeast, south, southwest, west, northwest] = drawnCards;
// Analyze center in relation to outer cards
analysis += `**Core Integration:** Your center (${center.card.name}) `;
if (center.orientation === "upright") {
analysis += "shows a strong, balanced core that can integrate the surrounding energies. ";
}
else {
analysis += "suggests the need for inner healing before achieving wholeness. ";
}
// Analyze directional balance
const directions = [north, northeast, east, southeast, south, southwest, west, northwest];
const uprightDirections = directions.filter(c => c.orientation === "upright").length;
analysis += `**Directional Balance:** With ${uprightDirections} out of 8 directions upright, `;
if (uprightDirections >= 6) {
analysis += "your life energies are well-balanced and flowing harmoniously. ";
}
else if (uprightDirections >= 4) {
analysis += "you have good balance with some areas needing attention. ";
}
else {
analysis += "focus on healing and balancing multiple life areas. ";
}
// Opposite directions analysis
const opposites = [
[north, south], [east, west], [northeast, southwest], [southeast, northwest]
];
let balancedPairs = 0;
opposites.forEach(([dir1, dir2]) => {
if (dir1.orientation === dir2.orientation) {
balancedPairs++;
}
});
analysis += `**Polarity Integration:** ${balancedPairs} out of 4 opposite pairs are balanced, `;
if (balancedPairs >= 3) {
analysis += "showing excellent integration of opposing forces. ";
}
else {
analysis += "indicating opportunities to harmonize conflicting energies. ";
}
analysis += "\n";
return analysis;
}
/**
* Generate Pentagram spread analysis
*/
generatePentagramAnalysis(drawnCards) {
if (drawnCards.length !== 5)
return "";
let analysis = "**Pentagram Elemental Analysis:**\n\n";
const [spirit, air, fire, earth, water] = drawnCards;
// Analyze elemental balance
const elements = [air, fire, earth, water];
const uprightElements = elements.filter(c => c.orientation === "upright").length;
analysis += `**Elemental Harmony:** With ${uprightElements} out of 4 elements upright, `;
if (uprightElements === 4) {
analysis += "all elements are in perfect harmony, creating powerful manifestation energy. ";
}
else if (uprightElements >= 3) {
analysis += "strong elemental balance with minor adjustments needed. ";
}
else if (uprightElements >= 2) {
analysis += "moderate balance requiring attention to weaker elements. ";
}
else {
analysis += "significant elemental imbalance requiring healing and rebalancing. ";
}
// Spirit connection analysis
analysis += `**Divine Connection:** Spirit (${spirit.card.name}) `;
if (spirit.orientation === "upright") {
analysis += "shows strong divine connection guiding your elemental balance. ";
}
else {
analysis += "suggests the need to strengthen your spiritual foundation. ";
}
// Element-specific insights
analysis += `**Elemental Flow:** `;
if (air.orientation === "upright")
analysis += "Clear thinking and communication support your goals. ";
if (fire.orientation === "upright")
analysis += "Passionate energy drives your actions. ";
if (earth.orientation === "upright")
analysis += "Practical foundations support manifestation. ";
if (water.orientation === "upright")
analysis += "Emotional wisdom guides your intuition. ";
analysis += "\n";
return analysis;
}
/**
* Generate Mirror of Truth spread analysis
*/
generateMirrorOfTruthAnalysis(drawnCards) {
if (drawnCards.length !== 4)
return "";
let analysis = "**Mirror of Truth - Four Beams of Light Analysis:**\n\n";
const [yourPerspective, theirIntention, objectiveTruth, futureGuidance] = drawnCards;
// First Light Analysis - Your Perspective
analysis += `**First Light - Illuminate Yourself:** ${yourPerspective.card.name} (${yourPerspective.orientation})\n`;
analysis += `Your current emotional state and inner filters show: `;
if (yourPerspective.orientation === "upright") {
analysis += "Your perception of the situation is relatively clear, your emotional state is stable, and you can view the problem objectively.";
}
else {
analysis += "Your perspective may be influenced by strong emotions, anxiety, or expectations, requiring inner calm to see the truth clearly.";
}
analysis += "\n\n";
// Second Light Analysis - Their Intention
analysis += `**Second Light - Explore Their Heart:** ${theirIntention.card.name} (${theirIntention.orientation})\n`;
analysis += `Their true intentions and inner state indicate: `;
if (theirIntention.orientation === "upright") {
analysis += "Their motivations are relatively positive and sincere, with good intentions or at least neutral intent behind their actions.";
}
else {
analysis += "They may have complex inner states, their true intentions might not align with surface behavior, or they themselves are confused.";
}
analysis += "\n\n";
// Third Light Analysis - Objective Truth
analysis += `**Third Light - Restore Original Truth:** ${objectiveTruth.card.name} (${objectiveTruth.orientation})\n`;
analysis += `Stripping away all subjective emotions, the truth is: `;
if (objectiveTruth.orientation === "upright") {
analysis += "The situation itself is relatively simple and clear, you and the other person may have over-interpreted it. The facts are more direct than imagined.";
}
else {
analysis += "The situation does have complexity and hidden layers, requiring more time and information to fully understand.";
}
analysis += "\n\n";
// Fourth Light Analysis - Future Guidance
analysis += `**Fourth Light - Guide Future Direction:** ${futureGuidance.card.name} (${futureGuidance.orientation})\n`;
analysis += `Based on understanding the truth, you should: `;
if (futureGuidance.orientation === "upright") {
analysis += "Take positive and proactive action, now is a good time to clarify misunderstandings, improve relationships, or make decisions.";
}
else {
analysis += "Maintain patience and observation, don't rush into action, let time and more information reveal the best path forward.";
}
analysis += "\n\n";
// Comprehensive Analysis of Four Lights
analysis += `**Comprehensive Insights from Four Lights:**\n`;
const uprightCount = drawnCards.filter(c => c.orientation === "upright").length;
// Analyze relationship between your perspective and their intention
if (yourPerspective.orientation === theirIntention.orientation) {
analysis += `Your perception and their intention are in similar energy states, indicating some synchronicity between you. `;
}
else {
analysis += `Your perception and their intention have energy differences, which may be the source of misunderstanding. `;
}
// Analyze relationship between objective truth and guidance
if (objectiveTruth.orientation === futureGuidance.orientation) {
analysis += `The nature of the facts aligns with future guidance, indicating you can trust this direction. `;
}
else {
analysis += `The complexity of the facts requires flexibility and openness in your actions. `;
}
// Overall clarity assessment
analysis += `\n\n**Clarity of Truth:** ${uprightCount} out of 4 lights shine clearly, `;
if (uprightCount === 4) {
analysis += "all dimensions are clear, this is a moment of complete truth where decisive action can be taken.";
}
else if (uprightCount === 3) {
analysis += "most of the truth has been revealed, requiring only patience and understanding in one dimension.";
}
else if (uprightCount === 2) {
analysis += "truth is gradually emerging, requiring balance of information from different dimensions to make judgments.";
}
else if (uprightCount === 1) {
analysis += "currently only one dimension is relatively clear, more time is needed for other truths to surface.";
}
else {
analysis += "all dimensions are still in fog, this is a period requiring great patience and inner calm.";
}
analysis += "\n";
return analysis;
}
/**
* Check if two cards have similar energy
*/
cardsHaveSimilarEnergy(card1, card2) {
// Simple heuristic: same orientation and similar themes
if (card1.orientation !== card2.orientation)
return false;
// Check for similar suits or arcana
if (card1.card.suit && card2.card.suit && card1.card.suit === card2.card.suit)
return true;
if (card1.card.arcana === card2.card.arcana)
return true;
return false;
}
/**
* Generate overall interpretation considering card interactions
*/
generateOverallInterpretation(drawnCards, question) {
let overall = "**Overall Interpretation:**\n\n";
// Analyze the energy of the reading
const uprightCount = drawnCards.filter(c => c.orientation === "upright").length;
const reversedCount = drawnCards.filter(c => c.orientation === "reversed").length;
const majorArcanaCount = drawnCards.filter(c => c.card.arcana === "major").length;
const totalCards = drawnCards.length;
// Major Arcana influence analysis
if (majorArcanaCount > totalCards / 2) {
overall += "This reading is heavily influenced by Major Arcana cards, indicating that significant spiritual forces, life lessons, and karmic influences are at work. The universe is guiding you through important transformations. ";
}
else if (majorArcanaCount === 0) {
overall += "This reading contains only Minor Arcana cards, suggesting that the situation is primarily within your control and relates to everyday matters and practical concerns. ";
}
else {
overall += "The balance of Major and Minor Arcana cards suggests a blend of spiritual guidance and practical action is needed. ";
}
// Orientation analysis
const uprightPercentage = (uprightCount / totalCards) * 100;
if (uprightPercentage >= 80) {
overall += "The predominance of upright cards indicates positive energy, clear direction, and favorable circumstances. You're aligned with the natural flow of events. ";
}
else if (uprightPercentage >= 60) {
overall += "Most cards are upright, suggesting generally positive energy with some areas requiring attention or inner work. ";
}
else if (uprightPercentage >= 40) {
overall += "The balance of upright and reversed cards indicates a mixed situation with both opportunities and challenges present. ";
}
else if (uprightPercentage >= 20) {
overall += "The majority of reversed cards suggests internal blocks, delays, or the need for significant introspection and inner work. ";
}
else {
overall += "The predominance of reversed cards indicates a time of deep inner transformation, spiritual crisis, or significant obstacles that require patience and self-reflection. ";
}
// Add specific guidance based on card combinations and spread type
overall += this.generateAdvancedCombinationInterpretation(drawnCards, question);
return overall;
}
/**
* Generate advanced interpretation for card combinations
*/
generateAdvancedCombinationInterpretation(drawnCards, context) {
let interpretation = "";
// Elemental analysis
const elementCounts = this.analyzeElements(drawnCards);
interpretation += this.interpretElementalBalance(elementCounts);
// Suit analysis for Minor Arcana
const suitAnalysis = this.analyzeSuits(drawnCards);
interpretation += suitAnalysis;
// Numerical patterns
const numericalAnalysis = this.analyzeNumericalPatterns(drawnCards);
interpretation += numericalAnalysis;
// Court card analysis
const courtCardAnalysis = this.analyzeCourtCards(drawnCards);
interpretation += courtCardAnalysis;
// Archetypal patterns in Major Arcana
const archetypeAnalysis = this.analyzeMajorArcanaPatterns(drawnCards);
interpretation += archetypeAnalysis;
interpretation += "\n\nTrust your intuition as you reflect on these insights and how they apply to your specific situation.";
return interpretation;
}
/**
* Analyze elemental balance in the reading
*/
analyzeElements(drawnCards) {
const elementCounts = { fire: 0, water: 0, air: 0, earth: 0 };
drawnCards.forEach(drawnCard => {
if (drawnCard.card.element) {
elementCounts[drawnCard.card.element]++;
}
});
return elementCounts;
}
/**
* Interpret elemental balance
*/
interpretElementalBalance(elementCounts) {
const total = Object.values(elementCounts).reduce((a, b) => a + b, 0);
if (total === 0)
return "";
let interpretation = "";
const dominantElement = Object.entries(elementCounts)
.sort(([, a], [, b]) => b - a)[0];
if (dominantElement[1] > total / 2) {
switch (dominantElement[0]) {
case "fire":
interpretation += "The dominance of Fire energy suggests this is a time for action, creativity, and passionate pursuit of your goals. ";
break;
case "water":
interpretation += "The prevalence of Water energy indicates this situation is deeply emotional and intuitive, requiring you to trust your feelings. ";
break;
case "air":
interpretation += "The abundance of Air energy suggests this is primarily a mental matter requiring clear thinking, communication, and intellectual approach. ";
break;
case "earth":
interpretation += "The strong Earth energy indicates this situation requires practical action, patience, and attention to material concerns. ";
break;
}
}
// Check for missing elements
const missingElements = Object.entries(elementCounts)
.filter(([, count]) => count === 0)
.map(([element]) => element);
if (missingElements.length > 0) {
interpretation += `The absence of ${missingElements.join(" and ")} energy suggests you may need to cultivate these qualities to achieve balance. `;
}
return interpretation;
}
/**
* Analyze suit patterns
*/
analyzeSuits(drawnCards) {
const suits = drawnCards
.filter(c => c.card.suit)
.map(c => c.card.suit);
const suitCounts = suits.reduce((acc, suit) => {
acc[suit] = (acc[suit] || 0) + 1;
return acc;
}, {});
const dominantSuit = Object.entries(suitCounts)
.sort(([, a], [, b]) => b - a)[0];
if (!dominantSuit || dominantSuit[1] <= 1)
return "";
let interpretation = "";
switch (dominantSuit[0]) {
case "wands":
interpretation += "The multiple Wands indicate this situation involves creative projects, career ambitions, and the need for decisive action. ";
break;
case "cups":
interpretation += "The presence of multiple Cups shows this is fundamentally about emotions, relationships, and spiritual matters. ";
break;
case "swords":
interpretation += "The dominance of Swords reveals this situation involves mental challenges, conflicts, and the need for clear communication. ";
break;
case "pentacles":
interpretation += "Multiple Pentacles emphasize material concerns, financial matters, and the need for practical, grounded action. ";
break;
}
return interpretation;
}
/**
* Analyze numerical patterns in the reading
*/
analyzeNumericalPatterns(drawnCards) {
const numbers = drawnCards
.filter(c => c.card.number !== undefined)
.map(c => c.card.number);
if (numbers.length < 2)
return "";
let interpretation = "";
const avgNumber = numbers.reduce((a, b) => a + b, 0) / numbers.length;
// Analyze the journey stage
if (avgNumber <= 3) {
interpretation += "The low-numbered cards indicate this situation is in its beginning stages, full of potential and new energy. ";
}
else if (avgNumber <= 6) {
interpretation += "The mid-range numbers suggest this situation is in its development phase, requiring steady progress and patience. ";
}
else if (avgNumber <= 9) {
interpretation += "The higher numbers indicate this situation is approaching completion or mastery, requiring final efforts. ";
}
else {
interpretation += "The presence of high numbers and court cards suggests mastery, completion, or the involvement of significant people. ";
}
// Look for repeated numbers
const numberCounts = numbers.reduce((acc, num) => {
acc[num] = (acc[num] || 0) + 1;
return acc;
}, {});
const repeatedNumbers = Object.entries(numberCounts)
.filter(([, count]) => count > 1)
.map(([num]) => parseInt(num));
if (repeatedNumbers.length > 0) {
interpretation += `The repetition of ${repeatedNumbers.join(" and ")} emphasizes the themes of `;
repeatedNumbers.forEach(num => {
switch (num) {
case 1:
interpretation += "new beginnings and potential, ";
break;
case 2:
interpretation += "balance and partnerships, ";
break;
case 3:
interpretation += "creativity and growth, ";
break;
case 4:
interpretation += "stability and foundation, ";
break;
case 5:
interpretation += "change and challenge, ";
break;
case 6:
interpretation += "harmony and responsibility, ";
break;
case 7:
interpretation += "spiritual development and introspection, ";
break;
case 8:
interpretation += "material mastery and achievement, ";
break;
case 9:
interpretation += "completion and wisdom, ";
break;
case 10:
interpretation += "fulfillment and new cycles, ";
break;
}
});
interpretation = interpretation.slice(0, -2) + ". ";
}
return interpretation;
}
/**
* Analyze court cards in the reading
*/
analyzeCourtCards(drawnCards) {
const courtCards = drawnCards.filter(c => c.card.name.includes("Page") ||
c.card.name.includes("Knight") ||
c.card.name.includes("Queen") ||
c.card.name.includes("King"));
if (courtCards.length === 0)
return "";
let interpretation = "";
if (courtCards.length === 1) {
interpretation += "The presence of a court card suggests that a specific person or personality aspect is significant to this situation. ";
}
else {
interpretation += `The ${courtCards.length} court cards indicate that multiple people or personality aspects are influencing this situation. `;
}
return interpretation;
}
/**
* Analyze Major Arcana patterns and archetypal themes
*/
analyzeMajorArcanaPatterns(drawnCards) {
const majorCards = drawnCards.filter(c => c.card.arcana === "major");
if (majorCards.length === 0)
return "";
let interpretation = "";
// Analyze the Fool's Journey progression
const majorNumbers = majorCards
.map(c => c.card.number)
.sort((a, b) => a - b);
if (majorNumbers.length > 1) {
const span = majorNumbers[majorNumbers.length - 1] - majorNumbers[0];
if (span > 10) {
interpretation += "The wide span of Major Arcana cards suggests you're experiencing a significant life transformation that touches many aspects of your spiritual journey. ";
}
else if (span < 5) {
interpretation += "The close grouping of Major Arcana cards indicates you're working through a specific phase of spiritual development. ";
}
}
// Look for specific archetypal themes
const cardNames = majorCards.map(c => c.card.name.toLowerCase());
if (cardNames.includes("the fool") && cardNames.includes("the magician")) {
interpretation += "The presence of both The Fool and The Magician suggests a powerful combination of new beginnings and the ability to manifest your desires. ";
}
if (cardNames.includes("the high priestess") && cardNames.includes("the hierophant")) {
interpretation += "The High Priestess and Hierophant together indicate a balance between inner wisdom and traditional teachings. ";
}
return interpretation;
}
/**
* Generate interpretation for card combinations (legacy method for compatibility)
*/
generateCombinationInterpretation(drawnCards, context) {
return this.generateAdvancedCombinationInterpretation(drawnCards, context);
}
/**
* Format a reading for display
*/
formatReading(reading, spreadName, spreadDescription) {
let result = `# ${spreadName} Reading\n\n`;
result += `**Question:** ${reading.question}\n`;
result += `**Date:** ${reading.timestamp.toLocaleString()}\n`;
result += `**Reading ID:** ${reading.id}\n\n`;
result += `*${spreadDescription}*\n\n`;
result += `## Your Cards\n\n`;
readin