/* ============================================================================= AUTO TASK JAVASCRIPT - Intelligent Self-Executing Task Interface Premium VIP Mode Functionality ============================================================================= */ // ============================================================================= // STATE MANAGEMENT // ============================================================================= const AutoTaskState = { currentFilter: 'all', tasks: [], compiledPlan: null, pendingDecisions: [], pendingApprovals: [], refreshInterval: null, wsConnection: null }; // ============================================================================= // INITIALIZATION // ============================================================================= document.addEventListener('DOMContentLoaded', function() { initAutoTask(); }); function initAutoTask() { // Initialize WebSocket for real-time updates initWebSocket(); // Start auto-refresh startAutoRefresh(); // Setup event listeners setupEventListeners(); // Load initial stats updateStats(); // Setup keyboard shortcuts setupKeyboardShortcuts(); console.log('AutoTask initialized'); } // ============================================================================= // WEBSOCKET CONNECTION // ============================================================================= function initWebSocket() { const protocol = window.location.protocol === 'https:' ? 'wss:' : 'ws:'; const wsUrl = `${protocol}//${window.location.host}/ws/autotask`; try { AutoTaskState.wsConnection = new WebSocket(wsUrl); AutoTaskState.wsConnection.onopen = function() { console.log('AutoTask WebSocket connected'); }; AutoTaskState.wsConnection.onmessage = function(event) { handleWebSocketMessage(JSON.parse(event.data)); }; AutoTaskState.wsConnection.onclose = function() { console.log('AutoTask WebSocket disconnected, reconnecting...'); setTimeout(initWebSocket, 5000); }; AutoTaskState.wsConnection.onerror = function(error) { console.error('AutoTask WebSocket error:', error); }; } catch (e) { console.warn('WebSocket not available, using polling'); } } function handleWebSocketMessage(data) { switch (data.type) { case 'task_update': updateTaskInList(data.task); break; case 'step_progress': updateStepProgress(data.taskId, data.step, data.progress); break; case 'decision_required': showDecisionNotification(data.decision); break; case 'approval_required': showApprovalNotification(data.approval); break; case 'task_completed': onTaskCompleted(data.task); break; case 'task_failed': onTaskFailed(data.task, data.error); break; case 'stats_update': updateStatsFromData(data.stats); break; } } // ============================================================================= // EVENT LISTENERS // ============================================================================= function setupEventListeners() { // Intent form submission const intentForm = document.getElementById('intent-form'); if (intentForm) { intentForm.addEventListener('htmx:afterSwap', function(event) { if (event.detail.target.id === 'compilation-result') { onCompilationComplete(event); } }); } // Task list updates const taskList = document.getElementById('task-list'); if (taskList) { taskList.addEventListener('htmx:afterSwap', function() { updateStats(); highlightPendingItems(); }); } // Expand log entries on details open document.addEventListener('toggle', function(event) { if (event.target.classList.contains('execution-log') && event.target.open) { const taskId = event.target.closest('.autotask-item')?.dataset.taskId; if (taskId) { loadExecutionLogs(taskId); } } }, true); } function setupKeyboardShortcuts() { document.addEventListener('keydown', function(e) { // Alt + N: Focus on intent input if (e.altKey && e.key === 'n') { e.preventDefault(); document.getElementById('intent-input')?.focus(); } // Alt + R: Refresh tasks if (e.altKey && e.key === 'r') { e.preventDefault(); refreshTasks(); } // Escape: Close any open modal if (e.key === 'Escape') { closeAllModals(); } // Alt + 1-4: Switch filters if (e.altKey && e.key >= '1' && e.key <= '4') { e.preventDefault(); const filters = ['all', 'running', 'approval', 'decision']; const index = parseInt(e.key) - 1; const tabs = document.querySelectorAll('.filter-tab'); if (tabs[index]) { tabs[index].click(); } } }); } // ============================================================================= // AUTO REFRESH // ============================================================================= function startAutoRefresh() { // Refresh every 5 seconds AutoTaskState.refreshInterval = setInterval(function() { if (!document.hidden) { updateStats(); } }, 5000); } function stopAutoRefresh() { if (AutoTaskState.refreshInterval) { clearInterval(AutoTaskState.refreshInterval); AutoTaskState.refreshInterval = null; } } // ============================================================================= // STATS MANAGEMENT // ============================================================================= function updateStats() { fetch('/api/autotask/stats') .then(response => response.json()) .then(stats => { updateStatsFromData(stats); }) .catch(error => { console.error('Failed to fetch stats:', error); }); } function updateStatsFromData(stats) { // Header stats document.getElementById('stat-running').textContent = stats.running || 0; document.getElementById('stat-pending').textContent = stats.pending || 0; document.getElementById('stat-completed').textContent = stats.completed || 0; document.getElementById('stat-approval').textContent = stats.pending_approval || 0; // Filter counts document.getElementById('count-all').textContent = stats.total || 0; document.getElementById('count-running').textContent = stats.running || 0; document.getElementById('count-approval').textContent = stats.pending_approval || 0; document.getElementById('count-decision').textContent = stats.pending_decision || 0; // Highlight if approvals needed const approvalStat = document.querySelector('.stat-item.highlight'); if (approvalStat && stats.pending_approval > 0) { approvalStat.classList.add('attention'); } else if (approvalStat) { approvalStat.classList.remove('attention'); } } // ============================================================================= // TASK FILTERING // ============================================================================= function filterTasks(filter, button) { AutoTaskState.currentFilter = filter; // Update active tab document.querySelectorAll('.filter-tab').forEach(tab => { tab.classList.remove('active'); }); button.classList.add('active'); // Trigger HTMX request htmx.ajax('GET', `/api/autotask/list?filter=${filter}`, { target: '#task-list', swap: 'innerHTML' }); } function refreshTasks() { const filter = AutoTaskState.currentFilter; htmx.ajax('GET', `/api/autotask/list?filter=${filter}`, { target: '#task-list', swap: 'innerHTML' }); updateStats(); } // ============================================================================= // COMPILATION HANDLING // ============================================================================= function onCompilationComplete(event) { const result = event.detail.target.querySelector('.compiled-plan'); if (result) { // Scroll to result result.scrollIntoView({ behavior: 'smooth', block: 'start' }); // Store compiled plan const planId = result.dataset?.planId; if (planId) { AutoTaskState.compiledPlan = planId; } // Syntax highlight the code highlightBasicCode(); } } function highlightBasicCode() { const codeBlocks = document.querySelectorAll('.code-preview code'); codeBlocks.forEach(block => { // Basic syntax highlighting for BASIC keywords let html = block.innerHTML; // Keywords const keywords = [ 'PLAN_START', 'PLAN_END', 'STEP', 'SET', 'GET', 'IF', 'THEN', 'ELSE', 'END IF', 'FOR EACH', 'NEXT', 'WHILE', 'WEND', 'TALK', 'HEAR', 'LLM', 'CREATE_TASK', 'RUN_PYTHON', 'RUN_JAVASCRIPT', 'RUN_BASH', 'USE_MCP', 'POST', 'GET', 'PUT', 'PATCH', 'DELETE HTTP', 'REQUIRE_APPROVAL', 'SIMULATE_IMPACT', 'AUDIT_LOG', 'SEND_MAIL', 'SAVE', 'UPDATE', 'INSERT', 'DELETE', 'FIND' ]; keywords.forEach(keyword => { const regex = new RegExp(`\\b${keyword}\\b`, 'g'); html = html.replace(regex, `${keyword}`); }); // Comments html = html.replace(/(\'[^\n]*)/g, '$1'); // Strings html = html.replace(/("[^"]*")/g, '$1'); // Numbers html = html.replace(/\b(\d+)\b/g, '$1'); block.innerHTML = html; }); } function copyGeneratedCode() { const code = document.querySelector('.code-preview code')?.textContent; if (code) { navigator.clipboard.writeText(code).then(() => { showToast('Code copied to clipboard', 'success'); }).catch(() => { showToast('Failed to copy code', 'error'); }); } } function discardPlan() { if (confirm('Are you sure you want to discard this plan?')) { document.getElementById('compilation-result').innerHTML = ''; AutoTaskState.compiledPlan = null; document.getElementById('intent-input').value = ''; document.getElementById('intent-input').focus(); } } function editPlan() { // TODO: Implement plan editor showToast('Plan editor coming soon!', 'info'); } // ============================================================================= // PLAN EXECUTION // ============================================================================= function simulatePlan(planId) { showSimulationModal(); fetch(`/api/autotask/simulate/${planId}`, { method: 'POST' }) .then(response => response.json()) .then(result => { renderSimulationResult(result); }) .catch(error => { document.getElementById('simulation-content').innerHTML = `
❌

