Skip to content

Commit 603576e

Browse files
committed
Initial commit: Claude Viewer - Browse Claude conversation transcripts
- Next.js 14 web application with TypeScript - File tree navigation with auto-expand - Chat-style interface with markdown rendering - Dark mode support - Tool visualization for AI interactions - Playwright tests included - MIT License
0 parents  commit 603576e

23 files changed

+6086
-0
lines changed

.eslintrc.json

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
{
2+
"extends": "next/core-web-vitals"
3+
}

.gitignore

Lines changed: 60 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,60 @@
1+
# Dependencies
2+
node_modules/
3+
.pnp
4+
.pnp.js
5+
6+
# Testing
7+
coverage/
8+
test-results/
9+
playwright-report/
10+
playwright/.cache/
11+
12+
# Next.js
13+
.next/
14+
out/
15+
build/
16+
17+
# Production
18+
dist/
19+
20+
# Misc
21+
.DS_Store
22+
*.pem
23+
24+
# Debug
25+
npm-debug.log*
26+
yarn-debug.log*
27+
yarn-error.log*
28+
.pnpm-debug.log*
29+
30+
# Local env files
31+
.env
32+
.env*.local
33+
34+
# Vercel
35+
.vercel
36+
37+
# TypeScript
38+
*.tsbuildinfo
39+
next-env.d.ts
40+
41+
# IDE
42+
.vscode/
43+
.idea/
44+
*.swp
45+
*.swo
46+
*~
47+
48+
# OS
49+
.DS_Store
50+
Thumbs.db
51+
52+
# Test artifacts
53+
*.png
54+
debug-*.js
55+
tree-debug.png
56+
test-*.png
57+
58+
59+
CLAUDE.MD
60+
.claude/

CONTRIBUTING.md

Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,57 @@
1+
# Contributing to Claude Viewer
2+
3+
Thank you for your interest in contributing to Claude Viewer! We welcome contributions from the community.
4+
5+
## Getting Started
6+
7+
1. Fork the repository
8+
2. Clone your fork: `git clone https://github.com/YOUR-USERNAME/claude-viewer.git`
9+
3. Install dependencies: `yarn install`
10+
4. Create a new branch: `git checkout -b feature/your-feature-name`
11+
12+
## Development Workflow
13+
14+
1. Make your changes
15+
2. Run tests: `yarn test`
16+
3. Run type checking: `yarn typecheck`
17+
4. Run linting: `yarn lint`
18+
5. Commit your changes with a descriptive message
19+
6. Push to your fork and create a pull request
20+
21+
## Code Style
22+
23+
- We use TypeScript for type safety
24+
- Follow the existing code style
25+
- Use meaningful variable and function names
26+
- Add comments for complex logic
27+
- Keep components focused and reusable
28+
29+
## Testing
30+
31+
- Write tests for new features
32+
- Ensure all existing tests pass
33+
- Use Playwright for E2E testing
34+
- Run `yarn test` before submitting PR
35+
36+
## Pull Request Guidelines
37+
38+
- Keep PRs focused on a single feature or fix
39+
- Update documentation if needed
40+
- Ensure all tests pass
41+
- Provide a clear description of changes
42+
- Link any related issues
43+
44+
## Reporting Issues
45+
46+
- Use GitHub Issues to report bugs
47+
- Provide clear reproduction steps
48+
- Include system information
49+
- Attach error messages or screenshots (without personal data)
50+
51+
## Security
52+
53+
- Never commit sensitive information
54+
- Don't include personal session data in PRs
55+
- Report security issues privately
56+
57+
Thank you for contributing!

LICENSE

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
MIT License
2+
3+
Copyright (c) 2024 Claude Viewer Contributors
4+
5+
Permission is hereby granted, free of charge, to any person obtaining a copy
6+
of this software and associated documentation files (the "Software"), to deal
7+
in the Software without restriction, including without limitation the rights
8+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9+
copies of the Software, and to permit persons to whom the Software is
10+
furnished to do so, subject to the following conditions:
11+
12+
The above copyright notice and this permission notice shall be included in all
13+
copies or substantial portions of the Software.
14+
15+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21+
SOFTWARE.

README.md

