@jungjaehoon/mama-core 1.1.1 → 1.1.3

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 (67) hide show
  1. package/dist/config-loader.d.ts +61 -0
  2. package/dist/config-loader.js +187 -0
  3. package/dist/db-adapter/base-adapter.d.ts +76 -0
  4. package/dist/db-adapter/base-adapter.js +11 -0
  5. package/dist/db-adapter/index.d.ts +24 -0
  6. package/dist/db-adapter/index.js +29 -0
  7. package/dist/db-adapter/sqlite-adapter.d.ts +73 -0
  8. package/dist/db-adapter/sqlite-adapter.js +330 -0
  9. package/dist/db-adapter/statement.d.ts +119 -0
  10. package/dist/db-adapter/statement.js +113 -0
  11. package/dist/db-manager.d.ts +252 -0
  12. package/dist/db-manager.js +622 -0
  13. package/dist/debug-logger.d.ts +32 -0
  14. package/dist/debug-logger.js +83 -0
  15. package/dist/decision-formatter.d.ts +172 -0
  16. package/dist/decision-formatter.js +894 -0
  17. package/dist/decision-tracker.d.ts +218 -0
  18. package/dist/decision-tracker.js +531 -0
  19. package/dist/embedding-cache.d.ts +83 -0
  20. package/dist/embedding-cache.js +182 -0
  21. package/dist/embedding-client.d.ts +43 -0
  22. package/dist/embedding-client.js +132 -0
  23. package/dist/embedding-server/index.d.ts +65 -0
  24. package/dist/embedding-server/index.js +397 -0
  25. package/dist/embedding-server/mobile/auth.d.ts +53 -0
  26. package/dist/embedding-server/mobile/auth.js +140 -0
  27. package/dist/embedding-server/mobile/daemon.d.ts +128 -0
  28. package/dist/embedding-server/mobile/daemon.js +303 -0
  29. package/dist/embedding-server/mobile/output-parser.d.ts +115 -0
  30. package/dist/embedding-server/mobile/output-parser.js +241 -0
  31. package/dist/embedding-server/mobile/session-api.d.ts +57 -0
  32. package/dist/embedding-server/mobile/session-api.js +261 -0
  33. package/dist/embedding-server/mobile/session-manager.d.ts +135 -0
  34. package/dist/embedding-server/mobile/session-manager.js +333 -0
  35. package/dist/embedding-server/mobile/websocket-handler.d.ts +127 -0
  36. package/dist/embedding-server/mobile/websocket-handler.js +435 -0
  37. package/dist/embeddings.d.ts +75 -0
  38. package/dist/embeddings.js +262 -0
  39. package/dist/errors.d.ts +131 -0
  40. package/dist/errors.js +225 -0
  41. package/dist/index.d.ts +32 -0
  42. package/dist/index.js +193 -0
  43. package/dist/mama-api.d.ts +954 -0
  44. package/dist/mama-api.js +2210 -0
  45. package/dist/memory-inject.d.ts +24 -0
  46. package/dist/memory-inject.js +116 -0
  47. package/dist/memory-store.d.ts +103 -0
  48. package/dist/memory-store.js +129 -0
  49. package/dist/notification-manager.d.ts +7 -0
  50. package/dist/notification-manager.js +12 -0
  51. package/dist/ollama-client.d.ts +51 -0
  52. package/dist/ollama-client.js +308 -0
  53. package/dist/outcome-tracker.d.ts +165 -0
  54. package/dist/outcome-tracker.js +315 -0
  55. package/dist/progress-indicator.d.ts +48 -0
  56. package/dist/progress-indicator.js +82 -0
  57. package/dist/query-intent.d.ts +27 -0
  58. package/dist/query-intent.js +144 -0
  59. package/dist/relevance-scorer.d.ts +124 -0
  60. package/dist/relevance-scorer.js +243 -0
  61. package/dist/test-utils.d.ts +66 -0
  62. package/dist/test-utils.js +166 -0
  63. package/dist/tier-validator.d.ts +55 -0
  64. package/dist/tier-validator.js +216 -0
  65. package/dist/time-formatter.d.ts +25 -0
  66. package/dist/time-formatter.js +93 -0
  67. package/package.json +3 -2
