@decentnetwork/beagle 0.1.114 → 0.1.115

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/dist/desktop/app.js +191 -105
  2. package/package.json +2 -2
@@ -1,4 +1,4 @@
1
- window.__DK_UI_VERSION="0.1.114";
1
+ window.__DK_UI_VERSION="0.1.115";
2
2
  "use strict";
3
3
  (() => {
4
4
  // packages/beagle-ui/dist/beagle-ui.js
@@ -163,6 +163,140 @@ window.__DK_UI_VERSION="0.1.114";
163
163
  function DkBrowserNotice(props) {
164
164
  return H.DkBrowserNotice ? /* @__PURE__ */ React.createElement(H.DkBrowserNotice, { ...props }) : null;
165
165
  }
166
+ function protocolTest(rule) {
167
+ if (typeof rule !== "function")
168
+ return () => false;
169
+ return (msg) => {
170
+ if (!msg)
171
+ return false;
172
+ try {
173
+ const v = rule(msg);
174
+ return typeof v === "string" ? v || true : !!v;
175
+ } catch (e) {
176
+ return false;
177
+ }
178
+ };
179
+ }
180
+ function stripOwnPrefix(text) {
181
+ return String(text == null ? "" : text).replace(/^you:\s*/i, "");
182
+ }
183
+ function lastMessageOf(peer) {
184
+ const raw = String(peer && peer.lastMsg || "");
185
+ return {
186
+ text: stripOwnPrefix(raw),
187
+ dir: peer && peer.lastDir || (/^you:\s*/i.test(raw) ? "out" : "in"),
188
+ ts: peer && peer.lastTs || 0
189
+ };
190
+ }
191
+ function lastIsProtocol(peer, isProto) {
192
+ const last = lastMessageOf(peer);
193
+ if (!last.text)
194
+ return false;
195
+ return isProto(last);
196
+ }
197
+ function newestHumanMessage(msgs, isProto) {
198
+ const arr = msgs || [];
199
+ for (let i = arr.length - 1; i >= 0; i--) {
200
+ const m = arr[i];
201
+ if (!m)
202
+ continue;
203
+ if (m.file)
204
+ return m;
205
+ if (!m.text)
206
+ continue;
207
+ if (isProto({ text: m.text, dir: m.dir, ts: m.ts }))
208
+ continue;
209
+ return m;
210
+ }
211
+ return null;
212
+ }
213
+ function humanUnread(msgs, unread, isProto) {
214
+ const want = Number(unread) || 0;
215
+ if (want <= 0)
216
+ return { count: 0, exact: true };
217
+ const arr = msgs || [];
218
+ const window2 = arr.slice(Math.max(0, arr.length - want));
219
+ let n = 0;
220
+ for (const m of window2) {
221
+ if (!m || m.dir !== "in")
222
+ continue;
223
+ if (m.text && !m.file && isProto({ text: m.text, dir: m.dir, ts: m.ts }))
224
+ continue;
225
+ n++;
226
+ }
227
+ return { count: n, exact: window2.length >= want };
228
+ }
229
+ function rosterRow(peer, isProto, fix) {
230
+ const hidden = lastIsProtocol(peer, isProto);
231
+ if (!hidden) {
232
+ return {
233
+ preview: peer && peer.lastMsg || "",
234
+ lastTime: peer && peer.lastTime || "",
235
+ unread: Number(peer && peer.unread || 0),
236
+ activityTs: Number(peer && peer.lastTs || 0),
237
+ hidden: false
238
+ };
239
+ }
240
+ return {
241
+ preview: fix && fix.preview || "",
242
+ lastTime: fix && fix.lastTime || "",
243
+ unread: fix && fix.unreadExact ? fix.unread : 0,
244
+ activityTs: fix && fix.ts || 0,
245
+ hidden: true,
246
+ pending: !fix
247
+ };
248
+ }
249
+ function rosterUnreadTotal(peers, isProto, fixes) {
250
+ return (peers || []).reduce((n, p) => n + rosterRow(p, isProto, fixes && fixes[p.id]).unread, 0);
251
+ }
252
+ function collapseProtocol(thread, isProto, lang) {
253
+ const out = [];
254
+ let run = null;
255
+ const flush = () => {
256
+ if (!run)
257
+ return;
258
+ out.push({
259
+ protocol: true,
260
+ id: `proto-${run.first.id || run.startIndex}`,
261
+ count: run.items.length,
262
+ label: run.label,
263
+ dir: run.first.from === "me" ? "out" : "in",
264
+ text: run.items.map((m) => m.text).join("\n"),
265
+ line: protocolLine(run, lang)
266
+ });
267
+ run = null;
268
+ };
269
+ (thread || []).forEach((m, i) => {
270
+ const hit = m && !m.day ? isProto({ text: m.text, dir: m && m.from === "me" ? "out" : "in", ts: m && m.ts }) : false;
271
+ if (!hit || m && m.file) {
272
+ flush();
273
+ out.push(m);
274
+ return;
275
+ }
276
+ if (!run)
277
+ run = { first: m, startIndex: i, items: [], label: typeof hit === "string" ? hit : "" };
278
+ if (!run.label && typeof hit === "string")
279
+ run.label = hit;
280
+ run.items.push(m);
281
+ });
282
+ flush();
283
+ return out;
284
+ }
285
+ function protocolLine(run, lang) {
286
+ const arrow = run.first.from === "me" ? "\u2192" : "\u2190";
287
+ const n = run.items.length;
288
+ if (run.label) {
289
+ return `\u2699 ${arrow} ${run.label}${n > 1 ? ` \xB7 ${n}` : ""}`;
290
+ }
291
+ if (n > 1) {
292
+ return lang === "zh" ? `\u2699 ${arrow} ${n} \u6761\u534F\u8BAE\u6D88\u606F` : `\u2699 ${arrow} ${n} protocol messages`;
293
+ }
294
+ return `\u2699 ${arrow} ${protocolSummary(run.first.text)}`;
295
+ }
296
+ function protocolSummary(text, max = 72) {
297
+ const s = String(text == null ? "" : text).replace(/\s+/g, " ").trim();
298
+ return s.length > max ? s.slice(0, max - 1) + "\u2026" : s;
299
+ }
166
300
  function dkHash(s) {
167
301
  let h = 2166136261;
168
302
  for (let i = 0; i < s.length; i++) {
@@ -394,6 +528,48 @@ window.__DK_UI_VERSION="0.1.114";
394
528
  components: m.components
395
529
  };
396
530
  }
531
+ var DK_TAIL_MIN = 30;
532
+ var DK_TAIL_MAX = 200;
533
+ function useProtocolTails(peers, isProtocol, enabled) {
534
+ const [fixes, setFixes] = React.useState({});
535
+ const cache = React.useRef(/* @__PURE__ */ new Map());
536
+ const inFlight = React.useRef(/* @__PURE__ */ new Set());
537
+ React.useEffect(() => {
538
+ if (!enabled)
539
+ return;
540
+ for (const p of peers || []) {
541
+ if (!p || !lastIsProtocol(p, isProtocol))
542
+ continue;
543
+ const unread = Number(p.unread) || 0;
544
+ const key = `${p.lastTs || 0}:${unread}`;
545
+ const had = cache.current.get(p.id);
546
+ if (had && had.key === key)
547
+ continue;
548
+ if (inFlight.current.has(p.id))
549
+ continue;
550
+ const limit = Math.min(DK_TAIL_MAX, Math.max(DK_TAIL_MIN, unread + 5));
551
+ inFlight.current.add(p.id);
552
+ dkGet("/api/chat-history?peer=" + encodeURIComponent(p.id) + "&limit=" + limit).then((d) => {
553
+ const msgs = d && d.chats && d.chats[p.id] || [];
554
+ const human = newestHumanMessage(msgs, isProtocol);
555
+ const count = humanUnread(msgs, unread, isProtocol);
556
+ const fix = {
557
+ preview: human ? (human.dir === "out" ? "you: " : "") + (human.file ? human.file.name : human.text || "") : "",
558
+ lastTime: human ? dkClock(human.ts) : "",
559
+ ts: human ? human.ts : 0,
560
+ unread: count.count,
561
+ unreadExact: count.exact
562
+ };
563
+ cache.current.set(p.id, { key, fix });
564
+ setFixes((f) => Object.assign({}, f, { [p.id]: fix }));
565
+ }).catch(() => {
566
+ }).finally(() => {
567
+ inFlight.current.delete(p.id);
568
+ });
569
+ }
570
+ }, [peers, isProtocol, enabled]);
571
+ return fixes;
572
+ }
397
573
  function useDaemonData() {
398
574
  const [snap, setSnap] = React.useState({
399
575
  me: DK_ME_FALLBACK,
@@ -1493,98 +1669,6 @@ ${lines}`, { assistant: { kind: "adopt", rows: fresh } }));
1493
1669
  }, [append, lang, onReloadFriends]);
1494
1670
  return { thread, handle, removeFriends, adoptServicePeers };
1495
1671
  }
1496
- function protocolTest(rule) {
1497
- if (typeof rule !== "function")
1498
- return () => false;
1499
- return (msg) => {
1500
- if (!msg)
1501
- return false;
1502
- try {
1503
- const v = rule(msg);
1504
- return typeof v === "string" ? v || true : !!v;
1505
- } catch (e) {
1506
- return false;
1507
- }
1508
- };
1509
- }
1510
- function stripOwnPrefix(text) {
1511
- return String(text == null ? "" : text).replace(/^you:\s*/i, "");
1512
- }
1513
- function lastMessageOf(peer) {
1514
- const raw = String(peer && peer.lastMsg || "");
1515
- return {
1516
- text: stripOwnPrefix(raw),
1517
- dir: peer && peer.lastDir || (/^you:\s*/i.test(raw) ? "out" : "in"),
1518
- ts: peer && peer.lastTs || 0
1519
- };
1520
- }
1521
- function lastIsProtocol(peer, isProto) {
1522
- const last = lastMessageOf(peer);
1523
- if (!last.text)
1524
- return false;
1525
- return isProto(last);
1526
- }
1527
- function rosterRow(peer, isProto) {
1528
- const hidden = lastIsProtocol(peer, isProto);
1529
- return {
1530
- preview: hidden ? "" : peer && peer.lastMsg || "",
1531
- lastTime: hidden ? "" : peer && peer.lastTime || "",
1532
- unread: hidden ? 0 : Number(peer && peer.unread || 0),
1533
- activityTs: hidden ? 0 : Number(peer && peer.lastTs || 0),
1534
- hidden
1535
- };
1536
- }
1537
- function rosterUnreadTotal(peers, isProto) {
1538
- return (peers || []).reduce((n, p) => n + rosterRow(p, isProto).unread, 0);
1539
- }
1540
- function collapseProtocol(thread, isProto, lang) {
1541
- const out = [];
1542
- let run = null;
1543
- const flush = () => {
1544
- if (!run)
1545
- return;
1546
- out.push({
1547
- protocol: true,
1548
- id: `proto-${run.first.id || run.startIndex}`,
1549
- count: run.items.length,
1550
- label: run.label,
1551
- dir: run.first.from === "me" ? "out" : "in",
1552
- text: run.items.map((m) => m.text).join("\n"),
1553
- line: protocolLine(run, lang)
1554
- });
1555
- run = null;
1556
- };
1557
- (thread || []).forEach((m, i) => {
1558
- const hit = m && !m.day ? isProto({ text: m.text, dir: m && m.from === "me" ? "out" : "in", ts: m && m.ts }) : false;
1559
- if (!hit || m && m.file) {
1560
- flush();
1561
- out.push(m);
1562
- return;
1563
- }
1564
- if (!run)
1565
- run = { first: m, startIndex: i, items: [], label: typeof hit === "string" ? hit : "" };
1566
- if (!run.label && typeof hit === "string")
1567
- run.label = hit;
1568
- run.items.push(m);
1569
- });
1570
- flush();
1571
- return out;
1572
- }
1573
- function protocolLine(run, lang) {
1574
- const arrow = run.first.from === "me" ? "\u2192" : "\u2190";
1575
- const n = run.items.length;
1576
- if (run.label) {
1577
- return `\u2699 ${arrow} ${run.label}${n > 1 ? ` \xB7 ${n}` : ""}`;
1578
- }
1579
- if (n > 1) {
1580
- return lang === "zh" ? `\u2699 ${arrow} ${n} \u6761\u534F\u8BAE\u6D88\u606F` : `\u2699 ${arrow} ${n} protocol messages`;
1581
- }
1582
- return `\u2699 ${arrow} ${protocolSummary(run.first.text)}`;
1583
- }
1584
- function protocolSummary(text, max = 72) {
1585
- const s = String(text == null ? "" : text).replace(/\s+/g, " ").trim();
1586
- return s.length > max ? s.slice(0, max - 1) + "\u2026" : s;
1587
- }
1588
1672
  var DK_CMD_HIST_KEY = "beagle.assistant.history";
1589
1673
  var DK_CMD_HIST_MAX = 50;
1590
1674
  function RequestsBlock({ T, requests, onAct }) {
@@ -1645,9 +1729,9 @@ ${lines}`, { assistant: { kind: "adopt", rows: fresh } }));
1645
1729
  paddingLeft: 8
1646
1730
  } }, r.descr), failed[r.id] && /* @__PURE__ */ React.createElement("div", { style: { fontFamily: "var(--ui)", fontSize: 11, color: "var(--danger)" } }, failed[r.id]), /* @__PURE__ */ React.createElement("div", { style: { display: "flex", gap: 6 } }, /* @__PURE__ */ React.createElement(Btn, { tone: "ok", icon: "check", size: "sm", onClick: () => act(r, "accept"), style: { flex: 1 } }, T.accept), /* @__PURE__ */ React.createElement(Btn, { tone: "danger", icon: "x", size: "sm", onClick: () => act(r, "reject"), style: { flex: 1 } }, T.reject))))));
