#
tokens: 30478/50000 1/128 files (page 9/9)
lines: off (toggle) GitHub
raw markdown copy
This is page 9 of 9. Use http://codebase.md/tejpalvirk/contextmanager?page={x} to view the full context.

# Directory Structure

```
├── .gitattributes
├── .gitignore
├── build-all-domains.sh
├── developer
│   ├── .gitattributes
│   ├── developer_advancedcontext.txt
│   ├── developer_buildcontext.txt
│   ├── developer_deletecontext.txt
│   ├── developer_endsession_examples.txt
│   ├── developer_endsession.txt
│   ├── developer_loadcontext.txt
│   ├── developer_startsession.txt
│   ├── Dockerfile
│   ├── index.d.ts
│   ├── index.js
│   ├── index.ts
│   ├── package.json
│   ├── README.md
│   └── tsconfig.json
├── dist
│   ├── developer
│   │   ├── index.d.ts
│   │   └── index.js
│   ├── main
│   │   ├── descriptions
│   │   │   ├── common_advancedcontext.txt
│   │   │   ├── common_buildcontext.txt
│   │   │   ├── common_deletecontext.txt
│   │   │   ├── common_endsession.txt
│   │   │   ├── common_loadcontext.txt
│   │   │   ├── common_startsession.txt
│   │   │   ├── developer_advancedcontext.txt
│   │   │   ├── developer_buildcontext.txt
│   │   │   ├── developer_deletecontext.txt
│   │   │   ├── developer_endsession_examples.txt
│   │   │   ├── developer_endsession.txt
│   │   │   ├── developer_loadcontext.txt
│   │   │   ├── developer_startsession.txt
│   │   │   ├── project_advancedcontext.txt
│   │   │   ├── project_buildcontext.txt
│   │   │   ├── project_deletecontext.txt
│   │   │   ├── project_endsession_examples.txt
│   │   │   ├── project_endsession.txt
│   │   │   ├── project_loadcontext.txt
│   │   │   ├── project_startsession.txt
│   │   │   ├── qualitativeresearch_advancedcontext.txt
│   │   │   ├── qualitativeresearch_buildcontext.txt
│   │   │   ├── qualitativeresearch_deletecontext.txt
│   │   │   ├── qualitativeresearch_endsession_examples.txt
│   │   │   ├── qualitativeresearch_endsession.txt
│   │   │   ├── qualitativeresearch_loadcontext.txt
│   │   │   ├── qualitativeresearch_startsession.txt
│   │   │   ├── quantitativeresearch_advancedcontext.txt
│   │   │   ├── quantitativeresearch_buildcontext.txt
│   │   │   ├── quantitativeresearch_deletecontext.txt
│   │   │   ├── quantitativeresearch_endsession_examples.txt
│   │   │   ├── quantitativeresearch_endsession.txt
│   │   │   ├── quantitativeresearch_loadcontext.txt
│   │   │   ├── quantitativeresearch_startsession.txt
│   │   │   ├── student_advancedcontext.txt
│   │   │   ├── student_buildcontext.txt
│   │   │   ├── student_deletecontext.txt
│   │   │   ├── student_endsession_examples.txt
│   │   │   ├── student_endsession.txt
│   │   │   ├── student_loadcontext.txt
│   │   │   └── student_startsession.txt
│   │   ├── index.d.ts
│   │   ├── index.js
│   │   ├── mcp.d.ts
│   │   └── mcp.js
│   ├── project
│   │   ├── index.d.ts
│   │   └── index.js
│   ├── qualitativeresearch
│   │   ├── index.d.ts
│   │   └── index.js
│   ├── quantitativeresearch
│   │   ├── index.d.ts
│   │   └── index.js
│   └── student
│       ├── index.d.ts
│       └── index.js
├── main
│   ├── descriptions
│   │   ├── common_advancedcontext.txt
│   │   ├── common_buildcontext.txt
│   │   ├── common_deletecontext.txt
│   │   ├── common_endsession.txt
│   │   ├── common_loadcontext.txt
│   │   ├── common_startsession.txt
│   │   ├── developer_advancedcontext.txt
│   │   ├── developer_buildcontext.txt
│   │   ├── developer_deletecontext.txt
│   │   ├── developer_endsession_examples.txt
│   │   ├── developer_endsession.txt
│   │   ├── developer_loadcontext.txt
│   │   ├── developer_startsession.txt
│   │   ├── project_advancedcontext.txt
│   │   ├── project_buildcontext.txt
│   │   ├── project_deletecontext.txt
│   │   ├── project_endsession_examples.txt
│   │   ├── project_endsession.txt
│   │   ├── project_loadcontext.txt
│   │   ├── project_startsession.txt
│   │   ├── qualitativeresearch_advancedcontext.txt
│   │   ├── qualitativeresearch_buildcontext.txt
│   │   ├── qualitativeresearch_deletecontext.txt
│   │   ├── qualitativeresearch_endsession_examples.txt
│   │   ├── qualitativeresearch_endsession.txt
│   │   ├── qualitativeresearch_loadcontext.txt
│   │   ├── qualitativeresearch_startsession.txt
│   │   ├── quantitativeresearch_advancedcontext.txt
│   │   ├── quantitativeresearch_buildcontext.txt
│   │   ├── quantitativeresearch_deletecontext.txt
│   │   ├── quantitativeresearch_endsession_examples.txt
│   │   ├── quantitativeresearch_endsession.txt
│   │   ├── quantitativeresearch_loadcontext.txt
│   │   ├── quantitativeresearch_startsession.txt
│   │   ├── student_advancedcontext.txt
│   │   ├── student_buildcontext.txt
│   │   ├── student_deletecontext.txt
│   │   ├── student_endsession_examples.txt
│   │   ├── student_endsession.txt
│   │   ├── student_loadcontext.txt
│   │   └── student_startsession.txt
│   ├── index.js
│   ├── index.ts
│   ├── mcp.ts
│   ├── package.json
│   ├── README.md
│   └── tsconfig.json
├── package-lock.json
├── package.json
├── project
│   ├── .gitattributes
│   ├── Dockerfile
│   ├── index.d.ts
│   ├── index.js
│   ├── index.ts
│   ├── package.json
│   ├── project_advancedcontext.txt
│   ├── project_buildcontext.txt
│   ├── project_deletecontext.txt
│   ├── project_endsession_examples.txt
│   ├── project_endsession.txt
│   ├── project_loadcontext.txt
│   ├── project_startsession.txt
│   ├── README.md
│   └── tsconfig.json
├── qualitativeresearch
│   ├── .gitattributes
│   ├── Dockerfile
│   ├── index.d.ts
│   ├── index.js
│   ├── index.ts
│   ├── package.json
│   ├── qualitativeresearch_advancedcontext.txt
│   ├── qualitativeresearch_buildcontext.txt
│   ├── qualitativeresearch_deletecontext.txt
│   ├── qualitativeresearch_endsession_examples.txt
│   ├── qualitativeresearch_endsession.txt
│   ├── qualitativeresearch_loadcontext.txt
│   ├── qualitativeresearch_startsession.txt
│   ├── README.md
│   └── tsconfig.json
├── quantitativeresearch
│   ├── .gitattributes
│   ├── Dockerfile
│   ├── index.d.ts
│   ├── index.js
│   ├── index.ts
│   ├── package.json
│   ├── quantitativeresearch_advancedcontext.txt
│   ├── quantitativeresearch_buildcontext.txt
│   ├── quantitativeresearch_deletecontext.txt
│   ├── quantitativeresearch_endsession_examples.txt
│   ├── quantitativeresearch_endsession.txt
│   ├── quantitativeresearch_loadcontext.txt
│   ├── quantitativeresearch_startsession.txt
│   ├── README.md
│   └── tsconfig.json
├── README.md
├── student
│   ├── .gitattributes
│   ├── Dockerfile
│   ├── index.d.ts
│   ├── index.js
│   ├── index.ts
│   ├── package.json
│   ├── README.md
│   ├── student_advancedcontext.txt
│   ├── student_buildcontext.txt
│   ├── student_deletecontext.txt
│   ├── student_endsession_examples.txt
│   ├── student_endsession.txt
│   ├── student_loadcontext.txt
│   ├── student_startsession.txt
│   └── tsconfig.json
└── tsconfig.json
```

# Files

--------------------------------------------------------------------------------
/project/index.js:
--------------------------------------------------------------------------------

