@bolloon/bolloon-agent 0.1.33 → 0.1.35

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 (80) hide show
  1. package/.auto-evolve-calls +1 -0
  2. package/.last-auto-evolve-baseline +1 -0
  3. package/Bolloon.md +103 -0
  4. package/README.md +7 -2
  5. package/dist/agents/pi-sdk.js +264 -12
  6. package/dist/bollharness-integration/index.js +8 -1
  7. package/dist/bootstrap/bootstrap.js +114 -0
  8. package/dist/bootstrap/context-collector.js +296 -0
  9. package/dist/bootstrap/lifecycle-hooks.js +109 -0
  10. package/dist/bootstrap/project-context.js +151 -0
  11. package/dist/heartbeat/Watchdog.js +9 -1
  12. package/dist/index.js +11 -0
  13. package/dist/llm/pi-ai.js +31 -21
  14. package/dist/network/p2p-direct.js +59 -2
  15. package/dist/pi-ecosystem/index.js +9 -6
  16. package/dist/pi-ecosystem-judgment/adaptive-scan.js +231 -0
  17. package/dist/pi-ecosystem-judgment/causal-judge.js +449 -0
  18. package/dist/pi-ecosystem-judgment/decision.js +5 -2
  19. package/dist/pi-ecosystem-judgment/detect-hook.js +168 -0
  20. package/dist/pi-ecosystem-judgment/distill-prompt.js +226 -0
  21. package/dist/pi-ecosystem-judgment/evolve-judgment.js +170 -0
  22. package/dist/pi-ecosystem-judgment/human-value-pipeline.js +21 -0
  23. package/dist/pi-ecosystem-judgment/human-value-store.js +283 -22
  24. package/dist/pi-ecosystem-judgment/injection-gate.js +166 -0
  25. package/dist/pi-ecosystem-judgment/monitor-gate.js +188 -0
  26. package/dist/security/builtin-guards.js +124 -0
  27. package/dist/security/context-router-tool.js +106 -0
  28. package/dist/security/react-harness.js +143 -0
  29. package/dist/security/tool-gate.js +235 -0
  30. package/dist/social/heartbeat.js +19 -2
  31. package/dist/utils/auto-evolve-policy.js +117 -0
  32. package/dist/utils/clamp.js +7 -0
  33. package/dist/utils/double.js +6 -0
  34. package/dist/web/api-config.html +3 -3
  35. package/dist/web/client.js +1328 -351
  36. package/dist/web/index.html +34 -31
  37. package/dist/web/server.js +1128 -58
  38. package/dist/web/style.css +370 -0
  39. package/lefthook.yml +29 -0
  40. package/package.json +4 -2
  41. package/scripts/auto-evolve-loop.ts +376 -0
  42. package/scripts/auto-evolve-oneshot.sh +155 -0
  43. package/scripts/auto-evolve-snapshot.sh +136 -0
  44. package/scripts/detect-schema-changes.sh +48 -0
  45. package/scripts/diff-reviewer.ts +159 -0
  46. package/scripts/weekly-report.ts +364 -0
  47. package/src/agents/pi-sdk.ts +293 -15
  48. package/src/bollharness-integration/index.ts +8 -32
  49. package/src/bootstrap/bootstrap.ts +132 -0
  50. package/src/bootstrap/context-collector.ts +342 -0
  51. package/src/bootstrap/lifecycle-hooks.ts +176 -0
  52. package/src/bootstrap/project-context.ts +163 -0
  53. package/src/heartbeat/Watchdog.ts +9 -1
  54. package/src/index.ts +11 -0
  55. package/src/llm/pi-ai.ts +33 -22
  56. package/src/network/p2p-direct.ts +59 -3
  57. package/src/security/builtin-guards.ts +162 -0
  58. package/src/security/context-router-tool.ts +122 -0
  59. package/src/security/react-harness.ts +177 -0
  60. package/src/security/tool-gate.ts +294 -0
  61. package/src/social/ant-colony/index.js +19 -0
  62. package/src/social/heartbeat.ts +18 -2
  63. package/src/utils/auto-evolve-policy.ts +138 -0
  64. package/src/utils/clamp.ts +5 -0
  65. package/src/web/api-config.html +3 -3
  66. package/src/web/client.js +1328 -351
  67. package/src/web/index.html +34 -31
  68. package/src/web/server.ts +1179 -53
  69. package/src/web/style.css +370 -0
  70. package/staging/auto-evolve/clean-001/.review-verdict +9 -0
  71. package/staging/auto-evolve/clean-001/clean-001.patch +14 -0
  72. package/staging/auto-evolve/e2e-001/.patch-id +1 -0
  73. package/staging/auto-evolve/e2e-001/.review-verdict +12 -0
  74. package/staging/auto-evolve/e2e-001/e2e-001.patch +11 -0
  75. package/staging/auto-evolve/test-bad/.review-verdict +12 -0
  76. package/staging/auto-evolve/test-bad/test-bad.patch +11 -0
  77. package/src/social/ant-colony/AdaptiveHeartbeat.ts +0 -131
  78. package/src/social/ant-colony/PheromoneEngine.ts +0 -302
  79. package/src/social/ant-colony/index.ts +0 -18
  80. package/src/social/ant-colony/types.ts +0 -94
