@vfarcic/dot-ai
Version:
AI-powered development productivity platform that enhances software development workflows through intelligent automation and AI-driven assistance
157 lines (156 loc) • 7.4 kB
JavaScript
;
/**
* Report Scan Handler - Project Setup Tool
* PRD #177 - Scope-based workflow refactoring
*
* Step 2 of workflow: Return ALL questions for selected scope
*/
Object.defineProperty(exports, "__esModule", { value: true });
exports.handleReportScan = handleReportScan;
const error_handling_1 = require("../../core/error-handling");
const generic_session_manager_1 = require("../../core/generic-session-manager");
/**
* Handle reportScan stage - Step 2 of project setup workflow
*
* Returns all questions for the selected scope and list of files to generate
*/
async function handleReportScan(sessionId, existingFiles, selectedScopes, logger, requestId) {
return await error_handling_1.ErrorHandler.withErrorHandling(async () => {
logger.debug('Starting report scan analysis', { requestId, sessionId });
// Initialize session manager
const sessionManager = new generic_session_manager_1.GenericSessionManager('proj');
// Load session
const session = sessionManager.getSession(sessionId);
if (!session) {
return {
success: false,
error: {
message: `Session ${sessionId} not found`,
details: 'Please start a new session with step: "discover"'
}
};
}
// Validate session state
if (!session.data.allScopes || !session.data.filesToCheck) {
return {
success: false,
error: {
message: 'Invalid session state',
details: 'Session does not contain scope configuration data'
}
};
}
const allScopes = session.data.allScopes;
// Store or retrieve existingFiles
let filesToUse;
if (existingFiles !== undefined) {
filesToUse = existingFiles;
session.data.existingFiles = existingFiles;
sessionManager.updateSession(sessionId, session.data);
logger.debug('Stored existingFiles in session', { requestId, sessionId, count: existingFiles.length });
}
else if (session.data.existingFiles !== undefined) {
filesToUse = session.data.existingFiles;
logger.debug('Reusing existingFiles from session', { requestId, sessionId, count: filesToUse.length });
}
else {
return {
success: false,
error: {
message: 'existingFiles is required for first reportScan call',
details: 'Please provide an array of files that exist in the repository'
}
};
}
// If no scopes selected, return analysis report
if (!selectedScopes || selectedScopes.length === 0) {
// Analyze scope completeness
const scopeStatus = {};
for (const [scopeName, scopeConfig] of Object.entries(allScopes)) {
const missingFiles = scopeConfig.files.filter(file => !filesToUse.includes(file));
scopeStatus[scopeName] = {
complete: missingFiles.length === 0,
missingFiles
};
}
const incompleteScopes = Object.entries(scopeStatus)
.filter(([_, status]) => !status.complete)
.map(([scopeName, _]) => scopeName);
// Generate report for user to review
const report = generateReport(scopeStatus, allScopes);
logger.info('Generated scope analysis report', {
requestId,
sessionId,
totalScopes: Object.keys(allScopes).length,
incompleteScopes: incompleteScopes.length
});
const incompleteScopeNames = incompleteScopes.join('", "');
return {
success: true,
sessionId,
nextStep: 'generateScope',
scope: '',
questions: [],
filesToGenerate: [],
instructions: `${report}\n\nIncomplete scopes: ${incompleteScopes.join(', ')}\n\n**IMPORTANT**: Present each scope individually to the user. Do NOT combine or group scopes. Use exact scope names.\n\nTo proceed, call projectSetup tool again with:\n- step: "reportScan"\n- sessionId: "${sessionId}"\n- selectedScopes: ["${incompleteScopeNames}"] (Use exact scope names from the list above)`
};
}
// User selected scope(s) - take first scope to generate
const selectedScope = selectedScopes[0];
const scopeConfig = allScopes[selectedScope];
if (!scopeConfig) {
return {
success: false,
error: {
message: `Invalid scope: ${selectedScope}`,
details: `Available scopes: ${Object.keys(allScopes).join(', ')}`
}
};
}
// Calculate which files need to be generated
const filesToGenerate = scopeConfig.files.filter(file => !filesToUse.includes(file));
// Store selected scopes in session
session.data.selectedScopes = selectedScopes;
session.data.currentStep = 'generateScope';
sessionManager.updateSession(sessionId, session.data);
logger.info('Ready to generate scope', {
requestId,
sessionId,
scope: selectedScope,
filesToGenerate: filesToGenerate.length,
questions: scopeConfig.questions.length
});
// Return ALL questions for this scope
return {
success: true,
sessionId,
nextStep: 'generateScope',
scope: selectedScope,
questions: scopeConfig.questions,
filesToGenerate,
instructions: `Scope: ${selectedScope}\n\nFiles to generate (${filesToGenerate.length}):\n${filesToGenerate.map(f => `- ${f}`).join('\n')}\n\nQuestions (${scopeConfig.questions.length}):\n${scopeConfig.questions.map((q, i) => `${i + 1}. ${q.question} (ID: ${q.id}${q.required ? ', required' : ''})`).join('\n')}\n\nAnalyze the repository to determine answers for these questions. Present your suggested answers as a numbered list. Once finalized, call projectSetup tool with:\n- step: "generateScope"\n- sessionId: "${sessionId}"\n- scope: "${selectedScope}"\n- answers: {${scopeConfig.questions.slice(0, 2).map(q => `"${q.id}": "value"`).join(', ')}, ...}`
};
}, {
operation: 'project_setup_report_scan',
component: 'ProjectSetupTool',
requestId
});
}
/**
* Generate human-readable report of scope analysis
*/
function generateReport(scopeStatus, allScopes) {
const lines = ['Repository Analysis:', ''];
for (const [scopeName, status] of Object.entries(scopeStatus)) {
const scopeConfig = allScopes[scopeName];
const totalFiles = scopeConfig.files.length;
const missingCount = status.missingFiles.length;
const existingCount = totalFiles - missingCount;
const statusIcon = status.complete ? '✓' : '○';
lines.push(`${statusIcon} ${scopeName}: ${existingCount}/${totalFiles} files exist`);
if (!status.complete) {
lines.push(` Missing: ${status.missingFiles.join(', ')}`);
}
}
return lines.join('\n');
}