@bolloon/bolloon-agent 0.1.1 → 0.1.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (200) hide show
  1. package/bin/bolloon-cli.cjs +165 -0
  2. package/bin/bolloon-daemon.sh +207 -0
  3. package/bin/bolloon.cmd +11 -0
  4. package/dist/agents/constraint-layer.js +10 -15
  5. package/dist/agents/pi-sdk.js +433 -106
  6. package/dist/agents/protocol.js +82 -1
  7. package/dist/agents/subagent-manager.js +2 -2
  8. package/dist/agents/workflow-engine.js +15 -20
  9. package/dist/agents/workflow-pivot-loop.js +541 -0
  10. package/dist/bollharness/src/index.js +5 -0
  11. package/dist/bollharness/src/scripts/checks/check_adr_plan_numbering.js +6 -0
  12. package/dist/bollharness/src/scripts/checks/check_api_types.js +45 -0
  13. package/dist/bollharness/src/scripts/checks/check_artifact_link.js +146 -0
  14. package/dist/bollharness/src/scripts/checks/check_bridge_deps.js +6 -0
  15. package/dist/bollharness/src/scripts/checks/check_bugfix_binding.js +6 -0
  16. package/dist/bollharness/src/scripts/checks/check_bugfix_binding_ci.js +6 -0
  17. package/dist/bollharness/src/scripts/checks/check_doc_file_references.js +6 -0
  18. package/dist/bollharness/src/scripts/checks/check_doc_freshness.js +135 -0
  19. package/dist/bollharness/src/scripts/checks/check_doc_links.js +31 -0
  20. package/dist/bollharness/src/scripts/checks/check_file_existence_claims.js +6 -0
  21. package/dist/bollharness/src/scripts/checks/check_fragment_integrity.js +34 -0
  22. package/dist/bollharness/src/scripts/checks/check_hook_installed.js +63 -0
  23. package/dist/bollharness/src/scripts/checks/check_issue_closure.js +41 -0
  24. package/dist/bollharness/src/scripts/checks/check_mcp_parity.js +6 -0
  25. package/dist/bollharness/src/scripts/checks/check_security.js +48 -0
  26. package/dist/bollharness/src/scripts/checks/check_skill_parity.js +6 -0
  27. package/dist/bollharness/src/scripts/checks/check_versions.js +6 -0
  28. package/dist/bollharness/src/scripts/checks/finding.js +13 -0
  29. package/dist/bollharness/src/scripts/checks/next_decision_number.js +20 -0
  30. package/dist/bollharness/src/scripts/checks/regenerate_magic_docs.js +6 -0
  31. package/dist/bollharness/src/scripts/ci/detect_rebaseline_triggers.js +8 -0
  32. package/dist/bollharness/src/scripts/ci/scan_subprocess_cfg.js +8 -0
  33. package/dist/bollharness/src/scripts/ci/scan_verify_artifacts.js +8 -0
  34. package/dist/bollharness/src/scripts/ci/scan_yaml_schema.js +8 -0
  35. package/dist/bollharness/src/scripts/context_router.js +67 -0
  36. package/dist/bollharness/src/scripts/deploy-guard.js +157 -0
  37. package/dist/bollharness/src/scripts/guard-feedback.js +192 -0
  38. package/dist/bollharness/src/scripts/guard_router.js +158 -0
  39. package/dist/bollharness/src/scripts/hooks/_hook_output.js +6 -0
  40. package/dist/bollharness/src/scripts/hooks/auto-python3.js +6 -0
  41. package/dist/bollharness/src/scripts/hooks/deploy-progress-on-session-end.js +6 -0
  42. package/dist/bollharness/src/scripts/hooks/failure-analyzer.js +6 -0
  43. package/dist/bollharness/src/scripts/hooks/gate-judgment-inject.js +92 -0
  44. package/dist/bollharness/src/scripts/hooks/gate-transition-judgment.js +63 -0
  45. package/dist/bollharness/src/scripts/hooks/inbox-ack.js +6 -0
  46. package/dist/bollharness/src/scripts/hooks/inbox-inject-on-start.js +6 -0
  47. package/dist/bollharness/src/scripts/hooks/inbox-validate.js +6 -0
  48. package/dist/bollharness/src/scripts/hooks/inbox-write-ledger.js +6 -0
  49. package/dist/bollharness/src/scripts/hooks/initializer-agent.js +6 -0
  50. package/dist/bollharness/src/scripts/hooks/loop-detection.js +73 -0
  51. package/dist/bollharness/src/scripts/hooks/owner-guard.js +6 -0
  52. package/dist/bollharness/src/scripts/hooks/precompact.js +6 -0
  53. package/dist/bollharness/src/scripts/hooks/review-agent-gatekeeper.js +6 -0
  54. package/dist/bollharness/src/scripts/hooks/risk-tracker.js +108 -0
  55. package/dist/bollharness/src/scripts/hooks/sanitize-on-read.js +6 -0
  56. package/dist/bollharness/src/scripts/hooks/session-reflection.js +7 -0
  57. package/dist/bollharness/src/scripts/hooks/session-start-magic-docs.js +7 -0
  58. package/dist/bollharness/src/scripts/hooks/session-start-reset-risk.js +7 -0
  59. package/dist/bollharness/src/scripts/hooks/session-start-toolkit-reminder.js +7 -0
  60. package/dist/bollharness/src/scripts/hooks/stop-evaluator.js +157 -0
  61. package/dist/bollharness/src/scripts/hooks/tool-call-counter.js +6 -0
  62. package/dist/bollharness/src/scripts/hooks/trace-analyzer.js +10 -0
  63. package/dist/bollharness/src/scripts/install/install-trust-token.js +7 -0
  64. package/dist/bollharness/src/scripts/install/multi_project_registry.js +9 -0
  65. package/dist/bollharness/src/scripts/install/phase2_auto.js +21 -0
  66. package/dist/bollharness/src/scripts/install/pre_commit_installer.js +6 -0
  67. package/dist/bollharness/src/scripts/install/tier_selector.js +7 -0
  68. package/dist/bollharness/src/scripts/install/transcript_miner.js +7 -0
  69. package/dist/bollharness/src/scripts/lib/claim_patterns.js +10 -0
  70. package/dist/bollharness/src/scripts/lib/sanitize_patterns.js +12 -0
  71. package/dist/bollharness/src/scripts/sanitize.js +6 -0
  72. package/dist/bollharness-integration/channel-judgment-engine.js +530 -0
  73. package/dist/bollharness-integration/context-chain-router.js +383 -0
  74. package/dist/bollharness-integration/context-router-judgment.js +13 -21
  75. package/dist/bollharness-integration/context-router.js +22 -64
  76. package/dist/bollharness-integration/gate-state-machine.js +14 -19
  77. package/dist/bollharness-integration/gate-transition-hooks.js +16 -61
  78. package/dist/bollharness-integration/guard-checker.js +21 -68
  79. package/dist/bollharness-integration/index.js +14 -124
  80. package/dist/bollharness-integration/integration.js +13 -20
  81. package/dist/bollharness-integration/llm-judgment-engine.js +569 -0
  82. package/dist/bollharness-integration/skill-adapter.js +18 -64
  83. package/dist/cli-entry.js +261 -0
  84. package/dist/constraint-runtime/src/commands.js +17 -7
  85. package/dist/constraint-runtime/src/constraint/budget.js +1 -6
  86. package/dist/constraint-runtime/src/constraint/permission.js +1 -6
  87. package/dist/constraint-runtime/src/models.js +1 -3
  88. package/dist/constraint-runtime/src/tools.js +17 -7
  89. package/dist/constraints/index.js +1 -7
  90. package/dist/documents/reader.js +8 -49
  91. package/dist/heartbeat/DaemonManager.js +242 -0
  92. package/dist/heartbeat/HealthMonitor.js +285 -0
  93. package/dist/heartbeat/StartupVerifier.js +205 -0
  94. package/dist/heartbeat/Watchdog.js +168 -0
  95. package/dist/heartbeat/index.js +84 -0
  96. package/dist/heartbeat/types.js +5 -0
  97. package/dist/index.js +381 -28
  98. package/dist/llm/config-store.js +31 -57
  99. package/dist/llm/llm-judgment-client.js +389 -0
  100. package/dist/llm/pi-ai.js +9 -52
  101. package/dist/network/agent-network.js +46 -90
  102. package/dist/network/hybrid-messenger.js +125 -0
  103. package/dist/network/iroh-bootstrap.js +38 -0
  104. package/dist/network/iroh-discovery.js +145 -0
  105. package/dist/network/iroh-integration.js +9 -16
  106. package/dist/network/iroh-transport.js +10 -48
  107. package/dist/network/p2p.js +23 -62
  108. package/dist/network/storage/adapters/json-adapter.js +4 -42
  109. package/dist/network/storage/index.js +147 -0
  110. package/dist/network/storage/types.js +14 -0
  111. package/dist/pi-ecosystem/index.js +233 -0
  112. package/dist/pi-ecosystem-colony/index.js +29 -90
  113. package/dist/pi-ecosystem-goals/index.js +20 -74
  114. package/dist/pi-ecosystem-judgment/decision.js +29 -47
  115. package/dist/pi-ecosystem-judgment/distillation.js +16 -29
  116. package/dist/pi-ecosystem-judgment/human-value-store.js +13 -60
  117. package/dist/pi-ecosystem-judgment/index.js +21 -74
  118. package/dist/pi-ecosystem-judgment/value-injection.js +26 -72
  119. package/dist/pi-ecosystem-mcp/index.js +24 -78
  120. package/dist/pi-ecosystem-subagents/index.js +20 -69
  121. package/dist/social/ant-colony/AdaptiveHeartbeat.js +3 -8
  122. package/dist/social/ant-colony/PheromoneEngine.js +11 -49
  123. package/dist/social/ant-colony/index.js +6 -0
  124. package/dist/social/ant-colony/types.js +4 -8
  125. package/dist/social/channels/ChannelManager.js +8 -46
  126. package/dist/social/channels/DiapChannelBridge.js +9 -47
  127. package/dist/social/channels/InterestMatcher.js +2 -7
  128. package/dist/social/channels/channel-agent-session.js +309 -0
  129. package/dist/social/channels/channel-heartbeat-agent.js +494 -0
  130. package/dist/social/channels/diap-doc-parser.js +204 -0
  131. package/dist/social/channels/harness-workflow-integrator.js +446 -0
  132. package/dist/social/channels/index.js +9 -0
  133. package/dist/social/channels/types.js +3 -7
  134. package/dist/social/global-shared-context.js +6 -47
  135. package/dist/social/heartbeat.js +29 -72
  136. package/dist/social/persona/enhanced-persona.js +299 -0
  137. package/dist/web/client.js +302 -136
  138. package/dist/web/components/p2p/index.js +159 -9
  139. package/dist/web/components/p2p/p2p-connection.js +136 -0
  140. package/dist/web/components/p2p/p2p-manager.js +24 -0
  141. package/dist/web/components/p2p/p2p-store-memory.js +1 -1
  142. package/dist/web/components/p2p/types.js +7 -0
  143. package/dist/web/index.html +5 -0
  144. package/dist/web/style.css +118 -0
  145. package/package.json +12 -6
  146. package/scripts/build-cli.js +206 -0
  147. package/scripts/postinstall.js +153 -0
  148. package/src/agents/pi-sdk.ts +347 -28
  149. package/src/agents/protocol.ts +95 -1
  150. package/src/agents/workflow-pivot-loop.ts +674 -0
  151. package/src/bollharness/CLAUDE.md +73 -0
  152. package/src/bollharness/README.md +143 -0
  153. package/src/bollharness/README.zh-CN.md +131 -0
  154. package/src/bollharness/reference/boll-reference/scripts/hooks/stop-evaluator.md +57 -0
  155. package/src/bollharness/scripts/context-fragments/artifact-linkage.md +14 -0
  156. package/src/bollharness/scripts/context-fragments/auth-consumers.md +17 -0
  157. package/src/bollharness/scripts/context-fragments/bridge-constitution.md +13 -0
  158. package/src/bollharness/scripts/context-fragments/catalyst-distributed.md +18 -0
  159. package/src/bollharness/scripts/context-fragments/closure-checklist.md +13 -0
  160. package/src/bollharness/scripts/context-fragments/contract-consumers.md +15 -0
  161. package/src/bollharness/scripts/context-fragments/db-shared-structures.md +15 -0
  162. package/src/bollharness/scripts/context-fragments/fixed-three-layers.md +19 -0
  163. package/src/bollharness/scripts/context-fragments/general-dev-principles.md +11 -0
  164. package/src/bollharness/scripts/context-fragments/issue-first.md +8 -0
  165. package/src/bollharness/scripts/context-fragments/mcp-parity.md +16 -0
  166. package/src/bollharness/scripts/context-fragments/pi-agent-operations.md +108 -0
  167. package/src/bollharness/scripts/context-fragments/protocol-consumers.md +15 -0
  168. package/src/bollharness/scripts/context-fragments/run-events-consumers.md +15 -0
  169. package/src/bollharness/scripts/context-fragments/scene-fidelity.md +13 -0
  170. package/src/bollharness/scripts/context-fragments/truth-source-hierarchy.md +15 -0
  171. package/src/bollharness/scripts/context-fragments/two-language.md +15 -0
  172. package/src/bollharness/scripts/context-fragments/version-sources.md +14 -0
  173. package/src/bollharness/scripts/hooks/stop-evaluator.md +83 -0
  174. package/src/bollharness/templates/scaffold/CLAUDE.md +89 -0
  175. package/src/cli-entry.ts +304 -0
  176. package/src/heartbeat/DaemonManager.ts +283 -0
  177. package/src/heartbeat/HealthMonitor.ts +316 -0
  178. package/src/heartbeat/StartupVerifier.ts +223 -0
  179. package/src/heartbeat/Watchdog.ts +198 -0
  180. package/src/heartbeat/index.ts +108 -0
  181. package/src/heartbeat/types.ts +82 -0
  182. package/src/llm/config-store.ts +23 -5
  183. package/src/network/iroh-transport.ts +3 -3
  184. package/src/web/client.js +302 -136
  185. package/src/web/components/p2p/P2PModal.tsx +91 -3
  186. package/src/web/components/p2p/index.ts +171 -9
  187. package/src/web/components/p2p/p2p-connection.ts +153 -1
  188. package/src/web/components/p2p/p2p-manager.ts +39 -1
  189. package/src/web/components/p2p/p2p-store-memory.ts +1 -1
  190. package/src/web/components/p2p/p2p-tools.ts +315 -0
  191. package/src/web/components/p2p/types.ts +58 -0
  192. package/src/web/design.md +99 -0
  193. package/src/web/index.html +5 -0
  194. package/src/web/server.ts +353 -36
  195. package/src/web/style.css +118 -0
  196. package/tsconfig.cli.json +16 -0
  197. package/tsconfig.electron.json +1 -1
  198. package/tsconfig.json +1 -2
  199. package/dist/web/server.js +0 -1647
  200. package/dist/web/server.js.map +0 -1
