Some checks failed
BotServer CI / build (push) Failing after 13s
523 lines
15 KiB
Markdown
523 lines
15 KiB
Markdown
# 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:**
|
|
```javascript
|
|
// 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:**
|
|
```html
|
|
<!-- 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:**
|
|
```javascript
|
|
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:**
|
|
```javascript
|
|
// 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:**
|
|
```javascript
|
|
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:**
|
|
```html
|
|
<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:**
|
|
```javascript
|
|
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:**
|
|
```html
|
|
<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:**
|
|
```javascript
|
|
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:**
|
|
```javascript
|
|
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
|
|
|
|
```sql
|
|
-- 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)
|
|
6. ✅ File tree navigation
|
|
7. ✅ Keyboard shortcuts
|
|
8. ✅ Command palette
|
|
9. ✅ Node detail view
|
|
10. ✅ 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)
|