claude-flow-novice 1.3.0 → 1.3.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (305) hide show
  1. package/.claude-flow-novice/preferences/generation.json +147 -0
  2. package/.claude-flow-novice/preferences/language-configs/javascript.json +51 -0
  3. package/.claude-flow-novice/preferences/language-configs/python.json +50 -0
  4. package/.claude-flow-novice/preferences/language-configs/rust.json +237 -0
  5. package/.claude-flow-novice/preferences/language-configs/typescript.json +54 -0
  6. package/.claude-flow-novice/preferences/project-local.json +91 -0
  7. package/.claude-flow-novice/preferences/resource-delegation.json +120 -0
  8. package/.claude-flow-novice/preferences/team-shared.json +195 -0
  9. package/.claude-flow-novice/preferences/user-global.json +247 -0
  10. package/.claude-flow-novice/templates/claude-md-templates/CLAUDE-JAVASCRIPT.md +769 -0
  11. package/.claude-flow-novice/templates/claude-md-templates/CLAUDE-PYTHON.md +1214 -0
  12. package/.claude-flow-novice/templates/claude-md-templates/CLAUDE-RUST.md +475 -0
  13. package/.claude-flow-novice/templates/claude-md-templates/CLAUDE-TYPESCRIPT.md +851 -0
  14. package/.claude-flow-novice/templates/claude-md-templates/README.md +263 -0
  15. package/CLAUDE.md +81 -0
  16. package/README-NPM.md +0 -0
  17. package/package.json +11 -7
  18. package/scripts/build/README.md +167 -0
  19. package/scripts/build/build-config.js +27 -0
  20. package/scripts/build/build-prompt-copier.sh +30 -0
  21. package/scripts/build/performance-monitor.js +869 -0
  22. package/scripts/build/prepare-publish.js +150 -0
  23. package/scripts/build/typescript-fixer.js +621 -0
  24. package/scripts/build/unified-builder.sh +428 -0
  25. package/scripts/build/update-bin-version.js +32 -0
  26. package/scripts/dev/README.md +264 -0
  27. package/scripts/dev/claude-flow-wrapper.sh +35 -0
  28. package/scripts/dev/claude-monitor.py +419 -0
  29. package/scripts/dev/claude-sparc.sh +562 -0
  30. package/scripts/dev/claude-wrapper.sh +17 -0
  31. package/scripts/dev/demo-phase3-compliance.js +172 -0
  32. package/scripts/dev/demo-task-system.ts +224 -0
  33. package/scripts/dev/deployment-validator.js +315 -0
  34. package/scripts/dev/spawn-claude-terminal.sh +32 -0
  35. package/scripts/dev/start-portal.sh +506 -0
  36. package/scripts/dev/start-web-ui.js +15 -0
  37. package/scripts/dev/stop-portal.sh +311 -0
  38. package/scripts/dev/validate-examples.ts +288 -0
  39. package/scripts/dev/validate-phase2.cjs +451 -0
  40. package/scripts/dev/validate-phase2.js +785 -0
  41. package/scripts/dev/validate-phase3.cjs +208 -0
  42. package/scripts/dev/validate-security-remediation.js +1 -0
  43. package/scripts/legacy/README.md +272 -0
  44. package/scripts/legacy/batch-fix-ts.sh +54 -0
  45. package/scripts/legacy/build-migration.sh +105 -0
  46. package/scripts/legacy/build-monitor.js +209 -0
  47. package/scripts/legacy/build-with-filter.sh +84 -0
  48. package/scripts/legacy/build-workaround.sh +71 -0
  49. package/scripts/legacy/fix-ts-advanced.js +358 -0
  50. package/scripts/legacy/fix-ts-final.sh +50 -0
  51. package/scripts/legacy/fix-ts-targeted.sh +49 -0
  52. package/scripts/legacy/fix-typescript-errors.js +305 -0
  53. package/scripts/legacy/force-build.sh +63 -0
  54. package/scripts/legacy/optimize-performance.js +400 -0
  55. package/scripts/legacy/performance-monitor.js +263 -0
  56. package/scripts/legacy/performance-monitoring.js +532 -0
  57. package/scripts/legacy/performance-test-runner.js +645 -0
  58. package/scripts/legacy/quick-fix-ts.js +281 -0
  59. package/scripts/legacy/safe-build.sh +63 -0
  60. package/scripts/migration/README.md +434 -0
  61. package/scripts/migration/install-arm64.js +78 -0
  62. package/scripts/migration/install.js +83 -0
  63. package/scripts/migration/migrate-hooks.js +173 -0
  64. package/scripts/migration/migration-examples.ts +318 -0
  65. package/scripts/optimization/build-optimizer.js +438 -0
  66. package/scripts/optimization/config-validator.js +761 -0
  67. package/scripts/optimization/test-optimization.js +432 -0
  68. package/scripts/optimization/unified-activation.js +839 -0
  69. package/scripts/performance/ACTIVATION_COMMANDS.md +292 -0
  70. package/scripts/performance/sqlite-enhanced-activation.sh +583 -0
  71. package/scripts/performance/test-enhanced-backend.sh +504 -0
  72. package/scripts/performance-test-runner.js +698 -0
  73. package/scripts/security/README.md +339 -0
  74. package/scripts/security/install-git-hooks.sh +132 -0
  75. package/scripts/security/ruv-swarm-safe.js +74 -0
  76. package/scripts/test/README.md +236 -0
  77. package/scripts/test/check-links.ts +274 -0
  78. package/scripts/test/check-performance-regression.ts +168 -0
  79. package/scripts/test/coverage-report.ts +692 -0
  80. package/scripts/test/generate-swarm-tests.js +633 -0
  81. package/scripts/test/integration-test-validation.cjs +253 -0
  82. package/scripts/test/load-test-swarm.js +576 -0
  83. package/scripts/test/run-phase3-compliance-tests.js +427 -0
  84. package/scripts/test/test-batch-tasks.ts +29 -0
  85. package/scripts/test/test-byzantine-resolution.js +246 -0
  86. package/scripts/test/test-claude-spawn-options.sh +63 -0
  87. package/scripts/test/test-cli-wizard.js +331 -0
  88. package/scripts/test/test-comprehensive.js +401 -0
  89. package/scripts/test/test-coordination-features.ts +238 -0
  90. package/scripts/test/test-fallback-systems.js +276 -0
  91. package/scripts/test/test-init-command.ts +302 -0
  92. package/scripts/test/test-mcp.ts +251 -0
  93. package/scripts/test/test-runner.ts +568 -0
  94. package/scripts/test/test-swarm-integration.sh +92 -0
  95. package/scripts/test/test-swarm.ts +142 -0
  96. package/scripts/test/validation-summary.ts +408 -0
  97. package/scripts/utils/README.md +261 -0
  98. package/scripts/utils/clean-build-artifacts.sh +94 -0
  99. package/scripts/utils/cleanup-root.sh +69 -0
  100. package/scripts/utils/fix-cliffy-imports.js +307 -0
  101. package/scripts/utils/fix-duplicate-imports.js +114 -0
  102. package/scripts/utils/fix-error-handling.cjs +70 -0
  103. package/scripts/utils/fix-import-paths.js +104 -0
  104. package/scripts/utils/fix-imports.js +116 -0
  105. package/scripts/utils/fix-shebang.js +78 -0
  106. package/scripts/utils/fix-test-modules.js +27 -0
  107. package/scripts/utils/fix-timezone-issue-246.js +200 -0
  108. package/scripts/utils/fix-ts-comprehensive.py +182 -0
  109. package/scripts/utils/fix-ts-targeted-batch.js +250 -0
  110. package/scripts/utils/remove-benchmark-conflicts.sh +140 -0
  111. package/scripts/utils/simple-test-fixer.js +190 -0
  112. package/scripts/utils/validate-metrics-structure.cjs +144 -0
  113. package/scripts/verify-mcp-server.js +86 -0
  114. package/src/cli/simple-commands/__tests__/agent.test.js +291 -0
  115. package/src/cli/simple-commands/__tests__/memory.test.js +8 -0
  116. package/src/cli/simple-commands/__tests__/swarm.test.js +371 -0
  117. package/src/cli/simple-commands/__tests__/task.test.js +8 -0
  118. package/src/cli/simple-commands/agent.js +216 -0
  119. package/src/cli/simple-commands/analysis.js +570 -0
  120. package/src/cli/simple-commands/automation-executor.js +1603 -0
  121. package/src/cli/simple-commands/automation.js +627 -0
  122. package/src/cli/simple-commands/batch-manager.js +338 -0
  123. package/src/cli/simple-commands/claude-telemetry.js +311 -0
  124. package/src/cli/simple-commands/claude-track.js +102 -0
  125. package/src/cli/simple-commands/concurrent-display.js +348 -0
  126. package/src/cli/simple-commands/config.js +319 -0
  127. package/src/cli/simple-commands/coordination.js +307 -0
  128. package/src/cli/simple-commands/enhanced-ui-views.js +654 -0
  129. package/src/cli/simple-commands/enhanced-webui-complete.js +1038 -0
  130. package/src/cli/simple-commands/fix-hook-variables.js +363 -0
  131. package/src/cli/simple-commands/github/gh-coordinator.js +605 -0
  132. package/src/cli/simple-commands/github/github-api.js +624 -0
  133. package/src/cli/simple-commands/github/init.js +543 -0
  134. package/src/cli/simple-commands/github.js +377 -0
  135. package/src/cli/simple-commands/goal.js +145 -0
  136. package/src/cli/simple-commands/hive-mind/auto-save-middleware.js +311 -0
  137. package/src/cli/simple-commands/hive-mind/communication.js +740 -0
  138. package/src/cli/simple-commands/hive-mind/core.js +1031 -0
  139. package/src/cli/simple-commands/hive-mind/db-optimizer.js +872 -0
  140. package/src/cli/simple-commands/hive-mind/mcp-wrapper.js +1364 -0
  141. package/src/cli/simple-commands/hive-mind/memory.js +1292 -0
  142. package/src/cli/simple-commands/hive-mind/performance-optimizer.js +618 -0
  143. package/src/cli/simple-commands/hive-mind/performance-test.js +373 -0
  144. package/src/cli/simple-commands/hive-mind/queen.js +809 -0
  145. package/src/cli/simple-commands/hive-mind/session-manager.js +1223 -0
  146. package/src/cli/simple-commands/hive-mind-optimize.js +361 -0
  147. package/src/cli/simple-commands/hive-mind-wizard.js +281 -0
  148. package/src/cli/simple-commands/hive-mind.js +3112 -0
  149. package/src/cli/simple-commands/hive.js +140 -0
  150. package/src/cli/simple-commands/hook-safety.js +671 -0
  151. package/src/cli/simple-commands/hooks.js +1268 -0
  152. package/src/cli/simple-commands/init/.claude/checkpoints/1756224542.json +7 -0
  153. package/src/cli/simple-commands/init/.claude/checkpoints/1756224544.json +8 -0
  154. package/src/cli/simple-commands/init/README.md +106 -0
  155. package/src/cli/simple-commands/init/VALIDATION_ROLLBACK.md +488 -0
  156. package/src/cli/simple-commands/init/agent-copier.js +347 -0
  157. package/src/cli/simple-commands/init/batch-init.js +663 -0
  158. package/src/cli/simple-commands/init/claude-commands/claude-flow-commands.js +438 -0
  159. package/src/cli/simple-commands/init/claude-commands/optimized-claude-flow-commands.js +876 -0
  160. package/src/cli/simple-commands/init/claude-commands/optimized-slash-commands.js +356 -0
  161. package/src/cli/simple-commands/init/claude-commands/optimized-sparc-commands.js +501 -0
  162. package/src/cli/simple-commands/init/claude-commands/slash-commands.js +57 -0
  163. package/src/cli/simple-commands/init/claude-commands/sparc-commands.js +296 -0
  164. package/src/cli/simple-commands/init/copy-revised-templates.js +175 -0
  165. package/src/cli/simple-commands/init/executable-wrapper.js +122 -0
  166. package/src/cli/simple-commands/init/gitignore-updater.js +137 -0
  167. package/src/cli/simple-commands/init/help.js +110 -0
  168. package/src/cli/simple-commands/init/hive-mind-init.js +749 -0
  169. package/src/cli/simple-commands/init/index.js +1953 -0
  170. package/src/cli/simple-commands/init/performance-monitor.js +344 -0
  171. package/src/cli/simple-commands/init/rollback/backup-manager.js +542 -0
  172. package/src/cli/simple-commands/init/rollback/index.js +399 -0
  173. package/src/cli/simple-commands/init/rollback/recovery-manager.js +778 -0
  174. package/src/cli/simple-commands/init/rollback/rollback-executor.js +521 -0
  175. package/src/cli/simple-commands/init/rollback/state-tracker.js +486 -0
  176. package/src/cli/simple-commands/init/sparc/roo-readme.js +61 -0
  177. package/src/cli/simple-commands/init/sparc/roomodes-config.js +102 -0
  178. package/src/cli/simple-commands/init/sparc/workflows.js +40 -0
  179. package/src/cli/simple-commands/init/sparc-structure.js +68 -0
  180. package/src/cli/simple-commands/init/template-copier.js +640 -0
  181. package/src/cli/simple-commands/init/templates/CLAUDE.md +1185 -0
  182. package/src/cli/simple-commands/init/templates/CLAUDE.md.optimized +265 -0
  183. package/src/cli/simple-commands/init/templates/claude-flow-universal +81 -0
  184. package/src/cli/simple-commands/init/templates/claude-flow.bat +18 -0
  185. package/src/cli/simple-commands/init/templates/claude-flow.ps1 +24 -0
  186. package/src/cli/simple-commands/init/templates/claude-md.js +1101 -0
  187. package/src/cli/simple-commands/init/templates/commands/analysis/bottleneck-detect.md +162 -0
  188. package/src/cli/simple-commands/init/templates/commands/automation/auto-agent.md +122 -0
  189. package/src/cli/simple-commands/init/templates/commands/coordination/swarm-init.md +85 -0
  190. package/src/cli/simple-commands/init/templates/commands/github/github-swarm.md +121 -0
  191. package/src/cli/simple-commands/init/templates/commands/helpers/standard-checkpoint-hooks.sh +179 -0
  192. package/src/cli/simple-commands/init/templates/commands/hooks/notification.md +113 -0
  193. package/src/cli/simple-commands/init/templates/commands/hooks/post-command.md +116 -0
  194. package/src/cli/simple-commands/init/templates/commands/hooks/post-edit.md +117 -0
  195. package/src/cli/simple-commands/init/templates/commands/hooks/post-task.md +112 -0
  196. package/src/cli/simple-commands/init/templates/commands/hooks/pre-command.md +113 -0
  197. package/src/cli/simple-commands/init/templates/commands/hooks/pre-edit.md +113 -0
  198. package/src/cli/simple-commands/init/templates/commands/hooks/pre-search.md +112 -0
  199. package/src/cli/simple-commands/init/templates/commands/hooks/pre-task.md +111 -0
  200. package/src/cli/simple-commands/init/templates/commands/hooks/session-end.md +118 -0
  201. package/src/cli/simple-commands/init/templates/commands/hooks/session-restore.md +118 -0
  202. package/src/cli/simple-commands/init/templates/commands/hooks/session-start.md +117 -0
  203. package/src/cli/simple-commands/init/templates/coordination-md.js +340 -0
  204. package/src/cli/simple-commands/init/templates/coordination.md +16 -0
  205. package/src/cli/simple-commands/init/templates/enhanced-templates.js +2347 -0
  206. package/src/cli/simple-commands/init/templates/github-safe-enhanced.js +331 -0
  207. package/src/cli/simple-commands/init/templates/github-safe.js +106 -0
  208. package/src/cli/simple-commands/init/templates/memory-bank-md.js +259 -0
  209. package/src/cli/simple-commands/init/templates/memory-bank.md +16 -0
  210. package/src/cli/simple-commands/init/templates/readme-files.js +72 -0
  211. package/src/cli/simple-commands/init/templates/safe-hook-patterns.js +430 -0
  212. package/src/cli/simple-commands/init/templates/settings.json +109 -0
  213. package/src/cli/simple-commands/init/templates/settings.json.enhanced +35 -0
  214. package/src/cli/simple-commands/init/templates/sparc-modes.js +1401 -0
  215. package/src/cli/simple-commands/init/templates/verification-claude-md.js +432 -0
  216. package/src/cli/simple-commands/init/validation/config-validator.js +354 -0
  217. package/src/cli/simple-commands/init/validation/health-checker.js +599 -0
  218. package/src/cli/simple-commands/init/validation/index.js +388 -0
  219. package/src/cli/simple-commands/init/validation/mode-validator.js +387 -0
  220. package/src/cli/simple-commands/init/validation/post-init-validator.js +390 -0
  221. package/src/cli/simple-commands/init/validation/pre-init-validator.js +290 -0
  222. package/src/cli/simple-commands/init/validation/test-runner.js +488 -0
  223. package/src/cli/simple-commands/init.js +4 -0
  224. package/src/cli/simple-commands/mcp-health.js +163 -0
  225. package/src/cli/simple-commands/mcp-integration-layer.js +689 -0
  226. package/src/cli/simple-commands/mcp.js +420 -0
  227. package/src/cli/simple-commands/memory-consolidation.js +631 -0
  228. package/src/cli/simple-commands/memory.js +345 -0
  229. package/src/cli/simple-commands/migrate-hooks.js +63 -0
  230. package/src/cli/simple-commands/monitor.js +417 -0
  231. package/src/cli/simple-commands/neural.js +148 -0
  232. package/src/cli/simple-commands/pair-autofix-only.js +755 -0
  233. package/src/cli/simple-commands/pair-basic.js +751 -0
  234. package/src/cli/simple-commands/pair-old.js +623 -0
  235. package/src/cli/simple-commands/pair-working.js +849 -0
  236. package/src/cli/simple-commands/pair.js +849 -0
  237. package/src/cli/simple-commands/performance-hooks.js +149 -0
  238. package/src/cli/simple-commands/performance-metrics.js +601 -0
  239. package/src/cli/simple-commands/process-ui-enhanced.js +821 -0
  240. package/src/cli/simple-commands/process-ui.js +274 -0
  241. package/src/cli/simple-commands/realtime-update-system.js +659 -0
  242. package/src/cli/simple-commands/sparc/architecture.js +1750 -0
  243. package/src/cli/simple-commands/sparc/commands.js +575 -0
  244. package/src/cli/simple-commands/sparc/completion.js +1831 -0
  245. package/src/cli/simple-commands/sparc/coordinator.js +1045 -0
  246. package/src/cli/simple-commands/sparc/index.js +321 -0
  247. package/src/cli/simple-commands/sparc/phase-base.js +430 -0
  248. package/src/cli/simple-commands/sparc/pseudocode.js +984 -0
  249. package/src/cli/simple-commands/sparc/refinement.js +1856 -0
  250. package/src/cli/simple-commands/sparc/specification.js +736 -0
  251. package/src/cli/simple-commands/sparc-modes/architect.js +125 -0
  252. package/src/cli/simple-commands/sparc-modes/ask.js +126 -0
  253. package/src/cli/simple-commands/sparc-modes/code.js +148 -0
  254. package/src/cli/simple-commands/sparc-modes/debug.js +112 -0
  255. package/src/cli/simple-commands/sparc-modes/devops.js +137 -0
  256. package/src/cli/simple-commands/sparc-modes/docs-writer.js +38 -0
  257. package/src/cli/simple-commands/sparc-modes/generic.js +34 -0
  258. package/src/cli/simple-commands/sparc-modes/index.js +201 -0
  259. package/src/cli/simple-commands/sparc-modes/integration.js +55 -0
  260. package/src/cli/simple-commands/sparc-modes/mcp.js +38 -0
  261. package/src/cli/simple-commands/sparc-modes/monitoring.js +38 -0
  262. package/src/cli/simple-commands/sparc-modes/optimization.js +38 -0
  263. package/src/cli/simple-commands/sparc-modes/security-review.js +130 -0
  264. package/src/cli/simple-commands/sparc-modes/sparc-orchestrator.js +167 -0
  265. package/src/cli/simple-commands/sparc-modes/spec-pseudocode.js +38 -0
  266. package/src/cli/simple-commands/sparc-modes/supabase-admin.js +149 -0
  267. package/src/cli/simple-commands/sparc-modes/swarm.js +436 -0
  268. package/src/cli/simple-commands/sparc-modes/tdd.js +112 -0
  269. package/src/cli/simple-commands/sparc-modes/tutorial.js +277 -0
  270. package/src/cli/simple-commands/sparc.js +530 -0
  271. package/src/cli/simple-commands/start-ui.js +147 -0
  272. package/src/cli/simple-commands/start-wrapper.js +285 -0
  273. package/src/cli/simple-commands/start.js +2 -0
  274. package/src/cli/simple-commands/status.js +303 -0
  275. package/src/cli/simple-commands/stream-chain-clean.js +221 -0
  276. package/src/cli/simple-commands/stream-chain-fixed.js +89 -0
  277. package/src/cli/simple-commands/stream-chain-real.js +408 -0
  278. package/src/cli/simple-commands/stream-chain-working.js +323 -0
  279. package/src/cli/simple-commands/stream-chain.js +491 -0
  280. package/src/cli/simple-commands/stream-processor.js +340 -0
  281. package/src/cli/simple-commands/swarm-executor.js +253 -0
  282. package/src/cli/simple-commands/swarm-metrics-integration.js +371 -0
  283. package/src/cli/simple-commands/swarm-ui.js +741 -0
  284. package/src/cli/simple-commands/swarm-webui-integration.js +311 -0
  285. package/src/cli/simple-commands/swarm.js +2277 -0
  286. package/src/cli/simple-commands/task.js +228 -0
  287. package/src/cli/simple-commands/templates/mle-star-workflow.json +294 -0
  288. package/src/cli/simple-commands/timestamp-fix.js +104 -0
  289. package/src/cli/simple-commands/token-tracker.js +372 -0
  290. package/src/cli/simple-commands/tool-execution-framework.js +555 -0
  291. package/src/cli/simple-commands/train-and-stream.js +354 -0
  292. package/src/cli/simple-commands/training-pipeline.js +874 -0
  293. package/src/cli/simple-commands/training.js +288 -0
  294. package/src/cli/simple-commands/verification-hooks.js +336 -0
  295. package/src/cli/simple-commands/verification-integration.js +464 -0
  296. package/src/cli/simple-commands/verification-training-integration.js +646 -0
  297. package/src/cli/simple-commands/verification.js +551 -0
  298. package/src/cli/simple-commands/web-server.js +929 -0
  299. package/src/cli/simple-commands/webui-validator.js +136 -0
  300. package/src/language/README.md +503 -0
  301. package/src/language/claude-md-generator.js +618 -0
  302. package/src/language/cli.js +422 -0
  303. package/src/language/example.js +347 -0
  304. package/src/language/integration-system.js +619 -0
  305. package/src/language/language-detector.js +581 -0
