codedash-app 1.2.0 → 1.3.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 +35 -24
- package/package.json +1 -1
- package/src/frontend/app.js +80 -25
package/README.md
CHANGED
|
@@ -1,60 +1,71 @@
|
|
|
1
|
-
#
|
|
1
|
+
# CodeDash
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
Browser dashboard for Claude Code & Codex sessions. View, search, resume, and manage all your AI coding sessions.
|
|
4
4
|
|
|
5
|
-
|
|
5
|
+
https://github.com/user-attachments/assets/15c45659-365b-49f8-86a3-9005fa155ca6
|
|
6
|
+
|
|
7
|
+
  
|
|
6
8
|
|
|
7
9
|
## Quick Start
|
|
8
10
|
|
|
9
11
|
```bash
|
|
10
|
-
npx
|
|
12
|
+
npx codedash-app run
|
|
11
13
|
```
|
|
12
14
|
|
|
13
|
-
Opens `http://localhost:3847`
|
|
14
|
-
|
|
15
|
-
Custom port:
|
|
15
|
+
Opens `http://localhost:3847` in your browser.
|
|
16
16
|
|
|
17
17
|
```bash
|
|
18
|
-
npx
|
|
18
|
+
npx codedash-app run --port=4000 # custom port
|
|
19
|
+
npx codedash-app run --no-browser # don't auto-open
|
|
20
|
+
npx codedash-app list # list sessions in terminal
|
|
21
|
+
npx codedash-app stats # show statistics
|
|
19
22
|
```
|
|
20
23
|
|
|
21
24
|
## Features
|
|
22
25
|
|
|
23
26
|
**Sessions**
|
|
24
|
-
-
|
|
25
|
-
-
|
|
26
|
-
-
|
|
27
|
-
-
|
|
27
|
+
- Grid and List view with project grouping
|
|
28
|
+
- Trigram fuzzy search across session content and projects
|
|
29
|
+
- Filter by tool (Claude/Codex), tags, date range
|
|
30
|
+
- Star/pin important sessions (always shown first)
|
|
31
|
+
- Tag sessions: bug, feature, research, infra, deploy, review
|
|
32
|
+
- Activity heatmap (GitHub-style)
|
|
33
|
+
- Cost estimation per session
|
|
28
34
|
|
|
29
35
|
**Launch**
|
|
30
|
-
- Resume
|
|
31
|
-
- One-click launch with `--dangerously-skip-permissions` option
|
|
36
|
+
- Resume sessions in iTerm2, Terminal.app, Warp, Kitty, Alacritty
|
|
32
37
|
- Auto `cd` into the correct project directory
|
|
33
38
|
- Copy resume command to clipboard
|
|
34
39
|
- Terminal preference saved between sessions
|
|
35
40
|
|
|
36
41
|
**Manage**
|
|
37
42
|
- Delete sessions (file + history + env cleanup)
|
|
38
|
-
-
|
|
39
|
-
-
|
|
43
|
+
- Bulk select and delete
|
|
44
|
+
- Export conversations as Markdown
|
|
45
|
+
- Related git commits shown per session
|
|
46
|
+
- Auto-update notifications
|
|
47
|
+
|
|
48
|
+
**Themes**
|
|
49
|
+
- Dark (default), Light, System
|
|
40
50
|
|
|
41
51
|
**Keyboard Shortcuts**
|
|
42
|
-
- `/`
|
|
43
|
-
- `
|
|
52
|
+
- `/` focus search, `j/k` navigate, `Enter` open
|
|
53
|
+
- `x` star, `d` delete, `s` select mode, `g` toggle groups
|
|
54
|
+
- `r` refresh, `Escape` close panels
|
|
44
55
|
|
|
45
56
|
## How It Works
|
|
46
57
|
|
|
47
|
-
Reads session data from `~/.claude/`:
|
|
48
|
-
- `history.jsonl` — session index
|
|
49
|
-
- `projects
|
|
50
|
-
- `
|
|
58
|
+
Reads session data from `~/.claude/` and `~/.codex/`:
|
|
59
|
+
- `history.jsonl` — session index
|
|
60
|
+
- `projects/*/<session-id>.jsonl` — conversation data
|
|
61
|
+
- `sessions/` — Codex session files
|
|
51
62
|
|
|
52
|
-
Zero dependencies.
|
|
63
|
+
Zero dependencies. Everything runs on `localhost`.
|
|
53
64
|
|
|
54
65
|
## Requirements
|
|
55
66
|
|
|
56
67
|
- Node.js >= 16
|
|
57
|
-
- Claude Code
|
|
68
|
+
- Claude Code or Codex CLI installed
|
|
58
69
|
- macOS / Linux / Windows
|
|
59
70
|
|
|
60
71
|
## License
|
package/package.json
CHANGED
package/src/frontend/app.js
CHANGED
|
@@ -186,48 +186,103 @@ function saveTerminalPref(val) {
|
|
|
186
186
|
localStorage.setItem('codedash-terminal', val);
|
|
187
187
|
}
|
|
188
188
|
|
|
189
|
+
// ── Trigram search ─────────────────────────────────────────────
|
|
190
|
+
|
|
191
|
+
function trigrams(str) {
|
|
192
|
+
var s = ' ' + str.toLowerCase() + ' ';
|
|
193
|
+
var t = {};
|
|
194
|
+
for (var i = 0; i < s.length - 2; i++) {
|
|
195
|
+
var tri = s.substring(i, i + 3);
|
|
196
|
+
t[tri] = (t[tri] || 0) + 1;
|
|
197
|
+
}
|
|
198
|
+
return t;
|
|
199
|
+
}
|
|
200
|
+
|
|
201
|
+
function trigramScore(query, text) {
|
|
202
|
+
if (!query || !text) return 0;
|
|
203
|
+
var qt = trigrams(query);
|
|
204
|
+
var tt = trigrams(text);
|
|
205
|
+
var matches = 0;
|
|
206
|
+
var total = 0;
|
|
207
|
+
for (var k in qt) {
|
|
208
|
+
total += qt[k];
|
|
209
|
+
if (tt[k]) matches += Math.min(qt[k], tt[k]);
|
|
210
|
+
}
|
|
211
|
+
return total > 0 ? matches / total : 0;
|
|
212
|
+
}
|
|
213
|
+
|
|
214
|
+
function searchScore(query, session) {
|
|
215
|
+
var q = query.toLowerCase();
|
|
216
|
+
var fields = [
|
|
217
|
+
session.first_message || '',
|
|
218
|
+
session.project_short || '',
|
|
219
|
+
session.project || '',
|
|
220
|
+
session.id || '',
|
|
221
|
+
session.tool || ''
|
|
222
|
+
];
|
|
223
|
+
var haystack = fields.join(' ').toLowerCase();
|
|
224
|
+
|
|
225
|
+
// Exact substring match = highest score
|
|
226
|
+
if (haystack.indexOf(q) >= 0) return 1;
|
|
227
|
+
|
|
228
|
+
// Trigram fuzzy match
|
|
229
|
+
var best = 0;
|
|
230
|
+
for (var i = 0; i < fields.length; i++) {
|
|
231
|
+
var score = trigramScore(q, fields[i]);
|
|
232
|
+
if (score > best) best = score;
|
|
233
|
+
}
|
|
234
|
+
// Also score against full haystack
|
|
235
|
+
var fullScore = trigramScore(q, haystack);
|
|
236
|
+
if (fullScore > best) best = fullScore;
|
|
237
|
+
|
|
238
|
+
return best;
|
|
239
|
+
}
|
|
240
|
+
|
|
189
241
|
// ── Filtering ──────────────────────────────────────────────────
|
|
190
242
|
|
|
243
|
+
var SEARCH_THRESHOLD = 0.3;
|
|
244
|
+
|
|
191
245
|
function applyFilters() {
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
246
|
+
var scored = [];
|
|
247
|
+
for (var i = 0; i < allSessions.length; i++) {
|
|
248
|
+
var s = allSessions[i];
|
|
195
249
|
|
|
196
|
-
//
|
|
197
|
-
if (
|
|
198
|
-
var q = searchQuery.toLowerCase();
|
|
199
|
-
var haystack = (
|
|
200
|
-
(s.first_message || '') + ' ' +
|
|
201
|
-
(s.project || '') + ' ' +
|
|
202
|
-
(s.project_short || '') + ' ' +
|
|
203
|
-
(s.id || '') + ' ' +
|
|
204
|
-
(s.tool || '')
|
|
205
|
-
).toLowerCase();
|
|
206
|
-
if (haystack.indexOf(q) === -1) return false;
|
|
207
|
-
}
|
|
250
|
+
// Tool filter
|
|
251
|
+
if (toolFilter && s.tool !== toolFilter) continue;
|
|
208
252
|
|
|
209
253
|
// Tag filter
|
|
210
254
|
if (tagFilter) {
|
|
211
255
|
var sessionTags = tags[s.id] || [];
|
|
212
|
-
if (sessionTags.indexOf(tagFilter) === -1)
|
|
256
|
+
if (sessionTags.indexOf(tagFilter) === -1) continue;
|
|
213
257
|
}
|
|
214
258
|
|
|
215
259
|
// Date range
|
|
216
|
-
if (dateFrom && s.date < dateFrom)
|
|
217
|
-
if (dateTo && s.date > dateTo)
|
|
260
|
+
if (dateFrom && s.date < dateFrom) continue;
|
|
261
|
+
if (dateTo && s.date > dateTo) continue;
|
|
218
262
|
|
|
219
|
-
|
|
220
|
-
|
|
263
|
+
// Search with trigram scoring
|
|
264
|
+
var score = 1;
|
|
265
|
+
if (searchQuery) {
|
|
266
|
+
score = searchScore(searchQuery, s);
|
|
267
|
+
if (score < SEARCH_THRESHOLD) continue;
|
|
268
|
+
}
|
|
269
|
+
|
|
270
|
+
scored.push({ session: s, score: score });
|
|
271
|
+
}
|
|
221
272
|
|
|
222
|
-
//
|
|
223
|
-
|
|
224
|
-
var aStarred = stars.indexOf(a.id) >= 0 ? 1 : 0;
|
|
225
|
-
var bStarred = stars.indexOf(b.id) >= 0 ? 1 : 0;
|
|
273
|
+
// Sort: starred first, then by search score (if searching), then by time
|
|
274
|
+
scored.sort(function(a, b) {
|
|
275
|
+
var aStarred = stars.indexOf(a.session.id) >= 0 ? 1 : 0;
|
|
276
|
+
var bStarred = stars.indexOf(b.session.id) >= 0 ? 1 : 0;
|
|
226
277
|
if (aStarred !== bStarred) return bStarred - aStarred;
|
|
227
|
-
return b.
|
|
278
|
+
if (searchQuery && a.score !== b.score) return b.score - a.score;
|
|
279
|
+
return b.session.last_ts - a.session.last_ts;
|
|
228
280
|
});
|
|
229
281
|
|
|
282
|
+
filteredSessions = scored.map(function(x) { return x.session; });
|
|
283
|
+
|
|
230
284
|
render();
|
|
285
|
+
|
|
231
286
|
}
|
|
232
287
|
|
|
233
288
|
function onSearch(val) {
|