Give the wizard an assistant scoped to the step you are actually stuck on, so a first-run question can say "this" and mean something
This commit is contained in:
@@ -37,6 +37,12 @@
|
|||||||
// Step 2: auto-populate + guide + checklist.
|
// Step 2: auto-populate + guide + checklist.
|
||||||
// master.conf pull (for partner servers) lives in the checklist, not here.
|
// master.conf pull (for partner servers) lives in the checklist, not here.
|
||||||
|
|
||||||
|
// The assistant is a bonus on this page, never a dependency: vv_ai_ui_on() is false on a node
|
||||||
|
// with AI off or no model reachable, which is the normal state of the fresh install this wizard
|
||||||
|
// exists to serve. The card simply is not rendered and setup proceeds exactly as before.
|
||||||
|
require_once dirname(__DIR__) . '/include/ai_chat.php';
|
||||||
|
if (vv_ai_ui_on()) vv_ai_chat_assets();
|
||||||
|
|
||||||
$detectedHostname = vv_get_hostname();
|
$detectedHostname = vv_get_hostname();
|
||||||
|
|
||||||
// ── Identity already on disk? ────────────────────────────────────────────────────────────────
|
// ── Identity already on disk? ────────────────────────────────────────────────────────────────
|
||||||
@@ -313,6 +319,21 @@ hr.vv-hr { border: none; border-top: 1px solid #1e1e1e; margin: 22px 0; }
|
|||||||
<div id="vv-onboard-panel"></div>
|
<div id="vv-onboard-panel"></div>
|
||||||
<div id="vv-done-banner"></div>
|
<div id="vv-done-banner"></div>
|
||||||
|
|
||||||
|
<?php if (vv_ai_ui_on()): ?>
|
||||||
|
<hr class="vv-hr">
|
||||||
|
<div id="vv-su-ai-card">
|
||||||
|
<?php vv_ai_chat_markup('vv-su-ai', [
|
||||||
|
'profile' => 'varaverk',
|
||||||
|
'compact' => true,
|
||||||
|
'title' => 'Setup assistant',
|
||||||
|
'height' => '260px',
|
||||||
|
'tall' => '460px',
|
||||||
|
'empty' => 'Stuck on a step? Ask what it wants and why — "what is the API key for", '
|
||||||
|
. '"why does SSH need the other host", "what does populate actually do".',
|
||||||
|
]); ?>
|
||||||
|
</div>
|
||||||
|
<?php endif; ?>
|
||||||
|
|
||||||
<div style="margin-top:18px;text-align:right;">
|
<div style="margin-top:18px;text-align:right;">
|
||||||
<a href="#" id="vv-exit-link" onclick="vvGoNext(event)"
|
<a href="#" id="vv-exit-link" onclick="vvGoNext(event)"
|
||||||
style="font-size:11px;color:#3a3a3a;text-decoration:none;">Skip →</a>
|
style="font-size:11px;color:#3a3a3a;text-decoration:none;">Skip →</a>
|
||||||
@@ -443,6 +464,7 @@ function vvShowStep2(redirect, apiKey) {
|
|||||||
_vvRedirect = redirect || '?tab=scheduler';
|
_vvRedirect = redirect || '?tab=scheduler';
|
||||||
document.getElementById('vv-step1').style.display = 'none';
|
document.getElementById('vv-step1').style.display = 'none';
|
||||||
document.getElementById('vv-step2').style.display = 'block';
|
document.getElementById('vv-step2').style.display = 'block';
|
||||||
|
vvSetupAiInit(); // card is visible now, so it can measure itself correctly
|
||||||
if (apiKey && apiKey.ok) {
|
if (apiKey && apiKey.ok) {
|
||||||
const btn = document.getElementById('vv-key-btn');
|
const btn = document.getElementById('vv-key-btn');
|
||||||
const status = document.getElementById('vv-key-status');
|
const status = document.getElementById('vv-key-status');
|
||||||
@@ -676,6 +698,47 @@ function vvStartPhase2Watch(sinceMs) {
|
|||||||
_vvPartnerPoll = setInterval(check, 6000);
|
_vvPartnerPoll = setInterval(check, 6000);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ── Setup assistant ───────────────────────────────────────────────────────────
|
||||||
|
// Scoped to the step the operator is actually stuck on, so "what does this want" resolves without
|
||||||
|
// them naming it. The worker turns a non-empty scope into a line saying what is open in the
|
||||||
|
// WebGUI; the varaverk profile holds no scoped_log capability, so a checklist id never triggers a
|
||||||
|
// log lookup and cannot produce a "log missing" note for something that was never a script.
|
||||||
|
//
|
||||||
|
// Re-read at send time, not captured: the checklist re-polls while the page is open and the step
|
||||||
|
// they are on can change between opening the composer and pressing Ask.
|
||||||
|
//
|
||||||
|
// First not-ok, not-deferred item — deferred means "I have decided to skip this", which is not
|
||||||
|
// where they are stuck. Falls back to the bare page when the list is clean or has not loaded.
|
||||||
|
function vvSetupScope() {
|
||||||
|
const d = _vvLastChecklist;
|
||||||
|
if (!d || !Array.isArray(d.items)) return 'Setup';
|
||||||
|
const stuck = d.items.find(i => !i.ok && !i.deferred);
|
||||||
|
return stuck && stuck.id ? 'Setup/' + stuck.id : 'Setup';
|
||||||
|
}
|
||||||
|
|
||||||
|
// Mounted when Step 2 is revealed, not at parse time. This is the only page where the card starts
|
||||||
|
// inside a display:none block, and a chat that measured itself while hidden would come up wrong
|
||||||
|
// with nothing to correct it — the component carries no resize observer. Idempotent because
|
||||||
|
// vvShowStep2 is reachable more than once.
|
||||||
|
let _vvSetupAiUp = false;
|
||||||
|
function vvSetupAiInit() {
|
||||||
|
if (_vvSetupAiUp) return;
|
||||||
|
if (typeof VvAiChat !== 'function') return;
|
||||||
|
if (!document.getElementById('vv-su-ai-chat')) return; // AI off — card was never rendered
|
||||||
|
_vvSetupAiUp = true;
|
||||||
|
VvAiChat({
|
||||||
|
prefix: 'vv-su-ai',
|
||||||
|
profile: 'varaverk',
|
||||||
|
// Pinned, for the same reason the Partnership card pins it: resuming whatever thread was last
|
||||||
|
// touched anywhere in the UI could land a first-run operator mid-way through someone else's
|
||||||
|
// Scheduler conversation, on a card with no picker to get back from.
|
||||||
|
resumeProfile: 'varaverk',
|
||||||
|
scope: vvSetupScope,
|
||||||
|
scopeLabel: 'Setup',
|
||||||
|
empty: 'Stuck on a step? Ask what it wants and why.',
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
function vvLoadChecklist() {
|
function vvLoadChecklist() {
|
||||||
fetch('/plugins/varaverk/api/checklist.php?_=' + Date.now())
|
fetch('/plugins/varaverk/api/checklist.php?_=' + Date.now())
|
||||||
.then(r => r.json()).then(d => {
|
.then(r => r.json()).then(d => {
|
||||||
|
|||||||
Reference in New Issue
Block a user