@runcontext/ui 0.5.8 → 0.5.9
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/package.json +10 -4
- package/static/setup.js +1 -1557
package/static/setup.js
CHANGED
|
@@ -1,1557 +1 @@
|
|
|
1
|
-
(function () {
|
|
2
|
-
'use strict';
|
|
3
|
-
|
|
4
|
-
var STORAGE_KEY = 'runcontext_wizard_state';
|
|
5
|
-
var STEP_LABELS = ['Connect', 'Define', 'Scaffold', 'Checkpoint', 'Enrich', 'Serve'];
|
|
6
|
-
|
|
7
|
-
// ---- State persistence ----
|
|
8
|
-
|
|
9
|
-
function loadSavedState() {
|
|
10
|
-
try {
|
|
11
|
-
var saved = sessionStorage.getItem(STORAGE_KEY);
|
|
12
|
-
if (saved) return JSON.parse(saved);
|
|
13
|
-
} catch (e) { /* ignore */ }
|
|
14
|
-
return null;
|
|
15
|
-
}
|
|
16
|
-
|
|
17
|
-
function saveState() {
|
|
18
|
-
try {
|
|
19
|
-
var toSave = {
|
|
20
|
-
step: state.step,
|
|
21
|
-
brief: state.brief,
|
|
22
|
-
sources: state.sources,
|
|
23
|
-
pipelineId: state.pipelineId,
|
|
24
|
-
};
|
|
25
|
-
sessionStorage.setItem(STORAGE_KEY, JSON.stringify(toSave));
|
|
26
|
-
} catch (e) { /* ignore */ }
|
|
27
|
-
}
|
|
28
|
-
|
|
29
|
-
var saved = loadSavedState();
|
|
30
|
-
var state = {
|
|
31
|
-
step: saved ? saved.step : 1,
|
|
32
|
-
brief: saved ? saved.brief : {
|
|
33
|
-
product_name: '',
|
|
34
|
-
description: '',
|
|
35
|
-
owner: { name: '', team: '', email: '' },
|
|
36
|
-
sensitivity: 'internal',
|
|
37
|
-
docs: [],
|
|
38
|
-
},
|
|
39
|
-
sources: saved ? saved.sources : [],
|
|
40
|
-
pipelineId: saved ? saved.pipelineId : null,
|
|
41
|
-
pollTimer: null,
|
|
42
|
-
mcpPollTimer: null,
|
|
43
|
-
};
|
|
44
|
-
|
|
45
|
-
// ---- WebSocket Client ----
|
|
46
|
-
var ws = null;
|
|
47
|
-
var wsSessionId = null;
|
|
48
|
-
|
|
49
|
-
function connectWebSocket(sessionId) {
|
|
50
|
-
wsSessionId = sessionId;
|
|
51
|
-
var protocol = location.protocol === 'https:' ? 'wss:' : 'ws:';
|
|
52
|
-
ws = new WebSocket(protocol + '//' + location.host + '/ws?session=' + encodeURIComponent(sessionId) + '&role=wizard');
|
|
53
|
-
|
|
54
|
-
ws.onmessage = function (evt) {
|
|
55
|
-
try {
|
|
56
|
-
var event = JSON.parse(evt.data);
|
|
57
|
-
handleWsEvent(event);
|
|
58
|
-
} catch (e) { /* ignore */ }
|
|
59
|
-
};
|
|
60
|
-
|
|
61
|
-
ws.onclose = function () {
|
|
62
|
-
setTimeout(function () {
|
|
63
|
-
if (wsSessionId) connectWebSocket(wsSessionId);
|
|
64
|
-
}, 2000);
|
|
65
|
-
};
|
|
66
|
-
|
|
67
|
-
ws.onerror = function () { /* ignore, onclose handles reconnect */ };
|
|
68
|
-
}
|
|
69
|
-
|
|
70
|
-
function sendWsEvent(type, payload) {
|
|
71
|
-
if (ws && ws.readyState === WebSocket.OPEN) {
|
|
72
|
-
ws.send(JSON.stringify({ type: type, sessionId: wsSessionId, payload: payload || {} }));
|
|
73
|
-
}
|
|
74
|
-
}
|
|
75
|
-
|
|
76
|
-
function handleWsEvent(event) {
|
|
77
|
-
switch (event.type) {
|
|
78
|
-
case 'setup:step':
|
|
79
|
-
if (event.payload && event.payload.step) {
|
|
80
|
-
goToStep(event.payload.step);
|
|
81
|
-
}
|
|
82
|
-
break;
|
|
83
|
-
case 'setup:field':
|
|
84
|
-
if (event.payload && event.payload.fieldId) {
|
|
85
|
-
var input = document.getElementById(event.payload.fieldId);
|
|
86
|
-
if (input) {
|
|
87
|
-
input.value = event.payload.value || '';
|
|
88
|
-
input.dispatchEvent(new Event('input'));
|
|
89
|
-
}
|
|
90
|
-
}
|
|
91
|
-
break;
|
|
92
|
-
case 'pipeline:stage':
|
|
93
|
-
updateStageFromWs(event.payload || {});
|
|
94
|
-
break;
|
|
95
|
-
case 'enrich:progress':
|
|
96
|
-
updateEnrichProgress(event.payload || {});
|
|
97
|
-
break;
|
|
98
|
-
case 'enrich:log':
|
|
99
|
-
appendEnrichLog(event.payload || {});
|
|
100
|
-
break;
|
|
101
|
-
case 'tier:update':
|
|
102
|
-
if (event.payload && event.payload.tier) {
|
|
103
|
-
var badge = document.getElementById('tier-badge');
|
|
104
|
-
if (badge) badge.textContent = event.payload.tier;
|
|
105
|
-
}
|
|
106
|
-
break;
|
|
107
|
-
}
|
|
108
|
-
}
|
|
109
|
-
|
|
110
|
-
function updateStageFromWs(payload) {
|
|
111
|
-
// Update stage dots in the scaffold step
|
|
112
|
-
var stageEl = document.querySelector('[data-stage="' + payload.stage + '"]');
|
|
113
|
-
if (!stageEl) return;
|
|
114
|
-
var dot = stageEl.querySelector('.stage-dot');
|
|
115
|
-
if (dot) {
|
|
116
|
-
dot.className = 'stage-dot';
|
|
117
|
-
if (payload.status === 'running') dot.className += ' running';
|
|
118
|
-
else if (payload.status === 'done') dot.className += ' done';
|
|
119
|
-
else if (payload.status === 'error') dot.className += ' error';
|
|
120
|
-
}
|
|
121
|
-
var summary = stageEl.querySelector('.stage-summary');
|
|
122
|
-
if (summary && payload.summary) {
|
|
123
|
-
summary.textContent = payload.summary;
|
|
124
|
-
}
|
|
125
|
-
}
|
|
126
|
-
|
|
127
|
-
// ---- Helpers ----
|
|
128
|
-
|
|
129
|
-
function $(sel) { return document.querySelector(sel); }
|
|
130
|
-
function $$(sel) { return document.querySelectorAll(sel); }
|
|
131
|
-
|
|
132
|
-
function showError(fieldId, msg) {
|
|
133
|
-
var field = document.getElementById(fieldId);
|
|
134
|
-
if (!field) return;
|
|
135
|
-
field.classList.add('error');
|
|
136
|
-
var existing = field.parentElement.querySelector('.field-error');
|
|
137
|
-
if (existing) existing.remove();
|
|
138
|
-
if (msg) {
|
|
139
|
-
var el = document.createElement('p');
|
|
140
|
-
el.className = 'field-error';
|
|
141
|
-
el.textContent = msg;
|
|
142
|
-
field.parentElement.appendChild(el);
|
|
143
|
-
}
|
|
144
|
-
}
|
|
145
|
-
|
|
146
|
-
function clearErrors() {
|
|
147
|
-
$$('.error').forEach(function (el) { el.classList.remove('error'); });
|
|
148
|
-
$$('.field-error').forEach(function (el) { el.remove(); });
|
|
149
|
-
}
|
|
150
|
-
|
|
151
|
-
async function api(method, path, body) {
|
|
152
|
-
var opts = { method: method, headers: {} };
|
|
153
|
-
if (body && !(body instanceof FormData)) {
|
|
154
|
-
opts.headers['Content-Type'] = 'application/json';
|
|
155
|
-
opts.body = JSON.stringify(body);
|
|
156
|
-
} else if (body) {
|
|
157
|
-
opts.body = body;
|
|
158
|
-
}
|
|
159
|
-
var res = await fetch(path, opts);
|
|
160
|
-
if (!res.ok) {
|
|
161
|
-
var text = await res.text();
|
|
162
|
-
throw new Error(text || res.statusText);
|
|
163
|
-
}
|
|
164
|
-
var ct = res.headers.get('content-type') || '';
|
|
165
|
-
return ct.includes('json') ? res.json() : res.text();
|
|
166
|
-
}
|
|
167
|
-
|
|
168
|
-
// ---- DOM builder helper (avoid innerHTML for security) ----
|
|
169
|
-
|
|
170
|
-
function createElement(tag, attrs, children) {
|
|
171
|
-
var el = document.createElement(tag);
|
|
172
|
-
if (attrs) {
|
|
173
|
-
Object.keys(attrs).forEach(function (key) {
|
|
174
|
-
if (key === 'className') el.className = attrs[key];
|
|
175
|
-
else if (key === 'textContent') el.textContent = attrs[key];
|
|
176
|
-
else if (key === 'htmlFor') el.htmlFor = attrs[key];
|
|
177
|
-
else if (key === 'type') el.type = attrs[key];
|
|
178
|
-
else el.setAttribute(key, attrs[key]);
|
|
179
|
-
});
|
|
180
|
-
}
|
|
181
|
-
if (children) {
|
|
182
|
-
children.forEach(function (child) {
|
|
183
|
-
if (typeof child === 'string') {
|
|
184
|
-
el.appendChild(document.createTextNode(child));
|
|
185
|
-
} else if (child) {
|
|
186
|
-
el.appendChild(child);
|
|
187
|
-
}
|
|
188
|
-
});
|
|
189
|
-
}
|
|
190
|
-
return el;
|
|
191
|
-
}
|
|
192
|
-
|
|
193
|
-
// ---- Breadcrumb Stepper ----
|
|
194
|
-
|
|
195
|
-
function renderStepper() {
|
|
196
|
-
var container = document.getElementById('stepper');
|
|
197
|
-
if (!container) return;
|
|
198
|
-
container.textContent = '';
|
|
199
|
-
|
|
200
|
-
STEP_LABELS.forEach(function (label, i) {
|
|
201
|
-
var stepNum = i + 1;
|
|
202
|
-
var span = document.createElement('span');
|
|
203
|
-
span.textContent = label;
|
|
204
|
-
|
|
205
|
-
if (stepNum < state.step) {
|
|
206
|
-
span.className = 'step-completed';
|
|
207
|
-
span.addEventListener('click', function () {
|
|
208
|
-
goToStep(stepNum);
|
|
209
|
-
});
|
|
210
|
-
} else if (stepNum === state.step) {
|
|
211
|
-
span.className = 'step-active';
|
|
212
|
-
} else {
|
|
213
|
-
span.className = 'step-future';
|
|
214
|
-
}
|
|
215
|
-
|
|
216
|
-
container.appendChild(span);
|
|
217
|
-
|
|
218
|
-
if (stepNum < STEP_LABELS.length) {
|
|
219
|
-
var sep = document.createElement('span');
|
|
220
|
-
sep.className = 'step-separator';
|
|
221
|
-
sep.textContent = '>';
|
|
222
|
-
container.appendChild(sep);
|
|
223
|
-
}
|
|
224
|
-
});
|
|
225
|
-
}
|
|
226
|
-
|
|
227
|
-
// ---- Navigation ----
|
|
228
|
-
|
|
229
|
-
function goToStep(n) {
|
|
230
|
-
if (n < 1 || n > 6) return;
|
|
231
|
-
|
|
232
|
-
// Clear any running pipeline poll timer when navigating away
|
|
233
|
-
if (state.pollTimer) { clearInterval(state.pollTimer); state.pollTimer = null; }
|
|
234
|
-
|
|
235
|
-
var content = document.getElementById('wizard-content');
|
|
236
|
-
if (content) content.textContent = '';
|
|
237
|
-
|
|
238
|
-
state.step = n;
|
|
239
|
-
saveState();
|
|
240
|
-
|
|
241
|
-
renderStepper();
|
|
242
|
-
|
|
243
|
-
switch (n) {
|
|
244
|
-
case 1: renderConnectStep(); break;
|
|
245
|
-
case 2: renderDefineStep(); break;
|
|
246
|
-
case 3: renderScaffoldStep(); break;
|
|
247
|
-
case 4: renderCheckpointStep(); break;
|
|
248
|
-
case 5: renderEnrichStep(); break;
|
|
249
|
-
case 6: renderServeStep(); break;
|
|
250
|
-
}
|
|
251
|
-
}
|
|
252
|
-
|
|
253
|
-
function validateStep(n) {
|
|
254
|
-
clearErrors();
|
|
255
|
-
// Step-specific validation will be added as each step is implemented
|
|
256
|
-
return true;
|
|
257
|
-
}
|
|
258
|
-
|
|
259
|
-
// ---- Step action buttons helper ----
|
|
260
|
-
|
|
261
|
-
function createStepActions(showBack, showNext, nextLabel) {
|
|
262
|
-
var actions = createElement('div', { className: 'step-actions' });
|
|
263
|
-
if (showBack) {
|
|
264
|
-
var backBtn = createElement('button', { className: 'btn btn-secondary', textContent: 'Back' });
|
|
265
|
-
backBtn.addEventListener('click', function () {
|
|
266
|
-
goToStep(state.step - 1);
|
|
267
|
-
});
|
|
268
|
-
actions.appendChild(backBtn);
|
|
269
|
-
} else {
|
|
270
|
-
actions.appendChild(createElement('span'));
|
|
271
|
-
}
|
|
272
|
-
if (showNext) {
|
|
273
|
-
var nextBtn = createElement('button', { className: 'btn btn-primary', textContent: nextLabel || 'Next' });
|
|
274
|
-
nextBtn.addEventListener('click', function () {
|
|
275
|
-
if (validateStep(state.step)) goToStep(state.step + 1);
|
|
276
|
-
});
|
|
277
|
-
actions.appendChild(nextBtn);
|
|
278
|
-
}
|
|
279
|
-
return actions;
|
|
280
|
-
}
|
|
281
|
-
|
|
282
|
-
// ---- Step 1: Connect ----
|
|
283
|
-
|
|
284
|
-
function renderConnectStep() {
|
|
285
|
-
var content = document.getElementById('wizard-content');
|
|
286
|
-
if (!content) return;
|
|
287
|
-
|
|
288
|
-
var card = createElement('div', { className: 'card' });
|
|
289
|
-
|
|
290
|
-
card.appendChild(createElement('h2', { className: 'connect-heading', textContent: 'Connect Your Database' }));
|
|
291
|
-
card.appendChild(createElement('p', { className: 'connect-subheading', textContent: 'RunContext connects directly to your database via OAuth \u2014 your credentials never pass through the AI agent.' }));
|
|
292
|
-
|
|
293
|
-
// Detected databases hint (from MCP/IDE configs)
|
|
294
|
-
var detectedHint = createElement('div', { id: 'connect-detected-hint' });
|
|
295
|
-
card.appendChild(detectedHint);
|
|
296
|
-
|
|
297
|
-
// OAuth result area — positioned right after detected hint so db cards appear here
|
|
298
|
-
var oauthResult = createElement('div', { id: 'connect-oauth-result' });
|
|
299
|
-
card.appendChild(oauthResult);
|
|
300
|
-
|
|
301
|
-
// Platform picker grid (populated after fetching providers)
|
|
302
|
-
var platformGrid = createElement('div', { className: 'platform-grid', id: 'connect-platforms' });
|
|
303
|
-
platformGrid.appendChild(createElement('p', { className: 'muted', textContent: 'Loading providers\u2026' }));
|
|
304
|
-
card.appendChild(platformGrid);
|
|
305
|
-
|
|
306
|
-
// Manual connection string
|
|
307
|
-
var manual = createElement('div', { className: 'manual-connect' });
|
|
308
|
-
manual.appendChild(createElement('label', { className: 'label-uppercase', textContent: 'Manual Connection' }));
|
|
309
|
-
var manualRow = createElement('div', { className: 'manual-connect-row' });
|
|
310
|
-
var connInput = createElement('input', {
|
|
311
|
-
className: 'input',
|
|
312
|
-
id: 'connect-url',
|
|
313
|
-
type: 'text',
|
|
314
|
-
placeholder: 'postgres://user:pass@host:5432/dbname',
|
|
315
|
-
});
|
|
316
|
-
manualRow.appendChild(connInput);
|
|
317
|
-
var connBtn = createElement('button', { className: 'btn btn-primary', textContent: 'Connect' });
|
|
318
|
-
manualRow.appendChild(connBtn);
|
|
319
|
-
manual.appendChild(manualRow);
|
|
320
|
-
card.appendChild(manual);
|
|
321
|
-
|
|
322
|
-
content.appendChild(card);
|
|
323
|
-
|
|
324
|
-
// --- Detect sources first, then render providers (detected ones get highlighted) ---
|
|
325
|
-
fetchDetectedSources(detectedHint, platformGrid, oauthResult).then(function () {
|
|
326
|
-
fetchAuthProviders(platformGrid, oauthResult);
|
|
327
|
-
});
|
|
328
|
-
|
|
329
|
-
// --- Manual connect handler ---
|
|
330
|
-
connBtn.addEventListener('click', async function () {
|
|
331
|
-
var url = connInput.value.trim();
|
|
332
|
-
if (!url) return;
|
|
333
|
-
connBtn.textContent = 'Connecting\u2026';
|
|
334
|
-
connBtn.disabled = true;
|
|
335
|
-
try {
|
|
336
|
-
var result = await api('POST', '/api/sources', { connection: url });
|
|
337
|
-
var src = result.source || result;
|
|
338
|
-
state.sources = state.sources || [];
|
|
339
|
-
state.sources.push(src);
|
|
340
|
-
saveState();
|
|
341
|
-
updateDbStatus(src);
|
|
342
|
-
goToStep(2);
|
|
343
|
-
} catch (e) {
|
|
344
|
-
connBtn.textContent = 'Connect';
|
|
345
|
-
connBtn.disabled = false;
|
|
346
|
-
var errP = manual.querySelector('.field-error');
|
|
347
|
-
if (errP) errP.remove();
|
|
348
|
-
manual.appendChild(createElement('p', { className: 'field-error', textContent: e.message || 'Connection failed' }));
|
|
349
|
-
}
|
|
350
|
-
});
|
|
351
|
-
}
|
|
352
|
-
|
|
353
|
-
/** Map adapter type to the provider ID for OAuth */
|
|
354
|
-
var ADAPTER_TO_PROVIDER = {
|
|
355
|
-
postgres: 'neon', // default; detected sources refine below
|
|
356
|
-
mysql: 'planetscale',
|
|
357
|
-
duckdb: null, // local file, no OAuth needed
|
|
358
|
-
sqlite: null,
|
|
359
|
-
snowflake: 'snowflake',
|
|
360
|
-
bigquery: 'gcp',
|
|
361
|
-
clickhouse: 'clickhouse',
|
|
362
|
-
databricks: 'databricks',
|
|
363
|
-
mssql: 'azure-sql',
|
|
364
|
-
mongodb: 'mongodb',
|
|
365
|
-
};
|
|
366
|
-
|
|
367
|
-
/** Refine provider from origin hint (e.g. "mcp:claude-code/neon" → neon) */
|
|
368
|
-
function providerFromOrigin(origin, adapter) {
|
|
369
|
-
if (!origin) return ADAPTER_TO_PROVIDER[adapter] || null;
|
|
370
|
-
var o = origin.toLowerCase();
|
|
371
|
-
if (o.includes('neon')) return 'neon';
|
|
372
|
-
if (o.includes('supabase')) return 'supabase';
|
|
373
|
-
if (o.includes('aws') || o.includes('rds')) return 'aws-rds';
|
|
374
|
-
if (o.includes('azure')) return 'azure-sql';
|
|
375
|
-
if (o.includes('gcp') || o.includes('bigquery')) return 'gcp';
|
|
376
|
-
if (o.includes('planetscale')) return 'planetscale';
|
|
377
|
-
if (o.includes('cockroach')) return 'cockroachdb';
|
|
378
|
-
if (o.includes('snowflake')) return 'snowflake';
|
|
379
|
-
if (o.includes('clickhouse')) return 'clickhouse';
|
|
380
|
-
if (o.includes('databricks')) return 'databricks';
|
|
381
|
-
if (o.includes('mongodb') || o.includes('atlas')) return 'mongodb';
|
|
382
|
-
if (o.includes('motherduck') || o.includes('duckdb')) return null;
|
|
383
|
-
return ADAPTER_TO_PROVIDER[adapter] || null;
|
|
384
|
-
}
|
|
385
|
-
|
|
386
|
-
function fetchDetectedSources(container, platformGrid, oauthResult) {
|
|
387
|
-
return api('GET', '/api/sources').then(function (data) {
|
|
388
|
-
var sources = data.sources || data || [];
|
|
389
|
-
container.textContent = '';
|
|
390
|
-
if (sources.length === 0) {
|
|
391
|
-
updateDbStatus(null);
|
|
392
|
-
return;
|
|
393
|
-
}
|
|
394
|
-
|
|
395
|
-
// Group detected sources by provider
|
|
396
|
-
var byProvider = {};
|
|
397
|
-
var localFiles = [];
|
|
398
|
-
sources.forEach(function (src) {
|
|
399
|
-
var prov = providerFromOrigin(src.origin, src.adapter);
|
|
400
|
-
if (!prov) {
|
|
401
|
-
localFiles.push(src);
|
|
402
|
-
} else {
|
|
403
|
-
byProvider[prov] = byProvider[prov] || [];
|
|
404
|
-
byProvider[prov].push(src);
|
|
405
|
-
}
|
|
406
|
-
});
|
|
407
|
-
|
|
408
|
-
// Show detected hint banner
|
|
409
|
-
var hint = createElement('div', { className: 'detected-hint' });
|
|
410
|
-
var hintIcon = createElement('span', { className: 'detected-hint-icon', textContent: '\u{1F50D}' });
|
|
411
|
-
var provNames = Object.keys(byProvider);
|
|
412
|
-
var hintText;
|
|
413
|
-
if (provNames.length > 0) {
|
|
414
|
-
var names = provNames.map(function (p) { return p.charAt(0).toUpperCase() + p.slice(1); });
|
|
415
|
-
hintText = 'We detected ' + names.join(', ') + ' in your IDE configs. Click a provider below to connect securely via OAuth.';
|
|
416
|
-
} else {
|
|
417
|
-
hintText = 'We detected local database files. Use manual connection or select a provider below.';
|
|
418
|
-
}
|
|
419
|
-
hint.appendChild(hintIcon);
|
|
420
|
-
hint.appendChild(createElement('span', { textContent: hintText }));
|
|
421
|
-
container.appendChild(hint);
|
|
422
|
-
|
|
423
|
-
// For local files (duckdb, sqlite), show direct-use cards
|
|
424
|
-
localFiles.forEach(function (src) {
|
|
425
|
-
var card = createElement('div', { className: 'source-card source-card-local' }, [
|
|
426
|
-
createElement('span', { className: 'source-card-name', textContent: src.name || src.adapter }),
|
|
427
|
-
createElement('span', { className: 'source-card-meta', textContent: 'Local file' }),
|
|
428
|
-
createElement('button', { className: 'btn btn-primary', textContent: 'Use This' }),
|
|
429
|
-
]);
|
|
430
|
-
card.querySelector('.btn').addEventListener('click', function () {
|
|
431
|
-
state.sources = state.sources || [];
|
|
432
|
-
state.sources.push(src);
|
|
433
|
-
saveState();
|
|
434
|
-
updateDbStatus(src);
|
|
435
|
-
goToStep(2);
|
|
436
|
-
});
|
|
437
|
-
container.appendChild(card);
|
|
438
|
-
});
|
|
439
|
-
|
|
440
|
-
// Highlight matching providers in the platform grid
|
|
441
|
-
state._detectedProviders = provNames;
|
|
442
|
-
|
|
443
|
-
}).catch(function () {
|
|
444
|
-
container.textContent = '';
|
|
445
|
-
updateDbStatus(null);
|
|
446
|
-
});
|
|
447
|
-
}
|
|
448
|
-
|
|
449
|
-
function fetchAuthProviders(container, oauthResult) {
|
|
450
|
-
api('GET', '/api/auth/providers').then(function (data) {
|
|
451
|
-
var providers = data.providers || data || [];
|
|
452
|
-
// Replace the platform-grid with a plain wrapper for mixed content
|
|
453
|
-
var wrapper = createElement('div', { className: 'connect-providers' });
|
|
454
|
-
container.replaceWith(wrapper);
|
|
455
|
-
|
|
456
|
-
if (providers.length === 0) {
|
|
457
|
-
wrapper.appendChild(createElement('p', { className: 'muted', textContent: 'No OAuth providers available.' }));
|
|
458
|
-
return;
|
|
459
|
-
}
|
|
460
|
-
|
|
461
|
-
var detected = state._detectedProviders || [];
|
|
462
|
-
|
|
463
|
-
// Show detected providers first (highlighted)
|
|
464
|
-
var detectedProvs = [];
|
|
465
|
-
var otherProvs = [];
|
|
466
|
-
providers.forEach(function (prov) {
|
|
467
|
-
if (detected.indexOf(prov.id) !== -1) {
|
|
468
|
-
detectedProvs.push(prov);
|
|
469
|
-
} else {
|
|
470
|
-
otherProvs.push(prov);
|
|
471
|
-
}
|
|
472
|
-
});
|
|
473
|
-
|
|
474
|
-
// Detected providers get prominent cards
|
|
475
|
-
if (detectedProvs.length > 0) {
|
|
476
|
-
var detectedGrid = createElement('div', { className: 'source-cards' });
|
|
477
|
-
detectedProvs.forEach(function (prov) {
|
|
478
|
-
var card = createElement('div', { className: 'source-card source-card-detected' }, [
|
|
479
|
-
createElement('span', { className: 'source-card-badge', textContent: 'Detected' }),
|
|
480
|
-
createElement('span', { className: 'source-card-name', textContent: prov.displayName || prov.display_name || prov.id }),
|
|
481
|
-
createElement('span', { className: 'source-card-meta', textContent: (prov.cliAuthenticated ? 'CLI authenticated' : prov.cliInstalled ? 'CLI installed' : 'OAuth available') }),
|
|
482
|
-
createElement('button', { className: 'btn btn-primary', textContent: 'Connect via OAuth' }),
|
|
483
|
-
]);
|
|
484
|
-
card.querySelector('.btn').addEventListener('click', function () {
|
|
485
|
-
startOAuthFlow(prov, wrapper, oauthResult);
|
|
486
|
-
});
|
|
487
|
-
detectedGrid.appendChild(card);
|
|
488
|
-
});
|
|
489
|
-
wrapper.appendChild(detectedGrid);
|
|
490
|
-
|
|
491
|
-
if (otherProvs.length > 0) {
|
|
492
|
-
wrapper.appendChild(createElement('div', { className: 'section-divider' }, ['Other providers']));
|
|
493
|
-
}
|
|
494
|
-
}
|
|
495
|
-
|
|
496
|
-
// Other providers as button grid
|
|
497
|
-
if (otherProvs.length > 0) {
|
|
498
|
-
var grid = createElement('div', { className: 'platform-grid' });
|
|
499
|
-
otherProvs.forEach(function (prov) {
|
|
500
|
-
var btn = createElement('button', { className: 'platform-btn', textContent: prov.displayName || prov.display_name || prov.name || prov.id });
|
|
501
|
-
btn.addEventListener('click', function () {
|
|
502
|
-
startOAuthFlow(prov, wrapper, oauthResult);
|
|
503
|
-
});
|
|
504
|
-
grid.appendChild(btn);
|
|
505
|
-
});
|
|
506
|
-
wrapper.appendChild(grid);
|
|
507
|
-
}
|
|
508
|
-
}).catch(function () {
|
|
509
|
-
container.textContent = '';
|
|
510
|
-
container.appendChild(createElement('p', { className: 'muted', textContent: 'Could not load providers.' }));
|
|
511
|
-
});
|
|
512
|
-
}
|
|
513
|
-
|
|
514
|
-
async function startOAuthFlow(provider, providerWrapper, oauthResult) {
|
|
515
|
-
// Disable all buttons
|
|
516
|
-
providerWrapper.querySelectorAll('.platform-btn').forEach(function (b) { b.disabled = true; });
|
|
517
|
-
providerWrapper.querySelectorAll('.source-card .btn').forEach(function (b) { b.disabled = true; });
|
|
518
|
-
|
|
519
|
-
// Show loading in the oauth result area (right after detected cards)
|
|
520
|
-
oauthResult.textContent = '';
|
|
521
|
-
oauthResult.appendChild(createElement('p', { className: 'muted', textContent: 'Connecting to ' + (provider.displayName || provider.display_name || provider.id) + '\u2026 A browser window may open for authentication.' }));
|
|
522
|
-
|
|
523
|
-
try {
|
|
524
|
-
var data = await api('POST', '/api/auth/start', { provider: provider.id });
|
|
525
|
-
var databases = data.databases || data || [];
|
|
526
|
-
oauthResult.textContent = '';
|
|
527
|
-
|
|
528
|
-
if (databases.length === 0) {
|
|
529
|
-
oauthResult.appendChild(createElement('p', { className: 'muted', textContent: 'No databases found for this provider.' }));
|
|
530
|
-
providerWrapper.querySelectorAll('.platform-btn').forEach(function (b) { b.disabled = false; });
|
|
531
|
-
providerWrapper.querySelectorAll('.source-card .btn').forEach(function (b) { b.disabled = false; });
|
|
532
|
-
return;
|
|
533
|
-
}
|
|
534
|
-
|
|
535
|
-
// Hide the other providers / platform grid — show only database results
|
|
536
|
-
providerWrapper.style.display = 'none';
|
|
537
|
-
|
|
538
|
-
var oauthHeader = createElement('div', { className: 'oauth-result-header' });
|
|
539
|
-
oauthHeader.appendChild(createElement('label', { className: 'label-uppercase', textContent: 'Select a database from ' + (provider.displayName || provider.display_name || provider.id) }));
|
|
540
|
-
var backLink = createElement('button', { className: 'btn btn-secondary btn-sm', textContent: '\u2190 Back to providers' });
|
|
541
|
-
backLink.addEventListener('click', function () {
|
|
542
|
-
oauthResult.textContent = '';
|
|
543
|
-
providerWrapper.style.display = '';
|
|
544
|
-
providerWrapper.querySelectorAll('.platform-btn').forEach(function (b) { b.disabled = false; });
|
|
545
|
-
providerWrapper.querySelectorAll('.source-card .btn').forEach(function (b) { b.disabled = false; });
|
|
546
|
-
});
|
|
547
|
-
oauthHeader.appendChild(backLink);
|
|
548
|
-
oauthResult.appendChild(oauthHeader);
|
|
549
|
-
|
|
550
|
-
var dbGrid = createElement('div', { className: 'source-cards' });
|
|
551
|
-
databases.forEach(function (db) {
|
|
552
|
-
var m = db.metadata || {};
|
|
553
|
-
// Title: "project / branch" if available, else just db name
|
|
554
|
-
var title = m.project ? m.project + ' / ' + (m.branch || 'main') : (db.name || db.database);
|
|
555
|
-
// Subtitle line 1: db name + adapter + region + org
|
|
556
|
-
var parts = [db.name || db.database];
|
|
557
|
-
if (db.adapter) parts.push(db.adapter);
|
|
558
|
-
if (m.region) parts.push(m.region);
|
|
559
|
-
if (m.org && m.org !== 'Personal') parts.push(m.org);
|
|
560
|
-
else if (m.org === 'Personal') parts.push('personal');
|
|
561
|
-
var line1 = parts.join(' \u2022 ');
|
|
562
|
-
// Subtitle line 2: host (truncated)
|
|
563
|
-
var line2 = db.host || '';
|
|
564
|
-
|
|
565
|
-
var dbCard = createElement('div', { className: 'source-card' }, [
|
|
566
|
-
createElement('span', { className: 'source-card-name', textContent: title }),
|
|
567
|
-
createElement('span', { className: 'source-card-meta', textContent: line1 }),
|
|
568
|
-
line2 ? createElement('span', { className: 'source-card-host', textContent: line2 }) : null,
|
|
569
|
-
createElement('button', { className: 'btn btn-primary', textContent: 'Use This' }),
|
|
570
|
-
].filter(Boolean));
|
|
571
|
-
dbCard.querySelector('.btn').addEventListener('click', async function () {
|
|
572
|
-
try {
|
|
573
|
-
await api('POST', '/api/auth/select-db', { provider: provider.id, database: db });
|
|
574
|
-
state.sources = state.sources || [];
|
|
575
|
-
state.sources.push(db);
|
|
576
|
-
saveState();
|
|
577
|
-
updateDbStatus(db);
|
|
578
|
-
goToStep(2);
|
|
579
|
-
} catch (e) {
|
|
580
|
-
oauthResult.appendChild(createElement('p', { className: 'field-error', textContent: e.message || 'Failed to select database' }));
|
|
581
|
-
}
|
|
582
|
-
});
|
|
583
|
-
dbGrid.appendChild(dbCard);
|
|
584
|
-
});
|
|
585
|
-
oauthResult.appendChild(dbGrid);
|
|
586
|
-
} catch (e) {
|
|
587
|
-
oauthResult.textContent = '';
|
|
588
|
-
oauthResult.appendChild(createElement('p', { className: 'field-error', textContent: e.message || 'OAuth flow failed' }));
|
|
589
|
-
providerWrapper.querySelectorAll('.platform-btn').forEach(function (b) { b.disabled = false; });
|
|
590
|
-
providerWrapper.querySelectorAll('.source-card .btn').forEach(function (b) { b.disabled = false; });
|
|
591
|
-
}
|
|
592
|
-
}
|
|
593
|
-
|
|
594
|
-
// ---- Step 2: Define ----
|
|
595
|
-
|
|
596
|
-
function renderDefineStep() {
|
|
597
|
-
var content = document.getElementById('wizard-content');
|
|
598
|
-
if (!content) return;
|
|
599
|
-
|
|
600
|
-
var card = createElement('div', { className: 'card' });
|
|
601
|
-
|
|
602
|
-
card.appendChild(createElement('h2', { textContent: 'Define Your Data Product' }));
|
|
603
|
-
card.appendChild(createElement('p', { className: 'muted', textContent: 'Tell us about your data product. This metadata helps AI agents understand what they\u2019re working with.' }));
|
|
604
|
-
|
|
605
|
-
var form = createElement('div', { className: 'define-form' });
|
|
606
|
-
|
|
607
|
-
// Product Name (full width, required)
|
|
608
|
-
var nameGroup = createElement('div', { className: 'field full-width' });
|
|
609
|
-
nameGroup.appendChild(createElement('label', { htmlFor: 'product_name', textContent: 'Product Name *' }));
|
|
610
|
-
nameGroup.appendChild(createElement('input', {
|
|
611
|
-
className: 'input',
|
|
612
|
-
id: 'product_name',
|
|
613
|
-
type: 'text',
|
|
614
|
-
placeholder: 'my-data-product',
|
|
615
|
-
}));
|
|
616
|
-
nameGroup.appendChild(createElement('p', { className: 'hint', textContent: 'Alphanumeric, hyphens, and underscores only.' }));
|
|
617
|
-
form.appendChild(nameGroup);
|
|
618
|
-
|
|
619
|
-
// Description (full width, required)
|
|
620
|
-
var descGroup = createElement('div', { className: 'field full-width' });
|
|
621
|
-
descGroup.appendChild(createElement('label', { htmlFor: 'description', textContent: 'Description *' }));
|
|
622
|
-
var descInput = createElement('textarea', {
|
|
623
|
-
className: 'textarea',
|
|
624
|
-
id: 'description',
|
|
625
|
-
placeholder: 'What does this data product provide?',
|
|
626
|
-
});
|
|
627
|
-
descGroup.appendChild(descInput);
|
|
628
|
-
form.appendChild(descGroup);
|
|
629
|
-
|
|
630
|
-
// Owner Name (left column)
|
|
631
|
-
var ownerNameGroup = createElement('div', { className: 'field' });
|
|
632
|
-
ownerNameGroup.appendChild(createElement('label', { htmlFor: 'owner_name', textContent: 'Owner Name' }));
|
|
633
|
-
ownerNameGroup.appendChild(createElement('input', {
|
|
634
|
-
className: 'input',
|
|
635
|
-
id: 'owner_name',
|
|
636
|
-
type: 'text',
|
|
637
|
-
placeholder: 'Jane Doe',
|
|
638
|
-
}));
|
|
639
|
-
form.appendChild(ownerNameGroup);
|
|
640
|
-
|
|
641
|
-
// Team (right column)
|
|
642
|
-
var teamGroup = createElement('div', { className: 'field' });
|
|
643
|
-
teamGroup.appendChild(createElement('label', { htmlFor: 'owner_team', textContent: 'Team' }));
|
|
644
|
-
teamGroup.appendChild(createElement('input', {
|
|
645
|
-
className: 'input',
|
|
646
|
-
id: 'owner_team',
|
|
647
|
-
type: 'text',
|
|
648
|
-
placeholder: 'Data Engineering',
|
|
649
|
-
}));
|
|
650
|
-
form.appendChild(teamGroup);
|
|
651
|
-
|
|
652
|
-
// Email (left column)
|
|
653
|
-
var emailGroup = createElement('div', { className: 'field' });
|
|
654
|
-
emailGroup.appendChild(createElement('label', { htmlFor: 'owner_email', textContent: 'Email' }));
|
|
655
|
-
emailGroup.appendChild(createElement('input', {
|
|
656
|
-
className: 'input',
|
|
657
|
-
id: 'owner_email',
|
|
658
|
-
type: 'text',
|
|
659
|
-
placeholder: 'jane@example.com',
|
|
660
|
-
}));
|
|
661
|
-
form.appendChild(emailGroup);
|
|
662
|
-
|
|
663
|
-
// Sensitivity (right column)
|
|
664
|
-
var sensGroup = createElement('div', { className: 'field' });
|
|
665
|
-
sensGroup.appendChild(createElement('label', { htmlFor: 'sensitivity', textContent: 'Sensitivity' }));
|
|
666
|
-
var sensSelect = createElement('select', { className: 'select', id: 'sensitivity' });
|
|
667
|
-
[
|
|
668
|
-
{ value: 'public', text: 'Public' },
|
|
669
|
-
{ value: 'internal', text: 'Internal' },
|
|
670
|
-
{ value: 'confidential', text: 'Confidential' },
|
|
671
|
-
{ value: 'restricted', text: 'Restricted' },
|
|
672
|
-
].forEach(function (opt) {
|
|
673
|
-
var option = createElement('option', { value: opt.value, textContent: opt.text });
|
|
674
|
-
sensSelect.appendChild(option);
|
|
675
|
-
});
|
|
676
|
-
sensSelect.value = 'internal';
|
|
677
|
-
sensGroup.appendChild(sensSelect);
|
|
678
|
-
form.appendChild(sensGroup);
|
|
679
|
-
|
|
680
|
-
// Action buttons (full width)
|
|
681
|
-
var actions = createElement('div', { className: 'define-actions' });
|
|
682
|
-
|
|
683
|
-
var backBtn = createElement('button', { className: 'btn btn-secondary', textContent: 'Back' });
|
|
684
|
-
backBtn.addEventListener('click', function () { goToStep(1); });
|
|
685
|
-
actions.appendChild(backBtn);
|
|
686
|
-
|
|
687
|
-
var continueBtn = createElement('button', { className: 'btn btn-primary', textContent: 'Continue' });
|
|
688
|
-
continueBtn.addEventListener('click', async function () {
|
|
689
|
-
clearErrors();
|
|
690
|
-
var valid = true;
|
|
691
|
-
|
|
692
|
-
var productName = document.getElementById('product_name').value.trim();
|
|
693
|
-
var description = document.getElementById('description').value.trim();
|
|
694
|
-
|
|
695
|
-
if (!productName) {
|
|
696
|
-
showError('product_name', 'Product name is required.');
|
|
697
|
-
valid = false;
|
|
698
|
-
} else if (!/^[a-zA-Z0-9_-]+$/.test(productName)) {
|
|
699
|
-
showError('product_name', 'Only letters, numbers, hyphens, and underscores allowed.');
|
|
700
|
-
valid = false;
|
|
701
|
-
}
|
|
702
|
-
|
|
703
|
-
if (!description) {
|
|
704
|
-
showError('description', 'Description is required.');
|
|
705
|
-
valid = false;
|
|
706
|
-
}
|
|
707
|
-
|
|
708
|
-
if (!valid) return;
|
|
709
|
-
|
|
710
|
-
state.brief.product_name = productName;
|
|
711
|
-
state.brief.description = description;
|
|
712
|
-
state.brief.owner.name = document.getElementById('owner_name').value.trim();
|
|
713
|
-
state.brief.owner.team = document.getElementById('owner_team').value.trim();
|
|
714
|
-
state.brief.owner.email = document.getElementById('owner_email').value.trim();
|
|
715
|
-
state.brief.sensitivity = document.getElementById('sensitivity').value;
|
|
716
|
-
saveState();
|
|
717
|
-
|
|
718
|
-
continueBtn.textContent = 'Saving\u2026';
|
|
719
|
-
continueBtn.disabled = true;
|
|
720
|
-
try {
|
|
721
|
-
await api('POST', '/api/brief', state.brief);
|
|
722
|
-
goToStep(3);
|
|
723
|
-
} catch (e) {
|
|
724
|
-
continueBtn.textContent = 'Continue';
|
|
725
|
-
continueBtn.disabled = false;
|
|
726
|
-
var errP = createElement('p', { className: 'field-error', textContent: e.message || 'Failed to save. Please try again.' });
|
|
727
|
-
actions.appendChild(errP);
|
|
728
|
-
}
|
|
729
|
-
});
|
|
730
|
-
actions.appendChild(continueBtn);
|
|
731
|
-
form.appendChild(actions);
|
|
732
|
-
|
|
733
|
-
card.appendChild(form);
|
|
734
|
-
content.appendChild(card);
|
|
735
|
-
|
|
736
|
-
// Pre-fill from saved state first
|
|
737
|
-
if (state.brief.product_name) document.getElementById('product_name').value = state.brief.product_name;
|
|
738
|
-
if (state.brief.description) document.getElementById('description').value = state.brief.description;
|
|
739
|
-
if (state.brief.owner.name) document.getElementById('owner_name').value = state.brief.owner.name;
|
|
740
|
-
if (state.brief.owner.team) document.getElementById('owner_team').value = state.brief.owner.team;
|
|
741
|
-
if (state.brief.owner.email) document.getElementById('owner_email').value = state.brief.owner.email;
|
|
742
|
-
if (state.brief.sensitivity) document.getElementById('sensitivity').value = state.brief.sensitivity;
|
|
743
|
-
|
|
744
|
-
// Auto-suggest from selected source (if fields are still empty)
|
|
745
|
-
var hasAnyField = state.brief.product_name || state.brief.description || state.brief.owner.name;
|
|
746
|
-
if (!hasAnyField && state.sources && state.sources.length > 0) {
|
|
747
|
-
var suggestNote = createElement('p', { className: 'muted suggest-loading', textContent: 'Auto-filling from your database\u2026' });
|
|
748
|
-
card.insertBefore(suggestNote, form);
|
|
749
|
-
|
|
750
|
-
api('POST', '/api/suggest-brief', { source: state.sources[0] }).then(function (data) {
|
|
751
|
-
suggestNote.remove();
|
|
752
|
-
// Only fill empty fields
|
|
753
|
-
var fields = [
|
|
754
|
-
{ id: 'product_name', val: data.product_name, stateKey: 'product_name' },
|
|
755
|
-
{ id: 'description', val: data.description, stateKey: 'description' },
|
|
756
|
-
{ id: 'owner_name', val: data.owner && data.owner.name, stateKey: null },
|
|
757
|
-
{ id: 'owner_team', val: data.owner && data.owner.team, stateKey: null },
|
|
758
|
-
{ id: 'owner_email', val: data.owner && data.owner.email, stateKey: null },
|
|
759
|
-
{ id: 'sensitivity', val: data.sensitivity, stateKey: 'sensitivity' },
|
|
760
|
-
];
|
|
761
|
-
fields.forEach(function (f) {
|
|
762
|
-
var el = document.getElementById(f.id);
|
|
763
|
-
if (el && !el.value && f.val) {
|
|
764
|
-
el.value = f.val;
|
|
765
|
-
}
|
|
766
|
-
});
|
|
767
|
-
}).catch(function () {
|
|
768
|
-
suggestNote.textContent = '';
|
|
769
|
-
});
|
|
770
|
-
}
|
|
771
|
-
}
|
|
772
|
-
|
|
773
|
-
// ---- Step 3: Scaffold ----
|
|
774
|
-
|
|
775
|
-
var SCAFFOLD_STAGES = [
|
|
776
|
-
{ key: 'introspect', label: 'Extracting schema from database...' },
|
|
777
|
-
{ key: 'scaffold', label: 'Building semantic plane files...' },
|
|
778
|
-
{ key: 'verify', label: 'Validating semantic plane...' },
|
|
779
|
-
{ key: 'autofix', label: 'Fixing any issues...' },
|
|
780
|
-
{ key: 'agent-instructions', label: 'Generating agent instructions...' },
|
|
781
|
-
];
|
|
782
|
-
|
|
783
|
-
function renderScaffoldStep() {
|
|
784
|
-
var content = document.getElementById('wizard-content');
|
|
785
|
-
if (!content) return;
|
|
786
|
-
|
|
787
|
-
var card = createElement('div', { className: 'card' });
|
|
788
|
-
|
|
789
|
-
card.appendChild(createElement('h2', { textContent: 'Building Your Semantic Plane' }));
|
|
790
|
-
card.appendChild(createElement('p', { className: 'muted', textContent: 'Connecting to your database and extracting schema metadata. This creates a Bronze-tier semantic plane.' }));
|
|
791
|
-
|
|
792
|
-
// Stage rows container
|
|
793
|
-
var stagesContainer = createElement('div', { className: 'scaffold-stages', id: 'scaffold-stages' });
|
|
794
|
-
SCAFFOLD_STAGES.forEach(function (stage) {
|
|
795
|
-
var row = createElement('div', { className: 'stage-row', id: 'stage-' + stage.key, 'data-stage': stage.key }, [
|
|
796
|
-
createElement('span', { className: 'stage-dot' }),
|
|
797
|
-
createElement('span', { className: 'stage-name', textContent: stage.label }),
|
|
798
|
-
]);
|
|
799
|
-
stagesContainer.appendChild(row);
|
|
800
|
-
});
|
|
801
|
-
card.appendChild(stagesContainer);
|
|
802
|
-
|
|
803
|
-
// Error area
|
|
804
|
-
var errorArea = createElement('div', { id: 'scaffold-error' });
|
|
805
|
-
card.appendChild(errorArea);
|
|
806
|
-
|
|
807
|
-
// Action area (Start / Retry button)
|
|
808
|
-
var actionArea = createElement('div', { className: 'step-actions', id: 'scaffold-actions' });
|
|
809
|
-
|
|
810
|
-
var backBtn = createElement('button', { className: 'btn btn-secondary', textContent: 'Back' });
|
|
811
|
-
backBtn.addEventListener('click', function () { goToStep(2); });
|
|
812
|
-
actionArea.appendChild(backBtn);
|
|
813
|
-
|
|
814
|
-
// If we already have a pipelineId, resume polling; otherwise show Start button
|
|
815
|
-
if (state.pipelineId) {
|
|
816
|
-
actionArea.appendChild(createElement('span', { className: 'muted', textContent: 'Build in progress...' }));
|
|
817
|
-
card.appendChild(actionArea);
|
|
818
|
-
content.appendChild(card);
|
|
819
|
-
startScaffoldPolling();
|
|
820
|
-
} else {
|
|
821
|
-
var startBtn = createElement('button', { className: 'btn btn-primary', textContent: 'Start Build', id: 'scaffold-start-btn' });
|
|
822
|
-
startBtn.addEventListener('click', function () { startScaffoldBuild(startBtn); });
|
|
823
|
-
actionArea.appendChild(startBtn);
|
|
824
|
-
card.appendChild(actionArea);
|
|
825
|
-
content.appendChild(card);
|
|
826
|
-
}
|
|
827
|
-
}
|
|
828
|
-
|
|
829
|
-
async function startScaffoldBuild(btn) {
|
|
830
|
-
btn.textContent = 'Starting...';
|
|
831
|
-
btn.disabled = true;
|
|
832
|
-
|
|
833
|
-
var errorArea = document.getElementById('scaffold-error');
|
|
834
|
-
if (errorArea) errorArea.textContent = '';
|
|
835
|
-
|
|
836
|
-
var body = {
|
|
837
|
-
productName: state.brief.product_name,
|
|
838
|
-
targetTier: 'bronze',
|
|
839
|
-
};
|
|
840
|
-
if (state.sources && state.sources[0]) {
|
|
841
|
-
var src = state.sources[0];
|
|
842
|
-
body.dataSource = (typeof src === 'string' ? src : src.name || src.database || '').replace(/[^a-zA-Z0-9_-]/g, '_');
|
|
843
|
-
}
|
|
844
|
-
|
|
845
|
-
try {
|
|
846
|
-
var result = await api('POST', '/api/pipeline/start', body);
|
|
847
|
-
state.pipelineId = result.id;
|
|
848
|
-
saveState();
|
|
849
|
-
btn.textContent = 'Building...';
|
|
850
|
-
startScaffoldPolling();
|
|
851
|
-
} catch (e) {
|
|
852
|
-
btn.textContent = 'Start Build';
|
|
853
|
-
btn.disabled = false;
|
|
854
|
-
var errorArea = document.getElementById('scaffold-error');
|
|
855
|
-
if (errorArea) {
|
|
856
|
-
errorArea.textContent = '';
|
|
857
|
-
errorArea.appendChild(createElement('p', { className: 'field-error', textContent: e.message || 'Failed to start build.' }));
|
|
858
|
-
}
|
|
859
|
-
}
|
|
860
|
-
}
|
|
861
|
-
|
|
862
|
-
function startScaffoldPolling() {
|
|
863
|
-
if (state.pollTimer) { clearInterval(state.pollTimer); state.pollTimer = null; }
|
|
864
|
-
|
|
865
|
-
async function poll() {
|
|
866
|
-
if (!state.pipelineId) return;
|
|
867
|
-
try {
|
|
868
|
-
var status = await api('GET', '/api/pipeline/status/' + state.pipelineId);
|
|
869
|
-
var stages = status.stages || [];
|
|
870
|
-
var hasError = false;
|
|
871
|
-
var allDone = true;
|
|
872
|
-
|
|
873
|
-
SCAFFOLD_STAGES.forEach(function (def) {
|
|
874
|
-
var row = document.getElementById('stage-' + def.key);
|
|
875
|
-
if (!row) return;
|
|
876
|
-
|
|
877
|
-
var match = null;
|
|
878
|
-
for (var i = 0; i < stages.length; i++) {
|
|
879
|
-
if (stages[i].name === def.key) { match = stages[i]; break; }
|
|
880
|
-
}
|
|
881
|
-
|
|
882
|
-
var dot = row.querySelector('.stage-dot');
|
|
883
|
-
// Reset classes
|
|
884
|
-
dot.className = 'stage-dot';
|
|
885
|
-
|
|
886
|
-
// Remove any previous summary/error elements
|
|
887
|
-
var oldSummary = row.querySelector('.stage-summary');
|
|
888
|
-
if (oldSummary) oldSummary.remove();
|
|
889
|
-
var oldError = row.querySelector('.stage-error');
|
|
890
|
-
if (oldError) oldError.remove();
|
|
891
|
-
|
|
892
|
-
if (!match || match.status === 'pending') {
|
|
893
|
-
allDone = false;
|
|
894
|
-
} else if (match.status === 'running') {
|
|
895
|
-
dot.classList.add('running');
|
|
896
|
-
allDone = false;
|
|
897
|
-
} else if (match.status === 'done') {
|
|
898
|
-
dot.classList.add('done');
|
|
899
|
-
if (match.summary) {
|
|
900
|
-
row.appendChild(createElement('span', { className: 'stage-summary', textContent: match.summary }));
|
|
901
|
-
}
|
|
902
|
-
} else if (match.status === 'error') {
|
|
903
|
-
dot.classList.add('error');
|
|
904
|
-
hasError = true;
|
|
905
|
-
allDone = false;
|
|
906
|
-
if (match.error) {
|
|
907
|
-
row.appendChild(createElement('span', { className: 'stage-error', textContent: match.error }));
|
|
908
|
-
}
|
|
909
|
-
}
|
|
910
|
-
});
|
|
911
|
-
|
|
912
|
-
if (hasError) {
|
|
913
|
-
if (state.pollTimer) { clearInterval(state.pollTimer); state.pollTimer = null; }
|
|
914
|
-
showScaffoldError(status.error || 'A pipeline stage failed.');
|
|
915
|
-
} else if (allDone && stages.length > 0) {
|
|
916
|
-
if (state.pollTimer) { clearInterval(state.pollTimer); state.pollTimer = null; }
|
|
917
|
-
goToStep(4);
|
|
918
|
-
}
|
|
919
|
-
} catch (e) {
|
|
920
|
-
// Network error — keep polling, it may recover
|
|
921
|
-
}
|
|
922
|
-
}
|
|
923
|
-
|
|
924
|
-
poll();
|
|
925
|
-
state.pollTimer = setInterval(poll, 2000);
|
|
926
|
-
}
|
|
927
|
-
|
|
928
|
-
function showScaffoldError(msg) {
|
|
929
|
-
var errorArea = document.getElementById('scaffold-error');
|
|
930
|
-
if (!errorArea) return;
|
|
931
|
-
errorArea.textContent = '';
|
|
932
|
-
errorArea.appendChild(createElement('p', { className: 'field-error', textContent: msg }));
|
|
933
|
-
|
|
934
|
-
var actions = document.getElementById('scaffold-actions');
|
|
935
|
-
if (!actions) return;
|
|
936
|
-
// Remove old start/building button if any
|
|
937
|
-
var oldBtn = actions.querySelector('.btn-primary');
|
|
938
|
-
if (oldBtn) oldBtn.remove();
|
|
939
|
-
var oldMuted = actions.querySelector('.muted');
|
|
940
|
-
if (oldMuted) oldMuted.remove();
|
|
941
|
-
|
|
942
|
-
var retryBtn = createElement('button', { className: 'btn btn-primary', textContent: 'Retry' });
|
|
943
|
-
retryBtn.addEventListener('click', function () {
|
|
944
|
-
state.pipelineId = null;
|
|
945
|
-
saveState();
|
|
946
|
-
// Reset stage dots
|
|
947
|
-
SCAFFOLD_STAGES.forEach(function (def) {
|
|
948
|
-
var row = document.getElementById('stage-' + def.key);
|
|
949
|
-
if (!row) return;
|
|
950
|
-
var dot = row.querySelector('.stage-dot');
|
|
951
|
-
if (dot) dot.className = 'stage-dot';
|
|
952
|
-
var s = row.querySelector('.stage-summary');
|
|
953
|
-
if (s) s.remove();
|
|
954
|
-
var e = row.querySelector('.stage-error');
|
|
955
|
-
if (e) e.remove();
|
|
956
|
-
});
|
|
957
|
-
errorArea.textContent = '';
|
|
958
|
-
startScaffoldBuild(retryBtn);
|
|
959
|
-
});
|
|
960
|
-
actions.appendChild(retryBtn);
|
|
961
|
-
}
|
|
962
|
-
|
|
963
|
-
// ---- Step 4: Checkpoint ----
|
|
964
|
-
|
|
965
|
-
function renderCheckpointStep() {
|
|
966
|
-
var content = document.getElementById('wizard-content');
|
|
967
|
-
if (!content) return;
|
|
968
|
-
|
|
969
|
-
var card = createElement('div', { className: 'card checkpoint-card' });
|
|
970
|
-
|
|
971
|
-
card.appendChild(createElement('h2', { textContent: 'Bronze Tier Achieved' }));
|
|
972
|
-
|
|
973
|
-
// Tier scorecard
|
|
974
|
-
var scorecard = createElement('div', { className: 'tier-scorecard' });
|
|
975
|
-
|
|
976
|
-
// Bronze (achieved)
|
|
977
|
-
var bronzeRow = createElement('div', { className: 'tier-row achieved' }, [
|
|
978
|
-
createElement('span', { className: 'tier-label', textContent: 'Bronze' }),
|
|
979
|
-
createElement('span', { className: 'tier-desc', textContent: 'Schema metadata, table/column names, types, row counts' }),
|
|
980
|
-
]);
|
|
981
|
-
scorecard.appendChild(bronzeRow);
|
|
982
|
-
|
|
983
|
-
// Silver
|
|
984
|
-
var silverRow = createElement('div', { className: 'tier-row' }, [
|
|
985
|
-
createElement('span', { className: 'tier-label', textContent: 'Silver' }),
|
|
986
|
-
createElement('span', { className: 'tier-desc', textContent: 'Column descriptions, sample values, trust tags' }),
|
|
987
|
-
]);
|
|
988
|
-
scorecard.appendChild(silverRow);
|
|
989
|
-
|
|
990
|
-
// Gold
|
|
991
|
-
var goldRow = createElement('div', { className: 'tier-row' }, [
|
|
992
|
-
createElement('span', { className: 'tier-label', textContent: 'Gold' }),
|
|
993
|
-
createElement('span', { className: 'tier-desc', textContent: 'Join rules, grain statements, semantic roles, golden queries, guardrail filters' }),
|
|
994
|
-
]);
|
|
995
|
-
scorecard.appendChild(goldRow);
|
|
996
|
-
|
|
997
|
-
card.appendChild(scorecard);
|
|
998
|
-
|
|
999
|
-
// Explanatory text
|
|
1000
|
-
card.appendChild(createElement('p', { className: 'checkpoint-explain', textContent: 'Your semantic plane has basic schema metadata. AI tools can use this now, but with Gold tier they\'ll understand join relationships, business descriptions, and query patterns.' }));
|
|
1001
|
-
|
|
1002
|
-
// CTA buttons
|
|
1003
|
-
var ctas = createElement('div', { className: 'checkpoint-ctas' });
|
|
1004
|
-
|
|
1005
|
-
var serveBtn = createElement('button', { className: 'btn btn-secondary', textContent: 'Start MCP Server' });
|
|
1006
|
-
serveBtn.addEventListener('click', function () { goToStep(6); });
|
|
1007
|
-
ctas.appendChild(serveBtn);
|
|
1008
|
-
|
|
1009
|
-
var goldBtn = createElement('button', { className: 'btn btn-primary', textContent: 'Continue to Gold' });
|
|
1010
|
-
goldBtn.addEventListener('click', function () { goToStep(5); });
|
|
1011
|
-
ctas.appendChild(goldBtn);
|
|
1012
|
-
|
|
1013
|
-
card.appendChild(ctas);
|
|
1014
|
-
content.appendChild(card);
|
|
1015
|
-
}
|
|
1016
|
-
|
|
1017
|
-
// ---- Step 5: Enrich ----
|
|
1018
|
-
|
|
1019
|
-
var ENRICH_REQUIREMENTS = [
|
|
1020
|
-
{ key: 'column-descriptions', label: 'Column descriptions', initial: '0/45 columns' },
|
|
1021
|
-
{ key: 'sample-values', label: 'Sample values', initial: '0/45 columns' },
|
|
1022
|
-
{ key: 'join-rules', label: 'Join rules', initial: '0/0' },
|
|
1023
|
-
{ key: 'grain-statements', label: 'Grain statements', initial: '0/0' },
|
|
1024
|
-
{ key: 'semantic-roles', label: 'Semantic roles', initial: '0/0' },
|
|
1025
|
-
{ key: 'golden-queries', label: 'Golden queries', initial: '0/0' },
|
|
1026
|
-
{ key: 'guardrail-filters', label: 'Guardrail filters', initial: '0/0' },
|
|
1027
|
-
];
|
|
1028
|
-
|
|
1029
|
-
function renderEnrichStep() {
|
|
1030
|
-
var content = document.getElementById('wizard-content');
|
|
1031
|
-
if (!content) return;
|
|
1032
|
-
|
|
1033
|
-
var card = createElement('div', { className: 'card' });
|
|
1034
|
-
|
|
1035
|
-
card.appendChild(createElement('h2', { textContent: 'Enriching to Gold' }));
|
|
1036
|
-
card.appendChild(createElement('p', { className: 'muted', textContent: 'RunContext is analyzing your schema to add descriptions, join rules, and query patterns.' }));
|
|
1037
|
-
|
|
1038
|
-
// Start Enrichment button area
|
|
1039
|
-
var startArea = createElement('div', { className: 'step-actions', id: 'enrich-start-area' });
|
|
1040
|
-
var backBtn = createElement('button', { className: 'btn btn-secondary', textContent: 'Back' });
|
|
1041
|
-
backBtn.addEventListener('click', function () { goToStep(4); });
|
|
1042
|
-
startArea.appendChild(backBtn);
|
|
1043
|
-
|
|
1044
|
-
var startBtn = createElement('button', { className: 'btn btn-primary', textContent: 'Start Enrichment', id: 'enrich-start-btn' });
|
|
1045
|
-
startBtn.addEventListener('click', function () { startEnrichment(startBtn); });
|
|
1046
|
-
startArea.appendChild(startBtn);
|
|
1047
|
-
card.appendChild(startArea);
|
|
1048
|
-
|
|
1049
|
-
// Dashboard (always visible — shows checklist pre-enrichment)
|
|
1050
|
-
var dashboard = createElement('div', { className: 'enrich-dashboard', id: 'enrich-dashboard' });
|
|
1051
|
-
|
|
1052
|
-
// Top panel: Requirements checklist
|
|
1053
|
-
var checklist = createElement('div', { className: 'enrich-checklist' });
|
|
1054
|
-
ENRICH_REQUIREMENTS.forEach(function (req) {
|
|
1055
|
-
var row = createElement('div', { className: 'enrich-row', id: 'enrich-req-' + req.key });
|
|
1056
|
-
|
|
1057
|
-
var header = createElement('div', { className: 'enrich-row-header' });
|
|
1058
|
-
header.appendChild(createElement('span', { className: 'stage-dot' }));
|
|
1059
|
-
header.appendChild(createElement('span', { className: 'enrich-req-name', textContent: req.label }));
|
|
1060
|
-
header.appendChild(createElement('span', { className: 'enrich-progress', textContent: req.initial }));
|
|
1061
|
-
header.appendChild(createElement('span', { className: 'enrich-arrow', textContent: '\u25B6' }));
|
|
1062
|
-
|
|
1063
|
-
header.addEventListener('click', function () {
|
|
1064
|
-
row.classList.toggle('expanded');
|
|
1065
|
-
});
|
|
1066
|
-
|
|
1067
|
-
var detail = createElement('div', { className: 'enrich-row-detail' }, [
|
|
1068
|
-
'Details will appear as enrichment progresses.',
|
|
1069
|
-
]);
|
|
1070
|
-
|
|
1071
|
-
row.appendChild(header);
|
|
1072
|
-
row.appendChild(detail);
|
|
1073
|
-
checklist.appendChild(row);
|
|
1074
|
-
});
|
|
1075
|
-
dashboard.appendChild(checklist);
|
|
1076
|
-
|
|
1077
|
-
// Bottom panel: Activity log
|
|
1078
|
-
var logSection = createElement('div', { className: 'activity-log' });
|
|
1079
|
-
logSection.appendChild(createElement('div', { className: 'activity-log-title', textContent: 'Activity Log' }));
|
|
1080
|
-
var logContainer = createElement('div', { id: 'activity-log' });
|
|
1081
|
-
logContainer.appendChild(createElement('div', { className: 'log-entry' }, [
|
|
1082
|
-
createElement('span', { className: 'log-time', textContent: new Date().toLocaleTimeString() }),
|
|
1083
|
-
createElement('span', {}, [' Waiting for enrichment to start...']),
|
|
1084
|
-
]));
|
|
1085
|
-
logSection.appendChild(logContainer);
|
|
1086
|
-
dashboard.appendChild(logSection);
|
|
1087
|
-
|
|
1088
|
-
// Error area
|
|
1089
|
-
var errorArea = createElement('div', { id: 'enrich-error' });
|
|
1090
|
-
dashboard.appendChild(errorArea);
|
|
1091
|
-
|
|
1092
|
-
card.appendChild(dashboard);
|
|
1093
|
-
content.appendChild(card);
|
|
1094
|
-
}
|
|
1095
|
-
|
|
1096
|
-
async function startEnrichment(btn) {
|
|
1097
|
-
btn.textContent = 'Starting...';
|
|
1098
|
-
btn.disabled = true;
|
|
1099
|
-
|
|
1100
|
-
var errorArea = document.getElementById('enrich-error');
|
|
1101
|
-
if (errorArea) errorArea.textContent = '';
|
|
1102
|
-
|
|
1103
|
-
var body = {
|
|
1104
|
-
productName: state.brief.product_name,
|
|
1105
|
-
targetTier: 'gold',
|
|
1106
|
-
};
|
|
1107
|
-
if (state.sources && state.sources[0]) {
|
|
1108
|
-
var src = state.sources[0];
|
|
1109
|
-
body.dataSource = (typeof src === 'string' ? src : src.name || src.database || '').replace(/[^a-zA-Z0-9_-]/g, '_');
|
|
1110
|
-
}
|
|
1111
|
-
|
|
1112
|
-
try {
|
|
1113
|
-
var result = await api('POST', '/api/pipeline/start', body);
|
|
1114
|
-
state.pipelineId = result.id;
|
|
1115
|
-
saveState();
|
|
1116
|
-
|
|
1117
|
-
// Hide start button area
|
|
1118
|
-
var startArea = document.getElementById('enrich-start-area');
|
|
1119
|
-
if (startArea) startArea.style.display = 'none';
|
|
1120
|
-
|
|
1121
|
-
appendEnrichLog({ message: 'Enrichment pipeline started.' });
|
|
1122
|
-
startEnrichPolling();
|
|
1123
|
-
} catch (e) {
|
|
1124
|
-
btn.textContent = 'Start Enrichment';
|
|
1125
|
-
btn.disabled = false;
|
|
1126
|
-
if (errorArea) {
|
|
1127
|
-
errorArea.textContent = '';
|
|
1128
|
-
errorArea.appendChild(createElement('p', { className: 'field-error', textContent: e.message || 'Failed to start enrichment.' }));
|
|
1129
|
-
}
|
|
1130
|
-
}
|
|
1131
|
-
}
|
|
1132
|
-
|
|
1133
|
-
function startEnrichPolling() {
|
|
1134
|
-
if (state.pollTimer) { clearInterval(state.pollTimer); state.pollTimer = null; }
|
|
1135
|
-
|
|
1136
|
-
async function poll() {
|
|
1137
|
-
if (!state.pipelineId) return;
|
|
1138
|
-
try {
|
|
1139
|
-
var status = await api('GET', '/api/pipeline/status/' + state.pipelineId);
|
|
1140
|
-
var stages = status.stages || [];
|
|
1141
|
-
var hasError = false;
|
|
1142
|
-
var silverDone = false;
|
|
1143
|
-
var goldDone = false;
|
|
1144
|
-
|
|
1145
|
-
for (var i = 0; i < stages.length; i++) {
|
|
1146
|
-
var s = stages[i];
|
|
1147
|
-
if (s.name === 'enrich-silver' && s.status === 'done') silverDone = true;
|
|
1148
|
-
if (s.name === 'enrich-gold' && s.status === 'done') goldDone = true;
|
|
1149
|
-
if (s.status === 'error') hasError = true;
|
|
1150
|
-
}
|
|
1151
|
-
|
|
1152
|
-
if (hasError) {
|
|
1153
|
-
if (state.pollTimer) { clearInterval(state.pollTimer); state.pollTimer = null; }
|
|
1154
|
-
showEnrichError(status.error || 'An enrichment stage failed.');
|
|
1155
|
-
return;
|
|
1156
|
-
}
|
|
1157
|
-
|
|
1158
|
-
if (silverDone) {
|
|
1159
|
-
appendEnrichLog({ message: 'Silver enrichment complete.' });
|
|
1160
|
-
}
|
|
1161
|
-
if (silverDone && goldDone) {
|
|
1162
|
-
if (state.pollTimer) { clearInterval(state.pollTimer); state.pollTimer = null; }
|
|
1163
|
-
appendEnrichLog({ message: 'Gold enrichment complete! Advancing...' });
|
|
1164
|
-
goToStep(6);
|
|
1165
|
-
}
|
|
1166
|
-
} catch (e) {
|
|
1167
|
-
// Network error — keep polling
|
|
1168
|
-
}
|
|
1169
|
-
}
|
|
1170
|
-
|
|
1171
|
-
poll();
|
|
1172
|
-
state.pollTimer = setInterval(poll, 3000);
|
|
1173
|
-
}
|
|
1174
|
-
|
|
1175
|
-
function showEnrichError(msg) {
|
|
1176
|
-
var errorArea = document.getElementById('enrich-error');
|
|
1177
|
-
if (!errorArea) return;
|
|
1178
|
-
errorArea.textContent = '';
|
|
1179
|
-
errorArea.appendChild(createElement('p', { className: 'field-error', textContent: msg }));
|
|
1180
|
-
|
|
1181
|
-
var retryBtn = createElement('button', { className: 'btn btn-primary', textContent: 'Retry' });
|
|
1182
|
-
retryBtn.addEventListener('click', function () {
|
|
1183
|
-
errorArea.textContent = '';
|
|
1184
|
-
state.pipelineId = null;
|
|
1185
|
-
saveState();
|
|
1186
|
-
// Reset requirement rows to pending
|
|
1187
|
-
ENRICH_REQUIREMENTS.forEach(function (req) {
|
|
1188
|
-
var row = document.getElementById('enrich-req-' + req.key);
|
|
1189
|
-
if (!row) return;
|
|
1190
|
-
var dot = row.querySelector('.stage-dot');
|
|
1191
|
-
if (dot) dot.className = 'stage-dot';
|
|
1192
|
-
var prog = row.querySelector('.enrich-progress');
|
|
1193
|
-
if (prog) prog.textContent = req.initial;
|
|
1194
|
-
});
|
|
1195
|
-
// Show start area again, hide dashboard
|
|
1196
|
-
var startArea = document.getElementById('enrich-start-area');
|
|
1197
|
-
if (startArea) startArea.style.display = '';
|
|
1198
|
-
var dashboard = document.getElementById('enrich-dashboard');
|
|
1199
|
-
if (dashboard) dashboard.style.display = 'none';
|
|
1200
|
-
var startBtn = document.getElementById('enrich-start-btn');
|
|
1201
|
-
if (startBtn) {
|
|
1202
|
-
startBtn.textContent = 'Start Enrichment';
|
|
1203
|
-
startBtn.disabled = false;
|
|
1204
|
-
}
|
|
1205
|
-
});
|
|
1206
|
-
errorArea.appendChild(retryBtn);
|
|
1207
|
-
}
|
|
1208
|
-
|
|
1209
|
-
function updateEnrichProgress(payload) {
|
|
1210
|
-
// payload: { requirement: string, status: string, progress: string }
|
|
1211
|
-
var row = document.getElementById('enrich-req-' + payload.requirement);
|
|
1212
|
-
if (!row) return;
|
|
1213
|
-
var dot = row.querySelector('.stage-dot');
|
|
1214
|
-
var prog = row.querySelector('.enrich-progress');
|
|
1215
|
-
if (dot) {
|
|
1216
|
-
dot.className = 'stage-dot' + (payload.status === 'working' ? ' running' : payload.status === 'done' ? ' done' : '');
|
|
1217
|
-
}
|
|
1218
|
-
if (prog) prog.textContent = payload.progress || '';
|
|
1219
|
-
}
|
|
1220
|
-
|
|
1221
|
-
function appendEnrichLog(payload) {
|
|
1222
|
-
// payload: { message: string, timestamp?: string }
|
|
1223
|
-
var log = document.getElementById('activity-log');
|
|
1224
|
-
if (!log) return;
|
|
1225
|
-
var ts = payload.timestamp ? new Date(payload.timestamp).toLocaleTimeString() : new Date().toLocaleTimeString();
|
|
1226
|
-
var entry = createElement('div', { className: 'log-entry' }, [
|
|
1227
|
-
createElement('span', { className: 'log-time' }, [ts]),
|
|
1228
|
-
createElement('span', {}, [' ' + payload.message]),
|
|
1229
|
-
]);
|
|
1230
|
-
log.appendChild(entry);
|
|
1231
|
-
log.scrollTop = log.scrollHeight;
|
|
1232
|
-
}
|
|
1233
|
-
|
|
1234
|
-
// ---- Step 6: Serve ----
|
|
1235
|
-
|
|
1236
|
-
function renderServeStep() {
|
|
1237
|
-
var content = document.getElementById('wizard-content');
|
|
1238
|
-
if (!content) return;
|
|
1239
|
-
|
|
1240
|
-
var card = createElement('div', { className: 'card serve-card' });
|
|
1241
|
-
|
|
1242
|
-
card.appendChild(createElement('h2', { textContent: 'Your Semantic Plane is Ready' }));
|
|
1243
|
-
|
|
1244
|
-
// Tier detection placeholder — will be filled async
|
|
1245
|
-
var tierBadge = createElement('span', { className: 'serve-tier-badge bronze', id: 'tier-badge', textContent: 'Bronze' });
|
|
1246
|
-
card.appendChild(tierBadge);
|
|
1247
|
-
|
|
1248
|
-
var messageEl = createElement('p', { className: 'muted' });
|
|
1249
|
-
messageEl.textContent = 'Your Bronze tier semantic plane is ready for AI agents.';
|
|
1250
|
-
card.appendChild(messageEl);
|
|
1251
|
-
|
|
1252
|
-
var upgradeHint = createElement('p', { className: 'muted' });
|
|
1253
|
-
upgradeHint.style.marginTop = '8px';
|
|
1254
|
-
upgradeHint.style.display = 'none';
|
|
1255
|
-
card.appendChild(upgradeHint);
|
|
1256
|
-
|
|
1257
|
-
// Fetch tier from pipeline status
|
|
1258
|
-
if (state.pipelineId) {
|
|
1259
|
-
fetch('/api/pipeline/status/' + state.pipelineId)
|
|
1260
|
-
.then(function (res) { return res.json(); })
|
|
1261
|
-
.then(function (data) {
|
|
1262
|
-
var stages = data.stages || [];
|
|
1263
|
-
var tier = 'Bronze';
|
|
1264
|
-
var tierClass = 'bronze';
|
|
1265
|
-
var hasSilver = false;
|
|
1266
|
-
var hasGold = false;
|
|
1267
|
-
for (var i = 0; i < stages.length; i++) {
|
|
1268
|
-
if (stages[i].name === 'enrich-gold' && stages[i].status === 'done') {
|
|
1269
|
-
hasGold = true;
|
|
1270
|
-
}
|
|
1271
|
-
if (stages[i].name === 'enrich-silver' && stages[i].status === 'done') {
|
|
1272
|
-
hasSilver = true;
|
|
1273
|
-
}
|
|
1274
|
-
}
|
|
1275
|
-
if (hasGold) {
|
|
1276
|
-
tier = 'Gold';
|
|
1277
|
-
tierClass = 'gold';
|
|
1278
|
-
} else if (hasSilver) {
|
|
1279
|
-
tier = 'Silver';
|
|
1280
|
-
tierClass = 'silver';
|
|
1281
|
-
}
|
|
1282
|
-
|
|
1283
|
-
tierBadge.className = 'serve-tier-badge ' + tierClass;
|
|
1284
|
-
tierBadge.textContent = tier;
|
|
1285
|
-
messageEl.textContent = 'Your ' + tier + ' tier semantic plane is ready for AI agents.';
|
|
1286
|
-
|
|
1287
|
-
if (!hasGold) {
|
|
1288
|
-
var missing = [];
|
|
1289
|
-
if (!hasSilver) missing.push('Silver enrichment');
|
|
1290
|
-
missing.push('Gold enrichment');
|
|
1291
|
-
upgradeHint.textContent = 'To reach Gold, you still need: ' + missing.join(', ') + '. You can run enrichment later with `context enrich --target gold`.';
|
|
1292
|
-
upgradeHint.style.display = 'block';
|
|
1293
|
-
}
|
|
1294
|
-
})
|
|
1295
|
-
.catch(function () { /* keep Bronze default */ });
|
|
1296
|
-
}
|
|
1297
|
-
|
|
1298
|
-
// CTAs
|
|
1299
|
-
var ctas = createElement('div', { className: 'serve-ctas' });
|
|
1300
|
-
|
|
1301
|
-
var startBtn = createElement('button', { className: 'btn btn-primary', textContent: 'Start MCP Server' });
|
|
1302
|
-
startBtn.addEventListener('click', function () {
|
|
1303
|
-
startBtn.disabled = true;
|
|
1304
|
-
startBtn.textContent = 'Loading...';
|
|
1305
|
-
fetch('/api/mcp-config')
|
|
1306
|
-
.then(function (res) { return res.json(); })
|
|
1307
|
-
.then(function (config) {
|
|
1308
|
-
startBtn.textContent = 'Start MCP Server';
|
|
1309
|
-
startBtn.disabled = false;
|
|
1310
|
-
// Remove existing config block if any
|
|
1311
|
-
var existing = card.querySelector('.mcp-config-block');
|
|
1312
|
-
if (existing) existing.remove();
|
|
1313
|
-
var configBlock = createElement('div', { className: 'mcp-config-block' });
|
|
1314
|
-
configBlock.textContent = JSON.stringify(config, null, 2);
|
|
1315
|
-
// Insert after CTAs
|
|
1316
|
-
var ctaParent = ctas.parentNode;
|
|
1317
|
-
if (ctaParent) ctaParent.insertBefore(configBlock, ctas.nextSibling);
|
|
1318
|
-
|
|
1319
|
-
var copyHint = card.querySelector('.mcp-copy-hint');
|
|
1320
|
-
if (!copyHint) {
|
|
1321
|
-
copyHint = createElement('p', { className: 'muted mcp-copy-hint' });
|
|
1322
|
-
copyHint.textContent = 'Copy the JSON above into your IDE\'s MCP settings, or run: context serve';
|
|
1323
|
-
copyHint.style.marginTop = '8px';
|
|
1324
|
-
copyHint.style.fontSize = '0.85rem';
|
|
1325
|
-
var configEl = card.querySelector('.mcp-config-block');
|
|
1326
|
-
if (configEl && configEl.nextSibling) {
|
|
1327
|
-
ctaParent.insertBefore(copyHint, configEl.nextSibling);
|
|
1328
|
-
} else if (configEl) {
|
|
1329
|
-
ctaParent.appendChild(copyHint);
|
|
1330
|
-
}
|
|
1331
|
-
}
|
|
1332
|
-
})
|
|
1333
|
-
.catch(function () {
|
|
1334
|
-
startBtn.textContent = 'Start MCP Server';
|
|
1335
|
-
startBtn.disabled = false;
|
|
1336
|
-
});
|
|
1337
|
-
});
|
|
1338
|
-
ctas.appendChild(startBtn);
|
|
1339
|
-
|
|
1340
|
-
var publishBtn = createElement('button', { className: 'btn btn-secondary', textContent: 'Publish to Cloud' });
|
|
1341
|
-
publishBtn.disabled = true;
|
|
1342
|
-
publishBtn.title = 'Coming soon';
|
|
1343
|
-
ctas.appendChild(publishBtn);
|
|
1344
|
-
|
|
1345
|
-
card.appendChild(ctas);
|
|
1346
|
-
|
|
1347
|
-
// CLI Commands section
|
|
1348
|
-
var cmds = createElement('div', { className: 'serve-commands' });
|
|
1349
|
-
cmds.appendChild(createElement('div', { className: 'serve-commands-title', textContent: 'CLI Commands' }));
|
|
1350
|
-
|
|
1351
|
-
var cmdData = [
|
|
1352
|
-
['context serve', 'Start the MCP server'],
|
|
1353
|
-
['context tier', 'Check your current tier'],
|
|
1354
|
-
['context enrich --target gold', 'Enrich to Gold tier'],
|
|
1355
|
-
['context verify', 'Validate your semantic plane'],
|
|
1356
|
-
];
|
|
1357
|
-
for (var i = 0; i < cmdData.length; i++) {
|
|
1358
|
-
var row = createElement('div', { className: 'serve-cmd-row' }, [
|
|
1359
|
-
createElement('span', { className: 'serve-cmd', textContent: cmdData[i][0] }),
|
|
1360
|
-
createElement('span', { className: 'serve-cmd-desc', textContent: cmdData[i][1] }),
|
|
1361
|
-
]);
|
|
1362
|
-
cmds.appendChild(row);
|
|
1363
|
-
}
|
|
1364
|
-
card.appendChild(cmds);
|
|
1365
|
-
|
|
1366
|
-
// Continue Enrichment link (shown if not Gold — updated async)
|
|
1367
|
-
var continueLink = createElement('p', {});
|
|
1368
|
-
continueLink.style.marginTop = '16px';
|
|
1369
|
-
var linkEl = createElement('a', { textContent: 'Continue Enrichment' });
|
|
1370
|
-
linkEl.style.color = 'var(--rc-color-accent, #c9a55a)';
|
|
1371
|
-
linkEl.style.cursor = 'pointer';
|
|
1372
|
-
linkEl.style.fontSize = '0.875rem';
|
|
1373
|
-
linkEl.addEventListener('click', function () {
|
|
1374
|
-
goToStep(5);
|
|
1375
|
-
});
|
|
1376
|
-
continueLink.appendChild(linkEl);
|
|
1377
|
-
card.appendChild(continueLink);
|
|
1378
|
-
|
|
1379
|
-
// Hide continue link if Gold
|
|
1380
|
-
if (state.pipelineId) {
|
|
1381
|
-
fetch('/api/pipeline/status/' + state.pipelineId)
|
|
1382
|
-
.then(function (res) { return res.json(); })
|
|
1383
|
-
.then(function (data) {
|
|
1384
|
-
var stages = data.stages || [];
|
|
1385
|
-
for (var j = 0; j < stages.length; j++) {
|
|
1386
|
-
if (stages[j].name === 'enrich-gold' && stages[j].status === 'done') {
|
|
1387
|
-
continueLink.style.display = 'none';
|
|
1388
|
-
break;
|
|
1389
|
-
}
|
|
1390
|
-
}
|
|
1391
|
-
})
|
|
1392
|
-
.catch(function () { /* keep visible */ });
|
|
1393
|
-
}
|
|
1394
|
-
|
|
1395
|
-
card.appendChild(createStepActions(true, false));
|
|
1396
|
-
content.appendChild(card);
|
|
1397
|
-
}
|
|
1398
|
-
|
|
1399
|
-
// ---- Review / Build helpers (will be re-implemented in later tasks) ----
|
|
1400
|
-
|
|
1401
|
-
function createReviewRow(label, value) {
|
|
1402
|
-
return createElement('div', { className: 'review-row' }, [
|
|
1403
|
-
createElement('span', { className: 'review-label', textContent: label }),
|
|
1404
|
-
createElement('span', { className: 'review-value', textContent: value }),
|
|
1405
|
-
]);
|
|
1406
|
-
}
|
|
1407
|
-
|
|
1408
|
-
// ---- Existing Products Banner ----
|
|
1409
|
-
|
|
1410
|
-
async function checkExistingProducts() {
|
|
1411
|
-
try {
|
|
1412
|
-
var res = await fetch('/api/products');
|
|
1413
|
-
var products = await res.json();
|
|
1414
|
-
if (products.length > 0) {
|
|
1415
|
-
var content = document.getElementById('wizard-content');
|
|
1416
|
-
if (!content) return;
|
|
1417
|
-
|
|
1418
|
-
var banner = createElement('div', { className: 'existing-products-banner' });
|
|
1419
|
-
|
|
1420
|
-
var title = createElement('p', { className: 'banner-title' });
|
|
1421
|
-
title.textContent = 'Your semantic plane has ' + products.length + ' data product' + (products.length === 1 ? '' : 's') + '. Adding another.';
|
|
1422
|
-
banner.appendChild(title);
|
|
1423
|
-
|
|
1424
|
-
var list = createElement('div', { className: 'product-chips' });
|
|
1425
|
-
for (var i = 0; i < products.length; i++) {
|
|
1426
|
-
list.appendChild(createElement('span', { className: 'product-chip', textContent: products[i].name }));
|
|
1427
|
-
}
|
|
1428
|
-
banner.appendChild(list);
|
|
1429
|
-
|
|
1430
|
-
// Insert banner before the first card
|
|
1431
|
-
var firstCard = content.querySelector('.card');
|
|
1432
|
-
if (firstCard) {
|
|
1433
|
-
content.insertBefore(banner, firstCard);
|
|
1434
|
-
} else {
|
|
1435
|
-
content.appendChild(banner);
|
|
1436
|
-
}
|
|
1437
|
-
}
|
|
1438
|
-
} catch (e) {
|
|
1439
|
-
// ignore - not critical
|
|
1440
|
-
}
|
|
1441
|
-
}
|
|
1442
|
-
|
|
1443
|
-
// ---- Sidebar Interactions ----
|
|
1444
|
-
|
|
1445
|
-
function setupSidebarLocked() {
|
|
1446
|
-
var tooltip = document.getElementById('locked-tooltip');
|
|
1447
|
-
if (!tooltip) return;
|
|
1448
|
-
|
|
1449
|
-
$$('.nav-item.locked').forEach(function (item) {
|
|
1450
|
-
item.addEventListener('click', function (e) {
|
|
1451
|
-
e.preventDefault();
|
|
1452
|
-
e.stopPropagation();
|
|
1453
|
-
var rect = item.getBoundingClientRect();
|
|
1454
|
-
tooltip.style.display = 'block';
|
|
1455
|
-
tooltip.style.left = rect.left + 'px';
|
|
1456
|
-
tooltip.style.top = (rect.bottom + 6) + 'px';
|
|
1457
|
-
});
|
|
1458
|
-
});
|
|
1459
|
-
|
|
1460
|
-
document.addEventListener('click', function (e) {
|
|
1461
|
-
if (tooltip.style.display !== 'none') {
|
|
1462
|
-
var isLocked = false;
|
|
1463
|
-
$$('.nav-item.locked').forEach(function (item) {
|
|
1464
|
-
if (item.contains(e.target)) isLocked = true;
|
|
1465
|
-
});
|
|
1466
|
-
if (!isLocked) {
|
|
1467
|
-
tooltip.style.display = 'none';
|
|
1468
|
-
}
|
|
1469
|
-
}
|
|
1470
|
-
});
|
|
1471
|
-
}
|
|
1472
|
-
|
|
1473
|
-
// ---- Sidebar Status Polling ----
|
|
1474
|
-
|
|
1475
|
-
function pollMcpStatus() {
|
|
1476
|
-
async function check() {
|
|
1477
|
-
var dot = document.getElementById('mcp-status-dot');
|
|
1478
|
-
var text = document.getElementById('mcp-status-text');
|
|
1479
|
-
var serverDot = document.getElementById('mcp-server-dot');
|
|
1480
|
-
var serverText = document.getElementById('mcp-server-text');
|
|
1481
|
-
if (!dot || !text) return;
|
|
1482
|
-
try {
|
|
1483
|
-
var controller = new AbortController();
|
|
1484
|
-
var timer = setTimeout(function () { controller.abort(); }, 2000);
|
|
1485
|
-
var res = await fetch('http://localhost:3333/health', {
|
|
1486
|
-
method: 'GET',
|
|
1487
|
-
mode: 'no-cors',
|
|
1488
|
-
signal: controller.signal,
|
|
1489
|
-
});
|
|
1490
|
-
clearTimeout(timer);
|
|
1491
|
-
// mode: 'no-cors' returns opaque response (status 0) but means server is reachable
|
|
1492
|
-
dot.classList.remove('error');
|
|
1493
|
-
dot.classList.add('success');
|
|
1494
|
-
text.textContent = 'connected';
|
|
1495
|
-
if (serverDot) { serverDot.classList.remove('error'); serverDot.classList.add('success'); }
|
|
1496
|
-
if (serverText) serverText.textContent = 'MCP running';
|
|
1497
|
-
} catch (e) {
|
|
1498
|
-
dot.classList.remove('success');
|
|
1499
|
-
text.textContent = 'offline';
|
|
1500
|
-
if (serverDot) { serverDot.classList.remove('success'); }
|
|
1501
|
-
if (serverText) serverText.textContent = 'MCP stopped';
|
|
1502
|
-
}
|
|
1503
|
-
}
|
|
1504
|
-
check();
|
|
1505
|
-
state.mcpPollTimer = setInterval(check, 10000);
|
|
1506
|
-
}
|
|
1507
|
-
|
|
1508
|
-
function updateDbStatus(source) {
|
|
1509
|
-
var dot = document.getElementById('db-status-dot');
|
|
1510
|
-
var text = document.getElementById('db-status-text');
|
|
1511
|
-
if (!dot || !text) return;
|
|
1512
|
-
if (source) {
|
|
1513
|
-
dot.classList.remove('error');
|
|
1514
|
-
dot.classList.add('success');
|
|
1515
|
-
text.textContent = (source.name || source.adapter) + ' connected';
|
|
1516
|
-
} else {
|
|
1517
|
-
dot.classList.remove('success');
|
|
1518
|
-
dot.classList.add('error');
|
|
1519
|
-
text.textContent = 'No database';
|
|
1520
|
-
}
|
|
1521
|
-
}
|
|
1522
|
-
|
|
1523
|
-
// ---- Init ----
|
|
1524
|
-
|
|
1525
|
-
function init() {
|
|
1526
|
-
setupSidebarLocked();
|
|
1527
|
-
pollMcpStatus();
|
|
1528
|
-
|
|
1529
|
-
// Restore DB status from saved state
|
|
1530
|
-
if (state.sources && state.sources.length > 0) {
|
|
1531
|
-
updateDbStatus(state.sources[0]);
|
|
1532
|
-
}
|
|
1533
|
-
|
|
1534
|
-
goToStep(state.step);
|
|
1535
|
-
|
|
1536
|
-
// Create or resume a WebSocket session
|
|
1537
|
-
var urlParams = new URLSearchParams(window.location.search);
|
|
1538
|
-
var sessionParam = urlParams.get('session');
|
|
1539
|
-
if (sessionParam) {
|
|
1540
|
-
connectWebSocket(sessionParam);
|
|
1541
|
-
} else {
|
|
1542
|
-
fetch('/api/session', { method: 'POST' })
|
|
1543
|
-
.then(function (r) { return r.json(); })
|
|
1544
|
-
.then(function (data) {
|
|
1545
|
-
if (data.sessionId) {
|
|
1546
|
-
connectWebSocket(data.sessionId);
|
|
1547
|
-
// Update URL without reload so session persists on refresh
|
|
1548
|
-
var newUrl = window.location.pathname + '?session=' + encodeURIComponent(data.sessionId);
|
|
1549
|
-
window.history.replaceState({}, '', newUrl);
|
|
1550
|
-
}
|
|
1551
|
-
})
|
|
1552
|
-
.catch(function () { /* WebSocket is best-effort */ });
|
|
1553
|
-
}
|
|
1554
|
-
}
|
|
1555
|
-
|
|
1556
|
-
document.addEventListener('DOMContentLoaded', init);
|
|
1557
|
-
})();
|
|
1
|
+
(function(){"use strict";var _e,h,tt,nt,O,it,rt,at,st,Le,De,Oe,ve={},he=[],nn=/acit|ex(?:s|g|n|p|$)|rph|grid|ows|mnc|ntw|ine[ch]|zoo|^ord|itera/i,pe=Array.isArray;function A(t,e){for(var n in e)t[n]=e[n];return t}function Ue(t){t&&t.parentNode&&t.parentNode.removeChild(t)}function rn(t,e,n){var r,i,s,o={};for(s in e)s=="key"?r=e[s]:s=="ref"?i=e[s]:o[s]=e[s];if(arguments.length>2&&(o.children=arguments.length>3?_e.call(arguments,2):n),typeof t=="function"&&t.defaultProps!=null)for(s in t.defaultProps)o[s]===void 0&&(o[s]=t.defaultProps[s]);return me(t,o,r,i,null)}function me(t,e,n,r,i){var s={type:t,props:e,key:n,ref:r,__k:null,__:null,__b:0,__e:null,__c:null,constructor:void 0,__v:i??++tt,__i:-1,__u:0};return i==null&&h.vnode!=null&&h.vnode(s),s}function U(t){return t.children}function te(t,e){this.props=t,this.context=e}function Y(t,e){if(e==null)return t.__?Y(t.__,t.__i+1):null;for(var n;e<t.__k.length;e++)if((n=t.__k[e])!=null&&n.__e!=null)return n.__e;return typeof t.type=="function"?Y(t):null}function an(t){if(t.__P&&t.__d){var e=t.__v,n=e.__e,r=[],i=[],s=A({},e);s.__v=e.__v+1,h.vnode&&h.vnode(s),Me(t.__P,s,e,t.__n,t.__P.namespaceURI,32&e.__u?[n]:null,r,n??Y(e),!!(32&e.__u),i),s.__v=e.__v,s.__.__k[s.__i]=s,_t(r,s,i),e.__e=e.__=null,s.__e!=n&&ot(s)}}function ot(t){if((t=t.__)!=null&&t.__c!=null)return t.__e=t.__c.base=null,t.__k.some(function(e){if(e!=null&&e.__e!=null)return t.__e=t.__c.base=e.__e}),ot(t)}function lt(t){(!t.__d&&(t.__d=!0)&&O.push(t)&&!ye.__r++||it!=h.debounceRendering)&&((it=h.debounceRendering)||rt)(ye)}function ye(){try{for(var t,e=1;O.length;)O.length>e&&O.sort(at),t=O.shift(),e=O.length,an(t)}finally{O.length=ye.__r=0}}function ct(t,e,n,r,i,s,o,c,d,u,_){var l,y,f,k,I,$,g,m=r&&r.__k||he,q=e.length;for(d=sn(n,e,m,d,q),l=0;l<q;l++)(f=n.__k[l])!=null&&(y=f.__i!=-1&&m[f.__i]||ve,f.__i=l,$=Me(t,f,y,i,s,o,c,d,u,_),k=f.__e,f.ref&&y.ref!=f.ref&&(y.ref&&je(y.ref,null,f),_.push(f.ref,f.__c||k,f)),I==null&&k!=null&&(I=k),(g=!!(4&f.__u))||y.__k===f.__k?d=ut(f,d,t,g):typeof f.type=="function"&&$!==void 0?d=$:k&&(d=k.nextSibling),f.__u&=-7);return n.__e=I,d}function sn(t,e,n,r,i){var s,o,c,d,u,_=n.length,l=_,y=0;for(t.__k=new Array(i),s=0;s<i;s++)(o=e[s])!=null&&typeof o!="boolean"&&typeof o!="function"?(typeof o=="string"||typeof o=="number"||typeof o=="bigint"||o.constructor==String?o=t.__k[s]=me(null,o,null,null,null):pe(o)?o=t.__k[s]=me(U,{children:o},null,null,null):o.constructor===void 0&&o.__b>0?o=t.__k[s]=me(o.type,o.props,o.key,o.ref?o.ref:null,o.__v):t.__k[s]=o,d=s+y,o.__=t,o.__b=t.__b+1,c=null,(u=o.__i=on(o,n,d,l))!=-1&&(l--,(c=n[u])&&(c.__u|=2)),c==null||c.__v==null?(u==-1&&(i>_?y--:i<_&&y++),typeof o.type!="function"&&(o.__u|=4)):u!=d&&(u==d-1?y--:u==d+1?y++:(u>d?y--:y++,o.__u|=4))):t.__k[s]=null;if(l)for(s=0;s<_;s++)(c=n[s])!=null&&(2&c.__u)==0&&(c.__e==r&&(r=Y(c)),ht(c,c));return r}function ut(t,e,n,r){var i,s;if(typeof t.type=="function"){for(i=t.__k,s=0;i&&s<i.length;s++)i[s]&&(i[s].__=t,e=ut(i[s],e,n,r));return e}t.__e!=e&&(r&&(e&&t.type&&!e.parentNode&&(e=Y(t)),n.insertBefore(t.__e,e||null)),e=t.__e);do e=e&&e.nextSibling;while(e!=null&&e.nodeType==8);return e}function on(t,e,n,r){var i,s,o,c=t.key,d=t.type,u=e[n],_=u!=null&&(2&u.__u)==0;if(u===null&&c==null||_&&c==u.key&&d==u.type)return n;if(r>(_?1:0)){for(i=n-1,s=n+1;i>=0||s<e.length;)if((u=e[o=i>=0?i--:s++])!=null&&(2&u.__u)==0&&c==u.key&&d==u.type)return o}return-1}function dt(t,e,n){e[0]=="-"?t.setProperty(e,n??""):t[e]=n==null?"":typeof n!="number"||nn.test(e)?n:n+"px"}function ge(t,e,n,r,i){var s,o;e:if(e=="style")if(typeof n=="string")t.style.cssText=n;else{if(typeof r=="string"&&(t.style.cssText=r=""),r)for(e in r)n&&e in n||dt(t.style,e,"");if(n)for(e in n)r&&n[e]==r[e]||dt(t.style,e,n[e])}else if(e[0]=="o"&&e[1]=="n")s=e!=(e=e.replace(st,"$1")),o=e.toLowerCase(),e=o in t||e=="onFocusOut"||e=="onFocusIn"?o.slice(2):e.slice(2),t.l||(t.l={}),t.l[e+s]=n,n?r?n.u=r.u:(n.u=Le,t.addEventListener(e,s?Oe:De,s)):t.removeEventListener(e,s?Oe:De,s);else{if(i=="http://www.w3.org/2000/svg")e=e.replace(/xlink(H|:h)/,"h").replace(/sName$/,"s");else if(e!="width"&&e!="height"&&e!="href"&&e!="list"&&e!="form"&&e!="tabIndex"&&e!="download"&&e!="rowSpan"&&e!="colSpan"&&e!="role"&&e!="popover"&&e in t)try{t[e]=n??"";break e}catch{}typeof n=="function"||(n==null||n===!1&&e[4]!="-"?t.removeAttribute(e):t.setAttribute(e,e=="popover"&&n==1?"":n))}}function ft(t){return function(e){if(this.l){var n=this.l[e.type+t];if(e.t==null)e.t=Le++;else if(e.t<n.u)return;return n(h.event?h.event(e):e)}}}function Me(t,e,n,r,i,s,o,c,d,u){var _,l,y,f,k,I,$,g,m,q,V,fe,tn,Be,et,N=e.type;if(e.constructor!==void 0)return null;128&n.__u&&(d=!!(32&n.__u),s=[c=e.__e=n.__e]),(_=h.__b)&&_(e);e:if(typeof N=="function")try{if(g=e.props,m=N.prototype&&N.prototype.render,q=(_=N.contextType)&&r[_.__c],V=_?q?q.props.value:_.__:r,n.__c?$=(l=e.__c=n.__c).__=l.__E:(m?e.__c=l=new N(g,V):(e.__c=l=new te(g,V),l.constructor=N,l.render=cn),q&&q.sub(l),l.state||(l.state={}),l.__n=r,y=l.__d=!0,l.__h=[],l._sb=[]),m&&l.__s==null&&(l.__s=l.state),m&&N.getDerivedStateFromProps!=null&&(l.__s==l.state&&(l.__s=A({},l.__s)),A(l.__s,N.getDerivedStateFromProps(g,l.__s))),f=l.props,k=l.state,l.__v=e,y)m&&N.getDerivedStateFromProps==null&&l.componentWillMount!=null&&l.componentWillMount(),m&&l.componentDidMount!=null&&l.__h.push(l.componentDidMount);else{if(m&&N.getDerivedStateFromProps==null&&g!==f&&l.componentWillReceiveProps!=null&&l.componentWillReceiveProps(g,V),e.__v==n.__v||!l.__e&&l.shouldComponentUpdate!=null&&l.shouldComponentUpdate(g,l.__s,V)===!1){e.__v!=n.__v&&(l.props=g,l.state=l.__s,l.__d=!1),e.__e=n.__e,e.__k=n.__k,e.__k.some(function(ee){ee&&(ee.__=e)}),he.push.apply(l.__h,l._sb),l._sb=[],l.__h.length&&o.push(l);break e}l.componentWillUpdate!=null&&l.componentWillUpdate(g,l.__s,V),m&&l.componentDidUpdate!=null&&l.__h.push(function(){l.componentDidUpdate(f,k,I)})}if(l.context=V,l.props=g,l.__P=t,l.__e=!1,fe=h.__r,tn=0,m)l.state=l.__s,l.__d=!1,fe&&fe(e),_=l.render(l.props,l.state,l.context),he.push.apply(l.__h,l._sb),l._sb=[];else do l.__d=!1,fe&&fe(e),_=l.render(l.props,l.state,l.context),l.state=l.__s;while(l.__d&&++tn<25);l.state=l.__s,l.getChildContext!=null&&(r=A(A({},r),l.getChildContext())),m&&!y&&l.getSnapshotBeforeUpdate!=null&&(I=l.getSnapshotBeforeUpdate(f,k)),Be=_!=null&&_.type===U&&_.key==null?vt(_.props.children):_,c=ct(t,pe(Be)?Be:[Be],e,n,r,i,s,o,c,d,u),l.base=e.__e,e.__u&=-161,l.__h.length&&o.push(l),$&&(l.__E=l.__=null)}catch(ee){if(e.__v=null,d||s!=null)if(ee.then){for(e.__u|=d?160:128;c&&c.nodeType==8&&c.nextSibling;)c=c.nextSibling;s[s.indexOf(c)]=null,e.__e=c}else{for(et=s.length;et--;)Ue(s[et]);Re(e)}else e.__e=n.__e,e.__k=n.__k,ee.then||Re(e);h.__e(ee,e,n)}else s==null&&e.__v==n.__v?(e.__k=n.__k,e.__e=n.__e):c=e.__e=ln(n.__e,e,n,r,i,s,o,d,u);return(_=h.diffed)&&_(e),128&e.__u?void 0:c}function Re(t){t&&(t.__c&&(t.__c.__e=!0),t.__k&&t.__k.some(Re))}function _t(t,e,n){for(var r=0;r<n.length;r++)je(n[r],n[++r],n[++r]);h.__c&&h.__c(e,t),t.some(function(i){try{t=i.__h,i.__h=[],t.some(function(s){s.call(i)})}catch(s){h.__e(s,i.__v)}})}function vt(t){return typeof t!="object"||t==null||t.__b>0?t:pe(t)?t.map(vt):A({},t)}function ln(t,e,n,r,i,s,o,c,d){var u,_,l,y,f,k,I,$=n.props||ve,g=e.props,m=e.type;if(m=="svg"?i="http://www.w3.org/2000/svg":m=="math"?i="http://www.w3.org/1998/Math/MathML":i||(i="http://www.w3.org/1999/xhtml"),s!=null){for(u=0;u<s.length;u++)if((f=s[u])&&"setAttribute"in f==!!m&&(m?f.localName==m:f.nodeType==3)){t=f,s[u]=null;break}}if(t==null){if(m==null)return document.createTextNode(g);t=document.createElementNS(i,m,g.is&&g),c&&(h.__m&&h.__m(e,s),c=!1),s=null}if(m==null)$===g||c&&t.data==g||(t.data=g);else{if(s=s&&_e.call(t.childNodes),!c&&s!=null)for($={},u=0;u<t.attributes.length;u++)$[(f=t.attributes[u]).name]=f.value;for(u in $)f=$[u],u=="dangerouslySetInnerHTML"?l=f:u=="children"||u in g||u=="value"&&"defaultValue"in g||u=="checked"&&"defaultChecked"in g||ge(t,u,null,f,i);for(u in g)f=g[u],u=="children"?y=f:u=="dangerouslySetInnerHTML"?_=f:u=="value"?k=f:u=="checked"?I=f:c&&typeof f!="function"||$[u]===f||ge(t,u,f,$[u],i);if(_)c||l&&(_.__html==l.__html||_.__html==t.innerHTML)||(t.innerHTML=_.__html),e.__k=[];else if(l&&(t.innerHTML=""),ct(e.type=="template"?t.content:t,pe(y)?y:[y],e,n,r,m=="foreignObject"?"http://www.w3.org/1999/xhtml":i,s,o,s?s[0]:n.__k&&Y(n,0),c,d),s!=null)for(u=s.length;u--;)Ue(s[u]);c||(u="value",m=="progress"&&k==null?t.removeAttribute("value"):k!=null&&(k!==t[u]||m=="progress"&&!k||m=="option"&&k!=$[u])&&ge(t,u,k,$[u],i),u="checked",I!=null&&I!=t[u]&&ge(t,u,I,$[u],i))}return t}function je(t,e,n){try{if(typeof t=="function"){var r=typeof t.__u=="function";r&&t.__u(),r&&e==null||(t.__u=t(e))}else t.current=e}catch(i){h.__e(i,n)}}function ht(t,e,n){var r,i;if(h.unmount&&h.unmount(t),(r=t.ref)&&(r.current&&r.current!=t.__e||je(r,null,e)),(r=t.__c)!=null){if(r.componentWillUnmount)try{r.componentWillUnmount()}catch(s){h.__e(s,e)}r.base=r.__P=null}if(r=t.__k)for(i=0;i<r.length;i++)r[i]&&ht(r[i],e,n||typeof t.type!="function");n||Ue(t.__e),t.__c=t.__=t.__e=void 0}function cn(t,e,n){return this.constructor(t,n)}function Fe(t,e,n){var r,i,s,o;e==document&&(e=document.documentElement),h.__&&h.__(t,e),i=(r=!1)?null:e.__k,s=[],o=[],Me(e,t=e.__k=rn(U,null,[t]),i||ve,ve,e.namespaceURI,i?null:e.firstChild?_e.call(e.childNodes):null,s,i?i.__e:e.firstChild,r,o),_t(s,t,o)}_e=he.slice,h={__e:function(t,e,n,r){for(var i,s,o;e=e.__;)if((i=e.__c)&&!i.__)try{if((s=i.constructor)&&s.getDerivedStateFromError!=null&&(i.setState(s.getDerivedStateFromError(t)),o=i.__d),i.componentDidCatch!=null&&(i.componentDidCatch(t,r||{}),o=i.__d),o)return i.__E=i}catch(c){t=c}throw t}},tt=0,nt=function(t){return t!=null&&t.constructor===void 0},te.prototype.setState=function(t,e){var n;n=this.__s!=null&&this.__s!=this.state?this.__s:this.__s=A({},this.state),typeof t=="function"&&(t=t(A({},n),this.props)),t&&A(n,t),t!=null&&this.__v&&(e&&this._sb.push(e),lt(this))},te.prototype.forceUpdate=function(t){this.__v&&(this.__e=!0,t&&this.__h.push(t),lt(this))},te.prototype.render=U,O=[],rt=typeof Promise=="function"?Promise.prototype.then.bind(Promise.resolve()):setTimeout,at=function(t,e){return t.__v.__b-e.__v.__b},ye.__r=0,st=/(PointerCapture)$|Capture$/i,Le=0,De=ft(!1),Oe=ft(!0);var un=0;function a(t,e,n,r,i,s){e||(e={});var o,c,d=e;if("ref"in d)for(c in d={},e)c=="ref"?o=e[c]:d[c]=e[c];var u={type:t,props:d,key:n,ref:o,__k:null,__:null,__b:0,__e:null,__c:null,constructor:void 0,__v:--un,__i:-1,__u:0,__source:i,__self:s};if(typeof t=="function"&&(o=t.defaultProps))for(c in o)d[c]===void 0&&(d[c]=o[c]);return h.vnode&&h.vnode(u),u}var qe,P,ze,pt,mt=0,yt=[],w=h,gt=w.__b,bt=w.__r,wt=w.diffed,kt=w.__c,St=w.unmount,Ct=w.__;function dn(t,e){w.__h&&w.__h(P,t,mt||e),mt=0;var n=P.__H||(P.__H={__:[],__h:[]});return t>=n.__.length&&n.__.push({}),n.__[t]}function $t(t,e){var n=dn(qe++,7);return vn(n.__H,e)&&(n.__=t(),n.__H=e,n.__h=t),n.__}function fn(){for(var t;t=yt.shift();){var e=t.__H;if(t.__P&&e)try{e.__h.some(be),e.__h.some(Ge),e.__h=[]}catch(n){e.__h=[],w.__e(n,t.__v)}}}w.__b=function(t){P=null,gt&>(t)},w.__=function(t,e){t&&e.__k&&e.__k.__m&&(t.__m=e.__k.__m),Ct&&Ct(t,e)},w.__r=function(t){bt&&bt(t),qe=0;var e=(P=t.__c).__H;e&&(ze===P?(e.__h=[],P.__h=[],e.__.some(function(n){n.__N&&(n.__=n.__N),n.u=n.__N=void 0})):(e.__h.some(be),e.__h.some(Ge),e.__h=[],qe=0)),ze=P},w.diffed=function(t){wt&&wt(t);var e=t.__c;e&&e.__H&&(e.__H.__h.length&&(yt.push(e)!==1&&pt===w.requestAnimationFrame||((pt=w.requestAnimationFrame)||_n)(fn)),e.__H.__.some(function(n){n.u&&(n.__H=n.u),n.u=void 0})),ze=P=null},w.__c=function(t,e){e.some(function(n){try{n.__h.some(be),n.__h=n.__h.filter(function(r){return!r.__||Ge(r)})}catch(r){e.some(function(i){i.__h&&(i.__h=[])}),e=[],w.__e(r,n.__v)}}),kt&&kt(t,e)},w.unmount=function(t){St&&St(t);var e,n=t.__c;n&&n.__H&&(n.__H.__.some(function(r){try{be(r)}catch(i){e=i}}),n.__H=void 0,e&&w.__e(e,n.__v))};var xt=typeof requestAnimationFrame=="function";function _n(t){var e,n=function(){clearTimeout(r),xt&&cancelAnimationFrame(e),setTimeout(t)},r=setTimeout(n,35);xt&&(e=requestAnimationFrame(n))}function be(t){var e=P,n=t.__c;typeof n=="function"&&(t.__c=void 0,n()),P=e}function Ge(t){var e=P;t.__c=t.__(),P=e}function vn(t,e){return!t||t.length!==e.length||e.some(function(n,r){return n!==t[r]})}var hn=Symbol.for("preact-signals");function we(){if(B>1)B--;else{var t,e=!1;for((function(){var i=Se;for(Se=void 0;i!==void 0;)i.S.v===i.v&&(i.S.i=i.i),i=i.o})();ne!==void 0;){var n=ne;for(ne=void 0,ke++;n!==void 0;){var r=n.u;if(n.u=void 0,n.f&=-3,!(8&n.f)&&Pt(n))try{n.c()}catch(i){e||(t=i,e=!0)}n=r}}if(ke=0,B--,e)throw t}}function pn(t){if(B>0)return t();He=++mn,B++;try{return t()}finally{we()}}var p=void 0;function Et(t){var e=p;p=void 0;try{return t()}finally{p=e}}var ne=void 0,B=0,ke=0,mn=0,He=0,Se=void 0,Ce=0;function Tt(t){if(p!==void 0){var e=t.n;if(e===void 0||e.t!==p)return e={i:0,S:t,p:p.s,n:void 0,t:p,e:void 0,x:void 0,r:e},p.s!==void 0&&(p.s.n=e),p.s=e,t.n=e,32&p.f&&t.S(e),e;if(e.i===-1)return e.i=0,e.n!==void 0&&(e.n.p=e.p,e.p!==void 0&&(e.p.n=e.n),e.p=p.s,e.n=void 0,p.s.n=e,p.s=e),e}}function S(t,e){this.v=t,this.i=0,this.n=void 0,this.t=void 0,this.l=0,this.W=e?.watched,this.Z=e?.unwatched,this.name=e?.name}S.prototype.brand=hn,S.prototype.h=function(){return!0},S.prototype.S=function(t){var e=this,n=this.t;n!==t&&t.e===void 0&&(t.x=n,this.t=t,n!==void 0?n.e=t:Et(function(){var r;(r=e.W)==null||r.call(e)}))},S.prototype.U=function(t){var e=this;if(this.t!==void 0){var n=t.e,r=t.x;n!==void 0&&(n.x=r,t.e=void 0),r!==void 0&&(r.e=n,t.x=void 0),t===this.t&&(this.t=r,r===void 0&&Et(function(){var i;(i=e.Z)==null||i.call(e)}))}},S.prototype.subscribe=function(t){var e=this;return K(function(){var n=e.value,r=p;p=void 0;try{t(n)}finally{p=r}},{name:"sub"})},S.prototype.valueOf=function(){return this.value},S.prototype.toString=function(){return this.value+""},S.prototype.toJSON=function(){return this.value},S.prototype.peek=function(){var t=p;p=void 0;try{return this.value}finally{p=t}},Object.defineProperty(S.prototype,"value",{get:function(){var t=Tt(this);return t!==void 0&&(t.i=this.i),this.v},set:function(t){if(t!==this.v){if(ke>100)throw new Error("Cycle detected");(function(n){B!==0&&ke===0&&n.l!==He&&(n.l=He,Se={S:n,v:n.v,i:n.i,o:Se})})(this),this.v=t,this.i++,Ce++,B++;try{for(var e=this.t;e!==void 0;e=e.x)e.t.N()}finally{we()}}}});function v(t,e){return new S(t,e)}function Pt(t){for(var e=t.s;e!==void 0;e=e.n)if(e.S.i!==e.i||!e.S.h()||e.S.i!==e.i)return!0;return!1}function It(t){for(var e=t.s;e!==void 0;e=e.n){var n=e.S.n;if(n!==void 0&&(e.r=n),e.S.n=e,e.i=-1,e.n===void 0){t.s=e;break}}}function Nt(t){for(var e=t.s,n=void 0;e!==void 0;){var r=e.p;e.i===-1?(e.S.U(e),r!==void 0&&(r.n=e.n),e.n!==void 0&&(e.n.p=r)):n=e,e.S.n=e.r,e.r!==void 0&&(e.r=void 0),e=r}t.s=n}function z(t,e){S.call(this,void 0),this.x=t,this.s=void 0,this.g=Ce-1,this.f=4,this.W=e?.watched,this.Z=e?.unwatched,this.name=e?.name}z.prototype=new S,z.prototype.h=function(){if(this.f&=-3,1&this.f)return!1;if((36&this.f)==32||(this.f&=-5,this.g===Ce))return!0;if(this.g=Ce,this.f|=1,this.i>0&&!Pt(this))return this.f&=-2,!0;var t=p;try{It(this),p=this;var e=this.x();(16&this.f||this.v!==e||this.i===0)&&(this.v=e,this.f&=-17,this.i++)}catch(n){this.v=n,this.f|=16,this.i++}return p=t,Nt(this),this.f&=-2,!0},z.prototype.S=function(t){if(this.t===void 0){this.f|=36;for(var e=this.s;e!==void 0;e=e.n)e.S.S(e)}S.prototype.S.call(this,t)},z.prototype.U=function(t){if(this.t!==void 0&&(S.prototype.U.call(this,t),this.t===void 0)){this.f&=-33;for(var e=this.s;e!==void 0;e=e.n)e.S.U(e)}},z.prototype.N=function(){if(!(2&this.f)){this.f|=6;for(var t=this.t;t!==void 0;t=t.x)t.t.N()}},Object.defineProperty(z.prototype,"value",{get:function(){if(1&this.f)throw new Error("Cycle detected");var t=Tt(this);if(this.h(),t!==void 0&&(t.i=this.i),16&this.f)throw this.v;return this.v}});function At(t,e){return new z(t,e)}function Bt(t){var e=t.m;if(t.m=void 0,typeof e=="function"){B++;var n=p;p=void 0;try{e()}catch(r){throw t.f&=-2,t.f|=8,We(t),r}finally{p=n,we()}}}function We(t){for(var e=t.s;e!==void 0;e=e.n)e.S.U(e);t.x=void 0,t.s=void 0,Bt(t)}function yn(t){if(p!==this)throw new Error("Out-of-order effect");Nt(this),p=t,this.f&=-2,8&this.f&&We(this),we()}function Z(t,e){this.x=t,this.m=void 0,this.s=void 0,this.u=void 0,this.f=32,this.name=e?.name}Z.prototype.c=function(){var t=this.S();try{if(8&this.f||this.x===void 0)return;var e=this.x();typeof e=="function"&&(this.m=e)}finally{t()}},Z.prototype.S=function(){if(1&this.f)throw new Error("Cycle detected");this.f|=1,this.f&=-9,Bt(this),It(this),B++;var t=p;return p=this,yn.bind(this,t)},Z.prototype.N=function(){2&this.f||(this.f|=2,this.u=ne,ne=this)},Z.prototype.d=function(){this.f|=8,1&this.f||We(this)},Z.prototype.dispose=function(){this.d()};function K(t,e){var n=new Z(t,e);try{n.c()}catch(i){throw n.d(),i}var r=n.d.bind(n);return r[Symbol.dispose]=r,r}var Lt,$e,gn=typeof window<"u"&&!!window.__PREACT_SIGNALS_DEVTOOLS__,Dt=[];K(function(){Lt=this.N})();function Q(t,e){h[t]=e.bind(null,h[t]||function(){})}function xe(t){if($e){var e=$e;$e=void 0,e()}$e=t&&t.S()}function Ot(t){var e=this,n=t.data,r=wn(n);r.value=n;var i=$t(function(){for(var c=e,d=e.__v;d=d.__;)if(d.__c){d.__c.__$f|=4;break}var u=At(function(){var f=r.value.value;return f===0?0:f===!0?"":f||""}),_=At(function(){return!Array.isArray(u.value)&&!nt(u.value)}),l=K(function(){if(this.N=Ut,_.value){var f=u.value;c.__v&&c.__v.__e&&c.__v.__e.nodeType===3&&(c.__v.__e.data=f)}}),y=e.__$u.d;return e.__$u.d=function(){l(),y.call(this)},[_,u]},[]),s=i[0],o=i[1];return s.value?o.peek():o.value}Ot.displayName="ReactiveTextNode",Object.defineProperties(S.prototype,{constructor:{configurable:!0,value:void 0},type:{configurable:!0,value:Ot},props:{configurable:!0,get:function(){var t=this;return{data:{get value(){return t.value}}}}},__b:{configurable:!0,value:1}}),Q("__b",function(t,e){if(typeof e.type=="string"){var n,r=e.props;for(var i in r)if(i!=="children"){var s=r[i];s instanceof S&&(n||(e.__np=n={}),n[i]=s,r[i]=s.peek())}}t(e)}),Q("__r",function(t,e){if(t(e),e.type!==U){xe();var n,r=e.__c;r&&(r.__$f&=-2,(n=r.__$u)===void 0&&(r.__$u=n=(function(i,s){var o;return K(function(){o=this},{name:s}),o.c=i,o})(function(){var i;gn&&((i=n.y)==null||i.call(n)),r.__$f|=1,r.setState({})},typeof e.type=="function"?e.type.displayName||e.type.name:""))),xe(n)}}),Q("__e",function(t,e,n,r){xe(),t(e,n,r)}),Q("diffed",function(t,e){xe();var n;if(typeof e.type=="string"&&(n=e.__e)){var r=e.__np,i=e.props;if(r){var s=n.U;if(s)for(var o in s){var c=s[o];c!==void 0&&!(o in r)&&(c.d(),s[o]=void 0)}else s={},n.U=s;for(var d in r){var u=s[d],_=r[d];u===void 0?(u=bn(n,d,_),s[d]=u):u.o(_,i)}for(var l in r)i[l]=r[l]}}t(e)});function bn(t,e,n,r){var i=e in t&&t.ownerSVGElement===void 0,s=v(n),o=n.peek();return{o:function(c,d){s.value=c,o=c.peek()},d:K(function(){this.N=Ut;var c=s.value.value;o!==c?(o=void 0,i?t[e]=c:c!=null&&(c!==!1||e[4]==="-")?t.setAttribute(e,c):t.removeAttribute(e)):o=void 0})}}Q("unmount",function(t,e){if(typeof e.type=="string"){var n=e.__e;if(n){var r=n.U;if(r){n.U=void 0;for(var i in r){var s=r[i];s&&s.d()}}}e.__np=void 0}else{var o=e.__c;if(o){var c=o.__$u;c&&(o.__$u=void 0,c.d())}}t(e)}),Q("__h",function(t,e,n,r){(r<3||r===9)&&(e.__$f|=2),t(e,n,r)}),te.prototype.shouldComponentUpdate=function(t,e){if(this.__R)return!0;var n=this.__$u,r=n&&n.s!==void 0;for(var i in e)return!0;if(this.__f||typeof this.u=="boolean"&&this.u===!0){var s=2&this.__$f;if(!(r||s||4&this.__$f)||1&this.__$f)return!0}else if(!(r||4&this.__$f)||3&this.__$f)return!0;for(var o in t)if(o!=="__source"&&t[o]!==this.props[o])return!0;for(var c in this.props)if(!(c in t))return!0;return!1};function wn(t,e){return $t(function(){return v(t,e)},[])}var kn=function(t){queueMicrotask(function(){queueMicrotask(t)})};function Sn(){pn(function(){for(var t;t=Dt.shift();)Lt.call(t)})}function Ut(){Dt.push(this)===1&&(h.requestAnimationFrame||kn)(Sn)}const Mt="runcontext_wizard_state",Rt=["Connect","Define","Scaffold","Checkpoint","Enrich","Serve"],b=v(1),L=v({product_name:"",description:"",owner:{name:"",team:"",email:""},sensitivity:"internal",docs:[]}),x=v([]),T=v(null),Je=v(null),X=v({}),ie=v({}),G=v([]);function Cn(){try{const t=sessionStorage.getItem(Mt);if(!t)return;const e=JSON.parse(t);e.step&&(b.value=e.step),e.brief&&(L.value=e.brief),e.sources&&(x.value=e.sources),e.pipelineId&&(T.value=e.pipelineId)}catch{}}Cn(),K(()=>{const t={step:b.value,brief:L.value,sources:x.value,pipelineId:T.value};try{sessionStorage.setItem(Mt,JSON.stringify(t))}catch{}});function C({variant:t="primary",size:e="md",className:n,children:r,...i}){const s=["rc-btn",`rc-btn--${t}`,`rc-btn--${e}`,n].filter(Boolean).join(" ");return a("button",{className:s,...i,children:r})}function M({interactive:t=!1,className:e,children:n,...r}){const i=["rc-card",t&&"rc-card--interactive",e].filter(Boolean).join(" ");return a("div",{className:i,...r,children:n})}function $n({variant:t,className:e,children:n,...r}){const i=["rc-badge",`rc-badge--${t}`,e].filter(Boolean).join(" ");return a("span",{className:i,...r,children:n})}var xn={gold:"AI-Ready",silver:"Trusted",bronze:"Discoverable"};function jt({tier:t,...e}){return a($n,{variant:t,...e,children:xn[t]})}function re({error:t=!1,className:e,...n}){const r=["rc-input",t&&"rc-input--error",e].filter(Boolean).join(" ");return a("input",{className:r,...n})}function En({error:t=!1,className:e,...n}){const r=["rc-textarea",t&&"rc-textarea--error",e].filter(Boolean).join(" ");return a("textarea",{className:r,...n})}function Tn({error:t=!1,className:e,children:n,...r}){const i=["rc-select",t&&"rc-select--error",e].filter(Boolean).join(" ");return a("select",{className:i,...r,children:n})}function Pn({events:t,className:e,...n}){const r=["rc-activity-feed",e].filter(Boolean).join(" ");return t.length===0?a("div",{className:r,...n,children:a("p",{className:"rc-activity-feed__message",children:"No recent activity."})}):a("div",{className:r,...n,children:t.map(i=>a("div",{className:"rc-activity-feed__item",children:[a("span",{className:"rc-activity-feed__dot"}),a("span",{className:"rc-activity-feed__message",children:i.message}),a("span",{className:"rc-activity-feed__meta",children:i.timestamp})]},i.id))})}function Ft({message:t,action:e,className:n,...r}){const i=["rc-error-card",n].filter(Boolean).join(" ");return a("div",{className:i,...r,children:[a("p",{className:"rc-error-card__message",children:t}),e]})}function In({code:t,className:e,...n}){const r=["rc-code",e].filter(Boolean).join(" ");return a("pre",{className:r,...n,children:a("code",{children:t})})}function Nn(){return a(M,{className:"checkpoint-card",children:[a("h2",{children:"Bronze Tier Achieved"}),a("div",{class:"tier-scorecard",children:[a("div",{class:"tier-row achieved",children:[a(jt,{tier:"bronze"}),a("span",{class:"tier-desc",children:"Schema metadata, table/column names, types, row counts"})]}),a("div",{class:"tier-row",children:[a("span",{class:"tier-label",children:"Silver"}),a("span",{class:"tier-desc",children:"Column descriptions, sample values, trust tags"})]}),a("div",{class:"tier-row",children:[a("span",{class:"tier-label",children:"Gold"}),a("span",{class:"tier-desc",children:"Join rules, grain statements, semantic roles, golden queries, guardrail filters"})]})]}),a("p",{class:"checkpoint-explain",children:"Your semantic plane has basic schema metadata. AI tools can use this now, but with Gold tier they will understand join relationships, business descriptions, and query patterns."}),a("div",{class:"checkpoint-ctas",children:[a(C,{variant:"secondary",onClick:()=>{b.value=6},children:"Start MCP Server"}),a(C,{onClick:()=>{b.value=5},children:"Continue to Gold"})]})]})}async function E(t,e,n){const r={method:t,headers:{}};n&&!(n instanceof FormData)?(r.headers["Content-Type"]="application/json",r.body=JSON.stringify(n)):n&&(r.body=n);const i=await fetch(e,r);if(!i.ok){const o=await i.text();throw new Error(o||i.statusText)}return(i.headers.get("content-type")||"").includes("json")?i.json():i.text()}const qt={postgres:"neon",mysql:"planetscale",duckdb:null,sqlite:null,snowflake:"snowflake",bigquery:"gcp",clickhouse:"clickhouse",databricks:"databricks",mssql:"azure-sql",mongodb:"mongodb"};function An(t,e){if(!t)return e?qt[e]??null:null;const n=t.toLowerCase();return n.includes("neon")?"neon":n.includes("supabase")?"supabase":n.includes("planetscale")?"planetscale":n.includes("snowflake")?"snowflake":n.includes("bigquery")||n.includes("gcp")?"gcp":n.includes("clickhouse")?"clickhouse":n.includes("databricks")?"databricks":n.includes("azure")?"azure-sql":n.includes("mongodb")||n.includes("atlas")?"mongodb":e?qt[e]??null:null}const Ve=v([]),zt=v([]),Gt=v(new Set),ae=v([]),se=v(null),R=v(!1),D=v(null),oe=v(""),le=v(!1),ce=v(null),Ht=v(!1);function Ye(t){const e=document.getElementById("db-status-dot"),n=document.getElementById("db-status-text");e&&(e.classList.remove("error"),e.classList.add("success")),n&&(n.textContent=(t.name||t.adapter||"database")+" connected")}async function Bn(){try{const t=await E("GET","/api/auth/providers");Ve.value=t}catch{}}async function Ln(){try{const e=(await E("GET","/api/sources")).sources||[];zt.value=e;const n=new Set;for(const r of e){const i=An(r.origin,r.adapter);i&&n.add(i)}Gt.value=n}catch{}}async function Wt(t){R.value=!0,D.value=null,se.value=t;try{const e=await E("POST","/api/auth/start",{provider:t});e.databases&&(ae.value=e.databases)}catch(e){D.value=e.message||"OAuth failed"}finally{R.value=!1}}async function Dn(t){R.value=!0,D.value=null;try{if((await E("POST","/api/auth/select-db",{provider:se.value,database:t})).ok){const n={name:t.name||t.database,adapter:t.adapter,host:t.host,database:t.database||t.name,metadata:t.metadata};x.value=[n,...x.value],Ye(n),ae.value=[],se.value=null,b.value=2}}catch(e){D.value=e.message||"Failed to select database"}finally{R.value=!1}}async function On(t){const e={name:t.name,adapter:t.adapter,host:t.host,database:t.database||t.name,metadata:t.metadata};x.value=[e,...x.value],Ye(e),b.value=2}async function Un(){const t=oe.value.trim();if(t){le.value=!0,ce.value=null;try{const e=await E("POST","/api/sources",{connection:t});e.source&&(x.value=[e.source,...x.value],Ye(e.source),oe.value="",b.value=2)}catch(e){ce.value=e.message||"Connection failed"}finally{le.value=!1}}}function Mn(){ae.value=[],se.value=null,D.value=null}function Rn(){if(Ht.value||(Ht.value=!0,Bn(),Ln()),ae.value.length>0)return a("div",{children:[a("div",{class:"oauth-result-header",children:[a("h2",{class:"connect-heading",children:"Select a database"}),a("a",{href:"#",class:"muted",onClick:i=>{i.preventDefault(),Mn()},children:"← Back to providers"})]}),D.value&&a("p",{class:"field-error",children:D.value}),a("div",{class:"source-cards",children:ae.value.map(i=>a(M,{interactive:!0,children:a("div",{class:"source-card",children:[a("div",{class:"source-card-name",children:i.name||i.database}),i.host&&a("div",{class:"source-card-host",children:i.host}),i.adapter&&a("div",{class:"source-card-meta",children:i.adapter}),a(C,{size:"sm",disabled:R.value,onClick:()=>Dn(i),children:"Use This"})]})},i.id||i.name))})]});const t=Gt.value,e=zt.value.filter(i=>i.adapter==="duckdb"||i.adapter==="sqlite"),n=Ve.value.filter(i=>t.has(i.id)),r=Ve.value.filter(i=>!t.has(i.id));return a("div",{children:[a("h2",{class:"connect-heading",children:"Connect a database"}),a("p",{class:"connect-subheading",children:"Choose a cloud provider, use a local file, or paste a connection string."}),D.value&&a("p",{class:"field-error",children:D.value}),t.size>0&&a("p",{class:"detected-hint",children:"We detected database configurations in your project."}),e.length>0&&a("div",{class:"source-cards",children:e.map(i=>a(M,{interactive:!0,children:a("div",{class:"source-card source-card-local",children:[a("span",{class:"source-card-badge",children:i.adapter}),a("div",{class:"source-card-name",children:i.name||i.database}),i.host&&a("div",{class:"source-card-host",children:i.host}),a(C,{size:"sm",onClick:()=>On(i),children:"Use This"})]})},i.name||i.database))}),n.length>0&&a("div",{class:"source-cards",children:n.map(i=>a(M,{interactive:!0,children:a("div",{class:"source-card source-card-detected",children:[a("span",{class:"source-card-badge",children:"detected"}),a("div",{class:"source-card-name",children:i.displayName||i.display_name||i.id}),a(C,{size:"sm",disabled:R.value,onClick:()=>Wt(i.id),children:R.value&&se.value===i.id?"Connecting...":"Connect"})]})},i.id))}),(e.length>0||n.length>0)&&r.length>0&&a("div",{class:"section-divider"}),r.length>0&&a("div",{class:"platform-grid",children:r.map(i=>a("button",{class:"platform-btn",disabled:R.value,onClick:()=>Wt(i.id),children:i.displayName||i.display_name||i.id},i.id))}),a("div",{class:"manual-connect",children:[a("label",{class:"label-uppercase",children:"Or paste a connection string"}),a("div",{class:"manual-connect-row",children:[a(re,{placeholder:"postgres://user:pass@host:5432/dbname",value:oe.value,onInput:i=>{oe.value=i.target.value},error:!!ce.value,disabled:le.value}),a(C,{variant:"secondary",disabled:le.value||!oe.value.trim(),onClick:()=>Un(),children:le.value?"Connecting...":"Connect"})]}),ce.value&&a("p",{class:"field-error",children:ce.value})]})]})}const Ee=v(!1),Te=v(""),Jt=v({}),Pe=v(!1);function jn(){const t=L.value;function e(i,s){if(i.startsWith("owner.")){const o=i.split(".")[1];L.value={...t,owner:{...t.owner,[o]:s}}}else L.value={...t,[i]:s}}async function n(){const i={};if(t.product_name.trim()?/^[a-zA-Z0-9_-]+$/.test(t.product_name.trim())||(i.product_name="Only letters, numbers, hyphens, and underscores allowed."):i.product_name="Product name is required.",t.description.trim()||(i.description="Description is required."),Jt.value=i,!(Object.keys(i).length>0)){Ee.value=!0,Te.value="";try{await E("POST","/api/brief",t),b.value=3}catch(s){Te.value=s.message||"Failed to save. Please try again."}finally{Ee.value=!1}}}!Pe.value&&!t.product_name&&!t.description&&!t.owner.name&&x.value.length>0&&(Pe.value=!0,E("POST","/api/suggest-brief",{source:x.value[0]}).then(i=>{const s=L.value;L.value={product_name:s.product_name||i.product_name||"",description:s.description||i.description||"",owner:{name:s.owner.name||i.owner?.name||"",team:s.owner.team||i.owner?.team||"",email:s.owner.email||i.owner?.email||""},sensitivity:s.sensitivity||i.sensitivity||"internal",docs:s.docs}}).catch(()=>{}).finally(()=>{Pe.value=!1}));const r=Jt.value;return a(M,{children:[a("h2",{children:"Define Your Data Product"}),a("p",{class:"muted",children:"Tell us about your data product. This metadata helps AI agents understand what they are working with."}),Pe.value&&a("p",{class:"muted suggest-loading",children:"Auto-filling from your database..."}),a("div",{class:"define-form",children:[a("div",{class:"field full-width",children:[a("label",{for:"product_name",children:"Product Name *"}),a(re,{id:"product_name",value:t.product_name,onInput:i=>e("product_name",i.currentTarget.value),placeholder:"my-data-product",error:!!r.product_name}),r.product_name&&a("p",{class:"field-error",children:r.product_name}),a("p",{class:"hint",children:"Alphanumeric, hyphens, and underscores only."})]}),a("div",{class:"field full-width",children:[a("label",{for:"description",children:"Description *"}),a(En,{id:"description",value:t.description,onInput:i=>e("description",i.currentTarget.value),placeholder:"What does this data product provide?",error:!!r.description}),r.description&&a("p",{class:"field-error",children:r.description})]}),a("div",{class:"field",children:[a("label",{for:"owner_name",children:"Owner Name"}),a(re,{id:"owner_name",value:t.owner.name,onInput:i=>e("owner.name",i.currentTarget.value),placeholder:"Jane Doe"})]}),a("div",{class:"field",children:[a("label",{for:"owner_team",children:"Team"}),a(re,{id:"owner_team",value:t.owner.team,onInput:i=>e("owner.team",i.currentTarget.value),placeholder:"Data Engineering"})]}),a("div",{class:"field",children:[a("label",{for:"owner_email",children:"Email"}),a(re,{id:"owner_email",value:t.owner.email,onInput:i=>e("owner.email",i.currentTarget.value),placeholder:"jane@example.com"})]}),a("div",{class:"field",children:[a("label",{for:"sensitivity",children:"Sensitivity"}),a(Tn,{id:"sensitivity",value:t.sensitivity,onChange:i=>e("sensitivity",i.currentTarget.value),children:[a("option",{value:"public",children:"Public"}),a("option",{value:"internal",children:"Internal"}),a("option",{value:"confidential",children:"Confidential"}),a("option",{value:"restricted",children:"Restricted"})]})]}),a("div",{class:"define-actions",children:[a(C,{variant:"secondary",onClick:()=>{b.value=1},children:"Back"}),a(C,{onClick:n,disabled:Ee.value,children:Ee.value?"Saving...":"Continue"})]}),Te.value&&a("p",{class:"field-error",children:Te.value})]})]})}const Fn=[{key:"column-descriptions",label:"Column descriptions",initial:"0/45 columns"},{key:"sample-values",label:"Sample values",initial:"0/45 columns"},{key:"join-rules",label:"Join rules",initial:"0/0"},{key:"grain-statements",label:"Grain statements",initial:"0/0"},{key:"semantic-roles",label:"Semantic roles",initial:"0/0"},{key:"golden-queries",label:"Golden queries",initial:"0/0"},{key:"guardrail-filters",label:"Guardrail filters",initial:"0/0"}],ue=v(!1),H=v(""),Ze=v(new Set);let Ie=null;function Ke(){Ie&&(clearInterval(Ie),Ie=null)}async function Vt(){ue.value=!0,H.value="",ie.value={},G.value=[{message:"Enrichment pipeline started.",timestamp:new Date().toISOString()}];const t={productName:L.value.product_name,targetTier:"gold"};if(x.value[0]){const e=x.value[0];t.dataSource=(typeof e=="string"?e:e.name||e.database||"").replace(/[^a-zA-Z0-9_-]/g,"_")}try{const e=await E("POST","/api/pipeline/start",t);T.value=e.id,qn()}catch(e){ue.value=!1,H.value=e.message||"Failed to start enrichment."}}function qn(){Ke();async function t(){if(T.value)try{const e=await E("GET","/api/pipeline/status/"+T.value),n=e.stages||[];let r=!1,i=!1,s=!1;for(const o of n)(o.name==="enrich-silver"||o.stage==="enrich-silver")&&o.status==="done"&&(i=!0),(o.name==="enrich-gold"||o.stage==="enrich-gold")&&o.status==="done"&&(s=!0),o.status==="error"&&(r=!0);r?(Ke(),ue.value=!1,H.value=e.error||"An enrichment stage failed."):i&&s&&(Ke(),ue.value=!1,G.value=[...G.value,{message:"Gold enrichment complete! Advancing...",timestamp:new Date().toISOString()}],b.value=6)}catch{}}t(),Ie=setInterval(t,3e3)}function zn(){T.value=null,ie.value={},G.value=[],H.value="",Vt()}function Gn(t){const e=new Set(Ze.value);e.has(t)?e.delete(t):e.add(t),Ze.value=e}function Hn(){const t=ie.value,e=Ze.value,n=G.value.map((r,i)=>({id:String(i),type:"log",message:r.message,timestamp:new Date(r.timestamp).toLocaleTimeString()}));return a(M,{children:[a("h2",{children:"Enriching to Gold"}),a("p",{class:"muted",children:"RunContext is analyzing your schema to add descriptions, join rules, and query patterns."}),!ue.value&&!H.value&&a("div",{class:"step-actions",children:[a(C,{variant:"secondary",onClick:()=>{b.value=4},children:"Back"}),a(C,{onClick:Vt,children:"Start Enrichment"})]}),a("div",{class:"enrich-dashboard",children:[a("div",{class:"enrich-checklist",children:Fn.map(r=>{const i=t[r.key],s=i?.status||"",o=["stage-dot",s==="working"?"running":s==="done"?"done":""].filter(Boolean).join(" ");return a("div",{class:`enrich-row${e.has(r.key)?" expanded":""}`,children:[a("div",{class:"enrich-row-header",onClick:()=>Gn(r.key),children:[a("span",{class:o}),a("span",{class:"enrich-req-name",children:r.label}),a("span",{class:"enrich-progress",children:i?.progress||r.initial}),a("span",{class:"enrich-arrow",children:"▶"})]}),a("div",{class:"enrich-row-detail",children:"Details will appear as enrichment progresses."})]})})}),a("div",{class:"activity-log",children:[a("div",{class:"activity-log-title",children:"Activity Log"}),a(Pn,{events:n})]})]}),H.value&&a(Ft,{message:H.value,action:a(C,{onClick:zn,children:"Retry"})})]})}function Wn({stageKey:t,label:e,status:n,summary:r,error:i}){const s=["stage-dot",n==="running"?"running":n==="done"?"done":n==="error"?"error":""].filter(Boolean).join(" ");return a("div",{class:"stage-row","data-stage":t,children:[a("span",{class:s}),a("span",{class:"stage-name",children:e}),r&&a("span",{class:"stage-summary",children:r}),i&&a("span",{class:"stage-error",children:i})]})}const Yt=[{key:"introspect",label:"Extracting schema from database..."},{key:"scaffold",label:"Building semantic plane files..."},{key:"verify",label:"Validating semantic plane..."},{key:"autofix",label:"Fixing any issues..."},{key:"agent-instructions",label:"Generating agent instructions..."}],W=v(!1),j=v("");let de=null;function Ne(){de&&(clearInterval(de),de=null)}async function Zt(){W.value=!0,j.value="",X.value={};const t={productName:L.value.product_name,targetTier:"bronze"};if(x.value[0]){const e=x.value[0];t.dataSource=(typeof e=="string"?e:e.name||e.database||"").replace(/[^a-zA-Z0-9_-]/g,"_")}try{const e=await E("POST","/api/pipeline/start",t);T.value=e.id,Kt()}catch(e){W.value=!1,j.value=e.message||"Failed to start build."}}function Kt(){Ne();async function t(){if(T.value)try{const e=await E("GET","/api/pipeline/status/"+T.value),n=e.stages||[],r={};let i=!1,s=!0;for(const o of Yt){const c=n.find(d=>d.stage===o.key||d.name===o.key);!c||c.status==="pending"?(s=!1,r[o.key]={status:"pending"}):(r[o.key]={status:c.status,summary:c.summary,error:c.error},c.status==="running"&&(s=!1),c.status==="error"&&(i=!0,s=!1))}X.value=r,i?(Ne(),W.value=!1,j.value=e.error||"A pipeline stage failed."):s&&n.length>0&&(Ne(),W.value=!1,b.value=4)}catch{}}t(),de=setInterval(t,2e3)}function Jn(){T.value=null,X.value={},j.value="",Zt()}function Vn(){T.value&&!de&&!j.value&&(W.value=!0,Kt());const t=X.value;return a(M,{children:[a("h2",{children:"Building Your Semantic Plane"}),a("p",{class:"muted",children:"Connecting to your database and extracting schema metadata. This creates a Bronze-tier semantic plane."}),a("div",{class:"scaffold-stages",children:Yt.map(e=>a(Wn,{stageKey:e.key,label:e.label,status:t[e.key]?.status,summary:t[e.key]?.summary,error:t[e.key]?.error},e.key))}),j.value&&a(Ft,{message:j.value,action:a(C,{onClick:Jn,children:"Retry"})}),a("div",{class:"step-actions",children:[a(C,{variant:"secondary",onClick:()=>{Ne(),b.value=2},children:"Back"}),!W.value&&!T.value&&!j.value&&a(C,{onClick:Zt,children:"Start Build"}),W.value&&a("span",{class:"muted",children:"Build in progress..."})]})]})}const J=v("bronze"),Qe=v(null),Ae=v(!1),Qt=v(!1);function Yn(){!Qt.value&&T.value&&(Qt.value=!0,E("GET","/api/pipeline/status/"+T.value).then(n=>{const r=n.stages||[];let i=!1,s=!1;for(const o of r)(o.name==="enrich-gold"||o.stage==="enrich-gold")&&o.status==="done"&&(s=!0),(o.name==="enrich-silver"||o.stage==="enrich-silver")&&o.status==="done"&&(i=!0);s?J.value="gold":i&&(J.value="silver")}).catch(()=>{}));async function t(){Ae.value=!0;try{const n=await E("GET","/api/mcp-config");Qe.value=JSON.stringify(n,null,2)}catch{}finally{Ae.value=!1}}const e=J.value.charAt(0).toUpperCase()+J.value.slice(1);return a(M,{className:"serve-card",children:[a("h2",{children:"Your Semantic Plane is Ready"}),a(jt,{tier:J.value}),a("p",{class:"muted",children:["Your ",e," tier semantic plane is ready for AI agents."]}),J.value!=="gold"&&a("p",{class:"muted",style:{marginTop:"8px"},children:["To reach Gold, run enrichment with ",a("code",{children:"context enrich --target gold"}),"."]}),a("div",{class:"serve-ctas",children:[a(C,{onClick:t,disabled:Ae.value,children:Ae.value?"Loading...":"Start MCP Server"}),a(C,{variant:"secondary",disabled:!0,title:"Coming soon",children:"Publish to Cloud"})]}),Qe.value&&a(U,{children:[a(In,{code:Qe.value}),a("p",{class:"muted",style:{marginTop:"8px",fontSize:"0.85rem"},children:["Copy the JSON above into your IDE's MCP settings, or run: ",a("code",{children:"context serve"})]})]}),a("div",{class:"serve-commands",children:[a("div",{class:"serve-commands-title",children:"CLI Commands"}),[["context serve","Start the MCP server"],["context tier","Check your current tier"],["context enrich --target gold","Enrich to Gold tier"],["context verify","Validate your semantic plane"]].map(([n,r])=>a("div",{class:"serve-cmd-row",children:[a("span",{class:"serve-cmd",children:n}),a("span",{class:"serve-cmd-desc",children:r})]}))]}),J.value!=="gold"&&a("p",{style:{marginTop:"16px"},children:a("a",{style:{color:"var(--rc-color-accent, #c9a55a)",cursor:"pointer",fontSize:"0.875rem"},onClick:()=>{b.value=5},children:"Continue Enrichment"})}),a("div",{class:"step-actions",children:a(C,{variant:"secondary",onClick:()=>{b.value=b.value-1},children:"Back"})})]})}function Zn(){switch(b.value){case 1:return a(Rn,{});case 2:return a(jn,{});case 3:return a(Vn,{});case 4:return a(Nn,{});case 5:return a(Hn,{});case 6:return a(Yn,{});default:return null}}function Kn(){return a(Zn,{})}function Qn(){const t=b.value;return a(U,{children:Rt.map((e,n)=>{const r=n+1,i=r<t?"step-completed":r===t?"step-active":"step-future";return a(U,{children:[a("span",{class:i,onClick:r<t?()=>{b.value=r}:void 0,style:r<t?{cursor:"pointer"}:void 0,children:e}),r<Rt.length&&a("span",{class:"step-separator",children:">"})]},e)})})}let F=null;function Xe(t){Je.value=t,F&&(F.onclose=null,F.close(),F=null);const e=location.protocol==="https:"?"wss:":"ws:";F=new WebSocket(`${e}//${location.host}/ws?session=${encodeURIComponent(t)}&role=wizard`),F.onmessage=n=>{try{const r=JSON.parse(n.data);Xn(r)}catch{}},F.onclose=()=>{setTimeout(()=>{Je.value&&Xe(Je.value)},2e3)},F.onerror=()=>{}}function Xn(t){const e=t.payload||{};switch(t.type){case"setup:step":e.step&&(b.value=e.step);break;case"setup:field":{const n=document.getElementById(e.fieldId);n&&(n.value=e.value||"",n.dispatchEvent(new Event("input")));break}case"pipeline:stage":X.value={...X.value,[e.stage]:{status:e.status,summary:e.summary,error:e.error}};break;case"enrich:progress":ie.value={...ie.value,[e.requirement]:{status:e.status,progress:e.progress}};break;case"enrich:log":G.value=[...G.value,{message:e.message,timestamp:e.timestamp||new Date().toISOString()}];break}}const Xt=document.getElementById("wizard-content");Xt&&Fe(a(Kn,{}),Xt);const en=document.getElementById("stepper");en&&Fe(a(Qn,{}),en);function ei(){const t=document.getElementById("locked-tooltip");t&&(document.querySelectorAll(".nav-item.locked").forEach(e=>{e.addEventListener("click",n=>{n.preventDefault(),n.stopPropagation();const r=e.getBoundingClientRect();t.style.display="block",t.style.left=r.left+"px",t.style.top=r.bottom+6+"px"})}),document.addEventListener("click",e=>{if(t.style.display!=="none"){let n=!1;document.querySelectorAll(".nav-item.locked").forEach(r=>{r.contains(e.target)&&(n=!0)}),n||(t.style.display="none")}}))}function ti(){async function t(){const e=document.getElementById("mcp-status-dot"),n=document.getElementById("mcp-status-text"),r=document.getElementById("mcp-server-dot"),i=document.getElementById("mcp-server-text");if(!(!e||!n))try{const s=new AbortController,o=setTimeout(()=>s.abort(),2e3);await fetch("http://localhost:3333/health",{method:"GET",mode:"no-cors",signal:s.signal}),clearTimeout(o),e.classList.remove("error"),e.classList.add("success"),n.textContent="connected",r&&(r.classList.remove("error"),r.classList.add("success")),i&&(i.textContent="MCP running")}catch{e.classList.remove("success"),n.textContent="offline",r&&r.classList.remove("success"),i&&(i.textContent="MCP stopped")}}t(),setInterval(t,1e4)}function ni(){if(ei(),ti(),x.value.length>0){const n=x.value[0],r=document.getElementById("db-status-dot"),i=document.getElementById("db-status-text");r&&i&&(r.classList.remove("error"),r.classList.add("success"),i.textContent=(n.name||n.adapter)+" connected")}E("GET","/api/products").then(n=>{if(n.length>0){const r=document.getElementById("wizard-content");if(!r)return;const i=document.createElement("div");r.insertBefore(i,r.firstChild),Fe(a("div",{class:"existing-products-banner",children:[a("p",{class:"banner-title",children:["Your semantic plane has ",n.length," data product",n.length===1?"":"s",". Adding another."]}),a("div",{class:"product-chips",children:n.map(s=>a("span",{class:"product-chip",children:s.name}))})]}),i)}}).catch(()=>{});const e=new URLSearchParams(window.location.search).get("session");e?Xe(e):E("POST","/api/session").then(n=>{if(n.sessionId){Xe(n.sessionId);const r=window.location.pathname+"?session="+encodeURIComponent(n.sessionId);window.history.replaceState({},"",r)}}).catch(()=>{})}document.addEventListener("DOMContentLoaded",ni)})();
|