```javascript
#!/usr/bin/env node
// Updated imports using the modern MCP SDK API
import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
import { z } from "zod";
// Node.js type declarations
import { promises as fs } from 'fs';
import * as path from 'path';
import { fileURLToPath } from 'url';
import { readFileSync, existsSync } from "fs";
// Define memory file path using environment variable with fallback
const parentPath = path.dirname(fileURLToPath(import.meta.url));
const defaultMemoryPath = path.join(parentPath, 'memory.json');
const defaultSessionsPath = path.join(parentPath, 'sessions.json');
// Properly handle absolute and relative paths for MEMORY_FILE_PATH
const MEMORY_FILE_PATH = process.env.MEMORY_FILE_PATH
    ? path.isAbsolute(process.env.MEMORY_FILE_PATH)
        ? process.env.MEMORY_FILE_PATH // Use absolute path as is
        : path.join(process.cwd(), process.env.MEMORY_FILE_PATH) // Relative to current working directory
    : defaultMemoryPath; // Default fallback
// Properly handle absolute and relative paths for SESSIONS_FILE_PATH
const SESSIONS_FILE_PATH = process.env.SESSIONS_FILE_PATH
    ? path.isAbsolute(process.env.SESSIONS_FILE_PATH)
        ? process.env.SESSIONS_FILE_PATH // Use absolute path as is
        : path.join(process.cwd(), process.env.SESSIONS_FILE_PATH) // Relative to current working directory
    : defaultSessionsPath; // Default fallback
// Project management specific entity types
const validEntityTypes = [
    'project', // The main container for all related entities
    'task', // Individual work items that need to be completed
    'milestone', // Key checkpoints or deliverables in the project
    'resource', // Materials, tools, or assets needed for the project
    'teamMember', // People involved in the project
    'note', // Documentation, ideas, or observations
    'document', // Formal project documents
    'issue', // Problems or blockers
    'risk', // Potential future problems
    'decision', // Important choices made during the project
    'dependency', // External requirements or prerequisites
    'component', // Parts or modules of the project
    'stakeholder', // People affected by or interested in the project
    'change', // Modifications to project scope or requirements
    'status', // Entity status values
    'priority' // Entity priority values
];
// Validation functions
function isValidEntityType(type) {
    return validEntityTypes.includes(type);
}
function validateEntityType(type) {
    if (!isValidEntityType(type)) {
        throw new Error(`Invalid entity type: ${type}. Valid types are: ${validEntityTypes.join(', ')}`);
    }
}
const __filename = fileURLToPath(import.meta.url);
const __dirname = path.dirname(__filename);
// Collect tool descriptions from text files
const toolDescriptions = {
    'startsession': '',
    'loadcontext': '',
    'deletecontext': '',
    'buildcontext': '',
    'advancedcontext': '',
    'endsession': '',
};
for (const tool of Object.keys(toolDescriptions)) {
    const descriptionFilePath = path.resolve(__dirname, `project_${tool}.txt`);
    if (existsSync(descriptionFilePath)) {
        toolDescriptions[tool] = readFileSync(descriptionFilePath, 'utf-8');
    }
}
// Session management functions
async function loadSessionStates() {
    try {
        const fileContent = await fs.readFile(SESSIONS_FILE_PATH, 'utf-8');
        const sessions = JSON.parse(fileContent);
        // Convert from object to Map
        const sessionsMap = new Map();
        for (const [key, value] of Object.entries(sessions)) {
            sessionsMap.set(key, value);
        }
        return sessionsMap;
    }
    catch (error) {
        if (error instanceof Error && 'code' in error && error.code === "ENOENT") {
            return new Map();
        }
        throw error;
    }
}
async function saveSessionStates(sessionsMap) {
    // Convert from Map to object
    const sessions = {};
    for (const [key, value] of sessionsMap.entries()) {
        sessions[key] = value;
    }
    await fs.writeFile(SESSIONS_FILE_PATH, JSON.stringify(sessions, null, 2), 'utf-8');
}
// Generate a unique session ID
function generateSessionId() {
    return `proj_${Date.now()}_${Math.random().toString(36).substring(2, 15)}`;
}
// Define common relation types for project entities
const VALID_RELATION_TYPES = [
    'part_of', // Indicates an entity is a component/subset of another
    'depends_on', // Shows dependencies between entities
    'assigned_to', // Links tasks to team members
    'created_by', // Tracks who created an entity
    'modified_by', // Records who changed an entity
    'related_to', // Shows general connections between entities
    'blocks', // Indicates one entity is blocking another
    'manages', // Shows management relationships
    'contributes_to', // Shows contributions to entities
    'documents', // Links documentation to entities
    'scheduled_for', // Connects entities to dates or timeframes
    'responsible_for', // Assigns ownership/responsibility
    'reports_to', // Indicates reporting relationships
    'categorized_as', // Links entities to categories or types
    'required_for', // Shows requirements for completion
    'discovered_in', // Links issues to their discovery context
    'resolved_by', // Shows what resolved an issue
    'impacted_by', // Shows impact relationships
    'stakeholder_of', // Links stakeholders to projects/components
    'prioritized_as', // Indicates priority levels
    'has_status', // Connects an entity to its status
    'has_priority', // Connects an entity to its priority
    'precedes' // Indicates one entity comes before another in sequence
];
// Valid status and priority values
const VALID_STATUS_VALUES = ['active', 'completed', 'pending', 'blocked', 'cancelled'];
const VALID_PRIORITY_VALUES = ['high', 'low'];
// Status values for different entity types
const STATUS_VALUES = {
    project: ['planning', 'in_progress', 'on_hold', 'completed', 'cancelled', 'archived'],
    task: ['not_started', 'in_progress', 'blocked', 'under_review', 'completed', 'cancelled'],
    milestone: ['planned', 'approaching', 'reached', 'missed', 'rescheduled'],
    issue: ['identified', 'analyzing', 'fixing', 'testing', 'resolved', 'wont_fix'],
    risk: ['identified', 'monitoring', 'mitigating', 'occurred', 'avoided', 'accepted'],
    decision: ['proposed', 'under_review', 'approved', 'rejected', 'implemented', 'reversed']
};
class KnowledgeGraphManager {
    async loadGraph() {
        try {
            const fileContent = await fs.readFile(MEMORY_FILE_PATH, 'utf-8');
            return JSON.parse(fileContent);
        }
        catch (error) {
            // If file doesn't exist or is invalid, return an empty graph
            return { entities: [], relations: [] };
        }
    }
    async saveGraph(graph) {
        await fs.writeFile(MEMORY_FILE_PATH, JSON.stringify(graph, null, 2), 'utf-8');
    }
    // Initialize status and priority entities
    async initializeStatusAndPriority() {
        const graph = await this.loadGraph();
        // Create status entities if they don't exist
        for (const statusValue of VALID_STATUS_VALUES) {
            const statusName = `status:${statusValue}`;
            if (!graph.entities.some(e => e.name === statusName && e.entityType === 'status')) {
                graph.entities.push({
                    name: statusName,
                    entityType: 'status',
                    observations: [`A ${statusValue} status value`]
                });
            }
        }
        // Create priority entities if they don't exist
        for (const priorityValue of VALID_PRIORITY_VALUES) {
            const priorityName = `priority:${priorityValue}`;
            if (!graph.entities.some(e => e.name === priorityName && e.entityType === 'priority')) {
                graph.entities.push({
                    name: priorityName,
                    entityType: 'priority',
                    observations: [`A ${priorityValue} priority value`]
                });
            }
        }
        await this.saveGraph(graph);
    }
    // Helper method to get status of an entity
    async getEntityStatus(entityName) {
        const graph = await this.loadGraph();
        // Find status relation for this entity
        const statusRelation = graph.relations.find(r => r.from === entityName &&
            r.relationType === 'has_status');
        if (statusRelation) {
            // Extract status value from the status entity name (status:value)
            return statusRelation.to.split(':')[1];
        }
        return null;
    }
    // Helper method to get priority of an entity
    async getEntityPriority(entityName) {
        const graph = await this.loadGraph();
        // Find priority relation for this entity
        const priorityRelation = graph.relations.find(r => r.from === entityName &&
            r.relationType === 'has_priority');
        if (priorityRelation) {
            // Extract priority value from the priority entity name (priority:value)
            return priorityRelation.to.split(':')[1];
        }
        return null;
    }
    // Helper method to set status of an entity
    async setEntityStatus(entityName, statusValue) {
        if (!VALID_STATUS_VALUES.includes(statusValue)) {
            throw new Error(`Invalid status value: ${statusValue}. Valid values are: ${VALID_STATUS_VALUES.join(', ')}`);
        }
        const graph = await this.loadGraph();
        // Remove any existing status relations for this entity
        graph.relations = graph.relations.filter(r => !(r.from === entityName && r.relationType === 'has_status'));
        // Add new status relation
        graph.relations.push({
            from: entityName,
            to: `status:${statusValue}`,
            relationType: 'has_status'
        });
        await this.saveGraph(graph);
    }
    // Helper method to set priority of an entity
    async setEntityPriority(entityName, priorityValue) {
        if (!VALID_PRIORITY_VALUES.includes(priorityValue)) {
            throw new Error(`Invalid priority value: ${priorityValue}. Valid values are: ${VALID_PRIORITY_VALUES.join(', ')}`);
        }
        const graph = await this.loadGraph();
        // Remove any existing priority relations for this entity
        graph.relations = graph.relations.filter(r => !(r.from === entityName && r.relationType === 'has_priority'));
        // Add new priority relation
        graph.relations.push({
            from: entityName,
            to: `priority:${priorityValue}`,
            relationType: 'has_priority'
        });
        await this.saveGraph(graph);
    }
    async createEntities(entities) {
        const graph = await this.loadGraph();
        // Validate entity names don't already exist
        for (const entity of entities) {
            if (graph.entities.some(e => e.name === entity.name)) {
                throw new Error(`Entity with name ${entity.name} already exists`);
            }
            validateEntityType(entity.entityType);
        }
        // Add new entities
        graph.entities.push(...entities);
        // Save updated graph
        await this.saveGraph(graph);
        return graph;
    }
    async createRelations(relations) {
        const graph = await this.loadGraph();
        // Validate relations
        for (const relation of relations) {
            // Check if entities exist
            if (!graph.entities.some(e => e.name === relation.from)) {
                throw new Error(`Entity '${relation.from}' not found`);
            }
            if (!graph.entities.some(e => e.name === relation.to)) {
                throw new Error(`Entity '${relation.to}' not found`);
            }
            if (!VALID_RELATION_TYPES.includes(relation.relationType)) {
                throw new Error(`Invalid relation type: ${relation.relationType}. Valid types are: ${VALID_RELATION_TYPES.join(', ')}`);
            }
            // Check if relation already exists
            if (graph.relations.some(r => r.from === relation.from &&
                r.to === relation.to &&
                r.relationType === relation.relationType)) {
                throw new Error(`Relation from '${relation.from}' to '${relation.to}' with type '${relation.relationType}' already exists`);
            }
        }
        // Add relations
        graph.relations.push(...relations);
        // Save updated graph
        await this.saveGraph(graph);
        return graph;
    }
    async addObservations(entityName, observations) {
        const graph = await this.loadGraph();
        // Find the entity
        const entity = graph.entities.find(e => e.name === entityName);
        if (!entity) {
            throw new Error(`Entity '${entityName}' not found`);
        }
        // Add observations
        entity.observations.push(...observations);
        // Save updated graph
        await this.saveGraph(graph);
        return graph;
    }
    async deleteEntities(entityNames) {
        const graph = await this.loadGraph();
        // Remove the entities
        graph.entities = graph.entities.filter(e => !entityNames.includes(e.name));
        // Remove any relations that involve those entities
        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();
        for (const deletion of deletions) {
            const entity = graph.entities.find(e => e.name === deletion.entityName);
            if (entity) {
                entity.observations = entity.observations.filter(o => !deletion.observations.includes(o));
            }
        }
        await this.saveGraph(graph);
    }
    async deleteRelations(relations) {
        const graph = await this.loadGraph();
        // Remove matching relations
        graph.relations = graph.relations.filter(r => !relations.some(rel => r.from === rel.from && r.to === rel.to && r.relationType === rel.relationType));
        await this.saveGraph(graph);
    }
    async readGraph() {
        return await this.loadGraph();
    }
    async searchNodes(query) {
        const graph = await this.loadGraph();
        const lowerQuery = query.toLowerCase();
        // Simple implementation: search entity names, types, and observations
        const matchingEntities = graph.entities.filter(entity => entity.name.toLowerCase().includes(lowerQuery) ||
            entity.entityType.toLowerCase().includes(lowerQuery) ||
            entity.observations.some(o => o.toLowerCase().includes(lowerQuery)));
        // Get entity names for filtering relations
        const matchingEntityNames = new Set(matchingEntities.map(e => e.name));
        // Find relations between matching entities
        const matchingRelations = graph.relations.filter(relation => matchingEntityNames.has(relation.from) && matchingEntityNames.has(relation.to));
        // Also include relations where the relation type matches the query
        const additionalRelations = graph.relations.filter(relation => relation.relationType.toLowerCase().includes(lowerQuery) ||
            (relation.observations && relation.observations.some(o => o.toLowerCase().includes(lowerQuery))));
        // Merge relations without duplicates
        const allRelations = [...matchingRelations];
        for (const relation of additionalRelations) {
            if (!allRelations.some(r => r.from === relation.from &&
                r.to === relation.to &&
                r.relationType === relation.relationType)) {
                allRelations.push(relation);
                // Add the entities involved in these additional relations
                if (!matchingEntityNames.has(relation.from)) {
                    const fromEntity = graph.entities.find(e => e.name === relation.from);
                    if (fromEntity) {
                        matchingEntities.push(fromEntity);
                        matchingEntityNames.add(relation.from);
                    }
                }
                if (!matchingEntityNames.has(relation.to)) {
                    const toEntity = graph.entities.find(e => e.name === relation.to);
                    if (toEntity) {
                        matchingEntities.push(toEntity);
                        matchingEntityNames.add(relation.to);
                    }
                }
            }
        }
        return {
            entities: matchingEntities,
            relations: allRelations
        };
    }
    async openNodes(names) {
        const graph = await this.loadGraph();
        // Find the specified entities
        const entities = graph.entities.filter(e => names.includes(e.name));
        // Find relations between the specified entities
        const relations = graph.relations.filter(r => names.includes(r.from) && names.includes(r.to));
        return {
            entities,
            relations
        };
    }
    // Provides a comprehensive view of a project including tasks, milestones, team members, issues, etc.
    async getProjectOverview(projectName) {
        const graph = await this.loadGraph();
        // Find the project
        const project = graph.entities.find(e => e.name === projectName && e.entityType === 'project');
        if (!project) {
            throw new Error(`Project '${projectName}' not found`);
        }
        // Extract project info from observations
        const description = project.observations.find(o => o.startsWith('Description:'))?.split(':', 2)[1]?.trim();
        const startDate = project.observations.find(o => o.startsWith('StartDate:'))?.split(':', 2)[1]?.trim();
        const endDate = project.observations.find(o => o.startsWith('EndDate:'))?.split(':', 2)[1]?.trim();
        const priority = project.observations.find(o => o.startsWith('Priority:'))?.split(':', 2)[1]?.trim();
        const status = project.observations.find(o => o.startsWith('Status:'))?.split(':', 2)[1]?.trim() || 'planning';
        const goal = project.observations.find(o => o.startsWith('Goal:'))?.split(':', 2)[1]?.trim();
        const budget = project.observations.find(o => o.startsWith('Budget:'))?.split(':', 2)[1]?.trim();
        // Find components of the project
        const components = graph.entities.filter(e => {
            return graph.relations.some(r => r.from === e.name &&
                r.to === projectName &&
                r.relationType === 'part_of' &&
                e.entityType === 'component');
        });
        // Find tasks for this project
        const tasks = [];
        for (const relation of graph.relations) {
            if (relation.relationType === 'part_of' && relation.to === projectName) {
                const task = graph.entities.find(e => e.name === relation.from && e.entityType === 'task');
                if (task) {
                    tasks.push(task);
                }
            }
        }
        // Group tasks by status
        const tasksByStatus = {};
        for (const task of tasks) {
            const taskStatus = task.observations.find(o => o.startsWith('Status:'))?.split(':', 2)[1]?.trim() || 'not_started';
            if (!tasksByStatus[taskStatus]) {
                tasksByStatus[taskStatus] = [];
            }
            tasksByStatus[taskStatus].push(task);
        }
        // Find milestones for this project
        const milestones = [];
        for (const relation of graph.relations) {
            if (relation.relationType === 'part_of' && relation.to === projectName) {
                const milestone = graph.entities.find(e => e.name === relation.from && e.entityType === 'milestone');
                if (milestone) {
                    milestones.push(milestone);
                }
            }
        }
        // Sort milestones by date
        milestones.sort((a, b) => {
            const aDate = a.observations.find(o => o.startsWith('Date:'))?.split(':', 2)[1]?.trim() || '';
            const bDate = b.observations.find(o => o.startsWith('Date:'))?.split(':', 2)[1]?.trim() || '';
            return new Date(aDate).getTime() - new Date(bDate).getTime();
        });
        // Find team members for this project
        const teamMembers = [];
        for (const relation of graph.relations) {
            if ((relation.relationType === 'assigned_to' || relation.relationType === 'manages' || relation.relationType === 'contributes_to') &&
                relation.to === projectName) {
                const teamMember = graph.entities.find(e => e.name === relation.from && e.entityType === 'teamMember');
                if (teamMember && !teamMembers.some(tm => tm.name === teamMember.name)) {
                    teamMembers.push(teamMember);
                }
            }
        }
        // Find issues for this project
        const issues = [];
        for (const relation of graph.relations) {
            if (relation.relationType === 'part_of' && relation.to === projectName) {
                const issue = graph.entities.find(e => e.name === relation.from && e.entityType === 'issue');
                if (issue) {
                    issues.push(issue);
                }
            }
        }
        // Group issues by status
        const issuesByStatus = {};
        for (const issue of issues) {
            const issueStatus = issue.observations.find(o => o.startsWith('Status:'))?.split(':', 2)[1]?.trim() || 'identified';
            if (!issuesByStatus[issueStatus]) {
                issuesByStatus[issueStatus] = [];
            }
            issuesByStatus[issueStatus].push(issue);
        }
        // Find risks for this project
        const risks = [];
        for (const relation of graph.relations) {
            if (relation.relationType === 'part_of' && relation.to === projectName) {
                const risk = graph.entities.find(e => e.name === relation.from && e.entityType === 'risk');
                if (risk) {
                    risks.push(risk);
                }
            }
        }
        // Find resources for this project
        const resources = [];
        for (const relation of graph.relations) {
            if (relation.relationType === 'part_of' && relation.to === projectName) {
                const resource = graph.entities.find(e => e.name === relation.from && e.entityType === 'resource');
                if (resource) {
                    resources.push(resource);
                }
            }
        }
        // Find stakeholders for this project
        const stakeholders = [];
        for (const relation of graph.relations) {
            if (relation.relationType === 'stakeholder_of' && relation.to === projectName) {
                const stakeholder = graph.entities.find(e => e.name === relation.from && e.entityType === 'stakeholder');
                if (stakeholder) {
                    stakeholders.push(stakeholder);
                }
            }
        }
        // Calculate task completion rate
        const completedTasks = tasks.filter(t => t.observations.find(o => o.startsWith('Status:'))?.split(':', 2)[1]?.trim() === 'completed').length;
        const taskCompletionRate = tasks.length > 0 ? (completedTasks / tasks.length) * 100 : 0;
        // Get upcoming milestones
        const today = new Date();
        const upcomingMilestones = milestones.filter(m => {
            const dateStr = m.observations.find(o => o.startsWith('Date:'))?.split(':', 2)[1]?.trim();
            if (dateStr) {
                const milestoneDate = new Date(dateStr);
                return milestoneDate >= today;
            }
            return false;
        });
        return {
            project,
            info: {
                description,
                startDate,
                endDate,
                priority,
                status,
                goal,
                budget
            },
            summary: {
                taskCount: tasks.length,
                completedTasks,
                taskCompletionRate: Math.round(taskCompletionRate),
                milestoneCount: milestones.length,
                teamMemberCount: teamMembers.length,
                issueCount: issues.length,
                riskCount: risks.length,
                componentCount: components.length
            },
            components,
            tasks,
            tasksByStatus,
            milestones,
            upcomingMilestones,
            teamMembers,
            issues,
            issuesByStatus,
            risks,
            resources,
            stakeholders
        };
    }
    // Visualizes dependencies between tasks, optionally to a specified depth
    async getTaskDependencies(taskName, depth = 2) {
        const graph = await this.loadGraph();
        // Find the task
        const task = graph.entities.find(e => e.name === taskName && e.entityType === 'task');
        if (!task) {
            throw new Error(`Task '${taskName}' not found`);
        }
        // Find the project this task belongs to
        let projectName;
        for (const relation of graph.relations) {
            if (relation.relationType === 'part_of' && relation.from === taskName) {
                const project = graph.entities.find(e => e.name === relation.to && e.entityType === 'project');
                if (project) {
                    projectName = project.name;
                    break;
                }
            }
        }
        const dependencyMap = new Map();
        // Helper function to add a task and its dependencies recursively
        const addDependencies = (taskEntity, currentLevel, direction) => {
            if (currentLevel > depth)
                return;
            // Create node if it doesn't exist
            if (!dependencyMap.has(taskEntity.name)) {
                dependencyMap.set(taskEntity.name, {
                    task: taskEntity,
                    dependsOn: [],
                    dependedOnBy: [],
                    level: direction === 'dependsOn' ? currentLevel : 0
                });
            }
            const node = dependencyMap.get(taskEntity.name);
            // Update level if this path is shorter
            if (direction === 'dependsOn' && currentLevel < node.level) {
                node.level = currentLevel;
            }
            if (direction === 'dependsOn') {
                // Find tasks this task depends on
                for (const relation of graph.relations) {
                    if (relation.relationType === 'depends_on' && relation.from === taskEntity.name) {
                        const dependencyTask = graph.entities.find(e => e.name === relation.to && e.entityType === 'task');
                        if (dependencyTask) {
                            // Check if this dependency is already in the node's dependsOn list
                            if (!node.dependsOn.some(d => d.task.name === dependencyTask.name)) {
                                // Recursively add dependencies
                                addDependencies(dependencyTask, currentLevel + 1, 'dependsOn');
                                // Add this dependency to the node's dependsOn list
                                const dependencyNode = dependencyMap.get(dependencyTask.name);
                                node.dependsOn.push(dependencyNode);
                                // Add the reverse relationship
                                if (!dependencyNode.dependedOnBy.some(d => d.task.name === taskEntity.name)) {
                                    dependencyNode.dependedOnBy.push(node);
                                }
                            }
                        }
                    }
                }
            }
            else { // direction === 'dependedOnBy'
                // Find tasks that depend on this task
                for (const relation of graph.relations) {
                    if (relation.relationType === 'depends_on' && relation.to === taskEntity.name) {
                        const dependentTask = graph.entities.find(e => e.name === relation.from && e.entityType === 'task');
                        if (dependentTask) {
                            // Check if this dependent is already in the node's dependedOnBy list
                            if (!node.dependedOnBy.some(d => d.task.name === dependentTask.name)) {
                                // Recursively add dependents
                                addDependencies(dependentTask, currentLevel + 1, 'dependedOnBy');
                                // Add this dependent to the node's dependedOnBy list
                                const dependentNode = dependencyMap.get(dependentTask.name);
                                node.dependedOnBy.push(dependentNode);
                                // Add the reverse relationship
                                if (!dependentNode.dependsOn.some(d => d.task.name === taskEntity.name)) {
                                    dependentNode.dependsOn.push(node);
                                }
                            }
                        }
                    }
                }
            }
        };
        // Start with the main task and build the dependency tree in both directions
        addDependencies(task, 0, 'dependsOn');
        addDependencies(task, 0, 'dependedOnBy');
        // Convert to a serializable structure without circular references
        const serializableDependencies = Array.from(dependencyMap.values()).map(node => {
            const { task, level } = node;
            return {
                task,
                level,
                dependsOn: node.dependsOn.map(d => d.task.name),
                dependedOnBy: node.dependedOnBy.map(d => d.task.name),
                status: task.observations.find(o => o.startsWith('Status:'))?.split(':', 2)[1]?.trim() || 'not_started',
                dueDate: task.observations.find(o => o.startsWith('DueDate:'))?.split(':', 2)[1]?.trim(),
                assignee: this.getTaskAssignee(graph, task.name)
            };
        });
        // Sort by level (dependency depth)
        serializableDependencies.sort((a, b) => a.level - b.level);
        // Calculate the critical path
        const criticalPath = this.calculateCriticalPath(graph, serializableDependencies);
        return {
            task,
            projectName,
            dependencies: serializableDependencies,
            criticalPath,
            summary: {
                totalDependencies: serializableDependencies.length - 1, // Exclude the main task
                maxDepth: depth,
                blockedBy: serializableDependencies.filter(d => d.task.name !== taskName &&
                    d.status !== 'completed' &&
                    task.observations.find(o => o.startsWith('Status:'))?.split(':', 2)[1]?.trim() !== 'completed').length
            }
        };
    }
    // Helper to find the assignee of a task
    getTaskAssignee(graph, taskName) {
        for (const relation of graph.relations) {
            if (relation.relationType === 'assigned_to' && relation.from === taskName) {
                const teamMember = graph.entities.find(e => e.name === relation.to && e.entityType === 'teamMember');
                if (teamMember) {
                    return teamMember.name;
                }
            }
        }
        return undefined;
    }
    // Helper to calculate the critical path
    calculateCriticalPath(graph, dependencies) {
        // Simple implementation - find the longest chain of dependencies
        // A more sophisticated implementation would account for task durations
        // Create an adjacency list
        const adjacencyList = new Map();
        // Initialize the adjacency list for all tasks
        for (const dep of dependencies) {
            adjacencyList.set(dep.task.name, []);
        }
        // Populate the adjacency list with dependencies
        for (const dep of dependencies) {
            for (const dependsOn of dep.dependsOn) {
                const list = adjacencyList.get(dependsOn) || [];
                list.push(dep.task.name);
                adjacencyList.set(dependsOn, list);
            }
        }
        // Find tasks with no dependencies (starting points)
        const startNodes = dependencies
            .filter(dep => dep.dependsOn.length === 0)
            .map(dep => dep.task.name);
        // Find tasks that no other tasks depend on (end points)
        const endNodes = dependencies
            .filter(dep => dep.dependedOnBy.length === 0)
            .map(dep => dep.task.name);
        // If there are multiple start or end nodes, we need a more sophisticated algorithm
        // For simplicity, we'll just find the longest path from any start to any end
        // Find all paths from start to end
        const allPaths = [];
        const findPaths = (current, path = []) => {
            const newPath = [...path, current];
            if (endNodes.includes(current)) {
                allPaths.push(newPath);
                return;
            }
            const nextNodes = adjacencyList.get(current) || [];
            for (const next of nextNodes) {
                // Avoid cycles
                if (!path.includes(next)) {
                    findPaths(next, newPath);
                }
            }
        };
        for (const start of startNodes) {
            findPaths(start);
        }
        // Find the longest path
        allPaths.sort((a, b) => b.length - a.length);
        return allPaths.length > 0 ? allPaths[0] : [];
    }
    // See all tasks assigned to a team member
    async getTeamMemberAssignments(teamMemberName) {
        const graph = await this.loadGraph();
        // Find the team member
        const teamMember = graph.entities.find(e => e.name === teamMemberName && e.entityType === 'teamMember');
        if (!teamMember) {
            throw new Error(`Team member '${teamMemberName}' not found`);
        }
        // Extract team member info
        const role = teamMember.observations.find(o => o.startsWith('Role:'))?.split(':', 2)[1]?.trim();
        const skills = teamMember.observations.find(o => o.startsWith('Skills:'))?.split(':', 2)[1]?.trim();
        const availability = teamMember.observations.find(o => o.startsWith('Availability:'))?.split(':', 2)[1]?.trim();
        const assignedTasks = [];
        // Find assigned tasks through 'assigned_to' relations
        for (const relation of graph.relations) {
            if (relation.relationType === 'assigned_to' && relation.to === teamMemberName) {
                const task = graph.entities.find(e => e.name === relation.from && e.entityType === 'task');
                if (task) {
                    // Find the project this task belongs to
                    let project;
                    for (const taskRelation of graph.relations) {
                        if (taskRelation.relationType === 'part_of' && taskRelation.from === task.name) {
                            project = graph.entities.find(e => e.name === taskRelation.to && e.entityType === 'project');
                            if (project)
                                break;
                        }
                    }
                    // Extract task info
                    const dueDate = task.observations.find(o => o.startsWith('DueDate:'))?.split(':', 2)[1]?.trim();
                    const status = task.observations.find(o => o.startsWith('Status:'))?.split(':', 2)[1]?.trim() || 'not_started';
                    const priority = task.observations.find(o => o.startsWith('Priority:'))?.split(':', 2)[1]?.trim();
                    assignedTasks.push({
                        task,
                        project,
                        dueDate,
                        status,
                        priority
                    });
                }
            }
        }
        // Sort tasks by due date
        assignedTasks.sort((a, b) => {
            if (!a.dueDate)
                return 1;
            if (!b.dueDate)
                return -1;
            return new Date(a.dueDate).getTime() - new Date(b.dueDate).getTime();
        });
        // Find projects this team member is involved in
        const projects = [];
        for (const relation of graph.relations) {
            if ((relation.relationType === 'manages' || relation.relationType === 'contributes_to') &&
                relation.from === teamMemberName) {
                const project = graph.entities.find(e => e.name === relation.to && e.entityType === 'project');
                if (project && !projects.some(p => p.name === project.name)) {
                    projects.push(project);
                }
            }
        }
        // Group tasks by project
        const tasksByProject = {};
        for (const assignment of assignedTasks) {
            const projectName = assignment.project?.name || 'Unassigned';
            if (!tasksByProject[projectName]) {
                tasksByProject[projectName] = [];
            }
            tasksByProject[projectName].push(assignment);
        }
        // Group tasks by status
        const tasksByStatus = {};
        for (const assignment of assignedTasks) {
            if (!tasksByStatus[assignment.status]) {
                tasksByStatus[assignment.status] = [];
            }
            tasksByStatus[assignment.status].push(assignment);
        }
        // Calculate workload metrics
        const completedTasks = assignedTasks.filter(t => t.status === 'completed').length;
        const inProgressTasks = assignedTasks.filter(t => t.status === 'in_progress').length;
        const notStartedTasks = assignedTasks.filter(t => t.status === 'not_started').length;
        const blockedTasks = assignedTasks.filter(t => t.status === 'blocked').length;
        // Calculate upcoming deadlines
        const today = new Date();
        const upcomingDeadlines = assignedTasks
            .filter(t => {
            if (!t.dueDate || t.status === 'completed')
                return false;
            const dueDate = new Date(t.dueDate);
            const daysUntilDue = Math.ceil((dueDate.getTime() - today.getTime()) / (1000 * 60 * 60 * 24));
            return daysUntilDue >= 0 && daysUntilDue <= 7; // Within the next week
        })
            .sort((a, b) => {
            return new Date(a.dueDate).getTime() - new Date(b.dueDate).getTime();
        });
        // Find overdue tasks
        const overdueTasks = assignedTasks
            .filter(t => {
            if (!t.dueDate || t.status === 'completed')
                return false;
            const dueDate = new Date(t.dueDate);
            return dueDate < today;
        })
            .sort((a, b) => {
            return new Date(a.dueDate).getTime() - new Date(b.dueDate).getTime();
        });
        return {
            teamMember,
            info: {
                role,
                skills,
                availability
            },
            workload: {
                totalTasks: assignedTasks.length,
                completedTasks,
                inProgressTasks,
                notStartedTasks,
                blockedTasks,
                completionRate: assignedTasks.length > 0 ?
                    Math.round((completedTasks / assignedTasks.length) * 100) : 0
            },
            assignedTasks,
            tasksByProject,
            tasksByStatus,
            projects,
            upcomingDeadlines,
            overdueTasks
        };
    }
    // Track progress toward project milestones
    async getMilestoneProgress(projectName, milestoneName) {
        const graph = await this.loadGraph();
        // Find the project
        const project = graph.entities.find(e => e.name === projectName && e.entityType === 'project');
        if (!project) {
            throw new Error(`Project '${projectName}' not found`);
        }
        // Find milestones for this project, or a specific milestone if provided
        const milestones = milestoneName
            ? graph.entities.filter(e => e.name === milestoneName &&
                e.entityType === 'milestone' &&
                graph.relations.some(r => r.from === e.name && r.to === projectName && r.relationType === 'part_of'))
            : graph.entities.filter(e => e.entityType === 'milestone' &&
                graph.relations.some(r => r.from === e.name && r.to === projectName && r.relationType === 'part_of'));
        if (milestoneName && milestones.length === 0) {
            throw new Error(`Milestone '${milestoneName}' not found in project '${projectName}'`);
        }
        // Process each milestone
        const milestoneProgress = [];
        for (const milestone of milestones) {
            // Extract milestone info
            const description = milestone.observations.find(o => o.startsWith('Description:'))?.split(':', 2)[1]?.trim();
            const date = milestone.observations.find(o => o.startsWith('Date:'))?.split(':', 2)[1]?.trim();
            const status = milestone.observations.find(o => o.startsWith('Status:'))?.split(':', 2)[1]?.trim() || 'planned';
            const criteria = milestone.observations.find(o => o.startsWith('Criteria:'))?.split(':', 2)[1]?.trim();
            // Find related tasks
            const relatedTasks = [];
            for (const relation of graph.relations) {
                if (relation.relationType === 'required_for' && relation.to === milestone.name) {
                    const task = graph.entities.find(e => e.name === relation.from && e.entityType === 'task');
                    if (task) {
                        relatedTasks.push(task);
                    }
                }
            }
            // Calculate task completion for this milestone
            const completedTasks = relatedTasks.filter(task => task.observations.find(o => o.startsWith('Status:'))?.split(':', 2)[1]?.trim() === 'completed').length;
            const completionPercentage = relatedTasks.length > 0
                ? Math.round((completedTasks / relatedTasks.length) * 100)
                : status === 'reached' ? 100 : 0;
            // Calculate days until/since milestone
            let daysRemaining = null;
            let isOverdue = false;
            if (date) {
                const milestoneDate = new Date(date);
                const today = new Date();
                const diffTime = milestoneDate.getTime() - today.getTime();
                daysRemaining = Math.ceil(diffTime / (1000 * 60 * 60 * 24));
                isOverdue = diffTime < 0 && status !== 'reached' && status !== 'missed';
            }
            // Find blockers (incomplete tasks that are required)
            const blockers = relatedTasks.filter(task => {
                const taskStatus = task.observations.find(o => o.startsWith('Status:'))?.split(':', 2)[1]?.trim();
                return taskStatus !== 'completed' && taskStatus !== 'cancelled';
            });
            milestoneProgress.push({
                milestone,
                info: {
                    description,
                    date,
                    status,
                    criteria
                },
                progress: {
                    totalTasks: relatedTasks.length,
                    completedTasks,
                    completionPercentage,
                    daysRemaining,
                    isOverdue
                },
                relatedTasks,
                blockers
            });
        }
        // Sort milestones by date
        milestoneProgress.sort((a, b) => {
            if (!a.info.date)
                return 1;
            if (!b.info.date)
                return -1;
            return new Date(a.info.date).getTime() - new Date(b.info.date).getTime();
        });
        // Calculate overall project milestone progress
        const totalMilestones = milestoneProgress.length;
        const reachedMilestones = milestoneProgress.filter(m => m.info.status === 'reached').length;
        const averageCompletion = totalMilestones > 0
            ? milestoneProgress.reduce((sum, m) => sum + m.progress.completionPercentage, 0) / totalMilestones
            : 0;
        return {
            project,
            milestones: milestoneProgress,
            summary: {
                totalMilestones,
                reachedMilestones,
                milestoneCompletionRate: totalMilestones > 0 ? Math.round((reachedMilestones / totalMilestones) * 100) : 0,
                averageCompletion: Math.round(averageCompletion),
                nextMilestone: milestoneProgress.find(m => m.info.status !== 'reached' && m.info.status !== 'missed'),
                overdueMilestones: milestoneProgress.filter(m => m.progress.isOverdue).length
            }
        };
    }
    // Create a timeline view with important dates
    async getProjectTimeline(projectName) {
        const graph = await this.loadGraph();
        // Find the project
        const project = graph.entities.find(e => e.name === projectName && e.entityType === 'project');
        if (!project) {
            throw new Error(`Project '${projectName}' not found`);
        }
        // Extract project dates
        const projectStartDate = project.observations.find(o => o.startsWith('StartDate:'))?.split(':', 2)[1]?.trim();
        const projectEndDate = project.observations.find(o => o.startsWith('EndDate:'))?.split(':', 2)[1]?.trim();
        const timelineEvents = [];
        // Add project start and end dates
        if (projectStartDate) {
            timelineEvents.push({
                date: new Date(projectStartDate),
                entity: project,
                eventType: 'project_start',
                description: 'Project Start'
            });
        }
        if (projectEndDate) {
            timelineEvents.push({
                date: new Date(projectEndDate),
                entity: project,
                eventType: 'project_end',
                description: 'Project End'
            });
        }
        // Find milestones for this project
        const milestones = graph.entities.filter(e => e.entityType === 'milestone' &&
            graph.relations.some(r => r.from === e.name && r.to === projectName && r.relationType === 'part_of'));
        // Add milestones to timeline
        for (const milestone of milestones) {
            const date = milestone.observations.find(o => o.startsWith('Date:'))?.split(':', 2)[1]?.trim();
            if (date) {
                timelineEvents.push({
                    date: new Date(date),
                    entity: milestone,
                    eventType: 'milestone',
                    description: milestone.observations.find(o => o.startsWith('Description:'))?.split(':', 2)[1]?.trim(),
                    status: milestone.observations.find(o => o.startsWith('Status:'))?.split(':', 2)[1]?.trim()
                });
            }
        }
        // Find tasks with due dates
        const tasks = graph.entities.filter(e => e.entityType === 'task' &&
            graph.relations.some(r => r.from === e.name && r.to === projectName && r.relationType === 'part_of'));
        // Add tasks to timeline
        for (const task of tasks) {
            const dueDate = task.observations.find(o => o.startsWith('DueDate:'))?.split(':', 2)[1]?.trim();
            if (dueDate) {
                timelineEvents.push({
                    date: new Date(dueDate),
                    entity: task,
                    eventType: 'task',
                    description: task.observations.find(o => o.startsWith('Description:'))?.split(':', 2)[1]?.trim(),
                    status: task.observations.find(o => o.startsWith('Status:'))?.split(':', 2)[1]?.trim()
                });
            }
        }
        // Sort timeline events by date
        timelineEvents.sort((a, b) => a.date.getTime() - b.date.getTime());
        // Calculate time spans between events
        const timelineWithSpans = timelineEvents.map((event, index) => {
            let daysFromStart = 0;
            let daysToNext = 0;
            if (index === 0 && projectStartDate) {
                // First event relative to project start
                daysFromStart = 0;
            }
            else if (index > 0) {
                // Days from previous event
                const prevDate = timelineEvents[index - 1].date;
                daysFromStart = Math.round((event.date.getTime() - prevDate.getTime()) / (1000 * 60 * 60 * 24));
            }
            if (index < timelineEvents.length - 1) {
                // Days until next event
                const nextDate = timelineEvents[index + 1].date;
                daysToNext = Math.round((nextDate.getTime() - event.date.getTime()) / (1000 * 60 * 60 * 24));
            }
            return {
                ...event,
                dateString: event.date.toISOString().split('T')[0],
                daysFromStart,
                daysToNext
            };
        });
        // Find the current position in the timeline
        const today = new Date();
        let currentPosition = -1;
        for (let i = 0; i < timelineEvents.length; i++) {
            if (timelineEvents[i].date >= today) {
                currentPosition = i;
                break;
            }
        }
        // If we're past all events, set current position to the last event
        if (currentPosition === -1 && timelineEvents.length > 0) {
            currentPosition = timelineEvents.length - 1;
        }
        // Calculate overall project progress based on timeline
        let progressPercentage = 0;
        if (timelineEvents.length >= 2) {
            const startDate = timelineEvents[0].date;
            const endDate = timelineEvents[timelineEvents.length - 1].date;
            const totalDuration = endDate.getTime() - startDate.getTime();
            if (totalDuration > 0) {
                const elapsed = today.getTime() - startDate.getTime();
                progressPercentage = Math.min(100, Math.max(0, Math.round((elapsed / totalDuration) * 100)));
            }
        }
        return {
            project,
            timeline: timelineWithSpans,
            currentPosition,
            progressPercentage,
            projectDuration: timelineEvents.length >= 2 ?
                Math.round((timelineEvents[timelineEvents.length - 1].date.getTime() - timelineEvents[0].date.getTime()) / (1000 * 60 * 60 * 24)) : 0,
            upcomingEvents: timelineWithSpans.filter(e => e.date >= today).slice(0, 5)
        };
    }
    // Shows how resources are allocated across the project
    async getResourceAllocation(projectName, resourceName) {
        const graph = await this.loadGraph();
        // Find the project
        const project = graph.entities.find(e => e.name === projectName && e.entityType === 'project');
        if (!project) {
            throw new Error(`Project '${projectName}' not found`);
        }
        // Find resources for this project, or a specific resource if provided
        const resources = resourceName
            ? graph.entities.filter(e => e.name === resourceName &&
                e.entityType === 'resource' &&
                graph.relations.some(r => r.from === e.name && r.to === projectName && r.relationType === 'part_of'))
            : graph.entities.filter(e => e.entityType === 'resource' &&
                graph.relations.some(r => r.from === e.name && r.to === projectName && r.relationType === 'part_of'));
        if (resourceName && resources.length === 0) {
            throw new Error(`Resource '${resourceName}' not found in project '${projectName}'`);
        }
        // Process each resource
        const resourceAllocations = [];
        for (const resource of resources) {
            // Extract resource info
            const type = resource.observations.find(o => o.startsWith('Type:'))?.split(':', 2)[1]?.trim();
            const availability = resource.observations.find(o => o.startsWith('Availability:'))?.split(':', 2)[1]?.trim();
            const capacity = resource.observations.find(o => o.startsWith('Capacity:'))?.split(':', 2)[1]?.trim();
            const cost = resource.observations.find(o => o.startsWith('Cost:'))?.split(':', 2)[1]?.trim();
            // Find tasks that use this resource
            const assignedTasks = [];
            for (const relation of graph.relations) {
                if (relation.relationType === 'requires' && relation.to === resource.name) {
                    const task = graph.entities.find(e => e.name === relation.from && e.entityType === 'task');
                    if (task) {
                        assignedTasks.push(task);
                    }
                }
            }
            // Sort tasks by due date
            assignedTasks.sort((a, b) => {
                const aDate = a.observations.find(o => o.startsWith('DueDate:'))?.split(':', 2)[1]?.trim() || '';
                const bDate = b.observations.find(o => o.startsWith('DueDate:'))?.split(':', 2)[1]?.trim() || '';
                if (!aDate)
                    return 1;
                if (!bDate)
                    return -1;
                return new Date(aDate).getTime() - new Date(bDate).getTime();
            });
            // Group tasks by status
            const tasksByStatus = {};
            for (const task of assignedTasks) {
                const status = task.observations.find(o => o.startsWith('Status:'))?.split(':', 2)[1]?.trim() || 'not_started';
                if (!tasksByStatus[status]) {
                    tasksByStatus[status] = [];
                }
                tasksByStatus[status].push(task);
            }
            // Find team members using this resource
            const teamMembers = [];
            for (const relation of graph.relations) {
                if (relation.relationType === 'uses' && relation.to === resource.name) {
                    const teamMember = graph.entities.find(e => e.name === relation.from && e.entityType === 'teamMember');
                    if (teamMember) {
                        teamMembers.push(teamMember);
                    }
                }
            }
            // Calculate usage percentage based on assigned tasks
            const totalTasks = assignedTasks.length;
            const inProgressTasks = tasksByStatus['in_progress']?.length || 0;
            // Simple formula for usage percentage
            const usagePercentage = capacity
                ? Math.min(100, Math.round((inProgressTasks / parseInt(capacity)) * 100))
                : totalTasks > 0 ? 50 : 0; // Default to 50% if we have tasks but no capacity
            resourceAllocations.push({
                resource,
                info: {
                    type,
                    availability,
                    capacity,
                    cost
                },
                usage: {
                    totalTasks,
                    inProgressTasks,
                    usagePercentage
                },
                assignedTasks,
                tasksByStatus,
                teamMembers
            });
        }
        // Sort resources by usage percentage (descending)
        resourceAllocations.sort((a, b) => b.usage.usagePercentage - a.usage.usagePercentage);
        // Identify overallocated resources
        const overallocatedResources = resourceAllocations.filter(r => r.usage.usagePercentage > 90);
        // Identify underutilized resources
        const underutilizedResources = resourceAllocations.filter(r => r.usage.usagePercentage < 20 && r.usage.totalTasks > 0);
        return {
            project,
            resources: resourceAllocations,
            summary: {
                totalResources: resources.length,
                overallocatedCount: overallocatedResources.length,
                underutilizedCount: underutilizedResources.length
            },
            overallocatedResources,
            underutilizedResources
        };
    }
    // Identifies potential risks and their impact
    async getProjectRisks(projectName) {
        const graph = await this.loadGraph();
        // Find the project
        const project = graph.entities.find(e => e.name === projectName && e.entityType === 'project');
        if (!project) {
            throw new Error(`Project '${projectName}' not found`);
        }
        // Find risks for this project
        const risks = graph.entities.filter(e => e.entityType === 'risk' &&
            graph.relations.some(r => r.from === e.name && r.to === projectName && r.relationType === 'part_of'));
        // Process each risk
        const processedRisks = [];
        for (const risk of risks) {
            // Extract risk info
            const description = risk.observations.find(o => o.startsWith('Description:'))?.split(':', 2)[1]?.trim();
            const likelihood = risk.observations.find(o => o.startsWith('Likelihood:'))?.split(':', 2)[1]?.trim();
            const impact = risk.observations.find(o => o.startsWith('Impact:'))?.split(':', 2)[1]?.trim();
            const status = risk.observations.find(o => o.startsWith('Status:'))?.split(':', 2)[1]?.trim() || 'identified';
            const mitigation = risk.observations.find(o => o.startsWith('Mitigation:'))?.split(':', 2)[1]?.trim();
            // Calculate risk score (if likelihood and impact are numerical)
            let riskScore;
            if (likelihood && impact) {
                const likelihoodValue = parseInt(likelihood);
                const impactValue = parseInt(impact);
                if (!isNaN(likelihoodValue) && !isNaN(impactValue)) {
                    riskScore = likelihoodValue * impactValue;
                }
            }
            // Find components or tasks affected by this risk
            const affectedEntities = [];
            for (const relation of graph.relations) {
                if (relation.relationType === 'impacted_by' && relation.to === risk.name) {
                    const entity = graph.entities.find(e => e.name === relation.from);
                    if (entity) {
                        affectedEntities.push(entity);
                    }
                }
            }
            processedRisks.push({
                risk,
                info: {
                    description,
                    likelihood,
                    impact,
                    status,
                    mitigation,
                    riskScore
                },
                affectedEntities
            });
        }
        // Sort risks by risk score (descending)
        processedRisks.sort((a, b) => {
            if (a.info.riskScore === undefined)
                return 1;
            if (b.info.riskScore === undefined)
                return -1;
            return b.info.riskScore - a.info.riskScore;
        });
        // Group risks by status
        const risksByStatus = {};
        for (const processedRisk of processedRisks) {
            const status = processedRisk.info.status;
            if (!risksByStatus[status]) {
                risksByStatus[status] = [];
            }
            risksByStatus[status].push(processedRisk);
        }
        // Identify high-priority risks
        const highPriorityRisks = processedRisks.filter(r => {
            if (r.info.riskScore !== undefined) {
                return r.info.riskScore >= 15; // Threshold for high priority
            }
            return r.info.impact === 'high' || r.info.likelihood === 'high';
        });
        return {
            project,
            risks: processedRisks,
            risksByStatus,
            summary: {
                totalRisks: risks.length,
                highPriorityCount: highPriorityRisks.length,
                mitigatedCount: risksByStatus['mitigating']?.length || 0,
                avoidedCount: risksByStatus['avoided']?.length || 0,
                acceptedCount: risksByStatus['accepted']?.length || 0,
                occurredCount: risksByStatus['occurred']?.length || 0
            },
            highPriorityRisks
        };
    }
    // Find connections between different projects
    async findRelatedProjects(projectName, depth = 1) {
        const graph = await this.loadGraph();
        // Find the project
        const project = graph.entities.find(e => e.name === projectName && e.entityType === 'project');
        if (!project) {
            throw new Error(`Project '${projectName}' not found`);
        }
        const relatedProjects = [];
        const processedProjects = new Set([projectName]);
        // Helper function to find connections between projects
        const findConnections = (currentProjectName, currentDepth) => {
            if (currentDepth > depth)
                return;
            // Find all other projects
            const otherProjects = graph.entities.filter(e => e.entityType === 'project' &&
                e.name !== currentProjectName &&
                !processedProjects.has(e.name));
            for (const otherProject of otherProjects) {
                // Add to processed set to avoid cycles
                processedProjects.add(otherProject.name);
                // Find shared team members
                const sharedTeamMembers = [];
                const projectTeamMembers = new Set();
                const otherProjectTeamMembers = new Set();
                // Get team members for current project
                for (const relation of graph.relations) {
                    if ((relation.relationType === 'assigned_to' || relation.relationType === 'contributes_to' || relation.relationType === 'manages') &&
                        relation.to === currentProjectName) {
                        const teamMember = graph.entities.find(e => e.name === relation.from && e.entityType === 'teamMember');
                        if (teamMember) {
                            projectTeamMembers.add(teamMember.name);
                        }
                    }
                }
                // Get team members for other project
                for (const relation of graph.relations) {
                    if ((relation.relationType === 'assigned_to' || relation.relationType === 'contributes_to' || relation.relationType === 'manages') &&
                        relation.to === otherProject.name) {
                        const teamMember = graph.entities.find(e => e.name === relation.from && e.entityType === 'teamMember');
                        if (teamMember) {
                            otherProjectTeamMembers.add(teamMember.name);
                            if (projectTeamMembers.has(teamMember.name)) {
                                sharedTeamMembers.push(teamMember);
                            }
                        }
                    }
                }
                // Find shared resources
                const sharedResources = [];
                const projectResources = new Set();
                const otherProjectResources = new Set();
                // Get resources for current project
                for (const relation of graph.relations) {
                    if (relation.relationType === 'part_of' && relation.to === currentProjectName) {
                        const resource = graph.entities.find(e => e.name === relation.from && e.entityType === 'resource');
                        if (resource) {
                            projectResources.add(resource.name);
                        }
                    }
                }
                // Get resources for other project
                for (const relation of graph.relations) {
                    if (relation.relationType === 'part_of' && relation.to === otherProject.name) {
                        const resource = graph.entities.find(e => e.name === relation.from && e.entityType === 'resource');
                        if (resource) {
                            otherProjectResources.add(resource.name);
                            if (projectResources.has(resource.name)) {
                                sharedResources.push(resource);
                            }
                        }
                    }
                }
                // Find shared stakeholders
                const sharedStakeholders = [];
                const projectStakeholders = new Set();
                const otherProjectStakeholders = new Set();
                // Get stakeholders for current project
                for (const relation of graph.relations) {
                    if (relation.relationType === 'stakeholder_of' && relation.to === currentProjectName) {
                        const stakeholder = graph.entities.find(e => e.name === relation.from && e.entityType === 'stakeholder');
                        if (stakeholder) {
                            projectStakeholders.add(stakeholder.name);
                        }
                    }
                }
                // Get stakeholders for other project
                for (const relation of graph.relations) {
                    if (relation.relationType === 'stakeholder_of' && relation.to === otherProject.name) {
                        const stakeholder = graph.entities.find(e => e.name === relation.from && e.entityType === 'stakeholder');
                        if (stakeholder) {
                            otherProjectStakeholders.add(stakeholder.name);
                            if (projectStakeholders.has(stakeholder.name)) {
                                sharedStakeholders.push(stakeholder);
                            }
                        }
                    }
                }
                // Find dependencies between projects
                const dependencies = [];
                // Check for 'depends_on' relations between projects
                for (const relation of graph.relations) {
                    if (relation.relationType === 'depends_on') {
                        if (relation.from === currentProjectName && relation.to === otherProject.name) {
                            dependencies.push(otherProject);
                        }
                        else if (relation.from === otherProject.name && relation.to === currentProjectName) {
                            dependencies.push(project);
                        }
                    }
                }
                // Calculate connection strength (simple formula based on shared entities)
                const connectionStrength = (sharedTeamMembers.length * 2) + // Team members have higher weight
                    (sharedResources.length * 1.5) + // Resources are also important
                    (dependencies.length * 3) + // Dependencies have highest weight
                    (sharedStakeholders.length * 1); // Stakeholders have standard weight
                // Determine primary connection type
                let connectionType = 'related';
                if (dependencies.length > 0) {
                    connectionType = 'dependency';
                }
                else if (sharedTeamMembers.length > 0) {
                    connectionType = 'shared_team';
                }
                else if (sharedResources.length > 0) {
                    connectionType = 'shared_resources';
                }
                else if (sharedStakeholders.length > 0) {
                    connectionType = 'shared_stakeholders';
                }
                // Only add connections with some relationship
                if (connectionStrength > 0) {
                    relatedProjects.push({
                        project: otherProject,
                        connectionType,
                        connectionStrength,
                        sharedEntities: {
                            teamMembers: sharedTeamMembers,
                            dependencies,
                            resources: sharedResources,
                            stakeholders: sharedStakeholders
                        }
                    });
                    // Recursively find connections for this project (up to the specified depth)
                    findConnections(otherProject.name, currentDepth + 1);
                }
            }
        };
        // Start the recursive search
        findConnections(projectName, 1);
        // Sort related projects by connection strength
        relatedProjects.sort((a, b) => b.connectionStrength - a.connectionStrength);
        return {
            project,
            relatedProjects,
            summary: {
                totalRelated: relatedProjects.length,
                byConnectionType: {
                    dependency: relatedProjects.filter(p => p.connectionType === 'dependency').length,
                    shared_team: relatedProjects.filter(p => p.connectionType === 'shared_team').length,
                    shared_resources: relatedProjects.filter(p => p.connectionType === 'shared_resources').length,
                    shared_stakeholders: relatedProjects.filter(p => p.connectionType === 'shared_stakeholders').length
                },
                maxDepth: depth
            }
        };
    }
    // Get decision log for a project
    async getDecisionLog(projectName) {
        const graph = await this.loadGraph();
        // Find the project
        const project = graph.entities.find(e => e.name === projectName && e.entityType === 'project');
        if (!project) {
            throw new Error(`Project '${projectName}' not found`);
        }
        // Find decisions for this project
        const decisions = graph.entities.filter(e => e.entityType === 'decision' &&
            graph.relations.some(r => r.from === e.name && r.to === projectName && r.relationType === 'part_of'));
        // Process each decision
        const processedDecisions = [];
        for (const decision of decisions) {
            // Extract decision info
            const description = decision.observations.find(o => o.startsWith('Description:'))?.split(':', 2)[1]?.trim();
            const date = decision.observations.find(o => o.startsWith('Date:'))?.split(':', 2)[1]?.trim();
            const status = decision.observations.find(o => o.startsWith('Status:'))?.split(':', 2)[1]?.trim() || 'proposed';
            const rationale = decision.observations.find(o => o.startsWith('Rationale:'))?.split(':', 2)[1]?.trim();
            const alternatives = decision.observations.find(o => o.startsWith('Alternatives:'))?.split(':', 2)[1]?.trim();
            // Find team members involved in this decision
            const involvedTeamMembers = [];
            for (const relation of graph.relations) {
                if (relation.relationType === 'created_by' && relation.from === decision.name) {
                    const teamMember = graph.entities.find(e => e.name === relation.to && e.entityType === 'teamMember');
                    if (teamMember) {
                        involvedTeamMembers.push(teamMember);
                    }
                }
            }
            // Find entities affected by this decision
            const affectedEntities = [];
            for (const relation of graph.relations) {
                if (relation.relationType === 'impacted_by' && relation.to === decision.name) {
                    const entity = graph.entities.find(e => e.name === relation.from);
                    if (entity) {
                        affectedEntities.push(entity);
                    }
                }
            }
            processedDecisions.push({
                decision,
                info: {
                    description,
                    date,
                    status,
                    rationale,
                    alternatives
                },
                involvedTeamMembers,
                affectedEntities
            });
        }
        // Sort decisions by date (most recent first)
        processedDecisions.sort((a, b) => {
            if (!a.info.date)
                return 1;
            if (!b.info.date)
                return -1;
            return new Date(b.info.date).getTime() - new Date(a.info.date).getTime();
        });
        // Group decisions by status
        const decisionsByStatus = {};
        for (const processedDecision of processedDecisions) {
            const status = processedDecision.info.status;
            if (!decisionsByStatus[status]) {
                decisionsByStatus[status] = [];
            }
            decisionsByStatus[status].push(processedDecision);
        }
        return {
            project,
            decisions: processedDecisions,
            decisionsByStatus,
            summary: {
                totalDecisions: decisions.length,
                approvedCount: decisionsByStatus['approved']?.length || 0,
                implementedCount: decisionsByStatus['implemented']?.length || 0,
                rejectedCount: decisionsByStatus['rejected']?.length || 0,
                proposedCount: decisionsByStatus['proposed']?.length || 0
            }
        };
    }
    // Analyze the overall health of the project
    async getProjectHealth(projectName) {
        const graph = await this.loadGraph();
        // Find the project
        const project = graph.entities.find(e => e.name === projectName && e.entityType === 'project');
        if (!project) {
            throw new Error(`Project '${projectName}' not found`);
        }
        // Get project information
        const status = project.observations.find(o => o.startsWith('Status:'))?.split(':', 2)[1]?.trim() || 'planning';
        const startDate = project.observations.find(o => o.startsWith('StartDate:'))?.split(':', 2)[1]?.trim();
        const endDate = project.observations.find(o => o.startsWith('EndDate:'))?.split(':', 2)[1]?.trim();
        // Helper function to get entities of a specific type for this project
        const getProjectEntities = (entityType) => {
            return graph.entities.filter(e => e.entityType === entityType &&
                graph.relations.some(r => r.from === e.name && r.to === projectName && r.relationType === 'part_of'));
        };
        // Get counts of various entities
        const tasks = getProjectEntities('task');
        const milestones = getProjectEntities('milestone');
        const issues = getProjectEntities('issue');
        const risks = getProjectEntities('risk');
        // Calculate task metrics
        const completedTasks = tasks.filter(t => t.observations.find(o => o.startsWith('Status:'))?.split(':', 2)[1]?.trim() === 'completed').length;
        const blockedTasks = tasks.filter(t => t.observations.find(o => o.startsWith('Status:'))?.split(':', 2)[1]?.trim() === 'blocked').length;
        const taskCompletionRate = tasks.length > 0 ? (completedTasks / tasks.length) * 100 : 0;
        // Calculate milestone metrics
        const reachedMilestones = milestones.filter(m => m.observations.find(o => o.startsWith('Status:'))?.split(':', 2)[1]?.trim() === 'reached').length;
        const missedMilestones = milestones.filter(m => m.observations.find(o => o.startsWith('Status:'))?.split(':', 2)[1]?.trim() === 'missed').length;
        const milestoneCompletionRate = milestones.length > 0 ? (reachedMilestones / milestones.length) * 100 : 0;
        // Calculate issue metrics
        const resolvedIssues = issues.filter(i => i.observations.find(o => o.startsWith('Status:'))?.split(':', 2)[1]?.trim() === 'resolved').length;
        const openIssues = issues.length - resolvedIssues;
        // Calculate risk metrics
        const mitigatedRisks = risks.filter(r => r.observations.find(o => o.startsWith('Status:'))?.split(':', 2)[1]?.trim() === 'mitigating' ||
            r.observations.find(o => o.startsWith('Status:'))?.split(':', 2)[1]?.trim() === 'avoided').length;
        const activeRisks = risks.filter(r => r.observations.find(o => o.startsWith('Status:'))?.split(':', 2)[1]?.trim() === 'identified' ||
            r.observations.find(o => o.startsWith('Status:'))?.split(':', 2)[1]?.trim() === 'monitoring').length;
        // Calculate timeline metrics
        let timelineProgress = 0;
        let behindSchedule = false;
        if (startDate && endDate) {
            const start = new Date(startDate).getTime();
            const end = new Date(endDate).getTime();
            const now = new Date().getTime();
            if (end > start) {
                // Calculate percentage of timeline elapsed
                const totalDuration = end - start;
                const elapsed = now - start;
                const timeElapsedPercent = Math.min(100, Math.max(0, (elapsed / totalDuration) * 100));
                // Calculate if project is behind schedule (completion percentage significantly less than time elapsed)
                behindSchedule = taskCompletionRate < (timeElapsedPercent - 15); // More than 15% behind
                timelineProgress = Math.round(timeElapsedPercent);
            }
        }
        // Calculate overall health score
        // This is a simple formula - can be adjusted based on specific project needs
        const healthFactors = [
            // Task factors
            tasks.length > 0 ? Math.min(100, taskCompletionRate) : 50,
            tasks.length > 0 ? Math.max(0, 100 - (blockedTasks / tasks.length) * 200) : 50,
            // Milestone factors
            milestones.length > 0 ? Math.min(100, milestoneCompletionRate) : 50,
            milestones.length > 0 ? Math.max(0, 100 - (missedMilestones / milestones.length) * 200) : 50,
            // Issue factors
            issues.length > 0 ? Math.min(100, (resolvedIssues / issues.length) * 100) : 50,
            issues.length > 0 ? Math.max(0, 100 - (openIssues / issues.length) * 100) : 50,
            // Risk factors
            risks.length > 0 ? Math.min(100, (mitigatedRisks / risks.length) * 100) : 50,
            risks.length > 0 ? Math.max(0, 100 - (activeRisks / risks.length) * 100) : 50,
            // Schedule factor
            behindSchedule ? 30 : 70 // Penalize being behind schedule
        ];
        // Average the health factors
        const healthScore = Math.round(healthFactors.reduce((sum, factor) => sum + factor, 0) / healthFactors.length);
        // Determine health status
        let healthStatus;
        if (healthScore >= 80) {
            healthStatus = 'healthy';
        }
        else if (healthScore >= 60) {
            healthStatus = 'attention_needed';
        }
        else if (healthScore >= 40) {
            healthStatus = 'at_risk';
        }
        else {
            healthStatus = 'critical';
        }
        // Find top issues (if any)
        const topIssues = issues
            .filter(i => i.observations.find(o => o.startsWith('Status:'))?.split(':', 2)[1]?.trim() !== 'resolved' &&
            i.observations.find(o => o.startsWith('Status:'))?.split(':', 2)[1]?.trim() !== 'wont_fix')
            .sort((a, b) => {
            const aPriority = a.observations.find(o => o.startsWith('Priority:'))?.split(':', 2)[1]?.trim() || 'N/A';
            const bPriority = b.observations.find(o => o.startsWith('Priority:'))?.split(':', 2)[1]?.trim() || 'N/A';
            // Simple priority sorting
            if (aPriority === 'high' && bPriority !== 'high')
                return -1;
            if (aPriority !== 'high' && bPriority === 'high')
                return 1;
            if (aPriority === 'N/A' && bPriority === 'low')
                return -1;
            if (aPriority === 'low' && bPriority === 'N/A')
                return 1;
            return 0;
        })
            .slice(0, 3); // Top 3 issues
        return {
            project,
            healthScore,
            healthStatus,
            metrics: {
                tasks: {
                    total: tasks.length,
                    completed: completedTasks,
                    blocked: blockedTasks,
                    completionRate: Math.round(taskCompletionRate)
                },
                milestones: {
                    total: milestones.length,
                    reached: reachedMilestones,
                    missed: missedMilestones,
                    completionRate: Math.round(milestoneCompletionRate)
                },
                issues: {
                    total: issues.length,
                    resolved: resolvedIssues,
                    open: openIssues,
                    resolutionRate: issues.length > 0 ? Math.round((resolvedIssues / issues.length) * 100) : 0
                },
                risks: {
                    total: risks.length,
                    mitigated: mitigatedRisks,
                    active: activeRisks,
                    mitigationRate: risks.length > 0 ? Math.round((mitigatedRisks / risks.length) * 100) : 0
                },
                timeline: {
                    progress: timelineProgress,
                    behindSchedule
                }
            },
            topIssues,
            recommendations: this.generateHealthRecommendations(healthStatus, {
                tasks,
                milestones,
                issues,
                risks,
                behindSchedule
            })
        };
    }
    // Helper method to generate health recommendations
    generateHealthRecommendations(healthStatus, metrics) {
        const recommendations = [];
        switch (healthStatus) {
            case 'healthy':
                recommendations.push('Continue current management practices');
                recommendations.push('Document successful strategies for future projects');
                break;
            case 'attention_needed':
                if (metrics.tasks.blocked > 0) {
                    recommendations.push('Address blocked tasks to maintain momentum');
                }
                if (metrics.issues.open > 2) {
                    recommendations.push('Resolve open issues to prevent escalation');
                }
                if (metrics.behindSchedule) {
                    recommendations.push('Review project timeline and adjust as needed');
                }
                break;
            case 'at_risk':
                if (metrics.tasks.blocked > 0) {
                    recommendations.push('Urgently resolve blocked tasks - consider reassigning resources');
                }
                if (metrics.behindSchedule) {
                    recommendations.push('Reevaluate project scope and timeline - consider adjustments');
                }
                if (metrics.risks.active > 0) {
                    recommendations.push('Implement mitigation strategies for active risks immediately');
                }
                if (metrics.issues.open > 0) {
                    recommendations.push('Prioritize issue resolution and prevent new issues');
                }
                break;
            case 'critical':
                recommendations.push('Conduct emergency project review with stakeholders');
                recommendations.push('Consider project restructuring or reset');
                recommendations.push('Implement daily status meetings and tight monitoring');
                if (metrics.tasks.blocked > 0) {
                    recommendations.push('Escalate blocked tasks to management for immediate action');
                }
                if (metrics.risks.active > 0) {
                    recommendations.push('Reassess all project risks and implement mitigation measures');
                }
                break;
        }
        return recommendations;
    }
}
// Setup the MCP server
async function main() {
    try {
        const knowledgeGraphManager = new KnowledgeGraphManager();
        // Initialize status and priority entities
        await knowledgeGraphManager.initializeStatusAndPriority();
        // Create the MCP server with a name and version
        const server = new McpServer({
            name: "Context Manager",
            version: "1.0.0"
        });
        // Define a resource that exposes the entire graph
        server.resource("graph", "graph://project", async (uri) => ({
            contents: [{
                    uri: uri.href,
                    text: JSON.stringify(await knowledgeGraphManager.readGraph(), null, 2)
                }]
        }));
        /**
         * Start a new work session. Returns session ID, recent sessions, active projects, high-priority tasks, upcoming milestones, and project health summary.
         */
        server.tool("startsession", toolDescriptions["startsession"], {}, async () => {
            try {
                // Generate a unique session ID
                const sessionId = generateSessionId();
                // Get recent sessions from persistent storage instead of entities
                const allSessionStates = await loadSessionStates();
                // Initialize the session state
                allSessionStates.set(sessionId, []);
                await saveSessionStates(allSessionStates);
                // Convert sessions map to array and get recent sessions
                const recentSessions = Array.from(allSessionStates.entries())
                    .map(([id, stages]) => {
                    // Extract summary data from the first stage (if it exists)
                    const summaryStage = stages.find(s => s.stage === "summary");
                    return {
                        id,
                        project: summaryStage?.stageData?.project || "Unknown project",
                        summary: summaryStage?.stageData?.summary || "No summary available"
                    };
                })
                    .slice(0, 3); // Default to 3 recent sessions
                // Get all projects
                const projectsQuery = await knowledgeGraphManager.searchNodes("entityType:project");
                const projects = [];
                // Filter for active projects based on has_status relation
                for (const project of projectsQuery.entities) {
                    const status = await knowledgeGraphManager.getEntityStatus(project.name);
                    if (status === "active") {
                        projects.push(project);
                    }
                }
                // Get tasks
                const taskQuery = await knowledgeGraphManager.searchNodes("entityType:task");
                const tasks = [];
                // Filter for high priority and active tasks
                for (const task of taskQuery.entities) {
                    const status = await knowledgeGraphManager.getEntityStatus(task.name);
                    const priority = await knowledgeGraphManager.getEntityPriority(task.name);
                    if (status === "active" && priority === "high") {
                        tasks.push(task);
                    }
                }
                // Get milestones
                const milestoneQuery = await knowledgeGraphManager.searchNodes("entityType:milestone");
                const milestones = [];
                // Filter for upcoming milestones
                for (const milestone of milestoneQuery.entities) {
                    const status = await knowledgeGraphManager.getEntityStatus(milestone.name);
                    if (status === "planned" || status === "approaching") {
                        milestones.push(milestone);
                    }
                }
                // Get risks
                const riskQuery = await knowledgeGraphManager.searchNodes("entityType:risk");
                const risks = [];
                // Filter for high priority risks
                for (const risk of riskQuery.entities) {
                    const priority = await knowledgeGraphManager.getEntityPriority(risk.name);
                    if (priority === "high") {
                        risks.push(risk);
                    }
                }
                // Prepare display text with truncated previews
                const projectsText = await Promise.all(projects.map(async (p) => {
                    const status = await knowledgeGraphManager.getEntityStatus(p.name) || "Unknown";
                    const priority = await knowledgeGraphManager.getEntityPriority(p.name);
                    const priorityText = priority ? `, Priority: ${priority}` : "";
                    // Show truncated preview of first observation
                    const preview = p.observations.length > 0
                        ? `${p.observations[0].substring(0, 60)}${p.observations[0].length > 60 ? '...' : ''}`
                        : "No description";
                    return `- **${p.name}** (Status: ${status}${priorityText}): ${preview}`;
                }));
                const tasksText = await Promise.all(tasks.slice(0, 10).map(async (t) => {
                    const status = await knowledgeGraphManager.getEntityStatus(t.name) || "Unknown";
                    const priority = await knowledgeGraphManager.getEntityPriority(t.name) || "Unknown";
                    const projectObs = t.observations.find(o => o.startsWith("project:"));
                    const project = projectObs ? projectObs.substring(8) : "Unknown project";
                    // Show truncated preview of first non-project observation
                    const nonProjectObs = t.observations.find(o => !o.startsWith("project:"));
                    const preview = nonProjectObs
                        ? `${nonProjectObs.substring(0, 60)}${nonProjectObs.length > 60 ? '...' : ''}`
                        : "No description";
                    return `- **${t.name}** (Project: ${project}, Status: ${status}, Priority: ${priority}): ${preview}`;
                }));
                const milestonesText = await Promise.all(milestones.slice(0, 8).map(async (m) => {
                    const status = await knowledgeGraphManager.getEntityStatus(m.name) || "Unknown";
                    const projectObs = m.observations.find(o => o.startsWith("project:"));
                    const project = projectObs ? projectObs.substring(8) : "Unknown project";
                    // Show truncated preview of first non-project observation
                    const nonProjectObs = m.observations.find(o => !o.startsWith("project:"));
                    const preview = nonProjectObs
                        ? `${nonProjectObs.substring(0, 60)}${nonProjectObs.length > 60 ? '...' : ''}`
                        : "No description";
                    return `- **${m.name}** (Project: ${project}, Status: ${status}): ${preview}`;
                }));
                const risksText = await Promise.all(risks.slice(0, 5).map(async (r) => {
                    const priority = await knowledgeGraphManager.getEntityPriority(r.name) || "Unknown";
                    const projectObs = r.observations.find(o => o.startsWith("project:"));
                    const project = projectObs ? projectObs.substring(8) : "Unknown project";
                    // Show truncated preview of first non-project observation
                    const nonProjectObs = r.observations.find(o => !o.startsWith("project:"));
                    const preview = nonProjectObs
                        ? `${nonProjectObs.substring(0, 60)}${nonProjectObs.length > 60 ? '...' : ''}`
                        : "No description";
                    return `- **${r.name}** (Project: ${project}, Priority: ${priority}): ${preview}`;
                }));
                const sessionsText = recentSessions.map(s => {
                    return `- ${s.project} - ${s.summary.substring(0, 60)}${s.summary.length > 60 ? '...' : ''}`;
                }).join("\n");
                return {
                    content: [{
                            type: "text",
                            text: `# Choose what to focus on in this session

