@bolloon/bolloon-agent 0.4.32 → 0.5.0

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 (157) hide show
  1. package/dist/agents/chain/explorer.js +52 -0
  2. package/dist/agents/chain/index.js +2 -0
  3. package/dist/agents/chain/onchain-trade.js +15 -1
  4. package/dist/agents/contacts/chain.js +27 -7
  5. package/dist/agents/execution-supervisor.js +493 -35
  6. package/dist/agents/external-events.js +35 -6
  7. package/dist/agents/gateway-group.js +100 -12
  8. package/dist/agents/goal-criteria.js +10 -3
  9. package/dist/agents/goal-flywheel/block-executor.js +346 -0
  10. package/dist/agents/goal-flywheel/continuation-decision.js +592 -0
  11. package/dist/agents/goal-flywheel/goal-change.js +754 -0
  12. package/dist/agents/goal-flywheel/index.js +26 -0
  13. package/dist/agents/goal-flywheel/memory-layers.js +227 -0
  14. package/dist/agents/goal-flywheel/run-closure.js +809 -0
  15. package/dist/agents/goal-flywheel/skill-candidate.js +628 -0
  16. package/dist/agents/goal-flywheel/types.js +329 -0
  17. package/dist/agents/goal-flywheel/wiring/change.js +288 -0
  18. package/dist/agents/goal-flywheel/wiring/closure.js +697 -0
  19. package/dist/agents/goal-flywheel/wiring/continuation.js +432 -0
  20. package/dist/agents/goal-flywheel/wiring/contract.js +270 -0
  21. package/dist/agents/goal-flywheel/wiring/index.js +26 -0
  22. package/dist/agents/goal-flywheel/wiring/monitor.js +254 -0
  23. package/dist/agents/goal-flywheel/wiring/seams.js +592 -0
  24. package/dist/agents/goal-flywheel/work-contract.js +478 -0
  25. package/dist/agents/goal-flywheel/work-monitor.js +488 -0
  26. package/dist/agents/goal-flywheel-wiring.js +1870 -0
  27. package/dist/agents/goal-state-reducer.js +406 -0
  28. package/dist/agents/goal-store.js +35 -1
  29. package/dist/agents/mobile-flywheel-view.js +144 -0
  30. package/dist/agents/mobile-task-actions-verify.js +74 -0
  31. package/dist/agents/mobile-task-actions.js +178 -0
  32. package/dist/agents/mobile-task-views.js +199 -0
  33. package/dist/agents/network-pulse.js +525 -27
  34. package/dist/agents/pi-sdk.js +75 -20
  35. package/dist/agents/run-store.js +18 -5
  36. package/dist/agents/skill-readiness.js +52 -10
  37. package/dist/agents/subagent-manager.js +209 -3
  38. package/dist/agents/task/task-onchain-runner.js +19 -1
  39. package/dist/agents/task/task-runner.js +36 -6
  40. package/dist/agents/task-board.js +702 -0
  41. package/dist/agents/task-group.js +524 -0
  42. package/dist/agents/task-public-text.js +89 -0
  43. package/dist/cli/commands/index.js +3 -0
  44. package/dist/cli/commands/tasks.js +977 -8
  45. package/dist/cli/identity-command.js +177 -0
  46. package/dist/cli/protocol-envelope.js +4 -0
  47. package/dist/cli/setup-wizard.js +71 -0
  48. package/dist/cli/update-commands.js +150 -24
  49. package/dist/cli-entry.js +12 -2
  50. package/dist/electron-build/agents/chain/explorer.js +59 -0
  51. package/dist/electron-build/agents/chain/explorer.js.map +1 -0
  52. package/dist/electron-build/agents/contacts/chain.js +26 -6
  53. package/dist/electron-build/agents/contacts/chain.js.map +1 -1
  54. package/dist/electron-build/agents/execution-supervisor.js +492 -34
  55. package/dist/electron-build/agents/execution-supervisor.js.map +1 -1
  56. package/dist/electron-build/agents/external-events.js +34 -5
  57. package/dist/electron-build/agents/external-events.js.map +1 -1
  58. package/dist/electron-build/agents/goal-criteria.js +10 -3
  59. package/dist/electron-build/agents/goal-criteria.js.map +1 -1
  60. package/dist/electron-build/agents/goal-flywheel/continuation-decision.js +598 -0
  61. package/dist/electron-build/agents/goal-flywheel/continuation-decision.js.map +1 -0
  62. package/dist/electron-build/agents/goal-flywheel/goal-change.js +773 -0
  63. package/dist/electron-build/agents/goal-flywheel/goal-change.js.map +1 -0
  64. package/dist/electron-build/agents/goal-flywheel/memory-layers.js +269 -0
  65. package/dist/electron-build/agents/goal-flywheel/memory-layers.js.map +1 -0
  66. package/dist/electron-build/agents/goal-flywheel/run-closure.js +818 -0
  67. package/dist/electron-build/agents/goal-flywheel/run-closure.js.map +1 -0
  68. package/dist/electron-build/agents/goal-flywheel/skill-candidate.js +642 -0
  69. package/dist/electron-build/agents/goal-flywheel/skill-candidate.js.map +1 -0
  70. package/dist/electron-build/agents/goal-flywheel/types.js +333 -0
  71. package/dist/electron-build/agents/goal-flywheel/types.js.map +1 -0
  72. package/dist/electron-build/agents/goal-flywheel/wiring/change.js +294 -0
  73. package/dist/electron-build/agents/goal-flywheel/wiring/change.js.map +1 -0
  74. package/dist/electron-build/agents/goal-flywheel/wiring/closure.js +742 -0
  75. package/dist/electron-build/agents/goal-flywheel/wiring/closure.js.map +1 -0
  76. package/dist/electron-build/agents/goal-flywheel/wiring/continuation.js +444 -0
  77. package/dist/electron-build/agents/goal-flywheel/wiring/continuation.js.map +1 -0
  78. package/dist/electron-build/agents/goal-flywheel/wiring/contract.js +279 -0
  79. package/dist/electron-build/agents/goal-flywheel/wiring/contract.js.map +1 -0
  80. package/dist/electron-build/agents/goal-flywheel/wiring/index.js +111 -0
  81. package/dist/electron-build/agents/goal-flywheel/wiring/index.js.map +1 -0
  82. package/dist/electron-build/agents/goal-flywheel/wiring/monitor.js +264 -0
  83. package/dist/electron-build/agents/goal-flywheel/wiring/monitor.js.map +1 -0
  84. package/dist/electron-build/agents/goal-flywheel/wiring/seams.js +612 -0
  85. package/dist/electron-build/agents/goal-flywheel/wiring/seams.js.map +1 -0
  86. package/dist/electron-build/agents/goal-flywheel/work-contract.js +488 -0
  87. package/dist/electron-build/agents/goal-flywheel/work-contract.js.map +1 -0
  88. package/dist/electron-build/agents/goal-flywheel/work-monitor.js +501 -0
  89. package/dist/electron-build/agents/goal-flywheel/work-monitor.js.map +1 -0
  90. package/dist/electron-build/agents/goal-flywheel-wiring.js +1962 -0
  91. package/dist/electron-build/agents/goal-flywheel-wiring.js.map +1 -0
  92. package/dist/electron-build/agents/goal-state-reducer.js +414 -0
  93. package/dist/electron-build/agents/goal-state-reducer.js.map +1 -0
  94. package/dist/electron-build/agents/goal-store.js +35 -1
  95. package/dist/electron-build/agents/goal-store.js.map +1 -1
  96. package/dist/electron-build/agents/local-signer.js +101 -0
  97. package/dist/electron-build/agents/local-signer.js.map +1 -0
  98. package/dist/electron-build/agents/network-pulse.js +531 -28
  99. package/dist/electron-build/agents/network-pulse.js.map +1 -1
  100. package/dist/electron-build/agents/pi-sdk.js +74 -19
  101. package/dist/electron-build/agents/pi-sdk.js.map +1 -1
  102. package/dist/electron-build/agents/run-store.js +20 -5
  103. package/dist/electron-build/agents/run-store.js.map +1 -1
  104. package/dist/electron-build/agents/skill-readiness.js +52 -9
  105. package/dist/electron-build/agents/skill-readiness.js.map +1 -1
  106. package/dist/electron-build/agents/task/task-runner.js +35 -5
  107. package/dist/electron-build/agents/task/task-runner.js.map +1 -1
  108. package/dist/electron-build/agents/task-board.js +761 -0
  109. package/dist/electron-build/agents/task-board.js.map +1 -0
  110. package/dist/electron-build/agents/task-contract.js +382 -0
  111. package/dist/electron-build/agents/task-contract.js.map +1 -0
  112. package/dist/electron-build/orbitdb/cid-database.js +83 -17
  113. package/dist/electron-build/orbitdb/cid-database.js.map +1 -1
  114. package/dist/electron-build/orbitdb/ipfs-node.js +31 -2
  115. package/dist/electron-build/orbitdb/ipfs-node.js.map +1 -1
  116. package/dist/electron-build/utils/dual-source.js +471 -0
  117. package/dist/electron-build/utils/dual-source.js.map +1 -0
  118. package/dist/electron-build/utils/update-manager.js +331 -57
  119. package/dist/electron-build/utils/update-manager.js.map +1 -1
  120. package/dist/electron-build/utils/update-state.js +16 -1
  121. package/dist/electron-build/utils/update-state.js.map +1 -1
  122. package/dist/electron-build/utils/version-info.js +82 -2
  123. package/dist/electron-build/utils/version-info.js.map +1 -1
  124. package/dist/index.js +103 -12
  125. package/dist/ios/chain-explorer.js +617 -0
  126. package/dist/ios/explorer.html +163 -0
  127. package/dist/ios/index.html +96 -0
  128. package/dist/ios/mobile-agent.js +2 -2
  129. package/dist/ios/mobile-contacts.js +329 -0
  130. package/dist/ios/mobile-core.js +1379 -226
  131. package/dist/ios/mobile-privacy.js +185 -0
  132. package/dist/ios/mobile.css +19 -0
  133. package/dist/ios/mobile.html +96 -0
  134. package/dist/ios/mobile.js +706 -7
  135. package/dist/ios/routes-chain-index.js +108 -0
  136. package/dist/ios/routes-contacts.js +420 -0
  137. package/dist/ios/routes-onchain-trade.js +99 -0
  138. package/dist/ios/routes-x402-info.js +1 -0
  139. package/dist/ios/server.js +762 -0
  140. package/dist/ios/task-frame-server.js +211 -0
  141. package/dist/orbitdb/cid-database.js +81 -16
  142. package/dist/orbitdb/ipfs-node.js +31 -2
  143. package/dist/utils/dual-source.js +426 -0
  144. package/dist/utils/update-cli.js +16 -21
  145. package/dist/utils/update-health.js +35 -5
  146. package/dist/utils/update-manager.js +329 -57
  147. package/dist/utils/update-state.js +16 -1
  148. package/dist/utils/version-info.js +75 -1
  149. package/dist/web/mobile-contacts.js +44 -11
  150. package/dist/web/mobile-core.js +1197 -513
  151. package/dist/web/mobile-tasks.js +339 -0
  152. package/dist/web/mobile.css +19 -0
  153. package/dist/web/mobile.html +64 -0
  154. package/dist/web/mobile.js +531 -1
  155. package/dist/web/routes-mobile-tasks.js +353 -0
  156. package/dist/web/server.js +163 -4
  157. package/package.json +3 -1
