UNPKG

@ttaqt/novel-workflow-mcp

Version:

MCP server for AI-assisted novel writing workflow with real-time web dashboard

171 lines (170 loc) 7.37 kB
import { PathUtils } from '../core/path-utils.js'; import { SpecParser } from '../core/parser.js'; export const storyStatusTool = { name: 'story-status', description: `Display comprehensive story writing progress overview. # Instructions Call when resuming work on a story or checking overall completion status. Shows which phases are complete and scene writing progress. After viewing status, read scenes.md directly to see all scenes and their status markers ([ ] pending, [-] in-progress, [x] completed).`, inputSchema: { type: 'object', properties: { projectPath: { type: 'string', description: 'Absolute path to the project root' }, storyName: { type: 'string', description: 'Name of the story' } }, required: ['projectPath', 'storyName'] } }; export async function storyStatusHandler(args, context) { const { projectPath, storyName } = args; try { const parser = new SpecParser(projectPath); const story = await parser.getSpec(storyName); if (!story) { return { success: false, message: `Story '${storyName}' not found`, nextSteps: [ 'Check story name', 'Use story-list for available stories', 'Create story with create-story-doc' ] }; } // Determine current phase and overall status let currentPhase = 'not-started'; let overallStatus = 'not-started'; // Map spec document names to story document names const hasOutlineBrief = story.phases.requirements?.exists; const hasOutlineDetailed = story.phases.design?.exists; const hasScenes = story.phases.tasks?.exists; if (!hasOutlineBrief) { currentPhase = 'outline-brief'; overallStatus = 'outline-brief-needed'; } else if (!hasOutlineDetailed) { currentPhase = 'outline-detailed'; overallStatus = 'outline-detailed-needed'; } else if (!hasScenes) { currentPhase = 'scenes'; overallStatus = 'scenes-needed'; } else if (story.taskProgress && story.taskProgress.pending > 0) { currentPhase = 'writing'; overallStatus = 'writing-in-progress'; } else if (story.taskProgress && story.taskProgress.total > 0 && story.taskProgress.completed === story.taskProgress.total) { currentPhase = 'completed'; overallStatus = 'completed'; } else { currentPhase = 'writing'; overallStatus = 'ready-to-write'; } // Phase details (with story-friendly names) const phaseDetails = [ { name: 'Brief Outline (简要大纲)', status: hasOutlineBrief ? (story.phases.requirements?.approved ? 'approved' : 'created') : 'missing', lastModified: story.phases.requirements?.lastModified }, { name: 'Detailed Outline (详细大纲)', status: hasOutlineDetailed ? (story.phases.design?.approved ? 'approved' : 'created') : 'missing', lastModified: story.phases.design?.lastModified }, { name: 'Scenes (场景清单)', status: hasScenes ? (story.phases.tasks?.approved ? 'approved' : 'created') : 'missing', lastModified: story.phases.tasks?.lastModified }, { name: 'Writing (正文创作)', status: story.phases.implementation?.exists ? 'in-progress' : 'not-started', progress: story.taskProgress } ]; // Next steps based on current phase const nextSteps = []; switch (currentPhase) { case 'outline-brief': nextSteps.push('Read template: .novel-workflow/templates/outline-brief-template.md'); nextSteps.push('Create: .novel-workflow/stories/{name}/outline-brief.md'); nextSteps.push('Request approval'); break; case 'outline-detailed': nextSteps.push('Read template: .novel-workflow/templates/outline-detailed-template.md'); nextSteps.push('Expand brief outline to detailed four-page outline'); nextSteps.push('Create: .novel-workflow/stories/{name}/outline-detailed.md'); nextSteps.push('Request approval'); break; case 'scenes': nextSteps.push('Read template: .novel-workflow/templates/scenes-template.md'); nextSteps.push('Break detailed outline into scenes'); nextSteps.push('Create: .novel-workflow/stories/{name}/scenes.md'); nextSteps.push('Request approval'); break; case 'writing': if (story.taskProgress && story.taskProgress.pending > 0) { nextSteps.push(`Read scenes: .novel-workflow/stories/${storyName}/scenes.md`); nextSteps.push('Edit scenes.md: Change [ ] to [-] for scene you start writing'); nextSteps.push('Write the scene following the _Prompt guidance'); nextSteps.push('Edit scenes.md: Change [-] to [x] when scene is completed'); } else { nextSteps.push(`Read scenes: .novel-workflow/stories/${storyName}/scenes.md`); nextSteps.push('Begin writing by marking first scene [-]'); } break; case 'completed': nextSteps.push('All scenes completed (marked [x])'); nextSteps.push('Review and polish the full manuscript'); break; } return { success: true, message: `Story '${storyName}' status: ${overallStatus}`, data: { name: storyName, description: story.description, currentPhase, overallStatus, createdAt: story.createdAt, lastModified: story.lastModified, phases: phaseDetails, sceneProgress: story.taskProgress || { total: 0, completed: 0, pending: 0, inProgress: 0 } }, nextSteps, projectContext: { projectPath, workflowRoot: PathUtils.getWorkflowRoot(projectPath), currentPhase, dashboardUrl: context.dashboardUrl } }; } catch (error) { const errorMessage = error instanceof Error ? error.message : String(error); return { success: false, message: `Failed to get story status: ${errorMessage}`, nextSteps: [ 'Check if the story exists', 'Verify the project path', 'List directory .novel-workflow/stories/ to see available stories' ] }; } } //# sourceMappingURL=story-status.js.map