@co0ontty/wand 1.17.2 → 1.17.4
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/web-ui/content/scripts.js +164 -16
- package/dist/web-ui/content/styles.css +27 -0
- package/package.json +1 -1
|
@@ -201,6 +201,7 @@
|
|
|
201
201
|
claudeHistoryLoaded: false,
|
|
202
202
|
claudeHistoryExpanded: true,
|
|
203
203
|
claudeHistoryExpandedDirs: {},
|
|
204
|
+
archivedExpanded: false,
|
|
204
205
|
sessionsManageMode: false,
|
|
205
206
|
selectedSessionIds: {},
|
|
206
207
|
selectedClaudeHistoryIds: {},
|
|
@@ -1733,7 +1734,7 @@
|
|
|
1733
1734
|
groups.push(renderRecentGroup(activeSessions, recentHistorySessions));
|
|
1734
1735
|
}
|
|
1735
1736
|
if (archivedSessions.length > 0) {
|
|
1736
|
-
groups.push(
|
|
1737
|
+
groups.push(renderArchivedGroup(archivedSessions));
|
|
1737
1738
|
}
|
|
1738
1739
|
groups.push(renderClaudeHistorySection());
|
|
1739
1740
|
if (activeSessions.length === 0 && archivedSessions.length === 0 && recentHistorySessions.length === 0) {
|
|
@@ -1754,12 +1755,17 @@
|
|
|
1754
1755
|
var historyCount = getSelectedClaudeHistoryIds().length;
|
|
1755
1756
|
var totalCount = sessionCount + historyCount;
|
|
1756
1757
|
var hasAny = totalCount > 0;
|
|
1758
|
+
var selectable = countSelectableItems();
|
|
1759
|
+
var allSelected = selectable > 0 && totalCount >= selectable;
|
|
1760
|
+
var selectAllLabel = allSelected ? "取消全选" : "全选";
|
|
1761
|
+
var selectAllAction = allSelected ? "clear-selection" : "select-all-visible";
|
|
1762
|
+
var selectAllDisabled = selectable === 0 ? ' disabled' : '';
|
|
1757
1763
|
|
|
1758
1764
|
return '<div class="session-manage-bar active">' +
|
|
1759
1765
|
'<div class="session-manage-summary">已选择 ' + totalCount + ' 项</div>' +
|
|
1760
1766
|
'<div class="session-manage-actions">' +
|
|
1761
|
-
'<button class="session-manage-btn" data-action="
|
|
1762
|
-
'<button class="session-manage-btn" data-action="clear-selection" type="button">清空</button>' +
|
|
1767
|
+
'<button class="session-manage-btn" data-action="' + selectAllAction + '" type="button"' + selectAllDisabled + '>' + selectAllLabel + '</button>' +
|
|
1768
|
+
'<button class="session-manage-btn" data-action="clear-selection" type="button"' + (hasAny ? '' : ' disabled') + '>清空</button>' +
|
|
1763
1769
|
'<button class="session-manage-btn danger" data-action="delete-selected" type="button"' + (hasAny ? '' : ' disabled') + '>删除所选</button>' +
|
|
1764
1770
|
'<button class="session-manage-btn" data-action="toggle-manage-mode" type="button">完成</button>' +
|
|
1765
1771
|
'</div>' +
|
|
@@ -1773,6 +1779,20 @@
|
|
|
1773
1779
|
'</section>';
|
|
1774
1780
|
}
|
|
1775
1781
|
|
|
1782
|
+
function renderArchivedGroup(archivedSessions) {
|
|
1783
|
+
var expanded = !!state.archivedExpanded;
|
|
1784
|
+
var chevron = expanded ? "▾" : "▸";
|
|
1785
|
+
var header = '<div class="session-group-title claude-history-toggle" data-action="toggle-archived-group">' +
|
|
1786
|
+
'<span class="chevron">' + chevron + '</span> 已归档 ' +
|
|
1787
|
+
'<span class="history-count">' + archivedSessions.length + '</span>' +
|
|
1788
|
+
'</div>';
|
|
1789
|
+
if (!expanded) {
|
|
1790
|
+
return '<section class="session-group">' + header + '</section>';
|
|
1791
|
+
}
|
|
1792
|
+
var items = archivedSessions.map(function(session) { return renderSessionItem(session, "sessions"); }).join("");
|
|
1793
|
+
return '<section class="session-group">' + header + items + '</section>';
|
|
1794
|
+
}
|
|
1795
|
+
|
|
1776
1796
|
function renderRecentGroup(activeSessions, recentHistorySessions) {
|
|
1777
1797
|
var html = '<section class="session-group">' +
|
|
1778
1798
|
'<div class="session-group-title">最近</div>';
|
|
@@ -1864,11 +1884,19 @@
|
|
|
1864
1884
|
updateSessionsList();
|
|
1865
1885
|
}
|
|
1866
1886
|
|
|
1887
|
+
function getSelectableSessions() {
|
|
1888
|
+
return state.sessions.filter(function(session) {
|
|
1889
|
+
return session.archived || !session.resumedToSessionId;
|
|
1890
|
+
});
|
|
1891
|
+
}
|
|
1892
|
+
|
|
1893
|
+
function countSelectableItems() {
|
|
1894
|
+
return getSelectableSessions().length + getVisibleClaudeHistorySessions().length;
|
|
1895
|
+
}
|
|
1896
|
+
|
|
1867
1897
|
function selectAllVisibleItems() {
|
|
1868
1898
|
var nextSessionIds = {};
|
|
1869
|
-
|
|
1870
|
-
return !session.resumedToSessionId;
|
|
1871
|
-
}).forEach(function(session) {
|
|
1899
|
+
getSelectableSessions().forEach(function(session) {
|
|
1872
1900
|
nextSessionIds[session.id] = true;
|
|
1873
1901
|
});
|
|
1874
1902
|
var nextHistoryIds = {};
|
|
@@ -2507,15 +2535,8 @@
|
|
|
2507
2535
|
// Ordered lists
|
|
2508
2536
|
escaped = escaped.replace(/^\d+\.\s+(.*)$/gm, '<li>$1</li>');
|
|
2509
2537
|
|
|
2510
|
-
// Tables
|
|
2511
|
-
escaped = escaped
|
|
2512
|
-
var cells = match.split("|").slice(1, -1);
|
|
2513
|
-
if (cells.every(function(c) { return /^[\-:]+$/.test(c.trim()); })) {
|
|
2514
|
-
return "";
|
|
2515
|
-
}
|
|
2516
|
-
return '<tr>' + cells.map(function(c) { return '<td>' + c.trim() + '</td>'; }).join("") + '</tr>';
|
|
2517
|
-
});
|
|
2518
|
-
escaped = escaped.replace(/(<tr>.*<\/tr>\n?)+/g, '<table>$&</table>');
|
|
2538
|
+
// Tables (GFM)
|
|
2539
|
+
escaped = parseMarkdownTables(escaped);
|
|
2519
2540
|
|
|
2520
2541
|
// Paragraphs
|
|
2521
2542
|
var paragraphs = escaped.split(/\n{2,}/);
|
|
@@ -3635,7 +3656,16 @@
|
|
|
3635
3656
|
if (scaleDownBtn) scaleDownBtn.addEventListener("click", function() { adjustTerminalScale(-0.25); });
|
|
3636
3657
|
if (scaleUpBtn) scaleUpBtn.addEventListener("click", function() { adjustTerminalScale(0.25); });
|
|
3637
3658
|
var pageRefreshBtn = document.getElementById("page-refresh-btn");
|
|
3638
|
-
if (pageRefreshBtn) pageRefreshBtn.addEventListener("click", function() {
|
|
3659
|
+
if (pageRefreshBtn) pageRefreshBtn.addEventListener("click", function(ev) {
|
|
3660
|
+
// Soft refresh: replay terminal buffer + rebuild chat view.
|
|
3661
|
+
// Fixes residual DOM from CSI cursor-jump sequences without losing page state.
|
|
3662
|
+
// Hold Shift to force a full page reload as an escape hatch.
|
|
3663
|
+
if (ev && ev.shiftKey) {
|
|
3664
|
+
location.reload();
|
|
3665
|
+
return;
|
|
3666
|
+
}
|
|
3667
|
+
softRefreshCurrentView();
|
|
3668
|
+
});
|
|
3639
3669
|
var jumpBottomBtn = document.getElementById("terminal-jump-bottom");
|
|
3640
3670
|
if (jumpBottomBtn) jumpBottomBtn.addEventListener("click", function() {
|
|
3641
3671
|
maybeScrollTerminalToBottom("force");
|
|
@@ -4125,6 +4155,9 @@
|
|
|
4125
4155
|
}
|
|
4126
4156
|
} else if (actionButton.dataset.action === "clear-all-history") {
|
|
4127
4157
|
clearAllClaudeHistory();
|
|
4158
|
+
} else if (actionButton.dataset.action === "toggle-archived-group") {
|
|
4159
|
+
state.archivedExpanded = !state.archivedExpanded;
|
|
4160
|
+
updateSessionsList();
|
|
4128
4161
|
} else if (actionButton.dataset.action === "resume" && actionButton.dataset.sessionId) {
|
|
4129
4162
|
handleResumeAction(actionButton);
|
|
4130
4163
|
} else if (actionButton.dataset.action === "resume-history" && actionButton.dataset.claudeSessionId) {
|
|
@@ -4493,6 +4526,38 @@
|
|
|
4493
4526
|
state.terminal.reset();
|
|
4494
4527
|
}
|
|
4495
4528
|
|
|
4529
|
+
// Soft resync terminal: reset WASM grid and replay full output buffer.
|
|
4530
|
+
// Clears any stale DOM rows left over from CSI cursor-jump sequences
|
|
4531
|
+
// (e.g. Claude permission menus redrawing in place while user holds arrow keys).
|
|
4532
|
+
function softResyncTerminal() {
|
|
4533
|
+
if (!state.terminal || !state.terminalOutput) return false;
|
|
4534
|
+
resetTerminal();
|
|
4535
|
+
state.terminal.write(state.terminalOutput);
|
|
4536
|
+
state.lastTerminalResyncAt = Date.now();
|
|
4537
|
+
maybeScrollTerminalToBottom("output");
|
|
4538
|
+
return true;
|
|
4539
|
+
}
|
|
4540
|
+
|
|
4541
|
+
// Soft refresh the whole current view without losing page state:
|
|
4542
|
+
// - Replays terminal buffer to clear residue
|
|
4543
|
+
// - Clears chat render cache and forces a full rebuild
|
|
4544
|
+
// Used by the refresh button and by automatic triggers
|
|
4545
|
+
// (e.g. permission escalation appearing/disappearing).
|
|
4546
|
+
function softRefreshCurrentView() {
|
|
4547
|
+
softResyncTerminal();
|
|
4548
|
+
if (typeof resetChatRenderCache === "function") resetChatRenderCache();
|
|
4549
|
+
if (typeof scheduleChatRender === "function") scheduleChatRender(true);
|
|
4550
|
+
else if (typeof render === "function") render();
|
|
4551
|
+
}
|
|
4552
|
+
|
|
4553
|
+
function scheduleSoftResyncTerminal(delayMs) {
|
|
4554
|
+
if (state.softResyncTimer) clearTimeout(state.softResyncTimer);
|
|
4555
|
+
state.softResyncTimer = setTimeout(function() {
|
|
4556
|
+
state.softResyncTimer = null;
|
|
4557
|
+
softResyncTerminal();
|
|
4558
|
+
}, typeof delayMs === "number" ? delayMs : 150);
|
|
4559
|
+
}
|
|
4560
|
+
|
|
4496
4561
|
function syncTerminalBuffer(sessionId, output, options) {
|
|
4497
4562
|
if (!state.terminal) return false;
|
|
4498
4563
|
var normalizedOutput = normalizeTerminalOutput(output || "");
|
|
@@ -5131,6 +5196,17 @@
|
|
|
5131
5196
|
if (normalizedSnapshot.id === state.selectedId) {
|
|
5132
5197
|
reconcileInteractiveState();
|
|
5133
5198
|
updateTaskDisplay();
|
|
5199
|
+
// Escalation/permission toggles are the common trigger for CSI cursor-jump
|
|
5200
|
+
// redraw sequences from Claude CLI. When they appear or dismiss, schedule a
|
|
5201
|
+
// debounced terminal resync so residual DOM rows get cleaned up automatically
|
|
5202
|
+
// — same fix the user used to have to reach for via the refresh button.
|
|
5203
|
+
var prevEsc = prevSession && prevSession.pendingEscalation ? 1 : 0;
|
|
5204
|
+
var nextEsc = updatedSession && updatedSession.pendingEscalation ? 1 : 0;
|
|
5205
|
+
var prevBlocked = prevSession && prevSession.permissionBlocked ? 1 : 0;
|
|
5206
|
+
var nextBlocked = updatedSession && updatedSession.permissionBlocked ? 1 : 0;
|
|
5207
|
+
if (prevEsc !== nextEsc || prevBlocked !== nextBlocked) {
|
|
5208
|
+
scheduleSoftResyncTerminal(200);
|
|
5209
|
+
}
|
|
5134
5210
|
}
|
|
5135
5211
|
// When a session transitions to a non-running state, try flushing cross-session queue
|
|
5136
5212
|
if (normalizedSnapshot.status && normalizedSnapshot.status !== "running" && state.crossSessionQueue.length > 0) {
|
|
@@ -6274,6 +6350,9 @@
|
|
|
6274
6350
|
defaultModel: (document.getElementById("cfg-default-model") || {}).value || "",
|
|
6275
6351
|
};
|
|
6276
6352
|
|
|
6353
|
+
var previousDefaultModel = (state.config && state.config.defaultModel) || "";
|
|
6354
|
+
var nextDefaultModel = body.defaultModel || "";
|
|
6355
|
+
|
|
6277
6356
|
fetch("/api/settings/config", {
|
|
6278
6357
|
method: "POST",
|
|
6279
6358
|
headers: { "Content-Type": "application/json" },
|
|
@@ -6292,6 +6371,15 @@
|
|
|
6292
6371
|
}
|
|
6293
6372
|
msgEl.classList.remove("hidden");
|
|
6294
6373
|
}
|
|
6374
|
+
if (!data || !data.error) {
|
|
6375
|
+
if (state.config) state.config.defaultModel = nextDefaultModel;
|
|
6376
|
+
state.configDefaultModel = nextDefaultModel;
|
|
6377
|
+
if (nextDefaultModel !== previousDefaultModel) {
|
|
6378
|
+
state.chatModel = "";
|
|
6379
|
+
try { localStorage.removeItem("wand-chat-model"); } catch (e) {}
|
|
6380
|
+
syncComposerModelSelect(getSelectedSession());
|
|
6381
|
+
}
|
|
6382
|
+
}
|
|
6295
6383
|
})
|
|
6296
6384
|
.catch(function() {
|
|
6297
6385
|
if (msgEl) {
|
|
@@ -13113,6 +13201,65 @@
|
|
|
13113
13201
|
return deduped.join(newline);
|
|
13114
13202
|
}
|
|
13115
13203
|
|
|
13204
|
+
function parseMarkdownTables(source) {
|
|
13205
|
+
var NL = "\n";
|
|
13206
|
+
var lines = source.split(NL);
|
|
13207
|
+
var out = [];
|
|
13208
|
+
var i = 0;
|
|
13209
|
+
|
|
13210
|
+
function splitRow(line) {
|
|
13211
|
+
var s = line.trim();
|
|
13212
|
+
if (s.charAt(0) === "|") s = s.slice(1);
|
|
13213
|
+
if (s.charAt(s.length - 1) === "|") s = s.slice(0, -1);
|
|
13214
|
+
return s.split("|");
|
|
13215
|
+
}
|
|
13216
|
+
function styleAttr(a) { return a ? ' style="text-align:' + a + '"' : ""; }
|
|
13217
|
+
function buildTable(headers, aligns, rows) {
|
|
13218
|
+
var thead = "<thead><tr>" + headers.map(function(c, idx) {
|
|
13219
|
+
return "<th" + styleAttr(aligns[idx]) + ">" + c.trim() + "</th>";
|
|
13220
|
+
}).join("") + "</tr></thead>";
|
|
13221
|
+
var tbody = rows.length ? ("<tbody>" + rows.map(function(r) {
|
|
13222
|
+
return "<tr>" + r.map(function(c, idx) {
|
|
13223
|
+
return "<td" + styleAttr(aligns[idx]) + ">" + c.trim() + "</td>";
|
|
13224
|
+
}).join("") + "</tr>";
|
|
13225
|
+
}).join("") + "</tbody>") : "";
|
|
13226
|
+
return '<div class="md-table-wrap"><table class="md-table">' + thead + tbody + "</table></div>";
|
|
13227
|
+
}
|
|
13228
|
+
|
|
13229
|
+
while (i < lines.length) {
|
|
13230
|
+
var header = lines[i];
|
|
13231
|
+
if (header.indexOf("|") !== -1 && i + 1 < lines.length) {
|
|
13232
|
+
var sep = lines[i + 1].trim();
|
|
13233
|
+
if (/^\|?\s*:?-+:?(\s*\|\s*:?-+:?)+\s*\|?$/.test(sep)) {
|
|
13234
|
+
var headers = splitRow(header);
|
|
13235
|
+
var aligns = splitRow(sep).map(function(c) {
|
|
13236
|
+
var t = c.trim();
|
|
13237
|
+
var L = t.charAt(0) === ":";
|
|
13238
|
+
var R = t.charAt(t.length - 1) === ":";
|
|
13239
|
+
if (L && R) return "center";
|
|
13240
|
+
if (R) return "right";
|
|
13241
|
+
if (L) return "left";
|
|
13242
|
+
return "";
|
|
13243
|
+
});
|
|
13244
|
+
var rows = [];
|
|
13245
|
+
var j = i + 2;
|
|
13246
|
+
while (j < lines.length) {
|
|
13247
|
+
var trimmed = lines[j].trim();
|
|
13248
|
+
if (!trimmed || trimmed.indexOf("|") === -1) break;
|
|
13249
|
+
rows.push(splitRow(lines[j]));
|
|
13250
|
+
j += 1;
|
|
13251
|
+
}
|
|
13252
|
+
out.push("", buildTable(headers, aligns, rows), "");
|
|
13253
|
+
i = j;
|
|
13254
|
+
continue;
|
|
13255
|
+
}
|
|
13256
|
+
}
|
|
13257
|
+
out.push(header);
|
|
13258
|
+
i += 1;
|
|
13259
|
+
}
|
|
13260
|
+
return out.join(NL);
|
|
13261
|
+
}
|
|
13262
|
+
|
|
13116
13263
|
function renderMarkdown(text) {
|
|
13117
13264
|
if (!text) return "";
|
|
13118
13265
|
|
|
@@ -13237,6 +13384,7 @@
|
|
|
13237
13384
|
result = replaceLinePrefix(result, "- ", '<li>', '</li>');
|
|
13238
13385
|
result = replaceLinePrefix(result, "* ", '<li>', '</li>');
|
|
13239
13386
|
result = replaceOrderedList(result);
|
|
13387
|
+
result = parseMarkdownTables(result);
|
|
13240
13388
|
|
|
13241
13389
|
var lines = result.split(newline);
|
|
13242
13390
|
var grouped = [];
|
|
@@ -4463,6 +4463,33 @@
|
|
|
4463
4463
|
padding: 2px 5px;
|
|
4464
4464
|
border-radius: 4px;
|
|
4465
4465
|
}
|
|
4466
|
+
.markdown-content .md-table-wrap {
|
|
4467
|
+
margin: 12px 0;
|
|
4468
|
+
overflow-x: auto;
|
|
4469
|
+
border: 1px solid var(--border);
|
|
4470
|
+
border-radius: var(--radius-sm);
|
|
4471
|
+
-webkit-overflow-scrolling: touch;
|
|
4472
|
+
}
|
|
4473
|
+
.markdown-content .md-table {
|
|
4474
|
+
border-collapse: collapse;
|
|
4475
|
+
width: 100%;
|
|
4476
|
+
font-size: 0.8125rem;
|
|
4477
|
+
white-space: normal;
|
|
4478
|
+
}
|
|
4479
|
+
.markdown-content .md-table th,
|
|
4480
|
+
.markdown-content .md-table td {
|
|
4481
|
+
border: 1px solid var(--border);
|
|
4482
|
+
padding: 6px 10px;
|
|
4483
|
+
text-align: left;
|
|
4484
|
+
vertical-align: top;
|
|
4485
|
+
}
|
|
4486
|
+
.markdown-content .md-table th {
|
|
4487
|
+
background: rgba(150, 118, 85, 0.1);
|
|
4488
|
+
font-weight: 600;
|
|
4489
|
+
}
|
|
4490
|
+
.markdown-content .md-table tbody tr:nth-child(even) {
|
|
4491
|
+
background: rgba(150, 118, 85, 0.04);
|
|
4492
|
+
}
|
|
4466
4493
|
.markdown-content .code-block {
|
|
4467
4494
|
margin: 12px 0;
|
|
4468
4495
|
border-radius: var(--radius-md);
|