Add Ralph skill for autonomous PRD creation and implementation

This commit is contained in:
Echo
2026-02-09 08:56:16 +00:00
parent 59abff1bce
commit e82a786885
27 changed files with 2673 additions and 67 deletions

View File

@@ -862,7 +862,7 @@ def clean_vtt(content):
if __name__ == '__main__':
port = 8080
port = 8088
os.chdir(KANBAN_DIR)
print(f"Starting Echo Task Board API on port {port}")

View File

@@ -3,13 +3,13 @@
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<link rel="icon" type="image/svg+xml" href="favicon.svg">
<link rel="icon" type="image/svg+xml" href="/echo/favicon.svg">
<title>Echo · Files</title>
<link rel="stylesheet" href="common.css">
<link rel="stylesheet" href="/echo/common.css">
<script src="https://unpkg.com/lucide@latest/dist/umd/lucide.min.js"></script>
<script src="https://cdn.jsdelivr.net/npm/marked/marked.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/html2pdf.js/0.10.1/html2pdf.bundle.min.js"></script>
<script src="swipe-nav.js"></script>
<script src="/echo/swipe-nav.js"></script>
<style>
.main {
display: flex;
@@ -829,20 +829,20 @@
</head>
<body>
<header class="header">
<a href="index.html" class="logo">
<a href="/echo/index.html" class="logo">
<i data-lucide="circle-dot"></i>
Echo
</a>
<nav class="nav">
<a href="index.html" class="nav-item">
<a href="/echo/index.html" class="nav-item">
<i data-lucide="layout-list"></i>
<span>Tasks</span>
</a>
<a href="notes.html" class="nav-item">
<a href="/echo/notes.html" class="nav-item">
<i data-lucide="file-text"></i>
<span>KB</span>
</a>
<a href="files.html" class="nav-item active">
<a href="/echo/files.html" class="nav-item active">
<i data-lucide="folder"></i>
<span>Files</span>
</a>

View File

@@ -4,7 +4,7 @@
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Echo · Grup Sprijin</title>
<link rel="stylesheet" href="common.css">
<link rel="stylesheet" href="/echo/common.css">
<script src="https://unpkg.com/lucide@latest/dist/umd/lucide.min.js"></script>
<style>
.main {
@@ -233,24 +233,24 @@
</head>
<body>
<header class="header">
<a href="index.html" class="logo">
<a href="/echo/index.html" class="logo">
<i data-lucide="circle-dot"></i>
Echo
</a>
<nav class="nav">
<a href="index.html" class="nav-item">
<a href="/echo/index.html" class="nav-item">
<i data-lucide="layout-list"></i>
<span>Tasks</span>
</a>
<a href="notes.html" class="nav-item">
<a href="/echo/notes.html" class="nav-item">
<i data-lucide="file-text"></i>
<span>Notes</span>
</a>
<a href="files.html" class="nav-item">
<a href="/echo/files.html" class="nav-item">
<i data-lucide="folder"></i>
<span>Files</span>
</a>
<a href="grup-sprijin.html" class="nav-item active">
<a href="/echo/grup-sprijin.html" class="nav-item active">
<i data-lucide="heart-handshake"></i>
<span>Grup</span>
</a>
@@ -476,7 +476,7 @@
if (fise.length > 0) {
document.getElementById('fiseSection').style.display = 'block';
document.getElementById('fiseList').innerHTML = fise.map(f => `
<a href="files.html#kanban/grup-sprijin/${f.name}" class="filter-btn" style="text-decoration: none;">
<a href="/echo/files.html#kanban/grup-sprijin/${f.name}" class="filter-btn" style="text-decoration: none;">
${f.name.replace('fisa-', '').replace('.md', '')}
</a>
`).join('');

View File

@@ -3,11 +3,11 @@
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<link rel="icon" type="image/svg+xml" href="favicon.svg">
<link rel="icon" type="image/svg+xml" href="/echo/favicon.svg">
<title>Echo · Dashboard</title>
<link rel="stylesheet" href="common.css">
<link rel="stylesheet" href="/echo/common.css">
<script src="https://unpkg.com/lucide@latest/dist/umd/lucide.min.js"></script>
<script src="swipe-nav.js"></script>
<script src="/echo/swipe-nav.js"></script>
<style>
.main {
max-width: 1400px;
@@ -1054,20 +1054,20 @@
</head>
<body>
<header class="header">
<a href="index.html" class="logo">
<a href="/echo/index.html" class="logo">
<i data-lucide="circle-dot"></i>
Echo
</a>
<nav class="nav">
<a href="index.html" class="nav-item active">
<a href="/echo/index.html" class="nav-item active">
<i data-lucide="layout-dashboard"></i>
<span>Dashboard</span>
</a>
<a href="notes.html" class="nav-item">
<a href="/echo/notes.html" class="nav-item">
<i data-lucide="file-text"></i>
<span>KB</span>
</a>
<a href="files.html" class="nav-item">
<a href="/echo/files.html" class="nav-item">
<i data-lucide="folder"></i>
<span>Files</span>
</a>
@@ -1526,7 +1526,7 @@
async function loadGitStatus() {
try {
const response = await fetch('./api/git?' + Date.now());
const response = await fetch('/echo/api/git?' + Date.now());
if (!response.ok) throw new Error('API error');
const git = await response.json();
@@ -1560,7 +1560,7 @@
const more = git.uncommittedCount > 3 ? ` +${git.uncommittedCount - 3}` : '';
html += `<div class="status-detail-item uncommitted">
<i data-lucide="alert-circle"></i>
<span><a href="files.html?git=1" style="color:var(--warning)"><strong>${git.uncommittedCount}</strong> necomise</a>: ${files}${more}</span>
<span><a href="/echo/files.html?git=1" style="color:var(--warning)"><strong>${git.uncommittedCount}</strong> necomise</a>: ${files}${more}</span>
</div>`;
}
@@ -1582,7 +1582,7 @@
async function loadAnafStatus() {
try {
const response = await fetch('status.json?' + Date.now());
const response = await fetch('/echo/status.json?' + Date.now());
if (!response.ok) throw new Error('No status.json');
const status = await response.json();
@@ -1610,7 +1610,7 @@
async function loadCronStatus() {
try {
const response = await fetch('./api/cron?' + Date.now());
const response = await fetch('/echo/api/cron?' + Date.now());
if (!response.ok) throw new Error('API error');
const data = await response.json();
@@ -1681,7 +1681,7 @@
async function loadAgentsStatus() {
try {
const response = await fetch('./api/agents?' + Date.now());
const response = await fetch('/echo/api/agents?' + Date.now());
if (!response.ok) throw new Error('API error');
const data = await response.json();
@@ -1737,7 +1737,7 @@
async function loadTodos() {
try {
const response = await fetch('todos.json?' + Date.now());
const response = await fetch('/echo/todos.json?' + Date.now());
if (response.ok) {
todosData = await response.json();
renderTodos();
@@ -1991,7 +1991,7 @@
// ===== ISSUES =====
async function loadIssues() {
try {
const response = await fetch('issues.json?' + Date.now());
const response = await fetch('/echo/issues.json?' + Date.now());
issuesData = await response.json();
populateProgramSelect();
renderIssues();
@@ -2017,7 +2017,7 @@
async function loadActivity() {
try {
// Fetch from unified activity API
const response = await fetch('./api/activity?t=' + Date.now());
const response = await fetch('/echo/api/activity?t=' + Date.now());
const data = await response.json();
if (data.error) throw new Error(data.error);

View File

@@ -3,11 +3,11 @@
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<link rel="icon" type="image/svg+xml" href="favicon.svg">
<link rel="icon" type="image/svg+xml" href="/echo/favicon.svg">
<title>Echo · KB</title>
<link rel="stylesheet" href="common.css">
<link rel="stylesheet" href="/echo/common.css">
<script src="https://unpkg.com/lucide@latest/dist/umd/lucide.min.js"></script>
<script src="swipe-nav.js"></script>
<script src="/echo/swipe-nav.js"></script>
<script src="https://cdn.jsdelivr.net/npm/marked/marked.min.js"></script>
<style>
.main {
@@ -679,20 +679,20 @@
</head>
<body>
<header class="header">
<a href="index.html" class="logo">
<a href="/echo/index.html" class="logo">
<i data-lucide="circle-dot"></i>
Echo
</a>
<nav class="nav">
<a href="index.html" class="nav-item">
<a href="/echo/index.html" class="nav-item">
<i data-lucide="layout-list"></i>
<span>Tasks</span>
</a>
<a href="notes.html" class="nav-item active">
<a href="/echo/notes.html" class="nav-item active">
<i data-lucide="file-text"></i>
<span>KB</span>
</a>
<a href="files.html" class="nav-item">
<a href="/echo/files.html" class="nav-item">
<i data-lucide="folder"></i>
<span>Files</span>
</a>
@@ -1172,7 +1172,7 @@
<div class="note-card" onclick="openNote('${note.file}')">
<div class="note-title">
${note.title}
<a href="files.html#${filesPath}" class="note-file-link" onclick="event.stopPropagation()" title="${filesPath}">
<a href="/echo/files.html#${filesPath}" class="note-file-link" onclick="event.stopPropagation()" title="${filesPath}">
<i data-lucide="external-link"></i>
</a>
</div>

View File

@@ -13,7 +13,7 @@
"ok": true,
"status": "OK",
"message": "Nicio modificare detectată",
"lastCheck": "06 Feb 2026, 14:00",
"lastCheck": "09 Feb 2026, 08:00",
"changesCount": 0
}
}

View File

@@ -1,5 +1,5 @@
{
"lastUpdated": "2026-02-08T07:00:00.000Z",
"lastUpdated": "2026-02-08T14:32:35.511Z",
"items": [
{
"id": "prov-2026-02-08",
@@ -8,8 +8,8 @@
"example": "Scenariul tău real: Într-un exercițiu NLP, partenerul te blochează sau critică. În loc să rămâi în defensivă ('e greu') → aplici pattern interrupt din Tony Robbins: observi fiziologia (umeri contractați?), schimbi focusul (ce pot învăța despre cum reacționez?), schimbi limbajul ('e provocator' în loc de 'e greu'). Exercițiul devine mirror pentru tiparele tale în relații/business - exact cum reacționezi când angajatul nu înțelege sau când clientul critică.",
"domain": "self",
"dueDate": "2026-02-08",
"done": false,
"doneAt": null,
"done": true,
"doneAt": "2026-02-08T14:32:35.511Z",
"source": "Tony Robbins - The Secret to an Extraordinary Life + Monica Ion - Legea Fractalilor",
"sourceUrl": "https://moltbot.tailf7372d.ts.net/echo/files.html#memory/kb/coaching/2026-02-08-dimineata.md",
"createdAt": "2026-02-08T07:00:00.000Z"