@bolloon/bolloon-agent 0.4.4 → 0.4.5

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (201) hide show
  1. package/README.md +135 -135
  2. package/bin/bolloon-cli.cjs +183 -183
  3. package/bin/bolloon-daemon.sh +207 -0
  4. package/bin/bolloon.cjs +0 -0
  5. package/dist/agents/constraint-layer.js +19 -19
  6. package/dist/agents/judgment-protocol.js +14 -14
  7. package/dist/agents/pi-sdk-types.js +12 -12
  8. package/dist/agents/pi-sdk.js +90 -90
  9. package/dist/agents/skill-organizer.js +19 -19
  10. package/dist/agents/workflow-pivot-loop.js +2 -2
  11. package/dist/bollharness/src/scripts/deploy-guard.js +8 -8
  12. package/dist/bollharness-integration/context-router-judgment.js +4 -4
  13. package/dist/bollharness-integration/context-router.js +292 -292
  14. package/dist/bollharness-integration/gate-state-machine.js +13 -13
  15. package/dist/bollharness-integration/llm-judgment-engine.js +134 -134
  16. package/dist/bollharness-integration/skill-adapter.js +21 -21
  17. package/dist/bootstrap/chat-archiver.js +14 -14
  18. package/dist/bootstrap/context-os.js +24 -24
  19. package/dist/bootstrap/memory-compressor.js +13 -13
  20. package/dist/cli-entry.js +36 -36
  21. package/dist/constraint-runtime/reference_data/archive_surface_snapshot.json +63 -0
  22. package/dist/constraint-runtime/reference_data/commands_snapshot.json +1037 -0
  23. package/dist/constraint-runtime/reference_data/subsystems/assistant.json +8 -0
  24. package/dist/constraint-runtime/reference_data/subsystems/bootstrap.json +8 -0
  25. package/dist/constraint-runtime/reference_data/subsystems/bridge.json +32 -0
  26. package/dist/constraint-runtime/reference_data/subsystems/buddy.json +13 -0
  27. package/dist/constraint-runtime/reference_data/subsystems/cli.json +26 -0
  28. package/dist/constraint-runtime/reference_data/subsystems/components.json +32 -0
  29. package/dist/constraint-runtime/reference_data/subsystems/constants.json +28 -0
  30. package/dist/constraint-runtime/reference_data/subsystems/coordinator.json +8 -0
  31. package/dist/constraint-runtime/reference_data/subsystems/entrypoints.json +15 -0
  32. package/dist/constraint-runtime/reference_data/subsystems/hooks.json +32 -0
  33. package/dist/constraint-runtime/reference_data/subsystems/keybindings.json +21 -0
  34. package/dist/constraint-runtime/reference_data/subsystems/memdir.json +15 -0
  35. package/dist/constraint-runtime/reference_data/subsystems/migrations.json +18 -0
  36. package/dist/constraint-runtime/reference_data/subsystems/moreright.json +8 -0
  37. package/dist/constraint-runtime/reference_data/subsystems/native_ts.json +11 -0
  38. package/dist/constraint-runtime/reference_data/subsystems/outputStyles.json +8 -0
  39. package/dist/constraint-runtime/reference_data/subsystems/plugins.json +9 -0
  40. package/dist/constraint-runtime/reference_data/subsystems/remote.json +11 -0
  41. package/dist/constraint-runtime/reference_data/subsystems/schemas.json +8 -0
  42. package/dist/constraint-runtime/reference_data/subsystems/screens.json +10 -0
  43. package/dist/constraint-runtime/reference_data/subsystems/server.json +10 -0
  44. package/dist/constraint-runtime/reference_data/subsystems/services.json +32 -0
  45. package/dist/constraint-runtime/reference_data/subsystems/skills.json +27 -0
  46. package/dist/constraint-runtime/reference_data/subsystems/state.json +13 -0
  47. package/dist/constraint-runtime/reference_data/subsystems/types.json +18 -0
  48. package/dist/constraint-runtime/reference_data/subsystems/upstreamproxy.json +9 -0
  49. package/dist/constraint-runtime/reference_data/subsystems/utils.json +32 -0
  50. package/dist/constraint-runtime/reference_data/subsystems/vim.json +12 -0
  51. package/dist/constraint-runtime/reference_data/subsystems/voice.json +8 -0
  52. package/dist/constraint-runtime/reference_data/tools_snapshot.json +922 -0
  53. package/dist/context-compaction/auto-compact.js +7 -7
  54. package/dist/electron/config.js.map +1 -0
  55. package/dist/electron/dialogs.js.map +1 -0
  56. package/dist/electron/first-run.js +54 -54
  57. package/dist/electron/first-run.js.map +1 -0
  58. package/dist/electron/ipc.js.map +1 -0
  59. package/dist/electron/logger.js.map +1 -0
  60. package/dist/electron/main.js.map +1 -0
  61. package/dist/electron/menu.js.map +1 -0
  62. package/dist/electron/paths.js.map +1 -0
  63. package/dist/electron/server.js.map +1 -0
  64. package/dist/electron/tray.js.map +1 -0
  65. package/dist/electron/window.js.map +1 -0
  66. package/dist/electron-build/electron/first-run.js +54 -54
  67. package/dist/electron-preload.js.map +1 -1
  68. package/dist/electron.js.map +1 -1
  69. package/dist/index.js +112 -112
  70. package/dist/llm/llm-judgment-client.js +102 -102
  71. package/dist/llm/pi-ai.js +48 -48
  72. package/dist/llm/system-prompt/layers/channel/human-async.md +41 -41
  73. package/dist/llm/system-prompt/layers/channel/local.md +14 -14
  74. package/dist/llm/system-prompt/layers/channel/p2p-agent.md +18 -18
  75. package/dist/llm/system-prompt/layers/channel/p2p-peer-sync.md +51 -51
  76. package/dist/llm/system-prompt/layers/channel/p2p-proactive.md +43 -43
  77. package/dist/llm/system-prompt/layers/channel/p2p-visitor.md +19 -19
  78. package/dist/llm/system-prompt/layers/channel/session-handoff.md +61 -61
  79. package/dist/llm/system-prompt/layers/core/artifacts_storage.md +89 -89
  80. package/dist/llm/system-prompt/layers/core/evenhandedness.md +21 -21
  81. package/dist/llm/system-prompt/layers/core/external-engagement.md +73 -73
  82. package/dist/llm/system-prompt/layers/core/hibs_reminders.md +15 -15
  83. package/dist/llm/system-prompt/layers/core/identity.md +48 -48
  84. package/dist/llm/system-prompt/layers/core/knowledge.md +17 -17
  85. package/dist/llm/system-prompt/layers/core/memory_system.md +12 -12
  86. package/dist/llm/system-prompt/layers/core/network_filesystem.md +28 -28
  87. package/dist/llm/system-prompt/layers/core/refusal.md +37 -37
  88. package/dist/llm/system-prompt/layers/core/tone.md +31 -31
  89. package/dist/llm/system-prompt/layers/core/tools.thin.md +13 -13
  90. package/dist/llm/system-prompt/layers/core/wellbeing.md +41 -41
  91. package/dist/llm/system-prompt/layers/role/architect.md +20 -20
  92. package/dist/llm/system-prompt/layers/role/expert.md +19 -19
  93. package/dist/llm/system-prompt/layers/role/implementer.md +15 -15
  94. package/dist/llm/system-prompt/layers/role/security.md +15 -15
  95. package/dist/llm/system-prompt/layers/tool/artifacts.md +72 -72
  96. package/dist/llm/system-prompt/layers/tool/bash.md +25 -25
  97. package/dist/llm/system-prompt/layers/tool/goal_handoff.md +77 -77
  98. package/dist/llm/system-prompt/layers/tool/hibs_api.md +171 -171
  99. package/dist/llm/system-prompt/layers/tool/image_search.md +70 -70
  100. package/dist/llm/system-prompt/layers/tool/manifest.md +89 -89
  101. package/dist/llm/system-prompt/layers/tool/mcp_apps.md +53 -53
  102. package/dist/llm/system-prompt/layers/tool/p2p_request.md +61 -61
  103. package/dist/llm/system-prompt/layers/tool/web_search.md +83 -83
  104. package/dist/llm/tool-manifest/ask_user_input.js +1 -1
  105. package/dist/llm/tool-manifest/bash.js +3 -3
  106. package/dist/llm/tool-manifest/create_file.js +4 -4
  107. package/dist/llm/tool-manifest/fetch_sports_data.js +3 -3
  108. package/dist/llm/tool-manifest/image_search.js +2 -2
  109. package/dist/llm/tool-manifest/index.js +59 -0
  110. package/dist/llm/tool-manifest/mcp.js +2 -2
  111. package/dist/llm/tool-manifest/message_compose.js +3 -3
  112. package/dist/llm/tool-manifest/places.js +2 -2
  113. package/dist/llm/tool-manifest/present_files.js +1 -1
  114. package/dist/llm/tool-manifest/recipe.js +2 -2
  115. package/dist/llm/tool-manifest/str_replace.js +5 -5
  116. package/dist/llm/tool-manifest/view.js +3 -3
  117. package/dist/llm/tool-manifest/weather.js +4 -4
  118. package/dist/llm/tool-manifest/web.js +4 -4
  119. package/dist/pi-ecosystem-judgment/causal-judge.js +51 -51
  120. package/dist/pi-ecosystem-judgment/distill-prompt.js +42 -42
  121. package/dist/pi-ecosystem-judgment/distillation.js +14 -14
  122. package/dist/pi-ecosystem-judgment/human-value-store.js +1 -1
  123. package/dist/pi-ecosystem-judgment/monitor-gate.js +28 -28
  124. package/dist/pi-ecosystem-judgment/value-injection.js +102 -102
  125. package/dist/pi-ecosystem-mcp/index.js +146 -5
  126. package/dist/security/context-router-tool.js +15 -15
  127. package/dist/utils/auto-update.js.map +1 -0
  128. package/dist/web/api-config.html +779 -779
  129. package/dist/web/client-hearth.js +10 -10
  130. package/dist/web/client.js.map +7 -0
  131. package/dist/web/components/wallet-viem.mjs +118 -118
  132. package/dist/web/edge-auth-client.js +120 -0
  133. package/dist/web/index.html +472 -472
  134. package/dist/web/manifest.json +20 -20
  135. package/dist/web/server.js +34 -67
  136. package/dist/web/style.css +4946 -4946
  137. package/package.json +195 -195
  138. package/scripts/build-cli.js +215 -215
  139. package/scripts/build-web.ts +130 -130
  140. package/scripts/postinstall.js +152 -152
  141. package/bin/bolloon.js +0 -157
  142. package/dist/pi-ecosystem-colony/index.js +0 -365
  143. package/dist/social/ant-colony/AdaptiveHeartbeat.js +0 -101
  144. package/dist/social/ant-colony/PheromoneEngine.js +0 -227
  145. package/dist/social/ant-colony/index.js +0 -6
  146. package/dist/social/ant-colony/types.js +0 -24
  147. package/dist/storage/trajectory.js +0 -101
  148. package/dist/test/ai-judgment-test.js +0 -80
  149. package/dist/test/bollharness-integration.test.js +0 -318
  150. package/dist/test/channel-agent-multi-dialogue.js +0 -205
  151. package/dist/test/channel-heartbeat-agent-test.js +0 -201
  152. package/dist/test/constraint-layer.test.js +0 -164
  153. package/dist/test/diap-identity-test.js +0 -172
  154. package/dist/test/diap-quick-test.js +0 -62
  155. package/dist/test/global-shared-context.test.js +0 -315
  156. package/dist/test/harness-judgment-injection.test.js +0 -246
  157. package/dist/test/harness-workflow-integrator-test.js +0 -228
  158. package/dist/test/human-value-store.test.js +0 -243
  159. package/dist/test/hybrid-integration-test.js +0 -118
  160. package/dist/test/hybrid-messenger-verify.js +0 -55
  161. package/dist/test/iroh-bistream-debug.js +0 -38
  162. package/dist/test/iroh-communication.test.js +0 -66
  163. package/dist/test/iroh-debug-test.js +0 -57
  164. package/dist/test/iroh-diap-test.js +0 -71
  165. package/dist/test/iroh-direct-connect.js +0 -55
  166. package/dist/test/iroh-e2e-fixed.js +0 -89
  167. package/dist/test/iroh-e2e-same-process.js +0 -63
  168. package/dist/test/iroh-e2e.js +0 -66
  169. package/dist/test/iroh-final-e2e.js +0 -72
  170. package/dist/test/iroh-relay-test.js +0 -37
  171. package/dist/test/iroh-simple-test.js +0 -41
  172. package/dist/test/iroh-transport-verify.js +0 -54
  173. package/dist/test/iroh-transport.test.js +0 -37
  174. package/dist/test/iroh-two-nodes.js +0 -70
  175. package/dist/test/iroh-verify.js +0 -44
  176. package/dist/test/judgment-decision.test.js +0 -219
  177. package/dist/test/llm-judgment-integration.test.js +0 -220
  178. package/dist/test/p2p-agent-complex-dialogue.js +0 -385
  179. package/dist/test/p2p-agent-dialogue.js +0 -341
  180. package/dist/test/p2p-agent-full-bidirectional.js +0 -510
  181. package/dist/test/p2p-agent-harness-flow.js +0 -437
  182. package/dist/test/p2p-agent-harness-single.js +0 -143
  183. package/dist/test/p2p-ai-dialogue-test.js +0 -318
  184. package/dist/test/p2p-cid-connect-test.js +0 -195
  185. package/dist/test/p2p-connect-receiver.js +0 -69
  186. package/dist/test/p2p-doc-transfer.js +0 -110
  187. package/dist/test/p2p-identity-page-test.js +0 -77
  188. package/dist/test/p2p-iroh-test.js +0 -171
  189. package/dist/test/p2p-minimal-test.js +0 -241
  190. package/dist/test/p2p-node-1.js +0 -148
  191. package/dist/test/p2p-node-2.js +0 -148
  192. package/dist/test/p2p-server.js +0 -281
  193. package/dist/test/p2p-two-nodes-test.js +0 -438
  194. package/dist/test/pi-sdk.test.js +0 -44
  195. package/dist/test/set-persona.js +0 -40
  196. package/dist/test/simple.test.js +0 -9
  197. package/dist/test/storage-integration.test.js +0 -150
  198. package/dist/test/subagent-manager.test.js +0 -276
  199. package/dist/test/test-gate-flow.test.js +0 -81
  200. package/dist/test/workflow-engine.test.js +0 -87
  201. package/dist/test/workflow-pivot-loop.test.js +0 -246
