@memextend/webui 0.1.0

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.
@@ -0,0 +1,183 @@
1
+ // apps/webui/src/api/stats.ts
2
+ // Copyright (c) 2026 ZodTTD LLC. MIT License.
3
+ import { Router } from 'express';
4
+ import { existsSync, statSync } from 'fs';
5
+ import { execSync } from 'child_process';
6
+ export const statsRouter = Router();
7
+ // Helper to format bytes
8
+ function formatBytes(bytes) {
9
+ if (bytes === 0)
10
+ return '0 B';
11
+ const k = 1024;
12
+ const sizes = ['B', 'KB', 'MB', 'GB'];
13
+ const i = Math.floor(Math.log(bytes) / Math.log(k));
14
+ return parseFloat((bytes / Math.pow(k, i)).toFixed(2)) + ' ' + sizes[i];
15
+ }
16
+ // Helper to get directory size
17
+ function getDirSize(dir) {
18
+ try {
19
+ const result = execSync(`du -sk "${dir}" 2>/dev/null | cut -f1`, {
20
+ encoding: 'utf-8'
21
+ }).trim();
22
+ return parseInt(result, 10) * 1024 || 0;
23
+ }
24
+ catch {
25
+ return 0;
26
+ }
27
+ }
28
+ // GET /api/stats - Get memory statistics
29
+ statsRouter.get('/', async (req, res) => {
30
+ try {
31
+ const { SQLiteStorage, LanceDBStorage, isModelAvailable } = await import('@memextend/core');
32
+ const sqlite = new SQLiteStorage(req.app.locals.dbPath);
33
+ const lancedb = await LanceDBStorage.create(req.app.locals.vectorsPath);
34
+ // Get counts
35
+ const memoryCount = sqlite.getMemoryCount();
36
+ const vectorCount = await lancedb.getVectorCount();
37
+ // Get global profiles
38
+ const globalProfiles = sqlite.getGlobalProfiles(100);
39
+ // Get all memories for type breakdown
40
+ const memories = sqlite.getAllMemories(undefined, 10000);
41
+ // Type breakdown
42
+ const typeBreakdown = {};
43
+ const sourceBreakdown = {};
44
+ const projectBreakdown = {};
45
+ for (const memory of memories) {
46
+ // Type
47
+ typeBreakdown[memory.type] = (typeBreakdown[memory.type] || 0) + 1;
48
+ // Source tool
49
+ const source = memory.sourceTool || (memory.type === 'reasoning' ? 'reasoning' : 'manual');
50
+ sourceBreakdown[source] = (sourceBreakdown[source] || 0) + 1;
51
+ // Project
52
+ const projectId = memory.projectId || 'global';
53
+ projectBreakdown[projectId] = (projectBreakdown[projectId] || 0) + 1;
54
+ }
55
+ // Date distribution (last 30 days)
56
+ const dateDistribution = {};
57
+ const now = new Date();
58
+ for (let i = 0; i < 30; i++) {
59
+ const date = new Date(now);
60
+ date.setDate(date.getDate() - i);
61
+ const dateStr = date.toISOString().split('T')[0];
62
+ dateDistribution[dateStr] = 0;
63
+ }
64
+ for (const memory of memories) {
65
+ const dateStr = memory.createdAt.split('T')[0];
66
+ if (dateDistribution[dateStr] !== undefined) {
67
+ dateDistribution[dateStr]++;
68
+ }
69
+ }
70
+ // Database sizes
71
+ const dbPath = req.app.locals.dbPath;
72
+ const vectorsPath = req.app.locals.vectorsPath;
73
+ const modelsPath = req.app.locals.modelsPath;
74
+ const dbSize = existsSync(dbPath) ? statSync(dbPath).size : 0;
75
+ const vectorsSize = existsSync(vectorsPath) ? getDirSize(vectorsPath) : 0;
76
+ const modelsSize = existsSync(modelsPath) ? getDirSize(modelsPath) : 0;
77
+ // Check model availability
78
+ const modelAvailable = isModelAvailable(modelsPath);
79
+ // Recent activity (last 7 days)
80
+ const sevenDaysAgo = new Date();
81
+ sevenDaysAgo.setDate(sevenDaysAgo.getDate() - 7);
82
+ const recentMemories = memories.filter(m => new Date(m.createdAt) >= sevenDaysAgo);
83
+ sqlite.close();
84
+ await lancedb.close();
85
+ res.json({
86
+ overview: {
87
+ totalMemories: memoryCount,
88
+ totalVectors: vectorCount,
89
+ globalProfiles: globalProfiles.length,
90
+ totalProjects: Object.keys(projectBreakdown).filter(k => k !== 'global').length
91
+ },
92
+ storage: {
93
+ database: {
94
+ size: dbSize,
95
+ sizeFormatted: formatBytes(dbSize)
96
+ },
97
+ vectors: {
98
+ size: vectorsSize,
99
+ sizeFormatted: formatBytes(vectorsSize)
100
+ },
101
+ models: {
102
+ size: modelsSize,
103
+ sizeFormatted: formatBytes(modelsSize)
104
+ },
105
+ total: {
106
+ size: dbSize + vectorsSize + modelsSize,
107
+ sizeFormatted: formatBytes(dbSize + vectorsSize + modelsSize)
108
+ }
109
+ },
110
+ embedding: {
111
+ modelAvailable,
112
+ modelName: 'nomic-embed-text-v1.5'
113
+ },
114
+ breakdowns: {
115
+ byType: typeBreakdown,
116
+ bySource: sourceBreakdown,
117
+ byProject: projectBreakdown
118
+ },
119
+ activity: {
120
+ last7Days: recentMemories.length,
121
+ dateDistribution
122
+ },
123
+ recentMemories: memories.slice(0, 5).map(m => ({
124
+ id: m.id,
125
+ preview: m.content.split('\n')[0].slice(0, 80),
126
+ type: m.type,
127
+ createdAt: m.createdAt
128
+ }))
129
+ });
130
+ }
131
+ catch (error) {
132
+ console.error('Error fetching stats:', error);
133
+ res.status(500).json({ error: error instanceof Error ? error.message : 'Unknown error' });
134
+ }
135
+ });
136
+ // GET /api/stats/global - Get global profiles
137
+ statsRouter.get('/global', async (req, res) => {
138
+ try {
139
+ const { SQLiteStorage } = await import('@memextend/core');
140
+ const sqlite = new SQLiteStorage(req.app.locals.dbPath);
141
+ const limit = parseInt(req.query.limit || '50', 10);
142
+ const profiles = sqlite.getGlobalProfiles(limit);
143
+ sqlite.close();
144
+ res.json({ profiles });
145
+ }
146
+ catch (error) {
147
+ console.error('Error fetching global profiles:', error);
148
+ res.status(500).json({ error: error instanceof Error ? error.message : 'Unknown error' });
149
+ }
150
+ });
151
+ // DELETE /api/stats/global/:id - Delete a specific global profile
152
+ statsRouter.delete('/global/:id', async (req, res) => {
153
+ try {
154
+ const { SQLiteStorage } = await import('@memextend/core');
155
+ const sqlite = new SQLiteStorage(req.app.locals.dbPath);
156
+ const deleted = sqlite.deleteGlobalProfile(req.params.id);
157
+ sqlite.close();
158
+ if (!deleted) {
159
+ res.status(404).json({ error: 'Global profile not found' });
160
+ return;
161
+ }
162
+ res.json({ success: true, id: req.params.id });
163
+ }
164
+ catch (error) {
165
+ console.error('Error deleting global profile:', error);
166
+ res.status(500).json({ error: error instanceof Error ? error.message : 'Unknown error' });
167
+ }
168
+ });
169
+ // DELETE /api/stats/global - Delete all global profiles
170
+ statsRouter.delete('/global', async (req, res) => {
171
+ try {
172
+ const { SQLiteStorage } = await import('@memextend/core');
173
+ const sqlite = new SQLiteStorage(req.app.locals.dbPath);
174
+ const deleted = sqlite.deleteAllGlobalProfiles();
175
+ sqlite.close();
176
+ res.json({ success: true, deleted });
177
+ }
178
+ catch (error) {
179
+ console.error('Error deleting all global profiles:', error);
180
+ res.status(500).json({ error: error instanceof Error ? error.message : 'Unknown error' });
181
+ }
182
+ });
183
+ //# sourceMappingURL=stats.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"stats.js","sourceRoot":"","sources":["../../src/api/stats.ts"],"names":[],"mappings":"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"}