claude-discover 1.10.9 → 1.10.11

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -6,7 +6,12 @@ Ever wondered what Claude Code is **actually** doing all day?
6
6
  <img width="1660" alt="claude-discover-dimmed-screenshot" src="https://github.com/user-attachments/assets/708d05c7-8769-47d8-b5bd-14337d1d6037" />
7
7
  <br><br>
8
8
 
9
- **Claude Discover** is a desktop tool that shows you what **Claude Code** is actually doing. It collects all your sessions (from the CLI, Desktop, or SDK) and puts them on one timeline, where you can read every conversation, peek at the system prompts, memories, and tools, inspect the raw API traffic behind it all, and see exactly where your tokens - and your money - went. (Spoiler: mostly on re-sending tool definitions.)
9
+ **Claude Discover** is a desktop app for exploring your local Claude Code data. Every session - from the CLI, Desktop, or SDK - lands on one timeline, where you can:
10
+
11
+ - read each conversation, with every tool call the terminal scrolled past
12
+ - see what was sent behind it: system prompt, memory files, tool definitions, injected reminders
13
+ - inspect the raw API traffic, including the side requests transcripts never record
14
+ - find where your tokens - and your money - went (spoiler: mostly on re-sending tool definitions)
10
15
 
11
16
  No configuration, no API keys, and **everything stays on your machine**.
12
17
 
@@ -39,7 +44,7 @@ claude-discover
39
44
  The same session exactly as Claude Code stores it on disk, one JSON line at a time. For when you don't want the story, you want the evidence.
40
45
 
41
46
  - **API request inspector**\
42
- A Postman-like view of every API request and response, captured by an optional local proxy (one click on, one click off). This is where the secrets live: the system prompt, your CLAUDE.md and memory files, tool definitions, injected reminders - all the stuff session logs politely never record.
47
+ A Postman-like view of every API request and response, captured by an optional local proxy (one click on, one click off). This is where the secrets live: the system prompt, your CLAUDE.md and memory files, tool definitions, injected reminders - plus the side requests (title, auto-mode checks, …) session logs never record.
43
48
 
44
49
  - **Session summary**\
45
50
  Token usage and cost for every session, and totals for the whole period. Computed from your local transcripts with current model rates - accurate to the cent.
@@ -16,4 +16,5 @@ export const PING_RESPONSE = 'claude-discover-proxy' // the ping body — proves
16
16
 
17
17
  export const DATA_DIR = process.env.CLAUDE_DISCOVER_DIR || path.join(os.homedir(), '.claude-discover') // global on purpose — session ids are unique, so one flat dir serves every Claude dir (env override used only by tests)
18
18
  export const REQUESTS_DIR = path.join(DATA_DIR, 'requests') // logs are kept forever — nothing deletes them
19
+ export const UNATTRIBUTED = 'unattributed' // the log name for requests without a session-id header
19
20
  export const ERROR_LOG_PATH = path.join(DATA_DIR, 'proxy.error.log') // capture errors — capture must never fail a request
package/bin/proxy.mjs CHANGED
@@ -14,7 +14,7 @@ import crypto from 'node:crypto'
14
14
  import { pathToFileURL } from 'node:url'
15
15
  import { parseArgs } from 'node:util'
16
16
 
17
- import { HOST, PORT, PROXY_URL, UPSTREAM, EXIT_ROUTE, PING_ROUTE, PING_RESPONSE, REQUESTS_DIR, ERROR_LOG_PATH } from './proxy.config.js'
17
+ import { HOST, PORT, PROXY_URL, UPSTREAM, EXIT_ROUTE, PING_ROUTE, PING_RESPONSE, REQUESTS_DIR, UNATTRIBUTED, ERROR_LOG_PATH } from './proxy.config.js'
18
18
 
19
19
  // How long an exiting proxy keeps serving in-flight responses — long replies stream for minutes
20
20
  const DRAIN_TIMEOUT_MS = 10 * 60_000
@@ -107,7 +107,7 @@ function decode(encoding, buf) {
107
107
 
108
108
  // ── 2. Claude Code capture ───────────────────────────────────────────────────
109
109
  // One JSON record per exchange in ~/.claude-discover/requests/<sessionId>.requests.jsonl
110
- // (session id from the X-Claude-Code-Session-Id header).
110
+ // (session id from the X-Claude-Code-Session-Id header; requests without a usable one go to the UNATTRIBUTED log).
111
111
 
112
112
  // Keep the header name (useful signal) but never the credential.
113
113
  function redactHeaders(headers, keys) {
@@ -116,8 +116,9 @@ function redactHeaders(headers, keys) {
116
116
  }
117
117
 
118
118
  function logRequest({ req, requestBody, status, responseHeaders, responseBody, timestamp, durationMs }) {
119
- const sessionId = req.headers['x-claude-code-session-id']
120
- if (!sessionId || !/^[\w-]+$/.test(sessionId)) return // header value becomes a filename — accept only safe ids
119
+ const header = req.headers['x-claude-code-session-id']
120
+ if (!header && req.method === 'HEAD') return // Claude Code's connectivity probe (HEAD /api/hello), every few seconds at times
121
+ const sessionId = /^[\w-]+$/.test(header ?? '') ? header : UNATTRIBUTED // header value becomes a filename — accept only safe ids
121
122
  const logPath = path.join(REQUESTS_DIR, `${sessionId}.requests.jsonl`)
122
123
  const record = { type: 'api-request', timestamp, url: `${req.method} ${req.url}`, status, durationMs }
123
124
  record.requestHeaders = redactHeaders(req.headers, ['authorization', 'x-api-key', 'proxy-authorization', 'cookie'])