Dashboard v2: Activity + Issues panels

- Replace Kanban with new Dashboard layout
- Status bar (ANAF, Git, Cron) - collapsible
- Activity panel - Clawdbot activity log
- Issues panel - Eisenhower priority, owner filter, programs
- All sections collapsible with localStorage persistence
- issues.json for ROA work tracking
- First issue: D101 RD49→RD50 fix
- Fix notes.html index.json format handling
This commit is contained in:
Echo
2026-01-30 19:48:01 +00:00
parent 42ce6c2698
commit fdabea7271
8 changed files with 1227 additions and 620 deletions

View File

@@ -31,11 +31,17 @@ python3 tools/email_send.py "dest@email.com" "Subiect" "Corp mesaj"
- **API:** `kanban/api.py`
- **Update task:** `python3 kanban/update_task.py`
### YouTube Notes
- **Folder:** `notes/youtube/`
### Notes (toate tipurile)
- **Folder:** `notes/` (subdirectoare: `youtube/`, `retete/`, etc.)
- **Update index:** `python3 tools/update_notes_index.py`
- **Pagina web:** https://moltbot.tailf7372d.ts.net/echo/notes.html
- **Tags domeniu:** `@work`, `@health`, `@growth`, `@sprijin`, `@scout`
**IMPORTANT:** Când salvez orice notă (rețete, youtube, etc.), trebuie să:
1. Salvez în subdirectorul potrivit din `notes/`
2. Rulez `python3 tools/update_notes_index.py` pentru a actualiza indexul
3. Dau link-ul către pagina notes.html
### Git
- **Repo:** ~/clawd → gitea.romfast.ro/romfast/clawd
- **Commit script:** `python3 tools/git_commit.py --push`

File diff suppressed because it is too large Load Diff

29
kanban/issues.json Normal file
View File

@@ -0,0 +1,29 @@
{
"lastUpdated": "2026-01-30T17:37:00.676Z",
"programs": [
"ROACONT",
"ROAGEST",
"ROAIMOB",
"ROAFACTURARE",
"ROADEF",
"ROASTART",
"ROAPRINT",
"ROAWEB",
"Clawdbot",
"Personal",
"Altele"
],
"issues": [
{
"id": "ROA-001",
"title": "D101: Mutare impozit precedent RD49→RD50",
"description": "RD 49 = în urma inspecției fiscale\nRD 50 = impozit precedent\nFormularul nu recalculează impozitul de 16%\nRD 40 se modifică și la 4.1",
"program": "ROACONT",
"owner": "marius",
"priority": "urgent-important",
"status": "todo",
"created": "2026-01-30T15:10:00Z",
"deadline": null
}
]
}

1
kanban/notes-data Symbolic link
View File

@@ -0,0 +1 @@
../notes

View File

