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`
|
||||
- **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`
|
||||
|
||||
1391
kanban/index.html
1391
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 = {};
|
||||
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
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
|
||||
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
|
||||
print(f"Scanning notes/{subdir}/...")
|
||||
category_stats[subdir] = 0
|
||||
|
||||
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}")
|
||||
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()
|
||||
|
||||
Reference in New Issue
Block a user