@graphty/remote-logger 1.1.1 → 1.2.1
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.
- package/README.md +318 -10
- package/dist/client/RemoteLogClient.d.ts +2 -0
- package/dist/client/RemoteLogClient.d.ts.map +1 -1
- package/dist/client/RemoteLogClient.js +35 -4
- package/dist/client/RemoteLogClient.js.map +1 -1
- package/dist/client/types.d.ts +13 -0
- package/dist/client/types.d.ts.map +1 -1
- package/dist/mcp/index.d.ts +9 -0
- package/dist/mcp/index.d.ts.map +1 -0
- package/dist/mcp/index.js +9 -0
- package/dist/mcp/index.js.map +1 -0
- package/dist/mcp/mcp-server.d.ts +32 -0
- package/dist/mcp/mcp-server.d.ts.map +1 -0
- package/dist/mcp/mcp-server.js +270 -0
- package/dist/mcp/mcp-server.js.map +1 -0
- package/dist/mcp/tools/index.d.ts +14 -0
- package/dist/mcp/tools/index.d.ts.map +1 -0
- package/dist/mcp/tools/index.js +14 -0
- package/dist/mcp/tools/index.js.map +1 -0
- package/dist/mcp/tools/logs-clear.d.ts +76 -0
- package/dist/mcp/tools/logs-clear.d.ts.map +1 -0
- package/dist/mcp/tools/logs-clear.js +58 -0
- package/dist/mcp/tools/logs-clear.js.map +1 -0
- package/dist/mcp/tools/logs-get-all.d.ts +60 -0
- package/dist/mcp/tools/logs-get-all.d.ts.map +1 -0
- package/dist/mcp/tools/logs-get-all.js +50 -0
- package/dist/mcp/tools/logs-get-all.js.map +1 -0
- package/dist/mcp/tools/logs-get-errors.d.ts +65 -0
- package/dist/mcp/tools/logs-get-errors.d.ts.map +1 -0
- package/dist/mcp/tools/logs-get-errors.js +46 -0
- package/dist/mcp/tools/logs-get-errors.js.map +1 -0
- package/dist/mcp/tools/logs-get-file-path.d.ts +75 -0
- package/dist/mcp/tools/logs-get-file-path.d.ts.map +1 -0
- package/dist/mcp/tools/logs-get-file-path.js +90 -0
- package/dist/mcp/tools/logs-get-file-path.js.map +1 -0
- package/dist/mcp/tools/logs-get-recent.d.ts +89 -0
- package/dist/mcp/tools/logs-get-recent.d.ts.map +1 -0
- package/dist/mcp/tools/logs-get-recent.js +74 -0
- package/dist/mcp/tools/logs-get-recent.js.map +1 -0
- package/dist/mcp/tools/logs-list-sessions.d.ts +64 -0
- package/dist/mcp/tools/logs-list-sessions.d.ts.map +1 -0
- package/dist/mcp/tools/logs-list-sessions.js +48 -0
- package/dist/mcp/tools/logs-list-sessions.js.map +1 -0
- package/dist/mcp/tools/logs-receive.d.ts +150 -0
- package/dist/mcp/tools/logs-receive.d.ts.map +1 -0
- package/dist/mcp/tools/logs-receive.js +68 -0
- package/dist/mcp/tools/logs-receive.js.map +1 -0
- package/dist/mcp/tools/logs-search.d.ts +91 -0
- package/dist/mcp/tools/logs-search.d.ts.map +1 -0
- package/dist/mcp/tools/logs-search.js +68 -0
- package/dist/mcp/tools/logs-search.js.map +1 -0
- package/dist/mcp/tools/logs-status.d.ts +45 -0
- package/dist/mcp/tools/logs-status.d.ts.map +1 -0
- package/dist/mcp/tools/logs-status.js +45 -0
- package/dist/mcp/tools/logs-status.js.map +1 -0
- package/dist/server/dual-server.d.ts +76 -0
- package/dist/server/dual-server.d.ts.map +1 -0
- package/dist/server/dual-server.js +214 -0
- package/dist/server/dual-server.js.map +1 -0
- package/dist/server/index.d.ts +5 -1
- package/dist/server/index.d.ts.map +1 -1
- package/dist/server/index.js +5 -1
- package/dist/server/index.js.map +1 -1
- package/dist/server/jsonl-writer.d.ts +93 -0
- package/dist/server/jsonl-writer.d.ts.map +1 -0
- package/dist/server/jsonl-writer.js +205 -0
- package/dist/server/jsonl-writer.js.map +1 -0
- package/dist/server/log-server.d.ts +62 -11
- package/dist/server/log-server.d.ts.map +1 -1
- package/dist/server/log-server.js +237 -101
- package/dist/server/log-server.js.map +1 -1
- package/dist/server/log-storage.d.ts +301 -0
- package/dist/server/log-storage.d.ts.map +1 -0
- package/dist/server/log-storage.js +408 -0
- package/dist/server/log-storage.js.map +1 -0
- package/dist/server/marker-utils.d.ts +69 -0
- package/dist/server/marker-utils.d.ts.map +1 -0
- package/dist/server/marker-utils.js +118 -0
- package/dist/server/marker-utils.js.map +1 -0
- package/dist/vite/index.d.ts +8 -0
- package/dist/vite/index.d.ts.map +1 -0
- package/dist/vite/index.js +8 -0
- package/dist/vite/index.js.map +1 -0
- package/dist/vite/plugin.d.ts +42 -0
- package/dist/vite/plugin.d.ts.map +1 -0
- package/dist/vite/plugin.js +46 -0
- package/dist/vite/plugin.js.map +1 -0
- package/package.json +12 -2
- package/src/client/RemoteLogClient.ts +52 -4
- package/src/client/types.ts +13 -0
- package/src/mcp/index.ts +25 -0
- package/src/mcp/mcp-server.ts +364 -0
- package/src/mcp/tools/index.ts +69 -0
- package/src/mcp/tools/logs-clear.ts +86 -0
- package/src/mcp/tools/logs-get-all.ts +78 -0
- package/src/mcp/tools/logs-get-errors.ts +71 -0
- package/src/mcp/tools/logs-get-file-path.ts +121 -0
- package/src/mcp/tools/logs-get-recent.ts +104 -0
- package/src/mcp/tools/logs-list-sessions.ts +71 -0
- package/src/mcp/tools/logs-receive.ts +96 -0
- package/src/mcp/tools/logs-search.ts +95 -0
- package/src/mcp/tools/logs-status.ts +69 -0
- package/src/server/dual-server.ts +308 -0
- package/src/server/index.ts +37 -0
- package/src/server/jsonl-writer.ts +277 -0
- package/src/server/log-server.ts +311 -119
- package/src/server/log-storage.ts +651 -0
- package/src/server/marker-utils.ts +144 -0
- package/src/vite/index.ts +8 -0
- package/src/vite/plugin.ts +59 -0
|
@@ -0,0 +1,408 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Shared log storage with session metadata support.
|
|
3
|
+
*
|
|
4
|
+
* This module provides a centralized storage for logs that can be shared
|
|
5
|
+
* between HTTP and MCP interfaces. It supports project markers for
|
|
6
|
+
* filtering logs by git worktree or project.
|
|
7
|
+
* @module server/log-storage
|
|
8
|
+
*/
|
|
9
|
+
import { extractMarkerFromSessionId } from "./marker-utils.js";
|
|
10
|
+
/**
|
|
11
|
+
* Default retention period in days.
|
|
12
|
+
*/
|
|
13
|
+
const DEFAULT_RETENTION_DAYS = 7;
|
|
14
|
+
/**
|
|
15
|
+
* Default cleanup interval in milliseconds (1 hour).
|
|
16
|
+
*/
|
|
17
|
+
const DEFAULT_CLEANUP_INTERVAL_MS = 60 * 60 * 1000;
|
|
18
|
+
/**
|
|
19
|
+
* Shared log storage with session metadata support.
|
|
20
|
+
*
|
|
21
|
+
* Provides methods for storing, querying, and managing logs across
|
|
22
|
+
* multiple sessions with support for project marker filtering.
|
|
23
|
+
*/
|
|
24
|
+
export class LogStorage {
|
|
25
|
+
/**
|
|
26
|
+
* Create a new LogStorage instance.
|
|
27
|
+
* @param options - Optional configuration including JSONL writer
|
|
28
|
+
*/
|
|
29
|
+
constructor(options = {}) {
|
|
30
|
+
this.sessions = new Map();
|
|
31
|
+
this.startTime = Date.now();
|
|
32
|
+
this.jsonlWriter = options.jsonlWriter;
|
|
33
|
+
// Determine retention days from options, env var, or default
|
|
34
|
+
const envRetention = process.env.REMOTE_LOG_RETENTION_DAYS;
|
|
35
|
+
this.retentionDays = options.retentionDays
|
|
36
|
+
?? (envRetention ? parseInt(envRetention, 10) : undefined)
|
|
37
|
+
?? DEFAULT_RETENTION_DAYS;
|
|
38
|
+
// Start periodic cleanup timer
|
|
39
|
+
const cleanupInterval = options.cleanupIntervalMs ?? DEFAULT_CLEANUP_INTERVAL_MS;
|
|
40
|
+
if (cleanupInterval > 0) {
|
|
41
|
+
this.cleanupTimer = setInterval(() => {
|
|
42
|
+
this.cleanupExpiredLogs();
|
|
43
|
+
}, cleanupInterval);
|
|
44
|
+
// Don't prevent process exit
|
|
45
|
+
this.cleanupTimer.unref?.();
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
/**
|
|
49
|
+
* Get the JSONL writer if configured.
|
|
50
|
+
* @returns The JSONL writer or undefined
|
|
51
|
+
*/
|
|
52
|
+
getJsonlWriter() {
|
|
53
|
+
return this.jsonlWriter;
|
|
54
|
+
}
|
|
55
|
+
/**
|
|
56
|
+
* Add logs to storage for a session.
|
|
57
|
+
* @param sessionId - Unique identifier for the session
|
|
58
|
+
* @param logs - Array of log entries to add
|
|
59
|
+
* @param options - Additional options (projectMarker, worktreePath, pageUrl)
|
|
60
|
+
*/
|
|
61
|
+
addLogs(sessionId, logs, options = {}) {
|
|
62
|
+
let sessionData = this.sessions.get(sessionId);
|
|
63
|
+
// Determine project marker for new sessions
|
|
64
|
+
const projectMarker = options.projectMarker || extractMarkerFromSessionId(sessionId);
|
|
65
|
+
if (!sessionData) {
|
|
66
|
+
// Create new session
|
|
67
|
+
sessionData = {
|
|
68
|
+
metadata: {
|
|
69
|
+
sessionId,
|
|
70
|
+
projectMarker,
|
|
71
|
+
worktreePath: options.worktreePath,
|
|
72
|
+
pageUrl: options.pageUrl,
|
|
73
|
+
firstLogTime: logs[0]?.time || new Date().toISOString(),
|
|
74
|
+
lastLogTime: logs[0]?.time || new Date().toISOString(),
|
|
75
|
+
logCount: 0,
|
|
76
|
+
errorCount: 0,
|
|
77
|
+
},
|
|
78
|
+
logs: [],
|
|
79
|
+
};
|
|
80
|
+
this.sessions.set(sessionId, sessionData);
|
|
81
|
+
}
|
|
82
|
+
// Add logs and update metadata
|
|
83
|
+
for (const log of logs) {
|
|
84
|
+
sessionData.logs.push(log);
|
|
85
|
+
sessionData.metadata.logCount++;
|
|
86
|
+
sessionData.metadata.lastLogTime = log.time;
|
|
87
|
+
if (log.level.toUpperCase() === "ERROR") {
|
|
88
|
+
sessionData.metadata.errorCount++;
|
|
89
|
+
}
|
|
90
|
+
// Write to JSONL file if writer is configured
|
|
91
|
+
if (this.jsonlWriter) {
|
|
92
|
+
// Use the session's project marker
|
|
93
|
+
const marker = sessionData.metadata.projectMarker;
|
|
94
|
+
void this.jsonlWriter.write(marker, {
|
|
95
|
+
time: log.time,
|
|
96
|
+
level: log.level,
|
|
97
|
+
message: log.message,
|
|
98
|
+
sessionId,
|
|
99
|
+
data: log.data,
|
|
100
|
+
});
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
// Update optional metadata if provided
|
|
104
|
+
if (options.worktreePath && !sessionData.metadata.worktreePath) {
|
|
105
|
+
sessionData.metadata.worktreePath = options.worktreePath;
|
|
106
|
+
}
|
|
107
|
+
if (options.pageUrl && !sessionData.metadata.pageUrl) {
|
|
108
|
+
sessionData.metadata.pageUrl = options.pageUrl;
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
/**
|
|
112
|
+
* Get logs with optional filtering.
|
|
113
|
+
* @param filter - Filter options
|
|
114
|
+
* @returns Array of log entries with session IDs
|
|
115
|
+
*/
|
|
116
|
+
getLogs(filter = {}) {
|
|
117
|
+
const results = [];
|
|
118
|
+
for (const [sessionId, sessionData] of this.sessions) {
|
|
119
|
+
// Filter by project marker
|
|
120
|
+
if (filter.projectMarker && sessionData.metadata.projectMarker !== filter.projectMarker) {
|
|
121
|
+
continue;
|
|
122
|
+
}
|
|
123
|
+
// Filter by session ID
|
|
124
|
+
if (filter.sessionId && sessionId !== filter.sessionId) {
|
|
125
|
+
continue;
|
|
126
|
+
}
|
|
127
|
+
for (const log of sessionData.logs) {
|
|
128
|
+
// Filter by level
|
|
129
|
+
if (filter.level && log.level.toUpperCase() !== filter.level.toUpperCase()) {
|
|
130
|
+
continue;
|
|
131
|
+
}
|
|
132
|
+
// Filter by since
|
|
133
|
+
if (filter.since && new Date(log.time) <= new Date(filter.since)) {
|
|
134
|
+
continue;
|
|
135
|
+
}
|
|
136
|
+
results.push({ ...log, sessionId });
|
|
137
|
+
}
|
|
138
|
+
}
|
|
139
|
+
return results;
|
|
140
|
+
}
|
|
141
|
+
/**
|
|
142
|
+
* Get the most recent logs across all sessions.
|
|
143
|
+
* @param count - Maximum number of logs to return
|
|
144
|
+
* @param filter - Optional filter to apply before limiting
|
|
145
|
+
* @returns Array of recent log entries (oldest first)
|
|
146
|
+
*/
|
|
147
|
+
getRecentLogs(count, filter = {}) {
|
|
148
|
+
const allLogs = this.getLogs(filter);
|
|
149
|
+
// Sort by time descending (newest first)
|
|
150
|
+
allLogs.sort((a, b) => new Date(b.time).getTime() - new Date(a.time).getTime());
|
|
151
|
+
// Take the most recent 'count' logs, then reverse to show oldest first
|
|
152
|
+
return allLogs.slice(0, count).reverse();
|
|
153
|
+
}
|
|
154
|
+
/**
|
|
155
|
+
* Get only ERROR level logs.
|
|
156
|
+
* @param filter - Optional filter options
|
|
157
|
+
* @returns Array of error log entries
|
|
158
|
+
*/
|
|
159
|
+
getErrors(filter = {}) {
|
|
160
|
+
const logs = this.getLogs({ ...filter, level: "ERROR" });
|
|
161
|
+
// Sort chronologically
|
|
162
|
+
return logs.sort((a, b) => new Date(a.time).getTime() - new Date(b.time).getTime());
|
|
163
|
+
}
|
|
164
|
+
/**
|
|
165
|
+
* Get all sessions with their metadata.
|
|
166
|
+
* @param filter - Optional filter options
|
|
167
|
+
* @returns Array of session metadata
|
|
168
|
+
*/
|
|
169
|
+
getSessions(filter = {}) {
|
|
170
|
+
const results = [];
|
|
171
|
+
for (const sessionData of this.sessions.values()) {
|
|
172
|
+
// Filter by project marker
|
|
173
|
+
if (filter.projectMarker && sessionData.metadata.projectMarker !== filter.projectMarker) {
|
|
174
|
+
continue;
|
|
175
|
+
}
|
|
176
|
+
// Filter by hasErrors
|
|
177
|
+
if (filter.hasErrors && sessionData.metadata.errorCount === 0) {
|
|
178
|
+
continue;
|
|
179
|
+
}
|
|
180
|
+
results.push({ ...sessionData.metadata });
|
|
181
|
+
}
|
|
182
|
+
return results;
|
|
183
|
+
}
|
|
184
|
+
/**
|
|
185
|
+
* Clear logs with optional filtering.
|
|
186
|
+
* @param filter - Optional filter to limit what is cleared
|
|
187
|
+
* @returns Object with count of cleared sessions
|
|
188
|
+
*/
|
|
189
|
+
clearLogs(filter = {}) {
|
|
190
|
+
let cleared = 0;
|
|
191
|
+
if (!filter.projectMarker && !filter.sessionId) {
|
|
192
|
+
// Clear all
|
|
193
|
+
cleared = this.sessions.size;
|
|
194
|
+
this.sessions.clear();
|
|
195
|
+
}
|
|
196
|
+
else {
|
|
197
|
+
// Clear selectively
|
|
198
|
+
const toDelete = [];
|
|
199
|
+
for (const [sessionId, sessionData] of this.sessions) {
|
|
200
|
+
if (filter.sessionId && sessionId === filter.sessionId) {
|
|
201
|
+
toDelete.push(sessionId);
|
|
202
|
+
}
|
|
203
|
+
else if (filter.projectMarker && sessionData.metadata.projectMarker === filter.projectMarker) {
|
|
204
|
+
toDelete.push(sessionId);
|
|
205
|
+
}
|
|
206
|
+
}
|
|
207
|
+
for (const sessionId of toDelete) {
|
|
208
|
+
this.sessions.delete(sessionId);
|
|
209
|
+
cleared++;
|
|
210
|
+
}
|
|
211
|
+
}
|
|
212
|
+
return { cleared };
|
|
213
|
+
}
|
|
214
|
+
/**
|
|
215
|
+
* Clear all logs (convenience method).
|
|
216
|
+
*/
|
|
217
|
+
clear() {
|
|
218
|
+
this.sessions.clear();
|
|
219
|
+
}
|
|
220
|
+
/**
|
|
221
|
+
* Set the HTTP server configuration.
|
|
222
|
+
* Call this after the HTTP server starts to make endpoint info available.
|
|
223
|
+
* @param config - Server configuration
|
|
224
|
+
*/
|
|
225
|
+
setServerConfig(config) {
|
|
226
|
+
this.serverConfig = config;
|
|
227
|
+
}
|
|
228
|
+
/**
|
|
229
|
+
* Get the HTTP server configuration.
|
|
230
|
+
* @returns Server configuration or undefined if not set
|
|
231
|
+
*/
|
|
232
|
+
getServerConfig() {
|
|
233
|
+
return this.serverConfig;
|
|
234
|
+
}
|
|
235
|
+
/**
|
|
236
|
+
* Get health status of the storage.
|
|
237
|
+
* @returns Health status object
|
|
238
|
+
*/
|
|
239
|
+
getHealth() {
|
|
240
|
+
let totalLogs = 0;
|
|
241
|
+
let totalErrors = 0;
|
|
242
|
+
for (const sessionData of this.sessions.values()) {
|
|
243
|
+
totalLogs += sessionData.metadata.logCount;
|
|
244
|
+
totalErrors += sessionData.metadata.errorCount;
|
|
245
|
+
}
|
|
246
|
+
return {
|
|
247
|
+
status: "ok",
|
|
248
|
+
sessionCount: this.sessions.size,
|
|
249
|
+
totalLogs,
|
|
250
|
+
totalErrors,
|
|
251
|
+
uptimeMs: Date.now() - this.startTime,
|
|
252
|
+
};
|
|
253
|
+
}
|
|
254
|
+
/**
|
|
255
|
+
* Get full server status including health and configuration.
|
|
256
|
+
* @returns Server status object
|
|
257
|
+
*/
|
|
258
|
+
getStatus() {
|
|
259
|
+
const health = this.getHealth();
|
|
260
|
+
return {
|
|
261
|
+
...health,
|
|
262
|
+
server: this.serverConfig,
|
|
263
|
+
retentionDays: this.retentionDays,
|
|
264
|
+
};
|
|
265
|
+
}
|
|
266
|
+
/**
|
|
267
|
+
* Get logs for a specific session.
|
|
268
|
+
* @param sessionId - The session ID to get logs for
|
|
269
|
+
* @returns Array of log entries for the session
|
|
270
|
+
*/
|
|
271
|
+
getLogsForSession(sessionId) {
|
|
272
|
+
const sessionData = this.sessions.get(sessionId);
|
|
273
|
+
return sessionData ? [...sessionData.logs] : [];
|
|
274
|
+
}
|
|
275
|
+
/**
|
|
276
|
+
* Get all logs grouped by session ID.
|
|
277
|
+
* @param filter - Optional filter options
|
|
278
|
+
* @param filter.projectMarker - Filter by project marker
|
|
279
|
+
* @returns Object mapping session IDs to log arrays
|
|
280
|
+
*/
|
|
281
|
+
getAllLogsBySession(filter = {}) {
|
|
282
|
+
const result = {};
|
|
283
|
+
for (const [sessionId, sessionData] of this.sessions) {
|
|
284
|
+
if (filter.projectMarker && sessionData.metadata.projectMarker !== filter.projectMarker) {
|
|
285
|
+
continue;
|
|
286
|
+
}
|
|
287
|
+
result[sessionId] = [...sessionData.logs];
|
|
288
|
+
}
|
|
289
|
+
return result;
|
|
290
|
+
}
|
|
291
|
+
/**
|
|
292
|
+
* Search logs by content.
|
|
293
|
+
* @param options - Search options
|
|
294
|
+
* @returns Array of matching log entries
|
|
295
|
+
*/
|
|
296
|
+
search(options) {
|
|
297
|
+
const { query, regex = false, projectMarker, level, limit = 100 } = options;
|
|
298
|
+
// Build the search pattern
|
|
299
|
+
let pattern;
|
|
300
|
+
try {
|
|
301
|
+
pattern = regex ? new RegExp(query, "i") : new RegExp(query.replace(/[.*+?^${}()|[\]\\]/g, "\\$&"), "i");
|
|
302
|
+
}
|
|
303
|
+
catch {
|
|
304
|
+
// Invalid regex, return empty results
|
|
305
|
+
return [];
|
|
306
|
+
}
|
|
307
|
+
const results = [];
|
|
308
|
+
for (const [sessionId, sessionData] of this.sessions) {
|
|
309
|
+
// Filter by project marker
|
|
310
|
+
if (projectMarker && sessionData.metadata.projectMarker !== projectMarker) {
|
|
311
|
+
continue;
|
|
312
|
+
}
|
|
313
|
+
for (const log of sessionData.logs) {
|
|
314
|
+
// Filter by level
|
|
315
|
+
if (level && log.level.toUpperCase() !== level.toUpperCase()) {
|
|
316
|
+
continue;
|
|
317
|
+
}
|
|
318
|
+
// Test message against pattern
|
|
319
|
+
if (pattern.test(log.message)) {
|
|
320
|
+
results.push({ ...log, sessionId });
|
|
321
|
+
if (results.length >= limit) {
|
|
322
|
+
return results;
|
|
323
|
+
}
|
|
324
|
+
}
|
|
325
|
+
}
|
|
326
|
+
}
|
|
327
|
+
return results;
|
|
328
|
+
}
|
|
329
|
+
/**
|
|
330
|
+
* Check if a session exists.
|
|
331
|
+
* @param sessionId - The session ID to check
|
|
332
|
+
* @returns True if the session exists
|
|
333
|
+
*/
|
|
334
|
+
hasSession(sessionId) {
|
|
335
|
+
return this.sessions.has(sessionId);
|
|
336
|
+
}
|
|
337
|
+
/**
|
|
338
|
+
* Get metadata for a specific session.
|
|
339
|
+
* @param sessionId - The session ID
|
|
340
|
+
* @returns Session metadata or undefined if not found
|
|
341
|
+
*/
|
|
342
|
+
getSessionMetadata(sessionId) {
|
|
343
|
+
const sessionData = this.sessions.get(sessionId);
|
|
344
|
+
return sessionData ? { ...sessionData.metadata } : undefined;
|
|
345
|
+
}
|
|
346
|
+
/**
|
|
347
|
+
* Get the configured retention period in days.
|
|
348
|
+
* @returns Number of days logs are retained
|
|
349
|
+
*/
|
|
350
|
+
getRetentionDays() {
|
|
351
|
+
return this.retentionDays;
|
|
352
|
+
}
|
|
353
|
+
/**
|
|
354
|
+
* Stop the periodic cleanup timer.
|
|
355
|
+
* Call this when shutting down to prevent memory leaks.
|
|
356
|
+
*/
|
|
357
|
+
stopCleanupTimer() {
|
|
358
|
+
if (this.cleanupTimer) {
|
|
359
|
+
clearInterval(this.cleanupTimer);
|
|
360
|
+
this.cleanupTimer = undefined;
|
|
361
|
+
}
|
|
362
|
+
}
|
|
363
|
+
/**
|
|
364
|
+
* Clean up logs older than the retention period.
|
|
365
|
+
* This removes individual logs from sessions, removes sessions
|
|
366
|
+
* that have no remaining logs, and cleans up old JSONL files.
|
|
367
|
+
* @returns Number of sessions that were completely removed
|
|
368
|
+
*/
|
|
369
|
+
cleanupExpiredLogs() {
|
|
370
|
+
const cutoffTime = new Date();
|
|
371
|
+
cutoffTime.setDate(cutoffTime.getDate() - this.retentionDays);
|
|
372
|
+
const cutoffMs = cutoffTime.getTime();
|
|
373
|
+
const sessionsToRemove = [];
|
|
374
|
+
for (const [sessionId, sessionData] of this.sessions) {
|
|
375
|
+
// Filter out expired logs
|
|
376
|
+
const remainingLogs = sessionData.logs.filter((log) => new Date(log.time).getTime() > cutoffMs);
|
|
377
|
+
if (remainingLogs.length === 0) {
|
|
378
|
+
// Session has no remaining logs, mark for removal
|
|
379
|
+
sessionsToRemove.push(sessionId);
|
|
380
|
+
}
|
|
381
|
+
else if (remainingLogs.length !== sessionData.logs.length) {
|
|
382
|
+
// Some logs were removed, update the session
|
|
383
|
+
sessionData.logs = remainingLogs;
|
|
384
|
+
// Recalculate metadata
|
|
385
|
+
let errorCount = 0;
|
|
386
|
+
for (const log of remainingLogs) {
|
|
387
|
+
if (log.level.toUpperCase() === "ERROR") {
|
|
388
|
+
errorCount++;
|
|
389
|
+
}
|
|
390
|
+
}
|
|
391
|
+
sessionData.metadata.logCount = remainingLogs.length;
|
|
392
|
+
sessionData.metadata.errorCount = errorCount;
|
|
393
|
+
sessionData.metadata.firstLogTime = remainingLogs[0].time;
|
|
394
|
+
sessionData.metadata.lastLogTime = remainingLogs[remainingLogs.length - 1].time;
|
|
395
|
+
}
|
|
396
|
+
}
|
|
397
|
+
// Remove empty sessions
|
|
398
|
+
for (const sessionId of sessionsToRemove) {
|
|
399
|
+
this.sessions.delete(sessionId);
|
|
400
|
+
}
|
|
401
|
+
// Clean up old JSONL files
|
|
402
|
+
if (this.jsonlWriter) {
|
|
403
|
+
this.jsonlWriter.cleanupOldFiles(this.retentionDays);
|
|
404
|
+
}
|
|
405
|
+
return sessionsToRemove.length;
|
|
406
|
+
}
|
|
407
|
+
}
|
|
408
|
+
//# sourceMappingURL=log-storage.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"log-storage.js","sourceRoot":"","sources":["../../src/server/log-storage.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Utilities for extracting and resolving project markers.
|
|
3
|
+
*
|
|
4
|
+
* Project markers are used to identify which git worktree or project
|
|
5
|
+
* a log session belongs to, enabling filtering of logs by project.
|
|
6
|
+
* @module server/marker-utils
|
|
7
|
+
*/
|
|
8
|
+
/**
|
|
9
|
+
* Extract a project marker from a filesystem path.
|
|
10
|
+
*
|
|
11
|
+
* The function looks for `.worktrees` in the path and extracts the worktree name.
|
|
12
|
+
* If no worktree is found, it falls back to the directory basename.
|
|
13
|
+
* @param cwd - The filesystem path to extract a marker from
|
|
14
|
+
* @returns The extracted project marker, or "default" if extraction fails
|
|
15
|
+
* @example
|
|
16
|
+
* // Worktree paths
|
|
17
|
+
* extractMarkerFromPath("/home/user/.worktrees/remote-logging") // "remote-logging"
|
|
18
|
+
* extractMarkerFromPath("C:\\Users\\dev\\.worktrees\\feature-xyz") // "feature-xyz"
|
|
19
|
+
*
|
|
20
|
+
* // Regular paths (uses basename)
|
|
21
|
+
* extractMarkerFromPath("/home/user/my-project") // "my-project"
|
|
22
|
+
*/
|
|
23
|
+
export declare function extractMarkerFromPath(cwd: string): string;
|
|
24
|
+
/**
|
|
25
|
+
* Extract a project marker from a session ID.
|
|
26
|
+
*
|
|
27
|
+
* Session IDs typically follow the format: {prefix}-{timestamp}-{random}
|
|
28
|
+
* This function extracts the prefix part as the project marker.
|
|
29
|
+
* @param sessionId - The session ID to extract a marker from
|
|
30
|
+
* @returns The extracted project marker, or "default" if extraction fails
|
|
31
|
+
* @example
|
|
32
|
+
* extractMarkerFromSessionId("graphty-element-1704067200000-abc123") // "graphty-element"
|
|
33
|
+
* extractMarkerFromSessionId("my-app-1704067200000-xyz") // "my-app"
|
|
34
|
+
* extractMarkerFromSessionId("simple") // "simple"
|
|
35
|
+
*/
|
|
36
|
+
export declare function extractMarkerFromSessionId(sessionId: string): string;
|
|
37
|
+
/**
|
|
38
|
+
* Options for resolving a project marker.
|
|
39
|
+
*/
|
|
40
|
+
export interface MarkerResolutionOptions {
|
|
41
|
+
/** Explicit project marker (highest priority) */
|
|
42
|
+
projectMarker?: string;
|
|
43
|
+
/** Working directory path to extract marker from */
|
|
44
|
+
workingDirectory?: string;
|
|
45
|
+
/** Session ID to extract marker from (lowest priority) */
|
|
46
|
+
sessionId?: string;
|
|
47
|
+
}
|
|
48
|
+
/**
|
|
49
|
+
* Resolve a project marker using a fallback chain.
|
|
50
|
+
*
|
|
51
|
+
* Priority order:
|
|
52
|
+
* 1. Explicit projectMarker parameter
|
|
53
|
+
* 2. Extracted from workingDirectory path
|
|
54
|
+
* 3. Extracted from sessionId
|
|
55
|
+
* 4. "default" as final fallback
|
|
56
|
+
* @param options - Resolution options with various marker sources
|
|
57
|
+
* @returns The resolved project marker
|
|
58
|
+
* @example
|
|
59
|
+
* resolveProjectMarker({
|
|
60
|
+
* projectMarker: "explicit",
|
|
61
|
+
* workingDirectory: "/path/to/.worktrees/from-path"
|
|
62
|
+
* }) // "explicit"
|
|
63
|
+
*
|
|
64
|
+
* resolveProjectMarker({
|
|
65
|
+
* workingDirectory: "/path/to/.worktrees/remote-logging"
|
|
66
|
+
* }) // "remote-logging"
|
|
67
|
+
*/
|
|
68
|
+
export declare function resolveProjectMarker(options: MarkerResolutionOptions): string;
|
|
69
|
+
//# sourceMappingURL=marker-utils.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"marker-utils.d.ts","sourceRoot":"","sources":["../../src/server/marker-utils.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAGH;;;;;;;;;;;;;;GAcG;AACH,wBAAgB,qBAAqB,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,CAwBzD;AAED;;;;;;;;;;;GAWG;AACH,wBAAgB,0BAA0B,CAAC,SAAS,EAAE,MAAM,GAAG,MAAM,CAuBpE;AAED;;GAEG;AACH,MAAM,WAAW,uBAAuB;IACpC,iDAAiD;IACjD,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,oDAAoD;IACpD,gBAAgB,CAAC,EAAE,MAAM,CAAC;IAC1B,0DAA0D;IAC1D,SAAS,CAAC,EAAE,MAAM,CAAC;CACtB;AAED;;;;;;;;;;;;;;;;;;;GAmBG;AACH,wBAAgB,oBAAoB,CAAC,OAAO,EAAE,uBAAuB,GAAG,MAAM,CAwB7E"}
|
|
@@ -0,0 +1,118 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Utilities for extracting and resolving project markers.
|
|
3
|
+
*
|
|
4
|
+
* Project markers are used to identify which git worktree or project
|
|
5
|
+
* a log session belongs to, enabling filtering of logs by project.
|
|
6
|
+
* @module server/marker-utils
|
|
7
|
+
*/
|
|
8
|
+
/**
|
|
9
|
+
* Extract a project marker from a filesystem path.
|
|
10
|
+
*
|
|
11
|
+
* The function looks for `.worktrees` in the path and extracts the worktree name.
|
|
12
|
+
* If no worktree is found, it falls back to the directory basename.
|
|
13
|
+
* @param cwd - The filesystem path to extract a marker from
|
|
14
|
+
* @returns The extracted project marker, or "default" if extraction fails
|
|
15
|
+
* @example
|
|
16
|
+
* // Worktree paths
|
|
17
|
+
* extractMarkerFromPath("/home/user/.worktrees/remote-logging") // "remote-logging"
|
|
18
|
+
* extractMarkerFromPath("C:\\Users\\dev\\.worktrees\\feature-xyz") // "feature-xyz"
|
|
19
|
+
*
|
|
20
|
+
* // Regular paths (uses basename)
|
|
21
|
+
* extractMarkerFromPath("/home/user/my-project") // "my-project"
|
|
22
|
+
*/
|
|
23
|
+
export function extractMarkerFromPath(cwd) {
|
|
24
|
+
if (!cwd || cwd === "/") {
|
|
25
|
+
return "default";
|
|
26
|
+
}
|
|
27
|
+
// Normalize trailing slashes
|
|
28
|
+
const normalizedPath = cwd.replace(/[/\\]+$/, "");
|
|
29
|
+
if (!normalizedPath) {
|
|
30
|
+
return "default";
|
|
31
|
+
}
|
|
32
|
+
// Check if in .worktrees directory (supports both Unix and Windows paths)
|
|
33
|
+
// Match: .worktrees/worktree-name or .worktrees\worktree-name
|
|
34
|
+
const worktreeMatch = normalizedPath.match(/\.worktrees[/\\]([^/\\]+)/);
|
|
35
|
+
if (worktreeMatch) {
|
|
36
|
+
return worktreeMatch[1];
|
|
37
|
+
}
|
|
38
|
+
// Fall back to directory name
|
|
39
|
+
// Handle both Unix and Windows paths by splitting on both separators
|
|
40
|
+
const segments = normalizedPath.split(/[/\\]/);
|
|
41
|
+
const basename = segments.filter(Boolean).pop();
|
|
42
|
+
return basename || "default";
|
|
43
|
+
}
|
|
44
|
+
/**
|
|
45
|
+
* Extract a project marker from a session ID.
|
|
46
|
+
*
|
|
47
|
+
* Session IDs typically follow the format: {prefix}-{timestamp}-{random}
|
|
48
|
+
* This function extracts the prefix part as the project marker.
|
|
49
|
+
* @param sessionId - The session ID to extract a marker from
|
|
50
|
+
* @returns The extracted project marker, or "default" if extraction fails
|
|
51
|
+
* @example
|
|
52
|
+
* extractMarkerFromSessionId("graphty-element-1704067200000-abc123") // "graphty-element"
|
|
53
|
+
* extractMarkerFromSessionId("my-app-1704067200000-xyz") // "my-app"
|
|
54
|
+
* extractMarkerFromSessionId("simple") // "simple"
|
|
55
|
+
*/
|
|
56
|
+
export function extractMarkerFromSessionId(sessionId) {
|
|
57
|
+
if (!sessionId) {
|
|
58
|
+
return "default";
|
|
59
|
+
}
|
|
60
|
+
// Session IDs follow format: {prefix}-{timestamp}-{random}
|
|
61
|
+
// The timestamp is typically a 13-digit number (milliseconds since epoch)
|
|
62
|
+
// We want to extract everything before the timestamp
|
|
63
|
+
// Look for pattern: name-{13 digits}-{suffix}
|
|
64
|
+
const timestampMatch = sessionId.match(/^(.+?)-(\d{10,13})-[a-zA-Z0-9]+$/);
|
|
65
|
+
if (timestampMatch) {
|
|
66
|
+
return timestampMatch[1];
|
|
67
|
+
}
|
|
68
|
+
// Fall back to first segment before hyphen
|
|
69
|
+
const firstHyphen = sessionId.indexOf("-");
|
|
70
|
+
if (firstHyphen > 0) {
|
|
71
|
+
return sessionId.substring(0, firstHyphen);
|
|
72
|
+
}
|
|
73
|
+
// Return the whole session ID if no hyphen
|
|
74
|
+
return sessionId;
|
|
75
|
+
}
|
|
76
|
+
/**
|
|
77
|
+
* Resolve a project marker using a fallback chain.
|
|
78
|
+
*
|
|
79
|
+
* Priority order:
|
|
80
|
+
* 1. Explicit projectMarker parameter
|
|
81
|
+
* 2. Extracted from workingDirectory path
|
|
82
|
+
* 3. Extracted from sessionId
|
|
83
|
+
* 4. "default" as final fallback
|
|
84
|
+
* @param options - Resolution options with various marker sources
|
|
85
|
+
* @returns The resolved project marker
|
|
86
|
+
* @example
|
|
87
|
+
* resolveProjectMarker({
|
|
88
|
+
* projectMarker: "explicit",
|
|
89
|
+
* workingDirectory: "/path/to/.worktrees/from-path"
|
|
90
|
+
* }) // "explicit"
|
|
91
|
+
*
|
|
92
|
+
* resolveProjectMarker({
|
|
93
|
+
* workingDirectory: "/path/to/.worktrees/remote-logging"
|
|
94
|
+
* }) // "remote-logging"
|
|
95
|
+
*/
|
|
96
|
+
export function resolveProjectMarker(options) {
|
|
97
|
+
// Priority 1: Explicit project marker
|
|
98
|
+
if (options.projectMarker) {
|
|
99
|
+
return options.projectMarker;
|
|
100
|
+
}
|
|
101
|
+
// Priority 2: Extract from working directory
|
|
102
|
+
if (options.workingDirectory) {
|
|
103
|
+
const fromPath = extractMarkerFromPath(options.workingDirectory);
|
|
104
|
+
if (fromPath !== "default") {
|
|
105
|
+
return fromPath;
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
// Priority 3: Extract from session ID
|
|
109
|
+
if (options.sessionId) {
|
|
110
|
+
const fromSession = extractMarkerFromSessionId(options.sessionId);
|
|
111
|
+
if (fromSession !== "default") {
|
|
112
|
+
return fromSession;
|
|
113
|
+
}
|
|
114
|
+
}
|
|
115
|
+
// Final fallback
|
|
116
|
+
return "default";
|
|
117
|
+
}
|
|
118
|
+
//# sourceMappingURL=marker-utils.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"marker-utils.js","sourceRoot":"","sources":["../../src/server/marker-utils.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAGH;;;;;;;;;;;;;;GAcG;AACH,MAAM,UAAU,qBAAqB,CAAC,GAAW;IAC7C,IAAI,CAAC,GAAG,IAAI,GAAG,KAAK,GAAG,EAAE,CAAC;QACtB,OAAO,SAAS,CAAC;IACrB,CAAC;IAED,6BAA6B;IAC7B,MAAM,cAAc,GAAG,GAAG,CAAC,OAAO,CAAC,SAAS,EAAE,EAAE,CAAC,CAAC;IAElD,IAAI,CAAC,cAAc,EAAE,CAAC;QAClB,OAAO,SAAS,CAAC;IACrB,CAAC;IAED,0EAA0E;IAC1E,8DAA8D;IAC9D,MAAM,aAAa,GAAG,cAAc,CAAC,KAAK,CAAC,2BAA2B,CAAC,CAAC;IACxE,IAAI,aAAa,EAAE,CAAC;QAChB,OAAO,aAAa,CAAC,CAAC,CAAC,CAAC;IAC5B,CAAC;IAED,8BAA8B;IAC9B,qEAAqE;IACrE,MAAM,QAAQ,GAAG,cAAc,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC;IAC/C,MAAM,QAAQ,GAAG,QAAQ,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC,GAAG,EAAE,CAAC;IAChD,OAAO,QAAQ,IAAI,SAAS,CAAC;AACjC,CAAC;AAED;;;;;;;;;;;GAWG;AACH,MAAM,UAAU,0BAA0B,CAAC,SAAiB;IACxD,IAAI,CAAC,SAAS,EAAE,CAAC;QACb,OAAO,SAAS,CAAC;IACrB,CAAC;IAED,2DAA2D;IAC3D,0EAA0E;IAC1E,qDAAqD;IAErD,8CAA8C;IAC9C,MAAM,cAAc,GAAG,SAAS,CAAC,KAAK,CAAC,kCAAkC,CAAC,CAAC;IAC3E,IAAI,cAAc,EAAE,CAAC;QACjB,OAAO,cAAc,CAAC,CAAC,CAAC,CAAC;IAC7B,CAAC;IAED,2CAA2C;IAC3C,MAAM,WAAW,GAAG,SAAS,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC;IAC3C,IAAI,WAAW,GAAG,CAAC,EAAE,CAAC;QAClB,OAAO,SAAS,CAAC,SAAS,CAAC,CAAC,EAAE,WAAW,CAAC,CAAC;IAC/C,CAAC;IAED,2CAA2C;IAC3C,OAAO,SAAS,CAAC;AACrB,CAAC;AAcD;;;;;;;;;;;;;;;;;;;GAmBG;AACH,MAAM,UAAU,oBAAoB,CAAC,OAAgC;IACjE,sCAAsC;IACtC,IAAI,OAAO,CAAC,aAAa,EAAE,CAAC;QACxB,OAAO,OAAO,CAAC,aAAa,CAAC;IACjC,CAAC;IAED,6CAA6C;IAC7C,IAAI,OAAO,CAAC,gBAAgB,EAAE,CAAC;QAC3B,MAAM,QAAQ,GAAG,qBAAqB,CAAC,OAAO,CAAC,gBAAgB,CAAC,CAAC;QACjE,IAAI,QAAQ,KAAK,SAAS,EAAE,CAAC;YACzB,OAAO,QAAQ,CAAC;QACpB,CAAC;IACL,CAAC;IAED,sCAAsC;IACtC,IAAI,OAAO,CAAC,SAAS,EAAE,CAAC;QACpB,MAAM,WAAW,GAAG,0BAA0B,CAAC,OAAO,CAAC,SAAS,CAAC,CAAC;QAClE,IAAI,WAAW,KAAK,SAAS,EAAE,CAAC;YAC5B,OAAO,WAAW,CAAC;QACvB,CAAC;IACL,CAAC;IAED,iBAAiB;IACjB,OAAO,SAAS,CAAC;AACrB,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/vite/index.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,EAAE,kBAAkB,EAAE,MAAM,aAAa,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/vite/index.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,EAAE,kBAAkB,EAAE,MAAM,aAAa,CAAC"}
|