Add Submit to Antigravity or Codex for Development modal with model picker and deep links

This commit is contained in:
airent106 committed 2026-10-29 22:30:48 -06:00
1 parent b5af03b628
commit 92c5039bcb
6 files changed
+752 -1

No files matched your search

+239
View File
@@ -1847,6 +1847,104 @@ function stageClipModalImage(dataUrl) {
}
}
const DEV_TARGETS = {
antigravity: {
id: "antigravity",
label: "🛸 Google Antigravity",
defaultModel: "gemini-3.1-pro",
models: [
{ id: "gemini-3.1-pro", label: "Gemini 3.1 Pro (Recommended — Full-Stack & Architecture)" },
{ id: "gemini-3.0-pro", label: "Gemini 3.0 Pro (Deep Reasoning & Complex Refactors)" },
{ id: "gemini-3.1-flash", label: "Gemini 3.1 Flash (Fast Iteration & UI Prototyping)" },
{ id: "gemini-3.1-flash-lite", label: "Gemini 3.1 Flash-Lite (Lightweight & Rapid Tasks)" },
{ id: "claude-sonnet-4.5", label: "Claude 4.5 Sonnet (via Antigravity Model Selector)" },
{ id: "claude-opus-4.5", label: "Claude 4.5 Opus (via Antigravity Model Selector)" }
]
},
codex: {
id: "codex",
label: "🤖 OpenAI Codex",
defaultModel: "gpt-5.6-sol",
models: [
{ id: "gpt-5.6-sol", label: "GPT-5.6-Sol (Recommended — Active Codex Default)" },
{ id: "gpt-5.3-codex", label: "GPT-5.3-Codex (Specialized Agentic Coding)" },
{ id: "gpt-5.4", label: "GPT-5.4 (Flagship Reasoning & Implementation)" },
{ id: "o3", label: "OpenAI o3 (Deep Architecture & Debugging)" },
{ id: "codex-mini-latest", label: "Codex Mini (Fast Lightweight Execution)" }
]
}
};
let activeDevTarget = "antigravity";
function populateDevModelOptions(targetApp) {
const meta = DEV_TARGETS[targetApp] || DEV_TARGETS.antigravity;
const sel = document.getElementById("dev-model-select");
if (!sel) return;
sel.innerHTML = meta.models
.map((m) => `<option value="${escapeHtml(m.id)}">${escapeHtml(m.label)}</option>`)
.join("");
sel.value = meta.defaultModel;
}
async function refreshDevSpecPreview() {
if (!state.activeIdeaId) return;
const model = document.getElementById("dev-model-select")?.value || "";
const includeHomelab = document.getElementById("dev-include-homelab")?.checked !== false;
const textarea = document.getElementById("dev-spec-preview-textarea");
if (!textarea) return;
const params = new URLSearchParams({
target: activeDevTarget,
model,
includeHomelab: String(includeHomelab)
});
try {
const res = await fetch(`/api/ideas/${state.activeIdeaId}/spec.md?${params.toString()}`);
if (res.ok) {
textarea.value = await res.text();
}
} catch (err) {
console.warn("Failed to load spec preview:", err);
}
}
async function openDevHandoffModal(defaultTarget = "antigravity") {
if (!state.activeIdeaId || !state.activeIdea) return;
activeDevTarget = defaultTarget;
const modal = document.getElementById("dev-handoff-modal");
if (!modal) return;
document.querySelectorAll("#dev-target-pills [data-dev-target]").forEach((btn) => {
btn.classList.toggle("active", btn.dataset.devTarget === activeDevTarget);
});
populateDevModelOptions(activeDevTarget);
const serverCodexWrap = document.getElementById("dev-server-codex-wrap");
if (serverCodexWrap) {
serverCodexWrap.classList.toggle("hidden", activeDevTarget !== "codex");
}
const submitBtn = document.getElementById("btn-submit-dev-handoff");
if (submitBtn) {
submitBtn.textContent =
activeDevTarget === "codex"
? "🚀 Submit & Open in OpenAI Codex"
: "🚀 Submit & Launch in Antigravity";
}
const homelabCb = document.getElementById("dev-include-homelab");
if (homelabCb) {
homelabCb.checked = state.activeIdea.category === "project" || !isCurrentProductTShirt();
}
document.getElementById("dev-handoff-result-box")?.classList.add("hidden");
modal.classList.remove("hidden");
await refreshDevSpecPreview();
}
function openExternalClipModal({ ideaId = null, prefillTitle = "", prefillText = "", prefillUrl = "" } = {}) {
const modal = document.getElementById("external-clip-modal");
const targetSel = document.getElementById("clip-target-idea");
@@ -1921,6 +2019,7 @@ function bindGlobalEvents() {
} else if (e.key === "Escape") {
document.getElementById("lightbox-modal")?.classList.add("hidden");
document.getElementById("settings-modal")?.classList.add("hidden");
document.getElementById("dev-handoff-modal")?.classList.add("hidden");
closeIdeaDrawer();
}
});
@@ -2681,6 +2780,146 @@ function bindGlobalEvents() {
}
});
// --- SUBMIT TO ANTIGRAVITY OR CODEX FOR DEVELOPMENT EVENTS ---
document.getElementById("btn-open-dev-handoff")?.addEventListener("click", () => {
openDevHandoffModal(activeDevTarget || "antigravity");
});
document.getElementById("btn-close-dev-modal")?.addEventListener("click", () => {
document.getElementById("dev-handoff-modal")?.classList.add("hidden");
});
document.getElementById("btn-cancel-dev-modal")?.addEventListener("click", () => {
document.getElementById("dev-handoff-modal")?.classList.add("hidden");
});
document.querySelectorAll("#dev-target-pills [data-dev-target]").forEach((btn) => {
btn.addEventListener("click", async () => {
activeDevTarget = btn.dataset.devTarget;
document.querySelectorAll("#dev-target-pills [data-dev-target]").forEach((b) =>
b.classList.toggle("active", b === btn)
);
populateDevModelOptions(activeDevTarget);
document.getElementById("dev-server-codex-wrap")?.classList.toggle("hidden", activeDevTarget !== "codex");
const submitBtn = document.getElementById("btn-submit-dev-handoff");
if (submitBtn) {
submitBtn.textContent =
activeDevTarget === "codex"
? "🚀 Submit & Open in OpenAI Codex"
: "🚀 Submit & Launch in Antigravity";
}
await refreshDevSpecPreview();
});
});
document.getElementById("dev-model-select")?.addEventListener("change", refreshDevSpecPreview);
document.getElementById("dev-include-homelab")?.addEventListener("change", refreshDevSpecPreview);
document.getElementById("btn-copy-dev-spec")?.addEventListener("click", async () => {
const text = document.getElementById("dev-spec-preview-textarea")?.value || "";
if (!text) return;
await navigator.clipboard.writeText(text);
showToast("📋 Copied full development specification to clipboard!");
});
document.getElementById("btn-download-dev-spec")?.addEventListener("click", () => {
if (!state.activeIdeaId) return;
const model = document.getElementById("dev-model-select")?.value || "";
const includeHomelab = document.getElementById("dev-include-homelab")?.checked !== false;
window.open(
`/api/ideas/${state.activeIdeaId}/spec.md?target=${encodeURIComponent(activeDevTarget)}&model=${encodeURIComponent(model)}&includeHomelab=${includeHomelab}`,
"_blank"
);
});
document.getElementById("dev-handoff-form")?.addEventListener("submit", async (e) => {
e.preventDefault();
if (!state.activeIdeaId) return;
const submitBtn = document.getElementById("btn-submit-dev-handoff");
const resultBox = document.getElementById("dev-handoff-result-box");
const model = document.getElementById("dev-model-select")?.value || "";
const customPrompt = document.getElementById("dev-spec-preview-textarea")?.value || "";
const includeHomelab = document.getElementById("dev-include-homelab")?.checked !== false;
const moveStatusToBuilding = document.getElementById("dev-move-building")?.checked !== false;
const executeServerCodex =
activeDevTarget === "codex" && Boolean(document.getElementById("dev-run-server-codex")?.checked);
if (submitBtn) {
submitBtn.disabled = true;
submitBtn.textContent = executeServerCodex
? "🤖 Running Codex Blueprint & Submitting..."
: "🚀 Packaging & Launching...";
}
try {
// 1. Copy full specification to clipboard so it's immediately ready to paste (Ctrl+V) in Antigravity or Codex
try {
await navigator.clipboard.writeText(customPrompt);
} catch {
// Ignore clipboard permission errors if non-HTTPS context
}
// 2. Persist handoff package & workspace on server
const res = await apiFetch(`/api/ideas/${state.activeIdeaId}/dev-handoff`, {
method: "POST",
body: JSON.stringify({
targetApp: activeDevTarget,
model,
customPrompt,
includeHomelab,
moveStatusToBuilding,
executeServerCodex
})
});
state.activeIdea = res.idea;
const handoff = res.handoff;
if (resultBox) {
resultBox.classList.remove("hidden");
resultBox.innerHTML = `
<div style="display:flex;justify-content:space-between;align-items:center;flex-wrap:wrap;gap:0.5rem;">
<strong>✅ Ready in ${escapeHtml(handoff.targetLabel)} (${escapeHtml(handoff.model)})</strong>
<div style="display:flex;gap:0.4rem;">
<a href="${escapeHtml(handoff.deepLinkUrl)}" class="btn btn-primary btn-xs">
🚀 Open ${activeDevTarget === "codex" ? "Codex App" : "Antigravity App"}
</a>
<a href="${escapeHtml(handoff.specUrl)}" target="_blank" rel="noopener noreferrer" class="btn btn-ghost btn-xs">
📄 View SPEC.md
</a>
</div>
</div>
<p class="muted-label" style="margin-top:0.25rem;">
Full specification has been <strong>copied to your clipboard (<kbd>Ctrl+V</kbd>)</strong> and saved to server workspace <code>${escapeHtml(handoff.slug)}</code>.
</p>
${
handoff.codexExecution?.output
? `<pre style="max-height:160px;overflow:auto;background:var(--bg-base);padding:0.5rem;border-radius:6px;font-size:0.75rem;white-space:pre-wrap;margin-top:0.35rem;">${escapeHtml(handoff.codexExecution.output)}</pre>`
: ""
}
`;
}
showToast(`🚀 Copied full spec & launching ${handoff.targetLabel} (${handoff.model})!`);
await loadIdeas();
renderDrawerContent();
// 3. Trigger the OS deep link to open Antigravity or Codex Desktop App
if (handoff.deepLinkUrl) {
window.location.href = handoff.deepLinkUrl;
}
} catch (err) {
showToast(`⚠️ ${err.message}`);
} finally {
if (submitBtn) {
submitBtn.disabled = false;
submitBtn.textContent =
activeDevTarget === "codex"
? "🚀 Submit & Open in OpenAI Codex"
: "🚀 Submit & Launch in Antigravity";
}
}
});
// Global Clipboard Paste (Ctrl+V) for screenshots & copied images
window.addEventListener("paste", async (e) => {
const items = e.clipboardData?.items;
+72
View File
@@ -376,6 +376,9 @@
</div>
</div>
<div class="drawer-header-actions">
<button type="button" id="btn-open-dev-handoff" class="btn btn-primary btn-sm" title="Submit all Spark info, specs, and mockups to Antigravity or OpenAI Codex for development">
🚀 Send to Dev
</button>
<button type="button" id="drawer-delete-btn" class="btn btn-danger-ghost btn-sm" title="Delete Idea">🗑️</button>
<button type="button" id="drawer-close-btn" class="btn btn-ghost btn-sm" title="Close (Esc)">✕ Close</button>
</div>
@@ -874,6 +877,75 @@
</div>
</div>
<!-- MODAL: SUBMIT SPARK TO ANTIGRAVITY OR CODEX FOR DEVELOPMENT -->
<div id="dev-handoff-modal" class="modal-backdrop hidden">
<div class="modal-card modal-card-wide">
<div class="modal-header">
<h3>🚀 Submit Spark for Development</h3>
<button type="button" id="btn-close-dev-modal" class="btn btn-ghost btn-sm">✕</button>
</div>
<form id="dev-handoff-form" class="modal-body">
<p class="muted-label">
Packages all Spark information (title, pitch, markdown specs, checklist, pros/cons, reference links, and mockup/attachment URLs) and sends it to <strong>Antigravity</strong> or <strong>OpenAI Codex</strong>.
</p>
<div class="form-row-2">
<div class="field-group">
<label>1. Target Coding App</label>
<div class="dev-target-pills" id="dev-target-pills">
<button type="button" class="pill-btn active" data-dev-target="antigravity">
🛸 Google Antigravity
</button>
<button type="button" class="pill-btn" data-dev-target="codex">
🤖 OpenAI Codex
</button>
</div>
</div>
<div class="field-group">
<label for="dev-model-select">2. Select AI Model</label>
<select id="dev-model-select" class="filter-select full-width"></select>
</div>
</div>
<div class="dev-options-row">
<label class="filter-checkbox">
<input type="checkbox" id="dev-include-homelab" checked />
<span>Include Homelab Stack Spec (vloser Docker + Gitea + Traefik + Homepage)</span>
</label>
<label class="filter-checkbox">
<input type="checkbox" id="dev-move-building" checked />
<span>Move Spark to 🛠️ Building stage</span>
</label>
<label class="filter-checkbox hidden" id="dev-server-codex-wrap">
<input type="checkbox" id="dev-run-server-codex" />
<span>⚡ Also run autonomous Codex blueprint on server</span>
</label>
</div>
<div class="field-group">
<div class="field-header-row">
<label for="dev-spec-preview-textarea">3. Complete Development Specification Payload (Editable)</label>
<div style="display:flex;gap:0.35rem;">
<button type="button" id="btn-copy-dev-spec" class="btn btn-ghost btn-xs">📋 Copy Prompt</button>
<button type="button" id="btn-download-dev-spec" class="btn btn-ghost btn-xs">⬇️ Download SPEC.md</button>
</div>
</div>
<textarea id="dev-spec-preview-textarea" rows="11" class="textarea-input dev-spec-textarea"></textarea>
</div>
<div id="dev-handoff-result-box" class="nb-edit-box hidden"></div>
<div class="modal-footer">
<button type="button" id="btn-cancel-dev-modal" class="btn btn-ghost">Cancel</button>
<button type="submit" id="btn-submit-dev-handoff" class="btn btn-primary">
🚀 Submit & Launch in Antigravity
</button>
</div>
</form>
</div>
</div>
<!-- MODAL: CARD / MOCKUP LIGHTBOX INSPECTOR -->
<div id="lightbox-modal" class="modal-backdrop hidden">
<div class="lightbox-card">
+29
View File
@@ -1445,6 +1445,35 @@ body {
width: min(680px, 95vw);
}
.modal-card-wide {
width: min(760px, 95vw);
max-height: 92vh;
display: flex;
flex-direction: column;
}
.modal-card-wide .modal-body {
overflow-y: auto;
}
.dev-target-pills {
display: flex;
gap: 0.45rem;
flex-wrap: wrap;
}
.dev-options-row {
display: flex;
gap: 0.65rem;
flex-wrap: wrap;
}
.dev-spec-textarea {
font-family: ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, monospace;
font-size: 0.78rem;
line-height: 1.45;
}
.modal-header {
padding: 0.9rem 1.15rem;
border-bottom: 1px solid var(--border-color);