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:
10
TOOLS.md
10
TOOLS.md
@@ -31,11 +31,17 @@ python3 tools/email_send.py "dest@email.com" "Subiect" "Corp mesaj"
|
|||||||
- **API:** `kanban/api.py`
|
- **API:** `kanban/api.py`
|
||||||
- **Update task:** `python3 kanban/update_task.py`
|
- **Update task:** `python3 kanban/update_task.py`
|
||||||
|
|
||||||
### YouTube Notes
|
### Notes (toate tipurile)
|
||||||
- **Folder:** `notes/youtube/`
|
- **Folder:** `notes/` (subdirectoare: `youtube/`, `retete/`, etc.)
|
||||||
- **Update index:** `python3 tools/update_notes_index.py`
|
- **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`
|
- **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
|
### Git
|
||||||
- **Repo:** ~/clawd → gitea.romfast.ro/romfast/clawd
|
- **Repo:** ~/clawd → gitea.romfast.ro/romfast/clawd
|
||||||
- **Commit script:** `python3 tools/git_commit.py --push`
|
- **Commit script:** `python3 tools/git_commit.py --push`
|
||||||
|
|||||||
1481
kanban/index.html
1481
kanban/index.html
File diff suppressed because it is too large
Load Diff
29
kanban/issues.json
Normal file
29
kanban/issues.json
Normal 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
1
kanban/notes-data
Symbolic link
@@ -0,0 +1 @@
|
|||||||
|
../notes
|
||||||
@@ -482,14 +482,15 @@
|
|||||||
|
|
||||||
const notesCache = {};
|
const notesCache = {};
|
||||||
let notesIndex = [];
|
let notesIndex = [];
|
||||||
const notesBasePath = "youtube-notes/";
|
const notesBasePath = "notes-data/";
|
||||||
const indexPath = notesBasePath + "index.json";
|
const indexPath = notesBasePath + "index.json";
|
||||||
|
|
||||||
// Load notes index from JSON
|
// Load notes index from JSON
|
||||||
async function loadNotesIndex() {
|
async function loadNotesIndex() {
|
||||||
try {
|
try {
|
||||||
const response = await fetch(indexPath + '?t=' + Date.now());
|
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`);
|
console.log(`Loaded ${notesIndex.length} notes from index.json`);
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
console.error('Failed to load notes index:', e);
|
console.error('Failed to load notes index:', e);
|
||||||
|
|||||||
179
notes/index.json
Normal file
179
notes/index.json
Normal 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"
|
||||||
|
]
|
||||||
|
}
|
||||||
82
notes/retete/ciorba-burta-falsa-cu-pui.md
Normal file
82
notes/retete/ciorba-burta-falsa-cu-pui.md
Normal 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ă
|
||||||
@@ -2,6 +2,7 @@
|
|||||||
"""
|
"""
|
||||||
Generează index.json pentru notes din fișierele .md
|
Generează index.json pentru notes din fișierele .md
|
||||||
Extrage titlu, dată, tags, și domenii (@work, @health, etc.)
|
Extrage titlu, dată, tags, și domenii (@work, @health, etc.)
|
||||||
|
Scanează TOATE subdirectoarele din notes/ (youtube, retete, etc.)
|
||||||
"""
|
"""
|
||||||
|
|
||||||
import os
|
import os
|
||||||
@@ -9,8 +10,11 @@ import re
|
|||||||
import json
|
import json
|
||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
|
|
||||||
NOTES_DIR = Path(__file__).parent.parent / "notes" / "youtube"
|
NOTES_ROOT = Path(__file__).parent.parent / "notes"
|
||||||
INDEX_FILE = NOTES_DIR / "index.json"
|
INDEX_FILE = NOTES_ROOT / "index.json"
|
||||||
|
|
||||||
|
# Subdirectoare de scanat (adaugă altele aici)
|
||||||
|
SCAN_DIRS = ['youtube', 'retete']
|
||||||
|
|
||||||
# Domenii de agenți
|
# Domenii de agenți
|
||||||
VALID_DOMAINS = ['work', 'health', 'growth', 'sprijin', 'scout']
|
VALID_DOMAINS = ['work', 'health', 'growth', 'sprijin', 'scout']
|
||||||
@@ -66,27 +70,43 @@ def extract_metadata(filepath):
|
|||||||
}
|
}
|
||||||
|
|
||||||
def generate_index():
|
def generate_index():
|
||||||
"""Generează index.json din toate fișierele .md"""
|
"""Generează index.json din toate fișierele .md din toate subdirectoarele"""
|
||||||
notes = []
|
notes = []
|
||||||
|
|
||||||
# Stats per domeniu
|
# Stats per domeniu
|
||||||
domain_stats = {d: 0 for d in VALID_DOMAINS}
|
domain_stats = {d: 0 for d in VALID_DOMAINS}
|
||||||
|
# Stats per categorie
|
||||||
|
category_stats = {}
|
||||||
|
|
||||||
for filepath in sorted(NOTES_DIR.glob("*.md"), reverse=True):
|
for subdir in SCAN_DIRS:
|
||||||
if filepath.name == 'index.json':
|
notes_dir = NOTES_ROOT / subdir
|
||||||
|
if not notes_dir.exists():
|
||||||
|
print(f" (skipping {subdir}/ - not found)")
|
||||||
continue
|
continue
|
||||||
try:
|
|
||||||
metadata = extract_metadata(filepath)
|
|
||||||
notes.append(metadata)
|
|
||||||
|
|
||||||
# Update domain stats
|
print(f"Scanning notes/{subdir}/...")
|
||||||
for d in metadata['domains']:
|
category_stats[subdir] = 0
|
||||||
domain_stats[d] += 1
|
|
||||||
|
for filepath in sorted(notes_dir.glob("*.md"), reverse=True):
|
||||||
domains_str = ' '.join([f'@{d}' for d in metadata['domains']]) if metadata['domains'] else '(no domain)'
|
if filepath.name == 'index.json':
|
||||||
print(f" + {metadata['title'][:40]}... {domains_str}")
|
continue
|
||||||
except Exception as e:
|
try:
|
||||||
print(f" ! Error processing {filepath.name}: {e}")
|
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
|
# Sortează după dată descrescător
|
||||||
notes.sort(key=lambda x: x['date'], reverse=True)
|
notes.sort(key=lambda x: x['date'], reverse=True)
|
||||||
@@ -96,9 +116,11 @@ def generate_index():
|
|||||||
"notes": notes,
|
"notes": notes,
|
||||||
"stats": {
|
"stats": {
|
||||||
"total": len(notes),
|
"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:
|
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"\n✅ Generated {INDEX_FILE} with {len(notes)} notes")
|
||||||
print(f" Domains: {domain_stats}")
|
print(f" Domains: {domain_stats}")
|
||||||
|
print(f" Categories: {category_stats}")
|
||||||
return output
|
return output
|
||||||
|
|
||||||
if __name__ == "__main__":
|
if __name__ == "__main__":
|
||||||
print("Scanning notes/youtube/...")
|
|
||||||
generate_index()
|
generate_index()
|
||||||
|
|||||||
Reference in New Issue
Block a user