// ============================================ // LITE TASKS VIEW // ============================================ // Lite-plan and lite-fix task list and detail rendering function renderLiteTasks() { const container = document.getElementById('mainContent'); const liteTasks = workflowData.liteTasks || {}; let sessions; if (currentLiteType === 'lite-plan') { sessions = liteTasks.litePlan || []; } else if (currentLiteType === 'lite-fix') { sessions = liteTasks.liteFix || []; } else if (currentLiteType === 'multi-cli-plan') { sessions = liteTasks.multiCliPlan || []; } else { sessions = []; } if (sessions.length === 0) { container.innerHTML = `
${t('empty.noLiteSessions', { type: currentLiteType })}
${t('empty.noLiteSessionsText', { type: currentLiteType })}
`; if (typeof lucide !== 'undefined') lucide.createIcons(); return; } // Render based on type if (currentLiteType === 'multi-cli-plan') { container.innerHTML = `
${sessions.map(session => renderMultiCliCard(session)).join('')}
`; } else { container.innerHTML = `
${sessions.map(session => renderLiteTaskCard(session)).join('')}
`; } // Initialize Lucide icons if (typeof lucide !== 'undefined') lucide.createIcons(); // Initialize collapsible sections document.querySelectorAll('.collapsible-header').forEach(header => { header.addEventListener('click', () => toggleSection(header)); }); // Render flowcharts for expanded tasks sessions.forEach(session => { session.tasks?.forEach(task => { if (task.flow_control?.implementation_approach) { renderFlowchartForTask(session.id, task); } }); }); } function renderLiteTaskCard(session) { const tasks = session.tasks || []; // Store session data for detail page const sessionKey = `lite-${session.type}-${session.id}`.replace(/[^a-zA-Z0-9-]/g, '-'); liteTaskDataStore[sessionKey] = session; return `
${escapeHtml(session.id)}
${session.type === 'lite-plan' ? ' ' + t('lite.plan') : ' ' + t('lite.fix')}
${formatDate(session.createdAt)} ${tasks.length} ${t('session.tasks')}
`; } // ============================================ // MULTI-CLI PLAN VIEW // ============================================ /** * Render a card for multi-cli-plan session * Shows: Session ID, round count, topic title, status, created date */ function renderMultiCliCard(session) { const sessionKey = `multi-cli-${session.id}`.replace(/[^a-zA-Z0-9-]/g, '-'); liteTaskDataStore[sessionKey] = session; // Extract info from latest synthesis or metadata const metadata = session.metadata || {}; const latestSynthesis = session.latestSynthesis || session.discussionTopic || {}; const roundCount = metadata.roundId || session.roundCount || 1; const topicTitle = getI18nText(latestSynthesis.title) || session.topicTitle || 'Discussion Topic'; const status = latestSynthesis.status || session.status || 'analyzing'; const createdAt = metadata.timestamp || session.createdAt || ''; // Status badge color mapping const statusColors = { 'decided': 'success', 'converged': 'success', 'plan_generated': 'success', 'completed': 'success', 'exploring': 'info', 'initialized': 'info', 'analyzing': 'warning', 'debating': 'warning', 'blocked': 'error', 'conflict': 'error' }; const statusColor = statusColors[status] || 'default'; return `
${escapeHtml(session.id)}
${t('lite.multiCli') || 'Multi-CLI'}
${escapeHtml(topicTitle)}
${formatDate(createdAt)} ${roundCount} ${t('multiCli.rounds') || 'rounds'} ${escapeHtml(status)}
`; } /** * Get text from i18n label object (supports {en, zh} format) */ function getI18nText(label) { if (!label) return ''; if (typeof label === 'string') return label; // Return based on current language or default to English const lang = window.currentLanguage || 'en'; return label[lang] || label.en || label.zh || ''; } // ============================================ // SYNTHESIS DATA TRANSFORMATION HELPERS // ============================================ /** * Extract files from synthesis solutions[].implementation_plan.tasks[].files * Returns object with fileTree and impactSummary arrays */ function extractFilesFromSynthesis(synthesis) { if (!synthesis || !synthesis.solutions) { return { fileTree: [], impactSummary: [], dependencyGraph: [] }; } const fileSet = new Set(); const impactMap = new Map(); synthesis.solutions.forEach(solution => { const tasks = solution.implementation_plan?.tasks || []; tasks.forEach(task => { const files = task.files || []; files.forEach(filePath => { fileSet.add(filePath); // Build impact summary based on task context if (!impactMap.has(filePath)) { impactMap.set(filePath, { filePath: filePath, score: 'medium', reasoning: { en: `Part of ${solution.title?.en || solution.id} implementation`, zh: `${solution.title?.zh || solution.id} 实现的一部分` } }); } }); }); }); // Convert to fileTree format (flat list with file type) const fileTree = Array.from(fileSet).map(path => ({ path: path, type: 'file', modificationStatus: 'modified', impactScore: 'medium' })); return { fileTree: fileTree, impactSummary: Array.from(impactMap.values()), dependencyGraph: [] }; } /** * Extract planning data from synthesis solutions[].implementation_plan * Builds planning object with functional requirements format */ function extractPlanningFromSynthesis(synthesis) { if (!synthesis || !synthesis.solutions) { return { functional: [], nonFunctional: [], acceptanceCriteria: [] }; } const functional = []; const acceptanceCriteria = []; let reqCounter = 1; let acCounter = 1; synthesis.solutions.forEach(solution => { const plan = solution.implementation_plan; if (!plan) return; // Extract approach as functional requirement if (plan.approach) { functional.push({ id: `FR-${String(reqCounter++).padStart(3, '0')}`, description: plan.approach, priority: solution.feasibility?.score >= 0.8 ? 'high' : 'medium', source: solution.id }); } // Extract tasks as acceptance criteria const tasks = plan.tasks || []; tasks.forEach(task => { acceptanceCriteria.push({ id: `AC-${String(acCounter++).padStart(3, '0')}`, description: task.title || { en: task.id, zh: task.id }, isMet: false }); }); }); return { functional: functional, nonFunctional: [], acceptanceCriteria: acceptanceCriteria }; } /** * Extract decision data from synthesis solutions * Sorts by feasibility score, returns highest as selected, rest as rejected */ function extractDecisionFromSynthesis(synthesis) { if (!synthesis || !synthesis.solutions || synthesis.solutions.length === 0) { return {}; } // Sort solutions by feasibility score (highest first) const sortedSolutions = [...synthesis.solutions].sort((a, b) => { const scoreA = a.feasibility?.score || 0; const scoreB = b.feasibility?.score || 0; return scoreB - scoreA; }); const selectedSolution = sortedSolutions[0]; const rejectedAlternatives = sortedSolutions.slice(1).map(sol => ({ ...sol, rejectionReason: sol.cons?.length > 0 ? sol.cons[0] : { en: 'Lower feasibility score', zh: '可行性评分较低' } })); // Calculate confidence from convergence level let confidenceScore = 0.5; if (synthesis.convergence) { const level = synthesis.convergence.level; if (level === 'high' || level === 'converged') confidenceScore = 0.9; else if (level === 'medium') confidenceScore = 0.7; else if (level === 'low') confidenceScore = 0.4; } return { status: synthesis.convergence?.recommendation || 'pending', summary: synthesis.convergence?.summary || {}, selectedSolution: selectedSolution, rejectedAlternatives: rejectedAlternatives, confidenceScore: confidenceScore }; } /** * Extract timeline data from synthesis convergence and cross_verification * Builds timeline array with events from discussion process */ function extractTimelineFromSynthesis(synthesis) { if (!synthesis) { return []; } const timeline = []; const now = new Date().toISOString(); // Add convergence summary as decision event if (synthesis.convergence?.summary) { timeline.push({ type: 'decision', timestamp: now, summary: synthesis.convergence.summary, contributor: { name: 'Synthesis', id: 'synthesis' }, reversibility: synthesis.convergence.recommendation === 'proceed' ? 'irreversible' : 'reversible' }); } // Add cross-verification agreements as agreement events const agreements = synthesis.cross_verification?.agreements || []; agreements.forEach((agreement, idx) => { timeline.push({ type: 'agreement', timestamp: now, summary: typeof agreement === 'string' ? { en: agreement, zh: agreement } : agreement, contributor: { name: 'Cross-Verification', id: 'cross-verify' }, evidence: [] }); }); // Add cross-verification disagreements as disagreement events const disagreements = synthesis.cross_verification?.disagreements || []; disagreements.forEach((disagreement, idx) => { timeline.push({ type: 'disagreement', timestamp: now, summary: typeof disagreement === 'string' ? { en: disagreement, zh: disagreement } : disagreement, contributor: { name: 'Cross-Verification', id: 'cross-verify' }, evidence: [] }); }); // Add solutions as proposal events const solutions = synthesis.solutions || []; solutions.forEach(solution => { timeline.push({ type: 'proposal', timestamp: now, summary: solution.description || solution.title || {}, contributor: { name: solution.id, id: solution.id }, evidence: solution.pros?.map(p => ({ type: 'pro', description: p })) || [] }); }); return timeline; } /** * Show multi-cli detail page with tabs (same layout as lite-plan) */ function showMultiCliDetailPage(sessionKey) { const session = liteTaskDataStore[sessionKey]; if (!session) return; currentView = 'multiCliDetail'; currentSessionDetailKey = sessionKey; hideStatsAndCarousel(); const container = document.getElementById('mainContent'); const metadata = session.metadata || {}; const plan = session.plan || {}; // Use session.tasks (normalized from backend) with fallback to plan.tasks const tasks = session.tasks?.length > 0 ? session.tasks : (plan.tasks || []); const roundCount = metadata.roundId || session.roundCount || 1; const status = session.status || 'analyzing'; container.innerHTML = `

