Skip to content

debug-bundle: include proxy-events.jsonl tail in saved bundles - #62

Merged
Juliusolsson05 merged 1 commit into
mainfrom
feat/bundle-proxy-events
May 7, 2026
Merged

Juliusolsson05 merged 1 commit into
mainfrom
feat/bundle-proxy-events

Conversation

@Juliusolsson05

Copy link
Copy Markdown
Owner

Summary

Pulls the wire-level proxy capture (from claude-code-headless' mitmAddon and codex-headless' ResponsesProxy) into every saved debug bundle, gated on the session having a proxy run dir on disk.

Closes the loop on the three-PR series:

After all three land, opening a debug bundle shows every API request that was sent during the session, including the actual prompt body — with no manual digging through hidden state directories.

What changes

New file: `src/main/storage/proxyEventsReader.ts`

  • Finds the latest proxy run dir matching `{cwd, sessionKey}`.
  • Reads `proxy-events.jsonl` with a 5 MiB tail cap (longer logs get a synthetic `{kind: 'truncated'}` header line so consumers know they're seeing only the tail).
  • Returns nulls on any error — bundle save must never fail because the proxy log is missing.
  • Uses the same `sanitizePath` helper the proxy writers use, so reader and writers can't disagree on segment shape.

New IPC: `debug:read-proxy-events`

  • Renderer-callable handler in `src/main/ipc/debug.ts`.
  • Single new types entry (`ProxyEventsBundleSection`) plus `debugApi.readProxyEvents` exposure.

Bundle assembler: `saveDebugBundle.ts`

  • Calls `window.api.readProxyEvents` during assembly.
  • Conditionally adds `proxy-events.jsonl` and `proxy-session-meta.json` to the file list when the reader finds something.
  • Manifest gains a `proxyRunDir` field pointing at the FULL log on disk for users who hit the tail cap.
  • Both callers (autosave + manual) pass `cwd` + `providerSessionId` from session meta.

Bundle layout after this lands

For a Claude/Codex session that ran with proxy:
```
debug-bundles/-/
├── manifest.json ← gains proxyRunDir field
├── state-snapshot.json
├── feed-debug.jsonl
├── work-context.json
├── proxy-semantic.json
├── proxy-events.jsonl ← NEW (wire-level capture)
├── proxy-session-meta.json ← NEW (proxy run metadata)
├── html-raw.html
├── html-clean.html
├── trace/
└── performance/
```

For a session without proxy (legacy or proxy disabled), the layout is unchanged — the new files are conditional.

Verification

  • `npm run build:app` ✅
  • Existing bundle layout unchanged for sessions without proxy.
  • Reader is fault-tolerant: missing run dir, unreadable file, or oversized log all degrade gracefully.

Trade-offs

  • Bundle size. A long-running session can have a multi-MB proxy log; tail cap at 5 MiB keeps bundles bounded. Users who need the full log find it at `manifest.proxyRunDir`.
  • Privacy. Bundles now include actual prompts and conversation bodies. Authorization headers are structurally excluded by the addon allowlist (PR proxy: bump headless request_shape capture and header filtering #55), but the bundle does carry user prompts. Worth a future toast on bundle-save: "bundle contains conversation prompts."

🤖 Generated with Claude Code

Pulls the wire-level proxy capture (from claude-code-headless'
mitmAddon and codex-headless' ResponsesProxy) into every saved
debug bundle, gated on the session having a proxy run dir on disk.

Forensic gap before this change:
  Bundles carried state-snapshot, feed-debug, proxy-semantic, and
  HTML — useful for "what did the renderer think happened" but
  silent on "what was actually sent on the wire". The on-disk
  proxy-events.jsonl had every prompt and header, but it lived
  outside the bundle's file list and required the user to manually
  find the run dir under ~/.config/cc-shell/proxy/. Anyone trying
  to debug a sidecar leak (the orphan-ghost case from PR #54)
  needed both the bundle AND the user's proxy dir to make any
  progress.

Three additions:

1. src/main/storage/proxyEventsReader.ts (new)
   Finds the latest proxy run dir matching {cwd, sessionKey}, reads
   proxy-events.jsonl, tails to PROXY_EVENTS_BUNDLE_MAX_BYTES (5
   MiB) when oversized. Returns nulls on any error — bundle save
   must NEVER fail because the proxy log is missing or unreadable.
   Uses the same sanitizePath helper the proxy writers use, so the
   reader and writers can never disagree on the segment shape.

2. IPC seam: 'debug:read-proxy-events'
   Renderer-callable handler that wraps the reader. Single new
   types entry (ProxyEventsBundleSection) plus debugApi.readProxyEvents.

3. saveDebugBundle.ts
   Calls window.api.readProxyEvents during assembly, conditionally
   adds proxy-events.jsonl + proxy-session-meta.json to the file
   list when the reader finds something. Manifest gains a
   `proxyRunDir` field pointing at the FULL log on disk so users
   who hit the 5 MiB tail cap know where to look for older traffic.

Both bundle callers (autosave + manual) pass cwd +
providerSessionId from session meta. No new state, no new IPC
shape beyond the one read.

Verification:
  - npm run build:app ✅
  - Existing bundle layout unchanged for sessions without proxy
    (the new files are conditional on reader output).
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant