@bolloon/bolloon-agent 0.1.1 → 0.1.2

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 +157 -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
@@ -0,0 +1,242 @@
1
+ /**
2
+ * DaemonManager - 守护进程管理器
3
+ * 支持自动重启、日志轮转、PID 管理
4
+ */
5
+ import * as fs from 'fs/promises';
6
+ import * as path from 'path';
7
+ export class DaemonManager {
8
+ config;
9
+ state = null;
10
+ stopRequested = false;
11
+ isChildProcess = false;
12
+ constructor(config = {}) {
13
+ this.config = {
14
+ maxRestarts: config.maxRestarts || 5,
15
+ restartDelayMs: config.restartDelayMs || 5000,
16
+ logFile: config.logFile || path.join(process.env.HOME || '/tmp', '.bolloon', 'daemon.log'),
17
+ pidFile: config.pidFile || path.join(process.env.HOME || '/tmp', '.bolloon', 'daemon.pid')
18
+ };
19
+ this.isChildProcess = process.env.BOLLOON_DAEMON_CHILD === '1';
20
+ }
21
+ /**
22
+ * 获取当前守护进程状态
23
+ */
24
+ async getState() {
25
+ try {
26
+ const pidData = await fs.readFile(this.config.pidFile, 'utf-8');
27
+ const pid = parseInt(pidData.trim(), 10);
28
+ if (isNaN(pid))
29
+ return null;
30
+ // 检查进程是否仍在运行
31
+ try {
32
+ process.kill(pid, 0); // Signal 0 只是检查进程是否存在
33
+ return { ...this.state, pid };
34
+ }
35
+ catch {
36
+ // 进程不存在
37
+ return null;
38
+ }
39
+ }
40
+ catch {
41
+ return null;
42
+ }
43
+ }
44
+ /**
45
+ * 检查是否已有守护进程在运行
46
+ */
47
+ async isRunning() {
48
+ const state = await this.getState();
49
+ return state !== null;
50
+ }
51
+ /**
52
+ * 保存 PID 文件
53
+ */
54
+ async savePid() {
55
+ await fs.mkdir(path.dirname(this.config.pidFile), { recursive: true });
56
+ await fs.writeFile(this.config.pidFile, String(process.pid));
57
+ console.log(`[Daemon] PID saved: ${process.pid}`);
58
+ }
59
+ /**
60
+ * 删除 PID 文件
61
+ */
62
+ async clearPid() {
63
+ try {
64
+ await fs.unlink(this.config.pidFile);
65
+ }
66
+ catch {
67
+ // 忽略删除失败
68
+ }
69
+ }
70
+ /**
71
+ * 写入日志
72
+ */
73
+ async writeLog(message) {
74
+ if (!this.config.logFile)
75
+ return;
76
+ try {
77
+ await fs.mkdir(path.dirname(this.config.logFile), { recursive: true });
78
+ const timestamp = new Date().toISOString();
79
+ await fs.appendFile(this.config.logFile, `[${timestamp}] ${message}\n`);
80
+ }
81
+ catch {
82
+ // 忽略日志写入失败
83
+ }
84
+ }
85
+ /**
86
+ * 启动主进程(父进程调用)
87
+ */
88
+ async spawn(processArgv = process.argv) {
89
+ // 检查是否已在运行
90
+ if (await this.isRunning()) {
91
+ console.log('[Daemon] Already running, pid:', (await this.getState())?.pid);
92
+ return;
93
+ }
94
+ this.state = {
95
+ pid: process.pid,
96
+ startedAt: Date.now(),
97
+ restartCount: 0
98
+ };
99
+ await this.savePid();
100
+ await this.writeLog('Daemon started');
101
+ // 设置优雅退出
102
+ this.setupGracefulShutdown();
103
+ // 注册信号处理
104
+ this.setupSignalHandlers();
105
+ console.log('[Daemon] Manager initialized');
106
+ }
107
+ /**
108
+ * 启动子进程并管理其生命周期
109
+ */
110
+ async runWithAutoRestart(childArgs) {
111
+ if (!this.isChildProcess) {
112
+ // 父进程:启动子进程
113
+ await this.runChildProcess(childArgs);
114
+ return;
115
+ }
116
+ // 子进程:正常运行主程序
117
+ console.log('[Daemon] Running as child process');
118
+ }
119
+ /**
120
+ * 启动子进程
121
+ */
122
+ async runChildProcess(childArgs) {
123
+ const { spawn } = await import('child_process');
124
+ let consecutiveFailures = 0;
125
+ while (!this.stopRequested && consecutiveFailures < this.config.maxRestarts) {
126
+ console.log(`[Daemon] Spawning child process (attempt ${consecutiveFailures + 1}/${this.config.maxRestarts})`);
127
+ const child = spawn(process.execPath, childArgs, {
128
+ stdio: 'inherit',
129
+ env: { ...process.env, BOLLOON_DAEMON_CHILD: '1' }
130
+ });
131
+ child.on('exit', async (code, signal) => {
132
+ const reason = signal || `exit code ${code}`;
133
+ console.log(`[Daemon] Child exited: ${reason}`);
134
+ if (this.stopRequested) {
135
+ console.log('[Daemon] Stop requested, not restarting');
136
+ await this.clearPid();
137
+ process.exit(0);
138
+ }
139
+ consecutiveFailures++;
140
+ this.state = {
141
+ ...this.state,
142
+ restartCount: consecutiveFailures,
143
+ lastRestartAt: Date.now(),
144
+ lastError: reason
145
+ };
146
+ if (consecutiveFailures < this.config.maxRestarts) {
147
+ console.log(`[Daemon] Restarting in ${this.config.restartDelayMs}ms...`);
148
+ await this.writeLog(`Child exited ${reason}, restarting (${consecutiveFailures}/${this.config.maxRestarts})`);
149
+ await new Promise(resolve => setTimeout(resolve, this.config.restartDelayMs));
150
+ // 继续 while 循环,重启子进程
151
+ }
152
+ else {
153
+ console.error('[Daemon] Max restarts reached, giving up');
154
+ await this.writeLog(`Max restarts reached (${this.config.maxRestarts})`);
155
+ await this.clearPid();
156
+ process.exit(1);
157
+ }
158
+ });
159
+ child.on('error', async (err) => {
160
+ console.error('[Daemon] Child process error:', err.message);
161
+ await this.writeLog(`Child error: ${err.message}`);
162
+ });
163
+ // 等待子进程退出
164
+ await new Promise((resolve) => {
165
+ child.on('exit', () => resolve());
166
+ });
167
+ }
168
+ }
169
+ /**
170
+ * 设置优雅退出
171
+ */
172
+ setupGracefulShutdown() {
173
+ let isShuttingDown = false;
174
+ const shutdown = async () => {
175
+ if (isShuttingDown)
176
+ return;
177
+ isShuttingDown = true;
178
+ console.log('[Daemon] Graceful shutdown...');
179
+ await this.writeLog('Graceful shutdown');
180
+ this.stopRequested = true;
181
+ await this.clearPid();
182
+ process.exit(0);
183
+ };
184
+ process.on('SIGTERM', shutdown);
185
+ process.on('SIGINT', shutdown);
186
+ process.on('uncaughtException', async (err) => {
187
+ console.error('[Daemon] Uncaught exception:', err);
188
+ await this.writeLog(`Uncaught exception: ${err.message}`);
189
+ await shutdown();
190
+ });
191
+ }
192
+ /**
193
+ * 设置信号处理
194
+ */
195
+ setupSignalHandlers() {
196
+ process.on('SIGHUP', () => {
197
+ console.log('[Daemon] Received SIGHUP, reloading...');
198
+ // 可以实现配置重载逻辑
199
+ });
200
+ }
201
+ /**
202
+ * 请求停止守护进程
203
+ */
204
+ async stop() {
205
+ const state = await this.getState();
206
+ if (state) {
207
+ console.log(`[Daemon] Sending SIGTERM to pid ${state.pid}`);
208
+ try {
209
+ process.kill(state.pid, 'SIGTERM');
210
+ }
211
+ catch {
212
+ console.log('[Daemon] Process not found, clearing PID');
213
+ }
214
+ }
215
+ await this.clearPid();
216
+ this.stopRequested = true;
217
+ }
218
+ /**
219
+ * 获取重启次数
220
+ */
221
+ async getRestartCount() {
222
+ return this.state?.restartCount || 0;
223
+ }
224
+ /**
225
+ * 检查是否可以继续重启
226
+ */
227
+ canRestart() {
228
+ return (this.state?.restartCount || 0) < this.config.maxRestarts;
229
+ }
230
+ }
231
+ // 全局实例
232
+ let daemonManagerInstance = null;
233
+ export function getDaemonManager() {
234
+ if (!daemonManagerInstance) {
235
+ daemonManagerInstance = new DaemonManager();
236
+ }
237
+ return daemonManagerInstance;
238
+ }
239
+ export function createDaemonManager(config) {
240
+ daemonManagerInstance = new DaemonManager(config);
241
+ return daemonManagerInstance;
242
+ }
@@ -0,0 +1,285 @@
1
+ /**
2
+ * HealthMonitor - 健康检查核心
3
+ * 监控 P2P、Iroh、LLM、内存等关键指标
4
+ */
5
+ import { getMinimax } from '../constraints/index.js';
6
+ export class HealthMonitor {
7
+ config;
8
+ lastHeartbeatTime = Date.now();
9
+ checkIntervalId = null;
10
+ onStatusChange;
11
+ constructor(config = {}) {
12
+ this.config = config;
13
+ this.onStatusChange = config.onStatusChange;
14
+ }
15
+ /**
16
+ * 执行完整健康检查
17
+ */
18
+ async check() {
19
+ const checks = {
20
+ p2p: await this.checkP2P(),
21
+ iroh: await this.checkIroh(),
22
+ llm: await this.checkLLM(),
23
+ memory: await this.checkMemory(),
24
+ heartbeat: await this.checkHeartbeat()
25
+ };
26
+ // 计算整体状态
27
+ const errors = Object.values(checks).filter(c => c.status === 'error').length;
28
+ let status = 'healthy';
29
+ if (errors >= 3) {
30
+ status = 'unhealthy';
31
+ }
32
+ else if (errors >= 1) {
33
+ status = 'degraded';
34
+ }
35
+ const healthStatus = {
36
+ status,
37
+ timestamp: new Date().toISOString(),
38
+ uptime_seconds: process.uptime(),
39
+ checks,
40
+ recommendations: this.generateRecommendations(checks)
41
+ };
42
+ this.onStatusChange?.(healthStatus);
43
+ return healthStatus;
44
+ }
45
+ /**
46
+ * 检查 P2P 连接状态
47
+ */
48
+ async checkP2P() {
49
+ const start = Date.now();
50
+ try {
51
+ // 从全局状态获取 HyperswarmCommunicator
52
+ const comm = global.hyperswarmComm;
53
+ if (!comm) {
54
+ return { status: 'ok', message: 'P2P not initialized yet', latency_ms: Date.now() - start };
55
+ }
56
+ const connections = comm.getConnections?.() || [];
57
+ return {
58
+ status: 'ok',
59
+ message: `Connected to ${connections.length} peers`,
60
+ details: { peer_count: connections.length },
61
+ latency_ms: Date.now() - start
62
+ };
63
+ }
64
+ catch (err) {
65
+ return { status: 'error', message: err.message, latency_ms: Date.now() - start };
66
+ }
67
+ }
68
+ /**
69
+ * 检查 Iroh 节点状态
70
+ */
71
+ async checkIroh() {
72
+ const start = Date.now();
73
+ try {
74
+ const { irohTransport } = await import('../network/iroh-transport.js');
75
+ if (!irohTransport.isRunning?.()) {
76
+ return { status: 'error', message: 'Iroh not running', latency_ms: Date.now() - start };
77
+ }
78
+ const nodeId = irohTransport.getNodeId?.() || '';
79
+ const peers = irohTransport.getPeers?.() || [];
80
+ const pendingOffline = irohTransport.getPendingOfflineCount?.() || 0;
81
+ return {
82
+ status: 'ok',
83
+ message: `Iroh running, ${peers.length} peers`,
84
+ details: {
85
+ nodeId: nodeId.substring(0, 16) + '...',
86
+ peer_count: peers.length,
87
+ pending_offline_messages: pendingOffline
88
+ },
89
+ latency_ms: Date.now() - start
90
+ };
91
+ }
92
+ catch (err) {
93
+ return { status: 'error', message: err.message, latency_ms: Date.now() - start };
94
+ }
95
+ }
96
+ /**
97
+ * 检查 LLM 连接状态
98
+ */
99
+ async checkLLM() {
100
+ const start = Date.now();
101
+ try {
102
+ const minimax = getMinimax();
103
+ if (!minimax) {
104
+ return { status: 'error', message: 'LLM not initialized', latency_ms: Date.now() - start };
105
+ }
106
+ // 执行 ping 测试
107
+ const latency = await this.pingLLM(minimax);
108
+ return {
109
+ status: 'ok',
110
+ message: 'LLM responsive',
111
+ details: { latency_ms: latency },
112
+ latency_ms: Date.now() - start
113
+ };
114
+ }
115
+ catch (err) {
116
+ return { status: 'error', message: err.message, latency_ms: Date.now() - start };
117
+ }
118
+ }
119
+ /**
120
+ * 检查内存使用
121
+ */
122
+ async checkMemory() {
123
+ const start = Date.now();
124
+ try {
125
+ const usage = process.memoryUsage();
126
+ const heapUsedPercent = (usage.heapUsed / usage.heapTotal) * 100;
127
+ const rssPercent = (usage.rss / (1024 * 1024 * 1024)) * 100; // GB
128
+ // 获取系统总内存 (macOS/Linux)
129
+ let systemMemoryPercent = 0;
130
+ try {
131
+ if (process.platform === 'darwin' || process.platform === 'linux') {
132
+ const { execSync } = require('child_process');
133
+ if (process.platform === 'darwin') {
134
+ const total = execSync('sysctl -n hw.memsize').toString().trim();
135
+ const free = execSync('vm_stat | grep "Pages free" | awk \'{print $3}\' | tr -d "."');
136
+ const pageSize = execSync('sysctl -n vm.pagesize').toString().trim();
137
+ systemMemoryPercent = ((parseInt(free) * parseInt(pageSize)) / parseInt(total)) * 100;
138
+ }
139
+ }
140
+ }
141
+ catch {
142
+ // 忽略系统内存获取失败
143
+ }
144
+ const isHealthy = heapUsedPercent < 80;
145
+ return {
146
+ status: isHealthy ? 'ok' : 'error',
147
+ message: isHealthy ? 'Memory usage normal' : 'Memory usage high',
148
+ details: {
149
+ heap_used_mb: Math.round(usage.heapUsed / 1024 / 1024),
150
+ heap_total_mb: Math.round(usage.heapTotal / 1024 / 1024),
151
+ heap_used_percent: Math.round(heapUsedPercent * 10) / 10,
152
+ rss_mb: Math.round(usage.rss / 1024 / 1024)
153
+ },
154
+ latency_ms: Date.now() - start
155
+ };
156
+ }
157
+ catch (err) {
158
+ return { status: 'error', message: err.message, latency_ms: Date.now() - start };
159
+ }
160
+ }
161
+ /**
162
+ * 检查心跳活跃度
163
+ */
164
+ async checkHeartbeat() {
165
+ const start = Date.now();
166
+ const elapsed = Date.now() - this.lastHeartbeatTime;
167
+ // 获取 SocialHeartbeat 状态
168
+ const heartbeat = global.socialHeartbeat;
169
+ let agentsCount = 0;
170
+ let antColonyEnabled = false;
171
+ if (heartbeat) {
172
+ const agents = heartbeat.getDiscoveredAgents?.();
173
+ agentsCount = agents?.length || 0;
174
+ antColonyEnabled = heartbeat.isAntColonyEnabled?.() || false;
175
+ }
176
+ return {
177
+ status: elapsed < 60000 ? 'ok' : 'error',
178
+ message: elapsed < 60000
179
+ ? `Heartbeat active ${Math.round(elapsed / 1000)}s ago`
180
+ : 'Heartbeat inactive for > 60s',
181
+ details: {
182
+ last_heartbeat_ms: elapsed,
183
+ discovered_agents: agentsCount,
184
+ ant_colony_enabled: antColonyEnabled
185
+ },
186
+ latency_ms: Date.now() - start
187
+ };
188
+ }
189
+ /**
190
+ * 记录心跳活跃
191
+ */
192
+ recordHeartbeat() {
193
+ this.lastHeartbeatTime = Date.now();
194
+ }
195
+ /**
196
+ * 获取当前状态(不执行检查)
197
+ */
198
+ getQuickStatus() {
199
+ const usage = process.memoryUsage();
200
+ return {
201
+ status: 'active',
202
+ lastHeartbeat: this.lastHeartbeatTime,
203
+ memoryUsage: Math.round((usage.heapUsed / usage.heapTotal) * 100)
204
+ };
205
+ }
206
+ /**
207
+ * 生成健康建议
208
+ */
209
+ generateRecommendations(checks) {
210
+ const recommendations = [];
211
+ if (checks.p2p.status === 'error') {
212
+ recommendations.push('P2P 连接失败,建议检查网络');
213
+ }
214
+ if (checks.iroh.status === 'error') {
215
+ recommendations.push('Iroh 节点未运行,消息可能无法发送');
216
+ }
217
+ if (checks.llm.status === 'error') {
218
+ recommendations.push('LLM 连接失败,检查 API 密钥配置');
219
+ }
220
+ if (checks.memory.status === 'error') {
221
+ recommendations.push('内存使用率过高,考虑重启服务');
222
+ }
223
+ if (checks.heartbeat.status === 'error') {
224
+ recommendations.push('心跳长时间未活跃,检查系统是否卡死');
225
+ }
226
+ return recommendations;
227
+ }
228
+ /**
229
+ * Ping LLM 测试响应
230
+ */
231
+ async pingLLM(minimax) {
232
+ const start = Date.now();
233
+ try {
234
+ // 简单的 chat 测试
235
+ if (minimax.chat) {
236
+ await minimax.chat('ping', 'test', { maxTokens: 1 });
237
+ }
238
+ else if (minimax.ping) {
239
+ await minimax.ping();
240
+ }
241
+ return Date.now() - start;
242
+ }
243
+ catch {
244
+ // 如果 ping 失败,返回一个较大的值但不是错误
245
+ return Date.now() - start;
246
+ }
247
+ }
248
+ /**
249
+ * 开始定期健康检查
250
+ */
251
+ startPeriodicCheck(intervalMs = 60000, callback) {
252
+ if (this.checkIntervalId) {
253
+ clearInterval(this.checkIntervalId);
254
+ }
255
+ const checkFn = async () => {
256
+ const status = await this.check();
257
+ callback?.(status);
258
+ this.onStatusChange?.(status);
259
+ };
260
+ this.checkIntervalId = setInterval(checkFn, intervalMs);
261
+ // 立即执行一次
262
+ checkFn();
263
+ }
264
+ /**
265
+ * 停止定期检查
266
+ */
267
+ stopPeriodicCheck() {
268
+ if (this.checkIntervalId) {
269
+ clearInterval(this.checkIntervalId);
270
+ this.checkIntervalId = null;
271
+ }
272
+ }
273
+ }
274
+ // 全局实例
275
+ let healthMonitorInstance = null;
276
+ export function getHealthMonitor() {
277
+ if (!healthMonitorInstance) {
278
+ healthMonitorInstance = new HealthMonitor();
279
+ }
280
+ return healthMonitorInstance;
281
+ }
282
+ export function createHealthMonitor(config) {
283
+ healthMonitorInstance = new HealthMonitor(config);
284
+ return healthMonitorInstance;
285
+ }