@@ -482,14 +482,15 @@
const notesCache = {};
let notesIndex = [];
const notesBasePath = "youtube-notes/";
const notesBasePath = "notes-data/";
const indexPath = notesBasePath + "index.json";
// Load notes index from JSON
async function loadNotesIndex() {
try {
const response = await fetch(indexPath + '?t=' + Date.now());
notesIndex = await response.json();
const data = await response.json();
notesIndex = Array.isArray(data) ? data : (data.notes || []);
console.log(`Loaded ${notesIndex.length} notes from index.json`);
} catch (e) {
console.error('Failed to load notes index:', e);

179
notes/index.json Normal file
View File

@@ -0,0 +1,179 @@
{
"notes": [
{
"file": "youtube/2026-01-30_clawdbot-personal-os-kitze.md",
"title": "How I Use Clawdbot to Run My Business and Life 24/7",
"date": "2026-01-30",
"tags": [
"clawdbot",
"productivity",
"personas",
"automation"
],
"domains": [
"work",
"growth"
],
"video": "https://youtu.be/YRhGtHfs1Lw",
"tldr": "Kitze folosește **UN SINGUR gateway Clawdbot** cu **MULTIPLE PERSONAS** pe Telegram/Discord. Fiecare personă are:\n- Personalitate diferită (avatar, stil de vorbit)\n- Skills diferite (acces la tool-uri...",
"category": "youtube"
},
{
"file": "youtube/2026-01-29_remotion-skill-claude-code.md",
"title": "How people are generating videos with Claude Code (Remotion Skill)",
"date": "2026-01-29",
"tags": [
"remotion",
"claude-code",
"video",
"automation"
],
"domains": [
"work"
],
"video": "https://youtu.be/7OR-L0AySn8",
"tldr": "Remotion Skill permite generarea de videouri programatic cu Claude Code. Funcționează prin React components → video export. Demo live: Claude creează animații YouTube (like, subscribe, cursor) doar di...",
"category": "youtube"
},
{
"file": "youtube/2026-01-29_gsd-framework-claude-code.md",
"title": "Forget Ralph Loops: The New GSD Framework for Claude Code",
"date": "2026-01-29",
"tags": [
"claude-code",
"gsd",
"framework",
"sub-agents",
"automation"
],
"domains": [
"work"
],
"video": "https://www.youtube.com/watch?v=l94A53kIUB0",
"tldr": "GSD (Get Shit Done) este un framework open-source pentru Claude Code care orchestrează sub-agenți pentru a completa proiecte urmând spec-driven development. Rezolvă problema \"context bloat\" prin rular...",
"category": "youtube"
},
{
"file": "youtube/2026-01-29_greseli-post-apa.md",
"title": "Greșeli frecvente în timpul postului doar cu apă",
"date": "2026-01-29",
"tags": [
"post",
"water-fasting",
"sănătate",
"detox"
],
"domains": [
"health"
],
"video": "https://youtu.be/4QjkI0sf64M",
"tldr": "Greșelile frecvente pe care le fac oamenii când țin post terapeutic cu apă și cum să le eviți. Puncte cheie: pregătire corectă, curățarea colonului, calitatea apei, și importanța scopului spiritual.",
"category": "youtube"
},
{
"file": "youtube/2026-01-29_cloudflare-tunnel-localhost-public.md",
"title": "Cloudflare Tunnel: Make Localhost Public Without Port Forwarding",
"date": "2026-01-29",
"tags": [
"cloudflare",
"tunnel",
"localhost",
"networking",
"devops"
],
"domains": [
"work"
],
"video": "https://youtu.be/etluT8UC-nw",
"tldr": "Cloudflare Tunnel permite expunerea unui server local (localhost) pe internet printr-un domeniu public, fără port forwarding, fără configurare router, fără expunerea IP-ului public. App-ul rămâne pe m...",
"category": "youtube"
},
{
"file": "youtube/2026-01-29_clawdbot-security-vulnerabilities.md",
"title": "It Got Worse (Clawdbot) - Security Vulnerabilities",
"date": "2026-01-29",
"tags": [
"clawdbot",
"security",
"vulnerabilities",
"hacking"
],
"domains": [
"work"
],
"video": "https://youtu.be/rPAKq2oQVBs",
"tldr": "Video critic despre vulnerabilitățile de securitate ale Clawdbot - sute/mii de instanțe au fost compromise. Probleme principale: porturi default, parole lipsă, reverse proxy misconfigurat, skills mali...",
"category": "youtube"
},
{
"file": "youtube/2025-01-30_clawdbot-5-use-cases.md",
"title": "5 Insane ClawdBot Use Cases You Need To Do Immediately",
"date": "2025-01-30",
"tags": [
"clawdbot",
"automation",
"productivity",
"ai-assistant"
],
"domains": [
"work"
],
"video": "https://www.youtube.com/watch?v=b-l9sGh1-UY",
"tldr": "5 use case-uri pentru ClawdBot care îl transformă dintr-un simplu chatbot într-un asistent proactiv care lucrează pentru tine chiar și când dormi.",
"category": "youtube"
},
{
"file": "youtube/2025-01-30_claude-code-do-work-pattern.md",
"title": "The Most Powerful Claude Code Pattern I've Found",
"date": "2025-01-30",
"tags": [
"claude-code",
"skills",
"workflow",
"automation",
"do-work"
],
"domains": [
"work"
],
"video": "https://youtu.be/I9-tdhxiH7w",
"tldr": "Un pattern puternic pentru Claude Code: **Do Work** - o coadă de task-uri pe care Claude le procesează automat, unul câte unul, în sub-agenți cu context curat. Ideea cheie: **construiește tool-uri pen...",
"category": "youtube"
},
{
"file": "retete/ciorba-burta-falsa-cu-pui.md",
"title": "Ciorbă de Burtă Falsă cu Pui și Ciuperci Pleurotus",
"date": "",
"tags": [],
"domains": [],
"video": "",
"tldr": "",
"category": "retete"
}
],
"stats": {
"total": 9,
"by_domain": {
"work": 7,
"health": 1,
"growth": 1,
"sprijin": 0,
"scout": 0
},
"by_category": {
"youtube": 8,
"retete": 1
}
},
"domains": [
"work",
"health",
"growth",
"sprijin",
"scout"
],
"categories": [
"youtube",
"retete"
]
}

View File

@@ -0,0 +1,82 @@
# Ciorbă de Burtă Falsă cu Pui și Ciuperci Pleurotus
**Salvat:** 2026-01-30
**Sursa:** Laura Laurențiu (adaptat)
**Timp preparare:** ~50 minute
**Porții:** 6-8
---
## Ingrediente
### Carne
- 300-400g piept de pui (sau pulpe dezosate)
### Legume & Ciuperci
- 500g ciuperci pleurotus
- 1 morcov mare
- 1 ceapă medie
- 1 bucată țelină (cât un ou mic)
- 1 ardei roșu mic
- 2-3 căței usturoi
### Pentru dres
- 200g smântână grasă (25%)
- 2 gălbenușuri de ou
### Condimente
- 2 foi dafin
- 30ml ulei
- 2-3 linguri oțet
- Sare
- Piper
- Ardei iute (opțional, la servire)
---
## Mod de preparare
### 1. Fierbe carnea
- Pune puiul în ~2.5 litri apă rece cu puțină sare
- Fierbe 30-40 minute, spumează când e nevoie
- Scoate carnea, taie-o bucăți și păstreaz-o
### 2. Pregătește legumele
- Curăță ciupercile pleurotus, îndepărtează tulpinile groase
- Taie ciupercile în fâșii lungi de ~1cm (să arate ca burta)
- Toaca ceapa mărunt
- Rade morcovul pe răzătoare mare
- Taie țelina și ardeiul cubulețe
### 3. Călește și fierbe
- Încinge uleiul într-o oală mare
- Călește ceapa și morcovul 7-8 minute la foc mic
- Adaugă zeama de pui fiartă
- Adaugă țelina, ardeiul, ciupercile și dafinul
- Fierbe 25 minute la foc mediu
### 4. Mujdeiul
- Pisează usturoiul cu 1 linguriță sare în mojar
- Adaugă 3 linguri apă rece și oțetul
- Amestecă bine
### 5. Dresul (la final!)
- Bate smântâna cu cele 2 gălbenușuri
- Temperează: adaugă câteva linguri de zeamă fierbinte în smântână, amestecând
- Toarnă amestecul în oală, la foc oprit
- Adaugă mujdeiul și carnea de pui
- Potrivește de sare, oțet și piper
---
## Servire
- Se servește fierbinte
- Cu ardei iute și smântână extra la masă
- Pâine proaspătă alături
---
## Note
- Ciupercile pleurotus tăiate fâșii dau textura de "burtă"
- Nu fierbe după ce ai adăugat smântâna (se taie)
- Se poate face și de post: fără carne, cu lapte vegetal în loc de smântână

View File

@@ -2,6 +2,7 @@
"""
Generează index.json pentru notes din fișierele .md
Extrage titlu, dată, tags, și domenii (@work, @health, etc.)
Scanează TOATE subdirectoarele din notes/ (youtube, retete, etc.)
"""
import os
@@ -9,8 +10,11 @@ import re
import json
from pathlib import Path
NOTES_DIR = Path(__file__).parent.parent / "notes" / "youtube"
INDEX_FILE = NOTES_DIR / "index.json"
NOTES_ROOT = Path(__file__).parent.parent / "notes"
INDEX_FILE = NOTES_ROOT / "index.json"
# Subdirectoare de scanat (adaugă altele aici)
SCAN_DIRS = ['youtube', 'retete']
# Domenii de agenți
VALID_DOMAINS = ['work', 'health', 'growth', 'sprijin', 'scout']
@@ -66,27 +70,43 @@ def extract_metadata(filepath):
}
def generate_index():
"""Generează index.json din toate fișierele .md"""
"""Generează index.json din toate fișierele .md din toate subdirectoarele"""
notes = []
# Stats per domeniu
domain_stats = {d: 0 for d in VALID_DOMAINS}
# Stats per categorie
category_stats = {}
for filepath in sorted(NOTES_DIR.glob("*.md"), reverse=True):
if filepath.name == 'index.json':
for subdir in SCAN_DIRS:
notes_dir = NOTES_ROOT / subdir
if not notes_dir.exists():
print(f" (skipping {subdir}/ - not found)")
continue
try:
metadata = extract_metadata(filepath)
notes.append(metadata)
# Update domain stats
for d in metadata['domains']:
domain_stats[d] += 1
domains_str = ' '.join([f'@{d}' for d in metadata['domains']]) if metadata['domains'] else '(no domain)'
print(f" + {metadata['title'][:40]}... {domains_str}")
except Exception as e:
print(f" ! Error processing {filepath.name}: {e}")
print(f"Scanning notes/{subdir}/...")
category_stats[subdir] = 0
for filepath in sorted(notes_dir.glob("*.md"), reverse=True):
if filepath.name == 'index.json':
continue
try:
metadata = extract_metadata(filepath)
# Adaugă categoria (subdirectorul)
metadata['category'] = subdir
# Modifică path-ul fișierului să includă subdirectorul
metadata['file'] = f"{subdir}/{filepath.name}"
notes.append(metadata)
# Update stats
category_stats[subdir] += 1
for d in metadata['domains']:
domain_stats[d] += 1
domains_str = ' '.join([f'@{d}' for d in metadata['domains']]) if metadata['domains'] else ''
print(f" + {metadata['title'][:40]}... {domains_str}")
except Exception as e:
print(f" ! Error processing {filepath.name}: {e}")
# Sortează după dată descrescător
notes.sort(key=lambda x: x['date'], reverse=True)
@@ -96,9 +116,11 @@ def generate_index():
"notes": notes,
"stats": {
"total": len(notes),
"by_domain": domain_stats
"by_domain": domain_stats,
"by_category": category_stats
},
"domains": VALID_DOMAINS
"domains": VALID_DOMAINS,
"categories": SCAN_DIRS
}
with open(INDEX_FILE, 'w', encoding='utf-8') as f:
@@ -106,8 +128,8 @@ def generate_index():
print(f"\n✅ Generated {INDEX_FILE} with {len(notes)} notes")
print(f" Domains: {domain_stats}")
print(f" Categories: {category_stats}")
return output
if __name__ == "__main__":
print("Scanning notes/youtube/...")
generate_index()