1647
1731
  }
1648
- function PeerRow({ peer, T, active, onClick, muted, isProtocol }) {
1732
+ function PeerRow({ peer, T, active, onClick, muted, isProtocol, fix }) {
1649
1733
  const name = peer.alias || peer.userId;
1650
- const row = rosterRow(peer, isProtocol || (() => false));
1734
+ const row = rosterRow(peer, isProtocol || (() => false), fix);
1651
1735
  return /* @__PURE__ */ React.createElement("button", { onClick, style: {
1652
1736
  display: "flex",
1653
1737
  alignItems: "center",
@@ -1678,11 +1762,11 @@ ${lines}`, { assistant: { kind: "adopt", rows: fresh } }));
1678
1762
  minWidth: 0
1679
1763
  } }, dkRowPreview(row.preview)))), /* @__PURE__ */ React.createElement("div", { style: { display: "flex", flexDirection: "column", alignItems: "flex-end", gap: 4, flexShrink: 0 } }, /* @__PURE__ */ React.createElement("span", { style: { fontFamily: "var(--mono)", fontSize: 10.5, color: "var(--faint)" } }, row.lastTime), row.unread ? /* @__PURE__ */ React.createElement(Unread, { n: row.unread }) : peer.pending ? /* @__PURE__ */ React.createElement(Icon, { name: "clock", size: 11, stroke: 2.2, color: "var(--warn, #d29922)", title: "friend request pending" }) : /* @__PURE__ */ React.createElement(StatusDot, { online: peer.online })));
1680
1764
  }
1681
- function dkActivityTs(p, isProtocol) {
1682
- const row = rosterRow(p, isProtocol || (() => false));
1765
+ function dkActivityTs(p, isProtocol, fix) {
1766
+ const row = rosterRow(p, isProtocol || (() => false), fix);
1683
1767
  return Math.max(row.activityTs, p.acceptedAt || 0, p.requestedAt || 0);
1684
1768
  }
1685
- function PeerSidebar({ T, peers, requests, activeId, onSelect, onAct, onAdd, prefillAddr, onPrefillConsumed, muted, wide, isProtocol }) {
1769
+ function PeerSidebar({ T, peers, requests, activeId, onSelect, onAct, onAdd, prefillAddr, onPrefillConsumed, muted, wide, isProtocol, protocolFix }) {
1686
1770
  const [q, setQ] = React.useState("");
1687
1771
  const [addr, setAddr] = React.useState("");
1688
1772
  const [addState, setAddState] = React.useState(null);
@@ -1727,7 +1811,8 @@ ${lines}`, { assistant: { kind: "adopt", rows: fresh } }));
1727
1811
  }).slice().sort((a, b) => {
1728
1812
  if (!!a.pinned !== !!b.pinned)
1729
1813
  return a.pinned ? -1 : 1;
1730
- const ta = dkActivityTs(a, isProtocol), tb = dkActivityTs(b, isProtocol);
1814
+ const ta = dkActivityTs(a, isProtocol, protocolFix && protocolFix[a.id]);
1815
+ const tb = dkActivityTs(b, isProtocol, protocolFix && protocolFix[b.id]);
1731
1816
  if (ta !== tb)
1732
1817
  return tb - ta;
1733
1818
  return String(a.alias || a.userId || "").localeCompare(String(b.alias || b.userId || ""));
@@ -1766,7 +1851,7 @@ ${lines}`, { assistant: { kind: "adopt", rows: fresh } }));
1766
1851
  fontSize: 11.5,
1767
1852
  lineHeight: 1.35,
1768
1853
  color: addState.kind === "err" ? "var(--bad, #e5484d)" : addState.kind === "ok" ? "var(--good, #46a758)" : "var(--faint)"
1769
- } }, addState.msg), /* @__PURE__ */ React.createElement("div", { style: { position: "relative", display: "flex", alignItems: "center" } }, /* @__PURE__ */ React.createElement(Icon, { name: "search", size: 15, color: "var(--faint)", stroke: 2, style: { position: "absolute", left: 9 } }), /* @__PURE__ */ React.createElement("input", { value: q, onChange: (e) => setQ(e.target.value), placeholder: T.search, style: { ...inputStyle, paddingLeft: 30 } }))), /* @__PURE__ */ React.createElement("div", { style: { flex: 1, overflow: "auto", padding: "10px 8px 16px" } }, /* @__PURE__ */ React.createElement(RequestsBlock, { T, requests, onAct }), /* @__PURE__ */ React.createElement(Section, { label: T.peers, count: `${online}/${peers.length}`, style: { margin: "6px 4px 8px" } }), /* @__PURE__ */ React.createElement("div", { style: { display: "flex", flexDirection: "column", gap: 2 } }, filtered.map((p) => /* @__PURE__ */ React.createElement(PeerRow, { key: p.id, peer: p, T, active: p.id === activeId, onClick: () => onSelect(p.id), muted: !!muted && muted.includes(p.id), isProtocol })), !filtered.length && /* @__PURE__ */ React.createElement("div", { style: { padding: 16, textAlign: "center", fontFamily: "var(--mono)", fontSize: 12, color: "var(--faint)" } }, "no matches"))));
1854
+ } }, addState.msg), /* @__PURE__ */ React.createElement("div", { style: { position: "relative", display: "flex", alignItems: "center" } }, /* @__PURE__ */ React.createElement(Icon, { name: "search", size: 15, color: "var(--faint)", stroke: 2, style: { position: "absolute", left: 9 } }), /* @__PURE__ */ React.createElement("input", { value: q, onChange: (e) => setQ(e.target.value), placeholder: T.search, style: { ...inputStyle, paddingLeft: 30 } }))), /* @__PURE__ */ React.createElement("div", { style: { flex: 1, overflow: "auto", padding: "10px 8px 16px" } }, /* @__PURE__ */ React.createElement(RequestsBlock, { T, requests, onAct }), /* @__PURE__ */ React.createElement(Section, { label: T.peers, count: `${online}/${peers.length}`, style: { margin: "6px 4px 8px" } }), /* @__PURE__ */ React.createElement("div", { style: { display: "flex", flexDirection: "column", gap: 2 } }, filtered.map((p) => /* @__PURE__ */ React.createElement(PeerRow, { key: p.id, peer: p, T, active: p.id === activeId, onClick: () => onSelect(p.id), muted: !!muted && muted.includes(p.id), isProtocol, fix: protocolFix && protocolFix[p.id] })), !filtered.length && /* @__PURE__ */ React.createElement("div", { style: { padding: 16, textAlign: "center", fontFamily: "var(--mono)", fontSize: 12, color: "var(--faint)" } }, "no matches"))));
1770
1855
  }
1771
1856
  var inputStyle = {
1772
1857
  flex: 1,
@@ -3367,12 +3452,12 @@ ${peer.address}`
3367
3452
  function ChatEmpty({ T }) {
3368
3453
  return /* @__PURE__ */ React.createElement("div", { style: { flex: 1, display: "flex", flexDirection: "column", alignItems: "center", justifyContent: "center", gap: 12, color: "var(--faint)", background: "var(--bg)" } }, /* @__PURE__ */ React.createElement(Icon, { name: "message", size: 40, stroke: 1.4, color: "var(--line)" }), /* @__PURE__ */ React.createElement("div", { style: { fontFamily: "var(--mono)", fontSize: 13 } }, T.pickPeer));
3369
3454
  }
3370
- function ChatTab({ T, lang, peers, requests, activeId, thread, isProtocol, onSelect, onAct, onAdd, onSend, onSendFile, onSendRtcFile, onAlias, onRemove, onOpenNet, onCall, onReloadThread, hasEarlier, onLoadEarlier, onAssistantRemove, onAssistantAdopt, prefillAddr, onPrefillConsumed, muted, onToggleMute, phone, onBack }) {
3455
+ function ChatTab({ T, lang, peers, requests, activeId, thread, isProtocol, protocolFix, onSelect, onAct, onAdd, onSend, onSendFile, onSendRtcFile, onAlias, onRemove, onOpenNet, onCall, onReloadThread, hasEarlier, onLoadEarlier, onAssistantRemove, onAssistantAdopt, prefillAddr, onPrefillConsumed, muted, onToggleMute, phone, onBack }) {
3371
3456
  const peer = peers.find((p) => p.id === activeId);
3372
3457
  if (phone) {
3373
- return peer ? /* @__PURE__ */ React.createElement(Conversation, { T, peer, lang, peers, onOpenChat: onSelect, thread, isProtocol, onSend, onSendFile, onSendRtcFile, onAlias, onRemove, onOpenNet, onCall, onReloadThread, hasEarlier, onLoadEarlier, onAssistantRemove, onAssistantAdopt, muted: !!muted && muted.includes(peer.id), onToggleMute, phone: true, onBack }) : /* @__PURE__ */ React.createElement(PeerSidebar, { T, peers, requests, activeId, onSelect, onAct, onAdd, prefillAddr, onPrefillConsumed, muted, isProtocol, wide: true });
3458
+ return peer ? /* @__PURE__ */ React.createElement(Conversation, { T, peer, lang, peers, onOpenChat: onSelect, thread, isProtocol, onSend, onSendFile, onSendRtcFile, onAlias, onRemove, onOpenNet, onCall, onReloadThread, hasEarlier, onLoadEarlier, onAssistantRemove, onAssistantAdopt, muted: !!muted && muted.includes(peer.id), onToggleMute, phone: true, onBack }) : /* @__PURE__ */ React.createElement(PeerSidebar, { T, peers, requests, activeId, onSelect, onAct, onAdd, prefillAddr, onPrefillConsumed, muted, isProtocol, protocolFix, wide: true });
3374
3459
  }
3375
- return /* @__PURE__ */ React.createElement("div", { style: { flex: 1, display: "flex", minWidth: 0, minHeight: 0 } }, /* @__PURE__ */ React.createElement(PeerSidebar, { T, peers, requests, activeId, onSelect, onAct, onAdd, prefillAddr, onPrefillConsumed, muted, isProtocol }), peer ? /* @__PURE__ */ React.createElement(Conversation, { T, peer, lang, peers, onOpenChat: onSelect, thread, isProtocol, onSend, onSendFile, onSendRtcFile, onAlias, onRemove, onOpenNet, onCall, onReloadThread, hasEarlier, onLoadEarlier, onAssistantRemove, onAssistantAdopt, muted: !!muted && muted.includes(peer.id), onToggleMute }) : /* @__PURE__ */ React.createElement(ChatEmpty, { T }));
3460
+ return /* @__PURE__ */ React.createElement("div", { style: { flex: 1, display: "flex", minWidth: 0, minHeight: 0 } }, /* @__PURE__ */ React.createElement(PeerSidebar, { T, peers, requests, activeId, onSelect, onAct, onAdd, prefillAddr, onPrefillConsumed, muted, isProtocol, protocolFix }), peer ? /* @__PURE__ */ React.createElement(Conversation, { T, peer, lang, peers, onOpenChat: onSelect, thread, isProtocol, onSend, onSendFile, onSendRtcFile, onAlias, onRemove, onOpenNet, onCall, onReloadThread, hasEarlier, onLoadEarlier, onAssistantRemove, onAssistantAdopt, muted: !!muted && muted.includes(peer.id), onToggleMute }) : /* @__PURE__ */ React.createElement(ChatEmpty, { T }));
3376
3461
  }
3377
3462
  Object.assign(window, { ChatTab });
3378
3463
  function CopyBtn({ value, copiedText = "Copied", copyFailedText = "Copy failed", copyTitle = "Copy" }) {
@@ -6884,6 +6969,7 @@ ${peer.address}`
6884
6969
  const mutedIds = Array.isArray(t.alertMuted) ? t.alertMuted : [];
6885
6970
  const onToggleMute = (id) => setTweak("alertMuted", mutedIds.includes(id) ? mutedIds.filter((x) => x !== id) : mutedIds.concat(id));
6886
6971
  const isProtocol = React.useMemo(() => protocolTest(hostIsProtocolMessage), []);
6972
+ const protocolFix = useProtocolTails(peers, isProtocol, !!hostIsProtocolMessage);
6887
6973
  useIncomingAlerts({
6888
6974
  T,
6889
6975
  peers,
@@ -7145,7 +7231,7 @@ ${peer.address}`
7145
7231
  const lastPeople = React.useRef("here");
7146
7232
  if (peopleTab)
7147
7233
  lastPeople.current = tab;
7148
- const unreadTotal = rosterUnreadTotal(peers, isProtocol) + (requests || []).length;
7234
+ const unreadTotal = rosterUnreadTotal(peers, isProtocol, protocolFix) + (requests || []).length;
7149
7235
  const NAV_FOR = {
7150
7236
  chat: { icon: "message", label: T.chat, active: tab === "chat", badge: unreadTotal, go: () => setTab("chat") },
7151
7237
  people: { icon: "users", label: T.people, active: peopleTab, go: () => setTab(lastPeople.current) },
@@ -7203,7 +7289,7 @@ ${peer.address}`
7203
7289
  fontWeight: 600,
7204
7290
  background: tab === n.id ? "var(--accent)" : "transparent",
7205
7291
  color: tab === n.id ? "#fff" : "var(--dim)"
7206
- } }, /* @__PURE__ */ React.createElement(Icon, { name: n.icon, size: 14, stroke: 2, color: tab === n.id ? "#fff" : "var(--dim)" }), n.label))), tab === "chat" && /* @__PURE__ */ React.createElement(ChatTab, { T, lang: t.lang, phone, isProtocol, onBack: closeConversation, peers, requests, activeId, thread: activeId === ASSISTANT_ID ? assistant.thread : data.threads[activeId], onSelect, onAct, onAdd, onSend, onSendFile, onSendRtcFile, onAlias, onRemove, onOpenNet, onCall, onReloadThread: () => activeId && data.loadThread(activeId), hasEarlier: !!(activeId && activeId !== ASSISTANT_ID && data.earlier[activeId]), onAssistantRemove: activeId === ASSISTANT_ID ? assistant.removeFriends : null, onAssistantAdopt: activeId === ASSISTANT_ID ? assistant.adoptServicePeers : null, onLoadEarlier: () => activeId && data.loadEarlier(activeId), prefillAddr: pendingAddr, onPrefillConsumed: () => setPendingAddr(""), muted: mutedIds, onToggleMute }), tab === "here" && /* @__PURE__ */ React.createElement(DiscoverTab, { T, kind: "bridge", peers, meId: me.userId, onAdd, onOpenChat }), tab === "recommended" && /* @__PURE__ */ React.createElement(DiscoverTab, { T, kind: "recommended", peers, meId: me.userId, onAdd, onOpenChat }), tab === "registered" && /* @__PURE__ */ React.createElement(DiscoverTab, { T, kind: "registered", peers, meId: me.userId, onAdd, onOpenChat }), tab === "network" && /* @__PURE__ */ React.createElement(NetworkTab, { T, me, peers, exits, activeExit, reqCount: requests.length, onSetExit, onOpenChat, backend, onArmLan: armLan, onCancelLan: cancelLan }), tab === "apps" && /* @__PURE__ */ React.createElement(AppsTab, { T, t, me, peers, phone, setTab }), tabs.map((x) => x.kind === "host" && tab === x.id ? /* @__PURE__ */ React.createElement(HostTabPane, { key: x.id, tab: x, props: { T, t, me, peers, phone, setTab }, lang: t.lang }) : null), tab === "profile" && /* @__PURE__ */ React.createElement(
7292
+ } }, /* @__PURE__ */ React.createElement(Icon, { name: n.icon, size: 14, stroke: 2, color: tab === n.id ? "#fff" : "var(--dim)" }), n.label))), tab === "chat" && /* @__PURE__ */ React.createElement(ChatTab, { T, lang: t.lang, phone, isProtocol, protocolFix, onBack: closeConversation, peers, requests, activeId, thread: activeId === ASSISTANT_ID ? assistant.thread : data.threads[activeId], onSelect, onAct, onAdd, onSend, onSendFile, onSendRtcFile, onAlias, onRemove, onOpenNet, onCall, onReloadThread: () => activeId && data.loadThread(activeId), hasEarlier: !!(activeId && activeId !== ASSISTANT_ID && data.earlier[activeId]), onAssistantRemove: activeId === ASSISTANT_ID ? assistant.removeFriends : null, onAssistantAdopt: activeId === ASSISTANT_ID ? assistant.adoptServicePeers : null, onLoadEarlier: () => activeId && data.loadEarlier(activeId), prefillAddr: pendingAddr, onPrefillConsumed: () => setPendingAddr(""), muted: mutedIds, onToggleMute }), tab === "here" && /* @__PURE__ */ React.createElement(DiscoverTab, { T, kind: "bridge", peers, meId: me.userId, onAdd, onOpenChat }), tab === "recommended" && /* @__PURE__ */ React.createElement(DiscoverTab, { T, kind: "recommended", peers, meId: me.userId, onAdd, onOpenChat }), tab === "registered" && /* @__PURE__ */ React.createElement(DiscoverTab, { T, kind: "registered", peers, meId: me.userId, onAdd, onOpenChat }), tab === "network" && /* @__PURE__ */ React.createElement(NetworkTab, { T, me, peers, exits, activeExit, reqCount: requests.length, onSetExit, onOpenChat, backend, onArmLan: armLan, onCancelLan: cancelLan }), tab === "apps" && /* @__PURE__ */ React.createElement(AppsTab, { T, t, me, peers, phone, setTab }), tabs.map((x) => x.kind === "host" && tab === x.id ? /* @__PURE__ */ React.createElement(HostTabPane, { key: x.id, tab: x, props: { T, t, me, peers, phone, setTab }, lang: t.lang }) : null), tab === "profile" && /* @__PURE__ */ React.createElement(
7207
7293
  ProfileTab,
7208
7294
  {
7209
7295
  T,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@decentnetwork/beagle",
3
- "version": "0.1.114",
3
+ "version": "0.1.115",
4
4
  "description": "Beagle — P2P chat, file transfer and calls for regular users, on the Decent Network. No admin privilege required.",
5
5
  "type": "module",
6
6
  "main": "./dist/index.js",
@@ -35,7 +35,7 @@
35
35
  "yargs": "^17.7.2"
36
36
  },
37
37
  "devDependencies": {
38
- "@decentnetwork/beagle-ui": "^0.2.28",
38
+ "@decentnetwork/beagle-ui": "^0.2.29",
39
39
  "@types/js-yaml": "^4.0.9",
40
40
  "@types/node": "^20.11.0",
41
41
  "@types/yargs": "^17.0.32",