@bolloon/bolloon-agent 0.6.5 → 0.6.6
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/chain/chain-settlement.js +0 -1
- package/dist/agents/chat-segmenter.js +4 -16
- package/dist/agents/contacts/human-directory.js +155 -0
- package/dist/agents/contacts/tools.js +79 -0
- package/dist/agents/experience-review.js +0 -3
- package/dist/agents/goal-flywheel/goal-change.js +3 -4
- package/dist/agents/goal-resume.js +0 -4
- package/dist/agents/intent-classifier.js +1 -1
- package/dist/agents/iteration-budget.js +12 -0
- package/dist/agents/knowledge-organizer.js +0 -2
- package/dist/agents/lesson-to-skill.js +0 -1
- package/dist/agents/loop-review.js +2 -2
- package/dist/agents/memory-store.js +359 -0
- package/dist/agents/opportunity-web-search.js +39 -0
- package/dist/agents/p2p-chat-tools.js +1 -2
- package/dist/agents/parse-tool-call.js +9 -22
- package/dist/agents/pi-harness.js +1 -2
- package/dist/agents/pi-sdk-tools.js +180 -5
- package/dist/agents/pi-sdk.js +143 -9
- package/dist/agents/process-runner.js +28 -9
- package/dist/agents/react-loop.js +9 -17
- package/dist/agents/runner-resolver.js +4 -3
- package/dist/agents/skill-loader.js +22 -15
- package/dist/agents/skills-manager.js +1 -25
- package/dist/agents/workflow-pivot-loop.js +152 -61
- package/dist/bootstrap/context-collector.js +2 -4
- package/dist/bootstrap/context-hierarchy.js +13 -1
- package/dist/cli/ink-app.js +44 -17
- package/dist/cli/intent-command.js +22 -12
- package/dist/cli/loading-tui.js +8 -2
- package/dist/cli/log-gate.js +40 -8
- package/dist/cli/mention-data.js +1 -0
- package/dist/cli/reply-hygiene.js +22 -0
- package/dist/cli/trace-line.js +61 -2
- package/dist/electron-build/agents/agent-gateway.js.map +1 -1
- package/dist/electron-build/agents/chain/chain-indexer.js.map +1 -1
- package/dist/electron-build/agents/chain/chain-settlement.js +0 -1
- package/dist/electron-build/agents/chain/chain-settlement.js.map +1 -1
- package/dist/electron-build/agents/contacts/chain.js.map +1 -1
- package/dist/electron-build/agents/contacts/human-directory.js +204 -0
- package/dist/electron-build/agents/contacts/human-directory.js.map +1 -0
- package/dist/electron-build/agents/contacts/policy.js.map +1 -1
- package/dist/electron-build/agents/contacts/tools.js +112 -0
- package/dist/electron-build/agents/contacts/tools.js.map +1 -1
- package/dist/electron-build/agents/experience-review.js +0 -3
- package/dist/electron-build/agents/experience-review.js.map +1 -1
- package/dist/electron-build/agents/external-events.js.map +1 -1
- package/dist/electron-build/agents/goal-flywheel/goal-change.js +3 -4
- package/dist/electron-build/agents/goal-flywheel/goal-change.js.map +1 -1
- package/dist/electron-build/agents/goal-flywheel-wiring.js.map +1 -1
- package/dist/electron-build/agents/goal-resume.js +0 -4
- package/dist/electron-build/agents/goal-resume.js.map +1 -1
- package/dist/electron-build/agents/intent-classifier.js +1 -1
- package/dist/electron-build/agents/lesson-to-skill.js +0 -1
- package/dist/electron-build/agents/lesson-to-skill.js.map +1 -1
- package/dist/electron-build/agents/loop-review.js +2 -2
- package/dist/electron-build/agents/loop-review.js.map +1 -1
- package/dist/electron-build/agents/memory-recall.js.map +1 -1
- package/dist/electron-build/agents/memory-store.js +404 -0
- package/dist/electron-build/agents/memory-store.js.map +1 -0
- package/dist/electron-build/agents/parse-tool-call.js +9 -22
- package/dist/electron-build/agents/parse-tool-call.js.map +1 -1
- package/dist/electron-build/agents/pi-harness.js +1 -2
- package/dist/electron-build/agents/pi-harness.js.map +1 -1
- package/dist/electron-build/agents/pi-sdk-tools.js +180 -5
- package/dist/electron-build/agents/pi-sdk-tools.js.map +1 -1
- package/dist/electron-build/agents/pi-sdk.js +143 -9
- package/dist/electron-build/agents/pi-sdk.js.map +1 -1
- package/dist/electron-build/agents/pre-tool-validator.js.map +1 -1
- package/dist/electron-build/agents/process-runner.js +28 -9
- package/dist/electron-build/agents/process-runner.js.map +1 -1
- package/dist/electron-build/agents/runner-resolver.js +4 -3
- package/dist/electron-build/agents/runner-resolver.js.map +1 -1
- package/dist/electron-build/agents/skill-loader.js +22 -16
- package/dist/electron-build/agents/skill-loader.js.map +1 -1
- package/dist/electron-build/agents/skill-supervisor-link.js.map +1 -1
- package/dist/electron-build/agents/skills-manager.js +0 -24
- package/dist/electron-build/agents/skills-manager.js.map +1 -1
- package/dist/electron-build/agents/task/task-runner.js.map +1 -1
- package/dist/electron-build/agents/workflow-engine.js.map +1 -1
- package/dist/electron-build/agents/workflow-pivot-loop.js +155 -62
- package/dist/electron-build/agents/workflow-pivot-loop.js.map +1 -1
- package/dist/electron-build/agents/x402/goal-run-bridge.js.map +1 -1
- package/dist/electron-build/bollharness-integration/gate-state-machine.js.map +1 -1
- package/dist/electron-build/bootstrap/context-collector.js +2 -4
- package/dist/electron-build/bootstrap/context-collector.js.map +1 -1
- package/dist/electron-build/bootstrap/context-hierarchy.js +13 -1
- package/dist/electron-build/bootstrap/context-hierarchy.js.map +1 -1
- package/dist/electron-build/electron-preload.js.map +1 -1
- package/dist/electron-build/external-engines/delegate.js.map +1 -1
- package/dist/electron-build/kernel/channel-actor.js +31 -2
- package/dist/electron-build/kernel/channel-actor.js.map +1 -1
- package/dist/electron-build/kernel/model-runtime.js +8 -1
- package/dist/electron-build/kernel/model-runtime.js.map +1 -1
- package/dist/electron-build/llm/config-store.js +20 -0
- package/dist/electron-build/llm/config-store.js.map +1 -1
- package/dist/electron-build/llm/embedding-adapter.js +75 -0
- package/dist/electron-build/llm/embedding-adapter.js.map +1 -0
- package/dist/electron-build/llm/pi-ai.js +96 -35
- package/dist/electron-build/llm/pi-ai.js.map +1 -1
- package/dist/electron-build/network/agent-network.js.map +1 -1
- package/dist/electron-build/orbitdb/memory-sync.js +76 -0
- package/dist/electron-build/orbitdb/memory-sync.js.map +1 -0
- package/dist/electron-build/pi-ecosystem-judgment/adaptive-scan.js.map +1 -1
- package/dist/electron-build/security/tool-gate.js +2 -0
- package/dist/electron-build/security/tool-gate.js.map +1 -1
- package/dist/electron-build/setup/setup-store.js +34 -6
- package/dist/electron-build/setup/setup-store.js.map +1 -1
- package/dist/electron-build/social/heartbeat.js +18 -5
- package/dist/electron-build/social/heartbeat.js.map +1 -1
- package/dist/electron-build/utils/update-manager.js.map +1 -1
- package/dist/index.js +250 -12
- package/dist/ios/bolloon-web.json +2 -2
- package/dist/ios/client.js +74 -35
- package/dist/ios/icons/icon-1400x1400.png +0 -0
- package/dist/ios/icons/icon-1400x1400.webp +0 -0
- package/dist/ios/index.html +106 -107
- package/dist/ios/mobile-agent.js +346 -45
- package/dist/ios/mobile-core.js +7303 -4590
- package/dist/ios/mobile-harness.js +1004 -0
- package/dist/ios/mobile-orbitdb.js +194 -0
- package/dist/ios/mobile-persona.js +80 -0
- package/dist/ios/mobile-privacy.js +2 -3
- package/dist/ios/mobile.css +286 -21
- package/dist/ios/mobile.html +106 -107
- package/dist/ios/mobile.js +300 -132
- package/dist/ios/routes-world.js +4 -1
- package/dist/ios/server.js +3 -1
- package/dist/ios/style.css +13 -5
- package/dist/ios/ui/message-renderer.js +4 -18
- package/dist/ios/ui/step-timeline.js +14 -1
- package/dist/kernel/channel-actor.js +30 -2
- package/dist/kernel/gate-scan.js +1 -1
- package/dist/kernel/index.js +33 -0
- package/dist/kernel/model-runtime.js +8 -1
- package/dist/kernel/plan.js +3 -3
- package/dist/kernel/roster.js +3 -3
- package/dist/llm/config-store.js +20 -0
- package/dist/llm/embedding-adapter.js +69 -0
- package/dist/llm/pi-ai.js +94 -34
- package/dist/orbitdb/memory-sync.js +70 -0
- package/dist/pi-ecosystem-judgment/adaptive-scan.js +1 -1
- package/dist/security/tool-gate.js +2 -0
- package/dist/setup/setup-store.js +34 -6
- package/dist/social/heartbeat.js +18 -5
- package/dist/web/bolloon-web.json +3 -3
- package/dist/web/client.js +74 -35
- package/dist/web/icons/icon-1400x1400.png +0 -0
- package/dist/web/icons/icon-1400x1400.webp +0 -0
- package/dist/web/index.html +37 -25
- package/dist/web/mobile-agent.js +351 -45
- package/dist/web/mobile-contacts.js +0 -4
- package/dist/web/mobile-core.js +7430 -4590
- package/dist/web/mobile-harness.js +1004 -0
- package/dist/web/mobile-orbitdb.js +194 -0
- package/dist/web/mobile-persona.js +80 -0
- package/dist/web/mobile-privacy.js +2 -3
- package/dist/web/mobile.css +286 -21
- package/dist/web/mobile.html +121 -107
- package/dist/web/mobile.js +409 -136
- package/dist/web/routes-contacts.js +94 -1
- package/dist/web/routes-world.js +4 -1
- package/dist/web/server.js +4 -2
- package/dist/web/style.css +13 -5
- package/dist/web/sw.js +1 -1
- package/dist/web/ui/message-renderer.js +4 -18
- package/dist/web/ui/step-timeline.js +14 -1
- package/package.json +3 -2
- package/scripts/build-web.ts +16 -1
|
@@ -0,0 +1,194 @@
|
|
|
1
|
+
let _orbit = null;
|
|
2
|
+
let _node = null;
|
|
3
|
+
/** 当前 OrbitDB 实例 (null = 未创建) */
|
|
4
|
+
export function getMobileOrbitDB() { return _orbit; }
|
|
5
|
+
/** 当前绑定的 helia 节点 (null = 未创建) */
|
|
6
|
+
export function getMobileOrbitNode() { return _node; }
|
|
7
|
+
/** 测试用: 重置实例 (不 stop 节点, 由调用方管) */
|
|
8
|
+
export function resetMobileOrbitDB() {
|
|
9
|
+
_orbit = null;
|
|
10
|
+
_node = null;
|
|
11
|
+
}
|
|
12
|
+
/**
|
|
13
|
+
* 创建手机端 OrbitDB (幂等)。
|
|
14
|
+
* 需要带 pubsub (gossipsub) 的 helia 节点 —— OrbitDB 4.x 的同步协议靠
|
|
15
|
+
* ipfs.libp2p.services.pubsub.addEventListener/subscribe。
|
|
16
|
+
* 不带 pubsub 的节点 (SDK 默认只启 identify) → open store 会抛
|
|
17
|
+
* "Cannot read properties of undefined (reading 'addEventListener')"。
|
|
18
|
+
* @returns { ok, orbit?, error? }
|
|
19
|
+
*/
|
|
20
|
+
export async function createMobileOrbitDB(node) {
|
|
21
|
+
if (_orbit)
|
|
22
|
+
return { ok: true, orbit: _orbit };
|
|
23
|
+
try {
|
|
24
|
+
const activeNode = node ?? _node ?? null;
|
|
25
|
+
if (!activeNode)
|
|
26
|
+
return { ok: false, error: '需要 helia 节点 (先 startMobileHelia)' };
|
|
27
|
+
_node = activeNode;
|
|
28
|
+
// 动态 import @orbitdb/core (browser bundle; 避免顶层拖慢首屏)
|
|
29
|
+
const orbitMod = await import('@orbitdb/core');
|
|
30
|
+
// @orbitdb/core 的 browser bundle 类型导出不稳定 → 显式收成 any (运行时仍是同一函数)
|
|
31
|
+
const createOrbitDB = orbitMod.default ?? orbitMod.createOrbitDB;
|
|
32
|
+
if (typeof createOrbitDB !== 'function')
|
|
33
|
+
return { ok: false, error: '@orbitdb/core 没有 createOrbitDB 导出' };
|
|
34
|
+
// 用 MemoryStorage (浏览器无 fs) — KeyStore/日志都在内存
|
|
35
|
+
const orbit = await createOrbitDB({
|
|
36
|
+
ipfs: activeNode,
|
|
37
|
+
// 浏览器安全: 全部内存, 不落盘 (真持久化靠 IPFS 网络)
|
|
38
|
+
directory: undefined,
|
|
39
|
+
});
|
|
40
|
+
_orbit = orbit;
|
|
41
|
+
return { ok: true, orbit };
|
|
42
|
+
}
|
|
43
|
+
catch (e) {
|
|
44
|
+
return { ok: false, error: `创建 OrbitDB 失败: ${String(e?.message || e).slice(0, 200)}` };
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
/**
|
|
48
|
+
* 用带 pubsub 的节点创建 OrbitDB。
|
|
49
|
+
* 内部: 若当前节点没有 services.pubsub, 则用 mobile-helia 高级路径 (libp2pOptions + gossipsub)
|
|
50
|
+
* 重建一个, 替换当前节点。返回重建结果。
|
|
51
|
+
*/
|
|
52
|
+
export async function createMobileOrbitDBWithPubsub(heliaMod) {
|
|
53
|
+
try {
|
|
54
|
+
const mh = heliaMod || (await import('./mobile-helia.js'));
|
|
55
|
+
// 先试现有节点 (可能已有 pubsub)
|
|
56
|
+
if (_node) {
|
|
57
|
+
const hasPubsub = !!(_node?.libp2p?.services?.pubsub);
|
|
58
|
+
if (hasPubsub) {
|
|
59
|
+
const r = await createMobileOrbitDB(_node);
|
|
60
|
+
return { ok: r.ok, orbit: r.orbit, node: _node, error: r.error };
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
// 没有 pubsub → 用 gossipsub 重建节点 (高级路径)
|
|
64
|
+
// 注意: buildCustomHelia 的 services 是 identify+ping(+dht), libp2pOptions 整体展开会覆盖 services
|
|
65
|
+
// → 必须带上 identify/ping 一起, 否则 circuit-relay transport 报 UnmetServiceDependenciesError
|
|
66
|
+
const { gossipsub } = await import('@libp2p/gossipsub');
|
|
67
|
+
const { identify } = await import('@libp2p/identify');
|
|
68
|
+
const { ping } = await import('@libp2p/ping');
|
|
69
|
+
const nodeR = await mh.createMobileHeliaNode({
|
|
70
|
+
libp2pOptions: {
|
|
71
|
+
services: {
|
|
72
|
+
identify: identify(), ping: ping(),
|
|
73
|
+
// allowPublishToZeroPeers: 单节点/刚启动时没有对端订阅也允许发布 (OrbitDB 4.x 同步需要);
|
|
74
|
+
// emitSelf: 自己发布的也回放给自己 (本地 store 一致性)
|
|
75
|
+
pubsub: gossipsub({ emitSelf: false, allowPublishToZeroTopicPeers: true }),
|
|
76
|
+
},
|
|
77
|
+
},
|
|
78
|
+
});
|
|
79
|
+
if (!nodeR.ok || !nodeR.node)
|
|
80
|
+
return { ok: false, error: nodeR.error || '重建带 pubsub 的节点失败' };
|
|
81
|
+
const r = await createMobileOrbitDB(nodeR.node);
|
|
82
|
+
return { ok: r.ok, orbit: r.orbit, node: nodeR.node, error: r.error };
|
|
83
|
+
}
|
|
84
|
+
catch (e) {
|
|
85
|
+
return { ok: false, error: `创建带 pubsub 的 OrbitDB 失败: ${String(e?.message || e).slice(0, 200)}` };
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
/** 打开 store (type: 'keyvalue' | 'documents' | 'events') */
|
|
89
|
+
export async function openStore(name, type = 'keyvalue', options = {}) {
|
|
90
|
+
try {
|
|
91
|
+
if (!_orbit) {
|
|
92
|
+
const r = await createMobileOrbitDB();
|
|
93
|
+
if (!r.ok)
|
|
94
|
+
return { ok: false, error: r.error };
|
|
95
|
+
}
|
|
96
|
+
const store = await _orbit.open(String(name || ''), { type, ...options });
|
|
97
|
+
return { ok: true, store };
|
|
98
|
+
}
|
|
99
|
+
catch (e) {
|
|
100
|
+
return { ok: false, error: `打开 store 失败: ${String(e?.message || e).slice(0, 200)}` };
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
/** kvstore: put */
|
|
104
|
+
export async function kvPut(store, key, value) {
|
|
105
|
+
try {
|
|
106
|
+
await store.put(String(key), value);
|
|
107
|
+
return { ok: true };
|
|
108
|
+
}
|
|
109
|
+
catch (e) {
|
|
110
|
+
return { ok: false, error: String(e?.message || e) };
|
|
111
|
+
}
|
|
112
|
+
}
|
|
113
|
+
/** kvstore: get */
|
|
114
|
+
export async function kvGet(store, key) {
|
|
115
|
+
try {
|
|
116
|
+
return { ok: true, value: await store.get(String(key)) };
|
|
117
|
+
}
|
|
118
|
+
catch (e) {
|
|
119
|
+
return { ok: false, error: String(e?.message || e) };
|
|
120
|
+
}
|
|
121
|
+
}
|
|
122
|
+
/** kvstore: del */
|
|
123
|
+
export async function kvDel(store, key) {
|
|
124
|
+
try {
|
|
125
|
+
await store.del(String(key));
|
|
126
|
+
return { ok: true };
|
|
127
|
+
}
|
|
128
|
+
catch (e) {
|
|
129
|
+
return { ok: false, error: String(e?.message || e) };
|
|
130
|
+
}
|
|
131
|
+
}
|
|
132
|
+
/** kvstore: 全部条目 */
|
|
133
|
+
export async function kvAll(store) {
|
|
134
|
+
try {
|
|
135
|
+
// @orbitdb/core 4.x kvstore: all() 返回 [{key, value, hash}] 数组
|
|
136
|
+
let all = {};
|
|
137
|
+
if (typeof store.all === 'function') {
|
|
138
|
+
const rows = (await store.all()) || [];
|
|
139
|
+
if (Array.isArray(rows)) {
|
|
140
|
+
for (const r of rows) {
|
|
141
|
+
if (r && r.key !== undefined)
|
|
142
|
+
all[String(r.key)] = r.value;
|
|
143
|
+
}
|
|
144
|
+
}
|
|
145
|
+
else if (typeof rows === 'object') {
|
|
146
|
+
all = rows;
|
|
147
|
+
}
|
|
148
|
+
}
|
|
149
|
+
else if (store.iterator) {
|
|
150
|
+
for (const [k, v] of (await store.iterator().collect())) {
|
|
151
|
+
if (k !== undefined)
|
|
152
|
+
all[String(k)] = v;
|
|
153
|
+
}
|
|
154
|
+
}
|
|
155
|
+
return { ok: true, entries: all };
|
|
156
|
+
}
|
|
157
|
+
catch (e) {
|
|
158
|
+
return { ok: false, error: String(e?.message || e) };
|
|
159
|
+
}
|
|
160
|
+
}
|
|
161
|
+
/** documents: 按索引查 (query(fn) — @orbitdb/core 4.x documents 的正确 API; indexBy 在 open 时声明) */
|
|
162
|
+
export async function docQuery(store, query) {
|
|
163
|
+
try {
|
|
164
|
+
let r;
|
|
165
|
+
if (typeof query === 'function') {
|
|
166
|
+
r = await store.query(query);
|
|
167
|
+
}
|
|
168
|
+
else if (query && typeof query === 'object') {
|
|
169
|
+
// 对象查询 → 转成匹配所有键值的函数 (与 indexBy 字段匹配)
|
|
170
|
+
const keys = Object.keys(query);
|
|
171
|
+
r = await store.query((doc) => keys.every((k) => doc?.[k] === query[k]));
|
|
172
|
+
}
|
|
173
|
+
else {
|
|
174
|
+
r = await store.get(String(query ?? ''));
|
|
175
|
+
}
|
|
176
|
+
return { ok: true, results: Array.isArray(r) ? r : (r ? [r] : []) };
|
|
177
|
+
}
|
|
178
|
+
catch (e) {
|
|
179
|
+
return { ok: false, error: String(e?.message || e) };
|
|
180
|
+
}
|
|
181
|
+
}
|
|
182
|
+
/** 关闭实例 (保留 helia 节点) */
|
|
183
|
+
export async function stopMobileOrbitDB() {
|
|
184
|
+
try {
|
|
185
|
+
if (_orbit)
|
|
186
|
+
await _orbit.stop();
|
|
187
|
+
_orbit = null;
|
|
188
|
+
return { ok: true };
|
|
189
|
+
}
|
|
190
|
+
catch {
|
|
191
|
+
_orbit = null;
|
|
192
|
+
return { ok: true };
|
|
193
|
+
}
|
|
194
|
+
}
|
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
// src/web/mobile-persona.ts
|
|
2
|
+
var PERSONA_KEY = "bolloon_mobile_persona";
|
|
3
|
+
var DEFAULT_PERSONA = {
|
|
4
|
+
name: "blln-mobile",
|
|
5
|
+
personality: "严谨、可靠、有边界感",
|
|
6
|
+
values: ["本地优先", "隐私优先", "诚实透明"],
|
|
7
|
+
interests: ["P2P 网络", "AI 智能体", "知识系统"],
|
|
8
|
+
style: "简洁中文,先给结论再给细节",
|
|
9
|
+
boundaries: ["不假装能做做不到的事", "不编造数据"],
|
|
10
|
+
extra: ""
|
|
11
|
+
};
|
|
12
|
+
function safeGet() {
|
|
13
|
+
try {
|
|
14
|
+
return window.localStorage;
|
|
15
|
+
} catch {
|
|
16
|
+
return globalThis.localStorage || { getItem: () => null, setItem: () => {
|
|
17
|
+
} };
|
|
18
|
+
}
|
|
19
|
+
}
|
|
20
|
+
function loadPersona() {
|
|
21
|
+
try {
|
|
22
|
+
const raw = safeGet().getItem(PERSONA_KEY);
|
|
23
|
+
if (!raw) return { ...DEFAULT_PERSONA };
|
|
24
|
+
const p = JSON.parse(raw);
|
|
25
|
+
return {
|
|
26
|
+
name: typeof p.name === "string" && p.name ? p.name : DEFAULT_PERSONA.name,
|
|
27
|
+
personality: typeof p.personality === "string" ? p.personality : DEFAULT_PERSONA.personality,
|
|
28
|
+
values: Array.isArray(p.values) ? p.values : DEFAULT_PERSONA.values,
|
|
29
|
+
interests: Array.isArray(p.interests) ? p.interests : DEFAULT_PERSONA.interests,
|
|
30
|
+
style: typeof p.style === "string" ? p.style : DEFAULT_PERSONA.style,
|
|
31
|
+
boundaries: Array.isArray(p.boundaries) ? p.boundaries : DEFAULT_PERSONA.boundaries,
|
|
32
|
+
extra: typeof p.extra === "string" ? p.extra : ""
|
|
33
|
+
};
|
|
34
|
+
} catch {
|
|
35
|
+
return { ...DEFAULT_PERSONA };
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
function savePersona(partial) {
|
|
39
|
+
const cur = loadPersona();
|
|
40
|
+
const next = {
|
|
41
|
+
name: typeof partial.name === "string" && partial.name.trim() ? partial.name.trim() : cur.name,
|
|
42
|
+
personality: typeof partial.personality === "string" ? partial.personality : cur.personality,
|
|
43
|
+
values: Array.isArray(partial.values) ? partial.values : cur.values,
|
|
44
|
+
interests: Array.isArray(partial.interests) ? partial.interests : cur.interests,
|
|
45
|
+
style: typeof partial.style === "string" ? partial.style : cur.style,
|
|
46
|
+
boundaries: Array.isArray(partial.boundaries) ? partial.boundaries : cur.boundaries,
|
|
47
|
+
extra: typeof partial.extra === "string" ? partial.extra : cur.extra
|
|
48
|
+
};
|
|
49
|
+
try {
|
|
50
|
+
safeGet().setItem(PERSONA_KEY, JSON.stringify(next));
|
|
51
|
+
} catch {
|
|
52
|
+
}
|
|
53
|
+
return next;
|
|
54
|
+
}
|
|
55
|
+
function resetPersona() {
|
|
56
|
+
try {
|
|
57
|
+
safeGet().removeItem(PERSONA_KEY);
|
|
58
|
+
} catch {
|
|
59
|
+
}
|
|
60
|
+
return { ...DEFAULT_PERSONA };
|
|
61
|
+
}
|
|
62
|
+
function buildPersonaPrompt(p = loadPersona()) {
|
|
63
|
+
const lines = [
|
|
64
|
+
`你的名字: ${p.name}`,
|
|
65
|
+
`性格: ${p.personality}`,
|
|
66
|
+
p.style ? `说话方式: ${p.style}` : "",
|
|
67
|
+
p.values.length ? `价值观: ${p.values.join("、")}` : "",
|
|
68
|
+
p.interests.length ? `兴趣: ${p.interests.join("、")}` : "",
|
|
69
|
+
p.boundaries.length ? `不做的事: ${p.boundaries.join("、")}` : "",
|
|
70
|
+
p.extra ? `补充: ${p.extra}` : ""
|
|
71
|
+
].filter(Boolean);
|
|
72
|
+
return lines.join("\n");
|
|
73
|
+
}
|
|
74
|
+
export {
|
|
75
|
+
DEFAULT_PERSONA,
|
|
76
|
+
buildPersonaPrompt,
|
|
77
|
+
loadPersona,
|
|
78
|
+
resetPersona,
|
|
79
|
+
savePersona
|
|
80
|
+
};
|
|
@@ -53,9 +53,8 @@ export const PRIVACY_SUMMARY = [
|
|
|
53
53
|
body: '蓝牙扫描与连接:发现并连接附近设备与好友(已声明 neverForLocation,不用于推断位置)。' +
|
|
54
54
|
'位置权限:仅 Android 11 及以下系统要求蓝牙扫描需要它(已限制 maxSdkVersion=30,Android 12+ 不再申请)。' +
|
|
55
55
|
'网络:P2P 连接与下载。相机:调用系统相机应用完成拍摄,本应用不申请相机权限。' +
|
|
56
|
-
'
|
|
57
|
-
'
|
|
58
|
-
'应用商店下载的版本不含这两项,也没有这个能力。',
|
|
56
|
+
'跨 App 点按、滑动屏幕或调用系统能力所需的 Android 无障碍与 Shizuku:仅官网直装版本包含,属于可选扩展能力;' +
|
|
57
|
+
'手机端基础 Agent 不依赖这些权限即可直接运行。应用商店下载的版本不含跨 App 控制能力。',
|
|
59
58
|
},
|
|
60
59
|
{
|
|
61
60
|
title: '六、你的权利与注销',
|
package/dist/web/mobile.css
CHANGED
|
@@ -361,12 +361,13 @@ body {
|
|
|
361
361
|
|
|
362
362
|
/* ============ 世界机会流 (2026-10-05, leo Intent Network) ============ */
|
|
363
363
|
/* 主动流入: 打开首页即拉, 持续刷新; 不是按钮式被动响应 */
|
|
364
|
+
/* 首页世界机会流 (2026-10-07: 双栏卡片, 对应桌面世界模式) */
|
|
364
365
|
.world-feed {
|
|
365
366
|
padding: 10px 14px 4px;
|
|
366
|
-
border-bottom: 1px solid var(--border);
|
|
367
367
|
background: var(--bg);
|
|
368
368
|
overflow-y: auto;
|
|
369
|
-
|
|
369
|
+
flex: 1;
|
|
370
|
+
min-height: 0;
|
|
370
371
|
}
|
|
371
372
|
.world-feed-header {
|
|
372
373
|
display: flex;
|
|
@@ -382,20 +383,27 @@ body {
|
|
|
382
383
|
color: var(--text-muted);
|
|
383
384
|
font-weight: 400;
|
|
384
385
|
}
|
|
385
|
-
|
|
386
|
-
.world-feed-
|
|
386
|
+
/* 双栏网格 (2026-10-07: 首页双栏卡片) */
|
|
387
|
+
.world-feed-cards {
|
|
388
|
+
display: grid;
|
|
389
|
+
grid-template-columns: repeat(2, 1fr);
|
|
390
|
+
gap: 10px;
|
|
391
|
+
padding-bottom: 12px;
|
|
392
|
+
}
|
|
393
|
+
.world-feed-loading { font-size: 12px; color: var(--text-muted); padding: 8px 0; grid-column: 1 / -1; }
|
|
387
394
|
.world-feed-card {
|
|
388
395
|
background: var(--bg-card);
|
|
389
396
|
border: 1px solid var(--border);
|
|
390
397
|
border-left: 3px solid transparent;
|
|
391
|
-
border-radius:
|
|
392
|
-
padding: 10px
|
|
398
|
+
border-radius: 12px;
|
|
399
|
+
padding: 10px 10px;
|
|
400
|
+
min-width: 0;
|
|
393
401
|
}
|
|
394
402
|
.world-feed-card-top {
|
|
395
403
|
display: flex;
|
|
396
404
|
justify-content: space-between;
|
|
397
405
|
align-items: center;
|
|
398
|
-
gap:
|
|
406
|
+
gap: 6px;
|
|
399
407
|
}
|
|
400
408
|
.world-feed-title {
|
|
401
409
|
font-size: 13px;
|
|
@@ -404,6 +412,8 @@ body {
|
|
|
404
412
|
overflow: hidden;
|
|
405
413
|
text-overflow: ellipsis;
|
|
406
414
|
white-space: nowrap;
|
|
415
|
+
flex: 1;
|
|
416
|
+
min-width: 0;
|
|
407
417
|
}
|
|
408
418
|
.world-feed-pct {
|
|
409
419
|
color: var(--accent);
|
|
@@ -416,11 +426,15 @@ body {
|
|
|
416
426
|
font-size: 12px;
|
|
417
427
|
color: var(--text-secondary);
|
|
418
428
|
margin-top: 4px;
|
|
419
|
-
line-height: 1.
|
|
429
|
+
line-height: 1.4;
|
|
430
|
+
display: -webkit-box;
|
|
431
|
+
-webkit-line-clamp: 3;
|
|
432
|
+
-webkit-box-orient: vertical;
|
|
433
|
+
overflow: hidden;
|
|
420
434
|
}
|
|
421
435
|
.world-feed-actions {
|
|
422
436
|
display: flex;
|
|
423
|
-
gap:
|
|
437
|
+
gap: 6px;
|
|
424
438
|
margin-top: 8px;
|
|
425
439
|
}
|
|
426
440
|
.world-feed-btn {
|
|
@@ -439,6 +453,258 @@ body {
|
|
|
439
453
|
border-color: var(--border);
|
|
440
454
|
}
|
|
441
455
|
|
|
456
|
+
/* 首页底部输入框 (2026-10-07: 对应桌面世界模式输入框, Bolloon 风格) */
|
|
457
|
+
.world-input-bar {
|
|
458
|
+
display: flex;
|
|
459
|
+
gap: 8px;
|
|
460
|
+
align-items: center;
|
|
461
|
+
padding: 10px 14px;
|
|
462
|
+
border-top: 1px solid var(--border);
|
|
463
|
+
background: var(--bg-sidebar, #222220);
|
|
464
|
+
flex-shrink: 0;
|
|
465
|
+
}
|
|
466
|
+
.world-input-bar input {
|
|
467
|
+
flex: 1;
|
|
468
|
+
min-width: 0;
|
|
469
|
+
padding: 10px 12px;
|
|
470
|
+
border-radius: 10px;
|
|
471
|
+
border: 1px solid var(--border);
|
|
472
|
+
background: var(--bg-card, #222220);
|
|
473
|
+
color: var(--text);
|
|
474
|
+
font-size: 14px;
|
|
475
|
+
outline: none;
|
|
476
|
+
}
|
|
477
|
+
.world-input-bar input:focus {
|
|
478
|
+
border-color: var(--accent);
|
|
479
|
+
}
|
|
480
|
+
.world-input-send {
|
|
481
|
+
padding: 10px 16px;
|
|
482
|
+
border: 1px solid var(--accent);
|
|
483
|
+
background: var(--accent);
|
|
484
|
+
color: #1a1a18;
|
|
485
|
+
border-radius: 10px;
|
|
486
|
+
font-size: 13px;
|
|
487
|
+
font-weight: 600;
|
|
488
|
+
flex-shrink: 0;
|
|
489
|
+
}
|
|
490
|
+
|
|
491
|
+
/* ============ 好友 tab: 通讯录风格 (2026-10-07, 微信式) ============ */
|
|
492
|
+
.contacts-wrap {
|
|
493
|
+
position: relative;
|
|
494
|
+
}
|
|
495
|
+
.contacts-group-head {
|
|
496
|
+
padding: 6px 14px;
|
|
497
|
+
font-size: 12px;
|
|
498
|
+
font-weight: 600;
|
|
499
|
+
color: var(--text-muted);
|
|
500
|
+
background: var(--bg-hover, #222220);
|
|
501
|
+
}
|
|
502
|
+
.contact-row {
|
|
503
|
+
padding: 10px 14px;
|
|
504
|
+
border-bottom: 1px solid var(--border);
|
|
505
|
+
}
|
|
506
|
+
.contact-avatar {
|
|
507
|
+
background: var(--accent);
|
|
508
|
+
color: #1a1a18;
|
|
509
|
+
font-weight: 700;
|
|
510
|
+
}
|
|
511
|
+
.contact-sub {
|
|
512
|
+
font-size: 11px;
|
|
513
|
+
color: var(--text-muted);
|
|
514
|
+
margin-top: 2px;
|
|
515
|
+
}
|
|
516
|
+
.contacts-index {
|
|
517
|
+
position: fixed;
|
|
518
|
+
right: 2px;
|
|
519
|
+
top: 50%;
|
|
520
|
+
transform: translateY(-50%);
|
|
521
|
+
display: flex;
|
|
522
|
+
flex-direction: column;
|
|
523
|
+
align-items: center;
|
|
524
|
+
z-index: 50;
|
|
525
|
+
font-size: 10px;
|
|
526
|
+
color: var(--text-secondary);
|
|
527
|
+
user-select: none;
|
|
528
|
+
background: rgba(0,0,0,0.25);
|
|
529
|
+
border-radius: 8px;
|
|
530
|
+
padding: 2px 3px;
|
|
531
|
+
}
|
|
532
|
+
.contacts-index-letter {
|
|
533
|
+
padding: 1px 2px;
|
|
534
|
+
cursor: pointer;
|
|
535
|
+
line-height: 1.3;
|
|
536
|
+
}
|
|
537
|
+
.contacts-index-letter:hover { color: var(--accent); }
|
|
538
|
+
|
|
539
|
+
/* ============ 任务 tab: 公告板双栏瀑布流 (2026-10-07, 发现页风格) ============ */
|
|
540
|
+
.board-grid {
|
|
541
|
+
display: grid;
|
|
542
|
+
grid-template-columns: repeat(2, 1fr);
|
|
543
|
+
gap: 10px;
|
|
544
|
+
padding: 10px 14px;
|
|
545
|
+
}
|
|
546
|
+
.board-card {
|
|
547
|
+
background: var(--bg-card);
|
|
548
|
+
border: 1px solid var(--border);
|
|
549
|
+
border-radius: 12px;
|
|
550
|
+
padding: 10px;
|
|
551
|
+
min-width: 0;
|
|
552
|
+
display: flex;
|
|
553
|
+
flex-direction: column;
|
|
554
|
+
gap: 6px;
|
|
555
|
+
}
|
|
556
|
+
.board-card-cap {
|
|
557
|
+
font-size: 13px;
|
|
558
|
+
font-weight: 600;
|
|
559
|
+
color: var(--text);
|
|
560
|
+
line-height: 1.4;
|
|
561
|
+
display: -webkit-box;
|
|
562
|
+
-webkit-line-clamp: 2;
|
|
563
|
+
-webkit-box-orient: vertical;
|
|
564
|
+
overflow: hidden;
|
|
565
|
+
}
|
|
566
|
+
.board-card-status {
|
|
567
|
+
font-size: 10px;
|
|
568
|
+
padding: 2px 6px;
|
|
569
|
+
border-radius: 4px;
|
|
570
|
+
background: var(--bg-hover, #222220);
|
|
571
|
+
color: var(--accent);
|
|
572
|
+
align-self: flex-start;
|
|
573
|
+
}
|
|
574
|
+
.board-card-sub {
|
|
575
|
+
font-size: 11px;
|
|
576
|
+
color: var(--text-muted);
|
|
577
|
+
}
|
|
578
|
+
.board-card-btn {
|
|
579
|
+
margin-top: auto;
|
|
580
|
+
padding: 6px 0;
|
|
581
|
+
border: 1px solid var(--accent);
|
|
582
|
+
background: var(--accent);
|
|
583
|
+
color: #1a1a18;
|
|
584
|
+
border-radius: 8px;
|
|
585
|
+
font-size: 12px;
|
|
586
|
+
font-weight: 600;
|
|
587
|
+
}
|
|
588
|
+
|
|
589
|
+
/* ============ 任务 tab: 对话框模式 (2026-10-07) ============ */
|
|
590
|
+
.task-chat-page {
|
|
591
|
+
display: flex;
|
|
592
|
+
flex-direction: column;
|
|
593
|
+
min-height: 0;
|
|
594
|
+
}
|
|
595
|
+
.task-dash {
|
|
596
|
+
display: flex;
|
|
597
|
+
gap: 8px;
|
|
598
|
+
padding: 8px 14px;
|
|
599
|
+
border-bottom: 1px solid var(--border);
|
|
600
|
+
flex-shrink: 0;
|
|
601
|
+
}
|
|
602
|
+
.task-dash-btn {
|
|
603
|
+
flex: 1;
|
|
604
|
+
display: flex;
|
|
605
|
+
flex-direction: column;
|
|
606
|
+
align-items: center;
|
|
607
|
+
gap: 2px;
|
|
608
|
+
padding: 6px 0;
|
|
609
|
+
background: var(--bg-card, #222220);
|
|
610
|
+
border: 1px solid var(--border);
|
|
611
|
+
border-radius: 10px;
|
|
612
|
+
color: var(--text-secondary);
|
|
613
|
+
font-size: 11px;
|
|
614
|
+
}
|
|
615
|
+
.task-dash-ico { font-size: 16px; }
|
|
616
|
+
.task-chat {
|
|
617
|
+
flex: 1;
|
|
618
|
+
min-height: 0;
|
|
619
|
+
overflow-y: auto;
|
|
620
|
+
padding: 12px 14px;
|
|
621
|
+
display: flex;
|
|
622
|
+
flex-direction: column;
|
|
623
|
+
gap: 8px;
|
|
624
|
+
}
|
|
625
|
+
.task-chat-empty {
|
|
626
|
+
color: var(--text-muted);
|
|
627
|
+
font-size: 13px;
|
|
628
|
+
text-align: center;
|
|
629
|
+
padding: 40px 20px;
|
|
630
|
+
line-height: 1.6;
|
|
631
|
+
}
|
|
632
|
+
.task-msg {
|
|
633
|
+
max-width: 88%;
|
|
634
|
+
padding: 10px 12px;
|
|
635
|
+
border-radius: 12px;
|
|
636
|
+
font-size: 14px;
|
|
637
|
+
line-height: 1.5;
|
|
638
|
+
white-space: pre-wrap;
|
|
639
|
+
word-break: break-word;
|
|
640
|
+
}
|
|
641
|
+
.task-msg-user {
|
|
642
|
+
align-self: flex-end;
|
|
643
|
+
background: var(--accent);
|
|
644
|
+
color: #1a1a18;
|
|
645
|
+
border-bottom-right-radius: 4px;
|
|
646
|
+
}
|
|
647
|
+
.task-msg-ai {
|
|
648
|
+
align-self: flex-start;
|
|
649
|
+
background: var(--bg-card, #222220);
|
|
650
|
+
border: 1px solid var(--border);
|
|
651
|
+
color: var(--text);
|
|
652
|
+
border-bottom-left-radius: 4px;
|
|
653
|
+
}
|
|
654
|
+
.task-input-bar {
|
|
655
|
+
display: flex;
|
|
656
|
+
gap: 8px;
|
|
657
|
+
align-items: center;
|
|
658
|
+
padding: 10px 14px;
|
|
659
|
+
border-top: 1px solid var(--border);
|
|
660
|
+
background: var(--bg-sidebar, #222220);
|
|
661
|
+
flex-shrink: 0;
|
|
662
|
+
}
|
|
663
|
+
.task-input-bar input {
|
|
664
|
+
flex: 1;
|
|
665
|
+
min-width: 0;
|
|
666
|
+
padding: 10px 12px;
|
|
667
|
+
border-radius: 10px;
|
|
668
|
+
border: 1px solid var(--border);
|
|
669
|
+
background: var(--bg-card, #222220);
|
|
670
|
+
color: var(--text);
|
|
671
|
+
font-size: 14px;
|
|
672
|
+
outline: none;
|
|
673
|
+
}
|
|
674
|
+
.task-input-bar input:focus { border-color: var(--accent); }
|
|
675
|
+
.task-input-bar button {
|
|
676
|
+
padding: 10px 16px;
|
|
677
|
+
border: 1px solid var(--accent);
|
|
678
|
+
background: var(--accent);
|
|
679
|
+
color: #1a1a18;
|
|
680
|
+
border-radius: 10px;
|
|
681
|
+
font-size: 13px;
|
|
682
|
+
font-weight: 600;
|
|
683
|
+
flex-shrink: 0;
|
|
684
|
+
}
|
|
685
|
+
/* 网络工具覆盖层 */
|
|
686
|
+
.task-network-panel {
|
|
687
|
+
position: fixed;
|
|
688
|
+
inset: 0;
|
|
689
|
+
z-index: 80;
|
|
690
|
+
background: var(--bg);
|
|
691
|
+
display: flex;
|
|
692
|
+
flex-direction: column;
|
|
693
|
+
}
|
|
694
|
+
.task-network-head {
|
|
695
|
+
display: flex;
|
|
696
|
+
align-items: center;
|
|
697
|
+
gap: 8px;
|
|
698
|
+
padding: 10px 14px;
|
|
699
|
+
border-bottom: 1px solid var(--border);
|
|
700
|
+
flex-shrink: 0;
|
|
701
|
+
}
|
|
702
|
+
.task-network-body {
|
|
703
|
+
flex: 1;
|
|
704
|
+
min-height: 0;
|
|
705
|
+
overflow-y: auto;
|
|
706
|
+
}
|
|
707
|
+
|
|
442
708
|
/* ============ 双频滑动卡片 (主页面) ============ */
|
|
443
709
|
|
|
444
710
|
.card-carousel {
|
|
@@ -450,29 +716,28 @@ body {
|
|
|
450
716
|
}
|
|
451
717
|
|
|
452
718
|
.card-track {
|
|
453
|
-
|
|
454
|
-
|
|
455
|
-
|
|
456
|
-
|
|
719
|
+
/* 2026-10-06 (用户: 首页卡片变双栏): 从单卡纵向翻页改为两列网格, 一屏看更多智能体 */
|
|
720
|
+
display: grid;
|
|
721
|
+
grid-template-columns: repeat(2, 1fr);
|
|
722
|
+
gap: 12px;
|
|
723
|
+
padding: 12px;
|
|
457
724
|
overflow-y: auto;
|
|
458
725
|
overflow-x: hidden;
|
|
459
|
-
scroll-snap-type: y mandatory;
|
|
460
726
|
-webkit-overflow-scrolling: touch;
|
|
461
727
|
scroll-behavior: smooth;
|
|
462
728
|
height: 100%;
|
|
463
|
-
align-
|
|
464
|
-
touch-action: pan-y; /*
|
|
729
|
+
align-content: start;
|
|
730
|
+
touch-action: pan-y; /* 垂直交给原生滚动, 水平交给 JS 做删除 reveal */
|
|
465
731
|
}
|
|
466
732
|
|
|
467
733
|
.card-track::-webkit-scrollbar { display: none; }
|
|
468
734
|
|
|
469
|
-
/* 每张卡片外层:
|
|
735
|
+
/* 每张卡片外层: 网格单元 + 删除位 (双栏下固定比例, 不满屏) */
|
|
470
736
|
.card-wrap {
|
|
471
|
-
|
|
472
|
-
|
|
473
|
-
scroll-snap-align: start;
|
|
737
|
+
height: auto;
|
|
738
|
+
aspect-ratio: 3 / 4;
|
|
474
739
|
position: relative;
|
|
475
|
-
border-radius:
|
|
740
|
+
border-radius: 14px;
|
|
476
741
|
overflow: hidden;
|
|
477
742
|
min-height: 0;
|
|
478
743
|
}
|