@clauderecallhq/cli 0.0.1 → 0.11.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/LICENSE +33 -0
- package/README.md +543 -3
- package/README.public.md +523 -0
- package/dist/cli.js +354 -0
- package/dist/cli.js.map +1 -0
- package/dist/commands/activate.js +69 -0
- package/dist/commands/activate.js.map +1 -0
- package/dist/commands/audit-secrets.js +103 -0
- package/dist/commands/audit-secrets.js.map +1 -0
- package/dist/commands/blame.js +35 -0
- package/dist/commands/blame.js.map +1 -0
- package/dist/commands/config-verification.js +18 -0
- package/dist/commands/config-verification.js.map +1 -0
- package/dist/commands/context.js +144 -0
- package/dist/commands/context.js.map +1 -0
- package/dist/commands/correlate.js +70 -0
- package/dist/commands/correlate.js.map +1 -0
- package/dist/commands/digest.js +78 -0
- package/dist/commands/digest.js.map +1 -0
- package/dist/commands/health.js +62 -0
- package/dist/commands/health.js.map +1 -0
- package/dist/commands/index.js +247 -0
- package/dist/commands/index.js.map +1 -0
- package/dist/commands/install-extension.js +138 -0
- package/dist/commands/install-extension.js.map +1 -0
- package/dist/commands/license.js +39 -0
- package/dist/commands/license.js.map +1 -0
- package/dist/commands/list.js +47 -0
- package/dist/commands/list.js.map +1 -0
- package/dist/commands/mcp.js +29 -0
- package/dist/commands/mcp.js.map +1 -0
- package/dist/commands/open.js +28 -0
- package/dist/commands/open.js.map +1 -0
- package/dist/commands/paste.js +154 -0
- package/dist/commands/paste.js.map +1 -0
- package/dist/commands/projects.js +36 -0
- package/dist/commands/projects.js.map +1 -0
- package/dist/commands/search.js +67 -0
- package/dist/commands/search.js.map +1 -0
- package/dist/commands/semantic.js +173 -0
- package/dist/commands/semantic.js.map +1 -0
- package/dist/commands/show.js +121 -0
- package/dist/commands/show.js.map +1 -0
- package/dist/commands/start.js +47 -0
- package/dist/commands/start.js.map +1 -0
- package/dist/commands/stats.js +133 -0
- package/dist/commands/stats.js.map +1 -0
- package/dist/commands/status.js +45 -0
- package/dist/commands/status.js.map +1 -0
- package/dist/commands/stop.js +29 -0
- package/dist/commands/stop.js.map +1 -0
- package/dist/commands/thread.js +396 -0
- package/dist/commands/thread.js.map +1 -0
- package/dist/context/formatter.js +103 -0
- package/dist/context/formatter.js.map +1 -0
- package/dist/daemon/auto-tag-config.js +103 -0
- package/dist/daemon/auto-tag-config.js.map +1 -0
- package/dist/daemon/auto-tag-config.test.js +72 -0
- package/dist/daemon/auto-tag-config.test.js.map +1 -0
- package/dist/daemon/auto-title-config.js +70 -0
- package/dist/daemon/auto-title-config.js.map +1 -0
- package/dist/daemon/bulk-title-jobs.js +170 -0
- package/dist/daemon/bulk-title-jobs.js.map +1 -0
- package/dist/daemon/correlator.js +320 -0
- package/dist/daemon/correlator.js.map +1 -0
- package/dist/daemon/discover.js +316 -0
- package/dist/daemon/discover.js.map +1 -0
- package/dist/daemon/editor-detection.js +186 -0
- package/dist/daemon/editor-detection.js.map +1 -0
- package/dist/daemon/entrypoint.js +55 -0
- package/dist/daemon/entrypoint.js.map +1 -0
- package/dist/daemon/git-correlator.js +256 -0
- package/dist/daemon/git-correlator.js.map +1 -0
- package/dist/daemon/mcp-installer.js +108 -0
- package/dist/daemon/mcp-installer.js.map +1 -0
- package/dist/daemon/onboarding-state.js +140 -0
- package/dist/daemon/onboarding-state.js.map +1 -0
- package/dist/daemon/pidfile.js +57 -0
- package/dist/daemon/pidfile.js.map +1 -0
- package/dist/daemon/ports.js +48 -0
- package/dist/daemon/ports.js.map +1 -0
- package/dist/daemon/scanProgressRegistry.js +62 -0
- package/dist/daemon/scanProgressRegistry.js.map +1 -0
- package/dist/daemon/server.js +2010 -0
- package/dist/daemon/server.js.map +1 -0
- package/dist/daemon/tag-scanner/anthropic-client.js +40 -0
- package/dist/daemon/tag-scanner/anthropic-client.js.map +1 -0
- package/dist/daemon/tag-scanner/autopilot.js +131 -0
- package/dist/daemon/tag-scanner/autopilot.js.map +1 -0
- package/dist/daemon/tag-scanner/claude-cli-driver.js +250 -0
- package/dist/daemon/tag-scanner/claude-cli-driver.js.map +1 -0
- package/dist/daemon/tag-scanner/orchestrator.js +88 -0
- package/dist/daemon/tag-scanner/orchestrator.js.map +1 -0
- package/dist/daemon/tag-scanner/prompt.js +46 -0
- package/dist/daemon/tag-scanner/prompt.js.map +1 -0
- package/dist/daemon/tag-scanner/prompt.test.js +48 -0
- package/dist/daemon/tag-scanner/prompt.test.js.map +1 -0
- package/dist/daemon/tag-scanner/scan-state.js +49 -0
- package/dist/daemon/tag-scanner/scan-state.js.map +1 -0
- package/dist/daemon/tag-scanner/session-fetcher.js +82 -0
- package/dist/daemon/tag-scanner/session-fetcher.js.map +1 -0
- package/dist/daemon/tag-scanner/session-fetcher.test.js +34 -0
- package/dist/daemon/tag-scanner/session-fetcher.test.js.map +1 -0
- package/dist/daemon/tag-scanner/validator.js +50 -0
- package/dist/daemon/tag-scanner/validator.js.map +1 -0
- package/dist/daemon/tag-scanner/validator.test.js +41 -0
- package/dist/daemon/tag-scanner/validator.test.js.map +1 -0
- package/dist/daemon/terminal-registry.js +443 -0
- package/dist/daemon/terminal-registry.js.map +1 -0
- package/dist/daemon/ui.js +64 -0
- package/dist/daemon/ui.js.map +1 -0
- package/dist/daemon/watcher.js +256 -0
- package/dist/daemon/watcher.js.map +1 -0
- package/dist/db/client.js +22 -0
- package/dist/db/client.js.map +1 -0
- package/dist/db/schema.js +496 -0
- package/dist/db/schema.js.map +1 -0
- package/dist/license/api-base.js +13 -0
- package/dist/license/api-base.js.map +1 -0
- package/dist/license/manager.js +43 -0
- package/dist/license/manager.js.map +1 -0
- package/dist/license/public-key.js +19 -0
- package/dist/license/public-key.js.map +1 -0
- package/dist/license/storage.js +27 -0
- package/dist/license/storage.js.map +1 -0
- package/dist/license/verify.js +23 -0
- package/dist/license/verify.js.map +1 -0
- package/dist/mcp/audit.js +126 -0
- package/dist/mcp/audit.js.map +1 -0
- package/dist/mcp/prompts.js +180 -0
- package/dist/mcp/prompts.js.map +1 -0
- package/dist/mcp/server.js +502 -0
- package/dist/mcp/server.js.map +1 -0
- package/dist/mcp/thread-tools.js +363 -0
- package/dist/mcp/thread-tools.js.map +1 -0
- package/dist/mcp/write-tools.js +239 -0
- package/dist/mcp/write-tools.js.map +1 -0
- package/dist/parser/jsonl.js +150 -0
- package/dist/parser/jsonl.js.map +1 -0
- package/dist/semantic/chunker.js +47 -0
- package/dist/semantic/chunker.js.map +1 -0
- package/dist/semantic/config.js +74 -0
- package/dist/semantic/config.js.map +1 -0
- package/dist/semantic/embedder.js +54 -0
- package/dist/semantic/embedder.js.map +1 -0
- package/dist/semantic/fusion.js +38 -0
- package/dist/semantic/fusion.js.map +1 -0
- package/dist/semantic/model-download.js +69 -0
- package/dist/semantic/model-download.js.map +1 -0
- package/dist/semantic/pipeline.js +375 -0
- package/dist/semantic/pipeline.js.map +1 -0
- package/dist/semantic/query.js +42 -0
- package/dist/semantic/query.js.map +1 -0
- package/dist/semantic/worker.js +78 -0
- package/dist/semantic/worker.js.map +1 -0
- package/dist/stats/backfill.js +151 -0
- package/dist/stats/backfill.js.map +1 -0
- package/dist/stats/health.js +102 -0
- package/dist/stats/health.js.map +1 -0
- package/dist/stats/query.js +385 -0
- package/dist/stats/query.js.map +1 -0
- package/dist/utils/aliases.js +107 -0
- package/dist/utils/aliases.js.map +1 -0
- package/dist/utils/autoCollections.js +635 -0
- package/dist/utils/autoCollections.js.map +1 -0
- package/dist/utils/autoTitle.js +348 -0
- package/dist/utils/autoTitle.js.map +1 -0
- package/dist/utils/collections.js +446 -0
- package/dist/utils/collections.js.map +1 -0
- package/dist/utils/format.js +46 -0
- package/dist/utils/format.js.map +1 -0
- package/dist/utils/notes.js +270 -0
- package/dist/utils/notes.js.map +1 -0
- package/dist/utils/paths.js +50 -0
- package/dist/utils/paths.js.map +1 -0
- package/dist/utils/pricing.js +257 -0
- package/dist/utils/pricing.js.map +1 -0
- package/dist/utils/secret-scanner.js +166 -0
- package/dist/utils/secret-scanner.js.map +1 -0
- package/dist/utils/sessionLabel.js +64 -0
- package/dist/utils/sessionLabel.js.map +1 -0
- package/dist/utils/tags.js +97 -0
- package/dist/utils/tags.js.map +1 -0
- package/dist/utils/thread-context.js +129 -0
- package/dist/utils/thread-context.js.map +1 -0
- package/dist/utils/threadFilter.js +18 -0
- package/dist/utils/threadFilter.js.map +1 -0
- package/dist/utils/threads-titler.js +298 -0
- package/dist/utils/threads-titler.js.map +1 -0
- package/dist/utils/threads.js +383 -0
- package/dist/utils/threads.js.map +1 -0
- package/dist/utils/usage.js +76 -0
- package/dist/utils/usage.js.map +1 -0
- package/dist/verification/compute.js +88 -0
- package/dist/verification/compute.js.map +1 -0
- package/dist/verification/config.js +34 -0
- package/dist/verification/config.js.map +1 -0
- package/dist/web/assets/index-CIr6J4Fw.js +1201 -0
- package/dist/web/assets/index-Ctc8g9Jw.css +1 -0
- package/dist/web/assets/inter-cyrillic-400-normal-HOLc17fK.woff +0 -0
- package/dist/web/assets/inter-cyrillic-400-normal-obahsSVq.woff2 +0 -0
- package/dist/web/assets/inter-cyrillic-500-normal-BasfLYem.woff2 +0 -0
- package/dist/web/assets/inter-cyrillic-500-normal-CxZf_p3X.woff +0 -0
- package/dist/web/assets/inter-cyrillic-600-normal-4D_pXhcN.woff +0 -0
- package/dist/web/assets/inter-cyrillic-600-normal-CWCymEST.woff2 +0 -0
- package/dist/web/assets/inter-cyrillic-700-normal-CjBOestx.woff2 +0 -0
- package/dist/web/assets/inter-cyrillic-700-normal-DrXBdSj3.woff +0 -0
- package/dist/web/assets/inter-cyrillic-ext-400-normal-BQZuk6qB.woff2 +0 -0
- package/dist/web/assets/inter-cyrillic-ext-400-normal-DQukG94-.woff +0 -0
- package/dist/web/assets/inter-cyrillic-ext-500-normal-B0yAr1jD.woff2 +0 -0
- package/dist/web/assets/inter-cyrillic-ext-500-normal-BmqWE9Dz.woff +0 -0
- package/dist/web/assets/inter-cyrillic-ext-600-normal-Bcila6Z-.woff +0 -0
- package/dist/web/assets/inter-cyrillic-ext-600-normal-Dfes3d0z.woff2 +0 -0
- package/dist/web/assets/inter-cyrillic-ext-700-normal-BjwYoWNd.woff2 +0 -0
- package/dist/web/assets/inter-cyrillic-ext-700-normal-LO58E6JB.woff +0 -0
- package/dist/web/assets/inter-greek-400-normal-B4URO6DV.woff2 +0 -0
- package/dist/web/assets/inter-greek-400-normal-q2sYcFCs.woff +0 -0
- package/dist/web/assets/inter-greek-500-normal-BIZE56-Y.woff2 +0 -0
- package/dist/web/assets/inter-greek-500-normal-Xzm54t5V.woff +0 -0
- package/dist/web/assets/inter-greek-600-normal-BZpKdvQh.woff +0 -0
- package/dist/web/assets/inter-greek-600-normal-plRanbMR.woff2 +0 -0
- package/dist/web/assets/inter-greek-700-normal-BUv2fZ6O.woff +0 -0
- package/dist/web/assets/inter-greek-700-normal-C3JjAnD8.woff2 +0 -0
- package/dist/web/assets/inter-greek-ext-400-normal-DGGRlc-M.woff2 +0 -0
- package/dist/web/assets/inter-greek-ext-400-normal-KugGGMne.woff +0 -0
- package/dist/web/assets/inter-greek-ext-500-normal-2j5mBUwD.woff +0 -0
- package/dist/web/assets/inter-greek-ext-500-normal-C4iEst2y.woff2 +0 -0
- package/dist/web/assets/inter-greek-ext-600-normal-B8X0CLgF.woff +0 -0
- package/dist/web/assets/inter-greek-ext-600-normal-DRtmH8MT.woff2 +0 -0
- package/dist/web/assets/inter-greek-ext-700-normal-BoQ6DsYi.woff +0 -0
- package/dist/web/assets/inter-greek-ext-700-normal-qfdV9bQt.woff2 +0 -0
- package/dist/web/assets/inter-latin-400-normal-C38fXH4l.woff2 +0 -0
- package/dist/web/assets/inter-latin-400-normal-CyCys3Eg.woff +0 -0
- package/dist/web/assets/inter-latin-500-normal-BL9OpVg8.woff +0 -0
- package/dist/web/assets/inter-latin-500-normal-Cerq10X2.woff2 +0 -0
- package/dist/web/assets/inter-latin-600-normal-CiBQ2DWP.woff +0 -0
- package/dist/web/assets/inter-latin-600-normal-LgqL8muc.woff2 +0 -0
- package/dist/web/assets/inter-latin-700-normal-BLAVimhd.woff +0 -0
- package/dist/web/assets/inter-latin-700-normal-Yt3aPRUw.woff2 +0 -0
- package/dist/web/assets/inter-latin-ext-400-normal-77YHD8bZ.woff +0 -0
- package/dist/web/assets/inter-latin-ext-400-normal-C1nco2VV.woff2 +0 -0
- package/dist/web/assets/inter-latin-ext-500-normal-BxGbmqWO.woff +0 -0
- package/dist/web/assets/inter-latin-ext-500-normal-CV4jyFjo.woff2 +0 -0
- package/dist/web/assets/inter-latin-ext-600-normal-CIVaiw4L.woff +0 -0
- package/dist/web/assets/inter-latin-ext-600-normal-D2bJ5OIk.woff2 +0 -0
- package/dist/web/assets/inter-latin-ext-700-normal-Ca8adRJv.woff2 +0 -0
- package/dist/web/assets/inter-latin-ext-700-normal-TidjK2hL.woff +0 -0
- package/dist/web/assets/inter-vietnamese-400-normal-Bbgyi5SW.woff +0 -0
- package/dist/web/assets/inter-vietnamese-400-normal-DMkecbls.woff2 +0 -0
- package/dist/web/assets/inter-vietnamese-500-normal-DOriooB6.woff2 +0 -0
- package/dist/web/assets/inter-vietnamese-500-normal-mJboJaSs.woff +0 -0
- package/dist/web/assets/inter-vietnamese-600-normal-BuLX-rYi.woff +0 -0
- package/dist/web/assets/inter-vietnamese-600-normal-Cc8MFFhd.woff2 +0 -0
- package/dist/web/assets/inter-vietnamese-700-normal-BZaoP0fm.woff +0 -0
- package/dist/web/assets/inter-vietnamese-700-normal-DlLaEgI2.woff2 +0 -0
- package/dist/web/assets/jetbrains-mono-cyrillic-400-normal-BEIGL1Tu.woff2 +0 -0
- package/dist/web/assets/jetbrains-mono-cyrillic-400-normal-ugxPyKxw.woff +0 -0
- package/dist/web/assets/jetbrains-mono-cyrillic-500-normal-DJqRU3vO.woff +0 -0
- package/dist/web/assets/jetbrains-mono-cyrillic-500-normal-DmUKJPL_.woff2 +0 -0
- package/dist/web/assets/jetbrains-mono-greek-400-normal-B9oWc5Lo.woff +0 -0
- package/dist/web/assets/jetbrains-mono-greek-400-normal-C190GLew.woff2 +0 -0
- package/dist/web/assets/jetbrains-mono-greek-500-normal-D7SFKleX.woff +0 -0
- package/dist/web/assets/jetbrains-mono-greek-500-normal-JpySY46c.woff2 +0 -0
- package/dist/web/assets/jetbrains-mono-latin-400-normal-6-qcROiO.woff +0 -0
- package/dist/web/assets/jetbrains-mono-latin-400-normal-V6pRDFza.woff2 +0 -0
- package/dist/web/assets/jetbrains-mono-latin-500-normal-BWZEU5yA.woff2 +0 -0
- package/dist/web/assets/jetbrains-mono-latin-500-normal-CJOVTJB7.woff +0 -0
- package/dist/web/assets/jetbrains-mono-latin-ext-400-normal-Bc8Ftmh3.woff2 +0 -0
- package/dist/web/assets/jetbrains-mono-latin-ext-400-normal-fXTG6kC5.woff +0 -0
- package/dist/web/assets/jetbrains-mono-latin-ext-500-normal-Cut-4mMH.woff2 +0 -0
- package/dist/web/assets/jetbrains-mono-latin-ext-500-normal-ckzbgY84.woff +0 -0
- package/dist/web/assets/jetbrains-mono-vietnamese-400-normal-CqNFfHCs.woff +0 -0
- package/dist/web/assets/jetbrains-mono-vietnamese-500-normal-DNRqzVM1.woff +0 -0
- package/dist/web/favicon.svg +9 -0
- package/dist/web/index.html +15 -0
- package/package.json +79 -9
- package/bin/cli.js +0 -12
|
@@ -0,0 +1,151 @@
|
|
|
1
|
+
import { getDb } from '../db/client.js';
|
|
2
|
+
import { extractUsage } from '../parser/jsonl.js';
|
|
3
|
+
import { recomputeSessionRollup } from '../utils/usage.js';
|
|
4
|
+
const DEFAULT_CHUNK_SIZE = 500;
|
|
5
|
+
// Process-local set of message uuids whose raw_json is valid but carries
|
|
6
|
+
// no usage block (aborted assistant turns, pre-v0.10 Claude Code output).
|
|
7
|
+
// Without this the backfill endpoint would rescan them every call even
|
|
8
|
+
// though there is nothing to recover. Persisting to disk would need a
|
|
9
|
+
// schema migration for ~60–100 rows on a well-used install; an in-memory
|
|
10
|
+
// set is enough — on daemon restart we re-scan once, cheap.
|
|
11
|
+
const unparsable = new Set();
|
|
12
|
+
let lastRun = null;
|
|
13
|
+
let running = false;
|
|
14
|
+
/** Count of messages we've already scanned and confirmed have no usage data. */
|
|
15
|
+
export function getUnrecoverableCount() {
|
|
16
|
+
return unparsable.size;
|
|
17
|
+
}
|
|
18
|
+
function selectPendingSql() {
|
|
19
|
+
return `
|
|
20
|
+
SELECT m.uuid, m.session_id, m.timestamp, m.raw_json
|
|
21
|
+
FROM messages m
|
|
22
|
+
LEFT JOIN message_usage mu ON mu.message_uuid = m.uuid
|
|
23
|
+
WHERE m.role = 'assistant' AND mu.message_uuid IS NULL
|
|
24
|
+
AND m.uuid NOT IN (SELECT value FROM json_each(?))
|
|
25
|
+
LIMIT ?
|
|
26
|
+
`;
|
|
27
|
+
}
|
|
28
|
+
function runChunked(db, options) {
|
|
29
|
+
const totalLimit = options.limit ?? Number.MAX_SAFE_INTEGER;
|
|
30
|
+
const chunkSize = Math.max(1, options.chunkSize ?? DEFAULT_CHUNK_SIZE);
|
|
31
|
+
const selectStmt = db.prepare(selectPendingSql());
|
|
32
|
+
const insertStmt = db.prepare(`
|
|
33
|
+
INSERT INTO message_usage (
|
|
34
|
+
message_uuid, session_id, model,
|
|
35
|
+
input_tokens, output_tokens, cache_create_tokens, cache_read_tokens,
|
|
36
|
+
timestamp
|
|
37
|
+
) VALUES (
|
|
38
|
+
@uuid, @session_id, @model,
|
|
39
|
+
@input, @output, @cc, @cr, @ts
|
|
40
|
+
)
|
|
41
|
+
ON CONFLICT(message_uuid) DO NOTHING
|
|
42
|
+
`);
|
|
43
|
+
let scanned = 0;
|
|
44
|
+
let inserted = 0;
|
|
45
|
+
const allTouched = new Set();
|
|
46
|
+
while (scanned < totalLimit) {
|
|
47
|
+
const take = Math.min(chunkSize, totalLimit - scanned);
|
|
48
|
+
const skipList = JSON.stringify([...unparsable]);
|
|
49
|
+
const rows = selectStmt.all(skipList, take);
|
|
50
|
+
if (rows.length === 0)
|
|
51
|
+
break;
|
|
52
|
+
const chunkTouched = new Set();
|
|
53
|
+
const chunkTxn = db.transaction(() => {
|
|
54
|
+
for (const r of rows) {
|
|
55
|
+
let parsed;
|
|
56
|
+
try {
|
|
57
|
+
parsed = JSON.parse(r.raw_json);
|
|
58
|
+
}
|
|
59
|
+
catch {
|
|
60
|
+
unparsable.add(r.uuid);
|
|
61
|
+
continue;
|
|
62
|
+
}
|
|
63
|
+
const usage = extractUsage(parsed.message);
|
|
64
|
+
if (!usage) {
|
|
65
|
+
unparsable.add(r.uuid);
|
|
66
|
+
continue;
|
|
67
|
+
}
|
|
68
|
+
insertStmt.run({
|
|
69
|
+
uuid: r.uuid,
|
|
70
|
+
session_id: r.session_id,
|
|
71
|
+
model: parsed.message?.model ?? null,
|
|
72
|
+
input: usage.inputTokens,
|
|
73
|
+
output: usage.outputTokens,
|
|
74
|
+
cc: usage.cacheCreateTokens,
|
|
75
|
+
cr: usage.cacheReadTokens,
|
|
76
|
+
ts: r.timestamp,
|
|
77
|
+
});
|
|
78
|
+
inserted += 1;
|
|
79
|
+
chunkTouched.add(r.session_id);
|
|
80
|
+
}
|
|
81
|
+
for (const sid of chunkTouched) {
|
|
82
|
+
recomputeSessionRollup(db, sid);
|
|
83
|
+
allTouched.add(sid);
|
|
84
|
+
}
|
|
85
|
+
});
|
|
86
|
+
chunkTxn();
|
|
87
|
+
scanned += rows.length;
|
|
88
|
+
options.onProgress?.({
|
|
89
|
+
scanned,
|
|
90
|
+
inserted,
|
|
91
|
+
sessionsTouched: allTouched.size,
|
|
92
|
+
done: rows.length < take,
|
|
93
|
+
});
|
|
94
|
+
if (rows.length < take)
|
|
95
|
+
break;
|
|
96
|
+
}
|
|
97
|
+
return {
|
|
98
|
+
scanned,
|
|
99
|
+
inserted,
|
|
100
|
+
sessionsTouched: allTouched.size,
|
|
101
|
+
done: true,
|
|
102
|
+
};
|
|
103
|
+
}
|
|
104
|
+
/**
|
|
105
|
+
* Run a synchronous backfill pass in bounded chunks. Returns when either
|
|
106
|
+
* `limit` is reached or there are no more pending messages.
|
|
107
|
+
*/
|
|
108
|
+
export function runBackfill(options = {}) {
|
|
109
|
+
return runChunked(getDb(), options);
|
|
110
|
+
}
|
|
111
|
+
/**
|
|
112
|
+
* Kick the backfill in the background. Safe to call multiple times — a
|
|
113
|
+
* simple in-process gate prevents overlapping passes from stepping on
|
|
114
|
+
* each other.
|
|
115
|
+
*/
|
|
116
|
+
export function startBackgroundBackfill(opts = {}) {
|
|
117
|
+
if (running)
|
|
118
|
+
return false;
|
|
119
|
+
running = true;
|
|
120
|
+
queueMicrotask(() => {
|
|
121
|
+
try {
|
|
122
|
+
const result = runChunked(getDb(), opts);
|
|
123
|
+
lastRun = {
|
|
124
|
+
scanned: result.scanned,
|
|
125
|
+
inserted: result.inserted,
|
|
126
|
+
sessionsTouched: result.sessionsTouched,
|
|
127
|
+
finishedAt: new Date().toISOString(),
|
|
128
|
+
};
|
|
129
|
+
}
|
|
130
|
+
catch (err) {
|
|
131
|
+
console.error('[stats.backfill] failed:', err);
|
|
132
|
+
}
|
|
133
|
+
finally {
|
|
134
|
+
running = false;
|
|
135
|
+
}
|
|
136
|
+
});
|
|
137
|
+
return true;
|
|
138
|
+
}
|
|
139
|
+
export function isBackfillRunning() {
|
|
140
|
+
return running;
|
|
141
|
+
}
|
|
142
|
+
export function getLastBackfillRun() {
|
|
143
|
+
return lastRun;
|
|
144
|
+
}
|
|
145
|
+
/** Test helper — clears the in-memory unparsable cache. */
|
|
146
|
+
export function __resetBackfillState() {
|
|
147
|
+
unparsable.clear();
|
|
148
|
+
lastRun = null;
|
|
149
|
+
running = false;
|
|
150
|
+
}
|
|
151
|
+
//# sourceMappingURL=backfill.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"backfill.js","sourceRoot":"","sources":["../../src/stats/backfill.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,102 @@
|
|
|
1
|
+
import { getDb } from '../db/client.js';
|
|
2
|
+
function clamp01(n) {
|
|
3
|
+
return Math.max(0, Math.min(1, n));
|
|
4
|
+
}
|
|
5
|
+
export function computeHealthScore(projectId) {
|
|
6
|
+
const db = getDb();
|
|
7
|
+
const project = db
|
|
8
|
+
.prepare('SELECT id, name FROM projects WHERE id = ?')
|
|
9
|
+
.get(projectId);
|
|
10
|
+
if (!project)
|
|
11
|
+
return null;
|
|
12
|
+
const sessionStats = db
|
|
13
|
+
.prepare(`SELECT COUNT(*) AS cnt,
|
|
14
|
+
MAX(started_at) AS latest
|
|
15
|
+
FROM sessions WHERE project_id = ?`)
|
|
16
|
+
.get(projectId);
|
|
17
|
+
const sessionCount = sessionStats.cnt;
|
|
18
|
+
if (sessionCount === 0) {
|
|
19
|
+
return {
|
|
20
|
+
projectId,
|
|
21
|
+
projectName: project.name,
|
|
22
|
+
score: 0,
|
|
23
|
+
breakdown: {
|
|
24
|
+
sessionCount: { raw: 0, score: 0, weight: 0.2 },
|
|
25
|
+
recency: { daysSinceLastSession: Infinity, score: 0, weight: 0.25 },
|
|
26
|
+
fragmentation: { avgMessages: 0, score: 0, weight: 0.15 },
|
|
27
|
+
searchCoverage: { ratio: 0, score: 0, weight: 0.2 },
|
|
28
|
+
tagCoverage: { ratio: 0, score: 0, weight: 0.2 },
|
|
29
|
+
},
|
|
30
|
+
};
|
|
31
|
+
}
|
|
32
|
+
const sessionCountScore = clamp01(sessionCount / 10);
|
|
33
|
+
const daysSince = sessionStats.latest
|
|
34
|
+
? (Date.now() - new Date(sessionStats.latest).getTime()) / (1000 * 60 * 60 * 24)
|
|
35
|
+
: 90;
|
|
36
|
+
const recencyScore = clamp01(1 - daysSince / 90);
|
|
37
|
+
const fragRow = db
|
|
38
|
+
.prepare(`SELECT AVG(message_count) AS avg_msgs
|
|
39
|
+
FROM sessions WHERE project_id = ?`)
|
|
40
|
+
.get(projectId);
|
|
41
|
+
const avgMessages = fragRow.avg_msgs ?? 0;
|
|
42
|
+
const fragmentationScore = clamp01((avgMessages - 2) / 3);
|
|
43
|
+
const ftsRow = db
|
|
44
|
+
.prepare(`SELECT COUNT(*) AS total,
|
|
45
|
+
SUM(CASE WHEN m.content_text IS NOT NULL AND m.content_text != '' THEN 1 ELSE 0 END) AS covered
|
|
46
|
+
FROM messages m
|
|
47
|
+
JOIN sessions s ON s.id = m.session_id
|
|
48
|
+
WHERE s.project_id = ?`)
|
|
49
|
+
.get(projectId);
|
|
50
|
+
const searchRatio = ftsRow.total > 0 ? ftsRow.covered / ftsRow.total : 0.5;
|
|
51
|
+
const searchScore = clamp01(searchRatio);
|
|
52
|
+
const tagRow = db
|
|
53
|
+
.prepare(`SELECT COUNT(DISTINCT s.id) AS total,
|
|
54
|
+
COUNT(DISTINCT st.session_id) AS tagged
|
|
55
|
+
FROM sessions s
|
|
56
|
+
LEFT JOIN session_tags st ON st.session_id = s.id
|
|
57
|
+
WHERE s.project_id = ?`)
|
|
58
|
+
.get(projectId);
|
|
59
|
+
const tagRatio = tagRow.total > 0 ? tagRow.tagged / tagRow.total : 0;
|
|
60
|
+
const tagScore = clamp01(tagRatio);
|
|
61
|
+
const score = Math.round((sessionCountScore * 0.2 +
|
|
62
|
+
recencyScore * 0.25 +
|
|
63
|
+
fragmentationScore * 0.15 +
|
|
64
|
+
searchScore * 0.2 +
|
|
65
|
+
tagScore * 0.2) *
|
|
66
|
+
100);
|
|
67
|
+
return {
|
|
68
|
+
projectId,
|
|
69
|
+
projectName: project.name,
|
|
70
|
+
score,
|
|
71
|
+
breakdown: {
|
|
72
|
+
sessionCount: { raw: sessionCount, score: sessionCountScore, weight: 0.2 },
|
|
73
|
+
recency: { daysSinceLastSession: Math.round(daysSince), score: recencyScore, weight: 0.25 },
|
|
74
|
+
fragmentation: { avgMessages: Math.round(avgMessages * 10) / 10, score: fragmentationScore, weight: 0.15 },
|
|
75
|
+
searchCoverage: { ratio: Math.round(searchRatio * 100) / 100, score: searchScore, weight: 0.2 },
|
|
76
|
+
tagCoverage: { ratio: Math.round(tagRatio * 100) / 100, score: tagScore, weight: 0.2 },
|
|
77
|
+
},
|
|
78
|
+
};
|
|
79
|
+
}
|
|
80
|
+
export function computeHealthScoreByName(name) {
|
|
81
|
+
const db = getDb();
|
|
82
|
+
const row = db
|
|
83
|
+
.prepare('SELECT id FROM projects WHERE name = ?')
|
|
84
|
+
.get(name);
|
|
85
|
+
if (!row)
|
|
86
|
+
return null;
|
|
87
|
+
return computeHealthScore(row.id);
|
|
88
|
+
}
|
|
89
|
+
export function computeAllHealthScores() {
|
|
90
|
+
const db = getDb();
|
|
91
|
+
const projects = db
|
|
92
|
+
.prepare('SELECT id FROM projects ORDER BY name')
|
|
93
|
+
.all();
|
|
94
|
+
const scores = [];
|
|
95
|
+
for (const p of projects) {
|
|
96
|
+
const s = computeHealthScore(p.id);
|
|
97
|
+
if (s)
|
|
98
|
+
scores.push(s);
|
|
99
|
+
}
|
|
100
|
+
return scores;
|
|
101
|
+
}
|
|
102
|
+
//# sourceMappingURL=health.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"health.js","sourceRoot":"","sources":["../../src/stats/health.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,EAAE,MAAM,iBAAiB,CAAC;AAiBxC,SAAS,OAAO,CAAC,CAAS;IACxB,OAAO,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC;AACrC,CAAC;AAED,MAAM,UAAU,kBAAkB,CAAC,SAAiB;IAClD,MAAM,EAAE,GAAG,KAAK,EAAE,CAAC;IAEnB,MAAM,OAAO,GAAG,EAAE;SACf,OAAO,CAAC,4CAA4C,CAAC;SACrD,GAAG,CAAC,SAAS,CAA6C,CAAC;IAC9D,IAAI,CAAC,OAAO;QAAE,OAAO,IAAI,CAAC;IAE1B,MAAM,YAAY,GAAG,EAAE;SACpB,OAAO,CACN;;0CAEoC,CACrC;SACA,GAAG,CAAC,SAAS,CAA2C,CAAC;IAE5D,MAAM,YAAY,GAAG,YAAY,CAAC,GAAG,CAAC;IACtC,IAAI,YAAY,KAAK,CAAC,EAAE,CAAC;QACvB,OAAO;YACL,SAAS;YACT,WAAW,EAAE,OAAO,CAAC,IAAI;YACzB,KAAK,EAAE,CAAC;YACR,SAAS,EAAE;gBACT,YAAY,EAAE,EAAE,GAAG,EAAE,CAAC,EAAE,KAAK,EAAE,CAAC,EAAE,MAAM,EAAE,GAAG,EAAE;gBAC/C,OAAO,EAAE,EAAE,oBAAoB,EAAE,QAAQ,EAAE,KAAK,EAAE,CAAC,EAAE,MAAM,EAAE,IAAI,EAAE;gBACnE,aAAa,EAAE,EAAE,WAAW,EAAE,CAAC,EAAE,KAAK,EAAE,CAAC,EAAE,MAAM,EAAE,IAAI,EAAE;gBACzD,cAAc,EAAE,EAAE,KAAK,EAAE,CAAC,EAAE,KAAK,EAAE,CAAC,EAAE,MAAM,EAAE,GAAG,EAAE;gBACnD,WAAW,EAAE,EAAE,KAAK,EAAE,CAAC,EAAE,KAAK,EAAE,CAAC,EAAE,MAAM,EAAE,GAAG,EAAE;aACjD;SACF,CAAC;IACJ,CAAC;IAED,MAAM,iBAAiB,GAAG,OAAO,CAAC,YAAY,GAAG,EAAE,CAAC,CAAC;IAErD,MAAM,SAAS,GAAG,YAAY,CAAC,MAAM;QACnC,CAAC,CAAC,CAAC,IAAI,CAAC,GAAG,EAAE,GAAG,IAAI,IAAI,CAAC,YAAY,CAAC,MAAM,CAAC,CAAC,OAAO,EAAE,CAAC,GAAG,CAAC,IAAI,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,CAAC;QAChF,CAAC,CAAC,EAAE,CAAC;IACP,MAAM,YAAY,GAAG,OAAO,CAAC,CAAC,GAAG,SAAS,GAAG,EAAE,CAAC,CAAC;IAEjD,MAAM,OAAO,GAAG,EAAE;SACf,OAAO,CACN;0CACoC,CACrC;SACA,GAAG,CAAC,SAAS,CAAgC,CAAC;IACjD,MAAM,WAAW,GAAG,OAAO,CAAC,QAAQ,IAAI,CAAC,CAAC;IAC1C,MAAM,kBAAkB,GAAG,OAAO,CAAC,CAAC,WAAW,GAAG,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC;IAE1D,MAAM,MAAM,GAAG,EAAE;SACd,OAAO,CACN;;;;8BAIwB,CACzB;SACA,GAAG,CAAC,SAAS,CAAuC,CAAC;IACxD,MAAM,WAAW,GAAG,MAAM,CAAC,KAAK,GAAG,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,OAAO,GAAG,MAAM,CAAC,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC;IAC3E,MAAM,WAAW,GAAG,OAAO,CAAC,WAAW,CAAC,CAAC;IAEzC,MAAM,MAAM,GAAG,EAAE;SACd,OAAO,CACN;;;;8BAIwB,CACzB;SACA,GAAG,CAAC,SAAS,CAAsC,CAAC;IACvD,MAAM,QAAQ,GAAG,MAAM,CAAC,KAAK,GAAG,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,MAAM,GAAG,MAAM,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC;IACrE,MAAM,QAAQ,GAAG,OAAO,CAAC,QAAQ,CAAC,CAAC;IAEnC,MAAM,KAAK,GAAG,IAAI,CAAC,KAAK,CACtB,CAAC,iBAAiB,GAAG,GAAG;QACtB,YAAY,GAAG,IAAI;QACnB,kBAAkB,GAAG,IAAI;QACzB,WAAW,GAAG,GAAG;QACjB,QAAQ,GAAG,GAAG,CAAC;QACf,GAAG,CACN,CAAC;IAEF,OAAO;QACL,SAAS;QACT,WAAW,EAAE,OAAO,CAAC,IAAI;QACzB,KAAK;QACL,SAAS,EAAE;YACT,YAAY,EAAE,EAAE,GAAG,EAAE,YAAY,EAAE,KAAK,EAAE,iBAAiB,EAAE,MAAM,EAAE,GAAG,EAAE;YAC1E,OAAO,EAAE,EAAE,oBAAoB,EAAE,IAAI,CAAC,KAAK,CAAC,SAAS,CAAC,EAAE,KAAK,EAAE,YAAY,EAAE,MAAM,EAAE,IAAI,EAAE;YAC3F,aAAa,EAAE,EAAE,WAAW,EAAE,IAAI,CAAC,KAAK,CAAC,WAAW,GAAG,EAAE,CAAC,GAAG,EAAE,EAAE,KAAK,EAAE,kBAAkB,EAAE,MAAM,EAAE,IAAI,EAAE;YAC1G,cAAc,EAAE,EAAE,KAAK,EAAE,IAAI,CAAC,KAAK,CAAC,WAAW,GAAG,GAAG,CAAC,GAAG,GAAG,EAAE,KAAK,EAAE,WAAW,EAAE,MAAM,EAAE,GAAG,EAAE;YAC/F,WAAW,EAAE,EAAE,KAAK,EAAE,IAAI,CAAC,KAAK,CAAC,QAAQ,GAAG,GAAG,CAAC,GAAG,GAAG,EAAE,KAAK,EAAE,QAAQ,EAAE,MAAM,EAAE,GAAG,EAAE;SACvF;KACF,CAAC;AACJ,CAAC;AAED,MAAM,UAAU,wBAAwB,CAAC,IAAY;IACnD,MAAM,EAAE,GAAG,KAAK,EAAE,CAAC;IACnB,MAAM,GAAG,GAAG,EAAE;SACX,OAAO,CAAC,wCAAwC,CAAC;SACjD,GAAG,CAAC,IAAI,CAA+B,CAAC;IAC3C,IAAI,CAAC,GAAG;QAAE,OAAO,IAAI,CAAC;IACtB,OAAO,kBAAkB,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC;AACpC,CAAC;AAED,MAAM,UAAU,sBAAsB;IACpC,MAAM,EAAE,GAAG,KAAK,EAAE,CAAC;IACnB,MAAM,QAAQ,GAAG,EAAE;SAChB,OAAO,CAAC,uCAAuC,CAAC;SAChD,GAAG,EAA2B,CAAC;IAClC,MAAM,MAAM,GAAkB,EAAE,CAAC;IACjC,KAAK,MAAM,CAAC,IAAI,QAAQ,EAAE,CAAC;QACzB,MAAM,CAAC,GAAG,kBAAkB,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC;QACnC,IAAI,CAAC;YAAE,MAAM,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IACxB,CAAC;IACD,OAAO,MAAM,CAAC;AAChB,CAAC"}
|
|
@@ -0,0 +1,385 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* v0.10a — cost / token analytics query layer.
|
|
3
|
+
*
|
|
4
|
+
* Reads raw token counts from `message_usage` + per-session rollups from
|
|
5
|
+
* `sessions`, then derives dollar amounts via the pricing table at
|
|
6
|
+
* render time. Prices change; tokens don't.
|
|
7
|
+
*/
|
|
8
|
+
import { getDb } from '../db/client.js';
|
|
9
|
+
import { getUnrecoverableCount } from './backfill.js';
|
|
10
|
+
import { estimateCost, formatDollars, formatTokens, priceFor, } from '../utils/pricing.js';
|
|
11
|
+
function aggregateByModel(rows) {
|
|
12
|
+
const agg = new Map();
|
|
13
|
+
for (const r of rows) {
|
|
14
|
+
const key = r.model ?? null;
|
|
15
|
+
const prev = agg.get(key) ?? {
|
|
16
|
+
inputTokens: 0,
|
|
17
|
+
outputTokens: 0,
|
|
18
|
+
cacheCreateTokens: 0,
|
|
19
|
+
cacheReadTokens: 0,
|
|
20
|
+
messageCount: 0,
|
|
21
|
+
};
|
|
22
|
+
prev.inputTokens += r.input_tokens;
|
|
23
|
+
prev.outputTokens += r.output_tokens;
|
|
24
|
+
prev.cacheCreateTokens += r.cache_create_tokens;
|
|
25
|
+
prev.cacheReadTokens += r.cache_read_tokens;
|
|
26
|
+
prev.messageCount += r.n;
|
|
27
|
+
agg.set(key, prev);
|
|
28
|
+
}
|
|
29
|
+
const out = [];
|
|
30
|
+
for (const [model, m] of agg.entries()) {
|
|
31
|
+
const cost = estimateCost({
|
|
32
|
+
inputTokens: m.inputTokens,
|
|
33
|
+
outputTokens: m.outputTokens,
|
|
34
|
+
cacheCreateTokens: m.cacheCreateTokens,
|
|
35
|
+
cacheReadTokens: m.cacheReadTokens,
|
|
36
|
+
}, model);
|
|
37
|
+
out.push({
|
|
38
|
+
model,
|
|
39
|
+
modelLabel: priceFor(model).label,
|
|
40
|
+
inputTokens: m.inputTokens,
|
|
41
|
+
outputTokens: m.outputTokens,
|
|
42
|
+
cacheCreateTokens: m.cacheCreateTokens,
|
|
43
|
+
cacheReadTokens: m.cacheReadTokens,
|
|
44
|
+
messageCount: m.messageCount,
|
|
45
|
+
cost,
|
|
46
|
+
});
|
|
47
|
+
}
|
|
48
|
+
return out.sort((a, b) => b.cost.cents - a.cost.cents);
|
|
49
|
+
}
|
|
50
|
+
function buildByModelTotals(rows) {
|
|
51
|
+
const byModel = {};
|
|
52
|
+
for (const r of rows) {
|
|
53
|
+
byModel[r.model ?? '__unknown__'] = {
|
|
54
|
+
inputTokens: r.inputTokens,
|
|
55
|
+
outputTokens: r.outputTokens,
|
|
56
|
+
cacheCreateTokens: r.cacheCreateTokens,
|
|
57
|
+
cacheReadTokens: r.cacheReadTokens,
|
|
58
|
+
};
|
|
59
|
+
}
|
|
60
|
+
return { byModel };
|
|
61
|
+
}
|
|
62
|
+
export function getSessionStats(sessionId) {
|
|
63
|
+
const db = getDb();
|
|
64
|
+
const s = db
|
|
65
|
+
.prepare(`SELECT s.id, p.name AS project, s.started_at, s.ended_at,
|
|
66
|
+
s.message_count,
|
|
67
|
+
s.total_input_tokens, s.total_output_tokens,
|
|
68
|
+
s.total_cache_create_tokens, s.total_cache_read_tokens,
|
|
69
|
+
s.primary_model
|
|
70
|
+
FROM sessions s
|
|
71
|
+
LEFT JOIN projects p ON p.id = s.project_id
|
|
72
|
+
WHERE s.id = ?`)
|
|
73
|
+
.get(sessionId);
|
|
74
|
+
if (!s)
|
|
75
|
+
return null;
|
|
76
|
+
const perModel = db
|
|
77
|
+
.prepare(`SELECT model,
|
|
78
|
+
COALESCE(SUM(input_tokens), 0) AS input_tokens,
|
|
79
|
+
COALESCE(SUM(output_tokens), 0) AS output_tokens,
|
|
80
|
+
COALESCE(SUM(cache_create_tokens), 0) AS cache_create_tokens,
|
|
81
|
+
COALESCE(SUM(cache_read_tokens), 0) AS cache_read_tokens,
|
|
82
|
+
COUNT(*) AS n
|
|
83
|
+
FROM message_usage
|
|
84
|
+
WHERE session_id = ?
|
|
85
|
+
GROUP BY model`)
|
|
86
|
+
.all(sessionId);
|
|
87
|
+
const byModel = aggregateByModel(perModel);
|
|
88
|
+
const input = s.total_input_tokens ?? 0;
|
|
89
|
+
const output = s.total_output_tokens ?? 0;
|
|
90
|
+
const cc = s.total_cache_create_tokens ?? 0;
|
|
91
|
+
const cr = s.total_cache_read_tokens ?? 0;
|
|
92
|
+
const cost = estimateCost({
|
|
93
|
+
inputTokens: input,
|
|
94
|
+
outputTokens: output,
|
|
95
|
+
cacheCreateTokens: cc,
|
|
96
|
+
cacheReadTokens: cr,
|
|
97
|
+
...buildByModelTotals(byModel),
|
|
98
|
+
}, s.primary_model);
|
|
99
|
+
return {
|
|
100
|
+
sessionId: s.id,
|
|
101
|
+
project: s.project,
|
|
102
|
+
startedAt: s.started_at,
|
|
103
|
+
endedAt: s.ended_at,
|
|
104
|
+
messageCount: s.message_count,
|
|
105
|
+
primaryModel: s.primary_model,
|
|
106
|
+
primaryModelLabel: priceFor(s.primary_model).label,
|
|
107
|
+
inputTokens: input,
|
|
108
|
+
outputTokens: output,
|
|
109
|
+
cacheCreateTokens: cc,
|
|
110
|
+
cacheReadTokens: cr,
|
|
111
|
+
totalTokens: cost.totalTokens,
|
|
112
|
+
cost,
|
|
113
|
+
byModel,
|
|
114
|
+
display: {
|
|
115
|
+
dollars: formatDollars(cost.cents),
|
|
116
|
+
tokens: formatTokens(cost.totalTokens),
|
|
117
|
+
model: priceFor(s.primary_model).label,
|
|
118
|
+
},
|
|
119
|
+
};
|
|
120
|
+
}
|
|
121
|
+
export function getProjectStats(projectName) {
|
|
122
|
+
const db = getDb();
|
|
123
|
+
const p = db
|
|
124
|
+
.prepare(`SELECT id, name FROM projects WHERE name = ?`)
|
|
125
|
+
.get(projectName);
|
|
126
|
+
if (!p)
|
|
127
|
+
return null;
|
|
128
|
+
const perModel = db
|
|
129
|
+
.prepare(`SELECT mu.model,
|
|
130
|
+
COALESCE(SUM(mu.input_tokens), 0) AS input_tokens,
|
|
131
|
+
COALESCE(SUM(mu.output_tokens), 0) AS output_tokens,
|
|
132
|
+
COALESCE(SUM(mu.cache_create_tokens), 0) AS cache_create_tokens,
|
|
133
|
+
COALESCE(SUM(mu.cache_read_tokens), 0) AS cache_read_tokens,
|
|
134
|
+
COUNT(*) AS n
|
|
135
|
+
FROM message_usage mu
|
|
136
|
+
JOIN sessions s ON s.id = mu.session_id
|
|
137
|
+
WHERE s.project_id = ?
|
|
138
|
+
GROUP BY mu.model`)
|
|
139
|
+
.all(p.id);
|
|
140
|
+
const byModel = aggregateByModel(perModel);
|
|
141
|
+
const totalsRow = db
|
|
142
|
+
.prepare(`SELECT COALESCE(SUM(total_input_tokens), 0) AS input_tokens,
|
|
143
|
+
COALESCE(SUM(total_output_tokens), 0) AS output_tokens,
|
|
144
|
+
COALESCE(SUM(total_cache_create_tokens), 0) AS cache_create_tokens,
|
|
145
|
+
COALESCE(SUM(total_cache_read_tokens), 0) AS cache_read_tokens,
|
|
146
|
+
COUNT(*) AS session_count
|
|
147
|
+
FROM sessions WHERE project_id = ?`)
|
|
148
|
+
.get(p.id);
|
|
149
|
+
const cost = estimateCost({
|
|
150
|
+
inputTokens: totalsRow.input_tokens,
|
|
151
|
+
outputTokens: totalsRow.output_tokens,
|
|
152
|
+
cacheCreateTokens: totalsRow.cache_create_tokens,
|
|
153
|
+
cacheReadTokens: totalsRow.cache_read_tokens,
|
|
154
|
+
...buildByModelTotals(byModel),
|
|
155
|
+
}, null);
|
|
156
|
+
const topRaw = db
|
|
157
|
+
.prepare(`SELECT s.id, sa.alias, s.started_at,
|
|
158
|
+
s.total_input_tokens, s.total_output_tokens,
|
|
159
|
+
s.total_cache_create_tokens, s.total_cache_read_tokens,
|
|
160
|
+
s.primary_model
|
|
161
|
+
FROM sessions s
|
|
162
|
+
LEFT JOIN session_aliases sa ON sa.session_id = s.id
|
|
163
|
+
WHERE s.project_id = ?
|
|
164
|
+
ORDER BY (COALESCE(s.total_input_tokens,0)
|
|
165
|
+
+ COALESCE(s.total_output_tokens,0)
|
|
166
|
+
+ COALESCE(s.total_cache_create_tokens,0)
|
|
167
|
+
+ COALESCE(s.total_cache_read_tokens,0)) DESC
|
|
168
|
+
LIMIT 10`)
|
|
169
|
+
.all(p.id);
|
|
170
|
+
const topSessions = topRaw.map((r) => {
|
|
171
|
+
const c = estimateCost({
|
|
172
|
+
inputTokens: r.total_input_tokens ?? 0,
|
|
173
|
+
outputTokens: r.total_output_tokens ?? 0,
|
|
174
|
+
cacheCreateTokens: r.total_cache_create_tokens ?? 0,
|
|
175
|
+
cacheReadTokens: r.total_cache_read_tokens ?? 0,
|
|
176
|
+
}, r.primary_model);
|
|
177
|
+
return {
|
|
178
|
+
sessionId: r.id,
|
|
179
|
+
alias: r.alias,
|
|
180
|
+
startedAt: r.started_at,
|
|
181
|
+
totalTokens: c.totalTokens,
|
|
182
|
+
cost: c,
|
|
183
|
+
};
|
|
184
|
+
});
|
|
185
|
+
return {
|
|
186
|
+
project: p.name,
|
|
187
|
+
sessionCount: totalsRow.session_count,
|
|
188
|
+
inputTokens: totalsRow.input_tokens,
|
|
189
|
+
outputTokens: totalsRow.output_tokens,
|
|
190
|
+
cacheCreateTokens: totalsRow.cache_create_tokens,
|
|
191
|
+
cacheReadTokens: totalsRow.cache_read_tokens,
|
|
192
|
+
totalTokens: cost.totalTokens,
|
|
193
|
+
cost,
|
|
194
|
+
byModel,
|
|
195
|
+
topSessions,
|
|
196
|
+
display: {
|
|
197
|
+
dollars: formatDollars(cost.cents),
|
|
198
|
+
tokens: formatTokens(cost.totalTokens),
|
|
199
|
+
},
|
|
200
|
+
};
|
|
201
|
+
}
|
|
202
|
+
export function getOverviewStats(range = 'all') {
|
|
203
|
+
const db = getDb();
|
|
204
|
+
const sinceIso = (() => {
|
|
205
|
+
if (range === '7d')
|
|
206
|
+
return new Date(Date.now() - 7 * 86400_000).toISOString();
|
|
207
|
+
if (range === '30d')
|
|
208
|
+
return new Date(Date.now() - 30 * 86400_000).toISOString();
|
|
209
|
+
return null;
|
|
210
|
+
})();
|
|
211
|
+
// Single methodology across every field: sum message_usage rows whose
|
|
212
|
+
// timestamp falls in the window. Backfilled rows (timestamp IS NULL) are
|
|
213
|
+
// attributed to the session's started_at — the best we have for them.
|
|
214
|
+
// For range='all' there is no filter, so this matches the session rollups
|
|
215
|
+
// exactly (message_usage is 1:1 with assistant messages on write).
|
|
216
|
+
const whereMu = sinceIso
|
|
217
|
+
? `WHERE mu.timestamp >= @since OR (mu.timestamp IS NULL AND s.started_at >= @since)`
|
|
218
|
+
: '';
|
|
219
|
+
const whereMsg = sinceIso
|
|
220
|
+
? `WHERE m.timestamp >= @since OR (m.timestamp IS NULL AND s2.started_at >= @since)`
|
|
221
|
+
: '';
|
|
222
|
+
const params = sinceIso ? { since: sinceIso } : {};
|
|
223
|
+
// better-sqlite3 rejects a params object when the statement has no bindings.
|
|
224
|
+
const getRow = (sql) => sinceIso ? db.prepare(sql).get(params) : db.prepare(sql).get();
|
|
225
|
+
const allRows = (sql) => (sinceIso ? db.prepare(sql).all(params) : db.prepare(sql).all());
|
|
226
|
+
// byModel — one row per model, summed over the window.
|
|
227
|
+
const perModel = allRows(`SELECT mu.model,
|
|
228
|
+
COALESCE(SUM(mu.input_tokens), 0) AS input_tokens,
|
|
229
|
+
COALESCE(SUM(mu.output_tokens), 0) AS output_tokens,
|
|
230
|
+
COALESCE(SUM(mu.cache_create_tokens), 0) AS cache_create_tokens,
|
|
231
|
+
COALESCE(SUM(mu.cache_read_tokens), 0) AS cache_read_tokens,
|
|
232
|
+
COUNT(*) AS n
|
|
233
|
+
FROM message_usage mu
|
|
234
|
+
JOIN sessions s ON s.id = mu.session_id
|
|
235
|
+
${whereMu}
|
|
236
|
+
GROUP BY mu.model`);
|
|
237
|
+
const byModel = aggregateByModel(perModel);
|
|
238
|
+
// Totals — sum across the same filtered message_usage set. Guarantees
|
|
239
|
+
// that input/output/cc/cr on the response match the sum of byModel[].
|
|
240
|
+
let inputTokens = 0;
|
|
241
|
+
let outputTokens = 0;
|
|
242
|
+
let cacheCreateTokens = 0;
|
|
243
|
+
let cacheReadTokens = 0;
|
|
244
|
+
for (const m of byModel) {
|
|
245
|
+
inputTokens += m.inputTokens;
|
|
246
|
+
outputTokens += m.outputTokens;
|
|
247
|
+
cacheCreateTokens += m.cacheCreateTokens;
|
|
248
|
+
cacheReadTokens += m.cacheReadTokens;
|
|
249
|
+
}
|
|
250
|
+
const cost = estimateCost({
|
|
251
|
+
inputTokens,
|
|
252
|
+
outputTokens,
|
|
253
|
+
cacheCreateTokens,
|
|
254
|
+
cacheReadTokens,
|
|
255
|
+
...buildByModelTotals(byModel),
|
|
256
|
+
}, null);
|
|
257
|
+
// Session counters — use the same window. `totalSessions` counts any
|
|
258
|
+
// session with at least one message in range; `sessionsWithUsage` counts
|
|
259
|
+
// sessions with a priced message_usage row in range. For range='all'
|
|
260
|
+
// both degenerate to the full sessions table (and rows with no activity
|
|
261
|
+
// at all will simply not appear — which is correct).
|
|
262
|
+
const sessionsCounts = sinceIso
|
|
263
|
+
? getRow(`SELECT
|
|
264
|
+
(SELECT COUNT(DISTINCT m.session_id)
|
|
265
|
+
FROM messages m
|
|
266
|
+
JOIN sessions s2 ON s2.id = m.session_id
|
|
267
|
+
${whereMsg}) AS total_sessions,
|
|
268
|
+
(SELECT COUNT(DISTINCT mu.session_id)
|
|
269
|
+
FROM message_usage mu
|
|
270
|
+
JOIN sessions s ON s.id = mu.session_id
|
|
271
|
+
${whereMu}) AS sessions_with_usage`)
|
|
272
|
+
: db
|
|
273
|
+
.prepare(`SELECT
|
|
274
|
+
(SELECT COUNT(*) FROM sessions) AS total_sessions,
|
|
275
|
+
(SELECT COUNT(*) FROM sessions
|
|
276
|
+
WHERE (COALESCE(total_input_tokens,0)
|
|
277
|
+
+COALESCE(total_output_tokens,0)
|
|
278
|
+
+COALESCE(total_cache_create_tokens,0)
|
|
279
|
+
+COALESCE(total_cache_read_tokens,0)) > 0) AS sessions_with_usage`)
|
|
280
|
+
.get();
|
|
281
|
+
// Daily bucketing in *local* time (the daemon and browser share a
|
|
282
|
+
// machine, so the user's local TZ is what they expect to see). The
|
|
283
|
+
// 'localtime' modifier shifts the UTC ISO timestamp into the daemon's
|
|
284
|
+
// configured TZ before slicing the YYYY-MM-DD prefix. Without this, a
|
|
285
|
+
// user in PT working at 6pm sees their evening activity bucketed into
|
|
286
|
+
// tomorrow's UTC bar — confusing and the source of "stats look stale"
|
|
287
|
+
// bug reports.
|
|
288
|
+
const dailyRows = allRows(`SELECT substr(datetime(COALESCE(mu.timestamp, s.started_at, ''), 'localtime'), 1, 10) AS day,
|
|
289
|
+
mu.model,
|
|
290
|
+
COALESCE(SUM(mu.input_tokens), 0) AS input_tokens,
|
|
291
|
+
COALESCE(SUM(mu.output_tokens), 0) AS output_tokens,
|
|
292
|
+
COALESCE(SUM(mu.cache_create_tokens), 0) AS cache_create_tokens,
|
|
293
|
+
COALESCE(SUM(mu.cache_read_tokens), 0) AS cache_read_tokens
|
|
294
|
+
FROM message_usage mu
|
|
295
|
+
JOIN sessions s ON s.id = mu.session_id
|
|
296
|
+
${whereMu}
|
|
297
|
+
GROUP BY day, mu.model
|
|
298
|
+
ORDER BY day ASC`);
|
|
299
|
+
const dailyMap = new Map();
|
|
300
|
+
for (const r of dailyRows) {
|
|
301
|
+
if (!r.day)
|
|
302
|
+
continue;
|
|
303
|
+
const c = estimateCost({
|
|
304
|
+
inputTokens: r.input_tokens,
|
|
305
|
+
outputTokens: r.output_tokens,
|
|
306
|
+
cacheCreateTokens: r.cache_create_tokens,
|
|
307
|
+
cacheReadTokens: r.cache_read_tokens,
|
|
308
|
+
}, r.model);
|
|
309
|
+
const prev = dailyMap.get(r.day) ?? { tokens: 0, cents: 0 };
|
|
310
|
+
prev.tokens += c.totalTokens;
|
|
311
|
+
prev.cents += c.cents;
|
|
312
|
+
dailyMap.set(r.day, prev);
|
|
313
|
+
}
|
|
314
|
+
const daily = [...dailyMap.entries()]
|
|
315
|
+
.map(([day, v]) => ({ day, tokens: v.tokens, cents: v.cents }))
|
|
316
|
+
.sort((a, b) => a.day.localeCompare(b.day));
|
|
317
|
+
// Top sessions — aggregate in-window usage per session so a long-running
|
|
318
|
+
// session whose started_at is outside the window can still appear if its
|
|
319
|
+
// recent activity makes the top 10.
|
|
320
|
+
const topRaw = allRows(`SELECT s.id, p.name AS project, sa.alias, s.started_at,
|
|
321
|
+
COALESCE(SUM(mu.input_tokens), 0) AS input_tokens,
|
|
322
|
+
COALESCE(SUM(mu.output_tokens), 0) AS output_tokens,
|
|
323
|
+
COALESCE(SUM(mu.cache_create_tokens), 0) AS cache_create_tokens,
|
|
324
|
+
COALESCE(SUM(mu.cache_read_tokens), 0) AS cache_read_tokens,
|
|
325
|
+
s.primary_model
|
|
326
|
+
FROM message_usage mu
|
|
327
|
+
JOIN sessions s ON s.id = mu.session_id
|
|
328
|
+
LEFT JOIN projects p ON p.id = s.project_id
|
|
329
|
+
LEFT JOIN session_aliases sa ON sa.session_id = s.id
|
|
330
|
+
${whereMu}
|
|
331
|
+
GROUP BY s.id
|
|
332
|
+
ORDER BY (COALESCE(SUM(mu.input_tokens),0)
|
|
333
|
+
+ COALESCE(SUM(mu.output_tokens),0)
|
|
334
|
+
+ COALESCE(SUM(mu.cache_create_tokens),0)
|
|
335
|
+
+ COALESCE(SUM(mu.cache_read_tokens),0)) DESC
|
|
336
|
+
LIMIT 10`);
|
|
337
|
+
const topSessions = topRaw.map((r) => {
|
|
338
|
+
const c = estimateCost({
|
|
339
|
+
inputTokens: r.input_tokens,
|
|
340
|
+
outputTokens: r.output_tokens,
|
|
341
|
+
cacheCreateTokens: r.cache_create_tokens,
|
|
342
|
+
cacheReadTokens: r.cache_read_tokens,
|
|
343
|
+
}, r.primary_model);
|
|
344
|
+
return {
|
|
345
|
+
sessionId: r.id,
|
|
346
|
+
project: r.project,
|
|
347
|
+
alias: r.alias,
|
|
348
|
+
startedAt: r.started_at,
|
|
349
|
+
totalTokens: c.totalTokens,
|
|
350
|
+
cost: c,
|
|
351
|
+
};
|
|
352
|
+
});
|
|
353
|
+
// Backfill coverage is a global invariant — not range-scoped — so it
|
|
354
|
+
// never shifts depending on the filter the user picked.
|
|
355
|
+
const coverage = db
|
|
356
|
+
.prepare(`SELECT
|
|
357
|
+
(SELECT COUNT(*) FROM messages WHERE role='assistant') AS assistant_messages,
|
|
358
|
+
(SELECT COUNT(*) FROM message_usage) AS messages_with_usage`)
|
|
359
|
+
.get();
|
|
360
|
+
return {
|
|
361
|
+
range,
|
|
362
|
+
totalSessions: sessionsCounts.total_sessions,
|
|
363
|
+
sessionsWithUsage: sessionsCounts.sessions_with_usage,
|
|
364
|
+
inputTokens,
|
|
365
|
+
outputTokens,
|
|
366
|
+
cacheCreateTokens,
|
|
367
|
+
cacheReadTokens,
|
|
368
|
+
totalTokens: cost.totalTokens,
|
|
369
|
+
cost,
|
|
370
|
+
daily,
|
|
371
|
+
byModel,
|
|
372
|
+
topSessions,
|
|
373
|
+
backfill: {
|
|
374
|
+
assistantMessages: coverage.assistant_messages,
|
|
375
|
+
messagesWithUsage: coverage.messages_with_usage,
|
|
376
|
+
pending: Math.max(0, coverage.assistant_messages - coverage.messages_with_usage),
|
|
377
|
+
unrecoverable: Math.min(getUnrecoverableCount(), Math.max(0, coverage.assistant_messages - coverage.messages_with_usage)),
|
|
378
|
+
},
|
|
379
|
+
display: {
|
|
380
|
+
dollars: formatDollars(cost.cents),
|
|
381
|
+
tokens: formatTokens(cost.totalTokens),
|
|
382
|
+
},
|
|
383
|
+
};
|
|
384
|
+
}
|
|
385
|
+
//# sourceMappingURL=query.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"query.js","sourceRoot":"","sources":["../../src/stats/query.ts"],"names":[],"mappings":"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"}
|