wezard 2.0.4 → 2.0.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/daemon/cc-session.js +2 -0
- package/dist/daemon/cc-session.js.map +1 -1
- package/dist/daemon/inbound.js +25 -34
- package/dist/daemon/inbound.js.map +1 -1
- package/dist/daemon/index.js +2 -2
- package/dist/daemon/index.js.map +1 -1
- package/dist/daemon/mirror-bridge.js +66 -24
- package/dist/daemon/mirror-bridge.js.map +1 -1
- package/dist/daemon/peers.js +11 -0
- package/dist/daemon/peers.js.map +1 -1
- package/dist/shared/detail-render.js +84 -38
- package/dist/shared/detail-render.js.map +1 -1
- package/dist/shared/role-view.js +9 -4
- package/dist/shared/role-view.js.map +1 -1
- package/package.json +1 -1
- package/web/chat.css +36 -60
- package/web/chat.js +21 -26
package/web/chat.css
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
/* Rolepage 外壳。消息正文 (
|
|
1
|
+
/* Rolepage 外壳。消息正文 (气泡 / 过程框) 的样式来自 detail-render 的 SHARED_CSS/TURN_CSS,
|
|
2
2
|
由 /chat/app.css 拼在本文件之前 —— 这里管骨架、会话列表、左右气泡与页脚总账。
|
|
3
3
|
视觉只押一处: 「视角」。我说的靠右、染成视角色; 别人说的靠左、带头像; 气泡对面
|
|
4
4
|
那片空白是一道门 —— 点下去就换成对方的视角。其余一律安静。 */
|
|
@@ -211,13 +211,17 @@ span.av.go:hover { background: #2f55c924; box-shadow: 0 0 0 3px #2f55c924 }
|
|
|
211
211
|
.si .pv:empty { display: none }
|
|
212
212
|
|
|
213
213
|
/* 执行中的 wizard: 头像角上一盏呼吸灯 (同关系图的 .wav .live)。 */
|
|
214
|
-
.ci > .av
|
|
215
|
-
.ci > .av .live
|
|
214
|
+
.ci > .av { position: relative }
|
|
215
|
+
.ci > .av .live {
|
|
216
216
|
position: absolute; right: 1px; bottom: -3px; width: 9px; height: 9px;
|
|
217
217
|
border-radius: 50%; background: #1a7f37; border: 2px solid #fff;
|
|
218
218
|
animation: pulse 1.4s infinite;
|
|
219
219
|
}
|
|
220
|
-
|
|
220
|
+
/* 子项的头像太小, 角上挂不住一盏看得清的灯 —— 挪到名字右边, 与回复头上的 .tg-dot 同大。 */
|
|
221
|
+
.si .l1 .live {
|
|
222
|
+
flex: none; align-self: center; width: 7px; height: 7px;
|
|
223
|
+
border-radius: 50%; background: #1a7f37; animation: pulse 1.4s infinite;
|
|
224
|
+
}
|
|
221
225
|
|
|
222
226
|
/* ── 右栏头: 这个群聊 / 私聊是什么 ───────────────────────────────── */
|
|
223
227
|
.main { flex: 1; min-width: 0; min-height: 0; display: flex; flex-direction: column; background: var(--card) }
|
|
@@ -227,13 +231,8 @@ span.av.go:hover { background: #2f55c924; box-shadow: 0 0 0 3px #2f55c924 }
|
|
|
227
231
|
}
|
|
228
232
|
.chathead .back { display: none; border: 0; background: none; font-size: 22px; color: var(--mute); cursor: pointer; padding: 0 4px }
|
|
229
233
|
.ch-who { display: flex; gap: 11px; align-items: center; min-width: 0; flex: 1 }
|
|
230
|
-
.ch-who > .av:not(.mosaic) { font-size: 26px; line-height: 1; flex: none }
|
|
231
|
-
.ch-who .l { min-width: 0; display: flex; flex-direction: column; gap: 1px }
|
|
232
234
|
.ch-who .t { font-size: 16px; font-weight: 600; overflow: hidden; text-overflow: ellipsis; white-space: nowrap }
|
|
233
|
-
.ch-who > .t { flex: none }
|
|
234
|
-
.ch-who .tr { display: flex; align-items: center; gap: 6px; min-width: 0 }
|
|
235
|
-
.ch-who .jump { flex: none; display: inline-flex; padding: 3px; border-radius: 5px; color: var(--mute) }
|
|
236
|
-
.ch-who .jump:hover { color: var(--accent); background: var(--line) }
|
|
235
|
+
.ch-who > .t:not(:only-child) { flex: none }
|
|
237
236
|
.ch-who .sub { font-size: 11.5px; color: var(--mute); overflow: hidden; text-overflow: ellipsis; white-space: nowrap }
|
|
238
237
|
.ch-acts { display: flex; gap: 8px; align-items: center; flex: none; font-size: 12px; color: var(--mute) }
|
|
239
238
|
.vb {
|
|
@@ -276,10 +275,11 @@ span.av.go:hover { background: #2f55c924; box-shadow: 0 0 0 3px #2f55c924 }
|
|
|
276
275
|
/* 卡片里那份时刻是详情页要的, 这里已经写在 .mwho 上了 —— 同一条消息不报两次时间。 */
|
|
277
276
|
.mb .tg-time { display: none }
|
|
278
277
|
|
|
279
|
-
/* 入消息 (问句) 是一颗气泡; 出消息 (回复)
|
|
280
|
-
|
|
278
|
+
/* 入消息 (问句) 是一颗气泡; 出消息 (回复) 是一串气泡, 中间夹着虚线的过程框 ——
|
|
279
|
+
没有外层卡片, 直接排在对话底上。 */
|
|
280
|
+
.mb > .bubble.mq { border-radius: 14px }
|
|
281
|
+
.mb :is(.bubble.mq, .say > .bubble) { border-color: var(--line) }
|
|
281
282
|
.mb .mq .mmeta { display: flex; gap: 6px; flex-wrap: wrap; align-items: center; padding: 8px 14px 0; font-size: 11px; color: var(--faint) }
|
|
282
|
-
.mb .mq .md-body { padding: 10px 14px }
|
|
283
283
|
.mb .mq .mmeta + .md-body { padding-top: 4px }
|
|
284
284
|
.mchip { border-radius: 4px; padding: 0 5px; background: #f1f3f6; color: var(--mute) }
|
|
285
285
|
.mchip.priv { color: var(--priv); background: #9a5b1014 }
|
|
@@ -287,24 +287,14 @@ span.av.go:hover { background: #2f55c924; box-shadow: 0 0 0 3px #2f55c924 }
|
|
|
287
287
|
.mchip.graph { color: #6639ba; background: #8250df12 }
|
|
288
288
|
.mchip.sys { color: #0a7d6b; background: #0a7d6b12 }
|
|
289
289
|
|
|
290
|
-
/*
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
.mrow.mine .mb
|
|
294
|
-
.mrow.mine .mb .bubble, .
|
|
295
|
-
|
|
296
|
-
.mrow.mine .mb .
|
|
297
|
-
.mrow.mine .mb
|
|
298
|
-
.mrow.mine .mb .tool-body section > h2, .mrow.mine .mb .diff-meta,
|
|
299
|
-
.mrow.mine .mb .tool-call > summary:hover { background: var(--mine-soft); border-color: var(--mine-line) }
|
|
300
|
-
.mrow.mine .mb .md-body pre code { background: transparent }
|
|
301
|
-
/* 展开的工具正文 (command / diff / 文件内容) 与嵌在父轮里的 subagent 卡片都是裸
|
|
302
|
-
section, 吃的是 TURN_CSS 的白底 —— 同样收回气泡底色; subagent 的绿色左边线留着。 */
|
|
303
|
-
.mrow.mine .mb .tool-body section { background: transparent; border-color: var(--mine-line) }
|
|
304
|
-
.mrow.mine .mb .turn-group .turn-group { background: transparent; box-shadow: none; border-color: var(--mine-line) }
|
|
305
|
-
.mrow.mine .mb .turn-group .turn-group.subagent { border-left-color: #1a7f3733 }
|
|
306
|
-
.mrow.mine .mb .bubble details, .mrow.mine .mb .tg-head { border-color: var(--mine-line) }
|
|
307
|
-
.mrow.mine .mb .tool-body { border-left-color: var(--mine-line) }
|
|
290
|
+
/* 自己说的话染成视角色 —— 只染气泡; 过程框是底上的一道虚线, 不跟着染。气泡里
|
|
291
|
+
TURN_CSS 写死的灰底 (行内代码 / 代码块) 沉一档到 --mine-soft, 免得显成贴纸。 */
|
|
292
|
+
.mrow.mine .mb :is(.bubble.mq, .say > .bubble) { background: var(--mine); border-color: var(--mine-line) }
|
|
293
|
+
.mrow.mine .mb :is(.bubble.mq, .say) .md-body :is(code, pre) { background: var(--mine-soft); border-color: var(--mine-line) }
|
|
294
|
+
.mrow.mine .mb :is(.bubble.mq, .say) .md-body pre code { background: transparent }
|
|
295
|
+
/* 气泡跟着行靠右, 时刻翻到气泡左边; 嵌在过程框里的子 agent 不翻 —— 那不是我说的。 */
|
|
296
|
+
.mrow.mine .mb > .turn-group > .bubbles > .say { align-self: flex-end; flex-direction: row-reverse }
|
|
297
|
+
.mrow.mine .mb > .turn-group > .tg-head { justify-content: flex-end }
|
|
308
298
|
/* 工具正文是展开时才取的 (chat.js loadTool) —— 空壳期间说一句在干什么。 */
|
|
309
299
|
.tool-body[data-lazy-turn]:empty::before { content: "加载中…"; color: #8c959f; font-size: 12px }
|
|
310
300
|
.tool-body[data-lazy-turn][data-err]:empty::before { content: "加载失败 · 收起再展开重试"; color: #cf222e }
|
|
@@ -342,38 +332,27 @@ span.av.go:hover { background: #2f55c924; box-shadow: 0 0 0 3px #2f55c924 }
|
|
|
342
332
|
.flip { transition: none }
|
|
343
333
|
}
|
|
344
334
|
|
|
345
|
-
/* ──
|
|
346
|
-
/* section
|
|
347
|
-
|
|
335
|
+
/* ── 一轮回复 ───────────────────────────────────────────────────── */
|
|
336
|
+
/* 只是一根竖轴, 不是卡片: section 的默认白底 / 边框在这里收掉。本轮的账 (模型 /
|
|
337
|
+
token / 耗时) 压成末尾一行小字 —— 它是这条消息的脚注, 不是标题。 */
|
|
348
338
|
.turn-group {
|
|
349
|
-
display: flex; flex-direction: column; gap:
|
|
350
|
-
padding:
|
|
351
|
-
box-shadow: 0 1px 2px #1f23280a;
|
|
339
|
+
display: flex; flex-direction: column; gap: 8px;
|
|
340
|
+
padding: 0; border: 0; border-radius: 0; background: none;
|
|
352
341
|
}
|
|
353
|
-
.tg-head {
|
|
354
|
-
|
|
355
|
-
padding
|
|
342
|
+
.tg-head { order: 9; display: flex; align-items: center; gap: 4px 10px; flex-wrap: wrap; padding: 0 2px }
|
|
343
|
+
.tg-head .chip.model, .tg-head .chip.tier, .tg-tok {
|
|
344
|
+
padding: 0; border: 0; border-radius: 0; background: none; font-weight: 400;
|
|
345
|
+
font-size: 10.5px; color: var(--faint); font-family: ui-monospace, Menlo, monospace;
|
|
356
346
|
}
|
|
357
|
-
.tg-dot { width: 7px; height: 7px; border-radius: 50%;
|
|
358
|
-
.tg-dot.live { background: #1a7f37; animation: pulse 1.4s infinite }
|
|
347
|
+
.tg-dot { width: 7px; height: 7px; border-radius: 50%; flex: none; display: none }
|
|
348
|
+
.tg-dot.live { display: block; background: #1a7f37; animation: pulse 1.4s infinite }
|
|
359
349
|
.tg-time { font-size: 11.5px; color: #8c959f; font-family: ui-monospace, Menlo, monospace }
|
|
360
|
-
.tg-tok {
|
|
361
|
-
font-size: 11px; color: #57606a; background: #f1f3f6; border-radius: 9px;
|
|
362
|
-
padding: 1px 7px; font-family: ui-monospace, Menlo, monospace;
|
|
363
|
-
}
|
|
364
|
-
.turn-group .bubbles { margin-top: 0 }
|
|
365
|
-
/* 上下文断点 (/clear、/new、会话轮换): 断点条来自 TURN_CSS, 这里再给整张卡片
|
|
366
|
-
多留一口气 + 描边, 让"这一轮读不到上一轮"在滚动中一眼可辨。 */
|
|
367
|
-
.turn-group.cut { margin-top: 12px }
|
|
368
|
-
.turn-group.cut-clear, .turn-group.cut-new {
|
|
369
|
-
border-color: #d4a72c66; box-shadow: 0 1px 2px #1f23280a, 0 0 0 3px #d4a72c14;
|
|
370
|
-
}
|
|
371
|
-
/* graph 派的一轮: 卡片本身也着色, 滚动时不必读归因条就知道这不是人发的。 */
|
|
372
|
-
.turn-group.graph { border-color: #8250df44 }
|
|
373
350
|
|
|
374
351
|
/* ── 🏓 keepalive 折叠 ──────────────────────────────────────────────
|
|
375
352
|
保温 ping 不是对话, 但它是真花销 —— 所以留在时间轴上, 只是收成一行虚线。 */
|
|
376
|
-
|
|
353
|
+
/* summary 的灰底 / 底线是 SHARED_CSS 里通用 details 的 —— 圆角得自己裁, 底线只在展开时才是分割线。 */
|
|
354
|
+
.ping-fold { border: 1px dashed #d8dee4; border-radius: 10px; background: #fbfcfd; overflow: hidden }
|
|
355
|
+
.ping-fold:not([open]) > .ping-sum { border-bottom: 0 }
|
|
377
356
|
.ping-fold > .ping-sum {
|
|
378
357
|
display: flex; align-items: center; gap: 8px; padding: 6px 12px;
|
|
379
358
|
cursor: pointer; list-style: none; font-size: 11.5px; color: #8c959f;
|
|
@@ -392,8 +371,6 @@ span.av.go:hover { background: #2f55c924; box-shadow: 0 0 0 3px #2f55c924 }
|
|
|
392
371
|
.ping-fold .ping-body {
|
|
393
372
|
display: flex; flex-direction: column; gap: 10px; padding: 2px 10px 10px;
|
|
394
373
|
}
|
|
395
|
-
/* 展开后的 ping 轮次压一档: 它们是背景噪声, 不该和真对话卡片一样醒目。 */
|
|
396
|
-
.ping-fold .turn-group { box-shadow: none }
|
|
397
374
|
.ping-fold .mcol { max-width: 100% }
|
|
398
375
|
.ping-fold .flip { display: none }
|
|
399
376
|
|
|
@@ -408,7 +385,6 @@ span.av.go:hover { background: #2f55c924; box-shadow: 0 0 0 3px #2f55c924 }
|
|
|
408
385
|
.thread { padding: 12px }
|
|
409
386
|
.mcol { max-width: calc(86% + var(--av)) }
|
|
410
387
|
.flip { min-width: 16px; padding: 0 4px; font-size: 0 }
|
|
411
|
-
.turn-group { padding: 12px }
|
|
412
388
|
.thread { padding-bottom: calc(12px + env(safe-area-inset-bottom)) }
|
|
413
389
|
.usage { padding: 8px 12px; gap: 6px 14px }
|
|
414
390
|
.usage .u-kvs, .usage .leg { flex-wrap: wrap }
|
|
@@ -729,5 +705,5 @@ span.av.go:hover { background: #2f55c924; box-shadow: 0 0 0 3px #2f55c924 }
|
|
|
729
705
|
会话标题条与页脚总账只属于对话视图。 */
|
|
730
706
|
.pane { flex: 1; min-height: 0; display: flex; flex-direction: column; background: #fafbfc }
|
|
731
707
|
|
|
732
|
-
/*
|
|
708
|
+
/* 过程框里的工具行是 nowrap 的 —— 不裁一刀会把整列撑出横向滚动。 */
|
|
733
709
|
.mb > .turn-group { overflow: hidden }
|
package/web/chat.js
CHANGED
|
@@ -192,6 +192,12 @@
|
|
|
192
192
|
for (var i = 0; i < el.children.length; i++) if (el.children[i].classList.contains(cls)) return el.children[i];
|
|
193
193
|
return null;
|
|
194
194
|
};
|
|
195
|
+
// 一轮回复 (.tg-head) 与过程框 (.steps-head) 是同一副骨架: 头 + .bubbles。
|
|
196
|
+
var headOf = function (el) { return childBy(el, 'tg-head') || childBy(el, 'steps-head'); };
|
|
197
|
+
var swapHead = function (ex, nc) {
|
|
198
|
+
var eh = headOf(ex), nh = headOf(nc);
|
|
199
|
+
if (eh && nh) eh.innerHTML = nh.innerHTML;
|
|
200
|
+
};
|
|
195
201
|
var reconcile = function (cur, next) {
|
|
196
202
|
var open = snapOpen(cur), existing = {};
|
|
197
203
|
Array.prototype.forEach.call(cur.children, function (c) {
|
|
@@ -203,8 +209,7 @@
|
|
|
203
209
|
if (ex.getAttribute('data-sig') === nc.getAttribute('data-sig')) return ex;
|
|
204
210
|
var eb = childBy(ex, 'bubbles'), nb = childBy(nc, 'bubbles');
|
|
205
211
|
if (eb && nb) {
|
|
206
|
-
|
|
207
|
-
if (eh && nh) eh.innerHTML = nh.innerHTML;
|
|
212
|
+
swapHead(ex, nc);
|
|
208
213
|
reconcile(eb, nb);
|
|
209
214
|
ex.setAttribute('data-sig', nc.getAttribute('data-sig') || '');
|
|
210
215
|
return ex;
|
|
@@ -249,6 +254,14 @@
|
|
|
249
254
|
if (d.open && d.classList && d.classList.contains('tool-call')) loadTool(d);
|
|
250
255
|
}, true);
|
|
251
256
|
|
|
257
|
+
// 过程框的收起: 框头与框内空白是开关; 落在某一行工具上的点击归那一行自己。
|
|
258
|
+
// 收起态只是节点上的一个 class —— reconcile 认键留节点, 往框里添调用时它跟着留下。
|
|
259
|
+
inner.addEventListener('click', function (e) {
|
|
260
|
+
var s = e.target.closest && e.target.closest('.steps');
|
|
261
|
+
if (!s) return;
|
|
262
|
+
if (e.target.closest('.steps-head') || e.target === s || e.target === childBy(s, 'bubbles')) s.classList.toggle('folded');
|
|
263
|
+
});
|
|
264
|
+
|
|
252
265
|
// ── 左栏: 当前 role 的名片 + 会话列表 ──
|
|
253
266
|
var convOf = function (key) { return R.convs.filter(function (c) { return c.key === key; })[0]; };
|
|
254
267
|
|
|
@@ -283,8 +296,8 @@
|
|
|
283
296
|
ms.map(function (m) { return '<i>' + esc(m.label || roleLabel(m.role)) + '</i>'; }).join('') + '</span>';
|
|
284
297
|
};
|
|
285
298
|
|
|
286
|
-
var line = function (title, ts, pv) {
|
|
287
|
-
return '<span class="b"><span class="l1"><span class="t">' + title + '</span>' +
|
|
299
|
+
var line = function (title, ts, pv, lamp) {
|
|
300
|
+
return '<span class="b"><span class="l1"><span class="t">' + title + '</span>' + (lamp || '') +
|
|
288
301
|
'<span class="ts">' + esc(fmtAgo(ts)) + '</span></span>' +
|
|
289
302
|
'<span class="pv">' + esc(pv) + '</span></span>';
|
|
290
303
|
};
|
|
@@ -299,8 +312,8 @@
|
|
|
299
312
|
var sel = s.role === WITH;
|
|
300
313
|
return '<button class="si' + (sel ? ' on' : '') + '" data-conv="' + esc(c.key) + '" data-with="' + esc(s.role) + '" ' +
|
|
301
314
|
'title="' + esc('我与 ' + nameOf(s.role) + ' 在这里的 ' + s.count + ' 条往来') + '">' +
|
|
302
|
-
goSpan('av', s.role, esc(s.label)
|
|
303
|
-
line(nm(s.role, s.name, true), s.lastTs, s.preview) + '</button>';
|
|
315
|
+
goSpan('av', s.role, esc(s.label)) +
|
|
316
|
+
line(nm(s.role, s.name, true), s.lastTs, s.preview, lampOf(s.status)) + '</button>';
|
|
304
317
|
}).join('') + '</div>'
|
|
305
318
|
: '';
|
|
306
319
|
var sel = on && !WITH;
|
|
@@ -485,14 +498,6 @@
|
|
|
485
498
|
putUsage($('#ch-usage'), !wiz && WITH && VIEW === 'msgs' ? R.winStats : null);
|
|
486
499
|
};
|
|
487
500
|
|
|
488
|
-
// 只有真群 (`chat:<roomid>`) 才有跳转: `user:` 是人与 bot 的单聊, userid 指向的是人自己而不是这段会话。
|
|
489
|
-
var JUMP = '<svg viewBox="0 0 16 16" width="13" height="13" aria-hidden="true"><path d="M9.5 2.5h4v4M13.5 2.5 7.5 8.5M11.5 9.5v3a1 1 0 0 1-1 1h-7a1 1 0 0 1-1-1v-7a1 1 0 0 1 1-1h3" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"/></svg>';
|
|
490
|
-
var openInWecom = function (base) {
|
|
491
|
-
return base.indexOf('chat:') === 0
|
|
492
|
-
? '<a class="jump" href="wxwork://openconversation?roomid=' + encodeURIComponent(base.slice(5)) + '" title="在企业微信中打开这个群聊">' + JUMP + '</a>'
|
|
493
|
-
: '';
|
|
494
|
-
};
|
|
495
|
-
|
|
496
501
|
// ── 右栏头: 这个群聊 / 私聊是什么 (关系 / 日程视图时是视图名) ──
|
|
497
502
|
var renderHead = function () {
|
|
498
503
|
var who = $('#ch-who'), acts = $('#ch-acts');
|
|
@@ -505,16 +510,7 @@
|
|
|
505
510
|
}
|
|
506
511
|
var c = convOf(CONV);
|
|
507
512
|
if (!c) { who.innerHTML = ''; acts.innerHTML = ''; return; }
|
|
508
|
-
|
|
509
|
-
who.innerHTML = avatarOf(c) + '<span class="l"><span class="t">' + nm(c.peer, c.name, true) + '</span>' +
|
|
510
|
-
'<span class="sub">私聊 · ' + c.count + ' 条</span></span>';
|
|
511
|
-
} else {
|
|
512
|
-
var ms = membersOf(c);
|
|
513
|
-
who.innerHTML = avatarOf(c) + '<span class="l"><span class="tr"><span class="t">' + esc(c.name) + '</span>' + openInWecom(c.base) + '</span>' +
|
|
514
|
-
'<span class="sub">群聊 · ' + ms.length + ' 位成员 · ' +
|
|
515
|
-
ms.slice(0, 8).map(function (m) { return esc(m.label || roleLabel(m.role)); }).join('') +
|
|
516
|
-
(ms.length > 8 ? '…' : '') + '</span></span>';
|
|
517
|
-
}
|
|
513
|
+
who.innerHTML = '<span class="t">' + (c.kind === 'wizard' ? nm(c.peer, c.name, true) : esc(c.name)) + '</span>';
|
|
518
514
|
acts.innerHTML = WITH
|
|
519
515
|
? '<span class="with">只看我与 ' + nm(WITH, '', true) + '</span><button class="vb" id="ch-all">看全部</button>'
|
|
520
516
|
: '';
|
|
@@ -654,8 +650,7 @@
|
|
|
654
650
|
var ec = eb && eb.firstElementChild, nc = nb && nb.firstElementChild;
|
|
655
651
|
var ebb = ec && childBy(ec, 'bubbles'), nbb = nc && childBy(nc, 'bubbles');
|
|
656
652
|
if (ebb && nbb) {
|
|
657
|
-
|
|
658
|
-
if (eh && nh) eh.innerHTML = nh.innerHTML;
|
|
653
|
+
swapHead(ec, nc);
|
|
659
654
|
reconcile(ebb, nbb);
|
|
660
655
|
['data-sig', 'data-stale-at'].forEach(function (a) { cur.setAttribute(a, next.getAttribute(a)); });
|
|
661
656
|
} else {
|