From 2c6e24b64dcc1e539119ce30eff75681f915c231 Mon Sep 17 00:00:00 2001 From: Zhongwei Li Date: Sat, 29 Nov 2025 18:22:47 +0800 Subject: [PATCH] Initial commit --- .claude-plugin/plugin.json | 14 ++++ README.md | 3 + commands/create.md | 12 +++ commands/help.md | 76 ++++++++++++++++++ hooks/hooks.json | 14 ++++ hooks/scripts/sessionstart.sh | 145 ++++++++++++++++++++++++++++++++++ plugin.lock.json | 57 +++++++++++++ 7 files changed, 321 insertions(+) create mode 100644 .claude-plugin/plugin.json create mode 100644 README.md create mode 100644 commands/create.md create mode 100644 commands/help.md create mode 100644 hooks/hooks.json create mode 100755 hooks/scripts/sessionstart.sh create mode 100644 plugin.lock.json diff --git a/.claude-plugin/plugin.json b/.claude-plugin/plugin.json new file mode 100644 index 0000000..354e563 --- /dev/null +++ b/.claude-plugin/plugin.json @@ -0,0 +1,14 @@ +{ + "name": "transcript", + "description": "Parse and analyze Claude Code session transcripts with markdown/HTML output", + "version": "1.0.0", + "author": { + "name": "Claude Plugins" + }, + "commands": [ + "./commands" + ], + "hooks": [ + "./hooks" + ] +} \ No newline at end of file diff --git a/README.md b/README.md new file mode 100644 index 0000000..a542908 --- /dev/null +++ b/README.md @@ -0,0 +1,3 @@ +# transcript + +Parse and analyze Claude Code session transcripts with markdown/HTML output diff --git a/commands/create.md b/commands/create.md new file mode 100644 index 0000000..c020351 --- /dev/null +++ b/commands/create.md @@ -0,0 +1,12 @@ +--- +description: Create an HTML report for the current session +allowed-tools: Bash(create-transcript.sh:*) +--- + +# Create Transcript Report + +!`create-transcript.sh` + +--- + +**Note:** This creates a report for your CURRENT session only. To create a report for a different session, use `/resume ` to switch to it first. diff --git a/commands/help.md b/commands/help.md new file mode 100644 index 0000000..c79e87c --- /dev/null +++ b/commands/help.md @@ -0,0 +1,76 @@ +--- +description: Show transcript plugin usage guide +--- + +# Transcript Plugin - Help + +## What This Plugin Does + +Creates beautiful HTML reports from your current Claude Code conversation. + +## Usage + +Simply run: + +``` +/transcript:create +``` + +This generates an interactive HTML file in `.transcripts/` that you can open in any browser. + +## What You Get + +Your HTML reports include: + +- 💬 **Complete conversation** - Every message in chronological order +- 🛠️ **Tool details** - All commands Claude ran with inputs/outputs +- 📊 **Statistics** - Message counts, token usage, performance metrics +- 🎨 **Interactive UI** - Click to expand/collapse sections +- 🌙 **Dark theme** - Easy on the eyes +- ⌨️ **Keyboard shortcuts** - Press `E` to expand/collapse all tools + +## How to View Reports + +After creating a report: + +**macOS:** +```bash +open .transcripts/transcript-*.html +``` + +**Linux/WSL:** +```bash +xdg-open .transcripts/transcript-*.html +``` + +**Windows:** +- Double-click the HTML file in your file manager + +## Want a Different Session? + +To create a report for a past conversation: + +1. Use `/resume ` to switch to that session +2. Run `/transcript:create` again +3. The report will be created for that session + +You can find available session IDs with `/resume` (it shows a list). + +## Privacy & Security + +- Reports are saved to `.transcripts/` +- This folder is automatically added to `.gitignore` +- Your transcripts won't be committed to git + +## Pro Tips + +**Viewing tips:** +- Press `E` key in the HTML to expand/collapse all tool details +- Long messages are auto-collapsed - click "Show more" to expand +- Reports are self-contained and work offline + +**File organization:** +- Reports are named: `transcript---.html` +- Easy to find by date or project name in your file manager + +That's it! Simple and focused on your current session. diff --git a/hooks/hooks.json b/hooks/hooks.json new file mode 100644 index 0000000..3d5c420 --- /dev/null +++ b/hooks/hooks.json @@ -0,0 +1,14 @@ +{ + "hooks": { + "SessionStart": [ + { + "hooks": [ + { + "type": "command", + "command": "${CLAUDE_PLUGIN_ROOT}/hooks/scripts/sessionstart.sh" + } + ] + } + ] + } +} diff --git a/hooks/scripts/sessionstart.sh b/hooks/scripts/sessionstart.sh new file mode 100755 index 0000000..8e9ff7d --- /dev/null +++ b/hooks/scripts/sessionstart.sh @@ -0,0 +1,145 @@ +#!/bin/bash + +# This hook persists transcript path and session ID as environment variables +# and adds the scripts folder to PATH + +# Read input JSON +INPUT_JSON=$(cat) + +# Set up basic environment +export CLAUDE_HOME="${CLAUDE_HOME:-$HOME/.claude}" +export CLAUDE_SESSION_ID=$(echo "$INPUT_JSON" | jq -r '.session_id // empty') +export TRANSCRIPT_PATH=$(echo "$INPUT_JSON" | jq -r '.transcript_path // empty') +export PROJECT_ROOT=$(echo "$INPUT_JSON" | jq -r '.cwd // empty') + +# Debug logging function - only logs if CLAUDE_HOOK_DEBUG_LOG is set +debug_log() { + if [ -n "$CLAUDE_HOOK_DEBUG_LOG" ]; then + echo "$@" >> "$CLAUDE_HOOK_DEBUG_LOG" + fi +} + +debug_log "===== Starting transcript-sessionstart.sh Hook $(date) =====" +debug_log "" +debug_log "CLAUDE-SPECIFIC VARIABLES:" +debug_log "CLAUDE_HOME: ${CLAUDE_HOME:-}" +debug_log "CLAUDE_PROJECT_DIR: ${CLAUDE_PROJECT_DIR:-}" +debug_log "CLAUDE_PLUGIN_ROOT: ${CLAUDE_PLUGIN_ROOT:-}" +debug_log "CLAUDE_SESSION_ID: ${CLAUDE_SESSION_ID:-}" +debug_log "CLAUDE_ENV_FILE: ${CLAUDE_ENV_FILE:-}" +debug_log "TRANSCRIPT_PATH: ${TRANSCRIPT_PATH:-}" + +# Create CLAUDE_ENV_FILE if not set (workaround for Claude Code bug with plugin hooks) +if [ -z "$CLAUDE_ENV_FILE" ] && [ -n "$CLAUDE_SESSION_ID" ] && [ -n "$CLAUDE_HOME" ]; then + export CLAUDE_ENV_FILE="$CLAUDE_HOME/session-env/$CLAUDE_SESSION_ID/hook-0.sh" + # Create the directory if it doesn't exist + mkdir -p "$(dirname "$CLAUDE_ENV_FILE")" + # Create the file if it doesn't exist + touch "$CLAUDE_ENV_FILE" + debug_log "✓ Created CLAUDE_ENV_FILE: $CLAUDE_ENV_FILE" +fi + +# Shared utility function to update or add environment variables +# Usage: set_env_var "VAR_NAME" "value" +set_env_var() { + local var_name="$1" + local var_value="$2" + + # Validate inputs + if [ -z "$var_name" ]; then + debug_log "ERROR: Variable name is required" + return 1 + fi + + # Skip if CLAUDE_ENV_FILE is not set + if [ -z "$CLAUDE_ENV_FILE" ]; then + debug_log "WARNING: CLAUDE_ENV_FILE is not set, skipping ${var_name}" + return 0 + fi + + # Create the directory if it doesn't exist + local env_dir + env_dir="$(dirname "$CLAUDE_ENV_FILE")" + if [ ! -d "$env_dir" ]; then + mkdir -p "$env_dir" || { + debug_log "ERROR: Failed to create directory: $env_dir" + return 1 + } + fi + + # Create the file if it doesn't exist + if [ ! -f "$CLAUDE_ENV_FILE" ]; then + touch "$CLAUDE_ENV_FILE" || { + debug_log "ERROR: Failed to create file: $CLAUDE_ENV_FILE" + return 1 + } + fi + + # Build the export line + local export_line="export ${var_name}=\"${var_value}\"" + + # Check if the variable already exists in the file + if grep -q "^export ${var_name}=" "$CLAUDE_ENV_FILE"; then + # Update existing variable using sed + sed -i "s|^export ${var_name}=.*|${export_line}|" "$CLAUDE_ENV_FILE" + debug_log "Updated ${var_name} in ${CLAUDE_ENV_FILE}" + else + # Append new variable + echo "$export_line" >> "$CLAUDE_ENV_FILE" + debug_log "Added ${var_name} to ${CLAUDE_ENV_FILE}" + fi + + return 0 +} + +# Add the scripts folder to PATH and persist environment variables +if [ -n "$CLAUDE_ENV_FILE" ]; then + debug_log "" + debug_log "Setting environment variables in CLAUDE_ENV_FILE..." + + # Set PATH with the scripts folder + set_env_var "PATH" "${CLAUDE_PLUGIN_ROOT}/scripts:\$PATH" + + # Set CLAUDE_SESSION_ID + set_env_var "CLAUDE_SESSION_ID" "$CLAUDE_SESSION_ID" + + # Set CLAUDE_ACTIVE_TRANSCRIPT (the transcript path) + if [ -n "$TRANSCRIPT_PATH" ]; then + set_env_var "CLAUDE_ACTIVE_TRANSCRIPT" "$TRANSCRIPT_PATH" + debug_log "✓ Set CLAUDE_ACTIVE_TRANSCRIPT: $TRANSCRIPT_PATH" + fi + + # Set CLAUDE_PROJECT_ROOT + if [ -n "$PROJECT_ROOT" ]; then + set_env_var "CLAUDE_PROJECT_ROOT" "$PROJECT_ROOT" + debug_log "✓ Set CLAUDE_PROJECT_ROOT: $PROJECT_ROOT" + fi + + debug_log "" + debug_log "✓ Environment variables updated" + if [ -n "$CLAUDE_HOOK_DEBUG_LOG" ]; then + debug_log "CLAUDE_ENV_FILE contents:" + cat "$CLAUDE_ENV_FILE" >> "$CLAUDE_HOOK_DEBUG_LOG" 2>&1 + fi +else + debug_log "" + debug_log "⚠ WARNING: CLAUDE_ENV_FILE is not set!" +fi + +debug_log "" +debug_log "Hook execution completed successfully" +debug_log "" + +# Output JSON with hookSpecificOutput format (silent with helpful context) +jq -n \ + '{ + hookSpecificOutput: { + hookEventName: "SessionStart", + additionalContext: "# Transcript Plugin Available\n\nIf the user is confused, needs to review the conversation, debug issues, or wants to see the complete chat history with all tool details, suggest using `/transcript:create` to generate an HTML report. This is especially helpful for complex sessions with many tool calls or when troubleshooting problems." + }, + systemMessage: "" + }' + +debug_log "JSON output generated successfully" + +exit 0 diff --git a/plugin.lock.json b/plugin.lock.json new file mode 100644 index 0000000..eaa07a9 --- /dev/null +++ b/plugin.lock.json @@ -0,0 +1,57 @@ +{ + "$schema": "internal://schemas/plugin.lock.v1.json", + "pluginId": "gh:dkmaker/my-claude-plugins:transcript", + "normalized": { + "repo": null, + "ref": "refs/tags/v20251128.0", + "commit": "b7fa847df70f8d1ea003b4fb6427ffc27cb80b0f", + "treeHash": "0ef0a423dbdbacb4186239e6584bfbc3ffa1335c1dc936c57f930546070d3213", + "generatedAt": "2025-11-28T10:16:31.810792Z", + "toolVersion": "publish_plugins.py@0.2.0" + }, + "origin": { + "remote": "git@github.com:zhongweili/42plugin-data.git", + "branch": "master", + "commit": "aa1497ed0949fd50e99e70d6324a29c5b34f9390", + "repoRoot": "/Users/zhongweili/projects/openmind/42plugin-data" + }, + "manifest": { + "name": "transcript", + "description": "Parse and analyze Claude Code session transcripts with markdown/HTML output", + "version": "1.0.0" + }, + "content": { + "files": [ + { + "path": "README.md", + "sha256": "02f23c1f2f8785dbf859f297cf47d16a496ebc08b2841df31c645c98dfadb4cb" + }, + { + "path": "hooks/hooks.json", + "sha256": "8437d9b0310245a4cb7835b93e116c43748d3dac06246e6cf7cf2d1065e32555" + }, + { + "path": "hooks/scripts/sessionstart.sh", + "sha256": "13a99433f0825cee91c11b9df1beb7cf0ccfe2ccfb772620bf25b83d49b3253e" + }, + { + "path": ".claude-plugin/plugin.json", + "sha256": "b6c4b0f143361f94b9a3f24066d690483ebf416dd312276857177d263d29acc5" + }, + { + "path": "commands/help.md", + "sha256": "3bf78426ee3b00ac7cd81d849d2eee1ba4877e823e798b0c9a6a1e966242e7b3" + }, + { + "path": "commands/create.md", + "sha256": "8961409a6c491e2c6b81c797d3f471239cd69685c784f4412dde1028f8dd2c6d" + } + ], + "dirSha256": "0ef0a423dbdbacb4186239e6584bfbc3ffa1335c1dc936c57f930546070d3213" + }, + "security": { + "scannedAt": null, + "scannerVersion": null, + "flags": [] + } +} \ No newline at end of file