2026-02-26 12:40:44 -03:00
|
|
|
<!-- Vibe Window — APP_CREATE Canvas + Agents IDE (Phase 7) -->
|
|
|
|
|
<link rel="stylesheet" href="/suite/vibe/agents-sidebar.css" />
|
|
|
|
|
|
|
|
|
|
<div class="vibe-container" id="vibeWindow">
|
|
|
|
|
<!-- Pipeline Tabs -->
|
|
|
|
|
<div class="vibe-pipeline">
|
|
|
|
|
<button class="vibe-pipeline-tab" data-stage="plan">// PLAN</button>
|
|
|
|
|
<button class="vibe-pipeline-tab active" data-stage="build">// BUILD</button>
|
|
|
|
|
<button class="vibe-pipeline-tab" data-stage="review">// REVIEW</button>
|
|
|
|
|
<button class="vibe-pipeline-tab" data-stage="deploy">// DEPLOY</button>
|
|
|
|
|
<button class="vibe-pipeline-tab" data-stage="monitor">// MONITOR</button>
|
2026-02-24 19:02:48 -03:00
|
|
|
</div>
|
|
|
|
|
|
2026-02-26 12:40:44 -03:00
|
|
|
<!-- Main Content: Canvas + Sidebar -->
|
|
|
|
|
<div class="vibe-body">
|
|
|
|
|
<!-- Canvas Area -->
|
|
|
|
|
<div class="vibe-canvas" id="vibeCanvas">
|
|
|
|
|
<div class="vibe-canvas-empty" id="vibeCanvasEmpty">
|
|
|
|
|
<div class="vibe-canvas-icon">🎨</div>
|
|
|
|
|
<h3>Vibe — App Builder</h3>
|
|
|
|
|
<p>Describe what you want to build. An agent will generate the entire application.</p>
|
|
|
|
|
<div class="vibe-canvas-prompt">
|
|
|
|
|
<input type="text" class="vibe-prompt-input" id="vibePromptInput"
|
|
|
|
|
placeholder="e.g. 'Create a CRM for my clinic'" />
|
|
|
|
|
<button class="vibe-prompt-btn" id="vibePromptBtn" type="button">Build</button>
|
|
|
|
|
</div>
|
|
|
|
|
</div>
|
|
|
|
|
|
|
|
|
|
<!-- Generated Steps (populated dynamically) -->
|
|
|
|
|
<div class="vibe-steps" id="vibeSteps" style="display:none;"></div>
|
2026-02-24 19:02:48 -03:00
|
|
|
|
2026-02-26 12:40:44 -03:00
|
|
|
<!-- Preview Panel -->
|
|
|
|
|
<div class="vibe-preview" id="vibePreview" style="display:none;">
|
|
|
|
|
<div class="vibe-preview-header">
|
|
|
|
|
<span>// PREVIEW</span>
|
|
|
|
|
<input type="text" class="vibe-preview-url" id="vibePreviewUrl" value="" readonly />
|
|
|
|
|
</div>
|
|
|
|
|
<div class="vibe-preview-content" id="vibePreviewContent"></div>
|
2026-02-24 19:02:48 -03:00
|
|
|
</div>
|
|
|
|
|
</div>
|
|
|
|
|
|
2026-02-26 12:40:44 -03:00
|
|
|
<!-- Agents & Workspaces Sidebar (collapsible) -->
|
|
|
|
|
<aside class="agents-sidebar" id="agentsSidebar">
|
|
|
|
|
<div class="as-section">
|
|
|
|
|
<div class="as-section-header">
|
|
|
|
|
<h3>Agents</h3>
|
|
|
|
|
<button class="as-collapse-btn" id="agentsSidebarCollapse" type="button">◀</button>
|
|
|
|
|
</div>
|
|
|
|
|
|
|
|
|
|
<div class="as-agent-list" id="asAgentList">
|
|
|
|
|
<div class="as-agent-empty">
|
|
|
|
|
<p style="padding: 1rem; text-align: center; color: var(--text-tertiary); font-size: 0.8rem;">
|
|
|
|
|
No active agents attached.<br><br>
|
|
|
|
|
Click "Build" and BotServer will automatically attach necessary agents (Architect,
|
|
|
|
|
Fullstack, DBA) to your workspace.
|
|
|
|
|
</p>
|
|
|
|
|
</div>
|
|
|
|
|
</div>
|
|
|
|
|
|
|
|
|
|
<button class="as-create-btn" id="createAgentBtn" type="button">+ Create a New Agent</button>
|
|
|
|
|
</div>
|
|
|
|
|
|
|
|
|
|
<div class="as-section">
|
|
|
|
|
<div class="as-section-header">
|
|
|
|
|
<h3>Workspaces</h3>
|
|
|
|
|
</div>
|
|
|
|
|
|
|
|
|
|
<div class="as-workspace-list" id="asWorkspaceList">
|
|
|
|
|
<div class="as-workspace-item">
|
|
|
|
|
<button class="as-workspace-toggle" type="button">
|
|
|
|
|
<span class="as-workspace-arrow">▶</span>
|
|
|
|
|
<span>Production</span>
|
|
|
|
|
<span class="as-workspace-count">2</span>
|
|
|
|
|
</button>
|
|
|
|
|
<div class="as-workspace-body" style="display:none;">
|
|
|
|
|
<div class="as-workspace-agent">Agent #1</div>
|
|
|
|
|
<div class="as-workspace-agent">Agent #2</div>
|
|
|
|
|
<div class="as-workspace-dropzone" data-workspace="production">
|
|
|
|
|
Drag an Agent to Include
|
|
|
|
|
</div>
|
|
|
|
|
</div>
|
|
|
|
|
</div>
|
|
|
|
|
|
|
|
|
|
<div class="as-workspace-item">
|
|
|
|
|
<button class="as-workspace-toggle" type="button">
|
|
|
|
|
<span class="as-workspace-arrow">▶</span>
|
|
|
|
|
<span>Staging</span>
|
|
|
|
|
<span class="as-workspace-count">0</span>
|
|
|
|
|
</button>
|
|
|
|
|
<div class="as-workspace-body" style="display:none;">
|
|
|
|
|
<div class="as-workspace-dropzone" data-workspace="staging">
|
|
|
|
|
Drag an Agent to Include
|
|
|
|
|
</div>
|
|
|
|
|
</div>
|
|
|
|
|
</div>
|
|
|
|
|
</div>
|
|
|
|
|
</div>
|
|
|
|
|
</aside>
|
2026-02-24 19:02:48 -03:00
|
|
|
</div>
|
|
|
|
|
</div>
|
|
|
|
|
|
|
|
|
|
<script>
|
|
|
|
|
(function () {
|
|
|
|
|
"use strict";
|
|
|
|
|
|
2026-02-26 12:40:44 -03:00
|
|
|
function initVibe() {
|
|
|
|
|
setupPipelineTabs();
|
|
|
|
|
setupPrompt();
|
|
|
|
|
setupSidebarCollapse();
|
|
|
|
|
setupWorkspaceAccordions();
|
|
|
|
|
setupDragAndDrop();
|
2026-02-24 19:02:48 -03:00
|
|
|
}
|
|
|
|
|
|
2026-02-26 12:40:44 -03:00
|
|
|
function setupPipelineTabs() {
|
|
|
|
|
var container = document.querySelector(".vibe-pipeline");
|
|
|
|
|
if (!container) return;
|
2026-02-24 19:02:48 -03:00
|
|
|
|
2026-02-26 12:40:44 -03:00
|
|
|
container.addEventListener("click", function (e) {
|
|
|
|
|
var tab = e.target.closest(".vibe-pipeline-tab");
|
|
|
|
|
if (!tab) return;
|
|
|
|
|
container.querySelectorAll(".vibe-pipeline-tab").forEach(function (t) {
|
|
|
|
|
t.classList.remove("active");
|
2026-02-24 19:02:48 -03:00
|
|
|
});
|
2026-02-26 12:40:44 -03:00
|
|
|
tab.classList.add("active");
|
2026-02-24 19:02:48 -03:00
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
|
2026-02-26 12:40:44 -03:00
|
|
|
function setupPrompt() {
|
|
|
|
|
var input = document.getElementById("vibePromptInput");
|
|
|
|
|
var btn = document.getElementById("vibePromptBtn");
|
|
|
|
|
if (!input || !btn) return;
|
2026-02-24 19:02:48 -03:00
|
|
|
|
2026-02-26 12:40:44 -03:00
|
|
|
function submit() {
|
|
|
|
|
var text = input.value.trim();
|
|
|
|
|
if (!text) return;
|
2026-02-24 19:02:48 -03:00
|
|
|
|
2026-02-26 12:40:44 -03:00
|
|
|
btn.disabled = true;
|
|
|
|
|
btn.textContent = "Building...";
|
2026-02-24 19:02:48 -03:00
|
|
|
|
2026-02-26 12:40:44 -03:00
|
|
|
fetch("/api/autotask/classify", {
|
|
|
|
|
method: "POST",
|
|
|
|
|
headers: { "Content-Type": "application/json" },
|
|
|
|
|
body: JSON.stringify({ intent: text })
|
2026-02-24 19:02:48 -03:00
|
|
|
})
|
2026-02-26 12:40:44 -03:00
|
|
|
.then(function (r) { return r.json(); })
|
|
|
|
|
.then(function (data) {
|
|
|
|
|
btn.disabled = false;
|
|
|
|
|
btn.textContent = "Build";
|
|
|
|
|
if (data.result && data.result.app_url) {
|
|
|
|
|
showPreview(data.result.app_url);
|
|
|
|
|
} else if (data.app_url) {
|
|
|
|
|
showPreview(data.app_url);
|
|
|
|
|
} else if (data.error) {
|
|
|
|
|
alert("Error: " + data.error);
|
|
|
|
|
}
|
|
|
|
|
})
|
|
|
|
|
.catch(function () {
|
|
|
|
|
btn.disabled = false;
|
|
|
|
|
btn.textContent = "Build";
|
2026-02-24 19:02:48 -03:00
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
|
2026-02-26 12:40:44 -03:00
|
|
|
btn.addEventListener("click", submit);
|
|
|
|
|
input.addEventListener("keydown", function (e) {
|
|
|
|
|
if (e.key === "Enter") { e.preventDefault(); submit(); }
|
2026-02-24 19:02:48 -03:00
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
|
2026-02-26 12:40:44 -03:00
|
|
|
function showPreview(url) {
|
|
|
|
|
var preview = document.getElementById("vibePreview");
|
|
|
|
|
var urlBar = document.getElementById("vibePreviewUrl");
|
|
|
|
|
var content = document.getElementById("vibePreviewContent");
|
|
|
|
|
var empty = document.getElementById("vibeCanvasEmpty");
|
2026-02-24 19:02:48 -03:00
|
|
|
|
2026-02-26 12:40:44 -03:00
|
|
|
if (empty) empty.style.display = "none";
|
|
|
|
|
if (preview) preview.style.display = "";
|
|
|
|
|
if (urlBar) urlBar.value = url;
|
|
|
|
|
if (content) content.innerHTML = '<iframe src="' + url + '"></iframe>';
|
2026-02-24 19:02:48 -03:00
|
|
|
}
|
|
|
|
|
|
2026-02-26 12:40:44 -03:00
|
|
|
function setupSidebarCollapse() {
|
|
|
|
|
var btn = document.getElementById("agentsSidebarCollapse");
|
|
|
|
|
var sidebar = document.getElementById("agentsSidebar");
|
|
|
|
|
if (!btn || !sidebar) return;
|
2026-02-24 19:02:48 -03:00
|
|
|
|
2026-02-26 12:40:44 -03:00
|
|
|
btn.addEventListener("click", function () {
|
|
|
|
|
sidebar.classList.toggle("collapsed");
|
|
|
|
|
btn.textContent = sidebar.classList.contains("collapsed") ? "▶" : "◀";
|
2026-02-24 19:02:48 -03:00
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
|
2026-02-26 12:40:44 -03:00
|
|
|
function setupWorkspaceAccordions() {
|
|
|
|
|
var toggles = document.querySelectorAll(".as-workspace-toggle");
|
|
|
|
|
toggles.forEach(function (toggle) {
|
|
|
|
|
toggle.addEventListener("click", function () {
|
|
|
|
|
var body = this.nextElementSibling;
|
|
|
|
|
var arrow = this.querySelector(".as-workspace-arrow");
|
|
|
|
|
if (body) {
|
|
|
|
|
var isOpen = body.style.display !== "none";
|
|
|
|
|
body.style.display = isOpen ? "none" : "";
|
|
|
|
|
if (arrow) arrow.textContent = isOpen ? "▶" : "▼";
|
2026-02-25 10:15:47 -03:00
|
|
|
}
|
2026-02-24 19:02:48 -03:00
|
|
|
});
|
2026-02-26 12:40:44 -03:00
|
|
|
});
|
2026-02-24 19:02:48 -03:00
|
|
|
}
|
|
|
|
|
|
2026-02-26 12:40:44 -03:00
|
|
|
function setupDragAndDrop() {
|
|
|
|
|
var cards = document.querySelectorAll(".as-agent-card");
|
|
|
|
|
cards.forEach(function (card) {
|
|
|
|
|
card.addEventListener("dragstart", function (e) {
|
|
|
|
|
e.dataTransfer.setData("text/plain", card.getAttribute("data-agent-id"));
|
|
|
|
|
card.classList.add("dragging");
|
2026-02-24 19:02:48 -03:00
|
|
|
});
|
2026-02-26 12:40:44 -03:00
|
|
|
card.addEventListener("dragend", function () {
|
|
|
|
|
card.classList.remove("dragging");
|
|
|
|
|
});
|
|
|
|
|
});
|
2026-02-24 19:02:48 -03:00
|
|
|
|
2026-02-26 12:40:44 -03:00
|
|
|
var dropzones = document.querySelectorAll(".as-workspace-dropzone");
|
|
|
|
|
dropzones.forEach(function (zone) {
|
|
|
|
|
zone.addEventListener("dragover", function (e) {
|
2026-02-24 19:02:48 -03:00
|
|
|
e.preventDefault();
|
2026-02-26 12:40:44 -03:00
|
|
|
zone.classList.add("drag-over");
|
|
|
|
|
});
|
|
|
|
|
zone.addEventListener("dragleave", function () {
|
|
|
|
|
zone.classList.remove("drag-over");
|
|
|
|
|
});
|
|
|
|
|
zone.addEventListener("drop", function (e) {
|
2026-02-24 19:02:48 -03:00
|
|
|
e.preventDefault();
|
2026-02-26 12:40:44 -03:00
|
|
|
zone.classList.remove("drag-over");
|
|
|
|
|
var agentId = e.dataTransfer.getData("text/plain");
|
2026-02-24 19:02:48 -03:00
|
|
|
|
2026-02-26 12:40:44 -03:00
|
|
|
var agentEl = document.createElement("div");
|
|
|
|
|
agentEl.className = "as-workspace-agent";
|
|
|
|
|
agentEl.textContent = "Agent #" + agentId;
|
|
|
|
|
zone.parentNode.insertBefore(agentEl, zone);
|
|
|
|
|
});
|
2026-02-24 19:02:48 -03:00
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
|
2026-02-26 12:40:44 -03:00
|
|
|
if (document.readyState === "loading") {
|
|
|
|
|
document.addEventListener("DOMContentLoaded", initVibe);
|
|
|
|
|
} else {
|
|
|
|
|
initVibe();
|
|
|
|
|
}
|
2026-02-24 19:02:48 -03:00
|
|
|
})();
|
|
|
|
|
</script>
|