Skip to content

Commit 8140482

Browse files
pepperonasclaude
andcommitted
fix(test): boot API tests on a throwaway DB + 41 new tests + auto badges
The CI failure (`POST /api/achievements/recompute` -> expected 0 to be greater than 0) was an environment leak: the API tests started the server against the REAL data/tracker.db and ~/.claude. On a dev machine that happened to pass; in CI, with neither, the aggregator was empty. It also made the suite take 33s and let the recompute test rewrite the developer's own achievements table. DATA_DIR/DB_PATH are env-overridable now. The API tests boot on a temp DB with an empty CLAUDE_DIR and seed a deterministic 45-day history (test/fixtures/history.js). Suite: 33s -> 0.6s, and reproducible. 41 new tests (255 -> 296), all asserting behaviour rather than shapes: - parser: rate-limit events + stable ids, /subagents/ detection, line counting from Edit/Write input, incremental offsets - db: device CRUD & key regeneration, device deletion orphans messages, duplicate rate-limit events, project shares incl. expiry - aggregator: previous-month clamping (Mar 31 -> Feb 28), Monday week start, future-dated messages, empty payload, momentum filtering, 90 gapless local days - achievements: backfill determinism, atomic replace preference, no-op on empty history, tier-scaled sample gates (4d/10d/31d boundaries) - api: real numbers against the seeded history, MCP typing/grouping, sub-agent share, public pricing endpoint, 404 for unknown routes - config: DATA_DIR/DB_PATH resolution Badges: test count and LOC are generated by scripts/update-badges.js from the vitest JSON report and git ls-files, shown prominently at the top of all three READMEs, and refreshed on every push to main by .github/workflows/badges.yml. The hand-maintained numbers had drifted (badge said 238 tests, suite had 255; "LOC 25k+" was a guess). Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
1 parent a8e80c3 commit 8140482

17 files changed

Lines changed: 864 additions & 19 deletions

.github/workflows/badges.yml

Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
name: Badges
2+
3+
# Keeps the test-count and lines-of-code badges in the READMEs honest: they are
4+
# recomputed from the actual suite + tracked sources on every push to main and
5+
# committed back. Hand-maintained numbers always drifted (the badge claimed 238
6+
# tests while the suite had 255).
7+
on:
8+
push:
9+
branches: [main]
10+
11+
permissions:
12+
contents: write
13+
14+
concurrency:
15+
group: badges-${{ github.ref }}
16+
cancel-in-progress: true
17+
18+
jobs:
19+
update:
20+
runs-on: ubuntu-latest
21+
steps:
22+
- uses: actions/checkout@v4
23+
- uses: actions/setup-node@v4
24+
with:
25+
node-version: 20
26+
cache: npm
27+
- run: npm ci
28+
- name: Run the suite with a JSON report
29+
run: npx vitest run --reporter=json --outputFile=.vitest-report.json
30+
- name: Recompute badges
31+
run: node scripts/update-badges.js --report .vitest-report.json
32+
- name: Commit if the numbers moved
33+
run: |
34+
rm -f .vitest-report.json
35+
if [ -z "$(git status --porcelain README.md README_EN.md README_DE.md)" ]; then
36+
echo "Badges already up to date."
37+
exit 0
38+
fi
39+
git config user.name 'github-actions[bot]'
40+
git config user.email '41898282+github-actions[bot]@users.noreply.github.com'
41+
git add README.md README_EN.md README_DE.md
42+
git commit -m 'chore: refresh test/LOC badges [skip ci]'
43+
git push

.gitignore

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,3 +18,6 @@ sync-agent/node_modules/
1818
# Runtime logs (LaunchAgent/PM2)
1919
stdout.log
2020
stderr.log
21+
22+
# Vitest JSON report (badge automation)
23+
.vitest-report.json

CHANGELOG.md

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,20 @@
11
# Changelog
22