@@ -0,0 +1,1223 @@
1
+ /**
2
+ * Hive Mind Session Manager
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
+
15
+ 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
+ /**
33
+ * 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();
55
+ }
56
+ }
57
+
58
+ /**
59
+ * 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();
69
+ }
70
+ }
71
+
72
+ /**
73
+ * 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(`
85
+ Note: Session data will not persist between runs on Windows without SQLite.
86
+ To enable persistence, see: https://github.com/ruvnet/claude-code-flow/docs/windows-installation.md
87
+ `);
88
+ }
89
+ }
90
+
91
+ /**
92
+ * 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 });
100
+ }
101
+ }
102
+
103
+ /**
104
+ * 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(`
113
+ CREATE TABLE IF NOT EXISTS sessions (
114
+ id TEXT PRIMARY KEY,
115
+ swarm_id TEXT NOT NULL,
116
+ swarm_name TEXT NOT NULL,
117
+ objective TEXT,
118
+ status TEXT DEFAULT 'active',
119
+ created_at DATETIME DEFAULT CURRENT_TIMESTAMP,
120
+ updated_at DATETIME DEFAULT CURRENT_TIMESTAMP,
121
+ paused_at DATETIME,
122
+ resumed_at DATETIME,
123
+ completion_percentage REAL DEFAULT 0,
124
+ checkpoint_data TEXT,
125
+ metadata TEXT,
126
+ parent_pid INTEGER,
127
+ child_pids TEXT,
128
+ FOREIGN KEY (swarm_id) REFERENCES swarms(id)
129
+ );
130
+
131
+ CREATE TABLE IF NOT EXISTS session_checkpoints (
132
+ id TEXT PRIMARY KEY,
133
+ session_id TEXT NOT NULL,
134
+ checkpoint_name TEXT NOT NULL,
135
+ checkpoint_data TEXT,
136
+ created_at DATETIME DEFAULT CURRENT_TIMESTAMP,
137
+ FOREIGN KEY (session_id) REFERENCES sessions(id)
138
+ );
139
+
140
+ CREATE TABLE IF NOT EXISTS session_logs (
141
+ id INTEGER PRIMARY KEY AUTOINCREMENT,
142
+ session_id TEXT NOT NULL,
143
+ timestamp DATETIME DEFAULT CURRENT_TIMESTAMP,
144
+ log_level TEXT DEFAULT 'info',
145
+ message TEXT,
146
+ agent_id TEXT,
147
+ data TEXT,
148
+ FOREIGN KEY (session_id) REFERENCES sessions(id)
149
+ );
150
+ `);
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;
163
+ }
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);
235
+ }
236
+ }
237
+
238
+ /**
239
+ * 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(`
264
+ INSERT INTO sessions (id, swarm_id, swarm_name, objective, metadata, parent_pid)
265
+ VALUES (?, ?, ?, ?, ?, ?)
266
+ `);
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
+ /**
290
+ * 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(`
321
+ INSERT INTO session_checkpoints (id, session_id, checkpoint_name, checkpoint_data)
322
+ VALUES (?, ?, ?, ?)
323
+ `);
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(`
334
+ UPDATE sessions
335
+ SET checkpoint_data = ?, updated_at = CURRENT_TIMESTAMP
336
+ WHERE id = ?
337
+ `);
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
+ });
386
+ }
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(`
392
+ SELECT s.*,
393
+ COUNT(DISTINCT a.id) as agent_count,
394
+ COUNT(DISTINCT t.id) as task_count,
395
+ SUM(CASE WHEN t.status = 'completed' THEN 1 ELSE 0 END) as completed_tasks
396
+ FROM sessions s
397
+ LEFT JOIN agents a ON s.swarm_id = a.swarm_id
398
+ LEFT JOIN tasks t ON s.swarm_id = t.swarm_id
399
+ WHERE s.status = 'active' OR s.status = 'paused'
400
+ GROUP BY s.id
401
+ ORDER BY s.updated_at DESC
402
+ `);
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
+ }));
418
+ }
419
+ }
420
+
421
+ /**
422
+ * 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
+ `
461
+ 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
+ `
474
+ SELECT * FROM swarms WHERE id = ?
475
+ `,
476
+ )
477
+ .get(session.swarm_id);
478
+
479
+ // Get agents
480
+ const agents = this.db
481
+ .prepare(
482
+ `
483
+ 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
+ `
492
+ 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
+ `
501
+ SELECT * FROM session_checkpoints
502
+ WHERE session_id = ?
503
+ ORDER BY created_at DESC
504
+ `,
505
+ )
506
+ .all(sessionId);
507
+
508
+ // Get recent logs
509
+ const recentLogs = this.db
510
+ .prepare(
511
+ `
512
+ SELECT * FROM session_logs
513
+ WHERE session_id = ?
514
+ ORDER BY timestamp DESC
515
+ 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
+ /**
552
+ * 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(`
572
+ UPDATE sessions
573
+ SET status = 'paused', paused_at = CURRENT_TIMESTAMP, updated_at = CURRENT_TIMESTAMP
574
+ WHERE id = ?
575
+ `);
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);
590
+ }
591
+ }
592
+
593
+ return result.changes > 0;
594
+ }
595
+ }
596
+
597
+ /**
598
+ * 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(`
631
+ UPDATE sessions
632
+ SET status = 'active', resumed_at = CURRENT_TIMESTAMP, updated_at = CURRENT_TIMESTAMP
633
+ WHERE id = ?
634
+ `);
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
+ `
645
+ UPDATE agents
646
+ SET status = CASE
647
+ WHEN role = 'queen' THEN 'active'
648
+ ELSE 'idle'
649
+ END
650
+ WHERE swarm_id = ?
651
+ `,
652
+ )
653
+ .run(session.swarm_id);
654
+ }
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
+ /**
664
+ * 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(`
684
+ UPDATE sessions
685
+ SET status = 'completed', updated_at = CURRENT_TIMESTAMP, completion_percentage = 100
686
+ WHERE id = ?
687
+ `);
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);
702
+ }
703
+ }
704
+
705
+ return result.changes > 0;
706
+ }
707
+ }
708
+
709
+ /**
710
+ * 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
+ `
727
+ SELECT * FROM sessions
728
+ 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);
748
+ }
749
+
750
+ return sessionsToArchive.length;
751
+ }
752
+
753
+ /**
754
+ * 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(`
779
+ INSERT INTO session_logs (session_id, log_level, message, agent_id, data)
780
+ VALUES (?, ?, ?, ?, ?)
781
+ `);
782
+
783
+ stmt.run(
784
+ sessionId,
785
+ logLevel,
786
+ message,
787
+ agentId,
788
+ data ? sessionSerializer.serializeLogData(data) : null,
789
+ );
790
+ }
791
+ }
792
+
793
+ /**
794
+ * 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(`
809
+ SELECT * FROM session_logs
810
+ WHERE session_id = ?
811
+ ORDER BY timestamp DESC
812
+ LIMIT ? OFFSET ?
813
+ `);
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
+ /**
824
+ * 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(`
839
+ UPDATE sessions
840
+ SET completion_percentage = ?, updated_at = CURRENT_TIMESTAMP
841
+ WHERE id = ?
842
+ `);
843
+
844
+ stmt.run(completionPercentage, sessionId);
845
+ }
846
+ }
847
+
848
+ /**
849
+ * 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,
873
+ };
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
+ /**
902
+ * 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`);
909
+ }
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
+ /**
919
+ * 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
+ );
952
+ }
953
+
954
+ return newSessionId;
955
+ }
956
+
957
+ /**
958
+ * 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(`
992
+ UPDATE sessions
993
+ SET child_pids = ?, updated_at = CURRENT_TIMESTAMP
994
+ WHERE id = ?
995
+ `);
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);
1043
+ }
1044
+
1045
+ const stmt = this.db.prepare(`
1046
+ UPDATE sessions
1047
+ SET child_pids = ?, updated_at = CURRENT_TIMESTAMP
1048
+ WHERE id = ?
1049
+ `);
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
+ /**
1058
+ * 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);
1081
+ }
1082
+ }
1083
+
1084
+ /**
1085
+ * 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(`
1127
+ UPDATE sessions
1128
+ SET status = 'stopped', updated_at = CURRENT_TIMESTAMP
1129
+ WHERE id = ?
1130
+ `);
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);
1136
+ }
1137
+
1138
+ await this.logSessionEvent(sessionId, 'info', 'Session stopped');
1139
+
1140
+ return true;
1141
+ }
1142
+
1143
+ /**
1144
+ * 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
+ /**
1176
+ * 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
+ `
1189
+ SELECT * FROM sessions
1190
+ 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
+ }
1207
+ }
1208
+
1209
+ return cleanedCount;
1210
+ }
1211
+
1212
+ /**
1213
+ * Clean up and close database connection
1214
+ */
1215
+ close() {
1216
+ if (this.db && !this.isInMemory) {
1217
+ this.db.close();
1218
+ }
1219
+ }
1220
+ }
1221
+
1222
+ // Export for use in other modules
1223
+ export default HiveMindSessionManager;