@bolloon/bolloon-agent 0.6.2 → 0.6.3
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/gateway-group.js +172 -4
- package/dist/agents/group-autopilot.js +29 -1
- package/dist/agents/pi-sdk-tools.js +22 -2
- package/dist/agents/pi-sdk.js +8 -1
- package/dist/cli/mention-data.js +1 -1
- package/dist/cli/model-selector.js +84 -104
- package/dist/cli/setup-wizard.js +2 -10
- package/dist/cli/tui-select.js +99 -10
- package/dist/cli-entry.js +1 -9
- package/dist/electron-build/agents/gateway-group.js +177 -3
- package/dist/electron-build/agents/gateway-group.js.map +1 -1
- package/dist/electron-build/agents/group-autopilot.js +30 -2
- package/dist/electron-build/agents/group-autopilot.js.map +1 -1
- package/dist/electron-build/agents/pi-sdk-tools.js +21 -1
- package/dist/electron-build/agents/pi-sdk-tools.js.map +1 -1
- package/dist/electron-build/agents/pi-sdk.js +8 -1
- package/dist/electron-build/agents/pi-sdk.js.map +1 -1
- package/dist/electron-build/llm/config-store.js +2 -2
- package/dist/electron-build/llm/config-store.js.map +1 -1
- package/dist/electron-build/llm/model-selection.js +16 -2
- package/dist/electron-build/llm/model-selection.js.map +1 -1
- package/dist/electron-build/llm/pi-ai.js +2 -2
- package/dist/electron-build/llm/pi-ai.js.map +1 -1
- package/dist/index.js +121 -3
- package/dist/ios/bolloon-web.json +3 -3
- package/dist/ios/sw.js +1 -1
- package/dist/llm/config-store.js +2 -2
- package/dist/llm/model-selection.js +16 -2
- package/dist/llm/pi-ai.js +2 -2
- package/dist/web/bolloon-web.json +3 -3
- package/dist/web/sw.js +1 -1
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -49,7 +49,7 @@ export function parseGroupSub(input) {
|
|
|
49
49
|
// 与 `/channel <序号>` 同一个习惯 ✓ (列表里就带序号)
|
|
50
50
|
if (/^\d+$/.test(head))
|
|
51
51
|
return { sub: 'use', arg: head };
|
|
52
|
-
const known = ['list', 'new', 'join', 'leave', 'use', 'send', 'log', 'members', 'help'];
|
|
52
|
+
const known = ['list', 'new', 'join', 'leave', 'use', 'send', 'log', 'members', 'invite', 'kick', 'link', 'privacy', 'status', 'help'];
|
|
53
53
|
return { sub: known.includes(sub) ? sub : 'help', arg: known.includes(sub) ? arg : rest };
|
|
54
54
|
}
|
|
55
55
|
export const CLI_KNOWN_COMMAND_HEADS = new Set([
|
|
@@ -398,7 +398,7 @@ async function bootstrapIdentity() {
|
|
|
398
398
|
writeOut(` ${reused ? GRAY + '复用 ' : ''}${GRAY}DID:${RESET} ${did}`);
|
|
399
399
|
writeOut(` ${GRAY}名称:${RESET} ${name}`);
|
|
400
400
|
s.step(1, 5, reused ? '复用 DIAP 身份' : '生成 DIAP 身份', 'ok');
|
|
401
|
-
return { keypair: kp, did, name };
|
|
401
|
+
return { keypair: kp, did, name, created: !reused };
|
|
402
402
|
}
|
|
403
403
|
function publishDID(name, kp) {
|
|
404
404
|
// 2026-06-17: 去掉 IPNS 重试机制 — 老逻辑 60s × 10 次 = 10 分钟阻塞,
|
|
@@ -3878,6 +3878,11 @@ async function processInputInner(input, comm) {
|
|
|
3878
3878
|
dim(' /group send <文本> 往当前群发一条');
|
|
3879
3879
|
dim(' /group log [N] 看当前群最近 N 条 (默认 10)');
|
|
3880
3880
|
dim(' /group members 列当前群成员');
|
|
3881
|
+
dim(' /group invite <orbitdbId> 邀请进白名单 (门控群; 重建群地址)');
|
|
3882
|
+
dim(' /group kick <orbitdbId> 踢出白名单 (门控群; 重建群地址)');
|
|
3883
|
+
dim(' /group link 分享当前群链接');
|
|
3884
|
+
dim(' /group privacy on|off 隐私群标记 (默认建群即隐私)');
|
|
3885
|
+
dim(' /group status 群状态: 成员/消息/白名单/门控/隐私');
|
|
3881
3886
|
return;
|
|
3882
3887
|
}
|
|
3883
3888
|
if (sub === 'list') {
|
|
@@ -3983,6 +3988,116 @@ async function processInputInner(input, comm) {
|
|
|
3983
3988
|
dim(ms.length ? ms.join('\n') : '(暂无成员记录)');
|
|
3984
3989
|
return;
|
|
3985
3990
|
}
|
|
3991
|
+
// ── 2026-10-05 (leo): 群运营能力 —— 邀请/踢出/链接/隐私/状态
|
|
3992
|
+
if (sub === 'invite') {
|
|
3993
|
+
const gid = await ensureCurrentGroup(gg);
|
|
3994
|
+
if (!gid)
|
|
3995
|
+
return;
|
|
3996
|
+
const g = await gg.groupInfo(gid);
|
|
3997
|
+
if (!g) {
|
|
3998
|
+
dim('群不存在');
|
|
3999
|
+
return;
|
|
4000
|
+
}
|
|
4001
|
+
if (!g.gated) {
|
|
4002
|
+
appendLine(`${C_DIM}「${g.name}」是开放群 (write:[*]) —— 邀请 = 把链接发给对方自行加入:${RESET}\n${C_ACCENT}${g.link}${RESET}`);
|
|
4003
|
+
return;
|
|
4004
|
+
}
|
|
4005
|
+
if (!arg) {
|
|
4006
|
+
dim('用法: /group invite <orbitdbId> (门控群: 把对方加进白名单, 会重建群地址)');
|
|
4007
|
+
return;
|
|
4008
|
+
}
|
|
4009
|
+
const ref = {
|
|
4010
|
+
did: arg.startsWith('did:') ? arg : `did:key:z${arg.slice(0, 40)}`,
|
|
4011
|
+
publicKeyHex: '',
|
|
4012
|
+
orbitdbId: arg.startsWith('did:') ? (await gg.groupMembers(gid).catch(() => [])).find((m) => m === arg) || arg : arg,
|
|
4013
|
+
};
|
|
4014
|
+
const r = await gg.inviteMember(gid, ref);
|
|
4015
|
+
if (!r.ok) {
|
|
4016
|
+
appendLine(`${C_WARN}邀请失败: ${r.error}${RESET}`);
|
|
4017
|
+
return;
|
|
4018
|
+
}
|
|
4019
|
+
appendLine(renderMessageBox({
|
|
4020
|
+
title: `✅ 已邀请进白名单: ${r.group?.name}`,
|
|
4021
|
+
body: `新地址: ${r.group?.link}\n\n⚠ 重建代价 (IPFS 白名单不能就地改):\n${(r.costs || []).slice(0, 3).map((c) => `· ${c}`).join('\n')}\n\n把新链接发给对方, 用 /group join <链接> 加入 (老链接作废)`,
|
|
4022
|
+
color: C_ACCENT, maxLines: 12,
|
|
4023
|
+
}));
|
|
4024
|
+
currentGroupId = r.group?.id || currentGroupId;
|
|
4025
|
+
return;
|
|
4026
|
+
}
|
|
4027
|
+
if (sub === 'kick') {
|
|
4028
|
+
const gid = await ensureCurrentGroup(gg);
|
|
4029
|
+
if (!gid)
|
|
4030
|
+
return;
|
|
4031
|
+
const g = await gg.groupInfo(gid);
|
|
4032
|
+
if (!g) {
|
|
4033
|
+
dim('群不存在');
|
|
4034
|
+
return;
|
|
4035
|
+
}
|
|
4036
|
+
if (!g.gated) {
|
|
4037
|
+
dim('「' + g.name + '」是开放群 (write:[*]), 没有踢人语义 (人人可写)');
|
|
4038
|
+
return;
|
|
4039
|
+
}
|
|
4040
|
+
if (!arg) {
|
|
4041
|
+
dim('用法: /group kick <orbitdbId> (从白名单移除; 重建群地址)');
|
|
4042
|
+
return;
|
|
4043
|
+
}
|
|
4044
|
+
const r = await gg.kickMember(gid, arg);
|
|
4045
|
+
if (!r.ok) {
|
|
4046
|
+
appendLine(`${C_WARN}踢出失败: ${r.error}${RESET}`);
|
|
4047
|
+
return;
|
|
4048
|
+
}
|
|
4049
|
+
appendLine(renderMessageBox({
|
|
4050
|
+
title: `✅ 已移出白名单: ${r.group?.name}`,
|
|
4051
|
+
body: `新地址: ${r.group?.link}\n\n⚠ 重建代价:\n${(r.costs || []).slice(0, 3).map((c) => `· ${c}`).join('\n')}\n\n被踢者老链接作废; 其他成员要用新链接重新加入`,
|
|
4052
|
+
color: C_ACCENT, maxLines: 12,
|
|
4053
|
+
}));
|
|
4054
|
+
currentGroupId = r.group?.id || currentGroupId;
|
|
4055
|
+
return;
|
|
4056
|
+
}
|
|
4057
|
+
if (sub === 'link') {
|
|
4058
|
+
const gid = await ensureCurrentGroup(gg);
|
|
4059
|
+
if (!gid)
|
|
4060
|
+
return;
|
|
4061
|
+
const g = await gg.groupInfo(gid);
|
|
4062
|
+
if (!g) {
|
|
4063
|
+
dim('群不存在');
|
|
4064
|
+
return;
|
|
4065
|
+
}
|
|
4066
|
+
appendLine(renderMessageBox({ title: `群链接: ${g.name}`, body: `${g.link}\n\n复制发给同伴, 用 /group join <链接> 加入`, color: C_ACCENT, maxLines: 8 }));
|
|
4067
|
+
return;
|
|
4068
|
+
}
|
|
4069
|
+
if (sub === 'privacy') {
|
|
4070
|
+
const gid = await ensureCurrentGroup(gg);
|
|
4071
|
+
if (!gid)
|
|
4072
|
+
return;
|
|
4073
|
+
const on = arg === 'on' || arg === 'true' || arg === '1';
|
|
4074
|
+
const off = arg === 'off' || arg === 'false' || arg === '0';
|
|
4075
|
+
if (!on && !off) {
|
|
4076
|
+
dim('用法: /group privacy on|off (隐私群标记, 只影响本机展示/默认 ACL 说明)');
|
|
4077
|
+
return;
|
|
4078
|
+
}
|
|
4079
|
+
const r = await gg.setGroupPrivacy(gid, on);
|
|
4080
|
+
appendLine(r.ok ? `${C_ACCENT}✓ 隐私群 ${on ? '开启' : '关闭'}: ${r.group?.name}${RESET}${C_DIM} (白名单/ACL 由建群时决定, 本标记只做展示)${RESET}` : `${C_WARN}设置失败: ${r.error}${RESET}`);
|
|
4081
|
+
return;
|
|
4082
|
+
}
|
|
4083
|
+
if (sub === 'status') {
|
|
4084
|
+
const gid = await ensureCurrentGroup(gg);
|
|
4085
|
+
if (!gid)
|
|
4086
|
+
return;
|
|
4087
|
+
const s = await gg.groupStatus(gid);
|
|
4088
|
+
if (!s.ok || !s.status) {
|
|
4089
|
+
appendLine(`${C_WARN}${s.error}${RESET}`);
|
|
4090
|
+
return;
|
|
4091
|
+
}
|
|
4092
|
+
const st = s.status;
|
|
4093
|
+
const wl = st.writeList.slice(0, 12).join('\n ');
|
|
4094
|
+
appendLine(renderMessageBox({
|
|
4095
|
+
title: `群状态: ${st.group.name}`,
|
|
4096
|
+
body: `隐私: ${st.privacy ? '🔒 是' : '公开'} · 门控: ${st.gated ? '是' : '否'} · 成员: ${st.memberCount} · 消息: ${st.messageCount}\n最后同步: ${st.lastSyncAt || '-'}\n群主: ${st.ownerDid ? String(st.ownerDid).slice(0, 32) + '…' : '-'}\n\n写白名单 (${st.writeList.length}):\n ${wl || '(无)'}`,
|
|
4097
|
+
color: C_ACCENT, maxLines: 20,
|
|
4098
|
+
}));
|
|
4099
|
+
return;
|
|
4100
|
+
}
|
|
3986
4101
|
dim('用法: /group help');
|
|
3987
4102
|
}
|
|
3988
4103
|
catch (e) {
|
|
@@ -6135,7 +6250,7 @@ async function main() {
|
|
|
6135
6250
|
s.warn('未设置任何 LLM API Key,功能受限');
|
|
6136
6251
|
}
|
|
6137
6252
|
}
|
|
6138
|
-
const { keypair, did, name } = await bootstrapIdentity();
|
|
6253
|
+
const { keypair, did, name, created } = await bootstrapIdentity();
|
|
6139
6254
|
agentIdentity = { did, name, publicKey: Buffer.from(keypair.publicKey).toString('hex') };
|
|
6140
6255
|
// 2026-08-07: CLI 模式后台自动安装/启动本地 Kubo (web 模式 server.ts 已有, CLI 缺 → IPNS 发布后无法解析的根因)
|
|
6141
6256
|
// fire-and-forget, 不阻塞启动; Kubo 就绪后才发布 DID (避免 registerAgent 在 Kubo 未启动时 30s 超时)
|
|
@@ -6161,6 +6276,9 @@ async function main() {
|
|
|
6161
6276
|
catch (e) {
|
|
6162
6277
|
bootNotice('warn', `Kubo 自动安装失败 (非致命): ${String(e?.message || e).slice(0, 120)}`);
|
|
6163
6278
|
}
|
|
6279
|
+
// DID 已存在时不重复发布;只有首次创建或显式要求刷新才发布。
|
|
6280
|
+
if (!created && process.env.BOLLOON_REFRESH_DID !== '1')
|
|
6281
|
+
return;
|
|
6164
6282
|
publishDID(name, keypair).then(({ cid, ipnsName }) => {
|
|
6165
6283
|
if (cid)
|
|
6166
6284
|
agentIdentity.cid = cid;
|
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
{
|
|
2
2
|
"schema": "bolloon-mobile-web/1",
|
|
3
|
-
"version": "0.6.
|
|
3
|
+
"version": "0.6.3",
|
|
4
4
|
"channel": "stable",
|
|
5
5
|
"build": "stable",
|
|
6
|
-
"commit": "
|
|
7
|
-
"builtAt": "2026-10-
|
|
6
|
+
"commit": "eb3ebe6fed23cb70e901ac8da92e6420bc0673ad",
|
|
7
|
+
"builtAt": "2026-10-05T06:19:40.124Z",
|
|
8
8
|
"layer": "web",
|
|
9
9
|
"note": "web 资源层构建戳 (手机端 OTA 的身份第 ③ 级回退; 装机后以 OTA state.json 为准)"
|
|
10
10
|
}
|
package/dist/ios/sw.js
CHANGED
|
@@ -6,7 +6,7 @@
|
|
|
6
6
|
* 现在: 代码类资源 (html/js/css/json) 一律 **network-first** (拿不到网才回退缓存),
|
|
7
7
|
* 缓存名带版本号, activate 时清掉所有旧缓存; 图标等静态资源仍 cache-first。
|
|
8
8
|
*/
|
|
9
|
-
const CACHE = 'bolloon-mobile-v0.6.
|
|
9
|
+
const CACHE = 'bolloon-mobile-v0.6.3';
|
|
10
10
|
const SHELL = [
|
|
11
11
|
'./mobile.html',
|
|
12
12
|
'./mobile.css',
|
package/dist/llm/config-store.js
CHANGED
|
@@ -161,8 +161,8 @@ export const PROVIDER_INFO = {
|
|
|
161
161
|
// 2026-07-17: V3 系列 (deepseek-chat / deepseek-reasoner) 官方已下线, 改 V4
|
|
162
162
|
deepseek: { name: 'DeepSeek', description: '深度求索大模型 (V4)', requiresApiKey: true, models: ['deepseek-v4-flash', 'deepseek-v4-pro'] },
|
|
163
163
|
kimi: { name: 'Kimi (月之暗面)', description: 'Moonshot Kimi K 系列模型', requiresApiKey: true, models: ['kimi-k3', 'kimi-k2-0905', 'moonshot-v1-128k', 'moonshot-v1-32k'] },
|
|
164
|
-
glm: { name: 'GLM (智谱)', description: '智谱 GLM 系列模型', requiresApiKey: true, models: ['glm-5.2', 'glm-4.6', 'glm-4.5', 'glm-4-flash', 'glm-4'] },
|
|
165
|
-
qwen: { name: 'Qwen (通义千问)', description: '阿里云通义千问系列', requiresApiKey: true, models: ['qwen3-max', 'qwen-max', 'qwen-plus', 'qwen-turbo'] },
|
|
164
|
+
glm: { name: 'GLM (智谱)', description: '智谱 GLM 系列模型', requiresApiKey: true, models: ['glm-5.3-flash', 'glm-5.3', 'glm-5.2', 'glm-5', 'glm-4.6', 'glm-4.5', 'glm-4.7', 'glm-4-flash', 'glm-4'] },
|
|
165
|
+
qwen: { name: 'Qwen (通义千问)', description: '阿里云通义千问系列', requiresApiKey: true, models: ['qwen3.8-max', 'qwen3-max', 'qwen-max', 'qwen-plus', 'qwen-turbo'] },
|
|
166
166
|
mimo: { name: 'MiMo (小米)', description: '小米 MiMo V2 系列 (openai 兼容)', requiresApiKey: true, models: ['mimo-v2.5-pro', 'mimo-v2-pro', 'mimo-v2-omni', 'mimo-v2-flash', 'mimo-v2.5-pro-ultraspeed'] },
|
|
167
167
|
grok: { name: 'Grok (xAI)', description: 'xAI Grok 系列模型 (openai 兼容)', requiresApiKey: true, models: ['grok-4.5', 'grok-4', 'grok-4-fast'] },
|
|
168
168
|
local: { name: '本地模型', description: '本地部署的模型服务', requiresApiKey: false }
|
|
@@ -763,7 +763,21 @@ export function validateSelection(req, ctx) {
|
|
|
763
763
|
return { ok: false, failureClass: 'invalid_model', message: `${provider} 没有可用模型 (配置为空且默认模型为空)` };
|
|
764
764
|
}
|
|
765
765
|
let baseUrl = base.baseUrl;
|
|
766
|
-
|
|
766
|
+
const urlAction = req.baseUrlAction ?? (req.baseUrl !== undefined ? 'replace' : 'keep');
|
|
767
|
+
if (urlAction === 'clear') {
|
|
768
|
+
// 清除 URL 覆盖 → 回落**官方默认** (内置表/注册表声明的那个, 不含配置里覆盖过的值)。
|
|
769
|
+
// leo 2026-10-05: 「展示的 URL 默认需要官方的来源」—— 清除 = 回到官方, 不是回到上一个手填值。
|
|
770
|
+
const official = baseDefaultsOf(provider, null);
|
|
771
|
+
baseUrl = normalizeBaseUrl(official?.baseUrl || '');
|
|
772
|
+
if (!baseUrl && regEntry && regEntry.origin === 'catalog') {
|
|
773
|
+
return {
|
|
774
|
+
ok: false,
|
|
775
|
+
failureClass: 'invalid_url',
|
|
776
|
+
message: `${provider} 在目录里没有官方 api 基址 → 无法回落官方默认, 必须自定义 baseUrl (加 --base-url <地址> 或写进配置)`,
|
|
777
|
+
};
|
|
778
|
+
}
|
|
779
|
+
}
|
|
780
|
+
else if (req.baseUrl !== undefined) {
|
|
767
781
|
const shape = validateBaseUrlShape(req.baseUrl);
|
|
768
782
|
if (!shape.ok) {
|
|
769
783
|
return { ok: false, failureClass: 'invalid_url', message: `base URL 非法 — ${shape.reason}` };
|
|
@@ -974,7 +988,7 @@ export async function selectModel(req) {
|
|
|
974
988
|
const p = await runConnectionProbe({
|
|
975
989
|
provider: target.provider,
|
|
976
990
|
model: target.model,
|
|
977
|
-
baseUrl:
|
|
991
|
+
baseUrl: target.baseUrl, // 校验已按 URL 意图算好 (keep=当前 / replace=新值 / clear=官方默认)
|
|
978
992
|
configuredBaseUrl: stored?.baseUrl, // 配置里这一家现在写的地址
|
|
979
993
|
apiKey: target.apiKey,
|
|
980
994
|
});
|
package/dist/llm/pi-ai.js
CHANGED
|
@@ -752,7 +752,7 @@ export class PiAIModel {
|
|
|
752
752
|
// 2026-07-17: deepseek-chat (V3) 官方已下线, 迁 deepseek-v4-flash
|
|
753
753
|
deepseek: this.config.model || process.env.DEEPSEEK_MODEL || 'deepseek-v4-flash',
|
|
754
754
|
kimi: this.config.model || process.env.KIMI_MODEL || process.env.MOONSHOT_MODEL || 'kimi-k3',
|
|
755
|
-
glm: this.config.model || process.env.GLM_MODEL || process.env.ZHIPU_MODEL || 'glm-5.
|
|
755
|
+
glm: this.config.model || process.env.GLM_MODEL || process.env.ZHIPU_MODEL || 'glm-5.3-flash',
|
|
756
756
|
qwen: this.config.model || process.env.QWEN_MODEL || process.env.DASHSCOPE_MODEL || 'qwen3-max',
|
|
757
757
|
// 小米 MiMo (openai 兼容) — env override 优先, 默认 mimo-v2.5-pro
|
|
758
758
|
mimo: this.config.model || process.env.MIMO_MODEL || 'mimo-v2.5-pro',
|
|
@@ -1375,7 +1375,7 @@ function detectModel(provider) {
|
|
|
1375
1375
|
// 2026-07-17: V3 官方下线, 迁 V4
|
|
1376
1376
|
deepseek: 'deepseek-v4-flash',
|
|
1377
1377
|
kimi: 'kimi-k3',
|
|
1378
|
-
glm: 'glm-5.
|
|
1378
|
+
glm: 'glm-5.3-flash',
|
|
1379
1379
|
qwen: 'qwen3-max',
|
|
1380
1380
|
// 小米 MiMo 默认走最新旗舰版 (v2.5-Pro); 2026-06 当前公开版
|
|
1381
1381
|
mimo: 'mimo-v2.5-pro',
|
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
{
|
|
2
2
|
"schema": "bolloon-mobile-web/1",
|
|
3
|
-
"version": "0.6.
|
|
3
|
+
"version": "0.6.3",
|
|
4
4
|
"channel": "stable",
|
|
5
5
|
"build": "stable",
|
|
6
|
-
"commit": "
|
|
7
|
-
"builtAt": "2026-10-
|
|
6
|
+
"commit": "eb3ebe6fed23cb70e901ac8da92e6420bc0673ad",
|
|
7
|
+
"builtAt": "2026-10-05T06:24:49.679Z",
|
|
8
8
|
"layer": "web",
|
|
9
9
|
"note": "web 资源层构建戳 (手机端 OTA 的身份第 ③ 级回退; 装机后以 OTA state.json 为准)"
|
|
10
10
|
}
|
package/dist/web/sw.js
CHANGED
|
@@ -6,7 +6,7 @@
|
|
|
6
6
|
* 现在: 代码类资源 (html/js/css/json) 一律 **network-first** (拿不到网才回退缓存),
|
|
7
7
|
* 缓存名带版本号, activate 时清掉所有旧缓存; 图标等静态资源仍 cache-first。
|
|
8
8
|
*/
|
|
9
|
-
const CACHE = 'bolloon-mobile-v0.6.
|
|
9
|
+
const CACHE = 'bolloon-mobile-v0.6.3';
|
|
10
10
|
const SHELL = [
|
|
11
11
|
'./mobile.html',
|
|
12
12
|
'./mobile.css',
|