Lines changed: 118 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,118 @@
1+
# Claude Viewer
2+
3+
A modern web application for browsing and viewing Claude conversation session transcripts stored in the `.claude/projects` directory.
4+
5+
## Features
6+
7+
- 📁 **File Tree Navigation**: Browse your Claude sessions organized by project directories
8+
- 💬 **Chat-Style Interface**: View conversations in a familiar chat format
9+
- 🌗 **Dark Mode Support**: Toggle between light and dark themes
10+
- 🔍 **Auto-Expand Navigation**: Direct links to sessions automatically expand the file tree
11+
- 📋 **Copy Session Paths**: Quickly copy JSONL file paths to clipboard
12+
- 📝 **Markdown Rendering**: Full markdown support with syntax highlighting
13+
- 🛠️ **Tool Visualization**: See tool calls and results in formatted blocks
14+
15+
## Prerequisites
16+
17+
- Node.js 18.x or higher
18+
- Yarn package manager
19+
- Claude Code or Claude Desktop with session files in `~/.claude/projects/`
20+
21+
## Installation
22+
23+
1. Clone the repository:
24+
```bash
25+
git clone https://github.com/phpmypython/claude-viewer.git
26+
cd claude-viewer
27+
```
28+
29+
2. Install dependencies:
30+
```bash
31+
yarn install
32+
```
33+
34+
3. Run the development server:
35+
```bash
36+
yarn dev
37+
```
38+
39+
4. Open [http://localhost:3000](http://localhost:3000) in your browser
40+
41+
## Session File Location
42+
43+
By default, the application looks for Claude session files in:
44+
```
45+
~/.claude/projects/
46+
```
47+
48+
This is the standard location where Claude Code and Claude Desktop store conversation transcripts in JSONL format.
49+
50+
## Usage
51+
52+
### Browsing Sessions
53+
- Click on folders in the sidebar to expand/collapse them
54+
- Click on a session to view the conversation
55+
- Use the theme toggle button to switch between light and dark mode
56+
57+
### Direct Links
58+
You can link directly to a specific session using URL parameters:
59+
```
60+
http://localhost:3000/?session=<session-id>
61+
```
62+
63+
The application will automatically expand the file tree to show the selected session.
64+
65+
### Copying File Paths
66+
When viewing a session, hover over it in the sidebar and click the copy icon to copy the full JSONL file path to your clipboard.
67+
68+
## Development
69+
70+
### Running Tests
71+
```bash
72+
# Run all tests
73+
yarn test
74+
75+
# Run tests in watch mode
76+
yarn test:watch
77+
78+
# Run tests with UI
79+
yarn test:ui
80+
```
81+
82+
### Building for Production
83+
```bash
84+
yarn build
85+
yarn start
86+
```
87+
88+
### Project Structure
89+
```
90+
/app # Next.js app directory
91+
/api # API routes for reading sessions
92+
page.tsx # Main page component
93+
/components # React components
94+
Sidebar.tsx # File tree navigation
95+
ChatView.tsx # Conversation display
96+
/tests # Playwright E2E tests
97+
```
98+
99+
## Configuration
100+
101+
The application uses sensible defaults and doesn't require configuration for most users. If your Claude sessions are stored in a different location, you'll need to modify the API routes to point to the correct directory.
102+
103+
## Contributing
104+
105+
Contributions are welcome! Please feel free to submit a Pull Request.
106+
107+
## License
108+
109+
MIT License - see LICENSE file for details
110+
111+
## Acknowledgments
112+
113+
Built with:
114+
- [Next.js](https://nextjs.org/)
115+
- [React](https://reactjs.org/)
116+
- [Tailwind CSS](https://tailwindcss.com/)
117+
- [react-markdown](https://github.com/remarkjs/react-markdown)
118+
- [Playwright](https://playwright.dev/) for testing
Lines changed: 81 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,81 @@
1+
import { NextResponse } from 'next/server'
2+
import fs from 'fs/promises'
3+
import path from 'path'
4+
import os from 'os'
5+
6+
/**
7+
* GET /api/sessions/[project]/[session]
8+
*
9+
* Fetches the content of a specific Claude conversation session.
10+
* Reads the JSONL file and extracts all user and assistant messages.
11+
*
12+
* @param request - The incoming request object
13+
* @param params - Route parameters containing project name and session ID
14+
* @returns {Promise<NextResponse>} JSON response with array of messages
15+
*
16+
* Message format:
17+
* - role: 'user' | 'assistant' | 'system'
18+
* - content: Message content (string or array of content items)
19+
* - timestamp: ISO timestamp of the message
20+
*/
21+
export async function GET(
22+
request: Request,
23+
{ params }: { params: Promise<{ project: string; session: string }> }
24+
) {
25+
try {
26+
const { project, session } = await params
27+
const homeDir = os.homedir()
28+
const sessionPath = path.join(
29+
homeDir,
30+
'.claude',
31+
'projects',
32+
project,
33+
`${session}.jsonl`
34+
)
35+
36+
// Reading session from: sessionPath
37+
38+
// Check if file exists
39+
try {
40+
await fs.access(sessionPath)
41+
} catch {
42+
// Session file not found
43+
return NextResponse.json({ error: 'Session file not found' }, { status: 404 })
44+
}
45+
46+
const content = await fs.readFile(sessionPath, 'utf-8')
47+
const lines = content.trim().split('\n').filter(line => line.trim())
48+
49+
// Found ${lines.length} lines in session file
50+
51+
const parsedLines = lines.map((line, index) => {
52+
try {
53+
return JSON.parse(line)
54+
} catch (e) {
55+
// Failed to parse line ${index + 1}
56+
return null
57+
}
58+
}).filter(Boolean)
59+
60+
// Successfully parsed ${parsedLines.length} lines
61+
62+
// Extract messages from the parsed data
63+
const messages = parsedLines
64+
.filter(item => item.message && (item.type === 'user' || item.type === 'assistant'))
65+
.map(item => ({
66+
role: item.type,
67+
content: item.message.content,
68+
timestamp: item.timestamp
69+
}))
70+
71+
// Extracted ${messages.length} messages
72+
73+
return NextResponse.json({ messages })
74+
} catch (error) {
75+
// Error reading session
76+
return NextResponse.json({
77+
error: 'Failed to read session',
78+
details: error instanceof Error ? error.message : 'Unknown error'
79+
}, { status: 500 })
80+
}
81+
}

0 commit comments

Comments
 (0)