@@ -0,0 +1,185 @@
1
+ /**
2
+ * mobile-privacy.ts — 手机端隐私合规: 首启同意门 + 应用内政策摘要 + 本机数据注销
3
+ *
4
+ * 为什么单独成模块: 这三件事都必须能被单测锁住 —— 摘要少一个必填要素、同意版本号算错、
5
+ * 注销漏删一个库, 都是"上架被拒/合规缺口"级别的问题, 不能只靠肉眼看 UI。
6
+ *
7
+ * 上架要求对照 (华为/工信部口径):
8
+ * ① 首次启动必须先展示隐私政策, 用户同意前不得收集任何信息/申请任何权限 → needsPrivacyConsent + 门
9
+ * ② 隐私政策须含: 收集类型 · 用途 · 存储期限 · 第三方 SDK 清单 · 账号注销路径 → PRIVACY_SUMMARY
10
+ * ③ 必须提供注销入口且处理时限 ≤ 7 个工作日 → WIPE_TARGETS + wipeLocalData (本地即时)
11
+ */
12
+ /** localStorage 键: 记录用户已同意的政策版本 */
13
+ export const PRIVACY_CONSENT_KEY = 'bolloon_privacy_consent';
14
+ /** 政策版本: 摘要或权威页内容发生实质变化时必须 +1 → 会重新征求同意 */
15
+ export const PRIVACY_CONSENT_VERSION = '1';
16
+ /** 权威政策页 (应用市场表单要填的链接; 应用内摘要以它为准) */
17
+ export const PRIVACY_POLICY_URL = 'https://bolloon.cn/privacy.html';
18
+ /** APP 备案号: 备案完成后填入 (形如 浙ICP备XXXXXXXX号-XA), 留空时 UI 显示"备案办理中" */
19
+ export const APP_FILING_NO = '';
20
+ /** 主体联系邮箱 (政策里承诺 7 个工作日答复) */
21
+ export const PRIVACY_CONTACT = 'yuanjieliu65@gmail.com';
22
+ /** 注销时限承诺 (工作日) */
23
+ export const WIPE_SLA_WORKDAYS = 7;
24
+ /**
25
+ * 应用内政策摘要 —— 必须覆盖上架要求的必填要素。
26
+ * 单测逐个要素断言 (mobile-privacy.test.ts), 删要素即红。
27
+ */
28
+ export const PRIVACY_SUMMARY = [
29
+ {
30
+ title: '一、我们收集什么',
31
+ body: '本机生成的网络身份标识(DID)与密钥、你创建的智能体、会话与消息内容、好友与已知节点列表。' +
32
+ '这些数据默认只保存在你自己的设备上(IndexedDB),我们不设账号体系,不收集手机号、邮箱、通讯录、' +
33
+ '短信、通话记录、精确定位、设备唯一标识(IMEI/MAC/广告标识),也不做使用行为统计。',
34
+ },
35
+ {
36
+ title: '二、用途',
37
+ body: '上述数据仅用于提供你要求的功能:P2P 连接与身份验证、智能体会话、本地存储与展示。' +
38
+ '我们不用于广告、画像或向第三方出售。',
39
+ },
40
+ {
41
+ title: '三、存储位置与期限',
42
+ body: '全部保存在本机。卸载应用或在「设置 → 清除本机数据(注销)」即删除;我们服务器上没有你的副本,' +
43
+ '因此不存在"提交删除申请后还要等待"的环节。',
44
+ },
45
+ {
46
+ title: '四、第三方 SDK 与服务',
47
+ body: '你自选的大模型服务商(API Key 由你填写,你的设备直连该服务商,我们不经手);' +
48
+ '网站与安装包托管 Cloudflare / GitHub(境外)、版本号查询 npm registry、网页字体 Google Fonts。' +
49
+ '本应用不集成任何广告、行为统计或崩溃上报 SDK。若你启用微支付,链上交易记录公开且不可删除。',
50
+ },
51
+ {
52
+ title: '五、系统权限',
53
+ body: '蓝牙扫描与连接:发现并连接附近设备与好友(已声明 neverForLocation,不用于推断位置)。' +
54
+ '位置权限:仅 Android 11 及以下系统要求蓝牙扫描需要它(已限制 maxSdkVersion=30,Android 12+ 不再申请)。' +
55
+ '网络:P2P 连接与下载。相机:调用系统相机应用完成拍摄,本应用不申请相机权限。' +
56
+ '完全访问权限(让智能体在这台手机上点按、滑动屏幕或调用系统能力)与 Shizuku:仅官网直装版本包含,默认开启' +
57
+ '(首次使用会直接带你去系统开关页确认一次,之后一直有效)、随时可以关闭;' +
58
+ '应用商店下载的版本不含这两项,也没有这个能力。',
59
+ },
60
+ {
61
+ title: '六、你的权利与注销',
62
+ body: '你可以随时在本机查看、修改、删除全部数据。注销入口:设置 → 清除本机数据(注销),' +
63
+ '即时删除本机数据(异常情况最长 ' + WIPE_SLA_WORKDAYS + ' 个工作日)。' +
64
+ '已经写入公开区块链的交易记录任何服务方都无法删除。',
65
+ },
66
+ {
67
+ title: '七、联系我们',
68
+ body: '疑问或投诉请发邮件至 ' + PRIVACY_CONTACT + ',我们会在 ' + WIPE_SLA_WORKDAYS + ' 个工作日内答复。',
69
+ },
70
+ ];
71
+ /**
72
+ * 是否需要弹同意门。
73
+ * @param stored 本机已记录的同意值 (localStorage.getItem(PRIVACY_CONSENT_KEY))
74
+ * @returns true = 需要征求同意 (未同意 / 版本过期 / 值非法)
75
+ */
76
+ export function needsPrivacyConsent(stored) {
77
+ if (typeof stored !== 'string')
78
+ return true;
79
+ return stored.trim() !== PRIVACY_CONSENT_VERSION;
80
+ }
81
+ /** 同意后写入的值 */
82
+ export function consentRecord() {
83
+ return PRIVACY_CONSENT_VERSION;
84
+ }
85
+ /** 备案号展示文案 (未备案时如实说明, 不伪造编号) */
86
+ export function filingDisplay(no = APP_FILING_NO) {
87
+ const v = (no || '').trim();
88
+ return v ? `APP 备案号 ${v}` : 'APP 备案号:备案办理中';
89
+ }
90
+ /**
91
+ * 注销要清掉的东西 —— 清单必须与"我们声明收集的数据"一一对应, 少一个就是合规缺口。
92
+ * 注意: 不删 consent 记录 (同意记录不是个人信息, 且删了会在注销后立刻再弹一次门)。
93
+ */
94
+ export const WIPE_TARGETS = {
95
+ /** IndexedDB 库 (名称与各模块里的常量逐一核对过) */
96
+ databases: ['bolloon-mobile-data', 'bolloon-mobile', 'bolloon-mobile-payments', 'bolloon'],
97
+ /** localStorage 键前缀: 命中即清 */
98
+ localStoragePrefixes: ['bolloon_', 'bolloon.', 'bolloon-'],
99
+ /** 明确保留: 同意记录 + 界面偏好 (不含个人信息) */
100
+ keep: [PRIVACY_CONSENT_KEY, 'bolloon-lang', 'bolloon_theme'],
101
+ };
102
+ /** 注销后给用户看的说明 (诚实: 链上记录删不掉) */
103
+ export const WIPE_NOTICE = '已删除本机的身份标识(DID)、智能体、会话消息与钱包账本。' +
104
+ '已经写入公开区块链的交易记录无法删除,这一点任何服务方都做不到。' +
105
+ `如遇异常,我们的处理时限为 ${WIPE_SLA_WORKDAYS} 个工作日(${PRIVACY_CONTACT})。`;
106
+ /** 同意门文案 (集中在这里, 便于审计与翻译) */
107
+ export const CONSENT_TEXT = {
108
+ title: '隐私政策与权限说明',
109
+ intro: 'Bolloon 是本地优先的:没有账号体系,不收集手机号或邮箱,你的智能体、会话与消息只存在这台设备上。' +
110
+ '在你点击「同意并继续」之前,应用不会读取本机数据、不会连接网络、也不会申请任何系统权限。',
111
+ agree: '同意并继续',
112
+ decline: '不同意',
113
+ policyLink: '阅读完整隐私政策',
114
+ declinedTitle: '未同意,已停在说明页',
115
+ declinedBody: '你可以继续留在本页查阅说明,或退出应用。我们不会在此状态下收集任何信息。' +
116
+ '随时重新打开应用都可以再次选择。',
117
+ declinedReread: '重新阅读',
118
+ declinedExit: '退出应用',
119
+ };
120
+ /** 删除单个 IndexedDB 库 (供没有 reset 导出的模块使用, 如钱包库) */
121
+ function deleteDatabase(name) {
122
+ return new Promise((resolve, reject) => {
123
+ if (typeof indexedDB === 'undefined') {
124
+ resolve();
125
+ return;
126
+ }
127
+ const req = indexedDB.deleteDatabase(name);
128
+ req.onsuccess = () => resolve();
129
+ req.onerror = () => reject(req.error);
130
+ // 还有别的连接开着时会 blocked: 不等死, 如实返回 (下次启动会清掉)
131
+ req.onblocked = () => resolve();
132
+ });
133
+ }
134
+ /**
135
+ * 注销 / 清除本机数据 —— 应用内唯一的删除入口。
136
+ * 覆盖: 身份 DID+密钥库 · 智能体与会话消息库 · 支付库 · 钱包库 · localStorage 里的本机键。
137
+ * 不覆盖: 公开区块链上的历史交易 (任何服务方都删不了, 文案里已向用户说明)。
138
+ */
139
+ export async function wipeLocalData() {
140
+ const result = { deletedDatabases: [], clearedStorageKeys: [], failed: [] };
141
+ // ① 三个自带 reset 的库: 复用模块自己的实现 (它们会先关闭连接, 避免 onblocked)
142
+ const resets = [
143
+ ['bolloon-mobile-data', async () => (await import('./mobile-data.js')).resetDataDb()],
144
+ ['bolloon-mobile', async () => (await import('./mobile-agent.js')).resetAgentDb()],
145
+ ['bolloon-mobile-payments', async () => (await import('./mobile-payments.js')).resetPaymentsDb()],
146
+ ];
147
+ for (const [name, fn] of resets) {
148
+ try {
149
+ await fn();
150
+ result.deletedDatabases.push(name);
151
+ }
152
+ catch (e) {
153
+ result.failed.push(`${name}: ${e?.message || String(e)}`);
154
+ }
155
+ }
156
+ // ② 钱包库 (mobile-wallet.ts) 没有 reset 导出 → 直接删库
157
+ try {
158
+ await deleteDatabase('bolloon');
159
+ result.deletedDatabases.push('bolloon');
160
+ }
161
+ catch (e) {
162
+ result.failed.push(`bolloon: ${e?.message || String(e)}`);
163
+ }
164
+ // ③ localStorage: 按前缀清, 保留同意记录与界面偏好
165
+ try {
166
+ const keys = [];
167
+ for (let i = 0; i < localStorage.length; i++) {
168
+ const k = localStorage.key(i);
169
+ if (k)
170
+ keys.push(k);
171
+ }
172
+ const keep = WIPE_TARGETS.keep;
173
+ for (const k of keys) {
174
+ const hit = WIPE_TARGETS.localStoragePrefixes.some((p) => k.startsWith(p));
175
+ if (!hit || keep.includes(k))
176
+ continue;
177
+ localStorage.removeItem(k);
178
+ result.clearedStorageKeys.push(k);
179
+ }
180
+ }
181
+ catch (e) {
182
+ result.failed.push(`localStorage: ${e?.message || String(e)}`);
183
+ }
184
+ return result;
185
+ }
@@ -703,3 +703,22 @@ body {
703
703
  .policy-body p { font-size: 13px; line-height: 1.75; color: var(--text-secondary); margin: 0 0 10px; }
704
704
  .policy-body a { color: var(--accent); word-break: break-all; }
705
705
  .policy-meta { font-size: 12px; color: var(--text-muted); }
706
+
707
+ /* ============ 任务 tab (2026-09-25) ============ */
708
+ /* 页面里的列表/按钮都复用既有 .list / .list-item / .sheet-choice;
709
+ 这里只补两件事: 让长文本行不撑破卡片, 以及「减少动态效果」时把过渡/动画压到 0。 */
710
+ #page-tasks .list-item { align-items: flex-start; word-break: break-word; }
711
+ #page-tasks .list-item > div { min-width: 0; }
712
+ #page-tasks .section-label { word-break: break-word; }
713
+ #task-confirm-lines, #task-confirm-content { word-break: break-word; }
714
+ /* 标记: 页面顶部的签名状态行 (不能签名时用警示色, 但仍然只是一行文字) */
715
+ #tasks-signing[data-signing="no"] { color: #d08a2a; }
716
+
717
+ @media (prefers-reduced-motion: reduce) {
718
+ *, *::before, *::after {
719
+ animation-duration: 0.001ms !important;
720
+ animation-iteration-count: 1 !important;
721
+ transition-duration: 0.001ms !important;
722
+ scroll-behavior: auto !important;
723
+ }
724
+ }
@@ -104,6 +104,49 @@
104
104
  <div id="a2ui-root"></div>
105
105
  </section>
106
106
 
107
+ <!-- 任务 tab (2026-09-25): 与桌面/CLI 同一套任务闭环 —— 入群 · 发公告 · 看飞轮进度
108
+ 分工不变: 手机 = 输入 · 展示待发内容 · 设备签名确认; 桌面 = 落盘 · 执行 · 等待回复 · 证据。
109
+ 高风险动作 (入群/建群/发公告/发进群/留痕) 一律走确认页 → 设备签名 → 桌面验签。 -->
110
+ <section class="page" id="page-tasks" data-tab="tasks" hidden>
111
+ <div class="section-label" data-zh="本机授权与签名" data-en="This device: approval &amp; signing">本机授权与签名</div>
112
+ <div class="list">
113
+ <div class="list-item" id="tasks-signing-item"><span class="list-icon"><svg class="ico" viewBox="0 0 24 24"><rect x="4.5" y="10.5" width="15" height="9.5" rx="2.5"/><path d="M8 10.5V7.5a4 4 0 0 1 8 0v3"/><path d="M12 14v3"/></svg></span><span id="tasks-signing" style="flex:1">检查中…</span></div>
114
+ </div>
115
+ <div class="sheet-text" id="tasks-hint" style="font-size:12px;color:var(--text-secondary);padding:0 14px 6px"></div>
116
+ <div class="list" style="padding:0 14px 4px">
117
+ <button class="sheet-choice" id="tasks-refresh" data-zh="刷新任务数据" data-en="Refresh task data" style="width:100%">刷新任务数据</button>
118
+ </div>
119
+
120
+ <div class="section-label" data-zh="群 (与 CLI task group 同一份记录)" data-en="Groups (same records as CLI task group)">群 (与 CLI task group 同一份记录)</div>
121
+ <div class="list" id="tasks-groups"><div class="sheet-text" style="padding:0 14px">加载中…</div></div>
122
+ <div style="padding:0 14px 8px">
123
+ <input id="tasks-group-link" placeholder="群邀请链接 (orbitdb://…?type=group&amp;name=…)" style="width:100%;padding:10px 12px;border-radius:10px;border:1px solid var(--border);background:transparent;color:var(--text);font-size:14px" />
124
+ <button class="sheet-choice" id="tasks-group-join" data-zh="入群(需手机确认 + 签名)" data-en="Join group (needs on-device confirm + signature)" style="width:100%;margin-top:8px">入群(需手机确认 + 签名)</button>
125
+ <input id="tasks-group-name" placeholder="新群名称" style="width:100%;margin-top:8px;padding:10px 12px;border-radius:10px;border:1px solid var(--border);background:transparent;color:var(--text);font-size:14px" />
126
+ <button class="sheet-choice" id="tasks-group-create" data-zh="建群(需手机确认 + 签名)" data-en="Create group (needs on-device confirm + signature)" style="width:100%;margin-top:8px">建群(需手机确认 + 签名)</button>
127
+ </div>
128
+
129
+ <div class="section-label" data-zh="公告板 (与 CLI task board 同一份事实)" data-en="Task board (same facts as CLI task board)">公告板 (与 CLI task board 同一份事实)</div>
130
+ <div class="list" id="tasks-board"><div class="sheet-text" style="padding:0 14px">加载中…</div></div>
131
+ <div style="padding:0 14px 8px">
132
+ <input id="tasks-pub-capability" placeholder="能力 (例如 research)" style="width:100%;padding:10px 12px;border-radius:10px;border:1px solid var(--border);background:transparent;color:var(--text);font-size:14px" />
133
+ <input id="tasks-pub-instruction" placeholder="任务正文 (一句能执行的委托)" style="width:100%;margin-top:8px;padding:10px 12px;border-radius:10px;border:1px solid var(--border);background:transparent;color:var(--text);font-size:14px" />
134
+ <input id="tasks-pub-budget" placeholder="预算 (例如 0.05)" inputmode="decimal" style="width:100%;margin-top:8px;padding:10px 12px;border-radius:10px;border:1px solid var(--border);background:transparent;color:var(--text);font-size:14px" />
135
+ <input id="tasks-pub-deadline" placeholder="截止 (+24h / +2h / +1d, 留空=桌面默认 24h)" style="width:100%;margin-top:8px;padding:10px 12px;border-radius:10px;border:1px solid var(--border);background:transparent;color:var(--text);font-size:14px" />
136
+ <button class="sheet-choice" id="tasks-pub-submit" data-zh="发布公告(需手机确认 + 签名)" data-en="Publish announcement (needs on-device confirm + signature)" style="width:100%;margin-top:8px">发布公告(需手机确认 + 签名)</button>
137
+ </div>
138
+
139
+ <div class="section-label" data-zh="群过程痕迹 (只读, 脱敏)" data-en="Group trail (read-only, redacted)">群过程痕迹 (只读, 脱敏)</div>
140
+ <div class="list" id="tasks-trail-group-picker"></div>
141
+ <div class="list" id="tasks-trail"><div class="sheet-text" style="padding:0 14px">选一个群看这一期的痕迹</div></div>
142
+ <div style="padding:0 14px 8px">
143
+ <button class="sheet-choice" id="tasks-trail-refresh" data-zh="读群痕迹" data-en="Read group trail" style="width:100%">读群痕迹</button>
144
+ </div>
145
+
146
+ <div class="section-label" data-zh="飞轮进度 (只读, 与桌面同一状态)" data-en="Goal flywheel progress (read-only, same state as desktop)">飞轮进度 (只读, 与桌面同一状态)</div>
147
+ <div class="list" id="tasks-flywheel"><div class="sheet-text" style="padding:0 14px">加载中…</div></div>
148
+ </section>
149
+
107
150
  <!-- 我 tab -->
108
151
  <section class="page" id="page-me" data-tab="me" hidden>
109
152
  <div class="profile-card" id="profile-card">
@@ -121,6 +164,7 @@
121
164
  <div class="list-item" id="item-settings"><span class="list-icon"><svg class="ico" viewBox="0 0 24 24"><path d="M4 7.5h6M14 7.5h6M4 16.5h9M17 16.5h3"/><circle cx="12" cy="7.5" r="2.2"/><circle cx="15" cy="16.5" r="2.2"/></svg></span><span>设置</span><span class="list-arrow">›</span></div>
122
165
  <div class="list-item" id="item-wallet"><span class="list-icon"><svg class="ico" viewBox="0 0 24 24"><rect x="3" y="6.5" width="18" height="12" rx="3"/><path d="M3 10.5h18"/><circle cx="16.8" cy="14.5" r="1.3" fill="currentColor" stroke="none"/></svg></span><span>钱包</span><span class="list-arrow">›</span></div>
123
166
  <div class="list-item" id="item-judgments"><span class="list-icon"><svg class="ico" viewBox="0 0 24 24"><path d="M11 3.5l1.8 4.7 4.7 1.8-4.7 1.8L11 16.5l-1.8-4.7L4.5 10l4.7-1.8z"/><path d="M18.5 16l.6 1.6 1.6.6-1.6.6-.6 1.6-.6-1.6-1.6-.6 1.6-.6z"/></svg></span><span>判断力 API</span><span class="list-arrow">›</span></div>
167
+ <div class="list-item" id="item-contacts"><span class="list-icon"><svg class="ico" viewBox="0 0 24 24"><rect x="3.5" y="5.5" width="17" height="13" rx="2.5"/><path d="M3.5 9h17"/><circle cx="8.5" cy="14" r="1.6"/><path d="M12 13h5M12 15.5h3"/></svg></span><span>联系方式与授权</span><span class="list-arrow" id="contacts-arrow">›</span></div>
124
168
  <div class="list-item" id="item-login"><span class="list-icon"><svg class="ico" viewBox="0 0 24 24"><rect x="4.5" y="10.5" width="15" height="9.5" rx="2.5"/><path d="M8 10.5V7.5a4 4 0 0 1 8 0v3"/></svg></span><span id="login-label">登录</span><span class="list-arrow">›</span></div>
125
169
  <div class="list-item" id="item-logout"><span class="list-icon"><svg class="ico" viewBox="0 0 24 24"><path d="M14.5 4.5h3.5a2 2 0 0 1 2 2v11a2 2 0 0 1-2 2h-3.5"/><path d="M10 8.5l-3.5 3.5L10 15.5M6.5 12h8"/></svg></span><span>注销</span></div>
126
170
  </div>
@@ -132,6 +176,7 @@
132
176
  <button class="tab active" data-tab="main"><span class="tab-icon"><svg class="ico" viewBox="0 0 24 24"><rect x="3.5" y="3.5" width="7" height="7" rx="1.6"/><rect x="13.5" y="3.5" width="7" height="7" rx="1.6"/><rect x="3.5" y="13.5" width="7" height="7" rx="1.6"/><rect x="13.5" y="13.5" width="7" height="7" rx="1.6"/></svg></span><span>首页</span></button>
133
177
  <button class="tab" data-tab="friends"><span class="tab-icon"><svg class="ico" viewBox="0 0 24 24"><circle cx="9" cy="8" r="3.2"/><path d="M3.5 19c.8-3 3-4.6 5.5-4.6S13.7 16 14.5 19"/><path d="M17 8v6M14 11h6"/></svg></span><span>好友</span></button>
134
178
  <button class="tab" data-tab="network"><span class="tab-icon"><svg class="ico" viewBox="0 0 24 24"><circle cx="12" cy="12" r="8.5"/><path d="M3.5 12h17"/><path d="M12 3.5c2.3 2.3 3.5 5.3 3.5 8.5s-1.2 6.2-3.5 8.5c-2.3-2.3-3.5-5.3-3.5-8.5S9.7 5.8 12 3.5z"/></svg></span><span>网络</span></button>
179
+ <button class="tab" data-tab="tasks"><span class="tab-icon"><svg class="ico" viewBox="0 0 24 24"><path d="M4 7.5h10M4 12h7M4 16.5h12"/><path d="M18 5.5l1.6 1.6L22 4.5"/><path d="M18 14.5l1.6 1.6L22 13.5"/></svg></span><span>任务</span></button>
135
180
  <button class="tab" data-tab="me"><span class="tab-icon"><svg class="ico" viewBox="0 0 24 24"><circle cx="12" cy="8.5" r="4"/><path d="M4.5 20.5a7.5 7.5 0 0 1 15 0"/></svg></span><span>我</span></button>
136
181
  </nav>
137
182
 
@@ -235,3 +280,54 @@ if ('serviceWorker' in navigator) {
235
280
  </script>
236
281
  </body>
237
282
  </html>
283
+
284
+ <!-- 联系方式与持久授权 (2026-09-19): 手机确认一次, Agent 长期自动使用 -->
285
+ <div class="sheet" id="contacts-sheet" hidden>
286
+ <div class="sheet-inner">
287
+ <div class="sheet-title">联系方式与授权</div>
288
+ <div class="sheet-text" id="contacts-effective">加载中...</div>
289
+ <div class="sheet-text" id="contacts-signing" style="font-size:12px;color:var(--text-secondary)"></div>
290
+
291
+ <div id="contacts-approvals"></div>
292
+
293
+ <div class="sheet-title" style="margin-top:10px">我的联系方式</div>
294
+ <div id="contacts-list"><div class="sheet-text">加载中...</div></div>
295
+
296
+ <div style="margin-top:10px">
297
+ <input id="contacts-value" placeholder="手机号 (+86...) 或 邮箱" style="width:100%;padding:10px 12px;border-radius:10px;border:1px solid var(--border);background:transparent;color:var(--text);font-size:14px" />
298
+ <div style="display:flex;gap:8px;margin-top:8px">
299
+ <button class="sheet-choice" id="contacts-bind" style="flex:1">绑定并发送验证码</button>
300
+ </div>
301
+ <input id="contacts-code" placeholder="收到的验证码" inputmode="numeric" style="width:100%;margin-top:8px;padding:10px 12px;border-radius:10px;border:1px solid var(--border);background:transparent;color:var(--text);font-size:14px" />
302
+ <button class="sheet-choice" id="contacts-verify" style="margin-top:8px;width:100%">验证</button>
303
+ </div>
304
+
305
+ <div class="sheet-title" style="margin-top:12px">让 Bolloon 代表你联系外部的人</div>
306
+ <div class="sheet-text" id="contacts-willnot" style="font-size:12px"></div>
307
+ <div class="sheet-inner-choices" id="contacts-choices" style="margin-top:8px"></div>
308
+ <div class="sheet-inner-choices">
309
+ <button class="sheet-choice" id="contacts-revoke-all">撤销全部授权</button>
310
+ <button class="sheet-choice sheet-cancel" id="contacts-close">关闭</button>
311
+ </div>
312
+ </div>
313
+ </div>
314
+
315
+ <!-- 任务动作确认页 (2026-09-25): 展示待发内容 → 手机确认 → 设备签名 → 桌面验签执行
316
+ 高风险动作不许绕过这里: 入群 / 建群 / 发公告 / 发进群 / 过程留痕 都走这一个入口。 -->
317
+ <div class="sheet" id="task-confirm-sheet" hidden>
318
+ <div class="sheet-inner">
319
+ <div class="sheet-title" id="task-confirm-title">确认这个动作</div>
320
+ <div class="sheet-text" id="task-confirm-lines" style="font-size:12px"></div>
321
+ <div class="sheet-text" id="task-confirm-what" style="font-size:12px;color:var(--text-secondary)"></div>
322
+ <div id="task-confirm-group-wrap" hidden style="margin-top:8px">
323
+ <div class="sheet-text" data-zh="发到哪个群" data-en="Which group" style="font-size:12px"></div>
324
+ <div class="list" id="task-confirm-group"></div>
325
+ </div>
326
+ <div id="task-confirm-fields" style="margin-top:8px"></div>
327
+ <button class="sheet-choice" id="task-confirm-preview" hidden data-zh="预览要发进群的那一行" data-en="Preview the exact line to be posted">预览要发进群的那一行</button>
328
+ <div class="sheet-title" id="task-confirm-content-title" style="margin-top:10px" hidden data-zh="要发进群的内容 (原文)" data-en="Content to be posted (verbatim)">要发进群的内容 (原文)</div>
329
+ <div class="sheet-text" id="task-confirm-content" style="font-size:12px;white-space:pre-wrap;word-break:break-word" hidden></div>
330
+ <button class="sheet-choice" id="task-confirm-yes">确认并签名</button>
331
+ <button class="sheet-choice sheet-cancel" id="task-confirm-no">取消</button>
332
+ </div>
333
+ </div>