@bolloon/bolloon-agent 0.3.26 → 0.3.28
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/agents/decision-store.js +247 -0
- package/dist/agents/pi-sdk-tools.js +419 -0
- package/dist/bootstrap/context-os.js +213 -0
- package/dist/bootstrap/lifecycle-hooks.js +8 -2
- package/dist/bootstrap/memory-compressor.js +126 -1
- package/dist/bootstrap/persona-loader.js +88 -5
- package/dist/pi-ecosystem-mcp/index.js +153 -37
- package/dist/security/tool-gate.js +10 -0
- package/dist/web/client.js +119 -9
- package/dist/web/server-storage.js +9 -2
- package/dist/web/server.js +570 -36
- package/package.json +1 -1
package/dist/web/client.js
CHANGED
|
@@ -1689,7 +1689,72 @@
|
|
|
1689
1689
|
v3GlobalEventSource.onmessage = (e) => {
|
|
1690
1690
|
try {
|
|
1691
1691
|
const msg = JSON.parse(e.data);
|
|
1692
|
-
if (msg.type === "remote-chat-
|
|
1692
|
+
if (msg.type === "remote-chat-sent") {
|
|
1693
|
+
console.log("[v3] \u6536\u5230 remote-chat-sent:", msg.channelId, "|", String(msg.text || "").slice(0, 30));
|
|
1694
|
+
try {
|
|
1695
|
+
const pk = msg.fromPublicKey;
|
|
1696
|
+
const cid = msg.channelId;
|
|
1697
|
+
if (pk && cid && msg.text) {
|
|
1698
|
+
const key = `bolloon.rcmCache.${pk}.${cid}`;
|
|
1699
|
+
let arr = [];
|
|
1700
|
+
try {
|
|
1701
|
+
const raw = localStorage.getItem(key);
|
|
1702
|
+
if (raw) arr = JSON.parse(raw);
|
|
1703
|
+
} catch {
|
|
1704
|
+
arr = [];
|
|
1705
|
+
}
|
|
1706
|
+
if (!Array.isArray(arr)) arr = [];
|
|
1707
|
+
const entry = { type: "user", content: msg.text, timestamp: (/* @__PURE__ */ new Date()).toISOString(), source: "local-sent" };
|
|
1708
|
+
const dup = arr.some((m) => m.type === "user" && m.content === entry.content && m.source === "local-sent");
|
|
1709
|
+
if (!dup) {
|
|
1710
|
+
arr.push(entry);
|
|
1711
|
+
try {
|
|
1712
|
+
localStorage.setItem(key, JSON.stringify(arr.slice(-200)));
|
|
1713
|
+
} catch {
|
|
1714
|
+
}
|
|
1715
|
+
}
|
|
1716
|
+
}
|
|
1717
|
+
} catch {
|
|
1718
|
+
}
|
|
1719
|
+
const log = document.getElementById("rcm-log");
|
|
1720
|
+
if (!log) return;
|
|
1721
|
+
const modal = document.getElementById("remote-chat-modal");
|
|
1722
|
+
const openChannelId = modal ? modal.dataset.channelId : null;
|
|
1723
|
+
if (openChannelId && openChannelId !== msg.channelId) return;
|
|
1724
|
+
const prefix = `\u{1F464} \u6211 \u2192 \u8FDC\u7AEF${msg.peerName ? ` ${msg.peerName}` : ""}
|
|
1725
|
+
|
|
1726
|
+
`;
|
|
1727
|
+
addMessage2(prefix + (msg.text || ""), "user", false, log);
|
|
1728
|
+
if (msg.queued) {
|
|
1729
|
+
const qEl = document.createElement("div");
|
|
1730
|
+
qEl.className = "remote-chat-sysmsg remote-chat-sysmsg-info";
|
|
1731
|
+
qEl.textContent = "\u{1F4E4} \u5BF9\u65B9\u4E0D\u5728\u7EBF, \u6D88\u606F\u5DF2\u5165\u961F, \u4E0A\u7EBF\u540E\u81EA\u52A8\u9001\u8FBE";
|
|
1732
|
+
log.appendChild(qEl);
|
|
1733
|
+
}
|
|
1734
|
+
log.scrollTop = log.scrollHeight;
|
|
1735
|
+
} else if (msg.type === "remote-chat-step") {
|
|
1736
|
+
const log = document.getElementById("rcm-log");
|
|
1737
|
+
if (!log) return;
|
|
1738
|
+
const modal = document.getElementById("remote-chat-modal");
|
|
1739
|
+
const openChannelId = modal ? modal.dataset.channelId : null;
|
|
1740
|
+
if (openChannelId && openChannelId !== msg.channelId) return;
|
|
1741
|
+
let liveEl = document.getElementById("rcm-thinking-live-local");
|
|
1742
|
+
if (!liveEl) {
|
|
1743
|
+
liveEl = document.createElement("div");
|
|
1744
|
+
liveEl.id = "rcm-thinking-live-local";
|
|
1745
|
+
liveEl.className = "remote-chat-sysmsg remote-chat-sysmsg-info";
|
|
1746
|
+
log.appendChild(liveEl);
|
|
1747
|
+
}
|
|
1748
|
+
if (msg.stepType === "step_start") {
|
|
1749
|
+
liveEl.textContent = `\u{1F527} \u672C\u5730\u667A\u80FD\u4F53\u6B63\u5728\u8C03\u7528\u5DE5\u5177: ${msg.tool || "..."}`;
|
|
1750
|
+
} else if (msg.stepType === "step_done") {
|
|
1751
|
+
liveEl.textContent = `\u2705 \u672C\u5730\u5DE5\u5177\u8C03\u7528\u5B8C\u6210: ${msg.tool || ""}`;
|
|
1752
|
+
} else if (msg.stepType === "step_error") {
|
|
1753
|
+
liveEl.textContent = `\u274C \u672C\u5730\u5DE5\u5177\u8C03\u7528\u5931\u8D25: ${msg.tool || ""}`;
|
|
1754
|
+
liveEl.className = "remote-chat-sysmsg remote-chat-sysmsg-error";
|
|
1755
|
+
}
|
|
1756
|
+
log.scrollTop = log.scrollHeight;
|
|
1757
|
+
} else if (msg.type === "remote-chat-reply") {
|
|
1693
1758
|
const log = document.getElementById("rcm-log");
|
|
1694
1759
|
const thinkingEl = document.getElementById("rcm-thinking");
|
|
1695
1760
|
if (thinkingEl) thinkingEl.style.display = "none";
|
|
@@ -1793,15 +1858,25 @@
|
|
|
1793
1858
|
}
|
|
1794
1859
|
}
|
|
1795
1860
|
} else if (msg.type === "cross-mention-received") {
|
|
1861
|
+
const log = document.getElementById("rcm-log");
|
|
1862
|
+
const rcmModal = document.getElementById("remote-chat-modal");
|
|
1863
|
+
const rcmOpenId = rcmModal ? rcmModal.dataset.channelId : null;
|
|
1864
|
+
if (log && (!msg.targetChannelId || !rcmOpenId || rcmOpenId === msg.targetChannelId)) {
|
|
1865
|
+
const fromTxt = msg.source === "ai-mention-remote" ? `\u8FDC\u7AEF\u667A\u80FD\u4F53 ${msg.originChannelName ? `(${msg.originChannelName})` : ""}` : `${msg.originChannelName} (\u672C\u5730)`;
|
|
1866
|
+
addMessage2(`\u{1F4E1} ${fromTxt}
|
|
1867
|
+
|
|
1868
|
+
${msg.text || ""}`, "ai", false, log);
|
|
1869
|
+
log.scrollTop = log.scrollHeight;
|
|
1870
|
+
}
|
|
1796
1871
|
const allModals = document.querySelectorAll('.rcm-mention-toast, [id^="rcm-log"]');
|
|
1797
|
-
for (const
|
|
1798
|
-
if (!
|
|
1872
|
+
for (const logEl of allModals) {
|
|
1873
|
+
if (!logEl.id) continue;
|
|
1799
1874
|
const toast = document.createElement("div");
|
|
1800
1875
|
toast.style.cssText = "margin:6px 0;padding:8px 10px;background:#fce7f3;border-left:3px solid #ec4899;border-radius:4px;font-size:12px;color:#831843;";
|
|
1801
1876
|
const fromTxt = msg.source === "ai-mention-remote" ? `\u8FDC\u7AEF\u8282\u70B9 ${(msg.fromPublicKey || "").substring(0, 8)}\u2026 \u7684 ${msg.originChannelName}` : `${msg.originChannelName} (\u672C\u5730)`;
|
|
1802
1877
|
toast.innerHTML = `\u{1F4E1} <b>${fromTxt}</b> @-mention \u2192 \u5F53\u524D channel: <i>${escapeHtml2((msg.text || "").slice(0, 100))}</i>${msg.text && msg.text.length > 100 ? "\u2026" : ""}`;
|
|
1803
|
-
|
|
1804
|
-
|
|
1878
|
+
logEl.appendChild(toast);
|
|
1879
|
+
logEl.scrollTop = logEl.scrollHeight;
|
|
1805
1880
|
}
|
|
1806
1881
|
} else if (msg.type === "remote-channel-update") {
|
|
1807
1882
|
const peerId = msg.peerId;
|
|
@@ -4971,7 +5046,7 @@ ${data.error || "channel not found"}`, "error");
|
|
|
4971
5046
|
function openRemoteChannelChat(peerPublicKey, channelId, channelName) {
|
|
4972
5047
|
document.getElementById("remote-chat-modal")?.remove();
|
|
4973
5048
|
const html = `
|
|
4974
|
-
<div id="remote-chat-modal" class="remote-chat-overlay">
|
|
5049
|
+
<div id="remote-chat-modal" class="remote-chat-overlay" data-channel-id="${escapeHtml2(channelId)}" data-peer-id="${escapeHtml2(peerPublicKey)}">
|
|
4975
5050
|
<div class="remote-chat-shell">
|
|
4976
5051
|
<div class="remote-chat-header">
|
|
4977
5052
|
<div style="flex:1;min-width:0;">
|
|
@@ -5093,7 +5168,11 @@ ${data.error || "channel not found"}`, "error");
|
|
|
5093
5168
|
const type = m.type === "user" ? "user" : "ai";
|
|
5094
5169
|
let prefix = "";
|
|
5095
5170
|
if (m.type === "user") {
|
|
5096
|
-
if (m.source === "
|
|
5171
|
+
if (m.source === "local-sent") {
|
|
5172
|
+
prefix = `\u{1F464} \u6211 \u2192 \u8FDC\u7AEF
|
|
5173
|
+
|
|
5174
|
+
`;
|
|
5175
|
+
} else if (m.source === "remote") {
|
|
5097
5176
|
prefix = `\u{1F310} \u8FDC\u7AEF\u8BBF\u5BA2${m.fromPublicKey ? " (" + m.fromPublicKey.substring(0, 8) + "\u2026)" : ""}
|
|
5098
5177
|
|
|
5099
5178
|
`;
|
|
@@ -5103,9 +5182,19 @@ ${data.error || "channel not found"}`, "error");
|
|
|
5103
5182
|
`;
|
|
5104
5183
|
}
|
|
5105
5184
|
} else {
|
|
5106
|
-
|
|
5185
|
+
if (m.source === "remote-reply") {
|
|
5186
|
+
prefix = `\u{1F916} \u8FDC\u7AEF\u56DE\u590D
|
|
5187
|
+
|
|
5188
|
+
`;
|
|
5189
|
+
} else if (m.source === "ai-mention-remote") {
|
|
5190
|
+
prefix = `\u{1F4E1} \u8FDC\u7AEF\u667A\u80FD\u4F53 ${m.originChannelName ? `(${m.originChannelName})` : ""}
|
|
5107
5191
|
|
|
5108
5192
|
`;
|
|
5193
|
+
} else {
|
|
5194
|
+
prefix = `\u{1F916} A \u7684 LLM
|
|
5195
|
+
|
|
5196
|
+
`;
|
|
5197
|
+
}
|
|
5109
5198
|
}
|
|
5110
5199
|
addMessage2(prefix + (m.content || ""), type, false, log);
|
|
5111
5200
|
}
|
|
@@ -5123,12 +5212,33 @@ ${data.error || "channel not found"}`, "error");
|
|
|
5123
5212
|
writeRcmCache(cacheMsgs);
|
|
5124
5213
|
} catch {
|
|
5125
5214
|
}
|
|
5215
|
+
try {
|
|
5216
|
+
const cachedAll = readRcmCache();
|
|
5217
|
+
const localSent = cachedAll.filter((m) => m.source === "local-sent");
|
|
5218
|
+
if (localSent.length > 0) {
|
|
5219
|
+
const remoteContents = new Set(msgs.map((m) => m.content));
|
|
5220
|
+
for (const m of localSent) {
|
|
5221
|
+
if (remoteContents.has(m.content)) continue;
|
|
5222
|
+
const dup = Array.from(log.querySelectorAll(".message-user")).some(
|
|
5223
|
+
(el) => (el.textContent || "").includes(m.content)
|
|
5224
|
+
);
|
|
5225
|
+
if (dup) continue;
|
|
5226
|
+
addMessage2(`\u{1F464} \u6211 \u2192 \u8FDC\u7AEF
|
|
5227
|
+
|
|
5228
|
+
${m.content}`, "user", false, log);
|
|
5229
|
+
}
|
|
5230
|
+
setTimeout(() => {
|
|
5231
|
+
log.scrollTop = log.scrollHeight;
|
|
5232
|
+
}, 50);
|
|
5233
|
+
}
|
|
5234
|
+
} catch {
|
|
5235
|
+
}
|
|
5126
5236
|
}
|
|
5127
5237
|
const doSend = async () => {
|
|
5128
5238
|
const text = inputEl.value.trim();
|
|
5129
5239
|
if (!text) return;
|
|
5130
5240
|
append(text, "user");
|
|
5131
|
-
cacheRemoteMessage(peerPublicKey, channelId, { type: "user", content: text, timestamp: (/* @__PURE__ */ new Date()).toISOString() });
|
|
5241
|
+
cacheRemoteMessage(peerPublicKey, channelId, { type: "user", content: text, timestamp: (/* @__PURE__ */ new Date()).toISOString(), source: "local-sent" });
|
|
5132
5242
|
inputEl.value = "";
|
|
5133
5243
|
sendBtn2.disabled = true;
|
|
5134
5244
|
sendBtn2.textContent = "...";
|
|
@@ -24,13 +24,20 @@ export function getLastChannelsWriteAt() {
|
|
|
24
24
|
}
|
|
25
25
|
/** 对 channels 执行原子化的 read-modify-write, 自带互斥锁 */
|
|
26
26
|
export async function updateChannels(fn) {
|
|
27
|
-
|
|
27
|
+
const run = channelsLock.then(async () => {
|
|
28
28
|
const chs = await rawLoadChannels();
|
|
29
29
|
const result = fn(chs);
|
|
30
30
|
await rawSaveChannels(result);
|
|
31
31
|
return result;
|
|
32
32
|
});
|
|
33
|
-
|
|
33
|
+
// 2026-08-02 fix: 失败不毒化锁链 — 之前 channelsLock = channelsLock.then(...),
|
|
34
|
+
// 某次 fn 抛错 → 整个链变 rejected → 之后所有 updateChannels 直接 reject,
|
|
35
|
+
// fn 不再执行 → UI 创建 channel 偶发"不落盘" (静默丢失).
|
|
36
|
+
channelsLock = run.catch((e) => {
|
|
37
|
+
console.error('[updateChannels] 失败 (已隔离, 不影响后续操作):', e?.message || e);
|
|
38
|
+
return undefined;
|
|
39
|
+
});
|
|
40
|
+
return run;
|
|
34
41
|
}
|
|
35
42
|
async function rawLoadChannels() {
|
|
36
43
|
try {
|