Failed to simulate plan: ${error.message}

`; }); } function executePlan(planId) { const executionMode = document.querySelector('[name="execution_mode"]')?.value || 'semi-automatic'; const priority = document.querySelector('[name="priority"]')?.value || 'medium'; if (!confirm('Are you sure you want to execute this plan?')) { return; } fetch('/api/autotask/execute', { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ plan_id: planId, execution_mode: executionMode, priority: priority }) }) .then(response => response.json()) .then(result => { if (result.success) { showToast('Task execution started!', 'success'); document.getElementById('compilation-result').innerHTML = ''; document.getElementById('intent-input').value = ''; refreshTasks(); } else { showToast(`Failed to start execution: ${result.error}`, 'error'); } }) .catch(error => { showToast(`Failed to execute plan: ${error.message}`, 'error'); }); } // ============================================================================= // TASK ACTIONS // ============================================================================= function viewTaskDetails(taskId) { window.location.href = `/suite/tasks/detail/${taskId}`; } function simulateTask(taskId) { showSimulationModal(); fetch(`/api/autotask/${taskId}/simulate`, { method: 'POST' }) .then(response => response.json()) .then(result => { result.task_id = taskId; renderSimulationResult(result); }) .catch(error => { document.getElementById('simulation-content').innerHTML = `
❌

