@threadbase-sh/streamer 1.45.0 → 1.46.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 +56 -1
- package/dist/cli.cjs.map +1 -1
- package/dist/index.cjs +56 -1
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +18 -0
- package/dist/index.d.ts +18 -0
- package/dist/index.js +56 -1
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/dist/index.d.cts
CHANGED
|
@@ -824,6 +824,22 @@ declare class ConversationCache {
|
|
|
824
824
|
name: string;
|
|
825
825
|
sessionCount: number;
|
|
826
826
|
}>;
|
|
827
|
+
/** Every project with at least one cached conversation, most recently active
|
|
828
|
+
* first. Paths are the raw `project_path` values, which is what
|
|
829
|
+
* /api/conversations?project= matches on exactly — so a summary row is
|
|
830
|
+
* always joinable against the page it describes. */
|
|
831
|
+
listProjectSummaries(opts: {
|
|
832
|
+
limit: number;
|
|
833
|
+
offset: number;
|
|
834
|
+
}): {
|
|
835
|
+
projects: Array<{
|
|
836
|
+
path: string;
|
|
837
|
+
name: string;
|
|
838
|
+
conversationCount: number;
|
|
839
|
+
lastActivity: string;
|
|
840
|
+
}>;
|
|
841
|
+
total: number;
|
|
842
|
+
};
|
|
827
843
|
private ensureFileIndex;
|
|
828
844
|
updateFromLine(filePath: string, rawLine: string): void;
|
|
829
845
|
/**
|
|
@@ -1689,6 +1705,7 @@ type ApiDeps = {
|
|
|
1689
1705
|
handleSearchTarget: (id: string, req: IncomingMessage, res: ServerResponse) => Promise<void>;
|
|
1690
1706
|
handleListProjects: (url: URL, res: ServerResponse) => void;
|
|
1691
1707
|
handleGetPopularProjects: (url: URL, res: ServerResponse) => void;
|
|
1708
|
+
handleGetProjectSummaries: (url: URL, res: ServerResponse) => void;
|
|
1692
1709
|
handlePairStart: (res: ServerResponse) => void;
|
|
1693
1710
|
handlePairExchange: (req: IncomingMessage, res: ServerResponse) => Promise<void>;
|
|
1694
1711
|
handleBrowse: (url: URL, res: ServerResponse) => Promise<void>;
|
|
@@ -2119,6 +2136,7 @@ declare class StreamerServer {
|
|
|
2119
2136
|
private handleSessionsCount;
|
|
2120
2137
|
private handleGetRecentSessions;
|
|
2121
2138
|
private handleGetPopularProjects;
|
|
2139
|
+
private handleGetProjectSummaries;
|
|
2122
2140
|
private buildStatCache;
|
|
2123
2141
|
private codexScanOpts;
|
|
2124
2142
|
private newScanner;
|
package/dist/index.d.ts
CHANGED
|
@@ -824,6 +824,22 @@ declare class ConversationCache {
|
|
|
824
824
|
name: string;
|
|
825
825
|
sessionCount: number;
|
|
826
826
|
}>;
|
|
827
|
+
/** Every project with at least one cached conversation, most recently active
|
|
828
|
+
* first. Paths are the raw `project_path` values, which is what
|
|
829
|
+
* /api/conversations?project= matches on exactly — so a summary row is
|
|
830
|
+
* always joinable against the page it describes. */
|
|
831
|
+
listProjectSummaries(opts: {
|
|
832
|
+
limit: number;
|
|
833
|
+
offset: number;
|
|
834
|
+
}): {
|
|
835
|
+
projects: Array<{
|
|
836
|
+
path: string;
|
|
837
|
+
name: string;
|
|
838
|
+
conversationCount: number;
|
|
839
|
+
lastActivity: string;
|
|
840
|
+
}>;
|
|
841
|
+
total: number;
|
|
842
|
+
};
|
|
827
843
|
private ensureFileIndex;
|
|
828
844
|
updateFromLine(filePath: string, rawLine: string): void;
|
|
829
845
|
/**
|
|
@@ -1689,6 +1705,7 @@ type ApiDeps = {
|
|
|
1689
1705
|
handleSearchTarget: (id: string, req: IncomingMessage, res: ServerResponse) => Promise<void>;
|
|
1690
1706
|
handleListProjects: (url: URL, res: ServerResponse) => void;
|
|
1691
1707
|
handleGetPopularProjects: (url: URL, res: ServerResponse) => void;
|
|
1708
|
+
handleGetProjectSummaries: (url: URL, res: ServerResponse) => void;
|
|
1692
1709
|
handlePairStart: (res: ServerResponse) => void;
|
|
1693
1710
|
handlePairExchange: (req: IncomingMessage, res: ServerResponse) => Promise<void>;
|
|
1694
1711
|
handleBrowse: (url: URL, res: ServerResponse) => Promise<void>;
|
|
@@ -2119,6 +2136,7 @@ declare class StreamerServer {
|
|
|
2119
2136
|
private handleSessionsCount;
|
|
2120
2137
|
private handleGetRecentSessions;
|
|
2121
2138
|
private handleGetPopularProjects;
|
|
2139
|
+
private handleGetProjectSummaries;
|
|
2122
2140
|
private buildStatCache;
|
|
2123
2141
|
private codexScanOpts;
|
|
2124
2142
|
private newScanner;
|
package/dist/index.js
CHANGED
|
@@ -5306,7 +5306,10 @@ var createMiscRoutes = (deps) => {
|
|
|
5306
5306
|
// Same contract: this server serves GET /api/config/feature-flags. Lives
|
|
5307
5307
|
// here rather than behind /api/config (admin-only) so a read-only client
|
|
5308
5308
|
// still learns the server supports flags even if it can't read values.
|
|
5309
|
-
featureFlags: true
|
|
5309
|
+
featureFlags: true,
|
|
5310
|
+
// Same contract: this server serves GET /api/projects/summary, which the
|
|
5311
|
+
// Hub's grouped views need before they can draw a tree.
|
|
5312
|
+
projectSummary: true
|
|
5310
5313
|
});
|
|
5311
5314
|
});
|
|
5312
5315
|
app.get("/api/profiles", (c) => c.json([]));
|
|
@@ -5453,6 +5456,11 @@ var createProjectRoutes = (deps) => {
|
|
|
5453
5456
|
deps.handleGetPopularProjects(url, c.env.outgoing);
|
|
5454
5457
|
return alreadyHandled4();
|
|
5455
5458
|
});
|
|
5459
|
+
app.get("/summary", (c) => {
|
|
5460
|
+
const url = new URL(c.req.url);
|
|
5461
|
+
deps.handleGetProjectSummaries(url, c.env.outgoing);
|
|
5462
|
+
return alreadyHandled4();
|
|
5463
|
+
});
|
|
5456
5464
|
return app;
|
|
5457
5465
|
};
|
|
5458
5466
|
|
|
@@ -6320,6 +6328,21 @@ var ConversationCache = class _ConversationCache {
|
|
|
6320
6328
|
ORDER BY cnt DESC
|
|
6321
6329
|
LIMIT ?`
|
|
6322
6330
|
),
|
|
6331
|
+
// Same table, same rows and same NULL filter /api/conversations lists
|
|
6332
|
+
// from, so a group's count/last-activity can never disagree with the
|
|
6333
|
+
// page it opens. Bare project_name is the one from the MAX(last_activity)
|
|
6334
|
+
// row (SQLite's documented min/max-aggregate bare-column rule).
|
|
6335
|
+
projectSummaries: db.prepare(
|
|
6336
|
+
`SELECT project_path, project_name, COUNT(*) as cnt, MAX(last_activity) as latest
|
|
6337
|
+
FROM conversation_meta
|
|
6338
|
+
WHERE project_path IS NOT NULL
|
|
6339
|
+
GROUP BY project_path
|
|
6340
|
+
ORDER BY latest DESC, project_path ASC
|
|
6341
|
+
LIMIT ? OFFSET ?`
|
|
6342
|
+
),
|
|
6343
|
+
projectSummaryCount: db.prepare(
|
|
6344
|
+
"SELECT COUNT(DISTINCT project_path) as n FROM conversation_meta WHERE project_path IS NOT NULL"
|
|
6345
|
+
),
|
|
6323
6346
|
getFileState: db.prepare("SELECT * FROM conversation_file_state WHERE path = ?"),
|
|
6324
6347
|
upsertFileState: db.prepare(
|
|
6325
6348
|
`INSERT INTO conversation_file_state
|
|
@@ -6695,6 +6718,23 @@ var ConversationCache = class _ConversationCache {
|
|
|
6695
6718
|
sessionCount: r.cnt
|
|
6696
6719
|
}));
|
|
6697
6720
|
}
|
|
6721
|
+
/** Every project with at least one cached conversation, most recently active
|
|
6722
|
+
* first. Paths are the raw `project_path` values, which is what
|
|
6723
|
+
* /api/conversations?project= matches on exactly — so a summary row is
|
|
6724
|
+
* always joinable against the page it describes. */
|
|
6725
|
+
listProjectSummaries(opts) {
|
|
6726
|
+
const total = this.stmts.projectSummaryCount.get().n;
|
|
6727
|
+
const rows = opts.limit === 0 ? [] : this.stmts.projectSummaries.all(opts.limit, opts.offset);
|
|
6728
|
+
return {
|
|
6729
|
+
total,
|
|
6730
|
+
projects: rows.map((r) => ({
|
|
6731
|
+
path: r.project_path,
|
|
6732
|
+
name: r.project_name ?? r.project_path.split(/[/\\]/).pop() ?? r.project_path,
|
|
6733
|
+
conversationCount: r.cnt,
|
|
6734
|
+
lastActivity: new Date(r.latest ?? 0).toISOString()
|
|
6735
|
+
}))
|
|
6736
|
+
};
|
|
6737
|
+
}
|
|
6698
6738
|
ensureFileIndex() {
|
|
6699
6739
|
if (this.fileIndexLoaded) return;
|
|
6700
6740
|
const rows = this.stmts.allFilePaths.all();
|
|
@@ -10836,6 +10876,7 @@ var StreamerServer = class {
|
|
|
10836
10876
|
handleSearchTarget: (id, req, res) => this.handleSearchTarget(id, req, res),
|
|
10837
10877
|
handleListProjects: (url, res) => handleListProjects(url, res),
|
|
10838
10878
|
handleGetPopularProjects: (url, res) => this.handleGetPopularProjects(url, res),
|
|
10879
|
+
handleGetProjectSummaries: (url, res) => this.handleGetProjectSummaries(url, res),
|
|
10839
10880
|
handlePairStart: (res) => this.handlePairStart(res),
|
|
10840
10881
|
handlePairExchange: (req, res) => this.handlePairExchange(req, res),
|
|
10841
10882
|
handleBrowse: (url, res) => this.handleBrowse(url, res),
|
|
@@ -12401,6 +12442,20 @@ var StreamerServer = class {
|
|
|
12401
12442
|
const projects = this.cache.getPopularProjects(limit);
|
|
12402
12443
|
json(res, 200, { projects, total: projects.length });
|
|
12403
12444
|
}
|
|
12445
|
+
handleGetProjectSummaries(url, res) {
|
|
12446
|
+
if (this.rejectIfWarmingUp(res)) return;
|
|
12447
|
+
const limit = intParam(url, "limit", 200);
|
|
12448
|
+
const offset = intParam(url, "offset", 0);
|
|
12449
|
+
if (!this.cache) {
|
|
12450
|
+
json(res, 503, {
|
|
12451
|
+
error: "Conversation cache unavailable",
|
|
12452
|
+
code: "CACHE_UNAVAILABLE"
|
|
12453
|
+
});
|
|
12454
|
+
return;
|
|
12455
|
+
}
|
|
12456
|
+
const { projects, total } = this.cache.listProjectSummaries({ limit, offset });
|
|
12457
|
+
json(res, 200, { projects, total, offset, hasMore: offset + projects.length < total });
|
|
12458
|
+
}
|
|
12404
12459
|
buildStatCache(previousScanner) {
|
|
12405
12460
|
if (!this.cache) return void 0;
|
|
12406
12461
|
if (!previousScanner) {
|