@teddysc/claude-run 0.14.0 → 0.15.0
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 +15 -0
- package/dist/web/assets/index-B4G1ceoy.js +333 -0
- package/dist/web/index.html +1 -1
- package/package.json +3 -2
- package/spec.md +280 -0
- package/dist/web/assets/index-CfXKVwHJ.js +0 -333
package/dist/web/index.html
CHANGED
|
@@ -8,7 +8,7 @@
|
|
|
8
8
|
<link rel="icon" href="/icon-192.png" sizes="192x192" />
|
|
9
9
|
<link rel="icon" href="/icon-512.png" sizes="512x512" />
|
|
10
10
|
<link rel="apple-touch-icon" href="/icon-192.png" />
|
|
11
|
-
<script type="module" crossorigin src="/assets/index-
|
|
11
|
+
<script type="module" crossorigin src="/assets/index-B4G1ceoy.js"></script>
|
|
12
12
|
<link rel="stylesheet" crossorigin href="/assets/index-CSMaeBYb.css">
|
|
13
13
|
</head>
|
|
14
14
|
<body class="bg-zinc-900 text-zinc-100">
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@teddysc/claude-run",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.15.0",
|
|
4
4
|
"description": "A beautiful web UI for browsing Claude Code conversation history",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"bin": {
|
|
@@ -8,7 +8,8 @@
|
|
|
8
8
|
},
|
|
9
9
|
"main": "./dist/index.js",
|
|
10
10
|
"files": [
|
|
11
|
-
"dist"
|
|
11
|
+
"dist",
|
|
12
|
+
"spec.md"
|
|
12
13
|
],
|
|
13
14
|
"scripts": {
|
|
14
15
|
"dev": "concurrently \"bun run dev:web\" \"bun run dev:server\"",
|
package/spec.md
ADDED
|
@@ -0,0 +1,280 @@
|
|
|
1
|
+
# claude-run Specification
|
|
2
|
+
|
|
3
|
+
|
|
4
|
+
A beautiful web UI for browsing Claude Code conversation history.
|
|
5
|
+
|
|
6
|
+
Always run `bun run build` when you're done modifying code!!!
|
|
7
|
+
|
|
8
|
+
## Overview
|
|
9
|
+
|
|
10
|
+
claude-run is a web application that provides a searchable, browsable interface for Claude Code conversation history stored in `~/.claude/`. It consists of:
|
|
11
|
+
|
|
12
|
+
- **API Server**: Hono-based HTTP server with Server-Sent Events (SSE)
|
|
13
|
+
- **Web Frontend**: React + TypeScript + Tailwind CSS
|
|
14
|
+
- **File Watcher**: Real-time updates when conversations change
|
|
15
|
+
- **Full-Text Search**: ripgrep-powered search across conversation content
|
|
16
|
+
|
|
17
|
+
## Architecture
|
|
18
|
+
|
|
19
|
+
### Directory Structure
|
|
20
|
+
|
|
21
|
+
```
|
|
22
|
+
/Users/tsca/testdir/claude-run/
|
|
23
|
+
├── api/ # Backend API
|
|
24
|
+
│ ├── index.ts # CLI entry point
|
|
25
|
+
│ ├── server.ts # Hono HTTP server
|
|
26
|
+
│ ├── storage.ts # File system operations
|
|
27
|
+
│ ├── watcher.ts # File system watcher
|
|
28
|
+
│ ├── fulltext-search.ts # ripgrep search integration
|
|
29
|
+
│ └── types.ts # Shared TypeScript types
|
|
30
|
+
├── web/ # Frontend
|
|
31
|
+
│ ├── app.tsx # Main App component
|
|
32
|
+
│ ├── utils.ts # Client-side utilities
|
|
33
|
+
│ ├── utils/
|
|
34
|
+
│ │ └── url-state.ts # URL state serialization
|
|
35
|
+
│ ├── hooks/
|
|
36
|
+
│ │ └── use-event-source.ts # SSE hook
|
|
37
|
+
│ └── components/
|
|
38
|
+
│ ├── session-list.tsx # Sidebar session list
|
|
39
|
+
│ ├── session-view.tsx # Conversation viewer
|
|
40
|
+
│ └── export-dialog.tsx # Export functionality
|
|
41
|
+
└── package.json
|
|
42
|
+
```
|
|
43
|
+
|
|
44
|
+
### Data Model
|
|
45
|
+
|
|
46
|
+
#### Session
|
|
47
|
+
|
|
48
|
+
```typescript
|
|
49
|
+
interface Session {
|
|
50
|
+
id: string; // UUID from filename
|
|
51
|
+
display: string; // First user message (truncated)
|
|
52
|
+
timestamp: number; // Session start time
|
|
53
|
+
project: string; // Full project path
|
|
54
|
+
projectName: string; // Directory name only
|
|
55
|
+
messageCount: number; // User + assistant message count
|
|
56
|
+
startTime: number | null; // First message timestamp (ms)
|
|
57
|
+
endTime: number | null; // Last message timestamp (ms)
|
|
58
|
+
fileSizeBytes: number | null; // JSONL file size on disk
|
|
59
|
+
}
|
|
60
|
+
```
|
|
61
|
+
|
|
62
|
+
#### Conversation Message
|
|
63
|
+
|
|
64
|
+
```typescript
|
|
65
|
+
interface ConversationMessage {
|
|
66
|
+
type: "user" | "assistant" | "summary" | "file-history-snapshot";
|
|
67
|
+
uuid?: string;
|
|
68
|
+
timestamp?: number;
|
|
69
|
+
message?: {
|
|
70
|
+
model?: string;
|
|
71
|
+
content?: Array<{ type: string; text?: string; ... }>;
|
|
72
|
+
...
|
|
73
|
+
};
|
|
74
|
+
...
|
|
75
|
+
}
|
|
76
|
+
```
|
|
77
|
+
|
|
78
|
+
#### Session Metadata
|
|
79
|
+
|
|
80
|
+
```typescript
|
|
81
|
+
interface SessionMetadata {
|
|
82
|
+
id: string;
|
|
83
|
+
model: string | null; // null = unknown model
|
|
84
|
+
}
|
|
85
|
+
```
|
|
86
|
+
|
|
87
|
+
### File Storage
|
|
88
|
+
|
|
89
|
+
Claude Code stores data in `~/.claude/`:
|
|
90
|
+
|
|
91
|
+
- `history.jsonl` - Session metadata and display names
|
|
92
|
+
- `projects/<encoded-path>/<uuid>.jsonl` - Conversation files
|
|
93
|
+
- `file-history/` - File snapshots
|
|
94
|
+
|
|
95
|
+
## API Endpoints
|
|
96
|
+
|
|
97
|
+
### GET /api/projects
|
|
98
|
+
Returns list of all projects with sessions.
|
|
99
|
+
|
|
100
|
+
### GET /api/sessions/stream
|
|
101
|
+
Server-Sent Events stream for real-time session updates.
|
|
102
|
+
- Event: `sessions` - Full session list (on connect)
|
|
103
|
+
- Event: `sessionsUpdate` - Incremental updates
|
|
104
|
+
- Event: `heartbeat` - Keep-alive (30s interval)
|
|
105
|
+
|
|
106
|
+
### POST /api/sessions/metadata
|
|
107
|
+
Get model metadata for session IDs.
|
|
108
|
+
```json
|
|
109
|
+
{ "ids": ["uuid1", "uuid2"] }
|
|
110
|
+
```
|
|
111
|
+
|
|
112
|
+
### POST /api/sessions/delete
|
|
113
|
+
Delete sessions by ID (removes files and history entries).
|
|
114
|
+
```json
|
|
115
|
+
{ "ids": ["uuid1", "uuid2"] }
|
|
116
|
+
```
|
|
117
|
+
|
|
118
|
+
### POST /api/sessions/rename
|
|
119
|
+
Rename a session by updating its display title in history.jsonl.
|
|
120
|
+
```json
|
|
121
|
+
{ "id": "uuid1", "display": "New title", "project": "/path/to/project", "timestamp": 1700000000000 }
|
|
122
|
+
```
|
|
123
|
+
|
|
124
|
+
### GET /api/conversation/:id
|
|
125
|
+
Get full conversation for a session.
|
|
126
|
+
|
|
127
|
+
### GET /api/conversation/:id/stream
|
|
128
|
+
Server-Sent Events for real-time conversation updates.
|
|
129
|
+
|
|
130
|
+
### POST /api/search
|
|
131
|
+
Full-text search using ripgrep.
|
|
132
|
+
```json
|
|
133
|
+
{
|
|
134
|
+
"query": "search term",
|
|
135
|
+
"options": {
|
|
136
|
+
"mode": "literal" | "regex",
|
|
137
|
+
"caseSensitive": boolean,
|
|
138
|
+
"wordRegexp": boolean,
|
|
139
|
+
"maxMatchesPerFile": number
|
|
140
|
+
},
|
|
141
|
+
"project": "project path or null"
|
|
142
|
+
}
|
|
143
|
+
```
|
|
144
|
+
|
|
145
|
+
## URL State Management
|
|
146
|
+
|
|
147
|
+
All UI state is synchronized with URL query parameters for shareable links:
|
|
148
|
+
|
|
149
|
+
| Param | Description | Default |
|
|
150
|
+
| ----------- | ----------------------------------------- | ---------- |
|
|
151
|
+
| `project` | Selected project path | null (all) |
|
|
152
|
+
| `session` | Selected session ID (UUID) or UUID prefix | null |
|
|
153
|
+
| `s` | Alias for `session` (expanded on load) | null |
|
|
154
|
+
| `q` | Search query | "" |
|
|
155
|
+
| `ft` | Full-text search enabled | false |
|
|
156
|
+
| `ftMode` | Search mode (literal/regex) | "literal" |
|
|
157
|
+
| `cs` | Case sensitive search | false |
|
|
158
|
+
| `ww` | Whole word search | false |
|
|
159
|
+
| `mm` | Max matches per file | 200 |
|
|
160
|
+
| `sidebar` | Sidebar collapsed | false |
|
|
161
|
+
| `batch` | Batch selection mode | false |
|
|
162
|
+
| `noUnknown` | Hide Unknown model sessions | false |
|
|
163
|
+
| `sort` | Sidebar sort mode | "recent" |
|
|
164
|
+
|
|
165
|
+
Notes:
|
|
166
|
+
|
|
167
|
+
- `session` accepts either a full UUID (e.g. `3e47321c-57a6-4d5e-a6ce-b84edd02dddb`) or a UUID prefix (e.g. `3e47321c`). If multiple sessions share the prefix, the newest one (by session timestamp) is selected and the URL is rewritten to the full UUID.
|
|
168
|
+
- `s` is a shorthand alias for `session`. On page load, the app expands it to `session` and removes `s` from the URL.
|
|
169
|
+
|
|
170
|
+
### State Persistence
|
|
171
|
+
|
|
172
|
+
- Search: Debounced 600ms, replaceState while typing, pushState on idle
|
|
173
|
+
- Navigation: Immediate pushState
|
|
174
|
+
- Back/forward: All state restored from URL
|
|
175
|
+
|
|
176
|
+
## Features
|
|
177
|
+
|
|
178
|
+
### Session List Sidebar
|
|
179
|
+
|
|
180
|
+
- **Search**: Filter by display text or project name
|
|
181
|
+
- **Full-text search**: Toggle to search conversation content via ripgrep
|
|
182
|
+
- **Project filter**: Searchable dropdown with fuzzy match for project name and full path
|
|
183
|
+
- **Batch mode**: Multi-select sessions for bulk export
|
|
184
|
+
- **Unknown model filter**: Hide sessions without detected models
|
|
185
|
+
- Checkbox: "Hide Unknown model"
|
|
186
|
+
- When enabled and unknown sessions exist: "Delete Unknown (N)" button
|
|
187
|
+
- Delete removes session files and history entries
|
|
188
|
+
- **Compact metadata**: Message count, total duration, and JSONL file size
|
|
189
|
+
- **Sorting**: Sort by duration or JSONL size (ascending/descending)
|
|
190
|
+
|
|
191
|
+
### Conversation View
|
|
192
|
+
|
|
193
|
+
- **Header**: Session title, project path, model, start/end times, message count, total duration, and JSONL file size
|
|
194
|
+
- **Rename title**: Click the session title to edit and save a new name
|
|
195
|
+
- **Message rendering**: User/assistant messages with tool calls
|
|
196
|
+
- **Collapsible tool calls**: Click to expand/collapse
|
|
197
|
+
- **Copy button**: Copy message text to clipboard
|
|
198
|
+
- **Resume command**: Copy command to resume session in terminal
|
|
199
|
+
- **Export**: Download conversation as Markdown
|
|
200
|
+
|
|
201
|
+
### Export Dialog
|
|
202
|
+
|
|
203
|
+
- Single or batch session export
|
|
204
|
+
- Markdown format with metadata
|
|
205
|
+
- Copy to clipboard or download as file
|
|
206
|
+
|
|
207
|
+
### Real-time Updates
|
|
208
|
+
|
|
209
|
+
- File watcher monitors `~/.claude/projects/`
|
|
210
|
+
- SSE pushes updates to connected clients
|
|
211
|
+
- Session list and conversation view update automatically
|
|
212
|
+
|
|
213
|
+
## Session Metadata Extraction
|
|
214
|
+
|
|
215
|
+
For each session, the system extracts:
|
|
216
|
+
|
|
217
|
+
1. **Model**: First occurrence in user/assistant messages
|
|
218
|
+
2. **Start time**: First message timestamp
|
|
219
|
+
3. **End time**: Last message timestamp
|
|
220
|
+
4. **Message count**: Total user + assistant messages
|
|
221
|
+
5. **JSONL size**: File size on disk
|
|
222
|
+
|
|
223
|
+
Unknown model sessions are those where no model was found in the conversation.
|
|
224
|
+
|
|
225
|
+
## Cleanup and Maintenance
|
|
226
|
+
|
|
227
|
+
### Orphaned Session Cleanup
|
|
228
|
+
|
|
229
|
+
On startup, the system automatically removes orphaned history entries (sessions in `history.jsonl` without corresponding `.jsonl` files).
|
|
230
|
+
|
|
231
|
+
### Delete Logging
|
|
232
|
+
|
|
233
|
+
Both server and browser log deletion operations:
|
|
234
|
+
|
|
235
|
+
**Server console:**
|
|
236
|
+
```
|
|
237
|
+
[/api/sessions/delete] Received request to delete N sessions: [...]
|
|
238
|
+
[deleteSession] Attempting to delete: <uuid>
|
|
239
|
+
[deleteSession] Successfully deleted: <path>
|
|
240
|
+
[deleteSession] Removed from history.jsonl: <uuid>
|
|
241
|
+
```
|
|
242
|
+
|
|
243
|
+
**Browser console:**
|
|
244
|
+
```
|
|
245
|
+
[handleDeleteUnknownSessions] Requesting deletion of N sessions: [...]
|
|
246
|
+
[handleDeleteUnknownSessions] Server response: {...}
|
|
247
|
+
[handleDeleteUnknownSessions] N deleted, N failed
|
|
248
|
+
```
|
|
249
|
+
|
|
250
|
+
## Development
|
|
251
|
+
|
|
252
|
+
### Build
|
|
253
|
+
|
|
254
|
+
```bash
|
|
255
|
+
bun install
|
|
256
|
+
bun run build
|
|
257
|
+
```
|
|
258
|
+
|
|
259
|
+
### Run
|
|
260
|
+
|
|
261
|
+
```bash
|
|
262
|
+
bun start # Production
|
|
263
|
+
bun start --dev # Development with CORS
|
|
264
|
+
bun start --no-open # Don't open browser
|
|
265
|
+
bun start -p 3000 # Custom port
|
|
266
|
+
```
|
|
267
|
+
|
|
268
|
+
### Tech Stack
|
|
269
|
+
|
|
270
|
+
- **Runtime**: Bun
|
|
271
|
+
- **Server**: Hono
|
|
272
|
+
- **Frontend**: React, TanStack Virtual, Tailwind CSS, Lucide icons
|
|
273
|
+
- **Search**: ripgrep (rg)
|
|
274
|
+
- **Build**: Bun bundler
|
|
275
|
+
|
|
276
|
+
## Security Considerations
|
|
277
|
+
|
|
278
|
+
- Server binds to 127.0.0.1 by default (localhost only)
|
|
279
|
+
- File paths validated before operations
|
|
280
|
+
- No authentication (intended for local use only)
|