Failed to simulate task: ${error.message}

`; }); } function pauseTask(taskId) { fetch(`/api/autotask/${taskId}/pause`, { method: 'POST' }) .then(response => response.json()) .then(result => { if (result.success) { showToast('Task paused', 'success'); refreshTasks(); } else { showToast(`Failed to pause task: ${result.error}`, 'error'); } }); } function resumeTask(taskId) { fetch(`/api/autotask/${taskId}/resume`, { method: 'POST' }) .then(response => response.json()) .then(result => { if (result.success) { showToast('Task resumed', 'success'); refreshTasks(); } else { showToast(`Failed to resume task: ${result.error}`, 'error'); } }); } function cancelTask(taskId) { if (!confirm('Are you sure you want to cancel this task? This may not be reversible.')) { return; } fetch(`/api/autotask/${taskId}/cancel`, { method: 'POST' }) .then(response => response.json()) .then(result => { if (result.success) { showToast('Task cancelled', 'success'); refreshTasks(); } else { showToast(`Failed to cancel task: ${result.error}`, 'error'); } }); } function updateTaskInList(task) { const taskElement = document.querySelector(`[data-task-id="${task.id}"]`); if (taskElement) { // Update status badge const statusBadge = taskElement.querySelector('.task-status-badge'); if (statusBadge) { statusBadge.className = `task-status-badge status-${task.status}`; statusBadge.textContent = task.status.replace(/-/g, ' '); } // Update progress const progressFill = taskElement.querySelector('.progress-fill'); const progressText = taskElement.querySelector('.progress-text'); if (progressFill && progressText) { progressFill.style.width = `${task.progress}%`; progressText.textContent = `${task.current_step}/${task.total_steps} steps (${Math.round(task.progress)}%)`; } // Update data attribute taskElement.dataset.status = task.status; } } function updateStepProgress(taskId, step, progress) { const taskElement = document.querySelector(`[data-task-id="${taskId}"]`); if (taskElement) { const currentStep = taskElement.querySelector('.current-step'); if (currentStep) { currentStep.querySelector('.step-name').textContent = `Step ${step.order}: ${step.name}`; currentStep.querySelector('.step-status').textContent = `${Math.round(progress)}%`; } } } // ============================================================================= // DECISIONS // ============================================================================= function viewDecisions(taskId) { showDecisionModal(); fetch(`/api/autotask/${taskId}/decisions`) .then(response => response.json()) .then(decisions => { renderDecisions(taskId, decisions); }) .catch(error => { document.getElementById('decision-content').innerHTML = `
❌

Failed to load decisions: ${error.message}

`; }); } function renderDecisions(taskId, decisions) { const container = document.getElementById('decision-content'); if (!decisions || decisions.length === 0) { container.innerHTML = '

No pending decisions.

'; return; } let html = '
'; decisions.forEach(decision => { html += `

${decision.title}

${decision.description}