${escapeHtml(session.id)}

MULTI-CLI
${t('detail.created') || 'Created'} ${formatDate(metadata.timestamp || session.createdAt)}
${t('detail.tasks') || 'Tasks'} ${tasks.length} ${t('session.tasks') || 'tasks'}
${renderMultiCliTasksTab(session)}
`; // Initialize icons, collapsible sections, and task click handlers setTimeout(() => { if (typeof lucide !== 'undefined') lucide.createIcons(); initCollapsibleSections(container); initMultiCliTaskClickHandlers(); }, 50); } /** * Render the multi-cli toolbar content */ function renderMultiCliToolbar(session) { const plan = session.plan; // Use session.tasks (normalized from backend) with fallback to plan.tasks const tasks = session.tasks?.length > 0 ? session.tasks : (plan?.tasks || []); const taskCount = tasks.length; let toolbarHtml = `

${t('multiCli.toolbar.tasks') || 'Tasks'} ${taskCount}

`; // Quick Actions toolbarHtml += `
`; // Task List if (tasks.length > 0) { toolbarHtml += `
${tasks.map((task, idx) => { const taskTitle = task.title || task.name || task.summary || `Task ${idx + 1}`; const taskScope = task.meta?.scope || task.scope || ''; const taskIdValue = task.id || `T${idx + 1}`; return `
#${idx + 1}
${escapeHtml(taskTitle)} ${taskScope ? `${escapeHtml(taskScope)}` : ''}
`; }).join('')}
`; } else { toolbarHtml += `
${t('multiCli.toolbar.noTasks') || 'No tasks available'}
`; } // Session Info toolbarHtml += `
${t('multiCli.toolbar.sessionId') || 'Session'} ${escapeHtml(session.id)}
${plan?.summary ? `
${t('multiCli.toolbar.summary') || 'Summary'} ${escapeHtml(plan.summary)}
` : ''}
`; return toolbarHtml; } /** * Scroll to a specific task in the planning tab */ function scrollToMultiCliTask(taskIdx) { // Switch to planning tab if not active const planningTab = document.querySelector('.detail-tab[data-tab="planning"]'); if (planningTab && !planningTab.classList.contains('active')) { switchMultiCliDetailTab('planning'); // Wait for tab content to render setTimeout(() => scrollToTaskElement(taskIdx), 100); } else { scrollToTaskElement(taskIdx); } } /** * Open task drawer from toolbar (wrapper for openTaskDrawerForMultiCli) */ function openToolbarTaskDrawer(sessionId, taskId) { openTaskDrawerForMultiCli(sessionId, taskId); } /** * Scroll to task element in the DOM */ function scrollToTaskElement(taskIdx) { const taskItems = document.querySelectorAll('.fix-task-summary-item'); if (taskItems[taskIdx]) { taskItems[taskIdx].scrollIntoView({ behavior: 'smooth', block: 'center' }); // Highlight the task briefly taskItems[taskIdx].classList.add('toolbar-highlight'); setTimeout(() => { taskItems[taskIdx].classList.remove('toolbar-highlight'); }, 2000); // Expand the collapsible if collapsed const header = taskItems[taskIdx].querySelector('.collapsible-header'); const content = taskItems[taskIdx].querySelector('.collapsible-content'); if (header && content && content.classList.contains('collapsed')) { header.click(); } } } /** * Refresh the toolbar content */ function refreshMultiCliToolbar() { const session = liteTaskDataStore[currentSessionDetailKey]; if (!session) return; const toolbarContent = document.querySelector('.toolbar-content'); if (toolbarContent) { toolbarContent.innerHTML = renderMultiCliToolbar(session); if (typeof lucide !== 'undefined') lucide.createIcons(); } } /** * Export plan.json content */ function exportMultiCliPlanJson() { const session = liteTaskDataStore[currentSessionDetailKey]; if (!session || !session.plan) { if (typeof showRefreshToast === 'function') { showRefreshToast(t('multiCli.toolbar.noPlan') || 'No plan data available', 'warning'); } return; } const jsonStr = JSON.stringify(session.plan, null, 2); const blob = new Blob([jsonStr], { type: 'application/json' }); const url = URL.createObjectURL(blob); const a = document.createElement('a'); a.href = url; a.download = `plan-${session.id}.json`; document.body.appendChild(a); a.click(); document.body.removeChild(a); URL.revokeObjectURL(url); if (typeof showRefreshToast === 'function') { showRefreshToast(t('multiCli.toolbar.exported') || 'Plan exported successfully', 'success'); } } /** * View raw session JSON in modal */ function viewMultiCliRawJson() { const session = liteTaskDataStore[currentSessionDetailKey]; if (!session) return; // Reuse existing JSON modal pattern const overlay = document.createElement('div'); overlay.className = 'json-modal-overlay active'; overlay.innerHTML = `
${escapeHtml(session.id)} ${t('multiCli.toolbar.rawData') || 'Raw Session Data'}
${escapeHtml(JSON.stringify(session, null, 2))}
`; document.body.appendChild(overlay); } /** * Switch between multi-cli detail tabs */ function switchMultiCliDetailTab(tabName) { // Update active tab document.querySelectorAll('.detail-tab').forEach(tab => { tab.classList.toggle('active', tab.dataset.tab === tabName); }); const session = liteTaskDataStore[currentSessionDetailKey]; if (!session) return; const contentArea = document.getElementById('multiCliDetailTabContent'); switch (tabName) { case 'tasks': contentArea.innerHTML = renderMultiCliTasksTab(session); break; case 'discussion': contentArea.innerHTML = renderMultiCliDiscussionSection(session); break; case 'context': loadAndRenderMultiCliContextTab(session, contentArea); return; // Early return as this is async case 'summary': loadAndRenderMultiCliSummaryTab(session, contentArea); return; // Early return as this is async } // Re-initialize after tab switch setTimeout(() => { if (typeof lucide !== 'undefined') lucide.createIcons(); initCollapsibleSections(contentArea); // Initialize task click handlers for tasks tab if (tabName === 'tasks') { initMultiCliTaskClickHandlers(); } }, 50); } // ============================================ // MULTI-CLI TAB RENDERERS // ============================================ /** * Render Tasks tab - displays plan summary + tasks (same style as lite-plan) * Uses session.tasks (normalized tasks) with fallback to session.plan.tasks */ function renderMultiCliTasksTab(session) { const plan = session.plan || {}; // Use session.tasks (normalized from backend) with fallback to plan.tasks const tasks = session.tasks?.length > 0 ? session.tasks : (plan.tasks || []); // Populate drawer tasks for click-to-open functionality currentDrawerTasks = tasks; let sections = []; // Extract plan info from multiple sources (plan.json, synthesis, or session) // plan.json: task_description, solution.name, execution_flow // synthesis: solutions[].summary, solutions[].implementation_plan.approach const taskDescription = plan.task_description || session.topicTitle || ''; const solutionName = plan.solution?.name || (plan.solutions?.[0]?.name) || ''; const solutionSummary = plan.solutions?.[0]?.summary || ''; const approach = plan.solutions?.[0]?.implementation_plan?.approach || plan.execution_flow || ''; const feasibility = plan.solution?.feasibility || plan.solutions?.[0]?.feasibility; const effort = plan.solution?.effort || plan.solutions?.[0]?.effort || ''; const risk = plan.solution?.risk || plan.solutions?.[0]?.risk || ''; // Plan Summary Section (if any info available) const hasInfo = taskDescription || solutionName || solutionSummary || approach || plan.summary; if (hasInfo) { let planInfo = []; // Task description (main objective) if (taskDescription) { planInfo.push(`

${t('multiCli.plan.objective')}: ${escapeHtml(taskDescription)}

`); } // Solution name and summary if (solutionName) { planInfo.push(`

${t('multiCli.plan.solution')}: ${escapeHtml(solutionName)}

`); } if (solutionSummary) { planInfo.push(`

${escapeHtml(solutionSummary)}

`); } // Legacy summary field if (plan.summary && !taskDescription && !solutionSummary) { planInfo.push(`

${escapeHtml(plan.summary)}

`); } // Approach/execution flow if (approach) { planInfo.push(`

${t('multiCli.plan.approach')}: ${escapeHtml(approach)}

