genbox-agent 1.0.127 → 1.0.128

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 (45) hide show
  1. package/dist/configure-hooks.js +0 -0
  2. package/dist/hook.js +0 -0
  3. package/dist/readers/jsonl-watcher.d.ts +45 -0
  4. package/dist/readers/jsonl-watcher.d.ts.map +1 -0
  5. package/dist/readers/jsonl-watcher.js +288 -0
  6. package/dist/readers/jsonl-watcher.js.map +1 -0
  7. package/dist/readers/readers/claude-jsonl-reader.d.ts +156 -0
  8. package/dist/readers/readers/claude-jsonl-reader.js +556 -0
  9. package/dist/readers/readers/gemini-session-reader.d.ts +114 -0
  10. package/dist/readers/readers/gemini-session-reader.js +453 -0
  11. package/dist/readers/storage/repositories/messages.d.ts +156 -0
  12. package/dist/readers/storage/repositories/messages.js +276 -0
  13. package/dist/server/readers/claude-jsonl-reader.d.ts +156 -0
  14. package/dist/server/readers/claude-jsonl-reader.js +556 -0
  15. package/dist/server/readers/claude-session-reader.d.ts +117 -0
  16. package/dist/server/readers/claude-session-reader.js +414 -0
  17. package/dist/server/readers/gemini-session-reader.d.ts +114 -0
  18. package/dist/server/readers/gemini-session-reader.js +453 -0
  19. package/dist/server/readers/index.d.ts +8 -0
  20. package/dist/server/readers/index.js +24 -0
  21. package/dist/server/server/auth.d.ts +50 -0
  22. package/dist/server/server/auth.js +153 -0
  23. package/dist/server/server/index.d.ts +236 -0
  24. package/dist/server/server/index.js +1421 -0
  25. package/dist/server/server/port-finder.d.ts +44 -0
  26. package/dist/server/server/port-finder.js +266 -0
  27. package/dist/server/storage/index.d.ts +81 -0
  28. package/dist/server/storage/index.js +279 -0
  29. package/dist/server/storage/manager.d.ts +210 -0
  30. package/dist/server/storage/manager.js +988 -0
  31. package/dist/server/storage/repositories/events.d.ts +104 -0
  32. package/dist/server/storage/repositories/events.js +268 -0
  33. package/dist/server/storage/repositories/messages.d.ts +156 -0
  34. package/dist/server/storage/repositories/messages.js +276 -0
  35. package/dist/server/storage/repositories/sessions.d.ts +217 -0
  36. package/dist/server/storage/repositories/sessions.js +496 -0
  37. package/dist/server/storage/schema.d.ts +51 -0
  38. package/dist/server/storage/schema.js +332 -0
  39. package/dist/server/utils/prompt-detector.d.ts +27 -0
  40. package/dist/server/utils/prompt-detector.js +265 -0
  41. package/dist/server/utils/session-names.d.ts +18 -0
  42. package/dist/server/utils/session-names.js +41 -0
  43. package/dist/unified-daemon.js +0 -0
  44. package/dist/unified-hook.js +0 -0
  45. package/package.json +4 -4