@@ -1,6 +1,7 @@
1
1
  class P2PModalUI {
2
2
  modal = null;
3
3
  overlay = null;
4
+ connectedPeers = /* @__PURE__ */ new Map();
4
5
  constructor() {
5
6
  this.createModal();
6
7
  }
@@ -38,22 +39,49 @@ class P2PModalUI {
38
39
  }
39
40
  async render() {
40
41
  if (!this.modal) return;
42
+ await this.loadConnectionHistory();
41
43
  let identityHtml = '<div class="p2p-loading">\u52A0\u8F7D\u4E2D...</div>';
44
+ let identityData = { name: "\u672A\u77E5", did: "\u672A\u77E5", cid: "\u672A\u77E5" };
42
45
  try {
43
- const resp = await fetch("/api/identity");
44
- const data = await resp.json();
46
+ const irohResp = await fetch("/api/iroh/init", { method: "POST" });
47
+ const irohData = await irohResp.json();
48
+ if (irohData.cid) {
49
+ identityData = {
50
+ name: irohData.name || irohData.name?.split("-").slice(-1)[0] || "Bolloon",
51
+ did: irohData.did || "\u672A\u77E5",
52
+ cid: irohData.cid || "\u672A\u77E5",
53
+ nodeId: irohData.irohNodeId ? irohData.irohNodeId.substring(0, 20) + "..." : "\u672A\u77E5"
54
+ };
55
+ } else {
56
+ const resp = await fetch("/api/identity");
57
+ identityData = await resp.json();
58
+ identityData.cid = identityData.cid || "\u672A\u521D\u59CB\u5316";
59
+ identityData.nodeId = identityData.nodeId || "\u672A\u77E5";
60
+ }
45
61
  identityHtml = `
46
62
  <div class="p2p-section">
47
63
  <h3>\u8EAB\u4EFD\u4FE1\u606F</h3>
48
64
  <div class="p2p-info-row">
49
65
  <span class="label">\u540D\u79F0:</span>
50
- <span class="value">${this.escapeHtml(data.name || "\u672A\u77E5")}</span>
66
+ <span class="value">${this.escapeHtml(identityData.name || "\u672A\u77E5")}</span>
67
+ </div>
68
+ <div class="p2p-info-row">
69
+ <span class="label">CID:</span>
70
+ <span class="value mono">${this.escapeHtml(identityData.cid || "\u672A\u77E5")}</span>
51
71
  </div>
52
72
  <div class="p2p-info-row">
53
73
  <span class="label">DID:</span>
54
- <span class="value mono">${this.escapeHtml(data.did || "\u672A\u77E5")}</span>
74
+ <span class="value mono">${this.escapeHtml(identityData.did || "\u672A\u77E5")}</span>
75
+ </div>
76
+ <div class="p2p-info-row">
77
+ <span class="label">Node ID:</span>
78
+ <span class="value mono">${this.escapeHtml(identityData.nodeId || "\u672A\u77E5")}</span>
79
+ </div>
80
+ <div class="p2p-actions">
81
+ <button class="p2p-btn-secondary" id="p2p-copy-cid-btn">\u590D\u5236 CID</button>
82
+ <button class="p2p-btn-secondary" id="p2p-copy-did-btn">\u590D\u5236 DID</button>
83
+ <button class="p2p-btn-secondary" id="p2p-copy-nodeid-btn">\u590D\u5236 Node ID</button>
55
84
  </div>
56
- <button class="p2p-btn-primary" id="p2p-copy-btn">\u590D\u5236 DID</button>
57
85
  </div>
58
86
  `;
59
87
  } catch {
@@ -82,6 +110,12 @@ class P2PModalUI {
82
110
  </div>
83
111
  <div id="p2p-connect-result" class="p2p-result"></div>
84
112
  </div>
113
+ <div class="p2p-section">
114
+ <h3>\u5DF2\u8FDE\u63A5\u7684\u8282\u70B9</h3>
115
+ <div id="p2p-connected-peers" class="p2p-connected-peers">
116
+ \u6682\u65E0\u8FDE\u63A5
117
+ </div>
118
+ </div>
85
119
  </div>
86
120
  <div class="p2p-tab-content" data-tab="messages">
87
121
  <div class="p2p-section">
@@ -106,11 +140,24 @@ class P2PModalUI {
106
140
  if (tabName) this.switchTab(tabName);
107
141
  });
108
142
  });
109
- const copyBtn = this.modal.querySelector("#p2p-copy-btn");
110
- copyBtn?.addEventListener("click", async () => {
143
+ const copyCidBtn = this.modal.querySelector("#p2p-copy-cid-btn");
144
+ copyCidBtn?.addEventListener("click", async () => {
111
145
  try {
112
- const resp = await fetch("/api/identity");
113
- const data = await resp.json();
146
+ const irohResp = await fetch("/api/iroh/init", { method: "POST" });
147
+ const data = await irohResp.json();
148
+ if (data.cid) {
149
+ await navigator.clipboard.writeText(data.cid);
150
+ this.showToast("CID \u5DF2\u590D\u5236\u5230\u526A\u8D34\u677F");
151
+ }
152
+ } catch (e) {
153
+ console.error("\u590D\u5236\u5931\u8D25:", e);
154
+ }
155
+ });
156
+ const copyDidBtn = this.modal.querySelector("#p2p-copy-did-btn");
157
+ copyDidBtn?.addEventListener("click", async () => {
158
+ try {
159
+ const irohResp = await fetch("/api/iroh/init", { method: "POST" });
160
+ const data = await irohResp.json();
114
161
  if (data.did) {
115
162
  await navigator.clipboard.writeText(data.did);
116
163
  this.showToast("DID \u5DF2\u590D\u5236\u5230\u526A\u8D34\u677F");
@@ -119,6 +166,19 @@ class P2PModalUI {
119
166
  console.error("\u590D\u5236\u5931\u8D25:", e);
120
167
  }
121
168
  });
169
+ const copyNodeIdBtn = this.modal.querySelector("#p2p-copy-nodeid-btn");
170
+ copyNodeIdBtn?.addEventListener("click", async () => {
171
+ try {
172
+ const irohResp = await fetch("/api/iroh/init", { method: "POST" });
173
+ const data = await irohResp.json();
174
+ if (data.irohNodeId) {
175
+ await navigator.clipboard.writeText(data.irohNodeId);
176
+ this.showToast("Node ID \u5DF2\u590D\u5236\u5230\u526A\u8D34\u677F");
177
+ }
178
+ } catch (e) {
179
+ console.error("\u590D\u5236\u5931\u8D25:", e);
180
+ }
181
+ });
122
182
  const connectBtn = this.modal.querySelector("#p2p-connect-btn");
123
183
  connectBtn?.addEventListener("click", () => this.handleConnect());
124
184
  }
@@ -149,6 +209,23 @@ class P2PModalUI {
149
209
  if (data.ok) {
150
210
  result.innerHTML = `<div class="p2p-success">\u8FDE\u63A5\u6210\u529F\uFF01\u8282\u70B9: ${this.escapeHtml(data.nodeName || cid.substring(0, 16))}...</div>`;
151
211
  result.className = "p2p-result success";
212
+ input.value = "";
213
+ try {
214
+ await fetch("/api/p2p/history", {
215
+ method: "POST",
216
+ headers: { "Content-Type": "application/json" },
217
+ body: JSON.stringify({
218
+ cid,
219
+ // 输入的 CID 或 Node ID
220
+ irohNodeId: data.targetNodeId,
221
+ did: data.targetNodeId,
222
+ // 用 Node ID 作为 DID
223
+ name: data.nodeName || cid.substring(0, 16)
224
+ })
225
+ });
226
+ } catch (e) {
227
+ console.error("\u4FDD\u5B58\u8FDE\u63A5\u5931\u8D25:", e);
228
+ }
152
229
  } else {
153
230
  result.innerHTML = `<div class="p2p-error">${this.escapeHtml(data.error || "\u8FDE\u63A5\u5931\u8D25")}</div>`;
154
231
  result.className = "p2p-result error";
@@ -159,6 +236,44 @@ class P2PModalUI {
159
236
  result.className = "p2p-result error";
160
237
  }
161
238
  }
239
+ async loadConnectionHistory() {
240
+ try {
241
+ const resp = await fetch("/api/p2p/history");
242
+ const history = await resp.json();
243
+ this.connectedPeers.clear();
244
+ for (const entry of history) {
245
+ this.connectedPeers.set(entry.irohNodeId || entry.did, {
246
+ nodeId: entry.irohNodeId || entry.did,
247
+ name: entry.name || "Unknown",
248
+ time: entry.lastConnectedAt || Date.now()
249
+ });
250
+ }
251
+ this.updateConnectedPeersDisplay();
252
+ } catch (e) {
253
+ console.error("\u52A0\u8F7D\u8FDE\u63A5\u5386\u53F2\u5931\u8D25:", e);
254
+ }
255
+ }
256
+ updateConnectedPeersDisplay() {
257
+ const container = document.getElementById("p2p-connected-peers");
258
+ if (!container) return;
259
+ if (this.connectedPeers.size === 0) {
260
+ container.innerHTML = '<div class="p2p-empty">\u6682\u65E0\u8FDE\u63A5</div>';
261
+ return;
262
+ }
263
+ let html = "";
264
+ for (const [nodeId, info] of this.connectedPeers) {
265
+ const shortId = nodeId.substring(0, 16) + "...";
266
+ const time = new Date(info.time).toLocaleTimeString();
267
+ html += `
268
+ <div class="p2p-peer-item">
269
+ <span class="p2p-peer-name">${this.escapeHtml(info.name || shortId)}</span>
270
+ <span class="p2p-peer-id">${shortId}</span>
271
+ <span class="p2p-peer-time">${time}</span>
272
+ </div>
273
+ `;
274
+ }
275
+ container.innerHTML = html;
276
+ }
162
277
  escapeHtml(str) {
163
278
  const div = document.createElement("div");
164
279
  div.textContent = str;
@@ -348,6 +463,41 @@ style.textContent = `
348
463
  color: var(--text-muted, #606058);
349
464
  }
350
465
  .p2p-error { color: var(--error, #ef4444); }
466
+ .p2p-connected-peers {
467
+ background: var(--bg, #1a1a18);
468
+ border: 1px solid var(--border, #3a3a36);
469
+ border-radius: 8px;
470
+ overflow: hidden;
471
+ }
472
+ .p2p-connected-peers .p2p-empty {
473
+ padding: 16px;
474
+ text-align: center;
475
+ color: var(--text-muted, #606058);
476
+ font-size: 14px;
477
+ }
478
+ .p2p-peer-item {
479
+ display: flex;
480
+ align-items: center;
481
+ gap: 8px;
482
+ padding: 12px 16px;
483
+ border-bottom: 1px solid var(--border, #3a3a36);
484
+ }
485
+ .p2p-peer-item:last-child { border-bottom: none; }
486
+ .p2p-peer-name {
487
+ font-size: 14px;
488
+ color: var(--text, #d8d8c8);
489
+ min-width: 80px;
490
+ }
491
+ .p2p-peer-id {
492
+ flex: 1;
493
+ font-family: 'JetBrains Mono', monospace;
494
+ font-size: 12px;
495
+ color: var(--text-secondary, #909088);
496
+ }
497
+ .p2p-peer-time {
498
+ font-size: 12px;
499
+ color: var(--text-muted, #606058);
500
+ }
351
501
  `;
352
502
  document.head.appendChild(style);
353
503
  const p2pModal = new P2PModalUI();
@@ -157,5 +157,141 @@ export class P2PConnectionManager {
157
157
  this.reconnectTimers.clear();
158
158
  this.peers.clear();
159
159
  }
160
+ // 从 CID 解析身份
161
+ async resolveFromCID(cid) {
162
+ try {
163
+ const res = await fetch('/api/p2p/resolve-cid', {
164
+ method: 'POST',
165
+ headers: { 'Content-Type': 'application/json' },
166
+ body: JSON.stringify({ cid })
167
+ });
168
+ if (res.ok) {
169
+ const data = await res.json();
170
+ return {
171
+ success: true,
172
+ did: data.doc?.id || data.doc?.did,
173
+ cid: cid,
174
+ name: data.doc?.name,
175
+ peerId: data.doc?.peerId
176
+ };
177
+ }
178
+ else {
179
+ return { success: false, error: 'CID 解析失败' };
180
+ }
181
+ }
182
+ catch (e) {
183
+ return { success: false, error: e.message };
184
+ }
185
+ }
186
+ // 获取所有持久连接
187
+ async getPersistentConnections() {
188
+ try {
189
+ const res = await fetch('/api/p2p/persistent-connections');
190
+ if (res.ok) {
191
+ return await res.json();
192
+ }
193
+ return [];
194
+ }
195
+ catch {
196
+ return [];
197
+ }
198
+ }
199
+ // 切换连接状态
200
+ async toggleConnection(connection, enable) {
201
+ try {
202
+ if (enable) {
203
+ // 建立连接
204
+ const result = await this.connect(connection.cid);
205
+ if (result.success) {
206
+ await fetch('/api/p2p/connection-status', {
207
+ method: 'POST',
208
+ headers: { 'Content-Type': 'application/json' },
209
+ body: JSON.stringify({
210
+ id: connection.id,
211
+ status: 'connected',
212
+ channelId: connection.channelId
213
+ })
214
+ });
215
+ return true;
216
+ }
217
+ return false;
218
+ }
219
+ else {
220
+ // 断开连接
221
+ if (connection.peerId) {
222
+ await this.disconnect(connection.peerId);
223
+ }
224
+ await fetch('/api/p2p/connection-status', {
225
+ method: 'POST',
226
+ headers: { 'Content-Type': 'application/json' },
227
+ body: JSON.stringify({
228
+ id: connection.id,
229
+ status: 'disconnected'
230
+ })
231
+ });
232
+ return true;
233
+ }
234
+ }
235
+ catch {
236
+ return false;
237
+ }
238
+ }
239
+ // 连接并创建对话通道
240
+ async connectAndCreateChannel(input, onProgress) {
241
+ const parsed = this.parseInput(input);
242
+ if (parsed.type === 'invalid') {
243
+ return { success: false, error: parsed.error };
244
+ }
245
+ onProgress?.({ stage: 'validating', percent: 10, message: '验证输入格式...' });
246
+ let cid = '';
247
+ let did = '';
248
+ const value = parsed.value;
249
+ if (parsed.type === 'link' && typeof value !== 'string') {
250
+ cid = value.cid || '';
251
+ did = value.did || '';
252
+ }
253
+ else if (parsed.type === 'cid' && typeof value === 'string') {
254
+ cid = value;
255
+ }
256
+ else if (parsed.type === 'diapDoc' && typeof value !== 'string') {
257
+ cid = value.cid || '';
258
+ did = value.id || value.did || '';
259
+ }
260
+ if (!cid) {
261
+ return { success: false, error: '未找到 CID' };
262
+ }
263
+ // 如果没有 DID,从 CID 解析
264
+ if (!did) {
265
+ onProgress?.({ stage: 'resolving', percent: 30, message: '从 IPFS 解析身份...' });
266
+ const resolveResult = await this.resolveFromCID(cid);
267
+ if (resolveResult.success) {
268
+ did = resolveResult.did || '';
269
+ onProgress?.({ stage: 'identity_resolved', percent: 50, message: `身份解析完成: ${resolveResult.name}` });
270
+ }
271
+ }
272
+ // 创建对话通道
273
+ onProgress?.({ stage: 'creating_channel', percent: 60, message: '创建对话通道...' });
274
+ try {
275
+ const channelRes = await fetch('/api/p2p/create-channel', {
276
+ method: 'POST',
277
+ headers: { 'Content-Type': 'application/json' },
278
+ body: JSON.stringify({
279
+ peerDid: did,
280
+ peerName: did.substring(0, 16),
281
+ cid: cid,
282
+ peerId: ''
283
+ })
284
+ });
285
+ if (!channelRes.ok) {
286
+ return { success: false, error: '创建对话通道失败' };
287
+ }
288
+ }
289
+ catch (e) {
290
+ return { success: false, error: e.message };
291
+ }
292
+ // 执行连接
293
+ onProgress?.({ stage: 'connecting', percent: 80, message: '建立 P2P 连接...' });
294
+ return this.connect(input, onProgress);
295
+ }
160
296
  }
161
297
  export const p2pConnection = new P2PConnectionManager();
@@ -72,6 +72,30 @@ export class P2PManager {
72
72
  this.connection.destroy();
73
73
  this.messages.destroy();
74
74
  }
75
+ // 获取持久连接列表
76
+ async getPersistentConnections() {
77
+ return this.connection.getPersistentConnections();
78
+ }
79
+ // 更新连接状态
80
+ async updateConnectionStatus(id, status, channelId) {
81
+ await fetch('/api/p2p/connection-status', {
82
+ method: 'POST',
83
+ headers: { 'Content-Type': 'application/json' },
84
+ body: JSON.stringify({ id, status, channelId })
85
+ });
86
+ }
87
+ // 切换连接状态
88
+ async toggleConnection(connection, enable) {
89
+ return this.connection.toggleConnection(connection, enable);
90
+ }
91
+ // CID 解析
92
+ async resolveFromCID(cid) {
93
+ return this.connection.resolveFromCID(cid);
94
+ }
95
+ // 连接并创建对话通道
96
+ async connectAndCreateChannel(input, onProgress) {
97
+ return this.connection.connectAndCreateChannel(input, onProgress);
98
+ }
75
99
  }
76
100
  // 全局单例
77
101
  export const p2pManager = new P2PManager();
@@ -17,7 +17,7 @@ export class P2PStoreMemory {
17
17
  };
18
18
  // ==================== 连接历史 ====================
19
19
  async addToHistory(entry) {
20
- const existingIndex = this.history.findIndex(h => h.did === entry.did);
20
+ const existingIndex = this.history.findIndex(h => h.cid === entry.cid);
21
21
  if (existingIndex >= 0) {
22
22
  this.history[existingIndex] = {
23
23
  ...this.history[existingIndex],
@@ -21,3 +21,10 @@ export var MessageStatus;
21
21
  MessageStatus["FAILED"] = "failed";
22
22
  MessageStatus["QUEUED"] = "queued";
23
23
  })(MessageStatus || (MessageStatus = {}));
24
+ // 持久连接状态
25
+ export var PersistentConnectionStatus;
26
+ (function (PersistentConnectionStatus) {
27
+ PersistentConnectionStatus["CONNECTED"] = "connected";
28
+ PersistentConnectionStatus["DISCONNECTED"] = "disconnected";
29
+ PersistentConnectionStatus["RECONNECTING"] = "reconnecting";
30
+ })(PersistentConnectionStatus || (PersistentConnectionStatus = {}));
@@ -61,6 +61,11 @@
61
61
  <h1 id="channel-name">Bolloon Agent</h1>
62
62
  </div>
63
63
  <div class="header-right">
64
+ <button id="new-session-btn" class="header-action" title="新会话">
65
+ <svg width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
66
+ <path d="M12 5v14M5 12h14"></path>
67
+ </svg>
68
+ </button>
64
69
  <button id="theme-toggle" class="theme-toggle" title="切换主题">
65
70
  <svg class="sun-icon" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
66
71
  <circle cx="12" cy="12" r="5"></circle>
@@ -594,6 +594,21 @@ body {
594
594
  border-radius: 3px;
595
595
  }
596
596
 
597
+ /* Channel messages container */
598
+ .channel-messages {
599
+ display: none;
600
+ flex: 1;
601
+ overflow-y: auto;
602
+ padding: 24px;
603
+ flex-direction: column;
604
+ gap: 20px;
605
+ }
606
+
607
+ .channel-messages.active,
608
+ .channel-messages:not([style*="display: none"]) {
609
+ display: flex;
610
+ }
611
+
597
612
  .message {
598
613
  display: flex;
599
614
  flex-direction: column;
@@ -3231,6 +3246,109 @@ body {
3231
3246
  cursor: pointer;
3232
3247
  }
3233
3248
 
3249
+ /* Persistent Peers Section */
3250
+ .persistent-peers-section {
3251
+ margin: 16px 0;
3252
+ padding: 12px;
3253
+ background: var(--bg-secondary);
3254
+ border: 1px solid var(--border);
3255
+ border-radius: var(--radius);
3256
+ }
3257
+
3258
+ .persistent-peers-section h4 {
3259
+ margin-bottom: 12px;
3260
+ font-size: 14px;
3261
+ color: var(--text);
3262
+ }
3263
+
3264
+ .persistent-peer-item {
3265
+ display: flex;
3266
+ align-items: center;
3267
+ gap: 12px;
3268
+ padding: 12px;
3269
+ border: 1px solid var(--border);
3270
+ border-radius: 8px;
3271
+ margin-bottom: 8px;
3272
+ background: var(--bg-primary);
3273
+ transition: var(--transition);
3274
+ }
3275
+
3276
+ .persistent-peer-item:last-child {
3277
+ margin-bottom: 0;
3278
+ }
3279
+
3280
+ .persistent-peer-item.connected {
3281
+ border-color: var(--success);
3282
+ background: rgba(76, 175, 80, 0.05);
3283
+ }
3284
+
3285
+ .persistent-peer-item.disconnected {
3286
+ opacity: 0.8;
3287
+ }
3288
+
3289
+ .persistent-peer-item.reconnecting {
3290
+ border-color: var(--warning);
3291
+ animation: pulse 2s infinite;
3292
+ }
3293
+
3294
+ @keyframes pulse {
3295
+ 0%, 100% { opacity: 1; }
3296
+ 50% { opacity: 0.6; }
3297
+ }
3298
+
3299
+ .peer-status-indicator {
3300
+ flex-shrink: 0;
3301
+ }
3302
+
3303
+ .peer-status-indicator .dot {
3304
+ display: block;
3305
+ width: 10px;
3306
+ height: 10px;
3307
+ border-radius: 50%;
3308
+ }
3309
+
3310
+ .peer-status-indicator .dot.online {
3311
+ background: var(--success);
3312
+ box-shadow: 0 0 6px var(--success);
3313
+ }
3314
+
3315
+ .peer-status-indicator .dot.offline {
3316
+ background: var(--text-muted);
3317
+ }
3318
+
3319
+ .auto-badge {
3320
+ display: inline-block;
3321
+ padding: 2px 6px;
3322
+ font-size: 10px;
3323
+ background: var(--accent);
3324
+ color: var(--bg-primary);
3325
+ border-radius: 4px;
3326
+ margin-left: 6px;
3327
+ }
3328
+
3329
+ .peer-info .peer-name {
3330
+ display: flex;
3331
+ align-items: center;
3332
+ font-weight: 500;
3333
+ }
3334
+
3335
+ .peer-info .peer-meta {
3336
+ font-size: 12px;
3337
+ color: var(--text-secondary);
3338
+ display: flex;
3339
+ gap: 12px;
3340
+ margin-top: 4px;
3341
+ }
3342
+
3343
+ .btn-danger {
3344
+ background: var(--error);
3345
+ color: white;
3346
+ }
3347
+
3348
+ .btn-danger:hover {
3349
+ background: #c62828;
3350
+ }
3351
+
3234
3352
  /* Modal Small */
3235
3353
  .modal-sm {
3236
3354
  max-width: 300px !important;
package/package.json CHANGED
@@ -1,15 +1,20 @@
1
1
  {
2
2
  "name": "@bolloon/bolloon-agent",
3
- "version": "0.1.1",
3
+ "version": "0.1.3",
4
4
  "type": "module",
5
- "description": "P2P AI Document Agent with libp2p",
6
- "main": "dist/index.js",
5
+ "description": "P2P AI Document Agent - 全局安装后执行 `bolloon` 启动产品",
6
+ "main": "dist/cli.js",
7
7
  "author": "Bolloon Team",
8
+ "bin": {
9
+ "bolloon": "./bin/bolloon-cli.cjs"
10
+ },
8
11
  "scripts": {
9
12
  "build": "npm run build --workspaces --if-present",
10
13
  "build:main": "tsc",
14
+ "build:cli": "node scripts/build-cli.js",
11
15
  "build:web": "npx tsx scripts/build-web.ts",
12
16
  "build:electron": "tsc -p tsconfig.electron.json",
17
+ "build:all": "npm run build:main && npm run build:web && npm run build:electron && npm run build:cli",
13
18
  "start": "node dist/index.js",
14
19
  "dev": "tsx -r dotenv/config src/index.ts",
15
20
  "dev:web": "npm run build:web && npm run dev",
@@ -20,7 +25,8 @@
20
25
  "electron:pack": "electron-builder --dir",
21
26
  "test": "vitest run",
22
27
  "test:watch": "vitest",
23
- "test:pi-sdk": "tsx src/test/pi-sdk.test.ts"
28
+ "test:pi-sdk": "tsx src/test/pi-sdk.test.ts",
29
+ "postinstall": "node scripts/postinstall.js"
24
30
  },
25
31
  "workspaces": [
26
32
  "src/constraint-runtime"
@@ -73,11 +79,11 @@
73
79
  },
74
80
  "files": [
75
81
  "dist/**/*",
76
- "src/electron-main.js",
82
+ "bin/**/*",
77
83
  "package.json"
78
84
  ],
79
85
  "extraMetadata": {
80
- "main": "src/electron-main.js",
86
+ "main": "dist/electron.js",
81
87
  "type": "commonjs"
82
88
  },
83
89
  "win": {