@bolloon/bolloon-agent 0.4.13 → 0.4.15

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 (221) hide show
  1. package/README.md +127 -127
  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/agent-gateway.js +130 -0
  6. package/dist/agents/constraint-layer.js +19 -19
  7. package/dist/agents/gateway-group.js +261 -0
  8. package/dist/agents/gateway-network.js +278 -0
  9. package/dist/agents/judgment-protocol.js +14 -14
  10. package/dist/agents/pi-sdk-tools.js +117 -0
  11. package/dist/agents/pi-sdk-types.js +12 -12
  12. package/dist/agents/pi-sdk.js +101 -101
  13. package/dist/agents/skill-organizer.js +19 -19
  14. package/dist/agents/workflow-pivot-loop.js +2 -2
  15. package/dist/agents/x402/x402Pay.js +4 -0
  16. package/dist/bollharness/src/scripts/deploy-guard.js +8 -8
  17. package/dist/bollharness-integration/context-router-judgment.js +4 -4
  18. package/dist/bollharness-integration/context-router.js +292 -292
  19. package/dist/bollharness-integration/gate-state-machine.js +13 -13
  20. package/dist/bollharness-integration/llm-judgment-engine.js +134 -134
  21. package/dist/bollharness-integration/skill-adapter.js +21 -21
  22. package/dist/bootstrap/chat-archiver.js +14 -14
  23. package/dist/bootstrap/context-os.js +24 -24
  24. package/dist/bootstrap/memory-compressor.js +13 -13
  25. package/dist/cli-entry.js +36 -36
  26. package/dist/constraint-runtime/reference_data/archive_surface_snapshot.json +63 -0
  27. package/dist/constraint-runtime/reference_data/commands_snapshot.json +1037 -0
  28. package/dist/constraint-runtime/reference_data/subsystems/assistant.json +8 -0
  29. package/dist/constraint-runtime/reference_data/subsystems/bootstrap.json +8 -0
  30. package/dist/constraint-runtime/reference_data/subsystems/bridge.json +32 -0
  31. package/dist/constraint-runtime/reference_data/subsystems/buddy.json +13 -0
  32. package/dist/constraint-runtime/reference_data/subsystems/cli.json +26 -0
  33. package/dist/constraint-runtime/reference_data/subsystems/components.json +32 -0
  34. package/dist/constraint-runtime/reference_data/subsystems/constants.json +28 -0
  35. package/dist/constraint-runtime/reference_data/subsystems/coordinator.json +8 -0
  36. package/dist/constraint-runtime/reference_data/subsystems/entrypoints.json +15 -0
  37. package/dist/constraint-runtime/reference_data/subsystems/hooks.json +32 -0
  38. package/dist/constraint-runtime/reference_data/subsystems/keybindings.json +21 -0
  39. package/dist/constraint-runtime/reference_data/subsystems/memdir.json +15 -0
  40. package/dist/constraint-runtime/reference_data/subsystems/migrations.json +18 -0
  41. package/dist/constraint-runtime/reference_data/subsystems/moreright.json +8 -0
  42. package/dist/constraint-runtime/reference_data/subsystems/native_ts.json +11 -0
  43. package/dist/constraint-runtime/reference_data/subsystems/outputStyles.json +8 -0
  44. package/dist/constraint-runtime/reference_data/subsystems/plugins.json +9 -0
  45. package/dist/constraint-runtime/reference_data/subsystems/remote.json +11 -0
  46. package/dist/constraint-runtime/reference_data/subsystems/schemas.json +8 -0
  47. package/dist/constraint-runtime/reference_data/subsystems/screens.json +10 -0
  48. package/dist/constraint-runtime/reference_data/subsystems/server.json +10 -0
  49. package/dist/constraint-runtime/reference_data/subsystems/services.json +32 -0
  50. package/dist/constraint-runtime/reference_data/subsystems/skills.json +27 -0
  51. package/dist/constraint-runtime/reference_data/subsystems/state.json +13 -0
  52. package/dist/constraint-runtime/reference_data/subsystems/types.json +18 -0
  53. package/dist/constraint-runtime/reference_data/subsystems/upstreamproxy.json +9 -0
  54. package/dist/constraint-runtime/reference_data/subsystems/utils.json +32 -0
  55. package/dist/constraint-runtime/reference_data/subsystems/vim.json +12 -0
  56. package/dist/constraint-runtime/reference_data/subsystems/voice.json +8 -0
  57. package/dist/constraint-runtime/reference_data/tools_snapshot.json +922 -0
  58. package/dist/constraint-runtime/tools/PolymarketSDK/econ-integration.d.ts +55 -0
  59. package/dist/constraint-runtime/tools/PolymarketSDK/econ-integration.js +59 -0
  60. package/dist/context-compaction/auto-compact.js +7 -7
  61. package/dist/electron/config.js.map +1 -0
  62. package/dist/electron/dialogs.js.map +1 -0
  63. package/dist/electron/first-run.js +54 -54
  64. package/dist/electron/first-run.js.map +1 -0
  65. package/dist/electron/ipc.js.map +1 -0
  66. package/dist/electron/logger.js.map +1 -0
  67. package/dist/electron/main.js.map +1 -0
  68. package/dist/electron/menu.js.map +1 -0
  69. package/dist/electron/paths.js.map +1 -0
  70. package/dist/electron/server.js.map +1 -0
  71. package/dist/electron/tray.js.map +1 -0
  72. package/dist/electron/window.js.map +1 -0
  73. package/dist/electron-build/electron/first-run.js +54 -54
  74. package/dist/electron-preload.js.map +1 -1
  75. package/dist/electron.js.map +1 -1
  76. package/dist/index.js +112 -112
  77. package/dist/llm/llm-judgment-client.js +102 -102
  78. package/dist/llm/pi-ai.js +48 -48
  79. package/dist/llm/system-prompt/layers/channel/human-async.md +41 -41
  80. package/dist/llm/system-prompt/layers/channel/local.md +14 -14
  81. package/dist/llm/system-prompt/layers/channel/p2p-agent.md +18 -18
  82. package/dist/llm/system-prompt/layers/channel/p2p-peer-sync.md +51 -51
  83. package/dist/llm/system-prompt/layers/channel/p2p-proactive.md +43 -43
  84. package/dist/llm/system-prompt/layers/channel/p2p-visitor.md +19 -19
  85. package/dist/llm/system-prompt/layers/channel/session-handoff.md +61 -61
  86. package/dist/llm/system-prompt/layers/core/artifacts_storage.md +89 -89
  87. package/dist/llm/system-prompt/layers/core/evenhandedness.md +21 -21
  88. package/dist/llm/system-prompt/layers/core/external-engagement.md +73 -73
  89. package/dist/llm/system-prompt/layers/core/hibs_reminders.md +15 -15
  90. package/dist/llm/system-prompt/layers/core/identity.md +48 -48
  91. package/dist/llm/system-prompt/layers/core/knowledge.md +17 -17
  92. package/dist/llm/system-prompt/layers/core/memory_system.md +12 -12
  93. package/dist/llm/system-prompt/layers/core/network_filesystem.md +28 -28
  94. package/dist/llm/system-prompt/layers/core/refusal.md +37 -37
  95. package/dist/llm/system-prompt/layers/core/tone.md +31 -31
  96. package/dist/llm/system-prompt/layers/core/tools.thin.md +13 -13
  97. package/dist/llm/system-prompt/layers/core/wellbeing.md +41 -41
  98. package/dist/llm/system-prompt/layers/role/architect.md +20 -20
  99. package/dist/llm/system-prompt/layers/role/expert.md +19 -19
  100. package/dist/llm/system-prompt/layers/role/implementer.md +15 -15
  101. package/dist/llm/system-prompt/layers/role/security.md +15 -15
  102. package/dist/llm/system-prompt/layers/tool/artifacts.md +72 -72
  103. package/dist/llm/system-prompt/layers/tool/bash.md +25 -25
  104. package/dist/llm/system-prompt/layers/tool/goal_handoff.md +77 -77
  105. package/dist/llm/system-prompt/layers/tool/hibs_api.md +171 -171
  106. package/dist/llm/system-prompt/layers/tool/image_search.md +70 -70
  107. package/dist/llm/system-prompt/layers/tool/manifest.md +89 -89
  108. package/dist/llm/system-prompt/layers/tool/mcp_apps.md +53 -53
  109. package/dist/llm/system-prompt/layers/tool/p2p_request.md +61 -61
  110. package/dist/llm/system-prompt/layers/tool/web_search.md +83 -83
  111. package/dist/llm/tool-manifest/ask_user_input.js +1 -1
  112. package/dist/llm/tool-manifest/bash.js +3 -3
  113. package/dist/llm/tool-manifest/create_file.js +4 -4
  114. package/dist/llm/tool-manifest/fetch_sports_data.js +3 -3
  115. package/dist/llm/tool-manifest/image_search.js +2 -2
  116. package/dist/llm/tool-manifest/index.js +59 -0
  117. package/dist/llm/tool-manifest/mcp.js +2 -2
  118. package/dist/llm/tool-manifest/message_compose.js +3 -3
  119. package/dist/llm/tool-manifest/places.js +2 -2
  120. package/dist/llm/tool-manifest/present_files.js +1 -1
  121. package/dist/llm/tool-manifest/recipe.js +2 -2
  122. package/dist/llm/tool-manifest/str_replace.js +5 -5
  123. package/dist/llm/tool-manifest/view.js +3 -3
  124. package/dist/llm/tool-manifest/weather.js +4 -4
  125. package/dist/llm/tool-manifest/web.js +4 -4
  126. package/dist/network/p2p.js +78 -4
  127. package/dist/orbitdb/cid-database.js +39 -10
  128. package/dist/pi-ecosystem-judgment/causal-judge.js +51 -51
  129. package/dist/pi-ecosystem-judgment/distill-prompt.js +42 -42
  130. package/dist/pi-ecosystem-judgment/distillation.js +14 -14
  131. package/dist/pi-ecosystem-judgment/index.js +1 -1
  132. package/dist/pi-ecosystem-judgment/monitor-gate.js +28 -28
  133. package/dist/pi-ecosystem-judgment/value-injection.js +102 -102
  134. package/dist/security/context-router-tool.js +15 -15
  135. package/dist/utils/auto-update.js.map +1 -0
  136. package/dist/web/a2ui-client.js +1594 -223
  137. package/dist/web/api-config.html +779 -779
  138. package/dist/web/client-hearth.js +10 -10
  139. package/dist/web/client.js +273 -0
  140. package/dist/web/client.js.map +7 -0
  141. package/dist/web/components/wallet-viem.mjs +118 -118
  142. package/dist/web/index.html +502 -485
  143. package/dist/web/manifest.json +20 -20
  144. package/dist/web/mobile-agent.js +397 -0
  145. package/dist/web/mobile-core.js +86235 -0
  146. package/dist/web/mobile-data.js +346 -0
  147. package/dist/web/mobile-http-api.js +71 -0
  148. package/dist/web/mobile-p2p.js +250 -0
  149. package/dist/web/mobile-payments.js +80 -0
  150. package/dist/web/mobile-wallet.js +226 -0
  151. package/dist/web/mobile.css +483 -6
  152. package/dist/web/mobile.html +99 -50
  153. package/dist/web/mobile.js +1040 -187
  154. package/dist/web/server.js +196 -13
  155. package/dist/web/style.css +5062 -4946
  156. package/package.json +201 -198
  157. package/scripts/build-cli.js +215 -215
  158. package/scripts/build-web.ts +162 -149
  159. package/scripts/postinstall.js +152 -152
  160. package/bin/bolloon.js +0 -157
  161. package/dist/agents/python-exec.js +0 -115
  162. package/dist/pi-ecosystem-colony/index.js +0 -365
  163. package/dist/social/ant-colony/AdaptiveHeartbeat.js +0 -101
  164. package/dist/social/ant-colony/PheromoneEngine.js +0 -227
  165. package/dist/social/ant-colony/index.js +0 -6
  166. package/dist/social/ant-colony/types.js +0 -24
  167. package/dist/storage/trajectory.js +0 -101
  168. package/dist/test/ai-judgment-test.js +0 -80
  169. package/dist/test/bollharness-integration.test.js +0 -318
  170. package/dist/test/channel-agent-multi-dialogue.js +0 -205
  171. package/dist/test/channel-heartbeat-agent-test.js +0 -201
  172. package/dist/test/constraint-layer.test.js +0 -164
  173. package/dist/test/diap-identity-test.js +0 -172
  174. package/dist/test/diap-quick-test.js +0 -62
  175. package/dist/test/global-shared-context.test.js +0 -315
  176. package/dist/test/harness-judgment-injection.test.js +0 -246
  177. package/dist/test/harness-workflow-integrator-test.js +0 -228
  178. package/dist/test/human-value-store.test.js +0 -243
  179. package/dist/test/hybrid-integration-test.js +0 -118
  180. package/dist/test/hybrid-messenger-verify.js +0 -55
  181. package/dist/test/iroh-bistream-debug.js +0 -38
  182. package/dist/test/iroh-communication.test.js +0 -66
  183. package/dist/test/iroh-debug-test.js +0 -57
  184. package/dist/test/iroh-diap-test.js +0 -71
  185. package/dist/test/iroh-direct-connect.js +0 -55
  186. package/dist/test/iroh-e2e-fixed.js +0 -89
  187. package/dist/test/iroh-e2e-same-process.js +0 -63
  188. package/dist/test/iroh-e2e.js +0 -66
  189. package/dist/test/iroh-final-e2e.js +0 -72
  190. package/dist/test/iroh-relay-test.js +0 -37
  191. package/dist/test/iroh-simple-test.js +0 -41
  192. package/dist/test/iroh-transport-verify.js +0 -54
  193. package/dist/test/iroh-transport.test.js +0 -37
  194. package/dist/test/iroh-two-nodes.js +0 -70
  195. package/dist/test/iroh-verify.js +0 -44
  196. package/dist/test/judgment-decision.test.js +0 -219
  197. package/dist/test/llm-judgment-integration.test.js +0 -220
  198. package/dist/test/p2p-agent-complex-dialogue.js +0 -385
  199. package/dist/test/p2p-agent-dialogue.js +0 -341
  200. package/dist/test/p2p-agent-full-bidirectional.js +0 -510
  201. package/dist/test/p2p-agent-harness-flow.js +0 -437
  202. package/dist/test/p2p-agent-harness-single.js +0 -143
  203. package/dist/test/p2p-ai-dialogue-test.js +0 -318
  204. package/dist/test/p2p-cid-connect-test.js +0 -195
  205. package/dist/test/p2p-connect-receiver.js +0 -69
  206. package/dist/test/p2p-doc-transfer.js +0 -110
  207. package/dist/test/p2p-identity-page-test.js +0 -77
  208. package/dist/test/p2p-iroh-test.js +0 -171
  209. package/dist/test/p2p-minimal-test.js +0 -241
  210. package/dist/test/p2p-node-1.js +0 -148
  211. package/dist/test/p2p-node-2.js +0 -148
  212. package/dist/test/p2p-server.js +0 -281
  213. package/dist/test/p2p-two-nodes-test.js +0 -438
  214. package/dist/test/pi-sdk.test.js +0 -44
  215. package/dist/test/set-persona.js +0 -40
  216. package/dist/test/simple.test.js +0 -9
  217. package/dist/test/storage-integration.test.js +0 -150
  218. package/dist/test/subagent-manager.test.js +0 -276
  219. package/dist/test/test-gate-flow.test.js +0 -81
  220. package/dist/test/workflow-engine.test.js +0 -87
  221. package/dist/test/workflow-pivot-loop.test.js +0 -246