`); } // Metadata badges - concise format let metaBadges = []; if (feasibility) metaBadges.push(`${Math.round(feasibility * 100)}%`); if (effort) metaBadges.push(`${escapeHtml(effort)}`); if (risk) metaBadges.push(`${escapeHtml(risk)} ${t('multiCli.plan.risk')}`); // Legacy badges if (plan.severity) metaBadges.push(`${escapeHtml(plan.severity)}`); if (plan.complexity) metaBadges.push(`${escapeHtml(plan.complexity)}`); if (plan.estimated_time) metaBadges.push(`${escapeHtml(plan.estimated_time)}`); sections.push(`
${planInfo.join('')} ${metaBadges.length ? `
${metaBadges.join(' ')}
` : ''}
`); } // Tasks Section if (tasks.length === 0) { sections.push(`
${t('empty.noTasks') || 'No Tasks'}
${t('empty.noTasksText') || 'No tasks available for this session.'}
`); } else { sections.push(`
${tasks.map((task, idx) => renderMultiCliTaskItem(session.id, task, idx)).join('')}
`); } return `
${sections.join('')}
`; } /** * Render Plan tab - displays plan.json content (summary, approach, metadata) */ function renderMultiCliPlanTab(session) { const plan = session.plan; if (!plan) { return `
${t('multiCli.empty.planning') || 'No Plan Data'}
${t('multiCli.empty.planningText') || 'No plan.json found for this session.'}
`; } return `
${plan.summary ? `

Summary

${escapeHtml(plan.summary)}

` : ''} ${plan.root_cause ? `

Root Cause

${escapeHtml(plan.root_cause)}

` : ''} ${plan.strategy ? `

Fix Strategy

${escapeHtml(plan.strategy)}

` : ''} ${plan.approach ? `

Approach

${escapeHtml(plan.approach)}

` : ''} ${plan.user_requirements ? `

User Requirements

${escapeHtml(plan.user_requirements)}

` : ''} ${plan.focus_paths?.length ? `

Focus Paths

${plan.focus_paths.map(p => `${escapeHtml(p)}`).join('')}
` : ''}

Metadata

${plan.severity ? `
Severity: ${escapeHtml(plan.severity)}
` : ''} ${plan.risk_level ? `
Risk Level: ${escapeHtml(plan.risk_level)}
` : ''} ${plan.estimated_time ? `
Estimated Time: ${escapeHtml(plan.estimated_time)}
` : ''} ${plan.complexity ? `
Complexity: ${escapeHtml(plan.complexity)}
` : ''} ${plan.recommended_execution ? `
Execution: ${escapeHtml(plan.recommended_execution)}
` : ''}
`; } /** * Load and render Context tab - displays context-package content */ async function loadAndRenderMultiCliContextTab(session, contentArea) { contentArea.innerHTML = `
${t('common.loading') || 'Loading...'}
`; try { if (window.SERVER_MODE && session.path) { const response = await fetch(`/api/session-detail?path=${encodeURIComponent(session.path)}&type=context`); if (response.ok) { const data = await response.json(); contentArea.innerHTML = renderMultiCliContextContent(data.context, session); initCollapsibleSections(contentArea); if (typeof lucide !== 'undefined') lucide.createIcons(); return; } } // Fallback: show session context_package if available contentArea.innerHTML = renderMultiCliContextContent(session.context_package, session); initCollapsibleSections(contentArea); if (typeof lucide !== 'undefined') lucide.createIcons(); } catch (err) { contentArea.innerHTML = `
Failed to load context: ${err.message}
`; } } /** * Render context content for multi-cli */ function renderMultiCliContextContent(context, session) { // Also check for context_package in session const ctx = context || session.context_package || {}; if (!ctx || Object.keys(ctx).length === 0) { return `
${t('empty.noContext') || 'No Context Data'}
${t('empty.noContextText') || 'No context package available for this session.'}
`; } let sections = []; // Task Description if (ctx.task_description) { sections.push(`

${t('multiCli.context.taskDescription')}

${escapeHtml(ctx.task_description)}

`); } // Constraints if (ctx.constraints?.length) { sections.push(`

${t('multiCli.context.constraints')}

`); } // Focus Paths if (ctx.focus_paths?.length) { sections.push(`

${t('multiCli.context.focusPaths')}

${ctx.focus_paths.map(p => `${escapeHtml(p)}`).join('')}
`); } // Relevant Files if (ctx.relevant_files?.length) { sections.push(`
`); } // Dependencies if (ctx.dependencies?.length) { sections.push(`
`); } // Conflict Risks if (ctx.conflict_risks?.length) { sections.push(`

${t('multiCli.context.conflictRisks')}

`); } // Session ID if (ctx.session_id) { sections.push(`

${t('multiCli.context.sessionId')}

${escapeHtml(ctx.session_id)}
`); } // Raw JSON sections.push(`
`); return `
${sections.join('')}
`; } /** * Load and render Summary tab */ async function loadAndRenderMultiCliSummaryTab(session, contentArea) { contentArea.innerHTML = `
${t('common.loading') || 'Loading...'}
`; try { if (window.SERVER_MODE && session.path) { const response = await fetch(`/api/session-detail?path=${encodeURIComponent(session.path)}&type=summary`); if (response.ok) { const data = await response.json(); contentArea.innerHTML = renderMultiCliSummaryContent(data.summary, session); initCollapsibleSections(contentArea); if (typeof lucide !== 'undefined') lucide.createIcons(); return; } } // Fallback: show synthesis summary contentArea.innerHTML = renderMultiCliSummaryContent(null, session); initCollapsibleSections(contentArea); if (typeof lucide !== 'undefined') lucide.createIcons(); } catch (err) { contentArea.innerHTML = `
Failed to load summary: ${err.message}
`; } } /** * Render summary content for multi-cli */ function renderMultiCliSummaryContent(summary, session) { const synthesis = session.latestSynthesis || session.discussionTopic || {}; const plan = session.plan || {}; // Use summary from file or build from synthesis const summaryText = summary || synthesis.convergence?.summary || plan.summary; if (!summaryText && !synthesis.solutions?.length) { return `
${t('empty.noSummary') || 'No Summary'}
${t('empty.noSummaryText') || 'No summary available for this session.'}
`; } let sections = []; // Main Summary if (summaryText) { const summaryContent = typeof summaryText === 'string' ? summaryText : getI18nText(summaryText); sections.push(`

${t('multiCli.summary.title')}

${escapeHtml(summaryContent)}
`); } // Convergence Status if (synthesis.convergence) { const conv = synthesis.convergence; sections.push(`

${t('multiCli.summary.convergence')}

${escapeHtml(conv.level || 'unknown')} ${escapeHtml(conv.recommendation || '')}
`); } // Solutions Summary if (synthesis.solutions?.length) { sections.push(`
`); } return `
${sections.join('')}
`; } /** * Render Discussion Topic tab * Shows: title, description, scope, keyQuestions, status, tags */ function renderMultiCliTopicTab(session) { const topic = session.discussionTopic || session.latestSynthesis?.discussionTopic || {}; if (!topic || Object.keys(topic).length === 0) { return `
${t('multiCli.empty.topic') || 'No Discussion Topic'}
${t('multiCli.empty.topicText') || 'No discussion topic data available for this session.'}
`; } const title = getI18nText(topic.title) || 'Untitled'; const description = getI18nText(topic.description) || ''; const scope = topic.scope || {}; const keyQuestions = topic.keyQuestions || []; const status = topic.status || 'unknown'; const tags = topic.tags || []; let sections = []; // Title and Description sections.push(`

${escapeHtml(title)}

${description ? `

${escapeHtml(description)}

` : ''}
${escapeHtml(status)} ${tags.length ? tags.map(tag => `${escapeHtml(tag)}`).join('') : ''}
`); // Scope (included/excluded) if (scope.included?.length || scope.excluded?.length) { sections.push(`

${t('multiCli.scope') || 'Scope'}

${scope.included?.length ? `
${t('multiCli.scope.included') || 'Included'}:
` : ''} ${scope.excluded?.length ? `
${t('multiCli.scope.excluded') || 'Excluded'}:
` : ''}
`); } // Key Questions if (keyQuestions.length) { sections.push(`

${t('multiCli.keyQuestions') || 'Key Questions'}

    ${keyQuestions.map(q => `
  1. ${escapeHtml(getI18nText(q))}
  2. `).join('')}
