feat: replace JSONL file-tailing with hooks + OTEL observability#40
Open
SDS-Mode wants to merge 14 commits into
Open
feat: replace JSONL file-tailing with hooks + OTEL observability#40SDS-Mode wants to merge 14 commits into
SDS-Mode wants to merge 14 commits into
Conversation
Introduces the SessionContextMessage interface and SessionContextSchema for the new server→bridge message that delivers transcript path from a SessionStart hook, replacing heuristic discovery in the bridge. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
…ntext replay Add two public helpers on WebSocketHub (sendToBridge, broadcastToSession) and replay a stored transcriptPath as a session-context message when a bridge registers so the bridge can start its transcript watcher immediately even if hook ingress delivered the path before the bridge connected. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Implements POST /hook handler via createHookIngress factory with dependency injection, routing SessionStart/PostToolUse/PostToolUseFailure/Stop events to the appropriate bridge/watcher calls. Includes 19 tests covering auth, validation, all event routes, and graceful unknown-event handling. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Adds POST /otlp/v1/metrics and /otlp/v1/logs handlers that parse Claude Code's native OpenTelemetry JSON export, extract claude_code.token.usage data points, and broadcast usage-update messages to watching browsers without requiring auth. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Hook fires before bridge registers, so setTranscriptPath was a no-op when the session didn't exist yet. Add pendingPaths map to survive across registry.add() which creates a fresh Session object. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Add optional routes map to createHttpHandler so API routes take precedence over static file serving, then wire /hook, /otlp/v1/metrics, and /otlp/v1/logs into server/index.ts via createHookIngress and createOtelIngress. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Adds hooks.json declaring SessionStart, PostToolUse, PostToolUseFailure, and Stop hook events, each invoking hook-relay.ts. The relay script reads the hook payload from stdin, discovers the running server via state.json, and POSTs the payload to /hook — exiting silently if the server is unreachable so hooks never block Claude Code. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Replace the ~470 LOC transcript-watcher with an ~120 LOC version that
takes a mandatory file path (no discovery), tails JSONL incrementally,
and emits only user/assistant text entries. Tool-use, tool-result, and
usage extraction are all removed — those now come from hooks and OTEL.
Deleted: discoverTranscriptByBirthtime, discoverTranscriptPath,
readSubagentEntries, rediscover, UsageData, onUsage, onFileSwitch, and
all cwd/birthtime/subagent state. Added { persistent: false } to
fs.watch to fix bridge-fswatch-persistent (blocked MCP stdio shutdown).
bridge/index.ts updated to the new 2-arg constructor and receives the
transcript path via session-context message instead of discovery.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Adds three integration test scenarios verifying end-to-end flows through the running server: SessionStart delivers session-context to bridge, PostToolUse broadcasts transcript-entry to watching browser, and OTLP metrics broadcast usage-update to watching browser. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
…status schema mismatch - Delete resolveProjectDir() and /proc dependency - Replace startTranscriptWatcher with startWatcherForPath (called on session-context) - Remove transcript-status messages that Zod rejects (available:bool vs status:enum) - ws.onopen no longer starts watcher — waits for session-context from server - Add hooks reference to plugin.json so Claude Code discovers hook manifest Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
transcript-watcher.tsreduced from ~470 LOC to ~140 LOC — all discovery heuristics (birthtime correlation,/procPID lookup, cwd encoding, newest-JSONL guessing) deletedPOST /hookfor Claude Code hook events,POST /otlp/v1/*for OTEL telemetry ingestionhooks/hooks.json) — auto-registered on install, zero user configscripts/setup.tsextended to write OTEL env vars to.claude/settings.local.jsonArchitecture
Hook events provide the authoritative transcript path (via
session-contextWS message) and tool calls. OTEL provides token usage/cost. JSONL is retained only for assistant prose text.Resolved issues
bridge-proc-linux-only— code deletedbridge-birthtime-unreliable-fs— code deletedbridge-duplicate-chunk-logic— code deletedbridge-fswatch-persistent— fixed (persistent: false)bridge-reconnect-transcriptwatcher-restart— fixed by design (bridge waits forsession-contextinstead of replaying from offset 0)Test plan
persistent: false/clearpicks up new session🤖 Generated with Claude Code