@threadbase-sh/streamer 1.27.2 → 1.28.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.
- package/dist/cli.cjs +636 -156
- package/dist/cli.cjs.map +1 -1
- package/dist/index.cjs +500 -37
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +118 -1
- package/dist/index.d.ts +118 -1
- package/dist/index.js +481 -15
- package/dist/index.js.map +1 -1
- package/dist/migrations/009_create_offset_index.sql +28 -0
- package/package.json +2 -2
package/dist/index.d.cts
CHANGED
|
@@ -6,8 +6,9 @@ import { Logger as Logger$1 } from 'pino';
|
|
|
6
6
|
import { HttpBindings } from '@hono/node-server';
|
|
7
7
|
import { ServerResponse, IncomingMessage } from 'http';
|
|
8
8
|
import { WebSocket } from 'ws';
|
|
9
|
-
import { FileStatEntry, ConversationMeta } from '@threadbase-sh/scanner';
|
|
9
|
+
import { ConversationMessage, FileStatEntry, ConversationMeta } from '@threadbase-sh/scanner';
|
|
10
10
|
import Database from 'better-sqlite3';
|
|
11
|
+
import { Stats } from 'fs';
|
|
11
12
|
import { z } from 'zod';
|
|
12
13
|
import { Pool } from 'pg';
|
|
13
14
|
|
|
@@ -190,6 +191,7 @@ type WSMessage = {
|
|
|
190
191
|
type: "conversation_events";
|
|
191
192
|
sessionId: string;
|
|
192
193
|
lines: string[];
|
|
194
|
+
seqs?: (number | null)[];
|
|
193
195
|
} | {
|
|
194
196
|
type: "question";
|
|
195
197
|
sessionId: string;
|
|
@@ -367,6 +369,15 @@ interface SessionRunner {
|
|
|
367
369
|
dispose(): void;
|
|
368
370
|
}
|
|
369
371
|
|
|
372
|
+
interface LineSpan {
|
|
373
|
+
/** Absolute byte offset of the line's first byte in the file. */
|
|
374
|
+
byteOffset: number;
|
|
375
|
+
/** Byte length of the line content, excluding the trailing "\n". */
|
|
376
|
+
byteLength: number;
|
|
377
|
+
/** The decoded line text (no trailing "\n"). */
|
|
378
|
+
text: string;
|
|
379
|
+
}
|
|
380
|
+
|
|
370
381
|
interface ConversationCacheOptions {
|
|
371
382
|
filterAgentConversations?: boolean;
|
|
372
383
|
agentEntrypoints?: ReadonlySet<string>;
|
|
@@ -401,6 +412,25 @@ interface CachedTail {
|
|
|
401
412
|
messages: CachedTailMessage[];
|
|
402
413
|
tailSize: number;
|
|
403
414
|
}
|
|
415
|
+
/** A row of `conversation_file_state` — per-file offset-index resume state. */
|
|
416
|
+
interface FileStateRow {
|
|
417
|
+
path: string;
|
|
418
|
+
identity: string;
|
|
419
|
+
size: number;
|
|
420
|
+
mtime_ms: number;
|
|
421
|
+
byte_offset: number;
|
|
422
|
+
last_message_index: number;
|
|
423
|
+
}
|
|
424
|
+
/** A row of `conversation_message_index` — one indexed message's byte span. */
|
|
425
|
+
interface MessageIndexRow {
|
|
426
|
+
conversation_id: string;
|
|
427
|
+
message_index: number;
|
|
428
|
+
byte_offset: number;
|
|
429
|
+
byte_length: number;
|
|
430
|
+
uuid: string | null;
|
|
431
|
+
role: string | null;
|
|
432
|
+
ts: number | null;
|
|
433
|
+
}
|
|
404
434
|
interface ScannerMeta {
|
|
405
435
|
id: string;
|
|
406
436
|
sessionId?: string;
|
|
@@ -423,6 +453,8 @@ declare class ConversationCache {
|
|
|
423
453
|
private tailSize;
|
|
424
454
|
private fileIndex;
|
|
425
455
|
private fileIndexLoaded;
|
|
456
|
+
private indexParseState;
|
|
457
|
+
private backfillInFlight;
|
|
426
458
|
private tailSeq;
|
|
427
459
|
private nameSeq;
|
|
428
460
|
private stmts;
|
|
@@ -436,6 +468,78 @@ declare class ConversationCache {
|
|
|
436
468
|
* share the same connection. Internal API; not part of the public surface.
|
|
437
469
|
*/
|
|
438
470
|
getDatabase(): Database.Database;
|
|
471
|
+
getFileState(path: string): FileStateRow | null;
|
|
472
|
+
upsertFileState(row: FileStateRow): void;
|
|
473
|
+
/** Drop a file's index rows + file_state (truncation / identity change). */
|
|
474
|
+
deleteFileIndex(path: string, conversationId: string): void;
|
|
475
|
+
/** Append/replace index rows in one transaction. */
|
|
476
|
+
appendMessageIndexRows(rows: MessageIndexRow[]): void;
|
|
477
|
+
/** Rows for message_index in [fromIndex, toIndex), ordered ascending. */
|
|
478
|
+
getMessageIndexWindow(conversationId: string, fromIndex: number, toIndex: number): MessageIndexRow[];
|
|
479
|
+
getIndexedMessageCount(conversationId: string): number;
|
|
480
|
+
/**
|
|
481
|
+
* Conversation id for a JSONL path — the filename stem (matches the pseudo-id
|
|
482
|
+
* updateFromLine derives and the uuid the detail read path resolves). The
|
|
483
|
+
* offset index keys on this so the window select and the cursor agree.
|
|
484
|
+
*/
|
|
485
|
+
static conversationIdForFile(filePath: string): string;
|
|
486
|
+
/**
|
|
487
|
+
* Incremental offset-index writer: extend the index for a burst of appended
|
|
488
|
+
* lines (one watcher read) using their byte spans. Each line is classified
|
|
489
|
+
* with the scanner's parseJsonlLine (a running per-file reducer state), so the
|
|
490
|
+
* message ordering can never drift from the scanner's. Message lines get an
|
|
491
|
+
* index row at the next message_index; non-message lines (summary/sidecar)
|
|
492
|
+
* get no row but still advance byte_offset. file_state is updated to the end
|
|
493
|
+
* of the last consumed span.
|
|
494
|
+
*
|
|
495
|
+
* Requires an up-to-date `stat` (identity/size/mtime) for the file so the read
|
|
496
|
+
* path can detect truncation/replacement.
|
|
497
|
+
*
|
|
498
|
+
* `readFrom` is the absolute byte offset the watcher read started at, and
|
|
499
|
+
* `endOffset` is where it ended (readFrom + consumed, i.e. the watcher's new
|
|
500
|
+
* entry.offset). CONTIGUITY GUARD: the read must begin exactly where the index
|
|
501
|
+
* left off (`readFrom === existing.byte_offset`, or 0 with no state). If it
|
|
502
|
+
* doesn't — the watcher attached at EOF after the server was down, or an
|
|
503
|
+
* append raced an in-flight backfill — extending would assign wrong
|
|
504
|
+
* message_index values over a hole. In that case this writes nothing and
|
|
505
|
+
* returns null so the caller drops the index and backfills.
|
|
506
|
+
*
|
|
507
|
+
* On success returns the message_index assigned to each input span (null for a
|
|
508
|
+
* non-message line) so the caller can stamp WS `seq`. Empty array when spans
|
|
509
|
+
* is empty. `endOffset` is stored verbatim as byte_offset so the watcher's
|
|
510
|
+
* offset and file_state.byte_offset are the same number by construction.
|
|
511
|
+
*/
|
|
512
|
+
extendMessageIndex(filePath: string, spans: LineSpan[], stat: Stats, readFrom: number, endOffset: number): (number | null)[] | null;
|
|
513
|
+
clearIndexParseState(filePath: string): void;
|
|
514
|
+
/**
|
|
515
|
+
* On-demand full backfill of the offset index for a file with no/stale
|
|
516
|
+
* file_state (cold conversation, or after a truncation/replacement). Rebuilds
|
|
517
|
+
* from byte 0: drops any existing rows, walks the whole file in chunks with a
|
|
518
|
+
* running parse state, yields to the event loop every ~1000 lines so a large
|
|
519
|
+
* file never blocks, and writes index rows + file_state.
|
|
520
|
+
*
|
|
521
|
+
* Single-flighted per path: concurrent callers await the same walk. The
|
|
522
|
+
* triggering detail request is served by the scanner fallback while this runs.
|
|
523
|
+
*/
|
|
524
|
+
backfillIndex(filePath: string): Promise<void>;
|
|
525
|
+
private runBackfill;
|
|
526
|
+
/**
|
|
527
|
+
* Windowed detail read straight from the offset index — the hot path.
|
|
528
|
+
* Returns the parsed messages for message_index in [fromIndex, toIndex) plus
|
|
529
|
+
* the total indexed count, or null when the index can't serve this file (no
|
|
530
|
+
* file_state, identity/size mismatch = truncation/replacement, or cold index)
|
|
531
|
+
* so the caller falls back to the scanner and enqueues a backfill.
|
|
532
|
+
*
|
|
533
|
+
* On a match it SQL-selects the window's byte ranges and preads exactly those
|
|
534
|
+
* ranges from the JSONL (never the whole file), parsing only the sliced lines.
|
|
535
|
+
* Returns messages in the same ConversationMessage shape parseJsonlLine
|
|
536
|
+
* produces during a scan, so the payload is identical to the scanner path.
|
|
537
|
+
*/
|
|
538
|
+
readMessageWindow(filePath: string, fromIndex: number, toIndex: number): {
|
|
539
|
+
messages: ConversationMessage[];
|
|
540
|
+
total: number;
|
|
541
|
+
fromIndex: number;
|
|
542
|
+
} | null;
|
|
439
543
|
private agentEntrypointsKey;
|
|
440
544
|
private classifyAgentFile;
|
|
441
545
|
isAgentFileCached(filePath: string): boolean;
|
|
@@ -874,6 +978,7 @@ declare class StreamerServer {
|
|
|
874
978
|
private wsHub;
|
|
875
979
|
private fileWatcher;
|
|
876
980
|
private sessionFileMap;
|
|
981
|
+
private pendingLineSeqs;
|
|
877
982
|
private pendingQuestions;
|
|
878
983
|
private pendingQuestionKey;
|
|
879
984
|
private pendingPermission;
|
|
@@ -882,6 +987,7 @@ declare class StreamerServer {
|
|
|
882
987
|
private allScanners;
|
|
883
988
|
private scannerReady;
|
|
884
989
|
private scannerStale;
|
|
990
|
+
private refreshInFlight;
|
|
885
991
|
private binding;
|
|
886
992
|
private cacheReady;
|
|
887
993
|
private inFlightCacheWrites;
|
|
@@ -945,6 +1051,7 @@ declare class StreamerServer {
|
|
|
945
1051
|
private bindWithRetry;
|
|
946
1052
|
private bindWithRetryLoop;
|
|
947
1053
|
private trackCacheWrite;
|
|
1054
|
+
private refreshFileGuarded;
|
|
948
1055
|
close(): Promise<void>;
|
|
949
1056
|
private handleRequest;
|
|
950
1057
|
private handlePairStart;
|
|
@@ -1008,6 +1115,15 @@ interface ConversationWatcherEvents {
|
|
|
1008
1115
|
* downstream cache write + WebSocket broadcast.
|
|
1009
1116
|
*/
|
|
1010
1117
|
onNewLines?: (filePath: string, lines: string[]) => void;
|
|
1118
|
+
/**
|
|
1119
|
+
* Like onNewLines but also carries each line's absolute byte span in the
|
|
1120
|
+
* file (for the offset index). Fires ALONGSIDE onNewLines/onNewLine (it does
|
|
1121
|
+
* not replace them) so the cache tail write and the index extend can both
|
|
1122
|
+
* consume the same read. `readFrom` is the absolute byte offset the read
|
|
1123
|
+
* started at; `spans` are complete lines only (a torn trailing line is held
|
|
1124
|
+
* for the next read).
|
|
1125
|
+
*/
|
|
1126
|
+
onNewLineSpans?: (filePath: string, spans: LineSpan[], readFrom: number, endOffset: number) => void;
|
|
1011
1127
|
/** Fires when chokidar reports an add/change/unlink at the directory level. */
|
|
1012
1128
|
onConversationChanged?: (filePath: string) => void | Promise<void>;
|
|
1013
1129
|
/** Fires when a tailed file is deleted (per-file watcher unlink event). */
|
|
@@ -1031,6 +1147,7 @@ declare class ConversationWatcher {
|
|
|
1031
1147
|
private directories;
|
|
1032
1148
|
private onNewLine;
|
|
1033
1149
|
private onNewLines;
|
|
1150
|
+
private onNewLineSpans;
|
|
1034
1151
|
private onConversationChanged;
|
|
1035
1152
|
private onFileDeleted;
|
|
1036
1153
|
private onError;
|
package/dist/index.d.ts
CHANGED
|
@@ -6,8 +6,9 @@ import { Logger as Logger$1 } from 'pino';
|
|
|
6
6
|
import { HttpBindings } from '@hono/node-server';
|
|
7
7
|
import { ServerResponse, IncomingMessage } from 'http';
|
|
8
8
|
import { WebSocket } from 'ws';
|
|
9
|
-
import { FileStatEntry, ConversationMeta } from '@threadbase-sh/scanner';
|
|
9
|
+
import { ConversationMessage, FileStatEntry, ConversationMeta } from '@threadbase-sh/scanner';
|
|
10
10
|
import Database from 'better-sqlite3';
|
|
11
|
+
import { Stats } from 'fs';
|
|
11
12
|
import { z } from 'zod';
|
|
12
13
|
import { Pool } from 'pg';
|
|
13
14
|
|
|
@@ -190,6 +191,7 @@ type WSMessage = {
|
|
|
190
191
|
type: "conversation_events";
|
|
191
192
|
sessionId: string;
|
|
192
193
|
lines: string[];
|
|
194
|
+
seqs?: (number | null)[];
|
|
193
195
|
} | {
|
|
194
196
|
type: "question";
|
|
195
197
|
sessionId: string;
|
|
@@ -367,6 +369,15 @@ interface SessionRunner {
|
|
|
367
369
|
dispose(): void;
|
|
368
370
|
}
|
|
369
371
|
|
|
372
|
+
interface LineSpan {
|
|
373
|
+
/** Absolute byte offset of the line's first byte in the file. */
|
|
374
|
+
byteOffset: number;
|
|
375
|
+
/** Byte length of the line content, excluding the trailing "\n". */
|
|
376
|
+
byteLength: number;
|
|
377
|
+
/** The decoded line text (no trailing "\n"). */
|
|
378
|
+
text: string;
|
|
379
|
+
}
|
|
380
|
+
|
|
370
381
|
interface ConversationCacheOptions {
|
|
371
382
|
filterAgentConversations?: boolean;
|
|
372
383
|
agentEntrypoints?: ReadonlySet<string>;
|
|
@@ -401,6 +412,25 @@ interface CachedTail {
|
|
|
401
412
|
messages: CachedTailMessage[];
|
|
402
413
|
tailSize: number;
|
|
403
414
|
}
|
|
415
|
+
/** A row of `conversation_file_state` — per-file offset-index resume state. */
|
|
416
|
+
interface FileStateRow {
|
|
417
|
+
path: string;
|
|
418
|
+
identity: string;
|
|
419
|
+
size: number;
|
|
420
|
+
mtime_ms: number;
|
|
421
|
+
byte_offset: number;
|
|
422
|
+
last_message_index: number;
|
|
423
|
+
}
|
|
424
|
+
/** A row of `conversation_message_index` — one indexed message's byte span. */
|
|
425
|
+
interface MessageIndexRow {
|
|
426
|
+
conversation_id: string;
|
|
427
|
+
message_index: number;
|
|
428
|
+
byte_offset: number;
|
|
429
|
+
byte_length: number;
|
|
430
|
+
uuid: string | null;
|
|
431
|
+
role: string | null;
|
|
432
|
+
ts: number | null;
|
|
433
|
+
}
|
|
404
434
|
interface ScannerMeta {
|
|
405
435
|
id: string;
|
|
406
436
|
sessionId?: string;
|
|
@@ -423,6 +453,8 @@ declare class ConversationCache {
|
|
|
423
453
|
private tailSize;
|
|
424
454
|
private fileIndex;
|
|
425
455
|
private fileIndexLoaded;
|
|
456
|
+
private indexParseState;
|
|
457
|
+
private backfillInFlight;
|
|
426
458
|
private tailSeq;
|
|
427
459
|
private nameSeq;
|
|
428
460
|
private stmts;
|
|
@@ -436,6 +468,78 @@ declare class ConversationCache {
|
|
|
436
468
|
* share the same connection. Internal API; not part of the public surface.
|
|
437
469
|
*/
|
|
438
470
|
getDatabase(): Database.Database;
|
|
471
|
+
getFileState(path: string): FileStateRow | null;
|
|
472
|
+
upsertFileState(row: FileStateRow): void;
|
|
473
|
+
/** Drop a file's index rows + file_state (truncation / identity change). */
|
|
474
|
+
deleteFileIndex(path: string, conversationId: string): void;
|
|
475
|
+
/** Append/replace index rows in one transaction. */
|
|
476
|
+
appendMessageIndexRows(rows: MessageIndexRow[]): void;
|
|
477
|
+
/** Rows for message_index in [fromIndex, toIndex), ordered ascending. */
|
|
478
|
+
getMessageIndexWindow(conversationId: string, fromIndex: number, toIndex: number): MessageIndexRow[];
|
|
479
|
+
getIndexedMessageCount(conversationId: string): number;
|
|
480
|
+
/**
|
|
481
|
+
* Conversation id for a JSONL path — the filename stem (matches the pseudo-id
|
|
482
|
+
* updateFromLine derives and the uuid the detail read path resolves). The
|
|
483
|
+
* offset index keys on this so the window select and the cursor agree.
|
|
484
|
+
*/
|
|
485
|
+
static conversationIdForFile(filePath: string): string;
|
|
486
|
+
/**
|
|
487
|
+
* Incremental offset-index writer: extend the index for a burst of appended
|
|
488
|
+
* lines (one watcher read) using their byte spans. Each line is classified
|
|
489
|
+
* with the scanner's parseJsonlLine (a running per-file reducer state), so the
|
|
490
|
+
* message ordering can never drift from the scanner's. Message lines get an
|
|
491
|
+
* index row at the next message_index; non-message lines (summary/sidecar)
|
|
492
|
+
* get no row but still advance byte_offset. file_state is updated to the end
|
|
493
|
+
* of the last consumed span.
|
|
494
|
+
*
|
|
495
|
+
* Requires an up-to-date `stat` (identity/size/mtime) for the file so the read
|
|
496
|
+
* path can detect truncation/replacement.
|
|
497
|
+
*
|
|
498
|
+
* `readFrom` is the absolute byte offset the watcher read started at, and
|
|
499
|
+
* `endOffset` is where it ended (readFrom + consumed, i.e. the watcher's new
|
|
500
|
+
* entry.offset). CONTIGUITY GUARD: the read must begin exactly where the index
|
|
501
|
+
* left off (`readFrom === existing.byte_offset`, or 0 with no state). If it
|
|
502
|
+
* doesn't — the watcher attached at EOF after the server was down, or an
|
|
503
|
+
* append raced an in-flight backfill — extending would assign wrong
|
|
504
|
+
* message_index values over a hole. In that case this writes nothing and
|
|
505
|
+
* returns null so the caller drops the index and backfills.
|
|
506
|
+
*
|
|
507
|
+
* On success returns the message_index assigned to each input span (null for a
|
|
508
|
+
* non-message line) so the caller can stamp WS `seq`. Empty array when spans
|
|
509
|
+
* is empty. `endOffset` is stored verbatim as byte_offset so the watcher's
|
|
510
|
+
* offset and file_state.byte_offset are the same number by construction.
|
|
511
|
+
*/
|
|
512
|
+
extendMessageIndex(filePath: string, spans: LineSpan[], stat: Stats, readFrom: number, endOffset: number): (number | null)[] | null;
|
|
513
|
+
clearIndexParseState(filePath: string): void;
|
|
514
|
+
/**
|
|
515
|
+
* On-demand full backfill of the offset index for a file with no/stale
|
|
516
|
+
* file_state (cold conversation, or after a truncation/replacement). Rebuilds
|
|
517
|
+
* from byte 0: drops any existing rows, walks the whole file in chunks with a
|
|
518
|
+
* running parse state, yields to the event loop every ~1000 lines so a large
|
|
519
|
+
* file never blocks, and writes index rows + file_state.
|
|
520
|
+
*
|
|
521
|
+
* Single-flighted per path: concurrent callers await the same walk. The
|
|
522
|
+
* triggering detail request is served by the scanner fallback while this runs.
|
|
523
|
+
*/
|
|
524
|
+
backfillIndex(filePath: string): Promise<void>;
|
|
525
|
+
private runBackfill;
|
|
526
|
+
/**
|
|
527
|
+
* Windowed detail read straight from the offset index — the hot path.
|
|
528
|
+
* Returns the parsed messages for message_index in [fromIndex, toIndex) plus
|
|
529
|
+
* the total indexed count, or null when the index can't serve this file (no
|
|
530
|
+
* file_state, identity/size mismatch = truncation/replacement, or cold index)
|
|
531
|
+
* so the caller falls back to the scanner and enqueues a backfill.
|
|
532
|
+
*
|
|
533
|
+
* On a match it SQL-selects the window's byte ranges and preads exactly those
|
|
534
|
+
* ranges from the JSONL (never the whole file), parsing only the sliced lines.
|
|
535
|
+
* Returns messages in the same ConversationMessage shape parseJsonlLine
|
|
536
|
+
* produces during a scan, so the payload is identical to the scanner path.
|
|
537
|
+
*/
|
|
538
|
+
readMessageWindow(filePath: string, fromIndex: number, toIndex: number): {
|
|
539
|
+
messages: ConversationMessage[];
|
|
540
|
+
total: number;
|
|
541
|
+
fromIndex: number;
|
|
542
|
+
} | null;
|
|
439
543
|
private agentEntrypointsKey;
|
|
440
544
|
private classifyAgentFile;
|
|
441
545
|
isAgentFileCached(filePath: string): boolean;
|
|
@@ -874,6 +978,7 @@ declare class StreamerServer {
|
|
|
874
978
|
private wsHub;
|
|
875
979
|
private fileWatcher;
|
|
876
980
|
private sessionFileMap;
|
|
981
|
+
private pendingLineSeqs;
|
|
877
982
|
private pendingQuestions;
|
|
878
983
|
private pendingQuestionKey;
|
|
879
984
|
private pendingPermission;
|
|
@@ -882,6 +987,7 @@ declare class StreamerServer {
|
|
|
882
987
|
private allScanners;
|
|
883
988
|
private scannerReady;
|
|
884
989
|
private scannerStale;
|
|
990
|
+
private refreshInFlight;
|
|
885
991
|
private binding;
|
|
886
992
|
private cacheReady;
|
|
887
993
|
private inFlightCacheWrites;
|
|
@@ -945,6 +1051,7 @@ declare class StreamerServer {
|
|
|
945
1051
|
private bindWithRetry;
|
|
946
1052
|
private bindWithRetryLoop;
|
|
947
1053
|
private trackCacheWrite;
|
|
1054
|
+
private refreshFileGuarded;
|
|
948
1055
|
close(): Promise<void>;
|
|
949
1056
|
private handleRequest;
|
|
950
1057
|
private handlePairStart;
|
|
@@ -1008,6 +1115,15 @@ interface ConversationWatcherEvents {
|
|
|
1008
1115
|
* downstream cache write + WebSocket broadcast.
|
|
1009
1116
|
*/
|
|
1010
1117
|
onNewLines?: (filePath: string, lines: string[]) => void;
|
|
1118
|
+
/**
|
|
1119
|
+
* Like onNewLines but also carries each line's absolute byte span in the
|
|
1120
|
+
* file (for the offset index). Fires ALONGSIDE onNewLines/onNewLine (it does
|
|
1121
|
+
* not replace them) so the cache tail write and the index extend can both
|
|
1122
|
+
* consume the same read. `readFrom` is the absolute byte offset the read
|
|
1123
|
+
* started at; `spans` are complete lines only (a torn trailing line is held
|
|
1124
|
+
* for the next read).
|
|
1125
|
+
*/
|
|
1126
|
+
onNewLineSpans?: (filePath: string, spans: LineSpan[], readFrom: number, endOffset: number) => void;
|
|
1011
1127
|
/** Fires when chokidar reports an add/change/unlink at the directory level. */
|
|
1012
1128
|
onConversationChanged?: (filePath: string) => void | Promise<void>;
|
|
1013
1129
|
/** Fires when a tailed file is deleted (per-file watcher unlink event). */
|
|
@@ -1031,6 +1147,7 @@ declare class ConversationWatcher {
|
|
|
1031
1147
|
private directories;
|
|
1032
1148
|
private onNewLine;
|
|
1033
1149
|
private onNewLines;
|
|
1150
|
+
private onNewLineSpans;
|
|
1034
1151
|
private onConversationChanged;
|
|
1035
1152
|
private onFileDeleted;
|
|
1036
1153
|
private onError;
|