`); } return `
${sections.join('')}
`; } /** * Render Related Files tab * Shows: fileTree, impactSummary */ function renderMultiCliFilesTab(session) { // Use helper to extract files from synthesis data structure const relatedFiles = extractFilesFromSynthesis(session.latestSynthesis); if (!relatedFiles || (!relatedFiles.fileTree?.length && !relatedFiles.impactSummary?.length)) { return `
${t('multiCli.empty.files') || 'No Related Files'}
${t('multiCli.empty.filesText') || 'No file analysis data available for this session.'}
`; } const fileTree = relatedFiles.fileTree || []; const impactSummary = relatedFiles.impactSummary || []; const dependencyGraph = relatedFiles.dependencyGraph || []; let sections = []; // File Tree if (fileTree.length) { sections.push(`
`); } // Impact Summary if (impactSummary.length) { sections.push(`
`); } // Dependency Graph if (dependencyGraph.length) { sections.push(`
`); } return sections.length ? `
${sections.join('')}
` : `
${t('multiCli.empty.files') || 'No Related Files'}
`; } /** * Render file tree nodes recursively */ function renderFileTreeNodes(nodes, depth = 0) { return nodes.map(node => { const indent = depth * 16; const isDir = node.type === 'directory'; const icon = isDir ? 'folder' : 'file'; const modStatus = node.modificationStatus || 'unchanged'; const impactScore = node.impactScore || ''; let html = `
${escapeHtml(node.path || '')} ${modStatus !== 'unchanged' ? `${modStatus}` : ''} ${impactScore ? `${impactScore}` : ''}
`; if (node.children?.length) { html += renderFileTreeNodes(node.children, depth + 1); } return html; }).join(''); } /** * Render Planning tab - displays session.plan (plan.json content) * Reuses renderLitePlanTab style with Summary, Approach, Focus Paths, Metadata, and Tasks */ function renderMultiCliPlanningTab(session) { const plan = session.plan; if (!plan) { return `
${t('multiCli.empty.planning') || 'No Planning Data'}
${t('multiCli.empty.planningText') || 'No plan.json found for this session.'}
`; } return `
${plan.summary ? `

Summary

${escapeHtml(plan.summary)}

` : ''} ${plan.root_cause ? `

Root Cause

${escapeHtml(plan.root_cause)}

` : ''} ${plan.strategy ? `

Fix Strategy

${escapeHtml(plan.strategy)}

` : ''} ${plan.approach ? `

Approach

${escapeHtml(plan.approach)}

` : ''} ${plan.user_requirements ? `

User Requirements

${escapeHtml(plan.user_requirements)}

` : ''} ${plan.focus_paths?.length ? `

Focus Paths

${plan.focus_paths.map(p => `${escapeHtml(p)}`).join('')}
` : ''}

Metadata

${plan.severity ? `
Severity: ${escapeHtml(plan.severity)}
` : ''} ${plan.risk_level ? `
Risk Level: ${escapeHtml(plan.risk_level)}
` : ''} ${plan.estimated_time ? `
Estimated Time: ${escapeHtml(plan.estimated_time)}
` : ''} ${plan.complexity ? `
Complexity: ${escapeHtml(plan.complexity)}
` : ''} ${plan.recommended_execution ? `
Execution: ${escapeHtml(plan.recommended_execution)}
` : ''}
${plan.tasks?.length ? `

Tasks (${plan.tasks.length})

${plan.tasks.map((task, idx) => renderMultiCliTaskItem(session.id, task, idx)).join('')}
` : ''}
`; } /** * Render a single task item for multi-cli-plan (reuses lite-plan style) * Supports click to open drawer for details */ function renderMultiCliTaskItem(sessionId, task, idx) { const taskId = task.id || `T${idx + 1}`; const taskJsonId = `multi-cli-task-${sessionId}-${taskId}`.replace(/[^a-zA-Z0-9-]/g, '-'); taskJsonStore[taskJsonId] = task; // Get preview info - handle both normalized and raw formats // Normalized: meta.type, meta.scope, context.focus_paths, context.acceptance, flow_control.implementation_approach // Raw: action, scope, file, modification_points, implementation, acceptance const taskType = task.meta?.type || task.action || ''; const scope = task.meta?.scope || task.scope || task.file || ''; const filesCount = task.context?.focus_paths?.length || task.files?.length || task.modification_points?.length || 0; const implCount = task.flow_control?.implementation_approach?.length || task.implementation?.length || 0; const acceptCount = task.context?.acceptance?.length || task.acceptance?.length || task.acceptance_criteria?.length || 0; const dependsCount = task.context?.depends_on?.length || task.depends_on?.length || 0; // Escape for data attributes const safeSessionId = escapeHtml(sessionId); const safeTaskId = escapeHtml(taskId); return `
${escapeHtml(taskId)} ${escapeHtml(task.title || task.name || task.summary || 'Untitled')}
${taskType ? `${escapeHtml(taskType)}` : ''} ${scope ? `${escapeHtml(scope)}` : ''} ${filesCount > 0 ? `${filesCount} files` : ''} ${implCount > 0 ? `${implCount} steps` : ''} ${acceptCount > 0 ? `${acceptCount} criteria` : ''} ${dependsCount > 0 ? `${dependsCount} deps` : ''}
`; } /** * Initialize click handlers for multi-cli task items */ function initMultiCliTaskClickHandlers() { // Task item click handlers document.querySelectorAll('.multi-cli-task-item').forEach(item => { if (!item._clickBound) { item._clickBound = true; item.addEventListener('click', function(e) { // Don't trigger if clicking on JSON button if (e.target.closest('.btn-view-json')) return; const sessionId = this.dataset.sessionId; const taskId = this.dataset.taskId; openTaskDrawerForMultiCli(sessionId, taskId); }); } }); // JSON button click handlers document.querySelectorAll('.multi-cli-task-item .btn-view-json').forEach(btn => { if (!btn._clickBound) { btn._clickBound = true; btn.addEventListener('click', function(e) { e.stopPropagation(); const taskJsonId = this.dataset.taskJsonId; const displayId = this.dataset.taskDisplayId; showJsonModal(taskJsonId, displayId); }); } }); } /** * Open task drawer for multi-cli task */ function openTaskDrawerForMultiCli(sessionId, taskId) { const session = liteTaskDataStore[currentSessionDetailKey]; if (!session) return; // Use session.tasks (normalized from backend) with fallback to plan.tasks const tasks = session.tasks?.length > 0 ? session.tasks : (session.plan?.tasks || []); const task = tasks.find(t => (t.id || `T${tasks.indexOf(t) + 1}`) === taskId); if (!task) return; // Set current drawer tasks currentDrawerTasks = tasks; window._currentDrawerSession = session; document.getElementById('drawerTaskTitle').textContent = task.title || task.name || task.summary || taskId; document.getElementById('drawerContent').innerHTML = renderMultiCliTaskDrawerContent(task, session); document.getElementById('taskDetailDrawer').classList.add('open'); document.getElementById('drawerOverlay').classList.add('active'); // Re-init lucide icons in drawer setTimeout(() => { if (typeof lucide !== 'undefined') lucide.createIcons(); }, 50); } /** * Render drawer content for multi-cli task */ function renderMultiCliTaskDrawerContent(task, session) { const taskId = task.id || 'Task'; const action = task.action || ''; return `
${escapeHtml(taskId)} ${action ? `${escapeHtml(action.toUpperCase())}` : ''}
${renderMultiCliTaskOverview(task)}
${renderMultiCliTaskImplementation(task)}
${renderMultiCliTaskFiles(task)}
${escapeHtml(JSON.stringify(task, null, 2))}
`; } /** * Switch drawer tab for multi-cli task */ function switchMultiCliDrawerTab(tabName) { document.querySelectorAll('.drawer-tab').forEach(tab => { tab.classList.toggle('active', tab.dataset.tab === tabName); }); document.querySelectorAll('.drawer-panel').forEach(panel => { panel.classList.toggle('active', panel.dataset.tab === tabName); }); } /** * Render multi-cli task overview section * Handles both normalized format (meta, context, flow_control) and raw format */ function renderMultiCliTaskOverview(task) { let sections = []; // Extract from both normalized and raw formats const description = task.description || (task.context?.requirements?.length > 0 ? task.context.requirements.join('\n') : ''); const scope = task.meta?.scope || task.scope || task.file || ''; const acceptance = task.context?.acceptance || task.acceptance || task.acceptance_criteria || []; const dependsOn = task.context?.depends_on || task.depends_on || []; const focusPaths = task.context?.focus_paths || task.files?.map(f => typeof f === 'string' ? f : f.file) || []; const keyPoint = task._raw?.task?.key_point || task.key_point || ''; // Description/Key Point Card if (description || keyPoint) { sections.push(`
📝

${t('multiCli.task.description')}

${keyPoint ? `

${t('multiCli.task.keyPoint')}: ${escapeHtml(keyPoint)}

` : ''} ${description ? `

${escapeHtml(description)}

` : ''}
`); } // Scope Card if (scope) { sections.push(`
📂

${t('multiCli.task.scope')}

${escapeHtml(scope)}
`); } // Dependencies Card if (dependsOn.length > 0) { sections.push(`
🔗

${t('multiCli.task.dependencies')}

${dependsOn.map(dep => `${escapeHtml(dep)}`).join('')}
`); } // Focus Paths / Files Card if (focusPaths.length > 0) { sections.push(`
📁

${t('multiCli.task.targetFiles')}

`); } // Acceptance Criteria Card if (acceptance.length > 0) { sections.push(`

