@threadbase-sh/scanner 0.7.2 → 0.8.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/dist/index.d.cts CHANGED
@@ -23,10 +23,14 @@ interface MessageSnapshot {
23
23
  text: string;
24
24
  timestamp: string;
25
25
  }
26
+ type ProviderName = "claude-code" | "codex-cli";
26
27
  interface ConversationMeta {
27
28
  id: string;
28
29
  filePath: string;
29
30
  sessionId: string;
31
+ provider?: ProviderName;
32
+ kind?: "conversation" | "task";
33
+ externalSessionId?: string;
30
34
  sessionName: string;
31
35
  projectPath: string;
32
36
  projectName: string;
@@ -59,6 +63,8 @@ interface FileStatEntry {
59
63
  }
60
64
  interface ScanOptions {
61
65
  profiles?: Profile[];
66
+ providers?: ProviderName[];
67
+ codexRoots?: string[];
62
68
  tier?: string;
63
69
  tiers?: Record<string, ContentTier>;
64
70
  include?: Include;
@@ -85,6 +91,7 @@ interface ScanResult {
85
91
  }
86
92
  interface SearchOptions extends ScanOptions {
87
93
  fields?: string[];
94
+ provider?: ProviderName;
88
95
  }
89
96
  interface SearchMatch {
90
97
  field: string;
@@ -214,7 +221,6 @@ declare class SearchIndexer {
214
221
  limit?: number;
215
222
  }): SearchResult[];
216
223
  private getRecent;
217
- private generateMatches;
218
224
  getDocumentCount(): number;
219
225
  updateDocument(meta: ConversationMeta): void;
220
226
  removeDocument(id: string): void;
@@ -225,12 +231,131 @@ declare function createLogger(options?: LoggerOptions | Logger): Logger;
225
231
  declare function setLogger(logger: Logger): void;
226
232
  declare function getLogger(): Logger;
227
233
 
234
+ interface Sidecar {
235
+ version: number;
236
+ sourcePath: string;
237
+ sizeBytes: number;
238
+ mtimeMs: number;
239
+ lastIndexedOffset: number;
240
+ lastIndexedLine: number;
241
+ messageCount: number;
242
+ projectPath: string;
243
+ projectName: string;
244
+ branch: string | null;
245
+ firstSentAt: string | null;
246
+ firstSentText: string | null;
247
+ lastSentAt: string | null;
248
+ lastSentText: string | null;
249
+ updatedAt: string;
250
+ }
251
+ declare function sidecarPath(jsonlPath: string): string;
252
+ declare function readSidecar(jsonlPath: string): Sidecar | null;
253
+
228
254
  declare function resolveConfigDir(configDir: string): string;
229
255
  declare function getProjectsDir(profile: Profile): string;
230
256
  declare function detectDefaultProfile(): Promise<Profile>;
231
257
  declare function loadProfiles(configPath: string): Promise<Profile[]>;
232
258
  declare function saveProfiles(profiles: Profile[], configPath: string): Promise<void>;
233
259
 
260
+ interface ScannerProvider<Acc = unknown> {
261
+ name: ScannerProviderName;
262
+ discover(roots: string[]): Promise<DiscoveredConversationFile[]>;
263
+ canParse(filePath: string, sample: string): boolean;
264
+ createEmptyAccumulator(): Acc;
265
+ reduceEntry(acc: Acc, entry: Record<string, unknown>, tier: ContentTier): void;
266
+ finalize(acc: Acc, filePath: string, account: string, tier: ContentTier): ConversationMeta | null;
267
+ }
268
+ type ScannerProviderName = "claude-code" | "codex-cli";
269
+ interface DiscoveredConversationFile {
270
+ filePath: string;
271
+ account: string;
272
+ }
273
+
274
+ interface CodexAccumulator {
275
+ sessionId: string;
276
+ cwd: string;
277
+ gitBranch: string | null;
278
+ model: string | null;
279
+ latestTimestamp: string;
280
+ messageCount: number;
281
+ lastMessageSender: MessageSender;
282
+ firstUser: MessageSnapshot | null;
283
+ lastUser: MessageSnapshot | null;
284
+ lastAssistant: MessageSnapshot | null;
285
+ toolNames: string[];
286
+ previewParts: string[];
287
+ previewLength: number;
288
+ snippetParts: string[];
289
+ snippetLength: number;
290
+ }
291
+ declare class CodexCliProvider implements ScannerProvider<CodexAccumulator> {
292
+ readonly name: "codex-cli";
293
+ discover(roots: string[]): Promise<DiscoveredConversationFile[]>;
294
+ canParse(_filePath: string, sample: string): boolean;
295
+ createEmptyAccumulator(): CodexAccumulator;
296
+ reduceEntry(acc: CodexAccumulator, entry: Record<string, unknown>, tier: ContentTier): void;
297
+ finalize(acc: CodexAccumulator, filePath: string, account: string, tier: ContentTier): ConversationMeta | null;
298
+ }
299
+
300
+ interface ReducerState {
301
+ sessionId: string;
302
+ sessionName: string;
303
+ latestTimestamp: string;
304
+ cwd: string;
305
+ teamName: string;
306
+ model: string | null;
307
+ messageCount: number;
308
+ pageMessageCount: number;
309
+ lastMessageSender: MessageSender;
310
+ isTeammate: boolean;
311
+ firstUserSeen: boolean;
312
+ firstMessage: MessageSnapshot | null;
313
+ lastMessage: MessageSnapshot | null;
314
+ lastPrompt: string;
315
+ toolNames: string[];
316
+ previewParts: string[];
317
+ snippetParts: string[];
318
+ previewLength: number;
319
+ snippetLength: number;
320
+ badJsonLines: number;
321
+ }
322
+
323
+ declare class ThreadbaseProvider implements ScannerProvider<ReducerState> {
324
+ readonly name: "claude-code";
325
+ discover(roots: string[]): Promise<DiscoveredConversationFile[]>;
326
+ canParse(_filePath: string, sample: string): boolean;
327
+ createEmptyAccumulator(): ReducerState;
328
+ reduceEntry(acc: ReducerState, entry: Record<string, unknown>, tier: ContentTier): void;
329
+ finalize(acc: ReducerState, filePath: string, account: string, tier: ContentTier): ConversationMeta | null;
330
+ }
331
+
332
+ type JobReason = "watcher" | "manual" | "periodic";
333
+ interface IndexJob {
334
+ filePath: string;
335
+ account: string;
336
+ reason: JobReason;
337
+ }
338
+
339
+ interface PersistentConfig {
340
+ dbPath?: string;
341
+ sidecar?: boolean;
342
+ }
343
+ interface ConversationScannerOptions {
344
+ metadataCacheSize?: number;
345
+ conversationCacheSize?: number;
346
+ persistent?: false | PersistentConfig;
347
+ }
348
+ interface WatchOptions {
349
+ profiles?: Profile[];
350
+ debounceMs?: number;
351
+ periodicMs?: number;
352
+ }
353
+ interface ScannerChangeEvent {
354
+ filePath: string;
355
+ account: string;
356
+ meta: ConversationMeta | null;
357
+ reason: IndexJob["reason"];
358
+ }
234
359
  declare class ConversationScanner {
235
360
  private metadataCache;
236
361
  private conversationLRU;
@@ -238,18 +363,41 @@ declare class ConversationScanner {
238
363
  private projects;
239
364
  private indexer;
240
365
  private lastTier;
241
- constructor(options?: {
242
- metadataCacheSize?: number;
243
- conversationCacheSize?: number;
244
- });
366
+ private readonly dbPath;
367
+ private readonly sidecarEnabled;
368
+ private engineInstance;
369
+ private emitter;
370
+ private watcher;
371
+ private queue;
372
+ private periodicTimer;
373
+ constructor(options?: ConversationScannerOptions);
374
+ private get persistent();
375
+ private engine;
376
+ close(): void;
245
377
  scan(options?: ScanOptions): Promise<ScanResult>;
378
+ private scanPersistent;
379
+ private finalize;
380
+ private scanInMemory;
246
381
  search(query: string, options?: SearchOptions): Promise<SearchResult[]>;
247
382
  getConversation(id: string, _options?: GetConversationOptions): Promise<Conversation | null>;
248
383
  getConversationPage(id: string, options: GetConversationPageOptions): Promise<ConversationPage | null>;
249
384
  parseSingleFilePage(filePath: string, account: string | undefined, options: GetConversationPageOptions): Promise<SingleFilePage | null>;
250
385
  refreshFile(filePath: string, account?: string): Promise<ConversationMeta | null>;
251
386
  getMetadataCache(): Map<string, ConversationMeta>;
387
+ getConversationsBySessionId(sessionId: string): ConversationMeta[];
252
388
  getProjects(): string[];
389
+ on(event: "change", listener: (e: ScannerChangeEvent) => void): this;
390
+ on(event: "error", listener: (err: Error) => void): this;
391
+ off(event: string, listener: (...args: any[]) => void): this;
392
+ watch(options?: WatchOptions): Promise<void>;
393
+ private periodicReconcile;
394
+ unwatch(): Promise<void>;
395
+ private discoverWithProviders;
396
+ private resolveProviderForFile;
397
+ private addToSessionIndex;
398
+ private removeFromSessionIndex;
399
+ private resolveSessionId;
400
+ private sortBySessionPriority;
253
401
  private resolveProfiles;
254
402
  private transformView;
255
403
  private toTree;
@@ -266,4 +414,4 @@ declare function scan(options?: ScanOptions, scanner?: ConversationScanner): Pro
266
414
  declare function search(query: string, options?: SearchOptions, scanner?: ConversationScanner): Promise<SearchResult[]>;
267
415
  declare function getConversation(id: string, options?: GetConversationOptions, scanner?: ConversationScanner): Promise<Conversation | null>;
268
416
 
269
- export { type AttachmentSidecar, type ContentTier, type Conversation, type ConversationMessage, type ConversationMeta, type ConversationPage, ConversationScanner, DEFAULT_TIERS, type DeferredToolsDeltaAttachment, type FileStatEntry, type GetConversationOptions, type GetConversationPageOptions, type GroupedConversations, type Include, type MessageMetadata, type MessageSender, type MessageSnapshot, type Profile, type ScanOptions, type ScanResult, SearchIndexer, type SearchMatch, type SearchOptions, type SearchResult, type SingleFilePage, type SortOrder, type TeamInfo, type ToolResultBlock, type ToolUseBlock, type TreeConversation, type TurnDuration, VALID_SORT_ORDERS, type View, applyAccountFilter, applyIncludeFilter, applyPagination, applyProjectFilter, applySinceFilter, applySort, cleanSystemTags, createLogger, detectDefaultProfile, getConversation, getLogger, getProjectsDir, loadProfiles, readGitBranch, resetDefaultScanner, resolveConfigDir, resolveTier, saveProfiles, scan, search, setLogger };
417
+ export { type AttachmentSidecar, CodexCliProvider, type ContentTier, type Conversation, type ConversationMessage, type ConversationMeta, type ConversationPage, ConversationScanner, type ConversationScannerOptions, DEFAULT_TIERS, type DeferredToolsDeltaAttachment, type DiscoveredConversationFile, type FileStatEntry, type GetConversationOptions, type GetConversationPageOptions, type GroupedConversations, type Include, type MessageMetadata, type MessageSender, type MessageSnapshot, type PersistentConfig, type Profile, type ProviderName, type ScanOptions, type ScanResult, type ScannerChangeEvent, type ScannerProvider, type ScannerProviderName, SearchIndexer, type SearchMatch, type SearchOptions, type SearchResult, type Sidecar, type SingleFilePage, type SortOrder, type TeamInfo, ThreadbaseProvider, type ToolResultBlock, type ToolUseBlock, type TreeConversation, type TurnDuration, VALID_SORT_ORDERS, type View, type WatchOptions, applyAccountFilter, applyIncludeFilter, applyPagination, applyProjectFilter, applySinceFilter, applySort, cleanSystemTags, createLogger, detectDefaultProfile, getConversation, getLogger, getProjectsDir, loadProfiles, readGitBranch, readSidecar, resetDefaultScanner, resolveConfigDir, resolveTier, saveProfiles, scan, search, setLogger, sidecarPath };
package/dist/index.d.ts CHANGED
@@ -23,10 +23,14 @@ interface MessageSnapshot {
23
23
  text: string;
24
24
  timestamp: string;
25
25
  }
26
+ type ProviderName = "claude-code" | "codex-cli";
26
27
  interface ConversationMeta {
27
28
  id: string;
28
29
  filePath: string;
29
30
  sessionId: string;
31
+ provider?: ProviderName;
32
+ kind?: "conversation" | "task";
33
+ externalSessionId?: string;
30
34
  sessionName: string;
31
35
  projectPath: string;
32
36
  projectName: string;
@@ -59,6 +63,8 @@ interface FileStatEntry {
59
63
  }
60
64
  interface ScanOptions {
61
65
  profiles?: Profile[];
66
+ providers?: ProviderName[];
67
+ codexRoots?: string[];
62
68
  tier?: string;
63
69
  tiers?: Record<string, ContentTier>;
64
70
  include?: Include;
@@ -85,6 +91,7 @@ interface ScanResult {
85
91
  }
86
92
  interface SearchOptions extends ScanOptions {
87
93
  fields?: string[];
94
+ provider?: ProviderName;
88
95
  }
89
96
  interface SearchMatch {
90
97
  field: string;
@@ -214,7 +221,6 @@ declare class SearchIndexer {
214
221
  limit?: number;
215
222
  }): SearchResult[];
216
223
  private getRecent;
217
- private generateMatches;
218
224
  getDocumentCount(): number;
219
225
  updateDocument(meta: ConversationMeta): void;
220
226
  removeDocument(id: string): void;
@@ -225,12 +231,131 @@ declare function createLogger(options?: LoggerOptions | Logger): Logger;
225
231
  declare function setLogger(logger: Logger): void;
226
232
  declare function getLogger(): Logger;
227
233
 
234
+ interface Sidecar {
235
+ version: number;
236
+ sourcePath: string;
237
+ sizeBytes: number;
238
+ mtimeMs: number;
239
+ lastIndexedOffset: number;
240
+ lastIndexedLine: number;
241
+ messageCount: number;
242
+ projectPath: string;
243
+ projectName: string;
244
+ branch: string | null;
245
+ firstSentAt: string | null;
246
+ firstSentText: string | null;
247
+ lastSentAt: string | null;
248
+ lastSentText: string | null;
249
+ updatedAt: string;
250
+ }
251
+ declare function sidecarPath(jsonlPath: string): string;
252
+ declare function readSidecar(jsonlPath: string): Sidecar | null;
253
+
228
254
  declare function resolveConfigDir(configDir: string): string;
229
255
  declare function getProjectsDir(profile: Profile): string;
230
256
  declare function detectDefaultProfile(): Promise<Profile>;
231
257
  declare function loadProfiles(configPath: string): Promise<Profile[]>;
232
258
  declare function saveProfiles(profiles: Profile[], configPath: string): Promise<void>;
233
259
 
260
+ interface ScannerProvider<Acc = unknown> {
261
+ name: ScannerProviderName;
262
+ discover(roots: string[]): Promise<DiscoveredConversationFile[]>;
263
+ canParse(filePath: string, sample: string): boolean;
264
+ createEmptyAccumulator(): Acc;
265
+ reduceEntry(acc: Acc, entry: Record<string, unknown>, tier: ContentTier): void;
266
+ finalize(acc: Acc, filePath: string, account: string, tier: ContentTier): ConversationMeta | null;
267
+ }
268
+ type ScannerProviderName = "claude-code" | "codex-cli";
269
+ interface DiscoveredConversationFile {
270
+ filePath: string;
271
+ account: string;
272
+ }
273
+
274
+ interface CodexAccumulator {
275
+ sessionId: string;
276
+ cwd: string;
277
+ gitBranch: string | null;
278
+ model: string | null;
279
+ latestTimestamp: string;
280
+ messageCount: number;
281
+ lastMessageSender: MessageSender;
282
+ firstUser: MessageSnapshot | null;
283
+ lastUser: MessageSnapshot | null;
284
+ lastAssistant: MessageSnapshot | null;
285
+ toolNames: string[];
286
+ previewParts: string[];
287
+ previewLength: number;
288
+ snippetParts: string[];
289
+ snippetLength: number;
290
+ }
291
+ declare class CodexCliProvider implements ScannerProvider<CodexAccumulator> {
292
+ readonly name: "codex-cli";
293
+ discover(roots: string[]): Promise<DiscoveredConversationFile[]>;
294
+ canParse(_filePath: string, sample: string): boolean;
295
+ createEmptyAccumulator(): CodexAccumulator;
296
+ reduceEntry(acc: CodexAccumulator, entry: Record<string, unknown>, tier: ContentTier): void;
297
+ finalize(acc: CodexAccumulator, filePath: string, account: string, tier: ContentTier): ConversationMeta | null;
298
+ }
299
+
300
+ interface ReducerState {
301
+ sessionId: string;
302
+ sessionName: string;
303
+ latestTimestamp: string;
304
+ cwd: string;
305
+ teamName: string;
306
+ model: string | null;
307
+ messageCount: number;
308
+ pageMessageCount: number;
309
+ lastMessageSender: MessageSender;
310
+ isTeammate: boolean;
311
+ firstUserSeen: boolean;
312
+ firstMessage: MessageSnapshot | null;
313
+ lastMessage: MessageSnapshot | null;
314
+ lastPrompt: string;
315
+ toolNames: string[];
316
+ previewParts: string[];
317
+ snippetParts: string[];
318
+ previewLength: number;
319
+ snippetLength: number;
320
+ badJsonLines: number;
321
+ }
322
+
323
+ declare class ThreadbaseProvider implements ScannerProvider<ReducerState> {
324
+ readonly name: "claude-code";
325
+ discover(roots: string[]): Promise<DiscoveredConversationFile[]>;
326
+ canParse(_filePath: string, sample: string): boolean;
327
+ createEmptyAccumulator(): ReducerState;
328
+ reduceEntry(acc: ReducerState, entry: Record<string, unknown>, tier: ContentTier): void;
329
+ finalize(acc: ReducerState, filePath: string, account: string, tier: ContentTier): ConversationMeta | null;
330
+ }
331
+
332
+ type JobReason = "watcher" | "manual" | "periodic";
333
+ interface IndexJob {
334
+ filePath: string;
335
+ account: string;
336
+ reason: JobReason;
337
+ }
338
+
339
+ interface PersistentConfig {
340
+ dbPath?: string;
341
+ sidecar?: boolean;
342
+ }
343
+ interface ConversationScannerOptions {
344
+ metadataCacheSize?: number;
345
+ conversationCacheSize?: number;
346
+ persistent?: false | PersistentConfig;
347
+ }
348
+ interface WatchOptions {
349
+ profiles?: Profile[];
350
+ debounceMs?: number;
351
+ periodicMs?: number;
352
+ }
353
+ interface ScannerChangeEvent {
354
+ filePath: string;
355
+ account: string;
356
+ meta: ConversationMeta | null;
357
+ reason: IndexJob["reason"];
358
+ }
234
359
  declare class ConversationScanner {
235
360
  private metadataCache;
236
361
  private conversationLRU;
@@ -238,18 +363,41 @@ declare class ConversationScanner {
238
363
  private projects;
239
364
  private indexer;
240
365
  private lastTier;
241
- constructor(options?: {
242
- metadataCacheSize?: number;
243
- conversationCacheSize?: number;
244
- });
366
+ private readonly dbPath;
367
+ private readonly sidecarEnabled;
368
+ private engineInstance;
369
+ private emitter;
370
+ private watcher;
371
+ private queue;
372
+ private periodicTimer;
373
+ constructor(options?: ConversationScannerOptions);
374
+ private get persistent();
375
+ private engine;
376
+ close(): void;
245
377
  scan(options?: ScanOptions): Promise<ScanResult>;
378
+ private scanPersistent;
379
+ private finalize;
380
+ private scanInMemory;
246
381
  search(query: string, options?: SearchOptions): Promise<SearchResult[]>;
247
382
  getConversation(id: string, _options?: GetConversationOptions): Promise<Conversation | null>;
248
383
  getConversationPage(id: string, options: GetConversationPageOptions): Promise<ConversationPage | null>;
249
384
  parseSingleFilePage(filePath: string, account: string | undefined, options: GetConversationPageOptions): Promise<SingleFilePage | null>;
250
385
  refreshFile(filePath: string, account?: string): Promise<ConversationMeta | null>;
251
386
  getMetadataCache(): Map<string, ConversationMeta>;
387
+ getConversationsBySessionId(sessionId: string): ConversationMeta[];
252
388
  getProjects(): string[];
389
+ on(event: "change", listener: (e: ScannerChangeEvent) => void): this;
390
+ on(event: "error", listener: (err: Error) => void): this;
391
+ off(event: string, listener: (...args: any[]) => void): this;
392
+ watch(options?: WatchOptions): Promise<void>;
393
+ private periodicReconcile;
394
+ unwatch(): Promise<void>;
395
+ private discoverWithProviders;
396
+ private resolveProviderForFile;
397
+ private addToSessionIndex;
398
+ private removeFromSessionIndex;
399
+ private resolveSessionId;
400
+ private sortBySessionPriority;
253
401
  private resolveProfiles;
254
402
  private transformView;
255
403
  private toTree;
@@ -266,4 +414,4 @@ declare function scan(options?: ScanOptions, scanner?: ConversationScanner): Pro
266
414
  declare function search(query: string, options?: SearchOptions, scanner?: ConversationScanner): Promise<SearchResult[]>;
267
415
  declare function getConversation(id: string, options?: GetConversationOptions, scanner?: ConversationScanner): Promise<Conversation | null>;
268
416
 
269
- export { type AttachmentSidecar, type ContentTier, type Conversation, type ConversationMessage, type ConversationMeta, type ConversationPage, ConversationScanner, DEFAULT_TIERS, type DeferredToolsDeltaAttachment, type FileStatEntry, type GetConversationOptions, type GetConversationPageOptions, type GroupedConversations, type Include, type MessageMetadata, type MessageSender, type MessageSnapshot, type Profile, type ScanOptions, type ScanResult, SearchIndexer, type SearchMatch, type SearchOptions, type SearchResult, type SingleFilePage, type SortOrder, type TeamInfo, type ToolResultBlock, type ToolUseBlock, type TreeConversation, type TurnDuration, VALID_SORT_ORDERS, type View, applyAccountFilter, applyIncludeFilter, applyPagination, applyProjectFilter, applySinceFilter, applySort, cleanSystemTags, createLogger, detectDefaultProfile, getConversation, getLogger, getProjectsDir, loadProfiles, readGitBranch, resetDefaultScanner, resolveConfigDir, resolveTier, saveProfiles, scan, search, setLogger };
417
+ export { type AttachmentSidecar, CodexCliProvider, type ContentTier, type Conversation, type ConversationMessage, type ConversationMeta, type ConversationPage, ConversationScanner, type ConversationScannerOptions, DEFAULT_TIERS, type DeferredToolsDeltaAttachment, type DiscoveredConversationFile, type FileStatEntry, type GetConversationOptions, type GetConversationPageOptions, type GroupedConversations, type Include, type MessageMetadata, type MessageSender, type MessageSnapshot, type PersistentConfig, type Profile, type ProviderName, type ScanOptions, type ScanResult, type ScannerChangeEvent, type ScannerProvider, type ScannerProviderName, SearchIndexer, type SearchMatch, type SearchOptions, type SearchResult, type Sidecar, type SingleFilePage, type SortOrder, type TeamInfo, ThreadbaseProvider, type ToolResultBlock, type ToolUseBlock, type TreeConversation, type TurnDuration, VALID_SORT_ORDERS, type View, type WatchOptions, applyAccountFilter, applyIncludeFilter, applyPagination, applyProjectFilter, applySinceFilter, applySort, cleanSystemTags, createLogger, detectDefaultProfile, getConversation, getLogger, getProjectsDir, loadProfiles, readGitBranch, readSidecar, resetDefaultScanner, resolveConfigDir, resolveTier, saveProfiles, scan, search, setLogger, sidecarPath };