@@ -0,0 +1,333 @@
1
+ "use strict";
2
+ /**
3
+ * @fileoverview Session Manager - tracks multiple Claude Code sessions in SQLite
4
+ * @module mobile/session-manager
5
+ * @version 1.5.0
6
+ *
7
+ * Manages session lifecycle including creation, tracking, and termination.
8
+ * Sessions are persisted to SQLite for durability across server restarts.
9
+ *
10
+ * @example
11
+ * import { SessionManager } from './session-manager';
12
+ * const manager = new SessionManager();
13
+ * await manager.initDB();
14
+ * const { sessionId, daemon } = await manager.createSession('/path/to/project');
15
+ */
16
+ var __importDefault = (this && this.__importDefault) || function (mod) {
17
+ return (mod && mod.__esModule) ? mod : { "default": mod };
18
+ };
19
+ Object.defineProperty(exports, "__esModule", { value: true });
20
+ exports.SessionManager = exports.CREATE_SESSIONS_TABLE = exports.DEFAULT_DB_PATH = void 0;
21
+ const path_1 = __importDefault(require("path"));
22
+ const os_1 = __importDefault(require("os"));
23
+ const daemon_js_1 = require("./daemon.js");
24
+ /**
25
+ * Default database path
26
+ */
27
+ exports.DEFAULT_DB_PATH = process.env.MAMA_DB_PATH || path_1.default.join(os_1.default.homedir(), '.claude', 'mama-memory.db');
28
+ /**
29
+ * Sessions table creation SQL
30
+ */
31
+ exports.CREATE_SESSIONS_TABLE = `
32
+ CREATE TABLE IF NOT EXISTS sessions (
33
+ id TEXT PRIMARY KEY,
34
+ project_dir TEXT NOT NULL,
35
+ created_at TEXT DEFAULT (datetime('now')),
36
+ last_active TEXT DEFAULT (datetime('now')),
37
+ status TEXT DEFAULT 'active',
38
+ pid INTEGER,
39
+ client_id TEXT
40
+ )
41
+ `;
42
+ /**
43
+ * Create index for status queries
44
+ */
45
+ const CREATE_STATUS_INDEX = `
46
+ CREATE INDEX IF NOT EXISTS idx_sessions_status ON sessions(status)
47
+ `;
48
+ /**
49
+ * SessionManager class - manages Claude Code sessions
50
+ */
51
+ class SessionManager {
52
+ dbPath;
53
+ sessions;
54
+ db;
55
+ initialized;
56
+ /**
57
+ * Create a new SessionManager instance
58
+ * @param dbPath - Path to SQLite database
59
+ */
60
+ constructor(dbPath = exports.DEFAULT_DB_PATH) {
61
+ this.dbPath = dbPath;
62
+ this.sessions = new Map();
63
+ this.db = null;
64
+ this.initialized = false;
65
+ }
66
+ /**
67
+ * Initialize the SQLite database and create sessions table
68
+ */
69
+ async initDB() {
70
+ if (this.initialized) {
71
+ return;
72
+ }
73
+ try {
74
+ // Dynamically import better-sqlite3 to handle cases where it's not installed
75
+ // eslint-disable-next-line @typescript-eslint/no-require-imports
76
+ const Database = require('better-sqlite3');
77
+ this.db = new Database(this.dbPath);
78
+ // Create sessions table if not exists
79
+ this.db.exec(exports.CREATE_SESSIONS_TABLE);
80
+ this.db.exec(CREATE_STATUS_INDEX);
81
+ // Mark any orphaned 'active' sessions as 'terminated'
82
+ // (from previous server crashes)
83
+ this.db
84
+ .prepare(`
85
+ UPDATE sessions
86
+ SET status = 'terminated', last_active = datetime('now')
87
+ WHERE status = 'active'
88
+ `)
89
+ .run();
90
+ this.initialized = true;
91
+ console.error(`[SessionManager] Database initialized at ${this.dbPath}`);
92
+ // Setup cleanup on process exit
93
+ this._setupProcessCleanup();
94
+ }
95
+ catch (err) {
96
+ const message = err instanceof Error ? err.message : String(err);
97
+ console.error('[SessionManager] Failed to initialize database:', message);
98
+ throw err;
99
+ }
100
+ }
101
+ /**
102
+ * Create a new Claude Code session
103
+ * @param projectDir - Working directory for the session
104
+ * @returns Session ID and daemon
105
+ */
106
+ async createSession(projectDir) {
107
+ if (!this.initialized) {
108
+ await this.initDB();
109
+ }
110
+ // Generate unique session ID
111
+ const sessionId = `session_${Date.now()}_${Math.random().toString(36).substring(2, 8)}`;
112
+ // Create daemon instance
113
+ const daemon = new daemon_js_1.ClaudeDaemon(projectDir, sessionId);
114
+ try {
115
+ // Spawn the daemon
116
+ await daemon.spawn();
117
+ // Insert into database
118
+ const stmt = this.db.prepare(`
119
+ INSERT INTO sessions (id, project_dir, status, pid)
120
+ VALUES (?, ?, 'active', ?)
121
+ `);
122
+ stmt.run(sessionId, projectDir, daemon.getPid());
123
+ // Store in memory map
124
+ this.sessions.set(sessionId, {
125
+ daemon,
126
+ clientId: null,
127
+ projectDir,
128
+ createdAt: new Date().toISOString(),
129
+ });
130
+ // Setup daemon event handlers
131
+ this._setupDaemonHandlers(sessionId, daemon);
132
+ console.error(`[SessionManager] Session ${sessionId} created for ${projectDir}`);
133
+ return { sessionId, daemon };
134
+ }
135
+ catch (err) {
136
+ const message = err instanceof Error ? err.message : String(err);
137
+ console.error(`[SessionManager] Failed to create session:`, message);
138
+ // Cleanup on failure
139
+ daemon.kill();
140
+ throw err;
141
+ }
142
+ }
143
+ /**
144
+ * Get all active sessions
145
+ * @returns Array of active session info
146
+ */
147
+ async getActiveSessions() {
148
+ if (!this.initialized) {
149
+ await this.initDB();
150
+ }
151
+ const stmt = this.db.prepare(`
152
+ SELECT id, project_dir, started_at, last_active_at, status, pid, client_id
153
+ FROM sessions
154
+ WHERE status = 'active'
155
+ ORDER BY started_at DESC
156
+ `);
157
+ const rows = stmt.all();
158
+ // Enrich with in-memory data
159
+ return rows.map((row) => {
160
+ const memSession = this.sessions.get(row.id);
161
+ return {
162
+ id: row.id,
163
+ projectDir: row.project_dir,
164
+ createdAt: row.started_at,
165
+ lastActive: row.last_active_at,
166
+ status: row.status,
167
+ pid: row.pid,
168
+ clientId: row.client_id,
169
+ isAlive: memSession?.daemon?.isActive() || false,
170
+ };
171
+ });
172
+ }
173
+ /**
174
+ * Terminate a session by ID
175
+ * @param sessionId - Session to terminate
176
+ * @returns True if session was terminated
177
+ */
178
+ async terminateSession(sessionId) {
179
+ if (!this.initialized) {
180
+ await this.initDB();
181
+ }
182
+ const session = this.sessions.get(sessionId);
183
+ if (session) {
184
+ // Kill the daemon
185
+ if (session.daemon) {
186
+ session.daemon.kill();
187
+ }
188
+ // Remove from memory
189
+ this.sessions.delete(sessionId);
190
+ }
191
+ // Update database
192
+ const stmt = this.db.prepare(`
193
+ UPDATE sessions
194
+ SET status = 'terminated', last_active = datetime('now')
195
+ WHERE id = ?
196
+ `);
197
+ const result = stmt.run(sessionId);
198
+ console.error(`[SessionManager] Session ${sessionId} terminated`);
199
+ return result.changes > 0;
200
+ }
201
+ /**
202
+ * Get a session by ID
203
+ * @param sessionId - Session ID to look up
204
+ * @returns Session data or undefined
205
+ */
206
+ getSession(sessionId) {
207
+ return this.sessions.get(sessionId);
208
+ }
209
+ /**
210
+ * Update session's last active timestamp
211
+ * @param sessionId - Session ID
212
+ */
213
+ touchSession(sessionId) {
214
+ if (!this.db || !this.initialized) {
215
+ return;
216
+ }
217
+ const stmt = this.db.prepare(`
218
+ UPDATE sessions
219
+ SET last_active = datetime('now')
220
+ WHERE id = ?
221
+ `);
222
+ stmt.run(sessionId);
223
+ }
224
+ /**
225
+ * Assign a client to a session
226
+ * @param sessionId - Session ID
227
+ * @param clientId - Client ID
228
+ */
229
+ assignClient(sessionId, clientId) {
230
+ const session = this.sessions.get(sessionId);
231
+ if (session) {
232
+ session.clientId = clientId;
233
+ }
234
+ if (this.db && this.initialized) {
235
+ const stmt = this.db.prepare(`
236
+ UPDATE sessions
237
+ SET client_id = ?
238
+ WHERE id = ?
239
+ `);
240
+ stmt.run(clientId, sessionId);
241
+ }
242
+ }
243
+ /**
244
+ * Remove client assignment from a session
245
+ * @param sessionId - Session ID
246
+ */
247
+ unassignClient(sessionId) {
248
+ const session = this.sessions.get(sessionId);
249
+ if (session) {
250
+ session.clientId = null;
251
+ }
252
+ if (this.db && this.initialized) {
253
+ const stmt = this.db.prepare(`
254
+ UPDATE sessions
255
+ SET client_id = NULL
256
+ WHERE id = ?
257
+ `);
258
+ stmt.run(sessionId);
259
+ }
260
+ }
261
+ /**
262
+ * Get session count
263
+ * @returns Number of active sessions
264
+ */
265
+ getSessionCount() {
266
+ return this.sessions.size;
267
+ }
268
+ /**
269
+ * Terminate all active sessions
270
+ * @returns Number of sessions terminated
271
+ */
272
+ async terminateAll() {
273
+ const sessionIds = Array.from(this.sessions.keys());
274
+ let count = 0;
275
+ for (const sessionId of sessionIds) {
276
+ if (await this.terminateSession(sessionId)) {
277
+ count++;
278
+ }
279
+ }
280
+ return count;
281
+ }
282
+ /**
283
+ * Setup daemon event handlers
284
+ * @private
285
+ */
286
+ _setupDaemonHandlers(sessionId, daemon) {
287
+ daemon.on('exit', () => {
288
+ // Update database on daemon exit
289
+ if (this.db && this.initialized) {
290
+ const stmt = this.db.prepare(`
291
+ UPDATE sessions
292
+ SET status = 'terminated', last_active = datetime('now')
293
+ WHERE id = ?
294
+ `);
295
+ stmt.run(sessionId);
296
+ }
297
+ // Remove from memory
298
+ this.sessions.delete(sessionId);
299
+ console.error(`[SessionManager] Session ${sessionId} daemon exited, cleaned up`);
300
+ });
301
+ daemon.on('error', (err) => {
302
+ console.error(`[SessionManager] Session ${sessionId} daemon error:`, err.error);
303
+ });
304
+ }
305
+ /**
306
+ * Setup process cleanup handlers
307
+ * @private
308
+ */
309
+ _setupProcessCleanup() {
310
+ const cleanup = async () => {
311
+ console.error('[SessionManager] Process exiting, cleaning up sessions...');
312
+ await this.terminateAll();
313
+ if (this.db) {
314
+ this.db.close();
315
+ }
316
+ };
317
+ process.on('exit', () => void cleanup());
318
+ process.on('SIGINT', () => void cleanup());
319
+ process.on('SIGTERM', () => void cleanup());
320
+ }
321
+ /**
322
+ * Close the database connection
323
+ */
324
+ close() {
325
+ if (this.db) {
326
+ this.db.close();
327
+ this.db = null;
328
+ this.initialized = false;
329
+ }
330
+ }
331
+ }
332
+ exports.SessionManager = SessionManager;
333
+ //# sourceMappingURL=session-manager.js.map
@@ -0,0 +1,127 @@
1
+ /**
2
+ * @fileoverview WebSocket Handler - MessageRouter-based real-time communication
3
+ * @module mobile/websocket-handler
4
+ * @version 2.0.0
5
+ *
6
+ * Handles WebSocket connections for mobile clients, using MessageRouter
7
+ * for unified message processing (same as Discord/Slack gateways).
8
+ *
9
+ * @example
10
+ * import { createWebSocketHandler } from './websocket-handler';
11
+ * const wsHandler = createWebSocketHandler({
12
+ * httpServer,
13
+ * messageRouter,
14
+ * sessionStore,
15
+ * authToken: process.env.MAMA_AUTH_TOKEN
16
+ * });
17
+ */
18
+ import { WebSocketServer, WebSocket } from 'ws';
19
+ import type { Server as HTTPServer } from 'http';
20
+ /**
21
+ * Message router interface
22
+ */
23
+ interface MessageRouter {
24
+ process(message: NormalizedMessage): Promise<RouterResult>;
25
+ }
26
+ /**
27
+ * Session store interface
28
+ */
29
+ interface SessionStore {
30
+ getHistoryByChannel?(source: string, channelId: string): Array<{
31
+ user?: string;
32
+ bot?: string;
33
+ timestamp?: number;
34
+ }>;
35
+ getHistory?(sessionId: string): Array<{
36
+ user?: string;
37
+ bot?: string;
38
+ timestamp?: number;
39
+ }>;
40
+ }
41
+ /**
42
+ * Normalized message for router
43
+ */
44
+ interface NormalizedMessage {
45
+ source: string;
46
+ channelId: string;
47
+ channelName: string;
48
+ userId: string;
49
+ text: string;
50
+ contentBlocks?: ContentBlock[];
51
+ metadata: {
52
+ clientId: string;
53
+ sessionId?: string;
54
+ osAgentMode?: boolean;
55
+ timestamp: number;
56
+ };
57
+ }
58
+ /**
59
+ * Content block types
60
+ */
61
+ interface ImageContentBlock {
62
+ type: 'image';
63
+ source: {
64
+ type: 'base64';
65
+ media_type: string;
66
+ data: string;
67
+ };
68
+ }
69
+ interface TextContentBlock {
70
+ type: 'text';
71
+ text: string;
72
+ }
73
+ type ContentBlock = ImageContentBlock | TextContentBlock;
74
+ /**
75
+ * Router result
76
+ */
77
+ interface RouterResult {
78
+ response: string;
79
+ sessionId: string;
80
+ duration: number;
81
+ }
82
+ /**
83
+ * Client info stored in clients Map
84
+ */
85
+ interface ClientInfo {
86
+ clientId: string;
87
+ userId: string;
88
+ ws: WebSocket;
89
+ isAlive: boolean;
90
+ connectedAt: string;
91
+ sessionId?: string;
92
+ osAgentMode?: boolean;
93
+ language?: string;
94
+ }
95
+ /**
96
+ * WebSocket handler options
97
+ */
98
+ export interface WebSocketHandlerOptions {
99
+ httpServer: HTTPServer;
100
+ messageRouter: MessageRouter;
101
+ sessionStore: SessionStore;
102
+ authToken?: string;
103
+ }
104
+ /**
105
+ * Extended WebSocketServer with helper methods
106
+ */
107
+ type ExtendedWebSocketServer = WebSocketServer & {
108
+ getClients: () => Map<string, ClientInfo>;
109
+ getClientCount: () => number;
110
+ };
111
+ /**
112
+ * Create WebSocket handler with MessageRouter integration
113
+ */
114
+ export declare function createWebSocketHandler({ httpServer, messageRouter, sessionStore, authToken: _authToken, }: WebSocketHandlerOptions): ExtendedWebSocketServer;
115
+ /**
116
+ * WebSocketHandler class (backwards compatibility)
117
+ * @deprecated Use createWebSocketHandler() instead
118
+ */
119
+ export declare class WebSocketHandler {
120
+ private wss;
121
+ constructor(httpServer: HTTPServer, options: Partial<WebSocketHandlerOptions>);
122
+ getClients(): Map<string, ClientInfo>;
123
+ getClientCount(): number;
124
+ close(): void;
125
+ }
126
+ export {};
127
+ //# sourceMappingURL=websocket-handler.d.ts.map