${t('multiCli.task.acceptanceCriteria')}

`); } // Reference Card if (task.reference) { const ref = task.reference; sections.push(`
📚

${t('multiCli.task.reference')}

${ref.pattern ? `
${t('multiCli.task.pattern')}: ${escapeHtml(ref.pattern)}
` : ''} ${ref.files?.length ? `
${t('multiCli.task.files')}:
${ref.files.map(f => escapeHtml(f)).join('\n')}
` : ''} ${ref.examples ? `
${t('multiCli.task.examples')}: ${escapeHtml(ref.examples)}
` : ''}
`); } return sections.length ? sections.join('') : `
${t('multiCli.task.noOverviewData')}
`; } /** * Render multi-cli task implementation section * Handles both normalized format (flow_control.implementation_approach) and raw format */ function renderMultiCliTaskImplementation(task) { let sections = []; // Get implementation steps from normalized or raw format const implApproach = task.flow_control?.implementation_approach || []; const rawImpl = task.implementation || []; const modPoints = task.modification_points || []; // Modification Points / Flow Control Implementation Approach if (implApproach.length > 0) { sections.push(`

${t('multiCli.task.implementationSteps')}

    ${implApproach.map((step, idx) => `
  1. ${step.step || (idx + 1)} ${escapeHtml(step.action || step)}
  2. `).join('')}
`); } else if (modPoints.length > 0) { sections.push(`

${t('multiCli.task.modificationPoints')}

`); } // Raw Implementation Steps (if not already rendered via implApproach) if (rawImpl.length > 0 && implApproach.length === 0) { sections.push(`

${t('multiCli.task.implementationSteps')}

    ${rawImpl.map((step, idx) => `
  1. ${idx + 1} ${escapeHtml(step)}
  2. `).join('')}
`); } // Verification if (task.verification?.length) { sections.push(`

${t('multiCli.task.verification')}

`); } return sections.length ? sections.join('') : `
${t('multiCli.task.noImplementationData')}
`; } /** * Render multi-cli task files section * Handles both normalized format (context.focus_paths) and raw format */ function renderMultiCliTaskFiles(task) { const files = []; // Collect from normalized format (context.focus_paths) if (task.context?.focus_paths) { task.context.focus_paths.forEach(f => { if (f && !files.includes(f)) files.push(f); }); } // Collect from raw files array (plan.json format) if (task.files) { task.files.forEach(f => { const filePath = typeof f === 'string' ? f : f.file; if (filePath && !files.includes(filePath)) files.push(filePath); }); } // Collect from modification_points if (task.modification_points) { task.modification_points.forEach(mp => { if (mp.file && !files.includes(mp.file)) files.push(mp.file); }); } // Collect from scope/file (legacy) if (task.scope && !files.includes(task.scope)) files.push(task.scope); if (task.file && !files.includes(task.file)) files.push(task.file); // Collect from reference.files if (task.reference?.files) { task.reference.files.forEach(f => { if (f && !files.includes(f)) files.push(f); }); } if (files.length === 0) { return `
${t('multiCli.task.noFilesSpecified')}
`; } return `

${t('multiCli.task.targetFiles')}

`; } /** * Render a single requirement item */ function renderRequirementItem(req) { const priorityColors = { 'critical': 'error', 'high': 'warning', 'medium': 'info', 'low': 'default' }; const priority = req.priority || 'medium'; const colorClass = priorityColors[priority] || 'default'; return `
${escapeHtml(req.id || '')} ${escapeHtml(priority)}
${escapeHtml(getI18nText(req.description))}
${req.source ? `
${t('multiCli.source') || 'Source'}: ${escapeHtml(req.source)}
` : ''}
`; } /** * Render Decision tab * Shows: selectedSolution, rejectedAlternatives, confidenceScore */ function renderMultiCliDecisionTab(session) { // Use helper to extract decision from synthesis data structure const decision = extractDecisionFromSynthesis(session.latestSynthesis); if (!decision || !decision.selectedSolution) { return `
${t('multiCli.empty.decision') || 'No Decision Yet'}
${t('multiCli.empty.decisionText') || 'No decision has been made for this discussion yet.'}
`; } const status = decision.status || 'pending'; const summary = getI18nText(decision.summary) || ''; const selectedSolution = decision.selectedSolution || null; const rejectedAlternatives = decision.rejectedAlternatives || []; const confidenceScore = decision.confidenceScore || 0; let sections = []; // Decision Status and Summary sections.push(`
${escapeHtml(status)}
${t('multiCli.confidence') || 'Confidence'}:
${(confidenceScore * 100).toFixed(0)}%
${summary ? `

${escapeHtml(summary)}

` : ''}
`); // Selected Solution if (selectedSolution) { sections.push(`

${t('multiCli.selectedSolution') || 'Selected Solution'}

${renderSolutionCard(selectedSolution, true)}
`); } // Rejected Alternatives if (rejectedAlternatives.length) { sections.push(`
`); } return `
${sections.join('')}
`; } /** * Render a solution card */ function renderSolutionCard(solution, isSelected) { const title = getI18nText(solution.title) || 'Untitled Solution'; const description = getI18nText(solution.description) || ''; const pros = solution.pros || []; const cons = solution.cons || []; const risk = solution.risk || 'medium'; const effort = getI18nText(solution.estimatedEffort) || ''; const rejectionReason = solution.rejectionReason ? getI18nText(solution.rejectionReason) : ''; const sourceCLIs = solution.sourceCLIs || []; return `
${escapeHtml(solution.id || '')} ${escapeHtml(title)} ${escapeHtml(risk)}
${description ? `

${escapeHtml(description)}

` : ''} ${rejectionReason ? `
${t('multiCli.rejectionReason') || 'Reason'}: ${escapeHtml(rejectionReason)}
` : ''}
${pros.length ? `
${t('multiCli.pros') || 'Pros'}:
    ${pros.map(p => `
  • ${escapeHtml(getI18nText(p))}
  • `).join('')}
` : ''} ${cons.length ? `
${t('multiCli.cons') || 'Cons'}:
    ${cons.map(c => `
  • ${escapeHtml(getI18nText(c))}
  • `).join('')}
` : ''} ${effort ? `
${t('multiCli.effort') || 'Effort'}: ${escapeHtml(effort)}
` : ''} ${sourceCLIs.length ? `
${t('multiCli.sources') || 'Sources'}: ${sourceCLIs.map(s => `${escapeHtml(s)}`).join('')}
` : ''}
`; } /** * Render Timeline tab * Shows: decisionRecords.timeline */ function renderMultiCliTimelineTab(session) { // Use helper to extract timeline from synthesis data structure const timeline = extractTimelineFromSynthesis(session.latestSynthesis); if (!timeline || !timeline.length) { return `
${t('multiCli.empty.timeline') || 'No Timeline Events'}
${t('multiCli.empty.timelineText') || 'No decision timeline available for this session.'}
`; } const eventTypeIcons = { 'proposal': 'lightbulb', 'argument': 'message-square', 'agreement': 'thumbs-up', 'disagreement': 'thumbs-down', 'decision': 'check-circle', 'reversal': 'rotate-ccw' }; return `
${timeline.map(event => { const icon = eventTypeIcons[event.type] || 'circle'; const contributor = event.contributor || {}; const summary = getI18nText(event.summary) || ''; const evidence = event.evidence || []; return `
${escapeHtml(event.type || 'event')} ${escapeHtml(contributor.name || 'Unknown')} ${formatDate(event.timestamp)}
${escapeHtml(summary)}
${event.reversibility ? `${escapeHtml(event.reversibility)}` : ''} ${evidence.length ? `
${evidence.map(ev => `
${escapeHtml(ev.type || 'reference')} ${escapeHtml(getI18nText(ev.description))}
`).join('')}
` : ''}
`; }).join('')}
`; } /** * Render Rounds tab * Shows: navigation between round synthesis files */ function renderMultiCliRoundsTab(session) { const rounds = session.rounds || []; const metadata = session.metadata || {}; const totalRounds = metadata.roundId || rounds.length || 1; if (!rounds.length && totalRounds <= 1) { // Show current synthesis as single round return `
Round 1 ${t('multiCli.currentRound') || 'Current'}

${t('multiCli.singleRoundInfo') || 'This is a single-round discussion. View other tabs for details.'}

