Update dashboard, memory, root (+40 ~22 -2)
This commit is contained in:
@@ -2048,12 +2048,6 @@ def process_youtube(url):
|
||||
sys.executable, str(TOOLS_DIR / 'update_notes_index.py')
|
||||
], capture_output=True)
|
||||
|
||||
# Add task to kanban
|
||||
subprocess.run([
|
||||
sys.executable, str(KANBAN_DIR / 'update_task.py'),
|
||||
'add', 'in-progress', f'Sumarizare: {title[:30]}...', url, 'medium'
|
||||
], capture_output=True)
|
||||
|
||||
print(f"Created note: {filename}")
|
||||
return filename
|
||||
|
||||
|
||||
@@ -52,6 +52,13 @@
|
||||
"description": "",
|
||||
"created": "2026-02-03T21:02:31Z",
|
||||
"priority": "medium"
|
||||
},
|
||||
{
|
||||
"id": "task-041",
|
||||
"title": "Raport dimineață trimis pe email",
|
||||
"description": "",
|
||||
"created": "2026-02-04T06:31:05Z",
|
||||
"priority": "medium"
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -1,5 +1,5 @@
|
||||
{
|
||||
"lastUpdated": "2026-02-11T16:14:09.539711",
|
||||
"lastUpdated": "2026-02-11T22:07:48.431522",
|
||||
"habits": [
|
||||
{
|
||||
"id": "95c15eef-3a14-4985-a61e-0b64b72851b0",
|
||||
@@ -15,14 +15,19 @@
|
||||
"count": 5
|
||||
},
|
||||
"streak": {
|
||||
"current": 0,
|
||||
"current": 1,
|
||||
"best": 1,
|
||||
"lastCheckIn": "2026-02-11"
|
||||
},
|
||||
"lives": 0,
|
||||
"completions": [],
|
||||
"completions": [
|
||||
{
|
||||
"date": "2026-02-11",
|
||||
"type": "check"
|
||||
}
|
||||
],
|
||||
"createdAt": "2026-02-11T00:54:03.447063",
|
||||
"updatedAt": "2026-02-11T16:14:06.084264"
|
||||
"updatedAt": "2026-02-11T22:07:24.169781"
|
||||
},
|
||||
{
|
||||
"id": "ceddaa7e-caf9-4038-94bb-da486c586bf8",
|
||||
@@ -50,7 +55,7 @@
|
||||
}
|
||||
],
|
||||
"createdAt": "2026-02-11T01:58:44.779904",
|
||||
"updatedAt": "2026-02-11T16:14:09.539711"
|
||||
"updatedAt": "2026-02-11T22:07:48.431522"
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -688,7 +688,7 @@
|
||||
}
|
||||
|
||||
.issue-checkbox.in-progress {
|
||||
background: rgba(59, 130, 246, 0.3);
|
||||
background: rgba(59, 130, 246, 0.5);
|
||||
border-color: #3b82f6;
|
||||
}
|
||||
|
||||
@@ -1071,6 +1071,10 @@
|
||||
<i data-lucide="file-text"></i>
|
||||
<span>KB</span>
|
||||
</a>
|
||||
<a href="/echo/habits.html" class="nav-item">
|
||||
<i data-lucide="dumbbell"></i>
|
||||
<span>Habits</span>
|
||||
</a>
|
||||
<a href="/echo/files.html" class="nav-item">
|
||||
<i data-lucide="folder"></i>
|
||||
<span>Files</span>
|
||||
@@ -1448,7 +1452,7 @@
|
||||
let issuesData = null;
|
||||
let activityData = [];
|
||||
let currentFilter = 'all';
|
||||
let collapsedPriorities = new Set(['backlog']);
|
||||
let collapsedPriorities = new Set(['backlog', 'done']);
|
||||
|
||||
// Priority labels
|
||||
const priorityLabels = {
|
||||
@@ -2171,39 +2175,40 @@
|
||||
filtered = filtered.filter(i => i.owner === currentFilter);
|
||||
}
|
||||
|
||||
// Group by priority
|
||||
// Separate done from active
|
||||
const activeIssues = filtered.filter(i => i.status !== 'done');
|
||||
const doneIssues = filtered.filter(i => i.status === 'done');
|
||||
|
||||
// Group active by priority
|
||||
const grouped = {};
|
||||
priorityOrder.forEach(p => grouped[p] = []);
|
||||
|
||||
filtered.forEach(issue => {
|
||||
activeIssues.forEach(issue => {
|
||||
const p = issue.priority || 'backlog';
|
||||
if (grouped[p]) grouped[p].push(issue);
|
||||
else grouped['backlog'].push(issue);
|
||||
});
|
||||
|
||||
// Sort each group: todo first, then by date
|
||||
// Sort each group by date (newest first)
|
||||
Object.keys(grouped).forEach(p => {
|
||||
grouped[p].sort((a, b) => {
|
||||
if (a.status === 'done' && b.status !== 'done') return 1;
|
||||
if (a.status !== 'done' && b.status === 'done') return -1;
|
||||
return new Date(b.created) - new Date(a.created);
|
||||
});
|
||||
grouped[p].sort((a, b) => new Date(b.created) - new Date(a.created));
|
||||
});
|
||||
|
||||
let html = '';
|
||||
|
||||
// Render active issues by priority
|
||||
priorityOrder.forEach(priority => {
|
||||
const issues = grouped[priority];
|
||||
if (issues.length === 0) return;
|
||||
|
||||
const isCollapsed = collapsedPriorities.has(priority);
|
||||
const todoCount = issues.filter(i => i.status !== 'done').length;
|
||||
|
||||
html += `
|
||||
<div class="priority-group">
|
||||
<div class="priority-header ${isCollapsed ? 'collapsed' : ''}" onclick="togglePriority('${priority}')">
|
||||
<i data-lucide="chevron-down"></i>
|
||||
<span>${priorityLabels[priority]}</span>
|
||||
<span style="margin-left: auto; opacity: 0.7">${todoCount}/${issues.length}</span>
|
||||
<span style="margin-left: auto; opacity: 0.7">${issues.length}</span>
|
||||
</div>
|
||||
<div class="priority-content ${isCollapsed ? 'hidden' : ''}">
|
||||
${issues.map(issue => renderIssueItem(issue)).join('')}
|
||||
@@ -2212,6 +2217,25 @@
|
||||
`;
|
||||
});
|
||||
|
||||
// Render done issues separately at the end
|
||||
if (doneIssues.length > 0) {
|
||||
const isDoneCollapsed = collapsedPriorities.has('done');
|
||||
doneIssues.sort((a, b) => new Date(b.completed || b.updated) - new Date(a.completed || a.updated));
|
||||
|
||||
html += `
|
||||
<div class="priority-group">
|
||||
<div class="priority-header ${isDoneCollapsed ? 'collapsed' : ''}" onclick="togglePriority('done')">
|
||||
<i data-lucide="chevron-down"></i>
|
||||
<span>✅ Executate</span>
|
||||
<span style="margin-left: auto; opacity: 0.7">${doneIssues.length}</span>
|
||||
</div>
|
||||
<div class="priority-content ${isDoneCollapsed ? 'hidden' : ''}">
|
||||
${doneIssues.map(issue => renderIssueItem(issue)).join('')}
|
||||
</div>
|
||||
</div>
|
||||
`;
|
||||
}
|
||||
|
||||
body.innerHTML = html;
|
||||
lucide.createIcons();
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
{
|
||||
"lastUpdated": "2026-02-05T21:53:55.397Z",
|
||||
"lastUpdated": "2026-02-12T10:05:31.985Z",
|
||||
"programs": [
|
||||
"ROACONT",
|
||||
"ROAGEST",
|
||||
@@ -39,6 +39,18 @@
|
||||
"deadline": "2026-02-06",
|
||||
"updated": "2026-02-02T22:26:59.690Z",
|
||||
"completed": "2026-02-05T21:53:55.392Z"
|
||||
},
|
||||
{
|
||||
"id": "ROA-003",
|
||||
"title": "Auto-copiere manoperă din devize stimative în devize reale",
|
||||
"description": "",
|
||||
"program": "ROAGEST",
|
||||
"owner": "marius",
|
||||
"priority": "backlog",
|
||||
"status": "todo",
|
||||
"created": "2026-02-12T10:03:13.378157+00:00",
|
||||
"deadline": null,
|
||||
"updated": "2026-02-12T10:05:31.980Z"
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -10,19 +10,10 @@
|
||||
"time": "30 Jan 2026, 22:00"
|
||||
},
|
||||
"anaf": {
|
||||
"ok": false,
|
||||
"status": "MODIFICĂRI",
|
||||
"message": "1 modificări detectate",
|
||||
"lastCheck": "11 Feb 2026, 16:23",
|
||||
"changesCount": 1,
|
||||
"changes": [
|
||||
{
|
||||
"name": "Declarația 300 - Decont TVA",
|
||||
"url": "https://static.anaf.ro/static/10/Anaf/Declaratii_R/300.html",
|
||||
"summary": [
|
||||
"Pagina s-a modificat (vezi diff)"
|
||||
]
|
||||
}
|
||||
]
|
||||
"ok": true,
|
||||
"status": "OK",
|
||||
"message": "Nicio modificare detectată",
|
||||
"lastCheck": "12 Feb 2026, 08:00",
|
||||
"changesCount": 0
|
||||
}
|
||||
}
|
||||
@@ -1,43 +0,0 @@
|
||||
{
|
||||
"lastUpdated": "2026-02-11T03:00:04.800665",
|
||||
"columns": [
|
||||
{
|
||||
"id": "backlog",
|
||||
"name": "Backlog",
|
||||
"tasks": [
|
||||
{
|
||||
"id": "task-006",
|
||||
"title": "Email digest dimineața",
|
||||
"description": "Sumar email-uri importante la 8 AM",
|
||||
"created": "2025-01-30",
|
||||
"priority": "medium"
|
||||
},
|
||||
{
|
||||
"id": "task-007",
|
||||
"title": "Calendar sync",
|
||||
"description": "Alertă înainte de întâlniri Google Calendar",
|
||||
"created": "2025-01-30",
|
||||
"priority": "low"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": "in-progress",
|
||||
"name": "In Progress",
|
||||
"tasks": []
|
||||
},
|
||||
{
|
||||
"id": "done",
|
||||
"name": "Done",
|
||||
"tasks": [
|
||||
{
|
||||
"id": "task-041",
|
||||
"title": "Raport dimineață trimis pe email",
|
||||
"description": "",
|
||||
"created": "2026-02-04T06:31:05Z",
|
||||
"priority": "medium"
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -1,6 +1,19 @@
|
||||
{
|
||||
"lastUpdated": "2026-02-11T16:39:39.457Z",
|
||||
"lastUpdated": "2026-02-12T07:00:00.000Z",
|
||||
"items": [
|
||||
{
|
||||
"id": "prov-2026-02-12",
|
||||
"text": "Provocare: Primul Pas Minim (PPM) - alege idee și execută în MAX 10 min",
|
||||
"context": "Regula PPM: Orice idee pe care o ai astăzi → identifică primul pas care: (1) Durează MAX 10 minute (2) NU necesită alte persoane (3) E CONCRET (nu 'mă gândesc', ci 'scriu', 'sun', 'trimit', 'creez'). La prima pauză (10:00-11:00): Alege UNA din ideile tale recente, identifică PPM-ul, execută-l chiar dacă nu e perfect. La 17:00 notează: Ce idee? Care PPM? L-am executat? Dacă DA: cum mă simt, următorul pas? Dacă NU: ce m-a oprit, ce PPM MAI MIC mâine?",
|
||||
"example": "Exemplu concret: Ideea 'ar trebui să am task brief template pentru angajat'. PPM greu: 'Creez template complet cu toate secțiunile, testez, ajustez...' PPM SIMPLU: 'Deschid fișier task-brief-template.md și scriu primele 3 secțiuni (Task, Input, Output) în 10 minute'. Sau ideea 'trebuie să documentez soluții probleme clienți'. PPM: 'Creez folder memory/kb/roa/probleme-frecvente/ și scriu PRIMA problemă rezolvată recent în 10 minute'. Cel mai greu pas e PRIMUL - după ce ai început, creierul intră în flow mode.",
|
||||
"domain": "self",
|
||||
"dueDate": "2026-02-12",
|
||||
"done": false,
|
||||
"doneAt": null,
|
||||
"source": "Multi-Agent Pattern + Living Files Theory + Context Engineering",
|
||||
"sourceUrl": "https://moltbot.tailf7372d.ts.net/echo/files.html#memory/kb/coaching/2026-02-12-dimineata.md",
|
||||
"createdAt": "2026-02-12T07:00:00.000Z"
|
||||
},
|
||||
{
|
||||
"id": "prov-2026-02-11",
|
||||
"text": "Provocare: Identifică un task pe care îl execuți singur și ar putea fi orchestrat",
|
||||
|
||||
@@ -1,120 +0,0 @@
|
||||
#!/usr/bin/env python3
|
||||
"""
|
||||
Helper script for Echo to update kanban tasks.
|
||||
Usage: python3 update_task.py <action> <args>
|
||||
|
||||
Actions:
|
||||
add <column> <title> [description] [priority]
|
||||
move <task_id> <to_column>
|
||||
done <task_id>
|
||||
list
|
||||
"""
|
||||
|
||||
import json
|
||||
import sys
|
||||
from datetime import datetime
|
||||
from pathlib import Path
|
||||
|
||||
TASKS_FILE = Path(__file__).parent / 'tasks.json'
|
||||
|
||||
def load_tasks():
|
||||
with open(TASKS_FILE, 'r') as f:
|
||||
return json.load(f)
|
||||
|
||||
def save_tasks(data):
|
||||
data['lastUpdated'] = datetime.utcnow().isoformat() + 'Z'
|
||||
with open(TASKS_FILE, 'w') as f:
|
||||
json.dump(data, f, indent=2, ensure_ascii=False)
|
||||
|
||||
def get_next_id(data):
|
||||
max_id = 0
|
||||
for col in data['columns']:
|
||||
for task in col['tasks']:
|
||||
num = int(task['id'].split('-')[1])
|
||||
if num > max_id:
|
||||
max_id = num
|
||||
return f"task-{max_id + 1:03d}"
|
||||
|
||||
def add_task(column_id, title, description="", priority="medium"):
|
||||
data = load_tasks()
|
||||
new_task = {
|
||||
"id": get_next_id(data),
|
||||
"title": title,
|
||||
"description": description,
|
||||
"created": datetime.utcnow().strftime("%Y-%m-%dT%H:%M:%SZ"),
|
||||
"priority": priority
|
||||
}
|
||||
|
||||
for col in data['columns']:
|
||||
if col['id'] == column_id:
|
||||
col['tasks'].append(new_task)
|
||||
save_tasks(data)
|
||||
print(f"Added: {new_task['id']} - {title}")
|
||||
return
|
||||
|
||||
print(f"Column not found: {column_id}")
|
||||
|
||||
def move_task(task_id, to_column):
|
||||
data = load_tasks()
|
||||
task = None
|
||||
|
||||
# Find and remove task
|
||||
for col in data['columns']:
|
||||
for t in col['tasks']:
|
||||
if t['id'] == task_id:
|
||||
task = t
|
||||
col['tasks'].remove(t)
|
||||
break
|
||||
if task:
|
||||
break
|
||||
|
||||
if not task:
|
||||
print(f"Task not found: {task_id}")
|
||||
return
|
||||
|
||||
# Add to new column
|
||||
if to_column == 'done':
|
||||
task['completed'] = datetime.utcnow().strftime("%Y-%m-%dT%H:%M:%SZ")
|
||||
|
||||
for col in data['columns']:
|
||||
if col['id'] == to_column:
|
||||
col['tasks'].append(task)
|
||||
save_tasks(data)
|
||||
print(f"Moved: {task_id} -> {to_column}")
|
||||
return
|
||||
|
||||
print(f"Column not found: {to_column}")
|
||||
|
||||
def done_task(task_id):
|
||||
move_task(task_id, 'done')
|
||||
|
||||
def list_tasks():
|
||||
data = load_tasks()
|
||||
for col in data['columns']:
|
||||
print(f"\n{col['name']} ({len(col['tasks'])})")
|
||||
print("-" * 40)
|
||||
for task in col['tasks']:
|
||||
print(f" [{task['id']}] {task['title']}")
|
||||
|
||||
if __name__ == '__main__':
|
||||
if len(sys.argv) < 2:
|
||||
print(__doc__)
|
||||
sys.exit(1)
|
||||
|
||||
action = sys.argv[1]
|
||||
|
||||
if action == 'add' and len(sys.argv) >= 4:
|
||||
add_task(
|
||||
sys.argv[2], # column
|
||||
sys.argv[3], # title
|
||||
sys.argv[4] if len(sys.argv) > 4 else "",
|
||||
sys.argv[5] if len(sys.argv) > 5 else "medium"
|
||||
)
|
||||
elif action == 'move' and len(sys.argv) >= 4:
|
||||
move_task(sys.argv[2], sys.argv[3])
|
||||
elif action == 'done' and len(sys.argv) >= 3:
|
||||
done_task(sys.argv[2])
|
||||
elif action == 'list':
|
||||
list_tasks()
|
||||
else:
|
||||
print(__doc__)
|
||||
Reference in New Issue
Block a user