@jungjaehoon/mama-core 1.1.2 → 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,124 @@
1
+ /**
2
+ * MAMA (Memory-Augmented MCP Architecture) - Relevance Scorer
3
+ *
4
+ * Relevance scoring formula for decision ranking and top-N selection
5
+ * Tasks: 1.1-1.4, 2.1-2.7 (Relevance scoring and top-N selection)
6
+ * AC #1, #4, #5: Decision relevance, failure priority boost, top-N selection
7
+ *
8
+ * @module relevance-scorer
9
+ * @version 1.0
10
+ * @date 2025-11-14
11
+ */
12
+ /**
13
+ * Decision object for relevance scoring
14
+ */
15
+ export interface DecisionWithEmbedding {
16
+ id?: string;
17
+ topic?: string;
18
+ decision: string;
19
+ reasoning?: string | null;
20
+ outcome?: string | null;
21
+ failure_reason?: string | null;
22
+ user_involvement?: string;
23
+ confidence?: number;
24
+ created_at: number;
25
+ updated_at?: number;
26
+ embedding?: Float32Array;
27
+ relevanceScore?: number;
28
+ }
29
+ /**
30
+ * Query context for relevance calculation
31
+ */
32
+ export interface QueryContext {
33
+ embedding?: Float32Array;
34
+ }
35
+ /**
36
+ * Formatted context result
37
+ */
38
+ export interface FormattedContext {
39
+ full: Array<{
40
+ decision_id?: string;
41
+ topic?: string;
42
+ decision: string;
43
+ reasoning?: string | null;
44
+ outcome?: string | null;
45
+ failure_reason?: string | null;
46
+ user_involvement?: string;
47
+ confidence?: number;
48
+ relevanceScore?: number;
49
+ created_at: number;
50
+ }>;
51
+ summary: {
52
+ count: number;
53
+ duration_days: number;
54
+ failures: Array<{
55
+ decision: string;
56
+ reason: string | null | undefined;
57
+ }>;
58
+ } | null;
59
+ }
60
+ /**
61
+ * Calculate relevance score for a single decision
62
+ *
63
+ * Task 1.2: Implement calculateRelevance(decision, queryContext) function
64
+ * AC #1, #4: Relevance scoring with failure priority boost
65
+ *
66
+ * Formula:
67
+ * Relevance = (Recency × 0.2) + (Importance × 0.5) + (Semantic × 0.3)
68
+ *
69
+ * Where:
70
+ * - Recency: exp(-days_since / 30) [30-day half-life]
71
+ * - Importance: OUTCOME_WEIGHTS[outcome]
72
+ * - FAILED: 1.0 (highest - failures are most valuable)
73
+ * - PARTIAL: 0.7
74
+ * - SUCCESS: 0.5
75
+ * - null: 0.3 (ongoing, lowest)
76
+ * - Semantic: cosineSimilarity(decision.embedding, query.embedding)
77
+ *
78
+ * @param decision - Decision object
79
+ * @param queryContext - Query context
80
+ * @returns Relevance score (0.0-1.0)
81
+ */
82
+ export declare function calculateRelevance(decision: DecisionWithEmbedding, queryContext: QueryContext): number;
83
+ /**
84
+ * Select top N most relevant decisions
85
+ *
86
+ * Task 2.1: Add selectTopDecisions(decisions, queryContext, n=3) function
87
+ * AC #1, #5: Top-N selection with threshold filtering
88
+ *
89
+ * @param decisions - Array of decision objects
90
+ * @param queryContext - Query context with embedding
91
+ * @param n - Number of top decisions to return (default: 3)
92
+ * @returns Top N decisions with relevance scores
93
+ */
94
+ export declare function selectTopDecisions(decisions: DecisionWithEmbedding[], queryContext: QueryContext, n?: number): DecisionWithEmbedding[];
95
+ /**
96
+ * Format decisions with top-N selection and summary
97
+ *
98
+ * Task 8.2-8.3: Format top 3 in full detail, rest as summary
99
+ * AC #5: Top-N selection with summary
100
+ *
101
+ * @param decisions - All decisions (sorted by relevance)
102
+ * @param topN - Number of decisions to show in full detail (default: 3)
103
+ * @returns Formatted context {full: Array, summary: Object}
104
+ */
105
+ export declare function formatTopNContext(decisions: DecisionWithEmbedding[], topN?: number): FormattedContext;
106
+ /**
107
+ * Test result for relevance scoring
108
+ */
109
+ export interface TestResult {
110
+ name: string;
111
+ expected: string;
112
+ calculated: string;
113
+ pass: boolean;
114
+ }
115
+ /**
116
+ * Test relevance scoring with sample decisions
117
+ *
118
+ * Task 1.4: Test relevance scoring with sample decisions
119
+ * AC #1, #4: Verify scoring formula and failure priority
120
+ *
121
+ * @returns Test results
122
+ */
123
+ export declare function testRelevanceScoring(): TestResult[];
124
+ //# sourceMappingURL=relevance-scorer.d.ts.map
@@ -0,0 +1,243 @@
1
+ "use strict";
2
+ /**
3
+ * MAMA (Memory-Augmented MCP Architecture) - Relevance Scorer
4
+ *
5
+ * Relevance scoring formula for decision ranking and top-N selection
6
+ * Tasks: 1.1-1.4, 2.1-2.7 (Relevance scoring and top-N selection)
7
+ * AC #1, #4, #5: Decision relevance, failure priority boost, top-N selection
8
+ *
9
+ * @module relevance-scorer
10
+ * @version 1.0
11
+ * @date 2025-11-14
12
+ */
13
+ Object.defineProperty(exports, "__esModule", { value: true });
14
+ exports.calculateRelevance = calculateRelevance;
15
+ exports.selectTopDecisions = selectTopDecisions;
16
+ exports.formatTopNContext = formatTopNContext;
17
+ exports.testRelevanceScoring = testRelevanceScoring;
18
+ const embeddings_js_1 = require("./embeddings.js");
19
+ /**
20
+ * Outcome weights for importance scoring
21
+ */
22
+ const OUTCOME_WEIGHTS = {
23
+ FAILED: 1.0, // Highest - failures are most valuable (AC #4)
24
+ PARTIAL: 0.7,
25
+ SUCCESS: 0.5,
26
+ pending: 0.3, // Ongoing/pending, lowest
27
+ };
28
+ /**
29
+ * Calculate relevance score for a single decision
30
+ *
31
+ * Task 1.2: Implement calculateRelevance(decision, queryContext) function
32
+ * AC #1, #4: Relevance scoring with failure priority boost
33
+ *
34
+ * Formula:
35
+ * Relevance = (Recency × 0.2) + (Importance × 0.5) + (Semantic × 0.3)
36
+ *
37
+ * Where:
38
+ * - Recency: exp(-days_since / 30) [30-day half-life]
39
+ * - Importance: OUTCOME_WEIGHTS[outcome]
40
+ * - FAILED: 1.0 (highest - failures are most valuable)
41
+ * - PARTIAL: 0.7
42
+ * - SUCCESS: 0.5
43
+ * - null: 0.3 (ongoing, lowest)
44
+ * - Semantic: cosineSimilarity(decision.embedding, query.embedding)
45
+ *
46
+ * @param decision - Decision object
47
+ * @param queryContext - Query context
48
+ * @returns Relevance score (0.0-1.0)
49
+ */
50
+ function calculateRelevance(decision, queryContext) {
51
+ // ═══════════════════════════════════════════════════════════
52
+ // Recency Score (20%)
53
+ // ═══════════════════════════════════════════════════════════
54
+ // Exponential decay with 30-day half-life
55
+ const daysSince = (Date.now() - decision.created_at) / (1000 * 60 * 60 * 24);
56
+ const recencyScore = Math.exp(-daysSince / 30);
57
+ // Decay curve:
58
+ // 0 days = 1.0
59
+ // 30 days = 0.5
60
+ // 60 days = 0.25
61
+ // 90 days = 0.125
62
+ // ═══════════════════════════════════════════════════════════
63
+ // Importance Score (50%) - AC #4: Failure Priority Boost
64
+ // ═══════════════════════════════════════════════════════════
65
+ // Use explicit null check to avoid confusion with object key access
66
+ const outcomeKey = decision.outcome ?? 'pending';
67
+ const importanceScore = OUTCOME_WEIGHTS[outcomeKey] ?? OUTCOME_WEIGHTS.pending;
68
+ // ═══════════════════════════════════════════════════════════
69
+ // Semantic Score (30%)
70
+ // ═══════════════════════════════════════════════════════════
71
+ let semanticScore = 0;
72
+ if (decision.embedding && queryContext.embedding) {
73
+ // Task 1.3: Use cosine similarity function
74
+ semanticScore = (0, embeddings_js_1.cosineSimilarity)(decision.embedding, queryContext.embedding);
75
+ }
76
+ else {
77
+ // Fallback: no semantic match if embeddings missing
78
+ semanticScore = 0;
79
+ }
80
+ // ═══════════════════════════════════════════════════════════
81
+ // Weighted Sum (Total: 100%)
82
+ // ═══════════════════════════════════════════════════════════
83
+ const relevance = recencyScore * 0.2 + importanceScore * 0.5 + semanticScore * 0.3;
84
+ return relevance;
85
+ }
86
+ /**
87
+ * Select top N most relevant decisions
88
+ *
89
+ * Task 2.1: Add selectTopDecisions(decisions, queryContext, n=3) function
90
+ * AC #1, #5: Top-N selection with threshold filtering
91
+ *
92
+ * @param decisions - Array of decision objects
93
+ * @param queryContext - Query context with embedding
94
+ * @param n - Number of top decisions to return (default: 3)
95
+ * @returns Top N decisions with relevance scores
96
+ */
97
+ function selectTopDecisions(decisions, queryContext, n = 3) {
98
+ if (!Array.isArray(decisions) || decisions.length === 0) {
99
+ return [];
100
+ }
101
+ // Task 2.3: Score all results by relevance
102
+ const decisionsWithScores = decisions.map((decision) => ({
103
+ ...decision,
104
+ relevanceScore: calculateRelevance(decision, queryContext),
105
+ }));
106
+ // Task 2.4: Sort descending (highest relevance first)
107
+ decisionsWithScores.sort((a, b) => (b.relevanceScore ?? 0) - (a.relevanceScore ?? 0));
108
+ // Task 2.6: Filter out < 0.5 relevance (AC #1)
109
+ const filtered = decisionsWithScores.filter((d) => (d.relevanceScore ?? 0) >= 0.5);
110
+ // Task 2.5: Return top 3 (or top N)
111
+ const topN = filtered.slice(0, n);
112
+ return topN;
113
+ }
114
+ /**
115
+ * Format decisions with top-N selection and summary
116
+ *
117
+ * Task 8.2-8.3: Format top 3 in full detail, rest as summary
118
+ * AC #5: Top-N selection with summary
119
+ *
120
+ * @param decisions - All decisions (sorted by relevance)
121
+ * @param topN - Number of decisions to show in full detail (default: 3)
122
+ * @returns Formatted context {full: Array, summary: Object}
123
+ */
124
+ function formatTopNContext(decisions, topN = 3) {
125
+ if (!Array.isArray(decisions) || decisions.length === 0) {
126
+ return { full: [], summary: null };
127
+ }
128
+ // Split into top N and rest
129
+ const fullDetailDecisions = decisions.slice(0, topN);
130
+ const summaryDecisions = decisions.slice(topN);
131
+ // Full detail for top N
132
+ const full = fullDetailDecisions.map((d) => ({
133
+ decision_id: d.id,
134
+ topic: d.topic,
135
+ decision: d.decision,
136
+ reasoning: d.reasoning,
137
+ outcome: d.outcome,
138
+ failure_reason: d.failure_reason,
139
+ user_involvement: d.user_involvement,
140
+ confidence: d.confidence,
141
+ relevanceScore: d.relevanceScore,
142
+ created_at: d.created_at,
143
+ }));
144
+ // Summary for rest (count, duration, key failures only)
145
+ let summary = null;
146
+ if (summaryDecisions.length > 0) {
147
+ // Calculate duration (oldest to newest)
148
+ const oldestTimestamp = Math.min(...summaryDecisions.map((d) => d.created_at));
149
+ const newestTimestamp = Math.max(...summaryDecisions.map((d) => d.created_at));
150
+ const durationDays = Math.floor((newestTimestamp - oldestTimestamp) / (1000 * 60 * 60 * 24));
151
+ // Extract key failures
152
+ const failures = summaryDecisions
153
+ .filter((d) => d.outcome === 'FAILED')
154
+ .map((d) => ({ decision: d.decision, reason: d.failure_reason }));
155
+ summary = {
156
+ count: summaryDecisions.length,
157
+ duration_days: durationDays,
158
+ failures: failures.slice(0, 3), // Show max 3 failures
159
+ };
160
+ }
161
+ return { full, summary };
162
+ }
163
+ /**
164
+ * Test relevance scoring with sample decisions
165
+ *
166
+ * Task 1.4: Test relevance scoring with sample decisions
167
+ * AC #1, #4: Verify scoring formula and failure priority
168
+ *
169
+ * @returns Test results
170
+ */
171
+ function testRelevanceScoring() {
172
+ const now = Date.now();
173
+ // Mock embeddings (dummy for testing)
174
+ const queryEmbedding = new Float32Array(384).fill(0.5);
175
+ const decisionEmbedding1 = new Float32Array(384).fill(0.5); // Identical (similarity = 1.0)
176
+ // eslint-disable-next-line @typescript-eslint/no-unused-vars
177
+ const _decisionEmbedding2 = new Float32Array(384).fill(0.3); // Different (similarity < 1.0)
178
+ const scenarios = [
179
+ // Scenario 1: Recent FAILED decision (should have highest relevance)
180
+ {
181
+ name: 'Recent FAILED decision',
182
+ decision: {
183
+ created_at: now - 5 * 24 * 60 * 60 * 1000, // 5 days ago
184
+ outcome: 'FAILED',
185
+ embedding: decisionEmbedding1,
186
+ decision: 'test decision',
187
+ },
188
+ queryContext: { embedding: queryEmbedding },
189
+ expected: {
190
+ recency: 0.85, // exp(-5/30) ≈ 0.85
191
+ importance: 1.0, // FAILED = 1.0 (AC #4)
192
+ semantic: 1.0, // Identical embeddings
193
+ relevance: 0.87, // (0.85×0.2) + (1.0×0.5) + (1.0×0.3)
194
+ },
195
+ },
196
+ // Scenario 2: Recent SUCCESS decision (lower importance)
197
+ {
198
+ name: 'Recent SUCCESS decision',
199
+ decision: {
200
+ created_at: now - 5 * 24 * 60 * 60 * 1000, // 5 days ago
201
+ outcome: 'SUCCESS',
202
+ embedding: decisionEmbedding1,
203
+ decision: 'test decision',
204
+ },
205
+ queryContext: { embedding: queryEmbedding },
206
+ expected: {
207
+ recency: 0.85,
208
+ importance: 0.5, // SUCCESS = 0.5
209
+ semantic: 1.0,
210
+ relevance: 0.62, // (0.85×0.2) + (0.5×0.5) + (1.0×0.3)
211
+ },
212
+ },
213
+ // Scenario 3: Old FAILED decision (recency decay)
214
+ {
215
+ name: 'Old FAILED decision',
216
+ decision: {
217
+ created_at: now - 60 * 24 * 60 * 60 * 1000, // 60 days ago
218
+ outcome: 'FAILED',
219
+ embedding: decisionEmbedding1,
220
+ decision: 'test decision',
221
+ },
222
+ queryContext: { embedding: queryEmbedding },
223
+ expected: {
224
+ recency: 0.25, // exp(-60/30) ≈ 0.25
225
+ importance: 1.0,
226
+ semantic: 1.0,
227
+ relevance: 0.85, // (0.25×0.2) + (1.0×0.5) + (1.0×0.3)
228
+ },
229
+ },
230
+ ];
231
+ const results = scenarios.map((scenario) => {
232
+ const calculated = calculateRelevance(scenario.decision, scenario.queryContext);
233
+ const pass = Math.abs(calculated - scenario.expected.relevance) < 0.05;
234
+ return {
235
+ name: scenario.name,
236
+ expected: scenario.expected.relevance.toFixed(2),
237
+ calculated: calculated.toFixed(2),
238
+ pass,
239
+ };
240
+ });
241
+ return results;
242
+ }
243
+ //# sourceMappingURL=relevance-scorer.js.map
@@ -0,0 +1,66 @@
1
+ /**
2
+ * MAMA Core Test Utilities
3
+ *
4
+ * Shared test helpers for mama-core consumers.
5
+ * Optimizes test performance by sharing expensive resources (embedding model, DB adapter).
6
+ *
7
+ * @module test-utils
8
+ * @version 1.1
9
+ */
10
+ /**
11
+ * Preload embedding model (call once in globalSetup)
12
+ *
13
+ * This loads the embedding model into memory so subsequent tests don't pay the ~2s load time.
14
+ * The model stays in memory due to singleton pattern in embeddings.ts.
15
+ */
16
+ export declare function preloadEmbeddingModel(): Promise<void>;
17
+ /**
18
+ * Create isolated test database
19
+ *
20
+ * Creates a unique test database and sets MAMA_DB_PATH.
21
+ * Use in beforeAll() of each test file.
22
+ *
23
+ * @param testName - Unique test identifier (e.g., 'search-narrative')
24
+ * @returns Test database path
25
+ */
26
+ export declare function initTestDB(testName: string): Promise<string>;
27
+ /**
28
+ * Cleanup test database
29
+ *
30
+ * Call in afterAll() to clean up test database files.
31
+ *
32
+ * @param testDbPath - Path returned by initTestDB
33
+ */
34
+ export declare function cleanupTestDB(testDbPath?: string): Promise<void>;
35
+ /**
36
+ * Cleanup all test databases
37
+ *
38
+ * Call in globalTeardown to clean up all test databases.
39
+ */
40
+ export declare function cleanupAllTestDBs(): void;
41
+ /**
42
+ * Check if embeddings are available
43
+ *
44
+ * Returns false if embedding model failed to load (e.g., CI without ONNX).
45
+ * Use to conditionally skip semantic search tests.
46
+ */
47
+ export declare function isEmbeddingsAvailable(): Promise<boolean>;
48
+ /**
49
+ * Create mock tool context
50
+ *
51
+ * Returns a mock context object for MCP tool tests.
52
+ */
53
+ export declare function createMockToolContext(): {
54
+ logger: {
55
+ info: () => void;
56
+ warn: () => void;
57
+ error: () => void;
58
+ };
59
+ };
60
+ /**
61
+ * Suppress console output during tests
62
+ *
63
+ * Returns restore function to call after test.
64
+ */
65
+ export declare function suppressConsole(): () => void;
66
+ //# sourceMappingURL=test-utils.d.ts.map
@@ -0,0 +1,166 @@
1
+ "use strict";
2
+ /**
3
+ * MAMA Core Test Utilities
4
+ *
5
+ * Shared test helpers for mama-core consumers.
6
+ * Optimizes test performance by sharing expensive resources (embedding model, DB adapter).
7
+ *
8
+ * @module test-utils
9
+ * @version 1.1
10
+ */
11
+ var __importDefault = (this && this.__importDefault) || function (mod) {
12
+ return (mod && mod.__esModule) ? mod : { "default": mod };
13
+ };
14
+ Object.defineProperty(exports, "__esModule", { value: true });
15
+ exports.preloadEmbeddingModel = preloadEmbeddingModel;
16
+ exports.initTestDB = initTestDB;
17
+ exports.cleanupTestDB = cleanupTestDB;
18
+ exports.cleanupAllTestDBs = cleanupAllTestDBs;
19
+ exports.isEmbeddingsAvailable = isEmbeddingsAvailable;
20
+ exports.createMockToolContext = createMockToolContext;
21
+ exports.suppressConsole = suppressConsole;
22
+ const path_1 = __importDefault(require("path"));
23
+ const fs_1 = __importDefault(require("fs"));
24
+ const os_1 = __importDefault(require("os"));
25
+ const db_manager_js_1 = require("./db-manager.js");
26
+ const debug_logger_js_1 = require("./debug-logger.js");
27
+ // Track test databases for cleanup
28
+ const testDatabases = [];
29
+ // Embedding model preload state
30
+ let embeddingModelPreloaded = false;
31
+ /**
32
+ * Preload embedding model (call once in globalSetup)
33
+ *
34
+ * This loads the embedding model into memory so subsequent tests don't pay the ~2s load time.
35
+ * The model stays in memory due to singleton pattern in embeddings.ts.
36
+ */
37
+ async function preloadEmbeddingModel() {
38
+ if (embeddingModelPreloaded) {
39
+ return;
40
+ }
41
+ try {
42
+ const { generateEmbedding } = await import('./embeddings.js');
43
+ await generateEmbedding('preload');
44
+ embeddingModelPreloaded = true;
45
+ }
46
+ catch (error) {
47
+ // Non-fatal: some CI environments may not have ONNX runtime
48
+ const message = error instanceof Error ? error.message : String(error);
49
+ (0, debug_logger_js_1.warn)(`[test-utils] Embedding model preload failed: ${message}`);
50
+ }
51
+ }
52
+ /**
53
+ * Create isolated test database
54
+ *
55
+ * Creates a unique test database and sets MAMA_DB_PATH.
56
+ * Use in beforeAll() of each test file.
57
+ *
58
+ * @param testName - Unique test identifier (e.g., 'search-narrative')
59
+ * @returns Test database path
60
+ */
61
+ async function initTestDB(testName) {
62
+ // Reset any existing DB state first
63
+ (0, db_manager_js_1.resetDBState)({ disconnect: true });
64
+ // Create unique test database path
65
+ const testDbPath = path_1.default.join(os_1.default.tmpdir(), `mama-test-${testName}-${Date.now()}.db`);
66
+ // Clean up any existing files
67
+ cleanupDbFiles(testDbPath);
68
+ // Set environment variable
69
+ process.env.MAMA_DB_PATH = testDbPath;
70
+ // Track for cleanup
71
+ testDatabases.push(testDbPath);
72
+ // Initialize database
73
+ await (0, db_manager_js_1.initDB)();
74
+ return testDbPath;
75
+ }
76
+ /**
77
+ * Cleanup test database
78
+ *
79
+ * Call in afterAll() to clean up test database files.
80
+ *
81
+ * @param testDbPath - Path returned by initTestDB
82
+ */
83
+ async function cleanupTestDB(testDbPath) {
84
+ // Close database connection
85
+ await (0, db_manager_js_1.closeDB)();
86
+ // Clean up files
87
+ if (testDbPath) {
88
+ cleanupDbFiles(testDbPath);
89
+ }
90
+ }
91
+ /**
92
+ * Cleanup all test databases
93
+ *
94
+ * Call in globalTeardown to clean up all test databases.
95
+ */
96
+ function cleanupAllTestDBs() {
97
+ for (const dbPath of testDatabases) {
98
+ cleanupDbFiles(dbPath);
99
+ }
100
+ testDatabases.length = 0;
101
+ }
102
+ /**
103
+ * Helper to clean up SQLite database files
104
+ */
105
+ function cleanupDbFiles(dbPath) {
106
+ const files = [dbPath, `${dbPath}-wal`, `${dbPath}-shm`];
107
+ for (const file of files) {
108
+ try {
109
+ if (fs_1.default.existsSync(file)) {
110
+ fs_1.default.unlinkSync(file);
111
+ }
112
+ }
113
+ catch {
114
+ // Ignore cleanup errors
115
+ }
116
+ }
117
+ }
118
+ /**
119
+ * Check if embeddings are available
120
+ *
121
+ * Returns false if embedding model failed to load (e.g., CI without ONNX).
122
+ * Use to conditionally skip semantic search tests.
123
+ */
124
+ async function isEmbeddingsAvailable() {
125
+ try {
126
+ const { generateEmbedding } = await import('./embeddings.js');
127
+ await generateEmbedding('test');
128
+ return true;
129
+ }
130
+ catch {
131
+ return false;
132
+ }
133
+ }
134
+ /**
135
+ * Create mock tool context
136
+ *
137
+ * Returns a mock context object for MCP tool tests.
138
+ */
139
+ function createMockToolContext() {
140
+ return {
141
+ logger: {
142
+ info: () => { },
143
+ warn: () => { },
144
+ error: () => { },
145
+ },
146
+ };
147
+ }
148
+ /**
149
+ * Suppress console output during tests
150
+ *
151
+ * Returns restore function to call after test.
152
+ */
153
+ function suppressConsole() {
154
+ const originalLog = console.log;
155
+ const originalWarn = console.warn;
156
+ const originalError = console.error;
157
+ console.log = () => { };
158
+ console.warn = () => { };
159
+ console.error = () => { };
160
+ return () => {
161
+ console.log = originalLog;
162
+ console.warn = originalWarn;
163
+ console.error = originalError;
164
+ };
165
+ }
166
+ //# sourceMappingURL=test-utils.js.map
@@ -0,0 +1,55 @@
1
+ /**
2
+ * MAMA Tier Validator
3
+ *
4
+ * Centralized tier validation module for MAMA.
5
+ * Validates system requirements and determines tier status (1 or 2).
6
+ *
7
+ * Tier 1: Full features (Node.js 18+, SQLite, Embeddings, Database)
8
+ * Tier 2: Degraded mode (missing one or more requirements)
9
+ *
10
+ * @module tier-validator
11
+ */
12
+ export interface CheckResult {
13
+ status: 'pass' | 'fail';
14
+ details: string;
15
+ }
16
+ export interface NamedCheckResult extends CheckResult {
17
+ name: string;
18
+ }
19
+ export interface TierValidation {
20
+ tier: 1 | 2;
21
+ checks: NamedCheckResult[];
22
+ }
23
+ /**
24
+ * Validates Node.js version requirement
25
+ */
26
+ export declare function checkNodeVersion(): CheckResult;
27
+ /**
28
+ * Validates SQLite (better-sqlite3) availability
29
+ */
30
+ export declare function checkSQLite(): CheckResult;
31
+ /**
32
+ * Validates embedding model availability
33
+ */
34
+ export declare function checkEmbeddings(): CheckResult;
35
+ /**
36
+ * Validates database file accessibility
37
+ */
38
+ export declare function checkDatabase(): CheckResult;
39
+ /**
40
+ * Validates MAMA tier status
41
+ *
42
+ * Performs all system checks and determines tier:
43
+ * - Tier 1: All checks pass (full features)
44
+ * - Tier 2: One or more checks fail (degraded mode)
45
+ */
46
+ export declare function validateTier(): Promise<TierValidation>;
47
+ /**
48
+ * Get user-friendly tier description
49
+ */
50
+ export declare function getTierDescription(tier: number): string;
51
+ /**
52
+ * Get tier status banner
53
+ */
54
+ export declare function getTierBanner(validation: TierValidation): string;
55
+ //# sourceMappingURL=tier-validator.d.ts.map