File without changes
package/dist/hook.js CHANGED
File without changes
@@ -0,0 +1,45 @@
1
+ /**
2
+ * JSONL File Watcher
3
+ *
4
+ * Watches Claude JSONL files for changes and incrementally syncs new messages
5
+ * to the local database. Provides instant message sync with zero polling overhead.
6
+ */
7
+ import { StorageManager } from '../storage/manager';
8
+ export declare class JSONLWatcher {
9
+ private claudeProjectsDir;
10
+ private storageManager;
11
+ private watcher;
12
+ private fileStates;
13
+ private debounceTimers;
14
+ private broadcastCallback?;
15
+ constructor(claudeProjectsDir: string, storageManager: StorageManager);
16
+ /**
17
+ * Set callback for broadcasting events to connected clients
18
+ */
19
+ setBroadcastCallback(callback: (event: any) => void): void;
20
+ /**
21
+ * Start watching JSONL files
22
+ */
23
+ start(): void;
24
+ /**
25
+ * Stop watching files
26
+ */
27
+ stop(): Promise<void>;
28
+ /**
29
+ * Handle file change with debouncing
30
+ */
31
+ private handleFileChange;
32
+ /**
33
+ * Incrementally sync new content from a JSONL file
34
+ */
35
+ private syncFile;
36
+ /**
37
+ * Get watcher status
38
+ */
39
+ getStatus(): {
40
+ running: boolean;
41
+ watchedFiles: number;
42
+ trackedFiles: number;
43
+ };
44
+ }
45
+ //# sourceMappingURL=jsonl-watcher.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"jsonl-watcher.d.ts","sourceRoot":"","sources":["../../src/readers/jsonl-watcher.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAKH,OAAO,EAAE,cAAc,EAAE,MAAM,oBAAoB,CAAC;AAOpD,qBAAa,YAAY;IAOrB,OAAO,CAAC,iBAAiB;IACzB,OAAO,CAAC,cAAc;IAPxB,OAAO,CAAC,OAAO,CAA0B;IACzC,OAAO,CAAC,UAAU,CAAgC;IAClD,OAAO,CAAC,cAAc,CAAqC;IAC3D,OAAO,CAAC,iBAAiB,CAAC,CAAuB;gBAGvC,iBAAiB,EAAE,MAAM,EACzB,cAAc,EAAE,cAAc;IAGxC;;OAEG;IACH,oBAAoB,CAAC,QAAQ,EAAE,CAAC,KAAK,EAAE,GAAG,KAAK,IAAI,GAAG,IAAI;IAI1D;;OAEG;IACH,KAAK,IAAI,IAAI;IA+Cb;;OAEG;IACG,IAAI,IAAI,OAAO,CAAC,IAAI,CAAC;IAqB3B;;OAEG;IACH,OAAO,CAAC,gBAAgB;IAgBxB;;OAEG;YACW,QAAQ;IAiJtB;;OAEG;IACH,SAAS,IAAI;QACX,OAAO,EAAE,OAAO,CAAC;QACjB,YAAY,EAAE,MAAM,CAAC;QACrB,YAAY,EAAE,MAAM,CAAC;KACtB;CAOF"}
@@ -0,0 +1,288 @@
1
+ "use strict";
2
+ /**
3
+ * JSONL File Watcher
4
+ *
5
+ * Watches Claude JSONL files for changes and incrementally syncs new messages
6
+ * to the local database. Provides instant message sync with zero polling overhead.
7
+ */
8
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
9
+ if (k2 === undefined) k2 = k;
10
+ var desc = Object.getOwnPropertyDescriptor(m, k);
11
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
12
+ desc = { enumerable: true, get: function() { return m[k]; } };
13
+ }
14
+ Object.defineProperty(o, k2, desc);
15
+ }) : (function(o, m, k, k2) {
16
+ if (k2 === undefined) k2 = k;
17
+ o[k2] = m[k];
18
+ }));
19
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
20
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
21
+ }) : function(o, v) {
22
+ o["default"] = v;
23
+ });
24
+ var __importStar = (this && this.__importStar) || (function () {
25
+ var ownKeys = function(o) {
26
+ ownKeys = Object.getOwnPropertyNames || function (o) {
27
+ var ar = [];
28
+ for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
29
+ return ar;
30
+ };
31
+ return ownKeys(o);
32
+ };
33
+ return function (mod) {
34
+ if (mod && mod.__esModule) return mod;
35
+ var result = {};
36
+ if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
37
+ __setModuleDefault(result, mod);
38
+ return result;
39
+ };
40
+ })();
41
+ var __importDefault = (this && this.__importDefault) || function (mod) {
42
+ return (mod && mod.__esModule) ? mod : { "default": mod };
43
+ };
44
+ Object.defineProperty(exports, "__esModule", { value: true });
45
+ exports.JSONLWatcher = void 0;
46
+ const chokidar_1 = __importDefault(require("chokidar"));
47
+ const fs = __importStar(require("fs"));
48
+ const path = __importStar(require("path"));
49
+ class JSONLWatcher {
50
+ claudeProjectsDir;
51
+ storageManager;
52
+ watcher = null;
53
+ fileStates = new Map();
54
+ debounceTimers = new Map();
55
+ broadcastCallback;
56
+ constructor(claudeProjectsDir, storageManager) {
57
+ this.claudeProjectsDir = claudeProjectsDir;
58
+ this.storageManager = storageManager;
59
+ }
60
+ /**
61
+ * Set callback for broadcasting events to connected clients
62
+ */
63
+ setBroadcastCallback(callback) {
64
+ this.broadcastCallback = callback;
65
+ }
66
+ /**
67
+ * Start watching JSONL files
68
+ */
69
+ start() {
70
+ if (this.watcher) {
71
+ console.log('[JSONLWatcher] Already running');
72
+ return;
73
+ }
74
+ // Check if directory exists
75
+ if (!fs.existsSync(this.claudeProjectsDir)) {
76
+ console.log(`[JSONLWatcher] Directory not found: ${this.claudeProjectsDir}`);
77
+ console.log('[JSONLWatcher] Will not start watcher (Claude Code not installed?)');
78
+ return;
79
+ }
80
+ const watchPattern = `${this.claudeProjectsDir}/**/*.jsonl`;
81
+ console.log(`[JSONLWatcher] Starting file watcher: ${watchPattern}`);
82
+ this.watcher = chokidar_1.default.watch(watchPattern, {
83
+ persistent: true,
84
+ ignoreInitial: true, // Don't trigger on existing files at startup
85
+ // IMPORTANT: Don't use awaitWriteFinish - Claude writes continuously during responses
86
+ // and we want real-time updates, not waiting for the file to stabilize
87
+ awaitWriteFinish: false,
88
+ // Performance options
89
+ usePolling: false, // Use native fs events (faster)
90
+ interval: 100,
91
+ binaryInterval: 300,
92
+ });
93
+ this.watcher.on('change', (filePath) => {
94
+ this.handleFileChange(filePath);
95
+ });
96
+ this.watcher.on('add', (filePath) => {
97
+ console.log(`[JSONLWatcher] New file detected: ${path.basename(filePath)}`);
98
+ this.handleFileChange(filePath);
99
+ });
100
+ this.watcher.on('error', (error) => {
101
+ const message = error instanceof Error ? error.message : String(error);
102
+ console.error(`[JSONLWatcher] Error: ${message}`);
103
+ });
104
+ this.watcher.on('ready', () => {
105
+ console.log('[JSONLWatcher] Ready and watching for changes');
106
+ });
107
+ }
108
+ /**
109
+ * Stop watching files
110
+ */
111
+ async stop() {
112
+ if (!this.watcher)
113
+ return;
114
+ console.log('[JSONLWatcher] Stopping...');
115
+ // Clear all debounce timers
116
+ for (const timer of this.debounceTimers.values()) {
117
+ clearTimeout(timer);
118
+ }
119
+ this.debounceTimers.clear();
120
+ // Close watcher
121
+ await this.watcher.close();
122
+ this.watcher = null;
123
+ // Clear file states
124
+ this.fileStates.clear();
125
+ console.log('[JSONLWatcher] Stopped');
126
+ }
127
+ /**
128
+ * Handle file change with debouncing
129
+ */
130
+ handleFileChange(filePath) {
131
+ // Clear existing timer for this file
132
+ const existingTimer = this.debounceTimers.get(filePath);
133
+ if (existingTimer) {
134
+ clearTimeout(existingTimer);
135
+ }
136
+ // Set new timer - sync after 50ms of no changes (fast but batches rapid writes)
137
+ const timer = setTimeout(() => {
138
+ this.syncFile(filePath);
139
+ this.debounceTimers.delete(filePath);
140
+ }, 50);
141
+ this.debounceTimers.set(filePath, timer);
142
+ }
143
+ /**
144
+ * Incrementally sync new content from a JSONL file
145
+ */
146
+ async syncFile(filePath) {
147
+ try {
148
+ // Get current file stats
149
+ const stats = fs.statSync(filePath);
150
+ const currentSize = stats.size;
151
+ // Get last known state
152
+ const fileState = this.fileStates.get(filePath) || {
153
+ lastPosition: 0,
154
+ lastSize: 0,
155
+ };
156
+ // Check if file was truncated (rare but possible)
157
+ if (currentSize < fileState.lastSize) {
158
+ console.warn(`[JSONLWatcher] File truncated: ${path.basename(filePath)} (${fileState.lastSize} → ${currentSize} bytes)`);
159
+ fileState.lastPosition = 0;
160
+ fileState.lastSize = 0;
161
+ }
162
+ // Calculate bytes to read
163
+ const bytesToRead = currentSize - fileState.lastPosition;
164
+ if (bytesToRead <= 0) {
165
+ // No new data
166
+ return;
167
+ }
168
+ // Read only new bytes
169
+ const fd = fs.openSync(filePath, 'r');
170
+ const buffer = Buffer.alloc(bytesToRead);
171
+ fs.readSync(fd, buffer, 0, bytesToRead, fileState.lastPosition);
172
+ fs.closeSync(fd);
173
+ // Parse new lines
174
+ const newContent = buffer.toString('utf-8');
175
+ const newLines = newContent
176
+ .split('\n')
177
+ .filter(line => line.trim().length > 0);
178
+ if (newLines.length === 0) {
179
+ // Update position even if no complete lines
180
+ fileState.lastPosition = currentSize;
181
+ fileState.lastSize = currentSize;
182
+ this.fileStates.set(filePath, fileState);
183
+ return;
184
+ }
185
+ // Parse JSONL entries
186
+ const newMessages = [];
187
+ for (const line of newLines) {
188
+ try {
189
+ const entry = JSON.parse(line);
190
+ newMessages.push(entry);
191
+ }
192
+ catch (error) {
193
+ console.error(`[JSONLWatcher] Failed to parse line: ${line.substring(0, 100)}...`);
194
+ }
195
+ }
196
+ if (newMessages.length === 0) {
197
+ fileState.lastPosition = currentSize;
198
+ fileState.lastSize = currentSize;
199
+ this.fileStates.set(filePath, fileState);
200
+ return;
201
+ }
202
+ // Extract Claude session ID from first message
203
+ const firstMessage = newMessages[0];
204
+ const sessionId = firstMessage.session_id || firstMessage.sessionId;
205
+ if (!sessionId) {
206
+ console.warn(`[JSONLWatcher] No session ID in messages from ${path.basename(filePath)}`);
207
+ fileState.lastPosition = currentSize;
208
+ fileState.lastSize = currentSize;
209
+ this.fileStates.set(filePath, fileState);
210
+ return;
211
+ }
212
+ // Only process sessions that already exist in Genbox storage
213
+ // This prevents external Claude sessions from appearing in Genbox
214
+ const session = this.storageManager.sessions.getById(sessionId);
215
+ if (!session) {
216
+ // Session not created through Genbox - skip it
217
+ fileState.lastPosition = currentSize;
218
+ fileState.lastSize = currentSize;
219
+ this.fileStates.set(filePath, fileState);
220
+ return;
221
+ }
222
+ // Store new messages - these are incremental new lines from the file
223
+ // Each entry from newMessages is a new line that wasn't read before
224
+ let messagesAdded = 0;
225
+ for (const msg of newMessages) {
226
+ // Only store user/assistant messages
227
+ if (msg.type === 'user' || msg.type === 'assistant') {
228
+ // Use message UUID from Claude if available, otherwise generate one
229
+ const messageId = msg.uuid || msg.id;
230
+ try {
231
+ this.storageManager.messages.create({
232
+ id: messageId, // Use Claude's message ID to avoid duplicates
233
+ sessionId,
234
+ role: msg.role || msg.type,
235
+ content: msg.message?.content || msg.content || [],
236
+ inputTokens: msg.message?.usage?.input_tokens || msg.input_tokens || 0,
237
+ outputTokens: msg.message?.usage?.output_tokens || msg.output_tokens || 0,
238
+ cacheReadTokens: msg.message?.usage?.cache_read_input_tokens || msg.cache_read_tokens || 0,
239
+ cacheWriteTokens: msg.message?.usage?.cache_creation_input_tokens || msg.cache_write_tokens || 0,
240
+ costCents: msg.costUSD ? Math.round(msg.costUSD * 100) : (msg.cost_cents || 0),
241
+ });
242
+ messagesAdded++;
243
+ }
244
+ catch (error) {
245
+ // Ignore duplicate messages (unique constraint on ID)
246
+ if (!String(error).includes('UNIQUE')) {
247
+ console.error(`[JSONLWatcher] Failed to store message: ${error}`);
248
+ }
249
+ }
250
+ }
251
+ }
252
+ // Update file state
253
+ fileState.lastPosition = currentSize;
254
+ fileState.lastSize = currentSize;
255
+ this.fileStates.set(filePath, fileState);
256
+ if (messagesAdded > 0) {
257
+ console.log(`[JSONLWatcher] ✓ Synced ${messagesAdded} messages from ${path.basename(filePath)} (session: ${sessionId.substring(0, 8)}...)`);
258
+ // Broadcast update to connected clients
259
+ if (this.broadcastCallback) {
260
+ this.broadcastCallback({
261
+ type: 'message:received',
262
+ sessionId,
263
+ data: {
264
+ messageCount: newMessages.length,
265
+ messagesAdded,
266
+ source: 'file_watcher',
267
+ },
268
+ });
269
+ }
270
+ }
271
+ }
272
+ catch (error) {
273
+ console.error(`[JSONLWatcher] Error syncing ${path.basename(filePath)}: ${error.message}`);
274
+ }
275
+ }
276
+ /**
277
+ * Get watcher status
278
+ */
279
+ getStatus() {
280
+ return {
281
+ running: this.watcher !== null,
282
+ watchedFiles: this.watcher ? Object.keys(this.watcher.getWatched()).length : 0,
283
+ trackedFiles: this.fileStates.size,
284
+ };
285
+ }
286
+ }
287
+ exports.JSONLWatcher = JSONLWatcher;
288
+ //# sourceMappingURL=jsonl-watcher.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"jsonl-watcher.js","sourceRoot":"","sources":["../../src/readers/jsonl-watcher.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,156 @@
1
+ /**
2
+ * Claude JSONL Session Reader
3
+ *
4
+ * Reads Claude Code session data directly from ~/.claude/projects/{project}/{session}.jsonl
5
+ * Parses JSONL entries and converts them to a unified message format.
6
+ */
7
+ import { ContentBlock } from '../storage/repositories/messages';
8
+ export interface ClaudeJsonlEntry {
9
+ parentUuid?: string;
10
+ uuid: string;
11
+ type: 'user' | 'assistant' | 'system';
12
+ subtype?: string;
13
+ timestamp: string;
14
+ sessionId: string;
15
+ version?: string;
16
+ cwd?: string;
17
+ gitBranch?: string;
18
+ slug?: string;
19
+ isSidechain?: boolean;
20
+ userType?: string;
21
+ requestId?: string;
22
+ message?: {
23
+ role: 'user' | 'assistant';
24
+ model?: string;
25
+ id?: string;
26
+ type?: string;
27
+ content: string | Array<{
28
+ type: 'text' | 'tool_use' | 'tool_result' | 'image';
29
+ text?: string;
30
+ id?: string;
31
+ name?: string;
32
+ input?: Record<string, any>;
33
+ tool_use_id?: string;
34
+ content?: any;
35
+ is_error?: boolean;
36
+ }>;
37
+ stop_reason?: string | null;
38
+ usage?: {
39
+ input_tokens: number;
40
+ output_tokens: number;
41
+ cache_read_input_tokens?: number;
42
+ cache_creation_input_tokens?: number;
43
+ cache_creation?: {
44
+ ephemeral_5m_input_tokens?: number;
45
+ ephemeral_1h_input_tokens?: number;
46
+ };
47
+ };
48
+ };
49
+ toolUseResult?: Array<{
50
+ type: 'text' | 'image';
51
+ text?: string;
52
+ source?: any;
53
+ }>;
54
+ hookCount?: number;
55
+ hookInfos?: Array<{
56
+ command: string;
57
+ }>;
58
+ hookErrors?: string[];
59
+ level?: string;
60
+ }
61
+ /**
62
+ * Unified message format for display
63
+ */
64
+ export interface UnifiedMessage {
65
+ id: string;
66
+ sessionId: string;
67
+ role: 'user' | 'assistant' | 'system' | 'tool';
68
+ timestamp: number;
69
+ content: ContentBlock[];
70
+ model?: string;
71
+ inputTokens?: number;
72
+ outputTokens?: number;
73
+ cacheReadTokens?: number;
74
+ cacheWriteTokens?: number;
75
+ toolName?: string;
76
+ toolId?: string;
77
+ isToolResult?: boolean;
78
+ isError?: boolean;
79
+ preview?: string;
80
+ }
81
+ /**
82
+ * Session metadata from JSONL
83
+ */
84
+ export interface ClaudeSessionMeta {
85
+ sessionId: string;
86
+ projectPath: string;
87
+ gitBranch?: string;
88
+ version?: string;
89
+ slug?: string;
90
+ messageCount: number;
91
+ lastTimestamp?: number;
92
+ }
93
+ /**
94
+ * Find Claude project folder for the current working directory
95
+ */
96
+ export declare function findClaudeProjectFolder(cwd?: string): string | null;
97
+ /**
98
+ * Find the most recent session JSONL file across ALL project folders
99
+ * Useful for local/direct sessions where we don't know which project folder to use
100
+ */
101
+ export declare function findLatestSessionFileGlobal(): string | null;
102
+ /**
103
+ * Find the Claude session file closest to a given timestamp
104
+ * Used to match dtach sessions to their corresponding Claude JSONL files
105
+ * @param targetTimestamp - Unix timestamp in milliseconds
106
+ * @param maxDeltaMs - Maximum time difference to consider a match (default 5 minutes)
107
+ */
108
+ export declare function findSessionFileByTimestamp(targetTimestamp: number, maxDeltaMs?: number): string | null;
109
+ /**
110
+ * Find the Claude session file closest to a given timestamp within a specific project folder
111
+ * Used to match dtach sessions to their corresponding Claude JSONL files
112
+ * @param projectFolder - The Claude project folder path
113
+ * @param targetTimestamp - Unix timestamp in milliseconds
114
+ * @param maxDeltaMs - Maximum time difference to consider a match (default 5 minutes)
115
+ */
116
+ export declare function findSessionFileByTimestampInProject(projectFolder: string, targetTimestamp: number, maxDeltaMs?: number): string | null;
117
+ /**
118
+ * Find the most recent session JSONL file in a project folder
119
+ */
120
+ export declare function findLatestSessionFile(projectFolder: string): string | null;
121
+ /**
122
+ * Find session file by session ID (UUID)
123
+ */
124
+ export declare function findSessionFile(projectFolder: string, sessionId: string): string | null;
125
+ /**
126
+ * Read and parse a Claude JSONL session file
127
+ * Returns messages in chronological order
128
+ */
129
+ export declare function readClaudeSession(filePath: string, options?: {
130
+ limit?: number;
131
+ fromTimestamp?: number;
132
+ }): Promise<{
133
+ messages: UnifiedMessage[];
134
+ meta: ClaudeSessionMeta;
135
+ }>;
136
+ /**
137
+ * Read Claude session synchronously (for simpler use cases)
138
+ * Note: For large files, prefer the async version
139
+ */
140
+ export declare function readClaudeSessionSync(filePath: string, limit?: number): UnifiedMessage[];
141
+ /**
142
+ * Watch a Claude session file for changes
143
+ * Calls callback with new messages when file is updated
144
+ */
145
+ export declare function watchClaudeSession(filePath: string, callback: (messages: UnifiedMessage[]) => void, options?: {
146
+ pollInterval?: number;
147
+ }): () => void;
148
+ /**
149
+ * List all Claude sessions in a project folder
150
+ */
151
+ export declare function listClaudeSessions(projectFolder: string): Array<{
152
+ sessionId: string;
153
+ filePath: string;
154
+ size: number;
155
+ lastModified: number;
156
+ }>;