@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.
Files changed (169) hide show
  1. package/dist/agents/chain/chain-settlement.js +0 -1
  2. package/dist/agents/chat-segmenter.js +4 -16
  3. package/dist/agents/contacts/human-directory.js +155 -0
  4. package/dist/agents/contacts/tools.js +79 -0
  5. package/dist/agents/experience-review.js +0 -3
  6. package/dist/agents/goal-flywheel/goal-change.js +3 -4
  7. package/dist/agents/goal-resume.js +0 -4
  8. package/dist/agents/intent-classifier.js +1 -1
  9. package/dist/agents/iteration-budget.js +12 -0
  10. package/dist/agents/knowledge-organizer.js +0 -2
  11. package/dist/agents/lesson-to-skill.js +0 -1
  12. package/dist/agents/loop-review.js +2 -2
  13. package/dist/agents/memory-store.js +359 -0
  14. package/dist/agents/opportunity-web-search.js +39 -0
  15. package/dist/agents/p2p-chat-tools.js +1 -2
  16. package/dist/agents/parse-tool-call.js +9 -22
  17. package/dist/agents/pi-harness.js +1 -2
  18. package/dist/agents/pi-sdk-tools.js +180 -5
  19. package/dist/agents/pi-sdk.js +143 -9
  20. package/dist/agents/process-runner.js +28 -9
  21. package/dist/agents/react-loop.js +9 -17
  22. package/dist/agents/runner-resolver.js +4 -3
  23. package/dist/agents/skill-loader.js +22 -15
  24. package/dist/agents/skills-manager.js +1 -25
  25. package/dist/agents/workflow-pivot-loop.js +152 -61
  26. package/dist/bootstrap/context-collector.js +2 -4
  27. package/dist/bootstrap/context-hierarchy.js +13 -1
  28. package/dist/cli/ink-app.js +44 -17
  29. package/dist/cli/intent-command.js +22 -12
  30. package/dist/cli/loading-tui.js +8 -2
  31. package/dist/cli/log-gate.js +40 -8
  32. package/dist/cli/mention-data.js +1 -0
  33. package/dist/cli/reply-hygiene.js +22 -0
  34. package/dist/cli/trace-line.js +61 -2
  35. package/dist/electron-build/agents/agent-gateway.js.map +1 -1
  36. package/dist/electron-build/agents/chain/chain-indexer.js.map +1 -1
  37. package/dist/electron-build/agents/chain/chain-settlement.js +0 -1
  38. package/dist/electron-build/agents/chain/chain-settlement.js.map +1 -1
  39. package/dist/electron-build/agents/contacts/chain.js.map +1 -1
  40. package/dist/electron-build/agents/contacts/human-directory.js +204 -0
  41. package/dist/electron-build/agents/contacts/human-directory.js.map +1 -0
  42. package/dist/electron-build/agents/contacts/policy.js.map +1 -1
  43. package/dist/electron-build/agents/contacts/tools.js +112 -0
  44. package/dist/electron-build/agents/contacts/tools.js.map +1 -1
  45. package/dist/electron-build/agents/experience-review.js +0 -3
  46. package/dist/electron-build/agents/experience-review.js.map +1 -1
  47. package/dist/electron-build/agents/external-events.js.map +1 -1
  48. package/dist/electron-build/agents/goal-flywheel/goal-change.js +3 -4
  49. package/dist/electron-build/agents/goal-flywheel/goal-change.js.map +1 -1
  50. package/dist/electron-build/agents/goal-flywheel-wiring.js.map +1 -1
  51. package/dist/electron-build/agents/goal-resume.js +0 -4
  52. package/dist/electron-build/agents/goal-resume.js.map +1 -1
  53. package/dist/electron-build/agents/intent-classifier.js +1 -1
  54. package/dist/electron-build/agents/lesson-to-skill.js +0 -1
  55. package/dist/electron-build/agents/lesson-to-skill.js.map +1 -1
  56. package/dist/electron-build/agents/loop-review.js +2 -2
  57. package/dist/electron-build/agents/loop-review.js.map +1 -1
  58. package/dist/electron-build/agents/memory-recall.js.map +1 -1
  59. package/dist/electron-build/agents/memory-store.js +404 -0
  60. package/dist/electron-build/agents/memory-store.js.map +1 -0
  61. package/dist/electron-build/agents/parse-tool-call.js +9 -22
  62. package/dist/electron-build/agents/parse-tool-call.js.map +1 -1
  63. package/dist/electron-build/agents/pi-harness.js +1 -2
  64. package/dist/electron-build/agents/pi-harness.js.map +1 -1
  65. package/dist/electron-build/agents/pi-sdk-tools.js +180 -5
  66. package/dist/electron-build/agents/pi-sdk-tools.js.map +1 -1
  67. package/dist/electron-build/agents/pi-sdk.js +143 -9
  68. package/dist/electron-build/agents/pi-sdk.js.map +1 -1
  69. package/dist/electron-build/agents/pre-tool-validator.js.map +1 -1
  70. package/dist/electron-build/agents/process-runner.js +28 -9
  71. package/dist/electron-build/agents/process-runner.js.map +1 -1
  72. package/dist/electron-build/agents/runner-resolver.js +4 -3
  73. package/dist/electron-build/agents/runner-resolver.js.map +1 -1
  74. package/dist/electron-build/agents/skill-loader.js +22 -16
  75. package/dist/electron-build/agents/skill-loader.js.map +1 -1
  76. package/dist/electron-build/agents/skill-supervisor-link.js.map +1 -1
  77. package/dist/electron-build/agents/skills-manager.js +0 -24
  78. package/dist/electron-build/agents/skills-manager.js.map +1 -1
  79. package/dist/electron-build/agents/task/task-runner.js.map +1 -1
  80. package/dist/electron-build/agents/workflow-engine.js.map +1 -1
  81. package/dist/electron-build/agents/workflow-pivot-loop.js +155 -62
  82. package/dist/electron-build/agents/workflow-pivot-loop.js.map +1 -1
  83. package/dist/electron-build/agents/x402/goal-run-bridge.js.map +1 -1
  84. package/dist/electron-build/bollharness-integration/gate-state-machine.js.map +1 -1
  85. package/dist/electron-build/bootstrap/context-collector.js +2 -4
  86. package/dist/electron-build/bootstrap/context-collector.js.map +1 -1
  87. package/dist/electron-build/bootstrap/context-hierarchy.js +13 -1
  88. package/dist/electron-build/bootstrap/context-hierarchy.js.map +1 -1
  89. package/dist/electron-build/electron-preload.js.map +1 -1
  90. package/dist/electron-build/external-engines/delegate.js.map +1 -1
  91. package/dist/electron-build/kernel/channel-actor.js +31 -2
  92. package/dist/electron-build/kernel/channel-actor.js.map +1 -1
  93. package/dist/electron-build/kernel/model-runtime.js +8 -1
  94. package/dist/electron-build/kernel/model-runtime.js.map +1 -1
  95. package/dist/electron-build/llm/config-store.js +20 -0
  96. package/dist/electron-build/llm/config-store.js.map +1 -1
  97. package/dist/electron-build/llm/embedding-adapter.js +75 -0
  98. package/dist/electron-build/llm/embedding-adapter.js.map +1 -0
  99. package/dist/electron-build/llm/pi-ai.js +96 -35
  100. package/dist/electron-build/llm/pi-ai.js.map +1 -1
  101. package/dist/electron-build/network/agent-network.js.map +1 -1
  102. package/dist/electron-build/orbitdb/memory-sync.js +76 -0
  103. package/dist/electron-build/orbitdb/memory-sync.js.map +1 -0
  104. package/dist/electron-build/pi-ecosystem-judgment/adaptive-scan.js.map +1 -1
  105. package/dist/electron-build/security/tool-gate.js +2 -0
  106. package/dist/electron-build/security/tool-gate.js.map +1 -1
  107. package/dist/electron-build/setup/setup-store.js +34 -6
  108. package/dist/electron-build/setup/setup-store.js.map +1 -1
  109. package/dist/electron-build/social/heartbeat.js +18 -5
  110. package/dist/electron-build/social/heartbeat.js.map +1 -1
  111. package/dist/electron-build/utils/update-manager.js.map +1 -1
  112. package/dist/index.js +250 -12
  113. package/dist/ios/bolloon-web.json +2 -2
  114. package/dist/ios/client.js +74 -35
  115. package/dist/ios/icons/icon-1400x1400.png +0 -0
  116. package/dist/ios/icons/icon-1400x1400.webp +0 -0
  117. package/dist/ios/index.html +106 -107
  118. package/dist/ios/mobile-agent.js +346 -45
  119. package/dist/ios/mobile-core.js +7303 -4590
  120. package/dist/ios/mobile-harness.js +1004 -0
  121. package/dist/ios/mobile-orbitdb.js +194 -0
  122. package/dist/ios/mobile-persona.js +80 -0
  123. package/dist/ios/mobile-privacy.js +2 -3
  124. package/dist/ios/mobile.css +286 -21
  125. package/dist/ios/mobile.html +106 -107
  126. package/dist/ios/mobile.js +300 -132
  127. package/dist/ios/routes-world.js +4 -1
  128. package/dist/ios/server.js +3 -1
  129. package/dist/ios/style.css +13 -5
  130. package/dist/ios/ui/message-renderer.js +4 -18
  131. package/dist/ios/ui/step-timeline.js +14 -1
  132. package/dist/kernel/channel-actor.js +30 -2
  133. package/dist/kernel/gate-scan.js +1 -1
  134. package/dist/kernel/index.js +33 -0
  135. package/dist/kernel/model-runtime.js +8 -1
  136. package/dist/kernel/plan.js +3 -3
  137. package/dist/kernel/roster.js +3 -3
  138. package/dist/llm/config-store.js +20 -0
  139. package/dist/llm/embedding-adapter.js +69 -0
  140. package/dist/llm/pi-ai.js +94 -34
  141. package/dist/orbitdb/memory-sync.js +70 -0
  142. package/dist/pi-ecosystem-judgment/adaptive-scan.js +1 -1
  143. package/dist/security/tool-gate.js +2 -0
  144. package/dist/setup/setup-store.js +34 -6
  145. package/dist/social/heartbeat.js +18 -5
  146. package/dist/web/bolloon-web.json +3 -3
  147. package/dist/web/client.js +74 -35
  148. package/dist/web/icons/icon-1400x1400.png +0 -0
  149. package/dist/web/icons/icon-1400x1400.webp +0 -0
  150. package/dist/web/index.html +37 -25
  151. package/dist/web/mobile-agent.js +351 -45
  152. package/dist/web/mobile-contacts.js +0 -4
  153. package/dist/web/mobile-core.js +7430 -4590
  154. package/dist/web/mobile-harness.js +1004 -0
  155. package/dist/web/mobile-orbitdb.js +194 -0
  156. package/dist/web/mobile-persona.js +80 -0
  157. package/dist/web/mobile-privacy.js +2 -3
  158. package/dist/web/mobile.css +286 -21
  159. package/dist/web/mobile.html +121 -107
  160. package/dist/web/mobile.js +409 -136
  161. package/dist/web/routes-contacts.js +94 -1
  162. package/dist/web/routes-world.js +4 -1
  163. package/dist/web/server.js +4 -2
  164. package/dist/web/style.css +13 -5
  165. package/dist/web/sw.js +1 -1
  166. package/dist/web/ui/message-renderer.js +4 -18
  167. package/dist/web/ui/step-timeline.js +14 -1
  168. package/package.json +3 -2
  169. 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
