UNPKG

squabble-mcp

Version:

Engineer-driven development with critical-thinking PM collaboration - MCP server for Claude

114 lines 4.03 kB
import fs from 'fs-extra'; import path from 'path'; export class WorkspaceManager { workspaceRoot; projectRoot; isInitialized = false; constructor() { // Get the current working directory (project root) this.projectRoot = process.cwd(); this.workspaceRoot = path.join(this.projectRoot, '.squabble'); // Check if already initialized this.isInitialized = fs.existsSync(this.workspaceRoot); } async initialize() { // Create workspace structure const directories = [ 'workspace/requirements', 'workspace/designs', 'workspace/decisions', 'workspace/tasks', 'workspace/reviews', // For review requests/responses 'workspace/context', 'workspace/plans', // For implementation plans 'archive' ]; for (const dir of directories) { await fs.ensureDir(path.join(this.workspaceRoot, dir)); } // Initialize default files if they don't exist const tasksFile = this.getTasksPath(); if (!await fs.pathExists(tasksFile)) { await this.saveTasks([]); } this.isInitialized = true; } checkInitialized() { if (!this.isInitialized) { throw new Error('Squabble workspace not initialized. Run init_workspace first.'); } } // Paths getWorkspaceRoot() { this.checkInitialized(); return this.workspaceRoot; } getTasksPath() { return path.join(this.workspaceRoot, 'workspace/tasks/tasks.json'); } getDecisionsPath() { return path.join(this.workspaceRoot, 'workspace/decisions'); } getReviewsPath() { return path.join(this.workspaceRoot, 'workspace/reviews'); } getContextPath() { return path.join(this.workspaceRoot, 'workspace/context'); } // Task Management async getTasks() { try { const data = await fs.readFile(this.getTasksPath(), 'utf-8'); return JSON.parse(data) || []; } catch (error) { return []; } } async saveTasks(tasks) { await fs.writeFile(this.getTasksPath(), JSON.stringify(tasks, null, 2), 'utf-8'); } // Decision Management async saveDecision(decision) { const timestamp = new Date().toISOString().replace(/[:.]/g, '-'); const decisionPath = path.join(this.getDecisionsPath(), `${timestamp}-${decision.type}.json`); await fs.writeFile(decisionPath, JSON.stringify(decision, null, 2), 'utf-8'); } // PM Session Management (for --resume functionality) async savePMSession(session) { const sessionPath = path.join(this.getContextPath(), 'pm-session.json'); // Ensure we only keep last 3 sessions if (session.sessionHistory.length > 3) { session.sessionHistory = session.sessionHistory.slice(-3); } await fs.writeFile(sessionPath, JSON.stringify(session, null, 2), 'utf-8'); } async getPMSession() { try { const sessionPath = path.join(this.getContextPath(), 'pm-session.json'); const data = await fs.readFile(sessionPath, 'utf-8'); return JSON.parse(data); } catch (error) { return null; } } // Review directory path for new review.log files // Keeping the getReviewsPath for directory structure // Context Management async saveContext(key, data) { const contextPath = path.join(this.getContextPath(), `${key}.json`); await fs.writeFile(contextPath, JSON.stringify(data, null, 2), 'utf-8'); } async getContext(key) { try { const contextPath = path.join(this.getContextPath(), `${key}.json`); const data = await fs.readFile(contextPath, 'utf-8'); return JSON.parse(data); } catch (error) { return null; } } } //# sourceMappingURL=manager.js.map