${decision.options.map(opt => `

${opt.description}

πŸ’° ${opt.estimated_impact.cost_change >= 0 ? '+' : ''}$${opt.estimated_impact.cost_change} ⏱️ ${opt.estimated_impact.time_change_minutes >= 0 ? '+' : ''}${opt.estimated_impact.time_change_minutes}m ⚠️ ${opt.risk_level}
`).join('')}
`; }); html += '
'; container.innerHTML = html; } function submitDecision(taskId, decisionId) { const selectedOption = document.querySelector(`input[name="decision_${decisionId}"]:checked`)?.value; if (!selectedOption) { showToast('Please select an option', 'warning'); return; } fetch(`/api/autotask/${taskId}/decide`, { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ decision_id: decisionId, option_id: selectedOption }) }) .then(response => response.json()) .then(result => { if (result.success) { showToast('Decision submitted', 'success'); closeDecisionModal(); refreshTasks(); } else { showToast(`Failed to submit decision: ${result.error}`, 'error'); } }); } function skipDecision(taskId, decisionId) { if (!confirm('Are you sure you want to skip this decision? The default option will be used.')) { return; } fetch(`/api/autotask/${taskId}/decide`, { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ decision_id: decisionId, skip: true }) }) .then(response => response.json()) .then(result => { if (result.success) { showToast('Decision skipped', 'info'); closeDecisionModal(); refreshTasks(); } else { showToast(`Failed to skip decision: ${result.error}`, 'error'); } }); } function showDecisionNotification(decision) { showToast(`Decision required: ${decision.title}`, 'warning', 10000); updateStats(); } // ============================================================================= // APPROVALS // ============================================================================= function viewApprovals(taskId) { showApprovalModal(); fetch(`/api/autotask/${taskId}/approvals`) .then(response => response.json()) .then(approvals => { renderApprovals(taskId, approvals); }) .catch(error => { document.getElementById('approval-content').innerHTML = `
❌

Failed to load approvals: ${error.message}

`; }); } function renderApprovals(taskId, approvals) { const container = document.getElementById('approval-content'); if (!approvals || approvals.length === 0) { container.innerHTML = '

No pending approvals.

'; return; } let html = '
'; approvals.forEach(approval => { html += `
${approval.approval_type.replace(/_/g, ' ')} ${approval.risk_level} Risk

${approval.title}

${approval.description}

Impact Summary

${approval.impact_summary}

${approval.simulation_result ? `
Simulation Result
Risk: ${approval.simulation_result.risk_level} Confidence: ${Math.round(approval.simulation_result.confidence * 100)}%
` : ''}
Step: ${approval.step_name || 'N/A'} Expires: ${formatRelativeTime(approval.expires_at)} Default: ${approval.default_action}
`; }); html += '
'; container.innerHTML = html; } function approveApproval(taskId, approvalId) { submitApprovalDecision(taskId, approvalId, 'approve'); } function rejectApproval(taskId, approvalId) { if (!confirm('Are you sure you want to reject this action?')) { return; } submitApprovalDecision(taskId, approvalId, 'reject'); } function deferApproval(taskId, approvalId) { submitApprovalDecision(taskId, approvalId, 'defer'); } function submitApprovalDecision(taskId, approvalId, action) { fetch(`/api/autotask/${taskId}/approve`, { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ approval_id: approvalId, action: action }) }) .then(response => response.json()) .then(result => { if (result.success) { const messages = { 'approve': 'Approval granted', 'reject': 'Approval rejected', 'defer': 'Approval deferred' }; showToast(messages[action], 'success'); closeApprovalModal(); refreshTasks(); } else { showToast(`Failed to ${action}: ${result.error}`, 'error'); } }); } function showApprovalNotification(approval) { showToast(`Approval required: ${approval.title}`, 'warning', 10000); updateStats(); } // ============================================================================= // SIMULATION // ============================================================================= function renderSimulationResult(result) { const container = document.getElementById('simulation-content'); const statusIcon = result.success ? 'βœ…' : '⚠️'; const statusText = result.success ? 'Simulation Successful' : 'Simulation Found Issues'; let html = `
${statusIcon} ${statusText}
Confidence: ${Math.round(result.confidence * 100)}%

Impact Assessment

πŸ’Ύ Data Impact ${result.impact.data_impact.records_modified} records modified
πŸ’° Cost Impact $${result.impact.cost_impact.total_estimated_cost.toFixed(2)}
⏱️ Time Impact ${formatDuration(result.impact.time_impact.estimated_duration_seconds)}
πŸ”’ Security Impact ${result.impact.security_impact.risk_level}

Step-by-Step Predictions

${result.step_outcomes.map(step => `
${step.would_succeed ? 'βœ…' : '⚠️'} ${step.step_name} ${Math.round(step.success_probability * 100)}% success
`).join('')}
${result.side_effects.length > 0 ? `

⚠️ Potential Side Effects

${result.side_effects.map(effect => `
${effect.description} ${effect.mitigation ? `Mitigation: ${effect.mitigation}` : ''}
`).join('')}
` : ''} ${result.recommendations.length > 0 ? `

πŸ’‘ Recommendations

${result.recommendations.map(rec => `
${rec.description} ${rec.action ? `` : ''}
`).join('')}
` : ''}
`; container.innerHTML = html; } function proc