package/src/web/style.css CHANGED
@@ -4083,3 +4083,373 @@ body:has(> .api-config-page) {
4083
4083
  cursor: pointer;
4084
4084
  accent-color: var(--accent);
4085
4085
  }
4086
+
4087
+ /* ============================================================
4088
+ * 2026-06-10: 远程聊天 modal — 完全对齐本地聊天风格
4089
+ * 用 CSS 变量, 字体继承全局 JetBrains Mono, 支持深/浅色主题切换
4090
+ * ============================================================ */
4091
+ .remote-chat-overlay {
4092
+ position: fixed;
4093
+ inset: 0;
4094
+ background: rgba(0, 0, 0, 0.55);
4095
+ z-index: 10002;
4096
+ display: flex;
4097
+ align-items: center;
4098
+ justify-content: center;
4099
+ }
4100
+ .remote-chat-shell {
4101
+ background: var(--bg-main);
4102
+ color: var(--text);
4103
+ border: 1px solid var(--border);
4104
+ border-radius: 8px;
4105
+ width: 720px;
4106
+ max-width: 92vw;
4107
+ height: 80vh;
4108
+ max-height: 80vh;
4109
+ display: flex;
4110
+ flex-direction: column;
4111
+ box-shadow: 0 10px 40px rgba(0, 0, 0, 0.35);
4112
+ font-family: inherit;
4113
+ }
4114
+ .remote-chat-header {
4115
+ padding: 12px 16px;
4116
+ border-bottom: 1px solid var(--border);
4117
+ display: flex;
4118
+ align-items: center;
4119
+ justify-content: space-between;
4120
+ gap: 8px;
4121
+ background: var(--bg-sidebar);
4122
+ border-radius: 8px 8px 0 0;
4123
+ }
4124
+ .remote-chat-title {
4125
+ font-size: 15px;
4126
+ font-weight: 600;
4127
+ color: var(--text);
4128
+ }
4129
+ .remote-chat-meta {
4130
+ font-size: 11px;
4131
+ color: var(--text-muted);
4132
+ margin-top: 2px;
4133
+ overflow: hidden;
4134
+ text-overflow: ellipsis;
4135
+ white-space: nowrap;
4136
+ }
4137
+ .remote-chat-btn-secondary {
4138
+ background: var(--bg-hover);
4139
+ border: 1px solid var(--border);
4140
+ color: var(--text-secondary);
4141
+ cursor: pointer;
4142
+ padding: 4px 10px;
4143
+ border-radius: 4px;
4144
+ font-size: 11px;
4145
+ font-family: inherit;
4146
+ }
4147
+ .remote-chat-btn-secondary:hover {
4148
+ background: var(--bg-active);
4149
+ color: var(--text);
4150
+ }
4151
+ .remote-chat-btn-close {
4152
+ background: none;
4153
+ border: none;
4154
+ font-size: 20px;
4155
+ color: var(--text-muted);
4156
+ cursor: pointer;
4157
+ padding: 0 8px;
4158
+ line-height: 1;
4159
+ }
4160
+ .remote-chat-btn-close:hover {
4161
+ color: var(--text);
4162
+ }
4163
+ .remote-chat-thinking {
4164
+ padding: 8px 16px;
4165
+ background: var(--bg-hover);
4166
+ color: var(--text-secondary);
4167
+ font-size: 12px;
4168
+ border-bottom: 1px solid var(--border);
4169
+ }
4170
+ .remote-chat-log {
4171
+ flex: 1;
4172
+ overflow-y: auto;
4173
+ padding: 12px 16px;
4174
+ background: var(--bg-main);
4175
+ }
4176
+ .remote-chat-input-row {
4177
+ padding: 10px 12px;
4178
+ border-top: 1px solid var(--border);
4179
+ display: flex;
4180
+ gap: 6px;
4181
+ background: var(--bg-sidebar);
4182
+ border-radius: 0 0 8px 8px;
4183
+ }
4184
+ .remote-chat-input {
4185
+ flex: 1;
4186
+ padding: 8px 10px;
4187
+ border: 1px solid var(--border);
4188
+ border-radius: 4px;
4189
+ font-size: 13px;
4190
+ background: var(--bg-main);
4191
+ color: var(--text);
4192
+ font-family: inherit;
4193
+ }
4194
+ .remote-chat-input:focus {
4195
+ outline: none;
4196
+ border-color: var(--accent, #a4b630);
4197
+ }
4198
+ .remote-chat-btn-send {
4199
+ padding: 8px 14px;
4200
+ background: var(--user-bg);
4201
+ color: var(--user-text);
4202
+ border: none;
4203
+ border-radius: 4px;
4204
+ cursor: pointer;
4205
+ font-size: 13px;
4206
+ font-weight: 600;
4207
+ font-family: inherit;
4208
+ }
4209
+ .remote-chat-btn-send:hover:not(:disabled) {
4210
+ filter: brightness(1.1);
4211
+ }
4212
+ .remote-chat-btn-send:disabled {
4213
+ opacity: 0.5;
4214
+ cursor: wait;
4215
+ }
4216
+ .remote-chat-sysmsg {
4217
+ margin: 6px 0;
4218
+ padding: 6px 10px;
4219
+ border-radius: 4px;
4220
+ font-size: 11px;
4221
+ text-align: center;
4222
+ border: 1px solid var(--border);
4223
+ }
4224
+ .remote-chat-sysmsg-info {
4225
+ background: var(--bg-hover);
4226
+ color: var(--text-secondary);
4227
+ }
4228
+ .remote-chat-sysmsg-warn {
4229
+ background: var(--bg-hover);
4230
+ color: var(--text);
4231
+ border-color: var(--border-light);
4232
+ }
4233
+ .remote-chat-sysmsg-error {
4234
+ background: rgba(220, 38, 38, 0.12);
4235
+ color: #fca5a5;
4236
+ border-color: rgba(220, 38, 38, 0.3);
4237
+ }
4238
+ .remote-chat-judgments {
4239
+ margin: 0 0 8px;
4240
+ padding: 8px 10px;
4241
+ background: var(--bg-hover);
4242
+ border-left: 3px solid var(--accent, #a4b630);
4243
+ border-radius: 4px;
4244
+ font-size: 12px;
4245
+ }
4246
+ .remote-chat-judgments-title {
4247
+ font-weight: 600;
4248
+ color: var(--text);
4249
+ margin-bottom: 4px;
4250
+ }
4251
+ .remote-chat-judgment-item {
4252
+ margin: 3px 0;
4253
+ padding-left: 8px;
4254
+ color: var(--text);
4255
+ }
4256
+ .remote-chat-judgment-tag {
4257
+ color: var(--text-muted);
4258
+ font-size: 10px;
4259
+ }
4260
+ .remote-chat-judgment-reason {
4261
+ color: var(--text-secondary);
4262
+ font-size: 11px;
4263
+ }
4264
+ .remote-chat-judgments-foot {
4265
+ margin-top: 6px;
4266
+ color: var(--text-muted);
4267
+ font-size: 11px;
4268
+ }
4269
+
4270
+ /* ============================================================
4271
+ * 2026-06-10: 好友申请 modal — 对齐本地风格 + CSS 变量
4272
+ * ============================================================ */
4273
+ .friend-req-overlay {
4274
+ position: fixed;
4275
+ inset: 0;
4276
+ background: rgba(0, 0, 0, 0.55);
4277
+ z-index: 10004;
4278
+ display: flex;
4279
+ align-items: center;
4280
+ justify-content: center;
4281
+ }
4282
+ .friend-req-shell {
4283
+ background: var(--bg-main);
4284
+ color: var(--text);
4285
+ border: 1px solid var(--border);
4286
+ border-radius: 8px;
4287
+ width: 460px;
4288
+ max-width: 92vw;
4289
+ box-shadow: 0 10px 40px rgba(0, 0, 0, 0.4);
4290
+ font-family: inherit;
4291
+ }
4292
+ .friend-req-header {
4293
+ padding: 14px 18px;
4294
+ border-bottom: 1px solid var(--border);
4295
+ background: var(--bg-sidebar);
4296
+ display: flex;
4297
+ align-items: center;
4298
+ gap: 10px;
4299
+ border-radius: 8px 8px 0 0;
4300
+ }
4301
+ .friend-req-title {
4302
+ font-size: 15px;
4303
+ font-weight: 600;
4304
+ color: var(--text);
4305
+ }
4306
+ .friend-req-meta {
4307
+ font-size: 11px;
4308
+ color: var(--text-muted);
4309
+ margin-top: 2px;
4310
+ overflow: hidden;
4311
+ text-overflow: ellipsis;
4312
+ white-space: nowrap;
4313
+ }
4314
+ .friend-req-body {
4315
+ padding: 14px 18px;
4316
+ font-size: 13px;
4317
+ color: var(--text);
4318
+ line-height: 1.5;
4319
+ }
4320
+ .friend-req-actions {
4321
+ padding: 10px 18px;
4322
+ border-top: 1px solid var(--border);
4323
+ display: flex;
4324
+ gap: 8px;
4325
+ justify-content: flex-end;
4326
+ background: var(--bg-sidebar);
4327
+ border-radius: 0 0 8px 8px;
4328
+ }
4329
+ .friend-req-btn-deny {
4330
+ padding: 6px 14px;
4331
+ background: var(--bg-hover);
4332
+ color: var(--text-secondary);
4333
+ border: 1px solid var(--border);
4334
+ border-radius: 4px;
4335
+ cursor: pointer;
4336
+ font-size: 13px;
4337
+ font-family: inherit;
4338
+ }
4339
+ .friend-req-btn-deny:hover {
4340
+ background: var(--bg-active);
4341
+ color: var(--text);
4342
+ }
4343
+ .friend-req-btn-accept {
4344
+ padding: 6px 14px;
4345
+ background: var(--user-bg);
4346
+ color: var(--user-text);
4347
+ border: none;
4348
+ border-radius: 4px;
4349
+ cursor: pointer;
4350
+ font-size: 13px;
4351
+ font-weight: 600;
4352
+ font-family: inherit;
4353
+ }
4354
+ .friend-req-btn-accept:hover {
4355
+ filter: brightness(1.1);
4356
+ }
4357
+
4358
+ /* ============================================================
4359
+ * 2026-06-10: Toast 入场动画 (simple-toast 用)
4360
+ * ============================================================ */
4361
+ @keyframes toast-in {
4362
+ from {
4363
+ opacity: 0;
4364
+ transform: translateX(20px);
4365
+ }
4366
+ to {
4367
+ opacity: 1;
4368
+ transform: translateX(0);
4369
+ }
4370
+ }
4371
+
4372
+ /* ============================================================
4373
+ * 2026-06-10: P2P peer-group 可折叠 — 复用 #remote-agents-section.collapsed 模式
4374
+ * peer header 加 .peer-caret, 点击切 .remote-peer-group.collapsed
4375
+ * 折叠后隐藏 .remote-peer-channels, caret 旋转 -90deg
4376
+ * ============================================================ */
4377
+ .remote-peer-group .peer-caret {
4378
+ display: inline-block;
4379
+ font-size: 10px;
4380
+ color: var(--text-muted);
4381
+ transition: transform 0.15s ease;
4382
+ user-select: none;
4383
+ width: 12px;
4384
+ text-align: center;
4385
+ }
4386
+ .remote-peer-group.collapsed .peer-caret {
4387
+ transform: rotate(-90deg);
4388
+ }
4389
+ .remote-peer-group.collapsed > .remote-peer-channels {
4390
+ display: none;
4391
+ }
4392
+ .remote-peer-group .remote-peer-header {
4393
+ /* 让 caret 单独成可点区域时不撑破 header */
4394
+ user-select: none;
4395
+ }
4396
+
4397
+ /* ============================================================
4398
+ * 2026-06-11: 分享 channel modal (P2P peer 分享) — 用 friend-req-shell 风格
4399
+ * ============================================================ */
4400
+ .share-modal-shell {
4401
+ width: 520px;
4402
+ max-height: 80vh;
4403
+ }
4404
+ .share-modal-hint {
4405
+ padding: 8px 18px;
4406
+ font-size: 12px;
4407
+ color: var(--text-muted);
4408
+ background: var(--bg-sidebar);
4409
+ border-bottom: 1px solid var(--border);
4410
+ }
4411
+ .share-modal-list {
4412
+ flex: 1;
4413
+ overflow-y: auto;
4414
+ padding: 4px 18px;
4415
+ max-height: 50vh;
4416
+ }
4417
+ .share-modal-empty {
4418
+ color: var(--text-muted);
4419
+ padding: 20px;
4420
+ text-align: center;
4421
+ }
4422
+ .share-modal-row {
4423
+ display: flex;
4424
+ align-items: flex-start;
4425
+ gap: 10px;
4426
+ padding: 8px 4px;
4427
+ cursor: pointer;
4428
+ border-bottom: 1px solid var(--border);
4429
+ font-family: inherit;
4430
+ }
4431
+ .share-modal-row:hover {
4432
+ background: var(--bg-hover);
4433
+ }
4434
+ .share-modal-cb {
4435
+ margin-top: 4px;
4436
+ cursor: pointer;
4437
+ width: 16px;
4438
+ height: 16px;
4439
+ accent-color: var(--accent);
4440
+ }
4441
+ .share-modal-row-info {
4442
+ flex: 1;
4443
+ min-width: 0;
4444
+ }
4445
+ .share-modal-row-name {
4446
+ font-size: 13px;
4447
+ font-weight: 500;
4448
+ color: var(--text);
4449
+ }
4450
+ .share-modal-row-meta {
4451
+ font-size: 10px;
4452
+ color: var(--text-muted);
4453
+ margin-top: 2px;
4454
+ font-family: 'JetBrains Mono', monospace;
4455
+ }
@@ -0,0 +1,9 @@
1
+ {
2
+ "patchId": "clean-001",
3
+ "model": "claude-haiku-4-5",
4
+ "schemaChange": false,
5
+ "verdict": "PASS",
6
+ "concerns": [],
7
+ "suggestions": [],
8
+ "reviewedAt": "2026-06-14T11:03:51.521Z"
9
+ }
@@ -0,0 +1,14 @@
1
+ diff --git a/src/utils/_e2e-clean.ts b/src/utils/_e2e-clean.ts
2
+ new file mode 100644
3
+ index 0000000..314f5a1
4
+ --- /dev/null
5
+ +++ b/src/utils/_e2e-clean.ts
6
+ @@ -0,0 +1,8 @@
7
+ +/**
8
+ + * _e2e-clean.ts — 干净的 LLM 改动示例
9
+ + */
10
+ +export function formatBytes(n: number): string {
11
+ + if (n < 1024) return `${n} B`;
12
+ + if (n < 1024 * 1024) return `${(n / 1024).toFixed(1)} KB`;
13
+ + return `${(n / 1024 / 1024).toFixed(1)} MB`;
14
+ +}
@@ -0,0 +1 @@
1
+ e2e-001
@@ -0,0 +1,12 @@
1
+ {
2
+ "patchId": "e2e-001",
3
+ "model": "claude-haiku-4-5",
4
+ "schemaChange": false,
5
+ "verdict": "FAIL",
6
+ "concerns": [
7
+ "使用了 any",
8
+ "留了 console.log"
9
+ ],
10
+ "suggestions": [],
11
+ "reviewedAt": "2026-06-14T11:03:24.772Z"
12
+ }
@@ -0,0 +1,11 @@
1
+ diff --git a/src/utils/_e2e-real.ts b/src/utils/_e2e-real.ts
2
+ new file mode 100644
3
+ index 0000000..abcaa65
4
+ --- /dev/null
5
+ +++ b/src/utils/_e2e-real.ts
6
+ @@ -0,0 +1,5 @@
7
+ +export function processInput(input: any): any {
8
+ + const result: any = JSON.parse(input);
9
+ + console.log('processing', result);
10
+ + return result;
11
+ +}
@@ -0,0 +1,12 @@
1
+ {
2
+ "patchId": "test-bad",
3
+ "model": "claude-haiku-4-5",
4
+ "schemaChange": false,
5
+ "verdict": "FAIL",
6
+ "concerns": [
7
+ "使用了 any",
8
+ "留了 console.log"
9
+ ],
10
+ "suggestions": [],
11
+ "reviewedAt": "2026-06-14T11:31:26.558Z"
12
+ }
@@ -0,0 +1,11 @@
1
+ diff --git a/src/utils/foo.ts b/src/utils/foo.ts
2
+ new file mode 100644
3
+ index 0000000..abc
4
+ --- /dev/null
5
+ +++ b/src/utils/foo.ts
6
+ @@ -0,0 +1,5 @@
7
+ +export function parseInput(input: string): any {
8
+ + const x: any = JSON.parse(input);
9
+ + console.log('parsed', x);
10
+ + return x;
11
+ +}
@@ -1,131 +0,0 @@
1
- /**
2
- * AdaptiveHeartbeat - 动态心跳策略
3
- *
4
- * 基于活跃度、信息素密度等因子动态调整心跳间隔
5
- */
6
-
7
- import {
8
- HeartbeatDecision,
9
- AdaptiveHeartbeatConfig,
10
- DEFAULT_ADAPTIVE_CONFIG,
11
- } from './types.js';
12
-
13
- export class AdaptiveHeartbeat {
14
- private config: AdaptiveHeartbeatConfig;
15
- private lastActivityTime: number = Date.now();
16
- private activityHistory: number[] = [];
17
- private recentDiscoveries: number = 0;
18
- private pheromoneDensity: number = 0;
19
- private discoveryBoost: number = 0;
20
- private activityTimer: ReturnType<typeof setInterval> | null = null;
21
-
22
- constructor(config?: Partial<AdaptiveHeartbeatConfig>) {
23
- this.config = { ...DEFAULT_ADAPTIVE_CONFIG, ...config };
24
- this.startActivityTracking();
25
- }
26
-
27
- /**
28
- * 获取下一次心跳的决策
29
- */
30
- decide(): HeartbeatDecision {
31
- const now = Date.now();
32
- const timeSinceLastActivity = now - this.lastActivityTime;
33
-
34
- const activityRate = this.calculateActivityRate();
35
- const pheromoneFactor = this.pheromoneDensity;
36
- const discoveryFactor = this.calculateDiscoveryFactor();
37
-
38
- const combinedFactor =
39
- activityRate * 0.2 +
40
- pheromoneFactor * this.config.pheromoneBoostFactor +
41
- discoveryFactor * this.config.discoveryBoostFactor;
42
-
43
- const interval = Math.max(
44
- this.config.minInterval,
45
- Math.min(
46
- this.config.maxInterval,
47
- this.config.baseInterval * (1 - combinedFactor * 0.7)
48
- )
49
- );
50
-
51
- let priority: HeartbeatDecision['priorityLevel'] = 'normal';
52
- if (discoveryFactor > 0.5 || this.discoveryBoost > 0.6) {
53
- priority = 'high';
54
- } else if (this.discoveryBoost > 0.8) {
55
- priority = 'urgent';
56
- } else if (activityRate < this.config.lowActivityThreshold) {
57
- priority = 'low';
58
- }
59
-
60
- return {
61
- interval: Math.round(interval),
62
- shouldExplore: discoveryFactor > 0.3 || pheromoneFactor > 0.5,
63
- shouldBroadcast: priority !== 'low' || timeSinceLastActivity > this.config.baseInterval,
64
- priorityLevel: priority,
65
- };
66
- }
67
-
68
- /**
69
- * 记录活跃事件
70
- */
71
- recordActivity(type: 'message' | 'discovery' | 'channel'): void {
72
- const now = Date.now();
73
- this.lastActivityTime = now;
74
- this.activityHistory.push(now);
75
-
76
- if (type === 'discovery') {
77
- this.recentDiscoveries++;
78
- this.discoveryBoost = Math.min(1, this.discoveryBoost + 0.2);
79
- }
80
-
81
- this.discoveryBoost = Math.max(0, this.discoveryBoost - 0.05);
82
- }
83
-
84
- /**
85
- * 设置信息素密度
86
- */
87
- setPheromoneDensity(density: number): void {
88
- this.pheromoneDensity = Math.max(0, Math.min(1, density));
89
- }
90
-
91
- /**
92
- * 获取当前配置
93
- */
94
- getConfig(): AdaptiveHeartbeatConfig {
95
- return { ...this.config };
96
- }
97
-
98
- /**
99
- * 更新配置
100
- */
101
- updateConfig(updates: Partial<AdaptiveHeartbeatConfig>): void {
102
- this.config = { ...this.config, ...updates };
103
- }
104
-
105
- private calculateActivityRate(): number {
106
- const now = Date.now();
107
- const recentActivity = this.activityHistory.filter(
108
- (t) => now - t < 60000
109
- ).length;
110
- return recentActivity / 60;
111
- }
112
-
113
- private calculateDiscoveryFactor(): number {
114
- return Math.min(1, this.recentDiscoveries / 5);
115
- }
116
-
117
- private startActivityTracking(): void {
118
- this.activityTimer = setInterval(() => {
119
- const cutoff = Date.now() - 5 * 60 * 1000;
120
- this.activityHistory = this.activityHistory.filter((t) => t > cutoff);
121
- this.recentDiscoveries = Math.max(0, this.recentDiscoveries - 1);
122
- this.discoveryBoost = Math.max(0, this.discoveryBoost - 0.1);
123
- }, 60000);
124
- }
125
-
126
- shutdown(): void {
127
- if (this.activityTimer) {
128
- clearInterval(this.activityTimer);
129
- }
130
- }
131
- }