@johpaz/hive-sdk 0.1.6 โ†’ 0.3.0

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 (238) hide show
  1. package/CHANGELOG.md +441 -0
  2. package/README.md +21 -3
  3. package/package.json +27 -5
  4. package/packages/core/src/agent/acceptance-checks.ts +9 -9
  5. package/packages/core/src/agent/agent-catalog.ts +82 -25
  6. package/packages/core/src/agent/agent-loop.ts +115 -26
  7. package/packages/core/src/agent/capability-search.ts +2 -2
  8. package/packages/core/src/agent/catalog-selector.ts +4 -4
  9. package/packages/core/src/agent/compaction.ts +30 -10
  10. package/packages/core/src/agent/context-compiler.ts +63 -36
  11. package/packages/core/src/agent/conversation-store.ts +167 -9
  12. package/packages/core/src/agent/curator.ts +16 -7
  13. package/packages/core/src/agent/delegation-runtime.ts +5 -5
  14. package/packages/core/src/agent/goal-runner.ts +9 -9
  15. package/packages/core/src/agent/index.ts +1 -0
  16. package/packages/core/src/agent/llm-client.ts +98 -37
  17. package/packages/core/src/agent/llm-providers/anthropic.ts +4 -4
  18. package/packages/core/src/agent/llm-providers/deepseek.ts +1 -1
  19. package/packages/core/src/agent/llm-providers/gemini.ts +4 -4
  20. package/packages/core/src/agent/llm-providers/groq.ts +1 -1
  21. package/packages/core/src/agent/llm-providers/hiveagents.ts +3 -3
  22. package/packages/core/src/agent/llm-providers/interface.ts +2 -2
  23. package/packages/core/src/agent/llm-providers/kimi.ts +1 -1
  24. package/packages/core/src/agent/llm-providers/minimax.ts +1 -1
  25. package/packages/core/src/agent/llm-providers/mistral.ts +1 -1
  26. package/packages/core/src/agent/llm-providers/modelscope.ts +1 -1
  27. package/packages/core/src/agent/llm-providers/nvidia.ts +40 -1
  28. package/packages/core/src/agent/llm-providers/ollama.ts +4 -4
  29. package/packages/core/src/agent/llm-providers/openai-compat-base.ts +47 -7
  30. package/packages/core/src/agent/llm-providers/openai.ts +1 -1
  31. package/packages/core/src/agent/llm-providers/opencode-go.ts +1 -1
  32. package/packages/core/src/agent/llm-providers/openrouter.ts +1 -1
  33. package/packages/core/src/agent/llm-providers/qwen.ts +1 -1
  34. package/packages/core/src/agent/llm-providers/z-ai.ts +1 -1
  35. package/packages/core/src/agent/mcp-result-normalizer.ts +192 -0
  36. package/packages/core/src/agent/playbook-selector.ts +22 -7
  37. package/packages/core/src/agent/prompt-builder.ts +5 -5
  38. package/packages/core/src/agent/proof-packet.ts +5 -5
  39. package/packages/core/src/agent/providers/index.ts +39 -4
  40. package/packages/core/src/agent/realtime-providers/gemini-live.ts +238 -0
  41. package/packages/core/src/agent/realtime-providers/index.ts +29 -0
  42. package/packages/core/src/agent/realtime-providers/interface.ts +108 -0
  43. package/packages/core/src/agent/reflector.ts +38 -15
  44. package/packages/core/src/agent/run-store.ts +8 -8
  45. package/packages/core/src/agent/service.ts +10 -10
  46. package/packages/core/src/agent/skill-selector.ts +6 -6
  47. package/packages/core/src/agent/thread-id.ts +71 -0
  48. package/packages/core/src/agent/thread-store.ts +293 -0
  49. package/packages/core/src/agent/tool-selector.ts +9 -5
  50. package/packages/core/src/agent/tracer.ts +5 -5
  51. package/packages/core/src/api/createAgent.ts +67 -2
  52. package/packages/core/src/artifacts/index.ts +15 -0
  53. package/packages/core/src/artifacts/store.ts +161 -5
  54. package/packages/core/src/canvas/emitter.ts +2 -2
  55. package/packages/core/src/canvas/index.ts +9 -0
  56. package/packages/core/src/channels/telegram.ts +1 -1
  57. package/packages/core/src/channels/webchat.ts +1 -1
  58. package/packages/core/src/config/loader.ts +14 -5
  59. package/packages/core/src/ethics/EthicsGuard.ts +7 -1
  60. package/packages/core/src/events/agent-bus.ts +3 -3
  61. package/packages/core/src/events/channel-narration.ts +3 -3
  62. package/packages/core/src/events/event-bus.ts +1 -1
  63. package/packages/core/src/events/index.ts +18 -0
  64. package/packages/core/src/events/narration.ts +3 -3
  65. package/packages/core/src/events/tool-narration.ts +4 -0
  66. package/packages/core/src/gateway/channel-notify.ts +103 -6
  67. package/packages/core/src/gateway/delegation-groups.ts +4 -4
  68. package/packages/core/src/gateway/durable-queue.ts +18 -6
  69. package/packages/core/src/gateway/index.ts +3 -0
  70. package/packages/core/src/gateway/job-store.ts +11 -5
  71. package/packages/core/src/gateway/notification-inbox.ts +2 -2
  72. package/packages/core/src/gateway/server.ts +2 -2
  73. package/packages/core/src/harness/executors.ts +493 -0
  74. package/packages/core/src/harness/index.ts +12 -2
  75. package/packages/core/src/hooks/index.ts +203 -0
  76. package/packages/core/src/images/index.ts +161 -0
  77. package/packages/core/src/index.ts +1 -0
  78. package/packages/core/src/mcp/MCPClient.ts +3 -3
  79. package/packages/core/src/mcp/hot-reload.ts +5 -5
  80. package/packages/core/src/mcp/tool-sync.ts +5 -5
  81. package/packages/core/src/mcp/transports/index.ts +2 -2
  82. package/packages/core/src/mcp/transports/sse.ts +1 -1
  83. package/packages/core/src/models/index.ts +36 -0
  84. package/packages/core/src/multimodal/index.ts +2 -2
  85. package/packages/core/src/multimodal/vision-service.ts +51 -19
  86. package/packages/core/src/plugins/loader.ts +4 -1
  87. package/packages/core/src/resilience/circuit-breaker.ts +16 -5
  88. package/packages/core/src/resilience/index.ts +13 -0
  89. package/packages/core/src/resilience/retry.ts +1 -1
  90. package/packages/core/src/scheduler/CronScheduler.ts +54 -27
  91. package/packages/core/src/scheduler/cron/expression.ts +165 -0
  92. package/packages/core/src/scheduler/cron/index.ts +10 -0
  93. package/packages/core/src/scheduler/cron/job.ts +339 -0
  94. package/packages/core/src/scheduler/cron/next-run.ts +121 -0
  95. package/packages/core/src/scheduler/cron/zoned-time.ts +138 -0
  96. package/packages/core/src/scheduler/index.ts +21 -3
  97. package/packages/core/src/scheduler/integration.ts +25 -14
  98. package/packages/core/src/scheduler/types.ts +3 -18
  99. package/packages/core/src/services/agents.ts +268 -0
  100. package/packages/core/src/services/cron.ts +257 -0
  101. package/packages/core/src/services/endpoints.ts +289 -0
  102. package/packages/core/src/services/ethics.ts +107 -0
  103. package/packages/core/src/services/images.ts +212 -0
  104. package/packages/core/src/services/index.ts +112 -0
  105. package/packages/core/src/services/mcp.ts +201 -0
  106. package/packages/core/src/services/memory.ts +133 -0
  107. package/packages/core/src/services/models.ts +179 -0
  108. package/packages/core/src/services/providers.ts +152 -0
  109. package/packages/core/src/services/setup.ts +222 -0
  110. package/packages/core/src/services/skills.ts +241 -0
  111. package/packages/core/src/services/swarms.ts +307 -0
  112. package/packages/core/src/services/tools.ts +106 -0
  113. package/packages/core/src/sessions/index.ts +268 -0
  114. package/packages/core/src/sessions/resolve.ts +108 -0
  115. package/packages/core/src/skills/SkillLoader.ts +8 -1
  116. package/packages/core/src/skills/bundled/artifacts/artifact_reader/SKILL.md +105 -0
  117. package/packages/core/src/skills/bundled/cron_manager/SKILL.md +21 -11
  118. package/packages/core/src/skills/bundled/images/image_editor/SKILL.md +120 -0
  119. package/packages/core/src/skills/bundled/web/browser_automate/SKILL.md +12 -3
  120. package/packages/core/src/skills/bundled/web/browser_scrape/SKILL.md +22 -7
  121. package/packages/core/src/skills/bundled-data.generated.ts +110 -12
  122. package/packages/core/src/storage/bootstrap.ts +107 -12
  123. package/packages/core/src/storage/causal-events.ts +1 -1
  124. package/packages/core/src/storage/collections.ts +138 -2
  125. package/packages/core/src/storage/crypto.ts +35 -4
  126. package/packages/core/src/storage/hive.ts +1 -1
  127. package/packages/core/src/storage/hivedb.ts +10 -1
  128. package/packages/core/src/storage/index.ts +2 -1
  129. package/packages/core/src/storage/onboarding.ts +61 -45
  130. package/packages/core/src/storage/reconcile.ts +11 -6
  131. package/packages/core/src/storage/seed.ts +191 -23
  132. package/packages/core/src/storage/usage.ts +3 -3
  133. package/packages/core/src/swarm/AgentExecutor.ts +2 -2
  134. package/packages/core/src/swarm/Coordinator.ts +8 -8
  135. package/packages/core/src/swarm/EventBridge.ts +2 -2
  136. package/packages/core/src/swarm/RoleSwarm.ts +234 -0
  137. package/packages/core/src/swarm/TaskGraph.ts +2 -2
  138. package/packages/core/src/swarm/index.ts +7 -0
  139. package/packages/core/src/swarm/presets/HiveLearnPreset.ts +2 -2
  140. package/packages/core/src/swarm/presets/ResearchPreset.ts +2 -2
  141. package/packages/core/src/swarm/strategies/ParallelStrategy.ts +1 -1
  142. package/packages/core/src/swarm/strategies/PriorityStrategy.ts +3 -3
  143. package/packages/core/src/swarm/types.ts +3 -18
  144. package/packages/core/src/tool-runtime/embedded-worker.generated.ts +21 -0
  145. package/packages/core/src/tool-runtime/index.ts +129 -14
  146. package/packages/core/src/tools/ToolExecutor.ts +7 -3
  147. package/packages/core/src/tools/agents/index.ts +18 -60
  148. package/packages/core/src/tools/cli/index.ts +55 -0
  149. package/packages/core/src/tools/core/index.ts +52 -4
  150. package/packages/core/src/tools/cron/index.ts +8 -8
  151. package/packages/core/src/tools/images/index.ts +130 -0
  152. package/packages/core/src/tools/index.ts +14 -1
  153. package/packages/core/src/tools/office/office-escribir-xlsx.ts +2 -1
  154. package/packages/core/src/tools/office/office-leer-xlsx.ts +2 -1
  155. package/packages/core/src/tools/office/xlsx-loader.ts +19 -0
  156. package/packages/core/src/tools/web/artifact-inspect.ts +2 -2
  157. package/packages/core/src/tools/web/artifact-read.ts +162 -0
  158. package/packages/core/src/tools/web/browser-backend.ts +141 -44
  159. package/packages/core/src/tools/web/browser-click.ts +2 -2
  160. package/packages/core/src/tools/web/browser-extract.ts +2 -2
  161. package/packages/core/src/tools/web/browser-navigate.ts +2 -2
  162. package/packages/core/src/tools/web/browser-screenshot.ts +12 -5
  163. package/packages/core/src/tools/web/browser-script.ts +2 -2
  164. package/packages/core/src/tools/web/browser-service.ts +63 -384
  165. package/packages/core/src/tools/web/browser-session.ts +125 -0
  166. package/packages/core/src/tools/web/browser-type.ts +2 -2
  167. package/packages/core/src/tools/web/browser-wait.ts +2 -2
  168. package/packages/core/src/tools/web/computer-use.ts +553 -0
  169. package/packages/core/src/tools/web/index.ts +8 -1
  170. package/packages/core/src/tools/web/webview-backend.ts +460 -21
  171. package/packages/core/src/utils/index.ts +1 -0
  172. package/packages/core/src/utils/logger.ts +12 -4
  173. package/packages/core/src/utils/redact-binary.ts +17 -0
  174. package/packages/core/src/utils/toon.ts +1 -1
  175. package/packages/core/src/voice/index.ts +6 -6
  176. package/bun.lock +0 -859
  177. package/bunfig.toml +0 -9
  178. package/docs/API-AGENTS.md +0 -367
  179. package/docs/API-CONTEXT-COMPILER.md +0 -249
  180. package/docs/API-DAG-SCHEDULER.md +0 -273
  181. package/docs/API-TOOLS-SKILLS-CHANNELS.md +0 -446
  182. package/docs/API-WORKERS-EVENTS.md +0 -299
  183. package/docs/HIVE-HARNESS.md +0 -113
  184. package/docs/INDEX.md +0 -190
  185. package/docs/TEMPLATE-HIVE-APP.md +0 -360
  186. package/packages/cli/package.json +0 -17
  187. package/packages/cli/src/commands/create-app.test.ts +0 -180
  188. package/packages/core/package.json +0 -70
  189. package/packages/core/src/api/createAgent.test.ts +0 -160
  190. package/packages/core/src/canvas/canvas.test.ts +0 -36
  191. package/packages/core/src/channels/channels.test.ts +0 -18
  192. package/packages/core/src/ethics/EthicsGuard.test.ts +0 -108
  193. package/packages/core/src/gateway/gateway.test.ts +0 -38
  194. package/packages/core/src/memory/Scratchpad.test.ts +0 -68
  195. package/packages/core/src/scheduler/scheduler.test.ts +0 -15
  196. package/packages/core/src/skills/skills.test.ts +0 -62
  197. package/packages/core/src/swarm/swarm.test.ts +0 -24
  198. package/packages/core/src/tool-runtime/tool-runtime.test.ts +0 -99
  199. package/packages/core/src/tools/ToolRegistry.test.ts +0 -98
  200. package/packages/core/src/tools/api/api-request.test.ts +0 -164
  201. package/packages/core/src/tools/web/browser-service.test.ts +0 -83
  202. package/packages/core/src/workers/workers.test.ts +0 -41
  203. package/scripts/bump-version.ts +0 -248
  204. package/scripts/generate-skill-bundle.ts +0 -108
  205. package/test/acceptance-checks.test.ts +0 -403
  206. package/test/agent-loop-terminal-synthesis.test.ts +0 -32
  207. package/test/browser-backend.test.ts +0 -308
  208. package/test/catalog-agents-stay-enabled.test.ts +0 -117
  209. package/test/causal-events.test.ts +0 -117
  210. package/test/compaction.test.ts +0 -105
  211. package/test/context-compiler.test.ts +0 -269
  212. package/test/curator.test.ts +0 -130
  213. package/test/durable-queue.test.ts +0 -114
  214. package/test/harness-barrel.test.ts +0 -64
  215. package/test/hive-helpers.test.ts +0 -130
  216. package/test/hivedb-search.test.ts +0 -189
  217. package/test/internal-turns.test.ts +0 -166
  218. package/test/job-idempotency.test.ts +0 -68
  219. package/test/job-retry-backoff.test.ts +0 -184
  220. package/test/job-store.test.ts +0 -381
  221. package/test/llm-retry.test.ts +0 -97
  222. package/test/memory-perf.test.ts +0 -774
  223. package/test/minimal-loadout.test.ts +0 -78
  224. package/test/model-catalog.test.ts +0 -105
  225. package/test/preload.ts +0 -12
  226. package/test/reflector.test.ts +0 -320
  227. package/test/retention-cap.test.ts +0 -91
  228. package/test/retired-capabilities-pruned.test.ts +0 -192
  229. package/test/run-store.test.ts +0 -355
  230. package/test/scratchpad.test.ts +0 -74
  231. package/test/secrets-durability.test.ts +0 -119
  232. package/test/seed-model-reseed.test.ts +0 -155
  233. package/test/setup-agent-seed.test.ts +0 -264
  234. package/test/tool-inventory.test.ts +0 -65
  235. package/test/tool-runtime.test.ts +0 -258
  236. package/test/tool-selector-runtime-tools.test.ts +0 -117
  237. package/test/toon.test.ts +0 -429
  238. package/tsconfig.json +0 -42
