@luckydraw/cumulus 0.28.4 → 0.28.5
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/gateway/adapters/webchat.d.ts.map +1 -1
- package/dist/gateway/adapters/webchat.js +6 -0
- package/dist/gateway/adapters/webchat.js.map +1 -1
- package/dist/gateway/gateway-agents-mcp.js +87 -0
- package/dist/gateway/gateway-agents-mcp.js.map +1 -1
- package/dist/gateway/static/blex.min.js +34 -11
- package/dist/gateway/static/chat.html +5 -0
- package/dist/gateway/static/icon-192.png +0 -0
- package/dist/gateway/static/icon-192.svg +4 -0
- package/dist/gateway/static/manifest.json +15 -0
- package/dist/gateway/static/widget.js +209 -47
- package/package.json +1 -1
|
@@ -3,6 +3,11 @@
|
|
|
3
3
|
<head>
|
|
4
4
|
<meta charset="utf-8">
|
|
5
5
|
<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1, user-scalable=no">
|
|
6
|
+
<meta name="apple-mobile-web-app-capable" content="yes">
|
|
7
|
+
<meta name="apple-mobile-web-app-status-bar-style" content="black-translucent">
|
|
8
|
+
<meta name="apple-mobile-web-app-title" content="Cumulus">
|
|
9
|
+
<link rel="manifest" href="/manifest.json">
|
|
10
|
+
<link rel="apple-touch-icon" href="/icon-192.png">
|
|
6
11
|
<title>Cumulus Chat</title>
|
|
7
12
|
<style>
|
|
8
13
|
*, *::before, *::after { box-sizing: border-box; }
|
|
Binary file
|
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
<svg xmlns="http://www.w3.org/2000/svg" width="192" height="192" viewBox="0 0 192 192">
|
|
2
|
+
<rect width="192" height="192" rx="32" fill="#2d2d2d"/>
|
|
3
|
+
<text x="96" y="120" font-family="system-ui, -apple-system, sans-serif" font-size="100" font-weight="700" fill="#e0e0e0" text-anchor="middle">C</text>
|
|
4
|
+
</svg>
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "Cumulus Chat",
|
|
3
|
+
"short_name": "Cumulus",
|
|
4
|
+
"start_url": "/chat",
|
|
5
|
+
"display": "standalone",
|
|
6
|
+
"background_color": "#1e1e1e",
|
|
7
|
+
"theme_color": "#1e1e1e",
|
|
8
|
+
"icons": [
|
|
9
|
+
{
|
|
10
|
+
"src": "/icon-192.png",
|
|
11
|
+
"sizes": "192x192",
|
|
12
|
+
"type": "image/png"
|
|
13
|
+
}
|
|
14
|
+
]
|
|
15
|
+
}
|
|
@@ -234,10 +234,13 @@
|
|
|
234
234
|
' display: inline-flex; align-items: center; gap: 0.3em;',
|
|
235
235
|
' background: #2a3a4a; color: #d4e8f8; border: 1px solid #3a5060;',
|
|
236
236
|
' border-radius: 1em; padding: 0.15em 0.6em; font-size: 0.82em;',
|
|
237
|
-
' cursor: default; max-width: 32ch;
|
|
237
|
+
' cursor: default; max-width: 32ch;',
|
|
238
|
+
'}',
|
|
239
|
+
'.cumulus-interaction-chip .chip-label {',
|
|
240
|
+
' overflow: hidden; text-overflow: ellipsis; white-space: nowrap; min-width: 0;',
|
|
238
241
|
'}',
|
|
239
242
|
'.cumulus-interaction-chip .chip-dismiss {',
|
|
240
|
-
' cursor: pointer; opacity: 0.6; font-size: 0.9em; margin-left: 0.2em;',
|
|
243
|
+
' cursor: pointer; opacity: 0.6; font-size: 0.9em; margin-left: 0.2em; flex-shrink: 0;',
|
|
241
244
|
'}',
|
|
242
245
|
'.cumulus-interaction-chip .chip-dismiss:hover { opacity: 1; }',
|
|
243
246
|
|
|
@@ -246,10 +249,13 @@
|
|
|
246
249
|
' display: inline-flex; align-items: center; gap: 0.3em;',
|
|
247
250
|
' background: #2a3a2a; color: #b8e6b8; border: 1px solid #3a6040;',
|
|
248
251
|
' border-radius: 1em; padding: 0.15em 0.6em; font-size: 0.82em;',
|
|
249
|
-
' cursor: default; max-width: 40ch;
|
|
252
|
+
' cursor: default; max-width: 40ch;',
|
|
253
|
+
'}',
|
|
254
|
+
'.cumulus-annotation-chip .chip-label {',
|
|
255
|
+
' overflow: hidden; text-overflow: ellipsis; white-space: nowrap; min-width: 0;',
|
|
250
256
|
'}',
|
|
251
257
|
'.cumulus-annotation-chip .chip-dismiss {',
|
|
252
|
-
' cursor: pointer; opacity: 0.6; font-size: 0.9em; margin-left: 0.2em;',
|
|
258
|
+
' cursor: pointer; opacity: 0.6; font-size: 0.9em; margin-left: 0.2em; flex-shrink: 0;',
|
|
253
259
|
'}',
|
|
254
260
|
'.cumulus-annotation-chip .chip-dismiss:hover { opacity: 1; }',
|
|
255
261
|
|
|
@@ -1228,7 +1234,23 @@
|
|
|
1228
1234
|
|
|
1229
1235
|
// Per-thread store for blex interaction values (poll answers, confirm clicks, etc.)
|
|
1230
1236
|
// Key: "threadName" → Map<"msgTimestamp:blockIdx", interactionValue>
|
|
1237
|
+
// Backed by localStorage for persistence across page refreshes
|
|
1238
|
+
var BLEX_STORE_KEY = 'cumulus-blex-interactions';
|
|
1231
1239
|
var blexInteractionStore = {};
|
|
1240
|
+
try {
|
|
1241
|
+
var saved = localStorage.getItem(BLEX_STORE_KEY);
|
|
1242
|
+
if (saved) blexInteractionStore = JSON.parse(saved);
|
|
1243
|
+
} catch (e) {
|
|
1244
|
+
/* ignore corrupt/missing localStorage */
|
|
1245
|
+
}
|
|
1246
|
+
|
|
1247
|
+
function _flushBlexStore() {
|
|
1248
|
+
try {
|
|
1249
|
+
localStorage.setItem(BLEX_STORE_KEY, JSON.stringify(blexInteractionStore));
|
|
1250
|
+
} catch (e) {
|
|
1251
|
+
/* quota exceeded or private browsing */
|
|
1252
|
+
}
|
|
1253
|
+
}
|
|
1232
1254
|
|
|
1233
1255
|
// Extract ~~~blex:TYPE\n{json}\n~~~ fences from text
|
|
1234
1256
|
// Returns { text: string (with placeholders), blocks: Array<{type, json, idx}> }
|
|
@@ -1288,9 +1310,10 @@
|
|
|
1288
1310
|
if (handle && handle.onInteraction) {
|
|
1289
1311
|
// Wire interaction handler
|
|
1290
1312
|
handle.onInteraction(function (interaction) {
|
|
1291
|
-
// Store the interaction value for persistence across re-renders
|
|
1313
|
+
// Store the interaction value for persistence across re-renders + refreshes
|
|
1292
1314
|
if (store && storeKey && interaction.value !== undefined) {
|
|
1293
1315
|
store[storeKey] = interaction.value;
|
|
1316
|
+
_flushBlexStore();
|
|
1294
1317
|
}
|
|
1295
1318
|
|
|
1296
1319
|
// Find the panel — try el.closest first, fall back to document query
|
|
@@ -1319,8 +1342,8 @@
|
|
|
1319
1342
|
sendBtn.click();
|
|
1320
1343
|
}
|
|
1321
1344
|
} else {
|
|
1322
|
-
// Deferred: add to chip tray
|
|
1323
|
-
addInteractionChip(panel, interaction, handle);
|
|
1345
|
+
// Deferred: add to chip tray (sourceId deduplicates rapid-fire from same block)
|
|
1346
|
+
addInteractionChip(panel, interaction, handle, block.type + '-' + idx);
|
|
1324
1347
|
}
|
|
1325
1348
|
}
|
|
1326
1349
|
});
|
|
@@ -1360,16 +1383,27 @@
|
|
|
1360
1383
|
}
|
|
1361
1384
|
|
|
1362
1385
|
// Add a deferred interaction chip to the chip tray
|
|
1363
|
-
|
|
1386
|
+
// If a chip from the same source already exists, replace it (prevents spam from rapid interactions)
|
|
1387
|
+
function addInteractionChip(panel, interaction, handle, sourceId) {
|
|
1364
1388
|
if (!panel) return;
|
|
1365
1389
|
var tray = panel.querySelector('.cumulus-chip-tray');
|
|
1366
1390
|
if (!tray) return;
|
|
1367
1391
|
|
|
1392
|
+
// Replace existing chip from same source instead of appending
|
|
1393
|
+
if (sourceId) {
|
|
1394
|
+
var existing = tray.querySelector(
|
|
1395
|
+
'.cumulus-interaction-chip[data-source="' + sourceId + '"]'
|
|
1396
|
+
);
|
|
1397
|
+
if (existing) existing.remove();
|
|
1398
|
+
}
|
|
1399
|
+
|
|
1368
1400
|
var chip = document.createElement('span');
|
|
1369
1401
|
chip.className = 'cumulus-interaction-chip';
|
|
1370
1402
|
chip.setAttribute('data-serialized', interaction.serialized || '');
|
|
1403
|
+
if (sourceId) chip.setAttribute('data-source', sourceId);
|
|
1371
1404
|
|
|
1372
1405
|
var label = document.createElement('span');
|
|
1406
|
+
label.className = 'chip-label';
|
|
1373
1407
|
label.textContent =
|
|
1374
1408
|
(interaction.icon || '\u2022') +
|
|
1375
1409
|
' ' +
|
|
@@ -1435,17 +1469,30 @@
|
|
|
1435
1469
|
var chip = document.createElement('span');
|
|
1436
1470
|
chip.className = 'cumulus-annotation-chip';
|
|
1437
1471
|
chip.setAttribute('data-serialized', serialized);
|
|
1472
|
+
chip.setAttribute('data-quote', quote);
|
|
1473
|
+
chip.setAttribute('data-comment', comment);
|
|
1474
|
+
chip.setAttribute('data-is-code', isCodeBlock ? '1' : '');
|
|
1475
|
+
chip.setAttribute('data-code-lang', codeLang || '');
|
|
1438
1476
|
chip.title = '"' + quote + '"\n\n' + comment;
|
|
1439
1477
|
|
|
1440
1478
|
var label = document.createElement('span');
|
|
1479
|
+
label.className = 'chip-label';
|
|
1441
1480
|
label.textContent =
|
|
1442
1481
|
'\uD83D\uDCDD \u201C' + truncatedQuote + '\u201D \u2192 ' + truncatedComment;
|
|
1443
1482
|
chip.appendChild(label);
|
|
1444
1483
|
|
|
1484
|
+
// Click label to edit
|
|
1485
|
+
label.style.cursor = 'pointer';
|
|
1486
|
+
label.addEventListener('click', function (e) {
|
|
1487
|
+
e.stopPropagation();
|
|
1488
|
+
showAnnotationEditPopover(panel, chip);
|
|
1489
|
+
});
|
|
1490
|
+
|
|
1445
1491
|
var dismiss = document.createElement('span');
|
|
1446
1492
|
dismiss.className = 'chip-dismiss';
|
|
1447
1493
|
dismiss.textContent = '\u00d7';
|
|
1448
|
-
dismiss.addEventListener('click', function () {
|
|
1494
|
+
dismiss.addEventListener('click', function (e) {
|
|
1495
|
+
e.stopPropagation();
|
|
1449
1496
|
chip.remove();
|
|
1450
1497
|
});
|
|
1451
1498
|
chip.appendChild(dismiss);
|
|
@@ -1453,6 +1500,104 @@
|
|
|
1453
1500
|
tray.appendChild(chip);
|
|
1454
1501
|
}
|
|
1455
1502
|
|
|
1503
|
+
// Show the annotation popover near a chip for editing
|
|
1504
|
+
function showAnnotationEditPopover(panel, chip) {
|
|
1505
|
+
dismissAnnotationPopover(panel);
|
|
1506
|
+
|
|
1507
|
+
var quote = chip.getAttribute('data-quote') || '';
|
|
1508
|
+
var comment = chip.getAttribute('data-comment') || '';
|
|
1509
|
+
var isCodeBlock = chip.getAttribute('data-is-code') === '1';
|
|
1510
|
+
var codeLang = chip.getAttribute('data-code-lang') || '';
|
|
1511
|
+
|
|
1512
|
+
var popover = document.createElement('div');
|
|
1513
|
+
popover.className = 'cumulus-annotation-popover';
|
|
1514
|
+
|
|
1515
|
+
// Position near the chip
|
|
1516
|
+
var panelRect = panel.getBoundingClientRect();
|
|
1517
|
+
var chipRect = chip.getBoundingClientRect();
|
|
1518
|
+
var top = chipRect.top - panelRect.top + panel.scrollTop - 160;
|
|
1519
|
+
if (top < 4) top = chipRect.bottom - panelRect.top + panel.scrollTop + 4;
|
|
1520
|
+
var left = chipRect.left - panelRect.left;
|
|
1521
|
+
if (left + 260 > panelRect.width) left = panelRect.width - 270;
|
|
1522
|
+
if (left < 4) left = 4;
|
|
1523
|
+
popover.style.top = top + 'px';
|
|
1524
|
+
popover.style.left = left + 'px';
|
|
1525
|
+
|
|
1526
|
+
var quoteEl = document.createElement('div');
|
|
1527
|
+
quoteEl.className = 'annotation-quote';
|
|
1528
|
+
quoteEl.textContent = '\u201C' + quote + '\u201D';
|
|
1529
|
+
popover.appendChild(quoteEl);
|
|
1530
|
+
|
|
1531
|
+
var textarea = document.createElement('textarea');
|
|
1532
|
+
textarea.placeholder = 'Edit comment\u2026';
|
|
1533
|
+
textarea.rows = 4;
|
|
1534
|
+
textarea.value = comment;
|
|
1535
|
+
textarea.setAttribute('data-testid', 'annotation-edit-comment');
|
|
1536
|
+
popover.appendChild(textarea);
|
|
1537
|
+
|
|
1538
|
+
var actions = document.createElement('div');
|
|
1539
|
+
actions.className = 'annotation-actions';
|
|
1540
|
+
|
|
1541
|
+
var cancelBtn = document.createElement('button');
|
|
1542
|
+
cancelBtn.className = 'annotation-cancel';
|
|
1543
|
+
cancelBtn.textContent = 'Cancel';
|
|
1544
|
+
cancelBtn.addEventListener('click', function () {
|
|
1545
|
+
dismissAnnotationPopover(panel);
|
|
1546
|
+
});
|
|
1547
|
+
|
|
1548
|
+
var submitBtn = document.createElement('button');
|
|
1549
|
+
submitBtn.className = 'annotation-submit';
|
|
1550
|
+
submitBtn.textContent = 'Update';
|
|
1551
|
+
submitBtn.setAttribute('data-testid', 'annotation-edit-submit');
|
|
1552
|
+
submitBtn.addEventListener('click', function () {
|
|
1553
|
+
var newComment = textarea.value.trim();
|
|
1554
|
+
if (!newComment) {
|
|
1555
|
+
dismissAnnotationPopover(panel);
|
|
1556
|
+
return;
|
|
1557
|
+
}
|
|
1558
|
+
// Update chip data
|
|
1559
|
+
var newSerialized;
|
|
1560
|
+
if (isCodeBlock) {
|
|
1561
|
+
newSerialized =
|
|
1562
|
+
'```' +
|
|
1563
|
+
(codeLang && codeLang !== 'text' ? codeLang : '') +
|
|
1564
|
+
'\n' +
|
|
1565
|
+
quote +
|
|
1566
|
+
'\n```\n' +
|
|
1567
|
+
newComment;
|
|
1568
|
+
} else {
|
|
1569
|
+
newSerialized = '> ' + quote.replace(/\n/g, '\n> ') + '\n' + newComment;
|
|
1570
|
+
}
|
|
1571
|
+
chip.setAttribute('data-serialized', newSerialized);
|
|
1572
|
+
chip.setAttribute('data-comment', newComment);
|
|
1573
|
+
var truncQ = quote.length > 30 ? quote.substring(0, 30) + '\u2026' : quote;
|
|
1574
|
+
var truncC = newComment.length > 30 ? newComment.substring(0, 30) + '\u2026' : newComment;
|
|
1575
|
+
var labelEl = chip.querySelector('.chip-label');
|
|
1576
|
+
if (labelEl) {
|
|
1577
|
+
labelEl.textContent = '\uD83D\uDCDD \u201C' + truncQ + '\u201D \u2192 ' + truncC;
|
|
1578
|
+
}
|
|
1579
|
+
chip.title = '"' + quote + '"\n\n' + newComment;
|
|
1580
|
+
dismissAnnotationPopover(panel);
|
|
1581
|
+
});
|
|
1582
|
+
|
|
1583
|
+
actions.appendChild(cancelBtn);
|
|
1584
|
+
actions.appendChild(submitBtn);
|
|
1585
|
+
popover.appendChild(actions);
|
|
1586
|
+
|
|
1587
|
+
textarea.addEventListener('keydown', function (e) {
|
|
1588
|
+
if (e.key === 'Enter' && !e.shiftKey) {
|
|
1589
|
+
e.preventDefault();
|
|
1590
|
+
submitBtn.click();
|
|
1591
|
+
} else if (e.key === 'Escape') {
|
|
1592
|
+
dismissAnnotationPopover(panel);
|
|
1593
|
+
}
|
|
1594
|
+
});
|
|
1595
|
+
|
|
1596
|
+
panel.appendChild(popover);
|
|
1597
|
+
textarea.focus();
|
|
1598
|
+
textarea.setSelectionRange(textarea.value.length, textarea.value.length);
|
|
1599
|
+
}
|
|
1600
|
+
|
|
1456
1601
|
// Show the annotation popover near a text selection
|
|
1457
1602
|
function showAnnotationPopover(panel, selectedText, anchorRect, isCodeBlock, codeLang) {
|
|
1458
1603
|
// Remove any existing popover
|
|
@@ -4587,55 +4732,72 @@
|
|
|
4587
4732
|
// ── Push notification subscription ──
|
|
4588
4733
|
function registerPushNotifications() {
|
|
4589
4734
|
if (!('serviceWorker' in navigator) || !('PushManager' in window)) {
|
|
4590
|
-
console.log('[Cumulus] Push notifications not supported');
|
|
4735
|
+
console.log('[Cumulus] Push notifications not supported in this browser');
|
|
4591
4736
|
return;
|
|
4592
4737
|
}
|
|
4593
4738
|
|
|
4594
|
-
|
|
4595
|
-
.
|
|
4596
|
-
|
|
4597
|
-
|
|
4598
|
-
|
|
4599
|
-
// Check existing subscription
|
|
4600
|
-
return registration.pushManager.getSubscription().then(function (existing) {
|
|
4601
|
-
if (existing) {
|
|
4602
|
-
// Already subscribed — send to server in case it's new/different
|
|
4603
|
-
sendPushSubscription(existing);
|
|
4604
|
-
return;
|
|
4605
|
-
}
|
|
4739
|
+
if (!('Notification' in window)) {
|
|
4740
|
+
console.log('[Cumulus] Notification API not available');
|
|
4741
|
+
return;
|
|
4742
|
+
}
|
|
4606
4743
|
|
|
4607
|
-
|
|
4608
|
-
|
|
4609
|
-
|
|
4610
|
-
|
|
4611
|
-
|
|
4612
|
-
|
|
4613
|
-
|
|
4614
|
-
|
|
4615
|
-
|
|
4616
|
-
|
|
4744
|
+
// Must request permission explicitly (required for iOS PWA)
|
|
4745
|
+
Notification.requestPermission().then(function (permission) {
|
|
4746
|
+
console.log('[Cumulus] Notification permission:', permission);
|
|
4747
|
+
if (permission !== 'granted') {
|
|
4748
|
+
console.log('[Cumulus] Push notifications denied by user');
|
|
4749
|
+
return;
|
|
4750
|
+
}
|
|
4751
|
+
|
|
4752
|
+
navigator.serviceWorker
|
|
4753
|
+
.register('/sw.js', { scope: '/' })
|
|
4754
|
+
.then(function (registration) {
|
|
4755
|
+
console.log('[Cumulus] Service worker registered, scope:', registration.scope);
|
|
4756
|
+
|
|
4757
|
+
// Wait for the service worker to be ready
|
|
4758
|
+
return navigator.serviceWorker.ready.then(function (reg) {
|
|
4759
|
+
// Check existing subscription
|
|
4760
|
+
return reg.pushManager.getSubscription().then(function (existing) {
|
|
4761
|
+
if (existing) {
|
|
4762
|
+
console.log('[Cumulus] Existing push subscription found');
|
|
4763
|
+
sendPushSubscription(existing);
|
|
4617
4764
|
return;
|
|
4618
4765
|
}
|
|
4619
4766
|
|
|
4620
|
-
//
|
|
4621
|
-
|
|
4622
|
-
|
|
4623
|
-
|
|
4624
|
-
|
|
4767
|
+
// Get VAPID key from server
|
|
4768
|
+
var loc = window.location;
|
|
4769
|
+
var apiUrl = loc.protocol + '//' + loc.host;
|
|
4770
|
+
fetch(apiUrl + '/api/push/vapid-key')
|
|
4771
|
+
.then(function (r) {
|
|
4772
|
+
return r.json();
|
|
4625
4773
|
})
|
|
4626
|
-
.then(function (
|
|
4627
|
-
|
|
4628
|
-
|
|
4774
|
+
.then(function (data) {
|
|
4775
|
+
if (!data.publicKey) {
|
|
4776
|
+
console.log('[Cumulus] Push not configured on server (no VAPID key)');
|
|
4777
|
+
return;
|
|
4778
|
+
}
|
|
4779
|
+
|
|
4780
|
+
console.log('[Cumulus] Subscribing to push with VAPID key');
|
|
4781
|
+
return reg.pushManager
|
|
4782
|
+
.subscribe({
|
|
4783
|
+
userVisibleOnly: true,
|
|
4784
|
+
applicationServerKey: urlBase64ToUint8Array(data.publicKey),
|
|
4785
|
+
})
|
|
4786
|
+
.then(function (subscription) {
|
|
4787
|
+
console.log('[Cumulus] Push subscription created:', subscription.endpoint);
|
|
4788
|
+
sendPushSubscription(subscription);
|
|
4789
|
+
});
|
|
4790
|
+
})
|
|
4791
|
+
.catch(function (err) {
|
|
4792
|
+
console.warn('[Cumulus] Push subscription failed:', err.message || err);
|
|
4629
4793
|
});
|
|
4630
|
-
})
|
|
4631
|
-
.catch(function (err) {
|
|
4632
|
-
console.warn('[Cumulus] Push subscription failed:', err);
|
|
4633
4794
|
});
|
|
4795
|
+
});
|
|
4796
|
+
})
|
|
4797
|
+
.catch(function (err) {
|
|
4798
|
+
console.warn('[Cumulus] Service worker registration failed:', err.message || err);
|
|
4634
4799
|
});
|
|
4635
|
-
|
|
4636
|
-
.catch(function (err) {
|
|
4637
|
-
console.warn('[Cumulus] Service worker registration failed:', err);
|
|
4638
|
-
});
|
|
4800
|
+
});
|
|
4639
4801
|
}
|
|
4640
4802
|
|
|
4641
4803
|
function sendPushSubscription(subscription) {
|