diff --git a/TOOLS.md b/TOOLS.md index 848e81e..f42d0d3 100644 --- a/TOOLS.md +++ b/TOOLS.md @@ -51,6 +51,69 @@ python3 tools/email_send.py "dest@email.com" "Subiect" "Corp mesaj" - **Repo:** ~/clawd → gitea.romfast.ro/romfast/clawd - **Commit script:** `python3 tools/git_commit.py --push` +### Docker LXC (portainer) +- **Host:** 10.0.20.170 (LXC 100 pe pvemini) +- **User:** echo +- **SSH:** `ssh echo@10.0.20.170` +- **Portainer:** https://10.0.20.170:9443 +- **Docker:** v28.3.3 + Compose v2.39.1 +- **Resurse:** 1GB RAM, 20GB disk (4.1GB folosit) +- **Proiecte:** `/opt/docker/` + +**Containere:** +| Container | Port | Status | Descriere | +|-----------|------|--------|-----------| +| portainer | 9443 | ✅ | Management Docker | +| nginx | 443, 8080 | ✅ | Reverse proxy | +| roa-efactura | 5003 | ⚠️ unhealthy | E-Factura ANAF | +| pdf-qr-app | 5002 | ✅ | QR facturi | +| flask_app | 5001 | ✅ | ROA Flask | +| bt-web-automation | 5000, 8081 | ✅ | BT automation | +| pulse | 7655 | ✅ | Monitoring Proxmox | +| wol-manager | - | ✅ | Wake-on-LAN | +| rustdesk (hbbs+hbbr) | 21115-21119 | ✅ | Remote desktop server | + +**Proiecte docker-compose:** +- `/opt/docker/docker-compose.yaml` - stack principal (nginx, flask, efactura, qr) +- `/opt/docker/wol/docker-compose.yml` - Wake-on-LAN +- `/opt/docker/qrinvoice/docker-compose.yml` - QR Invoice app + +### Proxmox Cluster (3 noduri) +**User:** echo | **Restricție:** doar din 10.0.20.173 (moltbot) | **Sudo:** qm, pct, pvesh + +#### pveelite (10.0.20.202) +- **Resurse:** 16GB RAM, 557GB disk +- **SSH:** `ssh echo@10.0.20.202` + +| VMID | Tip | Nume | Status | +|------|-----|------|--------| +| 109 | VM | oracle-dr-windows | stopped | +| 101 | LXC | minecraft | stopped | +| 110 | LXC | moltbot | running | +| 301 | LXC | docker-portainer-template | stopped | + +#### pvemini (10.0.20.201) +- **Resurse:** 64GB RAM, 1.4TB disk +- **SSH:** `ssh echo@10.0.20.201` + +| VMID | Tip | Nume | Status | +|------|-----|------|--------| +| 201 | VM | roacentral | running | +| 300 | VM | Win11-Template | stopped | +| 302 | VM | oracle-test-302 | stopped | +| 100 | LXC | portainer | running | +| 103 | LXC | dokploy | running | +| 104 | LXC | flowise | running | +| 105 | LXC | test | stopped | +| 106 | LXC | gitea | running | +| 108 | LXC | central-oracle | running | +| 171 | LXC | claude-agent | running | + +#### pve1 (10.0.20.200) +- **Resurse:** 32GB RAM, 1.3TB disk +- **SSH:** `ssh echo@10.0.20.200` +- **Status:** Gol (fără VM/LXC) + --- ## ⚡ Echo Work - Unelte specifice diff --git a/agents/echo-health/memory/provocare-azi.md b/agents/echo-health/memory/provocare-azi.md index 9177a80..094ff50 100644 --- a/agents/echo-health/memory/provocare-azi.md +++ b/agents/echo-health/memory/provocare-azi.md @@ -1,2 +1,2 @@ -TIP: Mișcare fizică / Pattern Interrupt -PROVOCARE: Ridică-te, fă 5 respirații adânci (inspiră 4 sec, expiră 6 sec), întinde-te (ridică brațele, deschide pieptul), mergi 2 minute oriunde. E resetare de stare prin corp - corpul nu știe să mintă. +TIP: Recunoștință / Priming seară +PROVOCARE: 3 minute înainte de somn - găsește 3 momente bune din zi și SIMTE-le (nu doar gândește). Unde în corp? Ce senzație? Antrenament de sistem nervos. diff --git a/agents/echo-work/memory/approved-tasks.md b/agents/echo-work/memory/approved-tasks.md new file mode 100644 index 0000000..39d3297 --- /dev/null +++ b/agents/echo-work/memory/approved-tasks.md @@ -0,0 +1,8 @@ +# Task-uri aprobate pentru execuție + +Acest fișier e populat de raportul de seară când Marius aprobă task-uri. +Job-ul night-execute (23:00) le execută și golește fișierul. + +--- + + diff --git a/agents/echo-work/memory/reguli-comunicare.md b/agents/echo-work/memory/reguli-comunicare.md index 96cf9e8..3b179b9 100644 --- a/agents/echo-work/memory/reguli-comunicare.md +++ b/agents/echo-work/memory/reguli-comunicare.md @@ -9,5 +9,20 @@ Când primesc mesaj de la alt agent (via sessions_send): Marius nu vede mesajele interne - trebuie să comunic transparent ce se întâmplă. +--- + +## Execuție task-uri + +**Din raportul de seară (job evening-report):** +- Aprobări ("ok X") → notez în `approved-tasks.md` +- Confirm: "✅ Notat pentru 23:00: [task-uri]" +- Job-ul `night-execute` (23:00) execută + +**Din conversație directă separată:** +- Dacă Marius cere explicit → execut imediat +- Dacă e continuare din raport → respectă fluxul 23:00 + +**NU amesteca contextele!** + --- *Adăugat: 2026-01-31* diff --git a/dashboard/api.py b/dashboard/api.py index 33891ad..b8805a5 100644 --- a/dashboard/api.py +++ b/dashboard/api.py @@ -108,6 +108,8 @@ class TaskBoardHandler(SimpleHTTPRequestHandler): self.handle_activity() elif self.path.startswith('/api/files'): self.handle_files_get() + elif self.path.startswith('/api/diff'): + self.handle_git_diff() elif self.path.startswith('/api/'): self.send_error(404) else: @@ -155,6 +157,14 @@ class TaskBoardHandler(SimpleHTTPRequestHandler): cwd=workspace, capture_output=True, text=True, timeout=5 ).stdout.strip() + # Parse uncommitted into structured format + uncommitted_parsed = [] + for line in uncommitted: + if len(line) >= 3: + status = line[:2].strip() + filepath = line[3:].strip() + uncommitted_parsed.append({'status': status, 'path': filepath}) + self.send_json({ 'branch': branch, 'lastCommit': { @@ -163,6 +173,7 @@ class TaskBoardHandler(SimpleHTTPRequestHandler): 'time': commit_parts[2] if len(commit_parts) > 2 else '' }, 'uncommitted': uncommitted, + 'uncommittedParsed': uncommitted_parsed, 'uncommittedCount': len(uncommitted), 'diffStat': diff_stat, 'clean': len(uncommitted) == 0 @@ -170,6 +181,60 @@ class TaskBoardHandler(SimpleHTTPRequestHandler): except Exception as e: self.send_json({'error': str(e)}, 500) + def handle_git_diff(self): + """Get git diff for a specific file.""" + from urllib.parse import urlparse, parse_qs + parsed = urlparse(self.path) + params = parse_qs(parsed.query) + + filepath = params.get('path', [''])[0] + + if not filepath: + self.send_json({'error': 'path required'}, 400) + return + + try: + workspace = Path('/home/moltbot/clawd') + + # Security check + target = (workspace / filepath).resolve() + if not str(target).startswith(str(workspace)): + self.send_json({'error': 'Access denied'}, 403) + return + + # Get diff (try staged first, then unstaged) + diff = subprocess.run( + ['git', 'diff', '--cached', '--', filepath], + cwd=workspace, capture_output=True, text=True, timeout=10 + ).stdout + + if not diff: + diff = subprocess.run( + ['git', 'diff', '--', filepath], + cwd=workspace, capture_output=True, text=True, timeout=10 + ).stdout + + # If still no diff, file might be untracked - show full content + if not diff: + status = subprocess.run( + ['git', 'status', '--short', '--', filepath], + cwd=workspace, capture_output=True, text=True, timeout=5 + ).stdout.strip() + + if status.startswith('??'): + # Untracked file - show as new + if target.exists(): + content = target.read_text(encoding='utf-8', errors='replace')[:50000] + diff = f"+++ b/{filepath}\n" + '\n'.join(f'+{line}' for line in content.split('\n')) + + self.send_json({ + 'path': filepath, + 'diff': diff or 'No changes', + 'hasDiff': bool(diff) + }) + except Exception as e: + self.send_json({'error': str(e)}, 500) + def handle_agents_status(self): """Get agents status - fast version reading session files directly.""" try: @@ -361,11 +426,44 @@ class TaskBoardHandler(SimpleHTTPRequestHandler): 'text': message[:60] + ('...' if len(message) > 60 else ''), 'agent': 'git', 'time': local_time.strftime('%H:%M'), - 'timestamp': timestamp * 1000 + 'timestamp': timestamp * 1000, + 'commitHash': commit_hash[:8] }) except: pass + # 2b. Git uncommitted files + try: + result = subprocess.run( + ['git', 'status', '--short'], + cwd=workspace, capture_output=True, text=True, timeout=10 + ) + if result.returncode == 0 and result.stdout.strip(): + for line in result.stdout.strip().split('\n'): + if len(line) >= 4: + # Git status format: XY filename (XY = 2 chars status) + # Handle both "M " and " M" formats + status = line[:2] + # Find filepath - skip status chars and any spaces + filepath = line[2:].lstrip() + if not filepath: + continue + status_clean = status.strip() + status_labels = {'M': 'modificat', 'A': 'adăugat', 'D': 'șters', '??': 'nou', 'R': 'redenumit'} + status_label = status_labels.get(status_clean, status_clean) + activities.append({ + 'type': 'git-file', + 'icon': 'file-diff', + 'text': f"{filepath}", + 'agent': f"git ({status_label})", + 'time': 'acum', + 'timestamp': int(datetime.now().timestamp() * 1000), + 'path': filepath, + 'gitStatus': status_clean + }) + except: + pass + # 3. Recent files in kb/ (last 24h) try: kb_dir = workspace / 'kb' diff --git a/dashboard/favicon.svg b/dashboard/favicon.svg new file mode 100644 index 0000000..9fac3a0 --- /dev/null +++ b/dashboard/favicon.svg @@ -0,0 +1,4 @@ + + + + diff --git a/dashboard/files.html b/dashboard/files.html index cb51d86..33c4509 100644 --- a/dashboard/files.html +++ b/dashboard/files.html @@ -3,6 +3,7 @@ + Echo · Files @@ -294,6 +295,41 @@ background: var(--accent-subtle); } + .file-item.git-changed { + border-left: 3px solid var(--warning); + } + + .git-badge { + display: inline-block; + font-size: 10px; + font-weight: 700; + padding: 1px 4px; + border-radius: 3px; + margin-right: 4px; + font-family: var(--font-mono); + } + + .git-modified { background: #3b82f620; color: #3b82f6; } + .git-added { background: #22c55e20; color: #22c55e; } + .git-deleted { background: #ef444420; color: #ef4444; } + .git-untracked { background: #f59e0b20; color: #f59e0b; } + .git-renamed { background: #8b5cf620; color: #8b5cf6; } + + .diff-btn { + background: var(--accent); + color: white; + border: none; + padding: 2px 8px; + border-radius: 4px; + font-size: 11px; + cursor: pointer; + font-family: var(--font-mono); + } + + .diff-btn:hover { + opacity: 0.8; + } + .file-icon { width: 40px; height: 40px; @@ -419,6 +455,9 @@ .preview-active #markdownPreview { display: block; } .btn-preview.active { background: var(--accent); color: white; } + .btn-diff.active { background: var(--warning); color: white; } + + #gitFilterBtn.active { background: var(--warning); color: white; } .editor-footer { padding: var(--space-2) var(--space-5); @@ -493,6 +532,13 @@ ~/clawd
+ +
+ +
+
+ @@ -611,6 +660,8 @@ let currentSortBy = localStorage.getItem('filesSortBy') || 'name'; let currentSortDir = localStorage.getItem('filesSortDir') || 'asc'; let currentItems = []; + let gitStatus = {}; // Map of filepath -> status (M, A, D, ??) + let gitOnlyMode = false; // Show only git-changed files // Initialize view mode function initViewMode() { @@ -690,6 +741,63 @@ document.getElementById('editorBtn').classList.add('active'); } + async function loadGitStatus() { + try { + const response = await fetch(`${API_BASE}/api/git?` + Date.now()); + const data = await response.json(); + gitStatus = {}; + if (data.uncommittedParsed) { + data.uncommittedParsed.forEach(item => { + gitStatus[item.path] = item.status; + }); + } + } catch (e) { + console.error('Failed to load git status:', e); + } + } + + async function showDiff(filepath, event) { + if (event) event.stopPropagation(); + try { + const response = await fetch(`${API_BASE}/api/diff?path=${encodeURIComponent(filepath)}`); + const data = await response.json(); + + // Show in a modal or the editor + const diffHtml = data.diff + .split('\n') + .map(line => { + if (line.startsWith('+') && !line.startsWith('+++')) { + return `${escapeHtml(line)}`; + } else if (line.startsWith('-') && !line.startsWith('---')) { + return `${escapeHtml(line)}`; + } else if (line.startsWith('@@')) { + return `${escapeHtml(line)}`; + } + return escapeHtml(line); + }) + .join('\n'); + + // Open file in editor with diff view + document.getElementById('editorFileName').textContent = `DIFF: ${filepath}`; + document.getElementById('codeEditor').value = data.diff; + document.getElementById('markdownPreview').innerHTML = `
${diffHtml}
`; + document.getElementById('editorBody').classList.add('preview-active'); + document.getElementById('previewBtn').style.display = 'flex'; + document.getElementById('previewBtn').classList.add('active'); + document.getElementById('saveBtn').disabled = true; + document.getElementById('reloadBtn').disabled = true; + currentFile = null; + setStatus('Diff view', 'saved'); + showEditor(); + } catch (e) { + alert('Eroare la încărcare diff: ' + e.message); + } + } + + function escapeHtml(text) { + return text.replace(/&/g, '&').replace(//g, '>'); + } + async function loadPath(path = '') { currentPath = path; updateBreadcrumb(); @@ -704,6 +812,7 @@ } if (data.type === 'dir') { + await loadGitStatus(); // Refresh git status renderFileGrid(data.items); updateURL(path); } else if (data.type === 'file') { @@ -796,37 +905,42 @@ const fileType = item.type === 'dir' ? 'Folder' : getFileType(item.name); const sizeStr = item.size !== undefined ? formatSize(item.size) : '-'; + // Git status + const gStatus = gitStatus[item.path] || ''; + const gitBadge = gStatus ? getGitBadge(gStatus) : ''; + const hasGitChange = !!gStatus; + if (currentViewMode === 'details') { return ` -
+
-
${item.name}
+
${gitBadge}${item.name}
${fileType} ${sizeStr} - ${dateStr || '-'} + ${hasGitChange ? `` : (dateStr || '-')}
`; } else if (currentViewMode === 'list') { return ` -
+
-
${item.name}
+
${gitBadge}${item.name}
`; } else { // Tiles view - original style return ` -
+
-
${item.name}
+
${gitBadge}${item.name}
`; } @@ -881,6 +995,17 @@ return (bytes / (1024 * 1024)).toFixed(1) + ' MB'; } + function getGitBadge(status) { + const badges = { + 'M': 'M', + 'A': 'A', + 'D': 'D', + '??': '+', + 'R': 'R', + }; + return badges[status] || `${status}`; + } + function handleClick(path, type) { if (type === 'dir') { loadPath(path); @@ -905,6 +1030,10 @@ const isMarkdown = path.endsWith('.md'); document.getElementById('previewBtn').style.display = isMarkdown ? 'flex' : 'none'; + // Always show diff button - let user check if file has changes + document.getElementById('diffBtn').style.display = 'flex'; + document.getElementById('diffBtn').classList.remove('active'); + // Auto-activate preview for markdown files if (isMarkdown) { const preview = document.getElementById('markdownPreview'); @@ -929,6 +1058,7 @@ function togglePreview() { const editorBody = document.getElementById('editorBody'); const previewBtn = document.getElementById('previewBtn'); + const diffBtn = document.getElementById('diffBtn'); const preview = document.getElementById('markdownPreview'); const content = document.getElementById('codeEditor').value; @@ -936,16 +1066,69 @@ // Switch to edit mode editorBody.classList.remove('preview-active'); previewBtn.classList.remove('active'); + if (diffBtn) diffBtn.classList.remove('active'); setStatus('Edit mode', 'saved'); } else { // Switch to preview mode preview.innerHTML = marked.parse(content); editorBody.classList.add('preview-active'); previewBtn.classList.add('active'); + if (diffBtn) diffBtn.classList.remove('active'); setStatus('Preview mode', 'saved'); } } + async function toggleDiff() { + if (!currentFile) return; + + const editorBody = document.getElementById('editorBody'); + const diffBtn = document.getElementById('diffBtn'); + const previewBtn = document.getElementById('previewBtn'); + const preview = document.getElementById('markdownPreview'); + + // If already showing diff, switch back to edit + if (diffBtn.classList.contains('active')) { + editorBody.classList.remove('preview-active'); + diffBtn.classList.remove('active'); + setStatus('Edit mode', 'saved'); + return; + } + + try { + setStatus('Se încarcă diff...', 'modified'); + const response = await fetch(`${API_BASE}/api/diff?path=${encodeURIComponent(currentFile)}`); + const data = await response.json(); + + if (data.error) { + setStatus('Eroare: ' + data.error, 'error'); + return; + } + + // Format diff with colors + const diffHtml = data.diff + .split('\n') + .map(line => { + if (line.startsWith('+') && !line.startsWith('+++')) { + return `${escapeHtml(line)}`; + } else if (line.startsWith('-') && !line.startsWith('---')) { + return `${escapeHtml(line)}`; + } else if (line.startsWith('@@')) { + return `${escapeHtml(line)}`; + } + return escapeHtml(line); + }) + .join('\n'); + + preview.innerHTML = `
${diffHtml || 'Nicio modificare față de ultima versiune comisă.'}
`; + editorBody.classList.add('preview-active'); + diffBtn.classList.add('active'); + if (previewBtn) previewBtn.classList.remove('active'); + setStatus('Diff view', 'saved'); + } catch (e) { + setStatus('Eroare: ' + e.message, 'error'); + } + } + async function saveFile() { if (!currentFile) return; @@ -1028,7 +1211,68 @@ // Init initViewMode(); - loadPath(getPathFromURL()); + + // Check for git mode + const urlParams = new URLSearchParams(window.location.search); + if (urlParams.get('git') === '1') { + gitOnlyMode = true; + loadGitChangedFiles(); + } else { + loadPath(getPathFromURL()); + } + + function toggleGitFilter() { + gitOnlyMode = !gitOnlyMode; + const btn = document.getElementById('gitFilterBtn'); + btn.classList.toggle('active', gitOnlyMode); + + if (gitOnlyMode) { + loadGitChangedFiles(); + } else { + // Return to normal browse + window.history.replaceState(null, '', 'files.html'); + loadPath(''); + } + } + + async function loadGitChangedFiles() { + await loadGitStatus(); + const changedPaths = Object.keys(gitStatus); + + // Update button state + document.getElementById('gitFilterBtn').classList.add('active'); + + if (changedPaths.length === 0) { + document.getElementById('breadcrumb').innerHTML = ` + ~/clawd + + ✓ Git curat + `; + lucide.createIcons(); + showError('Nicio modificare git - totul e comis!'); + return; + } + + // Update breadcrumb + document.getElementById('breadcrumb').innerHTML = ` + ~/clawd + + 🔸 Git Changes (${changedPaths.length}) + `; + lucide.createIcons(); + + // Create virtual items for changed files + const items = changedPaths.map(path => ({ + name: path, + path: path, + type: 'file', + size: null, + mtime: null + })); + + currentItems = items; + renderFileGrid(items); + } diff --git a/dashboard/index.html b/dashboard/index.html index cb6f9b9..778d91c 100644 --- a/dashboard/index.html +++ b/dashboard/index.html @@ -3,6 +3,7 @@ + Echo · Dashboard @@ -14,61 +15,6 @@ padding: var(--space-5); } - /* Stats Summary */ - .stats-summary { - display: grid; - grid-template-columns: repeat(4, 1fr); - gap: var(--space-3); - margin-bottom: var(--space-4); - } - - @media (max-width: 768px) { - .stats-summary { - grid-template-columns: repeat(2, 1fr); - } - } - - .stat-card { - display: flex; - align-items: center; - gap: var(--space-3); - padding: var(--space-4); - background: var(--bg-surface); - border: 1px solid var(--border); - border-radius: var(--radius-lg); - } - - .stat-icon { - width: 40px; - height: 40px; - display: flex; - align-items: center; - justify-content: center; - background: var(--accent-subtle); - border-radius: var(--radius-md); - color: var(--accent); - } - - .stat-icon svg { - width: 20px; - height: 20px; - } - - .stat-content { - flex: 1; - } - - .stat-value { - font-size: var(--text-xl); - font-weight: 700; - color: var(--text-primary); - } - - .stat-label { - font-size: var(--text-xs); - color: var(--text-muted); - } - .page-header { margin-bottom: var(--space-4); } @@ -518,6 +464,11 @@ color: #f97316; } + .activity-icon.git-file { + background: rgba(234, 179, 8, 0.2); + color: #eab308; + } + .activity-icon.file { background: rgba(20, 184, 166, 0.2); color: #14b8a6; @@ -1000,38 +951,6 @@
- -
-
-
-
-
0
-
Tasks azi
-
-
-
-
-
-
0
-
Tasks săpt.
-
-
-
-
-
-
0
-
Tasks lună
-
-
-
-
-
-
0
-
Insights
-
-
-
-
@@ -1297,40 +1216,28 @@ // Update details const details = document.getElementById('gitDetails'); + const GITEA_URL = 'https://gitea.romfast.ro/romfast/clawd'; let html = ` -
- - Branch: ${git.branch} -
- Last: ${git.lastCommit.hash} ${git.lastCommit.message} (${git.lastCommit.time}) + ${git.lastCommit.hash} ${git.lastCommit.message.substring(0, 40)}${git.lastCommit.message.length > 40 ? '...' : ''} (${git.lastCommit.time})
`; if (git.uncommittedCount > 0) { + const files = git.uncommitted.slice(0, 3).map(f => f.trim().split(' ').pop()).join(', '); + const more = git.uncommittedCount > 3 ? ` +${git.uncommittedCount - 3}` : ''; html += `
- ${git.uncommittedCount} fișiere necomise: -
`; - git.uncommitted.slice(0, 5).forEach(file => { - html += `
- - ${file} -
`; - }); - if (git.uncommittedCount > 5) { - html += `
- ... și încă ${git.uncommittedCount - 5} -
`; - } - } else { - html += `
- - Totul comis ✓ + ${git.uncommittedCount} necomise: ${files}${more}
`; } + html += ``; + details.innerHTML = html; lucide.createIcons(); @@ -1354,7 +1261,9 @@ badge.className = 'status-badge ' + (status.anaf.ok !== false ? 'ok' : 'warning'); const subtitle = document.getElementById('anafSubtitle'); - subtitle.textContent = status.anaf.message || 'Nicio modificare detectată'; + const lastCheck = status.anaf.lastCheck || '-'; + const msg = status.anaf.ok !== false ? 'Nicio modificare' : (status.anaf.message || 'Modificări!'); + subtitle.textContent = `${msg} · ${lastCheck}`; if (status.anaf.lastCheck) { document.getElementById('anafLastCheck').textContent = @@ -1542,51 +1451,9 @@ function refreshActivity() { loadActivity(); - loadStats(); showToast('Activitate reîmprospătată'); } - async function loadStats() { - try { - // Load tasks - const tasksRes = await fetch('tasks.json'); - const tasksData = await tasksRes.json(); - - // Get done tasks - const doneColumn = tasksData.columns.find(c => c.id === 'done'); - const doneTasks = doneColumn ? doneColumn.tasks : []; - - const now = new Date(); - const todayStart = new Date(now.getFullYear(), now.getMonth(), now.getDate()); - const weekStart = new Date(todayStart); - weekStart.setDate(weekStart.getDate() - weekStart.getDay() + 1); // Monday - const monthStart = new Date(now.getFullYear(), now.getMonth(), 1); - - let today = 0, week = 0, month = 0; - - doneTasks.forEach(task => { - if (!task.completed) return; - const completed = new Date(task.completed); - if (completed >= todayStart) today++; - if (completed >= weekStart) week++; - if (completed >= monthStart) month++; - }); - - document.getElementById('statToday').textContent = today; - document.getElementById('statWeek').textContent = week; - document.getElementById('statMonth').textContent = month; - - // Count insights - const insightsRes = await fetch('/echo/api/files?path=kb/insights'); - if (insightsRes.ok) { - const insightsData = await insightsRes.json(); - document.getElementById('statInsights').textContent = insightsData.files ? insightsData.files.length : 0; - } - } catch (e) { - console.log('Stats load error:', e); - } - } - function renderActivity() { const body = document.getElementById('activityBody'); @@ -1607,6 +1474,7 @@ const typeLabels = { 'cron': '⏰ Cron Jobs', 'git': '📦 Git Commits', + 'git-file': '🔸 Git Changes', 'file': '📄 Fișiere', 'task': '✅ Task-uri' }; @@ -1617,13 +1485,22 @@ Ultimele 24h
- ${activityData.map(item => ` -
+ ${activityData.map(item => { + let clickAttr = ''; + if (item.type === 'git-file' && item.path) { + clickAttr = `onclick="window.open('files.html#${item.path}', '_blank')" style="cursor:pointer"`; + } else if (item.path) { + clickAttr = `onclick="window.open('files.html#${item.path}', '_blank')" style="cursor:pointer"`; + } else if (item.type === 'git' && item.commitHash) { + clickAttr = `onclick="window.open('https://gitea.romfast.ro/romfast/clawd/commit/${item.commitHash}', '_blank')" style="cursor:pointer"`; + } + return ` +
-
${item.text}
+
${item.type === 'git' && item.commitHash ? `${item.commitHash}` : ''}${item.text}
${typeLabels[item.type] || item.type} ${item.agent} @@ -1631,7 +1508,7 @@
- `).join('')} + `}).join('')}
`; lucide.createIcons(); @@ -1867,7 +1744,6 @@ loadStatus(); loadIssues(); loadActivity(); - loadStats(); diff --git a/dashboard/notes.html b/dashboard/notes.html index d3cf8ab..5ba93be 100644 --- a/dashboard/notes.html +++ b/dashboard/notes.html @@ -3,6 +3,7 @@ + Echo · KB @@ -1203,7 +1204,7 @@ try { let content = notesCache[file]; if (!content) { - const response = await fetch(file); + const response = await fetch(file + '?t=' + Date.now()); content = await response.text(); notesCache[file] = content; } @@ -1222,7 +1223,7 @@ async function preloadNotes() { for (const note of notesIndex) { try { - const response = await fetch(note.file); + const response = await fetch(note.file + '?t=' + Date.now()); notesCache[note.file] = await response.text(); } catch (e) { notesCache[note.file] = ''; diff --git a/dashboard/status.json b/dashboard/status.json index cd28419..7342d6c 100644 --- a/dashboard/status.json +++ b/dashboard/status.json @@ -1,4 +1,19 @@ { - "git": {"status": "4 fișiere", "clean": false, "files": 4}, - "lastReport": {"type": "evening", "summary": "notes.html îmbunătățit (filtre colorate), rețetă salvată", "time": "30 Jan 2026, 22:00"} -} + "git": { + "status": "4 fișiere", + "clean": false, + "files": 4 + }, + "lastReport": { + "type": "evening", + "summary": "notes.html îmbunătățit (filtre colorate), rețetă salvată", + "time": "30 Jan 2026, 22:00" + }, + "anaf": { + "ok": true, + "status": "OK", + "message": "Nicio modificare detectată", + "lastCheck": "31 Jan 2026, 13:43", + "changesCount": 0 + } +} \ No newline at end of file diff --git a/kb/PROCES-INSIGHTS.md b/kb/PROCES-INSIGHTS.md new file mode 100644 index 0000000..bac157d --- /dev/null +++ b/kb/PROCES-INSIGHTS.md @@ -0,0 +1,98 @@ +# Proces Extragere Insights + +**Scop:** Extrag TOATE ideile acționabile din notele YouTube, nu doar 1-2. + +--- + +## Când se rulează + +- **Morning report** (08:30) - scanează note noi din ultimele 48h +- **Evening report** (20:00) - scanează note noi din ultimele 48h + +--- + +## Pași extragere + +### 1. Identifică notele noi +```bash +find /home/moltbot/clawd/kb/youtube/ -mtime -2 -name "*.md" +``` + +### 2. Citește COMPLET fiecare notă + +**NU doar TL;DR!** Verifică TOATE secțiunile: +- [ ] **TL;DR** - rezumat general +- [ ] **Puncte Cheie** - concepte principale +- [ ] **Acțiuni Practice** - ce poți face concret +- [ ] **Citate** - fraze memorabile care pot deveni provocări +- [ ] **Resurse** - linkuri, cărți, tool-uri menționate + +### 3. Pentru fiecare idee acționabilă + +Întreabă-te: +- **Este acționabil?** (pot face ceva concret cu asta?) +- **Pentru cine?** (stabilește tag-ul) +- **De ce contează?** (ce problemă rezolvă?) + +### 4. Stabilește tag-ul + +| Tag | Domeniu | Exemple | +|-----|---------|---------| +| @work | Productivitate, cod, automatizări | tool-uri, patterns, workflows | +| @health | Sănătate, corp, energie | exerciții, nutriție, somn | +| @growth | Dezvoltare personală, mindset | tehnici mentale, obiceiuri | +| @sprijin | Relații, emoții, grup sprijin | comunicare, conflicte | +| @scout | Cercetași, activități | jocuri, tabere, proiecte | + +### 5. Format insight + +```markdown +- [ ] 📌 **Titlu scurt și clar** - [Sursa](link) + *Context: Ce e, de ce e util, ce problemă rezolvă, cum se aplică* +``` + +**Prioritate emoji:** +- ⚡ Urgent + Important (fă acum) +- 📌 Important dar nu urgent (planifică) +- 💡 Nice to have (backlog) + +--- + +## Checklist calitate + +Înainte de a termina scanarea, verifică: + +- [ ] Am citit nota COMPLETĂ, nu doar TL;DR? +- [ ] Am verificat TOATE secțiunile (Puncte Cheie, Acțiuni, Citate)? +- [ ] Fiecare insight are CONTEXT (nu doar titlu)? +- [ ] Am stabilit tag-ul corect pentru fiecare? +- [ ] Am extras TOATE ideile acționabile, nu doar cele evidente? + +--- + +## Exemple bune vs rele + +❌ **Rău:** +``` +- [ ] 💡 Activitate hero's journey pentru cercetași +``` +(Lipsă context - ce e hero's journey? cum se aplică?) + +✅ **Bun:** +``` +- [ ] 📌 **Activitate hero's journey pentru cercetași** - [Tony Robbins](link) + *Context: Viața pare OK → ceva se întâmplă → "call to adventure" (pare sfârșit dar e început). + Exercițiu: cercetașii identifică un moment greu din viață care s-a dovedit a fi un dar.* +``` + +--- + +## Fișiere relevante + +- **Note YouTube:** `/home/moltbot/clawd/kb/youtube/` +- **Insights zilnice:** `/home/moltbot/clawd/kb/insights/YYYY-MM-DD.md` +- **Backlog:** `/home/moltbot/clawd/kb/backlog.md` + +--- + +*Creat: 2026-01-31 | Actualizat de Echo Work* diff --git a/kb/coaching/2026-01-31-seara.md b/kb/coaching/2026-01-31-seara.md new file mode 100644 index 0000000..d653d26 --- /dev/null +++ b/kb/coaching/2026-01-31-seara.md @@ -0,0 +1,69 @@ +# Gândul de seară - 2026-01-31 + +**Tags:** @health @coaching #tony-robbins #recunostinta #priming + +## Mesaj trimis + +[❤️ Echo] **GÂNDUL DE SEARĂ** 🌙 + +--- + +**Mai întâi: cum a fost provocarea de azi?** + +Dimineață ți-am propus pattern interrupt-ul: ridică-te, 5 respirații, întinde-te, mergi 2 minute. + +Ai încercat? Când te-ai ridicat azi doar ca să te miști, fără scop? Dacă da - ce ai observat? + +--- + +Acum, pentru seară: + +> *"Work on gratitude and happiness is automatic."* +> — Tony Robbins + +**Recunoștința nu se gândește. Se simte.** + +Tony Robbins are un ritual de 10 minute în fiecare dimineață - dar funcționează și seara, înainte de somn. Îl numește **Priming**: + +Nu *gândești* 3 lucruri pentru care ești recunoscător. +Le **simți**. Le treci prin corp. + +De ce contează asta seara? + +Pentru că închei ziua nu cu lista de ce ai greșit, ce n-ai terminat, ce te îngrijorează. +Ci cu ce a mers. Ce a fost acolo pentru tine. Ce ți-a ieșit. + +> *"What's wrong is always available. So is what's right."* + +Ai de ales ce focusezi. + +--- + +**🌙 PROVOCAREA DE SEARĂ** *(3 minute, înainte de somn)* + +1. Stai jos, relaxat, ochii închiși +2. Gândește-te la un moment de azi care a fost bun +3. **Simte-l** - nu doar "a fost ok", ci: unde în corp simți recunoștința? Ce senzație are? Cât de mare poți să o faci? +4. Repetă cu încă 2 momente (pot fi mici - un mesaj, o cafea, un râs) + +Nu e exercițiu de gândire pozitivă. E **antrenament de sistem nervos**. + +Adormi cu totul altceva în corp. + +--- + +*Noapte liniștită!* ✨ + +## Surse folosite + +- [Tony Robbins - Extraordinary Life](http://100.120.119.70:8080/files.html#kb/youtube/2026-01-31_tony-robbins-secret-extraordinary-life.md) - Priming ritual, recunoștința simțită (nu gândită), citate despre recunoștință și focus +- [Insights 2026-01-31](http://100.120.119.70:8080/files.html#kb/insights/2026-01-31.md) - Exercițiu Priming marcat ca integrat + +## Provocarea zilei + +TIP: Recunoștință / Priming seară +PROVOCARE: 3 minute înainte de somn - găsește 3 momente bune din zi și SIMTE-le (nu doar gândește). Unde în corp? Ce senzație? Antrenament de sistem nervos. + +## Follow-up provocare dimineață + +Am întrebat dacă a încercat pattern interrupt-ul (ridicat, 5 respirații, întins, mers 2 min) și ce a observat. diff --git a/kb/health/checklist-post-apa.md b/kb/health/checklist-post-apa.md new file mode 100644 index 0000000..9e4807b --- /dev/null +++ b/kb/health/checklist-post-apa.md @@ -0,0 +1,51 @@ +# Checklist Post cu Apă + +**Sursă:** [Greșeli frecvente în timpul postului](https://youtu.be/4QjkI0sf64M) - Cristina și alimentația naturală +**Tags:** @health #post #water-fasting #detox + +--- + +## Context + +Postul terapeutic trebuie să fie un **post al stării de bine**. Dacă experimentezi stări de rău, greață sau dureri (altele decât cele de "lucru" localizate) - ceva nu e în regulă. + +--- + +## ✅ Checklist + +### Înainte de post (tranziție) +- [ ] 1 săptămână tranziție pe vegetale/lichide +- [ ] Elimină produsele animale gradual +- [ ] Ideal: treci prin sucuri/ciorbe înainte de post complet + +### În timpul postului +- [ ] **Clisme zilnice** (sau cel mult la 2 zile) - CRUCIAL! +- [ ] Apă de calitate cu minerale (magneziu, calciu, potasiu) +- [ ] Evită: apă demineralizată, Bucovina, apă distilată +- [ ] Suplimente Ca/Mg efervescente dacă apa e săracă +- [ ] Curăță limba cu bicarbonat (limba albă = toxine) +- [ ] Monitorizează simptomele - nu le ignora! + +### Mental/Spiritual +- [ ] Scop care depășește propria persoană +- [ ] Nu doar pentru slăbit - pentru vindecare, rugăciune, alții + +--- + +## ⚠️ Semne de alarmă + +**Oprește postul sau fă clismă URGENT dacă:** +- Stări de leșin (= intoxicație colon, NU "ispită") +- Greață persistentă +- Dureri de cap intense +- Apăsare, angoasă, anxietate + +--- + +## 📚 De citit + +- "Jurnalul unui post de 40 de zile cu apă" - Cristina (Meridiane Publishing, Iași) + +--- + +*Notă: Acest checklist e pentru referință. Consultă un specialist înainte de posturi lungi.* diff --git a/kb/index.json b/kb/index.json index 0e481f8..6af923d 100644 --- a/kb/index.json +++ b/kb/index.json @@ -21,6 +21,47 @@ "video": "", "tldr": "PROVOCARE: Ridică-te, fă 5 respirații adânci (4-6), întinde-te, mergi 2 minute. Resetare de stare prin corp." }, + { + "file": "notes-data/coaching/2026-01-31-seara.md", + "title": "Gândul de seară - 2026-01-31", + "date": "2026-01-31", + "tags": [ + "tony-robbins", + "recunostinta", + "priming" + ], + "domains": [ + "health" + ], + "types": [ + "coaching", + "reflectie" + ], + "category": "coaching", + "project": null, + "subdir": null, + "video": "", + "tldr": "Am întrebat dacă a încercat pattern interrupt-ul (ridicat, 5 respirații, întins, mers 2 min) și ce a observat." + }, + { + "file": "notes-data/health/checklist-post-apa.md", + "title": "Checklist Post cu Apă", + "date": "2026-01-31", + "tags": [ + "post", + "water-fasting", + "detox" + ], + "domains": [ + "health" + ], + "types": [], + "category": "health", + "project": null, + "subdir": null, + "video": "", + "tldr": "*Notă: Acest checklist e pentru referință. Consultă un specialist înainte de posturi lungi.*" + }, { "file": "notes-data/insights/2026-01-31.md", "title": "Insights 2026-01-31", @@ -56,6 +97,19 @@ "video": "", "tldr": "*Acest document se actualizează când se modifică fluxul joburilor.*" }, + { + "file": "notes-data/projects/ssh-access-echo.md", + "title": "Acces SSH pentru Echo", + "date": "2026-01-31", + "tags": [], + "domains": [], + "types": [], + "category": "projects", + "project": null, + "subdir": null, + "video": "", + "tldr": "*Actualizat: 2026-01-31*" + }, { "file": "notes-data/projects/grup-sprijin/README.md", "title": "Grup de Sprijin - Lideri Cercetași", @@ -188,15 +242,15 @@ "project": null, "subdir": null, "video": "", - "tldr": "- Insights trebuie să aibă status clar ca să nu se repete propunerile" + "tldr": "- Files: view modes ca Windows Explorer (List/Details/Tiles)" }, { "file": "notes-data/projects/vending-master/README.md", "title": "Proiect: Vending Master - Integrare Website → ROA", "date": "2026-01-30", "tags": [ - "integrare", - "vending-master" + "vending-master", + "integrare" ], "domains": [ "work" @@ -661,18 +715,19 @@ } ], "stats": { - "total": 33, + "total": 36, "by_domain": { "work": 9, - "health": 5, + "health": 7, "growth": 3, "sprijin": 16, "scout": 1 }, "by_category": { - "coaching": 1, + "coaching": 2, + "health": 1, "insights": 1, - "projects": 17, + "projects": 18, "retete": 1, "youtube": 9, "memory": 3, @@ -699,6 +754,7 @@ ], "categories": [ "coaching", + "health", "insights", "projects", "retete", diff --git a/kb/insights/2026-01-31.md b/kb/insights/2026-01-31.md index 92ba443..e8a93a9 100644 --- a/kb/insights/2026-01-31.md +++ b/kb/insights/2026-01-31.md @@ -10,16 +10,18 @@ Idei extrase din note YouTube. Format: `[ ]` neprocesat, `[x]` făcut, `[→]` b - [x] ⚡ Verificare securitate Clawdbot (port, trustedProxies) - FĂCUT 2026-01-31 de Echo Work - [x] ⚡ Git commit + push restructurare - FĂCUT 2026-01-31 de Echo Work (99 fișiere) -- [ ] 📌 Template spec-driven development în kb/projects/ - [GSD](https://moltbot.tailf7372d.ts.net/echo/files.html#kb/youtube/2026-01-29_gsd-framework-claude-code.md) -- [ ] 💡 Job proactive coding noaptea (ora 23) - [5 Use Cases](https://moltbot.tailf7372d.ts.net/echo/files.html#kb/youtube/2026-01-30_clawdbot-5-use-cases.md) -- [ ] 💡 Spellbook - prompt templates cu variabile - [Kitze](https://moltbot.tailf7372d.ts.net/echo/files.html#kb/youtube/2026-01-30_clawdbot-personal-os-kitze.md) +- [—] 📌 Template spec-driven development în kb/projects/ - [GSD](https://moltbot.tailf7372d.ts.net/echo/files.html#kb/youtube/2026-01-29_gsd-framework-claude-code.md) - SKIP 2026-01-31 +- [—] 💡 Job proactive coding noaptea (ora 23) - [5 Use Cases](https://moltbot.tailf7372d.ts.net/echo/files.html#kb/youtube/2026-01-30_clawdbot-5-use-cases.md) - SKIP 2026-01-31 (există deja night-execute) +- [—] 💡 Spellbook - prompt templates cu variabile - [Kitze](https://moltbot.tailf7372d.ts.net/echo/files.html#kb/youtube/2026-01-30_clawdbot-personal-os-kitze.md) - SKIP 2026-01-31 --- ## @health - Sănătate -- [ ] 📌 Reminder "ridică-te, mergi 2 min" în respirații - [Tony Robbins](https://moltbot.tailf7372d.ts.net/echo/files.html#kb/youtube/2026-01-31_tony-robbins-secret-extraordinary-life.md) -- [ ] 💡 Checklist post negru (tranziție, clisme, apă) - [Post Apă](https://moltbot.tailf7372d.ts.net/echo/files.html#kb/youtube/2026-01-29_greseli-post-apa.md) +- [x] 📌 Reminder "ridică-te, mergi 2 min" în respirații - [Tony Robbins](https://moltbot.tailf7372d.ts.net/echo/files.html#kb/youtube/2026-01-31_tony-robbins-secret-extraordinary-life.md) - FĂCUT 2026-01-31 (actualizat job respiratie-orar cu context Pattern Interrupt) +- [x] 💡 Checklist post negru (tranziție, clisme, apă) - [Post Apă](https://moltbot.tailf7372d.ts.net/echo/files.html#kb/youtube/2026-01-29_greseli-post-apa.md) - FĂCUT 2026-01-31 (creat kb/health/checklist-post-apa.md) +- [ ] 📌 **Apă rece/duș rece pentru deblocare rapidă** - [Tony Robbins](https://moltbot.tailf7372d.ts.net/echo/files.html#kb/youtube/2026-01-31_tony-robbins-secret-extraordinary-life.md) + *Context: Schimbarea de temperatură resetează instant starea. Când ești blocat/stresat, duș rece sau apă pe față.* --- @@ -27,8 +29,16 @@ Idei extrase din note YouTube. Format: `[ ]` neprocesat, `[x]` făcut, `[→]` b - [x] ⚡ Exercițiu Priming în morning-coaching - INTEGRAT în job morning-coaching (citește din insights) - [x] 📌 Pattern Interrupt tehnica - INTEGRAT în job morning-coaching ca provocare practică -- [ ] 💡 Dezvoltă personalitățile agenților (stil, nu doar funcțional) - [Kitze](https://moltbot.tailf7372d.ts.net/echo/files.html#kb/youtube/2026-01-30_clawdbot-personal-os-kitze.md) +- [—] 💡 Dezvoltă personalitățile agenților (stil, nu doar funcțional) - [Kitze](https://moltbot.tailf7372d.ts.net/echo/files.html#kb/youtube/2026-01-30_clawdbot-personal-os-kitze.md) - SKIP 2026-01-31 - [x] 💡 "Pentru cine altcineva faci?" - INTEGRAT în coaching dimineață/seară +- [ ] 📌 **Tehnica focus pentru anxietate** - [Tony Robbins](https://moltbot.tailf7372d.ts.net/echo/files.html#kb/youtube/2026-01-31_tony-robbins-secret-extraordinary-life.md) + *Context: Nu doar CE vezi, ci CUM. Anxietate = imagine mare, aproape, se îndepărtează. Încredere = imagine se apropie. Schimbă perspectiva mental.* +- [ ] 📌 **"Can we begin again?"** - [Tony Robbins](https://moltbot.tailf7372d.ts.net/echo/files.html#kb/youtube/2026-01-31_tony-robbins-secret-extraordinary-life.md) + *Context: Tehnică de reset în relații/conflicte. În loc să escaladezi, propui reset.* +- [ ] 💡 **Cele 5 arii de stăpânit** - [Tony Robbins](https://moltbot.tailf7372d.ts.net/echo/files.html#kb/youtube/2026-01-31_tony-robbins-secret-extraordinary-life.md) + *Context: 1.Corp 2.Emoții 3.Relații 4.Timp 5.Finanțe+Spiritualitate. Framework pentru audit personal.* +- [ ] 💡 **Obiective nerealiste, timeline strâns** - [Tony Robbins](https://moltbot.tailf7372d.ts.net/echo/files.html#kb/youtube/2026-01-31_tony-robbins-secret-extraordinary-life.md) + *Context: Goals mari cu deadline 12-36 luni max. "Unrealistic goals with realistic timeline" forțează acțiune.* --- @@ -37,12 +47,19 @@ Idei extrase din note YouTube. Format: `[ ]` neprocesat, `[x]` făcut, `[→]` b - [x] ⚡ Fișă "blocare vs deblocare" - CREAT `kb/projects/grup-sprijin/biblioteca/fisa-blocare-vs-deblocare.md` - [x] 📌 Întrebare "Ce moment greu s-a dovedit cadou?" - CREAT `kb/projects/grup-sprijin/biblioteca/intrebare-moment-greu-cadou.md` - [x] 💡 "Pentru cine altcineva faci?" - CREAT `kb/projects/grup-sprijin/biblioteca/intrebare-pentru-cine-altcineva.md` +- [ ] 📌 **"I love you too much to go this place"** - [Tony Robbins](https://moltbot.tailf7372d.ts.net/echo/files.html#kb/youtube/2026-01-31_tony-robbins-secret-extraordinary-life.md) + *Context: Frază pentru a opri escaladarea în conflicte. Recunoaște că mergi într-o direcție proastă și propune oprire.* +- [ ] 💡 **Ritualuri de conectare** - [Tony Robbins](https://moltbot.tailf7372d.ts.net/echo/files.html#kb/youtube/2026-01-31_tony-robbins-secret-extraordinary-life.md) + *Context: Cina fără telefoane, hot tub catch-up, priviri, atingeri. Fă momentele să conteze.* --- ## @scout - Cercetași -- [ ] 💡 Activitate hero's journey pentru cercetași - [Tony Robbins](https://moltbot.tailf7372d.ts.net/echo/files.html#kb/youtube/2026-01-31_tony-robbins-secret-extraordinary-life.md) +- [ ] 📌 **Activitate hero's journey pentru cercetași** - [Tony Robbins](https://moltbot.tailf7372d.ts.net/echo/files.html#kb/youtube/2026-01-31_tony-robbins-secret-extraordinary-life.md) + *Context: Viața pare OK → ceva se întâmplă → "call to adventure" (pare sfârșit dar e început). Exercițiu: cercetașii identifică un moment greu din viață care s-a dovedit a fi un dar. Conexiune cu povestea lui Tony: la 11 ani era sărac, un străin a adus mâncare → a învățat "strangers care" → acum hrănește milioane.* +- [ ] 💡 **"Începe de unde ești"** - [Tony Robbins](https://moltbot.tailf7372d.ts.net/echo/files.html#kb/youtube/2026-01-31_tony-robbins-secret-extraordinary-life.md) + *Context: Povestea lui Tony - la 17 ani a hrănit 2 familii, apoi 4, 8, acum 42 milioane. "If I won't give a dime out of a dollar, how will I ever give a million out of 10?" Aplicabil pentru proiecte cercetași de ajutor comunitar.* --- diff --git a/kb/projects/ssh-access-echo.md b/kb/projects/ssh-access-echo.md new file mode 100644 index 0000000..d5f6f0b --- /dev/null +++ b/kb/projects/ssh-access-echo.md @@ -0,0 +1,78 @@ +# Acces SSH pentru Echo + +Instrucțiuni pentru a da acces SSH lui Echo pe un server nou. + +## Cheia SSH publică + +``` +ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIO8ULMGdacgLrW3YhNb3+bsUsP60LdEohwNPgpiRAdSE echo@moltbot +``` + +## Comenzi (rulează ca root) + +### 1. Creează user echo +```bash +adduser echo +``` + +### 2. Adaugă în grupuri necesare (opțional) +```bash +# Pentru Docker: +usermod -aG docker echo + +# Pentru sudo (dacă e nevoie): +usermod -aG sudo echo +``` + +### 3. Setup SSH key +```bash +mkdir -p /home/echo/.ssh +echo "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIO8ULMGdacgLrW3YhNb3+bsUsP60LdEohwNPgpiRAdSE echo@moltbot" > /home/echo/.ssh/authorized_keys +chown -R echo:echo /home/echo/.ssh +chmod 700 /home/echo/.ssh +chmod 600 /home/echo/.ssh/authorized_keys +``` + +### 4. Securizare (blochează parola) +```bash +passwd -l echo +``` + +### 5. Verifică SSH activ +```bash +systemctl status sshd || apt install -y openssh-server +``` + +## Comandă rapidă (all-in-one) + +```bash +adduser echo --disabled-password --gecos "" && \ +mkdir -p /home/echo/.ssh && \ +echo "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIO8ULMGdacgLrW3YhNb3+bsUsP60LdEohwNPgpiRAdSE echo@moltbot" > /home/echo/.ssh/authorized_keys && \ +chown -R echo:echo /home/echo/.ssh && \ +chmod 700 /home/echo/.ssh && \ +chmod 600 /home/echo/.ssh/authorized_keys && \ +echo "Done! Echo poate accesa: ssh echo@$(hostname -I | awk '{print $1}')" +``` + +## Pentru LXC Proxmox + +```bash +# De pe Proxmox host: +pct enter + +# Apoi rulează comenzile de mai sus +``` + +## Servere cu acces configurat + +| Server | IP | User | Acces | Note | +|--------|-----|------|-------|------| +| portainer | 10.0.20.170 | echo | ✅ | Docker, LXC 100 pe pvemini | +| pveelite | 10.0.20.202 | echo | ✅ | Proxmox node, sudo: qm/pct/pvesh | +| pvemini | 10.0.20.201 | echo | ✅ | Proxmox node, sudo: qm/pct/pvesh | +| pve1 | 10.0.20.200 | echo | ✅ | Proxmox node, sudo: qm/pct/pvesh | + +--- + +*Actualizat: 2026-01-31* diff --git a/tools/anaf-monitor/monitor_v2.py b/tools/anaf-monitor/monitor_v2.py index bc5fe19..4facbe3 100644 --- a/tools/anaf-monitor/monitor_v2.py +++ b/tools/anaf-monitor/monitor_v2.py @@ -14,6 +14,7 @@ SCRIPT_DIR = Path(__file__).parent CONFIG_FILE = SCRIPT_DIR / "config.json" VERSIONS_FILE = SCRIPT_DIR / "versions.json" LOG_FILE = SCRIPT_DIR / "monitor.log" +DASHBOARD_STATUS = SCRIPT_DIR.parent.parent / "dashboard" / "status.json" SSL_CTX = ssl.create_default_context() SSL_CTX.check_hostname = False @@ -171,6 +172,21 @@ def check_page(page, saved_versions): log(f"OK: {page_id}") return None +def update_dashboard_status(has_changes, changes_count): + """Actualizează status.json pentru dashboard""" + try: + status = load_json(DASHBOARD_STATUS, {}) + status['anaf'] = { + 'ok': not has_changes, + 'status': 'MODIFICĂRI' if has_changes else 'OK', + 'message': f'{changes_count} modificări detectate' if has_changes else 'Nicio modificare detectată', + 'lastCheck': datetime.now().strftime('%d %b %Y, %H:%M'), + 'changesCount': changes_count + } + save_json(DASHBOARD_STATUS, status) + except Exception as e: + log(f"ERROR updating dashboard status: {e}") + def main(): log("=== Starting ANAF monitor v2 ===") @@ -184,6 +200,10 @@ def main(): all_changes.append(result) save_json(VERSIONS_FILE, saved_versions) + + # Update dashboard status + update_dashboard_status(len(all_changes) > 0, len(all_changes)) + log("=== Monitor complete ===") print(json.dumps({"changes": all_changes}, ensure_ascii=False, indent=2))