genesis-ai-cli 7.4.5

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 (227) hide show
  1. package/.env.example +78 -0
  2. package/README.md +282 -0
  3. package/dist/src/active-inference/actions.d.ts +75 -0
  4. package/dist/src/active-inference/actions.js +250 -0
  5. package/dist/src/active-inference/autonomous-loop.d.ts +103 -0
  6. package/dist/src/active-inference/autonomous-loop.js +289 -0
  7. package/dist/src/active-inference/core.d.ts +85 -0
  8. package/dist/src/active-inference/core.js +555 -0
  9. package/dist/src/active-inference/demo-autonomous-loop.d.ts +8 -0
  10. package/dist/src/active-inference/demo-autonomous-loop.js +338 -0
  11. package/dist/src/active-inference/demo-value-integration.d.ts +8 -0
  12. package/dist/src/active-inference/demo-value-integration.js +174 -0
  13. package/dist/src/active-inference/index.d.ts +32 -0
  14. package/dist/src/active-inference/index.js +88 -0
  15. package/dist/src/active-inference/integration.d.ts +114 -0
  16. package/dist/src/active-inference/integration.js +698 -0
  17. package/dist/src/active-inference/memory-integration.d.ts +51 -0
  18. package/dist/src/active-inference/memory-integration.js +232 -0
  19. package/dist/src/active-inference/observations.d.ts +67 -0
  20. package/dist/src/active-inference/observations.js +147 -0
  21. package/dist/src/active-inference/test-active-inference.d.ts +8 -0
  22. package/dist/src/active-inference/test-active-inference.js +320 -0
  23. package/dist/src/active-inference/test-value-integration.d.ts +6 -0
  24. package/dist/src/active-inference/test-value-integration.js +168 -0
  25. package/dist/src/active-inference/types.d.ts +150 -0
  26. package/dist/src/active-inference/types.js +59 -0
  27. package/dist/src/active-inference/value-integration.d.ts +164 -0
  28. package/dist/src/active-inference/value-integration.js +459 -0
  29. package/dist/src/agents/base-agent.d.ts +53 -0
  30. package/dist/src/agents/base-agent.js +178 -0
  31. package/dist/src/agents/builder.d.ts +67 -0
  32. package/dist/src/agents/builder.js +537 -0
  33. package/dist/src/agents/critic.d.ts +35 -0
  34. package/dist/src/agents/critic.js +322 -0
  35. package/dist/src/agents/ethicist.d.ts +54 -0
  36. package/dist/src/agents/ethicist.js +393 -0
  37. package/dist/src/agents/explorer.d.ts +26 -0
  38. package/dist/src/agents/explorer.js +216 -0
  39. package/dist/src/agents/feeling.d.ts +41 -0
  40. package/dist/src/agents/feeling.js +320 -0
  41. package/dist/src/agents/index.d.ts +111 -0
  42. package/dist/src/agents/index.js +222 -0
  43. package/dist/src/agents/memory.d.ts +69 -0
  44. package/dist/src/agents/memory.js +404 -0
  45. package/dist/src/agents/message-bus.d.ts +88 -0
  46. package/dist/src/agents/message-bus.js +267 -0
  47. package/dist/src/agents/narrator.d.ts +90 -0
  48. package/dist/src/agents/narrator.js +473 -0
  49. package/dist/src/agents/planner.d.ts +38 -0
  50. package/dist/src/agents/planner.js +341 -0
  51. package/dist/src/agents/predictor.d.ts +73 -0
  52. package/dist/src/agents/predictor.js +506 -0
  53. package/dist/src/agents/sensor.d.ts +88 -0
  54. package/dist/src/agents/sensor.js +377 -0
  55. package/dist/src/agents/test-agents.d.ts +6 -0
  56. package/dist/src/agents/test-agents.js +73 -0
  57. package/dist/src/agents/types.d.ts +194 -0
  58. package/dist/src/agents/types.js +7 -0
  59. package/dist/src/brain/index.d.ts +185 -0
  60. package/dist/src/brain/index.js +843 -0
  61. package/dist/src/brain/trace.d.ts +91 -0
  62. package/dist/src/brain/trace.js +327 -0
  63. package/dist/src/brain/types.d.ts +165 -0
  64. package/dist/src/brain/types.js +51 -0
  65. package/dist/src/cli/chat.d.ts +237 -0
  66. package/dist/src/cli/chat.js +1959 -0
  67. package/dist/src/cli/dispatcher.d.ts +182 -0
  68. package/dist/src/cli/dispatcher.js +718 -0
  69. package/dist/src/cli/human-loop.d.ts +170 -0
  70. package/dist/src/cli/human-loop.js +543 -0
  71. package/dist/src/cli/index.d.ts +12 -0
  72. package/dist/src/cli/index.js +28 -0
  73. package/dist/src/cli/interactive.d.ts +141 -0
  74. package/dist/src/cli/interactive.js +757 -0
  75. package/dist/src/cli/ui.d.ts +205 -0
  76. package/dist/src/cli/ui.js +632 -0
  77. package/dist/src/consciousness/attention-schema.d.ts +154 -0
  78. package/dist/src/consciousness/attention-schema.js +432 -0
  79. package/dist/src/consciousness/global-workspace.d.ts +149 -0
  80. package/dist/src/consciousness/global-workspace.js +422 -0
  81. package/dist/src/consciousness/index.d.ts +186 -0
  82. package/dist/src/consciousness/index.js +476 -0
  83. package/dist/src/consciousness/phi-calculator.d.ts +119 -0
  84. package/dist/src/consciousness/phi-calculator.js +445 -0
  85. package/dist/src/consciousness/phi-decisions.d.ts +169 -0
  86. package/dist/src/consciousness/phi-decisions.js +383 -0
  87. package/dist/src/consciousness/phi-monitor.d.ts +153 -0
  88. package/dist/src/consciousness/phi-monitor.js +465 -0
  89. package/dist/src/consciousness/types.d.ts +260 -0
  90. package/dist/src/consciousness/types.js +44 -0
  91. package/dist/src/daemon/dream-mode.d.ts +115 -0
  92. package/dist/src/daemon/dream-mode.js +470 -0
  93. package/dist/src/daemon/index.d.ts +162 -0
  94. package/dist/src/daemon/index.js +542 -0
  95. package/dist/src/daemon/maintenance.d.ts +139 -0
  96. package/dist/src/daemon/maintenance.js +549 -0
  97. package/dist/src/daemon/process.d.ts +82 -0
  98. package/dist/src/daemon/process.js +442 -0
  99. package/dist/src/daemon/scheduler.d.ts +90 -0
  100. package/dist/src/daemon/scheduler.js +494 -0
  101. package/dist/src/daemon/types.d.ts +213 -0
  102. package/dist/src/daemon/types.js +50 -0
  103. package/dist/src/epistemic/index.d.ts +74 -0
  104. package/dist/src/epistemic/index.js +225 -0
  105. package/dist/src/grounding/epistemic-stack.d.ts +100 -0
  106. package/dist/src/grounding/epistemic-stack.js +408 -0
  107. package/dist/src/grounding/feedback.d.ts +98 -0
  108. package/dist/src/grounding/feedback.js +276 -0
  109. package/dist/src/grounding/index.d.ts +123 -0
  110. package/dist/src/grounding/index.js +224 -0
  111. package/dist/src/grounding/verifier.d.ts +149 -0
  112. package/dist/src/grounding/verifier.js +484 -0
  113. package/dist/src/healing/detector.d.ts +110 -0
  114. package/dist/src/healing/detector.js +436 -0
  115. package/dist/src/healing/fixer.d.ts +138 -0
  116. package/dist/src/healing/fixer.js +572 -0
  117. package/dist/src/healing/index.d.ts +23 -0
  118. package/dist/src/healing/index.js +43 -0
  119. package/dist/src/hooks/index.d.ts +135 -0
  120. package/dist/src/hooks/index.js +317 -0
  121. package/dist/src/index.d.ts +23 -0
  122. package/dist/src/index.js +1266 -0
  123. package/dist/src/kernel/index.d.ts +155 -0
  124. package/dist/src/kernel/index.js +795 -0
  125. package/dist/src/kernel/invariants.d.ts +153 -0
  126. package/dist/src/kernel/invariants.js +355 -0
  127. package/dist/src/kernel/test-kernel.d.ts +6 -0
  128. package/dist/src/kernel/test-kernel.js +108 -0
  129. package/dist/src/kernel/test-real-mcp.d.ts +10 -0
  130. package/dist/src/kernel/test-real-mcp.js +295 -0
  131. package/dist/src/llm/index.d.ts +146 -0
  132. package/dist/src/llm/index.js +428 -0
  133. package/dist/src/llm/router.d.ts +136 -0
  134. package/dist/src/llm/router.js +510 -0
  135. package/dist/src/mcp/index.d.ts +85 -0
  136. package/dist/src/mcp/index.js +657 -0
  137. package/dist/src/mcp/resilient.d.ts +139 -0
  138. package/dist/src/mcp/resilient.js +417 -0
  139. package/dist/src/memory/cache.d.ts +118 -0
  140. package/dist/src/memory/cache.js +356 -0
  141. package/dist/src/memory/cognitive-workspace.d.ts +231 -0
  142. package/dist/src/memory/cognitive-workspace.js +521 -0
  143. package/dist/src/memory/consolidation.d.ts +99 -0
  144. package/dist/src/memory/consolidation.js +443 -0
  145. package/dist/src/memory/episodic.d.ts +114 -0
  146. package/dist/src/memory/episodic.js +394 -0
  147. package/dist/src/memory/forgetting.d.ts +134 -0
  148. package/dist/src/memory/forgetting.js +324 -0
  149. package/dist/src/memory/index.d.ts +211 -0
  150. package/dist/src/memory/index.js +367 -0
  151. package/dist/src/memory/indexer.d.ts +123 -0
  152. package/dist/src/memory/indexer.js +479 -0
  153. package/dist/src/memory/procedural.d.ts +136 -0
  154. package/dist/src/memory/procedural.js +479 -0
  155. package/dist/src/memory/semantic.d.ts +132 -0
  156. package/dist/src/memory/semantic.js +497 -0
  157. package/dist/src/memory/types.d.ts +193 -0
  158. package/dist/src/memory/types.js +15 -0
  159. package/dist/src/orchestrator.d.ts +65 -0
  160. package/dist/src/orchestrator.js +317 -0
  161. package/dist/src/persistence/index.d.ts +257 -0
  162. package/dist/src/persistence/index.js +763 -0
  163. package/dist/src/pipeline/executor.d.ts +51 -0
  164. package/dist/src/pipeline/executor.js +695 -0
  165. package/dist/src/pipeline/index.d.ts +7 -0
  166. package/dist/src/pipeline/index.js +11 -0
  167. package/dist/src/self-production.d.ts +67 -0
  168. package/dist/src/self-production.js +205 -0
  169. package/dist/src/subagents/executor.d.ts +58 -0
  170. package/dist/src/subagents/executor.js +283 -0
  171. package/dist/src/subagents/index.d.ts +37 -0
  172. package/dist/src/subagents/index.js +53 -0
  173. package/dist/src/subagents/registry.d.ts +23 -0
  174. package/dist/src/subagents/registry.js +167 -0
  175. package/dist/src/subagents/types.d.ts +79 -0
  176. package/dist/src/subagents/types.js +14 -0
  177. package/dist/src/tools/bash.d.ts +139 -0
  178. package/dist/src/tools/bash.js +583 -0
  179. package/dist/src/tools/edit.d.ts +125 -0
  180. package/dist/src/tools/edit.js +424 -0
  181. package/dist/src/tools/git.d.ts +179 -0
  182. package/dist/src/tools/git.js +504 -0
  183. package/dist/src/tools/index.d.ts +21 -0
  184. package/dist/src/tools/index.js +163 -0
  185. package/dist/src/types.d.ts +145 -0
  186. package/dist/src/types.js +7 -0
  187. package/dist/src/world-model/decoder.d.ts +163 -0
  188. package/dist/src/world-model/decoder.js +517 -0
  189. package/dist/src/world-model/digital-twin.d.ts +219 -0
  190. package/dist/src/world-model/digital-twin.js +695 -0
  191. package/dist/src/world-model/encoder.d.ts +141 -0
  192. package/dist/src/world-model/encoder.js +564 -0
  193. package/dist/src/world-model/index.d.ts +221 -0
  194. package/dist/src/world-model/index.js +772 -0
  195. package/dist/src/world-model/predictor.d.ts +161 -0
  196. package/dist/src/world-model/predictor.js +681 -0
  197. package/dist/src/world-model/test-value-jepa.d.ts +8 -0
  198. package/dist/src/world-model/test-value-jepa.js +430 -0
  199. package/dist/src/world-model/types.d.ts +341 -0
  200. package/dist/src/world-model/types.js +69 -0
  201. package/dist/src/world-model/value-jepa.d.ts +247 -0
  202. package/dist/src/world-model/value-jepa.js +622 -0
  203. package/dist/test/brain.test.d.ts +11 -0
  204. package/dist/test/brain.test.js +358 -0
  205. package/dist/test/cli/dispatcher.test.d.ts +4 -0
  206. package/dist/test/cli/dispatcher.test.js +332 -0
  207. package/dist/test/cli/human-loop.test.d.ts +4 -0
  208. package/dist/test/cli/human-loop.test.js +270 -0
  209. package/dist/test/grounding/feedback.test.d.ts +4 -0
  210. package/dist/test/grounding/feedback.test.js +462 -0
  211. package/dist/test/grounding/verifier.test.d.ts +4 -0
  212. package/dist/test/grounding/verifier.test.js +442 -0
  213. package/dist/test/grounding.test.d.ts +6 -0
  214. package/dist/test/grounding.test.js +246 -0
  215. package/dist/test/healing/detector.test.d.ts +4 -0
  216. package/dist/test/healing/detector.test.js +266 -0
  217. package/dist/test/healing/fixer.test.d.ts +4 -0
  218. package/dist/test/healing/fixer.test.js +369 -0
  219. package/dist/test/integration.test.d.ts +5 -0
  220. package/dist/test/integration.test.js +290 -0
  221. package/dist/test/tools/bash.test.d.ts +4 -0
  222. package/dist/test/tools/bash.test.js +348 -0
  223. package/dist/test/tools/edit.test.d.ts +4 -0
  224. package/dist/test/tools/edit.test.js +350 -0
  225. package/dist/test/tools/git.test.d.ts +4 -0
  226. package/dist/test/tools/git.test.js +350 -0
  227. package/package.json +60 -0