- '完全访问权限(让智能体在这台手机上点按、滑动屏幕或调用系统能力)与 Shizuku:仅官网直装版本包含,默认开启' +
57
- '(首次使用会直接带你去系统开关页确认一次,之后一直有效)、随时可以关闭;' +
58
- '应用商店下载的版本不含这两项,也没有这个能力。',
56
+ '跨 App 点按、滑动屏幕或调用系统能力所需的 Android 无障碍与 Shizuku:仅官网直装版本包含,属于可选扩展能力;' +
57
+ '手机端基础 Agent 不依赖这些权限即可直接运行。应用商店下载的版本不含跨 App 控制能力。',
59
58
  },
60
59
  {
61
60
  title: '六、你的权利与注销',
@@ -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
- max-height: 42vh;
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
- .world-feed-cards { display: flex; flex-direction: column; gap: 8px; }
386
- .world-feed-loading { font-size: 12px; color: var(--text-muted); padding: 8px 0; }
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: 10px;
392
- padding: 10px 12px;
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: 8px;
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.5;
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: 8px;
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
- display: flex;
454
- flex-direction: column; /* 上下翻卡 */
455
- gap: 16px;
456
- padding: 16px;
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-items: stretch;
464
- touch-action: pan-y; /* 垂直交给原生滚动翻卡, 水平交给 JS 做删除 reveal */
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
- flex: 0 0 auto;
472
- height: 80%; /* 不满屏: 露出下一张卡片的位置 */
473
- scroll-snap-align: start;
737
+ height: auto;
738
+ aspect-ratio: 3 / 4;
474
739
  position: relative;
475
- border-radius: 16px;
740
+ border-radius: 14px;
476
741
  overflow: hidden;
477
742
  min-height: 0;
478
743
  }