gb/VIBE.md
Rodrigo Rodriguez (Pragmatismo) f3bad05e76
Some checks failed
BotServer CI / build (push) Failing after 13s
Fix LXD socket handling in container mode
2026-03-15 18:19:22 -03:00

15 KiB

Vibe App Improvement Specification

Realistic Enhancements Based on Existing Architecture

Current State Analysis

Vibe is an AI-powered app builder with:

  • Mantis Farm: Multi-agent system (Mantis #1-4 with EVOLVED/BRED/WILD states)
  • Pipeline Stages: PLAN → BUILD → REVIEW → DEPLOY → MONITOR
  • Canvas: Task node visualization with drag-and-drop
  • Integrated Tools: Code editor, database schema, git, browser, terminal (via modals)
  • Chat Interface: Real-time WebSocket with Mantis #1
  • Deployment: Internal (GB Platform) and External (Forgejo ALM)
  • MCP Panel: Model Context Protocol servers
  • Backend: /api/autotask/classify endpoint for intent processing

🎯 Critical Improvements (Fix What's Broken)

1. Fix Task Node Rendering

Problem: Nodes don't persist after page refresh

Fix:

// Save nodes to localStorage
function saveCanvasState() {
    localStorage.setItem('vibe_canvas_state', JSON.stringify({
        nodes: taskNodes,
        project: currentProject,
        timestamp: Date.now()
    }));
}

// Restore on load
function restoreCanvasState() {
    const saved = localStorage.getItem('vibe_canvas_state');
    if (!saved) return;
    
    const state = JSON.parse(saved);
    currentProject = state.project;
    
    state.nodes.forEach((node, i) => {
        setTimeout(() => {
            addTaskNode(node.title, node.description, node.meta);
        }, i * 200);
    });
}

// Call on init
document.addEventListener('DOMContentLoaded', restoreCanvasState);

2. Make Editor Actually Editable

Problem: Editor modal loads but can't edit files

Fix:

<!-- Replace basic editor with Monaco -->
<div id="vibeEditorModal" class="vibe-editor-modal">
    <div class="editor-header">
        <span id="currentFileName">untitled.txt</span>
        <div class="editor-actions">
            <button onclick="saveFile()">💾 Save</button>
            <button onclick="closeEditor()"></button>
        </div>
    </div>
    <div id="monacoEditor" style="height: calc(100% - 50px);"></div>
</div>

<script src="/suite/js/vendor/monaco-editor/min/vs/loader.js"></script>
<script>
let editor;

function initMonaco() {
    require.config({ paths: { vs: '/suite/js/vendor/monaco-editor/min/vs' } });
    require(['vs/editor/editor.main'], function() {
        editor = monaco.editor.create(document.getElementById('monacoEditor'), {
            value: '',
            language: 'javascript',
            theme: 'vs-dark',
            automaticLayout: true
        });
    });
}

async function saveFile() {
    const content = editor.getValue();
    const filename = document.getElementById('currentFileName').textContent;
    
    await fetch('/api/vibe/file', {
        method: 'POST',
        headers: { 'Content-Type': 'application/json' },
        body: JSON.stringify({ filename, content })
    });
    
    vibeAddMsg('system', `✅ Saved ${filename}`);
}
</script>

3. Connect Database Schema Tool

Problem: Database modal shows but doesn't interact with actual DB

Fix:

async function loadDatabaseSchema() {
    const response = await fetch('/api/vibe/schema');
    const { tables } = await response.json();
    
    const schemaView = document.getElementById('databaseSchemaView');
    schemaView.innerHTML = tables.map(table => `
        <div class="table-card">
            <h4>${table.name}</h4>
            <div class="columns">
                ${table.columns.map(col => `
                    <div class="column">
                        <span class="col-name">${col.name}</span>
                        <span class="col-type">${col.type}</span>
                    </div>
                `).join('')}
            </div>
        </div>
    `).join('');
}

async function createTable() {
    const tableName = prompt('Table name:');
    if (!tableName) return;
    
    const response = await fetch('/api/vibe/schema/table', {
        method: 'POST',
        headers: { 'Content-Type': 'application/json' },
        body: JSON.stringify({
            name: tableName,
            columns: [
                { name: 'id', type: 'UUID PRIMARY KEY' },
                { name: 'created_at', type: 'TIMESTAMP DEFAULT NOW()' }
            ]
        })
    });
    
    if (response.ok) {
        vibeAddMsg('system', `✅ Created table ${tableName}`);
        loadDatabaseSchema();
    }
}

4. Fix Terminal Integration

Problem: Terminal doesn't execute commands

Fix:

// WebSocket for terminal
const terminalWs = new WebSocket(`ws://${location.host}/ws/terminal`);
const terminalOutput = document.getElementById('terminalOutput');

terminalWs.onmessage = (event) => {
    const line = document.createElement('div');
    line.textContent = event.data;
    terminalOutput.appendChild(line);
    terminalOutput.scrollTop = terminalOutput.scrollHeight;
};

function executeCommand(cmd) {
    terminalWs.send(JSON.stringify({ command: cmd }));
}

document.getElementById('terminalInput').addEventListener('keypress', (e) => {
    if (e.key === 'Enter') {
        const cmd = e.target.value;
        executeCommand(cmd);
        e.target.value = '';
    }
});

5. Make Git Status Actually Work

Problem: Git panel shows but doesn't show real status

Fix:

async function loadGitStatus() {
    const response = await fetch('/api/vibe/git/status');
    const { branch, changes } = await response.json();
    
    document.getElementById('gitBranch').textContent = branch;
    
    const changesList = document.getElementById('gitChanges');
    changesList.innerHTML = changes.map(change => `
        <div class="git-change ${change.status}">
            <span class="change-status">${change.status}</span>
            <span class="change-file">${change.file}</span>
        </div>
    `).join('');
}

async function gitCommit() {
    const message = prompt('Commit message:');
    if (!message) return;
    
    await fetch('/api/vibe/git/commit', {
        method: 'POST',
        headers: { 'Content-Type': 'application/json' },
        body: JSON.stringify({ message })
    });
    
    vibeAddMsg('system', `✅ Committed: ${message}`);
    loadGitStatus();
}

🚀 High-Value Additions

6. File Tree in Editor

What: Show project structure, click to open files

Implementation:

<div class="editor-sidebar">
    <div class="file-tree" id="fileTree">
        <!-- Populated dynamically -->
    </div>
</div>

<script>
async function loadFileTree() {
    const response = await fetch('/api/vibe/files');
    const { files } = await response.json();
    
    const tree = buildTree(files);
    document.getElementById('fileTree').innerHTML = renderTree(tree);
}

function renderTree(node, level = 0) {
    if (node.type === 'file') {
        return `
            <div class="tree-item file" style="padding-left: ${level * 16}px" 
                 onclick="openFile('${node.path}')">
                📄 ${node.name}
            </div>
        `;
    }
    
    return `
        <div class="tree-item folder" style="padding-left: ${level * 16}px">
            📁 ${node.name}
            ${node.children.map(child => renderTree(child, level + 1)).join('')}
        </div>
    `;
}

async function openFile(path) {
    const response = await fetch(`/api/vibe/file?path=${encodeURIComponent(path)}`);
    const content = await response.text();
    
    editor.setValue(content);
    document.getElementById('currentFileName').textContent = path.split('/').pop();
}
</script>

7. Keyboard Shortcuts

What: Cmd+S to save, Cmd+K for command palette

Implementation:

document.addEventListener('keydown', (e) => {
    // Cmd/Ctrl + S: Save
    if ((e.metaKey || e.ctrlKey) && e.key === 's') {
        e.preventDefault();
        saveFile();
    }
    
    // Cmd/Ctrl + K: Command palette
    if ((e.metaKey || e.ctrlKey) && e.key === 'k') {
        e.preventDefault();
        openCommandPalette();
    }
    
    // Cmd/Ctrl + B: Toggle sidebar
    if ((e.metaKey || e.ctrlKey) && e.key === 'b') {
        e.preventDefault();
        toggleSidebar();
    }
    
    // Escape: Close modals
    if (e.key === 'Escape') {
        closeAllModals();
    }
});

8. Quick Command Palette

What: Fuzzy search for all actions

Implementation:

<div id="commandPalette" class="command-palette" style="display: none;">
    <input type="text" id="commandInput" placeholder="Type a command...">
    <div class="command-results" id="commandResults"></div>
</div>

<script>
const commands = [
    { label: 'Save File', action: saveFile, shortcut: 'Cmd+S' },
    { label: 'New File', action: newFile, shortcut: 'Cmd+N' },
    { label: 'Open Terminal', action: () => openModal('terminal') },
    { label: 'Git Status', action: () => openModal('git') },
    { label: 'Database Schema', action: () => openModal('database') },
    { label: 'Deploy App', action: showDeploymentModal }
];

function openCommandPalette() {
    document.getElementById('commandPalette').style.display = 'flex';
    document.getElementById('commandInput').focus();
}

document.getElementById('commandInput').addEventListener('input', (e) => {
    const query = e.target.value.toLowerCase();
    const filtered = commands.filter(cmd => 
        cmd.label.toLowerCase().includes(query)
    );
    
    document.getElementById('commandResults').innerHTML = filtered.map(cmd => `
        <div class="command-item" onclick="executeCommand('${cmd.label}')">
            <span>${cmd.label}</span>
            <span class="shortcut">${cmd.shortcut || ''}</span>
        </div>
    `).join('');
});
</script>

9. Task Node Actions

What: Click node to see details, edit, or delete

Implementation:

function addTaskNode(title, description, meta) {
    // ... existing code ...
    
    node.onclick = () => showNodeDetails(nodeIdCounter);
    
    return node;
}

function showNodeDetails(nodeId) {
    const node = taskNodes.find(n => n.id === nodeId);
    if (!node) return;
    
    const modal = document.createElement('div');
    modal.className = 'node-details-modal';
    modal.innerHTML = `
        <div class="modal-content">
            <h3>${node.title}</h3>
            <p>${node.description}</p>
            
            <div class="node-files">
                <h4>Files</h4>
                ${(node.meta.fileList || []).map(f => `<div>📄 ${f}</div>`).join('')}
            </div>
            
            <div class="node-actions">
                <button onclick="editNode(${nodeId})">✏️ Edit</button>
                <button onclick="deleteNode(${nodeId})">🗑️ Delete</button>
                <button onclick="closeModal()">Close</button>
            </div>
        </div>
    `;
    
    document.body.appendChild(modal);
}

10. Deployment Status Tracking

What: Show real-time deployment progress

Implementation:

async function executeDeployment() {
    const deployButton = document.getElementById('deployButton');
    deployButton.textContent = 'Deploying...';
    deployButton.disabled = true;
    
    // Create progress tracker
    const progressDiv = document.createElement('div');
    progressDiv.className = 'deployment-progress';
    progressDiv.innerHTML = `
        <div class="progress-step active">📦 Building...</div>
        <div class="progress-step">🚀 Deploying...</div>
        <div class="progress-step">✅ Complete</div>
    `;
    document.querySelector('.vibe-deployment-panel').appendChild(progressDiv);
    
    // WebSocket for deployment events
    const deployWs = new WebSocket(`ws://${location.host}/ws/deployment`);
    
    deployWs.onmessage = (event) => {
        const data = JSON.parse(event.data);
        
        if (data.step === 'building') {
            updateProgressStep(0, 'active');
        } else if (data.step === 'deploying') {
            updateProgressStep(0, 'complete');
            updateProgressStep(1, 'active');
        } else if (data.step === 'complete') {
            updateProgressStep(1, 'complete');
            updateProgressStep(2, 'complete');
            
            vibeAddMsg('bot', `✅ Deployed to: ${data.url}`);
            deployButton.textContent = 'Deploy Now';
            deployButton.disabled = false;
        }
    };
    
    // Start deployment
    const response = await fetch('/api/deployment/deploy', {
        method: 'POST',
        headers: { 'Content-Type': 'application/json' },
        body: JSON.stringify(getDeploymentConfig())
    });
}

🔧 Backend API Requirements

# File Operations
GET    /api/vibe/files                  - List project files
GET    /api/vibe/file?path=...          - Get file content
POST   /api/vibe/file                   - Save file
DELETE /api/vibe/file?path=...          - Delete file

# Database
GET    /api/vibe/schema                 - Get database schema
POST   /api/vibe/schema/table           - Create table
POST   /api/vibe/schema/query           - Execute SQL query

# Git
GET    /api/vibe/git/status             - Get git status
POST   /api/vibe/git/commit             - Commit changes
POST   /api/vibe/git/push               - Push to remote

# Terminal
WS     /ws/terminal                     - Terminal WebSocket

# Deployment
POST   /api/deployment/deploy           - Deploy app
WS     /ws/deployment                   - Deployment progress

📊 Database Schema

-- Store canvas state
CREATE TABLE vibe_projects (
    id UUID PRIMARY KEY,
    user_id UUID NOT NULL,
    name VARCHAR(255),
    canvas_state JSONB,  -- nodes, connections
    files JSONB,         -- file tree
    created_at TIMESTAMP,
    updated_at TIMESTAMP
);

-- Track deployments
CREATE TABLE vibe_deployments (
    id UUID PRIMARY KEY,
    project_id UUID REFERENCES vibe_projects(id),
    target VARCHAR(50),  -- internal, external
    status VARCHAR(50),  -- building, deploying, complete, failed
    url TEXT,
    logs TEXT,
    deployed_at TIMESTAMP
);

Implementation Priority

Phase 1: Fix Broken Features (Week 1)

  1. Task node persistence
  2. Monaco editor integration
  3. Database schema viewer
  4. Terminal execution
  5. Git status display

Phase 2: Essential Features (Week 2)

  1. File tree navigation
  2. Keyboard shortcuts
  3. Command palette
  4. Node detail view
  5. Deployment tracking

Phase 3: Polish (Week 3)

  • Error handling
  • Loading states
  • Empty states
  • Responsive design
  • Performance optimization

🧪 Testing Checklist

  • Create new project
  • Add task nodes to canvas
  • Refresh page - nodes persist
  • Open file in editor
  • Edit and save file
  • View database schema
  • Execute terminal command
  • Check git status
  • Commit changes
  • Deploy app (internal)
  • Deploy app (external)
  • Use keyboard shortcuts
  • Search command palette

🎯 Success Metrics

  • Canvas state persists across sessions
  • Editor can open/edit/save files
  • All tool modals are functional
  • Deployment completes successfully
  • No console errors
  • Fast load time (< 2s)