@@ -0,0 +1,763 @@
1
+ "use strict";
2
+ /**
3
+ * Genesis 6.0 - State Persistence
4
+ *
5
+ * Save and load Genesis state to/from disk.
6
+ * Supports JSON format with optional compression.
7
+ *
8
+ * State includes:
9
+ * - Memory (episodic, semantic, procedural)
10
+ * - Conversation history
11
+ * - Session metadata
12
+ * - Configuration
13
+ */
14
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
15
+ if (k2 === undefined) k2 = k;
16
+ var desc = Object.getOwnPropertyDescriptor(m, k);
17
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
18
+ desc = { enumerable: true, get: function() { return m[k]; } };
19
+ }
20
+ Object.defineProperty(o, k2, desc);
21
+ }) : (function(o, m, k, k2) {
22
+ if (k2 === undefined) k2 = k;
23
+ o[k2] = m[k];
24
+ }));
25
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
26
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
27
+ }) : function(o, v) {
28
+ o["default"] = v;
29
+ });
30
+ var __importStar = (this && this.__importStar) || (function () {
31
+ var ownKeys = function(o) {
32
+ ownKeys = Object.getOwnPropertyNames || function (o) {
33
+ var ar = [];
34
+ for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
35
+ return ar;
36
+ };
37
+ return ownKeys(o);
38
+ };
39
+ return function (mod) {
40
+ if (mod && mod.__esModule) return mod;
41
+ var result = {};
42
+ if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
43
+ __setModuleDefault(result, mod);
44
+ return result;
45
+ };
46
+ })();
47
+ Object.defineProperty(exports, "__esModule", { value: true });
48
+ exports.SessionManager = exports.StateStore = void 0;
49
+ exports.createStateStore = createStateStore;
50
+ exports.getStateStore = getStateStore;
51
+ exports.resetStateStore = resetStateStore;
52
+ exports.getSessionManager = getSessionManager;
53
+ const fs = __importStar(require("fs"));
54
+ const path = __importStar(require("path"));
55
+ const crypto = __importStar(require("crypto"));
56
+ // ============================================================================
57
+ // Default Paths
58
+ // ============================================================================
59
+ const DEFAULT_DATA_DIR = path.join(process.env.HOME || '.', '.genesis');
60
+ const STATE_FILE = 'state.json';
61
+ const BACKUP_DIR = 'backups';
62
+ // ============================================================================
63
+ // State Store Class
64
+ // ============================================================================
65
+ class StateStore {
66
+ dataDir;
67
+ statePath;
68
+ backupDir;
69
+ options;
70
+ autoSaveTimer = null;
71
+ dirty = false;
72
+ // In-memory state
73
+ state;
74
+ constructor(options = {}) {
75
+ this.options = options;
76
+ this.dataDir = options.dataDir || DEFAULT_DATA_DIR;
77
+ this.statePath = path.join(this.dataDir, STATE_FILE);
78
+ this.backupDir = path.join(this.dataDir, BACKUP_DIR);
79
+ // Initialize with empty state
80
+ this.state = this.createEmptyState();
81
+ // Ensure directories exist
82
+ this.ensureDirectories();
83
+ // Try to load existing state
84
+ this.loadSync();
85
+ // Start auto-save if enabled
86
+ if (options.autoSave) {
87
+ this.startAutoSave(options.autoSaveIntervalMs || 60000);
88
+ }
89
+ }
90
+ // ============================================================================
91
+ // Core Methods
92
+ // ============================================================================
93
+ /**
94
+ * Save state to disk
95
+ */
96
+ async save() {
97
+ try {
98
+ // Update metadata
99
+ this.state.lastModified = new Date();
100
+ this.state.checksum = this.calculateChecksum(this.state);
101
+ // Create backup before overwriting
102
+ await this.backup();
103
+ // Write state
104
+ const json = JSON.stringify(this.state, null, 2);
105
+ await fs.promises.writeFile(this.statePath, json, 'utf-8');
106
+ this.dirty = false;
107
+ this.options.onSave?.(this.state);
108
+ }
109
+ catch (error) {
110
+ const err = error instanceof Error ? error : new Error(String(error));
111
+ this.options.onError?.(err);
112
+ throw err;
113
+ }
114
+ }
115
+ /**
116
+ * Save state synchronously
117
+ */
118
+ saveSync() {
119
+ try {
120
+ this.state.lastModified = new Date();
121
+ this.state.checksum = this.calculateChecksum(this.state);
122
+ // Backup
123
+ this.backupSync();
124
+ // Write
125
+ const json = JSON.stringify(this.state, null, 2);
126
+ fs.writeFileSync(this.statePath, json, 'utf-8');
127
+ this.dirty = false;
128
+ this.options.onSave?.(this.state);
129
+ }
130
+ catch (error) {
131
+ const err = error instanceof Error ? error : new Error(String(error));
132
+ this.options.onError?.(err);
133
+ throw err;
134
+ }
135
+ }
136
+ /**
137
+ * Load state from disk
138
+ */
139
+ async load() {
140
+ try {
141
+ if (!fs.existsSync(this.statePath)) {
142
+ return this.state;
143
+ }
144
+ const json = await fs.promises.readFile(this.statePath, 'utf-8');
145
+ const loaded = JSON.parse(json);
146
+ // Validate checksum
147
+ const expectedChecksum = this.calculateChecksum(loaded);
148
+ if (loaded.checksum && loaded.checksum !== expectedChecksum) {
149
+ console.warn('[StateStore] Checksum mismatch - state may be corrupted');
150
+ }
151
+ // Merge with empty state to ensure all fields exist
152
+ this.state = this.mergeState(this.createEmptyState(), loaded);
153
+ this.options.onLoad?.(this.state);
154
+ return this.state;
155
+ }
156
+ catch (error) {
157
+ const err = error instanceof Error ? error : new Error(String(error));
158
+ this.options.onError?.(err);
159
+ throw err;
160
+ }
161
+ }
162
+ /**
163
+ * Load state synchronously
164
+ */
165
+ loadSync() {
166
+ try {
167
+ if (!fs.existsSync(this.statePath)) {
168
+ return this.state;
169
+ }
170
+ const json = fs.readFileSync(this.statePath, 'utf-8');
171
+ const loaded = JSON.parse(json);
172
+ this.state = this.mergeState(this.createEmptyState(), loaded);
173
+ this.options.onLoad?.(this.state);
174
+ return this.state;
175
+ }
176
+ catch (error) {
177
+ // If loading fails, keep empty state
178
+ console.warn('[StateStore] Failed to load state:', error);
179
+ return this.state;
180
+ }
181
+ }
182
+ /**
183
+ * Get current state
184
+ */
185
+ getState() {
186
+ return this.state;
187
+ }
188
+ /**
189
+ * Update state (partial update)
190
+ */
191
+ update(updates) {
192
+ this.state = this.mergeState(this.state, updates);
193
+ this.dirty = true;
194
+ }
195
+ /**
196
+ * Check if state has unsaved changes
197
+ */
198
+ isDirty() {
199
+ return this.dirty;
200
+ }
201
+ // ============================================================================
202
+ // Memory Operations
203
+ // ============================================================================
204
+ /**
205
+ * Update memory state
206
+ */
207
+ updateMemory(memory) {
208
+ this.state.memory = { ...this.state.memory, ...memory };
209
+ this.dirty = true;
210
+ }
211
+ /**
212
+ * Add episodic memory
213
+ */
214
+ addEpisode(episode) {
215
+ this.state.memory.episodic.push(episode);
216
+ this.state.memory.stats.totalEpisodes++;
217
+ this.dirty = true;
218
+ }
219
+ /**
220
+ * Add semantic memory
221
+ */
222
+ addFact(fact) {
223
+ this.state.memory.semantic.push(fact);
224
+ this.state.memory.stats.totalFacts++;
225
+ this.dirty = true;
226
+ }
227
+ /**
228
+ * Add procedural memory
229
+ */
230
+ addSkill(skill) {
231
+ this.state.memory.procedural.push(skill);
232
+ this.state.memory.stats.totalSkills++;
233
+ this.dirty = true;
234
+ }
235
+ // ============================================================================
236
+ // Conversation Operations
237
+ // ============================================================================
238
+ /**
239
+ * Update conversation history
240
+ */
241
+ updateConversation(messages, tokens) {
242
+ this.state.conversation.history = messages;
243
+ this.state.conversation.totalMessages = messages.length;
244
+ if (tokens) {
245
+ this.state.conversation.totalTokens += tokens;
246
+ }
247
+ this.dirty = true;
248
+ }
249
+ /**
250
+ * Add message to conversation
251
+ */
252
+ addMessage(message) {
253
+ this.state.conversation.history.push(message);
254
+ this.state.conversation.totalMessages++;
255
+ this.dirty = true;
256
+ }
257
+ /**
258
+ * Clear conversation history
259
+ */
260
+ clearConversation() {
261
+ this.state.conversation.history = [];
262
+ this.dirty = true;
263
+ }
264
+ // ============================================================================
265
+ // Session Operations
266
+ // ============================================================================
267
+ /**
268
+ * Record an interaction
269
+ */
270
+ recordInteraction() {
271
+ this.state.session.interactions++;
272
+ this.state.session.lastActivity = new Date();
273
+ this.dirty = true;
274
+ }
275
+ /**
276
+ * Start new session
277
+ */
278
+ newSession() {
279
+ this.state.session = {
280
+ id: crypto.randomUUID(),
281
+ startTime: new Date(),
282
+ interactions: 0,
283
+ lastActivity: new Date(),
284
+ };
285
+ this.dirty = true;
286
+ }
287
+ // ============================================================================
288
+ // Backup Operations
289
+ // ============================================================================
290
+ /**
291
+ * Create backup of current state
292
+ */
293
+ async backup() {
294
+ if (!fs.existsSync(this.statePath)) {
295
+ return null;
296
+ }
297
+ const timestamp = new Date().toISOString().replace(/[:.]/g, '-');
298
+ const backupPath = path.join(this.backupDir, `state-${timestamp}.json`);
299
+ await fs.promises.copyFile(this.statePath, backupPath);
300
+ // Clean old backups
301
+ await this.cleanOldBackups();
302
+ return backupPath;
303
+ }
304
+ /**
305
+ * Create backup synchronously
306
+ */
307
+ backupSync() {
308
+ if (!fs.existsSync(this.statePath)) {
309
+ return null;
310
+ }
311
+ const timestamp = new Date().toISOString().replace(/[:.]/g, '-');
312
+ const backupPath = path.join(this.backupDir, `state-${timestamp}.json`);
313
+ fs.copyFileSync(this.statePath, backupPath);
314
+ this.cleanOldBackupsSync();
315
+ return backupPath;
316
+ }
317
+ /**
318
+ * List available backups
319
+ */
320
+ listBackups() {
321
+ if (!fs.existsSync(this.backupDir)) {
322
+ return [];
323
+ }
324
+ return fs.readdirSync(this.backupDir)
325
+ .filter(f => f.endsWith('.json'))
326
+ .sort()
327
+ .reverse();
328
+ }
329
+ /**
330
+ * Restore from backup
331
+ */
332
+ async restoreBackup(backupName) {
333
+ const backupPath = path.join(this.backupDir, backupName);
334
+ if (!fs.existsSync(backupPath)) {
335
+ throw new Error(`Backup not found: ${backupName}`);
336
+ }
337
+ // Backup current state first
338
+ await this.backup();
339
+ // Copy backup to state file
340
+ await fs.promises.copyFile(backupPath, this.statePath);
341
+ // Reload
342
+ await this.load();
343
+ }
344
+ // ============================================================================
345
+ // Export/Import
346
+ // ============================================================================
347
+ /**
348
+ * Export state to a portable format
349
+ */
350
+ async export(outputPath) {
351
+ const exportData = {
352
+ ...this.state,
353
+ exportedAt: new Date(),
354
+ exportVersion: '1.0',
355
+ };
356
+ const json = JSON.stringify(exportData, null, 2);
357
+ await fs.promises.writeFile(outputPath, json, 'utf-8');
358
+ }
359
+ /**
360
+ * Import state from file
361
+ */
362
+ async import(inputPath, merge = false) {
363
+ const json = await fs.promises.readFile(inputPath, 'utf-8');
364
+ const imported = JSON.parse(json);
365
+ if (merge) {
366
+ // Merge with current state
367
+ this.state = this.mergeState(this.state, imported);
368
+ }
369
+ else {
370
+ // Replace state
371
+ this.state = this.mergeState(this.createEmptyState(), imported);
372
+ }
373
+ this.dirty = true;
374
+ await this.save();
375
+ }
376
+ // ============================================================================
377
+ // Auto-Save
378
+ // ============================================================================
379
+ /**
380
+ * Start auto-save timer
381
+ */
382
+ startAutoSave(intervalMs) {
383
+ this.stopAutoSave();
384
+ this.autoSaveTimer = setInterval(async () => {
385
+ if (this.dirty) {
386
+ try {
387
+ await this.save();
388
+ }
389
+ catch (error) {
390
+ console.error('[StateStore] Auto-save failed:', error);
391
+ }
392
+ }
393
+ }, intervalMs);
394
+ }
395
+ /**
396
+ * Stop auto-save timer
397
+ */
398
+ stopAutoSave() {
399
+ if (this.autoSaveTimer) {
400
+ clearInterval(this.autoSaveTimer);
401
+ this.autoSaveTimer = null;
402
+ }
403
+ }
404
+ // ============================================================================
405
+ // Cleanup
406
+ // ============================================================================
407
+ /**
408
+ * Reset state to empty
409
+ */
410
+ reset() {
411
+ this.state = this.createEmptyState();
412
+ this.dirty = true;
413
+ }
414
+ /**
415
+ * Delete all persisted data
416
+ */
417
+ async purge() {
418
+ this.stopAutoSave();
419
+ if (fs.existsSync(this.statePath)) {
420
+ await fs.promises.unlink(this.statePath);
421
+ }
422
+ if (fs.existsSync(this.backupDir)) {
423
+ const files = await fs.promises.readdir(this.backupDir);
424
+ for (const file of files) {
425
+ await fs.promises.unlink(path.join(this.backupDir, file));
426
+ }
427
+ }
428
+ this.reset();
429
+ }
430
+ /**
431
+ * Close and cleanup
432
+ */
433
+ close() {
434
+ this.stopAutoSave();
435
+ if (this.dirty) {
436
+ this.saveSync();
437
+ }
438
+ }
439
+ // ============================================================================
440
+ // Helpers
441
+ // ============================================================================
442
+ createEmptyState() {
443
+ return {
444
+ version: '6.0',
445
+ created: new Date(),
446
+ lastModified: new Date(),
447
+ checksum: '',
448
+ memory: {
449
+ episodic: [],
450
+ semantic: [],
451
+ procedural: [],
452
+ stats: {
453
+ totalEpisodes: 0,
454
+ totalFacts: 0,
455
+ totalSkills: 0,
456
+ },
457
+ },
458
+ conversation: {
459
+ history: [],
460
+ totalMessages: 0,
461
+ totalTokens: 0,
462
+ },
463
+ session: {
464
+ id: crypto.randomUUID(),
465
+ startTime: new Date(),
466
+ interactions: 0,
467
+ lastActivity: new Date(),
468
+ },
469
+ config: {
470
+ llm: {},
471
+ persistence: {},
472
+ },
473
+ };
474
+ }
475
+ mergeState(base, updates) {
476
+ return {
477
+ ...base,
478
+ ...updates,
479
+ memory: {
480
+ ...base.memory,
481
+ ...(updates.memory || {}),
482
+ stats: {
483
+ ...base.memory.stats,
484
+ ...(updates.memory?.stats || {}),
485
+ },
486
+ },
487
+ conversation: {
488
+ ...base.conversation,
489
+ ...(updates.conversation || {}),
490
+ },
491
+ session: {
492
+ ...base.session,
493
+ ...(updates.session || {}),
494
+ },
495
+ config: {
496
+ ...base.config,
497
+ ...(updates.config || {}),
498
+ llm: {
499
+ ...base.config.llm,
500
+ ...(updates.config?.llm || {}),
501
+ },
502
+ persistence: {
503
+ ...base.config.persistence,
504
+ ...(updates.config?.persistence || {}),
505
+ },
506
+ },
507
+ };
508
+ }
509
+ calculateChecksum(state) {
510
+ const data = JSON.stringify({
511
+ memory: state.memory,
512
+ conversation: state.conversation,
513
+ });
514
+ return crypto.createHash('sha256').update(data).digest('hex').slice(0, 16);
515
+ }
516
+ ensureDirectories() {
517
+ if (!fs.existsSync(this.dataDir)) {
518
+ fs.mkdirSync(this.dataDir, { recursive: true });
519
+ }
520
+ if (!fs.existsSync(this.backupDir)) {
521
+ fs.mkdirSync(this.backupDir, { recursive: true });
522
+ }
523
+ }
524
+ async cleanOldBackups() {
525
+ const maxBackups = this.options.maxBackups || 10;
526
+ const backups = this.listBackups();
527
+ if (backups.length > maxBackups) {
528
+ const toDelete = backups.slice(maxBackups);
529
+ for (const backup of toDelete) {
530
+ await fs.promises.unlink(path.join(this.backupDir, backup));
531
+ }
532
+ }
533
+ }
534
+ cleanOldBackupsSync() {
535
+ const maxBackups = this.options.maxBackups || 10;
536
+ const backups = this.listBackups();
537
+ if (backups.length > maxBackups) {
538
+ const toDelete = backups.slice(maxBackups);
539
+ for (const backup of toDelete) {
540
+ fs.unlinkSync(path.join(this.backupDir, backup));
541
+ }
542
+ }
543
+ }
544
+ /**
545
+ * Get data directory path
546
+ */
547
+ getDataDir() {
548
+ return this.dataDir;
549
+ }
550
+ /**
551
+ * Get stats
552
+ */
553
+ stats() {
554
+ const stateExists = fs.existsSync(this.statePath);
555
+ const stateSize = stateExists ? fs.statSync(this.statePath).size : 0;
556
+ return {
557
+ dataDir: this.dataDir,
558
+ stateExists,
559
+ stateSize,
560
+ backupCount: this.listBackups().length,
561
+ isDirty: this.dirty,
562
+ lastModified: this.state.lastModified,
563
+ };
564
+ }
565
+ }
566
+ exports.StateStore = StateStore;
567
+ // ============================================================================
568
+ // Factory & Singleton
569
+ // ============================================================================
570
+ let stateStoreInstance = null;
571
+ function createStateStore(options) {
572
+ return new StateStore(options);
573
+ }
574
+ function getStateStore(options) {
575
+ if (!stateStoreInstance) {
576
+ stateStoreInstance = createStateStore(options);
577
+ }
578
+ return stateStoreInstance;
579
+ }
580
+ function resetStateStore() {
581
+ if (stateStoreInstance) {
582
+ stateStoreInstance.close();
583
+ }
584
+ stateStoreInstance = null;
585
+ }
586
+ const SESSIONS_DIR = 'sessions';
587
+ class SessionManager {
588
+ dataDir;
589
+ sessionsDir;
590
+ options;
591
+ constructor(options = {}) {
592
+ this.options = options;
593
+ this.dataDir = options.dataDir || path.join(process.env.HOME || '.', '.genesis');
594
+ this.sessionsDir = path.join(this.dataDir, SESSIONS_DIR);
595
+ this.ensureDirectory();
596
+ }
597
+ /**
598
+ * List all saved sessions
599
+ */
600
+ listSessions() {
601
+ if (!fs.existsSync(this.sessionsDir)) {
602
+ return [];
603
+ }
604
+ const files = fs.readdirSync(this.sessionsDir)
605
+ .filter(f => f.endsWith('.json'))
606
+ .sort()
607
+ .reverse(); // Most recent first
608
+ const sessions = [];
609
+ for (const file of files) {
610
+ try {
611
+ const filePath = path.join(this.sessionsDir, file);
612
+ const data = JSON.parse(fs.readFileSync(filePath, 'utf-8'));
613
+ // Extract first user message as summary
614
+ const firstUserMsg = data.conversation?.history?.find(m => m.role === 'user');
615
+ const summary = firstUserMsg?.content?.slice(0, 80);
616
+ sessions.push({
617
+ id: data.session?.id || file.replace('.json', ''),
618
+ name: data.sessionName, // Optional session name
619
+ created: new Date(data.created),
620
+ lastModified: new Date(data.lastModified),
621
+ messageCount: data.conversation?.totalMessages || 0,
622
+ tokenCount: data.conversation?.totalTokens || 0,
623
+ summary,
624
+ });
625
+ }
626
+ catch {
627
+ // Skip invalid files
628
+ }
629
+ }
630
+ return sessions;
631
+ }
632
+ /**
633
+ * Get the most recent session ID
634
+ */
635
+ getLastSessionId() {
636
+ const sessions = this.listSessions();
637
+ return sessions.length > 0 ? sessions[0].id : null;
638
+ }
639
+ /**
640
+ * Save current state as a session
641
+ */
642
+ saveSession(state, name) {
643
+ const sessionId = state.session.id;
644
+ const sessionPath = this.getSessionPath(sessionId);
645
+ const sessionData = {
646
+ ...state,
647
+ sessionName: name,
648
+ };
649
+ fs.writeFileSync(sessionPath, JSON.stringify(sessionData, null, 2));
650
+ // Cleanup old sessions if needed
651
+ this.cleanupOldSessions();
652
+ return sessionId;
653
+ }
654
+ /**
655
+ * Load a session by ID (or 'last' for most recent)
656
+ */
657
+ loadSession(sessionIdOrLast) {
658
+ let sessionId = sessionIdOrLast;
659
+ // Handle 'last' keyword
660
+ if (sessionIdOrLast === 'last') {
661
+ const lastId = this.getLastSessionId();
662
+ if (!lastId)
663
+ return null;
664
+ sessionId = lastId;
665
+ }
666
+ // Try exact match first
667
+ let sessionPath = this.getSessionPath(sessionId);
668
+ // If not found, try partial match (first 8 chars like git)
669
+ if (!fs.existsSync(sessionPath)) {
670
+ const sessions = this.listSessions();
671
+ const match = sessions.find(s => s.id.startsWith(sessionId));
672
+ if (match) {
673
+ sessionPath = this.getSessionPath(match.id);
674
+ }
675
+ }
676
+ if (!fs.existsSync(sessionPath)) {
677
+ return null;
678
+ }
679
+ try {
680
+ const data = JSON.parse(fs.readFileSync(sessionPath, 'utf-8'));
681
+ return data;
682
+ }
683
+ catch {
684
+ return null;
685
+ }
686
+ }
687
+ /**
688
+ * Fork a session (create a copy with new ID)
689
+ */
690
+ forkSession(sessionId, newName) {
691
+ const originalState = this.loadSession(sessionId);
692
+ if (!originalState)
693
+ return null;
694
+ // Create new session with new ID
695
+ const forkedState = {
696
+ ...originalState,
697
+ session: {
698
+ ...originalState.session,
699
+ id: crypto.randomUUID(),
700
+ startTime: new Date(),
701
+ },
702
+ created: new Date(),
703
+ lastModified: new Date(),
704
+ };
705
+ return this.saveSession(forkedState, newName || `Fork of ${sessionId.slice(0, 8)}`);
706
+ }
707
+ /**
708
+ * Delete a session
709
+ */
710
+ deleteSession(sessionId) {
711
+ const sessionPath = this.getSessionPath(sessionId);
712
+ if (!fs.existsSync(sessionPath)) {
713
+ // Try partial match
714
+ const sessions = this.listSessions();
715
+ const match = sessions.find(s => s.id.startsWith(sessionId));
716
+ if (match) {
717
+ fs.unlinkSync(this.getSessionPath(match.id));
718
+ return true;
719
+ }
720
+ return false;
721
+ }
722
+ fs.unlinkSync(sessionPath);
723
+ return true;
724
+ }
725
+ /**
726
+ * Rename a session
727
+ */
728
+ renameSession(sessionId, newName) {
729
+ const state = this.loadSession(sessionId);
730
+ if (!state)
731
+ return false;
732
+ this.saveSession(state, newName);
733
+ return true;
734
+ }
735
+ getSessionPath(sessionId) {
736
+ return path.join(this.sessionsDir, `${sessionId}.json`);
737
+ }
738
+ ensureDirectory() {
739
+ if (!fs.existsSync(this.sessionsDir)) {
740
+ fs.mkdirSync(this.sessionsDir, { recursive: true });
741
+ }
742
+ }
743
+ cleanupOldSessions() {
744
+ const maxSessions = this.options.maxSessions || 50;
745
+ const sessions = this.listSessions();
746
+ if (sessions.length > maxSessions) {
747
+ // Delete oldest sessions
748
+ const toDelete = sessions.slice(maxSessions);
749
+ for (const session of toDelete) {
750
+ this.deleteSession(session.id);
751
+ }
752
+ }
753
+ }
754
+ }
755
+ exports.SessionManager = SessionManager;
756
+ // Singleton
757
+ let sessionManagerInstance = null;
758
+ function getSessionManager(options) {
759
+ if (!sessionManagerInstance) {
760
+ sessionManagerInstance = new SessionManager(options);
761
+ }
762
+ return sessionManagerInstance;
763
+ }