`; } // Render round navigation and content return `
${rounds.map((round, idx) => { const roundNum = idx + 1; const isActive = roundNum === totalRounds; const roundStatus = round.convergence?.recommendation || 'continue'; return `
Round ${roundNum} ${escapeHtml(roundStatus)}
`; }).join('')}
${renderRoundContent(rounds[totalRounds - 1] || rounds[0] || session)}
`; } /** * Render content for a specific round */ function renderRoundContent(round) { if (!round) { return `
${t('multiCli.noRoundData') || 'No data for this round.'}
`; } const metadata = round.metadata || {}; const agents = metadata.contributingAgents || []; const convergence = round._internal?.convergence || {}; const crossVerification = round._internal?.cross_verification || {}; let sections = []; // Round metadata sections.push(`
${t('multiCli.roundId') || 'Round'}: ${metadata.roundId || 1}
${t('multiCli.timestamp') || 'Time'}: ${formatDate(metadata.timestamp)}
${metadata.durationSeconds ? `
${t('multiCli.duration') || 'Duration'}: ${metadata.durationSeconds}s
` : ''}
`); // Contributing agents if (agents.length) { sections.push(`
${t('multiCli.contributors') || 'Contributors'}: ${agents.map(agent => `${escapeHtml(agent.name || agent.id)}`).join('')}
`); } // Convergence metrics if (convergence.score !== undefined) { sections.push(`
${t('multiCli.convergence') || 'Convergence'}: ${(convergence.score * 100).toFixed(0)}% ${escapeHtml(convergence.recommendation || '')} ${convergence.new_insights ? `${t('multiCli.newInsights') || 'New Insights'}` : ''}
`); } // Cross-verification if (crossVerification.agreements?.length || crossVerification.disagreements?.length) { sections.push(`
`); } // Round solutions if (round.solutions && round.solutions.length > 0) { sections.push(`
${t('multiCli.solutions') || 'Solutions'} (${round.solutions.length}):
${round.solutions.map((solution, idx) => `
${idx + 1} ${escapeHtml(solution.name || `Solution ${idx + 1}`)}
${solution.source_cli?.length ? `
${solution.source_cli.map(cli => `${escapeHtml(cli)}`).join('')}
` : ''}
${Math.round((solution.feasibility || 0) * 100)}% ${escapeHtml(solution.effort || 'medium')} ${escapeHtml(solution.risk || 'medium')}
${solution.summary ? `
${escapeHtml(getI18nText(solution.summary))}
` : ''} ${solution.implementation_plan?.approach ? `
` : ''} ${(solution.dependencies?.internal?.length || solution.dependencies?.external?.length) ? `
` : ''} ${solution.technical_concerns?.length ? `
` : ''}
`).join('')}
`); } return sections.join(''); } /** * Load a specific round's data (async, may fetch from server) */ async function loadMultiCliRound(sessionKey, roundNum) { const session = liteTaskDataStore[sessionKey]; if (!session) return; // Update active state in nav document.querySelectorAll('.round-item').forEach(item => { item.classList.toggle('active', parseInt(item.dataset.round) === roundNum); }); const contentArea = document.getElementById('multiCliRoundContent'); // If we have rounds array, use it if (session.rounds && session.rounds[roundNum - 1]) { contentArea.innerHTML = renderRoundContent(session.rounds[roundNum - 1]); initCollapsibleSections(contentArea); return; } // Otherwise try to fetch from server if (window.SERVER_MODE && session.path) { contentArea.innerHTML = `
${t('common.loading') || 'Loading...'}
`; try { const response = await fetch(`/api/session-detail?path=${encodeURIComponent(session.path)}&type=round&round=${roundNum}`); if (response.ok) { const data = await response.json(); contentArea.innerHTML = renderRoundContent(data.round || {}); initCollapsibleSections(contentArea); return; } } catch (err) { console.error('Failed to load round:', err); } } // Fallback contentArea.innerHTML = `
${t('multiCli.noRoundData') || 'No data for this round.'}
`; } /** * Render Discussion Section (combines Topic, Rounds, Decision) * Uses accordion layout to display discussion rounds */ function renderMultiCliDiscussionSection(session) { const rounds = session.rounds || []; const metadata = session.metadata || {}; const totalRounds = metadata.roundId || rounds.length || 1; const topic = session.discussionTopic || session.latestSynthesis?.discussionTopic || {}; // If no rounds, show topic summary and current synthesis if (!rounds.length) { const title = getI18nText(topic.title) || t('multiCli.discussion.discussionTopic'); const description = getI18nText(topic.description) || ''; const status = topic.status || session.status || 'analyzing'; return `

${escapeHtml(title)}

${escapeHtml(status)}
${description ? `

${escapeHtml(description)}

` : ''}

${t('multiCli.singleRoundInfo')}

`; } // Render accordion for multiple rounds const accordionItems = rounds.map((round, idx) => { const roundNum = idx + 1; const isLatest = roundNum === totalRounds; const roundMeta = round.metadata || {}; const convergence = round._internal?.convergence || round.convergence || {}; const recommendation = convergence.recommendation || 'continue'; const score = convergence.score !== undefined ? Math.round(convergence.score * 100) : null; const solutions = round.solutions || []; const agents = roundMeta.contributingAgents || []; return `
${isLatest ? '▼' : '►'}
${t('multiCli.round') || 'Round'} ${roundNum} ${formatDate(roundMeta.timestamp)}
${score !== null ? `${score}%` : ''} ${escapeHtml(recommendation)}
${round.discussionTopic ? `

${t('multiCli.topic') || 'Topic'}

${escapeHtml(getI18nText(round.discussionTopic.title || round.discussionTopic))}

` : ''} ${agents.length ? `

${t('multiCli.contributors') || 'Contributors'}

${agents.map(agent => `${escapeHtml(agent.name || agent.id || agent)}`).join('')}
` : ''} ${solutions.length ? `

${t('multiCli.solutions')} (${solutions.length})

${solutions.map((sol, sidx) => `
${sidx + 1} ${escapeHtml(sol.name || `${t('multiCli.summary.solution')} ${sidx + 1}`)}
${Math.round((sol.feasibility || 0) * 100)}% ${escapeHtml(sol.effort || 'M')} ${escapeHtml(sol.risk || 'M')}
${sol.summary ? `

${escapeHtml(getI18nText(sol.summary).substring(0, 100))}${getI18nText(sol.summary).length > 100 ? '...' : ''}

` : ''}
`).join('')}
` : ''} ${convergence.reasoning || round.decision ? `

${t('multiCli.decision')}

${escapeHtml(convergence.reasoning || round.decision || '')}

` : ''}
`; }).join(''); return `

${escapeHtml(getI18nText(topic.title) || t('multiCli.discussion.title'))}

${totalRounds} ${t('multiCli.tab.rounds')}
${accordionItems}
`; } /** * Render Association Section (context-package key fields) * Shows solution summary, dependencies, consensus */ function renderMultiCliAssociationSection(session) { const contextPkg = session.contextPackage || session.context_package || session.latestSynthesis?.context_package || {}; const solutions = contextPkg.solutions || session.latestSynthesis?.solutions || []; const dependencies = contextPkg.dependencies || {}; const consensus = contextPkg.consensus || session.latestSynthesis?._internal?.cross_verification || {}; const relatedFiles = extractFilesFromSynthesis(session.latestSynthesis); // Check if we have any content to display const hasSolutions = solutions.length > 0; const hasDependencies = dependencies.internal?.length || dependencies.external?.length; const hasConsensus = consensus.agreements?.length || consensus.resolved_conflicts?.length || consensus.disagreements?.length; const hasFiles = relatedFiles?.fileTree?.length || relatedFiles?.impactSummary?.length; if (!hasSolutions && !hasDependencies && !hasConsensus && !hasFiles) { return `
${t('multiCli.empty.association') || 'No Association Data'}
${t('multiCli.empty.associationText') || 'No context package or related files available for this session.'}
`; } let sections = []; // Solution Summary Cards if (hasSolutions) { sections.push(`

${t('multiCli.solutionSummary') || 'Solution Summary'}

${solutions.map((sol, idx) => `
${idx + 1} ${escapeHtml(sol.name || 'Solution ' + (idx + 1))}
${t('multiCli.feasibility') || 'Feasibility'} ${Math.round((sol.feasibility || 0) * 100)}%
${t('multiCli.effort') || 'Effort'} ${escapeHtml(sol.effort || 'medium')}
${t('multiCli.risk') || 'Risk'} ${escapeHtml(sol.risk || 'medium')}
${sol.summary ? `

${escapeHtml(getI18nText(sol.summary))}

` : ''}
`).join('')}
`); } // Dependencies Card if (hasDependencies) { sections.push(`

${t('multiCli.dependencies') || 'Dependencies'}

${dependencies.internal?.length ? `
${t('multiCli.internalDeps') || 'Internal'} ${dependencies.internal.length}
    ${dependencies.internal.map(dep => `
  • ${escapeHtml(getI18nText(dep))}
  • `).join('')}
` : ''} ${dependencies.external?.length ? `
${t('multiCli.externalDeps') || 'External'} ${dependencies.external.length}
    ${dependencies.external.map(dep => `
  • ${escapeHtml(getI18nText(dep))}
  • `).join('')}
` : ''}
`); } // Consensus Card if (hasConsensus) { sections.push(`

${t('multiCli.consensus') || 'Consensus'}

