feat: analytics parity — tool cost, date ranges, budgets, query explorer, replay, snapshots (v2.4.0)

Analytics parity phases 2–7 (docs/plans/analytics-parity/), built on
138e706 and ported onto v2.3.1:
- Cost by AI tool (?tool= on cost/analytics/stats/workflows, by_tool,
  Codex fast/priority and flex tiers, agenthub_cost_usd_total{tool,model})
- Date ranges (from/to) on cost/analytics/workflows; Analytics range select
  with Today / This week (Monday) / This month (1st) / 7d / 30d / 90d / All /
  Custom; workflow filters carried into workflow-stats.js (read worker)
- Budgets and cost alerts as alert rule types (alert_rules rebuilt without
  its rule_type CHECK), GET /api/budgets/status, rule preview, spend pace,
  status-bar budget chip; rules stay editable in place
- Query Explorer (/query, allowlisted sort, CSV/JSON export) and scheduled
  reports (report_definitions/report_runs, Settings → Reports)
- Session Replay tab and immutable snapshots (session_snapshots, /snapshot/:token)
- Remote Codex sync, push ingest with a hashed token, privacy redaction and
  ignored folders (Settings → Data), Cursor sessions (no cost)
- Read-only MCP server, statusline, Grafana/Prometheus files

Also: resizable sidebar, pet run/wave animations, the workspace home keeps a
half-typed prompt, and the pre-commit hook runs only the related tests for a
small commit.
This commit is contained in:
2026-10-06 17:12:28 +07:00
parent 837da6e5de
commit 4aae61297f
146 changed files with 13565 additions and 537 deletions
+17
View File
@@ -84,6 +84,9 @@ const gitCredentialsRouter = require("./routes/git-credentials");
const aiToolsRouter = require("./routes/ai-tools");
const runRouter = require("./routes/run");
const alertsRouter = require("./routes/alerts");
const budgetsRouter = require("./routes/budgets");
const queryRouter = require("./routes/query");
const reportsRouter = require("./routes/reports");
const webhooksRouter = require("./routes/webhooks");
const remoteSourcesRouter = require("./routes/remote-sources");
const metricsRouter = require("./routes/metrics");
@@ -92,6 +95,7 @@ const projectsRouter = require("./routes/projects");
const laneSourcesRouter = require("./routes/lane-sources");
const locksRouter = require("./routes/locks");
const petsRouter = require("./routes/pets");
const snapshotsRouter = require("./routes/snapshots");
const APP_VERSION = (() => {
try {
@@ -140,7 +144,11 @@ function createApp() {
app.use("/api/projects", projectsRouter);
app.use("/api/locks", locksRouter);
app.use("/api/pets", petsRouter);
app.use("/api/snapshots", snapshotsRouter);
app.use("/api/alerts", alertsRouter);
app.use("/api/budgets", budgetsRouter);
app.use("/api/query", queryRouter);
app.use("/api/reports", reportsRouter);
app.use("/api/webhooks", webhooksRouter);
app.use("/api/remote-sources", remoteSourcesRouter);
app.use("/api/metrics", metricsRouter);
@@ -361,6 +369,9 @@ function startBackgroundServices() {
}
}
// Scheduled reports (Settings → Reports). Off with DASHBOARD_REPORTS_MS=0.
require("./lib/reports").startReportScheduler();
// Rates for models seen in token_usage with no pricing row of their own.
require("./lib/pricing-sync").startPricingSync(require("./db").db);
// The AI Tools catalog of the newest release, when it is newer than this build.
@@ -578,6 +589,12 @@ function startBackgroundServices() {
} catch (err) {
console.warn("antigravity usage poll failed to start:", err.message);
}
// Cursor sessions (no tokens: its transcripts carry none), from its agent transcripts.
try {
require("./lib/cursor-usage").startCursorUsagePoll(broadcast);
} catch (err) {
console.warn("cursor usage poll failed to start:", err.message);
}
// Codex/Antigravity hooks the user installed forward through a script whose
// content names this build; point it here (the command in the tool's
// hooks.json, which Codex trusts, stays the same).