claude-flow-novice 2.0.3 → 2.0.4

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 (272) hide show
  1. package/dist/src/cli/commands/guidance.js +487 -668
  2. package/dist/src/cli/commands/index-validate.js +18 -29
  3. package/dist/src/cli/commands/mcp-troubleshoot.js +230 -282
  4. package/dist/src/cli/commands/neural-goal-init.js +92 -125
  5. package/dist/src/cli/commands/swarm-exec.js +317 -393
  6. package/dist/src/cli/commands/swarm.js +1 -1
  7. package/dist/src/cli/commands/validate-framework.js +983 -1100
  8. package/dist/src/cli/commands/validate.js +144 -223
  9. package/dist/src/cli/simple-commands/__tests__/agent.test.js +265 -277
  10. package/dist/src/cli/simple-commands/__tests__/memory.test.js +6 -7
  11. package/dist/src/cli/simple-commands/__tests__/swarm.test.js +373 -356
  12. package/dist/src/cli/simple-commands/__tests__/task.test.js +6 -7
  13. package/dist/src/cli/simple-commands/agent.js +157 -193
  14. package/dist/src/cli/simple-commands/analysis.js +336 -446
  15. package/dist/src/cli/simple-commands/automation-executor.js +1095 -1339
  16. package/dist/src/cli/simple-commands/automation.js +481 -469
  17. package/dist/src/cli/simple-commands/batch-manager.js +261 -313
  18. package/dist/src/cli/simple-commands/claude-telemetry.js +241 -267
  19. package/dist/src/cli/simple-commands/claude-track.js +68 -90
  20. package/dist/src/cli/simple-commands/concurrent-display.js +266 -320
  21. package/dist/src/cli/simple-commands/config.js +245 -290
  22. package/dist/src/cli/simple-commands/coordination.js +182 -234
  23. package/dist/src/cli/simple-commands/enhanced-ui-views.js +812 -615
  24. package/dist/src/cli/simple-commands/enhanced-webui-complete.js +922 -981
  25. package/dist/src/cli/simple-commands/fix-hook-variables.js +274 -294
  26. package/dist/src/cli/simple-commands/github/gh-coordinator.js +378 -457
  27. package/dist/src/cli/simple-commands/github/github-api.js +535 -574
  28. package/dist/src/cli/simple-commands/github/init.js +276 -303
  29. package/dist/src/cli/simple-commands/github.js +222 -247
  30. package/dist/src/cli/simple-commands/goal.js +51 -63
  31. package/dist/src/cli/simple-commands/hive-mind/auto-save-middleware.js +208 -278
  32. package/dist/src/cli/simple-commands/hive-mind/communication.js +601 -696
  33. package/dist/src/cli/simple-commands/hive-mind/core.js +907 -979
  34. package/dist/src/cli/simple-commands/hive-mind/db-optimizer.js +406 -655
  35. package/dist/src/cli/simple-commands/hive-mind/mcp-wrapper.js +1125 -1245
  36. package/dist/src/cli/simple-commands/hive-mind/memory.js +854 -1090
  37. package/dist/src/cli/simple-commands/hive-mind/performance-optimizer.js +459 -574
  38. package/dist/src/cli/simple-commands/hive-mind/performance-test.js +263 -347
  39. package/dist/src/cli/simple-commands/hive-mind/queen.js +727 -768
  40. package/dist/src/cli/simple-commands/hive-mind/session-manager.js +745 -1049
  41. package/dist/src/cli/simple-commands/hive-mind-optimize.js +227 -283
  42. package/dist/src/cli/simple-commands/hive-mind-wizard.js +174 -217
  43. package/dist/src/cli/simple-commands/hive-mind.js +1842 -2283
  44. package/dist/src/cli/simple-commands/hive.js +90 -79
  45. package/dist/src/cli/simple-commands/hook-safety.js +431 -521
  46. package/dist/src/cli/simple-commands/hooks/session-start-soul.js +203 -254
  47. package/dist/src/cli/simple-commands/hooks.js +1064 -1204
  48. package/dist/src/cli/simple-commands/init/agent-copier.js +294 -319
  49. package/dist/src/cli/simple-commands/init/batch-init.js +496 -562
  50. package/dist/src/cli/simple-commands/init/claude-commands/claude-flow-commands.js +13 -19
  51. package/dist/src/cli/simple-commands/init/claude-commands/optimized-claude-flow-commands.js +13 -19
  52. package/dist/src/cli/simple-commands/init/claude-commands/optimized-slash-commands.js +61 -88
  53. package/dist/src/cli/simple-commands/init/claude-commands/optimized-sparc-commands.js +125 -150
  54. package/dist/src/cli/simple-commands/init/claude-commands/slash-commands.js +42 -49
  55. package/dist/src/cli/simple-commands/init/claude-commands/sparc-commands.js +43 -61
  56. package/dist/src/cli/simple-commands/init/copy-revised-templates.js +141 -147
  57. package/dist/src/cli/simple-commands/init/executable-wrapper.js +31 -44
  58. package/dist/src/cli/simple-commands/init/gitignore-updater.js +64 -90
  59. package/dist/src/cli/simple-commands/init/help.js +104 -107
  60. package/dist/src/cli/simple-commands/init/hive-mind-init.js +509 -528
  61. package/dist/src/cli/simple-commands/init/index.js +1510 -1759
  62. package/dist/src/cli/simple-commands/init/performance-monitor.js +234 -317
  63. package/dist/src/cli/simple-commands/init/rollback/backup-manager.js +441 -504
  64. package/dist/src/cli/simple-commands/init/rollback/index.js +289 -364
  65. package/dist/src/cli/simple-commands/init/rollback/recovery-manager.js +652 -728
  66. package/dist/src/cli/simple-commands/init/rollback/rollback-executor.js +416 -481
  67. package/dist/src/cli/simple-commands/init/rollback/state-tracker.js +369 -448
  68. package/dist/src/cli/simple-commands/init/sparc/roo-readme.js +1 -2
  69. package/dist/src/cli/simple-commands/init/sparc/roomodes-config.js +122 -99
  70. package/dist/src/cli/simple-commands/init/sparc/workflows.js +32 -37
  71. package/dist/src/cli/simple-commands/init/sparc-structure.js +55 -62
  72. package/dist/src/cli/simple-commands/init/template-copier.js +421 -533
  73. package/dist/src/cli/simple-commands/init/templates/coordination-md.js +3 -6
  74. package/dist/src/cli/simple-commands/init/templates/enhanced-templates.js +344 -318
  75. package/dist/src/cli/simple-commands/init/templates/github-safe-enhanced.js +173 -218
  76. package/dist/src/cli/simple-commands/init/templates/github-safe.js +65 -75
  77. package/dist/src/cli/simple-commands/init/templates/memory-bank-md.js +3 -6
  78. package/dist/src/cli/simple-commands/init/templates/readme-files.js +2 -4
  79. package/dist/src/cli/simple-commands/init/templates/safe-hook-patterns.js +187 -230
  80. package/dist/src/cli/simple-commands/init/templates/sparc-modes.js +53 -80
  81. package/dist/src/cli/simple-commands/init/templates/verification-claude-md.js +101 -85
  82. package/dist/src/cli/simple-commands/init/validation/config-validator.js +283 -330
  83. package/dist/src/cli/simple-commands/init/validation/health-checker.js +495 -561
  84. package/dist/src/cli/simple-commands/init/validation/index.js +302 -358
  85. package/dist/src/cli/simple-commands/init/validation/mode-validator.js +308 -359
  86. package/dist/src/cli/simple-commands/init/validation/post-init-validator.js +389 -366
  87. package/dist/src/cli/simple-commands/init/validation/pre-init-validator.js +270 -268
  88. package/dist/src/cli/simple-commands/init/validation/test-runner.js +427 -447
  89. package/dist/src/cli/simple-commands/init.js +1 -2
  90. package/dist/src/cli/simple-commands/mcp-health.js +131 -158
  91. package/dist/src/cli/simple-commands/mcp-integration-layer.js +533 -634
  92. package/dist/src/cli/simple-commands/mcp.js +345 -400
  93. package/dist/src/cli/simple-commands/memory-consolidation.js +426 -537
  94. package/dist/src/cli/simple-commands/memory.js +247 -311
  95. package/dist/src/cli/simple-commands/migrate-hooks.js +39 -46
  96. package/dist/src/cli/simple-commands/monitor.js +294 -363
  97. package/dist/src/cli/simple-commands/neural.js +51 -65
  98. package/dist/src/cli/simple-commands/pair-autofix-only.js +538 -662
  99. package/dist/src/cli/simple-commands/pair-basic.js +528 -656
  100. package/dist/src/cli/simple-commands/pair-old.js +430 -543
  101. package/dist/src/cli/simple-commands/pair-working.js +615 -751
  102. package/dist/src/cli/simple-commands/pair.js +615 -751
  103. package/dist/src/cli/simple-commands/performance-hooks.js +83 -111
  104. package/dist/src/cli/simple-commands/performance-metrics.js +348 -433
  105. package/dist/src/cli/simple-commands/process-ui-enhanced.js +708 -787
  106. package/dist/src/cli/simple-commands/process-ui.js +230 -254
  107. package/dist/src/cli/simple-commands/realtime-update-system.js +525 -611
  108. package/dist/src/cli/simple-commands/sparc/architecture.js +1704 -1530
  109. package/dist/src/cli/simple-commands/sparc/commands.js +438 -516
  110. package/dist/src/cli/simple-commands/sparc/completion.js +1224 -1481
  111. package/dist/src/cli/simple-commands/sparc/coordinator.js +913 -978
  112. package/dist/src/cli/simple-commands/sparc/index.js +241 -298
  113. package/dist/src/cli/simple-commands/sparc/phase-base.js +314 -390
  114. package/dist/src/cli/simple-commands/sparc/pseudocode.js +965 -869
  115. package/dist/src/cli/simple-commands/sparc/refinement.js +980 -1273
  116. package/dist/src/cli/simple-commands/sparc/specification.js +559 -645
  117. package/dist/src/cli/simple-commands/sparc-modes/architect.js +1 -1
  118. package/dist/src/cli/simple-commands/sparc-modes/ask.js +1 -1
  119. package/dist/src/cli/simple-commands/sparc-modes/code.js +1 -1
  120. package/dist/src/cli/simple-commands/sparc-modes/debug.js +1 -1
  121. package/dist/src/cli/simple-commands/sparc-modes/devops.js +1 -1
  122. package/dist/src/cli/simple-commands/sparc-modes/docs-writer.js +1 -1
  123. package/dist/src/cli/simple-commands/sparc-modes/generic.js +1 -1
  124. package/dist/src/cli/simple-commands/sparc-modes/index.js +47 -55
  125. package/dist/src/cli/simple-commands/sparc-modes/integration.js +1 -1
  126. package/dist/src/cli/simple-commands/sparc-modes/mcp.js +1 -1
  127. package/dist/src/cli/simple-commands/sparc-modes/monitoring.js +1 -1
  128. package/dist/src/cli/simple-commands/sparc-modes/optimization.js +1 -1
  129. package/dist/src/cli/simple-commands/sparc-modes/security-review.js +1 -1
  130. package/dist/src/cli/simple-commands/sparc-modes/sparc-orchestrator.js +1 -1
  131. package/dist/src/cli/simple-commands/sparc-modes/spec-pseudocode.js +1 -1
  132. package/dist/src/cli/simple-commands/sparc-modes/supabase-admin.js +1 -1
  133. package/dist/src/cli/simple-commands/sparc-modes/swarm.js +101 -87
  134. package/dist/src/cli/simple-commands/sparc-modes/tdd.js +1 -1
  135. package/dist/src/cli/simple-commands/sparc-modes/tutorial.js +1 -1
  136. package/dist/src/cli/simple-commands/sparc.js +465 -493
  137. package/dist/src/cli/simple-commands/start-ui.js +108 -132
  138. package/dist/src/cli/simple-commands/start-wrapper.js +240 -268
  139. package/dist/src/cli/simple-commands/start.js +1 -1
  140. package/dist/src/cli/simple-commands/status.js +254 -275
  141. package/dist/src/cli/simple-commands/stream-chain-clean.js +128 -171
  142. package/dist/src/cli/simple-commands/stream-chain-fixed.js +61 -82
  143. package/dist/src/cli/simple-commands/stream-chain-real.js +267 -331
  144. package/dist/src/cli/simple-commands/stream-chain-working.js +211 -263
  145. package/dist/src/cli/simple-commands/stream-chain.js +260 -318
  146. package/dist/src/cli/simple-commands/stream-processor.js +290 -315
  147. package/dist/src/cli/simple-commands/swarm-executor.js +189 -222
  148. package/dist/src/cli/simple-commands/swarm-metrics-integration.js +208 -300
  149. package/dist/src/cli/simple-commands/swarm-ui.js +623 -703
  150. package/dist/src/cli/simple-commands/swarm-webui-integration.js +258 -286
  151. package/dist/src/cli/simple-commands/swarm.js +887 -1082
  152. package/dist/src/cli/simple-commands/task.js +161 -206
  153. package/dist/src/cli/simple-commands/timestamp-fix.js +59 -89
  154. package/dist/src/cli/simple-commands/token-tracker.js +258 -316
  155. package/dist/src/cli/simple-commands/tool-execution-framework.js +433 -519
  156. package/dist/src/cli/simple-commands/train-and-stream.js +275 -331
  157. package/dist/src/cli/simple-commands/training-pipeline.js +619 -725
  158. package/dist/src/cli/simple-commands/training.js +170 -227
  159. package/dist/src/cli/simple-commands/verification-hooks.js +261 -284
  160. package/dist/src/cli/simple-commands/verification-integration.js +389 -417
  161. package/dist/src/cli/simple-commands/verification-training-integration.js +486 -606
  162. package/dist/src/cli/simple-commands/verification.js +493 -513
  163. package/dist/src/cli/simple-commands/web-server.js +766 -836
  164. package/dist/src/cli/simple-commands/webui-validator.js +106 -124
  165. package/dist/src/coordination/event-bus/demo-wasm-integration.js +212 -251
  166. package/dist/src/coordination/event-bus/qe-event-bus.js +608 -748
  167. package/dist/src/coordination/event-bus/qe-event-bus.test.js +379 -454
  168. package/dist/src/coordination/iteration-tracker.js +363 -454
  169. package/dist/src/enterprise/analytics-manager.js +1135 -0
  170. package/dist/src/enterprise/audit-manager.js +1115 -0
  171. package/dist/src/enterprise/cloud-manager.js +891 -0
  172. package/dist/src/enterprise/deployment-manager.js +966 -0
  173. package/dist/src/enterprise/index.js +6 -0
  174. package/dist/src/enterprise/project-manager.js +584 -0
  175. package/dist/src/enterprise/security-manager.js +991 -0
  176. package/dist/src/index.js +1 -1
  177. package/dist/src/mcp/DEPRECATED.js +46 -60
  178. package/dist/src/mcp/fixes/mcp-error-fixes.js +115 -134
  179. package/dist/src/mcp/implementations/agent-tracker.js +114 -128
  180. package/dist/src/mcp/implementations/daa-tools.js +292 -350
  181. package/dist/src/mcp/implementations/workflow-tools.js +329 -361
  182. package/dist/src/mcp/mcp-config-manager.js +1183 -1331
  183. package/dist/src/mcp/mcp-server-novice-simplified.js +11 -17
  184. package/dist/src/mcp/mcp-server-novice.js +11 -17
  185. package/dist/src/mcp/mcp-server-sdk.js +11 -17
  186. package/dist/src/mcp/mcp-server.js +1620 -1484
  187. package/dist/src/mcp/ruv-swarm-wrapper.js +209 -239
  188. package/dist/src/memory/advanced-serializer.js +609 -589
  189. package/dist/src/memory/enhanced-examples.js +220 -305
  190. package/dist/src/memory/enhanced-memory.js +295 -336
  191. package/dist/src/memory/enhanced-session-serializer.js +408 -492
  192. package/dist/src/memory/fallback-memory-system.js +900 -1021
  193. package/dist/src/memory/fallback-store.js +93 -131
  194. package/dist/src/memory/high-performance-serialization.js +592 -730
  195. package/dist/src/memory/in-memory-store.js +161 -213
  196. package/dist/src/memory/index.js +123 -157
  197. package/dist/src/memory/lock-free-structures.js +578 -764
  198. package/dist/src/memory/memory-mapped-persistence.js +585 -766
  199. package/dist/src/memory/memory-pressure-manager.js +569 -707
  200. package/dist/src/memory/migration.js +358 -445
  201. package/dist/src/memory/shared-memory.js +641 -768
  202. package/dist/src/memory/sqlite-store.js +245 -325
  203. package/dist/src/memory/sqlite-wrapper.js +122 -151
  204. package/dist/src/memory/swarm-memory.js +470 -603
  205. package/dist/src/memory/test-example.js +126 -134
  206. package/dist/src/memory/ultra-fast-memory-store.js +622 -821
  207. package/dist/src/memory/unified-memory-manager.js +356 -437
  208. package/dist/src/migration/index.js +92 -0
  209. package/dist/src/migration/logger.js +121 -0
  210. package/dist/src/migration/migration-analyzer.js +268 -0
  211. package/dist/src/migration/migration-runner.js +522 -0
  212. package/dist/src/migration/migration-validator.js +285 -0
  213. package/dist/src/migration/progress-reporter.js +150 -0
  214. package/dist/src/migration/rollback-manager.js +321 -0
  215. package/dist/src/migration/tests/migration-system.test.js +7 -0
  216. package/dist/src/migration/types.js +3 -0
  217. package/dist/src/swarm/CodeRefactoringSwarm.js +777 -952
  218. package/dist/src/swarm/__tests__/integration.test.js +227 -0
  219. package/dist/src/swarm/__tests__/prompt-copier.test.js +344 -0
  220. package/dist/src/swarm/advanced-orchestrator.js +1095 -0
  221. package/dist/src/swarm/claude-code-interface.js +961 -0
  222. package/dist/src/swarm/claude-flow-executor.js +229 -0
  223. package/dist/src/swarm/consensus-coordinator.js +475 -0
  224. package/dist/src/swarm/coordinator.js +2993 -0
  225. package/dist/src/swarm/direct-executor.js +1180 -0
  226. package/dist/src/swarm/error-recovery/advanced-error-detection.js +691 -0
  227. package/dist/src/swarm/error-recovery/automated-recovery-workflows.js +998 -0
  228. package/dist/src/swarm/error-recovery/error-recovery-coordinator.js +1197 -0
  229. package/dist/src/swarm/error-recovery/recovery-monitoring.js +772 -0
  230. package/dist/src/swarm/error-recovery/resilience-architecture.js +714 -0
  231. package/dist/src/swarm/error-recovery/self-healing-mechanisms.js +1319 -0
  232. package/dist/src/swarm/error-recovery/test-error-recovery-effectiveness.js +808 -0
  233. package/dist/src/swarm/executor-v2.js +322 -0
  234. package/dist/src/swarm/executor.js +815 -0
  235. package/dist/src/swarm/hive-mind-integration.js +703 -0
  236. package/dist/src/swarm/index.js +41 -0
  237. package/dist/src/swarm/json-output-aggregator.js +267 -0
  238. package/dist/src/swarm/large-scale-coordinator.js +542 -0
  239. package/dist/src/swarm/mcp-integration-wrapper.js +628 -0
  240. package/dist/src/swarm/memory.js +1117 -0
  241. package/dist/src/swarm/optimizations/__tests__/optimization.test.js +348 -0
  242. package/dist/src/swarm/optimizations/async-file-manager.js +285 -0
  243. package/dist/src/swarm/optimizations/circular-buffer.js +162 -0
  244. package/dist/src/swarm/optimizations/connection-pool.js +244 -0
  245. package/dist/src/swarm/optimizations/index.js +28 -0
  246. package/dist/src/swarm/optimizations/optimized-executor.js +320 -0
  247. package/dist/src/swarm/optimizations/ttl-map.js +234 -0
  248. package/dist/src/swarm/prompt-cli.js +200 -0
  249. package/dist/src/swarm/prompt-copier-enhanced.js +202 -0
  250. package/dist/src/swarm/prompt-copier.js +381 -0
  251. package/dist/src/swarm/prompt-manager.js +295 -0
  252. package/dist/src/swarm/prompt-utils.js +310 -0
  253. package/dist/src/swarm/result-aggregator.js +718 -0
  254. package/dist/src/swarm/sparc-executor.js +1568 -0
  255. package/dist/src/swarm/strategies/auto.js +758 -0
  256. package/dist/src/swarm/strategies/base.js +128 -0
  257. package/dist/src/swarm/strategies/research.js +914 -0
  258. package/dist/src/swarm/strategies/strategy-metrics-patch.js +2 -0
  259. package/dist/src/swarm/types.js +52 -0
  260. package/dist/src/swarm/workers/copy-worker.js +56 -0
  261. package/dist/src/utils/__tests__/github-cli-safety-wrapper.test.js +332 -400
  262. package/dist/src/utils/github-cli-safe.js +56 -64
  263. package/dist/src/utils/github-cli-safety-wrapper.js +451 -546
  264. package/dist/src/utils/npx-isolated-cache.js +104 -119
  265. package/dist/src/utils/preference-manager.js +622 -652
  266. package/dist/src/utils/timezone-utils.js +86 -105
  267. package/dist/src/validators/epic-config-schema.js +214 -0
  268. package/dist/src/validators/index.js +10 -0
  269. package/dist/src/validators/swarm-init-validator.js +259 -0
  270. package/dist/src/validators/todowrite-batching-validator.js +215 -0
  271. package/dist/src/validators/todowrite-integration.js +187 -0
  272. package/package.json +2 -2