@@ -1,774 +0,0 @@
1
- import {
2
- describe,
3
- it,
4
- expect,
5
- beforeEach,
6
- afterEach,
7
- beforeAll,
8
- } from "bun:test";
9
- import { Mutex, Semaphore } from "async-mutex";
10
-
11
- interface MemorySnapshot {
12
- heapUsed: number;
13
- heapTotal: number;
14
- external: number;
15
- rss: number;
16
- timestamp: number;
17
- }
18
-
19
- interface ThresholdConfig {
20
- memoryLeakThresholdPercent: number;
21
- queryTimeThresholdMs: number;
22
- concurrencyDegradationThreshold: number;
23
- connectionPoolErrorThresholdPercent: number;
24
- maxActiveHandles: number;
25
- }
26
-
27
- const DEFAULT_THRESHOLDS: ThresholdConfig = {
28
- memoryLeakThresholdPercent: 20,
29
- queryTimeThresholdMs: 50,
30
- concurrencyDegradationThreshold: 3,
31
- connectionPoolErrorThresholdPercent: 5,
32
- maxActiveHandles: 50,
33
- };
34
-
35
- class MemoryMonitor {
36
- private snapshots: MemorySnapshot[] = [];
37
- private thresholds: ThresholdConfig;
38
-
39
- constructor(thresholds: Partial<ThresholdConfig> = {}) {
40
- this.thresholds = { ...DEFAULT_THRESHOLDS, ...thresholds };
41
- }
42
-
43
- captureSnapshot(): MemorySnapshot {
44
- const mem = process.memoryUsage();
45
- const snapshot: MemorySnapshot = {
46
- heapUsed: mem.heapUsed,
47
- heapTotal: mem.heapTotal,
48
- external: mem.external,
49
- rss: mem.rss,
50
- timestamp: Date.now(),
51
- };
52
- this.snapshots.push(snapshot);
53
- return snapshot;
54
- }
55
-
56
- getSnapshots(): MemorySnapshot[] {
57
- return this.snapshots;
58
- }
59
-
60
- calculateGrowthPercent(): number {
61
- if (this.snapshots.length < 2) return 0;
62
- const first = this.snapshots[0]!;
63
- const last = this.snapshots[this.snapshots.length - 1]!;
64
- return ((last.heapUsed - first.heapUsed) / first.heapUsed) * 100;
65
- }
66
-
67
- hasMemoryLeak(): boolean {
68
- return this.calculateGrowthPercent() > this.thresholds.memoryLeakThresholdPercent;
69
- }
70
-
71
- getMemoryInfo(): {
72
- initial: MemorySnapshot | null;
73
- final: MemorySnapshot | null;
74
- growthPercent: number;
75
- } {
76
- return {
77
- initial: this.snapshots[0] ?? null,
78
- final: this.snapshots[this.snapshots.length - 1] ?? null,
79
- growthPercent: this.calculateGrowthPercent(),
80
- };
81
- }
82
-
83
- reset(): void {
84
- this.snapshots = [];
85
- }
86
-
87
- setThresholds(thresholds: Partial<ThresholdConfig>): void {
88
- this.thresholds = { ...this.thresholds, ...thresholds };
89
- }
90
- }
91
-
92
- function getActiveHandleCount(): number {
93
- const Bun = globalThis.Bun as {
94
- numberOfActiveHandles?: () => number;
95
- } | null;
96
- if (Bun && typeof Bun.numberOfActiveHandles === "function") {
97
- return Bun.numberOfActiveHandles();
98
- }
99
- return 0;
100
- }
101
-
102
- function getActiveRequestCount(): number {
103
- const Bun = globalThis.Bun as {
104
- numberOfActiveRequests?: () => number;
105
- } | null;
106
- if (Bun && typeof Bun.numberOfActiveRequests === "function") {
107
- return Bun.numberOfActiveRequests();
108
- }
109
- return 0;
110
- }
111
-
112
- function getPendingPromiseCount(): number {
113
- return (globalThis as unknown as { Promise: { [key: string]: unknown } }).Promise
114
- ? 0
115
- : 0;
116
- }
117
-
118
- async function sleep(ms: number): Promise<void> {
119
- await new Promise((resolve) => setTimeout(resolve, ms));
120
- }
121
-
122
- describe("๐Ÿงช Memory & Performance Test Suite", () => {
123
- describe("๐Ÿ’พ Memory Leaks Detection", () => {
124
- let memoryMonitor: MemoryMonitor;
125
-
126
- beforeEach(() => {
127
- memoryMonitor = new MemoryMonitor({
128
- memoryLeakThresholdPercent: 20,
129
- });
130
- });
131
-
132
- it("should not leak memory when creating 1000+ checkpoints", async () => {
133
- console.log("\n๐Ÿ“Œ Testing memory leak with checkpoint creation...");
134
-
135
- const checkpoints: unknown[] = [];
136
- const memorySnapshots: number[] = [];
137
-
138
- for (let i = 0; i < 1000; i++) {
139
- if (i % 50 === 0) {
140
- memoryMonitor.captureSnapshot();
141
- const snap = memoryMonitor.captureSnapshot();
142
- memorySnapshots.push(snap.heapUsed);
143
- console.log(
144
- ` ๐Ÿ“Š Iteration ${i}: heapUsed=${(snap.heapUsed / 1024 / 1024).toFixed(2)}MB`
145
- );
146
- }
147
-
148
- checkpoints.push({
149
- id: `checkpoint-${i}`,
150
- data: { key: `value-${i}`, timestamp: Date.now() },
151
- });
152
-
153
- if (i % 200 === 0) {
154
- await sleep(10);
155
- }
156
- }
157
-
158
- memoryMonitor.captureSnapshot();
159
- const memoryInfo = memoryMonitor.getMemoryInfo();
160
- const growthPercent = memoryInfo.growthPercent;
161
-
162
- console.log(` ๐Ÿ“ˆ Memory growth: ${growthPercent.toFixed(2)}%`);
163
- console.log(` ๐ŸŸข Initial heap: ${((memoryInfo.initial?.heapUsed ?? 0) / 1024 / 1024).toFixed(2)}MB`);
164
- console.log(` ๐Ÿ”ด Final heap: ${((memoryInfo.final?.heapUsed ?? 0) / 1024 / 1024).toFixed(2)}MB`);
165
-
166
- expect(growthPercent).toBeLessThan(200);
167
- }, 30000);
168
-
169
- it("should not leak memory when processing messages", async () => {
170
- console.log("\n๐Ÿ“Œ Testing memory leak with message processing...");
171
-
172
- const messageQueue: unknown[] = [];
173
-
174
- for (let i = 0; i < 1500; i++) {
175
- if (i % 50 === 0) {
176
- memoryMonitor.captureSnapshot();
177
- }
178
-
179
- const message = {
180
- id: i,
181
- type: ["event", "command", "query", "response"][i % 4],
182
- payload: { data: "x".repeat(100) },
183
- timestamp: Date.now(),
184
- };
185
- messageQueue.push(message);
186
-
187
- if (i % 500 === 0 && messageQueue.length > 100) {
188
- messageQueue.splice(0, 100);
189
- }
190
- }
191
-
192
- const growthPercent = memoryMonitor.getMemoryInfo().growthPercent;
193
- console.log(` ๐Ÿ“ˆ Memory growth after processing: ${growthPercent.toFixed(2)}%`);
194
-
195
- expect(growthPercent).toBeLessThan(20);
196
- }, 30000);
197
-
198
- it("should detect memory leak with GC when available", async () => {
199
- console.log("\n๐Ÿ“Œ Testing with forced GC (if available)...");
200
-
201
- if (typeof globalThis.gc === "function") {
202
- globalThis.gc();
203
- memoryMonitor.captureSnapshot();
204
-
205
- for (let i = 0; i < 500; i++) {
206
- const obj = { data: new Array(1000).fill(i) };
207
- if (i % 100 === 0) {
208
- memoryMonitor.captureSnapshot();
209
- }
210
- }
211
-
212
- globalThis.gc();
213
- await sleep(100);
214
- memoryMonitor.captureSnapshot();
215
-
216
- const growthPercent = memoryMonitor.getMemoryInfo().growthPercent;
217
- console.log(` ๐Ÿ“ˆ Memory growth after GC: ${growthPercent.toFixed(2)}%`);
218
- } else {
219
- console.log(" โš ๏ธ GC not exposed, skipping detailed test");
220
- }
221
-
222
- expect(true).toBe(true);
223
- }, 30000);
224
- });
225
-
226
- describe("๐Ÿ‘ป Zombie/Phantom Process Detection", () => {
227
- it("should not leave active handles after operations", async () => {
228
- console.log("\n๐Ÿ“Œ Testing for zombie handles...");
229
-
230
- const initialHandles = getActiveHandleCount();
231
- console.log(` ๐Ÿ“Š Initial handles: ${initialHandles}`);
232
-
233
- const timers: Timer[] = [];
234
- for (let i = 0; i < 10; i++) {
235
- const timer = setTimeout(() => {}, 1000 + i);
236
- timers.push(timer);
237
- }
238
-
239
- const handlesDuring = getActiveHandleCount();
240
- console.log(` ๐Ÿ“Š Handles during operation: ${handlesDuring}`);
241
-
242
- timers.forEach((t) => clearTimeout(t));
243
- await sleep(1500);
244
-
245
- const finalHandles = getActiveHandleCount();
246
- console.log(` ๐Ÿ“Š Final handles: ${finalHandles}`);
247
-
248
- expect(finalHandles - initialHandles).toBeLessThan(5);
249
- });
250
-
251
- it("should not leave pending promises unresolved", async () => {
252
- console.log("\n๐Ÿ“Œ Testing for unresolved promises...");
253
-
254
- let resolvedCount = 0;
255
- const totalPromises = 100;
256
-
257
- const promises = Array.from({ length: totalPromises }, async () => {
258
- await new Promise((resolve) => setTimeout(resolve, Math.random() * 50));
259
- resolvedCount++;
260
- });
261
-
262
- console.log(` ๐Ÿ“Š Promises created: ${totalPromises}`);
263
-
264
- await Promise.all(promises);
265
- await sleep(100);
266
-
267
- console.log(` โœ… Promises resolved: ${resolvedCount}/${totalPromises}`);
268
-
269
- expect(resolvedCount).toBe(totalPromises);
270
- });
271
-
272
- it("should cleanup callbacks after session operations", async () => {
273
- console.log("\n๐Ÿ“Œ Testing callback cleanup...");
274
-
275
- const callbacks: Array<() => void> = [];
276
- const maxCallbacks = 50;
277
-
278
- for (let i = 0; i < maxCallbacks; i++) {
279
- const callback = () => {
280
- console.log(`Callback ${i} called`);
281
- };
282
- callbacks.push(callback);
283
- }
284
-
285
- const handlesBefore = getActiveHandleCount();
286
-
287
- callbacks.length = 0;
288
-
289
- await sleep(100);
290
-
291
- const handlesAfter = getActiveHandleCount();
292
- console.log(` ๐Ÿ“Š Handles before: ${handlesBefore}, after: ${handlesAfter}`);
293
-
294
- expect(Math.abs(handlesAfter - handlesBefore)).toBeLessThan(10);
295
- });
296
- });
297
-
298
- describe("๐Ÿญ Bottleneck Detection", () => {
299
- const mockDatabaseQuery = async (queryId: number): Promise<number> => {
300
- const start = Date.now();
301
- await new Promise((resolve) => setTimeout(resolve, Math.random() * 30 + 10));
302
- return Date.now() - start;
303
- };
304
-
305
- it("should complete database queries under 50ms threshold", async () => {
306
- console.log("\n๐Ÿ“Œ Testing query time thresholds...");
307
-
308
- const queryTimes: number[] = [];
309
-
310
- for (let i = 0; i < 100; i++) {
311
- const time = await mockDatabaseQuery(i);
312
- queryTimes.push(time);
313
-
314
- if (i % 20 === 0) {
315
- console.log(` โฑ๏ธ Query ${i}: ${time.toFixed(2)}ms`);
316
- }
317
- }
318
-
319
- const avgTime = queryTimes.reduce((a, b) => a + b, 0) / queryTimes.length;
320
- const maxTime = Math.max(...queryTimes);
321
- const slowQueries = queryTimes.filter((t) => t > 50).length;
322
-
323
- console.log(` ๐Ÿ“Š Average query time: ${avgTime.toFixed(2)}ms`);
324
- console.log(` ๐Ÿ“Š Max query time: ${maxTime.toFixed(2)}ms`);
325
- console.log(` โš ๏ธ Slow queries (>50ms): ${slowQueries}`);
326
-
327
- expect(avgTime).toBeLessThan(50);
328
- expect(slowQueries / queryTimes.length).toBeLessThan(0.1);
329
- });
330
-
331
- it("should scale linearly with increasing concurrency", async () => {
332
- console.log("\n๐Ÿ“Œ Testing scalability with concurrency levels...");
333
-
334
- const concurrencyLevels = [1, 10, 50, 100];
335
- const results: { concurrency: number; avgTime: number; p95Time: number }[] = [];
336
-
337
- for (const concurrency of concurrencyLevels) {
338
- const times: number[] = [];
339
- const batchSize = concurrency * 5;
340
-
341
- const batchStart = Date.now();
342
-
343
- const promises = Array.from({ length: batchSize }, async (_, i) => {
344
- const start = Date.now();
345
- await mockDatabaseQuery(i);
346
- const elapsed = Date.now() - start;
347
- times.push(elapsed);
348
- return elapsed;
349
- });
350
-
351
- await Promise.all(promises);
352
-
353
- const totalTime = Date.now() - batchStart;
354
- times.sort((a, b) => a - b);
355
- const p95Index = Math.floor(times.length * 0.95);
356
- const avgTime = times.reduce((a, b) => a + b, 0) / times.length;
357
-
358
- results.push({
359
- concurrency,
360
- avgTime,
361
- p95Time: times[p95Index] ?? 0,
362
- });
363
-
364
- console.log(
365
- ` ๐Ÿ“Š Concurrency ${concurrency}: avg=${avgTime.toFixed(2)}ms, p95=${times[p95Index]?.toFixed(2) ?? 0}ms, total=${totalTime}ms`
366
- );
367
- }
368
-
369
- const baseline = results[0]!.avgTime;
370
- const degradationFactors = results.map((r) => r.avgTime / baseline);
371
-
372
- console.log(` ๐Ÿ“ˆ Degradation factors: ${degradationFactors.map((d) => d.toFixed(2)).join(", ")}`);
373
-
374
- const maxDegradation = Math.max(...degradationFactors);
375
- console.log(` โš ๏ธ Max degradation: ${maxDegradation.toFixed(2)}x`);
376
-
377
- expect(maxDegradation).toBeLessThan(3);
378
- });
379
-
380
- it("should maintain performance under sustained load", async () => {
381
- console.log("\n๐Ÿ“Œ Testing sustained load performance...");
382
-
383
- const windows = 5;
384
- const windowSize = 20;
385
- const windowAverages: number[] = [];
386
-
387
- for (let w = 0; w < windows; w++) {
388
- const times: number[] = [];
389
-
390
- for (let i = 0; i < windowSize; i++) {
391
- const time = await mockDatabaseQuery(w * windowSize + i);
392
- times.push(time);
393
- }
394
-
395
- const avg = times.reduce((a, b) => a + b, 0) / times.length;
396
- windowAverages.push(avg);
397
- console.log(` ๐Ÿ“Š Window ${w + 1}: avg=${avg.toFixed(2)}ms`);
398
- }
399
-
400
- const firstHalfAvg =
401
- windowAverages.slice(0, Math.floor(windows / 2)).reduce((a, b) => a + b, 0) /
402
- Math.floor(windows / 2);
403
- const secondHalfAvg =
404
- windowAverages.slice(Math.floor(windows / 2)).reduce((a, b) => a + b, 0) /
405
- (windows - Math.floor(windows / 2));
406
-
407
- const degradation = secondHalfAvg / firstHalfAvg;
408
- console.log(` ๐Ÿ“ˆ First half avg: ${firstHalfAvg.toFixed(2)}ms`);
409
- console.log(` ๐Ÿ“ˆ Second half avg: ${secondHalfAvg.toFixed(2)}ms`);
410
- console.log(` ๐Ÿ“ˆ Degradation: ${degradation.toFixed(2)}x`);
411
-
412
- expect(degradation).toBeLessThan(2);
413
- }, 15000);
414
- });
415
-
416
- describe("๐Ÿ”Œ Connection Pool Stress", () => {
417
- interface MockConnection {
418
- id: number;
419
- inUse: boolean;
420
- acquiredAt?: number;
421
- }
422
-
423
- const createConnectionPool = (poolSize: number): MockConnection[] => {
424
- return Array.from({ length: poolSize }, (_, i) => ({
425
- id: i,
426
- inUse: false,
427
- }));
428
- };
429
-
430
- const acquireConnection = async (
431
- pool: MockConnection[],
432
- timeout = 5000
433
- ): Promise<MockConnection | null> => {
434
- const start = Date.now();
435
-
436
- while (Date.now() - start < timeout) {
437
- const available = pool.find((c) => !c.inUse);
438
- if (available) {
439
- available.inUse = true;
440
- available.acquiredAt = Date.now();
441
- return available;
442
- }
443
- await sleep(10);
444
- }
445
-
446
- return null;
447
- };
448
-
449
- const releaseConnection = (pool: MockConnection[], conn: MockConnection): void => {
450
- conn.inUse = false;
451
- conn.acquiredAt = undefined;
452
- };
453
-
454
- it("should handle 200+ simultaneous connections with <5% error rate", async () => {
455
- console.log("\n๐Ÿ“Œ Testing connection pool with burst of 200+ connections...");
456
-
457
- const poolSize = 50;
458
- const pool = createConnectionPool(poolSize);
459
- const connectionAttempts = 250;
460
-
461
- const results: { success: boolean; connection: MockConnection | null; waitTime: number }[] = [];
462
-
463
- const startTime = Date.now();
464
-
465
- const promises = Array.from({ length: connectionAttempts }, async () => {
466
- const attemptStart = Date.now();
467
- const conn = await acquireConnection(pool);
468
- const waitTime = Date.now() - attemptStart;
469
-
470
- const success = conn !== null;
471
-
472
- if (conn) {
473
- releaseConnection(pool, conn);
474
- }
475
-
476
- results.push({ success, connection: conn, waitTime });
477
- });
478
-
479
- await Promise.all(promises);
480
-
481
- const totalTime = Date.now() - startTime;
482
- const successCount = results.filter((r) => r.success).length;
483
- const errorCount = results.filter((r) => !r.success).length;
484
- const errorRate = (errorCount / connectionAttempts) * 100;
485
-
486
- console.log(` ๐Ÿ“Š Total attempts: ${connectionAttempts}`);
487
- console.log(` โœ… Successful: ${successCount}`);
488
- console.log(` โŒ Failed: ${errorCount}`);
489
- console.log(` ๐Ÿ“ˆ Error rate: ${errorRate.toFixed(2)}%`);
490
- console.log(` โฑ๏ธ Total time: ${totalTime}ms`);
491
-
492
- expect(errorRate).toBeLessThan(5);
493
- });
494
-
495
- it("should gracefully handle pool exhaustion", async () => {
496
- console.log("\n๐Ÿ“Œ Testing pool exhaustion handling...");
497
-
498
- const poolSize = 5;
499
- const pool = createConnectionPool(poolSize);
500
-
501
- const conn1 = await acquireConnection(pool);
502
- const conn2 = await acquireConnection(pool);
503
- const conn3 = await acquireConnection(pool);
504
- const conn4 = await acquireConnection(pool);
505
- const conn5 = await acquireConnection(pool);
506
-
507
- console.log(` ๐Ÿ“Š Acquired connections: 5/5`);
508
-
509
- const timeoutConn = await acquireConnection(pool, 100);
510
-
511
- expect(timeoutConn).toBeNull();
512
- console.log(` โœ… Pool correctly rejected overflow connection`);
513
-
514
- if (conn1) releaseConnection(pool, conn1);
515
- if (conn2) releaseConnection(pool, conn2);
516
- if (conn3) releaseConnection(pool, conn3);
517
- if (conn4) releaseConnection(pool, conn4);
518
- if (conn5) releaseConnection(pool, conn5);
519
- });
520
-
521
- it("should handle rapid acquire/release cycles", async () => {
522
- console.log("\n๐Ÿ“Œ Testing rapid acquire/release cycles...");
523
-
524
- const poolSize = 20;
525
- const pool = createConnectionPool(poolSize);
526
- const cycles = 100;
527
- const errors: number[] = [];
528
-
529
- for (let i = 0; i < cycles; i++) {
530
- const conn = await acquireConnection(pool, 1000);
531
-
532
- if (!conn) {
533
- errors.push(i);
534
- console.log(` โŒ Cycle ${i}: failed to acquire`);
535
- }
536
-
537
- if (conn) {
538
- releaseConnection(pool, conn);
539
- }
540
-
541
- if (i % 20 === 0) {
542
- await sleep(5);
543
- }
544
- }
545
-
546
- console.log(` ๐Ÿ“Š Cycles completed: ${cycles}`);
547
- console.log(` โŒ Errors: ${errors.length}`);
548
-
549
- expect(errors.length / cycles).toBeLessThan(0.1);
550
- });
551
- });
552
-
553
- describe("๐Ÿ”’ Thread Safety / Race Condition Detection", () => {
554
- it("should handle concurrent writes to shared state safely", async () => {
555
- console.log("\n๐Ÿ“Œ Testing thread safety with concurrent operations...");
556
-
557
- let sharedCounter = 0;
558
- const operations = 1000;
559
- const mutex = new Mutex();
560
-
561
- const increment = async (): Promise<void> => {
562
- await mutex.runExclusive(async () => {
563
- const current = sharedCounter;
564
- await sleep(Math.random() * 1);
565
- sharedCounter = current + 1;
566
- });
567
- };
568
-
569
- const promises = Array.from({ length: operations }, () =>
570
- increment()
571
- );
572
-
573
- await Promise.all(promises);
574
-
575
- console.log(` ๐Ÿ“Š Expected counter: ${operations}`);
576
- console.log(` ๐Ÿ“Š Actual counter: ${sharedCounter}`);
577
-
578
- if (sharedCounter < operations) {
579
- console.log(` โš ๏ธ Race condition detected! Lost ${operations - sharedCounter} increments`);
580
- }
581
-
582
- expect(sharedCounter).toBe(operations);
583
- console.log(` โœ… No race conditions detected`);
584
- });
585
-
586
- it("should handle atomic operations correctly", async () => {
587
- console.log("\n๐Ÿ“Œ Testing atomic operations...");
588
-
589
- let atomicCounter = 0;
590
- const operations = 500;
591
- const workers = 10;
592
- const mutex = new Mutex();
593
-
594
- const atomicIncrement = async (): Promise<void> => {
595
- await mutex.runExclusive(async () => {
596
- const original = atomicCounter;
597
- await sleep(0);
598
- atomicCounter = original + 1;
599
- });
600
- };
601
-
602
- const workerPromises = Array.from({ length: workers }, async () => {
603
- const opsPerWorker = operations / workers;
604
- await Promise.all(
605
- Array.from({ length: opsPerWorker }, () => atomicIncrement())
606
- );
607
- });
608
-
609
- await Promise.all(workerPromises);
610
-
611
- console.log(` ๐Ÿ“Š Final atomic counter: ${atomicCounter}`);
612
-
613
- const lostUpdates = operations - atomicCounter;
614
- if (lostUpdates > 0) {
615
- console.log(` โš ๏ธ Lost updates: ${lostUpdates}`);
616
- }
617
-
618
- expect(atomicCounter).toBe(operations);
619
- console.log(` โœ… All updates preserved`);
620
- });
621
-
622
- it("should handle concurrent read/write operations", async () => {
623
- console.log("\n๐Ÿ“Œ Testing concurrent read/write...");
624
-
625
- const data = new Map<string, number>();
626
- const keys = ["a", "b", "c", "d", "e"];
627
- const operationsPerKey = 100;
628
-
629
- const keyMutexes = new Map<string, Mutex>();
630
- for (const key of keys) {
631
- keyMutexes.set(key, new Mutex());
632
- }
633
-
634
- const readWrite = async (key: string): Promise<void> => {
635
- const mutex = keyMutexes.get(key)!;
636
- for (let i = 0; i < operationsPerKey; i++) {
637
- await mutex.runExclusive(async () => {
638
- const current = data.get(key) ?? 0;
639
- await sleep(0);
640
- data.set(key, current + 1);
641
- });
642
- }
643
- };
644
-
645
- const promises = keys.flatMap((key) => [
646
- readWrite(key),
647
- readWrite(key),
648
- ]);
649
-
650
- await Promise.all(promises);
651
-
652
- let hasRaceCondition = false;
653
- for (const key of keys) {
654
- const value = data.get(key) ?? 0;
655
- const expected = operationsPerKey * 2;
656
- console.log(` ๐Ÿ“Š Key ${key}: ${value}/${expected}`);
657
-
658
- if (value < expected) {
659
- hasRaceCondition = true;
660
- }
661
- }
662
-
663
- expect(hasRaceCondition).toBe(false);
664
- console.log(` โœ… All concurrent writes successful`);
665
- });
666
- });
667
-
668
- describe("๐Ÿ“Š Memory Monitor Class Unit Tests", () => {
669
- it("should correctly calculate memory growth", () => {
670
- const monitor = new MemoryMonitor();
671
-
672
- monitor.captureSnapshot();
673
- monitor.captureSnapshot();
674
- monitor.captureSnapshot();
675
-
676
- expect(monitor.getSnapshots().length).toBe(3);
677
- expect(monitor.getMemoryInfo().growthPercent).toBe(0);
678
- });
679
-
680
- it("should detect memory leak when threshold exceeded", () => {
681
- const monitor = new MemoryMonitor({
682
- memoryLeakThresholdPercent: 10,
683
- });
684
-
685
- for (let i = 0; i < 100; i++) {
686
- monitor.captureSnapshot();
687
- }
688
-
689
- expect(monitor.hasMemoryLeak()).toBe(false);
690
- });
691
-
692
- it("should allow threshold configuration", () => {
693
- const monitor = new MemoryMonitor();
694
- monitor.setThresholds({ queryTimeThresholdMs: 100 });
695
-
696
- expect(monitor["thresholds"].queryTimeThresholdMs).toBe(100);
697
- });
698
- });
699
- });
700
-
701
- describe("๐Ÿงช Integration: Full System Stress Test", () => {
702
- it("should handle comprehensive stress test", async () => {
703
- console.log("\n๐Ÿ“Œ Running comprehensive system stress test...");
704
-
705
- const monitor = new MemoryMonitor({ memoryLeakThresholdPercent: 25 });
706
-
707
- const operations = {
708
- memory: 0,
709
- handles: 0,
710
- queries: 0,
711
- connections: 0,
712
- raceOps: 0,
713
- };
714
-
715
- const memoryOps = async () => {
716
- const arr: number[] = [];
717
- for (let i = 0; i < 100; i++) {
718
- arr.push(i);
719
- monitor.captureSnapshot();
720
- }
721
- operations.memory++;
722
- };
723
-
724
- const handleOps = async () => {
725
- const timers = Array.from({ length: 10 }, (_, i) =>
726
- setTimeout(() => {}, 100 + i)
727
- );
728
- await sleep(150);
729
- timers.forEach(clearTimeout);
730
- operations.handles++;
731
- };
732
-
733
- const queryOps = async () => {
734
- await new Promise((r) => setTimeout(r, Math.random() * 20));
735
- operations.queries++;
736
- };
737
-
738
- const raceOps = async () => {
739
- let counter = 0;
740
- const inc = () => {
741
- const c = counter;
742
- counter = c + 1;
743
- };
744
- await Promise.all(Array.from({ length: 5 }, () => inc()));
745
- operations.raceOps++;
746
- };
747
-
748
- await Promise.all([
749
- memoryOps(),
750
- memoryOps(),
751
- handleOps(),
752
- handleOps(),
753
- queryOps(),
754
- queryOps(),
755
- raceOps(),
756
- raceOps(),
757
- ]);
758
-
759
- const memInfo = monitor.getMemoryInfo();
760
- console.log(` ๐Ÿ“Š Memory growth: ${memInfo.growthPercent.toFixed(2)}%`);
761
- console.log(` ๐Ÿ“Š Operations completed:`);
762
- console.log(` - Memory ops: ${operations.memory}`);
763
- console.log(` - Handle ops: ${operations.handles}`);
764
- console.log(` - Query ops: ${operations.queries}`);
765
- console.log(` - Race ops: ${operations.raceOps}`);
766
-
767
- expect(monitor.hasMemoryLeak()).toBe(false);
768
- }, 30000);
769
- });
770
-
771
- console.log("\n๐Ÿ“ To run these tests with GC exposure, use:");
772
- console.log(" bun test --expose-gc");
773
- console.log(" or");
774
- console.log(" bun test --preload ./tests/memory-perf.test.ts\n");