vitest's default glob reached the Electron app's specs under app/, which carry their own vitest config and their own jsdom in app/node_modules. From a root install that fails with ERR_MODULE_NOT_FOUND: jsdom, so the command CONTRIBUTING documents and the one RELEASING.md names as the pre-release gate both error out. Move the scoping CI already applies into package.json: test runs tests/ minus the parallelism-sensitive cache-refresh-lock suites, test:locks runs those three serially, test:watch keeps watch mode at the same scope. The first two are byte-identical to the invocations .github/workflows/tests.yml spells out, so the workflow can be pointed at the scripts to stop the two drifting apart again; that edit is left out of this PR so it needs no workflow permissions. test plus test:locks together still cover all 192 files under tests/. Scoping the script changes what a trailing path argument means: vitest ORs positional filters, so 'npm test -- tests/providers/hermes.test.ts' would no longer narrow to that file, it would run the whole suite. Rewrite those to 'npx vitest run <path>' everywhere they appear - four provider guides and the MCP design plan, thirteen lines in all. Also refresh the stale test docs: 42 files/568 tests (now 192 under tests/), the per-directory counts, the line claiming vitest does not run in CI which stopped being true when tests.yml landed, and the provider test-gap list, which still named antigravity and gemini after both gained test files. Record the cache-refresh-lock naming convention in CONTRIBUTING, since the split makes it load-bearing: a lock test that misses the prefix runs under the full worker pool and flakes, and one that matches it but is absent from test:locks never runs at all.
2.7 KiB
Hermes Agent
Hermes Agent CLI profiles.
- Source:
src/providers/hermes.ts - Loading: eager (
src/providers/index.ts) - Test:
tests/providers/hermes.test.ts
Where it reads from
| Source | Path |
|---|---|
| Default Hermes profile | $HERMES_HOME/state.db if set, otherwise ~/.hermes/state.db |
| Named Hermes profiles | $HERMES_HOME/profiles/<profile>/state.db |
Storage format
SQLite. The provider reads Hermes' aggregate sessions token/cost counters and the matching messages rows for user prompt and tool-call context.
Parser
Hermes stores durable token accounting at the session level, so CodeBurn emits one parsed call per Hermes session instead of one call per LLM API request. The call contains the aggregate session totals:
- input tokens
- output tokens
- cache-read tokens
- cache-write tokens
- reasoning tokens
- actual or estimated cost when Hermes recorded one
If Hermes recorded no positive cost, CodeBurn falls back to its normal model pricing table.
Project grouping
Discovery groups sessions by Hermes profile (default, coder, analytics, etc.). When a session message includes a clean Current working directory: /path line, parsing can attach that project path so CodeBurn can canonicalize worktrees. The parser deliberately ignores quoted or escaped prompt text that merely contains the phrase Current working directory:.
Tool mapping
Hermes tool_calls are normalized to CodeBurn display names where possible:
terminal->Bashread_file->Readwrite_file->Writepatch->Editsearch_files->Grep- browser tools ->
Browser - web tools ->
WebSearch/WebFetch - skill tools ->
Skill
Terminal command arguments are exposed as bashCommands for CodeBurn's command breakdowns.
Caching
The shared session cache fingerprints Hermes state DB files. HERMES_HOME is included in the provider environment fingerprint so changing the runtime home invalidates stale cached results.
Quirks
- The provider is aggregate-first because Hermes' stable accounting lives in
sessions. Do not infer per-turn usage from message text. - Source paths are encoded as
<dbPath>#hermes-session=<sessionId>so SQLite paths containing:remain safe. - SQLite schema checks are intentionally light: if the expected
sessionsormessagescolumns are absent, the DB is skipped.
When fixing a bug here
- Reproduce against a real Hermes
state.dbor a minimal SQLite fixture. - Run
npx vitest run tests/providers/hermes.test.ts. - For local smoke testing, use an isolated cache directory, for example:
CODEBURN_CACHE_DIR=/tmp/codeburn-hermes-cache node --import tsx -e "import { parseAllSessions } from './src/parser.ts'; console.log(await parseAllSessions(undefined, 'hermes'))".