@luckydraw/cumulus 0.27.21 → 0.27.23
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.
|
@@ -198,6 +198,17 @@
|
|
|
198
198
|
'.cumulus-msg em { font-style: italic; }',
|
|
199
199
|
'.cumulus-msg del { text-decoration: line-through; color: #888; }',
|
|
200
200
|
|
|
201
|
+
/* Blex block containers */
|
|
202
|
+
'.blex-block-container {',
|
|
203
|
+
' margin: 0.6em 0;',
|
|
204
|
+
' border-radius: 8px;',
|
|
205
|
+
' overflow: hidden;',
|
|
206
|
+
' min-height: 2em;',
|
|
207
|
+
'}',
|
|
208
|
+
'.blex-block-container[data-blex-ready="true"] {',
|
|
209
|
+
' min-height: auto;',
|
|
210
|
+
'}',
|
|
211
|
+
|
|
201
212
|
/* Headings */
|
|
202
213
|
'.cumulus-msg h1,.cumulus-msg h2,.cumulus-msg h3,.cumulus-msg h4,.cumulus-msg h5,.cumulus-msg h6 {',
|
|
203
214
|
' font-weight: 600; margin: 0.7em 0 0.3em; line-height: 1.3; color: #e8e8e8;',
|
|
@@ -1101,14 +1112,116 @@
|
|
|
1101
1112
|
el.appendChild(header);
|
|
1102
1113
|
|
|
1103
1114
|
var body = document.createElement('div');
|
|
1104
|
-
|
|
1115
|
+
var mdResult = renderMarkdown(agent.body);
|
|
1116
|
+
body.innerHTML = mdResult.html;
|
|
1117
|
+
renderBlexBlocks(body, mdResult.blexBlocks, null);
|
|
1105
1118
|
el.appendChild(body);
|
|
1106
1119
|
return el;
|
|
1107
1120
|
}
|
|
1108
1121
|
|
|
1109
1122
|
// ── Markdown ──────────────────────────────────────────────────────────────
|
|
1110
1123
|
|
|
1124
|
+
// ─── Blex block handle tracking ─────────────────────────────────────────────
|
|
1125
|
+
// Map: msgEl → Array<BlockHandle> — for cleanup on message delete/revert
|
|
1126
|
+
var blexHandles = new WeakMap();
|
|
1127
|
+
|
|
1128
|
+
/**
|
|
1129
|
+
* Parse blex fenced blocks from markdown text.
|
|
1130
|
+
* Returns { text: processedText, blocks: [{type, json, id}] }
|
|
1131
|
+
* Fences: ~~~blex:TYPE\n{json}\n~~~ or ```blex:TYPE\n{json}\n```
|
|
1132
|
+
*/
|
|
1133
|
+
function extractBlexBlocks(text) {
|
|
1134
|
+
var blocks = [];
|
|
1135
|
+
var BLEX_PREFIX = '\x00BLEX_';
|
|
1136
|
+
var processed = text.replace(
|
|
1137
|
+
/(?:~~~|```)blex:(\w[\w-]*)\n([\s\S]*?)(?:~~~|```)/g,
|
|
1138
|
+
function (_, type, json) {
|
|
1139
|
+
var idx = blocks.length;
|
|
1140
|
+
var id = 'blex-' + idx + '-' + Date.now();
|
|
1141
|
+
blocks.push({ type: type, json: json.trim(), id: id });
|
|
1142
|
+
return BLEX_PREFIX + idx + '\x00';
|
|
1143
|
+
}
|
|
1144
|
+
);
|
|
1145
|
+
return { text: processed, blocks: blocks };
|
|
1146
|
+
}
|
|
1147
|
+
|
|
1148
|
+
/**
|
|
1149
|
+
* After innerHTML is set, find blex placeholder divs and render blocks.
|
|
1150
|
+
* Returns array of BlockHandles for lifecycle management.
|
|
1151
|
+
*/
|
|
1152
|
+
function renderBlexBlocks(container, blocks, inputEl) {
|
|
1153
|
+
if (!blocks || !blocks.length || typeof window.Blex === 'undefined') return;
|
|
1154
|
+
var handles = [];
|
|
1155
|
+
var placeholders = container.querySelectorAll('[data-blex-idx]');
|
|
1156
|
+
placeholders.forEach(function (ph) {
|
|
1157
|
+
var idx = parseInt(ph.getAttribute('data-blex-idx'), 10);
|
|
1158
|
+
var block = blocks[idx];
|
|
1159
|
+
if (!block) return;
|
|
1160
|
+
|
|
1161
|
+
// Try to parse JSON
|
|
1162
|
+
var data;
|
|
1163
|
+
try {
|
|
1164
|
+
data = JSON.parse(block.json);
|
|
1165
|
+
} catch (e) {
|
|
1166
|
+
// Show parse error in a fallback
|
|
1167
|
+
ph.innerHTML =
|
|
1168
|
+
'<pre style="color:#f44;font-size:0.85em;">blex:' +
|
|
1169
|
+
escapeHtml(block.type) +
|
|
1170
|
+
' — invalid JSON: ' +
|
|
1171
|
+
escapeHtml(e.message) +
|
|
1172
|
+
'</pre>';
|
|
1173
|
+
return;
|
|
1174
|
+
}
|
|
1175
|
+
|
|
1176
|
+
var contentBlock = { type: block.type, id: block.id, data: data };
|
|
1177
|
+
|
|
1178
|
+
// Render the block
|
|
1179
|
+
window.Blex.renderBlock(contentBlock, ph)
|
|
1180
|
+
.then(function (handle) {
|
|
1181
|
+
handles.push(handle);
|
|
1182
|
+
// Wire interaction → inject into input
|
|
1183
|
+
if (handle && handle.onInteraction && inputEl) {
|
|
1184
|
+
handle.onInteraction(function (interaction) {
|
|
1185
|
+
if (interaction && interaction.serialized) {
|
|
1186
|
+
inputEl.value =
|
|
1187
|
+
(inputEl.value ? inputEl.value + '\n' : '') + interaction.serialized;
|
|
1188
|
+
inputEl.focus();
|
|
1189
|
+
// Trigger input event so send button updates
|
|
1190
|
+
inputEl.dispatchEvent(new Event('input', { bubbles: true }));
|
|
1191
|
+
}
|
|
1192
|
+
});
|
|
1193
|
+
}
|
|
1194
|
+
})
|
|
1195
|
+
.catch(function (err) {
|
|
1196
|
+
ph.innerHTML =
|
|
1197
|
+
'<pre style="color:#f44;font-size:0.85em;">blex:' +
|
|
1198
|
+
escapeHtml(block.type) +
|
|
1199
|
+
' render error: ' +
|
|
1200
|
+
escapeHtml(err.message) +
|
|
1201
|
+
'</pre>';
|
|
1202
|
+
});
|
|
1203
|
+
});
|
|
1204
|
+
blexHandles.set(container, handles);
|
|
1205
|
+
}
|
|
1206
|
+
|
|
1207
|
+
/**
|
|
1208
|
+
* Destroy all blex block handles for a message element.
|
|
1209
|
+
*/
|
|
1210
|
+
function destroyBlexBlocks(container) {
|
|
1211
|
+
var handles = blexHandles.get(container);
|
|
1212
|
+
if (handles) {
|
|
1213
|
+
handles.forEach(function (h) {
|
|
1214
|
+
if (h && h.destroy) h.destroy();
|
|
1215
|
+
});
|
|
1216
|
+
blexHandles.delete(container);
|
|
1217
|
+
}
|
|
1218
|
+
}
|
|
1219
|
+
|
|
1111
1220
|
function renderMarkdown(text) {
|
|
1221
|
+
// Phase 0.5: Extract blex fenced blocks — replace with unique tokens
|
|
1222
|
+
var blexResult = extractBlexBlocks(text);
|
|
1223
|
+
text = blexResult.text;
|
|
1224
|
+
|
|
1112
1225
|
// Phase 1: Extract fenced code blocks — replace with unique tokens
|
|
1113
1226
|
var codeBlocks = [];
|
|
1114
1227
|
var TOKEN_PREFIX = '\x00CODEBLOCK_';
|
|
@@ -1181,7 +1294,20 @@
|
|
|
1181
1294
|
return codeBlocks[parseInt(idx, 10)];
|
|
1182
1295
|
});
|
|
1183
1296
|
|
|
1184
|
-
|
|
1297
|
+
// Phase 7.5: Reinsert blex block placeholders
|
|
1298
|
+
if (blexResult.blocks.length > 0) {
|
|
1299
|
+
html = html.replace(/\x00BLEX_(\d+)\x00/g, function (_, idx) {
|
|
1300
|
+
return (
|
|
1301
|
+
'<div class="blex-block-container" data-blex-idx="' +
|
|
1302
|
+
idx +
|
|
1303
|
+
'" data-testid="blex-block-' +
|
|
1304
|
+
idx +
|
|
1305
|
+
'"></div>'
|
|
1306
|
+
);
|
|
1307
|
+
});
|
|
1308
|
+
}
|
|
1309
|
+
|
|
1310
|
+
return { html: html, blexBlocks: blexResult.blocks };
|
|
1185
1311
|
}
|
|
1186
1312
|
|
|
1187
1313
|
function buildCodeBlock(lang, escapedCode, tokenId) {
|
|
@@ -1688,10 +1814,29 @@
|
|
|
1688
1814
|
el.className = 'cumulus-msg assistant';
|
|
1689
1815
|
if (isStreaming) el.setAttribute('data-testid', 'webchat-streaming');
|
|
1690
1816
|
if (content) {
|
|
1691
|
-
|
|
1817
|
+
var mdResult = renderMarkdown(content);
|
|
1818
|
+
el.innerHTML = mdResult.html;
|
|
1692
1819
|
if (isStreaming) {
|
|
1693
1820
|
el.innerHTML += '<span class="cumulus-cursor"></span>';
|
|
1694
1821
|
}
|
|
1822
|
+
// Render blex blocks
|
|
1823
|
+
if (mdResult.blexBlocks.length > 0) {
|
|
1824
|
+
if (isStreaming && typeof window.Blex !== 'undefined') {
|
|
1825
|
+
// During streaming: show placeholders
|
|
1826
|
+
el.querySelectorAll('[data-blex-idx]').forEach(function (ph) {
|
|
1827
|
+
var idx = parseInt(ph.getAttribute('data-blex-idx'), 10);
|
|
1828
|
+
var block = mdResult.blexBlocks[idx];
|
|
1829
|
+
if (block) window.Blex.renderPlaceholder(block.type, ph);
|
|
1830
|
+
});
|
|
1831
|
+
} else if (!isStreaming) {
|
|
1832
|
+
// Final render: full blex blocks with interaction wiring
|
|
1833
|
+
var inputEl = el.closest('.cumulus-panel, .cumulus-widget');
|
|
1834
|
+
var blexInputEl = inputEl
|
|
1835
|
+
? inputEl.querySelector('.cumulus-input, .cumulus-standalone-input')
|
|
1836
|
+
: null;
|
|
1837
|
+
renderBlexBlocks(el, mdResult.blexBlocks, blexInputEl);
|
|
1838
|
+
}
|
|
1839
|
+
}
|
|
1695
1840
|
el.querySelectorAll('.code-block-copy-btn').forEach(function (btn) {
|
|
1696
1841
|
btn.addEventListener('click', function () {
|
|
1697
1842
|
var targetId = btn.getAttribute('data-copy-target');
|
|
@@ -1714,6 +1859,10 @@
|
|
|
1714
1859
|
}
|
|
1715
1860
|
|
|
1716
1861
|
function renderMessages() {
|
|
1862
|
+
// Destroy existing blex block handles before clearing DOM
|
|
1863
|
+
messagesEl.querySelectorAll('.cumulus-msg.assistant').forEach(function (m) {
|
|
1864
|
+
destroyBlexBlocks(m);
|
|
1865
|
+
});
|
|
1717
1866
|
messagesEl.innerHTML = '';
|
|
1718
1867
|
// Apply selection mode class
|
|
1719
1868
|
if (selectionMode) {
|
|
@@ -1974,7 +2123,10 @@
|
|
|
1974
2123
|
}
|
|
1975
2124
|
streaming = false;
|
|
1976
2125
|
stopRequested = false;
|
|
1977
|
-
if (embeddedStreamTimer) {
|
|
2126
|
+
if (embeddedStreamTimer) {
|
|
2127
|
+
clearTimeout(embeddedStreamTimer);
|
|
2128
|
+
embeddedStreamTimer = null;
|
|
2129
|
+
}
|
|
1978
2130
|
updateSendBtn();
|
|
1979
2131
|
}
|
|
1980
2132
|
showChatView();
|
|
@@ -2004,14 +2156,18 @@
|
|
|
2004
2156
|
if (streaming) {
|
|
2005
2157
|
console.warn('[Cumulus] Streaming timeout — resetting');
|
|
2006
2158
|
if (streamBuffer) {
|
|
2007
|
-
messages.push({
|
|
2159
|
+
messages.push({
|
|
2160
|
+
role: 'assistant',
|
|
2161
|
+
content: streamBuffer + '\n\n*(response may be incomplete)*',
|
|
2162
|
+
});
|
|
2008
2163
|
}
|
|
2009
2164
|
streaming = false;
|
|
2010
2165
|
streamBuffer = '';
|
|
2011
2166
|
updateSendBtn();
|
|
2012
2167
|
renderMessages();
|
|
2013
2168
|
// Reload history
|
|
2014
|
-
if (connection)
|
|
2169
|
+
if (connection)
|
|
2170
|
+
connection.send({ type: 'history', threadName: sessionId, limit: 50 });
|
|
2015
2171
|
}
|
|
2016
2172
|
embeddedStreamTimer = null;
|
|
2017
2173
|
}, EMBEDDED_STREAM_TIMEOUT);
|
|
@@ -2020,7 +2176,10 @@
|
|
|
2020
2176
|
case 'segment':
|
|
2021
2177
|
break;
|
|
2022
2178
|
case 'done':
|
|
2023
|
-
if (embeddedStreamTimer) {
|
|
2179
|
+
if (embeddedStreamTimer) {
|
|
2180
|
+
clearTimeout(embeddedStreamTimer);
|
|
2181
|
+
embeddedStreamTimer = null;
|
|
2182
|
+
}
|
|
2024
2183
|
if (stopRequested) {
|
|
2025
2184
|
stopRequested = false;
|
|
2026
2185
|
streaming = false;
|
|
@@ -2040,10 +2199,16 @@
|
|
|
2040
2199
|
break;
|
|
2041
2200
|
case 'interjected':
|
|
2042
2201
|
// Server confirms old stream was aborted. Partial already frozen client-side.
|
|
2043
|
-
if (embeddedStreamTimer) {
|
|
2202
|
+
if (embeddedStreamTimer) {
|
|
2203
|
+
clearTimeout(embeddedStreamTimer);
|
|
2204
|
+
embeddedStreamTimer = null;
|
|
2205
|
+
}
|
|
2044
2206
|
break;
|
|
2045
2207
|
case 'error':
|
|
2046
|
-
if (embeddedStreamTimer) {
|
|
2208
|
+
if (embeddedStreamTimer) {
|
|
2209
|
+
clearTimeout(embeddedStreamTimer);
|
|
2210
|
+
embeddedStreamTimer = null;
|
|
2211
|
+
}
|
|
2047
2212
|
stopRequested = false;
|
|
2048
2213
|
streaming = false;
|
|
2049
2214
|
if (streamBuffer) {
|
|
@@ -2265,7 +2430,10 @@
|
|
|
2265
2430
|
if (s && s.streaming) {
|
|
2266
2431
|
console.warn('[CumulusChat] Streaming timeout for thread:', threadName);
|
|
2267
2432
|
if (s.streamBuffer) {
|
|
2268
|
-
s.messages.push({
|
|
2433
|
+
s.messages.push({
|
|
2434
|
+
role: 'assistant',
|
|
2435
|
+
content: s.streamBuffer + '\n\n*(response may be incomplete — connection issue)*',
|
|
2436
|
+
});
|
|
2269
2437
|
}
|
|
2270
2438
|
s.streaming = false;
|
|
2271
2439
|
s.streamBuffer = '';
|
|
@@ -3002,10 +3170,29 @@
|
|
|
3002
3170
|
el.className = 'cumulus-msg assistant';
|
|
3003
3171
|
if (isStreaming) el.setAttribute('data-testid', 'webchat-streaming');
|
|
3004
3172
|
if (content) {
|
|
3005
|
-
|
|
3173
|
+
var mdResult = renderMarkdown(content);
|
|
3174
|
+
el.innerHTML = mdResult.html;
|
|
3006
3175
|
if (isStreaming) {
|
|
3007
3176
|
el.innerHTML += '<span class="cumulus-cursor"></span>';
|
|
3008
3177
|
}
|
|
3178
|
+
// Render blex blocks
|
|
3179
|
+
if (mdResult.blexBlocks.length > 0) {
|
|
3180
|
+
if (isStreaming && typeof window.Blex !== 'undefined') {
|
|
3181
|
+
// During streaming: show placeholders
|
|
3182
|
+
el.querySelectorAll('[data-blex-idx]').forEach(function (ph) {
|
|
3183
|
+
var idx = parseInt(ph.getAttribute('data-blex-idx'), 10);
|
|
3184
|
+
var block = mdResult.blexBlocks[idx];
|
|
3185
|
+
if (block) window.Blex.renderPlaceholder(block.type, ph);
|
|
3186
|
+
});
|
|
3187
|
+
} else if (!isStreaming) {
|
|
3188
|
+
// Final render: full blex blocks with interaction wiring
|
|
3189
|
+
var inputEl = el.closest('.cumulus-panel, .cumulus-widget');
|
|
3190
|
+
var blexInputEl = inputEl
|
|
3191
|
+
? inputEl.querySelector('.cumulus-input, .cumulus-standalone-input')
|
|
3192
|
+
: null;
|
|
3193
|
+
renderBlexBlocks(el, mdResult.blexBlocks, blexInputEl);
|
|
3194
|
+
}
|
|
3195
|
+
}
|
|
3009
3196
|
el.querySelectorAll('.code-block-copy-btn').forEach(function (btn) {
|
|
3010
3197
|
btn.addEventListener('click', function () {
|
|
3011
3198
|
var targetId = btn.getAttribute('data-copy-target');
|
|
@@ -3028,6 +3215,10 @@
|
|
|
3028
3215
|
}
|
|
3029
3216
|
|
|
3030
3217
|
function renderPanelMessages() {
|
|
3218
|
+
// Destroy existing blex block handles before clearing DOM
|
|
3219
|
+
messagesEl.querySelectorAll('.cumulus-msg.assistant').forEach(function (m) {
|
|
3220
|
+
destroyBlexBlocks(m);
|
|
3221
|
+
});
|
|
3031
3222
|
messagesEl.innerHTML = '';
|
|
3032
3223
|
// Apply selection mode class to messages container
|
|
3033
3224
|
if (state.selectionMode) {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@luckydraw/cumulus",
|
|
3
|
-
"version": "0.27.
|
|
3
|
+
"version": "0.27.23",
|
|
4
4
|
"description": "RLM-based CLI chat wrapper for Claude with external history context management",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "dist/index.js",
|
|
@@ -32,7 +32,7 @@
|
|
|
32
32
|
"cumulus-gateway": "./dist/gateway/daemon.js"
|
|
33
33
|
},
|
|
34
34
|
"scripts": {
|
|
35
|
-
"build": "tsc && rm -rf dist/gateway/static && cp -r src/gateway/static dist/gateway/static",
|
|
35
|
+
"build": "tsc && rm -rf dist/gateway/static && cp -r src/gateway/static dist/gateway/static && cp node_modules/@luckydraw/blex/dist/blex.min.global.js dist/gateway/static/blex.min.js && cp node_modules/@luckydraw/blex/dist/blex-chart.min.global.js dist/gateway/static/blex-chart.min.js",
|
|
36
36
|
"dev": "tsc --watch",
|
|
37
37
|
"lint": "eslint src",
|
|
38
38
|
"lint:fix": "eslint src --fix",
|
|
@@ -89,6 +89,7 @@
|
|
|
89
89
|
},
|
|
90
90
|
"dependencies": {
|
|
91
91
|
"@huggingface/transformers": "^3.8.1",
|
|
92
|
+
"@luckydraw/blex": "^0.1.0",
|
|
92
93
|
"@modelcontextprotocol/sdk": "^1.25.3",
|
|
93
94
|
"@slack/bolt": "^4.6.0",
|
|
94
95
|
"commander": "^14.0.2",
|