@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,308 @@
1
+ "use strict";
2
+ /**
3
+ * MAMA (Memory-Augmented MCP Architecture) - Ollama Client Wrapper
4
+ *
5
+ * Simple wrapper for Ollama API with EXAONE 3.5 support
6
+ *
7
+ * @module ollama-client
8
+ */
9
+ var __importDefault = (this && this.__importDefault) || function (mod) {
10
+ return (mod && mod.__esModule) ? mod : { "default": mod };
11
+ };
12
+ Object.defineProperty(exports, "__esModule", { value: true });
13
+ exports.FALLBACK_MODEL = exports.DEFAULT_MODEL = void 0;
14
+ exports.generate = generate;
15
+ exports.analyzeDecision = analyzeDecision;
16
+ exports.analyzeQueryIntent = analyzeQueryIntent;
17
+ exports.isAvailable = isAvailable;
18
+ exports.listModels = listModels;
19
+ const http_1 = __importDefault(require("http"));
20
+ const debug_logger_js_1 = require("./debug-logger.js");
21
+ // Ollama configuration
22
+ const OLLAMA_HOST = process.env.OLLAMA_HOST || 'localhost';
23
+ const OLLAMA_PORT = parseInt(process.env.OLLAMA_PORT || '11434', 10);
24
+ exports.DEFAULT_MODEL = 'exaone3.5:2.4b';
25
+ exports.FALLBACK_MODEL = 'gemma:2b';
26
+ /**
27
+ * Call Ollama API
28
+ */
29
+ function callOllamaAPI(endpoint, payload, timeout = 30000) {
30
+ return new Promise((resolve, reject) => {
31
+ const postData = JSON.stringify(payload);
32
+ const options = {
33
+ hostname: OLLAMA_HOST,
34
+ port: OLLAMA_PORT,
35
+ path: endpoint,
36
+ method: 'POST',
37
+ headers: {
38
+ 'Content-Type': 'application/json',
39
+ 'Content-Length': Buffer.byteLength(postData),
40
+ },
41
+ };
42
+ const req = http_1.default.request(options, (res) => {
43
+ let data = '';
44
+ res.on('data', (chunk) => {
45
+ data += chunk;
46
+ });
47
+ res.on('end', () => {
48
+ if (res.statusCode && res.statusCode >= 200 && res.statusCode < 300) {
49
+ try {
50
+ // Ollama returns NDJSON (newline-delimited JSON)
51
+ const lines = data.trim().split('\n');
52
+ const response = JSON.parse(lines[lines.length - 1]);
53
+ resolve(response);
54
+ }
55
+ catch (error) {
56
+ const message = error instanceof Error ? error.message : String(error);
57
+ reject(new Error(`Failed to parse Ollama response: ${message}`));
58
+ }
59
+ }
60
+ else {
61
+ reject(new Error(`Ollama API error: ${res.statusCode} - ${data}`));
62
+ }
63
+ });
64
+ });
65
+ req.on('error', (error) => {
66
+ reject(new Error(`Ollama connection failed: ${error.message}`));
67
+ });
68
+ req.setTimeout(timeout, () => {
69
+ req.destroy();
70
+ reject(new Error(`Ollama request timeout (${timeout}ms)`));
71
+ });
72
+ req.write(postData);
73
+ req.end();
74
+ });
75
+ }
76
+ /**
77
+ * Generate text with EXAONE 3.5
78
+ */
79
+ async function generate(prompt, options = {}) {
80
+ const { model = exports.DEFAULT_MODEL, format = null, temperature = 0.7, max_tokens = 500, timeout = 30000, } = options;
81
+ const payload = {
82
+ model,
83
+ prompt,
84
+ stream: false,
85
+ options: {
86
+ temperature,
87
+ num_predict: max_tokens,
88
+ },
89
+ };
90
+ if (format === 'json') {
91
+ payload.format = 'json';
92
+ }
93
+ try {
94
+ const response = await callOllamaAPI('/api/generate', payload, timeout);
95
+ // Extract response text
96
+ const responseText = response.response;
97
+ // Parse JSON if requested
98
+ if (format === 'json') {
99
+ try {
100
+ return JSON.parse(responseText);
101
+ }
102
+ catch {
103
+ throw new Error(`Failed to parse JSON response: ${responseText}`);
104
+ }
105
+ }
106
+ return responseText;
107
+ }
108
+ catch (error) {
109
+ const message = error instanceof Error ? error.message : String(error);
110
+ // Try fallback model if EXAONE fails
111
+ const isModelNotFound = /model ['"].*['"] not found/i.test(message) ||
112
+ (message.includes('404') && message.toLowerCase().includes('not found'));
113
+ if (model === exports.DEFAULT_MODEL && isModelNotFound) {
114
+ (0, debug_logger_js_1.error)(`[MAMA] EXAONE not found, trying fallback (${exports.FALLBACK_MODEL})...`);
115
+ return generate(prompt, {
116
+ ...options,
117
+ model: exports.FALLBACK_MODEL,
118
+ });
119
+ }
120
+ throw error;
121
+ }
122
+ }
123
+ /**
124
+ * Validate DecisionAnalysisResult shape at runtime
125
+ */
126
+ function isDecisionAnalysisResult(obj) {
127
+ if (typeof obj !== 'object' || obj === null) {
128
+ return false;
129
+ }
130
+ const o = obj;
131
+ return (typeof o.is_decision === 'boolean' &&
132
+ (typeof o.topic === 'string' || o.topic === null) &&
133
+ (typeof o.decision === 'string' || o.decision === null) &&
134
+ typeof o.reasoning === 'string' &&
135
+ typeof o.confidence === 'number');
136
+ }
137
+ /**
138
+ * Validate QueryIntentResult shape at runtime
139
+ */
140
+ function isQueryIntentResult(obj) {
141
+ if (typeof obj !== 'object' || obj === null) {
142
+ return false;
143
+ }
144
+ const o = obj;
145
+ return (typeof o.involves_decision === 'boolean' &&
146
+ (typeof o.topic === 'string' || o.topic === null) &&
147
+ (o.query_type === 'recall' || o.query_type === 'evolution' || o.query_type === 'none') &&
148
+ typeof o.reasoning === 'string');
149
+ }
150
+ /**
151
+ * Analyze decision from tool execution
152
+ */
153
+ async function analyzeDecision(toolExecution, sessionContext) {
154
+ const prompt = `
155
+ Analyze if this represents a DECISION (not just an action):
156
+
157
+ Session Context:
158
+ - Latest User Message: ${sessionContext.latest_user_message || 'N/A'}
159
+ - Recent Exchange: ${sessionContext.recent_exchange || 'N/A'}
160
+
161
+ Tool Execution:
162
+ - Tool: ${toolExecution.tool_name ?? 'N/A'}
163
+ - Input: ${JSON.stringify(toolExecution.tool_input ?? null)}
164
+ - Result: ${toolExecution.exit_code !== undefined ? (toolExecution.exit_code === 0 ? 'SUCCESS' : 'FAILED') : 'UNKNOWN'}
165
+
166
+ Decision Indicators:
167
+ 1. User explicitly chose between alternatives?
168
+ Example: "Let's use JWT" (not "Use JWT" - that's just action)
169
+
170
+ 2. User changed previous approach?
171
+ Example: "Complex → Simple approach"
172
+
173
+ 3. User expressed preference?
174
+ Example: "Let's do it this way from now", "This approach is better"
175
+
176
+ 4. Significant architectural choice?
177
+ Example: "Mesh structure: COMPLEX", "Authentication: JWT"
178
+
179
+ Is this a DECISION? Return JSON with "topic" as a short snake_case identifier:
180
+ {
181
+ "is_decision": boolean,
182
+ "topic": string or null (extract main technical topic in snake_case, e.g., "mesh_structure", "database_choice", "auth_strategy"),
183
+ "decision": string or null (the actual choice made, e.g., "COMPLEX", "PostgreSQL", "JWT"),
184
+ "reasoning": "Why this is/isn't a decision",
185
+ "confidence": 0.0-1.0
186
+ }
187
+
188
+ IMPORTANT: Generate "topic" freely based on context. Do NOT limit to predefined values.
189
+ `;
190
+ try {
191
+ const response = await generate(prompt, {
192
+ format: 'json',
193
+ temperature: 0.3,
194
+ max_tokens: 300,
195
+ });
196
+ if (!isDecisionAnalysisResult(response)) {
197
+ throw new Error('Invalid LLM response shape for DecisionAnalysisResult');
198
+ }
199
+ return response;
200
+ }
201
+ catch (error) {
202
+ const message = error instanceof Error ? error.message : String(error);
203
+ (0, debug_logger_js_1.error)(`[MAMA] Decision analysis FAILED: ${message}`);
204
+ throw new Error(`Decision analysis failed: ${message}`);
205
+ }
206
+ }
207
+ /**
208
+ * Analyze query intent
209
+ */
210
+ async function analyzeQueryIntent(userMessage) {
211
+ const prompt = `
212
+ Analyze this user message to determine if it involves past decisions:
213
+
214
+ User Message: "${userMessage}"
215
+
216
+ Questions to answer:
217
+ 1. Does this query reference past decisions or choices?
218
+ 2. Is the user asking about previous approaches?
219
+ 3. What topic is being discussed? (e.g., "mesh_structure", "authentication", "testing")
220
+
221
+ Return JSON:
222
+ {
223
+ "involves_decision": boolean,
224
+ "topic": "topic_name" | null,
225
+ "query_type": "recall" | "evolution" | "none",
226
+ "reasoning": "Why this involves/doesn't involve decisions"
227
+ }
228
+ `;
229
+ try {
230
+ const response = await generate(prompt, {
231
+ format: 'json',
232
+ temperature: 0.3,
233
+ max_tokens: 200,
234
+ });
235
+ if (!isQueryIntentResult(response)) {
236
+ throw new Error('Invalid LLM response shape for QueryIntentResult');
237
+ }
238
+ return response;
239
+ }
240
+ catch (error) {
241
+ const message = error instanceof Error ? error.message : String(error);
242
+ (0, debug_logger_js_1.error)(`[MAMA] Query intent analysis FAILED: ${message}`);
243
+ throw new Error(`Query intent analysis failed: ${message}`);
244
+ }
245
+ }
246
+ /**
247
+ * Check if Ollama is available
248
+ */
249
+ async function isAvailable() {
250
+ return new Promise((resolve) => {
251
+ const options = {
252
+ hostname: OLLAMA_HOST,
253
+ port: OLLAMA_PORT,
254
+ path: '/api/tags',
255
+ method: 'GET',
256
+ timeout: 2000,
257
+ };
258
+ const req = http_1.default.request(options, (res) => {
259
+ res.resume(); // Drain response body to release socket back to pool
260
+ resolve(res.statusCode !== undefined && res.statusCode >= 200 && res.statusCode < 300);
261
+ });
262
+ req.on('error', () => resolve(false));
263
+ req.on('timeout', () => {
264
+ req.destroy();
265
+ resolve(false);
266
+ });
267
+ req.end();
268
+ });
269
+ }
270
+ /**
271
+ * List available models
272
+ */
273
+ async function listModels() {
274
+ return new Promise((resolve, reject) => {
275
+ const options = {
276
+ hostname: OLLAMA_HOST,
277
+ port: OLLAMA_PORT,
278
+ path: '/api/tags',
279
+ method: 'GET',
280
+ timeout: 5000,
281
+ };
282
+ const req = http_1.default.request(options, (res) => {
283
+ let data = '';
284
+ res.on('data', (chunk) => {
285
+ data += chunk;
286
+ });
287
+ res.on('end', () => {
288
+ try {
289
+ const response = JSON.parse(data);
290
+ resolve(response.models?.map((m) => m.name) || []);
291
+ }
292
+ catch (error) {
293
+ const message = error instanceof Error ? error.message : String(error);
294
+ reject(new Error(`Failed to parse models response: ${message}`));
295
+ }
296
+ });
297
+ });
298
+ req.on('error', (error) => {
299
+ reject(new Error(`Failed to list models: ${error.message}`));
300
+ });
301
+ req.on('timeout', () => {
302
+ req.destroy();
303
+ reject(new Error('List models timeout'));
304
+ });
305
+ req.end();
306
+ });
307
+ }
308
+ //# sourceMappingURL=ollama-client.js.map
@@ -0,0 +1,165 @@
1
+ /**
2
+ * MAMA (Memory-Augmented MCP Architecture) - Outcome Tracker
3
+ *
4
+ * Track decision outcomes from user feedback
5
+ * Tasks: 4.1-4.8 (Failure/success indicators, UserPromptSubmit analysis, outcome marking)
6
+ * AC #3: Failure tracking (user feedback → outcome marked, failure_reason extracted, duration calculated)
7
+ *
8
+ * @module outcome-tracker
9
+ * @version 1.0
10
+ * @date 2025-11-14
11
+ */
12
+ /**
13
+ * Decision record from database
14
+ */
15
+ interface DecisionRecord {
16
+ id: string;
17
+ topic: string;
18
+ decision: string;
19
+ outcome?: string | null;
20
+ confidence?: number;
21
+ created_at: number;
22
+ }
23
+ /**
24
+ * Hook context from Claude Code
25
+ */
26
+ export interface HookContext {
27
+ user_message?: string;
28
+ session_id?: string;
29
+ }
30
+ /**
31
+ * Failure indicators
32
+ * Task 4.2: Define failure indicators
33
+ */
34
+ export declare const FAILURE_INDICATORS: RegExp[];
35
+ /**
36
+ * Success indicators
37
+ * Task 4.3: Define success indicators
38
+ */
39
+ export declare const SUCCESS_INDICATORS: RegExp[];
40
+ /**
41
+ * Partial success indicators
42
+ * Task 4.3: Define partial success indicators
43
+ */
44
+ export declare const PARTIAL_INDICATORS: RegExp[];
45
+ /**
46
+ * Recent decision time window (1 hour in milliseconds)
47
+ * Task 4.5: Only mark outcome if decision is recent (< 1 hour)
48
+ */
49
+ export declare const RECENT_WINDOW_MS: number;
50
+ /**
51
+ * Check if message matches failure indicators
52
+ *
53
+ * Task 4.2: Match failure patterns
54
+ *
55
+ * @param message - User message
56
+ * @returns True if failure detected
57
+ */
58
+ export declare function matchesFailureIndicators(message: string): boolean;
59
+ /**
60
+ * Check if message matches success indicators
61
+ *
62
+ * Task 4.3: Match success patterns
63
+ *
64
+ * @param message - User message
65
+ * @returns True if success detected
66
+ */
67
+ export declare function matchesSuccessIndicators(message: string): boolean;
68
+ /**
69
+ * Check if message matches partial success indicators
70
+ *
71
+ * Task 4.3: Match partial success patterns
72
+ *
73
+ * @param message - User message
74
+ * @returns True if partial success detected
75
+ */
76
+ export declare function matchesPartialIndicators(message: string): boolean;
77
+ /**
78
+ * Outcome type from analysis
79
+ */
80
+ export type OutcomeType = 'FAILED' | 'SUCCESS' | 'PARTIAL';
81
+ /**
82
+ * Determine outcome from user message
83
+ *
84
+ * Task 4.4, 4.5: Analyze user message for indicators
85
+ * AC #3: Failure tracking from user feedback
86
+ *
87
+ * @param message - User message
88
+ * @returns Outcome type ('FAILED', 'SUCCESS', 'PARTIAL') or null
89
+ */
90
+ export declare function analyzeOutcome(message: string): OutcomeType | null;
91
+ /**
92
+ * Extract failure reason from user message
93
+ *
94
+ * Task 4.6: Extract failure_reason from user message
95
+ * AC #3: failure_reason extracted
96
+ *
97
+ * Simple extraction: First sentence or first 200 characters
98
+ * Future: Use LLM for better extraction
99
+ *
100
+ * @param message - User message
101
+ * @param outcome - Outcome type
102
+ * @returns Failure reason
103
+ */
104
+ export declare function extractFailureReason(message: string, outcome: OutcomeType | null): string | null;
105
+ /**
106
+ * Get recent decision (within 1 hour)
107
+ *
108
+ * Task 4.5: Find recent decision (< 1 hour)
109
+ * AC #3: Recent decision (< 1 hour) marked
110
+ *
111
+ * @param sessionId - Session ID
112
+ * @returns Recent decision or null
113
+ */
114
+ export declare function getRecentDecision(sessionId: string): DecisionRecord | null;
115
+ /**
116
+ * Calculate duration in days
117
+ *
118
+ * Task 4.7: Calculate duration_days
119
+ * AC #3: duration_days calculated
120
+ *
121
+ * @param createdAt - Decision created timestamp
122
+ * @returns Duration in days
123
+ */
124
+ export declare function calculateDurationDays(createdAt: number): number;
125
+ /**
126
+ * Get evidence impact for outcome
127
+ *
128
+ * Task 6: Confidence evolution - Calculate impact based on outcome
129
+ * AC #5: Confidence score calculated based on history
130
+ *
131
+ * @param outcome - Outcome type ('FAILED', 'SUCCESS', 'PARTIAL')
132
+ * @param durationDays - Duration in days
133
+ * @returns Impact on confidence
134
+ */
135
+ export declare function getEvidenceImpact(outcome: OutcomeType, durationDays: number): number;
136
+ /**
137
+ * Mark decision outcome
138
+ *
139
+ * Task 4.8: Update decision row with outcome, failure_reason, duration_days
140
+ * Task 6.5: Update confidence when outcome is marked
141
+ * AC #3: Outcome marked with failure_reason and duration_days
142
+ * AC #5: Confidence evolution
143
+ *
144
+ * @param decisionId - Decision ID
145
+ * @param outcome - Outcome type ('FAILED', 'SUCCESS', 'PARTIAL')
146
+ * @param failureReason - Failure reason (if outcome=FAILED)
147
+ * @param durationDays - Duration in days
148
+ */
149
+ export declare function markOutcome(decisionId: string, outcome: OutcomeType, failureReason: string | null, durationDays: number): Promise<void>;
150
+ /**
151
+ * UserPromptSubmit Handler
152
+ *
153
+ * Task 4.4: On UserPromptSubmit, analyze user message for indicators
154
+ * Task 4.5: If matches + recent decision (< 1 hour), mark outcome
155
+ * Task 4.6: Extract failure_reason from user message
156
+ * Task 4.7: Calculate duration_days
157
+ * Task 4.8: Update decision row
158
+ *
159
+ * AC #3: Failure tracking (user feedback → outcome marked)
160
+ *
161
+ * @param hookContext - Hook context from Claude Code
162
+ */
163
+ export declare function onUserPromptSubmit(hookContext: HookContext): Promise<void>;
164
+ export {};
165
+ //# sourceMappingURL=outcome-tracker.d.ts.map