@@ -1,148 +0,0 @@
1
- /**
2
- * P2P Node 1 - Alice
3
- * 运行: npx tsx src/test/p2p-node-1.ts
4
- */
5
- import { config } from 'dotenv';
6
- import express from 'express';
7
- import { createServer } from 'http';
8
- import crypto from 'crypto';
9
- config();
10
- const PORT = 3001;
11
- const NAME = 'Alice';
12
- const TOPIC = 'bolloon-p2p-test';
13
- class P2PNode {
14
- id = crypto.randomUUID();
15
- name = NAME;
16
- port = PORT;
17
- topic = TOPIC;
18
- peers = new Map();
19
- heartbeatInterval = null;
20
- async start() {
21
- const app = express();
22
- app.use(express.json());
23
- app.get('/health', (req, res) => {
24
- res.json({ id: this.id, name: this.name, port: this.port, peers: Array.from(this.peers.keys()) });
25
- });
26
- app.get('/discovery', (req, res) => {
27
- res.json({ id: this.id, name: this.name, port: this.port, topic: this.topic });
28
- });
29
- app.get('/nodes', (req, res) => {
30
- const nodes = Array.from(this.peers.entries()).map(([id, p]) => ({ id, name: p.name, port: p.port }));
31
- nodes.push({ id: this.id, name: this.name, port: this.port });
32
- res.json(nodes);
33
- });
34
- app.post('/message', (req, res) => {
35
- const { type, content } = req.body;
36
- console.log(`\n📨 [${this.name}] 收到消息: ${type} - ${content.substring(0, 50)}...`);
37
- if (type === 'ping') {
38
- console.log(` → 回复 pong`);
39
- this.broadcastToAll('pong', `Pong from ${this.name}!`);
40
- }
41
- else if (type === 'harness-sync') {
42
- console.log(`\n🔄 [${this.name}] Harness 同步消息:`);
43
- try {
44
- const sync = JSON.parse(content);
45
- console.log(` Gate: ${sync.gate}`);
46
- console.log(` Skills: ${sync.skills?.join(', ')}`);
47
- }
48
- catch { }
49
- }
50
- else if (type === 'chat') {
51
- console.log(` → 回复: 你好!我是 Alice`);
52
- this.broadcastToAll('chat', `你好!我是 Alice,很高兴认识你!`);
53
- }
54
- res.json({ ok: true });
55
- });
56
- app.post('/broadcast', (req, res) => {
57
- const { type, content } = req.body;
58
- console.log(`\n📢 [${this.name}] 收到广播: ${type}`);
59
- res.json({ ok: true });
60
- });
61
- const server = createServer(app);
62
- return new Promise((resolve, reject) => {
63
- server.listen(this.port, () => {
64
- console.log(`\n✓ [${this.name}] 启动成功 on port ${this.port}`);
65
- console.log(` ID: ${this.id.substring(0, 16)}...`);
66
- console.log(` Topic: ${this.topic}`);
67
- this.startHeartbeat();
68
- resolve();
69
- });
70
- server.on('error', reject);
71
- });
72
- }
73
- startHeartbeat() {
74
- this.heartbeatInterval = setInterval(async () => {
75
- console.log(`\n💓 [${this.name}] 心跳 - 扫描邻居...`);
76
- await this.discoverPeers();
77
- console.log(` 当前邻居: ${this.peers.size}`);
78
- if (this.peers.size > 0) {
79
- // 发送测试消息
80
- const peer = Array.from(this.peers.entries())[0];
81
- const [peerId, peerInfo] = peer;
82
- console.log(`\n📤 [${this.name}] 发送测试消息给 ${peerInfo.name}...`);
83
- try {
84
- await fetch(`http://localhost:${peerInfo.port}/message`, {
85
- method: 'POST',
86
- headers: { 'Content-Type': 'application/json' },
87
- body: JSON.stringify({
88
- type: 'chat',
89
- content: `你好 ${peerInfo.name},我是 ${this.name}!`
90
- })
91
- });
92
- }
93
- catch (err) {
94
- console.log(` 发送失败: ${err}`);
95
- this.peers.delete(peerId);
96
- }
97
- }
98
- }, 8000);
99
- }
100
- async discoverPeers() {
101
- const ports = [3001, 3002, 3003, 3004, 3005];
102
- for (const port of ports) {
103
- if (port === this.port)
104
- continue;
105
- try {
106
- const resp = await fetch(`http://localhost:${port}/discovery`, {
107
- signal: AbortSignal.timeout(1000)
108
- });
109
- if (resp.ok) {
110
- const info = await resp.json();
111
- if (info.topic === this.topic && info.id !== this.id) {
112
- if (!this.peers.has(info.id)) {
113
- console.log(`\n🔍 [${this.name}] 发现新节点: ${info.name} on port ${info.port}`);
114
- this.peers.set(info.id, { name: info.name, port: info.port });
115
- }
116
- }
117
- }
118
- }
119
- catch { }
120
- }
121
- }
122
- async broadcastToAll(type, content) {
123
- for (const [peerId, peerInfo] of this.peers) {
124
- try {
125
- await fetch(`http://localhost:${peerInfo.port}/message`, {
126
- method: 'POST',
127
- headers: { 'Content-Type': 'application/json' },
128
- body: JSON.stringify({ type, content })
129
- });
130
- }
131
- catch { }
132
- }
133
- }
134
- async stop() {
135
- if (this.heartbeatInterval)
136
- clearInterval(this.heartbeatInterval);
137
- }
138
- }
139
- // 启动
140
- const node = new P2PNode();
141
- node.start().then(() => {
142
- console.log('\n━━━ 等待节点发现... ━━━\n');
143
- process.on('SIGINT', async () => {
144
- console.log('\n\n🛑 正在停止...');
145
- await node.stop();
146
- process.exit(0);
147
- });
148
- }).catch(console.error);
@@ -1,148 +0,0 @@
1
- /**
2
- * P2P Node 2 - Bob
3
- * 运行: npx tsx src/test/p2p-node-2.ts
4
- */
5
- import { config } from 'dotenv';
6
- import express from 'express';
7
- import { createServer } from 'http';
8
- import crypto from 'crypto';
9
- config();
10
- const PORT = 3002;
11
- const NAME = 'Bob';
12
- const TOPIC = 'bolloon-p2p-test';
13
- class P2PNode {
14
- id = crypto.randomUUID();
15
- name = NAME;
16
- port = PORT;
17
- topic = TOPIC;
18
- peers = new Map();
19
- heartbeatInterval = null;
20
- async start() {
21
- const app = express();
22
- app.use(express.json());
23
- app.get('/health', (req, res) => {
24
- res.json({ id: this.id, name: this.name, port: this.port, peers: Array.from(this.peers.keys()) });
25
- });
26
- app.get('/discovery', (req, res) => {
27
- res.json({ id: this.id, name: this.name, port: this.port, topic: this.topic });
28
- });
29
- app.get('/nodes', (req, res) => {
30
- const nodes = Array.from(this.peers.entries()).map(([id, p]) => ({ id, name: p.name, port: p.port }));
31
- nodes.push({ id: this.id, name: this.name, port: this.port });
32
- res.json(nodes);
33
- });
34
- app.post('/message', (req, res) => {
35
- const { type, content } = req.body;
36
- console.log(`\n📨 [${this.name}] 收到消息: ${type} - ${content.substring(0, 50)}...`);
37
- if (type === 'ping') {
38
- console.log(` → 回复 pong`);
39
- this.broadcastToAll('pong', `Pong from ${this.name}!`);
40
- }
41
- else if (type === 'harness-sync') {
42
- console.log(`\n🔄 [${this.name}] Harness 同步消息:`);
43
- try {
44
- const sync = JSON.parse(content);
45
- console.log(` Gate: ${sync.gate}`);
46
- console.log(` Skills: ${sync.skills?.join(', ')}`);
47
- }
48
- catch { }
49
- }
50
- else if (type === 'chat') {
51
- console.log(` → 回复: 你好!我是 Bob`);
52
- this.broadcastToAll('chat', `你好!我是 Bob,很高兴认识你!`);
53
- }
54
- res.json({ ok: true });
55
- });
56
- app.post('/broadcast', (req, res) => {
57
- const { type, content } = req.body;
58
- console.log(`\n📢 [${this.name}] 收到广播: ${type}`);
59
- res.json({ ok: true });
60
- });
61
- const server = createServer(app);
62
- return new Promise((resolve, reject) => {
63
- server.listen(this.port, () => {
64
- console.log(`\n✓ [${this.name}] 启动成功 on port ${this.port}`);
65
- console.log(` ID: ${this.id.substring(0, 16)}...`);
66
- console.log(` Topic: ${this.topic}`);
67
- this.startHeartbeat();
68
- resolve();
69
- });
70
- server.on('error', reject);
71
- });
72
- }
73
- startHeartbeat() {
74
- this.heartbeatInterval = setInterval(async () => {
75
- console.log(`\n💓 [${this.name}] 心跳 - 扫描邻居...`);
76
- await this.discoverPeers();
77
- console.log(` 当前邻居: ${this.peers.size}`);
78
- if (this.peers.size > 0) {
79
- // 发送测试消息
80
- const peer = Array.from(this.peers.entries())[0];
81
- const [peerId, peerInfo] = peer;
82
- console.log(`\n📤 [${this.name}] 发送测试消息给 ${peerInfo.name}...`);
83
- try {
84
- await fetch(`http://localhost:${peerInfo.port}/message`, {
85
- method: 'POST',
86
- headers: { 'Content-Type': 'application/json' },
87
- body: JSON.stringify({
88
- type: 'chat',
89
- content: `你好 ${peerInfo.name},我是 ${this.name}!`
90
- })
91
- });
92
- }
93
- catch (err) {
94
- console.log(` 发送失败: ${err}`);
95
- this.peers.delete(peerId);
96
- }
97
- }
98
- }, 8000);
99
- }
100
- async discoverPeers() {
101
- const ports = [3001, 3002, 3003, 3004, 3005];
102
- for (const port of ports) {
103
- if (port === this.port)
104
- continue;
105
- try {
106
- const resp = await fetch(`http://localhost:${port}/discovery`, {
107
- signal: AbortSignal.timeout(1000)
108
- });
109
- if (resp.ok) {
110
- const info = await resp.json();
111
- if (info.topic === this.topic && info.id !== this.id) {
112
- if (!this.peers.has(info.id)) {
113
- console.log(`\n🔍 [${this.name}] 发现新节点: ${info.name} on port ${info.port}`);
114
- this.peers.set(info.id, { name: info.name, port: info.port });
115
- }
116
- }
117
- }
118
- }
119
- catch { }
120
- }
121
- }
122
- async broadcastToAll(type, content) {
123
- for (const [peerId, peerInfo] of this.peers) {
124
- try {
125
- await fetch(`http://localhost:${peerInfo.port}/message`, {
126
- method: 'POST',
127
- headers: { 'Content-Type': 'application/json' },
128
- body: JSON.stringify({ type, content })
129
- });
130
- }
131
- catch { }
132
- }
133
- }
134
- async stop() {
135
- if (this.heartbeatInterval)
136
- clearInterval(this.heartbeatInterval);
137
- }
138
- }
139
- // 启动
140
- const node = new P2PNode();
141
- node.start().then(() => {
142
- console.log('\n━━━ 等待节点发现... ━━━\n');
143
- process.on('SIGINT', async () => {
144
- console.log('\n\n🛑 正在停止...');
145
- await node.stop();
146
- process.exit(0);
147
- });
148
- }).catch(console.error);
@@ -1,281 +0,0 @@
1
- /**
2
- * P2P Two Web Servers Integration Test
3
- * 测试两个独立 Web 服务器能否相互发现并进行 P2P 交流
4
- *
5
- * 需要两个终端:
6
- * 终端 1: npx tsx src/test/p2p-server-1.ts
7
- * 终端 2: npx tsx src/test/p2p-server-2.ts
8
- */
9
- import { config } from 'dotenv';
10
- import express from 'express';
11
- import { createServer } from 'http';
12
- import crypto from 'crypto';
13
- config();
14
- const HEARTBEAT_INTERVAL = 5000;
15
- const DISCOVERY_URL = process.env.DISCOVERY_URL || 'http://localhost:3000';
16
- class P2PServer {
17
- id;
18
- name;
19
- port;
20
- topic;
21
- peers = new Map();
22
- heartbeatInterval = null;
23
- server = null;
24
- messageQueue = [];
25
- constructor(name, port, topic = 'bolloon-p2p-test') {
26
- this.id = crypto.randomUUID();
27
- this.name = name;
28
- this.port = port;
29
- this.topic = topic;
30
- }
31
- async start() {
32
- const app = express();
33
- app.use(express.json());
34
- // 健康检查
35
- app.get('/health', (req, res) => {
36
- res.json({
37
- id: this.id,
38
- name: this.name,
39
- port: this.port,
40
- peers: Array.from(this.peers.keys()),
41
- topic: this.topic
42
- });
43
- });
44
- // 发现端点
45
- app.get('/discovery', (req, res) => {
46
- res.json({
47
- id: this.id,
48
- name: this.name,
49
- port: this.port,
50
- topic: this.topic,
51
- peers: Array.from(this.peers.keys())
52
- });
53
- });
54
- // 获取所有已知节点
55
- app.get('/nodes', (req, res) => {
56
- const nodes = Array.from(this.peers.values());
57
- nodes.push({
58
- id: this.id,
59
- name: this.name,
60
- port: this.port,
61
- topic: this.topic,
62
- peers: Array.from(this.peers.keys()),
63
- lastHeartbeat: Date.now()
64
- });
65
- res.json(nodes);
66
- });
67
- // 消息接收
68
- app.post('/message', (req, res) => {
69
- const { type, content } = req.body;
70
- const msg = {
71
- type,
72
- from: this.id,
73
- content,
74
- timestamp: Date.now(),
75
- id: crypto.randomUUID()
76
- };
77
- this.handleMessage(msg);
78
- res.json({ ok: true, msgId: msg.id });
79
- });
80
- // 广播消息
81
- app.post('/broadcast', (req, res) => {
82
- const { type, content } = req.body;
83
- console.log(`[${this.name}] 收到广播: ${type}`);
84
- res.json({ ok: true });
85
- });
86
- // 直接消息
87
- app.post('/send', (req, res) => {
88
- const { to, type, content } = req.body;
89
- this.sendToPeer(to, type, content);
90
- res.json({ ok: true });
91
- });
92
- // 设置消息处理器
93
- app.post('/set-handler', (req, res) => {
94
- const { type, handler } = req.body;
95
- console.log(`[${this.name}] 设置消息处理器: ${type}`);
96
- res.json({ ok: true });
97
- });
98
- this.server = createServer(app);
99
- return new Promise((resolve, reject) => {
100
- this.server.listen(this.port, () => {
101
- console.log(`✓ [${this.name}] 启动成功 on port ${this.port}`);
102
- console.log(` ID: ${this.id}`);
103
- console.log(` Discovery: http://localhost:${this.port}/discovery`);
104
- this.startHeartbeat();
105
- resolve();
106
- });
107
- this.server.on('error', reject);
108
- });
109
- }
110
- startHeartbeat() {
111
- this.heartbeatInterval = setInterval(async () => {
112
- await this.discoverPeers();
113
- }, HEARTBEAT_INTERVAL);
114
- // 立即执行一次
115
- this.discoverPeers();
116
- }
117
- async discoverPeers() {
118
- const ports = [3001, 3002, 3003, 3004, 3005];
119
- for (const port of ports) {
120
- if (port === this.port)
121
- continue;
122
- try {
123
- const resp = await fetch(`http://localhost:${port}/discovery`, {
124
- signal: AbortSignal.timeout(1000)
125
- });
126
- if (resp.ok) {
127
- const info = await resp.json();
128
- if (info.topic === this.topic && info.id !== this.id) {
129
- const existing = this.peers.get(info.id);
130
- if (!existing) {
131
- console.log(`\n🔍 [${this.name}] 发现新节点: ${info.name} on port ${info.port}`);
132
- console.log(` Peer ID: ${info.id.substring(0, 16)}...`);
133
- this.peers.set(info.id, {
134
- id: info.id,
135
- name: info.name,
136
- port: info.port,
137
- topic: info.topic,
138
- peers: info.peers || [],
139
- lastHeartbeat: Date.now()
140
- });
141
- }
142
- else {
143
- existing.lastHeartbeat = Date.now();
144
- }
145
- }
146
- }
147
- }
148
- catch {
149
- // 节点不存在
150
- }
151
- }
152
- }
153
- handleMessage(msg) {
154
- console.log(`\n📨 [${this.name}] 收到消息:`);
155
- console.log(` Type: ${msg.type}`);
156
- console.log(` From: ${msg.from.substring(0, 16)}...`);
157
- console.log(` Content: ${msg.content.substring(0, 50)}...`);
158
- this.messageQueue.push(msg);
159
- if (this.messageQueue.length > 100) {
160
- this.messageQueue.shift();
161
- }
162
- // 处理特定类型的消息
163
- if (msg.type === 'ping') {
164
- this.sendToPeer(msg.from, 'pong', `Pong from ${this.name}!`);
165
- }
166
- else if (msg.type === 'harness-sync') {
167
- console.log(`\n🔄 [${this.name}] 收到 Harness 同步消息`);
168
- try {
169
- const sync = JSON.parse(msg.content);
170
- console.log(` Gate: ${sync.gate || 'N/A'}`);
171
- console.log(` Skills: ${sync.skills?.join(', ') || 'N/A'}`);
172
- }
173
- catch {
174
- console.log(` Content: ${msg.content}`);
175
- }
176
- }
177
- else if (msg.type === 'chat') {
178
- console.log(`\n💬 [${this.name}] 收到聊天消息: ${msg.content}`);
179
- }
180
- }
181
- async sendToPeer(peerId, type, content) {
182
- const peer = this.peers.get(peerId);
183
- if (!peer) {
184
- console.log(`[${this.name}] Unknown peer: ${peerId.substring(0, 8)}...`);
185
- return;
186
- }
187
- try {
188
- await fetch(`http://localhost:${peer.port}/message`, {
189
- method: 'POST',
190
- headers: { 'Content-Type': 'application/json' },
191
- body: JSON.stringify({ type, content })
192
- });
193
- console.log(`[${this.name}] 消息已发送到 ${peer.name}`);
194
- }
195
- catch (err) {
196
- console.log(`[${this.name}] 发送失败:`, err);
197
- }
198
- }
199
- async broadcast(type, content) {
200
- console.log(`\n📢 [${this.name}] 广播消息: ${type}`);
201
- console.log(` Content: ${content.substring(0, 50)}...`);
202
- for (const [peerId, peer] of this.peers) {
203
- try {
204
- await fetch(`http://localhost:${peer.port}/broadcast`, {
205
- method: 'POST',
206
- headers: { 'Content-Type': 'application/json' },
207
- body: JSON.stringify({ type, content })
208
- });
209
- }
210
- catch {
211
- // peer unavailable
212
- }
213
- }
214
- }
215
- getPeers() {
216
- return Array.from(this.peers.keys());
217
- }
218
- getPeerCount() {
219
- return this.peers.size;
220
- }
221
- async stop() {
222
- if (this.heartbeatInterval) {
223
- clearInterval(this.heartbeatInterval);
224
- }
225
- if (this.server) {
226
- await new Promise(resolve => this.server.close(resolve));
227
- }
228
- }
229
- }
230
- // 导出以便在其他地方使用
231
- export { P2PServer };
232
- // 入口点
233
- async function main() {
234
- const args = process.argv.slice(2);
235
- const port = parseInt(args.find(a => a.startsWith('--port='))?.split('=')[1] || '3001');
236
- const name = args.find(a => a.startsWith('--name='))?.split('=')[1] || `Node-${port}`;
237
- const action = args[0] || 'start';
238
- if (action === 'start') {
239
- const node = new P2PServer(name, port);
240
- await node.start();
241
- console.log('\n━━━ 节点已启动,等待发现... ━━━\n');
242
- // 保持运行
243
- process.on('SIGINT', async () => {
244
- console.log('\n\n🛑 正在停止节点...');
245
- await node.stop();
246
- console.log('✓ 节点已停止');
247
- process.exit(0);
248
- });
249
- // 每 10 秒发送一次测试消息
250
- let count = 0;
251
- const testInterval = setInterval(async () => {
252
- count++;
253
- if (node.getPeerCount() > 0) {
254
- const peers = node.getPeers();
255
- const peerId = peers[0];
256
- if (count % 3 === 0) {
257
- // 每 30 秒发送 harness 同步
258
- const syncMsg = JSON.stringify({
259
- gate: count / 3,
260
- skills: ['arch', 'lead', 'harness-eng'],
261
- agents: [node.id, ...peers],
262
- timestamp: Date.now()
263
- });
264
- await node.sendToPeer(peerId, 'harness-sync', syncMsg);
265
- }
266
- else {
267
- // 普通聊天
268
- await node.sendToPeer(peerId, 'chat', `Hello from ${name}! Message #${count}`);
269
- }
270
- }
271
- else {
272
- console.log(`[${name}] 等待邻居... (${count * 10}s)`);
273
- }
274
- }, 10000);
275
- }
276
- }
277
- // 如果直接运行
278
- if (import.meta.url === `file://${process.argv[1]}`.replace(/\\/g, '/')) {
279
- main().catch(console.error);
280
- }
281
- export default P2PServer;