@@ -1,472 +1,472 @@
1
- <!DOCTYPE html>
2
- <html lang="zh-CN" data-theme="dark">
3
- <head>
4
- <meta charset="UTF-8">
5
- <meta name="viewport" content="width=device-width, initial-scale=1.0">
6
- <title>Bolloon Agent</title>
7
-
8
- <!-- Favicon -->
9
- <link rel="icon" type="image/x-icon" href="./icons/favicon.ico">
10
- <link rel="icon" type="image/png" sizes="32x32" href="./icons/favicon-32x32.png">
11
- <link rel="icon" type="image/png" sizes="16x16" href="./icons/favicon-16x16.png">
12
-
13
- <!-- Apple Touch Icon -->
14
- <link rel="apple-touch-icon" href="./icons/apple-touch-icon.png">
15
-
16
- <!-- PWA Manifest -->
17
- <link rel="manifest" href="./manifest.json">
18
-
19
- <!-- 2026-06-11: 移除 Google Fonts + jsdelivr 外部 CDN 阻塞 — 在大陆/跨公网 timeout 拖慢首屏/返回主页
20
- 字体: style.css 只用字面量 'JetBrains Mono', 系统有就用, 没有自动 fall back monospace
21
- marked/qrcode: 改 async 不阻塞 (下载失败时本地降级到 escape 文本, 不影响主聊天) -->
22
- <link rel="stylesheet" href="./style.css">
23
- <script async src="https://cdn.jsdelivr.net/npm/marked/marked.min.js"></script>
24
- <script async src="https://cdn.jsdelivr.net/npm/qrcode@1.5.3/build/qrcode.min.js"></script>
25
- </head>
26
- <body>
27
- <div class="app-container">
28
- <aside class="sidebar" id="sidebar">
29
- <div class="sidebar-header">
30
- <button id="sidebar-toggle" class="sidebar-toggle" title="收起侧边栏">
31
- <svg width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
32
- <polyline points="15 18 9 12 15 6"></polyline>
33
- </svg>
34
- </button>
35
- <span class="sidebar-brand">
36
- <span class="brand-icon">◈</span>
37
- <span class="brand-text">Bolloon</span>
38
- </span>
39
- <!-- 2026-06-11: 加载 Session 文件夹按钮删除 (2026-06-16: 残留注释 + input 占位同步清除) -->
40
- </div>
41
-
42
- <div class="sidebar-section">
43
- <div class="section-header">
44
- <span class="section-title">智能体</span>
45
- <!-- 2026-06-11: catalog-add-btn (添加智能体) 删除 -->
46
- </div>
47
- <button id="new-channel-btn" class="section-action" title="新建智能体">
48
- <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
49
- <line x1="12" y1="5" x2="12" y2="19"></line>
50
- <line x1="5" y1="12" x2="19" y2="12"></line>
51
- </svg>
52
- <span>新建智能体</span>
53
- </button>
54
- <ul class="channel-list" id="channel-list"></ul>
55
- </div>
56
-
57
- <!-- v3: 本地/远端分隔线 — 可拖拽改变两边高度 -->
58
- <div id="sidebar-split-handle" title="拖动调整上方/下方高度">
59
- <div class="split-handle-grip"></div>
60
- </div>
61
-
62
- <!-- v3 远端 P2P 好友 — 显式分享 + 持久化连接 -->
63
- <div class="sidebar-section" id="remote-agents-section">
64
- <div class="section-header is-compact is-clickable" id="remote-agents-header">
65
- <span class="section-header-row">
66
- <span id="remote-agents-toggle">▼</span>
67
- <span class="section-title">P2P 好友</span>
68
- </span>
69
- <span class="section-header-actions">
70
- <button id="p2p-toggle-all-btn" class="sidebar-mini-btn" title="切换全部展开/折叠">⊞ 展开</button>
71
- <button id="show-my-p2p-id-btn" class="sidebar-mini-btn" title="查看并复制我的 P2P publicKey">我的 ID</button>
72
- <button id="add-p2p-peer-btn" class="sidebar-mini-btn" title="添加 P2P 好友 (输入对方的 publicKey)">+ 好友</button>
73
- </span>
74
- </div>
75
- <ul class="channel-list" id="remote-channel-list">
76
- <li class="sidebar-empty-hint">(暂无好友, 点 + 添加)</li>
77
- </ul>
78
- </div>
79
-
80
- <div class="sidebar-footer">
81
- <div class="user-avatar" id="user-avatar" title="点击查看 DID 身份">
82
- <span class="avatar-letter" id="avatar-letter">?</span>
83
- </div>
84
- <div class="user-info">
85
- <span class="user-name" id="user-name" title="点击修改名字" style="cursor:pointer;">加载中...</span>
86
- <span class="user-did" id="user-did"></span>
87
- </div>
88
- <div class="agent-status">
89
- <span class="status-dot"></span>
90
- <span class="status-text">已连接</span>
91
- </div>
92
- </div>
93
- </aside>
94
-
95
- <main class="main">
96
- <header class="header">
97
- <div class="header-left">
98
- <span class="channel-indicator" id="channel-indicator"></span>
99
- <h1 id="channel-name">Bolloon Agent</h1>
100
- </div>
101
- <div class="header-right">
102
- <button id="theme-toggle" class="theme-toggle" title="切换主题">
103
- <svg class="sun-icon" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
104
- <circle cx="12" cy="12" r="5"></circle>
105
- <line x1="12" y1="1" x2="12" y2="3"></line>
106
- <line x1="12" y1="21" x2="12" y2="23"></line>
107
- <line x1="4.22" y1="4.22" x2="5.64" y2="5.64"></line>
108
- <line x1="18.36" y1="18.36" x2="19.78" y2="19.78"></line>
109
- <line x1="1" y1="12" x2="3" y2="12"></line>
110
- <line x1="21" y1="12" x2="23" y2="12"></line>
111
- <line x1="4.22" y1="19.78" x2="5.64" y2="18.36"></line>
112
- <line x1="18.36" y1="5.64" x2="19.78" y2="4.22"></line>
113
- </svg>
114
- <svg class="moon-icon" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
115
- <path d="M21 12.79A9 9 0 1 1 11.21 3 7 7 0 0 0 21 12.79z"></path>
116
- </svg>
117
- </button>
118
- <button id="api-config-btn" class="header-action" title="API 配置">
119
- <svg width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
120
- <circle cx="12" cy="12" r="3"></circle>
121
- <path d="M19.4 15a1.65 1.65 0 0 0 .33 1.82l.06.06a2 2 0 0 1 0 2.83 2 2 0 0 1-2.83 0l-.06-.06a1.65 1.65 0 0 0-1.82-.33 1.65 1.65 0 0 0-1 1.51V21a2 2 0 0 1-2 2 2 2 0 0 1-2-2v-.09A1.65 1.65 0 0 0 9 19.4a1.65 1.65 0 0 0-1.82.33l-.06.06a2 2 0 0 1-2.83 0 2 2 0 0 1 0-2.83l.06-.06a1.65 1.65 0 0 0 .33-1.82 1.65 1.65 0 0 0-1.51-1H3a2 2 0 0 1-2-2 2 2 0 0 1 2-2h.09A1.65 1.65 0 0 0 4.6 9a1.65 1.65 0 0 0-.33-1.82l-.06-.06a2 2 0 0 1 0-2.83 2 2 0 0 1 2.83 0l.06.06a1.65 1.65 0 0 0 1.82.33H9a1.65 1.65 0 0 0 1-1.51V3a2 2 0 0 1 2-2 2 2 0 0 1 2 2v.09a1.65 1.65 0 0 0 1 1.51 1.65 1.65 0 0 0 1.82-.33l.06-.06a2 2 0 0 1 2.83 0 2 2 0 0 1 0 2.83l-.06.06a1.65 1.65 0 0 0-.33 1.82V9a1.65 1.65 0 0 0 1.51 1H21a2 2 0 0 1 2 2 2 2 0 0 1-2 2h-.09a1.65 1.65 0 0 0-1.51 1z"></path>
122
- </svg>
123
- </button>
124
- <!-- v3: 顶栏 P2P 按钮 (旧 iroh/Diap 路径) 已移除, 改用侧边栏 "P2P 好友" → "+ 好友" -->
125
- <button id="wallet-btn" class="header-action" title="钱包管理">
126
- <svg width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
127
- <path d="M21 12V7a2 2 0 0 0-2-2H5a2 2 0 0 0-2 2v10a2 2 0 0 0 2 2h14a2 2 0 0 0 2-2v-3"></path>
128
- <circle cx="17" cy="12" r="1.5" fill="currentColor"></circle>
129
- <path d="M3 7l3-3h12l3 3"></path>
130
- </svg>
131
- <span id="wallet-badge" class="task-badge" style="display:none;">0</span>
132
- </button>
133
- <button id="judgments-btn" class="header-action" title="我的判断">
134
- <svg width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
135
- <path d="M12 2L4 6v6c0 5 3.5 9.5 8 10 4.5-.5 8-5 8-10V6l-8-4z"></path>
136
- <path d="M9 12l2 2 4-4"></path>
137
- </svg>
138
- <span id="judgments-badge" class="task-badge" style="display:none;">0</span>
139
- </button>
140
- </div>
141
- </header>
142
-
143
- <!-- P2P Network Modal (React) -->
144
- <div id="p2p-modal-root"></div>
145
-
146
- <!-- Task Queue Modal -->
147
- <div id="task-modal" class="modal">
148
- <div class="modal-content modal-wide">
149
- <div class="modal-header">
150
- <h2>任务队列</h2>
151
- <button id="task-modal-close" class="modal-close">&times;</button>
152
- </div>
153
- <div class="modal-body">
154
- <div class="task-toolbar">
155
- <button id="task-add-btn" class="btn-primary btn-sm">+ 新建任务</button>
156
- <button id="task-execute-next-btn" class="btn-secondary btn-sm">▶ 执行下一个</button>
157
- </div>
158
- <div id="task-list" class="task-list">
159
- <div class="task-empty">暂无任务,点击上方按钮创建</div>
160
- </div>
161
- </div>
162
- </div>
163
- </div>
164
-
165
-
166
- <!-- Create Task Modal -->
167
- <div id="create-task-modal" class="modal">
168
- <div class="modal-content">
169
- <div class="modal-header">
170
- <h2>新建任务</h2>
171
- <button id="create-task-modal-close" class="modal-close">&times;</button>
172
- </div>
173
- <div class="modal-body">
174
- <div class="form-group">
175
- <label>任务类型</label>
176
- <select id="task-type">
177
- <option value="chat">对话</option>
178
- <option value="read">读取文档</option>
179
- <option value="summarize">总结文档</option>
180
- </select>
181
- </div>
182
- <div class="form-group">
183
- <label>任务标题</label>
184
- <input type="text" id="task-title" placeholder="输入任务标题">
185
- </div>
186
- <div class="form-group">
187
- <label>任务描述</label>
188
- <textarea id="task-desc" placeholder="输入任务描述或内容" rows="3"></textarea>
189
- </div>
190
- <div class="btn-group">
191
- <button id="task-cancel-btn" class="btn-secondary">取消</button>
192
- <button id="task-create-btn" class="btn-primary">创建并执行</button>
193
- </div>
194
- </div>
195
- </div>
196
- </div>
197
-
198
- <!-- Judgments Modal (v1 核心) -->
199
- <div id="judgments-modal" class="modal">
200
- <div class="modal-content modal-wide">
201
- <div class="modal-header">
202
- <h2>我的判断</h2>
203
- <button id="judgments-modal-close" class="modal-close">&times;</button>
204
- </div>
205
- <div class="modal-body">
206
- <div class="form-group">
207
- <label>判断 (decision)</label>
208
- <textarea id="judgment-decision" rows="2" placeholder="例: 不在时让 AI 替我做决定"></textarea>
209
- </div>
210
- <div class="form-group">
211
- <label>理由 (reason, 可选)</label>
212
- <input type="text" id="judgment-reason" placeholder="例: 信任 Bolloon 的判断存储">
213
- </div>
214
- <div class="form-group judgment-form-row">
215
- <label>分类</label>
216
- <div class="judgment-polarity-toggle" id="judgment-polarity-toggle">
217
- <label class="polarity-opt active" data-polarity="positive">
218
- <input type="radio" name="judgment-polarity" value="positive" checked>
219
- <span>▲ 正向 <small>采纳</small></span>
220
- </label>
221
- <label class="polarity-opt" data-polarity="negative">
222
- <input type="radio" name="judgment-polarity" value="negative">
223
- <span>▼ 负向 <small>否决/避免</small></span>
224
- </label>
225
- </div>
226
- <details class="judgment-advanced-fold" style="margin-left:auto;">
227
- <summary style="font-size:11px;color:#6b7280;cursor:pointer;list-style:none;">高级 (领域/风险)</summary>
228
- <div style="display:flex;gap:10px;padding:6px 0 0;flex-wrap:wrap;font-size:11px;">
229
- <label>领域
230
- <select id="judgment-domain">
231
- <option value="general">general</option>
232
- <option value="code">code</option>
233
- <option value="architecture">architecture</option>
234
- <option value="security">security</option>
235
- <option value="testing">testing</option>
236
- </select>
237
- </label>
238
- <label>风险
239
- <select id="judgment-stakes">
240
- <option value="medium">medium</option>
241
- <option value="low">low</option>
242
- <option value="high">high</option>
243
- <option value="critical">critical</option>
244
- </select>
245
- </label>
246
- </div>
247
- </details>
248
- </div>
249
- <div class="btn-group">
250
- <button id="judgment-submit-btn" class="btn-primary">记录</button>
251
- <button id="judgment-import-btn" class="btn-secondary" title="从 .json / .yaml / .md / .txt / .html 文件批量导入">导入文件</button>
252
- <button id="judgment-cleanup-btn" class="btn-secondary" title="软删除测试灌水数据: loadAll 测试/测试原则 等启发式匹配">清理测试数据</button>
253
- <input type="file" id="judgment-import-file" accept=".json,.yaml,.yml,.md,.txt,.html,.htm" style="display:none">
254
- </div>
255
- <div id="judgment-error" class="form-info judgment-error"></div>
256
- <!-- v3 重做: tab 切换 — 默认显示当前 channel 的 judgment 上下文, 切换后才是全部 -->
257
- <div id="judgments-tabs" class="judgment-tab-bar">
258
- <button class="judgment-tab active" data-tab="channel">
259
- 本 channel <span id="judgments-tab-channel-name" class="tab-channel-name"></span>
260
- </button>
261
- <button class="judgment-tab" data-tab="global">全局</button>
262
- </div>
263
- <!-- 2026-07-22 简化: 正向 / 负向 两个主分类 (替换原 6 个 status tab)
264
- 正向 = 采纳类 (approve/modify/escalate), 会注入 prompt 复用
265
- 负向 = 否决/被推翻 (reject/rejected/superseded), 负向回收为避免清单
266
- 高级分析 (违规/自适应/因果) 折叠保留, 数据/API 不删 -->
267
- <div id="judgments-status-filter" class="judgment-status-bar">
268
- <button class="judgment-polarity-tab active" data-polarity="positive" title="采纳类: approve/modify/escalate, 会注入 prompt 复用">▲ 正向</button>
269
- <button class="judgment-polarity-tab" data-polarity="negative" title="否决/被推翻: reject/rejected/superseded, 负向回收为避免清单">▼ 负向</button>
270
- <details class="judgment-advanced-fold" style="margin-left:auto;">
271
- <summary style="font-size:11px;color:#6b7280;cursor:pointer;list-style:none;">⋯ 高级分析</summary>
272
- <div style="display:flex;gap:4px;padding:6px 0 0;flex-wrap:wrap;">
273
- <button class="judgment-status-tab" data-status="violations" style="font-size:11px;">违规记录</button>
274
- <button class="judgment-status-tab" data-status="adaptive" style="font-size:11px;">📊 自适应</button>
275
- <button class="judgment-status-tab" data-status="causal" style="font-size:11px;">🔍 因果分析</button>
276
- </div>
277
- </details>
278
- </div>
279
- <h3 class="judgment-list-header">
280
- <span id="judgments-list-title">本 channel 的判断力</span>
281
- <span class="judgment-list-actions">
282
- <label class="judgment-select-all-label">
283
- <input type="checkbox" id="judgment-select-all"> 全选
284
- </label>
285
- <span id="judgment-selected-count">已选 0</span>
286
- <button id="judgment-bulk-delete-btn" class="judgment-bulk-delete" disabled>批量删除</button>
287
- </span>
288
- </h3>
289
- <div id="judgments-list" class="task-list judgment-list">
290
- <div class="task-empty">加载中...</div>
291
- </div>
292
- </div>
293
- </div>
294
- </div>
295
-
296
- <!-- Agent Add / Wallet / Auto-tool Modal -->
297
- <div id="agent-add-modal" class="modal">
298
- <div class="modal-content">
299
- <div class="modal-header">
300
- <h2 id="agent-add-title">添加智能体</h2>
301
- <button id="agent-add-modal-close" class="modal-close">&times;</button>
302
- </div>
303
- <div class="modal-body">
304
- <div class="form-group">
305
- <label>智能体名称</label>
306
- <input type="text" id="agent-add-name" placeholder="例如: 交易助手">
307
- </div>
308
- <div class="form-group">
309
- <label>加密钱包地址 (EVM 0x... 或 Solana/Sui 等)</label>
310
- <div style="display:flex;gap:8px;">
311
- <input type="text" id="agent-add-wallet" placeholder="0x... (留空则不绑定)" style="flex:1;">
312
- <button type="button" id="agent-generate-wallet-btn" class="btn-secondary btn-sm" title="本地生成新钱包">生成</button>
313
- </div>
314
- <small class="form-hint">本地生成的钱包仅在浏览器内存, 服务端只保存公链地址, 不会上传私钥。</small>
315
- </div>
316
- <div class="form-group">
317
- <label class="checkbox-label">
318
- <input type="checkbox" id="agent-add-auto-tools" checked>
319
- <span>启用自动工具调用 (LLM 决定调用受信任工具时, agent 自动执行)</span>
320
- </label>
321
- </div>
322
- <div id="agent-add-wallet-info" class="form-info" style="display:none;"></div>
323
- <div class="btn-group">
324
- <button id="agent-add-cancel-btn" class="btn-secondary">取消</button>
325
- <button id="agent-add-confirm-btn" class="btn-primary">创建</button>
326
- </div>
327
- </div>
328
- </div>
329
- </div>
330
-
331
- <!-- Wallet Manager Modal (header 钱包按钮入口) -->
332
- <div id="wallet-modal" class="modal">
333
- <div class="modal-content modal-wide">
334
- <div class="modal-header">
335
- <h2>钱包管理</h2>
336
- <button id="wallet-modal-close" class="modal-close">&times;</button>
337
- </div>
338
- <div class="modal-body">
339
- <div class="form-group">
340
- <label>为当前智能体绑定加密钱包</label>
341
- <div style="display:flex;gap:8px;">
342
- <input type="text" id="wallet-bind-address" placeholder="0x... / Solana / Sui" style="flex:1;">
343
- <button type="button" id="wallet-generate-btn" class="btn-secondary btn-sm" title="本地生成新钱包">生成</button>
344
- </div>
345
- <small class="form-hint">仅当前激活智能体会使用此钱包; 服务端只保存公链地址, 私钥仅在浏览器内存。</small>
346
- </div>
347
- <div class="form-group">
348
- <label class="checkbox-label">
349
- <input type="checkbox" id="wallet-auto-tools" checked>
350
- <span>启用自动工具调用 (LLM 决定调用受信任工具时, agent 自动执行)</span>
351
- </label>
352
- </div>
353
- <div id="wallet-new-info" class="form-info" style="display:none;"></div>
354
- <div class="form-group" id="wallet-encrypt-group" style="display:none;">
355
- <label class="checkbox-label">
356
- <input type="checkbox" id="wallet-store-key" checked>
357
- <span>加密存储私钥到服务端 (用于 x402 自动支付)</span>
358
- </label>
359
- <small class="form-hint">私钥用 DID 派生密钥 AES-256-GCM 加密后上传, 仅当前智能体进程可解密。</small>
360
- </div>
361
- <div class="form-group" id="wallet-autopay-group" style="display:none;">
362
- <label class="checkbox-label">
363
- <input type="checkbox" id="wallet-autopay-enabled" checked>
364
- <span>自动支付 (智能体遇到 402 Payment Required 时自动用绑定钱包支付)</span>
365
- </label>
366
- </div>
367
- <div class="btn-group">
368
- <button id="wallet-bind-btn" class="btn-primary">绑定到当前智能体</button>
369
- <button id="wallet-unbind-btn" class="btn-secondary">解绑当前智能体</button>
370
- <button id="wallet-store-key-btn" class="btn-secondary" style="display:none;">存储加密私钥到服务端</button>
371
- </div>
372
-
373
- <h3 style="margin-top:24px;font-size:14px;font-weight:600;">所有已绑定钱包</h3>
374
- <div id="wallet-list" class="wallet-list">
375
- <div class="wallet-empty">暂未绑定钱包</div>
376
- </div>
377
- </div>
378
- </div>
379
- </div>
380
-
381
- <div class="messages" id="messages"></div>
382
-
383
- <!-- 2026-06-15: 旧 loop-timeline-panel 删除 — 步骤状态条改在每条 AI 消息气泡内挂 step-timeline 组件 -->
384
- <!-- 2026-06-16: 循环 status bar — 渲染 tool='loop' | 'compactor' | 'recovery' 的 status 事件
385
- 三态机: loading (spinner, 循环中) / retrying (spinner + "自动重试中 X/N", 失败自动重试) / done (检查按钮)
386
- 重试是 server 端自动的, 不暴露按钮给用户. -->
387
- <div id="loop-status-bar" class="loop-status-bar" hidden data-state="loading">
388
- <span class="loop-status-spinner" aria-hidden="true"></span>
389
- <span class="loop-status-icon" id="loop-status-icon" aria-hidden="true"></span>
390
- <span class="loop-status-text" id="loop-status-text"></span>
391
- <span class="loop-status-retry" id="loop-status-retry" hidden></span>
392
- <button id="loop-status-check" class="loop-status-action" hidden type="button">✓ 检查</button>
393
- </div>
394
-
395
- <div class="input-area">
396
- <div class="input-wrapper">
397
- <button id="send-tools-toggle" class="send-tools-toggle" title="本次发送是否允许工具调用 (点击切换)"
398
- style="display:none;align-items:center;gap:4px;background:transparent;border:1px solid var(--border);color:var(--text-muted);border-radius:6px;padding:4px 8px;font-size:11px;cursor:pointer;white-space:nowrap;flex-shrink:0;">
399
- 🔧 <span id="send-tools-label">工具:开</span>
400
- </button>
401
- <input type="text" id="input" placeholder="输入消息... (/ 命令 · @ 提及)" autocomplete="off">
402
- <button id="send" class="send-btn" data-state="idle" title="发送 (Enter)">
403
- <!-- 2026-06-15: 状态机 — 流式期间切到 abort 模式 (▢ 图标 + 红色边框) -->
404
- <svg class="send-icon" data-mode="send" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
405
- <line x1="22" y1="2" x2="11" y2="13"></line>
406
- <polygon points="22 2 15 22 11 13 2 9 22 2"></polygon>
407
- </svg>
408
- <svg class="send-icon" data-mode="abort" width="20" height="20" viewBox="0 0 24 24" fill="currentColor" stroke="currentColor" stroke-width="2" style="display:none;">
409
- <rect x="6" y="6" width="12" height="12" rx="1.5"></rect>
410
- </svg>
411
- </button>
412
- </div>
413
- </div>
414
- </main>
415
- </div>
416
-
417
- <!-- ========== 登录 Modal (2026-08-09) — GitHub/Google/邮箱/手机号, 仅骨架 ========== -->
418
- <div id="auth-modal" class="modal" style="display:none;">
419
- <div class="modal-content">
420
- <div class="modal-header">
421
- <h2>登录 · 账号绑定</h2>
422
- <button id="auth-modal-close" class="modal-close">&times;</button>
423
- </div>
424
- <div class="modal-body">
425
- <div id="auth-status-line" class="form-info" style="margin-bottom:12px;font-size:12px;"></div>
426
-
427
- <!-- OAuth 骨架按钮 -->
428
- <div class="form-group">
429
- <label>第三方账号</label>
430
- <div style="display:flex;gap:8px;flex-wrap:wrap;">
431
- <button type="button" class="btn-secondary auth-oauth-btn" data-provider="github" style="flex:1;min-width:120px;">GitHub</button>
432
- <button type="button" class="btn-secondary auth-oauth-btn" data-provider="google" style="flex:1;min-width:120px;">Google</button>
433
- </div>
434
- <small class="form-hint" id="auth-oauth-hint">骨架: 点击后记录账号归属当前 DID, 真实 OAuth 授权页后续接入。</small>
435
- </div>
436
-
437
- <!-- 邮箱登录骨架 -->
438
- <div class="form-group">
439
- <label for="auth-email">邮箱登录</label>
440
- <div style="display:flex;gap:8px;">
441
- <input type="email" id="auth-email" placeholder="you@example.com" style="flex:1;">
442
- <button type="button" class="btn-secondary" id="auth-email-btn">绑定</button>
443
- </div>
444
- <small class="form-hint">骨架: 记录邮箱归属当前 DID, 验证码发送后续接入。</small>
445
- </div>
446
-
447
- <!-- 手机号登录骨架 -->
448
- <div class="form-group">
449
- <label for="auth-phone">手机号登录</label>
450
- <div style="display:flex;gap:8px;">
451
- <input type="tel" id="auth-phone" placeholder="+86 138... " style="flex:1;">
452
- <button type="button" class="btn-secondary" id="auth-phone-btn">绑定</button>
453
- </div>
454
- <small class="form-hint">骨架: 记录手机号归属当前 DID, 短信验证码后续接入。</small>
455
- </div>
456
-
457
- <!-- 已绑定列表 -->
458
- <div id="auth-accounts-list" style="margin-top:8px;"></div>
459
-
460
- <div id="auth-msg" class="form-info" style="display:none;margin-top:8px;"></div>
461
- </div>
462
- </div>
463
- </div>
464
-
465
- <script type="module" src="./components/wallet-viem.mjs"></script>
466
- <script type="module" src="./components/p2p/index.js"></script>
467
- <script type="module" src="./ui/step-timeline.js"></script>
468
- <script type="module" src="./ui/message-renderer.js"></script>
469
- <!-- 2026-07-06: client.js 含 import 语句 (safeChannelName 兜底), 必须 type="module" -->
470
- <script type="module" src="./client.js"></script>
471
- </body>
472
- </html>
1
+ <!DOCTYPE html>
2
+ <html lang="zh-CN" data-theme="dark">
3
+ <head>
4
+ <meta charset="UTF-8">
5
+ <meta name="viewport" content="width=device-width, initial-scale=1.0">
6
+ <title>Bolloon Agent</title>
7
+
8
+ <!-- Favicon -->
9
+ <link rel="icon" type="image/x-icon" href="./icons/favicon.ico">
10
+ <link rel="icon" type="image/png" sizes="32x32" href="./icons/favicon-32x32.png">
11
+ <link rel="icon" type="image/png" sizes="16x16" href="./icons/favicon-16x16.png">
12
+
13
+ <!-- Apple Touch Icon -->
14
+ <link rel="apple-touch-icon" href="./icons/apple-touch-icon.png">
15
+
16
+ <!-- PWA Manifest -->
17
+ <link rel="manifest" href="./manifest.json">
18
+
19
+ <!-- 2026-06-11: 移除 Google Fonts + jsdelivr 外部 CDN 阻塞 — 在大陆/跨公网 timeout 拖慢首屏/返回主页
20
+ 字体: style.css 只用字面量 'JetBrains Mono', 系统有就用, 没有自动 fall back monospace
21
+ marked/qrcode: 改 async 不阻塞 (下载失败时本地降级到 escape 文本, 不影响主聊天) -->
22
+ <link rel="stylesheet" href="./style.css">
23
+ <script async src="https://cdn.jsdelivr.net/npm/marked/marked.min.js"></script>
24
+ <script async src="https://cdn.jsdelivr.net/npm/qrcode@1.5.3/build/qrcode.min.js"></script>
25
+ </head>
26
+ <body>
27
+ <div class="app-container">
28
+ <aside class="sidebar" id="sidebar">
29
+ <div class="sidebar-header">
30
+ <button id="sidebar-toggle" class="sidebar-toggle" title="收起侧边栏">
31
+ <svg width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
32
+ <polyline points="15 18 9 12 15 6"></polyline>
33
+ </svg>
34
+ </button>
35
+ <span class="sidebar-brand">
36
+ <span class="brand-icon">◈</span>
37
+ <span class="brand-text">Bolloon</span>
38
+ </span>
39
+ <!-- 2026-06-11: 加载 Session 文件夹按钮删除 (2026-06-16: 残留注释 + input 占位同步清除) -->
40
+ </div>
41
+
42
+ <div class="sidebar-section">
43
+ <div class="section-header">
44
+ <span class="section-title">智能体</span>
45
+ <!-- 2026-06-11: catalog-add-btn (添加智能体) 删除 -->
46
+ </div>
47
+ <button id="new-channel-btn" class="section-action" title="新建智能体">
48
+ <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
49
+ <line x1="12" y1="5" x2="12" y2="19"></line>
50
+ <line x1="5" y1="12" x2="19" y2="12"></line>
51
+ </svg>
52
+ <span>新建智能体</span>
53
+ </button>
54
+ <ul class="channel-list" id="channel-list"></ul>
55
+ </div>
56
+
57
+ <!-- v3: 本地/远端分隔线 — 可拖拽改变两边高度 -->
58
+ <div id="sidebar-split-handle" title="拖动调整上方/下方高度">
59
+ <div class="split-handle-grip"></div>
60
+ </div>
61
+
62
+ <!-- v3 远端 P2P 好友 — 显式分享 + 持久化连接 -->
63
+ <div class="sidebar-section" id="remote-agents-section">
64
+ <div class="section-header is-compact is-clickable" id="remote-agents-header">
65
+ <span class="section-header-row">
66
+ <span id="remote-agents-toggle">▼</span>
67
+ <span class="section-title">P2P 好友</span>
68
+ </span>
69
+ <span class="section-header-actions">
70
+ <button id="p2p-toggle-all-btn" class="sidebar-mini-btn" title="切换全部展开/折叠">⊞ 展开</button>
71
+ <button id="show-my-p2p-id-btn" class="sidebar-mini-btn" title="查看并复制我的 P2P publicKey">我的 ID</button>
72
+ <button id="add-p2p-peer-btn" class="sidebar-mini-btn" title="添加 P2P 好友 (输入对方的 publicKey)">+ 好友</button>
73
+ </span>
74
+ </div>
75
+ <ul class="channel-list" id="remote-channel-list">
76
+ <li class="sidebar-empty-hint">(暂无好友, 点 + 添加)</li>
77
+ </ul>
78
+ </div>
79
+
80
+ <div class="sidebar-footer">
81
+ <div class="user-avatar" id="user-avatar" title="点击查看 DID 身份">
82
+ <span class="avatar-letter" id="avatar-letter">?</span>
83
+ </div>
84
+ <div class="user-info">
85
+ <span class="user-name" id="user-name" title="点击修改名字" style="cursor:pointer;">加载中...</span>
86
+ <span class="user-did" id="user-did"></span>
87
+ </div>
88
+ <div class="agent-status">
89
+ <span class="status-dot"></span>
90
+ <span class="status-text">已连接</span>
91
+ </div>
92
+ </div>
93
+ </aside>
94
+
95
+ <main class="main">
96
+ <header class="header">
97
+ <div class="header-left">
98
+ <span class="channel-indicator" id="channel-indicator"></span>
99
+ <h1 id="channel-name">Bolloon Agent</h1>
100
+ </div>
101
+ <div class="header-right">
102
+ <button id="theme-toggle" class="theme-toggle" title="切换主题">
103
+ <svg class="sun-icon" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
104
+ <circle cx="12" cy="12" r="5"></circle>
105
+ <line x1="12" y1="1" x2="12" y2="3"></line>
106
+ <line x1="12" y1="21" x2="12" y2="23"></line>
107
+ <line x1="4.22" y1="4.22" x2="5.64" y2="5.64"></line>
108
+ <line x1="18.36" y1="18.36" x2="19.78" y2="19.78"></line>
109
+ <line x1="1" y1="12" x2="3" y2="12"></line>
110
+ <line x1="21" y1="12" x2="23" y2="12"></line>
111
+ <line x1="4.22" y1="19.78" x2="5.64" y2="18.36"></line>
112
+ <line x1="18.36" y1="5.64" x2="19.78" y2="4.22"></line>
113
+ </svg>
114
+ <svg class="moon-icon" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
115
+ <path d="M21 12.79A9 9 0 1 1 11.21 3 7 7 0 0 0 21 12.79z"></path>
116
+ </svg>
117
+ </button>
118
+ <button id="api-config-btn" class="header-action" title="API 配置">
119
+ <svg width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
120
+ <circle cx="12" cy="12" r="3"></circle>
121
+ <path d="M19.4 15a1.65 1.65 0 0 0 .33 1.82l.06.06a2 2 0 0 1 0 2.83 2 2 0 0 1-2.83 0l-.06-.06a1.65 1.65 0 0 0-1.82-.33 1.65 1.65 0 0 0-1 1.51V21a2 2 0 0 1-2 2 2 2 0 0 1-2-2v-.09A1.65 1.65 0 0 0 9 19.4a1.65 1.65 0 0 0-1.82.33l-.06.06a2 2 0 0 1-2.83 0 2 2 0 0 1 0-2.83l.06-.06a1.65 1.65 0 0 0 .33-1.82 1.65 1.65 0 0 0-1.51-1H3a2 2 0 0 1-2-2 2 2 0 0 1 2-2h.09A1.65 1.65 0 0 0 4.6 9a1.65 1.65 0 0 0-.33-1.82l-.06-.06a2 2 0 0 1 0-2.83 2 2 0 0 1 2.83 0l.06.06a1.65 1.65 0 0 0 1.82.33H9a1.65 1.65 0 0 0 1-1.51V3a2 2 0 0 1 2-2 2 2 0 0 1 2 2v.09a1.65 1.65 0 0 0 1 1.51 1.65 1.65 0 0 0 1.82-.33l.06-.06a2 2 0 0 1 2.83 0 2 2 0 0 1 0 2.83l-.06.06a1.65 1.65 0 0 0-.33 1.82V9a1.65 1.65 0 0 0 1.51 1H21a2 2 0 0 1 2 2 2 2 0 0 1-2 2h-.09a1.65 1.65 0 0 0-1.51 1z"></path>
122
+ </svg>
123
+ </button>
124
+ <!-- v3: 顶栏 P2P 按钮 (旧 iroh/Diap 路径) 已移除, 改用侧边栏 "P2P 好友" → "+ 好友" -->
125
+ <button id="wallet-btn" class="header-action" title="钱包管理">
126
+ <svg width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
127
+ <path d="M21 12V7a2 2 0 0 0-2-2H5a2 2 0 0 0-2 2v10a2 2 0 0 0 2 2h14a2 2 0 0 0 2-2v-3"></path>
128
+ <circle cx="17" cy="12" r="1.5" fill="currentColor"></circle>
129
+ <path d="M3 7l3-3h12l3 3"></path>
130
+ </svg>
131
+ <span id="wallet-badge" class="task-badge" style="display:none;">0</span>
132
+ </button>
133
+ <button id="judgments-btn" class="header-action" title="我的判断">
134
+ <svg width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
135
+ <path d="M12 2L4 6v6c0 5 3.5 9.5 8 10 4.5-.5 8-5 8-10V6l-8-4z"></path>
136
+ <path d="M9 12l2 2 4-4"></path>
137
+ </svg>
138
+ <span id="judgments-badge" class="task-badge" style="display:none;">0</span>
139
+ </button>
140
+ </div>
141
+ </header>
142
+
143
+ <!-- P2P Network Modal (React) -->
144
+ <div id="p2p-modal-root"></div>
145
+
146
+ <!-- Task Queue Modal -->
147
+ <div id="task-modal" class="modal">
148
+ <div class="modal-content modal-wide">
149
+ <div class="modal-header">
150
+ <h2>任务队列</h2>
151
+ <button id="task-modal-close" class="modal-close">&times;</button>
152
+ </div>
153
+ <div class="modal-body">
154
+ <div class="task-toolbar">
155
+ <button id="task-add-btn" class="btn-primary btn-sm">+ 新建任务</button>
156
+ <button id="task-execute-next-btn" class="btn-secondary btn-sm">▶ 执行下一个</button>
157
+ </div>
158
+ <div id="task-list" class="task-list">
159
+ <div class="task-empty">暂无任务,点击上方按钮创建</div>
160
+ </div>
161
+ </div>
162
+ </div>
163
+ </div>
164
+
165
+
166
+ <!-- Create Task Modal -->
167
+ <div id="create-task-modal" class="modal">
168
+ <div class="modal-content">
169
+ <div class="modal-header">
170
+ <h2>新建任务</h2>
171
+ <button id="create-task-modal-close" class="modal-close">&times;</button>
172
+ </div>
173
+ <div class="modal-body">
174
+ <div class="form-group">
175
+ <label>任务类型</label>
176
+ <select id="task-type">
177
+ <option value="chat">对话</option>
178
+ <option value="read">读取文档</option>
179
+ <option value="summarize">总结文档</option>
180
+ </select>
181
+ </div>
182
+ <div class="form-group">
183
+ <label>任务标题</label>
184
+ <input type="text" id="task-title" placeholder="输入任务标题">
185
+ </div>
186
+ <div class="form-group">
187
+ <label>任务描述</label>
188
+ <textarea id="task-desc" placeholder="输入任务描述或内容" rows="3"></textarea>
189
+ </div>
190
+ <div class="btn-group">
191
+ <button id="task-cancel-btn" class="btn-secondary">取消</button>
192
+ <button id="task-create-btn" class="btn-primary">创建并执行</button>
193
+ </div>
194
+ </div>
195
+ </div>
196
+ </div>
197
+
198
+ <!-- Judgments Modal (v1 核心) -->
199
+ <div id="judgments-modal" class="modal">
200
+ <div class="modal-content modal-wide">
201
+ <div class="modal-header">
202
+ <h2>我的判断</h2>
203
+ <button id="judgments-modal-close" class="modal-close">&times;</button>
204
+ </div>
205
+ <div class="modal-body">
206
+ <div class="form-group">
207
+ <label>判断 (decision)</label>
208
+ <textarea id="judgment-decision" rows="2" placeholder="例: 不在时让 AI 替我做决定"></textarea>
209
+ </div>
210
+ <div class="form-group">
211
+ <label>理由 (reason, 可选)</label>
212
+ <input type="text" id="judgment-reason" placeholder="例: 信任 Bolloon 的判断存储">
213
+ </div>
214
+ <div class="form-group judgment-form-row">
215
+ <label>分类</label>
216
+ <div class="judgment-polarity-toggle" id="judgment-polarity-toggle">
217
+ <label class="polarity-opt active" data-polarity="positive">
218
+ <input type="radio" name="judgment-polarity" value="positive" checked>
219
+ <span>▲ 正向 <small>采纳</small></span>
220
+ </label>
221
+ <label class="polarity-opt" data-polarity="negative">
222
+ <input type="radio" name="judgment-polarity" value="negative">
223
+ <span>▼ 负向 <small>否决/避免</small></span>
224
+ </label>
225
+ </div>
226
+ <details class="judgment-advanced-fold" style="margin-left:auto;">
227
+ <summary style="font-size:11px;color:#6b7280;cursor:pointer;list-style:none;">高级 (领域/风险)</summary>
228
+ <div style="display:flex;gap:10px;padding:6px 0 0;flex-wrap:wrap;font-size:11px;">
229
+ <label>领域
230
+ <select id="judgment-domain">
231
+ <option value="general">general</option>
232
+ <option value="code">code</option>
233
+ <option value="architecture">architecture</option>
234
+ <option value="security">security</option>
235
+ <option value="testing">testing</option>
236
+ </select>
237
+ </label>
238
+ <label>风险
239
+ <select id="judgment-stakes">
240
+ <option value="medium">medium</option>
241
+ <option value="low">low</option>
242
+ <option value="high">high</option>
243
+ <option value="critical">critical</option>
244
+ </select>
245
+ </label>
246
+ </div>
247
+ </details>
248
+ </div>
249
+ <div class="btn-group">
250
+ <button id="judgment-submit-btn" class="btn-primary">记录</button>
251
+ <button id="judgment-import-btn" class="btn-secondary" title="从 .json / .yaml / .md / .txt / .html 文件批量导入">导入文件</button>
252
+ <button id="judgment-cleanup-btn" class="btn-secondary" title="软删除测试灌水数据: loadAll 测试/测试原则 等启发式匹配">清理测试数据</button>
253
+ <input type="file" id="judgment-import-file" accept=".json,.yaml,.yml,.md,.txt,.html,.htm" style="display:none">
254
+ </div>
255
+ <div id="judgment-error" class="form-info judgment-error"></div>
256
+ <!-- v3 重做: tab 切换 — 默认显示当前 channel 的 judgment 上下文, 切换后才是全部 -->
257
+ <div id="judgments-tabs" class="judgment-tab-bar">
258
+ <button class="judgment-tab active" data-tab="channel">
259
+ 本 channel <span id="judgments-tab-channel-name" class="tab-channel-name"></span>
260
+ </button>
261
+ <button class="judgment-tab" data-tab="global">全局</button>
262
+ </div>
263
+ <!-- 2026-07-22 简化: 正向 / 负向 两个主分类 (替换原 6 个 status tab)
264
+ 正向 = 采纳类 (approve/modify/escalate), 会注入 prompt 复用
265
+ 负向 = 否决/被推翻 (reject/rejected/superseded), 负向回收为避免清单
266
+ 高级分析 (违规/自适应/因果) 折叠保留, 数据/API 不删 -->
267
+ <div id="judgments-status-filter" class="judgment-status-bar">
268
+ <button class="judgment-polarity-tab active" data-polarity="positive" title="采纳类: approve/modify/escalate, 会注入 prompt 复用">▲ 正向</button>
269
+ <button class="judgment-polarity-tab" data-polarity="negative" title="否决/被推翻: reject/rejected/superseded, 负向回收为避免清单">▼ 负向</button>
270
+ <details class="judgment-advanced-fold" style="margin-left:auto;">
271
+ <summary style="font-size:11px;color:#6b7280;cursor:pointer;list-style:none;">⋯ 高级分析</summary>
272
+ <div style="display:flex;gap:4px;padding:6px 0 0;flex-wrap:wrap;">
273
+ <button class="judgment-status-tab" data-status="violations" style="font-size:11px;">违规记录</button>
274
+ <button class="judgment-status-tab" data-status="adaptive" style="font-size:11px;">📊 自适应</button>
275
+ <button class="judgment-status-tab" data-status="causal" style="font-size:11px;">🔍 因果分析</button>
276
+ </div>
277
+ </details>
278
+ </div>
279
+ <h3 class="judgment-list-header">
280
+ <span id="judgments-list-title">本 channel 的判断力</span>
281
+ <span class="judgment-list-actions">
282
+ <label class="judgment-select-all-label">
283
+ <input type="checkbox" id="judgment-select-all"> 全选
284
+ </label>
285
+ <span id="judgment-selected-count">已选 0</span>
286
+ <button id="judgment-bulk-delete-btn" class="judgment-bulk-delete" disabled>批量删除</button>
287
+ </span>
288
+ </h3>
289
+ <div id="judgments-list" class="task-list judgment-list">
290
+ <div class="task-empty">加载中...</div>
291
+ </div>
292
+ </div>
293
+ </div>
294
+ </div>
295
+
296
+ <!-- Agent Add / Wallet / Auto-tool Modal -->
297
+ <div id="agent-add-modal" class="modal">
298
+ <div class="modal-content">
299
+ <div class="modal-header">
300
+ <h2 id="agent-add-title">添加智能体</h2>
301
+ <button id="agent-add-modal-close" class="modal-close">&times;</button>
302
+ </div>
303
+ <div class="modal-body">
304
+ <div class="form-group">
305
+ <label>智能体名称</label>
306
+ <input type="text" id="agent-add-name" placeholder="例如: 交易助手">
307
+ </div>
308
+ <div class="form-group">
309
+ <label>加密钱包地址 (EVM 0x... 或 Solana/Sui 等)</label>
310
+ <div style="display:flex;gap:8px;">
311
+ <input type="text" id="agent-add-wallet" placeholder="0x... (留空则不绑定)" style="flex:1;">
312
+ <button type="button" id="agent-generate-wallet-btn" class="btn-secondary btn-sm" title="本地生成新钱包">生成</button>
313
+ </div>
314
+ <small class="form-hint">本地生成的钱包仅在浏览器内存, 服务端只保存公链地址, 不会上传私钥。</small>
315
+ </div>
316
+ <div class="form-group">
317
+ <label class="checkbox-label">
318
+ <input type="checkbox" id="agent-add-auto-tools" checked>
319
+ <span>启用自动工具调用 (LLM 决定调用受信任工具时, agent 自动执行)</span>
320
+ </label>
321
+ </div>
322
+ <div id="agent-add-wallet-info" class="form-info" style="display:none;"></div>
323
+ <div class="btn-group">
324
+ <button id="agent-add-cancel-btn" class="btn-secondary">取消</button>
325
+ <button id="agent-add-confirm-btn" class="btn-primary">创建</button>
326
+ </div>
327
+ </div>
328
+ </div>
329
+ </div>
330
+
331
+ <!-- Wallet Manager Modal (header 钱包按钮入口) -->
332
+ <div id="wallet-modal" class="modal">
333
+ <div class="modal-content modal-wide">
334
+ <div class="modal-header">
335
+ <h2>钱包管理</h2>
336
+ <button id="wallet-modal-close" class="modal-close">&times;</button>
337
+ </div>
338
+ <div class="modal-body">
339
+ <div class="form-group">
340
+ <label>为当前智能体绑定加密钱包</label>
341
+ <div style="display:flex;gap:8px;">
342
+ <input type="text" id="wallet-bind-address" placeholder="0x... / Solana / Sui" style="flex:1;">
343
+ <button type="button" id="wallet-generate-btn" class="btn-secondary btn-sm" title="本地生成新钱包">生成</button>
344
+ </div>
345
+ <small class="form-hint">仅当前激活智能体会使用此钱包; 服务端只保存公链地址, 私钥仅在浏览器内存。</small>
346
+ </div>
347
+ <div class="form-group">
348
+ <label class="checkbox-label">
349
+ <input type="checkbox" id="wallet-auto-tools" checked>
350
+ <span>启用自动工具调用 (LLM 决定调用受信任工具时, agent 自动执行)</span>
351
+ </label>
352
+ </div>
353
+ <div id="wallet-new-info" class="form-info" style="display:none;"></div>
354
+ <div class="form-group" id="wallet-encrypt-group" style="display:none;">
355
+ <label class="checkbox-label">
356
+ <input type="checkbox" id="wallet-store-key" checked>
357
+ <span>加密存储私钥到服务端 (用于 x402 自动支付)</span>
358
+ </label>
359
+ <small class="form-hint">私钥用 DID 派生密钥 AES-256-GCM 加密后上传, 仅当前智能体进程可解密。</small>
360
+ </div>
361
+ <div class="form-group" id="wallet-autopay-group" style="display:none;">
362
+ <label class="checkbox-label">
363
+ <input type="checkbox" id="wallet-autopay-enabled" checked>
364
+ <span>自动支付 (智能体遇到 402 Payment Required 时自动用绑定钱包支付)</span>
365
+ </label>
366
+ </div>
367
+ <div class="btn-group">
368
+ <button id="wallet-bind-btn" class="btn-primary">绑定到当前智能体</button>
369
+ <button id="wallet-unbind-btn" class="btn-secondary">解绑当前智能体</button>
370
+ <button id="wallet-store-key-btn" class="btn-secondary" style="display:none;">存储加密私钥到服务端</button>
371
+ </div>
372
+
373
+ <h3 style="margin-top:24px;font-size:14px;font-weight:600;">所有已绑定钱包</h3>
374
+ <div id="wallet-list" class="wallet-list">
375
+ <div class="wallet-empty">暂未绑定钱包</div>
376
+ </div>
377
+ </div>
378
+ </div>
379
+ </div>
380
+
381
+ <div class="messages" id="messages"></div>
382
+
383
+ <!-- 2026-06-15: 旧 loop-timeline-panel 删除 — 步骤状态条改在每条 AI 消息气泡内挂 step-timeline 组件 -->
384
+ <!-- 2026-06-16: 循环 status bar — 渲染 tool='loop' | 'compactor' | 'recovery' 的 status 事件
385
+ 三态机: loading (spinner, 循环中) / retrying (spinner + "自动重试中 X/N", 失败自动重试) / done (检查按钮)
386
+ 重试是 server 端自动的, 不暴露按钮给用户. -->
387
+ <div id="loop-status-bar" class="loop-status-bar" hidden data-state="loading">
388
+ <span class="loop-status-spinner" aria-hidden="true"></span>
389
+ <span class="loop-status-icon" id="loop-status-icon" aria-hidden="true"></span>
390
+ <span class="loop-status-text" id="loop-status-text"></span>
391
+ <span class="loop-status-retry" id="loop-status-retry" hidden></span>
392
+ <button id="loop-status-check" class="loop-status-action" hidden type="button">✓ 检查</button>
393
+ </div>
394
+
395
+ <div class="input-area">
396
+ <div class="input-wrapper">
397
+ <button id="send-tools-toggle" class="send-tools-toggle" title="本次发送是否允许工具调用 (点击切换)"
398
+ style="display:none;align-items:center;gap:4px;background:transparent;border:1px solid var(--border);color:var(--text-muted);border-radius:6px;padding:4px 8px;font-size:11px;cursor:pointer;white-space:nowrap;flex-shrink:0;">
399
+ 🔧 <span id="send-tools-label">工具:开</span>
400
+ </button>
401
+ <input type="text" id="input" placeholder="输入消息... (/ 命令 · @ 提及)" autocomplete="off">
402
+ <button id="send" class="send-btn" data-state="idle" title="发送 (Enter)">
403
+ <!-- 2026-06-15: 状态机 — 流式期间切到 abort 模式 (▢ 图标 + 红色边框) -->
404
+ <svg class="send-icon" data-mode="send" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
405
+ <line x1="22" y1="2" x2="11" y2="13"></line>
406
+ <polygon points="22 2 15 22 11 13 2 9 22 2"></polygon>
407
+ </svg>
408
+ <svg class="send-icon" data-mode="abort" width="20" height="20" viewBox="0 0 24 24" fill="currentColor" stroke="currentColor" stroke-width="2" style="display:none;">
409
+ <rect x="6" y="6" width="12" height="12" rx="1.5"></rect>
410
+ </svg>
411
+ </button>
412
+ </div>
413
+ </div>
414
+ </main>
415
+ </div>
416
+
417
+ <!-- ========== 登录 Modal (2026-08-09) — GitHub/Google/邮箱/手机号, 仅骨架 ========== -->
418
+ <div id="auth-modal" class="modal" style="display:none;">
419
+ <div class="modal-content">
420
+ <div class="modal-header">
421
+ <h2>登录 · 账号绑定</h2>
422
+ <button id="auth-modal-close" class="modal-close">&times;</button>
423
+ </div>
424
+ <div class="modal-body">
425
+ <div id="auth-status-line" class="form-info" style="margin-bottom:12px;font-size:12px;"></div>
426
+
427
+ <!-- OAuth 骨架按钮 -->
428
+ <div class="form-group">
429
+ <label>第三方账号</label>
430
+ <div style="display:flex;gap:8px;flex-wrap:wrap;">
431
+ <button type="button" class="btn-secondary auth-oauth-btn" data-provider="github" style="flex:1;min-width:120px;">GitHub</button>
432
+ <button type="button" class="btn-secondary auth-oauth-btn" data-provider="google" style="flex:1;min-width:120px;">Google</button>
433
+ </div>
434
+ <small class="form-hint" id="auth-oauth-hint">骨架: 点击后记录账号归属当前 DID, 真实 OAuth 授权页后续接入。</small>
435
+ </div>
436
+
437
+ <!-- 邮箱登录骨架 -->
438
+ <div class="form-group">
439
+ <label for="auth-email">邮箱登录</label>
440
+ <div style="display:flex;gap:8px;">
441
+ <input type="email" id="auth-email" placeholder="you@example.com" style="flex:1;">
442
+ <button type="button" class="btn-secondary" id="auth-email-btn">绑定</button>
443
+ </div>
444
+ <small class="form-hint">骨架: 记录邮箱归属当前 DID, 验证码发送后续接入。</small>
445
+ </div>
446
+
447
+ <!-- 手机号登录骨架 -->
448
+ <div class="form-group">
449
+ <label for="auth-phone">手机号登录</label>
450
+ <div style="display:flex;gap:8px;">
451
+ <input type="tel" id="auth-phone" placeholder="+86 138... " style="flex:1;">
452
+ <button type="button" class="btn-secondary" id="auth-phone-btn">绑定</button>
453
+ </div>
454
+ <small class="form-hint">骨架: 记录手机号归属当前 DID, 短信验证码后续接入。</small>
455
+ </div>
456
+
457
+ <!-- 已绑定列表 -->
458
+ <div id="auth-accounts-list" style="margin-top:8px;"></div>
459
+
460
+ <div id="auth-msg" class="form-info" style="display:none;margin-top:8px;"></div>
461
+ </div>
462
+ </div>
463
+ </div>
464
+
465
+ <script type="module" src="./components/wallet-viem.mjs"></script>
466
+ <script type="module" src="./components/p2p/index.js"></script>
467
+ <script type="module" src="./ui/step-timeline.js"></script>
468
+ <script type="module" src="./ui/message-renderer.js"></script>
469
+ <!-- 2026-07-06: client.js 含 import 语句 (safeChannelName 兜底), 必须 type="module" -->
470
+ <script type="module" src="./client.js"></script>
471
+ </body>
472
+ </html>