@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.
Files changed (2) hide show
  1. package/package.json +10 -4
  2. 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&&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)})();