${consensus.agreements?.length ? `
${t('multiCli.agreements') || 'Agreements'} ${consensus.agreements.length}
    ${consensus.agreements.map(item => `
  • ${escapeHtml(item)}
  • `).join('')}
` : ''} ${(consensus.resolved_conflicts?.length || consensus.disagreements?.length) ? `
${t('multiCli.resolvedConflicts') || 'Resolved Conflicts'} ${(consensus.resolved_conflicts || consensus.disagreements || []).length}
    ${(consensus.resolved_conflicts || consensus.disagreements || []).map(item => `
  • ${escapeHtml(item)}
  • `).join('')}
` : ''}
`); } // Related Files (from existing Files tab logic) if (hasFiles) { sections.push(`

${t('multiCli.tab.files') || 'Related Files'}

${relatedFiles.fileTree?.length ? `
${relatedFiles.fileTree.slice(0, 10).map(file => `
${escapeHtml(typeof file === 'string' ? file : file.path || file.name)}
`).join('')} ${relatedFiles.fileTree.length > 10 ? `
+${relatedFiles.fileTree.length - 10} ${t('common.more') || 'more'}
` : ''}
` : ''} ${relatedFiles.impactSummary?.length ? `
${t('multiCli.impactSummary') || 'Impact Summary'}
    ${relatedFiles.impactSummary.slice(0, 5).map(item => `
  • ${escapeHtml(getI18nText(item))}
  • `).join('')}
` : ''}
`); } return `
${sections.join('')}
`; } // Lite Task Detail Page function showLiteTaskDetailPage(sessionKey) { const session = liteTaskDataStore[sessionKey]; if (!session) return; currentView = 'liteTaskDetail'; currentSessionDetailKey = sessionKey; // Hide stats grid and carousel on detail pages hideStatsAndCarousel(); // Also store in sessionDataStore for tab switching compatibility sessionDataStore[sessionKey] = { ...session, session_id: session.id, created_at: session.createdAt, path: session.path, type: session.type }; const container = document.getElementById('mainContent'); const tasks = session.tasks || []; const plan = session.plan || {}; const progress = session.progress || { total: 0, completed: 0, percentage: 0 }; const completed = tasks.filter(t => t.status === 'completed').length; const inProgress = tasks.filter(t => t.status === 'in_progress').length; const pending = tasks.filter(t => t.status === 'pending').length; container.innerHTML = `

${session.type === 'lite-plan' ? '' : ''} ${escapeHtml(session.id)}

${session.type}
${t('detail.created')} ${formatDate(session.createdAt)}
${t('detail.tasks')} ${tasks.length} ${t('session.tasks')}
${session.type === 'lite-fix' ? ` ` : ''}
${renderLiteTasksTab(session, tasks, completed, inProgress, pending)}
`; // Initialize collapsible sections and task click handlers setTimeout(() => { document.querySelectorAll('.collapsible-header').forEach(header => { header.addEventListener('click', () => toggleSection(header)); }); // Bind click events to lite task items on initial load initLiteTaskClickHandlers(); }, 50); } function goBackToLiteTasks() { currentView = 'liteTasks'; currentSessionDetailKey = null; updateContentTitle(); showStatsAndSearch(); renderLiteTasks(); } function switchLiteDetailTab(tabName) { // Update active tab document.querySelectorAll('.detail-tab').forEach(tab => { tab.classList.toggle('active', tab.dataset.tab === tabName); }); const session = liteTaskDataStore[currentSessionDetailKey]; if (!session) return; const contentArea = document.getElementById('liteDetailTabContent'); const tasks = session.tasks || []; const completed = tasks.filter(t => t.status === 'completed').length; const inProgress = tasks.filter(t => t.status === 'in_progress').length; const pending = tasks.filter(t => t.status === 'pending').length; switch (tabName) { case 'tasks': contentArea.innerHTML = renderLiteTasksTab(session, tasks, completed, inProgress, pending); // Re-initialize collapsible sections and task click handlers setTimeout(() => { document.querySelectorAll('.collapsible-header').forEach(header => { header.addEventListener('click', () => toggleSection(header)); }); // Bind click events to lite task items initLiteTaskClickHandlers(); }, 50); break; case 'plan': contentArea.innerHTML = renderLitePlanTab(session); // Re-initialize collapsible sections for plan tab setTimeout(() => { initCollapsibleSections(contentArea); }, 50); break; case 'diagnoses': contentArea.innerHTML = renderDiagnosesTab(session); // Re-initialize collapsible sections for diagnoses tab setTimeout(() => { initCollapsibleSections(contentArea); }, 50); break; case 'context': loadAndRenderLiteContextTab(session, contentArea); break; case 'summary': loadAndRenderLiteSummaryTab(session, contentArea); break; } } function renderLiteTasksTab(session, tasks, completed, inProgress, pending) { // Populate drawer tasks for click-to-open functionality currentDrawerTasks = tasks; if (tasks.length === 0) { return `
${t('empty.noTasks')}
${t('empty.noTasksText')}
`; } return `
${tasks.map(task => renderLiteTaskDetailItem(session.id, task)).join('')}
`; } function renderLiteTaskDetailItem(sessionId, task) { const rawTask = task._raw || task; const taskJsonId = `task-json-${sessionId}-${task.id}`.replace(/[^a-zA-Z0-9-]/g, '-'); taskJsonStore[taskJsonId] = rawTask; // Get preview info for lite tasks const action = rawTask.action || ''; const scope = rawTask.scope || ''; const modCount = rawTask.modification_points?.length || 0; const implCount = rawTask.implementation?.length || 0; const acceptCount = rawTask.acceptance?.length || 0; // Escape for data attributes const safeSessionId = escapeHtml(sessionId); const safeTaskId = escapeHtml(task.id); return `
${escapeHtml(task.id)} ${escapeHtml(task.title || 'Untitled')}
${action ? `${escapeHtml(action)}` : ''} ${scope ? `${escapeHtml(scope)}` : ''} ${modCount > 0 ? `${modCount} mods` : ''} ${implCount > 0 ? `${implCount} steps` : ''} ${acceptCount > 0 ? `${acceptCount} acceptance` : ''}
`; } function getMetaPreviewForLite(task, rawTask) { const meta = task.meta || {}; const parts = []; if (meta.type || rawTask.action) parts.push(meta.type || rawTask.action); if (meta.scope || rawTask.scope) parts.push(meta.scope || rawTask.scope); return parts.join(' | ') || 'No meta'; } /** * Initialize click handlers for lite task items */ function initLiteTaskClickHandlers() { // Task item click handlers document.querySelectorAll('.lite-task-item').forEach(item => { if (!item._clickBound) { item._clickBound = true; item.addEventListener('click', function(e) { // Don't trigger if clicking on JSON button if (e.target.closest('.btn-view-json')) return; const sessionId = this.dataset.sessionId; const taskId = this.dataset.taskId; openTaskDrawerForLite(sessionId, taskId); }); } }); // JSON button click handlers document.querySelectorAll('.btn-view-json').forEach(btn => { if (!btn._clickBound) { btn._clickBound = true; btn.addEventListener('click', function(e) { e.stopPropagation(); const taskJsonId = this.dataset.taskJsonId; const displayId = this.dataset.taskDisplayId; showJsonModal(taskJsonId, displayId); }); } }); } function openTaskDrawerForLite(sessionId, taskId) { const session = liteTaskDataStore[currentSessionDetailKey]; if (!session) return; const task = session.tasks?.find(t => t.id === taskId); if (!task) return; // Set current drawer tasks and session context currentDrawerTasks = session.tasks || []; window._currentDrawerSession = session; document.getElementById('drawerTaskTitle').textContent = task.title || taskId; // Use dedicated lite task drawer renderer document.getElementById('drawerContent').innerHTML = renderLiteTaskDrawerContent(task, session); document.getElementById('taskDetailDrawer').classList.add('open'); document.getElementById('drawerOverlay').classList.add('active'); } function renderLitePlanTab(session) { const plan = session.plan; const isFixPlan = session.type === 'lite-fix'; if (!plan) { return `
No Plan Data
No ${isFixPlan ? 'fix-plan.json' : 'plan.json'} found for this session.
`; } return `
${plan.summary ? `

Summary

${escapeHtml(plan.summary)}

` : ''} ${plan.root_cause ? `

Root Cause

${escapeHtml(plan.root_cause)}

` : ''} ${plan.strategy ? `

Fix Strategy

${escapeHtml(plan.strategy)}

` : ''} ${plan.approach ? `

Approach

${escapeHtml(plan.approach)}

` : ''} ${plan.user_requirements ? `

User Requirements

${escapeHtml(plan.user_requirements)}

` : ''} ${plan.focus_paths?.length ? `

Focus Paths

${plan.focus_paths.map(p => `${escapeHtml(p)}`).join('')}
` : ''}

Metadata

