UNPKG

coaia-memory

Version:

Creative-Oriented AI Assistant Memory - MCP server with structural tension charts and advancing pattern support, based on principles by Robert Fritz

1,053 lines 52.9 kB
#!/usr/bin/env node
import { Server } from "@modelcontextprotocol/sdk/server/index.js";
import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
import { CallToolRequestSchema, ListToolsRequestSchema, } from "@modelcontextprotocol/sdk/types.js";
import { promises as fs } from 'fs';
import path from 'path';
import { fileURLToPath } from 'url';
import minimist from 'minimist';
import { isAbsolute } from 'path';
// Parse args and handle paths safely
const argv = minimist(process.argv.slice(2));
// Handle help command
if (argv.help || argv.h) {
    console.log(`
🧠 COAIA Memory - Creative-Oriented AI Assistant Memory System v2.1.0
   Based on Robert Fritz's Structural Tension methodology

DESCRIPTION:
   MCP server that extends knowledge graphs with structural tension charts for 
   creative-oriented memory management. Supports advancing patterns, telescoping
   charts, and natural language interaction for AI assistants.

USAGE:
   coaia-memory [OPTIONS]
   npx coaia-memory [OPTIONS]

OPTIONS:
   --memory-path PATH    Custom path for memory storage (default: ./memory.jsonl)
   --help, -h           Show this help message

CORE FEATURES:
   
   📊 Structural Tension Charts
   • Create charts with desired outcomes, current reality, and action steps
   • Automatic due date distribution for strategic timing
   • Progress tracking and completion monitoring
   
   🔭 Telescoping Support  
   • Break down action steps into detailed sub-charts
   • Proper due date inheritance from parent steps
   • Navigate between overview and details seamlessly
   
   📈 Advancing Patterns
   • Completed actions flow into current reality automatically  
   • Success builds momentum for continued advancement
   • Prevents oscillating patterns through structural awareness

MCP TOOLS AVAILABLE:
   
   Chart Management (Common Workflow):
   • list_active_charts            - START HERE: See all charts and their progress
   • add_action_step               - Add strategic actions to existing charts  
   • telescope_action_step         - Break down action steps into detailed sub-charts
   • update_action_progress        - Track progress without completing actions
   • mark_action_complete          - Complete actions & update reality
   • update_current_reality        - Add observations directly to current reality
   • create_structural_tension_chart - Create new chart with outcome & reality
   
   Chart Analysis (Advanced):
   • get_chart_progress            - Detailed progress (redundant after list_active_charts)
   • open_nodes                    - Inspect specific chart components by exact name
   • read_graph                    - Dump all data (rarely needed)
   
   Knowledge Graph (Traditional):
   • create_entities               - Add entities (people, concepts, events)
   • create_relations              - Connect entities with relationships  
   • add_observations              - Record information about entities
   • search_nodes                  - Search across all stored information
   • read_graph                    - Export complete graph structure

EXAMPLE USAGE:

   # Start with custom memory path
   coaia-memory --memory-path /path/to/my-charts.jsonl
   
   # Use in Claude Desktop (add to claude_desktop_config.json):
   {
     "mcpServers": {
       "coaia-memory": {
         "command": "npx", 
         "args": ["-y", "coaia-memory", "--memory-path", "./charts.jsonl"]
       }
     }
   }

NATURAL LANGUAGE PATTERNS:

   Creating Charts:
   "I want to create a mobile app in 3 months"
   "My desired outcome is to establish a morning routine"
   
   Progress Tracking:
   "I completed the research phase yesterday"  
   "Show me progress on my Python learning goal"
   
   Telescoping:
   "Break down the Django tutorial step further"
   "I need more detail on the deployment action"

CREATIVE ORIENTATION PRINCIPLES:

   ✅ Focus on Creation (not problem-solving):
      • "I want to create..." vs "I need to fix..."
      • "My desired outcome..." vs "The problem is..."
   
   ✅ Structural Tension Awareness:
      • Always pair desired outcomes with current reality
      • Honest assessment creates productive tension
      • Action steps are strategic secondary action we choose todo to achive the primary goal
   
   ✅ Advancing Patterns:
      • Success builds on success
      • Completed actions become part of current reality
      • Momentum creates natural progression toward goals

PHILOSOPHY:
   COAIA Memory recognizes that structure determines behavior. By organizing
   memory around structural tension rather than problem-solving patterns, it
   naturally forms a structure that advances and helps build, not just the life you want, but the technologies to supports it's manifestation (hopefully!).

CREDITS:
   • Author: J.Guillaume D.-Isabelle <jgi@jgwill.com>
   • Methodology: Robert Fritz - https://robertfritz.com
   • Foundation: Shane Holloman (original mcp-knowledge-graph)
   • License: MIT

For more information, see: CLAUDE.md in the package directory
`);
    process.exit(0);
}
let memoryPath = argv['memory-path'];
// If a custom path is provided, ensure it's absolute
if (memoryPath && !isAbsolute(memoryPath)) {
    memoryPath = path.resolve(process.cwd(), memoryPath);
}
// Define the path to the JSONL file
const __dirname = path.dirname(fileURLToPath(import.meta.url));
// Use the custom path or default to the installation directory
const MEMORY_FILE_PATH = memoryPath || path.join(__dirname, 'memory.jsonl');
// The KnowledgeGraphManager class contains all operations to interact with the knowledge graph
class KnowledgeGraphManager {
    async loadGraph() {
        try {
            const data = await fs.readFile(MEMORY_FILE_PATH, "utf-8");
            const lines = data.split("\n").filter(line => line.trim() !== "");
            return lines.reduce((graph, line) => {
                const item = JSON.parse(line);
                if (item.type === "entity")
                    graph.entities.push(item);
                if (item.type === "relation")
                    graph.relations.push(item);
                return graph;
            }, { entities: [], relations: [] });
        }
        catch (error) {
            if (error instanceof Error && 'code' in error && error.code === "ENOENT") {
                return { entities: [], relations: [] };
            }
            throw error;
        }
    }
    async saveGraph(graph) {
        const lines = [
            ...graph.entities.map(e => JSON.stringify({ type: "entity", ...e })),
            ...graph.relations.map(r => JSON.stringify({ type: "relation", ...r })),
        ];
        await fs.writeFile(MEMORY_FILE_PATH, lines.join("\n"));
    }
    async createEntities(entities) {
        const graph = await this.loadGraph();
        const newEntities = entities.filter(e => !graph.entities.some(existingEntity => existingEntity.name === e.name));
        graph.entities.push(...newEntities);
        await this.saveGraph(graph);
        return newEntities;
    }
    async createRelations(relations) {
        const graph = await this.loadGraph();
        const newRelations = relations.filter(r => !graph.relations.some(existingRelation => existingRelation.from === r.from &&
            existingRelation.to === r.to &&
            existingRelation.relationType === r.relationType));
        graph.relations.push(...newRelations);
        await this.saveGraph(graph);
        return newRelations;
    }
    async addObservations(observations) {
        const graph = await this.loadGraph();
        const results = observations.map(o => {
            const entity = graph.entities.find(e => e.name === o.entityName);
            if (!entity) {
                throw new Error(`Entity with name ${o.entityName} not found`);
            }
            const newObservations = o.contents.filter(content => !entity.observations.includes(content));
            entity.observations.push(...newObservations);
            return { entityName: o.entityName, addedObservations: newObservations };
        });
        await this.saveGraph(graph);
        return results;
    }
    async deleteEntities(entityNames) {
        const graph = await this.loadGraph();
        graph.entities = graph.entities.filter(e => !entityNames.includes(e.name));
        graph.relations = graph.relations.filter(r => !entityNames.includes(r.from) && !entityNames.includes(r.to));
        await this.saveGraph(graph);
    }
    async deleteObservations(deletions) {
        const graph = await this.loadGraph();
        deletions.forEach(d => {
            const entity = graph.entities.find(e => e.name === d.entityName);
            if (entity) {
                entity.observations = entity.observations.filter(o => !d.observations.includes(o));
            }
        });
        await this.saveGraph(graph);
    }
    async deleteRelations(relations) {
        const graph = await this.loadGraph();
        graph.relations = graph.relations.filter(r => !relations.some(delRelation => r.from === delRelation.from &&
            r.to === delRelation.to &&
            r.relationType === delRelation.relationType));
        await this.saveGraph(graph);
    }
    async readGraph() {
        return this.loadGraph();
    }
    // Very basic search function
    async searchNodes(query) {
        const graph = await this.loadGraph();
        // Filter entities
        const filteredEntities = graph.entities.filter(e => e.name.toLowerCase().includes(query.toLowerCase()) ||
            e.entityType.toLowerCase().includes(query.toLowerCase()) ||
            e.observations.some(o => o.toLowerCase().includes(query.toLowerCase())));
        // Create a Set of filtered entity names for quick lookup
        const filteredEntityNames = new Set(filteredEntities.map(e => e.name));
        // Filter relations to only include those between filtered entities
        const filteredRelations = graph.relations.filter(r => filteredEntityNames.has(r.from) && filteredEntityNames.has(r.to));
        const filteredGraph = {
            entities: filteredEntities,
            relations: filteredRelations,
        };
        return filteredGraph;
    }
    async openNodes(names) {
        const graph = await this.loadGraph();
        // Filter entities
        const filteredEntities = graph.entities.filter(e => names.includes(e.name));
        // Create a Set of filtered entity names for quick lookup
        const filteredEntityNames = new Set(filteredEntities.map(e => e.name));
        // Filter relations to only include those between filtered entities
        const filteredRelations = graph.relations.filter(r => filteredEntityNames.has(r.from) && filteredEntityNames.has(r.to));
        const filteredGraph = {
            entities: filteredEntities,
            relations: filteredRelations,
        };
        return filteredGraph;
    }
    // COAIA-specific methods for structural tension charts and creative processes
    async createStructuralTensionChart(desiredOutcome, currentReality, dueDate, actionSteps) {
        const chartId = `chart_${Date.now()}`;
        const timestamp = new Date().toISOString();
        // Create chart, desired outcome, and current reality entities
        const entities = [
            {
                name: `${chartId}_chart`,
                entityType: 'structural_tension_chart',
                observations: [`Chart created on ${timestamp}`],
                metadata: {
                    chartId,
                    dueDate,
                    level: 0,
                    createdAt: timestamp,
                    updatedAt: timestamp
                }
            },
            {
                name: `${chartId}_desired_outcome`,
                entityType: 'desired_outcome',
                observations: [desiredOutcome],
                metadata: {
                    chartId,
                    dueDate,
                    createdAt: timestamp,
                    updatedAt: timestamp
                }
            },
            {
                name: `${chartId}_current_reality`,
                entityType: 'current_reality',
                observations: [currentReality],
                metadata: {
                    chartId,
                    createdAt: timestamp,
                    updatedAt: timestamp
                }
            }
        ];
        // Add action steps if provided
        if (actionSteps && actionSteps.length > 0) {
            const stepDueDates = this.distributeActionStepDates(new Date(), new Date(dueDate), actionSteps.length);
            actionSteps.forEach((step, index) => {
                entities.push({
                    name: `${chartId}_action_${index + 1}`,
                    entityType: 'action_step',
                    observations: [step],
                    metadata: {
                        chartId,
                        dueDate: stepDueDates[index].toISOString(),
                        completionStatus: false,
                        createdAt: timestamp,
                        updatedAt: timestamp
                    }
                });
            });
        }
        // Create relations
        const relations = [
            {
                from: `${chartId}_chart`,
                to: `${chartId}_desired_outcome`,
                relationType: 'contains',
                metadata: { createdAt: timestamp }
            },
            {
                from: `${chartId}_chart`,
                to: `${chartId}_current_reality`,
                relationType: 'contains',
                metadata: { createdAt: timestamp }
            },
            {
                from: `${chartId}_current_reality`,
                to: `${chartId}_desired_outcome`,
                relationType: 'creates_tension_with',
                metadata: { createdAt: timestamp }
            }
        ];
        // Add action step relations
        if (actionSteps && actionSteps.length > 0) {
            actionSteps.forEach((_, index) => {
                const actionName = `${chartId}_action_${index + 1}`;
                relations.push({
                    from: `${chartId}_chart`,
                    to: actionName,
                    relationType: 'contains',
                    metadata: { createdAt: timestamp }
                }, {
                    from: actionName,
                    to: `${chartId}_desired_outcome`,
                    relationType: 'advances_toward',
                    metadata: { createdAt: timestamp }
                });
            });
        }
        // Save to graph
        await this.createEntities(entities);
        await this.createRelations(relations);
        return { chartId, entities, relations };
    }
    async telescopeActionStep(actionStepName, newCurrentReality, initialActionSteps) {
        const graph = await this.loadGraph();
        const actionStep = graph.entities.find(e => e.name === actionStepName && e.entityType === 'action_step');
        if (!actionStep || !actionStep.metadata?.chartId) {
            throw new Error(`Action step ${actionStepName} not found or not properly configured`);
        }
        const parentChartId = actionStep.metadata.chartId;
        const inheritedDueDate = actionStep.metadata.dueDate || new Date(Date.now() + 7 * 24 * 60 * 60 * 1000).toISOString();
        const desiredOutcome = actionStep.observations[0]; // Use the action step description as the new desired outcome
        const result = await this.createStructuralTensionChart(desiredOutcome, newCurrentReality, inheritedDueDate, initialActionSteps);
        // Update the new chart's metadata to reflect telescoping relationship
        const newChart = await this.loadGraph();
        const chartEntity = newChart.entities.find(e => e.name === `${result.chartId}_chart`);
        if (chartEntity && chartEntity.metadata) {
            chartEntity.metadata.parentChart = parentChartId;
            chartEntity.metadata.parentActionStep = actionStepName;
            chartEntity.metadata.level = (actionStep.metadata.level || 0) + 1;
            chartEntity.metadata.updatedAt = new Date().toISOString();
        }
        await this.saveGraph(newChart);
        return { chartId: result.chartId, parentChart: parentChartId };
    }
    async markActionStepComplete(actionStepName) {
        const graph = await this.loadGraph();
        const actionStep = graph.entities.find(e => e.name === actionStepName && e.entityType === 'action_step');
        if (!actionStep) {
            throw new Error(`Action step ${actionStepName} not found`);
        }
        // Mark as complete
        if (actionStep.metadata) {
            actionStep.metadata.completionStatus = true;
            actionStep.metadata.updatedAt = new Date().toISOString();
        }
        // Structural tension principle: completed action steps flow into current reality,
        // changing the structural dynamic and advancing the system toward equilibrium
        if (actionStep.metadata?.chartId) {
            const currentReality = graph.entities.find(e => e.name === `${actionStep.metadata.chartId}_current_reality` &&
                e.entityType === 'current_reality');
            if (currentReality) {
                // The completed action step becomes part of current reality, 
                // creating new structural tension for continued advancement
                currentReality.observations.push(`Completed: ${actionStep.observations[0]}`);
                if (currentReality.metadata) {
                    currentReality.metadata.updatedAt = new Date().toISOString();
                }
            }
        }
        await this.saveGraph(graph);
    }
    async getChartProgress(chartId) {
        const graph = await this.loadGraph();
        const actionSteps = graph.entities.filter(e => e.entityType === 'action_step' &&
            e.metadata?.chartId === chartId);
        const completedActions = actionSteps.filter(e => e.metadata?.completionStatus === true).length;
        const totalActions = actionSteps.length;
        const progress = totalActions > 0 ? completedActions / totalActions : 0;
        // Find next incomplete action step with earliest due date
        const incompleteActions = actionSteps
            .filter(e => e.metadata?.completionStatus !== true)
            .sort((a, b) => {
            const dateA = new Date(a.metadata?.dueDate || '').getTime();
            const dateB = new Date(b.metadata?.dueDate || '').getTime();
            return dateA - dateB;
        });
        const chart = graph.entities.find(e => e.name === `${chartId}_chart`);
        return {
            chartId,
            progress,
            completedActions,
            totalActions,
            nextAction: incompleteActions[0]?.name,
            dueDate: chart?.metadata?.dueDate
        };
    }
    distributeActionStepDates(startDate, endDate, stepCount) {
        const totalTime = endDate.getTime() - startDate.getTime();
        const stepInterval = totalTime / (stepCount + 1); // +1 to leave space before final due date
        const dates = [];
        for (let i = 1; i <= stepCount; i++) {
            dates.push(new Date(startDate.getTime() + (stepInterval * i)));
        }
        return dates;
    }
    async listActiveCharts() {
        const graph = await this.loadGraph();
        const charts = graph.entities.filter(e => e.entityType === 'structural_tension_chart');
        const chartSummaries = await Promise.all(charts.map(async (chart) => {
            const chartId = chart.metadata?.chartId || chart.name.replace('_chart', '');
            const progress = await this.getChartProgress(chartId);
            // Get desired outcome
            const desiredOutcome = graph.entities.find(e => e.name === `${chartId}_desired_outcome` && e.entityType === 'desired_outcome');
            return {
                chartId,
                desiredOutcome: desiredOutcome?.observations[0] || 'Unknown outcome',
                dueDate: chart.metadata?.dueDate,
                progress: progress.progress,
                completedActions: progress.completedActions,
                totalActions: progress.totalActions,
                level: chart.metadata?.level || 0,
                parentChart: chart.metadata?.parentChart
            };
        }));
        return chartSummaries.sort((a, b) => {
            // Sort by level first (master charts first), then by due date
            if (a.level !== b.level)
                return a.level - b.level;
            const dateA = new Date(a.dueDate || '').getTime();
            const dateB = new Date(b.dueDate || '').getTime();
            return dateA - dateB;
        });
    }
    async updateActionProgress(actionStepName, progressObservation, updateCurrentReality) {
        const graph = await this.loadGraph();
        const actionStep = graph.entities.find(e => e.name === actionStepName && e.entityType === 'action_step');
        if (!actionStep) {
            throw new Error(`Action step ${actionStepName} not found`);
        }
        // Add progress observation to action step
        actionStep.observations.push(progressObservation);
        if (actionStep.metadata) {
            actionStep.metadata.updatedAt = new Date().toISOString();
        }
        // Optionally update current reality with progress
        if (updateCurrentReality && actionStep.metadata?.chartId) {
            const currentReality = graph.entities.find(e => e.name === `${actionStep.metadata.chartId}_current_reality` &&
                e.entityType === 'current_reality');
            if (currentReality) {
                // Progress observations flow into current reality, changing the structural dynamic
                currentReality.observations.push(`Progress on ${actionStep.observations[0]}: ${progressObservation}`);
                if (currentReality.metadata) {
                    currentReality.metadata.updatedAt = new Date().toISOString();
                }
            }
        }
        await this.saveGraph(graph);
    }
    async updateCurrentReality(chartId, newObservations) {
        const graph = await this.loadGraph();
        const currentReality = graph.entities.find(e => e.name === `${chartId}_current_reality` &&
            e.entityType === 'current_reality');
        if (!currentReality) {
            throw new Error(`Chart ${chartId} not found or missing current reality`);
        }
        // Add new observations to current reality
        const uniqueObservations = newObservations.filter(obs => !currentReality.observations.includes(obs));
        currentReality.observations.push(...uniqueObservations);
        if (currentReality.metadata) {
            currentReality.metadata.updatedAt = new Date().toISOString();
        }
        await this.saveGraph(graph);
    }
    async updateDesiredOutcome(chartId, newDesiredOutcome) {
        const graph = await this.loadGraph();
        const desiredOutcomeEntity = graph.entities.find(e => e.name === `${chartId}_desired_outcome` && e.entityType === 'desired_outcome');
        if (!desiredOutcomeEntity) {
            throw new Error(`Chart ${chartId} desired outcome not found`);
        }
        // Replace the first observation (which is the desired outcome text)
        desiredOutcomeEntity.observations[0] = newDesiredOutcome;
        if (desiredOutcomeEntity.metadata) {
            desiredOutcomeEntity.metadata.updatedAt = new Date().toISOString();
        }
        await this.saveGraph(graph);
    }
    async updateActionStepTitle(actionStepName, newTitle) {
        const graph = await this.loadGraph();
        const actionStepEntity = graph.entities.find(e => e.name === actionStepName);
        if (!actionStepEntity) {
            throw new Error(`Action step ${actionStepName} not found`);
        }
        // Replace the first observation (which is the action step title)
        actionStepEntity.observations[0] = newTitle;
        if (actionStepEntity.metadata) {
            actionStepEntity.metadata.updatedAt = new Date().toISOString();
        }
        await this.saveGraph(graph);
    }
    async addActionStep(parentChartId, actionStepTitle, dueDate, currentReality) {
        const graph = await this.loadGraph();
        const parentChart = graph.entities.find(e => e.entityType === 'structural_tension_chart' && e.metadata?.chartId === parentChartId);
        if (!parentChart) {
            throw new Error(`Parent chart ${parentChartId} not found`);
        }
        // Get parent chart's due date for auto-distribution
        const parentDueDate = parentChart.metadata?.dueDate;
        if (!parentDueDate) {
            throw new Error(`Parent chart ${parentChartId} has no due date`);
        }
        // Calculate due date for action step if not provided
        let actionStepDueDate = dueDate;
        if (!actionStepDueDate) {
            // Distribute between now and parent due date (simple midpoint for now)
            const now = new Date();
            const parentEnd = new Date(parentDueDate);
            const midpoint = new Date(now.getTime() + (parentEnd.getTime() - now.getTime()) / 2);
            actionStepDueDate = midpoint.toISOString();
        }
        // Set default current reality if not provided
        const actionCurrentReality = currentReality || `Ready to begin: ${actionStepTitle}`;
        // Create telescoped structural tension chart
        const telescopedChart = await this.createStructuralTensionChart(actionStepTitle, actionCurrentReality, actionStepDueDate);
        // Update the telescoped chart's metadata to show parent relationship
        const updatedGraph = await this.loadGraph();
        const telescopedChartEntity = updatedGraph.entities.find(e => e.name === `${telescopedChart.chartId}_chart`);
        if (telescopedChartEntity && telescopedChartEntity.metadata) {
            telescopedChartEntity.metadata.parentChart = parentChartId;
            telescopedChartEntity.metadata.level = (parentChart.metadata?.level || 0) + 1;
            telescopedChartEntity.metadata.updatedAt = new Date().toISOString();
        }
        // Create relationship: telescoped chart advances toward parent's desired outcome
        const parentDesiredOutcome = updatedGraph.entities.find(e => e.name === `${parentChartId}_desired_outcome` && e.entityType === 'desired_outcome');
        if (parentDesiredOutcome) {
            const timestamp = new Date().toISOString();
            await this.createRelations([{
                    from: `${telescopedChart.chartId}_desired_outcome`,
                    to: parentDesiredOutcome.name,
                    relationType: 'advances_toward',
                    metadata: { createdAt: timestamp }
                }]);
        }
        await this.saveGraph(updatedGraph);
        return {
            chartId: telescopedChart.chartId,
            actionStepName: `${telescopedChart.chartId}_desired_outcome`
        };
    }
    async removeActionStep(parentChartId, actionStepName) {
        const graph = await this.loadGraph();
        // Find the action step (which is actually a telescoped chart's desired outcome)
        const actionStepEntity = graph.entities.find(e => e.name === actionStepName);
        if (!actionStepEntity || !actionStepEntity.metadata?.chartId) {
            throw new Error(`Action step ${actionStepName} not found`);
        }
        const telescopedChartId = actionStepEntity.metadata.chartId;
        // Verify it belongs to the parent chart
        const telescopedChart = graph.entities.find(e => e.entityType === 'structural_tension_chart' &&
            e.metadata?.chartId === telescopedChartId &&
            e.metadata?.parentChart === parentChartId);
        if (!telescopedChart) {
            throw new Error(`Action step ${actionStepName} does not belong to chart ${parentChartId}`);
        }
        // Remove all entities belonging to the telescoped chart
        const entitiesToRemove = graph.entities
            .filter(e => e.metadata?.chartId === telescopedChartId)
            .map(e => e.name);
        await this.deleteEntities(entitiesToRemove);
    }
}
const knowledgeGraphManager = new KnowledgeGraphManager();
// The server instance and tools exposed to AI models
const server = new Server({
    name: "coaia-memory",
    version: "2.1.0",
}, {
    capabilities: {
        tools: {},
    },
});
server.setRequestHandler(ListToolsRequestSchema, async () => {
    return {
        tools: [
            {
                name: "create_entities",
                description: "ADVANCED: Create traditional knowledge graph entities. For structural tension charts, use create_structural_tension_chart or add_action_step instead.",
                inputSchema: {
                    type: "object",
                    properties: {
                        entities: {
                            type: "array",
                            items: {
                                type: "object",
                                properties: {
                                    name: { type: "string", description: "The name of the entity" },
                                    entityType: { type: "string", description: "The type of the entity" },
                                    observations: {
                                        type: "array",
                                        items: { type: "string" },
                                        description: "An array of observation contents associated with the entity"
                                    },
                                },
                                required: ["name", "entityType", "observations"],
                            },
                        },
                    },
                    required: ["entities"],
                },
            },
            {
                name: "create_relations",
                description: "Create multiple new relations between entities in the knowledge graph. Relations should be in active voice",
                inputSchema: {
                    type: "object",
                    properties: {
                        relations: {
                            type: "array",
                            items: {
                                type: "object",
                                properties: {
                                    from: { type: "string", description: "The name of the entity where the relation starts" },
                                    to: { type: "string", description: "The name of the entity where the relation ends" },
                                    relationType: { type: "string", description: "The type of the relation" },
                                },
                                required: ["from", "to", "relationType"],
                            },
                        },
                    },
                    required: ["relations"],
                },
            },
            {
                name: "add_observations",
                description: "ADVANCED: Add observations to traditional knowledge graph entities. For structural tension charts, use update_current_reality instead.",
                inputSchema: {
                    type: "object",
                    properties: {
                        observations: {
                            type: "array",
                            items: {
                                type: "object",
                                properties: {
                                    entityName: { type: "string", description: "The name of the entity to add the observations to" },
                                    contents: {
                                        type: "array",
                                        items: { type: "string" },
                                        description: "An array of observation contents to add"
                                    },
                                },
                                required: ["entityName", "contents"],
                            },
                        },
                    },
                    required: ["observations"],
                },
            },
            {
                name: "delete_entities",
                description: "Delete multiple entities and their associated relations from the knowledge graph",
                inputSchema: {
                    type: "object",
                    properties: {
                        entityNames: {
                            type: "array",
                            items: { type: "string" },
                            description: "An array of entity names to delete"
                        },
                    },
                    required: ["entityNames"],
                },
            },
            {
                name: "delete_observations",
                description: "Delete specific observations from entities in the knowledge graph",
                inputSchema: {
                    type: "object",
                    properties: {
                        deletions: {
                            type: "array",
                            items: {
                                type: "object",
                                properties: {
                                    entityName: { type: "string", description: "The name of the entity containing the observations" },
                                    observations: {
                                        type: "array",
                                        items: { type: "string" },
                                        description: "An array of observations to delete"
                                    },
                                },
                                required: ["entityName", "observations"],
                            },
                        },
                    },
                    required: ["deletions"],
                },
            },
            {
                name: "delete_relations",
                description: "Delete multiple relations from the knowledge graph",
                inputSchema: {
                    type: "object",
                    properties: {
                        relations: {
                            type: "array",
                            items: {
                                type: "object",
                                properties: {
                                    from: { type: "string", description: "The name of the entity where the relation starts" },
                                    to: { type: "string", description: "The name of the entity where the relation ends" },
                                    relationType: { type: "string", description: "The type of the relation" },
                                },
                                required: ["from", "to", "relationType"],
                            },
                            description: "An array of relations to delete"
                        },
                    },
                    required: ["relations"],
                },
            },
            {
                name: "read_graph",
                description: "RARELY USED: Dumps entire knowledge graph (all entities and relations). Only use for debugging or when you need to see ALL data. For chart work, use list_active_charts instead.",
                inputSchema: {
                    type: "object",
                    properties: {},
                },
            },
            {
                name: "search_nodes",
                description: "Search for nodes in the knowledge graph based on a query",
                inputSchema: {
                    type: "object",
                    properties: {
                        query: { type: "string", description: "The search query to match against entity names, types, and observation content" },
                    },
                    required: ["query"],
                },
            },
            {
                name: "open_nodes",
                description: "ADVANCED: Open specific entity nodes by exact name (e.g. 'chart_123_current_reality'). Only use if you need to inspect specific chart components. NOT for general chart viewing - use list_active_charts instead.",
                inputSchema: {
                    type: "object",
                    properties: {
                        names: {
                            type: "array",
                            items: { type: "string" },
                            description: "An array of exact entity names to retrieve (e.g. 'chart_123_desired_outcome')",
                        },
                    },
                    required: ["names"],
                },
            },
            {
                name: "create_structural_tension_chart",
                description: "Create a new structural tension chart with desired outcome, current reality, and optional action steps",
                inputSchema: {
                    type: "object",
                    properties: {
                        desiredOutcome: { type: "string", description: "What you want to create or achieve" },
                        currentReality: { type: "string", description: "Your current situation in relation to the desired outcome" },
                        dueDate: { type: "string", description: "When you want to achieve this outcome (ISO date string)" },
                        actionSteps: {
                            type: "array",
                            items: { type: "string" },
                            description: "Optional list of action steps needed to achieve the outcome",
                            optional: true
                        }
                    },
                    required: ["desiredOutcome", "currentReality", "dueDate"]
                }
            },
            {
                name: "telescope_action_step",
                description: "Break down an action step into a detailed structural tension chart with optional initial action steps",
                inputSchema: {
                    type: "object",
                    properties: {
                        actionStepName: { type: "string", description: "Name of the action step to telescope" },
                        newCurrentReality: { type: "string", description: "Current reality specific to this action step" },
                        initialActionSteps: {
                            type: "array",
                            items: { type: "string" },
                            description: "Optional list of initial action steps for the telescoped chart",
                            optional: true
                        }
                    },
                    required: ["actionStepName", "newCurrentReality"]
                }
            },
            {
                name: "mark_action_complete",
                description: "Mark an action step as completed and update current reality",
                inputSchema: {
                    type: "object",
                    properties: {
                        actionStepName: { type: "string", description: "Name of the completed action step" }
                    },
                    required: ["actionStepName"]
                }
            },
            {
                name: "get_chart_progress",
                description: "Get detailed progress for a specific chart (redundant if you just used list_active_charts which shows progress). Only use if you need the nextAction details.",
                inputSchema: {
                    type: "object",
                    properties: {
                        chartId: { type: "string", description: "ID of the chart to check progress for" }
                    },
                    required: ["chartId"]
                }
            },
            {
                name: "list_active_charts",
                description: "List all active structural tension charts with their progress. Use this FIRST to see all charts and their IDs. This shows chart overview with progress - you don't need other tools after this for basic chart information.",
                inputSchema: {
                    type: "object",
                    properties: {}
                }
            },
            {
                name: "update_action_progress",
                description: "Update progress on an action step without marking it complete, optionally updating current reality",
                inputSchema: {
                    type: "object",
                    properties: {
                        actionStepName: { type: "string", description: "Name of the action step to update progress for" },
                        progressObservation: { type: "string", description: "Description of progress made on this action step" },
                        updateCurrentReality: {
                            type: "boolean",
                            description: "Whether to also add this progress to current reality (optional, defaults to false)",
                            optional: true
                        }
                    },
                    required: ["actionStepName", "progressObservation"]
                }
            },
            {
                name: "update_current_reality",
                description: "FOR STRUCTURAL TENSION CHARTS: Add observations to current reality. DO NOT use add_observations or create_entities for chart work - use this instead.",
                inputSchema: {
                    type: "object",
                    properties: {
                        chartId: { type: "string", description: "ID of the chart to update current reality for" },
                        newObservations: {
                            type: "array",
                            items: { type: "string" },
                            description: "Array of new observations to add to current reality"
                        }
                    },
                    required: ["chartId", "newObservations"]
                }
            },
            {
                name: "add_action_step",
                description: "Add a strategic action step to an existing structural tension chart (creates telescoped chart)",
                inputSchema: {
                    type: "object",
                    properties: {
                        parentChartId: { type: "string", description: "ID of the parent chart to add the action step to" },
                        actionStepTitle: { type: "string", description: "Title of the action step (becomes desired outcome of telescoped chart)" },
                        dueDate: {
                            type: "string",
                            description: "Optional due date for the action step (ISO string). If not provided, auto-distributed between now and parent due date",
                            optional: true
                        },
                        currentReality: {
                            type: "string",
                            description: "Optional current reality specific to this action step. If not provided, defaults to 'Ready to begin: [title]'",
                            optional: true
                        }
                    },
                    required: ["parentChartId", "actionStepTitle"]
                }
            },
            {
                name: "remove_action_step",
                description: "Remove an action step from a structural tension chart (deletes telescoped chart)",
                inputSchema: {
                    type: "object",
                    properties: {
                        parentChartId: { type: "string", description: "ID of the parent chart containing the action step" },
                        actionStepName: { type: "string", description: "Name of the action step to remove (telescoped chart's desired outcome name)" }
                    },
                    required: ["parentChartId", "actionStepName"]
                }
            },
            {
                name: "update_desired_outcome",
                description: "Simple update of a chart's desired outcome (goal). Much easier than complex observation editing.",
                inputSchema: {
                    type: "object",
                    properties: {
                        chartId: { type: "string", description: "ID of the chart to update" },
                        newDesiredOutcome: { type: "string", description: "New desired outcome text" }
                    },
                    required: ["chartId", "newDesiredOutcome"]
                }
            },
            {
                name: "update_action_step_title",
                description: "Simple update of an action step's title. Much easier than complex observation editing.",
                inputSchema: {
                    type: "object",
                    properties: {
                        actionStepName: { type: "string", description: "Name of the action step entity to update (e.g. 'chart_123_desired_outcome')" },
                        newTitle: { type: "string", description: "New action step title" }
                    },
                    required: ["actionStepName", "newTitle"]
                }
            }
        ],
    };
});
server.setRequestHandler(CallToolRequestSchema, async (request) => {
    const { name, arguments: args } = request.params;
    if (!args) {
        throw new Error(`No arguments provided for tool: ${name}`);
    }
    switch (name) {
        case "create_entities":
            return { content: [{ type: "text", text: JSON.stringify(await knowledgeGraphManager.createEntities(args.entities), null, 2) }] };
        case "create_relations":
            return { content: [{ type: "text", text: JSON.stringify(await knowledgeGraphManager.createRelations(args.relations), null, 2) }] };
        case "add_observations":
            return { content: [{ type: "text", text: JSON.stringify(await knowledgeGraphManager.addObservations(args.observations), null, 2) }] };
        case "delete_entities":
            await knowledgeGraphManager.deleteEntities(args.entityNames);
            return { content: [{ type: "text", text: "Entities deleted successfully" }] };
        case "delete_observations":
            await knowledgeGraphManager.deleteObservations(args.deletions);
            return { content: [{ type: "text", text: "Observations deleted successfully" }] };
        case "delete_relations":
            await knowledgeGraphManager.deleteRelations(args.relations);
            return { content: [{ type: "text", text: "Relations deleted successfully" }] };
        case "read_graph":
            return { content: [{ type: "text", text: JSON.stringify(await knowledgeGraphManager.readGraph(), null, 2) }] };
        case "search_nodes":
            return { content: [{ type: "text", text: JSON.stringify(await knowledgeGraphManager.searchNodes(args.query), null, 2) }] };
        case "open_nodes":
            return { content: [{ type: "text", text: JSON.stringify(await knowledgeGraphManager.openNodes(args.names), null, 2) }] };
        case "create_structural_tension_chart":
            const chartResult = await knowledgeGraphManager.createStructuralTensionChart(args.desiredOutcome, args.currentReality, args.dueDate, args.actionSteps);
            return { content: [{ type: "text", text: JSON.stringify(chartResult, null, 2) }] };
        case "telescope_action_step":
            const telescopeResult = await knowledgeGraphManager.telescopeActionStep(args.actionStepName, args.newCurrentReality, args.initialActionSteps);
            return { content: [{ type: "text", text: JSON.stringify(telescopeResult, null, 2) }] };
        case "mark_action_complete":
            await knowledgeGraphManager.markActionStepComplete(args.actionStepName);
            return { content: [{ type: "text", text: `Action step '${args.actionStepName}' marked as complete and current reality updated` }] };
        case "get_chart_progress":
            const progressResult = await knowledgeGraphManager.getChartProgress(args.chartId);
            return { content: [{ type: "text", text: JSON.stringify(progressResult, null, 2) }] };
        case "list_active_charts":
            const chartsResult = await knowledgeGraphManager.listActiveCharts();
            // Format as hierarchical ASCII tree
            let hierarchyText = "## Structural Tension Charts Hierarchy\n\n";
            // Group by master charts (level 0)
            const masterCharts = chartsResult.filter(c => c.level === 0);
            const actionCharts = chartsResult.filter(c => c.level > 0);
            masterCharts.forEach(master => {
                const progress = master.progress > 0 ? ` (${Math.round(master.progress * 100)}% complete)` : "";
                const dueDate = master.dueDate ? ` [Due: ${new Date(master.dueDate).toLocaleDateString()}]` : "";
                hierarchyText += `📋 **${master.desiredOutcome}** (Master Chart)${progress}${dueDate}\n`;
                hierarchyText += `    ID: ${master.chartId}\n`;
                // Find action steps for this master chart
                const actions = actionCharts.filter(a => a.parentChart === master.chartId);
                if (actions.length > 0) {
                    actions.forEach((action, index) => {
                        const isLast = index === actions.length - 1;
                        const connector = isLast ? "└── " : "├── ";
                        const actionProgress = action.progress > 0 ? ` (${Math.round(action.progress * 100)}%)` : "";
                        const actionDue = action.dueDate ? ` [${new Date(action.dueDate).toLocaleDateString()}]` : "";
                        hierarchyText += `    ${connector}🎯 ${action.desiredOutcome} (Action Step)${actionProgress}${actionDue}\n`;
                        hierarchyText += `        ID: ${action.chartId}\n`;
                    });
                }
                else {
                    hierarchyText += `    └── (No action steps yet)\n`;
                }
                hierarchyText += "\n";
            });
            if (masterCharts.length === 0) {
                hierarchyText += "No active structural tension charts found.\n\n";
                hierarchyText += "💡 Create your first chart with: create_structural_tension_chart\n";
            }
            return { content: [{ type: "text", text: hierarchyText }] };
        case "update_action_progress":
            await knowledgeGraphManager.updateActionProgress(args.actionStepName, args.progressObservation, args.updateCurrentReality);
            return { content: [{ type: "text", text: `Action step '${args.actionStepName}' progress updated` }] };
        case "update_current_reality":
            await knowledgeGraphManager.updateCurrentReality(args.chartId, args.newObservations);
            return { content: [{ type: "text", text: `Current reality updated for chart '${args.chartId}'` }] };
        case "add_action_step":
            const addActionResult = await knowledgeGraphManager.addActionStep(args.parentChartId, args.actionStepTitle, args.dueDate, args.currentReality);
            return { content: [{ type: "text", text: `Action step '${args.actionStepTitle}' added to chart '${args.parentChartId}' as telescoped chart '${addActionResult.chartId}'` }] };
        case "remove_action_step":
            await knowledgeGraphManager.removeActionStep(args.parentChartId, args.actionStepName);
            return { content: [{ type: "text", text: `Action step '${args.actionStepName}' removed from chart '${args.parentChartId}'` }] };
        case "update_desired_outcome":
            await knowledgeGraphManager.updateDesiredOutcome(args.chartId, args.newDesiredOutcome);
            return { content: [{ type: "text", text: `Desired outcome updated for chart '${args.chartId}'` }] };
        case "update_action_step_title":
            await knowledgeGraphManager.updateActionStepTitle(args.actionStepName, args.newTitle);
            return { content: [{ type: "text", text: `Action step title updated for '${args.actionStepName}'` }] };
        default:
            throw new Error(`Unknown tool: ${name}`);
    }
});
async function main() {
    const transport = new StdioServerTransport();
    await server.connect(transport);
    console.error("COAIA Memory - Creative Oriented AI Assistant Memory Server running on stdio");
}
main().catch((error) => {
    console.error("Fatal error in main():", error);
    process.exit(1);
});
//# sourceMappingURL=index.js.map