3+
## [Unreleased] - 2026-07-22 (Tests & Badges)
4+
5+
### Fixed
6+
- **CI-Fehlschlag `POST /api/achievements/recompute` (`expected 0 to be greater than 0`)** — die API-Tests starteten den Server gegen die **echte** `data/tracker.db` und das echte `~/.claude`. Lokal lief das (zufällig) durch, in CI gibt es beides nicht → 0 Nachrichten → 0 Achievements. Nebenwirkungen: die Suite brauchte ~33 s und der Recompute-Test **überschrieb die reale Achievements-Tabelle des Entwicklers**. `DATA_DIR`/`DB_PATH` sind jetzt per Env überschreibbar; die API-Tests booten gegen eine Wegwerf-DB in `mkdtemp()` mit leerem `CLAUDE_DIR` und seeden vorher eine deterministische 45-Tage-History (`test/fixtures/history.js`). **Suite: 33 s → 0,6 s**, und sie ist reproduzierbar statt vom Rechner abhängig
7+
8+
### Added
9+
- **41 neue Tests (255 → 296)**, überall dort, wo bisher nur die Response-*Form* geprüft wurde:
10+
- **Parser**: Rate-Limit-Events (inkl. stabiler, aus Session+Timestamp abgeleiteter ID → Re-Parse dupliziert nicht), Sub-Agent-Erkennung über den `/subagents/`-Pfad, Zeilenzählung aus `Edit`/`Write`-Tool-Input, Offset-Fortschreibung beim inkrementellen Parsen
11+
- **DB**: Geräte-CRUD (eindeutige API-Keys, Key-Regenerierung invalidiert den alten Key, Löschen eines Geräts **verwaist** die Nachrichten statt sie zu löschen), Rate-Limit-Events (Duplikate werden ignoriert, leerer Batch), Projekt-Shares (48-stelliges Token, abgelaufene Shares sind öffentlich unsichtbar, bleiben aber verwaltbar, Löschen)
12+
- **Aggregator**: Vormonats-Cutoff-Clamping (31.03. → 28.02.), Montag als Wochenstart (Sonntag zählt zur abgelaufenen Woche), Zukunftsdaten werden ignoriert, leerer Aggregator liefert ein Null-Payload, Momentum-Einträge ohne Volumen fallen raus, `daily90` sind 90 lückenlose aufeinanderfolgende Lokaltage
13+
- **Achievements**: Backfill ist deterministisch (zwei Läufe = identische Daten), nutzt die atomare `replaceAchievementsForUser`-API wenn vorhanden, macht bei leerer History nichts (löscht insbesondere nichts) und die **Sample-Gates greifen stufenweise** (4 aktive Tage: kein Gold; 10: Gold, aber kein Platin/Diamant; 31: alle)
14+
- **API**: echte Zahlen statt Formen — Overview zählt die geseedeten 270 Nachrichten/90 Sessions/45 aktiven Tage, `/api/daily` deckt alle 45 Tage ab und summiert sich zum Overview, `daily90` endet auf heute, Heatmap-Summe == Overview, Tool-Kosten-Attribution inkl. MCP-Typisierung, MCP-Server-Gruppierung, Sub-Agent-Anteil, öffentliches `/api/pricing`, Zeitraumfilter verengt das Ergebnis, unbekannte `/api/*`-Routen liefern 404
15+
- **Config**: `DATA_DIR`/`DB_PATH`-Auflösung inkl. relativer Pfade
16+
- **Automatisch aktualisierte Badges** ganz oben in allen drei READMEs: **Tests** (aus dem echten Vitest-JSON-Report, nicht geschätzt) und **Lines of Code** (aus `git ls-files` über `*.js`/`*.css`/`*.html`). `scripts/update-badges.js` schreibt den Block zwischen `<!-- BADGES:START/END -->`, `npm run badges` lokal, und der neue Workflow `.github/workflows/badges.yml` rechnet sie bei **jedem Push auf main** neu und committet sie zurück (`[skip ci]`). Die handgepflegten Zahlen waren chronisch veraltet (Badge: 238 Tests, Suite: 255; „LOC 25k+" geraten statt gemessen)
17+
318
## [Unreleased] - 2026-07-22
419

520
### Added

CLAUDE.md

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ npm run test:watch # Tests in watch mode
1111
npm run test:coverage # Coverage report
1212
npm run lint # ESLint (lib/ + server.js only)
1313
npx vitest run test/parser.test.js # Run a single test file
14+
npm run badges # Recompute the test/LOC badges in all READMEs
1415
bash scripts/deploy.sh # Deploy to VPS (tracker.celox.io)
1516
```
1617

@@ -168,5 +169,6 @@ VPS deployment to tracker.celox.io:
168169
- **Costs**: Rounded to 2 decimals
169170
- **Unused variables**: Prefix with `_` (ESLint configured for this)
170171
- **German text**: Use proper umlauts (ü, ö, ä, ß), never ASCII substitutes (ue, oe, ae, ss)
171-
- **Tests**: Use vitest globals (no imports needed), temp dirs via `fs.mkdtempSync()`, API tests spawn server on random port. Multi-user tests set `MULTI_USER=true` in env and clear require cache. Modules whose config is read at require time (`config.js`, and anything reading `SESSION_SECRET`/`MULTI_USER` such as `anthropic-api.js`) are tested by setting `process.env` **before** a fresh `require`, with `delete require.cache[require.resolve(...)]` and env restored in `afterEach`. Coverage by file: `parser`, `aggregator` (+ `aggregator-cache`), `db`, `auth`, `pricing` (+ `pricing-fetcher`), `achievements`, `backup`, `sync`, `api`, `multi-user-api`, plus `export-html` (pure HTML/escaping/optional-tab rendering), `anthropic-api` (AES-256-GCM `encryptKey`/`decryptKey` round-trip + auth-tag tamper detection + admin-key storage/env-fallback resolution), and `config` (env defaults/overrides, `BASE_URL` and `CLAUDE_DIR`/`PROJECTS_DIR` derivation).
172+
- **Tests**: Use vitest globals (no imports needed), temp dirs via `fs.mkdtempSync()`. **Nothing may touch the real environment**: the API tests boot the server against a throwaway DB by setting `DB_PATH` + `CLAUDE_DIR` (both env-resolved in `config.js`) **before** requiring `lib/config`/`lib/db`/`lib/aggregator`/`server`, and seed it via `test/fixtures/history.js` (`buildHistory({days, perDay})` — a deterministic, index-derived multi-day history across 3 projects / 3 models / MCP + sub-agent messages). They previously booted on `data/tracker.db` and `~/.claude`, which made the suite 33 s long, machine-dependent (CI, with no data, failed on the achievements test) and let `POST /api/achievements/recompute` rewrite the developer's real achievements. Multi-user tests set `MULTI_USER=true` in env and clear the require cache. Modules whose config is read at require time (`config.js`, and anything reading `SESSION_SECRET`/`MULTI_USER` such as `anthropic-api.js`) are tested by setting `process.env` **before** a fresh `require`, with `delete require.cache[require.resolve(...)]` and env restored in `afterEach`. Prefer asserting **numbers over shapes** — `expect(body.messages).toBe(45 * 6)` catches an aggregation regression, `expect(Array.isArray(body))` does not. Coverage by file: `parser` (incl. rate-limit events, sub-agent path detection, line counting, offsets), `aggregator` (+ `aggregator-cache`, incl. calendar edge cases: previous-month clamping, Monday week start, future-dated messages, empty payloads), `db` (incl. devices, rate-limit events, project shares), `auth`, `pricing` (+ `pricing-fetcher`), `achievements` (incl. backfill determinism, atomic replace, tier-scaled sample gates), `backup`, `sync`, `api`, `multi-user-api`, plus `export-html` (pure HTML/escaping/optional-tab rendering), `anthropic-api` (AES-256-GCM `encryptKey`/`decryptKey` round-trip + auth-tag tamper detection + admin-key storage/env-fallback resolution), and `config` (env defaults/overrides, `BASE_URL`, `CLAUDE_DIR`/`PROJECTS_DIR` and `DATA_DIR`/`DB_PATH` derivation).
173+
- **README badges**: the test-count and LOC badges at the top of `README.md`/`README_EN.md`/`README_DE.md` are **generated**, never hand-edited — `scripts/update-badges.js` rewrites the block between `<!-- BADGES:START -->` / `<!-- BADGES:END -->` from the real vitest JSON report and `git ls-files`. `.github/workflows/badges.yml` runs it on every push to `main` and commits the result (`[skip ci]`); `npm run badges` does the same locally. Editing the numbers by hand just gets overwritten on the next push.
172174
- **ESLint**: Flat config (ESLint 9), only covers `lib/` and `server.js`

README.md

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,13 @@
88
Real-time dashboard for Claude Code token usage, API-equivalent cost estimation, and coding activity tracking.
99
</p>
1010

11+
<!-- BADGES:START -->
12+
<p align="center">
13+
<img src="https://img.shields.io/badge/tests-296_passing-3fb950?style=for-the-badge&logo=vitest&logoColor=white" alt="296 tests passing">
14+
<img src="https://img.shields.io/badge/code-31.8k_lines-58a6ff?style=for-the-badge&logo=javascript&logoColor=white" alt="31775 lines of code across 45 files">
15+
</p>
16+
<!-- BADGES:END -->
17+
1118
<p align="center">
1219
<a href="https://github.com/pepperonas/claude-token-tracker/actions/workflows/ci.yml"><img src="https://github.com/pepperonas/claude-token-tracker/actions/workflows/ci.yml/badge.svg" alt="CI"></a>
1320
<a href="LICENSE"><img src="https://img.shields.io/badge/License-MIT-blue.svg" alt="License: MIT"></a>
@@ -20,7 +27,6 @@
2027
<img src="https://img.shields.io/badge/Node.js-%3E%3D20.12-339933?logo=node.js&logoColor=white" alt="Node.js >= 20.12">
2128
<img src="https://img.shields.io/badge/SQLite-WAL_Mode-003B57?logo=sqlite&logoColor=white" alt="SQLite WAL">
2229
<img src="https://img.shields.io/badge/Chart.js-4.x-FF6384?logo=chartdotjs&logoColor=white" alt="Chart.js">
23-
<img src="https://img.shields.io/badge/Vitest-255_tests-6E9F18?logo=vitest&logoColor=white" alt="Tests">
2430
<img src="https://img.shields.io/badge/ESLint-9.x-4B32C3?logo=eslint&logoColor=white" alt="ESLint">
2531
</p>
2632

@@ -37,7 +43,6 @@
3743
<img src="https://img.shields.io/badge/deps-2_runtime-success" alt="Dependencies">
3844
<img src="https://img.shields.io/badge/no_framework-vanilla_JS-yellow" alt="No Framework">
3945
<img src="https://img.shields.io/badge/API-50+_endpoints-blue" alt="API Endpoints">
40-
<img src="https://img.shields.io/badge/LOC-25k+-informational" alt="Lines of Code">
4146
</p>
4247

4348
<p align="center">
@@ -152,7 +157,7 @@ Open [http://localhost:5010](http://localhost:5010)
152157
- **Token breakdown** — Input, Output, Cache Read, Cache Create with per-type API-equivalent cost estimation
153158
- **Share API** — secure external API for sharing project-specific token usage data with clients. Share tokens (48-char hex, 192-bit entropy) expose sanitized project data (tokens, cost, sessions, code lines, daily breakdown) via public endpoints. Admin key authentication for share management, rate limiting (30 req/min/IP), CORS restrictions, and optional expiry. Used by [OPS](https://github.com/pepperonas/celox-ops) for customer transparency dashboards. Settings UI shows Share Admin Key with copy button.
154159
- **Database download** — download the full SQLite database from Settings for local backup or analysis
155-
- **255 automated tests** — unit, integration, and multi-user API tests
160+
- **296 automated tests** — unit, integration, and multi-user API tests
156161
- **Zero-framework frontend** — vanilla JS, 2 runtime dependencies, no build step
157162

158163
## Screenshots

README_DE.md

Lines changed: 9 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,13 @@
22
<a href="README_EN.md"><img src="https://img.shields.io/badge/%F0%9F%87%AC%F0%9F%87%A7_English-Switch_Language-blue?style=for-the-badge" alt="Switch to English"></a>
33
</p>
44

5+
<!-- BADGES:START -->
6+
<p align="center">
7+
<img src="https://img.shields.io/badge/tests-296_passing-3fb950?style=for-the-badge&logo=vitest&logoColor=white" alt="296 tests passing">
8+
<img src="https://img.shields.io/badge/code-31.8k_lines-58a6ff?style=for-the-badge&logo=javascript&logoColor=white" alt="31775 lines of code across 45 files">
9+
</p>
10+
<!-- BADGES:END -->
11+
512
<p align="center">
613
<a href="https://github.com/pepperonas/claude-token-tracker/actions/workflows/ci.yml"><img src="https://github.com/pepperonas/claude-token-tracker/actions/workflows/ci.yml/badge.svg" alt="CI"></a>
714
<a href="LICENSE"><img src="https://img.shields.io/badge/Lizenz-MIT-blue.svg" alt="Lizenz: MIT"></a>
@@ -14,7 +21,6 @@
1421
<img src="https://img.shields.io/badge/Node.js-%3E%3D20.12-339933?logo=node.js&logoColor=white" alt="Node.js >= 20.12">
1522
<img src="https://img.shields.io/badge/SQLite-WAL--Modus-003B57?logo=sqlite&logoColor=white" alt="SQLite WAL">
1623
<img src="https://img.shields.io/badge/Chart.js-4.x-FF6384?logo=chartdotjs&logoColor=white" alt="Chart.js">
17-
<img src="https://img.shields.io/badge/Vitest-255_Tests-6E9F18?logo=vitest&logoColor=white" alt="Tests">
1824
<img src="https://img.shields.io/badge/ESLint-9.x-4B32C3?logo=eslint&logoColor=white" alt="ESLint">
1925
</p>
2026

@@ -31,7 +37,6 @@
3137
<img src="https://img.shields.io/badge/Deps-2_Runtime-success" alt="Abhängigkeiten">
3238
<img src="https://img.shields.io/badge/kein_Framework-Vanilla_JS-yellow" alt="Kein Framework">
3339
<img src="https://img.shields.io/badge/API-50+_Endpunkte-blue" alt="API Endpunkte">
34-
<img src="https://img.shields.io/badge/LOC-25k+-informational" alt="Codezeilen">
3540
</p>
3641

3742
<p align="center">
@@ -192,7 +197,7 @@ Dashboard zur Analyse deiner Claude Code Token-Nutzung. Liest die JSONL-Sitzungs
192197
- **Perioden-Vergleich** — immer sichtbare Pill-Leiste (Aus / Vorperiode / Letzte 7T / 30T / 90T / Eigener) vergleicht zwei Zeiträume sofort nebeneinander mit 8 Metriken (Tokens/Min, Zeilen/Stunde, Kosten/Zeile, Tokens/Zeile, Zeilen/Nachricht, Tools/Nachricht, I/O-Verhältnis, Coding-Stunden), Delta-Prozenten und farbcodierten Verbesserungs-/Verschlechterungsanzeigen — ein Klick genügt, kein separater Toggle nötig
193198
- **HTML-Export** — mobil-optimierter interaktiver Snapshot mit Chart.js, 8 Tabs (Übersicht, Charts, Sitzungen, Projekte, Modelle, Tools, Produktivität, Achievements), 12+ Charts und sortierbaren Tabellen. Optimiert für Smartphones (412px+) mit adaptiven Layouts, Touch-freundlichen Tabs und responsiven Chart-Darstellungen
194199
- **Globaler Vergleich** — eigene Statistiken gegen den Durchschnitt aller Nutzer vergleichen (Multi-User-Modus)
195-
- **255 automatisierte Tests** (Unit + Integration + Multi-User API + Achievements)
200+
- **296 automatisierte Tests** (Unit + Integration + Multi-User API + Achievements)
196201

197202
## Mobile Screenshots (iPhone 16 — 393px)
198203

@@ -457,7 +462,7 @@ Alle GET-Endpunkte unterstützen `?from=YYYY-MM-DD&to=YYYY-MM-DD` Query-Paramete
457462
## Entwicklung
458463

459464
```bash
460-
npm test # Alle 255 Tests ausführen (vitest)
465+
npm test # Alle 296 Tests ausführen (vitest)
461466
npm run test:watch # Tests im Watch-Modus
462467
npm run test:coverage # Coverage-Report
463468
npm run lint # ESLint (lib/ + server.js)

README_EN.md

Lines changed: 9 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,13 @@
22
<a href="README_DE.md"><img src="https://img.shields.io/badge/%F0%9F%87%A9%F0%9F%87%AA_Deutsch-Sprache_wechseln-blue?style=for-the-badge" alt="Auf Deutsch wechseln"></a>
33
</p>
44

5+
<!-- BADGES:START -->
6+
<p align="center">
7+
<img src="https://img.shields.io/badge/tests-296_passing-3fb950?style=for-the-badge&logo=vitest&logoColor=white" alt="296 tests passing">
8+
<img src="https://img.shields.io/badge/code-31.8k_lines-58a6ff?style=for-the-badge&logo=javascript&logoColor=white" alt="31775 lines of code across 45 files">
9+
</p>
10+
<!-- BADGES:END -->
11+
512
<p align="center">
613
<a href="https://github.com/pepperonas/claude-token-tracker/actions/workflows/ci.yml"><img src="https://github.com/pepperonas/claude-token-tracker/actions/workflows/ci.yml/badge.svg" alt="CI"></a>
714
<a href="LICENSE"><img src="https://img.shields.io/badge/License-MIT-blue.svg" alt="License: MIT"></a>
@@ -14,7 +21,6 @@
1421
<img src="https://img.shields.io/badge/Node.js-%3E%3D20.12-339933?logo=node.js&logoColor=white" alt="Node.js >= 20.12">
1522
<img src="https://img.shields.io/badge/SQLite-WAL_Mode-003B57?logo=sqlite&logoColor=white" alt="SQLite WAL">
1623
<img src="https://img.shields.io/badge/Chart.js-4.x-FF6384?logo=chartdotjs&logoColor=white" alt="Chart.js">
17-
<img src="https://img.shields.io/badge/Vitest-255_tests-6E9F18?logo=vitest&logoColor=white" alt="Tests">
1824
<img src="https://img.shields.io/badge/ESLint-9.x-4B32C3?logo=eslint&logoColor=white" alt="ESLint">
1925
</p>
2026

@@ -31,7 +37,6 @@
3137
<img src="https://img.shields.io/badge/deps-2_runtime-success" alt="Dependencies">
3238
<img src="https://img.shields.io/badge/no_framework-vanilla_JS-yellow" alt="No Framework">
3339
<img src="https://img.shields.io/badge/API-50+_endpoints-blue" alt="API Endpoints">
34-
<img src="https://img.shields.io/badge/LOC-25k+-informational" alt="Lines of Code">
3540
</p>
3641

3742
<p align="center">
@@ -192,7 +197,7 @@ Dashboard for analyzing your Claude Code token usage. Reads Claude Code's JSONL
192197
- **Period comparison** — always-visible inline pill selector (Off / Prev. Period / Last 7d / 30d / 90d / Custom) instantly compares two periods side-by-side with 8 metrics (Tokens/Min, Lines/Hour, Cost/Line, Tokens/Line, Lines/Turn, Tools/Turn, I/O Ratio, Coding Hours), delta percentages, and color-coded improvement/regression indicators — one click to activate, no toggle needed
193198
- **HTML export** — mobile-responsive interactive snapshot with Chart.js, 8 tabs (Overview, Charts, Sessions, Projects, Models, Tools, Productivity, Achievements), 12+ charts, and sortable tables. Optimized for phones (412px+) with adaptive layouts, touch-friendly tabs, and responsive chart rendering
194199
- **Global comparison** — compare your stats against the average of all users (multi-user mode)
195-
- **255 automated tests** (unit + integration + multi-user API + achievements)
200+
- **296 automated tests** (unit + integration + multi-user API + achievements)
196201

197202
## Mobile Screenshots (iPhone 16 — 393px)
198203

@@ -457,7 +462,7 @@ All GET endpoints support `?from=YYYY-MM-DD&to=YYYY-MM-DD` query parameters. Ana
457462
## Development
458463

459464
```bash
460-
npm test # Run all 255 tests (vitest)
465+
npm test # Run all 296 tests (vitest)
461466
npm run test:watch # Watch mode
462467
npm run test:coverage # Coverage report
463468
npm run lint # ESLint (lib/ + server.js)

lib/config.js

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,9 +7,17 @@ const CLAUDE_DIR = process.env.CLAUDE_DIR
77
: path.join(HOME, '.claude');
88

99
const PROJECTS_DIR = path.join(CLAUDE_DIR, 'projects');
10-
const DATA_DIR = path.join(__dirname, '..', 'data');
10+
// DATA_DIR/DB_PATH are env-overridable so tests (and any second instance) can
11+
// run against a throwaway database instead of the developer's real one — the
12+
// API tests used to boot the server on `data/tracker.db` and rewrite its
13+
// achievements table.
14+
const DATA_DIR = process.env.DATA_DIR
15+
? path.resolve(process.env.DATA_DIR)
16+
: path.join(__dirname, '..', 'data');
1117
const PORT = parseInt(process.env.PORT, 10) || 5010;
12-
const DB_PATH = path.join(DATA_DIR, 'tracker.db');
18+
const DB_PATH = process.env.DB_PATH
19+
? path.resolve(process.env.DB_PATH)
20+
: path.join(DATA_DIR, 'tracker.db');
1321
const BACKUP_PATH = process.env.BACKUP_PATH || '';
1422
const BACKUP_INTERVAL_HOURS = parseInt(process.env.BACKUP_INTERVAL_HOURS, 10) || 6;
1523
const STATS_CACHE_FILE = path.join(CLAUDE_DIR, 'stats-cache.json');

package.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@
99
"test:watch": "vitest",
1010
"test:coverage": "vitest run --coverage",
1111
"lint": "eslint lib/ server.js",
12+
"badges": "vitest run --reporter=json --outputFile=.vitest-report.json && node scripts/update-badges.js --report .vitest-report.json && rm -f .vitest-report.json",
1213
"postinstall": "node scripts/setup.js"
1314
},
1415
"author": "Martin Pfeffer",

0 commit comments

Comments
 (0)