${plan.severity ? `
Severity: ${escapeHtml(plan.severity)}
` : ''} ${plan.risk_level ? `
Risk Level: ${escapeHtml(plan.risk_level)}
` : ''} ${plan.estimated_time ? `
Estimated Time: ${escapeHtml(plan.estimated_time)}
` : ''} ${plan.complexity ? `
Complexity: ${escapeHtml(plan.complexity)}
` : ''} ${plan.recommended_execution ? `
Execution: ${escapeHtml(plan.recommended_execution)}
` : ''}
${plan.tasks?.length ? `

Fix Tasks (${plan.tasks.length})

${plan.tasks.map((task, idx) => `
#${idx + 1} ${escapeHtml(task.title || task.summary || 'Untitled')} ${task.scope ? `${escapeHtml(task.scope)}` : ''}
`).join('')}
` : ''}
`; } async function loadAndRenderLiteContextTab(session, contentArea) { contentArea.innerHTML = '
Loading context data...
'; try { if (window.SERVER_MODE && session.path) { const response = await fetch(`/api/session-detail?path=${encodeURIComponent(session.path)}&type=context`); if (response.ok) { const data = await response.json(); contentArea.innerHTML = renderLiteContextContent(data.context, data.explorations, session, data.diagnoses); // Re-initialize collapsible sections for explorations and diagnoses (scoped to contentArea) initCollapsibleSections(contentArea); return; } } // Fallback: show plan context if available contentArea.innerHTML = renderLiteContextContent(null, null, session, null); initCollapsibleSections(contentArea); } catch (err) { contentArea.innerHTML = `
Failed to load context: ${err.message}
`; } } async function loadAndRenderLiteSummaryTab(session, contentArea) { contentArea.innerHTML = '
Loading summaries...
'; try { if (window.SERVER_MODE && session.path) { const response = await fetch(`/api/session-detail?path=${encodeURIComponent(session.path)}&type=summary`); if (response.ok) { const data = await response.json(); contentArea.innerHTML = renderSummaryContent(data.summaries); return; } } // Fallback contentArea.innerHTML = `
No Summaries
No summaries found in .summaries/
`; if (typeof lucide !== 'undefined') lucide.createIcons(); } catch (err) { contentArea.innerHTML = `
Failed to load summaries: ${err.message}
`; } } // ============================================ // DIAGNOSES TAB RENDERING (lite-fix specific) // ============================================ function renderDiagnosesTab(session) { const diagnoses = session.diagnoses; if (!diagnoses || (!diagnoses.manifest && diagnoses.items?.length === 0)) { return `
${t('empty.noDiagnoses')}
${t('empty.noDiagnosesText')}
`; } let sections = []; // Manifest summary (if available) if (diagnoses.manifest) { sections.push(`

Diagnosis Summary

${diagnoses.manifest.total_diagnoses ? `
Total Diagnoses: ${diagnoses.manifest.total_diagnoses}
` : ''} ${diagnoses.manifest.diagnosis_angles ? `
Angles: ${diagnoses.manifest.diagnosis_angles.join(', ')}
` : ''} ${diagnoses.manifest.created_at ? `
Created: ${formatDate(diagnoses.manifest.created_at)}
` : ''}
`); } // Individual diagnosis items if (diagnoses.items && diagnoses.items.length > 0) { const diagnosisCards = diagnoses.items.map((diag) => { return renderDiagnosisCard(diag); }).join(''); sections.push(`

Diagnosis Details (${diagnoses.items.length})

${diagnosisCards}
`); } return `
${sections.join('')}
`; } function renderDiagnosisCard(diag) { const diagJsonId = `diag-json-${diag.id}`.replace(/[^a-zA-Z0-9-]/g, '-'); taskJsonStore[diagJsonId] = diag; return `
${escapeHtml(diag.id)}
`; } function renderDiagnosisContent(diag) { let content = []; // Symptom (for detailed diagnosis structure) if (diag.symptom) { const symptom = diag.symptom; content.push(`
Symptom: ${symptom.description ? `

${escapeHtml(symptom.description)}

` : ''} ${symptom.user_impact ? `
User Impact: ${escapeHtml(symptom.user_impact)}
` : ''} ${symptom.frequency ? `
Frequency: ${escapeHtml(symptom.frequency)}
` : ''} ${symptom.error_message ? `
Error: ${escapeHtml(symptom.error_message)}
` : ''}
`); } // Summary/Overview (for simple diagnosis structure) if (diag.summary || diag.overview) { content.push(`
Summary:

${escapeHtml(diag.summary || diag.overview)}

`); } // Root Cause Analysis if (diag.root_cause) { const rootCause = diag.root_cause; // Handle both object and string formats if (typeof rootCause === 'object') { content.push(`
Root Cause: ${rootCause.file ? `
File: ${escapeHtml(rootCause.file)}
` : ''} ${rootCause.line_range ? `
Lines: ${escapeHtml(rootCause.line_range)}
` : ''} ${rootCause.function ? `
Function: ${escapeHtml(rootCause.function)}
` : ''} ${rootCause.issue ? `

${escapeHtml(rootCause.issue)}

` : ''} ${rootCause.confidence ? `
Confidence: ${(rootCause.confidence * 100).toFixed(0)}%
` : ''} ${rootCause.category ? `
Category: ${escapeHtml(rootCause.category)}
` : ''}
`); } else if (typeof rootCause === 'string') { content.push(`
Root Cause:

${escapeHtml(rootCause)}

`); } } else if (diag.root_cause_analysis) { content.push(`
Root Cause:

${escapeHtml(diag.root_cause_analysis)}

`); } // Issues/Findings if (diag.issues && Array.isArray(diag.issues)) { content.push(`
Issues Found (${diag.issues.length}):
`); } // Affected Files if (diag.affected_files && Array.isArray(diag.affected_files)) { content.push(`
Affected Files:
${diag.affected_files.map(f => `${escapeHtml(typeof f === 'string' ? f : f.path || f.file)}`).join('')}
`); } // API Contracts (for api-contracts diagnosis) if (diag.contracts && Array.isArray(diag.contracts)) { content.push(`
API Contracts (${diag.contracts.length}):
${diag.contracts.map(contract => `
${escapeHtml(contract.endpoint || contract.name || 'Unknown')} ${contract.method ? `${escapeHtml(contract.method)}` : ''}
${contract.description ? `
${escapeHtml(contract.description)}
` : ''} ${contract.issues?.length ? `
${contract.issues.length} issue(s)
` : ''}
`).join('')}
`); } // Dataflow Analysis (for dataflow diagnosis) if (diag.dataflow || diag.data_flow) { const df = diag.dataflow || diag.data_flow; content.push(`
Data Flow Analysis: ${typeof df === 'string' ? `

${escapeHtml(df)}

` : `
${df.source ? `
Source: ${escapeHtml(df.source)}
` : ''} ${df.sink ? `
Sink: ${escapeHtml(df.sink)}
` : ''} ${df.transformations?.length ? `
Transformations:
    ${df.transformations.map(t => `
  1. ${escapeHtml(t)}
  2. `).join('')}
` : ''}
`}
`); } // Reproduction Steps if (diag.reproduction_steps && Array.isArray(diag.reproduction_steps)) { content.push(`
Reproduction Steps:
    ${diag.reproduction_steps.map(step => `
  1. ${escapeHtml(step)}
  2. `).join('')}
`); } // Fix Hints if (diag.fix_hints && Array.isArray(diag.fix_hints)) { content.push(`
Fix Hints (${diag.fix_hints.length}):
${diag.fix_hints.map((hint, idx) => `
Hint ${idx + 1}: ${escapeHtml(hint.description || 'No description')}
${hint.approach ? `
Approach: ${escapeHtml(hint.approach)}
` : ''} ${hint.risk ? `
Risk: ${escapeHtml(hint.risk)}
` : ''} ${hint.code_example ? `
Code Example:
${escapeHtml(hint.code_example)}
` : ''}
`).join('')}
`); } // Recommendations if (diag.recommendations && Array.isArray(diag.recommendations)) { content.push(`
Recommendations:
    ${diag.recommendations.map(rec => `
  1. ${escapeHtml(typeof rec === 'string' ? rec : rec.description || rec.action)}
  2. `).join('')}
`); } // Dependencies if (diag.dependencies && typeof diag.dependencies === 'string') { content.push(`
Dependencies:

${escapeHtml(diag.dependencies)}

`); } // Constraints if (diag.constraints && typeof diag.constraints === 'string') { content.push(`
Constraints:

${escapeHtml(diag.constraints)}

`); } // Clarification Needs if (diag.clarification_needs && Array.isArray(diag.clarification_needs)) { content.push(`
Clarification Needs:
${diag.clarification_needs.map(clar => `
Q: ${escapeHtml(clar.question)}
${clar.context ? `
Context: ${escapeHtml(clar.context)}
` : ''} ${clar.options && Array.isArray(clar.options) ? `
Options:
    ${clar.options.map(opt => `
  • ${escapeHtml(opt)}
  • `).join('')}
` : ''}
`).join('')}
`); } // Related Issues if (diag.related_issues && Array.isArray(diag.related_issues)) { content.push(`
Related Issues:
`); } // If no specific content was rendered, show raw JSON preview if (content.length === 0) { console.warn('[DEBUG] No content rendered for diagnosis:', diag); content.push(`
Debug: Raw JSON
${escapeHtml(JSON.stringify(diag, null, 2))}
`); } return content.join(''); }