87 `;
88
89function generateHtmlShell(sourceUrl: string): string {
90 return `
91 <!DOCTYPE html><html lang="en"><head><meta charset="UTF-8"><meta name="viewport" content="width=device-width, initial-scale=1.0"><title>Honeydew</title>
107 <template id="review-task-template"><div class="review-task-item"><input type="text" class="review-task-content" placeholder="Task description" required><input type="date" class="review-task-due-date" title="Due Date"><select class="review-task-load" title="Cognitive Load"><option value="Low">Low</option><option value="Medium" selected>Medium</option><option value="High">High</option></select><button type="button" class="review-task-delete-btn" title="Remove Task">×</button></div></template>
108 <script>
109 (function() {
110 const API_URL = '${sourceUrl}';
111 const STORE_KEYS = { projects: 'honeydew_projects_v1', tasks: 'honeydew_tasks_v1' };
117 const genId = () => Date.now().toString(36) + Math.random().toString(36).substr(2, 9);
118
119 function loadState() {
120 projects = getStore(STORE_KEYS.projects);
121 tasks = getStore(STORE_KEYS.tasks);
126 }
127
128 function render() {
129 renderSidebar();
130 renderTaskList();
132 }
133
134 function toggleLoading(btn, show) {
135 if (!btn) return;
136 btn.disabled = show;
138 }
139
140 function updateUIElements() {
141 const todayStr = new Date().toISOString().split("T")[0];
142 const todayTasks = tasks.filter(t => !t.isCompleted && t.dueDate === todayStr);
156 }
157
158 function renderSidebar() {
159 const mainViews = [
160 {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'},
165 }
166
167 function renderTaskList() {
168 const container = $("#task-list");
169 let filteredTasks = [], title = 'Tasks';
188 }
189
190 function renderChatLog() {
191 const log = $("#chat-log");
192 log.innerHTML = conversationHistory.map(msg => {
263 // --- MANUAL TOOL COMMAND LOGIC ---
264
265 function executeManualCommand(command) {
266 if (!command || !command.tool_name) return;
267
296 }
297
298 async function handleChatSubmit(e) {
299 e.preventDefault();
300 const input = $("#chat-input"), userMessage = input.value.trim();
345
346 // --- Standard Event Handlers ---
347 function handleAddTask(e) {
348 e.preventDefault();
349 const input = $("#new-task-input"), content = input.value.trim();
354 }
355
356 function handleTaskClick(e) {
357 const target = e.target, taskItem = target.closest(".task-item");
358 if (!taskItem) return;
369 }
370
371 function openEditModal(task) {
372 $("#edit-task-id").value = task.id;
373 $("#edit-task-content").value = task.content;
378 }
379
380 function handleUpdateTask(e) {
381 e.preventDefault();
382 const taskId = $("#edit-task-id").value, task = tasks.find(t => t.id === taskId);
390 }
391
392 async function triggerProjectSynthesisFromButton() {
393 const goal = prompt("Describe your new project or goal:", "Plan a launch party for a new product");
394 if (!goal) return;
407 }
408
409 async function triggerDailyRebalance() {
410 const todayStr = new Date().toISOString().split("T")[0];
411 const todayTasks = tasks.filter(t => !t.isCompleted && t.dueDate === todayStr);
433 }
434
435 function handleOpenChat() {
436 const mainInput = $('#new-task-input');
437 const text = mainInput.value.trim();
446 }
447
448 function addReviewTaskRow(taskData = {}) {
449 const template = $('#review-task-template');
450 const clone = template.content.cloneNode(true);
457 }
458
459 function openProjectReviewModal(data) {
460 const { projectName, tasks: aiTasks } = data;
461 $('#review-project-name').value = projectName;
468 }
469
470 function handleProjectReviewSubmit(e) {
471 e.preventDefault();
472 const projectName = $('#review-project-name').value.trim();
490 }
491
492 function bindEventListeners() {
493 document.body.addEventListener('click', e => {
494 if (e.target.closest('[data-view]')) {
546}
547
548export default async function(req: Request): Promise<Response> {
549 const openai = new OpenAI();
550 const url = new URL(req.url);