From ff98636d62c8c266b6eb26cb9f95463fd3de9e1c Mon Sep 17 00:00:00 2001 From: Jonathan Date: Thu, 6 Nov 2025 01:34:00 -0500 Subject: [PATCH 1/3] feat(claude-trace): add --no-html flag to skip HTML generation Add --no-html CLI flag to disable HTML report generation while preserving JSONL logging. This is useful for reducing file size when archiving conversations or when HTML viewing is not needed. Implementation: - Add --no-html flag parsing in cli.ts - Wire flag through CLAUDE_TRACE_GENERATE_HTML env var - Read env var in interceptor.ts constructor to set enableRealTimeHTML - Update help text and output messages Follows existing --no-open pattern for consistency. --- apps/claude-trace/src/cli.ts | 8 +++++++- apps/claude-trace/src/interceptor.ts | 11 +++++++++-- 2 files changed, 16 insertions(+), 3 deletions(-) diff --git a/apps/claude-trace/src/cli.ts b/apps/claude-trace/src/cli.ts index ad13e33..6dd24f4 100644 --- a/apps/claude-trace/src/cli.ts +++ b/apps/claude-trace/src/cli.ts @@ -35,6 +35,7 @@ ${colors.yellow}OPTIONS:${colors.reset} --run-with Pass all following arguments to Claude process --include-all-requests Include all requests made through fetch, otherwise only requests to v1/messages with more than 2 messages in the context --no-open Don't open generated HTML file in browser + --no-html Skip HTML generation (JSONL only) --log Specify custom log file base name (without extension) --claude-path Specify custom path to Claude binary --help, -h Show this help message @@ -234,6 +235,7 @@ async function runClaudeWithInterception( openInBrowser: boolean = false, customClaudePath?: string, logBaseName?: string, + generateHTML: boolean = true, ): Promise { log("Claude Trace", "blue"); log("Starting Claude with traffic logging", "yellow"); @@ -257,6 +259,7 @@ async function runClaudeWithInterception( NODE_OPTIONS: "--no-deprecation", CLAUDE_TRACE_INCLUDE_ALL_REQUESTS: includeAllRequests ? "true" : "false", CLAUDE_TRACE_OPEN_BROWSER: openInBrowser ? "true" : "false", + CLAUDE_TRACE_GENERATE_HTML: generateHTML ? "true" : "false", ...(logBaseName ? { CLAUDE_TRACE_LOG_NAME: logBaseName } : {}), }, stdio: "inherit", @@ -473,6 +476,9 @@ async function main(): Promise { // Check for no-open flag (inverted logic - open by default) const openInBrowser = !claudeTraceArgs.includes("--no-open"); + // Check for no-html flag (inverted logic - generate HTML by default) + const generateHTML = !claudeTraceArgs.includes("--no-html"); + // Check for custom Claude path let customClaudePath: string | undefined; const claudePathIndex = claudeTraceArgs.indexOf("--claude-path"); @@ -525,7 +531,7 @@ async function main(): Promise { } // Scenario 1: No args (or claude with args) -> launch claude with interception - await runClaudeWithInterception(claudeArgs, includeAllRequests, openInBrowser, customClaudePath, logBaseName); + await runClaudeWithInterception(claudeArgs, includeAllRequests, openInBrowser, customClaudePath, logBaseName, generateHTML); } main().catch((error) => { diff --git a/apps/claude-trace/src/interceptor.ts b/apps/claude-trace/src/interceptor.ts index 111c87f..a1c03ab 100644 --- a/apps/claude-trace/src/interceptor.ts +++ b/apps/claude-trace/src/interceptor.ts @@ -21,9 +21,12 @@ export class ClaudeTrafficLogger { private htmlGenerator: HTMLGenerator; constructor(config: InterceptorConfig = {}) { + // Check environment variable for HTML generation (defaults to true) + const enableHTMLFromEnv = process.env.CLAUDE_TRACE_GENERATE_HTML !== "false"; + this.config = { logDirectory: ".claude-trace", - enableRealTimeHTML: true, + enableRealTimeHTML: enableHTMLFromEnv, logLevel: "info", ...config, }; @@ -51,7 +54,11 @@ export class ClaudeTrafficLogger { // Output the actual filenames with absolute paths console.log(`Logs will be written to:`); console.log(` JSONL: ${path.resolve(this.logFile)}`); - console.log(` HTML: ${path.resolve(this.htmlFile)}`); + if (this.config.enableRealTimeHTML) { + console.log(` HTML: ${path.resolve(this.htmlFile)}`); + } else { + console.log(` HTML: (disabled via --no-html)`); + } } private isClaudeAPI(url: string | URL): boolean { From 8e93bfe5c84e0c96e395d01d0c824b76d6f38a21 Mon Sep 17 00:00:00 2001 From: Jonathan Date: Thu, 6 Nov 2025 11:15:21 -0500 Subject: [PATCH 2/3] docs: add --no-html flag to README usage examples --- apps/claude-trace/README.md | 3 +++ 1 file changed, 3 insertions(+) diff --git a/apps/claude-trace/README.md b/apps/claude-trace/README.md index c07ac93..d069843 100644 --- a/apps/claude-trace/README.md +++ b/apps/claude-trace/README.md @@ -17,6 +17,9 @@ claude-trace # Include all API requests (by default, only substantial conversations are logged) claude-trace --include-all-requests +# Skip HTML generation (JSONL only, saves ~60% disk space) +claude-trace --no-html + # Run Claude with specific arguments claude-trace --run-with chat --model sonnet-3.5 From af90382d45bce76afb905237e300e25b9728ad12 Mon Sep 17 00:00:00 2001 From: Jonathan Date: Thu, 6 Nov 2025 11:17:30 -0500 Subject: [PATCH 3/3] refactor: remove HTML disabled message when --no-html is used --- apps/claude-trace/src/interceptor.ts | 2 -- 1 file changed, 2 deletions(-) diff --git a/apps/claude-trace/src/interceptor.ts b/apps/claude-trace/src/interceptor.ts index a1c03ab..64780d0 100644 --- a/apps/claude-trace/src/interceptor.ts +++ b/apps/claude-trace/src/interceptor.ts @@ -56,8 +56,6 @@ export class ClaudeTrafficLogger { console.log(` JSONL: ${path.resolve(this.logFile)}`); if (this.config.enableRealTimeHTML) { console.log(` HTML: ${path.resolve(this.htmlFile)}`); - } else { - console.log(` HTML: (disabled via --no-html)`); } }