@sleep2agi/commhub-server 0.8.7-preview.0 → 0.8.8-preview.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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@sleep2agi/commhub-server",
3
- "version": "0.8.7-preview.0",
3
+ "version": "0.8.8-preview.0",
4
4
  "description": "CommHub Server — AI Agent communication hub with MCP protocol, multi-network isolation, user auth, and 17 MCP tools.",
5
5
  "type": "module",
6
6
  "main": "src/index.ts",
package/src/db.ts CHANGED
@@ -168,6 +168,15 @@ db.exec(`
168
168
  CREATE INDEX IF NOT EXISTS idx_tasks_from ON tasks(from_name);
169
169
  CREATE INDEX IF NOT EXISTS idx_tasks_status ON tasks(status);
170
170
  CREATE INDEX IF NOT EXISTS idx_tasks_created ON tasks(created_at);
171
+ -- #248 — composite index for the dashboard chat-panel history query
172
+ -- (/api/tasks?to_name=X&limit=30 ORDER BY created_at DESC). Without it
173
+ -- SQLite walks every row for the alias via idx_tasks_to and sorts in
174
+ -- memory; on an active node with thousands of tasks that's O(N log N)
175
+ -- per panel open. The composite ordered DESC lets the planner stop
176
+ -- after LIMIT rows — O(log N + LIMIT). Idempotent migration; safe to
177
+ -- ship — existing single-column idx_tasks_to is kept (other paths
178
+ -- use it and we don't need the risk of dropping it).
179
+ CREATE INDEX IF NOT EXISTS idx_tasks_to_created ON tasks(to_name, created_at DESC);
171
180
  `);
172
181
 
173
182
  // nodes table (V2 Sprint 2) — persistent node identity, separate from runtime sessions
package/src/index.ts CHANGED
@@ -1963,6 +1963,12 @@ Bun.serve({
1963
1963
  const toName = url.searchParams.get("to_name");
1964
1964
  const fromName = url.searchParams.get("from_name");
1965
1965
  const limit = Math.min(Number(url.searchParams.get("limit")) || 50, 200);
1966
+ // #248 — opt-out of the stats GROUP-BY scan. The dashboard chat panel
1967
+ // never consumes `stats`; it's a global per-status table scan that
1968
+ // dominates the request time on a large DB (270 MB / many tasks).
1969
+ // Existing callers that don't pass `skip_stats=1` get the same
1970
+ // {ok, tasks, count, stats} shape — backwards-compatible.
1971
+ const skipStats = url.searchParams.get("skip_stats") === "1";
1966
1972
 
1967
1973
  let sql = "SELECT * FROM tasks WHERE 1=1";
1968
1974
  const params: any[] = [];
@@ -1975,6 +1981,9 @@ Bun.serve({
1975
1981
  params.push(limit);
1976
1982
 
1977
1983
  const rows = db.all(sql, ...params);
1984
+ if (skipStats) {
1985
+ return withCors(req, Response.json({ ok: true, tasks: rows, count: rows.length }));
1986
+ }
1978
1987
  const statsParams: any[] = [];
1979
1988
  let statsSql = "SELECT status, COUNT(*) as count FROM tasks WHERE 1=1";
1980
1989
  statsSql = addNetworkScope(statsSql, statsParams, restScope);