@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.cjs
CHANGED
|
@@ -5345,7 +5345,10 @@ var createMiscRoutes = (deps) => {
|
|
|
5345
5345
|
// Same contract: this server serves GET /api/config/feature-flags. Lives
|
|
5346
5346
|
// here rather than behind /api/config (admin-only) so a read-only client
|
|
5347
5347
|
// still learns the server supports flags even if it can't read values.
|
|
5348
|
-
featureFlags: true
|
|
5348
|
+
featureFlags: true,
|
|
5349
|
+
// Same contract: this server serves GET /api/projects/summary, which the
|
|
5350
|
+
// Hub's grouped views need before they can draw a tree.
|
|
5351
|
+
projectSummary: true
|
|
5349
5352
|
});
|
|
5350
5353
|
});
|
|
5351
5354
|
app.get("/api/profiles", (c) => c.json([]));
|
|
@@ -5492,6 +5495,11 @@ var createProjectRoutes = (deps) => {
|
|
|
5492
5495
|
deps.handleGetPopularProjects(url, c.env.outgoing);
|
|
5493
5496
|
return alreadyHandled4();
|
|
5494
5497
|
});
|
|
5498
|
+
app.get("/summary", (c) => {
|
|
5499
|
+
const url = new URL(c.req.url);
|
|
5500
|
+
deps.handleGetProjectSummaries(url, c.env.outgoing);
|
|
5501
|
+
return alreadyHandled4();
|
|
5502
|
+
});
|
|
5495
5503
|
return app;
|
|
5496
5504
|
};
|
|
5497
5505
|
|
|
@@ -6357,6 +6365,21 @@ var ConversationCache = class _ConversationCache {
|
|
|
6357
6365
|
ORDER BY cnt DESC
|
|
6358
6366
|
LIMIT ?`
|
|
6359
6367
|
),
|
|
6368
|
+
// Same table, same rows and same NULL filter /api/conversations lists
|
|
6369
|
+
// from, so a group's count/last-activity can never disagree with the
|
|
6370
|
+
// page it opens. Bare project_name is the one from the MAX(last_activity)
|
|
6371
|
+
// row (SQLite's documented min/max-aggregate bare-column rule).
|
|
6372
|
+
projectSummaries: db.prepare(
|
|
6373
|
+
`SELECT project_path, project_name, COUNT(*) as cnt, MAX(last_activity) as latest
|
|
6374
|
+
FROM conversation_meta
|
|
6375
|
+
WHERE project_path IS NOT NULL
|
|
6376
|
+
GROUP BY project_path
|
|
6377
|
+
ORDER BY latest DESC, project_path ASC
|
|
6378
|
+
LIMIT ? OFFSET ?`
|
|
6379
|
+
),
|
|
6380
|
+
projectSummaryCount: db.prepare(
|
|
6381
|
+
"SELECT COUNT(DISTINCT project_path) as n FROM conversation_meta WHERE project_path IS NOT NULL"
|
|
6382
|
+
),
|
|
6360
6383
|
getFileState: db.prepare("SELECT * FROM conversation_file_state WHERE path = ?"),
|
|
6361
6384
|
upsertFileState: db.prepare(
|
|
6362
6385
|
`INSERT INTO conversation_file_state
|
|
@@ -6732,6 +6755,23 @@ var ConversationCache = class _ConversationCache {
|
|
|
6732
6755
|
sessionCount: r.cnt
|
|
6733
6756
|
}));
|
|
6734
6757
|
}
|
|
6758
|
+
/** Every project with at least one cached conversation, most recently active
|
|
6759
|
+
* first. Paths are the raw `project_path` values, which is what
|
|
6760
|
+
* /api/conversations?project= matches on exactly — so a summary row is
|
|
6761
|
+
* always joinable against the page it describes. */
|
|
6762
|
+
listProjectSummaries(opts) {
|
|
6763
|
+
const total = this.stmts.projectSummaryCount.get().n;
|
|
6764
|
+
const rows = opts.limit === 0 ? [] : this.stmts.projectSummaries.all(opts.limit, opts.offset);
|
|
6765
|
+
return {
|
|
6766
|
+
total,
|
|
6767
|
+
projects: rows.map((r) => ({
|
|
6768
|
+
path: r.project_path,
|
|
6769
|
+
name: r.project_name ?? r.project_path.split(/[/\\]/).pop() ?? r.project_path,
|
|
6770
|
+
conversationCount: r.cnt,
|
|
6771
|
+
lastActivity: new Date(r.latest ?? 0).toISOString()
|
|
6772
|
+
}))
|
|
6773
|
+
};
|
|
6774
|
+
}
|
|
6735
6775
|
ensureFileIndex() {
|
|
6736
6776
|
if (this.fileIndexLoaded) return;
|
|
6737
6777
|
const rows = this.stmts.allFilePaths.all();
|
|
@@ -10873,6 +10913,7 @@ var StreamerServer = class {
|
|
|
10873
10913
|
handleSearchTarget: (id, req, res) => this.handleSearchTarget(id, req, res),
|
|
10874
10914
|
handleListProjects: (url, res) => handleListProjects(url, res),
|
|
10875
10915
|
handleGetPopularProjects: (url, res) => this.handleGetPopularProjects(url, res),
|
|
10916
|
+
handleGetProjectSummaries: (url, res) => this.handleGetProjectSummaries(url, res),
|
|
10876
10917
|
handlePairStart: (res) => this.handlePairStart(res),
|
|
10877
10918
|
handlePairExchange: (req, res) => this.handlePairExchange(req, res),
|
|
10878
10919
|
handleBrowse: (url, res) => this.handleBrowse(url, res),
|
|
@@ -12438,6 +12479,20 @@ var StreamerServer = class {
|
|
|
12438
12479
|
const projects = this.cache.getPopularProjects(limit);
|
|
12439
12480
|
json(res, 200, { projects, total: projects.length });
|
|
12440
12481
|
}
|
|
12482
|
+
handleGetProjectSummaries(url, res) {
|
|
12483
|
+
if (this.rejectIfWarmingUp(res)) return;
|
|
12484
|
+
const limit = intParam(url, "limit", 200);
|
|
12485
|
+
const offset = intParam(url, "offset", 0);
|
|
12486
|
+
if (!this.cache) {
|
|
12487
|
+
json(res, 503, {
|
|
12488
|
+
error: "Conversation cache unavailable",
|
|
12489
|
+
code: "CACHE_UNAVAILABLE"
|
|
12490
|
+
});
|
|
12491
|
+
return;
|
|
12492
|
+
}
|
|
12493
|
+
const { projects, total } = this.cache.listProjectSummaries({ limit, offset });
|
|
12494
|
+
json(res, 200, { projects, total, offset, hasMore: offset + projects.length < total });
|
|
12495
|
+
}
|
|
12441
12496
|
buildStatCache(previousScanner) {
|
|
12442
12497
|
if (!this.cache) return void 0;
|
|
12443
12498
|
if (!previousScanner) {
|