From 170c65f5794ae0a4528606c8c7fbcec306546166 Mon Sep 17 00:00:00 2001 From: Echo Date: Mon, 2 Feb 2026 12:47:34 +0000 Subject: [PATCH] Update dashboard, memory, root (~6) --- AGENTS.md | 23 ++- TOOLS.md | 36 +++- dashboard/api.py | 6 +- dashboard/index.html | 322 ++++++++++++++++++++++++------ dashboard/todos.json | 8 +- memory/kb/projects/FLUX-JOBURI.md | 35 ++++ 6 files changed, 352 insertions(+), 78 deletions(-) diff --git a/AGENTS.md b/AGENTS.md index 604b9fe..32c0ac9 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -294,21 +294,28 @@ Dashboard: https://moltbot.tailf7372d.ts.net/echo/ --- -## 📊 Tipuri de propuneri în rapoarte +## 📊 Rapoarte cu propuneri acționabile -**Task-uri executabile** (le fac eu): -- Commit/push git -- Actualizare job-uri -- Creare fișiere/documente -- Automatizări +**📖 Documentație completă:** [`memory/kb/projects/FLUX-JOBURI.md`](memory/kb/projects/FLUX-JOBURI.md) + +**Categorii propuneri:** +- 🤖 **FAC EU** - Echo singur (git, fișiere, jobs) +- 🤝 **TU+EU** - Marius + Echo (sesiuni, review) +- 👤 **FACI TU** - Doar Marius (decizii, acțiuni externe) + +**Timing propuneri:** +- ⚡ **ACUM** - imediat după "1 pentru X" +- 🌙 **NOAPTE** - job 23:00 după "2 pentru X" +- 📅 **PROGRAMAT** - dată specifică +- ⏳ **CÂND POȚI** - fără deadline + +**Format obligatoriu:** `A0 - Titlu [categorie] [timing]` **Întrebări de reflecție** (pentru Marius): - NU le trimit pe canal - Le pun în `memory/kb/reflectii/YYYY-MM-DD_titlu.md` - Marius le citește când vrea -**În raport:** Fii explicit ce tip e fiecare propunere! - --- ## 📊 Flux Insights → Approved Tasks (OBLIGATORIU pentru rapoarte) diff --git a/TOOLS.md b/TOOLS.md index 2b107cc..2093869 100644 --- a/TOOLS.md +++ b/TOOLS.md @@ -107,13 +107,13 @@ memory_get path="memory/file.md" from=1 lines=50 | 01:00 | 03:00 | night-execute-late | #echo-work | Continuă execuția task-uri (run 2) | | 03:00 | 05:00 | archive-tasks | #echo-work | Arhivează task-uri vechi | | 06:00,17:00 | 08:00,19:00 | insights-extract | - | Extrage insights din memory/kb/ | -| 06:30 | 08:30 | morning-report | 📧 EMAIL | Raport dimineață HTML + TOATE propunerile cu context | +| 06:30 | 08:30 | morning-report | 📧 EMAIL | Raport dimineață - vezi [FLUX-JOBURI.md](memory/kb/projects/FLUX-JOBURI.md) | | 07:00 | 09:00 | morning-coaching | #echo-self + 📧 | Gând + provocare → memory/kb/coaching/ | | 07-17 | 09-19 | respiratie-orar | #echo-self | Pauze orare pattern interrupt | | 15:00 mar,joi | 17:00 | project-checkin | #echo-work | Check-in Vending Master | | 15:00 3/feb | 17:00 | grup-sprijin-pregatire | #echo-sprijin | Pregătire fișă grup joi | | 15:00 5/feb | 17:00 | grup-sprijin-5feb | #echo-sprijin | Reminder grup sprijin | -| 18:00 | 20:00 | evening-report | 📧 EMAIL | Raport seară HTML + TOATE propunerile cu context | +| 18:00 | 20:00 | evening-report | 📧 EMAIL | Raport seară - vezi [FLUX-JOBURI.md](memory/kb/projects/FLUX-JOBURI.md) | | 19:00 | 21:00 | evening-coaching | #echo-self + 📧 | Reflecție seară → memory/kb/coaching/ | | 20:00 | 22:00 | seara-merit-reminder | #echo-self | Reminder lista "10 lucruri pentru care merit respect" | | 19:00 dum | 21:00 | weekly-planning | #echo-work | Planning săptămânal | @@ -249,6 +249,38 @@ cron action=update jobId=X # modifică job | 108 | LXC | central-oracle | running | | 171 | LXC | claude-agent | running | +##### LXC 171 - claude-agent (Development Environment) +- **IP:** 10.0.20.171 +- **Resurse:** 4 cores, 16GB RAM, 32GB disk +- **OS:** Ubuntu (unprivileged, nesting enabled) +- **Tailscale:** Da (acces remote) + +**Servicii:** +- `code-server@claude` — VS Code în browser +- `ttyd` — Web Terminal +- `ssh` — acces direct + +**Claude Code:** +- Instalat și configurat +- Git configurat pentru `gitea.romfast.ro` +- Mod interactiv: `claude` (în terminal) +- Mod programatic: `claude -p "task description"` — pentru sarcini automatizate + +**Utilizare:** +```bash +# Acces SSH +ssh user@10.0.20.171 + +# Sau prin Proxmox +ssh echo@10.0.20.201 "sudo pct exec 171 -- bash" + +# Claude Code - interactiv +claude + +# Claude Code - task direct +claude -p "descrie sarcina aici" +``` + #### pve1 (10.0.20.200) - **Resurse:** 32GB RAM, 1.3TB disk - **SSH:** `ssh echo@10.0.20.200` diff --git a/dashboard/api.py b/dashboard/api.py index f187850..224dd56 100644 --- a/dashboard/api.py +++ b/dashboard/api.py @@ -192,11 +192,15 @@ class TaskBoardHandler(SimpleHTTPRequestHandler): ).stdout.strip() # Parse uncommitted into structured format + # Format: XY PATH where XY is 2 chars (index + working tree status) + # Examples: "M file" (staged), " M file" (unstaged), "?? file" (untracked) uncommitted_parsed = [] for line in uncommitted: if len(line) >= 3: status = line[:2].strip() - filepath = line[3:].strip() + # Path starts at position 3 for most cases, but we use lstrip + # to handle edge cases where there's no separator space + filepath = line[2:].lstrip().strip() uncommitted_parsed.append({'status': status, 'path': filepath}) self.send_json({ diff --git a/dashboard/index.html b/dashboard/index.html index 2044823..becb3c9 100644 --- a/dashboard/index.html +++ b/dashboard/index.html @@ -970,6 +970,27 @@ margin-bottom: var(--space-3); opacity: 0.5; } + + /* Danger button */ + .btn-danger { + background: #dc2626; + color: white; + border: none; + padding: var(--space-2) var(--space-4); + border-radius: var(--radius-md); + font-size: var(--text-sm); + cursor: pointer; + transition: all var(--transition-fast); + } + + .btn-danger:hover { + background: #b91c1c; + } + + /* Clickable todo item */ + .todo-item { + cursor: pointer; + } @@ -1181,10 +1202,11 @@ - - + + + @@ -1412,7 +1485,8 @@ `; if (git.uncommittedCount > 0) { - const files = git.uncommitted.slice(0, 3).map(f => f.trim().split(' ').pop()).join(', '); + // Use uncommittedParsed for correctly parsed paths + const files = (git.uncommittedParsed || []).slice(0, 3).map(f => f.path).join(', '); const more = git.uncommittedCount > 3 ? ` +${git.uncommittedCount - 3}` : ''; html += `
@@ -1662,8 +1736,8 @@ function renderTodoItem(todo) { const isOverdue = !todo.done && todo.dueDate < new Date().toISOString().split('T')[0]; return ` -
-
+
+
@@ -1746,36 +1820,102 @@ } function showAddTodoModal() { - const text = prompt('Todo (ex: @work Verifică client X)'); - if (text && text.trim()) { - addTodo(text.trim()); - } + document.getElementById('todoModalTitle').textContent = 'Todo nou'; + document.getElementById('todoEditId').value = ''; + document.getElementById('todoText').value = ''; + document.getElementById('todoContext').value = ''; + document.getElementById('todoExample').value = ''; + document.getElementById('todoDomain').value = 'work'; + document.getElementById('todoDueDate').value = new Date().toISOString().split('T')[0]; + document.getElementById('todoSource').value = ''; + document.getElementById('todoSourceUrl').value = ''; + document.getElementById('todoDeleteBtn').style.display = 'none'; + document.getElementById('todoSaveBtn').textContent = 'Adaugă'; + document.getElementById('todoModal').classList.add('active'); + document.getElementById('todoText').focus(); } - async function addTodo(text) { - // Parse domain from text (@work, @self, @sprijin, @scout) - let domain = 'work'; - const domainMatch = text.match(/@(work|self|sprijin|scout)/i); - if (domainMatch) { - domain = domainMatch[1].toLowerCase(); - text = text.replace(/@(work|self|sprijin|scout)/i, '').trim(); + function editTodo(id) { + const todo = todosData.items.find(t => t.id === id); + if (!todo) return; + + document.getElementById('todoModalTitle').textContent = 'Editare todo'; + document.getElementById('todoEditId').value = id; + document.getElementById('todoText').value = todo.text || ''; + document.getElementById('todoContext').value = todo.context || ''; + document.getElementById('todoExample').value = todo.example || ''; + document.getElementById('todoDomain').value = todo.domain || 'work'; + document.getElementById('todoDueDate').value = todo.dueDate || ''; + document.getElementById('todoSource').value = todo.source || ''; + document.getElementById('todoSourceUrl').value = todo.sourceUrl || ''; + document.getElementById('todoDeleteBtn').style.display = 'block'; + document.getElementById('todoSaveBtn').textContent = 'Salvează'; + document.getElementById('todoModal').classList.add('active'); + document.getElementById('todoText').focus(); + } + + function hideTodoModal() { + document.getElementById('todoModal').classList.remove('active'); + } + + async function saveTodoForm() { + const text = document.getElementById('todoText').value.trim(); + if (!text) { + showToast('Textul este obligatoriu', 'error'); + return; } - const todo = { - id: 'todo-' + Date.now(), - text: text, - domain: domain, - dueDate: new Date().toISOString().split('T')[0], - done: false, - doneAt: null, - source: 'manual', - createdAt: new Date().toISOString() - }; + const editId = document.getElementById('todoEditId').value; - todosData.items.push(todo); + if (editId) { + // Edit existing + const todo = todosData.items.find(t => t.id === editId); + if (todo) { + todo.text = text; + todo.context = document.getElementById('todoContext').value.trim() || null; + todo.example = document.getElementById('todoExample').value.trim() || null; + todo.domain = document.getElementById('todoDomain').value; + todo.dueDate = document.getElementById('todoDueDate').value || null; + todo.source = document.getElementById('todoSource').value.trim() || null; + todo.sourceUrl = document.getElementById('todoSourceUrl').value.trim() || null; + todo.updatedAt = new Date().toISOString(); + } + showToast('Todo actualizat'); + } else { + // Add new + const todo = { + id: 'todo-' + Date.now(), + text: text, + context: document.getElementById('todoContext').value.trim() || null, + example: document.getElementById('todoExample').value.trim() || null, + domain: document.getElementById('todoDomain').value, + dueDate: document.getElementById('todoDueDate').value || new Date().toISOString().split('T')[0], + done: false, + doneAt: null, + source: document.getElementById('todoSource').value.trim() || 'manual', + sourceUrl: document.getElementById('todoSourceUrl').value.trim() || null, + createdAt: new Date().toISOString() + }; + todosData.items.push(todo); + showToast('Todo adăugat'); + } + + hideTodoModal(); await saveTodos(); renderTodos(); - showToast('Todo adăugat'); + } + + async function deleteTodo() { + const editId = document.getElementById('todoEditId').value; + if (!editId) return; + + if (!confirm('Sigur ștergi acest todo?')) return; + + todosData.items = todosData.items.filter(t => t.id !== editId); + hideTodoModal(); + await saveTodos(); + renderTodos(); + showToast('Todo șters'); } // ===== ISSUES ===== @@ -2028,13 +2168,6 @@ showToast(issue.status === 'done' ? 'Issue finalizat! ✓' : 'Issue redeschis'); } - function editIssue(id) { - const issue = issuesData.issues.find(i => i.id === id); - if (issue) { - alert(`Edit: ${issue.title}\n\n${issue.description || 'Fără descriere'}`); - } - } - // Filters document.getElementById('issuesFilters').addEventListener('click', (e) => { if (e.target.classList.contains('filter-btn')) { @@ -2045,22 +2178,47 @@ } }); - // Modal + // Issue Modal function showAddModal() { - document.getElementById('addModal').classList.add('active'); - document.getElementById('issueTitle').focus(); - } - - function hideAddModal() { - document.getElementById('addModal').classList.remove('active'); + document.getElementById('issueModalTitle').textContent = 'Issue nou'; + document.getElementById('issueEditId').value = ''; document.getElementById('issueTitle').value = ''; document.getElementById('issueDesc').value = ''; document.getElementById('issueProgram').value = ''; document.getElementById('issueOwner').value = 'marius'; document.getElementById('issuePriority').value = 'urgent-important'; document.getElementById('issueDeadline').value = ''; + document.getElementById('issueDeleteBtn').style.display = 'none'; + document.getElementById('issueSaveBtn').textContent = 'Adaugă'; + document.getElementById('issueModal').classList.add('active'); + document.getElementById('issueTitle').focus(); } + function editIssue(id) { + const issue = issuesData.issues.find(i => i.id === id); + if (!issue) return; + + document.getElementById('issueModalTitle').textContent = 'Editare issue'; + document.getElementById('issueEditId').value = id; + document.getElementById('issueTitle').value = issue.title || ''; + document.getElementById('issueDesc').value = issue.description || ''; + document.getElementById('issueProgram').value = issue.program || ''; + document.getElementById('issueOwner').value = issue.owner || 'marius'; + document.getElementById('issuePriority').value = issue.priority || 'backlog'; + document.getElementById('issueDeadline').value = issue.deadline || ''; + document.getElementById('issueDeleteBtn').style.display = 'block'; + document.getElementById('issueSaveBtn').textContent = 'Salvează'; + document.getElementById('issueModal').classList.add('active'); + document.getElementById('issueTitle').focus(); + } + + function hideIssueModal() { + document.getElementById('issueModal').classList.remove('active'); + } + + // Legacy alias + function hideAddModal() { hideIssueModal(); } + function populateProgramSelect() { const select = document.getElementById('issueProgram'); select.innerHTML = ''; @@ -2071,32 +2229,67 @@ } } - async function addIssue() { + async function saveIssue() { const title = document.getElementById('issueTitle').value.trim(); if (!title) { showToast('Titlul este obligatoriu', 'error'); return; } - const newIssue = { - id: 'ROA-' + String(issuesData.issues.length + 1).padStart(3, '0'), - title: title, - description: document.getElementById('issueDesc').value.trim(), - program: document.getElementById('issueProgram').value, - owner: document.getElementById('issueOwner').value, - priority: document.getElementById('issuePriority').value, - status: 'todo', - created: new Date().toISOString(), - deadline: document.getElementById('issueDeadline').value || null - }; + const editId = document.getElementById('issueEditId').value; + + if (editId) { + // Edit existing + const issue = issuesData.issues.find(i => i.id === editId); + if (issue) { + issue.title = title; + issue.description = document.getElementById('issueDesc').value.trim(); + issue.program = document.getElementById('issueProgram').value; + issue.owner = document.getElementById('issueOwner').value; + issue.priority = document.getElementById('issuePriority').value; + issue.deadline = document.getElementById('issueDeadline').value || null; + issue.updated = new Date().toISOString(); + } + showToast('Issue actualizat!'); + } else { + // Add new + const newIssue = { + id: 'ROA-' + String(issuesData.issues.length + 1).padStart(3, '0'), + title: title, + description: document.getElementById('issueDesc').value.trim(), + program: document.getElementById('issueProgram').value, + owner: document.getElementById('issueOwner').value, + priority: document.getElementById('issuePriority').value, + status: 'todo', + created: new Date().toISOString(), + deadline: document.getElementById('issueDeadline').value || null + }; + issuesData.issues.unshift(newIssue); + showToast('Issue adăugat!'); + } - issuesData.issues.unshift(newIssue); - hideAddModal(); + hideIssueModal(); renderIssues(); updateIssuesCount(); await saveIssues(); - showToast('Issue adăugat!'); } + + async function deleteIssue() { + const editId = document.getElementById('issueEditId').value; + if (!editId) return; + + if (!confirm('Sigur ștergi acest issue?')) return; + + issuesData.issues = issuesData.issues.filter(i => i.id !== editId); + hideIssueModal(); + renderIssues(); + updateIssuesCount(); + await saveIssues(); + showToast('Issue șters'); + } + + // Legacy alias + async function addIssue() { await saveIssue(); } async function saveIssues() { issuesData.lastUpdated = new Date().toISOString(); @@ -2122,9 +2315,12 @@ setTimeout(() => toast.classList.remove('show'), 3000); } - // Close modal on outside click - document.getElementById('addModal').addEventListener('click', (e) => { - if (e.target.id === 'addModal') hideAddModal(); + // Close modals on outside click + document.getElementById('issueModal').addEventListener('click', (e) => { + if (e.target.id === 'issueModal') hideIssueModal(); + }); + document.getElementById('todoModal').addEventListener('click', (e) => { + if (e.target.id === 'todoModal') hideTodoModal(); }); // Init diff --git a/dashboard/todos.json b/dashboard/todos.json index 665127e..98b186b 100644 --- a/dashboard/todos.json +++ b/dashboard/todos.json @@ -1,5 +1,5 @@ { - "lastUpdated": "2026-02-02T11:29:00Z", + "lastUpdated": "2026-02-02T12:17:34.010Z", "items": [ { "id": "prov-2026-02-02", @@ -8,11 +8,11 @@ "example": "'Vreau să sun un client vechi' → Eforturi: 5 min pregătire, 10 min apel, posibil să zică nu, disconfort inițial. Îmi asum? Dacă da, sun acum. Dacă nu, aleg altceva mai mic.", "domain": "self", "dueDate": "2026-02-02", - "done": false, - "doneAt": null, + "done": true, + "doneAt": "2026-02-02T12:17:34.010Z", "source": "Zoltan Vereș - Motivația Intrinsecă", "sourceUrl": "https://moltbot.tailf7372d.ts.net/echo/files.html#memory/kb/youtube/2026-02-02_zoltan-veres-motivatie-intrinseca-complet.md", "createdAt": "2026-02-02T09:00:00Z" } ] -} +} \ No newline at end of file diff --git a/memory/kb/projects/FLUX-JOBURI.md b/memory/kb/projects/FLUX-JOBURI.md index 240c7a8..abb88d8 100644 --- a/memory/kb/projects/FLUX-JOBURI.md +++ b/memory/kb/projects/FLUX-JOBURI.md @@ -58,6 +58,41 @@ Execuție noaptea: --- +## 📊 Propuneri Acționabile în Rapoarte + +### Categorii (cine face) + +| Tag | Cine | Exemplu | +|-----|------|---------| +| 🤖 FAC EU | Echo singur | Git commit, creare fișier, update job | +| 🤝 TU+EU | Marius + Echo | Sesiune de lucru, review împreună | +| 👤 FACI TU | Doar Marius | Reflecție, decizie, acțiune externă | + +### Timing (când) + +| Tag | Când | Răspuns Marius | +|-----|------|----------------| +| ⚡ ACUM | Imediat după aprobare | "1 pentru X" | +| 🌙 NOAPTE | Job night-execute (23:00) | "2 pentru X" | +| 📅 PROGRAMAT | Data specifică | Echo setează reminder/job | +| ⏳ CÂND POȚI | Fără deadline | Pentru Marius, nu urgent | + +### Format propunere + +``` +**A0 - [Titlu scurt]** 🤖 FAC EU ⚡ ACUM +Descriere: ce face exact +Rezultat: ce obține Marius +``` + +### Coduri răspuns rapid +- `1 pentru A0,A3` → Execut ACUM +- `2 pentru A1,A4` → approved-tasks.md pentru noapte +- `3 pentru A2` → Skip (marchez [—] în insights) +- Text liber → Procesez și răspund + +--- + ## 📝 Cine Creează Ce ### 1. Note YouTube (`kb/youtube/`)