vibespot 1.1.0 → 1.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +103 -33
- package/README.md +11 -1
- package/assets/plan-templates/agency-services.md +42 -0
- package/assets/plan-templates/blog-content-hub.md +41 -0
- package/assets/plan-templates/ecommerce-product.md +42 -0
- package/assets/plan-templates/event-registration.md +42 -0
- package/assets/plan-templates/portfolio.md +41 -0
- package/assets/plan-templates/restaurant.md +42 -0
- package/assets/plan-templates/saas-landing.md +42 -0
- package/dist/index.js +259 -228
- package/dist/index.js.map +1 -1
- package/package.json +8 -4
- package/starters/01-saas-landing.json +43 -0
- package/starters/02-portfolio.json +39 -0
- package/starters/03-restaurant.json +39 -0
- package/starters/04-event.json +39 -0
- package/starters/05-coming-soon.json +32 -0
- package/ui/chat.js +865 -130
- package/ui/dashboard.js +194 -12
- package/ui/docs/index.html +89 -10
- package/ui/field-editor.js +1 -1
- package/ui/index.html +156 -37
- package/ui/marketplace.js +218 -0
- package/ui/plan.js +0 -0
- package/ui/preview.js +316 -1
- package/ui/settings.js +35 -21
- package/ui/setup.js +291 -3
- package/ui/styles.css +1305 -120
package/ui/preview.js
CHANGED
|
@@ -4,10 +4,39 @@
|
|
|
4
4
|
|
|
5
5
|
const previewFrame = document.getElementById("preview-frame");
|
|
6
6
|
|
|
7
|
+
// Highlights to apply once the iframe finishes loading after the next refresh.
|
|
8
|
+
let pendingChangedModules = null;
|
|
9
|
+
let pendingNewModules = null;
|
|
10
|
+
|
|
11
|
+
previewFrame.addEventListener("load", () => {
|
|
12
|
+
if (!pendingChangedModules && !pendingNewModules) return;
|
|
13
|
+
const changed = pendingChangedModules;
|
|
14
|
+
const fresh = pendingNewModules;
|
|
15
|
+
pendingChangedModules = null;
|
|
16
|
+
pendingNewModules = null;
|
|
17
|
+
try {
|
|
18
|
+
const doc = previewFrame.contentDocument || previewFrame.contentWindow.document;
|
|
19
|
+
if (!doc || !doc.body) return;
|
|
20
|
+
ensureChangeHighlightStyles(doc);
|
|
21
|
+
if (fresh && fresh.length) animateNewModules(doc, fresh);
|
|
22
|
+
if (changed && changed.length) highlightChangedModules(doc, changed, fresh || []);
|
|
23
|
+
} catch {
|
|
24
|
+
// cross-origin — skip
|
|
25
|
+
}
|
|
26
|
+
});
|
|
27
|
+
|
|
7
28
|
/**
|
|
8
29
|
* Refresh the preview iframe by reloading from /preview endpoint.
|
|
30
|
+
*
|
|
31
|
+
* @param {Object} [opts]
|
|
32
|
+
* @param {string[]} [opts.changedModules] Module names that were just regenerated.
|
|
33
|
+
* @param {string[]} [opts.newModules] Subset of changedModules that are first-time additions.
|
|
9
34
|
*/
|
|
10
|
-
function refreshPreview() {
|
|
35
|
+
function refreshPreview(opts) {
|
|
36
|
+
if (opts && (opts.changedModules || opts.newModules)) {
|
|
37
|
+
pendingChangedModules = opts.changedModules || null;
|
|
38
|
+
pendingNewModules = opts.newModules || null;
|
|
39
|
+
}
|
|
11
40
|
// Use srcdoc approach: fetch preview HTML and set as srcdoc
|
|
12
41
|
// This avoids cache issues and allows the iframe to update smoothly
|
|
13
42
|
fetch("/preview")
|
|
@@ -20,6 +49,79 @@ function refreshPreview() {
|
|
|
20
49
|
});
|
|
21
50
|
}
|
|
22
51
|
|
|
52
|
+
// ---------------------------------------------------------------------------
|
|
53
|
+
// Change highlighting — outline glow on regenerated modules and slide-in for
|
|
54
|
+
// brand-new modules. Styles are injected into the sandboxed preview iframe.
|
|
55
|
+
// ---------------------------------------------------------------------------
|
|
56
|
+
|
|
57
|
+
function ensureChangeHighlightStyles(doc) {
|
|
58
|
+
if (doc.getElementById("vibespot-change-highlight-css")) return;
|
|
59
|
+
const style = doc.createElement("style");
|
|
60
|
+
style.id = "vibespot-change-highlight-css";
|
|
61
|
+
style.textContent = `
|
|
62
|
+
@keyframes vibespot-change-glow {
|
|
63
|
+
0% { outline-color: rgba(232, 97, 58, 0.85); box-shadow: 0 0 0 6px rgba(232, 97, 58, 0.18); }
|
|
64
|
+
70% { outline-color: rgba(232, 97, 58, 0.55); box-shadow: 0 0 0 4px rgba(232, 97, 58, 0.10); }
|
|
65
|
+
100% { outline-color: rgba(232, 97, 58, 0); box-shadow: 0 0 0 0 rgba(232, 97, 58, 0); }
|
|
66
|
+
}
|
|
67
|
+
.vibespot-module--changed {
|
|
68
|
+
outline: 2px solid rgba(232, 97, 58, 0.85);
|
|
69
|
+
outline-offset: 4px;
|
|
70
|
+
border-radius: 2px;
|
|
71
|
+
animation: vibespot-change-glow 2s ease-out forwards;
|
|
72
|
+
}
|
|
73
|
+
@keyframes vibespot-module-slide-in {
|
|
74
|
+
0% { opacity: 0; transform: translateY(24px); }
|
|
75
|
+
100% { opacity: 1; transform: translateY(0); }
|
|
76
|
+
}
|
|
77
|
+
.vibespot-module--new {
|
|
78
|
+
animation: vibespot-module-slide-in 0.6s cubic-bezier(0.2, 0.8, 0.2, 1) both;
|
|
79
|
+
}
|
|
80
|
+
@media (prefers-reduced-motion: reduce) {
|
|
81
|
+
.vibespot-module--changed,
|
|
82
|
+
.vibespot-module--new { animation: none; }
|
|
83
|
+
.vibespot-module--changed { outline-color: transparent; }
|
|
84
|
+
}
|
|
85
|
+
`;
|
|
86
|
+
doc.head.appendChild(style);
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
function highlightChangedModules(doc, moduleNames, newModuleNames) {
|
|
90
|
+
// Skip modules that are already getting the slide-in animation — the slide-in
|
|
91
|
+
// is a stronger signal on its own.
|
|
92
|
+
const newSet = new Set(newModuleNames);
|
|
93
|
+
for (const name of moduleNames) {
|
|
94
|
+
if (newSet.has(name)) continue;
|
|
95
|
+
const el = doc.querySelector(`[data-module="${cssEscape(name)}"]`);
|
|
96
|
+
if (!el) continue;
|
|
97
|
+
el.classList.remove("vibespot-module--changed");
|
|
98
|
+
// Force a reflow so the animation restarts if the class was just removed.
|
|
99
|
+
void el.offsetWidth;
|
|
100
|
+
el.classList.add("vibespot-module--changed");
|
|
101
|
+
setTimeout(() => {
|
|
102
|
+
el.classList.remove("vibespot-module--changed");
|
|
103
|
+
}, 2200);
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
function animateNewModules(doc, moduleNames) {
|
|
108
|
+
for (const name of moduleNames) {
|
|
109
|
+
const el = doc.querySelector(`[data-module="${cssEscape(name)}"]`);
|
|
110
|
+
if (!el) continue;
|
|
111
|
+
el.classList.add("vibespot-module--new");
|
|
112
|
+
setTimeout(() => {
|
|
113
|
+
el.classList.remove("vibespot-module--new");
|
|
114
|
+
}, 700);
|
|
115
|
+
}
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
function cssEscape(value) {
|
|
119
|
+
if (typeof CSS !== "undefined" && typeof CSS.escape === "function") {
|
|
120
|
+
return CSS.escape(value);
|
|
121
|
+
}
|
|
122
|
+
return String(value).replace(/["\\]/g, "\\$&");
|
|
123
|
+
}
|
|
124
|
+
|
|
23
125
|
/**
|
|
24
126
|
* Scroll the preview iframe to a specific module by name.
|
|
25
127
|
*/
|
|
@@ -278,3 +380,216 @@ function clearAllModulesWorking() {
|
|
|
278
380
|
|
|
279
381
|
// Preview refresh is triggered by setup.js after a session is created.
|
|
280
382
|
// Do NOT auto-refresh here.
|
|
383
|
+
|
|
384
|
+
// ---------------------------------------------------------------------------
|
|
385
|
+
// Select mode — click an element in the preview to reference it in chat
|
|
386
|
+
// ---------------------------------------------------------------------------
|
|
387
|
+
|
|
388
|
+
const selectModeBtn = document.getElementById("select-mode-toggle");
|
|
389
|
+
const previewContainer = document.getElementById("preview-container");
|
|
390
|
+
|
|
391
|
+
let selectModeActive = false;
|
|
392
|
+
let hoveredEl = null;
|
|
393
|
+
let hoverLabelEl = null;
|
|
394
|
+
let onMouseOver = null;
|
|
395
|
+
let onMouseOut = null;
|
|
396
|
+
let onClick = null;
|
|
397
|
+
let onKeyDown = null;
|
|
398
|
+
|
|
399
|
+
function ensureSelectModeStyles(doc) {
|
|
400
|
+
if (doc.getElementById("vibespot-select-css")) return;
|
|
401
|
+
const style = doc.createElement("style");
|
|
402
|
+
style.id = "vibespot-select-css";
|
|
403
|
+
style.textContent = `
|
|
404
|
+
html.vibespot-select-mode, html.vibespot-select-mode * { cursor: crosshair !important; }
|
|
405
|
+
html.vibespot-select-mode a, html.vibespot-select-mode button { pointer-events: none; }
|
|
406
|
+
.vibespot-select-hover {
|
|
407
|
+
outline: 2px solid #e8613a !important;
|
|
408
|
+
outline-offset: 2px !important;
|
|
409
|
+
background-color: rgba(232, 97, 58, 0.08) !important;
|
|
410
|
+
}
|
|
411
|
+
.vibespot-select-label {
|
|
412
|
+
position: fixed;
|
|
413
|
+
z-index: 2147483647;
|
|
414
|
+
pointer-events: none;
|
|
415
|
+
font: 500 11px/1.4 -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif;
|
|
416
|
+
color: #fff;
|
|
417
|
+
background: #e8613a;
|
|
418
|
+
padding: 3px 8px;
|
|
419
|
+
border-radius: 4px;
|
|
420
|
+
box-shadow: 0 2px 6px rgba(0,0,0,0.25);
|
|
421
|
+
white-space: nowrap;
|
|
422
|
+
max-width: 70vw;
|
|
423
|
+
overflow: hidden;
|
|
424
|
+
text-overflow: ellipsis;
|
|
425
|
+
}
|
|
426
|
+
`;
|
|
427
|
+
doc.head.appendChild(style);
|
|
428
|
+
}
|
|
429
|
+
|
|
430
|
+
function describeElement(el) {
|
|
431
|
+
if (!el) return "";
|
|
432
|
+
const moduleEl = el.closest("[data-module]");
|
|
433
|
+
const moduleName = moduleEl ? moduleEl.getAttribute("data-module") : null;
|
|
434
|
+
const tag = (el.tagName || "").toLowerCase();
|
|
435
|
+
let kind = tag;
|
|
436
|
+
if (tag.match(/^h[1-6]$/)) kind = "headline";
|
|
437
|
+
else if (tag === "p") kind = "paragraph";
|
|
438
|
+
else if (tag === "a") kind = "link";
|
|
439
|
+
else if (tag === "button") kind = "button";
|
|
440
|
+
else if (tag === "img") kind = "image";
|
|
441
|
+
else if (tag === "ul" || tag === "ol") kind = "list";
|
|
442
|
+
else if (tag === "li") kind = "list item";
|
|
443
|
+
|
|
444
|
+
if (moduleName && moduleEl === el) return moduleName;
|
|
445
|
+
if (moduleName) return `${moduleName} > ${kind}`;
|
|
446
|
+
return kind;
|
|
447
|
+
}
|
|
448
|
+
|
|
449
|
+
function buildChatPrefill(el) {
|
|
450
|
+
if (!el) return "";
|
|
451
|
+
const moduleEl = el.closest("[data-module]");
|
|
452
|
+
const moduleName = moduleEl ? moduleEl.getAttribute("data-module") : null;
|
|
453
|
+
const tag = (el.tagName || "").toLowerCase();
|
|
454
|
+
const text = (el.textContent || "").trim().replace(/\s+/g, " ").slice(0, 80);
|
|
455
|
+
|
|
456
|
+
let elementPart;
|
|
457
|
+
if (tag.match(/^h[1-6]$/)) elementPart = "the headline";
|
|
458
|
+
else if (tag === "p") elementPart = "the paragraph";
|
|
459
|
+
else if (tag === "a") elementPart = "the link";
|
|
460
|
+
else if (tag === "button") elementPart = "the button";
|
|
461
|
+
else if (tag === "img") elementPart = "the image";
|
|
462
|
+
else elementPart = `the ${tag}`;
|
|
463
|
+
|
|
464
|
+
if (moduleEl === el && moduleName) {
|
|
465
|
+
return `In the ${moduleName} section, `;
|
|
466
|
+
}
|
|
467
|
+
if (moduleName) {
|
|
468
|
+
const quote = text ? ` ("${text}${text.length === 80 ? "…" : ""}")` : "";
|
|
469
|
+
return `In the ${moduleName} section, ${elementPart}${quote} `;
|
|
470
|
+
}
|
|
471
|
+
return `${elementPart} `;
|
|
472
|
+
}
|
|
473
|
+
|
|
474
|
+
function clearHover(doc) {
|
|
475
|
+
if (hoveredEl) {
|
|
476
|
+
hoveredEl.classList.remove("vibespot-select-hover");
|
|
477
|
+
hoveredEl = null;
|
|
478
|
+
}
|
|
479
|
+
if (hoverLabelEl && hoverLabelEl.parentNode) {
|
|
480
|
+
hoverLabelEl.parentNode.removeChild(hoverLabelEl);
|
|
481
|
+
}
|
|
482
|
+
hoverLabelEl = null;
|
|
483
|
+
}
|
|
484
|
+
|
|
485
|
+
function attachSelectHandlers() {
|
|
486
|
+
let doc;
|
|
487
|
+
try {
|
|
488
|
+
doc = previewFrame.contentDocument || previewFrame.contentWindow?.document;
|
|
489
|
+
} catch { return; }
|
|
490
|
+
if (!doc || !doc.body) return;
|
|
491
|
+
|
|
492
|
+
ensureSelectModeStyles(doc);
|
|
493
|
+
doc.documentElement.classList.add("vibespot-select-mode");
|
|
494
|
+
|
|
495
|
+
onMouseOver = (e) => {
|
|
496
|
+
const el = e.target;
|
|
497
|
+
if (!el || el === doc.body || el === doc.documentElement) return;
|
|
498
|
+
if (el.classList && el.classList.contains("vibespot-select-label")) return;
|
|
499
|
+
if (hoveredEl === el) return;
|
|
500
|
+
if (hoveredEl) hoveredEl.classList.remove("vibespot-select-hover");
|
|
501
|
+
hoveredEl = el;
|
|
502
|
+
el.classList.add("vibespot-select-hover");
|
|
503
|
+
|
|
504
|
+
if (!hoverLabelEl) {
|
|
505
|
+
hoverLabelEl = doc.createElement("div");
|
|
506
|
+
hoverLabelEl.className = "vibespot-select-label";
|
|
507
|
+
doc.body.appendChild(hoverLabelEl);
|
|
508
|
+
}
|
|
509
|
+
hoverLabelEl.textContent = describeElement(el);
|
|
510
|
+
const rect = el.getBoundingClientRect();
|
|
511
|
+
hoverLabelEl.style.top = Math.max(4, rect.top - 22) + "px";
|
|
512
|
+
hoverLabelEl.style.left = Math.max(4, rect.left) + "px";
|
|
513
|
+
};
|
|
514
|
+
|
|
515
|
+
onMouseOut = (e) => {
|
|
516
|
+
if (!e.relatedTarget) clearHover(doc);
|
|
517
|
+
};
|
|
518
|
+
|
|
519
|
+
onClick = (e) => {
|
|
520
|
+
e.preventDefault();
|
|
521
|
+
e.stopPropagation();
|
|
522
|
+
const prefill = buildChatPrefill(e.target);
|
|
523
|
+
deactivateSelectMode();
|
|
524
|
+
if (typeof window.prefillChatInput === "function") {
|
|
525
|
+
window.prefillChatInput(prefill);
|
|
526
|
+
}
|
|
527
|
+
};
|
|
528
|
+
|
|
529
|
+
onKeyDown = (e) => {
|
|
530
|
+
if (e.key === "Escape") deactivateSelectMode();
|
|
531
|
+
};
|
|
532
|
+
|
|
533
|
+
doc.addEventListener("mouseover", onMouseOver, true);
|
|
534
|
+
doc.addEventListener("mouseout", onMouseOut, true);
|
|
535
|
+
doc.addEventListener("click", onClick, true);
|
|
536
|
+
doc.addEventListener("keydown", onKeyDown, true);
|
|
537
|
+
}
|
|
538
|
+
|
|
539
|
+
function detachSelectHandlers() {
|
|
540
|
+
let doc;
|
|
541
|
+
try {
|
|
542
|
+
doc = previewFrame.contentDocument || previewFrame.contentWindow?.document;
|
|
543
|
+
} catch { return; }
|
|
544
|
+
if (!doc) return;
|
|
545
|
+
doc.documentElement.classList.remove("vibespot-select-mode");
|
|
546
|
+
clearHover(doc);
|
|
547
|
+
if (onMouseOver) doc.removeEventListener("mouseover", onMouseOver, true);
|
|
548
|
+
if (onMouseOut) doc.removeEventListener("mouseout", onMouseOut, true);
|
|
549
|
+
if (onClick) doc.removeEventListener("click", onClick, true);
|
|
550
|
+
if (onKeyDown) doc.removeEventListener("keydown", onKeyDown, true);
|
|
551
|
+
onMouseOver = onMouseOut = onClick = onKeyDown = null;
|
|
552
|
+
}
|
|
553
|
+
|
|
554
|
+
function activateSelectMode() {
|
|
555
|
+
if (selectModeActive) return;
|
|
556
|
+
selectModeActive = true;
|
|
557
|
+
if (selectModeBtn) selectModeBtn.setAttribute("aria-pressed", "true");
|
|
558
|
+
if (previewContainer) previewContainer.classList.add("preview--select-mode");
|
|
559
|
+
attachSelectHandlers();
|
|
560
|
+
}
|
|
561
|
+
|
|
562
|
+
function deactivateSelectMode() {
|
|
563
|
+
if (!selectModeActive) return;
|
|
564
|
+
selectModeActive = false;
|
|
565
|
+
if (selectModeBtn) selectModeBtn.setAttribute("aria-pressed", "false");
|
|
566
|
+
if (previewContainer) previewContainer.classList.remove("preview--select-mode");
|
|
567
|
+
detachSelectHandlers();
|
|
568
|
+
}
|
|
569
|
+
|
|
570
|
+
function setSelectModeDisabled(disabled) {
|
|
571
|
+
if (!selectModeBtn) return;
|
|
572
|
+
if (disabled) {
|
|
573
|
+
deactivateSelectMode();
|
|
574
|
+
selectModeBtn.disabled = true;
|
|
575
|
+
} else {
|
|
576
|
+
selectModeBtn.disabled = false;
|
|
577
|
+
}
|
|
578
|
+
}
|
|
579
|
+
|
|
580
|
+
if (selectModeBtn) {
|
|
581
|
+
selectModeBtn.addEventListener("click", () => {
|
|
582
|
+
if (selectModeBtn.disabled) return;
|
|
583
|
+
if (selectModeActive) deactivateSelectMode();
|
|
584
|
+
else activateSelectMode();
|
|
585
|
+
});
|
|
586
|
+
}
|
|
587
|
+
|
|
588
|
+
if (previewFrame) {
|
|
589
|
+
previewFrame.addEventListener("load", () => {
|
|
590
|
+
if (selectModeActive) attachSelectHandlers();
|
|
591
|
+
});
|
|
592
|
+
}
|
|
593
|
+
|
|
594
|
+
window.setSelectModeDisabled = setSelectModeDisabled;
|
|
595
|
+
window.deactivateSelectMode = deactivateSelectMode;
|
package/ui/settings.js
CHANGED
|
@@ -100,7 +100,7 @@ function renderAITab(body, data) {
|
|
|
100
100
|
// Engine selector
|
|
101
101
|
const section = el("section", "settings__section");
|
|
102
102
|
section.appendChild(sectionTitle("Engine"));
|
|
103
|
-
section.appendChild(desc("Choose which AI engine generates your HubSpot
|
|
103
|
+
section.appendChild(desc("Choose which AI engine generates your HubSpot sections. API engines need an API key. CLI engines need the tool installed on your system."));
|
|
104
104
|
|
|
105
105
|
const selectEl = el("div", "settings__engine-select");
|
|
106
106
|
const allEngines = [
|
|
@@ -176,9 +176,9 @@ function renderAITab(body, data) {
|
|
|
176
176
|
const agenticMode = config.agenticMode;
|
|
177
177
|
|
|
178
178
|
if (isCli) {
|
|
179
|
-
agenticSection.appendChild(desc("Decompose AI generation into specialized agents with per-
|
|
179
|
+
agenticSection.appendChild(desc("Decompose AI generation into specialized agents with per-section parallel calls. Better quality and structured output enforcement. CLI engines use subprocess calls — may be slower than API engines."));
|
|
180
180
|
} else {
|
|
181
|
-
agenticSection.appendChild(desc("Decompose AI generation into specialized agents with per-
|
|
181
|
+
agenticSection.appendChild(desc("Decompose AI generation into specialized agents with per-section parallel calls. Better quality and structured output enforcement."));
|
|
182
182
|
}
|
|
183
183
|
|
|
184
184
|
const toggleRow = el("div", "settings__toggle-row");
|
|
@@ -189,7 +189,7 @@ function renderAITab(body, data) {
|
|
|
189
189
|
|
|
190
190
|
const sub = el("div", "settings__toggle-label-sub");
|
|
191
191
|
if (agenticMode === true) {
|
|
192
|
-
sub.textContent = "Active — multi-stage pipeline with parallel
|
|
192
|
+
sub.textContent = "Active — multi-stage pipeline with parallel section generation";
|
|
193
193
|
sub.style.color = "var(--success)";
|
|
194
194
|
} else if (agenticMode === false) {
|
|
195
195
|
sub.textContent = "Disabled — using single-call mode";
|
|
@@ -551,7 +551,7 @@ function renderFigmaTab(body, data) {
|
|
|
551
551
|
|
|
552
552
|
const section = el("section", "settings__section");
|
|
553
553
|
section.appendChild(sectionTitle("Personal Access Token"));
|
|
554
|
-
section.appendChild(desc("Connect your Figma account to import designs directly into HubSpot CMS
|
|
554
|
+
section.appendChild(desc("Connect your Figma account to import designs directly into HubSpot CMS sections. Tokens are stored locally and only used to call the Figma API."));
|
|
555
555
|
|
|
556
556
|
const figmaToken = config.figmaToken;
|
|
557
557
|
const figmaKeyInfo = {
|
|
@@ -1394,36 +1394,47 @@ function getModelsForEngine(engine) {
|
|
|
1394
1394
|
switch (engine) {
|
|
1395
1395
|
case "claude-code":
|
|
1396
1396
|
return [
|
|
1397
|
-
{ id: "
|
|
1398
|
-
{ id: "opus", label: "Claude Opus" },
|
|
1399
|
-
{ id: "
|
|
1397
|
+
{ id: "claude-opus-4-7", label: "Claude Opus 4.7" },
|
|
1398
|
+
{ id: "claude-opus-4-6", label: "Claude Opus 4.6" },
|
|
1399
|
+
{ id: "claude-sonnet-4-6", label: "Claude Sonnet 4.6 (default)" },
|
|
1400
|
+
{ id: "claude-sonnet-4-5", label: "Claude Sonnet 4.5" },
|
|
1401
|
+
{ id: "claude-haiku-4-5", label: "Claude Haiku 4.5" },
|
|
1400
1402
|
];
|
|
1401
1403
|
case "anthropic-api":
|
|
1402
1404
|
case "claude-oauth":
|
|
1403
1405
|
return [
|
|
1404
|
-
{ id: "claude-
|
|
1406
|
+
{ id: "claude-opus-4-7", label: "Claude Opus 4.7" },
|
|
1405
1407
|
{ id: "claude-opus-4-6", label: "Claude Opus 4.6" },
|
|
1408
|
+
{ id: "claude-sonnet-4-6", label: "Claude Sonnet 4.6 (default)" },
|
|
1409
|
+
{ id: "claude-sonnet-4-5", label: "Claude Sonnet 4.5" },
|
|
1406
1410
|
{ id: "claude-haiku-4-5-20251001", label: "Claude Haiku 4.5" },
|
|
1407
1411
|
];
|
|
1408
1412
|
case "openai-api":
|
|
1409
1413
|
return [
|
|
1410
|
-
{ id: "gpt-
|
|
1411
|
-
{ id: "gpt-
|
|
1412
|
-
{ id: "
|
|
1413
|
-
{ id: "
|
|
1414
|
+
{ id: "gpt-5.5", label: "GPT-5.5 (default)" },
|
|
1415
|
+
{ id: "gpt-5.5-pro", label: "GPT-5.5 Pro" },
|
|
1416
|
+
{ id: "gpt-5.4-mini", label: "GPT-5.4 Mini" },
|
|
1417
|
+
{ id: "gpt-5.4-nano", label: "GPT-5.4 Nano" },
|
|
1418
|
+
{ id: "gpt-5.3-codex", label: "GPT-5.3 Codex" },
|
|
1414
1419
|
];
|
|
1415
1420
|
case "gemini-cli":
|
|
1416
1421
|
case "gemini-api":
|
|
1417
1422
|
return [
|
|
1418
|
-
{ id: "gemini-2.5-
|
|
1419
|
-
{ id: "gemini-2.5-
|
|
1423
|
+
{ id: "gemini-2.5-pro", label: "Gemini 2.5 Pro (default)" },
|
|
1424
|
+
{ id: "gemini-2.5-flash", label: "Gemini 2.5 Flash" },
|
|
1420
1425
|
{ id: "gemini-2.0-flash", label: "Gemini 2.0 Flash" },
|
|
1421
1426
|
];
|
|
1422
1427
|
case "codex-cli":
|
|
1423
1428
|
return [
|
|
1424
|
-
{ id: "
|
|
1425
|
-
{ id: "
|
|
1426
|
-
{ id: "gpt-
|
|
1429
|
+
{ id: "gpt-5.5", label: "GPT-5.5 (default)" },
|
|
1430
|
+
{ id: "gpt-5.5-pro", label: "GPT-5.5 Pro" },
|
|
1431
|
+
{ id: "gpt-5.3-codex", label: "GPT-5.3 Codex" },
|
|
1432
|
+
{ id: "gpt-5.2-codex", label: "GPT-5.2 Codex" },
|
|
1433
|
+
{ id: "gpt-5.1-codex-max", label: "GPT-5.1 Codex Max" },
|
|
1434
|
+
{ id: "gpt-5.1-codex-mini", label: "GPT-5.1 Codex Mini" },
|
|
1435
|
+
{ id: "gpt-5.4-mini", label: "GPT-5.4 Mini" },
|
|
1436
|
+
{ id: "gpt-5.4-nano", label: "GPT-5.4 Nano" },
|
|
1437
|
+
{ id: "codex-mini-latest", label: "Codex Mini (latest)" },
|
|
1427
1438
|
];
|
|
1428
1439
|
default:
|
|
1429
1440
|
return [];
|
|
@@ -1432,10 +1443,13 @@ function getModelsForEngine(engine) {
|
|
|
1432
1443
|
|
|
1433
1444
|
function getCurrentModel(engine, config) {
|
|
1434
1445
|
switch (engine) {
|
|
1435
|
-
case "claude-code": return config.claudeCodeModel || "sonnet";
|
|
1446
|
+
case "claude-code": return config.claudeCodeModel || "claude-sonnet-4-6";
|
|
1436
1447
|
case "anthropic-api":
|
|
1437
1448
|
case "claude-oauth": return config.anthropicApiModel || "claude-sonnet-4-6";
|
|
1438
|
-
case "openai-api": return config.openaiApiModel || "gpt-
|
|
1449
|
+
case "openai-api": return config.openaiApiModel || "gpt-5.5";
|
|
1450
|
+
case "codex-cli": return config.codexCliModel || "gpt-5.5";
|
|
1451
|
+
case "gemini-cli": return config.geminiCliModel || "gemini-2.5-pro";
|
|
1452
|
+
case "gemini-api": return config.geminiApiModel || "gemini-2.5-pro";
|
|
1439
1453
|
default: return null;
|
|
1440
1454
|
}
|
|
1441
1455
|
}
|
|
@@ -1501,7 +1515,7 @@ document.getElementById("settings-overlay").addEventListener("click", (e) => {
|
|
|
1501
1515
|
if (e.target.id === "settings-overlay") closeSettings();
|
|
1502
1516
|
});
|
|
1503
1517
|
|
|
1504
|
-
document.getElementById("btn-setup-settings").addEventListener("click", openSettings);
|
|
1518
|
+
document.getElementById("btn-setup-settings").addEventListener("click", () => openSettings());
|
|
1505
1519
|
|
|
1506
1520
|
document.addEventListener("keydown", (e) => {
|
|
1507
1521
|
if (e.key === "Escape" && !document.getElementById("settings-overlay").classList.contains("hidden")) {
|