@threadbase-sh/streamer 1.67.0 → 1.67.2
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/api/handlers/conversations.handlers.d.ts +29 -0
- package/dist/api/handlers/conversations.handlers.d.ts.map +1 -1
- package/dist/cli.cjs +86 -17
- package/dist/cli.cjs.map +1 -1
- package/dist/conversation-cache.d.ts.map +1 -1
- package/dist/index.cjs +63 -4
- package/dist/index.cjs.map +1 -1
- package/dist/index.js +68 -9
- package/dist/index.js.map +1 -1
- package/package.json +2 -2
|
@@ -60,6 +60,35 @@ export declare class ConversationHandlers {
|
|
|
60
60
|
handleGetPopularProjects(url: URL, res: ServerResponse): void;
|
|
61
61
|
handleGetProjectSummaries(url: URL, res: ServerResponse): void;
|
|
62
62
|
findJsonlPath(uuid: string): string | null;
|
|
63
|
+
/**
|
|
64
|
+
* Resolve a conversation id to a JSONL path, in order of authority.
|
|
65
|
+
*
|
|
66
|
+
* `findJsonlPath` alone answers 64.0% of this machine's 961 conversations and
|
|
67
|
+
* 0 of 343 Codex ones — it reconstructs `<projectsDir>/<dir>/<uuid>.jsonl`,
|
|
68
|
+
* which is Claude Code's layout, and a Codex rollout is
|
|
69
|
+
* `rollout-<ts>-<uuid>.jsonl` under a date path, so that walk cannot match one
|
|
70
|
+
* by construction. The ladder below answers 99.7%, leaving only the three
|
|
71
|
+
* whose file is genuinely gone.
|
|
72
|
+
*/
|
|
73
|
+
locateJsonlPath(uuid: string, lookupId: string): Promise<string | null>;
|
|
74
|
+
/**
|
|
75
|
+
* Does `filePath` actually hold the conversation `requestedId` names?
|
|
76
|
+
*
|
|
77
|
+
* The filename settles it for both providers: Claude writes `<uuid>.jsonl`
|
|
78
|
+
* (or `agent-<agentId>.jsonl`), Codex writes `rollout-<ts>-<uuid>.jsonl`.
|
|
79
|
+
* Only when the name says nothing do we open the file — and there the naive
|
|
80
|
+
* rule is wrong, because **a Claude subagent transcript carries the PARENT's
|
|
81
|
+
* `sessionId`**. Matching on `sessionId` alone therefore verifies exactly the
|
|
82
|
+
* file this check exists to reject, so a sidechain is refused outright unless
|
|
83
|
+
* it was asked for by its own `agent-<agentId>` name, which the filename
|
|
84
|
+
* branch above already covers.
|
|
85
|
+
*/
|
|
86
|
+
isJsonlPathFor(filePath: string, requestedId: string): Promise<boolean>;
|
|
87
|
+
/** First parseable JSONL line, for identity checks. Null on an empty or unreadable file. */
|
|
88
|
+
readFirstJsonlEntry(filePath: string): Promise<{
|
|
89
|
+
sessionId?: string;
|
|
90
|
+
isSidechain?: boolean;
|
|
91
|
+
} | null>;
|
|
63
92
|
readCwdFromJsonl(filePath: string): Promise<string | null>;
|
|
64
93
|
findConversationByUuid(uuid: string): Promise<Conversation | null>;
|
|
65
94
|
handleGetConversation(id: string, url: URL, res: ServerResponse, ifNoneMatch?: string): Promise<void>;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"conversations.handlers.d.ts","sourceRoot":"","sources":["../../../src/api/handlers/conversations.handlers.ts"],"names":[],"mappings":"AAAA,OAAO,EAKL,KAAK,YAAY,EAKlB,MAAM,wBAAwB,CAAC;AAEhC,OAAO,KAAK,EAAE,eAAe,EAAE,cAAc,EAAE,MAAM,MAAM,CAAC;AAG5D,OAAO,EAAE,iBAAiB,EAAE,MAAM,0BAA0B,CAAC;AAC7D,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,4BAA4B,CAAC;AACrE,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,cAAc,CAAC;AAO3C,OAAO,KAAK,EAAE,cAAc,EAAE,WAAW,EAAE,MAAM,uBAAuB,CAAC;AAazE,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,qBAAqB,CAAC;AACxD,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,aAAa,CAAC;AAIrD,OAAO,KAAK,EAAE,KAAK,EAAE,MAAM,cAAc,CAAC;AAe1C;;;;;;;;;;;GAWG;AACH,MAAM,MAAM,wBAAwB,GAAG;IACrC,cAAc,EAAE,cAAc,CAAC;IAC/B,YAAY,EAAE,YAAY,CAAC;IAC3B,UAAU,EAAE,kBAAkB,CAAC;IAC/B,KAAK,EAAE,KAAK,CAAC;IACb,YAAY,EAAE,WAAW,EAAE,GAAG,SAAS,CAAC;IACxC,KAAK,EAAE,MAAM,iBAAiB,GAAG,IAAI,CAAC;IACtC,GAAG,EAAE,MAAM,MAAM,CAAC;IAClB,iBAAiB,EAAE,CAAC,GAAG,EAAE,cAAc,KAAK,OAAO,CAAC;IACpD,UAAU,EAAE,CAAC,CAAC,EAAE,KAAK,EAAE,iBAAiB,EAAE,SAAS,EAAE,MAAM,OAAO,CAAC,CAAC,CAAC,KAAK,OAAO,CAAC,CAAC,CAAC,CAAC;IACrF,eAAe,EAAE,CAAC,IAAI,EAAE,OAAO,CAAC,OAAO,CAAC,KAAK,IAAI,CAAC;IAClD,2BAA2B,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,MAAM,CAAC;IACtD,uBAAuB,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,MAAM,GAAG,IAAI,CAAC;IACzD,uBAAuB,EAAE,CAAC,OAAO,EAAE,MAAM,KAAK,OAAO,CAAC;CACvD,CAAC;AAEF;;;;;;;;GAQG;AACH,qBAAa,oBAAoB;IACnB,OAAO,CAAC,IAAI;IAAxB,YAAoB,IAAI,EAAE,wBAAwB,EAAI;IAEtD,OAAO,KAAK,cAAc,GAEzB;IAED,OAAO,KAAK,YAAY,GAEvB;IAED,OAAO,KAAK,UAAU,GAErB;IAED,OAAO,KAAK,KAAK,GAEhB;IAED,OAAO,KAAK,YAAY,GAEvB;IAED,OAAO,KAAK,KAAK,GAEhB;IAED,OAAO,KAAK,GAAG,GAEd;IAEK,uBAAuB,CAAC,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,cAAc,GAAG,OAAO,CAAC,IAAI,CAAC,CAsH1E;IAEK,wBAAwB,CAAC,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,cAAc,GAAG,OAAO,CAAC,IAAI,CAAC,CAgC3E;IAKD,OAAO,CAAC,wBAAwB;IAmBhC,uBAAuB,CAAC,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,cAAc,GAAG,IAAI,CA4B3D;IAED,wBAAwB,CAAC,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,cAAc,GAAG,IAAI,CAQ5D;IAED,yBAAyB,CAAC,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,cAAc,GAAG,IAAI,CAgB7D;IAED,aAAa,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,CAmBzC;IAEK,gBAAgB,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC,CAsB/D;IAEK,sBAAsB,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,YAAY,GAAG,IAAI,CAAC,
|
|
1
|
+
{"version":3,"file":"conversations.handlers.d.ts","sourceRoot":"","sources":["../../../src/api/handlers/conversations.handlers.ts"],"names":[],"mappings":"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"}
|
package/dist/cli.cjs
CHANGED
|
@@ -99746,8 +99746,8 @@ var require_pattern = __commonJS({
|
|
|
99746
99746
|
}
|
|
99747
99747
|
exports2.endsWithSlashGlobStar = endsWithSlashGlobStar;
|
|
99748
99748
|
function isAffectDepthOfReadingPattern(pattern) {
|
|
99749
|
-
const
|
|
99750
|
-
return endsWithSlashGlobStar(pattern) || isStaticPattern(
|
|
99749
|
+
const basename13 = path2.basename(pattern);
|
|
99750
|
+
return endsWithSlashGlobStar(pattern) || isStaticPattern(basename13);
|
|
99751
99751
|
}
|
|
99752
99752
|
exports2.isAffectDepthOfReadingPattern = isAffectDepthOfReadingPattern;
|
|
99753
99753
|
function expandPatternsWithBraceExpansion(patterns2) {
|
|
@@ -139150,10 +139150,10 @@ var ReaddirpStream = class extends import_node_stream.Readable {
|
|
|
139150
139150
|
}
|
|
139151
139151
|
async _formatEntry(dirent, path2) {
|
|
139152
139152
|
let entry;
|
|
139153
|
-
const
|
|
139153
|
+
const basename13 = this._isDirent ? dirent.name : dirent;
|
|
139154
139154
|
try {
|
|
139155
|
-
const fullPath = (0, import_node_path8.resolve)((0, import_node_path8.join)(path2,
|
|
139156
|
-
entry = { path: (0, import_node_path8.relative)(this._root, fullPath), fullPath, basename:
|
|
139155
|
+
const fullPath = (0, import_node_path8.resolve)((0, import_node_path8.join)(path2, basename13));
|
|
139156
|
+
entry = { path: (0, import_node_path8.relative)(this._root, fullPath), fullPath, basename: basename13 };
|
|
139157
139157
|
entry[this._statsProp] = this._isDirent ? dirent : await this._stat(fullPath);
|
|
139158
139158
|
} catch (err) {
|
|
139159
139159
|
this._onError(err);
|
|
@@ -139694,9 +139694,9 @@ var NodeFsHandler = class {
|
|
|
139694
139694
|
_watchWithNodeFs(path2, listener) {
|
|
139695
139695
|
const opts = this.fsw.options;
|
|
139696
139696
|
const directory = sp.dirname(path2);
|
|
139697
|
-
const
|
|
139697
|
+
const basename13 = sp.basename(path2);
|
|
139698
139698
|
const parent = this.fsw._getWatchedDir(directory);
|
|
139699
|
-
parent.add(
|
|
139699
|
+
parent.add(basename13);
|
|
139700
139700
|
const absolutePath = sp.resolve(path2);
|
|
139701
139701
|
const options = {
|
|
139702
139702
|
persistent: opts.persistent
|
|
@@ -139706,7 +139706,7 @@ var NodeFsHandler = class {
|
|
|
139706
139706
|
let closer;
|
|
139707
139707
|
if (opts.usePolling) {
|
|
139708
139708
|
const enableBin = opts.interval !== opts.binaryInterval;
|
|
139709
|
-
options.interval = enableBin && isBinaryPath(
|
|
139709
|
+
options.interval = enableBin && isBinaryPath(basename13) ? opts.binaryInterval : opts.interval;
|
|
139710
139710
|
closer = setFsWatchFileListener(path2, absolutePath, options, {
|
|
139711
139711
|
listener,
|
|
139712
139712
|
rawEmitter: this.fsw._emitRaw
|
|
@@ -139729,10 +139729,10 @@ var NodeFsHandler = class {
|
|
|
139729
139729
|
return;
|
|
139730
139730
|
}
|
|
139731
139731
|
const dirname18 = sp.dirname(file2);
|
|
139732
|
-
const
|
|
139732
|
+
const basename13 = sp.basename(file2);
|
|
139733
139733
|
const parent = this.fsw._getWatchedDir(dirname18);
|
|
139734
139734
|
let prevStats = stats;
|
|
139735
|
-
if (parent.has(
|
|
139735
|
+
if (parent.has(basename13))
|
|
139736
139736
|
return;
|
|
139737
139737
|
const listener = async (path2, newStats) => {
|
|
139738
139738
|
if (!this.fsw._throttle(THROTTLE_MODE_WATCH, file2, 5))
|
|
@@ -139757,9 +139757,9 @@ var NodeFsHandler = class {
|
|
|
139757
139757
|
prevStats = newStats2;
|
|
139758
139758
|
}
|
|
139759
139759
|
} catch (error51) {
|
|
139760
|
-
this.fsw._remove(dirname18,
|
|
139760
|
+
this.fsw._remove(dirname18, basename13);
|
|
139761
139761
|
}
|
|
139762
|
-
} else if (parent.has(
|
|
139762
|
+
} else if (parent.has(basename13)) {
|
|
139763
139763
|
const at2 = newStats.atimeMs;
|
|
139764
139764
|
const mt2 = newStats.mtimeMs;
|
|
139765
139765
|
if (!at2 || at2 <= mt2 || mt2 !== prevStats.mtimeMs) {
|
|
@@ -143610,8 +143610,18 @@ var IndexQueue = class {
|
|
|
143610
143610
|
};
|
|
143611
143611
|
var BATCH_SIZE2 = 12;
|
|
143612
143612
|
var DEFAULT_CONFIG_PATH2 = "~/.config/threadbase-scanner";
|
|
143613
|
+
function isTestProcess() {
|
|
143614
|
+
return Boolean(process.env.VITEST) || Boolean(process.env.JEST_WORKER_ID) || process.env.NODE_ENV === "test";
|
|
143615
|
+
}
|
|
143613
143616
|
function defaultDbPath() {
|
|
143614
|
-
|
|
143617
|
+
const override = process.env.TB_SCANNER_DB;
|
|
143618
|
+
if (override) return override;
|
|
143619
|
+
if (isTestProcess()) {
|
|
143620
|
+
throw new Error(
|
|
143621
|
+
"TB_SCANNER_DB must be set under a test runner. Refusing to open the default index at ~/.config/threadbase-scanner/index.db, because test fixtures written there are indistinguishable from real conversations and corrupt every measurement of the index. Point it at a temp directory in your test setup, or pass persistent.dbPath explicitly."
|
|
143622
|
+
);
|
|
143623
|
+
}
|
|
143624
|
+
return (0, import_path10.join)((0, import_os8.homedir)(), ".config", "threadbase-scanner", "index.db");
|
|
143615
143625
|
}
|
|
143616
143626
|
function capForMemory(doc, max) {
|
|
143617
143627
|
const combined = combineSearchContent(doc);
|
|
@@ -144602,6 +144612,7 @@ CREATE TABLE IF NOT EXISTS session_names (
|
|
|
144602
144612
|
);
|
|
144603
144613
|
`;
|
|
144604
144614
|
var cacheLog = getLogger("cache");
|
|
144615
|
+
var PARSE_STATE_LOOKBACK = 8;
|
|
144605
144616
|
var ConversationCache = class _ConversationCache {
|
|
144606
144617
|
db;
|
|
144607
144618
|
tailSize;
|
|
@@ -145118,7 +145129,7 @@ var ConversationCache = class _ConversationCache {
|
|
|
145118
145129
|
if (to2 <= from) return { messages: [], total, fromIndex: from };
|
|
145119
145130
|
const rows = this.getMessageIndexWindow(
|
|
145120
145131
|
_ConversationCache.conversationIdForFile(filePath),
|
|
145121
|
-
from,
|
|
145132
|
+
Math.max(0, from - PARSE_STATE_LOOKBACK),
|
|
145122
145133
|
to2
|
|
145123
145134
|
);
|
|
145124
145135
|
if (rows.length === 0) return { messages: [], total, fromIndex: from };
|
|
@@ -145130,7 +145141,7 @@ var ConversationCache = class _ConversationCache {
|
|
|
145130
145141
|
const buf = Buffer.alloc(row.byte_length);
|
|
145131
145142
|
(0, import_fs18.readSync)(fd, buf, 0, row.byte_length, row.byte_offset);
|
|
145132
145143
|
const msg = parseJsonlLine(buf.toString("utf-8"), state);
|
|
145133
|
-
if (msg) messages.push(msg);
|
|
145144
|
+
if (msg && row.message_index >= from) messages.push(msg);
|
|
145134
145145
|
}
|
|
145135
145146
|
} finally {
|
|
145136
145147
|
(0, import_fs18.closeSync)(fd);
|
|
@@ -146482,6 +146493,64 @@ var ConversationHandlers = class {
|
|
|
146482
146493
|
}
|
|
146483
146494
|
return null;
|
|
146484
146495
|
}
|
|
146496
|
+
/**
|
|
146497
|
+
* Resolve a conversation id to a JSONL path, in order of authority.
|
|
146498
|
+
*
|
|
146499
|
+
* `findJsonlPath` alone answers 64.0% of this machine's 961 conversations and
|
|
146500
|
+
* 0 of 343 Codex ones — it reconstructs `<projectsDir>/<dir>/<uuid>.jsonl`,
|
|
146501
|
+
* which is Claude Code's layout, and a Codex rollout is
|
|
146502
|
+
* `rollout-<ts>-<uuid>.jsonl` under a date path, so that walk cannot match one
|
|
146503
|
+
* by construction. The ladder below answers 99.7%, leaving only the three
|
|
146504
|
+
* whose file is genuinely gone.
|
|
146505
|
+
*/
|
|
146506
|
+
async locateJsonlPath(uuid3, lookupId) {
|
|
146507
|
+
const live = this.deps.findLiveSessionFilePath(uuid3) ?? this.deps.findLiveSessionFilePath(lookupId);
|
|
146508
|
+
if (live) return live;
|
|
146509
|
+
const cached4 = this.cache?.getMetaById(lookupId)?.filePath;
|
|
146510
|
+
if (cached4 && await this.isJsonlPathFor(cached4, lookupId)) return cached4;
|
|
146511
|
+
return this.findJsonlPath(lookupId);
|
|
146512
|
+
}
|
|
146513
|
+
/**
|
|
146514
|
+
* Does `filePath` actually hold the conversation `requestedId` names?
|
|
146515
|
+
*
|
|
146516
|
+
* The filename settles it for both providers: Claude writes `<uuid>.jsonl`
|
|
146517
|
+
* (or `agent-<agentId>.jsonl`), Codex writes `rollout-<ts>-<uuid>.jsonl`.
|
|
146518
|
+
* Only when the name says nothing do we open the file — and there the naive
|
|
146519
|
+
* rule is wrong, because **a Claude subagent transcript carries the PARENT's
|
|
146520
|
+
* `sessionId`**. Matching on `sessionId` alone therefore verifies exactly the
|
|
146521
|
+
* file this check exists to reject, so a sidechain is refused outright unless
|
|
146522
|
+
* it was asked for by its own `agent-<agentId>` name, which the filename
|
|
146523
|
+
* branch above already covers.
|
|
146524
|
+
*/
|
|
146525
|
+
async isJsonlPathFor(filePath, requestedId) {
|
|
146526
|
+
if (!(0, import_fs20.existsSync)(filePath)) return false;
|
|
146527
|
+
const stem = (0, import_path18.basename)(filePath).replace(/\.jsonl$/, "");
|
|
146528
|
+
if (stem === requestedId || stem.includes(requestedId)) return true;
|
|
146529
|
+
const first = await this.readFirstJsonlEntry(filePath);
|
|
146530
|
+
if (!first || first.isSidechain === true) return false;
|
|
146531
|
+
return first.sessionId === requestedId;
|
|
146532
|
+
}
|
|
146533
|
+
/** First parseable JSONL line, for identity checks. Null on an empty or unreadable file. */
|
|
146534
|
+
async readFirstJsonlEntry(filePath) {
|
|
146535
|
+
return new Promise((resolve4) => {
|
|
146536
|
+
const rl = (0, import_readline4.createInterface)({ input: (0, import_fs20.createReadStream)(filePath), crlfDelay: Infinity });
|
|
146537
|
+
let done = false;
|
|
146538
|
+
rl.on("line", (line) => {
|
|
146539
|
+
if (done) return;
|
|
146540
|
+
try {
|
|
146541
|
+
const entry = JSON.parse(line);
|
|
146542
|
+
done = true;
|
|
146543
|
+
rl.close();
|
|
146544
|
+
resolve4(entry);
|
|
146545
|
+
} catch {
|
|
146546
|
+
}
|
|
146547
|
+
});
|
|
146548
|
+
rl.on("close", () => {
|
|
146549
|
+
if (!done) resolve4(null);
|
|
146550
|
+
});
|
|
146551
|
+
rl.on("error", () => resolve4(null));
|
|
146552
|
+
});
|
|
146553
|
+
}
|
|
146485
146554
|
async readCwdFromJsonl(filePath) {
|
|
146486
146555
|
return new Promise((resolve4) => {
|
|
146487
146556
|
const rl = (0, import_readline4.createInterface)({ input: (0, import_fs20.createReadStream)(filePath), crlfDelay: Infinity });
|
|
@@ -146507,7 +146576,7 @@ var ConversationHandlers = class {
|
|
|
146507
146576
|
async findConversationByUuid(uuid3) {
|
|
146508
146577
|
const lookupId = this.deps.resolveConversationLookupId(uuid3);
|
|
146509
146578
|
if (!this.scannerManager.ready && !this.scanProfiles) {
|
|
146510
|
-
const filePath2 =
|
|
146579
|
+
const filePath2 = await this.locateJsonlPath(uuid3, lookupId);
|
|
146511
146580
|
if (filePath2) {
|
|
146512
146581
|
const account = this.cache?.getMetaById(lookupId)?.account ?? void 0;
|
|
146513
146582
|
const coldScanner = this.scannerManager.current ?? this.scannerManager.newScanner();
|
|
@@ -146559,7 +146628,7 @@ var ConversationHandlers = class {
|
|
|
146559
146628
|
return fromIndex;
|
|
146560
146629
|
}
|
|
146561
146630
|
if (this.scanProfiles) return null;
|
|
146562
|
-
const filePath =
|
|
146631
|
+
const filePath = await this.locateJsonlPath(uuid3, lookupId);
|
|
146563
146632
|
if (!filePath) return null;
|
|
146564
146633
|
if (this.scannerManager.ready) {
|
|
146565
146634
|
const account = this.cache?.getMetaById(lookupId)?.account ?? void 0;
|