54 }.`;
55
56function generateHtmlShell(sourceUrl: string): string {
57 return `
58<!DOCTYPE html><html lang="en"><head><meta charset="UTF-8"><meta name="viewport" content="width=device-width, initial-scale=1.0"><title>AuraTask - AI Todo</title>
72<div class="modal-overlay" id="chat-modal"><div class="modal-content"><div class="chat-header"><h3>Chat with Aura</h3></div><div id="chat-log"></div><form id="chat-form"><input type="text" id="chat-input" placeholder="Ask Aura to do something..." required><button type="submit" class="btn btn-primary">Send</button></form></div></div>
73<script>
74(function() {
75 const API_URL = '${sourceUrl}';
76 const STORE_KEYS = { projects: 'aura_projects_v1', tasks: 'aura_tasks_v1' };
83 const genId = () => Date.now().toString(36) + Math.random().toString(36).substr(2, 9);
84
85 function checkTaskLoad() {
86 if (tasks.filter(t => !t.isCompleted).length >= ACTIVE_TASK_WARNING_THRESHOLD) {
87 return confirm("You have a lot of active tasks. Are you sure you want to add more? It might be a good time to complete some items first.");
90 }
91
92 function loadState() {
93 projects = getStore(STORE_KEYS.projects);
94 tasks = getStore(STORE_KEYS.tasks);
99 }
100
101 function render() {
102 renderSidebar();
103 renderTaskList();
105 }
106
107 function toggleLoading(btn, show) {
108 if (!btn) return;
109 isLoading = show;
112 }
113
114 function updateUIElements() {
115 const todayStr = new Date().toISOString().split("T")[0];
116 const todayTasks = tasks.filter(t => !t.isCompleted && t.dueDate === todayStr);
126 }
127
128 function renderSidebar() {
129 const mainViews = [
130 {id:'today',name:'Today',icon:'M6 2a1 1 0 00-1 1v1H4a2 2 0 00-2 2v10a2 2 0 002 2h12a2 2 0 002-2V6a2 2 0 00-2-2h-1V3a1 1 0 10-2 0v1H7V3a1 1 0 00-1-1z'},
135 }
136
137 function renderTaskList() {
138 const container = $("#task-list");
139 let filteredTasks = [], title = 'Tasks';
158 }
159
160 function renderChatLog() {
161 const log = $("#chat-log");
162 log.innerHTML = conversationHistory.map((msg, idx) => {
170 }
171
172 function addMessageToChat(sender, text, plan = null, requiresConfirmation = false) {
173 conversationHistory.push({ sender, text, plan, requiresConfirmation });
174 renderChatLog();
175 }
176
177 function executePlan(plan) {
178 plan.forEach(action => {
179 if (action.operation === 'CREATE_TASK') {
191 }
192
193 function handleAddTask(e) {
194 e.preventDefault();
195 if (!checkTaskLoad()) return;
204 }
205
206 function handleTaskClick(e) {
207 const target = e.target, taskItem = target.closest(".task-item");
208 if (!taskItem) return;
223 }
224
225 function openEditModal(task) {
226 $("#edit-task-id").value = task.id;
227 $("#edit-task-content").value = task.content;
232 }
233
234 function handleUpdateTask(e) {
235 e.preventDefault();
236 const taskId = $("#edit-task-id").value, task = tasks.find(t => t.id === taskId);
245 }
246
247 async function handleChatSubmit(e) {
248 e.preventDefault();
249 const input = $("#chat-input"), userMessage = input.value.trim();
268 }
269
270 function handlePlanConfirm(e) {
271 const action = e.target.dataset.planAction, idx = e.target.dataset.planIdx;
272 if (!action || !idx) return;
277 }
278
279 async function triggerProjectSynthesis() {
280 if (!checkTaskLoad()) return;
281 const goal = $("#synthesis-goal-input").value.trim();
307 }
308
309 async function triggerDailyRebalance() {
310 const todayStr = new Date().toISOString().split("T")[0];
311 const todayTasks = tasks.filter(t => !t.isCompleted && t.dueDate === todayStr);
339 }
340
341 function bindEventListeners() {
342 document.body.addEventListener('click', e => {
343 if (e.target.closest('[data-view]')) {
371}
372
373export default async function(req: Request): Promise<Response> {
374 const openai = new OpenAI();
375 const url = new URL(req.url);