spec-workflow-mcp
Version:
MCP server for managing spec workflow (requirements, design, implementation)
114 lines • 4.5 kB
JavaScript
/**
* Analyze workflow stage
*/
import { join } from 'path';
import { getStageFileName, getStageName } from '../shared/documentStatus.js';
import { isStageConfirmed, isStageSkipped } from '../shared/confirmationStatus.js';
import { openApiLoader } from '../shared/openApiLoader.js';
import { isDocumentEdited } from '../shared/documentAnalyzer.js';
import { isObject, hasProperty } from '../shared/typeGuards.js';
export function analyzeStage(path, stage, status) {
if (stage === 'completed') {
return {
canProceed: false,
needsConfirmation: false,
reason: 'All stages completed',
suggestions: []
};
}
const stageData = status[stage];
// Type guard to handle 'completed' stage
const isCompletedStage = (s) => s === 'completed';
const confirmed = isCompletedStage(stage) ? false : isStageConfirmed(path, stage);
const skipped = isCompletedStage(stage) ? false : isStageSkipped(path, stage);
// If stage is skipped or confirmed, can proceed
if (confirmed || skipped) {
return {
canProceed: true,
needsConfirmation: false,
suggestions: [`${getStageName(stage)} completed, can proceed to next stage`]
};
}
// Check if document exists
if (!stageData || !stageData.exists) {
return {
canProceed: false,
needsConfirmation: false,
reason: `${getStageName(stage)} does not exist`,
suggestions: [`Create ${getStageName(stage)}`],
guide: getStageGuide(stage)
};
}
// Check if document has been edited
const fileName = getStageFileName(stage);
const filePath = join(path, fileName);
const edited = isDocumentEdited(filePath);
if (!edited) {
// Document exists but not edited
return {
canProceed: false,
needsConfirmation: false,
reason: `${getStageName(stage)} not edited yet (still contains template markers)`,
suggestions: [
`Please edit ${fileName} and remove all <template-*> markers`,
'Fill in actual content before using check operation'
],
guide: getStageGuide(stage)
};
}
// Document edited but not confirmed
return {
canProceed: false,
needsConfirmation: true,
reason: `${getStageName(stage)} edited but not confirmed yet`,
suggestions: ['Please use confirm operation to confirm this stage is complete'],
guide: getStageGuide(stage)
};
}
export function getStageStatus(stage, status, path) {
const stageData = status[stage];
const exists = stageData?.exists || false;
const confirmed = exists && stage !== 'completed' ? isStageConfirmed(path, stage) : false;
const skipped = exists && stage !== 'completed' ? isStageSkipped(path, stage) : false;
const globalConfig = openApiLoader.getGlobalConfig();
const statusTextConfig = isObject(globalConfig) && hasProperty(globalConfig, 'status_text') && isObject(globalConfig.status_text) ? globalConfig.status_text : {};
const statusText = {
not_created: typeof statusTextConfig.not_created === 'string' ? statusTextConfig.not_created : 'Not created',
not_confirmed: typeof statusTextConfig.not_confirmed === 'string' ? statusTextConfig.not_confirmed : 'Pending confirmation',
completed: typeof statusTextConfig.completed === 'string' ? statusTextConfig.completed : 'Completed',
skipped: typeof statusTextConfig.skipped === 'string' ? statusTextConfig.skipped : 'Skipped'
};
let displayStatus = statusText.not_created;
if (exists) {
if (skipped) {
displayStatus = statusText.skipped;
}
else if (confirmed) {
displayStatus = statusText.completed;
}
else {
displayStatus = statusText.not_confirmed;
}
}
return {
exists,
confirmed,
skipped,
displayStatus
};
}
function getStageGuide(stage) {
const guideMap = {
requirements: 'requirements-guide',
design: 'design-guide',
tasks: 'tasks-guide',
completed: ''
};
const guideId = guideMap[stage];
if (!guideId)
return null;
// Get resource from OpenAPI - already in MCP format
const resource = openApiLoader.getSharedResource(guideId);
return resource || null;
}
//# sourceMappingURL=analyzeStage.js.map