@@ -1,115 +1,85 @@
1
1
  /**
2
2
  * Hive Mind Session Manager
3
3
  * Handles session persistence and resume functionality for swarms
4
- */
5
-
6
- import path from 'path';
7
- import { existsSync, mkdirSync } from 'fs';
8
- import { readFile, writeFile } from 'fs/promises';
9
- import chalk from 'chalk';
10
- import { cwd } from '../../node-compat.js';
11
- import { createDatabase, isSQLiteAvailable, isWindows } from '../../../memory/sqlite-wrapper.js';
12
- import { sessionSerializer } from '../../../memory/enhanced-session-serializer.js';
13
- import { SerializationError, DeserializationError } from '../../../memory/advanced-serializer.js';
14
-
4
+ */ import path from "path";
5
+ import { existsSync, mkdirSync } from "fs";
6
+ import { readFile, writeFile } from "node:fs/promises";
7
+ import { cwd } from "../../node-compat.js";
8
+ import { createDatabase, isSQLiteAvailable, isWindows } from "../../../memory/sqlite-wrapper.js";
9
+ import { sessionSerializer } from "../../../memory/enhanced-session-serializer.js";
15
10
  export class HiveMindSessionManager {
16
- constructor(hiveMindDir = null) {
17
- this.hiveMindDir = hiveMindDir || path.join(cwd(), '.hive-mind');
18
- this.sessionsDir = path.join(this.hiveMindDir, 'sessions');
19
- this.dbPath = path.join(this.hiveMindDir, 'hive.db');
20
- this.db = null;
21
- this.isInMemory = false;
22
- this.memoryStore = null;
23
- this.initializationPromise = null;
24
-
25
- // Ensure directories exist
26
- this.ensureDirectories();
27
-
28
- // Initialize database connection (store promise for later)
29
- this.initializationPromise = this.initializeDatabase();
30
- }
31
-
32
- /**
11
+ /**
33
12
  * Initialize database with fallback support
34
- */
35
- async initializeDatabase() {
36
- try {
37
- const sqliteAvailable = await isSQLiteAvailable();
38
-
39
- if (!sqliteAvailable) {
40
- console.warn('SQLite not available, using in-memory session storage');
41
- this.initializeInMemoryFallback();
42
- return;
43
- }
44
-
45
- this.db = await createDatabase(this.dbPath);
46
- if (this.db) {
47
- this.initializeSchema();
48
- } else {
49
- throw new Error('Failed to create database instance');
50
- }
51
- } catch (error) {
52
- console.error('Failed to create SQLite database:', error.message);
53
- console.warn('Falling back to in-memory session storage');
54
- this.initializeInMemoryFallback();
13
+ */ async initializeDatabase() {
14
+ try {
15
+ const sqliteAvailable = await isSQLiteAvailable();
16
+ if (!sqliteAvailable) {
17
+ console.warn('SQLite not available, using in-memory session storage');
18
+ this.initializeInMemoryFallback();
19
+ return;
20
+ }
21
+ this.db = await createDatabase(this.dbPath);
22
+ if (this.db) {
23
+ this.initializeSchema();
24
+ } else {
25
+ throw new Error('Failed to create database instance');
26
+ }
27
+ } catch (error) {
28
+ console.error('Failed to create SQLite database:', error.message);
29
+ console.warn('Falling back to in-memory session storage');
30
+ this.initializeInMemoryFallback();
31
+ }
55
32
  }
56
- }
57
-
58
- /**
33
+ /**
59
34
  * Ensure database is initialized before use
60
- */
61
- async ensureInitialized() {
62
- if (this.initializationPromise) {
63
- await this.initializationPromise;
64
- this.initializationPromise = null;
65
- }
66
-
67
- if (this.db === null && !this.isInMemory) {
68
- await this.initializeDatabase();
35
+ */ async ensureInitialized() {
36
+ if (this.initializationPromise) {
37
+ await this.initializationPromise;
38
+ this.initializationPromise = null;
39
+ }
40
+ if (this.db === null && !this.isInMemory) {
41
+ await this.initializeDatabase();
42
+ }
69
43
  }
70
- }
71
-
72
- /**
44
+ /**
73
45
  * Initialize in-memory fallback for session storage
74
- */
75
- initializeInMemoryFallback() {
76
- this.isInMemory = true;
77
- this.memoryStore = {
78
- sessions: new Map(),
79
- checkpoints: new Map(),
80
- logs: new Map(),
81
- };
82
-
83
- if (isWindows()) {
84
- console.info(`
46
+ */ initializeInMemoryFallback() {
47
+ this.isInMemory = true;
48
+ this.memoryStore = {
49
+ sessions: new Map(),
50
+ checkpoints: new Map(),
51
+ logs: new Map()
52
+ };
53
+ if (isWindows()) {
54
+ console.info(`
85
55
  Note: Session data will not persist between runs on Windows without SQLite.
86
56
  To enable persistence, see: https://github.com/ruvnet/claude-code-flow/docs/windows-installation.md
87
57
  `);
58
+ }
88
59
  }
89
- }
90
-
91
- /**
60
+ /**
92
61
  * Ensure required directories exist
93
- */
94
- ensureDirectories() {
95
- if (!existsSync(this.hiveMindDir)) {
96
- mkdirSync(this.hiveMindDir, { recursive: true });
97
- }
98
- if (!existsSync(this.sessionsDir)) {
99
- mkdirSync(this.sessionsDir, { recursive: true });
62
+ */ ensureDirectories() {
63
+ if (!existsSync(this.hiveMindDir)) {
64
+ mkdirSync(this.hiveMindDir, {
65
+ recursive: true
66
+ });
67
+ }
68
+ if (!existsSync(this.sessionsDir)) {
69
+ mkdirSync(this.sessionsDir, {
70
+ recursive: true
71
+ });
72
+ }
100
73
  }
101
- }
102
-
103
- /**
74
+ /**
104
75
  * Initialize database schema for sessions
105
- */
106
- initializeSchema() {
107
- if (!this.db) {
108
- console.error('Database not initialized');
109
- return;
110
- }
111
- // Create the base schema
112
- this.db.exec(`
76
+ */ initializeSchema() {
77
+ if (!this.db) {
78
+ console.error('Database not initialized');
79
+ return;
80
+ }
81
+ // Create the base schema
82
+ this.db.exec(`
113
83
  CREATE TABLE IF NOT EXISTS sessions (
114
84
  id TEXT PRIMARY KEY,
115
85
  swarm_id TEXT NOT NULL,
@@ -148,247 +118,189 @@ To enable persistence, see: https://github.com/ruvnet/claude-code-flow/docs/wind
148
118
  FOREIGN KEY (session_id) REFERENCES sessions(id)
149
119
  );
150
120
  `);
151
-
152
- // Run migrations to add new columns
153
- this.runMigrations();
154
- }
155
-
156
- /**
157
- * Run database migrations
158
- */
159
- runMigrations() {
160
- if (!this.db) {
161
- console.error('Database not initialized for migrations');
162
- return;
121
+ // Run migrations to add new columns
122
+ this.runMigrations();
163
123
  }
164
- try {
165
- // Check if required columns exist
166
- const columns = this.db.prepare('PRAGMA table_info(sessions)').all();
167
-
168
- // Core columns
169
- const hasObjective = columns.some((col) => col.name === 'objective');
170
- const hasSwarmName = columns.some((col) => col.name === 'swarm_name');
171
- const hasCheckpointData = columns.some((col) => col.name === 'checkpoint_data');
172
- const hasMetadata = columns.some((col) => col.name === 'metadata');
173
- const hasParentPid = columns.some((col) => col.name === 'parent_pid');
174
- const hasChildPids = columns.some((col) => col.name === 'child_pids');
175
-
176
- // Timestamp columns
177
- const hasUpdatedAt = columns.some((col) => col.name === 'updated_at');
178
- const hasPausedAt = columns.some((col) => col.name === 'paused_at');
179
- const hasResumedAt = columns.some((col) => col.name === 'resumed_at');
180
- const hasCompletionPercentage = columns.some((col) => col.name === 'completion_percentage');
181
-
182
- if (!hasObjective) {
183
- this.db.exec('ALTER TABLE sessions ADD COLUMN objective TEXT');
184
- console.log('Added objective column to sessions table');
185
- }
186
-
187
- if (!hasSwarmName) {
188
- this.db.exec('ALTER TABLE sessions ADD COLUMN swarm_name TEXT');
189
- console.log('Added swarm_name column to sessions table');
190
- }
191
-
192
- if (!hasCheckpointData) {
193
- this.db.exec('ALTER TABLE sessions ADD COLUMN checkpoint_data TEXT');
194
- console.log('Added checkpoint_data column to sessions table');
195
- }
196
-
197
- if (!hasMetadata) {
198
- this.db.exec('ALTER TABLE sessions ADD COLUMN metadata TEXT');
199
- console.log('Added metadata column to sessions table');
200
- }
201
-
202
- if (!hasParentPid) {
203
- this.db.exec('ALTER TABLE sessions ADD COLUMN parent_pid INTEGER');
204
- console.log('Added parent_pid column to sessions table');
205
- }
206
-
207
- if (!hasChildPids) {
208
- this.db.exec('ALTER TABLE sessions ADD COLUMN child_pids TEXT');
209
- console.log('Added child_pids column to sessions table');
210
- }
211
-
212
- if (!hasUpdatedAt) {
213
- this.db.exec(
214
- 'ALTER TABLE sessions ADD COLUMN updated_at DATETIME DEFAULT CURRENT_TIMESTAMP',
215
- );
216
- console.log('Added updated_at column to sessions table');
217
- }
218
-
219
- if (!hasPausedAt) {
220
- this.db.exec('ALTER TABLE sessions ADD COLUMN paused_at DATETIME');
221
- console.log('Added paused_at column to sessions table');
222
- }
223
-
224
- if (!hasResumedAt) {
225
- this.db.exec('ALTER TABLE sessions ADD COLUMN resumed_at DATETIME');
226
- console.log('Added resumed_at column to sessions table');
227
- }
228
-
229
- if (!hasCompletionPercentage) {
230
- this.db.exec('ALTER TABLE sessions ADD COLUMN completion_percentage REAL DEFAULT 0');
231
- console.log('Added completion_percentage column to sessions table');
232
- }
233
- } catch (error) {
234
- console.error('Migration error:', error);
124
+ /**
125
+ * Run database migrations
126
+ */ runMigrations() {
127
+ if (!this.db) {
128
+ console.error('Database not initialized for migrations');
129
+ return;
130
+ }
131
+ try {
132
+ // Check if required columns exist
133
+ const columns = this.db.prepare('PRAGMA table_info(sessions)').all();
134
+ // Core columns
135
+ const hasObjective = columns.some((col)=>col.name === 'objective');
136
+ const hasSwarmName = columns.some((col)=>col.name === 'swarm_name');
137
+ const hasCheckpointData = columns.some((col)=>col.name === 'checkpoint_data');
138
+ const hasMetadata = columns.some((col)=>col.name === 'metadata');
139
+ const hasParentPid = columns.some((col)=>col.name === 'parent_pid');
140
+ const hasChildPids = columns.some((col)=>col.name === 'child_pids');
141
+ // Timestamp columns
142
+ const hasUpdatedAt = columns.some((col)=>col.name === 'updated_at');
143
+ const hasPausedAt = columns.some((col)=>col.name === 'paused_at');
144
+ const hasResumedAt = columns.some((col)=>col.name === 'resumed_at');
145
+ const hasCompletionPercentage = columns.some((col)=>col.name === 'completion_percentage');
146
+ if (!hasObjective) {
147
+ this.db.exec('ALTER TABLE sessions ADD COLUMN objective TEXT');
148
+ console.log('Added objective column to sessions table');
149
+ }
150
+ if (!hasSwarmName) {
151
+ this.db.exec('ALTER TABLE sessions ADD COLUMN swarm_name TEXT');
152
+ console.log('Added swarm_name column to sessions table');
153
+ }
154
+ if (!hasCheckpointData) {
155
+ this.db.exec('ALTER TABLE sessions ADD COLUMN checkpoint_data TEXT');
156
+ console.log('Added checkpoint_data column to sessions table');
157
+ }
158
+ if (!hasMetadata) {
159
+ this.db.exec('ALTER TABLE sessions ADD COLUMN metadata TEXT');
160
+ console.log('Added metadata column to sessions table');
161
+ }
162
+ if (!hasParentPid) {
163
+ this.db.exec('ALTER TABLE sessions ADD COLUMN parent_pid INTEGER');
164
+ console.log('Added parent_pid column to sessions table');
165
+ }
166
+ if (!hasChildPids) {
167
+ this.db.exec('ALTER TABLE sessions ADD COLUMN child_pids TEXT');
168
+ console.log('Added child_pids column to sessions table');
169
+ }
170
+ if (!hasUpdatedAt) {
171
+ this.db.exec('ALTER TABLE sessions ADD COLUMN updated_at DATETIME DEFAULT CURRENT_TIMESTAMP');
172
+ console.log('Added updated_at column to sessions table');
173
+ }
174
+ if (!hasPausedAt) {
175
+ this.db.exec('ALTER TABLE sessions ADD COLUMN paused_at DATETIME');
176
+ console.log('Added paused_at column to sessions table');
177
+ }
178
+ if (!hasResumedAt) {
179
+ this.db.exec('ALTER TABLE sessions ADD COLUMN resumed_at DATETIME');
180
+ console.log('Added resumed_at column to sessions table');
181
+ }
182
+ if (!hasCompletionPercentage) {
183
+ this.db.exec('ALTER TABLE sessions ADD COLUMN completion_percentage REAL DEFAULT 0');
184
+ console.log('Added completion_percentage column to sessions table');
185
+ }
186
+ } catch (error) {
187
+ console.error('Migration error:', error);
188
+ }
235
189
  }
236
- }
237
-
238
- /**
190
+ /**
239
191
  * Create a new session for a swarm
240
- */
241
- async createSession(swarmId, swarmName, objective, metadata = {}) {
242
- await this.ensureInitialized();
243
-
244
- const sessionId = `session-${Date.now()}-${Math.random().toString(36).substring(2, 11)}`;
245
-
246
- if (this.isInMemory) {
247
- // Use in-memory storage
248
- const sessionData = {
249
- id: sessionId,
250
- swarm_id: swarmId,
251
- swarm_name: swarmName,
252
- objective,
253
- status: 'active',
254
- created_at: new Date().toISOString(),
255
- updated_at: new Date().toISOString(),
256
- metadata: sessionSerializer.serializeMetadata(metadata),
257
- parent_pid: process.pid,
258
- child_pids: '[]',
259
- };
260
- this.memoryStore.sessions.set(sessionId, sessionData);
261
- } else {
262
- // Use SQLite
263
- const stmt = this.db.prepare(`
192
+ */ async createSession(swarmId, swarmName, objective, metadata = {}) {
193
+ await this.ensureInitialized();
194
+ const sessionId = `session-${Date.now()}-${Math.random().toString(36).substring(2, 11)}`;
195
+ if (this.isInMemory) {
196
+ // Use in-memory storage
197
+ const sessionData = {
198
+ id: sessionId,
199
+ swarm_id: swarmId,
200
+ swarm_name: swarmName,
201
+ objective,
202
+ status: 'active',
203
+ created_at: new Date().toISOString(),
204
+ updated_at: new Date().toISOString(),
205
+ metadata: sessionSerializer.serializeMetadata(metadata),
206
+ parent_pid: process.pid,
207
+ child_pids: '[]'
208
+ };
209
+ this.memoryStore.sessions.set(sessionId, sessionData);
210
+ } else {
211
+ // Use SQLite
212
+ const stmt = this.db.prepare(`
264
213
  INSERT INTO sessions (id, swarm_id, swarm_name, objective, metadata, parent_pid)
265
214
  VALUES (?, ?, ?, ?, ?, ?)
266
215
  `);
267
-
268
- stmt.run(
269
- sessionId,
270
- swarmId,
271
- swarmName,
272
- objective,
273
- sessionSerializer.serializeMetadata(metadata),
274
- process.pid,
275
- );
276
- }
277
-
278
- // Log session creation
279
- await this.logSessionEvent(sessionId, 'info', 'Session created', null, {
280
- swarmId,
281
- swarmName,
282
- objective,
283
- parentPid: process.pid,
284
- });
285
-
286
- return sessionId;
287
- }
288
-
289
- /**
216
+ stmt.run(sessionId, swarmId, swarmName, objective, sessionSerializer.serializeMetadata(metadata), process.pid);
217
+ }
218
+ // Log session creation
219
+ await this.logSessionEvent(sessionId, 'info', 'Session created', null, {
220
+ swarmId,
221
+ swarmName,
222
+ objective,
223
+ parentPid: process.pid
224
+ });
225
+ return sessionId;
226
+ }
227
+ /**
290
228
  * Save session checkpoint
291
- */
292
- async saveCheckpoint(sessionId, checkpointName, checkpointData) {
293
- await this.ensureInitialized();
294
-
295
- const checkpointId = `checkpoint-${Date.now()}-${Math.random().toString(36).substring(2, 11)}`;
296
-
297
- if (this.isInMemory) {
298
- // Use in-memory storage
299
- const checkpointEntry = {
300
- id: checkpointId,
301
- session_id: sessionId,
302
- checkpoint_name: checkpointName,
303
- checkpoint_data: sessionSerializer.serializeCheckpointData(checkpointData),
304
- created_at: new Date().toISOString(),
305
- };
306
-
307
- if (!this.memoryStore.checkpoints.has(sessionId)) {
308
- this.memoryStore.checkpoints.set(sessionId, []);
309
- }
310
- this.memoryStore.checkpoints.get(sessionId).push(checkpointEntry);
311
-
312
- // Update session data
313
- const session = this.memoryStore.sessions.get(sessionId);
314
- if (session) {
315
- session.checkpoint_data = sessionSerializer.serializeCheckpointData(checkpointData);
316
- session.updated_at = new Date().toISOString();
317
- }
318
- } else {
319
- // Save to database
320
- const stmt = this.db.prepare(`
229
+ */ async saveCheckpoint(sessionId, checkpointName, checkpointData) {
230
+ await this.ensureInitialized();
231
+ const checkpointId = `checkpoint-${Date.now()}-${Math.random().toString(36).substring(2, 11)}`;
232
+ if (this.isInMemory) {
233
+ // Use in-memory storage
234
+ const checkpointEntry = {
235
+ id: checkpointId,
236
+ session_id: sessionId,
237
+ checkpoint_name: checkpointName,
238
+ checkpoint_data: sessionSerializer.serializeCheckpointData(checkpointData),
239
+ created_at: new Date().toISOString()
240
+ };
241
+ if (!this.memoryStore.checkpoints.has(sessionId)) {
242
+ this.memoryStore.checkpoints.set(sessionId, []);
243
+ }
244
+ this.memoryStore.checkpoints.get(sessionId).push(checkpointEntry);
245
+ // Update session data
246
+ const session = this.memoryStore.sessions.get(sessionId);
247
+ if (session) {
248
+ session.checkpoint_data = sessionSerializer.serializeCheckpointData(checkpointData);
249
+ session.updated_at = new Date().toISOString();
250
+ }
251
+ } else {
252
+ // Save to database
253
+ const stmt = this.db.prepare(`
321
254
  INSERT INTO session_checkpoints (id, session_id, checkpoint_name, checkpoint_data)
322
255
  VALUES (?, ?, ?, ?)
323
256
  `);
324
-
325
- stmt.run(
326
- checkpointId,
327
- sessionId,
328
- checkpointName,
329
- sessionSerializer.serializeCheckpointData(checkpointData),
330
- );
331
-
332
- // Update session checkpoint data and timestamp
333
- const updateStmt = this.db.prepare(`
257
+ stmt.run(checkpointId, sessionId, checkpointName, sessionSerializer.serializeCheckpointData(checkpointData));
258
+ // Update session checkpoint data and timestamp
259
+ const updateStmt = this.db.prepare(`
334
260
  UPDATE sessions
335
261
  SET checkpoint_data = ?, updated_at = CURRENT_TIMESTAMP
336
262
  WHERE id = ?
337
263
  `);
338
-
339
- updateStmt.run(sessionSerializer.serializeCheckpointData(checkpointData), sessionId);
340
- }
341
-
342
- // Save checkpoint file for backup
343
- const checkpointFile = path.join(this.sessionsDir, `${sessionId}-${checkpointName}.json`);
344
- await writeFile(
345
- checkpointFile,
346
- sessionSerializer.serializeSessionData({
347
- sessionId,
348
- checkpointId,
349
- checkpointName,
350
- timestamp: new Date().toISOString(),
351
- data: checkpointData,
352
- }),
353
- );
354
-
355
- await this.logSessionEvent(sessionId, 'info', `Checkpoint saved: ${checkpointName}`, null, {
356
- checkpointId,
357
- });
358
-
359
- return checkpointId;
360
- }
361
-
362
- /**
363
- * Get active sessions
364
- */
365
- async getActiveSessions() {
366
- await this.ensureInitialized();
367
-
368
- if (this.isInMemory) {
369
- // Use in-memory storage
370
- const sessions = [];
371
- for (const [sessionId, session] of this.memoryStore.sessions) {
372
- if (session.status === 'active' || session.status === 'paused') {
373
- sessions.push({
374
- ...session,
375
- metadata: session.metadata
376
- ? sessionSerializer.deserializeMetadata(session.metadata)
377
- : {},
378
- checkpoint_data: session.checkpoint_data
379
- ? sessionSerializer.deserializeCheckpointData(session.checkpoint_data)
380
- : null,
381
- agent_count: 0, // Not tracked in memory mode
382
- task_count: 0, // Not tracked in memory mode
383
- completed_tasks: 0, // Not tracked in memory mode
384
- completion_percentage: 0,
385
- });
264
+ updateStmt.run(sessionSerializer.serializeCheckpointData(checkpointData), sessionId);
386
265
  }
387
- }
388
- return sessions.sort((a, b) => new Date(b.updated_at) - new Date(a.updated_at));
389
- } else {
390
- // Use SQLite
391
- const stmt = this.db.prepare(`
266
+ // Save checkpoint file for backup
267
+ const checkpointFile = path.join(this.sessionsDir, `${sessionId}-${checkpointName}.json`);
268
+ await writeFile(checkpointFile, sessionSerializer.serializeSessionData({
269
+ sessionId,
270
+ checkpointId,
271
+ checkpointName,
272
+ timestamp: new Date().toISOString(),
273
+ data: checkpointData
274
+ }));
275
+ await this.logSessionEvent(sessionId, 'info', `Checkpoint saved: ${checkpointName}`, null, {
276
+ checkpointId
277
+ });
278
+ return checkpointId;
279
+ }
280
+ /**
281
+ * Get active sessions
282
+ */ async getActiveSessions() {
283
+ await this.ensureInitialized();
284
+ if (this.isInMemory) {
285
+ // Use in-memory storage
286
+ const sessions = [];
287
+ for (const [sessionId, session] of this.memoryStore.sessions){
288
+ if (session.status === 'active' || session.status === 'paused') {
289
+ sessions.push({
290
+ ...session,
291
+ metadata: session.metadata ? sessionSerializer.deserializeMetadata(session.metadata) : {},
292
+ checkpoint_data: session.checkpoint_data ? sessionSerializer.deserializeCheckpointData(session.checkpoint_data) : null,
293
+ agent_count: 0,
294
+ task_count: 0,
295
+ completed_tasks: 0,
296
+ completion_percentage: 0
297
+ });
298
+ }
299
+ }
300
+ return sessions.sort((a, b)=>new Date(b.updated_at) - new Date(a.updated_at));
301
+ } else {
302
+ // Use SQLite
303
+ const stmt = this.db.prepare(`
392
304
  SELECT s.*,
393
305
  COUNT(DISTINCT a.id) as agent_count,
394
306
  COUNT(DISTINCT t.id) as task_count,
@@ -400,824 +312,608 @@ To enable persistence, see: https://github.com/ruvnet/claude-code-flow/docs/wind
400
312
  GROUP BY s.id
401
313
  ORDER BY s.updated_at DESC
402
314
  `);
403
-
404
- const sessions = stmt.all();
405
-
406
- // Parse JSON fields
407
- return sessions.map((session) => ({
408
- ...session,
409
- metadata: session.metadata ? sessionSerializer.deserializeMetadata(session.metadata) : {},
410
- checkpoint_data: session.checkpoint_data
411
- ? sessionSerializer.deserializeCheckpointData(session.checkpoint_data)
412
- : null,
413
- completion_percentage:
414
- session.task_count > 0
415
- ? Math.round((session.completed_tasks / session.task_count) * 100)
416
- : 0,
417
- }));
315
+ const sessions = stmt.all();
316
+ // Parse JSON fields
317
+ return sessions.map((session)=>({
318
+ ...session,
319
+ metadata: session.metadata ? sessionSerializer.deserializeMetadata(session.metadata) : {},
320
+ checkpoint_data: session.checkpoint_data ? sessionSerializer.deserializeCheckpointData(session.checkpoint_data) : null,
321
+ completion_percentage: session.task_count > 0 ? Math.round(session.completed_tasks / session.task_count * 100) : 0
322
+ }));
323
+ }
418
324
  }
419
- }
420
-
421
- /**
325
+ /**
422
326
  * Get session by ID with full details
423
- */
424
- async getSession(sessionId) {
425
- await this.ensureInitialized();
426
-
427
- if (this.isInMemory) {
428
- // Use in-memory storage
429
- const session = this.memoryStore.sessions.get(sessionId);
430
- if (!session) {
431
- return null;
432
- }
433
-
434
- // Return simplified session data for in-memory mode
435
- return {
436
- ...session,
437
- metadata: session.metadata ? sessionSerializer.deserializeMetadata(session.metadata) : {},
438
- checkpoint_data: session.checkpoint_data
439
- ? sessionSerializer.deserializeCheckpointData(session.checkpoint_data)
440
- : null,
441
- swarm: null, // Not available in memory mode
442
- agents: [], // Not available in memory mode
443
- tasks: [], // Not available in memory mode
444
- checkpoints: this.memoryStore.checkpoints.get(sessionId) || [],
445
- recentLogs: this.memoryStore.logs.get(sessionId) || [],
446
- statistics: {
447
- totalAgents: 0,
448
- activeAgents: 0,
449
- totalTasks: 0,
450
- completedTasks: 0,
451
- pendingTasks: 0,
452
- inProgressTasks: 0,
453
- completionPercentage: session.completion_percentage || 0,
454
- },
455
- };
456
- }
457
-
458
- const session = this.db
459
- .prepare(
460
- `
327
+ */ async getSession(sessionId) {
328
+ await this.ensureInitialized();
329
+ if (this.isInMemory) {
330
+ // Use in-memory storage
331
+ const session = this.memoryStore.sessions.get(sessionId);
332
+ if (!session) {
333
+ return null;
334
+ }
335
+ // Return simplified session data for in-memory mode
336
+ return {
337
+ ...session,
338
+ metadata: session.metadata ? sessionSerializer.deserializeMetadata(session.metadata) : {},
339
+ checkpoint_data: session.checkpoint_data ? sessionSerializer.deserializeCheckpointData(session.checkpoint_data) : null,
340
+ swarm: null,
341
+ agents: [],
342
+ tasks: [],
343
+ checkpoints: this.memoryStore.checkpoints.get(sessionId) || [],
344
+ recentLogs: this.memoryStore.logs.get(sessionId) || [],
345
+ statistics: {
346
+ totalAgents: 0,
347
+ activeAgents: 0,
348
+ totalTasks: 0,
349
+ completedTasks: 0,
350
+ pendingTasks: 0,
351
+ inProgressTasks: 0,
352
+ completionPercentage: session.completion_percentage || 0
353
+ }
354
+ };
355
+ }
356
+ const session = this.db.prepare(`
461
357
  SELECT * FROM sessions WHERE id = ?
462
- `,
463
- )
464
- .get(sessionId);
465
-
466
- if (!session) {
467
- return null;
468
- }
469
-
470
- // Get associated swarm data
471
- const swarm = this.db
472
- .prepare(
473
- `
358
+ `).get(sessionId);
359
+ if (!session) {
360
+ return null;
361
+ }
362
+ // Get associated swarm data
363
+ const swarm = this.db.prepare(`
474
364
  SELECT * FROM swarms WHERE id = ?
475
- `,
476
- )
477
- .get(session.swarm_id);
478
-
479
- // Get agents
480
- const agents = this.db
481
- .prepare(
482
- `
365
+ `).get(session.swarm_id);
366
+ // Get agents
367
+ const agents = this.db.prepare(`
483
368
  SELECT * FROM agents WHERE swarm_id = ?
484
- `,
485
- )
486
- .all(session.swarm_id);
487
-
488
- // Get tasks
489
- const tasks = this.db
490
- .prepare(
491
- `
369
+ `).all(session.swarm_id);
370
+ // Get tasks
371
+ const tasks = this.db.prepare(`
492
372
  SELECT * FROM tasks WHERE swarm_id = ?
493
- `,
494
- )
495
- .all(session.swarm_id);
496
-
497
- // Get checkpoints
498
- const checkpoints = this.db
499
- .prepare(
500
- `
373
+ `).all(session.swarm_id);
374
+ // Get checkpoints
375
+ const checkpoints = this.db.prepare(`
501
376
  SELECT * FROM session_checkpoints
502
377
  WHERE session_id = ?
503
378
  ORDER BY created_at DESC
504
- `,
505
- )
506
- .all(sessionId);
507
-
508
- // Get recent logs
509
- const recentLogs = this.db
510
- .prepare(
511
- `
379
+ `).all(sessionId);
380
+ // Get recent logs
381
+ const recentLogs = this.db.prepare(`
512
382
  SELECT * FROM session_logs
513
383
  WHERE session_id = ?
514
384
  ORDER BY timestamp DESC
515
385
  LIMIT 50
516
- `,
517
- )
518
- .all(sessionId);
519
-
520
- return {
521
- ...session,
522
- metadata: session.metadata ? sessionSerializer.deserializeMetadata(session.metadata) : {},
523
- checkpoint_data: session.checkpoint_data
524
- ? sessionSerializer.deserializeCheckpointData(session.checkpoint_data)
525
- : null,
526
- swarm,
527
- agents,
528
- tasks,
529
- checkpoints: checkpoints.map((cp) => ({
530
- ...cp,
531
- checkpoint_data: sessionSerializer.deserializeCheckpointData(cp.checkpoint_data),
532
- })),
533
- recentLogs,
534
- statistics: {
535
- totalAgents: agents.length,
536
- activeAgents: agents.filter((a) => a.status === 'active' || a.status === 'busy').length,
537
- totalTasks: tasks.length,
538
- completedTasks: tasks.filter((t) => t.status === 'completed').length,
539
- pendingTasks: tasks.filter((t) => t.status === 'pending').length,
540
- inProgressTasks: tasks.filter((t) => t.status === 'in_progress').length,
541
- completionPercentage:
542
- tasks.length > 0
543
- ? Math.round(
544
- (tasks.filter((t) => t.status === 'completed').length / tasks.length) * 100,
545
- )
546
- : 0,
547
- },
548
- };
549
- }
550
-
551
- /**
386
+ `).all(sessionId);
387
+ return {
388
+ ...session,
389
+ metadata: session.metadata ? sessionSerializer.deserializeMetadata(session.metadata) : {},
390
+ checkpoint_data: session.checkpoint_data ? sessionSerializer.deserializeCheckpointData(session.checkpoint_data) : null,
391
+ swarm,
392
+ agents,
393
+ tasks,
394
+ checkpoints: checkpoints.map((cp)=>({
395
+ ...cp,
396
+ checkpoint_data: sessionSerializer.deserializeCheckpointData(cp.checkpoint_data)
397
+ })),
398
+ recentLogs,
399
+ statistics: {
400
+ totalAgents: agents.length,
401
+ activeAgents: agents.filter((a)=>a.status === 'active' || a.status === 'busy').length,
402
+ totalTasks: tasks.length,
403
+ completedTasks: tasks.filter((t)=>t.status === 'completed').length,
404
+ pendingTasks: tasks.filter((t)=>t.status === 'pending').length,
405
+ inProgressTasks: tasks.filter((t)=>t.status === 'in_progress').length,
406
+ completionPercentage: tasks.length > 0 ? Math.round(tasks.filter((t)=>t.status === 'completed').length / tasks.length * 100) : 0
407
+ }
408
+ };
409
+ }
410
+ /**
552
411
  * Pause a session
553
- */
554
- async pauseSession(sessionId) {
555
- await this.ensureInitialized();
556
-
557
- if (this.isInMemory) {
558
- // Use in-memory storage
559
- const session = this.memoryStore.sessions.get(sessionId);
560
- if (session) {
561
- session.status = 'paused';
562
- session.paused_at = new Date().toISOString();
563
- session.updated_at = new Date().toISOString();
564
-
565
- await this.logSessionEvent(sessionId, 'info', 'Session paused');
566
- return true;
567
- }
568
- return false;
569
- } else {
570
- // Use SQLite
571
- const stmt = this.db.prepare(`
412
+ */ async pauseSession(sessionId) {
413
+ await this.ensureInitialized();
414
+ if (this.isInMemory) {
415
+ // Use in-memory storage
416
+ const session = this.memoryStore.sessions.get(sessionId);
417
+ if (session) {
418
+ session.status = 'paused';
419
+ session.paused_at = new Date().toISOString();
420
+ session.updated_at = new Date().toISOString();
421
+ await this.logSessionEvent(sessionId, 'info', 'Session paused');
422
+ return true;
423
+ }
424
+ return false;
425
+ } else {
426
+ // Use SQLite
427
+ const stmt = this.db.prepare(`
572
428
  UPDATE sessions
573
429
  SET status = 'paused', paused_at = CURRENT_TIMESTAMP, updated_at = CURRENT_TIMESTAMP
574
430
  WHERE id = ?
575
431
  `);
576
-
577
- const result = stmt.run(sessionId);
578
-
579
- if (result.changes > 0) {
580
- await this.logSessionEvent(sessionId, 'info', 'Session paused');
581
-
582
- // Update swarm status
583
- const session = this.db
584
- .prepare('SELECT swarm_id FROM sessions WHERE id = ?')
585
- .get(sessionId);
586
- if (session) {
587
- this.db
588
- .prepare('UPDATE swarms SET status = ? WHERE id = ?')
589
- .run('paused', session.swarm_id);
432
+ const result = stmt.run(sessionId);
433
+ if (result.changes > 0) {
434
+ await this.logSessionEvent(sessionId, 'info', 'Session paused');
435
+ // Update swarm status
436
+ const session = this.db.prepare('SELECT swarm_id FROM sessions WHERE id = ?').get(sessionId);
437
+ if (session) {
438
+ this.db.prepare('UPDATE swarms SET status = ? WHERE id = ?').run('paused', session.swarm_id);
439
+ }
440
+ }
441
+ return result.changes > 0;
590
442
  }
591
- }
592
-
593
- return result.changes > 0;
594
443
  }
595
- }
596
-
597
- /**
444
+ /**
598
445
  * Resume any previous session (paused, stopped, or inactive)
599
- */
600
- async resumeSession(sessionId) {
601
- const session = await this.getSession(sessionId);
602
-
603
- if (!session) {
604
- throw new Error(`Session ${sessionId} not found`);
605
- }
606
-
607
- // Allow resuming any session regardless of status
608
- console.log(`Resuming session ${sessionId} from status: ${session.status}`);
609
-
610
- // If session was stopped, log that we're restarting it
611
- if (session.status === 'stopped') {
612
- await this.logSessionEvent(
613
- sessionId,
614
- 'info',
615
- `Restarting stopped session with original configuration`,
616
- );
617
- }
618
-
619
- // Update session status
620
- if (this.isInMemory) {
621
- // Use in-memory storage
622
- const sessionData = this.memoryStore.sessions.get(sessionId);
623
- if (sessionData) {
624
- sessionData.status = 'active';
625
- sessionData.resumed_at = new Date().toISOString();
626
- sessionData.updated_at = new Date().toISOString();
627
- }
628
- } else {
629
- // Use SQLite
630
- const stmt = this.db.prepare(`
446
+ */ async resumeSession(sessionId) {
447
+ const session = await this.getSession(sessionId);
448
+ if (!session) {
449
+ throw new Error(`Session ${sessionId} not found`);
450
+ }
451
+ // Allow resuming any session regardless of status
452
+ console.log(`Resuming session ${sessionId} from status: ${session.status}`);
453
+ // If session was stopped, log that we're restarting it
454
+ if (session.status === 'stopped') {
455
+ await this.logSessionEvent(sessionId, 'info', `Restarting stopped session with original configuration`);
456
+ }
457
+ // Update session status
458
+ if (this.isInMemory) {
459
+ // Use in-memory storage
460
+ const sessionData = this.memoryStore.sessions.get(sessionId);
461
+ if (sessionData) {
462
+ sessionData.status = 'active';
463
+ sessionData.resumed_at = new Date().toISOString();
464
+ sessionData.updated_at = new Date().toISOString();
465
+ }
466
+ } else {
467
+ // Use SQLite
468
+ const stmt = this.db.prepare(`
631
469
  UPDATE sessions
632
470
  SET status = 'active', resumed_at = CURRENT_TIMESTAMP, updated_at = CURRENT_TIMESTAMP
633
471
  WHERE id = ?
634
472
  `);
635
-
636
- stmt.run(sessionId);
637
-
638
- // Update swarm status
639
- this.db.prepare('UPDATE swarms SET status = ? WHERE id = ?').run('active', session.swarm_id);
640
-
641
- // Update agent statuses
642
- this.db
643
- .prepare(
644
- `
473
+ stmt.run(sessionId);
474
+ // Update swarm status
475
+ this.db.prepare('UPDATE swarms SET status = ? WHERE id = ?').run('active', session.swarm_id);
476
+ // Update agent statuses
477
+ this.db.prepare(`
645
478
  UPDATE agents
646
479
  SET status = CASE
647
480
  WHEN role = 'queen' THEN 'active'
648
481
  ELSE 'idle'
649
482
  END
650
483
  WHERE swarm_id = ?
651
- `,
652
- )
653
- .run(session.swarm_id);
484
+ `).run(session.swarm_id);
485
+ }
486
+ await this.logSessionEvent(sessionId, 'info', 'Session resumed', null, {
487
+ pausedDuration: session.paused_at ? new Date() - new Date(session.paused_at) : null
488
+ });
489
+ return session;
654
490
  }
655
-
656
- await this.logSessionEvent(sessionId, 'info', 'Session resumed', null, {
657
- pausedDuration: session.paused_at ? new Date() - new Date(session.paused_at) : null,
658
- });
659
-
660
- return session;
661
- }
662
-
663
- /**
491
+ /**
664
492
  * Mark session as completed
665
- */
666
- async completeSession(sessionId) {
667
- await this.ensureInitialized();
668
-
669
- if (this.isInMemory) {
670
- // Use in-memory storage
671
- const session = this.memoryStore.sessions.get(sessionId);
672
- if (session) {
673
- session.status = 'completed';
674
- session.updated_at = new Date().toISOString();
675
- session.completion_percentage = 100;
676
-
677
- await this.logSessionEvent(sessionId, 'info', 'Session completed');
678
- return true;
679
- }
680
- return false;
681
- } else {
682
- // Use SQLite
683
- const stmt = this.db.prepare(`
493
+ */ async completeSession(sessionId) {
494
+ await this.ensureInitialized();
495
+ if (this.isInMemory) {
496
+ // Use in-memory storage
497
+ const session = this.memoryStore.sessions.get(sessionId);
498
+ if (session) {
499
+ session.status = 'completed';
500
+ session.updated_at = new Date().toISOString();
501
+ session.completion_percentage = 100;
502
+ await this.logSessionEvent(sessionId, 'info', 'Session completed');
503
+ return true;
504
+ }
505
+ return false;
506
+ } else {
507
+ // Use SQLite
508
+ const stmt = this.db.prepare(`
684
509
  UPDATE sessions
685
510
  SET status = 'completed', updated_at = CURRENT_TIMESTAMP, completion_percentage = 100
686
511
  WHERE id = ?
687
512
  `);
688
-
689
- const result = stmt.run(sessionId);
690
-
691
- if (result.changes > 0) {
692
- await this.logSessionEvent(sessionId, 'info', 'Session completed');
693
-
694
- // Update swarm status
695
- const session = this.db
696
- .prepare('SELECT swarm_id FROM sessions WHERE id = ?')
697
- .get(sessionId);
698
- if (session) {
699
- this.db
700
- .prepare('UPDATE swarms SET status = ? WHERE id = ?')
701
- .run('completed', session.swarm_id);
513
+ const result = stmt.run(sessionId);
514
+ if (result.changes > 0) {
515
+ await this.logSessionEvent(sessionId, 'info', 'Session completed');
516
+ // Update swarm status
517
+ const session = this.db.prepare('SELECT swarm_id FROM sessions WHERE id = ?').get(sessionId);
518
+ if (session) {
519
+ this.db.prepare('UPDATE swarms SET status = ? WHERE id = ?').run('completed', session.swarm_id);
520
+ }
521
+ }
522
+ return result.changes > 0;
702
523
  }
703
- }
704
-
705
- return result.changes > 0;
706
524
  }
707
- }
708
-
709
- /**
525
+ /**
710
526
  * Archive old sessions
711
- */
712
- async archiveSessions(daysOld = 30) {
713
- await this.ensureInitialized();
714
-
715
- if (this.isInMemory) {
716
- // In-memory mode doesn't support archiving
717
- console.warn('Session archiving not supported in in-memory mode');
718
- return 0;
719
- }
720
-
721
- const cutoffDate = new Date();
722
- cutoffDate.setDate(cutoffDate.getDate() - daysOld);
723
-
724
- const sessionsToArchive = this.db
725
- .prepare(
726
- `
527
+ */ async archiveSessions(daysOld = 30) {
528
+ await this.ensureInitialized();
529
+ if (this.isInMemory) {
530
+ // In-memory mode doesn't support archiving
531
+ console.warn('Session archiving not supported in in-memory mode');
532
+ return 0;
533
+ }
534
+ const cutoffDate = new Date();
535
+ cutoffDate.setDate(cutoffDate.getDate() - daysOld);
536
+ const sessionsToArchive = this.db.prepare(`
727
537
  SELECT * FROM sessions
728
538
  WHERE status = 'completed' AND updated_at < ?
729
- `,
730
- )
731
- .all(cutoffDate.toISOString());
732
-
733
- const archiveDir = path.join(this.sessionsDir, 'archive');
734
- if (!existsSync(archiveDir)) {
735
- mkdirSync(archiveDir, { recursive: true });
736
- }
737
-
738
- for (const session of sessionsToArchive) {
739
- const sessionData = await this.getSession(session.id);
740
- const archiveFile = path.join(archiveDir, `${session.id}-archive.json`);
741
-
742
- await writeFile(archiveFile, sessionSerializer.serializeSessionData(sessionData));
743
-
744
- // Remove from database
745
- this.db.prepare('DELETE FROM session_logs WHERE session_id = ?').run(session.id);
746
- this.db.prepare('DELETE FROM session_checkpoints WHERE session_id = ?').run(session.id);
747
- this.db.prepare('DELETE FROM sessions WHERE id = ?').run(session.id);
539
+ `).all(cutoffDate.toISOString());
540
+ const archiveDir = path.join(this.sessionsDir, 'archive');
541
+ if (!existsSync(archiveDir)) {
542
+ mkdirSync(archiveDir, {
543
+ recursive: true
544
+ });
545
+ }
546
+ for (const session of sessionsToArchive){
547
+ const sessionData = await this.getSession(session.id);
548
+ const archiveFile = path.join(archiveDir, `${session.id}-archive.json`);
549
+ await writeFile(archiveFile, sessionSerializer.serializeSessionData(sessionData));
550
+ // Remove from database
551
+ this.db.prepare('DELETE FROM session_logs WHERE session_id = ?').run(session.id);
552
+ this.db.prepare('DELETE FROM session_checkpoints WHERE session_id = ?').run(session.id);
553
+ this.db.prepare('DELETE FROM sessions WHERE id = ?').run(session.id);
554
+ }
555
+ return sessionsToArchive.length;
748
556
  }
749
-
750
- return sessionsToArchive.length;
751
- }
752
-
753
- /**
557
+ /**
754
558
  * Log session event
755
- */
756
- async logSessionEvent(sessionId, logLevel, message, agentId = null, data = null) {
757
- await this.ensureInitialized();
758
-
759
- if (this.isInMemory) {
760
- // Use in-memory storage for logs
761
- const logId = `log-${Date.now()}-${Math.random().toString(36).substring(2, 11)}`;
762
- const logEntry = {
763
- id: logId,
764
- session_id: sessionId,
765
- timestamp: new Date().toISOString(),
766
- log_level: logLevel,
767
- message,
768
- agent_id: agentId,
769
- data: data ? sessionSerializer.serializeLogData(data) : null,
770
- };
771
-
772
- if (!this.memoryStore.logs.has(sessionId)) {
773
- this.memoryStore.logs.set(sessionId, []);
774
- }
775
- this.memoryStore.logs.get(sessionId).push(logEntry);
776
- } else {
777
- // Use SQLite
778
- const stmt = this.db.prepare(`
559
+ */ async logSessionEvent(sessionId, logLevel, message, agentId = null, data = null) {
560
+ await this.ensureInitialized();
561
+ if (this.isInMemory) {
562
+ // Use in-memory storage for logs
563
+ const logId = `log-${Date.now()}-${Math.random().toString(36).substring(2, 11)}`;
564
+ const logEntry = {
565
+ id: logId,
566
+ session_id: sessionId,
567
+ timestamp: new Date().toISOString(),
568
+ log_level: logLevel,
569
+ message,
570
+ agent_id: agentId,
571
+ data: data ? sessionSerializer.serializeLogData(data) : null
572
+ };
573
+ if (!this.memoryStore.logs.has(sessionId)) {
574
+ this.memoryStore.logs.set(sessionId, []);
575
+ }
576
+ this.memoryStore.logs.get(sessionId).push(logEntry);
577
+ } else {
578
+ // Use SQLite
579
+ const stmt = this.db.prepare(`
779
580
  INSERT INTO session_logs (session_id, log_level, message, agent_id, data)
780
581
  VALUES (?, ?, ?, ?, ?)
781
582
  `);
782
-
783
- stmt.run(
784
- sessionId,
785
- logLevel,
786
- message,
787
- agentId,
788
- data ? sessionSerializer.serializeLogData(data) : null,
789
- );
583
+ stmt.run(sessionId, logLevel, message, agentId, data ? sessionSerializer.serializeLogData(data) : null);
584
+ }
790
585
  }
791
- }
792
-
793
- /**
586
+ /**
794
587
  * Get session logs
795
- */
796
- async getSessionLogs(sessionId, limit = 100, offset = 0) {
797
- await this.ensureInitialized();
798
-
799
- if (this.isInMemory) {
800
- // Use in-memory storage
801
- const logs = this.memoryStore.logs.get(sessionId) || [];
802
- return logs.slice(offset, offset + limit).map((log) => ({
803
- ...log,
804
- data: log.data ? sessionSerializer.deserializeLogData(log.data) : null,
805
- }));
806
- }
807
-
808
- const stmt = this.db.prepare(`
588
+ */ async getSessionLogs(sessionId, limit = 100, offset = 0) {
589
+ await this.ensureInitialized();
590
+ if (this.isInMemory) {
591
+ // Use in-memory storage
592
+ const logs = this.memoryStore.logs.get(sessionId) || [];
593
+ return logs.slice(offset, offset + limit).map((log)=>({
594
+ ...log,
595
+ data: log.data ? sessionSerializer.deserializeLogData(log.data) : null
596
+ }));
597
+ }
598
+ const stmt = this.db.prepare(`
809
599
  SELECT * FROM session_logs
810
600
  WHERE session_id = ?
811
601
  ORDER BY timestamp DESC
812
602
  LIMIT ? OFFSET ?
813
603
  `);
814
-
815
- const logs = stmt.all(sessionId, limit, offset);
816
-
817
- return logs.map((log) => ({
818
- ...log,
819
- data: log.data ? sessionSerializer.deserializeLogData(log.data) : null,
820
- }));
821
- }
822
-
823
- /**
604
+ const logs = stmt.all(sessionId, limit, offset);
605
+ return logs.map((log)=>({
606
+ ...log,
607
+ data: log.data ? sessionSerializer.deserializeLogData(log.data) : null
608
+ }));
609
+ }
610
+ /**
824
611
  * Update session progress
825
- */
826
- async updateSessionProgress(sessionId, completionPercentage) {
827
- await this.ensureInitialized();
828
-
829
- if (this.isInMemory) {
830
- // Use in-memory storage
831
- const session = this.memoryStore.sessions.get(sessionId);
832
- if (session) {
833
- session.completion_percentage = completionPercentage;
834
- session.updated_at = new Date().toISOString();
835
- }
836
- } else {
837
- // Use SQLite
838
- const stmt = this.db.prepare(`
612
+ */ async updateSessionProgress(sessionId, completionPercentage) {
613
+ await this.ensureInitialized();
614
+ if (this.isInMemory) {
615
+ // Use in-memory storage
616
+ const session = this.memoryStore.sessions.get(sessionId);
617
+ if (session) {
618
+ session.completion_percentage = completionPercentage;
619
+ session.updated_at = new Date().toISOString();
620
+ }
621
+ } else {
622
+ // Use SQLite
623
+ const stmt = this.db.prepare(`
839
624
  UPDATE sessions
840
625
  SET completion_percentage = ?, updated_at = CURRENT_TIMESTAMP
841
626
  WHERE id = ?
842
627
  `);
843
-
844
- stmt.run(completionPercentage, sessionId);
628
+ stmt.run(completionPercentage, sessionId);
629
+ }
845
630
  }
846
- }
847
-
848
- /**
631
+ /**
849
632
  * Generate session summary
850
- */
851
- async generateSessionSummary(sessionId) {
852
- const session = await this.getSession(sessionId);
853
-
854
- if (!session) {
855
- return null;
856
- }
857
-
858
- const duration =
859
- session.paused_at && session.resumed_at
860
- ? new Date(session.updated_at) -
861
- new Date(session.created_at) -
862
- (new Date(session.resumed_at) - new Date(session.paused_at))
863
- : new Date(session.updated_at) - new Date(session.created_at);
864
-
865
- const tasksByType = session.agents.reduce((acc, agent) => {
866
- const agentTasks = session.tasks.filter((t) => t.agent_id === agent.id);
867
- if (!acc[agent.type]) {
868
- acc[agent.type] = {
869
- total: 0,
870
- completed: 0,
871
- inProgress: 0,
872
- pending: 0,
633
+ */ async generateSessionSummary(sessionId) {
634
+ const session = await this.getSession(sessionId);
635
+ if (!session) {
636
+ return null;
637
+ }
638
+ const duration = session.paused_at && session.resumed_at ? new Date(session.updated_at) - new Date(session.created_at) - (new Date(session.resumed_at) - new Date(session.paused_at)) : new Date(session.updated_at) - new Date(session.created_at);
639
+ const tasksByType = session.agents.reduce((acc, agent)=>{
640
+ const agentTasks = session.tasks.filter((t)=>t.agent_id === agent.id);
641
+ if (!acc[agent.type]) {
642
+ acc[agent.type] = {
643
+ total: 0,
644
+ completed: 0,
645
+ inProgress: 0,
646
+ pending: 0
647
+ };
648
+ }
649
+ acc[agent.type].total += agentTasks.length;
650
+ acc[agent.type].completed += agentTasks.filter((t)=>t.status === 'completed').length;
651
+ acc[agent.type].inProgress += agentTasks.filter((t)=>t.status === 'in_progress').length;
652
+ acc[agent.type].pending += agentTasks.filter((t)=>t.status === 'pending').length;
653
+ return acc;
654
+ }, {});
655
+ return {
656
+ sessionId: session.id,
657
+ swarmName: session.swarm_name,
658
+ objective: session.objective,
659
+ status: session.status,
660
+ duration: Math.round(duration / 1000 / 60),
661
+ statistics: session.statistics,
662
+ tasksByType,
663
+ checkpointCount: session.checkpoints.length,
664
+ lastCheckpoint: session.checkpoints[0] || null,
665
+ timeline: {
666
+ created: session.created_at,
667
+ lastUpdated: session.updated_at,
668
+ paused: session.paused_at,
669
+ resumed: session.resumed_at
670
+ }
873
671
  };
874
- }
875
- acc[agent.type].total += agentTasks.length;
876
- acc[agent.type].completed += agentTasks.filter((t) => t.status === 'completed').length;
877
- acc[agent.type].inProgress += agentTasks.filter((t) => t.status === 'in_progress').length;
878
- acc[agent.type].pending += agentTasks.filter((t) => t.status === 'pending').length;
879
- return acc;
880
- }, {});
881
-
882
- return {
883
- sessionId: session.id,
884
- swarmName: session.swarm_name,
885
- objective: session.objective,
886
- status: session.status,
887
- duration: Math.round(duration / 1000 / 60), // minutes
888
- statistics: session.statistics,
889
- tasksByType,
890
- checkpointCount: session.checkpoints.length,
891
- lastCheckpoint: session.checkpoints[0] || null,
892
- timeline: {
893
- created: session.created_at,
894
- lastUpdated: session.updated_at,
895
- paused: session.paused_at,
896
- resumed: session.resumed_at,
897
- },
898
- };
899
- }
900
-
901
- /**
672
+ }
673
+ /**
902
674
  * Export session data
903
- */
904
- async exportSession(sessionId, exportPath = null) {
905
- const session = await this.getSession(sessionId);
906
-
907
- if (!session) {
908
- throw new Error(`Session ${sessionId} not found`);
675
+ */ async exportSession(sessionId, exportPath = null) {
676
+ const session = await this.getSession(sessionId);
677
+ if (!session) {
678
+ throw new Error(`Session ${sessionId} not found`);
679
+ }
680
+ const exportFile = exportPath || path.join(this.sessionsDir, `${sessionId}-export.json`);
681
+ await writeFile(exportFile, sessionSerializer.serializeSessionData(session));
682
+ return exportFile;
909
683
  }
910
-
911
- const exportFile = exportPath || path.join(this.sessionsDir, `${sessionId}-export.json`);
912
-
913
- await writeFile(exportFile, sessionSerializer.serializeSessionData(session));
914
-
915
- return exportFile;
916
- }
917
-
918
- /**
684
+ /**
919
685
  * Import session data
920
- */
921
- async importSession(importPath) {
922
- const sessionData = sessionSerializer.deserializeSessionData(
923
- await readFile(importPath, 'utf8'),
924
- );
925
-
926
- // Create new session with imported data
927
- const newSessionId = this.createSession(
928
- sessionData.swarm_id,
929
- sessionData.swarm_name,
930
- sessionData.objective,
931
- sessionData.metadata,
932
- );
933
-
934
- // Import checkpoints
935
- for (const checkpoint of sessionData.checkpoints || []) {
936
- await this.saveCheckpoint(
937
- newSessionId,
938
- checkpoint.checkpoint_name,
939
- checkpoint.checkpoint_data,
940
- );
941
- }
942
-
943
- // Import logs
944
- for (const log of sessionData.recentLogs || []) {
945
- await this.logSessionEvent(
946
- newSessionId,
947
- log.log_level,
948
- log.message,
949
- log.agent_id,
950
- log.data ? sessionSerializer.deserializeLogData(log.data) : null,
951
- );
686
+ */ async importSession(importPath) {
687
+ const sessionData = sessionSerializer.deserializeSessionData(await readFile(importPath, 'utf8'));
688
+ // Create new session with imported data
689
+ const newSessionId = this.createSession(sessionData.swarm_id, sessionData.swarm_name, sessionData.objective, sessionData.metadata);
690
+ // Import checkpoints
691
+ for (const checkpoint of sessionData.checkpoints || []){
692
+ await this.saveCheckpoint(newSessionId, checkpoint.checkpoint_name, checkpoint.checkpoint_data);
693
+ }
694
+ // Import logs
695
+ for (const log of sessionData.recentLogs || []){
696
+ await this.logSessionEvent(newSessionId, log.log_level, log.message, log.agent_id, log.data ? sessionSerializer.deserializeLogData(log.data) : null);
697
+ }
698
+ return newSessionId;
952
699
  }
953
-
954
- return newSessionId;
955
- }
956
-
957
- /**
700
+ /**
958
701
  * Add a child process PID to session
959
- */
960
- async addChildPid(sessionId, pid) {
961
- await this.ensureInitialized();
962
-
963
- if (this.isInMemory) {
964
- // Use in-memory storage
965
- const session = this.memoryStore.sessions.get(sessionId);
966
- if (!session) return false;
967
-
968
- const childPids = session.child_pids
969
- ? sessionSerializer.deserializeLogData(session.child_pids)
970
- : [];
971
- if (!childPids.includes(pid)) {
972
- childPids.push(pid);
973
- }
974
- session.child_pids = sessionSerializer.serializeLogData(childPids);
975
- session.updated_at = new Date().toISOString();
976
-
977
- await this.logSessionEvent(sessionId, 'info', 'Child process added', null, { pid });
978
- return true;
979
- }
980
-
981
- const session = this.db.prepare('SELECT child_pids FROM sessions WHERE id = ?').get(sessionId);
982
- if (!session) return false;
983
-
984
- const childPids = session.child_pids
985
- ? sessionSerializer.deserializeLogData(session.child_pids)
986
- : [];
987
- if (!childPids.includes(pid)) {
988
- childPids.push(pid);
989
- }
990
-
991
- const stmt = this.db.prepare(`
702
+ */ async addChildPid(sessionId, pid) {
703
+ await this.ensureInitialized();
704
+ if (this.isInMemory) {
705
+ // Use in-memory storage
706
+ const session = this.memoryStore.sessions.get(sessionId);
707
+ if (!session) return false;
708
+ const childPids = session.child_pids ? sessionSerializer.deserializeLogData(session.child_pids) : [];
709
+ if (!childPids.includes(pid)) {
710
+ childPids.push(pid);
711
+ }
712
+ session.child_pids = sessionSerializer.serializeLogData(childPids);
713
+ session.updated_at = new Date().toISOString();
714
+ await this.logSessionEvent(sessionId, 'info', 'Child process added', null, {
715
+ pid
716
+ });
717
+ return true;
718
+ }
719
+ const session = this.db.prepare('SELECT child_pids FROM sessions WHERE id = ?').get(sessionId);
720
+ if (!session) return false;
721
+ const childPids = session.child_pids ? sessionSerializer.deserializeLogData(session.child_pids) : [];
722
+ if (!childPids.includes(pid)) {
723
+ childPids.push(pid);
724
+ }
725
+ const stmt = this.db.prepare(`
992
726
  UPDATE sessions
993
727
  SET child_pids = ?, updated_at = CURRENT_TIMESTAMP
994
728
  WHERE id = ?
995
729
  `);
996
-
997
- stmt.run(sessionSerializer.serializeLogData(childPids), sessionId);
998
-
999
- await this.logSessionEvent(sessionId, 'info', 'Child process added', null, { pid });
1000
- return true;
1001
- }
1002
-
1003
- /**
1004
- * Remove a child process PID from session
1005
- */
1006
- async removeChildPid(sessionId, pid) {
1007
- await this.ensureInitialized();
1008
-
1009
- if (this.isInMemory) {
1010
- // Use in-memory storage
1011
- const session = this.memoryStore.sessions.get(sessionId);
1012
- if (!session) return false;
1013
-
1014
- const childPids = session.child_pids
1015
- ? sessionSerializer.deserializeLogData(session.child_pids)
1016
- : [];
1017
- const index = childPids.indexOf(pid);
1018
- if (index > -1) {
1019
- childPids.splice(index, 1);
1020
- }
1021
- session.child_pids = sessionSerializer.serializeLogData(childPids);
1022
- session.updated_at = new Date().toISOString();
1023
-
1024
- await this.logSessionEvent(sessionId, 'info', 'Child process removed', null, { pid });
1025
- return true;
1026
- }
1027
-
1028
- // Check if database connection is still open before operations
1029
- if (!this.db || !this.db.open) {
1030
- console.warn('Database connection closed, cannot remove child PID during cleanup');
1031
- return false;
1032
- }
1033
-
1034
- const session = this.db.prepare('SELECT child_pids FROM sessions WHERE id = ?').get(sessionId);
1035
- if (!session) return false;
1036
-
1037
- const childPids = session.child_pids
1038
- ? sessionSerializer.deserializeLogData(session.child_pids)
1039
- : [];
1040
- const index = childPids.indexOf(pid);
1041
- if (index > -1) {
1042
- childPids.splice(index, 1);
730
+ stmt.run(sessionSerializer.serializeLogData(childPids), sessionId);
731
+ await this.logSessionEvent(sessionId, 'info', 'Child process added', null, {
732
+ pid
733
+ });
734
+ return true;
1043
735
  }
1044
-
1045
- const stmt = this.db.prepare(`
736
+ /**
737
+ * Remove a child process PID from session
738
+ */ async removeChildPid(sessionId, pid) {
739
+ await this.ensureInitialized();
740
+ if (this.isInMemory) {
741
+ // Use in-memory storage
742
+ const session = this.memoryStore.sessions.get(sessionId);
743
+ if (!session) return false;
744
+ const childPids = session.child_pids ? sessionSerializer.deserializeLogData(session.child_pids) : [];
745
+ const index = childPids.indexOf(pid);
746
+ if (index > -1) {
747
+ childPids.splice(index, 1);
748
+ }
749
+ session.child_pids = sessionSerializer.serializeLogData(childPids);
750
+ session.updated_at = new Date().toISOString();
751
+ await this.logSessionEvent(sessionId, 'info', 'Child process removed', null, {
752
+ pid
753
+ });
754
+ return true;
755
+ }
756
+ // Check if database connection is still open before operations
757
+ if (!this.db || !this.db.open) {
758
+ console.warn('Database connection closed, cannot remove child PID during cleanup');
759
+ return false;
760
+ }
761
+ const session = this.db.prepare('SELECT child_pids FROM sessions WHERE id = ?').get(sessionId);
762
+ if (!session) return false;
763
+ const childPids = session.child_pids ? sessionSerializer.deserializeLogData(session.child_pids) : [];
764
+ const index = childPids.indexOf(pid);
765
+ if (index > -1) {
766
+ childPids.splice(index, 1);
767
+ }
768
+ const stmt = this.db.prepare(`
1046
769
  UPDATE sessions
1047
770
  SET child_pids = ?, updated_at = CURRENT_TIMESTAMP
1048
771
  WHERE id = ?
1049
772
  `);
1050
-
1051
- stmt.run(sessionSerializer.serializeLogData(childPids), sessionId);
1052
-
1053
- await this.logSessionEvent(sessionId, 'info', 'Child process removed', null, { pid });
1054
- return true;
1055
- }
1056
-
1057
- /**
773
+ stmt.run(sessionSerializer.serializeLogData(childPids), sessionId);
774
+ await this.logSessionEvent(sessionId, 'info', 'Child process removed', null, {
775
+ pid
776
+ });
777
+ return true;
778
+ }
779
+ /**
1058
780
  * Get all child PIDs for a session
1059
- */
1060
- async getChildPids(sessionId) {
1061
- await this.ensureInitialized();
1062
-
1063
- if (this.isInMemory) {
1064
- // Use in-memory storage
1065
- const session = this.memoryStore.sessions.get(sessionId);
1066
- if (!session || !session.child_pids) return [];
1067
- return sessionSerializer.deserializeLogData(session.child_pids);
1068
- } else {
1069
- // Check if database connection is still open
1070
- if (!this.db || !this.db.open) {
1071
- console.warn('Database connection closed, cannot get child PIDs during cleanup');
1072
- return [];
1073
- }
1074
-
1075
- // Use SQLite
1076
- const session = this.db
1077
- .prepare('SELECT child_pids FROM sessions WHERE id = ?')
1078
- .get(sessionId);
1079
- if (!session || !session.child_pids) return [];
1080
- return sessionSerializer.deserializeLogData(session.child_pids);
781
+ */ async getChildPids(sessionId) {
782
+ await this.ensureInitialized();
783
+ if (this.isInMemory) {
784
+ // Use in-memory storage
785
+ const session = this.memoryStore.sessions.get(sessionId);
786
+ if (!session || !session.child_pids) return [];
787
+ return sessionSerializer.deserializeLogData(session.child_pids);
788
+ } else {
789
+ // Check if database connection is still open
790
+ if (!this.db || !this.db.open) {
791
+ console.warn('Database connection closed, cannot get child PIDs during cleanup');
792
+ return [];
793
+ }
794
+ // Use SQLite
795
+ const session = this.db.prepare('SELECT child_pids FROM sessions WHERE id = ?').get(sessionId);
796
+ if (!session || !session.child_pids) return [];
797
+ return sessionSerializer.deserializeLogData(session.child_pids);
798
+ }
1081
799
  }
1082
- }
1083
-
1084
- /**
800
+ /**
1085
801
  * Stop a session and terminate all child processes
1086
- */
1087
- async stopSession(sessionId) {
1088
- const session = await this.getSession(sessionId);
1089
- if (!session) {
1090
- throw new Error(`Session ${sessionId} not found`);
1091
- }
1092
-
1093
- // Get child PIDs
1094
- const childPids = await this.getChildPids(sessionId);
1095
-
1096
- // Terminate child processes
1097
- for (const pid of childPids) {
1098
- try {
1099
- process.kill(pid, 'SIGTERM');
1100
- await this.logSessionEvent(sessionId, 'info', 'Child process terminated', null, { pid });
1101
- } catch (err) {
1102
- // Process might already be dead
1103
- await this.logSessionEvent(
1104
- sessionId,
1105
- 'warning',
1106
- 'Failed to terminate child process',
1107
- null,
1108
- {
1109
- pid,
1110
- error: err.message,
1111
- },
1112
- );
1113
- }
1114
- }
1115
-
1116
- // Update session status
1117
- if (this.isInMemory) {
1118
- // Use in-memory storage
1119
- const sessionData = this.memoryStore.sessions.get(sessionId);
1120
- if (sessionData) {
1121
- sessionData.status = 'stopped';
1122
- sessionData.updated_at = new Date().toISOString();
1123
- }
1124
- } else {
1125
- // Use SQLite
1126
- const stmt = this.db.prepare(`
802
+ */ async stopSession(sessionId) {
803
+ const session = await this.getSession(sessionId);
804
+ if (!session) {
805
+ throw new Error(`Session ${sessionId} not found`);
806
+ }
807
+ // Get child PIDs
808
+ const childPids = await this.getChildPids(sessionId);
809
+ // Terminate child processes
810
+ for (const pid of childPids){
811
+ try {
812
+ process.kill(pid, 'SIGTERM');
813
+ await this.logSessionEvent(sessionId, 'info', 'Child process terminated', null, {
814
+ pid
815
+ });
816
+ } catch (err) {
817
+ // Process might already be dead
818
+ await this.logSessionEvent(sessionId, 'warning', 'Failed to terminate child process', null, {
819
+ pid,
820
+ error: err.message
821
+ });
822
+ }
823
+ }
824
+ // Update session status
825
+ if (this.isInMemory) {
826
+ // Use in-memory storage
827
+ const sessionData = this.memoryStore.sessions.get(sessionId);
828
+ if (sessionData) {
829
+ sessionData.status = 'stopped';
830
+ sessionData.updated_at = new Date().toISOString();
831
+ }
832
+ } else {
833
+ // Use SQLite
834
+ const stmt = this.db.prepare(`
1127
835
  UPDATE sessions
1128
836
  SET status = 'stopped', updated_at = CURRENT_TIMESTAMP
1129
837
  WHERE id = ?
1130
838
  `);
1131
-
1132
- stmt.run(sessionId);
1133
-
1134
- // Update swarm status
1135
- this.db.prepare('UPDATE swarms SET status = ? WHERE id = ?').run('stopped', session.swarm_id);
839
+ stmt.run(sessionId);
840
+ // Update swarm status
841
+ this.db.prepare('UPDATE swarms SET status = ? WHERE id = ?').run('stopped', session.swarm_id);
842
+ }
843
+ await this.logSessionEvent(sessionId, 'info', 'Session stopped');
844
+ return true;
1136
845
  }
1137
-
1138
- await this.logSessionEvent(sessionId, 'info', 'Session stopped');
1139
-
1140
- return true;
1141
- }
1142
-
1143
- /**
846
+ /**
1144
847
  * Get active sessions with process information
1145
- */
1146
- async getActiveSessionsWithProcessInfo() {
1147
- const sessions = await this.getActiveSessions();
1148
-
1149
- // Add process info to each session
1150
- return sessions.map((session) => {
1151
- const childPids = session.child_pids
1152
- ? sessionSerializer.deserializeLogData(session.child_pids)
1153
- : [];
1154
- const aliveChildPids = [];
1155
-
1156
- // Check which child processes are still alive
1157
- for (const pid of childPids) {
1158
- try {
1159
- process.kill(pid, 0); // Signal 0 just checks if process exists
1160
- aliveChildPids.push(pid);
1161
- } catch (err) {
1162
- // Process is dead
1163
- }
1164
- }
1165
-
1166
- return {
1167
- ...session,
1168
- parent_pid: session.parent_pid,
1169
- child_pids: aliveChildPids,
1170
- total_processes: 1 + aliveChildPids.length,
1171
- };
1172
- });
1173
- }
1174
-
1175
- /**
848
+ */ async getActiveSessionsWithProcessInfo() {
849
+ const sessions = await this.getActiveSessions();
850
+ // Add process info to each session
851
+ return sessions.map((session)=>{
852
+ const childPids = session.child_pids ? sessionSerializer.deserializeLogData(session.child_pids) : [];
853
+ const aliveChildPids = [];
854
+ // Check which child processes are still alive
855
+ for (const pid of childPids){
856
+ try {
857
+ process.kill(pid, 0); // Signal 0 just checks if process exists
858
+ aliveChildPids.push(pid);
859
+ } catch (err) {
860
+ // Process is dead
861
+ }
862
+ }
863
+ return {
864
+ ...session,
865
+ parent_pid: session.parent_pid,
866
+ child_pids: aliveChildPids,
867
+ total_processes: 1 + aliveChildPids.length
868
+ };
869
+ });
870
+ }
871
+ /**
1176
872
  * Clean up orphaned processes
1177
- */
1178
- async cleanupOrphanedProcesses() {
1179
- await this.ensureInitialized();
1180
-
1181
- if (this.isInMemory) {
1182
- // In-memory mode doesn't track orphaned processes
1183
- return 0;
1184
- }
1185
-
1186
- const sessions = this.db
1187
- .prepare(
1188
- `
873
+ */ async cleanupOrphanedProcesses() {
874
+ await this.ensureInitialized();
875
+ if (this.isInMemory) {
876
+ // In-memory mode doesn't track orphaned processes
877
+ return 0;
878
+ }
879
+ const sessions = this.db.prepare(`
1189
880
  SELECT * FROM sessions
1190
881
  WHERE status IN ('active', 'paused')
1191
- `,
1192
- )
1193
- .all();
1194
-
1195
- let cleanedCount = 0;
1196
-
1197
- for (const session of sessions) {
1198
- // Check if parent process is still alive
1199
- try {
1200
- process.kill(session.parent_pid, 0);
1201
- } catch (err) {
1202
- // Parent is dead, clean up session
1203
- await this.stopSession(session.id);
1204
- cleanedCount++;
1205
- await this.logSessionEvent(session.id, 'info', 'Orphaned session cleaned up');
1206
- }
882
+ `).all();
883
+ let cleanedCount = 0;
884
+ for (const session of sessions){
885
+ // Check if parent process is still alive
886
+ try {
887
+ process.kill(session.parent_pid, 0);
888
+ } catch (err) {
889
+ // Parent is dead, clean up session
890
+ await this.stopSession(session.id);
891
+ cleanedCount++;
892
+ await this.logSessionEvent(session.id, 'info', 'Orphaned session cleaned up');
893
+ }
894
+ }
895
+ return cleanedCount;
1207
896
  }
1208
-
1209
- return cleanedCount;
1210
- }
1211
-
1212
- /**
897
+ /**
1213
898
  * Clean up and close database connection
1214
- */
1215
- close() {
1216
- if (this.db && !this.isInMemory) {
1217
- this.db.close();
899
+ */ close() {
900
+ if (this.db && !this.isInMemory) {
901
+ this.db.close();
902
+ }
903
+ }
904
+ constructor(hiveMindDir = null){
905
+ this.hiveMindDir = hiveMindDir || path.join(cwd(), '.hive-mind');
906
+ this.sessionsDir = path.join(this.hiveMindDir, 'sessions');
907
+ this.dbPath = path.join(this.hiveMindDir, 'hive.db');
908
+ this.db = null;
909
+ this.isInMemory = false;
910
+ this.memoryStore = null;
911
+ this.initializationPromise = null;
912
+ // Ensure directories exist
913
+ this.ensureDirectories();
914
+ // Initialize database connection (store promise for later)
915
+ this.initializationPromise = this.initializeDatabase();
1218
916
  }
1219
- }
1220
917
  }
1221
-
1222
918
  // Export for use in other modules
1223
919
  export default HiveMindSessionManager;