## Session ID
\`${sessionId}\`

## Recent Project Management Sessions
${sessionsText || "No recent sessions found."}

## Active Projects
${projectsText.join("\n") || "No active projects found."}

## High-Priority Tasks
${tasksText.join("\n") || "No high-priority tasks found."}

## Upcoming Milestones
${milestonesText.join("\n") || "No upcoming milestones found."}

## Top Project Risks
${risksText.join("\n") || "No high severity risks identified."}

To load specific project context, use the \`loadcontext\` tool with the project name and session ID - ${sessionId}`
                        }]
                };
            }
            catch (error) {
                return {
                    content: [{
                            type: "text",
                            text: JSON.stringify({
                                success: false,
                                error: error instanceof Error ? error.message : String(error)
                            }, null, 2)
                        }]
                };
            }
        });
        /**
         * Load context for a specific entity
         */
        server.tool("loadcontext", toolDescriptions["loadcontext"], {
            entityName: z.string(),
            entityType: z.string().optional(),
            sessionId: z.string().optional() // Optional to maintain backward compatibility
        }, async ({ entityName, entityType = "project", sessionId }) => {
            try {
                // Validate session if ID is provided
                if (sessionId) {
                    const sessionStates = await loadSessionStates();
                    if (!sessionStates.has(sessionId)) {
                        console.warn(`Warning: Session ${sessionId} not found, but proceeding with context load`);
                        // Initialize it anyway for more robustness
                        sessionStates.set(sessionId, []);
                        await saveSessionStates(sessionStates);
                    }
                    // Track that this entity was loaded in this session
                    const sessionState = sessionStates.get(sessionId) || [];
                    const loadEvent = {
                        type: 'context_loaded',
                        timestamp: new Date().toISOString(),
                        entityName,
                        entityType
                    };
                    sessionState.push(loadEvent);
                    sessionStates.set(sessionId, sessionState);
                    await saveSessionStates(sessionStates);
                }
                // Get the entity
                // Changed from using 'name:' prefix to directly searching by the entity name
                const entityGraph = await knowledgeGraphManager.searchNodes(entityName);
                if (entityGraph.entities.length === 0) {
                    throw new Error(`Entity ${entityName} not found`);
                }
                // Find the exact entity by name (case-sensitive match)
                const entity = entityGraph.entities.find(e => e.name === entityName);
                if (!entity) {
                    throw new Error(`Entity ${entityName} not found`);
                }
                // Different context loading based on entity type
                let contextMessage = "";
                if (entityType === "project") {
                    // Get project overview
                    const projectOverview = await knowledgeGraphManager.getProjectOverview(entityName);
                    // Get status and priority using relation-based approach
                    const status = await knowledgeGraphManager.getEntityStatus(entityName) || "Unknown";
                    const priority = await knowledgeGraphManager.getEntityPriority(entityName);
                    const priorityText = priority ? `- **Priority**: ${priority}` : "";
                    // Format observations without truncation or pattern matching
                    const observationsList = entity.observations.length > 0
                        ? entity.observations.map(obs => `- ${obs}`).join("\n")
                        : "No observations";
                    // Format tasks
                    const tasksText = await Promise.all((projectOverview.tasks || []).map(async (task) => {
                        const taskStatus = await knowledgeGraphManager.getEntityStatus(task.name) || "Unknown";
                        const taskPriority = await knowledgeGraphManager.getEntityPriority(task.name) || "Not set";
                        // Find the first observation that doesn't look like metadata
                        const description = task.observations.find(o => !o.startsWith('Project:') &&
                            !o.includes(':')) || "No description";
                        return `- **${task.name}** (Status: ${taskStatus}, Priority: ${taskPriority}): ${description}`;
                    }));
                    // Format milestones
                    const milestonesText = await Promise.all((projectOverview.milestones || []).map(async (milestone) => {
                        const milestoneStatus = await knowledgeGraphManager.getEntityStatus(milestone.name) || "Unknown";
                        // Find the first observation that doesn't look like metadata
                        const description = milestone.observations.find(o => !o.startsWith('Project:') &&
                            !o.includes(':')) || "No description";
                        return `- **${milestone.name}** (Status: ${milestoneStatus}): ${description}`;
                    }));
                    // Format issues
                    const issuesText = await Promise.all((projectOverview.issues || []).map(async (issue) => {
                        const issueStatus = await knowledgeGraphManager.getEntityStatus(issue.name) || "Unknown";
                        const issuePriority = await knowledgeGraphManager.getEntityPriority(issue.name) || "Not set";
                        // Find the first observation that doesn't look like metadata
                        const description = issue.observations.find(o => !o.startsWith('Project:') &&
                            !o.includes(':')) || "No description";
                        return `- **${issue.name}** (Status: ${issueStatus}, Priority: ${issuePriority}): ${description}`;
                    }));
                    // Format team members
                    const teamMembersText = (projectOverview.teamMembers || []).map((member) => {
                        const role = member.observations.find(o => o.startsWith('Role:'))?.split(':', 2)[1]?.trim() || 'Not specified';
                        return `- **${member.name}** (Role: ${role})`;
                    }).join("\n") || "No team members found";
                    // Format risks
                    const risksText = await Promise.all((projectOverview.risks || []).map(async (risk) => {
                        const riskStatus = await knowledgeGraphManager.getEntityStatus(risk.name) || "Unknown";
                        const riskPriority = await knowledgeGraphManager.getEntityPriority(risk.name) || "Not set";
                        // Find the first observation that doesn't look like metadata
                        const description = risk.observations.find(o => !o.startsWith('Project:') &&
                            !o.includes(':')) || "No description";
                        return `- **${risk.name}** (Status: ${riskStatus}, Priority: ${riskPriority}): ${description}`;
                    }));
                    contextMessage = `# Project Context: ${entityName}

## Project Overview
- **Status**: ${status}
${priorityText}

## Observations
${observationsList}

## Tasks (${projectOverview.summary.completedTasks || 0}/${projectOverview.summary.taskCount || 0} completed)
${tasksText.join("\n") || "No tasks found"}

## Milestones
${milestonesText.join("\n") || "No milestones found"}

## Issues
${issuesText.join("\n") || "No issues found"}

## Team Members
${teamMembersText}

## Risks
${risksText.join("\n") || "No risks found"}`;
                }
                else if (entityType === "task") {
                    // Get task dependencies and information
                    const taskDependencies = await knowledgeGraphManager.getTaskDependencies(entityName);
                    // Get project name
                    const projectName = taskDependencies.projectName || "Unknown project";
                    // Get status and priority using relation-based approach
                    const status = await knowledgeGraphManager.getEntityStatus(entityName) || "Unknown";
                    const priority = await knowledgeGraphManager.getEntityPriority(entityName) || "Not set";
                    // Format observations without truncation or pattern matching
                    const observationsList = entity.observations.length > 0
                        ? entity.observations.map(obs => `- ${obs}`).join("\n")
                        : "No observations";
                    // Get assignee if available
                    let assigneeText = "No assignee";
                    for (const relation of entityGraph.relations) {
                        if (relation.relationType === 'assigned_to' && relation.from === entityName) {
                            const teamMember = entityGraph.entities.find(e => e.name === relation.to && e.entityType === 'teamMember');
                            if (teamMember) {
                                assigneeText = teamMember.name;
                                break;
                            }
                        }
                    }
                    // Get precedes/follows relations to show task sequence
                    const precedesRelations = entityGraph.relations.filter(r => r.relationType === 'precedes' && r.from === entityName);
                    const followsRelations = entityGraph.relations.filter(r => r.relationType === 'precedes' && r.to === entityName);
                    const precedesText = precedesRelations.length > 0
                        ? precedesRelations.map(r => `- **${r.to}**`).join("\n")
                        : "No tasks follow this task";
                    const followsText = followsRelations.length > 0
                        ? followsRelations.map(r => `- **${r.from}**`).join("\n")
                        : "No tasks precede this task";
                    // Process dependency information
                    const dependsOnTasks = [];
                    const dependedOnByTasks = [];
                    for (const dep of taskDependencies.dependencies) {
                        if (dep.task.name !== entityName) {
                            if (dep.dependsOn.includes(entityName)) {
                                dependsOnTasks.push(dep.task);
                            }
                            if (dep.dependedOnBy.includes(entityName)) {
                                dependedOnByTasks.push(dep.task);
                            }
                        }
                    }
                    // Format dependencies with async status lookup
                    const dependsOnPromises = dependsOnTasks.map(async (task) => {
                        const depStatus = await knowledgeGraphManager.getEntityStatus(task.name) || "Unknown";
                        return `- **${task.name}** (Status: ${depStatus}): This task depends on ${entityName}`;
                    });
                    const dependedOnByPromises = dependedOnByTasks.map(async (task) => {
                        const depStatus = await knowledgeGraphManager.getEntityStatus(task.name) || "Unknown";
                        return `- **${task.name}** (Status: ${depStatus}): ${entityName} depends on this task`;
                    });
                    const dependsOnText = (await Promise.all(dependsOnPromises)).join("\n") || "No tasks depend on this task";
                    const dependedOnByText = (await Promise.all(dependedOnByPromises)).join("\n") || "This task doesn't depend on other tasks";
                    // Determine if task is on critical path
                    const onCriticalPath = taskDependencies.criticalPath?.includes(entityName);
                    const criticalPathText = onCriticalPath ?
                        "⚠️ This task is on the critical path. Delays will impact the project timeline." :
                        "This task is not on the critical path.";
                    contextMessage = `# Task Context: ${entityName}

## Task Overview
- **Project**: ${projectName}
- **Status**: ${status}
- **Priority**: ${priority}
- **Assignee**: ${assigneeText}
- **Critical Path**: ${criticalPathText}

## Observations
${observationsList}

## Task Sequencing
### Tasks That Follow This Task
${precedesText}

### Tasks That Precede This Task
${followsText}

## Task Dependencies
### Tasks That Depend On This Task
${dependsOnText}

### Tasks This Task Depends On
${dependedOnByText}`;
                }
                else if (entityType === "milestone") {
                    // Get milestone progress
                    const projectName = entity.observations.find(o => o.startsWith('Project:'))?.split(':', 2)[1]?.trim();
                    if (!projectName) {
                        throw new Error(`Project not found for milestone ${entityName}`);
                    }
                    const milestoneProgress = await knowledgeGraphManager.getMilestoneProgress(projectName, entityName);
                    if (!milestoneProgress || !milestoneProgress.milestones || milestoneProgress.milestones.length === 0) {
                        throw new Error(`Milestone progress data not available for ${entityName}`);
                    }
                    // Find this milestone
                    const milestone = milestoneProgress.milestones.find((m) => m.milestone.name === entityName);
                    if (!milestone) {
                        throw new Error(`Milestone ${entityName} not found in progress data`);
                    }
                    // Format milestone context
                    const description = milestone.info.description || "No description available";
                    const date = milestone.info.date || "Not set";
                    const status = milestone.info.status || "planned";
                    const criteria = milestone.info.criteria || "Not specified";
                    // Format tasks required for this milestone
                    const tasksText = milestone.relatedTasks?.map((task) => {
                        const taskStatus = task.observations.find(o => o.startsWith('Status:'))?.split(':', 2)[1]?.trim() || 'not_started';
                        return `- **${task.name}** (Status: ${taskStatus})`;
                    }).join("\n") || "No tasks found";
                    // Format blockers
                    const blockersText = milestone.blockers?.map((task) => {
                        const taskStatus = task.observations.find(o => o.startsWith('Status:'))?.split(':', 2)[1]?.trim() || 'not_started';
                        return `- **${task.name}** (Status: ${taskStatus})`;
                    }).join("\n") || "No blocking tasks";
                    contextMessage = `# Milestone Context: ${entityName}

## Milestone Details
- **Project**: ${projectName}
- **Status**: ${status}
- **Date**: ${date}
- **Completion Criteria**: ${criteria}
- **Description**: ${description}
- **Progress**: ${milestone.progress.completionPercentage || 0}% complete
- **Days Remaining**: ${milestone.progress.daysRemaining !== null ? milestone.progress.daysRemaining : 'Unknown'}
- **Overdue**: ${milestone.progress.isOverdue ? 'Yes' : 'No'}

## Required Tasks (${milestone.progress.completedTasks || 0}/${milestone.progress.totalTasks || 0} completed)
${tasksText}

## Blocking Tasks
${blockersText}`;
                }
                else if (entityType === "teamMember") {
                    // Get team member assignments
                    const teamMemberAssignments = await knowledgeGraphManager.getTeamMemberAssignments(entityName);
                    // Format team member context
                    const role = teamMemberAssignments.info.role || "Not specified";
                    const skills = teamMemberAssignments.info.skills || "Not specified";
                    const availability = teamMemberAssignments.info.availability || "Not specified";
                    // Format assigned tasks
                    const tasksText = teamMemberAssignments.assignedTasks?.map((assignment) => {
                        return `- **${assignment.task.name}** (Project: ${assignment.project?.name || 'Unassigned'}, Status: ${assignment.status}, Due: ${assignment.dueDate || 'Not set'})`;
                    }).join("\n") || "No tasks assigned";
                    // Format projects
                    const projectsText = teamMemberAssignments.projects?.map((project) => {
                        return `- **${project.name}**`;
                    }).join("\n") || "Not assigned to any projects";
                    // Format deadlines
                    const deadlinesText = teamMemberAssignments.upcomingDeadlines?.map((assignment) => {
                        return `- **${assignment.task.name}** (Due: ${assignment.dueDate})`;
                    }).join("\n") || "No upcoming deadlines";
                    // Format overdue tasks
                    const overdueText = teamMemberAssignments.overdueTasks?.map((assignment) => {
                        return `- **${assignment.task.name}** (Due: ${assignment.dueDate})`;
                    }).join("\n") || "No overdue tasks";
                    contextMessage = `# Team Member Context: ${entityName}

## Team Member Details
- **Role**: ${role}
- **Skills**: ${skills}
- **Availability**: ${availability}
- **Workload**: ${teamMemberAssignments.assignedTasks.length} tasks assigned (${teamMemberAssignments.workload.completionRate}% completed)

## Assigned Tasks
${tasksText}

## Projects
${projectsText}

## Upcoming Deadlines
${deadlinesText}

## Overdue Tasks
${overdueText}`;
                }
                else if (entityType === "resource") {
                    // Find which project this resource belongs to
                    let projectName = 'Unknown project';
                    for (const relation of entityGraph.relations) {
                        if (relation.relationType === 'part_of' && relation.from === entityName) {
                            const project = entityGraph.entities.find(e => e.name === relation.to && e.entityType === 'project');
                            if (project) {
                                projectName = project.name;
                                break;
                            }
                        }
                    }
                    // Get resource allocation
                    const resourceAllocation = await knowledgeGraphManager.getResourceAllocation(projectName, entityName);
                    if (!resourceAllocation || !resourceAllocation.resources || resourceAllocation.resources.length === 0) {
                        throw new Error(`Resource allocation data not available for ${entityName}`);
                    }
                    // Find this resource
                    const resource = resourceAllocation.resources.find((r) => r.resource.name === entityName);
                    if (!resource) {
                        throw new Error(`Resource ${entityName} not found in allocation data`);
                    }
                    // Format resource context
                    const type = resource.info.type || "Not specified";
                    const availability = resource.info.availability || "Not specified";
                    const capacity = resource.info.capacity || "Not specified";
                    const cost = resource.info.cost || "Not specified";
                    // Format assigned tasks
                    const tasksText = resource.assignedTasks?.map((task) => {
                        const status = task.observations.find(o => o.startsWith('Status:'))?.split(':', 2)[1]?.trim() || 'not_started';
                        return `- **${task.name}** (Status: ${status})`;
                    }).join("\n") || "No tasks assigned";
                    // Format team members using this resource
                    const teamMembersText = resource.teamMembers?.map((member) => {
                        return `- **${member.name}**`;
                    }).join("\n") || "No team members assigned";
                    contextMessage = `# Resource Context: ${entityName}

## Resource Details
- **Type**: ${type}
- **Project**: ${projectName}
- **Availability**: ${availability}
- **Capacity**: ${capacity}
- **Cost**: ${cost}
- **Usage**: ${resource.usage.usagePercentage}% (${resource.usage.inProgressTasks} tasks in progress)

## Assigned Tasks
${tasksText}

## Team Members Using This Resource
${teamMembersText}`;
                }
                else {
                    // Generic entity context for other entity types
                    // Find all relations involving this entity
                    const relations = await knowledgeGraphManager.openNodes([entityName]);
                    // Build a text representation of related entities
                    const incomingRelations = relations.relations.filter(r => r.to === entityName);
                    const outgoingRelations = relations.relations.filter(r => r.from === entityName);
                    const incomingText = incomingRelations.map(rel => {
                        const sourceEntity = relations.entities.find(e => e.name === rel.from);
                        if (!sourceEntity)
                            return null;
                        return `- **${sourceEntity.name}** (${sourceEntity.entityType}) → ${rel.relationType} → ${entityName}`;
                    }).filter(Boolean).join("\n") || "No incoming relations";
                    const outgoingText = outgoingRelations.map(rel => {
                        const targetEntity = relations.entities.find(e => e.name === rel.to);
                        if (!targetEntity)
                            return null;
                        return `- **${entityName}** → ${rel.relationType} → **${targetEntity.name}** (${targetEntity.entityType})`;
                    }).filter(Boolean).join("\n") || "No outgoing relations";
                    // Format observations
                    const observationsText = entity.observations.map((obs) => `- ${obs}`).join("\n") || "No observations";
                    contextMessage = `# Entity Context: ${entityName} (${entityType})

## Observations
${observationsText}

## Incoming Relations
${incomingText}

## Outgoing Relations
${outgoingText}`;
                }
                return {
                    content: [{
                            type: "text",
                            text: contextMessage
                        }]
                };
            }
            catch (error) {
                return {
                    content: [{
                            type: "text",
                            text: JSON.stringify({
                                success: false,
                                error: error instanceof Error ? error.message : String(error)
                            }, null, 2)
                        }]
                };
            }
        });
        // Helper function to process each stage of endsession
        async function processStage(params, previousStages) {
            // Process based on the stage
            switch (params.stage) {
                case "summary":
                    // Process summary stage
                    return {
                        stage: "summary",
                        stageNumber: params.stageNumber,
                        analysis: params.analysis || "",
                        stageData: params.stageData || {
                            summary: "",
                            duration: "",
                            project: ""
                        },
                        completed: !params.nextStageNeeded
                    };
                case "achievements":
                    // Process achievements stage
                    return {
                        stage: "achievements",
                        stageNumber: params.stageNumber,
                        analysis: params.analysis || "",
                        stageData: params.stageData || { achievements: [] },
                        completed: !params.nextStageNeeded
                    };
                case "taskUpdates":
                    // Process task updates stage
                    return {
                        stage: "taskUpdates",
                        stageNumber: params.stageNumber,
                        analysis: params.analysis || "",
                        stageData: params.stageData || { updates: [] },
                        completed: !params.nextStageNeeded
                    };
                case "newTasks":
                    // Process new tasks stage
                    return {
                        stage: "newTasks",
                        stageNumber: params.stageNumber,
                        analysis: params.analysis || "",
                        stageData: params.stageData || { tasks: [] },
                        completed: !params.nextStageNeeded
                    };
                case "projectStatus":
                    // Process project status stage
                    return {
                        stage: "projectStatus",
                        stageNumber: params.stageNumber,
                        analysis: params.analysis || "",
                        stageData: params.stageData || {
                            projectStatus: "",
                            projectObservation: ""
                        },
                        completed: !params.nextStageNeeded
                    };
                case "riskUpdates":
                    // Process risk updates stage
                    return {
                        stage: "riskUpdates",
                        stageNumber: params.stageNumber,
                        analysis: params.analysis || "",
                        stageData: params.stageData || { risks: [] },
                        completed: !params.nextStageNeeded
                    };
                case "assembly":
                    // Final assembly stage - compile all arguments for end-session
                    return {
                        stage: "assembly",
                        stageNumber: params.stageNumber,
                        analysis: "Final assembly of end-session arguments",
                        stageData: assembleEndSessionArgs(previousStages),
                        completed: true
                    };
                default:
                    throw new Error(`Unknown stage: ${params.stage}`);
            }
        }
        // Helper function to assemble the final end-session arguments
        function assembleEndSessionArgs(stages) {
            const summaryStage = stages.find(s => s.stage === "summary");
            const achievementsStage = stages.find(s => s.stage === "achievements");
            const taskUpdatesStage = stages.find(s => s.stage === "taskUpdates");
            const newTasksStage = stages.find(s => s.stage === "newTasks");
            const projectStatusStage = stages.find(s => s.stage === "projectStatus");
            const riskUpdatesStage = stages.find(s => s.stage === "riskUpdates");
            return {
                summary: summaryStage?.stageData?.summary || "",
                duration: summaryStage?.stageData?.duration || "unknown",
                project: summaryStage?.stageData?.project || "",
                achievements: JSON.stringify(achievementsStage?.stageData?.achievements || []),
                taskUpdates: JSON.stringify(taskUpdatesStage?.stageData?.updates || []),
                projectStatus: projectStatusStage?.stageData?.projectStatus || "",
                projectObservation: projectStatusStage?.stageData?.projectObservation || "",
                newTasks: JSON.stringify(newTasksStage?.stageData?.tasks || []),
                riskUpdates: JSON.stringify(riskUpdatesStage?.stageData?.risks || [])
            };
        }
        /**
         * End session by processing all stages and recording the final results.
         * Only use this tool if the user asks for it.
         *
         * Usage examples:
         *
         * 1. Starting the end session process with the summary stage:
         * {
         *   "sessionId": "proj_1234567890_abc123",  // From startsession
         *   "stage": "summary",
         *   "stageNumber": 1,
         *   "totalStages": 6,
         *   "analysis": "Analyzed progress on the marketing campaign project",
         *   "stageData": {
         *     "summary": "Completed the social media strategy components",
         *     "duration": "4 hours",
         *     "project": "Q4 Marketing Campaign"  // Project name
         *   },
         *   "nextStageNeeded": true,  // More stages coming
         *   "isRevision": false
         * }
         *
         * 2. Middle stage for milestones:
         * {
         *   "sessionId": "proj_1234567890_abc123",
         *   "stage": "milestones",
         *   "stageNumber": 2,
         *   "totalStages": 6,
         *   "analysis": "Updated milestone progress",
         *   "stageData": {
         *     "milestones": [
         *       { "name": "Content Creation", "status": "completed", "notes": "All blog posts and social media content finished" },
         *       { "name": "Channel Selection", "status": "in_progress", "notes": "Evaluating performance of different platforms" }
         *     ]
         *   },
         *   "nextStageNeeded": true,
         *   "isRevision": false
         * }
         *
         * 3. Final assembly stage:
         * {
         *   "sessionId": "proj_1234567890_abc123",
         *   "stage": "assembly",
         *   "stageNumber": 6,
         *   "totalStages": 6,
         *   "nextStageNeeded": false,  // This completes the session
         *   "isRevision": false
         * }
         */
        server.tool("endsession", toolDescriptions["endsession"], {
            sessionId: z.string().describe("The unique session identifier obtained from startsession"),
            stage: z.string().describe("Current stage of analysis: 'summary', 'milestones', 'risks', 'tasks', 'teamUpdates', or 'assembly'"),
            stageNumber: z.number().int().positive().describe("The sequence number of the current stage (starts at 1)"),
            totalStages: z.number().int().positive().describe("Total number of stages in the workflow (typically 6 for standard workflow)"),
            analysis: z.string().optional().describe("Text analysis or observations for the current stage"),
            stageData: z.record(z.string(), z.any()).optional().describe(`Stage-specific data structure - format depends on the stage type:
        - For 'summary' stage: { summary: "Session summary text", duration: "4 hours", project: "Project Name" }
        - For 'milestones' stage: { milestones: [{ name: "Milestone1", status: "completed", notes: "Notes about completion" }] }
        - For 'risks' stage: { risks: [{ name: "Risk1", severity: "high", mitigation: "Plan to address this risk" }] }
        - For 'tasks' stage: { tasks: [{ name: "Task1", status: "in_progress", assignee: "Team Member", notes: "Status update" }] }
        - For 'teamUpdates' stage: { teamUpdates: [{ member: "Team Member", status: "Completed assigned tasks", blockers: "None" }] }
        - For 'assembly' stage: no stageData needed - automatic assembly of previous stages`),
            nextStageNeeded: z.boolean().describe("Whether additional stages are needed after this one (false for final stage)"),
            isRevision: z.boolean().optional().describe("Whether this is revising a previous stage"),
            revisesStage: z.number().int().positive().optional().describe("If revising, which stage number is being revised")
        }, async (params, extra) => {
            try {
                // Load session states from persistent storage
                const sessionStates = await loadSessionStates();
                // Validate session ID
                if (!sessionStates.has(params.sessionId)) {
                    return {
                        content: [{
                                type: "text",
                                text: JSON.stringify({
                                    success: false,
                                    error: `Session with ID ${params.sessionId} not found. Please start a new session with startsession.`
                                }, null, 2)
                            }]
                    };
                }
                // Get or initialize session state
                let sessionState = sessionStates.get(params.sessionId) || [];
                // Process the current stage
                const stageResult = await processStage(params, sessionState);
                // Store updated state
                if (params.isRevision && params.revisesStage) {
                    // Find the analysis stages in the session state
                    const analysisStages = sessionState.filter(item => item.type === 'analysis_stage') || [];
                    if (params.revisesStage <= analysisStages.length) {
                        // Replace the revised stage
                        analysisStages[params.revisesStage - 1] = {
                            type: 'analysis_stage',
                            ...stageResult
                        };
                    }
                    else {
                        // Add as a new stage
                        analysisStages.push({
                            type: 'analysis_stage',
                            ...stageResult
                        });
                    }
                    // Update the session state with the modified analysis stages
                    sessionState = [
                        ...sessionState.filter(item => item.type !== 'analysis_stage'),
                        ...analysisStages
                    ];
                }
                else {
                    // Add new stage
                    sessionState.push({
                        type: 'analysis_stage',
                        ...stageResult
                    });
                }
                // Update in persistent storage
                sessionStates.set(params.sessionId, sessionState);
                await saveSessionStates(sessionStates);
                // Check if this is the final assembly stage and no more stages are needed
                if (params.stage === "assembly" && !params.nextStageNeeded) {
                    // Get the assembled arguments
                    const args = stageResult.stageData;
                    try {
                        // Parse arguments
                        const summary = args.summary;
                        const duration = args.duration;
                        const project = args.project;
                        const achievements = args.achievements ? JSON.parse(args.achievements) : [];
                        const taskUpdates = args.taskUpdates ? JSON.parse(args.taskUpdates) : [];
                        const projectStatus = args.projectStatus;
                        const projectObservation = args.projectObservation;
                        const newTasks = args.newTasks ? JSON.parse(args.newTasks) : [];
                        const riskUpdates = args.riskUpdates ? JSON.parse(args.riskUpdates) : [];
                        // Create a timestamp to use for entity naming
                        const timestamp = new Date().getTime().toString();
                        // Create achievement entities and link them to the project
                        const achievementEntities = await Promise.all(achievements.map(async (achievement, index) => {
                            const achievementName = `achievement_${timestamp}_${index}`;
                            await knowledgeGraphManager.createEntities([{
                                    name: achievementName,
                                    entityType: 'decision',
                                    observations: [achievement],
                                    embedding: undefined
                                }]);
                            await knowledgeGraphManager.createRelations([{
                                    from: achievementName,
                                    to: project,
                                    relationType: 'part_of',
                                    observations: []
                                }]);
                            return achievementName;
                        }));
                        // Update task statuses using entity-relation approach
                        await Promise.all(taskUpdates.map(async (taskUpdate) => {
                            try {
                                // Map task status to standard values
                                let standardStatus = taskUpdate.status;
                                if (taskUpdate.status === 'completed' || taskUpdate.status === 'done' || taskUpdate.status === 'finished') {
                                    standardStatus = 'completed';
                                }
                                else if (taskUpdate.status === 'in_progress' || taskUpdate.status === 'ongoing' || taskUpdate.status === 'started') {
                                    standardStatus = 'active';
                                }
                                else if (taskUpdate.status === 'not_started' || taskUpdate.status === 'planned' || taskUpdate.status === 'upcoming') {
                                    standardStatus = 'inactive';
                                }
                                // Update the task status using the entity-relation approach
                                await knowledgeGraphManager.setEntityStatus(taskUpdate.name, standardStatus);
                                // If the task is completed, link it to the current session
                                if (standardStatus === 'completed') {
                                    await knowledgeGraphManager.createRelations([{
                                            from: params.sessionId,
                                            to: taskUpdate.name,
                                            relationType: 'resolves',
                                            observations: []
                                        }]);
                                }
                                // Add progress as an observation if provided
                                if (taskUpdate.progress) {
                                    await knowledgeGraphManager.addObservations(taskUpdate.name, [`Progress: ${taskUpdate.progress}`]);
                                }
                            }
                            catch (error) {
                                console.error(`Error updating task ${taskUpdate.name}: ${error}`);
                            }
                        }));
                        // Update project status if specified
                        if (project && projectStatus) {
                            try {
                                // Map project status to standard values
                                let standardStatus = projectStatus;
                                if (projectStatus === 'completed' || projectStatus === 'done' || projectStatus === 'finished') {
                                    standardStatus = 'completed';
                                }
                                else if (projectStatus === 'in_progress' || projectStatus === 'ongoing' || projectStatus === 'active') {
                                    standardStatus = 'active';
                                }
                                else if (projectStatus === 'not_started' || projectStatus === 'planned' || projectStatus === 'upcoming') {
                                    standardStatus = 'inactive';
                                }
                                // Update the project status using the entity-relation approach
                                await knowledgeGraphManager.setEntityStatus(project, standardStatus);
                                // Add project observation if provided
                                if (projectObservation) {
                                    await knowledgeGraphManager.addObservations(project, [projectObservation]);
                                }
                            }
                            catch (error) {
                                console.error(`Error updating project ${project}: ${error}`);
                            }
                        }
                        // Create new tasks with specified attributes
                        const newTaskEntities = await Promise.all(newTasks.map(async (task) => {
                            try {
                                // Create the task entity
                                await knowledgeGraphManager.createEntities([{
                                        name: task.name,
                                        entityType: 'task',
                                        observations: [
                                            task.description ? `Description: ${task.description}` : 'No description'
                                        ],
                                        embedding: undefined
                                    }]);
                                // Set task priority using entity-relation approach
                                const priority = task.priority || 'N/A';
                                await knowledgeGraphManager.setEntityPriority(task.name, priority);
                                // Set task status to active by default using entity-relation approach
                                await knowledgeGraphManager.setEntityStatus(task.name, 'active');
                                // Link the task to the project
                                await knowledgeGraphManager.createRelations([{
                                        from: task.name,
                                        to: project,
                                        relationType: 'part_of',
                                        observations: []
                                    }]);
                                // Handle task sequencing if specified
                                if (task.precedes) {
                                    await knowledgeGraphManager.createRelations([{
                                            from: task.name,
                                            to: task.precedes,
                                            relationType: 'precedes',
                                            observations: []
                                        }]);
                                }
                                if (task.follows) {
                                    await knowledgeGraphManager.createRelations([{
                                            from: task.follows,
                                            to: task.name,
                                            relationType: 'precedes',
                                            observations: []
                                        }]);
                                }
                                return task.name;
                            }
                            catch (error) {
                                console.error(`Error creating task ${task.name}: ${error}`);
                                return null;
                            }
                        }));
                        // Process risk updates
                        await Promise.all(riskUpdates.map(async (risk) => {
                            try {
                                // Try to find the risk entity, create it if it doesn't exist
                                const riskEntity = (await knowledgeGraphManager.openNodes([risk.name])).entities
                                    .find(e => e.name === risk.name && e.entityType === 'risk');
                                if (!riskEntity) {
                                    // Create new risk entity
                                    await knowledgeGraphManager.createEntities([{
                                            name: risk.name,
                                            entityType: 'risk',
                                            observations: [],
                                            embedding: undefined
                                        }]);
                                    // Link it to the project
                                    await knowledgeGraphManager.createRelations([{
                                            from: risk.name,
                                            to: project,
                                            relationType: 'part_of',
                                            observations: []
                                        }]);
                                }
                                // Update risk status using entity-relation approach
                                await knowledgeGraphManager.setEntityStatus(risk.name, risk.status);
                                // Add risk observation if provided
                                if (risk.impact) {
                                    await knowledgeGraphManager.addObservations(risk.name, [`Impact: ${risk.impact}`, `Probability: ${risk.probability}`]);
                                }
                            }
                            catch (error) {
                                console.error(`Error updating risk ${risk.name}: ${error}`);
                            }
                        }));
                        // Record session completion in persistent storage
                        sessionState.push({
                            type: 'session_completed',
                            timestamp: new Date().toISOString(),
                            summary: summary,
                            project: project
                        });
                        sessionStates.set(params.sessionId, sessionState);
                        await saveSessionStates(sessionStates);
                        // Prepare the summary message
                        const summaryMessage = `# Project Session Recorded

I've recorded your project session focusing on ${project}.

## Decisions Documented
${achievements.map((a) => `- ${a}`).join('\n') || "No decisions recorded."}

## Task Updates
${taskUpdates.map((t) => `- ${t.name}: ${t.status}${t.progress ? ` (Progress: ${t.progress})` : ''}`).join('\n') || "No task updates."}

## Project Status
Project ${project} has been updated to: ${projectStatus}

${newTasks && newTasks.length > 0 ? `## New Tasks Added
${newTasks.map((t) => `- ${t.name}: ${t.description} (Priority: ${t.priority || "N/A"})`).join('\n')}` : "No new tasks added."}

${riskUpdates && riskUpdates.length > 0 ? `## Risk Updates
${riskUpdates.map((r) => `- ${r.name}: Status ${r.status} (Impact: ${r.impact}, Probability: ${r.probability})`).join('\n')}` : "No risk updates."}

## Session Summary
${summary}

Would you like me to perform any additional updates to your project knowledge graph?`;
                        // Return the final result with the session recorded message
                        return {
                            content: [{
                                    type: "text",
                                    text: JSON.stringify({
                                        success: true,
                                        stageCompleted: params.stage,
                                        nextStageNeeded: false,
                                        stageResult: stageResult,
                                        sessionRecorded: true,
                                        summaryMessage: summaryMessage
                                    }, null, 2)
                                }]
                        };
                    }
                    catch (error) {
                        return {
                            content: [{
                                    type: "text",
                                    text: JSON.stringify({
                                        success: false,
                                        error: `Error recording project session: ${error instanceof Error ? error.message : String(error)}`
                                    }, null, 2)
                                }]
                        };
                    }
                }
                else {
                    // This is not the final stage or more stages are needed
                    // Return intermediate result
                    return {
                        content: [{
                                type: "text",
                                text: JSON.stringify({
                                    success: true,
                                    stageCompleted: params.stage,
                                    nextStageNeeded: params.nextStageNeeded,
                                    stageResult: stageResult,
                                    endSessionArgs: params.stage === "assembly" ? stageResult.stageData : null
                                }, null, 2)
                            }]
                    };
                }
            }
            catch (error) {
                return {
                    content: [{
                            type: "text",
                            text: JSON.stringify({
                                success: false,
                                error: error instanceof Error ? error.message : String(error)
                            }, null, 2)
                        }]
                };
            }
        });
        /**
         * Create entities, relations, and observations.
         */
        server.tool("buildcontext", toolDescriptions["buildcontext"], {
            type: z.enum(["entities", "relations", "observations"]).describe("Type of creation operation: 'entities', 'relations', or 'observations'"),
            data: z.array(z.any()).describe("Data for the creation operation, structure varies by type but must be an array")
        }, async ({ type, data }) => {
            try {
                let result;
                switch (type) {
                    case "entities":
                        // Ensure entities match the Entity interface
                        const typedEntities = data.map((e) => ({
                            name: e.name,
                            entityType: e.entityType,
                            observations: e.observations,
                            embedding: e.embedding
                        }));
                        result = await knowledgeGraphManager.createEntities(typedEntities);
                        return {
                            content: [{
                                    type: "text",
                                    text: JSON.stringify({ success: true, created: result }, null, 2)
                                }]
                        };
                    case "relations":
                        // Ensure relations match the Relation interface
                        const typedRelations = data.map((r) => ({
                            from: r.from,
                            to: r.to,
                            relationType: r.relationType,
                            observations: r.observations
                        }));
                        result = await knowledgeGraphManager.createRelations(typedRelations);
                        return {
                            content: [{
                                    type: "text",
                                    text: JSON.stringify({ success: true, created: result }, null, 2)
                                }]
                        };
                    case "observations":
                        // For project domain, addObservations takes entity name and observations
                        for (const item of data) {
                            if (item.entityName && Array.isArray(item.contents)) {
                                await knowledgeGraphManager.addObservations(item.entityName, item.contents);
                            }
                        }
                        return {
                            content: [{
                                    type: "text",
                                    text: JSON.stringify({ success: true, message: "Added observations to entities" }, null, 2)
                                }]
                        };
                    default:
                        throw new Error(`Invalid type: ${type}. Must be 'entities', 'relations', or 'observations'.`);
                }
            }
            catch (error) {
                return {
                    content: [{
                            type: "text",
                            text: JSON.stringify({
                                success: false,
                                error: error instanceof Error ? error.message : String(error)
                            }, null, 2)
                        }]
                };
            }
        });
        /**
         * Delete entities, relations, and observations.
         */
        server.tool("deletecontext", toolDescriptions["deletecontext"], {
            type: z.enum(["entities", "relations", "observations"]).describe("Type of deletion operation: 'entities', 'relations', or 'observations'"),
            data: z.array(z.any()).describe("Data for the deletion operation, structure varies by type but must be an array")
        }, async ({ type, data }) => {
            try {
                switch (type) {
                    case "entities":
                        await knowledgeGraphManager.deleteEntities(data);
                        return {
                            content: [{
                                    type: "text",
                                    text: JSON.stringify({ success: true, message: `Deleted ${data.length} entities` }, null, 2)
                                }]
                        };
                    case "relations":
                        // Ensure relations match the Relation interface
                        const typedRelations = data.map((r) => ({
                            from: r.from,
                            to: r.to,
                            relationType: r.relationType
                        }));
                        await knowledgeGraphManager.deleteRelations(typedRelations);
                        return {
                            content: [{
                                    type: "text",
                                    text: JSON.stringify({ success: true, message: `Deleted ${data.length} relations` }, null, 2)
                                }]
                        };
                    case "observations":
                        // Ensure deletions match the required interface
                        const typedDeletions = data.map((d) => ({
                            entityName: d.entityName,
                            observations: d.observations
                        }));
                        await knowledgeGraphManager.deleteObservations(typedDeletions);
                        return {
                            content: [{
                                    type: "text",
                                    text: JSON.stringify({ success: true, message: `Deleted observations from ${data.length} entities` }, null, 2)
                                }]
                        };
                    default:
                        throw new Error(`Invalid type: ${type}. Must be 'entities', 'relations', or 'observations'.`);
                }
            }
            catch (error) {
                return {
                    content: [{
                            type: "text",
                            text: JSON.stringify({
                                success: false,
                                error: error instanceof Error ? error.message : String(error)
                            }, null, 2)
                        }]
                };
            }
        });
        /**
         * Read the graph, search nodes, open nodes, get project overview, get task dependencies, get team member assignments, get milestone progress, get project timeline, get resource allocation, get project risks, find related projects, get decision log, and get project health.
         */
        server.tool("advancedcontext", toolDescriptions["advancedcontext"], {
            type: z.enum([
                "graph",
                "search",
                "nodes",
                "project",
                "dependencies",
                "assignments",
                "milestones",
                "timeline",
                "resources",
                "risks",
                "related",
                "decisions",
                "health"
            ]).describe("Type of get operation"),
            params: z.record(z.string(), z.any()).describe("Parameters for the get operation, structure varies by type")
        }, async ({ type, params }) => {
            try {
                let result;
                switch (type) {
                    case "graph":
                        result = await knowledgeGraphManager.readGraph();
                        return {
                            content: [{
                                    type: "text",
                                    text: JSON.stringify({ success: true, graph: result }, null, 2)
                                }]
                        };
                    case "search":
                        result = await knowledgeGraphManager.searchNodes(params.query);
                        return {
                            content: [{
                                    type: "text",
                                    text: JSON.stringify({ success: true, results: result }, null, 2)
                                }]
                        };
                    case "nodes":
                        result = await knowledgeGraphManager.openNodes(params.names);
                        return {
                            content: [{
                                    type: "text",
                                    text: JSON.stringify({ success: true, nodes: result }, null, 2)
                                }]
                        };
                    case "project":
                        result = await knowledgeGraphManager.getProjectOverview(params.projectName);
                        return {
                            content: [{
                                    type: "text",
                                    text: JSON.stringify({ success: true, project: result }, null, 2)
                                }]
                        };
                    case "dependencies":
                        result = await knowledgeGraphManager.getTaskDependencies(params.taskName, params.depth || 2);
                        return {
                            content: [{
                                    type: "text",
                                    text: JSON.stringify({ success: true, dependencies: result }, null, 2)
                                }]
                        };
                    case "assignments":
                        result = await knowledgeGraphManager.getTeamMemberAssignments(params.teamMemberName);
                        return {
                            content: [{
                                    type: "text",
                                    text: JSON.stringify({ success: true, assignments: result }, null, 2)
                                }]
                        };
                    case "milestones":
                        result = await knowledgeGraphManager.getMilestoneProgress(params.projectName, params.milestoneName);
                        return {
                            content: [{
                                    type: "text",
                                    text: JSON.stringify({ success: true, milestones: result }, null, 2)
                                }]
                        };
                    case "timeline":
                        result = await knowledgeGraphManager.getProjectTimeline(params.projectName);
                        return {
                            content: [{
                                    type: "text",
                                    text: JSON.stringify({ success: true, timeline: result }, null, 2)
                                }]
                        };
                    case "resources":
                        result = await knowledgeGraphManager.getResourceAllocation(params.projectName, params.resourceName);
                        return {
                            content: [{
                                    type: "text",
                                    text: JSON.stringify({ success: true, resources: result }, null, 2)
                                }]
                        };
                    case "risks":
                        result = await knowledgeGraphManager.getProjectRisks(params.projectName);
                        return {
                            content: [{
                                    type: "text",
                                    text: JSON.stringify({ success: true, risks: result }, null, 2)
                                }]
                        };
                    case "related":
                        result = await knowledgeGraphManager.findRelatedProjects(params.projectName, params.depth || 1);
                        return {
                            content: [{
                                    type: "text",
                                    text: JSON.stringify({ success: true, relatedProjects: result }, null, 2)
                                }]
                        };
                    case "decisions":
                        result = await knowledgeGraphManager.getDecisionLog(params.projectName);
                        return {
                            content: [{
                                    type: "text",
                                    text: JSON.stringify({ success: true, decisions: result }, null, 2)
                                }]
                        };
                    case "health":
                        result = await knowledgeGraphManager.getProjectHealth(params.projectName);
                        return {
                            content: [{
                                    type: "text",
                                    text: JSON.stringify({ success: true, health: result }, null, 2)
                                }]
                        };
                    default:
                        throw new Error(`Invalid type: ${type}. Must be one of the supported get operation types.`);
                }
            }
            catch (error) {
                return {
                    content: [{
                            type: "text",
                            text: JSON.stringify({
                                success: false,
                                error: error instanceof Error ? error.message : String(error)
                            }, null, 2)
                        }]
                };
            }
        });
        // Connect the server to the transport
        const transport = new StdioServerTransport();
        await server.connect(transport);
    }
    catch (error) {
        console.error("Error starting server:", error);
        process.exit(1);
    }
}
// Start the server
main().catch(error => {
    console.error('Fatal error:', error);
    process.exit(1);
});
// Export the KnowledgeGraphManager class for testing
export { KnowledgeGraphManager };

```
Page 9/9FirstPrevNextLast