@threadbase-sh/streamer 1.22.2 → 1.23.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/cli.cjs +24 -4
- package/dist/cli.cjs.map +1 -1
- package/dist/index.cjs +24 -4
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +18 -1
- package/dist/index.d.ts +18 -1
- package/dist/index.js +24 -4
- package/dist/index.js.map +1 -1
- package/package.json +2 -1
package/dist/index.d.cts
CHANGED
|
@@ -454,7 +454,24 @@ declare class ConversationCache {
|
|
|
454
454
|
getSessionName(sessionId: string): string | null;
|
|
455
455
|
listSessionNames(): Record<string, string>;
|
|
456
456
|
invalidate(id?: string): void;
|
|
457
|
-
|
|
457
|
+
/**
|
|
458
|
+
* Drop the cached row for a file. Two callers with opposite intent:
|
|
459
|
+
* - a directory-watch "change" event (the file was appended to) — pass
|
|
460
|
+
* `skipIfTailed: true`. A cached tail means the row is being actively
|
|
461
|
+
* maintained from the file's real content by the live-tail
|
|
462
|
+
* (updateFromLines) or warm-up path, fresher than any scanner-derived
|
|
463
|
+
* view. Both watchers fire on the same append with no ordering guarantee;
|
|
464
|
+
* without this guard the invalidate can land after the tail write and wipe
|
|
465
|
+
* the just-cached row, flickering the conversation out of
|
|
466
|
+
* /api/conversations on nearly every message (CRITICAL #2). The debounced
|
|
467
|
+
* rescan still re-derives metadata, so skipping the eager drop loses
|
|
468
|
+
* nothing.
|
|
469
|
+
* - a genuine unlink (the file is gone) — leave `skipIfTailed` false so the
|
|
470
|
+
* row is always removed, otherwise a deleted session ghosts in the cache.
|
|
471
|
+
*/
|
|
472
|
+
invalidateByFilePath(filePath: string, opts?: {
|
|
473
|
+
skipIfTailed?: boolean;
|
|
474
|
+
}): string | null;
|
|
458
475
|
/**
|
|
459
476
|
* Drop rows whose `file_path` no longer exists on disk AND which have no
|
|
460
477
|
* cached tail to fall back to. Rows with a tail are left alone so
|
package/dist/index.d.ts
CHANGED
|
@@ -454,7 +454,24 @@ declare class ConversationCache {
|
|
|
454
454
|
getSessionName(sessionId: string): string | null;
|
|
455
455
|
listSessionNames(): Record<string, string>;
|
|
456
456
|
invalidate(id?: string): void;
|
|
457
|
-
|
|
457
|
+
/**
|
|
458
|
+
* Drop the cached row for a file. Two callers with opposite intent:
|
|
459
|
+
* - a directory-watch "change" event (the file was appended to) — pass
|
|
460
|
+
* `skipIfTailed: true`. A cached tail means the row is being actively
|
|
461
|
+
* maintained from the file's real content by the live-tail
|
|
462
|
+
* (updateFromLines) or warm-up path, fresher than any scanner-derived
|
|
463
|
+
* view. Both watchers fire on the same append with no ordering guarantee;
|
|
464
|
+
* without this guard the invalidate can land after the tail write and wipe
|
|
465
|
+
* the just-cached row, flickering the conversation out of
|
|
466
|
+
* /api/conversations on nearly every message (CRITICAL #2). The debounced
|
|
467
|
+
* rescan still re-derives metadata, so skipping the eager drop loses
|
|
468
|
+
* nothing.
|
|
469
|
+
* - a genuine unlink (the file is gone) — leave `skipIfTailed` false so the
|
|
470
|
+
* row is always removed, otherwise a deleted session ghosts in the cache.
|
|
471
|
+
*/
|
|
472
|
+
invalidateByFilePath(filePath: string, opts?: {
|
|
473
|
+
skipIfTailed?: boolean;
|
|
474
|
+
}): string | null;
|
|
458
475
|
/**
|
|
459
476
|
* Drop rows whose `file_path` no longer exists on disk AND which have no
|
|
460
477
|
* cached tail to fall back to. Rows with a tail are left alone so
|
package/dist/index.js
CHANGED
|
@@ -2532,7 +2532,10 @@ var ConversationCache = class _ConversationCache {
|
|
|
2532
2532
|
model = excluded.model,
|
|
2533
2533
|
account = excluded.account,
|
|
2534
2534
|
branch = excluded.branch,
|
|
2535
|
-
message_count
|
|
2535
|
+
-- message_count is incremented by live tailing but recounted from
|
|
2536
|
+
-- scratch by a scanner rescan; a stale rescan must not carry a live
|
|
2537
|
+
-- session's count backwards, so take the max instead of overwriting.
|
|
2538
|
+
message_count = MAX(conversation_meta.message_count, excluded.message_count),
|
|
2536
2539
|
last_activity = excluded.last_activity,
|
|
2537
2540
|
first_message = excluded.first_message,
|
|
2538
2541
|
last_message = excluded.last_message,
|
|
@@ -2809,6 +2812,7 @@ var ConversationCache = class _ConversationCache {
|
|
|
2809
2812
|
fileSize = s.size;
|
|
2810
2813
|
} catch {
|
|
2811
2814
|
}
|
|
2815
|
+
const seq = ++this.tailSeq;
|
|
2812
2816
|
this.stmts.upsertFull.run({
|
|
2813
2817
|
id,
|
|
2814
2818
|
file_path: m.filePath,
|
|
@@ -2823,7 +2827,7 @@ var ConversationCache = class _ConversationCache {
|
|
|
2823
2827
|
first_message: m.firstMessage ? JSON.stringify(m.firstMessage) : null,
|
|
2824
2828
|
last_message: m.lastMessage ? JSON.stringify(m.lastMessage) : null,
|
|
2825
2829
|
preview: m.preview ?? null,
|
|
2826
|
-
updated_at:
|
|
2830
|
+
updated_at: seq,
|
|
2827
2831
|
mtime_ms: mtimeMs,
|
|
2828
2832
|
file_size: fileSize,
|
|
2829
2833
|
provider: m.provider ?? CLAUDE_CODE_PROVIDER
|
|
@@ -3040,9 +3044,25 @@ var ConversationCache = class _ConversationCache {
|
|
|
3040
3044
|
this.fileIndex.clear();
|
|
3041
3045
|
}
|
|
3042
3046
|
}
|
|
3043
|
-
|
|
3047
|
+
/**
|
|
3048
|
+
* Drop the cached row for a file. Two callers with opposite intent:
|
|
3049
|
+
* - a directory-watch "change" event (the file was appended to) — pass
|
|
3050
|
+
* `skipIfTailed: true`. A cached tail means the row is being actively
|
|
3051
|
+
* maintained from the file's real content by the live-tail
|
|
3052
|
+
* (updateFromLines) or warm-up path, fresher than any scanner-derived
|
|
3053
|
+
* view. Both watchers fire on the same append with no ordering guarantee;
|
|
3054
|
+
* without this guard the invalidate can land after the tail write and wipe
|
|
3055
|
+
* the just-cached row, flickering the conversation out of
|
|
3056
|
+
* /api/conversations on nearly every message (CRITICAL #2). The debounced
|
|
3057
|
+
* rescan still re-derives metadata, so skipping the eager drop loses
|
|
3058
|
+
* nothing.
|
|
3059
|
+
* - a genuine unlink (the file is gone) — leave `skipIfTailed` false so the
|
|
3060
|
+
* row is always removed, otherwise a deleted session ghosts in the cache.
|
|
3061
|
+
*/
|
|
3062
|
+
invalidateByFilePath(filePath, opts) {
|
|
3044
3063
|
const row = this.stmts.getIdByFilePath.get(filePath);
|
|
3045
3064
|
if (!row) return null;
|
|
3065
|
+
if (opts?.skipIfTailed && this.stmts.hasTail.get(row.id)) return null;
|
|
3046
3066
|
this.invalidate(row.id);
|
|
3047
3067
|
return row.id;
|
|
3048
3068
|
}
|
|
@@ -4268,7 +4288,7 @@ var StreamerServer = class {
|
|
|
4268
4288
|
}
|
|
4269
4289
|
},
|
|
4270
4290
|
onConversationChanged: (filePath) => {
|
|
4271
|
-
this.cache?.invalidateByFilePath(filePath);
|
|
4291
|
+
this.cache?.invalidateByFilePath(filePath, { skipIfTailed: true });
|
|
4272
4292
|
this.markScannerStaleDebounced();
|
|
4273
4293
|
this.log.debug?.(`Scanner invalidated by directory event: ${filePath}`, {
|
|
4274
4294
|
filePath,
|