fix: session-activity-tracker never records (CLAUDE_SESSION_ID unset)

session-activity-tracker.js is correctly registered in
posttooluse-dispatcher.js's SYNC_HOOKS and fires on every tool call --
but buildActivityRow() only ever read the session id from
ECC_SESSION_ID/CLAUDE_SESSION_ID environment variables, which Claude
Code does not actually set for hook subprocesses. Every row silently
came back null and nothing was ever written to
~/.claude/metrics/tool-usage.jsonl, with no error anywhere.

The session id is available in the hook's own stdin JSON payload
(input.session_id) in real invocations. This prefers that, keeping the
env vars as a fallback. New test added; all 18 existing + new tests
pass.

Also adds a live Activity view to the capabilities dashboard
(scripts/dashboard-web.js) reading that same metrics file, so Skill
vs. Agent vs. raw-tool usage is visible in real time instead of
requiring a manual tail+jq -- verified live against a real session
before this commit. Documents the loopback-only, no-auth design and
the standard SSH-port-forwarding pattern for viewing it from another
device you control.
This commit is contained in:
Clovis
2026-09-05 16:58:17 -07:00
parent ec74a88644
commit cfca5c8153
3 changed files with 38 additions and 1 deletions
+7 -1
View File
@@ -567,7 +567,13 @@ function buildActivityRow(input, env = process.env) {
}
const toolName = String(input?.tool_name || '').trim();
const sessionId = String(env.ECC_SESSION_ID || env.CLAUDE_SESSION_ID || '').trim();
// Claude Code does not set CLAUDE_SESSION_ID as an environment variable for
// hook subprocesses -- the session id is only available in the hook's own
// stdin JSON payload. Prefer that; keep the env vars as a fallback for any
// caller that does set them.
const sessionId = String(
input?.session_id || env.ECC_SESSION_ID || env.CLAUDE_SESSION_ID || ''
).trim();
if (!toolName || !sessionId) {
return null;
}