@bolloon/bolloon-agent 0.5.3 → 0.5.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/agents/agent-identity-store.js +41 -5
- package/dist/agents/background-notices.js +124 -0
- package/dist/agents/channel-identity.js +54 -0
- package/dist/agents/code-write-gate.js +47 -0
- package/dist/agents/deny-pipeline.js +11 -2
- package/dist/agents/egress-sanitize.js +69 -0
- package/dist/agents/error-classifier.js +67 -5
- package/dist/agents/experience-review.js +226 -0
- package/dist/agents/gateway-group.js +153 -18
- package/dist/agents/iteration-budget.js +64 -0
- package/dist/agents/lesson-to-skill.js +211 -0
- package/dist/agents/managed-services.js +64 -0
- package/dist/agents/parse-tool-call.js +38 -32
- package/dist/agents/pi-sdk-session-manager.js +72 -3
- package/dist/agents/pi-sdk-tools.js +268 -47
- package/dist/agents/pi-sdk.js +470 -22
- package/dist/agents/plan-store.js +36 -0
- package/dist/agents/process-runner.js +64 -2
- package/dist/agents/session-store.js +144 -3
- package/dist/agents/shell-guard.js +109 -13
- package/dist/agents/skill-health.js +90 -0
- package/dist/agents/skill-ledger.js +129 -0
- package/dist/agents/tool-loop-guard.js +303 -0
- package/dist/agents/tool-path-args.js +53 -0
- package/dist/agents/tool-result-gate.js +50 -0
- package/dist/agents/tool-subset.js +109 -0
- package/dist/agents/tool-telemetry.js +97 -0
- package/dist/agents/wallet-tools.js +63 -0
- package/dist/bootstrap/context-collector.js +37 -7
- package/dist/bootstrap/lifecycle-hooks.js +12 -3
- package/dist/bootstrap/persona-init.js +174 -0
- package/dist/bootstrap/persona-loader.js +5 -1
- package/dist/cli/ink-app.js +231 -32
- package/dist/cli/input-history.js +119 -0
- package/dist/cli/input-paste.js +218 -0
- package/dist/cli/loading-tui.js +69 -7
- package/dist/cli/log-gate.js +46 -1
- package/dist/cli/mention-data.js +30 -0
- package/dist/cli/reasoning-view.js +103 -0
- package/dist/cli/session-summary.js +129 -0
- package/dist/cli/session-tree.js +141 -0
- package/dist/cli/startup-notice.js +25 -0
- package/dist/cli/status-segments.js +155 -0
- package/dist/cli/stores.js +16 -0
- package/dist/cli/trace-line.js +54 -0
- package/dist/cli/wallet-store.js +159 -0
- package/dist/cli/wallet-table.js +46 -0
- package/dist/cli-entry.js +22 -0
- package/dist/context-compaction/auto-compact.js +37 -2
- package/dist/electron-build/agents/agent-identity-store.js +43 -5
- package/dist/electron-build/agents/agent-identity-store.js.map +1 -1
- package/dist/electron-build/agents/background-notices.js +138 -0
- package/dist/electron-build/agents/background-notices.js.map +1 -0
- package/dist/electron-build/agents/channel-identity.js +64 -0
- package/dist/electron-build/agents/channel-identity.js.map +1 -0
- package/dist/electron-build/agents/code-write-gate.js +55 -0
- package/dist/electron-build/agents/code-write-gate.js.map +1 -0
- package/dist/electron-build/agents/deny-pipeline.js +11 -2
- package/dist/electron-build/agents/deny-pipeline.js.map +1 -1
- package/dist/electron-build/agents/egress-sanitize.js +76 -0
- package/dist/electron-build/agents/egress-sanitize.js.map +1 -0
- package/dist/electron-build/agents/error-classifier.js +68 -5
- package/dist/electron-build/agents/error-classifier.js.map +1 -1
- package/dist/electron-build/agents/experience-review.js +243 -0
- package/dist/electron-build/agents/experience-review.js.map +1 -0
- package/dist/electron-build/agents/iteration-budget.js +73 -0
- package/dist/electron-build/agents/iteration-budget.js.map +1 -0
- package/dist/electron-build/agents/lesson-to-skill.js +228 -0
- package/dist/electron-build/agents/lesson-to-skill.js.map +1 -0
- package/dist/electron-build/agents/managed-services.js +69 -0
- package/dist/electron-build/agents/managed-services.js.map +1 -0
- package/dist/electron-build/agents/parse-tool-call.js +38 -32
- package/dist/electron-build/agents/parse-tool-call.js.map +1 -1
- package/dist/electron-build/agents/pi-sdk-session-manager.js +75 -3
- package/dist/electron-build/agents/pi-sdk-session-manager.js.map +1 -1
- package/dist/electron-build/agents/pi-sdk-tools.js +268 -46
- package/dist/electron-build/agents/pi-sdk-tools.js.map +1 -1
- package/dist/electron-build/agents/pi-sdk-types.js.map +1 -1
- package/dist/electron-build/agents/pi-sdk.js +471 -22
- package/dist/electron-build/agents/pi-sdk.js.map +1 -1
- package/dist/electron-build/agents/plan-store.js +37 -0
- package/dist/electron-build/agents/plan-store.js.map +1 -1
- package/dist/electron-build/agents/process-runner.js +71 -2
- package/dist/electron-build/agents/process-runner.js.map +1 -1
- package/dist/electron-build/agents/session-store.js +144 -3
- package/dist/electron-build/agents/session-store.js.map +1 -1
- package/dist/electron-build/agents/shell-guard.js +110 -14
- package/dist/electron-build/agents/shell-guard.js.map +1 -1
- package/dist/electron-build/agents/skill-health.js +103 -0
- package/dist/electron-build/agents/skill-health.js.map +1 -0
- package/dist/electron-build/agents/skill-ledger.js +146 -0
- package/dist/electron-build/agents/skill-ledger.js.map +1 -0
- package/dist/electron-build/agents/tool-loop-guard.js +319 -0
- package/dist/electron-build/agents/tool-loop-guard.js.map +1 -0
- package/dist/electron-build/agents/tool-path-args.js +63 -0
- package/dist/electron-build/agents/tool-path-args.js.map +1 -0
- package/dist/electron-build/agents/tool-result-gate.js +59 -0
- package/dist/electron-build/agents/tool-result-gate.js.map +1 -0
- package/dist/electron-build/agents/tool-subset.js +116 -0
- package/dist/electron-build/agents/tool-subset.js.map +1 -0
- package/dist/electron-build/agents/tool-telemetry.js +108 -0
- package/dist/electron-build/agents/tool-telemetry.js.map +1 -0
- package/dist/electron-build/agents/wallet-tools.js +102 -0
- package/dist/electron-build/agents/wallet-tools.js.map +1 -0
- package/dist/electron-build/bootstrap/context-collector.js +38 -7
- package/dist/electron-build/bootstrap/context-collector.js.map +1 -1
- package/dist/electron-build/bootstrap/lifecycle-hooks.js +12 -3
- package/dist/electron-build/bootstrap/lifecycle-hooks.js.map +1 -1
- package/dist/electron-build/bootstrap/persona-init.js +216 -0
- package/dist/electron-build/bootstrap/persona-init.js.map +1 -0
- package/dist/electron-build/bootstrap/persona-loader.js +5 -1
- package/dist/electron-build/bootstrap/persona-loader.js.map +1 -1
- package/dist/electron-build/cli/wallet-store.js +200 -0
- package/dist/electron-build/cli/wallet-store.js.map +1 -0
- package/dist/electron-build/context-compaction/auto-compact.js +38 -2
- package/dist/electron-build/context-compaction/auto-compact.js.map +1 -1
- package/dist/electron-build/external-engines/delegate.js +22 -0
- package/dist/electron-build/external-engines/delegate.js.map +1 -1
- package/dist/electron-build/llm/pi-ai.js +25 -0
- package/dist/electron-build/llm/pi-ai.js.map +1 -1
- package/dist/electron-build/orbitdb/cid-database.js +55 -0
- package/dist/electron-build/orbitdb/cid-database.js.map +1 -1
- package/dist/electron-build/orbitdb/ipfs-node.js +36 -11
- package/dist/electron-build/orbitdb/ipfs-node.js.map +1 -1
- package/dist/electron-build/web/server-storage.js +26 -5
- package/dist/electron-build/web/server-storage.js.map +1 -1
- package/dist/external-engines/delegate.js +21 -0
- package/dist/index.js +1324 -173
- package/dist/llm/pi-ai.js +23 -0
- package/dist/orbitdb/cid-database.js +55 -0
- package/dist/orbitdb/event-index.js +370 -0
- package/dist/orbitdb/event-query.js +131 -0
- package/dist/orbitdb/event-shell.js +510 -0
- package/dist/orbitdb/group-access.js +381 -0
- package/dist/orbitdb/group-shards.js +140 -0
- package/dist/orbitdb/ipfs-node.js +36 -11
- package/dist/web/bolloon-web.json +3 -3
- package/dist/web/client.js +3 -2
- package/dist/web/mobile-core.js +7762 -6289
- package/dist/web/routes-mobile-tasks.js +2 -1
- package/dist/web/server-storage.js +26 -5
- package/dist/web/server.js +2 -0
- package/dist/web/sw.js +1 -1
- package/package.json +2 -1
|
@@ -0,0 +1,159 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* wallet-store.ts — bolloon 自己的钱包台账: **一个目录, 一钱包一文件** (leo 2026-09-30)
|
|
3
|
+
*
|
|
4
|
+
* 事实与边界:
|
|
5
|
+
* · agent 工具 `wallet_create` / `wallet_import` 只**生成/解析**钱包, **从不落盘**
|
|
6
|
+
* (`constraint-runtime/src/tools/WalletTools/createWallet.ts` 纯 `Wallet.createRandom()`) ⇒
|
|
7
|
+
* `/wallet` 一直是「钱包 (0)」不是路径写错, 是**从来没写过文件**。
|
|
8
|
+
* · 台账目录 = `~/.bolloon/wallets/`, **一钱包一文件** `<名字>.json` (**0600**)。
|
|
9
|
+
* 放这儿而不是仓库里: 仓库是公开的 (`private:false`), 私钥进 git 就完了。
|
|
10
|
+
* · 文件里允许有私钥/助记词 (签名要用), 但**命令输出永不回显** —— 只给地址 + 路径。
|
|
11
|
+
* · 不读别的 agent 的钱包目录 (`~/.hermes/wallets/…`): `chain-config.ts` 定的硬规则 ——
|
|
12
|
+
* 那不属于本进程, 读了就是越权。要收编必须由**用户显式给路径** (`/wallet import <path>`)。
|
|
13
|
+
* · 老的单文件台账 (`~/.bolloon/wallets.json`) 若存在 ⇒ 一次性拆进目录, 原文件改名 `.migrated`
|
|
14
|
+
* (不删: 用户的数据, 出问题能翻回去)。
|
|
15
|
+
*/
|
|
16
|
+
import * as fs from 'fs/promises';
|
|
17
|
+
import * as path from 'path';
|
|
18
|
+
/** 一钱包一文件所在目录 */
|
|
19
|
+
export function walletsDir() {
|
|
20
|
+
return path.join(process.env.HOME || '/tmp', '.bolloon', 'wallets');
|
|
21
|
+
}
|
|
22
|
+
/** 文件名安全化 (只保留字母数字与 - _ .) */
|
|
23
|
+
function safeName(name, fallback = 'wallet') {
|
|
24
|
+
const s = String(name || '').trim().replace(/[^A-Za-z0-9._-]+/g, '-').replace(/^-+|-+$/g, '');
|
|
25
|
+
return s || fallback;
|
|
26
|
+
}
|
|
27
|
+
async function readOne(file) {
|
|
28
|
+
try {
|
|
29
|
+
const raw = JSON.parse(await fs.readFile(file, 'utf-8'));
|
|
30
|
+
const address = raw?.address;
|
|
31
|
+
if (typeof address !== 'string' || !address.startsWith('0x'))
|
|
32
|
+
return null;
|
|
33
|
+
return {
|
|
34
|
+
name: String(raw?.name || path.basename(file).replace(/\.json$/, '')),
|
|
35
|
+
address,
|
|
36
|
+
network: String(raw?.network || '—'),
|
|
37
|
+
source: raw?.source === 'imported' ? 'imported' : 'created',
|
|
38
|
+
createdAt: String(raw?.createdAt || ''),
|
|
39
|
+
privateKey: typeof raw?.privateKey === 'string' ? raw.privateKey : undefined,
|
|
40
|
+
mnemonic: typeof raw?.mnemonic === 'string' ? raw.mnemonic : undefined,
|
|
41
|
+
};
|
|
42
|
+
}
|
|
43
|
+
catch {
|
|
44
|
+
return null; // 坏文件不挡列表 —— 但下面 loadWallets 会把"读不了的"计数报出去
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
/** 老单文件台账拆进目录 (一次性; 原文件改名 .migrated 保留) */
|
|
48
|
+
async function migrateLegacySingleFile(dir) {
|
|
49
|
+
const legacy = path.join(process.env.HOME || '/tmp', '.bolloon', 'wallets.json');
|
|
50
|
+
let raw;
|
|
51
|
+
try {
|
|
52
|
+
raw = JSON.parse(await fs.readFile(legacy, 'utf-8'));
|
|
53
|
+
}
|
|
54
|
+
catch {
|
|
55
|
+
return 0;
|
|
56
|
+
}
|
|
57
|
+
const list = Array.isArray(raw) ? raw : Array.isArray(raw?.wallets) ? raw.wallets : [];
|
|
58
|
+
let n = 0;
|
|
59
|
+
for (const w of list) {
|
|
60
|
+
if (!w?.address)
|
|
61
|
+
continue;
|
|
62
|
+
const rec = {
|
|
63
|
+
name: safeName(w.name || `wallet-${n + 1}`), address: String(w.address),
|
|
64
|
+
network: String(w.network || '—'), source: w.source === 'imported' ? 'imported' : 'created',
|
|
65
|
+
createdAt: String(w.createdAt || new Date().toISOString()),
|
|
66
|
+
privateKey: typeof w.privateKey === 'string' ? w.privateKey : undefined,
|
|
67
|
+
mnemonic: typeof w.mnemonic === 'string' ? w.mnemonic : undefined,
|
|
68
|
+
};
|
|
69
|
+
await writeWalletFile(dir, rec);
|
|
70
|
+
n++;
|
|
71
|
+
}
|
|
72
|
+
try {
|
|
73
|
+
await fs.rename(legacy, `${legacy}.migrated`);
|
|
74
|
+
}
|
|
75
|
+
catch { /* 改名失败就留着, 下次再试 */ }
|
|
76
|
+
return n;
|
|
77
|
+
}
|
|
78
|
+
async function writeWalletFile(dir, rec) {
|
|
79
|
+
await fs.mkdir(dir, { recursive: true });
|
|
80
|
+
const file = path.join(dir, `${safeName(rec.name)}.json`);
|
|
81
|
+
const tmp = `${file}.tmp`;
|
|
82
|
+
await fs.writeFile(tmp, JSON.stringify(rec, null, 2), { encoding: 'utf-8', mode: 0o600 });
|
|
83
|
+
await fs.rename(tmp, file);
|
|
84
|
+
try {
|
|
85
|
+
await fs.chmod(file, 0o600);
|
|
86
|
+
}
|
|
87
|
+
catch { /* 已足够 */ }
|
|
88
|
+
return file;
|
|
89
|
+
}
|
|
90
|
+
/** 迁移只做一次 (模块级旗标) —— 每次进程首次读台账时试一次 */
|
|
91
|
+
let legacyMigrated = false;
|
|
92
|
+
/** 读全部钱包 (一钱包一文件, 按文件名排序) */
|
|
93
|
+
export async function loadWallets() {
|
|
94
|
+
const dir = walletsDir();
|
|
95
|
+
await fs.mkdir(dir, { recursive: true }).catch(() => { });
|
|
96
|
+
// 老单文件台账: 每进程首次读的时候试一次迁移 (旗标防重复; 迁移里自己判断有没有老文件)
|
|
97
|
+
if (!legacyMigrated) {
|
|
98
|
+
legacyMigrated = true;
|
|
99
|
+
const n = await migrateLegacySingleFile(dir);
|
|
100
|
+
if (n > 0) { /* 迁移来的文件就在下面一起读 */ }
|
|
101
|
+
}
|
|
102
|
+
let names = [];
|
|
103
|
+
try {
|
|
104
|
+
names = (await fs.readdir(dir)).filter(n => n.endsWith('.json') && !n.endsWith('.tmp')).sort();
|
|
105
|
+
}
|
|
106
|
+
catch (e) {
|
|
107
|
+
throw new Error(`钱包目录读不了 (${dir}): ${String(e?.message || e).slice(0, 120)}`);
|
|
108
|
+
}
|
|
109
|
+
const out = [];
|
|
110
|
+
for (const n of names) {
|
|
111
|
+
const rec = await readOne(path.join(dir, n));
|
|
112
|
+
if (rec)
|
|
113
|
+
out.push(rec);
|
|
114
|
+
}
|
|
115
|
+
return out;
|
|
116
|
+
}
|
|
117
|
+
/**
|
|
118
|
+
* 写一个钱包进目录。
|
|
119
|
+
* · 同地址**不新建文件**: 合并进那条 (不覆盖已有私钥/助记词)
|
|
120
|
+
* · 名字撞了就自动加后缀 (-2, -3 …)
|
|
121
|
+
*/
|
|
122
|
+
export async function addWallet(rec) {
|
|
123
|
+
const dir = walletsDir();
|
|
124
|
+
const existing = await loadWallets();
|
|
125
|
+
const dup = existing.find(w => w.address.toLowerCase() === rec.address.toLowerCase());
|
|
126
|
+
if (dup) {
|
|
127
|
+
const merged = {
|
|
128
|
+
...rec,
|
|
129
|
+
name: dup.name, // 保留原来的文件名/名字
|
|
130
|
+
privateKey: dup.privateKey || rec.privateKey,
|
|
131
|
+
mnemonic: dup.mnemonic || rec.mnemonic,
|
|
132
|
+
createdAt: dup.createdAt || rec.createdAt,
|
|
133
|
+
};
|
|
134
|
+
const file = await writeWalletFile(dir, merged);
|
|
135
|
+
return { rec: merged, replaced: true, file };
|
|
136
|
+
}
|
|
137
|
+
let name = safeName(rec.name);
|
|
138
|
+
const used = new Set(existing.map(w => w.name));
|
|
139
|
+
for (let i = 2; used.has(name); i++)
|
|
140
|
+
name = `${safeName(rec.name)}-${i}`;
|
|
141
|
+
const out = { ...rec, name };
|
|
142
|
+
const file = await writeWalletFile(dir, out);
|
|
143
|
+
return { rec: out, replaced: false, file };
|
|
144
|
+
}
|
|
145
|
+
/** 按 # / 地址 / 名字挑一个 */
|
|
146
|
+
export function pickWallet(list, spec) {
|
|
147
|
+
if (!spec)
|
|
148
|
+
return list[0];
|
|
149
|
+
const n = Number(spec);
|
|
150
|
+
if (Number.isFinite(n) && n >= 1)
|
|
151
|
+
return list[n - 1];
|
|
152
|
+
if (spec.startsWith('0x'))
|
|
153
|
+
return list.find(w => w.address.toLowerCase() === spec.toLowerCase());
|
|
154
|
+
return list.find(w => w.name === spec);
|
|
155
|
+
}
|
|
156
|
+
/** 地址缩写 (单行显示用) */
|
|
157
|
+
export function shortAddr(a) {
|
|
158
|
+
return a && a.length > 12 ? `${a.slice(0, 6)}…${a.slice(-4)}` : String(a || '?');
|
|
159
|
+
}
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* wallet-table.ts — `/wallet` 的钱包表格渲染 (leo 2026-09-30: 「钱包格式也统一一个表格」)
|
|
3
|
+
*
|
|
4
|
+
* 为什么单独抽出来: 表格的**对齐/裁宽**必须能确定性验证 —— 之前它内联在 CLI 的 /wallet 分支里,
|
|
5
|
+
* 只能靠 PTY 抓包看 (那工具这轮抽风 6 次只成 2 次), 验证变成了碰运气。
|
|
6
|
+
* 抽成纯函数 (进 list, 出 string[] 无 ANSI) ⇒ 可以直接跑、直接看列宽对不对 (含中文名列)。
|
|
7
|
+
*
|
|
8
|
+
* 与 `/sessions` 同一套口径: 列宽按终端宽动态分配; 中文按**显示宽**对齐 (dispWidth);
|
|
9
|
+
* 地址优先给满 42 字符 (能直接复制), 列宽不足才退回缩写 (0x1234…abcd) —— 不截半截地址。
|
|
10
|
+
*/
|
|
11
|
+
import { dispWidth, truncate } from './loading-tui.js';
|
|
12
|
+
/**
|
|
13
|
+
* 返回表格行 (无 ANSI): [表头, 分隔线, ...数据行]
|
|
14
|
+
* 调用方负责加颜色前缀/缩进。
|
|
15
|
+
*/
|
|
16
|
+
export function renderWalletTable(list, opts) {
|
|
17
|
+
const zh = opts.lang !== 'en';
|
|
18
|
+
const PAD = (v, w) => v + ' '.repeat(Math.max(0, w - dispWidth(v)));
|
|
19
|
+
const avail = Math.max(60, opts.width - 2);
|
|
20
|
+
const wN = 3, wChain = 8, wSrc = 6, wDate = 10;
|
|
21
|
+
const fixed = wN + wChain + wSrc + wDate + 5; // 5 = 列间空格
|
|
22
|
+
const wAddr = Math.max(13, Math.min(42, Math.floor((avail - fixed) * 0.55)));
|
|
23
|
+
const wName = Math.max(12, avail - fixed - wAddr);
|
|
24
|
+
const cols = [wN, wName, wAddr, wChain, wSrc, wDate];
|
|
25
|
+
const hdr = [
|
|
26
|
+
PAD('#', wN),
|
|
27
|
+
PAD(zh ? '名字' : 'Name', wName),
|
|
28
|
+
PAD(zh ? '地址' : 'Address', wAddr),
|
|
29
|
+
PAD(zh ? '链' : 'Chain', wChain),
|
|
30
|
+
PAD(zh ? '来源' : 'Source', wSrc),
|
|
31
|
+
PAD(zh ? '建立' : 'Created', wDate),
|
|
32
|
+
].join(' ');
|
|
33
|
+
const rule = cols.map(w => '─'.repeat(w)).join(' ');
|
|
34
|
+
const rows = list.map((w, k) => {
|
|
35
|
+
const addr = wAddr >= 42 ? w.address : opts.shortAddr(w.address);
|
|
36
|
+
return [
|
|
37
|
+
PAD(String(k + 1), wN),
|
|
38
|
+
PAD(truncate(w.name, wName), wName),
|
|
39
|
+
PAD(truncate(addr, wAddr), wAddr),
|
|
40
|
+
PAD(truncate(w.network || '—', wChain), wChain),
|
|
41
|
+
PAD(w.source === 'imported' ? (zh ? '导入' : 'imported') : (zh ? '生成' : 'created'), wSrc),
|
|
42
|
+
PAD(String(w.createdAt).slice(0, 10), wDate),
|
|
43
|
+
].join(' ');
|
|
44
|
+
});
|
|
45
|
+
return [hdr, rule, ...rows];
|
|
46
|
+
}
|
package/dist/cli-entry.js
CHANGED
|
@@ -21,6 +21,8 @@ import { printBanner } from './cli/loading-tui.js';
|
|
|
21
21
|
import { discoverEngines, delegateToEngine } from './external-engines/index.js';
|
|
22
22
|
import { x402CheckBalance, x402Fetch } from './agents/x402/x402Pay.js';
|
|
23
23
|
import { runVersionCommand, runUpdateCommand, runDoctorCommand, runRuntimeCommand, UPDATE_HELP } from './cli/update-commands.js';
|
|
24
|
+
import { installStartupLogGate } from './cli/log-gate.js';
|
|
25
|
+
import { waitForTermSize } from './cli/loading-tui.js';
|
|
24
26
|
import { collectVersionInfo } from './utils/version-info.js';
|
|
25
27
|
// 2026-09-27: 启动前言的默认静默 + 显式查询命令 (与 `src/index.ts` 同一套判断)
|
|
26
28
|
import { startupPreambleVisible } from './cli/startup-notice.js';
|
|
@@ -965,6 +967,26 @@ async function main() {
|
|
|
965
967
|
await startWebServer(args);
|
|
966
968
|
break;
|
|
967
969
|
case 'cli':
|
|
970
|
+
/**
|
|
971
|
+
* 2026-09-30 修复 (leo 报「开启过程的日志没去掉」): 启动日志门原先在 `index.ts` 很靠后的位置才装,
|
|
972
|
+
* 于是**早于它**发生的第三方输出会直接落到 tty, 出现在启动面板之前 (实测 SDK 的 ipfs 装配会打
|
|
973
|
+
* `[warn]: ipfs init 失败…` 两行 + 它自己的子进程输出, 共 4 行泄漏).
|
|
974
|
+
* 门覆盖 `process.stdout.write` / `process.stderr.write` / `console.*` 三层, 且**是单例**
|
|
975
|
+
* (index.ts 里那次 `installStartupLogGate` 会直接复用它) ⇒ 在这里提前装, 行为不变、只是更早生效.
|
|
976
|
+
* 与 index 侧同一套跳过条件: `--json` (stdout 是机器数据本体) / 一次性工具 / 命令式诊断 不装门.
|
|
977
|
+
*/
|
|
978
|
+
{
|
|
979
|
+
const a = args;
|
|
980
|
+
const isOneShotTool = !!(a.tool || a.prompt);
|
|
981
|
+
const isCommandLike = !!(a.supervise || a.setupStatus || a.setupResume || a.setupRepair
|
|
982
|
+
|| a.setupReconfigure || a.setupTest);
|
|
983
|
+
if (!a.json && !isOneShotTool && !isCommandLike) {
|
|
984
|
+
installStartupLogGate({ mode: 'cli-interactive', args: process.argv.slice(2) });
|
|
985
|
+
}
|
|
986
|
+
}
|
|
987
|
+
// 2026-09-30: 先等真实终端尺寸就位再出第一帧 —— 否则面板会先按兜底 80 列渲染一次,
|
|
988
|
+
// 拿到真尺寸后再渲染一次, 而静态输出覆盖不掉旧内容 ⇒ 顶框被重复打印 + 宽度乱变.
|
|
989
|
+
await waitForTermSize();
|
|
968
990
|
await startCLI(args);
|
|
969
991
|
break;
|
|
970
992
|
case 'engine':
|
|
@@ -108,10 +108,12 @@ export async function autoCompact(history, opts = {}) {
|
|
|
108
108
|
role: 'system',
|
|
109
109
|
content: `[Auto-Compact Summary] ${summary}`,
|
|
110
110
|
};
|
|
111
|
+
// 2026-10-01: **摘要后面紧跟一条"保目标"锚点** ✓ —— 摘要丢目标它还在(详见 buildGoalAnchor ✓)
|
|
112
|
+
const anchor = buildGoalAnchor(toCollapse, remaining);
|
|
111
113
|
return {
|
|
112
|
-
history: [summaryMsg, ...remaining],
|
|
114
|
+
history: [summaryMsg, ...(anchor ? [anchor] : []), ...remaining],
|
|
113
115
|
applied: true,
|
|
114
|
-
detail: `collapsed ${cutTo} messages into 1 summary (cache key: ${key})`,
|
|
116
|
+
detail: `collapsed ${cutTo} messages into 1 summary (cache key: ${key})${anchor ? ' + 保目标锚点' : ''}`,
|
|
115
117
|
};
|
|
116
118
|
}
|
|
117
119
|
catch (err) {
|
|
@@ -142,3 +144,36 @@ export function _resetAutoCompactCacheForTest() {
|
|
|
142
144
|
// 实际缓存由 readCache/writeCache 管理, 这里只暴露接口
|
|
143
145
|
// 测试可以走 fs.rm CACHE_DIR() 清理
|
|
144
146
|
}
|
|
147
|
+
/**
|
|
148
|
+
* **压缩前后"保目标"锚点** (2026-10-01, 用户: 「压缩前后保目标」)。
|
|
149
|
+
* 为什么: auto-compact 会把较早的历史**整段换成一句摘要** ✗ —— 摘要写给"过去发生了什么",
|
|
150
|
+
* 而**当前目标**往往丢在里面 ⇒ 压完模型醒过来半失忆 ⇒ 答非所问 / 重头问 / 改目标 ✓(真机实测 ✓)。
|
|
151
|
+
* 做法: 折叠前从历史里**确定性**抽出三件事(用户要什么 · 已经做到哪 · 下一步 ✓)+ 落成一条 system 消息
|
|
152
|
+
* **紧跟摘要**放回 ⇒ 摘要丢了目标它也还在 ✓。不调模型(便宜 ✓ 可测 ✓)。
|
|
153
|
+
*/
|
|
154
|
+
export function buildGoalAnchor(collapsed, remaining = []) {
|
|
155
|
+
const all = [...collapsed, ...remaining];
|
|
156
|
+
if (!all.length)
|
|
157
|
+
return null;
|
|
158
|
+
const clip = (s, n) => String(s ?? '').replace(/\s+/g, ' ').trim().slice(0, n);
|
|
159
|
+
// ⓐ 用户当前要的(最近一条 user ✓ —— 若在 remaining 里也没关系, 取全局最后一条 ✓)
|
|
160
|
+
const lastUser = [...all].reverse().find((m) => m.role === 'user');
|
|
161
|
+
const ask = lastUser ? clip(String(lastUser.content || ''), 300) : '';
|
|
162
|
+
// ⓑ 已经做到哪: 最近 3 个工具动作(名字 + 结果要点 ✓)
|
|
163
|
+
const tools = all.filter((m) => m.role === 'tool').slice(-3).map((m) => {
|
|
164
|
+
const r = m.toolResult;
|
|
165
|
+
const head = clip(String(r?.error || r?.output || m.content || ''), 80);
|
|
166
|
+
return ` · ${m.tool || 'tool'}: ${head}`;
|
|
167
|
+
});
|
|
168
|
+
// ⓒ 助手最后说的一句话(它的意图/下一步 ✓)
|
|
169
|
+
const lastAssistant = [...all].reverse().find((m) => m.role === 'assistant' && String(m.content || '').trim());
|
|
170
|
+
const said = lastAssistant ? clip(String(lastAssistant.content || ''), 200) : '';
|
|
171
|
+
const body = [
|
|
172
|
+
'【压缩前的现场 · 别丢】',
|
|
173
|
+
ask ? `用户当前要的: ${ask}` : '用户当前要的: (未捕捉到 —— 若不确定, 先按最近的目标继续, 别改题)',
|
|
174
|
+
tools.length ? `已经做过:\n${tools.join('\n')}` : '',
|
|
175
|
+
said ? `我上一步说的是: ${said}` : '',
|
|
176
|
+
'下一步: 接着把上面这件事**做完** —— 不要重头问、不要换目标、不要重复已完成的步骤。',
|
|
177
|
+
].filter(Boolean).join('\n');
|
|
178
|
+
return { role: 'system', content: body };
|
|
179
|
+
}
|
|
@@ -53,6 +53,8 @@ exports.AgentIdentityStore = void 0;
|
|
|
53
53
|
exports.channelsPaths = channelsPaths;
|
|
54
54
|
exports.activeChannelFile = activeChannelFile;
|
|
55
55
|
exports.getIdentityStore = getIdentityStore;
|
|
56
|
+
exports.resetIdentityStoreSingletons = resetIdentityStoreSingletons;
|
|
57
|
+
exports.assertTestWriteTarget = assertTestWriteTarget;
|
|
56
58
|
const fs = __importStar(require("fs/promises"));
|
|
57
59
|
const path = __importStar(require("path"));
|
|
58
60
|
const HOME = () => process.env.HOME || '/tmp';
|
|
@@ -202,11 +204,47 @@ class AgentIdentityStore {
|
|
|
202
204
|
}
|
|
203
205
|
}
|
|
204
206
|
exports.AgentIdentityStore = AgentIdentityStore;
|
|
205
|
-
|
|
206
|
-
|
|
207
|
+
// 2026-10-01 (数据事故修复): 单例**按 home 分桶**, 不再把 HOME 绑死在一个实例上。
|
|
208
|
+
//
|
|
209
|
+
// 事故经过 (真事, 用户丢了 4 个智能体): 测试 `channel-not-found.test.ts` 设了隔离 HOME
|
|
210
|
+
// (process.env.HOME = TMP_HOME), 但 vitest 复用 worker —— 同 worker 里**别的测试先**碰过
|
|
211
|
+
// getIdentityStore() ⇒ 单例已按**真实** HOME 构造 ⇒ 该测试的夹具 channel
|
|
212
|
+
// ("real test msg"/"test-agent") 直接写进真实的 ~/.bolloon/sessions/channels.json,
|
|
213
|
+
// 而且是**整表覆盖** ⇒ 用户 4 个 channel 只剩 1 条。
|
|
214
|
+
// 根因就是这里: `new AgentIdentityStore()` 的默认参数 `home = HOME()` 只在**构造那一刻**取值,
|
|
215
|
+
// 之后 process.env.HOME 再怎么变都影响不到它。
|
|
216
|
+
const _storesByHome = new Map();
|
|
217
|
+
/** 单例 (CLI / server 共用, **按当前 HOME 分桶**; 改过 HOME 的测试会自然拿到自己的实例) */
|
|
207
218
|
function getIdentityStore() {
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
219
|
+
const home = HOME();
|
|
220
|
+
let st = _storesByHome.get(home);
|
|
221
|
+
if (!st) {
|
|
222
|
+
st = new AgentIdentityStore(home);
|
|
223
|
+
_storesByHome.set(home, st);
|
|
224
|
+
}
|
|
225
|
+
return st;
|
|
226
|
+
}
|
|
227
|
+
/** 仅供测试: 丢弃所有缓存实例 (改完 HOME 后强制重建) */
|
|
228
|
+
function resetIdentityStoreSingletons() {
|
|
229
|
+
_storesByHome.clear();
|
|
230
|
+
}
|
|
231
|
+
/**
|
|
232
|
+
* 测试期写盘硬保护 (2026-10-01, 数据事故后的第二道闸)。
|
|
233
|
+
*
|
|
234
|
+
* 事故: 测试夹具把用户的真实 channels.json 整表覆盖 (4 个智能体只剩 1 条)。
|
|
235
|
+
* 第一道修的是根因 (单例按 HOME 分桶); 这道是**兜底**: 只要进程带着测试标志,
|
|
236
|
+
* 就**只允许**写临时目录下的数据 —— 真实 HOME (~/.bolloon) 一律拒绝并抛错。
|
|
237
|
+
* 宁可让测试红, 也不能再动用户的数据。
|
|
238
|
+
*/
|
|
239
|
+
function assertTestWriteTarget(home, what = '数据') {
|
|
240
|
+
const isTest = !!process.env.VITEST || process.env.NODE_ENV === 'test';
|
|
241
|
+
if (!isTest)
|
|
242
|
+
return;
|
|
243
|
+
const h = String(home || '').replace(/\/+$/, '');
|
|
244
|
+
const tmpLike = h.startsWith('/tmp/') || h.startsWith('/var/folders/') || h.startsWith('/private/var/folders/') || /bolloon[-_].*test/i.test(h);
|
|
245
|
+
if (!tmpLike) {
|
|
246
|
+
throw new Error(`[test-guard] 测试进程拒绝写非临时目录的${what}: ${h} —— ` +
|
|
247
|
+
`真实数据目录只能在正常 CLI/服务进程中写 (这道闸就是为防上次"夹具覆盖真实 channels.json"的事故)`);
|
|
248
|
+
}
|
|
211
249
|
}
|
|
212
250
|
//# sourceMappingURL=agent-identity-store.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"agent-identity-store.js","sourceRoot":"","sources":["../../../src/agents/agent-identity-store.ts"],"names":[],"mappings":";AAAA;;;;;;;;;;;;;;;GAeG
|
|
1
|
+
{"version":3,"file":"agent-identity-store.js","sourceRoot":"","sources":["../../../src/agents/agent-identity-store.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,138 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
exports.DELEGATE_ENV_MARK = void 0;
|
|
7
|
+
exports.noticesPath = noticesPath;
|
|
8
|
+
exports.collectDelegateNotices = collectDelegateNotices;
|
|
9
|
+
exports.renderDelegateNotices = renderDelegateNotices;
|
|
10
|
+
exports.noticesQueuePath = noticesQueuePath;
|
|
11
|
+
exports.pushNotice = pushNotice;
|
|
12
|
+
exports.drainNotices = drainNotices;
|
|
13
|
+
exports.renderNoticeBlock = renderNoticeBlock;
|
|
14
|
+
/**
|
|
15
|
+
* 后台委派的结果回灌 (2026-10-01, 用户: 「开展子智能体后,bolloon 没有回归」+「还是卡住了,学 hermes」)。
|
|
16
|
+
*
|
|
17
|
+
* 学的是"**起完就走, 结果自己回来**"这个形态:
|
|
18
|
+
* 起委派 ⇒ 立刻返回(带 session id ✓) ⇒ 父智能体继续干别的 ✓ ⇒ 它跑完后, 结果作为**一行提示**注入下一轮 ✓。
|
|
19
|
+
* 判据性质: 只对"我起的后台委派"发提示(命令里带标记 ✓) · **同一条只提示一次**(落盘记号 ✓) · 未跑完/已提示过 ⇒ 不提 ✓。
|
|
20
|
+
*/
|
|
21
|
+
const node_fs_1 = __importDefault(require("node:fs"));
|
|
22
|
+
const node_os_1 = __importDefault(require("node:os"));
|
|
23
|
+
const node_path_1 = __importDefault(require("node:path"));
|
|
24
|
+
const process_runner_js_1 = require("./process-runner.js");
|
|
25
|
+
/** 起后台委派时在命令前加的环境标记 ⇒ 便于识别"这是我起的委派" */
|
|
26
|
+
exports.DELEGATE_ENV_MARK = 'BOLLOON_DELEGATE=1';
|
|
27
|
+
function noticesPath(home = node_os_1.default.homedir()) {
|
|
28
|
+
return node_path_1.default.join(home, '.bolloon', 'delegate-notices.json');
|
|
29
|
+
}
|
|
30
|
+
function loadNoticed(home) {
|
|
31
|
+
try {
|
|
32
|
+
const raw = node_fs_1.default.readFileSync(noticesPath(home), 'utf-8');
|
|
33
|
+
const obj = JSON.parse(raw);
|
|
34
|
+
return obj && typeof obj === 'object' ? obj : {};
|
|
35
|
+
}
|
|
36
|
+
catch {
|
|
37
|
+
return {};
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
function saveNoticed(map, home) {
|
|
41
|
+
try {
|
|
42
|
+
const p = noticesPath(home);
|
|
43
|
+
node_fs_1.default.mkdirSync(node_path_1.default.dirname(p), { recursive: true });
|
|
44
|
+
node_fs_1.default.writeFileSync(p, JSON.stringify(map), { mode: 0o600 });
|
|
45
|
+
}
|
|
46
|
+
catch {
|
|
47
|
+
/* best-effort: 提示记不下来最多重复一次, 不该打断主流程 */
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
/** 收集"已完成、且还没提示过"的后台委派, 每个一条中文提示; 同时落盘记号(只提示一次 ✓) */
|
|
51
|
+
function collectDelegateNotices(home,
|
|
52
|
+
/** 便于门注入假 session(默认读真实的 ✓) */
|
|
53
|
+
injected) {
|
|
54
|
+
let sessions = [];
|
|
55
|
+
if (injected)
|
|
56
|
+
sessions = injected;
|
|
57
|
+
else {
|
|
58
|
+
try {
|
|
59
|
+
sessions = (0, process_runner_js_1.listSessions)();
|
|
60
|
+
}
|
|
61
|
+
catch {
|
|
62
|
+
return [];
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
const noticed = loadNoticed(home);
|
|
66
|
+
const lines = [];
|
|
67
|
+
let changed = false;
|
|
68
|
+
for (const s of sessions) {
|
|
69
|
+
if (!String(s.cmd || '').includes(exports.DELEGATE_ENV_MARK))
|
|
70
|
+
continue; // 只认我起的委派
|
|
71
|
+
if (s.status === 'running')
|
|
72
|
+
continue; // 还没跑完 ⇒ 不提
|
|
73
|
+
if (noticed[s.id])
|
|
74
|
+
continue; // 提过 ⇒ 不提
|
|
75
|
+
const how = s.status === 'exited' ? `退出码 ${s.exitCode ?? 0}` : `状态 ${s.status}`;
|
|
76
|
+
lines.push(`[后台委派完成] session ${s.id} · ${how} —— 结果用 \`process poll ${s.id}\` 取; 若已达成目标就继续下一步, 别重发同样的委派。`);
|
|
77
|
+
noticed[s.id] = Date.now();
|
|
78
|
+
changed = true;
|
|
79
|
+
}
|
|
80
|
+
if (changed)
|
|
81
|
+
saveNoticed(noticed, home);
|
|
82
|
+
return lines;
|
|
83
|
+
}
|
|
84
|
+
/** 拼成一段(没有就返回空串 ✓) */
|
|
85
|
+
function renderDelegateNotices(home) {
|
|
86
|
+
const lines = collectDelegateNotices(home);
|
|
87
|
+
return lines.length ? lines.join('\n') : '';
|
|
88
|
+
}
|
|
89
|
+
function noticesQueuePath(home = node_os_1.default.homedir()) {
|
|
90
|
+
return node_path_1.default.join(home, '.bolloon', 'notices-queue.jsonl');
|
|
91
|
+
}
|
|
92
|
+
/** 投递一条(后台线程/异步回调都能安全调 ✓; 失败只吞不抛 ✓) */
|
|
93
|
+
function pushNotice(kind, text, home = node_os_1.default.homedir()) {
|
|
94
|
+
try {
|
|
95
|
+
const p = noticesQueuePath(home);
|
|
96
|
+
node_fs_1.default.mkdirSync(node_path_1.default.dirname(p), { recursive: true });
|
|
97
|
+
node_fs_1.default.appendFileSync(p, JSON.stringify({ kind, text, at: Date.now() }) + '\n');
|
|
98
|
+
}
|
|
99
|
+
catch { /* 丢一条提示不该打断主流程 */ }
|
|
100
|
+
}
|
|
101
|
+
/** 空闲时排空(读走即清空 ✓): 返回"上一轮之后攒下的"通知, 供本轮开头一次性交代 ✓ */
|
|
102
|
+
function drainNotices(home = node_os_1.default.homedir()) {
|
|
103
|
+
const p = noticesQueuePath(home);
|
|
104
|
+
let raw = '';
|
|
105
|
+
try {
|
|
106
|
+
raw = node_fs_1.default.readFileSync(p, 'utf-8');
|
|
107
|
+
}
|
|
108
|
+
catch {
|
|
109
|
+
return [];
|
|
110
|
+
}
|
|
111
|
+
const out = [];
|
|
112
|
+
for (const line of raw.split('\n')) {
|
|
113
|
+
if (!line.trim())
|
|
114
|
+
continue;
|
|
115
|
+
try {
|
|
116
|
+
const o = JSON.parse(line);
|
|
117
|
+
if (o && typeof o.text === 'string' && (o.kind === 'delegate' || o.kind === 'review'))
|
|
118
|
+
out.push(o);
|
|
119
|
+
}
|
|
120
|
+
catch { /* 坏行跳过 */ }
|
|
121
|
+
}
|
|
122
|
+
try {
|
|
123
|
+
node_fs_1.default.writeFileSync(p, '', { mode: 0o600 });
|
|
124
|
+
}
|
|
125
|
+
catch { /* 清空失败 ⇒ 下轮可能重复一次, 可接受 */ }
|
|
126
|
+
return out;
|
|
127
|
+
}
|
|
128
|
+
/** 拼成一段"任务源块"(自包含 ✓: 说明是什么 + 现在该做什么 + 别重复) */
|
|
129
|
+
function renderNoticeBlock(home = node_os_1.default.homedir()) {
|
|
130
|
+
const items = drainNotices(home);
|
|
131
|
+
if (!items.length)
|
|
132
|
+
return '';
|
|
133
|
+
const lines = items.map((n) => n.kind === 'review'
|
|
134
|
+
? `- [复盘产出] ${n.text}\n ⇒ 若它意味着要**改代码/改技能**, 现在就把这一步做掉(别只记下来); 若只是知识, 说明它已入库即可。`
|
|
135
|
+
: `- [后台任务完成] ${n.text}`);
|
|
136
|
+
return `【后台回流 · 这是新一轮】上一轮之后攒下 ${items.length} 条, 请在本轮一并处理:\n${lines.join('\n')}`;
|
|
137
|
+
}
|
|
138
|
+
//# sourceMappingURL=background-notices.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"background-notices.js","sourceRoot":"","sources":["../../../src/agents/background-notices.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
exports.isUsableDid = isUsableDid;
|
|
7
|
+
exports.channelIdentityUsable = channelIdentityUsable;
|
|
8
|
+
exports.agentPersonaName = agentPersonaName;
|
|
9
|
+
exports.nameForChannel = nameForChannel;
|
|
10
|
+
/**
|
|
11
|
+
* 每个 channel 的**自己的**身份 (2026-10-01)。
|
|
12
|
+
*
|
|
13
|
+
* 用户实测: 两个不同 channel (agent_18cece3f / test-agent) 都答「我叫小龙」, 且 get_identity 返回
|
|
14
|
+
* `DID: `(空) —— 症状是"读身份的还有问题"。
|
|
15
|
+
* 根因: index.ts 组装 identityDoc 时, 只有 channel 记录**同时**有 did 和 publicKey 才用它,
|
|
16
|
+
* 否则落到 `agentIdentity`(进程级**共享**的一个) ⇒ 多个 channel 共用一个身份 ✗;
|
|
17
|
+
* 而 channel 记录里还可能存着假 DID (`did:local:…`) ✗, 或干脆没 did (测试夹具建的) ✗。
|
|
18
|
+
* 规矩: 身份归属**以 channel 的 agentId 为准** —— 每个 agent 用自己的真 did:key (落盘密钥),
|
|
19
|
+
* 名字优先用该 agent 自己的 persona.json, 其次渠道名 (渠道名天然各不相同)。
|
|
20
|
+
*/
|
|
21
|
+
const node_fs_1 = __importDefault(require("node:fs"));
|
|
22
|
+
const node_path_1 = __importDefault(require("node:path"));
|
|
23
|
+
const node_os_1 = __importDefault(require("node:os"));
|
|
24
|
+
/** 假的/垃圾 DID: 不该被当成身份用 (老代码自造过 did:local: / did:pi:) */
|
|
25
|
+
function isUsableDid(did) {
|
|
26
|
+
const s = String(did ?? '').trim();
|
|
27
|
+
if (!s)
|
|
28
|
+
return false;
|
|
29
|
+
return !/^did:(local|pi):/i.test(s);
|
|
30
|
+
}
|
|
31
|
+
/** channel 记录里的身份够不够用 (did 真 + 有公钥) */
|
|
32
|
+
function channelIdentityUsable(ch) {
|
|
33
|
+
return !!ch && isUsableDid(ch.did) && !!ch.publicKey;
|
|
34
|
+
}
|
|
35
|
+
/** 该 agent 自己的 persona.json 里的名字 (没有就 undefined) */
|
|
36
|
+
function agentPersonaName(agentId, home = node_os_1.default.homedir()) {
|
|
37
|
+
const id = String(agentId || '').trim();
|
|
38
|
+
if (!id)
|
|
39
|
+
return undefined;
|
|
40
|
+
const safe = id.replace(/[^a-zA-Z0-9._-]/g, '_');
|
|
41
|
+
try {
|
|
42
|
+
const p = node_path_1.default.join(home, '.bolloon', 'persona', safe, 'persona.json');
|
|
43
|
+
const j = JSON.parse(node_fs_1.default.readFileSync(p, 'utf-8'));
|
|
44
|
+
const n = String(j?.name ?? '').trim();
|
|
45
|
+
return n || undefined;
|
|
46
|
+
}
|
|
47
|
+
catch {
|
|
48
|
+
return undefined;
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
/**
|
|
52
|
+
* channel 应该显示/使用什么名字。
|
|
53
|
+
* 顺序: 该 agent 的 persona.json → channel 记录里的 persona.name → channel 名 → agentId
|
|
54
|
+
* **绝不**回落到"某个全局身份的名字" —— 那正是"两个 channel 一个名"的来源。
|
|
55
|
+
*/
|
|
56
|
+
function nameForChannel(ch, agentId, home = node_os_1.default.homedir()) {
|
|
57
|
+
const id = String(agentId || ch?.agentId || '').trim();
|
|
58
|
+
return ((id ? agentPersonaName(id, home) : undefined) ||
|
|
59
|
+
String(ch?.persona?.name ?? '').trim() ||
|
|
60
|
+
String(ch?.name ?? '').trim() ||
|
|
61
|
+
id ||
|
|
62
|
+
'agent');
|
|
63
|
+
}
|
|
64
|
+
//# sourceMappingURL=channel-identity.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"channel-identity.js","sourceRoot":"","sources":["../../../src/agents/channel-identity.ts"],"names":[],"mappings":";;;;;;;;;AAAA;;;;;;;;;;GAUG;AACH,sDAAyB;AACzB,0DAA6B;AAC7B,sDAAyB;AAEzB,wDAAwD;AACxD,qBAA4B,GAAY;IACtC,MAAM,CAAC,GAAG,MAAM,CAAC,GAAG,IAAI,EAAE,CAAC,CAAC,IAAI,EAAE,CAAC;IACnC,IAAI,CAAC,CAAC;QAAE,OAAO,KAAK,CAAC;IACrB,OAAO,CAAC,mBAAmB,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;AACtC,CAAC;AAED,uCAAuC;AACvC,+BAAsC,EAA2D;IAC/F,OAAO,CAAC,CAAC,EAAE,IAAI,WAAW,CAAC,EAAE,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC,EAAE,CAAC,SAAS,CAAC;AACvD,CAAC;AAED,oDAAoD;AACpD,0BAAiC,OAAe,EAAE,IAAI,GAAG,iBAAE,CAAC,OAAO,EAAE;IACnE,MAAM,EAAE,GAAG,MAAM,CAAC,OAAO,IAAI,EAAE,CAAC,CAAC,IAAI,EAAE,CAAC;IACxC,IAAI,CAAC,EAAE;QAAE,OAAO,SAAS,CAAC;IAC1B,MAAM,IAAI,GAAG,EAAE,CAAC,OAAO,CAAC,kBAAkB,EAAE,GAAG,CAAC,CAAC;IACjD,IAAI,CAAC;QACH,MAAM,CAAC,GAAG,mBAAI,CAAC,IAAI,CAAC,IAAI,EAAE,UAAU,EAAE,SAAS,EAAE,IAAI,EAAE,cAAc,CAAC,CAAC;QACvE,MAAM,CAAC,GAAG,IAAI,CAAC,KAAK,CAAC,iBAAE,CAAC,YAAY,CAAC,CAAC,EAAE,OAAO,CAAC,CAAC,CAAC;QAClD,MAAM,CAAC,GAAG,MAAM,CAAC,CAAC,EAAE,IAAI,IAAI,EAAE,CAAC,CAAC,IAAI,EAAE,CAAC;QACvC,OAAO,CAAC,IAAI,SAAS,CAAC;IACxB,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,SAAS,CAAC;IACnB,CAAC;AACH,CAAC;AAED;;;;GAIG;AACH,wBACE,EAAuF,EACvF,OAAgB,EAChB,IAAI,GAAG,iBAAE,CAAC,OAAO,EAAE;IAEnB,MAAM,EAAE,GAAG,MAAM,CAAC,OAAO,IAAI,EAAE,EAAE,OAAO,IAAI,EAAE,CAAC,CAAC,IAAI,EAAE,CAAC;IACvD,OAAO,CACL,CAAC,EAAE,CAAC,CAAC,CAAC,gBAAgB,CAAC,EAAE,EAAE,IAAI,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC;QAC7C,MAAM,CAAC,EAAE,EAAE,OAAO,EAAE,IAAI,IAAI,EAAE,CAAC,CAAC,IAAI,EAAE;QACtC,MAAM,CAAC,EAAE,EAAE,IAAI,IAAI,EAAE,CAAC,CAAC,IAAI,EAAE;QAC7B,EAAE;QACF,OAAO,CACR,CAAC;AACJ,CAAC"}
|