@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.
@@ -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-CfXKVwHJ.js"></script>
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.14.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)